1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/dom/workers/Queue.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,202 @@ 1.4 +/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#ifndef mozilla_dom_workers_queue_h__ 1.10 +#define mozilla_dom_workers_queue_h__ 1.11 + 1.12 +#include "Workers.h" 1.13 + 1.14 +#include "mozilla/Mutex.h" 1.15 +#include "nsTArray.h" 1.16 + 1.17 +BEGIN_WORKERS_NAMESPACE 1.18 + 1.19 +template <typename T, int TCount> 1.20 +struct StorageWithTArray 1.21 +{ 1.22 + typedef nsAutoTArray<T, TCount> StorageType; 1.23 + 1.24 + static void Reverse(StorageType& aStorage) 1.25 + { 1.26 + uint32_t length = aStorage.Length(); 1.27 + for (uint32_t index = 0; index < length / 2; index++) { 1.28 + uint32_t reverseIndex = length - 1 - index; 1.29 + 1.30 + T t1 = aStorage.ElementAt(index); 1.31 + T t2 = aStorage.ElementAt(reverseIndex); 1.32 + 1.33 + aStorage.ReplaceElementsAt(index, 1, t2); 1.34 + aStorage.ReplaceElementsAt(reverseIndex, 1, t1); 1.35 + } 1.36 + } 1.37 + 1.38 + static bool IsEmpty(const StorageType& aStorage) 1.39 + { 1.40 + return !!aStorage.IsEmpty(); 1.41 + } 1.42 + 1.43 + static bool Push(StorageType& aStorage, const T& aEntry) 1.44 + { 1.45 + return !!aStorage.AppendElement(aEntry); 1.46 + } 1.47 + 1.48 + static bool Pop(StorageType& aStorage, T& aEntry) 1.49 + { 1.50 + if (IsEmpty(aStorage)) { 1.51 + return false; 1.52 + } 1.53 + 1.54 + uint32_t index = aStorage.Length() - 1; 1.55 + aEntry = aStorage.ElementAt(index); 1.56 + aStorage.RemoveElementAt(index); 1.57 + return true; 1.58 + } 1.59 + 1.60 + static void Clear(StorageType& aStorage) 1.61 + { 1.62 + aStorage.Clear(); 1.63 + } 1.64 + 1.65 + static void Compact(StorageType& aStorage) 1.66 + { 1.67 + aStorage.Compact(); 1.68 + } 1.69 +}; 1.70 + 1.71 +class LockingWithMutex 1.72 +{ 1.73 + mozilla::Mutex mMutex; 1.74 + 1.75 +protected: 1.76 + LockingWithMutex() 1.77 + : mMutex("LockingWithMutex::mMutex") 1.78 + { } 1.79 + 1.80 + void Lock() 1.81 + { 1.82 + mMutex.Lock(); 1.83 + } 1.84 + 1.85 + void Unlock() 1.86 + { 1.87 + mMutex.Unlock(); 1.88 + } 1.89 + 1.90 + class AutoLock 1.91 + { 1.92 + LockingWithMutex& mHost; 1.93 + 1.94 + public: 1.95 + AutoLock(LockingWithMutex& aHost) 1.96 + : mHost(aHost) 1.97 + { 1.98 + mHost.Lock(); 1.99 + } 1.100 + 1.101 + ~AutoLock() 1.102 + { 1.103 + mHost.Unlock(); 1.104 + } 1.105 + }; 1.106 + 1.107 + friend class AutoLock; 1.108 +}; 1.109 + 1.110 +class NoLocking 1.111 +{ 1.112 +protected: 1.113 + void Lock() 1.114 + { } 1.115 + 1.116 + void Unlock() 1.117 + { } 1.118 + 1.119 + class AutoLock 1.120 + { 1.121 + public: 1.122 + AutoLock(NoLocking& aHost) 1.123 + { } 1.124 + 1.125 + ~AutoLock() 1.126 + { } 1.127 + }; 1.128 +}; 1.129 + 1.130 +template <typename T, 1.131 + int TCount = 256, 1.132 + class LockingPolicy = NoLocking, 1.133 + class StoragePolicy = StorageWithTArray<T, TCount % 2 ? 1.134 + TCount / 2 + 1 : 1.135 + TCount / 2> > 1.136 +class Queue : public LockingPolicy 1.137 +{ 1.138 + typedef typename StoragePolicy::StorageType StorageType; 1.139 + typedef typename LockingPolicy::AutoLock AutoLock; 1.140 + 1.141 + StorageType mStorage1; 1.142 + StorageType mStorage2; 1.143 + 1.144 + StorageType* mFront; 1.145 + StorageType* mBack; 1.146 + 1.147 +public: 1.148 + Queue() 1.149 + : mFront(&mStorage1), mBack(&mStorage2) 1.150 + { } 1.151 + 1.152 + bool IsEmpty() 1.153 + { 1.154 + AutoLock lock(*this); 1.155 + return StoragePolicy::IsEmpty(*mFront) && 1.156 + StoragePolicy::IsEmpty(*mBack); 1.157 + } 1.158 + 1.159 + bool Push(const T& aEntry) 1.160 + { 1.161 + AutoLock lock(*this); 1.162 + return StoragePolicy::Push(*mBack, aEntry); 1.163 + } 1.164 + 1.165 + bool Pop(T& aEntry) 1.166 + { 1.167 + AutoLock lock(*this); 1.168 + if (StoragePolicy::IsEmpty(*mFront)) { 1.169 + StoragePolicy::Compact(*mFront); 1.170 + StoragePolicy::Reverse(*mBack); 1.171 + StorageType* tmp = mFront; 1.172 + mFront = mBack; 1.173 + mBack = tmp; 1.174 + } 1.175 + return StoragePolicy::Pop(*mFront, aEntry); 1.176 + } 1.177 + 1.178 + void Clear() 1.179 + { 1.180 + AutoLock lock(*this); 1.181 + StoragePolicy::Clear(*mFront); 1.182 + StoragePolicy::Clear(*mBack); 1.183 + } 1.184 + 1.185 + // XXX Do we need this? 1.186 + void Lock() 1.187 + { 1.188 + LockingPolicy::Lock(); 1.189 + } 1.190 + 1.191 + // XXX Do we need this? 1.192 + void Unlock() 1.193 + { 1.194 + LockingPolicy::Unlock(); 1.195 + } 1.196 + 1.197 +private: 1.198 + // Queue is not copyable. 1.199 + Queue(const Queue&); 1.200 + Queue & operator=(const Queue&); 1.201 +}; 1.202 + 1.203 +END_WORKERS_NAMESPACE 1.204 + 1.205 +#endif /* mozilla_dom_workers_queue_h__ */