mirror of
https://github.com/yuanyuanxiang/SimpleRemoter.git
synced 2026-01-22 07:14:15 +08:00
186 lines
3.4 KiB
Go
186 lines
3.4 KiB
Go
package buffer
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"sync"
|
|
)
|
|
|
|
// Buffer is a thread-safe dynamic buffer for network I/O
|
|
type Buffer struct {
|
|
data []byte
|
|
mu sync.RWMutex
|
|
offset int // read offset for lazy compaction
|
|
}
|
|
|
|
// New creates a new buffer with optional initial capacity
|
|
func New(capacity ...int) *Buffer {
|
|
cap := 4096
|
|
if len(capacity) > 0 && capacity[0] > 0 {
|
|
cap = capacity[0]
|
|
}
|
|
return &Buffer{
|
|
data: make([]byte, 0, cap),
|
|
}
|
|
}
|
|
|
|
// Write appends data to the buffer
|
|
func (b *Buffer) Write(p []byte) (int, error) {
|
|
b.mu.Lock()
|
|
defer b.mu.Unlock()
|
|
b.data = append(b.data, p...)
|
|
return len(p), nil
|
|
}
|
|
|
|
// WriteUint32 writes a uint32 in little-endian format
|
|
func (b *Buffer) WriteUint32(v uint32) {
|
|
buf := make([]byte, 4)
|
|
binary.LittleEndian.PutUint32(buf, v)
|
|
b.Write(buf)
|
|
}
|
|
|
|
// Read reads and removes data from the buffer
|
|
func (b *Buffer) Read(n int) []byte {
|
|
b.mu.Lock()
|
|
defer b.mu.Unlock()
|
|
|
|
available := len(b.data) - b.offset
|
|
if n > available {
|
|
n = available
|
|
}
|
|
if n <= 0 {
|
|
return nil
|
|
}
|
|
|
|
result := make([]byte, n)
|
|
copy(result, b.data[b.offset:b.offset+n])
|
|
b.offset += n
|
|
|
|
// Compact when offset is large enough
|
|
if b.offset > len(b.data)/2 && b.offset > 1024 {
|
|
b.compact()
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
// Peek returns data without removing it
|
|
func (b *Buffer) Peek(n int) []byte {
|
|
b.mu.RLock()
|
|
defer b.mu.RUnlock()
|
|
|
|
available := len(b.data) - b.offset
|
|
if n > available {
|
|
n = available
|
|
}
|
|
if n <= 0 {
|
|
return nil
|
|
}
|
|
|
|
result := make([]byte, n)
|
|
copy(result, b.data[b.offset:b.offset+n])
|
|
return result
|
|
}
|
|
|
|
// PeekAt returns data at a specific offset without removing it
|
|
func (b *Buffer) PeekAt(offset, n int) []byte {
|
|
b.mu.RLock()
|
|
defer b.mu.RUnlock()
|
|
|
|
start := b.offset + offset
|
|
if start >= len(b.data) {
|
|
return nil
|
|
}
|
|
|
|
end := start + n
|
|
if end > len(b.data) {
|
|
end = len(b.data)
|
|
}
|
|
|
|
result := make([]byte, end-start)
|
|
copy(result, b.data[start:end])
|
|
return result
|
|
}
|
|
|
|
// Skip removes n bytes from the beginning
|
|
func (b *Buffer) Skip(n int) int {
|
|
b.mu.Lock()
|
|
defer b.mu.Unlock()
|
|
|
|
available := len(b.data) - b.offset
|
|
if n > available {
|
|
n = available
|
|
}
|
|
b.offset += n
|
|
|
|
// Compact when offset is large enough
|
|
if b.offset > len(b.data)/2 && b.offset > 1024 {
|
|
b.compact()
|
|
}
|
|
|
|
return n
|
|
}
|
|
|
|
// Len returns the length of unread data
|
|
func (b *Buffer) Len() int {
|
|
b.mu.RLock()
|
|
defer b.mu.RUnlock()
|
|
return len(b.data) - b.offset
|
|
}
|
|
|
|
// Bytes returns all unread data without removing it
|
|
func (b *Buffer) Bytes() []byte {
|
|
b.mu.RLock()
|
|
defer b.mu.RUnlock()
|
|
|
|
n := len(b.data) - b.offset
|
|
if n <= 0 {
|
|
return nil
|
|
}
|
|
|
|
result := make([]byte, n)
|
|
copy(result, b.data[b.offset:])
|
|
return result
|
|
}
|
|
|
|
// Clear removes all data from the buffer
|
|
func (b *Buffer) Clear() {
|
|
b.mu.Lock()
|
|
defer b.mu.Unlock()
|
|
b.data = b.data[:0]
|
|
b.offset = 0
|
|
}
|
|
|
|
// compact moves remaining data to the beginning
|
|
func (b *Buffer) compact() {
|
|
if b.offset > 0 {
|
|
remaining := len(b.data) - b.offset
|
|
copy(b.data[:remaining], b.data[b.offset:])
|
|
b.data = b.data[:remaining]
|
|
b.offset = 0
|
|
}
|
|
}
|
|
|
|
// GetByte returns a single byte at offset
|
|
func (b *Buffer) GetByte(offset int) byte {
|
|
b.mu.RLock()
|
|
defer b.mu.RUnlock()
|
|
|
|
idx := b.offset + offset
|
|
if idx >= len(b.data) {
|
|
return 0
|
|
}
|
|
return b.data[idx]
|
|
}
|
|
|
|
// GetUint32 returns a uint32 at offset in little-endian format
|
|
func (b *Buffer) GetUint32(offset int) uint32 {
|
|
b.mu.RLock()
|
|
defer b.mu.RUnlock()
|
|
|
|
idx := b.offset + offset
|
|
if idx+4 > len(b.data) {
|
|
return 0
|
|
}
|
|
return binary.LittleEndian.Uint32(b.data[idx : idx+4])
|
|
}
|