mirror of https://github.com/goccy/go-json.git
Enable FirstWin option for stream decoder
This commit is contained in:
parent
34b7053412
commit
5c39787fbd
|
@ -462,3 +462,18 @@ func Benchmark_Decode_LargeStruct_Stream_GoJson(b *testing.B) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Decode_LargeStruct_Stream_GoJsonFirstWinMode(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
reader := bytes.NewReader(LargeFixture)
|
||||
for i := 0; i < b.N; i++ {
|
||||
result := LargePayload{}
|
||||
reader.Reset(LargeFixture)
|
||||
if err := gojson.NewDecoder(reader).DecodeWithOption(
|
||||
&result,
|
||||
gojson.DecodeFieldPriorityFirstWin(),
|
||||
); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -134,6 +134,10 @@ func (d *Decoder) Buffered() io.Reader {
|
|||
// See the documentation for Unmarshal for details about
|
||||
// the conversion of JSON into a Go value.
|
||||
func (d *Decoder) Decode(v interface{}) error {
|
||||
return d.DecodeWithOption(v)
|
||||
}
|
||||
|
||||
func (d *Decoder) DecodeWithOption(v interface{}, optFuncs ...DecodeOptionFunc) error {
|
||||
header := (*emptyInterface)(unsafe.Pointer(&v))
|
||||
typ := header.typ
|
||||
ptr := uintptr(header.ptr)
|
||||
|
@ -153,6 +157,9 @@ func (d *Decoder) Decode(v interface{}) error {
|
|||
return err
|
||||
}
|
||||
s := d.s
|
||||
for _, optFunc := range optFuncs {
|
||||
optFunc(s.Option)
|
||||
}
|
||||
if err := dec.DecodeStream(s, 0, header.ptr); err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ type Stream struct {
|
|||
allRead bool
|
||||
UseNumber bool
|
||||
DisallowUnknownFields bool
|
||||
Option *Option
|
||||
}
|
||||
|
||||
func NewStream(r io.Reader) *Stream {
|
||||
|
@ -32,6 +33,7 @@ func NewStream(r io.Reader) *Stream {
|
|||
r: r,
|
||||
bufSize: initBufSize,
|
||||
buf: make([]byte, initBufSize),
|
||||
Option: &Option{},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -661,6 +661,14 @@ func (d *structDecoder) DecodeStream(s *Stream, depth int64, p unsafe.Pointer) e
|
|||
s.cursor++
|
||||
return nil
|
||||
}
|
||||
var (
|
||||
seenFields map[int]struct{}
|
||||
seenFieldNum int
|
||||
)
|
||||
firstWin := (s.Option.Flag & FirstWinOption) != 0
|
||||
if firstWin {
|
||||
seenFields = make(map[int]struct{}, d.fieldUniqueNameNum)
|
||||
}
|
||||
for {
|
||||
s.reset()
|
||||
field, key, err := d.keyStreamDecoder(d, s)
|
||||
|
@ -675,8 +683,25 @@ func (d *structDecoder) DecodeStream(s *Stream, depth int64, p unsafe.Pointer) e
|
|||
if field.err != nil {
|
||||
return field.err
|
||||
}
|
||||
if err := field.dec.DecodeStream(s, depth, unsafe.Pointer(uintptr(p)+field.offset)); err != nil {
|
||||
return err
|
||||
if firstWin {
|
||||
if _, exists := seenFields[field.fieldIdx]; exists {
|
||||
if err := s.skipValue(depth); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if err := field.dec.DecodeStream(s, depth, unsafe.Pointer(uintptr(p)+field.offset)); err != nil {
|
||||
return err
|
||||
}
|
||||
seenFieldNum++
|
||||
if d.fieldUniqueNameNum <= seenFieldNum {
|
||||
return s.skipObject(depth)
|
||||
}
|
||||
seenFields[field.fieldIdx] = struct{}{}
|
||||
}
|
||||
} else {
|
||||
if err := field.dec.DecodeStream(s, depth, unsafe.Pointer(uintptr(p)+field.offset)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else if s.DisallowUnknownFields {
|
||||
return fmt.Errorf("json: unknown field %q", key)
|
||||
|
|
Loading…
Reference in New Issue