-
Notifications
You must be signed in to change notification settings - Fork 0
/
graph.go
157 lines (137 loc) · 2.96 KB
/
graph.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
package tok
import (
"fmt"
"sort"
"strconv"
"strings"
)
//------------------------------------------------------------------------------
// Node
type Node struct {
Segment
Nodes []*Node
}
// Equal
func (n *Node) Equal(oth *Node) bool {
if n.Segment != oth.Segment {
return false
}
if len(n.Nodes) != len(oth.Nodes) {
return false
}
for i, sub := range n.Nodes {
if !sub.Equal(oth.Nodes[i]) {
return false
}
}
return true
}
type nodeByPos []*Node
func (s nodeByPos) Len() int {
return len(s)
}
func (s nodeByPos) Less(i, j int) bool {
return s[i].Before(s[j].Token)
}
func (s nodeByPos) Swap(i, j int) {
s[i], s[j] = s[j], s[i]
}
//------------------------------------------------------------------------------
// Graph allows to arrange the picked values hierarchically.
type Graph struct {
Root *Node
}
func rankNodes(a *Node, b *Node) bool {
if a.Clashes(b.Token) {
return false
}
nodes := []*Node{}
var ok bool
for i := 0; i < len(a.Nodes); i++ {
c := a.Nodes[i]
if b.Covers(c.Token) {
ok = rankNodes(b, c)
if !ok {
return false
}
} else if b.Clashes(c.Token) {
return false
} else {
if c.Covers(b.Token) {
return rankNodes(c, b)
}
nodes = append(nodes, c)
}
}
a.Nodes = nodes
a.Nodes = append(a.Nodes, b)
sort.Stable(nodeByPos(a.Nodes))
return true
}
// Append appends a Segment to a graph.
func (g *Graph) Append(seg Segment) (*Graph, bool) {
n := &Node{Segment: seg}
bkp := g.Root.Token
if !g.Root.Covers(n.Token) {
if len(g.Root.Nodes) > 0 {
g.Root.Token = g.Root.Token.Merge(n.Segment.Token)
} else {
g.Root.Token = n.Segment.Token
}
}
ok := rankNodes(g.Root, n)
if !ok {
g.Root.Token = bkp
}
return g, ok
}
// Equal
func (g *Graph) Equal(oth *Graph) bool {
return g.Root.Equal(oth.Root)
}
func makeStackLines(b *strings.Builder, prefix string, i int, n *Node) {
prefix = fmt.Sprintf("%s%d.%s", prefix, i, n.String())
b.WriteString(prefix)
b.WriteRune(' ')
b.WriteString(strconv.Itoa(n.Len()))
b.WriteRune('\n')
for j, sub := range n.Nodes {
makeStackLines(b, prefix+";", j+1, sub)
}
}
// FlameStack
func (g *Graph) FlameStack() string {
b := &strings.Builder{}
makeStackLines(b, "", 1, g.Root)
return b.String()
}
func (n *Node) appendLeafs(leafs *[]Segment) {
if len(n.Nodes) == 0 {
*leafs = append(*leafs, n.Segment)
} else {
for _, sub := range n.Nodes {
sub.appendLeafs(leafs)
}
}
}
// Leafs returns the values of a graph that hang on the leafs.
func (g *Graph) Leafs() []Segment {
leafs := []Segment{}
g.Root.appendLeafs(&leafs)
return leafs
}
// BuildGraph creates a graph with the segments.
// The name argument will be used as the info of the root node.
func BuildGraph(name string, segments []Segment) *Graph {
g := NewGraph(name)
for _, v := range segments {
g.Append(v)
}
return g
}
// NewGraph creates an empty graph with name as the info of the root node.
func NewGraph(name string) *Graph {
g := &Graph{&Node{}}
g.Root.Segment.Info = name
return g
}