tor-browser

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

Fifo.h (5688B)


      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 js_Fifo_h
      8 #define js_Fifo_h
      9 
     10 #include <algorithm>
     11 #include <utility>
     12 
     13 #include "js/Vector.h"
     14 
     15 namespace js {
     16 
     17 // A first-in-first-out queue container type. Fifo calls constructors and
     18 // destructors of all elements added so non-PODs may be used safely. |Fifo|
     19 // stores the first |MinInlineCapacity| elements in-place before resorting to
     20 // dynamic allocation.
     21 //
     22 // T requirements:
     23 //  - Either movable or copyable.
     24 // MinInlineCapacity requirements:
     25 //  - Must be even.
     26 // AllocPolicy:
     27 //  - see "Allocation policies" in AllocPolicy.h
     28 //
     29 // The vector template description is variadic to handle the differences
     30 // between GCVector and Vector in template parameters.
     31 template <typename T, size_t MinInlineCapacity = 0,
     32          class AllocPolicy = TempAllocPolicy,
     33          template <typename, size_t, class, typename...> class VectorType =
     34              Vector>
     35 class Fifo {
     36  static_assert(MinInlineCapacity % 2 == 0, "MinInlineCapacity must be even!");
     37 
     38 protected:
     39  // An element A is "younger" than an element B if B was inserted into the
     40  // |Fifo| before A was.
     41  //
     42  // Invariant 1: Every element within |front_| is older than every element
     43  // within |rear_|.
     44  // Invariant 2: Entries within |front_| are sorted from younger to older.
     45  // Invariant 3: Entries within |rear_| are sorted from older to younger.
     46  // Invariant 4: If the |Fifo| is not empty, then |front_| is not empty.
     47  VectorType<T, MinInlineCapacity / 2, AllocPolicy> front_;
     48  VectorType<T, MinInlineCapacity / 2, AllocPolicy> rear_;
     49 
     50 private:
     51  // Maintain invariants after adding or removing entries.
     52  void fixup() {
     53    if (front_.empty() && !rear_.empty()) {
     54      front_.swap(rear_);
     55      std::reverse(front_.begin(), front_.end());
     56    }
     57  }
     58 
     59 public:
     60  explicit Fifo(AllocPolicy alloc = AllocPolicy())
     61      : front_(alloc), rear_(alloc) {}
     62 
     63  Fifo(Fifo&& rhs)
     64      : front_(std::move(rhs.front_)), rear_(std::move(rhs.rear_)) {}
     65 
     66  Fifo& operator=(Fifo&& rhs) {
     67    MOZ_ASSERT(&rhs != this, "self-move disallowed");
     68    this->~Fifo();
     69    new (this) Fifo(std::move(rhs));
     70    return *this;
     71  }
     72 
     73  Fifo(const Fifo&) = delete;
     74  Fifo& operator=(const Fifo&) = delete;
     75 
     76  size_t length() const {
     77    MOZ_ASSERT_IF(rear_.length() > 0, front_.length() > 0);  // Invariant 4.
     78    return front_.length() + rear_.length();
     79  }
     80 
     81  bool empty() const {
     82    MOZ_ASSERT_IF(rear_.length() > 0, front_.length() > 0);  // Invariant 4.
     83    return front_.empty();
     84  }
     85 
     86  // Iterator from oldest to yongest element.
     87  struct ConstIterator {
     88    const Fifo& self_;
     89    size_t idx_;
     90 
     91    ConstIterator(const Fifo& self, size_t idx) : self_(self), idx_(idx) {}
     92 
     93    ConstIterator& operator++() {
     94      ++idx_;
     95      return *this;
     96    }
     97 
     98    const T& operator*() const {
     99      // Iterate front in reverse, then rear.
    100      size_t split = self_.front_.length();
    101      return (idx_ < split) ? self_.front_[(split - 1) - idx_]
    102                            : self_.rear_[idx_ - split];
    103    }
    104 
    105    bool operator!=(const ConstIterator& other) const {
    106      return (&self_ != &other.self_) || (idx_ != other.idx_);
    107    }
    108  };
    109 
    110  ConstIterator begin() const { return ConstIterator(*this, 0); }
    111 
    112  ConstIterator end() const { return ConstIterator(*this, length()); }
    113 
    114  // Push an element to the back of the queue. This method can take either a
    115  // |const T&| or a |T&&|.
    116  template <typename U>
    117  [[nodiscard]] bool pushBack(U&& u) {
    118    if (!rear_.append(std::forward<U>(u))) {
    119      return false;
    120    }
    121    fixup();
    122    return true;
    123  }
    124 
    125  // Construct a T in-place at the back of the queue.
    126  template <typename... Args>
    127  [[nodiscard]] bool emplaceBack(Args&&... args) {
    128    if (!rear_.emplaceBack(std::forward<Args>(args)...)) {
    129      return false;
    130    }
    131    fixup();
    132    return true;
    133  }
    134 
    135  // Construct a T in-place at the front of the queue,
    136  // making it the next to be popped off.
    137  template <typename... Args>
    138  [[nodiscard]] bool emplaceFront(Args&&... args) {
    139    return front_.emplaceBack(std::forward<Args>(args)...);
    140  }
    141 
    142  // Access the element at the front of the queue.
    143  T& front() {
    144    MOZ_ASSERT(!empty());
    145    return front_.back();
    146  }
    147  const T& front() const {
    148    MOZ_ASSERT(!empty());
    149    return front_.back();
    150  }
    151 
    152  // Remove the front element from the queue.
    153  void popFront() {
    154    MOZ_ASSERT(!empty());
    155    front_.popBack();
    156    fixup();
    157  }
    158 
    159  // Convenience utility.
    160  T popCopyFront() {
    161    T ret = front();
    162    popFront();
    163    return ret;
    164  }
    165 
    166  // Clear all elements from the queue.
    167  void clear() {
    168    front_.clear();
    169    rear_.clear();
    170  }
    171 
    172  // Clear all elements for which the given predicate returns 'true'. Return
    173  // the number of elements removed.
    174  template <class Pred>
    175  size_t eraseIf(Pred pred) {
    176    size_t frontLength = front_.length();
    177    front_.eraseIf(pred);
    178    size_t erased = frontLength - front_.length();
    179 
    180    size_t rearLength = rear_.length();
    181    rear_.eraseIf(pred);
    182    erased += rearLength - rear_.length();
    183 
    184    fixup();
    185    return erased;
    186  }
    187 
    188  size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
    189    return front_.sizeOfExcludingThis(mallocSizeOf) +
    190           rear_.sizeOfExcludingThis(mallocSizeOf);
    191  }
    192  size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
    193    return mallocSizeOf(this) + sizeOfExcludingThis(mallocSizeOf);
    194  }
    195 };
    196 
    197 }  // namespace js
    198 
    199 #endif /* js_Fifo_h */