1 /* === E T L =============================================================== */
4 ** \brief Template Object Handle Implementation
8 ** Copyright (c) 2002 Robert B. Quattlebaum Jr.
9 ** Copyright (c) 2007 Chris Moore
11 ** This package is free software; you can redistribute it and/or
12 ** modify it under the terms of the GNU General Public License as
13 ** published by the Free Software Foundation; either version 2 of
14 ** the License, or (at your option) any later version.
16 ** This package is distributed in the hope that it will be useful,
17 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
18 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 ** General Public License for more details.
23 ** This is an internal header file, included by other ETL headers.
24 ** You should not attempt to use it directly.
26 /* ========================================================================= */
28 /* === S T A R T =========================================================== */
30 #ifndef __ETL__HANDLE_H
31 #define __ETL__HANDLE_H
33 /* === H E A D E R S ======================================================= */
35 // include the next line in an attempt to increase stability
36 #define ETL_LOCK_REFCOUNTS
40 #ifdef ETL_LOCK_REFCOUNTS
41 # include "_mutex_simple.h"
44 /* === M A C R O S ========================================================= */
46 /* === T Y P E D E F S ===================================================== */
48 #define ETL_SELF_DELETING_SHARED_OBJECT
50 /* === C L A S S E S & S T R U C T S ======================================= */
53 #define assert_cast static_cast
55 #define assert_cast dynamic_cast
61 // Forward Declarations
62 template <class T> class handle;
63 template <class T> class loose_handle;
64 template <class T> class rhandle;
67 // ========================================================================
68 /*! \class shared_object _handle.h ETL/handle
69 ** \brief Shared Object Base Class
70 ** \see handle, loose_handle
77 #ifdef ETL_LOCK_REFCOUNTS
78 mutable etl::mutex mtx;
82 shared_object():refcount(0) { }
84 #ifdef ETL_SELF_DELETING_SHARED_OBJECT
85 virtual ~shared_object() { }
93 #ifdef ETL_LOCK_REFCOUNTS
94 etl::mutex::lock lock(mtx);
100 //! Returns \c false if object needs to be deleted
105 #ifdef ETL_LOCK_REFCOUNTS
106 etl::mutex::lock lock(mtx);
114 #ifdef ETL_SELF_DELETING_SHARED_OBJECT
120 #ifdef ETL_SELF_DELETING_SHARED_OBJECT
127 int count()const { return refcount; }
129 }; // END of class shared_object
131 // ========================================================================
132 /*! \class virtual_shared_object _handle.h ETL/handle
133 ** \brief Virtual Shared Object Base Class
134 ** \see handle, loose_handle
137 class virtual_shared_object
140 virtual_shared_object() { }
142 virtual ~virtual_shared_object()=0;
143 virtual void ref()const=0;
144 virtual bool unref()const=0;
145 virtual int count()const=0;
146 virtual virtual_shared_object *clone()=0;
147 }; // END of class virtual_shared_object
149 // ========================================================================
150 /*! \class handle _handle.h ETL/handle
151 ** \brief Object Handle
152 ** \see shared_object, loose_handle
160 typedef T value_type;
161 typedef T& reference;
162 typedef const T& const_reference;
164 typedef const T* const_pointer;
165 typedef int count_type;
166 typedef int size_type;
172 value_type *obj; //!< Pointer to object
176 //! Default constructor - empty handle
177 handle():obj(NULL) {}
179 //! Constructor that constructs from a pointer to new object
180 handle(pointer x):obj(x)
186 //! Default copy constructor
187 handle(const handle<value_type> &x):obj(x.get())
193 //! Handle is released on deletion
194 ~handle() { detach(); }
196 //! Template Assignment operator
197 /*! \note This class may not be necessary, and may be removed
198 ** at some point in the future.
201 template <class U> handle<value_type> &
202 operator=(const handle<U> &x)
209 obj=static_cast<value_type*>(x.get());
215 //! Assignment operator
217 operator=(const handle<value_type> &x)
229 //! Swaps the values of two handles without reference counts
231 swap(handle<value_type> &x)
239 //! Handle detach procedure
240 /*! unref()'s the object and sets the internal object pointer to \c NULL */
246 #ifdef ETL_SELF_DELETING_SHARED_OBJECT
250 if(xobj && !xobj->unref())
255 // This will be reintroduced with a new function
256 //void release() { detach(); }
258 void reset() { detach(); }
260 bool empty()const { return obj==0; }
262 //! Creates a new instance of a T object and puts it in the handle.
263 /*! Uses the default constructor */
264 void spawn() { operator=(handle(new T())); }
266 handle<value_type> clone()const { assert(obj); return static_cast<value_type*>(obj->clone()); }
268 //! Returns a constant handle to our object
269 handle<const value_type> constant()const { assert(obj); return *this; }
271 //! Returns number of instances
274 { return obj?obj->count():0; }
276 //! Returns true if there is only one instance of the object
279 { assert(obj); return count()==1; }
283 { assert(obj); return *obj; }
287 { assert(obj); return obj; }
289 //! More explicit bool cast
291 { return obj!=NULL; }
293 operator handle<const value_type>()const
294 { return handle<const value_type>(static_cast<const_pointer>(obj)); }
296 //! <tt> static_cast\<\> </tt> wrapper
297 template <class U> static handle<T> cast_static (const handle<U> &x) { return handle<T>(static_cast <T*>(x.get())); }
298 //! <tt> dynamic_cast\<\> </tt> wrapper
299 template <class U> static handle<T> cast_dynamic (const handle<U> &x) { return handle<T>(dynamic_cast <T*>(x.get())); }
300 //! <tt> const_cast\<\> </tt> wrapper
301 template <class U> static handle<T> cast_const (const handle<U> &x) { return handle<T>(const_cast <T*>(x.get())); }
302 //! <tt> reinterpret_cast\<\> </tt> wrapper
303 template <class U> static handle<T> cast_reinterpret(const handle<U> &x) { return handle<T>(reinterpret_cast<T*>(x.get())); }
305 template <class U> static handle<T> cast_static (const loose_handle<U> &x);
306 template <class U> static handle<T> cast_dynamic (const loose_handle<U> &x);
307 template <class U> static handle<T> cast_const (const loose_handle<U> &x);
308 template <class U> static handle<T> cast_reinterpret(const loose_handle<U> &x);
310 template <class U> static handle<T> cast_static (const rhandle<U> &x);
311 template <class U> static handle<T> cast_dynamic (const rhandle<U> &x);
312 template <class U> static handle<T> cast_const (const rhandle<U> &x);
313 template <class U> static handle<T> cast_reinterpret(const rhandle<U> &x);
315 template <class U> static handle<T> cast_static (U* x);
316 template <class U> static handle<T> cast_dynamic (U* x);
317 template <class U> static handle<T> cast_const (U* x);
318 template <class U> static handle<T> cast_reinterpret(U* x);
320 //! Returns pointer to the object that is being wrapped
321 pointer get()const { return obj; }
327 //! static_cast<> overload -- Useful for implicit casts
329 operator handle<U>()const
330 { return handle<U>(static_cast<U*>(obj)); }
331 }; // END of template class handle
333 // ========================================================================
334 /*! \class rshared_object _handle.h ETL/handle
335 ** \brief Replaceable Shared Object Base Class
339 class rshared_object : public shared_object
342 mutable int rrefcount;
349 rshared_object():rrefcount(0),front_(0),back_(0) { }
362 { return rrefcount; }
363 }; // END of class rshared_object
365 // ========================================================================
366 /*! \class rhandle _handle.h ETL/handle
367 ** \brief Replaceable Object Handle
368 ** \see rshared_object, handle, loose_handle
372 class rhandle : public handle<T>
374 friend class rshared_object;
377 typedef T value_type;
378 typedef T& reference;
379 typedef const T& const_reference;
381 typedef const T* const_pointer;
382 typedef int count_type;
383 typedef int size_type;
386 using handle<value_type>::count;
387 using handle<value_type>::unique;
388 using handle<value_type>::operator bool;
389 using handle<value_type>::get;
390 using handle<value_type>::operator*;
391 using handle<value_type>::operator->;
394 operator const handle<value_type>&()const
399 using handle<value_type>::obj;
401 rhandle<value_type> *prev_;
402 rhandle<value_type> *next_;
406 // value_type*& obj(handle<T>::obj); // Required to keep gcc 3.4.2 from barfing
411 // If this is the first reversible handle
414 obj->front_=obj->back_=this;
419 prev_=reinterpret_cast<rhandle<value_type>*>(obj->back_);
425 void del_from_rlist()
427 // value_type*& obj(handle<T>::obj); // Required to keep gcc 3.4.2 from barfing
431 // If this is the last reversible handle
432 if(obj->front_==obj->back_)
434 obj->front_=obj->back_=0;
440 obj->front_=(void*)next_;
445 obj->back_=(void*)prev_;
452 //! Default constructor - empty handle
455 //! Constructor that constructs from a pointer to new object
456 rhandle(pointer x):handle<T>(x)
458 // value_type*& obj(handle<T>::obj); // Required to keep gcc 3.4.2 from barfing
459 if(obj)add_to_rlist();
462 rhandle(const handle<value_type> &x):handle<T>(x)
464 // value_type*& obj(handle<T>::obj); // Required to keep gcc 3.4.2 from barfing
465 if(obj)add_to_rlist();
468 //! Default copy constructor
469 rhandle(const rhandle<value_type> &x):handle<T>(x)
471 // value_type*& obj(handle<T>::obj); // Required to keep gcc 3.4.2 from barfing
472 if(obj)add_to_rlist();
475 //! Handle is released on deletion
476 ~rhandle() { detach(); }
478 //! Template Assignment operator
479 /*! \note This class may not be necessary, and may be removed
480 ** at some point in the future.
483 template <class U> const handle<value_type> &
484 operator=(const handle<U> &x)
491 obj=static_cast<value_type*>(x.get());
501 //! Assignment operator
502 rhandle<value_type> &
503 operator=(const rhandle<value_type> &x)
505 // value_type*& obj(handle<T>::obj); // Required to keep gcc 3.4.2 from barfing
521 operator=(const handle<value_type> &x)
523 // value_type*& obj(handle<T>::obj); // Required to keep gcc 3.4.2 from barfing
539 operator=(value_type* x)
541 // value_type*& obj(handle<T>::obj); // Required to keep gcc 3.4.2 from barfing
556 //! Handle release procedure
557 /*! unref()'s the object and sets the internal object pointer to \c NULL */
561 // value_type*& obj(handle<T>::obj); // Required to keep gcc 3.4.2 from barfing
562 if(obj)del_from_rlist();
563 handle<value_type>::detach();
567 // This will be reintroduced with a new function
568 //void release() { detach(); }
570 void reset() { detach(); }
572 //! Creates a new instance of a T object and puts it in the handle.
573 /*! Uses the default constructor */
574 void spawn() { operator=(handle<value_type>(new T())); }
576 //! Returns number of reversible instances
580 // value_type*const& obj(handle<T>::obj); // Required to keep gcc 3.4.2 from barfing
581 return obj?obj->rcount():0;
584 //! Returns true if there is only one instance of the object
588 // value_type*& obj(handle<T>::obj); // Required to keep gcc 3.4.2 from barfing
589 assert(obj); return obj->front_==obj->back_;
593 int replace(const handle<value_type> &x)
595 // value_type*& obj(handle<T>::obj); // Required to keep gcc 3.4.2 from barfing
597 assert(x.get()!=obj);
602 rhandle<value_type> *iter;
603 rhandle<value_type> *next;
605 iter=reinterpret_cast<rhandle<value_type>*>(obj->front_);
616 for(;iter;iter=next,next=iter?iter->next_:0,i++)
618 assert(iter->get()==obj_);
622 assert(obj==x.get());
627 //! Swaps the values of two handles without reference counts
628 /*! \warning not yet implemented. \writeme */
630 swap(handle<value_type> &x);
640 }; // END of template class rhandle
643 // ========================================================================
644 /*! \class loose_handle _handle.h ETL/handle
645 ** \brief Loose Object Handle
646 ** \see shared_object, handle
654 typedef T value_type;
655 typedef T& reference;
656 typedef const T& const_reference;
658 typedef const T* const_pointer;
659 typedef int count_type;
660 typedef int size_type;
666 value_type *obj; //!< Pointer to object
670 //! Default constructor - empty handle
671 loose_handle():obj(0) {}
673 //! Constructor that constructs from a pointer to new object
674 loose_handle(pointer x):obj(x) { }
676 //! Default copy constructor
677 loose_handle(const loose_handle<value_type> &x):obj(x.get()) { }
679 loose_handle(const handle<value_type> &x):obj(x.get()) { }
681 template <class U> const loose_handle<value_type> &
682 operator=(const handle<U> &x)
687 obj=static_cast<value_type*>(x.get());
691 template <class U> const loose_handle<value_type> &
692 operator=(const loose_handle<U> &x)
697 obj=static_cast<value_type*>(x.get());
701 //! Assignment operator
702 const loose_handle<value_type> &
703 operator=(const loose_handle<value_type> &x)
712 //! Swaps the values of two handles without reference counts
713 loose_handle<value_type> &
714 swap(loose_handle<value_type> &x)
722 //! Handle release procedure
723 void detach() { obj=0; }
725 // This will be reintroduced with a new function
726 //void release() { detach(); }
728 void reset() { detach(); }
730 bool empty()const { return obj==0; }
732 handle<value_type> clone()const { assert(obj); return obj->clone(); }
734 //! Returns a constant handle to our object
735 loose_handle<const value_type> constant()const { return *this; }
737 //! Returns number of instances
740 { return obj?obj->count():0; }
744 { assert(obj); return *obj; }
748 { assert(obj); return obj; }
750 //! static_cast<> overload
752 //operator loose_handle<U>()const
753 //{ return loose_handle<U>(static_cast<U*>(obj)); }
755 //! static_cast<> overload (for consts)
756 operator loose_handle<const value_type>()const
757 { return loose_handle<const value_type>(static_cast<const_pointer>(obj)); }
759 operator handle<value_type>()const
760 { return handle<value_type>(obj); }
762 operator rhandle<value_type>()const
763 { return rhandle<value_type>(obj); }
765 //! Returns pointer to the object that is being wrapped
766 pointer get()const { return obj; }
768 //! More explicit bool cast
776 void ref() { if(obj)obj->ref(); }
778 bool unref() { if(obj && !obj->unref()){ obj=0; return false; } return true; }
779 }; // END of template class loose_handle
781 // cast loose_handle<> -> handle<>
782 template <class T> template <class U> handle<T> handle<T>::cast_static (const loose_handle<U>& x) { return handle<T>(static_cast <T*>(x.get())); }
783 template <class T> template <class U> handle<T> handle<T>::cast_dynamic (const loose_handle<U>& x) { return handle<T>(dynamic_cast <T*>(x.get())); }
784 template <class T> template <class U> handle<T> handle<T>::cast_const (const loose_handle<U>& x) { return handle<T>(const_cast <T*>(x.get())); }
785 template <class T> template <class U> handle<T> handle<T>::cast_reinterpret(const loose_handle<U>& x) { return handle<T>(reinterpret_cast<T*>(x.get())); }
787 // cast rhandle_handle<> -> handle<>
788 template <class T> template <class U> handle<T> handle<T>::cast_static (const rhandle<U>& x) { return handle<T>(static_cast <T*>(x.get())); }
789 template <class T> template <class U> handle<T> handle<T>::cast_dynamic (const rhandle<U>& x) { return handle<T>(dynamic_cast <T*>(x.get())); }
790 template <class T> template <class U> handle<T> handle<T>::cast_const (const rhandle<U>& x) { return handle<T>(const_cast <T*>(x.get())); }
791 template <class T> template <class U> handle<T> handle<T>::cast_reinterpret(const rhandle<U>& x) { return handle<T>(reinterpret_cast<T*>(x.get())); }
793 // cast U* -> handle<>
794 template <class T> template <class U> handle<T> handle<T>::cast_static (U* x) { return handle<T>(static_cast <T*>(x)); }
795 template <class T> template <class U> handle<T> handle<T>::cast_dynamic (U* x) { return handle<T>(dynamic_cast <T*>(x)); }
796 template <class T> template <class U> handle<T> handle<T>::cast_const (U* x) { return handle<T>(const_cast <T*>(x)); }
797 template <class T> template <class U> handle<T> handle<T>::cast_reinterpret(U* x) { return handle<T>(reinterpret_cast<T*>(x)); }
799 // operator== for handle<>, loose_handle<> and T*
800 template <class T,class U> bool operator==(const handle <T>& lhs,const handle <U>& rhs) { return (lhs.get()==rhs.get()); }
801 template <class T,class U> bool operator==(const loose_handle<T>& lhs,const loose_handle<U>& rhs) { return (lhs.get()==rhs.get()); }
802 template <class T,class U> bool operator==(const handle <T>& lhs,const loose_handle<U>& rhs) { return (lhs.get()==rhs.get()); }
803 template <class T,class U> bool operator==(const loose_handle<T>& lhs,const handle <U>& rhs) { return (lhs.get()==rhs.get()); }
804 template <class T> bool operator==(const handle<T>& lhs,const T* rhs) { return (lhs.get()==rhs); }
805 template <class T> bool operator==(const loose_handle<T>& lhs,const T* rhs) { return (lhs.get()==rhs); }
806 template <class T> bool operator==(const T* lhs,const handle<T>& rhs) { return (lhs ==rhs.get()); }
807 template <class T> bool operator==(const T* lhs,const loose_handle<T>& rhs) { return (lhs ==rhs.get()); }
809 // operator!= for handle<>, loose_handle<> and T*
810 template <class T,class U> bool operator!=(const handle <T>& lhs,const handle <U>& rhs) { return (lhs.get()!=rhs.get()); }
811 template <class T,class U> bool operator!=(const loose_handle<T>& lhs,const loose_handle<U>& rhs) { return (lhs.get()!=rhs.get()); }
812 template <class T,class U> bool operator!=(const handle <T>& lhs,const loose_handle<U>& rhs) { return (lhs.get()!=rhs.get()); }
813 template <class T,class U> bool operator!=(const loose_handle<T>& lhs,const handle <U>& rhs) { return (lhs.get()!=rhs.get()); }
814 template <class T> bool operator!=(const handle<T>& lhs,const T* rhs) { return (lhs.get()!=rhs); }
815 template <class T> bool operator!=(const loose_handle<T>& lhs,const T* rhs) { return (lhs.get()!=rhs); }
816 template <class T> bool operator!=(const T* lhs,const handle<T>& rhs) { return (lhs !=rhs.get()); }
817 template <class T> bool operator!=(const T* lhs,const loose_handle<T>& rhs) { return (lhs !=rhs.get()); }
819 // operator< for handle<>, loose_handle<> and T*
820 template <class T,class U> bool operator<(const handle<T>& lhs,const handle<U>& rhs) { return (lhs.get()<rhs.get()); }
821 template <class T,class U> bool operator<(const loose_handle<T>& lhs,const loose_handle<U>& rhs) { return (lhs.get()<rhs.get()); }
822 template <class T,class U> bool operator<(const handle<T>& lhs,const loose_handle<U>& rhs) { return (lhs.get()<rhs.get()); }
823 template <class T,class U> bool operator<(const loose_handle<T>& lhs,const handle<U>& rhs) { return (lhs.get()<rhs.get()); }
824 template <class T> bool operator<(const handle<T>& lhs,const T* rhs) { return (lhs.get()<rhs); }
825 template <class T> bool operator<(const loose_handle<T>& lhs,const T* rhs) { return (lhs.get()<rhs); }
826 template <class T> bool operator<(const T* lhs,const handle<T>& rhs) { return (lhs <rhs.get()); }
827 template <class T> bool operator<(const T* lhs,const loose_handle<T>& rhs) { return (lhs <rhs.get()); }
831 /* === E N D =============================================================== */