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