Pre-allocate ninjaString slices

Naively pre-allocate ninjaString slices by counting $ characters as
an estimate of how many variables will be needed.  Saves 5% cpu time
on one workload.

Change-Id: Ib3a41df559d728b2db047f6dbbf9eb06d7045303
This commit is contained in:
Colin Cross 2015-04-14 16:28:51 -07:00
parent 7bf6f62130
commit 8c1c6c03f8
2 changed files with 13 additions and 3 deletions

View file

@ -80,7 +80,12 @@ type stateFunc func(*parseState, int, rune) (stateFunc, error)
// occurrences are expected to be variables or $$) and returns a list of the
// variable names that the string references.
func parseNinjaString(scope scope, str string) (*ninjaString, error) {
result := &ninjaString{}
// naively pre-allocate slices by counting $ signs
n := strings.Count(str, "$")
result := &ninjaString{
strings: make([]string, 0, n+1),
variables: make([]Variable, 0, n),
}
parseState := &parseState{
scope: scope,

View file

@ -65,6 +65,11 @@ var ninjaParseTestCases = []struct {
vars: []string{"foo"},
strs: []string{"","$$"},
},
{
input: "foo bar",
vars: nil,
strs: []string{"foo bar"},
},
{
input: "foo $ bar",
err: "invalid character after '$' at byte offset 5",
@ -90,7 +95,7 @@ var ninjaParseTestCases = []struct {
func TestParseNinjaString(t *testing.T) {
for _, testCase := range ninjaParseTestCases {
scope := newLocalScope(nil, "namespace")
var expectedVars []Variable
expectedVars := []Variable{}
for _, varName := range testCase.vars {
v, err := scope.LookupVariable(varName)
if err != nil {
@ -107,7 +112,7 @@ func TestParseNinjaString(t *testing.T) {
if !reflect.DeepEqual(output.variables, expectedVars) {
t.Errorf("incorrect variable list:")
t.Errorf(" input: %q", testCase.input)
t.Errorf(" expected: %#v", testCase.vars)
t.Errorf(" expected: %#v", expectedVars)
t.Errorf(" got: %#v", output.variables)
}
if !reflect.DeepEqual(output.strings, testCase.strs) {