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 "DmdStdContainers.h"
23 class CacheInvalidator
{
24 friend class AbstractCache
;
27 mutable webgl::dmd_unordered_set
<AbstractCache
*> mCaches
;
30 virtual ~CacheInvalidator() {
31 // It's actually generally unsafe to wait until now to invalidate caches,
32 // because when used as a mixin, this dtor is called after the dtor for the
33 // derived class. This means that if the derived class holds a cache (or is
34 // a cache!), OnInvalidate() will be called on a destroyed object.
35 // MOZ_ASSERT(!mCaches);
39 void InvalidateCaches() const;
43 size_t SizeOfExcludingThis(mozilla::MallocSizeOf mso
) const {
44 return mCaches
.SizeOfExcludingThis(mso
);
51 using InvalidatorListT
= std::vector
<const CacheInvalidator
*>;
54 InvalidatorListT mInvalidators
;
57 AbstractCache() = default;
59 explicit AbstractCache(InvalidatorListT
&& invalidators
) {
60 ResetInvalidators(std::move(invalidators
));
63 virtual ~AbstractCache() { ResetInvalidators({}); }
66 virtual void OnInvalidate() = 0;
68 void ResetInvalidators(InvalidatorListT
&&);
69 void AddInvalidator(const CacheInvalidator
&);
75 class CacheMaybe
: public AbstractCache
{
80 CacheMaybe
& operator=(Maybe
<U
>&& rhs
) {
83 mVal
.emplace(std::move(rhs
.ref()));
88 CacheMaybe
& operator=(Nothing
) { return *this = Maybe
<T
>(); }
90 void OnInvalidate() override
{
92 ResetInvalidators({});
95 explicit operator bool() const { return bool(mVal
); }
96 T
* get() const { return mVal
.ptrOr(nullptr); }
97 T
* operator->() const { return get(); }
102 template <typename KeyT
, typename ValueT
>
103 class CacheWeakMap final
{
104 class Entry final
: public AbstractCache
{
106 CacheWeakMap
& mParent
;
110 Entry(CacheWeakMap
& parent
, const KeyT
& key
, ValueT
&& value
)
111 : mParent(parent
), mKey(key
), mValue(std::move(value
)) {}
113 void OnInvalidate() override
{
114 const auto erased
= mParent
.mMap
.erase(&mKey
);
115 MOZ_ALWAYS_TRUE(erased
== 1);
119 struct DerefHash final
{
120 size_t operator()(const KeyT
* const a
) const {
121 return std::hash
<KeyT
>()(*a
);
124 struct DerefEqual final
{
125 bool operator()(const KeyT
* const a
, const KeyT
* const b
) const {
130 using MapT
= webgl::dmd_unordered_map
<const KeyT
*, UniquePtr
<Entry
>,
131 DerefHash
, DerefEqual
>;
135 size_t SizeOfExcludingThis(mozilla::MallocSizeOf mso
) const {
136 return mMap
.SizeOfExcludingThis(mso
);
139 UniquePtr
<Entry
> MakeEntry(const KeyT
& key
, ValueT
&& value
) {
140 return UniquePtr
<Entry
>(new Entry(*this, key
, std::move(value
)));
142 UniquePtr
<Entry
> MakeEntry(const KeyT
& key
, const ValueT
& value
) {
143 return MakeEntry(key
, ValueT(value
));
146 const ValueT
* Insert(UniquePtr
<Entry
>&& entry
) {
147 auto insertable
= typename
MapT::value_type
{&entry
->mKey
, std::move(entry
)};
149 const auto res
= mMap
.insert(std::move(insertable
));
150 const auto& didInsert
= res
.second
;
151 MOZ_ALWAYS_TRUE(didInsert
);
153 const auto& itr
= res
.first
;
154 return &itr
->second
->mValue
;
157 const ValueT
* Find(const KeyT
& key
) const {
158 const auto itr
= mMap
.find(&key
);
159 if (itr
== mMap
.end()) return nullptr;
161 return &itr
->second
->mValue
;
166 const auto itr
= mMap
.begin();
167 if (itr
== mMap
.end()) return;
168 itr
->second
->OnInvalidate();
172 ~CacheWeakMap() { Clear(); }
175 } // namespace mozilla
177 #endif // MOZILLA_CACHE_INVALIDATOR_H_