From 8912b6bf3b22ff668b6448742cd50e7b837182ec Mon Sep 17 00:00:00 2001 From: Bala FA Date: Sat, 11 Feb 2017 01:21:41 +0530 Subject: [PATCH] trie: new package (#3729) This implements a simple trie tree for minio server/tools. This package borrows idea from https://godoc.org/golang.org/x/text/internal/triegen. --- cmd/commands.go | 7 ++- cmd/main.go | 2 +- {cmd => pkg/trie}/trie.go | 80 ++++++++++++++++++---------------- {cmd => pkg/trie}/trie_test.go | 12 ++--- 4 files changed, 55 insertions(+), 46 deletions(-) rename {cmd => pkg/trie}/trie.go (58%) rename {cmd => pkg/trie}/trie_test.go (89%) diff --git a/cmd/commands.go b/cmd/commands.go index 96aa05ec0..b74f33f4a 100644 --- a/cmd/commands.go +++ b/cmd/commands.go @@ -16,13 +16,16 @@ package cmd -import "github.com/minio/cli" +import ( + "github.com/minio/cli" + "github.com/minio/minio/pkg/trie" +) // Collection of minio commands currently supported are. var commands = []cli.Command{} // Collection of minio commands currently supported in a trie tree. -var commandsTree = newTrie() +var commandsTree = trie.NewTrie() // registerCommand registers a cli command. func registerCommand(command cli.Command) { diff --git a/cmd/main.go b/cmd/main.go index e6db20ad6..5bfb8f77b 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -94,7 +94,7 @@ func findClosestCommands(command string) []string { sort.Strings(closestCommands) // Suggest other close commands - allow missed, wrongly added and // even transposed characters - for _, value := range commandsTree.walk(commandsTree.root) { + for _, value := range commandsTree.Walk(commandsTree.Root()) { if sort.SearchStrings(closestCommands, value.(string)) < len(closestCommands) { continue } diff --git a/cmd/trie.go b/pkg/trie/trie.go similarity index 58% rename from cmd/trie.go rename to pkg/trie/trie.go index fb84c3556..d32858c13 100644 --- a/cmd/trie.go +++ b/pkg/trie/trie.go @@ -1,5 +1,5 @@ /* - * Minio Cloud Storage, (C) 2015 Minio, Inc. + * Minio Cloud Storage, (C) 2014, 2015, 2016, 2017 Minio, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,80 +14,78 @@ * limitations under the License. */ -package cmd +// Package trie implements a simple trie tree for minio server/tools borrows +// idea from - https://godoc.org/golang.org/x/text/internal/triegen. +package trie -// This package borrows idea from - https://godoc.org/golang.org/x/text/internal/triegen +// Node trie tree node container carries value and children. +type Node struct { + exists bool + value interface{} + child map[rune]*Node // runes as child. +} -// Trie trie container +// newNode create a new trie node. +func newNode() *Node { + return &Node{ + exists: false, + value: nil, + child: make(map[rune]*Node), + } +} + +// Trie is a trie container. type Trie struct { - root *trieNode + root *Node size int } -// newTrie get new trie -func newTrie() *Trie { - return &Trie{ - root: newTrieNode(), - size: 0, - } +// Root returns root node. +func (t *Trie) Root() *Node { + return t.root } -// trieNode trie tree node container carries value and children -type trieNode struct { - exists bool - value interface{} - child map[rune]*trieNode // runes as child -} - -func newTrieNode() *trieNode { - return &trieNode{ - exists: false, - value: nil, - child: make(map[rune]*trieNode), - } -} - -// Insert insert a key +// Insert insert a key. func (t *Trie) Insert(key string) { curNode := t.root for _, v := range key { if curNode.child[v] == nil { - curNode.child[v] = newTrieNode() + curNode.child[v] = newNode() } curNode = curNode.child[v] } if !curNode.exists { - // increment when new rune child is added + // increment when new rune child is added. t.size++ curNode.exists = true } - // value is stored for retrieval in future + // value is stored for retrieval in future. curNode.value = key } -// PrefixMatch - prefix match +// PrefixMatch - prefix match. func (t *Trie) PrefixMatch(key string) []interface{} { node, _ := t.findNode(key) if node != nil { - return t.walk(node) + return t.Walk(node) } return []interface{}{} } -// walk the tree -func (t *Trie) walk(node *trieNode) (ret []interface{}) { +// Walk the tree. +func (t *Trie) Walk(node *Node) (ret []interface{}) { if node.exists { ret = append(ret, node.value) } for _, v := range node.child { - ret = append(ret, t.walk(v)...) + ret = append(ret, t.Walk(v)...) } return } -// find nodes corresponding to key -func (t *Trie) findNode(key string) (node *trieNode, index int) { +// find nodes corresponding to key. +func (t *Trie) findNode(key string) (node *Node, index int) { curNode := t.root f := false for k, v := range key { @@ -110,3 +108,11 @@ func (t *Trie) findNode(key string) (node *trieNode, index int) { return curNode, index } + +// NewTrie create a new trie. +func NewTrie() *Trie { + return &Trie{ + root: newNode(), + size: 0, + } +} diff --git a/cmd/trie_test.go b/pkg/trie/trie_test.go similarity index 89% rename from cmd/trie_test.go rename to pkg/trie/trie_test.go index b37093144..454b898e0 100644 --- a/cmd/trie_test.go +++ b/pkg/trie/trie_test.go @@ -14,7 +14,7 @@ * limitations under the License. */ -package cmd +package trie import ( "testing" @@ -23,7 +23,7 @@ import ( // Simply make sure creating a new tree works. func TestNewTrie(t *testing.T) { var trie *Trie - trie = newTrie() + trie = NewTrie() if trie.size != 0 { t.Errorf("expected size 0, got: %d", trie.size) @@ -33,7 +33,7 @@ func TestNewTrie(t *testing.T) { // Ensure that we can insert new keys into the tree, then check the size. func TestInsert(t *testing.T) { var trie *Trie - trie = newTrie() + trie = NewTrie() // We need to have an empty tree to begin with. if trie.size != 0 { @@ -52,10 +52,10 @@ func TestInsert(t *testing.T) { // Ensure that PrefixMatch gives us the correct two keys in the tree. func TestPrefixMatch(t *testing.T) { var trie *Trie - trie = newTrie() + trie = NewTrie() // Feed it some fodder: only 'minio' and 'miny-os' should trip the matcher. - trie.Insert(globalMinioDefaultOwnerID) + trie.Insert("minio") trie.Insert("amazon") trie.Insert("cheerio") trie.Insert("miny-o's") @@ -65,7 +65,7 @@ func TestPrefixMatch(t *testing.T) { t.Errorf("expected two matches, got: %d", len(matches)) } - if matches[0] != globalMinioDefaultOwnerID && matches[1] != globalMinioDefaultOwnerID { + if matches[0] != "minio" && matches[1] != "minio" { t.Errorf("expected one match to be 'minio', got: '%s' and '%s'", matches[0], matches[1]) } }