Files
tsnet-proxy/vendor/github.com/gaissmai/bart/internal/allot/generate_allottbl.go
T
2026-10-22 12:27:19 +01:00

237 lines
7.3 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//go:build generate
//go:generate go run $GOFILE
// Copyright (c) 2026 Karl Gaissmaier
// SPDX-License-Identifier: MIT
// Package main generates lookup tables for route allocation in the BART routing table.
//
// This generator creates two precomputed lookup tables (PfxRoutesLookupTbl and
// FringeRoutesLookupTbl) that enable fast prefix coverage queries. Each table maps
// a base index (1..255) to a bitset containing all more specific indices covered
// by that prefix.
//
// The tables model a complete binary tree where:
// - Indices 1..255 represent prefixes up to /7
// - Indices 256..511 represent /8 prefixes (stored separately as "fringe")
package main
import (
"fmt"
"os"
"os/exec"
"strings"
"text/template"
"github.com/gaissmai/bart/internal/bitset"
)
var (
thisFname = os.Getenv("GOFILE")
outFname = "allotroutesgenerated.go"
)
var (
// prefixAllotTbl holds the bitsets for indices 1..255 (prefixes up to /7).
// For each index idx, the bitset contains all descendant indices in the
// range 1..255 that are covered by the prefix at idx.
prefixAllotTbl [256]bitset.BitSet256
// fringeAllotTbl holds the bitsets for indices 1..255, but tracks descendants
// in the range 256..511 (/8 prefixes). The bitset at index idx contains all
// /8 fringe indices (minus 256 offset) covered by the prefix at idx.
fringeAllotTbl [256]bitset.BitSet256
)
// data holds the template variables for code generation
var data struct {
File string
PrefixAllotTable string
FringeAllotTable string
}
// colored prefix for informational and error messages
const (
INFO = "\x1b[34mINFO:\x1b[0m"
DIE = "\x1b[31mERROR:\x1b[0m"
)
func main() {
outFile, err := os.Create(outFname)
if err != nil {
fmt.Fprintf(os.Stderr, "%s %v\n", DIE, err)
os.Exit(1)
}
// Generate both lookup tables using the stack-based algorithm
prefixAllotTbl, fringeAllotTbl = genAllotTables()
// Populate template data
data.File = thisFname
data.PrefixAllotTable = asString(prefixAllotTbl)
data.FringeAllotTable = asString(fringeAllotTbl)
// Parse the template ...
t := template.Must(template.New("foo").Parse(codeTemplate))
// ... and execute it with our data
err = t.Execute(outFile, data)
if err != nil {
fmt.Fprintf(os.Stderr, "%s %v\n", DIE, err)
_ = outFile.Close()
os.Exit(1)
}
// Ensure the file is properly closed before formatting
if err := outFile.Close(); err != nil {
fmt.Fprintf(os.Stderr, "%s %v\n", DIE, err)
os.Exit(1)
}
fmt.Fprintf(os.Stdout, "%s ✓ Generated %s\n", INFO, outFname)
// Run goimports to organize imports and format the code
goimports := exec.Command("goimports", "-w", outFname)
fmt.Fprintf(os.Stdout, "%s Running goimports on %s\n", INFO, outFname)
if out, err := goimports.CombinedOutput(); err != nil {
fmt.Fprintf(os.Stderr, "%s %s\n", DIE, string(out))
os.Exit(1)
}
fmt.Fprintf(os.Stdout, "%s ✓ goimports completed\n", INFO)
// Run gofumpt for additional formatting consistency
gofumpt := exec.Command("gofumpt", "-w", outFname)
fmt.Fprintf(os.Stdout, "%s Running gofumpt on %s\n", INFO, outFname)
if out, err := gofumpt.CombinedOutput(); err != nil {
fmt.Fprintf(os.Stderr, "%s %s\n", DIE, string(out))
os.Exit(1)
}
fmt.Fprintf(os.Stdout, "%s ✓ gofumpt completed\n", INFO)
fmt.Println()
}
// genAllotTables generates both prefix and fringe allocation lookup tables.
//
// For each base index idx (1..255), it performs a breadth-first traversal of the
// complete binary tree rooted at idx, collecting all descendant indices. The
// traversal uses a stack-based approach instead of recursion.
//
// The algorithm:
// 1. Start with the root index idx in the stack
// 2. For each index j in the stack:
// - If j < 256: add j to prefixAllotTbl[idx]
// - If j >= 256: add (j-256) to fringeAllotTbl[idx]
// - If j < 256: push children (2*j and 2*j+1) onto the stack
// 3. Continue until the stack is exhausted
//
// This builds a complete binary tree where each node knows all its descendants,
// split into two ranges: [1..255] and [256..511].
//
// Returns the prefix table (indices 1..255) and fringe table (indices 256..511).
func genAllotTables() (prefix, fringe [256]bitset.BitSet256) {
prefixAllotTbl := [256]bitset.BitSet256{}
fringeAllotTbl := [256]bitset.BitSet256{}
for idx := 1; idx < 256; idx++ {
// allot algorithm, stack based instead of recursion
stack := make([]int, 0, 512)
stack = append(stack, idx)
for i := 0; i < len(stack); i++ {
j := stack[i]
if j < 256 {
prefixAllotTbl[idx].Set(uint8(j))
} else {
fringeAllotTbl[idx].Set(uint8(j - 256))
}
// max j is 511, so stop the duplication at 256 and above
if j >= 256 {
continue
}
// build a complete binary tree
// left: j*2
// right: (j*2)+1
stack = append(stack, j<<1, (j<<1)+1)
}
}
return prefixAllotTbl, fringeAllotTbl
}
// asString converts a lookup table to a formatted Go source string.
//
// Each entry in the table is formatted as:
//
// /* idx: N */ BitSet256{...}, // [list of set bits]
//
// For bitsets with 10 or more set bits, the list is truncated with "..." to
// keep the generated code readable. Index 0 is marked as "invalid" since no
// valid prefix maps to base index 0 in the BART structure.
//
// The returned string is ready to be embedded into the generated Go file.
func asString(tbl [256]bitset.BitSet256) string {
builder := strings.Builder{}
// Index 0 is invalid (no valid prefix maps to 0)
fmt.Fprintf(&builder, " /* idx: %3d */ %#v, // %s\n", 0, tbl[0], "invalid")
// Format each valid index with its bitset and the list of set bits, e.g.
// /* idx: 13 */ {0x204a, 0x0, 0x0, 0x0}, // [1 3 6 13]
for idx := 1; idx < 256; idx++ {
fmt.Fprintf(&builder, " /* idx: %3d */ %#v, // ", idx, tbl[idx])
bits := tbl[idx].Bits()
if len(bits) < 10 {
fmt.Fprintf(&builder, "%v\n", bits)
} else {
fmt.Fprint(&builder, "[")
for _, bit := range bits[:5] {
fmt.Fprintf(&builder, "%d, ", bit)
}
fmt.Fprintln(&builder, "... ]")
}
}
return builder.String()
}
// codeTemplate is the Go source template for the generated allotRoutes_gen.go file.
// It embeds the precomputed lookup tables and includes documentation about
// their structure and usage.
const codeTemplate = `// Code generated by {{.File}}; DO NOT EDIT.
// Copyright (c) 2026 Karl Gaissmaier
// SPDX-License-Identifier: MIT
package allot
// PfxRoutesLookupTbl is a lookup table of BitSet256 entries.
//
// It maps a baseIndex (1..255) to a bitset that contains all more
// specific baseIndices that are covered by the prefix at that index.
//
// The idea:
//
// If prefix P has baseIndex idx, then P covers all prefixes in the subtree
// rooted at idx. This table enumerates and encodes those indices.
//
// The table is split:
// - PfxRoutesLookupTbl holds prefixes up to /7
// - FringeRoutesLookupTbl holds /8 prefixes
//
// This structure allows for very fast set inclusion checks using simple bitwise AND.
//
//nolint:gochecknoglobals // Precomputed read‑only table used in hot paths.
var PfxRoutesLookupTbl = [256]bitset.BitSet256{
{{.PrefixAllotTable}} }
// FringeRoutesLookupTbl, the second 256 Bits, see also the PfxRoutesLookupTbl for the first 256 Bits
// we split 512 bits into 2×256 to leverage BitSet256 optimizations.
//
//nolint:gochecknoglobals // Precomputed read‑only table used in hot paths.
var FringeRoutesLookupTbl = [256]bitset.BitSet256{
{{.FringeAllotTable}} }
`