storj.io/minio@v0.0.0-20230509071714-0cbc90f649b1/pkg/trie/trie.go (about)

     1  /*
     2   * MinIO Cloud Storage, (C) 2014, 2015, 2016, 2017 MinIO, Inc.
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *     http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  
    17  // Package trie implements a simple trie tree for minio server/tools borrows
    18  // idea from - https://godoc.org/golang.org/x/text/internal/triegen.
    19  package trie
    20  
    21  // Node trie tree node container carries value and children.
    22  type Node struct {
    23  	exists bool
    24  	value  string
    25  	child  map[rune]*Node // runes as child.
    26  }
    27  
    28  // newNode create a new trie node.
    29  func newNode() *Node {
    30  	return &Node{
    31  		exists: false,
    32  		value:  "",
    33  		child:  make(map[rune]*Node),
    34  	}
    35  }
    36  
    37  // Trie is a trie container.
    38  type Trie struct {
    39  	root *Node
    40  	size int
    41  }
    42  
    43  // Root returns root node.
    44  func (t *Trie) Root() *Node {
    45  	return t.root
    46  }
    47  
    48  // Insert insert a key.
    49  func (t *Trie) Insert(key string) {
    50  	curNode := t.root
    51  	for _, v := range key {
    52  		if curNode.child[v] == nil {
    53  			curNode.child[v] = newNode()
    54  		}
    55  		curNode = curNode.child[v]
    56  	}
    57  
    58  	if !curNode.exists {
    59  		// increment when new rune child is added.
    60  		t.size++
    61  		curNode.exists = true
    62  	}
    63  	// value is stored for retrieval in future.
    64  	curNode.value = key
    65  }
    66  
    67  // PrefixMatch - prefix match.
    68  func (t *Trie) PrefixMatch(key string) []string {
    69  	node, _ := t.findNode(key)
    70  	if node == nil {
    71  		return nil
    72  	}
    73  	return t.Walk(node)
    74  }
    75  
    76  // Walk the tree.
    77  func (t *Trie) Walk(node *Node) (ret []string) {
    78  	if node.exists {
    79  		ret = append(ret, node.value)
    80  	}
    81  	for _, v := range node.child {
    82  		ret = append(ret, t.Walk(v)...)
    83  	}
    84  	return
    85  }
    86  
    87  // find nodes corresponding to key.
    88  func (t *Trie) findNode(key string) (node *Node, index int) {
    89  	curNode := t.root
    90  	f := false
    91  	for k, v := range key {
    92  		if f {
    93  			index = k
    94  			f = false
    95  		}
    96  		if curNode.child[v] == nil {
    97  			return nil, index
    98  		}
    99  		curNode = curNode.child[v]
   100  		if curNode.exists {
   101  			f = true
   102  		}
   103  	}
   104  
   105  	if curNode.exists {
   106  		index = len(key)
   107  	}
   108  
   109  	return curNode, index
   110  }
   111  
   112  // NewTrie create a new trie.
   113  func NewTrie() *Trie {
   114  	return &Trie{
   115  		root: newNode(),
   116  		size: 0,
   117  	}
   118  }