use internal id
This commit is contained in:
parent
85c5d19d4f
commit
aa3fe6dd2c
@ -2,9 +2,7 @@ package pools
|
||||
|
||||
import (
|
||||
"math"
|
||||
"reflect"
|
||||
"sync"
|
||||
"unsafe"
|
||||
|
||||
"github.com/alice-lg/alice-lg/pkg/api"
|
||||
)
|
||||
@ -13,7 +11,8 @@ import (
|
||||
// This works with large and standard communities. For extended
|
||||
// communities, use the ExtCommunityPool.
|
||||
type CommunitiesPool struct {
|
||||
root *Node[int, api.Community]
|
||||
root *Node[int, api.Community]
|
||||
counter uint64
|
||||
sync.RWMutex
|
||||
}
|
||||
|
||||
@ -24,35 +23,42 @@ func NewCommunitiesPool() *CommunitiesPool {
|
||||
}
|
||||
}
|
||||
|
||||
// Acquire a single bgp community
|
||||
func (p *CommunitiesPool) Acquire(c api.Community) api.Community {
|
||||
// AcquireGid acquires a single bgp community with gid
|
||||
func (p *CommunitiesPool) AcquireGid(c api.Community) (api.Community, uint64) {
|
||||
p.Lock()
|
||||
defer p.Unlock()
|
||||
if len(c) == 0 {
|
||||
return p.root.value
|
||||
return p.root.value, p.root.gid
|
||||
}
|
||||
return p.root.traverse(c, c)
|
||||
v, gid := p.root.traverse(p.counter+1, c, c)
|
||||
if gid > p.counter {
|
||||
p.counter = gid
|
||||
}
|
||||
return v, gid
|
||||
}
|
||||
|
||||
// Acquire a single bgp community without gid
|
||||
func (p *CommunitiesPool) Acquire(c api.Community) api.Community {
|
||||
v, _ := p.AcquireGid(c)
|
||||
return v
|
||||
}
|
||||
|
||||
// Read a single bgp community
|
||||
func (p *CommunitiesPool) Read(c api.Community) api.Community {
|
||||
func (p *CommunitiesPool) Read(c api.Community) (api.Community, uint64) {
|
||||
p.RLock()
|
||||
defer p.RUnlock()
|
||||
if len(c) == 0 {
|
||||
return p.root.value // root
|
||||
return p.root.value, p.root.gid
|
||||
}
|
||||
v := p.root.read(c)
|
||||
if v == nil {
|
||||
return nil
|
||||
}
|
||||
return v
|
||||
return p.root.read(c)
|
||||
}
|
||||
|
||||
// CommunitiesSetPool is for deduplicating a list of BGP communities
|
||||
// (Large and default. The ext communities representation right now
|
||||
// makes problems and need to be fixed. TODO.)
|
||||
type CommunitiesSetPool struct {
|
||||
root *Node[unsafe.Pointer, []api.Community]
|
||||
root *Node[uint64, []api.Community]
|
||||
counter uint64
|
||||
sync.Mutex
|
||||
}
|
||||
|
||||
@ -60,32 +66,47 @@ type CommunitiesSetPool struct {
|
||||
// of BGP communities.
|
||||
func NewCommunitiesSetPool() *CommunitiesSetPool {
|
||||
return &CommunitiesSetPool{
|
||||
root: NewNode[unsafe.Pointer, []api.Community]([]api.Community{}),
|
||||
root: NewNode[uint64, []api.Community]([]api.Community{}),
|
||||
}
|
||||
}
|
||||
|
||||
// Acquire a list of bgp communities
|
||||
func (p *CommunitiesSetPool) Acquire(communities []api.Community) []api.Community {
|
||||
// AcquireGid acquires a list of bgp communities and returns a gid
|
||||
func (p *CommunitiesSetPool) AcquireGid(
|
||||
communities []api.Community,
|
||||
) ([]api.Community, uint64) {
|
||||
p.Lock()
|
||||
defer p.Unlock()
|
||||
// Make identification list by using the pointer address
|
||||
// of the deduplicated community as ID
|
||||
ids := make([]unsafe.Pointer, len(communities))
|
||||
ids := make([]uint64, len(communities))
|
||||
set := make([]api.Community, len(communities))
|
||||
for i, comm := range communities {
|
||||
commPtr := Communities.Acquire(comm)
|
||||
ids[i] = reflect.ValueOf(commPtr).UnsafePointer()
|
||||
set[i] = commPtr
|
||||
ptr, gid := Communities.AcquireGid(comm)
|
||||
ids[i] = gid
|
||||
set[i] = ptr
|
||||
}
|
||||
if len(ids) == 0 {
|
||||
return p.root.value
|
||||
return p.root.value, p.root.gid
|
||||
}
|
||||
return p.root.traverse(set, ids)
|
||||
v, id := p.root.traverse(p.counter+1, set, ids)
|
||||
if id > p.counter {
|
||||
p.counter = id
|
||||
}
|
||||
return v, id
|
||||
}
|
||||
|
||||
// Acquire a list of bgp communities
|
||||
func (p *CommunitiesSetPool) Acquire(
|
||||
communities []api.Community,
|
||||
) []api.Community {
|
||||
v, _ := p.AcquireGid(communities)
|
||||
return v
|
||||
}
|
||||
|
||||
// ExtCommunitiesSetPool is for deduplicating a list of ext. BGP communities
|
||||
type ExtCommunitiesSetPool struct {
|
||||
root *Node[unsafe.Pointer, []api.ExtCommunity]
|
||||
root *Node[uint64, []api.ExtCommunity]
|
||||
counter uint64
|
||||
sync.Mutex
|
||||
}
|
||||
|
||||
@ -93,7 +114,7 @@ type ExtCommunitiesSetPool struct {
|
||||
// of BGP communities.
|
||||
func NewExtCommunitiesSetPool() *ExtCommunitiesSetPool {
|
||||
return &ExtCommunitiesSetPool{
|
||||
root: NewNode[unsafe.Pointer, []api.ExtCommunity]([]api.ExtCommunity{}),
|
||||
root: NewNode[uint64, []api.ExtCommunity]([]api.ExtCommunity{}),
|
||||
}
|
||||
}
|
||||
|
||||
@ -105,23 +126,37 @@ func extPrefixToInt(s string) int {
|
||||
return v
|
||||
}
|
||||
|
||||
// AcquireExt a list of ext bgp communities
|
||||
func (p *ExtCommunitiesSetPool) Acquire(communities []api.ExtCommunity) []api.ExtCommunity {
|
||||
// AcquireGid acquires a list of ext bgp communities
|
||||
func (p *ExtCommunitiesSetPool) AcquireGid(
|
||||
communities []api.ExtCommunity,
|
||||
) ([]api.ExtCommunity, uint64) {
|
||||
p.Lock()
|
||||
defer p.Unlock()
|
||||
|
||||
// Make identification list
|
||||
ids := make([]unsafe.Pointer, len(communities))
|
||||
ids := make([]uint64, len(communities))
|
||||
for i, comm := range communities {
|
||||
r := extPrefixToInt(comm[0].(string))
|
||||
icomm := []int{r, comm[1].(int), comm[2].(int)}
|
||||
|
||||
// get community identifier
|
||||
commPtr := ExtCommunities.Acquire(icomm)
|
||||
ids[i] = reflect.ValueOf(commPtr).UnsafePointer()
|
||||
_, gid := ExtCommunities.AcquireGid(icomm)
|
||||
ids[i] = gid
|
||||
}
|
||||
if len(ids) == 0 {
|
||||
return p.root.value
|
||||
return p.root.value, p.root.gid
|
||||
}
|
||||
return p.root.traverse(communities, ids)
|
||||
v, id := p.root.traverse(p.counter+1, communities, ids)
|
||||
if id > p.counter {
|
||||
p.counter = id
|
||||
}
|
||||
return v, id
|
||||
}
|
||||
|
||||
// Acquire a list of ext bgp communities
|
||||
func (p *ExtCommunitiesSetPool) Acquire(
|
||||
communities []api.ExtCommunity,
|
||||
) []api.ExtCommunity {
|
||||
v, _ := p.AcquireGid(communities)
|
||||
return v
|
||||
}
|
||||
|
@ -9,16 +9,16 @@ import (
|
||||
"github.com/alice-lg/alice-lg/pkg/api"
|
||||
)
|
||||
|
||||
func TestAcquireCommunity(t *testing.T) {
|
||||
func TestAcquireGidCommunity(t *testing.T) {
|
||||
c1 := api.Community{2342, 5, 1}
|
||||
c2 := api.Community{2342, 5, 1}
|
||||
c3 := api.Community{2342, 5}
|
||||
|
||||
p := NewCommunitiesPool()
|
||||
|
||||
pc1 := p.Acquire(c1)
|
||||
pc2 := p.Acquire(c2)
|
||||
pc3 := p.Acquire(c3)
|
||||
pc1, gid1 := p.AcquireGid(c1)
|
||||
pc2, gid2 := p.AcquireGid(c2)
|
||||
pc3, gid3 := p.AcquireGid(c3)
|
||||
|
||||
if fmt.Sprintf("%p", c1) == fmt.Sprintf("%p", c2) {
|
||||
t.Error("expected c1 !== c2")
|
||||
@ -28,10 +28,19 @@ func TestAcquireCommunity(t *testing.T) {
|
||||
t.Error("expected pc1 == pc2")
|
||||
}
|
||||
|
||||
if gid1 != gid2 {
|
||||
t.Error("expected gid1 == gid2")
|
||||
}
|
||||
|
||||
if gid1 == gid3 {
|
||||
t.Error("expected gid1 != gid3")
|
||||
}
|
||||
|
||||
fmt.Printf("c1: %p, c2: %p, c3: %p\n", c1, c2, c3)
|
||||
fmt.Printf("pc1: %p, pc2: %p, pc3: %p\n", pc1, pc2, pc3)
|
||||
|
||||
log.Println(c3, pc3)
|
||||
log.Println(gid1, gid2, gid3)
|
||||
}
|
||||
|
||||
func TestCommunityRead(t *testing.T) {
|
||||
@ -41,22 +50,29 @@ func TestCommunityRead(t *testing.T) {
|
||||
|
||||
p := NewCommunitiesPool()
|
||||
|
||||
pc1 := p.Acquire(c1)
|
||||
pc2 := p.Read(c2)
|
||||
pc3 := p.Read(c3)
|
||||
pc1, gid1 := p.AcquireGid(c1)
|
||||
pc2, gid2 := p.Read(c2)
|
||||
pc3, gid3 := p.Read(c3)
|
||||
|
||||
fmt.Printf("pc1: %p, pc2: %p, pc3: %p\n", pc1, pc2, pc3)
|
||||
fmt.Printf("gid1: %d, gid2: %d, gid3: %d\n", gid1, gid2, gid3)
|
||||
|
||||
if fmt.Sprintf("%p", pc1) != fmt.Sprintf("%p", pc2) {
|
||||
t.Error("expected pc1 == pc2")
|
||||
}
|
||||
if gid1 != gid2 {
|
||||
t.Error("expected gid1 == gid2")
|
||||
}
|
||||
|
||||
if pc3 != nil {
|
||||
t.Error("expected pc3 == nil, got", pc3)
|
||||
}
|
||||
if gid3 != 0 {
|
||||
t.Error("expected gid3 == 0, got", gid3)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAcquireCommunitiesSets(t *testing.T) {
|
||||
func TestAcquireGidCommunitiesSets(t *testing.T) {
|
||||
c1 := []api.Community{
|
||||
{2342, 5, 1},
|
||||
{2342, 5, 2},
|
||||
@ -75,9 +91,9 @@ func TestAcquireCommunitiesSets(t *testing.T) {
|
||||
|
||||
p := NewCommunitiesSetPool()
|
||||
|
||||
pc1 := p.Acquire(c1)
|
||||
pc2 := p.Acquire(c2)
|
||||
pc3 := p.Acquire(c3)
|
||||
pc1, gid1 := p.AcquireGid(c1)
|
||||
pc2, gid2 := p.AcquireGid(c2)
|
||||
pc3, gid3 := p.AcquireGid(c3)
|
||||
|
||||
if fmt.Sprintf("%p", c1) == fmt.Sprintf("%p", c2) {
|
||||
t.Error("expected c1 !== c2")
|
||||
@ -86,9 +102,14 @@ func TestAcquireCommunitiesSets(t *testing.T) {
|
||||
if fmt.Sprintf("%p", pc1) != fmt.Sprintf("%p", pc2) {
|
||||
t.Error("expected pc1 == pc2")
|
||||
}
|
||||
if gid1 != gid2 {
|
||||
t.Error("expected gid1 == gid2")
|
||||
}
|
||||
|
||||
fmt.Printf("c1: %p, c2: %p, c3: %p\n", c1, c2, c3)
|
||||
fmt.Printf("pc1: %p, pc2: %p, pc3: %p\n", pc1, pc2, pc3)
|
||||
|
||||
t.Logf("gid1: %d, gid2: %d, gid3: %d\n", gid1, gid2, gid3)
|
||||
}
|
||||
|
||||
func TestSetCommunityIdentity(t *testing.T) {
|
||||
@ -98,10 +119,11 @@ func TestSetCommunityIdentity(t *testing.T) {
|
||||
{2341, 1, 1},
|
||||
}
|
||||
|
||||
pset := CommunitiesSets.Acquire(set)
|
||||
pval := Communities.Acquire(api.Community{2341, 6, 2})
|
||||
pset, gid1 := CommunitiesSets.AcquireGid(set)
|
||||
pval, gid2 := Communities.AcquireGid(api.Community{2341, 6, 2})
|
||||
|
||||
fmt.Printf("set: %p, pset[1]: %p, pval: %p\n", set, pset[1], pval)
|
||||
fmt.Printf("gid1: %d, gid2: %d\n", gid1, gid2)
|
||||
|
||||
p1 := reflect.ValueOf(pset[1]).UnsafePointer()
|
||||
p2 := reflect.ValueOf(pval).UnsafePointer()
|
||||
@ -111,7 +133,7 @@ func TestSetCommunityIdentity(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestAcquireExtCommunitiesSets(t *testing.T) {
|
||||
func TestAcquireGidExtCommunitiesSets(t *testing.T) {
|
||||
c1 := []api.ExtCommunity{
|
||||
{"ro", 5, 1},
|
||||
{"ro", 5, 2},
|
||||
@ -130,9 +152,9 @@ func TestAcquireExtCommunitiesSets(t *testing.T) {
|
||||
|
||||
p := NewExtCommunitiesSetPool()
|
||||
|
||||
pc1 := p.Acquire(c1)
|
||||
pc2 := p.Acquire(c2)
|
||||
pc3 := p.Acquire(c3)
|
||||
pc1, gid1 := p.AcquireGid(c1)
|
||||
pc2, gid2 := p.AcquireGid(c2)
|
||||
pc3, gid3 := p.AcquireGid(c3)
|
||||
|
||||
if fmt.Sprintf("%p", c1) == fmt.Sprintf("%p", c2) {
|
||||
t.Error("expected c1 !== c2")
|
||||
@ -141,7 +163,11 @@ func TestAcquireExtCommunitiesSets(t *testing.T) {
|
||||
if fmt.Sprintf("%p", pc1) != fmt.Sprintf("%p", pc2) {
|
||||
t.Error("expected pc1 == pc2")
|
||||
}
|
||||
if gid1 != gid2 {
|
||||
t.Error("expected gid1 == gid2")
|
||||
}
|
||||
|
||||
fmt.Printf("c1: %p, c2: %p, c3: %p\n", c1, c2, c3)
|
||||
fmt.Printf("pc1: %p, pc2: %p, pc3: %p\n", pc1, pc2, pc3)
|
||||
fmt.Printf("gid1: %d, gid2: %d, gid3: %d\n", gid1, gid2, gid3)
|
||||
}
|
||||
|
@ -9,7 +9,8 @@ import (
|
||||
//
|
||||
// A Tree datastructure is used.
|
||||
type IntListPool struct {
|
||||
root *Node[int, []int]
|
||||
root *Node[int, []int]
|
||||
counter uint64
|
||||
sync.Mutex
|
||||
}
|
||||
|
||||
@ -20,15 +21,25 @@ func NewIntListPool() *IntListPool {
|
||||
}
|
||||
}
|
||||
|
||||
// Acquire int list from pool
|
||||
func (p *IntListPool) Acquire(list []int) []int {
|
||||
// AcquireGid int list from pool and return with gid
|
||||
func (p *IntListPool) AcquireGid(list []int) ([]int, uint64) {
|
||||
p.Lock()
|
||||
defer p.Unlock()
|
||||
|
||||
if len(list) == 0 {
|
||||
return p.root.value // root
|
||||
return p.root.value, p.root.gid // root
|
||||
}
|
||||
return p.root.traverse(list, list)
|
||||
v, c := p.root.traverse(p.counter+1, list, list)
|
||||
if c > p.counter {
|
||||
p.counter = c
|
||||
}
|
||||
return v, c
|
||||
}
|
||||
|
||||
// Acquire int list from pool without gid
|
||||
func (p *IntListPool) Acquire(list []int) []int {
|
||||
v, _ := p.AcquireGid(list)
|
||||
return v
|
||||
}
|
||||
|
||||
// A StringListPool can be used for deduplicating lists
|
||||
@ -50,10 +61,11 @@ func NewStringListPool() *StringListPool {
|
||||
}
|
||||
}
|
||||
|
||||
// Acquire the string list pointer from the pool
|
||||
func (p *StringListPool) Acquire(list []string) []string {
|
||||
// AcquireGid aquires the string list pointer from the pool
|
||||
// and also returns the gid.
|
||||
func (p *StringListPool) AcquireGid(list []string) ([]string, uint64) {
|
||||
if len(list) == 0 {
|
||||
return p.root.value
|
||||
return p.root.value, p.root.gid
|
||||
}
|
||||
|
||||
// Make idenfier list
|
||||
@ -69,5 +81,11 @@ func (p *StringListPool) Acquire(list []string) []string {
|
||||
id[i] = v
|
||||
}
|
||||
|
||||
return p.root.traverse(list, id)
|
||||
return p.root.traverse(uint64(p.head), list, id)
|
||||
}
|
||||
|
||||
// Acquire aquires the string list pointer from the pool
|
||||
func (p *StringListPool) Acquire(list []string) []string {
|
||||
v, _ := p.AcquireGid(list)
|
||||
return v
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package pools
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"testing"
|
||||
)
|
||||
|
||||
@ -12,9 +13,12 @@ func TestAcquireIntList(t *testing.T) {
|
||||
|
||||
p := NewIntListPool()
|
||||
|
||||
r1 := p.Acquire(a)
|
||||
r1, gid1 := p.AcquireGid(a)
|
||||
p.Acquire(c)
|
||||
r2 := p.Acquire(b)
|
||||
r2, gid2 := p.AcquireGid(b)
|
||||
|
||||
log.Println("r1", r1, "gid1", gid1)
|
||||
log.Println("r2", r2, "gid2", gid2)
|
||||
|
||||
if fmt.Sprintf("%p", a) == fmt.Sprintf("%p", b) {
|
||||
t.Error("lists should not be same pointer", fmt.Sprintf("%p %p", a, b))
|
||||
@ -22,7 +26,17 @@ func TestAcquireIntList(t *testing.T) {
|
||||
if fmt.Sprintf("%p", r1) != fmt.Sprintf("%p", r2) {
|
||||
t.Error("lists should be same pointer", fmt.Sprintf("%p %p", r1, r2))
|
||||
}
|
||||
if gid1 != gid2 {
|
||||
t.Error("gid should be same, got:", gid1, gid2)
|
||||
}
|
||||
|
||||
t.Log(fmt.Sprintf("Ptr: %p %p => %p %p", a, b, r1, r2))
|
||||
|
||||
_, gid3 := p.AcquireGid(c)
|
||||
if gid3 == gid1 {
|
||||
t.Error("gid should not be same, got:", gid3, gid1)
|
||||
}
|
||||
t.Log("gid3", gid3, "gid1", gid1)
|
||||
}
|
||||
|
||||
func TestAcquireStringList(t *testing.T) {
|
||||
@ -31,9 +45,9 @@ func TestAcquireStringList(t *testing.T) {
|
||||
e := []string{"foo", "bpf"}
|
||||
|
||||
p2 := NewStringListPool()
|
||||
x1 := p2.Acquire(q)
|
||||
x2 := p2.Acquire(w)
|
||||
x3 := p2.Acquire(e)
|
||||
fmt.Printf("Ptr: %p %p => %p %p\n", q, w, x1, x2)
|
||||
fmt.Printf("Ptr: %p => %p\n", e, x3)
|
||||
x1, g1 := p2.AcquireGid(q)
|
||||
x2, g2 := p2.AcquireGid(w)
|
||||
x3, g3 := p2.AcquireGid(e)
|
||||
fmt.Printf("Ptr: %p %p => %p %d %p %d \n", q, w, x1, g1, x2, g2)
|
||||
fmt.Printf("Ptr: %p => %p %d\n", e, x3, g3)
|
||||
}
|
||||
|
@ -1,24 +1,10 @@
|
||||
package pools
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
|
||||
"github.com/alice-lg/alice-lg/pkg/api"
|
||||
)
|
||||
|
||||
// NOTE: Yes, generics could be used here.
|
||||
// This also looks like a pretty good use case for them.
|
||||
// However, the performance penalty is too high.
|
||||
//
|
||||
// With: Refreshed routes of rs1.foo (BIRD2 IPv4) in 26.905169348s
|
||||
// Without: Refreshed routes of rs1.foo (BIRD2 IPv4) in 46.760695927s
|
||||
//
|
||||
// So yeah. Copy and paste time!
|
||||
|
||||
type Node[T comparable, V any] struct {
|
||||
children map[T]*Node[T, V] // map of children
|
||||
value V
|
||||
final bool
|
||||
gid uint64
|
||||
}
|
||||
|
||||
// NewNode creates a new tree node
|
||||
@ -32,7 +18,7 @@ func NewNode[T comparable, V any](value V) *Node[T, V] {
|
||||
|
||||
// traverse inserts a new node into the three if required
|
||||
// or returns the object if it already exists.
|
||||
func (n *Node[T, V]) traverse(value V, tail []T) V {
|
||||
func (n *Node[T, V]) traverse(gid uint64, value V, tail []T) (V, uint64) {
|
||||
id := tail[0]
|
||||
tail = tail[1:]
|
||||
|
||||
@ -49,15 +35,16 @@ func (n *Node[T, V]) traverse(value V, tail []T) V {
|
||||
if !child.final {
|
||||
child.value = value
|
||||
child.final = true
|
||||
child.gid = gid
|
||||
}
|
||||
return child.value
|
||||
return child.value, child.gid
|
||||
}
|
||||
|
||||
return child.traverse(value, tail)
|
||||
return child.traverse(gid, value, tail)
|
||||
}
|
||||
|
||||
// read returns the object if it exists or nil if not.
|
||||
func (n *Node[T, V]) read(tail []T) V {
|
||||
func (n *Node[T, V]) read(tail []T) (V, uint64) {
|
||||
id := tail[0]
|
||||
tail = tail[1:]
|
||||
|
||||
@ -65,246 +52,12 @@ func (n *Node[T, V]) read(tail []T) V {
|
||||
child, ok := n.children[id]
|
||||
if !ok {
|
||||
var zero V
|
||||
return zero
|
||||
return zero, 0
|
||||
}
|
||||
|
||||
// Set obj if required
|
||||
if len(tail) == 0 {
|
||||
return child.value
|
||||
}
|
||||
|
||||
return child.read(tail)
|
||||
}
|
||||
|
||||
// IntListNode is a node with an integer as key and
|
||||
// a list of integers as value.
|
||||
type IntListNode struct {
|
||||
children map[int]*IntListNode
|
||||
value []int
|
||||
}
|
||||
|
||||
// NewIntListNode creates a new int tree node
|
||||
func NewIntListNode(value []int) *IntListNode {
|
||||
return &IntListNode{
|
||||
children: map[int]*IntListNode{},
|
||||
value: value,
|
||||
}
|
||||
}
|
||||
|
||||
// IntList traverse inserts a new node into the three if required
|
||||
// or returns the object if it already exists.
|
||||
func (n *IntListNode) traverse(value []int, tail []int) []int {
|
||||
id := tail[0]
|
||||
tail = tail[1:]
|
||||
|
||||
// Seek for identifier in children
|
||||
child, ok := n.children[id]
|
||||
if !ok {
|
||||
child = NewIntListNode(nil)
|
||||
n.children[id] = child
|
||||
}
|
||||
|
||||
// Set obj if required
|
||||
if len(tail) == 0 {
|
||||
if child.value == nil {
|
||||
child.value = value
|
||||
}
|
||||
return child.value
|
||||
}
|
||||
|
||||
return child.traverse(value, tail)
|
||||
}
|
||||
|
||||
// read returns the object if it exists or nil if not.
|
||||
func (n *IntListNode) read(tail []int) []int {
|
||||
id := tail[0]
|
||||
tail = tail[1:]
|
||||
|
||||
// Seek for identifier in children
|
||||
child, ok := n.children[id]
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Set obj if required
|
||||
if len(tail) == 0 {
|
||||
return child.value
|
||||
}
|
||||
|
||||
return child.read(tail)
|
||||
}
|
||||
|
||||
// StringListNode is a node with an integer as key and
|
||||
// a list of integers as value.
|
||||
type StringListNode struct {
|
||||
children map[int]*StringListNode
|
||||
value []string
|
||||
}
|
||||
|
||||
// NewStringListNode creates a new int tree node
|
||||
func NewStringListNode(value []string) *StringListNode {
|
||||
return &StringListNode{
|
||||
children: map[int]*StringListNode{},
|
||||
value: value,
|
||||
}
|
||||
}
|
||||
|
||||
// StringList traverse inserts a new node into the three if required
|
||||
// or returns the object if it already exists.
|
||||
func (n *StringListNode) traverse(value []string, tail []int) []string {
|
||||
id := tail[0]
|
||||
tail = tail[1:]
|
||||
|
||||
// Seek for identifier in children
|
||||
child, ok := n.children[id]
|
||||
if !ok {
|
||||
child = NewStringListNode(nil)
|
||||
n.children[id] = child
|
||||
}
|
||||
|
||||
// Set obj if required
|
||||
if len(tail) == 0 {
|
||||
if child.value == nil {
|
||||
child.value = value
|
||||
}
|
||||
return child.value
|
||||
}
|
||||
|
||||
return child.traverse(value, tail)
|
||||
}
|
||||
|
||||
// read returns the object if it exists or nil if not.
|
||||
func (n *StringListNode) read(tail []int) []string {
|
||||
id := tail[0]
|
||||
tail = tail[1:]
|
||||
|
||||
// Seek for identifier in children
|
||||
child, ok := n.children[id]
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Set obj if required
|
||||
if len(tail) == 0 {
|
||||
return child.value
|
||||
}
|
||||
|
||||
return child.read(tail)
|
||||
}
|
||||
|
||||
// CommunityNode is a node with an integer as key
|
||||
type CommunityNode struct {
|
||||
children map[int]*CommunityNode
|
||||
value api.Community
|
||||
}
|
||||
|
||||
// NewCommunityNode creates a new int tree node
|
||||
func NewCommunityNode(value []int) *CommunityNode {
|
||||
return &CommunityNode{
|
||||
children: map[int]*CommunityNode{},
|
||||
value: value,
|
||||
}
|
||||
}
|
||||
|
||||
// CommunityNode: traverse inserts a new node into the three if required
|
||||
// or returns the object if it already exists.
|
||||
func (n *CommunityNode) traverse(value api.Community, tail []int) api.Community {
|
||||
id := tail[0]
|
||||
tail = tail[1:]
|
||||
|
||||
// Seek for identifier in children
|
||||
child, ok := n.children[id]
|
||||
if !ok {
|
||||
child = NewCommunityNode(nil)
|
||||
n.children[id] = child
|
||||
}
|
||||
|
||||
// Set obj if required
|
||||
if len(tail) == 0 {
|
||||
if child.value == nil {
|
||||
child.value = value
|
||||
}
|
||||
return child.value
|
||||
}
|
||||
|
||||
return child.traverse(value, tail)
|
||||
}
|
||||
|
||||
// read returns the object if it exists or nil if not.
|
||||
func (n *CommunityNode) read(tail []int) api.Community {
|
||||
id := tail[0]
|
||||
tail = tail[1:]
|
||||
|
||||
// Seek for identifier in children
|
||||
child, ok := n.children[id]
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Set obj if required
|
||||
if len(tail) == 0 {
|
||||
return child.value
|
||||
}
|
||||
|
||||
return child.read(tail)
|
||||
}
|
||||
|
||||
// CommunityListNode is a node with an integer as key and
|
||||
// a list of integers as value.
|
||||
type CommunityListNode struct {
|
||||
children map[unsafe.Pointer]*CommunityListNode
|
||||
value []api.Community
|
||||
}
|
||||
|
||||
// NewCommunityListNode creates a new int tree node
|
||||
func NewCommunityListNode(value []api.Community) *CommunityListNode {
|
||||
return &CommunityListNode{
|
||||
children: map[unsafe.Pointer]*CommunityListNode{},
|
||||
value: value,
|
||||
}
|
||||
}
|
||||
|
||||
// CommunityList traverse inserts a new node into the three if required
|
||||
// or returns the object if it already exists.
|
||||
func (n *CommunityListNode) traverse(
|
||||
value []api.Community,
|
||||
tail []unsafe.Pointer,
|
||||
) []api.Community {
|
||||
id := tail[0]
|
||||
tail = tail[1:]
|
||||
|
||||
// Seek for identifier in children
|
||||
child, ok := n.children[id]
|
||||
if !ok {
|
||||
child = NewCommunityListNode(nil)
|
||||
n.children[id] = child
|
||||
}
|
||||
|
||||
// Set obj if required
|
||||
if len(tail) == 0 {
|
||||
if child.value == nil {
|
||||
child.value = value
|
||||
}
|
||||
return child.value
|
||||
}
|
||||
|
||||
return child.traverse(value, tail)
|
||||
}
|
||||
|
||||
// read returns the object if it exists or nil if not.
|
||||
func (n *CommunityListNode) read(tail []unsafe.Pointer) []api.Community {
|
||||
id := tail[0]
|
||||
tail = tail[1:]
|
||||
|
||||
// Seek for identifier in children
|
||||
child, ok := n.children[id]
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Set obj if required
|
||||
if len(tail) == 0 {
|
||||
return child.value
|
||||
return child.value, child.gid
|
||||
}
|
||||
|
||||
return child.read(tail)
|
||||
|
Loading…
x
Reference in New Issue
Block a user