91#ifndef TPL_RADIX_TREE_H
92#define TPL_RADIX_TREE_H
118template <
typename T,
typename Char =
char>
123 using Key = std::basic_string<Char>;
140 static constexpr size_t npos =
static_cast<size_t>(-1);
152 for (
const auto &
kv : node->children)
154 return kv.second.get();
160 for (
size_t i = 0; i < node->children.size(); ++i)
161 if (node->children[i].first == c)
168 node->
children.append(std::make_pair(c, std::move(child)));
175 const size_t last = node->
children.size() - 1;
178 std::ignore = node->
children.remove_last();
185 const size_t max_n = std::min(label.size(), key.size() -
key_off);
199 template <
typename U>
209 if (
cur->value.has_value())
215 cur->value.emplace(std::forward<U>(
value));
220 const Char c = key[i];
225 auto leaf = std::make_unique<Node>(key.substr(i));
226 leaf->value.emplace(std::forward<U>(
value));
234 const size_t remaining = key.size() - i;
237 if (
lcp == label.size())
250 split->children.reserve(
lcp == remaining ? 1 : 2);
252 if (
lcp == remaining)
259 auto leaf = std::make_unique<Node>(key.substr(i +
lcp));
260 leaf->value.emplace(std::forward<U>(
value));
268 split->children.append(std::make_pair(
child_first, std::unique_ptr<Node>{}));
269 std::unique_ptr<Node>
detached = std::move(
cur->children[
slot].second);
281 while (i < key.size())
283 const Char c = key[i];
285 if (child ==
nullptr)
289 const size_t remaining = key.size() - i;
290 if (label.size() > remaining
or key.compare(i, label.size(), label) != 0)
301 if (node->
value.has_value())
313 requires std::is_copy_constructible_v<T>
315 auto dst = std::make_unique<Node>(src->edge_label);
316 if (src->value.has_value())
317 dst->value.emplace(*src->value);
318 dst->children.reserve(src->children.size());
319 for (
const auto &
kv : src->children)
376 requires std::is_copy_constructible_v<T>
386 requires std::is_copy_constructible_v<T>
476 while (i < key.size())
478 const Char c = key[i];
485 const size_t remaining = key.size() - i;
486 if (label.size() > remaining
or key.compare(i, label.size(), label) != 0)
494 if (
not cur->value.has_value())
506 Node *node = f.parent->children[f.slot].second.get();
518 f.parent->children[f.slot].second = std::move(
only.second);
534 return find(key) !=
nullptr;
547 return (n !=
nullptr and n->
value.has_value()) ? &*n->
value :
nullptr;
560 return (n !=
nullptr and n->
value.has_value()) ?
const_cast<T *
>(&*n->
value) :
nullptr;
580 std::optional<Key>
best;
584 if (
cur->value.has_value())
587 while (i < key.size())
589 const Char c = key[i];
591 if (child ==
nullptr)
595 const size_t remaining = key.size() - i;
596 if (label.size() > remaining
or key.compare(i, label.size(), label) != 0)
601 if (
cur->value.has_value())
602 best = key.substr(0, i);
626 if (child ==
nullptr)
630 const size_t remaining =
prefix.size() - i;
633 if (
lcp < label.size())
635 if (
lcp != remaining)
688 if (node->
value.has_value())
699 for (
size_t i = 0; i < node->
children.size(); ++i)
700 for (
size_t j = i + 1; j < node->
children.size(); ++j)
706 if (
kv.second->edge_label.empty()
or kv.second->edge_label[0] !=
kv.first)
Exception handling system with formatted messages for Aleph-w.
size_t size_t int32_t value
size_t size_t int32_t * out
Simple dynamic array with automatic resizing and functional operations.
constexpr bool is_empty() const noexcept
Checks if the container is empty.
T & append(const T &data)
Append a copy of data
T & get_last() noexcept
return a modifiable reference to the last element.
Compressed prefix tree mapping std::basic_string<Char> keys to values of type T.
RadixTree(RadixTree &&other)
Move constructor: other is left as a valid, empty tree.
static void remove_child_at(Node *node, const size_t idx)
Remove the child at idx in O(1) by swapping with the last slot; the (unordered) children array does n...
static bool verify_rec(const Node *node, const bool is_root, size_t &counted_values)
RadixTree()
Construct an empty tree.
bool is_empty() const noexcept
Check whether the tree holds no keys.
const T * find(const Key &key) const noexcept
Look up key.
std::basic_string< Char > Key
Key type: strings over Char.
bool insert(const Key &key, T &&value)
Insert key with value moved in, only if key is absent.
static std::unique_ptr< Node > clone_node(const Node *src)
static void add_child(Node *node, const Char c, std::unique_ptr< Node > child)
bool insert(const Key &key, const T &value)
Insert key with a copy of value, only if key is absent.
RadixTree(const RadixTree &other)
Deep-copy constructor: every node is cloned independently.
size_t size() const noexcept
Return the number of keys currently stored.
bool verify() const
Recursively verify the tree's structural invariants.
T * find(const Key &key) noexcept
Non-const overload of find(const Key&).
static constexpr size_t npos
static size_t find_child_slot(Node *node, const Char c) noexcept
static size_t common_prefix_length(const Key &label, const Key &key, const size_t key_off) noexcept
Length of the common prefix between label and key[key_off..).
bool insert_impl(const Key &key, U &&value, const bool assign_if_present=false)
Shared implementation for insert()'s copy/move overloads and for insert_or_assign(): U is deduced as ...
std::optional< Key > longest_prefix(const Key &key) const
Find the longest stored key that is a prefix of key.
~RadixTree()=default
Destructor.
std::unique_ptr< Node > root_
void insert_or_assign(const Key &key, T value)
Insert key with value, or overwrite the existing value if key is already present.
bool contains(const Key &key) const noexcept
Check whether key is present.
static void collect_keys(const Node *node, Key &prefix_acc, Array< Key > &out)
Array< Key > keys_with_prefix(const Key &prefix) const
Return every stored key that starts with prefix.
static const Node * find_child(const Node *node, const Char c) noexcept
RadixTree & operator=(RadixTree &&other)
Move assignment operator: other is left as a valid, empty tree.
bool erase(const Key &key)
Remove key if present, merging any resulting single-child, valueless node back into a compressed edge...
const Node * find_node(const Key &key) const noexcept
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.
and
Check uniqueness with explicit hash + equality functors.
std::decay_t< typename HeadC::Item_Type > T
static void prefix(Node *root, DynList< Node * > &acc)
std::vector< std::string > & split(const std::string &s, const char delim, std::vector< std::string > &elems)
Split a std::string by a single delimiter character.
Array< std::pair< Char, std::unique_ptr< Node > > > children
Dynamic array container with automatic resizing.