Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
117 changes: 117 additions & 0 deletions pkg/internal/largebuf/large_buffer.go
Original file line number Diff line number Diff line change
Expand Up @@ -543,6 +543,123 @@ func (r *LargeBufferReader) Bytes() []byte {
return b
}

// ── Cursor-based scalar helpers ───────────────────────────────────────────────
//
// Each helper reads a fixed-width integer at the current cursor position and advances it.
// All delegate to ReadN: zero-copy within a chunk, scratch-backed across boundaries.

// ReadU8 reads a uint8 at the current cursor position.
func (r *LargeBufferReader) ReadU8() (uint8, error) {
b, err := r.ReadN(1)
if err != nil {
return 0, err
}

return b[0], nil
}

// ReadU16BE reads a big-endian uint16 at the current cursor position.
func (r *LargeBufferReader) ReadU16BE() (uint16, error) {
b, err := r.ReadN(2)
if err != nil {
return 0, err
}

return binary.BigEndian.Uint16(b), nil
}
Comment thread
rafaelroquetto marked this conversation as resolved.

// ReadI16BE reads a big-endian int16 at the current cursor position.
func (r *LargeBufferReader) ReadI16BE() (int16, error) {
v, err := r.ReadU16BE()

return int16(v), err
}

// ReadU32BE reads a big-endian uint32 at the current cursor position.
func (r *LargeBufferReader) ReadU32BE() (uint32, error) {
b, err := r.ReadN(4)
if err != nil {
return 0, err
}

return binary.BigEndian.Uint32(b), nil
}

// ReadI32BE reads a big-endian int32 at the current cursor position.
func (r *LargeBufferReader) ReadI32BE() (int32, error) {
v, err := r.ReadU32BE()

return int32(v), err
}

// ReadU64BE reads a big-endian uint64 at the current cursor position.
func (r *LargeBufferReader) ReadU64BE() (uint64, error) {
b, err := r.ReadN(8)
if err != nil {
return 0, err
}

return binary.BigEndian.Uint64(b), nil
}

// ReadI64BE reads a big-endian int64 at the current cursor position.
func (r *LargeBufferReader) ReadI64BE() (int64, error) {
v, err := r.ReadU64BE()

return int64(v), err
}

// ReadU16LE reads a little-endian uint16 at the current cursor position.
func (r *LargeBufferReader) ReadU16LE() (uint16, error) {
b, err := r.ReadN(2)
if err != nil {
return 0, err
}

return binary.LittleEndian.Uint16(b), nil
}

// ReadI16LE reads a little-endian int16 at the current cursor position.
func (r *LargeBufferReader) ReadI16LE() (int16, error) {
v, err := r.ReadU16LE()

return int16(v), err
}

// ReadU32LE reads a little-endian uint32 at the current cursor position.
func (r *LargeBufferReader) ReadU32LE() (uint32, error) {
b, err := r.ReadN(4)
if err != nil {
return 0, err
}

return binary.LittleEndian.Uint32(b), nil
}

// ReadI32LE reads a little-endian int32 at the current cursor position.
func (r *LargeBufferReader) ReadI32LE() (int32, error) {
v, err := r.ReadU32LE()

return int32(v), err
}

// ReadU64LE reads a little-endian uint64 at the current cursor position.
func (r *LargeBufferReader) ReadU64LE() (uint64, error) {
b, err := r.ReadN(8)
if err != nil {
return 0, err
}

return binary.LittleEndian.Uint64(b), nil
}

// ReadI64LE reads a little-endian int64 at the current cursor position.
func (r *LargeBufferReader) ReadI64LE() (int64, error) {
v, err := r.ReadU64LE()

return int64(v), err
}

