Remove the "** FIXME: THIS DOES NOT ACTUALLY WORK YET" lines.
[synfig.git] / ETL / trunk / ETL / _smart_ptr.h
1 /* ========================================================================
2 ** Extended Template and Library
3 ** Template Smart Pointer Implementation
4 ** $Id$
5 **
6 ** Copyright (c) 2002 Robert B. Quattlebaum Jr.
7 **
8 ** This package is free software; you can redistribute it and/or
9 ** modify it under the terms of the GNU General Public License as
10 ** published by the Free Software Foundation; either version 2 of
11 ** the License, or (at your option) any later version.
12 **
13 ** This package 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 ** General Public License for more details.
17 **
18 ** === N O T E S ===========================================================
19 **
20 ** This is an internal header file, included by other ETL headers.
21 ** You should not attempt to use it directly.
22 **
23 ** ========================================================================= */
24
25 /* === S T A R T =========================================================== */
26
27 #ifndef __ETL__SMART_PTR_H
28 #define __ETL__SMART_PTR_H
29
30 /* === H E A D E R S ======================================================= */
31
32 #include <cassert>
33 #include "_ref_count.h"
34
35 /* === M A C R O S ========================================================= */
36
37 /* === T Y P E D E F S ===================================================== */
38
39 /* === C L A S S E S & S T R U C T S ======================================= */
40
41 _ETL_BEGIN_NAMESPACE
42
43 template <class T>
44 struct generic_deleter
45 {
46         void operator()(T* x)const { delete x; }
47 };
48
49 template <class T>
50 struct array_deleter
51 {
52         void operator()(T* x)const { delete [] x; }
53 };
54
55 // ========================================================================
56 /*!     \class  smart_ptr       _smart_ptr.h    ETL/smart_ptr
57 **      \brief  Object Smart Pointer
58 **      \see loose_smart_ptr
59 **      \writeme
60 */
61 template <class T, class D=generic_deleter<T> >
62 class smart_ptr
63 {
64 public:
65
66         typedef T value_type;
67         typedef T& reference;
68         typedef const T& const_reference;
69         typedef T* pointer;
70         typedef const T* const_pointer;
71         typedef int count_type;
72         typedef int size_type;
73         typedef D destructor_type;
74
75 #ifdef DOXYGEN_SHOULD_SKIP_THIS         // #ifdef is not a typo
76 private:
77 #endif
78         value_type *obj;                //!< \internal Pointer to object
79         reference_counter refcount;
80
81 public:
82         // Private constructor for convenience
83         smart_ptr(value_type* obj,reference_counter refcount):obj(obj),refcount(refcount) {  }
84
85         //! Default constructor - empty smart_ptr
86         smart_ptr():obj(0),refcount(false) {}
87
88         //! Constructor that constructs from a pointer to new object
89         /*! A new smart_ptr is created with a pointer
90                 to a newly allocated object. We need
91                 to be explicit with this so we don't
92                 accidently have two smart_ptrs for one
93                 object -- that would be bad.    */
94         explicit smart_ptr(value_type* x):obj(x),refcount(x?true:false) {  }
95
96         //! Template copy constructor
97         /*! This template constructor allows us to cast
98                 smart_ptrs much like we would pointers. */
99 #ifdef _WIN32
100         template <class U>
101         smart_ptr(const smart_ptr<U> &x):obj((pointer)&*x.obj),refcount(x.refcount())
102                 { }
103 #endif
104
105         //! Default copy constructor
106         /*! The template above is not good enough
107                 for all compilers. We need to explicitly
108                 define the copy constructor for this
109                 class to work on those compilers. */
110         smart_ptr(const smart_ptr<value_type> &x):obj(x.obj),refcount(x.refcount) {  }
111
112         explicit smart_ptr(const value_type &x):obj(new value_type(x)) { }
113
114         //! smart_ptr is released on deletion
115         ~smart_ptr() { if(refcount.unique()) destructor_type()(obj); }
116
117         //! Template Assignment operator
118         template <class U> const smart_ptr<value_type> &
119         operator=(const smart_ptr<U> &x)
120         {
121                 if(x.get()==obj)
122                         return *this;
123
124                 reset();
125
126                 if(x.obj)
127                 {
128                         obj=(pointer)x.get();
129                         refcount=x.refcount;
130                 }
131
132                 return *this;
133         }
134
135         //! Assignment operator
136         const smart_ptr<value_type> &
137         operator=(const smart_ptr<value_type> &x)
138         {
139                 if(x.get()==obj)
140                         return *this;
141
142                 reset();
143
144                 if(x.obj)
145                 {
146
147                         obj=(pointer)x.get();
148                         refcount=x.refcount;
149                 }
150
151                 return *this;
152         }
153
154         //! smart_ptr reset procedure
155         void
156         reset()
157         {
158                 if(obj)
159                 {
160                         if(refcount.unique()) destructor_type()(obj);
161                         refcount.detach();
162                         obj=0;
163                 }
164         }
165
166         void spawn() { operator=(smart_ptr(new T)); }
167
168         //! Returns number of instances
169         const count_type& count()const { return refcount; }
170
171         //! Returns true if there is only one instance of the object
172         bool unique()const { return refcount.unique(); }
173
174         //! Returns a constant handle to our object
175         smart_ptr<const value_type> constant() { return *this; }
176
177         reference operator*()const { assert(obj); return *obj; }
178
179         pointer operator->()const { assert(obj); return obj; }
180
181
182         operator smart_ptr<const value_type>()const
183         { return smart_ptr<const value_type>(static_cast<const_pointer>(obj)); }
184
185         //! static_cast<> wrapper
186         template <class U> static
187         smart_ptr<T> cast_static(const smart_ptr<U> &x)
188         { if(!x)return NULL; return smart_ptr<T>(static_cast<T*>(x.get()),x.refcount); }
189
190         //! dynamic_cast<> wrapper
191         template <class U> static
192         smart_ptr<T> cast_dynamic(const smart_ptr<U> &x)
193         { if(!x)return 0; return smart_ptr<T>(dynamic_cast<T*>(x.get()),x.refcount); }
194
195         //! const_cast<> wrapper
196         template <class U> static
197         smart_ptr<T> cast_const(const smart_ptr<U> &x)
198         { if(!x)return 0; return smart_ptr<T>(const_cast<T*>(x.get()),x.refcount); }
199
200         pointer get()const { return obj; }
201
202         //! More explicit bool cast
203         operator bool()const { return obj!=0; }
204
205         bool operator!()const { return !obj; }
206
207         //! Overloaded cast operator -- useful for implicit casts
208         template <class U>
209         operator smart_ptr<U>()
210         {
211                 // This next line should provide a syntax check
212                 // to make sure that this cast makes sense.
213                 // If it doesn't, this should have a compiler error.
214                 // Otherwise, it should get optimized right out
215                 // of the code.
216                 //(U*)obj;
217
218                 return *reinterpret_cast<smart_ptr<U>*>(this);
219         }
220
221 }; // END of template class smart_ptr
222
223 // ========================================================================
224 /*!     \class  loose_smart_ptr _smart_ptr.h    ETL/smart_ptr
225 **      \brief  Loose Object Smart Pointer
226 **      \see smart_ptr
227 **      \writeme
228 */
229 template <class T>
230 class loose_smart_ptr
231 {
232 public:
233
234         typedef T value_type;
235         typedef T& reference;
236         typedef const T& const_reference;
237         typedef T* pointer;
238         typedef const T* const_pointer;
239         typedef int count_type;
240         typedef int size_type;
241
242 private:
243         value_type *obj;                //!< \internal Pointer to object
244         weak_reference_counter refcount;        //!< \internal Pointer to object's reference counter
245
246 public:
247
248         //! Default constructor - empty smart_ptr
249         loose_smart_ptr():obj(0),refcount(0) {}
250
251         //! Default copy constructor
252         loose_smart_ptr(const loose_smart_ptr<value_type> &x):obj(x.get()),refcount(x.refcount) { }
253
254         loose_smart_ptr(const smart_ptr<value_type> &x):obj(x.get()),refcount(x.refcount) { }
255
256         void reset() { obj=0,refcount=0; }
257
258         operator smart_ptr<value_type>()
259         {
260                 return smart_ptr<value_type>(static_cast<pointer>(obj),refcount);
261         }
262
263         operator smart_ptr<const value_type>()
264         {
265                 return smart_ptr<const value_type>(static_cast<const_pointer>(obj),refcount);
266         }
267
268         //! Returns number of instances
269         const count_type& count()const { return refcount; }
270
271         bool unique()const { return refcount.unique(); }
272
273         reference operator*()const { assert(obj); return *obj; }
274
275         pointer operator->()const { assert(obj); return obj; }
276
277         pointer get()const { return obj; }
278
279         bool operator!()const { return !obj; }
280 };
281
282 template <class T,class U> bool
283 operator==(const smart_ptr<T> &lhs,const smart_ptr<U> &rhs)
284         { return (lhs.get()==rhs.get()); }
285 template <class T,class U> bool
286 operator==(const loose_smart_ptr<T> &lhs,const loose_smart_ptr<U> &rhs)
287         { return (lhs.get()==rhs.get()); }
288 template <class T,class U> bool
289 operator==(const smart_ptr<T> &lhs,const loose_smart_ptr<U> &rhs)
290         { return (lhs.get()==rhs.get()); }
291 template <class T,class U> bool
292 operator==(const loose_smart_ptr<T> &lhs,const smart_ptr<U> &rhs)
293         { return (lhs.get()==rhs.get()); }
294 template <class T> bool
295 operator==(const smart_ptr<T> &lhs,const T *rhs)
296         { return (lhs.get()==rhs); }
297 template <class T> bool
298 operator==(const loose_smart_ptr<T> &lhs,const T *rhs)
299         { return (lhs.get()==rhs); }
300 template <class T> bool
301 operator==(const T *lhs,const smart_ptr<T> &rhs)
302         { return (lhs==rhs.get()); }
303 template <class T> bool
304 operator==(const T *lhs,const loose_smart_ptr<T> &rhs)
305         { return (lhs==rhs.get()); }
306
307
308 template <class T,class U> bool
309 operator!=(const smart_ptr<T> &lhs,const smart_ptr<U> &rhs)
310         { return (lhs.get()!=rhs.get()); }
311 template <class T,class U> bool
312 operator!=(const loose_smart_ptr<T> &lhs,const loose_smart_ptr<U> &rhs)
313         { return (lhs.get()!=rhs.get()); }
314 template <class T,class U> bool
315 operator!=(const smart_ptr<T> &lhs,const loose_smart_ptr<U> &rhs)
316         { return (lhs.get()!=rhs.get()); }
317 template <class T,class U> bool
318 operator!=(const loose_smart_ptr<T> &lhs,const smart_ptr<U> &rhs)
319         { return (lhs.get()!=rhs.get()); }
320 template <class T> bool
321 operator!=(const smart_ptr<T> &lhs,const T *rhs)
322         { return (lhs.get()!=rhs); }
323 template <class T> bool
324 operator!=(const loose_smart_ptr<T> &lhs,const T *rhs)
325         { return (lhs.get()!=rhs); }
326 template <class T> bool
327 operator!=(const T *lhs,const smart_ptr<T> &rhs)
328         { return (lhs!=rhs.get()); }
329 template <class T> bool
330 operator!=(const T *lhs,const loose_smart_ptr<T> &rhs)
331         { return (lhs!=rhs.get()); }
332
333
334 template <class T,class U> bool
335 operator<(const smart_ptr<T> &lhs,const smart_ptr<U> &rhs)
336         { return (lhs.get()<rhs.get()); }
337 template <class T,class U> bool
338 operator<(const loose_smart_ptr<T> &lhs,const loose_smart_ptr<U> &rhs)
339         { return (lhs.get()<rhs.get()); }
340 template <class T,class U> bool
341 operator<(const smart_ptr<T> &lhs,const loose_smart_ptr<U> &rhs)
342         { return (lhs.get()<rhs.get()); }
343 template <class T,class U> bool
344 operator<(const loose_smart_ptr<T> &lhs,const smart_ptr<U> &rhs)
345         { return (lhs.get()<rhs.get()); }
346 template <class T> bool
347 operator<(const smart_ptr<T> &lhs,const T *rhs)
348         { return (lhs.get()<rhs); }
349 template <class T> bool
350 operator<(const loose_smart_ptr<T> &lhs,const T *rhs)
351         { return (lhs.get()<rhs); }
352 template <class T> bool
353 operator<(const T *lhs,const smart_ptr<T> &rhs)
354         { return (lhs<rhs.get()); }
355 template <class T> bool
356 operator<(const T *lhs,const loose_smart_ptr<T> &rhs)
357         { return (lhs<rhs.get()); }
358
359 _ETL_END_NAMESPACE
360
361 /* === E N D =============================================================== */
362
363 #endif