summaryrefslogtreecommitdiff
path: root/libs/glibmm2/glibmm/listhandle.h
diff options
context:
space:
mode:
Diffstat (limited to 'libs/glibmm2/glibmm/listhandle.h')
-rw-r--r--libs/glibmm2/glibmm/listhandle.h406
1 files changed, 406 insertions, 0 deletions
diff --git a/libs/glibmm2/glibmm/listhandle.h b/libs/glibmm2/glibmm/listhandle.h
new file mode 100644
index 0000000000..94b366d91b
--- /dev/null
+++ b/libs/glibmm2/glibmm/listhandle.h
@@ -0,0 +1,406 @@
+// -*- c++ -*-
+#ifndef _GLIBMM_LISTHANDLE_H
+#define _GLIBMM_LISTHANDLE_H
+
+/* $Id$ */
+
+/* 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 <glib/glist.h>
+#include <glibmm/containerhandle_shared.h>
+
+
+namespace Glib
+{
+
+namespace Container_Helpers
+{
+
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+
+/* Create and fill a GList as efficient as possible.
+ * This requires bidirectional iterators.
+ */
+template <class Bi, class Tr>
+GList* create_list(Bi pbegin, Bi pend, Tr)
+{
+ GList* head = 0;
+
+ 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_list_prepend(head, const_cast<void*>(item));
+ }
+
+ return head;
+}
+
+/* Create a GList 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 <class For, class Tr>
+GList* create_list(For pbegin, Tr)
+{
+ GList* head = 0;
+
+ 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_list_prepend(head, const_cast<void*>(item));
+ ++pbegin;
+ }
+
+ return g_list_reverse(head);
+}
+
+
+/* Convert from any container that supports bidirectional iterators.
+ */
+template <class Tr, class Cont>
+struct ListSourceTraits
+{
+ static GList* get_data(const Cont& cont)
+ { return Glib::Container_Helpers::create_list(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 <class Tr, class Cont>
+struct ListSourceTraits<Tr,Cont*>
+{
+ static GList* get_data(const Cont* array)
+ { return (array) ? Glib::Container_Helpers::create_list(array, Tr()) : 0; }
+
+ static const Glib::OwnershipType initial_ownership = Glib::OWNERSHIP_SHALLOW;
+};
+
+template <class Tr, class Cont>
+struct ListSourceTraits<Tr,const Cont*> : ListSourceTraits<Tr,Cont*>
+{};
+
+/* 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 <class Tr, class Cont, size_t N>
+struct ListSourceTraits<Tr,Cont[N]>
+{
+ static GList* get_data(const Cont* array)
+ { return Glib::Container_Helpers::create_list(array, array + (N - 1), Tr()); }
+
+ static const Glib::OwnershipType initial_ownership = Glib::OWNERSHIP_SHALLOW;
+};
+
+template <class Tr, class Cont, size_t N>
+struct ListSourceTraits<Tr,const Cont[N]> : ListSourceTraits<Tr,Cont[N]>
+{};
+
+#endif /* DOXYGEN_SHOULD_SKIP_THIS */
+
+
+/**
+ * @ingroup ContHelpers
+ * 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.
+ */
+template <class Tr>
+class ListHandleIterator
+{
+public:
+ typedef typename Tr::CppType CppType;
+ typedef typename Tr::CType CType;
+
+ typedef std::forward_iterator_tag iterator_category;
+ typedef CppType value_type;
+ typedef ptrdiff_t difference_type;
+ typedef value_type reference;
+ typedef void pointer;
+
+ explicit inline ListHandleIterator(const GList* node);
+
+ inline value_type operator*() const;
+ inline ListHandleIterator<Tr> & operator++();
+ inline const ListHandleIterator<Tr> operator++(int);
+
+ inline bool operator==(const ListHandleIterator<Tr>& rhs) const;
+ inline bool operator!=(const ListHandleIterator<Tr>& rhs) const;
+
+private:
+ const GList* node_;
+};
+
+} // namespace Container_Helpers
+
+
+/**
+ * @ingroup ContHandles
+ */
+template < class T, class Tr = Glib::Container_Helpers::TypeTraits<T> >
+class ListHandle
+{
+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::ListHandleIterator<Tr> const_iterator;
+ typedef Glib::Container_Helpers::ListHandleIterator<Tr> iterator;
+
+ template <class Cont> inline
+ ListHandle(const Cont& container);
+
+ // Take over ownership of an array created by GTK+ functions.
+ inline ListHandle(GList* glist, Glib::OwnershipType ownership);
+
+ // Copying clears the ownership flag of the source handle.
+ inline ListHandle(const ListHandle<T,Tr>& other);
+
+ ~ListHandle();
+
+ 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 GList* data() const;
+ inline size_t size() const;
+ inline bool empty() const;
+
+private:
+ GList * plist_;
+ mutable Glib::OwnershipType ownership_;
+
+ // No copy assignment.
+ ListHandle<T,Tr>& operator=(const ListHandle<T,Tr>&);
+};
+
+
+/***************************************************************************/
+/* Inline implementation */
+/***************************************************************************/
+
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+
+namespace Container_Helpers
+{
+
+/**** Glib::Container_Helpers::ListHandleIterator<> ************************/
+
+template <class Tr> inline
+ListHandleIterator<Tr>::ListHandleIterator(const GList* node)
+:
+ node_ (node)
+{}
+
+template <class Tr> inline
+typename ListHandleIterator<Tr>::value_type ListHandleIterator<Tr>::operator*() const
+{
+ return Tr::to_cpp_type(static_cast<typename Tr::CTypeNonConst>(node_->data));
+}
+
+template <class Tr> inline
+ListHandleIterator<Tr>& ListHandleIterator<Tr>::operator++()
+{
+ node_ = node_->next;
+ return *this;
+}
+
+template <class Tr> inline
+const ListHandleIterator<Tr> ListHandleIterator<Tr>::operator++(int)
+{
+ const ListHandleIterator<Tr> tmp (*this);
+ node_ = node_->next;
+ return tmp;
+}
+
+template <class Tr> inline
+bool ListHandleIterator<Tr>::operator==(const ListHandleIterator<Tr>& rhs) const
+{
+ return (node_ == rhs.node_);
+}
+
+template <class Tr> inline
+bool ListHandleIterator<Tr>::operator!=(const ListHandleIterator<Tr>& rhs) const
+{
+ return (node_ != rhs.node_);
+}
+
+} // namespace Container_Helpers
+
+
+/**** Glib::ListHandle<> ***************************************************/
+
+template <class T, class Tr>
+ template <class Cont>
+inline
+ListHandle<T,Tr>::ListHandle(const Cont& container)
+:
+ plist_ (Glib::Container_Helpers::ListSourceTraits<Tr,Cont>::get_data(container)),
+ ownership_ (Glib::Container_Helpers::ListSourceTraits<Tr,Cont>::initial_ownership)
+{}
+
+template <class T, class Tr> inline
+ListHandle<T,Tr>::ListHandle(GList* glist, Glib::OwnershipType ownership)
+:
+ plist_ (glist),
+ ownership_ (ownership)
+{}
+
+template <class T, class Tr> inline
+ListHandle<T,Tr>::ListHandle(const ListHandle<T,Tr>& other)
+:
+ plist_ (other.plist_),
+ ownership_ (other.ownership_)
+{
+ other.ownership_ = Glib::OWNERSHIP_NONE;
+}
+
+template <class T, class Tr>
+ListHandle<T,Tr>::~ListHandle()
+{
+ if(ownership_ != Glib::OWNERSHIP_NONE)
+ {
+ if(ownership_ != Glib::OWNERSHIP_SHALLOW)
+ {
+ // Deep ownership: release each container element.
+ for(GList* node = plist_; node != 0; node = node->next)
+ Tr::release_c_type(static_cast<typename Tr::CTypeNonConst>(node->data));
+ }
+ g_list_free(plist_);
+ }
+}
+
+template <class T, class Tr> inline
+typename ListHandle<T,Tr>::const_iterator ListHandle<T,Tr>::begin() const
+{
+ return Glib::Container_Helpers::ListHandleIterator<Tr>(plist_);
+}
+
+template <class T, class Tr> inline
+typename ListHandle<T,Tr>::const_iterator ListHandle<T,Tr>::end() const
+{
+ return Glib::Container_Helpers::ListHandleIterator<Tr>(0);
+}
+
+template <class T, class Tr>
+ template <class U>
+inline
+ListHandle<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
+ListHandle<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
+ListHandle<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 ListHandle<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 ListHandle<T,Tr>::copy(Out pdest) const
+{
+ std::copy(this->begin(), this->end(), pdest);
+}
+
+template <class T, class Tr> inline
+GList* ListHandle<T,Tr>::data() const
+{
+ return plist_;
+}
+
+template <class T, class Tr> inline
+size_t ListHandle<T,Tr>::size() const
+{
+ return g_list_length(plist_);
+}
+
+template <class T, class Tr> inline
+bool ListHandle<T,Tr>::empty() const
+{
+ return (plist_ == 0);
+}
+
+#endif /* DOXYGEN_SHOULD_SKIP_THIS */
+
+} // namespace Glib
+
+
+#endif /* _GLIBMM_LISTHANDLE_H */
+