/* -*- 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 #include #include namespace mozilla { namespace detail { class CacheMapUntypedEntry; } class CacheMapInvalidator { friend class detail::CacheMapUntypedEntry; mutable std::unordered_set mCacheEntries; public: ~CacheMapInvalidator() { InvalidateCaches(); } void InvalidateCaches() const; }; namespace detail { class CacheMapUntypedEntry { template friend class CacheMap; private: const std::vector mInvalidators; protected: CacheMapUntypedEntry(std::vector&& invalidators); ~CacheMapUntypedEntry(); public: virtual void Invalidate() const = 0; }; struct DerefLess final { template bool operator()(const T* const a, const T* const b) const { return *a < *b; } }; } // namespace detail template class CacheMap final { class Entry final : public detail::CacheMapUntypedEntry { public: CacheMap& mParent; const KeyT mKey; const ValueT mValue; Entry(std::vector&& 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, detail::DerefLess> MapT; MapT mMap; public: const ValueT* Insert(KeyT&& key, ValueT&& value, std::vector&& invalidators) { UniquePtr 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_