// -*- c++ -*- #ifndef _GLIBMM_ARRAYHANDLE_H #define _GLIBMM_ARRAYHANDLE_H /* $Id: arrayhandle.h 4 2005-05-13 20:47:18Z taybin $ */ /* 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 Library General Public * License as published by the Free Software Foundation; either * version 2 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include <glibmm/containerhandle_shared.h> namespace Glib { namespace Container_Helpers { #ifndef DOXYGEN_SHOULD_SKIP_THIS /* Count the number of elements in a 0-terminated sequence. */ template <class T> inline 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 <class For, class Tr> typename Tr::CType* create_array(For pbegin, size_t size, Tr) { typedef typename Tr::CType CType; CType *const array = static_cast<CType*>(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; } /* Convert from any container that supports forward * iterators and has a size() method. */ template <class Tr, class Cont> struct ArraySourceTraits { typedef typename Tr::CType CType; static size_t get_size(const Cont& cont) { return cont.size(); } static const CType* get_data(const Cont& cont, size_t size) { return Glib::Container_Helpers::create_array(cont.begin(), size, Tr()); } 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 <class Tr, class Cont> struct ArraySourceTraits<Tr,Cont*> { typedef typename Tr::CType CType; static 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, size_t) { return array; } static const Glib::OwnershipType initial_ownership = Glib::OWNERSHIP_NONE; }; template <class Tr, class Cont> struct ArraySourceTraits<Tr,const Cont*> : ArraySourceTraits<Tr,Cont*> {}; /* 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 <class Tr, class Cont, size_t N> struct ArraySourceTraits<Tr,Cont[N]> { typedef typename Tr::CType CType; static size_t get_size(const CType*) { return (N - 1); } static const CType* get_data(const CType* array, size_t) { return array; } static const Glib::OwnershipType initial_ownership = Glib::OWNERSHIP_NONE; }; template <class Tr, class Cont, size_t N> struct ArraySourceTraits<Tr,const Cont[N]> : ArraySourceTraits<Tr,Cont[N]> {}; #endif /* DOXYGEN_SHOULD_SKIP_THIS */ /** * @ingroup ContHelpers */ template <class Tr> class ArrayHandleIterator { public: typedef typename Tr::CppType CppType; typedef typename Tr::CType CType; typedef std::random_access_iterator_tag iterator_category; typedef CppType value_type; typedef ptrdiff_t difference_type; typedef value_type reference; typedef void pointer; explicit inline ArrayHandleIterator(const CType* pos); inline value_type operator*() const; inline value_type operator[](difference_type offset) const; inline ArrayHandleIterator<Tr> & operator++(); inline const ArrayHandleIterator<Tr> 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<Tr> & operator+=(difference_type rhs); inline ArrayHandleIterator<Tr> & operator-=(difference_type rhs); inline const ArrayHandleIterator<Tr> operator+ (difference_type rhs) const; inline const ArrayHandleIterator<Tr> operator- (difference_type rhs) const; inline difference_type operator-(const ArrayHandleIterator<Tr>& rhs) const; inline bool operator==(const ArrayHandleIterator<Tr>& rhs) const; inline bool operator!=(const ArrayHandleIterator<Tr>& rhs) const; inline bool operator< (const ArrayHandleIterator<Tr>& rhs) const; inline bool operator> (const ArrayHandleIterator<Tr>& rhs) const; inline bool operator<=(const ArrayHandleIterator<Tr>& rhs) const; inline bool operator>=(const ArrayHandleIterator<Tr>& rhs) const; private: const CType* pos_; }; } // namespace Container_Helpers /** 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. * @ingroup ContHandles */ template < class T, class Tr = Glib::Container_Helpers::TypeTraits<T> > 00188 class ArrayHandle { public: typedef typename Tr::CppType CppType; typedef typename Tr::CType CType; typedef CppType value_type; typedef size_t size_type; typedef ptrdiff_t difference_type; typedef Glib::Container_Helpers::ArrayHandleIterator<Tr> const_iterator; typedef Glib::Container_Helpers::ArrayHandleIterator<Tr> iterator; template <class Cont> inline ArrayHandle(const Cont& container); // Take over ownership of an array created by GTK+ functions. inline ArrayHandle(const CType* array, 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<T,Tr>& other); ~ArrayHandle(); inline const_iterator begin() const; inline const_iterator end() const; template <class U> inline operator std::vector<U>() const; template <class U> inline operator std::deque<U>() const; template <class U> inline operator std::list<U>() const; template <class Cont> inline void assign_to(Cont& container) const; template <class Out> inline void copy(Out pdest) const; inline const CType* data() const; inline size_t size() const; inline bool empty() const; private: size_t size_; const CType* parray_; mutable Glib::OwnershipType ownership_; // No copy assignment. ArrayHandle<T, Tr>& operator=(const ArrayHandle<T,Tr>&); }; /** 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<Glib::ustring> or std::vector<Glib::ustring>. * @ingroup ContHandles */ 00243 typedef ArrayHandle<Glib::ustring> StringArrayHandle; /***************************************************************************/ /* Inline implementation */ /***************************************************************************/ #ifndef DOXYGEN_SHOULD_SKIP_THIS namespace Container_Helpers { /**** Glib::Container_Helpers::ArrayHandleIterator<> ***********************/ template <class Tr> inline ArrayHandleIterator<Tr>::ArrayHandleIterator(const CType* pos) : pos_ (pos) {} template <class Tr> inline typename ArrayHandleIterator<Tr>::value_type ArrayHandleIterator<Tr>::operator*() const { return Tr::to_cpp_type(*pos_); } template <class Tr> inline typename ArrayHandleIterator<Tr>::value_type ArrayHandleIterator<Tr>::operator[](difference_type offset) const { return Tr::to_cpp_type(pos_[offset]); } template <class Tr> inline ArrayHandleIterator<Tr>& ArrayHandleIterator<Tr>::operator++() { ++pos_; return *this; } template <class Tr> inline const ArrayHandleIterator<Tr> ArrayHandleIterator<Tr>::operator++(int) { return ArrayHandleIterator<Tr>(pos_++); } template <class Tr> inline ArrayHandleIterator<Tr>& ArrayHandleIterator<Tr>::operator+=(typename ArrayHandleIterator<Tr>::difference_type rhs) { pos_ += rhs; return *this; } template <class Tr> inline ArrayHandleIterator<Tr>& ArrayHandleIterator<Tr>::operator-=(typename ArrayHandleIterator<Tr>::difference_type rhs) { pos_ -= rhs; return *this; } template <class Tr> inline const ArrayHandleIterator<Tr> ArrayHandleIterator<Tr>::operator+(typename ArrayHandleIterator<Tr>::difference_type rhs) const { return ArrayHandleIterator<Tr>(pos_ + rhs); } template <class Tr> inline const ArrayHandleIterator<Tr> ArrayHandleIterator<Tr>::operator-(typename ArrayHandleIterator<Tr>::difference_type rhs) const { return ArrayHandleIterator<Tr>(pos_ - rhs); } template <class Tr> inline typename ArrayHandleIterator<Tr>::difference_type ArrayHandleIterator<Tr>::operator-(const ArrayHandleIterator<Tr>& rhs) const { return (pos_ - rhs.pos_); } template <class Tr> inline bool ArrayHandleIterator<Tr>::operator==(const ArrayHandleIterator<Tr>& rhs) const { return (pos_ == rhs.pos_); } template <class Tr> inline bool ArrayHandleIterator<Tr>::operator!=(const ArrayHandleIterator<Tr>& rhs) const { return (pos_ != rhs.pos_); } template <class Tr> inline bool ArrayHandleIterator<Tr>::operator<(const ArrayHandleIterator<Tr>& rhs) const { return (pos_ < rhs.pos_); } template <class Tr> inline bool ArrayHandleIterator<Tr>::operator>(const ArrayHandleIterator<Tr>& rhs) const { return (pos_ > rhs.pos_); } template <class Tr> inline bool ArrayHandleIterator<Tr>::operator<=(const ArrayHandleIterator<Tr>& rhs) const { return (pos_ <= rhs.pos_); } template <class Tr> inline bool ArrayHandleIterator<Tr>::operator>=(const ArrayHandleIterator<Tr>& rhs) const { return (pos_ >= rhs.pos_); } } // namespace Container_Helpers /**** Glib::ArrayHandle<> **************************************************/ template <class T, class Tr> template <class Cont> inline ArrayHandle<T,Tr>::ArrayHandle(const Cont& container) : size_ (Glib::Container_Helpers::ArraySourceTraits<Tr,Cont>::get_size(container)), parray_ (Glib::Container_Helpers::ArraySourceTraits<Tr,Cont>::get_data(container, size_)), ownership_ (Glib::Container_Helpers::ArraySourceTraits<Tr,Cont>::initial_ownership) {} template <class T, class Tr> inline ArrayHandle<T,Tr>::ArrayHandle(const typename ArrayHandle<T,Tr>::CType* array, size_t array_size, Glib::OwnershipType ownership) : size_ (array_size), parray_ (array), ownership_ (ownership) {} template <class T, class Tr> inline ArrayHandle<T,Tr>::ArrayHandle(const typename ArrayHandle<T,Tr>::CType* array, Glib::OwnershipType ownership) : size_ ((array) ? Glib::Container_Helpers::compute_array_size(array) : 0), parray_ (array), ownership_ (ownership) {} template <class T, class Tr> inline ArrayHandle<T,Tr>::ArrayHandle(const ArrayHandle<T,Tr>& other) : size_ (other.size_), parray_ (other.parray_), ownership_ (other.ownership_) { other.ownership_ = Glib::OWNERSHIP_NONE; } template <class T, class Tr> ArrayHandle<T,Tr>::~ArrayHandle() { if(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<CType*>(parray_)); } } template <class T, class Tr> inline typename ArrayHandle<T,Tr>::const_iterator ArrayHandle<T,Tr>::begin() const { return Glib::Container_Helpers::ArrayHandleIterator<Tr>(parray_); } template <class T, class Tr> inline typename ArrayHandle<T,Tr>::const_iterator ArrayHandle<T,Tr>::end() const { return Glib::Container_Helpers::ArrayHandleIterator<Tr>(parray_ + size_); } template <class T, class Tr> template <class U> inline ArrayHandle<T,Tr>::operator std::vector<U>() const { #ifdef GLIBMM_HAVE_TEMPLATE_SEQUENCE_CTORS return std::vector<U>(this->begin(), this->end()); #else std::vector<U> temp; temp.reserve(this->size()); Glib::Container_Helpers::fill_container(temp, this->begin(), this->end()); return temp; #endif } template <class T, class Tr> template <class U> inline ArrayHandle<T,Tr>::operator std::deque<U>() const { #ifdef GLIBMM_HAVE_TEMPLATE_SEQUENCE_CTORS return std::deque<U>(this->begin(), this->end()); #else std::deque<U> temp; Glib::Container_Helpers::fill_container(temp, this->begin(), this->end()); return temp; #endif } template <class T, class Tr> template <class U> inline ArrayHandle<T,Tr>::operator std::list<U>() const { #ifdef GLIBMM_HAVE_TEMPLATE_SEQUENCE_CTORS return std::list<U>(this->begin(), this->end()); #else std::list<U> temp; Glib::Container_Helpers::fill_container(temp, this->begin(), this->end()); return temp; #endif } template <class T, class Tr> template <class Cont> inline void ArrayHandle<T,Tr>::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 <class T, class Tr> template <class Out> inline void ArrayHandle<T,Tr>::copy(Out pdest) const { std::copy(this->begin(), this->end(), pdest); } template <class T, class Tr> inline const typename ArrayHandle<T,Tr>::CType* ArrayHandle<T,Tr>::data() const { return parray_; } template <class T, class Tr> inline size_t ArrayHandle<T,Tr>::size() const { return size_; } template <class T, class Tr> inline bool ArrayHandle<T,Tr>::empty() const { return (size_ == 0); } #endif /* DOXYGEN_SHOULD_SKIP_THIS */ } // namespace Glib #endif /* _GLIBMM_ARRAYHANDLE_H */