Bug 1729395 - Handle message sender going away during message processing r=robwu
[gecko.git] / dom / canvas / CacheInvalidator.h
blobe63f1e4cc2ef24deabdf90f5e0f0cd8699473d73
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/. */
7 #ifndef MOZILLA_CACHE_INVALIDATOR_H_
8 #define MOZILLA_CACHE_INVALIDATOR_H_
10 #include "mozilla/Maybe.h"
11 #include "mozilla/UniquePtr.h"
12 #include <unordered_map>
13 #include <unordered_set>
14 #include <vector>
16 // -
18 namespace mozilla {
20 class AbstractCache;
22 // -
24 class CacheInvalidator {
25 friend class AbstractCache;
27 private:
28 mutable std::unordered_set<AbstractCache*> mCaches;
30 public:
31 virtual ~CacheInvalidator() {
32 // It's actually generally unsafe to wait until now to invalidate caches,
33 // because when used as a mixin, this dtor is called after the dtor for the
34 // derived class. This means that if the derived class holds a cache (or is
35 // a cache!), OnInvalidate() will be called on a destroyed object.
36 // MOZ_ASSERT(!mCaches);
37 InvalidateCaches();
40 void InvalidateCaches() const;
43 // -
45 class AbstractCache {
46 using InvalidatorListT = std::vector<const CacheInvalidator*>;
48 private:
49 InvalidatorListT mInvalidators;
51 public:
52 AbstractCache() = default;
54 explicit AbstractCache(InvalidatorListT&& invalidators) {
55 ResetInvalidators(std::move(invalidators));
58 virtual ~AbstractCache() { ResetInvalidators({}); }
60 public:
61 virtual void OnInvalidate() = 0;
63 void ResetInvalidators(InvalidatorListT&&);
64 void AddInvalidator(const CacheInvalidator&);
67 // -
69 template <typename T>
70 class CacheMaybe : public AbstractCache {
71 Maybe<T> mVal;
73 public:
74 template <typename U>
75 CacheMaybe& operator=(Maybe<U>&& rhs) {
76 mVal.reset();
77 if (rhs) {
78 mVal.emplace(std::move(rhs.ref()));
80 return *this;
83 CacheMaybe& operator=(Nothing) { return *this = Maybe<T>(); }
85 void OnInvalidate() override {
86 *this = Nothing();
87 ResetInvalidators({});
90 explicit operator bool() const { return bool(mVal); }
91 T* get() const { return mVal.ptrOr(nullptr); }
92 T* operator->() const { return get(); }
95 // -
97 template <typename KeyT, typename ValueT>
98 class CacheWeakMap final {
99 class Entry final : public AbstractCache {
100 public:
101 CacheWeakMap& mParent;
102 const KeyT mKey;
103 const ValueT mValue;
105 Entry(CacheWeakMap& parent, const KeyT& key, ValueT&& value)
106 : mParent(parent), mKey(key), mValue(std::move(value)) {}
108 void OnInvalidate() override {
109 const auto erased = mParent.mMap.erase(&mKey);
110 MOZ_ALWAYS_TRUE(erased == 1);
114 struct DerefHash final {
115 size_t operator()(const KeyT* const a) const {
116 return std::hash<KeyT>()(*a);
119 struct DerefEqual final {
120 bool operator()(const KeyT* const a, const KeyT* const b) const {
121 return *a == *b;
125 using MapT =
126 std::unordered_map<const KeyT*, UniquePtr<Entry>, DerefHash, DerefEqual>;
127 MapT mMap;
129 public:
130 UniquePtr<Entry> MakeEntry(const KeyT& key, ValueT&& value) {
131 return UniquePtr<Entry>(new Entry(*this, key, std::move(value)));
133 UniquePtr<Entry> MakeEntry(const KeyT& key, const ValueT& value) {
134 return MakeEntry(key, ValueT(value));
137 const ValueT* Insert(UniquePtr<Entry>&& entry) {
138 auto insertable = typename MapT::value_type{&entry->mKey, std::move(entry)};
140 const auto res = mMap.insert(std::move(insertable));
141 const auto& didInsert = res.second;
142 MOZ_ALWAYS_TRUE(didInsert);
144 const auto& itr = res.first;
145 return &itr->second->mValue;
148 const ValueT* Find(const KeyT& key) const {
149 const auto itr = mMap.find(&key);
150 if (itr == mMap.end()) return nullptr;
152 return &itr->second->mValue;
155 void Clear() const {
156 while (true) {
157 const auto itr = mMap.begin();
158 if (itr == mMap.end()) return;
159 itr->second->OnInvalidate();
163 ~CacheWeakMap() { Clear(); }
166 } // namespace mozilla
168 #endif // MOZILLA_CACHE_INVALIDATOR_H_