1 /* === E T L =============================================================== */
4 ** \brief Template Object Handle Implementation
8 ** Copyright (c) 2002 Robert B. Quattlebaum Jr.
9 ** Copyright (c) 2007, 2008 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 ======================================================= */
37 /* === M A C R O S ========================================================= */
39 /* === T Y P E D E F S ===================================================== */
41 #define ETL_SELF_DELETING_SHARED_OBJECT
43 /* === C L A S S E S & S T R U C T S ======================================= */
46 #define assert_cast static_cast
48 #define assert_cast dynamic_cast
54 // Forward Declarations
55 template <class T> class handle;
56 template <class T> class loose_handle;
57 template <class T> class rhandle;
60 // ========================================================================
61 /*! \class shared_object _handle.h ETL/handle
62 ** \brief Shared Object Base Class
63 ** \see handle, loose_handle
70 #ifdef ETL_LOCK_REFCOUNTS
71 mutable etl::mutex mtx;
75 shared_object():refcount(0) { }
77 #ifdef ETL_SELF_DELETING_SHARED_OBJECT
78 virtual ~shared_object() { }
86 #ifdef ETL_LOCK_REFCOUNTS
87 etl::mutex::lock lock(mtx);
93 //! Returns \c false if object needs to be deleted
98 #ifdef ETL_LOCK_REFCOUNTS
99 etl::mutex::lock lock(mtx);
107 #ifdef ETL_SELF_DELETING_SHARED_OBJECT
113 #ifdef ETL_SELF_DELETING_SHARED_OBJECT
120 int count()const { return refcount; }
122 }; // END of class shared_object
124 // ========================================================================
125 /*! \class virtual_shared_object _handle.h ETL/handle
126 ** \brief Virtual Shared Object Base Class
127 ** \see handle, loose_handle
130 class virtual_shared_object
133 virtual_shared_object() { }
135 virtual ~virtual_shared_object()=0;
136 virtual void ref()const=0;
137 virtual bool unref()const=0;
138 virtual int count()const=0;
139 virtual virtual_shared_object *clone()=0;
140 }; // END of class virtual_shared_object
142 // ========================================================================
143 /*! \class handle _handle.h ETL/handle
144 ** \brief Object Handle
145 ** \see shared_object, loose_handle
153 typedef T value_type;
154 typedef T& reference;
155 typedef const T& const_reference;
157 typedef const T* const_pointer;
158 typedef int count_type;
159 typedef int size_type;
165 value_type *obj; //!< Pointer to object
169 //! Default constructor - empty handle
170 handle():obj(NULL) {}
172 //! Constructor that constructs from a pointer to new object
173 handle(pointer x):obj(x)
179 //! Default copy constructor
180 handle(const handle<value_type> &x):obj(x.get())
186 //! Handle is released on deletion
187 ~handle() { detach(); }
189 //! Template Assignment operator
190 /*! \note This class may not be necessary, and may be removed
191 ** at some point in the future.
194 template <class U> handle<value_type> &
195 operator=(const handle<U> &x)
202 obj=static_cast<value_type*>(x.get());
208 //! Assignment operator
210 operator=(const handle<value_type> &x)
222 //! Swaps the values of two handles without reference counts
224 swap(handle<value_type> &x)
232 //! Handle detach procedure
233 /*! unref()'s the object and sets the internal object pointer to \c NULL */
239 #ifdef ETL_SELF_DELETING_SHARED_OBJECT
243 if(xobj && !xobj->unref())
248 // This will be reintroduced with a new function
249 //void release() { detach(); }
251 void reset() { detach(); }
253 bool empty()const { return obj==0; }
255 //! Creates a new instance of a T object and puts it in the handle.
256 /*! Uses the default constructor */
257 void spawn() { operator=(handle(new T())); }
259 handle<value_type> clone()const { assert(obj); return static_cast<value_type*>(obj->clone()); }
261 //! Returns a constant handle to our object
262 handle<const value_type> constant()const { assert(obj); return *this; }
264 //! Returns number of instances
267 { return obj?obj->count():0; }
269 //! Returns true if there is only one instance of the object
272 { assert(obj); return count()==1; }
276 { assert(obj); return *obj; }
280 { assert(obj); return obj; }
282 //! More explicit bool cast
284 { return obj!=NULL; }
286 operator handle<const value_type>()const
287 { return handle<const value_type>(static_cast<const_pointer>(obj)); }
289 //! <tt> static_cast\<\> </tt> wrapper
290 template <class U> static handle<T> cast_static (const handle<U> &x) { return handle<T>(static_cast <T*>(x.get())); }
291 //! <tt> dynamic_cast\<\> </tt> wrapper
292 template <class U> static handle<T> cast_dynamic (const handle<U> &x) { return handle<T>(dynamic_cast <T*>(x.get())); }
293 //! <tt> const_cast\<\> </tt> wrapper
294 template <class U> static handle<T> cast_const (const handle<U> &x) { return handle<T>(const_cast <T*>(x.get())); }
295 //! <tt> reinterpret_cast\<\> </tt> wrapper
296 template <class U> static handle<T> cast_reinterpret(const handle<U> &x) { return handle<T>(reinterpret_cast<T*>(x.get())); }
298 template <class U> static handle<T> cast_static (const loose_handle<U> &x);
299 template <class U> static handle<T> cast_dynamic (const loose_handle<U> &x);
300 template <class U> static handle<T> cast_const (const loose_handle<U> &x);
301 template <class U> static handle<T> cast_reinterpret(const loose_handle<U> &x);
303 template <class U> static handle<T> cast_static (const rhandle<U> &x);
304 template <class U> static handle<T> cast_dynamic (const rhandle<U> &x);
305 template <class U> static handle<T> cast_const (const rhandle<U> &x);
306 template <class U> static handle<T> cast_reinterpret(const rhandle<U> &x);
308 template <class U> static handle<T> cast_static (U* x);
309 template <class U> static handle<T> cast_dynamic (U* x);
310 template <class U> static handle<T> cast_const (U* x);
311 template <class U> static handle<T> cast_reinterpret(U* x);
313 //! Returns pointer to the object that is being wrapped
314 pointer get()const { return obj; }
320 //! static_cast<> overload -- Useful for implicit casts
322 operator handle<U>()const
323 { return handle<U>(static_cast<U*>(obj)); }
324 }; // END of template class handle
326 // ========================================================================
327 /*! \class rshared_object _handle.h ETL/handle
328 ** \brief Replaceable Shared Object Base Class
332 class rshared_object : public shared_object
335 mutable int rrefcount;
342 rshared_object():rrefcount(0),front_(0),back_(0) { }
355 { return rrefcount; }
356 }; // END of class rshared_object
358 // ========================================================================
359 /*! \class rhandle _handle.h ETL/handle
360 ** \brief Replaceable Object Handle
361 ** \see rshared_object, handle, loose_handle
365 class rhandle : public handle<T>
367 friend class rshared_object;
370 typedef T value_type;
371 typedef T& reference;
372 typedef const T& const_reference;
374 typedef const T* const_pointer;
375 typedef int count_type;
376 typedef int size_type;
379 using handle<value_type>::count;
380 using handle<value_type>::unique;
381 using handle<value_type>::operator bool;
382 using handle<value_type>::get;
383 using handle<value_type>::operator*;
384 using handle<value_type>::operator->;
387 operator const handle<value_type>&()const
392 using handle<value_type>::obj;
394 rhandle<value_type> *prev_;
395 rhandle<value_type> *next_;
399 // value_type*& obj(handle<T>::obj); // Required to keep gcc 3.4.2 from barfing
404 // If this is the first reversible handle
407 obj->front_=obj->back_=this;
412 prev_=reinterpret_cast<rhandle<value_type>*>(obj->back_);
418 void del_from_rlist()
420 // value_type*& obj(handle<T>::obj); // Required to keep gcc 3.4.2 from barfing
424 // If this is the last reversible handle
425 if(obj->front_==obj->back_)
427 obj->front_=obj->back_=0;
433 obj->front_=(void*)next_;
438 obj->back_=(void*)prev_;
445 //! Default constructor - empty handle
448 //! Constructor that constructs from a pointer to new object
449 rhandle(pointer x):handle<T>(x)
451 // value_type*& obj(handle<T>::obj); // Required to keep gcc 3.4.2 from barfing
452 if(obj)add_to_rlist();
455 rhandle(const handle<value_type> &x):handle<T>(x)
457 // value_type*& obj(handle<T>::obj); // Required to keep gcc 3.4.2 from barfing
458 if(obj)add_to_rlist();
461 //! Default copy constructor
462 rhandle(const rhandle<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 //! Handle is released on deletion
469 ~rhandle() { detach(); }
471 //! Template Assignment operator
472 /*! \note This class may not be necessary, and may be removed
473 ** at some point in the future.
476 template <class U> const handle<value_type> &
477 operator=(const handle<U> &x)
484 obj=static_cast<value_type*>(x.get());
494 //! Assignment operator
495 rhandle<value_type> &
496 operator=(const rhandle<value_type> &x)
498 // value_type*& obj(handle<T>::obj); // Required to keep gcc 3.4.2 from barfing
514 operator=(const handle<value_type> &x)
516 // value_type*& obj(handle<T>::obj); // Required to keep gcc 3.4.2 from barfing
532 operator=(value_type* x)
534 // value_type*& obj(handle<T>::obj); // Required to keep gcc 3.4.2 from barfing
549 //! Handle release procedure
550 /*! unref()'s the object and sets the internal object pointer to \c NULL */
554 // value_type*& obj(handle<T>::obj); // Required to keep gcc 3.4.2 from barfing
555 if(obj)del_from_rlist();
556 handle<value_type>::detach();
560 // This will be reintroduced with a new function
561 //void release() { detach(); }
563 void reset() { detach(); }
565 //! Creates a new instance of a T object and puts it in the handle.
566 /*! Uses the default constructor */
567 void spawn() { operator=(handle<value_type>(new T())); }
569 //! Returns number of reversible instances
573 // value_type*const& obj(handle<T>::obj); // Required to keep gcc 3.4.2 from barfing
574 return obj?obj->rcount():0;
577 //! Returns true if there is only one instance of the object
581 // value_type*& obj(handle<T>::obj); // Required to keep gcc 3.4.2 from barfing
582 assert(obj); return obj->front_==obj->back_;
586 int replace(const handle<value_type> &x)
588 // value_type*& obj(handle<T>::obj); // Required to keep gcc 3.4.2 from barfing
590 assert(x.get()!=obj);
595 rhandle<value_type> *iter;
596 rhandle<value_type> *next;
598 iter=reinterpret_cast<rhandle<value_type>*>(obj->front_);
609 for(;iter;iter=next,next=iter?iter->next_:0,i++)
611 assert(iter->get()==obj_);
615 assert(obj==x.get());
620 //! Swaps the values of two handles without reference counts
621 /*! \warning not yet implemented. \writeme */
623 swap(handle<value_type> &x);
633 }; // END of template class rhandle
636 // ========================================================================
637 /*! \class loose_handle _handle.h ETL/handle
638 ** \brief Loose Object Handle
639 ** \see shared_object, handle
647 typedef T value_type;
648 typedef T& reference;
649 typedef const T& const_reference;
651 typedef const T* const_pointer;
652 typedef int count_type;
653 typedef int size_type;
659 value_type *obj; //!< Pointer to object
663 //! Default constructor - empty handle
664 loose_handle():obj(0) {}
666 //! Constructor that constructs from a pointer to new object
667 loose_handle(pointer x):obj(x) { }
669 //! Default copy constructor
670 loose_handle(const loose_handle<value_type> &x):obj(x.get()) { }
672 loose_handle(const handle<value_type> &x):obj(x.get()) { }
674 template <class U> const loose_handle<value_type> &
675 operator=(const handle<U> &x)
680 obj=static_cast<value_type*>(x.get());
684 template <class U> const loose_handle<value_type> &
685 operator=(const loose_handle<U> &x)
690 obj=static_cast<value_type*>(x.get());
694 //! Assignment operator
695 const loose_handle<value_type> &
696 operator=(const loose_handle<value_type> &x)
705 //! Swaps the values of two handles without reference counts
706 loose_handle<value_type> &
707 swap(loose_handle<value_type> &x)
715 //! Handle release procedure
716 void detach() { obj=0; }
718 // This will be reintroduced with a new function
719 //void release() { detach(); }
721 void reset() { detach(); }
723 bool empty()const { return obj==0; }
725 handle<value_type> clone()const { assert(obj); return obj->clone(); }
727 //! Returns a constant handle to our object
728 loose_handle<const value_type> constant()const { return *this; }
730 //! Returns number of instances
733 { return obj?obj->count():0; }
737 { assert(obj); return *obj; }
741 { assert(obj); return obj; }
743 //! static_cast<> overload
745 //operator loose_handle<U>()const
746 //{ return loose_handle<U>(static_cast<U*>(obj)); }
748 //! static_cast<> overload (for consts)
749 operator loose_handle<const value_type>()const
750 { return loose_handle<const value_type>(static_cast<const_pointer>(obj)); }
752 operator handle<value_type>()const
753 { return handle<value_type>(obj); }
755 operator rhandle<value_type>()const
756 { return rhandle<value_type>(obj); }
758 //! Returns pointer to the object that is being wrapped
759 pointer get()const { return obj; }
761 //! More explicit bool cast
769 void ref() { if(obj)obj->ref(); }
771 bool unref() { if(obj && !obj->unref()){ obj=0; return false; } return true; }
772 }; // END of template class loose_handle
774 // cast loose_handle<> -> handle<>
775 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())); }
776 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())); }
777 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())); }
778 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())); }
780 // cast rhandle_handle<> -> handle<>
781 template <class T> template <class U> handle<T> handle<T>::cast_static (const rhandle<U>& x) { return handle<T>(static_cast <T*>(x.get())); }
782 template <class T> template <class U> handle<T> handle<T>::cast_dynamic (const rhandle<U>& x) { return handle<T>(dynamic_cast <T*>(x.get())); }
783 template <class T> template <class U> handle<T> handle<T>::cast_const (const rhandle<U>& x) { return handle<T>(const_cast <T*>(x.get())); }
784 template <class T> template <class U> handle<T> handle<T>::cast_reinterpret(const rhandle<U>& x) { return handle<T>(reinterpret_cast<T*>(x.get())); }
786 // cast U* -> handle<>
787 template <class T> template <class U> handle<T> handle<T>::cast_static (U* x) { return handle<T>(static_cast <T*>(x)); }
788 template <class T> template <class U> handle<T> handle<T>::cast_dynamic (U* x) { return handle<T>(dynamic_cast <T*>(x)); }
789 template <class T> template <class U> handle<T> handle<T>::cast_const (U* x) { return handle<T>(const_cast <T*>(x)); }
790 template <class T> template <class U> handle<T> handle<T>::cast_reinterpret(U* x) { return handle<T>(reinterpret_cast<T*>(x)); }
792 // operator== for handle<>, loose_handle<> and T*
793 template <class T,class U> bool operator==(const handle <T>& lhs,const handle <U>& rhs) { return (lhs.get()==rhs.get()); }
794 template <class T,class U> bool operator==(const loose_handle<T>& lhs,const loose_handle<U>& rhs) { return (lhs.get()==rhs.get()); }
795 template <class T,class U> bool operator==(const handle <T>& lhs,const loose_handle<U>& rhs) { return (lhs.get()==rhs.get()); }
796 template <class T,class U> bool operator==(const loose_handle<T>& lhs,const handle <U>& rhs) { return (lhs.get()==rhs.get()); }
797 template <class T> bool operator==(const handle<T>& lhs,const T* rhs) { return (lhs.get()==rhs); }
798 template <class T> bool operator==(const loose_handle<T>& lhs,const T* rhs) { return (lhs.get()==rhs); }
799 template <class T> bool operator==(const T* lhs,const handle<T>& rhs) { return (lhs ==rhs.get()); }
800 template <class T> bool operator==(const T* lhs,const loose_handle<T>& rhs) { return (lhs ==rhs.get()); }
802 // operator!= for handle<>, loose_handle<> and T*
803 template <class T,class U> bool operator!=(const handle <T>& lhs,const handle <U>& rhs) { return (lhs.get()!=rhs.get()); }
804 template <class T,class U> bool operator!=(const loose_handle<T>& lhs,const loose_handle<U>& rhs) { return (lhs.get()!=rhs.get()); }
805 template <class T,class U> bool operator!=(const handle <T>& lhs,const loose_handle<U>& rhs) { return (lhs.get()!=rhs.get()); }
806 template <class T,class U> bool operator!=(const loose_handle<T>& lhs,const handle <U>& rhs) { return (lhs.get()!=rhs.get()); }
807 template <class T> bool operator!=(const handle<T>& lhs,const T* rhs) { return (lhs.get()!=rhs); }
808 template <class T> bool operator!=(const loose_handle<T>& lhs,const T* rhs) { return (lhs.get()!=rhs); }
809 template <class T> bool operator!=(const T* lhs,const handle<T>& rhs) { return (lhs !=rhs.get()); }
810 template <class T> bool operator!=(const T* lhs,const loose_handle<T>& rhs) { return (lhs !=rhs.get()); }
812 // operator< for handle<>, loose_handle<> and T*
813 template <class T,class U> bool operator<(const handle<T>& lhs,const handle<U>& rhs) { return (lhs.get()<rhs.get()); }
814 template <class T,class U> bool operator<(const loose_handle<T>& lhs,const loose_handle<U>& rhs) { return (lhs.get()<rhs.get()); }
815 template <class T,class U> bool operator<(const handle<T>& lhs,const loose_handle<U>& rhs) { return (lhs.get()<rhs.get()); }
816 template <class T,class U> bool operator<(const loose_handle<T>& lhs,const handle<U>& rhs) { return (lhs.get()<rhs.get()); }
817 template <class T> bool operator<(const handle<T>& lhs,const T* rhs) { return (lhs.get()<rhs); }
818 template <class T> bool operator<(const loose_handle<T>& lhs,const T* rhs) { return (lhs.get()<rhs); }
819 template <class T> bool operator<(const T* lhs,const handle<T>& rhs) { return (lhs <rhs.get()); }
820 template <class T> bool operator<(const T* lhs,const loose_handle<T>& rhs) { return (lhs <rhs.get()); }
824 /* === E N D =============================================================== */