Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
prefix-tree.H
Go to the documentation of this file.
1
2/*
3 Aleph_w
4
5 Data structures & Algorithms
6 version 2.0.0b
7 https://github.com/lrleon/Aleph-w
8
9 This file is part of Aleph-w library
10
11 Copyright (c) 2002-2026 Leandro Rabindranath Leon
12
13 Permission is hereby granted, free of charge, to any person obtaining a copy
14 of this software and associated documentation files (the "Software"), to deal
15 in the Software without restriction, including without limitation the rights
16 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17 copies of the Software, and to permit persons to whom the Software is
18 furnished to do so, subject to the following conditions:
19
20 The above copyright notice and this permission notice shall be included in all
21 copies or substantial portions of the Software.
22
23 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29 SOFTWARE.
30*/
31
48#ifndef PREFIX_TREE_H
49#define PREFIX_TREE_H
50
51#include <cassert>
52#include <cstddef>
53#include <iostream>
54#include <optional>
55#include <string>
56#include <tuple>
57#include <type_traits>
58#include <utility>
59
60#include <tpl_tree_node.H>
61#include <tpl_dynArray.H>
62#include <tpl_dynList.H>
63#include <ah-errors.H>
64
65namespace Aleph {
126class Cnode : public Tree_Node<char>
127{
128 bool ends_word_ = false;
129
140 template <typename Node>
141 [[nodiscard]] static std::tuple<Node *, const char *> search_prefix_impl(Node *root,
142 const char *prefix) noexcept
143 {
144 assert(root != nullptr);
145 assert(prefix != nullptr);
146
147 auto node = root;
148 for (const char *ptr = prefix; *ptr != '\0'; ++ptr)
149 {
150 auto *child = node->search_child(*ptr);
151 if (child == nullptr)
152 return std::make_tuple(node, ptr);
153 node = child;
154 }
155
156 return std::make_tuple(node, "");
157 }
158
168 template <typename Node>
169 [[nodiscard]] static Node *search_child_impl(Node *root, const char c) noexcept
170 {
171 assert(root != nullptr);
172
173 for (auto *child = root->get_left_child(); child != nullptr; child = child->get_right_sibling())
174 {
175 const char key = child->get_key();
176 if (key == c)
177 return static_cast<Node *>(child);
178 if (key > c)
179 return nullptr;
180 }
181
182 return nullptr;
183 }
184
194 template <typename Node>
195 [[nodiscard]] static Node *greater_child_impl(Node *root, const char c) noexcept
196 {
197 assert(root != nullptr);
198
199 for (auto *child = root->get_left_child(); child != nullptr; child = child->get_right_sibling())
200 if (child->get_key() > c)
201 return static_cast<Node *>(child);
202 return nullptr;
203 }
204
211 {
212 Cnode *root_ = nullptr;
213
214 public:
216 {
217 // empty
218 }
219
221 {
222 if (root_ != nullptr)
223 {
224 root_->destroy();
225 delete root_;
226 }
227 }
228
230 {
231 return root_;
232 }
233
235 {
236 Cnode *ret = root_;
237 root_ = nullptr;
238 return ret;
239 }
240 };
241
244 {
245 Cnode **nodes_ = nullptr;
246 size_t count_ = 0;
247 bool owns_nodes_ = true;
248
249 public:
250 explicit Pending_Path_Guard(const size_t count) : nodes_(new Cnode *[count]), count_(count)
251 {
252 for (size_t i = 0; i < count_; ++i)
253 nodes_[i] = nullptr;
254 }
255
257 {
258 if (owns_nodes_)
259 for (size_t i = 0; i < count_; ++i)
260 delete nodes_[i];
261 delete[] nodes_;
262 }
263
264 [[nodiscard]] Cnode *operator [] (const size_t i) const noexcept
265 {
266 return nodes_[i];
267 }
268
269 void set(const size_t i, Cnode *node) const noexcept
270 {
271 nodes_[i] = node;
272 }
273
275 {
276 owns_nodes_ = false;
277 }
278 };
279
282 {
283 Cnode *target_ = nullptr;
286 bool active_ = true;
287
288 public:
295
297 {
298 active_ = false;
299 }
300
302 {
303 if (not active_)
304 return;
305
307 {
308 auto *child = static_cast<Cnode *>(target_->get_right_child());
309 const bool child_was_leftmost = child->is_leftmost();
312 {
313 if (previous_rightmost_ == nullptr)
314 target_->set_is_leaf(true);
315 break;
316 }
317 }
318
320 }
321 };
322
323public:
328 explicit Cnode(const char c) noexcept
329 {
330 this->get_key() = c;
331 }
332
338 {
339 return get_key();
340 }
341
350 {
353 {
354 r.append(static_cast<Cnode *>(p));
355 });
356 return r;
357 }
358
363 [[nodiscard]] std::string to_str() const
364 {
365 std::string ret(1, symbol());
367 {
368 const auto *node = static_cast<const Cnode *>(p);
369 ret += "(" + node->to_str() + ")";
370 });
371 return ret;
372 }
373
381 {
382 return ends_word_;
383 }
384
392 {
394 ends_word_ = true;
395 }
396
402 [[nodiscard]] Cnode *search_child(const char c) noexcept
403 {
404 return search_child_impl(this, c);
405 }
406
412 [[nodiscard]] const Cnode *search_child(const char c) const noexcept
413 {
414 return search_child_impl(this, c);
415 }
416
424 [[nodiscard]] Cnode *greater_child(const char c) noexcept
425 {
426 return greater_child_impl(this, c);
427 }
428
436 [[nodiscard]] const Cnode *greater_child(const char c) const noexcept
437 {
438 return greater_child_impl(this, c);
439 }
440
451 [[nodiscard]] std::tuple<Cnode *, const char *> search_prefix(const char *prefix) noexcept
452 {
453 return search_prefix_impl(this, prefix);
454 }
455
466 [[nodiscard]] std::tuple<const Cnode *, const char *> search_prefix(const char *prefix) const noexcept
467 {
468 return search_prefix_impl(this, prefix);
469 }
470
478 [[nodiscard]] const Cnode *search_word(const char *word) const noexcept
479 {
480 assert(word != nullptr);
481
482 auto node = this;
483 for (const char *ptr = word; *ptr != '\0'; ++ptr)
484 {
485 node = node->search_child(*ptr);
486 if (node == nullptr)
487 return nullptr;
488 }
489
490 return node->is_end_word() ? node : nullptr;
491 }
492
498 [[nodiscard]] bool contains(const std::string &word) const noexcept
499 {
500 return search_word(word.c_str()) != nullptr;
501 }
502
508 {
509 size_t n = is_end_word() ? 1 : 0;
510 for_each_child([&n](const Tree_Node<char> *p)
511 {
512 n += static_cast<const Cnode *>(p)->count();
513 });
514 return n;
515 }
516
528 const size_t max_word_length = 2048) const
529 {
530 auto [node, remaining] = search_prefix(prefix.c_str());
531
532 // Prefix not fully matched
533 if (*remaining != '\0')
534 return {};
535
536 assert(prefix.size() <= max_word_length);
538 std::string word(prefix);
539 word.reserve(max_word_length);
540
541 node->words_impl(word, ret_val, max_word_length);
542 return ret_val;
543 }
544
555 {
556 assert(search_child(child->symbol()) == nullptr);
557
558 if (Cnode *sibling = greater_child(child->symbol()); sibling == nullptr)
559 this->insert_rightmost_child(child);
560 else
561 sibling->insert_left_sibling(child);
562
563 return child;
564 }
565
579 bool insert_word(const std::string &word)
580 {
581 auto [pp, rem] = search_prefix(word.c_str());
582
583 if (*rem == '\0')
584 {
585 if (pp->is_end_word())
586 return false;
587 pp->mark_end_word();
588 return true;
589 }
590
591 size_t n = 0;
592 for (const char *ptr = rem; *ptr; ++ptr)
593 ++n;
594
595 Pending_Path_Guard path(n);
596 for (size_t i = 0; i < n; ++i)
597 path.set(i, new Cnode(rem[i]));
598
599 path[n - 1]->mark_end_word();
600 path.release_nodes();
601
602 auto *parent = pp->insert_child(path[0]);
603 for (size_t i = 1; i < n; ++i)
604 {
605 parent->insert_rightmost_child(path[i]);
606 parent = path[i];
607 }
608
609 return true;
610 }
611
618 {
619 for (auto p = static_cast<Cnode *>(get_right_child()); p != nullptr;)
620 {
621 Cnode *to_delete = p;
622 p = static_cast<Cnode *>(p->get_left_sibling());
623 destroy_tree(to_delete);
624 }
625 this->set_is_leaf(true);
626 }
627
628private:
629 void words_impl(std::string &word, DynArray<std::string> &l, const size_t max_word_length) const
630 {
631 if (is_end_word())
632 l.append(word);
633
634 for (const Tree_Node<char> *child = get_left_child(); child != nullptr;
635 child = child->get_right_sibling())
636 {
637 assert(word.size() < max_word_length);
638 const auto *node = static_cast<const Cnode *>(child);
639 word.push_back(node->symbol());
641 word.pop_back();
642 }
643 }
644
645public:
656 {
658 std::string word;
660
662
663 return ret_val;
664 }
665
670 void print_words(const size_t max_word_length = 2048) const
671 {
673 .for_each([](const std::string &w)
674 {
675 std::cout << w << '\n';
676 });
677 }
678
690 static void clone(const Tree_Node<char> *src, Tree_Node<char> *tgt)
691 {
692 const auto *src_node = static_cast<const Cnode *>(src);
693 auto *tgt_node = static_cast<Cnode *>(tgt);
695 tgt_node->ends_word_ = src_node->ends_word_;
696
697 for (const Tree_Node<char> *src_child = src_node->get_left_child(); src_child != nullptr;
698 src_child = src_child->get_right_sibling())
699 {
700 const auto *child = static_cast<const Cnode *>(src_child);
704 (void) cloned_child.release();
706 }
707
708 rollback.release();
709 }
710
720 [[nodiscard]] Cnode *clone() const
721 {
723 clone(this, ret.get());
724 return ret.release();
725 }
726};
727
747{
748 Cnode *root_ = nullptr;
749 mutable size_t word_count_ = 0;
750 mutable bool count_dirty_ = false;
751 mutable bool mutable_root_exposed_ = false;
752
754 static void destroy_root(Cnode *root) noexcept
755 {
756 if (root == nullptr)
757 return;
758
759 root->destroy();
760 delete root;
761 }
762
765 {
766 std::swap(root_, other.root_);
767 std::swap(word_count_, other.word_count_);
768 std::swap(count_dirty_, other.count_dirty_);
769 std::swap(mutable_root_exposed_, other.mutable_root_exposed_);
770 }
771
772public:
781 {
782 // empty
783 }
784
792 : root_(other.root_->clone()), word_count_(other.count()),
794 {
795 // empty
796 }
797
809
818
830 {
831 if (this == &other)
832 return *this;
833
834 Cnode *new_root = other.root_->clone();
835 const size_t new_count = other.count();
837 root_ = new_root;
839 count_dirty_ = false;
840 mutable_root_exposed_ = false;
841 return *this;
842 }
843
853 {
854 if (this == &other)
855 return *this;
856
857 Prefix_Tree tmp(std::move(other));
859 return *this;
860 }
861
869 bool insert_word(const std::string &word)
870 {
871 const bool inserted = root_->insert_word(word);
873 ++word_count_;
874 return inserted;
875 }
876
882 [[nodiscard]] bool contains(const std::string &word) const noexcept
883 {
884 return root_->contains(word);
885 }
886
898 {
899 return root_->words(max_word_length);
900 }
901
914 const size_t max_word_length = 2048) const
915 {
917 }
918
933 {
934 if (root_ == nullptr)
935 return 0;
936
938 {
940 count_dirty_ = false;
941 }
942 return word_count_;
943 }
944
953 {
954 return count();
955 }
956
965 {
966 count_dirty_ = true;
968 return root_;
969 }
970
979 {
980 return root_;
981 }
982};
983
1017template <typename T>
1019{
1020public:
1022 using Key = std::string;
1023
1025 using Value = T;
1026
1027private:
1029 class Node : public Tree_Node<char>
1030 {
1031 std::optional<Value> value_;
1032
1034 template <typename Node_Type>
1035 [[nodiscard]] static Node_Type *search_child_impl(Node_Type *root,
1036 const char c) noexcept
1037 {
1038 assert(root != nullptr);
1039
1040 for (auto *child = root->get_left_child(); child != nullptr;
1041 child = child->get_right_sibling())
1042 {
1043 const char key = child->get_key();
1044 if (key == c)
1045 return static_cast<Node_Type *>(child);
1046 if (key > c)
1047 return nullptr;
1048 }
1049
1050 return nullptr;
1051 }
1052
1054 template <typename Node_Type>
1055 [[nodiscard]] static Node_Type *greater_child_impl(Node_Type *root,
1056 const char c) noexcept
1057 {
1058 assert(root != nullptr);
1059
1060 for (auto *child = root->get_left_child(); child != nullptr;
1061 child = child->get_right_sibling())
1062 if (child->get_key() > c)
1063 return static_cast<Node_Type *>(child);
1064 return nullptr;
1065 }
1066
1068 template <typename Node_Type>
1069 [[nodiscard]] static std::tuple<Node_Type *, const char *>
1070 search_prefix_impl(Node_Type *root, const char *prefix) noexcept
1071 {
1072 assert(root != nullptr);
1073 assert(prefix != nullptr);
1074
1075 auto *node = root;
1076 for (const char *ptr = prefix; *ptr != '\0'; ++ptr)
1077 {
1078 auto *child = node->search_child(*ptr);
1079 if (child == nullptr)
1080 return std::make_tuple(node, ptr);
1081 node = child;
1082 }
1083
1084 return std::make_tuple(node, "");
1085 }
1086
1089 {
1090 Node *root_ = nullptr;
1091
1092 public:
1094 {
1095 // empty
1096 }
1097
1099 {
1100 if (root_ != nullptr)
1101 {
1102 root_->destroy();
1103 delete root_;
1104 }
1105 }
1106
1108 {
1109 return root_;
1110 }
1111
1113 {
1114 Node *ret = root_;
1115 root_ = nullptr;
1116 return ret;
1117 }
1118 };
1119
1122 {
1123 Node **nodes_ = nullptr;
1124 size_t count_ = 0;
1125 bool owns_nodes_ = true;
1126
1127 public:
1128 explicit Pending_Path_Guard(const size_t count)
1129 : nodes_(new Node *[count]), count_(count)
1130 {
1131 for (size_t i = 0; i < count_; ++i)
1132 nodes_[i] = nullptr;
1133 }
1134
1136 {
1137 if (owns_nodes_)
1138 for (size_t i = 0; i < count_; ++i)
1139 delete nodes_[i];
1140 delete[] nodes_;
1141 }
1142
1143 [[nodiscard]] Node *operator [] (const size_t i) const noexcept
1144 {
1145 return nodes_[i];
1146 }
1147
1148 void set(const size_t i, Node *node) const noexcept
1149 {
1150 nodes_[i] = node;
1151 }
1152
1154 {
1155 owns_nodes_ = false;
1156 }
1157 };
1158
1159 public:
1164 explicit Node(const char c) noexcept
1165 {
1166 this->get_key() = c;
1167 }
1168
1177 template <typename U>
1178 Node(const char c, U &&value) : value_(std::forward<U>(value))
1179 {
1180 this->get_key() = c;
1181 }
1182
1188 {
1189 return get_key();
1190 }
1191
1197 {
1198 return value_.has_value();
1199 }
1200
1206 {
1207 return value_.has_value() ? &*value_ : nullptr;
1208 }
1209
1215 {
1216 return value_.has_value() ? &*value_ : nullptr;
1217 }
1218
1224 {
1225 value_.reset();
1226 }
1227
1235 template <typename U>
1237 {
1238 value_.emplace(std::forward<U>(value));
1239 }
1240
1246 [[nodiscard]] Node *search_child(const char c) noexcept
1247 {
1248 return search_child_impl(this, c);
1249 }
1250
1256 [[nodiscard]] const Node *search_child(const char c) const noexcept
1257 {
1258 return search_child_impl(this, c);
1259 }
1260
1266 [[nodiscard]] Node *greater_child(const char c) noexcept
1267 {
1268 return greater_child_impl(this, c);
1269 }
1270
1276 [[nodiscard]] const Node *greater_child(const char c) const noexcept
1277 {
1278 return greater_child_impl(this, c);
1279 }
1280
1288 [[nodiscard]] std::tuple<Node *, const char *>
1289 search_prefix(const char *prefix) noexcept
1290 {
1291 return search_prefix_impl(this, prefix);
1292 }
1293
1301 [[nodiscard]] std::tuple<const Node *, const char *>
1302 search_prefix(const char *prefix) const noexcept
1303 {
1304 return search_prefix_impl(this, prefix);
1305 }
1306
1315 {
1316 assert(search_child(child->symbol()) == nullptr);
1317
1318 if (Node *sibling = greater_child(child->symbol()); sibling == nullptr)
1319 this->insert_rightmost_child(child);
1320 else
1321 sibling->insert_left_sibling(child);
1322
1323 return child;
1324 }
1325
1337 template <typename U>
1338 void insert_suffix(const char *suffix, U &&value)
1339 {
1340 assert(suffix != nullptr);
1341 assert(*suffix != '\0');
1342
1343 size_t n = 0;
1344 for (const char *ptr = suffix; *ptr != '\0'; ++ptr)
1345 ++n;
1346
1347 Pending_Path_Guard path(n);
1348 for (size_t i = 0; i + 1 < n; ++i)
1349 path.set(i, new Node(suffix[i]));
1350 path.set(n - 1, new Node(suffix[n - 1], std::forward<U>(value)));
1351 path.release_nodes();
1352
1353 Node *parent = insert_child(path[0]);
1354 for (size_t i = 1; i < n; ++i)
1355 {
1356 parent->insert_rightmost_child(path[i]);
1357 parent = path[i];
1358 }
1359 }
1360
1366 {
1367 for (auto *p = static_cast<Node *>(get_right_child()); p != nullptr;)
1368 {
1369 Node *to_delete = p;
1370 p = static_cast<Node *>(p->get_left_sibling());
1371 destroy_tree(to_delete);
1372 }
1373 this->set_is_leaf(true);
1374 }
1375
1384 {
1386 clone_into(this, ret.get());
1387 return ret.release();
1388 }
1389
1397 static void clone_into(const Node *src, Node *tgt)
1398 requires std::is_copy_constructible_v<Value>
1399 {
1400 assert(src != nullptr);
1401 assert(tgt != nullptr);
1402
1403 if (src->value_.has_value())
1404 tgt->value_.emplace(*src->value_);
1405
1406 for (const Tree_Node<char> *src_child = src->get_left_child();
1407 src_child != nullptr; src_child = src_child->get_right_sibling())
1408 {
1409 const auto *child = static_cast<const Node *>(src_child);
1411 Node *tgt_child = cloned_child.get();
1413 (void) cloned_child.release();
1415 }
1416 }
1417
1427 const size_t max_word_length) const
1428 {
1429 if (has_value())
1430 out.append(word);
1431
1432 for (const Tree_Node<char> *child = get_left_child(); child != nullptr;
1433 child = child->get_right_sibling())
1434 {
1435 assert(word.size() < max_word_length);
1436 const auto *node = static_cast<const Node *>(child);
1437 word.push_back(node->symbol());
1439 word.pop_back();
1440 }
1441 }
1442 };
1443
1444 Node *root_ = nullptr;
1445 size_t size_ = 0;
1446
1448 static void destroy_root(Node *root) noexcept
1449 {
1450 if (root == nullptr)
1451 return;
1452
1453 root->destroy();
1454 delete root;
1455 }
1456
1459 {
1460 if (root_ == nullptr)
1461 root_ = new Node('\0');
1462 }
1463
1465 [[nodiscard]] const Node *find_node(const std::string &word) const noexcept
1466 {
1467 if (root_ == nullptr)
1468 return nullptr;
1469
1470 auto [node, remaining] = root_->search_prefix(word.c_str());
1471 return *remaining == '\0' ? node : nullptr;
1472 }
1473
1475 [[nodiscard]] Node *find_node(const std::string &word) noexcept
1476 {
1477 return const_cast<Node *>(
1478 static_cast<const Prefix_Tree_Map *>(this)->find_node(word));
1479 }
1480
1489 template <typename U>
1490 bool insert_impl(const std::string &word, U &&value,
1491 const bool assign_if_present = false)
1492 {
1493 ensure_root();
1494
1495 auto [node, remaining] = root_->search_prefix(word.c_str());
1496 if (*remaining == '\0')
1497 {
1498 if (node->has_value())
1499 {
1501 *node->value() = std::forward<U>(value);
1502 return false;
1503 }
1504 node->emplace_value(std::forward<U>(value));
1505 ++size_;
1506 return true;
1507 }
1508
1509 node->insert_suffix(remaining, std::forward<U>(value));
1510 ++size_;
1511 return true;
1512 }
1513
1514public:
1520 {
1521 // empty
1522 }
1523
1531 requires std::is_copy_constructible_v<Value>
1532 : root_(other.root_ != nullptr ? other.root_->clone() : nullptr),
1534 {
1535 // empty
1536 }
1537
1543 : root_(other.root_), size_(other.size_)
1544 {
1545 other.root_ = nullptr;
1546 other.size_ = 0;
1547 }
1548
1557
1569 requires std::is_copy_constructible_v<Value>
1570 {
1571 if (this == &other)
1572 return *this;
1573
1574 Node *new_root = other.root_ != nullptr ? other.root_->clone() : nullptr;
1576 root_ = new_root;
1577 size_ = other.size_;
1578 return *this;
1579 }
1580
1587 {
1588 if (this == &other)
1589 return *this;
1590
1592 root_ = other.root_;
1593 size_ = other.size_;
1594 other.root_ = nullptr;
1595 other.size_ = 0;
1596 return *this;
1597 }
1598
1607 bool insert(const Key &key, const Value &value)
1608 {
1609 return insert_impl(key, value);
1610 }
1611
1622 bool insert(const Key &key, Value &&value)
1623 {
1624 return insert_impl(key, std::move(value));
1625 }
1626
1635 {
1636 insert_impl(key, std::move(value), /* assign_if_present = */ true);
1637 }
1638
1649 bool erase(const Key &key) noexcept
1650 {
1651 Node *node = find_node(key);
1652 if (node == nullptr or not node->has_value())
1653 return false;
1654
1655 node->reset_value();
1656 --size_;
1657 return true;
1658 }
1659
1667 [[nodiscard]] bool contains(const Key &key) const noexcept
1668 {
1669 return find(key) != nullptr;
1670 }
1671
1680 [[nodiscard]] const Value *find(const Key &key) const noexcept
1681 {
1682 const Node *node = find_node(key);
1683 return node != nullptr ? node->value() : nullptr;
1684 }
1685
1694 [[nodiscard]] Value *find(const Key &key) noexcept
1695 {
1696 Node *node = find_node(key);
1697 return node != nullptr ? node->value() : nullptr;
1698 }
1699
1707 {
1708 return size_;
1709 }
1710
1720 {
1721 return size();
1722 }
1723
1731 {
1732 return size_ == 0;
1733 }
1734
1739 void clear()
1740 {
1741 Node *new_root = new Node('\0');
1743 root_ = new_root;
1744 size_ = 0;
1745 }
1746
1757 [[nodiscard]] DynArray<Key> words(const size_t max_word_length = 2048) const
1758 {
1760 if (root_ == nullptr)
1761 return ret;
1762
1763 std::string word;
1766 return ret;
1767 }
1768
1781 const size_t max_word_length = 2048) const
1782 {
1784 if (root_ == nullptr)
1785 return ret;
1786
1787 auto [node, remaining] = root_->search_prefix(prefix.c_str());
1788 if (*remaining != '\0')
1789 return ret;
1790
1791 assert(prefix.size() <= max_word_length);
1792 std::string word(prefix);
1793 word.reserve(max_word_length);
1794 node->words_impl(word, ret, max_word_length);
1795 return ret;
1796 }
1797};
1798} // end namespace Aleph
1799
1800#endif // PREFIX_TREE_H
Exception handling system with formatted messages for Aleph-w.
WeightedDigraph::Node Node
long double w
Definition btreepic.C:153
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
Restore a clone target if appending cloned children fails.
Clone_Target_Rollback(Cnode *target) noexcept
Tree_Node< char > * previous_rightmost_
Own a detached subtree until it is committed elsewhere.
Cnode * get() const noexcept
Detached_Subtree_Guard(Cnode *root) noexcept
Own standalone nodes until an insertion path is committed.
void set(const size_t i, Cnode *node) const noexcept
Pending_Path_Guard(const size_t count)
Cnode * operator[](const size_t i) const noexcept
Low-level prefix tree node for storing character sequences.
Cnode * search_child(const char c) noexcept
Search for a mutable child with the given character.
Cnode(const char c) noexcept
Construct a node with the given character.
size_t count() const noexcept
Count total words stored in this subtree.
static void clone(const Tree_Node< char > *src, Tree_Node< char > *tgt)
Clone helper - copies children from src to tgt.
Cnode * clone() const
Create a deep copy of this subtree.
static std::tuple< Node *, const char * > search_prefix_impl(Node *root, const char *prefix) noexcept
Shared implementation for mutable and const prefix searches.
bool contains(const std::string &word) const noexcept
Check if a word exists in the tree.
void destroy() noexcept
Destroy all children of this node.
const Cnode * greater_child(const char c) const noexcept
Find the first const child with a character greater than c.
Cnode * greater_child(const char c) noexcept
Find the first mutable child with a character greater than c.
std::tuple< Cnode *, const char * > search_prefix(const char *prefix) noexcept
Search for a prefix in the mutable tree.
std::string to_str() const
Convert the subtree to a string representation.
void words_impl(std::string &word, DynArray< std::string > &l, const size_t max_word_length) const
std::tuple< const Cnode *, const char * > search_prefix(const char *prefix) const noexcept
Search for a prefix in the const tree.
const Cnode * search_word(const char *word) const noexcept
Search for a complete word in the tree.
void mark_end_word()
Mark this node as the end of a word.
void print_words(const size_t max_word_length=2048) const
Print all words to stdout.
bool is_end_word() const noexcept
Check if this node marks the end of a word.
Cnode * insert_child(Cnode *child)
Insert a child node in sorted order.
char symbol() const noexcept
Return the character stored in this node.
static Node * search_child_impl(Node *root, const char c) noexcept
Shared implementation for mutable and const child lookup.
bool insert_word(const std::string &word)
Insert a word into the tree.
const Cnode * search_child(const char c) const noexcept
Search for a const child with the given character.
DynArray< std::string > words(size_t max_word_length=2048) const
Get all words stored in this subtree.
DynArray< std::string > words_with_prefix(const std::string &prefix, const size_t max_word_length=2048) const
Get all words starting with a given prefix.
DynList< Cnode * > children() const
Return a list of all child nodes.
static Node * greater_child_impl(Node *root, const char c) noexcept
Shared implementation for mutable and const sorted-child lookup.
void reserve(const size_t l, const size_t r)
Allocate a range of entries.
Doubly-linked list (defined in tpl_dynList.H).
Definition htlist.H:1155
T & append(const T &item)
Definition htlist.H:1271
Own a detached map subtree until it is committed.
Own standalone insertion nodes until a new path is committed.
void set(const size_t i, Node *node) const noexcept
Internal trie node storing one character and an optional value.
static void clone_into(const Node *src, Node *tgt)
Copy src contents into an already allocated target node.
void words_impl(std::string &word, DynArray< std::string > &out, const size_t max_word_length) const
Append all terminal keys in this subtree.
Node(const char c) noexcept
Construct a structural node with no mapped value.
const Node * search_child(const char c) const noexcept
Search for a const child with the given character.
void insert_suffix(const char *suffix, U &&value)
Insert a key suffix below this node.
Node * clone() const
Clone this node and all descendants.
void emplace_value(U &&value)
Emplace this node's mapped value.
Node * insert_child(Node *child)
Insert a child node in sorted order.
char symbol() const noexcept
Return the character stored in this node.
std::optional< Value > value_
const Node * greater_child(const char c) const noexcept
Find the first const child with a character greater than c.
std::tuple< const Node *, const char * > search_prefix(const char *prefix) const noexcept
Search for a prefix in the const tree.
void reset_value() noexcept
Remove this node's mapped value.
Node * greater_child(const char c) noexcept
Find the first mutable child with a character greater than c.
bool has_value() const noexcept
Check whether this node terminates a key.
static std::tuple< Node_Type *, const char * > search_prefix_impl(Node_Type *root, const char *prefix) noexcept
Shared mutable and const prefix search.
static Node_Type * greater_child_impl(Node_Type *root, const char c) noexcept
Shared mutable and const sorted-child lookup.
static Node_Type * search_child_impl(Node_Type *root, const char c) noexcept
Shared mutable and const child lookup.
std::tuple< Node *, const char * > search_prefix(const char *prefix) noexcept
Search for a prefix in the mutable tree.
const Value * value() const noexcept
Return the stored mapped value.
Node(const char c, U &&value)
Construct a terminal node with a mapped value.
void destroy() noexcept
Destroy all children of this node.
Value * value() noexcept
Return the stored mapped value.
Node * search_child(const char c) noexcept
Search for a mutable child with the given character.
Owning prefix tree map from strings to values.
DynArray< Key > words(const size_t max_word_length=2048) const
Get all keys stored in the map.
size_t count() const noexcept
Return the number of stored key-value pairs.
T Value
Mapped value type stored in terminal nodes.
bool contains(const Key &key) const noexcept
Check whether key is stored.
void ensure_root()
Ensure the root node exists after a move.
Value * find(const Key &key) noexcept
Mutable lookup overload.
Node * find_node(const std::string &word) noexcept
Find the terminal node for word.
Prefix_Tree_Map & operator=(const Prefix_Tree_Map &other)
Replace this map with a deep copy of another map.
bool insert(const Key &key, Value &&value)
Insert key with a moved value if absent.
const Value * find(const Key &key) const noexcept
Look up key.
bool insert(const Key &key, const Value &value)
Insert key with a copied value if absent.
std::string Key
Key type accepted by the map.
Prefix_Tree_Map(Prefix_Tree_Map &&other) noexcept
Move-construct, taking ownership of another map's root.
Prefix_Tree_Map(const Prefix_Tree_Map &other)
Construct a deep copy of another prefix map.
DynArray< Key > words_with_prefix(const Key &prefix, const size_t max_word_length=2048) const
Get all keys with a given prefix.
void insert_or_assign(const Key &key, Value value)
Insert key or overwrite its mapped value.
const Node * find_node(const std::string &word) const noexcept
Find the terminal node for word.
bool insert_impl(const std::string &word, U &&value, const bool assign_if_present=false)
Shared implementation for insert()'s copy/move overloads and for insert_or_assign(): when assign_if_p...
Prefix_Tree_Map()
Construct an empty prefix map.
bool erase(const Key &key) noexcept
Remove key if present.
void clear()
Remove every key-value pair from the map.
static void destroy_root(Node *root) noexcept
Destroy an owned root and all descendants.
size_t size() const noexcept
Return the number of stored key-value pairs.
~Prefix_Tree_Map() noexcept
Destroy the owned root and all descendants.
bool is_empty() const noexcept
Check whether the map has no keys.
Owning prefix tree wrapper.
bool insert_word(const std::string &word)
Insert a word into the tree.
static void destroy_root(Cnode *root) noexcept
Destroy an owned root and all its descendants.
const Cnode * root() const noexcept
Return the const root node.
Prefix_Tree & operator=(const Prefix_Tree &other)
Replace this tree with a deep copy of another tree.
Prefix_Tree()
Construct an empty prefix tree.
DynArray< std::string > words(const size_t max_word_length=2048) const
Get all words stored in the tree.
DynArray< std::string > words_with_prefix(const std::string &prefix, const size_t max_word_length=2048) const
Get all words with a given prefix.
Prefix_Tree(Prefix_Tree &&other)
Move-construct, taking ownership of another tree's contents.
Prefix_Tree(const Prefix_Tree &other)
Construct a deep copy of another prefix tree.
Cnode * root() noexcept
Return the mutable root node.
~Prefix_Tree() noexcept
Destroy the owned root and all descendants.
size_t count() const noexcept
Count the words stored in the tree.
void swap_state(Prefix_Tree &other) noexcept
Swap internal ownership and cached count state.
bool contains(const std::string &word) const noexcept
Check whether a word exists in the tree.
size_t size() const noexcept
Return the number of words stored in the tree.
Forward declaration used by CRTP helpers before the full node definition.
Tree_Node * get_left_child() const noexcept
Returns the leftmost child of this.
void insert_rightmost_child(Tree_Node *p) noexcept
Inserts p as the rightmost child of this.
void set_is_leaf(bool value) noexcept
Sets the leaf flag.
void for_each_child(Operation &op) const
Visits each child of this and executes the operation on the child node.
Tree_Node * get_right_child() const noexcept
Returns the rightmost child of this.
char & get_key() noexcept
Returns a modifiable reference to the node contents.
void for_each(Operation &operation)
Traverse all the container and performs an operation on each element.
Definition ah-dry.H:796
__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
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
void destroy_tree(Node *root)
Destroys (frees memory) the tree whose root is root.
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
static void suffix(Node *root, DynList< Node * > &acc)
and
Check uniqueness with explicit hash + equality functors.
std::decay_t< typename HeadC::Item_Type > T
Definition ah-zip.H:105
static void prefix(Node *root, DynList< Node * > &acc)
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.
gsl_rng * r
Lazy and scalable dynamic array implementation.
Alias for htlist.H (DynList implementation).
General tree (n-ary tree) node.
DynList< int > l