Update etcd client to 3.3.9

This commit is contained in:
Joe Betz
2018-10-01 16:53:57 -07:00
parent 5d0c19c261
commit 4263c75211
432 changed files with 44092 additions and 43584 deletions

View File

@@ -2,8 +2,8 @@
// Use of this source code is governed by a MIT license found in the LICENSE file.
/*
High Performance, Feature-Rich Idiomatic Go codec/encoding library for
binc, msgpack, cbor, json.
High Performance, Feature-Rich Idiomatic Go 1.4+ codec/encoding library for
binc, msgpack, cbor, json
Supported Serialization formats are:
@@ -11,21 +11,17 @@ Supported Serialization formats are:
- 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:
- simple:
To install:
go get github.com/ugorji/go/codec
This package understands the 'unsafe' tag, to allow using unsafe semantics:
- When decoding into a struct, you need to read the field name as a string
so you can find the struct field it is mapped to.
Using `unsafe` will bypass the allocation and copying overhead of []byte->string conversion.
To install using unsafe, pass the 'unsafe' tag:
go get -tags=unsafe github.com/ugorji/go/codec
This package will carefully use '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=safe ...'. Note that unsafe is only supported for the last 3
go sdk versions e.g. current go release is go 1.9, so we support unsafe use only from
go 1.7+ . This is because supporting unsafe requires knowledge of implementation details.
For detailed usage information, read the primer at http://ugorji.net/blog/go-codec-primer .
@@ -35,12 +31,17 @@ the standard library (ie json, xml, gob, etc).
Rich Feature Set includes:
- Simple but extremely powerful and feature-rich API
- Support for go1.4 and above, while selectively using newer APIs for later releases
- Good code coverage ( > 70% )
- 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% mode exists where 'unsafe' is not used at all.
- Lock-free (sans mutex) concurrency for scaling to 100's of cores
- Multiple conversions:
Package coerces types where appropriate
Package coerces types where appropriate
e.g. decode an int in the stream into a float, etc.
- Corner Cases:
- 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
@@ -56,7 +57,7 @@ Rich Feature Set includes:
- Fast (no-reflection) encoding/decoding of common maps and slices
- Code-generation for faster performance.
- Support binary (e.g. messagepack, cbor) and text (e.g. json) formats
- Support indefinite-length formats to enable true streaming
- 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.
@@ -68,12 +69,12 @@ Rich Feature Set includes:
- 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
- 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
Extension Support
Users can register a function to handle the encoding or decoding of
@@ -160,40 +161,25 @@ Sample usage model:
//OR rpcCodec := codec.MsgpackSpecRpc.ClientCodec(conn, h)
client := rpc.NewClientWithCodec(rpcCodec)
Running Tests
To run tests, use the following:
go test
To run the full suite of tests, use the following:
go test -tags alltests -run Suite
You can run the tag 'safe' to run tests or build in safe mode. e.g.
go test -tags safe -run Json
go test -tags "alltests safe" -run Suite
Running Benchmarks
Please see http://github.com/ugorji/go-codec-bench .
*/
package codec
// Benefits of go-codec:
//
// - encoding/json always reads whole file into memory first.
// This makes it unsuitable for parsing very large files.
// - encoding/xml cannot parse into a map[string]interface{}
// I found this out on reading https://github.com/clbanning/mxj
// TODO:
//
// - optimization for codecgen:
// if len of entity is <= 3 words, then support a value receiver for encode.
// - (En|De)coder should store an error when it occurs.
// Until reset, subsequent calls return that error that was stored.
// This means that free panics must go away.
// All errors must be raised through errorf method.
// - Decoding using a chan is good, but incurs concurrency costs.
// This is because there's no fast way to use a channel without it
// having to switch goroutines constantly.
// Callback pattern is still the best. Maybe consider supporting something like:
// type X struct {
// Name string
// Ys []Y
// Ys chan <- Y
// Ys func(Y) -> call this function for each entry
// }
// - Consider adding a isZeroer interface { isZero() bool }
// It is used within isEmpty, for omitEmpty support.
// - Consider making Handle used AS-IS within the encoding/decoding session.
// This means that we don't cache Handle information within the (En|De)coder,
// except we really need it at Reset(...)
// - Consider adding math/big support
// - Consider reducing the size of the generated functions:
// Maybe use one loop, and put the conditionals in the loop.
// for ... { if cLen > 0 { if j == cLen { break } } else if dd.CheckBreak() { break } }

View File

@@ -7,26 +7,29 @@ go_library(
"binc.go",
"cbor.go",
"decode.go",
"decode_go.go",
"decode_go14.go",
"encode.go",
"fast-path.generated.go",
"gen.generated.go",
"gen.go",
"gen-helper.generated.go",
"gen_15.go",
"gen_16.go",
"gen_17.go",
"goversion_arrayof_gte_go15.go",
"goversion_arrayof_lt_go15.go",
"goversion_makemap_gte_go19.go",
"goversion_makemap_lt_go19.go",
"goversion_unsupported_lt_go14.go",
"goversion_vendor_eq_go15.go",
"goversion_vendor_eq_go16.go",
"goversion_vendor_gte_go17.go",
"goversion_vendor_lt_go15.go",
"helper.go",
"helper_internal.go",
"helper_not_unsafe.go",
"helper_unsafe.go",
"json.go",
"msgpack.go",
"noop.go",
"prebuild.go",
"rpc.go",
"simple.go",
"time.go",
"z.go",
],
importmap = "k8s.io/kubernetes/vendor/github.com/ugorji/go/codec",
importpath = "github.com/ugorji/go/codec",

View File

@@ -15,17 +15,11 @@ To install:
go get github.com/ugorji/go/codec
This package understands the `unsafe` tag, to allow using unsafe semantics:
- When decoding into a struct, you need to read the field name as a string
so you can find the struct field it is mapped to.
Using `unsafe` will bypass the allocation and copying overhead of `[]byte->string` conversion.
To use it, you must pass the `unsafe` tag during install:
```
go install -tags=unsafe github.com/ugorji/go/codec
```
This package will carefully use '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=safe ...'. Note that unsafe is only supported for the last 3
go sdk versions e.g. current go release is go 1.9, so we support unsafe use only from
go 1.7+ . This is because supporting unsafe requires knowledge of implementation details.
Online documentation: http://godoc.org/github.com/ugorji/go/codec
Detailed Usage/How-to Primer: http://ugorji.net/blog/go-codec-primer
@@ -36,8 +30,13 @@ the standard library (ie json, xml, gob, etc).
Rich Feature Set includes:
- Simple but extremely powerful and feature-rich API
- Support for go1.4 and above, while selectively using newer APIs for later releases
- Good code coverage ( > 70% )
- 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% mode exists where 'unsafe' is not used at all.
- Lock-free (sans mutex) concurrency for scaling to 100's of cores
- Multiple conversions:
Package coerces types where appropriate
e.g. decode an int in the stream into a float, etc.
@@ -146,3 +145,22 @@ Typical usage model:
//OR rpcCodec := codec.MsgpackSpecRpc.ClientCodec(conn, h)
client := rpc.NewClientWithCodec(rpcCodec)
## Running Tests
To run tests, use the following:
go test
To run the full suite of tests, use the following:
go test -tags alltests -run Suite
You can run the tag 'safe' to run tests or build in safe mode. e.g.
go test -tags safe -run Json
go test -tags "alltests safe" -run Suite
## Running Benchmarks
Please see http://github.com/ugorji/go-codec-bench .

View File

