-
Notifications
You must be signed in to change notification settings - Fork 38
/
Copy pathlru_encoded.hpp
79 lines (66 loc) · 1.78 KB
/
lru_encoded.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
/**
* Copyright Quadrivium LLC
* All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <scale/scale.hpp>
#include <boost/container_hash/hash.hpp>
#include "common/buffer_view.hpp"
#include "utils/lru.hpp"
namespace kagome {
/**
* LRU with encoded value deduplication.
* Used to cache runtime call results.
*/
template <typename K, typename V>
class LruEncoded {
public:
LruEncoded(size_t capacity) : values_{capacity}, hashes_{capacity} {}
std::optional<std::shared_ptr<V>> get(const K &k) {
return values_.get(k);
}
std::shared_ptr<V> put(const K &k, const V &v) {
return put(k, V{v});
}
std::shared_ptr<V> put(const K &k, V &&v) {
return put(k, std::move(v), scale::encode(v).value());
}
std::shared_ptr<V> put(const K &k, V &&v, common::BufferView encoded) {
auto h = hash(encoded);
auto weak = hashes_.get(h);
std::shared_ptr<V> shared;
if (weak) {
shared = weak->get().lock();
// check collisions (size_t is weak hash)
if (shared and *shared != v) {
shared.reset();
}
}
if (not shared) {
shared = std::make_shared<V>(std::move(v));
if (weak) {
weak->get() = shared;
} else {
hashes_.put(h, shared);
}
}
values_.put(k, std::shared_ptr<V>{shared});
return shared;
}
void erase(const K &k) {
values_.erase(k);
}
template <typename F>
void erase_if(const F &f) {
values_.erase_if(f);
}
private:
using Hash = size_t;
Hash hash(common::BufferView v) {
return boost::hash_range(v.begin(), v.end());
}
Lru<K, std::shared_ptr<V>> values_;
Lru<Hash, std::weak_ptr<V>> hashes_;
};
} // namespace kagome