From f4937865e46ae8fd3aff745450e1b51b4aad3552 Mon Sep 17 00:00:00 2001 From: Clayton Coleman Date: Wed, 23 Jan 2019 18:07:48 -0500 Subject: [PATCH] Optimize focus to avoid allocations Both regex creation and ConcatenatedString() are expensive. Memoize them within the spec iterator so we don't recalculate them later. --- internal/spec/specs.go | 45 +++++++++++++++++++++++++++++++----------- 1 file changed, 33 insertions(+), 12 deletions(-) diff --git a/internal/spec/specs.go b/internal/spec/specs.go index 006185ab5..27c0d1d6c 100644 --- a/internal/spec/specs.go +++ b/internal/spec/specs.go @@ -7,14 +7,21 @@ import ( ) type Specs struct { - specs []*Spec + specs []*Spec + names []string + hasProgrammaticFocus bool RegexScansFilePath bool } func NewSpecs(specs []*Spec) *Specs { + names := make([]string, len(specs)) + for i, spec := range specs { + names[i] = spec.ConcatenatedString() + } return &Specs{ specs: specs, + names: names, } } @@ -30,10 +37,13 @@ func (e *Specs) Shuffle(r *rand.Rand) { sort.Sort(e) permutation := r.Perm(len(e.specs)) shuffledSpecs := make([]*Spec, len(e.specs)) + names := make([]string, len(e.specs)) for i, j := range permutation { shuffledSpecs[i] = e.specs[j] + names[i] = e.names[j] } e.specs = shuffledSpecs + e.names = names } func (e *Specs) ApplyFocus(description string, focusString string, skipString string) { @@ -64,33 +74,43 @@ func (e *Specs) applyProgrammaticFocus() { // toMatch returns a byte[] to be used by regex matchers. When adding new behaviours to the matching function, // this is the place which we append to. -func (e *Specs) toMatch(description string, spec *Spec) []byte { +func (e *Specs) toMatch(description string, i int) []byte { + if i > len(e.names) { + return nil + } if e.RegexScansFilePath { return []byte( description + " " + - spec.ConcatenatedString() + " " + - spec.subject.CodeLocation().FileName) + e.names[i] + " " + + e.specs[i].subject.CodeLocation().FileName) } else { return []byte( description + " " + - spec.ConcatenatedString()) + e.names[i]) } } func (e *Specs) applyRegExpFocusAndSkip(description string, focusString string, skipString string) { - for _, spec := range e.specs { + var focusFilter *regexp.Regexp + if focusString != "" { + focusFilter = regexp.MustCompile(focusString) + } + var skipFilter *regexp.Regexp + if skipString != "" { + skipFilter = regexp.MustCompile(skipString) + } + + for i, spec := range e.specs { matchesFocus := true matchesSkip := false - toMatch := e.toMatch(description, spec) + toMatch := e.toMatch(description, i) - if focusString != "" { - focusFilter := regexp.MustCompile(focusString) + if focusFilter != nil { matchesFocus = focusFilter.Match([]byte(toMatch)) } - if skipString != "" { - skipFilter := regexp.MustCompile(skipString) + if skipFilter != nil { matchesSkip = skipFilter.Match([]byte(toMatch)) } @@ -115,9 +135,10 @@ func (e *Specs) Len() int { } func (e *Specs) Less(i, j int) bool { - return e.specs[i].ConcatenatedString() < e.specs[j].ConcatenatedString() + return e.names[i] < e.names[j] } func (e *Specs) Swap(i, j int) { + e.names[i], e.names[j] = e.names[j], e.names[i] e.specs[i], e.specs[j] = e.specs[j], e.specs[i] }