123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468 |
- // Copyright (c) 2014 The go-patricia AUTHORS
- //
- // Use of this source code is governed by The MIT License
- // that can be found in the LICENSE file.
- package patricia
- import (
- "errors"
- )
- //------------------------------------------------------------------------------
- // Trie
- //------------------------------------------------------------------------------
- const (
- DefaultMaxPrefixPerNode = 10
- DefaultMaxChildrenPerSparseNode = 8
- )
- type (
- Prefix []byte
- Item interface{}
- VisitorFunc func(prefix Prefix, item Item) error
- )
- // Trie is a generic patricia trie that allows fast retrieval of items by prefix.
- // and other funky stuff.
- //
- // Trie is not thread-safe.
- type Trie struct {
- prefix Prefix
- item Item
- maxPrefixPerNode int
- maxChildrenPerSparseNode int
- children childList
- }
- // Public API ------------------------------------------------------------------
- type Option func(*Trie)
- // Trie constructor.
- func NewTrie(options ...Option) *Trie {
- trie := &Trie{}
- for _, opt := range options {
- opt(trie)
- }
- if trie.maxPrefixPerNode <= 0 {
- trie.maxPrefixPerNode = DefaultMaxPrefixPerNode
- }
- if trie.maxChildrenPerSparseNode <= 0 {
- trie.maxChildrenPerSparseNode = DefaultMaxChildrenPerSparseNode
- }
- trie.children = newSparseChildList(trie.maxChildrenPerSparseNode)
- return trie
- }
- func MaxPrefixPerNode(value int) Option {
- return func(trie *Trie) {
- trie.maxPrefixPerNode = value
- }
- }
- func MaxChildrenPerSparseNode(value int) Option {
- return func(trie *Trie) {
- trie.maxChildrenPerSparseNode = value
- }
- }
- // Item returns the item stored in the root of this trie.
- func (trie *Trie) Item() Item {
- return trie.item
- }
- // Insert inserts a new item into the trie using the given prefix. Insert does
- // not replace existing items. It returns false if an item was already in place.
- func (trie *Trie) Insert(key Prefix, item Item) (inserted bool) {
- return trie.put(key, item, false)
- }
- // Set works much like Insert, but it always sets the item, possibly replacing
- // the item previously inserted.
- func (trie *Trie) Set(key Prefix, item Item) {
- trie.put(key, item, true)
- }
- // Get returns the item located at key.
- //
- // This method is a bit dangerous, because Get can as well end up in an internal
- // node that is not really representing any user-defined value. So when nil is
- // a valid value being used, it is not possible to tell if the value was inserted
- // into the tree by the user or not. A possible workaround for this is not to use
- // nil interface as a valid value, even using zero value of any type is enough
- // to prevent this bad behaviour.
- func (trie *Trie) Get(key Prefix) (item Item) {
- _, node, found, leftover := trie.findSubtree(key)
- if !found || len(leftover) != 0 {
- return nil
- }
- return node.item
- }
- // Match returns what Get(prefix) != nil would return. The same warning as for
- // Get applies here as well.
- func (trie *Trie) Match(prefix Prefix) (matchedExactly bool) {
- return trie.Get(prefix) != nil
- }
- // MatchSubtree returns true when there is a subtree representing extensions
- // to key, that is if there are any keys in the tree which have key as prefix.
- func (trie *Trie) MatchSubtree(key Prefix) (matched bool) {
- _, _, matched, _ = trie.findSubtree(key)
- return
- }
- // Visit calls visitor on every node containing a non-nil item
- // in alphabetical order.
- //
- // If an error is returned from visitor, the function stops visiting the tree
- // and returns that error, unless it is a special error - SkipSubtree. In that
- // case Visit skips the subtree represented by the current node and continues
- // elsewhere.
- func (trie *Trie) Visit(visitor VisitorFunc) error {
- return trie.walk(nil, visitor)
- }
- // VisitSubtree works much like Visit, but it only visits nodes matching prefix.
- func (trie *Trie) VisitSubtree(prefix Prefix, visitor VisitorFunc) error {
- // Nil prefix not allowed.
- if prefix == nil {
- panic(ErrNilPrefix)
- }
- // Empty trie must be handled explicitly.
- if trie.prefix == nil {
- return nil
- }
- // Locate the relevant subtree.
- _, root, found, leftover := trie.findSubtree(prefix)
- if !found {
- return nil
- }
- prefix = append(prefix, leftover...)
- // Visit it.
- return root.walk(prefix, visitor)
- }
- // VisitPrefixes visits only nodes that represent prefixes of key.
- // To say the obvious, returning SkipSubtree from visitor makes no sense here.
- func (trie *Trie) VisitPrefixes(key Prefix, visitor VisitorFunc) error {
- // Nil key not allowed.
- if key == nil {
- panic(ErrNilPrefix)
- }
- // Empty trie must be handled explicitly.
- if trie.prefix == nil {
- return nil
- }
- // Walk the path matching key prefixes.
- node := trie
- prefix := key
- offset := 0
- for {
- // Compute what part of prefix matches.
- common := node.longestCommonPrefixLength(key)
- key = key[common:]
- offset += common
- // Partial match means that there is no subtree matching prefix.
- if common < len(node.prefix) {
- return nil
- }
- // Call the visitor.
- if item := node.item; item != nil {
- if err := visitor(prefix[:offset], item); err != nil {
- return err
- }
- }
- if len(key) == 0 {
- // This node represents key, we are finished.
- return nil
- }
- // There is some key suffix left, move to the children.
- child := node.children.next(key[0])
- if child == nil {
- // There is nowhere to continue, return.
- return nil
- }
- node = child
- }
- }
- // Delete deletes the item represented by the given prefix.
- //
- // True is returned if the matching node was found and deleted.
- func (trie *Trie) Delete(key Prefix) (deleted bool) {
- // Nil prefix not allowed.
- if key == nil {
- panic(ErrNilPrefix)
- }
- // Empty trie must be handled explicitly.
- if trie.prefix == nil {
- return false
- }
- // Find the relevant node.
- parent, node, _, leftover := trie.findSubtree(key)
- if len(leftover) != 0 {
- return false
- }
- // If the item is already set to nil, there is nothing to do.
- if node.item == nil {
- return false
- }
- // Delete the item.
- node.item = nil
- // Compact since that might be possible now.
- if compacted := node.compact(); compacted != node {
- if parent == nil {
- *node = *compacted
- } else {
- parent.children.replace(node.prefix[0], compacted)
- *parent = *parent.compact()
- }
- }
- return true
- }
- // DeleteSubtree finds the subtree exactly matching prefix and deletes it.
- //
- // True is returned if the subtree was found and deleted.
- func (trie *Trie) DeleteSubtree(prefix Prefix) (deleted bool) {
- // Nil prefix not allowed.
- if prefix == nil {
- panic(ErrNilPrefix)
- }
- // Empty trie must be handled explicitly.
- if trie.prefix == nil {
- return false
- }
- // Locate the relevant subtree.
- parent, root, found, _ := trie.findSubtree(prefix)
- if !found {
- return false
- }
- // If we are in the root of the trie, reset the trie.
- if parent == nil {
- root.prefix = nil
- root.children = newSparseChildList(trie.maxPrefixPerNode)
- return true
- }
- // Otherwise remove the root node from its parent.
- parent.children.remove(root)
- return true
- }
- // Internal helper methods -----------------------------------------------------
- func (trie *Trie) put(key Prefix, item Item, replace bool) (inserted bool) {
- // Nil prefix not allowed.
- if key == nil {
- panic(ErrNilPrefix)
- }
- var (
- common int
- node *Trie = trie
- child *Trie
- )
- if node.prefix == nil {
- if len(key) <= trie.maxPrefixPerNode {
- node.prefix = key
- goto InsertItem
- }
- node.prefix = key[:trie.maxPrefixPerNode]
- key = key[trie.maxPrefixPerNode:]
- goto AppendChild
- }
- for {
- // Compute the longest common prefix length.
- common = node.longestCommonPrefixLength(key)
- key = key[common:]
- // Only a part matches, split.
- if common < len(node.prefix) {
- goto SplitPrefix
- }
- // common == len(node.prefix) since never (common > len(node.prefix))
- // common == len(former key) <-> 0 == len(key)
- // -> former key == node.prefix
- if len(key) == 0 {
- goto InsertItem
- }
- // Check children for matching prefix.
- child = node.children.next(key[0])
- if child == nil {
- goto AppendChild
- }
- node = child
- }
- SplitPrefix:
- // Split the prefix if necessary.
- child = new(Trie)
- *child = *node
- *node = *NewTrie()
- node.prefix = child.prefix[:common]
- child.prefix = child.prefix[common:]
- child = child.compact()
- node.children = node.children.add(child)
- AppendChild:
- // Keep appending children until whole prefix is inserted.
- // This loop starts with empty node.prefix that needs to be filled.
- for len(key) != 0 {
- child := NewTrie()
- if len(key) <= trie.maxPrefixPerNode {
- child.prefix = key
- node.children = node.children.add(child)
- node = child
- goto InsertItem
- } else {
- child.prefix = key[:trie.maxPrefixPerNode]
- key = key[trie.maxPrefixPerNode:]
- node.children = node.children.add(child)
- node = child
- }
- }
- InsertItem:
- // Try to insert the item if possible.
- if replace || node.item == nil {
- node.item = item
- return true
- }
- return false
- }
- func (trie *Trie) compact() *Trie {
- // Only a node with a single child can be compacted.
- if trie.children.length() != 1 {
- return trie
- }
- child := trie.children.head()
- // If any item is set, we cannot compact since we want to retain
- // the ability to do searching by key. This makes compaction less usable,
- // but that simply cannot be avoided.
- if trie.item != nil || child.item != nil {
- return trie
- }
- // Make sure the combined prefixes fit into a single node.
- if len(trie.prefix)+len(child.prefix) > trie.maxPrefixPerNode {
- return trie
- }
- // Concatenate the prefixes, move the items.
- child.prefix = append(trie.prefix, child.prefix...)
- if trie.item != nil {
- child.item = trie.item
- }
- return child
- }
- func (trie *Trie) findSubtree(prefix Prefix) (parent *Trie, root *Trie, found bool, leftover Prefix) {
- // Find the subtree matching prefix.
- root = trie
- for {
- // Compute what part of prefix matches.
- common := root.longestCommonPrefixLength(prefix)
- prefix = prefix[common:]
- // We used up the whole prefix, subtree found.
- if len(prefix) == 0 {
- found = true
- leftover = root.prefix[common:]
- return
- }
- // Partial match means that there is no subtree matching prefix.
- if common < len(root.prefix) {
- leftover = root.prefix[common:]
- return
- }
- // There is some prefix left, move to the children.
- child := root.children.next(prefix[0])
- if child == nil {
- // There is nowhere to continue, there is no subtree matching prefix.
- return
- }
- parent = root
- root = child
- }
- }
- func (trie *Trie) walk(actualRootPrefix Prefix, visitor VisitorFunc) error {
- var prefix Prefix
- // Allocate a bit more space for prefix at the beginning.
- if actualRootPrefix == nil {
- prefix = make(Prefix, 32+len(trie.prefix))
- copy(prefix, trie.prefix)
- prefix = prefix[:len(trie.prefix)]
- } else {
- prefix = make(Prefix, 32+len(actualRootPrefix))
- copy(prefix, actualRootPrefix)
- prefix = prefix[:len(actualRootPrefix)]
- }
- // Visit the root first. Not that this works for empty trie as well since
- // in that case item == nil && len(children) == 0.
- if trie.item != nil {
- if err := visitor(prefix, trie.item); err != nil {
- if err == SkipSubtree {
- return nil
- }
- return err
- }
- }
- // Then continue to the children.
- return trie.children.walk(&prefix, visitor)
- }
- func (trie *Trie) longestCommonPrefixLength(prefix Prefix) (i int) {
- for ; i < len(prefix) && i < len(trie.prefix) && prefix[i] == trie.prefix[i]; i++ {
- }
- return
- }
- // Errors ----------------------------------------------------------------------
- var (
- SkipSubtree = errors.New("Skip this subtree")
- ErrNilPrefix = errors.New("Nil prefix passed into a method call")
- )
|