// copyN copies exactly len(dst) bytes from the current read position into dst, advancing the
// cursor. Assumes the caller has already verified that len(dst) <= r.Remaining().
func (r *LargeBufferReader) copyN(dst []byte) {
Expand Down
209 changes: 209 additions & 0 deletions pkg/internal/largebuf/large_buffer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -974,6 +974,215 @@ func TestCursorUnchanged_byAbsoluteOffsetMethods(t *testing.T) {
assert.Equal(t, before, r.ReadOffset(), "U32LEAt must not move cursor")
}

// ── Cursor-based scalar helpers ───────────────────────────────────────────────

func TestReaderScalarBE_withinSingleChunk(t *testing.T) {
// Sequential layout: U8 | U16BE | U32BE | U64BE | I16BE | I32BE | I64BE
data := []byte{
0x42,
0x01, 0x02,
0x01, 0x02, 0x03, 0x04,
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
0x01, 0x02,
0x01, 0x02, 0x03, 0x04,
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
}
lb := NewLargeBufferFrom(data)
r := lb.NewReader()

u8, err := r.ReadU8()
require.NoError(t, err)
assert.Equal(t, uint8(0x42), u8)

u16, err := r.ReadU16BE()
require.NoError(t, err)
assert.Equal(t, uint16(0x0102), u16)

u32, err := r.ReadU32BE()
require.NoError(t, err)
assert.Equal(t, uint32(0x01020304), u32)

u64, err := r.ReadU64BE()
require.NoError(t, err)
assert.Equal(t, uint64(0x0102030405060708), u64)

i16, err := r.ReadI16BE()
require.NoError(t, err)
assert.Equal(t, int16(0x0102), i16)

i32, err := r.ReadI32BE()
require.NoError(t, err)
assert.Equal(t, int32(0x01020304), i32)

i64, err := r.ReadI64BE()
require.NoError(t, err)
assert.Equal(t, int64(0x0102030405060708), i64)

assert.Equal(t, 0, r.Remaining())
}

func TestReaderScalarBE_crossChunkBoundary(t *testing.T) {
lb := NewLargeBuffer()
lb.AppendChunk([]byte{0x01, 0x02})
lb.AppendChunk([]byte{0x03, 0x04, 0x05, 0x06, 0x07, 0x08})

r := lb.NewReader()

u32, err := r.ReadU32BE()
require.NoError(t, err)
assert.Equal(t, uint32(0x01020304), u32)

r.Reset()
u64, err := r.ReadU64BE()
require.NoError(t, err)
assert.Equal(t, uint64(0x0102030405060708), u64)
}

func TestReaderScalarBE_signedNegativeValues(t *testing.T) {
lb := NewLargeBufferFrom(bytes.Repeat([]byte{0xFF}, 14)) // 2+4+8 bytes
r := lb.NewReader()

i16, err := r.ReadI16BE()
require.NoError(t, err)
assert.Equal(t, int16(-1), i16)

i32, err := r.ReadI32BE()
require.NoError(t, err)
assert.Equal(t, int32(-1), i32)

i64, err := r.ReadI64BE()
require.NoError(t, err)
assert.Equal(t, int64(-1), i64)
}

func TestReaderScalarLE_withinSingleChunk(t *testing.T) {
// Sequential layout: U16LE | U32LE | U64LE | I16LE | I32LE | I64LE
data := []byte{
0x02, 0x01,
0x04, 0x03, 0x02, 0x01,
0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01,
0x02, 0x01,
0x04, 0x03, 0x02, 0x01,
0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01,
}
lb := NewLargeBufferFrom(data)
r := lb.NewReader()

u16, err := r.ReadU16LE()
require.NoError(t, err)
assert.Equal(t, uint16(0x0102), u16)

u32, err := r.ReadU32LE()
require.NoError(t, err)
assert.Equal(t, uint32(0x01020304), u32)

u64, err := r.ReadU64LE()
require.NoError(t, err)
assert.Equal(t, uint64(0x0102030405060708), u64)

i16, err := r.ReadI16LE()
require.NoError(t, err)
assert.Equal(t, int16(0x0102), i16)

i32, err := r.ReadI32LE()
require.NoError(t, err)
assert.Equal(t, int32(0x01020304), i32)

i64, err := r.ReadI64LE()
require.NoError(t, err)
assert.Equal(t, int64(0x0102030405060708), i64)

assert.Equal(t, 0, r.Remaining())
}

func TestReaderScalarLE_crossChunkBoundary(t *testing.T) {
lb := NewLargeBuffer()
lb.AppendChunk([]byte{0x04, 0x03})
lb.AppendChunk([]byte{0x02, 0x01, 0x08, 0x07, 0x06, 0x05})

r := lb.NewReader()

u32, err := r.ReadU32LE()
require.NoError(t, err)
assert.Equal(t, uint32(0x01020304), u32)

r.Reset()
u64, err := r.ReadU64LE()
require.NoError(t, err)
assert.Equal(t, uint64(0x0506070801020304), u64)
}

func TestReaderScalarLE_signedNegativeValues(t *testing.T) {
lb := NewLargeBufferFrom(bytes.Repeat([]byte{0xFF}, 14)) // 2+4+8 bytes
r := lb.NewReader()

i16, err := r.ReadI16LE()
require.NoError(t, err)
assert.Equal(t, int16(-1), i16)

i32, err := r.ReadI32LE()
require.NoError(t, err)
assert.Equal(t, int32(-1), i32)

i64, err := r.ReadI64LE()
require.NoError(t, err)
assert.Equal(t, int64(-1), i64)
}

func TestReaderScalar_advancesCursor(t *testing.T) {
lb := NewLargeBufferFrom(bytes.Repeat([]byte{0x00}, 16))
r := lb.NewReader()

assert.Equal(t, 16, r.Remaining())
_, err := r.ReadU8()
require.NoError(t, err)
assert.Equal(t, 15, r.Remaining())
_, err = r.ReadU16BE()
require.NoError(t, err)
assert.Equal(t, 13, r.Remaining())
_, err = r.ReadU32BE()
require.NoError(t, err)
assert.Equal(t, 9, r.Remaining())
_, err = r.ReadU64BE()
require.NoError(t, err)
assert.Equal(t, 1, r.Remaining())
}

func TestReaderScalar_tooShort_returnsError(t *testing.T) {
lb := NewLargeBufferFrom([]byte{0x01, 0x02})
r := lb.NewReader()

_, _ = r.ReadU16BE() // consume all bytes

_, err := r.ReadU8()
require.Error(t, err)

r.Reset()
_, _ = r.ReadU8()
_, err = r.ReadU16BE() // only 1 byte left
require.Error(t, err)
}

func TestReaderScalar_zeroAllocs(t *testing.T) {
lb := NewLargeBufferFrom(bytes.Repeat([]byte{0x01}, 64))
r := lb.NewReader()
// lastErr is declared outside the closure so require.NoError can be called
// after AllocsPerRun as calling it inside the closure would itself allocate.
var lastErr error

allocs := testing.AllocsPerRun(1000, func() {
r.Reset()
for r.Remaining() >= 4 {
if _, lastErr = r.ReadU32BE(); lastErr != nil {
break
}
}
})

require.NoError(t, lastErr)
assert.Zero(t, allocs, "cursor scalar reads within a single chunk must be zero-alloc")
}

// ── Zero-alloc verification for hot path ─────────────────────────────────────

func TestReadN_singleChunk_zeroAllocsWithBinaryDecode(t *testing.T) {
Expand Down