diff --git a/decode_compile.go b/decode_compile.go index c494f90..1538f56 100644 --- a/decode_compile.go +++ b/decode_compile.go @@ -260,6 +260,8 @@ func (d *Decoder) removeConflictFields(fieldMap map[string]*structFieldSet, conf dec: v.dec, offset: baseOffset + v.offset, isTaggedKey: v.isTaggedKey, + key: k, + keyLen: int64(len(k)), } fieldMap[k] = fieldSet lower := strings.ToLower(k) @@ -282,6 +284,8 @@ func (d *Decoder) removeConflictFields(fieldMap map[string]*structFieldSet, conf dec: v.dec, offset: baseOffset + v.offset, isTaggedKey: v.isTaggedKey, + key: k, + keyLen: int64(len(k)), } fieldMap[k] = fieldSet lower := strings.ToLower(k) @@ -345,6 +349,8 @@ func (d *Decoder) compileStruct(typ *rtype, structName, fieldName string) (decod dec: newAnonymousFieldDecoder(pdec.typ, v.offset, v.dec), offset: field.Offset, isTaggedKey: v.isTaggedKey, + key: k, + keyLen: int64(len(k)), } fieldMap[k] = fieldSet lower := strings.ToLower(k) @@ -367,6 +373,8 @@ func (d *Decoder) compileStruct(typ *rtype, structName, fieldName string) (decod dec: newAnonymousFieldDecoder(pdec.typ, v.offset, v.dec), offset: field.Offset, isTaggedKey: v.isTaggedKey, + key: k, + keyLen: int64(len(k)), } fieldMap[k] = fieldSet lower := strings.ToLower(k) @@ -388,19 +396,23 @@ func (d *Decoder) compileStruct(typ *rtype, structName, fieldName string) (decod if tag.isString { dec = newWrappedStringDecoder(dec, structName, field.Name) } - fieldSet := &structFieldSet{dec: dec, offset: field.Offset, isTaggedKey: tag.isTaggedKey} + var key string if tag.key != "" { - fieldMap[tag.key] = fieldSet - lower := strings.ToLower(tag.key) - if _, exists := fieldMap[lower]; !exists { - fieldMap[lower] = fieldSet - } + key = tag.key } else { - fieldMap[field.Name] = fieldSet - lower := strings.ToLower(field.Name) - if _, exists := fieldMap[lower]; !exists { - fieldMap[lower] = fieldSet - } + key = field.Name + } + fieldSet := &structFieldSet{ + dec: dec, + offset: field.Offset, + isTaggedKey: tag.isTaggedKey, + key: key, + keyLen: int64(len(key)), + } + fieldMap[key] = fieldSet + lower := strings.ToLower(key) + if _, exists := fieldMap[lower]; !exists { + fieldMap[lower] = fieldSet } } } diff --git a/decode_struct.go b/decode_struct.go index 3395133..961dcbd 100644 --- a/decode_struct.go +++ b/decode_struct.go @@ -12,6 +12,8 @@ type structFieldSet struct { dec decoder offset uintptr isTaggedKey bool + key string + keyLen int64 } type structDecoder struct { @@ -157,6 +159,7 @@ func decodeKeyByBitmapInt8(d *structDecoder, buf []byte, cursor int64) (int64, * keyIdx := 0 bitmap := d.keyBitmapInt8 keyBitmapLen := len(bitmap) + start := cursor for { c := char(b, cursor) switch c { @@ -164,7 +167,12 @@ func decodeKeyByBitmapInt8(d *structDecoder, buf []byte, cursor int64) (int64, * x := uint64(curBit & -curBit) fieldSetIndex := bitHashTable[(x*0x03F566ED27179461)>>58] field = d.sortedFieldSets[fieldSetIndex] + keyLen := cursor - start cursor++ + if keyLen < field.keyLen { + // early match + return cursor, nil, nil + } return cursor, field, nil case nul: return 0, nil, errUnexpectedEndOfJSON("string", cursor) @@ -237,6 +245,7 @@ func decodeKeyByBitmapInt16(d *structDecoder, buf []byte, cursor int64) (int64, keyIdx := 0 bitmap := d.keyBitmapInt16 keyBitmapLen := len(bitmap) + start := cursor for { c := char(b, cursor) switch c { @@ -244,7 +253,12 @@ func decodeKeyByBitmapInt16(d *structDecoder, buf []byte, cursor int64) (int64, x := uint64(curBit & -curBit) fieldSetIndex := bitHashTable[(x*0x03F566ED27179461)>>58] field = d.sortedFieldSets[fieldSetIndex] + keyLen := cursor - start cursor++ + if keyLen < field.keyLen { + // early match + return cursor, nil, nil + } return cursor, field, nil case nul: return 0, nil, errUnexpectedEndOfJSON("string", cursor) @@ -341,10 +355,13 @@ func decodeKeyByBitmapInt8Stream(d *structDecoder, s *stream) (*structFieldSet, x := uint64(curBit & -curBit) fieldSetIndex := bitHashTable[(x*0x03F566ED27179461)>>58] field = d.sortedFieldSets[fieldSetIndex] - b := s.buf[start:s.cursor] - key := *(*string)(unsafe.Pointer(&b)) + keyLen := s.cursor - start s.cursor++ - return field, key, nil + if keyLen < field.keyLen { + // early match + return nil, field.key, nil + } + return field, field.key, nil case nul: if s.read() { continue @@ -441,10 +458,13 @@ func decodeKeyByBitmapInt16Stream(d *structDecoder, s *stream) (*structFieldSet, x := uint64(curBit & -curBit) fieldSetIndex := bitHashTable[(x*0x03F566ED27179461)>>58] field = d.sortedFieldSets[fieldSetIndex] - b := s.buf[start:s.cursor] - key := *(*string)(unsafe.Pointer(&b)) + keyLen := s.cursor - start s.cursor++ - return field, key, nil + if keyLen < field.keyLen { + // early match + return nil, field.key, nil + } + return field, field.key, nil case nul: if s.read() { continue