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