Commit a4366b05 authored by Frank Denis's avatar Frank Denis

Update deps

parent 10986aba
......@@ -92,7 +92,7 @@
branch = "master"
name = "github.com/jedisct1/dlog"
packages = ["."]
revision = "52c32ac39e436cd9295a4629a91f0613ce67052f"
revision = "d3f1bf94f2a248f6d000c48612836796f333f2dd"
[[projects]]
branch = "master"
......@@ -112,6 +112,12 @@
packages = ["."]
revision = "88b1956e8d9a013c98dda528d3a5b77f168b057f"
[[projects]]
name = "github.com/k-sone/critbitgo"
packages = ["."]
revision = "1b44ffc7fc9ad8dea28251e340eadb04093c8af3"
version = "v1.1.0"
[[projects]]
branch = "master"
name = "github.com/kardianos/osext"
......@@ -142,7 +148,7 @@
"poly1305",
"salsa20/salsa"
]
revision = "12892e8c234f4fe6f6803f052061de9057903bb2"
revision = "b2aa35443fbc700ab74c586ae79b81c171851023"
[[projects]]
branch = "master"
......@@ -154,7 +160,7 @@
"ipv4",
"ipv6"
]
revision = "b68f30494add4df6bd8ef5e82803f308e7f7c59c"
revision = "61147c48b25b599e5b561d2e9c4f3e1ef489ca41"
[[projects]]
branch = "master"
......@@ -166,7 +172,7 @@
"windows/svc/eventlog",
"windows/svc/mgr"
]
revision = "378d26f46672a356c46195c28f61bdb4c0a781dd"
revision = "3b87a42e500a6dc65dae1a55d0b641295971163e"
[[projects]]
name = "gopkg.in/natefinch/lumberjack.v2"
......@@ -177,6 +183,6 @@
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
inputs-digest = "b42eaffe36e3d325de06319d842b067e1c2b9f197089422d6a2df2a5947e3c4c"
inputs-digest = "a4dd651828c61eaf4a60761a081ef914190ece4cfa682cb3391712be98bdb34b"
solver-name = "gps-cdcl"
solver-version = 1
......@@ -38,6 +38,10 @@
branch = "master"
name = "github.com/jedisct1/dlog"
[[constraint]]
branch = "master"
name = "github.com/jedisct1/go-clocksmith"
[[constraint]]
branch = "master"
name = "github.com/jedisct1/go-minisign"
......@@ -46,17 +50,17 @@
branch = "master"
name = "github.com/jedisct1/xsecretbox"
[[constraint]]
name = "github.com/k-sone/critbitgo"
version = "1.1.0"
[[constraint]]
branch = "master"
name = "github.com/kardianos/service"
[[constraint]]
name = "github.com/miekg/dns"
version = "1.0.4"
[[constraint]]
branch = "master"
name = "github.com/pquerna/cachecontrol"
version = "1.0.5"
[[constraint]]
branch = "master"
......@@ -65,7 +69,3 @@
[[constraint]]
name = "gopkg.in/natefinch/lumberjack.v2"
version = "2.1.0"
[[constraint]]
branch = "master"
name = "github.com/jedisct1/go-clocksmith"
......@@ -15,7 +15,7 @@
"windows/registry",
"windows/svc/eventlog"
]
revision = "37707fdb30a5b38865cfb95e5aab41707daec7fd"
revision = "378d26f46672a356c46195c28f61bdb4c0a781dd"
[solve-meta]
analyzer-name = "dep"
......
language: go
go:
- 1.5
- 1.6
- 1.7
## 1.1.0 (2016/12/29)
- Add `LongestPrefix ` and `Walk` functions
## 1.0.0 (2016/04/02)
- Initial release
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.
[![Build Status](https://travis-ci.org/k-sone/critbitgo.svg?branch=master)](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
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()
}
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"}