File: buffer.go

package info (click to toggle)
golang-modernc-internal 1.0.0-2
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, forky, sid, trixie
  • size: 148 kB
  • sloc: makefile: 124
file content (146 lines) | stat: -rw-r--r-- 3,220 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
// Copyright 2016 The Internal 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 buffer implements a pool of pointers to byte slices.
//
// Example usage pattern
//
//	p := buffer.Get(size)
//	b := *p	// Now you can use b in any way you need.
//	...
//	// When b will not be used anymore
//	buffer.Put(p)
//	...
//	// If b or p are not going out of scope soon, optionally
//	b = nil
//	p = nil
//
// Otherwise the pool cannot release the buffer on garbage collection.
//
// Do not do
//
//	p := buffer.Get(size)
//	b := *p
//	...
//	buffer.Put(&b)
//
// or
//
//	b := *buffer.Get(size)
//	...
//	buffer.Put(&b)
package buffer // import "modernc.org/internal/buffer"

import (
	"modernc.org/internal/slice"
	"io"
)

// CGet returns a pointer to a byte slice of len size. The pointed to byte
// slice is zeroed up to its cap. CGet panics for size < 0.
//
// CGet is safe for concurrent use by multiple goroutines.
func CGet(size int) *[]byte { return slice.Bytes.CGet(size).(*[]byte) }

// Get returns a pointer to a byte slice of len size. The pointed to byte slice
// is not zeroed. Get panics for size < 0.
//
// Get is safe for concurrent use by multiple goroutines.
func Get(size int) *[]byte { return slice.Bytes.Get(size).(*[]byte) }

// Put puts a pointer to a byte slice into a pool for possible later reuse by
// CGet or Get.
//
// Put is safe for concurrent use by multiple goroutines.
func Put(p *[]byte) { slice.Bytes.Put(p) }

// Bytes is similar to bytes.Buffer but may generate less garbage when properly
// Closed. Zero value is ready to use.
type Bytes struct {
	p *[]byte
}

// Bytes return the content of b. The result is R/O.
func (b *Bytes) Bytes() []byte {
	if b.p != nil {
		return *b.p
	}

	return nil
}

// Close will recycle the underlying storage, if any. After Close, b is again
// the zero value.
func (b *Bytes) Close() error {
	if b.p != nil {
		Put(b.p)
		b.p = nil
	}
	return nil
}

// Len returns the size of content in b.
func (b *Bytes) Len() int {
	if b.p != nil {
		return len(*b.p)
	}

	return 0
}

// Reset discard the content of Bytes while keeping the internal storage, if any.
func (b *Bytes) Reset() {
	if b.p != nil {
		*b.p = (*b.p)[:0]
	}
}

// Write writes p into b and returns (len(p), nil).
func (b *Bytes) Write(p []byte) (int, error) {
	n := b.Len()
	b.grow(n + len(p))
	copy((*b.p)[n:], p)
	return len(p), nil
}

// WriteByte writes p into b and returns nil.
func (b *Bytes) WriteByte(p byte) error {
	n := b.Len()
	b.grow(n + 1)
	(*b.p)[n] = p
	return nil
}

// WriteTo writes b's content to w and returns the number of bytes written to w
// and an error, if any.
func (b *Bytes) WriteTo(w io.Writer) (int64, error) {
	n, err := w.Write(b.Bytes())
	return int64(n), err
}

// WriteString writes s to b and returns (len(s), nil).
func (b *Bytes) WriteString(s string) (int, error) {
	n := b.Len()
	b.grow(n + len(s))
	copy((*b.p)[n:], s)
	return len(s), nil
}

func (b *Bytes) grow(n int) {
	if b.p != nil {
		if n <= cap(*b.p) {
			*b.p = (*b.p)[:n]
			return
		}

		np := Get(2 * n)
		*np = (*np)[:n]
		copy(*np, *b.p)
		Put(b.p)
		b.p = np
		return
	}

	b.p = Get(n)
}