mirror of
https://github.com/DNSCrypt/dnscrypt-proxy.git
synced 2025-04-04 21:57:44 +03:00
Update deps
This commit is contained in:
parent
10986aba62
commit
a4366b0593
15 changed files with 1592 additions and 15 deletions
16
Gopkg.lock
generated
16
Gopkg.lock
generated
|
@ -92,7 +92,7 @@
|
||||||
branch = "master"
|
branch = "master"
|
||||||
name = "github.com/jedisct1/dlog"
|
name = "github.com/jedisct1/dlog"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
revision = "52c32ac39e436cd9295a4629a91f0613ce67052f"
|
revision = "d3f1bf94f2a248f6d000c48612836796f333f2dd"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
|
@ -112,6 +112,12 @@
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
revision = "88b1956e8d9a013c98dda528d3a5b77f168b057f"
|
revision = "88b1956e8d9a013c98dda528d3a5b77f168b057f"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
name = "github.com/k-sone/critbitgo"
|
||||||
|
packages = ["."]
|
||||||
|
revision = "1b44ffc7fc9ad8dea28251e340eadb04093c8af3"
|
||||||
|
version = "v1.1.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
name = "github.com/kardianos/osext"
|
name = "github.com/kardianos/osext"
|
||||||
|
@ -142,7 +148,7 @@
|
||||||
"poly1305",
|
"poly1305",
|
||||||
"salsa20/salsa"
|
"salsa20/salsa"
|
||||||
]
|
]
|
||||||
revision = "12892e8c234f4fe6f6803f052061de9057903bb2"
|
revision = "b2aa35443fbc700ab74c586ae79b81c171851023"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
|
@ -154,7 +160,7 @@
|
||||||
"ipv4",
|
"ipv4",
|
||||||
"ipv6"
|
"ipv6"
|
||||||
]
|
]
|
||||||
revision = "b68f30494add4df6bd8ef5e82803f308e7f7c59c"
|
revision = "61147c48b25b599e5b561d2e9c4f3e1ef489ca41"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
|
@ -166,7 +172,7 @@
|
||||||
"windows/svc/eventlog",
|
"windows/svc/eventlog",
|
||||||
"windows/svc/mgr"
|
"windows/svc/mgr"
|
||||||
]
|
]
|
||||||
revision = "378d26f46672a356c46195c28f61bdb4c0a781dd"
|
revision = "3b87a42e500a6dc65dae1a55d0b641295971163e"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
name = "gopkg.in/natefinch/lumberjack.v2"
|
name = "gopkg.in/natefinch/lumberjack.v2"
|
||||||
|
@ -177,6 +183,6 @@
|
||||||
[solve-meta]
|
[solve-meta]
|
||||||
analyzer-name = "dep"
|
analyzer-name = "dep"
|
||||||
analyzer-version = 1
|
analyzer-version = 1
|
||||||
inputs-digest = "b42eaffe36e3d325de06319d842b067e1c2b9f197089422d6a2df2a5947e3c4c"
|
inputs-digest = "a4dd651828c61eaf4a60761a081ef914190ece4cfa682cb3391712be98bdb34b"
|
||||||
solver-name = "gps-cdcl"
|
solver-name = "gps-cdcl"
|
||||||
solver-version = 1
|
solver-version = 1
|
||||||
|
|
18
Gopkg.toml
18
Gopkg.toml
|
@ -38,6 +38,10 @@
|
||||||
branch = "master"
|
branch = "master"
|
||||||
name = "github.com/jedisct1/dlog"
|
name = "github.com/jedisct1/dlog"
|
||||||
|
|
||||||
|
[[constraint]]
|
||||||
|
branch = "master"
|
||||||
|
name = "github.com/jedisct1/go-clocksmith"
|
||||||
|
|
||||||
[[constraint]]
|
[[constraint]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
name = "github.com/jedisct1/go-minisign"
|
name = "github.com/jedisct1/go-minisign"
|
||||||
|
@ -46,17 +50,17 @@
|
||||||
branch = "master"
|
branch = "master"
|
||||||
name = "github.com/jedisct1/xsecretbox"
|
name = "github.com/jedisct1/xsecretbox"
|
||||||
|
|
||||||
|
[[constraint]]
|
||||||
|
name = "github.com/k-sone/critbitgo"
|
||||||
|
version = "1.1.0"
|
||||||
|
|
||||||
[[constraint]]
|
[[constraint]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
name = "github.com/kardianos/service"
|
name = "github.com/kardianos/service"
|
||||||
|
|
||||||
[[constraint]]
|
[[constraint]]
|
||||||
name = "github.com/miekg/dns"
|
name = "github.com/miekg/dns"
|
||||||
version = "1.0.4"
|
version = "1.0.5"
|
||||||
|
|
||||||
[[constraint]]
|
|
||||||
branch = "master"
|
|
||||||
name = "github.com/pquerna/cachecontrol"
|
|
||||||
|
|
||||||
[[constraint]]
|
[[constraint]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
|
@ -65,7 +69,3 @@
|
||||||
[[constraint]]
|
[[constraint]]
|
||||||
name = "gopkg.in/natefinch/lumberjack.v2"
|
name = "gopkg.in/natefinch/lumberjack.v2"
|
||||||
version = "2.1.0"
|
version = "2.1.0"
|
||||||
|
|
||||||
[[constraint]]
|
|
||||||
branch = "master"
|
|
||||||
name = "github.com/jedisct1/go-clocksmith"
|
|
||||||
|
|
2
vendor/github.com/jedisct1/dlog/Gopkg.lock
generated
vendored
2
vendor/github.com/jedisct1/dlog/Gopkg.lock
generated
vendored
|
@ -15,7 +15,7 @@
|
||||||
"windows/registry",
|
"windows/registry",
|
||||||
"windows/svc/eventlog"
|
"windows/svc/eventlog"
|
||||||
]
|
]
|
||||||
revision = "37707fdb30a5b38865cfb95e5aab41707daec7fd"
|
revision = "378d26f46672a356c46195c28f61bdb4c0a781dd"
|
||||||
|
|
||||||
[solve-meta]
|
[solve-meta]
|
||||||
analyzer-name = "dep"
|
analyzer-name = "dep"
|
||||||
|
|
6
vendor/github.com/k-sone/critbitgo/.travis.yml
generated
vendored
Normal file
6
vendor/github.com/k-sone/critbitgo/.travis.yml
generated
vendored
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
language: go
|
||||||
|
|
||||||
|
go:
|
||||||
|
- 1.5
|
||||||
|
- 1.6
|
||||||
|
- 1.7
|
7
vendor/github.com/k-sone/critbitgo/CHANGES.md
generated
vendored
Normal file
7
vendor/github.com/k-sone/critbitgo/CHANGES.md
generated
vendored
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
## 1.1.0 (2016/12/29)
|
||||||
|
|
||||||
|
- Add `LongestPrefix ` and `Walk` functions
|
||||||
|
|
||||||
|
## 1.0.0 (2016/04/02)
|
||||||
|
|
||||||
|
- Initial release
|
22
vendor/github.com/k-sone/critbitgo/LICENSE
generated
vendored
Normal file
22
vendor/github.com/k-sone/critbitgo/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2015 Keita Sone
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
44
vendor/github.com/k-sone/critbitgo/README.md
generated
vendored
Normal file
44
vendor/github.com/k-sone/critbitgo/README.md
generated
vendored
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
[](https://travis-ci.org/k-sone/critbitgo)
|
||||||
|
|
||||||
|
critbitgo
|
||||||
|
=========
|
||||||
|
|
||||||
|
[Crit-bit trees](http://cr.yp.to/critbit.html) in golang and its applications.
|
||||||
|
|
||||||
|
This implementation extended to handle the key that contains a null character from [C implementation](https://github.com/agl/critbit).
|
||||||
|
|
||||||
|
Usage
|
||||||
|
--------
|
||||||
|
|
||||||
|
```go
|
||||||
|
// Create Trie
|
||||||
|
trie := critbitgo.NewTrie()
|
||||||
|
|
||||||
|
// Insert
|
||||||
|
trie.Insert([]byte("aa"), "value1")
|
||||||
|
trie.Insert([]byte("bb"), "value2")
|
||||||
|
trie.Insert([]byte("ab"), "value3")
|
||||||
|
|
||||||
|
// Get
|
||||||
|
v, ok := trie.Get([]byte("aa"))
|
||||||
|
fmt.Println(v, ok) // -> value1 true
|
||||||
|
|
||||||
|
// Iterate containing keys
|
||||||
|
trie.Allprefixed([]byte{}, func(key []byte, value interface{}) bool {
|
||||||
|
fmt.Println(key, value) // -> [97 97] value1
|
||||||
|
// [97 98] value3
|
||||||
|
// [98 98] value2
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
|
||||||
|
// Delete
|
||||||
|
v, ok = trie.Delete([]byte("aa"))
|
||||||
|
fmt.Println(v, ok) // -> value1 true
|
||||||
|
v, ok = trie.Delete([]byte("aa"))
|
||||||
|
fmt.Println(v, ok) // -> <nil> false
|
||||||
|
```
|
||||||
|
|
||||||
|
License
|
||||||
|
-------
|
||||||
|
|
||||||
|
MIT
|
388
vendor/github.com/k-sone/critbitgo/critbit.go
generated
vendored
Normal file
388
vendor/github.com/k-sone/critbitgo/critbit.go
generated
vendored
Normal file
|
@ -0,0 +1,388 @@
|
||||||
|
package critbitgo
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/hex"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
// The matrix of most significant bit
|
||||||
|
var msbMatrix [256]byte
|
||||||
|
|
||||||
|
func buildMsbMatrix() {
|
||||||
|
for i := 0; i < len(msbMatrix); i++ {
|
||||||
|
b := byte(i)
|
||||||
|
b |= b >> 1
|
||||||
|
b |= b >> 2
|
||||||
|
b |= b >> 4
|
||||||
|
msbMatrix[i] = b &^ (b >> 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type node struct {
|
||||||
|
internal *internal
|
||||||
|
external *external
|
||||||
|
}
|
||||||
|
|
||||||
|
type internal struct {
|
||||||
|
child [2]node
|
||||||
|
offset int
|
||||||
|
bit byte
|
||||||
|
cont bool // if true, key of child[1] contains key of child[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
type external struct {
|
||||||
|
key []byte
|
||||||
|
value interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// finding the critical bit.
|
||||||
|
func (n *external) criticalBit(key []byte) (offset int, bit byte, cont bool) {
|
||||||
|
nlen := len(n.key)
|
||||||
|
klen := len(key)
|
||||||
|
mlen := nlen
|
||||||
|
if nlen > klen {
|
||||||
|
mlen = klen
|
||||||
|
}
|
||||||
|
|
||||||
|
// find first differing byte and bit
|
||||||
|
for offset = 0; offset < mlen; offset++ {
|
||||||
|
if a, b := key[offset], n.key[offset]; a != b {
|
||||||
|
bit = msbMatrix[a^b]
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if nlen < klen {
|
||||||
|
bit = msbMatrix[key[offset]]
|
||||||
|
} else if nlen > klen {
|
||||||
|
bit = msbMatrix[n.key[offset]]
|
||||||
|
} else {
|
||||||
|
// two keys are equal
|
||||||
|
offset = -1
|
||||||
|
}
|
||||||
|
return offset, bit, true
|
||||||
|
}
|
||||||
|
|
||||||
|
// calculate direction.
|
||||||
|
func (n *internal) direction(key []byte) int {
|
||||||
|
if n.offset < len(key) && (key[n.offset]&n.bit != 0 || n.cont) {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Crit-bit Tree
|
||||||
|
type Trie struct {
|
||||||
|
root node
|
||||||
|
size int
|
||||||
|
}
|
||||||
|
|
||||||
|
// searching the tree.
|
||||||
|
func (t *Trie) search(key []byte) *node {
|
||||||
|
n := &t.root
|
||||||
|
for n.internal != nil {
|
||||||
|
n = &n.internal.child[n.internal.direction(key)]
|
||||||
|
}
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
|
||||||
|
// membership testing.
|
||||||
|
func (t *Trie) Contains(key []byte) bool {
|
||||||
|
if n := t.search(key); n.external != nil && bytes.Equal(n.external.key, key) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// get member.
|
||||||
|
// if `key` is in Trie, `ok` is true.
|
||||||
|
func (t *Trie) Get(key []byte) (value interface{}, ok bool) {
|
||||||
|
if n := t.search(key); n.external != nil && bytes.Equal(n.external.key, key) {
|
||||||
|
return n.external.value, true
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// insert into the tree (replaceable).
|
||||||
|
func (t *Trie) insert(key []byte, value interface{}, replace bool) bool {
|
||||||
|
// an empty tree
|
||||||
|
if t.size == 0 {
|
||||||
|
t.root.external = &external{
|
||||||
|
key: key,
|
||||||
|
value: value,
|
||||||
|
}
|
||||||
|
t.size = 1
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
n := t.search(key)
|
||||||
|
newOffset, newBit, newCont := n.external.criticalBit(key)
|
||||||
|
|
||||||
|
// already exists in the tree
|
||||||
|
if newOffset == -1 {
|
||||||
|
if replace {
|
||||||
|
n.external.value = value
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// allocate new node
|
||||||
|
newNode := &internal{
|
||||||
|
offset: newOffset,
|
||||||
|
bit: newBit,
|
||||||
|
cont: newCont,
|
||||||
|
}
|
||||||
|
direction := newNode.direction(key)
|
||||||
|
newNode.child[direction].external = &external{
|
||||||
|
key: key,
|
||||||
|
value: value,
|
||||||
|
}
|
||||||
|
|
||||||
|
// insert new node
|
||||||
|
wherep := &t.root
|
||||||
|
for in := wherep.internal; in != nil; in = wherep.internal {
|
||||||
|
if in.offset > newOffset || (in.offset == newOffset && in.bit < newBit) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
wherep = &in.child[in.direction(key)]
|
||||||
|
}
|
||||||
|
|
||||||
|
if wherep.internal != nil {
|
||||||
|
newNode.child[1-direction].internal = wherep.internal
|
||||||
|
} else {
|
||||||
|
newNode.child[1-direction].external = wherep.external
|
||||||
|
wherep.external = nil
|
||||||
|
}
|
||||||
|
wherep.internal = newNode
|
||||||
|
t.size += 1
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// insert into the tree.
|
||||||
|
// if `key` is alredy in Trie, return false.
|
||||||
|
func (t *Trie) Insert(key []byte, value interface{}) bool {
|
||||||
|
return t.insert(key, value, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
// set into the tree.
|
||||||
|
func (t *Trie) Set(key []byte, value interface{}) {
|
||||||
|
t.insert(key, value, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
// deleting elements.
|
||||||
|
// if `key` is in Trie, `ok` is true.
|
||||||
|
func (t *Trie) Delete(key []byte) (value interface{}, ok bool) {
|
||||||
|
// an empty tree
|
||||||
|
if t.size == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var direction int
|
||||||
|
var whereq *node // pointer to the grandparent
|
||||||
|
var wherep *node = &t.root
|
||||||
|
|
||||||
|
// finding the best candidate to delete
|
||||||
|
for in := wherep.internal; in != nil; in = wherep.internal {
|
||||||
|
direction = in.direction(key)
|
||||||
|
whereq = wherep
|
||||||
|
wherep = &in.child[direction]
|
||||||
|
}
|
||||||
|
|
||||||
|
// checking that we have the right element
|
||||||
|
if !bytes.Equal(wherep.external.key, key) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
value = wherep.external.value
|
||||||
|
ok = true
|
||||||
|
|
||||||
|
// removing the node
|
||||||
|
if whereq == nil {
|
||||||
|
wherep.external = nil
|
||||||
|
} else {
|
||||||
|
othern := whereq.internal.child[1-direction]
|
||||||
|
whereq.internal = othern.internal
|
||||||
|
whereq.external = othern.external
|
||||||
|
}
|
||||||
|
t.size -= 1
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// clearing a tree.
|
||||||
|
func (t *Trie) Clear() {
|
||||||
|
t.root.internal = nil
|
||||||
|
t.root.external = nil
|
||||||
|
t.size = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// return the number of key in a tree.
|
||||||
|
func (t *Trie) Size() int {
|
||||||
|
return t.size
|
||||||
|
}
|
||||||
|
|
||||||
|
// fetching elements with a given prefix.
|
||||||
|
// handle is called with arguments key and value (if handle returns `false`, the iteration is aborted)
|
||||||
|
func (t *Trie) Allprefixed(prefix []byte, handle func(key []byte, value interface{}) bool) bool {
|
||||||
|
// an empty tree
|
||||||
|
if t.size == 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// walk tree, maintaining top pointer
|
||||||
|
p := &t.root
|
||||||
|
top := p
|
||||||
|
if len(prefix) > 0 {
|
||||||
|
for p.internal != nil {
|
||||||
|
top = p
|
||||||
|
p = &p.internal.child[p.internal.direction(prefix)]
|
||||||
|
}
|
||||||
|
|
||||||
|
// check prefix
|
||||||
|
if !bytes.Contains(p.external.key, prefix) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return allprefixed(top, handle)
|
||||||
|
}
|
||||||
|
|
||||||
|
func allprefixed(n *node, handle func([]byte, interface{}) bool) bool {
|
||||||
|
if n.internal != nil {
|
||||||
|
// dealing with an internal node while recursing
|
||||||
|
for i := 0; i < 2; i++ {
|
||||||
|
if !allprefixed(&n.internal.child[i], handle) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// dealing with an external node while recursing
|
||||||
|
return handle(n.external.key, n.external.value)
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Search for the longest matching key from the beginning of the given key.
|
||||||
|
// if `key` is in Trie, `ok` is true.
|
||||||
|
func (t *Trie) LongestPrefix(given []byte) (key []byte, value interface{}, ok bool) {
|
||||||
|
// an empty tree
|
||||||
|
if t.size == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return longestPrefix(&t.root, given)
|
||||||
|
}
|
||||||
|
|
||||||
|
func longestPrefix(n *node, key []byte) ([]byte, interface{}, bool) {
|
||||||
|
if n.internal != nil {
|
||||||
|
direction := n.internal.direction(key)
|
||||||
|
if k, v, ok := longestPrefix(&n.internal.child[direction], key); ok {
|
||||||
|
return k, v, ok
|
||||||
|
}
|
||||||
|
if direction == 1 {
|
||||||
|
return longestPrefix(&n.internal.child[0], key)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if bytes.HasPrefix(key, n.external.key) {
|
||||||
|
return n.external.key, n.external.value, true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Iterating elements from a given start key.
|
||||||
|
// handle is called with arguments key and value (if handle returns `false`, the iteration is aborted)
|
||||||
|
func (t *Trie) Walk(start []byte, handle func(key []byte, value interface{}) bool) bool {
|
||||||
|
var seek bool
|
||||||
|
if start != nil {
|
||||||
|
seek = true
|
||||||
|
}
|
||||||
|
return walk(&t.root, start, &seek, handle)
|
||||||
|
}
|
||||||
|
|
||||||
|
func walk(n *node, key []byte, seek *bool, handle func([]byte, interface{}) bool) bool {
|
||||||
|
if n.internal != nil {
|
||||||
|
var direction int
|
||||||
|
if *seek {
|
||||||
|
direction = n.internal.direction(key)
|
||||||
|
}
|
||||||
|
if !walk(&n.internal.child[direction], key, seek, handle) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if !(*seek) && direction == 0 {
|
||||||
|
// iteration another side
|
||||||
|
return walk(&n.internal.child[1], key, seek, handle)
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
if *seek {
|
||||||
|
if bytes.Equal(n.external.key, key) {
|
||||||
|
// seek completed
|
||||||
|
*seek = false
|
||||||
|
} else {
|
||||||
|
// key is not in Trie
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return handle(n.external.key, n.external.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// dump tree. (for debugging)
|
||||||
|
func (t *Trie) Dump(w io.Writer) {
|
||||||
|
if t.root.internal == nil && t.root.external == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if w == nil {
|
||||||
|
w = os.Stdout
|
||||||
|
}
|
||||||
|
dump(w, &t.root, true, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
func dump(w io.Writer, n *node, right bool, prefix string) {
|
||||||
|
var ownprefix string
|
||||||
|
if right {
|
||||||
|
ownprefix = prefix
|
||||||
|
} else {
|
||||||
|
ownprefix = prefix[:len(prefix)-1] + "`"
|
||||||
|
}
|
||||||
|
|
||||||
|
if in := n.internal; in != nil {
|
||||||
|
fmt.Fprintf(w, "%s-- off=%d, bit=%08b(%02x), cont=%v\n", ownprefix, in.offset, in.bit, in.bit, in.cont)
|
||||||
|
for i := 0; i < 2; i++ {
|
||||||
|
var nextprefix string
|
||||||
|
switch i {
|
||||||
|
case 0:
|
||||||
|
nextprefix = prefix + " |"
|
||||||
|
right = true
|
||||||
|
case 1:
|
||||||
|
nextprefix = prefix + " "
|
||||||
|
right = false
|
||||||
|
}
|
||||||
|
dump(w, &in.child[i], right, nextprefix)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fmt.Fprintf(w, "%s-- key=%d (%s)\n", ownprefix, n.external.key, key2str(n.external.key))
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func key2str(key []byte) string {
|
||||||
|
for _, c := range key {
|
||||||
|
if !strconv.IsPrint(rune(c)) {
|
||||||
|
return hex.EncodeToString(key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return string(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
// create a tree.
|
||||||
|
func NewTrie() *Trie {
|
||||||
|
return &Trie{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
buildMsbMatrix()
|
||||||
|
}
|
348
vendor/github.com/k-sone/critbitgo/critbit_test.go
generated
vendored
Normal file
348
vendor/github.com/k-sone/critbitgo/critbit_test.go
generated
vendored
Normal file
|
@ -0,0 +1,348 @@
|
||||||
|
package critbitgo_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"math/rand"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/k-sone/critbitgo"
|
||||||
|
)
|
||||||
|
|
||||||
|
func buildTrie(t *testing.T, keys []string) *critbitgo.Trie {
|
||||||
|
trie := critbitgo.NewTrie()
|
||||||
|
for _, key := range keys {
|
||||||
|
if !trie.Insert([]byte(key), key) {
|
||||||
|
t.Errorf("Insert() - failed insert \"%s\"\n%s", key, dumpTrie(trie))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return trie
|
||||||
|
}
|
||||||
|
|
||||||
|
func dumpTrie(trie *critbitgo.Trie) string {
|
||||||
|
buf := bytes.NewBufferString("")
|
||||||
|
trie.Dump(buf)
|
||||||
|
return buf.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestInsert(t *testing.T) {
|
||||||
|
// normal build
|
||||||
|
keys := []string{"", "a", "aa", "b", "bb", "ab", "ba", "aba", "bab"}
|
||||||
|
trie := buildTrie(t, keys)
|
||||||
|
dump := dumpTrie(trie)
|
||||||
|
|
||||||
|
// random build
|
||||||
|
random := rand.New(rand.NewSource(0))
|
||||||
|
for i := 0; i < 10; i++ {
|
||||||
|
// shuffle keys
|
||||||
|
lkeys := make([]string, len(keys))
|
||||||
|
for j, index := range random.Perm(len(keys)) {
|
||||||
|
lkeys[j] = keys[index]
|
||||||
|
}
|
||||||
|
|
||||||
|
ltrie := buildTrie(t, lkeys)
|
||||||
|
ldump := dumpTrie(ltrie)
|
||||||
|
if dump != ldump {
|
||||||
|
t.Errorf("Insert() - different tries\norigin:\n%s\nother:\n%s\n", dump, ldump)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// error check
|
||||||
|
if trie.Insert([]byte("a"), nil) {
|
||||||
|
t.Error("Insert() - check exists")
|
||||||
|
}
|
||||||
|
if !trie.Insert([]byte("c"), nil) {
|
||||||
|
t.Error("Insert() - check not exists")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSet(t *testing.T) {
|
||||||
|
keys := []string{"", "a", "aa", "b", "bb", "ab", "ba", "aba", "bab"}
|
||||||
|
trie := buildTrie(t, keys)
|
||||||
|
|
||||||
|
trie.Set([]byte("a"), 100)
|
||||||
|
v, _ := trie.Get([]byte("a"))
|
||||||
|
if n, ok := v.(int); !ok || n != 100 {
|
||||||
|
t.Errorf("Set() - failed replace - %v", v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestContains(t *testing.T) {
|
||||||
|
keys := []string{"", "a", "aa", "b", "bb", "ab", "ba", "aba", "bab"}
|
||||||
|
trie := buildTrie(t, keys)
|
||||||
|
|
||||||
|
for _, key := range keys {
|
||||||
|
if !trie.Contains([]byte(key)) {
|
||||||
|
t.Error("Contains() - not found - %s", key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if trie.Contains([]byte("aaa")) {
|
||||||
|
t.Error("Contains() - phantom found")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGet(t *testing.T) {
|
||||||
|
keys := []string{"", "a", "aa", "b", "bb", "ab", "ba", "aba", "bab"}
|
||||||
|
trie := buildTrie(t, keys)
|
||||||
|
|
||||||
|
for _, key := range keys {
|
||||||
|
if value, ok := trie.Get([]byte(key)); value != key || !ok {
|
||||||
|
t.Error("Get() - not found - %s", key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if value, ok := trie.Get([]byte("aaa")); value != nil || ok {
|
||||||
|
t.Error("Get() - phantom found")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDelete(t *testing.T) {
|
||||||
|
keys := []string{"", "a", "aa", "b", "bb", "ab", "ba", "aba", "bab"}
|
||||||
|
trie := buildTrie(t, keys)
|
||||||
|
|
||||||
|
for i, key := range keys {
|
||||||
|
if !trie.Contains([]byte(key)) {
|
||||||
|
t.Error("Delete() - not exists - %s", key)
|
||||||
|
}
|
||||||
|
if v, ok := trie.Delete([]byte(key)); !ok || v != key {
|
||||||
|
t.Error("Delete() - failed - %s", key)
|
||||||
|
}
|
||||||
|
if trie.Contains([]byte(key)) {
|
||||||
|
t.Error("Delete() - exists - %s", key)
|
||||||
|
}
|
||||||
|
if i != len(keys) {
|
||||||
|
for _, key2 := range keys[i+1:] {
|
||||||
|
if !trie.Contains([]byte(key2)) {
|
||||||
|
t.Errorf("Delete() - other not exists - %s", key2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSize(t *testing.T) {
|
||||||
|
keys := []string{"", "a", "aa", "b", "bb", "ab", "ba", "aba", "bab"}
|
||||||
|
trie := buildTrie(t, keys)
|
||||||
|
klen := len(keys)
|
||||||
|
if s := trie.Size(); s != klen {
|
||||||
|
t.Errorf("Size() - expected [%s], actual [%s]", klen, s)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, key := range keys {
|
||||||
|
trie.Delete([]byte(key))
|
||||||
|
if s := trie.Size(); s != klen-(i+1) {
|
||||||
|
t.Errorf("Size() - expected [%s], actual [%s]", klen, s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAllprefixed(t *testing.T) {
|
||||||
|
keys := []string{"", "a", "aa", "b", "bb", "ab", "ba", "aba", "bab"}
|
||||||
|
trie := buildTrie(t, keys)
|
||||||
|
|
||||||
|
elems := make([]string, 0, len(keys))
|
||||||
|
handle := func(key []byte, value interface{}) bool {
|
||||||
|
if k := string(key); k == value {
|
||||||
|
elems = append(elems, k)
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if !trie.Allprefixed([]byte{}, handle) {
|
||||||
|
t.Error("Allprefixed() - invalid result")
|
||||||
|
}
|
||||||
|
if len(elems) != 9 {
|
||||||
|
t.Errorf("Allprefixed() - invalid elems length [%v]", elems)
|
||||||
|
}
|
||||||
|
for i, key := range []string{"", "a", "aa", "ab", "aba", "b", "ba", "bab", "bb"} {
|
||||||
|
if key != elems[i] {
|
||||||
|
t.Errorf("Allprefixed() - not found [%s]", key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
elems = make([]string, 0, len(keys))
|
||||||
|
if !trie.Allprefixed([]byte("a"), handle) {
|
||||||
|
t.Error("Allprefixed() - invalid result")
|
||||||
|
}
|
||||||
|
if len(elems) != 4 {
|
||||||
|
t.Errorf("Allprefixed() - invalid elems length [%v]", elems)
|
||||||
|
}
|
||||||
|
for i, key := range []string{"a", "aa", "ab", "aba"} {
|
||||||
|
if key != elems[i] {
|
||||||
|
t.Errorf("Allprefixed() - not found [%s]", key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
elems = make([]string, 0, len(keys))
|
||||||
|
handle = func(key []byte, value interface{}) bool {
|
||||||
|
if k := string(key); k == value {
|
||||||
|
elems = append(elems, k)
|
||||||
|
}
|
||||||
|
if string(key) == "aa" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if trie.Allprefixed([]byte("a"), handle) {
|
||||||
|
t.Error("Allprefixed() - invalid result")
|
||||||
|
}
|
||||||
|
if len(elems) != 2 {
|
||||||
|
t.Errorf("Allprefixed() - invalid elems length [%v]", elems)
|
||||||
|
}
|
||||||
|
for i, key := range []string{"a", "aa"} {
|
||||||
|
if key != elems[i] {
|
||||||
|
t.Errorf("Allprefixed() - not found [%s]", key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLongestPrefix(t *testing.T) {
|
||||||
|
keys := []string{"a", "aa", "b", "bb", "ab", "ba", "aba", "bab"}
|
||||||
|
trie := buildTrie(t, keys)
|
||||||
|
|
||||||
|
expects := map[string]string{
|
||||||
|
"a": "a",
|
||||||
|
"a^": "a",
|
||||||
|
"aaa": "aa",
|
||||||
|
"abc": "ab",
|
||||||
|
"bac": "ba",
|
||||||
|
"bbb": "bb",
|
||||||
|
"bc": "b",
|
||||||
|
}
|
||||||
|
for g, k := range expects {
|
||||||
|
if key, value, ok := trie.LongestPrefix([]byte(g)); !ok || string(key) != k || value != k {
|
||||||
|
t.Errorf("LongestPrefix() - invalid result - %s not %s", key, g)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, _, ok := trie.LongestPrefix([]byte{}); ok {
|
||||||
|
t.Error("LongestPrefix() - invalid result - not empty")
|
||||||
|
}
|
||||||
|
if _, _, ok := trie.LongestPrefix([]byte("^")); ok {
|
||||||
|
t.Error("LongestPrefix() - invalid result - not empty")
|
||||||
|
}
|
||||||
|
if _, _, ok := trie.LongestPrefix([]byte("c")); ok {
|
||||||
|
t.Error("LongestPrefix() - invalid result - not empty")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWalk(t *testing.T) {
|
||||||
|
keys := []string{"", "a", "aa", "b", "bb", "ab", "ba", "aba", "bab"}
|
||||||
|
trie := buildTrie(t, keys)
|
||||||
|
|
||||||
|
elems := make([]string, 0, len(keys))
|
||||||
|
handle := func(key []byte, value interface{}) bool {
|
||||||
|
if k := string(key); k == value {
|
||||||
|
elems = append(elems, k)
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if !trie.Walk([]byte{}, handle) {
|
||||||
|
t.Error("Walk() - invalid result")
|
||||||
|
}
|
||||||
|
if len(elems) != 9 {
|
||||||
|
t.Errorf("Walk() - invalid elems length [%v]", elems)
|
||||||
|
}
|
||||||
|
for i, key := range []string{"", "a", "aa", "ab", "aba", "b", "ba", "bab", "bb"} {
|
||||||
|
if key != elems[i] {
|
||||||
|
t.Errorf("Walk() - not found [%s]", key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
elems = make([]string, 0, len(keys))
|
||||||
|
if !trie.Walk([]byte("ab"), handle) {
|
||||||
|
t.Error("Walk() - invalid result")
|
||||||
|
}
|
||||||
|
if len(elems) != 6 {
|
||||||
|
t.Errorf("Walk() - invalid elems length [%v]", elems)
|
||||||
|
}
|
||||||
|
for i, key := range []string{"ab", "aba", "b", "ba", "bab", "bb"} {
|
||||||
|
if key != elems[i] {
|
||||||
|
t.Errorf("Walk() - not found [%s]", key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
elems = make([]string, 0, len(keys))
|
||||||
|
if !trie.Walk(nil, handle) {
|
||||||
|
t.Error("Walk() - invalid result")
|
||||||
|
}
|
||||||
|
if len(elems) != 9 {
|
||||||
|
t.Errorf("Walk() - invalid elems length [%v]", elems)
|
||||||
|
}
|
||||||
|
for i, key := range []string{"", "a", "aa", "ab", "aba", "b", "ba", "bab", "bb"} {
|
||||||
|
if key != elems[i] {
|
||||||
|
t.Errorf("Walk() - not found [%s]", key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
elems = make([]string, 0, len(keys))
|
||||||
|
handle = func(key []byte, value interface{}) bool {
|
||||||
|
if k := string(key); k == value {
|
||||||
|
elems = append(elems, k)
|
||||||
|
}
|
||||||
|
if string(key) == "aa" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if trie.Walk([]byte("a"), handle) {
|
||||||
|
t.Error("Walk() - invalid result")
|
||||||
|
}
|
||||||
|
if len(elems) != 2 {
|
||||||
|
t.Errorf("Walk() - invalid elems length [%v]", elems)
|
||||||
|
}
|
||||||
|
for i, key := range []string{"a", "aa"} {
|
||||||
|
if key != elems[i] {
|
||||||
|
t.Errorf("Walk() - not found [%s]", key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if trie.Walk([]byte("^"), handle) {
|
||||||
|
t.Error("Walk() - invalid result")
|
||||||
|
}
|
||||||
|
if trie.Walk([]byte("aaa"), handle) {
|
||||||
|
t.Error("Walk() - invalid result")
|
||||||
|
}
|
||||||
|
if trie.Walk([]byte("c"), handle) {
|
||||||
|
t.Error("Walk() - invalid result")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestKeyContainsZeroValue(t *testing.T) {
|
||||||
|
trie := critbitgo.NewTrie()
|
||||||
|
trie.Insert([]byte{1, 0, 1}, nil)
|
||||||
|
trie.Insert([]byte{1}, nil)
|
||||||
|
trie.Insert([]byte{0, 1, 1}, nil)
|
||||||
|
trie.Insert([]byte{}, nil)
|
||||||
|
trie.Insert([]byte{0, 0, 1}, nil)
|
||||||
|
trie.Insert([]byte{1, 1}, nil)
|
||||||
|
trie.Insert([]byte{1, 1, 1}, nil)
|
||||||
|
trie.Insert([]byte{0, 1}, nil)
|
||||||
|
trie.Insert([]byte{0, 1, 0}, nil)
|
||||||
|
trie.Insert([]byte{0, 0}, nil)
|
||||||
|
trie.Insert([]byte{0, 0, 0}, nil)
|
||||||
|
trie.Insert([]byte{0}, nil)
|
||||||
|
|
||||||
|
var index int
|
||||||
|
exp := [][]byte{
|
||||||
|
[]byte{},
|
||||||
|
[]byte{0},
|
||||||
|
[]byte{0, 0},
|
||||||
|
[]byte{0, 0, 0},
|
||||||
|
[]byte{0, 0, 1},
|
||||||
|
[]byte{0, 1},
|
||||||
|
[]byte{0, 1, 0},
|
||||||
|
[]byte{0, 1, 1},
|
||||||
|
[]byte{1},
|
||||||
|
[]byte{1, 0, 1},
|
||||||
|
[]byte{1, 1},
|
||||||
|
[]byte{1, 1, 1},
|
||||||
|
}
|
||||||
|
handle := func(key []byte, _ interface{}) bool {
|
||||||
|
if !bytes.Equal(exp[index], key) {
|
||||||
|
t.Errorf("Key Order - index=%d, expected [%x], actula [%x]", index, exp[index], key)
|
||||||
|
}
|
||||||
|
index += 1
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
trie.Allprefixed([]byte(""), handle)
|
||||||
|
}
|
57
vendor/github.com/k-sone/critbitgo/map.go
generated
vendored
Normal file
57
vendor/github.com/k-sone/critbitgo/map.go
generated
vendored
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
package critbitgo
|
||||||
|
|
||||||
|
import (
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
// The map is sorted according to the natural ordering of its keys
|
||||||
|
type SortedMap struct {
|
||||||
|
trie *Trie
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *SortedMap) Contains(key string) bool {
|
||||||
|
return m.trie.Contains(*(*[]byte)(unsafe.Pointer(&key)))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *SortedMap) Get(key string) (value interface{}, ok bool) {
|
||||||
|
return m.trie.Get(*(*[]byte)(unsafe.Pointer(&key)))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *SortedMap) Set(key string, value interface{}) {
|
||||||
|
m.trie.Set([]byte(key), value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *SortedMap) Delete(key string) (value interface{}, ok bool) {
|
||||||
|
return m.trie.Delete(*(*[]byte)(unsafe.Pointer(&key)))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *SortedMap) Clear() {
|
||||||
|
m.trie.Clear()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *SortedMap) Size() int {
|
||||||
|
return m.trie.Size()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns a slice of sorted keys
|
||||||
|
func (m *SortedMap) Keys() []string {
|
||||||
|
keys := make([]string, 0, m.Size())
|
||||||
|
m.trie.Allprefixed([]byte{}, func(k []byte, v interface{}) bool {
|
||||||
|
keys = append(keys, string(k))
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
return keys
|
||||||
|
}
|
||||||
|
|
||||||
|
// Executes a provided function for each element that has a given prefix.
|
||||||
|
// if handle returns `false`, the iteration is aborted.
|
||||||
|
func (m *SortedMap) Each(prefix string, handle func(key string, value interface{}) bool) bool {
|
||||||
|
return m.trie.Allprefixed([]byte(prefix), func(k []byte, v interface{}) bool {
|
||||||
|
return handle(string(k), v)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a SortedMap
|
||||||
|
func NewSortedMap() *SortedMap {
|
||||||
|
return &SortedMap{NewTrie()}
|
||||||
|
}
|
119
vendor/github.com/k-sone/critbitgo/map_bench_test.go
generated
vendored
Normal file
119
vendor/github.com/k-sone/critbitgo/map_bench_test.go
generated
vendored
Normal file
|
@ -0,0 +1,119 @@
|
||||||
|
package critbitgo_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"math/rand"
|
||||||
|
"sort"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
var keyCount int = 10000
|
||||||
|
var keyLen int = 128
|
||||||
|
|
||||||
|
var keys []string
|
||||||
|
var alphabet string = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
|
||||||
|
var alphalen int = len(alphabet)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
keys = make([]string, keyCount)
|
||||||
|
random := rand.New(rand.NewSource(0))
|
||||||
|
for i := 0; i < len(keys); i++ {
|
||||||
|
keys[i] = genRandomKey(random)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func genRandomKey(rand *rand.Rand) string {
|
||||||
|
buf := bytes.NewBufferString("")
|
||||||
|
for i := 0; i < keyLen; i++ {
|
||||||
|
buf.WriteByte(alphabet[rand.Intn(alphalen)])
|
||||||
|
}
|
||||||
|
return buf.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func buildMap(keys []string) map[string]string {
|
||||||
|
m := make(map[string]string)
|
||||||
|
for _, key := range keys {
|
||||||
|
m[key] = key
|
||||||
|
}
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkMapBuild(b *testing.B) {
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
buildMap(keys)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkSortedMapBuild(b *testing.B) {
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
buildSortedMap(keys)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkMapGet(b *testing.B) {
|
||||||
|
m := buildMap(keys)
|
||||||
|
random := rand.New(rand.NewSource(0))
|
||||||
|
b.ResetTimer()
|
||||||
|
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
k := keys[random.Intn(keyCount)]
|
||||||
|
_ = m[k]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkSortedMapGet(b *testing.B) {
|
||||||
|
m := buildSortedMap(keys)
|
||||||
|
random := rand.New(rand.NewSource(0))
|
||||||
|
b.ResetTimer()
|
||||||
|
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
k := keys[random.Intn(keyCount)]
|
||||||
|
_, _ = m.Get(k)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkMapDelete(b *testing.B) {
|
||||||
|
m := buildMap(keys)
|
||||||
|
random := rand.New(rand.NewSource(0))
|
||||||
|
b.ResetTimer()
|
||||||
|
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
k := keys[random.Intn(keyCount)]
|
||||||
|
if _, ok := m[k]; ok {
|
||||||
|
delete(m, k)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkSortedMapDelete(b *testing.B) {
|
||||||
|
m := buildSortedMap(keys)
|
||||||
|
random := rand.New(rand.NewSource(0))
|
||||||
|
b.ResetTimer()
|
||||||
|
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
k := keys[random.Intn(keyCount)]
|
||||||
|
m.Delete(k)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkMapKeys(b *testing.B) {
|
||||||
|
m := buildMap(keys)
|
||||||
|
b.ResetTimer()
|
||||||
|
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
list := make([]string, 0, len(m))
|
||||||
|
for _, k := range m {
|
||||||
|
list = append(list, k)
|
||||||
|
}
|
||||||
|
sort.Strings(list)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkSortedMapKeys(b *testing.B) {
|
||||||
|
m := buildSortedMap(keys)
|
||||||
|
b.ResetTimer()
|
||||||
|
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
m.Keys()
|
||||||
|
}
|
||||||
|
}
|
164
vendor/github.com/k-sone/critbitgo/map_test.go
generated
vendored
Normal file
164
vendor/github.com/k-sone/critbitgo/map_test.go
generated
vendored
Normal file
|
@ -0,0 +1,164 @@
|
||||||
|
package critbitgo_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/k-sone/critbitgo"
|
||||||
|
)
|
||||||
|
|
||||||
|
func buildSortedMap(keys []string) *critbitgo.SortedMap {
|
||||||
|
m := critbitgo.NewSortedMap()
|
||||||
|
for _, key := range keys {
|
||||||
|
m.Set(key, key)
|
||||||
|
}
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSortedMapContains(t *testing.T) {
|
||||||
|
keys := []string{"", "a", "aa", "b", "bb", "ab", "ba", "aba", "bab"}
|
||||||
|
m := buildSortedMap(keys)
|
||||||
|
|
||||||
|
for _, key := range keys {
|
||||||
|
if !m.Contains(key) {
|
||||||
|
t.Error("Contains() - not found - [%s]", key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if m.Contains("aaa") {
|
||||||
|
t.Error("Contains() - phantom found")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSortedMapGet(t *testing.T) {
|
||||||
|
keys := []string{"", "a", "aa", "b", "bb", "ab", "ba", "aba", "bab"}
|
||||||
|
m := buildSortedMap(keys)
|
||||||
|
|
||||||
|
for _, key := range keys {
|
||||||
|
if value, ok := m.Get(key); !ok || value != key {
|
||||||
|
t.Error("Get() - not found - [%s]", key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if value, ok := m.Get("aaa"); ok || value != nil {
|
||||||
|
t.Error("Get() - phantom found")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSortedMapDelete(t *testing.T) {
|
||||||
|
keys := []string{"", "a", "aa", "b", "bb", "ab", "ba", "aba", "bab"}
|
||||||
|
m := buildSortedMap(keys)
|
||||||
|
|
||||||
|
for i, key := range keys {
|
||||||
|
if !m.Contains(key) {
|
||||||
|
t.Error("Delete() - not exists - [%s]", key)
|
||||||
|
}
|
||||||
|
if value, ok := m.Delete(key); !ok || value != key {
|
||||||
|
t.Error("Delete() - failed - [%s]", key)
|
||||||
|
}
|
||||||
|
if m.Contains(key) {
|
||||||
|
t.Error("Delete() - exists - [%s]", key)
|
||||||
|
}
|
||||||
|
if value, ok := m.Delete(key); ok || value != nil {
|
||||||
|
t.Error("Delete() - phantom found - [%s]", key)
|
||||||
|
}
|
||||||
|
if i != len(keys) {
|
||||||
|
for _, key2 := range keys[i+1:] {
|
||||||
|
if !m.Contains(key2) {
|
||||||
|
t.Errorf("Delete() - other not exists - [%s](%s)", key2, key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSortedMapSize(t *testing.T) {
|
||||||
|
keys := []string{"", "a", "aa", "b", "bb", "ab", "ba", "aba", "bab"}
|
||||||
|
m := buildSortedMap(keys)
|
||||||
|
klen := len(keys)
|
||||||
|
if s := m.Size(); s != klen {
|
||||||
|
t.Errorf("Size() - expected [%s], actual [%s]", klen, s)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, key := range keys {
|
||||||
|
m.Delete(key)
|
||||||
|
if s := m.Size(); s != klen-(i+1) {
|
||||||
|
t.Errorf("Size() - expected [%s], actual [%s]", klen, s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSortedMapKeys(t *testing.T) {
|
||||||
|
keys := []string{"", "a", "aa", "b", "bb", "ab", "ba", "aba", "bab"}
|
||||||
|
m := buildSortedMap(keys)
|
||||||
|
skeys := m.Keys()
|
||||||
|
for _, key := range keys {
|
||||||
|
match := false
|
||||||
|
for _, skey := range skeys {
|
||||||
|
if key == skey {
|
||||||
|
match = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !match {
|
||||||
|
t.Errorf("Keys() - not found [%s]", key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSortedMapEach(t *testing.T) {
|
||||||
|
keys := []string{"", "a", "aa", "b", "bb", "ab", "ba", "aba", "bab"}
|
||||||
|
m := buildSortedMap(keys)
|
||||||
|
|
||||||
|
elems := make(map[string]interface{})
|
||||||
|
handle := func(key string, value interface{}) bool {
|
||||||
|
elems[key] = value
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if !m.Each("", handle) {
|
||||||
|
t.Error("Each() - invalid result")
|
||||||
|
}
|
||||||
|
for _, key := range keys {
|
||||||
|
if _, ok := elems[key]; !ok {
|
||||||
|
t.Errorf("Each() - not found [%s]", key)
|
||||||
|
} else if value, ok := elems[key].(string); !ok || value != key {
|
||||||
|
t.Errorf("Each() - invalid value [%s](%s)", value, key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
elems = make(map[string]interface{})
|
||||||
|
handle = func(key string, value interface{}) bool {
|
||||||
|
elems[key] = value
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if !m.Each("b", handle) {
|
||||||
|
t.Error("Each() - invalid result")
|
||||||
|
}
|
||||||
|
for _, key := range keys {
|
||||||
|
if strings.Index(key, "b") == 0 {
|
||||||
|
if _, ok := elems[key]; !ok {
|
||||||
|
t.Errorf("Each() - not found [%s]", key)
|
||||||
|
} else if value, ok := elems[key].(string); !ok || value != key {
|
||||||
|
t.Errorf("Each() - invalid value [%s](%s)", value, key)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if _, ok := elems[key]; ok {
|
||||||
|
t.Errorf("Each() - phantom found [%s]", key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
elems = make(map[string]interface{})
|
||||||
|
handle = func(key string, value interface{}) bool {
|
||||||
|
elems[key] = value
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if !m.Each("c", handle) {
|
||||||
|
t.Error("Each() - invalid result")
|
||||||
|
}
|
||||||
|
for _, key := range keys {
|
||||||
|
if _, ok := elems[key]; ok {
|
||||||
|
t.Errorf("Each() - phantom found [%s]", key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
228
vendor/github.com/k-sone/critbitgo/net.go
generated
vendored
Normal file
228
vendor/github.com/k-sone/critbitgo/net.go
generated
vendored
Normal file
|
@ -0,0 +1,228 @@
|
||||||
|
package critbitgo
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
mask32 = net.IPMask{0xff, 0xff, 0xff, 0xff}
|
||||||
|
mask128 = net.IPMask{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}
|
||||||
|
)
|
||||||
|
|
||||||
|
// IP routing table.
|
||||||
|
type Net struct {
|
||||||
|
trie *Trie
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add a route.
|
||||||
|
// If `r` is not IPv4/IPv6 network, returns an error.
|
||||||
|
func (n *Net) Add(r *net.IPNet, value interface{}) (err error) {
|
||||||
|
var ip net.IP
|
||||||
|
if ip, _, err = netValidateIPNet(r); err == nil {
|
||||||
|
n.trie.Set(netIPNetToKey(ip, r.Mask), value)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add a route.
|
||||||
|
// If `s` is not CIDR notation, returns an error.
|
||||||
|
func (n *Net) AddCIDR(s string, value interface{}) (err error) {
|
||||||
|
var r *net.IPNet
|
||||||
|
if _, r, err = net.ParseCIDR(s); err == nil {
|
||||||
|
n.Add(r, value)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete a specific route.
|
||||||
|
// If `r` is not IP4/IPv6 network or a route is not found, `ok` is false.
|
||||||
|
func (n *Net) Delete(r *net.IPNet) (value interface{}, ok bool, err error) {
|
||||||
|
var ip net.IP
|
||||||
|
if ip, _, err = netValidateIPNet(r); err == nil {
|
||||||
|
value, ok = n.trie.Delete(netIPNetToKey(ip, r.Mask))
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete a specific route.
|
||||||
|
// If `s` is not CIDR notation or a route is not found, `ok` is false.
|
||||||
|
func (n *Net) DeleteCIDR(s string) (value interface{}, ok bool, err error) {
|
||||||
|
var r *net.IPNet
|
||||||
|
if _, r, err = net.ParseCIDR(s); err == nil {
|
||||||
|
value, ok, err = n.Delete(r)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get a specific route.
|
||||||
|
// If `r` is not IPv4/IPv6 network or a route is not found, `ok` is false.
|
||||||
|
func (n *Net) Get(r *net.IPNet) (value interface{}, ok bool, err error) {
|
||||||
|
var ip net.IP
|
||||||
|
if ip, _, err = netValidateIPNet(r); err == nil {
|
||||||
|
value, ok = n.trie.Get(netIPNetToKey(ip, r.Mask))
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get a specific route.
|
||||||
|
// If `s` is not CIDR notation or a route is not found, `ok` is false.
|
||||||
|
func (n *Net) GetCIDR(s string) (value interface{}, ok bool, err error) {
|
||||||
|
var r *net.IPNet
|
||||||
|
if _, r, err = net.ParseCIDR(s); err == nil {
|
||||||
|
value, ok, err = n.Get(r)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return a specific route by using the longest prefix matching.
|
||||||
|
// If `r` is not IPv4/IPv6 network or a route is not found, `route` is nil.
|
||||||
|
func (n *Net) Match(r *net.IPNet) (route *net.IPNet, value interface{}, err error) {
|
||||||
|
var ip net.IP
|
||||||
|
if ip, _, err = netValidateIP(r.IP); err == nil {
|
||||||
|
if k, v := n.match(netIPNetToKey(ip, r.Mask)); k != nil {
|
||||||
|
route = netKeyToIPNet(k)
|
||||||
|
value = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return a specific route by using the longest prefix matching.
|
||||||
|
// If `s` is not CIDR notation, or a route is not found, `route` is nil.
|
||||||
|
func (n *Net) MatchCIDR(s string) (route *net.IPNet, value interface{}, err error) {
|
||||||
|
var r *net.IPNet
|
||||||
|
if _, r, err = net.ParseCIDR(s); err == nil {
|
||||||
|
route, value, err = n.Match(r)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return a specific route by using the longest prefix matching.
|
||||||
|
// If `ip` is invalid IP, or a route is not found, `route` is nil.
|
||||||
|
func (n *Net) MatchIP(ip net.IP) (route *net.IPNet, value interface{}, err error) {
|
||||||
|
var isV4 bool
|
||||||
|
ip, isV4, err = netValidateIP(ip)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var mask net.IPMask
|
||||||
|
if isV4 {
|
||||||
|
mask = mask32
|
||||||
|
} else {
|
||||||
|
mask = mask128
|
||||||
|
}
|
||||||
|
if k, v := n.match(netIPNetToKey(ip, mask)); k != nil {
|
||||||
|
route = netKeyToIPNet(k)
|
||||||
|
value = v
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *Net) match(key []byte) ([]byte, interface{}) {
|
||||||
|
if n.trie.size > 0 {
|
||||||
|
if node := lookup(&n.trie.root, key, false); node != nil {
|
||||||
|
return node.external.key, node.external.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func lookup(p *node, key []byte, backtracking bool) *node {
|
||||||
|
if p.internal != nil {
|
||||||
|
var direction int
|
||||||
|
if p.internal.offset == len(key)-1 {
|
||||||
|
// selecting the larger side when comparing the mask
|
||||||
|
direction = 1
|
||||||
|
} else if backtracking {
|
||||||
|
direction = 0
|
||||||
|
} else {
|
||||||
|
direction = p.internal.direction(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
if c := lookup(&p.internal.child[direction], key, backtracking); c != nil {
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
if direction == 1 {
|
||||||
|
// search other node
|
||||||
|
return lookup(&p.internal.child[0], key, true)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
} else {
|
||||||
|
nlen := len(p.external.key)
|
||||||
|
if nlen != len(key) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// check mask
|
||||||
|
mask := p.external.key[nlen-1]
|
||||||
|
if mask > key[nlen-1] {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// compare both keys with mask
|
||||||
|
div := int(mask >> 3)
|
||||||
|
for i := 0; i < div; i++ {
|
||||||
|
if p.external.key[i] != key[i] {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if mod := uint(mask & 0x07); mod > 0 {
|
||||||
|
bit := 8 - mod
|
||||||
|
if p.external.key[div] != key[div]&(0xff>>bit<<bit) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deletes all routes.
|
||||||
|
func (n *Net) Clear() {
|
||||||
|
n.trie.Clear()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns number of routes.
|
||||||
|
func (n *Net) Size() int {
|
||||||
|
return n.trie.Size()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create IP routing table
|
||||||
|
func NewNet() *Net {
|
||||||
|
return &Net{NewTrie()}
|
||||||
|
}
|
||||||
|
|
||||||
|
func netValidateIP(ip net.IP) (nIP net.IP, isV4 bool, err error) {
|
||||||
|
if v4 := ip.To4(); v4 != nil {
|
||||||
|
nIP = v4
|
||||||
|
isV4 = true
|
||||||
|
} else if ip.To16() != nil {
|
||||||
|
nIP = ip
|
||||||
|
} else {
|
||||||
|
err = &net.AddrError{Err: "Invalid IP address", Addr: ip.String()}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func netValidateIPNet(r *net.IPNet) (nIP net.IP, isV4 bool, err error) {
|
||||||
|
if r == nil {
|
||||||
|
err = &net.AddrError{Err: "IP network is nil"}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return netValidateIP(r.IP)
|
||||||
|
}
|
||||||
|
|
||||||
|
func netIPNetToKey(ip net.IP, mask net.IPMask) []byte {
|
||||||
|
// +--------------+------+
|
||||||
|
// | ip address.. | mask |
|
||||||
|
// +--------------+------+
|
||||||
|
ones, _ := mask.Size()
|
||||||
|
return append(ip, byte(ones))
|
||||||
|
}
|
||||||
|
|
||||||
|
func netKeyToIPNet(k []byte) *net.IPNet {
|
||||||
|
iplen := len(k) - 1
|
||||||
|
return &net.IPNet{
|
||||||
|
IP: net.IP(k[:iplen]),
|
||||||
|
Mask: net.CIDRMask(int(k[iplen]), iplen*8),
|
||||||
|
}
|
||||||
|
}
|
78
vendor/github.com/k-sone/critbitgo/net_bench_test.go
generated
vendored
Normal file
78
vendor/github.com/k-sone/critbitgo/net_bench_test.go
generated
vendored
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
package critbitgo_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math/rand"
|
||||||
|
"net"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/k-sone/critbitgo"
|
||||||
|
)
|
||||||
|
|
||||||
|
var routeCount int = 10000
|
||||||
|
var routes []string
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
routes = make([]string, routeCount)
|
||||||
|
random := rand.New(rand.NewSource(0))
|
||||||
|
for i := 0; i < len(routes); i++ {
|
||||||
|
routes[i] = genRoute(random)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func genRoute(rand *rand.Rand) string {
|
||||||
|
ip := rand.Int31()
|
||||||
|
mask := rand.Intn(33)
|
||||||
|
ipnet := &net.IPNet{
|
||||||
|
IP: net.IP{byte(ip >> 24), byte(ip >> 16), byte(ip >> 8), byte(ip)},
|
||||||
|
Mask: net.CIDRMask(mask, 32),
|
||||||
|
}
|
||||||
|
return ipnet.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func buildNet(keys []string) *critbitgo.Net {
|
||||||
|
tree := critbitgo.NewNet()
|
||||||
|
for i := 0; i < len(keys); i++ {
|
||||||
|
tree.AddCIDR(keys[i], nil)
|
||||||
|
}
|
||||||
|
tree.AddCIDR("0.0.0.0/5", nil)
|
||||||
|
return tree
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkNetBuild(b *testing.B) {
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
buildNet(routes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkNetGet(b *testing.B) {
|
||||||
|
n := buildNet(routes)
|
||||||
|
random := rand.New(rand.NewSource(0))
|
||||||
|
b.ResetTimer()
|
||||||
|
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
k := routes[random.Intn(routeCount)]
|
||||||
|
n.GetCIDR(k)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkNetDelete(b *testing.B) {
|
||||||
|
n := buildNet(routes)
|
||||||
|
random := rand.New(rand.NewSource(0))
|
||||||
|
b.ResetTimer()
|
||||||
|
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
k := routes[random.Intn(keyCount)]
|
||||||
|
n.DeleteCIDR(k)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkNetMatch(b *testing.B) {
|
||||||
|
n := buildNet(routes)
|
||||||
|
random := rand.New(rand.NewSource(0))
|
||||||
|
b.ResetTimer()
|
||||||
|
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
s := genRoute(random)
|
||||||
|
n.MatchCIDR(s)
|
||||||
|
}
|
||||||
|
}
|
110
vendor/github.com/k-sone/critbitgo/net_test.go
generated
vendored
Normal file
110
vendor/github.com/k-sone/critbitgo/net_test.go
generated
vendored
Normal file
|
@ -0,0 +1,110 @@
|
||||||
|
package critbitgo_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/k-sone/critbitgo"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestNet(t *testing.T) {
|
||||||
|
trie := critbitgo.NewNet()
|
||||||
|
cidr := "192.168.1.0/24"
|
||||||
|
host := "192.168.1.1/32"
|
||||||
|
hostIP := net.IPv4(192, 168, 1, 1)
|
||||||
|
|
||||||
|
if _, _, err := trie.GetCIDR(""); err == nil {
|
||||||
|
t.Error("GetCIDR() - not error")
|
||||||
|
}
|
||||||
|
if v, ok, err := trie.GetCIDR(cidr); v != nil || ok || err != nil {
|
||||||
|
t.Errorf("GetCIDR() - phantom: %v, %v, %v", v, ok, err)
|
||||||
|
}
|
||||||
|
if _, _, err := trie.MatchCIDR(""); err == nil {
|
||||||
|
t.Error("MatchCIDR() - not error")
|
||||||
|
}
|
||||||
|
if r, v, err := trie.MatchCIDR(host); r != nil || v != nil || err != nil {
|
||||||
|
t.Errorf("MatchCIDR() - phantom: %v, %v, %v", r, v, err)
|
||||||
|
}
|
||||||
|
if _, _, err := trie.MatchIP(net.IP([]byte{})); err == nil {
|
||||||
|
t.Error("MatchIP() - not error")
|
||||||
|
}
|
||||||
|
if r, v, err := trie.MatchIP(hostIP); r != nil || v != nil || err != nil {
|
||||||
|
t.Errorf("MatchIP() - phantom: %v, %v, %v", r, v, err)
|
||||||
|
}
|
||||||
|
if _, _, err := trie.DeleteCIDR(""); err == nil {
|
||||||
|
t.Error("DeleteCIDR() - not error")
|
||||||
|
}
|
||||||
|
if v, ok, err := trie.DeleteCIDR(cidr); v != nil || ok || err != nil {
|
||||||
|
t.Errorf("DeleteCIDR() - phantom: %v, %v, %v", v, ok, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := trie.AddCIDR(cidr, &cidr); err != nil {
|
||||||
|
t.Errorf("AddCIDR() - %s: error occurred %s", cidr, err)
|
||||||
|
}
|
||||||
|
if v, ok, err := trie.GetCIDR(cidr); v != &cidr || !ok || err != nil {
|
||||||
|
t.Errorf("GetCIDR() - failed: %v, %v, %v", v, ok, err)
|
||||||
|
}
|
||||||
|
if r, v, err := trie.MatchCIDR(host); r == nil || r.String() != cidr || v != &cidr || err != nil {
|
||||||
|
t.Errorf("MatchCIDR() - failed: %v, %v, %v", r, v, err)
|
||||||
|
}
|
||||||
|
if r, v, err := trie.MatchIP(hostIP); r == nil || r.String() != cidr || v != &cidr || err != nil {
|
||||||
|
t.Errorf("MatchIP() - failed: %v, %v, %v", r, v, err)
|
||||||
|
}
|
||||||
|
if v, ok, err := trie.DeleteCIDR(cidr); v != &cidr || !ok || err != nil {
|
||||||
|
t.Errorf("DeleteCIDR() - failed: %v, %v, %v", v, ok, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkMatch(t *testing.T, trie *critbitgo.Net, request, expect string) {
|
||||||
|
route, value, err := trie.MatchCIDR(request)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("MatchCIDR() - %s: error occurred %s", request, err)
|
||||||
|
}
|
||||||
|
if cidr := route.String(); expect != cidr {
|
||||||
|
t.Errorf("MatchCIDR() - %s: expected [%s], actual [%s]", request, expect, cidr)
|
||||||
|
}
|
||||||
|
if value == nil {
|
||||||
|
t.Errorf("MatchCIDR() - %s: no value", request)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNetMatch(t *testing.T) {
|
||||||
|
trie := critbitgo.NewNet()
|
||||||
|
|
||||||
|
cidrs := []string{
|
||||||
|
"0.0.0.0/4",
|
||||||
|
"192.168.0.0/16",
|
||||||
|
"192.168.1.0/24",
|
||||||
|
"192.168.1.0/28",
|
||||||
|
"192.168.1.0/32",
|
||||||
|
"192.168.1.1/32",
|
||||||
|
"192.168.1.2/32",
|
||||||
|
"192.168.1.32/27",
|
||||||
|
"192.168.1.32/30",
|
||||||
|
"192.168.2.1/32",
|
||||||
|
"192.168.2.2/32",
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, cidr := range cidrs {
|
||||||
|
if err := trie.AddCIDR(cidr, &cidr); err != nil {
|
||||||
|
t.Errorf("AddCIDR() - %s: error occurred %s", cidr, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
checkMatch(t, trie, "10.0.0.0/8", "0.0.0.0/4")
|
||||||
|
checkMatch(t, trie, "192.168.1.0/24", "192.168.1.0/24")
|
||||||
|
checkMatch(t, trie, "192.168.1.0/30", "192.168.1.0/28")
|
||||||
|
checkMatch(t, trie, "192.168.1.0/32", "192.168.1.0/32")
|
||||||
|
checkMatch(t, trie, "192.168.1.128/26", "192.168.1.0/24")
|
||||||
|
checkMatch(t, trie, "192.168.2.128/26", "192.168.0.0/16")
|
||||||
|
checkMatch(t, trie, "192.168.1.1/32", "192.168.1.1/32")
|
||||||
|
checkMatch(t, trie, "192.168.1.2/32", "192.168.1.2/32")
|
||||||
|
checkMatch(t, trie, "192.168.1.3/32", "192.168.1.0/28")
|
||||||
|
checkMatch(t, trie, "192.168.1.32/32", "192.168.1.32/30")
|
||||||
|
checkMatch(t, trie, "192.168.1.35/32", "192.168.1.32/30")
|
||||||
|
checkMatch(t, trie, "192.168.1.36/32", "192.168.1.32/27")
|
||||||
|
checkMatch(t, trie, "192.168.1.63/32", "192.168.1.32/27")
|
||||||
|
checkMatch(t, trie, "192.168.1.64/32", "192.168.1.0/24")
|
||||||
|
checkMatch(t, trie, "192.168.2.2/32", "192.168.2.2/32")
|
||||||
|
checkMatch(t, trie, "192.168.2.3/32", "192.168.0.0/16")
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue