Advertisement
novacisko

RefCounting in LightSpeed (only header)

Nov 12th, 2011
153
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 7.94 KB | None | 0 0
  1. #ifndef LIGHTSPEED_MEMORY_REFCNTPTR_H_
  2. #define LIGHTSPEED_MEMORY_REFCNTPTR_H_
  3.  
  4. #include "allocPointer.h"
  5.  
  6.  
  7. namespace LightSpeed {
  8.  
  9.  
  10.  
  11.     ///Implements ref counting to allow RefCntPtr work with the object
  12.     /**
  13.      * @param Counter type that implements counting
  14.      */
  15.     class RefCntObj {
  16.         static const natural fastFlag = (~natural(0)) << (sizeof(natural) * 8 - 1);
  17.     public:
  18.  
  19.         RefCntObj():counter(fastFlag) {}
  20.  
  21.         ///adds reference to counter
  22.         void addRef() const {
  23.             if ((counter & fastFlag)) ++counter;
  24.             else addRefMT();
  25.         }
  26.  
  27.         ///releases reference to counter
  28.         /**
  29.          * @retval true counter reaches a zero and object must be destroyed
  30.          * @retval false counter did not reached a zero
  31.          */
  32.         bool release() const {
  33.             if ((counter & fastFlag) != 0) {
  34.                 return --counter <= fastFlag;
  35.             } else {
  36.                 return releaseMT();
  37.             }
  38.         }
  39.  
  40.         ///Returns true, if object is not shared
  41.         bool isShared() const {return (counter & ~fastFlag) != 1;}
  42.  
  43.         ///Sets counter to MT
  44.         void enableMTAccess() const {counter &= ~fastFlag;}
  45.         ///Sets counter to ST
  46.         void disableMTAccess() const {counter |= fastFlag;}
  47.         ///Object is allocated statically
  48.         /** allows to work with RefCntObj, but allocated statically.
  49.          * Counter never reaches a zero
  50.          */
  51.         void setStaticObj() const {counter |= fastFlag >> 1;}
  52.  
  53.     protected:
  54.         ///counter
  55.         mutable natural counter;
  56.  
  57.         void addRefMT() const;
  58.         bool releaseMT() const;
  59.     };
  60.  
  61.  
  62.     ///Shared ref count pointer (intrusive)
  63.     /**Sharing is implemented intrusive using internal counter and it is controlled
  64.      * by methods addRef() and release()
  65.      *
  66.      * Deleting of controlling object is handled by this class instead of
  67.      * referenced class. The referenced class must only export the methods
  68.      * addRef() and release() and must be able report, that reference count
  69.      * reached zero.
  70.      */
  71.     template<typename T,  typename Alloc = StdFactory::Factory<T> >
  72.     class RefCntPtr: public AllocPointer<T,Alloc> {
  73.     public:
  74.         typedef AllocPointer<T,Alloc> Super;
  75.  
  76.         ///Constructs empty pointer
  77.         RefCntPtr() {}
  78.         ///Constructs empty pointer
  79.         RefCntPtr(NullType x):Super(x) {}
  80.         ///Constructs a pointer and add reference
  81.         /**
  82.          * @para p pointer to assign the new instance
  83.          */
  84.         RefCntPtr(T *p):Super(p) {
  85.             addRefPtr();
  86.         }
  87.         ///Destroy instance and release reference
  88.         /**
  89.          * Destroys instance and releases reference. Object can be
  90.          * released, if reference count reaches zero
  91.          */
  92.         ~RefCntPtr() {
  93.             releasePtr();
  94.         }
  95.         RefCntPtr(NullType x, const Alloc &r):Super(x,r) {}
  96.         RefCntPtr(T *ptr,const Alloc &r):Super(ptr,r) {addRefPtr();}
  97.  
  98.  
  99.         ///Copy constructor
  100.         /**@param other source object        
  101.          */
  102.         RefCntPtr(const RefCntPtr &other)
  103.             :Super(other.get(),(const Alloc &)other) {
  104.             addRefPtr();
  105.         }
  106.  
  107.         operator RefCntPtr<const T,Alloc>() const {
  108.             return RefCntPtr<const T,Alloc>(this->ptr,*this);
  109.         }
  110.  
  111.  
  112.         ///Assignment
  113.         /**@param other source object
  114.          * @return this        
  115.          */
  116.         RefCntPtr &operator=(const RefCntPtr &other) {
  117.             Alloc::operator=(other);
  118.             other.manualAddRef();
  119.             releasePtr();
  120.             this->ptr = other.ptr;
  121.             return *this;
  122.         }
  123.  
  124.  
  125.         ///Retrieves MT version of ref.counter
  126.         /**
  127.          * By default, every RefCntPtr is constructed for Single-threaded
  128.          * environment. You can uses RefCntPtr in this mode in MT environment,
  129.          * but you should not share such an objects between the threads.
  130.          *
  131.          * This function enables MT-sharing for current object. You can
  132.          * then duplicate pointers and share object independently to
  133.          * on which thread this happen. Note that sharing object between
  134.          * the threads is slightly slower. But sharing pointer between
  135.          * threads without calling this function can cause unpredictable
  136.          * results,
  137.          *
  138.          * @return copy of reference initializes for multithreaded access
  139.          *
  140.          * @note You should always use result to multithreading share.
  141.          * Do not rely on implementation, it can be changed in the future.
  142.          * Always use getMT() to share object between the threads, even if you
  143.          * know, that object is already in MT mode. There can be change in the future
  144.          * while multiple counters will be used each for different thread
  145.          *
  146.          */
  147.         RefCntPtr getMT() const {
  148.             if (this->ptr) {
  149.                 const RefCntObj *obj = static_cast<const RefCntObj *>(this->ptr);
  150.                 obj->enableMTAccess();
  151.             }
  152.             return *this;
  153.         }
  154.  
  155.         ///True, if object is shared at more than once
  156.         /**
  157.          * @retval true object is shared
  158.          * @retval false object is not shared, this is only reference
  159.          */
  160.         bool isShared() const {
  161.             if (this->ptr == 0) return false;
  162.             return this->ptr->isShared();
  163.         }
  164.  
  165.         ///Manually adds reference
  166.         /** Use only in special cases, when you track count of references differently.
  167.           Note that mistake in reference counting may cause memory leak or
  168.           working with destroyed object
  169.           */
  170.         void manualAddRef() const {
  171.             addRefPtr();
  172.         }
  173.         ///Manually releases reference
  174.         /** Use only in special cases, when you track count of references differently.
  175.           Note that mistake in reference counting may cause memory leak or
  176.           working with destroyed object
  177.           */
  178.         bool manualRelease() const {
  179.             return releasePtrNoDetach();
  180.         }
  181.  
  182.         ///Detaches object from the reference counting
  183.         /** Use only if you want to stop reference counting on the
  184.             object and use another type of reference tracking. This
  185.             is also useful, when you need to change implementation in the
  186.             counting for example from MT unsafe to MT save.
  187.  
  188.             Function decreases reference and removes pointer. Also sets
  189.             this smart pointer to NULL. It expects, that reference count
  190.             reaches zero, but object will not destroyed. This expectation
  191.             is not checked, so you can call this function even the object
  192.             is still shared. But this is not recommended, because this
  193.             will not prevent destruction later. You should do this only
  194.             when isShared() returns false
  195.             */
  196.         T *detach() {
  197.             if (this->ptr) {
  198.                 this->ptr->release();
  199.             }
  200.             return Super::detach();
  201.         }
  202.  
  203.         ///Attaches object to the pointer
  204.         void attach(T *ptr) {
  205.             Super::attach(ptr);
  206.             addRefPtr();
  207.         }
  208.  
  209.         ///Serializing support
  210.         template<typename Arch>
  211.         void serialize(Arch &arch) {
  212.             if (arch.loading()) {
  213.                 releasePtr();
  214.                 Super::serialize(arch);
  215.                 addRefPtr();
  216.             } else {
  217.                 Super::serialize(arch);
  218.             }          
  219.         }
  220.  
  221.         ///Creates new instance using current factory
  222.         void create() {Super::create();addRefPtr();}
  223.         ///Creates new instance using current factory
  224.         /**
  225.          * @param x source instance
  226.          */
  227.         void create(const T &x) {Super::create(x);addRefPtr();}
  228.  
  229.  
  230.  
  231.     protected:
  232.  
  233.  
  234.         ///safety add new reference
  235.         inline void addRefPtr() const {
  236.             if (this->ptr) {
  237.                 this->ptr->addRef();
  238.             }
  239.         }
  240.         ///safety release reference and handle releasing the resource
  241.         inline bool releasePtr() const {
  242.             if (!this->ptr) return false;
  243.             if (this->ptr->release() == true) {
  244.                 const_cast<RefCntPtr *>(this)->Super::clear();
  245.             } else {
  246.                 const_cast<RefCntPtr *>(this)->Super::detach();
  247.             }
  248.             return true;
  249.         }
  250.  
  251.         ///releases reference, but will not detach the object from the pointer
  252.         inline bool releasePtrNoDetach() const {
  253.             if (!this->ptr) return false;
  254.             if (this->ptr->release() == true) {
  255.                 const_cast<RefCntPtr *>(this)->Super::clear();
  256.             }
  257.             return true;
  258.         }
  259. };
  260.  
  261.  
  262.  
  263.  
  264.    
  265.  
  266. } // namespace LightSpeed
  267.  
  268. #endif /*REFCNTPTR_H_*/
  269.  
  270.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement