├── .gitignore ├── .travis.yml ├── LICENSE.txt ├── README.md ├── go.mod ├── htree.go ├── htree_example.go ├── htree_mem.go └── htree_test.go /.gitignore: -------------------------------------------------------------------------------- 1 | .*.sw[opn] 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | 3 | go: 4 | - 1.5.2 5 | - 1.6 6 | 7 | install: 8 | - go get github.com/golang/lint/golint 9 | - go get github.com/GeertJohan/fgt 10 | 11 | script: fgt golint && go test 12 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | 2 | Copyright (c) 2023, hit9 3 | 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without modification, 7 | are permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, 10 | this list of conditions and the following disclaimer. 11 | * Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | * Neither the name of htree nor the names of its contributors 15 | may be used to endorse or promote products derived from this software 16 | without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 22 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 23 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 25 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 26 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 27 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | HTree 2 | ===== 3 | 4 | Package htree implements the in-memory hash tree. 5 | 6 | https://pkg.go.dev/github.com/hit9/htree 7 | 8 | Example 9 | ------- 10 | 11 | ```go 12 | package main 13 | 14 | import ( 15 | "fmt" 16 | "github.com/hit9/htree" 17 | ) 18 | 19 | // Item implements htree.Item. 20 | type Item struct { 21 | key uint32 22 | value string 23 | } 24 | 25 | // Key returns the item key. 26 | func (item Item) Key() uint32 { 27 | return item.key 28 | } 29 | 30 | func main() { 31 | t := htree.New() 32 | // Add an item. 33 | item := t.Put(Item{123, "data1"}) 34 | // Get an item. 35 | item = t.Get(Item{key: 123}) 36 | fmt.Println(item) 37 | } 38 | ``` 39 | 40 | License 41 | ------- 42 | 43 | BSD. 44 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/hit9/htree 2 | 3 | go 1.15 4 | -------------------------------------------------------------------------------- /htree.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Chao Wang . 2 | 3 | /* 4 | 5 | Package htree implements the in-memory hash tree. 6 | 7 | Abstract 8 | 9 | Hash-Tree is a key-value multi-tree with fast indexing performance and 10 | high space utilization. 11 | 12 | Take 10 consecutive prime numbers: 13 | 14 | 2, 3, 5, 7, 11, 13, 17, 19, 23, 29 15 | 16 | And they can distinguish all uint32 numbers: 17 | 18 | 2*3*5*7*11*13*17*19*23*29 > ^uint32(0) 19 | 20 | Key insertion steps: 21 | 22 | 1. Suppose depth is d, its prime p = Primes[d] 23 | 2. Get the remainder of key divided by p, r = key % p 24 | 3. If r is already taken by another node, go to the next depth. 25 | 4. Otherwise create a new child node and bind r to it. 26 | 27 | Example htree: 28 | 29 | ROOT 30 | | %2 31 | +-- 0: A(12) 12%2=0: A 32 | | | %3 33 | | +-- 0: C(6) 6%2=0 && 6%3=0: C 34 | | |-- 1: D(4) 4%2=0 && 4%3=1: D 35 | | +-- 2: E(8) 8%2=0 && 8%3=2: E 36 | +-- 1: B(3) 3%2=1: B 37 | | %3 38 | +-- 0: F(9) 9%2=1 && 9%3=0: F 39 | |-- 1: G(7) 7%2=1 && 7%3=1: G 40 | +-- 2: H(11) 11%2=1 && 11%3=2: H 41 | 42 | Complexity 43 | 44 | Child nodes are stored in an array orderly, and checked by binary-search but 45 | not indexed by remainders, array indexing will result redundancy entries, this 46 | is for less memory usage, with a bit performance loss. A node is created only 47 | when a new key is inserted. So the worst time complexity is O(Sum(lg2~lg29)), 48 | is constant level, and the entries utilization is 100%. 49 | 50 | Compare To Map 51 | 52 | Although hashtable is very fast with O(1) time complexity, but there is always 53 | about ~25% table entries are unused, because the hash-table load factor is usually 54 | .75. And this htree is suitable for memory-bounded cases. 55 | 56 | HTree is better for local locks if you want a safe container. 57 | 58 | Map may need to rehash and resize on insertions. 59 | 60 | Goroutine Safety 61 | 62 | No. Lock granularity depends on the use case. 63 | 64 | */ 65 | package htree // import "github.com/hit9/htree" 66 | 67 | // Item is a single object in the tree. 68 | type Item interface { 69 | // Key returns an uint32 number to distinguish node with another. 70 | Key() uint32 71 | } 72 | 73 | // Uint32 implements the Item interface. 74 | type Uint32 uint32 75 | 76 | // Key returns the htree node key. 77 | func (i Uint32) Key() uint32 { 78 | return uint32(i) 79 | } 80 | 81 | type children []*node 82 | 83 | // node is an internel node in the htree. 84 | type node struct { 85 | item Item 86 | depth int8 // int8 number on [0,10] 87 | remainder int8 // item.Key()%primes[father.depth] 88 | children children // ordered by remainder 89 | } 90 | 91 | // HTree is the hash-tree. 92 | type HTree struct { 93 | root *node // empty root node 94 | length int // number of nodes 95 | conflicts int // number of conflicts 96 | } 97 | 98 | // Iterator is an iterator on the htree. 99 | type Iterator struct { 100 | t *HTree 101 | fathers []*node // stack of father node 102 | indexes []int // stack of father's index in the brothers 103 | n *node // current node 104 | i int // current index in n's brothers 105 | } 106 | 107 | // Prime numbers to build the tree. 108 | var primes = [10]int{2, 3, 5, 7, 11, 13, 17, 19, 23, 29} 109 | 110 | // modulo returns the remainder after division of key by the prime. 111 | func modulo(key uint32, depth int8) int8 { 112 | return int8(key % uint32(primes[depth])) 113 | } 114 | 115 | // newNode creates a new node. 116 | func newNode(item Item, depth int8, remainder int8) *node { 117 | // item,depth,remainder won't be rewritten once init. 118 | return &node{ 119 | item: item, 120 | depth: depth, 121 | remainder: remainder, 122 | } 123 | } 124 | 125 | // insert a node into the children slice at index i. 126 | func (s *children) insert(i int, n *node) { 127 | *s = append(*s, nil) 128 | if i < len(*s) { 129 | copy((*s)[i+1:], (*s)[i:]) 130 | } 131 | (*s)[i] = n 132 | } 133 | 134 | // delete a node from the children slice at index i. 135 | func (s *children) delete(i int) { 136 | (*s) = append((*s)[:i], (*s)[i+1:]...) 137 | } 138 | 139 | // search child by remainder via binary-search, returns the result 140 | // and left/right positions. 141 | func (s *children) search(r int8) (ok bool, left, right int) { 142 | right = len(*s) - 1 143 | for left < right { 144 | mid := (left + right) >> 1 145 | child := (*s)[mid] 146 | if r > child.remainder { 147 | left = mid + 1 148 | } else { 149 | right = mid 150 | } 151 | } 152 | if left == right { 153 | child := (*s)[left] 154 | if r == child.remainder { 155 | ok = true 156 | return 157 | } 158 | } 159 | return 160 | } 161 | 162 | // New creates a new htree. 163 | func New() *HTree { 164 | return &HTree{root: &node{}} 165 | } 166 | 167 | // Len returns the number of nodes in the tree. 168 | func (t *HTree) Len() int { return t.length } 169 | 170 | // Conflicts returns the number of conflicts in the tree. 171 | func (t *HTree) Conflicts() int { return t.conflicts } 172 | 173 | // get item recursively, nil on not found. 174 | func (t *HTree) get(n *node, item Item) Item { 175 | r := modulo(item.Key(), n.depth) 176 | ok, left, _ := n.children.search(r) 177 | if ok { 178 | // Get the child with the same remainder. 179 | child := n.children[left] 180 | if child.item.Key() == item.Key() { 181 | // Found. 182 | return child.item 183 | } 184 | // Next depth. 185 | return t.get(child, item) 186 | } 187 | // Not found. 188 | return nil 189 | } 190 | 191 | // put finds item recursively, if the node with given item is 192 | // found, returns it. Otherwise new a node with the item.If the 193 | // depth overflows, nil is returned. 194 | func (t *HTree) put(n *node, item Item) Item { 195 | r := modulo(item.Key(), n.depth) 196 | ok, left, right := n.children.search(r) 197 | if ok { 198 | // Get the child with the same remainder. 199 | child := n.children[left] 200 | if child.item.Key() == item.Key() { 201 | t.conflicts++ 202 | return child.item // reuse 203 | } 204 | // Next depth. 205 | return t.put(child, item) 206 | } 207 | if n.depth >= int8(len(primes)-1) { 208 | return nil // depth overflows 209 | } 210 | // Create a new node. 211 | child := newNode(item, n.depth+1, r) 212 | if len(n.children) == 0 || (right == len(n.children)-1 && 213 | r >= n.children[right].remainder) { 214 | n.children = append(n.children, child) 215 | } else { 216 | n.children.insert(right, child) 217 | } 218 | t.length++ 219 | return child.item 220 | } 221 | 222 | // delete finds node by item recursively, if found, deletes it and 223 | // returns the item, else nil. 224 | func (t *HTree) delete(n *node, item Item) Item { 225 | r := modulo(item.Key(), n.depth) 226 | ok, left, _ := n.children.search(r) 227 | if ok { 228 | // Get the child with the same remaider. 229 | child := n.children[left] 230 | if child.item.Key() == item.Key() { 231 | if len(child.children) == 0 { 232 | // Delete child directly. 233 | n.children.delete(left) 234 | } else { 235 | // Find the leaf on this branch. 236 | father := child 237 | leaf := father.children[0] 238 | for { 239 | if len(leaf.children) == 0 { 240 | break 241 | } 242 | father = leaf 243 | leaf = father.children[0] 244 | } 245 | // Replace child with new node. 246 | father.children.delete(0) 247 | n.children[left] = newNode(leaf.item, child.depth, child.remainder) 248 | n.children[left].children = child.children 249 | } 250 | t.length-- 251 | return child.item 252 | } 253 | return t.delete(child, item) 254 | } 255 | return nil 256 | } 257 | 258 | // Get item from htree, nil if not found. 259 | func (t *HTree) Get(item Item) Item { 260 | return t.get(t.root, item) 261 | } 262 | 263 | // Put item into htree and returns the item. If the item already in the 264 | /// tree, return it, else new a node with the given item and return this 265 | // item. If the depth overflows, nil is returned. 266 | func (t *HTree) Put(item Item) Item { 267 | return t.put(t.root, item) 268 | } 269 | 270 | // Delete item from htree and returns the item, nil on not found. 271 | func (t *HTree) Delete(item Item) Item { 272 | return t.delete(t.root, item) 273 | } 274 | 275 | // NewIterator returns a new iterator on this htree. 276 | func (t *HTree) NewIterator() *Iterator { 277 | return &Iterator{n: t.root, i: 0, t: t} 278 | } 279 | 280 | // Next seeks the iterator to next. 281 | // Iteration order sample: 282 | // 283 | // root 284 | // / \ 285 | // 0 1 %2 286 | // / \ / \ 287 | // 4 2 3 5 %3 288 | // 289 | // Order: 0 -> 4 -> 2 -> 1 -> 3 -> 5 290 | func (iter *Iterator) Next() bool { 291 | if len(iter.n.children) > 0 { 292 | // Push stack 293 | iter.fathers = append(iter.fathers, iter.n) 294 | iter.indexes = append(iter.indexes, iter.i) 295 | iter.n = iter.n.children[0] 296 | iter.i = 0 297 | return true 298 | } 299 | for len(iter.fathers) > 0 { 300 | l := len(iter.fathers) 301 | father := iter.fathers[l-1] 302 | if iter.i < len(father.children)-1 { 303 | iter.i++ 304 | iter.n = father.children[iter.i] 305 | return true 306 | } 307 | // Pop stack 308 | iter.fathers, father = iter.fathers[:l-1], iter.fathers[l-1] 309 | iter.indexes, iter.i = iter.indexes[:l-1], iter.indexes[l-1] 310 | } 311 | return false 312 | } 313 | 314 | // Item returns the current item. 315 | func (iter *Iterator) Item() Item { 316 | return iter.n.item 317 | } 318 | -------------------------------------------------------------------------------- /htree_example.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Chao Wang . 2 | 3 | // +build ignore 4 | 5 | package main 6 | 7 | import ( 8 | "fmt" 9 | "github.com/hit9/htree" 10 | ) 11 | 12 | // Item implements htree.Item. 13 | type Item struct { 14 | key uint32 15 | value string 16 | } 17 | 18 | // Key returns the item key. 19 | func (item Item) Key() uint32 { 20 | return item.key 21 | } 22 | 23 | func main() { 24 | t := htree.New() 25 | // Add an item. 26 | item := t.Put(Item{123, "data1"}) 27 | // Get an item. 28 | item = t.Get(Item{key: 123}) 29 | fmt.Println(item) 30 | } 31 | -------------------------------------------------------------------------------- /htree_mem.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Chao Wang . 2 | 3 | // +build ignore 4 | 5 | package main 6 | 7 | import ( 8 | "flag" 9 | "fmt" 10 | "github.com/hit9/htree" 11 | "math/rand" 12 | "runtime" 13 | ) 14 | 15 | var ( 16 | size = flag.Int("size", 1000000, "size of the tree to build") 17 | ) 18 | 19 | func main() { 20 | flag.Parse() 21 | var stats runtime.MemStats 22 | runtime.GC() 23 | runtime.ReadMemStats(&stats) 24 | before := stats.Alloc 25 | t := htree.New() 26 | for i := 0; i < *size; i++ { 27 | t.Put(htree.Uint32(rand.Uint32())) 28 | } 29 | runtime.GC() 30 | runtime.ReadMemStats(&stats) 31 | after := stats.Alloc 32 | total := float64(after - before) 33 | fmt.Printf("%5d entry %9.1f B %5.1f B/entry", *size, total, total/float64(*size)) 34 | if t.Len() > 0 { // Make sure t won't be gc 35 | fmt.Printf("\n") 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /htree_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Chao Wang . 2 | 3 | package htree 4 | 5 | import ( 6 | "math/rand" 7 | "runtime" 8 | "testing" 9 | ) 10 | 11 | // Must asserts the given value is True for testing. 12 | func Must(t *testing.T, v bool) { 13 | if !v { 14 | _, fileName, line, _ := runtime.Caller(1) 15 | t.Errorf("\n unexcepted: %s:%d", fileName, line) 16 | } 17 | } 18 | 19 | func TestPrimesLargerThanUint32(t *testing.T) { 20 | s := uint64(1) 21 | for i := 0; i < len(primes); i++ { 22 | s *= uint64(primes[i]) 23 | } 24 | Must(t, s > uint64(^uint32(0))) 25 | } 26 | 27 | func TestTreeInside(t *testing.T) { 28 | /* 29 | root 30 | / \ 31 | 0 1 %2 32 | /|\ /|\ 33 | 6 4 2 3 7 5 %3 34 | | | 35 | 8 9 %5 36 | */ 37 | tree := New() 38 | for i := 0; i < 10; i++ { 39 | tree.Put(Uint32(i)) 40 | } 41 | n1_0 := tree.root.children[0] 42 | n1_1 := tree.root.children[1] 43 | n2_0_0 := n1_0.children[0] 44 | n2_0_1 := n1_0.children[1] 45 | n2_0_2 := n1_0.children[2] 46 | n2_1_0 := n1_1.children[0] 47 | n2_1_1 := n1_1.children[1] 48 | n2_1_2 := n1_1.children[2] 49 | Must(t, n1_0.item == Uint32(0)) 50 | Must(t, n1_1.item == Uint32(1)) 51 | Must(t, n2_0_0.item == Uint32(6)) 52 | Must(t, n2_0_1.item == Uint32(4)) 53 | Must(t, n2_0_2.item == Uint32(2)) 54 | Must(t, n2_1_0.item == Uint32(3)) 55 | Must(t, n2_1_1.item == Uint32(7)) 56 | Must(t, n2_1_2.item == Uint32(5)) 57 | Must(t, len(n2_0_2.children) == 1) 58 | Must(t, n2_0_2.children[0].item == Uint32(8)) 59 | Must(t, len(n2_1_0.children) == 1) 60 | Must(t, n2_1_0.children[0].item == Uint32(9)) 61 | Must(t, n1_0.remainder == 0) 62 | Must(t, n1_1.remainder == 1) 63 | Must(t, n2_0_0.remainder == 0) 64 | Must(t, n2_0_1.remainder == 1) 65 | Must(t, n2_0_2.remainder == 2) 66 | Must(t, n2_1_0.remainder == 0) 67 | Must(t, n2_1_1.remainder == 1) 68 | Must(t, n2_1_2.remainder == 2) 69 | } 70 | 71 | func TestPutN(t *testing.T) { 72 | tree := New() 73 | n := 1024 74 | for i := 0; i < n; i++ { 75 | item := Uint32(rand.Uint32()) 76 | // Must put 77 | Must(t, tree.Put(item) != nil) 78 | // Must get 79 | Must(t, tree.Get(item) == item) 80 | // Must len++ 81 | Must(t, tree.Len()+tree.Conflicts() == i+1) 82 | } 83 | } 84 | 85 | func TestPutReuse(t *testing.T) { 86 | /* 87 | root 88 | / \ 89 | 0 1 %2 90 | /|\ /|\ 91 | 6 4 2 3 7 5 %3 92 | | | 93 | 8 9 %5 94 | */ 95 | tree := New() 96 | for i := 0; i < 10; i++ { 97 | tree.Put(Uint32(i)) 98 | } 99 | Must(t, tree.Len() == 10) 100 | item := Uint32(9) 101 | Must(t, tree.Put(item) == item) 102 | Must(t, tree.Conflicts() == 1) 103 | Must(t, tree.Len() == 10) 104 | } 105 | 106 | func TestPutNewNode(t *testing.T) { 107 | /* 108 | root 109 | / \ 110 | 0 1 %2 111 | /|\ /|\ 112 | 6 4 2 3 7 5 %3 113 | | | 114 | 8 9 %5 115 | */ 116 | tree := New() 117 | for i := 0; i < 10; i++ { 118 | tree.Put(Uint32(i)) 119 | } 120 | Must(t, tree.Len() == 10) 121 | item := Uint32(10) 122 | Must(t, tree.Put(item) == item) 123 | Must(t, tree.Conflicts() == 0) 124 | Must(t, tree.Len() == 11) 125 | } 126 | 127 | func TestGetN(t *testing.T) { 128 | tree := New() 129 | n := 1024 130 | for i := 0; i < n; i++ { 131 | item := Uint32(rand.Uint32()) 132 | tree.Put(item) 133 | // Must get 134 | Must(t, tree.Get(item) == item) 135 | // Must cant get 136 | Must(t, tree.Get(Uint32(n+i)) == nil) 137 | } 138 | } 139 | 140 | func TestDeleteN(t *testing.T) { 141 | tree := New() 142 | n := 1024 143 | for i := 0; i < n; i++ { 144 | item := Uint32(rand.Uint32()) 145 | tree.Put(item) 146 | // Must delete 147 | Must(t, tree.Delete(item) == item) 148 | // Must cant delete 149 | Must(t, tree.Delete(Uint32(n+i)) == nil) 150 | // Must len-- 151 | Must(t, tree.Len() == 0) 152 | } 153 | } 154 | 155 | func TestDeleteReplace(t *testing.T) { 156 | /* 157 | root 158 | / \ 159 | 0 1 %2 160 | /|\ /|\ 161 | 6 4 2 3 7 5 %3 162 | | | 163 | 42 8 %5 164 | */ 165 | tree := New() 166 | for i := 0; i < 9; i++ { 167 | tree.Put(Uint32(i)) 168 | } 169 | tree.Put(Uint32(42)) 170 | Must(t, tree.Len() == 10) 171 | item := Uint32(0) 172 | // Must delete 173 | Must(t, tree.Delete(item) == item) 174 | // Original child must be replaced by new node:42 175 | Must(t, tree.root.children[0].item == Uint32(42)) 176 | Must(t, tree.root.children[0].remainder == 0) 177 | Must(t, tree.root.children[0].depth == 1) 178 | // The children shouldnt be changed 179 | Must(t, len(tree.root.children[0].children) == 3) 180 | // Node must be a leaf now. 181 | leaf := tree.root.children[0].children[0] 182 | Must(t, len(leaf.children) == 0) 183 | // Must length-- 184 | Must(t, tree.Len() == 9) 185 | } 186 | 187 | func TestDeleteLeaf(t *testing.T) { 188 | /* 189 | root 190 | / \ 191 | 0 1 %2 192 | /|\ /|\ 193 | 6 4 2 3 7 5 %3 194 | */ 195 | tree := New() 196 | for i := 0; i < 8; i++ { 197 | tree.Put(Uint32(i)) 198 | } 199 | Must(t, tree.Len() == 8) 200 | item := Uint32(7) 201 | // Must delete 202 | Must(t, tree.Delete(item) == item) 203 | // Must node(1) has 2 nodes now 204 | Must(t, len(tree.root.children[1].children) == 2) 205 | // Must length-- 206 | Must(t, tree.Len() == 7) 207 | } 208 | 209 | func TestIteratorEmpty(t *testing.T) { 210 | tree := New() 211 | i := 0 212 | iter := tree.NewIterator() 213 | for iter.Next() { 214 | i++ 215 | } 216 | // Must iterates 0 times 217 | Must(t, i == 0) 218 | } 219 | 220 | func TestIteratorOrder(t *testing.T) { 221 | /* 222 | root 223 | / \ 224 | 0 1 %2 225 | / \ / \ 226 | 4 2 3 5 %3 227 | */ 228 | tree := New() 229 | tree.Put(Uint32(0)) 230 | tree.Put(Uint32(1)) 231 | tree.Put(Uint32(2)) 232 | tree.Put(Uint32(3)) 233 | tree.Put(Uint32(4)) 234 | tree.Put(Uint32(5)) 235 | iter := tree.NewIterator() 236 | Must(t, iter.Next() && iter.Item() == Uint32(0)) 237 | Must(t, iter.Next() && iter.Item() == Uint32(4)) 238 | Must(t, iter.Next() && iter.Item() == Uint32(2)) 239 | Must(t, iter.Next() && iter.Item() == Uint32(1)) 240 | Must(t, iter.Next() && iter.Item() == Uint32(3)) 241 | Must(t, iter.Next() && iter.Item() == Uint32(5)) 242 | } 243 | 244 | func TestIteratorLarge(t *testing.T) { 245 | tree := New() 246 | n := 1024 * 10 247 | for i := 0; i < n; i++ { 248 | item := Uint32(rand.Uint32()) 249 | tree.Put(item) 250 | } 251 | j := 0 252 | iter := tree.NewIterator() 253 | for iter.Next() { 254 | j++ 255 | } 256 | Must(t, j == tree.Len()) 257 | } 258 | 259 | func BenchmarkPut(b *testing.B) { 260 | t := New() 261 | for i := 0; i < b.N; i++ { 262 | t.Put(Uint32(i)) 263 | } 264 | } 265 | 266 | func BenchmarkGet(b *testing.B) { 267 | t := New() 268 | for i := 0; i < b.N; i++ { 269 | t.Put(Uint32(i)) 270 | } 271 | b.ResetTimer() 272 | for i := 0; i < b.N; i++ { 273 | t.Get(Uint32(i)) 274 | } 275 | } 276 | 277 | func BenchmarkIteratorNext(b *testing.B) { 278 | t := New() 279 | for i := 0; i < b.N; i++ { 280 | t.Put(Uint32(i)) 281 | } 282 | iter := t.NewIterator() 283 | b.ResetTimer() 284 | for i := 0; i < b.N; i++ { 285 | iter.Next() 286 | } 287 | } 288 | 289 | func BenchmarkGetLargeTree(b *testing.B) { 290 | t := New() 291 | n := 1000 * 1000 // Million 292 | for i := 0; i < n; i++ { 293 | t.Put(Uint32(rand.Uint32())) 294 | } 295 | b.ResetTimer() 296 | for i := 0; i < b.N; i++ { 297 | t.Get(Uint32(i)) 298 | } 299 | } 300 | 301 | func BenchmarkPutLargeTree(b *testing.B) { 302 | t := New() 303 | n := 1000 * 1000 // Million 304 | for i := 0; i < n; i++ { 305 | t.Put(Uint32(rand.Uint32())) 306 | } 307 | b.ResetTimer() 308 | for i := 0; i < b.N; i++ { 309 | t.Put(Uint32(i)) 310 | } 311 | } 312 | 313 | func BenchmarkDeleteLargeTree(b *testing.B) { 314 | t := New() 315 | n := 1000 * 1000 // Million 316 | for i := 0; i < n; i++ { 317 | t.Put(Uint32(rand.Uint32())) 318 | } 319 | b.ResetTimer() 320 | for i := 0; i < b.N; i++ { 321 | t.Delete(Uint32(i)) 322 | } 323 | } 324 | --------------------------------------------------------------------------------