From f8c7c7a612860bbb0c5574502b65d79413ab1408 Mon Sep 17 00:00:00 2001 From: Masaaki Goshima Date: Thu, 11 Feb 2021 22:10:14 +0900 Subject: [PATCH 1/2] Optimize decoding of struct field --- decode_struct.go | 93 ++++-------------------------------------------- 1 file changed, 7 insertions(+), 86 deletions(-) diff --git a/decode_struct.go b/decode_struct.go index cd66ad4..326a89b 100644 --- a/decode_struct.go +++ b/decode_struct.go @@ -109,8 +109,13 @@ func (d *structDecoder) tryOptimize() { sortedKeys = append(sortedKeys, key) } sort.Strings(sortedKeys) + + // By allocating one extra capacity than `maxKeyLen`, + // it is possible to avoid the process of comparing the index of the key with the length of the bitmap each time. + bitmapLen := maxKeyLen + 1 if len(sortedKeys) <= 8 { - keyBitmap := make([][256]int8, maxKeyLen) + // maxKeyLen + keyBitmap := make([][256]int8, bitmapLen) for i, key := range sortedKeys { for j := 0; j < len(key); j++ { c := key[j] @@ -122,7 +127,7 @@ func (d *structDecoder) tryOptimize() { d.keyDecoder = decodeKeyByBitmapInt8 d.keyStreamDecoder = decodeKeyByBitmapInt8Stream } else { - keyBitmap := make([][256]int16, maxKeyLen) + keyBitmap := make([][256]int16, bitmapLen) for i, key := range sortedKeys { for j := 0; j < len(key); j++ { c := key[j] @@ -158,7 +163,6 @@ func decodeKeyByBitmapInt8(d *structDecoder, buf []byte, cursor int64) (int64, * } keyIdx := 0 bitmap := d.keyBitmapInt8 - keyBitmapLen := len(bitmap) start := cursor for { c := char(b, cursor) @@ -177,23 +181,6 @@ func decodeKeyByBitmapInt8(d *structDecoder, buf []byte, cursor int64) (int64, * case nul: return 0, nil, errUnexpectedEndOfJSON("string", cursor) default: - if keyIdx >= keyBitmapLen { - for { - cursor++ - switch char(b, cursor) { - case '"': - cursor++ - return cursor, field, nil - case '\\': - cursor++ - if char(b, cursor) == nul { - return 0, nil, errUnexpectedEndOfJSON("string", cursor) - } - case nul: - return 0, nil, errUnexpectedEndOfJSON("string", cursor) - } - } - } curBit &= bitmap[keyIdx][largeToSmallTable[c]] if curBit == 0 { for { @@ -244,7 +231,6 @@ func decodeKeyByBitmapInt16(d *structDecoder, buf []byte, cursor int64) (int64, } keyIdx := 0 bitmap := d.keyBitmapInt16 - keyBitmapLen := len(bitmap) start := cursor for { c := char(b, cursor) @@ -263,23 +249,6 @@ func decodeKeyByBitmapInt16(d *structDecoder, buf []byte, cursor int64) (int64, case nul: return 0, nil, errUnexpectedEndOfJSON("string", cursor) default: - if keyIdx >= keyBitmapLen { - for { - cursor++ - switch char(b, cursor) { - case '"': - cursor++ - return cursor, field, nil - case '\\': - cursor++ - if char(b, cursor) == nul { - return 0, nil, errUnexpectedEndOfJSON("string", cursor) - } - case nul: - return 0, nil, errUnexpectedEndOfJSON("string", cursor) - } - } - } curBit &= bitmap[keyIdx][largeToSmallTable[c]] if curBit == 0 { for { @@ -352,7 +321,6 @@ func decodeKeyByBitmapInt8Stream(d *structDecoder, s *stream) (*structFieldSet, } keyIdx := 0 bitmap := d.keyBitmapInt8 - keyBitmapLen := len(bitmap) for { c := s.char() switch c { @@ -373,29 +341,6 @@ func decodeKeyByBitmapInt8Stream(d *structDecoder, s *stream) (*structFieldSet, } return nil, "", errUnexpectedEndOfJSON("string", s.totalOffset()) default: - if keyIdx >= keyBitmapLen { - for { - s.cursor++ - switch s.char() { - case '"': - b := s.buf[start:s.cursor] - key := *(*string)(unsafe.Pointer(&b)) - s.cursor++ - return field, key, nil - case '\\': - s.cursor++ - if s.char() == nul { - if !s.read() { - return nil, "", errUnexpectedEndOfJSON("string", s.totalOffset()) - } - } - case nul: - if !s.read() { - return nil, "", errUnexpectedEndOfJSON("string", s.totalOffset()) - } - } - } - } curBit &= bitmap[keyIdx][largeToSmallTable[c]] if curBit == 0 { for { @@ -460,7 +405,6 @@ func decodeKeyByBitmapInt16Stream(d *structDecoder, s *stream) (*structFieldSet, } keyIdx := 0 bitmap := d.keyBitmapInt16 - keyBitmapLen := len(bitmap) for { c := s.char() switch c { @@ -481,29 +425,6 @@ func decodeKeyByBitmapInt16Stream(d *structDecoder, s *stream) (*structFieldSet, } return nil, "", errUnexpectedEndOfJSON("string", s.totalOffset()) default: - if keyIdx >= keyBitmapLen { - for { - s.cursor++ - switch s.char() { - case '"': - b := s.buf[start:s.cursor] - key := *(*string)(unsafe.Pointer(&b)) - s.cursor++ - return field, key, nil - case '\\': - s.cursor++ - if s.char() == nul { - if !s.read() { - return nil, "", errUnexpectedEndOfJSON("string", s.totalOffset()) - } - } - case nul: - if !s.read() { - return nil, "", errUnexpectedEndOfJSON("string", s.totalOffset()) - } - } - } - } curBit &= bitmap[keyIdx][largeToSmallTable[c]] if curBit == 0 { for { From f5d4fc66a370560489ea9827505d9476dcf5e2b8 Mon Sep 17 00:00:00 2001 From: Masaaki Goshima Date: Thu, 11 Feb 2021 22:17:18 +0900 Subject: [PATCH 2/2] Remove unnecessary comment --- decode_struct.go | 1 - 1 file changed, 1 deletion(-) diff --git a/decode_struct.go b/decode_struct.go index 326a89b..bfd46d6 100644 --- a/decode_struct.go +++ b/decode_struct.go @@ -114,7 +114,6 @@ func (d *structDecoder) tryOptimize() { // it is possible to avoid the process of comparing the index of the key with the length of the bitmap each time. bitmapLen := maxKeyLen + 1 if len(sortedKeys) <= 8 { - // maxKeyLen keyBitmap := make([][256]int8, bitmapLen) for i, key := range sortedKeys { for j := 0; j < len(key); j++ {