pl-nk v0.4.5
Plonk|Plink|Plank are a set of cross-platform C/C++ frameworks for audio software development
plonk_LockFreeStack.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_LOCKFREESTACK_H
00040 #define PLONK_LOCKFREESTACK_H
00041 
00042 #include "../core/plonk_CoreForwardDeclarations.h"
00043 #include "plonk_ContainerForwardDeclarations.h"
00044 
00045 #include "../core/plonk_SmartPointer.h"
00046 #include "../core/plonk_WeakPointer.h"
00047 
00048 template<class ValueType>                                               
00049 class LockFreeStackInternal : public SmartPointer
00050 {
00051 public:
00052     typedef LockFreeStack<ValueType>        StackType;
00053 
00054     LockFreeStackInternal() throw()
00055     {
00056         initStack (liveStack);
00057         initStack (deadStack);
00058     }
00059     
00060     ~LockFreeStackInternal()
00061     {
00062         deInitStack (liveStack);
00063         deInitStack (deadStack);
00064     }
00065     
00066     inline void push (ValueType const& value) throw()
00067     {
00068         PlankLockFreeStackElementRef element = createElement (value);
00069         ResultCode result = pl_LockFreeStack_Push (&liveStack, element);
00070         plonk_assert (result == PlankResult_OK);
00071 #ifndef PLONK_DEBUG
00072         (void)result;
00073 #endif
00074     }
00075     
00076     inline ValueType pop() throw()
00077     {
00078         ValueType value;
00079         ValueType* valuePtr = popInternal (&value);
00080         return (valuePtr == 0) ? getNullValue() : value;
00081     }
00082     
00083     void clear() throw()
00084     {
00085         ValueType* valuePtr;
00086         do 
00087         {
00088             valuePtr = popInternal (0);
00089         } while (valuePtr != 0);
00090     }
00091     
00092     void clearCache() throw()
00093     {
00094         ResultCode result = pl_LockFreeStack_Clear (&deadStack);
00095         plonk_assert (result == PlankResult_OK);
00096 #ifndef PLONK_DEBUG
00097         (void)result;
00098 #endif
00099     }
00100 
00101     void clearAll() throw()
00102     {
00103         ResultCode result = pl_LockFreeStack_Clear (&liveStack);
00104         plonk_assert (result == PlankResult_OK);
00105         
00106         clearCache();
00107         
00108 #ifndef PLONK_DEBUG
00109         (void)result;
00110 #endif
00111     }
00112     
00113     inline LongLong length() throw()
00114     {
00115         return pl_LockFreeStack_GetSize (&liveStack);
00116     }
00117     
00118     friend class LockFreeStack<ValueType>;
00119     
00120 private:
00121     PLONK_ALIGN(16) PlankLockFreeStack liveStack;
00122     PLONK_ALIGN(16) PlankLockFreeStack deadStack;
00123         
00124     static void initStack (PlankLockFreeStack& stack) throw()
00125     {
00126         pl_LockFreeStack_Init (&stack);
00127         pl_LockFreeStack_SetFreeElementDataFunction (&stack, LockFreeStackInternal::freeElement);
00128     }
00129     
00130     static void deInitStack (PlankLockFreeStack& stack) throw()
00131     {
00132         ResultCode result;
00133         
00134         result = pl_LockFreeStack_Clear (&stack);
00135         plonk_assert (result == PlankResult_OK);
00136         
00137         result = pl_LockFreeStack_DeInit (&stack);
00138         plonk_assert (result == PlankResult_OK);
00139         
00140 #ifndef PLONK_DEBUG
00141         (void)result;
00142 #endif
00143     }
00144     
00145     inline PlankLockFreeStackElementRef createElement (ValueType const& value) throw()
00146     {
00147         PlankLockFreeStackElementRef element;
00148         ResultCode result = pl_LockFreeStack_Pop (&deadStack, &element);
00149         plonk_assert (result == PlankResult_OK);
00150         
00151         if (element != 0)
00152         {
00153             ValueType* const data = static_cast<ValueType*> (pl_LockFreeStackElement_GetData (element));
00154             plonk_assert (data != 0);
00155             *data = value;
00156         }
00157         else 
00158         {
00159             element = pl_LockFreeStackElement_CreateAndInit();
00160             plonk_assert (element != 0);
00161             pl_LockFreeStackElement_SetData (element, new ValueType (value));
00162         }
00163         
00164 #ifndef PLONK_DEBUG
00165         (void)result;
00166 #endif
00167         
00168         return element;
00169     }
00170     
00171     static ResultCode freeElement (Pointer data)
00172     {
00173         delete static_cast<ValueType*> (data);
00174         return PlankResult_OK;
00175     }
00176     
00177     static inline ValueType getNullValue() throw()
00178     {
00179         static ValueType null = ValueType();
00180         return null;
00181     }
00182     
00183     ValueType* popInternal (ValueType* value) throw()
00184     {
00185         ValueType* valuePtr = 0;
00186         
00187         PlankLockFreeStackElementRef element;
00188         ResultCode result = pl_LockFreeStack_Pop (&liveStack, &element);
00189         plonk_assert (result == PlankResult_OK);
00190         
00191         if (element != 0)
00192         {
00193             valuePtr = static_cast <ValueType*> (pl_LockFreeStackElement_GetData (element));
00194             plonk_assert (valuePtr != 0);
00195                         
00196             if (value != 0)
00197                 *value = *valuePtr;
00198             
00199             *valuePtr = getNullValue();
00200             
00201             result = pl_LockFreeStack_Push (&deadStack, element);
00202             plonk_assert (result == PlankResult_OK);
00203         }
00204         
00205 #ifndef PLONK_DEBUG
00206         (void)result;
00207 #endif
00208         
00209         return valuePtr;
00210     }
00211 
00212 };
00213 
00214 
00215 template<class ValueType>                                               
00216 class LockFreeStackInternal<ValueType*> : public SmartPointer
00217 {
00218 public:
00219     typedef LockFreeStack<ValueType*>        StackType;
00220     
00221     LockFreeStackInternal() throw()
00222     {
00223         pl_LockFreeStack_Init (&stack);
00224     }
00225     
00226     ~LockFreeStackInternal()
00227     {
00228         pl_LockFreeStack_DeInit (&stack);
00229     }
00230     
00231     void push (ValueType* const value) throw()
00232     {
00233         PlankLockFreeStackElementRef element = pl_LockFreeStackElement_CreateAndInit();
00234         plonk_assert (element != 0);
00235         pl_LockFreeStackElement_SetData (element, value);
00236         ResultCode result = pl_LockFreeStack_Push (&stack, element);
00237         plonk_assert (result == PlankResult_OK);
00238 #ifndef PLONK_DEBUG
00239         (void)result;
00240 #endif
00241     }
00242     
00243     ValueType* pop() throw()
00244     {
00245         ValueType* returnValue;
00246         
00247         PlankLockFreeStackElementRef element;
00248         ResultCode result = pl_LockFreeStack_Pop (&stack, &element);
00249         plonk_assert (result == PlankResult_OK);
00250         
00251         if (element != 0)
00252         {
00253             returnValue = static_cast <ValueType*> (pl_LockFreeStackElement_GetData (element));                        
00254             result = pl_LockFreeStackElement_Destroy (element);
00255             plonk_assert (result == PlankResult_OK);
00256         }
00257         
00258 #ifndef PLONK_DEBUG
00259         (void)result;
00260 #endif
00261         
00262         return returnValue;
00263     }
00264     
00265     void clear() throw()
00266     {
00267         ResultCode result = pl_LockFreeStack_Clear (&stack);
00268         plonk_assert (result == PlankResult_OK);
00269 #ifndef PLONK_DEBUG
00270         (void)result;
00271 #endif
00272     }
00273     
00274     void clearCache() throw()
00275     {
00276         // not applicable
00277     }
00278     
00279     void clearAll() throw()
00280     {
00281         clear();
00282     }
00283     
00284     LongLong length() throw()
00285     {
00286         return pl_LockFreeStack_GetSize (&stack);
00287     }
00288     
00289     friend class LockFreeStack<ValueType*>;
00290     
00291 private:
00292     PLONK_ALIGN(16) PlankLockFreeStack stack;
00293 };
00294 
00295 
00296 
00297 //------------------------------------------------------------------------------
00298 
00300 template<class ValueType>                                               
00301 class LockFreeStack : public SmartPointerContainer<LockFreeStackInternal<ValueType> >
00302 {
00303 public:
00304     typedef LockFreeStackInternal<ValueType>    Internal;
00305     typedef SmartPointerContainer<Internal>     Base;
00306     typedef WeakPointerContainer<LockFreeStack> Weak;    
00307 
00308     inline LockFreeStack()
00309     :   Base (new Internal())
00310     {
00311     }
00312     
00313     inline explicit LockFreeStack (Internal* internalToUse) throw() 
00314         :       Base (internalToUse)
00315         {
00316         }
00317     
00321     static LockFreeStack fromWeak (Weak const& weak) throw()
00322     {
00323         return weak.fromWeak();
00324     }    
00325     
00327     inline LockFreeStack (LockFreeStack const& copy) throw()
00328     :   Base (static_cast<Base const&> (copy))
00329     {
00330     }
00331     
00332     inline LockFreeStack (Dynamic const& other) throw()
00333     :   Base (other.as<LockFreeStack>().getInternal())
00334     {
00335     }    
00336     
00338     inline LockFreeStack& operator= (LockFreeStack const& other) throw()
00339         {
00340                 if (this != &other)
00341             this->setInternal (other.getInternal());
00342         
00343         return *this;
00344         }
00345     
00346     inline void push (ValueType const& value) throw()
00347     {
00348         this->getInternal()->push (value);
00349     }
00350     
00351     inline ValueType pop() throw()
00352     {
00353         return this->getInternal()->pop();
00354     }
00355     
00356     inline void clear() throw()
00357     {
00358         return this->getInternal()->clear();
00359     }
00360     
00361     inline void clearCache() throw()
00362     {
00363         return this->getInternal()->clearCache();
00364     }
00365     
00366     inline void clearAll() throw()
00367     {
00368         return this->getInternal()->clearAll();
00369     }
00370 
00371     inline LongLong length() throw()
00372     {
00373         return this->getInternal()->length();
00374     }
00375     
00376     PLONK_OBJECTARROWOPERATOR(LockFreeStack);
00377 };
00378 
00379 
00380 #endif // PLONK_LOCKFREESTACK_H
 All Classes Functions Typedefs Enumerations Enumerator Properties