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
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
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"
42 #ifdef PRINT_RADIX_TREE
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.
58 struct KeyVisitorAdapter
{
62 KeyVisitorAdapter(V
&_visitor
, const TCHAR
*_key
)
63 :visitor(_visitor
), key(_key
) {}
65 void operator()(const T
&value
) const {
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.
78 Leaf(Leaf
*_next
, const T
&_value
)
79 :next(_next
), value(_value
) {}
83 * A linked list of Leaf objects.
89 LeafList():head(nullptr) {}
93 while (next
!= nullptr) {
103 while (next
!= 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;
133 leaf_r
= &leaf
->next
;
139 T
*GetFirstPointer() {
140 return head
!= nullptr
145 const T
*GetFirstPointer() const {
146 return head
!= nullptr
152 T
*GetIf(const P
&predicate
) {
153 for (Leaf
*leaf
= head
; leaf
!= nullptr; leaf
= leaf
->next
)
154 if (predicate(leaf
->value
))
161 const T
*GetIf(const P
&predicate
) const {
162 for (Leaf
*leaf
= head
; leaf
!= nullptr; leaf
= leaf
->next
)
163 if (predicate(leaf
->value
))
170 void VisitAll(V
&visitor
) {
171 for (Leaf
*leaf
= head
; leaf
!= nullptr; leaf
= leaf
->next
)
172 visitor(leaf
->value
);
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
;
196 Node(const TCHAR
*_label
)
198 next_sibling(nullptr), children(nullptr) {}
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
214 label
+= Node::label
.MAX_SIZE
- 1;
215 Node
*node
= new Node(label
);
216 bottom
->children
= node
;
220 bottom
->AddValue(value
);
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
236 const TCHAR
*MatchKey(const TCHAR
*key
) const {
237 const TCHAR
*l
= label
.c_str();
239 while (!StringIsEmpty(key
) && *key
== *l
) {
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
256 const TCHAR
*MatchPrefix(const TCHAR
*prefix
) const {
257 const TCHAR
*l
= label
.c_str();
259 while (!StringIsEmpty(prefix
) && !StringIsEmpty(l
)) {
270 T
*Get(const TCHAR
*key
) {
271 if (StringIsEmpty(key
))
273 return leaves
.GetFirstPointer();
275 const auto m
= FindChild(key
);
276 return m
.IsFullMatch(key
)
281 const T
*Get(const TCHAR
*key
) const {
282 if (StringIsEmpty(key
))
284 return leaves
.GetFirstPointer();
286 const auto m
= FindChild(key
);
287 return m
.IsFullMatch(key
)
293 T
*GetIf(const TCHAR
*key
, const P
&predicate
) {
294 if (StringIsEmpty(key
))
296 return leaves
.GetIf(predicate
);
298 const auto m
= FindChild(key
);
299 return m
.IsFullMatch(key
)
300 ? m
.node
->GetIf(m
.key
, predicate
)
305 const T
*GetIf(const TCHAR
*key
, const P
&predicate
) const {
306 if (StringIsEmpty(key
))
308 return leaves
.GetIf(predicate
);
310 const auto m
= FindChild(key
);
311 return m
.IsFullMatch(key
)
312 ? m
.node
->GetIf(m
.key
, predicate
)
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
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];
330 const auto m
= FindChild(prefix
);
335 if (m
.IsFullMatch(prefix
))
337 return m
.node
->Suggest(m
.key
, dest
, max_length
);
339 /* return one character */
340 dest
[0u] = m
.node
->label
[(unsigned)(m
.key
- prefix
)];
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
350 void Split(size_t length
) {
352 assert(length
< label
.length());
354 Node
*node
= new Node(label
.c_str() + length
);
355 node
->children
= children
;
358 leaves
.Swap(node
->leaves
);
360 label
.Truncate(length
);
364 * Add a value. There is no specific order of values with the
367 void AddValue(const T
&value
) {
372 * Remove all values of this node.
374 void RemoveValues() {
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 */
398 const auto m
= FindChild(key
);
399 if (m
.IsFullMatch(key
))
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
);
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.
427 void VisitValues(V
&visitor
) {
428 leaves
.VisitAll(visitor
);
432 * Visit all direct values of this node in no specific order.
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().
444 void VisitValues(const TCHAR
*prefix
, V
&visitor
) const {
448 const KeyVisitorAdapter
<V
> adapter(visitor
, key
.c_str());
449 VisitValues(adapter
);
453 * Recursively visit all child nodes and their values in
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
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().
482 void VisitAllChildren(const TCHAR
*prefix
, V
&visitor
) const {
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
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
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.
518 void Visit(const TCHAR
*key
, V
&visitor
) {
519 const TCHAR
*match
= MatchPrefix(key
);
520 if (match
== nullptr)
523 if (StringIsEmpty(match
))
524 VisitValues(visitor
);
526 VisitChildren(match
, visitor
);
530 * Recursively visit all values with the specified key. The
531 * key is matched on this node's label first.
534 void Visit(const TCHAR
*key
, V
&visitor
) const {
535 const TCHAR
*match
= MatchPrefix(key
);
536 if (match
== nullptr)
539 if (StringIsEmpty(match
))
540 VisitValues(visitor
);
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
551 void VisitPrefixChildren(const TCHAR
*prefix
, V
&visitor
) {
552 if (StringIsEmpty(prefix
))
553 VisitAllChildren(visitor
);
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
565 void VisitPrefixChildren(const TCHAR
*prefix
, V
&visitor
) const {
566 if (StringIsEmpty(prefix
))
567 VisitAllChildren(visitor
);
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.
580 void VisitPrefix(const TCHAR
*prefix
, V
&visitor
) {
581 const TCHAR
*match
= MatchPrefix(prefix
);
582 if (match
== nullptr)
585 if (StringIsEmpty(match
)) {
586 VisitValues(visitor
);
587 VisitAllChildren(visitor
);
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.
599 void VisitPrefix(const TCHAR
*prefix
, V
&visitor
) const {
600 const TCHAR
*match
= MatchPrefix(prefix
);
601 if (match
== nullptr)
604 if (StringIsEmpty(match
)) {
605 VisitValues(visitor
);
606 VisitAllChildren(visitor
);
608 VisitPrefixChildren(match
, visitor
);
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
));
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 */
658 const auto m
= FindChild(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
;
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
);
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
);
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
;
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
,
703 out
<< "node '" << node
.label
<< "' {\n";
704 for (const RadixTree
<T
>::Leaf
*leaf
= node
.leaves
; leaf
!= nullptr;
706 out
<< " value " << leaf
->value
<< "\n";
707 for (const RadixTree
<T
>::Node
*child
= node
.children
; child
!= nullptr;
708 child
= child
->next_sibling
)
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.
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
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
750 T
&GetIf(const TCHAR
*key
, T
&default_value
, const P
&predicate
) {
751 const T
*value
= root
.GetIf(key
, predicate
);
752 return value
!= nullptr
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
767 * Get a list of characters following the specified prefix. There
768 * is no special indication whether there is a value for the exact
771 * @param prefix the prefix
772 * @param dest the destination buffer which will be filled with
774 * @param max_length the size of the buffer, including the trailing
776 * @return the destination buffer, or nullptr if the prefix does not
779 TCHAR
*Suggest(const TCHAR
*prefix
, TCHAR
*dest
, size_t max_length
) const {
780 return root
.Suggest(prefix
, dest
, max_length
);
788 * Add a new value with the specified key. Multiple values can
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.
819 void VisitAll(V
&visitor
) {
820 root
.VisitValues(visitor
);
821 root
.VisitAllChildren(visitor
);
825 * Visit all values in alphabetic order.
828 void VisitAll(V
&visitor
) const {
829 root
.VisitValues(visitor
);
830 root
.VisitAllChildren(visitor
);
834 * Visit all key/value pairs in alphabetic order.
837 void VisitAllPairs(V
&visitor
) const {
838 root
.VisitValues(_T(""), visitor
);
839 root
.VisitAllChildren(_T(""), visitor
);
843 * Visit all values with the specified key.
846 void Visit(const TCHAR
*key
, V
&visitor
) {
847 root
.Visit(key
, visitor
);
851 * Visit all values with the specified key.
854 void Visit(const TCHAR
*key
, V
&visitor
) const {
855 root
.Visit(key
, visitor
);
859 * Visit all values matching the specified prefix in alphabetic
863 void VisitPrefix(const TCHAR
*prefix
, V
&visitor
) {
864 root
.VisitPrefix(prefix
, visitor
);
868 * Visit all values matching the specified prefix in alphabetic
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 */