cmd/digraph: only print non-trivial sccs

In 'digraph sccs', do not print trivial single-node components.
This is more useful because it distinguishes nodes with self-loops (printed)
from nodes without (not printed).

Also remove an unnecessary TODO about map[string]bool vs map[string]struct{}.
The savings is at most 5% and if we really cared about storage we would probably
not use a map at all.

Change-Id: I6049b3c0f99a913c65f08c6c40e77ae99d1ba8c4
Reviewed-on: https://go-review.googlesource.com/c/tools/+/396834
Reviewed-by: Russ Cox <rsc@golang.org>
TryBot-Result: Gopher Robot <gobot@golang.org>
Auto-Submit: Dmitri Shuralyov <dmitshur@golang.org>
gopls-CI: kokoro <noreply+kokoro@google.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
Run-TryBot: Dmitri Shuralyov <dmitshur@golang.org>
Reviewed-by: Roland Shoemaker <roland@golang.org>
This commit is contained in:
Russ Cox 2022-03-30 09:29:51 -04:00 committed by Gopher Robot
parent 6fff1af1a8
commit c862641ee9
2 changed files with 16 additions and 4 deletions

View File

@ -122,7 +122,8 @@ The support commands are:
allpaths <node> <node>
the set of nodes on all paths from the first node to the second
sccs
all strongly connected components (one per line)
all non-trivial strongly connected components, one per line
(single-node components are only printed for nodes with self-loops)
scc <node>
the set of nodes nodes strongly connected to the specified one
focus <node>
@ -158,7 +159,7 @@ func (l nodelist) println(sep string) {
fmt.Fprintln(stdout)
}
type nodeset map[string]bool // TODO(deklerk): change bool to struct to reduce memory footprint
type nodeset map[string]bool
func (s nodeset) sort() nodelist {
nodes := make(nodelist, len(s))
@ -266,6 +267,9 @@ func (g graph) sccs() []nodeset {
if !seen[top] {
scc = make(nodeset)
rvisit(top)
if len(scc) == 1 && !g[top][top] {
continue
}
sccs = append(sccs, scc)
}
}
@ -365,7 +369,7 @@ func parse(rd io.Reader) (graph, error) {
return g, nil
}
// Overridable for testing purposes.
// Overridable for redirection.
var stdin io.Reader = os.Stdin
var stdout io.Writer = os.Stdout
@ -485,9 +489,16 @@ func digraph(cmd string, args []string) error {
if len(args) != 0 {
return fmt.Errorf("usage: digraph sccs")
}
buf := new(bytes.Buffer)
oldStdout := stdout
stdout = buf
for _, scc := range g.sccs() {
scc.sort().println(" ")
}
lines := strings.SplitAfter(buf.String(), "\n")
sort.Strings(lines)
stdout = oldStdout
io.WriteString(stdout, strings.Join(lines, ""))
case "scc":
if len(args) != 1 {

View File

@ -27,6 +27,7 @@ a b c
b d
c d
d c
e e
`
for _, test := range []struct {
@ -41,7 +42,7 @@ d c
{"transpose", g1, "transpose", nil, "belt pants\njacket sweater\npants shorts\nshoes pants\nshoes socks\nsweater shirt\ntie shirt\n"},
{"forward", g1, "forward", []string{"socks"}, "shoes\nsocks\n"},
{"forward multiple args", g1, "forward", []string{"socks", "sweater"}, "jacket\nshoes\nsocks\nsweater\n"},
{"scss", g2, "sccs", nil, "a\nb\nc d\n"},
{"scss", g2, "sccs", nil, "c d\ne\n"},
{"scc", g2, "scc", []string{"d"}, "c\nd\n"},
{"succs", g2, "succs", []string{"a"}, "b\nc\n"},
{"preds", g2, "preds", []string{"c"}, "a\nd\n"},