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
|
// See the documentation for Unmarshal for details about
|
||||||
// the conversion of JSON into a Go value.
|
// the conversion of JSON into a Go value.
|
||||||
func (d *Decoder) Decode(v interface{}) error {
|
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))
|
header := (*emptyInterface)(unsafe.Pointer(&v))
|
||||||
typ := header.typ
|
typ := header.typ
|
||||||
ptr := uintptr(header.ptr)
|
ptr := uintptr(header.ptr)
|
||||||
|
@ -153,6 +157,9 @@ func (d *Decoder) Decode(v interface{}) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
s := d.s
|
s := d.s
|
||||||
|
for _, optFunc := range optFuncs {
|
||||||
|
optFunc(s.Option)
|
||||||
|
}
|
||||||
if err := dec.DecodeStream(s, 0, header.ptr); err != nil {
|
if err := dec.DecodeStream(s, 0, header.ptr); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,7 @@ type Stream struct {
|
||||||
allRead bool
|
allRead bool
|
||||||
UseNumber bool
|
UseNumber bool
|
||||||
DisallowUnknownFields bool
|
DisallowUnknownFields bool
|
||||||
|
Option *Option
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewStream(r io.Reader) *Stream {
|
func NewStream(r io.Reader) *Stream {
|
||||||
|
@ -32,6 +33,7 @@ func NewStream(r io.Reader) *Stream {
|
||||||
r: r,
|
r: r,
|
||||||
bufSize: initBufSize,
|
bufSize: initBufSize,
|
||||||
buf: make([]byte, 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++
|
s.cursor++
|
||||||
return nil
|
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 {
|
for {
|
||||||
s.reset()
|
s.reset()
|
||||||
field, key, err := d.keyStreamDecoder(d, s)
|
field, key, err := d.keyStreamDecoder(d, s)
|
||||||
|
@ -675,9 +683,26 @@ func (d *structDecoder) DecodeStream(s *Stream, depth int64, p unsafe.Pointer) e
|
||||||
if field.err != nil {
|
if field.err != nil {
|
||||||
return field.err
|
return field.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 {
|
if err := field.dec.DecodeStream(s, depth, unsafe.Pointer(uintptr(p)+field.offset)); err != nil {
|
||||||
return err
|
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 {
|
} else if s.DisallowUnknownFields {
|
||||||
return fmt.Errorf("json: unknown field %q", key)
|
return fmt.Errorf("json: unknown field %q", key)
|
||||||
} else {
|
} else {
|
||||||
|
|
Loading…
Reference in New Issue