Skip to content

Commit

Permalink
API change, All* returns an iterator
Browse files Browse the repository at this point in the history
The All* methods return an iterator instead of being an iterator.
  • Loading branch information
gaissmai committed Jul 23, 2024
1 parent da4d1a7 commit 1f053cc
Show file tree
Hide file tree
Showing 7 changed files with 68 additions and 71 deletions.
28 changes: 14 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ The child array at each stride level is also popcount compressed.

## API

The API changes in v0.4.2, 0.5.3, v0.6.3, v0.10.1, v0.11.0
The API changes in v0.4.2, 0.5.3, v0.6.3, v0.10.1, v0.11.0, v0.12.0

```golang
import "github.com/gaissmai/bart"
Expand All @@ -59,26 +59,26 @@ The API changes in v0.4.2, 0.5.3, v0.6.3, v0.10.1, v0.11.0
func (t *Table[V]) LookupPrefix(pfx netip.Prefix) (val V, ok bool)
func (t *Table[V]) LookupPrefixLPM(pfx netip.Prefix) (lpm netip.Prefix, val V, ok bool)

func (t *Table[V]) Subnets(pfx netip.Prefix) func(yield func(netip.Prefix, V) bool)
func (t *Table[V]) Supernets(pfx netip.Prefix) func(yield func(netip.Prefix, V) bool)

func (t *Table[V]) OverlapsPrefix(pfx netip.Prefix) bool

func (t *Table[V]) Overlaps(o *Table[V]) bool
func (t *Table[V]) Overlaps(o *Table[V]) bool
func (t *Table[V]) Overlaps4(o *Table[V]) bool
func (t *Table[V]) Overlaps6(o *Table[V]) bool

func (t *Table[V]) Size() int
func (t *Table[V]) Size4() int
func (t *Table[V]) Size6() int
func (t *Table[V]) Supernets(pfx netip.Prefix) func(yield func(netip.Prefix, V) bool)
func (t *Table[V]) Subnets(pfx netip.Prefix) func(yield func(netip.Prefix, V) bool)

func (t *Table[V]) All() func(yield func(pfx netip.Prefix, val V) bool)
func (t *Table[V]) All4() func(yield func(pfx netip.Prefix, val V) bool)
func (t *Table[V]) All6() func(yield func(pfx netip.Prefix, val V) bool)

func (t *Table[V]) All(yield func(pfx netip.Prefix, val V) bool)
func (t *Table[V]) All4(yield func(pfx netip.Prefix, val V) bool)
func (t *Table[V]) All6(yield func(pfx netip.Prefix, val V) bool)
func (t *Table[V]) AllSorted() func(yield func(pfx netip.Prefix, val V) bool)
func (t *Table[V]) All4Sorted() func(yield func(pfx netip.Prefix, val V) bool)
func (t *Table[V]) All6Sorted() func(yield func(pfx netip.Prefix, val V) bool)

func (t *Table[V]) AllSorted(yield func(pfx netip.Prefix, val V) bool)
func (t *Table[V]) All4Sorted(yield func(pfx netip.Prefix, val V) bool)
func (t *Table[V]) All6Sorted(yield func(pfx netip.Prefix, val V) bool)
func (t *Table[V]) Size() int
func (t *Table[V]) Size4() int
func (t *Table[V]) Size6() int

func (t *Table[V]) String() string
func (t *Table[V]) Fprint(w io.Writer) error
Expand Down
2 changes: 1 addition & 1 deletion example_iter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ func ExampleTable_All4_rangeoverfunc() {
rtbl.Insert(item.cidr, item.nextHop)
}

for pfx, val := range rtbl.All4Sorted {
for pfx, val := range rtbl.All4Sorted() {
fmt.Printf("%v\t%v\n", pfx, val)
}

Expand Down
2 changes: 1 addition & 1 deletion example_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ func ExampleTable_All4_callback() {
for _, item := range input {
rtbl.Insert(item.cidr, item.nextHop)
}
rtbl.All4Sorted(func(pfx netip.Prefix, val netip.Addr) bool {
rtbl.All4Sorted()(func(pfx netip.Prefix, val netip.Addr) bool {
fmt.Printf("%v\t%v\n", pfx, val)
return true
})
Expand Down
18 changes: 9 additions & 9 deletions table_cb_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ func TestAll(t *testing.T) {
}

// check if pfx/val is as expected
rtbl.All(func(pfx netip.Prefix, val int) bool {
rtbl.All()(func(pfx netip.Prefix, val int) bool {
if seen[pfx] != val {
t.Errorf("%v got value: %v, expected: %v", pfx, val, seen[pfx])
}
Expand All @@ -180,15 +180,15 @@ func TestAll(t *testing.T) {
}

// check if pfx/val is as expected
rtbl.All4(func(pfx netip.Prefix, val int) bool {
rtbl.All4()(func(pfx netip.Prefix, val int) bool {
if seen[pfx] != val {
t.Errorf("%v got value: %v, expected: %v", pfx, val, seen[pfx])
}
delete(seen, pfx)
return true
})

rtbl.All6(func(pfx netip.Prefix, val int) bool {
rtbl.All6()(func(pfx netip.Prefix, val int) bool {
if seen[pfx] != val {
t.Errorf("%v got value: %v, expected: %v", pfx, val, seen[pfx])
}
Expand Down Expand Up @@ -222,10 +222,10 @@ func TestAll(t *testing.T) {
}

// iterate and update the values
rtbl.All(yield)
rtbl.All()(yield)

// test if all values got updated, yield now as closure
rtbl.All(func(pfx netip.Prefix, val int) bool {
rtbl.All()(func(pfx netip.Prefix, val int) bool {
if seen[pfx] != val {
t.Errorf("%v got value: %v, expected: %v", pfx, val, seen[pfx])
}
Expand All @@ -241,7 +241,7 @@ func TestAll(t *testing.T) {

// check if callback stops prematurely
countV6 := 0
rtbl.All(func(pfx netip.Prefix, val int) bool {
rtbl.All()(func(pfx netip.Prefix, val int) bool {
// max 1000 IPv6 prefixes
if !pfx.Addr().Is4() {
countV6++
Expand Down Expand Up @@ -279,7 +279,7 @@ func TestAllSorted(t *testing.T) {

slices.SortFunc(expect, cmpPrefix)

rtbl.AllSorted(func(pfx netip.Prefix, _ int) bool {
rtbl.AllSorted()(func(pfx netip.Prefix, _ int) bool {
got = append(got, pfx)
return true
})
Expand All @@ -301,7 +301,7 @@ func BenchmarkAll(b *testing.B) {
b.Run("All", func(b *testing.B) {
b.ResetTimer()
for i := 0; i < b.N; i++ {
rtbl.All(func(pfx netip.Prefix, _ int) bool {
rtbl.All()(func(pfx netip.Prefix, _ int) bool {
return true
})
}
Expand All @@ -310,7 +310,7 @@ func BenchmarkAll(b *testing.B) {
b.Run("AllSorted", func(b *testing.B) {
b.ResetTimer()
for i := 0; i < b.N; i++ {
rtbl.AllSorted(func(pfx netip.Prefix, _ int) bool {
rtbl.AllSorted()(func(pfx netip.Prefix, _ int) bool {
return true
})
}
Expand Down
59 changes: 28 additions & 31 deletions table_iter.go
Original file line number Diff line number Diff line change
Expand Up @@ -146,55 +146,52 @@ func (t *Table[V]) Subnets(pfx netip.Prefix) func(yield func(netip.Prefix, V) bo
}
}

// All may be used in a for/range loop to iterate
// through all the prefixes.
// The sort order is undefined and you must not rely on it!
//
// Prefixes must not be inserted or deleted during iteration, otherwise
// the behavior is undefined. However, value updates are permitted.
//
// If the yield function returns false, the iteration ends prematurely.
func (t *Table[V]) All(yield func(pfx netip.Prefix, val V) bool) {
// All returns an iterator over key-value pairs from Table. The iteration order
// is not specified and is not guaranteed to be the same from one call to the
// next.
func (t *Table[V]) All() func(yield func(pfx netip.Prefix, val V) bool) {
t.init()
// respect early exit
_ = t.rootV4.allRec(zeroPath, 0, true, yield) &&
t.rootV6.allRec(zeroPath, 0, false, yield)
return func(yield func(netip.Prefix, V) bool) {
_ = t.rootV4.allRec(zeroPath, 0, true, yield) && t.rootV6.allRec(zeroPath, 0, false, yield)
}
}

// All4, like [Table.All] but only for the v4 routing table.
func (t *Table[V]) All4(yield func(pfx netip.Prefix, val V) bool) {
func (t *Table[V]) All4() func(yield func(pfx netip.Prefix, val V) bool) {
t.init()
t.rootV4.allRec(zeroPath, 0, true, yield)
return func(yield func(netip.Prefix, V) bool) {
_ = t.rootV4.allRec(zeroPath, 0, true, yield)
}
}

// All6, like [Table.All] but only for the v6 routing table.
func (t *Table[V]) All6(yield func(pfx netip.Prefix, val V) bool) {
func (t *Table[V]) All6() func(yield func(pfx netip.Prefix, val V) bool) {
t.init()
t.rootV6.allRec(zeroPath, 0, false, yield)
return func(yield func(netip.Prefix, V) bool) {
_ = t.rootV6.allRec(zeroPath, 0, false, yield)
}
}

// AllSorted may be used in a for/range loop to iterate
// through all the prefixes in natural CIDR sort order.
//
// Prefixes must not be inserted or deleted during iteration, otherwise
// the behavior is undefined. However, value updates are permitted.
//
// If the yield function returns false, the iteration ends prematurely.
func (t *Table[V]) AllSorted(yield func(pfx netip.Prefix, val V) bool) {
// AllSorted returns an iterator over key-value pairs from Table in natural CIDR sort order.
func (t *Table[V]) AllSorted() func(yield func(pfx netip.Prefix, val V) bool) {
t.init()
// respect early exit
_ = t.rootV4.allRecSorted(zeroPath, 0, true, yield) &&
t.rootV6.allRecSorted(zeroPath, 0, false, yield)
return func(yield func(netip.Prefix, V) bool) {
_ = t.rootV4.allRecSorted(zeroPath, 0, true, yield) && t.rootV6.allRecSorted(zeroPath, 0, false, yield)
}
}

// All4Sorted, like [Table.AllSorted] but only for the v4 routing table.
func (t *Table[V]) All4Sorted(yield func(pfx netip.Prefix, val V) bool) {
func (t *Table[V]) All4Sorted() func(yield func(pfx netip.Prefix, val V) bool) {
t.init()
t.rootV4.allRecSorted(zeroPath, 0, true, yield)
return func(yield func(netip.Prefix, V) bool) {
_ = t.rootV4.allRecSorted(zeroPath, 0, true, yield)
}
}

// All6Sorted, like [Table.AllSorted] but only for the v6 routing table.
func (t *Table[V]) All6Sorted(yield func(pfx netip.Prefix, val V) bool) {
func (t *Table[V]) All6Sorted() func(yield func(pfx netip.Prefix, val V) bool) {
t.init()
t.rootV6.allRecSorted(zeroPath, 0, false, yield)
return func(yield func(netip.Prefix, V) bool) {
_ = t.rootV6.allRecSorted(zeroPath, 0, false, yield)
}
}
24 changes: 12 additions & 12 deletions table_iter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ func TestAll4RangeOverFunc(t *testing.T) {
}

// rangefunc iterator
for pfx, val := range rtbl.All4 {
for pfx, val := range rtbl.All4() {
// check if pfx/val is as expected
if seen[pfx] != val {
t.Errorf("%v got value: %v, expected: %v", pfx, val, seen[pfx])
Expand All @@ -45,7 +45,7 @@ func TestAll4RangeOverFunc(t *testing.T) {

// check if callback stops prematurely
count := 0
for _, _ = range rtbl.All4 {
for _, _ = range rtbl.All4() {
count++
if count >= 1000 {
break
Expand All @@ -71,7 +71,7 @@ func TestAll6RangeOverFunc(t *testing.T) {
}

// rangefunc iterator
for pfx, val := range rtbl.All6 {
for pfx, val := range rtbl.All6() {
// check if pfx/val is as expected
if seen[pfx] != val {
t.Errorf("%v got value: %v, expected: %v", pfx, val, seen[pfx])
Expand All @@ -93,7 +93,7 @@ func TestAll6RangeOverFunc(t *testing.T) {

// check if callback stops prematurely
count := 0
for _, _ = range rtbl.All6 {
for _, _ = range rtbl.All6() {
count++
if count >= 1000 {
break
Expand All @@ -119,7 +119,7 @@ func TestAllRangeOverFunc(t *testing.T) {
}

// rangefunc iterator
for pfx, val := range rtbl.All {
for pfx, val := range rtbl.All() {
// check if pfx/val is as expected
if seen[pfx] != val {
t.Errorf("%v got value: %v, expected: %v", pfx, val, seen[pfx])
Expand All @@ -141,7 +141,7 @@ func TestAllRangeOverFunc(t *testing.T) {

// check if callback stops prematurely
count := 0
for _, _ = range rtbl.All {
for _, _ = range rtbl.All() {
count++
if count >= 1000 {
break
Expand All @@ -167,7 +167,7 @@ func TestAll4SortedIter(t *testing.T) {
}

// rangefunc iterator
for pfx, val := range rtbl.All4Sorted {
for pfx, val := range rtbl.All4Sorted() {
// check if pfx/val is as expected
if seen[pfx] != val {
t.Errorf("%v got value: %v, expected: %v", pfx, val, seen[pfx])
Expand All @@ -189,7 +189,7 @@ func TestAll4SortedIter(t *testing.T) {

// check if callback stops prematurely
count := 0
for _, _ = range rtbl.All4Sorted {
for _, _ = range rtbl.All4Sorted() {
count++
if count >= 1000 {
break
Expand All @@ -215,7 +215,7 @@ func TestAll6SortedRangeOverFunc(t *testing.T) {
}

// rangefunc iterator
for pfx, val := range rtbl.All6Sorted {
for pfx, val := range rtbl.All6Sorted() {
// check if pfx/val is as expected
if seen[pfx] != val {
t.Errorf("%v got value: %v, expected: %v", pfx, val, seen[pfx])
Expand All @@ -237,7 +237,7 @@ func TestAll6SortedRangeOverFunc(t *testing.T) {

// check if callback stops prematurely
count := 0
for _, _ = range rtbl.All6Sorted {
for _, _ = range rtbl.All6Sorted() {
count++
if count >= 1000 {
break
Expand All @@ -263,7 +263,7 @@ func TestAllSortedRangeOverFunc(t *testing.T) {
}

// rangefunc iterator
for pfx, val := range rtbl.AllSorted {
for pfx, val := range rtbl.AllSorted() {
// check if pfx/val is as expected
if seen[pfx] != val {
t.Errorf("%v got value: %v, expected: %v", pfx, val, seen[pfx])
Expand All @@ -285,7 +285,7 @@ func TestAllSortedRangeOverFunc(t *testing.T) {

// check if callback stops prematurely
count := 0
for _, _ = range rtbl.AllSorted {
for _, _ = range rtbl.AllSorted() {
count++
if count >= 1000 {
break
Expand Down
6 changes: 3 additions & 3 deletions table_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1628,12 +1628,12 @@ func TestSize(t *testing.T) {
var golden4 int
var golden6 int

rtbl.All4Sorted(func(netip.Prefix, any) bool {
rtbl.All4Sorted()(func(netip.Prefix, any) bool {
golden4++
return true
})

rtbl.All6Sorted(func(netip.Prefix, any) bool {
rtbl.All6Sorted()(func(netip.Prefix, any) bool {
golden6++
return true
})
Expand Down Expand Up @@ -1928,7 +1928,7 @@ func (t *Table[V]) dumpAsGoldTable() goldTable[V] {
t.init()
var tbl goldTable[V]

t.AllSorted(func(pfx netip.Prefix, val V) bool {
t.AllSorted()(func(pfx netip.Prefix, val V) bool {
tbl = append(tbl, goldTableItem[V]{pfx: pfx, val: val})
return true
})
Expand Down

0 comments on commit 1f053cc

Please sign in to comment.