Skip to content

Commit

Permalink
now with path compression
Browse files Browse the repository at this point in the history
  • Loading branch information
gaissmai committed Jan 3, 2025
1 parent e4cfdc8 commit 2c1de7c
Show file tree
Hide file tree
Showing 27 changed files with 1,191 additions and 3,950 deletions.
115 changes: 69 additions & 46 deletions dumper.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,17 @@ func (t *Table[V]) dump(w io.Writer) {
return
}

fmt.Fprintf(w, "### IPv4: size(%d)", t.Size4())
t.root4.dumpRec(w, zeroPath, 0, true)
if t.Size4() > 0 {
fmt.Fprintln(w)
fmt.Fprintf(w, "### IPv4: size(%d), nodes(%d)", t.Size4(), t.nodes4())
t.root4.dumpRec(w, zeroPath, 0, true)
}

fmt.Fprintf(w, "### IPv6: size(%d)", t.Size6())
t.root6.dumpRec(w, zeroPath, 0, false)
if t.Size6() > 0 {
fmt.Fprintln(w)
fmt.Fprintf(w, "### IPv6: size(%d), nodes(%d)", t.Size6(), t.nodes6())
t.root6.dumpRec(w, zeroPath, 0, false)
}
}

// dumpRec, rec-descent the trie.
Expand All @@ -55,10 +61,13 @@ func (n *node[V]) dumpRec(w io.Writer, path [16]byte, depth int, is4 bool) {
// the node may have childs, the rec-descent monster starts
for i, addr := range allChildAddrs {
octet := byte(addr)
child := n.children.Items[i]
path[depth] = octet

child.dumpRec(w, path, depth+1, is4)
switch child := n.children.Items[i].(type) {
case *leaf[V]:
continue
case *node[V]:
child.dumpRec(w, path, depth+1, is4)
}
}
}

Expand Down Expand Up @@ -98,34 +107,68 @@ func (n *node[V]) dump(w io.Writer, path [16]byte, depth int, is4 bool) {
fmt.Fprintln(w)
}

if childCount := n.children.Len(); childCount != 0 {
// print the childs for this node
fmt.Fprintf(w, "%schilds(#%d):", indent, childCount)
if n.children.Len() != 0 {

// no heap allocs
allChildAddrs := n.children.AsSlice(make([]uint, 0, maxNodeChildren))
nodeAddrs := make([]uint, 0, maxNodeChildren)
leafAddrs := make([]uint, 0, maxNodeChildren)

for _, addr := range allChildAddrs {
octet := byte(addr)
fmt.Fprintf(w, " %s", octetFmt(octet, is4))
// the node has recursive child nodes or path-compressed leaves
for i, addr := range n.children.AsSlice(make([]uint, 0, maxNodeChildren)) {
switch n.children.Items[i].(type) {
case *node[V]:
nodeAddrs = append(nodeAddrs, addr)
continue
case *leaf[V]:
leafAddrs = append(leafAddrs, addr)
}
}

fmt.Fprintln(w)
}
if nodeCount := len(nodeAddrs); nodeCount > 0 {
// print the childs for this node
fmt.Fprintf(w, "%schilds(#%d):", indent, nodeCount)

for _, addr := range nodeAddrs {
octet := byte(addr)
fmt.Fprintf(w, " %s", octetFmt(octet, is4))
}

if pathcompCount := n.pathcomp.Len(); pathcompCount != 0 {
// print the pathcomp prefixes for this node
fmt.Fprintf(w, "%spathcp(#%d):", indent, pathcompCount)
fmt.Fprintln(w)
}

// no heap allocs
allPathComps := n.pathcomp.AsSlice(make([]uint, 0, maxNodeChildren))
if leafCount := len(leafAddrs); leafCount > 0 {
// print the pathcomp prefixes for this node
fmt.Fprintf(w, "%sleaves(#%d):", indent, leafCount)

for i, addr := range allPathComps {
pc := n.pathcomp.Items[i]
fmt.Fprintf(w, " %d:[%s, %v]", addr, pc.prefix, pc.value)
for _, addr := range leafAddrs {
octet := byte(addr)
k := n.children.MustGet(addr)
pc := k.(*leaf[V])

fmt.Fprintf(w, " %s:{%s, %v}", octetFmt(octet, is4), pc.prefix, pc.value)
}
fmt.Fprintln(w)
}
}
}

fmt.Fprintln(w)
// hasType returns the nodeType.
func (n *node[V]) hasType() nodeType {
prefixCount := n.prefixes.Len()
childCount := n.children.Len()
nodeCount, leafCount := n.nodeAndLeafCount()

switch {
case prefixCount == 0 && childCount == 0:
return nullNode
case nodeCount == 0:
return leafNode
case (prefixCount > 0 || leafCount > 0) && nodeCount > 0:
return fullNode
case (prefixCount == 0 && leafCount == 0) && nodeCount > 0:
return intermediateNode
default:
panic(fmt.Sprintf("UNREACHABLE: pfx: %d, chld: %d, node: %d, leaf: %d",
prefixCount, childCount, nodeCount, leafCount))
}
}

Expand Down Expand Up @@ -183,23 +226,3 @@ func (nt nodeType) String() string {
return "unreachable"
}
}

// hasType returns the nodeType.
func (n *node[V]) hasType() nodeType {
prefixCount := n.prefixes.Len()
childCount := n.children.Len()
pathcompCount := n.pathcomp.Len()

switch {
case prefixCount == 0 && childCount == 0 && pathcompCount == 0:
return nullNode
case prefixCount != 0 && childCount != 0:
return fullNode
case prefixCount == 0 && pathcompCount == 0 && childCount != 0:
return intermediateNode
case childCount == 0:
return leafNode
default:
panic(fmt.Sprintf("UNREACHABLE: pfx: %d, chld: %d, pc: %d", prefixCount, childCount, pathcompCount))
}
}
162 changes: 0 additions & 162 deletions dumper2.go

This file was deleted.

16 changes: 8 additions & 8 deletions dumper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,14 @@ func TestDumperPanic(t *testing.T) {
}
}()

