Skip to content

Commit 0becd17

Browse files
klauspostphilhofer
authored andcommitted
Add missing bin header functions
There is no bytes equivalent of `(m *Reader) ReadBytesHeader()` and `(mw *Writer) WriteBytesHeader`. Add `ReadBytesHeader(b []byte)` and `AppendBytesHeader(b []byte, sz uint32)`.
1 parent 82be092 commit 0becd17

File tree

4 files changed

+135
-0
lines changed

4 files changed

+135
-0
lines changed

msgp/read_bytes.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,46 @@ func ReadArrayHeaderBytes(b []byte) (sz uint32, o []byte, err error) {
253253
}
254254
}
255255

256+
// ReadBytesHeader reads the 'bin' header size
257+
// off of 'b' and returns the size and remaining bytes.
258+
// Possible errors:
259+
// - ErrShortBytes (too few bytes)
260+
// - TypeError{} (not a bin object)
261+
func ReadBytesHeader(b []byte) (sz uint32, o []byte, err error) {
262+
if len(b) < 1 {
263+
return 0, nil, ErrShortBytes
264+
}
265+
switch b[0] {
266+
case mbin8:
267+
if len(b) < 2 {
268+
err = ErrShortBytes
269+
return
270+
}
271+
sz = uint32(b[1])
272+
o = b[2:]
273+
return
274+
case mbin16:
275+
if len(b) < 3 {
276+
err = ErrShortBytes
277+
return
278+
}
279+
sz = uint32(big.Uint16(b[1:]))
280+
o = b[3:]
281+
return
282+
case mbin32:
283+
if len(b) < 5 {
284+
err = ErrShortBytes
285+
return
286+
}
287+
sz = big.Uint32(b[1:])
288+
o = b[5:]
289+
return
290+
default:
291+
err = badPrefix(BinType, b[0])
292+
return
293+
}
294+
}
295+
256296
// ReadNilBytes tries to read a "nil" byte
257297
// off of 'b' and return the remaining bytes.
258298
// Possible errors:

msgp/read_bytes_test.go

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,50 @@ func BenchmarkReadArrayHeaderBytes(b *testing.B) {
9898
}
9999
}
100100

101+
func TestReadBytesHeader(t *testing.T) {
102+
var buf bytes.Buffer
103+
en := NewWriter(&buf)
104+
105+
tests := []uint32{0, 1, 5, 49082, 1 << 16, math.MaxUint32}
106+
107+
for i, v := range tests {
108+
buf.Reset()
109+
en.WriteBytesHeader(v)
110+
en.Flush()
111+
112+
out, left, err := ReadBytesHeader(buf.Bytes())
113+
if err != nil {
114+
t.Errorf("test case %d: %s", i, err)
115+
}
116+
117+
if len(left) != 0 {
118+
t.Errorf("expected 0 bytes left; found %d", len(left))
119+
}
120+
121+
if out != v {
122+
t.Errorf("%d in; %d out", v, out)
123+
}
124+
}
125+
}
126+
127+
func BenchmarkTestReadBytesHeader(b *testing.B) {
128+
sizes := []uint32{1, 100, tuint16, tuint32}
129+
buf := make([]byte, 0, 5*len(sizes))
130+
for _, sz := range sizes {
131+
buf = AppendBytesHeader(buf, sz)
132+
}
133+
b.SetBytes(int64(len(buf) / len(sizes)))
134+
b.ReportAllocs()
135+
b.ResetTimer()
136+
o := buf
137+
for i := 0; i < b.N; i++ {
138+
_, buf, _ = ReadBytesHeader(buf)
139+
if len(buf) == 0 {
140+
buf = o
141+
}
142+
}
143+
}
144+
101145
func TestReadNilBytes(t *testing.T) {
102146
var buf bytes.Buffer
103147
en := NewWriter(&buf)

msgp/write_bytes.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,26 @@ func AppendBytes(b []byte, bts []byte) []byte {
193193
return o[:n+copy(o[n:], bts)]
194194
}
195195

196+
// AppendBytesHeader appends an 'bin' header with
197+
// the given size to the slice.
198+
func AppendBytesHeader(b []byte, sz uint32) []byte {
199+
var o []byte
200+
var n int
201+
switch {
202+
case sz <= math.MaxUint8:
203+
o, n = ensure(b, 2)
204+
prefixu8(o[n:], mbin8, uint8(sz))
205+
return o
206+
case sz <= math.MaxUint16:
207+
o, n = ensure(b, 3)
208+
prefixu16(o[n:], mbin16, uint16(sz))
209+
return o
210+
}
211+
o, n = ensure(b, 5)
212+
prefixu32(o[n:], mbin32, sz)
213+
return o
214+
}
215+
196216
// AppendBool appends a bool to the slice
197217
func AppendBool(b []byte, t bool) []byte {
198218
if t {

msgp/write_bytes_test.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,37 @@ func BenchmarkAppendArrayHeader(b *testing.B) {
9393
}
9494
}
9595

96+
func TestAppendBytesHeader(t *testing.T) {
97+
szs := []uint32{0, 1, uint32(tint8), uint32(tint16), tuint32, math.MaxUint32}
98+
var buf bytes.Buffer
99+
en := NewWriter(&buf)
100+
101+
var bts []byte
102+
for _, sz := range szs {
103+
buf.Reset()
104+
en.WriteBytesHeader(sz)
105+
en.Flush()
106+
bts = AppendBytesHeader(bts[0:0], sz)
107+
108+
if !bytes.Equal(buf.Bytes(), bts) {
109+
t.Errorf("for size %d, encoder wrote %q and append wrote %q", sz, buf.Bytes(), bts)
110+
}
111+
}
112+
}
113+
114+
func BenchmarkAppendBytesHeader(b *testing.B) {
115+
buf := make([]byte, 0, 9)
116+
N := b.N / 4
117+
b.ReportAllocs()
118+
b.ResetTimer()
119+
for i := 0; i < N; i++ {
120+
AppendBytesHeader(buf[:0], 0)
121+
AppendBytesHeader(buf[:0], uint32(tint8))
122+
AppendBytesHeader(buf[:0], tuint16)
123+
AppendBytesHeader(buf[:0], tuint32)
124+
}
125+
}
126+
96127
func TestAppendNil(t *testing.T) {
97128
var bts []byte
98129
bts = AppendNil(bts[0:0])

0 commit comments

Comments
 (0)