aboutsummaryrefslogtreecommitdiff
path: root/src/strings
diff options
context:
space:
mode:
authorBrad Fitzpatrick <bradfitz@golang.org>2018-08-02 20:02:24 +0000
committerBrad Fitzpatrick <bradfitz@golang.org>2018-08-21 02:50:58 +0000
commitc544e0fbdb7344b2025650aaf70bab3b09d72003 (patch)
tree284bee6c1ae58b7fcf8a4371ed09c2402e394da3 /src/strings
parent9087d13ec3e39e50aae6c6a8cf99dc66225ab132 (diff)
downloadgo-c544e0fbdb7344b2025650aaf70bab3b09d72003.tar.gz
go-c544e0fbdb7344b2025650aaf70bab3b09d72003.zip
strings: select Replacer algorithm and build machine lazily
Saves 22KB of memory in stdlib packages. Updates #26775 Change-Id: Ia19fe7aff61f6e2ddd83cd35969d7ff94526591f Reviewed-on: https://go-review.googlesource.com/127661 Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Ian Lance Taylor <iant@golang.org>
Diffstat (limited to 'src/strings')
-rw-r--r--src/strings/export_test.go2
-rw-r--r--src/strings/replace.go28
2 files changed, 24 insertions, 6 deletions
diff --git a/src/strings/export_test.go b/src/strings/export_test.go
index 17c806aa56..b39cee6b1d 100644
--- a/src/strings/export_test.go
+++ b/src/strings/export_test.go
@@ -5,10 +5,12 @@
package strings
func (r *Replacer) Replacer() interface{} {
+ r.once.Do(r.buildOnce)
return r.r
}
func (r *Replacer) PrintTrie() string {
+ r.once.Do(r.buildOnce)
gen := r.r.(*genericReplacer)
return gen.printNode(&gen.root, 0)
}
diff --git a/src/strings/replace.go b/src/strings/replace.go
index 58a11a63db..dbda950194 100644
--- a/src/strings/replace.go
+++ b/src/strings/replace.go
@@ -4,12 +4,17 @@
package strings
-import "io"
+import (
+ "io"
+ "sync"
+)
// Replacer replaces a list of strings with replacements.
// It is safe for concurrent use by multiple goroutines.
type Replacer struct {
- r replacer
+ once sync.Once // guards buildOnce method
+ r replacer
+ oldnew []string
}
// replacer is the interface that a replacement algorithm needs to implement.
@@ -25,15 +30,24 @@ func NewReplacer(oldnew ...string) *Replacer {
if len(oldnew)%2 == 1 {
panic("strings.NewReplacer: odd argument count")
}
+ return &Replacer{oldnew: append([]string(nil), oldnew...)}
+}
+
+func (r *Replacer) buildOnce() {
+ r.r = r.build()
+ r.oldnew = nil
+}
+func (b *Replacer) build() replacer {
+ oldnew := b.oldnew
if len(oldnew) == 2 && len(oldnew[0]) > 1 {
- return &Replacer{r: makeSingleStringReplacer(oldnew[0], oldnew[1])}
+ return makeSingleStringReplacer(oldnew[0], oldnew[1])
}
allNewBytes := true
for i := 0; i < len(oldnew); i += 2 {
if len(oldnew[i]) != 1 {
- return &Replacer{r: makeGenericReplacer(oldnew)}
+ return makeGenericReplacer(oldnew)
}
if len(oldnew[i+1]) != 1 {
allNewBytes = false
@@ -52,7 +66,7 @@ func NewReplacer(oldnew ...string) *Replacer {
n := oldnew[i+1][0]
r[o] = n
}
- return &Replacer{r: &r}
+ return &r
}
r := byteStringReplacer{toReplace: make([]string, 0, len(oldnew)/2)}
@@ -71,16 +85,18 @@ func NewReplacer(oldnew ...string) *Replacer {
r.replacements[o] = []byte(n)
}
- return &Replacer{r: &r}
+ return &r
}
// Replace returns a copy of s with all replacements performed.
func (r *Replacer) Replace(s string) string {
+ r.once.Do(r.buildOnce)
return r.r.Replace(s)
}
// WriteString writes s to w with all replacements performed.
func (r *Replacer) WriteString(w io.Writer, s string) (n int, err error) {
+ r.once.Do(r.buildOnce)
return r.r.WriteString(w, s)
}