The Pedigree Project 0.1
RadixTree.h
Go to the documentation of this file.
1/*
2 * Copyright (c) 2008-2014, Pedigree Developers
3 *
4 * Please see the CONTRIB file in the root of the source tree for a full
5 * list of contributors.
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
20#ifndef KERNEL_UTILITIES_RADIX_TREE_H
21#define KERNEL_UTILITIES_RADIX_TREE_H
22
23#include "pedigree/kernel/Log.h"
24#include "pedigree/kernel/compiler.h"
25#include "pedigree/kernel/processor/types.h"
26#include "pedigree/kernel/utilities/Cord.h"
27#include "pedigree/kernel/utilities/Iterator.h"
28#include "pedigree/kernel/utilities/ObjectPool.h"
29#include "pedigree/kernel/utilities/Result.h"
30#include "pedigree/kernel/utilities/String.h"
31#include "pedigree/kernel/utilities/Vector.h"
32#include "pedigree/kernel/utilities/utility.h"
33
45template <class T>
46class EXPORTED_PUBLIC RadixTree {
47 private:
49 class Node {
50 public:
58
59 Node(bool bCaseSensitive)
60 : m_Key(),
61 value(T()),
62 m_Children(),
63 m_pParent(0),
64 m_bCaseSensitive(bCaseSensitive),
65 m_pParentTree(0),
66 m_bHasValue(false) {}
67
68 ~Node();
69
70 // Clears all known children and returns them to the parent ObjectPool
71 void returnAllChildren();
72
76 return doNext();
77 }
82 return 0;
83 }
84
87 Node* findChild(const char* cpKey) const;
88
90 void addChild(Node* pNode);
91
93 void replaceChild(Node* pNodeOld, Node* pNodeNew);
94
96 void removeChild(Node* pChild);
97
101 MatchType matchKey(const char* cpKey, size_t& offset) const;
102
104 Node* getFirstChild() const;
105
109 void prependKey(const String& cpKey);
110
111 void setKey(const char* cpKey);
113 void setKey(const char* cpKey, size_t lengthHint);
115 void setKey(const String& cpKey);
116 inline const char* getKey() const {
117 return m_Key.cstr();
118 }
119 const String& getKeyStr() const {
120 return m_Key;
121 }
122 inline void setValue(const T& pV) {
123 value = pV;
124 m_bHasValue = true;
125 }
126 inline void removeValue() {
127 value = T();
128 m_bHasValue = false;
129 }
130 inline const T& getValue() const {
131 return value;
132 }
133 inline void setParent(Node* pP) {
134 m_pParent = pP;
135 }
136 inline Node* getParent() const {
137 return m_pParent;
138 }
139 inline bool hasValue() const {
140 return m_bHasValue;
141 }
142
143 void dump(void (*emit_line)(const char* s)) const;
144
157
160
166
167 private:
168 Node(const Node&);
169 Node& operator=(const Node&);
170
172 Node* doNext() const;
173
176 Node* getNextSibling() const;
177 };
178
179 public:
181 typedef ::Iterator<T, Node> Iterator;
185
192 RadixTree(bool bCaseSensitive);
195
199
202 size_t count() const;
206 void insert(const String& key, const T& value);
213 MUST_USE_RESULT bool lookup(const String& key, T& value) const;
214
222 template <typename U = T>
223 typename pedigree_std::enable_if<pedigree_std::is_same<U, T>::value &&
224 !pedigree_std::is_same<U, void*>::value,
225 LookupType>::type
226 lookup(const String& key) const {
227 T value = T();
228 if (lookup(key, value)) {
229 return LookupType::withValue(value);
230 }
231 return LookupType::withError(true);
232 }
234 void remove(const String& key);
235
237 void clear();
238
241 Node* iterNode = iter.__getNode();
242 Node* next = iterNode->next();
243 remove(iterNode->getKeyStr());
244 Iterator ret(next);
245 return ret;
246 }
247
250 inline Iterator begin() {
251 if (!m_pRoot) {
252 return Iterator(0);
253 }
254 return Iterator(m_pRoot->hasValue() ? m_pRoot : m_pRoot->next());
255 }
258 inline ConstIterator begin() const {
259 if (!m_pRoot) {
260 return ConstIterator(0);
261 }
262 return ConstIterator(m_pRoot->hasValue() ? m_pRoot : m_pRoot->next());
263 }
266 inline Iterator end() {
267 return Iterator(0);
268 }
271 inline ConstIterator end() const {
272 return ConstIterator(0);
273 }
274
276 void dump(void (*emit_line)(const char* s)) const;
277
278 private:
280 Node* cloneNode(Node* node, Node* parent);
283 Node* p = m_NodePool.allocate(m_bCaseSensitive);
284 p->m_pParent = 0;
285 p->m_pParentTree = this;
286 return p;
287 }
289 void returnNode(Node* p) {
290 if (p) {
291 p->returnAllChildren();
292 // wipe out info that shouldn't go back to the pool
293 p->m_Key.clear();
294 p->value = T();
295 p->m_pParent = 0;
296 p->m_bHasValue = false;
297 m_NodePool.deallocate(p);
298 }
299 }
300
302 size_t m_nItems;
310};
311
312template <class T>
313RadixTree<T>::RadixTree() : m_nItems(0), m_pRoot(0), m_bCaseSensitive(true), m_NodePool() {}
314
315template <class T>
316RadixTree<T>::RadixTree(bool bCaseSensitive)
317 : m_nItems(0), m_pRoot(0), m_bCaseSensitive(bCaseSensitive), m_NodePool() {}
318
319template <class T>
321 clear();
322 returnNode(m_pRoot);
323}
324
325template <class T>
327 : m_nItems(0), m_pRoot(0), m_bCaseSensitive(x.m_bCaseSensitive), m_NodePool() {
328 clear();
330 m_pRoot = cloneNode(x.m_pRoot, 0);
331 m_nItems = x.m_nItems;
332}
333
334template <class T>
336 if (this == &x)
337 return *this;
338
339 clear();
340 returnNode(m_pRoot);
341 m_pRoot = cloneNode(x.m_pRoot, 0);
342 m_nItems = x.m_nItems;
344 return *this;
345}
346
347template <class T>
348size_t RadixTree<T>::count() const {
349 return m_nItems;
350}
351
352template <class T>
353void RadixTree<T>::insert(const String& key, const T& value) {
354 if (!m_pRoot) {
355 // The root node always exists and is a lambda transition node
356 // (zero-length key). This removes the need for most special cases.
357 m_pRoot = getNewNode();
358 m_pRoot->setKey(0);
359 }
360
361 if (!key.length()) {
362 if (!m_pRoot->hasValue())
363 ++m_nItems;
364 m_pRoot->setValue(value);
365 return;
366 }
367
368 Node* pNode = m_pRoot;
369
370 const char* cpKey = static_cast<const char*>(key);
371 const char* cpKeyOrig = cpKey;
372 size_t cpKeyLength = key.length();
373
374 while (true) {
375 size_t partialOffset = 0;
376 switch (pNode->matchKey(cpKey, partialOffset)) {
377 case Node::ExactMatch: {
378 if (!pNode->hasValue()) {
379 m_nItems++;
380 }
381
382 pNode->setValue(value);
383 return;
384 }
385 case Node::NoMatch: {
386 FATAL("RadixTree: algorithmic error!");
387 break;
388 }
389 case Node::PartialMatch: {
390 // We need to create an intermediate node that contains the
391 // partial match, then adjust the key of this node.
392
393 // Find the common key prefix.
394 size_t i = partialOffset;
395
396 Node* pInter = getNewNode();
397
398 // Intermediate node's key is the common prefix of both keys.
399 pInter->m_Key.assign(cpKey, partialOffset);
400
401 // Must do this before pNode's key is changed.
402 pNode->getParent()->replaceChild(pNode, pInter);
403
404 // pNode's new key is the uncommon postfix.
405 size_t len = pNode->m_Key.length();
406
407 pNode->m_Key.ltrim(partialOffset);
408
409 // If the uncommon postfix of the key is non-zero length, we
410 // have to create another node, a child of pInter.
411 if (cpKey[partialOffset] != 0) {
412 Node* pChild = getNewNode();
413 pChild->setKey(&cpKey[partialOffset],
414 (cpKeyLength - partialOffset - (cpKey - cpKeyOrig)));
415 pChild->setValue(value);
416 pChild->setParent(pInter);
417 pInter->addChild(pChild);
418 } else {
419 pInter->setValue(value);
420 }
421
422 pInter->setParent(pNode->getParent());
423 pInter->addChild(pNode);
424 pNode->setParent(pInter);
425
426 m_nItems++;
427 return;
428 }
429 case Node::OverMatch: {
430 cpKey += pNode->m_Key.length();
431
432 Node* pChild = pNode->findChild(cpKey);
433 if (pChild) {
434 pNode = pChild;
435 // Iterative case.
436 break;
437 } else {
438 // No child - create a new one.
439 pChild = getNewNode();
440 pChild->setKey(cpKey, cpKeyLength - (cpKey - cpKeyOrig));
441 pChild->setValue(value);
442 pChild->setParent(pNode);
443 pNode->addChild(pChild);
444
445 m_nItems++;
446 return;
447 }
448 }
449 }
450 }
451}
452
453template <class T>
454bool RadixTree<T>::lookup(const String& key, T& value) const {
455 value = T();
456
457 if (!m_pRoot) {
458 return false;
459 }
460
461 if (!key.length()) {
462 if (m_pRoot->hasValue()) {
463 value = m_pRoot->getValue();
464 return true;
465 }
466 return false;
467 }
468
469 Node* pNode = m_pRoot;
470
471 const char* cpKey = static_cast<const char*>(key);
472
473 while (true) {
474 size_t offset = 0;
475 switch (pNode->matchKey(cpKey, offset)) {
476 case Node::ExactMatch:
477 if (!pNode->hasValue()) {
478 // No value here, exact match on key. This can happen in
479 // cases where we needed to create a node to split a key
480 // but nothing was attached to the split node.
481 return false;
482 }
483 value = pNode->getValue();
484 return true;
485 case Node::NoMatch:
486 case Node::PartialMatch:
487 return false;
488 case Node::OverMatch: {
489 cpKey += pNode->m_Key.length();
490
491 Node* pChild = pNode->findChild(cpKey);
492 if (pChild) {
493 pNode = pChild;
494 // Iterative case.
495 break;
496 } else {
497 return false;
498 }
499 }
500 }
501 }
502}
503
504template <class T>
505void RadixTree<T>::remove(const String& key) {
506 if (!m_pRoot) {
507 // The root node always exists and is a lambda transition node
508 // (zero-length key). This removes the need for most special cases.
509 m_pRoot = getNewNode();
510 m_pRoot->setKey(0);
511 }
512
513 Node* pNode = m_pRoot;
514
515 const char* cpKey = static_cast<const char*>(key);
516
517 // Our invariant is that the root node always exists. Therefore we must
518 // special case here so it doesn't get deleted.
519 if (!cpKey || (*cpKey == 0)) {
520 if (m_pRoot->hasValue()) {
521 m_pRoot->removeValue();
522 --m_nItems;
523 }
524 return;
525 }
526
527 while (true) {
528 size_t offset = 0;
529 switch (pNode->matchKey(cpKey, offset)) {
530 case Node::ExactMatch: {
531 if (!pNode->hasValue())
532 return;
533
534 // Delete this node. If we set the value to zero, it is
535 // effectively removed from the map. There are only certain
536 // cases in which we can delete the node completely, however.
537 pNode->removeValue();
538 m_nItems--;
539
540 // We have the invariant that the tree is always optimised. This
541 // means that when we delete a node we only have to optimise the
542 // local branch. There are two situations that need covering:
543 // (a) No children. This means it's a leaf node and can be
544 // deleted. We then need to consider its parent,
545 // which, if its value is zero and now has zero or one
546 // children can be optimised itself.
547 // (b) One child. This is a linear progression and the child
548 // node's key can be changed to be concatenation of
549 // pNode's and its. This doesn't affect anything farther
550 // up the tree and so no recursion is needed.
551
552 Node* pParent = 0;
553 if (pNode->m_Children.count() == 0) {
554 // Leaf node, can just delete.
555 pParent = pNode->getParent();
556 pParent->removeChild(pNode);
557 returnNode(pNode);
558
559 pNode = pParent;
560 // Optimise up the tree.
561 while (true) {
562 if (pNode == m_pRoot)
563 return;
564
565 if (pNode->m_Children.count() == 1 && !pNode->hasValue())
566 // Break out of this loop and get caught in the next
567 // if(pNode->m_nChildren == 1)
568 break;
569
570 if (pNode->m_Children.count() == 0 && !pNode->hasValue()) {
571 // Leaf node, can just delete.
572 pParent = pNode->getParent();
573 pParent->removeChild(pNode);
574 returnNode(pNode);
575
576 pNode = pParent;
577 continue;
578 }
579 return;
580 }
581 }
582
583 if (pNode->m_Children.count() == 1) {
584 // Change the child's key to be the concatenation of ours
585 // and its.
586 Node* pChild = pNode->getFirstChild();
587 pParent = pNode->getParent();
588
589 // Must call this before delete, so pChild doesn't get
590 // deleted.
591 pNode->removeChild(pChild);
592
593 pChild->prependKey(pNode->getKeyStr());
594 pChild->setParent(pParent);
595 pParent->removeChild(pNode);
596 pParent->addChild(pChild);
597
598 returnNode(pNode);
599 }
600 return;
601 }
602 case Node::NoMatch:
603 case Node::PartialMatch:
604 // Can't happen unless the key didn't actually exist.
605 return;
606 case Node::OverMatch: {
607 cpKey += pNode->m_Key.length();
608
609 Node* pChild = pNode->findChild(cpKey);
610 if (pChild) {
611 pNode = pChild;
612 // Iterative case.
613 break;
614 } else
615 return;
616 }
617 }
618 }
619}
620
621template <class T>
623 // Deal with the easy case first.
624 if (!pNode)
625 return 0;
626
627 Node* n = getNewNode();
628 n->setKey(pNode->m_Key);
629 if (pNode->hasValue())
630 n->setValue(pNode->value);
631 n->setParent(pParent);
632
634 it != pNode->m_Children.end(); ++it) {
635 n->addChild(cloneNode((*it), n));
636 }
637
638 return n;
639}
640
641template <class T>
643 if (!m_pRoot)
644 m_pRoot = getNewNode();
645 else
646 m_pRoot->returnAllChildren();
647
648 m_pRoot->setKey(0);
649 m_pRoot->removeValue();
650 m_pRoot->setParent(0);
651 m_nItems = 0;
652}
653
654template <class T>
655void RadixTree<T>::dump(void (*emit_line)(const char* s)) const {
656 if (m_pRoot) {
657 m_pRoot->dump(emit_line);
658 }
659}
660
661//
662// RadixTree::Node implementation.
663//
664
665template <class T>
667 returnAllChildren();
668}
669
670template <class T>
672 // Returns depth-first, which ensures we're not returning any children
673 // while the ObjectPool lock is held.
674 for (auto it : m_Children) {
675 it->returnAllChildren();
676 m_pParentTree->returnNode(it);
677 }
678
679 m_Children.clear();
680}
681
682template <class T>
683typename RadixTree<T>::Node* RadixTree<T>::Node::findChild(const char* cpKey) const {
684 for (auto it : m_Children) {
685 size_t offset = 0;
686 if (it->matchKey(cpKey, offset) != NoMatch) {
687 return it;
688 }
689 }
690 return 0;
691}
692
693template <class T>
695 if (pNode)
696 m_Children.pushBack(pNode);
697}
698
699template <class T>
700void RadixTree<T>::Node::replaceChild(Node* pNodeOld, Node* pNodeNew) {
701 for (auto it = m_Children.begin(); it != m_Children.end(); ++it) {
702 if (*it == pNodeOld) {
703 *it = pNodeNew;
704 break;
705 }
706 }
707}
708
709template <class T>
711 for (typename RadixTree<T>::Node::childlist_t::Iterator it = m_Children.begin();
712 it != m_Children.end();) {
713 if ((*it) == pChild) {
714 it = m_Children.erase(it);
715 } else
716 ++it;
717 }
718}
719
720template <class T>
722 size_t& offset) const {
723 // Cannot partially match (e.g. toast/toastier == PartialMatch if the
724 // cpKey is longer (e.g. toastier/toast == OverMatch)).
725 if (!m_Key.length()) {
726 return OverMatch;
727 }
728
729 const char* myKey = getKey();
730
731 // Do some quick checks early.
732 if ((m_bCaseSensitive && (cpKey[0] != myKey[0])) ||
733 ((!m_bCaseSensitive) && (toLower(cpKey[0]) != toLower(myKey[0])))) {
734 // non-partial, first character didn't even match
735 return NoMatch;
736 }
737
738 size_t i = 0;
739 int r = StringCompareCase(cpKey, myKey, m_bCaseSensitive, m_Key.length() + 1, &i);
740
741 if (r == 0) {
742 // exact match, all characters & null terminators matched
743 return ExactMatch;
744 } else if (m_Key[i] == 0) {
745 return OverMatch;
746 } else {
747 // partial, both strings share a common prefix
748 offset = i;
749 return PartialMatch;
750 }
751}
752
753template <class T>
754void RadixTree<T>::Node::setKey(const char* cpKey) {
755 m_Key.assign(cpKey);
756}
757
758template <class T>
759void RadixTree<T>::Node::setKey(const char* cpKey, size_t lengthHint) {
760 m_Key.assign(cpKey, lengthHint);
761}
762
763template <class T>
765 m_Key.assign(cpKey);
766}
767
768template <class T>
770 return *(m_Children.begin());
771}
772
773template <class T>
775 String tmp = pedigree_std::move(m_Key);
776 m_Key.assign(cpKey);
777 m_Key += tmp;
778}
779
780template <class T>
782 // pNode needs to be settable, but not what it points to!
783 Node const* pNode = this;
784 while ((pNode == this) || (pNode && !pNode->hasValue())) {
785 Node const* tmp;
786 if (pNode->m_Children.count())
787 pNode = pNode->getFirstChild();
788 else {
789 tmp = pNode;
790 pNode = 0;
791 while (tmp && tmp->m_pParent != 0 /* Root node */) {
792 if ((pNode = tmp->getNextSibling()) != 0)
793 break;
794 tmp = tmp->m_pParent;
795 }
796 if (tmp->m_pParent == 0)
797 return 0;
798 }
799 }
800 return const_cast<Node*>(pNode);
801}
802
803template <class T>
805 if (!m_pParent)
806 return 0;
807
808 bool b = false;
809 for (typename RadixTree<T>::Node::childlist_t::Iterator it = m_pParent->m_Children.begin();
810 it != m_pParent->m_Children.end(); ++it) {
811 if (b)
812 return (*it);
813 if ((*it) == this)
814 b = true;
815 }
816
817 return 0;
818}
819
820template <class T>
821void RadixTree<T>::Node::dump(void (*emit_line)(const char* s)) const {
822 for (auto it : m_Children) {
823 // depth-first dump the next node
824 it->dump(emit_line);
825
826 // dump this connection
827 String s;
828 s.Format(" \"Node<%p: %s>\" -> \"Node<%p: %s>\";", static_cast<const void*>(it), it->getKey(),
829 static_cast<const void*>(this), static_cast<const char*>(m_Key));
830 emit_line(static_cast<const char*>(s));
831 }
832}
833
834// Explicitly instantiate RadixTree<void*> early.
835extern template class RadixTree<void*>; // IWYU pragma: keep
836
839#endif
An iterator applicable for many data structures.
Definition Iterator.h:41
Struct * __getNode()
Definition Iterator.h:121
const bool m_bCaseSensitive
Definition RadixTree.h:156
RadixTree * m_pParentTree
Definition RadixTree.h:159
childlist_t m_Children
Definition RadixTree.h:152
@ NoMatch
Key didn't match node key at all.
Definition RadixTree.h:54
@ PartialMatch
A subset of key matched the node key.
Definition RadixTree.h:55
@ ExactMatch
Key matched node key exactly.
Definition RadixTree.h:53
Node * previous()
Definition RadixTree.h:81
Node * next()
Definition RadixTree.h:75
A key/value dictionary for string keys.
Definition RadixTree.h:46
Iterator::Const ConstIterator
Definition RadixTree.h:183
ConstIterator end() const
Definition RadixTree.h:271
Iterator end()
Definition RadixTree.h:266
const bool m_bCaseSensitive
Definition RadixTree.h:306
ObjectPool< Node > m_NodePool
Definition RadixTree.h:309
Node * m_pRoot
Definition RadixTree.h:304
void returnNode(Node *p)
Definition RadixTree.h:289
size_t m_nItems
Definition RadixTree.h:302
::Iterator< T, Node > Iterator
Definition RadixTree.h:181
Iterator erase(Iterator iter)
Definition RadixTree.h:240
pedigree_std::enable_if< pedigree_std::is_same< U, T >::value &&!pedigree_std::is_same< U, void * >::value, LookupType >::type lookup(const String &key) const
Definition RadixTree.h:226
Node * getNewNode()
Definition RadixTree.h:282
ConstIterator begin() const
Definition RadixTree.h:258
Iterator begin()
Definition RadixTree.h:250
void ltrim(size_t n)
Definition String.cc:408
A vector / dynamic array.
Definition Vector.h:33
Iterator end()
Definition Vector.h:172
Node * * Iterator
Definition Vector.h:36
Iterator begin()
Definition Vector.h:162
Node * doNext() const
Definition RadixTree.h:781
void addChild(Node *pNode)
Definition RadixTree.h:694
RadixTree(bool bCaseSensitive)
Definition RadixTree.h:316
void remove(const String &key)
Definition RadixTree.h:505
RadixTree & operator=(const RadixTree &x)
Definition RadixTree.h:335
MUST_USE_RESULT bool lookup(const String &key, T &value) const
Definition RadixTree.h:454
Node * cloneNode(Node *node, Node *parent)
Definition RadixTree.h:622
void insert(const String &key, const T &value)
Definition RadixTree.h:353
void removeChild(Node *pChild)
Definition RadixTree.h:710
size_t count() const
Definition RadixTree.h:348
void replaceChild(Node *pNodeOld, Node *pNodeNew)
Definition RadixTree.h:700
Node * findChild(const char *cpKey) const
Definition RadixTree.h:683
void prependKey(const String &cpKey)
Definition RadixTree.h:774
RadixTree(const RadixTree< T > &x)
Definition RadixTree.h:326
void clear()
Definition RadixTree.h:642
Node * getFirstChild() const
Definition RadixTree.h:769
Node * getNextSibling() const
Definition RadixTree.h:804
MatchType matchKey(const char *cpKey, size_t &offset) const
Definition RadixTree.h:721
size_t count() const
Definition Vector.h:270
void dump(void(*emit_line)(const char *s)) const
Definition RadixTree.h:655