michael@0: /* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef mozilla_dom_workers_queue_h__ michael@0: #define mozilla_dom_workers_queue_h__ michael@0: michael@0: #include "Workers.h" michael@0: michael@0: #include "mozilla/Mutex.h" michael@0: #include "nsTArray.h" michael@0: michael@0: BEGIN_WORKERS_NAMESPACE michael@0: michael@0: template michael@0: struct StorageWithTArray michael@0: { michael@0: typedef nsAutoTArray StorageType; michael@0: michael@0: static void Reverse(StorageType& aStorage) michael@0: { michael@0: uint32_t length = aStorage.Length(); michael@0: for (uint32_t index = 0; index < length / 2; index++) { michael@0: uint32_t reverseIndex = length - 1 - index; michael@0: michael@0: T t1 = aStorage.ElementAt(index); michael@0: T t2 = aStorage.ElementAt(reverseIndex); michael@0: michael@0: aStorage.ReplaceElementsAt(index, 1, t2); michael@0: aStorage.ReplaceElementsAt(reverseIndex, 1, t1); michael@0: } michael@0: } michael@0: michael@0: static bool IsEmpty(const StorageType& aStorage) michael@0: { michael@0: return !!aStorage.IsEmpty(); michael@0: } michael@0: michael@0: static bool Push(StorageType& aStorage, const T& aEntry) michael@0: { michael@0: return !!aStorage.AppendElement(aEntry); michael@0: } michael@0: michael@0: static bool Pop(StorageType& aStorage, T& aEntry) michael@0: { michael@0: if (IsEmpty(aStorage)) { michael@0: return false; michael@0: } michael@0: michael@0: uint32_t index = aStorage.Length() - 1; michael@0: aEntry = aStorage.ElementAt(index); michael@0: aStorage.RemoveElementAt(index); michael@0: return true; michael@0: } michael@0: michael@0: static void Clear(StorageType& aStorage) michael@0: { michael@0: aStorage.Clear(); michael@0: } michael@0: michael@0: static void Compact(StorageType& aStorage) michael@0: { michael@0: aStorage.Compact(); michael@0: } michael@0: }; michael@0: michael@0: class LockingWithMutex michael@0: { michael@0: mozilla::Mutex mMutex; michael@0: michael@0: protected: michael@0: LockingWithMutex() michael@0: : mMutex("LockingWithMutex::mMutex") michael@0: { } michael@0: michael@0: void Lock() michael@0: { michael@0: mMutex.Lock(); michael@0: } michael@0: michael@0: void Unlock() michael@0: { michael@0: mMutex.Unlock(); michael@0: } michael@0: michael@0: class AutoLock michael@0: { michael@0: LockingWithMutex& mHost; michael@0: michael@0: public: michael@0: AutoLock(LockingWithMutex& aHost) michael@0: : mHost(aHost) michael@0: { michael@0: mHost.Lock(); michael@0: } michael@0: michael@0: ~AutoLock() michael@0: { michael@0: mHost.Unlock(); michael@0: } michael@0: }; michael@0: michael@0: friend class AutoLock; michael@0: }; michael@0: michael@0: class NoLocking michael@0: { michael@0: protected: michael@0: void Lock() michael@0: { } michael@0: michael@0: void Unlock() michael@0: { } michael@0: michael@0: class AutoLock michael@0: { michael@0: public: michael@0: AutoLock(NoLocking& aHost) michael@0: { } michael@0: michael@0: ~AutoLock() michael@0: { } michael@0: }; michael@0: }; michael@0: michael@0: template > michael@0: class Queue : public LockingPolicy michael@0: { michael@0: typedef typename StoragePolicy::StorageType StorageType; michael@0: typedef typename LockingPolicy::AutoLock AutoLock; michael@0: michael@0: StorageType mStorage1; michael@0: StorageType mStorage2; michael@0: michael@0: StorageType* mFront; michael@0: StorageType* mBack; michael@0: michael@0: public: michael@0: Queue() michael@0: : mFront(&mStorage1), mBack(&mStorage2) michael@0: { } michael@0: michael@0: bool IsEmpty() michael@0: { michael@0: AutoLock lock(*this); michael@0: return StoragePolicy::IsEmpty(*mFront) && michael@0: StoragePolicy::IsEmpty(*mBack); michael@0: } michael@0: michael@0: bool Push(const T& aEntry) michael@0: { michael@0: AutoLock lock(*this); michael@0: return StoragePolicy::Push(*mBack, aEntry); michael@0: } michael@0: michael@0: bool Pop(T& aEntry) michael@0: { michael@0: AutoLock lock(*this); michael@0: if (StoragePolicy::IsEmpty(*mFront)) { michael@0: StoragePolicy::Compact(*mFront); michael@0: StoragePolicy::Reverse(*mBack); michael@0: StorageType* tmp = mFront; michael@0: mFront = mBack; michael@0: mBack = tmp; michael@0: } michael@0: return StoragePolicy::Pop(*mFront, aEntry); michael@0: } michael@0: michael@0: void Clear() michael@0: { michael@0: AutoLock lock(*this); michael@0: StoragePolicy::Clear(*mFront); michael@0: StoragePolicy::Clear(*mBack); michael@0: } michael@0: michael@0: // XXX Do we need this? michael@0: void Lock() michael@0: { michael@0: LockingPolicy::Lock(); michael@0: } michael@0: michael@0: // XXX Do we need this? michael@0: void Unlock() michael@0: { michael@0: LockingPolicy::Unlock(); michael@0: } michael@0: michael@0: private: michael@0: // Queue is not copyable. michael@0: Queue(const Queue&); michael@0: Queue & operator=(const Queue&); michael@0: }; michael@0: michael@0: END_WORKERS_NAMESPACE michael@0: michael@0: #endif /* mozilla_dom_workers_queue_h__ */