#ifndef _GLIBMM_ARRAYHANDLE_H #define _GLIBMM_ARRAYHANDLE_H /* Copyright (C) 2002 The gtkmm Development Team * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . */ #include #include namespace Glib { namespace Container_Helpers { #ifndef DOXYGEN_SHOULD_SKIP_THIS /* Count the number of elements in a 0-terminated sequence. */ template inline std::size_t compute_array_size(const T* array) { const T* pend = array; while (*pend) ++pend; return (pend - array); } /* Allocate and fill a 0-terminated array. The size argument * specifies the number of elements in the input sequence. */ template typename Tr::CType* create_array(For pbegin, std::size_t size, Tr) { using CType = typename Tr::CType; CType* const array = static_cast(g_malloc((size + 1) * sizeof(CType))); CType* const array_end = array + size; for (CType* pdest = array; pdest != array_end; ++pdest) { // Use & to force a warning if the iterator returns a temporary object. *pdest = Tr::to_c_type(*&*pbegin); ++pbegin; } *array_end = CType(); return array; } template gboolean* create_bool_array(For pbegin, std::size_t size) { gboolean* const array(static_cast(g_malloc((size + 1) * sizeof(gboolean)))); gboolean* const array_end(array + size); for (gboolean* pdest(array); pdest != array_end; ++pdest) { *pdest = *pbegin; ++pbegin; } *array_end = false; return array; } /* Convert from any container that supports forward * iterators and has a size() method. */ template struct ArraySourceTraits { using CType = typename Tr::CType; static std::size_t get_size(const Cont& cont) { return cont.size(); } static const CType* get_data(const Cont& cont, std::size_t size) { return Glib::Container_Helpers::create_array(cont.begin(), size, Tr()); } static const Glib::OwnershipType initial_ownership = Glib::OWNERSHIP_SHALLOW; }; // source traits for bools. template struct BoolArraySourceTraits { using CType = gboolean; static std::size_t get_size(const Cont& cont) { return cont.size(); } static const CType* get_data(const Cont& cont, std::size_t size) { return Glib::Container_Helpers::create_bool_array(cont.begin(), size); } static const Glib::OwnershipType initial_ownership = Glib::OWNERSHIP_SHALLOW; }; /* Convert from a 0-terminated array. The Cont argument must be a pointer * to the first element. Note that only arrays of the C type are supported. */ template struct ArraySourceTraits { using CType = typename Tr::CType; static std::size_t get_size(const CType* array) { return (array) ? Glib::Container_Helpers::compute_array_size(array) : 0; } static const CType* get_data(const CType* array, std::size_t) { return array; } static const Glib::OwnershipType initial_ownership = Glib::OWNERSHIP_NONE; }; template struct ArraySourceTraits : ArraySourceTraits { }; /* Convert from a 0-terminated array. The Cont argument must be a pointer * to the first element. Note that only arrays of the C type are supported. * For consistency, the array must be 0-terminated, even though the array * size is known at compile time. */ template struct ArraySourceTraits { using CType = typename Tr::CType; static std::size_t get_size(const CType*) { return (N - 1); } static const CType* get_data(const CType* array, std::size_t) { return array; } static const Glib::OwnershipType initial_ownership = Glib::OWNERSHIP_NONE; }; template struct ArraySourceTraits : ArraySourceTraits { }; #endif /* DOXYGEN_SHOULD_SKIP_THIS */ /** * @ingroup ContHelpers */ template class ArrayHandleIterator { public: using CppType = typename Tr::CppType; using CType = typename Tr::CType; using iterator_category = std::random_access_iterator_tag; using value_type = CppType; using difference_type = std::ptrdiff_t; using reference = value_type; using pointer = void; explicit inline ArrayHandleIterator(const CType* pos); inline value_type operator*() const; inline value_type operator[](difference_type offset) const; inline ArrayHandleIterator& operator++(); inline const ArrayHandleIterator operator++(int); // these are needed by msvc 2005 when using deque. inline ArrayHandleIterator& operator--(); inline const ArrayHandleIterator operator--(int); // All this random access stuff is only there because STL algorithms // usually have optimized specializations for random access iterators, // and we don't want to give away efficiency for nothing. // inline ArrayHandleIterator& operator+=(difference_type rhs); inline ArrayHandleIterator& operator-=(difference_type rhs); inline const ArrayHandleIterator operator+(difference_type rhs) const; inline const ArrayHandleIterator operator-(difference_type rhs) const; inline difference_type operator-(const ArrayHandleIterator& rhs) const; inline bool operator==(const ArrayHandleIterator& rhs) const; inline bool operator!=(const ArrayHandleIterator& rhs) const; inline bool operator<(const ArrayHandleIterator& rhs) const; inline bool operator>(const ArrayHandleIterator& rhs) const; inline bool operator<=(const ArrayHandleIterator& rhs) const; inline bool operator>=(const ArrayHandleIterator& rhs) const; private: const CType* pos_; }; } // namespace Container_Helpers // TODO: When we can break ABI, remove this and replace uses of it with std::vector. // We cannot deprecate it yet, because we cannot easily deprecate methods that use it //- for instance, we cannot just override methods that use it as a return type. /** This is an intermediate type. When a method takes this, or returns this, you * should use a standard C++ container of your choice, such as std::list or * std::vector. * * However, this is not used in new API. We now prefer to just use std::vector, * which is less flexibile, but makes the API clearer. * * @ingroup ContHandles */ template > class ArrayHandle { public: using CppType = typename Tr::CppType; using CType = typename Tr::CType; using value_type = CppType; using size_type = std::size_t; using difference_type = std::ptrdiff_t; using const_iterator = Glib::Container_Helpers::ArrayHandleIterator; using iterator = Glib::Container_Helpers::ArrayHandleIterator; template inline ArrayHandle(const Cont& container); // Take over ownership of an array created by GTK+ functions. inline ArrayHandle(const CType* array, std::size_t array_size, Glib::OwnershipType ownership); inline ArrayHandle(const CType* array, Glib::OwnershipType ownership); // Copying clears the ownership flag of the source handle. inline ArrayHandle(const ArrayHandle& other); ~ArrayHandle() noexcept; inline const_iterator begin() const; inline const_iterator end() const; template inline operator std::vector() const; template inline operator std::deque() const; template inline operator std::list() const; template inline void assign_to(Cont& container) const; template inline void copy(Out pdest) const; inline const CType* data() const; inline std::size_t size() const; inline bool empty() const; private: std::size_t size_; const CType* parray_; mutable Glib::OwnershipType ownership_; // No copy assignment. ArrayHandle& operator=(const ArrayHandle&); }; template <> class GLIBMM_API ArrayHandle> { public: using Me = ArrayHandle>; using Tr = Container_Helpers::TypeTraits; using CppType = Tr::CppType; using CType = Tr::CType; using value_type = CppType; using size_type = std::size_t; using difference_type = std::ptrdiff_t; using const_iterator = Glib::Container_Helpers::ArrayHandleIterator; using iterator = Glib::Container_Helpers::ArrayHandleIterator; template inline ArrayHandle(const Cont& container); // Take over ownership of an array created by GTK+ functions. inline ArrayHandle(const CType* array, std::size_t array_size, Glib::OwnershipType ownership); inline ArrayHandle(const CType* array, Glib::OwnershipType ownership); // Copying clears the ownership flag of the source handle. inline ArrayHandle(const Me& other); ~ArrayHandle() noexcept; inline const_iterator begin() const; inline const_iterator end() const; // this is inside class definition, so msvc 2005, 2008 and 2010 can compile this code. template inline operator std::vector() const { #ifdef GLIBMM_HAVE_TEMPLATE_SEQUENCE_CTORS return std::vector(this->begin(), this->end()); #else std::vector temp; temp.reserve(this->size()); Glib::Container_Helpers::fill_container(temp, this->begin(), this->end()); return temp; #endif } // this is inside class definition, so msvc 2005, 2008 and 2010 can compile this code. template inline operator std::deque() const { #ifdef GLIBMM_HAVE_TEMPLATE_SEQUENCE_CTORS return std::deque(this->begin(), this->end()); #else std::deque temp; Glib::Container_Helpers::fill_container(temp, this->begin(), this->end()); return temp; #endif } // this is inside class definition, so msvc 2005, 2008 and 2010 can compile this code. template inline operator std::list() const { #ifdef GLIBMM_HAVE_TEMPLATE_SEQUENCE_CTORS return std::list(this->begin(), this->end()); #else std::list temp; Glib::Container_Helpers::fill_container(temp, this->begin(), this->end()); return temp; #endif } template inline void assign_to(Cont& container) const; template inline void copy(Out pdest) const; inline const CType* data() const; inline std::size_t size() const; inline bool empty() const; private: std::size_t size_; const CType* parray_; mutable Glib::OwnershipType ownership_; // No copy assignment. Me& operator=(const Me&); }; // TODO: Remove this when we can break glibmm API. /** If a method takes this as an argument, or has this as a return type, then you can use a standard * container such as std::list or std::vector. * * * However, this is not used in new API. We now prefer to just use std::vector, * which is less flexibile, but makes the API clearer. * * @ingroup ContHandles */ using StringArrayHandle = ArrayHandle; /***************************************************************************/ /* Inline implementation */ /***************************************************************************/ #ifndef DOXYGEN_SHOULD_SKIP_THIS namespace Container_Helpers { /**** Glib::Container_Helpers::ArrayHandleIterator<> ***********************/ template inline ArrayHandleIterator::ArrayHandleIterator(const CType* pos) : pos_(pos) { } template inline typename ArrayHandleIterator::value_type ArrayHandleIterator::operator*() const { return Tr::to_cpp_type(*pos_); } template inline typename ArrayHandleIterator::value_type ArrayHandleIterator::operator[]( difference_type offset) const { return Tr::to_cpp_type(pos_[offset]); } template inline ArrayHandleIterator& ArrayHandleIterator::operator++() { ++pos_; return *this; } template inline const ArrayHandleIterator ArrayHandleIterator::operator++(int) { return ArrayHandleIterator(pos_++); } template inline ArrayHandleIterator& ArrayHandleIterator::operator--() { --pos_; return *this; } template inline const ArrayHandleIterator ArrayHandleIterator::operator--(int) { return ArrayHandleIterator(pos_--); } template inline ArrayHandleIterator& ArrayHandleIterator::operator+=(typename ArrayHandleIterator::difference_type rhs) { pos_ += rhs; return *this; } template inline ArrayHandleIterator& ArrayHandleIterator::operator-=(typename ArrayHandleIterator::difference_type rhs) { pos_ -= rhs; return *this; } template inline const ArrayHandleIterator ArrayHandleIterator::operator+(typename ArrayHandleIterator::difference_type rhs) const { return ArrayHandleIterator(pos_ + rhs); } template inline const ArrayHandleIterator ArrayHandleIterator::operator-(typename ArrayHandleIterator::difference_type rhs) const { return ArrayHandleIterator(pos_ - rhs); } template inline typename ArrayHandleIterator::difference_type ArrayHandleIterator::operator-(const ArrayHandleIterator& rhs) const { return (pos_ - rhs.pos_); } template inline bool ArrayHandleIterator::operator==(const ArrayHandleIterator& rhs) const { return (pos_ == rhs.pos_); } template inline bool ArrayHandleIterator::operator!=(const ArrayHandleIterator& rhs) const { return (pos_ != rhs.pos_); } template inline bool ArrayHandleIterator::operator<(const ArrayHandleIterator& rhs) const { return (pos_ < rhs.pos_); } template inline bool ArrayHandleIterator::operator>(const ArrayHandleIterator& rhs) const { return (pos_ > rhs.pos_); } template inline bool ArrayHandleIterator::operator<=(const ArrayHandleIterator& rhs) const { return (pos_ <= rhs.pos_); } template inline bool ArrayHandleIterator::operator>=(const ArrayHandleIterator& rhs) const { return (pos_ >= rhs.pos_); } } // namespace Container_Helpers /**** Glib::ArrayHandle<> **************************************************/ template template inline ArrayHandle::ArrayHandle(const Cont& container) : size_(Glib::Container_Helpers::ArraySourceTraits::get_size(container)), parray_(Glib::Container_Helpers::ArraySourceTraits::get_data(container, size_)), ownership_(Glib::Container_Helpers::ArraySourceTraits::initial_ownership) { } template inline ArrayHandle::ArrayHandle(const typename ArrayHandle::CType* array, std::size_t array_size, Glib::OwnershipType ownership) : size_((array) ? array_size : 0), parray_(array), ownership_(ownership) { } template inline ArrayHandle::ArrayHandle( const typename ArrayHandle::CType* array, Glib::OwnershipType ownership) : size_((array) ? Glib::Container_Helpers::compute_array_size(array) : 0), parray_(array), ownership_(ownership) { } template inline ArrayHandle::ArrayHandle(const ArrayHandle& other) : size_(other.size_), parray_(other.parray_), ownership_(other.ownership_) { other.ownership_ = Glib::OWNERSHIP_NONE; } template ArrayHandle::~ArrayHandle() noexcept { if (parray_ && ownership_ != Glib::OWNERSHIP_NONE) { if (ownership_ != Glib::OWNERSHIP_SHALLOW) { // Deep ownership: release each container element. const CType* const pend = parray_ + size_; for (const CType* p = parray_; p != pend; ++p) Tr::release_c_type(*p); } g_free(const_cast(parray_)); } } template inline typename ArrayHandle::const_iterator ArrayHandle::begin() const { return Glib::Container_Helpers::ArrayHandleIterator(parray_); } template inline typename ArrayHandle::const_iterator ArrayHandle::end() const { return Glib::Container_Helpers::ArrayHandleIterator(parray_ + size_); } template template inline ArrayHandle::operator std::vector() const { #ifdef GLIBMM_HAVE_TEMPLATE_SEQUENCE_CTORS return std::vector(this->begin(), this->end()); #else std::vector temp; temp.reserve(this->size()); Glib::Container_Helpers::fill_container(temp, this->begin(), this->end()); return temp; #endif } template template inline ArrayHandle::operator std::deque() const { #ifdef GLIBMM_HAVE_TEMPLATE_SEQUENCE_CTORS return std::deque(this->begin(), this->end()); #else std::deque temp; Glib::Container_Helpers::fill_container(temp, this->begin(), this->end()); return temp; #endif } template template inline ArrayHandle::operator std::list() const { #ifdef GLIBMM_HAVE_TEMPLATE_SEQUENCE_CTORS return std::list(this->begin(), this->end()); #else std::list temp; Glib::Container_Helpers::fill_container(temp, this->begin(), this->end()); return temp; #endif } template template inline void ArrayHandle::assign_to(Cont& container) const { #ifdef GLIBMM_HAVE_TEMPLATE_SEQUENCE_CTORS container.assign(this->begin(), this->end()); #else Cont temp; Glib::Container_Helpers::fill_container(temp, this->begin(), this->end()); container.swap(temp); #endif } template template inline void ArrayHandle::copy(Out pdest) const { std::copy(this->begin(), this->end(), pdest); } template inline const typename ArrayHandle::CType* ArrayHandle::data() const { return parray_; } template inline std::size_t ArrayHandle::size() const { return size_; } template inline bool ArrayHandle::empty() const { return (size_ == 0); } /**** Glib::ArrayHandle **********************************************/ template inline ArrayHandle>::ArrayHandle(const Cont& container) : size_(Glib::Container_Helpers::BoolArraySourceTraits::get_size(container)), parray_(Glib::Container_Helpers::BoolArraySourceTraits::get_data(container, size_)), ownership_(Glib::Container_Helpers::BoolArraySourceTraits::initial_ownership) { } inline ArrayHandle>::ArrayHandle( const gboolean* array, std::size_t array_size, Glib::OwnershipType ownership) : size_((array) ? array_size : 0), parray_(array), ownership_(ownership) { } inline ArrayHandle>::ArrayHandle( const gboolean* array, Glib::OwnershipType ownership) : size_((array) ? Glib::Container_Helpers::compute_array_size(array) : 0), parray_(array), ownership_(ownership) { } inline ArrayHandle>::ArrayHandle( const ArrayHandle>& other) : size_(other.size_), parray_(other.parray_), ownership_(other.ownership_) { other.ownership_ = Glib::OWNERSHIP_NONE; } inline ArrayHandle>::const_iterator ArrayHandle>::begin() const { return Glib::Container_Helpers::ArrayHandleIterator(parray_); } inline ArrayHandle>::const_iterator ArrayHandle>::end() const { return Glib::Container_Helpers::ArrayHandleIterator(parray_ + size_); } template inline void ArrayHandle>::assign_to(Cont& container) const { #ifdef GLIBMM_HAVE_TEMPLATE_SEQUENCE_CTORS container.assign(this->begin(), this->end()); #else Cont temp; Glib::Container_Helpers::fill_container(temp, this->begin(), this->end()); container.swap(temp); #endif } template inline void ArrayHandle>::copy(Out pdest) const { std::copy(this->begin(), this->end(), pdest); } inline const gboolean* ArrayHandle>::data() const { return parray_; } inline std::size_t ArrayHandle>::size() const { return size_; } inline bool ArrayHandle>::empty() const { return (size_ == 0); } #endif /* DOXYGEN_SHOULD_SKIP_THIS */ } // namespace Glib #endif /* _GLIBMM_ARRAYHANDLE_H */