tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

Queue.h (3754B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #ifndef mozilla_dom_workerinternal_Queue_h
      8 #define mozilla_dom_workerinternal_Queue_h
      9 
     10 #include "mozilla/Mutex.h"
     11 #include "nsTArray.h"
     12 
     13 namespace mozilla::dom::workerinternals {
     14 
     15 template <typename T, int TCount>
     16 struct StorageWithTArray {
     17  typedef AutoTArray<T, TCount> StorageType;
     18 
     19  static void Reverse(StorageType& aStorage) {
     20    uint32_t length = aStorage.Length();
     21    for (uint32_t index = 0; index < length / 2; index++) {
     22      uint32_t reverseIndex = length - 1 - index;
     23 
     24      T t1 = aStorage.ElementAt(index);
     25      T t2 = aStorage.ElementAt(reverseIndex);
     26 
     27      aStorage.ReplaceElementsAt(index, 1, t2);
     28      aStorage.ReplaceElementsAt(reverseIndex, 1, t1);
     29    }
     30  }
     31 
     32  static bool IsEmpty(const StorageType& aStorage) {
     33    return !!aStorage.IsEmpty();
     34  }
     35 
     36  static void Push(StorageType& aStorage, const T& aEntry) {
     37    aStorage.AppendElement(aEntry);
     38  }
     39 
     40  static bool Pop(StorageType& aStorage, T& aEntry) {
     41    if (IsEmpty(aStorage)) {
     42      return false;
     43    }
     44 
     45    aEntry = aStorage.PopLastElement();
     46    return true;
     47  }
     48 
     49  static void Clear(StorageType& aStorage) { aStorage.Clear(); }
     50 
     51  static void Compact(StorageType& aStorage) { aStorage.Compact(); }
     52 };
     53 
     54 class MOZ_CAPABILITY("mutex") LockingWithMutex {
     55  mozilla::Mutex mMutex;
     56 
     57 protected:
     58  LockingWithMutex() : mMutex("LockingWithMutex::mMutex") {}
     59 
     60  void Lock() MOZ_CAPABILITY_ACQUIRE() { mMutex.Lock(); }
     61 
     62  void Unlock() MOZ_CAPABILITY_RELEASE() { mMutex.Unlock(); }
     63 
     64  class MOZ_SCOPED_CAPABILITY AutoLock {
     65    LockingWithMutex& mHost;
     66 
     67   public:
     68    explicit AutoLock(LockingWithMutex& aHost) MOZ_CAPABILITY_ACQUIRE(aHost)
     69        : mHost(aHost) {
     70      mHost.Lock();
     71    }
     72 
     73    ~AutoLock() MOZ_CAPABILITY_RELEASE() { mHost.Unlock(); }
     74  };
     75 
     76  friend class AutoLock;
     77 };
     78 
     79 class NoLocking {
     80 protected:
     81  void Lock() {}
     82 
     83  void Unlock() {}
     84 
     85  class AutoLock {
     86   public:
     87    explicit AutoLock(NoLocking& aHost) {}
     88 
     89    ~AutoLock() = default;
     90  };
     91 };
     92 
     93 template <typename T, int TCount = 256, class LockingPolicy = NoLocking,
     94          class StoragePolicy =
     95              StorageWithTArray<T, TCount % 2 ? TCount / 2 + 1 : TCount / 2> >
     96 class Queue : public LockingPolicy {
     97  typedef typename StoragePolicy::StorageType StorageType;
     98  typedef typename LockingPolicy::AutoLock AutoLock;
     99 
    100  StorageType mStorage1;
    101  StorageType mStorage2;
    102 
    103  StorageType* mFront;
    104  StorageType* mBack;
    105 
    106 public:
    107  Queue() : mFront(&mStorage1), mBack(&mStorage2) {}
    108 
    109  bool IsEmpty() {
    110    AutoLock lock(*this);
    111    return StoragePolicy::IsEmpty(*mFront) && StoragePolicy::IsEmpty(*mBack);
    112  }
    113 
    114  void Push(const T& aEntry) {
    115    AutoLock lock(*this);
    116    StoragePolicy::Push(*mBack, aEntry);
    117  }
    118 
    119  bool Pop(T& aEntry) {
    120    AutoLock lock(*this);
    121    if (StoragePolicy::IsEmpty(*mFront)) {
    122      StoragePolicy::Compact(*mFront);
    123      StoragePolicy::Reverse(*mBack);
    124      StorageType* tmp = mFront;
    125      mFront = mBack;
    126      mBack = tmp;
    127    }
    128    return StoragePolicy::Pop(*mFront, aEntry);
    129  }
    130 
    131  void Clear() {
    132    AutoLock lock(*this);
    133    StoragePolicy::Clear(*mFront);
    134    StoragePolicy::Clear(*mBack);
    135  }
    136 
    137  // XXX Do we need this?
    138  void Lock() { LockingPolicy::Lock(); }
    139 
    140  // XXX Do we need this?
    141  void Unlock() { LockingPolicy::Unlock(); }
    142 
    143 private:
    144  // Queue is not copyable.
    145  Queue(const Queue&);
    146  Queue& operator=(const Queue&);
    147 };
    148 
    149 }  // namespace mozilla::dom::workerinternals
    150 
    151 #endif /* mozilla_dom_workerinternals_Queue_h*/