Skip to content

Commit

Permalink
Merge pull request #85 from qmuntal/optg
Browse files Browse the repository at this point in the history
Reduce ToGraph memory usage
  • Loading branch information
qmuntal authored Aug 23, 2024
2 parents 30a7b0c + 3ee7ce7 commit 2fa91c8
Show file tree
Hide file tree
Showing 2 changed files with 22 additions and 22 deletions.
36 changes: 14 additions & 22 deletions graph.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,20 +26,20 @@ func (g *graph) formatStateMachine(sm *StateMachine) string {

for _, sr := range stateList {
if sr.Superstate == nil {
sb.WriteString(g.formatOneState(sr, 1))
g.formatOneState(&sb, sr, 1)
}
}
for _, sr := range stateList {
if sr.HasInitialState {
dest := sm.stateConfig[sr.InitialTransitionTarget]
if dest != nil {
src := clusterStr(sr.State, true, true)
sb.WriteString(g.formatOneLine(src, str(dest.State, true), ""))
formatOneLine(&sb, src, str(dest.State, true), "")
}
}
}
for _, sr := range stateList {
sb.WriteString(g.formatAllStateTransitions(sm, sr))
g.formatAllStateTransitions(&sb, sm, sr)
}
initialState, err := sm.State(context.Background())
if err == nil {
Expand Down Expand Up @@ -69,12 +69,11 @@ func (g *graph) formatActions(sr *stateRepresentation) string {
return strings.Join(es, "\\n")
}

func (g *graph) formatOneState(sr *stateRepresentation, level int) string {
func (g *graph) formatOneState(sb *strings.Builder, sr *stateRepresentation, level int) {
var indent string
for i := 0; i < level; i++ {
indent += "\t"
}
var sb strings.Builder
sb.WriteString(fmt.Sprintf("%s%s [label=\"%s", indent, str(sr.State, true), str(sr.State, false)))
act := g.formatActions(sr)
if act != "" {
Expand All @@ -93,11 +92,10 @@ func (g *graph) formatOneState(sr *stateRepresentation, level int) string {
sb.WriteString(fmt.Sprintf("%s\t\"%s\" [label=\"\", shape=point];\n", indent, clusterStr(sr.State, false, true)))
}
for _, substate := range sr.Substates {
sb.WriteString(g.formatOneState(substate, level+1))
g.formatOneState(sb, substate, level+1)
}
sb.WriteString(indent + "}\n")
}
return sb.String()
}

func (g *graph) getEntryActions(ab []actionBehaviour, t Trigger) []string {
Expand All @@ -110,9 +108,7 @@ func (g *graph) getEntryActions(ab []actionBehaviour, t Trigger) []string {
return actions
}

func (g *graph) formatAllStateTransitions(sm *StateMachine, sr *stateRepresentation) string {
var sb strings.Builder

func (g *graph) formatAllStateTransitions(sb *strings.Builder, sm *StateMachine, sr *stateRepresentation) {
triggerList := make([]triggerBehaviour, 0, len(sr.TriggerBehaviours))
for _, triggers := range sr.TriggerBehaviours {
triggerList = append(triggerList, triggers...)
Expand All @@ -137,25 +133,25 @@ func (g *graph) formatAllStateTransitions(sm *StateMachine, sr *stateRepresentat
if _, ok := lines[ln]; !ok {
order = append(order, ln)
}
lines[ln] = append(lines[ln], g.formatOneTransition(t.Trigger, nil, t.Guard))
lines[ln] = append(lines[ln], formatOneTransition(t.Trigger, nil, t.Guard))
case *reentryTriggerBehaviour:
actions := g.getEntryActions(sr.EntryActions, t.Trigger)
ln := line{sr.State, t.Destination}
if _, ok := lines[ln]; !ok {
order = append(order, ln)
}
lines[ln] = append(lines[ln], g.formatOneTransition(t.Trigger, actions, t.Guard))
lines[ln] = append(lines[ln], formatOneTransition(t.Trigger, actions, t.Guard))
case *internalTriggerBehaviour:
actions := g.getEntryActions(sr.EntryActions, t.Trigger)
ln := line{sr.State, sr.State}
if _, ok := lines[ln]; !ok {
order = append(order, ln)
}
lines[ln] = append(lines[ln], g.formatOneTransition(t.Trigger, actions, t.Guard))
lines[ln] = append(lines[ln], formatOneTransition(t.Trigger, actions, t.Guard))
case *transitioningTriggerBehaviour:
src := sm.stateConfig[sr.State]
if src == nil {
return ""
continue
}
dest := sm.stateConfig[t.Destination]
var actions []string
Expand All @@ -172,21 +168,19 @@ func (g *graph) formatAllStateTransitions(sm *StateMachine, sr *stateRepresentat
if _, ok := lines[ln]; !ok {
order = append(order, ln)
}
lines[ln] = append(lines[ln], g.formatOneTransition(t.Trigger, actions, t.Guard))
lines[ln] = append(lines[ln], formatOneTransition(t.Trigger, actions, t.Guard))
case *dynamicTriggerBehaviour:
// TODO: not supported yet
}
}

for _, ln := range order {
content := lines[ln]
sb.WriteString(g.formatOneLine(str(ln.source, true), str(ln.destination, true), strings.Join(content, "\\n")))
formatOneLine(sb, str(ln.source, true), str(ln.destination, true), strings.Join(content, "\\n"))
}

return sb.String()
}

func (g *graph) formatOneTransition(trigger Trigger, actions []string, guards transitionGuard) string {
func formatOneTransition(trigger Trigger, actions []string, guards transitionGuard) string {
var sb strings.Builder
sb.WriteString(str(trigger, false))
if len(actions) > 0 {
Expand All @@ -202,11 +196,9 @@ func (g *graph) formatOneTransition(trigger Trigger, actions []string, guards tr
return sb.String()
}

func (g *graph) formatOneLine(fromNodeName, toNodeName, label string) string {
var sb strings.Builder
func formatOneLine(sb *strings.Builder, fromNodeName, toNodeName, label string) {
sb.WriteString(fmt.Sprintf("\t%s -> %s [label=\"%s\"", fromNodeName, toNodeName, label))
sb.WriteString("];\n")
return sb.String()
}

func clusterStr(state any, quote, init bool) string {
Expand Down
8 changes: 8 additions & 0 deletions graph_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,3 +155,11 @@ func TestStateMachine_ToGraph(t *testing.T) {
})
}
}

func BenchmarkToGraph(b *testing.B) {
sm := phoneCall()
b.ResetTimer()
for i := 0; i < b.N; i++ {
_ = sm.ToGraph()
}
}

0 comments on commit 2fa91c8

Please sign in to comment.