1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 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_MruCache_h
8 #define mozilla_MruCache_h
11 #include <type_traits>
14 #include "mozilla/Attributes.h"
15 #include "mozilla/HashFunctions.h"
21 // Helper struct for checking if a value is empty.
23 // `IsNotEmpty` will return true if `Value` is not a pointer type or if the
24 // pointer value is not null.
25 template <typename Value
, bool IsPtr
= std::is_pointer
<Value
>::value
>
27 static bool IsNotEmpty(const Value
&) { return true; }
29 // Template specialization for the `IsPtr == true` case.
30 template <typename Value
>
31 struct EmptyChecker
<Value
, true> {
32 static bool IsNotEmpty(const Value
& aVal
) { return aVal
!= nullptr; }
37 // Provides a most recently used cache that can be used as a layer on top of
38 // a larger container where lookups can be expensive. The default size is 31,
39 // which as a prime number provides a better distrubution of cached entries.
41 // Users are expected to provide a `Cache` class that defines two required
43 // - A method for providing the hash of a key:
45 // static HashNumber Hash(const KeyType& aKey)
47 // - A method for matching a key to a value, for pointer types the value
48 // is guaranteed not to be null.
50 // static bool Match(const KeyType& aKey, const ValueType& aVal)
53 // class MruExample : public MruCache<void*, PtrInfo*, MruExample>
55 // static HashNumber Hash(const KeyType& aKey)
57 // return HashGeneric(aKey);
59 // static Match(const KeyType& aKey, const ValueType& aVal)
61 // return aVal->mPtr == aKey;
64 template <class Key
, class Value
, class Cache
, size_t Size
= 31>
66 // Best distribution is achieved with a prime number. Ideally the closest
67 // to a power of two will be the most efficient use of memory. This
68 // assertion is pretty weak, but should catch the common inclination to
69 // use a power-of-two.
70 static_assert(Size
% 2 != 0, "Use a prime number");
72 // This is a stronger assertion but significantly limits the values to just
73 // those close to a power-of-two value.
74 // static_assert(Size == 7 || Size == 13 || Size == 31 || Size == 61 ||
75 // Size == 127 || Size == 251 || Size == 509 || Size == 1021,
76 // "Use a prime number less than 1024");
80 using ValueType
= Value
;
83 MruCache(const MruCache
&) = delete;
84 MruCache(const MruCache
&&) = delete;
86 // Inserts the given value into the cache. Potentially overwrites an
89 void Put(const KeyType
& aKey
, U
&& aVal
) {
90 *RawEntry(aKey
) = std::forward
<U
>(aVal
);
93 // Removes the given entry if it is in the cache.
94 void Remove(const KeyType
& aKey
) { Lookup(aKey
).Remove(); }
96 // Clears all cached entries and resets them to a default value.
98 for (ValueType
& val
: mCache
) {
103 // Helper that holds an entry that matched a lookup key. Usage:
105 // auto p = mCache.Lookup(aKey);
110 // auto foo = new Foo();
115 Entry(ValueType
* aEntry
, bool aMatch
) : mEntry(aEntry
), mMatch(aMatch
) {
119 explicit operator bool() const { return mMatch
; }
121 ValueType
& Data() const {
126 template <typename U
>
127 void Set(U
&& aValue
) {
129 Data() = std::forward
<U
>(aValue
);
134 Data() = ValueType
{};
140 ValueType
* mEntry
; // Location of the entry in the cache.
141 bool mMatch
; // Whether the value matched.
144 // Retrieves an entry from the cache. Can be used to test if an entry is
145 // present, update the entry to a new value, or remove the entry if one was
147 Entry
Lookup(const KeyType
& aKey
) {
148 using EmptyChecker
= detail::EmptyChecker
<ValueType
>;
150 auto entry
= RawEntry(aKey
);
151 bool match
= EmptyChecker::IsNotEmpty(*entry
) && Cache::Match(aKey
, *entry
);
152 return Entry(entry
, match
);
156 MOZ_ALWAYS_INLINE ValueType
* RawEntry(const KeyType
& aKey
) {
157 return &mCache
[Cache::Hash(aKey
) % Size
];
160 ValueType mCache
[Size
] = {};
163 } // namespace mozilla
165 #endif // mozilla_mrucache_h