2019-05-23 00:16:55 +03:00
|
|
|
package bytesutil
|
|
|
|
|
|
|
|
|
|
import (
|
2023-04-14 14:32:43 -07:00
|
|
|
"fmt"
|
2019-05-23 00:16:55 +03:00
|
|
|
"io"
|
|
|
|
|
"sync"
|
|
|
|
|
|
|
|
|
|
"github.com/VictoriaMetrics/VictoriaMetrics/lib/filestream"
|
2024-05-12 11:24:48 +02:00
|
|
|
"github.com/VictoriaMetrics/VictoriaMetrics/lib/slicesutil"
|
2019-05-23 00:16:55 +03:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// ByteBuffer implements a simple byte buffer.
|
|
|
|
|
type ByteBuffer struct {
|
|
|
|
|
// B is the underlying byte slice.
|
|
|
|
|
B []byte
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-14 14:32:43 -07:00
|
|
|
// Path returns an unique id for bb.
|
|
|
|
|
func (bb *ByteBuffer) Path() string {
|
2023-06-19 22:37:24 -07:00
|
|
|
return fmt.Sprintf("ByteBuffer/%p/mem", bb)
|
2023-04-14 14:32:43 -07:00
|
|
|
}
|
|
|
|
|
|
2019-05-23 00:16:55 +03:00
|
|
|
// Reset resets bb.
|
|
|
|
|
func (bb *ByteBuffer) Reset() {
|
|
|
|
|
bb.B = bb.B[:0]
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-10 14:10:39 +02:00
|
|
|
// Len returns the length of the data stored in bb.
|
|
|
|
|
func (bb *ByteBuffer) Len() int {
|
|
|
|
|
return len(bb.B)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// MustWrite writes p to bb.
|
|
|
|
|
func (bb *ByteBuffer) MustWrite(p []byte) {
|
|
|
|
|
bb.B = append(bb.B, p...)
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-01 20:23:48 +02:00
|
|
|
// Grow grows bb capacity, so it can accept n bytes without additional allocations.
|
|
|
|
|
func (bb *ByteBuffer) Grow(n int) {
|
|
|
|
|
bLen := len(bb.B)
|
|
|
|
|
bb.B = slicesutil.SetLength(bb.B, bLen+n)
|
|
|
|
|
bb.B = bb.B[:bLen]
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-23 00:16:55 +03:00
|
|
|
// Write appends p to bb.
|
|
|
|
|
func (bb *ByteBuffer) Write(p []byte) (int, error) {
|
2025-04-10 14:10:39 +02:00
|
|
|
bb.MustWrite(p)
|
2019-05-23 00:16:55 +03:00
|
|
|
return len(p), nil
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-10 14:10:39 +02:00
|
|
|
// WriteTo writes bb contents to w.
|
|
|
|
|
func (bb *ByteBuffer) WriteTo(w io.Writer) (int64, error) {
|
|
|
|
|
n, err := w.Write(bb.B)
|
|
|
|
|
return int64(n), err
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-18 20:37:51 +03:00
|
|
|
// ReadFrom reads all the data from r to bb until EOF.
|
|
|
|
|
func (bb *ByteBuffer) ReadFrom(r io.Reader) (int64, error) {
|
|
|
|
|
b := bb.B
|
|
|
|
|
bLen := len(b)
|
2025-03-27 14:44:00 +01:00
|
|
|
if cap(b) < 4*1024 {
|
|
|
|
|
// Pre-allocate at least 4KiB
|
|
|
|
|
b = slicesutil.SetLength(b, 4*1024)
|
|
|
|
|
}
|
2019-06-18 20:37:51 +03:00
|
|
|
offset := bLen
|
|
|
|
|
for {
|
2025-03-27 14:44:00 +01:00
|
|
|
if free := cap(b) - offset; free < (cap(b) / 16) {
|
2024-08-07 16:49:43 +02:00
|
|
|
// grow slice by 30% similar to how Go does this
|
|
|
|
|
// https://go.googlesource.com/go/+/2dda92ff6f9f07eeb110ecbf0fc2d7a0ddd27f9d
|
|
|
|
|
// higher growth rates could consume excessive memory when reading big amounts of data.
|
2025-03-27 14:44:00 +01:00
|
|
|
n := int(1.3 * float64(cap(b)))
|
|
|
|
|
b = slicesutil.SetLength(b, n)
|
2019-06-18 20:37:51 +03:00
|
|
|
}
|
2025-03-27 14:44:00 +01:00
|
|
|
n, err := r.Read(b[offset:cap(b)])
|
2019-06-18 20:37:51 +03:00
|
|
|
offset += n
|
|
|
|
|
if err != nil {
|
|
|
|
|
bb.B = b[:offset]
|
|
|
|
|
if err == io.EOF {
|
|
|
|
|
err = nil
|
|
|
|
|
}
|
|
|
|
|
return int64(offset - bLen), err
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-23 00:16:55 +03:00
|
|
|
// NewReader returns new reader for the given bb.
|
|
|
|
|
func (bb *ByteBuffer) NewReader() filestream.ReadCloser {
|
|
|
|
|
return &reader{
|
2025-04-10 14:10:39 +02:00
|
|
|
bb: bb,
|
|
|
|
|
data: ToUnsafeString(bb.B),
|
2019-05-23 00:16:55 +03:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type reader struct {
|
2025-04-10 14:10:39 +02:00
|
|
|
// bb is used only for Path() call.
|
2019-05-23 00:16:55 +03:00
|
|
|
bb *ByteBuffer
|
|
|
|
|
|
2025-04-10 14:10:39 +02:00
|
|
|
// data to read.
|
|
|
|
|
data string
|
|
|
|
|
|
|
|
|
|
// readOffset is the offset in the data for read.
|
2019-05-23 00:16:55 +03:00
|
|
|
readOffset int
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-14 14:32:43 -07:00
|
|
|
// Path returns an unique id for the underlying ByteBuffer.
|
|
|
|
|
func (r *reader) Path() string {
|
|
|
|
|
return r.bb.Path()
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-23 00:16:55 +03:00
|
|
|
// Read reads up to len(p) bytes from bb.
|
|
|
|
|
func (r *reader) Read(p []byte) (int, error) {
|
|
|
|
|
var err error
|
2025-04-10 14:10:39 +02:00
|
|
|
n := copy(p, r.data[r.readOffset:])
|
2019-05-23 00:16:55 +03:00
|
|
|
if n < len(p) {
|
|
|
|
|
err = io.EOF
|
|
|
|
|
}
|
|
|
|
|
r.readOffset += n
|
|
|
|
|
return n, err
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-17 16:32:10 +01:00
|
|
|
// MustClose closes bb for subsequent reuse.
|
2019-05-23 00:16:55 +03:00
|
|
|
func (r *reader) MustClose() {
|
|
|
|
|
r.bb = nil
|
2025-04-10 14:10:39 +02:00
|
|
|
r.data = ""
|
2019-05-23 00:16:55 +03:00
|
|
|
r.readOffset = 0
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ByteBufferPool is a pool of ByteBuffers.
|
|
|
|
|
type ByteBufferPool struct {
|
|
|
|
|
p sync.Pool
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Get obtains a ByteBuffer from bbp.
|
|
|
|
|
func (bbp *ByteBufferPool) Get() *ByteBuffer {
|
|
|
|
|
bbv := bbp.p.Get()
|
|
|
|
|
if bbv == nil {
|
|
|
|
|
return &ByteBuffer{}
|
|
|
|
|
}
|
|
|
|
|
return bbv.(*ByteBuffer)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Put puts bb into bbp.
|
|
|
|
|
func (bbp *ByteBufferPool) Put(bb *ByteBuffer) {
|
|
|
|
|
bb.Reset()
|
|
|
|
|
bbp.p.Put(bb)
|
|
|
|
|
}
|