2021-10-06 14:28:56 +00:00
|
|
|
/*
|
|
|
|
Copyright 2021 Erigon contributors
|
|
|
|
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
you may not use this file except in compliance with the License.
|
|
|
|
You may obtain a copy of the License at
|
|
|
|
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
See the License for the specific language governing permissions and
|
|
|
|
limitations under the License.
|
|
|
|
*/
|
|
|
|
|
|
|
|
package patricia
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"math/bits"
|
|
|
|
"strings"
|
|
|
|
)
|
|
|
|
|
|
|
|
// Implementation of paticia tree for efficient search of substrings from a dictionary in a given string
|
|
|
|
|
|
|
|
type node struct {
|
|
|
|
p0 uint32 // Number of bits in the left prefix is encoded into the lower 5 bits, the remaining 27 bits are left prefix
|
|
|
|
p1 uint32 // Number of bits in the right prefix is encoding into the lower 5 bits, the remaining 27 bits are right prefix
|
|
|
|
//size uint64
|
2021-10-11 17:31:49 +00:00
|
|
|
n0 *node
|
|
|
|
n1 *node
|
|
|
|
val interface{} // value associated with the key
|
2021-10-06 14:28:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func tostr(x uint32) string {
|
|
|
|
str := fmt.Sprintf("%b", x)
|
|
|
|
for len(str) < 32 {
|
|
|
|
str = "0" + str
|
|
|
|
}
|
|
|
|
return str[:x&0x1f]
|
|
|
|
}
|
|
|
|
|
2021-10-11 17:31:49 +00:00
|
|
|
// print assumes values are byte slices
|
2021-10-06 14:28:56 +00:00
|
|
|
func (n *node) print(sb *strings.Builder, indent string) {
|
|
|
|
sb.WriteString(indent)
|
|
|
|
fmt.Fprintf(sb, "%p ", n)
|
|
|
|
sb.WriteString(tostr(n.p0))
|
|
|
|
sb.WriteString("\n")
|
|
|
|
if n.n0 != nil {
|
|
|
|
n.n0.print(sb, indent+" ")
|
|
|
|
}
|
|
|
|
sb.WriteString(indent)
|
|
|
|
fmt.Fprintf(sb, "%p ", n)
|
|
|
|
sb.WriteString(tostr(n.p1))
|
|
|
|
sb.WriteString("\n")
|
|
|
|
if n.n1 != nil {
|
|
|
|
n.n1.print(sb, indent+" ")
|
|
|
|
}
|
2021-10-11 17:31:49 +00:00
|
|
|
if n.val != nil {
|
2021-10-06 14:28:56 +00:00
|
|
|
sb.WriteString(indent)
|
2021-10-11 17:31:49 +00:00
|
|
|
sb.WriteString("val:")
|
|
|
|
fmt.Fprintf(sb, " %x", n.val.([]byte))
|
2021-10-06 14:28:56 +00:00
|
|
|
sb.WriteString("\n")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (n *node) String() string {
|
|
|
|
var sb strings.Builder
|
|
|
|
n.print(&sb, "")
|
|
|
|
return sb.String()
|
|
|
|
}
|
|
|
|
|
|
|
|
type state struct {
|
|
|
|
n *node
|
|
|
|
head uint32
|
|
|
|
tail uint32
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *state) String() string {
|
|
|
|
return fmt.Sprintf("%p head %s tail %s", s.n, tostr(s.head), tostr(s.tail))
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *state) reset(n *node) {
|
|
|
|
s.n = n
|
|
|
|
s.head = 0
|
|
|
|
s.tail = 0
|
|
|
|
}
|
|
|
|
|
|
|
|
func makestate(n *node) *state {
|
|
|
|
return &state{n: n, head: 0, tail: 0}
|
|
|
|
}
|
|
|
|
|
|
|
|
// transition consumes next byte of the key, moves the state to corresponding
|
|
|
|
// node of the patricia tree and returns divergence prefix (0 if there is no divergence)
|
2022-01-24 22:13:48 +00:00
|
|
|
func (s *state) transition(b byte, readonly bool) uint32 {
|
2021-10-06 14:28:56 +00:00
|
|
|
bitsLeft := 8 // Bits in b to process
|
|
|
|
b32 := uint32(b) << 24
|
|
|
|
for bitsLeft > 0 {
|
|
|
|
//fmt.Printf("bitsLeft = %d, b32 = %x, s.head = %s, s.tail = %s\n", bitsLeft, b32, tostr(s.head), tostr(s.tail))
|
|
|
|
if s.head == 0 {
|
|
|
|
// tail has not been determined yet, do it now
|
|
|
|
if b32&0x80000000 == 0 {
|
|
|
|
s.tail = s.n.p0
|
|
|
|
} else {
|
|
|
|
s.tail = s.n.p1
|
|
|
|
}
|
|
|
|
//fmt.Printf("s.tail <- %s\n", tostr(s.tail))
|
|
|
|
}
|
|
|
|
if s.tail == 0 {
|
|
|
|
return b32 | uint32(bitsLeft)
|
|
|
|
}
|
|
|
|
tailLen := int(s.tail & 0x1f)
|
|
|
|
firstDiff := bits.LeadingZeros32(s.tail ^ b32) // First bit where b32 and tail are different
|
|
|
|
//fmt.Printf("firstDiff = %d, bitsLeft = %d\n", firstDiff, bitsLeft)
|
|
|
|
if firstDiff < bitsLeft {
|
|
|
|
//fmt.Printf("firstDiff < bitsLeft\n")
|
|
|
|
if firstDiff >= tailLen {
|
|
|
|
//fmt.Printf("firstDiff >= tailLen\n")
|
|
|
|
bitsLeft -= tailLen
|
|
|
|
b32 <<= tailLen
|
|
|
|
// Need to switch to the next node
|
|
|
|
if (s.head == 0 && s.tail&0x80000000 == 0) || (s.head != 0 && s.head&0x80000000 == 0) {
|
|
|
|
if s.n.n0 == nil {
|
2022-01-24 22:13:48 +00:00
|
|
|
if readonly {
|
|
|
|
return b32 | uint32(bitsLeft)
|
|
|
|
}
|
2021-10-06 14:28:56 +00:00
|
|
|
//fmt.Printf("new node n0\n")
|
|
|
|
s.n.n0 = &node{}
|
|
|
|
if b32&0x80000000 == 0 {
|
|
|
|
s.n.n0.p0 = b32 | uint32(bitsLeft)
|
|
|
|
} else {
|
|
|
|
s.n.n0.p1 = b32 | uint32(bitsLeft)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
s.n = s.n.n0
|
|
|
|
} else {
|
|
|
|
if s.n.n1 == nil {
|
2022-01-24 22:13:48 +00:00
|
|
|
if readonly {
|
|
|
|
return b32 | uint32(bitsLeft)
|
|
|
|
}
|
2021-10-06 14:28:56 +00:00
|
|
|
//fmt.Printf("new node n1\n")
|
|
|
|
s.n.n1 = &node{}
|
|
|
|
if b32&0x80000000 == 0 {
|
|
|
|
s.n.n1.p0 = b32 | uint32(bitsLeft)
|
|
|
|
} else {
|
|
|
|
s.n.n1.p1 = b32 | uint32(bitsLeft)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
s.n = s.n.n1
|
|
|
|
}
|
|
|
|
//fmt.Printf("s.n = %p\n", s.n)
|
|
|
|
s.head = 0
|
|
|
|
s.tail = 0
|
|
|
|
} else {
|
|
|
|
bitsLeft -= firstDiff
|
|
|
|
b32 <<= firstDiff
|
|
|
|
// there is divergence, move head and tail
|
|
|
|
mask := ^(uint32(1)<<(32-firstDiff) - 1)
|
|
|
|
s.head |= (s.tail & mask) >> (s.head & 0x1f)
|
|
|
|
s.head += uint32(firstDiff)
|
|
|
|
s.tail = (s.tail&0xffffffe0)<<firstDiff | (s.tail & 0x1f)
|
|
|
|
s.tail -= uint32(firstDiff)
|
|
|
|
return b32 | uint32(bitsLeft)
|
|
|
|
}
|
|
|
|
} else if tailLen < bitsLeft {
|
|
|
|
//fmt.Printf("tailLen < bitsLeft\n")
|
|
|
|
bitsLeft -= tailLen
|
|
|
|
b32 <<= tailLen
|
|
|
|
// Switch to the next node
|
|
|
|
if (s.head == 0 && s.tail&0x80000000 == 0) || (s.head != 0 && s.head&0x80000000 == 0) {
|
|
|
|
if s.n.n0 == nil {
|
2022-01-24 22:13:48 +00:00
|
|
|
if readonly {
|
|
|
|
return b32 | uint32(bitsLeft)
|
|
|
|
}
|
2021-10-06 14:28:56 +00:00
|
|
|
s.n.n0 = &node{}
|
|
|
|
if b32&0x80000000 == 0 {
|
|
|
|
s.n.n0.p0 = b32 | uint32(bitsLeft)
|
|
|
|
} else {
|
|
|
|
s.n.n0.p1 = b32 | uint32(bitsLeft)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
s.n = s.n.n0
|
|
|
|
} else {
|
|
|
|
if s.n.n1 == nil {
|
2022-01-24 22:13:48 +00:00
|
|
|
if readonly {
|
|
|
|
return b32 | uint32(bitsLeft)
|
|
|
|
}
|
2021-10-06 14:28:56 +00:00
|
|
|
s.n.n1 = &node{}
|
|
|
|
if b32&0x80000000 == 0 {
|
|
|
|
s.n.n1.p0 = b32 | uint32(bitsLeft)
|
|
|
|
} else {
|
|
|
|
s.n.n1.p1 = b32 | uint32(bitsLeft)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
s.n = s.n.n1
|
|
|
|
}
|
|
|
|
s.head = 0
|
|
|
|
s.tail = 0
|
|
|
|
} else {
|
|
|
|
// key byte is consumed
|
|
|
|
mask := ^(uint32(1)<<(32-bitsLeft) - 1)
|
|
|
|
s.head |= (s.tail & mask) >> (s.head & 0x1f)
|
|
|
|
s.head += uint32(bitsLeft)
|
|
|
|
s.tail = (s.tail&0xffffffe0)<<bitsLeft | (s.tail & 0x1f)
|
|
|
|
s.tail -= uint32(bitsLeft)
|
|
|
|
bitsLeft = 0
|
|
|
|
if s.tail == 0 {
|
|
|
|
if s.head&0x80000000 == 0 {
|
|
|
|
if s.n.n0 != nil {
|
|
|
|
s.n = s.n.n0
|
|
|
|
s.head = 0
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if s.n.n1 != nil {
|
|
|
|
s.n = s.n.n1
|
|
|
|
s.head = 0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *state) diverge(divergence uint32) {
|
|
|
|
if s.tail == 0 {
|
|
|
|
// try to add to the existing head
|
|
|
|
//fmt.Printf("adding divergence to existing head\n")
|
|
|
|
dLen := int(divergence & 0x1f)
|
|
|
|
headLen := int(s.head & 0x1f)
|
|
|
|
d32 := divergence & 0xffffffe0
|
|
|
|
//fmt.Printf("headLen %d + dLen %d = %d\n", headLen, dLen, headLen+dLen)
|
|
|
|
if headLen+dLen > 27 {
|
|
|
|
mask := ^(uint32(1)<<(headLen+5) - 1)
|
|
|
|
//fmt.Printf("mask = %b\n", mask)
|
|
|
|
s.head |= (d32 & mask) >> headLen
|
|
|
|
s.head += uint32(27 - headLen)
|
|
|
|
//fmt.Printf("s.head %s\n", tostr(s.head))
|
|
|
|
var dn node
|
|
|
|
if (s.head == 0 && s.tail&0x80000000 == 0) || (s.head != 0 && s.head&0x80000000 == 0) {
|
|
|
|
s.n.p0 = s.head
|
|
|
|
s.n.n0 = &dn
|
|
|
|
} else {
|
|
|
|
s.n.p1 = s.head
|
|
|
|
s.n.n1 = &dn
|
|
|
|
}
|
|
|
|
s.n = &dn
|
|
|
|
s.head = 0
|
|
|
|
s.tail = 0
|
|
|
|
d32 <<= 27 - headLen
|
|
|
|
dLen -= (27 - headLen)
|
|
|
|
headLen = 0
|
|
|
|
}
|
|
|
|
//fmt.Printf("headLen %d + dLen %d = %d\n", headLen, dLen, headLen+dLen)
|
|
|
|
mask := ^(uint32(1)<<(32-dLen) - 1)
|
|
|
|
//fmt.Printf("mask = %b\n", mask)
|
|
|
|
s.head |= (d32 & mask) >> headLen
|
|
|
|
s.head += uint32(dLen)
|
|
|
|
//fmt.Printf("s.head %s\n", tostr(s.head))
|
|
|
|
if (s.head == 0 && s.tail&0x80000000 == 0) || (s.head != 0 && s.head&0x80000000 == 0) {
|
|
|
|
s.n.p0 = s.head
|
|
|
|
} else {
|
|
|
|
s.n.p1 = s.head
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
// create a new node
|
|
|
|
var dn node
|
|
|
|
if divergence&0x80000000 == 0 {
|
|
|
|
dn.p0 = divergence
|
|
|
|
dn.p1 = s.tail
|
|
|
|
if (s.head == 0 && s.tail&0x80000000 == 0) || (s.head != 0 && s.head&0x80000000 == 0) {
|
|
|
|
dn.n1 = s.n.n0
|
|
|
|
} else {
|
|
|
|
dn.n1 = s.n.n1
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
dn.p1 = divergence
|
|
|
|
dn.p0 = s.tail
|
|
|
|
if (s.head == 0 && s.tail&0x80000000 == 0) || (s.head != 0 && s.head&0x80000000 == 0) {
|
|
|
|
dn.n0 = s.n.n0
|
|
|
|
} else {
|
|
|
|
dn.n0 = s.n.n1
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (s.head == 0 && s.tail&0x80000000 == 0) || (s.head != 0 && s.head&0x80000000 == 0) {
|
|
|
|
s.n.n0 = &dn
|
|
|
|
s.n.p0 = s.head
|
|
|
|
} else {
|
|
|
|
s.n.n1 = &dn
|
|
|
|
s.n.p1 = s.head
|
|
|
|
}
|
|
|
|
s.n = &dn
|
|
|
|
s.head = divergence
|
|
|
|
s.tail = 0
|
|
|
|
}
|
|
|
|
|
2021-10-11 17:31:49 +00:00
|
|
|
func (n *node) insert(key []byte, value interface{}) {
|
2021-10-06 14:28:56 +00:00
|
|
|
s := makestate(n)
|
|
|
|
for _, b := range key {
|
2022-01-24 22:13:48 +00:00
|
|
|
divergence := s.transition(b, false /* readonly */)
|
2021-10-06 14:28:56 +00:00
|
|
|
if divergence != 0 {
|
|
|
|
s.diverge(divergence)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
s.insert(value)
|
|
|
|
}
|
|
|
|
|
2021-10-11 17:31:49 +00:00
|
|
|
func (s *state) insert(value interface{}) {
|
2021-10-06 14:28:56 +00:00
|
|
|
if s.tail != 0 {
|
|
|
|
s.diverge(0)
|
|
|
|
}
|
|
|
|
if s.head != 0 {
|
|
|
|
var dn node
|
|
|
|
if s.head&0x80000000 == 0 {
|
|
|
|
s.n.n0 = &dn
|
|
|
|
} else {
|
|
|
|
s.n.n1 = &dn
|
|
|
|
}
|
|
|
|
s.n = &dn
|
|
|
|
s.head = 0
|
|
|
|
}
|
2021-10-11 17:31:49 +00:00
|
|
|
s.n.val = value
|
2021-10-06 14:28:56 +00:00
|
|
|
}
|
|
|
|
|
2021-10-11 17:31:49 +00:00
|
|
|
func (n *node) get(key []byte) (interface{}, bool) {
|
2021-10-06 14:28:56 +00:00
|
|
|
s := makestate(n)
|
|
|
|
for _, b := range key {
|
2022-01-24 22:13:48 +00:00
|
|
|
divergence := s.transition(b, true /* readonly */)
|
2021-10-06 14:28:56 +00:00
|
|
|
//fmt.Printf("get %x, b = %x, divergence = %s\nstate=%s\n", key, b, tostr(divergence), s)
|
|
|
|
if divergence != 0 {
|
|
|
|
return nil, false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if s.tail != 0 {
|
|
|
|
return nil, false
|
|
|
|
}
|
2021-10-11 17:31:49 +00:00
|
|
|
return s.n.val, s.n.val != nil
|
2021-10-06 14:28:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type PatriciaTree struct {
|
|
|
|
root node
|
|
|
|
}
|
|
|
|
|
2021-10-11 17:31:49 +00:00
|
|
|
func (pt *PatriciaTree) Insert(key []byte, value interface{}) {
|
2021-10-06 14:28:56 +00:00
|
|
|
pt.root.insert(key, value)
|
|
|
|
}
|
|
|
|
|
2021-10-11 17:31:49 +00:00
|
|
|
func (pt PatriciaTree) Get(key []byte) (interface{}, bool) {
|
2021-10-06 14:28:56 +00:00
|
|
|
return pt.root.get(key)
|
|
|
|
}
|
|
|
|
|
|
|
|
type Match struct {
|
|
|
|
Start int
|
|
|
|
End int
|
2021-10-11 17:31:49 +00:00
|
|
|
Val interface{}
|
2021-10-06 14:28:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type MatchFinder struct {
|
|
|
|
s state
|
|
|
|
matches []Match
|
|
|
|
}
|
|
|
|
|
|
|
|
func (mf *MatchFinder) FindLongestMatches(pt *PatriciaTree, data []byte) []Match {
|
|
|
|
matchCount := 0
|
|
|
|
s := &mf.s
|
|
|
|
lastEnd := 0
|
|
|
|
for start := 0; start < len(data)-1; start++ {
|
|
|
|
s.reset(&pt.root)
|
|
|
|
emitted := false
|
|
|
|
for end := start + 1; end < len(data); end++ {
|
2022-01-24 22:13:48 +00:00
|
|
|
if d := s.transition(data[end-1], true /* readonly */); d == 0 {
|
2021-10-11 17:31:49 +00:00
|
|
|
if s.tail == 0 && s.n.val != nil && end > lastEnd {
|
2021-10-06 14:28:56 +00:00
|
|
|
var m *Match
|
|
|
|
if !emitted {
|
|
|
|
if matchCount == len(mf.matches) {
|
|
|
|
mf.matches = append(mf.matches, Match{})
|
|
|
|
m = &mf.matches[len(mf.matches)-1]
|
|
|
|
} else {
|
|
|
|
m = &mf.matches[matchCount]
|
|
|
|
}
|
|
|
|
matchCount++
|
|
|
|
emitted = true
|
|
|
|
} else {
|
|
|
|
m = &mf.matches[matchCount-1]
|
|
|
|
}
|
|
|
|
// This possible overwrites previous match for the same start position
|
|
|
|
m.Start = start
|
|
|
|
m.End = end
|
2021-10-11 17:31:49 +00:00
|
|
|
m.Val = s.n.val
|
2021-10-06 14:28:56 +00:00
|
|
|
lastEnd = end
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return mf.matches[:matchCount]
|
|
|
|
}
|