Skip to content

Commit

Permalink
Merge pull request #65 from qmuntal/reduceallocs
Browse files Browse the repository at this point in the history
Reduce state transition allocations
  • Loading branch information
qmuntal authored Aug 25, 2023
2 parents 66acf1d + e1bd8bb commit 23039c6
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 34 deletions.
44 changes: 17 additions & 27 deletions states.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,37 +72,26 @@ func (sr *stateRepresentation) FindHandler(ctx context.Context, trigger Trigger,
}

func (sr *stateRepresentation) findHandler(ctx context.Context, trigger Trigger, args ...any) (result triggerBehaviourResult, ok bool) {
var (
possibleBehaviours []triggerBehaviour
)
if possibleBehaviours, ok = sr.TriggerBehaviours[trigger]; !ok {
possibleBehaviours, ok := sr.TriggerBehaviours[trigger]
if !ok {
return
}
allResults := make([]triggerBehaviourResult, 0, len(possibleBehaviours))
var unmet []string
for _, behaviour := range possibleBehaviours {
allResults = append(allResults, triggerBehaviourResult{
Handler: behaviour,
UnmetGuardConditions: behaviour.UnmetGuardConditions(ctx, args...),
})
}
metResults := make([]triggerBehaviourResult, 0, len(allResults))
unmetResults := make([]triggerBehaviourResult, 0, len(allResults))
for _, result := range allResults {
if len(result.UnmetGuardConditions) == 0 {
metResults = append(metResults, result)
} else {
unmetResults = append(unmetResults, result)
unmet = behaviour.UnmetGuardConditions(ctx, unmet[:0], args...)
if len(unmet) == 0 {
if result.Handler != nil && len(result.UnmetGuardConditions) == 0 {
panic(fmt.Sprintf("stateless: Multiple permitted exit transitions are configured from state '%v' for trigger '%v'. Guard clauses must be mutually exclusive.", sr.State, trigger))
}
result.Handler = behaviour
result.UnmetGuardConditions = nil
} else if result.Handler == nil {
result.Handler = behaviour
result.UnmetGuardConditions = make([]string, len(unmet))
copy(result.UnmetGuardConditions, unmet)
}
}
if len(metResults) > 1 {
panic(fmt.Sprintf("stateless: Multiple permitted exit transitions are configured from state '%v' for trigger '%v'. Guard clauses must be mutually exclusive.", sr.State, trigger))
}
if len(metResults) == 1 {
result, ok = metResults[0], true
} else if len(unmetResults) > 0 {
result, ok = unmetResults[0], false
}
return
return result, result.Handler != nil && len(result.UnmetGuardConditions) == 0
}

func (sr *stateRepresentation) Activate(ctx context.Context) error {
Expand Down Expand Up @@ -210,9 +199,10 @@ func (sr *stateRepresentation) AddTriggerBehaviour(tb triggerBehaviour) {
}

func (sr *stateRepresentation) PermittedTriggers(ctx context.Context, args ...any) (triggers []Trigger) {
var unmet []string
for key, value := range sr.TriggerBehaviours {
for _, tb := range value {
if len(tb.UnmetGuardConditions(ctx, args...)) == 0 {
if len(tb.UnmetGuardConditions(ctx, unmet[:0], args...)) == 0 {
triggers = append(triggers, key)
break
}
Expand Down
17 changes: 10 additions & 7 deletions triggers.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,19 +61,22 @@ func (t transitionGuard) GuardConditionMet(ctx context.Context, args ...any) boo
return true
}

func (t transitionGuard) UnmetGuardConditions(ctx context.Context, args ...any) []string {
unmet := make([]string, 0, len(t.Guards))
func (t transitionGuard) UnmetGuardConditions(ctx context.Context, buf []string, args ...any) []string {
if cap(buf) < len(t.Guards) {
buf = make([]string, 0, len(t.Guards))
}
buf = buf[:0]
for _, guard := range t.Guards {
if !guard.Guard(ctx, args...) {
unmet = append(unmet, guard.Description.String())
buf = append(buf, guard.Description.String())
}
}
return unmet
return buf
}

type triggerBehaviour interface {
GuardConditionMet(context.Context, ...any) bool
UnmetGuardConditions(context.Context, ...any) []string
UnmetGuardConditions(context.Context, []string, ...any) []string
GetTrigger() Trigger
}

Expand All @@ -90,8 +93,8 @@ func (t *baseTriggerBehaviour) GuardConditionMet(ctx context.Context, args ...an
return t.Guard.GuardConditionMet(ctx, args...)
}

func (t *baseTriggerBehaviour) UnmetGuardConditions(ctx context.Context, args ...any) []string {
return t.Guard.UnmetGuardConditions(ctx, args...)
func (t *baseTriggerBehaviour) UnmetGuardConditions(ctx context.Context, buf []string, args ...any) []string {
return t.Guard.UnmetGuardConditions(ctx, buf, args...)
}

type ignoredTriggerBehaviour struct {
Expand Down

0 comments on commit 23039c6

Please sign in to comment.