Makefile: remove spurious tab
[xcsoar.git] / src / Util / RadixTree.hpp
blobbdda3d45a5482f312ba56d8c3df8ef99995bacf1
1 /*
2 * Copyright (C) 2010 Max Kellermann <max@duempel.org>
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
8 * - Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the
14 * distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
19 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
20 * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
25 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
27 * OF THE POSSIBILITY OF SUCH DAMAGE.
30 #ifndef XCSOAR_RADIX_TREE_HPP
31 #define XCSOAR_RADIX_TREE_HPP
33 #include "Util/NonCopyable.hpp"
34 #include "Util/StaticString.hpp"
35 #include "StringUtil.hpp"
36 #include "tstring.hpp"
38 #include <algorithm>
39 #include <assert.h>
40 #include <tchar.h>
42 #ifdef PRINT_RADIX_TREE
43 #include <ostream>
44 #endif
46 /**
47 * An associative container which maps TCHAR strings to arbitrary
48 * objects. Each "key" may have multiple values.
50 * This class provides a sorted iterator, which is optimized for
51 * prefix search. This is useful e.g. when you want to show an
52 * incremental result set when the user starts typing an item name.
53 * Besides that, a key lookup is quite efficient.
55 template<typename T>
56 class RadixTree {
57 template<class V>
58 struct KeyVisitorAdapter {
59 V &visitor;
60 const TCHAR *key;
62 KeyVisitorAdapter(V &_visitor, const TCHAR *_key)
63 :visitor(_visitor), key(_key) {}
65 void operator()(const T &value) const {
66 visitor(key, value);
70 /**
71 * A leaf holds one value associated with a key. Next to the value,
72 * it has a "next" attribute to build a singly linked list.
74 struct Leaf {
75 Leaf *next;
76 T value;
78 Leaf(Leaf *_next, const T &_value)
79 :next(_next), value(_value) {}
82 /**
83 * A linked list of Leaf objects.
85 struct LeafList {
86 Leaf *head;
88 constexpr
89 LeafList():head(nullptr) {}
91 ~LeafList() {
92 Leaf *next = head;
93 while (next != nullptr) {
94 Leaf *leaf = next;
95 next = leaf->next;
97 delete leaf;
101 void Clear() {
102 Leaf *next = head;
103 while (next != nullptr) {
104 Leaf *leaf = next;
105 next = leaf->next;
107 delete leaf;
110 head = nullptr;
113 void Swap(LeafList &other) {
114 std::swap(head, other.head);
117 void Add(const T &value) {
118 head = new Leaf(head, value);
121 bool Remove(const T &value) {
122 Leaf **leaf_r = &head;
124 while (*leaf_r != nullptr) {
125 Leaf *leaf = *leaf_r;
126 if (leaf->value == value) {
127 *leaf_r = leaf->next;
128 leaf->next = nullptr;
129 delete leaf;
130 return true;
133 leaf_r = &leaf->next;
136 return false;
139 T *GetFirstPointer() {
140 return head != nullptr
141 ? &head->value
142 : nullptr;
145 const T *GetFirstPointer() const {
146 return head != nullptr
147 ? &head->value
148 : nullptr;
151 template<class P>
152 T *GetIf(const P &predicate) {
153 for (Leaf *leaf = head; leaf != nullptr; leaf = leaf->next)
154 if (predicate(leaf->value))
155 return &leaf->value;
157 return nullptr;
160 template<class P>
161 const T *GetIf(const P &predicate) const {
162 for (Leaf *leaf = head; leaf != nullptr; leaf = leaf->next)
163 if (predicate(leaf->value))
164 return &leaf->value;
166 return nullptr;
169 template<typename V>
170 void VisitAll(V &visitor) {
171 for (Leaf *leaf = head; leaf != nullptr; leaf = leaf->next)
172 visitor(leaf->value);
175 template<typename V>
176 void VisitAll(V &visitor) const {
177 for (const Leaf *leaf = head; leaf != nullptr; leaf = leaf->next)
178 visitor(leaf->value);
183 * A node in the radix tree. The "label" attribute is a substring
184 * of the key. A node can have any number of values (or none).
186 * All siblings start with a different letter (this is a basic
187 * property of radix trees). When inserting a node starting with
188 * the same character, the node has to be splitted.
190 struct Node : private NonCopyable {
191 StaticString<8> label;
192 Node *next_sibling, *children;
193 LeafList leaves;
195 constexpr
196 Node(const TCHAR *_label)
197 :label(_label),
198 next_sibling(nullptr), children(nullptr) {}
199 ~Node() {
200 delete next_sibling;
201 delete children;
205 * Create a new Node with the specified label (suffix) and value.
206 * If the label is too long for the StaticString, multiple chained
207 * Node objects are created.
209 Node *CreateLeaf(const TCHAR *label, const T &value) const {
210 Node *top = new Node(label), *bottom = top;
211 while (_tcslen(label) >= Node::label.MAX_SIZE) {
212 /* label too long for the Node's StaticString, create another
213 child Node */
214 label += Node::label.MAX_SIZE - 1;
215 Node *node = new Node(label);
216 bottom->children = node;
217 bottom = node;
220 bottom->AddValue(value);
221 return top;
224 void Clear() {
225 delete children;
226 children = nullptr;
227 leaves.Clear();
231 * Find the first mismatching character. Returns the original
232 * parameter if there is no match at all. Returns the end of the
233 * string if there is a full match (even if the node's label is
234 * longer).
236 const TCHAR *MatchKey(const TCHAR *key) const {
237 const TCHAR *l = label.c_str();
239 while (!StringIsEmpty(key) && *key == *l) {
240 ++key;
241 ++l;
244 return key;
248 * Check if the label begins with the specified prefix. Returns
249 * the original parameter if there is no match at all. Returns
250 * the end of the prefix string if there is a full match (even if
251 * the node's label is longer). If the label is shorter than the
252 * prefix, returns a pointer to the first prefix character which
253 * is outside of the label's scope. Returns nullptr if there is a
254 * mismatch.
256 const TCHAR *MatchPrefix(const TCHAR *prefix) const {
257 const TCHAR *l = label.c_str();
259 while (!StringIsEmpty(prefix) && !StringIsEmpty(l)) {
260 if (*l != *prefix)
261 return nullptr;
263 ++prefix;
264 ++l;
267 return prefix;
270 T *Get(const TCHAR *key) {
271 if (StringIsEmpty(key))
272 /* found */
273 return leaves.GetFirstPointer();
275 const auto m = FindChild(key);
276 return m.IsFullMatch(key)
277 ? m.node->Get(m.key)
278 : nullptr;
281 const T *Get(const TCHAR *key) const {
282 if (StringIsEmpty(key))
283 /* found */
284 return leaves.GetFirstPointer();
286 const auto m = FindChild(key);
287 return m.IsFullMatch(key)
288 ? m.node->Get(m.key)
289 : nullptr;
292 template<class P>
293 T *GetIf(const TCHAR *key, const P &predicate) {
294 if (StringIsEmpty(key))
295 /* found */
296 return leaves.GetIf(predicate);
298 const auto m = FindChild(key);
299 return m.IsFullMatch(key)
300 ? m.node->GetIf(m.key, predicate)
301 : nullptr;
304 template<class P>
305 const T *GetIf(const TCHAR *key, const P &predicate) const {
306 if (StringIsEmpty(key))
307 /* found */
308 return leaves.GetIf(predicate);
310 const auto m = FindChild(key);
311 return m.IsFullMatch(key)
312 ? m.node->GetIf(m.key, predicate)
313 : nullptr;
316 TCHAR *Suggest(const TCHAR *prefix, TCHAR *dest, size_t max_length) const {
317 if (StringIsEmpty(prefix)) {
318 /* exact match - return the first character of all child
319 nodes */
320 TCHAR *retval = dest, *end = dest + max_length - 1;
322 for (const Node *node = children; node != nullptr && dest < end;
323 node = node->next_sibling)
324 *dest++ = node->label[0u];
326 *dest = _T('\0');
327 return retval;
330 const auto m = FindChild(prefix);
331 if (m.key == prefix)
332 /* mismatch */
333 return nullptr;
335 if (m.IsFullMatch(prefix))
336 /* recurse */
337 return m.node->Suggest(m.key, dest, max_length);
339 /* return one character */
340 dest[0u] = m.node->label[(unsigned)(m.key - prefix)];
341 dest[1] = _T('\0');
342 return dest;
346 * Split the node label at the specified position, creating a new
347 * child node which becomes the parent of all this node's children
348 * and values.
350 void Split(size_t length) {
351 assert(length > 0);
352 assert(length < label.length());
354 Node *node = new Node(label.c_str() + length);
355 node->children = children;
356 children = node;
358 leaves.Swap(node->leaves);
360 label.Truncate(length);
364 * Add a value. There is no specific order of values with the
365 * same key.
367 void AddValue(const T &value) {
368 leaves.Add(value);
372 * Remove all values of this node.
374 void RemoveValues() {
375 leaves.Clear();
379 * Remove the specified value. If there are multiple instances of
380 * the same value, only one is removed.
382 * @return true if a value was found and removed
384 bool RemoveValue(const T &value) {
385 return leaves.Remove(value);
389 * Remove all values with the specified key.
391 void RemoveValues(const TCHAR *key) {
392 assert(key != nullptr);
394 if (StringIsEmpty(key)) {
395 /* this is the right node */
396 RemoveValues();
397 } else {
398 const auto m = FindChild(key);
399 if (m.IsFullMatch(key))
400 /* recurse */
401 m.node->RemoveValues(m.key);
406 * Remove the specified value.
408 * @return true if a value was found and removed
410 bool RemoveValue(const TCHAR *key, const T &value) {
411 assert(key != nullptr);
413 if (StringIsEmpty(key)) {
414 /* this is the right node */
415 return RemoveValue(value);
416 } else {
417 const auto m = FindChild(key);
418 return m.IsFullMatch(key) &&
419 m.node->RemoveValue(m.key, value);
424 * Visit all direct values of this node in no specific order.
426 template<typename V>
427 void VisitValues(V &visitor) {
428 leaves.VisitAll(visitor);
432 * Visit all direct values of this node in no specific order.
434 template<typename V>
435 void VisitValues(V &visitor) const {
436 leaves.VisitAll(visitor);
440 * Visit all direct values of this node in no specific order.
441 * This overload is used by VisitAllPairs().
443 template<typename V>
444 void VisitValues(const TCHAR *prefix, V &visitor) const {
445 tstring key(prefix);
446 key.append(label);
448 const KeyVisitorAdapter<V> adapter(visitor, key.c_str());
449 VisitValues(adapter);
453 * Recursively visit all child nodes and their values in
454 * alphabetic order.
456 template<typename V>
457 void VisitAllChildren(V &visitor) {
458 for (Node *node = children; node != nullptr; node = node->next_sibling) {
459 node->VisitValues(visitor);
460 node->VisitAllChildren(visitor);
465 * Recursively visit all child nodes and their values in
466 * alphabetic order.
468 template<typename V>
469 void VisitAllChildren(V &visitor) const {
470 for (const Node *node = children; node != nullptr;
471 node = node->next_sibling) {
472 node->VisitValues(visitor);
473 node->VisitAllChildren(visitor);
478 * Recursively visit all child nodes and their values in
479 * alphabetic order. This overload is used by VisitAllPairs().
481 template<typename V>
482 void VisitAllChildren(const TCHAR *prefix, V &visitor) const {
483 tstring key(prefix);
484 key.append(label);
486 for (const Node *node = children; node != nullptr;
487 node = node->next_sibling) {
488 node->VisitValues(key.c_str(), visitor);
489 node->VisitAllChildren(key.c_str(), visitor);
494 * Recursively visit all child nodes with the specified prefix in
495 * alphabetic order. The prefix is only matched on children's
496 * labels.
498 template<typename V>
499 void VisitChildren(const TCHAR *key, V &visitor) {
500 VisitSiblings(children, key, visitor);
504 * Recursively visit all child nodes with the specified prefix in
505 * alphabetic order. The prefix is only matched on children's
506 * labels.
508 template<typename V>
509 void VisitChildren(const TCHAR *key, V &visitor) const {
510 VisitSiblings(const_cast<const Node *>(children), key, visitor);
514 * Recursively visit all values with the specified key. The
515 * key is matched on this node's label first.
517 template<typename V>
518 void Visit(const TCHAR *key, V &visitor) {
519 const TCHAR *match = MatchPrefix(key);
520 if (match == nullptr)
521 return;
523 if (StringIsEmpty(match))
524 VisitValues(visitor);
525 else
526 VisitChildren(match, visitor);
530 * Recursively visit all values with the specified key. The
531 * key is matched on this node's label first.
533 template<typename V>
534 void Visit(const TCHAR *key, V &visitor) const {
535 const TCHAR *match = MatchPrefix(key);
536 if (match == nullptr)
537 return;
539 if (StringIsEmpty(match))
540 VisitValues(visitor);
541 else
542 VisitChildren(match, visitor);
546 * Recursively visit all child nodes with the specified prefix in
547 * alphabetic order. The prefix is only matched on children's
548 * labels.
550 template<typename V>
551 void VisitPrefixChildren(const TCHAR *prefix, V &visitor) {
552 if (StringIsEmpty(prefix))
553 VisitAllChildren(visitor);
554 else
555 for (Node *node = children; node != nullptr; node = node->next_sibling)
556 node->VisitPrefix(prefix, visitor);
560 * Recursively visit all child nodes with the specified prefix in
561 * alphabetic order. The prefix is only matched on children's
562 * labels.
564 template<typename V>
565 void VisitPrefixChildren(const TCHAR *prefix, V &visitor) const {
566 if (StringIsEmpty(prefix))
567 VisitAllChildren(visitor);
568 else
569 for (const Node *node = children; node != nullptr;
570 node = node->next_sibling)
571 node->VisitPrefix(prefix, visitor);
575 * Recursively visit all values and child nodes with the specified
576 * prefix in alphabetic order. The prefix is matched on this
577 * node's label first.
579 template<typename V>
580 void VisitPrefix(const TCHAR *prefix, V &visitor) {
581 const TCHAR *match = MatchPrefix(prefix);
582 if (match == nullptr)
583 return;
585 if (StringIsEmpty(match)) {
586 VisitValues(visitor);
587 VisitAllChildren(visitor);
588 } else {
589 VisitPrefixChildren(match, visitor);
594 * Recursively visit all values and child nodes with the specified
595 * prefix in alphabetic order. The prefix is matched on this
596 * node's label first.
598 template<typename V>
599 void VisitPrefix(const TCHAR *prefix, V &visitor) const {
600 const TCHAR *match = MatchPrefix(prefix);
601 if (match == nullptr)
602 return;
604 if (StringIsEmpty(match)) {
605 VisitValues(visitor);
606 VisitAllChildren(visitor);
607 } else {
608 VisitPrefixChildren(match, visitor);
612 struct Match {
613 Node *node;
614 const TCHAR *key;
616 Match(Node *_node, const TCHAR *_key)
617 :node(_node), key(_key) {}
619 bool IsFullMatch(const TCHAR *key) const {
620 return this->key != key && this->key >= key + node->label.length();
625 * Find a matching child node. Returns a pair containing the node
626 * pointer (or nullptr if this node has no children), and a pointer
627 * to the portion of the key which was not used yet.
629 struct Match FindChild(const TCHAR *key) const {
630 Node *node = children, *prev = nullptr;
631 while (node != nullptr) {
632 const TCHAR *label = node->label.c_str();
633 if (key[0u] < label[0u])
634 return Match(prev, key);
635 else if (key[0u] == label[0u])
636 return Match(node, node->MatchKey(key));
638 prev = node;
639 node = node->next_sibling;
642 return Match(prev, key);
646 * Adds a new value relative to this node, possibly creating a new
647 * node and/or splitting an existing node.
649 void Add(const TCHAR *key, const T &value) {
650 assert(key != nullptr);
652 if (StringIsEmpty(key)) {
653 /* add to this node */
654 AddValue(value);
655 return;
658 const auto m = FindChild(key);
659 if (m.key == key) {
660 /* no match - create new node */
661 Node *node = CreateLeaf(key, value);
663 if (m.node == nullptr) {
664 /* insert before list head */
665 node->next_sibling = children;
666 children = node;
667 } else {
668 /* insert after that node */
669 node->next_sibling = m.node->next_sibling;
670 m.node->next_sibling = node;
672 } else if (m.IsFullMatch(key)) {
673 m.node->Add(m.key, value);
674 } else {
675 /* split existing node */
676 m.node->Split(m.key - key);
678 if (StringIsEmpty(m.key)) {
679 /* add to splitted parent node */
680 m.node->AddValue(value);
681 } else {
682 Node *node = CreateLeaf(m.key, value);
684 if (m.key[0u] < m.node->children->label[0u]) {
685 /* insert before list head */
686 node->next_sibling = m.node->children;
687 m.node->children = node;
688 } else {
689 /* insert after the splitted child node */
690 assert(m.node->children->next_sibling == nullptr);
692 m.node->children->next_sibling = node;
698 #ifdef PRINT_RADIX_TREE
699 template <typename Char, typename Traits>
700 friend std::basic_ostream<Char, Traits> &
701 operator<<(typename std::basic_ostream<Char, Traits>& out,
702 const Node &node) {
703 out << "node '" << node.label << "' {\n";
704 for (const RadixTree<T>::Leaf *leaf = node.leaves; leaf != nullptr;
705 leaf = leaf->next)
706 out << " value " << leaf->value << "\n";
707 for (const RadixTree<T>::Node *child = node.children; child != nullptr;
708 child = child->next_sibling)
709 out << *child;
710 return out << "}\n";
712 #endif /* PRINT_RADIX_TREE */
716 * The root node is a special case: its key is the empty string, and
717 * it is never split, it has no siblings.
719 Node root;
721 public:
722 constexpr
723 RadixTree():root(_T("")) {}
726 * Gets a value for the specified key. Returns the parameter
727 * default_value if the specified key is not present. If there are
728 * multiple values, any one is returned.
730 T &Get(const TCHAR *key, T &default_value) {
731 T *value = root.get(key);
732 return value != nullptr
733 ? *value
734 : default_value;
738 * Gets a value for the specified key. Returns the parameter
739 * default_value if the specified key is not present. If there are
740 * multiple values, any one is returned.
742 const T &Get(const TCHAR *key, const T &default_value) const {
743 const T *value = root.Get(key);
744 return value != nullptr
745 ? *value
746 : default_value;
749 template<class P>
750 T &GetIf(const TCHAR *key, T &default_value, const P &predicate) {
751 const T *value = root.GetIf(key, predicate);
752 return value != nullptr
753 ? *value
754 : default_value;
757 template<class P>
758 const T &GetIf(const TCHAR *key, const T &default_value,
759 const P &predicate) const {
760 const T *value = root.GetIf(key, predicate);
761 return value != nullptr
762 ? *value
763 : default_value;
767 * Get a list of characters following the specified prefix. There
768 * is no special indication whether there is a value for the exact
769 * key.
771 * @param prefix the prefix
772 * @param dest the destination buffer which will be filled with
773 * characters
774 * @param max_length the size of the buffer, including the trailing
775 * null byte
776 * @return the destination buffer, or nullptr if the prefix does not
777 * occur in the tree
779 TCHAR *Suggest(const TCHAR *prefix, TCHAR *dest, size_t max_length) const {
780 return root.Suggest(prefix, dest, max_length);
783 void Clear() {
784 root.Clear();
788 * Add a new value with the specified key. Multiple values can
789 * exist for one key.
791 void Add(const TCHAR *key, const T &value) {
792 root.Add(key, value);
796 * Remove all values with the specified key.
798 void Remove(const TCHAR *key) {
799 assert(key != nullptr);
801 root.RemoveValues(key);
805 * Remove a value with the specified key.
807 * @return true if a value was found and removed
809 bool Remove(const TCHAR *key, const T &value) {
810 assert(key != nullptr);
812 return root.RemoveValue(key, value);
816 * Visit all values in alphabetic order.
818 template<typename V>
819 void VisitAll(V &visitor) {
820 root.VisitValues(visitor);
821 root.VisitAllChildren(visitor);
825 * Visit all values in alphabetic order.
827 template<typename V>
828 void VisitAll(V &visitor) const {
829 root.VisitValues(visitor);
830 root.VisitAllChildren(visitor);
834 * Visit all key/value pairs in alphabetic order.
836 template<typename V>
837 void VisitAllPairs(V &visitor) const {
838 root.VisitValues(_T(""), visitor);
839 root.VisitAllChildren(_T(""), visitor);
843 * Visit all values with the specified key.
845 template<typename V>
846 void Visit(const TCHAR *key, V &visitor) {
847 root.Visit(key, visitor);
851 * Visit all values with the specified key.
853 template<typename V>
854 void Visit(const TCHAR *key, V &visitor) const {
855 root.Visit(key, visitor);
859 * Visit all values matching the specified prefix in alphabetic
860 * order.
862 template<typename V>
863 void VisitPrefix(const TCHAR *prefix, V &visitor) {
864 root.VisitPrefix(prefix, visitor);
868 * Visit all values matching the specified prefix in alphabetic
869 * order.
871 template<typename V>
872 void VisitPrefix(const TCHAR *prefix, V &visitor) const {
873 root.VisitPrefix(prefix, visitor);
876 #ifdef PRINT_RADIX_TREE
877 template <typename Char, typename Traits>
878 friend std::basic_ostream<Char, Traits> &
879 operator<<(typename std::basic_ostream<Char, Traits>& out,
880 const RadixTree<T> &rt) {
881 return out << rt.root;
883 #endif /* PRINT_RADIX_TREE */
886 #endif