pl-nk v0.4.5
Plonk|Plink|Plank are a set of cross-platform C/C++ frameworks for audio software development
plonk_SmartPointerContainer.h
00001 /*
00002  -------------------------------------------------------------------------------
00003  This file is part of the Plink, Plonk, Plank libraries
00004   by Martin Robinson
00005  
00006  http://code.google.com/p/pl-nk/
00007  
00008  Copyright University of the West of England, Bristol 2011-14
00009  All rights reserved.
00010  
00011  Redistribution and use in source and binary forms, with or without
00012  modification, are permitted provided that the following conditions are met:
00013  
00014  * Redistributions of source code must retain the above copyright
00015    notice, this list of conditions and the following disclaimer.
00016  * Redistributions in binary form must reproduce the above copyright
00017    notice, this list of conditions and the following disclaimer in the
00018    documentation and/or other materials provided with the distribution.
00019  * Neither the name of University of the West of England, Bristol nor 
00020    the names of its contributors may be used to endorse or promote products
00021    derived from this software without specific prior written permission.
00022  
00023  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
00024  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00025  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
00026  DISCLAIMED. IN NO EVENT SHALL UNIVERSITY OF THE WEST OF ENGLAND, BRISTOL BE 
00027  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
00028  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 
00029  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
00030  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
00031  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 
00032  OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
00033  
00034  This software makes use of third party libraries. For more information see:
00035  doc/license.txt included in the distribution.
00036  -------------------------------------------------------------------------------
00037  */
00038 
00039 #ifndef PLONK_SMARTPOINTERCONTAINER_H
00040 #define PLONK_SMARTPOINTERCONTAINER_H
00041 
00042 #include "plonk_SmartPointer.h"
00043 #include "plonk_WeakPointer.h"
00044 
00045 
00046 #define PLONK_OBJECTARROWOPERATOR(Type) \
00047     inline Type* operator->() throw() { return this; } \
00048         inline const Type* operator->() const throw() { return this; }
00049 
00050 
00061 template<class SmartPointerType>
00062 class SmartPointerContainerBase : public PlonkBase
00063 {
00064 public: 
00065     typedef AtomicValue<SmartPointerType*> AtomicPointer;
00066     
00067     inline static SmartPointerType* getNullSmartPointer() throw() 
00068     { 
00069         return static_cast<SmartPointerType*> (0); 
00070     }
00071     
00072         inline SmartPointerContainerBase() throw() 
00073         :       internal (getNullSmartPointer())
00074         {
00075         }
00076     
00077     inline SmartPointerContainerBase (SmartPointerType* internalToUse) throw() 
00078         :       internal (getNullSmartPointer())
00079         {
00080         if (internalToUse != getNullSmartPointer())
00081         {
00082             internalToUse->incrementRefCount();
00083             AtomicPointer temp (internalToUse);
00084             internal.swapWith (temp);
00085         }
00086         }
00087     
00088     inline ~SmartPointerContainerBase()
00089         {        
00090         AtomicPointer temp (getNullSmartPointer());
00091         internal.swapWith (temp);
00092         
00093         SmartPointerType* const tempPtr = temp.getPtrUnchecked(); // unchecked version is fine here
00094         
00095                 if (tempPtr != getNullSmartPointer()) 
00096                         tempPtr->decrementRefCount(); 
00097         }
00098     
00099         inline SmartPointerType* getInternal() const throw() 
00100         {
00101                 return internal.getPtr();
00102         }
00103     
00104     inline SmartPointerType* operator->() throw() 
00105         {
00106                 return internal.getPtr();
00107         }
00108     
00109         inline const SmartPointerType* operator->() const throw() 
00110         {
00111                 return internal.getPtr();
00112         }
00113         
00114         inline bool isNull() const throw()
00115         {
00116                 return internal.getPtr() == getNullSmartPointer();
00117         }
00118         
00119         inline bool isNotNull() const throw()
00120         {
00121                 return internal.getPtr() != getNullSmartPointer();
00122         }
00123         
00124         inline void setInternal (SmartPointerType* newInternal) throw()
00125         {
00126         SmartPointerContainerBase temp (newInternal);
00127         internal.swapWith (temp.internal);        
00128         }
00129     
00130     inline void swapWith (SmartPointerContainerBase& other) throw()
00131     {
00132         // is this a problem is other.internal is contended?
00133         internal.swapWith (other.internal);
00134     }
00135         
00136         inline SmartPointerContainerBase (SmartPointerContainerBase const& copy) throw()
00137     :   internal (getNullSmartPointer())
00138         {
00139         SmartPointerType* copyPtr = copy.internal.getPtr();
00140         
00141         if (copyPtr != getNullSmartPointer()) 
00142         {
00143             copyPtr->incrementRefCount();
00144             AtomicPointer temp (copyPtr);
00145             internal.swapWith (temp);            
00146         }        
00147         }
00148         
00149         inline SmartPointerContainerBase& operator= (SmartPointerContainerBase const& other) throw()
00150         {
00151                 if (this != &other)
00152             this->setInternal (other.getInternal());
00153         
00154                 return *this;           
00155         }    
00156     
00157         inline bool operator== (SmartPointerContainerBase const& other) const throw()
00158         {
00159                 return internal == other.internal;
00160         }
00161         
00162         inline bool operator!= (SmartPointerContainerBase const& other) const throw()
00163         {
00164                 return internal != other.internal;
00165         }
00166     
00167     
00168 private:
00169     AtomicPointer internal;
00170 };
00171 
00172 
00173 template<class SmartPointerType, bool enableWeak>
00174 class SmartPointerContainer : public SmartPointerContainerBase<SmartPointerType>
00175 {
00176 public:
00177     inline SmartPointerContainer (SmartPointerType* internalToUse = 0) throw() 
00178         :       SmartPointerContainerBase<SmartPointerType> (internalToUse)
00179         {
00180         }
00181     
00182     inline SmartPointerContainer (SmartPointerContainer const& copy) throw()
00183         :       SmartPointerContainerBase<SmartPointerType> (copy)
00184         {
00185         }
00186     
00187     inline SmartPointerContainer& operator= (SmartPointerContainer const& other) throw()
00188         {
00189                 if (this != &other)
00190             this->setInternal (other.getInternal());
00191         
00192                 return *this;           
00193         }    
00194     
00195 };
00196 
00197 template<class SmartPointerType>
00198 class SmartPointerContainer<SmartPointerType, true> : public SmartPointerContainerBase<SmartPointerType>
00199 {
00200 public:    
00201     typedef SmartPointerContainerBase<SmartPointerType> Base;
00202     
00203     inline SmartPointerContainer (SmartPointerType* internalToUse = 0) throw() 
00204         :       SmartPointerContainerBase<SmartPointerType> (internalToUse)
00205         {
00206         }
00207     
00208     inline SmartPointerContainer (SmartPointerContainer const& copy) throw()
00209         :       SmartPointerContainerBase<SmartPointerType> (static_cast<Base const&> (copy))
00210         {
00211         }    
00212     
00213     inline SmartPointerContainer& operator= (SmartPointerContainer const& other) throw()
00214         {
00215                 if (this != &other)
00216             this->setInternal (other.getInternal());
00217         
00218                 return *this;           
00219         }    
00220 
00221     WeakPointer* getWeakPointer() const throw()
00222     {
00223         const SmartPointerType* const p = this->getInternal();
00224             
00225         if (p != Base::getNullSmartPointer())
00226         {
00227             WeakPointer* w = static_cast<WeakPointer*> (p->getWeak());            
00228             return w;
00229         }
00230         
00231         return 0;
00232     }
00233     
00234 };
00235 
00236 
00237 template<class SmartPointerContainerType>
00238 void swap (SmartPointerContainerType& a, 
00239            SmartPointerContainerType& b) throw()
00240 {
00241     a.swapWith (b);
00242 }
00243 
00244 template<class ScopedPointerType>
00245 class ScopedPointerContainer
00246 {
00247 public:
00248     typedef AtomicValue<ScopedPointerType*> AtomicPointer;
00249 
00250     ScopedPointerContainer() throw()
00251     :   internal (0)
00252     {
00253     }
00254     
00255     ScopedPointerContainer (ScopedPointerType* const raw) throw()
00256     :   internal (raw)
00257     {
00258     }
00259     
00260     ~ScopedPointerContainer()
00261     {
00262         destroy (*this);
00263     }
00264     
00265     inline ScopedPointerContainer (ScopedPointerContainer& copy) throw()
00266     :   internal (0)
00267         {
00268         this->swapWith (copy);        
00269         }
00270 
00271     inline ScopedPointerContainer& operator= (ScopedPointerType* const raw) throw()
00272         {
00273                 ScopedPointerContainer tmp (raw);
00274         this->swapWith (tmp);                
00275                 return *this;           
00276         }    
00277     
00278         inline ScopedPointerContainer& operator= (ScopedPointerContainer& other) throw()
00279         {
00280                 if (this != &other)
00281         {
00282             destroy (*this);
00283             this->swapWith (other);
00284         }
00285         
00286                 return *this;           
00287         }    
00288     
00289     inline static void destroy (ScopedPointerContainer& container) throw()
00290     {
00291         AtomicPointer tmp (0);
00292         container.internal.swapWith (tmp);
00293         delete tmp.getPtrUnchecked(); // unchecked is fine here
00294     }
00295     
00296     inline void swapWith (ScopedPointerContainer& other) throw()
00297     {
00298         // other might be contended
00299         internal.swapWith (other.internal);
00300     }
00301     
00302     inline ScopedPointerType* getInternal() throw() 
00303     {
00304         return internal.getPtr(); 
00305     }
00306     
00307     inline ScopedPointerType* operator->() throw() 
00308     { 
00309         plonk_assert(internal.getPtrUnchecked() != 0);
00310         return internal.getPtr(); 
00311     }
00312     
00313         inline const ScopedPointerType* operator->() const throw() 
00314     { 
00315         plonk_assert(internal.getPtrUnchecked() != 0);
00316         return internal.getPtr(); 
00317     }
00318     
00319     template<class OtherType>
00320     inline bool operator== (OtherType const& other) const throw()
00321         {
00322                 return internal.getPtrUnchecked() == other;
00323         }
00324         
00325     template<class OtherType>
00326         inline bool operator!= (OtherType const& other) const throw()
00327         {
00328                 return internal.getPtrUnchecked() != other;
00329         }
00330         
00331 private:
00332     AtomicPointer internal;    
00333 };
00334 
00335 //------------------------------------------------------------------------------
00336 
00337 #define PLONKSMARTPOINTERCONTAINER_DEEPCOPY(CONTAINERTYPE,SMARTPOINTERTYPE)\
00338     inline CONTAINERTYPE deepCopy() const throw()\
00339     {\
00340         SMARTPOINTERTYPE* const theCopy = static_cast<SMARTPOINTERTYPE*> (this->getInternal()->deepCopy());\
00341         plonk_assert (theCopy != 0);\
00342         return CONTAINERTYPE (theCopy);\
00343     }
00344     
00345 //------------------------------------------------------------------------------
00346     
00347     
00348 template<class PlankSharedPtrType> class PlankWeakPtrContainer;
00349     
00350 template<class PlankSharedPtrType>
00351 class PlankSharedPtrContainer : public PlonkBase
00352 {
00353 public:
00354     typedef PlankSharedPtrType              Internal;
00355     typedef AtomicValue<Internal>           AtomicPointer;
00356     typedef PlankWeakPtrContainer<Internal> Weak;
00357 
00358     inline static Internal getNullSharedPtr() throw()
00359     {
00360         return static_cast<Internal> (0);
00361     }
00362     
00363     inline static PlankSharedPtrContainer getNull() throw()
00364     {
00365         static PlankSharedPtrContainer null (getNullSharedPtr());
00366         return null;
00367     }
00368     
00369     PlankSharedPtrContainer (Internal p) throw()
00370     :   internal (p ? reinterpret_cast<Internal> (pl_SharefPtr_IncrementRefCountAndGetPtr (reinterpret_cast<PlankSharedPtrRef> (p))) : getNullSharedPtr())
00371     {
00372     }
00373     
00374     PlankSharedPtrContainer (Weak const& weak) throw()
00375     :   internal ()
00376     {
00377     }
00378     
00379     inline PlankSharedPtrContainer (PlankSharedPtrContainer const& copy) throw()
00380     :   internal (getNullSharedPtr())
00381         {
00382         Internal const copyPtr = copy.internal.getPtr();
00383         
00384         if (copyPtr != getNullSharedPtr())
00385         {
00386             AtomicPointer temp (reinterpret_cast<Internal> (pl_SharefPtr_IncrementRefCountAndGetPtr (reinterpret_cast<PlankSharedPtrRef> (copyPtr))));
00387             internal.swapWith (temp);
00388         }
00389         }
00390     
00391     ~PlankSharedPtrContainer()
00392     {
00393         AtomicPointer temp (getNullSharedPtr());
00394         internal.swapWith (temp);
00395         
00396         Internal const tempPtr = temp.getPtrUnchecked(); // unchecked version is fine here
00397         
00398                 if (tempPtr != getNullSharedPtr())
00399                         pl_SharedPtr_DecrementRefCount (reinterpret_cast<PlankSharedPtrRef> (tempPtr));
00400     }
00401 
00402     inline PlankSharedPtrContainer& operator= (PlankSharedPtrContainer const& other) throw()
00403     {
00404         if (this != &other)
00405             this->setInternal (other.getInternal());
00406             
00407         return *this;
00408     }
00409     
00410     inline void setInternal (Internal newInternal) throw()
00411         {
00412         PlankSharedPtrContainer temp (newInternal);
00413         internal.swapWith (temp.internal);
00414         }
00415     
00416     inline void swapWith (PlankSharedPtrContainer& other) throw()
00417     {
00418         internal.swapWith (other.internal);
00419     }
00420 
00421     inline Internal getInternal() throw()
00422     {
00423         return internal.getPtr();
00424     }
00425 
00426     inline Internal getInternal() const throw()
00427     {
00428         return internal.getPtr();
00429     }
00430 
00431     inline Internal operator->() throw()
00432         {
00433                 return internal.getPtr();
00434         }
00435     
00436         inline const Internal operator->() const throw()
00437         {
00438                 return internal.getPtr();
00439         }
00440     
00441         inline bool isNull() const throw()
00442         {
00443                 return internal.getPtr() == getNullSharedPtr();
00444         }
00445         
00446         inline bool isNotNull() const throw()
00447         {
00448                 return internal.getPtr() != getNullSharedPtr();
00449         }
00450     
00451     Weak getWeak() throw()
00452     {
00453         return Weak (pl_SharedPtr_GetWeakPtr (reinterpret_cast<PlankSharedPtrRef> (internal.getPtr())));
00454     }
00455     
00456 protected:
00458     template<typename InitFunction>
00459     inline void initInternalWithFunction (InitFunction initFunction) throw()
00460         {
00461         plonk_assert (internal.getPtrUnchecked() == PlankSharedPtrContainer::getNullSharedPtr());
00462         Internal newInternal;
00463         initFunction (&newInternal);
00464         internal.getAtomicRef()->ptr = newInternal;
00465         }
00466     
00467     template<typename InitFunction, typename ArgType>
00468     inline void initInternalWithFunction (InitFunction initFunction, ArgType arg) throw()
00469         {
00470         plonk_assert (internal.getPtrUnchecked() == PlankSharedPtrContainer::getNullSharedPtr());
00471         Internal newInternal;
00472         initFunction (&newInternal, arg);
00473         internal.getAtomicRef()->ptr = newInternal;
00474         }
00475 
00476     
00477 private:
00478     AtomicPointer internal;
00479 };
00480     
00481 //------------------------------------------------------------------------------
00482 
00483 template<class PlankSharedPtrType>
00484 class PlankWeakPtrContainer : public PlankSharedPtrContainer<PlankWeakPtrRef>
00485 {
00486 public:
00487     typedef PlankSharedPtrContainer<PlankWeakPtrRef> Base;
00488     typedef PlankSharedPtrContainer<PlankSharedPtrType> OriginalType;
00489     
00490     PlankWeakPtrContainer() throw()
00491     :   Base (Base::getNullSharedPtr())
00492     {
00493     }
00494     
00495     PlankWeakPtrContainer (PlankWeakPtrRef p) throw()
00496     :   Base (p)
00497     {
00498         if (p)
00499         {
00500             pl_WeakPtr_DecrementRefCount (p);
00501         }
00502     }
00503     
00504     PlankWeakPtrContainer (PlankWeakPtrContainer const& copy) throw()
00505     :   Base (static_cast<Base const&> (copy))
00506     {
00507     }
00508 
00509     PlankWeakPtrContainer& operator= (PlankWeakPtrContainer const& other) throw()
00510     {
00511         if (this != &other)
00512             this->setInternal (other.getInternal());
00513         
00514         return *this;
00515     }
00516     
00517     OriginalType fromWeak() const throw()
00518     {
00519         PlankSharedPtrType sharedPtr = reinterpret_cast<PlankSharedPtrType> (pl_WeakPtr_GetSharedPtr (this->getInternal()));
00520         OriginalType result (sharedPtr);
00521         pl_SharedPtr_DecrementRefCount (reinterpret_cast<PlankSharedPtrRef> (sharedPtr));
00522         return result;
00523     }
00524     
00525 };
00526 
00527 //------------------------------------------------------------------------------
00528 
00529 template<class PlankSharePtrContainterType>
00530 class PlankSharedPtrArrayContainer : public PlankSharedPtrContainer<PlankSharedPtrArrayRef>
00531 {
00532 public:
00533     typedef PlankSharedPtrContainer<PlankSharedPtrArrayRef> Base;
00534     typedef PlankSharePtrContainterType                     ElementType;
00535     typedef typename ElementType::Internal                  ElementInternalType;
00536     typedef Base::Weak                                      Weak;
00537 
00538     PlankSharedPtrArrayContainer() throw()
00539     :   Base (Base::getNullSharedPtr())
00540     {
00541         initInternalWithFunction (pl_SharedPtrArray_CreateSharedPtr, 0);
00542     }
00543     
00544     PlankSharedPtrArrayContainer (FourCharCode const& elementType) throw()
00545     :   Base (Base::getNullSharedPtr())
00546     {
00547         initInternalWithFunction (pl_SharedPtrArray_CreateSharedPtr, elementType);
00548     }
00549     
00550     PlankSharedPtrArrayContainer (PlankSharedPtrArrayRef p) throw()
00551     :   Base (p)
00552     {
00553     }
00554     
00555     PlankSharedPtrArrayContainer (PlankSharedPtrArrayContainer const& copy) throw()
00556     :   Base (static_cast<Base const&> (copy))
00557     {
00558     }
00559     
00560     PlankSharedPtrArrayContainer (Base const& base) throw()
00561     :   Base (base)
00562     {
00563     }
00564     
00565     PlankSharedPtrArrayContainer (Weak const& weak) throw()
00566     :   Base (weak.fromWeak())
00567     {
00568     }
00569     
00570     PlankSharedPtrArrayContainer& operator= (PlankSharedPtrArrayContainer const& other) throw()
00571     {
00572         if (this != &other)
00573             this->setInternal (other.getInternal());
00574         
00575         return *this;
00576     }
00577     
00578     void clear() throw()
00579     {
00580         Internal const internal = this->getInternal();
00581         
00582         if (internal != ElementType::getNullSharedPtr())
00583             pl_SharedPtrArray_Clear (internal);
00584     }
00585     
00586     Long length() const throw()
00587     {
00588         Internal const internal = this->getInternal();
00589         return internal ? pl_SharedPtrArray_GetLength (internal) : 0;
00590     }
00591 
00592     inline ElementType operator[] (const Long index) const throw()
00593     {
00594         Internal const internal = this->getInternal();
00595         plonk_assert (internal != Base::getNullSharedPtr());
00596         return internal ? ElementType (reinterpret_cast<ElementInternalType> (pl_SharedPtrArray_GetSharedPtr (internal, index))) : ElementType::getNull();
00597     }
00598 
00599     inline ElementType at (const Long index) const throw()
00600     {
00601         return at (index);
00602     }
00603     
00604     inline ElementType wrapAt (const Long index) const throw()
00605     {
00606         Internal const internal = this->getInternal();
00607 
00608         if (internal == Base::getNullSharedPtr())
00609             return ElementType::getNull();
00610         else plonk_assertfalse;
00611         
00612         UnsignedLong length = (unsigned long)this->length();
00613         
00614         if (length == 0)
00615             return ElementType::getNull();
00616 
00617         int indexToUse = index;
00618                 while (indexToUse < 0)
00619                         indexToUse += length;
00620                 
00621         return ElementType (reinterpret_cast<ElementInternalType> (pl_SharedPtrArray_GetSharedPtr (internal,
00622                                                                                                    (unsigned long)indexToUse % length)));
00623         
00624                 return this->getArray()[(unsigned long)indexToUse % (unsigned long)this->length()];
00625     }
00626 
00627     PlankSharedPtrArrayContainer& add (ElementType const& item) throw()
00628     {
00629         Internal const internal = this->getInternal();
00630         
00631         if (internal != Base::getNullSharedPtr())
00632             pl_SharedPtrArray_AddSharedPtr (internal, reinterpret_cast<PlankSharedPtrRef> (item.getInternal()));
00633         else plonk_assertfalse;
00634         
00635         return *this;
00636     }
00637     
00638     PlankSharedPtrArrayContainer& remove (const Long index) throw()
00639     {
00640         Internal const internal = this->getInternal();
00641         
00642         if (internal != Base::getNullSharedPtr())
00643             pl_SharedPtrArray_RemoveSharedPtr (internal, index);
00644         else plonk_assertfalse;
00645         
00646         return *this;
00647     }
00648     
00649     PlankSharedPtrArrayContainer& put (const Long index, ElementType const& item) throw()
00650     {
00651         Internal const internal = this->getInternal();
00652         
00653         if (internal != Base::getNullSharedPtr())
00654             pl_SharedPtrArray_PutSharedPtr (internal, index, static_cast<PlankSharedPtrRef> (item.getInternal()));
00655         else plonk_assertfalse;
00656         
00657         return *this;
00658     }
00659 
00660 };
00661 
00662 
00663 #define PLANKSHAREDPTRCONTAINER_DEFINE(NAME)\
00664     NAME NAME::getNull() throw() { static NAME null (Base::getNullSharedPtr()); return null; }\
00665     NAME::NAME() throw() : Base (Base::getNullSharedPtr()) { initInternalWithFunction (pl_##NAME##_CreateSharedPtr); }\
00666     NAME::NAME (Plank##NAME##Ref p) throw() : Base (p) { }\
00667     NAME::NAME (NAME const& copy) throw() : Base (static_cast<PlankSharedPtrContainer<Plank##NAME##Ref> const&> (copy)) { }\
00668     NAME::NAME (Base const& base) throw() : Base (base) { }\
00669     NAME::NAME (Weak const& weak) throw() : Base (weak.fromWeak()) { }\
00670     NAME& NAME::operator= (NAME const &other) throw() { if (this != &other) this->setInternal (other.getInternal()); return *this; }\
00671     Plank##NAME##Ref NAME::incrementRefCountAndGetPeer() throw() { return pl_##NAME##_IncrementRefCountAndGet (this->getInternal()); }
00672 
00673 
00674 #endif // PLONK_SMARTPOINTERCONTAINER_H
 All Classes Functions Typedefs Enumerations Enumerator Properties