diff --git a/common/alloc/buffer.go b/common/alloc/buffer.go index 929d2a624..eea2866c2 100644 --- a/common/alloc/buffer.go +++ b/common/alloc/buffer.go @@ -5,6 +5,10 @@ import ( "sync" ) +const ( + DefaultOffset = 16 +) + func Release(buffer *Buffer) { if buffer != nil { buffer.Release() @@ -22,9 +26,10 @@ func Len(buffer *Buffer) int { // the buffer into an internal buffer pool, in order to recreate a buffer more // quickly. type Buffer struct { - head []byte - pool *bufferPool - Value []byte + head []byte + pool *bufferPool + Value []byte + offset int } // Release recycles the buffer into an internal buffer pool. @@ -38,7 +43,8 @@ func (b *Buffer) Release() { // Clear clears the content of the buffer, results an empty buffer with // Len() = 0. func (b *Buffer) Clear() *Buffer { - b.Value = b.head[:0] + b.offset = DefaultOffset + b.Value = b.head[b.offset:b.offset] return b } @@ -54,6 +60,19 @@ func (b *Buffer) Append(data []byte) *Buffer { return b } +// Prepend prepends bytes in front of the buffer. Caller must ensure total bytes prepended is +// no more than 16 bytes. +func (b *Buffer) Prepend(data []byte) *Buffer { + newoffset := b.offset - len(data) + if newoffset < 0 { + newoffset = 0 + } + copy(b.head[newoffset:], data) + b.Value = b.head[newoffset : b.offset+len(b.Value)] + b.offset = newoffset + return b +} + func (b *Buffer) Bytes() []byte { return b.Value } @@ -125,9 +144,10 @@ func (p *bufferPool) allocate() *Buffer { b = p.allocator.Get().([]byte) } return &Buffer{ - head: b, - pool: p, - Value: b, + head: b, + pool: p, + Value: b[DefaultOffset:], + offset: DefaultOffset, } } diff --git a/common/alloc/buffer_test.go b/common/alloc/buffer_test.go index 77ee7a1c6..192e77174 100644 --- a/common/alloc/buffer_test.go +++ b/common/alloc/buffer_test.go @@ -32,3 +32,19 @@ func TestBufferIsFull(t *testing.T) { buffer.Clear() assert.Bool(buffer.IsFull()).IsFalse() } + +func TestBufferPrepend(t *testing.T) { + v2testing.Current(t) + + buffer := NewBuffer().Clear() + defer buffer.Release() + + buffer.Append([]byte{'a', 'b', 'c'}) + buffer.Prepend([]byte{'x', 'y', 'z'}) + + assert.Int(buffer.Len()).Equals(6) + assert.Bytes(buffer.Value).Equals([]byte("xyzabc")) + + buffer.Prepend([]byte{'u', 'v', 'w'}) + assert.Bytes(buffer.Value).Equals([]byte("uvwxyzabc")) +}