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