Fix algorithm of struct field detection

This commit is contained in:
Masaaki Goshima 2021-02-06 20:07:01 +09:00
parent a75b5e9d93
commit 0c1e7c61e0
2 changed files with 49 additions and 17 deletions

View File

@ -260,6 +260,8 @@ func (d *Decoder) removeConflictFields(fieldMap map[string]*structFieldSet, conf
dec: v.dec, dec: v.dec,
offset: baseOffset + v.offset, offset: baseOffset + v.offset,
isTaggedKey: v.isTaggedKey, isTaggedKey: v.isTaggedKey,
key: k,
keyLen: int64(len(k)),
} }
fieldMap[k] = fieldSet fieldMap[k] = fieldSet
lower := strings.ToLower(k) lower := strings.ToLower(k)
@ -282,6 +284,8 @@ func (d *Decoder) removeConflictFields(fieldMap map[string]*structFieldSet, conf
dec: v.dec, dec: v.dec,
offset: baseOffset + v.offset, offset: baseOffset + v.offset,
isTaggedKey: v.isTaggedKey, isTaggedKey: v.isTaggedKey,
key: k,
keyLen: int64(len(k)),
} }
fieldMap[k] = fieldSet fieldMap[k] = fieldSet
lower := strings.ToLower(k) 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), dec: newAnonymousFieldDecoder(pdec.typ, v.offset, v.dec),
offset: field.Offset, offset: field.Offset,
isTaggedKey: v.isTaggedKey, isTaggedKey: v.isTaggedKey,
key: k,
keyLen: int64(len(k)),
} }
fieldMap[k] = fieldSet fieldMap[k] = fieldSet
lower := strings.ToLower(k) 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), dec: newAnonymousFieldDecoder(pdec.typ, v.offset, v.dec),
offset: field.Offset, offset: field.Offset,
isTaggedKey: v.isTaggedKey, isTaggedKey: v.isTaggedKey,
key: k,
keyLen: int64(len(k)),
} }
fieldMap[k] = fieldSet fieldMap[k] = fieldSet
lower := strings.ToLower(k) lower := strings.ToLower(k)
@ -388,22 +396,26 @@ func (d *Decoder) compileStruct(typ *rtype, structName, fieldName string) (decod
if tag.isString { if tag.isString {
dec = newWrappedStringDecoder(dec, structName, field.Name) dec = newWrappedStringDecoder(dec, structName, field.Name)
} }
fieldSet := &structFieldSet{dec: dec, offset: field.Offset, isTaggedKey: tag.isTaggedKey} var key string
if tag.key != "" { if tag.key != "" {
fieldMap[tag.key] = fieldSet key = tag.key
lower := strings.ToLower(tag.key)
if _, exists := fieldMap[lower]; !exists {
fieldMap[lower] = fieldSet
}
} else { } else {
fieldMap[field.Name] = fieldSet key = field.Name
lower := strings.ToLower(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 { if _, exists := fieldMap[lower]; !exists {
fieldMap[lower] = fieldSet fieldMap[lower] = fieldSet
} }
} }
} }
}
delete(d.structTypeToDecoder, typeptr) delete(d.structTypeToDecoder, typeptr)
structDec.tryOptimize() structDec.tryOptimize()
return structDec, nil return structDec, nil

View File

