From 03653db5a59cd88b481403d312d7c324b56af377 Mon Sep 17 00:00:00 2001 From: Ox Cart Date: Thu, 30 May 2019 12:17:43 -0500 Subject: [PATCH] Added ByteSlice and ByteSlicePool --- bytepool.go | 1 + byteslice.go | 81 +++++++++++++++++++++++++++++++++++++++++++++++ byteslice_test.go | 38 ++++++++++++++++++++++ go.mod | 5 +++ go.sum | 7 ++++ 5 files changed, 132 insertions(+) create mode 100644 byteslice.go create mode 100644 byteslice_test.go create mode 100644 go.mod create mode 100644 go.sum diff --git a/bytepool.go b/bytepool.go index deda16a..a5ebe05 100644 --- a/bytepool.go +++ b/bytepool.go @@ -5,6 +5,7 @@ package bpool type BytePool struct { c chan []byte w int + h int } // NewBytePool creates a new BytePool bounded to the given maxSize, with new diff --git a/byteslice.go b/byteslice.go new file mode 100644 index 0000000..7b94b39 --- /dev/null +++ b/byteslice.go @@ -0,0 +1,81 @@ +package bpool + +// WrapByteSlice wraps a []byte as a ByteSlice +func WrapByteSlice(full []byte, headerLength int) ByteSlice { + return ByteSlice{ + full: full, + current: full[headerLength:], + head: headerLength, + end: len(full), + } +} + +// ByteSlice provides a wrapper around []byte with some added convenience +type ByteSlice struct { + full []byte + current []byte + head int + end int +} + +// ResliceTo reslices the end of the current slice. +func (b ByteSlice) ResliceTo(end int) ByteSlice { + return ByteSlice{ + full: b.full, + current: b.current[:end], + head: b.head, + end: b.head + end, + } +} + +// Bytes returns the current slice +func (b ByteSlice) Bytes() []byte { + return b.current +} + +// BytesWithHeader returns the current slice preceded by the header +func (b ByteSlice) BytesWithHeader() []byte { + return b.full[:b.end] +} + +// Full returns the full original buffer underlying the ByteSlice +func (b ByteSlice) Full() []byte { + return b.full +} + +// ByteSlicePool is a bool of byte slices +type ByteSlicePool interface { + // Get gets a byte slice from the pool + GetSlice() ByteSlice + // Put returns a byte slice to the pool + PutSlice(ByteSlice) + // NumPooled returns the number of currently pooled items + NumPooled() int +} + +// NewByteSlicePool creates a new ByteSlicePool bounded to the +// given maxSize, with new byte arrays sized based on width +func NewByteSlicePool(maxSize int, width int) ByteSlicePool { + return NewHeaderPreservingByteSlicePool(maxSize, width, 0) +} + +// NewHeaderPreservingByteSlicePool creates a new ByteSlicePool bounded to the +// given maxSize, with new byte arrays sized based on width and headerLength +// preserved at the beginning of the slice. +func NewHeaderPreservingByteSlicePool(maxSize int, width int, headerLength int) ByteSlicePool { + return &BytePool{ + c: make(chan []byte, maxSize), + w: width + headerLength, + h: headerLength, + } +} + +// GetSlice implements the method from interface ByteSlicePool +func (bp *BytePool) GetSlice() ByteSlice { + return WrapByteSlice(bp.Get(), bp.h) +} + +// PutSlice implements the method from interface ByteSlicePool +func (bp *BytePool) PutSlice(b ByteSlice) { + bp.Put(b.Full()) +} diff --git a/byteslice_test.go b/byteslice_test.go new file mode 100644 index 0000000..f7fc31a --- /dev/null +++ b/byteslice_test.go @@ -0,0 +1,38 @@ +package bpool + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestByteSlice(t *testing.T) { + full := []byte("abcde") + bs := WrapByteSlice(full, 1) + assert.EqualValues(t, full[1:], bs.Bytes()) + assert.EqualValues(t, full, bs.BytesWithHeader()) + assert.EqualValues(t, full, bs.Full()) + bs = bs.ResliceTo(2) + assert.EqualValues(t, full[1:3], bs.Bytes()) + assert.EqualValues(t, full[:3], bs.BytesWithHeader()) + assert.EqualValues(t, full, bs.Full()) + bs = bs.ResliceTo(1) + assert.EqualValues(t, full[1:2], bs.Bytes()) + assert.EqualValues(t, full[:2], bs.BytesWithHeader()) + assert.EqualValues(t, full, bs.Full()) + +} + +func TestHeaderPreservingByteSlicePool(t *testing.T) { + full := []byte{0, 0, 'a', 'b', 'c'} + data := full[2:] + pool := NewHeaderPreservingByteSlicePool(1, 3, 2) + b := pool.GetSlice() + copy(b.Bytes(), data) + assert.Equal(t, data, b.Bytes()) + assert.Equal(t, full, b.Full()) + pool.PutSlice(b) + assert.Equal(t, 1, pool.NumPooled()) + pool.PutSlice(WrapByteSlice(full, 2)) + assert.Equal(t, 1, pool.NumPooled(), "Pool should not grow beyond its size limit") +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..9bb3147 --- /dev/null +++ b/go.mod @@ -0,0 +1,5 @@ +module github.com/oxtoacart/bpool + +go 1.12 + +require github.com/stretchr/testify v1.3.0 diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..4347755 --- /dev/null +++ b/go.sum @@ -0,0 +1,7 @@ +github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=