Update go version
This commit is contained in:
24
vendor/honnef.co/go/tools/internal/xtools-internal/graph/allpaths.go
vendored
Normal file
24
vendor/honnef.co/go/tools/internal/xtools-internal/graph/allpaths.go
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
// Copyright 2026 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package graph
|
||||
|
||||
// AllPaths returns the set of nodes that are part of at least one path from src to dst.
|
||||
func AllPaths[NodeID comparable](g Graph[NodeID], src, dst NodeID) map[NodeID]bool {
|
||||
// We intersect the forward closure of 'src' with
|
||||
// the reverse closure of 'dst'. This is not the most
|
||||
// efficient implementation, but it's the clearest,
|
||||
// and the previous one had bugs.
|
||||
|
||||
fwd := Reachable(g, src)
|
||||
rev := Reachable(Transpose(g), dst)
|
||||
|
||||
// Intersection
|
||||
for n := range fwd {
|
||||
if !rev[n] {
|
||||
delete(fwd, n)
|
||||
}
|
||||
}
|
||||
return fwd
|
||||
}
|
||||
89
vendor/honnef.co/go/tools/internal/xtools-internal/graph/compact.go
vendored
Normal file
89
vendor/honnef.co/go/tools/internal/xtools-internal/graph/compact.go
vendored
Normal file
@@ -0,0 +1,89 @@
|
||||
// Copyright 2026 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package graph
|
||||
|
||||
import "iter"
|
||||
|
||||
// A CompactGraph is a Graph with nodes that are compactly numbered from [0,
|
||||
// NumNodes()).
|
||||
//
|
||||
// Compactly numbered graphs are useful for many graph algorithms, and many
|
||||
// graph representations are naturally compact.
|
||||
//
|
||||
// To compact an arbitrary graph, use [Compact].
|
||||
type CompactGraph interface {
|
||||
Graph[int]
|
||||
IsCompact()
|
||||
}
|
||||
|
||||
// A nodePreserving graph is a transformation of another graph that preserves
|
||||
// node IDs.
|
||||
type nodePreserving interface {
|
||||
Graph[int]
|
||||
unwrapPreservingNodes() Graph[int]
|
||||
}
|
||||
|
||||
// Compact takes a Graph with arbitrary NodeIDs and returns a compact graph.
|
||||
//
|
||||
// If g implements [CompactGraph], it assumes g is already compact and simply
|
||||
// returns g and an identity mapping.
|
||||
func Compact[NodeID comparable](g Graph[NodeID]) (CompactGraph, *Index[NodeID]) {
|
||||
// If it's already compact, simply return it.
|
||||
if gc, ok := g.(CompactGraph); ok {
|
||||
// The above assertion ensures NodeID is int, so we know this type
|
||||
// assertion will always succeed.
|
||||
return gc, any(NewIdentityIndex(gc.NumNodes())).(*Index[NodeID])
|
||||
}
|
||||
|
||||
// If it's a transformation and the underlying graph is compact, we can use
|
||||
// an identity index. Though we still need to build a compactGraph to
|
||||
// satisfy the CompactGraph interface.
|
||||
g2, _ := g.(nodePreserving)
|
||||
for g2 != nil {
|
||||
unwrapped := g2.unwrapPreservingNodes()
|
||||
if gc, ok := unwrapped.(CompactGraph); ok {
|
||||
index := any(NewIdentityIndex(gc.NumNodes())).(*Index[NodeID])
|
||||
cg := compactGraph[NodeID]{g, index}
|
||||
return &cg, index
|
||||
}
|
||||
g2, _ = unwrapped.(nodePreserving)
|
||||
}
|
||||
|
||||
// Nope, just build an index.
|
||||
cg := compactGraph[NodeID]{g, NewIndex(g.Nodes())}
|
||||
return &cg, cg.m
|
||||
}
|
||||
|
||||
type compactGraph[NodeID comparable] struct {
|
||||
g Graph[NodeID]
|
||||
m *Index[NodeID]
|
||||
}
|
||||
|
||||
func (g *compactGraph[NodeID]) Nodes() iter.Seq[int] {
|
||||
return func(yield func(int) bool) {
|
||||
for i := range g.g.NumNodes() {
|
||||
if !yield(i) {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (g *compactGraph[NodeID]) NumNodes() int {
|
||||
return g.g.NumNodes()
|
||||
}
|
||||
|
||||
func (g *compactGraph[NodeID]) Out(node int) iter.Seq[int] {
|
||||
id := g.m.Value(node)
|
||||
return func(yield func(int) bool) {
|
||||
for nid := range g.g.Out(id) {
|
||||
if !yield(g.m.Index(nid)) {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (g *compactGraph[NodeID]) IsCompact() {}
|
||||
33
vendor/honnef.co/go/tools/internal/xtools-internal/graph/graph.go
vendored
Normal file
33
vendor/honnef.co/go/tools/internal/xtools-internal/graph/graph.go
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
// Copyright 2026 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package graph provides a common abstraction for directed graphs and standard
|
||||
// graph algorithms.
|
||||
//
|
||||
// In general, this package does not provide or assume any concrete graph
|
||||
// representation. It's up to the caller of this package to implement the
|
||||
// [Graph] interface, either directly or as an adapter around another type.
|
||||
package graph
|
||||
|
||||
import "iter"
|
||||
|
||||
// A Graph implements a directed graph where nodes in the graph are identified
|
||||
// by the NodeID type.
|
||||
//
|
||||
// If a concrete graph type stores additional information about nodes and/or
|
||||
// edges, it will conventionally provide methods of the form:
|
||||
//
|
||||
// Node(node NodeID) nodeInfo
|
||||
// Edge(from, to NodeID) edgeInfo
|
||||
type Graph[NodeID comparable] interface {
|
||||
// Nodes yields all nodes in this graph.
|
||||
Nodes() iter.Seq[NodeID]
|
||||
|
||||
// NumNodes returns the total number of nodes in this graph.
|
||||
NumNodes() int
|
||||
|
||||
// Out yields the out-edges of node. Out must be deterministic, though
|
||||
// otherwise there is no constraint on the order of the returned sequence.
|
||||
Out(node NodeID) iter.Seq[NodeID]
|
||||
}
|
||||
96
vendor/honnef.co/go/tools/internal/xtools-internal/graph/index.go
vendored
Normal file
96
vendor/honnef.co/go/tools/internal/xtools-internal/graph/index.go
vendored
Normal file
@@ -0,0 +1,96 @@
|
||||
// Copyright 2026 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package graph
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"iter"
|
||||
"slices"
|
||||
)
|
||||
|
||||
// An Index is an immutable, bijective map between [0, N) and an ordered list of keys.
|
||||
type Index[Key comparable] struct {
|
||||
// There are three Index representations:
|
||||
//
|
||||
// - If identN > 0, an identity map of [0, identN).
|
||||
// - If index == nil, a sorted integer index in values.
|
||||
// - Otherwise, a full index in values and index.
|
||||
|
||||
identN int
|
||||
values []Key
|
||||
index map[Key]int
|
||||
}
|
||||
|
||||
// NewIndex returns an index for the specified list of values.
|
||||
func NewIndex[Key comparable](values iter.Seq[Key]) *Index[Key] {
|
||||
vs := slices.Collect(values)
|
||||
if len(vs) == 0 {
|
||||
return new(Index[Key])
|
||||
}
|
||||
|
||||
// Fast path: a naturally sorted list needs no index. (Sadly, there's no way
|
||||
// to ask "is Key ordered?")
|
||||
if vi, ok := any(vs).([]int); ok && slices.IsSorted(vi) {
|
||||
return &Index[Key]{values: vs}
|
||||
}
|
||||
|
||||
index := make(map[Key]int, len(vs))
|
||||
for i, v := range vs {
|
||||
index[v] = i
|
||||
}
|
||||
return &Index[Key]{values: vs, index: index}
|
||||
}
|
||||
|
||||
// NewIdentityIndex returns an index that maps [0, n) to [0, n).
|
||||
func NewIdentityIndex(n int) *Index[int] {
|
||||
if n < 0 {
|
||||
panic("n < 0")
|
||||
}
|
||||
// If n == 0, this is actually a "sorted integer index", but it doesn't
|
||||
// matter because everything is out of bounds either way.
|
||||
return &Index[int]{identN: n}
|
||||
}
|
||||
|
||||
// Value maps an index to a key.
|
||||
func (ix *Index[Key]) Value(index int) Key {
|
||||
if ix.identN > 0 {
|
||||
if index < 0 || index >= ix.identN {
|
||||
panic(fmt.Sprintf("index %d out of range [0, %d)", index, ix.identN))
|
||||
}
|
||||
return any(index).(Key)
|
||||
}
|
||||
if index < 0 || index >= len(ix.values) {
|
||||
panic(fmt.Sprintf("index %d out of range [0, %d)", index, ix.identN))
|
||||
}
|
||||
return ix.values[index]
|
||||
}
|
||||
|
||||
// Index maps a key to an index.
|
||||
func (ix *Index[Key]) Index(key Key) int {
|
||||
if key, ok := any(key).(int); ok {
|
||||
// Integer-only optimizations.
|
||||
switch {
|
||||
case ix.identN > 0:
|
||||
// Identity.
|
||||
if 0 <= key && key < ix.identN {
|
||||
return key
|
||||
}
|
||||
goto oob
|
||||
|
||||
case ix.index == nil:
|
||||
// Sorted integers.
|
||||
if i, ok := slices.BinarySearch(any(ix.values).([]int), key); ok {
|
||||
return i
|
||||
}
|
||||
goto oob
|
||||
}
|
||||
}
|
||||
if i, ok := ix.index[key]; ok {
|
||||
return i
|
||||
}
|
||||
|
||||
oob:
|
||||
panic(fmt.Sprintf("key %v not in index", key))
|
||||
}
|
||||
94
vendor/honnef.co/go/tools/internal/xtools-internal/graph/order.go
vendored
Normal file
94
vendor/honnef.co/go/tools/internal/xtools-internal/graph/order.go
vendored
Normal file
@@ -0,0 +1,94 @@
|
||||
// Copyright 2026 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package graph
|
||||
|
||||
import "slices"
|
||||
|
||||
// Postorder returns the sequence of nodes in the spanning DAG of g, in
|
||||
// postorder.
|
||||
//
|
||||
// For rootless subgraphs, it breaks cycles by starting at the lowest numbered
|
||||
// node.
|
||||
//
|
||||
// This algorithm runs in O(V + E) time and O(V + E) space.
|
||||
func Postorder[NodeID comparable](g Graph[NodeID]) []NodeID {
|
||||
cg, nodeMap := Compact(g)
|
||||
|
||||
numNodes := cg.NumNodes()
|
||||
if numNodes == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
result := make([]NodeID, 0, numNodes)
|
||||
visited := newBitset(numNodes)
|
||||
onStack := newBitset(numNodes)
|
||||
|
||||
// visit performs a Depth-First Search.
|
||||
var visit func(u int)
|
||||
visit = func(u int) {
|
||||
if !visited.add(u) {
|
||||
return
|
||||
}
|
||||
onStack.add(u)
|
||||
|
||||
for v := range cg.Out(u) {
|
||||
if onStack.contains(v) {
|
||||
// Cycle detected (back-edge).
|
||||
// To resolve, we simply skip processing this edge further in the
|
||||
// current recursion, effectively "breaking" the cycle at this point.
|
||||
continue
|
||||
}
|
||||
visit(v)
|
||||
}
|
||||
|
||||
onStack.remove(u)
|
||||
// Post-order: add to result after all descendants are processed.
|
||||
result = append(result, nodeMap.Value(u))
|
||||
}
|
||||
|
||||
// Visit every node in ascending order to ensure stability.
|
||||
for u := range numNodes {
|
||||
visit(u)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// ReversePostorder returns the nodes of the graph in reverse post-order.
|
||||
//
|
||||
// If g is a directed acyclic graph (DAG), the result is a topological sort of
|
||||
// g.
|
||||
//
|
||||
// See [Postorder] for how this handles back-edges and cycles.
|
||||
//
|
||||
// This algorithm runs in O(V + E) time and O(V + E) space.
|
||||
func ReversePostorder[NodeID comparable](g Graph[NodeID]) []NodeID {
|
||||
result := Postorder(g)
|
||||
slices.Reverse(result)
|
||||
return result
|
||||
}
|
||||
|
||||
// bitset is a simple fixed-size bitset used to reduce memory overhead.
|
||||
type bitset []uint64
|
||||
|
||||
func newBitset(n int) bitset {
|
||||
return make(bitset, (n+63)/64)
|
||||
}
|
||||
|
||||
func (b bitset) add(u int) bool {
|
||||
if b.contains(u) {
|
||||
return false
|
||||
}
|
||||
b[u/64] |= 1 << (u % 64)
|
||||
return true
|
||||
}
|
||||
|
||||
func (b bitset) remove(u int) {
|
||||
b[u/64] &= ^(1 << (u % 64))
|
||||
}
|
||||
|
||||
func (b bitset) contains(u int) bool {
|
||||
return b[u/64]&(1<<(u%64)) != 0
|
||||
}
|
||||
23
vendor/honnef.co/go/tools/internal/xtools-internal/graph/reachable.go
vendored
Normal file
23
vendor/honnef.co/go/tools/internal/xtools-internal/graph/reachable.go
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
// Copyright 2026 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package graph
|
||||
|
||||
// Reachable returns the set of nodes reachable from the given roots.
|
||||
func Reachable[NodeID comparable](g Graph[NodeID], roots ...NodeID) map[NodeID]bool {
|
||||
seen := make(map[NodeID]bool)
|
||||
var visit func(node NodeID)
|
||||
visit = func(node NodeID) {
|
||||
if !seen[node] {
|
||||
seen[node] = true
|
||||
for e := range g.Out(node) {
|
||||
visit(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, root := range roots {
|
||||
visit(root)
|
||||
}
|
||||
return seen
|
||||
}
|
||||
39
vendor/honnef.co/go/tools/internal/xtools-internal/graph/scc.go
vendored
Normal file
39
vendor/honnef.co/go/tools/internal/xtools-internal/graph/scc.go
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
// Copyright 2026 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package graph
|
||||
|
||||
import "slices"
|
||||
|
||||
// SCCs computes the strongly connected components of the graph g.
|
||||
func SCCs[NodeID comparable](g Graph[NodeID]) [][]NodeID {
|
||||
// Use Kosaraju's algorithm. Tarjan is overkill here.
|
||||
|
||||
// Forward pass
|
||||
S := Postorder(g)
|
||||
|
||||
// Reverse pass
|
||||
gt := Transpose(g)
|
||||
seen := make(map[NodeID]bool)
|
||||
var scc []NodeID
|
||||
var sccs [][]NodeID
|
||||
var rvisit func(NodeID)
|
||||
rvisit = func(u NodeID) {
|
||||
if !seen[u] {
|
||||
seen[u] = true
|
||||
scc = append(scc, u)
|
||||
for v := range gt.Out(u) {
|
||||
rvisit(v)
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, root := range slices.Backward(S) {
|
||||
if !seen[root] {
|
||||
scc = nil
|
||||
rvisit(root)
|
||||
sccs = append(sccs, scc)
|
||||
}
|
||||
}
|
||||
return sccs
|
||||
}
|
||||
45
vendor/honnef.co/go/tools/internal/xtools-internal/graph/shortest.go
vendored
Normal file
45
vendor/honnef.co/go/tools/internal/xtools-internal/graph/shortest.go
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
// Copyright 2026 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package graph
|
||||
|
||||
import "slices"
|
||||
|
||||
// ShortestPath returns a shortest path from src to dst in g.
|
||||
// It returns the path as a slice of nodes starting with src and ending with dst.
|
||||
// If no path is found, it returns nil.
|
||||
func ShortestPath[NodeID comparable](g Graph[NodeID], src, dst NodeID) []NodeID {
|
||||
if src == dst {
|
||||
return []NodeID{src}
|
||||
}
|
||||
|
||||
pred := make(map[NodeID]NodeID)
|
||||
queue := []NodeID{src}
|
||||
// Mark src as seen.
|
||||
pred[src] = src
|
||||
|
||||
for len(queue) > 0 {
|
||||
n := queue[0]
|
||||
queue = queue[1:]
|
||||
|
||||
if n == dst {
|
||||
// Reconstruct path
|
||||
var path []NodeID
|
||||
for curr := dst; curr != src; curr = pred[curr] {
|
||||
path = append(path, curr)
|
||||
}
|
||||
path = append(path, src)
|
||||
slices.Reverse(path)
|
||||
return path
|
||||
}
|
||||
|
||||
for v := range g.Out(n) {
|
||||
if _, seen := pred[v]; !seen {
|
||||
pred[v] = n
|
||||
queue = append(queue, v)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
51
vendor/honnef.co/go/tools/internal/xtools-internal/graph/transpose.go
vendored
Normal file
51
vendor/honnef.co/go/tools/internal/xtools-internal/graph/transpose.go
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
// Copyright 2026 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package graph
|
||||
|
||||
import (
|
||||
"iter"
|
||||
"slices"
|
||||
)
|
||||
|
||||
type transpose[NodeID comparable] struct {
|
||||
Graph Graph[NodeID]
|
||||
preds map[NodeID][]NodeID
|
||||
}
|
||||
|
||||
// transpose returns a graph like g but with all edges reversed. Node IDs are
|
||||
// identical to the underlying graph.
|
||||
//
|
||||
// Transpose preserves compactness.
|
||||
func Transpose[NodeID comparable](g Graph[NodeID]) Graph[NodeID] {
|
||||
if g, ok := g.(transpose[NodeID]); ok {
|
||||
// Transpose(Transpose(g)) == g
|
||||
return g.Graph
|
||||
}
|
||||
|
||||
preds := make(map[NodeID][]NodeID)
|
||||
for nid := range g.Nodes() {
|
||||
for succ := range g.Out(nid) {
|
||||
preds[succ] = append(preds[succ], nid)
|
||||
}
|
||||
}
|
||||
return transpose[NodeID]{g, preds}
|
||||
}
|
||||
|
||||
func (t transpose[NodeID]) NumNodes() int {
|
||||
return len(t.preds)
|
||||
}
|
||||
|
||||
func (t transpose[NodeID]) Nodes() iter.Seq[NodeID] {
|
||||
return t.Graph.Nodes()
|
||||
}
|
||||
|
||||
func (t transpose[NodeID]) Out(n NodeID) iter.Seq[NodeID] {
|
||||
return slices.Values(t.preds[n])
|
||||
}
|
||||
|
||||
//lint:ignore U1000 False positive in Staticcheck 2026.1 and older.
|
||||
func (t transpose[NodeID]) unwrapPreservingNodes() Graph[NodeID] {
|
||||
return t.Graph
|
||||
}
|
||||
Reference in New Issue
Block a user