Fix three minor memory leaks in the Editor by using Gtk::manage
[ardour.git] / libs / glibmm2 / glibmm / slisthandle.h
1 // -*- c++ -*-
2 #ifndef _GLIBMM_SLISTHANDLE_H
3 #define _GLIBMM_SLISTHANDLE_H
4
5 /* $Id$ */
6
7 /* Copyright (C) 2002 The gtkmm Development Team
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Library General Public
11  * License as published by the Free Software Foundation; either
12  * version 2 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Library General Public License for more details.
18  *
19  * You should have received a copy of the GNU Library General Public
20  * License along with this library; if not, write to the Free
21  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22  */
23
24 #include <glib/gslist.h>
25 #include <glibmm/containerhandle_shared.h>
26
27
28 namespace Glib
29 {
30
31 namespace Container_Helpers
32 {
33
34 #ifndef DOXYGEN_SHOULD_SKIP_THIS
35
36 /* Create and fill a GSList as efficient as possible.
37  * This requires bidirectional iterators.
38  */
39 template <class Bi, class Tr>
40 GSList* create_slist(Bi pbegin, Bi pend, Tr)
41 {
42   GSList* head = 0;
43
44   while(pend != pbegin)
45   {
46     // Use & to force a warning if the iterator returns a temporary object.
47     const void *const item = Tr::to_c_type(*&*--pend);
48     head = g_slist_prepend(head, const_cast<void*>(item));
49   }
50
51   return head;
52 }
53
54 /* Create a GSList from a 0-terminated input sequence.
55  * Build it in reverse order and reverse the whole list afterwards,
56  * because appending to the list would be horribly inefficient.
57  */
58 template <class For, class Tr>
59 GSList* create_slist(For pbegin, Tr)
60 {
61   GSList* head = 0;
62
63   while(*pbegin)
64   {
65     // Use & to force a warning if the iterator returns a temporary object.
66     const void *const item = Tr::to_c_type(*&*pbegin);
67     head = g_slist_prepend(head, const_cast<void*>(item));
68     ++pbegin;
69   }
70
71   return g_slist_reverse(head);
72 }
73
74
75 /* Convert from any container that supports bidirectional iterators.
76  */
77 template <class Tr, class Cont>
78 struct SListSourceTraits
79 {
80   static GSList* get_data(const Cont& cont)
81     { return Glib::Container_Helpers::create_slist(cont.begin(), cont.end(), Tr()); }
82
83   static const Glib::OwnershipType initial_ownership = Glib::OWNERSHIP_SHALLOW;
84 };
85
86 /* Convert from a 0-terminated array.  The Cont
87  * argument must be a pointer to the first element.
88  */
89 template <class Tr, class Cont>
90 struct SListSourceTraits<Tr,Cont*>
91 {
92   static GSList* get_data(const Cont* array)
93     { return (array) ? Glib::Container_Helpers::create_slist(array, Tr()) : 0; }
94
95   static const Glib::OwnershipType initial_ownership = Glib::OWNERSHIP_SHALLOW;
96 };
97
98 template <class Tr, class Cont>
99 struct SListSourceTraits<Tr,const Cont*> : SListSourceTraits<Tr,Cont*>
100 {};
101
102 /* Convert from a 0-terminated array.  The Cont argument must be a pointer
103  * to the first element.  For consistency, the array must be 0-terminated,
104  * even though the array size is known at compile time.
105  */
106 template <class Tr, class Cont, size_t N>
107 struct SListSourceTraits<Tr,Cont[N]>
108 {
109   static GSList* get_data(const Cont* array)
110     { return Glib::Container_Helpers::create_slist(array, array + (N - 1), Tr()); }
111
112   static const Glib::OwnershipType initial_ownership = Glib::OWNERSHIP_SHALLOW;
113 };
114
115 template <class Tr, class Cont, size_t N>
116 struct SListSourceTraits<Tr,const Cont[N]> : SListSourceTraits<Tr,Cont[N]>
117 {};
118
119 #endif /* DOXYGEN_SHOULD_SKIP_THIS */
120
121
122 /**
123  * @ingroup ContHelpers
124  * If a method takes this as an argument, or has this as a return type, then you can use a standard
125  * container such as std::list or std::vector.
126  */
127 template <class Tr>
128 class SListHandleIterator
129 {
130 public:
131   typedef typename Tr::CppType        CppType;
132   typedef typename Tr::CType          CType;
133
134   typedef std::forward_iterator_tag   iterator_category;
135   typedef CppType                     value_type;
136   typedef ptrdiff_t                   difference_type;
137   typedef value_type                  reference;
138   typedef void                        pointer;
139
140   explicit inline SListHandleIterator(const GSList* node);
141
142   inline value_type                    operator*() const;
143   inline SListHandleIterator<Tr> &     operator++();
144   inline const SListHandleIterator<Tr> operator++(int);
145
146   inline bool operator==(const SListHandleIterator<Tr>& rhs) const;
147   inline bool operator!=(const SListHandleIterator<Tr>& rhs) const;
148
149 private:
150   const GSList* node_;
151 };
152
153 } // namespace Container_Helpers
154
155
156 /**
157  * @ingroup ContHandles
158  */
159 template < class T, class Tr = Glib::Container_Helpers::TypeTraits<T> >
160 class SListHandle
161 {
162 public:
163   typedef typename Tr::CppType  CppType;
164   typedef typename Tr::CType    CType;
165
166   typedef CppType               value_type;
167   typedef size_t                size_type;
168   typedef ptrdiff_t             difference_type;
169
170   typedef Glib::Container_Helpers::SListHandleIterator<Tr>   const_iterator;
171   typedef Glib::Container_Helpers::SListHandleIterator<Tr>   iterator;
172
173   template <class Cont> inline
174     SListHandle(const Cont& container);
175
176   // Take over ownership of a GSList created by GTK+ functions.
177   inline SListHandle(GSList* glist, Glib::OwnershipType ownership);
178
179   // Copying clears the ownership flag of the source handle.
180   inline SListHandle(const SListHandle<T,Tr>& other);
181
182   ~SListHandle();
183
184   inline const_iterator begin() const;
185   inline const_iterator end()   const;
186
187   template <class U> inline operator std::vector<U>() const;
188   template <class U> inline operator std::deque<U>()  const;
189   template <class U> inline operator std::list<U>()   const;
190
191   template <class Cont> inline
192     void assign_to(Cont& container) const;
193   template <class Out> inline
194     void copy(Out pdest) const;
195
196   inline GSList* data()  const;
197   inline size_t  size()  const;
198   inline bool    empty() const;
199
200 private:
201   GSList *                    pslist_;
202   mutable Glib::OwnershipType ownership_;
203
204   // No copy assignment.
205   SListHandle<T,Tr>& operator=(const SListHandle<T,Tr>&);
206 };
207
208
209 /***************************************************************************/
210 /*  Inline implementation                                                  */
211 /***************************************************************************/
212
213 #ifndef DOXYGEN_SHOULD_SKIP_THIS
214
215 namespace Container_Helpers
216 {
217
218 /**** Glib::Container_Helpers::SListHandleIterator<> ***********************/
219
220 template <class Tr> inline
221 SListHandleIterator<Tr>::SListHandleIterator(const GSList* node)
222 :
223   node_ (node)
224 {}
225
226 template <class Tr> inline
227 typename SListHandleIterator<Tr>::value_type SListHandleIterator<Tr>::operator*() const
228 {
229   return Tr::to_cpp_type(static_cast<typename Tr::CTypeNonConst>(node_->data));
230 }
231
232 template <class Tr> inline
233 SListHandleIterator<Tr>& SListHandleIterator<Tr>::operator++()
234 {
235   node_ = node_->next;
236   return *this;
237 }
238
239 template <class Tr> inline
240 const SListHandleIterator<Tr> SListHandleIterator<Tr>::operator++(int)
241 {
242   const SListHandleIterator<Tr> tmp (*this);
243   node_ = node_->next;
244   return tmp;
245 }
246
247 template <class Tr> inline
248 bool SListHandleIterator<Tr>::operator==(const SListHandleIterator<Tr>& rhs) const
249 {
250   return (node_ == rhs.node_);
251 }
252
253 template <class Tr> inline
254 bool SListHandleIterator<Tr>::operator!=(const SListHandleIterator<Tr>& rhs) const
255 {
256   return (node_ != rhs.node_);
257 }
258
259 } // namespace Container_Helpers
260
261
262 /**** Glib::SListHandle<> **************************************************/
263
264 template <class T, class Tr>
265   template <class Cont>
266 inline
267 SListHandle<T,Tr>::SListHandle(const Cont& container)
268 :
269   pslist_    (Glib::Container_Helpers::SListSourceTraits<Tr,Cont>::get_data(container)),
270   ownership_ (Glib::Container_Helpers::SListSourceTraits<Tr,Cont>::initial_ownership)
271 {}
272
273 template <class T, class Tr> inline
274 SListHandle<T,Tr>::SListHandle(GSList* gslist, Glib::OwnershipType ownership)
275 :
276   pslist_    (gslist),
277   ownership_ (ownership)
278 {}
279
280 template <class T, class Tr> inline
281 SListHandle<T,Tr>::SListHandle(const SListHandle<T,Tr>& other)
282 :
283   pslist_    (other.pslist_),
284   ownership_ (other.ownership_)
285 {
286   other.ownership_ = Glib::OWNERSHIP_NONE;
287 }
288
289 template <class T, class Tr>
290 SListHandle<T,Tr>::~SListHandle()
291 {
292   if(ownership_ != Glib::OWNERSHIP_NONE)
293   {
294     if(ownership_ != Glib::OWNERSHIP_SHALLOW)
295     {
296       // Deep ownership: release each container element.
297       for(GSList* node = pslist_; node != 0; node = node->next)
298         Tr::release_c_type(static_cast<typename Tr::CTypeNonConst>(node->data));
299     }
300     g_slist_free(pslist_);
301   }
302 }
303
304 template <class T, class Tr> inline
305 typename SListHandle<T,Tr>::const_iterator SListHandle<T,Tr>::begin() const
306 {
307   return Glib::Container_Helpers::SListHandleIterator<Tr>(pslist_);
308 }
309
310 template <class T, class Tr> inline
311 typename SListHandle<T,Tr>::const_iterator SListHandle<T,Tr>::end() const
312 {
313   return Glib::Container_Helpers::SListHandleIterator<Tr>(0);
314 }
315
316 template <class T, class Tr>
317   template <class U>
318 inline
319 SListHandle<T,Tr>::operator std::vector<U>() const
320 {
321 #ifdef GLIBMM_HAVE_TEMPLATE_SEQUENCE_CTORS
322   return std::vector<U>(this->begin(), this->end());
323 #else
324   std::vector<U> temp;
325   temp.reserve(this->size());
326   Glib::Container_Helpers::fill_container(temp, this->begin(), this->end());
327   return temp;
328 #endif
329 }
330
331 template <class T, class Tr>
332   template <class U>
333 inline
334 SListHandle<T,Tr>::operator std::deque<U>() const
335 {
336 #ifdef GLIBMM_HAVE_TEMPLATE_SEQUENCE_CTORS
337   return std::deque<U>(this->begin(), this->end());
338 #else
339   std::deque<U> temp;
340   Glib::Container_Helpers::fill_container(temp, this->begin(), this->end());
341   return temp;
342 #endif
343 }
344
345 template <class T, class Tr>
346   template <class U>
347 inline
348 SListHandle<T,Tr>::operator std::list<U>() const
349 {
350 #ifdef GLIBMM_HAVE_TEMPLATE_SEQUENCE_CTORS
351   return std::list<U>(this->begin(), this->end());
352 #else
353   std::list<U> temp;
354   Glib::Container_Helpers::fill_container(temp, this->begin(), this->end());
355   return temp;
356 #endif
357 }
358
359 template <class T, class Tr>
360   template <class Cont>
361 inline
362 void SListHandle<T,Tr>::assign_to(Cont& container) const
363 {
364 #ifdef GLIBMM_HAVE_TEMPLATE_SEQUENCE_CTORS
365   container.assign(this->begin(), this->end());
366 #else
367   Cont temp;
368   Glib::Container_Helpers::fill_container(temp, this->begin(), this->end());
369   container.swap(temp);
370 #endif
371 }
372
373 template <class T, class Tr>
374   template <class Out>
375 inline
376 void SListHandle<T,Tr>::copy(Out pdest) const
377 {
378   std::copy(this->begin(), this->end(), pdest);
379 }
380
381 template <class T, class Tr> inline
382 GSList* SListHandle<T,Tr>::data() const
383 {
384   return pslist_;
385 }
386
387 template <class T, class Tr> inline
388 size_t SListHandle<T,Tr>::size() const
389 {
390   return g_slist_length(pslist_);
391 }
392
393 template <class T, class Tr> inline
394 bool SListHandle<T,Tr>::empty() const
395 {
396   return (pslist_ == 0);
397 }
398
399 #endif /* DOXYGEN_SHOULD_SKIP_THIS */
400
401 } // namespace Glib
402
403
404 #endif /* _GLIBMM_SLISTHANDLE_H */
405