buffer.go 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. // Copyright 2016 The Internal 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 buffer implements a pool of pointers to byte slices.
  5. //
  6. // Example usage pattern
  7. //
  8. // p := buffer.Get(size)
  9. // b := *p // Now you can use b in any way you need.
  10. // ...
  11. // // When b will not be used anymore
  12. // buffer.Put(p)
  13. // ...
  14. // // If b or p are not going out of scope soon, optionally
  15. // b = nil
  16. // p = nil
  17. //
  18. // Otherwise the pool cannot release the buffer on garbage collection.
  19. //
  20. // Do not do
  21. //
  22. // p := buffer.Get(size)
  23. // b := *p
  24. // ...
  25. // buffer.Put(&b)
  26. //
  27. // or
  28. //
  29. // b := *buffer.Get(size)
  30. // ...
  31. // buffer.Put(&b)
  32. package buffer
  33. import (
  34. "github.com/cznic/internal/slice"
  35. "io"
  36. )
  37. // CGet returns a pointer to a byte slice of len size. The pointed to byte
  38. // slice is zeroed up to its cap. CGet panics for size < 0.
  39. //
  40. // CGet is safe for concurrent use by multiple goroutines.
  41. func CGet(size int) *[]byte { return slice.Bytes.CGet(size).(*[]byte) }
  42. // Get returns a pointer to a byte slice of len size. The pointed to byte slice
  43. // is not zeroed. Get panics for size < 0.
  44. //
  45. // Get is safe for concurrent use by multiple goroutines.
  46. func Get(size int) *[]byte { return slice.Bytes.Get(size).(*[]byte) }
  47. // Put puts a pointer to a byte slice into a pool for possible later reuse by
  48. // CGet or Get.
  49. //
  50. // Put is safe for concurrent use by multiple goroutines.
  51. func Put(p *[]byte) { slice.Bytes.Put(p) }
  52. // Bytes is similar to bytes.Buffer but may generate less garbage when properly
  53. // Closed. Zero value is ready to use.
  54. type Bytes struct {
  55. p *[]byte
  56. }
  57. // Bytes return the content of b. The result is R/O.
  58. func (b *Bytes) Bytes() []byte {
  59. if b.p != nil {
  60. return *b.p
  61. }
  62. return nil
  63. }
  64. // Close will recycle the underlying storage, if any. After Close, b is again
  65. // the zero value.
  66. func (b *Bytes) Close() error {
  67. if b.p != nil {
  68. Put(b.p)
  69. b.p = nil
  70. }
  71. return nil
  72. }
  73. // Len returns the size of content in b.
  74. func (b *Bytes) Len() int {
  75. if b.p != nil {
  76. return len(*b.p)
  77. }
  78. return 0
  79. }
  80. // Reset discard the content of Bytes while keeping the internal storage, if any.
  81. func (b *Bytes) Reset() {
  82. if b.p != nil {
  83. *b.p = (*b.p)[:0]
  84. }
  85. }
  86. // Write writes p into b and returns (len(p), nil).
  87. func (b *Bytes) Write(p []byte) (int, error) {
  88. n := b.Len()
  89. b.grow(n + len(p))
  90. copy((*b.p)[n:], p)
  91. return len(p), nil
  92. }
  93. // WriteByte writes p into b and returns nil.
  94. func (b *Bytes) WriteByte(p byte) error {
  95. n := b.Len()
  96. b.grow(n + 1)
  97. (*b.p)[n] = p
  98. return nil
  99. }
  100. // WriteTo writes b's content to w and returns the number of bytes written to w
  101. // and an error, if any.
  102. func (b *Bytes) WriteTo(w io.Writer) (int64, error) {
  103. n, err := w.Write(b.Bytes())
  104. return int64(n), err
  105. }
  106. // WriteString writes s to b and returns (len(s), nil).
  107. func (b *Bytes) WriteString(s string) (int, error) {
  108. n := b.Len()
  109. b.grow(n + len(s))
  110. copy((*b.p)[n:], s)
  111. return len(s), nil
  112. }
  113. func (b *Bytes) grow(n int) {
  114. if b.p != nil {
  115. if n <= cap(*b.p) {
  116. *b.p = (*b.p)[:n]
  117. return
  118. }
  119. np := Get(2 * n)
  120. *np = (*np)[:n]
  121. copy(*np, *b.p)
  122. Put(b.p)
  123. b.p = np
  124. return
  125. }
  126. b.p = Get(n)
  127. }