reSIProcate/rutil  9694
SharedCount.hxx
Go to the documentation of this file.
00001 #if !defined(RESIP_SHAREDCOUNT_HXX)
00002 #define RESIP_SHAREDCOUNT_HXX
00003 
00012 #include <memory>           // std::auto_ptr, std::allocator
00013 #include <functional>       // std::less
00014 #include <exception>        // std::exception
00015 #include <new>              // std::bad_alloc
00016 #include <typeinfo>         // std::type_info in get_deleter
00017 #include <cstddef>          // std::size_t
00018 #include "rutil/Lock.hxx"
00019 #include "rutil/Mutex.hxx"
00020 //#include "rutil/Logger.hxx"
00021 
00022 #ifdef __BORLANDC__
00023 # pragma warn -8026     // Functions with excep. spec. are not expanded inline
00024 # pragma warn -8027     // Functions containing try are not expanded inline
00025 #endif
00026 
00027 namespace resip
00028 {
00029 
00030 // verify that types are complete for increased safety
00031 template<class T> inline void checked_delete(T * x)
00032 {
00033    // intentionally complex - simplification causes regressions
00034    typedef char type_must_be_complete[ sizeof(T)? 1: -1 ];
00035    (void) sizeof(type_must_be_complete);
00036    delete x;
00037 };
00038 
00039 template<class T> struct checked_deleter
00040 {
00041    typedef void result_type;
00042    typedef T * argument_type;
00043 
00044    void operator()(T * x) const
00045    {
00046        // resip:: disables ADL
00047        resip::checked_delete(x);
00048    }
00049 };
00050 
00051 // The standard library that comes with Borland C++ 5.5.1
00052 // defines std::exception and its members as having C calling
00053 // convention (-pc). When the definition of bad_weak_ptr
00054 // is compiled with -ps, the compiler issues an error.
00055 // Hence, the temporary #pragma option -pc below. The version
00056 // check is deliberately conservative.
00057 #if defined(__BORLANDC__) && __BORLANDC__ == 0x551
00058 # pragma option push -pc
00059 #endif
00060 
00061 class bad_weak_ptr: public std::exception
00062 {
00063 public:
00064 
00065    virtual char const * what() const throw()
00066    {
00067        return "resip::bad_weak_ptr";
00068    }
00069 };
00070 
00071 #if defined(__BORLANDC__) && __BORLANDC__ == 0x551
00072 # pragma option pop
00073 #endif
00074 
00075 class sp_counted_base
00076 {
00077 private:
00078 
00079 public:
00080 
00081    sp_counted_base(): use_count_(1), weak_count_(1)
00082    {
00083    }
00084 
00085    virtual ~sp_counted_base() // nothrow
00086    {
00087    }
00088 
00089    // dispose() is called when use_count_ drops to zero, to release
00090    // the resources managed by *this.
00091    virtual void dispose() = 0; // nothrow
00092 
00093    // destruct() is called when weak_count_ drops to zero.
00094    virtual void destruct() // nothrow
00095    {
00096        delete this;
00097    }
00098 
00099    virtual void * get_deleter(std::type_info const & ti) = 0;
00100 
00101    void add_ref_copy()
00102    {
00103       Lock lock(mMutex); (void)lock;
00104       ++use_count_;
00105       //GenericLog(Subsystem::SIP, resip::Log::Info, << "********* SharedCount::add_ref_copy: " << use_count_);
00106    }
00107 
00108    void add_ref_lock()
00109    {
00110       Lock lock(mMutex); (void)lock;
00111       // if(use_count_ == 0) throw(resip::bad_weak_ptr());
00112       if (use_count_ == 0) throw resip::bad_weak_ptr();
00113       ++use_count_;
00114       //GenericLog(Subsystem::SIP, resip::Log::Info, << "********* SharedCount::add_ref_lock: " << use_count_);
00115    }
00116 
00117    void release() // nothrow
00118    {
00119       {
00120          Lock lock(mMutex); (void)lock;
00121          long new_use_count = --use_count_;
00122          //GenericLog(Subsystem::SIP, resip::Log::Info, << "********* SharedCount::release: " << use_count_);
00123 
00124          if(new_use_count != 0) return;
00125       }
00126 
00127       dispose();
00128       weak_release();
00129    }
00130 
00131    void weak_add_ref() // nothrow
00132    {
00133       Lock lock(mMutex); (void)lock;
00134       ++weak_count_;
00135    }
00136 
00137    void weak_release() // nothrow
00138    {
00139       long new_weak_count;
00140 
00141       {
00142          Lock lock(mMutex); (void)lock;
00143          new_weak_count = --weak_count_;
00144       }
00145 
00146       if(new_weak_count == 0)
00147       {
00148           destruct();
00149       }
00150    }
00151 
00152    long use_count() const // nothrow
00153    {
00154       Lock lock(mMutex); (void)lock;
00155       return use_count_;
00156    }
00157 
00158 private:
00159 
00160    sp_counted_base(sp_counted_base const &);
00161    sp_counted_base & operator= (sp_counted_base const &);
00162 
00163    long use_count_;        // #shared
00164    long weak_count_;       // #weak + (#shared != 0)
00165 
00166    mutable Mutex mMutex;
00167 };
00168 
00169 //
00170 // Borland's Codeguard trips up over the -Vx- option here:
00171 //
00172 #ifdef __CODEGUARD__
00173 # pragma option push -Vx-
00174 #endif
00175 
00176 template<class P, class D> class sp_counted_base_impl: public sp_counted_base
00177 {
00178 private:
00179 
00180    P ptr; // copy constructor must not throw
00181    D del; // copy constructor must not throw
00182 
00183    sp_counted_base_impl(sp_counted_base_impl const &);
00184    sp_counted_base_impl & operator= (sp_counted_base_impl const &);
00185 
00186    typedef sp_counted_base_impl<P, D> this_type;
00187 
00188 public:
00189 
00190    // pre: initial_use_count <= initial_weak_count, d(p) must not throw
00191    sp_counted_base_impl(P p, D d): ptr(p), del(d)
00192    {
00193    }
00194 
00195    virtual void dispose() // nothrow
00196    {
00197       del(ptr);
00198    }
00199 
00200    virtual void * get_deleter(std::type_info const & ti)
00201    {
00202       return ti == typeid(D)? &del: 0;
00203    }
00204 
00205    void * operator new(size_t)
00206    {
00207       return std::allocator<this_type>().allocate(1, static_cast<this_type *>(0));
00208    }
00209 
00210    void operator delete(void * p)
00211    {
00212       std::allocator<this_type>().deallocate(static_cast<this_type *>(p), 1);
00213    }
00214 
00215 };
00216 
00217 class shared_count
00218 {
00219 private:
00220 
00221    sp_counted_base * pi_;
00222 
00223 public:
00224 
00225    shared_count(): pi_(0) // nothrow
00226    {
00227    }
00228 
00229    template<class P, class D> shared_count(P p, D d): pi_(0)
00230    {
00231       try
00232       {
00233          pi_ = new sp_counted_base_impl<P, D>(p, d);
00234       }
00235       catch(...)
00236       {
00237          d(p); // delete p
00238          throw;
00239       }
00240    }
00241 
00242    // auto_ptr<Y> is special cased to provide the strong guarantee
00243    template<class Y>
00244    explicit shared_count(std::auto_ptr<Y> & r): pi_(new sp_counted_base_impl< Y *, checked_deleter<Y> >(r.get(), checked_deleter<Y>()))
00245    {
00246       r.release();
00247    }
00248 
00249    ~shared_count() // nothrow
00250    {
00251       if(pi_ != 0) pi_->release();
00252    }
00253 
00254    shared_count(shared_count const & r): pi_(r.pi_) // nothrow
00255    {
00256       if(pi_ != 0) pi_->add_ref_copy();
00257    }
00258 
00259    shared_count & operator= (shared_count const & r) // nothrow
00260    {
00261       sp_counted_base * tmp = r.pi_;
00262       if(tmp != 0) tmp->add_ref_copy();
00263       if(pi_ != 0) pi_->release();
00264       pi_ = tmp;
00265 
00266       return *this;
00267    }
00268 
00269    void swap(shared_count & r) // nothrow
00270    {
00271       sp_counted_base * tmp = r.pi_;
00272       r.pi_ = pi_;
00273       pi_ = tmp;
00274    }
00275 
00276    long use_count() const // nothrow
00277    {
00278       return pi_ != 0? pi_->use_count(): 0;
00279    }
00280 
00281    bool unique() const // nothrow
00282    {
00283       return use_count() == 1;
00284    }
00285 
00286    friend inline bool operator==(shared_count const & a, shared_count const & b)
00287    {
00288       return a.pi_ == b.pi_;
00289    }
00290 
00291    friend inline bool operator<(shared_count const & a, shared_count const & b)
00292    {
00293       return std::less<sp_counted_base *>()(a.pi_, b.pi_);
00294    }
00295 
00296    void * get_deleter(std::type_info const & ti) const
00297    {
00298       return pi_? pi_->get_deleter(ti): 0;
00299    }
00300 };
00301 
00302 #ifdef __CODEGUARD__
00303 # pragma option pop
00304 #endif
00305 
00306 } // namespace resip
00307 
00308 #ifdef __BORLANDC__
00309 # pragma warn .8027     // Functions containing try are not expanded inline
00310 # pragma warn .8026     // Functions with excep. spec. are not expanded inline
00311 #endif
00312 
00313 
00314 #endif
00315 
00316 // Note:  This implementation is a modified version of shared_count from
00317 // Boost.org
00318 //
00319 
00320 /* ====================================================================
00321  *
00322  * Boost Software License - Version 1.0 - August 17th, 2003
00323  * 
00324  * Permission is hereby granted, free of charge, to any person or organization
00325  * obtaining a copy of the software and accompanying documentation covered by
00326  * this license (the "Software") to use, reproduce, display, distribute,
00327  * execute, and transmit the Software, and to prepare derivative works of the
00328  * Software, and to permit third-parties to whom the Software is furnished to
00329  * do so, all subject to the following:
00330  * 
00331  * The copyright notices in the Software and this entire statement, including
00332  * the above license grant, this restriction and the following disclaimer,
00333  * must be included in all copies of the Software, in whole or in part, and
00334  * all derivative works of the Software, unless such copies or derivative
00335  * works are solely in the form of machine-executable object code generated by
00336  * a source language processor.
00337  * 
00338  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00339  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00340  * FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
00341  * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
00342  * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
00343  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
00344  * DEALINGS IN THE SOFTWARE.
00345  *
00346  * ====================================================================
00347  */
00348 
00349 
00350 /* ====================================================================
00351  * The Vovida Software License, Version 1.0
00352  *
00353  * Copyright (c) 2000 Vovida Networks, Inc.  All rights reserved.
00354  *
00355  * Redistribution and use in source and binary forms, with or without
00356  * modification, are permitted provided that the following conditions
00357  * are met:
00358  *
00359  * 1. Redistributions of source code must retain the above copyright
00360  *    notice, this list of conditions and the following disclaimer.
00361  *
00362  * 2. Redistributions in binary form must reproduce the above copyright
00363  *    notice, this list of conditions and the following disclaimer in
00364  *    the documentation and/or other materials provided with the
00365  *    distribution.
00366  *
00367  * 3. The names "VOCAL", "Vovida Open Communication Application Library",
00368  *    and "Vovida Open Communication Application Library (VOCAL)" must
00369  *    not be used to endorse or promote products derived from this
00370  *    software without prior written permission. For written
00371  *    permission, please contact vocal@vovida.org.
00372  *
00373  * 4. Products derived from this software may not be called "VOCAL", nor
00374  *    may "VOCAL" appear in their name, without prior written
00375  *    permission of Vovida Networks, Inc.
00376  *
00377  * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
00378  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00379  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
00380  * NON-INFRINGEMENT ARE DISCLAIMED.  IN NO EVENT SHALL VOVIDA
00381  * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
00382  * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
00383  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
00384  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00385  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
00386  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00387  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
00388  * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
00389  * DAMAGE.
00390  *
00391  * ====================================================================
00392  *
00393  * This software consists of voluntary contributions made by Vovida
00394  * Networks, Inc. and many individuals on behalf of Vovida Networks,
00395  * Inc.  For more information on Vovida Networks, Inc., please see
00396  * <http://www.vovida.org/>.
00397  *
00398  */