00001 /* base.h: Reference-counted pointers 00002 * 00003 * Copyright 1999,2000,2001 BrightStation PLC 00004 * Copyright 2002 Ananova Ltd 00005 * Copyright 2002,2003,2004,2007 Olly Betts 00006 * 00007 * This program is free software; you can redistribute it and/or 00008 * modify it under the terms of the GNU General Public License as 00009 * published by the Free Software Foundation; either version 2 of the 00010 * License, or (at your option) any later version. 00011 * 00012 * This program is distributed in the hope that it will be useful, 00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00015 * GNU General Public License for more details. 00016 * 00017 * You should have received a copy of the GNU General Public License 00018 * along with this program; if not, write to the Free Software 00019 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 00020 * USA 00021 */ 00022 00023 #ifndef XAPIAN_INCLUDED_BASE_H 00024 #define XAPIAN_INCLUDED_BASE_H 00025 00026 #include <xapian/deprecated.h> 00027 00028 namespace Xapian { 00029 namespace Internal { 00030 00035 class RefCntBase { 00036 /* Note: We never delete a pointer to a subclass of RefCntBase using 00037 * a RefCntBase *, so we don't need a virtual destructor here. 00038 */ 00039 protected: 00047 RefCntBase(const RefCntBase &) : ref_count(0) { } 00048 00049 public: 00051 RefCntBase() : ref_count(0) { } 00052 00053 typedef unsigned int ref_count_t; 00054 00058 mutable ref_count_t ref_count; 00059 }; 00060 00065 template <class T> 00066 class RefCntPtr { 00067 private: 00068 T *dest; 00069 00070 public: 00071 T *operator->() const; 00072 T &operator*() const; 00073 T *get() const; 00082 RefCntPtr(T *dest_); 00083 RefCntPtr(); 00084 RefCntPtr(const RefCntPtr &other); 00085 void operator=(const RefCntPtr &other); 00086 void operator=(T *dest_); 00087 ~RefCntPtr(); 00088 00089 template <class U> 00090 RefCntPtr(const RefCntPtr<U> &other); 00091 }; 00092 00093 template <class T> 00094 inline RefCntPtr<T>::RefCntPtr(T *dest_) : dest(dest_) 00095 { 00096 if (dest) ++dest->ref_count; 00097 } 00098 00099 template <class T> 00100 inline RefCntPtr<T>::RefCntPtr() : dest(0) 00101 { 00102 } 00103 00104 template <class T> 00105 inline RefCntPtr<T>::RefCntPtr(const RefCntPtr &other) : dest(other.dest) 00106 { 00107 if (dest) ++dest->ref_count; 00108 } 00109 00110 template <class T> 00111 inline void RefCntPtr<T>::operator=(const RefCntPtr &other) { 00112 operator=(other.dest); 00113 } 00114 00115 template <class T> 00116 inline void RefCntPtr<T>::operator=(T *dest_) { 00117 // check if we're assigning a pointer to itself 00118 if (dest == dest_) return; 00119 00120 // copy the new dest in before we delete the old to avoid a small 00121 // window in which dest points to a deleted object 00122 // FIXME: if pointer assignment isn't atomic, we ought to use locking... 00123 T *old_dest = dest; 00124 dest = dest_; 00125 if (dest) ++dest->ref_count; 00126 if (old_dest && --old_dest->ref_count == 0) delete old_dest; 00127 } 00128 00129 template <class T> 00130 inline RefCntPtr<T>::~RefCntPtr() 00131 { 00132 if (dest && --dest->ref_count == 0) { 00133 // zero before we delete to avoid a small window in which dest points 00134 // to a deleted object 00135 // FIXME: if pointer assignment isn't atomic, we ought to use locking... 00136 T * condemned = dest; 00137 dest = 0; 00138 delete condemned; 00139 } 00140 } 00141 00142 template <class T> 00143 template <class U> 00144 inline 00145 RefCntPtr<T>::RefCntPtr(const RefCntPtr<U> &other) 00146 : dest(other.get()) 00147 { 00148 if (dest) ++dest->ref_count; 00149 } 00150 00151 template <class T> 00152 inline T *RefCntPtr<T>::operator->() const 00153 { 00154 return dest; 00155 } 00156 00157 template <class T> 00158 inline T &RefCntPtr<T>::operator*() const 00159 { 00160 return *dest; 00161 } 00162 00163 template <class T> 00164 inline T *RefCntPtr<T>::get() const 00165 { 00166 return dest; 00167 } 00168 00169 } 00170 } 00171 00172 #endif /* XAPIAN_INCLUDED_BASE_H */