X-Git-Url: https://git.pterodactylus.net/?a=blobdiff_plain;f=ETL%2FETL%2F_handle.h;fp=ETL%2FETL%2F_handle.h;h=393894cc0baf1e40ccf936d5857fac31146dbe20;hb=a095981e18cc37a8ecc7cd237cc22b9c10329264;hp=0000000000000000000000000000000000000000;hpb=9459638ad6797b8139f1e9f0715c96076dbf0890;p=synfig.git diff --git a/ETL/ETL/_handle.h b/ETL/ETL/_handle.h new file mode 100644 index 0000000..393894c --- /dev/null +++ b/ETL/ETL/_handle.h @@ -0,0 +1,826 @@ +/* === 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