COWReference.hpp

Go to the documentation of this file.
00001 /*******************************************************************************
00002  * Copyright (C) 2004 Vintela, Inc. All rights reserved.
00003  * Copyright (C) 2005 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  *
00011  *  - Redistributions in binary form must reproduce the above copyright notice,
00012  *    this list of conditions and the following disclaimer in the documentation
00013  *    and/or other materials provided with the distribution.
00014  *
00015  *  - Neither the name of Vintela, Inc., Novell, Inc., nor the names of its
00016  *    contributors may be used to endorse or promote products derived from this
00017  *    software without specific prior written permission.
00018  *
00019  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
00020  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00021  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00022  * ARE DISCLAIMED. IN NO EVENT SHALL Vintela, Inc., Novell, Inc., OR THE 
00023  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
00024  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
00025  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 
00026  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
00027  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
00028  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
00029  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00030  *******************************************************************************/
00031 
00032 
00037 #ifndef BLOCXX_COWREFERENCE_HPP_INCLUDE_GUARD_
00038 #define BLOCXX_COWREFERENCE_HPP_INCLUDE_GUARD_
00039 #include "blocxx/BLOCXX_config.h"
00040 #include "blocxx/COWReferenceBase.hpp"
00041 
00042 namespace BLOCXX_NAMESPACE
00043 {
00044 
00050 template<class T>
00051 class COWReference : private COWReferenceBase
00052 {
00053 public:
00054    typedef T element_type;
00055 
00060    COWReference();
00061 
00066    explicit COWReference(T* ptr);
00067 
00074    COWReference(const COWReference<T>& arg);
00075 
00083    template <class U>
00084    COWReference(const COWReference<U>& arg);
00085 
00091    ~COWReference();
00092 
00101    COWReference<T>& operator= (const COWReference<T>& arg);
00102 
00112    COWReference<T>& operator= (T* newObj);
00113 
00114    void swap(COWReference<T>& arg);
00115 
00119    T* operator->();
00120    
00124    const T* operator->() const;
00125 
00129    T& operator*();
00130 
00134    const T& operator*() const;
00135 
00139    const T* getPtr() const;
00140 
00141    typedef T* volatile COWReference::*safe_bool;
00142    operator safe_bool () const
00143    {  
00144       return m_pObj ? &COWReference::m_pObj : 0; 
00145    }
00146 
00152    bool operator!() const
00153    {  
00154       return !m_pObj; 
00155    }
00156 
00157    template <class U>
00158       COWReference<U> cast_to() const;
00159       
00160    template <class U>
00161       void useRefCountOf(const COWReference<U>&); 
00162 
00163 #if !defined(__GNUC__) || __GNUC__ > 2 // causes gcc 2.95 to ICE
00164    /* This is so the templated constructor will work */
00165    template <class U> friend class COWReference;
00166 private:
00167 #endif
00168    T* volatile m_pObj;
00169    void decRef();
00170    void getWriteLock();
00171 };
00172 
00174 template<class T>
00175 inline COWReference<T>::COWReference()
00176 : COWReferenceBase(), m_pObj(0)
00177 {
00178 }
00180 template<class T>
00181 inline COWReference<T>::COWReference(T* ptr)
00182 : COWReferenceBase(), m_pObj(ptr)
00183 {
00184 }
00186 template<class T>
00187 inline COWReference<T>::COWReference(const COWReference<T>& arg)
00188 : COWReferenceBase(arg), m_pObj(arg.m_pObj)
00189 {
00190 }
00192 template<class T>
00193 template<class U>
00194 inline COWReference<T>::COWReference(const COWReference<U>& arg)
00195 : COWReferenceBase(arg), m_pObj(arg.m_pObj)
00196 {
00197 }
00199 template<class T>
00200 inline COWReference<T>::~COWReference()
00201 {
00202    try
00203    {
00204       decRef();
00205    }
00206    catch (...)
00207    {
00208       // don't let exceptions escape
00209    }
00210 }
00212 template<class T>
00213 inline void COWReference<T>::decRef()
00214 {
00215    typedef char type_must_be_complete[sizeof(T)];
00216    if (COWReferenceBase::decRef())
00217    {
00218       delete m_pObj;
00219       m_pObj = 0;
00220    }
00221 }
00222 
00224 template<class T>
00225 inline void COWReference<T>::getWriteLock()
00226 {
00227    if (COWReferenceBase::refCountGreaterThanOne())
00228    {
00229       // this needs to happen first to avoid a race condition between 
00230       // another thread deleting the object and this one making a copy.
00231       T* tmp = COWReferenceClone(m_pObj);
00232       // this will decrement the count and then make a new one if we're making a copy.
00233       if (COWReferenceBase::getWriteLock())
00234       {
00235          delete tmp;
00236       }
00237       else
00238       {
00239          m_pObj = tmp;
00240       }
00241    }
00242 }
00244 template<class T>
00245 inline COWReference<T>& COWReference<T>::operator= (const COWReference<T>& arg)
00246 {
00247    COWReference<T>(arg).swap(*this);
00248    return *this;
00249 }
00251 template<class T>
00252 inline COWReference<T>& COWReference<T>::operator= (T* newObj)
00253 {
00254    COWReference<T>(newObj).swap(*this);
00255    return *this;
00256 }
00258 template <class T>
00259 inline void COWReference<T>::swap(COWReference<T>& arg)
00260 {
00261    COWReferenceBase::swap(arg);
00262    COWRefSwap(m_pObj, arg.m_pObj);
00263 }
00265 template<class T>
00266 inline T* COWReference<T>::operator->()
00267 {
00268 #ifdef BLOCXX_CHECK_NULL_REFERENCES
00269    checkNull(this);
00270    checkNull(m_pObj);
00271 #endif
00272    getWriteLock();
00273 
00274    return m_pObj;
00275 }
00277 template<class T>
00278 inline T& COWReference<T>::operator*()
00279 {
00280 #ifdef BLOCXX_CHECK_NULL_REFERENCES
00281    checkNull(this);
00282    checkNull(m_pObj);
00283 #endif
00284    getWriteLock();
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    checkNull(this);
00294    checkNull(m_pObj);
00295 #endif
00296 
00297    return m_pObj;
00298 }
00300 template<class T>
00301 inline const T& COWReference<T>::operator*() const
00302 {
00303 #ifdef BLOCXX_CHECK_NULL_REFERENCES
00304    checkNull(this);
00305    checkNull(m_pObj);
00306 #endif
00307 
00308    return *(m_pObj);
00309 }
00311 template<class T>
00312 inline const T* COWReference<T>::getPtr() const
00313 {
00314    return m_pObj;
00315 }
00317 template <class T>
00318 template <class U>
00319 inline COWReference<U>
00320 COWReference<T>::cast_to() const
00321 {
00322    COWReference<U> rval;
00323    rval.m_pObj = dynamic_cast<U*>(m_pObj);
00324    if (rval.m_pObj)
00325    {
00326       rval.useRefCountOf(*this);
00327    }
00328    return rval;
00329 }
00331 template <class T>
00332 template <class U>
00333 inline void
00334 COWReference<T>::useRefCountOf(const COWReference<U>& arg)
00335 {
00336    COWReferenceBase::useRefCountOf(arg);
00337 }
00339 // Comparisons
00340 template <class T, class U>
00341 inline bool operator==(const COWReference<T>& a, const COWReference<U>& b)
00342 {
00343    return a.getPtr() == b.getPtr();
00344 }
00346 template <class T, class U>
00347 inline bool operator!=(const COWReference<T>& a, const COWReference<U>& b)
00348 {
00349    return a.getPtr() != b.getPtr();
00350 }
00352 template <class T, class U>
00353 inline bool operator<(const COWReference<T>& a, const COWReference<U>& b)
00354 {
00355    return a.getPtr() < b.getPtr();
00356 }
00357 
00359 template <class T>
00360 inline T* COWReferenceClone(T* obj)
00361 {
00362    // default implementation.  If a certain class doesn't have clone()
00363    // (like std::vector), then they can overload this function
00364    return obj->clone();
00365 }
00366 
00367 } // end namespace BLOCXX_NAMESPACE
00368 
00369 #endif   // BLOCXX_COWREFERENCE_HPP_

Generated on Fri Jun 16 15:39:08 2006 for blocxx by  doxygen 1.4.6