Update dependencies

This commit is contained in:
bluepython508
2025-04-09 01:00:12 +01:00
parent f0641ffd6e
commit 5a9cfc022c
882 changed files with 68930 additions and 24201 deletions

305
vendor/github.com/gaissmai/bart/overlaps.go generated vendored Normal file
View File

@@ -0,0 +1,305 @@
package bart
import (
"net/netip"
"github.com/gaissmai/bart/internal/bitset"
)
// overlaps returns true if any IP in the nodes n or o overlaps.
func (n *node[V]) overlaps(o *node[V], depth int) bool {
nPfxCount := n.prefixes.Len()
oPfxCount := o.prefixes.Len()
nChildCount := n.children.Len()
oChildCount := o.children.Len()
// ##############################
// 1. Test if any routes overlaps
// ##############################
// full cross check
if nPfxCount > 0 && oPfxCount > 0 {
if n.overlapsRoutes(o) {
return true
}
}
// ####################################
// 2. Test if routes overlaps any child
// ####################################
// swap nodes to help chance on its way,
// if the first call to expensive overlapsChildrenIn() is already true,
// if both orders are false it doesn't help either
if nChildCount > oChildCount {
n, o = o, n
nPfxCount = n.prefixes.Len()
oPfxCount = o.prefixes.Len()
nChildCount = n.children.Len()
oChildCount = o.children.Len()
}
if nPfxCount > 0 && oChildCount > 0 {
if n.overlapsChildrenIn(o) {
return true
}
}
// symmetric reverse
if oPfxCount > 0 && nChildCount > 0 {
if o.overlapsChildrenIn(n) {
return true
}
}
// ###########################################
// 3. childs with same octet in nodes n and o
// ###########################################
// stop condition, n or o have no childs
if nChildCount == 0 || oChildCount == 0 {
return false
}
// stop condition, no child with identical octet in n and o
if !n.children.IntersectsAny(o.children.BitSet) {
return false
}
return n.overlapsSameChildren(o, depth)
}
// overlapsRoutes, test if n overlaps o prefixes and vice versa
func (n *node[V]) overlapsRoutes(o *node[V]) bool {
// some prefixes are identical, trivial overlap
if n.prefixes.IntersectsAny(o.prefixes.BitSet) {
return true
}
// get the lowest idx (biggest prefix)
nFirstIdx, _ := n.prefixes.FirstSet()
oFirstIdx, _ := o.prefixes.FirstSet()
// start with other min value, see ART algo
nIdx := oFirstIdx
oIdx := nFirstIdx
// make full cross check
nOK := true
oOK := true
// zip, range over n and o together to help chance on its way
for nOK || oOK {
if nOK {
// does any route in o overlap this prefix from n
if nIdx, nOK = n.prefixes.NextSet(nIdx); nOK {
if o.lpmTest(nIdx) {
return true
}
nIdx++
}
}
if oOK {
// does any route in n overlap this prefix from o
if oIdx, oOK = o.prefixes.NextSet(oIdx); oOK {
if n.lpmTest(oIdx) {
return true
}
oIdx++
}
}
}
return false
}
// overlapsChildrenIn, test if prefixes in n overlaps child octets in o.
func (n *node[V]) overlapsChildrenIn(o *node[V]) bool {
pfxCount := n.prefixes.Len()
childCount := o.children.Len()
// heuristic, compare benchmarks
// when will we range over the children and when will we do bitset calc?
magicNumber := 15
doRange := childCount < magicNumber || pfxCount > magicNumber
// do range over, not so many childs and maybe to many prefixes for other algo below
if doRange {
lowerBound, _ := n.prefixes.FirstSet()
for _, addr := range o.children.AsSlice(make([]uint, 0, maxNodeChildren)) {
idx := hostIndex(addr)
if idx < lowerBound { // lpm match impossible
continue
}
if n.lpmTest(idx) {
return true
}
}
return false
}
// do bitset intersection, alloted route table with child octets
// maybe to many childs for range over or not so many prefixes to
// build the alloted routing table from them
// make allot table with prefixes as bitsets, bitsets are precalculated
// just union the bitsets to one bitset (allot table) for all prefixes
// in this node
prefixRoutes := bitset.BitSet(make([]uint64, 8))
allIndices := n.prefixes.AsSlice(make([]uint, 0, maxNodePrefixes))
for _, idx := range allIndices {
// get pre alloted bitset for idx
prefixRoutes.InPlaceUnion(allotLookupTbl[idx])
}
// clone a bitset without heap allocation
// shift-right children bitset by 256 (firstHostIndex)
c8 := make([]uint64, 8)
copy(c8[4:], o.children.BitSet) // 4*64= 256
hostRoutes := bitset.BitSet(c8)
return prefixRoutes.IntersectsAny(hostRoutes)
}
// overlapsSameChildren, find same octets with bitset intersection.
func (n *node[V]) overlapsSameChildren(o *node[V], depth int) bool {
// clone a bitset without heap allocation
c4 := [4]uint64{}
copy(c4[:], n.children.BitSet)
nChildrenBitsetCloned := bitset.BitSet(c4[:])
// intersect in place the cloned child bitset from n with o
nChildrenBitsetCloned.InPlaceIntersection(o.children.BitSet)
allCommonChildren := nChildrenBitsetCloned.AsSlice(make([]uint, 0, maxNodeChildren))
// range over all child addrs, common in n and o
for _, addr := range allCommonChildren {
nChild := n.children.MustGet(addr)
oChild := o.children.MustGet(addr)
if overlapsTwoChilds[V](nChild, oChild, depth+1) {
return true
}
}
return false
}
// overlapsTwoChilds, childs can be node or leaf.
func overlapsTwoChilds[V any](nChild, oChild any, depth int) bool {
// 4 possible different combinations for n and o
//
// node, node --> overlapsRec
// node, leaf --> overlapsPrefixAtDepth
// leaf, node --> overlapsPrefixAtDepth
// leaf, leaf --> netip.Prefix.Overlaps
//
switch nKind := nChild.(type) {
case *node[V]:
switch oKind := oChild.(type) {
case *node[V]: // node, node
return nKind.overlaps(oKind, depth)
case *leaf[V]: // node, leaf
return nKind.overlapsPrefixAtDepth(oKind.prefix, depth)
}
case *leaf[V]:
switch oKind := oChild.(type) {
case *node[V]: // leaf, node
return oKind.overlapsPrefixAtDepth(nKind.prefix, depth)
case *leaf[V]: // leaf, leaf
return oKind.prefix.Overlaps(nKind.prefix)
}
default:
panic("logic error, wrong node type")
}
return false
}
// overlapsPrefixAtDepth, returns true if node overlaps with prefix
// starting with prefix octet at depth.
//
// Needed for path compressed prefix some level down in the node trie.
func (n *node[V]) overlapsPrefixAtDepth(pfx netip.Prefix, depth int) bool {
ip := pfx.Addr()
bits := pfx.Bits()
lastIdx, lastBits := lastOctetIdxAndBits(bits)
octets := ip.AsSlice()
octets = octets[:lastIdx+1]
for ; depth < len(octets); depth++ {
octet := octets[depth]
addr := uint(octet)
// full octet path in node trie, check overlap with last prefix octet
if depth == lastIdx {
return n.overlapsIdx(pfxToIdx(octet, lastBits))
}
// test if any route overlaps prefix´ so far
// no best match needed, forward tests without backtracking
if n.prefixes.Len() != 0 && n.lpmTest(hostIndex(addr)) {
return true
}
if !n.children.Test(addr) {
return false
}
// next child, node or leaf
switch kid := n.children.MustGet(addr).(type) {
case *node[V]:
n = kid
continue
case *leaf[V]:
return kid.prefix.Overlaps(pfx)
default:
panic("logic error, wrong node type")
}
}
panic("unreachable: " + pfx.String())
}
// overlapsIdx returns true if node overlaps with prefix.
func (n *node[V]) overlapsIdx(idx uint) bool {
// 1. Test if any route in this node overlaps prefix?
if n.lpmTest(idx) {
return true
}
// 2. Test if prefix overlaps any route in this node
// use bitset intersections instead of range loops
// shallow copy pre alloted bitset for idx
allotedPrefixRoutes := allotLookupTbl[idx]
if allotedPrefixRoutes.IntersectsAny(n.prefixes.BitSet) {
return true
}
// 3. Test if prefix overlaps any child in this node
// shift-right children bitset by 256 (firstHostIndex)
c8 := [8]uint64{}
copy(c8[4:], n.children.BitSet) // 4*64= 256
hostRoutes := bitset.BitSet(c8[:])
// use bitsets intersection instead of range loops
return allotedPrefixRoutes.IntersectsAny(hostRoutes)
}