@@ -61,7 +61,8 @@ type bincEncDriver struct {
m map[string]uint16 // symbols
b [scratchByteArrayLen]byte
s uint16 // symbols sequencer
encNoSeparator
// encNoSeparator
encDriverNoopContainerWriter
}
func (e *bincEncDriver) IsBuiltinType(rt uintptr) bool {
@@ -195,11 +196,11 @@ func (e *bincEncDriver) encodeExtPreamble(xtag byte, length int) {
e.w.writen1(xtag)
}
func (e *bincEncDriver) EncodeArrayStart(length int) {
func (e *bincEncDriver) WriteArrayStart(length int) {
e.encLen(bincVdArray<<4, uint64(length))
}
func (e *bincEncDriver) EncodeMapStart(length int) {
func (e *bincEncDriver) WriteMapStart(length int) {
e.encLen(bincVdMap<<4, uint64(length))
}
@@ -332,13 +333,14 @@ type bincDecDriver struct {
bd byte
vd byte
vs byte
noStreamingCodec
decNoSeparator
// noStreamingCodec
// decNoSeparator
b [scratchByteArrayLen]byte
// linear searching on this slice is ok,
// because we typically expect < 32 symbols in each stream.
s []bincDecSymbol
decDriverNoopContainerReader
}
func (d *bincDecDriver) readNextBd() {
@@ -356,6 +358,9 @@ func (d *bincDecDriver) uncacheRead() {
}
func (d *bincDecDriver) ContainerType() (vt valueType) {
if !d.bdRead {
d.readNextBd()
}
if d.vd == bincVdSpecial && d.vs == bincSpNil {
return valueTypeNil
} else if d.vd == bincVdByteArray {
@@ -509,7 +514,7 @@ func (d *bincDecDriver) DecodeInt(bitsize uint8) (i int64) {
i = -i
}
if chkOvf.Int(i, bitsize) {
d.d.errorf("binc: overflow integer: %v", i)
d.d.errorf("binc: overflow integer: %v for num bits: %v", i, bitsize)
return
}
d.bdRead = false
@@ -580,6 +585,9 @@ func (d *bincDecDriver) DecodeBool() (b bool) {
}
func (d *bincDecDriver) ReadMapStart() (length int) {
if !d.bdRead {
d.readNextBd()
}
if d.vd != bincVdMap {
d.d.errorf("Invalid d.vd for map. Expecting 0x%x. Got: 0x%x", bincVdMap, d.vd)
return
@@ -590,6 +598,9 @@ func (d *bincDecDriver) ReadMapStart() (length int) {
}
func (d *bincDecDriver) ReadArrayStart() (length int) {
if !d.bdRead {
d.readNextBd()
}
if d.vd != bincVdArray {
d.d.errorf("Invalid d.vd for array. Expecting 0x%x. Got: 0x%x", bincVdArray, d.vd)
return
@@ -639,12 +650,12 @@ func (d *bincDecDriver) decStringAndBytes(bs []byte, withString, zerocopy bool)
if d.br {
bs2 = d.r.readx(slen)
} else if len(bs) == 0 {
bs2 = decByteSlice(d.r, slen, d.b[:])
bs2 = decByteSlice(d.r, slen, d.d.h.MaxInitLen, d.b[:])
} else {
bs2 = decByteSlice(d.r, slen, bs)
bs2 = decByteSlice(d.r, slen, d.d.h.MaxInitLen, bs)
}
} else {
bs2 = decByteSlice(d.r, slen, bs)
bs2 = decByteSlice(d.r, slen, d.d.h.MaxInitLen, bs)
}
if withString {
s = string(bs2)
@@ -696,7 +707,7 @@ func (d *bincDecDriver) decStringAndBytes(bs []byte, withString, zerocopy bool)
// since using symbols, do not store any part of
// the parameter bs in the map, as it might be a shared buffer.
// bs2 = decByteSlice(d.r, slen, bs)
bs2 = decByteSlice(d.r, slen, nil)
bs2 = decByteSlice(d.r, slen, d.d.h.MaxInitLen, nil)
if withString {
s = string(bs2)
}
@@ -719,11 +730,12 @@ func (d *bincDecDriver) DecodeString() (s string) {
return
}
func (d *bincDecDriver) DecodeBytes(bs []byte, isstring, zerocopy bool) (bsOut []byte) {
if isstring {
bsOut, _ = d.decStringAndBytes(bs, false, zerocopy)
return
}
func (d *bincDecDriver) DecodeStringAsBytes() (s []byte) {
s, _ = d.decStringAndBytes(d.b[:], false, true)
return
}
func (d *bincDecDriver) DecodeBytes(bs []byte, zerocopy bool) (bsOut []byte) {
if !d.bdRead {
d.readNextBd()
}
@@ -747,7 +759,7 @@ func (d *bincDecDriver) DecodeBytes(bs []byte, isstring, zerocopy bool) (bsOut [
bs = d.b[:]
}
}
return decByteSlice(d.r, clen, bs)
return decByteSlice(d.r, clen, d.d.h.MaxInitLen, bs)
}
func (d *bincDecDriver) DecodeExt(rv interface{}, xtag uint64, ext Ext) (realxtag uint64) {
@@ -780,7 +792,7 @@ func (d *bincDecDriver) decodeExtV(verifyTag bool, tag byte) (xtag byte, xbs []b
}
xbs = d.r.readx(l)
} else if d.vd == bincVdByteArray {
xbs = d.DecodeBytes(nil, false, true)
xbs = d.DecodeBytes(nil, true)
} else {
d.d.errorf("Invalid d.vd for extensions (Expecting extensions or byte array). Got: 0x%x", d.vd)
return
@@ -794,7 +806,7 @@ func (d *bincDecDriver) DecodeNaked() {
d.readNextBd()
}
n := &d.d.n
n := d.d.n
var decodeFurther bool
switch d.vd {
@@ -849,7 +861,7 @@ func (d *bincDecDriver) DecodeNaked() {
n.s = d.DecodeString()
case bincVdByteArray:
n.v = valueTypeBytes
n.l = d.DecodeBytes(nil, false, false)
n.l = d.DecodeBytes(nil, false)
case bincVdTimestamp:
n.v = valueTypeTimestamp
tt, err := decodeTime(d.r.readx(int(d.vs)))
@@ -899,6 +911,7 @@ func (d *bincDecDriver) DecodeNaked() {
type BincHandle struct {
BasicHandle
binaryEncodingType
noElemSeparators
}
func (h *BincHandle) SetBytesExt(rt reflect.Type, tag uint64, ext BytesExt) (err error) {
@@ -910,7 +923,11 @@ func (h *BincHandle) newEncDriver(e *Encoder) encDriver {
}
func (h *BincHandle) newDecDriver(d *Decoder) decDriver {
return &bincDecDriver{d: d, r: d.r, h: h, br: d.bytes}
return &bincDecDriver{d: d, h: h, r: d.r, br: d.bytes}
}
func (_ *BincHandle) IsBuiltinType(rt uintptr) bool {
return rt == timeTypId
}
func (e *bincEncDriver) reset() {
@@ -920,7 +937,7 @@ func (e *bincEncDriver) reset() {
}
func (d *bincDecDriver) reset() {
d.r = d.d.r
d.r, d.br = d.d.r, d.d.bytes
d.s = nil
d.bd, d.bdRead, d.vd, d.vs = 0, false, 0, 0
}

View File

@@ -61,7 +61,8 @@ const (
type cborEncDriver struct {
noBuiltInTypes
encNoSeparator
encDriverNoopContainerWriter
// encNoSeparator
e *Encoder
w encWriter
h *CborHandle
@@ -134,21 +135,41 @@ func (e *cborEncDriver) EncodeExt(rv interface{}, xtag uint64, ext Ext, en *Enco
func (e *cborEncDriver) EncodeRawExt(re *RawExt, en *Encoder) {
e.encUint(uint64(re.Tag), cborBaseTag)
if re.Data != nil {
if false && re.Data != nil {
en.encode(re.Data)
} else if re.Value == nil {
e.EncodeNil()
} else {
} else if re.Value != nil {
en.encode(re.Value)
} else {
e.EncodeNil()
}
}
func (e *cborEncDriver) EncodeArrayStart(length int) {
e.encLen(cborBaseArray, length)
func (e *cborEncDriver) WriteArrayStart(length int) {
if e.h.IndefiniteLength {
e.w.writen1(cborBdIndefiniteArray)
} else {
e.encLen(cborBaseArray, length)
}
}
func (e *cborEncDriver) EncodeMapStart(length int) {
e.encLen(cborBaseMap, length)
func (e *cborEncDriver) WriteMapStart(length int) {
if e.h.IndefiniteLength {
e.w.writen1(cborBdIndefiniteMap)
} else {
e.encLen(cborBaseMap, length)
}
}
func (e *cborEncDriver) WriteMapEnd() {
if e.h.IndefiniteLength {
e.w.writen1(cborBdBreak)
}
}
func (e *cborEncDriver) WriteArrayEnd() {
if e.h.IndefiniteLength {
e.w.writen1(cborBdBreak)
}
}
func (e *cborEncDriver) EncodeString(c charEncoding, v string) {
@@ -180,7 +201,8 @@ type cborDecDriver struct {
bdRead bool
bd byte
noBuiltInTypes
decNoSeparator
// decNoSeparator
decDriverNoopContainerReader
}
func (d *cborDecDriver) readNextBd() {
@@ -196,6 +218,9 @@ func (d *cborDecDriver) uncacheRead() {
}
func (d *cborDecDriver) ContainerType() (vt valueType) {
if !d.bdRead {
d.readNextBd()
}
if d.bd == cborBdNil {
return valueTypeNil
} else if d.bd == cborBdIndefiniteBytes || (d.bd >= cborBaseBytes && d.bd < cborBaseString) {
@@ -351,6 +376,9 @@ func (d *cborDecDriver) DecodeBool() (b bool) {
}
func (d *cborDecDriver) ReadMapStart() (length int) {
if !d.bdRead {
d.readNextBd()
}
d.bdRead = false
if d.bd == cborBdIndefiniteMap {
return -1
@@ -359,6 +387,9 @@ func (d *cborDecDriver) ReadMapStart() (length int) {
}
func (d *cborDecDriver) ReadArrayStart() (length int) {
if !d.bdRead {
d.readNextBd()
}
d.bdRead = false
if d.bd == cborBdIndefiniteArray {
return -1
@@ -398,7 +429,7 @@ func (d *cborDecDriver) decAppendIndefiniteBytes(bs []byte) []byte {
return bs
}
func (d *cborDecDriver) DecodeBytes(bs []byte, isstring, zerocopy bool) (bsOut []byte) {
func (d *cborDecDriver) DecodeBytes(bs []byte, zerocopy bool) (bsOut []byte) {
if !d.bdRead {
d.readNextBd()
}
@@ -421,11 +452,15 @@ func (d *cborDecDriver) DecodeBytes(bs []byte, isstring, zerocopy bool) (bsOut [
bs = d.b[:]
}
}
return decByteSlice(d.r, clen, bs)
return decByteSlice(d.r, clen, d.d.h.MaxInitLen, bs)
}
func (d *cborDecDriver) DecodeString() (s string) {
return string(d.DecodeBytes(d.b[:], true, true))
return string(d.DecodeBytes(d.b[:], true))
}
func (d *cborDecDriver) DecodeStringAsBytes() (s []byte) {
return d.DecodeBytes(d.b[:], true)
}
func (d *cborDecDriver) DecodeExt(rv interface{}, xtag uint64, ext Ext) (realxtag uint64) {
@@ -456,7 +491,7 @@ func (d *cborDecDriver) DecodeNaked() {
d.readNextBd()
}
n := &d.d.n
n := d.d.n
var decodeFurther bool
switch d.bd {
@@ -476,7 +511,7 @@ func (d *cborDecDriver) DecodeNaked() {
n.f = d.DecodeFloat(false)
case cborBdIndefiniteBytes:
n.v = valueTypeBytes
n.l = d.DecodeBytes(nil, false, false)
n.l = d.DecodeBytes(nil, false)
case cborBdIndefiniteString:
n.v = valueTypeString
n.s = d.DecodeString()
@@ -501,7 +536,7 @@ func (d *cborDecDriver) DecodeNaked() {
n.i = d.DecodeInt(64)
case d.bd >= cborBaseBytes && d.bd < cborBaseString:
n.v = valueTypeBytes
n.l = d.DecodeBytes(nil, false, false)
n.l = d.DecodeBytes(nil, false)
case d.bd >= cborBaseString && d.bd < cborBaseArray:
n.v = valueTypeString
n.s = d.DecodeString()
@@ -564,7 +599,11 @@ func (d *cborDecDriver) DecodeNaked() {
//
type CborHandle struct {
binaryEncodingType
noElemSeparators
BasicHandle
// IndefiniteLength=true, means that we encode using indefinitelength
IndefiniteLength bool
}
func (h *CborHandle) SetInterfaceExt(rt reflect.Type, tag uint64, ext InterfaceExt) (err error) {
@@ -576,7 +615,7 @@ func (h *CborHandle) newEncDriver(e *Encoder) encDriver {
}
func (h *CborHandle) newDecDriver(d *Decoder) decDriver {
return &cborDecDriver{d: d, r: d.r, h: h, br: d.bytes}
return &cborDecDriver{d: d, h: h, r: d.r, br: d.bytes}
}
func (e *cborEncDriver) reset() {
@@ -584,7 +623,7 @@ func (e *cborEncDriver) reset() {
}
func (d *cborDecDriver) reset() {
d.r = d.d.r
d.r, d.br = d.d.r, d.d.bytes
d.bd, d.bdRead = 0, false
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -40,9 +40,6 @@ import (
const fastpathEnabled = true
const fastpathCheckNilFalse = false // for reflect
const fastpathCheckNilTrue = true // for type switch
type fastpathT struct {}
var fastpathTV fastpathT
@@ -50,8 +47,8 @@ var fastpathTV fastpathT
type fastpathE struct {
rtid uintptr
rt reflect.Type
encfn func(*encFnInfo, reflect.Value)
decfn func(*decFnInfo, reflect.Value)
encfn func(*Encoder, *codecFnInfo, reflect.Value)
decfn func(*Decoder, *codecFnInfo, reflect.Value)
}
type fastpathA [{{ .FastpathLen }}]fastpathE
@@ -84,19 +81,25 @@ var fastpathAV fastpathA
// due to possible initialization loop error, make fastpath in an init()
func init() {
i := 0
fn := func(v interface{}, fe func(*encFnInfo, reflect.Value), fd func(*decFnInfo, reflect.Value)) (f fastpathE) {
fn := func(v interface{},
fe func(*Encoder, *codecFnInfo, reflect.Value),
fd func(*Decoder, *codecFnInfo, reflect.Value)) (f fastpathE) {
xrt := reflect.TypeOf(v)
xptr := reflect.ValueOf(xrt).Pointer()
xptr := rt2id(xrt)
if useLookupRecognizedTypes {
recognizedRtids = append(recognizedRtids, xptr)
recognizedRtidPtrs = append(recognizedRtidPtrs, rt2id(reflect.PtrTo(xrt)))
}
fastpathAV[i] = fastpathE{xptr, xrt, fe, fd}
i++
return
}
{{range .Values}}{{if not .Primitive}}{{if not .MapKey }}
fn([]{{ .Elem }}(nil), (*encFnInfo).{{ .MethodNamePfx "fastpathEnc" false }}R, (*decFnInfo).{{ .MethodNamePfx "fastpathDec" false }}R){{end}}{{end}}{{end}}
fn([]{{ .Elem }}(nil), (*Encoder).{{ .MethodNamePfx "fastpathEnc" false }}R, (*Decoder).{{ .MethodNamePfx "fastpathDec" false }}R){{end}}{{end}}{{end}}
{{range .Values}}{{if not .Primitive}}{{if .MapKey }}
fn(map[{{ .MapKey }}]{{ .Elem }}(nil), (*encFnInfo).{{ .MethodNamePfx "fastpathEnc" false }}R, (*decFnInfo).{{ .MethodNamePfx "fastpathDec" false }}R){{end}}{{end}}{{end}}
fn(map[{{ .MapKey }}]{{ .Elem }}(nil), (*Encoder).{{ .MethodNamePfx "fastpathEnc" false }}R, (*Decoder).{{ .MethodNamePfx "fastpathDec" false }}R){{end}}{{end}}{{end}}
sort.Sort(fastpathAslice(fastpathAV[:]))
}
@@ -109,10 +112,10 @@ func fastpathEncodeTypeSwitch(iv interface{}, e *Encoder) bool {
{{range .Values}}{{if not .Primitive}}{{if not .MapKey }}
case []{{ .Elem }}:{{else}}
case map[{{ .MapKey }}]{{ .Elem }}:{{end}}
fastpathTV.{{ .MethodNamePfx "Enc" false }}V(v, fastpathCheckNilTrue, e){{if not .MapKey }}
fastpathTV.{{ .MethodNamePfx "Enc" false }}V(v, e){{if not .MapKey }}
case *[]{{ .Elem }}:{{else}}
case *map[{{ .MapKey }}]{{ .Elem }}:{{end}}
fastpathTV.{{ .MethodNamePfx "Enc" false }}V(*v, fastpathCheckNilTrue, e)
fastpathTV.{{ .MethodNamePfx "Enc" false }}V(*v, e)
{{end}}{{end}}
default:
_ = v // TODO: workaround https://github.com/golang/go/issues/12927 (remove after go 1.6 release)
@@ -125,9 +128,9 @@ func fastpathEncodeTypeSwitchSlice(iv interface{}, e *Encoder) bool {
switch v := iv.(type) {
{{range .Values}}{{if not .Primitive}}{{if not .MapKey }}
case []{{ .Elem }}:
fastpathTV.{{ .MethodNamePfx "Enc" false }}V(v, fastpathCheckNilTrue, e)
fastpathTV.{{ .MethodNamePfx "Enc" false }}V(v, e)
case *[]{{ .Elem }}:
fastpathTV.{{ .MethodNamePfx "Enc" false }}V(*v, fastpathCheckNilTrue, e)
fastpathTV.{{ .MethodNamePfx "Enc" false }}V(*v, e)
{{end}}{{end}}{{end}}
default:
_ = v // TODO: workaround https://github.com/golang/go/issues/12927 (remove after go 1.6 release)
@@ -140,9 +143,9 @@ func fastpathEncodeTypeSwitchMap(iv interface{}, e *Encoder) bool {
switch v := iv.(type) {
{{range .Values}}{{if not .Primitive}}{{if .MapKey }}
case map[{{ .MapKey }}]{{ .Elem }}:
fastpathTV.{{ .MethodNamePfx "Enc" false }}V(v, fastpathCheckNilTrue, e)
fastpathTV.{{ .MethodNamePfx "Enc" false }}V(v, e)
case *map[{{ .MapKey }}]{{ .Elem }}:
fastpathTV.{{ .MethodNamePfx "Enc" false }}V(*v, fastpathCheckNilTrue, e)
fastpathTV.{{ .MethodNamePfx "Enc" false }}V(*v, e)
{{end}}{{end}}{{end}}
default:
_ = v // TODO: workaround https://github.com/golang/go/issues/12927 (remove after go 1.6 release)
@@ -154,68 +157,53 @@ func fastpathEncodeTypeSwitchMap(iv interface{}, e *Encoder) bool {
// -- -- fast path functions
{{range .Values}}{{if not .Primitive}}{{if not .MapKey }}
func (f *encFnInfo) {{ .MethodNamePfx "fastpathEnc" false }}R(rv reflect.Value) {
func (e *Encoder) {{ .MethodNamePfx "fastpathEnc" false }}R(f *codecFnInfo, rv reflect.Value) {
if f.ti.mbs {
fastpathTV.{{ .MethodNamePfx "EncAsMap" false }}V(rv.Interface().([]{{ .Elem }}), fastpathCheckNilFalse, f.e)
fastpathTV.{{ .MethodNamePfx "EncAsMap" false }}V(rv2i(rv).([]{{ .Elem }}), e)
} else {
fastpathTV.{{ .MethodNamePfx "Enc" false }}V(rv.Interface().([]{{ .Elem }}), fastpathCheckNilFalse, f.e)
fastpathTV.{{ .MethodNamePfx "Enc" false }}V(rv2i(rv).([]{{ .Elem }}), e)
}
}
func (_ fastpathT) {{ .MethodNamePfx "Enc" false }}V(v []{{ .Elem }}, checkNil bool, e *Encoder) {
ee := e.e
cr := e.cr
if checkNil && v == nil {
ee.EncodeNil()
return
}
ee.EncodeArrayStart(len(v))
func (_ fastpathT) {{ .MethodNamePfx "Enc" false }}V(v []{{ .Elem }}, e *Encoder) {
ee, esep := e.e, e.hh.hasElemSeparators()
ee.WriteArrayStart(len(v))
for _, v2 := range v {
if cr != nil { cr.sendContainerState(containerArrayElem) }
if esep { ee.WriteArrayElem() }
{{ encmd .Elem "v2"}}
}
if cr != nil { cr.sendContainerState(containerArrayEnd) }{{/* ee.EncodeEnd() */}}
ee.WriteArrayEnd()
}
func (_ fastpathT) {{ .MethodNamePfx "EncAsMap" false }}V(v []{{ .Elem }}, checkNil bool, e *Encoder) {
ee := e.e
cr := e.cr
if checkNil && v == nil {
ee.EncodeNil()
return
}
func (_ fastpathT) {{ .MethodNamePfx "EncAsMap" false }}V(v []{{ .Elem }}, e *Encoder) {
ee, esep := e.e, e.hh.hasElemSeparators()
if len(v)%2 == 1 {
e.errorf("mapBySlice requires even slice length, but got %v", len(v))
return
}
ee.EncodeMapStart(len(v) / 2)
ee.WriteMapStart(len(v) / 2)
for j, v2 := range v {
if cr != nil {
if esep {
if j%2 == 0 {
cr.sendContainerState(containerMapKey)
ee.WriteMapElemKey()
} else {
cr.sendContainerState(containerMapValue)
ee.WriteMapElemValue()
}
}
{{ encmd .Elem "v2"}}
}
if cr != nil { cr.sendContainerState(containerMapEnd) }
ee.WriteMapEnd()
}
{{end}}{{end}}{{end}}
{{range .Values}}{{if not .Primitive}}{{if .MapKey }}
func (f *encFnInfo) {{ .MethodNamePfx "fastpathEnc" false }}R(rv reflect.Value) {
fastpathTV.{{ .MethodNamePfx "Enc" false }}V(rv.Interface().(map[{{ .MapKey }}]{{ .Elem }}), fastpathCheckNilFalse, f.e)
func (e *Encoder) {{ .MethodNamePfx "fastpathEnc" false }}R(f *codecFnInfo, rv reflect.Value) {
fastpathTV.{{ .MethodNamePfx "Enc" false }}V(rv2i(rv).(map[{{ .MapKey }}]{{ .Elem }}), e)
}
func (_ fastpathT) {{ .MethodNamePfx "Enc" false }}V(v map[{{ .MapKey }}]{{ .Elem }}, checkNil bool, e *Encoder) {
ee := e.e
cr := e.cr
if checkNil && v == nil {
ee.EncodeNil()
return
}
ee.EncodeMapStart(len(v))
func (_ fastpathT) {{ .MethodNamePfx "Enc" false }}V(v map[{{ .MapKey }}]{{ .Elem }}, e *Encoder) {
ee, esep := e.e, e.hh.hasElemSeparators()
ee.WriteMapStart(len(v))
{{if eq .MapKey "string"}}asSymbols := e.h.AsSymbols&AsSymbolMapStringKeysFlag != 0
{{end}}if e.h.Canonical {
{{if eq .MapKey "interface{}"}}{{/* out of band
@@ -234,9 +222,9 @@ func (_ fastpathT) {{ .MethodNamePfx "Enc" false }}V(v map[{{ .MapKey }}]{{ .Ele
}
sort.Sort(bytesISlice(v2))
for j := range v2 {
if cr != nil { cr.sendContainerState(containerMapKey) }
if esep { ee.WriteMapElemKey() }
e.asis(v2[j].v)
if cr != nil { cr.sendContainerState(containerMapValue) }
if esep { ee.WriteMapElemValue() }
e.encode(v[v2[j].i])
} {{else}}{{ $x := sorttype .MapKey true}}v2 := make([]{{ $x }}, len(v))
var i int
@@ -246,28 +234,28 @@ func (_ fastpathT) {{ .MethodNamePfx "Enc" false }}V(v map[{{ .MapKey }}]{{ .Ele
}
sort.Sort({{ sorttype .MapKey false}}(v2))
for _, k2 := range v2 {
if cr != nil { cr.sendContainerState(containerMapKey) }
if esep { ee.WriteMapElemKey() }
{{if eq .MapKey "string"}}if asSymbols {
ee.EncodeSymbol(k2)
} else {
ee.EncodeString(c_UTF8, k2)
}{{else}}{{ $y := printf "%s(k2)" .MapKey }}{{ encmd .MapKey $y }}{{end}}
if cr != nil { cr.sendContainerState(containerMapValue) }
if esep { ee.WriteMapElemValue() }
{{ $y := printf "v[%s(k2)]" .MapKey }}{{ encmd .Elem $y }}
} {{end}}
} else {
for k2, v2 := range v {
if cr != nil { cr.sendContainerState(containerMapKey) }
if esep { ee.WriteMapElemKey() }
{{if eq .MapKey "string"}}if asSymbols {
ee.EncodeSymbol(k2)
} else {
ee.EncodeString(c_UTF8, k2)
}{{else}}{{ encmd .MapKey "k2"}}{{end}}
if cr != nil { cr.sendContainerState(containerMapValue) }
if esep { ee.WriteMapElemValue() }
{{ encmd .Elem "v2"}}
}
}
if cr != nil { cr.sendContainerState(containerMapEnd) }{{/* ee.EncodeEnd() */}}
ee.WriteMapEnd()
}
{{end}}{{end}}{{end}}
@@ -280,11 +268,10 @@ func fastpathDecodeTypeSwitch(iv interface{}, d *Decoder) bool {
{{range .Values}}{{if not .Primitive}}{{if not .MapKey }}
case []{{ .Elem }}:{{else}}
case map[{{ .MapKey }}]{{ .Elem }}:{{end}}
fastpathTV.{{ .MethodNamePfx "Dec" false }}V(v, fastpathCheckNilFalse, false, d){{if not .MapKey }}
case *[]{{ .Elem }}:{{else}}
case *map[{{ .MapKey }}]{{ .Elem }}:{{end}}
v2, changed2 := fastpathTV.{{ .MethodNamePfx "Dec" false }}V(*v, fastpathCheckNilFalse, true, d)
if changed2 {
fastpathTV.{{ .MethodNamePfx "Dec" false }}V(v, false, d){{if not .MapKey }}
case *[]{{ .Elem }}: {{else}}
case *map[{{ .MapKey }}]{{ .Elem }}: {{end}}
if v2, changed2 := fastpathTV.{{ .MethodNamePfx "Dec" false }}V(*v, true, d); changed2 {
*v = v2
}
{{end}}{{end}}
@@ -295,6 +282,20 @@ func fastpathDecodeTypeSwitch(iv interface{}, d *Decoder) bool {
return true
}
func fastpathDecodeSetZeroTypeSwitch(iv interface{}, d *Decoder) bool {
switch v := iv.(type) {
{{range .Values}}{{if not .Primitive}}{{if not .MapKey }}
case *[]{{ .Elem }}: {{else}}
case *map[{{ .MapKey }}]{{ .Elem }}: {{end}}
*v = nil
{{end}}{{end}}
default:
_ = v // TODO: workaround https://github.com/golang/go/issues/12927 (remove after go 1.6 release)
return false
}
return true
}
// -- -- fast path functions
{{range .Values}}{{if not .Primitive}}{{if not .MapKey }}
{{/*
@@ -303,40 +304,29 @@ Slices can change if they
- are addressable (from a ptr)
- are settable (e.g. contained in an interface{})
*/}}
func (f *decFnInfo) {{ .MethodNamePfx "fastpathDec" false }}R(rv reflect.Value) {
array := f.seq == seqTypeArray
if !array && rv.CanAddr() { {{/* // CanSet => CanAddr + Exported */}}
vp := rv.Addr().Interface().(*[]{{ .Elem }})
v, changed := fastpathTV.{{ .MethodNamePfx "Dec" false }}V(*vp, fastpathCheckNilFalse, !array, f.d)
if changed {
*vp = v
func (d *Decoder) {{ .MethodNamePfx "fastpathDec" false }}R(f *codecFnInfo, rv reflect.Value) {
if array := f.seq == seqTypeArray; !array && rv.Kind() == reflect.Ptr {
var vp = rv2i(rv).(*[]{{ .Elem }})
if v, changed := fastpathTV.{{ .MethodNamePfx "Dec" false }}V(*vp, !array, d); changed {
*vp = v
}
} else {
v := rv.Interface().([]{{ .Elem }})
fastpathTV.{{ .MethodNamePfx "Dec" false }}V(v, fastpathCheckNilFalse, false, f.d)
fastpathTV.{{ .MethodNamePfx "Dec" false }}V(rv2i(rv).([]{{ .Elem }}), !array, d)
}
}
func (f fastpathT) {{ .MethodNamePfx "Dec" false }}X(vp *[]{{ .Elem }}, checkNil bool, d *Decoder) {
v, changed := f.{{ .MethodNamePfx "Dec" false }}V(*vp, checkNil, true, d)
if changed {
func (f fastpathT) {{ .MethodNamePfx "Dec" false }}X(vp *[]{{ .Elem }}, d *Decoder) {
if v, changed := f.{{ .MethodNamePfx "Dec" false }}V(*vp, true, d); changed {
*vp = v
}
}
func (_ fastpathT) {{ .MethodNamePfx "Dec" false }}V(v []{{ .Elem }}, checkNil bool, canChange bool, d *Decoder) (_ []{{ .Elem }}, changed bool) {
func (_ fastpathT) {{ .MethodNamePfx "Dec" false }}V(v []{{ .Elem }}, canChange bool, d *Decoder) (_ []{{ .Elem }}, changed bool) {
dd := d.d
{{/* // if dd.isContainerType(valueTypeNil) { dd.TryDecodeAsNil() */}}
if checkNil && dd.TryDecodeAsNil() {
if v != nil {
changed = true
}
return nil, changed
}
slh, containerLenS := d.decSliceHelperStart()
if containerLenS == 0 {
if canChange {
if v == nil {
if v == nil {
v = []{{ .Elem }}{}
} else if len(v) != 0 {
v = v[:0]
@@ -346,98 +336,62 @@ func (_ fastpathT) {{ .MethodNamePfx "Dec" false }}V(v []{{ .Elem }}, checkNil b
slh.End()
return v, changed
}
if containerLenS > 0 {
x2read := containerLenS
var xtrunc bool
hasLen := containerLenS > 0
var xlen int
if hasLen && canChange {
if containerLenS > cap(v) {
if canChange { {{/*
// fast-path is for "basic" immutable types, so no need to copy them over
// s := make([]{{ .Elem }}, decInferLen(containerLenS, d.h.MaxInitLen))
// copy(s, v[:cap(v)])
// v = s */}}
var xlen int
xlen, xtrunc = decInferLen(containerLenS, d.h.MaxInitLen, {{ .Size }})
if xtrunc {
if xlen <= cap(v) {
v = v[:xlen]
} else {
v = make([]{{ .Elem }}, xlen)
}
} else {
v = make([]{{ .Elem }}, xlen)
}
changed = true
xlen = decInferLen(containerLenS, d.h.MaxInitLen, {{ .Size }})
if xlen <= cap(v) {
v = v[:xlen]
} else {
d.arrayCannotExpand(len(v), containerLenS)
v = make([]{{ .Elem }}, xlen)
}
x2read = len(v)
changed = true
} else if containerLenS != len(v) {
if canChange {
v = v[:containerLenS]
changed = true
}
} {{/* // all checks done. cannot go past len. */}}
j := 0
for ; j < x2read; j++ {
slh.ElemContainerState(j)
{{ if eq .Elem "interface{}" }}d.decode(&v[j]){{ else }}v[j] = {{ decmd .Elem }}{{ end }}
}
if xtrunc { {{/* // means canChange=true, changed=true already. */}}
for ; j < containerLenS; j++ {
v = append(v, {{ zerocmd .Elem }})
slh.ElemContainerState(j)
{{ if eq .Elem "interface{}" }}d.decode(&v[j]){{ else }}v[j] = {{ decmd .Elem }}{{ end }}
}
} else if !canChange {
for ; j < containerLenS; j++ {
slh.ElemContainerState(j)
d.swallow()
}
}
} else {
breakFound := dd.CheckBreak() {{/* check break first, so we can initialize v with a capacity of 4 if necessary */}}
if breakFound {
if canChange {
if v == nil {
v = []{{ .Elem }}{}
} else if len(v) != 0 {
v = v[:0]
}
changed = true
}
slh.End()
return v, changed
}
if cap(v) == 0 {
v = make([]{{ .Elem }}, 1, 4)
changed = true
}
j := 0
for ; !breakFound; j++ {
if j >= len(v) {
if canChange {
v = append(v, {{ zerocmd .Elem }})
changed = true
} else {
d.arrayCannotExpand(len(v), j+1)
}
}
slh.ElemContainerState(j)
if j < len(v) { {{/* // all checks done. cannot go past len. */}}
{{ if eq .Elem "interface{}" }}d.decode(&v[j])
{{ else }}v[j] = {{ decmd .Elem }}{{ end }}
} else {
d.swallow()
}
breakFound = dd.CheckBreak()
}
if canChange && j < len(v) {
v = v[:j]
v = v[:containerLenS]
changed = true
}
}
slh.End()
j := 0
for ; (hasLen && j < containerLenS) || !(hasLen || dd.CheckBreak()); j++ {
if j == 0 && len(v) == 0 {
if hasLen {
xlen = decInferLen(containerLenS, d.h.MaxInitLen, {{ .Size }})
} else {
xlen = 8
}
v = make([]{{ .Elem }}, xlen)
changed = true
}
// if indefinite, etc, then expand the slice if necessary
var decodeIntoBlank bool
if j >= len(v) {
if canChange {
v = append(v, {{ zerocmd .Elem }})
changed = true
} else {
d.arrayCannotExpand(len(v), j+1)
decodeIntoBlank = true
}
}
slh.ElemContainerState(j)
if decodeIntoBlank {
d.swallow()
} else {
{{ if eq .Elem "interface{}" }}d.decode(&v[j]){{ else }}v[j] = {{ decmd .Elem }}{{ end }}
}
}
if canChange {
if j < len(v) {
v = v[:j]
changed = true
} else if j == 0 && v == nil {
v = make([]{{ .Elem }}, 0)
changed = true
}
}
slh.End()
return v, changed
}
@@ -450,77 +404,58 @@ Maps can change if they are
- addressable (from a ptr)
- settable (e.g. contained in an interface{})
*/}}
func (f *decFnInfo) {{ .MethodNamePfx "fastpathDec" false }}R(rv reflect.Value) {
if rv.CanAddr() {
vp := rv.Addr().Interface().(*map[{{ .MapKey }}]{{ .Elem }})
v, changed := fastpathTV.{{ .MethodNamePfx "Dec" false }}V(*vp, fastpathCheckNilFalse, true, f.d)
if changed {
func (d *Decoder) {{ .MethodNamePfx "fastpathDec" false }}R(f *codecFnInfo, rv reflect.Value) {
if rv.Kind() == reflect.Ptr {
vp := rv2i(rv).(*map[{{ .MapKey }}]{{ .Elem }})
if v, changed := fastpathTV.{{ .MethodNamePfx "Dec" false }}V(*vp, true, d); changed {
*vp = v
}
} else {
v := rv.Interface().(map[{{ .MapKey }}]{{ .Elem }})
fastpathTV.{{ .MethodNamePfx "Dec" false }}V(v, fastpathCheckNilFalse, false, f.d)
return
}
fastpathTV.{{ .MethodNamePfx "Dec" false }}V(rv2i(rv).(map[{{ .MapKey }}]{{ .Elem }}), false, d)
}
func (f fastpathT) {{ .MethodNamePfx "Dec" false }}X(vp *map[{{ .MapKey }}]{{ .Elem }}, checkNil bool, d *Decoder) {
v, changed := f.{{ .MethodNamePfx "Dec" false }}V(*vp, checkNil, true, d)
if changed {
func (f fastpathT) {{ .MethodNamePfx "Dec" false }}X(vp *map[{{ .MapKey }}]{{ .Elem }}, d *Decoder) {
if v, changed := f.{{ .MethodNamePfx "Dec" false }}V(*vp, true, d); changed {
*vp = v
}
}
func (_ fastpathT) {{ .MethodNamePfx "Dec" false }}V(v map[{{ .MapKey }}]{{ .Elem }}, checkNil bool, canChange bool,
func (_ fastpathT) {{ .MethodNamePfx "Dec" false }}V(v map[{{ .MapKey }}]{{ .Elem }}, canChange bool,
d *Decoder) (_ map[{{ .MapKey }}]{{ .Elem }}, changed bool) {
dd := d.d
cr := d.cr
dd, esep := d.d, d.hh.hasElemSeparators()
{{/* // if dd.isContainerType(valueTypeNil) {dd.TryDecodeAsNil() */}}
if checkNil && dd.TryDecodeAsNil() {
if v != nil {
changed = true
}
return nil, changed
}
containerLen := dd.ReadMapStart()
if canChange && v == nil {
xlen, _ := decInferLen(containerLen, d.h.MaxInitLen, {{ .Size }})
xlen := decInferLen(containerLen, d.h.MaxInitLen, {{ .Size }})
v = make(map[{{ .MapKey }}]{{ .Elem }}, xlen)
changed = true
}
if containerLen == 0 {
dd.ReadMapEnd()
return v, changed
}
{{ if eq .Elem "interface{}" }}mapGet := !d.h.MapValueReset && !d.h.InterfaceReset{{end}}
var mk {{ .MapKey }}
var mv {{ .Elem }}
if containerLen > 0 {
for j := 0; j < containerLen; j++ {
if cr != nil { cr.sendContainerState(containerMapKey) }
{{ if eq .MapKey "interface{}" }}mk = nil
d.decode(&mk)
if bv, bok := mk.([]byte); bok {
mk = d.string(bv) {{/* // maps cannot have []byte as key. switch to string. */}}
}{{ else }}mk = {{ decmd .MapKey }}{{ end }}
if cr != nil { cr.sendContainerState(containerMapValue) }
{{ if eq .Elem "interface{}" }}if mapGet { mv = v[mk] } else { mv = nil }
d.decode(&mv){{ else }}mv = {{ decmd .Elem }}{{ end }}
if v != nil {
v[mk] = mv
}
hasLen := containerLen > 0
for j := 0; (hasLen && j < containerLen) || !(hasLen || dd.CheckBreak()); j++ {
if esep { dd.ReadMapElemKey() }
{{ if eq .MapKey "interface{}" }}mk = nil
d.decode(&mk)
if bv, bok := mk.([]byte); bok {
mk = d.string(bv) {{/* // maps cannot have []byte as key. switch to string. */}}
}{{ else }}mk = {{ decmd .MapKey }}{{ end }}
if esep { dd.ReadMapElemValue() }
if dd.TryDecodeAsNil() {
if d.h.DeleteOnNilMapValue { delete(v, mk) } else { v[mk] = {{ zerocmd .Elem }} }
continue
}
} else if containerLen < 0 {
for j := 0; !dd.CheckBreak(); j++ {
if cr != nil { cr.sendContainerState(containerMapKey) }
{{ if eq .MapKey "interface{}" }}mk = nil
d.decode(&mk)
if bv, bok := mk.([]byte); bok {
mk = d.string(bv) {{/* // maps cannot have []byte as key. switch to string. */}}
}{{ else }}mk = {{ decmd .MapKey }}{{ end }}
if cr != nil { cr.sendContainerState(containerMapValue) }
{{ if eq .Elem "interface{}" }}if mapGet { mv = v[mk] } else { mv = nil }
d.decode(&mv){{ else }}mv = {{ decmd .Elem }}{{ end }}
if v != nil {
v[mk] = mv
}
{{ if eq .Elem "interface{}" }}if mapGet { mv = v[mk] } else { mv = nil }
d.decode(&mv){{ else }}mv = {{ decmd .Elem }}{{ end }}
if v != nil {
v[mk] = mv
}
}
if cr != nil { cr.sendContainerState(containerMapEnd) }
dd.ReadMapEnd()
return v, changed
}

View File

@@ -14,17 +14,18 @@ const fastpathEnabled = false
// This tag disables fastpath during build, allowing for faster build, test execution,
// short-program runs, etc.
func fastpathDecodeTypeSwitch(iv interface{}, d *Decoder) bool { return false }
func fastpathEncodeTypeSwitch(iv interface{}, e *Encoder) bool { return false }
func fastpathEncodeTypeSwitchSlice(iv interface{}, e *Encoder) bool { return false }
func fastpathEncodeTypeSwitchMap(iv interface{}, e *Encoder) bool { return false }
func fastpathDecodeTypeSwitch(iv interface{}, d *Decoder) bool { return false }
func fastpathEncodeTypeSwitch(iv interface{}, e *Encoder) bool { return false }
func fastpathEncodeTypeSwitchSlice(iv interface{}, e *Encoder) bool { return false }
func fastpathEncodeTypeSwitchMap(iv interface{}, e *Encoder) bool { return false }
func fastpathDecodeSetZeroTypeSwitch(iv interface{}, d *Decoder) bool { return false }
type fastpathT struct{}
type fastpathE struct {
rtid uintptr
rt reflect.Type
encfn func(*encFnInfo, reflect.Value)
decfn func(*decFnInfo, reflect.Value)
encfn func(*Encoder, *codecFnInfo, reflect.Value)
decfn func(*Decoder, *codecFnInfo, reflect.Value)
}
type fastpathA [0]fastpathE

View File

@@ -13,92 +13,65 @@ if {{var "l"}} == 0 {
{{var "v"}} = make({{ .CTyp }}, 0)
{{var "c"}} = true
} {{end}}
} else if {{var "l"}} > 0 {
{{if isChan }}if {{var "v"}} == nil {
{{var "rl"}}, _ = z.DecInferLen({{var "l"}}, z.DecBasicHandle().MaxInitLen, {{ .Size }})
{{var "v"}} = make({{ .CTyp }}, {{var "rl"}})
{{var "c"}} = true
}
for {{var "r"}} := 0; {{var "r"}} < {{var "l"}}; {{var "r"}}++ {
{{var "h"}}.ElemContainerState({{var "r"}})
var {{var "t"}} {{ .Typ }}
{{ $x := printf "%st%s" .TempVar .Rand }}{{ decLineVar $x }}
{{var "v"}} <- {{var "t"}}
}
{{ else }} var {{var "rr"}}, {{var "rl"}} int {{/* // num2read, length of slice/array/chan */}}
var {{var "rt"}} bool {{/* truncated */}}
_, _ = {{var "rl"}}, {{var "rt"}}
{{var "rr"}} = {{var "l"}} // len({{var "v"}})
} else {
{{var "hl"}} := {{var "l"}} > 0
var {{var "rl"}} int; _ = {{var "rl"}}
{{if isSlice }} if {{var "hl"}} {
if {{var "l"}} > cap({{var "v"}}) {
{{if isArray }}z.DecArrayCannotExpand(len({{var "v"}}), {{var "l"}})
{{ else }}{{if not .Immutable }}
{{var "rg"}} := len({{var "v"}}) > 0
{{var "v2"}} := {{var "v"}} {{end}}
{{var "rl"}}, {{var "rt"}} = z.DecInferLen({{var "l"}}, z.DecBasicHandle().MaxInitLen, {{ .Size }})
if {{var "rt"}} {
if {{var "rl"}} <= cap({{var "v"}}) {
{{var "v"}} = {{var "v"}}[:{{var "rl"}}]
} else {
{{var "v"}} = make([]{{ .Typ }}, {{var "rl"}})
}
{{var "rl"}} = z.DecInferLen({{var "l"}}, z.DecBasicHandle().MaxInitLen, {{ .Size }})
if {{var "rl"}} <= cap({{var "v"}}) {
{{var "v"}} = {{var "v"}}[:{{var "rl"}}]
} else {
{{var "v"}} = make([]{{ .Typ }}, {{var "rl"}})
}
{{var "c"}} = true
{{var "rr"}} = len({{var "v"}}) {{if not .Immutable }}
if {{var "rg"}} { copy({{var "v"}}, {{var "v2"}}) } {{end}} {{end}}{{/* end not Immutable, isArray */}}
} {{if isSlice }} else if {{var "l"}} != len({{var "v"}}) {
} else if {{var "l"}} != len({{var "v"}}) {
{{var "v"}} = {{var "v"}}[:{{var "l"}}]
{{var "c"}} = true
} {{end}} {{/* end isSlice:47 */}}
{{var "j"}} := 0
for ; {{var "j"}} < {{var "rr"}} ; {{var "j"}}++ {
{{var "h"}}.ElemContainerState({{var "j"}})
{{ $x := printf "%[1]vv%[2]v[%[1]vj%[2]v]" .TempVar .Rand }}{{ decLineVar $x }}
}
{{if isArray }}for ; {{var "j"}} < {{var "l"}} ; {{var "j"}}++ {
} {{end}}
var {{var "j"}} int
// var {{var "dn"}} bool
for ; ({{var "hl"}} && {{var "j"}} < {{var "l"}}) || !({{var "hl"}} || r.CheckBreak()); {{var "j"}}++ {
{{if not isArray}} if {{var "j"}} == 0 && len({{var "v"}}) == 0 {
if {{var "hl"}} {
{{var "rl"}} = z.DecInferLen({{var "l"}}, z.DecBasicHandle().MaxInitLen, {{ .Size }})
} else {
{{var "rl"}} = 8
}
{{var "v"}} = make([]{{ .Typ }}, {{var "rl"}})
{{var "c"}} = true
}{{end}}
{{var "h"}}.ElemContainerState({{var "j"}})
z.DecSwallow()
}
{{ else }}if {{var "rt"}} {
for ; {{var "j"}} < {{var "l"}} ; {{var "j"}}++ {
{{var "v"}} = append({{var "v"}}, {{ zero}})
{{var "h"}}.ElemContainerState({{var "j"}})
{{ $x := printf "%[1]vv%[2]v[%[1]vj%[2]v]" .TempVar .Rand }}{{ decLineVar $x }}
}
} {{end}} {{/* end isArray:56 */}}
{{end}} {{/* end isChan:16 */}}
} else { {{/* len < 0 */}}
{{var "j"}} := 0
for ; !r.CheckBreak(); {{var "j"}}++ {
{{if isChan }}
{{var "h"}}.ElemContainerState({{var "j"}})
var {{var "t"}} {{ .Typ }}
{{ $x := printf "%st%s" .TempVar .Rand }}{{ decLineVar $x }}
{{var "v"}} <- {{var "t"}}
{{ else }}
// {{var "dn"}} = r.TryDecodeAsNil()
{{if isChan}}{{ $x := printf "%[1]vv%[2]v" .TempVar .Rand }}var {{var $x}} {{ .Typ }}
{{ decLineVar $x }}
{{var "v"}} <- {{ $x }}
{{else}}
// if indefinite, etc, then expand the slice if necessary
var {{var "db"}} bool
if {{var "j"}} >= len({{var "v"}}) {
{{if isArray }}z.DecArrayCannotExpand(len({{var "v"}}), {{var "j"}}+1)
{{ else }}{{var "v"}} = append({{var "v"}}, {{zero}})// var {{var "z"}} {{ .Typ }}
{{var "c"}} = true {{end}}
{{if isSlice }} {{var "v"}} = append({{var "v"}}, {{ zero }}); {{var "c"}} = true
{{else}} z.DecArrayCannotExpand(len(v), {{var "j"}}+1); {{var "db"}} = true
{{end}}
}
{{var "h"}}.ElemContainerState({{var "j"}})
if {{var "j"}} < len({{var "v"}}) {
{{ $x := printf "%[1]vv%[2]v[%[1]vj%[2]v]" .TempVar .Rand }}{{ decLineVar $x }}
} else {
if {{var "db"}} {
z.DecSwallow()
} else {
{{ $x := printf "%[1]vv%[2]v[%[1]vj%[2]v]" .TempVar .Rand }}{{ decLineVar $x }}
}
{{end}}
{{end}}
}
{{if isSlice }}if {{var "j"}} < len({{var "v"}}) {
{{if isSlice}} if {{var "j"}} < len({{var "v"}}) {
{{var "v"}} = {{var "v"}}[:{{var "j"}}]
{{var "c"}} = true
} else if {{var "j"}} == 0 && {{var "v"}} == nil {
{{var "v"}} = []{{ .Typ }}{}
{{var "v"}} = make([]{{ .Typ }}, 0)
{{var "c"}} = true
}{{end}}
} {{end}}
}
{{var "h"}}.End()
{{if not isArray }}if {{var "c"}} {
*{{ .Varname }} = {{var "v"}}
}{{end}}

View File

@@ -2,21 +2,22 @@
{{var "l"}} := r.ReadMapStart()
{{var "bh"}} := z.DecBasicHandle()
if {{var "v"}} == nil {
{{var "rl"}}, _ := z.DecInferLen({{var "l"}}, {{var "bh"}}.MaxInitLen, {{ .Size }})
{{var "rl"}} := z.DecInferLen({{var "l"}}, {{var "bh"}}.MaxInitLen, {{ .Size }})
{{var "v"}} = make(map[{{ .KTyp }}]{{ .Typ }}, {{var "rl"}})
*{{ .Varname }} = {{var "v"}}
}
var {{var "mk"}} {{ .KTyp }}
var {{var "mv"}} {{ .Typ }}
var {{var "mg"}} {{if decElemKindPtr}}, {{var "ms"}}, {{var "mok"}}{{end}} bool
var {{var "mg"}}, {{var "mdn"}} {{if decElemKindPtr}}, {{var "ms"}}, {{var "mok"}}{{end}} bool
if {{var "bh"}}.MapValueReset {
{{if decElemKindPtr}}{{var "mg"}} = true
{{else if decElemKindIntf}}if !{{var "bh"}}.InterfaceReset { {{var "mg"}} = true }
{{else if not decElemKindImmutable}}{{var "mg"}} = true
{{end}} }
if {{var "l"}} > 0 {
for {{var "j"}} := 0; {{var "j"}} < {{var "l"}}; {{var "j"}}++ {
z.DecSendContainerState(codecSelfer_containerMapKey{{ .Sfx }})
if {{var "l"}} != 0 {
{{var "hl"}} := {{var "l"}} > 0
for {{var "j"}} := 0; ({{var "hl"}} && {{var "j"}} < {{var "l"}}) || !({{var "hl"}} || r.CheckBreak()); {{var "j"}}++ {
r.ReadMapElemKey() {{/* z.DecSendContainerState(codecSelfer_containerMapKey{{ .Sfx }}) */}}
{{ $x := printf "%vmk%v" .TempVar .Rand }}{{ decLineVarK $x }}
{{ if eq .KTyp "interface{}" }}{{/* // special case if a byte array. */}}if {{var "bv"}}, {{var "bok"}} := {{var "mk"}}.([]byte); {{var "bok"}} {
{{var "mk"}} = string({{var "bv"}})
@@ -28,31 +29,14 @@ for {{var "j"}} := 0; {{var "j"}} < {{var "l"}}; {{var "j"}}++ {
{{var "ms"}} = false
} {{else}}{{var "mv"}} = {{var "v"}}[{{var "mk"}}] {{end}}
} {{if not decElemKindImmutable}}else { {{var "mv"}} = {{decElemZero}} }{{end}}
z.DecSendContainerState(codecSelfer_containerMapValue{{ .Sfx }})
{{ $x := printf "%vmv%v" .TempVar .Rand }}{{ decLineVar $x }}
if {{if decElemKindPtr}} {{var "ms"}} && {{end}} {{var "v"}} != nil {
{{var "v"}}[{{var "mk"}}] = {{var "mv"}}
}
}
} else if {{var "l"}} < 0 {
for {{var "j"}} := 0; !r.CheckBreak(); {{var "j"}}++ {
z.DecSendContainerState(codecSelfer_containerMapKey{{ .Sfx }})
{{ $x := printf "%vmk%v" .TempVar .Rand }}{{ decLineVarK $x }}
{{ if eq .KTyp "interface{}" }}{{/* // special case if a byte array. */}}if {{var "bv"}}, {{var "bok"}} := {{var "mk"}}.([]byte); {{var "bok"}} {
{{var "mk"}} = string({{var "bv"}})
}{{ end }}{{if decElemKindPtr}}
{{var "ms"}} = true {{ end }}
if {{var "mg"}} {
{{if decElemKindPtr}}{{var "mv"}}, {{var "mok"}} = {{var "v"}}[{{var "mk"}}]
if {{var "mok"}} {
{{var "ms"}} = false
} {{else}}{{var "mv"}} = {{var "v"}}[{{var "mk"}}] {{end}}
} {{if not decElemKindImmutable}}else { {{var "mv"}} = {{decElemZero}} }{{end}}
z.DecSendContainerState(codecSelfer_containerMapValue{{ .Sfx }})
{{ $x := printf "%vmv%v" .TempVar .Rand }}{{ decLineVar $x }}
if {{if decElemKindPtr}} {{var "ms"}} && {{end}} {{var "v"}} != nil {
r.ReadMapElemValue() {{/* z.DecSendContainerState(codecSelfer_containerMapValue{{ .Sfx }}) */}}
{{var "mdn"}} = false
{{ $x := printf "%vmv%v" .TempVar .Rand }}{{ $y := printf "%vmdn%v" .TempVar .Rand }}{{ decLineVar $x $y }}
if {{var "mdn"}} {
if {{ var "bh" }}.DeleteOnNilMapValue { delete({{var "v"}}, {{var "mk"}}) } else { {{var "v"}}[{{var "mk"}}] = {{decElemZero}} }
} else if {{if decElemKindPtr}} {{var "ms"}} && {{end}} {{var "v"}} != nil {
{{var "v"}}[{{var "mk"}}] = {{var "mv"}}
}
}
} // else len==0: TODO: Should we clear map entries?
z.DecSendContainerState(codecSelfer_containerMapEnd{{ .Sfx }})
r.ReadMapEnd() {{/* z.DecSendContainerState(codecSelfer_containerMapEnd{{ .Sfx }}) */}}

View File

@@ -15,6 +15,9 @@ import (
"reflect"
)
// GenVersion is the current version of codecgen.
const GenVersion = 8
// 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
// library users. They WILL change continuously and without notice.
@@ -26,17 +29,24 @@ import (
// to perform encoding or decoding of primitives or known slice or map types.
// GenHelperEncoder is exported so that it can be used externally by codecgen.
//
// Library users: DO NOT USE IT DIRECTLY. IT WILL CHANGE CONTINOUSLY WITHOUT NOTICE.
func GenHelperEncoder(e *Encoder) (genHelperEncoder, encDriver) {
return genHelperEncoder{e: e}, e.e
}
// GenHelperDecoder is exported so that it can be used externally by codecgen.
//
// Library users: DO NOT USE IT DIRECTLY. IT WILL CHANGE CONTINOUSLY WITHOUT NOTICE.
func GenHelperDecoder(d *Decoder) (genHelperDecoder, decDriver) {
return genHelperDecoder{d: d}, d.d
}
// Library users: DO NOT USE IT DIRECTLY. IT WILL CHANGE CONTINOUSLY WITHOUT NOTICE.
func BasicHandleDoNotUse(h Handle) *BasicHandle {
return h.getBasicHandle()
}
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
type genHelperEncoder struct {
e *Encoder
@@ -56,13 +66,14 @@ func (f genHelperEncoder) EncBasicHandle() *BasicHandle {
// 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()
return f.e.cf.be // f.e.hh.isBinaryEncoding()
}
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperEncoder) EncFallback(iv interface{}) {
// println(">>>>>>>>> EncFallback")
f.e.encodeI(iv, false, false)
// f.e.encodeI(iv, false, false)
f.e.encodeValue(reflect.ValueOf(iv), nil, false)
}
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
@@ -85,7 +96,7 @@ func (f genHelperEncoder) EncBinaryMarshal(iv encoding.BinaryMarshaler) {
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperEncoder) EncRaw(iv Raw) {
f.e.raw(iv)
f.e.rawBytes(iv)
}
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
@@ -98,7 +109,7 @@ func (f genHelperEncoder) TimeRtidIfBinc() uintptr {
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperEncoder) IsJSONHandle() bool {
return f.e.js
return f.e.cf.js
}
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
@@ -112,7 +123,7 @@ func (f genHelperEncoder) EncExt(v interface{}) (r bool) {
if rt.Kind() == reflect.Ptr {
rt = rt.Elem()
}
rtid := reflect.ValueOf(rt).Pointer()
rtid := rt2id(rt)
if xfFn := f.e.h.getExt(rtid); xfFn != nil {
f.e.e.EncodeExt(v, xfFn.tag, xfFn.ext, f.e)
return true
@@ -120,13 +131,6 @@ func (f genHelperEncoder) EncExt(v interface{}) (r bool) {
return false
}
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperEncoder) EncSendContainerState(c containerState) {
if f.e.cr != nil {
f.e.cr.sendContainerState(c)
}
}
// ---------------- DECODER FOLLOWS -----------------
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
@@ -152,7 +156,12 @@ func (f genHelperDecoder) DecScratchBuffer() []byte {
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperDecoder) DecFallback(iv interface{}, chkPtr bool) {
// println(">>>>>>>>> DecFallback")
f.d.decodeI(iv, chkPtr, false, false, false)
rv := reflect.ValueOf(iv)
if chkPtr {
rv = f.d.ensureDecodeable(rv)
}
f.d.decodeValue(rv, nil, false, false)
// f.d.decodeValueFallback(rv)
}
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
@@ -172,7 +181,7 @@ func (f genHelperDecoder) DecArrayCannotExpand(sliceLen, streamLen int) {
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperDecoder) DecTextUnmarshal(tm encoding.TextUnmarshaler) {
fnerr := tm.UnmarshalText(f.d.d.DecodeBytes(f.d.b[:], true, true))
fnerr := tm.UnmarshalText(f.d.d.DecodeStringAsBytes())
if fnerr != nil {
panic(fnerr)
}
@@ -180,7 +189,7 @@ func (f genHelperDecoder) DecTextUnmarshal(tm encoding.TextUnmarshaler) {
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperDecoder) DecJSONUnmarshal(tm jsonUnmarshaler) {
// bs := f.dd.DecodeBytes(f.d.b[:], true, true)
// bs := f.dd.DecodeStringAsBytes()
// grab the bytes to be read, as UnmarshalJSON needs the full JSON so as to unmarshal it itself.
fnerr := tm.UnmarshalJSON(f.d.nextValueBytes())
if fnerr != nil {
@@ -190,7 +199,7 @@ func (f genHelperDecoder) DecJSONUnmarshal(tm jsonUnmarshaler) {
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperDecoder) DecBinaryUnmarshal(bm encoding.BinaryUnmarshaler) {
fnerr := bm.UnmarshalBinary(f.d.d.DecodeBytes(nil, false, true))
fnerr := bm.UnmarshalBinary(f.d.d.DecodeBytes(nil, true))
if fnerr != nil {
panic(fnerr)
}
@@ -198,7 +207,7 @@ func (f genHelperDecoder) DecBinaryUnmarshal(bm encoding.BinaryUnmarshaler) {
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperDecoder) DecRaw() []byte {
return f.d.raw()
return f.d.rawBytes()
}
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
@@ -222,7 +231,7 @@ func (f genHelperDecoder) HasExtensions() bool {
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperDecoder) DecExt(v interface{}) (r bool) {
rt := reflect.TypeOf(v).Elem()
rtid := reflect.ValueOf(rt).Pointer()
rtid := rt2id(rt)
if xfFn := f.d.h.getExt(rtid); xfFn != nil {
f.d.d.DecodeExt(v, xfFn.tag, xfFn.ext)
return true
@@ -231,13 +240,11 @@ func (f genHelperDecoder) DecExt(v interface{}) (r bool) {
}
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperDecoder) DecInferLen(clen, maxlen, unit int) (rvlen int, truncated bool) {
func (f genHelperDecoder) DecInferLen(clen, maxlen, unit int) (rvlen int) {
return decInferLen(clen, maxlen, unit)
}
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperDecoder) DecSendContainerState(c containerState) {
if f.d.cr != nil {
f.d.cr.sendContainerState(c)
}
func (f genHelperDecoder) StringView(v []byte) string {
return stringView(v)
}

View File

@@ -15,6 +15,9 @@ import (
"reflect"
)
// GenVersion is the current version of codecgen.
const GenVersion = {{ .Version }}
// 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
// library users. They WILL change continuously and without notice.
@@ -26,17 +29,24 @@ import (
// to perform encoding or decoding of primitives or known slice or map types.
// GenHelperEncoder is exported so that it can be used externally by codecgen.
//
// Library users: DO NOT USE IT DIRECTLY. IT WILL CHANGE CONTINOUSLY WITHOUT NOTICE.
func GenHelperEncoder(e *Encoder) (genHelperEncoder, encDriver) {
return genHelperEncoder{e:e}, e.e
}
// GenHelperDecoder is exported so that it can be used externally by codecgen.
//
// Library users: DO NOT USE IT DIRECTLY. IT WILL CHANGE CONTINOUSLY WITHOUT NOTICE.
func GenHelperDecoder(d *Decoder) (genHelperDecoder, decDriver) {
return genHelperDecoder{d:d}, d.d
}
// Library users: DO NOT USE IT DIRECTLY. IT WILL CHANGE CONTINOUSLY WITHOUT NOTICE.
func BasicHandleDoNotUse(h Handle) *BasicHandle {
return h.getBasicHandle()
}
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
type genHelperEncoder struct {
e *Encoder
@@ -56,12 +66,13 @@ func (f genHelperEncoder) EncBasicHandle() *BasicHandle {
// 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()
return f.e.cf.be // f.e.hh.isBinaryEncoding()
}
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperEncoder) EncFallback(iv interface{}) {
// println(">>>>>>>>> EncFallback")
f.e.encodeI(iv, false, false)
// f.e.encodeI(iv, false, false)
f.e.encodeValue(reflect.ValueOf(iv), nil, false)
}
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperEncoder) EncTextMarshal(iv encoding.TextMarshaler) {
@@ -80,7 +91,7 @@ func (f genHelperEncoder) EncBinaryMarshal(iv encoding.BinaryMarshaler) {
}
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperEncoder) EncRaw(iv Raw) {
f.e.raw(iv)
f.e.rawBytes(iv)
}
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperEncoder) TimeRtidIfBinc() uintptr {
@@ -91,7 +102,7 @@ func (f genHelperEncoder) TimeRtidIfBinc() uintptr {
}
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperEncoder) IsJSONHandle() bool {
return f.e.js
return f.e.cf.js
}
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperEncoder) HasExtensions() bool {
@@ -103,19 +114,21 @@ func (f genHelperEncoder) EncExt(v interface{}) (r bool) {
if rt.Kind() == reflect.Ptr {
rt = rt.Elem()
}
rtid := reflect.ValueOf(rt).Pointer()
rtid := rt2id(rt)
if xfFn := f.e.h.getExt(rtid); xfFn != nil {
f.e.e.EncodeExt(v, xfFn.tag, xfFn.ext, f.e)
return true
}
return false
}
{{/*
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperEncoder) EncSendContainerState(c containerState) {
if f.e.cr != nil {
f.e.cr.sendContainerState(c)
}
}
*/}}
// ---------------- DECODER FOLLOWS -----------------
@@ -138,7 +151,12 @@ func (f genHelperDecoder) DecScratchBuffer() []byte {
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperDecoder) DecFallback(iv interface{}, chkPtr bool) {
// println(">>>>>>>>> DecFallback")
f.d.decodeI(iv, chkPtr, false, false, false)
rv := reflect.ValueOf(iv)
if chkPtr {
rv = f.d.ensureDecodeable(rv)
}
f.d.decodeValue(rv, nil, false, false)
// f.d.decodeValueFallback(rv)
}
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperDecoder) DecSliceHelperStart() (decSliceHelper, int) {
@@ -154,14 +172,14 @@ func (f genHelperDecoder) DecArrayCannotExpand(sliceLen, streamLen int) {
}
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperDecoder) DecTextUnmarshal(tm encoding.TextUnmarshaler) {
fnerr := tm.UnmarshalText(f.d.d.DecodeBytes(f.d.b[:], true, true))
fnerr := tm.UnmarshalText(f.d.d.DecodeStringAsBytes())
if fnerr != nil {
panic(fnerr)
}
}
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperDecoder) DecJSONUnmarshal(tm jsonUnmarshaler) {
// bs := f.dd.DecodeBytes(f.d.b[:], true, true)
// bs := f.dd.DecodeStringAsBytes()
// grab the bytes to be read, as UnmarshalJSON needs the full JSON so as to unmarshal it itself.
fnerr := tm.UnmarshalJSON(f.d.nextValueBytes())
if fnerr != nil {
@@ -170,14 +188,14 @@ func (f genHelperDecoder) DecJSONUnmarshal(tm jsonUnmarshaler) {
}
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperDecoder) DecBinaryUnmarshal(bm encoding.BinaryUnmarshaler) {
fnerr := bm.UnmarshalBinary(f.d.d.DecodeBytes(nil, false, true))
fnerr := bm.UnmarshalBinary(f.d.d.DecodeBytes(nil, true))
if fnerr != nil {
panic(fnerr)
}
}
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperDecoder) DecRaw() []byte {
return f.d.raw()
return f.d.rawBytes()
}
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperDecoder) TimeRtidIfBinc() uintptr {
@@ -197,7 +215,7 @@ func (f genHelperDecoder) HasExtensions() bool {
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperDecoder) DecExt(v interface{}) (r bool) {
rt := reflect.TypeOf(v).Elem()
rtid := reflect.ValueOf(rt).Pointer()
rtid := rt2id(rt)
if xfFn := f.d.h.getExt(rtid); xfFn != nil {
f.d.d.DecodeExt(v, xfFn.tag, xfFn.ext)
return true
@@ -205,15 +223,21 @@ func (f genHelperDecoder) DecExt(v interface{}) (r bool) {
return false
}
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperDecoder) DecInferLen(clen, maxlen, unit int) (rvlen int, truncated bool) {
func (f genHelperDecoder) DecInferLen(clen, maxlen, unit int) (rvlen int) {
return decInferLen(clen, maxlen, unit)
}
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperDecoder) StringView(v []byte) string {
return stringView(v)
}
{{/*
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperDecoder) DecSendContainerState(c containerState) {
if f.d.cr != nil {
f.d.cr.sendContainerState(c)
}
}
*/}}
{{/*

View File

@@ -10,21 +10,22 @@ const genDecMapTmpl = `
{{var "l"}} := r.ReadMapStart()
{{var "bh"}} := z.DecBasicHandle()
if {{var "v"}} == nil {
{{var "rl"}}, _ := z.DecInferLen({{var "l"}}, {{var "bh"}}.MaxInitLen, {{ .Size }})
{{var "rl"}} := z.DecInferLen({{var "l"}}, {{var "bh"}}.MaxInitLen, {{ .Size }})
{{var "v"}} = make(map[{{ .KTyp }}]{{ .Typ }}, {{var "rl"}})
*{{ .Varname }} = {{var "v"}}
}
var {{var "mk"}} {{ .KTyp }}
var {{var "mv"}} {{ .Typ }}
var {{var "mg"}} {{if decElemKindPtr}}, {{var "ms"}}, {{var "mok"}}{{end}} bool
var {{var "mg"}}, {{var "mdn"}} {{if decElemKindPtr}}, {{var "ms"}}, {{var "mok"}}{{end}} bool
if {{var "bh"}}.MapValueReset {
{{if decElemKindPtr}}{{var "mg"}} = true
{{else if decElemKindIntf}}if !{{var "bh"}}.InterfaceReset { {{var "mg"}} = true }
{{else if not decElemKindImmutable}}{{var "mg"}} = true
{{end}} }
if {{var "l"}} > 0 {
for {{var "j"}} := 0; {{var "j"}} < {{var "l"}}; {{var "j"}}++ {
z.DecSendContainerState(codecSelfer_containerMapKey{{ .Sfx }})
if {{var "l"}} != 0 {
{{var "hl"}} := {{var "l"}} > 0
for {{var "j"}} := 0; ({{var "hl"}} && {{var "j"}} < {{var "l"}}) || !({{var "hl"}} || r.CheckBreak()); {{var "j"}}++ {
r.ReadMapElemKey() {{/* z.DecSendContainerState(codecSelfer_containerMapKey{{ .Sfx }}) */}}
{{ $x := printf "%vmk%v" .TempVar .Rand }}{{ decLineVarK $x }}
{{ if eq .KTyp "interface{}" }}{{/* // special case if a byte array. */}}if {{var "bv"}}, {{var "bok"}} := {{var "mk"}}.([]byte); {{var "bok"}} {
{{var "mk"}} = string({{var "bv"}})
@@ -36,34 +37,17 @@ for {{var "j"}} := 0; {{var "j"}} < {{var "l"}}; {{var "j"}}++ {
{{var "ms"}} = false
} {{else}}{{var "mv"}} = {{var "v"}}[{{var "mk"}}] {{end}}
} {{if not decElemKindImmutable}}else { {{var "mv"}} = {{decElemZero}} }{{end}}
z.DecSendContainerState(codecSelfer_containerMapValue{{ .Sfx }})
{{ $x := printf "%vmv%v" .TempVar .Rand }}{{ decLineVar $x }}
if {{if decElemKindPtr}} {{var "ms"}} && {{end}} {{var "v"}} != nil {
{{var "v"}}[{{var "mk"}}] = {{var "mv"}}
}
}
} else if {{var "l"}} < 0 {
for {{var "j"}} := 0; !r.CheckBreak(); {{var "j"}}++ {
z.DecSendContainerState(codecSelfer_containerMapKey{{ .Sfx }})
{{ $x := printf "%vmk%v" .TempVar .Rand }}{{ decLineVarK $x }}
{{ if eq .KTyp "interface{}" }}{{/* // special case if a byte array. */}}if {{var "bv"}}, {{var "bok"}} := {{var "mk"}}.([]byte); {{var "bok"}} {
{{var "mk"}} = string({{var "bv"}})
}{{ end }}{{if decElemKindPtr}}
{{var "ms"}} = true {{ end }}
if {{var "mg"}} {
{{if decElemKindPtr}}{{var "mv"}}, {{var "mok"}} = {{var "v"}}[{{var "mk"}}]
if {{var "mok"}} {
{{var "ms"}} = false
} {{else}}{{var "mv"}} = {{var "v"}}[{{var "mk"}}] {{end}}
} {{if not decElemKindImmutable}}else { {{var "mv"}} = {{decElemZero}} }{{end}}
z.DecSendContainerState(codecSelfer_containerMapValue{{ .Sfx }})
{{ $x := printf "%vmv%v" .TempVar .Rand }}{{ decLineVar $x }}
if {{if decElemKindPtr}} {{var "ms"}} && {{end}} {{var "v"}} != nil {
r.ReadMapElemValue() {{/* z.DecSendContainerState(codecSelfer_containerMapValue{{ .Sfx }}) */}}
{{var "mdn"}} = false
{{ $x := printf "%vmv%v" .TempVar .Rand }}{{ $y := printf "%vmdn%v" .TempVar .Rand }}{{ decLineVar $x $y }}
if {{var "mdn"}} {
if {{ var "bh" }}.DeleteOnNilMapValue { delete({{var "v"}}, {{var "mk"}}) } else { {{var "v"}}[{{var "mk"}}] = {{decElemZero}} }
} else if {{if decElemKindPtr}} {{var "ms"}} && {{end}} {{var "v"}} != nil {
{{var "v"}}[{{var "mk"}}] = {{var "mv"}}
}
}
} // else len==0: TODO: Should we clear map entries?
z.DecSendContainerState(codecSelfer_containerMapEnd{{ .Sfx }})
r.ReadMapEnd() {{/* z.DecSendContainerState(codecSelfer_containerMapEnd{{ .Sfx }}) */}}
`
const genDecListTmpl = `
@@ -82,94 +66,67 @@ if {{var "l"}} == 0 {
{{var "v"}} = make({{ .CTyp }}, 0)
{{var "c"}} = true
} {{end}}
} else if {{var "l"}} > 0 {
{{if isChan }}if {{var "v"}} == nil {
{{var "rl"}}, _ = z.DecInferLen({{var "l"}}, z.DecBasicHandle().MaxInitLen, {{ .Size }})
{{var "v"}} = make({{ .CTyp }}, {{var "rl"}})
{{var "c"}} = true
}
for {{var "r"}} := 0; {{var "r"}} < {{var "l"}}; {{var "r"}}++ {
{{var "h"}}.ElemContainerState({{var "r"}})
var {{var "t"}} {{ .Typ }}
{{ $x := printf "%st%s" .TempVar .Rand }}{{ decLineVar $x }}
{{var "v"}} <- {{var "t"}}
}
{{ else }} var {{var "rr"}}, {{var "rl"}} int {{/* // num2read, length of slice/array/chan */}}
var {{var "rt"}} bool {{/* truncated */}}
_, _ = {{var "rl"}}, {{var "rt"}}
{{var "rr"}} = {{var "l"}} // len({{var "v"}})
} else {
{{var "hl"}} := {{var "l"}} > 0
var {{var "rl"}} int; _ = {{var "rl"}}
{{if isSlice }} if {{var "hl"}} {
if {{var "l"}} > cap({{var "v"}}) {
{{if isArray }}z.DecArrayCannotExpand(len({{var "v"}}), {{var "l"}})
{{ else }}{{if not .Immutable }}
{{var "rg"}} := len({{var "v"}}) > 0
{{var "v2"}} := {{var "v"}} {{end}}
{{var "rl"}}, {{var "rt"}} = z.DecInferLen({{var "l"}}, z.DecBasicHandle().MaxInitLen, {{ .Size }})
if {{var "rt"}} {
if {{var "rl"}} <= cap({{var "v"}}) {
{{var "v"}} = {{var "v"}}[:{{var "rl"}}]
} else {
{{var "v"}} = make([]{{ .Typ }}, {{var "rl"}})
}
{{var "rl"}} = z.DecInferLen({{var "l"}}, z.DecBasicHandle().MaxInitLen, {{ .Size }})
if {{var "rl"}} <= cap({{var "v"}}) {
{{var "v"}} = {{var "v"}}[:{{var "rl"}}]
} else {
{{var "v"}} = make([]{{ .Typ }}, {{var "rl"}})
}
{{var "c"}} = true
{{var "rr"}} = len({{var "v"}}) {{if not .Immutable }}
if {{var "rg"}} { copy({{var "v"}}, {{var "v2"}}) } {{end}} {{end}}{{/* end not Immutable, isArray */}}
} {{if isSlice }} else if {{var "l"}} != len({{var "v"}}) {
} else if {{var "l"}} != len({{var "v"}}) {
{{var "v"}} = {{var "v"}}[:{{var "l"}}]
{{var "c"}} = true
} {{end}} {{/* end isSlice:47 */}}
{{var "j"}} := 0
for ; {{var "j"}} < {{var "rr"}} ; {{var "j"}}++ {
{{var "h"}}.ElemContainerState({{var "j"}})
{{ $x := printf "%[1]vv%[2]v[%[1]vj%[2]v]" .TempVar .Rand }}{{ decLineVar $x }}
}
{{if isArray }}for ; {{var "j"}} < {{var "l"}} ; {{var "j"}}++ {
} {{end}}
var {{var "j"}} int
// var {{var "dn"}} bool
for ; ({{var "hl"}} && {{var "j"}} < {{var "l"}}) || !({{var "hl"}} || r.CheckBreak()); {{var "j"}}++ {
{{if not isArray}} if {{var "j"}} == 0 && len({{var "v"}}) == 0 {
if {{var "hl"}} {
{{var "rl"}} = z.DecInferLen({{var "l"}}, z.DecBasicHandle().MaxInitLen, {{ .Size }})
} else {
{{var "rl"}} = 8
}
{{var "v"}} = make([]{{ .Typ }}, {{var "rl"}})
{{var "c"}} = true
}{{end}}
{{var "h"}}.ElemContainerState({{var "j"}})
z.DecSwallow()
}
{{ else }}if {{var "rt"}} {
for ; {{var "j"}} < {{var "l"}} ; {{var "j"}}++ {
{{var "v"}} = append({{var "v"}}, {{ zero}})
{{var "h"}}.ElemContainerState({{var "j"}})
{{ $x := printf "%[1]vv%[2]v[%[1]vj%[2]v]" .TempVar .Rand }}{{ decLineVar $x }}
}
} {{end}} {{/* end isArray:56 */}}
{{end}} {{/* end isChan:16 */}}
} else { {{/* len < 0 */}}
{{var "j"}} := 0
for ; !r.CheckBreak(); {{var "j"}}++ {
{{if isChan }}
{{var "h"}}.ElemContainerState({{var "j"}})
var {{var "t"}} {{ .Typ }}
{{ $x := printf "%st%s" .TempVar .Rand }}{{ decLineVar $x }}
{{var "v"}} <- {{var "t"}}
{{ else }}
// {{var "dn"}} = r.TryDecodeAsNil()
{{if isChan}}{{ $x := printf "%[1]vv%[2]v" .TempVar .Rand }}var {{var $x}} {{ .Typ }}
{{ decLineVar $x }}
{{var "v"}} <- {{ $x }}
{{else}}
// if indefinite, etc, then expand the slice if necessary
var {{var "db"}} bool
if {{var "j"}} >= len({{var "v"}}) {
{{if isArray }}z.DecArrayCannotExpand(len({{var "v"}}), {{var "j"}}+1)
{{ else }}{{var "v"}} = append({{var "v"}}, {{zero}})// var {{var "z"}} {{ .Typ }}
{{var "c"}} = true {{end}}
{{if isSlice }} {{var "v"}} = append({{var "v"}}, {{ zero }}); {{var "c"}} = true
{{else}} z.DecArrayCannotExpand(len(v), {{var "j"}}+1); {{var "db"}} = true
{{end}}
}
{{var "h"}}.ElemContainerState({{var "j"}})
if {{var "j"}} < len({{var "v"}}) {
{{ $x := printf "%[1]vv%[2]v[%[1]vj%[2]v]" .TempVar .Rand }}{{ decLineVar $x }}
} else {
if {{var "db"}} {
z.DecSwallow()
} else {
{{ $x := printf "%[1]vv%[2]v[%[1]vj%[2]v]" .TempVar .Rand }}{{ decLineVar $x }}
}
{{end}}
{{end}}
}
{{if isSlice }}if {{var "j"}} < len({{var "v"}}) {
{{if isSlice}} if {{var "j"}} < len({{var "v"}}) {
{{var "v"}} = {{var "v"}}[:{{var "j"}}]
{{var "c"}} = true
} else if {{var "j"}} == 0 && {{var "v"}} == nil {
{{var "v"}} = []{{ .Typ }}{}
{{var "v"}} = make([]{{ .Typ }}, 0)
{{var "c"}} = true
}{{end}}
} {{end}}
}
{{var "h"}}.End()
{{if not isArray }}if {{var "c"}} {
*{{ .Varname }} = {{var "v"}}
}{{end}}
`

View File

@@ -1,3 +1,5 @@
// +build codecgen.exec
// Copyright (c) 2012-2015 Ugorji Nwoke. All rights reserved.
// Use of this source code is governed by a MIT license found in the LICENSE file.
@@ -80,6 +82,10 @@ import (
// Note:
// It was a conscious decision to have gen.go always explicitly call EncodeNil or TryDecodeAsNil.
// This way, there isn't a function call overhead just to see that we should not enter a block of code.
//
// Note:
// codecgen-generated code depends on the variables defined by fast-path.generated.go.
// consequently, you cannot run with tags "codecgen notfastpath".
// GenVersion is the current version of codecgen.
//
@@ -94,7 +100,8 @@ import (
// 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.
const GenVersion = 5
// v6: removed unsafe from gen, and now uses codecgen.exec tag
const genVersion = 8
const (
genCodecPkg = "codec1978"
@@ -126,7 +133,6 @@ var (
genExpectArrayOrMapErr = errors.New("unexpected type. Expecting array/map/slice")
genBase64enc = base64.NewEncoding("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789__")
genQNameRegex = regexp.MustCompile(`[A-Za-z_.]+`)
genCheckVendor bool
)
// genRunner holds some state used during a Gen run.
@@ -147,8 +153,7 @@ type genRunner struct {
is map[reflect.Type]struct{} // types seen during import search
bp string // base PkgPath, for which we are generating for
cpfx string // codec package prefix
unsafe bool // is unsafe to be used in generated code?
cpfx string // codec package prefix
tm map[reflect.Type]struct{} // types for which enc/dec must be generated
ts []reflect.Type // types for which enc/dec must be generated
@@ -158,13 +163,16 @@ type genRunner struct {
ti *TypeInfos
// rr *rand.Rand // random generator for file-specific types
nx bool // no extensions
}
// Gen will write a complete go file containing Selfer implementations for each
// type passed. All the types must be in the same package.
//
// Library users: *DO NOT USE IT DIRECTLY. IT WILL CHANGE CONTINOUSLY WITHOUT NOTICE.*
func Gen(w io.Writer, buildTags, pkgName, uid string, useUnsafe bool, ti *TypeInfos, typ ...reflect.Type) {
// Library users: DO NOT USE IT DIRECTLY. IT WILL CHANGE CONTINOUSLY WITHOUT NOTICE.
func Gen(w io.Writer, buildTags, pkgName, uid string, noExtensions bool,
ti *TypeInfos, typ ...reflect.Type) {
// All types passed to this method do not have a codec.Selfer method implemented directly.
// codecgen already checks the AST and skips any types that define the codec.Selfer methods.
// Consequently, there's no need to check and trim them if they implement codec.Selfer
@@ -173,19 +181,19 @@ func Gen(w io.Writer, buildTags, pkgName, uid string, useUnsafe bool, ti *TypeIn
return
}
x := genRunner{
unsafe: useUnsafe,
w: w,
t: typ,
te: make(map[uintptr]bool),
td: make(map[uintptr]bool),
im: make(map[string]reflect.Type),
imn: make(map[string]string),
is: make(map[reflect.Type]struct{}),
tm: make(map[reflect.Type]struct{}),
ts: []reflect.Type{},
bp: genImportPath(typ[0]),
xs: uid,
ti: ti,
w: w,
t: typ,
te: make(map[uintptr]bool),
td: make(map[uintptr]bool),
im: make(map[string]reflect.Type),
imn: make(map[string]string),
is: make(map[reflect.Type]struct{}),
tm: make(map[reflect.Type]struct{}),
ts: []reflect.Type{},
bp: genImportPath(typ[0]),
xs: uid,
ti: ti,
nx: noExtensions,
}
if x.ti == nil {
x.ti = defTypeInfos
@@ -234,11 +242,8 @@ func Gen(w io.Writer, buildTags, pkgName, uid string, useUnsafe bool, ti *TypeIn
x.linef("%s \"%s\"", x.imn[k], k)
}
// add required packages
for _, k := range [...]string{"reflect", "unsafe", "runtime", "fmt", "errors"} {
for _, k := range [...]string{"reflect", "runtime", "fmt", "errors"} {
if _, ok := x.im[k]; !ok {
if k == "unsafe" && !x.unsafe {
continue
}
x.line("\"" + k + "\"")
}
}
@@ -265,20 +270,16 @@ func Gen(w io.Writer, buildTags, pkgName, uid string, useUnsafe bool, ti *TypeIn
x.line(")")
x.line("")
if x.unsafe {
x.line("type codecSelferUnsafeString" + x.xs + " struct { Data uintptr; Len int}")
x.line("")
}
x.hn = "codecSelfer" + x.xs
x.line("type " + x.hn + " struct{}")
x.line("")
x.varsfxreset()
x.line("func init() {")
x.linef("if %sGenVersion != %v {", x.cpfx, GenVersion)
x.linef("if %sGenVersion != %v {", x.cpfx, genVersion)
x.line("_, file, _, _ := runtime.Caller(0)")
x.line(`err := fmt.Errorf("codecgen version mismatch: current: %v, need %v. Re-generate file: %v", `)
x.linef(`%v, %sGenVersion, file)`, GenVersion, x.cpfx)
x.linef(`%v, %sGenVersion, file)`, genVersion, x.cpfx)
x.line("panic(err)")
x.linef("}")
x.line("if false { // reference the types, but skip this branch at build/run time")
@@ -289,10 +290,6 @@ func Gen(w io.Writer, buildTags, pkgName, uid string, useUnsafe bool, ti *TypeIn
x.linef("var v%v %s.%s", n, x.imn[k], t.Name())
n++
}
if x.unsafe {
x.linef("var v%v unsafe.Pointer", n)
n++
}
if n > 0 {
x.out("_")
for i := 1; i < n; i++ {
@@ -315,7 +312,7 @@ func Gen(w io.Writer, buildTags, pkgName, uid string, useUnsafe bool, ti *TypeIn
}
for _, t := range x.ts {
rtid := reflect.ValueOf(t).Pointer()
rtid := rt2id(t)
// generate enc functions for all these slice/map types.
x.varsfxreset()
x.linef("func (x %s) enc%s(v %s%s, e *%sEncoder) {", x.hn, x.genMethodNameT(t), x.arr2str(t, "*"), x.genTypeName(t), x.cpfx)
@@ -545,21 +542,21 @@ func (x *genRunner) selfer(encode bool) {
x.out(fnSigPfx)
x.line(") codecDecodeSelfFromMap(l int, d *" + x.cpfx + "Decoder) {")
x.genRequiredMethodVars(false)
x.decStructMap(genTopLevelVarName, "l", reflect.ValueOf(t0).Pointer(), t0, genStructMapStyleConsolidated)
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", reflect.ValueOf(t0).Pointer(), t0, genStructMapStyleLenPrefix)
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", reflect.ValueOf(t0).Pointer(), t0, genStructMapStyleCheckBreak)
x.decStructMap(genTopLevelVarName, "l", rt2id(t0), t0, genStructMapStyleCheckBreak)
x.line("}")
x.line("")
}
@@ -568,7 +565,7 @@ func (x *genRunner) selfer(encode bool) {
x.out(fnSigPfx)
x.line(") codecDecodeSelfFromArray(l int, d *" + x.cpfx + "Decoder) {")
x.genRequiredMethodVars(false)
x.decStructArray(genTopLevelVarName, "l", "return", reflect.ValueOf(t0).Pointer(), t0)
x.decStructArray(genTopLevelVarName, "l", "return", rt2id(t0), t0)
x.line("}")
x.line("")
@@ -645,7 +642,7 @@ func (x *genRunner) encVar(varname string, t reflect.Type) {
// enc will encode a variable (varname) of type t,
// except t is of kind reflect.Struct or reflect.Array, wherein varname is of type ptrTo(T) (to prevent copying)
func (x *genRunner) enc(varname string, t reflect.Type) {
rtid := reflect.ValueOf(t).Pointer()
rtid := rt2id(t)
// We call CodecEncodeSelf if one of the following are honored:
// - the type already implements Selfer, call that
// - the type has a Selfer implementation just created, use that
@@ -720,7 +717,7 @@ func (x *genRunner) enc(varname string, t reflect.Type) {
x.linef("r.EncodeBuiltin(%s, %s)", vrtid, varname)
}
// only check for extensions if the type is named, and has a packagePath.
if genImportPath(t) != "" && t.Name() != "" {
if !x.nx && genImportPath(t) != "" && t.Name() != "" {
// first check if extensions are configued, before doing the interface conversion
x.linef("} else if z.HasExtensions() && z.EncExt(%s) {", varname)
}
@@ -780,7 +777,7 @@ func (x *genRunner) enc(varname string, t reflect.Type) {
x.line("r.EncodeStringBytes(codecSelferC_RAW" + x.xs + ", []byte(" + varname + "))")
} else if fastpathAV.index(rtid) != -1 {
g := x.newGenV(t)
x.line("z.F." + g.MethodNamePfx("Enc", false) + "V(" + varname + ", false, e)")
x.line("z.F." + g.MethodNamePfx("Enc", false) + "V(" + varname + ", e)")
} else {
x.xtraSM(varname, true, t)
// x.encListFallback(varname, rtid, t)
@@ -794,7 +791,7 @@ func (x *genRunner) enc(varname string, t reflect.Type) {
// x.line("if " + varname + " == nil { \nr.EncodeNil()\n } else { ")
if fastpathAV.index(rtid) != -1 {
g := x.newGenV(t)
x.line("z.F." + g.MethodNamePfx("Enc", false) + "V(" + varname + ", false, e)")
x.line("z.F." + g.MethodNamePfx("Enc", false) + "V(" + varname + ", e)")
} else {
x.xtraSM(varname, true, t)
// x.encMapFallback(varname, rtid, t)
@@ -852,55 +849,64 @@ func (x *genRunner) encStruct(varname string, rtid uintptr, t reflect.Type) {
// number of non-empty things we write out first.
// This is required as we need to pre-determine the size of the container,
// to support length-prefixing.
x.linef("var %s [%v]bool", numfieldsvar, len(tisfi))
x.linef("_, _, _ = %s, %s, %s", sepVarname, numfieldsvar, struct2arrvar)
if ti.anyOmitEmpty {
x.linef("var %s [%v]bool", numfieldsvar, len(tisfi))
x.linef("_ = %s", numfieldsvar)
}
x.linef("_, _ = %s, %s", sepVarname, struct2arrvar)
x.linef("const %s bool = %v", ti2arrayvar, ti.toArray)
nn := 0
for j, si := range tisfi {
if !si.omitEmpty {
nn++
continue
}
var t2 reflect.StructField
var omitline string
if si.i != -1 {
t2 = t.Field(int(si.i))
} else {
t2typ := t
varname3 := varname
for _, ix := range si.is {
for t2typ.Kind() == reflect.Ptr {
t2typ = t2typ.Elem()
}
t2 = t2typ.Field(ix)
t2typ = t2.Type
varname3 = varname3 + "." + t2.Name
if t2typ.Kind() == reflect.Ptr {
omitline += varname3 + " != nil && "
var nn int
if ti.anyOmitEmpty {
for j, si := range tisfi {
if !si.omitEmpty {
nn++
continue
}
var t2 reflect.StructField
var omitline string
{
t2typ := t
varname3 := varname
for ij, ix := range si.is {
if uint8(ij) == si.nis {
break
}
for t2typ.Kind() == reflect.Ptr {
t2typ = t2typ.Elem()
}
t2 = t2typ.Field(int(ix))
t2typ = t2.Type
varname3 = varname3 + "." + t2.Name
if t2typ.Kind() == reflect.Ptr {
omitline += varname3 + " != nil && "
}
}
}
// never 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)
switch t2.Type.Kind() {
case reflect.Struct:
omitline += " true"
case reflect.Map, reflect.Slice, reflect.Array, reflect.Chan:
omitline += "len(" + varname + "." + t2.Name + ") != 0"
default:
omitline += varname + "." + t2.Name + " != " + x.genZeroValueR(t2.Type)
}
x.linef("%s[%v] = %s", numfieldsvar, j, omitline)
}
// never 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)
switch t2.Type.Kind() {
case reflect.Struct:
omitline += " true"
case reflect.Map, reflect.Slice, reflect.Array, reflect.Chan:
omitline += "len(" + varname + "." + t2.Name + ") != 0"
default:
omitline += varname + "." + t2.Name + " != " + x.genZeroValueR(t2.Type)
}
x.linef("%s[%v] = %s", numfieldsvar, j, omitline)
}
x.linef("var %snn%s int", genTempVarPfx, i)
// x.linef("var %snn%s int", genTempVarPfx, i)
x.linef("if %s || %s {", ti2arrayvar, struct2arrvar) // if ti.toArray {
x.line("r.EncodeArrayStart(" + strconv.FormatInt(int64(len(tisfi)), 10) + ")")
x.linef("r.WriteArrayStart(%d)", len(tisfi))
x.linef("} else {") // if not ti.toArray
x.linef("%snn%s = %v", genTempVarPfx, i, nn)
x.linef("for _, b := range %s { if b { %snn%s++ } }", numfieldsvar, genTempVarPfx, i)
x.linef("r.EncodeMapStart(%snn%s)", genTempVarPfx, i)
x.linef("%snn%s = %v", genTempVarPfx, i, 0)
// x.line("r.EncodeMapStart(" + strconv.FormatInt(int64(len(tisfi)), 10) + ")")
if ti.anyOmitEmpty {
x.linef("var %snn%s = %v", genTempVarPfx, i, nn)
x.linef("for _, b := range %s { if b { %snn%s++ } }", numfieldsvar, genTempVarPfx, i)
x.linef("r.WriteMapStart(%snn%s)", genTempVarPfx, i)
x.linef("%snn%s = %v", genTempVarPfx, i, 0)
} else {
x.linef("r.WriteMapStart(%d)", len(tisfi))
}
x.line("}") // close if not StructToArray
for j, si := range tisfi {
@@ -908,17 +914,18 @@ func (x *genRunner) encStruct(varname string, rtid uintptr, t reflect.Type) {
isNilVarName := genTempVarPfx + "n" + i
var labelUsed bool
var t2 reflect.StructField
if si.i != -1 {
t2 = t.Field(int(si.i))
} else {
{
t2typ := t
varname3 := varname
for _, ix := range si.is {
for ij, ix := range si.is {
if uint8(ij) == si.nis {
break
}
// fmt.Printf("%%%% %v, ix: %v\n", t2typ, ix)
for t2typ.Kind() == reflect.Ptr {
t2typ = t2typ.Elem()
}
t2 = t2typ.Field(ix)
t2 = t2typ.Field(int(ix))
t2typ = t2.Type
varname3 = varname3 + "." + t2.Name
if t2typ.Kind() == reflect.Ptr {
@@ -941,9 +948,10 @@ func (x *genRunner) encStruct(varname string, rtid uintptr, t reflect.Type) {
x.linef("if %s || %s {", ti2arrayvar, struct2arrvar) // if ti.toArray
if labelUsed {
x.line("if " + isNilVarName + " { r.EncodeNil() } else { ")
x.linef("if %s { r.WriteArrayElem(); r.EncodeNil() } else { ", isNilVarName)
// x.linef("if %s { z.EncSendContainerState(codecSelfer_containerArrayElem%s); r.EncodeNil() } else { ", isNilVarName, x.xs)
}
x.linef("z.EncSendContainerState(codecSelfer_containerArrayElem%s)", x.xs)
x.line("r.WriteArrayElem()") // x.linef("z.EncSendContainerState(codecSelfer_containerArrayElem%s)", x.xs)
if si.omitEmpty {
x.linef("if %s[%v] {", numfieldsvar, j)
}
@@ -962,9 +970,9 @@ func (x *genRunner) encStruct(varname string, rtid uintptr, t reflect.Type) {
if si.omitEmpty {
x.linef("if %s[%v] {", numfieldsvar, j)
}
x.linef("z.EncSendContainerState(codecSelfer_containerMapKey%s)", x.xs)
x.line("r.WriteMapElemKey()") // x.linef("z.EncSendContainerState(codecSelfer_containerMapKey%s)", x.xs)
x.line("r.EncodeString(codecSelferC_UTF8" + x.xs + ", string(\"" + si.encName + "\"))")
x.linef("z.EncSendContainerState(codecSelfer_containerMapValue%s)", x.xs)
x.line("r.WriteMapElemValue()") // x.linef("z.EncSendContainerState(codecSelfer_containerMapValue%s)", x.xs)
if labelUsed {
x.line("if " + isNilVarName + " { r.EncodeNil() } else { ")
x.encVar(varname+"."+t2.Name, t2.Type)
@@ -978,9 +986,9 @@ func (x *genRunner) encStruct(varname string, rtid uintptr, t reflect.Type) {
x.linef("} ") // end if/else ti.toArray
}
x.linef("if %s || %s {", ti2arrayvar, struct2arrvar) // if ti.toArray {
x.linef("z.EncSendContainerState(codecSelfer_containerArrayEnd%s)", x.xs)
x.line("r.WriteArrayEnd()") // x.linef("z.EncSendContainerState(codecSelfer_containerArrayEnd%s)", x.xs)
x.line("} else {")
x.linef("z.EncSendContainerState(codecSelfer_containerMapEnd%s)", x.xs)
x.line("r.WriteMapEnd()") // x.linef("z.EncSendContainerState(codecSelfer_containerMapEnd%s)", x.xs)
x.line("}")
}
@@ -996,36 +1004,36 @@ func (x *genRunner) encListFallback(varname string, t reflect.Type) {
}
i := x.varsfx()
g := genTempVarPfx
x.line("r.EncodeArrayStart(len(" + varname + "))")
x.line("r.WriteArrayStart(len(" + varname + "))")
if t.Kind() == reflect.Chan {
x.linef("for %si%s, %si2%s := 0, len(%s); %si%s < %si2%s; %si%s++ {", g, i, g, i, varname, g, i, g, i, g, i)
x.linef("z.EncSendContainerState(codecSelfer_containerArrayElem%s)", x.xs)
x.line("r.WriteArrayElem()") // x.linef("z.EncSendContainerState(codecSelfer_containerArrayElem%s)", x.xs)
x.linef("%sv%s := <-%s", g, i, varname)
} else {
// x.linef("for %si%s, %sv%s := range %s {", genTempVarPfx, i, genTempVarPfx, i, varname)
x.linef("for _, %sv%s := range %s {", genTempVarPfx, i, varname)
x.linef("z.EncSendContainerState(codecSelfer_containerArrayElem%s)", x.xs)
x.line("r.WriteArrayElem()") // x.linef("z.EncSendContainerState(codecSelfer_containerArrayElem%s)", x.xs)
}
x.encVar(genTempVarPfx+"v"+i, t.Elem())
x.line("}")
x.linef("z.EncSendContainerState(codecSelfer_containerArrayEnd%s)", x.xs)
x.line("r.WriteArrayEnd()") // x.linef("z.EncSendContainerState(codecSelfer_containerArrayEnd%s)", x.xs)
}
func (x *genRunner) encMapFallback(varname string, t reflect.Type) {
// TODO: expand this to handle canonical.
i := x.varsfx()
x.line("r.EncodeMapStart(len(" + varname + "))")
x.line("r.WriteMapStart(len(" + varname + "))")
x.linef("for %sk%s, %sv%s := range %s {", genTempVarPfx, i, genTempVarPfx, i, varname)
// x.line("for " + genTempVarPfx + "k" + i + ", " + genTempVarPfx + "v" + i + " := range " + varname + " {")
x.linef("z.EncSendContainerState(codecSelfer_containerMapKey%s)", x.xs)
x.line("r.WriteMapElemKey()") // f("z.EncSendContainerState(codecSelfer_containerMapKey%s)", x.xs)
x.encVar(genTempVarPfx+"k"+i, t.Key())
x.linef("z.EncSendContainerState(codecSelfer_containerMapValue%s)", x.xs)
x.line("r.WriteMapElemValue()") // f("z.EncSendContainerState(codecSelfer_containerMapValue%s)", x.xs)
x.encVar(genTempVarPfx+"v"+i, t.Elem())
x.line("}")
x.linef("z.EncSendContainerState(codecSelfer_containerMapEnd%s)", x.xs)
x.line("r.WriteMapEnd()") // f("z.EncSendContainerState(codecSelfer_containerMapEnd%s)", x.xs)
}
func (x *genRunner) decVar(varname string, t reflect.Type, canBeNil bool) {
func (x *genRunner) decVar(varname, decodedNilVarname string, t reflect.Type, canBeNil bool) {
// We only encode as nil if a nillable value.
// This removes some of the wasted checks for TryDecodeAsNil.
// We need to think about this more, to see what happens if omitempty, etc
@@ -1038,7 +1046,9 @@ func (x *genRunner) decVar(varname string, t reflect.Type, canBeNil bool) {
}
if canBeNil {
x.line("if r.TryDecodeAsNil() {")
if t.Kind() == reflect.Ptr {
if decodedNilVarname != "" {
x.line(decodedNilVarname + " = true")
} else if t.Kind() == reflect.Ptr {
x.line("if " + varname + " != nil { ")
// if varname is a field of a struct (has a dot in it),
@@ -1098,7 +1108,7 @@ func (x *genRunner) dec(varname string, t reflect.Type) {
// assumptions:
// - the varname is to a pointer already. No need to take address of it
// - t is always a baseType T (not a *T, etc).
rtid := reflect.ValueOf(t).Pointer()
rtid := rt2id(t)
tptr := reflect.PtrTo(t)
if x.checkForSelfer(t, varname) {
if t.Implements(selferTyp) || tptr.Implements(selferTyp) {
@@ -1156,7 +1166,7 @@ func (x *genRunner) dec(varname string, t reflect.Type) {
x.linef("r.DecodeBuiltin(%s, %s)", vrtid, varname)
}
// only check for extensions if the type is named, and has a packagePath.
if genImportPath(t) != "" && t.Name() != "" {
if !x.nx && genImportPath(t) != "" && t.Name() != "" {
// first check if extensions are configued, before doing the interface conversion
x.linef("} else if z.HasExtensions() && z.DecExt(%s) {", varname)
}
@@ -1231,10 +1241,10 @@ func (x *genRunner) dec(varname string, t reflect.Type) {
// - if elements are primitives or Selfers, call dedicated function on each member.
// - else call Encoder.encode(XXX) on it.
if rtid == uint8SliceTypId {
x.line("*" + varname + " = r.DecodeBytes(*(*[]byte)(" + varname + "), false, false)")
x.line("*" + varname + " = r.DecodeBytes(*(*[]byte)(" + varname + "), false)")
} else if fastpathAV.index(rtid) != -1 {
g := x.newGenV(t)
x.line("z.F." + g.MethodNamePfx("Dec", false) + "X(" + varname + ", false, d)")
x.line("z.F." + g.MethodNamePfx("Dec", false) + "X(" + varname + ", d)")
} else {
x.xtraSM(varname, false, t)
// x.decListFallback(varname, rtid, false, t)
@@ -1246,7 +1256,7 @@ func (x *genRunner) dec(varname string, t reflect.Type) {
// - else call Encoder.encode(XXX) on it.
if fastpathAV.index(rtid) != -1 {
g := x.newGenV(t)
x.line("z.F." + g.MethodNamePfx("Dec", false) + "X(" + varname + ", false, d)")
x.line("z.F." + g.MethodNamePfx("Dec", false) + "X(" + varname + ", d)")
} else {
x.xtraSM(varname, false, t)
// x.decMapFallback(varname, rtid, t)
@@ -1318,11 +1328,11 @@ func (x *genRunner) decTryAssignPrimitive(varname string, t reflect.Type) (tryAs
func (x *genRunner) decListFallback(varname string, rtid uintptr, t reflect.Type) {
if t.AssignableTo(uint8SliceTyp) {
x.line("*" + varname + " = r.DecodeBytes(*((*[]byte)(" + varname + ")), false, false)")
x.line("*" + varname + " = r.DecodeBytes(*((*[]byte)(" + varname + ")), false)")
return
}
if t.Kind() == reflect.Array && t.Elem().Kind() == reflect.Uint8 {
x.linef("r.DecodeBytes( ((*[%s]byte)(%s))[:], false, true)", t.Len(), varname)
x.linef("r.DecodeBytes( ((*[%s]byte)(%s))[:], true)", t.Len(), varname)
return
}
type tstruc struct {
@@ -1340,13 +1350,13 @@ func (x *genRunner) decListFallback(varname string, rtid uintptr, t reflect.Type
funcs := make(template.FuncMap)
funcs["decLineVar"] = func(varname string) string {
x.decVar(varname, telem, false)
return ""
}
funcs["decLine"] = func(pfx string) string {
x.decVar(ts.TempVar+pfx+ts.Rand, reflect.PtrTo(telem), false)
x.decVar(varname, "", telem, false)
return ""
}
// funcs["decLine"] = func(pfx string) string {
// x.decVar(ts.TempVar+pfx+ts.Rand, "", reflect.PtrTo(telem), false)
// return ""
// }
funcs["var"] = func(s string) string {
return ts.TempVar + s + ts.Rand
}
@@ -1402,21 +1412,21 @@ func (x *genRunner) decMapFallback(varname string, rtid uintptr, t reflect.Type)
return telem.Kind() == reflect.Interface
}
funcs["decLineVarK"] = func(varname string) string {
x.decVar(varname, tkey, false)
x.decVar(varname, "", tkey, false)
return ""
}
funcs["decLineVar"] = func(varname string) string {
x.decVar(varname, telem, false)
return ""
}
funcs["decLineK"] = func(pfx string) string {
x.decVar(ts.TempVar+pfx+ts.Rand, reflect.PtrTo(tkey), false)
return ""
}
funcs["decLine"] = func(pfx string) string {
x.decVar(ts.TempVar+pfx+ts.Rand, reflect.PtrTo(telem), false)
funcs["decLineVar"] = func(varname, decodedNilVarname string) string {
x.decVar(varname, decodedNilVarname, telem, false)
return ""
}
// funcs["decLineK"] = func(pfx string) string {
// x.decVar(ts.TempVar+pfx+ts.Rand, reflect.PtrTo(tkey), false)
// return ""
// }
// funcs["decLine"] = func(pfx string) string {
// x.decVar(ts.TempVar+pfx+ts.Rand, reflect.PtrTo(telem), false)
// return ""
// }
funcs["var"] = func(s string) string {
return ts.TempVar + s + ts.Rand
}
@@ -1437,18 +1447,19 @@ func (x *genRunner) decStructMapSwitch(kName string, varname string, rtid uintpt
for _, si := range tisfi {
x.line("case \"" + si.encName + "\":")
var t2 reflect.StructField
if si.i != -1 {
t2 = t.Field(int(si.i))
} else {
{
//we must accommodate anonymous fields, where the embedded field is a nil pointer in the value.
// t2 = t.FieldByIndex(si.is)
t2typ := t
varname3 := varname
for _, ix := range si.is {
for ij, ix := range si.is {
if uint8(ij) == si.nis {
break
}
for t2typ.Kind() == reflect.Ptr {
t2typ = t2typ.Elem()
}
t2 = t2typ.Field(ix)
t2 = t2typ.Field(int(ix))
t2typ = t2.Type
varname3 = varname3 + "." + t2.Name
if t2typ.Kind() == reflect.Ptr {
@@ -1456,7 +1467,7 @@ func (x *genRunner) decStructMapSwitch(kName string, varname string, rtid uintpt
}
}
}
x.decVar(varname+"."+t2.Name, t2.Type, false)
x.decVar(varname+"."+t2.Name, "", t2.Type, false)
}
x.line("default:")
// pass the slice here, so that the string will not escape, and maybe save allocation
@@ -1469,17 +1480,6 @@ func (x *genRunner) decStructMap(varname, lenvarname string, rtid uintptr, t ref
i := x.varsfx()
kName := tpfx + "s" + i
// We thought to use ReadStringAsBytes, as go compiler might optimize the copy out.
// However, using that was more expensive, as it seems that the switch expression
// is evaluated each time.
//
// We could depend on decodeString using a temporary/shared buffer internally.
// However, this model of creating a byte array, and using explicitly is faster,
// and allows optional use of unsafe []byte->string conversion without alloc.
// Also, ensure that the slice array doesn't escape.
// That will help escape analysis prevent allocation when it gets better.
// x.line("var " + kName + "Arr = [32]byte{} // default string to decode into")
// x.line("var " + kName + "Slc = " + kName + "Arr[:] // default slice to decode into")
// use the scratch buffer to avoid allocation (most field names are < 32).
@@ -1498,21 +1498,15 @@ func (x *genRunner) decStructMap(varname, lenvarname string, rtid uintptr, t ref
x.linef("if %shl%s { if %sj%s >= %s { break }", tpfx, i, tpfx, i, lenvarname)
x.line("} else { if r.CheckBreak() { break }; }")
}
x.linef("z.DecSendContainerState(codecSelfer_containerMapKey%s)", x.xs)
x.line(kName + "Slc = r.DecodeBytes(" + kName + "Slc, true, true)")
x.line("r.ReadMapElemKey()") // f("z.DecSendContainerState(codecSelfer_containerMapKey%s)", x.xs)
x.line(kName + "Slc = r.DecodeStringAsBytes()")
// let string be scoped to this loop alone, so it doesn't escape.
if x.unsafe {
x.line(kName + "SlcHdr := codecSelferUnsafeString" + x.xs + "{uintptr(unsafe.Pointer(&" +
kName + "Slc[0])), len(" + kName + "Slc)}")
x.line(kName + " := *(*string)(unsafe.Pointer(&" + kName + "SlcHdr))")
} else {
x.line(kName + " := string(" + kName + "Slc)")
}
x.linef("z.DecSendContainerState(codecSelfer_containerMapValue%s)", x.xs)
x.line(kName + " := string(" + kName + "Slc)")
x.line("r.ReadMapElemValue()") // f("z.DecSendContainerState(codecSelfer_containerMapValue%s)", x.xs)
x.decStructMapSwitch(kName, varname, rtid, t)
x.line("} // end for " + tpfx + "j" + i)
x.linef("z.DecSendContainerState(codecSelfer_containerMapEnd%s)", x.xs)
x.line("r.ReadMapEnd()") // f("z.DecSendContainerState(codecSelfer_containerMapEnd%s)", x.xs)
}
func (x *genRunner) decStructArray(varname, lenvarname, breakString string, rtid uintptr, t reflect.Type) {
@@ -1525,18 +1519,19 @@ func (x *genRunner) decStructArray(varname, lenvarname, breakString string, rtid
x.linef("var %shl%s bool = %s >= 0", tpfx, i, lenvarname) // has length
for _, si := range tisfi {
var t2 reflect.StructField
if si.i != -1 {
t2 = t.Field(int(si.i))
} else {
{
//we must accommodate anonymous fields, where the embedded field is a nil pointer in the value.
// t2 = t.FieldByIndex(si.is)
t2typ := t
varname3 := varname
for _, ix := range si.is {
for ij, ix := range si.is {
if uint8(ij) == si.nis {
break
}
for t2typ.Kind() == reflect.Ptr {
t2typ = t2typ.Elem()
}
t2 = t2typ.Field(ix)
t2 = t2typ.Field(int(ix))
t2typ = t2.Type
varname3 = varname3 + "." + t2.Name
if t2typ.Kind() == reflect.Ptr {
@@ -1548,10 +1543,10 @@ func (x *genRunner) decStructArray(varname, lenvarname, breakString string, rtid
x.linef("%sj%s++; if %shl%s { %sb%s = %sj%s > %s } else { %sb%s = r.CheckBreak() }",
tpfx, i, tpfx, i, tpfx, i,
tpfx, i, lenvarname, tpfx, i)
x.linef("if %sb%s { z.DecSendContainerState(codecSelfer_containerArrayEnd%s); %s }",
tpfx, i, x.xs, breakString)
x.linef("z.DecSendContainerState(codecSelfer_containerArrayElem%s)", x.xs)
x.decVar(varname+"."+t2.Name, t2.Type, true)
x.linef("if %sb%s { r.ReadArrayEnd(); %s }", tpfx, i, breakString)
// x.linef("if %sb%s { z.DecSendContainerState(codecSelfer_containerArrayEnd%s); %s }", tpfx, i, x.xs, breakString)
x.line("r.ReadArrayElem()") // f("z.DecSendContainerState(codecSelfer_containerArrayElem%s)", x.xs)
x.decVar(varname+"."+t2.Name, "", t2.Type, true)
}
// read remaining values and throw away.
x.line("for {")
@@ -1559,10 +1554,10 @@ func (x *genRunner) decStructArray(varname, lenvarname, breakString string, rtid
tpfx, i, tpfx, i, tpfx, i,
tpfx, i, lenvarname, tpfx, i)
x.linef("if %sb%s { break }", tpfx, i)
x.linef("z.DecSendContainerState(codecSelfer_containerArrayElem%s)", x.xs)
x.line("r.ReadArrayElem()") // f("z.DecSendContainerState(codecSelfer_containerArrayElem%s)", x.xs)
x.linef(`z.DecStructFieldNotFound(%sj%s - 1, "")`, tpfx, i)
x.line("}")
x.linef("z.DecSendContainerState(codecSelfer_containerArrayEnd%s)", x.xs)
x.line("r.ReadArrayEnd()") // f("z.DecSendContainerState(codecSelfer_containerArrayEnd%s)", x.xs)
}
func (x *genRunner) decStruct(varname string, rtid uintptr, t reflect.Type) {
@@ -1572,7 +1567,7 @@ func (x *genRunner) decStruct(varname string, rtid uintptr, t reflect.Type) {
x.linef("if %sct%s == codecSelferValueTypeMap%s {", genTempVarPfx, i, x.xs)
x.line(genTempVarPfx + "l" + i + " := r.ReadMapStart()")
x.linef("if %sl%s == 0 {", genTempVarPfx, i)
x.linef("z.DecSendContainerState(codecSelfer_containerMapEnd%s)", x.xs)
x.line("r.ReadMapEnd()") // f("z.DecSendContainerState(codecSelfer_containerMapEnd%s)", x.xs)
if genUseOneFunctionForDecStructMap {
x.line("} else { ")
x.linef("x.codecDecodeSelfFromMap(%sl%s, d)", genTempVarPfx, i)
@@ -1588,7 +1583,7 @@ func (x *genRunner) decStruct(varname string, rtid uintptr, t reflect.Type) {
x.linef("} else if %sct%s == codecSelferValueTypeArray%s {", genTempVarPfx, i, x.xs)
x.line(genTempVarPfx + "l" + i + " := r.ReadArrayStart()")
x.linef("if %sl%s == 0 {", genTempVarPfx, i)
x.linef("z.DecSendContainerState(codecSelfer_containerArrayEnd%s)", x.xs)
x.line("r.ReadArrayEnd()") // f("z.DecSendContainerState(codecSelfer_containerArrayEnd%s)", x.xs)
x.line("} else { ")
x.linef("x.codecDecodeSelfFromArray(%sl%s, d)", genTempVarPfx, i)
x.line("}")
@@ -1653,15 +1648,8 @@ func (x *genV) MethodNamePfx(prefix string, prim bool) string {
func genImportPath(t reflect.Type) (s string) {
s = t.PkgPath()
if genCheckVendor {
// HACK: Misbehaviour occurs in go 1.5. May have to re-visit this later.
// if s contains /vendor/ OR startsWith vendor/, then return everything after it.
const vendorStart = "vendor/"
const vendorInline = "/vendor/"
if i := strings.LastIndex(s, vendorInline); i >= 0 {
s = s[i+len(vendorInline):]
} else if strings.HasPrefix(s, vendorStart) {
s = s[len(vendorStart):]
}
// HACK: always handle vendoring. It should be typically on in go 1.6, 1.7
s = stripVendor(s)
}
return
}
@@ -1783,8 +1771,8 @@ func genIsImmutable(t reflect.Type) (v bool) {
}
type genInternal struct {
Values []genV
Unsafe bool
Version int
Values []genV
}
func (x genInternal) FastpathLen() (l int) {
@@ -1884,8 +1872,21 @@ func genInternalSortType(s string, elem bool) string {
panic("sorttype: unexpected type: " + s)
}
func stripVendor(s string) string {
// HACK: Misbehaviour occurs in go 1.5. May have to re-visit this later.
// if s contains /vendor/ OR startsWith vendor/, then return everything after it.
const vendorStart = "vendor/"
const vendorInline = "/vendor/"
if i := strings.LastIndex(s, vendorInline); i >= 0 {
s = s[i+len(vendorInline):]
} else if strings.HasPrefix(s, vendorStart) {
s = s[len(vendorStart):]
}
return s
}
// var genInternalMu sync.Mutex
var genInternalV genInternal
var genInternalV = genInternal{Version: genVersion}
var genInternalTmplFuncs template.FuncMap
var genInternalOnce sync.Once
@@ -1948,7 +1949,7 @@ func genInternalInit() {
"float64": 8,
"bool": 1,
}
var gt genInternal
var gt = genInternal{Version: genVersion}
// For each slice or map type, there must be a (symmetrical) Encode and Decode fast-path function
for _, s := range types {
@@ -1980,11 +1981,10 @@ func genInternalInit() {
// It is run by the program author alone.
// Unfortunately, it has to be exported so that it can be called from a command line tool.
// *** DO NOT USE ***
func genInternalGoFile(r io.Reader, w io.Writer, safe bool) (err error) {
func genInternalGoFile(r io.Reader, w io.Writer) (err error) {
genInternalOnce.Do(genInternalInit)
gt := genInternalV
gt.Unsafe = !safe
t := template.New("").Funcs(genInternalTmplFuncs)

View File

@@ -9,8 +9,6 @@ import "reflect"
const reflectArrayOfSupported = true
func reflectArrayOf(rvn reflect.Value) (rvn2 reflect.Value) {
rvn2 = reflect.New(reflect.ArrayOf(rvn.Len(), intfTyp)).Elem()
reflect.Copy(rvn2, rvn)
return
func reflectArrayOf(count int, elem reflect.Type) reflect.Type {
return reflect.ArrayOf(count, elem)
}

View File

@@ -9,6 +9,6 @@ import "reflect"
const reflectArrayOfSupported = false
func reflectArrayOf(rvn reflect.Value) (rvn2 reflect.Value) {
panic("reflect.ArrayOf unsupported")
func reflectArrayOf(count int, elem reflect.Type) reflect.Type {
panic("codec: reflect.ArrayOf unsupported in this go version")
}

View File

@@ -0,0 +1,15 @@
// Copyright (c) 2012-2015 Ugorji Nwoke. All rights reserved.
// Use of this source code is governed by a MIT license found in the LICENSE file.
// +build go1.9
package codec
import "reflect"
func makeMapReflect(t reflect.Type, size int) reflect.Value {
if size < 0 {
return reflect.MakeMapWithSize(t, 4)
}
return reflect.MakeMapWithSize(t, size)
}

View File

@@ -0,0 +1,12 @@
// Copyright (c) 2012-2015 Ugorji Nwoke. All rights reserved.
// Use of this source code is governed by a MIT license found in the LICENSE file.
// +build !go1.9
package codec
import "reflect"
func makeMapReflect(t reflect.Type, size int) reflect.Value {
return reflect.MakeMap(t)
}

View File

@@ -0,0 +1,17 @@
// Copyright (c) 2012-2015 Ugorji Nwoke. All rights reserved.
// Use of this source code is governed by a MIT license found in the LICENSE file.
// +build !go1.4
package codec
// This codec package will only work for go1.4 and above.
// This is for the following reasons:
// - go 1.4 was released in 2014
// - go runtime is written fully in go
// - interface only holds pointers
// - reflect.Value is stabilized as 3 words
func init() {
panic("codec: go 1.3 and below are not supported")
}

View File

@@ -7,6 +7,4 @@ package codec
import "os"
func init() {
genCheckVendor = os.Getenv("GO15VENDOREXPERIMENT") == "1"
}
var genCheckVendor = os.Getenv("GO15VENDOREXPERIMENT") == "1"

View File

@@ -1,12 +1,10 @@
// Copyright (c) 2012-2015 Ugorji Nwoke. All rights reserved.
// Use of this source code is governed by a MIT license found in the LICENSE file.
// +build go1.6
// +build go1.6,!go1.7
package codec
import "os"
func init() {
genCheckVendor = os.Getenv("GO15VENDOREXPERIMENT") != "0"
}
var genCheckVendor = os.Getenv("GO15VENDOREXPERIMENT") != "0"

View File

@@ -5,6 +5,4 @@
package codec
func init() {
genCheckVendor = true
}
const genCheckVendor = true

View File

@@ -0,0 +1,8 @@
// Copyright (c) 2012-2015 Ugorji Nwoke. All rights reserved.
// Use of this source code is governed by a MIT license found in the LICENSE file.
// +build !go1.5
package codec
var genCheckVendor = false

File diff suppressed because it is too large Load Diff

View File

@@ -219,24 +219,3 @@ func growCap(oldCap, unit, num int) (newCap int) {
}
return
}
func expandSliceValue(s reflect.Value, num int) reflect.Value {
if num <= 0 {
return s
}
l0 := s.Len()
l1 := l0 + num // new slice length
if l1 < l0 {
panic("ExpandSlice: slice overflow")
}
c0 := s.Cap()
if l1 <= c0 {
return s.Slice(0, l1)
}
st := s.Type()
c1 := growCap(c0, int(st.Elem().Size()), num)
s2 := reflect.MakeSlice(st, l1, c1)
// println("expandslicevalue: cap-old: ", c0, ", cap-new: ", c1, ", len-new: ", l1)
reflect.Copy(s2, s)
return s2
}

View File

@@ -1,13 +1,21 @@
// +build !unsafe
// +build !go1.7 safe appengine
// Copyright (c) 2012-2015 Ugorji Nwoke. All rights reserved.
// Use of this source code is governed by a MIT license found in the LICENSE file.
package codec
import (
"reflect"
"sync/atomic"
)
// 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.
//
// Usage: Always maintain a reference to v while result of this call is in use,
// and call keepAlive4BytesView(v) at point where done with view.
func stringView(v []byte) string {
return string(v)
}
@@ -15,6 +23,134 @@ func stringView(v []byte) string {
// bytesView returns a view of the string as a []byte.
// In unsafe mode, it doesn't incur allocation and copying caused by conversion.
// In regular safe mode, it is an allocation and copy.
//
// Usage: Always maintain a reference to v while result of this call is in use,
// and call keepAlive4BytesView(v) at point where done with view.
func bytesView(v string) []byte {
return []byte(v)
}
func definitelyNil(v interface{}) bool {
return false
// rv := reflect.ValueOf(v)
// switch rv.Kind() {
// case reflect.Invalid:
// return true
// case reflect.Ptr, reflect.Interface, reflect.Chan, reflect.Slice, reflect.Map, reflect.Func:
// return rv.IsNil()
// default:
// return false
// }
}
// // keepAlive4BytesView maintains a reference to the input parameter for bytesView.
// //
// // Usage: call this at point where done with the bytes view.
// func keepAlive4BytesView(v string) {}
// // keepAlive4BytesView maintains a reference to the input parameter for stringView.
// //
// // Usage: call this at point where done with the string view.
// func keepAlive4StringView(v []byte) {}
func rv2i(rv reflect.Value) interface{} {
return rv.Interface()
}
func rt2id(rt reflect.Type) uintptr {
return reflect.ValueOf(rt).Pointer()
}
func rv2rtid(rv reflect.Value) uintptr {
return reflect.ValueOf(rv.Type()).Pointer()
}
// --------------------------
// type ptrToRvMap struct{}
// func (_ *ptrToRvMap) init() {}
// func (_ *ptrToRvMap) get(i interface{}) reflect.Value {
// return reflect.ValueOf(i).Elem()
// }
// --------------------------
type atomicTypeInfoSlice struct {
v atomic.Value
}
func (x *atomicTypeInfoSlice) load() *[]rtid2ti {
i := x.v.Load()
if i == nil {
return nil
}
return i.(*[]rtid2ti)
}
func (x *atomicTypeInfoSlice) store(p *[]rtid2ti) {
x.v.Store(p)
}
// --------------------------
func (d *Decoder) raw(f *codecFnInfo, rv reflect.Value) {
rv.SetBytes(d.rawBytes())
}
func (d *Decoder) kString(f *codecFnInfo, rv reflect.Value) {
rv.SetString(d.d.DecodeString())
}
func (d *Decoder) kBool(f *codecFnInfo, rv reflect.Value) {
rv.SetBool(d.d.DecodeBool())
}
func (d *Decoder) kFloat32(f *codecFnInfo, rv reflect.Value) {
rv.SetFloat(d.d.DecodeFloat(true))
}
func (d *Decoder) kFloat64(f *codecFnInfo, rv reflect.Value) {
rv.SetFloat(d.d.DecodeFloat(false))
}
func (d *Decoder) kInt(f *codecFnInfo, rv reflect.Value) {
rv.SetInt(d.d.DecodeInt(intBitsize))
}
func (d *Decoder) kInt8(f *codecFnInfo, rv reflect.Value) {
rv.SetInt(d.d.DecodeInt(8))
}
func (d *Decoder) kInt16(f *codecFnInfo, rv reflect.Value) {
rv.SetInt(d.d.DecodeInt(16))
}
func (d *Decoder) kInt32(f *codecFnInfo, rv reflect.Value) {
rv.SetInt(d.d.DecodeInt(32))
}
func (d *Decoder) kInt64(f *codecFnInfo, rv reflect.Value) {
rv.SetInt(d.d.DecodeInt(64))
}
func (d *Decoder) kUint(f *codecFnInfo, rv reflect.Value) {
rv.SetUint(d.d.DecodeUint(uintBitsize))
}
func (d *Decoder) kUintptr(f *codecFnInfo, rv reflect.Value) {
rv.SetUint(d.d.DecodeUint(uintBitsize))
}
func (d *Decoder) kUint8(f *codecFnInfo, rv reflect.Value) {
rv.SetUint(d.d.DecodeUint(8))
}
func (d *Decoder) kUint16(f *codecFnInfo, rv reflect.Value) {
rv.SetUint(d.d.DecodeUint(16))
}
func (d *Decoder) kUint32(f *codecFnInfo, rv reflect.Value) {
rv.SetUint(d.d.DecodeUint(32))
}
func (d *Decoder) kUint64(f *codecFnInfo, rv reflect.Value) {
rv.SetUint(d.d.DecodeUint(64))
}

View File

@@ -1,4 +1,6 @@
// +build unsafe
// +build !safe
// +build !appengine
// +build go1.7
// Copyright (c) 2012-2015 Ugorji Nwoke. All rights reserved.
// Use of this source code is governed by a MIT license found in the LICENSE file.
@@ -6,10 +8,17 @@
package codec
import (
"reflect"
"sync/atomic"
"unsafe"
)
// This file has unsafe variants of some helper methods.
// NOTE: See helper_not_unsafe.go for the usage information.
// var zeroRTv [4]uintptr
const unsafeFlagIndir = 1 << 7 // keep in sync with GO_ROOT/src/reflect/value.go
type unsafeString struct {
Data uintptr
@@ -22,9 +31,17 @@ type unsafeSlice struct {
Cap int
}
// 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.
type unsafeIntf struct {
typ unsafe.Pointer
word unsafe.Pointer
}
type unsafeReflectValue struct {
typ unsafe.Pointer
ptr unsafe.Pointer
flag uintptr
}
func stringView(v []byte) string {
if len(v) == 0 {
return ""
@@ -35,9 +52,6 @@ func stringView(v []byte) string {
return *(*string)(unsafe.Pointer(&sx))
}
// bytesView returns a view of the string as a []byte.
// In unsafe mode, it doesn't incur allocation and copying caused by conversion.
// In regular safe mode, it is an allocation and copy.
func bytesView(v string) []byte {
if len(v) == 0 {
return zeroByteSlice
@@ -47,3 +61,358 @@ func bytesView(v string) []byte {
bx := unsafeSlice{sx.Data, sx.Len, sx.Len}
return *(*[]byte)(unsafe.Pointer(&bx))
}
func definitelyNil(v interface{}) bool {
return (*unsafeIntf)(unsafe.Pointer(&v)).word == nil
}
// func keepAlive4BytesView(v string) {
// runtime.KeepAlive(v)
// }
// func keepAlive4StringView(v []byte) {
// runtime.KeepAlive(v)
// }
// TODO: consider a more generally-known optimization for reflect.Value ==> Interface
//
// Currently, we use this fragile method that taps into implememtation details from
// the source go stdlib reflect/value.go,
// and trims the implementation.
func rv2i(rv reflect.Value) interface{} {
if false {
return rv.Interface()
}
urv := (*unsafeReflectValue)(unsafe.Pointer(&rv))
// references that are single-words (map, ptr) may be double-referenced as flagIndir
kk := urv.flag & (1<<5 - 1)
if (kk == uintptr(reflect.Map) || kk == uintptr(reflect.Ptr)) && urv.flag&unsafeFlagIndir != 0 {
return *(*interface{})(unsafe.Pointer(&unsafeIntf{word: *(*unsafe.Pointer)(urv.ptr), typ: urv.typ}))
}
return *(*interface{})(unsafe.Pointer(&unsafeIntf{word: urv.ptr, typ: urv.typ}))
}
func rt2id(rt reflect.Type) uintptr {
return uintptr(((*unsafeIntf)(unsafe.Pointer(&rt))).word)
}
func rv2rtid(rv reflect.Value) uintptr {
return uintptr((*unsafeReflectValue)(unsafe.Pointer(&rv)).typ)
}
// func rv0t(rt reflect.Type) reflect.Value {
// ut := (*unsafeIntf)(unsafe.Pointer(&rt))
// // we need to determine whether ifaceIndir, and then whether to just pass 0 as the ptr
// uv := unsafeReflectValue{ut.word, &zeroRTv, flag(rt.Kind())}
// return *(*reflect.Value)(unsafe.Pointer(&uv})
// }
// --------------------------
type atomicTypeInfoSlice struct {
v unsafe.Pointer
}
func (x *atomicTypeInfoSlice) load() *[]rtid2ti {
return (*[]rtid2ti)(atomic.LoadPointer(&x.v))
}
func (x *atomicTypeInfoSlice) store(p *[]rtid2ti) {
atomic.StorePointer(&x.v, unsafe.Pointer(p))
}
// --------------------------
func (d *Decoder) raw(f *codecFnInfo, rv reflect.Value) {
urv := (*unsafeReflectValue)(unsafe.Pointer(&rv))
// if urv.flag&unsafeFlagIndir != 0 {
// urv.ptr = *(*unsafe.Pointer)(urv.ptr)
// }
*(*[]byte)(urv.ptr) = d.rawBytes()
}
func (d *Decoder) kString(f *codecFnInfo, rv reflect.Value) {
urv := (*unsafeReflectValue)(unsafe.Pointer(&rv))
*(*string)(urv.ptr) = d.d.DecodeString()
}
func (d *Decoder) kBool(f *codecFnInfo, rv reflect.Value) {
urv := (*unsafeReflectValue)(unsafe.Pointer(&rv))
*(*bool)(urv.ptr) = d.d.DecodeBool()
}
func (d *Decoder) kFloat32(f *codecFnInfo, rv reflect.Value) {
urv := (*unsafeReflectValue)(unsafe.Pointer(&rv))
*(*float32)(urv.ptr) = float32(d.d.DecodeFloat(true))
}
func (d *Decoder) kFloat64(f *codecFnInfo, rv reflect.Value) {
urv := (*unsafeReflectValue)(unsafe.Pointer(&rv))
*(*float64)(urv.ptr) = d.d.DecodeFloat(false)
}
func (d *Decoder) kInt(f *codecFnInfo, rv reflect.Value) {
urv := (*unsafeReflectValue)(unsafe.Pointer(&rv))
*(*int)(urv.ptr) = int(d.d.DecodeInt(intBitsize))
}
func (d *Decoder) kInt8(f *codecFnInfo, rv reflect.Value) {
urv := (*unsafeReflectValue)(unsafe.Pointer(&rv))
*(*int8)(urv.ptr) = int8(d.d.DecodeInt(8))
}
func (d *Decoder) kInt16(f *codecFnInfo, rv reflect.Value) {
urv := (*unsafeReflectValue)(unsafe.Pointer(&rv))
*(*int16)(urv.ptr) = int16(d.d.DecodeInt(16))
}
func (d *Decoder) kInt32(f *codecFnInfo, rv reflect.Value) {
urv := (*unsafeReflectValue)(unsafe.Pointer(&rv))
*(*int32)(urv.ptr) = int32(d.d.DecodeInt(32))
}
func (d *Decoder) kInt64(f *codecFnInfo, rv reflect.Value) {
urv := (*unsafeReflectValue)(unsafe.Pointer(&rv))
*(*int64)(urv.ptr) = d.d.DecodeInt(64)
}
func (d *Decoder) kUint(f *codecFnInfo, rv reflect.Value) {
urv := (*unsafeReflectValue)(unsafe.Pointer(&rv))
*(*uint)(urv.ptr) = uint(d.d.DecodeUint(uintBitsize))
}
func (d *Decoder) kUintptr(f *codecFnInfo, rv reflect.Value) {
urv := (*unsafeReflectValue)(unsafe.Pointer(&rv))
*(*uintptr)(urv.ptr) = uintptr(d.d.DecodeUint(uintBitsize))
}
func (d *Decoder) kUint8(f *codecFnInfo, rv reflect.Value) {
urv := (*unsafeReflectValue)(unsafe.Pointer(&rv))
*(*uint8)(urv.ptr) = uint8(d.d.DecodeUint(8))
}
func (d *Decoder) kUint16(f *codecFnInfo, rv reflect.Value) {
urv := (*unsafeReflectValue)(unsafe.Pointer(&rv))
*(*uint16)(urv.ptr) = uint16(d.d.DecodeUint(16))
}
func (d *Decoder) kUint32(f *codecFnInfo, rv reflect.Value) {
urv := (*unsafeReflectValue)(unsafe.Pointer(&rv))
*(*uint32)(urv.ptr) = uint32(d.d.DecodeUint(32))
}
func (d *Decoder) kUint64(f *codecFnInfo, rv reflect.Value) {
urv := (*unsafeReflectValue)(unsafe.Pointer(&rv))
*(*uint64)(urv.ptr) = d.d.DecodeUint(64)
}
// ------------
// func rt2id(rt reflect.Type) uintptr {
// return uintptr(((*unsafeIntf)(unsafe.Pointer(&rt))).word)
// // var i interface{} = rt
// // // ui := (*unsafeIntf)(unsafe.Pointer(&i))
// // return ((*unsafeIntf)(unsafe.Pointer(&i))).word
// }
// func rv2i(rv reflect.Value) interface{} {
// urv := (*unsafeReflectValue)(unsafe.Pointer(&rv))
// // non-reference type: already indir
// // reference type: depend on flagIndir property ('cos maybe was double-referenced)
// // const (unsafeRvFlagKindMask = 1<<5 - 1 , unsafeRvFlagIndir = 1 << 7 )
// // rvk := reflect.Kind(urv.flag & (1<<5 - 1))
// // if (rvk == reflect.Chan ||
// // rvk == reflect.Func ||
// // rvk == reflect.Interface ||
// // rvk == reflect.Map ||
// // rvk == reflect.Ptr ||
// // rvk == reflect.UnsafePointer) && urv.flag&(1<<8) != 0 {
// // fmt.Printf(">>>>> ---- double indirect reference: %v, %v\n", rvk, rv.Type())
// // return *(*interface{})(unsafe.Pointer(&unsafeIntf{word: *(*unsafe.Pointer)(urv.ptr), typ: urv.typ}))
// // }
// if urv.flag&(1<<5-1) == uintptr(reflect.Map) && urv.flag&(1<<7) != 0 {
// // fmt.Printf(">>>>> ---- double indirect reference: %v, %v\n", rvk, rv.Type())
// return *(*interface{})(unsafe.Pointer(&unsafeIntf{word: *(*unsafe.Pointer)(urv.ptr), typ: urv.typ}))
// }
// // fmt.Printf(">>>>> ++++ direct reference: %v, %v\n", rvk, rv.Type())
// return *(*interface{})(unsafe.Pointer(&unsafeIntf{word: urv.ptr, typ: urv.typ}))
// }
// const (
// unsafeRvFlagKindMask = 1<<5 - 1
// unsafeRvKindDirectIface = 1 << 5
// unsafeRvFlagIndir = 1 << 7
// unsafeRvFlagAddr = 1 << 8
// unsafeRvFlagMethod = 1 << 9
// _USE_RV_INTERFACE bool = false
// _UNSAFE_RV_DEBUG = true
// )
// type unsafeRtype struct {
// _ [2]uintptr
// _ uint32
// _ uint8
// _ uint8
// _ uint8
// kind uint8
// _ [2]uintptr
// _ int32
// }
// func _rv2i(rv reflect.Value) interface{} {
// // Note: From use,
// // - it's never an interface
// // - the only calls here are for ifaceIndir types.
// // (though that conditional is wrong)
// // To know for sure, we need the value of t.kind (which is not exposed).
// //
// // Need to validate the path: type is indirect ==> only value is indirect ==> default (value is direct)
// // - Type indirect, Value indirect: ==> numbers, boolean, slice, struct, array, string
// // - Type Direct, Value indirect: ==> map???
// // - Type Direct, Value direct: ==> pointers, unsafe.Pointer, func, chan, map
// //
// // TRANSLATES TO:
// // if typeIndirect { } else if valueIndirect { } else { }
// //
// // Since we don't deal with funcs, then "flagNethod" is unset, and can be ignored.
// if _USE_RV_INTERFACE {
// return rv.Interface()
// }
// urv := (*unsafeReflectValue)(unsafe.Pointer(&rv))
// // if urv.flag&unsafeRvFlagMethod != 0 || urv.flag&unsafeRvFlagKindMask == uintptr(reflect.Interface) {
// // println("***** IS flag method or interface: delegating to rv.Interface()")
// // return rv.Interface()
// // }
// // if urv.flag&unsafeRvFlagKindMask == uintptr(reflect.Interface) {
// // println("***** IS Interface: delegate to rv.Interface")
// // return rv.Interface()
// // }
// // if urv.flag&unsafeRvFlagKindMask&unsafeRvKindDirectIface == 0 {
// // if urv.flag&unsafeRvFlagAddr == 0 {
// // println("***** IS ifaceIndir typ")
// // // ui := unsafeIntf{word: urv.ptr, typ: urv.typ}
// // // return *(*interface{})(unsafe.Pointer(&ui))
// // // return *(*interface{})(unsafe.Pointer(&unsafeIntf{word: urv.ptr, typ: urv.typ}))
// // }
// // } else if urv.flag&unsafeRvFlagIndir != 0 {
// // println("***** IS flagindir")
// // // return *(*interface{})(unsafe.Pointer(&unsafeIntf{word: *(*unsafe.Pointer)(urv.ptr), typ: urv.typ}))
// // } else {
// // println("***** NOT flagindir")
// // return *(*interface{})(unsafe.Pointer(&unsafeIntf{word: urv.ptr, typ: urv.typ}))
// // }
// // println("***** default: delegate to rv.Interface")
// urt := (*unsafeRtype)(unsafe.Pointer(urv.typ))
// if _UNSAFE_RV_DEBUG {
// fmt.Printf(">>>> start: %v: ", rv.Type())
// fmt.Printf("%v - %v\n", *urv, *urt)
// }
// if urt.kind&unsafeRvKindDirectIface == 0 {
// if _UNSAFE_RV_DEBUG {
// fmt.Printf("**** +ifaceIndir type: %v\n", rv.Type())
// }
// // println("***** IS ifaceIndir typ")
// // if true || urv.flag&unsafeRvFlagAddr == 0 {
// // // println(" ***** IS NOT addr")
// return *(*interface{})(unsafe.Pointer(&unsafeIntf{word: urv.ptr, typ: urv.typ}))
// // }
// } else if urv.flag&unsafeRvFlagIndir != 0 {
// if _UNSAFE_RV_DEBUG {
// fmt.Printf("**** +flagIndir type: %v\n", rv.Type())
// }
// // println("***** IS flagindir")
// return *(*interface{})(unsafe.Pointer(&unsafeIntf{word: *(*unsafe.Pointer)(urv.ptr), typ: urv.typ}))
// } else {
// if _UNSAFE_RV_DEBUG {
// fmt.Printf("**** -flagIndir type: %v\n", rv.Type())
// }
// // println("***** NOT flagindir")
// return *(*interface{})(unsafe.Pointer(&unsafeIntf{word: urv.ptr, typ: urv.typ}))
// }
// // println("***** default: delegating to rv.Interface()")
// // return rv.Interface()
// }
// var staticM0 = make(map[string]uint64)
// var staticI0 = (int32)(-5)
// func staticRv2iTest() {
// i0 := (int32)(-5)
// m0 := make(map[string]uint16)
// m0["1"] = 1
// for _, i := range []interface{}{
// (int)(7),
// (uint)(8),
// (int16)(-9),
// (uint16)(19),
// (uintptr)(77),
// (bool)(true),
// float32(-32.7),
// float64(64.9),
// complex(float32(19), 5),
// complex(float64(-32), 7),
// [4]uint64{1, 2, 3, 4},
// (chan<- int)(nil), // chan,
// rv2i, // func
// io.Writer(ioutil.Discard),
// make(map[string]uint),
// (map[string]uint)(nil),
// staticM0,
// m0,
// &m0,
// i0,
// &i0,
// &staticI0,
// &staticM0,
// []uint32{6, 7, 8},
// "abc",
// Raw{},
// RawExt{},
// &Raw{},
// &RawExt{},
// unsafe.Pointer(&i0),
// } {
// i2 := rv2i(reflect.ValueOf(i))
// eq := reflect.DeepEqual(i, i2)
// fmt.Printf(">>>> %v == %v? %v\n", i, i2, eq)
// }
// // os.Exit(0)
// }
// func init() {
// staticRv2iTest()
// }
// func rv2i(rv reflect.Value) interface{} {
// if _USE_RV_INTERFACE || rv.Kind() == reflect.Interface || rv.CanAddr() {
// return rv.Interface()
// }
// // var i interface{}
// // ui := (*unsafeIntf)(unsafe.Pointer(&i))
// var ui unsafeIntf
// urv := (*unsafeReflectValue)(unsafe.Pointer(&rv))
// // fmt.Printf("urv: flag: %b, typ: %b, ptr: %b\n", urv.flag, uintptr(urv.typ), uintptr(urv.ptr))
// if (urv.flag&unsafeRvFlagKindMask)&unsafeRvKindDirectIface == 0 {
// if urv.flag&unsafeRvFlagAddr != 0 {
// println("***** indirect and addressable! Needs typed move - delegate to rv.Interface()")
// return rv.Interface()
// }
// println("****** indirect type/kind")
// ui.word = urv.ptr
// } else if urv.flag&unsafeRvFlagIndir != 0 {
// println("****** unsafe rv flag indir")
// ui.word = *(*unsafe.Pointer)(urv.ptr)
// } else {
// println("****** default: assign prt to word directly")
// ui.word = urv.ptr
// }
// // ui.word = urv.ptr
// ui.typ = urv.typ
// // fmt.Printf("(pointers) ui.typ: %p, word: %p\n", ui.typ, ui.word)
// // fmt.Printf("(binary) ui.typ: %b, word: %b\n", uintptr(ui.typ), uintptr(ui.word))
// return *(*interface{})(unsafe.Pointer(&ui))
// // return i
// }

File diff suppressed because it is too large Load Diff

33
vendor/github.com/ugorji/go/codec/mammoth-test.go.tmpl generated vendored Normal file
View File

@@ -0,0 +1,33 @@
// Copyright (c) 2012-2015 Ugorji Nwoke. All rights reserved.
// Use of this source code is governed by a MIT license found in the LICENSE file.
// ************************************************************
// DO NOT EDIT.
// THIS FILE IS AUTO-GENERATED from mammoth-test.go.tmpl
// ************************************************************
package codec
// TestMammoth has all the different paths optimized in fast-path
// It has all the primitives, slices and maps.
//
// For each of those types, it has a pointer and a non-pointer field.
type TestMammoth struct {
{{range .Values }}{{if .Primitive }}{{/*
*/}}{{ .MethodNamePfx "F" true }} {{ .Primitive }}
{{ .MethodNamePfx "Fptr" true }} *{{ .Primitive }}
{{end}}{{end}}
{{range .Values }}{{if not .Primitive }}{{if not .MapKey }}{{/*
*/}}{{ .MethodNamePfx "F" false }} []{{ .Elem }}
{{ .MethodNamePfx "Fptr" false }} *[]{{ .Elem }}
{{end}}{{end}}{{end}}
{{range .Values }}{{if not .Primitive }}{{if .MapKey }}{{/*
*/}}{{ .MethodNamePfx "F" false }} map[{{ .MapKey }}]{{ .Elem }}
{{ .MethodNamePfx "Fptr" false }} *map[{{ .MapKey }}]{{ .Elem }}
{{end}}{{end}}{{end}}
}

View File

@@ -104,7 +104,8 @@ var (
type msgpackEncDriver struct {
noBuiltInTypes
encNoSeparator
encDriverNoopContainerWriter
// encNoSeparator
e *Encoder
w encWriter
h *MsgpackHandle
@@ -213,21 +214,22 @@ func (e *msgpackEncDriver) encodeExtPreamble(xtag byte, l int) {
}
}
func (e *msgpackEncDriver) EncodeArrayStart(length int) {
func (e *msgpackEncDriver) WriteArrayStart(length int) {
e.writeContainerLen(msgpackContainerList, length)
}
func (e *msgpackEncDriver) EncodeMapStart(length int) {
func (e *msgpackEncDriver) WriteMapStart(length int) {
e.writeContainerLen(msgpackContainerMap, length)
}
func (e *msgpackEncDriver) EncodeString(c charEncoding, s string) {
slen := len(s)
if c == c_RAW && e.h.WriteExt {
e.writeContainerLen(msgpackContainerBin, len(s))
e.writeContainerLen(msgpackContainerBin, slen)
} else {
e.writeContainerLen(msgpackContainerStr, len(s))
e.writeContainerLen(msgpackContainerStr, slen)
}
if len(s) > 0 {
if slen > 0 {
e.w.writestr(s)
}
}
@@ -237,12 +239,13 @@ func (e *msgpackEncDriver) EncodeSymbol(v string) {
}
func (e *msgpackEncDriver) EncodeStringBytes(c charEncoding, bs []byte) {
slen := len(bs)
if c == c_RAW && e.h.WriteExt {
e.writeContainerLen(msgpackContainerBin, len(bs))
e.writeContainerLen(msgpackContainerBin, slen)
} else {
e.writeContainerLen(msgpackContainerStr, len(bs))
e.writeContainerLen(msgpackContainerStr, slen)
}
if len(bs) > 0 {
if slen > 0 {
e.w.writeb(bs)
}
}
@@ -272,8 +275,9 @@ type msgpackDecDriver struct {
bdRead bool
br bool // bytes reader
noBuiltInTypes
noStreamingCodec
decNoSeparator
// noStreamingCodec
// decNoSeparator
decDriverNoopContainerReader
}
// Note: This returns either a primitive (int, bool, etc) for non-containers,
@@ -286,7 +290,7 @@ func (d *msgpackDecDriver) DecodeNaked() {
d.readNextBd()
}
bd := d.bd
n := &d.d.n
n := d.d.n
var decodeFurther bool
switch bd {
@@ -349,11 +353,11 @@ func (d *msgpackDecDriver) DecodeNaked() {
n.s = d.DecodeString()
} else {
n.v = valueTypeBytes
n.l = d.DecodeBytes(nil, false, false)
n.l = d.DecodeBytes(nil, false)
}
case bd == mpBin8, bd == mpBin16, bd == mpBin32:
n.v = valueTypeBytes
n.l = d.DecodeBytes(nil, false, false)
n.l = d.DecodeBytes(nil, false)
case bd == mpArray16, bd == mpArray32, bd >= mpFixArrayMin && bd <= mpFixArrayMax:
n.v = valueTypeArray
decodeFurther = true
@@ -525,17 +529,46 @@ func (d *msgpackDecDriver) DecodeBool() (b bool) {
return
}
func (d *msgpackDecDriver) DecodeBytes(bs []byte, isstring, zerocopy bool) (bsOut []byte) {
func (d *msgpackDecDriver) DecodeBytes(bs []byte, zerocopy bool) (bsOut []byte) {
if !d.bdRead {
d.readNextBd()
}
// DecodeBytes could be from: bin str fixstr fixarray array ...
var clen int
// ignore isstring. Expect that the bytes may be found from msgpackContainerStr or msgpackContainerBin
if bd := d.bd; bd == mpBin8 || bd == mpBin16 || bd == mpBin32 {
clen = d.readContainerLen(msgpackContainerBin)
} else {
vt := d.ContainerType()
switch vt {
case valueTypeBytes:
// valueTypeBytes may be a mpBin or an mpStr container
if bd := d.bd; bd == mpBin8 || bd == mpBin16 || bd == mpBin32 {
clen = d.readContainerLen(msgpackContainerBin)
} else {
clen = d.readContainerLen(msgpackContainerStr)
}
case valueTypeString:
clen = d.readContainerLen(msgpackContainerStr)
case valueTypeArray:
clen = d.readContainerLen(msgpackContainerList)
// ensure everything after is one byte each
for i := 0; i < clen; i++ {
d.readNextBd()
if d.bd == mpNil {
bs = append(bs, 0)
} else if d.bd == mpUint8 {
bs = append(bs, d.r.readn1())
} else {
d.d.errorf("cannot read non-byte into a byte array")
return
}
}
d.bdRead = false
return bs
default:
d.d.errorf("invalid container type: expecting bin|str|array")
return
}
// these are (bin|str)(8|16|32)
// println("DecodeBytes: clen: ", clen)
d.bdRead = false
// bytes may be nil, so handle it. if nil, clen=-1.
@@ -549,11 +582,15 @@ func (d *msgpackDecDriver) DecodeBytes(bs []byte, isstring, zerocopy bool) (bsOu
bs = d.b[:]
}
}
return decByteSlice(d.r, clen, bs)
return decByteSlice(d.r, clen, d.d.h.MaxInitLen, bs)
}
func (d *msgpackDecDriver) DecodeString() (s string) {
return string(d.DecodeBytes(d.b[:], true, true))
return string(d.DecodeBytes(d.b[:], true))
}
func (d *msgpackDecDriver) DecodeStringAsBytes() (s []byte) {
return d.DecodeBytes(d.b[:], true)
}
func (d *msgpackDecDriver) readNextBd() {
@@ -569,6 +606,9 @@ func (d *msgpackDecDriver) uncacheRead() {
}
func (d *msgpackDecDriver) ContainerType() (vt valueType) {
if !d.bdRead {
d.readNextBd()
}
bd := d.bd
if bd == mpNil {
return valueTypeNil
@@ -621,10 +661,16 @@ func (d *msgpackDecDriver) readContainerLen(ct msgpackContainerType) (clen int)
}
func (d *msgpackDecDriver) ReadMapStart() int {
if !d.bdRead {
d.readNextBd()
}
return d.readContainerLen(msgpackContainerMap)
}
func (d *msgpackDecDriver) ReadArrayStart() int {
if !d.bdRead {
d.readNextBd()
}
return d.readContainerLen(msgpackContainerList)
}
@@ -678,10 +724,10 @@ func (d *msgpackDecDriver) decodeExtV(verifyTag bool, tag byte) (xtag byte, xbs
}
xbd := d.bd
if xbd == mpBin8 || xbd == mpBin16 || xbd == mpBin32 {
xbs = d.DecodeBytes(nil, false, true)
xbs = d.DecodeBytes(nil, true)
} else if xbd == mpStr8 || xbd == mpStr16 || xbd == mpStr32 ||
(xbd >= mpFixStrMin && xbd <= mpFixStrMax) {
xbs = d.DecodeBytes(nil, true, true)
xbs = d.DecodeStringAsBytes()
} else {
clen := d.readExtLen()
xtag = d.r.readn1()
@@ -716,6 +762,7 @@ type MsgpackHandle struct {
// a []byte or string based on the setting of RawToString.
WriteExt bool
binaryEncodingType
noElemSeparators
}
func (h *MsgpackHandle) SetBytesExt(rt reflect.Type, tag uint64, ext BytesExt) (err error) {
@@ -727,7 +774,7 @@ func (h *MsgpackHandle) newEncDriver(e *Encoder) encDriver {
}
func (h *MsgpackHandle) newDecDriver(d *Decoder) decDriver {
return &msgpackDecDriver{d: d, r: d.r, h: h, br: d.bytes}
return &msgpackDecDriver{d: d, h: h, r: d.r, br: d.bytes}
}
func (e *msgpackEncDriver) reset() {
@@ -735,7 +782,7 @@ func (e *msgpackEncDriver) reset() {
}
func (d *msgpackDecDriver) reset() {
d.r = d.d.r
d.r, d.br = d.d.r, d.d.bytes
d.bd, d.bdRead = 0, false
}

View File

@@ -1,6 +1,8 @@
// Copyright (c) 2012-2015 Ugorji Nwoke. All rights reserved.
// Use of this source code is governed by a MIT license found in the LICENSE file.
// +build ignore
package codec
import (
@@ -105,10 +107,9 @@ func (h *noopDrv) DecodeUint(bitsize uint8) (ui uint64) { return uint64(h.
func (h *noopDrv) DecodeFloat(chkOverflow32 bool) (f float64) { return float64(h.m(95)) }
func (h *noopDrv) DecodeBool() (b bool) { return h.m(2) == 0 }
func (h *noopDrv) DecodeString() (s string) { return h.S[h.m(8)] }
func (h *noopDrv) DecodeStringAsBytes() []byte { return h.DecodeBytes(nil, true) }
// func (h *noopDrv) DecodeStringAsBytes(bs []byte) []byte { return h.DecodeBytes(bs) }
func (h *noopDrv) DecodeBytes(bs []byte, isstring, zerocopy bool) []byte { return h.B[h.m(len(h.B))] }
func (h *noopDrv) DecodeBytes(bs []byte, zerocopy bool) []byte { return h.B[h.m(len(h.B))] }
func (h *noopDrv) ReadEnd() { h.end() }

View File

@@ -1,3 +0,0 @@
package codec
//go:generate bash prebuild.sh

View File

@@ -1,199 +0,0 @@
#!/bin/bash
# _needgen is a helper function to tell if we need to generate files for msgp, codecgen.
_needgen() {
local a="$1"
zneedgen=0
if [[ ! -e "$a" ]]
then
zneedgen=1
echo 1
return 0
fi
for i in `ls -1 *.go.tmpl gen.go values_test.go`
do
if [[ "$a" -ot "$i" ]]
then
zneedgen=1
echo 1
return 0
fi
done
echo 0
}
# _build generates fast-path.go and gen-helper.go.
#
# It is needed because there is some dependency between the generated code
# and the other classes. Consequently, we have to totally remove the
# generated files and put stubs in place, before calling "go run" again
# to recreate them.
_build() {
if ! [[ "${zforce}" == "1" ||
"1" == $( _needgen "fast-path.generated.go" ) ||
"1" == $( _needgen "gen-helper.generated.go" ) ||
"1" == $( _needgen "gen.generated.go" ) ||
1 == 0 ]]
then
return 0
fi
# echo "Running prebuild"
if [ "${zbak}" == "1" ]
then
# echo "Backing up old generated files"
_zts=`date '+%m%d%Y_%H%M%S'`
_gg=".generated.go"
[ -e "gen-helper${_gg}" ] && mv gen-helper${_gg} gen-helper${_gg}__${_zts}.bak
[ -e "fast-path${_gg}" ] && mv fast-path${_gg} fast-path${_gg}__${_zts}.bak
# [ -e "safe${_gg}" ] && mv safe${_gg} safe${_gg}__${_zts}.bak
# [ -e "unsafe${_gg}" ] && mv unsafe${_gg} unsafe${_gg}__${_zts}.bak
else
rm -f fast-path.generated.go gen.generated.go gen-helper.generated.go \
*safe.generated.go *_generated_test.go *.generated_ffjson_expose.go
fi
cat > gen.generated.go <<EOF
// Copyright (c) 2012-2015 Ugorji Nwoke. All rights reserved.
// Use of this source code is governed by a MIT license found in the LICENSE file.
package codec
// DO NOT EDIT. THIS FILE IS AUTO-GENERATED FROM gen-dec-(map|array).go.tmpl
const genDecMapTmpl = \`
EOF
cat >> gen.generated.go < gen-dec-map.go.tmpl
cat >> gen.generated.go <<EOF
\`
const genDecListTmpl = \`
EOF
cat >> gen.generated.go < gen-dec-array.go.tmpl
cat >> gen.generated.go <<EOF
\`
EOF
cat > gen-from-tmpl.codec.generated.go <<EOF
package codec
import "io"
func GenInternalGoFile(r io.Reader, w io.Writer, safe bool) error {
return genInternalGoFile(r, w, safe)
}
EOF
cat > gen-from-tmpl.generated.go <<EOF
//+build ignore
package main
//import "flag"
import "ugorji.net/codec"
import "os"
func run(fnameIn, fnameOut string, safe bool) {
fin, err := os.Open(fnameIn)
if err != nil { panic(err) }
defer fin.Close()
fout, err := os.Create(fnameOut)
if err != nil { panic(err) }
defer fout.Close()
err = codec.GenInternalGoFile(fin, fout, safe)
if err != nil { panic(err) }
}
func main() {
// do not make safe/unsafe variants.
// Instead, depend on escape analysis, and place string creation and usage appropriately.
// run("unsafe.go.tmpl", "safe.generated.go", true)
// run("unsafe.go.tmpl", "unsafe.generated.go", false)
run("fast-path.go.tmpl", "fast-path.generated.go", false)
run("gen-helper.go.tmpl", "gen-helper.generated.go", false)
}
EOF
go run -tags=notfastpath gen-from-tmpl.generated.go && \
rm -f gen-from-tmpl.*generated.go
}
_codegenerators() {
if [[ $zforce == "1" ||
"1" == $( _needgen "values_codecgen${zsfx}" ) ||
"1" == $( _needgen "values_msgp${zsfx}" ) ||
"1" == $( _needgen "values_ffjson${zsfx}" ) ||
1 == 0 ]]
then
# codecgen creates some temporary files in the directory (main, pkg).
# Consequently, we should start msgp and ffjson first, and also put a small time latency before
# starting codecgen.
# Without this, ffjson chokes on one of the temporary files from codecgen.
if [[ $zexternal == "1" ]]
then
echo "ffjson ... " && \
ffjson -w values_ffjson${zsfx} $zfin &
zzzIdFF=$!
echo "msgp ... " && \
msgp -tests=false -o=values_msgp${zsfx} -file=$zfin &
zzzIdMsgp=$!
sleep 1 # give ffjson and msgp some buffer time. see note above.
fi
echo "codecgen - !unsafe ... " && \
codecgen -rt codecgen -t 'x,codecgen,!unsafe' -o values_codecgen${zsfx} -d 19780 $zfin &
zzzIdC=$!
echo "codecgen - unsafe ... " && \
codecgen -u -rt codecgen -t 'x,codecgen,unsafe' -o values_codecgen_unsafe${zsfx} -d 19781 $zfin &
zzzIdCU=$!
wait $zzzIdC $zzzIdCU $zzzIdMsgp $zzzIdFF && \
# remove (M|Unm)arshalJSON implementations, so they don't conflict with encoding/json bench \
if [[ $zexternal == "1" ]]
then
sed -i 's+ MarshalJSON(+ _MarshalJSON(+g' values_ffjson${zsfx} && \
sed -i 's+ UnmarshalJSON(+ _UnmarshalJSON(+g' values_ffjson${zsfx}
fi && \
echo "generators done!" && \
true
fi
}
# _init reads the arguments and sets up the flags
_init() {
OPTIND=1
while getopts "fbx" flag
do
case "x$flag" in
'xf') zforce=1;;
'xb') zbak=1;;
'xx') zexternal=1;;
*) echo "prebuild.sh accepts [-fbx] only"; return 1;;
esac
done
shift $((OPTIND-1))
OPTIND=1
}
# main script.
# First ensure that this is being run from the basedir (i.e. dirname of script is .)
if [ "." = `dirname $0` ]
then
zmydir=`pwd`
zfin="test_values.generated.go"
zsfx="_generated_test.go"
# rm -f *_generated_test.go
rm -f codecgen-*.go && \
_init "$@" && \
_build && \
cp $zmydir/values_test.go $zmydir/$zfin && \
_codegenerators && \
echo prebuild done successfully
rm -f $zmydir/$zfin
else
echo "Script must be run from the directory it resides in"
fi

View File

@@ -5,18 +5,19 @@ package codec
import (
"bufio"
"errors"
"io"
"net/rpc"
"sync"
)
// rpcEncodeTerminator allows a handler specify a []byte terminator to send after each Encode.
//
// Some codecs like json need to put a space after each encoded value, to serve as a
// delimiter for things like numbers (else json codec will continue reading till EOF).
type rpcEncodeTerminator interface {
rpcEncodeTerminate() []byte
}
// // rpcEncodeTerminator allows a handler specify a []byte terminator to send after each Encode.
// //
// // Some codecs like json need to put a space after each encoded value, to serve as a
// // delimiter for things like numbers (else json codec will continue reading till EOF).
// type rpcEncodeTerminator interface {
// rpcEncodeTerminate() []byte
// }
// Rpc provides a rpc Server or Client Codec for rpc communication.
type Rpc interface {
@@ -52,6 +53,12 @@ type rpcCodec struct {
func newRPCCodec(conn io.ReadWriteCloser, h Handle) rpcCodec {
bw := bufio.NewWriter(conn)
br := bufio.NewReader(conn)
// defensive: ensure that jsonH has TermWhitespace turned on.
if jsonH, ok := h.(*JsonHandle); ok && !jsonH.TermWhitespace {
panic(errors.New("rpc requires a JsonHandle with TermWhitespace set to true"))
}
return rpcCodec{
rwc: conn,
bw: bw,
@@ -77,17 +84,17 @@ func (c *rpcCodec) write(obj1, obj2 interface{}, writeObj2, doFlush bool) (err e
if err = c.enc.Encode(obj1); err != nil {
return
}
t, tOk := c.h.(rpcEncodeTerminator)
if tOk {
c.bw.Write(t.rpcEncodeTerminate())
}
// t, tOk := c.h.(rpcEncodeTerminator)
// if tOk {
// c.bw.Write(t.rpcEncodeTerminate())
// }
if writeObj2 {
if err = c.enc.Encode(obj2); err != nil {
return
}
if tOk {
c.bw.Write(t.rpcEncodeTerminate())
}
// if tOk {
// c.bw.Write(t.rpcEncodeTerminate())
// }
}
if doFlush {
return c.bw.Flush()

View File

@@ -30,7 +30,8 @@ const (
type simpleEncDriver struct {
noBuiltInTypes
encNoSeparator
encDriverNoopContainerWriter
// encNoSeparator
e *Encoder
h *SimpleHandle
w encWriter
@@ -124,11 +125,11 @@ func (e *simpleEncDriver) encodeExtPreamble(xtag byte, length int) {
e.w.writen1(xtag)
}
func (e *simpleEncDriver) EncodeArrayStart(length int) {
func (e *simpleEncDriver) WriteArrayStart(length int) {
e.encLen(simpleVdArray, length)
}
func (e *simpleEncDriver) EncodeMapStart(length int) {
func (e *simpleEncDriver) WriteMapStart(length int) {
e.encLen(simpleVdMap, length)
}
@@ -155,10 +156,10 @@ type simpleDecDriver struct {
bdRead bool
bd byte
br bool // bytes reader
b [scratchByteArrayLen]byte
noBuiltInTypes
noStreamingCodec
decNoSeparator
b [scratchByteArrayLen]byte
// noStreamingCodec
decDriverNoopContainerReader
}
func (d *simpleDecDriver) readNextBd() {
@@ -174,6 +175,9 @@ func (d *simpleDecDriver) uncacheRead() {
}
func (d *simpleDecDriver) ContainerType() (vt valueType) {
if !d.bdRead {
d.readNextBd()
}
if d.bd == simpleVdNil {
return valueTypeNil
} else if d.bd == simpleVdByteArray || d.bd == simpleVdByteArray+1 ||
@@ -315,11 +319,17 @@ func (d *simpleDecDriver) DecodeBool() (b bool) {
}
func (d *simpleDecDriver) ReadMapStart() (length int) {
if !d.bdRead {
d.readNextBd()
}
d.bdRead = false
return d.decLen()
}
func (d *simpleDecDriver) ReadArrayStart() (length int) {
if !d.bdRead {
d.readNextBd()
}
d.bdRead = false
return d.decLen()
}
@@ -352,10 +362,14 @@ func (d *simpleDecDriver) decLen() int {
}
func (d *simpleDecDriver) DecodeString() (s string) {
return string(d.DecodeBytes(d.b[:], true, true))
return string(d.DecodeBytes(d.b[:], true))
}
func (d *simpleDecDriver) DecodeBytes(bs []byte, isstring, zerocopy bool) (bsOut []byte) {
func (d *simpleDecDriver) DecodeStringAsBytes() (s []byte) {
return d.DecodeBytes(d.b[:], true)
}
func (d *simpleDecDriver) DecodeBytes(bs []byte, zerocopy bool) (bsOut []byte) {
if !d.bdRead {
d.readNextBd()
}
@@ -372,7 +386,7 @@ func (d *simpleDecDriver) DecodeBytes(bs []byte, isstring, zerocopy bool) (bsOut
bs = d.b[:]
}
}
return decByteSlice(d.r, clen, bs)
return decByteSlice(d.r, clen, d.d.h.MaxInitLen, bs)
}
func (d *simpleDecDriver) DecodeExt(rv interface{}, xtag uint64, ext Ext) (realxtag uint64) {
@@ -406,7 +420,7 @@ func (d *simpleDecDriver) decodeExtV(verifyTag bool, tag byte) (xtag byte, xbs [
}
xbs = d.r.readx(l)
case simpleVdByteArray, simpleVdByteArray + 1, simpleVdByteArray + 2, simpleVdByteArray + 3, simpleVdByteArray + 4:
xbs = d.DecodeBytes(nil, false, true)
xbs = d.DecodeBytes(nil, true)
default:
d.d.errorf("Invalid d.bd for extensions (Expecting extensions or byte array). Got: 0x%x", d.bd)
return
@@ -420,7 +434,7 @@ func (d *simpleDecDriver) DecodeNaked() {
d.readNextBd()
}
n := &d.d.n
n := d.d.n
var decodeFurther bool
switch d.bd {
@@ -454,7 +468,7 @@ func (d *simpleDecDriver) DecodeNaked() {
n.s = d.DecodeString()
case simpleVdByteArray, simpleVdByteArray + 1, simpleVdByteArray + 2, simpleVdByteArray + 3, simpleVdByteArray + 4:
n.v = valueTypeBytes
n.l = d.DecodeBytes(nil, false, false)
n.l = d.DecodeBytes(nil, false)
case simpleVdExt, simpleVdExt + 1, simpleVdExt + 2, simpleVdExt + 3, simpleVdExt + 4:
n.v = valueTypeExt
l := d.decLen()
@@ -499,6 +513,7 @@ func (d *simpleDecDriver) DecodeNaked() {
type SimpleHandle struct {
BasicHandle
binaryEncodingType
noElemSeparators
}
func (h *SimpleHandle) SetBytesExt(rt reflect.Type, tag uint64, ext BytesExt) (err error) {
@@ -510,7 +525,7 @@ func (h *SimpleHandle) newEncDriver(e *Encoder) encDriver {
}
func (h *SimpleHandle) newDecDriver(d *Decoder) decDriver {
return &simpleDecDriver{d: d, r: d.r, h: h, br: d.bytes}
return &simpleDecDriver{d: d, h: h, r: d.r, br: d.bytes}
}
func (e *simpleEncDriver) reset() {
@@ -518,7 +533,7 @@ func (e *simpleEncDriver) reset() {
}
func (d *simpleDecDriver) reset() {
d.r = d.d.r
d.r, d.br = d.d.r, d.d.bytes
d.bd, d.bdRead = 0, false
}

View File

@@ -34,7 +34,7 @@ def get_test_data_list():
True,
u"null",
None,
u"someday",
u"some&day>some<day",
1328176922000002000,
u"",
-2206187877999998000,
@@ -84,7 +84,7 @@ def doRpcServer(port, stopTimeSec):
def EchoStruct(self, msg):
return ("%s" % msg)
addr = msgpackrpc.Address('localhost', port)
addr = msgpackrpc.Address('127.0.0.1', port)
server = msgpackrpc.Server(EchoHandler())
server.listen(addr)
# run thread to stop it after stopTimeSec seconds if > 0
@@ -96,14 +96,14 @@ def doRpcServer(port, stopTimeSec):
server.start()
def doRpcClientToPythonSvc(port):
address = msgpackrpc.Address('localhost', port)
address = msgpackrpc.Address('127.0.0.1', port)
client = msgpackrpc.Client(address, unpack_encoding='utf-8')
print client.call("Echo123", "A1", "B2", "C3")
print client.call("EchoStruct", {"A" :"Aa", "B":"Bb", "C":"Cc"})
def doRpcClientToGoSvc(port):
# print ">>>> port: ", port, " <<<<<"
address = msgpackrpc.Address('localhost', port)
address = msgpackrpc.Address('127.0.0.1', port)
client = msgpackrpc.Client(address, unpack_encoding='utf-8')
print client.call("TestRpcInt.Echo123", ["A1", "B2", "C3"])
print client.call("TestRpcInt.EchoStruct", {"A" :"Aa", "B":"Bb", "C":"Cc"})

View File

@@ -1,102 +0,0 @@
#!/bin/bash
# Run all the different permutations of all the tests.
# This helps ensure that nothing gets broken.
_run() {
# 1. VARIATIONS: regular (t), canonical (c), IO R/W (i),
# binc-nosymbols (n), struct2array (s), intern string (e),
# json-indent (d), circular (l)
# 2. MODE: reflection (r), external (x), codecgen (g), unsafe (u), notfastpath (f)
# 3. OPTIONS: verbose (v), reset (z), must (m),
#
# Use combinations of mode to get exactly what you want,
# and then pass the variations you need.
ztags=""
zargs=""
local OPTIND
OPTIND=1
while getopts "_xurtcinsvgzmefdl" flag
do
case "x$flag" in
'xr') ;;
'xf') ztags="$ztags notfastpath" ;;
'xg') ztags="$ztags codecgen" ;;
'xx') ztags="$ztags x" ;;
'xu') ztags="$ztags unsafe" ;;
'xv') zargs="$zargs -tv" ;;
'xz') zargs="$zargs -tr" ;;
'xm') zargs="$zargs -tm" ;;
'xl') zargs="$zargs -tl" ;;
*) ;;
esac
done
# shift $((OPTIND-1))
printf '............. TAGS: %s .............\n' "$ztags"
# echo ">>>>>>> TAGS: $ztags"
OPTIND=1
while getopts "_xurtcinsvgzmefdl" flag
do
case "x$flag" in
'xt') printf ">>>>>>> REGULAR : "; go test "-tags=$ztags" $zargs ; sleep 2 ;;
'xc') printf ">>>>>>> CANONICAL : "; go test "-tags=$ztags" $zargs -tc; sleep 2 ;;
'xi') printf ">>>>>>> I/O : "; go test "-tags=$ztags" $zargs -ti; sleep 2 ;;
'xn') printf ">>>>>>> NO_SYMBOLS : "; go test "-tags=$ztags" -run=Binc $zargs -tn; sleep 2 ;;
'xs') printf ">>>>>>> TO_ARRAY : "; go test "-tags=$ztags" $zargs -ts; sleep 2 ;;
'xe') printf ">>>>>>> INTERN : "; go test "-tags=$ztags" $zargs -te; sleep 2 ;;
'xd') printf ">>>>>>> INDENT : ";
go test "-tags=$ztags" -run=JsonCodecsTable -td=-1 $zargs;
go test "-tags=$ztags" -run=JsonCodecsTable -td=8 $zargs;
sleep 2 ;;
*) ;;
esac
done
shift $((OPTIND-1))
OPTIND=1
}
# echo ">>>>>>> RUNNING VARIATIONS OF TESTS"
if [[ "x$@" = "x" || "x$@" = "x-A" ]]; then
# All: r, x, g, gu
_run "-_tcinsed_ml" # regular
_run "-_tcinsed_ml_z" # regular with reset
_run "-_tcinsed_ml_f" # regular with no fastpath (notfastpath)
_run "-x_tcinsed_ml" # external
_run "-gx_tcinsed_ml" # codecgen: requires external
_run "-gxu_tcinsed_ml" # codecgen + unsafe
elif [[ "x$@" = "x-Z" ]]; then
# Regular
_run "-_tcinsed_ml" # regular
_run "-_tcinsed_ml_z" # regular with reset
elif [[ "x$@" = "x-F" ]]; then
# regular with notfastpath
_run "-_tcinsed_ml_f" # regular
_run "-_tcinsed_ml_zf" # regular with reset
elif [[ "x$@" = "x-C" ]]; then
# codecgen
_run "-gx_tcinsed_ml" # codecgen: requires external
_run "-gxu_tcinsed_ml" # codecgen + unsafe
elif [[ "x$@" = "x-X" ]]; then
# external
_run "-x_tcinsed_ml" # external
elif [[ "x$@" = "x-h" || "x$@" = "x-?" ]]; then
cat <<EOF
Usage: tests.sh [options...]
-A run through all tests (regular, external, codecgen)
-Z regular tests only
-F regular tests only (without fastpath, so they run quickly)
-C codecgen only
-X external only
-h show help (usage)
-? same as -h
(no options)
same as -A
(unrecognized options)
just pass on the options from the command line
EOF
else
_run "$@"
fi

View File

@@ -5,23 +5,10 @@ package codec
import (
"fmt"
"reflect"
"time"
)
var (
timeDigits = [...]byte{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'}
timeExtEncFn = func(rv reflect.Value) (bs []byte, err error) {
defer panicToErr(&err)
bs = timeExt{}.WriteExt(rv.Interface())
return
}
timeExtDecFn = func(rv reflect.Value, bs []byte) (err error) {
defer panicToErr(&err)
timeExt{}.ReadExt(rv.Interface(), bs)
return
}
)
var timeDigits = [...]byte{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'}
type timeExt struct{}
@@ -210,24 +197,24 @@ func decodeTime(bs []byte) (tt time.Time, err error) {
return
}
func timeLocUTCName(tzint int16) string {
if tzint == 0 {
return "UTC"
}
var tzname = []byte("UTC+00:00")
//tzname := fmt.Sprintf("UTC%s%02d:%02d", tzsign, tz/60, tz%60) //perf issue using Sprintf. inline below.
//tzhr, tzmin := tz/60, tz%60 //faster if u convert to int first
var tzhr, tzmin int16
if tzint < 0 {
tzname[3] = '-' // (TODO: verify. this works here)
tzhr, tzmin = -tzint/60, (-tzint)%60
} else {
tzhr, tzmin = tzint/60, tzint%60
}
tzname[4] = timeDigits[tzhr/10]
tzname[5] = timeDigits[tzhr%10]
tzname[7] = timeDigits[tzmin/10]
tzname[8] = timeDigits[tzmin%10]
return string(tzname)
//return time.FixedZone(string(tzname), int(tzint)*60)
}
// func timeLocUTCName(tzint int16) string {
// if tzint == 0 {
// return "UTC"
// }
// var tzname = []byte("UTC+00:00")
// //tzname := fmt.Sprintf("UTC%s%02d:%02d", tzsign, tz/60, tz%60) //perf issue using Sprintf. inline below.
// //tzhr, tzmin := tz/60, tz%60 //faster if u convert to int first
// var tzhr, tzmin int16
// if tzint < 0 {
// tzname[3] = '-' // (TODO: verify. this works here)
// tzhr, tzmin = -tzint/60, (-tzint)%60
// } else {
// tzhr, tzmin = tzint/60, tzint%60
// }
// tzname[4] = timeDigits[tzhr/10]
// tzname[5] = timeDigits[tzhr%10]
// tzname[7] = timeDigits[tzmin/10]
// tzname[8] = timeDigits[tzmin%10]
// return string(tzname)
// //return time.FixedZone(string(tzname), int(tzint)*60)
// }

426
vendor/github.com/ugorji/go/codec/xml.go generated vendored Normal file
View File

@@ -0,0 +1,426 @@
// +build ignore
package codec
import "reflect"
/*
A strict Non-validating namespace-aware XML 1.0 parser and (en|de)coder.
We are attempting this due to perceived issues with encoding/xml:
- Complicated. It tried to do too much, and is not as simple to use as json.
- Due to over-engineering, reflection is over-used AND performance suffers:
java is 6X faster:http://fabsk.eu/blog/category/informatique/dev/golang/
even PYTHON performs better: http://outgoing.typepad.com/outgoing/2014/07/exploring-golang.html
codec framework will offer the following benefits
- VASTLY improved performance (when using reflection-mode or codecgen)
- simplicity and consistency: with the rest of the supported formats
- all other benefits of codec framework (streaming, codegeneration, etc)
codec is not a drop-in replacement for encoding/xml.
It is a replacement, based on the simplicity and performance of codec.
Look at it like JAXB for Go.
Challenges:
- Need to output XML preamble, with all namespaces at the right location in the output.
- Each "end" block is dynamic, so we need to maintain a context-aware stack
- How to decide when to use an attribute VS an element
- How to handle chardata, attr, comment EXPLICITLY.
- Should it output fragments?
e.g. encoding a bool should just output true OR false, which is not well-formed XML.
Extend the struct tag. See representative example:
type X struct {
ID uint8 codec:"xid|http://ugorji.net/x-namespace id,omitempty,toarray,attr,cdata"
}
Based on this, we encode
- fields as elements, BUT encode as attributes if struct tag contains ",attr".
- text as entity-escaped text, BUT encode as CDATA if struct tag contains ",cdata".
In this mode, we only encode as attribute if ",attr" is found, and only encode as CDATA
if ",cdata" is found in the struct tag.
To handle namespaces:
- XMLHandle is denoted as being namespace-aware.
Consequently, we WILL use the ns:name pair to encode and decode if defined, else use the plain name.
- *Encoder and *Decoder know whether the Handle "prefers" namespaces.
- add *Encoder.getEncName(*structFieldInfo).
No one calls *structFieldInfo.indexForEncName directly anymore
- add *Decoder.getStructFieldInfo(encName string) // encName here is either like abc, or h1:nsabc
No one accesses .encName anymore except in
- let encode.go and decode.go use these (for consistency)
- only problem exists for gen.go, where we create a big switch on encName.
Now, we also have to add a switch on strings.endsWith(kName, encNsName)
- gen.go will need to have many more methods, and then double-on the 2 switch loops like:
switch k {
case "abc" : x.abc()
case "def" : x.def()
default {
switch {
case !nsAware: panic(...)
case strings.endsWith("nsabc"): x.abc()
default: panic(...)
}
}
}
The structure below accomodates this:
type typeInfo struct {
sfi []*structFieldInfo // sorted by encName
sfins // sorted by namespace
sfia // sorted, to have those with attributes at the top. Needed to write XML appropriately.
sfip // unsorted
}
type structFieldInfo struct {
encName
nsEncName
ns string
attr bool
cdata bool
}
indexForEncName is now an internal helper function that takes a sorted array
(one of ti.sfins or ti.sfi). It is only used by *Encoder.getStructFieldInfo(...)
There will be a separate parser from the builder.
The parser will have a method: next() xmlToken method.
xmlToken has fields:
- type uint8: 0 | ElementStart | ElementEnd | AttrKey | AttrVal | Text
- value string
- ns string
SEE: http://www.xml.com/pub/a/98/10/guide0.html?page=3#ENTDECL
The following are skipped when parsing:
- External Entities (from external file)
- Notation Declaration e.g. <!NOTATION GIF87A SYSTEM "GIF">
- Entity Declarations & References
- XML Declaration (assume UTF-8)
- XML Directive i.e. <! ... >
- Other Declarations: Notation, etc.
- Comment
- Processing Instruction
- schema / DTD for validation:
We are not a VALIDATING parser. Validation is done elsewhere.
However, some parts of the DTD internal subset are used (SEE BELOW).
For Attribute List Declarations e.g.
<!ATTLIST foo:oldjoke name ID #REQUIRED label CDATA #IMPLIED status ( funny | notfunny ) 'funny' >
We considered using the ATTLIST to get "default" value, but not to validate the contents. (VETOED)
The following XML features are supported
- Namespace
- Element
- Attribute
- cdata
- Unicode escape
The following DTD (when as an internal sub-set) features are supported:
- Internal Entities e.g.
<!ELEMENT burns "ugorji is cool" > AND entities for the set: [<>&"']
- Parameter entities e.g.
<!ENTITY % personcontent "ugorji is cool"> <!ELEMENT burns (%personcontent;)*>
At decode time, a structure containing the following is kept
- namespace mapping
- default attribute values
- all internal entities (<>&"' and others written in the document)
When decode starts, it parses XML namespace declarations and creates a map in the
xmlDecDriver. While parsing, that map continously gets updated.
The only problem happens when a namespace declaration happens on the node that it defines.
e.g. <hn:name xmlns:hn="http://www.ugorji.net" >
To handle this, each Element must be fully parsed at a time,
even if it amounts to multiple tokens which are returned one at a time on request.
xmlns is a special attribute name.
- It is used to define namespaces, including the default
- It is never returned as an AttrKey or AttrVal.
*We may decide later to allow user to use it e.g. you want to parse the xmlns mappings into a field.*
Number, bool, null, mapKey, etc can all be decoded from any xmlToken.
This accomodates map[int]string for example.
It should be possible to create a schema from the types,
or vice versa (generate types from schema with appropriate tags).
This is however out-of-scope from this parsing project.
We should write all namespace information at the first point that it is referenced in the tree,
and use the mapping for all child nodes and attributes. This means that state is maintained
at a point in the tree. This also means that calls to Decode or MustDecode will reset some state.
When decoding, it is important to keep track of entity references and default attribute values.
It seems these can only be stored in the DTD components. We should honor them when decoding.
Configuration for XMLHandle will look like this:
XMLHandle
DefaultNS string
// Encoding:
NS map[string]string // ns URI to key, used for encoding
// Decoding: in case ENTITY declared in external schema or dtd, store info needed here
Entities map[string]string // map of entity rep to character
During encode, if a namespace mapping is not defined for a namespace found on a struct,
then we create a mapping for it using nsN (where N is 1..1000000, and doesn't conflict
with any other namespace mapping).
Note that different fields in a struct can have different namespaces.
However, all fields will default to the namespace on the _struct field (if defined).
An XML document is a name, a map of attributes and a list of children.
Consequently, we cannot "DecodeNaked" into a map[string]interface{} (for example).
We have to "DecodeNaked" into something that resembles XML data.
To support DecodeNaked (decode into nil interface{}) we have to define some "supporting" types:
type Name struct { // Prefered. Less allocations due to conversions.
Local string
Space string
}
type Element struct {
Name Name
Attrs map[Name]string
Children []interface{} // each child is either *Element or string
}
Only two "supporting" types are exposed for XML: Name and Element.
We considered 'type Name string' where Name is like "Space Local" (space-separated).
We decided against it, because each creation of a name would lead to
double allocation (first convert []byte to string, then concatenate them into a string).
The benefit is that it is faster to read Attrs from a map. But given that Element is a value
object, we want to eschew methods and have public exposed variables.
We also considered the following, where xml types were not value objects, and we used
intelligent accessor methods to extract information and for performance.
*** WE DECIDED AGAINST THIS. ***
type Attr struct {
Name Name
Value string
}
// Element is a ValueObject: There are no accessor methods.
// Make element self-contained.
type Element struct {
Name Name
attrsMap map[string]string // where key is "Space Local"
attrs []Attr
childrenT []string
childrenE []Element
childrenI []int // each child is a index into T or E.
}
func (x *Element) child(i) interface{} // returns string or *Element
Per XML spec and our default handling, white space is insignificant between elements,
specifically between parent-child or siblings. White space occuring alone between start
and end element IS significant. However, if xml:space='preserve', then we 'preserve'
all whitespace. This is more critical when doing a DecodeNaked, but MAY not be as critical
when decoding into a typed value.
**Note: there is no xml: namespace. The xml: attributes were defined before namespaces.**
**So treat them as just "directives" that should be interpreted to mean something**.
On encoding, we don't add any prettifying markup (indenting, etc).
A document or element can only be encoded/decoded from/to a struct. In this mode:
- struct name maps to element name (or tag-info from _struct field)
- fields are mapped to child elements or attributes
A map is either encoded as attributes on current element, or as a set of child elements.
Maps are encoded as attributes iff their keys and values are primitives (number, bool, string).
A list is encoded as a set of child elements.
Primitives (number, bool, string) are encoded as an element, attribute or text
depending on the context.
Extensions must encode themselves as a text string.
Encoding is tough, specifically when encoding mappings, because we need to encode
as either attribute or element. To do this, we need to default to encoding as attributes,
and then let Encoder inform the Handle when to start encoding as nodes.
i.e. Encoder does something like:
h.EncodeMapStart()
h.Encode(), h.Encode(), ...
h.EncodeMapNotAttrSignal() // this is not a bool, because it's a signal
h.Encode(), h.Encode(), ...
h.EncodeEnd()
Only XMLHandle understands this, and will set itself to start encoding as elements.
This support extends to maps. For example, if a struct field is a map, and it has
the struct tag signifying it should be attr, then all its fields are encoded as attributes.
e.g.
type X struct {
M map[string]int `codec:"m,attr"` // encode as attributes
}
Question:
- if encoding a map, what if map keys have spaces in them???
Then they cannot be attributes or child elements. Error.
Misc:
- For attribute values, normalize by trimming beginning and ending white space,
and converting every white space sequence to a single space.
- ATTLIST restrictions are enforced.
e.g. default value of xml:space, skipping xml:XYZ style attributes, etc.
- Consider supporting NON-STRICT mode (e.g. to handle HTML parsing).
Some elements e.g. br, hr, etc need not close and should be auto-closed
... (see http://www.w3.org/TR/html4/loose.dtd)
An expansive set of entities are pre-defined.
- Have easy way to create a HTML parser:
add a HTML() method to XMLHandle, that will set Strict=false, specify AutoClose,
and add HTML Entities to the list.
- Support validating element/attribute XMLName before writing it.
Keep this behind a flag, which is set to false by default (for performance).
type XMLHandle struct {
CheckName bool
}
ROADMAP (1 weeks):
- build encoder (1 day)
- build decoder (based off xmlParser) (1 day)
- implement xmlParser (2 days).
Look at encoding/xml for inspiration.
- integrate and TEST (1 days)
- write article and post it (1 day)
*/
// ----------- PARSER -------------------
type xmlTokenType uint8
const (
_ xmlTokenType = iota << 1
xmlTokenElemStart
xmlTokenElemEnd
xmlTokenAttrKey
xmlTokenAttrVal
xmlTokenText
)
type xmlToken struct {
Type xmlTokenType
Value string
Namespace string // blank for AttrVal and Text
}
type xmlParser struct {
r decReader
toks []xmlToken // list of tokens.
ptr int // ptr into the toks slice
done bool // nothing else to parse. r now returns EOF.
}
func (x *xmlParser) next() (t *xmlToken) {
// once x.done, or x.ptr == len(x.toks) == 0, then return nil (to signify finish)
if !x.done && len(x.toks) == 0 {
x.nextTag()
}
// parses one element at a time (into possible many tokens)
if x.ptr < len(x.toks) {
t = &(x.toks[x.ptr])
x.ptr++
if x.ptr == len(x.toks) {
x.ptr = 0
x.toks = x.toks[:0]
}
}
return
}
// nextTag will parses the next element and fill up toks.
// It set done flag if/once EOF is reached.
func (x *xmlParser) nextTag() {
// TODO: implement.
}
// ----------- ENCODER -------------------
type xmlEncDriver struct {
e *Encoder
w encWriter
h *XMLHandle
b [64]byte // scratch
bs []byte // scratch
// s jsonStack
noBuiltInTypes
}
// ----------- DECODER -------------------
type xmlDecDriver struct {
d *Decoder
h *XMLHandle
r decReader // *bytesDecReader decReader
ct valueType // container type. one of unset, array or map.
bstr [8]byte // scratch used for string \UXXX parsing
b [64]byte // scratch
// wsSkipped bool // whitespace skipped
// s jsonStack
noBuiltInTypes
}
// DecodeNaked will decode into an XMLNode
// XMLName is a value object representing a namespace-aware NAME
type XMLName struct {
Local string
Space string
}
// XMLNode represents a "union" of the different types of XML Nodes.
// Only one of fields (Text or *Element) is set.
type XMLNode struct {
Element *Element
Text string
}
// XMLElement is a value object representing an fully-parsed XML element.
type XMLElement struct {
Name Name
Attrs map[XMLName]string
// Children is a list of child nodes, each being a *XMLElement or string
Children []XMLNode
}
// ----------- HANDLE -------------------
type XMLHandle struct {
BasicHandle
textEncodingType
DefaultNS string
NS map[string]string // ns URI to key, for encoding
Entities map[string]string // entity representation to string, for encoding.
}
func (h *XMLHandle) newEncDriver(e *Encoder) encDriver {
return &xmlEncDriver{e: e, w: e.w, h: h}
}
func (h *XMLHandle) newDecDriver(d *Decoder) decDriver {
// d := xmlDecDriver{r: r.(*bytesDecReader), h: h}
hd := xmlDecDriver{d: d, r: d.r, h: h}
hd.n.bytes = d.b[:]
return &hd
}
func (h *XMLHandle) SetInterfaceExt(rt reflect.Type, tag uint64, ext InterfaceExt) (err error) {
return h.SetExt(rt, tag, &setExtWrapper{i: ext})
}
var _ decDriver = (*xmlDecDriver)(nil)
var _ encDriver = (*xmlEncDriver)(nil)

23
vendor/github.com/ugorji/go/codec/z.go generated vendored Normal file
View File

@@ -0,0 +1,23 @@
// Copyright (c) 2012-2015 Ugorji Nwoke. All rights reserved.
// Use of this source code is governed by a MIT license found in the LICENSE file.
package codec
import "sort"
// TODO: this is brittle, as it depends on z.go's init() being called last.
// The current build tools all honor that files are passed in lexical order.
// However, we should consider using an init_channel,
// that each person doing init will write to.
func init() {
if !useLookupRecognizedTypes {
return
}
sort.Sort(uintptrSlice(recognizedRtids))
sort.Sort(uintptrSlice(recognizedRtidPtrs))
recognizedRtidOrPtrs = make([]uintptr, len(recognizedRtids)+len(recognizedRtidPtrs))
copy(recognizedRtidOrPtrs, recognizedRtids)
copy(recognizedRtidOrPtrs[len(recognizedRtids):], recognizedRtidPtrs)
sort.Sort(uintptrSlice(recognizedRtidOrPtrs))
}