func (g *VisitGraph) Size() int {
	return len(g.nodes)
}
Size of the graph.
package block
import (
	"errors"
	"fmt"
	"log"
	"sync"
	"golang.org/x/tools/go/ssa"
)
var (
	ErrEdgesStackEmpty = errors.New("blockgraph: cannot pop edges: stack empty")
	ErrBadNode         = errors.New("VisitNode does not contain block (or has nil block)")
	ErrBadBlock        = errors.New("internal error: Block is nil")
	ErrBadParentFn     = errors.New("internal error: Block has nil parent Fn")
)
type visitedEdges map[int]map[int]bool
type VisitGraph struct {
	sync.Mutex
	nodes []*VisitNode
	visited map[*ssa.Function]visitedEdges
	reentrant bool
	edgesStack map[*ssa.Function][]visitedEdges
}
func NewVisitGraph(reentrant bool) *VisitGraph {
	if reentrant {
		return &VisitGraph{
			visited:    make(map[*ssa.Function]visitedEdges),
			reentrant:  true,
			edgesStack: make(map[*ssa.Function][]visitedEdges),
		}
	}
	return &VisitGraph{
		visited: make(map[*ssa.Function]visitedEdges),
	}
}
func (g *VisitGraph) pushEdges(fn *ssa.Function) {
	if g.reentrant {
		if edges, ok := g.visited[fn]; ok {
			g.edgesStack[fn] = append(g.edgesStack[fn], edges)
			g.visited[fn] = nil
		}
	}
}
func (g *VisitGraph) popEdges(fn *ssa.Function) error {
	if g.reentrant {
		if len(g.edgesStack[fn]) < 1 {
			return ErrEdgesStackEmpty
		}
		g.visited[fn] = g.edgesStack[fn][len(g.edgesStack[fn])-1]
		g.edgesStack[fn] = g.edgesStack[fn][:len(g.edgesStack[fn])-1]
	}
	return nil
}
func (g *VisitGraph) Visit(n *VisitNode) {
	g.Lock()
	defer g.Unlock()
	g.nodes = append(g.nodes, n)
	if len(g.nodes) > 1 {
		n.Prev = g.nodes[len(g.nodes)-2]
		g.nodes[len(g.nodes)-2].Next = n
	}
	if n.Index() == 0 {
		g.markNewFuncVisit(n)
	} else {
		if n.Prev == nil {
			log.Printf("Visit: there is no previous block")
			return
		}
		g.markVisit(n.Prev, n)
	}
}
func (g *VisitGraph) MarkLast(n *VisitNode) {
	if g.reentrant {
		g.popEdges(n.Fn())
	}
}
func (g *VisitGraph) markVisit(prev, n *VisitNode) {
	if prev.Fn() != n.Fn() {
		log.Printf("markVisit: previous block %q#%d and current block %q#%d are in different function",
			prev.Fn(), prev.Index(), n.Fn(), n.Index())
		return
	}
	if _, ok := g.visited[n.Fn()]; !ok {
		log.Printf("markVisit: Function %q was not visited before but visiting block %d",
			n.Fn(), n.Index())
		g.markNewFuncVisit(n)
	}
	g.visited[n.Fn()][n.Index()][prev.Index()] = true
}
func (g *VisitGraph) markNewFuncVisit(n *VisitNode) {
	if _, ok := g.visited[n.Fn()]; ok {
		if !g.reentrant {
			log.Printf("Function %q was visited", n.Fn())
			return
		}
		g.pushEdges(n.Fn())
	}
	g.visited[n.Fn()] = make(map[int]map[int]bool)
	for _, b := range n.Fn().Blocks {
		g.visited[n.Fn()][b.Index] = make(map[int]bool)
		for _, p := range b.Preds {
			g.visited[n.Fn()][b.Index][p.Index] = false
		}
	}
}
func (g *VisitGraph) VisitFrom(prev, n *VisitNode) {
	g.Lock()
	defer g.Unlock()
	g.nodes = append(g.nodes, n)
	if len(g.nodes) > 1 {
		n.Prev = g.nodes[len(g.nodes)-2]
		g.nodes[len(g.nodes)-2].Next = n
	}
	validPrev := false
PREVCHECK:
	for i := len(g.nodes) - 1; i >= 0; i-- {
		if g.nodes[i].Blk() == prev.Blk() {
			validPrev = true
			break PREVCHECK
		}
	}
	if !validPrev {
		log.Printf("VisitFrom: %v is not a valid existing VisitNode", prev)
	}
	g.markVisit(prev, n)
}
func (g *VisitGraph) LastNode() *VisitNode {
	if len(g.nodes) == 0 {
		log.Printf("VisitGraph.LastNode: empty graph")
		return nil
	}
	return g.nodes[len(g.nodes)-1]
}