1 #ifndef _GLIBMM_VECTORUTILS_H
2 #define _GLIBMM_VECTORUTILS_H
3 
4 /* Copyright(C) 2011 The glibmm Development Team
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
18  */
19 #include <vector>
20 #include <glibmmconfig.h>
21 #include <glibmm/containerhandle_shared.h>
22 #include <cstddef>
23 
24 /* There are three types of functions:
25  * 1. Returning a container.
26  * 2. Taking a container as a parameter.
27  * 3. Returning a container as a parameter.
28  *
29  * Ad 1. When a function returns a container it can own:
30  * a) a container and data, callers ownership - none (caller owns neither
31  *    container nor data),
32  * b) only data, callers ownership - shallow (caller owns only a container),
33  * c) nothing, callers ownership - deep (caller owns both container and data).
34  *
35  * Above cases are simple - here we just create a vector with copies of returned
36  * container's data and then, depending on ownership transfer, we destroy
37  * nothing or container only or both container and data.
38  *
39  * Ad 2. When a function takes a container as a parameter it can take
40  * an ownership of:
41  * a) a container and data, callers ownership - none (caller loses ownership
42  *    of both container and data),
43  * b) only data, callers ownership - shallow (caller loses ownership of data),
44  * c) nothing, callers ownership - deep (caller does not lose ownership
45  *    to both container and data).
46  *
47  * Above cases are also simple - from given vector we create a C copy
48  * of container and data, pass them to function and then, depending on ownership
49  * transfer, we destroy nothing or container only or both container and data.
50  * But note that a) and b) cases are probably wrong by design, so we don't cover
51  * them here.
52  *
53  * Ad 3. Such functions are best wrapped by hand if we want to use a vector
54  * here.
55  */
56 
57 namespace Glib
58 {
59 
60 namespace Container_Helpers
61 {
62 
63 #ifndef DOXYGEN_SHOULD_SKIP_THIS
64 
65 // TODO: docs!
66 
67 /* Count the number of elements in a 0-terminated sequence.
68  */
69 template <class T>
70 inline std::size_t
compute_array_size2(const T * array)71 compute_array_size2(const T* array)
72 {
73   if (array)
74   {
75     const T* pend(array);
76 
77     while (*pend)
78     {
79       ++pend;
80     }
81     return (pend - array);
82   }
83 
84   return 0;
85 }
86 
87 /* Allocate and fill a 0-terminated array.  The size argument
88  * specifies the number of elements in the input sequence.
89  */
90 template <class Tr>
91 typename Tr::CType*
create_array(typename std::vector<typename Tr::CppType>::const_iterator pbegin,std::size_t size)92 create_array(typename std::vector<typename Tr::CppType>::const_iterator pbegin, std::size_t size)
93 {
94   using CType = typename Tr::CType;
95 
96   CType* const array(static_cast<CType*>(g_malloc((size + 1) * sizeof(CType))));
97   CType* const array_end(array + size);
98 
99   for (CType* pdest(array); pdest != array_end; ++pdest)
100   {
101     // Use & to force a warning if the iterator returns a temporary object.
102     *pdest = Tr::to_c_type(*&*pbegin);
103     ++pbegin;
104   }
105   *array_end = CType();
106 
107   return array;
108 }
109 
110 /* first class function for bools, because std::vector<bool> is a specialization
111  * which does not conform to being an STL container.
112  */
113 GLIBMM_API
114 gboolean* create_bool_array(std::vector<bool>::const_iterator pbegin, std::size_t size);
115 
116 /* Create and fill a GList as efficient as possible.
117  * This requires bidirectional iterators.
118  */
119 template <class Tr>
120 GList*
create_glist(const typename std::vector<typename Tr::CppType>::const_iterator pbegin,typename std::vector<typename Tr::CppType>::const_iterator pend)121 create_glist(const typename std::vector<typename Tr::CppType>::const_iterator pbegin,
122   typename std::vector<typename Tr::CppType>::const_iterator pend)
123 {
124   GList* head(nullptr);
125 
126   while (pend != pbegin)
127   {
128     // Use & to force a warning if the iterator returns a temporary object.
129     const void* const item(Tr::to_c_type(*&*--pend));
130     head = g_list_prepend(head, const_cast<void*>(item));
131   }
132 
133   return head;
134 }
135 
136 /* Create and fill a GSList as efficient as possible.
137  * This requires bidirectional iterators.
138  */
139 template <class Tr>
140 GSList*
create_gslist(const typename std::vector<typename Tr::CppType>::const_iterator pbegin,typename std::vector<typename Tr::CppType>::const_iterator pend)141 create_gslist(const typename std::vector<typename Tr::CppType>::const_iterator pbegin,
142   typename std::vector<typename Tr::CppType>::const_iterator pend)
143 {
144   GSList* head(nullptr);
145 
146   while (pend != pbegin)
147   {
148     // Use & to force a warning if the iterator returns a temporary object.
149     const void* const item(Tr::to_c_type(*&*--pend));
150     head = g_slist_prepend(head, const_cast<void*>(item));
151   }
152 
153   return head;
154 }
155 
156 #endif /* DOXYGEN_SHOULD_SKIP_THIS */
157 
158 template <class Tr>
159 class ArrayIterator
160 {
161 public:
162   using CppType = typename Tr::CppType;
163   using CType = typename Tr::CType;
164 
165   using iterator_category = std::random_access_iterator_tag;
166   using value_type = CppType;
167   using difference_type = std::ptrdiff_t;
168   using reference = value_type;
169   using pointer = void;
170 
171   explicit inline ArrayIterator(const CType* pos);
172 
173   inline value_type operator*() const;
174   inline value_type operator[](difference_type offset) const;
175 
176   inline ArrayIterator<Tr>& operator++();
177   inline const ArrayIterator<Tr> operator++(int);
178 
179   // All this random access stuff is only there because STL algorithms
180   // usually have optimized specializations for random access iterators,
181   // and we don't want to give away efficiency for nothing.
182   inline ArrayIterator<Tr>& operator+=(difference_type rhs);
183   inline ArrayIterator<Tr>& operator-=(difference_type rhs);
184   inline const ArrayIterator<Tr> operator+(difference_type rhs) const;
185   inline const ArrayIterator<Tr> operator-(difference_type rhs) const;
186   inline difference_type operator-(const ArrayIterator<Tr>& rhs) const;
187 
188   inline bool operator==(const ArrayIterator<Tr>& rhs) const;
189   inline bool operator!=(const ArrayIterator<Tr>& rhs) const;
190   inline bool operator<(const ArrayIterator<Tr>& rhs) const;
191   inline bool operator>(const ArrayIterator<Tr>& rhs) const;
192   inline bool operator<=(const ArrayIterator<Tr>& rhs) const;
193   inline bool operator>=(const ArrayIterator<Tr>& rhs) const;
194 
195 private:
196   const CType* pos_;
197 };
198 
199 template <class Tr>
200 class ListIterator
201 {
202 public:
203   using CppType = typename Tr::CppType;
204   using CType = typename Tr::CType;
205 
206   using iterator_category = std::forward_iterator_tag;
207   using value_type = CppType;
208   using difference_type = std::ptrdiff_t;
209   using reference = value_type;
210   using pointer = void;
211 
212   explicit inline ListIterator(const GList* node);
213 
214   inline value_type operator*() const;
215   inline ListIterator<Tr>& operator++();
216   inline const ListIterator<Tr> operator++(int);
217 
218   inline bool operator==(const ListIterator<Tr>& rhs) const;
219   inline bool operator!=(const ListIterator<Tr>& rhs) const;
220 
221 private:
222   const GList* node_;
223 };
224 
225 template <class Tr>
226 class SListIterator
227 {
228 public:
229   using CppType = typename Tr::CppType;
230   using CType = typename Tr::CType;
231 
232   using iterator_category = std::forward_iterator_tag;
233   using value_type = CppType;
234   using difference_type = std::ptrdiff_t;
235   using reference = value_type;
236   using pointer = void;
237 
238   explicit inline SListIterator(const GSList* node);
239 
240   inline value_type operator*() const;
241   inline SListIterator<Tr>& operator++();
242   inline const SListIterator<Tr> operator++(int);
243 
244   inline bool operator==(const SListIterator<Tr>& rhs) const;
245   inline bool operator!=(const SListIterator<Tr>& rhs) const;
246 
247 private:
248   const GSList* node_;
249 };
250 
251 /** A keeper class for C array.
252  *
253  * Primarily used by C++ wrappers like gtkmm.
254  *
255  * Its main purpose is to free its data when they are not needed. What will be
256  * destroyed depends on passed ownership upon construction.
257  *
258  * The most common usage of Glib::ArrayKeeper is getting its data when converting
259  * std::vector to a C array:
260  * @code
261  * void G::Temp::do_something(const std::vector<int>& v)
262  * {
263  *   g_temp_do_something(gobj(), Glib::ArrayHandler<int>::vector_to_array(v).data());
264  * }
265  * @endcode
266  * Variables of this class are seldom defined directly - it is mostly used as
267  * a temporary variable returned by Glib::ArrayHandler::vector_to_array().
268  *
269  * Note that the usage above is correct with regards to C++ standard point 12.2.3.
270  * That means that data returned by data() method is valid through whole
271  * g_temp_do_something function and is destroyed, when this function returns.
272  */
273 template <typename Tr>
274 class ArrayKeeper
275 {
276 public:
277   using CppType = typename Tr::CppType;
278   using CType = typename Tr::CType;
279 
280   /** Constructs an ArrayKeeper holding @a array of size @a array_size.
281    * @a ownership tells what should be destroyed with keeper destruction:
282    * <ul>
283    * <li>Glib::OWNERSHIP_NONE - keeper won't destroy data it holds.</li>
284    * <li>Glib::OWNERSHIP_SHALLOW - keeper will destroy only container it holds.</li>
285    * <li>Glib::OWNERSHIP_DEEP - keeper will destroy data and container it holds.</li>
286    * </ul>
287    *
288    * @param array - C array to hold.
289    * @param array_size - length of @a array.
290    * @param ownership - ownership definition.
291    */
292   explicit inline ArrayKeeper(
293     const CType* array, std::size_t array_size, Glib::OwnershipType ownership);
294   inline ArrayKeeper(const ArrayKeeper& keeper);
295   ~ArrayKeeper() noexcept;
296 
297   /** Gets data the keeper holds.
298    *
299    * Note that this data is owned by the keeper, so there is no need to free it.
300    *
301    * @return C array owned by ArrayKeeper.
302    */
303   inline CType* data() const;
304 
305 private:
306   CType* array_;
307   std::size_t array_size_;
308   mutable Glib::OwnershipType ownership_;
309 };
310 
311 /** A keeper class for GList.
312  *
313  * Primarily used by C++ wrappers like gtkmm.
314  *
315  * Its main purpose is to free its data when they are not needed. What will be
316  * destroyed depends on passed ownership upon construction.
317  *
318  * The most common usage of Glib::GListKeeper is getting its data when converting
319  * std::vector to a GList*:
320  * @code
321  * void G::Temp::do_something(const std::vector<int>& v)
322  * {
323  *   g_temp_do_something(gobj(), Glib::ListHandler<int>::vector_to_list(v).data());
324  * }
325  * @endcode
326  * Variables of this class are seldom defined directly - it is mostly used as
327  * a temporary variable returned by Glib::ListHandler::vector_to_list().
328  *
329  * Note that the usage above is correct with regards to C++ standard point 12.2.3.
330  * That means that data returned by data() method is valid through whole
331  * g_temp_do_something function and is destroyed, when this function returns.
332  */
333 template <typename Tr>
334 class GListKeeper
335 {
336 public:
337   using CppType = typename Tr::CppType;
338   using CType = typename Tr::CType;
339 
340   /** Constructs an GListKeeper holding @a glist.
341    * @a ownership tells what should be destroyed with keeper destruction:
342    * <ul>
343    * <li>Glib::OWNERSHIP_NONE - keeper won't destroy data it holds.</li>
344    * <li>Glib::OWNERSHIP_SHALLOW - keeper will destroy only container it holds.</li>
345    * <li>Glib::OWNERSHIP_DEEP - keeper will destroy data and container it holds.</li>
346    * </ul>
347    *
348    * @param glist - GList* to hold.
349    * @param ownership - ownership definition.
350    */
351   explicit inline GListKeeper(const GList* glist, Glib::OwnershipType ownership);
352   inline GListKeeper(const GListKeeper& keeper);
353   ~GListKeeper() noexcept;
354 
355   /** Gets data the keeper holds.
356    *
357    * Note that this data is owned by the keeper, so there is no need to free it.
358    *
359    * @return GList* owned by GListKeeper.
360    */
361   inline GList* data() const;
362 
363 private:
364   GList* glist_;
365   mutable Glib::OwnershipType ownership_;
366 };
367 
368 /** A keeper class for GSList.
369  *
370  * Primarily used by C++ wrappers like gtkmm.
371  *
372  * Its main purpose is to free its data when they are not needed. What will be
373  * destroyed depends on passed ownership upon construction.
374  *
375  * The most common usage of Glib::GSListKeeper is getting its data when converting
376  * std::vector to a GSList*:
377  * @code
378  * void G::Temp::do_something(const std::vector<int>& v)
379  * {
380  *   g_temp_do_something(gobj(), Glib::SListHandler<int>::vector_to_slist(v).data());
381  * }
382  * @endcode
383  * Variables of this class are seldom defined directly - it is mostly used as
384  * a temporary variable returned by Glib::SListHandler::vector_to_slist().
385  *
386  * Note that the usage above is correct with regards to C++ standard point 12.2.3.
387  * That means that data returned by data() method is valid through whole
388  * g_temp_do_something function and is destroyed, when this function returns.
389  */
390 template <typename Tr>
391 class GSListKeeper
392 {
393 public:
394   using CppType = typename Tr::CppType;
395   using CType = typename Tr::CType;
396 
397   /** Constructs an GSListKeeper holding @a gslist.
398    * @a ownership tells what should be destroyed with keeper destruction:
399    * <ul>
400    * <li>Glib::OWNERSHIP_NONE - keeper won't destroy data it holds.</li>
401    * <li>Glib::OWNERSHIP_SHALLOW - keeper will destroy only container it holds.</li>
402    * <li>Glib::OWNERSHIP_DEEP - keeper will destroy data and container it holds.</li>
403    * </ul>
404    *
405    * @param gslist - GList* to hold.
406    * @param ownership - ownership definition.
407    */
408   explicit inline GSListKeeper(const GSList* gslist, Glib::OwnershipType ownership);
409   inline GSListKeeper(const GSListKeeper& keeper);
410   ~GSListKeeper() noexcept;
411 
412   /** Gets data the keeper holds.
413    *
414    * Note that this data is owned by the keeper, so there is no need to free it.
415    *
416    * @return GSList* owned by GSListKeeper.
417    */
418   inline GSList* data() const;
419 
420 private:
421   GSList* gslist_;
422   mutable Glib::OwnershipType ownership_;
423 };
424 
425 } // namespace Container_Helpers
426 
427 // Note that this is a struct instead of templated functions because standard template arguments
428 // for function templates is a C++0x feature.
429 /** A utility for converting between std::vector and plain C arrays.
430  * This would normally only be used by glibmm or gtkmm itself, or similar
431  * libraries that wrap C APIs.
432  *
433  * For instance:
434  * @code
435  * std::vector<Glib::ustring> PixbufFormat::get_mime_types() const
436  * {
437  *   return
438  * Glib::ArrayHandler<Glib::ustring>::array_to_vector(gdk_pixbuf_format_get_mime_types(const_cast<GdkPixbufFormat*>(gobj())),
439  * Glib::OWNERSHIP_DEEP);
440  * }
441  * @endcode
442  * or
443  * @code
444  * void Display::store_clipboard(const Glib::RefPtr<Gdk::Window>& clipboard_window, guint32 time_,
445  * const std::vector<Glib::ustring>& targets)
446  * {
447  *   if (!targets.size ())
448  *   {
449  *     gdk_display_store_clipboard(gobj(),
450  *                                 Glib::unwrap (clipboard_window),
451  *                                 time_,
452  *                                 Glib::ArrayHandler<Glib::ustring,
453  * AtomUstringTraits>::vector_to_array(targets).data (),
454  *                                 targets.size ());
455  *   }
456  * }
457  * @endcode
458  * Note that usage below is wrong - data() returns a pointer to data owned by
459  * a temporary ArrayKeeper returned by vector_to_array(), which is destroyed at
460  * the end of this instruction. For details, see Glib::ArrayKeeper.
461  * @code
462  * const char** array = Glib::ArrayHandler<Glib::ustring>::vector_to_array(vec).data ();
463  * @endcode
464  */
465 template <typename T, typename Tr = Glib::Container_Helpers::TypeTraits<T>>
466 class ArrayHandler
467 {
468 public:
469   using CType = typename Tr::CType;
470   using CppType = T;
471   using VectorType = std::vector<CppType>;
472   using ArrayKeeperType = typename Glib::Container_Helpers::ArrayKeeper<Tr>;
473   using ArrayIteratorType = typename Glib::Container_Helpers::ArrayIterator<Tr>;
474 
475   // maybe think about using C++0x move constructors?
476   static VectorType array_to_vector(
477     const CType* array, std::size_t array_size, Glib::OwnershipType ownership);
478   static VectorType array_to_vector(const CType* array, Glib::OwnershipType ownership);
479   static ArrayKeeperType vector_to_array(const VectorType& vector);
480 };
481 
482 template <>
483 class GLIBMM_API ArrayHandler<bool>
484 {
485 public:
486   using CType = gboolean;
487   using CppType = bool;
488   using VectorType = std::vector<bool>;
489   typedef Glib::Container_Helpers::ArrayKeeper<Glib::Container_Helpers::TypeTraits<bool>>
490     ArrayKeeperType;
491   typedef Glib::Container_Helpers::ArrayIterator<Glib::Container_Helpers::TypeTraits<bool>>
492     ArrayIteratorType;
493 
494   // maybe think about using C++0x move constructors?
495   static VectorType array_to_vector(
496     const CType* array, std::size_t array_size, Glib::OwnershipType ownership);
497   static VectorType array_to_vector(const CType* array, Glib::OwnershipType ownership);
498   static ArrayKeeperType vector_to_array(const VectorType& vector);
499 };
500 
501 /** A utility for converting between std::vector and GList.
502  * This would normally only be used by glibmm or gtkmm itself, or similar
503  * libraries that wrap C APIs.
504  *
505  * For instance:
506  * @code
507  * std::vector< Glib::RefPtr<Window> > Window::get_children()
508  * {
509  *   return Glib::ListHandler<Glib::RefPtr<Window>
510  * >::list_to_vector(gdk_window_get_children(gobj()), Glib::OWNERSHIP_SHALLOW);
511  * }
512  * @endcode
513  * or
514  * @code
515  * void Window::set_icon_list(const std::vector< Glib::RefPtr<Gdk::Pixbuf> >& pixbufs)
516  * {
517  *   gdk_window_set_icon_list(gobj(), Glib::ListHandler<Glib::RefPtr<Gdk::Pixbuf>
518  * >::vector_to_list(pixbufs).data ());
519  * }
520  * @endcode
521  * Note that usage below is wrong - data() returns a pointer to data owned by
522  * a temporary ListKeeper returned by vector_to_list(), which is destroyed at
523  * the end of this instruction. For details, see Glib::ListKeeper.
524  * @code
525  * GList* glist = Glib::ListHandler<Glib::RefPtr<Gdk::Pixbuf> >::vector_to_list(pixbufs).data();
526  * @endcode
527  */
528 template <typename T, typename Tr = Glib::Container_Helpers::TypeTraits<T>>
529 class ListHandler
530 {
531 public:
532   using CType = typename Tr::CType;
533   using CppType = T;
534   using VectorType = std::vector<CppType>;
535   using GListKeeperType = typename Glib::Container_Helpers::GListKeeper<Tr>;
536   using ListIteratorType = typename Glib::Container_Helpers::ListIterator<Tr>;
537 
538   // maybe think about using C++0x move constructors?
539   static VectorType list_to_vector(GList* glist, Glib::OwnershipType ownership);
540   static GListKeeperType vector_to_list(const VectorType& vector);
541 };
542 
543 /** A utility for converting between std::vector and GSList.
544  * This would normally only be used by glibmm or gtkmm itself, or similar
545  * libraries that wrap C APIs.
546  *
547  * For instance:
548  * @code
549  * std::vector< Glib::RefPtr<Display> > DisplayManager::list_displays()
550  * {
551  *   return Glib::SListHandler<Glib::RefPtr<Display>
552  * >::slist_to_vector(gdk_display_manager_list_displays(gobj()), Glib::OWNERSHIP_SHALLOW);
553  * }
554  * @endcode
555  * or
556  * @code
557  * void Stuff::set_slist(const std::vector<int>& ints)
558  * {
559  *   g_stuff_set_slist(gobj(), Glib::SListHandler<int>::vector_to_slist(ints).data ());
560  * }
561  * @endcode
562  * Note that usage below is wrong - data() returns a pointer to data owned by
563  * a temporary SListKeeper returned by vector_to_slist(), which is destroyed at
564  * the end of this instruction. For details, see Glib::SListKeeper.
565  * @code
566  * GSList* gslist = Glib::SListHandler< Glib::RefPtr<Display> >::vector_to_slist(vec).data();
567  * @endcode
568  */
569 template <typename T, typename Tr = Glib::Container_Helpers::TypeTraits<T>>
570 class SListHandler
571 {
572 public:
573   using CType = typename Tr::CType;
574   using CppType = T;
575   using VectorType = std::vector<CppType>;
576   using GSListKeeperType = typename Glib::Container_Helpers::GSListKeeper<Tr>;
577   using SListIteratorType = typename Glib::Container_Helpers::SListIterator<Tr>;
578 
579   // maybe think about using C++0x move constructors?
580   static VectorType slist_to_vector(GSList* gslist, Glib::OwnershipType ownership);
581   static GSListKeeperType vector_to_slist(const VectorType& vector);
582 };
583 
584 /***************************************************************************/
585 /*  Inline implementation                                                  */
586 /***************************************************************************/
587 
588 #ifndef DOXYGEN_SHOULD_SKIP_THIS
589 
590 namespace Container_Helpers
591 {
592 
593 /**** Glib::Container_Helpers::ArrayIterator<> ***********************/
594 
595 template <class Tr>
ArrayIterator(const CType * pos)596 inline ArrayIterator<Tr>::ArrayIterator(const CType* pos) : pos_(pos)
597 {
598 }
599 
600 template <class Tr>
601 inline typename ArrayIterator<Tr>::value_type ArrayIterator<Tr>::operator*() const
602 {
603   return Tr::to_cpp_type(*pos_);
604 }
605 
606 template <class Tr>
607 inline
608   typename ArrayIterator<Tr>::value_type ArrayIterator<Tr>::operator[](difference_type offset) const
609 {
610   return Tr::to_cpp_type(pos_[offset]);
611 }
612 
613 template <class Tr>
614 inline ArrayIterator<Tr>& ArrayIterator<Tr>::operator++()
615 {
616   ++pos_;
617   return *this;
618 }
619 
620 template <class Tr>
621 inline const ArrayIterator<Tr> ArrayIterator<Tr>::operator++(int)
622 {
623   return ArrayIterator<Tr>(pos_++);
624 }
625 
626 template <class Tr>
627 inline ArrayIterator<Tr>&
628 ArrayIterator<Tr>::operator+=(typename ArrayIterator<Tr>::difference_type rhs)
629 {
630   pos_ += rhs;
631   return *this;
632 }
633 
634 template <class Tr>
635 inline ArrayIterator<Tr>&
636 ArrayIterator<Tr>::operator-=(typename ArrayIterator<Tr>::difference_type rhs)
637 {
638   pos_ -= rhs;
639   return *this;
640 }
641 
642 template <class Tr>
643 inline const ArrayIterator<Tr>
644 ArrayIterator<Tr>::operator+(typename ArrayIterator<Tr>::difference_type rhs) const
645 {
646   return ArrayIterator<Tr>(pos_ + rhs);
647 }
648 
649 template <class Tr>
650 inline const ArrayIterator<Tr>
651 ArrayIterator<Tr>::operator-(typename ArrayIterator<Tr>::difference_type rhs) const
652 {
653   return ArrayIterator<Tr>(pos_ - rhs);
654 }
655 
656 template <class Tr>
657 inline typename ArrayIterator<Tr>::difference_type
658 ArrayIterator<Tr>::operator-(const ArrayIterator<Tr>& rhs) const
659 {
660   return (pos_ - rhs.pos_);
661 }
662 
663 template <class Tr>
664 inline bool
665 ArrayIterator<Tr>::operator==(const ArrayIterator<Tr>& rhs) const
666 {
667   return (pos_ == rhs.pos_);
668 }
669 
670 template <class Tr>
671 inline bool
672 ArrayIterator<Tr>::operator!=(const ArrayIterator<Tr>& rhs) const
673 {
674   return (pos_ != rhs.pos_);
675 }
676 
677 template <class Tr>
678 inline bool
679 ArrayIterator<Tr>::operator<(const ArrayIterator<Tr>& rhs) const
680 {
681   return (pos_ < rhs.pos_);
682 }
683 
684 template <class Tr>
685 inline bool
686 ArrayIterator<Tr>::operator>(const ArrayIterator<Tr>& rhs) const
687 {
688   return (pos_ > rhs.pos_);
689 }
690 
691 template <class Tr>
692 inline bool
693 ArrayIterator<Tr>::operator<=(const ArrayIterator<Tr>& rhs) const
694 {
695   return (pos_ <= rhs.pos_);
696 }
697 
698 template <class Tr>
699 inline bool
700 ArrayIterator<Tr>::operator>=(const ArrayIterator<Tr>& rhs) const
701 {
702   return (pos_ >= rhs.pos_);
703 }
704 
705 /**** Glib::Container_Helpers::ListIterator<> ************************/
706 
707 template <class Tr>
ListIterator(const GList * node)708 inline ListIterator<Tr>::ListIterator(const GList* node) : node_(node)
709 {
710 }
711 
712 template <class Tr>
713 inline typename ListIterator<Tr>::value_type ListIterator<Tr>::operator*() const
714 {
715   return Tr::to_cpp_type(static_cast<typename Tr::CTypeNonConst>(node_->data));
716 }
717 
718 template <class Tr>
719 inline ListIterator<Tr>& ListIterator<Tr>::operator++()
720 {
721   node_ = node_->next;
722   return *this;
723 }
724 
725 template <class Tr>
726 inline const ListIterator<Tr> ListIterator<Tr>::operator++(int)
727 {
728   const ListIterator<Tr> tmp(*this);
729   node_ = node_->next;
730   return tmp;
731 }
732 
733 template <class Tr>
734 inline bool
735 ListIterator<Tr>::operator==(const ListIterator<Tr>& rhs) const
736 {
737   return (node_ == rhs.node_);
738 }
739 
740 template <class Tr>
741 inline bool
742 ListIterator<Tr>::operator!=(const ListIterator<Tr>& rhs) const
743 {
744   return (node_ != rhs.node_);
745 }
746 
747 /**** Glib::Container_Helpers::SListIterator<> ************************/
748 
749 template <class Tr>
SListIterator(const GSList * node)750 inline SListIterator<Tr>::SListIterator(const GSList* node) : node_(node)
751 {
752 }
753 
754 template <class Tr>
755 inline typename SListIterator<Tr>::value_type SListIterator<Tr>::operator*() const
756 {
757   return Tr::to_cpp_type(static_cast<typename Tr::CTypeNonConst>(node_->data));
758 }
759 
760 template <class Tr>
761 inline SListIterator<Tr>& SListIterator<Tr>::operator++()
762 {
763   node_ = node_->next;
764   return *this;
765 }
766 
767 template <class Tr>
768 inline const SListIterator<Tr> SListIterator<Tr>::operator++(int)
769 {
770   const ListIterator<Tr> tmp(*this);
771   node_ = node_->next;
772   return tmp;
773 }
774 
775 template <class Tr>
776 inline bool
777 SListIterator<Tr>::operator==(const SListIterator<Tr>& rhs) const
778 {
779   return (node_ == rhs.node_);
780 }
781 
782 template <class Tr>
783 inline bool
784 SListIterator<Tr>::operator!=(const SListIterator<Tr>& rhs) const
785 {
786   return (node_ != rhs.node_);
787 }
788 
789 /**** Glib::Container_Helpers::ArrayKeeper<> ************************/
790 
791 template <typename Tr>
ArrayKeeper(const CType * array,std::size_t array_size,Glib::OwnershipType ownership)792 inline ArrayKeeper<Tr>::ArrayKeeper(
793   const CType* array, std::size_t array_size, Glib::OwnershipType ownership)
794 : array_(const_cast<CType*>(array)), array_size_(array_size), ownership_(ownership)
795 {
796 }
797 
798 template <typename Tr>
ArrayKeeper(const ArrayKeeper & keeper)799 inline ArrayKeeper<Tr>::ArrayKeeper(const ArrayKeeper& keeper)
800 : array_(keeper.array_), array_size_(keeper.array_size_), ownership_(keeper.ownership_)
801 {
802   keeper.ownership_ = Glib::OWNERSHIP_NONE;
803 }
804 
805 template <typename Tr>
~ArrayKeeper()806 ArrayKeeper<Tr>::~ArrayKeeper() noexcept
807 {
808   if (array_ && ownership_ != Glib::OWNERSHIP_NONE)
809   {
810     if (ownership_ != Glib::OWNERSHIP_SHALLOW)
811     {
812       // Deep ownership: release each container element.
813       const CType* const array_end(array_ + array_size_);
814 
815       for (const CType* p(array_); p != array_end; ++p)
816       {
817         Tr::release_c_type(*p);
818       }
819     }
820     g_free(const_cast<CType*>(array_));
821   }
822 }
823 
824 template <typename Tr>
825 inline typename Tr::CType*
data()826 ArrayKeeper<Tr>::data() const
827 {
828   return array_;
829 }
830 
831 /**** Glib::Container_Helpers::GListKeeper<> ************************/
832 
833 template <typename Tr>
GListKeeper(const GList * glist,Glib::OwnershipType ownership)834 inline GListKeeper<Tr>::GListKeeper(const GList* glist, Glib::OwnershipType ownership)
835 : glist_(const_cast<GList*>(glist)), ownership_(ownership)
836 {
837 }
838 
839 template <typename Tr>
GListKeeper(const GListKeeper & keeper)840 inline GListKeeper<Tr>::GListKeeper(const GListKeeper& keeper)
841 : glist_(keeper.glist_), ownership_(keeper.ownership_)
842 {
843   keeper.ownership_ = Glib::OWNERSHIP_NONE;
844 }
845 
846 template <typename Tr>
~GListKeeper()847 GListKeeper<Tr>::~GListKeeper() noexcept
848 {
849   using CTypeNonConst = typename Tr::CTypeNonConst;
850 
851   if (glist_ && ownership_ != Glib::OWNERSHIP_NONE)
852   {
853     if (ownership_ != Glib::OWNERSHIP_SHALLOW)
854     {
855       // Deep ownership: release each container element.
856       for (GList* node = glist_; node; node = node->next)
857       {
858         Tr::release_c_type(static_cast<CTypeNonConst>(node->data));
859       }
860     }
861     g_list_free(glist_);
862   }
863 }
864 
865 template <typename Tr>
866 inline GList*
data()867 GListKeeper<Tr>::data() const
868 {
869   return glist_;
870 }
871 
872 /**** Glib::Container_Helpers::GSListKeeper<> ************************/
873 
874 template <typename Tr>
GSListKeeper(const GSList * gslist,Glib::OwnershipType ownership)875 inline GSListKeeper<Tr>::GSListKeeper(const GSList* gslist, Glib::OwnershipType ownership)
876 : gslist_(const_cast<GSList*>(gslist)), ownership_(ownership)
877 {
878 }
879 
880 template <typename Tr>
GSListKeeper(const GSListKeeper & keeper)881 inline GSListKeeper<Tr>::GSListKeeper(const GSListKeeper& keeper)
882 : gslist_(keeper.gslist_), ownership_(keeper.ownership_)
883 {
884   keeper.ownership_ = Glib::OWNERSHIP_NONE;
885 }
886 
887 template <typename Tr>
~GSListKeeper()888 GSListKeeper<Tr>::~GSListKeeper() noexcept
889 {
890   using CTypeNonConst = typename Tr::CTypeNonConst;
891   if (gslist_ && ownership_ != Glib::OWNERSHIP_NONE)
892   {
893     if (ownership_ != Glib::OWNERSHIP_SHALLOW)
894     {
895       // Deep ownership: release each container element.
896       for (GSList* node = gslist_; node; node = node->next)
897       {
898         Tr::release_c_type(static_cast<CTypeNonConst>(node->data));
899       }
900     }
901     g_slist_free(gslist_);
902   }
903 }
904 
905 template <typename Tr>
906 inline GSList*
data()907 GSListKeeper<Tr>::data() const
908 {
909   return gslist_;
910 }
911 
912 } // namespace Container_Helpers
913 
914 /**** Glib::ArrayHandler<> ************************/
915 
916 template <typename T, class Tr>
917 typename ArrayHandler<T, Tr>::VectorType
array_to_vector(const CType * array,std::size_t array_size,Glib::OwnershipType ownership)918 ArrayHandler<T, Tr>::array_to_vector(
919   const CType* array, std::size_t array_size, Glib::OwnershipType ownership)
920 {
921   if (array)
922   {
923     // it will handle destroying data depending on passed ownership.
924     ArrayKeeperType keeper(array, array_size, ownership);
925 #ifdef GLIBMM_HAVE_TEMPLATE_SEQUENCE_CTORS
926     return VectorType(ArrayIteratorType(array), ArrayIteratorType(array + array_size));
927 #else
928     VectorType temp;
929     temp.reserve(array_size);
930     Glib::Container_Helpers::fill_container(
931       temp, ArrayIteratorType(array), ArrayIteratorType(array + array_size));
932     return temp;
933 #endif
934   }
935   return VectorType();
936 }
937 
938 template <typename T, class Tr>
939 typename ArrayHandler<T, Tr>::VectorType
array_to_vector(const CType * array,Glib::OwnershipType ownership)940 ArrayHandler<T, Tr>::array_to_vector(const CType* array, Glib::OwnershipType ownership)
941 {
942   return array_to_vector(array, Glib::Container_Helpers::compute_array_size2(array), ownership);
943 }
944 
945 template <typename T, class Tr>
946 typename ArrayHandler<T, Tr>::ArrayKeeperType
vector_to_array(const VectorType & vector)947 ArrayHandler<T, Tr>::vector_to_array(const VectorType& vector)
948 {
949   return ArrayKeeperType(Glib::Container_Helpers::create_array<Tr>(vector.begin(), vector.size()),
950     vector.size(), Glib::OWNERSHIP_SHALLOW);
951 }
952 
953 /**** Glib::ListHandler<> ************************/
954 
955 template <typename T, class Tr>
956 typename ListHandler<T, Tr>::VectorType
list_to_vector(GList * glist,Glib::OwnershipType ownership)957 ListHandler<T, Tr>::list_to_vector(GList* glist, Glib::OwnershipType ownership)
958 {
959   // it will handle destroying data depending on passed ownership.
960   GListKeeperType keeper(glist, ownership);
961 #ifdef GLIBMM_HAVE_TEMPLATE_SEQUENCE_CTORS
962   return VectorType(ListIteratorType(glist), ListIteratorType(nullptr));
963 #else
964   VectorType temp;
965   temp.reserve(g_list_length(glist));
966   Glib::Container_Helpers::fill_container(temp, ListIteratorType(glist), ListIteratorType(nullptr));
967   return temp;
968 #endif
969 }
970 
971 template <typename T, class Tr>
972 typename ListHandler<T, Tr>::GListKeeperType
vector_to_list(const VectorType & vector)973 ListHandler<T, Tr>::vector_to_list(const VectorType& vector)
974 {
975   return GListKeeperType(Glib::Container_Helpers::create_glist<Tr>(vector.begin(), vector.end()),
976     Glib::OWNERSHIP_SHALLOW);
977 }
978 
979 /**** Glib::SListHandler<> ************************/
980 
981 template <typename T, class Tr>
982 typename SListHandler<T, Tr>::VectorType
slist_to_vector(GSList * gslist,Glib::OwnershipType ownership)983 SListHandler<T, Tr>::slist_to_vector(GSList* gslist, Glib::OwnershipType ownership)
984 {
985   // it will handle destroying data depending on passed ownership.
986   GSListKeeperType keeper(gslist, ownership);
987 #ifdef GLIBMM_HAVE_TEMPLATE_SEQUENCE_CTORS
988   return VectorType(SListIteratorType(gslist), SListIteratorType(nullptr));
989 #else
990   VectorType temp;
991   temp.reserve(g_slist_length(gslist));
992   Glib::Container_Helpers::fill_container(
993     temp, SListIteratorType(gslist), SListIteratorType(nullptr));
994   return temp;
995 #endif
996 }
997 
998 template <typename T, class Tr>
999 typename SListHandler<T, Tr>::GSListKeeperType
vector_to_slist(const VectorType & vector)1000 SListHandler<T, Tr>::vector_to_slist(const VectorType& vector)
1001 {
1002   return GSListKeeperType(Glib::Container_Helpers::create_gslist<Tr>(vector.begin(), vector.end()),
1003     Glib::OWNERSHIP_SHALLOW);
1004 }
1005 
1006 #endif /* DOXYGEN_SHOULD_SKIP_THIS */
1007 
1008 } // namespace Glib
1009 
1010 #endif /* _GLIBMM_VECTORUTILS_H */
1011