]> Cypherpunks repositories - gostls13.git/commitdiff
strings: select Replacer algorithm and build machine lazily
authorBrad Fitzpatrick <bradfitz@golang.org>
Thu, 2 Aug 2018 20:02:24 +0000 (20:02 +0000)
committerBrad Fitzpatrick <bradfitz@golang.org>
Tue, 21 Aug 2018 02:50:58 +0000 (02:50 +0000)
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>
src/strings/export_test.go
src/strings/replace.go

index 17c806aa56373c0ef9230b2aa08ca3aff6fba0eb..b39cee6b1ded1601fdfbee6b849fb527a7cef586 100644 (file)
@@ -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)
 }
index 58a11a63dbeb486c4084762be656f2daa0a0b226..dbda9501945b8df85eeed51c1939ef72b3da2b73 100644 (file)
@@ -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)
 }