Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
tpl_persistent_hash_map.H
Go to the documentation of this file.
1/*
2 Aleph_w
3
4 Data structures & Algorithms
5 https://github.com/lrleon/Aleph-w
6
7 This file is part of Aleph-w library
8
9 Copyright (c) 2002-2026 Leandro Rabindranath Leon
10
11 Permission is hereby granted, free of charge, to any person obtaining a copy
12 of this software and associated documentation files (the "Software"), to deal
13 in the Software without restriction, including without limitation the rights
14 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15 copies of the Software, and to permit persons to whom the Software is
16 furnished to do so, subject to the following conditions:
17
18 The above copyright notice and this permission notice shall be included in all
19 copies or substantial portions of the Software.
20
21 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27 SOFTWARE.
28*/
29
55#ifndef TPL_PERSISTENT_HASH_MAP_H
56#define TPL_PERSISTENT_HASH_MAP_H
57
58#include <bit>
59#include <cstdint>
60#include <limits>
61#include <memory>
62#include <type_traits>
63#include <utility>
64
65#include <ah-errors.H>
66#include <ahFunction.H>
67#include <hash-fct.H>
68#include <tpl_array.H>
69
70namespace Aleph
71{
72
111template <typename Key, typename T, class Cmp = Aleph::equal_to<Key>>
113{
114 static_assert(std::is_copy_constructible_v<Key>,
115 "PersistentHashMap requires copy-constructible keys");
116 static_assert(std::is_copy_assignable_v<Key>,
117 "PersistentHashMap requires copy-assignable keys");
118 static_assert(std::is_copy_constructible_v<T>,
119 "PersistentHashMap requires copy-constructible mapped values");
120 static_assert(std::is_copy_assignable_v<T>,
121 "PersistentHashMap requires copy-assignable mapped values");
122 static_assert(std::is_copy_constructible_v<Cmp>,
123 "PersistentHashMap requires a copy-constructible comparator");
124
125public:
127 using Hash_Fct_Ptr = size_t (*)(const Key &);
128
129private:
130 static constexpr size_t BITS_PER_LEVEL = 5;
131 static constexpr size_t BRANCHING_FACTOR = 1ULL << BITS_PER_LEVEL;
132 static constexpr size_t LEVEL_MASK = BRANCHING_FACTOR - 1;
133
135 enum class NodeType
136 {
137 LEAF,
138 BITMAP,
139 COLLISION
140 };
141
143 struct Node
144 {
146
147 explicit Node(const NodeType t) noexcept
148 : type(t)
149 {
150 // Empty.
151 }
152
153 virtual ~Node() = default;
154 };
155
156 using NodePtr = std::shared_ptr<const Node>;
157
158 struct LeafNode : public Node
159 {
160 Key key;
162 size_t hash;
163
164 LeafNode(Key k, T v, const size_t h)
165 : Node(NodeType::LEAF), key(std::move(k)), value(std::move(v)), hash(h)
166 {
167 // Empty.
168 }
169 };
170
171 struct BitmapNode : public Node
172 {
173 std::uint32_t bitmap = 0;
175
176 BitmapNode(const std::uint32_t b, Array<NodePtr> c)
177 : Node(NodeType::BITMAP), bitmap(b), children(std::move(c))
178 {
179 // Empty.
180 }
181 };
182
183 struct CollisionNode : public Node
184 {
185 size_t hash = 0;
187
188 CollisionNode(const size_t h, Array<std::pair<Key, T>> e)
189 : Node(NodeType::COLLISION), hash(h), entries(std::move(e))
190 {
191 // Empty.
192 }
193 };
194
198 size_t size_ = 0;
199
201 const Hash_Fct_Ptr hash_fct,
202 Cmp cmp,
203 const size_t size)
204 : root_(std::move(root)), hash_fct_(hash_fct), cmp_(std::move(cmp)), size_(size)
205 {
206 // Empty.
207 }
208
209 [[nodiscard]] static size_t bitpos(const size_t hash, const size_t shift) noexcept
210 {
211 return (hash >> shift) & LEVEL_MASK;
212 }
213
214 [[nodiscard]] static std::uint32_t bit(const size_t pos) noexcept
215 {
216 return std::uint32_t{1} << pos;
217 }
218
219 [[nodiscard]] static size_t index(const std::uint32_t bitmap,
220 const std::uint32_t bit_value) noexcept
221 {
222 return std::popcount(bitmap & (bit_value - 1));
223 }
224
225 [[nodiscard]] static NodePtr make_leaf(const Key &key, const T &value, const size_t hash)
226 {
227 return std::make_shared<LeafNode>(key, value, hash);
228 }
229
230 [[nodiscard]] static NodePtr make_leaf(const Key &key, T &&value, const size_t hash)
231 {
232 return std::make_shared<LeafNode>(key, std::move(value), hash);
233 }
234
235 [[nodiscard]] static NodePtr make_leaf_from_value(const Key &key,
236 const T *value,
238 const size_t hash)
239 {
240 return movable_value != nullptr
241 ? make_leaf(key, std::move(*movable_value), hash)
242 : make_leaf(key, *value, hash);
243 }
244
245 static void append_entry(Array<std::pair<Key, T>> &entries,
246 const Key &key,
247 const T *value,
249 {
250 if (movable_value != nullptr)
251 entries.append(std::pair<Key, T>{key, std::move(*movable_value)});
252 else
253 entries.append(std::pair<Key, T>{key, *value});
254 }
255
257 const NodePtr &n2,
258 const size_t shift) const
259 {
260 const size_t h1 = n1->type == NodeType::LEAF
261 ? static_cast<const LeafNode *>(n1.get())->hash
262 : static_cast<const CollisionNode *>(n1.get())->hash;
263 const size_t h2 = n2->type == NodeType::LEAF
264 ? static_cast<const LeafNode *>(n2.get())->hash
265 : static_cast<const CollisionNode *>(n2.get())->hash;
266
267 const size_t p1 = bitpos(h1, shift);
268 const size_t p2 = bitpos(h2, shift);
269
270 if (p1 != p2)
271 {
272 Array<NodePtr> children;
273 children.reserve(2);
274 if (p1 < p2)
275 {
276 children.append(n1);
277 children.append(n2);
278 }
279 else
280 {
281 children.append(n2);
282 children.append(n1);
283 }
284 return std::make_shared<BitmapNode>(bit(p1) | bit(p2), std::move(children));
285 }
286
287 Array<NodePtr> children;
288 children.append(merge_leaves(n1, n2, shift + BITS_PER_LEVEL));
289 return std::make_shared<BitmapNode>(bit(p1), std::move(children));
290 }
291
293 const Key &key,
294 const T *value,
296 const size_t hash,
297 const size_t shift,
298 const bool replace,
299 bool &added,
300 bool &changed) const
301 {
302 if (node == nullptr)
303 {
304 added = true;
305 changed = true;
306 return make_leaf_from_value(key, value, movable_value, hash);
307 }
308
309 if (node->type == NodeType::LEAF)
310 {
311 const auto leaf = static_cast<const LeafNode *>(node.get());
312 if (cmp_(key, leaf->key))
313 {
314 added = false;
315 if (not replace)
316 {
317 changed = false;
318 return node;
319 }
320
321 changed = true;
322 return make_leaf_from_value(leaf->key, value, movable_value, leaf->hash);
323 }
324
325 if (leaf->hash == hash)
326 {
328 entries.reserve(2);
329 entries.append(std::pair<Key, T>{leaf->key, leaf->value});
330 append_entry(entries, key, value, movable_value);
331 added = true;
332 changed = true;
333 return std::make_shared<CollisionNode>(hash, std::move(entries));
334 }
335
337 added = true;
338 changed = true;
339 return merge_leaves(node, new_leaf, shift);
340 }
341
342 if (node->type == NodeType::BITMAP)
343 {
344 const auto bnode = static_cast<const BitmapNode *>(node.get());
345 const size_t pos = bitpos(hash, shift);
346 const std::uint32_t b = bit(pos);
347 const size_t idx = index(bnode->bitmap, b);
348
349 if ((bnode->bitmap & b) == 0)
350 {
352 new_children.reserve(bnode->children.size() + 1);
353 for (size_t i = 0; i < idx; ++i)
354 new_children.append(bnode->children[i]);
356 for (size_t i = idx; i < bnode->children.size(); ++i)
357 new_children.append(bnode->children[i]);
358
359 added = true;
360 changed = true;
361 return std::make_shared<BitmapNode>(bnode->bitmap | b, std::move(new_children));
362 }
363
364 const NodePtr child = bnode->children[idx];
365 NodePtr new_child = insert_impl(child, key, value, movable_value, hash,
367 if (not changed)
368 return node;
369
371 new_children[idx] = std::move(new_child);
372 return std::make_shared<BitmapNode>(bnode->bitmap, std::move(new_children));
373 }
374
375 if (node->type == NodeType::COLLISION)
376 {
377 const auto cnode = static_cast<const CollisionNode *>(node.get());
378 if (hash != cnode->hash)
379 {
381 added = true;
382 changed = true;
383 return merge_leaves(node, new_leaf, shift);
384 }
385
386 if (not replace)
387 for (const auto &entry : cnode->entries)
388 if (cmp_(key, entry.first))
389 {
390 added = false;
391 changed = false;
392 return node;
393 }
394
396 new_entries.reserve(cnode->entries.size() + 1);
397 bool found = false;
398 for (const auto &entry : cnode->entries)
399 if (cmp_(key, entry.first) and not found)
400 {
402 found = true;
403 }
404 else
405 new_entries.append(entry);
406
407 if (not found)
408 {
410 added = true;
411 }
412 else
413 added = false;
414
415 changed = true;
416 return std::make_shared<CollisionNode>(hash, std::move(new_entries));
417 }
418
419 changed = false;
420 return node;
421 }
422
424 const Key &key,
425 const size_t hash,
426 const size_t shift,
427 bool &removed) const
428 {
429 if (node == nullptr)
430 return nullptr;
431
432 if (node->type == NodeType::LEAF)
433 {
434 const auto leaf = static_cast<const LeafNode *>(node.get());
435 if (cmp_(key, leaf->key))
436 {
437 removed = true;
438 return nullptr;
439 }
440 return node;
441 }
442
443 if (node->type == NodeType::BITMAP)
444 {
445 const auto bnode = static_cast<const BitmapNode *>(node.get());
446 const size_t pos = bitpos(hash, shift);
447 const std::uint32_t b = bit(pos);
448 if ((bnode->bitmap & b) == 0)
449 return node;
450
451 const size_t idx = index(bnode->bitmap, b);
452 const NodePtr child = bnode->children[idx];
453 NodePtr new_child = erase_impl(child, key, hash, shift + BITS_PER_LEVEL, removed);
454 if (new_child == child)
455 return node;
456
457 if (new_child == nullptr)
458 {
459 if (bnode->bitmap == b)
460 return nullptr;
461
462 if (std::popcount(bnode->bitmap) == 2)
463 {
464 const size_t other_idx = idx == 0 ? 1 : 0;
465 NodePtr other_child = bnode->children[other_idx];
466 if (other_child->type == NodeType::LEAF or
468 return other_child;
469 }
470
472 new_children.reserve(bnode->children.size() - 1);
473 for (size_t i = 0; i < bnode->children.size(); ++i)
474 if (i != idx)
475 new_children.append(bnode->children[i]);
476 return std::make_shared<BitmapNode>(bnode->bitmap & ~b, std::move(new_children));
477 }
478
480 new_children[idx] = std::move(new_child);
481 if (new_children.size() == 1 and
482 (new_children[0]->type == NodeType::LEAF or
484 return new_children[0];
485 return std::make_shared<BitmapNode>(bnode->bitmap, std::move(new_children));
486 }
487
488 if (node->type == NodeType::COLLISION)
489 {
490 const auto cnode = static_cast<const CollisionNode *>(node.get());
491 if (hash != cnode->hash)
492 return node;
493
495 new_entries.reserve(cnode->entries.size());
496 for (const auto &entry : cnode->entries)
497 if (cmp_(key, entry.first))
498 removed = true;
499 else
500 new_entries.append(entry);
501
502 if (not removed)
503 return node;
504 if (new_entries.size() == 1)
505 return std::make_shared<LeafNode>(new_entries[0].first,
506 std::move(new_entries[0].second),
507 hash);
508 return std::make_shared<CollisionNode>(hash, std::move(new_entries));
509 }
510
511 return node;
512 }
513
514 [[nodiscard]] const T *find_impl(const NodePtr &node,
515 const Key &key,
516 const size_t hash,
517 const size_t shift) const
518 {
519 if (node == nullptr)
520 return nullptr;
521
522 if (node->type == NodeType::LEAF)
523 {
524 const auto leaf = static_cast<const LeafNode *>(node.get());
525 return cmp_(key, leaf->key) ? &leaf->value : nullptr;
526 }
527
528 if (node->type == NodeType::BITMAP)
529 {
530 const auto bnode = static_cast<const BitmapNode *>(node.get());
531 const size_t pos = bitpos(hash, shift);
532 const std::uint32_t b = bit(pos);
533 if ((bnode->bitmap & b) == 0)
534 return nullptr;
535 return find_impl(bnode->children[index(bnode->bitmap, b)],
536 key, hash, shift + BITS_PER_LEVEL);
537 }
538
539 if (node->type == NodeType::COLLISION)
540 {
541 const auto cnode = static_cast<const CollisionNode *>(node.get());
542 if (hash != cnode->hash)
543 return nullptr;
544 for (const auto &entry : cnode->entries)
545 if (cmp_(key, entry.first))
546 return &entry.second;
547 }
548
549 return nullptr;
550 }
551
552 [[nodiscard]] bool hashes_match_slot(const NodePtr &node,
553 const size_t shift,
554 const size_t pos) const
555 {
556 if (node == nullptr)
557 return false;
558 if (node->type == NodeType::LEAF)
559 return bitpos(static_cast<const LeafNode *>(node.get())->hash, shift) == pos;
560 if (node->type == NodeType::COLLISION)
561 return bitpos(static_cast<const CollisionNode *>(node.get())->hash, shift) == pos;
562
563 const auto bnode = static_cast<const BitmapNode *>(node.get());
564 for (size_t i = 0; i < bnode->children.size(); ++i)
565 if (not hashes_match_slot(bnode->children[i], shift, pos))
566 return false;
567 return true;
568 }
569
571 {
572 for (size_t i = 0; i < node.entries.size(); ++i)
573 for (size_t j = i + 1; j < node.entries.size(); ++j)
574 if (cmp_(node.entries[i].first, node.entries[j].first))
575 return false;
576 return true;
577 }
578
579 [[nodiscard]] bool verify_rec(const NodePtr &node, const size_t shift, size_t &count) const
580 {
581 count = 0;
582 if (node == nullptr)
583 return true;
584
585 if (node->type == NodeType::LEAF)
586 {
587 const auto leaf = static_cast<const LeafNode *>(node.get());
588 if (hash_fct_(leaf->key) != leaf->hash)
589 return false;
590 count = 1;
591 return true;
592 }
593
594 if (node->type == NodeType::COLLISION)
595 {
596 const auto cnode = static_cast<const CollisionNode *>(node.get());
597 if (cnode->entries.size() < 2 or not collision_keys_are_unique(*cnode))
598 return false;
599 for (const auto &entry : cnode->entries)
600 if (hash_fct_(entry.first) != cnode->hash)
601 return false;
602 count = cnode->entries.size();
603 return true;
604 }
605
606 if (node->type == NodeType::BITMAP)
607 {
608 const auto bnode = static_cast<const BitmapNode *>(node.get());
609 const size_t child_count = std::popcount(bnode->bitmap);
610 if (child_count == 0 or child_count != bnode->children.size())
611 return false;
612 if (bnode->children.size() == 1 and
613 (bnode->children[0]->type == NodeType::LEAF or
614 bnode->children[0]->type == NodeType::COLLISION))
615 return false;
616
617 size_t idx = 0;
618 size_t total = 0;
619 for (size_t pos = 0; pos < BRANCHING_FACTOR; ++pos)
620 {
621 const std::uint32_t b = bit(pos);
622 if ((bnode->bitmap & b) == 0)
623 continue;
624
625 if (idx >= bnode->children.size())
626 return false;
627 const NodePtr &child = bnode->children[idx++];
628 if (child == nullptr or not hashes_match_slot(child, shift, pos))
629 return false;
630
631 size_t subtree_count = 0;
632 if (not verify_rec(child, shift + BITS_PER_LEVEL, subtree_count))
633 return false;
634 ah_overflow_error_if(total > std::numeric_limits<size_t>::max() - subtree_count)
635 << "PersistentHashMap::verify(): node count would overflow";
637 }
638
639 if (idx != bnode->children.size())
640 return false;
641 count = total;
642 return true;
643 }
644
645 return false;
646 }
647
648 static void collect_keys(const NodePtr &node, Array<Key> &out)
649 {
650 if (node == nullptr)
651 return;
652 if (node->type == NodeType::LEAF)
653 {
654 out.append(static_cast<const LeafNode *>(node.get())->key);
655 return;
656 }
657 if (node->type == NodeType::COLLISION)
658 {
659 const auto cnode = static_cast<const CollisionNode *>(node.get());
660 for (const auto &entry : cnode->entries)
661 out.append(entry.first);
662 return;
663 }
664
665 const auto bnode = static_cast<const BitmapNode *>(node.get());
666 for (size_t i = 0; i < bnode->children.size(); ++i)
667 collect_keys(bnode->children[i], out);
668 }
669
670 static void collect_items(const NodePtr &node, Array<std::pair<Key, T>> &out)
671 {
672 if (node == nullptr)
673 return;
674 if (node->type == NodeType::LEAF)
675 {
676 const auto leaf = static_cast<const LeafNode *>(node.get());
677 out.append(std::pair<Key, T>{leaf->key, leaf->value});
678 return;
679 }
680 if (node->type == NodeType::COLLISION)
681 {
682 const auto cnode = static_cast<const CollisionNode *>(node.get());
683 for (const auto &entry : cnode->entries)
684 out.append(entry);
685 return;
686 }
687
688 const auto bnode = static_cast<const BitmapNode *>(node.get());
689 for (size_t i = 0; i < bnode->children.size(); ++i)
690 collect_items(bnode->children[i], out);
691 }
692
693 [[nodiscard]] size_t size_after_insert(const bool added) const
694 {
695 if (not added)
696 return size_;
697 ah_overflow_error_if(size_ == std::numeric_limits<size_t>::max())
698 << "PersistentHashMap: size would overflow";
699 return size_ + 1;
700 }
701
702public:
713 const Cmp &cmp = Cmp())
714 : hash_fct_(hash_fct), cmp_(cmp)
715 {
717 << "PersistentHashMap: hash function must not be null";
718 }
719
725 [[nodiscard]] size_t size() const noexcept { return size_; }
726
732 [[nodiscard]] bool is_empty() const noexcept { return size_ == 0; }
733
743 [[nodiscard]] PersistentHashMap insert(const Key &key, const T &value) const
744 {
745 bool added = false;
746 bool changed = false;
747 NodePtr new_root = insert_impl(root_, key, &value, nullptr, hash_fct_(key), 0,
748 false, added, changed);
749 if (not changed)
750 return *this;
752 }
753
763 [[nodiscard]] PersistentHashMap insert(const Key &key, T &&value) const
764 {
765 bool added = false;
766 bool changed = false;
767 NodePtr new_root = insert_impl(root_, key, nullptr, &value, hash_fct_(key), 0,
768 false, added, changed);
769 if (not changed)
770 return *this;
772 }
773
782 [[nodiscard]] PersistentHashMap insert_or_assign(const Key &key, const T &value) const
783 {
784 bool added = false;
785 bool changed = false;
786 NodePtr new_root = insert_impl(root_, key, &value, nullptr, hash_fct_(key), 0,
787 true, added, changed);
789 }
790
800 {
801 bool added = false;
802 bool changed = false;
803 NodePtr new_root = insert_impl(root_, key, nullptr, &value, hash_fct_(key), 0,
804 true, added, changed);
806 }
807
816 [[nodiscard]] PersistentHashMap erase(const Key &key) const
817 {
818 bool removed = false;
820 if (not removed)
821 return *this;
822 return PersistentHashMap(std::move(new_root), hash_fct_, cmp_, size_ - 1);
823 }
824
832 [[nodiscard]] bool contains(const Key &key) const
833 {
834 return find(key) != nullptr;
835 }
836
845 [[nodiscard]] const T *find(const Key &key) const
846 {
847 return find_impl(root_, key, hash_fct_(key), 0);
848 }
849
858 {
860 out.reserve(size());
862 return out;
863 }
864
873 {
875 out.reserve(size());
877 return out;
878 }
879
889 [[nodiscard]] bool verify() const
890 {
891 size_t count = 0;
892 return verify_rec(root_, 0, count) and count == size_;
893 }
894};
895
896} // namespace Aleph
897
898#endif // TPL_PERSISTENT_HASH_MAP_H
Exception handling system with formatted messages for Aleph-w.
#define ah_domain_error_unless(C)
Throws std::domain_error if condition does NOT hold.
Definition ah-errors.H:543
#define ah_overflow_error_if(C)
Throws std::overflow_error if condition holds.
Definition ah-errors.H:468
Standard functor implementations and comparison objects.
long double h
Definition btreepic.C:154
size_t size_t int32_t value
Definition ca-c-api.h:116
size_t size_t int32_t * out
Definition ca-c-api.h:120
Simple dynamic array with automatic resizing and functional operations.
Definition tpl_array.H:138
constexpr size_t size() const noexcept
Return the number of elements stored in the stack.
Definition tpl_array.H:365
T & append(const T &data)
Append a copy of data
Definition tpl_array.H:250
void reserve(size_t cap)
Reserves cap cells into the array.
Definition tpl_array.H:320
Immutable unordered map backed by a Hash Array Mapped Trie (HAMT).
PersistentHashMap(const Hash_Fct_Ptr hash_fct=dft_hash_ptr_fct< Key >, const Cmp &cmp=Cmp())
Construct an empty persistent hash map.
bool is_empty() const noexcept
Return true when this version has no bindings.
bool hashes_match_slot(const NodePtr &node, const size_t shift, const size_t pos) const
static constexpr size_t BRANCHING_FACTOR
NodePtr insert_impl(const NodePtr &node, const Key &key, const T *value, T *movable_value, const size_t hash, const size_t shift, const bool replace, bool &added, bool &changed) const
NodeType
Types of polymorphic nodes in the HAMT.
@ LEAF
Terminal leaf node that stores exactly one (key, value) pair.
@ BITMAP
Compressed internal node that uses a 32-bit bitmap for routing.
@ COLLISION
Terminal node that stores multiple (key, value) pairs with the exact same hash.
static NodePtr make_leaf(const Key &key, T &&value, const size_t hash)
static NodePtr make_leaf_from_value(const Key &key, const T *value, T *movable_value, const size_t hash)
static size_t index(const std::uint32_t bitmap, const std::uint32_t bit_value) noexcept
static constexpr size_t BITS_PER_LEVEL
PersistentHashMap insert(const Key &key, T &&value) const
Return a new version with key inserted if absent, moving value.
size_t size_after_insert(const bool added) const
PersistentHashMap insert_or_assign(const Key &key, const T &value) const
Return a new version with key bound to value.
bool collision_keys_are_unique(const CollisionNode &node) const
bool verify() const
Verify HAMT routing, collision, uniqueness and size invariants.
std::shared_ptr< const Node > NodePtr
static std::uint32_t bit(const size_t pos) noexcept
NodePtr erase_impl(const NodePtr &node, const Key &key, const size_t hash, const size_t shift, bool &removed) const
Array< std::pair< Key, T > > items() const
Return all key/value bindings in unspecified order.
bool verify_rec(const NodePtr &node, const size_t shift, size_t &count) const
size_t(*)(const Key &) Hash_Fct_Ptr
Hash function pointer type used by this map.
static NodePtr make_leaf(const Key &key, const T &value, const size_t hash)
PersistentHashMap insert(const Key &key, const T &value) const
Return a new version with key inserted if absent.
Array< Key > keys() const
Return all keys in unspecified order.
static size_t bitpos(const size_t hash, const size_t shift) noexcept
NodePtr merge_leaves(const NodePtr &n1, const NodePtr &n2, const size_t shift) const
static void collect_items(const NodePtr &node, Array< std::pair< Key, T > > &out)
bool contains(const Key &key) const
Test whether key is present.
PersistentHashMap erase(const Key &key) const
Return a new version without key.
static constexpr size_t LEVEL_MASK
const T * find_impl(const NodePtr &node, const Key &key, const size_t hash, const size_t shift) const
PersistentHashMap(NodePtr root, const Hash_Fct_Ptr hash_fct, Cmp cmp, const size_t size)
static void collect_keys(const NodePtr &node, Array< Key > &out)
PersistentHashMap insert_or_assign(const Key &key, T &&value) const
Return a new version with key bound to moved value.
static void append_entry(Array< std::pair< Key, T > > &entries, const Key &key, const T *value, T *movable_value)
const T * find(const Key &key) const
Find a mapped value.
size_t size() const noexcept
Return the number of bindings stored in this version.
__gmp_expr< T, __gmp_binary_expr< __gmp_expr< T, U >, unsigned long int, __gmp_root_function > > root(const __gmp_expr< T, U > &expr, unsigned long int l)
Definition gmpfrxx.h:4071
int cmp(const __gmp_expr< T, U > &expr1, const __gmp_expr< V, W > &expr2)
Definition gmpfrxx.h:4129
size_t blossom_maximum_cardinality_matching(const GT &g, DynDlist< typename GT::Arc * > &matching, SA sa=SA())
Alias of compute_maximum_cardinality_general_matching().
Definition Blossom.H:466
Standard hash functions for Aleph types.
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
and
Check uniqueness with explicit hash + equality functors.
std::decay_t< typename HeadC::Item_Type > T
Definition ah-zip.H:105
void replace(Itor beg, const Itor &end, const T &old_value, const T &new_value)
Replace elements equal to a value.
Definition ahAlgo.H:815
Itor::difference_type count(const Itor &beg, const Itor &end, const T &value)
Count elements equal to a value.
Definition ahAlgo.H:127
STL namespace.
BitmapNode(const std::uint32_t b, Array< NodePtr > c)
CollisionNode(const size_t h, Array< std::pair< Key, T > > e)
Polymorphic base node managed by std::shared_ptr for structural sharing.
static int * k
Dynamic array container with automatic resizing.