sing/common/buf/buffer.go
2023-12-24 08:03:40 +08:00

381 lines
6.6 KiB
Go

package buf
import (
"crypto/rand"
"io"
"net"
"github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/atomic"
"github.com/sagernet/sing/common/debug"
E "github.com/sagernet/sing/common/exceptions"
F "github.com/sagernet/sing/common/format"
)
type Buffer struct {
data []byte
start int
end int
capacity int
refs atomic.Int32
managed bool
}
func New() *Buffer {
return &Buffer{
data: Get(BufferSize),
capacity: BufferSize,
managed: true,
}
}
func NewPacket() *Buffer {
return &Buffer{
data: Get(UDPBufferSize),
capacity: UDPBufferSize,
managed: true,
}
}
func NewSize(size int) *Buffer {
if size == 0 {
return &Buffer{}
} else if size > 65535 {
return &Buffer{
data: make([]byte, size),
capacity: size,
}
}
return &Buffer{
data: Get(size),
capacity: size,
managed: true,
}
}
func As(data []byte) *Buffer {
return &Buffer{
data: data,
end: len(data),
capacity: len(data),
}
}
func With(data []byte) *Buffer {
return &Buffer{
data: data,
capacity: len(data),
}
}
func (b *Buffer) Byte(index int) byte {
return b.data[b.start+index]
}
func (b *Buffer) SetByte(index int, value byte) {
b.data[b.start+index] = value
}
func (b *Buffer) Extend(n int) []byte {
end := b.end + n
if end > b.capacity {
panic(F.ToString("buffer overflow: capacity ", b.capacity, ",end ", b.end, ", need ", n))
}
ext := b.data[b.end:end]
b.end = end
return ext
}
func (b *Buffer) Advance(from int) {
b.start += from
}
func (b *Buffer) Truncate(to int) {
b.end = b.start + to
}
func (b *Buffer) Write(data []byte) (n int, err error) {
if len(data) == 0 {
return
}
if b.IsFull() {
return 0, io.ErrShortBuffer
}
n = copy(b.data[b.end:b.capacity], data)
b.end += n
return
}
func (b *Buffer) ExtendHeader(n int) []byte {
if b.start < n {
panic(F.ToString("buffer overflow: capacity ", b.capacity, ",start ", b.start, ", need ", n))
}
b.start -= n
return b.data[b.start : b.start+n]
}
func (b *Buffer) WriteRandom(size int) []byte {
buffer := b.Extend(size)
common.Must1(io.ReadFull(rand.Reader, buffer))
return buffer
}
func (b *Buffer) WriteByte(d byte) error {
if b.IsFull() {
return io.ErrShortBuffer
}
b.data[b.end] = d
b.end++
return nil
}
func (b *Buffer) ReadOnceFrom(r io.Reader) (int, error) {
if b.IsFull() {
return 0, io.ErrShortBuffer
}
n, err := r.Read(b.FreeBytes())
b.end += n
return n, err
}
func (b *Buffer) ReadPacketFrom(r net.PacketConn) (int64, net.Addr, error) {
if b.IsFull() {
return 0, nil, io.ErrShortBuffer
}
n, addr, err := r.ReadFrom(b.FreeBytes())
b.end += n
return int64(n), addr, err
}
func (b *Buffer) ReadAtLeastFrom(r io.Reader, min int) (int64, error) {
if min <= 0 {
n, err := b.ReadOnceFrom(r)
return int64(n), err
}
if b.IsFull() {
return 0, io.ErrShortBuffer
}
n, err := io.ReadAtLeast(r, b.FreeBytes(), min)
b.end += n
return int64(n), err
}
func (b *Buffer) ReadFullFrom(r io.Reader, size int) (n int, err error) {
if b.end+size > b.capacity {
return 0, io.ErrShortBuffer
}
n, err = io.ReadFull(r, b.data[b.end:b.end+size])
b.end += n
return
}
func (b *Buffer) ReadFrom(reader io.Reader) (n int64, err error) {
for {
if b.IsFull() {
return 0, io.ErrShortBuffer
}
var readN int
readN, err = reader.Read(b.FreeBytes())
b.end += readN
n += int64(readN)
if err != nil {
if E.IsMulti(err, io.EOF) {
err = nil
}
return
}
}
}
func (b *Buffer) WriteRune(s rune) (int, error) {
return b.Write([]byte{byte(s)})
}
func (b *Buffer) WriteString(s string) (n int, err error) {
if len(s) == 0 {
return
}
if b.IsFull() {
return 0, io.ErrShortBuffer
}
n = copy(b.data[b.end:b.capacity], s)
b.end += n
return
}
func (b *Buffer) WriteZero() error {
if b.IsFull() {
return io.ErrShortBuffer
}
b.data[b.end] = 0
b.end++
return nil
}
func (b *Buffer) WriteZeroN(n int) error {
if b.end+n > b.capacity {
return io.ErrShortBuffer
}
common.ClearArray(b.Extend(n))
return nil
}
func (b *Buffer) ReadByte() (byte, error) {
if b.IsEmpty() {
return 0, io.EOF
}
nb := b.data[b.start]
b.start++
return nb, nil
}
func (b *Buffer) ReadBytes(n int) ([]byte, error) {
if b.end-b.start < n {
return nil, io.EOF
}
nb := b.data[b.start : b.start+n]
b.start += n
return nb, nil
}
func (b *Buffer) Read(data []byte) (n int, err error) {
if b.IsEmpty() {
return 0, io.EOF
}
n = copy(data, b.data[b.start:b.end])
b.start += n
return
}
func (b *Buffer) WriteTo(w io.Writer) (int64, error) {
n, err := w.Write(b.Bytes())
return int64(n), err
}
func (b *Buffer) Resize(start, end int) {
b.start = start
b.end = b.start + end
}
func (b *Buffer) Reserve(n int) {
if n > b.capacity {
panic(F.ToString("buffer overflow: capacity ", b.capacity, ", need ", n))
}
b.capacity -= n
}
func (b *Buffer) OverCap(n int) {
if b.capacity+n > len(b.data) {
panic(F.ToString("buffer overflow: capacity ", len(b.data), ", need ", b.capacity+n))
}
b.capacity += n
}
func (b *Buffer) Reset() {
b.start = 0
b.end = 0
b.capacity = len(b.data)
}
// Deprecated: use Reset instead.
func (b *Buffer) FullReset() {
b.Reset()
}
func (b *Buffer) IncRef() {
b.refs.Add(1)
}
func (b *Buffer) DecRef() {
b.refs.Add(-1)
}
func (b *Buffer) Release() {
if b == nil || !b.managed {
return
}
if b.refs.Load() > 0 {
return
}
common.Must(Put(b.data))
*b = Buffer{}
}
func (b *Buffer) Leak() {
if debug.Enabled {
if b == nil || !b.managed {
return
}
refs := b.refs.Load()
if refs == 0 {
panic("leaking buffer")
} else {
panic(F.ToString("leaking buffer with ", refs, " references"))
}
} else {
b.Release()
}
}
func (b *Buffer) Start() int {
return b.start
}
func (b *Buffer) Len() int {
return b.end - b.start
}
func (b *Buffer) Cap() int {
return b.capacity
}
func (b *Buffer) RawCap() int {
return len(b.data)
}
func (b *Buffer) Bytes() []byte {
return b.data[b.start:b.end]
}
func (b *Buffer) From(n int) []byte {
return b.data[b.start+n : b.end]
}
func (b *Buffer) To(n int) []byte {
return b.data[b.start : b.start+n]
}
func (b *Buffer) Range(start, end int) []byte {
return b.data[b.start+start : b.start+end]
}
func (b *Buffer) Index(start int) []byte {
return b.data[b.start+start : b.start+start]
}
func (b *Buffer) FreeLen() int {
return b.capacity - b.end
}
func (b *Buffer) FreeBytes() []byte {
return b.data[b.end:b.capacity]
}
func (b *Buffer) IsEmpty() bool {
return b.end-b.start == 0
}
func (b *Buffer) IsFull() bool {
return b.end == b.capacity
}
func (b *Buffer) ToOwned() *Buffer {
n := NewSize(len(b.data))
copy(n.data[b.start:b.end], b.data[b.start:b.end])
n.start = b.start
n.end = b.end
n.capacity = b.capacity
return n
}