replace fixed-size carry buffer with dynamic slice

Replace the fixed [256]byte carry buffer with a dynamic []byte slice to support arbitrarily long lines without heap allocation during accumulation. Update all carry buffer handling logic to use len(s.carry) and append instead of fixed-size copy operations.
This commit is contained in:
Eric Coissac
2026-03-11 17:05:34 +01:00
parent 09fbc217d3
commit 8c318c480e

View File

@@ -2,13 +2,12 @@ package obiformats
import "bytes" import "bytes"
// ropeScanner reads lines from a PieceOfChunk rope without heap allocation. // ropeScanner reads lines from a PieceOfChunk rope.
// The carry buffer (stack) handles lines that span two rope nodes. // The carry buffer handles lines that span two rope nodes; it grows as needed.
type ropeScanner struct { type ropeScanner struct {
current *PieceOfChunk current *PieceOfChunk
pos int pos int
carry [256]byte // 256 gives ample margin for typical flat-file lines carry []byte
carryN int
} }
func newRopeScanner(rope *PieceOfChunk) *ropeScanner { func newRopeScanner(rope *PieceOfChunk) *ropeScanner {
@@ -21,10 +20,10 @@ func newRopeScanner(rope *PieceOfChunk) *ropeScanner {
func (s *ropeScanner) ReadLine() []byte { func (s *ropeScanner) ReadLine() []byte {
for { for {
if s.current == nil { if s.current == nil {
if s.carryN > 0 { if len(s.carry) > 0 {
n := s.carryN line := s.carry
s.carryN = 0 s.carry = s.carry[:0]
return s.carry[:n] return line
} }
return nil return nil
} }
@@ -34,13 +33,12 @@ func (s *ropeScanner) ReadLine() []byte {
if idx >= 0 { if idx >= 0 {
var line []byte var line []byte
if s.carryN == 0 { if len(s.carry) == 0 {
line = data[:idx] line = data[:idx]
} else { } else {
n := copy(s.carry[s.carryN:], data[:idx]) s.carry = append(s.carry, data[:idx]...)
s.carryN += n line = s.carry
line = s.carry[:s.carryN] s.carry = s.carry[:0]
s.carryN = 0
} }
s.pos += idx + 1 s.pos += idx + 1
if s.pos >= len(s.current.data) { if s.pos >= len(s.current.data) {
@@ -54,8 +52,7 @@ func (s *ropeScanner) ReadLine() []byte {
} }
// No \n in this node: accumulate into carry and advance // No \n in this node: accumulate into carry and advance
n := copy(s.carry[s.carryN:], data) s.carry = append(s.carry, data...)
s.carryN += n
s.current = s.current.Next() s.current = s.current.Next()
s.pos = 0 s.pos = 0
} }