![]() |
pl-nk v0.4.5
Plonk|Plink|Plank are a set of cross-platform C/C++ frameworks for audio software development
|
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_COLLECTIONS_H 00040 #define PLONK_COLLECTIONS_H 00041 00042 #include "../core/plonk_CoreForwardDeclarations.h" 00043 #include "plonk_ContainerForwardDeclarations.h" 00044 #include "plonk_DynamicContainer.h" 00045 00046 #include "../core/plonk_SmartPointer.h" 00047 #include "../core/plonk_WeakPointer.h" 00048 #include "../core/plonk_Thread.h" 00049 #include "plonk_ObjectArray.h" 00050 #include "plonk_SimpleArray.h" 00051 00052 00053 template<class ValueType, class KeyType> 00054 class DictionaryInternal : public SmartPointer 00055 { 00056 public: 00057 typedef Dictionary<ValueType,KeyType> Container; 00058 00059 DictionaryInternal() throw() 00060 { 00061 } 00062 00063 DictionaryInternal (const int initialCapacity) throw() 00064 : values (ObjectArray<ValueType>::emptyWithAllocatedSize (initialCapacity)), 00065 keys (ObjectArray<KeyType>::emptyWithAllocatedSize (initialCapacity)) 00066 { 00067 } 00068 00069 ~DictionaryInternal() 00070 { 00071 } 00072 00073 ObjectArray<ValueType>& getValues() throw() 00074 { 00075 return values; 00076 } 00077 00078 ObjectArray<KeyType>& getKeys() throw() 00079 { 00080 return keys; 00081 } 00082 00083 const ObjectArray<ValueType>& getValues() const throw() 00084 { 00085 return values; 00086 } 00087 00088 const ObjectArray<KeyType>& getKeys() const throw() 00089 { 00090 return keys; 00091 } 00092 00093 private: 00094 ObjectArray<ValueType> values; 00095 ObjectArray<KeyType> keys; 00096 }; 00097 00098 00099 //------------------------------------------------------------------------------ 00100 00102 template<class ValueType, class KeyType> 00103 class KeyValuePair 00104 { 00105 public: 00106 KeyValuePair() throw() 00107 { 00108 } 00109 00110 KeyValuePair (KeyType const& key, ValueType const& value) throw() 00111 : v (value), 00112 k (key) 00113 { 00114 } 00115 00116 KeyValuePair (KeyValuePair const& copy) throw() 00117 : v (copy.v), 00118 k (copy.k) 00119 { 00120 } 00121 00122 KeyValuePair operator= (KeyValuePair const& other) throw() 00123 { 00124 if (this != &other) 00125 { 00126 v = other.v; 00127 k = other.k; 00128 } 00129 00130 return *this; 00131 } 00132 00133 const KeyType& getKey() const throw() { return k; } 00134 const ValueType& getValue() const throw() { return v; } 00135 00136 private: 00137 ValueType v; 00138 KeyType k; 00139 }; 00140 00141 00142 //------------------------------------------------------------------------------ 00143 00144 00150 template<class ValueType, class KeyType> 00151 class Dictionary : public SmartPointerContainer< DictionaryInternal<ValueType,KeyType> > 00152 { 00153 public: 00154 typedef KeyValuePair<ValueType,KeyType> KeyValuePairType; 00155 typedef ObjectArray<KeyValuePairType> KeyValuePairArrayType; 00156 00157 typedef DictionaryInternal<ValueType,KeyType> Internal; 00158 typedef SmartPointerContainer<Internal> Base; 00159 typedef WeakPointerContainer<Dictionary> Weak; 00160 00162 Dictionary() throw() 00163 : Base (new Internal()) 00164 { 00165 } 00166 00167 explicit Dictionary (const int initialCapacity) throw() 00168 : Base (new Internal (initialCapacity)) 00169 { 00170 } 00171 00172 explicit Dictionary (Internal* internalToUse) throw() 00173 : Base (internalToUse) 00174 { 00175 } 00176 00177 Dictionary (Dictionary const& copy) throw() 00178 : Base (static_cast<Base const&> (copy)) 00179 { 00180 } 00181 00182 Dictionary (Dynamic const& other) throw() 00183 : Base (other.as<Dictionary>().getInternal()) 00184 { 00185 } 00186 00188 Dictionary& operator= (Dictionary const& other) throw() 00189 { 00190 if (this != &other) 00191 this->setInternal (other.getInternal());//this->setInternal (other.containerCopy().getInternal()); 00192 00193 return *this; 00194 } 00195 00199 static Dictionary fromWeak (Weak const& weak) throw() 00200 { 00201 return weak.fromWeak(); 00202 } 00203 00204 static const Dictionary& getNull() throw() 00205 { 00206 static Dictionary null; 00207 return null; 00208 } 00209 00211 Dictionary (KeyValuePairArrayType const& pairs) throw() 00212 : Base (new Internal()) 00213 { 00214 put (pairs); 00215 } 00216 00218 const ObjectArray<ValueType>& getValues() const throw() 00219 { 00220 return this->getInternal()->getValues(); 00221 } 00222 00224 const ObjectArray<KeyType>& getKeys() const throw() 00225 { 00226 return this->getInternal()->getKeys(); 00227 } 00228 00230 KeyValuePairArrayType getPairs() const throw() 00231 { 00232 KeyValuePairArrayType pairs = KeyValuePairArrayType::withSize (length()); 00233 00234 for (int i = 0; i < length(); ++i) 00235 pairs[i] = KeyValuePairType (key (i), value (i)); 00236 00237 return pairs; 00238 } 00239 00244 ValueType put (KeyType const& key, ValueType const& value) throw() 00245 { 00246 ObjectArray<ValueType>& values = this->getInternal()->getValues(); 00247 ObjectArray<KeyType>& keys = this->getInternal()->getKeys(); 00248 00249 int index = keys.indexOf (key); 00250 00251 if (index >= 0) 00252 { 00253 ValueType oldValue = values[index]; 00254 values.put (index, value); 00255 return oldValue; 00256 } 00257 else 00258 { 00259 keys.add (key); 00260 values.add (value); 00261 return ObjectArray<ValueType>::getNullObject(); 00262 } 00263 } 00264 00265 ValueType put (KeyValuePairType const& pair) throw() 00266 { 00267 return put (pair.getKey(), pair.getValue()); 00268 } 00269 00270 void put (KeyValuePairArrayType const& pairs) throw() 00271 { 00272 for (int i = 0; i < pairs.length(); ++i) 00273 put (pairs[i]); 00274 } 00275 00276 bool containsKey (KeyType const& key) throw() 00277 { 00278 return this->getInternal()->getKeys().contains (key); 00279 } 00280 00281 bool containsValue (ValueType const& value) throw() 00282 { 00283 return this->getInternal()->getValues().contains (value); 00284 } 00285 00288 ValueType& at (KeyType const& key) throw() 00289 { 00290 ObjectArray<ValueType>& values = this->getInternal()->getValues(); 00291 ObjectArray<KeyType>& keys = this->getInternal()->getKeys(); 00292 00293 const int index = keys.indexOf (key); 00294 return values[index]; 00295 } 00296 00299 const ValueType& at (KeyType const& key) const throw() 00300 { 00301 ObjectArray<ValueType> const& values = getValues(); 00302 ObjectArray<KeyType> const& keys = getKeys(); 00303 00304 const int index = keys.indexOf (key); 00305 return values[index]; 00306 } 00307 00308 ValueType& atIndex (const int index) throw() 00309 { 00310 ObjectArray<ValueType>& values = this->getInternal()->getValues(); 00311 return values[index]; 00312 } 00313 00314 const ValueType& atIndex (const int index) const throw() 00315 { 00316 ObjectArray<ValueType> const& values = getValues(); 00317 return values[index]; 00318 } 00319 00320 ValueType& atIndexUnchecked (const int index) throw() 00321 { 00322 ObjectArray<ValueType>& values = this->getInternal()->getValues(); 00323 return values.atUnchecked (index); 00324 } 00325 00326 const ValueType& atIndexUnchecked (const int index) const throw() 00327 { 00328 ObjectArray<ValueType> const& values = getValues(); 00329 return values.atUnchecked (index); 00330 } 00331 00334 ValueType& operator[] (KeyType const& key) throw() 00335 { 00336 ObjectArray<ValueType>& values = this->getInternal()->getValues(); 00337 ObjectArray<KeyType>& keys = this->getInternal()->getKeys(); 00338 00339 const int index = keys.indexOf (key); 00340 return values[index]; 00341 } 00342 00345 const ValueType& operator[] (KeyType const& key) const throw() 00346 { 00347 ObjectArray<ValueType> const& values = getValues(); 00348 ObjectArray<KeyType> const& keys = getKeys(); 00349 00350 const int index = keys.indexOf (key); 00351 return values[index]; 00352 } 00353 00356 ValueType remove (KeyType const& key) throw() 00357 { 00358 ObjectArray<ValueType>& values = this->getInternal()->getValues(); 00359 ObjectArray<KeyType>& keys = this->getInternal()->getKeys(); 00360 00361 const int index = keys.indexOf (key); 00362 00363 if (index >= 0) 00364 { 00365 ValueType removed = values[index]; 00366 keys.remove (index); 00367 values.remove (index); 00368 return removed; 00369 } 00370 else 00371 { 00372 return ObjectArray<ValueType>::getNullObject(); 00373 } 00374 } 00375 00377 const KeyType& keyForValue (ValueType const& value) const 00378 { 00379 ObjectArray<ValueType> const& values = getValues(); 00380 ObjectArray<KeyType> const& keys = getKeys(); 00381 00382 const int index = values.indexOf (value); 00383 return keys[index]; 00384 } 00385 00387 KeyType& key (const int index) throw() 00388 { 00389 return getKeys()[index]; 00390 } 00391 00393 ValueType& value (const int index) throw() 00394 { 00395 return getValues()[index]; 00396 } 00397 00399 const KeyType& key (const int index) const throw() 00400 { 00401 return getKeys()[index]; 00402 } 00403 00405 const ValueType& value (const int index) const throw() 00406 { 00407 return getValues()[index]; 00408 } 00409 00411 int length() const throw() 00412 { 00413 ObjectArray<ValueType> const& values = getValues(); 00414 00415 plonk_assert (values.length() == getKeys().length()); // these should be the same length! 00416 00417 return values.length(); 00418 } 00419 00421 int size() const throw() 00422 { 00423 ObjectArray<ValueType> const& values = getValues(); 00424 ObjectArray<KeyType> const& keys = getKeys(); 00425 00426 plonk_assert (values.size() == keys.size()); // these should be the same size! 00427 00428 return values.size(); 00429 } 00430 00431 PLONK_OBJECTARROWOPERATOR(Dictionary); 00432 00433 }; 00434 00436 00438 // The SmartPointerContainer and ScopedPointerContainer are thread-safe in terms 00439 // of copying the object but not actions on the object. This class holds another 00440 // container object and ensures thread-safe manipulations on the object. 00441 // The container must respond to the -> operator and implement copy() which 00442 // should return a deep object of the object. */ 00443 // 00444 //template<class Container> 00445 //class ThreadSafeAccess 00446 //{ 00447 //public: 00448 // typedef typename Container::Internal ContainerInternal; 00449 // 00450 // ThreadSafeAccess() throw() 00451 // { 00452 // } 00453 // 00454 // ~ThreadSafeAccess() 00455 // { 00456 // } 00457 // 00458 // explicit ThreadSafeAccess (Container const& initialValue) throw() 00459 // : read (initialValue.copy()), 00460 // write (initialValue.copy()) 00461 // { 00462 // } 00463 // 00464 // const Container& getRead() throw() 00465 // { 00466 // return read; 00467 // } 00468 // 00469 // bool checkout() throw() 00470 // { 00471 // const Threading::ID threadID = Threading::getCurrentThreadID(); 00472 // 00473 // if (writingThread.compareAndSwap (0, threadID)) 00474 // { 00475 // write = read.copy(); 00476 // return true; 00477 // } 00478 // 00479 // return false; 00480 // } 00481 // 00482 // bool commit() throw() 00483 // { 00484 // const Threading::ID threadID = Threading::getCurrentThreadID(); 00485 // 00486 // if (writingThread == threadID) 00487 // { 00488 // read.swapWith (write); 00489 // writingThread = 0; 00490 // return true; 00491 // } 00492 // 00493 // return false; 00494 // } 00495 // 00496 // Container operator->() throw() 00497 // { 00498 // plonk_assert (writingThread == Threading::getCurrentThreadID()); 00499 // return write; 00500 // } 00501 // 00502 // const Container& operator*() const throw() 00503 // { 00504 // return read; 00505 // } 00506 // 00507 // 00508 // 00509 //private: 00510 // Container read; 00511 // Container write; 00512 // AtomicValue<Threading::ID> writingThread; 00513 //}; 00514 00515 //template<class Container, int NumThreads> 00516 //class ThreadSafeAccess 00517 //{ 00518 //public: 00519 // typedef typename Container::Internal ContainerInternal; 00520 // typedef ObjectArray<Container> Containers; 00521 // typedef AtomicValue<Threading::ID> AtomicThreadID; 00522 // typedef ObjectArray<AtomicThreadID> Threads; 00523 // 00524 // ThreadSafeAccess() throw() 00525 // : containers (Containers::withSize (NumThreads)), 00526 // threads (Threads::withSize (NumThreads)) 00527 // { 00528 // clearThreads(); 00529 // threads.atUnchecked (0) = Threading::getCurrentThreadID(); 00530 // } 00531 // 00532 // ~ThreadSafeAccess() 00533 // { 00534 // } 00535 // 00536 // explicit ThreadSafeAccess (Container const& initialValue) throw() 00537 // : containers (Containers::withSize (NumThreads)), 00538 // threads (Threads::withSize (NumThreads)) 00539 // { 00540 // for (int i = 0; i < NumThreads; ++i) 00541 // containers.atUnchecked (i) = initialValue.copy(); 00542 // 00543 // clearThreads(); 00544 // threads.atUnchecked (0) = Threading::getCurrentThreadID(); 00545 // } 00546 // 00547 // Container operator->() throw() 00548 // { 00549 // const Threading::ID threadID = Threading::getCurrentThreadID(); 00550 // 00551 // if (threads.contains (threadID)) 00552 // { 00553 // return containers.atUnchecked (threads.indexOf (threadID)); 00554 // } 00555 // else 00556 // { 00557 // AtomicThreadID* const ids = threads.getArray(); 00558 // 00559 // for (int i = 0; i < NumThreads; ++i) 00560 // if (ids[i].compareAndSwap (0, threadID)) 00561 // return containers.atUnchecked (i); 00562 // } 00563 // 00564 // plonk_assertfalse; // too many threads trying to access the data 00565 // return Container::getNull(); 00566 // } 00567 // 00568 // void releaseThread() throw() 00569 // { 00570 // const Threading::ID threadID = Threading::getCurrentThreadID(); 00571 // AtomicThreadID* const ids = threads.getArray(); 00572 // 00573 // for (int i = 0; i < NumThreads; ++i) 00574 // if (ids[i].compareAndSwap (threadID, 0)) 00575 // return; 00576 // } 00577 // 00578 //private: 00579 // Containers containers; 00580 // Threads threads; 00581 // 00582 // void clearThreads() throw() 00583 // { 00584 // for (int i = 0; i < NumThreads; ++i) 00585 // threads.atUnchecked (i) = 0; 00586 // } 00587 //}; 00588 00589 00590 00591 #endif // PLONK_COLLECTIONS_H