add new sigc++2 directory
[ardour.git] / libs / glibmm2 / glib / glibmm / arrayhandle.h
1 // -*- c++ -*-
2 #ifndef _GLIBMM_ARRAYHANDLE_H
3 #define _GLIBMM_ARRAYHANDLE_H
4
5 /* $Id: arrayhandle.h 32 2003-04-21 17:39:41Z murrayc $ */
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 <glibmm/containerhandle_shared.h>
25
26
27 namespace Glib
28 {
29
30 namespace Container_Helpers
31 {
32
33 #ifndef DOXYGEN_SHOULD_SKIP_THIS
34
35 /* Count the number of elements in a 0-terminated sequence.
36  */
37 template <class T> inline
38 size_t compute_array_size(const T* array)
39 {
40   const T* pend = array;
41
42   while(*pend)
43     ++pend;
44
45   return (pend - array);
46 }
47
48 /* Allocate and fill a 0-terminated array.  The size argument
49  * specifies the number of elements in the input sequence.
50  */
51 template <class For, class Tr>
52 typename Tr::CType* create_array(For pbegin, size_t size, Tr)
53 {
54   typedef typename Tr::CType CType;
55
56   CType *const array = static_cast<CType*>(g_malloc((size + 1) * sizeof(CType)));
57   CType *const array_end = array + size;
58
59   for(CType* pdest = array; pdest != array_end; ++pdest)
60   {
61     // Use & to force a warning if the iterator returns a temporary object.
62     *pdest = Tr::to_c_type(*&*pbegin);
63     ++pbegin;
64   }
65
66   *array_end = CType();
67   return array;
68 }
69
70
71 /* Convert from any container that supports forward
72  * iterators and has a size() method.
73  */
74 template <class Tr, class Cont>
75 struct ArraySourceTraits
76 {
77   typedef typename Tr::CType CType;
78
79   static size_t get_size(const Cont& cont)
80     { return cont.size(); }
81
82   static const CType* get_data(const Cont& cont, size_t size)
83     { return Glib::Container_Helpers::create_array(cont.begin(), size, Tr()); }
84
85   static const Glib::OwnershipType initial_ownership = Glib::OWNERSHIP_SHALLOW;
86 };
87
88 /* Convert from a 0-terminated array.  The Cont argument must be a pointer
89  * to the first element.  Note that only arrays of the C type are supported.
90  */
91 template <class Tr, class Cont>
92 struct ArraySourceTraits<Tr,Cont*>
93 {
94   typedef typename Tr::CType CType;
95
96   static size_t get_size(const CType* array)
97     { return (array) ? Glib::Container_Helpers::compute_array_size(array) : 0; }
98
99   static const CType* get_data(const CType* array, size_t)
100     { return array; }
101
102   static const Glib::OwnershipType initial_ownership = Glib::OWNERSHIP_NONE;
103 };
104
105 template <class Tr, class Cont>
106 struct ArraySourceTraits<Tr,const Cont*> : ArraySourceTraits<Tr,Cont*>
107 {};
108
109 /* Convert from a 0-terminated array.  The Cont argument must be a pointer
110  * to the first element.  Note that only arrays of the C type are supported.
111  * For consistency, the array must be 0-terminated, even though the array
112  * size is known at compile time.
113  */
114 template <class Tr, class Cont, size_t N>
115 struct ArraySourceTraits<Tr,Cont[N]>
116 {
117   typedef typename Tr::CType CType;
118
119   static size_t get_size(const CType*)
120     { return (N - 1); }
121
122   static const CType* get_data(const CType* array, size_t)
123     { return array; }
124
125   static const Glib::OwnershipType initial_ownership = Glib::OWNERSHIP_NONE;
126 };
127
128 template <class Tr, class Cont, size_t N>
129 struct ArraySourceTraits<Tr,const Cont[N]> : ArraySourceTraits<Tr,Cont[N]>
130 {};
131
132 #endif /* DOXYGEN_SHOULD_SKIP_THIS */
133
134
135 /**
136  * @ingroup ContHelpers
137  */
138 template <class Tr>
139 class ArrayHandleIterator
140 {
141 public:
142   typedef typename Tr::CppType              CppType;
143   typedef typename Tr::CType                CType;
144
145   typedef std::random_access_iterator_tag   iterator_category;
146   typedef CppType                           value_type;
147   typedef ptrdiff_t                         difference_type;
148   typedef value_type                        reference;
149   typedef void                              pointer;
150
151   explicit inline ArrayHandleIterator(const CType* pos);
152
153   inline value_type operator*() const;
154   inline value_type operator[](difference_type offset) const;
155
156   inline ArrayHandleIterator<Tr> &     operator++();
157   inline const ArrayHandleIterator<Tr> operator++(int);
158
159   // All this random access stuff is only there because STL algorithms
160   // usually have optimized specializations for random access iterators,
161   // and we don't want to give away efficiency for nothing.
162   //
163   inline ArrayHandleIterator<Tr> &     operator+=(difference_type rhs);
164   inline ArrayHandleIterator<Tr> &     operator-=(difference_type rhs);
165   inline const ArrayHandleIterator<Tr> operator+ (difference_type rhs) const;
166   inline const ArrayHandleIterator<Tr> operator- (difference_type rhs) const;
167   inline difference_type operator-(const ArrayHandleIterator<Tr>& rhs) const;
168
169   inline bool operator==(const ArrayHandleIterator<Tr>& rhs) const;
170   inline bool operator!=(const ArrayHandleIterator<Tr>& rhs) const;
171   inline bool operator< (const ArrayHandleIterator<Tr>& rhs) const;
172   inline bool operator> (const ArrayHandleIterator<Tr>& rhs) const;
173   inline bool operator<=(const ArrayHandleIterator<Tr>& rhs) const;
174   inline bool operator>=(const ArrayHandleIterator<Tr>& rhs) const;
175
176 private:
177   const CType* pos_;
178 };
179
180 } // namespace Container_Helpers
181
182
183 /** If a method takes this as an argument, or has this as a return type, then you can use a standard
184  * container such as std::list or std::vector.
185  * @ingroup ContHandles
186  */
187 template < class T, class Tr = Glib::Container_Helpers::TypeTraits<T> >
188 class ArrayHandle
189 {
190 public:
191   typedef typename Tr::CppType  CppType;
192   typedef typename Tr::CType    CType;
193
194   typedef CppType               value_type;
195   typedef size_t                size_type;
196   typedef ptrdiff_t             difference_type;
197
198   typedef Glib::Container_Helpers::ArrayHandleIterator<Tr>   const_iterator;
199   typedef Glib::Container_Helpers::ArrayHandleIterator<Tr>   iterator;
200
201   template <class Cont> inline
202     ArrayHandle(const Cont& container);
203
204   // Take over ownership of an array created by GTK+ functions.
205   inline ArrayHandle(const CType* array, size_t array_size, Glib::OwnershipType ownership);
206   inline ArrayHandle(const CType* array, Glib::OwnershipType ownership);
207
208   // Copying clears the ownership flag of the source handle.
209   inline ArrayHandle(const ArrayHandle<T,Tr>& other);
210
211   ~ArrayHandle();
212
213   inline const_iterator begin() const;
214   inline const_iterator end()   const;
215
216   template <class U> inline operator std::vector<U>() const;
217   template <class U> inline operator std::deque<U>()  const;
218   template <class U> inline operator std::list<U>()   const;
219
220   template <class Cont> inline
221     void assign_to(Cont& container) const;
222
223   template <class Out> inline
224     void copy(Out pdest) const;
225
226   inline const CType* data()  const;
227   inline size_t       size()  const;
228   inline bool         empty() const;
229
230 private:
231   size_t                      size_;
232   const CType*                parray_;
233   mutable Glib::OwnershipType ownership_;
234
235   // No copy assignment.
236   ArrayHandle<T, Tr>& operator=(const ArrayHandle<T,Tr>&);
237 };
238
239 /** If a method takes this as an argument, or has this as a return type, then you can use a standard
240  * container such as std::list<Glib::ustring> or std::vector<Glib::ustring>.
241  * @ingroup ContHandles
242  */
243 typedef ArrayHandle<Glib::ustring> StringArrayHandle;
244
245
246 /***************************************************************************/
247 /*  Inline implementation                                                  */
248 /***************************************************************************/
249
250 #ifndef DOXYGEN_SHOULD_SKIP_THIS
251
252 namespace Container_Helpers
253 {
254
255 /**** Glib::Container_Helpers::ArrayHandleIterator<> ***********************/
256
257 template <class Tr> inline
258 ArrayHandleIterator<Tr>::ArrayHandleIterator(const CType* pos)
259 :
260   pos_ (pos)
261 {}
262
263 template <class Tr> inline
264 typename ArrayHandleIterator<Tr>::value_type ArrayHandleIterator<Tr>::operator*() const
265 {
266   return Tr::to_cpp_type(*pos_);
267 }
268
269 template <class Tr> inline
270 typename ArrayHandleIterator<Tr>::value_type
271 ArrayHandleIterator<Tr>::operator[](difference_type offset) const
272 {
273   return Tr::to_cpp_type(pos_[offset]);
274 }
275
276 template <class Tr> inline
277 ArrayHandleIterator<Tr>& ArrayHandleIterator<Tr>::operator++()
278 {
279   ++pos_;
280   return *this;
281 }
282
283 template <class Tr> inline
284 const ArrayHandleIterator<Tr> ArrayHandleIterator<Tr>::operator++(int)
285 {
286   return ArrayHandleIterator<Tr>(pos_++);
287 }
288
289 template <class Tr> inline
290 ArrayHandleIterator<Tr>&
291 ArrayHandleIterator<Tr>::operator+=(typename ArrayHandleIterator<Tr>::difference_type rhs)
292 {
293   pos_ += rhs;
294   return *this;
295 }
296
297 template <class Tr> inline
298 ArrayHandleIterator<Tr>&
299 ArrayHandleIterator<Tr>::operator-=(typename ArrayHandleIterator<Tr>::difference_type rhs)
300 {
301   pos_ -= rhs;
302   return *this;
303 }
304
305 template <class Tr> inline
306 const ArrayHandleIterator<Tr>
307 ArrayHandleIterator<Tr>::operator+(typename ArrayHandleIterator<Tr>::difference_type rhs) const
308 {
309   return ArrayHandleIterator<Tr>(pos_ + rhs);
310 }
311
312 template <class Tr> inline
313 const ArrayHandleIterator<Tr>
314 ArrayHandleIterator<Tr>::operator-(typename ArrayHandleIterator<Tr>::difference_type rhs) const
315 {
316   return ArrayHandleIterator<Tr>(pos_ - rhs);
317 }
318
319 template <class Tr> inline
320 typename ArrayHandleIterator<Tr>::difference_type
321 ArrayHandleIterator<Tr>::operator-(const ArrayHandleIterator<Tr>& rhs) const
322 {
323   return (pos_ - rhs.pos_);
324 }
325
326 template <class Tr> inline
327 bool ArrayHandleIterator<Tr>::operator==(const ArrayHandleIterator<Tr>& rhs) const
328 {
329   return (pos_ == rhs.pos_);
330 }
331
332 template <class Tr> inline
333 bool ArrayHandleIterator<Tr>::operator!=(const ArrayHandleIterator<Tr>& rhs) const
334 {
335   return (pos_ != rhs.pos_);
336 }
337
338 template <class Tr> inline
339 bool ArrayHandleIterator<Tr>::operator<(const ArrayHandleIterator<Tr>& rhs) const
340 {
341   return (pos_ < rhs.pos_);
342 }
343
344 template <class Tr> inline
345 bool ArrayHandleIterator<Tr>::operator>(const ArrayHandleIterator<Tr>& rhs) const
346 {
347   return (pos_ > rhs.pos_);
348 }
349
350 template <class Tr> inline
351 bool ArrayHandleIterator<Tr>::operator<=(const ArrayHandleIterator<Tr>& rhs) const
352 {
353   return (pos_ <= rhs.pos_);
354 }
355
356 template <class Tr> inline
357 bool ArrayHandleIterator<Tr>::operator>=(const ArrayHandleIterator<Tr>& rhs) const
358 {
359   return (pos_ >= rhs.pos_);
360 }
361
362 } // namespace Container_Helpers
363
364
365 /**** Glib::ArrayHandle<> **************************************************/
366
367 template <class T, class Tr>
368   template <class Cont>
369 inline
370 ArrayHandle<T,Tr>::ArrayHandle(const Cont& container)
371 :
372   size_      (Glib::Container_Helpers::ArraySourceTraits<Tr,Cont>::get_size(container)),
373   parray_    (Glib::Container_Helpers::ArraySourceTraits<Tr,Cont>::get_data(container, size_)),
374   ownership_ (Glib::Container_Helpers::ArraySourceTraits<Tr,Cont>::initial_ownership)
375 {}
376
377 template <class T, class Tr> inline
378 ArrayHandle<T,Tr>::ArrayHandle(const typename ArrayHandle<T,Tr>::CType* array, size_t array_size,
379                                Glib::OwnershipType ownership)
380 :
381   size_      (array_size),
382   parray_    (array),
383   ownership_ (ownership)
384 {}
385
386 template <class T, class Tr> inline
387 ArrayHandle<T,Tr>::ArrayHandle(const typename ArrayHandle<T,Tr>::CType* array,
388                                Glib::OwnershipType ownership)
389 :
390   size_      ((array) ? Glib::Container_Helpers::compute_array_size(array) : 0),
391   parray_    (array),
392   ownership_ (ownership)
393 {}
394
395 template <class T, class Tr> inline
396 ArrayHandle<T,Tr>::ArrayHandle(const ArrayHandle<T,Tr>& other)
397 :
398   size_      (other.size_),
399   parray_    (other.parray_),
400   ownership_ (other.ownership_)
401 {
402   other.ownership_ = Glib::OWNERSHIP_NONE;
403 }
404
405 template <class T, class Tr>
406 ArrayHandle<T,Tr>::~ArrayHandle()
407 {
408   if(ownership_ != Glib::OWNERSHIP_NONE)
409   {
410     if(ownership_ != Glib::OWNERSHIP_SHALLOW)
411     {
412       // Deep ownership: release each container element.
413       const CType *const pend = parray_ + size_;
414       for(const CType* p = parray_; p != pend; ++p)
415         Tr::release_c_type(*p);
416     }
417     g_free(const_cast<CType*>(parray_));
418   }
419 }
420
421 template <class T, class Tr> inline
422 typename ArrayHandle<T,Tr>::const_iterator ArrayHandle<T,Tr>::begin() const
423 {
424   return Glib::Container_Helpers::ArrayHandleIterator<Tr>(parray_);
425 }
426
427 template <class T, class Tr> inline
428 typename ArrayHandle<T,Tr>::const_iterator ArrayHandle<T,Tr>::end() const
429 {
430   return Glib::Container_Helpers::ArrayHandleIterator<Tr>(parray_ + size_);
431 }
432
433 template <class T, class Tr>
434   template <class U>
435 inline
436 ArrayHandle<T,Tr>::operator std::vector<U>() const
437 {
438 #ifdef GLIBMM_HAVE_TEMPLATE_SEQUENCE_CTORS
439   return std::vector<U>(this->begin(), this->end());
440 #else
441   std::vector<U> temp;
442   temp.reserve(this->size());
443   Glib::Container_Helpers::fill_container(temp, this->begin(), this->end());
444   return temp;
445 #endif
446 }
447
448 template <class T, class Tr>
449   template <class U>
450 inline
451 ArrayHandle<T,Tr>::operator std::deque<U>() const
452 {
453 #ifdef GLIBMM_HAVE_TEMPLATE_SEQUENCE_CTORS
454   return std::deque<U>(this->begin(), this->end());
455 #else
456   std::deque<U> temp;
457   Glib::Container_Helpers::fill_container(temp, this->begin(), this->end());
458   return temp;
459 #endif
460 }
461
462 template <class T, class Tr>
463   template <class U>
464 inline
465 ArrayHandle<T,Tr>::operator std::list<U>() const
466 {
467 #ifdef GLIBMM_HAVE_TEMPLATE_SEQUENCE_CTORS
468   return std::list<U>(this->begin(), this->end());
469 #else
470   std::list<U> temp;
471   Glib::Container_Helpers::fill_container(temp, this->begin(), this->end());
472   return temp;
473 #endif
474 }
475
476 template <class T, class Tr>
477   template <class Cont>
478 inline
479 void ArrayHandle<T,Tr>::assign_to(Cont& container) const
480 {
481 #ifdef GLIBMM_HAVE_TEMPLATE_SEQUENCE_CTORS
482   container.assign(this->begin(), this->end());
483 #else
484   Cont temp;
485   Glib::Container_Helpers::fill_container(temp, this->begin(), this->end());
486   container.swap(temp);
487 #endif
488 }
489
490 template <class T, class Tr>
491   template <class Out>
492 inline
493 void ArrayHandle<T,Tr>::copy(Out pdest) const
494 {
495   std::copy(this->begin(), this->end(), pdest);
496 }
497
498 template <class T, class Tr> inline
499 const typename ArrayHandle<T,Tr>::CType* ArrayHandle<T,Tr>::data() const
500 {
501   return parray_;
502 }
503
504 template <class T, class Tr> inline
505 size_t ArrayHandle<T,Tr>::size() const
506 {
507   return size_;
508 }
509
510 template <class T, class Tr> inline
511 bool ArrayHandle<T,Tr>::empty() const
512 {
513   return (size_ == 0);
514 }
515
516 #endif /* DOXYGEN_SHOULD_SKIP_THIS */
517
518 } // namespace Glib
519
520
521 #endif /* _GLIBMM_ARRAYHANDLE_H */
522