tor-browser

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

CacheInvalidator.h (4491B)


      1 /* -*- Mode: C++; tab-width: 13; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=13 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_CACHE_INVALIDATOR_H_
      8 #define MOZILLA_CACHE_INVALIDATOR_H_
      9 
     10 #include <cstddef>  // nullptr_t
     11 #include <memory>
     12 #include <optional>
     13 #include <vector>
     14 
     15 #include "DmdStdContainers.h"
     16 #include "mozilla/Assertions.h"
     17 
     18 // -
     19 
     20 namespace mozilla {
     21 
     22 class AbstractCache;
     23 
     24 // -
     25 
     26 class CacheInvalidator {
     27  friend class AbstractCache;
     28 
     29 private:
     30  mutable webgl::dmd_unordered_set<AbstractCache*> mCaches;
     31 
     32 public:
     33  virtual ~CacheInvalidator() {
     34    // It's actually generally unsafe to wait until now to invalidate caches,
     35    // because when used as a mixin, this dtor is called after the dtor for the
     36    // derived class. This means that if the derived class holds a cache (or is
     37    // a cache!), OnInvalidate() will be called on a destroyed object.
     38    // MOZ_ASSERT(!mCaches);
     39    InvalidateCaches();
     40  }
     41 
     42  void InvalidateCaches() const;
     43 
     44  // -
     45 
     46  size_t SizeOfExcludingThis(mozilla::MallocSizeOf mso) const {
     47    return mCaches.SizeOfExcludingThis(mso);
     48  }
     49 };
     50 
     51 // -
     52 
     53 class AbstractCache {
     54  using InvalidatorListT = std::vector<const CacheInvalidator*>;
     55 
     56 private:
     57  InvalidatorListT mInvalidators;
     58 
     59 public:
     60  AbstractCache() = default;
     61 
     62  explicit AbstractCache(InvalidatorListT&& invalidators) {
     63    ResetInvalidators(std::move(invalidators));
     64  }
     65 
     66  virtual ~AbstractCache() { ResetInvalidators({}); }
     67 
     68 public:
     69  virtual void OnInvalidate() = 0;
     70 
     71  void ResetInvalidators(InvalidatorListT&&);
     72  void AddInvalidator(const CacheInvalidator&);
     73 };
     74 
     75 // -
     76 
     77 template <typename T>
     78 class CacheMaybe : public AbstractCache {
     79  std::optional<T> mVal;
     80 
     81 public:
     82  CacheMaybe& operator=(std::optional<T>&& rhs) {
     83    mVal.swap(rhs);
     84    rhs.reset();
     85    return *this;
     86  }
     87 
     88  template <typename U>
     89  CacheMaybe& operator=(U&& rhs) {
     90    mVal.emplace(std::move(rhs));
     91    return *this;
     92  }
     93 
     94  CacheMaybe& operator=(std::nullptr_t) {
     95    mVal.reset();
     96    return *this;
     97  }
     98 
     99  void OnInvalidate() override {
    100    *this = {};
    101    ResetInvalidators({});
    102  }
    103 
    104  explicit operator bool() const { return bool(mVal); }
    105  T* get() const { return mVal ? &*mVal : nullptr; }
    106  T* operator->() const { return get(); }
    107 };
    108 
    109 // -
    110 
    111 template <typename KeyT, typename ValueT>
    112 class CacheWeakMap final {
    113  class Entry final : public AbstractCache {
    114   public:
    115    CacheWeakMap& mParent;
    116    const KeyT mKey;
    117    const ValueT mValue;
    118 
    119    Entry(CacheWeakMap& parent, const KeyT& key, ValueT&& value)
    120        : mParent(parent), mKey(key), mValue(std::move(value)) {}
    121 
    122    void OnInvalidate() override {
    123      const auto erased = mParent.mMap.erase(&mKey);
    124      MOZ_ALWAYS_TRUE(erased == 1);
    125    }
    126  };
    127 
    128  struct DerefHash final {
    129    size_t operator()(const KeyT* const a) const {
    130      return std::hash<KeyT>()(*a);
    131    }
    132  };
    133  struct DerefEqual final {
    134    bool operator()(const KeyT* const a, const KeyT* const b) const {
    135      return *a == *b;
    136    }
    137  };
    138 
    139  using MapT = webgl::dmd_unordered_map<const KeyT*, std::unique_ptr<Entry>,
    140                                        DerefHash, DerefEqual>;
    141  MapT mMap;
    142 
    143 public:
    144  size_t SizeOfExcludingThis(mozilla::MallocSizeOf mso) const {
    145    return mMap.SizeOfExcludingThis(mso);
    146  }
    147 
    148  std::unique_ptr<Entry> MakeEntry(const KeyT& key, ValueT&& value) {
    149    return std::unique_ptr<Entry>(new Entry(*this, key, std::move(value)));
    150  }
    151  std::unique_ptr<Entry> MakeEntry(const KeyT& key, const ValueT& value) {
    152    return MakeEntry(key, ValueT(value));
    153  }
    154 
    155  const ValueT* Insert(std::unique_ptr<Entry>&& entry) {
    156    auto insertable = typename MapT::value_type{&entry->mKey, std::move(entry)};
    157 
    158    const auto res = mMap.insert(std::move(insertable));
    159    const auto& didInsert = res.second;
    160    MOZ_ALWAYS_TRUE(didInsert);
    161 
    162    const auto& itr = res.first;
    163    return &itr->second->mValue;
    164  }
    165 
    166  const ValueT* Find(const KeyT& key) const {
    167    const auto itr = mMap.find(&key);
    168    if (itr == mMap.end()) return nullptr;
    169 
    170    return &itr->second->mValue;
    171  }
    172 
    173  void Clear() const {
    174    while (true) {
    175      const auto itr = mMap.begin();
    176      if (itr == mMap.end()) return;
    177      itr->second->OnInvalidate();
    178    }
    179  }
    180 
    181  ~CacheWeakMap() { Clear(); }
    182 };
    183 
    184 }  // namespace mozilla
    185 
    186 #endif  // MOZILLA_CACHE_INVALIDATOR_H_