reSIProcate/rutil  9694
SharedPtr.hxx
Go to the documentation of this file.
00001 #if !defined(RESIP_SHAREDPTR_HXX)
00002 #define RESIP_SHAREDPTR_HXX
00003 
00013 #include "rutil/SharedCount.hxx"
00014 #include <memory>               // for std::auto_ptr
00015 #include <algorithm>            // for std::swap
00016 #include <functional>           // for std::less
00017 #include <typeinfo>             // for std::bad_cast
00018 #include <iosfwd>               // for std::basic_ostream
00019 #include <cassert>
00020 
00021 namespace resip
00022 {
00023 
00024 template<class T> class enable_shared_from_this;
00025 
00026 struct static_cast_tag {};
00027 struct const_cast_tag {};
00028 struct dynamic_cast_tag {};
00029 struct polymorphic_cast_tag {};
00030 
00031 template<class T> struct SharedPtr_traits
00032 {
00033    typedef T & reference;
00034 };
00035 
00036 template<> struct SharedPtr_traits<void>
00037 {
00038    typedef void reference;
00039 };
00040 
00041 template<> struct SharedPtr_traits<void const>
00042 {
00043    typedef void reference;
00044 };
00045 
00046 template<> struct SharedPtr_traits<void volatile>
00047 {
00048    typedef void reference;
00049 };
00050 
00051 template<> struct SharedPtr_traits<void const volatile>
00052 {
00053    typedef void reference;
00054 };
00055 
00056 // enable_shared_from_this support
00057 
00058 template<class T, class Y> void sp_enable_shared_from_this( shared_count const & pn, resip::enable_shared_from_this<T> const * pe, Y const * px )
00059 {
00060    if(pe != 0) pe->_internal_weak_this._internal_assign(const_cast<Y*>(px), pn);
00061 }
00062 
00063 inline void sp_enable_shared_from_this( shared_count const & /*pn*/, ... )
00064 {
00065 }
00066 
00073 template<class T> class SharedPtr
00074 {
00075 private:
00076 
00077    // Borland 5.5.1 specific workaround
00078    typedef SharedPtr<T> this_type;
00079 
00080 public:
00081 
00082    typedef T element_type;
00083    typedef T value_type;
00084    typedef T * pointer;
00085    typedef typename SharedPtr_traits<T>::reference reference;
00086 
00087    SharedPtr(): px(0), pn() // never throws in 1.30+
00088    {
00089    }
00090 
00091    template<class Y>
00092    explicit SharedPtr(Y * p): px(p), pn(p, checked_deleter<Y>()) // Y must be complete
00093    {
00094        sp_enable_shared_from_this( pn, p, p );
00095    }
00096 
00097    //
00098    // Requirements: D's copy constructor must not throw
00099    //
00100    // SharedPtr will release p by calling d(p)
00101    //
00102 
00103    template<class Y, class D> SharedPtr(Y * p, D d): px(p), pn(p, d)
00104    {
00105        sp_enable_shared_from_this( pn, p, p );
00106    }
00107 
00108 //  generated copy constructor, assignment, destructor are fine...
00109 
00110 //  except that Borland C++ has a bug, and g++ with -Wsynth warns
00111 #if defined(__BORLANDC__) || defined(__GNUC__)
00112    SharedPtr & operator=(SharedPtr const & r) // never throws
00113    {
00114        px = r.px;
00115        pn = r.pn; // shared_count::op= doesn't throw
00116        return *this;
00117    }
00118 #endif
00119 
00120    template<class Y>
00121    SharedPtr(SharedPtr<Y> const & r): px(r.px), pn(r.pn) // never throws
00122    {
00123    }
00124 
00125    template<class Y>
00126    SharedPtr(SharedPtr<Y> const & r, static_cast_tag): px(static_cast<element_type *>(r.px)), pn(r.pn)
00127    {
00128    }
00129 
00130    template<class Y>
00131    SharedPtr(SharedPtr<Y> const & r, const_cast_tag): px(const_cast<element_type *>(r.px)), pn(r.pn)
00132    {
00133    }
00134 
00135    template<class Y>
00136    SharedPtr(SharedPtr<Y> const & r, dynamic_cast_tag): px(dynamic_cast<element_type *>(r.px)), pn(r.pn)
00137    {
00138       if(px == 0) // need to allocate new counter -- the cast failed
00139       {
00140          pn = resip::shared_count();
00141       }
00142    }
00143 
00144    template<class Y>
00145    SharedPtr(SharedPtr<Y> const & r, polymorphic_cast_tag): px(dynamic_cast<element_type *>(r.px)), pn(r.pn)
00146    {
00147       if(px == 0)
00148       {
00149          throw std::bad_cast();
00150       }
00151    }
00152 
00153    template<class Y>
00154    explicit SharedPtr(std::auto_ptr<Y> & r): px(r.get()), pn()
00155    {
00156       Y * tmp = r.get();
00157       pn = shared_count(r);
00158       sp_enable_shared_from_this( pn, tmp, tmp );
00159    }
00160 
00161    template<class Y>
00162    SharedPtr & operator=(SharedPtr<Y> const & r) // never throws
00163    {
00164       px = r.px;
00165       pn = r.pn; // shared_count::op= doesn't throw
00166       return *this;
00167    }
00168 
00169    template<class Y>
00170    SharedPtr & operator=(std::auto_ptr<Y> & r)
00171    {
00172       this_type(r).swap(*this);
00173       return *this;
00174    }
00175 
00176    void reset() // never throws in 1.30+
00177    {
00178       this_type().swap(*this);
00179    }
00180 
00181    template<class Y> void reset(Y * p) // Y must be complete
00182    {
00183       assert(p == 0 || p != px); // catch self-reset errors
00184       this_type(p).swap(*this);
00185    }
00186 
00187    template<class Y, class D> void reset(Y * p, D d)
00188    {
00189       this_type(p, d).swap(*this);
00190    }
00191 
00192    reference operator* () const // never throws
00193    {
00194       assert(px != 0);
00195       return *px;
00196    }
00197 
00198    T * operator-> () const // never throws
00199    {
00200       assert(px != 0);
00201       return px;
00202    }
00203     
00204    T * get() const // never throws
00205    {
00206       return px;
00207    }
00208 
00209    // implicit conversion to "bool"
00210 #if defined(__SUNPRO_CC) // BOOST_WORKAROUND(__SUNPRO_CC, <= 0x530)
00211    operator bool () const
00212    {
00213       return px != 0;
00214    }
00215 #elif defined(__MWERKS__) // BOOST_WORKAROUND(__MWERKS__, BOOST_TESTED_AT(0x3003))
00216    typedef T * (this_type::*unspecified_bool_type)() const;
00217    operator unspecified_bool_type() const // never throws
00218    {
00219       return px == 0? 0: &this_type::get;
00220    }
00221 #else 
00222    typedef T * this_type::*unspecified_bool_type;
00223    operator unspecified_bool_type() const // never throws
00224    {
00225       return px == 0? 0: &this_type::px;
00226    }
00227 #endif
00228 
00229    // operator! is redundant, but some compilers need it
00230    bool operator! () const // never throws
00231    {
00232       return px == 0;
00233    }
00234 
00235    bool unique() const // never throws
00236    {
00237       return pn.unique();
00238    }
00239 
00240    long use_count() const // never throws
00241    {
00242       return pn.use_count();
00243    }
00244 
00245    void swap(SharedPtr<T> & other) // never throws
00246    {
00247       std::swap(px, other.px);
00248       pn.swap(other.pn);
00249    }
00250 
00251    template<class Y> bool _internal_less(SharedPtr<Y> const & rhs) const
00252    {
00253       return pn < rhs.pn;
00254    }
00255 
00256    void * _internal_get_deleter(std::type_info const & ti) const
00257    {
00258       return pn.get_deleter(ti);
00259    }
00260 
00261 // Tasteless as this may seem, making all members public allows member templates
00262 // to work in the absence of member template friends. (Matthew Langston)
00263 
00264 private:
00265 
00266    template<class Y> friend class SharedPtr;
00267 
00268    T * px;                     // contained pointer
00269    shared_count pn;    // reference counter
00270 
00271 };  // SharedPtr
00272 
00273 template<class T, class U> inline bool operator==(SharedPtr<T> const & a, SharedPtr<U> const & b)
00274 {
00275     return a.get() == b.get();
00276 }
00277 
00278 template<class T, class U> inline bool operator!=(SharedPtr<T> const & a, SharedPtr<U> const & b)
00279 {
00280     return a.get() != b.get();
00281 }
00282 
00283 #if __GNUC__ == 2 && __GNUC_MINOR__ <= 96
00284 
00285 // Resolve the ambiguity between our op!= and the one in rel_ops
00286 
00287 template<class T> inline bool operator!=(SharedPtr<T> const & a, SharedPtr<T> const & b)
00288 {
00289     return a.get() != b.get();
00290 }
00291 
00292 #endif
00293 
00294 template<class T, class U> inline bool operator<(SharedPtr<T> const & a, SharedPtr<U> const & b)
00295 {
00296     return a._internal_less(b);
00297 }
00298 
00299 template<class T> inline void swap(SharedPtr<T> & a, SharedPtr<T> & b)
00300 {
00301     a.swap(b);
00302 }
00303 
00304 template<class T, class U> SharedPtr<T> static_pointer_cast(SharedPtr<U> const & r)
00305 {
00306     return SharedPtr<T>(r, static_cast_tag());
00307 }
00308 
00309 template<class T, class U> SharedPtr<T> const_pointer_cast(SharedPtr<U> const & r)
00310 {
00311     return SharedPtr<T>(r, const_cast_tag());
00312 }
00313 
00314 template<class T, class U> SharedPtr<T> dynamic_pointer_cast(SharedPtr<U> const & r)
00315 {
00316     return SharedPtr<T>(r, dynamic_cast_tag());
00317 }
00318 
00319 // shared_*_cast names are deprecated. Use *_pointer_cast instead.
00320 
00321 template<class T, class U> SharedPtr<T> shared_static_cast(SharedPtr<U> const & r)
00322 {
00323     return SharedPtr<T>(r, static_cast_tag());
00324 }
00325 
00326 template<class T, class U> SharedPtr<T> shared_dynamic_cast(SharedPtr<U> const & r)
00327 {
00328     return SharedPtr<T>(r, dynamic_cast_tag());
00329 }
00330 
00331 template<class T, class U> SharedPtr<T> shared_polymorphic_cast(SharedPtr<U> const & r)
00332 {
00333     return SharedPtr<T>(r, polymorphic_cast_tag());
00334 }
00335 
00336 template<class T, class U> SharedPtr<T> shared_polymorphic_downcast(SharedPtr<U> const & r)
00337 {
00338     assert(dynamic_cast<T *>(r.get()) == r.get());
00339     return shared_static_cast<T>(r);
00340 }
00341 
00342 template<class T> inline T * get_pointer(SharedPtr<T> const & p)
00343 {
00344     return p.get();
00345 }
00346 
00347 // operator<<
00348 #if defined(__GNUC__) &&  (__GNUC__ < 3)
00349 template<class Y> EncodeStream & operator<< (EncodeStream & os, SharedPtr<Y> const & p)
00350 {
00351     os << p.get();
00352     return os;
00353 }
00354 #else
00355 template<class E, class T, class Y> std::basic_ostream<E, T> & operator<< (std::basic_ostream<E, T> & os, SharedPtr<Y> const & p)
00356 {
00357     os << p.get();
00358     return os;
00359 }
00360 #endif
00361 
00362 // get_deleter (experimental)
00363 #if (defined(__GNUC__) &&  (__GNUC__ < 3)) || (defined(__EDG_VERSION__) && (__EDG_VERSION__ <= 238))
00364 // g++ 2.9x doesn't allow static_cast<X const *>(void *)
00365 // apparently EDG 2.38 also doesn't accept it
00366 template<class D, class T> D * get_deleter(SharedPtr<T> const & p)
00367 {
00368     void const * q = p._internal_get_deleter(typeid(D));
00369     return const_cast<D *>(static_cast<D const *>(q));
00370 }
00371 #else
00372 template<class D, class T> D * get_deleter(SharedPtr<T> const & p)
00373 {
00374     return static_cast<D *>(p._internal_get_deleter(typeid(D)));
00375 }
00376 #endif
00377 
00378 } // namespace resip
00379 
00380 #endif
00381 
00382 // Note:  This implementation is a modified version of shared_ptr from
00383 // Boost.org
00384 //
00385 // http://www.boost.org/libs/smart_ptr/shared_ptr.htm
00386 //
00387 
00388 /* ====================================================================
00389  *
00390  * Boost Software License - Version 1.0 - August 17th, 2003
00391  * 
00392  * Permission is hereby granted, free of charge, to any person or organization
00393  * obtaining a copy of the software and accompanying documentation covered by
00394  * this license (the "Software") to use, reproduce, display, distribute,
00395  * execute, and transmit the Software, and to prepare derivative works of the
00396  * Software, and to permit third-parties to whom the Software is furnished to
00397  * do so, all subject to the following:
00398  * 
00399  * The copyright notices in the Software and this entire statement, including
00400  * the above license grant, this restriction and the following disclaimer,
00401  * must be included in all copies of the Software, in whole or in part, and
00402  * all derivative works of the Software, unless such copies or derivative
00403  * works are solely in the form of machine-executable object code generated by
00404  * a source language processor.
00405  * 
00406  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00407  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00408  * FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
00409  * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
00410  * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
00411  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
00412  * DEALINGS IN THE SOFTWARE.
00413  *
00414  * ====================================================================
00415  */
00416 
00417 
00418 /* ====================================================================
00419  * The Vovida Software License, Version 1.0
00420  *
00421  * Copyright (c) 2000 Vovida Networks, Inc.  All rights reserved.
00422  *
00423  * Redistribution and use in source and binary forms, with or without
00424  * modification, are permitted provided that the following conditions
00425  * are met:
00426  *
00427  * 1. Redistributions of source code must retain the above copyright
00428  *    notice, this list of conditions and the following disclaimer.
00429  *
00430  * 2. Redistributions in binary form must reproduce the above copyright
00431  *    notice, this list of conditions and the following disclaimer in
00432  *    the documentation and/or other materials provided with the
00433  *    distribution.
00434  *
00435  * 3. The names "VOCAL", "Vovida Open Communication Application Library",
00436  *    and "Vovida Open Communication Application Library (VOCAL)" must
00437  *    not be used to endorse or promote products derived from this
00438  *    software without prior written permission. For written
00439  *    permission, please contact vocal@vovida.org.
00440  *
00441  * 4. Products derived from this software may not be called "VOCAL", nor
00442  *    may "VOCAL" appear in their name, without prior written
00443  *    permission of Vovida Networks, Inc.
00444  *
00445  * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
00446  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00447  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
00448  * NON-INFRINGEMENT ARE DISCLAIMED.  IN NO EVENT SHALL VOVIDA
00449  * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
00450  * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
00451  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
00452  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00453  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
00454  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00455  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
00456  * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
00457  * DAMAGE.
00458  *
00459  * ====================================================================
00460  *
00461  * This software consists of voluntary contributions made by Vovida
00462  * Networks, Inc. and many individuals on behalf of Vovida Networks,
00463  * Inc.  For more information on Vovida Networks, Inc., please see
00464  * <http://www.vovida.org/>.
00465  *
00466  */