/* === E T L =============================================================== */ /*! \file _handle.h ** $Id$ ** \brief Template Object Handle Implementation ** \internal ** ** \legal ** Copyright (c) 2002 Robert B. Quattlebaum Jr. ** Copyright (c) 2007, 2008 Chris Moore ** ** This package is free software; you can redistribute it and/or ** modify it under the terms of the GNU General Public License as ** published by the Free Software Foundation; either version 2 of ** the License, or (at your option) any later version. ** ** This package is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ** General Public License for more details. ** \endlegal ** ** \note ** This is an internal header file, included by other ETL headers. ** You should not attempt to use it directly. */ /* ========================================================================= */ /* === S T A R T =========================================================== */ #ifndef __ETL__HANDLE_H #define __ETL__HANDLE_H /* === H E A D E R S ======================================================= */ #include /* === M A C R O S ========================================================= */ /* === T Y P E D E F S ===================================================== */ #define ETL_SELF_DELETING_SHARED_OBJECT /* === C L A S S E S & S T R U C T S ======================================= */ #ifdef NDEBUG #define assert_cast static_cast #else #define assert_cast dynamic_cast #endif _ETL_BEGIN_NAMESPACE // Forward Declarations template class handle; template class loose_handle; template class rhandle; // ======================================================================== /*! \class shared_object _handle.h ETL/handle ** \brief Shared Object Base Class ** \see handle, loose_handle ** \writeme */ class shared_object { private: mutable int refcount; #ifdef ETL_LOCK_REFCOUNTS mutable etl::mutex mtx; #endif protected: shared_object():refcount(0) { } #ifdef ETL_SELF_DELETING_SHARED_OBJECT virtual ~shared_object() { } #else ~shared_object() { } #endif public: void ref()const { #ifdef ETL_LOCK_REFCOUNTS etl::mutex::lock lock(mtx); #endif assert(refcount>=0); refcount++; } //! Returns \c false if object needs to be deleted bool unref()const { bool ret = true; { #ifdef ETL_LOCK_REFCOUNTS etl::mutex::lock lock(mtx); #endif assert(refcount>0); refcount--; if(refcount==0) { ret = false; #ifdef ETL_SELF_DELETING_SHARED_OBJECT refcount=-666; #endif } } #ifdef ETL_SELF_DELETING_SHARED_OBJECT if (!ret) delete this; #endif return ret; } int count()const { return refcount; } }; // END of class shared_object // ======================================================================== /*! \class virtual_shared_object _handle.h ETL/handle ** \brief Virtual Shared Object Base Class ** \see handle, loose_handle ** \writeme */ class virtual_shared_object { protected: virtual_shared_object() { } public: virtual ~virtual_shared_object()=0; virtual void ref()const=0; virtual bool unref()const=0; virtual int count()const=0; virtual virtual_shared_object *clone()=0; }; // END of class virtual_shared_object // ======================================================================== /*! \class handle _handle.h ETL/handle ** \brief Object Handle ** \see shared_object, loose_handle ** \writeme */ template class handle { public: typedef T value_type; typedef T& reference; typedef const T& const_reference; typedef T* pointer; typedef const T* const_pointer; typedef int count_type; typedef int size_type; protected: #ifdef _DEBUG public: #endif value_type *obj; //!< Pointer to object public: //! Default constructor - empty handle handle():obj(NULL) {} //! Constructor that constructs from a pointer to new object handle(pointer x):obj(x) { if(obj) obj->ref(); } //! Default copy constructor handle(const handle &x):obj(x.get()) { if(obj) obj->ref(); } //! Handle is released on deletion ~handle() { detach(); } //! Template Assignment operator /*! \note This class may not be necessary, and may be removed ** at some point in the future. */ /* template handle & operator=(const handle &x) { if(x.get()==obj) return *this; detach(); obj=static_cast(x.get()); if(obj)obj->ref(); return *this; } */ //! Assignment operator handle & operator=(const handle &x) { if(x.get()==obj) return *this; detach(); obj=x.get(); if(obj)obj->ref(); return *this; } //! Swaps the values of two handles without reference counts handle & swap(handle &x) { pointer ptr=x.obj; x.obj=obj; obj=ptr; return *this; } //! Handle detach procedure /*! unref()'s the object and sets the internal object pointer to \c NULL */ void detach() { pointer xobj(obj); obj=0; #ifdef ETL_SELF_DELETING_SHARED_OBJECT if(xobj) xobj->unref(); #else if(xobj && !xobj->unref()) delete xobj; #endif } // This will be reintroduced with a new function //void release() { detach(); } void reset() { detach(); } bool empty()const { return obj==0; } //! Creates a new instance of a T object and puts it in the handle. /*! Uses the default constructor */ void spawn() { operator=(handle(new T())); } handle clone()const { assert(obj); return static_cast(obj->clone()); } //! Returns a constant handle to our object handle constant()const { assert(obj); return *this; } //! Returns number of instances count_type count()const { return obj?obj->count():0; } //! Returns true if there is only one instance of the object bool unique()const { assert(obj); return count()==1; } reference operator*()const { assert(obj); return *obj; } pointer operator->()const { assert(obj); return obj; } //! More explicit bool cast operator bool()const { return obj!=NULL; } operator handle()const { return handle(static_cast(obj)); } //! static_cast\<\> wrapper template static handle cast_static (const handle &x) { return handle(static_cast (x.get())); } //! dynamic_cast\<\> wrapper template static handle cast_dynamic (const handle &x) { return handle(dynamic_cast (x.get())); } //! const_cast\<\> wrapper template static handle cast_const (const handle &x) { return handle(const_cast (x.get())); } //! reinterpret_cast\<\> wrapper template static handle cast_reinterpret(const handle &x) { return handle(reinterpret_cast(x.get())); } template static handle cast_static (const loose_handle &x); template static handle cast_dynamic (const loose_handle &x); template static handle cast_const (const loose_handle &x); template static handle cast_reinterpret(const loose_handle &x); template static handle cast_static (const rhandle &x); template static handle cast_dynamic (const rhandle &x); template static handle cast_const (const rhandle &x); template static handle cast_reinterpret(const rhandle &x); template static handle cast_static (U* x); template static handle cast_dynamic (U* x); template static handle cast_const (U* x); template static handle cast_reinterpret(U* x); //! Returns pointer to the object that is being wrapped pointer get()const { return obj; } bool operator!()const { return !obj; } //! static_cast<> overload -- Useful for implicit casts template operator handle()const { return handle(static_cast(obj)); } }; // END of template class handle // ======================================================================== /*! \class rshared_object _handle.h ETL/handle ** \brief Replaceable Shared Object Base Class ** \see rhandle ** \writeme */ class rshared_object : public shared_object { private: mutable int rrefcount; public: void *front_; void *back_; protected: rshared_object():rrefcount(0),front_(0),back_(0) { } public: void rref()const { rrefcount++; } void runref()const { assert(rrefcount>0); rrefcount--; } int rcount()const { return rrefcount; } }; // END of class rshared_object // ======================================================================== /*! \class rhandle _handle.h ETL/handle ** \brief Replaceable Object Handle ** \see rshared_object, handle, loose_handle ** \writeme */ template class rhandle : public handle { friend class rshared_object; public: typedef T value_type; typedef T& reference; typedef const T& const_reference; typedef T* pointer; typedef const T* const_pointer; typedef int count_type; typedef int size_type; using handle::count; using handle::unique; using handle::operator bool; using handle::get; using handle::operator*; using handle::operator->; /* operator const handle&()const { return *this; } */ private: using handle::obj; rhandle *prev_; rhandle *next_; void add_to_rlist() { // value_type*& obj(handle::obj); // Required to keep gcc 3.4.2 from barfing assert(obj); obj->rref(); // If this is the first reversible handle if(!obj->front_) { obj->front_=obj->back_=this; prev_=next_=0; return; } prev_=reinterpret_cast*>(obj->back_); next_=0; prev_->next_=this; obj->back_=this; } void del_from_rlist() { // value_type*& obj(handle::obj); // Required to keep gcc 3.4.2 from barfing assert(obj); obj->runref(); // If this is the last reversible handle if(obj->front_==obj->back_) { obj->front_=obj->back_=0; prev_=next_=0; return; } if(!prev_) obj->front_=(void*)next_; else prev_->next_=next_; if(!next_) obj->back_=(void*)prev_; else next_->prev_=prev_; } public: //! Default constructor - empty handle rhandle() {} //! Constructor that constructs from a pointer to new object rhandle(pointer x):handle(x) { // value_type*& obj(handle::obj); // Required to keep gcc 3.4.2 from barfing if(obj)add_to_rlist(); } rhandle(const handle &x):handle(x) { // value_type*& obj(handle::obj); // Required to keep gcc 3.4.2 from barfing if(obj)add_to_rlist(); } //! Default copy constructor rhandle(const rhandle &x):handle(x) { // value_type*& obj(handle::obj); // Required to keep gcc 3.4.2 from barfing if(obj)add_to_rlist(); } //! Handle is released on deletion ~rhandle() { detach(); } //! Template Assignment operator /*! \note This class may not be necessary, and may be removed ** at some point in the future. */ /* template const handle & operator=(const handle &x) { if(x.get()==obj) return *this; detach(); obj=static_cast(x.get()); if(obj) { obj->ref(); add_to_rlist(); } return *this; } */ //! Assignment operator rhandle & operator=(const rhandle &x) { // value_type*& obj(handle::obj); // Required to keep gcc 3.4.2 from barfing if(x.get()==obj) return *this; detach(); obj=x.get(); if(obj) { obj->ref(); add_to_rlist(); } return *this; } rhandle& operator=(const handle &x) { // value_type*& obj(handle::obj); // Required to keep gcc 3.4.2 from barfing if(x.get()==obj) return *this; detach(); obj=x.get(); if(obj) { obj->ref(); add_to_rlist(); } return *this; } rhandle& operator=(value_type* x) { // value_type*& obj(handle::obj); // Required to keep gcc 3.4.2 from barfing if(x==obj) return *this; detach(); obj=x; if(obj) { obj->ref(); add_to_rlist(); } return *this; } //! Handle release procedure /*! unref()'s the object and sets the internal object pointer to \c NULL */ void detach() { // value_type*& obj(handle::obj); // Required to keep gcc 3.4.2 from barfing if(obj)del_from_rlist(); handle::detach(); obj=0; } // This will be reintroduced with a new function //void release() { detach(); } void reset() { detach(); } //! Creates a new instance of a T object and puts it in the handle. /*! Uses the default constructor */ void spawn() { operator=(handle(new T())); } //! Returns number of reversible instances count_type rcount()const { // value_type*const& obj(handle::obj); // Required to keep gcc 3.4.2 from barfing return obj?obj->rcount():0; } //! Returns true if there is only one instance of the object bool runique()const { // value_type*& obj(handle::obj); // Required to keep gcc 3.4.2 from barfing assert(obj); return obj->front_==obj->back_; } //! \writeme int replace(const handle &x) { // value_type*& obj(handle::obj); // Required to keep gcc 3.4.2 from barfing assert(obj); assert(x.get()!=obj); if(x.get()==obj) return 0; rhandle *iter; rhandle *next; iter=reinterpret_cast*>(obj->front_); assert(iter); next=iter->next_; int i=0; #ifndef NDEBUG pointer obj_=obj; #endif for(;iter;iter=next,next=iter?iter->next_:0,i++) { assert(iter->get()==obj_); (*iter)=x; } assert(obj==x.get()); return i; } //! Swaps the values of two handles without reference counts /*! \warning not yet implemented. \writeme */ handle & swap(handle &x); /* { assert(0); pointer ptr=x.obj; x.obj=obj; obj=ptr; return *this; } */ }; // END of template class rhandle // ======================================================================== /*! \class loose_handle _handle.h ETL/handle ** \brief Loose Object Handle ** \see shared_object, handle ** \writeme */ template class loose_handle { public: typedef T value_type; typedef T& reference; typedef const T& const_reference; typedef T* pointer; typedef const T* const_pointer; typedef int count_type; typedef int size_type; protected: #ifdef _DEBUG public: #endif value_type *obj; //!< Pointer to object public: //! Default constructor - empty handle loose_handle():obj(0) {} //! Constructor that constructs from a pointer to new object loose_handle(pointer x):obj(x) { } //! Default copy constructor loose_handle(const loose_handle &x):obj(x.get()) { } loose_handle(const handle &x):obj(x.get()) { } template const loose_handle & operator=(const handle &x) { if(x.get()==obj) return *this; obj=static_cast(x.get()); return *this; } template const loose_handle & operator=(const loose_handle &x) { if(x.get()==obj) return *this; obj=static_cast(x.get()); return *this; } //! Assignment operator const loose_handle & operator=(const loose_handle &x) { if(x.get()==obj) return *this; obj=x.get(); return *this; } //! Swaps the values of two handles without reference counts loose_handle & swap(loose_handle &x) { pointer ptr=x.obj; x.obj=obj; obj=ptr; return *this; } //! Handle release procedure void detach() { obj=0; } // This will be reintroduced with a new function //void release() { detach(); } void reset() { detach(); } bool empty()const { return obj==0; } handle clone()const { assert(obj); return obj->clone(); } //! Returns a constant handle to our object loose_handle constant()const { return *this; } //! Returns number of instances count_type count()const { return obj?obj->count():0; } reference operator*()const { assert(obj); return *obj; } pointer operator->()const { assert(obj); return obj; } //! static_cast<> overload //template //operator loose_handle()const //{ return loose_handle(static_cast(obj)); } //! static_cast<> overload (for consts) operator loose_handle()const { return loose_handle(static_cast(obj)); } operator handle()const { return handle(obj); } operator rhandle()const { return rhandle(obj); } //! Returns pointer to the object that is being wrapped pointer get()const { return obj; } //! More explicit bool cast operator bool()const { return obj!=0; } bool operator!()const { return !obj; } void ref() { if(obj)obj->ref(); } bool unref() { if(obj && !obj->unref()){ obj=0; return false; } return true; } }; // END of template class loose_handle // cast loose_handle<> -> handle<> template template handle handle::cast_static (const loose_handle& x) { return handle(static_cast (x.get())); } template template handle handle::cast_dynamic (const loose_handle& x) { return handle(dynamic_cast (x.get())); } template template handle handle::cast_const (const loose_handle& x) { return handle(const_cast (x.get())); } template template handle handle::cast_reinterpret(const loose_handle& x) { return handle(reinterpret_cast(x.get())); } // cast rhandle_handle<> -> handle<> template template handle handle::cast_static (const rhandle& x) { return handle(static_cast (x.get())); } template template handle handle::cast_dynamic (const rhandle& x) { return handle(dynamic_cast (x.get())); } template template handle handle::cast_const (const rhandle& x) { return handle(const_cast (x.get())); } template template handle handle::cast_reinterpret(const rhandle& x) { return handle(reinterpret_cast(x.get())); } // cast U* -> handle<> template template handle handle::cast_static (U* x) { return handle(static_cast (x)); } template template handle handle::cast_dynamic (U* x) { return handle(dynamic_cast (x)); } template template handle handle::cast_const (U* x) { return handle(const_cast (x)); } template template handle handle::cast_reinterpret(U* x) { return handle(reinterpret_cast(x)); } // operator== for handle<>, loose_handle<> and T* template bool operator==(const handle & lhs,const handle & rhs) { return (lhs.get()==rhs.get()); } template bool operator==(const loose_handle& lhs,const loose_handle& rhs) { return (lhs.get()==rhs.get()); } template bool operator==(const handle & lhs,const loose_handle& rhs) { return (lhs.get()==rhs.get()); } template bool operator==(const loose_handle& lhs,const handle & rhs) { return (lhs.get()==rhs.get()); } template bool operator==(const handle& lhs,const T* rhs) { return (lhs.get()==rhs); } template bool operator==(const loose_handle& lhs,const T* rhs) { return (lhs.get()==rhs); } template bool operator==(const T* lhs,const handle& rhs) { return (lhs ==rhs.get()); } template bool operator==(const T* lhs,const loose_handle& rhs) { return (lhs ==rhs.get()); } // operator!= for handle<>, loose_handle<> and T* template bool operator!=(const handle & lhs,const handle & rhs) { return (lhs.get()!=rhs.get()); } template bool operator!=(const loose_handle& lhs,const loose_handle& rhs) { return (lhs.get()!=rhs.get()); } template bool operator!=(const handle & lhs,const loose_handle& rhs) { return (lhs.get()!=rhs.get()); } template bool operator!=(const loose_handle& lhs,const handle & rhs) { return (lhs.get()!=rhs.get()); } template bool operator!=(const handle& lhs,const T* rhs) { return (lhs.get()!=rhs); } template bool operator!=(const loose_handle& lhs,const T* rhs) { return (lhs.get()!=rhs); } template bool operator!=(const T* lhs,const handle& rhs) { return (lhs !=rhs.get()); } template bool operator!=(const T* lhs,const loose_handle& rhs) { return (lhs !=rhs.get()); } // operator< for handle<>, loose_handle<> and T* template bool operator<(const handle& lhs,const handle& rhs) { return (lhs.get() bool operator<(const loose_handle& lhs,const loose_handle& rhs) { return (lhs.get() bool operator<(const handle& lhs,const loose_handle& rhs) { return (lhs.get() bool operator<(const loose_handle& lhs,const handle& rhs) { return (lhs.get() bool operator<(const handle& lhs,const T* rhs) { return (lhs.get() bool operator<(const loose_handle& lhs,const T* rhs) { return (lhs.get() bool operator<(const T* lhs,const handle& rhs) { return (lhs bool operator<(const T* lhs,const loose_handle& rhs) { return (lhs