1 | /* |
2 | * Copyright 2020 Google Inc. |
3 | * |
4 | * Use of this source code is governed by a BSD-style license that can be |
5 | * found in the LICENSE file. |
6 | */ |
7 | |
8 | #ifndef GrHashMapWithCache_DEFINED |
9 | #define GrHashMapWithCache_DEFINED |
10 | |
11 | #include "include/private/SkChecksum.h" |
12 | #include "include/private/SkNoncopyable.h" |
13 | #include "include/private/SkTHash.h" |
14 | |
15 | // Cheaper than SkGoodHash and good enough for UniqueID tables. |
16 | struct GrCheapHash { |
17 | uint32_t operator()(uint32_t val) { |
18 | return SkChecksum::CheapMix(val); |
19 | } |
20 | }; |
21 | |
22 | /** A hash map that caches the most recently accessed entry. |
23 | The API is a subset of SkHashMap, and you must provide a |
24 | sentinel key that will never be present, such as SK_InvalidUniqueID. |
25 | |
26 | KeyTraits must have: |
27 | - static K GetInvalidKey() |
28 | */ |
29 | template <typename K, typename V, typename KeyTraits, typename HashT = SkGoodHash> |
30 | class GrHashMapWithCache : public SkNoncopyable { |
31 | public: |
32 | // How many key/value pairs are in the table? |
33 | int count() const { return fMap.count(); } |
34 | |
35 | // Approximately how many bytes of memory do we use beyond sizeof(*this)? |
36 | size_t approxBytesUsed() const { return fMap.approxBytesUsed(); } |
37 | |
38 | // N.B. The pointers returned by set() and find() are valid only until the next call to set(). |
39 | |
40 | // If there is key/value entry in the table with this key, return a pointer to the value. |
41 | // If not, return null. |
42 | const V* find(const K& key) const { |
43 | if (key != fLastKey) { |
44 | fLastKey = key; |
45 | fLastValue = fMap.find(key); |
46 | } |
47 | return fLastValue; |
48 | } |
49 | |
50 | // Set key to val in the map, replacing any previous value with the same key. |
51 | // We copy both key and val, and return a pointer to the value copy now in the map. |
52 | const V* set(K key, V val) { |
53 | if (fLastValue && key == fLastKey) { |
54 | *fLastValue = std::move(val); |
55 | } else { |
56 | fLastKey = key; |
57 | fLastValue = fMap.set(std::move(key), std::move(val)); |
58 | } |
59 | return fLastValue; |
60 | } |
61 | |
62 | // Remove the key/value entry in the table with this key. |
63 | void remove(K key) { |
64 | // Match SkTHashMap requirement. The caller can find() if they're unsure. |
65 | SkASSERT(fMap.find(fLastKey)); |
66 | fLastKey = std::move(key); |
67 | fLastValue = nullptr; |
68 | fMap.remove(fLastKey); |
69 | } |
70 | |
71 | // Clear the map. |
72 | void reset() { |
73 | fLastKey = KeyTraits::GetInvalidKey(); |
74 | fLastValue = nullptr; |
75 | fMap.reset(); |
76 | } |
77 | |
78 | private: |
79 | SkTHashMap<K, V, HashT> fMap; |
80 | mutable K fLastKey = KeyTraits::GetInvalidKey(); |
81 | mutable V* fLastValue = nullptr; |
82 | }; |
83 | |
84 | #endif |
85 | |