00001 #ifndef _BOOST_CMT_RETAINABLE_HPP_
00002 #define _BOOST_CMT_RETAINABLE_HPP_
00003 #include <boost/assert.hpp>
00004 #include <boost/intrusive_ptr.hpp>
00005 #include <boost/atomic.hpp>
00006 #include <boost/memory_order.hpp>
00007
00008 namespace boost { namespace cmt {
00009
00014 template<typename T>
00015 class stack_retainable : public T {
00016 public:
00017 template<typename A, typename B, typename C>
00018 stack_retainable( const A& a, const B& b, const C& c)
00019 :T(a,b,c){}
00020 template<typename A, typename B, typename C, typename D>
00021 stack_retainable( const A& a, const B& b, const C& c, const D& d)
00022 :T(a,b,c,d){}
00023
00024 stack_retainable(){}
00025 ~stack_retainable() {}
00026 };
00027
00036 class retainable {
00037 public:
00038 template<typename T>
00039 friend class stack_retainable;
00040
00041 retainable():m_ref_count(1) {}
00042
00043 inline void retain() {
00044 m_ref_count.fetch_add(1, boost::memory_order_relaxed);
00045 }
00046
00047 inline void release() {
00048 if( 1 == m_ref_count.fetch_sub(1, boost::memory_order_release) ) {
00049 boost::atomic_thread_fence(boost::memory_order_acquire);
00050 delete this;
00051 }
00052 }
00053
00054 protected:
00055 virtual ~retainable() {}
00056
00057 private:
00058 retainable(const retainable&):m_ref_count(1) {}
00059
00060 retainable& operator=(const retainable& ) {
00061 return *this;
00062 }
00063
00064 boost::atomic<int32_t> m_ref_count;
00065 };
00066
00067
00068
00069
00070 template<typename T>
00071 class retainable_ptr
00072 {
00073 public:
00074 explicit retainable_ptr(T* t = 0, bool inc = false)
00075 :cnt(t) {
00076 if( inc && cnt ) cnt->retain();
00077 }
00078
00079 retainable_ptr( const retainable_ptr<T>& copy )
00080 :cnt(copy.cnt) {
00081 if( cnt ) cnt->retain();
00082 }
00083
00084 #ifdef BOOST_HAS_RVALUE_REFS
00085 retainable_ptr( retainable_ptr<T>&& mv )
00086 :cnt(mv.cnt) {
00087 mv.cnt = NULL;
00088 }
00089
00090 inline retainable_ptr<T>& operator=(retainable_ptr<T>&& mv ) {
00091 cnt = mv.cnt;
00092 mv.cnt = NULL;
00093 return *this;
00094 }
00095 #endif
00096 ~retainable_ptr() {
00097 if( cnt ) cnt->release();
00098 }
00099
00100 template<typename U>
00101 operator retainable_ptr<U>()const {
00102 retainable_ptr<U> u;
00103 u.cnt = dynamic_cast<U*>(cnt);
00104 if( u.cnt )
00105 u.cnt->retain();
00106 return u;
00107 }
00108 retainable_ptr& reset() {
00109 if( !cnt )
00110 return *this;
00111 cnt->release();
00112 cnt = 0;
00113 return *this;
00114 }
00115
00116 inline bool operator!()const { return cnt == 0; }
00117 inline operator bool()const { return cnt != 0; }
00118
00119 inline retainable_ptr<T>& operator=(const retainable_ptr<T>& copy ) {
00120 if( cnt == copy.cnt )
00121 return *this;
00122 if( cnt )
00123 cnt->release();
00124 cnt = copy.cnt;
00125 if( cnt )
00126 cnt->retain();
00127 return *this;
00128 }
00129 inline T& operator* () const { return *cnt; }
00130 inline T * operator-> () const { return cnt; }
00131
00132 inline bool operator==( const retainable_ptr& p )const {
00133 return get() == p.get();
00134 }
00135 inline bool operator<( const retainable_ptr& p )const {
00136 return get() < p.get();
00137 }
00138 inline T * get() const { return cnt; }
00139
00140 private:
00141 template<typename U> friend class retainable_ptr;
00142 T* cnt;
00143 };
00144 template<typename T>
00145 T* get_pointer( const retainable_ptr<T>& p ) { return p.get(); }
00146
00147 template<class T, class U>
00148 inline bool operator==(retainable_ptr<T> const & a, retainable_ptr<U> const & b) {
00149 return a.get() == b.get();
00150 }
00151
00152 template<class T, class U>
00153 inline bool operator!=(retainable_ptr<T> const & a, retainable_ptr<U> const & b) {
00154 return a.get() != b.get();
00155 }
00156
00157 template<class T, class U>
00158 inline retainable_ptr<T> dynamic_retainable_cast( const retainable_ptr<U>& u ) {
00159 T* t = dynamic_cast<T*>(u.get());
00160 if( t ) t->retain();
00161 return retainable_ptr<T>( t );
00162 }
00163 template<class T, class U>
00164 inline retainable_ptr<T> static_retainable_cast( const retainable_ptr<U>& u ) {
00165 T* t = static_cast<T*>(u.get());
00166 if( t )
00167 t->retain();
00168 return retainable_ptr<T>( t );
00169 }
00170
00171 } }
00172
00173 #endif