1 /* -*- Mode: C++; tab-width: 13; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=13 sts=2 et sw=2 tw=80: */
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/. */
7 #ifndef MOZILLA_CACHE_INVALIDATOR_H_
8 #define MOZILLA_CACHE_INVALIDATOR_H_
10 #include "mozilla/Maybe.h"
11 #include "mozilla/UniquePtr.h"
12 #include <unordered_map>
13 #include <unordered_set>
24 class CacheInvalidator
{
25 friend class AbstractCache
;
28 mutable std::unordered_set
<AbstractCache
*> mCaches
;
31 virtual ~CacheInvalidator() {
32 // It's actually generally unsafe to wait until now to invalidate caches,
33 // because when used as a mixin, this dtor is called after the dtor for the
34 // derived class. This means that if the derived class holds a cache (or is
35 // a cache!), OnInvalidate() will be called on a destroyed object.
36 // MOZ_ASSERT(!mCaches);
40 void InvalidateCaches() const;
46 typedef std::vector
<const CacheInvalidator
*> InvalidatorListT
;
49 InvalidatorListT mInvalidators
;
52 AbstractCache() = default;
54 explicit AbstractCache(InvalidatorListT
&& invalidators
) {
55 ResetInvalidators(std::move(invalidators
));
58 virtual ~AbstractCache() { ResetInvalidators({}); }
61 virtual void OnInvalidate() = 0;
63 void ResetInvalidators(InvalidatorListT
&&);
64 void AddInvalidator(const CacheInvalidator
&);
70 class CacheMaybe
: public AbstractCache
{
75 CacheMaybe
& operator=(Maybe
<U
>&& rhs
) {
78 mVal
.emplace(std::move(rhs
.ref()));
83 CacheMaybe
& operator=(Nothing
) { return *this = Maybe
<T
>(); }
85 void OnInvalidate() override
{
87 ResetInvalidators({});
90 explicit operator bool() const { return bool(mVal
); }
91 T
* get() const { return mVal
.ptrOr(nullptr); }
92 T
* operator->() const { return get(); }
97 template <typename KeyT
, typename ValueT
>
98 class CacheWeakMap final
{
99 class Entry final
: public AbstractCache
{
101 CacheWeakMap
& mParent
;
105 Entry(CacheWeakMap
& parent
, const KeyT
& key
, ValueT
&& value
)
106 : mParent(parent
), mKey(key
), mValue(std::move(value
)) {}
108 void OnInvalidate() override
{
109 const auto erased
= mParent
.mMap
.erase(&mKey
);
110 MOZ_ALWAYS_TRUE(erased
== 1);
114 struct DerefHash final
{
115 size_t operator()(const KeyT
* const a
) const {
116 return std::hash
<KeyT
>()(*a
);
119 struct DerefEqual final
{
120 bool operator()(const KeyT
* const a
, const KeyT
* const b
) const {
125 typedef std::unordered_map
<const KeyT
*, UniquePtr
<Entry
>, DerefHash
,
131 UniquePtr
<Entry
> MakeEntry(const KeyT
& key
, ValueT
&& value
) {
132 return UniquePtr
<Entry
>(new Entry(*this, key
, std::move(value
)));
134 UniquePtr
<Entry
> MakeEntry(const KeyT
& key
, const ValueT
& value
) {
135 return MakeEntry(key
, ValueT(value
));
138 const ValueT
* Insert(UniquePtr
<Entry
>&& entry
) {
139 auto insertable
= typename
MapT::value_type
{&entry
->mKey
, std::move(entry
)};
141 const auto res
= mMap
.insert(std::move(insertable
));
142 const auto& didInsert
= res
.second
;
143 MOZ_ALWAYS_TRUE(didInsert
);
145 const auto& itr
= res
.first
;
146 return &itr
->second
->mValue
;
149 const ValueT
* Find(const KeyT
& key
) const {
150 const auto itr
= mMap
.find(&key
);
151 if (itr
== mMap
.end()) return nullptr;
153 return &itr
->second
->mValue
;
158 const auto itr
= mMap
.begin();
159 if (itr
== mMap
.end()) return;
160 itr
->second
->OnInvalidate();
164 ~CacheWeakMap() { Clear(); }
167 } // namespace mozilla
169 #endif // MOZILLA_CACHE_INVALIDATOR_H_