cloudflared/vendor/github.com/golang-collections/collections/tst/tst.go
2018-07-19 15:02:24 -05:00

307 lines
5.6 KiB
Go

package tst
import (
"fmt"
)
type (
Node struct {
key byte
value interface{}
left, middle, right *Node
}
NodeIterator struct {
step int
node *Node
prev *NodeIterator
}
TernarySearchTree struct {
length int
root *Node
}
)
// Create a new ternary search tree
func New() *TernarySearchTree {
tree := &TernarySearchTree{}
tree.Init()
return tree
}
// Iterate over the collection
func (this *TernarySearchTree) Do(callback func(string, interface{})bool) {
if this.Len() == 0 {
return
}
bs := []byte{}
i := &NodeIterator{0,this.root,nil}
for i != nil {
switch i.step {
// Left
case 0:
i.step++
if i.node.left != nil {
i = &NodeIterator{0,i.node.left,i}
continue
}
// Value
case 1:
i.step++
if i.node.key > 0 {
bs = append(bs, i.node.key)
}
if i.node.value != nil {
if !callback(string(bs), i.node.value) {
return
}
continue
}
// Middle
case 2:
i.step++
if i.node.middle != nil {
i = &NodeIterator{0,i.node.middle,i}
continue
}
// Right
case 3:
if len(bs) > 0 {
bs = bs[:len(bs)-1]
}
i.step++
if i.node.right != nil {
i = &NodeIterator{0,i.node.right,i}
continue
}
// Backtrack
case 4:
i = i.prev
}
}
}
// Get the value at the specified key. Returns nil if not found.
func (this *TernarySearchTree) Get(key string) interface{} {
if this.length == 0 {
return nil
}
node := this.root
bs := []byte(key)
for i := 0; i < len(bs); {
b := bs[i]
if b > node.key {
if node.right == nil {
return nil
}
node = node.right
} else if (b < node.key) {
if node.left == nil {
return nil
}
node = node.left
} else {
i++
if i < len(bs) {
if node.middle == nil {
return nil
}
node = node.middle
} else {
break
}
}
}
return node.value
}
func (this *TernarySearchTree) GetLongestPrefix(key string) interface{} {
if this.length == 0 {
return nil
}
n := this.root
v := n.value
bs := []byte(key)
for i := 0; i < len(bs); {
b := bs[i]
if n.value != nil {
v = n.value
}
if b > n.key {
if n.right == nil {
break
}
n = n.right
} else if b < n.key {
if n.left == nil {
break
}
n = n.left
} else {
i++
if i < len(bs) {
if n.middle == nil {
break
}
n = n.middle
} else {
break
}
}
}
if n.value != nil {
v = n.value
}
return v
}
// Test to see whether or not the given key is contained in the tree.
func (this *TernarySearchTree) Has(key string) bool {
return this.Get(key) != nil
}
// Initialize the tree (reset it so that it's empty). New will do this for you.
func (this *TernarySearchTree) Init() {
this.length = 0
this.root = nil
}
// Insert a new key value pair into the collection
func (this *TernarySearchTree) Insert(key string, value interface{}) {
// If the value is nil then remove this key from the collection
if value == nil {
this.Remove(key)
return
}
if this.length == 0 {
this.root = &Node{0,nil,nil,nil,nil}
}
t := this.root
bs := []byte(key)
for i := 0; i < len(bs); {
b := bs[i]
if b > t.key {
if t.right == nil {
t.right = &Node{b,nil,nil,nil,nil}
}
t = t.right
} else if b < t.key {
if t.left == nil {
t.left = &Node{b,nil,nil,nil,nil}
}
t = t.left
} else {
i++
if i < len(bs) {
if t.middle == nil {
t.middle = &Node{bs[i],nil,nil,nil,nil}
}
t = t.middle
}
}
}
if t.value == nil {
this.length++
}
t.value = value
}
// Get the number of items stored in the tree
func (this *TernarySearchTree) Len() int {
return this.length
}
// Remove a key from the collection
func (this *TernarySearchTree) Remove(key string) interface{} {
if this.length == 0 {
return nil
}
var remove *Node
var direction int
t := this.root
bs := []byte(key)
for i := 0; i < len(bs); {
b := bs[i]
if b > t.key {
// Not in the collection
if t.right == nil {
return nil
}
// This is a branch so we have to keep it
remove = t
direction = 1
// Move to the next node
t = t.right
} else if b < t.key {
// Not in the collection
if t.left == nil {
return nil
}
// This is a branch so we have to keep it
remove = t
direction = -1
// Move to the next node
t = t.left
} else {
i++
if i < len(bs) {
// Not in the collection
if t.middle == nil {
return nil
}
// Has a value so we need to keep at least this much
if t.value != nil {
remove = t
direction = 0
}
// Move to the next node
t = t.middle
}
}
}
// If this was the only item in the tree, set the root pointer to nil
if this.length == 1 {
this.root = nil
} else {
if direction == -1 {
remove.left = nil
} else if direction == 0 {
remove.middle = nil
} else {
remove.right = nil
}
}
this.length--
return t.value
}
func (this *TernarySearchTree) String() string {
if this.length == 0 {
return "{}"
}
return this.root.String()
}
// Dump the tree to a string for easier debugging
func (this *Node) String() string {
str := "{" + string(this.key)
if this.value != nil {
str += ":" + fmt.Sprint(this.value)
}
if this.left != nil {
str += this.left.String()
} else {
str += " "
}
if this.middle != nil {
str += this.middle.String()
} else {
str += " "
}
if this.right != nil {
str += this.right.String()
} else {
str += " "
}
str += "}"
return str
}