@ -12,6 +12,8 @@ type structFieldSet struct {
dec decoder dec decoder
offset uintptr offset uintptr
isTaggedKey bool isTaggedKey bool
key string
keyLen int64
} }
type structDecoder struct { type structDecoder struct {
@ -157,6 +159,7 @@ func decodeKeyByBitmapInt8(d *structDecoder, buf []byte, cursor int64) (int64, *
keyIdx := 0 keyIdx := 0
bitmap := d.keyBitmapInt8 bitmap := d.keyBitmapInt8
keyBitmapLen := len(bitmap) keyBitmapLen := len(bitmap)
start := cursor
for { for {
c := char(b, cursor) c := char(b, cursor)
switch c { switch c {
@ -164,7 +167,12 @@ func decodeKeyByBitmapInt8(d *structDecoder, buf []byte, cursor int64) (int64, *
x := uint64(curBit & -curBit) x := uint64(curBit & -curBit)
fieldSetIndex := bitHashTable[(x*0x03F566ED27179461)>>58] fieldSetIndex := bitHashTable[(x*0x03F566ED27179461)>>58]
field = d.sortedFieldSets[fieldSetIndex] field = d.sortedFieldSets[fieldSetIndex]
keyLen := cursor - start
cursor++ cursor++
if keyLen < field.keyLen {
// early match
return cursor, nil, nil
}
return cursor, field, nil return cursor, field, nil
case nul: case nul:
return 0, nil, errUnexpectedEndOfJSON("string", cursor) return 0, nil, errUnexpectedEndOfJSON("string", cursor)
@ -237,6 +245,7 @@ func decodeKeyByBitmapInt16(d *structDecoder, buf []byte, cursor int64) (int64,
keyIdx := 0 keyIdx := 0
bitmap := d.keyBitmapInt16 bitmap := d.keyBitmapInt16
keyBitmapLen := len(bitmap) keyBitmapLen := len(bitmap)
start := cursor
for { for {
c := char(b, cursor) c := char(b, cursor)
switch c { switch c {
@ -244,7 +253,12 @@ func decodeKeyByBitmapInt16(d *structDecoder, buf []byte, cursor int64) (int64,
x := uint64(curBit & -curBit) x := uint64(curBit & -curBit)
fieldSetIndex := bitHashTable[(x*0x03F566ED27179461)>>58] fieldSetIndex := bitHashTable[(x*0x03F566ED27179461)>>58]
field = d.sortedFieldSets[fieldSetIndex] field = d.sortedFieldSets[fieldSetIndex]
keyLen := cursor - start
cursor++ cursor++
if keyLen < field.keyLen {
// early match
return cursor, nil, nil
}
return cursor, field, nil return cursor, field, nil
case nul: case nul:
return 0, nil, errUnexpectedEndOfJSON("string", cursor) return 0, nil, errUnexpectedEndOfJSON("string", cursor)
@ -341,10 +355,13 @@ func decodeKeyByBitmapInt8Stream(d *structDecoder, s *stream) (*structFieldSet,
x := uint64(curBit & -curBit) x := uint64(curBit & -curBit)
fieldSetIndex := bitHashTable[(x*0x03F566ED27179461)>>58] fieldSetIndex := bitHashTable[(x*0x03F566ED27179461)>>58]
field = d.sortedFieldSets[fieldSetIndex] field = d.sortedFieldSets[fieldSetIndex]
b := s.buf[start:s.cursor] keyLen := s.cursor - start
key := *(*string)(unsafe.Pointer(&b))
s.cursor++ s.cursor++
return field, key, nil if keyLen < field.keyLen {
// early match
return nil, field.key, nil
}
return field, field.key, nil
case nul: case nul:
if s.read() { if s.read() {
continue continue
@ -441,10 +458,13 @@ func decodeKeyByBitmapInt16Stream(d *structDecoder, s *stream) (*structFieldSet,
x := uint64(curBit & -curBit) x := uint64(curBit & -curBit)
fieldSetIndex := bitHashTable[(x*0x03F566ED27179461)>>58] fieldSetIndex := bitHashTable[(x*0x03F566ED27179461)>>58]
field = d.sortedFieldSets[fieldSetIndex] field = d.sortedFieldSets[fieldSetIndex]
b := s.buf[start:s.cursor] keyLen := s.cursor - start
key := *(*string)(unsafe.Pointer(&b))
s.cursor++ s.cursor++
return field, key, nil if keyLen < field.keyLen {
// early match
return nil, field.key, nil
}
return field, field.key, nil
case nul: case nul:
if s.read() { if s.read() {
continue continue