TUN-528: Move cloudflared into a separate repo

This commit is contained in:
Areg Harutyunyan
2018-05-01 18:45:06 -05:00
parent e8c621a648
commit d06fc520c7
4726 changed files with 1763680 additions and 0 deletions

View File

@@ -0,0 +1,20 @@
Copyright (c) 2012 Caleb Doxsey
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@@ -0,0 +1,26 @@
# Badgerodon Collections
Maps and slices go a long way in Go, but sometimes you need more. This is a collection of collections that may be useful.
## Queue
A [queue](http://en.wikipedia.org/wiki/Queue_(data_structure%29) is a first-in first-out data structure.
## Set
A [set](http://en.wikipedia.org/wiki/Set_(computer_science%29) is an unordered collection of unique values typically used for testing membership.
## Skip list
A [skip list](http://en.wikipedia.org/wiki/Skip_list) is a data structure that stores nodes in a hierarchy of linked lists. It gives performance similar to binary search trees by using a random number of forward links to skip parts of the list.
## Splay Tree
A [splay tree](http://en.wikipedia.org/wiki/Splay_tree) is a type of binary search tree where every access to the tree results in the tree being rearranged so that the current node gets put on top.
## Stack
A [stack](http://en.wikipedia.org/wiki/Stack_(abstract_data_type%29) is a last-in last-out data structure.
## Trie
A [trie](http://en.wikipedia.org/wiki/Trie) is a type of tree where each node represents one byte of a key.
## Ternary Search Tree
A [ternary search tree](http://en.wikipedia.org/wiki/Ternary_search_tree) is similar to a trie in that nodes store the letters of the key, but instead of either using a list or hash at each node a binary tree is used. Ternary search trees have the performance benefits of a trie without the usual memory costs.

View File

@@ -0,0 +1,27 @@
package collections
type (
Collection interface {
Do(func(interface{})bool)
}
)
func GetRange(c Collection, start, length int) []interface{} {
end := start + length
items := make([]interface{}, length)
i := 0
j := 0
c.Do(func(item interface{})bool{
if i >= start {
if i < end {
items[j] = item
j++
} else {
return false
}
}
i++
return true
})
return items[:j]
}

View File

@@ -0,0 +1,52 @@
package grid
import (
. "github.com/badgerodon/collections"
)
type (
Grid struct {
values []interface{}
cols, rows int
}
)
func New(cols, rows int) *Grid {
return &Grid{
values: make([]interface{}, cols*rows),
cols: cols,
rows: rows,
}
}
func (this *Grid) Do(f func(p Point, value interface{})) {
for x := 0; x < this.cols; x++ {
for y := 0; y < this.rows; y++ {
f(Point{x, y}, this.values[x*this.cols+y])
}
}
}
func (this *Grid) Get(p Point) interface{} {
if p.X < 0 || p.Y < 0 || p.X >= this.cols || p.Y >= this.rows {
return nil
}
v, _ := this.values[p.X*this.cols+p.Y]
return v
}
func (this *Grid) Rows() int {
return this.rows
}
func (this *Grid) Cols() int {
return this.cols
}
func (this *Grid) Len() int {
return this.rows * this.cols
}
func (this *Grid) Set(p Point, v interface{}) {
}

View File

@@ -0,0 +1,7 @@
package collections
type (
Point struct {
X, Y int
}
)

View File

@@ -0,0 +1,55 @@
package queue
type (
Queue struct {
start, end *node
length int
}
node struct {
value interface{}
next *node
}
)
// Create a new queue
func New() *Queue {
return &Queue{nil,nil,0}
}
// Take the next item off the front of the queue
func (this *Queue) Dequeue() interface{} {
if this.length == 0 {
return nil
}
n := this.start
if this.length == 1 {
this.start = nil
this.end = nil
} else {
this.start = this.start.next
}
this.length--
return n.value
}
// Put an item on the end of a queue
func (this *Queue) Enqueue(value interface{}) {
n := &node{value,nil}
if this.length == 0 {
this.start = n
this.end = n
} else {
this.end.next = n
this.end = n
}
this.length++
}
// Return the number of items in the queue
func (this *Queue) Len() int {
return this.length
}
// Return the first item in the queue without removing it
func (this *Queue) Peek() interface{} {
if this.length == 0 {
return nil
}
return this.start.value
}

View File

@@ -0,0 +1,50 @@
package queue
import (
"testing"
)
func Test(t *testing.T) {
q := New()
if q.Len() != 0 {
t.Errorf("Length should be 0")
}
q.Enqueue(1)
if q.Len() != 1 {
t.Errorf("Length should be 1")
}
if q.Peek().(int) != 1 {
t.Errorf("Enqueued value should be 1")
}
v := q.Dequeue()
if v.(int) != 1 {
t.Errorf("Dequeued value should be 1")
}
if q.Peek() != nil || q.Dequeue() != nil {
t.Errorf("Empty queue should have no values")
}
q.Enqueue(1)
q.Enqueue(2)
if q.Len() != 2 {
t.Errorf("Length should be 2")
}
if q.Peek().(int) != 1 {
t.Errorf("First value should be 1")
}
q.Dequeue()
if q.Peek().(int) != 2 {
t.Errorf("Next value should be 2")
}
}

106
vendor/github.com/golang-collections/collections/set/set.go generated vendored Executable file
View File

@@ -0,0 +1,106 @@
package set
type (
Set struct {
hash map[interface{}]nothing
}
nothing struct{}
)
// Create a new set
func New(initial ...interface{}) *Set {
s := &Set{make(map[interface{}]nothing)}
for _, v := range initial {
s.Insert(v)
}
return s
}
// Find the difference between two sets
func (this *Set) Difference(set *Set) *Set {
n := make(map[interface{}]nothing)
for k, _ := range this.hash {
if _, exists := set.hash[k]; !exists {
n[k] = nothing{}
}
}
return &Set{n}
}
// Call f for each item in the set
func (this *Set) Do(f func(interface{})) {
for k, _ := range this.hash {
f(k)
}
}
// Test to see whether or not the element is in the set
func (this *Set) Has(element interface{}) bool {
_, exists := this.hash[element]
return exists
}
// Add an element to the set
func (this *Set) Insert(element interface{}) {
this.hash[element] = nothing{}
}
// Find the intersection of two sets
func (this *Set) Intersection(set *Set) *Set {
n := make(map[interface{}]nothing)
for k, _ := range this.hash {
if _, exists := set.hash[k]; exists {
n[k] = nothing{}
}
}
return &Set{n}
}
// Return the number of items in the set
func (this *Set) Len() int {
return len(this.hash)
}
// Test whether or not this set is a proper subset of "set"
func (this *Set) ProperSubsetOf(set *Set) bool {
return this.SubsetOf(set) && this.Len() < set.Len()
}
// Remove an element from the set
func (this *Set) Remove(element interface{}) {
delete(this.hash, element)
}
// Test whether or not this set is a subset of "set"
func (this *Set) SubsetOf(set *Set) bool {
if this.Len() > set.Len() {
return false
}
for k, _ := range this.hash {
if _, exists := set.hash[k]; !exists {
return false
}
}
return true
}
// Find the union of two sets
func (this *Set) Union(set *Set) *Set {
n := make(map[interface{}]nothing)
for k, _ := range this.hash {
n[k] = nothing{}
}
for k, _ := range set.hash {
n[k] = nothing{}
}
return &Set{n}
}

View File

@@ -0,0 +1,74 @@
package set
import (
"testing"
)
func Test(t *testing.T) {
s := New()
s.Insert(5)
if s.Len() != 1 {
t.Errorf("Length should be 1")
}
if !s.Has(5) {
t.Errorf("Membership test failed")
}
s.Remove(5)
if s.Len() != 0 {
t.Errorf("Length should be 0")
}
if s.Has(5) {
t.Errorf("The set should be empty")
}
// Difference
s1 := New(1,2,3,4,5,6)
s2 := New(4,5,6)
s3 := s1.Difference(s2)
if s3.Len() != 3 {
t.Errorf("Length should be 3")
}
if !(s3.Has(1) && s3.Has(2) && s3.Has(3)) {
t.Errorf("Set should only contain 1, 2, 3")
}
// Intersection
s3 = s1.Intersection(s2)
if s3.Len() != 3 {
t.Errorf("Length should be 3 after intersection")
}
if !(s3.Has(4) && s3.Has(5) && s3.Has(6)) {
t.Errorf("Set should contain 4, 5, 6")
}
// Union
s4 := New(7,8,9)
s3 = s2.Union(s4)
if s3.Len() != 6 {
t.Errorf("Length should be 6 after union")
}
if !(s3.Has(7)) {
t.Errorf("Set should contain 4, 5, 6, 7, 8, 9")
}
// Subset
if !s1.SubsetOf(s1) {
t.Errorf("set should be a subset of itself")
}
// Proper Subset
if s1.ProperSubsetOf(s1) {
t.Errorf("set should not be a subset of itself")
}
}

View File

@@ -0,0 +1,171 @@
package skip
import (
"fmt"
"math/rand"
"time"
)
type (
node struct {
next []*node
key interface{}
value interface{}
}
SkipList struct {
root *node
size int
less func(interface{},interface{})bool
gen *rand.Rand
probability float64
}
)
// Create a new skip list
func New(less func(interface{},interface{})bool) *SkipList {
gen := rand.New(rand.NewSource(time.Now().UnixNano()))
n := &node{make([]*node, 0),nil,nil}
return &SkipList{n, 0, less, gen, 0.75}
}
func (this *SkipList) Do(f func(interface{}, interface{})bool) {
if this.size == 0 {
return
}
cur := this.root.next[0]
for cur != nil {
if !f(cur.key, cur.value) {
break
}
cur = cur.next[0]
}
}
// Get an item from the skip list
func (this *SkipList) Get(key interface{}) interface{} {
if this.size == 0 {
return nil
}
cur := this.root
// Start at the top
for i := len(cur.next)-1; i >= 0; i-- {
for this.less(cur.next[i].key, key) {
cur = cur.next[i]
}
}
cur = cur.next[0]
if this.equals(cur.key, key) {
return cur.value
}
return nil
}
// Insert a new item into the skip list
func (this *SkipList) Insert(key interface{}, value interface{}) {
prev := this.getPrevious(key)
// Already in the list so just update the value
if len(prev) > 0 && prev[0].next[0] != nil && this.equals(prev[0].next[0].key, key) {
prev[0].next[0].value = value
return
}
h := len(this.root.next)
nh := this.pickHeight()
n := &node{make([]*node, nh),key,value}
// Higher than anything seen before, so tack it on top
if nh > h {
this.root.next = append(this.root.next, n)
}
// Update the previous nodes
for i := 0; i < h && i < nh; i++ {
n.next[i] = prev[i].next[i]
prev[i].next[i] = n
}
this.size++
}
// Get the length of the skip list
func (this *SkipList) Len() int {
return this.size
}
// Remove an item from the skip list
func (this *SkipList) Remove(key interface{}) interface{} {
prev := this.getPrevious(key)
if len(prev) == 0 {
return nil
}
cur := prev[0].next[0]
// If we found it
if cur != nil && this.equals(key, cur.key) {
// Change all the linked lists
for i := 0; i < len(prev); i++ {
if prev[i] != nil && prev[i].next[i] != nil {
prev[i].next[i] = cur.next[i]
}
}
// Kill off the upper links if they're nil
for i := len(this.root.next)-1; i>=0; i-- {
if this.root.next[i] == nil {
this.root.next = this.root.next[:i]
} else {
break
}
}
this.size--
return cur.value
}
return nil
}
// String representation of the list
func (this *SkipList) String() string {
str := "{"
if len(this.root.next) > 0 {
cur := this.root.next[0]
for cur != nil {
str += fmt.Sprint(cur.key)
str += ":"
str += fmt.Sprint(cur.value)
str += " "
cur = cur.next[0]
}
}
str += "}"
return str
}
// Get a vertical list of nodes of all the things that occur
// immediately before "key"
func (this *SkipList) getPrevious(key interface{}) []*node {
cur := this.root
h := len(cur.next)
nodes := make([]*node, h)
for i := h-1; i >= 0; i-- {
for cur.next[i] != nil && this.less(cur.next[i].key, key) {
cur = cur.next[i]
}
nodes[i] = cur
}
return nodes
}
// Defines an equals method in terms of "less"
func (this *SkipList) equals(a, b interface{}) bool {
return !this.less(a,b) && !this.less(b,a)
}
// Pick a random height
func (this *SkipList) pickHeight() int {
h := 1
for this.gen.Float64() > this.probability {
h++
}
if h > len(this.root.next) {
return h + 1
}
return h
}

View File

@@ -0,0 +1,38 @@
package skip
import (
//"fmt"
"testing"
)
func Test(t *testing.T) {
sl := New(func(a,b interface{})bool {
return a.(int) < b.(int)
})
sl.Insert(1, 100)
if sl.Len() != 1 {
t.Errorf("expecting len 1")
}
sl.Insert(1, 1000)
if sl.Len() != 1 {
t.Errorf("expecting len 1")
}
if sl.Get(1).(int) != 1000 {
t.Errorf("expecting sl[1] == 1000")
}
sl.Remove(1)
if sl.Len() != 0 {
t.Errorf("expecting len 0")
}
sl.Insert(2, 200)
sl.Insert(1, 100)
vs := make([]int, 0)
sl.Do(func(k, v interface{}) bool {
vs = append(vs, k.(int))
return true
})
if len(vs) != 2 || vs[0] != 1 || vs[1] != 2 {
t.Errorf("expecting sorted iteration of all keys")
}
}

View File

@@ -0,0 +1,487 @@
package splay
import (
"fmt"
)
type (
Any interface{}
LessFunc func(interface{}, interface{}) bool
VisitFunc func(interface{}) bool
node struct {
value Any
parent, left, right *node
}
nodei struct {
step int
node *node
prev *nodei
}
SplayTree struct {
length int
root *node
less LessFunc
}
)
// Create a new splay tree, using the less function to determine the order.
func New(less LessFunc) *SplayTree {
return &SplayTree{0, nil, less}
}
// Get the first value from the collection. Returns nil if empty.
func (this *SplayTree) First() Any {
if this.length == 0 {
return nil
}
n := this.root
for n.left != nil {
n = n.left
}
return n.value
}
// Get the last value from the collection. Returns nil if empty.
func (this *SplayTree) Last() Any {
if this.length == 0 {
return nil
}
n := this.root
for n.right != nil {
n = n.right
}
return n.value
}
// Get an item from the splay tree
func (this *SplayTree) Get(item Any) Any {
if this.length == 0 {
return nil
}
n := this.root
for n != nil {
if this.less(item, n.value) {
n = n.left
continue
}
if this.less(n.value, item) {
n = n.right
continue
}
this.splay(n)
return n.value
}
return nil
}
func (this *SplayTree) Has(value Any) bool {
return this.Get(value) != nil
}
func (this *SplayTree) Init() {
this.length = 0
this.root = nil
}
func (this *SplayTree) Add(value Any) {
if this.length == 0 {
this.root = &node{value, nil, nil, nil}
this.length = 1
return
}
n := this.root
for {
if this.less(value, n.value) {
if n.left == nil {
n.left = &node{value, n, nil, nil}
this.length++
n = n.left
break
}
n = n.left
continue
}
if this.less(n.value, value) {
if n.right == nil {
n.right = &node{value, n, nil, nil}
this.length++
n = n.right
break
}
n = n.right
continue
}
n.value = value
break
}
this.splay(n)
}
func (this *SplayTree) PreOrder(visit VisitFunc) {
if this.length == 1 {
return
}
i := &nodei{0, this.root, nil}
for i != nil {
switch i.step {
// Value
case 0:
i.step++
if !visit(i.node.value) {
break
}
// Left
case 1:
i.step++
if i.node.left != nil {
i = &nodei{0, i.node.left, i}
}
// Right
case 2:
i.step++
if i.node.right != nil {
i = &nodei{0, i.node.right, i}
}
default:
i = i.prev
}
}
}
func (this *SplayTree) InOrder(visit VisitFunc) {
if this.length == 1 {
return
}
i := &nodei{0, this.root, nil}
for i != nil {
switch i.step {
// Left
case 0:
i.step++
if i.node.left != nil {
i = &nodei{0, i.node.left, i}
}
// Value
case 1:
i.step++
if !visit(i.node.value) {
break
}
// Right
case 2:
i.step++
if i.node.right != nil {
i = &nodei{0, i.node.right, i}
}
default:
i = i.prev
}
}
}
func (this *SplayTree) PostOrder(visit VisitFunc) {
if this.length == 1 {
return
}
i := &nodei{0, this.root, nil}
for i != nil {
switch i.step {
// Left
case 0:
i.step++
if i.node.left != nil {
i = &nodei{0, i.node.left, i}
}
// Right
case 1:
i.step++
if i.node.right != nil {
i = &nodei{0, i.node.right, i}
}
// Value
case 2:
i.step++
if !visit(i.node.value) {
break
}
default:
i = i.prev
}
}
}
func (this *SplayTree) Do(visit VisitFunc) {
this.InOrder(visit)
}
func (this *SplayTree) Len() int {
return this.length
}
func (this *SplayTree) Remove(value Any) {
if this.length == 0 {
return
}
n := this.root
for n != nil {
if this.less(value, n.value) {
n = n.left
continue
}
if this.less(n.value, value) {
n = n.right
continue
}
// First splay the parent node
if n.parent != nil {
this.splay(n.parent)
}
// No children
if n.left == nil && n.right == nil {
// guess we're the root node
if n.parent == nil {
this.root = nil
break
}
if n.parent.left == n {
n.parent.left = nil
} else {
n.parent.right = nil
}
} else if n.left == nil {
// root node
if n.parent == nil {
this.root = n.right
break
}
if n.parent.left == n {
n.parent.left = n.right
} else {
n.parent.right = n.right
}
} else if n.right == nil {
// root node
if n.parent == nil {
this.root = n.left
break
}
if n.parent.left == n {
n.parent.left = n.left
} else {
n.parent.right = n.left
}
} else {
// find the successor
s := n.right
for s.left != nil {
s = s.left
}
np := n.parent
nl := n.left
nr := n.right
sp := s.parent
sr := s.right
// Update parent
s.parent = np
if np == nil {
this.root = s
} else {
if np.left == n {
np.left = s
} else {
np.right = s
}
}
// Update left
s.left = nl
s.left.parent = s
// Update right
if nr != s {
s.right = nr
s.right.parent = s
}
// Update successor parent
if sp.left == s {
sp.left = sr
} else {
sp.right = sr
}
}
break
}
if n != nil {
this.length--
}
}
func (this *SplayTree) String() string {
if this.length == 0 {
return "{}"
}
return this.root.String()
}
// Splay a node in the tree (send it to the top)
func (this *SplayTree) splay(n *node) {
// Already root, nothing to do
if n.parent == nil {
this.root = n
return
}
p := n.parent
g := p.parent
// Zig
if p == this.root {
if n == p.left {
p.rotateRight()
} else {
p.rotateLeft()
}
} else {
// Zig-zig
if n == p.left && p == g.left {
g.rotateRight()
p.rotateRight()
} else if n == p.right && p == g.right {
g.rotateLeft()
p.rotateLeft()
// Zig-zag
} else if n == p.right && p == g.left {
p.rotateLeft()
g.rotateRight()
} else if n == p.left && p == g.right {
p.rotateRight()
g.rotateLeft()
}
}
this.splay(n)
}
// Swap two nodes in the tree
func (this *SplayTree) swap(n1, n2 *node) {
p1 := n1.parent
l1 := n1.left
r1 := n1.right
p2 := n2.parent
l2 := n2.left
r2 := n2.right
// Update node links
n1.parent = p2
n1.left = l2
n1.right = r2
n2.parent = p1
n2.left = l1
n2.right = r1
// Update parent links
if p1 != nil {
if p1.left == n1 {
p1.left = n2
} else {
p1.right = n2
}
}
if p2 != nil {
if p2.left == n2 {
p2.left = n1
} else {
p2.right = n1
}
}
if n1 == this.root {
this.root = n2
} else if n2 == this.root {
this.root = n1
}
}
// Node methods
func (this *node) String() string {
str := "{" + fmt.Sprint(this.value) + "|"
if this.left != nil {
str += this.left.String()
}
str += "|"
if this.right != nil {
str += this.right.String()
}
str += "}"
return str
}
func (this *node) rotateLeft() {
parent := this.parent
pivot := this.right
child := pivot.left
if pivot == nil {
return
}
// Update the parent
if parent != nil {
if parent.left == this {
parent.left = pivot
} else {
parent.right = pivot
}
}
// Update the pivot
pivot.parent = parent
pivot.left = this
// Update the child
if child != nil {
child.parent = this
}
// Update this
this.parent = pivot
this.right = child
}
func (this *node) rotateRight() {
parent := this.parent
pivot := this.left
child := pivot.right
if pivot == nil {
return
}
// Update the parent
if parent != nil {
if parent.left == this {
parent.left = pivot
} else {
parent.right = pivot
}
}
// Update the pivot
pivot.parent = parent
pivot.right = this
if child != nil {
child.parent = this
}
// Update this
this.parent = pivot
this.left = child
}

View File

@@ -0,0 +1,27 @@
package splay
import (
//"fmt"
"testing"
)
func Test(t *testing.T) {
tree := New(func(a,b interface{})bool {
return a.(string) < b.(string)
})
tree.Insert("d", 4)
tree.Insert("b", 2)
tree.Insert("a", 1)
tree.Insert("c", 3)
if tree.Len() != 4 {
t.Errorf("expecting len 4")
}
tree.Remove("b")
if tree.Len() != 3 {
t.Errorf("expecting len 3")
}
}

View File

@@ -0,0 +1,44 @@
package stack
type (
Stack struct {
top *node
length int
}
node struct {
value interface{}
prev *node
}
)
// Create a new stack
func New() *Stack {
return &Stack{nil,0}
}
// Return the number of items in the stack
func (this *Stack) Len() int {
return this.length
}
// View the top item on the stack
func (this *Stack) Peek() interface{} {
if this.length == 0 {
return nil
}
return this.top.value
}
// Pop the top item of the stack and return it
func (this *Stack) Pop() interface{} {
if this.length == 0 {
return nil
}
n := this.top
this.top = n.prev
this.length--
return n.value
}
// Push a value onto the top of the stack
func (this *Stack) Push(value interface{}) {
n := &node{value,this.top}
this.top = n
this.length++
}

View File

@@ -0,0 +1,42 @@
package stack
import (
"testing"
)
func Test(t *testing.T) {
s := New()
if s.Len() != 0 {
t.Errorf("Length of an empty stack should be 0")
}
s.Push(1)
if s.Len() != 1 {
t.Errorf("Length should be 0")
}
if s.Peek().(int) != 1 {
t.Errorf("Top item on the stack should be 1")
}
if s.Pop().(int) != 1 {
t.Errorf("Top item should have been 1")
}
if s.Len() != 0 {
t.Errorf("Stack should be empty")
}
s.Push(1)
s.Push(2)
if s.Len() != 2 {
t.Errorf("Length should be 2")
}
if s.Peek().(int) != 2 {
t.Errorf("Top of the stack should be 2")
}
}

View File

@@ -0,0 +1,148 @@
package trie
import (
"fmt"
)
type (
Trie struct {
root *node
size int
}
node struct {
key interface{}
value interface{}
next [256]*node
}
iterator struct {
step int
node *node
prev *iterator
}
)
func toBytes(obj interface{}) []byte {
switch o := obj.(type) {
case []byte:
return o
case string:
return []byte(o)
}
return []byte(fmt.Sprint(obj))
}
func New() *Trie {
return &Trie{nil,0}
}
func (this *Trie) Do(handler func(interface{},interface{})bool) {
if this.size > 0 {
this.root.do(handler)
}
}
func (this *Trie) Get(key interface{}) interface{} {
if this.size == 0 {
return nil
}
bs := toBytes(key)
cur := this.root
for i := 0; i < len(bs); i++ {
if cur.next[bs[i]] != nil {
cur = cur.next[bs[i]]
} else {
return nil
}
}
return cur.value
}
func (this *Trie) Has(key interface{}) bool {
return this.Get(key) != nil
}
func (this *Trie) Init() {
this.root = nil
this.size = 0
}
func (this *Trie) Insert(key interface{}, value interface{}) {
if this.size == 0 {
this.root = newNode()
}
bs := toBytes(key)
cur := this.root
for i := 0; i < len(bs); i++ {
if cur.next[bs[i]] != nil {
cur = cur.next[bs[i]]
} else {
cur.next[bs[i]] = newNode()
cur = cur.next[bs[i]]
}
}
if cur.key == nil {
this.size++
}
cur.key = key
cur.value = value
}
func (this *Trie) Len() int {
return this.size
}
func (this *Trie) Remove(key interface{}) interface{} {
if this.size == 0 {
return nil
}
bs := toBytes(key)
cur := this.root
for i := 0; i < len(bs); i++ {
if cur.next[bs[i]] != nil {
cur = cur.next[bs[i]]
} else {
return nil
}
}
// TODO: cleanup dead nodes
val := cur.value
if cur.value != nil {
this.size--
cur.value = nil
cur.key = nil
}
return val
}
func (this *Trie) String() string {
str := "{"
i := 0
this.Do(func(k, v interface{}) bool {
if i > 0 {
str += ", "
}
str += fmt.Sprint(k, ":", v)
i++
return true
})
str += "}"
return str
}
func newNode() *node {
var next [256]*node
return &node{nil,nil,next}
}
func (this *node) do(handler func(interface{}, interface{}) bool) bool {
for i := 0; i < 256; i++ {
if this.next[i] != nil {
if this.next[i].key != nil {
if !handler(this.next[i].key, this.next[i].value) {
return false
}
}
if !this.next[i].do(handler) {
return false
}
}
}
return true
}

View File

@@ -0,0 +1,31 @@
package trie
import (
//"fmt"
"testing"
)
func Test(t *testing.T) {
x := New()
x.Insert(1, 100)
if x.Len() != 1 {
t.Errorf("expected len 1")
}
if x.Get(1).(int) != 100 {
t.Errorf("expected to get 100 for 1")
}
x.Remove(1)
if x.Len() != 0 {
t.Errorf("expected len 0")
}
x.Insert(2, 200)
x.Insert(1, 100)
vs := make([]int, 0)
x.Do(func(k, v interface{}) bool {
vs = append(vs, k.(int))
return true
})
if len(vs) != 2 || vs[0] != 1 || vs[1] != 2 {
t.Errorf("expected in order traversal")
}
}

View File

@@ -0,0 +1,306 @@
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
}

View File

@@ -0,0 +1,83 @@
package tst
import (
//"fmt"
"math/rand"
"testing"
)
func randomString() string {
n := 3 + rand.Intn(10)
bs := make([]byte, n)
for i := 0; i<n; i++ {
bs[i] = byte(97 + rand.Intn(25))
}
return string(bs)
}
func Test(t *testing.T) {
tree := New()
tree.Insert("test", 1)
if tree.Len() != 1 {
t.Errorf("expecting len 1")
}
if !tree.Has("test") {
t.Errorf("expecting to find key=test")
}
tree.Insert("testing", 2)
tree.Insert("abcd", 0)
found := false
tree.Do(func(key string, val interface{})bool {
if key == "test" && val.(int) == 1 {
found = true
}
return true
})
if !found {
t.Errorf("expecting iterator to find test")
}
tree.Remove("testing")
tree.Remove("abcd")
v := tree.Remove("test")
if tree.Len() != 0 {
t.Errorf("expecting len 0")
}
if tree.Has("test") {
t.Errorf("expecting not to find key=test")
}
if v.(int) != 1 {
t.Errorf("expecting value=1")
}
}
func BenchmarkInsert(b *testing.B) {
b.StopTimer()
strs := make([]string, b.N)
for i := 0; i<b.N; i++ {
strs[i] = randomString()
}
b.StartTimer()
tree := New()
for i, str := range strs {
tree.Insert(str, i)
}
}
func BenchmarkMapInsert(b *testing.B) {
b.StopTimer()
strs := make([]string, b.N)
for i := 0; i<b.N; i++ {
strs[i] = randomString()
}
b.StartTimer()
m := make(map[string]int)
for i, str := range strs {
m[str] = i
}
}