Commit c544e0fb authored by Brad Fitzpatrick's avatar Brad Fitzpatrick

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: default avatarIan Lance Taylor <iant@golang.org>
parent 9087d13e
...@@ -5,10 +5,12 @@ ...@@ -5,10 +5,12 @@
package strings package strings
func (r *Replacer) Replacer() interface{} { func (r *Replacer) Replacer() interface{} {
r.once.Do(r.buildOnce)
return r.r return r.r
} }
func (r *Replacer) PrintTrie() string { func (r *Replacer) PrintTrie() string {
r.once.Do(r.buildOnce)
gen := r.r.(*genericReplacer) gen := r.r.(*genericReplacer)
return gen.printNode(&gen.root, 0) return gen.printNode(&gen.root, 0)
} }
......
...@@ -4,12 +4,17 @@ ...@@ -4,12 +4,17 @@
package strings package strings
import "io" import (
"io"
"sync"
)
// Replacer replaces a list of strings with replacements. // Replacer replaces a list of strings with replacements.
// It is safe for concurrent use by multiple goroutines. // It is safe for concurrent use by multiple goroutines.
type Replacer struct { type Replacer struct {
once sync.Once // guards buildOnce method
r replacer r replacer
oldnew []string
} }
// replacer is the interface that a replacement algorithm needs to implement. // replacer is the interface that a replacement algorithm needs to implement.
...@@ -25,15 +30,24 @@ func NewReplacer(oldnew ...string) *Replacer { ...@@ -25,15 +30,24 @@ func NewReplacer(oldnew ...string) *Replacer {
if len(oldnew)%2 == 1 { if len(oldnew)%2 == 1 {
panic("strings.NewReplacer: odd argument count") 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 { if len(oldnew) == 2 && len(oldnew[0]) > 1 {
return &Replacer{r: makeSingleStringReplacer(oldnew[0], oldnew[1])} return makeSingleStringReplacer(oldnew[0], oldnew[1])
} }
allNewBytes := true allNewBytes := true
for i := 0; i < len(oldnew); i += 2 { for i := 0; i < len(oldnew); i += 2 {
if len(oldnew[i]) != 1 { if len(oldnew[i]) != 1 {
return &Replacer{r: makeGenericReplacer(oldnew)} return makeGenericReplacer(oldnew)
} }
if len(oldnew[i+1]) != 1 { if len(oldnew[i+1]) != 1 {
allNewBytes = false allNewBytes = false
...@@ -52,7 +66,7 @@ func NewReplacer(oldnew ...string) *Replacer { ...@@ -52,7 +66,7 @@ func NewReplacer(oldnew ...string) *Replacer {
n := oldnew[i+1][0] n := oldnew[i+1][0]
r[o] = n r[o] = n
} }
return &Replacer{r: &r} return &r
} }
r := byteStringReplacer{toReplace: make([]string, 0, len(oldnew)/2)} r := byteStringReplacer{toReplace: make([]string, 0, len(oldnew)/2)}
...@@ -71,16 +85,18 @@ func NewReplacer(oldnew ...string) *Replacer { ...@@ -71,16 +85,18 @@ func NewReplacer(oldnew ...string) *Replacer {
r.replacements[o] = []byte(n) r.replacements[o] = []byte(n)
} }
return &Replacer{r: &r} return &r
} }
// Replace returns a copy of s with all replacements performed. // Replace returns a copy of s with all replacements performed.
func (r *Replacer) Replace(s string) string { func (r *Replacer) Replace(s string) string {
r.once.Do(r.buildOnce)
return r.r.Replace(s) return r.r.Replace(s)
} }
// WriteString writes s to w with all replacements performed. // WriteString writes s to w with all replacements performed.
func (r *Replacer) WriteString(w io.Writer, s string) (n int, err error) { func (r *Replacer) WriteString(w io.Writer, s string) (n int, err error) {
r.once.Do(r.buildOnce)
return r.r.WriteString(w, s) return r.r.WriteString(w, s)
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment