blocxx
|
00001 /******************************************************************************* 00002 * Copyright (C) 2005, Vintela, Inc. All rights reserved. 00003 * Copyright (C) 2006, Novell, Inc. All rights reserved. 00004 * 00005 * Redistribution and use in source and binary forms, with or without 00006 * modification, are permitted provided that the following conditions are met: 00007 * 00008 * * Redistributions of source code must retain the above copyright notice, 00009 * this list of conditions and the following disclaimer. 00010 * * Redistributions in binary form must reproduce the above copyright 00011 * notice, this list of conditions and the following disclaimer in the 00012 * documentation and/or other materials provided with the distribution. 00013 * * Neither the name of 00014 * Vintela, Inc., 00015 * nor Novell, Inc., 00016 * nor the names of its contributors or employees may be used to 00017 * endorse or promote products derived from this software without 00018 * specific prior written permission. 00019 * 00020 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 00021 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 00022 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 00023 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 00024 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 00025 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 00026 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 00027 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 00028 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 00029 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 00030 * POSSIBILITY OF SUCH DAMAGE. 00031 *******************************************************************************/ 00032 00033 00038 #ifndef BLOCXX_COWREFERENCE_HPP_INCLUDE_GUARD_ 00039 #define BLOCXX_COWREFERENCE_HPP_INCLUDE_GUARD_ 00040 #include "blocxx/BLOCXX_config.h" 00041 #include "blocxx/COWReferenceBase.hpp" 00042 #include "blocxx/ReferenceHelpers.hpp" 00043 #include "blocxx/SafeBool.hpp" 00044 00045 namespace BLOCXX_NAMESPACE 00046 { 00047 00053 template<class T> 00054 class COWReference : private COWReferenceBase 00055 { 00056 public: 00057 typedef T element_type; 00058 00063 COWReference(); 00064 00069 explicit COWReference(T* ptr); 00070 00077 COWReference(const COWReference<T>& arg); 00078 00086 template <class U> 00087 COWReference(const COWReference<U>& arg); 00088 00094 ~COWReference(); 00095 00104 COWReference<T>& operator= (const COWReference<T>& arg); 00105 00115 COWReference<T>& operator= (T* newObj); 00116 00117 void swap(COWReference<T>& arg); 00118 00122 T* operator->(); 00123 00127 const T* operator->() const; 00128 00132 T& operator*(); 00133 00137 const T& operator*() const; 00138 00142 const T* getPtr() const; 00143 bool isNull() const BLOCXX_DEPRECATED; // in 3.1.0 00144 00145 BLOCXX_SAFE_BOOL_IMPL(COWReference, T* volatile, COWReference::m_pObj, m_pObj) 00146 00147 template <class U> 00148 COWReference<U> cast_to() const; 00149 00150 template <class U> 00151 void useRefCountOf(const COWReference<U>&); 00152 00153 #if !defined(__GNUC__) || __GNUC__ > 2 // causes gcc 2.95 to ICE 00154 /* This is so the templated constructor will work */ 00155 template <class U> friend class COWReference; 00156 private: 00157 #endif 00158 T* volatile m_pObj; 00159 void decRef(); 00160 void getWriteLock(); 00161 }; 00163 template<class T> 00164 inline COWReference<T>::COWReference() 00165 : COWReferenceBase(), m_pObj(0) 00166 { 00167 } 00169 template<class T> 00170 inline COWReference<T>::COWReference(T* ptr) 00171 : COWReferenceBase(), m_pObj(ptr) 00172 { 00173 } 00175 template<class T> 00176 inline COWReference<T>::COWReference(const COWReference<T>& arg) 00177 : COWReferenceBase(arg), m_pObj(arg.m_pObj) 00178 { 00179 } 00181 template<class T> 00182 template<class U> 00183 inline COWReference<T>::COWReference(const COWReference<U>& arg) 00184 : COWReferenceBase(arg), m_pObj(arg.m_pObj) 00185 { 00186 } 00188 template<class T> 00189 inline COWReference<T>::~COWReference() 00190 { 00191 try 00192 { 00193 decRef(); 00194 } 00195 catch (...) 00196 { 00197 // don't let exceptions escape 00198 } 00199 } 00201 template<class T> 00202 inline void COWReference<T>::decRef() 00203 { 00204 typedef char type_must_be_complete[sizeof(T)]; 00205 if (COWReferenceBase::decRef()) 00206 { 00207 delete m_pObj; 00208 m_pObj = 0; 00209 } 00210 } 00211 00213 template<class T> 00214 inline void COWReference<T>::getWriteLock() 00215 { 00216 if (COWReferenceBase::refCountGreaterThanOne()) 00217 { 00218 // this needs to happen first to avoid a race condition between 00219 // another thread deleting the object and this one making a copy. 00220 T* tmp = COWReferenceClone(m_pObj); 00221 // this will decrement the count and then make a new one if we're making a copy. 00222 if (COWReferenceBase::getWriteLock()) 00223 { 00224 delete tmp; 00225 } 00226 else 00227 { 00228 m_pObj = tmp; 00229 } 00230 } 00231 } 00233 template<class T> 00234 inline COWReference<T>& COWReference<T>::operator= (const COWReference<T>& arg) 00235 { 00236 COWReference<T>(arg).swap(*this); 00237 return *this; 00238 } 00240 template<class T> 00241 inline COWReference<T>& COWReference<T>::operator= (T* newObj) 00242 { 00243 COWReference<T>(newObj).swap(*this); 00244 return *this; 00245 } 00247 template <class T> 00248 inline void COWReference<T>::swap(COWReference<T>& arg) 00249 { 00250 COWReferenceBase::swap(arg); 00251 COWRefSwap(m_pObj, arg.m_pObj); 00252 } 00254 template<class T> 00255 inline T* COWReference<T>::operator->() 00256 { 00257 #ifdef BLOCXX_CHECK_NULL_REFERENCES 00258 ReferenceHelpers::checkNull(this); 00259 ReferenceHelpers::checkNull(m_pObj); 00260 #endif 00261 getWriteLock(); 00262 00263 return m_pObj; 00264 } 00266 template<class T> 00267 inline T& COWReference<T>::operator*() 00268 { 00269 #ifdef BLOCXX_CHECK_NULL_REFERENCES 00270 ReferenceHelpers::checkNull(this); 00271 ReferenceHelpers::checkNull(m_pObj); 00272 #endif 00273 getWriteLock(); 00274 00275 return *(m_pObj); 00276 } 00278 template<class T> 00279 inline const T* COWReference<T>::operator->() const 00280 { 00281 #ifdef BLOCXX_CHECK_NULL_REFERENCES 00282 ReferenceHelpers::checkNull(this); 00283 ReferenceHelpers::checkNull(m_pObj); 00284 #endif 00285 00286 return m_pObj; 00287 } 00289 template<class T> 00290 inline const T& COWReference<T>::operator*() const 00291 { 00292 #ifdef BLOCXX_CHECK_NULL_REFERENCES 00293 ReferenceHelpers::checkNull(this); 00294 ReferenceHelpers::checkNull(m_pObj); 00295 #endif 00296 00297 return *(m_pObj); 00298 } 00300 template<class T> 00301 inline const T* COWReference<T>::getPtr() const 00302 { 00303 return m_pObj; 00304 } 00306 template<class T> 00307 inline bool COWReference<T>::isNull() const 00308 { 00309 return (m_pObj == 0); 00310 } 00312 template <class T> 00313 template <class U> 00314 inline COWReference<U> 00315 COWReference<T>::cast_to() const 00316 { 00317 COWReference<U> rval; 00318 rval.m_pObj = dynamic_cast<U*>(m_pObj); 00319 if (rval.m_pObj) 00320 { 00321 rval.useRefCountOf(*this); 00322 } 00323 return rval; 00324 } 00326 template <class T> 00327 template <class U> 00328 inline void 00329 COWReference<T>::useRefCountOf(const COWReference<U>& arg) 00330 { 00331 COWReferenceBase::useRefCountOf(arg); 00332 } 00334 // Comparisons 00335 template <class T, class U> 00336 inline bool operator==(const COWReference<T>& a, const COWReference<U>& b) 00337 { 00338 return a.getPtr() == b.getPtr(); 00339 } 00341 template <class T, class U> 00342 inline bool operator!=(const COWReference<T>& a, const COWReference<U>& b) 00343 { 00344 return a.getPtr() != b.getPtr(); 00345 } 00347 template <class T, class U> 00348 inline bool operator<(const COWReference<T>& a, const COWReference<U>& b) 00349 { 00350 return a.getPtr() < b.getPtr(); 00351 } 00352 00354 template <class T> 00355 inline T* COWReferenceClone(T* obj) 00356 { 00357 // default implementation. If a certain class doesn't have clone() 00358 // (like std::vector), then they can overload this function 00359 return obj->clone(); 00360 } 00361 00362 } // end namespace BLOCXX_NAMESPACE 00363 00364 #endif // BLOCXX_COWREFERENCE_HPP_