alice-lg/pkg/pools/lists.go
2022-11-16 11:20:54 +01:00

113 lines
2.1 KiB
Go

package pools
import (
"sync"
)
// Node is a node in the tree.
type Node struct {
children map[int]*Node
counter int
ptr interface{}
}
// NewNode creates a new tree node
func NewNode(ptr interface{}) *Node {
return &Node{
children: map[int]*Node{},
ptr: ptr,
}
}
// Internally acquire list by traversing the tree and
// creating nodes if required.
func (n *Node) traverse(list interface{}, tail []int) interface{} {
value := tail[0]
tail = tail[1:]
// Seek for value in children
child, ok := n.children[value]
if !ok {
child = NewNode(nil)
n.children[value] = child
}
// Set list ptr if required
if len(tail) == 0 {
if child.ptr == nil {
child.ptr = list
}
return child.ptr
}
return child.traverse(list, tail)
}
// A IntListPool can be used to deduplicate
// lists of integers. Like an AS path or BGP communities.
//
// A Tree datastructure is used.
type IntListPool struct {
root *Node
sync.Mutex
}
// NewIntListPool creates a new int list pool
func NewIntListPool() *IntListPool {
return &IntListPool{
root: NewNode([]int{}),
}
}
// Acquire int list from pool
func (p *IntListPool) Acquire(list []int) []int {
p.Lock()
defer p.Unlock()
if len(list) == 0 {
return p.root.ptr.([]int) // root
}
return p.root.traverse(list, list).([]int)
}
// A StringListPool can be used for deduplicating lists
// of strings. (This is a variant of an int list, as string
// values are converted to int.
type StringListPool struct {
root *Node
values map[string]int
head int
sync.Mutex
}
// NewStringListPool creates a new string list.
func NewStringListPool() *StringListPool {
return &StringListPool{
head: 1,
values: map[string]int{},
root: NewNode([]string{}),
}
}
// Acquire the string list pointer from the pool
func (p *StringListPool) Acquire(list []string) []string {
if len(list) == 0 {
return p.root.ptr.([]string) // root
}
// Make idenfier list
id := make([]int, len(list))
for i, s := range list {
// Resolve string value into int
v, ok := p.values[s]
if !ok {
p.head++
p.values[s] = p.head
v = p.head
}
id[i] = v
}
return p.root.traverse(list, id).([]string)
}