Skip to content

Commit

Permalink
API change
Browse files Browse the repository at this point in the history
  • Loading branch information
gaissmai committed Dec 27, 2023
1 parent 9d830a4 commit 896666a
Show file tree
Hide file tree
Showing 6 changed files with 116 additions and 142 deletions.
33 changes: 15 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,30 +21,27 @@ but explicit for CIDRs. It has a narrow focus with a specialized API for IP rout
```go
import "github.com/gaissmai/cidrtree"

type Route struct{
CIDR netip.Prefix // route
Value any // payload, e.g. next hop(s)
}
type Table struct { // Has unexported fields. }
Table is an IPv4 and IPv6 routing table. The zero value is ready to use.

type Tree struct{ /* has unexported fields */ }
func New() *Table

func New(routes ...Route) Tree
func NewConcurrent(jobs int, routes ...Route) Tree
func (t Table) LookupIP(key netip.Addr) (cidr netip.Prefix, value any, ok bool)
func (t Table) LookupCIDR(key netip.Prefix) (cidr netip.Prefix, value any, ok bool)

func (t Tree) LookupIP(key netip.Addr) (cidr netip.Prefix, value any, ok bool)
func (t Tree) LookupCIDR(key netip.Prefix) (cidr netip.Prefix, value any, ok bool)
func (t Table) Insert(pfx netip.Prefix, val any) *Table
func (t *Table) InsertMutable(pfx netip.Prefix, val any)

func (t Tree) Insert(routes ...Route) Tree
func (t *Tree) InsertMutable(routes ...Route)
func (t Table) Delete(cidr netip.Prefix) (*Table, bool)
func (t *Table) DeleteMutable(cidr netip.Prefix) bool

func (t Tree) Delete(cidr netip.Prefix) (Tree, bool)
func (t *Tree) DeleteMutable(cidr netip.Prefix) bool
func (t Table) Clone() *Table

func (t Tree) Clone() Tree
func (t Tree) Union(other Tree, immutable bool) Tree
func (t Table) Union(other *Table) *Table
func (t *Table) UnionMutable(other *Table)

func (t Tree) String() string
func (t Tree) Fprint(w io.Writer) error
func (t Table) String() string
func (t Table) Fprint(w io.Writer) error

func (t Tree) Walk(cb func(r Route) bool)
func (t *Table) Walk(cb func(pfx netip.Prefix, val any) bool)
```
37 changes: 9 additions & 28 deletions bench_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package cidrtree_test
import (
"bufio"
"compress/gzip"
"encoding/binary"
"log"
"math/rand"
"net/netip"
Expand Down Expand Up @@ -70,27 +69,9 @@ func cloneAndShuffleRoutes(n int) []netip.Prefix {
return clone[:n]
}

func randomIP4() netip.Addr {
buf := make([]byte, 4)
u1 := rand.Uint32()
binary.LittleEndian.PutUint32(buf, u1)
ip, _ := netip.AddrFromSlice(buf)
return ip
}

func randomIP6() netip.Addr {
buf := make([]byte, 16)
u1 := rand.Uint64()
u2 := rand.Uint64()
binary.LittleEndian.PutUint64(buf[:8], u1)
binary.LittleEndian.PutUint64(buf[8:], u2)
ip, _ := netip.AddrFromSlice(buf)
return ip
}

func BenchmarkLookupIP(b *testing.B) {
for k := 1; k <= 1_000_000; k *= 10 {
rt := cidrtree.New[any]()
rt := cidrtree.New()
cidrs := cloneAndShuffleRoutes(k)
for _, cidr := range cidrs {
rt.InsertMutable(cidr, nil)
Expand All @@ -110,7 +91,7 @@ func BenchmarkLookupIP(b *testing.B) {

func BenchmarkLookupCIDR(b *testing.B) {
for k := 1; k <= 1_000_000; k *= 10 {
rt := cidrtree.New[any]()
rt := cidrtree.New()
cidrs := cloneAndShuffleRoutes(k)
for _, cidr := range cidrs {
rt.InsertMutable(cidr, nil)
Expand All @@ -132,7 +113,7 @@ func BenchmarkNew(b *testing.B) {
cidrs := cloneAndShuffleRoutes(k)
b.Run(intMap[k], func(b *testing.B) {
for n := 0; n < b.N; n++ {
rt := cidrtree.New[*netip.Addr]()
rt := cidrtree.New()
for i := range cidrs {
rt = rt.Insert(cidrs[i], nil)
}
Expand All @@ -143,7 +124,7 @@ func BenchmarkNew(b *testing.B) {

func BenchmarkClone(b *testing.B) {
for k := 1; k <= 1_000_000; k *= 10 {
rt := cidrtree.New[any]()
rt := cidrtree.New()
for _, cidr := range cloneAndShuffleRoutes(k) {
rt = rt.Insert(cidr, nil)
}
Expand All @@ -159,7 +140,7 @@ func BenchmarkClone(b *testing.B) {

func BenchmarkInsert(b *testing.B) {
for k := 1; k <= 1_000_000; k *= 10 {
rt := cidrtree.New[byte]()
rt := cidrtree.New()
cidrs := cloneAndShuffleRoutes(k)
for _, cidr := range cidrs {
rt = rt.Insert(cidr, 0)
Expand All @@ -177,7 +158,7 @@ func BenchmarkInsert(b *testing.B) {

func BenchmarkInsertMutable(b *testing.B) {
for k := 1; k <= 1_000_000; k *= 10 {
rt := cidrtree.New[byte]()
rt := cidrtree.New()
cidrs := cloneAndShuffleRoutes(k)
for _, cidr := range cidrs {
rt = rt.Insert(cidr, 0)
Expand All @@ -195,7 +176,7 @@ func BenchmarkInsertMutable(b *testing.B) {

func BenchmarkDelete(b *testing.B) {
for k := 1; k <= 1_000_000; k *= 10 {
rt := cidrtree.New[any]()
rt := cidrtree.New()
cidrs := cloneAndShuffleRoutes(k)
for _, cidr := range cidrs {
rt = rt.Insert(cidr, nil)
Expand All @@ -214,7 +195,7 @@ func BenchmarkDelete(b *testing.B) {

func BenchmarkMutableDelete(b *testing.B) {
for k := 1; k <= 1_000_000; k *= 10 {
rt := cidrtree.New[any]()
rt := cidrtree.New()
cidrs := cloneAndShuffleRoutes(k)
for _, cidr := range cidrs {
rt = rt.Insert(cidr, nil)
Expand All @@ -233,7 +214,7 @@ func BenchmarkMutableDelete(b *testing.B) {

func BenchmarkWalk(b *testing.B) {
for k := 1; k <= 1_000_000; k *= 10 {
rt := cidrtree.New[any]()
rt := cidrtree.New()
cidrs := cloneAndShuffleRoutes(k)
for _, cidr := range cidrs {
rt.InsertMutable(cidr, nil)
Expand Down
8 changes: 4 additions & 4 deletions example_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ var input = []netip.Prefix{
netip.MustParsePrefix("192.168.1.0/24"),
}

func ExampleTree_Fprint() {
rtbl := cidrtree.New[any]()
func ExampleTable_Fprint() {
rtbl := cidrtree.New()
for _, cidr := range input {
rtbl.InsertMutable(cidr, nil)
}
Expand All @@ -51,13 +51,13 @@ func ExampleTree_Fprint() {
// └─ fe80::/10 (<nil>)
}

func ExampleTree_Walk() {
func ExampleTable_Walk() {
cb := func(p netip.Prefix, val any) bool {
fmt.Printf("%v (%v)\n", p, val)
return true
}

rtbl := cidrtree.New[any]()
rtbl := cidrtree.New()
for _, cidr := range input {
rtbl.InsertMutable(cidr, nil)
}
Expand Down
24 changes: 12 additions & 12 deletions stringify.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (
)

// String returns a hierarchical tree diagram of the ordered CIDRs as string, just a wrapper for [Tree.Fprint].
func (t Table[T]) String() string {
func (t Table) String() string {
w := new(strings.Builder)
_ = t.Fprint(w)
return w.String()
Expand All @@ -17,7 +17,7 @@ func (t Table[T]) String() string {
//
// The order from top to bottom is in ascending order of the start address
// and the subtree structure is determined by the CIDRs coverage.
func (t Table[T]) Fprint(w io.Writer) error {
func (t Table) Fprint(w io.Writer) error {
if err := t.root4.fprint(w); err != nil {
return err
}
Expand All @@ -27,16 +27,16 @@ func (t Table[T]) Fprint(w io.Writer) error {
return nil
}

func (n *node[T]) fprint(w io.Writer) error {
func (n *node) fprint(w io.Writer) error {
if n == nil {
return nil
}

// pcm = parent-child-mapping
var pcm parentChildsMap[T]
var pcm parentChildsMap

// init map
pcm.pcMap = make(map[*node[T]][]*node[T])
pcm.pcMap = make(map[*node][]*node)

pcm = n.buildParentChildsMap(pcm)

Expand All @@ -50,11 +50,11 @@ func (n *node[T]) fprint(w io.Writer) error {
}

// start recursion with root and empty padding
var root *node[T]
var root *node
return root.walkAndStringify(w, pcm, "")
}

func (n *node[T]) walkAndStringify(w io.Writer, pcm parentChildsMap[T], pad string) error {
func (n *node) walkAndStringify(w io.Writer, pcm parentChildsMap, pad string) error {
// the prefix (pad + glyphe) is already printed on the line on upper level
if n != nil {
if _, err := fmt.Fprintf(w, "%v (%v)\n", n.cidr, n.value); err != nil {
Expand Down Expand Up @@ -92,13 +92,13 @@ func (n *node[T]) walkAndStringify(w io.Writer, pcm parentChildsMap[T], pad stri
// parentChildsMap, needed for hierarchical tree printing, this is not BST printing!
//
// CIDR tree, parent->childs relation printed. A parent CIDR covers a child CIDR.
type parentChildsMap[T any] struct {
pcMap map[*node[T]][]*node[T] // parent -> []child map
stack []*node[T] // just needed for the algo
type parentChildsMap struct {
pcMap map[*node][]*node // parent -> []child map
stack []*node // just needed for the algo
}

// buildParentChildsMap, in-order traversal
func (n *node[T]) buildParentChildsMap(pcm parentChildsMap[T]) parentChildsMap[T] {
func (n *node) buildParentChildsMap(pcm parentChildsMap) parentChildsMap {
if n == nil {
return pcm
}
Expand All @@ -114,7 +114,7 @@ func (n *node[T]) buildParentChildsMap(pcm parentChildsMap[T]) parentChildsMap[T
}

// pcmForNode, find parent in stack, remove cidrs from stack, put this cidr on stack.
func (n *node[T]) pcmForNode(pcm parentChildsMap[T]) parentChildsMap[T] {
func (n *node) pcmForNode(pcm parentChildsMap) parentChildsMap {
// if this cidr is covered by a prev cidr on stack
for j := len(pcm.stack) - 1; j >= 0; j-- {
that := pcm.stack[j]
Expand Down
Loading

0 comments on commit 896666a

Please sign in to comment.