pl-nk v0.4.5
Plonk|Plink|Plank are a set of cross-platform C/C++ frameworks for audio software development
plonk_LockFreeQueue.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_LOCKFREEQUEUE_H
00040 #define PLONK_LOCKFREEQUEUE_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 LockFreeQueueInternal : public SmartPointer
00050 {
00051 public:
00052     typedef LockFreeQueue<ValueType>        QueueType;
00053     
00054     LockFreeQueueInternal() throw()
00055     {
00056         initQueue (liveQueue);
00057         initQueue (deadQueue);
00058     }
00059     
00060     ~LockFreeQueueInternal()
00061     {
00062         deInitQueue (liveQueue);
00063         deInitQueue (deadQueue);
00064     }
00065     
00066     inline void push (ValueType const& value) throw()
00067     {
00068         PlankLockFreeQueueElementRef element = createElement (value);
00069         ResultCode result = pl_LockFreeQueue_Push (&liveQueue, 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     template<class OtherType>
00084     inline bool pop (OtherType& value)
00085     {
00086         ValueType tmp;
00087         ValueType* valuePtr = popInternal (&tmp);
00088  
00089         if (valuePtr != 0)
00090         {
00091             value = tmp;
00092             return true;
00093         }
00094         else return false;
00095     }
00096 
00097     void clear() throw()
00098     {
00099         ValueType* valuePtr;
00100         do 
00101         {
00102             valuePtr = popInternal (0);
00103         } while (valuePtr != 0);
00104     }
00105     
00106     void clearCache() throw()
00107     {
00108         ResultCode result = pl_LockFreeQueue_Clear (&deadQueue);
00109         plonk_assert (result == PlankResult_OK);
00110 #ifndef PLONK_DEBUG
00111         (void)result;
00112 #endif
00113     }
00114     
00115     void clearAll() throw()
00116     {
00117         ResultCode result = pl_LockFreeQueue_Clear (&liveQueue);
00118         plonk_assert (result == PlankResult_OK);
00119         
00120         clearCache();
00121         
00122 #ifndef PLONK_DEBUG
00123         (void)result;
00124 #endif
00125     }
00126     
00127     inline int length() throw()
00128     {
00129         return pl_LockFreeQueue_GetSize (&liveQueue);
00130     }
00131     
00132     friend class LockFreeQueue<ValueType>;
00133     
00134 private:
00135     PLONK_ALIGN(16) PlankLockFreeQueue liveQueue;
00136     PLONK_ALIGN(16) PlankLockFreeQueue deadQueue;
00137     
00138     static void initQueue (PlankLockFreeQueue& queue) throw()
00139     {
00140         pl_LockFreeQueue_Init (&queue);
00141         pl_LockFreeQueue_SetFreeElementDataFunction (&queue, LockFreeQueueInternal::freeElement);
00142     }
00143     
00144     static void deInitQueue (PlankLockFreeQueue& queue) throw()
00145     {
00146         ResultCode result;
00147         
00148         result = pl_LockFreeQueue_Clear (&queue);
00149         plonk_assert (result == PlankResult_OK);
00150         
00151         result = pl_LockFreeQueue_DeInit (&queue);
00152         plonk_assert (result == PlankResult_OK);
00153         
00154 #ifndef PLONK_DEBUG
00155         (void)result;
00156 #endif
00157     }
00158     
00159     inline PlankLockFreeQueueElementRef createElement (ValueType const& value) throw()
00160     {
00161         PlankLockFreeQueueElementRef element;
00162         ResultCode result = pl_LockFreeQueue_Pop (&deadQueue, &element);
00163         plonk_assert (result == PlankResult_OK);
00164         
00165         if (element != 0)
00166         {
00167             ValueType* const data = static_cast<ValueType*> (pl_LockFreeQueueElement_GetData (element));
00168             plonk_assert (data != 0);
00169             *data = value;
00170         }
00171         else 
00172         {
00173             element = pl_LockFreeQueueElement_CreateAndInit();
00174             plonk_assert (element != 0);
00175             pl_LockFreeQueueElement_SetData (element, new ValueType (value));
00176         }
00177         
00178 #ifndef PLONK_DEBUG
00179         (void)result;
00180 #endif
00181         
00182         return element;
00183     }
00184     
00185     static ResultCode freeElement (Pointer data)
00186     {
00187         delete static_cast<ValueType*> (data);
00188         return PlankResult_OK;
00189     }
00190     
00191     static inline ValueType getNullValue() throw()
00192     {
00193         static ValueType null = ValueType();
00194         return null;
00195     }
00196     
00197     ValueType* popInternal (ValueType* value) throw()
00198     {
00199         ValueType* valuePtr = 0;
00200         
00201         PlankLockFreeQueueElementRef element;
00202         ResultCode result = pl_LockFreeQueue_Pop (&liveQueue, &element);
00203         plonk_assert (result == PlankResult_OK);
00204         
00205         if (element != 0)
00206         {
00207             valuePtr = static_cast <ValueType*> (pl_LockFreeQueueElement_GetData (element));
00208             plonk_assert (valuePtr != 0);
00209             
00210             if (value != 0)
00211                 *value = *valuePtr;
00212             
00213             *valuePtr = getNullValue();
00214             
00215             result = pl_LockFreeQueue_Push (&deadQueue, element);
00216             plonk_assert (result == PlankResult_OK);
00217         }
00218         
00219 #ifndef PLONK_DEBUG
00220         (void)result;
00221 #endif
00222         
00223         return valuePtr;
00224     }
00225     
00226 };
00227 
00228 
00229 
00230 template<class ValueType>                                               
00231 class LockFreeQueueInternal<ValueType*> : public SmartPointer
00232 {
00233 public:
00234     typedef LockFreeQueue<ValueType*>        QueueType;
00235     
00236     LockFreeQueueInternal() throw()
00237     {
00238         pl_LockFreeQueue_Init (&queue);
00239     }
00240     
00241     ~LockFreeQueueInternal()
00242     {
00243         pl_LockFreeQueue_DeInit (&queue);
00244     }
00245     
00246     void push (ValueType* const value) throw()
00247     {
00248         PlankLockFreeQueueElementRef element = pl_LockFreeQueueElement_CreateAndInit();
00249         plonk_assert (element != 0);
00250         pl_LockFreeQueueElement_SetData (element, value);
00251         ResultCode result = pl_LockFreeQueue_Push (&queue, element);
00252         plonk_assert (result == PlankResult_OK);
00253 #ifndef PLONK_DEBUG
00254         (void)result;
00255 #endif
00256     }
00257     
00258     ValueType* pop() throw()
00259     {
00260         ValueType* returnValue;
00261         
00262         PlankLockFreeQueueElementRef element;
00263         ResultCode result = pl_LockFreeQueue_Pop (&queue, &element);
00264         plonk_assert (result == PlankResult_OK);
00265         
00266         if (element != 0)
00267         {
00268             returnValue = static_cast <ValueType*> (pl_LockFreeQueueElement_GetData (element));                        
00269             result = pl_LockFreeQueueElement_Destroy (element);
00270             plonk_assert (result == PlankResult_OK);
00271         }
00272         
00273 #ifndef PLONK_DEBUG
00274         (void)result;
00275 #endif
00276         
00277         return returnValue;
00278     }
00279     
00280     template<class OtherType>
00281     inline bool pop (OtherType& value)
00282     {
00283         return value = pop() ? true : false;
00284     }
00285     
00286     void clear() throw()
00287     {
00288         ResultCode result = pl_LockFreeQueue_Clear (&queue);
00289         plonk_assert (result == PlankResult_OK);
00290 #ifndef PLONK_DEBUG
00291         (void)result;
00292 #endif
00293     }
00294     
00295     void clearCache() throw()
00296     {
00297         // not applicable
00298     }
00299     
00300     void clearAll() throw()
00301     {
00302         clear();
00303     }
00304         
00305     int length() throw()
00306     {
00307         return pl_LockFreeQueue_GetSize (&queue);
00308     }
00309 
00310     friend class LockFreeQueue<ValueType*>;
00311     
00312 private:
00313     PLONK_ALIGN(16) PlankLockFreeQueue queue;
00314 };
00315 
00316 
00317 
00318 //------------------------------------------------------------------------------
00319 
00321 template<class ValueType>                                               
00322 class LockFreeQueue : public SmartPointerContainer<LockFreeQueueInternal<ValueType> >
00323 {
00324 public:
00325     typedef LockFreeQueueInternal<ValueType>    Internal;
00326     typedef SmartPointerContainer<Internal>     Base;
00327     typedef WeakPointerContainer<LockFreeQueue> Weak;    
00328 
00329     inline LockFreeQueue()
00330     :   Base (new Internal())
00331     {
00332     }
00333     
00334     inline explicit LockFreeQueue (Internal* internalToUse) throw() 
00335         :       Base (internalToUse)
00336         {
00337         }
00338     
00342     static LockFreeQueue fromWeak (Weak const& weak) throw()
00343     {
00344         return weak.fromWeak();
00345     }    
00346     
00348     inline LockFreeQueue (LockFreeQueue const& copy) throw()
00349     :   Base (static_cast<Base const&> (copy))
00350     {
00351     }
00352     
00353     inline LockFreeQueue (Dynamic const& other) throw()
00354     :   Base (other.as<LockFreeQueue>().getInternal())
00355     {
00356     }    
00357     
00359     inline LockFreeQueue& operator= (LockFreeQueue const& other) throw()
00360         {
00361                 if (this != &other)
00362             this->setInternal (other.getInternal());
00363         
00364         return *this;
00365         }
00366     
00367     inline void push (ValueType const& value) throw()
00368     {
00369         this->getInternal()->push (value);
00370     }
00371     
00372     inline ValueType pop() throw()
00373     {
00374         return this->getInternal()->pop();
00375     }
00376     
00377     template<class OtherType>
00378     inline bool pop (OtherType& value)
00379     {
00380         return this->getInternal()->pop (value);
00381     }
00382     
00383     inline void clear() throw()
00384     {
00385         return this->getInternal()->clear();
00386     }
00387     
00388     inline void clearCache() throw()
00389     {
00390         return this->getInternal()->clearCache();
00391     }
00392     
00393     inline void clearAll() throw()
00394     {
00395         return this->getInternal()->clearAll();
00396     }
00397     
00398     void increaseCache (const int count) throw()
00399     {
00400         // dirty hack for now..
00401         
00402         plonk_assert (count > 0);
00403         
00404         for (int i = 0; i < count; ++i)
00405             push (ValueType());
00406         
00407         clear(); // moves items to the dead queue
00408     }
00409     
00410     inline int length() throw()
00411     {
00412         return this->getInternal()->length();
00413     }
00414     
00415     PLONK_OBJECTARROWOPERATOR(LockFreeQueue);
00416 
00417 };
00418 
00419 
00420 #endif // PLONK_LOCKFREEQUEUE_H
 All Classes Functions Typedefs Enumerations Enumerator Properties