mirror of
https://github.com/QuilibriumNetwork/ceremonyclient.git
synced 2026-02-21 18:37:26 +08:00
389 lines
8.8 KiB
Go
389 lines
8.8 KiB
Go
// Modified from https://github.com/tatsushid/go-critbit, MIT Licensed
|
|
// Exports fields for seerialization and uses explicit value type
|
|
//
|
|
// Package critbit implements Crit-Bit tree for byte sequences.
|
|
//
|
|
// Crit-Bit tree [1] is fast, memory efficient and a variant of PATRICIA trie.
|
|
// This implementation can be used for byte sequences if it includes a null
|
|
// byte or not. This is based on [2] and extends it to support a null byte in a
|
|
// byte sequence.
|
|
//
|
|
// [1]: http://cr.yp.to/critbit.html (definition)
|
|
// [2]: https://github.com/agl/critbit (C implementation and document)
|
|
package tries
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/gob"
|
|
)
|
|
|
|
type NodeType int
|
|
|
|
func init() {
|
|
gob.Register(&INode{})
|
|
gob.Register(&ENode{})
|
|
}
|
|
|
|
type Value struct {
|
|
Key []byte
|
|
EarliestFrame uint64
|
|
LatestFrame uint64
|
|
Count uint64
|
|
}
|
|
|
|
const (
|
|
Internal NodeType = iota
|
|
External
|
|
)
|
|
|
|
type Node interface {
|
|
kind() NodeType
|
|
}
|
|
|
|
type INode struct {
|
|
Children [2]Node
|
|
Pos int
|
|
Other uint8
|
|
}
|
|
|
|
func (n *INode) kind() NodeType { return Internal }
|
|
|
|
type ENode struct {
|
|
Key []byte
|
|
Value Value
|
|
}
|
|
|
|
func (n *ENode) kind() NodeType { return External }
|
|
|
|
// Tree represents a critbit tree.
|
|
type Tree struct {
|
|
Root Node
|
|
Size int
|
|
}
|
|
|
|
// New returns an empty tree.
|
|
func New() *Tree {
|
|
return &Tree{}
|
|
}
|
|
|
|
// Len returns a number of elements in the tree.
|
|
func (t *Tree) Len() int {
|
|
return t.Size
|
|
}
|
|
|
|
func (t *Tree) direction(k []byte, pos int, other uint8) int {
|
|
var c uint8
|
|
if pos < len(k) {
|
|
c = k[pos]
|
|
} else if other == 0xff {
|
|
return 0
|
|
}
|
|
return (1 + int(other|c)) >> 8
|
|
}
|
|
|
|
func (t *Tree) lookup(k []byte) (*ENode, *INode) {
|
|
if t.Root == nil {
|
|
return nil, nil
|
|
}
|
|
|
|
var top *INode
|
|
p := t.Root
|
|
for {
|
|
switch n := p.(type) {
|
|
case *ENode:
|
|
return n, top
|
|
case *INode:
|
|
if top == nil || n.Pos < len(k) {
|
|
top = n
|
|
}
|
|
p = n.Children[t.direction(k, n.Pos, n.Other)]
|
|
}
|
|
}
|
|
}
|
|
|
|
// Get searches a given key from the tree. If the key exists in the tree, it
|
|
// returns its value and true. If not, it returns nil and false.
|
|
func (t *Tree) Get(k []byte) (interface{}, bool) {
|
|
n, _ := t.lookup(k)
|
|
if n != nil && bytes.Equal(k, n.Key) {
|
|
return n.Value, true
|
|
}
|
|
return nil, false
|
|
}
|
|
|
|
func (t *Tree) findFirstDiffByte(k []byte, n *ENode) (pos int, other uint8, match bool) {
|
|
var byt, b byte
|
|
for pos = 0; pos < len(k); pos++ {
|
|
b = k[pos]
|
|
byt = 0
|
|
if pos < len(n.Key) {
|
|
byt = n.Key[pos]
|
|
}
|
|
if byt != b {
|
|
return pos, byt ^ b, false
|
|
}
|
|
}
|
|
if pos < len(n.Key) {
|
|
return pos, n.Key[pos], false
|
|
} else if pos == len(n.Key) {
|
|
return 0, 0, true
|
|
}
|
|
return pos - 1, 0, false
|
|
}
|
|
|
|
func (t *Tree) findInsertPos(k []byte, pos int, other uint8) (*Node, Node) {
|
|
p := &t.Root
|
|
for {
|
|
switch n := (*p).(type) {
|
|
case *ENode:
|
|
return p, n
|
|
case *INode:
|
|
if n.Pos > pos {
|
|
return p, n
|
|
}
|
|
if n.Pos == pos && n.Other > other {
|
|
return p, n
|
|
}
|
|
p = &n.Children[t.direction(k, n.Pos, n.Other)]
|
|
}
|
|
}
|
|
}
|
|
|
|
// Insert adds or updates a given key to the tree and returns its previous
|
|
// value and if anything was set or not. If there is the key in the tree, it
|
|
// adds the key and the value to the tree and returns nil and true when it
|
|
// succeeded while if not, it updates the key's value and returns its previous
|
|
// value and true when it succeeded.
|
|
func (t *Tree) Insert(k []byte, v Value) (interface{}, bool) {
|
|
key := append([]byte{}, k...)
|
|
|
|
n, _ := t.lookup(k)
|
|
if n == nil { // only happens when t.root is nil
|
|
t.Root = &ENode{Key: key, Value: v}
|
|
t.Size++
|
|
return nil, true
|
|
}
|
|
|
|
pos, other, match := t.findFirstDiffByte(k, n)
|
|
if match {
|
|
orig := n.Value
|
|
n.Value = v
|
|
return orig, true
|
|
}
|
|
|
|
other |= other >> 1
|
|
other |= other >> 2
|
|
other |= other >> 4
|
|
other = ^(other &^ (other >> 1))
|
|
di := t.direction(n.Key, pos, other)
|
|
|
|
newn := &INode{Pos: pos, Other: other}
|
|
newn.Children[1-di] = &ENode{Key: key, Value: v}
|
|
|
|
p, child := t.findInsertPos(k, pos, other)
|
|
newn.Children[di] = child
|
|
*p = newn
|
|
|
|
t.Size++
|
|
return nil, true
|
|
}
|
|
|
|
func (t *Tree) findDeletePos(k []byte) (*Node, *ENode, int) {
|
|
if t.Root == nil {
|
|
return nil, nil, 0
|
|
}
|
|
|
|
var di int
|
|
var q *Node
|
|
p := &t.Root
|
|
for {
|
|
switch n := (*p).(type) {
|
|
case *ENode:
|
|
return q, n, di
|
|
case *INode:
|
|
di = t.direction(k, n.Pos, n.Other)
|
|
q = p
|
|
p = &n.Children[di]
|
|
}
|
|
}
|
|
}
|
|
|
|
// Delete removes a given key and its value from the tree. If it succeeded, it
|
|
// returns the key's previous value and true while if not, it returns nil and
|
|
// false. On an empty tree, it always fails.
|
|
func (t *Tree) Delete(k []byte) (interface{}, bool) {
|
|
q, n, di := t.findDeletePos(k)
|
|
if n == nil || !bytes.Equal(k, n.Key) {
|
|
return nil, false
|
|
}
|
|
t.Size--
|
|
if q == nil {
|
|
t.Root = nil
|
|
return n.Value, true
|
|
}
|
|
tmp := (*q).(*INode)
|
|
*q = tmp.Children[1-di]
|
|
return n.Value, true
|
|
}
|
|
|
|
// Clear removes all elements in the tree. If it removes something, it returns
|
|
// true while the tree is empty and there is nothing to remove, it returns
|
|
// false.
|
|
func (t *Tree) Clear() bool {
|
|
if t.Root != nil {
|
|
t.Root = nil
|
|
t.Size = 0
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
// Minimum searches a key from the tree in lexicographic order and returns the
|
|
// first one and its value. If it found such a key, it also returns true as the
|
|
// bool value while if not, it returns false as it.
|
|
func (t *Tree) Minimum() ([]byte, interface{}, bool) {
|
|
if t.Root == nil {
|
|
return nil, nil, false
|
|
}
|
|
|
|
p := t.Root
|
|
for {
|
|
switch n := p.(type) {
|
|
case *ENode:
|
|
return n.Key, n.Value, true
|
|
case *INode:
|
|
p = n.Children[0]
|
|
}
|
|
}
|
|
}
|
|
|
|
// Maximum searches a key from the tree in lexicographic order and returns the
|
|
// last one and its value. If it found such a key, it also returns true as the
|
|
// bool value while if not, it returns false as it.
|
|
func (t *Tree) Maximum() ([]byte, interface{}, bool) {
|
|
if t.Root == nil {
|
|
return nil, nil, false
|
|
}
|
|
|
|
p := t.Root
|
|
for {
|
|
switch n := p.(type) {
|
|
case *ENode:
|
|
return n.Key, n.Value, true
|
|
case *INode:
|
|
p = n.Children[1]
|
|
}
|
|
}
|
|
}
|
|
|
|
func (t *Tree) longestPrefix(p Node, prefix []byte) ([]byte, interface{}, bool) {
|
|
if p == nil {
|
|
return nil, nil, false
|
|
}
|
|
var di int
|
|
var c uint8
|
|
switch n := p.(type) {
|
|
case *ENode:
|
|
if bytes.HasPrefix(prefix, n.Key) {
|
|
return n.Key, n.Value, true
|
|
}
|
|
case *INode:
|
|
c = 0
|
|
if n.Pos < len(prefix) {
|
|
c = prefix[n.Pos]
|
|
}
|
|
di = (1 + int(n.Other|c)) >> 8
|
|
|
|
if k, v, ok := t.longestPrefix(n.Children[di], prefix); ok {
|
|
return k, v, ok
|
|
} else if di == 1 {
|
|
return t.longestPrefix(n.Children[0], prefix)
|
|
}
|
|
}
|
|
return nil, nil, false
|
|
}
|
|
|
|
// LongestPrefix searches the longest key which is included in a given key and
|
|
// returns the found key and its value. For example, if there are "f", "fo",
|
|
// "foobar" in the tree and "foo" is given, it returns "fo". If it found such a
|
|
// key, it returns true as the bool value while if not, it returns false as it.
|
|
func (t *Tree) LongestPrefix(prefix []byte) ([]byte, interface{}, bool) {
|
|
return t.longestPrefix(t.Root, prefix)
|
|
}
|
|
|
|
// WalkFn is used at walking a tree. It receives a key and its value of each
|
|
// elements which a walk function gives. If it returns true, a walk function
|
|
// should be terminated at there.
|
|
type WalkFn func(k []byte, v interface{}) bool
|
|
|
|
func (t *Tree) walk(p Node, fn WalkFn) bool {
|
|
if p == nil {
|
|
return false
|
|
}
|
|
switch n := p.(type) {
|
|
case *ENode:
|
|
return fn(n.Key, n.Value)
|
|
case *INode:
|
|
for i := 0; i < 2; i++ {
|
|
if t.walk(n.Children[i], fn) {
|
|
return true
|
|
}
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
// Walk walks whole the tree and call a given function with each element's key
|
|
// and value. If the function returns true, the walk is terminated at there.
|
|
func (t *Tree) Walk(fn WalkFn) {
|
|
t.walk(t.Root, fn)
|
|
}
|
|
|
|
// WalkPrefix walks the tree under a given prefix and call a given function
|
|
// with each element's key and value. For example, the tree has "f", "fo",
|
|
// "foob", "foobar" and "foo" is given, it visits "foob" and "foobar" elements.
|
|
// If the function returns true, the walk is terminated at there.
|
|
func (t *Tree) WalkPrefix(prefix []byte, fn WalkFn) {
|
|
n, top := t.lookup(prefix)
|
|
if n == nil || !bytes.HasPrefix(n.Key, prefix) {
|
|
return
|
|
}
|
|
wrapper := func(k []byte, v interface{}) bool {
|
|
if bytes.HasPrefix(k, prefix) {
|
|
return fn(k, v)
|
|
}
|
|
return false
|
|
}
|
|
t.walk(top, wrapper)
|
|
}
|
|
|
|
func (t *Tree) walkPath(p Node, path []byte, fn WalkFn) bool {
|
|
if p == nil {
|
|
return false
|
|
}
|
|
var di int
|
|
switch n := p.(type) {
|
|
case *ENode:
|
|
if bytes.HasPrefix(path, n.Key) {
|
|
return fn(n.Key, n.Value)
|
|
}
|
|
case *INode:
|
|
di = t.direction(path, n.Pos, n.Other)
|
|
if di == 1 {
|
|
if t.walkPath(n.Children[0], path, fn) {
|
|
return true
|
|
}
|
|
}
|
|
return t.walkPath(n.Children[di], path, fn)
|
|
}
|
|
return false
|
|
}
|
|
|
|
// WalkPath walks the tree from the root up to a given key and call a given
|
|
// function with each element's key and value. For example, the tree has "f",
|
|
// "fo", "foob", "foobar" and "foo" is given, it visits "f" and "fo" elements.
|
|
// If the function returns true, the walk is terminated at there.
|
|
func (t *Tree) WalkPath(path []byte, fn WalkFn) {
|
|
t.walkPath(t.Root, path, fn)
|
|
}
|