71#ifndef TPL_PATRICIA_TRIE_H
72#define TPL_PATRICIA_TRIE_H
87namespace patricia_trie_detail
98template <
typename UInt>
102 static constexpr size_t bit_width = std::numeric_limits<UInt>::digits;
114 const size_t bit_index)
noexcept
128 const UInt rhs)
noexcept
146 template <
typename Node>
148 const UInt key)
noexcept
150 while (node !=
nullptr and not node->leaf)
151 node = node->child[
bit_at(key, node->bit_index) ? 1 : 0].get();
164 template <
typename Node>
178 template <
typename Node>
185 out.append(node->key);
202 template <
typename Node>
205 const UInt key)
noexcept
212 if (
root->key != key)
220 std::unique_ptr<Node> * link = &
root;
221 while ((*link)->leaf ==
false)
224 link = &(*link)->child[
bit_at(key, (*link)->bit_index) ? 1 : 0];
227 if ((*link)->key != key)
231 const size_t side =
bit_at(key, parent->bit_index) ? 1 : 0;
247 template <
typename Node>
249 const size_t bit_index,
271 template <
typename Node>
282 if constexpr (
requires { node->value.has_value(); })
283 if (
not node->value.has_value())
289 if constexpr (
requires { node->value.has_value(); })
290 if (node->value.has_value())
296 if (node->child[0] ==
nullptr or node->child[1] ==
nullptr)
321template <
typename UInt>
322requires (std::is_integral_v<UInt>
and std::is_unsigned_v<UInt>
and
323 not std::is_same_v<UInt, bool>)
331 static constexpr size_t bit_width = std::numeric_limits<Key>::digits;
338 size_t bit_index = 0;
339 std::array<std::unique_ptr<Node>, 2> child{};
342 explicit Node(
const size_t bit)
noexcept : leaf(
false), bit_index(bit) {}
353 auto dst = src->
leaf ? std::make_unique<Node>(src->
key)
354 : std::make_unique<Node>(src->
bit_index);
357 dst->child[0] = clone_node(src->
child[0].get());
358 dst->child[1] = clone_node(src->
child[1].get());
379 : root_(clone_node(
other.root_.get())), size_(
other.size_)
391 root_ = clone_node(
other.root_.get());
402 : root_(std::move(
other.root_)), size_(
other.size_)
416 root_ = std::move(
other.root_);
457 const Node * leaf = Detail::leaf_for(root_.get(), key);
458 return leaf !=
nullptr and leaf->
key == key;
468 if (root_ ==
nullptr)
470 root_ = std::make_unique<Node>(key);
475 const Node *
existing = Detail::leaf_for(root_.get(), key);
480 auto * link = &root_;
481 while ((*link)->leaf ==
false and (*link)->bit_index <
diff_bit)
482 link = &(*link)->child[Detail::bit_at(key, (*link)->bit_index) ? 1 : 0];
485 const size_t side = Detail::bit_at(key,
diff_bit) ? 1 : 0;
486 branch->child[
side] = std::make_unique<Node>(key);
488 *link = std::move(
branch);
500 return Detail::erase_key(root_, size_, key);
511 Detail::collect_keys(root_.get(), result);
527 const bool ok = Detail::check_invariants_rec(root_.get(), 0,
false,
counted);
544template <
typename UInt,
typename T>
545requires (std::is_integral_v<UInt>
and std::is_unsigned_v<UInt>
and
546 not std::is_same_v<UInt, bool>)
557 static constexpr size_t bit_width = std::numeric_limits<Key>::digits;
564 size_t bit_index = 0;
566 std::array<std::unique_ptr<Node>, 2> child{};
568 template <
typename U>
571 explicit Node(
const size_t bit)
noexcept : leaf(
false), bit_index(bit) {}
579 requires std::is_copy_constructible_v<Value>
583 auto dst = src->leaf ? std::make_unique<Node>(src->key, *src->value)
584 : std::make_unique<Node>(src->bit_index);
587 dst->child[0] = clone_node(src->child[0].get());
588 dst->child[1] = clone_node(src->child[1].get());
593 template <
typename U>
596 if (root_ ==
nullptr)
598 root_ = std::make_unique<Node>(key, std::forward<U>(
value));
603 const Node *
existing = Detail::leaf_for(root_.get(), key);
608 auto * link = &root_;
609 while ((*link)->leaf ==
false and (*link)->bit_index <
diff_bit)
610 link = &(*link)->child[Detail::bit_at(key, (*link)->bit_index) ? 1 : 0];
613 const size_t side = Detail::bit_at(key,
diff_bit) ? 1 : 0;
614 branch->child[
side] = std::make_unique<Node>(key, std::forward<U>(
value));
616 *link = std::move(
branch);
637 requires std::is_copy_constructible_v<Value>
638 : root_(clone_node(
other.root_.get())), size_(
other.size_)
647 requires std::is_copy_constructible_v<Value>
651 root_ = clone_node(
other.root_.get());
662 : root_(std::move(
other.root_)), size_(
other.size_)
676 root_ = std::move(
other.root_);
719 return insert_impl(key,
value);
734 return insert_impl(key, std::move(
value));
750 insert_impl(key, std::move(
value));
760 return Detail::erase_key(root_, size_, key);
770 return find(key) !=
nullptr;
781 const Node * leaf = Detail::leaf_for(root_.get(), key);
782 return (leaf !=
nullptr and leaf->
key == key) ? &*leaf->
value :
nullptr;
794 Node * leaf = Detail::leaf_for(root_.get(), key);
795 return (leaf !=
nullptr and leaf->
key == key) ? &*leaf->
value :
nullptr;
806 Detail::collect_keys(root_.get(), result);
823 const bool ok = Detail::check_invariants_rec(root_.get(), 0,
false,
counted);
WeightedDigraph::Node Node
size_t size_t int32_t value
size_t size_t int32_t * out
Simple dynamic array with automatic resizing and functional operations.
void reserve(size_t cap)
Reserves cap cells into the array.
Compressed bitwise map for unsigned integral keys.
bool insert(const Key key, Value &&value)
Insert key with value moved in, only if key is absent.
PatriciaMap & operator=(const PatriciaMap &other)
Deep-copy assignment.
Array< Key > keys() const
Return all stored keys.
PatriciaMap()=default
Construct an empty map.
T Value
Mapped value type stored at each leaf.
size_t size() const noexcept
Return the number of stored key-value pairs.
bool erase(const Key key) noexcept
Remove key if present.
std::unique_ptr< Node > root_
bool check_invariants() const noexcept
Verify structural invariants recursively.
bool insert_impl(const Key key, U &&value)
bool insert(const Key key, const Value &value)
Insert key with a copy of value, only if key is absent.
static std::unique_ptr< Node > clone_node(const Node *src)
void insert_or_assign(const Key key, Value value)
Insert key or overwrite the mapped value if key exists.
void clear() noexcept
Remove every key-value pair from the map.
const Value * find(const Key key) const noexcept
Look up key.
PatriciaMap(PatriciaMap &&other) noexcept
Move constructor.
PatriciaMap(const PatriciaMap &other)
Deep-copy constructor.
bool contains(const Key key) const noexcept
Check whether key is stored.
Value * find(const Key key) noexcept
Mutable lookup overload.
PatriciaMap & operator=(PatriciaMap &&other) noexcept
Move assignment.
~PatriciaMap()=default
Destructor.
bool is_empty() const noexcept
Check whether the map has no key-value pairs.
UInt Key
Key type stored by the map.
Compressed bitwise set for unsigned integral keys.
bool check_invariants() const noexcept
Verify structural invariants recursively.
static std::unique_ptr< Node > clone_node(const Node *src)
PatriciaSet(const PatriciaSet &other)
Deep-copy constructor.
size_t size() const noexcept
Return the number of stored keys.
std::unique_ptr< Node > root_
bool insert(const Key key)
Insert key if absent.
PatriciaSet & operator=(const PatriciaSet &other)
Deep-copy assignment.
bool erase(const Key key) noexcept
Remove key if present.
PatriciaSet()=default
Construct an empty set.
~PatriciaSet()=default
Destructor.
UInt Key
Key type stored by the set.
PatriciaSet(PatriciaSet &&other) noexcept
Move constructor.
void clear() noexcept
Remove every key from the set.
PatriciaSet & operator=(PatriciaSet &&other) noexcept
Move assignment.
bool is_empty() const noexcept
Check whether the set has no keys.
bool contains(const Key key) const noexcept
Check whether key is stored.
Array< Key > keys() const
Return all stored keys.
Minimal std::expected-style result type for C++20.
__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)
size_t blossom_maximum_cardinality_matching(const GT &g, DynDlist< typename GT::Arc * > &matching, SA sa=SA())
Alias of compute_maximum_cardinality_general_matching().
Main namespace for Aleph-w library functions.
size_t size(Node *root) noexcept
and
Check uniqueness with explicit hash + equality functors.
std::decay_t< typename HeadC::Item_Type > T
Itor find(const Itor &beg, const Itor &end, const T &value)
Find the first element equal to a value.
bool diff(const C1 &c1, const C2 &c2, Eq e=Eq())
Check if two containers differ.
std::optional< Value > value
Node(const size_t bit) noexcept
Node(const Key k) noexcept
Node(const size_t bit) noexcept
std::array< std::unique_ptr< Node >, 2 > child
Shared fixed-width bit-trie algorithms for Patricia containers.
static size_t first_differing_bit(const UInt lhs, const UInt rhs) noexcept
Find the first bit where two keys differ.
static const Node * leaf_for(const Node *node, const UInt key) noexcept
Find the leaf reached by routing a key through a Patricia tree.
static Node * leaf_for(Node *node, const UInt key) noexcept
Mutable overload of leaf_for().
static bool erase_key(std::unique_ptr< Node > &root, size_t &size, const UInt key) noexcept
Remove a key using the shared Patricia deletion algorithm.
static bool check_invariants_rec(const Node *node, const size_t parent_bit, const bool has_parent, size_t &counted) noexcept
Recursively verify Patricia structural invariants.
static constexpr size_t bit_width
Number of significant bits in UInt.
static bool bit_at(const UInt key, const size_t bit_index) noexcept
Return the bit at a most-significant-bit-first index.
static void collect_keys(const Node *node, Array< UInt > &out)
Append all leaf keys in a Patricia subtree.
static bool subtree_matches(const Node *node, const size_t bit_index, const bool expected) noexcept
Check that every leaf in a subtree matches a routing bit.
Dynamic array container with automatic resizing.