blocxx

COWReference.hpp

Go to the documentation of this file.
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_