libmoost
/home/mhx/git/github/libmoost/include/moost/guarded_ptr.hpp
Go to the documentation of this file.
00001 /* vim:set ts=3 sw=3 sts=3 et: */
00098 #ifndef MOOST_GUARDED_PTR_HPP__
00099 #define MOOST_GUARDED_PTR_HPP__
00100 
00101 #include <cassert>
00102 
00103 #include <boost/noncopyable.hpp>
00104 #include <boost/scoped_ptr.hpp>
00105 #include <boost/thread/shared_mutex.hpp>
00106 #include <boost/thread/locks.hpp>
00107 
00108 namespace moost {
00109 
00119 template<typename T>
00120 class guarded_ptr : boost::noncopyable
00121 {
00122 public:
00123    typedef T element_type;
00124    typedef T value_type;
00125    typedef T * pointer;
00126    typedef T const * const_pointer;
00127    typedef T & reference;
00128    typedef T const & const_reference;
00129 
00138    class shared_access : boost::noncopyable
00139    {
00140    public:
00141       shared_access(guarded_ptr const & guard)
00142          : m_gptr(guard)
00143       {
00144          m_gptr.m_mutex.lock_shared();
00145       }
00146 
00147       ~shared_access()
00148       {
00149          m_gptr.m_mutex.unlock_shared();
00150       }
00151 
00152       const_reference operator*() const
00153       {
00154          return *(m_gptr.m_ptr);
00155       }
00156       const_pointer operator->() const
00157       {
00158          return m_gptr.m_ptr.get();
00159       }
00160 
00161    private:
00162       guarded_ptr const & m_gptr;
00163    };
00164 
00173    class exclusive_access : boost::noncopyable
00174    {
00175    public:
00176       exclusive_access(guarded_ptr &guard)
00177          : m_gptr(guard)
00178       {
00179          m_gptr.m_mutex.lock();
00180       }
00181 
00182       ~exclusive_access()
00183       {
00184          m_gptr.m_mutex.unlock();
00185       }
00186 
00187       reference operator*()
00188       {
00189          return *(m_gptr.m_ptr);
00190       }
00191       const_reference operator*() const
00192       {
00193          return *(m_gptr.m_ptr);
00194       }
00195       pointer operator->()
00196       {
00197          return m_gptr.m_ptr.get();
00198       }
00199       const_pointer operator->() const
00200       {
00201          return m_gptr.m_ptr.get();
00202       }
00203 
00204    private:
00205       guarded_ptr & m_gptr;
00206    };
00207 
00219    class upgradable_access : boost::noncopyable
00220    {
00221    public:
00222       upgradable_access(guarded_ptr &guard)
00223          : m_gptr(guard)
00224          , m_upgraded(false)
00225       {
00226          m_gptr.m_mutex.lock_upgrade();
00227       }
00228       ~upgradable_access()
00229       {
00230          if (m_upgraded)
00231          {
00232             m_gptr.m_mutex.unlock();
00233          }
00234          else
00235          {
00236             m_gptr.m_mutex.unlock_upgrade();
00237          }
00238       }
00239 
00240       const_reference operator*() const
00241       {
00242          return *(m_gptr.m_ptr);
00243       }
00244       const_pointer operator->() const
00245       {
00246          return m_gptr.m_ptr.get();
00247       }
00248 
00259       class upgrade
00260       {
00261       public:
00262          upgrade(upgradable_access & parent)
00263             : m_parent(parent)
00264          {
00265             parent.m_gptr.m_mutex.unlock_upgrade_and_lock();
00266             parent.m_upgraded = true;
00267          }
00268 
00269          reference operator*()
00270          {
00271             return *(m_parent.m_gptr.m_ptr);
00272          }
00273          const_reference operator*() const
00274          {
00275             return *(m_parent.m_gptr.m_ptr);
00276          }
00277          pointer operator->()
00278          {
00279             return m_parent.m_gptr.m_ptr.get();
00280          }
00281          const_pointer operator->() const
00282          {
00283             return m_parent.m_gptr.m_ptr.get();
00284          }
00285 
00286       private:
00287          upgradable_access & m_parent;
00288       };
00289 
00290    private:
00291       guarded_ptr & m_gptr;
00292       bool m_upgraded;
00293    };
00294 
00295    guarded_ptr(pointer ptr)
00296       : m_ptr(assert_not_null(ptr)) // do the assert early during construction
00297    {
00298    }
00299 
00300 private:
00301    pointer assert_not_null(pointer ptr)
00302    {
00303       assert(ptr);
00304       return ptr;
00305    }
00306 
00307    boost::scoped_ptr<element_type> const m_ptr;
00308    boost::shared_mutex mutable m_mutex;
00309 };
00310 
00311 } // namespace moost
00312 
00313 #endif // ifndef MOOST_GUARDED_PTR_HPP__