|
|
@@ -0,0 +1,74 @@
|
|
|
+// Copyright (c) 2020 Tailscale Inc & 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 strbuilder defines a string builder type that allocates
|
|
|
+// less than the standard library's strings.Builder by using a
|
|
|
+// sync.Pool, so it doesn't matter if the compiler can't prove that
|
|
|
+// the builder doesn't escape into the fmt package, etc.
|
|
|
+package strbuilder
|
|
|
+
|
|
|
+import (
|
|
|
+ "bytes"
|
|
|
+ "strconv"
|
|
|
+ "sync"
|
|
|
+)
|
|
|
+
|
|
|
+var pool = sync.Pool{
|
|
|
+ New: func() interface{} { return new(Builder) },
|
|
|
+}
|
|
|
+
|
|
|
+type Builder struct {
|
|
|
+ bb bytes.Buffer
|
|
|
+ scratch [20]byte // long enough for MinInt64, MaxUint64
|
|
|
+ locked bool // in pool, not for use
|
|
|
+}
|
|
|
+
|
|
|
+// Get returns a new or reused string Builder.
|
|
|
+func Get() *Builder {
|
|
|
+ b := pool.Get().(*Builder)
|
|
|
+ b.bb.Reset()
|
|
|
+ b.locked = false
|
|
|
+ return b
|
|
|
+}
|
|
|
+
|
|
|
+// String both returns the Builder's string, and returns the builder
|
|
|
+// to the pool.
|
|
|
+func (b *Builder) String() string {
|
|
|
+ if b.locked {
|
|
|
+ panic("String called twiced on Builder")
|
|
|
+ }
|
|
|
+ s := b.bb.String()
|
|
|
+ b.locked = true
|
|
|
+ pool.Put(b)
|
|
|
+ return s
|
|
|
+}
|
|
|
+
|
|
|
+func (b *Builder) WriteByte(v byte) error {
|
|
|
+ return b.bb.WriteByte(v)
|
|
|
+}
|
|
|
+
|
|
|
+func (b *Builder) WriteString(s string) (int, error) {
|
|
|
+ return b.bb.WriteString(s)
|
|
|
+}
|
|
|
+
|
|
|
+func (b *Builder) Write(p []byte) (int, error) {
|
|
|
+ return b.bb.Write(p)
|
|
|
+}
|
|
|
+
|
|
|
+func (b *Builder) WriteInt(v int64) {
|
|
|
+ b.Write(strconv.AppendInt(b.scratch[:0], v, 10))
|
|
|
+}
|
|
|
+
|
|
|
+func (b *Builder) WriteUint(v uint64) {
|
|
|
+ b.Write(strconv.AppendUint(b.scratch[:0], v, 10))
|
|
|
+}
|
|
|
+
|
|
|
+// Grow grows the buffer's capacity, if necessary, to guarantee space
|
|
|
+// for another n bytes. After Grow(n), at least n bytes can be written
|
|
|
+// to the buffer without another allocation. If n is negative, Grow
|
|
|
+// will panic. If the buffer can't grow it will panic with
|
|
|
+// ErrTooLarge.
|
|
|
+func (b *Builder) Grow(n int) {
|
|
|
+ b.bb.Grow(n)
|
|
|
+}
|