Skip to content

Commit 5dd1706

Browse files
committed
slice improvements
1 parent 4ce3249 commit 5dd1706

File tree

8 files changed

+205
-70
lines changed

8 files changed

+205
-70
lines changed

accumulated_buffer.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,20 +9,20 @@ package msgpack
99

1010
func newPreallocBuf() *preallocBuf {
1111
return &preallocBuf{
12-
buf: make([]byte, 1024),
12+
buf: make([]byte, accBufSize),
1313
index: 0,
1414
}
1515
}
1616

1717
func (g *preallocBuf) allocateBuffer(len int) []byte {
18-
if g.index+len < 1024 {
18+
if g.index+len < accBufSize {
1919
g.index += len
2020
return g.buf[g.index-len : g.index]
2121
}
22-
if len >= 1024 {
22+
if len >= accBufMax {
2323
return make([]byte, len)
2424
}
25-
g.buf = make([]byte, 1024)
25+
g.buf = make([]byte, accBufSize)
2626
g.index = len
2727
return g.buf[0:len]
2828
}

decode_complex.go

Lines changed: 15 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -8,20 +8,20 @@
88
package msgpack
99

1010
func (d *Decoder) decodeFixMap() (map[string]interface{}, error) {
11-
var len = d.nextByte ^ msgPackFlagFixMap
11+
var len = int(d.nextByte ^ msgPackFlagFixMap)
1212

1313
if len < 4 {
1414
return d.mapDecoderFuncsByLen[len]()
1515
}
1616

17-
return d.decodeMapAny(int(len))
17+
return d.decodeMapAny(len)
1818
}
1919

2020
func (d *Decoder) decodeMap16() (map[string]interface{}, error) {
2121
var len, err = d.readLen16()
2222

2323
if err != nil {
24-
return nil, err
24+
return map[string]interface{}{}, err
2525
}
2626

2727
return d.decodeMapAny(len)
@@ -31,50 +31,38 @@ func (d *Decoder) decodeMap32() (map[string]interface{}, error) {
3131
var len, err = d.readLen32()
3232

3333
if err != nil {
34-
return nil, err
34+
return map[string]interface{}{}, err
3535
}
3636

3737
return d.decodeMapAny(len)
3838
}
3939

4040
func (d *Decoder) decodeFixSlice() ([]interface{}, error) {
41-
return d.decodeSlice(int(d.nextByte ^ msgPackFlagFixArray))
41+
var len = int(d.nextByte ^ msgPackFlagFixArray)
42+
43+
if len < 4 {
44+
return d.sliceDecoderFuncsByLen[len]()
45+
}
46+
47+
return d.decodeSliceAny(len)
4248
}
4349

4450
func (d *Decoder) decodeSlice16() ([]interface{}, error) {
4551
var len, err = d.readLen16()
4652

4753
if err != nil {
48-
return nil, err
54+
return []interface{}{}, err
4955
}
5056

51-
return d.decodeSlice(len)
57+
return d.decodeSliceAny(len)
5258
}
5359

5460
func (d *Decoder) decodeSlice32() ([]interface{}, error) {
5561
var len, err = d.readLen32()
5662

5763
if err != nil {
58-
return nil, err
59-
}
60-
61-
return d.decodeSlice(len)
62-
}
63-
64-
func (d *Decoder) decodeSlice(len int) ([]interface{}, error) {
65-
var (
66-
err error
67-
s = make([]interface{}, len)
68-
i = 0
69-
)
70-
71-
for ; i < len; i++ {
72-
var value interface{}
73-
if err = d.handleNext(&value); err != nil {
74-
return nil, err
75-
}
76-
s[i] = value
64+
return []interface{}{}, err
7765
}
7866

79-
return s, nil
67+
return d.decodeSliceAny(len)
8068
}

globals.go

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,6 @@ const (
3939
max5BitPlusOne = (1 << 5)
4040
max4BitPlusOne = (1 << 4)
4141
negFixIntMask = (-1 << 5)
42-
)
43-
44-
var (
45-
emptyMap = make(map[string]interface{}, 0)
42+
accBufSize = 4 << 10
43+
accBufMax = 1 << 10
4644
)

helpers.go

Lines changed: 9 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -10,43 +10,32 @@ package msgpack
1010
import "unsafe"
1111

1212
func (d *Decoder) readLen16() (int, error) {
13-
var err error
14-
15-
if d.twoBytes[0], err = d.r.ReadByte(); err != nil {
16-
return 0, err
17-
}
18-
d.twoBytes[1], err = d.r.ReadByte()
19-
13+
var _, err = d.r.Read(d.twoBytes[:])
2014
return int(d.twoBytes[0])<<8 | int(d.twoBytes[1]), err
2115
}
2216

2317
func (d *Decoder) readLen32() (int, error) {
24-
var err error
25-
26-
if _, err = d.r.Read(d.fourBytes[:]); err != nil {
27-
return 0, err
28-
}
29-
30-
return int(d.fourBytes[0])<<24 | int(d.fourBytes[1])<<16 | int(d.fourBytes[2])<<8 | int(d.fourBytes[3]), nil
18+
var _, err = d.r.Read(d.fourBytes[:])
19+
return int(d.fourBytes[0])<<24 | int(d.fourBytes[1])<<16 | int(d.fourBytes[2])<<8 | int(d.fourBytes[3]), err
3120
}
3221

3322
func (d *Decoder) readFull(buf unsafe.Pointer) error {
3423
var (
35-
index = 0
36-
n = 0
37-
err error
38-
24+
err error
25+
index = 0
26+
n = 0
3927
strLen = len((*(*[]byte)(buf)))
28+
b = *(*[]byte)(buf)
4029
)
4130

4231
for index < strLen {
43-
if n, err = d.r.Read((*(*[]byte)(buf))[index:]); err != nil {
32+
if n, err = d.r.Read(b[index:]); err != nil {
4433
return err
4534
}
4635
index += n
4736
}
4837

49-
return nil
38+
return err
5039
}
5140

5241
//go:nosplit

helpers_test.go

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/*
2+
* Copyright (c) 2022, arivum.
3+
* All rights reserved.
4+
* SPDX-License-Identifier: MIT
5+
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
6+
*/
7+
8+
package msgpack
9+
10+
import (
11+
"bufio"
12+
"io"
13+
"testing"
14+
"unsafe"
15+
)
16+
17+
func BenchmarkReadFull(b *testing.B) {
18+
rd, wt := io.Pipe()
19+
go func() {
20+
for i := 0; i < b.N; i++ {
21+
wt.Write([]byte{byte(b.N >> 24), byte(b.N >> 16), byte(b.N >> 8), byte(b.N)})
22+
}
23+
}()
24+
r := bufio.NewReader(rd)
25+
d := NewDecoder(r)
26+
bb := make([]byte, 4)
27+
buf := noescape(unsafe.Pointer(&bb))
28+
for i := 0; i < b.N; i++ {
29+
d.readFull(buf)
30+
}
31+
}
32+
33+
func BenchmarkReadLen32(b *testing.B) {
34+
rd, wt := io.Pipe()
35+
go func() {
36+
for i := 0; i < b.N; i++ {
37+
wt.Write([]byte{byte(b.N >> 24), byte(b.N >> 16), byte(b.N >> 8), byte(b.N)})
38+
}
39+
}()
40+
r := bufio.NewReader(rd)
41+
d := NewDecoder(r)
42+
for i := 0; i < b.N; i++ {
43+
d.readLen16()
44+
}
45+
}
46+
47+
func BenchmarkReadLen16(b *testing.B) {
48+
rd, wt := io.Pipe()
49+
go func() {
50+
for i := 0; i < b.N; i++ {
51+
wt.Write([]byte{byte(b.N >> 24), byte(b.N >> 16), byte(b.N >> 8), byte(b.N)})
52+
}
53+
}()
54+
r := bufio.NewReader(rd)
55+
d := NewDecoder(r)
56+
for i := 0; i < b.N; i++ {
57+
d.readLen16()
58+
}
59+
}

messagepack.go

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,22 +15,31 @@ import (
1515

1616
func NewDecoder(r io.Reader) *Decoder {
1717
var (
18-
buf = bufio.NewReader(r)
18+
buf = bufio.NewReaderSize(r, 8<<10)
19+
b = newPreallocBuf()
1920
d = &Decoder{
2021
underlayingReader: r,
2122
r: buf,
2223
s: make(chan interface{}, 100),
23-
buf: newPreallocBuf(),
24+
buf: b,
2425
}
2526
)
2627
d.mapDecoderFuncsByLen = []func() (map[string]interface{}, error){
2728
func() (map[string]interface{}, error) {
28-
return emptyMap, nil
29+
return map[string]interface{}{}, nil
2930
},
3031
d.decodeMapEnrolledSingleEntry,
3132
d.decodeMapEnrolledTwoEntries,
3233
d.decodeMapEnrolledThreeEntries,
3334
}
35+
d.sliceDecoderFuncsByLen = []func() ([]interface{}, error){
36+
func() ([]interface{}, error) {
37+
return []interface{}{}, nil
38+
},
39+
d.decodeSliceEnrolledSingleEntry,
40+
d.decodeSliceEnrolledTwoEntries,
41+
d.decodeSliceEnrolledThreeEntries,
42+
}
3443
return d
3544
}
3645

slice_improvements.go

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
/*
2+
* Copyright (c) 2022, arivum.
3+
* All rights reserved.
4+
* SPDX-License-Identifier: MIT
5+
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
6+
*/
7+
8+
package msgpack
9+
10+
func (d *Decoder) decodeSliceEnrolledSingleEntry() ([]interface{}, error) {
11+
var (
12+
err error
13+
value interface{}
14+
)
15+
16+
// if d.nextByte, err = d.r.ReadByte(); err != nil {
17+
// return nil, err
18+
// }
19+
// if key, err = d.directDecodeString(); err != nil {
20+
// return nil, err
21+
// }
22+
err = d.handleNext(&value)
23+
24+
return []interface{}{
25+
value,
26+
}, err
27+
}
28+
29+
func (d *Decoder) decodeSliceEnrolledTwoEntries() ([]interface{}, error) {
30+
var (
31+
value1, value2 interface{}
32+
err error
33+
)
34+
35+
if err = d.handleNext(&value1); err != nil {
36+
return nil, err
37+
}
38+
39+
if err = d.handleNext(&value2); err != nil {
40+
return nil, err
41+
}
42+
43+
return []interface{}{
44+
value1,
45+
value2,
46+
}, nil
47+
}
48+
49+
func (d *Decoder) decodeSliceEnrolledThreeEntries() ([]interface{}, error) {
50+
var (
51+
value1, value2, value3 interface{}
52+
err error
53+
)
54+
55+
if err = d.handleNext(&value1); err != nil {
56+
return nil, err
57+
}
58+
59+
if err = d.handleNext(&value2); err != nil {
60+
return nil, err
61+
}
62+
63+
if err = d.handleNext(&value3); err != nil {
64+
return nil, err
65+
}
66+
67+
return []interface{}{
68+
value1,
69+
value2,
70+
value3,
71+
}, nil
72+
}
73+
74+
func (d *Decoder) decodeSliceAny(len int) ([]interface{}, error) {
75+
var (
76+
s = make([]interface{}, len)
77+
err error
78+
i = 0
79+
)
80+
81+
for ; i < len; i++ {
82+
//var value interface{}
83+
84+
if err = d.handleNext(&s[i]); err != nil {
85+
return nil, err
86+
}
87+
88+
}
89+
90+
return s, nil
91+
}

types.go

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -14,18 +14,19 @@ import (
1414
)
1515

1616
type Decoder struct {
17-
buf *preallocBuf
18-
underlayingReader io.Reader
19-
r *bufio.Reader
20-
s chan interface{}
21-
mapDecoderFuncsByLen []func() (map[string]interface{}, error)
22-
lastError error
23-
twoBytes [2]byte
24-
fourBytes [4]byte
25-
eightBytes [8]byte
26-
nextByte byte
27-
closeOnce sync.Once
28-
closeChan chan struct{}
17+
buf *preallocBuf
18+
underlayingReader io.Reader
19+
r *bufio.Reader
20+
s chan interface{}
21+
mapDecoderFuncsByLen []func() (map[string]interface{}, error)
22+
sliceDecoderFuncsByLen []func() ([]interface{}, error)
23+
lastError error
24+
twoBytes [2]byte
25+
fourBytes [4]byte
26+
eightBytes [8]byte
27+
nextByte byte
28+
closeOnce sync.Once
29+
closeChan chan struct{}
2930
}
3031

3132
type preallocBuf struct {

0 commit comments

Comments
 (0)