00001 // -*- c++ -*- 00002 #ifndef _cairo_REFPTR_H 00003 #define _cairo_REFPTR_H 00004 00005 /* $Id: refptr.h,v 1.3 2006/03/06 17:55:51 jjongsma Exp $ */ 00006 00007 /* Copyright 2005 The cairomm Development Team 00008 * 00009 * This library is free software; you can redistribute it and/or 00010 * modify it under the terms of the GNU Library General Public 00011 * License as published by the Free Software Foundation; either 00012 * version 2 of the License, or (at your option) any later version. 00013 * 00014 * This library is distributed in the hope that it will be useful, 00015 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00017 * Library General Public License for more details. 00018 * 00019 * You should have received a copy of the GNU Library General Public 00020 * License along with this library; if not, write to the Free Software 00021 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 00022 * 02110-1301, USA. 00023 */ 00024 00025 00026 namespace Cairo 00027 { 00028 00046 template <class T_CppObject> 00047 class RefPtr 00048 { 00049 public: 00054 inline RefPtr(); 00055 00057 inline ~RefPtr(); 00058 00060 explicit inline RefPtr(T_CppObject* pCppObject); 00061 00066 inline RefPtr(const RefPtr<T_CppObject>& src); 00067 00072 template <class T_CastFrom> 00073 inline RefPtr(const RefPtr<T_CastFrom>& src); 00074 00080 inline void swap(RefPtr<T_CppObject>& other); 00081 00083 inline RefPtr<T_CppObject>& operator=(const RefPtr<T_CppObject>& src); 00084 00089 template <class T_CastFrom> 00090 inline RefPtr<T_CppObject>& operator=(const RefPtr<T_CastFrom>& src); 00091 00093 inline bool operator==(const RefPtr<T_CppObject>& src) const; 00094 00096 inline bool operator!=(const RefPtr<T_CppObject>& src) const; 00097 00103 inline T_CppObject* operator->() const; 00104 00113 inline operator bool() const; 00114 00116 inline void clear(); 00117 00118 00126 template <class T_CastFrom> 00127 static inline RefPtr<T_CppObject> cast_dynamic(const RefPtr<T_CastFrom>& src); 00128 00136 template <class T_CastFrom> 00137 static inline RefPtr<T_CppObject> cast_static(const RefPtr<T_CastFrom>& src); 00138 00146 template <class T_CastFrom> 00147 static inline RefPtr<T_CppObject> cast_const(const RefPtr<T_CastFrom>& src); 00148 00149 private: 00150 T_CppObject* pCppObject_; 00151 }; 00152 00153 00154 #ifndef DOXYGEN_SHOULD_SKIP_THIS 00155 00156 // RefPtr<>::operator->() comes first here since it's used by other methods. 00157 // If it would come after them it wouldn't be inlined. 00158 00159 template <class T_CppObject> inline 00160 T_CppObject* RefPtr<T_CppObject>::operator->() const 00161 { 00162 return pCppObject_; 00163 } 00164 00165 template <class T_CppObject> inline 00166 RefPtr<T_CppObject>::RefPtr() 00167 : 00168 pCppObject_ (0) 00169 {} 00170 00171 template <class T_CppObject> inline 00172 RefPtr<T_CppObject>::~RefPtr() 00173 { 00174 if(pCppObject_) 00175 pCppObject_->unreference(); // This could cause pCppObject to be deleted. 00176 } 00177 00178 template <class T_CppObject> inline 00179 RefPtr<T_CppObject>::RefPtr(T_CppObject* pCppObject) 00180 : 00181 pCppObject_ (pCppObject) 00182 {} 00183 00184 template <class T_CppObject> inline 00185 RefPtr<T_CppObject>::RefPtr(const RefPtr<T_CppObject>& src) 00186 : 00187 pCppObject_ (src.pCppObject_) 00188 { 00189 if(pCppObject_) 00190 pCppObject_->reference(); 00191 } 00192 00193 // The templated ctor allows copy construction from any object that's 00194 // castable. Thus, it does downcasts: 00195 // base_ref = derived_ref 00196 template <class T_CppObject> 00197 template <class T_CastFrom> 00198 inline 00199 RefPtr<T_CppObject>::RefPtr(const RefPtr<T_CastFrom>& src) 00200 : 00201 // A different RefPtr<> will not allow us access to pCppObject_. We need 00202 // to add a get_underlying() for this, but that would encourage incorrect 00203 // use, so we use the less well-known operator->() accessor: 00204 pCppObject_ (src.operator->()) 00205 { 00206 if(pCppObject_) 00207 pCppObject_->reference(); 00208 } 00209 00210 template <class T_CppObject> inline 00211 void RefPtr<T_CppObject>::swap(RefPtr<T_CppObject>& other) 00212 { 00213 T_CppObject *const temp = pCppObject_; 00214 pCppObject_ = other.pCppObject_; 00215 other.pCppObject_ = temp; 00216 } 00217 00218 template <class T_CppObject> inline 00219 RefPtr<T_CppObject>& RefPtr<T_CppObject>::operator=(const RefPtr<T_CppObject>& src) 00220 { 00221 // In case you haven't seen the swap() technique to implement copy 00222 // assignment before, here's what it does: 00223 // 00224 // 1) Create a temporary RefPtr<> instance via the copy ctor, thereby 00225 // increasing the reference count of the source object. 00226 // 00227 // 2) Swap the internal object pointers of *this and the temporary 00228 // RefPtr<>. After this step, *this already contains the new pointer, 00229 // and the old pointer is now managed by temp. 00230 // 00231 // 3) The destructor of temp is executed, thereby unreferencing the 00232 // old object pointer. 00233 // 00234 // This technique is described in Herb Sutter's "Exceptional C++", and 00235 // has a number of advantages over conventional approaches: 00236 // 00237 // - Code reuse by calling the copy ctor. 00238 // - Strong exception safety for free. 00239 // - Self assignment is handled implicitely. 00240 // - Simplicity. 00241 // - It just works and is hard to get wrong; i.e. you can use it without 00242 // even thinking about it to implement copy assignment whereever the 00243 // object data is managed indirectly via a pointer, which is very common. 00244 00245 RefPtr<T_CppObject> temp (src); 00246 this->swap(temp); 00247 return *this; 00248 } 00249 00250 template <class T_CppObject> 00251 template <class T_CastFrom> 00252 inline 00253 RefPtr<T_CppObject>& RefPtr<T_CppObject>::operator=(const RefPtr<T_CastFrom>& src) 00254 { 00255 RefPtr<T_CppObject> temp (src); 00256 this->swap(temp); 00257 return *this; 00258 } 00259 00260 template <class T_CppObject> inline 00261 bool RefPtr<T_CppObject>::operator==(const RefPtr<T_CppObject>& src) const 00262 { 00263 return (pCppObject_ == src.pCppObject_); 00264 } 00265 00266 template <class T_CppObject> inline 00267 bool RefPtr<T_CppObject>::operator!=(const RefPtr<T_CppObject>& src) const 00268 { 00269 return (pCppObject_ != src.pCppObject_); 00270 } 00271 00272 template <class T_CppObject> inline 00273 RefPtr<T_CppObject>::operator bool() const 00274 { 00275 return (pCppObject_ != 0); 00276 } 00277 00278 template <class T_CppObject> inline 00279 void RefPtr<T_CppObject>::clear() 00280 { 00281 RefPtr<T_CppObject> temp; // swap with an empty RefPtr<> to clear *this 00282 this->swap(temp); 00283 } 00284 00285 template <class T_CppObject> 00286 template <class T_CastFrom> 00287 inline 00288 RefPtr<T_CppObject> RefPtr<T_CppObject>::cast_dynamic(const RefPtr<T_CastFrom>& src) 00289 { 00290 T_CppObject *const pCppObject = dynamic_cast<T_CppObject*>(src.operator->()); 00291 00292 if(pCppObject) 00293 pCppObject->reference(); 00294 00295 return RefPtr<T_CppObject>(pCppObject); 00296 } 00297 00298 template <class T_CppObject> 00299 template <class T_CastFrom> 00300 inline 00301 RefPtr<T_CppObject> RefPtr<T_CppObject>::cast_static(const RefPtr<T_CastFrom>& src) 00302 { 00303 T_CppObject *const pCppObject = static_cast<T_CppObject*>(src.operator->()); 00304 00305 if(pCppObject) 00306 pCppObject->reference(); 00307 00308 return RefPtr<T_CppObject>(pCppObject); 00309 } 00310 00311 template <class T_CppObject> 00312 template <class T_CastFrom> 00313 inline 00314 RefPtr<T_CppObject> RefPtr<T_CppObject>::cast_const(const RefPtr<T_CastFrom>& src) 00315 { 00316 T_CppObject *const pCppObject = const_cast<T_CppObject*>(src.operator->()); 00317 00318 if(pCppObject) 00319 pCppObject->reference(); 00320 00321 return RefPtr<T_CppObject>(pCppObject); 00322 } 00323 00324 #endif /* DOXYGEN_SHOULD_SKIP_THIS */ 00325 00327 template <class T_CppObject> inline 00328 void swap(RefPtr<T_CppObject>& lhs, RefPtr<T_CppObject>& rhs) 00329 { 00330 lhs.swap(rhs); 00331 } 00332 00333 } // namespace Cairo 00334 00335 00336 #endif /* _cairo_REFPTR_H */ 00337 00338 // vim: ts=2 sw=2 et