6 #ifndef XENIUM_VYUKOV_HASH_MAP_IMPL
7 #error "This is an impl file and must not be included directly!"
10 namespace xenium::impl {
13 struct vyukov_hash_map_common {
16 template <
class Accessor>
17 static void reset(Accessor&& acc) {
23 struct vyukov_hash_map_trivial_key : vyukov_hash_map_common<Key> {
25 static bool compare_trivial_key(Cell& key_cell,
const Key& key, hash_t ) {
26 return key_cell.load(std::memory_order_relaxed) == key;
29 template <
class Accessor>
30 static bool compare_nontrivial_key(
const Accessor&,
const Key&) {
35 static hash_t rehash(
const Key& k) {
41 struct vyukov_hash_map_nontrivial_key : vyukov_hash_map_common<Key> {
43 static bool compare_trivial_key(Cell& key_cell,
const Key& , hash_t hash) {
44 return key_cell.load(std::memory_order_relaxed) == hash;
47 template <
class Accessor>
48 static bool compare_nontrivial_key(
const Accessor& acc,
const Key& key) {
49 return acc.key() == key;
53 static hash_t rehash(hash_t h) {
58 template <
class Key,
class Value,
class VReclaimer,
class ValueReclaimer,
class Reclaimer>
59 struct vyukov_hash_map_traits<Key, managed_ptr<Value, VReclaimer>, ValueReclaimer, Reclaimer, true, true> :
60 bits::vyukov_hash_map_trivial_key<Key> {
61 static_assert(!parameter::is_set<ValueReclaimer>::value,
62 "value_reclaimer policy can only be used with non-trivial key/value types");
64 using value_type = Value*;
65 using storage_key_type = std::atomic<Key>;
66 using storage_value_type =
typename VReclaimer::template concurrent_ptr<Value>;
67 using iterator_value_type = std::pair<const Key, Value*>;
68 using iterator_reference = iterator_value_type;
73 Value* operator->() const noexcept {
return guard.get(); }
74 Value& operator*() const noexcept {
return guard.get(); }
75 void reset() { guard.reset(); }
76 void reclaim() { guard.reclaim(); }
79 accessor(storage_value_type& v, std::memory_order order) : guard(acquire_guard(v, order)) {}
80 typename storage_value_type::guard_ptr guard;
81 friend struct vyukov_hash_map_traits;
84 static accessor acquire(storage_value_type& v, std::memory_order order) {
return accessor(v, order); }
86 template <
bool AcquireAccessor>
87 static void store_item(storage_key_type& key_cell,
88 storage_value_type& value_cell,
92 std::memory_order order,
94 key_cell.store(k, std::memory_order_relaxed);
95 value_cell.store(v, order);
96 if (AcquireAccessor) {
97 acc.guard =
typename storage_value_type::guard_ptr(v);
101 template <
bool AcquireAccessor>
102 static bool compare_key(storage_key_type& key_cell,
103 storage_value_type& value_cell,
107 if (key_cell.load(std::memory_order_relaxed) != key) {
110 if (AcquireAccessor) {
111 acc.guard =
typename storage_value_type::guard_ptr(value_cell.load(std::memory_order_relaxed));
116 static iterator_reference deref_iterator(storage_key_type& k, storage_value_type& v) {
117 return {k.load(std::memory_order_relaxed), v.load(std::memory_order_relaxed).get()};
120 static void reclaim(accessor& a) { a.guard.reclaim(); }
121 static void reclaim_internal(accessor&) {}
124 template <
class Key,
class Value,
class VReclaimer,
class ValueReclaimer,
class Reclaimer>
125 struct vyukov_hash_map_traits<Key, managed_ptr<Value, VReclaimer>, ValueReclaimer, Reclaimer, false, true> :
126 bits::vyukov_hash_map_nontrivial_key<Key> {
127 using reclaimer = std::conditional_t<parameter::is_set<ValueReclaimer>::value, ValueReclaimer, Reclaimer>;
129 struct node : reclaimer::template enable_concurrent_ptr<node> {
130 node(Key&& key, Value* value) : key(std::move(key)), value(std::move(value)) {}
133 typename VReclaimer::template concurrent_ptr<Value> value;
136 using value_type = Value*;
137 using storage_key_type = std::atomic<size_t>;
138 using storage_value_type =
typename reclaimer::template concurrent_ptr<node>;
139 using iterator_value_type = std::pair<const Key&, value_type>;
140 using iterator_reference = iterator_value_type;
144 accessor() =
default;
145 Value* operator->() const noexcept {
return value_guard.get(); }
146 Value& operator*() const noexcept {
return *value_guard.get(); }
153 accessor(storage_value_type& v, std::memory_order order) :
154 node_guard(acquire_guard(v, order)),
155 value_guard(acquire_guard(node_guard->value, order)) {}
156 [[nodiscard]]
const Key& key()
const {
return node_guard->key; }
158 typename storage_value_type::guard_ptr node_guard;
159 typename VReclaimer::template concurrent_ptr<Value>::guard_ptr value_guard;
160 friend struct vyukov_hash_map_traits;
161 friend struct bits::vyukov_hash_map_nontrivial_key<Key>;
164 static accessor acquire(storage_value_type& v, std::memory_order order) {
return accessor(v, order); }
166 template <
bool AcquireAccessor>
167 static void store_item(storage_key_type& key_cell,
168 storage_value_type& value_cell,
172 std::memory_order order,
174 auto n =
new node(std::move(k), v);
175 if (AcquireAccessor) {
176 acc.node_guard =
typename storage_value_type::guard_ptr(n);
177 acc.value_guard =
typename VReclaimer::template concurrent_ptr<Value>::guard_ptr(v);
179 key_cell.store(hash, std::memory_order_relaxed);
180 value_cell.store(n, order);
183 template <
bool AcquireAccessor>
184 static bool compare_key(storage_key_type& key_cell,
185 storage_value_type& value_cell,
189 if (key_cell.load(std::memory_order_relaxed) != hash) {
192 acc.node_guard =
typename storage_value_type::guard_ptr(value_cell.load(std::memory_order_relaxed));
193 if (acc.node_guard->key == key) {
194 if (AcquireAccessor) {
195 acc.value_guard =
typename VReclaimer::template concurrent_ptr<Value>::guard_ptr(
196 acc.node_guard->value.load(std::memory_order_relaxed));
203 static iterator_reference deref_iterator(storage_key_type&, storage_value_type& v) {
204 auto node = v.load(std::memory_order_relaxed);
205 return {node->key, node->value.load(std::memory_order_relaxed).get()};
208 static void reclaim(accessor& a) {
209 a.value_guard.reclaim();
210 a.node_guard.reclaim();
212 static void reclaim_internal(accessor& a) {
216 auto g = a.node_guard;
221 template <
class Key,
class Value,
class ValueReclaimer,
class Reclaimer>
222 struct vyukov_hash_map_traits<Key, Value, ValueReclaimer, Reclaimer, true, true> :
223 bits::vyukov_hash_map_trivial_key<Key> {
224 static_assert(!parameter::is_set<ValueReclaimer>::value,
225 "value_reclaimer policy can only be used with non-trivial key/value types");
227 using value_type = Value;
228 using storage_key_type = std::atomic<Key>;
229 using storage_value_type = std::atomic<Value>;
230 using iterator_value_type = std::pair<const Key, Value>;
231 using iterator_reference = iterator_value_type;
235 accessor() =
default;
236 const value_type& operator*() const noexcept {
return v; }
239 accessor(storage_value_type& v, std::memory_order order) : v(v.load(order)) {}
241 friend struct vyukov_hash_map_traits;
244 static void reset(accessor&&) {}
245 static accessor acquire(storage_value_type& v, std::memory_order order) {
return accessor(v, order); }
247 template <
bool AcquireAccessor>
248 static void store_item(storage_key_type& key_cell,
249 storage_value_type& value_cell,
253 std::memory_order order,
255 key_cell.store(k, std::memory_order_relaxed);
256 value_cell.store(v, order);
257 if (AcquireAccessor) {
262 template <
bool AcquireAccessor>
263 static bool compare_key(storage_key_type& key_cell,
264 storage_value_type& value_cell,
268 if (key_cell.load(std::memory_order_relaxed) != key) {
271 if (AcquireAccessor) {
272 acc.v = value_cell.load(std::memory_order_relaxed);
277 static iterator_reference deref_iterator(storage_key_type& k, storage_value_type& v) {
278 return {k.load(std::memory_order_relaxed), v.load(std::memory_order_relaxed)};
281 static void reclaim(accessor&) {}
282 static void reclaim_internal(accessor&) {}
285 template <
class Key,
class Value,
class ValueReclaimer,
class Reclaimer>
286 struct vyukov_hash_map_traits<Key, Value, ValueReclaimer, Reclaimer, true, false> :
287 bits::vyukov_hash_map_trivial_key<Key> {
288 using reclaimer = std::conditional_t<parameter::is_set<ValueReclaimer>::value, ValueReclaimer, Reclaimer>;
290 struct node : reclaimer::template enable_concurrent_ptr<node> {
291 explicit node(Value&& value) : value(std::move(value)) {}
295 using value_type = Value;
296 using storage_key_type = std::atomic<Key>;
297 using storage_value_type =
typename reclaimer::template concurrent_ptr<node>;
298 using iterator_value_type = std::pair<const Key, Value&>;
299 using iterator_reference = iterator_value_type;
303 accessor() =
default;
304 Value* operator->() const noexcept {
return &guard->value; }
305 Value& operator*() const noexcept {
return guard->value; }
306 void reset() { guard.reset(); }
309 accessor(storage_value_type& v, std::memory_order order) : guard(acquire_guard(v, order)) {}
310 typename storage_value_type::guard_ptr guard;
311 friend struct vyukov_hash_map_traits;
314 static accessor acquire(storage_value_type& v, std::memory_order order) {
return accessor(v, order); }
316 template <
bool AcquireAccessor>
317 static bool compare_key(storage_key_type& key_cell,
318 storage_value_type& value_cell,
322 if (key_cell.load(std::memory_order_relaxed) != key) {
325 if (AcquireAccessor) {
326 acc.guard =
typename storage_value_type::guard_ptr(value_cell.load(std::memory_order_relaxed));
331 template <
bool AcquireAccessor>
332 static void store_item(storage_key_type& key_cell,
333 storage_value_type& value_cell,
337 std::memory_order order,
339 auto n =
new node(std::move(v));
340 if (AcquireAccessor) {
341 acc.guard =
typename storage_value_type::guard_ptr(n);
343 key_cell.store(k, std::memory_order_relaxed);
344 value_cell.store(n, order);
347 static iterator_reference deref_iterator(storage_key_type& k, storage_value_type& v) {
348 auto node = v.load(std::memory_order_relaxed);
349 return {k.load(std::memory_order_relaxed), node->value};
352 static void reclaim(accessor& a) { a.guard.reclaim(); }
353 static void reclaim_internal(accessor& a) {
362 template <
class Key,
class Value,
class ValueReclaimer,
class Reclaimer,
bool TrivialValue>
363 struct vyukov_hash_map_traits<Key, Value, ValueReclaimer, Reclaimer, false, TrivialValue> :
364 bits::vyukov_hash_map_nontrivial_key<Key> {
365 using reclaimer = std::conditional_t<parameter::is_set<ValueReclaimer>::value, ValueReclaimer, Reclaimer>;
367 struct node : reclaimer::template enable_concurrent_ptr<node> {
368 node(Key&& key, Value&& value) : data(std::move(key), std::move(value)) {}
370 std::pair<const Key, Value> data;
373 using value_type = Value;
374 using storage_key_type = std::atomic<hash_t>;
375 using storage_value_type =
typename reclaimer::template concurrent_ptr<node>;
376 using iterator_value_type = std::pair<const Key, Value>;
377 using iterator_reference = iterator_value_type&;
381 accessor() =
default;
382 Value* operator->() const noexcept {
return &guard->data.second; }
383 Value& operator*() const noexcept {
return guard->data.second; }
384 void reset() { guard.reset(); }
387 accessor(storage_value_type& v, std::memory_order order) : guard(acquire_guard(v, order)) {}
388 [[nodiscard]]
const Key& key()
const {
return guard->data.first; }
389 typename storage_value_type::guard_ptr guard;
390 friend struct vyukov_hash_map_traits;
391 friend struct bits::vyukov_hash_map_nontrivial_key<Key>;
394 static accessor acquire(storage_value_type& v, std::memory_order order) {
return accessor(v, order); }
396 template <
bool AcquireAccessor>
397 static void store_item(storage_key_type& key_cell,
398 storage_value_type& value_cell,
402 std::memory_order order,
404 auto n =
new node(std::move(k), std::move(v));
405 if (AcquireAccessor) {
406 acc.guard =
typename storage_value_type::guard_ptr(n);
408 key_cell.store(hash, std::memory_order_relaxed);
409 value_cell.store(n, order);
412 template <
bool AcquireAccessor>
413 static bool compare_key(storage_key_type& key_cell,
414 storage_value_type& value_cell,
418 if (key_cell.load(std::memory_order_relaxed) != hash) {
421 acc.guard =
typename storage_value_type::guard_ptr(value_cell.load(std::memory_order_relaxed));
422 return acc.guard->data.first == key;
425 static iterator_reference deref_iterator(storage_key_type&, storage_value_type& v) {
426 auto node = v.load(std::memory_order_relaxed);
430 static void reclaim(accessor& a) { a.guard.reclaim(); }
431 static void reclaim_internal(accessor& a) {