1 #ifndef _GLIBMM_CONTAINERS_H
2 #define _GLIBMM_CONTAINERS_H
3 
4 /* containers.h
5  *
6  * Copyright (C) 1998-2002 The gtkmm Development Team
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
20  */
21 
22 #include <glibmmconfig.h>
23 #include <glibmm/sarray.h> /* for backward compatibility */
24 #include <glibmm/wrap.h>
25 #include <glib.h>
26 #include <iterator>
27 #include <cstddef>
28 
29 #ifndef DOXYGEN_SHOULD_SKIP_THIS
30 
31 namespace Glib
32 {
33 
34 template <class T>
35 class List_Iterator;
36 template <class T>
37 class List_ConstIterator;
38 template <class T>
39 class List_ReverseIterator;
40 
41 // Most of these methods in the non-template classes needs to be moved
42 // to implementation.
43 
44 // Daniel Elstner has ideas about generating these per-widget with m4. murrayc.
45 
46 extern GLIBMM_API gpointer glibmm_null_pointer;
47 
48 template <class T>
49 class List_Iterator_Base
50 {
51 public:
52   using value_type = T;
53   using pointer = T*;
54   using reference = T&;
55 };
56 
57 /// For instance, List_Iterator< Gtk::Widget >
58 template <class T>
59 class List_Iterator : public List_Iterator_Base<T>
60 {
61 public:
62   using iterator_category = std::bidirectional_iterator_tag;
63   using size_type = std::size_t;
64   using difference_type = std::ptrdiff_t;
65 
66   using pointer = typename List_Iterator_Base<T>::pointer;
67   using reference = typename List_Iterator_Base<T>::reference;
68 
69   GList* const* head_;
70   GList* node_;
71 
72   using Self = List_Iterator<T>;
73 
List_Iterator(GList * const & head,GList * node)74   List_Iterator(GList* const& head, GList* node) : head_(&head), node_(node) {}
75 
List_Iterator()76   List_Iterator() : head_(nullptr), node_(nullptr) {}
77 
List_Iterator(const Self & src)78   List_Iterator(const Self& src) : head_(src.head_), node_(src.node_) {}
79 
80   bool operator==(const Self& src) const { return node_ == src.node_; }
81   bool operator!=(const Self& src) const { return node_ != src.node_; }
82 
83   Self& operator++()
84   {
85     if (!node_)
86       node_ = g_list_first(*head_);
87     else
88       node_ = (GList*)g_list_next(node_);
89     return *this;
90   }
91 
92   Self operator++(int)
93   {
94     Self tmp = *this;
95     ++*this;
96     return tmp;
97   }
98 
99   Self& operator--()
100   {
101     if (!node_)
102       node_ = g_list_last(*head_);
103     else
104       node_ = (GList*)g_list_previous(node_);
105 
106     return *this;
107   }
108 
109   Self operator--(int)
110   {
111     Self tmp = *this;
112     --*this;
113     return tmp;
114   }
115 
116   reference operator*() const { return *(pointer)(node_ ? node_->data : glibmm_null_pointer); }
117 
118   pointer operator->() const { return &**this; }
119 };
120 
121 /// For instance, SList_Iterator< Gtk::Widget >
122 template <class T>
123 class SList_Iterator : public List_Iterator_Base<T>
124 {
125 public:
126   using iterator_category = std::forward_iterator_tag;
127   using size_type = std::size_t;
128   using difference_type = std::ptrdiff_t;
129 
130   using pointer = typename List_Iterator_Base<T>::pointer;
131   using reference = typename List_Iterator_Base<T>::reference;
132 
133   GSList* node_;
134   using Self = SList_Iterator<T>;
135 
SList_Iterator(GSList * node)136   SList_Iterator(GSList* node) : node_(node) {}
137 
SList_Iterator()138   SList_Iterator() : node_(nullptr) {}
139 
SList_Iterator(const Self & src)140   SList_Iterator(const Self& src) : node_(src.node_) {}
141 
142   bool operator==(const Self& src) const { return node_ == src.node_; }
143   bool operator!=(const Self& src) const { return node_ != src.node_; }
144 
145   Self& operator++()
146   {
147     node_ = g_slist_next(node_);
148     return *this;
149   }
150 
151   Self operator++(int)
152   {
153     Self tmp = *this;
154     ++*this;
155     return tmp;
156   }
157 
158   reference operator*() const
159   {
160     return reinterpret_cast<T&>(node_ ? node_->data : glibmm_null_pointer);
161   }
162 
163   pointer operator->() const { return &**this; }
164 };
165 
166 // This iterator variation returns T_IFace (wrapped from T_Impl)
167 // For instance,  List_Cpp_Iterator<GtkWidget, Gtk::Widget> is
168 // a little like std::list<Gtk::Widget>::iterator
169 template <class T_Impl, class T_IFace>
170 class List_Cpp_Iterator : public List_Iterator_Base<T_IFace>
171 {
172 public:
173   using iterator_category = std::bidirectional_iterator_tag;
174   using size_type = std::size_t;
175   using difference_type = std::ptrdiff_t;
176 
177   using pointer = typename List_Iterator_Base<T_IFace>::pointer;
178   using reference = typename List_Iterator_Base<T_IFace>::reference;
179 
180   using Self = List_Cpp_Iterator<T_Impl, T_IFace>;
181 
182   GList** head_;
183   GList* node_;
184 
185   bool operator==(const Self& src) const { return node_ == src.node_; }
186   bool operator!=(const Self& src) const { return node_ != src.node_; }
187 
List_Cpp_Iterator(GList * & head,GList * node)188   List_Cpp_Iterator(GList*& head, GList* node) : head_(&head), node_(node) {}
189 
List_Cpp_Iterator()190   List_Cpp_Iterator() : head_(nullptr), node_(nullptr) {}
191 
List_Cpp_Iterator(const Self & src)192   List_Cpp_Iterator(const Self& src) : head_(src.head_), node_(src.node_) {}
193 
194   reference operator*() const
195   {
196     if (node_ && node_->data)
197     {
198       // We copy/paste the widget wrap() implementation here,
199       // because we can not use a specific Glib::wrap(T_Impl) overload here,
200       // because that would be "dependent", and g++ 3.4 does not allow that.
201       // The specific Glib::wrap() overloads don't do anything special anyway.
202       GObject* cobj = static_cast<GObject*>(node_->data);
203 
204 #ifdef GLIBMM_CAN_USE_DYNAMIC_CAST_IN_UNUSED_TEMPLATE_WITHOUT_DEFINITION
205       return *dynamic_cast<pointer>(Glib::wrap_auto(cobj, false));
206 #else
207       // We really do need to use dynamic_cast<>, so I expect problems if this code is used.
208       // murrayc.
209       return *static_cast<pointer>(Glib::wrap_auto(cobj, false));
210 #endif
211     }
212     return *static_cast<pointer>(nullptr); // boom!
213   }
214 
215   pointer operator->() const { return &**this; }
216 
217   Self& operator++()
218   {
219     if (!node_)
220       node_ = g_list_first(*head_);
221     else
222       node_ = (GList*)g_list_next(node_);
223 
224     return *this;
225   }
226 
227   Self operator++(int)
228   {
229     Self tmp = *this;
230     ++*this;
231     return tmp;
232   }
233 
234   Self& operator--()
235   {
236     if (!node_)
237       node_ = g_list_last(*head_);
238     else
239       node_ = (GList*)g_list_previous(node_);
240 
241     return *this;
242   }
243 
244   Self operator--(int)
245   {
246     Self tmp = *this;
247     --*this;
248     return tmp;
249   }
250 };
251 
252 template <class T_Base>
253 class List_ReverseIterator : private T_Base
254 {
255 public:
256   using iterator_category = typename T_Base::iterator_category;
257   using size_type = typename T_Base::size_type;
258   using difference_type = typename T_Base::difference_type;
259 
260   using value_type = typename T_Base::value_type;
261   using pointer = typename T_Base::pointer;
262   using reference = typename T_Base::reference;
263 
264   using Self = List_ReverseIterator<T_Base>;
265 
266   bool operator==(const Self& src) const { return T_Base::operator==(src); }
267   bool operator!=(const Self& src) const { return T_Base::operator!=(src); }
268 
List_ReverseIterator(GList * const & head,GList * node)269   List_ReverseIterator(GList* const& head, GList* node) : T_Base(head, node) {}
270 
List_ReverseIterator()271   List_ReverseIterator() : T_Base() {}
272 
List_ReverseIterator(const Self & src)273   List_ReverseIterator(const Self& src) : T_Base(src) {}
274 
List_ReverseIterator(const T_Base & src)275   List_ReverseIterator(const T_Base& src) : T_Base(src) { ++(*this); }
276 
277   Self& operator++()
278   {
279     T_Base::operator--();
280     return *this;
281   }
282   Self& operator--()
283   {
284     T_Base::operator++();
285     return *this;
286   }
287   Self operator++(int)
288   {
289     Self src = *this;
290     T_Base::operator--();
291     return src;
292   }
293   Self operator--(int)
294   {
295     Self src = *this;
296     T_Base::operator++();
297     return src;
298   }
299 
300   reference operator*() const { return T_Base::operator*(); }
301   pointer operator->() const { return T_Base::operator->(); }
302 };
303 
304 template <class T_Base>
305 class List_ConstIterator : public T_Base
306 {
307 public:
308   using iterator_category = typename T_Base::iterator_category;
309   using size_type = typename T_Base::size_type;
310   using difference_type = typename T_Base::difference_type;
311 
312   using value_type = const typename T_Base::value_type;
313   using pointer = const typename T_Base::pointer;
314   using reference = const typename T_Base::reference;
315 
316   using Self = List_ConstIterator<T_Base>;
317 
318   bool operator==(const Self& src) const { return T_Base::operator==(src); }
319   bool operator!=(const Self& src) const { return T_Base::operator!=(src); }
320 
List_ConstIterator(GList * const & head,GList * node)321   List_ConstIterator(GList* const& head, GList* node) : T_Base(head, node) {}
322 
List_ConstIterator()323   List_ConstIterator() : T_Base() {}
324 
List_ConstIterator(const Self & src)325   List_ConstIterator(const Self& src) : T_Base(src) {}
326 
List_ConstIterator(const T_Base & src)327   List_ConstIterator(const T_Base& src) : T_Base(src) {}
328 
329   Self& operator++()
330   {
331     T_Base::operator++();
332     return *this;
333   }
334   Self& operator--()
335   {
336     T_Base::operator--();
337     return *this;
338   }
339   Self operator++(int)
340   {
341     Self src = *this;
342     T_Base::operator++();
343     return src;
344   }
345   Self operator--(int)
346   {
347     Self src = *this;
348     T_Base::operator--();
349     return src;
350   }
351 
352   reference operator*() const { return T_Base::operator*(); }
353   pointer operator->() const { return T_Base::operator->(); }
354 };
355 
356 } // namespace Glib
357 
358 #endif /* DOXYGEN_SHOULD_SKIP_THIS */
359 
360 #endif /* _GLIBMM_CONTAINERS_H */
361