Compile go/doc's 4 regexps lazily, on demand.
Also, add a test for the one that had no test coverage.
This reduces init-time CPU as well as heap by ~20KB when they're not
used, which seems to be common enough. As an example, cmd/doc only
seems to use 1 of them. (as noted by temporary print statements)
Updates #26775
Change-Id: I85df89b836327a53fb8e1ace3f92480374270368
Reviewed-on: https://go-review.googlesource.com/127875
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
// Go parser.
"go/ast": {"L4", "OS", "go/scanner", "go/token"},
- "go/doc": {"L4", "go/ast", "go/token", "regexp", "text/template"},
+ "go/doc": {"L4", "OS", "go/ast", "go/token", "regexp", "text/template"},
"go/parser": {"L4", "OS", "go/ast", "go/scanner", "go/token"},
"go/printer": {"L4", "OS", "go/ast", "go/scanner", "go/token", "text/tabwriter"},
"go/scanner": {"L4", "OS", "go/token"},
import (
"io"
- "regexp"
"strings"
"text/template" // for HTMLEscape
"unicode"
urlRx = protoPart + `://` + hostPart + pathPart
)
-var matchRx = regexp.MustCompile(`(` + urlRx + `)|(` + identRx + `)`)
+var matchRx = newLazyRE(`(` + urlRx + `)|(` + identRx + `)`)
var (
html_a = []byte(`<a href="`)
lines []string
}
-var nonAlphaNumRx = regexp.MustCompile(`[^a-zA-Z0-9]`)
+var nonAlphaNumRx = newLazyRE(`[^a-zA-Z0-9]`)
func anchorID(line string) string {
// Add a "hdr-" prefix to avoid conflicting with IDs used for package symbols.
test(t, AllDecls)
test(t, AllMethods)
}
+
+func TestAnchorID(t *testing.T) {
+ const in = "Important Things 2 Know & Stuff"
+ const want = "hdr-Important_Things_2_Know___Stuff"
+ got := anchorID(in)
+ if got != want {
+ t.Errorf("anchorID(%q) = %q; want %q", in, got, want)
+ }
+}
--- /dev/null
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package doc
+
+import (
+ "os"
+ "regexp"
+ "strings"
+ "sync"
+)
+
+type lazyRE struct {
+ str string
+ once sync.Once
+ rx *regexp.Regexp
+}
+
+func (r *lazyRE) re() *regexp.Regexp {
+ r.once.Do(r.build)
+ return r.rx
+}
+
+func (r *lazyRE) build() {
+ r.rx = regexp.MustCompile(r.str)
+ r.str = ""
+}
+
+func (r *lazyRE) FindStringSubmatchIndex(s string) []int {
+ return r.re().FindStringSubmatchIndex(s)
+}
+
+func (r *lazyRE) ReplaceAllString(src, repl string) string {
+ return r.re().ReplaceAllString(src, repl)
+}
+
+func (r *lazyRE) MatchString(s string) bool {
+ return r.re().MatchString(s)
+}
+
+var inTest = len(os.Args) > 0 && strings.HasSuffix(strings.TrimSuffix(os.Args[0], ".exe"), ".test")
+
+func newLazyRE(str string) *lazyRE {
+ lr := &lazyRE{str: str}
+ if inTest {
+ // In tests, always compile the regexps early.
+ lr.re()
+ }
+ return lr
+}
import (
"go/ast"
"go/token"
- "regexp"
"sort"
"strconv"
)
}
var (
- noteMarker = `([A-Z][A-Z]+)\(([^)]+)\):?` // MARKER(uid), MARKER at least 2 chars, uid at least 1 char
- noteMarkerRx = regexp.MustCompile(`^[ \t]*` + noteMarker) // MARKER(uid) at text start
- noteCommentRx = regexp.MustCompile(`^/[/*][ \t]*` + noteMarker) // MARKER(uid) at comment start
+ noteMarker = `([A-Z][A-Z]+)\(([^)]+)\):?` // MARKER(uid), MARKER at least 2 chars, uid at least 1 char
+ noteMarkerRx = newLazyRE(`^[ \t]*` + noteMarker) // MARKER(uid) at text start
+ noteCommentRx = newLazyRE(`^/[/*][ \t]*` + noteMarker) // MARKER(uid) at comment start
)
// readNote collects a single note from a sequence of comments.