1 /* -*- Mode: C++; tab-width: 13; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* vim: set ts=13 sts=4 et sw=4 tw=90: */
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_MAP_H_
8 #define MOZILLA_CACHE_MAP_H_
9 
10 #include "mozilla/UniquePtr.h"
11 #include <map>
12 #include <unordered_set>
13 #include <vector>
14 
15 namespace mozilla {
16 
17 namespace detail {
18 class CacheMapUntypedEntry;
19 }
20 
21 class CacheMapInvalidator {
22   friend class detail::CacheMapUntypedEntry;
23 
24   mutable std::unordered_set<const detail::CacheMapUntypedEntry*> mCacheEntries;
25 
26  public:
~CacheMapInvalidator()27   ~CacheMapInvalidator() { InvalidateCaches(); }
28 
29   void InvalidateCaches() const;
30 };
31 
32 namespace detail {
33 
34 class CacheMapUntypedEntry {
35   template <typename, typename>
36   friend class CacheMap;
37 
38  private:
39   const std::vector<const CacheMapInvalidator*> mInvalidators;
40 
41  protected:
42   CacheMapUntypedEntry(std::vector<const CacheMapInvalidator*>&& invalidators);
43   ~CacheMapUntypedEntry();
44 
45  public:
46   virtual void Invalidate() const = 0;
47 };
48 
49 struct DerefLess final {
50   template <typename T>
operatorfinal51   bool operator()(const T* const a, const T* const b) const {
52     return *a < *b;
53   }
54 };
55 
56 }  // namespace detail
57 
58 template <typename KeyT, typename ValueT>
59 class CacheMap final {
60   class Entry final : public detail::CacheMapUntypedEntry {
61    public:
62     CacheMap& mParent;
63     const KeyT mKey;
64     const ValueT mValue;
65 
Entry(std::vector<const CacheMapInvalidator * > && invalidators,CacheMap & parent,KeyT && key,ValueT && value)66     Entry(std::vector<const CacheMapInvalidator*>&& invalidators,
67           CacheMap& parent, KeyT&& key, ValueT&& value)
68         : detail::CacheMapUntypedEntry(Move(invalidators)),
69           mParent(parent),
70           mKey(Move(key)),
71           mValue(Move(value)) {}
72 
Invalidate()73     void Invalidate() const override {
74       const auto erased = mParent.mMap.erase(&mKey);
75       MOZ_ALWAYS_TRUE(erased == 1);
76     }
77 
78     bool operator<(const Entry& x) const { return mKey < x.mKey; }
79   };
80 
81   typedef std::map<const KeyT*, UniquePtr<const Entry>, detail::DerefLess> MapT;
82   MapT mMap;
83 
84  public:
Insert(KeyT && key,ValueT && value,std::vector<const CacheMapInvalidator * > && invalidators)85   const ValueT* Insert(KeyT&& key, ValueT&& value,
86                        std::vector<const CacheMapInvalidator*>&& invalidators) {
87     UniquePtr<const Entry> entry(
88         new Entry(Move(invalidators), *this, Move(key), Move(value)));
89 
90     typename MapT::value_type insertable{&entry->mKey, nullptr};
91     insertable.second = Move(entry);
92 
93     const auto res = mMap.insert(Move(insertable));
94     const auto& didInsert = res.second;
95     MOZ_ALWAYS_TRUE(didInsert);
96 
97     const auto& itr = res.first;
98     return &itr->second->mValue;
99   }
100 
Find(const KeyT & key)101   const ValueT* Find(const KeyT& key) const {
102     const auto itr = mMap.find(&key);
103     if (itr == mMap.end()) return nullptr;
104 
105     return &itr->second->mValue;
106   }
107 
Invalidate()108   void Invalidate() {
109     while (mMap.size()) {
110       const auto& itr = mMap.begin();
111       itr->second->Invalidate();
112     }
113   }
114 };
115 
116 }  // namespace mozilla
117 
118 #endif  // MOZILLA_CACHE_MAP_H_
119