summaryrefslogtreecommitdiffstats
path: root/dom/canvas/CacheInvalidator.h
diff options
context:
space:
mode:
Diffstat (limited to 'dom/canvas/CacheInvalidator.h')
-rw-r--r--dom/canvas/CacheInvalidator.h168
1 files changed, 168 insertions, 0 deletions
diff --git a/dom/canvas/CacheInvalidator.h b/dom/canvas/CacheInvalidator.h
new file mode 100644
index 0000000000..e63f1e4cc2
--- /dev/null
+++ b/dom/canvas/CacheInvalidator.h
@@ -0,0 +1,168 @@
+/* -*- Mode: C++; tab-width: 13; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=13 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef MOZILLA_CACHE_INVALIDATOR_H_
+#define MOZILLA_CACHE_INVALIDATOR_H_
+
+#include "mozilla/Maybe.h"
+#include "mozilla/UniquePtr.h"
+#include <unordered_map>
+#include <unordered_set>
+#include <vector>
+
+// -
+
+namespace mozilla {
+
+class AbstractCache;
+
+// -
+
+class CacheInvalidator {
+ friend class AbstractCache;
+
+ private:
+ mutable std::unordered_set<AbstractCache*> mCaches;
+
+ public:
+ virtual ~CacheInvalidator() {
+ // It's actually generally unsafe to wait until now to invalidate caches,
+ // because when used as a mixin, this dtor is called after the dtor for the
+ // derived class. This means that if the derived class holds a cache (or is
+ // a cache!), OnInvalidate() will be called on a destroyed object.
+ // MOZ_ASSERT(!mCaches);
+ InvalidateCaches();
+ }
+
+ void InvalidateCaches() const;
+};
+
+// -
+
+class AbstractCache {
+ using InvalidatorListT = std::vector<const CacheInvalidator*>;
+
+ private:
+ InvalidatorListT mInvalidators;
+
+ public:
+ AbstractCache() = default;
+
+ explicit AbstractCache(InvalidatorListT&& invalidators) {
+ ResetInvalidators(std::move(invalidators));
+ }
+
+ virtual ~AbstractCache() { ResetInvalidators({}); }
+
+ public:
+ virtual void OnInvalidate() = 0;
+
+ void ResetInvalidators(InvalidatorListT&&);
+ void AddInvalidator(const CacheInvalidator&);
+};
+
+// -
+
+template <typename T>
+class CacheMaybe : public AbstractCache {
+ Maybe<T> mVal;
+
+ public:
+ template <typename U>
+ CacheMaybe& operator=(Maybe<U>&& rhs) {
+ mVal.reset();
+ if (rhs) {
+ mVal.emplace(std::move(rhs.ref()));
+ }
+ return *this;
+ }
+
+ CacheMaybe& operator=(Nothing) { return *this = Maybe<T>(); }
+
+ void OnInvalidate() override {
+ *this = Nothing();
+ ResetInvalidators({});
+ }
+
+ explicit operator bool() const { return bool(mVal); }
+ T* get() const { return mVal.ptrOr(nullptr); }
+ T* operator->() const { return get(); }
+};
+
+// -
+
+template <typename KeyT, typename ValueT>
+class CacheWeakMap final {
+ class Entry final : public AbstractCache {
+ public:
+ CacheWeakMap& mParent;
+ const KeyT mKey;
+ const ValueT mValue;
+
+ Entry(CacheWeakMap& parent, const KeyT& key, ValueT&& value)
+ : mParent(parent), mKey(key), mValue(std::move(value)) {}
+
+ void OnInvalidate() override {
+ const auto erased = mParent.mMap.erase(&mKey);
+ MOZ_ALWAYS_TRUE(erased == 1);
+ }
+ };
+
+ struct DerefHash final {
+ size_t operator()(const KeyT* const a) const {
+ return std::hash<KeyT>()(*a);
+ }
+ };
+ struct DerefEqual final {
+ bool operator()(const KeyT* const a, const KeyT* const b) const {
+ return *a == *b;
+ }
+ };
+
+ using MapT =
+ std::unordered_map<const KeyT*, UniquePtr<Entry>, DerefHash, DerefEqual>;
+ MapT mMap;
+
+ public:
+ UniquePtr<Entry> MakeEntry(const KeyT& key, ValueT&& value) {
+ return UniquePtr<Entry>(new Entry(*this, key, std::move(value)));
+ }
+ UniquePtr<Entry> MakeEntry(const KeyT& key, const ValueT& value) {
+ return MakeEntry(key, ValueT(value));
+ }
+
+ const ValueT* Insert(UniquePtr<Entry>&& entry) {
+ auto insertable = typename MapT::value_type{&entry->mKey, std::move(entry)};
+
+ const auto res = mMap.insert(std::move(insertable));
+ const auto& didInsert = res.second;
+ MOZ_ALWAYS_TRUE(didInsert);
+
+ const auto& itr = res.first;
+ return &itr->second->mValue;
+ }
+
+ const ValueT* Find(const KeyT& key) const {
+ const auto itr = mMap.find(&key);
+ if (itr == mMap.end()) return nullptr;
+
+ return &itr->second->mValue;
+ }
+
+ void Clear() const {
+ while (true) {
+ const auto itr = mMap.begin();
+ if (itr == mMap.end()) return;
+ itr->second->OnInvalidate();
+ }
+ }
+
+ ~CacheWeakMap() { Clear(); }
+};
+
+} // namespace mozilla
+
+#endif // MOZILLA_CACHE_INVALIDATOR_H_