55#ifndef TPL_PERSISTENT_HASH_MAP_H
56#define TPL_PERSISTENT_HASH_MAP_H
111template <
typename Key,
typename T,
class Cmp = Aleph::equal_to<Key>>
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");
216 return std::uint32_t{1} << pos;
222 return std::popcount(bitmap & (
bit_value - 1));
227 return std::make_shared<LeafNode>(key,
value, hash);
232 return std::make_shared<LeafNode>(key, std::move(
value), hash);
251 entries.append(std::pair<Key, T>{key, std::move(*
movable_value)});
253 entries.append(std::pair<Key, T>{key, *
value});
258 const size_t shift)
const
261 ?
static_cast<const LeafNode *
>(n1.get())->hash
264 ?
static_cast<const LeafNode *
>(n2.get())->hash
267 const size_t p1 =
bitpos(
h1, shift);
268 const size_t p2 =
bitpos(
h2, shift);
284 return std::make_shared<BitmapNode>(
bit(p1) |
bit(p2), std::move(children));
289 return std::make_shared<BitmapNode>(
bit(p1), std::move(children));
311 const auto leaf =
static_cast<const LeafNode *
>(node.get());
312 if (
cmp_(key, leaf->key))
325 if (leaf->hash == hash)
329 entries.
append(std::pair<Key, T>{leaf->key, leaf->value});
333 return std::make_shared<CollisionNode>(hash, std::move(entries));
345 const size_t pos =
bitpos(hash, shift);
346 const std::uint32_t b =
bit(pos);
349 if ((
bnode->bitmap & b) == 0)
353 for (
size_t i = 0; i < idx; ++i)
356 for (
size_t i = idx; i <
bnode->children.size(); ++i)
378 if (hash !=
cnode->hash)
387 for (
const auto &entry :
cnode->entries)
388 if (
cmp_(key, entry.first))
398 for (
const auto &entry :
cnode->entries)
416 return std::make_shared<CollisionNode>(hash, std::move(
new_entries));
434 const auto leaf =
static_cast<const LeafNode *
>(node.get());
435 if (
cmp_(key, leaf->key))
446 const size_t pos =
bitpos(hash, shift);
447 const std::uint32_t b =
bit(pos);
448 if ((
bnode->bitmap & b) == 0)
459 if (
bnode->bitmap == b)
462 if (std::popcount(
bnode->bitmap) == 2)
464 const size_t other_idx = idx == 0 ? 1 : 0;
473 for (
size_t i = 0; i <
bnode->children.size(); ++i)
476 return std::make_shared<BitmapNode>(
bnode->bitmap & ~b, std::move(
new_children));
491 if (hash !=
cnode->hash)
496 for (
const auto &entry :
cnode->entries)
497 if (
cmp_(key, entry.first))
505 return std::make_shared<LeafNode>(
new_entries[0].first,
508 return std::make_shared<CollisionNode>(hash, std::move(
new_entries));
517 const size_t shift)
const
524 const auto leaf =
static_cast<const LeafNode *
>(node.get());
525 return cmp_(key, leaf->key) ? &leaf->value :
nullptr;
531 const size_t pos =
bitpos(hash, shift);
532 const std::uint32_t b =
bit(pos);
533 if ((
bnode->bitmap & b) == 0)
542 if (hash !=
cnode->hash)
544 for (
const auto &entry :
cnode->entries)
545 if (
cmp_(key, entry.first))
546 return &entry.second;
554 const size_t pos)
const
564 for (
size_t i = 0; i <
bnode->children.size(); ++i)
573 for (
size_t j = i + 1; j < node.
entries.
size(); ++j)
587 const auto leaf =
static_cast<const LeafNode *
>(node.get());
599 for (
const auto &entry :
cnode->entries)
609 const size_t child_count = std::popcount(
bnode->bitmap);
610 if (child_count == 0
or child_count !=
bnode->children.size())
621 const std::uint32_t b =
bit(pos);
622 if ((
bnode->bitmap & b) == 0)
625 if (idx >=
bnode->children.size())
635 <<
"PersistentHashMap::verify(): node count would overflow";
639 if (idx !=
bnode->children.size())
660 for (
const auto &entry :
cnode->entries)
661 out.append(entry.first);
666 for (
size_t i = 0; i <
bnode->children.size(); ++i)
676 const auto leaf =
static_cast<const LeafNode *
>(node.get());
677 out.append(std::pair<Key, T>{leaf->key, leaf->value});
683 for (
const auto &entry :
cnode->entries)
689 for (
size_t i = 0; i <
bnode->children.size(); ++i)
698 <<
"PersistentHashMap: size would overflow";
717 <<
"PersistentHashMap: hash function must not be null";
834 return find(key) !=
nullptr;
Exception handling system with formatted messages for Aleph-w.
#define ah_domain_error_unless(C)
Throws std::domain_error if condition does NOT hold.
#define ah_overflow_error_if(C)
Throws std::overflow_error if condition holds.
Standard functor implementations and comparison objects.
size_t size_t int32_t value
size_t size_t int32_t * out
Simple dynamic array with automatic resizing and functional operations.
constexpr size_t size() const noexcept
Return the number of elements stored in the stack.
T & append(const T &data)
Append a copy of data
void reserve(size_t cap)
Reserves cap cells into the array.
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)
int cmp(const __gmp_expr< T, U > &expr1, const __gmp_expr< V, W > &expr2)
size_t blossom_maximum_cardinality_matching(const GT &g, DynDlist< typename GT::Arc * > &matching, SA sa=SA())
Alias of compute_maximum_cardinality_general_matching().
Standard hash functions for Aleph types.
Main namespace for Aleph-w library functions.
and
Check uniqueness with explicit hash + equality functors.
std::decay_t< typename HeadC::Item_Type > T
void replace(Itor beg, const Itor &end, const T &old_value, const T &new_value)
Replace elements equal to a value.
Itor::difference_type count(const Itor &beg, const Itor &end, const T &value)
Count elements equal to a value.
BitmapNode(const std::uint32_t b, Array< NodePtr > c)
Array< NodePtr > children
Array< std::pair< Key, T > > entries
CollisionNode(const size_t h, Array< std::pair< Key, T > > e)
LeafNode(Key k, T v, const size_t h)
Polymorphic base node managed by std::shared_ptr for structural sharing.
Node(const NodeType t) noexcept
Dynamic array container with automatic resizing.