Bug 1404196 - Add CacheMap for simplifying complex cache dependency invalidation. - r=daoshengmu draft
authorJeff Gilbert <jgilbert@mozilla.com>
Mon, 30 Oct 2017 13:56:18 -0700
changeset 689133 1f83d85da3a86f5acef633c1f48d3e1686fcca9a
parent 689132 253c9db6c2a4c75c228c6a7590c6f56c698f2af4
child 689134 8b7373c5396dae3ac2b40ab20ad549ed398b5b95
push id86923
push userbmo:jgilbert@mozilla.com
push dateTue, 31 Oct 2017 03:29:56 +0000
reviewersdaoshengmu
bugs1404196
milestone58.0a1
Bug 1404196 - Add CacheMap for simplifying complex cache dependency invalidation. - r=daoshengmu MozReview-Commit-ID: IhzkHf9bhTv
dom/canvas/CacheMap.cpp
dom/canvas/CacheMap.h
dom/canvas/moz.build
new file mode 100644
--- /dev/null
+++ b/dom/canvas/CacheMap.cpp
@@ -0,0 +1,43 @@
+/* -*- Mode: C++; tab-width: 13; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim: set ts=13 sts=4 et sw=4 tw=90: */
+/* 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/. */
+
+#include "CacheMap.h"
+
+namespace mozilla {
+
+void
+CacheMapInvalidator::InvalidateCaches() const
+{
+    while (mCacheEntries.size()) {
+        const auto& entry = *(mCacheEntries.begin());
+        entry->Invalidate();
+        MOZ_ASSERT(mCacheEntries.find(entry) == mCacheEntries.end());
+    }
+}
+
+namespace detail {
+
+CacheMapUntypedEntry::CacheMapUntypedEntry(std::vector<const CacheMapInvalidator*>&& invalidators)
+    : mInvalidators(Move(invalidators))
+{
+    for (const auto& cur : mInvalidators) {
+        // Don't assert that we insert, since there may be dupes in `invalidators`.
+        // (and it's not worth removing the dupes)
+        (void)cur->mCacheEntries.insert(this);
+    }
+}
+
+CacheMapUntypedEntry::~CacheMapUntypedEntry()
+{
+    for (const auto& cur : mInvalidators) {
+        // There might be dupes, so erase might return >1.
+        (void)cur->mCacheEntries.erase(this);
+    }
+}
+
+} // namespace detail
+
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/canvas/CacheMap.h
@@ -0,0 +1,128 @@
+/* -*- Mode: C++; tab-width: 13; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim: set ts=13 sts=4 et sw=4 tw=90: */
+/* 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_MAP_H_
+#define MOZILLA_CACHE_MAP_H_
+
+#include "mozilla/UniquePtr.h"
+#include <map>
+#include <unordered_set>
+#include <vector>
+
+namespace mozilla {
+
+namespace detail {
+struct CacheMapUntypedEntry;
+}
+
+class CacheMapInvalidator
+{
+    friend struct detail::CacheMapUntypedEntry;
+
+    mutable std::unordered_set<const detail::CacheMapUntypedEntry*> mCacheEntries;
+
+public:
+    ~CacheMapInvalidator() {
+        InvalidateCaches();
+    }
+
+    void InvalidateCaches() const;
+};
+
+namespace detail {
+
+struct CacheMapUntypedEntry
+{
+    template<typename, typename> friend class CacheMap;
+
+    const std::vector<const CacheMapInvalidator*> mInvalidators;
+
+    CacheMapUntypedEntry(std::vector<const CacheMapInvalidator*>&& invalidators);
+    ~CacheMapUntypedEntry();
+
+public:
+    virtual void Invalidate() const = 0;
+};
+
+template<typename T>
+struct DerefLess final {
+    bool operator ()(const T* const a, const T* const b) const {
+        return *a < *b;
+    }
+};
+
+} // namespace detail
+
+
+template<typename KeyT, typename ValueT>
+class CacheMap final
+{
+    struct Entry final : public detail::CacheMapUntypedEntry {
+        CacheMap& mParent;
+        const KeyT mKey;
+        const ValueT mValue;
+
+        Entry(std::vector<const CacheMapInvalidator*>&& invalidators, CacheMap& parent,
+              KeyT&& key, ValueT&& value)
+            : detail::CacheMapUntypedEntry(Move(invalidators))
+            , mParent(parent)
+            , mKey(Move(key))
+            , mValue(Move(value))
+        { }
+
+        void Invalidate() const override {
+            const auto erased = mParent.mMap.erase(&mKey);
+            MOZ_ALWAYS_TRUE( erased == 1 );
+        }
+
+        bool operator <(const Entry& x) const {
+            return mKey < x.mKey;
+        }
+    };
+
+    typedef std::map<const KeyT*, UniquePtr<const Entry>, detail::DerefLess<KeyT>> MapT;
+    MapT mMap;
+
+public:
+    const ValueT* Insert(KeyT&& key, ValueT&& value,
+                         std::vector<const CacheMapInvalidator*>&& invalidators)
+    {
+        UniquePtr<const Entry> entry( new Entry(Move(invalidators), *this, Move(key),
+                                                Move(value)) );
+
+        typename MapT::value_type insertable{
+            &entry->mKey,
+            nullptr
+        };
+        insertable.second = Move(entry);
+
+        const auto res = mMap.insert(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 Invalidate() {
+        while (mMap.size()) {
+            const auto& itr = mMap.begin();
+            itr->second->Invalidate();
+        }
+    }
+};
+
+} // namespace mozilla
+
+#endif // MOZILLA_CACHE_MAP_H_
--- a/dom/canvas/moz.build
+++ b/dom/canvas/moz.build
@@ -89,16 +89,17 @@ UNIFIED_SOURCES += [
 ]
 
 SOURCES += [
     'ImageUtils.cpp',
 ]
 
 # WebGL Sources
 UNIFIED_SOURCES += [
+    'CacheMap.cpp',
     'TexUnpackBlob.cpp',
     'WebGL1Context.cpp',
     'WebGL2Context.cpp',
     'WebGL2ContextBuffers.cpp',
     'WebGL2ContextFramebuffers.cpp',
     'WebGL2ContextMRTs.cpp',
     'WebGL2ContextPrograms.cpp',
     'WebGL2ContextQueries.cpp',