diff options
Diffstat (limited to 'vendor/github.com/ugorji/go')
29 files changed, 1474 insertions, 1284 deletions
diff --git a/vendor/github.com/ugorji/go/codec/README.md b/vendor/github.com/ugorji/go/codec/README.md index 138a5fc9c..e4c45bc83 100644 --- a/vendor/github.com/ugorji/go/codec/README.md +++ b/vendor/github.com/ugorji/go/codec/README.md @@ -6,13 +6,13 @@ codec/encoding library for binc, msgpack, cbor, json. Supported Serialization formats are: - msgpack: https://github.com/msgpack/msgpack - - binc: http://github.com/ugorji/binc - - cbor: http://cbor.io http://tools.ietf.org/html/rfc7049 - - json: http://json.org http://tools.ietf.org/html/rfc7159 + - binc: http://github.com/ugorji/binc + - cbor: http://cbor.io http://tools.ietf.org/html/rfc7049 + - json: http://json.org http://tools.ietf.org/html/rfc7159 - simple: -This package will carefully use 'package unsafe' for performance reasons in -specific places. You can build without unsafe use by passing the safe or +This package will carefully use 'package unsafe' for performance reasons +in specific places. You can build without unsafe use by passing the safe or appengine tag i.e. 'go install -tags=codec.safe ...'. This library works with both the standard `gc` and the `gccgo` compilers. @@ -20,67 +20,70 @@ This library works with both the standard `gc` and the `gccgo` compilers. For detailed usage information, read the primer at http://ugorji.net/blog/go-codec-primer . -The idiomatic Go support is as seen in other encoding packages in the -standard library (ie json, xml, gob, etc). +The idiomatic Go support is as seen in other encoding packages in the standard +library (ie json, xml, gob, etc). Rich Feature Set includes: - Simple but extremely powerful and feature-rich API - - Support for go 1.4 and above, while selectively using newer APIs for later releases + - Support for go 1.4 and above, while selectively using newer APIs for later + releases - Excellent code coverage ( > 90% ) - - Very High Performance. - Our extensive benchmarks show us outperforming Gob, Json, Bson, etc by 2-4X. + - Very High Performance. Our extensive benchmarks show us outperforming Gob, + Json, Bson, etc by 2-4X. - Careful selected use of 'unsafe' for targeted performance gains. - 100% safe mode supported, where 'unsafe' is not used at all. - Lock-free (sans mutex) concurrency for scaling to 100's of cores - - In-place updates during decode, with option to zero value in maps and slices prior to decode - - Coerce types where appropriate - e.g. decode an int in the stream into a float, decode numbers from formatted strings, etc - - Corner Cases: - Overflows, nil maps/slices, nil values in streams are handled correctly + - In-place updates during decode, with option to zero value in maps and slices + prior to decode + - Coerce types where appropriate e.g. decode an int in the stream into a + float, decode numbers from formatted strings, etc + - Corner Cases: Overflows, nil maps/slices, nil values in streams are handled + correctly - Standard field renaming via tags - Support for omitting empty fields during an encoding - - Encoding from any value and decoding into pointer to any value - (struct, slice, map, primitives, pointers, interface{}, etc) + - Encoding from any value and decoding into pointer to any value (struct, + slice, map, primitives, pointers, interface{}, etc) - Extensions to support efficient encoding/decoding of any named types - Support encoding.(Binary|Text)(M|Unm)arshaler interfaces - - Support using existence of `IsZero() bool` to determine if a value is a zero value. - Analogous to time.Time.IsZero() bool. - - Decoding without a schema (into a interface{}). - Includes Options to configure what specific map or slice type to use - when decoding an encoded list or map into a nil interface{} + - Support using existence of `IsZero() bool` to determine if a value is a zero + value. Analogous to time.Time.IsZero() bool. + - Decoding without a schema (into a interface{}). Includes Options to + configure what specific map or slice type to use when decoding an encoded + list or map into a nil interface{} - Mapping a non-interface type to an interface, so we can decode appropriately into any interface type with a correctly configured non-interface value. - - Encode a struct as an array, and decode struct from an array in the data stream - - Option to encode struct keys as numbers (instead of strings) - (to support structured streams with fields encoded as numeric codes) + - Encode a struct as an array, and decode struct from an array in the data + stream + - Option to encode struct keys as numbers (instead of strings) (to support + structured streams with fields encoded as numeric codes) - Comprehensive support for anonymous fields - Fast (no-reflection) encoding/decoding of common maps and slices - Code-generation for faster performance, supported in go 1.6+ - Support binary (e.g. messagepack, cbor) and text (e.g. json) formats - - Support indefinite-length formats to enable true streaming - (for formats which support it e.g. json, cbor) - - Support canonical encoding, where a value is ALWAYS encoded as same sequence of bytes. - This mostly applies to maps, where iteration order is non-deterministic. + - Support indefinite-length formats to enable true streaming (for formats + which support it e.g. json, cbor) + - Support canonical encoding, where a value is ALWAYS encoded as same + sequence of bytes. This mostly applies to maps, where iteration order is + non-deterministic. - NIL in data stream decoded as zero value - - Never silently skip data when decoding. - User decides whether to return an error or silently skip data when keys or indexes - in the data stream do not map to fields in the struct. - - Detect and error when encoding a cyclic reference (instead of stack overflow shutdown) + - Never silently skip data when decoding. User decides whether to return an + error or silently skip data when keys or indexes in the data stream do not + map to fields in the struct. + - Detect and error when encoding a cyclic reference (instead of stack overflow + shutdown) - Encode/Decode from/to chan types (for iterative streaming support) - Drop-in replacement for encoding/json. `json:` key in struct tag supported. - Provides a RPC Server and Client Codec for net/rpc communication protocol. - - Handle unique idiosyncrasies of codecs e.g. - - For messagepack, configure how ambiguities in handling raw bytes are resolved - - For messagepack, provide rpc server/client codec to support - msgpack-rpc protocol defined at: - https://github.com/msgpack-rpc/msgpack-rpc/blob/master/spec.md + - Handle unique idiosyncrasies of codecs e.g. For messagepack, + configure how ambiguities in handling raw bytes are resolved and provide + rpc server/client codec to support msgpack-rpc protocol defined at: + https://github.com/msgpack-rpc/msgpack-rpc/blob/master/spec.md +# Extension Support -## Extension Support - -Users can register a function to handle the encoding or decoding of their -custom types. +Users can register a function to handle the encoding or decoding of their custom +types. There are no restrictions on what the custom type can be. Some examples: @@ -92,43 +95,44 @@ There are no restrictions on what the custom type can be. Some examples: type GifImage struct { ... } ``` -As an illustration, MyStructWithUnexportedFields would normally be encoded -as an empty map because it has no exported fields, while UUID would be -encoded as a string. However, with extension support, you can encode any of -these however you like. +As an illustration, MyStructWithUnexportedFields would normally be encoded as +an empty map because it has no exported fields, while UUID would be encoded as a +string. However, with extension support, you can encode any of these however you +like. There is also seamless support provided for registering an extension (with a tag) but letting the encoding mechanism default to the standard way. +# Custom Encoding and Decoding -## Custom Encoding and Decoding - -This package maintains symmetry in the encoding and decoding halfs. We -determine how to encode or decode by walking this decision tree +This package maintains symmetry in the encoding and decoding halfs. We determine +how to encode or decode by walking this decision tree - is there an extension registered for the type? - is type a codec.Selfer? - - is format binary, and is type a encoding.BinaryMarshaler and BinaryUnmarshaler? - - is format specifically json, and is type a encoding/json.Marshaler and Unmarshaler? - - is format text-based, and type an encoding.TextMarshaler and TextUnmarshaler? - - else we use a pair of functions based on the "kind" of the type e.g. map, slice, int64, etc + - is format binary, and is type a encoding.BinaryMarshaler and + BinaryUnmarshaler? + - is format specifically json, and is type a encoding/json.Marshaler and + Unmarshaler? + - is format text-based, and type an encoding.TextMarshaler and + TextUnmarshaler? + - else we use a pair of functions based on the "kind" of the type e.g. map, + slice, int64, etc This symmetry is important to reduce chances of issues happening because the encoding and decoding sides are out of sync e.g. decoded via very specific encoding.TextUnmarshaler but encoded via kind-specific generalized mode. -Consequently, if a type only defines one-half of the symmetry (e.g. it -implements UnmarshalJSON() but not MarshalJSON() ), then that type doesn't +Consequently, if a type only defines one-half of the symmetry (e.g. +it implements UnmarshalJSON() but not MarshalJSON() ), then that type doesn't satisfy the check and we will continue walking down the decision tree. +# RPC -## RPC - -RPC Client and Server Codecs are implemented, so the codecs can be used with -the standard net/rpc package. +RPC Client and Server Codecs are implemented, so the codecs can be used with the +standard net/rpc package. - -## Usage +# Usage The Handle is SAFE for concurrent READ, but NOT SAFE for concurrent modification. @@ -137,13 +141,13 @@ The Encoder and Decoder are NOT safe for concurrent use. Consequently, the usage model is basically: - - Create and initialize the Handle before any use. - Once created, DO NOT modify it. - - Multiple Encoders or Decoders can now use the Handle concurrently. - They only read information off the Handle (never write). + - Create and initialize the Handle before any use. Once created, DO NOT modify + it. + - Multiple Encoders or Decoders can now use the Handle concurrently. They only + read information off the Handle (never write). - However, each Encoder or Decoder MUST not be used concurrently - - To re-use an Encoder/Decoder, call Reset(...) on it first. - This allows you use state maintained on the Encoder/Decoder. + - To re-use an Encoder/Decoder, call Reset(...) on it first. This allows you + use state maintained on the Encoder/Decoder. Sample usage model: @@ -194,8 +198,7 @@ Sample usage model: client := rpc.NewClientWithCodec(rpcCodec) ``` - -## Running Tests +# Running Tests To run tests, use the following: @@ -216,7 +219,7 @@ You can run the tag 'codec.safe' to run tests or build in safe mode. e.g. go test -tags "alltests codec.safe" -run Suite ``` -## Running Benchmarks +# Running Benchmarks ``` cd bench @@ -225,11 +228,9 @@ You can run the tag 'codec.safe' to run tests or build in safe mode. e.g. Please see http://github.com/ugorji/go-codec-bench . +# Caveats -## Caveats - -Struct fields matching the following are ignored during encoding and -decoding +Struct fields matching the following are ignored during encoding and decoding - struct tag value set to - - func, complex numbers, unsafe pointers @@ -239,14 +240,14 @@ decoding Every other field in a struct will be encoded/decoded. -Embedded fields are encoded as if they exist in the top-level struct, with -some caveats. See Encode documentation. +Embedded fields are encoded as if they exist in the top-level struct, with some +caveats. See Encode documentation. ## Exported Package API ```go const CborStreamBytes byte = 0x5f ... -const GenVersion = 25 +const GenVersion = 26 var SelfExt = &extFailWrapper{} var GoRpc goRpc var MsgpackSpecRpc msgpackSpecRpc diff --git a/vendor/github.com/ugorji/go/codec/binc.go b/vendor/github.com/ugorji/go/codec/binc.go index e54215dd4..9ed15a0bf 100644 --- a/vendor/github.com/ugorji/go/codec/binc.go +++ b/vendor/github.com/ugorji/go/codec/binc.go @@ -7,6 +7,7 @@ import ( "math" "reflect" "time" + "unicode/utf8" ) // Symbol management: @@ -555,7 +556,10 @@ func (d *bincDecDriver) decUint() (v uint64) { case 1: v = uint64(bigen.Uint16(d.d.decRd.readn2())) case 2: - v = uint64(bigen.Uint32(d.d.decRd.readn3())) + b3 := d.d.decRd.readn3() + var b [4]byte + copy(b[1:], b3[:]) + v = uint64(bigen.Uint32(b)) case 3: v = uint64(bigen.Uint32(d.d.decRd.readn4())) case 4, 5, 6: @@ -789,6 +793,11 @@ func (d *bincDecDriver) DecodeStringAsBytes() (bs2 []byte) { default: d.d.errorf("string/bytes - %s %x-%x/%s", msgBadDesc, d.vd, d.vs, bincdesc(d.vd, d.vs)) } + + if d.h.ValidateUnicode && !utf8.Valid(bs2) { + d.d.errorf("DecodeStringAsBytes: invalid UTF-8: %s", bs2) + } + d.bdRead = false return } @@ -1090,18 +1099,18 @@ func (d *bincDecDriver) nextValueBytesBdReadR(v0 []byte) (v []byte) { //------------------------------------ -//BincHandle is a Handle for the Binc Schema-Free Encoding Format -//defined at https://github.com/ugorji/binc . +// BincHandle is a Handle for the Binc Schema-Free Encoding Format +// defined at https://github.com/ugorji/binc . // -//BincHandle currently supports all Binc features with the following EXCEPTIONS: -// - only integers up to 64 bits of precision are supported. -// big integers are unsupported. -// - Only IEEE 754 binary32 and binary64 floats are supported (ie Go float32 and float64 types). -// extended precision and decimal IEEE 754 floats are unsupported. -// - Only UTF-8 strings supported. -// Unicode_Other Binc types (UTF16, UTF32) are currently unsupported. +// BincHandle currently supports all Binc features with the following EXCEPTIONS: +// - only integers up to 64 bits of precision are supported. +// big integers are unsupported. +// - Only IEEE 754 binary32 and binary64 floats are supported (ie Go float32 and float64 types). +// extended precision and decimal IEEE 754 floats are unsupported. +// - Only UTF-8 strings supported. +// Unicode_Other Binc types (UTF16, UTF32) are currently unsupported. // -//Note that these EXCEPTIONS are temporary and full support is possible and may happen soon. +// Note that these EXCEPTIONS are temporary and full support is possible and may happen soon. type BincHandle struct { BasicHandle binaryEncodingType @@ -1158,50 +1167,49 @@ func (h *BincHandle) newDecDriver() decDriver { // // Format Description // -// A timestamp is composed of 3 components: -// -// - secs: signed integer representing seconds since unix epoch -// - nsces: unsigned integer representing fractional seconds as a -// nanosecond offset within secs, in the range 0 <= nsecs < 1e9 -// - tz: signed integer representing timezone offset in minutes east of UTC, -// and a dst (daylight savings time) flag +// A timestamp is composed of 3 components: // -// When encoding a timestamp, the first byte is the descriptor, which -// defines which components are encoded and how many bytes are used to -// encode secs and nsecs components. *If secs/nsecs is 0 or tz is UTC, it -// is not encoded in the byte array explicitly*. +// - secs: signed integer representing seconds since unix epoch +// - nsces: unsigned integer representing fractional seconds as a +// nanosecond offset within secs, in the range 0 <= nsecs < 1e9 +// - tz: signed integer representing timezone offset in minutes east of UTC, +// and a dst (daylight savings time) flag // -// Descriptor 8 bits are of the form `A B C DDD EE`: -// A: Is secs component encoded? 1 = true -// B: Is nsecs component encoded? 1 = true -// C: Is tz component encoded? 1 = true -// DDD: Number of extra bytes for secs (range 0-7). -// If A = 1, secs encoded in DDD+1 bytes. -// If A = 0, secs is not encoded, and is assumed to be 0. -// If A = 1, then we need at least 1 byte to encode secs. -// DDD says the number of extra bytes beyond that 1. -// E.g. if DDD=0, then secs is represented in 1 byte. -// if DDD=2, then secs is represented in 3 bytes. -// EE: Number of extra bytes for nsecs (range 0-3). -// If B = 1, nsecs encoded in EE+1 bytes (similar to secs/DDD above) +// When encoding a timestamp, the first byte is the descriptor, which +// defines which components are encoded and how many bytes are used to +// encode secs and nsecs components. *If secs/nsecs is 0 or tz is UTC, it +// is not encoded in the byte array explicitly*. // -// Following the descriptor bytes, subsequent bytes are: +// Descriptor 8 bits are of the form `A B C DDD EE`: +// A: Is secs component encoded? 1 = true +// B: Is nsecs component encoded? 1 = true +// C: Is tz component encoded? 1 = true +// DDD: Number of extra bytes for secs (range 0-7). +// If A = 1, secs encoded in DDD+1 bytes. +// If A = 0, secs is not encoded, and is assumed to be 0. +// If A = 1, then we need at least 1 byte to encode secs. +// DDD says the number of extra bytes beyond that 1. +// E.g. if DDD=0, then secs is represented in 1 byte. +// if DDD=2, then secs is represented in 3 bytes. +// EE: Number of extra bytes for nsecs (range 0-3). +// If B = 1, nsecs encoded in EE+1 bytes (similar to secs/DDD above) // -// secs component encoded in `DDD + 1` bytes (if A == 1) -// nsecs component encoded in `EE + 1` bytes (if B == 1) -// tz component encoded in 2 bytes (if C == 1) +// Following the descriptor bytes, subsequent bytes are: // -// secs and nsecs components are integers encoded in a BigEndian -// 2-complement encoding format. +// secs component encoded in `DDD + 1` bytes (if A == 1) +// nsecs component encoded in `EE + 1` bytes (if B == 1) +// tz component encoded in 2 bytes (if C == 1) // -// tz component is encoded as 2 bytes (16 bits). Most significant bit 15 to -// Least significant bit 0 are described below: +// secs and nsecs components are integers encoded in a BigEndian +// 2-complement encoding format. // -// Timezone offset has a range of -12:00 to +14:00 (ie -720 to +840 minutes). -// Bit 15 = have\_dst: set to 1 if we set the dst flag. -// Bit 14 = dst\_on: set to 1 if dst is in effect at the time, or 0 if not. -// Bits 13..0 = timezone offset in minutes. It is a signed integer in Big Endian format. +// tz component is encoded as 2 bytes (16 bits). Most significant bit 15 to +// Least significant bit 0 are described below: // +// Timezone offset has a range of -12:00 to +14:00 (ie -720 to +840 minutes). +// Bit 15 = have\_dst: set to 1 if we set the dst flag. +// Bit 14 = dst\_on: set to 1 if dst is in effect at the time, or 0 if not. +// Bits 13..0 = timezone offset in minutes. It is a signed integer in Big Endian format. func bincEncodeTime(t time.Time) []byte { // t := rv2i(rv).(time.Time) tsecs, tnsecs := t.Unix(), t.Nanosecond() diff --git a/vendor/github.com/ugorji/go/codec/build.sh b/vendor/github.com/ugorji/go/codec/build.sh index c7704f758..023faf3d4 100644 --- a/vendor/github.com/ugorji/go/codec/build.sh +++ b/vendor/github.com/ugorji/go/codec/build.sh @@ -307,8 +307,10 @@ _usage() { cat <<EOF primary usage: $0 - -[tesow m n l d] -> [t=tests (e=extra, s=short, o=cover, w=wait), m=make, n=inlining diagnostics, l=mid-stack inlining, d=race detector] - -v -> v=verbose + -t[esow] -> t=tests [e=extra, s=short, o=cover, w=wait] + -[md] -> [m=make, d=race detector] + -[n l i] -> [n=inlining diagnostics, l=mid-stack inlining, i=check inlining for path (path)] + -v -> v=verbose EOF if [[ "$(type -t _usage_run)" = "function" ]]; then _usage_run ; fi } @@ -329,7 +331,7 @@ _main() { local gocmd=${MYGOCMD:-go} OPTIND=1 - while getopts ":cetmnrgpfvldsowkxyzb:" flag + while getopts ":cetmnrgpfvldsowkxyzi" flag do case "x$flag" in 'xo') zcover=1 ;; @@ -341,7 +343,7 @@ _main() { 'xl') zargs+=("-gcflags"); zargs+=("-l=4") ;; 'xn') zargs+=("-gcflags"); zargs+=("-m=2") ;; 'xd') zargs+=("-race") ;; - 'xb') x='b'; zbenchflags=${OPTARG} ;; + # 'xi') x='i'; zbenchflags=${OPTARG} ;; x\?) _usage; return 1 ;; *) x=$flag ;; esac @@ -359,7 +361,7 @@ _main() { 'xy') _analyze_debug_types "$@" ;; 'xz') _analyze_do_inlining_and_more "$@" ;; 'xk') _go_compiler_validation_suite ;; - 'xb') _bench "$@" ;; + 'xi') _check_inlining_one "$@" ;; esac # unset zforce zargs zbenchflags } diff --git a/vendor/github.com/ugorji/go/codec/cbor.go b/vendor/github.com/ugorji/go/codec/cbor.go index 45eb822b9..10944487e 100644 --- a/vendor/github.com/ugorji/go/codec/cbor.go +++ b/vendor/github.com/ugorji/go/codec/cbor.go @@ -7,6 +7,7 @@ import ( "math" "reflect" "time" + "unicode/utf8" ) // major @@ -629,7 +630,11 @@ func (d *cborDecDriver) DecodeBytes(bs []byte) (bsOut []byte) { } func (d *cborDecDriver) DecodeStringAsBytes() (s []byte) { - return d.DecodeBytes(nil) + s = d.DecodeBytes(nil) + if d.h.ValidateUnicode && !utf8.Valid(s) { + d.d.errorf("DecodeStringAsBytes: invalid UTF-8: %s", s) + } + return } func (d *cborDecDriver) DecodeTime() (t time.Time) { diff --git a/vendor/github.com/ugorji/go/codec/decode.go b/vendor/github.com/ugorji/go/codec/decode.go index d454db09c..db87f2e71 100644 --- a/vendor/github.com/ugorji/go/codec/decode.go +++ b/vendor/github.com/ugorji/go/codec/decode.go @@ -16,9 +16,9 @@ import ( const msgBadDesc = "unrecognized descriptor byte" const ( - decDefMaxDepth = 1024 // maximum depth - decDefChanCap = 64 // should be large, as cap cannot be expanded - decScratchByteArrayLen = (8 + 2 + 2) * 8 // around cacheLineSize ie ~64, depending on Decoder size + decDefMaxDepth = 1024 // maximum depth + decDefChanCap = 64 // should be large, as cap cannot be expanded + decScratchByteArrayLen = (8 + 2 + 2 + 1) * 8 // around cacheLineSize ie ~64, depending on Decoder size // MARKER: massage decScratchByteArrayLen to ensure xxxDecDriver structs fit within cacheLine*N @@ -150,13 +150,11 @@ type decDriver interface { // If the format doesn't prefix the length, it returns containerLenUnknown. // If the expected array was a nil in the stream, it returns containerLenNil. ReadArrayStart() int - ReadArrayEnd() // ReadMapStart will return the length of the array. // If the format doesn't prefix the length, it returns containerLenUnknown. // If the expected array was a nil in the stream, it returns containerLenNil. ReadMapStart() int - ReadMapEnd() reset() @@ -186,6 +184,8 @@ type decDriverContainerTracker interface { ReadArrayElem() ReadMapElemKey() ReadMapElemValue() + ReadArrayEnd() + ReadMapEnd() } type decNegintPosintFloatNumber interface { @@ -202,11 +202,11 @@ func (x decDriverNoopNumberHelper) decFloat() (f float64, ok bool) { panic("decF type decDriverNoopContainerReader struct{} -func (x decDriverNoopContainerReader) ReadArrayStart() (v int) { panic("ReadArrayStart unsupported") } -func (x decDriverNoopContainerReader) ReadArrayEnd() {} -func (x decDriverNoopContainerReader) ReadMapStart() (v int) { panic("ReadMapStart unsupported") } -func (x decDriverNoopContainerReader) ReadMapEnd() {} -func (x decDriverNoopContainerReader) CheckBreak() (v bool) { return } +// func (x decDriverNoopContainerReader) ReadArrayStart() (v int) { panic("ReadArrayStart unsupported") } +// func (x decDriverNoopContainerReader) ReadMapStart() (v int) { panic("ReadMapStart unsupported") } +func (x decDriverNoopContainerReader) ReadArrayEnd() {} +func (x decDriverNoopContainerReader) ReadMapEnd() {} +func (x decDriverNoopContainerReader) CheckBreak() (v bool) { return } // DecodeOptions captures configuration options during decode. type DecodeOptions struct { @@ -335,6 +335,12 @@ type DecodeOptions struct { // // This mostly impacts when we decode registered extensions. PreferPointerForStructOrArray bool + + // ValidateUnicode controls will cause decoding to fail if an expected unicode + // string is well-formed but include invalid codepoints. + // + // This could have a performance impact. + ValidateUnicode bool } // ---------------------------------------- @@ -638,7 +644,7 @@ func (d *Decoder) kInterface(f *codecFnInfo, rv reflect.Value) { // decode into it, and reset the interface to that new value. if !canDecode { - rvn2 := d.oneShotAddrRV(rvType(rvn), rvn.Kind()) + rvn2 := d.oneShotAddrRV(rvn.Type(), rvn.Kind()) rvSetDirect(rvn2, rvn) rvn = rvn2 } @@ -660,6 +666,16 @@ func decStructFieldKeyNotString(dd decDriver, keyType valueType, b *[decScratchB return } +func (d *Decoder) kStructField(si *structFieldInfo, rv reflect.Value) { + if d.d.TryNil() { + if rv = si.path.field(rv); rv.IsValid() { + decSetNonNilRV2Zero(rv) + } + return + } + d.decodeValueNoCheckNil(si.path.fieldAlloc(rv), nil) +} + func (d *Decoder) kStruct(f *codecFnInfo, rv reflect.Value) { ctyp := d.d.ContainerType() ti := f.ti @@ -691,7 +707,7 @@ func (d *Decoder) kStruct(f *codecFnInfo, rv reflect.Value) { } d.mapElemValue() if si := ti.siForEncName(rvkencname); si != nil { - d.decodeValue(si.path.fieldAlloc(rv), nil) + d.kStructField(si, rv) } else if mf != nil { // store rvkencname in new []byte, as it previously shares Decoder.b, which is used in decode name2 = append(name2[:0], rvkencname...) @@ -713,38 +729,21 @@ func (d *Decoder) kStruct(f *codecFnInfo, rv reflect.Value) { } // Not much gain from doing it two ways for array. // Arrays are not used as much for structs. - hasLen := containerLen >= 0 - var checkbreak bool tisfi := ti.sfi.source() - for j, si := range tisfi { - if hasLen { - if j == containerLen { - break - } - } else if d.checkBreak() { - checkbreak = true - break - } + hasLen := containerLen >= 0 + + // iterate all the items in the stream + // if mapped elem-wise to a field, handle it + // if more stream items than cap be mapped, error it + for j := 0; d.containerNext(j, containerLen, hasLen); j++ { d.arrayElem() - d.decodeValue(si.path.fieldAlloc(rv), nil) - } - var proceed bool - if hasLen { - proceed = containerLen > len(tisfi) - } else { - proceed = !checkbreak - } - // if (hasLen && containerLen > len(tisfi)) || (!hasLen && !checkbreak) { - if proceed { - // read remaining values and throw away - for j := len(tisfi); ; j++ { - if !d.containerNext(j, containerLen, hasLen) { - break - } - d.arrayElem() + if j < len(tisfi) { + d.kStructField(tisfi[j], rv) + } else { d.structFieldNotFound(j, "") } } + d.arrayEnd() } else { d.onerror(errNeedMapOrArrayDecodeToStruct) @@ -1215,7 +1214,7 @@ func (d *Decoder) kMap(f *codecFnInfo, rv reflect.Value) { d.decodeValue(rvk, keyFn) // special case if interface wrapping a byte slice if ktypeIsIntf { - if rvk2 := rvk.Elem(); rvk2.IsValid() && rvType(rvk2) == uint8SliceTyp { + if rvk2 := rvk.Elem(); rvk2.IsValid() && rvk2.Type() == uint8SliceTyp { kstr2bs = rvGetBytes(rvk2) rvSetIntf(rvk, rv4istr(fnRvk2())) } @@ -1406,6 +1405,7 @@ func (d *Decoder) r() *decRd { func (d *Decoder) init(h Handle) { initHandle(h) + d.cbreak = d.js || d.cbor d.bytes = true d.err = errDecoderNotInitialized d.h = h.getBasicHandle() @@ -1450,21 +1450,11 @@ func (d *Decoder) Reset(r io.Reader) { r = &eofReader } d.bytes = false - if d.h.ReaderBufferSize > 0 { - if d.bi == nil { - d.bi = new(bufioDecReader) - } - d.bi.reset(r, d.h.ReaderBufferSize, &d.blist) - d.bufio = true - d.decReader = d.bi - } else { - if d.ri == nil { - d.ri = new(ioDecReader) - } - d.ri.reset(r, &d.blist) - d.bufio = false - d.decReader = d.ri + if d.ri == nil { + d.ri = new(ioDecReader) } + d.ri.reset(r, d.h.ReaderBufferSize, &d.blist) + d.decReader = d.ri d.resetCommon() } @@ -1474,7 +1464,6 @@ func (d *Decoder) ResetBytes(in []byte) { if in == nil { in = []byte{} } - d.bufio = false d.bytes = true d.decReader = &d.rb d.rb.reset(in) @@ -1505,14 +1494,15 @@ func (d *Decoder) naked() *fauxUnion { // We will decode and store a value in that nil interface. // // Sample usages: -// // Decoding into a non-nil typed value -// var f float32 -// err = codec.NewDecoder(r, handle).Decode(&f) // -// // Decoding into nil interface -// var v interface{} -// dec := codec.NewDecoder(r, handle) -// err = dec.Decode(&v) +// // Decoding into a non-nil typed value +// var f float32 +// err = codec.NewDecoder(r, handle).Decode(&f) +// +// // Decoding into nil interface +// var v interface{} +// dec := codec.NewDecoder(r, handle) +// err = dec.Decode(&v) // // When decoding into a nil interface{}, we will decode into an appropriate value based // on the contents of the stream: @@ -1520,6 +1510,7 @@ func (d *Decoder) naked() *fauxUnion { // - Other values are decoded appropriately depending on the type: // bool, string, []byte, time.Time, etc // - Extensions are decoded as RawExt (if no ext function registered for the tag) +// // Configurations exist on the Handle to override defaults // (e.g. for MapType, SliceType and how to decode raw bytes). // @@ -1814,7 +1805,7 @@ PTR: if rv.Kind() == reflect.Ptr { rvpValid = true if rvIsNil(rv) { - rvSetDirect(rv, reflect.New(rvType(rv).Elem())) + rvSetDirect(rv, reflect.New(rv.Type().Elem())) } rvp = rv rv = rv.Elem() @@ -1822,7 +1813,7 @@ PTR: } if fn == nil { - fn = d.h.fn(rvType(rv)) + fn = d.h.fn(rv.Type()) } if fn.i.addrD { if rvpValid { @@ -1908,9 +1899,9 @@ func (d *Decoder) rawBytes() (v []byte) { // i.e. if necessary, make new copy always. v = d.d.nextValueBytes([]byte{}) if d.bytes && !d.h.ZeroCopy { - v0 := v - v = make([]byte, len(v)) - copy(v, v0) + vv := make([]byte, len(v)) + copy(vv, v) // using copy here triggers make+copy optimization eliding memclr + v = vv } return } @@ -1941,7 +1932,34 @@ func (d *Decoder) decodeFloat32() float32 { // MARKER: do not call mapEnd if mapStart returns containerLenNil. +// MARKER: optimize decoding since all formats do not truly support all decDriver'ish operations. +// - Read(Map|Array)Start is only supported by all formats. +// - CheckBreak is only supported by json and cbor. +// - Read(Map|Array)End is only supported by json. +// - Read(Map|Array)Elem(Kay|Value) is only supported by json. +// Honor these in the code, to reduce the number of interface calls (even if empty). + +func (d *Decoder) checkBreak() (v bool) { + // MARKER: jsonDecDriver.CheckBreak() cannot be inlined (over budget inlining cost). + // Consequently, there's no benefit in incurring the cost of this wrapping function. + // It is faster to just call the interface method directly. + + // if d.js { + // return d.jsondriver().CheckBreak() + // } + // if d.cbor { + // return d.cbordriver().CheckBreak() + // } + + if d.cbreak { + v = d.d.CheckBreak() + } + return +} + func (d *Decoder) containerNext(j, containerLen int, hasLen bool) bool { + // MARKER: keep in sync with gen-helper.go.tmpl + // return (hasLen && j < containerLen) || !(hasLen || slh.d.checkBreak()) if hasLen { return j < containerLen @@ -1972,7 +1990,10 @@ func (d *Decoder) mapElemValue() { } func (d *Decoder) mapEnd() { - d.d.ReadMapEnd() + if d.js { + d.jsondriver().ReadMapEnd() + } + // d.d.ReadMapEnd() d.depthDecr() d.c = 0 } @@ -1993,7 +2014,10 @@ func (d *Decoder) arrayElem() { } func (d *Decoder) arrayEnd() { - d.d.ReadArrayEnd() + if d.js { + d.jsondriver().ReadArrayEnd() + } + // d.d.ReadArrayEnd() d.depthDecr() d.c = 0 } @@ -2028,7 +2052,7 @@ func (d *Decoder) interfaceExtConvertAndDecode(v interface{}, ext InterfaceExt) if !rv.CanAddr() { rvk = rv.Kind() - rv2 = d.oneShotAddrRV(rvType(rv), rvk) + rv2 = d.oneShotAddrRV(rv.Type(), rvk) if rvk == reflect.Interface { rvSetIntf(rv2, rv) } else { @@ -2157,9 +2181,9 @@ func (x decSliceHelper) arrayCannotExpand(hasLen bool, lenv, j, containerLenS in // decNextValueBytesHelper helps with NextValueBytes calls. // // Typical usage: -// - each Handle's decDriver will implement a high level nextValueBytes, -// which will track the current cursor, delegate to a nextValueBytesR -// method, and then potentially call bytesRdV at the end. +// - each Handle's decDriver will implement a high level nextValueBytes, +// which will track the current cursor, delegate to a nextValueBytesR +// method, and then potentially call bytesRdV at the end. // // See simple.go for typical usage model. type decNextValueBytesHelper struct { @@ -2178,6 +2202,12 @@ func (x decNextValueBytesHelper) appendN(v *[]byte, b ...byte) { } } +func (x decNextValueBytesHelper) appendS(v *[]byte, b string) { + if *v != nil && !x.d.bytes { + *v = append(*v, b...) + } +} + func (x decNextValueBytesHelper) bytesRdV(v *[]byte, startpos uint) { if x.d.bytes { *v = x.d.rb.b[startpos:x.d.rb.c] @@ -2281,12 +2311,8 @@ func isDecodeable(rv reflect.Value) (canDecode bool, reason decNotDecodeableReas } func decByteSlice(r *decRd, clen, maxInitLen int, bs []byte) (bsOut []byte) { - if clen == 0 { - return zeroByteSlice - } - if len(bs) == clen { - bsOut = bs - r.readb(bsOut) + if clen <= 0 { + bsOut = zeroByteSlice } else if cap(bs) >= clen { bsOut = bs[:clen] r.readb(bsOut) @@ -2305,10 +2331,10 @@ func decByteSlice(r *decRd, clen, maxInitLen int, bs []byte) (bsOut []byte) { } // decInferLen will infer a sensible length, given the following: -// - clen: length wanted. -// - maxlen: max length to be returned. -// if <= 0, it is unset, and we infer it based on the unit size -// - unit: number of bytes for each element of the collection +// - clen: length wanted. +// - maxlen: max length to be returned. +// if <= 0, it is unset, and we infer it based on the unit size +// - unit: number of bytes for each element of the collection func decInferLen(clen, maxlen, unit int) int { // anecdotal testing showed increase in allocation with map length of 16. // We saw same typical alloc from 0-8, then a 20% increase at 16. diff --git a/vendor/github.com/ugorji/go/codec/doc.go b/vendor/github.com/ugorji/go/codec/doc.go index b390f9a8f..1a16bca8b 100644 --- a/vendor/github.com/ugorji/go/codec/doc.go +++ b/vendor/github.com/ugorji/go/codec/doc.go @@ -73,23 +73,23 @@ Rich Feature Set includes: - Drop-in replacement for encoding/json. `json:` key in struct tag supported. - Provides a RPC Server and Client Codec for net/rpc communication protocol. - Handle unique idiosyncrasies of codecs e.g. - - For messagepack, configure how ambiguities in handling raw bytes are resolved - - For messagepack, provide rpc server/client codec to support - msgpack-rpc protocol defined at: - https://github.com/msgpack-rpc/msgpack-rpc/blob/master/spec.md + For messagepack, configure how ambiguities in handling raw bytes are resolved and + provide rpc server/client codec to support + msgpack-rpc protocol defined at: + https://github.com/msgpack-rpc/msgpack-rpc/blob/master/spec.md -Extension Support +# Extension Support Users can register a function to handle the encoding or decoding of their custom types. There are no restrictions on what the custom type can be. Some examples: - type BisSet []int - type BitSet64 uint64 - type UUID string - type MyStructWithUnexportedFields struct { a int; b bool; c []int; } - type GifImage struct { ... } + type BisSet []int + type BitSet64 uint64 + type UUID string + type MyStructWithUnexportedFields struct { a int; b bool; c []int; } + type GifImage struct { ... } As an illustration, MyStructWithUnexportedFields would normally be encoded as an empty map because it has no exported fields, while UUID @@ -99,7 +99,7 @@ encode any of these however you like. There is also seamless support provided for registering an extension (with a tag) but letting the encoding mechanism default to the standard way. -Custom Encoding and Decoding +# Custom Encoding and Decoding This package maintains symmetry in the encoding and decoding halfs. We determine how to encode or decode by walking this decision tree @@ -120,12 +120,12 @@ Consequently, if a type only defines one-half of the symmetry then that type doesn't satisfy the check and we will continue walking down the decision tree. -RPC +# RPC RPC Client and Server Codecs are implemented, so the codecs can be used with the standard net/rpc package. -Usage +# Usage The Handle is SAFE for concurrent READ, but NOT SAFE for concurrent modification. @@ -133,96 +133,95 @@ The Encoder and Decoder are NOT safe for concurrent use. Consequently, the usage model is basically: - - Create and initialize the Handle before any use. - Once created, DO NOT modify it. - - Multiple Encoders or Decoders can now use the Handle concurrently. - They only read information off the Handle (never write). - - However, each Encoder or Decoder MUST not be used concurrently - - To re-use an Encoder/Decoder, call Reset(...) on it first. - This allows you use state maintained on the Encoder/Decoder. + - Create and initialize the Handle before any use. + Once created, DO NOT modify it. + - Multiple Encoders or Decoders can now use the Handle concurrently. + They only read information off the Handle (never write). + - However, each Encoder or Decoder MUST not be used concurrently + - To re-use an Encoder/Decoder, call Reset(...) on it first. + This allows you use state maintained on the Encoder/Decoder. Sample usage model: - // create and configure Handle - var ( - bh codec.BincHandle - mh codec.MsgpackHandle - ch codec.CborHandle - ) - - mh.MapType = reflect.TypeOf(map[string]interface{}(nil)) - - // configure extensions - // e.g. for msgpack, define functions and enable Time support for tag 1 - // mh.SetExt(reflect.TypeOf(time.Time{}), 1, myExt) - - // create and use decoder/encoder - var ( - r io.Reader - w io.Writer - b []byte - h = &bh // or mh to use msgpack - ) - - dec = codec.NewDecoder(r, h) - dec = codec.NewDecoderBytes(b, h) - err = dec.Decode(&v) - - enc = codec.NewEncoder(w, h) - enc = codec.NewEncoderBytes(&b, h) - err = enc.Encode(v) - - //RPC Server - go func() { - for { - conn, err := listener.Accept() - rpcCodec := codec.GoRpc.ServerCodec(conn, h) - //OR rpcCodec := codec.MsgpackSpecRpc.ServerCodec(conn, h) - rpc.ServeCodec(rpcCodec) - } - }() - - //RPC Communication (client side) - conn, err = net.Dial("tcp", "localhost:5555") - rpcCodec := codec.GoRpc.ClientCodec(conn, h) - //OR rpcCodec := codec.MsgpackSpecRpc.ClientCodec(conn, h) - client := rpc.NewClientWithCodec(rpcCodec) - -Running Tests + // create and configure Handle + var ( + bh codec.BincHandle + mh codec.MsgpackHandle + ch codec.CborHandle + ) + + mh.MapType = reflect.TypeOf(map[string]interface{}(nil)) + + // configure extensions + // e.g. for msgpack, define functions and enable Time support for tag 1 + // mh.SetExt(reflect.TypeOf(time.Time{}), 1, myExt) + + // create and use decoder/encoder + var ( + r io.Reader + w io.Writer + b []byte + h = &bh // or mh to use msgpack + ) + + dec = codec.NewDecoder(r, h) + dec = codec.NewDecoderBytes(b, h) + err = dec.Decode(&v) + + enc = codec.NewEncoder(w, h) + enc = codec.NewEncoderBytes(&b, h) + err = enc.Encode(v) + + //RPC Server + go func() { + for { + conn, err := listener.Accept() + rpcCodec := codec.GoRpc.ServerCodec(conn, h) + //OR rpcCodec := codec.MsgpackSpecRpc.ServerCodec(conn, h) + rpc.ServeCodec(rpcCodec) + } + }() + + //RPC Communication (client side) + conn, err = net.Dial("tcp", "localhost:5555") + rpcCodec := codec.GoRpc.ClientCodec(conn, h) + //OR rpcCodec := codec.MsgpackSpecRpc.ClientCodec(conn, h) + client := rpc.NewClientWithCodec(rpcCodec) + +# Running Tests To run tests, use the following: - go test + go test To run the full suite of tests, use the following: - go test -tags alltests -run Suite + go test -tags alltests -run Suite You can run the tag 'codec.safe' to run tests or build in safe mode. e.g. - go test -tags codec.safe -run Json - go test -tags "alltests codec.safe" -run Suite + go test -tags codec.safe -run Json + go test -tags "alltests codec.safe" -run Suite Running Benchmarks - cd bench - go test -bench . -benchmem -benchtime 1s + cd bench + go test -bench . -benchmem -benchtime 1s Please see http://github.com/ugorji/go-codec-bench . -Caveats +# Caveats Struct fields matching the following are ignored during encoding and decoding - - struct tag value set to - - - func, complex numbers, unsafe pointers - - unexported and not embedded - - unexported and embedded and not struct kind - - unexported and embedded pointers (from go1.10) + - struct tag value set to - + - func, complex numbers, unsafe pointers + - unexported and not embedded + - unexported and embedded and not struct kind + - unexported and embedded pointers (from go1.10) Every other field in a struct will be encoded/decoded. Embedded fields are encoded as if they exist in the top-level struct, with some caveats. See Encode documentation. - */ package codec diff --git a/vendor/github.com/ugorji/go/codec/encode.go b/vendor/github.com/ugorji/go/codec/encode.go index e411bdb81..53389b085 100644 --- a/vendor/github.com/ugorji/go/codec/encode.go +++ b/vendor/github.com/ugorji/go/codec/encode.go @@ -686,15 +686,11 @@ func (e *Encoder) kMap(f *codecFnInfo, rv reflect.Value) { var rvv = mapAddrLoopvarRV(f.ti.elem, vtypeKind) - if e.h.Canonical { - e.kMapCanonical(f.ti, rv, rvv, valFn) - e.mapEnd() - return - } - rtkey := f.ti.key var keyTypeIsString = stringTypId == rt2id(rtkey) // rtkeyid - if !keyTypeIsString { + if keyTypeIsString { + keyFn = e.h.fn(rtkey) + } else { for rtkey.Kind() == reflect.Ptr { rtkey = rtkey.Elem() } @@ -703,6 +699,12 @@ func (e *Encoder) kMap(f *codecFnInfo, rv reflect.Value) { } } + if e.h.Canonical { + e.kMapCanonical(f.ti, rv, rvv, keyFn, valFn) + e.mapEnd() + return + } + var rvk = mapAddrLoopvarRV(f.ti.key, ktypeKind) var it mapIter @@ -723,11 +725,14 @@ func (e *Encoder) kMap(f *codecFnInfo, rv reflect.Value) { e.mapEnd() } -func (e *Encoder) kMapCanonical(ti *typeInfo, rv, rvv reflect.Value, valFn *codecFn) { - // we previously did out-of-band if an extension was registered. - // This is not necessary, as the natural kind is sufficient for ordering. - +func (e *Encoder) kMapCanonical(ti *typeInfo, rv, rvv reflect.Value, keyFn, valFn *codecFn) { + // The base kind of the type of the map key is sufficient for ordering. + // We only do out of band if that kind is not ordered (number or string), bool or time.Time. + // If the key is a predeclared type, directly call methods on encDriver e.g. EncodeString + // but if not, call encodeValue, in case it has an extension registered or otherwise. rtkey := ti.key + rtkeydecl := rtkey.PkgPath() == "" && rtkey.Name() != "" // key type is predeclared + mks := rv.MapKeys() rtkeyKind := rtkey.Kind() kfast := mapKeyFastKindFor(rtkeyKind) @@ -736,18 +741,24 @@ func (e *Encoder) kMapCanonical(ti *typeInfo, rv, rvv reflect.Value, valFn *code switch rtkeyKind { case reflect.Bool: - mksv := make([]boolRv, len(mks)) - for i, k := range mks { - v := &mksv[i] - v.r = k - v.v = k.Bool() + // though bool keys make no sense in a map, it *could* happen. + // in that case, we MUST support it in reflection mode, + // as that is the fallback for even codecgen and others. + + // sort the keys so that false comes before true + // ie if 2 keys in order (true, false), then swap them + if len(mks) == 2 && mks[0].Bool() { + mks[0], mks[1] = mks[1], mks[0] } - sort.Sort(boolRvSlice(mksv)) - for i := range mksv { + for i := range mks { e.mapElemKey() - e.e.EncodeBool(mksv[i].v) + if rtkeydecl { + e.e.EncodeBool(mks[i].Bool()) + } else { + e.encodeValueNonNil(mks[i], keyFn) + } e.mapElemValue() - e.encodeValue(mapGet(rv, mksv[i].r, rvv, kfast, visindirect, visref), valFn) + e.encodeValue(mapGet(rv, mks[i], rvv, kfast, visindirect, visref), valFn) } case reflect.String: mksv := make([]stringRv, len(mks)) @@ -759,7 +770,11 @@ func (e *Encoder) kMapCanonical(ti *typeInfo, rv, rvv reflect.Value, valFn *code sort.Sort(stringRvSlice(mksv)) for i := range mksv { e.mapElemKey() - e.e.EncodeString(mksv[i].v) + if rtkeydecl { + e.e.EncodeString(mksv[i].v) + } else { + e.encodeValueNonNil(mksv[i].r, keyFn) + } e.mapElemValue() e.encodeValue(mapGet(rv, mksv[i].r, rvv, kfast, visindirect, visref), valFn) } @@ -773,7 +788,11 @@ func (e *Encoder) kMapCanonical(ti *typeInfo, rv, rvv reflect.Value, valFn *code sort.Sort(uint64RvSlice(mksv)) for i := range mksv { e.mapElemKey() - e.e.EncodeUint(mksv[i].v) + if rtkeydecl { + e.e.EncodeUint(mksv[i].v) + } else { + e.encodeValueNonNil(mksv[i].r, keyFn) + } e.mapElemValue() e.encodeValue(mapGet(rv, mksv[i].r, rvv, kfast, visindirect, visref), valFn) } @@ -787,7 +806,11 @@ func (e *Encoder) kMapCanonical(ti *typeInfo, rv, rvv reflect.Value, valFn *code sort.Sort(int64RvSlice(mksv)) for i := range mksv { e.mapElemKey() - e.e.EncodeInt(mksv[i].v) + if rtkeydecl { + e.e.EncodeInt(mksv[i].v) + } else { + e.encodeValueNonNil(mksv[i].r, keyFn) + } e.mapElemValue() e.encodeValue(mapGet(rv, mksv[i].r, rvv, kfast, visindirect, visref), valFn) } @@ -801,7 +824,11 @@ func (e *Encoder) kMapCanonical(ti *typeInfo, rv, rvv reflect.Value, valFn *code sort.Sort(float64RvSlice(mksv)) for i := range mksv { e.mapElemKey() - e.e.EncodeFloat32(float32(mksv[i].v)) + if rtkeydecl { + e.e.EncodeFloat32(float32(mksv[i].v)) + } else { + e.encodeValueNonNil(mksv[i].r, keyFn) + } e.mapElemValue() e.encodeValue(mapGet(rv, mksv[i].r, rvv, kfast, visindirect, visref), valFn) } @@ -815,11 +842,15 @@ func (e *Encoder) kMapCanonical(ti *typeInfo, rv, rvv reflect.Value, valFn *code sort.Sort(float64RvSlice(mksv)) for i := range mksv { e.mapElemKey() - e.e.EncodeFloat64(mksv[i].v) + if rtkeydecl { + e.e.EncodeFloat64(mksv[i].v) + } else { + e.encodeValueNonNil(mksv[i].r, keyFn) + } e.mapElemValue() e.encodeValue(mapGet(rv, mksv[i].r, rvv, kfast, visindirect, visref), valFn) } - case reflect.Struct: + default: if rtkey == timeTyp { mksv := make([]timeRv, len(mks)) for i, k := range mks { @@ -836,8 +867,7 @@ func (e *Encoder) kMapCanonical(ti *typeInfo, rv, rvv reflect.Value, valFn *code } break } - fallthrough - default: + // out-of-band // first encode each key to a []byte first, then sort them, then record bs0 := e.blist.get(len(mks) * 16) @@ -1010,16 +1040,17 @@ func (e *Encoder) ResetBytes(out *[]byte) { // To set an option on all fields (e.g. omitempty on all fields), you // can create a field called _struct, and set flags on it. The options // which can be set on _struct are: -// - omitempty: so all fields are omitted if empty -// - toarray: so struct is encoded as an array -// - int: so struct key names are encoded as signed integers (instead of strings) -// - uint: so struct key names are encoded as unsigned integers (instead of strings) -// - float: so struct key names are encoded as floats (instead of strings) +// - omitempty: so all fields are omitted if empty +// - toarray: so struct is encoded as an array +// - int: so struct key names are encoded as signed integers (instead of strings) +// - uint: so struct key names are encoded as unsigned integers (instead of strings) +// - float: so struct key names are encoded as floats (instead of strings) +// // More details on these below. // // Struct values "usually" encode as maps. Each exported struct field is encoded unless: -// - the field's tag is "-", OR -// - the field is empty (empty or the zero value) and its tag specifies the "omitempty" option. +// - the field's tag is "-", OR +// - the field is empty (empty or the zero value) and its tag specifies the "omitempty" option. // // When encoding as a map, the first string in the tag (before the comma) // is the map key string to use when encoding. @@ -1032,8 +1063,9 @@ func (e *Encoder) ResetBytes(out *[]byte) { // This is done with the int,uint or float option on the _struct field (see above). // // However, struct values may encode as arrays. This happens when: -// - StructToArray Encode option is set, OR -// - the tag on the _struct field sets the "toarray" option +// - StructToArray Encode option is set, OR +// - the tag on the _struct field sets the "toarray" option +// // Note that omitempty is ignored when encoding struct values as arrays, // as an entry must be encoded for each field, to maintain its position. // @@ -1043,33 +1075,33 @@ func (e *Encoder) ResetBytes(out *[]byte) { // or interface value, and any array, slice, map, or string of length zero. // // Anonymous fields are encoded inline except: -// - the struct tag specifies a replacement name (first value) -// - the field is of an interface type +// - the struct tag specifies a replacement name (first value) +// - the field is of an interface type // // Examples: // -// // NOTE: 'json:' can be used as struct tag key, in place 'codec:' below. -// type MyStruct struct { -// _struct bool `codec:",omitempty"` //set omitempty for every field -// Field1 string `codec:"-"` //skip this field -// Field2 int `codec:"myName"` //Use key "myName" in encode stream -// Field3 int32 `codec:",omitempty"` //use key "Field3". Omit if empty. -// Field4 bool `codec:"f4,omitempty"` //use key "f4". Omit if empty. -// io.Reader //use key "Reader". -// MyStruct `codec:"my1" //use key "my1". -// MyStruct //inline it -// ... -// } +// // NOTE: 'json:' can be used as struct tag key, in place 'codec:' below. +// type MyStruct struct { +// _struct bool `codec:",omitempty"` //set omitempty for every field +// Field1 string `codec:"-"` //skip this field +// Field2 int `codec:"myName"` //Use key "myName" in encode stream +// Field3 int32 `codec:",omitempty"` //use key "Field3". Omit if empty. +// Field4 bool `codec:"f4,omitempty"` //use key "f4". Omit if empty. +// io.Reader //use key "Reader". +// MyStruct `codec:"my1" //use key "my1". +// MyStruct //inline it +// ... +// } // -// type MyStruct struct { -// _struct bool `codec:",toarray"` //encode struct as an array -// } +// type MyStruct struct { +// _struct bool `codec:",toarray"` //encode struct as an array +// } // -// type MyStruct struct { -// _struct bool `codec:",uint"` //encode struct with "unsigned integer" keys -// Field1 string `codec:"1"` //encode Field1 key using: EncodeInt(1) -// Field2 string `codec:"2"` //encode Field2 key using: EncodeInt(2) -// } +// type MyStruct struct { +// _struct bool `codec:",uint"` //encode struct with "unsigned integer" keys +// Field1 string `codec:"1"` //encode Field1 key using: EncodeInt(1) +// Field2 string `codec:"2"` //encode Field2 key using: EncodeInt(2) +// } // // The mode of encoding is based on the type of the value. When a value is seen: // - If a Selfer, call its CodecEncodeSelf method @@ -1293,7 +1325,7 @@ TOP: } if fn == nil { - fn = e.h.fn(rvType(rv)) + fn = e.h.fn(rv.Type()) } if !fn.i.addrE { // typically, addrE = false, so check it first @@ -1310,6 +1342,19 @@ TOP: } } +// encodeValueNonNil can encode a number, bool, or string +// OR non-nil values of kind map, slice and chan. +func (e *Encoder) encodeValueNonNil(rv reflect.Value, fn *codecFn) { + if fn == nil { + fn = e.h.fn(rv.Type()) + } + + if fn.i.addrE { // typically, addrE = false, so check it first + rv = e.addrRV(rv, fn.i.ti.rt, fn.i.ti.ptr) + } + fn.fe(e, &fn.i, rv) +} + // addrRV returns a addressable value which may be readonly func (e *Encoder) addrRV(rv reflect.Value, typ, ptrType reflect.Type) (rva reflect.Value) { if rv.CanAddr() { diff --git a/vendor/github.com/ugorji/go/codec/fast-path.generated.go b/vendor/github.com/ugorji/go/codec/fast-path.generated.go index a2c258196..941ef798f 100644 --- a/vendor/github.com/ugorji/go/codec/fast-path.generated.go +++ b/vendor/github.com/ugorji/go/codec/fast-path.generated.go @@ -3019,7 +3019,7 @@ func (fastpathT) DecSliceIntfY(v []interface{}, d *Decoder) (v2 []interface{}, c } } var j int - for j = 0; (hasLen && j < containerLenS) || !(hasLen || d.checkBreak()); j++ { + for j = 0; d.containerNext(j, containerLenS, hasLen); j++ { if j == 0 && len(v) == 0 { // means hasLen == false xlen = decInferLen(containerLenS, d.h.MaxInitLen, 16) v = make([]interface{}, uint(xlen)) @@ -3052,7 +3052,7 @@ func (fastpathT) DecSliceIntfN(v []interface{}, d *Decoder) { return } hasLen := containerLenS > 0 - for j := 0; (hasLen && j < containerLenS) || !(hasLen || d.checkBreak()); j++ { + for j := 0; d.containerNext(j, containerLenS, hasLen); j++ { if j >= len(v) { slh.arrayCannotExpand(hasLen, len(v), j, containerLenS) return @@ -3118,7 +3118,7 @@ func (fastpathT) DecSliceStringY(v []string, d *Decoder) (v2 []string, changed b } } var j int - for j = 0; (hasLen && j < containerLenS) || !(hasLen || d.checkBreak()); j++ { + for j = 0; d.containerNext(j, containerLenS, hasLen); j++ { if j == 0 && len(v) == 0 { // means hasLen == false xlen = decInferLen(containerLenS, d.h.MaxInitLen, 16) v = make([]string, uint(xlen)) @@ -3151,7 +3151,7 @@ func (fastpathT) DecSliceStringN(v []string, d *Decoder) { return } hasLen := containerLenS > 0 - for j := 0; (hasLen && j < containerLenS) || !(hasLen || d.checkBreak()); j++ { + for j := 0; d.containerNext(j, containerLenS, hasLen); j++ { if j >= len(v) { slh.arrayCannotExpand(hasLen, len(v), j, containerLenS) return @@ -3217,7 +3217,7 @@ func (fastpathT) DecSliceBytesY(v [][]byte, d *Decoder) (v2 [][]byte, changed bo } } var j int - for j = 0; (hasLen && j < containerLenS) || !(hasLen || d.checkBreak()); j++ { + for j = 0; d.containerNext(j, containerLenS, hasLen); j++ { if j == 0 && len(v) == 0 { // means hasLen == false xlen = decInferLen(containerLenS, d.h.MaxInitLen, 24) v = make([][]byte, uint(xlen)) @@ -3250,7 +3250,7 @@ func (fastpathT) DecSliceBytesN(v [][]byte, d *Decoder) { return } hasLen := containerLenS > 0 - for j := 0; (hasLen && j < containerLenS) || !(hasLen || d.checkBreak()); j++ { + for j := 0; d.containerNext(j, containerLenS, hasLen); j++ { if j >= len(v) { slh.arrayCannotExpand(hasLen, len(v), j, containerLenS) return @@ -3316,7 +3316,7 @@ func (fastpathT) DecSliceFloat32Y(v []float32, d *Decoder) (v2 []float32, change } } var j int - for j = 0; (hasLen && j < containerLenS) || !(hasLen || d.checkBreak()); j++ { + for j = 0; d.containerNext(j, containerLenS, hasLen); j++ { if j == 0 && len(v) == 0 { // means hasLen == false xlen = decInferLen(containerLenS, d.h.MaxInitLen, 4) v = make([]float32, uint(xlen)) @@ -3349,7 +3349,7 @@ func (fastpathT) DecSliceFloat32N(v []float32, d *Decoder) { return } hasLen := containerLenS > 0 - for j := 0; (hasLen && j < containerLenS) || !(hasLen || d.checkBreak()); j++ { + for j := 0; d.containerNext(j, containerLenS, hasLen); j++ { if j >= len(v) { slh.arrayCannotExpand(hasLen, len(v), j, containerLenS) return @@ -3415,7 +3415,7 @@ func (fastpathT) DecSliceFloat64Y(v []float64, d *Decoder) (v2 []float64, change } } var j int - for j = 0; (hasLen && j < containerLenS) || !(hasLen || d.checkBreak()); j++ { + for j = 0; d.containerNext(j, containerLenS, hasLen); j++ { if j == 0 && len(v) == 0 { // means hasLen == false xlen = decInferLen(containerLenS, d.h.MaxInitLen, 8) v = make([]float64, uint(xlen)) @@ -3448,7 +3448,7 @@ func (fastpathT) DecSliceFloat64N(v []float64, d *Decoder) { return } hasLen := containerLenS > 0 - for j := 0; (hasLen && j < containerLenS) || !(hasLen || d.checkBreak()); j++ { + for j := 0; d.containerNext(j, containerLenS, hasLen); j++ { if j >= len(v) { slh.arrayCannotExpand(hasLen, len(v), j, containerLenS) return @@ -3522,7 +3522,7 @@ func (fastpathT) DecSliceUint8Y(v []uint8, d *Decoder) (v2 []uint8, changed bool } } var j int - for j = 0; (hasLen && j < containerLenS) || !(hasLen || d.checkBreak()); j++ { + for j = 0; d.containerNext(j, containerLenS, hasLen); j++ { if j == 0 && len(v) == 0 { // means hasLen == false xlen = decInferLen(containerLenS, d.h.MaxInitLen, 1) v = make([]uint8, uint(xlen)) @@ -3565,7 +3565,7 @@ func (fastpathT) DecSliceUint8N(v []uint8, d *Decoder) { return } hasLen := containerLenS > 0 - for j := 0; (hasLen && j < containerLenS) || !(hasLen || d.checkBreak()); j++ { + for j := 0; d.containerNext(j, containerLenS, hasLen); j++ { if j >= len(v) { slh.arrayCannotExpand(hasLen, len(v), j, containerLenS) return @@ -3631,7 +3631,7 @@ func (fastpathT) DecSliceUint64Y(v []uint64, d *Decoder) (v2 []uint64, changed b } } var j int - for j = 0; (hasLen && j < containerLenS) || !(hasLen || d.checkBreak()); j++ { + for j = 0; d.containerNext(j, containerLenS, hasLen); j++ { if j == 0 && len(v) == 0 { // means hasLen == false xlen = decInferLen(containerLenS, d.h.MaxInitLen, 8) v = make([]uint64, uint(xlen)) @@ -3664,7 +3664,7 @@ func (fastpathT) DecSliceUint64N(v []uint64, d *Decoder) { return } hasLen := containerLenS > 0 - for j := 0; (hasLen && j < containerLenS) || !(hasLen || d.checkBreak()); j++ { + for j := 0; d.containerNext(j, containerLenS, hasLen); j++ { if j >= len(v) { slh.arrayCannotExpand(hasLen, len(v), j, containerLenS) return @@ -3730,7 +3730,7 @@ func (fastpathT) DecSliceIntY(v []int, d *Decoder) (v2 []int, changed bool) { } } var j int - for j = 0; (hasLen && j < containerLenS) || !(hasLen || d.checkBreak()); j++ { + for j = 0; d.containerNext(j, containerLenS, hasLen); j++ { if j == 0 && len(v) == 0 { // means hasLen == false xlen = decInferLen(containerLenS, d.h.MaxInitLen, 8) v = make([]int, uint(xlen)) @@ -3763,7 +3763,7 @@ func (fastpathT) DecSliceIntN(v []int, d *Decoder) { return } hasLen := containerLenS > 0 - for j := 0; (hasLen && j < containerLenS) || !(hasLen || d.checkBreak()); j++ { + for j := 0; d.containerNext(j, containerLenS, hasLen); j++ { if j >= len(v) { slh.arrayCannotExpand(hasLen, len(v), j, containerLenS) return @@ -3829,7 +3829,7 @@ func (fastpathT) DecSliceInt32Y(v []int32, d *Decoder) (v2 []int32, changed bool } } var j int - for j = 0; (hasLen && j < containerLenS) || !(hasLen || d.checkBreak()); j++ { + for j = 0; d.containerNext(j, containerLenS, hasLen); j++ { if j == 0 && len(v) == 0 { // means hasLen == false xlen = decInferLen(containerLenS, d.h.MaxInitLen, 4) v = make([]int32, uint(xlen)) @@ -3862,7 +3862,7 @@ func (fastpathT) DecSliceInt32N(v []int32, d *Decoder) { return } hasLen := containerLenS > 0 - for j := 0; (hasLen && j < containerLenS) || !(hasLen || d.checkBreak()); j++ { + for j := 0; d.containerNext(j, containerLenS, hasLen); j++ { if j >= len(v) { slh.arrayCannotExpand(hasLen, len(v), j, containerLenS) return @@ -3928,7 +3928,7 @@ func (fastpathT) DecSliceInt64Y(v []int64, d *Decoder) (v2 []int64, changed bool } } var j int - for j = 0; (hasLen && j < containerLenS) || !(hasLen || d.checkBreak()); j++ { + for j = 0; d.containerNext(j, containerLenS, hasLen); j++ { if j == 0 && len(v) == 0 { // means hasLen == false xlen = decInferLen(containerLenS, d.h.MaxInitLen, 8) v = make([]int64, uint(xlen)) @@ -3961,7 +3961,7 @@ func (fastpathT) DecSliceInt64N(v []int64, d *Decoder) { return } hasLen := containerLenS > 0 - for j := 0; (hasLen && j < containerLenS) || !(hasLen || d.checkBreak()); j++ { + for j := 0; d.containerNext(j, containerLenS, hasLen); j++ { if j >= len(v) { slh.arrayCannotExpand(hasLen, len(v), j, containerLenS) return @@ -4027,7 +4027,7 @@ func (fastpathT) DecSliceBoolY(v []bool, d *Decoder) (v2 []bool, changed bool) { } } var j int - for j = 0; (hasLen && j < containerLenS) || !(hasLen || d.checkBreak()); j++ { + for j = 0; d.containerNext(j, containerLenS, hasLen); j++ { if j == 0 && len(v) == 0 { // means hasLen == false xlen = decInferLen(containerLenS, d.h.MaxInitLen, 1) v = make([]bool, uint(xlen)) @@ -4060,7 +4060,7 @@ func (fastpathT) DecSliceBoolN(v []bool, d *Decoder) { return } hasLen := containerLenS > 0 - for j := 0; (hasLen && j < containerLenS) || !(hasLen || d.checkBreak()); j++ { + for j := 0; d.containerNext(j, containerLenS, hasLen); j++ { if j >= len(v) { slh.arrayCannotExpand(hasLen, len(v), j, containerLenS) return @@ -4108,7 +4108,7 @@ func (fastpathT) DecMapStringIntfL(v map[string]interface{}, containerLen int, d var mk string var mv interface{} hasLen := containerLen > 0 - for j := 0; (hasLen && j < containerLen) || !(hasLen || d.checkBreak()); j++ { + for j := 0; d.containerNext(j, containerLen, hasLen); j++ { d.mapElemKey() mk = d.stringZC(d.d.DecodeStringAsBytes()) d.mapElemValue() @@ -4158,7 +4158,7 @@ func (fastpathT) DecMapStringStringL(v map[string]string, containerLen int, d *D var mk string var mv string hasLen := containerLen > 0 - for j := 0; (hasLen && j < containerLen) || !(hasLen || d.checkBreak()); j++ { + for j := 0; d.containerNext(j, containerLen, hasLen); j++ { d.mapElemKey() mk = d.stringZC(d.d.DecodeStringAsBytes()) d.mapElemValue() @@ -4204,7 +4204,7 @@ func (fastpathT) DecMapStringBytesL(v map[string][]byte, containerLen int, d *De var mk string var mv []byte hasLen := containerLen > 0 - for j := 0; (hasLen && j < containerLen) || !(hasLen || d.checkBreak()); j++ { + for j := 0; d.containerNext(j, containerLen, hasLen); j++ { d.mapElemKey() mk = d.stringZC(d.d.DecodeStringAsBytes()) d.mapElemValue() @@ -4254,7 +4254,7 @@ func (fastpathT) DecMapStringUint8L(v map[string]uint8, containerLen int, d *Dec var mk string var mv uint8 hasLen := containerLen > 0 - for j := 0; (hasLen && j < containerLen) || !(hasLen || d.checkBreak()); j++ { + for j := 0; d.containerNext(j, containerLen, hasLen); j++ { d.mapElemKey() mk = d.stringZC(d.d.DecodeStringAsBytes()) d.mapElemValue() @@ -4299,7 +4299,7 @@ func (fastpathT) DecMapStringUint64L(v map[string]uint64, containerLen int, d *D var mk string var mv uint64 hasLen := containerLen > 0 - for j := 0; (hasLen && j < containerLen) || !(hasLen || d.checkBreak()); j++ { + for j := 0; d.containerNext(j, containerLen, hasLen); j++ { d.mapElemKey() mk = d.stringZC(d.d.DecodeStringAsBytes()) d.mapElemValue() @@ -4344,7 +4344,7 @@ func (fastpathT) DecMapStringIntL(v map[string]int, containerLen int, d *Decoder var mk string var mv int hasLen := containerLen > 0 - for j := 0; (hasLen && j < containerLen) || !(hasLen || d.checkBreak()); j++ { + for j := 0; d.containerNext(j, containerLen, hasLen); j++ { d.mapElemKey() mk = d.stringZC(d.d.DecodeStringAsBytes()) d.mapElemValue() @@ -4389,7 +4389,7 @@ func (fastpathT) DecMapStringInt32L(v map[string]int32, containerLen int, d *Dec var mk string var mv int32 hasLen := containerLen > 0 - for j := 0; (hasLen && j < containerLen) || !(hasLen || d.checkBreak()); j++ { + for j := 0; d.containerNext(j, containerLen, hasLen); j++ { d.mapElemKey() mk = d.stringZC(d.d.DecodeStringAsBytes()) d.mapElemValue() @@ -4434,7 +4434,7 @@ func (fastpathT) DecMapStringFloat64L(v map[string]float64, containerLen int, d var mk string var mv float64 hasLen := containerLen > 0 - for j := 0; (hasLen && j < containerLen) || !(hasLen || d.checkBreak()); j++ { + for j := 0; d.containerNext(j, containerLen, hasLen); j++ { d.mapElemKey() mk = d.stringZC(d.d.DecodeStringAsBytes()) d.mapElemValue() @@ -4479,7 +4479,7 @@ func (fastpathT) DecMapStringBoolL(v map[string]bool, containerLen int, d *Decod var mk string var mv bool hasLen := containerLen > 0 - for j := 0; (hasLen && j < containerLen) || !(hasLen || d.checkBreak()); j++ { + for j := 0; d.containerNext(j, containerLen, hasLen); j++ { d.mapElemKey() mk = d.stringZC(d.d.DecodeStringAsBytes()) d.mapElemValue() @@ -4525,7 +4525,7 @@ func (fastpathT) DecMapUint8IntfL(v map[uint8]interface{}, containerLen int, d * var mk uint8 var mv interface{} hasLen := containerLen > 0 - for j := 0; (hasLen && j < containerLen) || !(hasLen || d.checkBreak()); j++ { + for j := 0; d.containerNext(j, containerLen, hasLen); j++ { d.mapElemKey() mk = uint8(chkOvf.UintV(d.d.DecodeUint64(), 8)) d.mapElemValue() @@ -4575,7 +4575,7 @@ func (fastpathT) DecMapUint8StringL(v map[uint8]string, containerLen int, d *Dec var mk uint8 var mv string hasLen := containerLen > 0 - for j := 0; (hasLen && j < containerLen) || !(hasLen || d.checkBreak()); j++ { + for j := 0; d.containerNext(j, containerLen, hasLen); j++ { d.mapElemKey() mk = uint8(chkOvf.UintV(d.d.DecodeUint64(), 8)) d.mapElemValue() @@ -4621,7 +4621,7 @@ func (fastpathT) DecMapUint8BytesL(v map[uint8][]byte, containerLen int, d *Deco var mk uint8 var mv []byte hasLen := containerLen > 0 - for j := 0; (hasLen && j < containerLen) || !(hasLen || d.checkBreak()); j++ { + for j := 0; d.containerNext(j, containerLen, hasLen); j++ { d.mapElemKey() mk = uint8(chkOvf.UintV(d.d.DecodeUint64(), 8)) d.mapElemValue() @@ -4671,7 +4671,7 @@ func (fastpathT) DecMapUint8Uint8L(v map[uint8]uint8, containerLen int, d *Decod var mk uint8 var mv uint8 hasLen := containerLen > 0 - for j := 0; (hasLen && j < containerLen) || !(hasLen || d.checkBreak()); j++ { + for j := 0; d.containerNext(j, containerLen, hasLen); j++ { d.mapElemKey() mk = uint8(chkOvf.UintV(d.d.DecodeUint64(), 8)) d.mapElemValue() @@ -4716,7 +4716,7 @@ func (fastpathT) DecMapUint8Uint64L(v map[uint8]uint64, containerLen int, d *Dec var mk uint8 var mv uint64 hasLen := containerLen > 0 - for j := 0; (hasLen && j < containerLen) || !(hasLen || d.checkBreak()); j++ { + for j := 0; d.containerNext(j, containerLen, hasLen); j++ { d.mapElemKey() mk = uint8(chkOvf.UintV(d.d.DecodeUint64(), 8)) d.mapElemValue() @@ -4761,7 +4761,7 @@ func (fastpathT) DecMapUint8IntL(v map[uint8]int, containerLen int, d *Decoder) var mk uint8 var mv int hasLen := containerLen > 0 - for j := 0; (hasLen && j < containerLen) || !(hasLen || d.checkBreak()); j++ { + for j := 0; d.containerNext(j, containerLen, hasLen); j++ { d.mapElemKey() mk = uint8(chkOvf.UintV(d.d.DecodeUint64(), 8)) d.mapElemValue() @@ -4806,7 +4806,7 @@ func (fastpathT) DecMapUint8Int32L(v map[uint8]int32, containerLen int, d *Decod var mk uint8 var mv int32 hasLen := containerLen > 0 - for j := 0; (hasLen && j < containerLen) || !(hasLen || d.checkBreak()); j++ { + for j := 0; d.containerNext(j, containerLen, hasLen); j++ { d.mapElemKey() mk = uint8(chkOvf.UintV(d.d.DecodeUint64(), 8)) d.mapElemValue() @@ -4851,7 +4851,7 @@ func (fastpathT) DecMapUint8Float64L(v map[uint8]float64, containerLen int, d *D var mk uint8 var mv float64 hasLen := containerLen > 0 - for j := 0; (hasLen && j < containerLen) || !(hasLen || d.checkBreak()); j++ { + for j := 0; d.containerNext(j, containerLen, hasLen); j++ { d.mapElemKey() mk = uint8(chkOvf.UintV(d.d.DecodeUint64(), 8)) d.mapElemValue() @@ -4896,7 +4896,7 @@ func (fastpathT) DecMapUint8BoolL(v map[uint8]bool, containerLen int, d *Decoder var mk uint8 var mv bool hasLen := containerLen > 0 - for j := 0; (hasLen && j < containerLen) || !(hasLen || d.checkBreak()); j++ { + for j := 0; d.containerNext(j, containerLen, hasLen); j++ { d.mapElemKey() mk = uint8(chkOvf.UintV(d.d.DecodeUint64(), 8)) d.mapElemValue() @@ -4942,7 +4942,7 @@ func (fastpathT) DecMapUint64IntfL(v map[uint64]interface{}, containerLen int, d var mk uint64 var mv interface{} hasLen := containerLen > 0 - for j := 0; (hasLen && j < containerLen) || !(hasLen || d.checkBreak()); j++ { + for j := 0; d.containerNext(j, containerLen, hasLen); j++ { d.mapElemKey() mk = d.d.DecodeUint64() d.mapElemValue() @@ -4992,7 +4992,7 @@ func (fastpathT) DecMapUint64StringL(v map[uint64]string, containerLen int, d *D var mk uint64 var mv string hasLen := containerLen > 0 - for j := 0; (hasLen && j < containerLen) || !(hasLen || d.checkBreak()); j++ { + for j := 0; d.containerNext(j, containerLen, hasLen); j++ { d.mapElemKey() mk = d.d.DecodeUint64() d.mapElemValue() @@ -5038,7 +5038,7 @@ func (fastpathT) DecMapUint64BytesL(v map[uint64][]byte, containerLen int, d *De var mk uint64 var mv []byte hasLen := containerLen > 0 - for j := 0; (hasLen && j < containerLen) || !(hasLen || d.checkBreak()); j++ { + for j := 0; d.containerNext(j, containerLen, hasLen); j++ { d.mapElemKey() mk = d.d.DecodeUint64() d.mapElemValue() @@ -5088,7 +5088,7 @@ func (fastpathT) DecMapUint64Uint8L(v map[uint64]uint8, containerLen int, d *Dec var mk uint64 var mv uint8 hasLen := containerLen > 0 - for j := 0; (hasLen && j < containerLen) || !(hasLen || d.checkBreak()); j++ { + for j := 0; d.containerNext(j, containerLen, hasLen); j++ { d.mapElemKey() mk = d.d.DecodeUint64() d.mapElemValue() @@ -5133,7 +5133,7 @@ func (fastpathT) DecMapUint64Uint64L(v map[uint64]uint64, containerLen int, d *D var mk uint64 var mv uint64 hasLen := containerLen > 0 - for j := 0; (hasLen && j < containerLen) || !(hasLen || d.checkBreak()); j++ { + for j := 0; d.containerNext(j, containerLen, hasLen); j++ { d.mapElemKey() mk = d.d.DecodeUint64() d.mapElemValue() @@ -5178,7 +5178,7 @@ func (fastpathT) DecMapUint64IntL(v map[uint64]int, containerLen int, d *Decoder var mk uint64 var mv int hasLen := containerLen > 0 - for j := 0; (hasLen && j < containerLen) || !(hasLen || d.checkBreak()); j++ { + for j := 0; d.containerNext(j, containerLen, hasLen); j++ { d.mapElemKey() mk = d.d.DecodeUint64() d.mapElemValue() @@ -5223,7 +5223,7 @@ func (fastpathT) DecMapUint64Int32L(v map[uint64]int32, containerLen int, d *Dec var mk uint64 var mv int32 hasLen := containerLen > 0 - for j := 0; (hasLen && j < containerLen) || !(hasLen || d.checkBreak()); j++ { + for j := 0; d.containerNext(j, containerLen, hasLen); j++ { d.mapElemKey() mk = d.d.DecodeUint64() d.mapElemValue() @@ -5268,7 +5268,7 @@ func (fastpathT) DecMapUint64Float64L(v map[uint64]float64, containerLen int, d var mk uint64 var mv float64 hasLen := containerLen > 0 - for j := 0; (hasLen && j < containerLen) || !(hasLen || d.checkBreak()); j++ { + for j := 0; d.containerNext(j, containerLen, hasLen); j++ { d.mapElemKey() mk = d.d.DecodeUint64() d.mapElemValue() @@ -5313,7 +5313,7 @@ func (fastpathT) DecMapUint64BoolL(v map[uint64]bool, containerLen int, d *Decod var mk uint64 var mv bool hasLen := containerLen > 0 - for j := 0; (hasLen && j < containerLen) || !(hasLen || d.checkBreak()); j++ { + for j := 0; d.containerNext(j, containerLen, hasLen); j++ { d.mapElemKey() mk = d.d.DecodeUint64() d.mapElemValue() @@ -5359,7 +5359,7 @@ func (fastpathT) DecMapIntIntfL(v map[int]interface{}, containerLen int, d *Deco var mk int var mv interface{} hasLen := containerLen > 0 - for j := 0; (hasLen && j < containerLen) || !(hasLen || d.checkBreak()); j++ { + for j := 0; d.containerNext(j, containerLen, hasLen); j++ { d.mapElemKey() mk = int(chkOvf.IntV(d.d.DecodeInt64(), intBitsize)) d.mapElemValue() @@ -5409,7 +5409,7 @@ func (fastpathT) DecMapIntStringL(v map[int]string, containerLen int, d *Decoder var mk int var mv string hasLen := containerLen > 0 - for j := 0; (hasLen && j < containerLen) || !(hasLen || d.checkBreak()); j++ { + for j := 0; d.containerNext(j, containerLen, hasLen); j++ { d.mapElemKey() mk = int(chkOvf.IntV(d.d.DecodeInt64(), intBitsize)) d.mapElemValue() @@ -5455,7 +5455,7 @@ func (fastpathT) DecMapIntBytesL(v map[int][]byte, containerLen int, d *Decoder) var mk int var mv []byte hasLen := containerLen > 0 - for j := 0; (hasLen && j < containerLen) || !(hasLen || d.checkBreak()); j++ { + for j := 0; d.containerNext(j, containerLen, hasLen); j++ { d.mapElemKey() mk = int(chkOvf.IntV(d.d.DecodeInt64(), intBitsize)) d.mapElemValue() @@ -5505,7 +5505,7 @@ func (fastpathT) DecMapIntUint8L(v map[int]uint8, containerLen int, d *Decoder) var mk int var mv uint8 hasLen := containerLen > 0 - for j := 0; (hasLen && j < containerLen) || !(hasLen || d.checkBreak()); j++ { + for j := 0; d.containerNext(j, containerLen, hasLen); j++ { d.mapElemKey() mk = int(chkOvf.IntV(d.d.DecodeInt64(), intBitsize)) d.mapElemValue() @@ -5550,7 +5550,7 @@ func (fastpathT) DecMapIntUint64L(v map[int]uint64, containerLen int, d *Decoder var mk int var mv uint64 hasLen := containerLen > 0 - for j := 0; (hasLen && j < containerLen) || !(hasLen || d.checkBreak()); j++ { + for j := 0; d.containerNext(j, containerLen, hasLen); j++ { d.mapElemKey() mk = int(chkOvf.IntV(d.d.DecodeInt64(), intBitsize)) d.mapElemValue() @@ -5595,7 +5595,7 @@ func (fastpathT) DecMapIntIntL(v map[int]int, containerLen int, d *Decoder) { var mk int var mv int hasLen := containerLen > 0 - for j := 0; (hasLen && j < containerLen) || !(hasLen || d.checkBreak()); j++ { + for j := 0; d.containerNext(j, containerLen, hasLen); j++ { d.mapElemKey() mk = int(chkOvf.IntV(d.d.DecodeInt64(), intBitsize)) d.mapElemValue() @@ -5640,7 +5640,7 @@ func (fastpathT) DecMapIntInt32L(v map[int]int32, containerLen int, d *Decoder) var mk int var mv int32 hasLen := containerLen > 0 - for j := 0; (hasLen && j < containerLen) || !(hasLen || d.checkBreak()); j++ { + for j := 0; d.containerNext(j, containerLen, hasLen); j++ { d.mapElemKey() mk = int(chkOvf.IntV(d.d.DecodeInt64(), intBitsize)) d.mapElemValue() @@ -5685,7 +5685,7 @@ func (fastpathT) DecMapIntFloat64L(v map[int]float64, containerLen int, d *Decod var mk int var mv float64 hasLen := containerLen > 0 - for j := 0; (hasLen && j < containerLen) || !(hasLen || d.checkBreak()); j++ { + for j := 0; d.containerNext(j, containerLen, hasLen); j++ { d.mapElemKey() mk = int(chkOvf.IntV(d.d.DecodeInt64(), intBitsize)) d.mapElemValue() @@ -5730,7 +5730,7 @@ func (fastpathT) DecMapIntBoolL(v map[int]bool, containerLen int, d *Decoder) { var mk int var mv bool hasLen := containerLen > 0 - for j := 0; (hasLen && j < containerLen) || !(hasLen || d.checkBreak()); j++ { + for j := 0; d.containerNext(j, containerLen, hasLen); j++ { d.mapElemKey() mk = int(chkOvf.IntV(d.d.DecodeInt64(), intBitsize)) d.mapElemValue() @@ -5776,7 +5776,7 @@ func (fastpathT) DecMapInt32IntfL(v map[int32]interface{}, containerLen int, d * var mk int32 var mv interface{} hasLen := containerLen > 0 - for j := 0; (hasLen && j < containerLen) || !(hasLen || d.checkBreak()); j++ { + for j := 0; d.containerNext(j, containerLen, hasLen); j++ { d.mapElemKey() mk = int32(chkOvf.IntV(d.d.DecodeInt64(), 32)) d.mapElemValue() @@ -5826,7 +5826,7 @@ func (fastpathT) DecMapInt32StringL(v map[int32]string, containerLen int, d *Dec var mk int32 var mv string hasLen := containerLen > 0 - for j := 0; (hasLen && j < containerLen) || !(hasLen || d.checkBreak()); j++ { + for j := 0; d.containerNext(j, containerLen, hasLen); j++ { d.mapElemKey() mk = int32(chkOvf.IntV(d.d.DecodeInt64(), 32)) d.mapElemValue() @@ -5872,7 +5872,7 @@ func (fastpathT) DecMapInt32BytesL(v map[int32][]byte, containerLen int, d *Deco var mk int32 var mv []byte hasLen := containerLen > 0 - for j := 0; (hasLen && j < containerLen) || !(hasLen || d.checkBreak()); j++ { + for j := 0; d.containerNext(j, containerLen, hasLen); j++ { d.mapElemKey() mk = int32(chkOvf.IntV(d.d.DecodeInt64(), 32)) d.mapElemValue() @@ -5922,7 +5922,7 @@ func (fastpathT) DecMapInt32Uint8L(v map[int32]uint8, containerLen int, d *Decod var mk int32 var mv uint8 hasLen := containerLen > 0 - for j := 0; (hasLen && j < containerLen) || !(hasLen || d.checkBreak()); j++ { + for j := 0; d.containerNext(j, containerLen, hasLen); j++ { d.mapElemKey() mk = int32(chkOvf.IntV(d.d.DecodeInt64(), 32)) d.mapElemValue() @@ -5967,7 +5967,7 @@ func (fastpathT) DecMapInt32Uint64L(v map[int32]uint64, containerLen int, d *Dec var mk int32 var mv uint64 hasLen := containerLen > 0 - for j := 0; (hasLen && j < containerLen) || !(hasLen || d.checkBreak()); j++ { + for j := 0; d.containerNext(j, containerLen, hasLen); j++ { d.mapElemKey() mk = int32(chkOvf.IntV(d.d.DecodeInt64(), 32)) d.mapElemValue() @@ -6012,7 +6012,7 @@ func (fastpathT) DecMapInt32IntL(v map[int32]int, containerLen int, d *Decoder) var mk int32 var mv int hasLen := containerLen > 0 - for j := 0; (hasLen && j < containerLen) || !(hasLen || d.checkBreak()); j++ { + for j := 0; d.containerNext(j, containerLen, hasLen); j++ { d.mapElemKey() mk = int32(chkOvf.IntV(d.d.DecodeInt64(), 32)) d.mapElemValue() @@ -6057,7 +6057,7 @@ func (fastpathT) DecMapInt32Int32L(v map[int32]int32, containerLen int, d *Decod var mk int32 var mv int32 hasLen := containerLen > 0 - for j := 0; (hasLen && j < containerLen) || !(hasLen || d.checkBreak()); j++ { + for j := 0; d.containerNext(j, containerLen, hasLen); j++ { d.mapElemKey() mk = int32(chkOvf.IntV(d.d.DecodeInt64(), 32)) d.mapElemValue() @@ -6102,7 +6102,7 @@ func (fastpathT) DecMapInt32Float64L(v map[int32]float64, containerLen int, d *D var mk int32 var mv float64 hasLen := containerLen > 0 - for j := 0; (hasLen && j < containerLen) || !(hasLen || d.checkBreak()); j++ { + for j := 0; d.containerNext(j, containerLen, hasLen); j++ { d.mapElemKey() mk = int32(chkOvf.IntV(d.d.DecodeInt64(), 32)) d.mapElemValue() @@ -6147,7 +6147,7 @@ func (fastpathT) DecMapInt32BoolL(v map[int32]bool, containerLen int, d *Decoder var mk int32 var mv bool hasLen := containerLen > 0 - for j := 0; (hasLen && j < containerLen) || !(hasLen || d.checkBreak()); j++ { + for j := 0; d.containerNext(j, containerLen, hasLen); j++ { d.mapElemKey() mk = int32(chkOvf.IntV(d.d.DecodeInt64(), 32)) d.mapElemValue() diff --git a/vendor/github.com/ugorji/go/codec/fast-path.go.tmpl b/vendor/github.com/ugorji/go/codec/fast-path.go.tmpl index 56801ee5c..1a1cb95c6 100644 --- a/vendor/github.com/ugorji/go/codec/fast-path.go.tmpl +++ b/vendor/github.com/ugorji/go/codec/fast-path.go.tmpl @@ -409,7 +409,7 @@ func (fastpathT) {{ .MethodNamePfx "Dec" false }}Y(v []{{ .Elem }}, d *Decoder) } } var j int - for j = 0; (hasLen && j < containerLenS) || !(hasLen || d.checkBreak()); j++ { + for j = 0; d.containerNext(j, containerLenS, hasLen); j++ { if j == 0 && len(v) == 0 { // means hasLen == false xlen = decInferLen(containerLenS, d.h.MaxInitLen, {{ .Size }}) {{/* xlen = decDefSliceCap */}} v = make([]{{ .Elem }}, uint(xlen)) @@ -455,7 +455,7 @@ func (fastpathT) {{ .MethodNamePfx "Dec" false }}N(v []{{ .Elem }}, d *Decoder) return } hasLen := containerLenS > 0 - for j := 0; (hasLen && j < containerLenS) || !(hasLen || d.checkBreak()); j++ { + for j := 0; d.containerNext(j, containerLenS, hasLen); j++ { {{/* // if indefinite, etc, then expand the slice if necessary */ -}} if j >= len(v) { slh.arrayCannotExpand(hasLen, len(v), j, containerLenS) @@ -531,7 +531,7 @@ func (fastpathT) {{ .MethodNamePfx "Dec" false }}L(v map[{{ .MapKey }}]{{ .Elem var mk {{ .MapKey }} var mv {{ .Elem }} hasLen := containerLen > 0 - for j := 0; (hasLen && j < containerLen) || !(hasLen || d.checkBreak()); j++ { + for j := 0; d.containerNext(j, containerLen, hasLen); j++ { d.mapElemKey() {{ if eq .MapKey "interface{}" }}mk = nil d.decode(&mk) diff --git a/vendor/github.com/ugorji/go/codec/gen-dec-array.go.tmpl b/vendor/github.com/ugorji/go/codec/gen-dec-array.go.tmpl index e92175059..5e119e715 100644 --- a/vendor/github.com/ugorji/go/codec/gen-dec-array.go.tmpl +++ b/vendor/github.com/ugorji/go/codec/gen-dec-array.go.tmpl @@ -42,8 +42,8 @@ if {{var "l"}} == 0 { } {{end -}} var {{var "j"}} int - {{/* // var {{var "dn"}} bool */ -}} - for {{var "j"}} = 0; ({{var "hl"}} && {{var "j"}} < {{var "l"}}) || !({{var "hl"}} || z.DecCheckBreak()); {{var "j"}}++ { // bounds-check-elimination + {{/* // var {{var "dn"}} bool */ -}} + for {{var "j"}} = 0; z.DecContainerNext({{var "j"}}, {{var "l"}}, {{var "hl"}}); {{var "j"}}++ { {{if not isArray}} if {{var "j"}} == 0 && {{var "v"}} == nil { if {{var "hl"}} { {{var "rl"}} = z.DecInferLen({{var "l"}}, z.DecBasicHandle().MaxInitLen, {{ .Size }}) diff --git a/vendor/github.com/ugorji/go/codec/gen-dec-map.go.tmpl b/vendor/github.com/ugorji/go/codec/gen-dec-map.go.tmpl index a7ce62b59..b32ade2e1 100644 --- a/vendor/github.com/ugorji/go/codec/gen-dec-map.go.tmpl +++ b/vendor/github.com/ugorji/go/codec/gen-dec-map.go.tmpl @@ -19,7 +19,7 @@ if z.DecBasicHandle().MapValueReset { {{end}} } if {{var "l"}} != 0 { {{var "hl"}} := {{var "l"}} > 0 - for {{var "j"}} := 0; ({{var "hl"}} && {{var "j"}} < {{var "l"}}) || !({{var "hl"}} || z.DecCheckBreak()); {{var "j"}}++ { + for {{var "j"}} := 0; z.DecContainerNext({{var "j"}}, {{var "l"}}, {{var "hl"}}); {{var "j"}}++ { z.DecReadMapElemKey() {{ if eq .KTyp "string" -}} {{ decLineVarK $mk -}}{{- /* decLineVarKStrZC $mk */ -}} diff --git a/vendor/github.com/ugorji/go/codec/gen-helper.generated.go b/vendor/github.com/ugorji/go/codec/gen-helper.generated.go index 5643b6af9..676203daf 100644 --- a/vendor/github.com/ugorji/go/codec/gen-helper.generated.go +++ b/vendor/github.com/ugorji/go/codec/gen-helper.generated.go @@ -13,7 +13,7 @@ import ( ) // GenVersion is the current version of codecgen. -const GenVersion = 25 +const GenVersion = 26 // This file is used to generate helper code for codecgen. // The values here i.e. genHelper(En|De)coder are not to be used directly by @@ -66,6 +66,11 @@ func (f genHelperEncoder) EncBasicHandle() *BasicHandle { } // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* +func (f genHelperEncoder) EncWr() *encWr { + return f.e.w() +} + +// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (f genHelperEncoder) EncBinary() bool { return f.e.be // f.e.hh.isBinaryEncoding() } @@ -113,11 +118,6 @@ func (f genHelperEncoder) EncExtension(v interface{}, xfFn *extTypeTagFn) { } // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* -func (f genHelperEncoder) WriteStr(s string) { - f.e.w().writestr(s) -} - -// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (f genHelperEncoder) EncWriteMapStart(length int) { f.e.mapStart(length) } // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* @@ -148,9 +148,19 @@ func (f genHelperEncoder) EncEncodeComplex128(v complex128) { f.e.encodeComplex1 func (f genHelperEncoder) EncEncode(v interface{}) { f.e.encode(v) } // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* +func (f genHelperEncoder) EncFnGivenAddr(v interface{}) *codecFn { + return f.e.h.fn(reflect.TypeOf(v).Elem()) +} + +// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* +func (f genHelperEncoder) EncEncodeNumBoolStrKindGivenAddr(v interface{}, encFn *codecFn) { + f.e.encodeValueNonNil(reflect.ValueOf(v).Elem(), encFn) +} + +// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (f genHelperEncoder) EncEncodeMapNonNil(v interface{}) { if skipFastpathTypeSwitchInDirectCall || !fastpathEncodeTypeSwitch(v, f.e) { - f.e.encodeValue(reflect.ValueOf(v), nil) + f.e.encodeValueNonNil(reflect.ValueOf(v), nil) } } @@ -268,10 +278,17 @@ func (f genHelperDecoder) DecReadMapElemValue() { f.d.mapElemValue() } func (f genHelperDecoder) DecDecodeFloat32() float32 { return f.d.decodeFloat32() } // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* -func (f genHelperDecoder) DecCheckBreak() bool { return f.d.checkBreak() } - -// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (f genHelperDecoder) DecStringZC(v []byte) string { return f.d.stringZC(v) } // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (f genHelperDecoder) DecodeBytesInto(v []byte) []byte { return f.d.decodeBytesInto(v) } + +// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* +func (f genHelperDecoder) DecContainerNext(j, containerLen int, hasLen bool) bool { + // return f.d.containerNext(j, containerLen, hasLen) + // rewriting so it can be inlined + if hasLen { + return j < containerLen + } + return !f.d.checkBreak() +} diff --git a/vendor/github.com/ugorji/go/codec/gen-helper.go.tmpl b/vendor/github.com/ugorji/go/codec/gen-helper.go.tmpl index 1f1339684..bf824ebdd 100644 --- a/vendor/github.com/ugorji/go/codec/gen-helper.go.tmpl +++ b/vendor/github.com/ugorji/go/codec/gen-helper.go.tmpl @@ -73,6 +73,10 @@ func (f genHelperEncoder) EncBasicHandle() *BasicHandle { return f.e.h } // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* +func (f genHelperEncoder) EncWr() *encWr { + return f.e.w() +} +// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (f genHelperEncoder) EncBinary() bool { return f.e.be // f.e.hh.isBinaryEncoding() } @@ -111,10 +115,7 @@ func (f genHelperEncoder) Extension(v interface{}) (xfn *extTypeTagFn) { func (f genHelperEncoder) EncExtension(v interface{}, xfFn *extTypeTagFn) { f.e.e.EncodeExt(v, xfFn.rt, xfFn.tag, xfFn.ext) } -// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* -func (f genHelperEncoder) WriteStr(s string) { - f.e.w().writestr(s) -} + // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (f genHelperEncoder) EncWriteMapStart(length int) { f.e.mapStart(length) } // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* @@ -136,9 +137,15 @@ func (f genHelperEncoder) EncEncodeComplex128(v complex128) { f.e.encodeComplex1 // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (f genHelperEncoder) EncEncode(v interface{}) { f.e.encode(v) } // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* +func (f genHelperEncoder) EncFnGivenAddr(v interface{}) *codecFn { return f.e.h.fn(reflect.TypeOf(v).Elem()) } +// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* +func (f genHelperEncoder) EncEncodeNumBoolStrKindGivenAddr(v interface{}, encFn *codecFn) { + f.e.encodeValueNonNil(reflect.ValueOf(v).Elem(), encFn) +} +// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (f genHelperEncoder) EncEncodeMapNonNil(v interface{}) { if skipFastpathTypeSwitchInDirectCall || !fastpathEncodeTypeSwitch(v, f.e) { - f.e.encodeValue(reflect.ValueOf(v), nil) + f.e.encodeValueNonNil(reflect.ValueOf(v), nil) } } @@ -205,12 +212,6 @@ func (f genHelperDecoder) DecRaw() []byte { return f.d.rawBytes() } func (f genHelperDecoder) IsJSONHandle() bool { return f.d.js } -{{/* -// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* -func (f genHelperDecoder) I2Rtid(v interface{}) uintptr { - return i2rtid(v) -} -*/ -}} // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (f genHelperDecoder) Extension(v interface{}) (xfn *extTypeTagFn) { return f.d.h.getExtForI(v) @@ -242,8 +243,31 @@ func (f genHelperDecoder) DecReadMapElemValue() { f.d.mapElemValue() } // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (f genHelperDecoder) DecDecodeFloat32() float32 { return f.d.decodeFloat32() } // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* -func (f genHelperDecoder) DecCheckBreak() bool { return f.d.checkBreak() } -// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (f genHelperDecoder) DecStringZC(v []byte) string { return f.d.stringZC(v) } // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (f genHelperDecoder) DecodeBytesInto(v []byte) []byte { return f.d.decodeBytesInto(v) } +// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* +func (f genHelperDecoder) DecContainerNext(j, containerLen int, hasLen bool) bool { + // return f.d.containerNext(j, containerLen, hasLen) + // rewriting so it can be inlined + if hasLen { + return j < containerLen + } + return !f.d.checkBreak() +} + +{{/* +// MARKER: remove WriteStr, as it cannot be inlined as of 20230201. +// Instead, generated code calls (*encWr).WriteStr directly. + +// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* +// func (f genHelperEncoder) WriteStr(s string) { +// f.e.encWr.writestr(s) +// } + +// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* +func (f genHelperDecoder) I2Rtid(v interface{}) uintptr { + return i2rtid(v) +} + +*/ -}} diff --git a/vendor/github.com/ugorji/go/codec/gen.generated.go b/vendor/github.com/ugorji/go/codec/gen.generated.go index 0ea79e75d..277180a01 100644 --- a/vendor/github.com/ugorji/go/codec/gen.generated.go +++ b/vendor/github.com/ugorji/go/codec/gen.generated.go @@ -29,7 +29,7 @@ if z.DecBasicHandle().MapValueReset { {{end}} } if {{var "l"}} != 0 { {{var "hl"}} := {{var "l"}} > 0 - for {{var "j"}} := 0; ({{var "hl"}} && {{var "j"}} < {{var "l"}}) || !({{var "hl"}} || z.DecCheckBreak()); {{var "j"}}++ { + for {{var "j"}} := 0; z.DecContainerNext({{var "j"}}, {{var "l"}}, {{var "hl"}}); {{var "j"}}++ { z.DecReadMapElemKey() {{ if eq .KTyp "string" -}} {{ decLineVarK $mk -}}{{- /* decLineVarKStrZC $mk */ -}} @@ -113,8 +113,8 @@ if {{var "l"}} == 0 { } {{end -}} var {{var "j"}} int - {{/* // var {{var "dn"}} bool */ -}} - for {{var "j"}} = 0; ({{var "hl"}} && {{var "j"}} < {{var "l"}}) || !({{var "hl"}} || z.DecCheckBreak()); {{var "j"}}++ { // bounds-check-elimination + {{/* // var {{var "dn"}} bool */ -}} + for {{var "j"}} = 0; z.DecContainerNext({{var "j"}}, {{var "l"}}, {{var "hl"}}); {{var "j"}}++ { {{if not isArray}} if {{var "j"}} == 0 && {{var "v"}} == nil { if {{var "hl"}} { {{var "rl"}} = z.DecInferLen({{var "l"}}, z.DecBasicHandle().MaxInitLen, {{ .Size }}) diff --git a/vendor/github.com/ugorji/go/codec/gen.go b/vendor/github.com/ugorji/go/codec/gen.go index 8c5bbf201..d0cec1972 100644 --- a/vendor/github.com/ugorji/go/codec/gen.go +++ b/vendor/github.com/ugorji/go/codec/gen.go @@ -43,15 +43,17 @@ import ( // // However, note following codecgen caveats: // - Canonical option. -// If Canonical=true, codecgen'ed code will delegate encoding maps to reflection-based code. +// If Canonical=true, codecgen'ed code may delegate encoding maps to reflection-based code. // This is due to the runtime work needed to marshal a map in canonical mode. +// However, if map key is a pre-defined/builtin numeric or string type, codecgen +// will try to write it out itself // - CheckCircularRef option. // When encoding a struct, a circular reference can lead to a stack overflow. // If CheckCircularRef=true, codecgen'ed code will delegate encoding structs to reflection-based code. // - MissingFielder implementation. // If a type implements MissingFielder, a Selfer is not generated (with a warning message). -// Statically reproducing the runtime work needed to extract the missing fields and marshal them along with the struct fields, -// while handling the Canonical=true special case, was onerous to implement. +// Statically reproducing the runtime work needed to extract the missing fields and marshal them +// along with the struct fields, while handling the Canonical=true special case, was onerous to implement. // // During encode/decode, Selfer takes precedence. // A type implementing Selfer will know how to encode/decode itself statically. @@ -125,14 +127,13 @@ import ( // // v1: Initial Version // v2: - -// v3: Changes for Kubernetes: -// changes in signature of some unpublished helper methods and codecgen cmdline arguments. +// v3: For Kubernetes: changes in signature of some unpublished helper methods and codecgen cmdline arguments. // v4: Removed separator support from (en|de)cDriver, and refactored codec(gen) // v5: changes to support faster json decoding. Let encoder/decoder maintain state of collections. // v6: removed unsafe from gen, and now uses codecgen.exec tag // v7: - // v8: current - we now maintain compatibility with old generated code. -// v9: skipped +// v9: - skipped // v10: modified encDriver and decDriver interfaces. // v11: remove deprecated methods of encDriver and decDriver. // v12: removed deprecated methods from genHelper and changed container tracking logic @@ -149,7 +150,8 @@ import ( // v23: 20210203 changed slice/map types for which we generate fast-path functions // v24: 20210226 robust handling for Canonical|CheckCircularRef flags and MissingFielder implementations // v25: 20210406 pass base reflect.Type to side(En|De)code and (En|De)codeExt calls -const genVersion = 25 +// v26: 20230201 genHelper changes for more inlining and consequent performance +const genVersion = 26 const ( genCodecPkg = "codec1978" // MARKER: keep in sync with codecgen/gen.go @@ -160,16 +162,9 @@ const ( // This is because nil can appear anywhere, so we should always check. genAnythingCanBeNil = true - // if genUseOneFunctionForDecStructMap, make a single codecDecodeSelferFromMap function; - // else make codecDecodeSelferFromMap{LenPrefix,CheckBreak} so that conditionals - // are not executed a lot. - // - // From testing, it didn't make much difference in runtime, so keep as true (one function only) - genUseOneFunctionForDecStructMap = true - // genStructCanonical configures whether we generate 2 paths based on Canonical flag // when encoding struct fields. - genStructCanonical = false + genStructCanonical = true // genFastpathCanonical configures whether we support Canonical in fast path. // The savings is not much. @@ -179,15 +174,8 @@ const ( // genFastpathTrimTypes configures whether we trim uncommon fastpath types. genFastpathTrimTypes = true - - // genDecStructArrayInlineLoopCheck configures whether we create a next function - // for each iteration in the loop and call it, or just inline it. - // - // with inlining, we get better performance but about 10% larger files. - genDecStructArrayInlineLoopCheck = true ) -type genStructMapStyle uint8 type genStringDecAsBytes string type genStringDecZC string @@ -195,12 +183,6 @@ var genStringDecAsBytesTyp = reflect.TypeOf(genStringDecAsBytes("")) var genStringDecZCTyp = reflect.TypeOf(genStringDecZC("")) var genFormats = []string{"Json", "Cbor", "Msgpack", "Binc", "Simple"} -const ( - genStructMapStyleConsolidated genStructMapStyle = iota - genStructMapStyleLenPrefix - genStructMapStyleCheckBreak -) - var ( errGenAllTypesSamePkg = errors.New("All types must be in the same package") errGenExpectArrayOrMap = errors.New("unexpected type - expecting array/map/slice") @@ -390,7 +372,7 @@ func Gen(w io.Writer, buildTags, pkgName, uid string, noExtensions bool, } } // add required packages - for _, k := range [...]string{"runtime", "errors", "strconv"} { // "reflect", "fmt" + for _, k := range [...]string{"runtime", "errors", "strconv", "sort"} { // "reflect", "fmt" if _, ok := x.im[k]; !ok { x.line("\"" + k + "\"") } @@ -416,6 +398,7 @@ func Gen(w io.Writer, buildTags, pkgName, uid string, noExtensions bool, x.line(")") x.line("var (") x.line("errCodecSelferOnlyMapOrArrayEncodeToStruct" + x.xs + " = " + "errors.New(`only encoded map or array can be decoded into a struct`)") + x.line("_ sort.Interface = nil") x.line(")") x.line("") @@ -425,6 +408,16 @@ func Gen(w io.Writer, buildTags, pkgName, uid string, noExtensions bool, x.linef("func %sFalse() bool { return false }", x.hn) x.linef("func %sTrue() bool { return true }", x.hn) x.line("") + + // add types for sorting canonical + for _, s := range []string{"string", "uint64", "int64", "float64"} { + x.linef("type %s%sSlice []%s", x.hn, s, s) + x.linef("func (p %s%sSlice) Len() int { return len(p) }", x.hn, s) + x.linef("func (p %s%sSlice) Swap(i, j int) { p[uint(i)], p[uint(j)] = p[uint(j)], p[uint(i)] }", x.hn, s) + x.linef("func (p %s%sSlice) Less(i, j int) bool { return p[uint(i)] < p[uint(j)] }", x.hn, s) + } + + x.line("") x.varsfxreset() x.line("func init() {") x.linef("if %sGenVersion != %v {", x.cpfx, genVersion) @@ -759,28 +752,12 @@ func (x *genRunner) selfer(encode bool) { } // write is containerMap - if genUseOneFunctionForDecStructMap { - x.out(fnSigPfx) - x.line(") codecDecodeSelfFromMap(l int, d *" + x.cpfx + "Decoder) {") - x.genRequiredMethodVars(false) - x.decStructMap(genTopLevelVarName, "l", rt2id(t0), t0, genStructMapStyleConsolidated) - x.line("}") - x.line("") - } else { - x.out(fnSigPfx) - x.line(") codecDecodeSelfFromMapLenPrefix(l int, d *" + x.cpfx + "Decoder) {") - x.genRequiredMethodVars(false) - x.decStructMap(genTopLevelVarName, "l", rt2id(t0), t0, genStructMapStyleLenPrefix) - x.line("}") - x.line("") - - x.out(fnSigPfx) - x.line(") codecDecodeSelfFromMapCheckBreak(l int, d *" + x.cpfx + "Decoder) {") - x.genRequiredMethodVars(false) - x.decStructMap(genTopLevelVarName, "l", rt2id(t0), t0, genStructMapStyleCheckBreak) - x.line("}") - x.line("") - } + x.out(fnSigPfx) + x.line(") codecDecodeSelfFromMap(l int, d *" + x.cpfx + "Decoder) {") + x.genRequiredMethodVars(false) + x.decStructMap(genTopLevelVarName, "l", rt2id(t0), t0) + x.line("}") + x.line("") // write containerArray x.out(fnSigPfx) @@ -942,9 +919,14 @@ func (x *genRunner) enc(varname string, t reflect.Type, isptr bool) { if ti2.flagSelfer { x.linef("%s %s.CodecEncodeSelf(e)", hasIf.c(true), varname) return - } else if ti2.flagSelferPtr { - x.linef("%s %ssf%s := &%s", hasIf.c(true), genTempVarPfx, mi, varname) - x.linef("%ssf%s.CodecEncodeSelf(e)", genTempVarPfx, mi) + } + if ti2.flagSelferPtr { + if isptr { + x.linef("%s %s.CodecEncodeSelf(e)", hasIf.c(true), varname) + } else { + x.linef("%s %ssf%s := &%s", hasIf.c(true), genTempVarPfx, mi, varname) + x.linef("%ssf%s.CodecEncodeSelf(e)", genTempVarPfx, mi) + } return } @@ -1134,7 +1116,7 @@ func (x *genRunner) doEncOmitEmptyLine(t2 reflect.StructField, varname string, b func (x *genRunner) encOmitEmptyLine(t2 reflect.StructField, varname string, buf *genBuf) { // xdebugf("calling encOmitEmptyLine on: %v", t2.Type) // smartly check omitEmpty on a struct type, as it may contain uncomparable map/slice/etc. - // also, for maps/slices/arrays, check if len ! 0 (not if == zero value) + // also, for maps/slices, check if len ! 0 (not if == zero value) varname2 := varname + "." + t2.Name switch t2.Type.Kind() { case reflect.Struct: @@ -1169,9 +1151,9 @@ func (x *genRunner) encOmitEmptyLine(t2 reflect.StructField, varname string, buf buf.s(varname2).s(" != ").s(x.genZeroValueR(t2.Type)) break } - // fmt.Printf("???? !!!! We shouldn't get to this point !!!! ???? - for type: %v\n", t2.Type) // buf.s("(") buf.s(x.sayFalse()) // buf.s("false") + var wrote bool for i, n := 0, t2.Type.NumField(); i < n; i++ { f := t2.Type.Field(i) if f.PkgPath != "" { // unexported @@ -1179,12 +1161,27 @@ func (x *genRunner) encOmitEmptyLine(t2 reflect.StructField, varname string, buf } buf.s(" || ") x.encOmitEmptyLine(f, varname2, buf) + wrote = true + } + if !wrote { + buf.s(" || ").s(x.sayTrue()) } //buf.s(")") case reflect.Bool: buf.s("bool(").s(varname2).s(")") - case reflect.Map, reflect.Slice, reflect.Array, reflect.Chan: + case reflect.Map, reflect.Slice, reflect.Chan: buf.s("len(").s(varname2).s(") != 0") + case reflect.Array: + tlen := t2.Type.Len() + if tlen == 0 { + buf.s(x.sayFalse()) + } else if t2.Type.Comparable() { + buf.s(varname2).s(" != ").s(x.genZeroValueR(t2.Type)) + } else { // then we cannot even compare the individual values + // TODO use playground to check if you can compare to a + // zero value of an array, even if array not comparable. + buf.s(x.sayTrue()) + } default: buf.s(varname2).s(" != ").s(x.genZeroValueR(t2.Type)) } @@ -1214,7 +1211,10 @@ func (x *genRunner) encStruct(varname string, rtid uintptr, t reflect.Type) { } genFQNs := make([]genFQN, len(tisfi)) + si2Pos := make(map[*structFieldInfo]int) // stores position in sorted structFieldInfos + for j, si := range tisfi { + si2Pos[si] = j q := &genFQNs[j] q.i = x.varsfx() q.nilVar = genTempVarPfx + "n" + q.i @@ -1329,11 +1329,13 @@ func (x *genRunner) encStruct(varname string, rtid uintptr, t reflect.Type) { } fn := func(tisfi []*structFieldInfo) { - for j, si := range tisfi { - q := &genFQNs[j] + // tisfi here may be source or sorted, so use the src position stored elsewhere + for _, si := range tisfi { + pos := si2Pos[si] + q := &genFQNs[pos] doOmitEmptyCheck := (omitEmptySometimes && si.path.omitEmpty) || omitEmptyAlways if doOmitEmptyCheck { - x.linef("if %s[%v] {", numfieldsvar, j) + x.linef("if %s[%v] {", numfieldsvar, pos) } x.linef("z.EncWriteMapElemKey()") @@ -1348,7 +1350,7 @@ func (x *genRunner) encStruct(varname string, rtid uintptr, t reflect.Type) { default: // string if x.jsonOnlyWhen == nil { if si.path.encNameAsciiAlphaNum { - x.linef(`if z.IsJSONHandle() { z.WriteStr("\"%s\"") } else { `, si.encName) + x.linef(`if z.IsJSONHandle() { z.EncWr().WriteStr("\"%s\"") } else { `, si.encName) } x.linef("r.EncodeString(`%s`)", si.encName) if si.path.encNameAsciiAlphaNum { @@ -1356,7 +1358,7 @@ func (x *genRunner) encStruct(varname string, rtid uintptr, t reflect.Type) { } } else if *(x.jsonOnlyWhen) { if si.path.encNameAsciiAlphaNum { - x.linef(`z.WriteStr("\"%s\"")`, si.encName) + x.linef(`z.EncWr().WriteStr("\"%s\"")`, si.encName) } else { x.linef("r.EncodeString(`%s`)", si.encName) } @@ -1381,7 +1383,7 @@ func (x *genRunner) encStruct(varname string, rtid uintptr, t reflect.Type) { if genStructCanonical { x.linef("if z.EncBasicHandle().Canonical {") // if Canonical block fn(ti.sfi.sorted()) - x.linef("} else {") // else !cononical block + x.linef("} else {") // else !Canonical block fn(ti.sfi.source()) x.linef("}") // end if Canonical block } else { @@ -1445,9 +1447,109 @@ func (x *genRunner) encListFallback(varname string, t reflect.Type) { func (x *genRunner) encMapFallback(varname string, t reflect.Type) { x.linef("if %s == nil { r.EncodeNil()", varname) - x.linef("} else if z.EncBasicHandle().Canonical { z.EncEncodeMapNonNil(%s)", varname) + x.line("} else if z.EncBasicHandle().Canonical {") + + // Solve for easy case accomodated by sort package without reflection i.e. + // map keys of type: float, int, string (pre-defined/builtin types). + // + // To do this, we will get the keys into an array of uint64|float64|string, + // sort them, then write them out, and grab the value and encode it appropriately + tkey := t.Key() + tkind := tkey.Kind() + // tkeybase := tkey + // for tkeybase.Kind() == reflect.Ptr { + // tkeybase = tkeybase.Elem() + // } + // tikey := x.ti.get(rt2id(tkeybase), tkeybase) + + // pre-defined types have a name and no pkgpath and appropriate kind + predeclared := tkey.PkgPath() == "" && tkey.Name() != "" + + canonSortKind := reflect.Invalid + switch tkind { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + canonSortKind = reflect.Int64 + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + canonSortKind = reflect.Uint64 + case reflect.Float32, reflect.Float64: + canonSortKind = reflect.Float64 + case reflect.String: + canonSortKind = reflect.String + } + + var i string = x.varsfx() + + fnCanonNumBoolStrKind := func() { + if !predeclared { + x.linef("var %svv%s %s", genTempVarPfx, i, x.genTypeName(tkey)) + x.linef("%sencfn%s := z.EncFnGivenAddr(&%svv%s)", genTempVarPfx, i, genTempVarPfx, i) + } + // get the type, get the slice type its mapped to, and complete the code + x.linef("%ss%s := make([]%s, 0, len(%s))", genTempVarPfx, i, canonSortKind, varname) + x.linef("for k, _ := range %s {", varname) + x.linef(" %ss%s = append(%ss%s, %s(k))", genTempVarPfx, i, genTempVarPfx, i, canonSortKind) + x.linef("}") + x.linef("sort.Sort(%s%sSlice(%ss%s))", x.hn, canonSortKind, genTempVarPfx, i) + x.linef("z.EncWriteMapStart(len(%s))", varname) + x.linef("for _, %sv%s := range %ss%s {", genTempVarPfx, i, genTempVarPfx, i) + x.linef(" z.EncWriteMapElemKey()") + if predeclared { + switch tkind { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32: + x.linef("r.EncodeInt(int64(%sv%s))", genTempVarPfx, i) + case reflect.Int64: + x.linef("r.EncodeInt(%sv%s)", genTempVarPfx, i) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uintptr: + x.linef("r.EncodeUint(%sv%s)", genTempVarPfx, i) + case reflect.Uint64: + x.linef("r.EncodeUint(uint64(%sv%s))", genTempVarPfx, i) + case reflect.Float32: + x.linef("r.EncodeFloat32(float32(%sv%s))", genTempVarPfx, i) + case reflect.Float64: + x.linef("r.EncodeFloat64(%sv%s)", genTempVarPfx, i) + case reflect.String: + x.linef("r.EncodeString(%sv%s)", genTempVarPfx, i) + } + } else { + x.linef("%svv%s = %s(%sv%s)", genTempVarPfx, i, x.genTypeName(tkey), genTempVarPfx, i) + x.linef("z.EncEncodeNumBoolStrKindGivenAddr(&%svv%s, %sencfn%s)", genTempVarPfx, i, genTempVarPfx, i) + } + x.linef(" z.EncWriteMapElemValue()") + vname := genTempVarPfx + "e" + i + if predeclared { + x.linef("%s := %s[%s(%sv%s)]", vname, varname, x.genTypeName(tkey), genTempVarPfx, i) + } else { + x.linef("%s := %s[%svv%s]", vname, varname, genTempVarPfx, i) + } + x.encVar(vname, t.Elem()) + x.linef("}") + + x.line("z.EncWriteMapEnd()") + + } + + // if canonSortKind != reflect.Invalid && !tikey.flagMarshalInterface { + // if predeclared { + // fnCanonNumBoolStrKind() + // } else { + // // handle if an extension + // x.linef("if z.Extension(%s(%s)) != nil { z.EncEncodeMapNonNil(%s) } else {", + // x.genTypeName(tkey), x.genZeroValueR(tkey), varname) + // fnCanonNumBoolStrKind() + // x.line("}") + // } + // } else { + // x.linef("z.EncEncodeMapNonNil(%s)", varname) + // } + + if canonSortKind != reflect.Invalid { + fnCanonNumBoolStrKind() + } else { + x.linef("z.EncEncodeMapNonNil(%s)", varname) + } + x.line("} else {") - i := x.varsfx() + x.linef("z.EncWriteMapStart(len(%s))", varname) x.linef("for %sk%s, %sv%s := range %s {", genTempVarPfx, i, genTempVarPfx, i, varname) x.linef("z.EncWriteMapElemKey()") @@ -1456,6 +1558,7 @@ func (x *genRunner) encMapFallback(varname string, t reflect.Type) { x.encVar(genTempVarPfx+"v"+i, t.Elem()) x.line("}") x.line("z.EncWriteMapEnd()") + x.line("}") } @@ -1947,23 +2050,16 @@ func (x *genRunner) decStructMapSwitch(kName string, varname string, rtid uintpt x.linef("} // end switch %s", kName) } -func (x *genRunner) decStructMap(varname, lenvarname string, rtid uintptr, t reflect.Type, style genStructMapStyle) { +func (x *genRunner) decStructMap(varname, lenvarname string, rtid uintptr, t reflect.Type) { tpfx := genTempVarPfx ti := x.ti.get(rtid, t) i := x.varsfx() kName := tpfx + "s" + i - switch style { - case genStructMapStyleLenPrefix: - x.linef("for %sj%s := 0; %sj%s < %s; %sj%s++ {", tpfx, i, tpfx, i, lenvarname, tpfx, i) - case genStructMapStyleCheckBreak: - x.linef("for %sj%s := 0; !z.DecCheckBreak(); %sj%s++ {", tpfx, i, tpfx, i) - default: // 0, otherwise. - x.linef("var %shl%s bool = %s >= 0", tpfx, i, lenvarname) // has length - x.linef("for %sj%s := 0; ; %sj%s++ {", tpfx, i, tpfx, i) - x.linef("if %shl%s { if %sj%s >= %s { break }", tpfx, i, tpfx, i, lenvarname) - x.line("} else { if z.DecCheckBreak() { break }; }") - } + x.linef("var %shl%s bool = %s >= 0", tpfx, i, lenvarname) // has length + x.linef("for %sj%s := 0; z.DecContainerNext(%sj%s, %s, %shl%s); %sj%s++ {", + tpfx, i, tpfx, i, lenvarname, tpfx, i, tpfx, i) + x.line("z.DecReadMapElemKey()") // emulate decstructfieldkey @@ -1992,24 +2088,11 @@ func (x *genRunner) decStructArray(varname, lenvarname, breakString string, rtid x.linef("var %sj%s int", tpfx, i) x.linef("var %sb%s bool", tpfx, i) // break x.linef("var %shl%s bool = %s >= 0", tpfx, i, lenvarname) // has length - if !genDecStructArrayInlineLoopCheck { - x.linef("var %sfn%s = func() bool { ", tpfx, i) - x.linef("%sj%s++; if %shl%s { %sb%s = %sj%s > %s } else { %sb%s = z.DecCheckBreak() };", - tpfx, i, tpfx, i, tpfx, i, - tpfx, i, lenvarname, tpfx, i) - x.linef("if %sb%s { z.DecReadArrayEnd(); return true }; return false", tpfx, i) - x.linef("} // end func %sfn%s", tpfx, i) - } var newbuf, nilbuf genBuf for _, si := range tisfi { - if genDecStructArrayInlineLoopCheck { - x.linef("%sj%s++; if %shl%s { %sb%s = %sj%s > %s } else { %sb%s = z.DecCheckBreak() }", - tpfx, i, tpfx, i, tpfx, i, - tpfx, i, lenvarname, tpfx, i) - x.linef("if %sb%s { z.DecReadArrayEnd(); %s }", tpfx, i, breakString) - } else { - x.linef("if %sfn%s() { %s }", tpfx, i, breakString) - } + x.linef("%sj%s++", tpfx, i) + x.linef("%sb%s = !z.DecContainerNext(%sj%s, %s, %shl%s)", tpfx, i, tpfx, i, lenvarname, tpfx, i) + x.linef("if %sb%s { z.DecReadArrayEnd(); %s }", tpfx, i, breakString) x.line("z.DecReadArrayElem()") newbuf.reset() nilbuf.reset() @@ -2023,11 +2106,8 @@ func (x *genRunner) decStructArray(varname, lenvarname, breakString string, rtid } } // read remaining values and throw away. - x.line("for {") - x.linef("%sj%s++; if %shl%s { %sb%s = %sj%s > %s } else { %sb%s = z.DecCheckBreak() }", - tpfx, i, tpfx, i, tpfx, i, - tpfx, i, lenvarname, tpfx, i) - x.linef("if %sb%s { break }", tpfx, i) + x.linef("for %sj%s++; z.DecContainerNext(%sj%s, %s, %shl%s); %sj%s++ {", + tpfx, i, tpfx, i, lenvarname, tpfx, i, tpfx, i) x.line("z.DecReadArrayElem()") x.linef(`z.DecStructFieldNotFound(%sj%s - 1, "")`, tpfx, i) x.line("}") @@ -2042,15 +2122,10 @@ func (x *genRunner) decStruct(varname string, rtid uintptr, t reflect.Type) { x.linef("} else if %sct%s == codecSelferValueTypeMap%s {", genTempVarPfx, i, x.xs) x.line(genTempVarPfx + "l" + i + " := z.DecReadMapStart()") x.linef("if %sl%s == 0 {", genTempVarPfx, i) - if genUseOneFunctionForDecStructMap { - x.line("} else { ") - x.linef("%s.codecDecodeSelfFromMap(%sl%s, d)", varname, genTempVarPfx, i) - } else { - x.line("} else if " + genTempVarPfx + "l" + i + " > 0 { ") - x.line(varname + ".codecDecodeSelfFromMapLenPrefix(" + genTempVarPfx + "l" + i + ", d)") - x.line("} else {") - x.line(varname + ".codecDecodeSelfFromMapCheckBreak(" + genTempVarPfx + "l" + i + ", d)") - } + + x.line("} else { ") + x.linef("%s.codecDecodeSelfFromMap(%sl%s, d)", varname, genTempVarPfx, i) + x.line("}") x.line("z.DecReadMapEnd()") @@ -2684,7 +2759,7 @@ func genInternalSortableTypes() []string { // that are used for reflection-based canonical's encoding of maps. // // For now, we only support the highest sizes for -// int64, uint64, float64, bool, string, bytes. +// int64, uint64, float64, string, bytes. func genInternalSortablePlusTypes() []string { return []string{ "string", @@ -2692,7 +2767,7 @@ func genInternalSortablePlusTypes() []string { "uint64", // "uintptr", "int64", - "bool", + // "bool", "time", "bytes", } diff --git a/vendor/github.com/ugorji/go/codec/goversion_growslice_unsafe_gte_go120.go b/vendor/github.com/ugorji/go/codec/goversion_growslice_unsafe_gte_go120.go new file mode 100644 index 000000000..d5fed78e2 --- /dev/null +++ b/vendor/github.com/ugorji/go/codec/goversion_growslice_unsafe_gte_go120.go @@ -0,0 +1,28 @@ +// Copyright (c) 2012-2020 Ugorji Nwoke. All rights reserved. +// Use of this source code is governed by a MIT license found in the LICENSE file. + +//go:build go1.20 && !safe && !codec.safe && !appengine +// +build go1.20,!safe,!codec.safe,!appengine + +package codec + +import ( + _ "reflect" // needed for go linkname(s) + "unsafe" +) + +func growslice(typ unsafe.Pointer, old unsafeSlice, num int) (s unsafeSlice) { + // culled from GOROOT/runtime/slice.go + num -= old.Cap - old.Len + s = rtgrowslice(old.Data, old.Cap+num, old.Cap, num, typ) + s.Len = old.Len + return +} + +//go:linkname rtgrowslice runtime.growslice +//go:noescape +func rtgrowslice(oldPtr unsafe.Pointer, newLen, oldCap, num int, typ unsafe.Pointer) unsafeSlice + +// //go:linkname growslice reflect.growslice +// //go:noescape +// func growslice(typ unsafe.Pointer, old unsafeSlice, cap int) unsafeSlice diff --git a/vendor/github.com/ugorji/go/codec/goversion_growslice_unsafe_lt_go120.go b/vendor/github.com/ugorji/go/codec/goversion_growslice_unsafe_lt_go120.go new file mode 100644 index 000000000..550c5d9e0 --- /dev/null +++ b/vendor/github.com/ugorji/go/codec/goversion_growslice_unsafe_lt_go120.go @@ -0,0 +1,16 @@ +// Copyright (c) 2012-2020 Ugorji Nwoke. All rights reserved. +// Use of this source code is governed by a MIT license found in the LICENSE file. + +//go:build go1.9 && !go1.20 && !safe && !codec.safe && !appengine +// +build go1.9,!go1.20,!safe,!codec.safe,!appengine + +package codec + +import ( + _ "runtime" // needed for go linkname(s) + "unsafe" +) + +//go:linkname growslice runtime.growslice +//go:noescape +func growslice(typ unsafe.Pointer, old unsafeSlice, num int) unsafeSlice diff --git a/vendor/github.com/ugorji/go/codec/helper.go b/vendor/github.com/ugorji/go/codec/helper.go index dc485a5ef..19df27b60 100644 --- a/vendor/github.com/ugorji/go/codec/helper.go +++ b/vendor/github.com/ugorji/go/codec/helper.go @@ -215,7 +215,8 @@ import ( // Note: Negative tests that check for errors will fail, so only use this // when debugging, and run only one test at a time preferably. // -// Note: RPC tests espeially fail, as they depend on getting the error from an Encode/Decode call. +// Note: RPC tests depend on getting the error from an Encode/Decode call. +// Consequently, they will always fail if debugging = true. const debugging = false const ( @@ -617,6 +618,10 @@ func (e *codecError) Cause() error { return e.err } +func (e *codecError) Unwrap() error { + return e.err +} + func (e *codecError) Error() string { if e.encode { return fmt.Sprintf("%s encode error: %v", e.name, e.err) @@ -715,9 +720,10 @@ var SelfExt = &extFailWrapper{} // By definition, it is not allowed for a Selfer to directly call Encode or Decode on itself. // If that is done, Encode/Decode will rightfully fail with a Stack Overflow style error. // For example, the snippet below will cause such an error. -// type testSelferRecur struct{} -// func (s *testSelferRecur) CodecEncodeSelf(e *Encoder) { e.MustEncode(s) } -// func (s *testSelferRecur) CodecDecodeSelf(d *Decoder) { d.MustDecode(s) } +// +// type testSelferRecur struct{} +// func (s *testSelferRecur) CodecEncodeSelf(e *Encoder) { e.MustEncode(s) } +// func (s *testSelferRecur) CodecDecodeSelf(d *Decoder) { d.MustDecode(s) } // // Note: *the first set of bytes of any value MUST NOT represent nil in the format*. // This is because, during each decode, we first check the the next set of bytes @@ -761,13 +767,14 @@ type MissingFielder interface { // This affords storing a map in a specific sequence in the stream. // // Example usage: -// type T1 []string // or []int or []Point or any other "slice" type -// func (_ T1) MapBySlice{} // T1 now implements MapBySlice, and will be encoded as a map -// type T2 struct { KeyValues T1 } // -// var kvs = []string{"one", "1", "two", "2", "three", "3"} -// var v2 = T2{ KeyValues: T1(kvs) } -// // v2 will be encoded like the map: {"KeyValues": {"one": "1", "two": "2", "three": "3"} } +// type T1 []string // or []int or []Point or any other "slice" type +// func (_ T1) MapBySlice{} // T1 now implements MapBySlice, and will be encoded as a map +// type T2 struct { KeyValues T1 } +// +// var kvs = []string{"one", "1", "two", "2", "three", "3"} +// var v2 = T2{ KeyValues: T1(kvs) } +// // v2 will be encoded like the map: {"KeyValues": {"one": "1", "two": "2", "three": "3"} } // // The support of MapBySlice affords the following: // - A slice or array type which implements MapBySlice will be encoded as a map @@ -969,6 +976,7 @@ func (x *basicHandleRuntimeState) setExt(rt reflect.Type, tag uint64, ext Ext) ( // initHandle should be called only from codec.initHandle global function. // make it uninlineable, as it is called at most once for each handle. +// //go:noinline func (x *BasicHandle) initHandle(hh Handle) { handleInitMu.Lock() @@ -1554,6 +1562,10 @@ func (z bigenHelper) writeUint16(w *encWr, v uint16) { } func (z bigenHelper) writeUint32(w *encWr, v uint32) { + // w.writeb((z.PutUint32(v))[:]) + // x := z.PutUint32(v) + // w.writeb(x[:]) + // w.writen4(x[0], x[1], x[2], x[3]) w.writen4(z.PutUint32(v)) } @@ -1731,7 +1743,7 @@ func (path *structFieldInfoPathNode) fieldAlloc(v reflect.Value) (rv2 reflect.Va v = parent.fieldAlloc(v) for j, k := uint8(0), parent.numderef; j < k; j++ { if rvIsNil(v) { - rvSetDirect(v, reflect.New(rvType(v).Elem())) + rvSetDirect(v, reflect.New(v.Type().Elem())) } v = v.Elem() } @@ -1863,10 +1875,10 @@ type typeInfo struct { keykind, elemkind uint8 flagHasPkgPath bool // Type.PackagePath != "" - flagCustom bool // does this have custom implementation? flagComparable bool flagCanTransient bool + flagMarshalInterface bool // does this have custom (un)marshal implementation? flagSelferViaCodecgen bool // custom implementation flags @@ -2128,7 +2140,6 @@ func (x *TypeInfos) load(rt reflect.Type) (pti *typeInfo) { bset := func(when bool, b *bool) { if when { *b = true - ti.flagCustom = true } } @@ -2168,6 +2179,15 @@ func (x *TypeInfos) load(rt reflect.Type) (pti *typeInfo) { b1, b2 = implIntf(rt, isSelferViaCodecgenerTyp) ti.flagSelferViaCodecgen = b1 || b2 + ti.flagMarshalInterface = ti.flagSelfer || ti.flagSelferPtr || + ti.flagSelferViaCodecgen || + ti.flagBinaryMarshaler || ti.flagBinaryMarshalerPtr || + ti.flagBinaryUnmarshaler || ti.flagBinaryUnmarshalerPtr || + ti.flagTextMarshaler || ti.flagTextMarshalerPtr || + ti.flagTextUnmarshaler || ti.flagTextUnmarshalerPtr || + ti.flagJsonMarshaler || ti.flagJsonMarshalerPtr || + ti.flagJsonUnmarshaler || ti.flagJsonUnmarshalerPtr + b1 = rt.Comparable() // bset(b1, &ti.flagComparable) ti.flagComparable = b1 @@ -2443,6 +2463,14 @@ func implIntf(rt, iTyp reflect.Type) (base bool, indir bool) { return } +func bool2int(b bool) (v uint8) { + // MARKER: optimized to be a single instruction + if b { + v = 1 + } + return +} + func isSliceBoundsError(s string) bool { return strings.Contains(s, "index out of range") || strings.Contains(s, "slice bounds out of range") @@ -2581,17 +2609,22 @@ func (checkOverflow) Uint2Int(v uint64, neg bool) (overflow bool) { func (checkOverflow) SignedInt(v uint64) (overflow bool) { //e.g. -127 to 128 for int8 - pos := (v >> 63) == 0 - ui2 := v & 0x7fffffffffffffff - if pos { - if ui2 > math.MaxInt64 { - overflow = true - } - } else { - if ui2 > math.MaxInt64-1 { - overflow = true - } - } + // pos := (v >> 63) == 0 + // ui2 := v & 0x7fffffffffffffff + // if pos { + // if ui2 > math.MaxInt64 { + // overflow = true + // } + // } else { + // if ui2 > math.MaxInt64-1 { + // overflow = true + // } + // } + + // a signed integer has overflow if the sign (first) bit is 1 (negative) + // and the numbers after the sign bit is > maxint64 - 1 + overflow = (v>>63) != 0 && v&0x7fffffffffffffff > math.MaxInt64-1 + return } @@ -2774,22 +2807,23 @@ func freelistCapacity(length int) (capacity int) { // without bounds checking is sufficient. // // Typical usage model: -// peek may go together with put, iff pop=true. peek gets largest byte slice temporarily. -// check is used to switch a []byte if necessary -// get/put go together +// +// peek may go together with put, iff pop=true. peek gets largest byte slice temporarily. +// check is used to switch a []byte if necessary +// get/put go together // // Given that folks may get a []byte, and then append to it a lot which may re-allocate // a new []byte, we should try to return both (one received from blist and new one allocated). // // Typical usage model for get/put, when we don't know whether we may need more than requested -// v0 := blist.get() -// v1 := v0 -// ... use v1 ... -// blist.put(v1) -// if byteSliceAddr(v0) != byteSliceAddr(v1) { -// blist.put(v0) -// } // +// v0 := blist.get() +// v1 := v0 +// ... use v1 ... +// blist.put(v1) +// if byteSliceAddr(v0) != byteSliceAddr(v1) { +// blist.put(v0) +// } type bytesFreelist [][]byte // peek returns a slice of possibly non-zero'ed bytes, with len=0, diff --git a/vendor/github.com/ugorji/go/codec/helper_not_unsafe.go b/vendor/github.com/ugorji/go/codec/helper_not_unsafe.go index 57a3fe26d..10034b86f 100644 --- a/vendor/github.com/ugorji/go/codec/helper_not_unsafe.go +++ b/vendor/github.com/ugorji/go/codec/helper_not_unsafe.go @@ -22,6 +22,22 @@ const safeMode = true const transientSizeMax = 0 const transientValueHasStringSlice = true +func byteAt(b []byte, index uint) byte { + return b[index] +} + +func setByteAt(b []byte, index uint, val byte) { + b[index] = val +} + +func byteSliceOf(b []byte, start, end uint) []byte { + return b[start:end] +} + +// func byteSliceWithLen(b []byte, length uint) []byte { +// return b[:length] +// } + func stringView(v []byte) string { return string(v) } @@ -34,8 +50,13 @@ func byteSliceSameData(v1 []byte, v2 []byte) bool { return cap(v1) != 0 && cap(v2) != 0 && &(v1[:1][0]) == &(v2[:1][0]) } -func okBytes3(b []byte) (v [4]byte) { - copy(v[1:], b) +func okBytes2(b []byte) (v [2]byte) { + copy(v[:], b) + return +} + +func okBytes3(b []byte) (v [3]byte) { + copy(v[:], b) return } @@ -114,8 +135,19 @@ func isEmptyValue(v reflect.Value, tinfos *TypeInfos, recursive bool) bool { switch v.Kind() { case reflect.Invalid: return true - case reflect.Array, reflect.String: + case reflect.String: return v.Len() == 0 + case reflect.Array: + // zero := reflect.Zero(v.Type().Elem()) + // can I just check if the whole value is equal to zeros? seems not. + // can I just check if the whole value is equal to its zero value? no. + // Well, then we check if each value is empty without recursive. + for i, vlen := 0, v.Len(); i < vlen; i++ { + if !isEmptyValue(v.Index(i), tinfos, false) { + return false + } + } + return true case reflect.Map, reflect.Slice, reflect.Chan: return v.IsNil() || v.Len() == 0 case reflect.Bool: @@ -144,16 +176,16 @@ func isEmptyValue(v reflect.Value, tinfos *TypeInfos, recursive bool) bool { } // isEmptyStruct is only called from isEmptyValue, and checks if a struct is empty: -// - does it implement IsZero() bool -// - is it comparable, and can i compare directly using == -// - if checkStruct, then walk through the encodable fields -// and check if they are empty or not. +// - does it implement IsZero() bool +// - is it comparable, and can i compare directly using == +// - if checkStruct, then walk through the encodable fields +// and check if they are empty or not. func isEmptyStruct(v reflect.Value, tinfos *TypeInfos, recursive bool) bool { // v is a struct kind - no need to check again. // We only check isZero on a struct kind, to reduce the amount of times // that we lookup the rtid and typeInfo for each type as we walk the tree. - vt := rvType(v) + vt := v.Type() rtid := rt2id(vt) if tinfos == nil { tinfos = defTypeInfos @@ -505,7 +537,7 @@ func rvGetArrayBytes(rv reflect.Value, scratch []byte) (bs []byte) { } func rvGetArray4Slice(rv reflect.Value) (v reflect.Value) { - v = rvZeroAddrK(reflectArrayOf(rvLenSlice(rv), rvType(rv).Elem()), reflect.Array) + v = rvZeroAddrK(reflectArrayOf(rvLenSlice(rv), rv.Type().Elem()), reflect.Array) reflect.Copy(v, rv) return } @@ -615,6 +647,14 @@ func rvLenMap(rv reflect.Value) int { return rv.Len() } +// func copybytes(to, from []byte) int { +// return copy(to, from) +// } + +// func copybytestr(to []byte, from string) int { +// return copy(to, from) +// } + // func rvLenArray(rv reflect.Value) int { return rv.Len() } // ------------ map range and map indexing ---------- @@ -645,10 +685,6 @@ func (e *Encoder) jsondriver() *jsonEncDriver { // ---------- DECODER optimized --------------- -func (d *Decoder) checkBreak() bool { - return d.d.CheckBreak() -} - func (d *Decoder) jsondriver() *jsonDecDriver { return d.d.(*jsonDecDriver) } diff --git a/vendor/github.com/ugorji/go/codec/helper_not_unsafe_not_gc.go b/vendor/github.com/ugorji/go/codec/helper_not_unsafe_not_gc.go index e3fdc8854..502bc6086 100644 --- a/vendor/github.com/ugorji/go/codec/helper_not_unsafe_not_gc.go +++ b/vendor/github.com/ugorji/go/codec/helper_not_unsafe_not_gc.go @@ -6,7 +6,7 @@ package codec -import "reflect" +// import "reflect" // This files contains safe versions of the code where the unsafe versions are not supported // in either gccgo or gollvm. @@ -14,6 +14,8 @@ import "reflect" // - rvType: // reflect.toType is not supported in gccgo, gollvm. -func rvType(rv reflect.Value) reflect.Type { - return rv.Type() -} +// func rvType(rv reflect.Value) reflect.Type { +// return rv.Type() +// } + +var _ = 0 diff --git a/vendor/github.com/ugorji/go/codec/helper_unsafe.go b/vendor/github.com/ugorji/go/codec/helper_unsafe.go index 34cda6e27..4e29b030b 100644 --- a/vendor/github.com/ugorji/go/codec/helper_unsafe.go +++ b/vendor/github.com/ugorji/go/codec/helper_unsafe.go @@ -51,11 +51,9 @@ import ( // - IsNil // MARKER: Some functions here will not be hit during code coverage runs due to optimizations, e.g. -// - rvCopySlice: decode calls it if rvGrowSlice didn't set the new slice into the pointer to the orig slice. -// however, helper_unsafe sets it, so there's no need to call rvCopySlice later +// - rvCopySlice: called by decode if rvGrowSlice did not set new slice into pointer to orig slice. +// however, helper_unsafe sets it, so no need to call rvCopySlice later // - rvSlice: same as above -// - rvGetArray4Bytes: only called within kArray for []byte, but that is now handled -// within the fast-path directly const safeMode = false @@ -177,6 +175,32 @@ func (encPerType) AddressableRO(v reflect.Value) reflect.Value { return rvAddressableReadonly(v) } +// byteAt returns the byte given an index which is guaranteed +// to be within the bounds of the slice i.e. we defensively +// already verified that the index is less than the length of the slice. +func byteAt(b []byte, index uint) byte { + // return b[index] + return *(*byte)(unsafe.Pointer(uintptr((*unsafeSlice)(unsafe.Pointer(&b)).Data) + uintptr(index))) +} + +func byteSliceOf(b []byte, start, end uint) []byte { + s := (*unsafeSlice)(unsafe.Pointer(&b)) + s.Data = unsafe.Pointer(uintptr(s.Data) + uintptr(start)) + s.Len = int(end - start) + s.Cap -= int(start) + return b +} + +// func byteSliceWithLen(b []byte, length uint) []byte { +// (*unsafeSlice)(unsafe.Pointer(&b)).Len = int(length) +// return b +// } + +func setByteAt(b []byte, index uint, val byte) { + // b[index] = val + *(*byte)(unsafe.Pointer(uintptr((*unsafeSlice)(unsafe.Pointer(&b)).Data) + uintptr(index))) = val +} + // stringView returns a view of the []byte as a string. // In unsafe mode, it doesn't incur allocation and copying caused by conversion. // In regular safe mode, it is an allocation and copy. @@ -199,12 +223,15 @@ func byteSliceSameData(v1 []byte, v2 []byte) bool { } // MARKER: okBytesN functions will copy N bytes into the top slots of the return array. -// These functions expect that the bounds are valid, and have been checked before this is called. +// These functions expect that the bound check already occured and are are valid. // copy(...) does a number of checks which are unnecessary in this situation when in bounds. -func okBytes3(b []byte) (v [4]byte) { - *(*[3]byte)(unsafe.Pointer(&v[1])) = *((*[3]byte)(((*unsafeSlice)(unsafe.Pointer(&b))).Data)) - return +func okBytes2(b []byte) [2]byte { + return *((*[2]byte)(((*unsafeSlice)(unsafe.Pointer(&b))).Data)) +} + +func okBytes3(b []byte) [3]byte { + return *((*[3]byte)(((*unsafeSlice)(unsafe.Pointer(&b))).Data)) } func okBytes4(b []byte) [4]byte { @@ -446,7 +473,7 @@ func isEmptyValueFallbackRecur(urv *unsafeReflectValue, v reflect.Value, tinfos } ti := tinfos.find(uintptr(urv.typ)) if ti == nil { - ti = tinfos.load(rvType(v)) + ti = tinfos.load(v.Type()) } return unsafeCmpZero(urv.ptr, int(ti.size)) case reflect.Interface, reflect.Ptr: @@ -463,7 +490,11 @@ func isEmptyValueFallbackRecur(urv *unsafeReflectValue, v reflect.Value, tinfos case reflect.Map: return urv.ptr == nil || len_map(rvRefPtr(urv)) == 0 case reflect.Array: - return v.Len() == 0 + return v.Len() == 0 || + urv.ptr == nil || + urv.typ == nil || + rtsize2(urv.typ) == 0 || + unsafeCmpZero(urv.ptr, int(rtsize2(urv.typ))) } return false } @@ -858,7 +889,7 @@ func rvGetArray4Slice(rv reflect.Value) (v reflect.Value) { // // Consequently, we use rvLenSlice, not rvCapSlice. - t := reflectArrayOf(rvLenSlice(rv), rvType(rv).Elem()) + t := reflectArrayOf(rvLenSlice(rv), rv.Type().Elem()) // v = rvZeroAddrK(t, reflect.Array) uv := (*unsafeReflectValue)(unsafe.Pointer(&v)) @@ -996,6 +1027,32 @@ func rvLenMap(rv reflect.Value) int { return len_map(rvRefPtr((*unsafeReflectValue)(unsafe.Pointer(&rv)))) } +// copy is an intrinsic, which may use asm if length is small, +// or make a runtime call to runtime.memmove if length is large. +// Performance suffers when you always call runtime.memmove function. +// +// Consequently, there's no value in a copybytes call - just call copy() directly + +// func copybytes(to, from []byte) (n int) { +// n = (*unsafeSlice)(unsafe.Pointer(&from)).Len +// memmove( +// (*unsafeSlice)(unsafe.Pointer(&to)).Data, +// (*unsafeSlice)(unsafe.Pointer(&from)).Data, +// uintptr(n), +// ) +// return +// } + +// func copybytestr(to []byte, from string) (n int) { +// n = (*unsafeSlice)(unsafe.Pointer(&from)).Len +// memmove( +// (*unsafeSlice)(unsafe.Pointer(&to)).Data, +// (*unsafeSlice)(unsafe.Pointer(&from)).Data, +// uintptr(n), +// ) +// return +// } + // Note: it is hard to find len(...) of an array type, // as that is a field in the arrayType representing the array, and hard to introspect. // @@ -1159,7 +1216,10 @@ func (d *Decoder) zerocopystate() bool { } func (d *Decoder) stringZC(v []byte) (s string) { - if d.zerocopystate() { + // MARKER: inline zerocopystate directly so genHelper forwarding function fits within inlining cost + + // if d.zerocopystate() { + if d.decByteState == decByteStateZerocopy && d.h.ZeroCopy { return stringView(v) } return d.string(v) @@ -1178,22 +1238,6 @@ func (d *Decoder) mapKeyString(callFnRvk *bool, kstrbs, kstr2bs *[]byte) string // ---------- DECODER optimized --------------- -func (d *Decoder) checkBreak() bool { - // MARKER: jsonDecDriver.CheckBreak() costs over 80, and this isn't inlined. - // Consequently, there's no benefit in incurring the cost of this - // wrapping function checkBreak. - // - // It is faster to just call the interface method directly. - - // if d.js { - // return d.jsondriver().CheckBreak() - // } - // if d.cbor { - // return d.cbordriver().CheckBreak() - // } - return d.d.CheckBreak() -} - func (d *Decoder) jsondriver() *jsonDecDriver { return (*jsonDecDriver)((*unsafeIntf)(unsafe.Pointer(&d.d)).ptr) } @@ -1255,6 +1299,10 @@ func unsafeNew(typ unsafe.Pointer) unsafe.Pointer { // failing with "error: undefined reference" error. // however, runtime.{mallocgc, newarray} are supported, so use that instead. +//go:linkname memmove runtime.memmove +//go:noescape +func memmove(to, from unsafe.Pointer, n uintptr) + //go:linkname mallocgc runtime.mallocgc //go:noescape func mallocgc(size uintptr, typ unsafe.Pointer, needzero bool) unsafe.Pointer diff --git a/vendor/github.com/ugorji/go/codec/helper_unsafe_compiler_gc.go b/vendor/github.com/ugorji/go/codec/helper_unsafe_compiler_gc.go index 1cbce9d22..a5c7d59a0 100644 --- a/vendor/github.com/ugorji/go/codec/helper_unsafe_compiler_gc.go +++ b/vendor/github.com/ugorji/go/codec/helper_unsafe_compiler_gc.go @@ -13,9 +13,10 @@ import ( ) // keep in sync with -// $GOROOT/src/cmd/compile/internal/gc/reflect.go: MAXKEYSIZE, MAXELEMSIZE -// $GOROOT/src/runtime/map.go: maxKeySize, maxElemSize -// $GOROOT/src/reflect/type.go: maxKeySize, maxElemSize +// +// $GOROOT/src/cmd/compile/internal/gc/reflect.go: MAXKEYSIZE, MAXELEMSIZE +// $GOROOT/src/runtime/map.go: maxKeySize, maxElemSize +// $GOROOT/src/reflect/type.go: maxKeySize, maxElemSize // // We use these to determine whether the type is stored indirectly in the map or not. const ( @@ -27,9 +28,10 @@ func unsafeGrowslice(typ unsafe.Pointer, old unsafeSlice, cap, incr int) (v unsa return growslice(typ, old, cap+incr) } -func rvType(rv reflect.Value) reflect.Type { - return rvPtrToType(((*unsafeReflectValue)(unsafe.Pointer(&rv))).typ) // rv.Type() -} +// func rvType(rv reflect.Value) reflect.Type { +// return rvPtrToType(((*unsafeReflectValue)(unsafe.Pointer(&rv))).typ) +// // return rv.Type() +// } // mapStoresElemIndirect tells if the element type is stored indirectly in the map. // @@ -130,13 +132,9 @@ func mapGet(m, k, v reflect.Value, keyFastKind mapKeyFastKind, valIsIndirect, va //go:linkname unsafeZeroArr runtime.zeroVal var unsafeZeroArr [1024]byte -//go:linkname rvPtrToType reflect.toType -//go:noescape -func rvPtrToType(typ unsafe.Pointer) reflect.Type - -//go:linkname growslice runtime.growslice -//go:noescape -func growslice(typ unsafe.Pointer, old unsafeSlice, cap int) unsafeSlice +// //go:linkname rvPtrToType reflect.toType +// //go:noescape +// func rvPtrToType(typ unsafe.Pointer) reflect.Type //go:linkname mapassign_fast32 runtime.mapassign_fast32 //go:noescape diff --git a/vendor/github.com/ugorji/go/codec/json.go b/vendor/github.com/ugorji/go/codec/json.go index 8bd151f90..f7d2343e5 100644 --- a/vendor/github.com/ugorji/go/codec/json.go +++ b/vendor/github.com/ugorji/go/codec/json.go @@ -17,7 +17,6 @@ package codec // We cannot use strconv.(Q|Unq)uote because json quotes/unquotes differently. import ( - "bytes" "encoding/base64" "math" "reflect" @@ -30,35 +29,34 @@ import ( //-------------------------------- -var jsonLiterals = [...]byte{ - '"', 't', 'r', 'u', 'e', '"', - '"', 'f', 'a', 'l', 's', 'e', '"', - '"', 'n', 'u', 'l', 'l', '"', -} +// jsonLits and jsonLitb are defined at the package level, +// so they are guaranteed to be stored efficiently, making +// for better append/string comparison/etc. +// +// (anecdotal evidence from some benchmarking on go 1.20 devel in 20220104) +const jsonLits = `"true"false"null"` + +var jsonLitb = []byte(jsonLits) const ( - jsonLitTrueQ = 0 - jsonLitTrue = 1 - jsonLitFalseQ = 6 - jsonLitFalse = 7 - jsonLitNullQ = 13 - jsonLitNull = 14 + jsonLitT = 1 + jsonLitF = 6 + jsonLitN = 12 ) -var ( - // jsonLiteralTrueQ = jsonLiterals[jsonLitTrueQ : jsonLitTrueQ+6] - // jsonLiteralFalseQ = jsonLiterals[jsonLitFalseQ : jsonLitFalseQ+7] - // jsonLiteralNullQ = jsonLiterals[jsonLitNullQ : jsonLitNullQ+6] - - jsonLiteralTrue = jsonLiterals[jsonLitTrue : jsonLitTrue+4] - jsonLiteralFalse = jsonLiterals[jsonLitFalse : jsonLitFalse+5] - jsonLiteralNull = jsonLiterals[jsonLitNull : jsonLitNull+4] - - // these are used, after consuming the first char - jsonLiteral4True = jsonLiterals[jsonLitTrue+1 : jsonLitTrue+4] - jsonLiteral4False = jsonLiterals[jsonLitFalse+1 : jsonLitFalse+5] - jsonLiteral4Null = jsonLiterals[jsonLitNull+1 : jsonLitNull+4] -) +const jsonEncodeUintSmallsString = "" + + "00010203040506070809" + + "10111213141516171819" + + "20212223242526272829" + + "30313233343536373839" + + "40414243444546474849" + + "50515253545556575859" + + "60616263646566676869" + + "70717273747576777879" + + "80818283848586878889" + + "90919293949596979899" + +var jsonEncodeUintSmallsStringBytes = []byte(jsonEncodeUintSmallsString) const ( jsonU4Chk2 = '0' @@ -82,6 +80,11 @@ const ( // Both technically valid JSON, but bomb on JSONP, so fix here unconditionally. jsonEscapeMultiByteUnicodeSep = true + // jsonRecognizeBoolNullInQuotedStr is used during decoding into a blank interface{} + // to control whether we detect quoted values of bools and null where a map key is expected, + // and treat as nil, true or false. + jsonNakedBoolNullInQuotedStr = true + // jsonManualInlineDecRdInHotZones controls whether we manually inline some decReader calls. // // encode performance is at par with libraries that just iterate over bytes directly, @@ -186,7 +189,7 @@ type jsonEncDriver struct { // -xxx.yyyyyyyyyyyye-zzz // Consequently, 35 characters should be sufficient for encoding time, integers or floats. // We use up all the remaining bytes to make this use full cache lines. - b [56]byte + b [48]byte e Encoder } @@ -240,11 +243,9 @@ func (e *jsonEncDriver) WriteMapElemValue() { func (e *jsonEncDriver) EncodeNil() { // We always encode nil as just null (never in quotes) - // This allows us to easily decode if a nil in the json stream - // ie if initial token is n. + // so we can easily decode if a nil in the json stream ie if initial token is n. - // e.e.encWr.writeb(jsonLiteralNull) - e.e.encWr.writen4([4]byte{'n', 'u', 'l', 'l'}) + e.e.encWr.writestr(jsonLits[jsonLitN : jsonLitN+4]) } func (e *jsonEncDriver) EncodeTime(t time.Time) { @@ -280,30 +281,32 @@ func (e *jsonEncDriver) EncodeRawExt(re *RawExt) { } } -func (e *jsonEncDriver) EncodeBool(b bool) { - // Use writen with an array instead of writeb with a slice - // i.e. in place of e.e.encWr.writeb(jsonLiteralTrueQ) - // OR jsonLiteralTrue, jsonLiteralFalse, jsonLiteralFalseQ, etc - - if e.ks && e.e.c == containerMapKey { - if b { - e.e.encWr.writen4([4]byte{'"', 't', 'r', 'u'}) - e.e.encWr.writen2('e', '"') - } else { - e.e.encWr.writen4([4]byte{'"', 'f', 'a', 'l'}) - e.e.encWr.writen2('s', 'e') - e.e.encWr.writen1('"') - } - } else { - if b { - e.e.encWr.writen4([4]byte{'t', 'r', 'u', 'e'}) - } else { - e.e.encWr.writen4([4]byte{'f', 'a', 'l', 's'}) - e.e.encWr.writen1('e') - } - } +var jsonEncBoolStrs = [2][2]string{ + {jsonLits[jsonLitF : jsonLitF+5], jsonLits[jsonLitT : jsonLitT+4]}, + {jsonLits[jsonLitF-1 : jsonLitF+6], jsonLits[jsonLitT-1 : jsonLitT+5]}, } +func (e *jsonEncDriver) EncodeBool(b bool) { + e.e.encWr.writestr( + jsonEncBoolStrs[bool2int(e.ks && e.e.c == containerMapKey)%2][bool2int(b)%2]) +} + +// func (e *jsonEncDriver) EncodeBool(b bool) { +// if e.ks && e.e.c == containerMapKey { +// if b { +// e.e.encWr.writestr(jsonLits[jsonLitT-1 : jsonLitT+5]) +// } else { +// e.e.encWr.writestr(jsonLits[jsonLitF-1 : jsonLitF+6]) +// } +// } else { +// if b { +// e.e.encWr.writestr(jsonLits[jsonLitT : jsonLitT+4]) +// } else { +// e.e.encWr.writestr(jsonLits[jsonLitF : jsonLitF+5]) +// } +// } +// } + func (e *jsonEncDriver) encodeFloat(f float64, bitsize, fmt byte, prec int8) { var blen uint if e.ks && e.e.c == containerMapKey { @@ -339,25 +342,18 @@ func (e *jsonEncDriver) encodeUint(neg bool, quotes bool, u uint64) { // copied mostly from std library: strconv // this should only be called on 64bit OS. - const smallsString = "00010203040506070809" + - "10111213141516171819" + - "20212223242526272829" + - "30313233343536373839" + - "40414243444546474849" + - "50515253545556575859" + - "60616263646566676869" + - "70717273747576777879" + - "80818283848586878889" + - "90919293949596979899" + // const smallsString = jsonEncodeUintSmallsString + var ss = jsonEncodeUintSmallsStringBytes // typically, 19 or 20 bytes sufficient for decimal encoding a uint64 // var a [24]byte var a = e.b[0:24] - var i = uint8(len(a)) + var i = uint(len(a)) if quotes { i-- - a[i] = '"' + setByteAt(a, i, '"') + // a[i] = '"' } // u guaranteed to fit into a uint (as we are not 32bit OS) var is uint @@ -366,25 +362,31 @@ func (e *jsonEncDriver) encodeUint(neg bool, quotes bool, u uint64) { is = us % 100 * 2 us /= 100 i -= 2 - a[i+1] = smallsString[is+1] - a[i+0] = smallsString[is+0] + setByteAt(a, i+1, byteAt(ss, is+1)) + setByteAt(a, i, byteAt(ss, is)) + // a[i+1] = smallsString[is+1] + // a[i+0] = smallsString[is+0] } // us < 100 is = us * 2 i-- - a[i] = smallsString[is+1] + setByteAt(a, i, byteAt(ss, is+1)) + // a[i] = smallsString[is+1] if us >= 10 { i-- - a[i] = smallsString[is] + setByteAt(a, i, byteAt(ss, is)) + // a[i] = smallsString[is] } if neg { i-- - a[i] = '-' + setByteAt(a, i, '-') + // a[i] = '-' } if quotes { i-- - a[i] = '"' + setByteAt(a, i, '"') + // a[i] = '"' } e.e.encWr.writeb(a[i:]) } @@ -413,7 +415,8 @@ func (e *jsonEncDriver) EncodeInt(v int64) { } func (e *jsonEncDriver) EncodeUint(v uint64) { - quotes := e.is == 'A' || e.is == 'L' && v > 1<<53 || (e.ks && e.e.c == containerMapKey) + quotes := e.is == 'A' || e.is == 'L' && v > 1<<53 || + (e.ks && e.e.c == containerMapKey) if cpu32Bit { // use strconv directly, as optimized encodeUint only works on 64-bit alone @@ -461,11 +464,12 @@ func (e *jsonEncDriver) EncodeStringBytesRaw(v []byte) { // bs := e.e.blist.check(*e.buf, n)[:slen] // *e.buf = bs - bs := e.e.blist.peek(slen, false)[:slen] + bs := e.e.blist.peek(slen, false) + bs = bs[:slen] - bs[0] = '"' base64.StdEncoding.Encode(bs[1:], v) bs[len(bs)-1] = '"' + bs[0] = '"' e.e.encWr.writeb(bs) } @@ -632,7 +636,7 @@ func (d *jsonDecDriver) decoder() *Decoder { func (d *jsonDecDriver) ReadMapStart() int { d.advance() if d.tok == 'n' { - d.readLit4Null(d.d.decRd.readn3()) + d.checkLit3([3]byte{'u', 'l', 'l'}, d.d.decRd.readn3()) return containerLenNil } if d.tok != '{' { @@ -645,7 +649,7 @@ func (d *jsonDecDriver) ReadMapStart() int { func (d *jsonDecDriver) ReadArrayStart() int { d.advance() if d.tok == 'n' { - d.readLit4Null(d.d.decRd.readn3()) + d.checkLit3([3]byte{'u', 'l', 'l'}, d.d.decRd.readn3()) return containerLenNil } if d.tok != '[' { @@ -655,6 +659,12 @@ func (d *jsonDecDriver) ReadArrayStart() int { return containerLenUnknown } +// MARKER: +// We attempted making sure CheckBreak can be inlined, by moving the skipWhitespace +// call to an explicit (noinline) function call. +// However, this forces CheckBreak to always incur a function call if there was whitespace, +// with no clear benefit. + func (d *jsonDecDriver) CheckBreak() bool { d.advance() return d.tok == '}' || d.tok == ']' @@ -713,40 +723,31 @@ func (d *jsonDecDriver) readDelimError(xc uint8) { d.d.errorf("read json delimiter - expect char '%c' but got char '%c'", xc, d.tok) } -// MARKER: readLit4XXX takes the readn(3|4) as a parameter so they can be inlined. +// MARKER: checkLit takes the readn(3|4) result as a parameter so they can be inlined. // We pass the array directly to errorf, as passing slice pushes past inlining threshold, // and passing slice also might cause allocation of the bs array on the heap. -func (d *jsonDecDriver) readLit4True(bs [4]byte) { - // bs := d.d.decRd.readn3() +func (d *jsonDecDriver) checkLit3(got, expect [3]byte) { d.tok = 0 - if jsonValidateSymbols && bs != [...]byte{0, 'r', 'u', 'e'} { // !Equal jsonLiteral4True - // d.d.errorf("expecting %s: got %s", jsonLiteral4True, bs[:]) - d.d.errorf("expecting true: got t%s", bs) + if jsonValidateSymbols && got != expect { + d.d.errorf("expecting %s: got %s", expect, got) } } -func (d *jsonDecDriver) readLit4False(bs [4]byte) { - // bs := d.d.decRd.readn4() +func (d *jsonDecDriver) checkLit4(got, expect [4]byte) { d.tok = 0 - if jsonValidateSymbols && bs != [4]byte{'a', 'l', 's', 'e'} { // !Equal jsonLiteral4False - // d.d.errorf("expecting %s: got %s", jsonLiteral4False, bs) - d.d.errorf("expecting false: got f%s", bs) + if jsonValidateSymbols && got != expect { + d.d.errorf("expecting %s: got %s", expect, got) } } -func (d *jsonDecDriver) readLit4Null(bs [4]byte) { - // bs := d.d.decRd.readn3() // readx(3) - d.tok = 0 - if jsonValidateSymbols && bs != [...]byte{0, 'u', 'l', 'l'} { // !Equal jsonLiteral4Null - // d.d.errorf("expecting %s: got %s", jsonLiteral4Null, bs[:]) - d.d.errorf("expecting null: got n%s", bs) - } +func (d *jsonDecDriver) skipWhitespace() { + d.tok = d.d.decRd.skipWhitespace() } func (d *jsonDecDriver) advance() { if d.tok == 0 { - d.tok = d.d.decRd.skipWhitespace() // skip(&whitespaceCharBitset) + d.skipWhitespace() } } @@ -779,14 +780,14 @@ func (d *jsonDecDriver) nextValueBytesR(v0 []byte) (v []byte, cursor uint) { default: h.appendN(&v, dr.jsonReadNum()...) case 'n': - d.readLit4Null(d.d.decRd.readn3()) - h.appendN(&v, jsonLiteralNull...) + d.checkLit3([3]byte{'u', 'l', 'l'}, d.d.decRd.readn3()) + h.appendS(&v, jsonLits[jsonLitN:jsonLitN+4]) case 'f': - d.readLit4False(d.d.decRd.readn4()) - h.appendN(&v, jsonLiteralFalse...) + d.checkLit4([4]byte{'a', 'l', 's', 'e'}, d.d.decRd.readn4()) + h.appendS(&v, jsonLits[jsonLitF:jsonLitF+5]) case 't': - d.readLit4True(d.d.decRd.readn3()) - h.appendN(&v, jsonLiteralTrue...) + d.checkLit3([3]byte{'r', 'u', 'e'}, d.d.decRd.readn3()) + h.appendS(&v, jsonLits[jsonLitT:jsonLitT+4]) case '"': h.append1(&v, '"') consumeString() @@ -820,7 +821,7 @@ func (d *jsonDecDriver) TryNil() bool { // we shouldn't try to see if quoted "null" was here, right? // only the plain string: `null` denotes a nil (ie not quotes) if d.tok == 'n' { - d.readLit4Null(d.d.decRd.readn3()) + d.checkLit3([3]byte{'u', 'l', 'l'}, d.d.decRd.readn3()) return true } return false @@ -828,21 +829,21 @@ func (d *jsonDecDriver) TryNil() bool { func (d *jsonDecDriver) DecodeBool() (v bool) { d.advance() - if d.tok == 'n' { - d.readLit4Null(d.d.decRd.readn3()) - return - } + // bool can be in quotes if and only if it's a map key fquot := d.d.c == containerMapKey && d.tok == '"' if fquot { d.tok = d.d.decRd.readn1() } switch d.tok { case 'f': - d.readLit4False(d.d.decRd.readn4()) + d.checkLit4([4]byte{'a', 'l', 's', 'e'}, d.d.decRd.readn4()) // v = false case 't': - d.readLit4True(d.d.decRd.readn3()) + d.checkLit3([3]byte{'r', 'u', 'e'}, d.d.decRd.readn3()) v = true + case 'n': + d.checkLit3([3]byte{'u', 'l', 'l'}, d.d.decRd.readn3()) + // v = false default: d.d.errorf("decode bool: got first char %c", d.tok) // v = false // "unreachable" @@ -857,7 +858,7 @@ func (d *jsonDecDriver) DecodeTime() (t time.Time) { // read string, and pass the string into json.unmarshal d.advance() if d.tok == 'n' { - d.readLit4Null(d.d.decRd.readn3()) + d.checkLit3([3]byte{'u', 'l', 'l'}, d.d.decRd.readn3()) return } d.ensureReadingString() @@ -881,7 +882,7 @@ func (d *jsonDecDriver) ContainerType() (vt valueType) { } else if d.tok == '[' { return valueTypeArray } else if d.tok == 'n' { - d.readLit4Null(d.d.decRd.readn3()) + d.checkLit3([3]byte{'u', 'l', 'l'}, d.d.decRd.readn3()) return valueTypeNil } else if d.tok == '"' { return valueTypeString @@ -895,13 +896,11 @@ func (d *jsonDecDriver) decNumBytes() (bs []byte) { if d.tok == '"' { bs = dr.readUntil('"') } else if d.tok == 'n' { - d.readLit4Null(d.d.decRd.readn3()) + d.checkLit3([3]byte{'u', 'l', 'l'}, dr.readn3()) } else { if jsonManualInlineDecRdInHotZones { if dr.bytes { bs = dr.rb.jsonReadNum() - } else if dr.bufio { - bs = dr.bi.jsonReadNum() } else { bs = dr.ri.jsonReadNum() } @@ -967,7 +966,7 @@ func (d *jsonDecDriver) DecodeFloat32() (f float32) { func (d *jsonDecDriver) DecodeExt(rv interface{}, basetype reflect.Type, xtag uint64, ext Ext) { d.advance() if d.tok == 'n' { - d.readLit4Null(d.d.decRd.readn3()) + d.checkLit3([3]byte{'u', 'l', 'l'}, d.d.decRd.readn3()) return } if ext == nil { @@ -982,9 +981,7 @@ func (d *jsonDecDriver) DecodeExt(rv interface{}, basetype reflect.Type, xtag ui } func (d *jsonDecDriver) decBytesFromArray(bs []byte) []byte { - if bs == nil { - bs = []byte{} - } else { + if bs != nil { bs = bs[:0] } d.tok = 0 @@ -1006,7 +1003,7 @@ func (d *jsonDecDriver) DecodeBytes(bs []byte) (bsOut []byte) { d.d.decByteState = decByteStateNone d.advance() if d.tok == 'n' { - d.readLit4Null(d.d.decRd.readn3()) + d.checkLit3([3]byte{'u', 'l', 'l'}, d.d.decRd.readn3()) return nil } // if decoding into raw bytes, and the RawBytesExt is configured, use it to decode. @@ -1037,7 +1034,8 @@ func (d *jsonDecDriver) DecodeBytes(bs []byte) (bsOut []byte) { bsOut = bs[:slen] } else if bs == nil { d.d.decByteState = decByteStateReuseBuf - bsOut = d.d.blist.check(*d.buf, slen)[:slen] + bsOut = d.d.blist.check(*d.buf, slen) + bsOut = bsOut[:slen] *d.buf = bsOut } else { bsOut = make([]byte, slen) @@ -1056,7 +1054,7 @@ func (d *jsonDecDriver) DecodeStringAsBytes() (s []byte) { d.d.decByteState = decByteStateNone d.advance() - // common case + // common case - hoist outside the switch statement if d.tok == '"' { return d.dblQuoteStringAsBytes() } @@ -1064,19 +1062,19 @@ func (d *jsonDecDriver) DecodeStringAsBytes() (s []byte) { // handle non-string scalar: null, true, false or a number switch d.tok { case 'n': - d.readLit4Null(d.d.decRd.readn3()) + d.checkLit3([3]byte{'u', 'l', 'l'}, d.d.decRd.readn3()) return nil // []byte{} case 'f': - d.readLit4False(d.d.decRd.readn4()) - return jsonLiteralFalse + d.checkLit4([4]byte{'a', 'l', 's', 'e'}, d.d.decRd.readn4()) + return jsonLitb[jsonLitF : jsonLitF+5] case 't': - d.readLit4True(d.d.decRd.readn3()) - return jsonLiteralTrue + d.checkLit3([3]byte{'r', 'u', 'e'}, d.d.decRd.readn3()) + return jsonLitb[jsonLitT : jsonLitT+4] + default: + // try to parse a valid number + d.tok = 0 + return d.d.decRd.jsonReadNum() } - - // try to parse a valid number - d.tok = 0 - return d.d.decRd.jsonReadNum() } func (d *jsonDecDriver) ensureReadingString() { @@ -1093,6 +1091,7 @@ func (d *jsonDecDriver) readUnescapedString() (bs []byte) { } func (d *jsonDecDriver) dblQuoteStringAsBytes() (buf []byte) { + checkUtf8 := d.h.ValidateUnicode d.d.decByteState = decByteStateNone // use a local buf variable, so we don't do pointer chasing within loop buf = (*d.buf)[:0] @@ -1119,8 +1118,6 @@ func (d *jsonDecDriver) dblQuoteStringAsBytes() (buf []byte) { if jsonManualInlineDecRdInHotZones { if dr.bytes { bs = dr.rb.jsonReadAsisChars() - } else if dr.bufio { - bs = dr.bi.jsonReadAsisChars() } else { bs = dr.ri.jsonReadAsisChars() } @@ -1129,6 +1126,7 @@ func (d *jsonDecDriver) dblQuoteStringAsBytes() (buf []byte) { } APPEND: + _ = bs[0] // bounds check hint - slice must be > 0 elements buf = append(buf, bs[:len(bs)-1]...) c = bs[len(bs)-1] @@ -1153,7 +1151,11 @@ func (d *jsonDecDriver) dblQuoteStringAsBytes() (buf []byte) { case 't': buf = append(buf, '\t') case 'u': - buf = append(buf, d.bstr[:utf8.EncodeRune(d.bstr[:], d.appendStringAsBytesSlashU())]...) + rr := d.appendStringAsBytesSlashU() + if checkUtf8 && rr == unicode.ReplacementChar { + d.d.errorf("invalid UTF-8 character found after: %s", buf) + } + buf = append(buf, d.bstr[:utf8.EncodeRune(d.bstr[:], rr)]...) default: *d.buf = buf d.d.errorf("unsupported escaped value: %c", c) @@ -1221,14 +1223,14 @@ func (d *jsonDecDriver) DecodeNaked() { var bs []byte switch d.tok { case 'n': - d.readLit4Null(d.d.decRd.readn3()) + d.checkLit3([3]byte{'u', 'l', 'l'}, d.d.decRd.readn3()) z.v = valueTypeNil case 'f': - d.readLit4False(d.d.decRd.readn4()) + d.checkLit4([4]byte{'a', 'l', 's', 'e'}, d.d.decRd.readn4()) z.v = valueTypeBool z.b = false case 't': - d.readLit4True(d.d.decRd.readn3()) + d.checkLit3([3]byte{'r', 'u', 'e'}, d.d.decRd.readn3()) z.v = valueTypeBool z.b = true case '{': @@ -1236,18 +1238,20 @@ func (d *jsonDecDriver) DecodeNaked() { case '[': z.v = valueTypeArray // don't consume. kInterfaceNaked will call ReadArrayStart case '"': - // if a string, and MapKeyAsString, then try to decode it as a nil, bool or number first + // if a string, and MapKeyAsString, then try to decode it as a bool or number first bs = d.dblQuoteStringAsBytes() - if len(bs) > 0 && d.d.c == containerMapKey && d.h.MapKeyAsString { - if bytes.Equal(bs, jsonLiteralNull) { - z.v = valueTypeNil - } else if bytes.Equal(bs, jsonLiteralTrue) { + if jsonNakedBoolNullInQuotedStr && + d.h.MapKeyAsString && len(bs) > 0 && d.d.c == containerMapKey { + switch string(bs) { + // case "null": // nil is never quoted + // z.v = valueTypeNil + case "true": z.v = valueTypeBool z.b = true - } else if bytes.Equal(bs, jsonLiteralFalse) { + case "false": z.v = valueTypeBool z.b = false - } else { + default: // check if a number: float, int or uint if err := d.nakedNum(z, bs); err != nil { z.v = valueTypeString @@ -1275,13 +1279,13 @@ func (d *jsonDecDriver) DecodeNaked() { // JsonHandle is a handle for JSON encoding format. // // Json is comprehensively supported: -// - decodes numbers into interface{} as int, uint or float64 -// based on how the number looks and some config parameters e.g. PreferFloat, SignedInt, etc. -// - decode integers from float formatted numbers e.g. 1.27e+8 -// - decode any json value (numbers, bool, etc) from quoted strings -// - configurable way to encode/decode []byte . -// by default, encodes and decodes []byte using base64 Std Encoding -// - UTF-8 support for encoding and decoding +// - decodes numbers into interface{} as int, uint or float64 +// based on how the number looks and some config parameters e.g. PreferFloat, SignedInt, etc. +// - decode integers from float formatted numbers e.g. 1.27e+8 +// - decode any json value (numbers, bool, etc) from quoted strings +// - configurable way to encode/decode []byte . +// by default, encodes and decodes []byte using base64 Std Encoding +// - UTF-8 support for encoding and decoding // // It has better performance than the json library in the standard library, // by leveraging the performance improvements of the codec library. @@ -1453,5 +1457,4 @@ func jsonFloatStrconvFmtPrec32(f float32) (fmt byte, prec int8) { var _ decDriverContainerTracker = (*jsonDecDriver)(nil) var _ encDriverContainerTracker = (*jsonEncDriver)(nil) var _ decDriver = (*jsonDecDriver)(nil) - var _ encDriver = (*jsonEncDriver)(nil) diff --git a/vendor/github.com/ugorji/go/codec/msgpack.go b/vendor/github.com/ugorji/go/codec/msgpack.go index dc25530e7..c8b539d4e 100644 --- a/vendor/github.com/ugorji/go/codec/msgpack.go +++ b/vendor/github.com/ugorji/go/codec/msgpack.go @@ -24,6 +24,7 @@ import ( "net/rpc" "reflect" "time" + "unicode/utf8" ) const ( @@ -872,7 +873,11 @@ func (d *msgpackDecDriver) DecodeBytes(bs []byte) (bsOut []byte) { } func (d *msgpackDecDriver) DecodeStringAsBytes() (s []byte) { - return d.DecodeBytes(nil) + s = d.DecodeBytes(nil) + if d.h.ValidateUnicode && !utf8.Valid(s) { + d.d.errorf("DecodeStringAsBytes: invalid UTF-8: %s", s) + } + return } func (d *msgpackDecDriver) descBd() string { @@ -1071,7 +1076,7 @@ func (d *msgpackDecDriver) decodeExtV(verifyTag bool, tag byte) (xbs []byte, xta //-------------------------------------------------- -//MsgpackHandle is a Handle for the Msgpack Schema-Free Encoding Format. +// MsgpackHandle is a Handle for the Msgpack Schema-Free Encoding Format. type MsgpackHandle struct { binaryEncodingType BasicHandle diff --git a/vendor/github.com/ugorji/go/codec/reader.go b/vendor/github.com/ugorji/go/codec/reader.go index a683d9a2a..3fea9f4c7 100644 --- a/vendor/github.com/ugorji/go/codec/reader.go +++ b/vendor/github.com/ugorji/go/codec/reader.go @@ -3,7 +3,12 @@ package codec -import "io" +import ( + "bufio" + "bytes" + "io" + "strings" +) // decReader abstracts the reading source, allowing implementations that can // read from an io.Reader or directly off a byte slice with zero-copying. @@ -17,8 +22,7 @@ type decReader interface { readn1() byte readn2() [2]byte - // readn3 will read 3 bytes into the top-most elements of a 4-byte array - readn3() [4]byte + readn3() [3]byte readn4() [4]byte readn8() [8]byte // readn1eof() (v uint8, eof bool) @@ -62,55 +66,57 @@ const ( unreadByteCanUnread ) +// const defBufReaderSize = 4096 + // -------------------- -type ioDecReaderCommon struct { - r io.Reader // the reader passed in +// ioReaderByteScanner contains the io.Reader and io.ByteScanner interfaces +type ioReaderByteScanner interface { + io.Reader + io.ByteScanner + // ReadByte() (byte, error) + // UnreadByte() error + // Read(p []byte) (n int, err error) +} - n uint // num read +// ioReaderByteScannerT does a simple wrapper of a io.ByteScanner +// over a io.Reader +type ioReaderByteScannerT struct { + r io.Reader l byte // last byte ls unreadByteStatus // last byte status - b [6]byte // tiny buffer for reading single bytes - - blist *bytesFreelist - - bufr []byte // buffer for readTo/readUntil + _ [2]byte // padding + b [4]byte // tiny buffer for reading single bytes } -func (z *ioDecReaderCommon) reset(r io.Reader, blist *bytesFreelist) { - z.blist = blist - z.r = r - z.ls = unreadByteUndefined - z.l, z.n = 0, 0 - z.bufr = z.blist.check(z.bufr, 256) -} - -func (z *ioDecReaderCommon) numread() uint { - return z.n -} - -// ------------------------------------------ - -// ioDecReader is a decReader that reads off an io.Reader. -// -// It also has a fallback implementation of ByteScanner if needed. -type ioDecReader struct { - ioDecReaderCommon - - br io.ByteScanner - - x [64 + 48]byte // for: get struct field name, swallow valueTypeBytes, etc +func (z *ioReaderByteScannerT) ReadByte() (c byte, err error) { + if z.ls == unreadByteCanRead { + z.ls = unreadByteCanUnread + c = z.l + } else { + _, err = z.Read(z.b[:1]) + c = z.b[0] + } + return } -func (z *ioDecReader) reset(r io.Reader, blist *bytesFreelist) { - z.ioDecReaderCommon.reset(r, blist) - - z.br, _ = r.(io.ByteScanner) +func (z *ioReaderByteScannerT) UnreadByte() (err error) { + switch z.ls { + case unreadByteCanUnread: + z.ls = unreadByteCanRead + case unreadByteCanRead: + err = errDecUnreadByteLastByteNotRead + case unreadByteUndefined: + err = errDecUnreadByteNothingToRead + default: + err = errDecUnreadByteUnknown + } + return } -func (z *ioDecReader) Read(p []byte) (n int, err error) { +func (z *ioReaderByteScannerT) Read(p []byte) (n int, err error) { if len(p) == 0 { return } @@ -139,45 +145,79 @@ func (z *ioDecReader) Read(p []byte) (n int, err error) { return } -func (z *ioDecReader) ReadByte() (c byte, err error) { - if z.br != nil { - c, err = z.br.ReadByte() - if err == nil { - z.l = c - z.ls = unreadByteCanUnread +func (z *ioReaderByteScannerT) reset(r io.Reader) { + z.r = r + z.ls = unreadByteUndefined + z.l = 0 +} + +// ioDecReader is a decReader that reads off an io.Reader. +type ioDecReader struct { + rr ioReaderByteScannerT // the reader passed in, wrapped into a reader+bytescanner + + n uint // num read + + blist *bytesFreelist + + bufr []byte // buffer for readTo/readUntil + br ioReaderByteScanner // main reader used for Read|ReadByte|UnreadByte + bb *bufio.Reader // created internally, and reused on reset if needed + + x [64 + 40]byte // for: get struct field name, swallow valueTypeBytes, etc +} + +func (z *ioDecReader) reset(r io.Reader, bufsize int, blist *bytesFreelist) { + z.blist = blist + z.n = 0 + z.bufr = z.blist.check(z.bufr, 256) + z.br = nil + + var ok bool + + if bufsize <= 0 { + z.br, ok = r.(ioReaderByteScanner) + if !ok { + z.rr.reset(r) + z.br = &z.rr } return } - n, err := z.Read(z.b[:1]) - if n == 1 { - c = z.b[0] - if err == io.EOF { - err = nil // read was successful, so postpone EOF (till next time) + // bufsize > 0 ... + + // if bytes.[Buffer|Reader], no value in adding extra buffer + // if bufio.Reader, no value in extra buffer unless size changes + switch bb := r.(type) { + case *strings.Reader: + z.br = bb + case *bytes.Buffer: + z.br = bb + case *bytes.Reader: + z.br = bb + case *bufio.Reader: + if bb.Size() == bufsize { + z.br = bb } } - return -} -func (z *ioDecReader) UnreadByte() (err error) { - if z.br != nil { - err = z.br.UnreadByte() - if err == nil { - z.ls = unreadByteCanRead + if z.br == nil { + if z.bb != nil && z.bb.Size() == bufsize { + z.bb.Reset(r) + } else { + z.bb = bufio.NewReaderSize(r, bufsize) } - return + z.br = z.bb } +} - switch z.ls { - case unreadByteCanUnread: - z.ls = unreadByteCanRead - case unreadByteCanRead: - err = errDecUnreadByteLastByteNotRead - case unreadByteUndefined: - err = errDecUnreadByteNothingToRead - default: - err = errDecUnreadByteUnknown - } +func (z *ioDecReader) numread() uint { + return z.n +} + +func (z *ioDecReader) readn1() (b uint8) { + b, err := z.br.ReadByte() + halt.onerror(err) + z.n++ return } @@ -186,8 +226,8 @@ func (z *ioDecReader) readn2() (bs [2]byte) { return } -func (z *ioDecReader) readn3() (bs [4]byte) { - z.readb(bs[1:]) +func (z *ioDecReader) readn3() (bs [3]byte) { + z.readb(bs[:]) return } @@ -203,16 +243,16 @@ func (z *ioDecReader) readn8() (bs [8]byte) { func (z *ioDecReader) readx(n uint) (bs []byte) { if n == 0 { - return + return zeroByteSlice } if n < uint(len(z.x)) { bs = z.x[:n] } else { bs = make([]byte, n) } - _, err := readFull(z.r, bs) + nn, err := readFull(z.br, bs) + z.n += nn halt.onerror(err) - z.n += uint(len(bs)) return } @@ -220,38 +260,36 @@ func (z *ioDecReader) readb(bs []byte) { if len(bs) == 0 { return } - _, err := readFull(z.r, bs) + nn, err := readFull(z.br, bs) + z.n += nn halt.onerror(err) - z.n += uint(len(bs)) } -func (z *ioDecReader) readn1() (b uint8) { - b, err := z.ReadByte() - halt.onerror(err) - z.n++ - return -} - -func (z *ioDecReader) readn1eof() (b uint8, eof bool) { - b, err := z.ReadByte() - if err == nil { - z.n++ - } else if err == io.EOF { - eof = true - } else { - halt.onerror(err) - } - return -} +// func (z *ioDecReader) readn1eof() (b uint8, eof bool) { +// b, err := z.br.ReadByte() +// if err == nil { +// z.n++ +// } else if err == io.EOF { +// eof = true +// } else { +// halt.onerror(err) +// } +// return +// } func (z *ioDecReader) jsonReadNum() (bs []byte) { z.unreadn1() z.bufr = z.bufr[:0] LOOP: - i, eof := z.readn1eof() - if eof { + // i, eof := z.readn1eof() + i, err := z.br.ReadByte() + if err == io.EOF { return z.bufr } + if err != nil { + halt.onerror(err) + } + z.n++ if isNumberChar(i) { z.bufr = append(z.bufr, i) goto LOOP @@ -280,307 +318,45 @@ LOOP: return } +// func (z *ioDecReader) readUntil(stop byte) []byte { +// z.bufr = z.bufr[:0] +// LOOP: +// token := z.readn1() +// z.bufr = append(z.bufr, token) +// if token == stop { +// return z.bufr[:len(z.bufr)-1] +// } +// goto LOOP +// } + func (z *ioDecReader) readUntil(stop byte) []byte { z.bufr = z.bufr[:0] LOOP: token := z.readn1() - z.bufr = append(z.bufr, token) if token == stop { - return z.bufr[:len(z.bufr)-1] + return z.bufr } + z.bufr = append(z.bufr, token) goto LOOP } func (z *ioDecReader) unreadn1() { - err := z.UnreadByte() + err := z.br.UnreadByte() halt.onerror(err) z.n-- } // ------------------------------------ -type bufioDecReader struct { - ioDecReaderCommon - - c uint // cursor - buf []byte -} - -func (z *bufioDecReader) reset(r io.Reader, bufsize int, blist *bytesFreelist) { - z.ioDecReaderCommon.reset(r, blist) - z.c = 0 - if cap(z.buf) < bufsize { - z.buf = blist.get(bufsize) - } else { - z.buf = z.buf[:0] - } -} - -func (z *bufioDecReader) readb(p []byte) { - var n = uint(copy(p, z.buf[z.c:])) - z.n += n - z.c += n - if len(p) != int(n) { - z.readbFill(p, n, true, false) - } -} - -func readbFillHandleErr(err error, must, eof bool) (isEOF bool) { - if err == io.EOF { - isEOF = true - } - if must && !(eof && isEOF) { - halt.onerror(err) - } - return -} - -func (z *bufioDecReader) readbFill(p0 []byte, n uint, must, eof bool) (isEOF bool, err error) { - // at this point, there's nothing in z.buf to read (z.buf is fully consumed) - var p []byte - if p0 != nil { - p = p0[n:] - } - var n2 uint - if len(p) > cap(z.buf) { - n2, err = readFull(z.r, p) - if err != nil { - isEOF = readbFillHandleErr(err, must, eof) - return - } - n += n2 - z.n += n2 - // always keep last byte in z.buf - z.buf = z.buf[:1] - z.buf[0] = p[len(p)-1] - z.c = 1 - return - } - // z.c is now 0, and len(p) <= cap(z.buf) - var n1 int -LOOP: - // for len(p) > 0 && z.err == nil { - z.buf = z.buf[0:cap(z.buf)] - n1, err = z.r.Read(z.buf) - n2 = uint(n1) - if n2 == 0 && err != nil { - isEOF = readbFillHandleErr(err, must, eof) - return - } - err = nil - z.buf = z.buf[:n2] - z.c = 0 - if len(p) > 0 { - n2 = uint(copy(p, z.buf)) - z.c = n2 - n += n2 - z.n += n2 - p = p[n2:] - if len(p) > 0 { - goto LOOP - } - if z.c == 0 { - z.buf = z.buf[:1] - z.buf[0] = p[len(p)-1] - z.c = 1 - } - } - return -} - -func (z *bufioDecReader) readn1() (b byte) { - if z.c >= uint(len(z.buf)) { - z.readbFill(nil, 0, true, false) - } - b = z.buf[z.c] - z.c++ - z.n++ - return -} - -func (z *bufioDecReader) readn1eof() (b byte, eof bool) { - if z.c >= uint(len(z.buf)) { - eof, _ = z.readbFill(nil, 0, true, true) - if eof { - return - } - } - b = z.buf[z.c] - z.c++ - z.n++ - return -} - -func (z *bufioDecReader) unreadn1() { - if z.c == 0 { - halt.onerror(errDecUnreadByteNothingToRead) - } - z.c-- - z.n-- -} - -func (z *bufioDecReader) readn2() (bs [2]byte) { - z.readb(bs[:]) - return -} - -func (z *bufioDecReader) readn3() (bs [4]byte) { - z.readb(bs[1:]) - return -} - -func (z *bufioDecReader) readn4() (bs [4]byte) { - z.readb(bs[:]) - return -} - -func (z *bufioDecReader) readn8() (bs [8]byte) { - z.readb(bs[:]) - return -} - -func (z *bufioDecReader) readx(n uint) (bs []byte) { - if n == 0 { - // return - } else if z.c+n <= uint(len(z.buf)) { - bs = z.buf[z.c : z.c+n] - z.n += n - z.c += n - } else { - bs = make([]byte, n) - // n no longer used - can reuse - n = uint(copy(bs, z.buf[z.c:])) - z.n += n - z.c += n - z.readbFill(bs, n, true, false) - } - return -} - -func (z *bufioDecReader) jsonReadNum() (bs []byte) { - z.unreadn1() - z.bufr = z.bufr[:0] -LOOP: - i, eof := z.readn1eof() - if eof { - return z.bufr - } - if isNumberChar(i) { - z.bufr = append(z.bufr, i) - goto LOOP - } - z.unreadn1() - return z.bufr -} - -func (z *bufioDecReader) jsonReadAsisChars() (bs []byte) { - z.bufr = z.bufr[:0] -LOOP: - i := z.readn1() - z.bufr = append(z.bufr, i) - if i == '"' || i == '\\' { - return z.bufr - } - goto LOOP -} - -func (z *bufioDecReader) skipWhitespace() (token byte) { - i := z.c -LOOP: - if i < uint(len(z.buf)) { - // inline z.skipLoopFn(i) and refactor, so cost is within inline budget - token = z.buf[i] - i++ - if isWhitespaceChar(token) { - goto LOOP - } - z.n += i - 2 - z.c - z.c = i - return - } - return z.skipFillWhitespace() -} - -func (z *bufioDecReader) skipFillWhitespace() (token byte) { - z.n += uint(len(z.buf)) - z.c - var i, n2 int - var err error - for { - z.c = 0 - z.buf = z.buf[0:cap(z.buf)] - n2, err = z.r.Read(z.buf) - if n2 == 0 { - halt.onerror(err) - } - z.buf = z.buf[:n2] - for i, token = range z.buf { - if !isWhitespaceChar(token) { - z.n += (uint(i) - z.c) - 1 - z.loopFn(uint(i + 1)) - return - } - } - z.n += uint(n2) - } -} - -func (z *bufioDecReader) loopFn(i uint) { - z.c = i -} - -func (z *bufioDecReader) readUntil(stop byte) (out []byte) { - i := z.c -LOOP: - if i < uint(len(z.buf)) { - if z.buf[i] == stop { - z.n += (i - z.c) - 1 - i++ - out = z.buf[z.c:i] - z.c = i - goto FINISH - } - i++ - goto LOOP - } - out = z.readUntilFill(stop) -FINISH: - return out[:len(out)-1] -} - -func (z *bufioDecReader) readUntilFill(stop byte) []byte { - z.bufr = z.bufr[:0] - z.n += uint(len(z.buf)) - z.c - z.bufr = append(z.bufr, z.buf[z.c:]...) - for { - z.c = 0 - z.buf = z.buf[0:cap(z.buf)] - n1, err := z.r.Read(z.buf) - if n1 == 0 { - halt.onerror(err) - } - n2 := uint(n1) - z.buf = z.buf[:n2] - for i, token := range z.buf { - if token == stop { - z.n += (uint(i) - z.c) - 1 - z.bufr = append(z.bufr, z.buf[z.c:i+1]...) - z.loopFn(uint(i + 1)) - return z.bufr - } - } - z.bufr = append(z.bufr, z.buf...) - z.n += n2 - } -} - -// ------------------------------------ - // bytesDecReader is a decReader that reads off a byte slice with zero copying // // Note: we do not try to convert index'ing out of bounds to an io.EOF. // instead, we let it bubble up to the exported Encode/Decode method // and recover it as an io.EOF. // +// Every function here MUST defensively check bounds either explicitly +// or via a bounds check. +// // see panicValToErr(...) function in helper.go. type bytesDecReader struct { b []byte // data @@ -601,9 +377,11 @@ func (z *bytesDecReader) numread() uint { // However, we do it only once, and it's better than reslicing both z.b and return value. func (z *bytesDecReader) readx(n uint) (bs []byte) { - x := z.c + n - bs = z.b[z.c:x] - z.c = x + // x := z.c + n + // bs = z.b[z.c:x] + // z.c = x + bs = z.b[z.c : z.c+n] + z.c += n return } @@ -630,23 +408,26 @@ func (z *bytesDecReader) readb(bs []byte) { // return z.b[z.c-1] // } +// MARKER: readn{1,2,3,4,8} should throw an out of bounds error if past length. +// MARKER: readn1: explicitly ensure bounds check is done +// MARKER: readn{2,3,4,8}: ensure you slice z.b completely so we get bounds error if past end. + func (z *bytesDecReader) readn1() (v uint8) { v = z.b[z.c] z.c++ return } -// MARKER: for readn{2,3,4,8}, ensure you slice z.b completely so we get bounds error if past end. - func (z *bytesDecReader) readn2() (bs [2]byte) { // copy(bs[:], z.b[z.c:z.c+2]) - bs[1] = z.b[z.c+1] - bs[0] = z.b[z.c] + // bs[1] = z.b[z.c+1] + // bs[0] = z.b[z.c] + bs = okBytes2(z.b[z.c : z.c+2]) z.c += 2 return } -func (z *bytesDecReader) readn3() (bs [4]byte) { +func (z *bytesDecReader) readn3() (bs [3]byte) { // copy(bs[1:], z.b[z.c:z.c+3]) bs = okBytes3(z.b[z.c : z.c+3]) z.c += 3 @@ -668,14 +449,17 @@ func (z *bytesDecReader) readn8() (bs [8]byte) { } func (z *bytesDecReader) jsonReadNum() []byte { - z.c-- + z.c-- // unread i := z.c LOOP: + // gracefully handle end of slice, as end of stream is meaningful here if i < uint(len(z.b)) && isNumberChar(z.b[i]) { i++ goto LOOP } z.c, i = i, z.c + // MARKER: 20230103: byteSliceOf here prevents inlining of jsonReadNum + // return byteSliceOf(z.b, i, z.c) return z.b[i:z.c] } @@ -686,7 +470,8 @@ LOOP: i++ if token == '"' || token == '\\' { z.c, i = i, z.c - return z.b[i:z.c] + return byteSliceOf(z.b, i, z.c) + // return z.b[i:z.c] } goto LOOP } @@ -707,7 +492,8 @@ func (z *bytesDecReader) readUntil(stop byte) (out []byte) { i := z.c LOOP: if z.b[i] == stop { - out = z.b[z.c:i] + out = byteSliceOf(z.b, z.c, i) + // out = z.b[z.c:i] z.c = i + 1 return } @@ -718,6 +504,16 @@ LOOP: // -------------- type decRd struct { + rb bytesDecReader + ri *ioDecReader + + decReader + + bytes bool // is bytes reader + + // MARKER: these fields below should belong directly in Encoder. + // we pack them here for space efficiency and cache-line optimization. + mtr bool // is maptype a known type? str bool // is slicetype a known type? @@ -726,73 +522,66 @@ type decRd struct { jsms bool // is json handle, and MapKeyAsString cbor bool // is cbor handle - bytes bool // is bytes reader - bufio bool // is this a bufioDecReader? - - rb bytesDecReader - ri *ioDecReader - bi *bufioDecReader + cbreak bool // is a check breaker - decReader } -// From out benchmarking, we see the following in terms of performance: -// -// - interface calls -// - branch that can inline what it calls +// From out benchmarking, we see the following impact performance: // -// the if/else-if/else block is expensive to inline. -// Each node of this construct costs a lot and dominates the budget. -// Best to only do an if fast-path else block (so fast-path is inlined). -// This is irrespective of inlineExtraCallCost set in $GOROOT/src/cmd/compile/internal/gc/inl.go +// - functions that are too big to inline +// - interface calls (as no inlining can occur) // -// In decRd methods below, we delegate all IO functions into their own methods. -// This allows for the inlining of the common path when z.bytes=true. -// Go 1.12+ supports inlining methods with up to 1 inlined function (or 2 if no other constructs). +// decRd is designed to embed a decReader, and then re-implement some of the decReader +// methods using a conditional branch. // -// However, up through Go 1.13, decRd's readXXX, skip and unreadXXX methods are not inlined. -// Consequently, there is no benefit to do the xxxIO methods for decRd at this time. -// Instead, we have a if/else-if/else block so that IO calls do not have to jump through -// a second unnecessary function call. +// We only override the ones where the bytes version is inlined AND the wrapper method +// (containing the bytes version alongside a conditional branch) is also inlined. // -// If golang inlining gets better and bytesDecReader methods can be inlined, -// then we can revert to using these 2 functions so the bytesDecReader -// methods are inlined and the IO paths call out to a function. +// We use ./run.sh -z to check. // -// decRd is designed to embed a decReader, and then re-implement some of the decReader -// methods using a conditional branch. We only override the ones that have a bytes version -// that is small enough to be inlined. We use ./run.sh -z to check. -// Right now, only numread and readn1 can be inlined. +// Right now, only numread and "carefully crafted" readn1 can be inlined. func (z *decRd) numread() uint { if z.bytes { return z.rb.numread() - } else if z.bufio { - return z.bi.numread() - } else { - return z.ri.numread() } + return z.ri.numread() } func (z *decRd) readn1() (v uint8) { if z.bytes { - // MARKER: manually inline, else this function is not inlined. - // Keep in sync with bytesDecReader.readn1 // return z.rb.readn1() + // MARKER: calling z.rb.readn1() prevents decRd.readn1 from being inlined. + // copy code, to manually inline and explicitly return here. + // Keep in sync with bytesDecReader.readn1 v = z.rb.b[z.rb.c] z.rb.c++ - } else { - v = z.readn1IO() - } - return -} -func (z *decRd) readn1IO() uint8 { - if z.bufio { - return z.bi.readn1() + return } return z.ri.readn1() } +// func (z *decRd) readn4() [4]byte { +// if z.bytes { +// return z.rb.readn4() +// } +// return z.ri.readn4() +// } + +// func (z *decRd) readn3() [3]byte { +// if z.bytes { +// return z.rb.readn3() +// } +// return z.ri.readn3() +// } + +// func (z *decRd) skipWhitespace() byte { +// if z.bytes { +// return z.rb.skipWhitespace() +// } +// return z.ri.skipWhitespace() +// } + type devNullReader struct{} func (devNullReader) Read(p []byte) (int, error) { return 0, io.EOF } diff --git a/vendor/github.com/ugorji/go/codec/rpc.go b/vendor/github.com/ugorji/go/codec/rpc.go index cf72377c7..0da8ad577 100644 --- a/vendor/github.com/ugorji/go/codec/rpc.go +++ b/vendor/github.com/ugorji/go/codec/rpc.go @@ -198,29 +198,31 @@ type goRpc struct{} // This ensures we use an adequate buffer during reading and writing. // If not configured, we will internally initialize and use a buffer during reads and writes. // This can be turned off via the RPCNoBuffer option on the Handle. -// var handle codec.JsonHandle -// handle.RPCNoBuffer = true // turns off attempt by rpc module to initialize a buffer +// +// var handle codec.JsonHandle +// handle.RPCNoBuffer = true // turns off attempt by rpc module to initialize a buffer // // Example 1: one way of configuring buffering explicitly: -// var handle codec.JsonHandle // codec handle -// handle.ReaderBufferSize = 1024 -// handle.WriterBufferSize = 1024 -// var conn io.ReadWriteCloser // connection got from a socket -// var serverCodec = GoRpc.ServerCodec(conn, handle) -// var clientCodec = GoRpc.ClientCodec(conn, handle) +// +// var handle codec.JsonHandle // codec handle +// handle.ReaderBufferSize = 1024 +// handle.WriterBufferSize = 1024 +// var conn io.ReadWriteCloser // connection got from a socket +// var serverCodec = GoRpc.ServerCodec(conn, handle) +// var clientCodec = GoRpc.ClientCodec(conn, handle) // // Example 2: you can also explicitly create a buffered connection yourself, // and not worry about configuring the buffer sizes in the Handle. -// var handle codec.Handle // codec handle -// var conn io.ReadWriteCloser // connection got from a socket -// var bufconn = struct { // bufconn here is a buffered io.ReadWriteCloser -// io.Closer -// *bufio.Reader -// *bufio.Writer -// }{conn, bufio.NewReader(conn), bufio.NewWriter(conn)} -// var serverCodec = GoRpc.ServerCodec(bufconn, handle) -// var clientCodec = GoRpc.ClientCodec(bufconn, handle) // +// var handle codec.Handle // codec handle +// var conn io.ReadWriteCloser // connection got from a socket +// var bufconn = struct { // bufconn here is a buffered io.ReadWriteCloser +// io.Closer +// *bufio.Reader +// *bufio.Writer +// }{conn, bufio.NewReader(conn), bufio.NewWriter(conn)} +// var serverCodec = GoRpc.ServerCodec(bufconn, handle) +// var clientCodec = GoRpc.ClientCodec(bufconn, handle) var GoRpc goRpc func (x goRpc) ServerCodec(conn io.ReadWriteCloser, h Handle) rpc.ServerCodec { diff --git a/vendor/github.com/ugorji/go/codec/sort-slice.generated.go b/vendor/github.com/ugorji/go/codec/sort-slice.generated.go index 0c43bdaae..a755a02af 100644 --- a/vendor/github.com/ugorji/go/codec/sort-slice.generated.go +++ b/vendor/github.com/ugorji/go/codec/sort-slice.generated.go @@ -5,9 +5,11 @@ package codec -import "time" -import "reflect" -import "bytes" +import ( + "bytes" + "reflect" + "time" +) type stringSlice []string @@ -109,18 +111,6 @@ func (p int64RvSlice) Less(i, j int) bool { return p[uint(i)].v < p[uint(j)].v } -type boolRv struct { - v bool - r reflect.Value -} -type boolRvSlice []boolRv - -func (p boolRvSlice) Len() int { return len(p) } -func (p boolRvSlice) Swap(i, j int) { p[uint(i)], p[uint(j)] = p[uint(j)], p[uint(i)] } -func (p boolRvSlice) Less(i, j int) bool { - return !p[uint(i)].v && p[uint(j)].v -} - type timeRv struct { v time.Time r reflect.Value diff --git a/vendor/github.com/ugorji/go/codec/sort-slice.go.tmpl b/vendor/github.com/ugorji/go/codec/sort-slice.go.tmpl index 81bf4b488..98209603e 100644 --- a/vendor/github.com/ugorji/go/codec/sort-slice.go.tmpl +++ b/vendor/github.com/ugorji/go/codec/sort-slice.go.tmpl @@ -20,9 +20,11 @@ With the parameters passed in sortables or sortablesplus, package codec -import "time" -import "reflect" -import "bytes" +import ( + "time" + "reflect" + "bytes" +) {{/* func init() { _ = time.Unix } */}} diff --git a/vendor/github.com/ugorji/go/codec/writer.go b/vendor/github.com/ugorji/go/codec/writer.go index 4d2c9fe10..b6e4813f8 100644 --- a/vendor/github.com/ugorji/go/codec/writer.go +++ b/vendor/github.com/ugorji/go/codec/writer.go @@ -106,7 +106,8 @@ func (z *bufioEncWriter) writeqstr(s string) { if z.n+len(s)+2 > len(z.buf) { z.flush() } - z.buf[z.n] = '"' + setByteAt(z.buf, uint(z.n), '"') + // z.buf[z.n] = '"' z.n++ LOOP: a := len(z.buf) - z.n @@ -117,7 +118,8 @@ LOOP: goto LOOP } z.n += copy(z.buf[z.n:], s) - z.buf[z.n] = '"' + setByteAt(z.buf, uint(z.n), '"') + // z.buf[z.n] = '"' z.n++ } @@ -125,21 +127,29 @@ func (z *bufioEncWriter) writen1(b1 byte) { if 1 > len(z.buf)-z.n { z.flush() } - z.buf[z.n] = b1 + setByteAt(z.buf, uint(z.n), b1) + // z.buf[z.n] = b1 z.n++ } func (z *bufioEncWriter) writen2(b1, b2 byte) { if 2 > len(z.buf)-z.n { z.flush() } - z.buf[z.n+1] = b2 - z.buf[z.n] = b1 + setByteAt(z.buf, uint(z.n+1), b2) + setByteAt(z.buf, uint(z.n), b1) + // z.buf[z.n+1] = b2 + // z.buf[z.n] = b1 z.n += 2 } + func (z *bufioEncWriter) writen4(b [4]byte) { if 4 > len(z.buf)-z.n { z.flush() } + // setByteAt(z.buf, uint(z.n+3), b4) + // setByteAt(z.buf, uint(z.n+2), b3) + // setByteAt(z.buf, uint(z.n+1), b2) + // setByteAt(z.buf, uint(z.n), b1) copy(z.buf[z.n:], b[:]) z.n += 4 } @@ -185,14 +195,17 @@ func (z *bytesEncAppender) writen1(b1 byte) { func (z *bytesEncAppender) writen2(b1, b2 byte) { z.b = append(z.b, b1, b2) } + func (z *bytesEncAppender) writen4(b [4]byte) { z.b = append(z.b, b[:]...) - // z.b = append(z.b, b[0], b[1], b[2], b[3]) // prevents inlining encWr.writen4 + // z.b = append(z.b, b1, b2, b3, b4) // prevents inlining encWr.writen4 } + func (z *bytesEncAppender) writen8(b [8]byte) { z.b = append(z.b, b[:]...) // z.b = append(z.b, b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]) // prevents inlining encWr.writen4 } + func (z *bytesEncAppender) endErr() error { *(z.out) = z.b return nil @@ -205,16 +218,21 @@ func (z *bytesEncAppender) reset(in []byte, out *[]byte) { // -------------------------------------------------- type encWr struct { + wb bytesEncAppender + wf *bufioEncWriter + bytes bool // encoding to []byte - js bool // is json encoder? - be bool // is binary encoder? + + // MARKER: these fields below should belong directly in Encoder. + // we pack them here for space efficiency and cache-line optimization. + + js bool // is json encoder? + be bool // is binary encoder? c containerState calls uint16 seq uint16 // sequencer (e.g. used by binc for symbols, etc) - wb bytesEncAppender - wf *bufioEncWriter } // MARKER: manually inline bytesEncAppender.writenx/writeqstr methods, @@ -229,21 +247,25 @@ func (z *encWr) writeb(s []byte) { z.wf.writeb(s) } } -func (z *encWr) writeqstr(s string) { +func (z *encWr) writestr(s string) { if z.bytes { - // MARKER: z.wb.writeqstr(s) - z.wb.b = append(append(append(z.wb.b, '"'), s...), '"') + z.wb.writestr(s) } else { - z.wf.writeqstr(s) + z.wf.writestr(s) } } -func (z *encWr) writestr(s string) { + +// MARKER: Add WriteStr to be called directly by generated code without a genHelper forwarding function. +// Go's inlining model adds cost for forwarding functions, preventing inlining (cost goes above 80 budget). + +func (z *encWr) WriteStr(s string) { if z.bytes { z.wb.writestr(s) } else { z.wf.writestr(s) } } + func (z *encWr) writen1(b1 byte) { if z.bytes { z.wb.writen1(b1) @@ -260,21 +282,34 @@ func (z *encWr) writen2(b1, b2 byte) { z.wf.writen2(b1, b2) } } + func (z *encWr) writen4(b [4]byte) { if z.bytes { - z.wb.writen4(b) + // MARKER: z.wb.writen4(b1, b2, b3, b4) + z.wb.b = append(z.wb.b, b[:]...) + // z.wb.writen4(b) } else { z.wf.writen4(b) } } func (z *encWr) writen8(b [8]byte) { if z.bytes { + // z.wb.b = append(z.wb.b, b[:]...) z.wb.writen8(b) } else { z.wf.writen8(b) } } +func (z *encWr) writeqstr(s string) { + if z.bytes { + // MARKER: z.wb.writeqstr(s) + z.wb.b = append(append(append(z.wb.b, '"'), s...), '"') + } else { + z.wf.writeqstr(s) + } +} + func (z *encWr) endErr() error { if z.bytes { return z.wb.endErr() |