strbuilder.go 1.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
  1. // Copyright (c) 2020 Tailscale Inc & AUTHORS All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. // Package strbuilder defines a string builder type that allocates
  5. // less than the standard library's strings.Builder by using a
  6. // sync.Pool, so it doesn't matter if the compiler can't prove that
  7. // the builder doesn't escape into the fmt package, etc.
  8. package strbuilder
  9. import (
  10. "bytes"
  11. "strconv"
  12. "sync"
  13. )
  14. var pool = sync.Pool{
  15. New: func() interface{} { return new(Builder) },
  16. }
  17. type Builder struct {
  18. bb bytes.Buffer
  19. scratch [20]byte // long enough for MinInt64, MaxUint64
  20. locked bool // in pool, not for use
  21. }
  22. // Get returns a new or reused string Builder.
  23. func Get() *Builder {
  24. b := pool.Get().(*Builder)
  25. b.bb.Reset()
  26. b.locked = false
  27. return b
  28. }
  29. // String both returns the Builder's string, and returns the builder
  30. // to the pool.
  31. func (b *Builder) String() string {
  32. if b.locked {
  33. panic("String called twiced on Builder")
  34. }
  35. s := b.bb.String()
  36. b.locked = true
  37. pool.Put(b)
  38. return s
  39. }
  40. func (b *Builder) WriteByte(v byte) error {
  41. return b.bb.WriteByte(v)
  42. }
  43. func (b *Builder) WriteString(s string) (int, error) {
  44. return b.bb.WriteString(s)
  45. }
  46. func (b *Builder) Write(p []byte) (int, error) {
  47. return b.bb.Write(p)
  48. }
  49. func (b *Builder) WriteInt(v int64) {
  50. b.Write(strconv.AppendInt(b.scratch[:0], v, 10))
  51. }
  52. func (b *Builder) WriteUint(v uint64) {
  53. b.Write(strconv.AppendUint(b.scratch[:0], v, 10))
  54. }
  55. // Grow grows the buffer's capacity, if necessary, to guarantee space
  56. // for another n bytes. After Grow(n), at least n bytes can be written
  57. // to the buffer without another allocation. If n is negative, Grow
  58. // will panic. If the buffer can't grow it will panic with
  59. // ErrTooLarge.
  60. func (b *Builder) Grow(n int) {
  61. b.bb.Grow(n)
  62. }