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