#ifndef _GLIBMM_SLISTHANDLE_H #define _GLIBMM_SLISTHANDLE_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 #include namespace Glib { namespace Container_Helpers { #ifndef DOXYGEN_SHOULD_SKIP_THIS /* Create and fill a GSList as efficient as possible. * This requires bidirectional iterators. */ template GSList* create_slist(Bi pbegin, Bi pend, Tr) { GSList* head = nullptr; while (pend != pbegin) { // Use & to force a warning if the iterator returns a temporary object. const void* const item = Tr::to_c_type(*&*--pend); head = g_slist_prepend(head, const_cast(item)); } return head; } /* Create a GSList from a 0-terminated input sequence. * Build it in reverse order and reverse the whole list afterwards, * because appending to the list would be horribly inefficient. */ template GSList* create_slist(For pbegin, Tr) { GSList* head = nullptr; while (*pbegin) { // Use & to force a warning if the iterator returns a temporary object. const void* const item = Tr::to_c_type(*&*pbegin); head = g_slist_prepend(head, const_cast(item)); ++pbegin; } return g_slist_reverse(head); } /* Convert from any container that supports bidirectional iterators. */ template struct SListSourceTraits { static GSList* get_data(const Cont& cont) { return Glib::Container_Helpers::create_slist(cont.begin(), cont.end(), 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. */ template struct SListSourceTraits { static GSList* get_data(const Cont* array) { return (array) ? Glib::Container_Helpers::create_slist(array, Tr()) : nullptr; } static const Glib::OwnershipType initial_ownership = Glib::OWNERSHIP_SHALLOW; }; template struct SListSourceTraits : SListSourceTraits { }; /* Convert from a 0-terminated array. The Cont argument must be a pointer * to the first element. For consistency, the array must be 0-terminated, * even though the array size is known at compile time. */ template struct SListSourceTraits { static GSList* get_data(const Cont* array) { return Glib::Container_Helpers::create_slist(array, array + (N - 1), Tr()); } static const Glib::OwnershipType initial_ownership = Glib::OWNERSHIP_SHALLOW; }; template struct SListSourceTraits : SListSourceTraits { }; #endif /* DOXYGEN_SHOULD_SKIP_THIS */ /** * @ingroup ContHelpers */ template class SListHandleIterator { public: using CppType = typename Tr::CppType; using CType = typename Tr::CType; using iterator_category = std::forward_iterator_tag; using value_type = CppType; using difference_type = std::ptrdiff_t; using reference = value_type; using pointer = void; explicit inline SListHandleIterator(const GSList* node); inline value_type operator*() const; inline SListHandleIterator& operator++(); inline const SListHandleIterator operator++(int); inline bool operator==(const SListHandleIterator& rhs) const; inline bool operator!=(const SListHandleIterator& rhs) const; private: const GSList* node_; }; } // namespace Container_Helpers // TODO: Remove this when we can break glibmm API. /** 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 SListHandle { 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::SListHandleIterator; using iterator = Glib::Container_Helpers::SListHandleIterator; template inline SListHandle(const Cont& container); // Take over ownership of a GSList created by GTK+ functions. inline SListHandle(GSList* glist, Glib::OwnershipType ownership); // Copying clears the ownership flag of the source handle. inline SListHandle(const SListHandle& other); ~SListHandle() 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 GSList* data() const; inline std::size_t size() const; inline bool empty() const; private: GSList* pslist_; mutable Glib::OwnershipType ownership_; // No copy assignment. SListHandle& operator=(const SListHandle&); }; /***************************************************************************/ /* Inline implementation */ /***************************************************************************/ #ifndef DOXYGEN_SHOULD_SKIP_THIS namespace Container_Helpers { /**** Glib::Container_Helpers::SListHandleIterator<> ***********************/ template inline SListHandleIterator::SListHandleIterator(const GSList* node) : node_(node) { } template inline typename SListHandleIterator::value_type SListHandleIterator::operator*() const { return Tr::to_cpp_type(static_cast(node_->data)); } template inline SListHandleIterator& SListHandleIterator::operator++() { node_ = node_->next; return *this; } template inline const SListHandleIterator SListHandleIterator::operator++(int) { const SListHandleIterator tmp(*this); node_ = node_->next; return tmp; } template inline bool SListHandleIterator::operator==(const SListHandleIterator& rhs) const { return (node_ == rhs.node_); } template inline bool SListHandleIterator::operator!=(const SListHandleIterator& rhs) const { return (node_ != rhs.node_); } } // namespace Container_Helpers /**** Glib::SListHandle<> **************************************************/ template template inline SListHandle::SListHandle(const Cont& container) : pslist_(Glib::Container_Helpers::SListSourceTraits::get_data(container)), ownership_(Glib::Container_Helpers::SListSourceTraits::initial_ownership) { } template inline SListHandle::SListHandle(GSList* gslist, Glib::OwnershipType ownership) : pslist_(gslist), ownership_(ownership) { } template inline SListHandle::SListHandle(const SListHandle& other) : pslist_(other.pslist_), ownership_(other.ownership_) { other.ownership_ = Glib::OWNERSHIP_NONE; } template SListHandle::~SListHandle() noexcept { if (ownership_ != Glib::OWNERSHIP_NONE) { if (ownership_ != Glib::OWNERSHIP_SHALLOW) { // Deep ownership: release each container element. for (GSList* node = pslist_; node != nullptr; node = node->next) Tr::release_c_type(static_cast(node->data)); } g_slist_free(pslist_); } } template inline typename SListHandle::const_iterator SListHandle::begin() const { return Glib::Container_Helpers::SListHandleIterator(pslist_); } template inline typename SListHandle::const_iterator SListHandle::end() const { return Glib::Container_Helpers::SListHandleIterator(nullptr); } template template inline SListHandle::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 SListHandle::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 SListHandle::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 SListHandle::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 SListHandle::copy(Out pdest) const { std::copy(this->begin(), this->end(), pdest); } template inline GSList* SListHandle::data() const { return pslist_; } template inline std::size_t SListHandle::size() const { return g_slist_length(pslist_); } template inline bool SListHandle::empty() const { return (pslist_ == nullptr); } #endif /* DOXYGEN_SHOULD_SKIP_THIS */ } // namespace Glib #endif /* _GLIBMM_SLISTHANDLE_H */