tbl := new(Table2[any])
tbl := new(Table[any])
tbl.Insert(mpp("1.2.3.4/32"), nil)
tbl.dump(nil)
}

func TestDumperEmpty(t *testing.T) {
t.Parallel()
tbl := new(Table2[any])
tbl := new(Table[any])
checkDump(t, tbl, dumpTest{
cidrs: nil,
want: "",
Expand All @@ -38,7 +38,7 @@ func TestDumperEmpty(t *testing.T) {

func TestDumpDefaultRouteV4(t *testing.T) {
t.Parallel()
tbl := new(Table2[any])
tbl := new(Table[any])
checkDump(t, tbl, dumpTest{
cidrs: []netip.Prefix{
mpp("0.0.0.0/0"),
Expand All @@ -55,7 +55,7 @@ values(#1): <nil>

func TestDumpDefaultRouteV6(t *testing.T) {
t.Parallel()
tbl := new(Table2[any])
tbl := new(Table[any])
checkDump(t, tbl, dumpTest{
cidrs: []netip.Prefix{
mpp("::/0"),
Expand All @@ -72,7 +72,7 @@ values(#1): <nil>

func TestDumpSampleV4(t *testing.T) {
t.Parallel()
tbl := new(Table2[any])
tbl := new(Table[any])

checkDump(t, tbl, dumpTest{
cidrs: []netip.Prefix{
Expand Down Expand Up @@ -114,7 +114,7 @@ leaves(#3): 127:{127.0.0.1/32, <nil>} 169:{169.254.0.0/16, <nil>} 172:{172.16.0.

func TestDumpSampleV6(t *testing.T) {
t.Parallel()
tbl := new(Table2[any])
tbl := new(Table[any])
checkDump(t, tbl, dumpTest{
cidrs: []netip.Prefix{
mpp("fe80::/10"),
Expand All @@ -134,7 +134,7 @@ leaves(#2): 0x20:{2001:db8::/32, <nil>} 0xfe:{fe80::/10, <nil>}

func TestDumpSample(t *testing.T) {
t.Parallel()
tbl := new(Table2[any])
tbl := new(Table[any])

checkDump(t, tbl, dumpTest{
cidrs: []netip.Prefix{
Expand Down Expand Up @@ -185,7 +185,7 @@ leaves(#2): 0x20:{2001:db8::/32, <nil>} 0xfe:{fe80::/10, <nil>}
})
}

func checkDump(t *testing.T, tbl *Table2[any], tt dumpTest) {
func checkDump(t *testing.T, tbl *Table[any], tt dumpTest) {
t.Helper()
for _, cidr := range tt.cidrs {
tbl.Insert(cidr, nil)
Expand Down
Loading

0 comments on commit 2c1de7c

Please sign in to comment.