Commit da22ea5d authored by Wojciech Tyczynski's avatar Wojciech Tyczynski

Update ugorji dependency

parent a7425bf0
...@@ -708,7 +708,7 @@ ...@@ -708,7 +708,7 @@
}, },
{ {
"ImportPath": "github.com/ugorji/go/codec", "ImportPath": "github.com/ugorji/go/codec",
"Rev": "8a2a3a8c488c3ebd98f422a965260278267a0551" "Rev": "f1f1a805ed361a0e078bb537e4ea78cd37dcf065"
}, },
{ {
"ImportPath": "github.com/vaughan0/go-ini", "ImportPath": "github.com/vaughan0/go-ini",
......
...@@ -98,7 +98,21 @@ with the standard net/rpc package. ...@@ -98,7 +98,21 @@ with the standard net/rpc package.
Usage Usage
Typical usage model: The Handle is SAFE for concurrent READ, but NOT SAFE for concurrent modification.
The Encoder and Decoder are NOT safe for concurrent use.
Consequently, the usage model is basically:
- Create and initialize the Handle before any use.
Once created, DO NOT modify it.
- Multiple Encoders or Decoders can now use the Handle concurrently.
They only read information off the Handle (never write).
- However, each Encoder or Decoder MUST not be used concurrently
- To re-use an Encoder/Decoder, call Reset(...) on it first.
This allows you use state maintained on the Encoder/Decoder.
Sample usage model:
// create and configure Handle // create and configure Handle
var ( var (
...@@ -148,3 +162,32 @@ Typical usage model: ...@@ -148,3 +162,32 @@ Typical usage model:
*/ */
package codec 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:
//
// - (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 cnsider supporting something like:
// type X struct {
// Name string
// Ys []Y
// Ys chan <- Y
// Ys func(interface{}) -> call this interface for each entry in there.
// }
// - 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(...)
// - Handle recursive types during encoding/decoding?
...@@ -59,8 +59,8 @@ type bincEncDriver struct { ...@@ -59,8 +59,8 @@ type bincEncDriver struct {
e *Encoder e *Encoder
w encWriter w encWriter
m map[string]uint16 // symbols m map[string]uint16 // symbols
s uint16 // symbols sequencer
b [scratchByteArrayLen]byte b [scratchByteArrayLen]byte
s uint16 // symbols sequencer
encNoSeparator encNoSeparator
} }
...@@ -318,9 +318,9 @@ func (e *bincEncDriver) encLenNumber(bd byte, v uint64) { ...@@ -318,9 +318,9 @@ func (e *bincEncDriver) encLenNumber(bd byte, v uint64) {
//------------------------------------ //------------------------------------
type bincDecSymbol struct { type bincDecSymbol struct {
i uint16
s string s string
b []byte b []byte
i uint16
} }
type bincDecDriver struct { type bincDecDriver struct {
...@@ -329,7 +329,6 @@ type bincDecDriver struct { ...@@ -329,7 +329,6 @@ type bincDecDriver struct {
r decReader r decReader
br bool // bytes reader br bool // bytes reader
bdRead bool bdRead bool
bdType valueType
bd byte bd byte
vd byte vd byte
vs byte vs byte
...@@ -347,24 +346,23 @@ func (d *bincDecDriver) readNextBd() { ...@@ -347,24 +346,23 @@ func (d *bincDecDriver) readNextBd() {
d.vd = d.bd >> 4 d.vd = d.bd >> 4
d.vs = d.bd & 0x0f d.vs = d.bd & 0x0f
d.bdRead = true d.bdRead = true
d.bdType = valueTypeUnset
} }
func (d *bincDecDriver) IsContainerType(vt valueType) (b bool) { func (d *bincDecDriver) ContainerType() (vt valueType) {
switch vt { if d.vd == bincVdSpecial && d.vs == bincSpNil {
case valueTypeNil: return valueTypeNil
return d.vd == bincVdSpecial && d.vs == bincSpNil } else if d.vd == bincVdByteArray {
case valueTypeBytes: return valueTypeBytes
return d.vd == bincVdByteArray } else if d.vd == bincVdString {
case valueTypeString: return valueTypeString
return d.vd == bincVdString } else if d.vd == bincVdArray {
case valueTypeArray: return valueTypeArray
return d.vd == bincVdArray } else if d.vd == bincVdMap {
case valueTypeMap: return valueTypeMap
return d.vd == bincVdMap } else {
// d.d.errorf("isContainerType: unsupported parameter: %v", vt)
} }
d.d.errorf("isContainerType: unsupported parameter: %v", vt) return valueTypeUnset
return // "unreachable"
} }
func (d *bincDecDriver) TryDecodeAsNil() bool { func (d *bincDecDriver) TryDecodeAsNil() bool {
...@@ -695,7 +693,7 @@ func (d *bincDecDriver) decStringAndBytes(bs []byte, withString, zerocopy bool) ...@@ -695,7 +693,7 @@ func (d *bincDecDriver) decStringAndBytes(bs []byte, withString, zerocopy bool)
if withString { if withString {
s = string(bs2) s = string(bs2)
} }
d.s = append(d.s, bincDecSymbol{symbol, s, bs2}) d.s = append(d.s, bincDecSymbol{i: symbol, s: s, b: bs2})
} }
default: default:
d.d.errorf("Invalid d.vd. Expecting string:0x%x, bytearray:0x%x or symbol: 0x%x. Got: 0x%x", d.d.errorf("Invalid d.vd. Expecting string:0x%x, bytearray:0x%x or symbol: 0x%x. Got: 0x%x",
...@@ -784,97 +782,95 @@ func (d *bincDecDriver) decodeExtV(verifyTag bool, tag byte) (xtag byte, xbs []b ...@@ -784,97 +782,95 @@ func (d *bincDecDriver) decodeExtV(verifyTag bool, tag byte) (xtag byte, xbs []b
return return
} }
func (d *bincDecDriver) DecodeNaked() (v interface{}, vt valueType, decodeFurther bool) { func (d *bincDecDriver) DecodeNaked() {
if !d.bdRead { if !d.bdRead {
d.readNextBd() d.readNextBd()
} }
n := &d.d.n
var decodeFurther bool
switch d.vd { switch d.vd {
case bincVdSpecial: case bincVdSpecial:
switch d.vs { switch d.vs {
case bincSpNil: case bincSpNil:
vt = valueTypeNil n.v = valueTypeNil
case bincSpFalse: case bincSpFalse:
vt = valueTypeBool n.v = valueTypeBool
v = false n.b = false
case bincSpTrue: case bincSpTrue:
vt = valueTypeBool n.v = valueTypeBool
v = true n.b = true
case bincSpNan: case bincSpNan:
vt = valueTypeFloat n.v = valueTypeFloat
v = math.NaN() n.f = math.NaN()
case bincSpPosInf: case bincSpPosInf:
vt = valueTypeFloat n.v = valueTypeFloat
v = math.Inf(1) n.f = math.Inf(1)
case bincSpNegInf: case bincSpNegInf:
vt = valueTypeFloat n.v = valueTypeFloat
v = math.Inf(-1) n.f = math.Inf(-1)
case bincSpZeroFloat: case bincSpZeroFloat:
vt = valueTypeFloat n.v = valueTypeFloat
v = float64(0) n.f = float64(0)
case bincSpZero: case bincSpZero:
vt = valueTypeUint n.v = valueTypeUint
v = uint64(0) // int8(0) n.u = uint64(0) // int8(0)
case bincSpNegOne: case bincSpNegOne:
vt = valueTypeInt n.v = valueTypeInt
v = int64(-1) // int8(-1) n.i = int64(-1) // int8(-1)
default: default:
d.d.errorf("decodeNaked: Unrecognized special value 0x%x", d.vs) d.d.errorf("decodeNaked: Unrecognized special value 0x%x", d.vs)
return
} }
case bincVdSmallInt: case bincVdSmallInt:
vt = valueTypeUint n.v = valueTypeUint
v = uint64(int8(d.vs)) + 1 // int8(d.vs) + 1 n.u = uint64(int8(d.vs)) + 1 // int8(d.vs) + 1
case bincVdPosInt: case bincVdPosInt:
vt = valueTypeUint n.v = valueTypeUint
v = d.decUint() n.u = d.decUint()
case bincVdNegInt: case bincVdNegInt:
vt = valueTypeInt n.v = valueTypeInt
v = -(int64(d.decUint())) n.i = -(int64(d.decUint()))
case bincVdFloat: case bincVdFloat:
vt = valueTypeFloat n.v = valueTypeFloat
v = d.decFloat() n.f = d.decFloat()
case bincVdSymbol: case bincVdSymbol:
vt = valueTypeSymbol n.v = valueTypeSymbol
v = d.DecodeString() n.s = d.DecodeString()
case bincVdString: case bincVdString:
vt = valueTypeString n.v = valueTypeString
v = d.DecodeString() n.s = d.DecodeString()
case bincVdByteArray: case bincVdByteArray:
vt = valueTypeBytes n.v = valueTypeBytes
v = d.DecodeBytes(nil, false, false) n.l = d.DecodeBytes(nil, false, false)
case bincVdTimestamp: case bincVdTimestamp:
vt = valueTypeTimestamp n.v = valueTypeTimestamp
tt, err := decodeTime(d.r.readx(int(d.vs))) tt, err := decodeTime(d.r.readx(int(d.vs)))
if err != nil { if err != nil {
panic(err) panic(err)
} }
v = tt n.t = tt
case bincVdCustomExt: case bincVdCustomExt:
vt = valueTypeExt n.v = valueTypeExt
l := d.decLen() l := d.decLen()
var re RawExt n.u = uint64(d.r.readn1())
re.Tag = uint64(d.r.readn1()) n.l = d.r.readx(l)
re.Data = d.r.readx(l)
v = &re
vt = valueTypeExt
case bincVdArray: case bincVdArray:
vt = valueTypeArray n.v = valueTypeArray
decodeFurther = true decodeFurther = true
case bincVdMap: case bincVdMap:
vt = valueTypeMap n.v = valueTypeMap
decodeFurther = true decodeFurther = true
default: default:
d.d.errorf("decodeNaked: Unrecognized d.vd: 0x%x", d.vd) d.d.errorf("decodeNaked: Unrecognized d.vd: 0x%x", d.vd)
return
} }
if !decodeFurther { if !decodeFurther {
d.bdRead = false d.bdRead = false
} }
if vt == valueTypeUint && d.h.SignedInteger { if n.v == valueTypeUint && d.h.SignedInteger {
d.bdType = valueTypeInt n.v = valueTypeInt
v = int64(v.(uint64)) n.i = int64(n.u)
} }
return return
} }
...@@ -898,6 +894,10 @@ type BincHandle struct { ...@@ -898,6 +894,10 @@ type BincHandle struct {
binaryEncodingType binaryEncodingType
} }
func (h *BincHandle) SetBytesExt(rt reflect.Type, tag uint64, ext BytesExt) (err error) {
return h.SetExt(rt, tag, &setExtWrapper{b: ext})
}
func (h *BincHandle) newEncDriver(e *Encoder) encDriver { func (h *BincHandle) newEncDriver(e *Encoder) encDriver {
return &bincEncDriver{e: e, w: e.w} return &bincEncDriver{e: e, w: e.w}
} }
...@@ -906,8 +906,12 @@ func (h *BincHandle) newDecDriver(d *Decoder) decDriver { ...@@ -906,8 +906,12 @@ func (h *BincHandle) newDecDriver(d *Decoder) decDriver {
return &bincDecDriver{d: d, r: d.r, h: h, br: d.bytes} return &bincDecDriver{d: d, r: d.r, h: h, br: d.bytes}
} }
func (h *BincHandle) SetBytesExt(rt reflect.Type, tag uint64, ext BytesExt) (err error) { func (e *bincEncDriver) reset() {
return h.SetExt(rt, tag, &setExtWrapper{b: ext}) e.w = e.e.w
}
func (d *bincDecDriver) reset() {
d.r = d.d.r
} }
var _ decDriver = (*bincDecDriver)(nil) var _ decDriver = (*bincDecDriver)(nil)
......
...@@ -60,11 +60,11 @@ const ( ...@@ -60,11 +60,11 @@ const (
// ------------------- // -------------------
type cborEncDriver struct { type cborEncDriver struct {
noBuiltInTypes
encNoSeparator
e *Encoder e *Encoder
w encWriter w encWriter
h *CborHandle h *CborHandle
noBuiltInTypes
encNoSeparator
x [8]byte x [8]byte
} }
...@@ -175,11 +175,10 @@ type cborDecDriver struct { ...@@ -175,11 +175,10 @@ type cborDecDriver struct {
d *Decoder d *Decoder
h *CborHandle h *CborHandle
r decReader r decReader
b [scratchByteArrayLen]byte
br bool // bytes reader br bool // bytes reader
bdRead bool bdRead bool
bdType valueType
bd byte bd byte
b [scratchByteArrayLen]byte
noBuiltInTypes noBuiltInTypes
decNoSeparator decNoSeparator
} }
...@@ -187,24 +186,23 @@ type cborDecDriver struct { ...@@ -187,24 +186,23 @@ type cborDecDriver struct {
func (d *cborDecDriver) readNextBd() { func (d *cborDecDriver) readNextBd() {
d.bd = d.r.readn1() d.bd = d.r.readn1()
d.bdRead = true d.bdRead = true
d.bdType = valueTypeUnset
} }
func (d *cborDecDriver) IsContainerType(vt valueType) (bv bool) { func (d *cborDecDriver) ContainerType() (vt valueType) {
switch vt { if d.bd == cborBdNil {
case valueTypeNil: return valueTypeNil
return d.bd == cborBdNil } else if d.bd == cborBdIndefiniteBytes || (d.bd >= cborBaseBytes && d.bd < cborBaseString) {
case valueTypeBytes: return valueTypeBytes
return d.bd == cborBdIndefiniteBytes || (d.bd >= cborBaseBytes && d.bd < cborBaseString) } else if d.bd == cborBdIndefiniteString || (d.bd >= cborBaseString && d.bd < cborBaseArray) {
case valueTypeString: return valueTypeString
return d.bd == cborBdIndefiniteString || (d.bd >= cborBaseString && d.bd < cborBaseArray) } else if d.bd == cborBdIndefiniteArray || (d.bd >= cborBaseArray && d.bd < cborBaseMap) {
case valueTypeArray: return valueTypeArray
return d.bd == cborBdIndefiniteArray || (d.bd >= cborBaseArray && d.bd < cborBaseMap) } else if d.bd == cborBdIndefiniteMap || (d.bd >= cborBaseMap && d.bd < cborBaseTag) {
case valueTypeMap: return valueTypeMap
return d.bd == cborBdIndefiniteMap || (d.bd >= cborBaseMap && d.bd < cborBaseTag) } else {
// d.d.errorf("isContainerType: unsupported parameter: %v", vt)
} }
d.d.errorf("isContainerType: unsupported parameter: %v", vt) return valueTypeUnset
return // "unreachable"
} }
func (d *cborDecDriver) TryDecodeAsNil() bool { func (d *cborDecDriver) TryDecodeAsNil() bool {
...@@ -446,71 +444,72 @@ func (d *cborDecDriver) DecodeExt(rv interface{}, xtag uint64, ext Ext) (realxta ...@@ -446,71 +444,72 @@ func (d *cborDecDriver) DecodeExt(rv interface{}, xtag uint64, ext Ext) (realxta
return return
} }
func (d *cborDecDriver) DecodeNaked() (v interface{}, vt valueType, decodeFurther bool) { func (d *cborDecDriver) DecodeNaked() {
if !d.bdRead { if !d.bdRead {
d.readNextBd() d.readNextBd()
} }
n := &d.d.n
var decodeFurther bool
switch d.bd { switch d.bd {
case cborBdNil: case cborBdNil:
vt = valueTypeNil n.v = valueTypeNil
case cborBdFalse: case cborBdFalse:
vt = valueTypeBool n.v = valueTypeBool
v = false n.b = false
case cborBdTrue: case cborBdTrue:
vt = valueTypeBool n.v = valueTypeBool
v = true n.b = true
case cborBdFloat16, cborBdFloat32: case cborBdFloat16, cborBdFloat32:
vt = valueTypeFloat n.v = valueTypeFloat
v = d.DecodeFloat(true) n.f = d.DecodeFloat(true)
case cborBdFloat64: case cborBdFloat64:
vt = valueTypeFloat n.v = valueTypeFloat
v = d.DecodeFloat(false) n.f = d.DecodeFloat(false)
case cborBdIndefiniteBytes: case cborBdIndefiniteBytes:
vt = valueTypeBytes n.v = valueTypeBytes
v = d.DecodeBytes(nil, false, false) n.l = d.DecodeBytes(nil, false, false)
case cborBdIndefiniteString: case cborBdIndefiniteString:
vt = valueTypeString n.v = valueTypeString
v = d.DecodeString() n.s = d.DecodeString()
case cborBdIndefiniteArray: case cborBdIndefiniteArray:
vt = valueTypeArray n.v = valueTypeArray
decodeFurther = true decodeFurther = true
case cborBdIndefiniteMap: case cborBdIndefiniteMap:
vt = valueTypeMap n.v = valueTypeMap
decodeFurther = true decodeFurther = true
default: default:
switch { switch {
case d.bd >= cborBaseUint && d.bd < cborBaseNegInt: case d.bd >= cborBaseUint && d.bd < cborBaseNegInt:
if d.h.SignedInteger { if d.h.SignedInteger {
vt = valueTypeInt n.v = valueTypeInt
v = d.DecodeInt(64) n.i = d.DecodeInt(64)
} else { } else {
vt = valueTypeUint n.v = valueTypeUint
v = d.DecodeUint(64) n.u = d.DecodeUint(64)
} }
case d.bd >= cborBaseNegInt && d.bd < cborBaseBytes: case d.bd >= cborBaseNegInt && d.bd < cborBaseBytes:
vt = valueTypeInt n.v = valueTypeInt
v = d.DecodeInt(64) n.i = d.DecodeInt(64)
case d.bd >= cborBaseBytes && d.bd < cborBaseString: case d.bd >= cborBaseBytes && d.bd < cborBaseString:
vt = valueTypeBytes n.v = valueTypeBytes
v = d.DecodeBytes(nil, false, false) n.l = d.DecodeBytes(nil, false, false)
case d.bd >= cborBaseString && d.bd < cborBaseArray: case d.bd >= cborBaseString && d.bd < cborBaseArray:
vt = valueTypeString n.v = valueTypeString
v = d.DecodeString() n.s = d.DecodeString()
case d.bd >= cborBaseArray && d.bd < cborBaseMap: case d.bd >= cborBaseArray && d.bd < cborBaseMap:
vt = valueTypeArray n.v = valueTypeArray
decodeFurther = true decodeFurther = true
case d.bd >= cborBaseMap && d.bd < cborBaseTag: case d.bd >= cborBaseMap && d.bd < cborBaseTag:
vt = valueTypeMap n.v = valueTypeMap
decodeFurther = true decodeFurther = true
case d.bd >= cborBaseTag && d.bd < cborBaseSimple: case d.bd >= cborBaseTag && d.bd < cborBaseSimple:
vt = valueTypeExt n.v = valueTypeExt
var re RawExt n.u = d.decUint()
ui := d.decUint() n.l = nil
d.bdRead = false d.bdRead = false
re.Tag = ui // d.d.decode(&re.Value) // handled by decode itself.
d.d.decode(&re.Value)
v = &re
// decodeFurther = true // decodeFurther = true
default: default:
d.d.errorf("decodeNaked: Unrecognized d.bd: 0x%x", d.bd) d.d.errorf("decodeNaked: Unrecognized d.bd: 0x%x", d.bd)
...@@ -557,8 +556,12 @@ func (d *cborDecDriver) DecodeNaked() (v interface{}, vt valueType, decodeFurthe ...@@ -557,8 +556,12 @@ func (d *cborDecDriver) DecodeNaked() (v interface{}, vt valueType, decodeFurthe
// // Now, vv contains the same string "one-byte" // // Now, vv contains the same string "one-byte"
// //
type CborHandle struct { type CborHandle struct {
BasicHandle
binaryEncodingType binaryEncodingType
BasicHandle
}
func (h *CborHandle) SetInterfaceExt(rt reflect.Type, tag uint64, ext InterfaceExt) (err error) {
return h.SetExt(rt, tag, &setExtWrapper{i: ext})
} }
func (h *CborHandle) newEncDriver(e *Encoder) encDriver { func (h *CborHandle) newEncDriver(e *Encoder) encDriver {
...@@ -569,8 +572,12 @@ func (h *CborHandle) newDecDriver(d *Decoder) decDriver { ...@@ -569,8 +572,12 @@ func (h *CborHandle) newDecDriver(d *Decoder) decDriver {
return &cborDecDriver{d: d, r: d.r, h: h, br: d.bytes} return &cborDecDriver{d: d, r: d.r, h: h, br: d.bytes}
} }
func (h *CborHandle) SetInterfaceExt(rt reflect.Type, tag uint64, ext InterfaceExt) (err error) { func (e *cborEncDriver) reset() {
return h.SetExt(rt, tag, &setExtWrapper{i: ext}) e.w = e.e.w
}
func (d *cborDecDriver) reset() {
d.r = d.d.r
} }
var _ decDriver = (*cborDecDriver)(nil) var _ decDriver = (*cborDecDriver)(nil)
......
...@@ -9,6 +9,7 @@ import ( ...@@ -9,6 +9,7 @@ import (
"fmt" "fmt"
"io" "io"
"reflect" "reflect"
"time"
) )
// Some tagging information for error messages. // Some tagging information for error messages.
...@@ -48,16 +49,23 @@ type decDriver interface { ...@@ -48,16 +49,23 @@ type decDriver interface {
// this will check if the next token is a break. // this will check if the next token is a break.
CheckBreak() bool CheckBreak() bool
TryDecodeAsNil() bool TryDecodeAsNil() bool
// check if a container type: vt is one of: Bytes, String, Nil, Slice or Map. // vt is one of: Bytes, String, Nil, Slice or Map. Return unSet if not known.
// if vt param == valueTypeNil, and nil is seen in stream, consume the nil. ContainerType() (vt valueType)
IsContainerType(vt valueType) bool
IsBuiltinType(rt uintptr) bool IsBuiltinType(rt uintptr) bool
DecodeBuiltin(rt uintptr, v interface{}) DecodeBuiltin(rt uintptr, v interface{})
//decodeNaked: Numbers are decoded as int64, uint64, float64 only (no smaller sized number types).
//for extensions, decodeNaked must completely decode them as a *RawExt. // DecodeNaked will decode primitives (number, bool, string, []byte) and RawExt.
//extensions should also use readx to decode them, for efficiency. // For maps and arrays, it will not do the decoding in-band, but will signal
//kInterface will extract the detached byte slice if it has to pass it outside its realm. // the decoder, so that is done later, by setting the decNaked.valueType field.
DecodeNaked() (v interface{}, vt valueType, decodeFurther bool) //
// Note: Numbers are decoded as int64, uint64, float64 only (no smaller sized number types).
// for extensions, DecodeNaked must read the tag and the []byte if it exists.
// if the []byte is not read, then kInterfaceNaked will treat it as a Handle
// that stores the subsequent value in-band, and complete reading the RawExt.
//
// extensions should also use readx to decode them, for efficiency.
// kInterface will extract the detached byte slice if it has to pass it outside its realm.
DecodeNaked()
DecodeInt(bitsize uint8) (i int64) DecodeInt(bitsize uint8) (i int64)
DecodeUint(bitsize uint8) (ui uint64) DecodeUint(bitsize uint8) (ui uint64)
DecodeFloat(chkOverflow32 bool) (f float64) DecodeFloat(chkOverflow32 bool) (f float64)
...@@ -78,13 +86,15 @@ type decDriver interface { ...@@ -78,13 +86,15 @@ type decDriver interface {
// decodeExt(verifyTag bool, tag byte) (xtag byte, xbs []byte) // decodeExt(verifyTag bool, tag byte) (xtag byte, xbs []byte)
ReadMapStart() int ReadMapStart() int
ReadArrayStart() int ReadArrayStart() int
// ReadEnd registers the end of a map or array.
ReadEnd() reset()
uncacheRead()
} }
type decNoSeparator struct{} type decNoSeparator struct{}
func (_ decNoSeparator) ReadEnd() {} func (_ decNoSeparator) ReadEnd() {}
func (_ decNoSeparator) uncacheRead() {}
type DecodeOptions struct { type DecodeOptions struct {
// MapType specifies type to use during schema-less decoding of a map in the stream. // MapType specifies type to use during schema-less decoding of a map in the stream.
...@@ -326,6 +336,13 @@ type bytesDecReader struct { ...@@ -326,6 +336,13 @@ type bytesDecReader struct {
t int // track start t int // track start
} }
func (z *bytesDecReader) reset(in []byte) {
z.b = in
z.a = len(in)
z.c = 0
z.t = 0
}
func (z *bytesDecReader) numread() int { func (z *bytesDecReader) numread() int {
return z.c return z.c
} }
...@@ -460,12 +477,8 @@ func (f *decFnInfo) textUnmarshal(rv reflect.Value) { ...@@ -460,12 +477,8 @@ func (f *decFnInfo) textUnmarshal(rv reflect.Value) {
func (f *decFnInfo) jsonUnmarshal(rv reflect.Value) { func (f *decFnInfo) jsonUnmarshal(rv reflect.Value) {
tm := f.getValueForUnmarshalInterface(rv, f.ti.junmIndir).(jsonUnmarshaler) tm := f.getValueForUnmarshalInterface(rv, f.ti.junmIndir).(jsonUnmarshaler)
// bs := f.d.d.DecodeBytes(f.d.b[:], true, true) // bs := f.d.d.DecodeBytes(f.d.b[:], true, true)
// grab the bytes to be read, as UnmarshalJSON wants the full JSON to unmarshal it itself. // grab the bytes to be read, as UnmarshalJSON needs the full JSON so as to unmarshal it itself.
f.d.r.track() fnerr := tm.UnmarshalJSON(f.d.nextValueBytes())
f.d.swallow()
bs := f.d.r.stopTrack()
// fmt.Printf(">>>>>> REFLECTION JSON: %s\n", bs)
fnerr := tm.UnmarshalJSON(bs)
if fnerr != nil { if fnerr != nil {
panic(fnerr) panic(fnerr)
} }
...@@ -549,63 +562,96 @@ func (f *decFnInfo) kInterfaceNaked() (rvn reflect.Value) { ...@@ -549,63 +562,96 @@ func (f *decFnInfo) kInterfaceNaked() (rvn reflect.Value) {
// nil interface: // nil interface:
// use some hieristics to decode it appropriately // use some hieristics to decode it appropriately
// based on the detected next value in the stream. // based on the detected next value in the stream.
v, vt, decodeFurther := f.d.d.DecodeNaked() d := f.d
if vt == valueTypeNil { d.d.DecodeNaked()
n := &d.n
if n.v == valueTypeNil {
return return
} }
// We cannot decode non-nil stream value into nil interface with methods (e.g. io.Reader). // We cannot decode non-nil stream value into nil interface with methods (e.g. io.Reader).
if num := f.ti.rt.NumMethod(); num > 0 { // if num := f.ti.rt.NumMethod(); num > 0 {
f.d.errorf("cannot decode non-nil codec value into nil %v (%v methods)", f.ti.rt, num) if f.ti.numMeth > 0 {
d.errorf("cannot decode non-nil codec value into nil %v (%v methods)", f.ti.rt, f.ti.numMeth)
return return
} }
var useRvn bool // var useRvn bool
switch vt { switch n.v {
case valueTypeMap: case valueTypeMap:
if f.d.h.MapType == nil { // if d.h.MapType == nil || d.h.MapType == mapIntfIntfTyp {
var m2 map[interface{}]interface{} // } else if d.h.MapType == mapStrIntfTyp { // for json performance
v = &m2 // }
if d.mtid == 0 || d.mtid == mapIntfIntfTypId {
l := len(n.ms)
n.ms = append(n.ms, nil)
d.decode(&n.ms[l])
rvn = reflect.ValueOf(&n.ms[l]).Elem()
n.ms = n.ms[:l]
} else if d.mtid == mapStrIntfTypId { // for json performance
l := len(n.ns)
n.ns = append(n.ns, nil)
d.decode(&n.ns[l])
rvn = reflect.ValueOf(&n.ns[l]).Elem()
n.ns = n.ns[:l]
} else { } else {
rvn = reflect.New(f.d.h.MapType).Elem() rvn = reflect.New(d.h.MapType).Elem()
useRvn = true d.decodeValue(rvn, nil)
} }
case valueTypeArray: case valueTypeArray:
if f.d.h.SliceType == nil { // if d.h.SliceType == nil || d.h.SliceType == intfSliceTyp {
var m2 []interface{} if d.stid == 0 || d.stid == intfSliceTypId {
v = &m2 l := len(n.ss)
n.ss = append(n.ss, nil)
d.decode(&n.ss[l])
rvn = reflect.ValueOf(&n.ss[l]).Elem()
n.ss = n.ss[:l]
} else { } else {
rvn = reflect.New(f.d.h.SliceType).Elem() rvn = reflect.New(d.h.SliceType).Elem()
useRvn = true d.decodeValue(rvn, nil)
} }
case valueTypeExt: case valueTypeExt:
re := v.(*RawExt) var v interface{}
bfn := f.d.h.getExtForTag(re.Tag) tag, bytes := n.u, n.l // calling decode below might taint the values
if bytes == nil {
l := len(n.is)
n.is = append(n.is, nil)
v2 := &n.is[l]
n.is = n.is[:l]
d.decode(v2)
v = *v2
}
bfn := d.h.getExtForTag(tag)
if bfn == nil { if bfn == nil {
re.Data = detachZeroCopyBytes(f.d.bytes, nil, re.Data) var re RawExt
rvn = reflect.ValueOf(*re) re.Tag = tag
re.Data = detachZeroCopyBytes(d.bytes, nil, bytes)
rvn = reflect.ValueOf(re)
} else { } else {
rvnA := reflect.New(bfn.rt) rvnA := reflect.New(bfn.rt)
rvn = rvnA.Elem() rvn = rvnA.Elem()
if re.Data != nil { if bytes != nil {
bfn.ext.ReadExt(rvnA.Interface(), re.Data) bfn.ext.ReadExt(rvnA.Interface(), bytes)
} else { } else {
bfn.ext.UpdateExt(rvnA.Interface(), re.Value) bfn.ext.UpdateExt(rvnA.Interface(), v)
} }
} }
return case valueTypeNil:
} // no-op
if decodeFurther { case valueTypeInt:
if useRvn { rvn = reflect.ValueOf(&n.i).Elem()
f.d.decodeValue(rvn, nil) case valueTypeUint:
} else if v != nil { rvn = reflect.ValueOf(&n.u).Elem()
// this v is a pointer, so we need to dereference it when done case valueTypeFloat:
f.d.decode(v) rvn = reflect.ValueOf(&n.f).Elem()
rvn = reflect.ValueOf(v).Elem() case valueTypeBool:
useRvn = true rvn = reflect.ValueOf(&n.b).Elem()
} case valueTypeString, valueTypeSymbol:
} rvn = reflect.ValueOf(&n.s).Elem()
case valueTypeBytes:
if !useRvn && v != nil { rvn = reflect.ValueOf(&n.l).Elem()
rvn = reflect.ValueOf(v) case valueTypeTimestamp:
rvn = reflect.ValueOf(&n.t).Elem()
default:
panic(fmt.Errorf("kInterfaceNaked: unexpected valueType: %d", n.v))
} }
return return
} }
...@@ -655,10 +701,14 @@ func (f *decFnInfo) kStruct(rv reflect.Value) { ...@@ -655,10 +701,14 @@ func (f *decFnInfo) kStruct(rv reflect.Value) {
fti := f.ti fti := f.ti
d := f.d d := f.d
dd := d.d dd := d.d
if dd.IsContainerType(valueTypeMap) { cr := d.cr
ctyp := dd.ContainerType()
if ctyp == valueTypeMap {
containerLen := dd.ReadMapStart() containerLen := dd.ReadMapStart()
if containerLen == 0 { if containerLen == 0 {
dd.ReadEnd() if cr != nil {
cr.sendContainerState(containerMapEnd)
}
return return
} }
tisfi := fti.sfi tisfi := fti.sfi
...@@ -666,8 +716,14 @@ func (f *decFnInfo) kStruct(rv reflect.Value) { ...@@ -666,8 +716,14 @@ func (f *decFnInfo) kStruct(rv reflect.Value) {
if hasLen { if hasLen {
for j := 0; j < containerLen; j++ { for j := 0; j < containerLen; j++ {
// rvkencname := dd.DecodeString() // rvkencname := dd.DecodeString()
if cr != nil {
cr.sendContainerState(containerMapKey)
}
rvkencname := stringView(dd.DecodeBytes(f.d.b[:], true, true)) rvkencname := stringView(dd.DecodeBytes(f.d.b[:], true, true))
// rvksi := ti.getForEncName(rvkencname) // rvksi := ti.getForEncName(rvkencname)
if cr != nil {
cr.sendContainerState(containerMapValue)
}
if k := fti.indexForEncName(rvkencname); k > -1 { if k := fti.indexForEncName(rvkencname); k > -1 {
si := tisfi[k] si := tisfi[k]
if dd.TryDecodeAsNil() { if dd.TryDecodeAsNil() {
...@@ -682,8 +738,14 @@ func (f *decFnInfo) kStruct(rv reflect.Value) { ...@@ -682,8 +738,14 @@ func (f *decFnInfo) kStruct(rv reflect.Value) {
} else { } else {
for j := 0; !dd.CheckBreak(); j++ { for j := 0; !dd.CheckBreak(); j++ {
// rvkencname := dd.DecodeString() // rvkencname := dd.DecodeString()
if cr != nil {
cr.sendContainerState(containerMapKey)
}
rvkencname := stringView(dd.DecodeBytes(f.d.b[:], true, true)) rvkencname := stringView(dd.DecodeBytes(f.d.b[:], true, true))
// rvksi := ti.getForEncName(rvkencname) // rvksi := ti.getForEncName(rvkencname)
if cr != nil {
cr.sendContainerState(containerMapValue)
}
if k := fti.indexForEncName(rvkencname); k > -1 { if k := fti.indexForEncName(rvkencname); k > -1 {
si := tisfi[k] si := tisfi[k]
if dd.TryDecodeAsNil() { if dd.TryDecodeAsNil() {
...@@ -695,12 +757,16 @@ func (f *decFnInfo) kStruct(rv reflect.Value) { ...@@ -695,12 +757,16 @@ func (f *decFnInfo) kStruct(rv reflect.Value) {
d.structFieldNotFound(-1, rvkencname) d.structFieldNotFound(-1, rvkencname)
} }
} }
dd.ReadEnd()
} }
} else if dd.IsContainerType(valueTypeArray) { if cr != nil {
cr.sendContainerState(containerMapEnd)
}
} else if ctyp == valueTypeArray {
containerLen := dd.ReadArrayStart() containerLen := dd.ReadArrayStart()
if containerLen == 0 { if containerLen == 0 {
dd.ReadEnd() if cr != nil {
cr.sendContainerState(containerArrayEnd)
}
return return
} }
// Not much gain from doing it two ways for array. // Not much gain from doing it two ways for array.
...@@ -714,6 +780,9 @@ func (f *decFnInfo) kStruct(rv reflect.Value) { ...@@ -714,6 +780,9 @@ func (f *decFnInfo) kStruct(rv reflect.Value) {
} else if dd.CheckBreak() { } else if dd.CheckBreak() {
break break
} }
if cr != nil {
cr.sendContainerState(containerArrayElem)
}
if dd.TryDecodeAsNil() { if dd.TryDecodeAsNil() {
si.setToZeroValue(rv) si.setToZeroValue(rv)
} else { } else {
...@@ -723,10 +792,15 @@ func (f *decFnInfo) kStruct(rv reflect.Value) { ...@@ -723,10 +792,15 @@ func (f *decFnInfo) kStruct(rv reflect.Value) {
if containerLen > len(fti.sfip) { if containerLen > len(fti.sfip) {
// read remaining values and throw away // read remaining values and throw away
for j := len(fti.sfip); j < containerLen; j++ { for j := len(fti.sfip); j < containerLen; j++ {
if cr != nil {
cr.sendContainerState(containerArrayElem)
}
d.structFieldNotFound(j, "") d.structFieldNotFound(j, "")
} }
} }
dd.ReadEnd() if cr != nil {
cr.sendContainerState(containerArrayEnd)
}
} else { } else {
f.d.error(onlyMapOrArrayCanDecodeIntoStructErr) f.d.error(onlyMapOrArrayCanDecodeIntoStructErr)
return return
...@@ -740,59 +814,50 @@ func (f *decFnInfo) kSlice(rv reflect.Value) { ...@@ -740,59 +814,50 @@ func (f *decFnInfo) kSlice(rv reflect.Value) {
d := f.d d := f.d
dd := d.d dd := d.d
rtelem0 := ti.rt.Elem() rtelem0 := ti.rt.Elem()
ctyp := dd.ContainerType()
if dd.IsContainerType(valueTypeBytes) || dd.IsContainerType(valueTypeString) { if ctyp == valueTypeBytes || ctyp == valueTypeString {
if ti.rtid == uint8SliceTypId || rtelem0.Kind() == reflect.Uint8 { // you can only decode bytes or string in the stream into a slice or array of bytes
if f.seq == seqTypeChan { if !(ti.rtid == uint8SliceTypId || rtelem0.Kind() == reflect.Uint8) {
bs2 := dd.DecodeBytes(nil, false, true) f.d.errorf("bytes or string in the stream must be decoded into a slice or array of bytes, not %v", ti.rt)
ch := rv.Interface().(chan<- byte) }
for _, b := range bs2 { if f.seq == seqTypeChan {
ch <- b bs2 := dd.DecodeBytes(nil, false, true)
} ch := rv.Interface().(chan<- byte)
} else { for _, b := range bs2 {
rvbs := rv.Bytes() ch <- b
bs2 := dd.DecodeBytes(rvbs, false, false) }
if rvbs == nil && bs2 != nil || rvbs != nil && bs2 == nil || len(bs2) != len(rvbs) { } else {
if rv.CanSet() { rvbs := rv.Bytes()
rv.SetBytes(bs2) bs2 := dd.DecodeBytes(rvbs, false, false)
} else { if rvbs == nil && bs2 != nil || rvbs != nil && bs2 == nil || len(bs2) != len(rvbs) {
copy(rvbs, bs2) if rv.CanSet() {
} rv.SetBytes(bs2)
} else {
copy(rvbs, bs2)
} }
} }
return
} }
return
} }
// array := f.seq == seqTypeChan // array := f.seq == seqTypeChan
slh, containerLenS := d.decSliceHelperStart() slh, containerLenS := d.decSliceHelperStart() // only expects valueType(Array|Map)
var rvlen, numToRead int
var truncated bool // says that the len of the sequence is not same as the expected number of elements.
numToRead = containerLenS // if truncated, reset numToRead // // an array can never return a nil slice. so no need to check f.array here.
if containerLenS == 0 {
// an array can never return a nil slice. so no need to check f.array here.
if rv.IsNil() {
// either chan or slice
if rvlen, truncated = decInferLen(containerLenS, f.d.h.MaxInitLen, int(rtelem0.Size())); truncated {
numToRead = rvlen
}
if f.seq == seqTypeSlice { if f.seq == seqTypeSlice {
rv.Set(reflect.MakeSlice(ti.rt, rvlen, rvlen)) if rv.IsNil() {
rv.Set(reflect.MakeSlice(ti.rt, 0, 0))
} else {
rv.SetLen(0)
}
} else if f.seq == seqTypeChan { } else if f.seq == seqTypeChan {
rv.Set(reflect.MakeChan(ti.rt, rvlen)) if rv.IsNil() {
} rv.Set(reflect.MakeChan(ti.rt, 0))
} else { }
rvlen = rv.Len()
}
if containerLenS == 0 {
if f.seq == seqTypeSlice && rvlen != 0 {
rv.SetLen(0)
} }
// dd.ReadEnd() slh.End()
return return
} }
...@@ -806,30 +871,48 @@ func (f *decFnInfo) kSlice(rv reflect.Value) { ...@@ -806,30 +871,48 @@ func (f *decFnInfo) kSlice(rv reflect.Value) {
rv0 = rv rv0 = rv
rvChanged := false rvChanged := false
rvcap := rv.Cap()
// for j := 0; j < containerLenS; j++ { // for j := 0; j < containerLenS; j++ {
var rvlen int
if containerLenS >= 0 { // hasLen if containerLenS > 0 { // hasLen
if f.seq == seqTypeChan { if f.seq == seqTypeChan {
if rv.IsNil() {
rvlen, _ = decInferLen(containerLenS, f.d.h.MaxInitLen, int(rtelem0.Size()))
rv.Set(reflect.MakeChan(ti.rt, rvlen))
}
// handle chan specially: // handle chan specially:
for j := 0; j < containerLenS; j++ { for j := 0; j < containerLenS; j++ {
rv9 = reflect.New(rtelem0).Elem() rv9 = reflect.New(rtelem0).Elem()
slh.ElemContainerState(j)
d.decodeValue(rv9, fn) d.decodeValue(rv9, fn)
rv.Send(rv9) rv.Send(rv9)
} }
} else { // slice or array } else { // slice or array
var truncated bool // says len of sequence is not same as expected number of elements
numToRead := containerLenS // if truncated, reset numToRead
rvcap := rv.Cap()
rvlen = rv.Len()
if containerLenS > rvcap { if containerLenS > rvcap {
if f.seq == seqTypeArray { if f.seq == seqTypeArray {
d.arrayCannotExpand(rvlen, containerLenS) d.arrayCannotExpand(rvlen, containerLenS)
} else { } else {
oldRvlenGtZero := rvlen > 0 oldRvlenGtZero := rvlen > 0
rvlen, truncated = decInferLen(containerLenS, f.d.h.MaxInitLen, int(rtelem0.Size())) rvlen, truncated = decInferLen(containerLenS, f.d.h.MaxInitLen, int(rtelem0.Size()))
rv = reflect.MakeSlice(ti.rt, rvlen, rvlen) if truncated {
if oldRvlenGtZero && !isImmutableKind(rtelem0.Kind()) { if rvlen <= rvcap {
rv.SetLen(rvlen)
} else {
rv = reflect.MakeSlice(ti.rt, rvlen, rvlen)
rvChanged = true
}
} else {
rv = reflect.MakeSlice(ti.rt, rvlen, rvlen)
rvChanged = true
}
if rvChanged && oldRvlenGtZero && !isImmutableKind(rtelem0.Kind()) {
reflect.Copy(rv, rv0) // only copy up to length NOT cap i.e. rv0.Slice(0, rvcap) reflect.Copy(rv, rv0) // only copy up to length NOT cap i.e. rv0.Slice(0, rvcap)
} }
rvChanged = true rvcap = rvlen
} }
numToRead = rvlen numToRead = rvlen
} else if containerLenS != rvlen { } else if containerLenS != rvlen {
...@@ -841,6 +924,7 @@ func (f *decFnInfo) kSlice(rv reflect.Value) { ...@@ -841,6 +924,7 @@ func (f *decFnInfo) kSlice(rv reflect.Value) {
j := 0 j := 0
// we read up to the numToRead // we read up to the numToRead
for ; j < numToRead; j++ { for ; j < numToRead; j++ {
slh.ElemContainerState(j)
d.decodeValue(rv.Index(j), fn) d.decodeValue(rv.Index(j), fn)
} }
...@@ -849,6 +933,7 @@ func (f *decFnInfo) kSlice(rv reflect.Value) { ...@@ -849,6 +933,7 @@ func (f *decFnInfo) kSlice(rv reflect.Value) {
if f.seq == seqTypeArray { if f.seq == seqTypeArray {
for ; j < containerLenS; j++ { for ; j < containerLenS; j++ {
slh.ElemContainerState(j)
d.swallow() d.swallow()
} }
} else if truncated { // slice was truncated, as chan NOT in this block } else if truncated { // slice was truncated, as chan NOT in this block
...@@ -858,44 +943,59 @@ func (f *decFnInfo) kSlice(rv reflect.Value) { ...@@ -858,44 +943,59 @@ func (f *decFnInfo) kSlice(rv reflect.Value) {
if resetSliceElemToZeroValue { if resetSliceElemToZeroValue {
rv9.Set(reflect.Zero(rtelem0)) rv9.Set(reflect.Zero(rtelem0))
} }
slh.ElemContainerState(j)
d.decodeValue(rv9, fn) d.decodeValue(rv9, fn)
} }
} }
} }
} else { } else {
for j := 0; !dd.CheckBreak(); j++ { rvlen = rv.Len()
var decodeIntoBlank bool j := 0
// if indefinite, etc, then expand the slice if necessary for ; !dd.CheckBreak(); j++ {
if j >= rvlen {
if f.seq == seqTypeArray {
d.arrayCannotExpand(rvlen, j+1)
decodeIntoBlank = true
} else if f.seq == seqTypeSlice {
// rv = reflect.Append(rv, reflect.Zero(rtelem0)) // uses append logic, plus varargs
rv = expandSliceValue(rv, 1)
rv9 = rv.Index(j)
// rv.Index(rv.Len() - 1).Set(reflect.Zero(rtelem0))
if resetSliceElemToZeroValue {
rv9.Set(reflect.Zero(rtelem0))
}
rvlen++
rvChanged = true
}
} else if f.seq != seqTypeChan { // slice or array
rv9 = rv.Index(j)
}
if f.seq == seqTypeChan { if f.seq == seqTypeChan {
slh.ElemContainerState(j)
rv9 = reflect.New(rtelem0).Elem() rv9 = reflect.New(rtelem0).Elem()
d.decodeValue(rv9, fn) d.decodeValue(rv9, fn)
rv.Send(rv9) rv.Send(rv9)
} else if decodeIntoBlank { } else {
d.swallow() // if indefinite, etc, then expand the slice if necessary
} else { // seqTypeSlice var decodeIntoBlank bool
d.decodeValue(rv9, fn) if j >= rvlen {
if f.seq == seqTypeArray {
d.arrayCannotExpand(rvlen, j+1)
decodeIntoBlank = true
} else { // if f.seq == seqTypeSlice
// rv = reflect.Append(rv, reflect.Zero(rtelem0)) // uses append logic, plus varargs
rv = expandSliceValue(rv, 1)
rv9 = rv.Index(j)
// rv.Index(rv.Len() - 1).Set(reflect.Zero(rtelem0))
if resetSliceElemToZeroValue {
rv9.Set(reflect.Zero(rtelem0))
}
rvlen++
rvChanged = true
}
} else { // slice or array
rv9 = rv.Index(j)
}
slh.ElemContainerState(j)
if decodeIntoBlank {
d.swallow()
} else { // seqTypeSlice
d.decodeValue(rv9, fn)
}
}
}
if f.seq == seqTypeSlice {
if j < rvlen {
rv.SetLen(j)
} else if j == 0 && rv.IsNil() {
rv = reflect.MakeSlice(ti.rt, 0, 0)
rvChanged = true
} }
} }
slh.End()
} }
slh.End()
if rvChanged { if rvChanged {
rv0.Set(rv) rv0.Set(rv)
...@@ -911,20 +1011,22 @@ func (f *decFnInfo) kMap(rv reflect.Value) { ...@@ -911,20 +1011,22 @@ func (f *decFnInfo) kMap(rv reflect.Value) {
d := f.d d := f.d
dd := d.d dd := d.d
containerLen := dd.ReadMapStart() containerLen := dd.ReadMapStart()
cr := d.cr
ti := f.ti ti := f.ti
if rv.IsNil() { if rv.IsNil() {
rv.Set(reflect.MakeMap(ti.rt)) rv.Set(reflect.MakeMap(ti.rt))
} }
if containerLen == 0 { if containerLen == 0 {
// It is not length-prefix style container. They have no End marker. if cr != nil {
// dd.ReadMapEnd() cr.sendContainerState(containerMapEnd)
}
return return
} }
ktype, vtype := ti.rt.Key(), ti.rt.Elem() ktype, vtype := ti.rt.Key(), ti.rt.Elem()
ktypeId := reflect.ValueOf(ktype).Pointer() ktypeId := reflect.ValueOf(ktype).Pointer()
vtypeKind := vtype.Kind()
var keyFn, valFn *decFn var keyFn, valFn *decFn
var xtyp reflect.Type var xtyp reflect.Type
for xtyp = ktype; xtyp.Kind() == reflect.Ptr; xtyp = xtyp.Elem() { for xtyp = ktype; xtyp.Kind() == reflect.Ptr; xtyp = xtyp.Elem() {
...@@ -933,13 +1035,12 @@ func (f *decFnInfo) kMap(rv reflect.Value) { ...@@ -933,13 +1035,12 @@ func (f *decFnInfo) kMap(rv reflect.Value) {
for xtyp = vtype; xtyp.Kind() == reflect.Ptr; xtyp = xtyp.Elem() { for xtyp = vtype; xtyp.Kind() == reflect.Ptr; xtyp = xtyp.Elem() {
} }
valFn = d.getDecFn(xtyp, true, true) valFn = d.getDecFn(xtyp, true, true)
var mapGet bool var mapGet, mapSet bool
if !f.d.h.MapValueReset { if !f.d.h.MapValueReset {
// if pointer, mapGet = true // if pointer, mapGet = true
// if interface, mapGet = true if !DecodeNakedAlways (else false) // if interface, mapGet = true if !DecodeNakedAlways (else false)
// if builtin, mapGet = false // if builtin, mapGet = false
// else mapGet = true // else mapGet = true
vtypeKind := vtype.Kind()
if vtypeKind == reflect.Ptr { if vtypeKind == reflect.Ptr {
mapGet = true mapGet = true
} else if vtypeKind == reflect.Interface { } else if vtypeKind == reflect.Interface {
...@@ -951,12 +1052,15 @@ func (f *decFnInfo) kMap(rv reflect.Value) { ...@@ -951,12 +1052,15 @@ func (f *decFnInfo) kMap(rv reflect.Value) {
} }
} }
var rvk, rvv reflect.Value var rvk, rvv, rvz reflect.Value
// for j := 0; j < containerLen; j++ { // for j := 0; j < containerLen; j++ {
if containerLen > 0 { if containerLen > 0 {
for j := 0; j < containerLen; j++ { for j := 0; j < containerLen; j++ {
rvk = reflect.New(ktype).Elem() rvk = reflect.New(ktype).Elem()
if cr != nil {
cr.sendContainerState(containerMapKey)
}
d.decodeValue(rvk, keyFn) d.decodeValue(rvk, keyFn)
// special case if a byte array. // special case if a byte array.
...@@ -966,20 +1070,43 @@ func (f *decFnInfo) kMap(rv reflect.Value) { ...@@ -966,20 +1070,43 @@ func (f *decFnInfo) kMap(rv reflect.Value) {
rvk = reflect.ValueOf(d.string(rvk.Bytes())) rvk = reflect.ValueOf(d.string(rvk.Bytes()))
} }
} }
mapSet = true // set to false if u do a get, and its a pointer, and exists
if mapGet { if mapGet {
rvv = rv.MapIndex(rvk) rvv = rv.MapIndex(rvk)
if !rvv.IsValid() { if rvv.IsValid() {
rvv = reflect.New(vtype).Elem() if vtypeKind == reflect.Ptr {
mapSet = false
}
} else {
if rvz.IsValid() {
rvz.Set(reflect.Zero(vtype))
} else {
rvz = reflect.New(vtype).Elem()
}
rvv = rvz
} }
} else { } else {
rvv = reflect.New(vtype).Elem() if rvz.IsValid() {
rvz.Set(reflect.Zero(vtype))
} else {
rvz = reflect.New(vtype).Elem()
}
rvv = rvz
}
if cr != nil {
cr.sendContainerState(containerMapValue)
} }
d.decodeValue(rvv, valFn) d.decodeValue(rvv, valFn)
rv.SetMapIndex(rvk, rvv) if mapSet {
rv.SetMapIndex(rvk, rvv)
}
} }
} else { } else {
for j := 0; !dd.CheckBreak(); j++ { for j := 0; !dd.CheckBreak(); j++ {
rvk = reflect.New(ktype).Elem() rvk = reflect.New(ktype).Elem()
if cr != nil {
cr.sendContainerState(containerMapKey)
}
d.decodeValue(rvk, keyFn) d.decodeValue(rvk, keyFn)
// special case if a byte array. // special case if a byte array.
...@@ -989,18 +1116,40 @@ func (f *decFnInfo) kMap(rv reflect.Value) { ...@@ -989,18 +1116,40 @@ func (f *decFnInfo) kMap(rv reflect.Value) {
rvk = reflect.ValueOf(d.string(rvk.Bytes())) rvk = reflect.ValueOf(d.string(rvk.Bytes()))
} }
} }
mapSet = true // set to false if u do a get, and its a pointer, and exists
if mapGet { if mapGet {
rvv = rv.MapIndex(rvk) rvv = rv.MapIndex(rvk)
if !rvv.IsValid() { if rvv.IsValid() {
rvv = reflect.New(vtype).Elem() if vtypeKind == reflect.Ptr {
mapSet = false
}
} else {
if rvz.IsValid() {
rvz.Set(reflect.Zero(vtype))
} else {
rvz = reflect.New(vtype).Elem()
}
rvv = rvz
} }
} else { } else {
rvv = reflect.New(vtype).Elem() if rvz.IsValid() {
rvz.Set(reflect.Zero(vtype))
} else {
rvz = reflect.New(vtype).Elem()
}
rvv = rvz
}
if cr != nil {
cr.sendContainerState(containerMapValue)
} }
d.decodeValue(rvv, valFn) d.decodeValue(rvv, valFn)
rv.SetMapIndex(rvk, rvv) if mapSet {
rv.SetMapIndex(rvk, rvv)
}
} }
dd.ReadEnd() }
if cr != nil {
cr.sendContainerState(containerMapEnd)
} }
} }
...@@ -1009,6 +1158,65 @@ type decRtidFn struct { ...@@ -1009,6 +1158,65 @@ type decRtidFn struct {
fn decFn fn decFn
} }
// decNaked is used to keep track of the primitives decoded.
// Without it, we would have to decode each primitive and wrap it
// in an interface{}, causing an allocation.
// In this model, the primitives are decoded in a "pseudo-atomic" fashion,
// so we can rest assured that no other decoding happens while these
// primitives are being decoded.
//
// maps and arrays are not handled by this mechanism.
// However, RawExt is, and we accomodate for extensions that decode
// RawExt from DecodeNaked, but need to decode the value subsequently.
// kInterfaceNaked and swallow, which call DecodeNaked, handle this caveat.
//
// However, decNaked also keeps some arrays of default maps and slices
// used in DecodeNaked. This way, we can get a pointer to it
// without causing a new heap allocation.
//
// kInterfaceNaked will ensure that there is no allocation for the common
// uses.
type decNaked struct {
// r RawExt // used for RawExt, uint, []byte.
u uint64
i int64
f float64
l []byte
s string
t time.Time
b bool
v valueType
// stacks for reducing allocation
is []interface{}
ms []map[interface{}]interface{}
ns []map[string]interface{}
ss [][]interface{}
// rs []RawExt
// keep arrays at the bottom? Chance is that they are not used much.
ia [4]interface{}
ma [4]map[interface{}]interface{}
na [4]map[string]interface{}
sa [4][]interface{}
// ra [2]RawExt
}
func (n *decNaked) reset() {
if n.ss != nil {
n.ss = n.ss[:0]
}
if n.is != nil {
n.is = n.is[:0]
}
if n.ms != nil {
n.ms = n.ms[:0]
}
if n.ns != nil {
n.ns = n.ns[:0]
}
}
// A Decoder reads and decodes an object from an input stream in the codec format. // A Decoder reads and decodes an object from an input stream in the codec format.
type Decoder struct { type Decoder struct {
// hopefully, reduce derefencing cost by laying the decReader inside the Decoder. // hopefully, reduce derefencing cost by laying the decReader inside the Decoder.
...@@ -1019,32 +1227,84 @@ type Decoder struct { ...@@ -1019,32 +1227,84 @@ type Decoder struct {
// as the handler MAY need to do some coordination. // as the handler MAY need to do some coordination.
r decReader r decReader
// sa [initCollectionCap]decRtidFn // sa [initCollectionCap]decRtidFn
s []decRtidFn h *BasicHandle
h *BasicHandle hh Handle
rb bytesDecReader
hh Handle
be bool // is binary encoding be bool // is binary encoding
bytes bool // is bytes reader bytes bool // is bytes reader
js bool // is json handle js bool // is json handle
rb bytesDecReader
ri ioDecReader ri ioDecReader
f map[uintptr]*decFn cr containerStateRecv
is map[string]string // used for interning strings
s []decRtidFn
f map[uintptr]*decFn
// _ uintptr // for alignment purposes, so next one starts from a cache line // _ uintptr // for alignment purposes, so next one starts from a cache line
b [scratchByteArrayLen]byte // cache the mapTypeId and sliceTypeId for faster comparisons
mtid uintptr
stid uintptr
n decNaked
b [scratchByteArrayLen]byte
is map[string]string // used for interning strings
} }
// NewDecoder returns a Decoder for decoding a stream of bytes from an io.Reader. // NewDecoder returns a Decoder for decoding a stream of bytes from an io.Reader.
// //
// For efficiency, Users are encouraged to pass in a memory buffered reader // For efficiency, Users are encouraged to pass in a memory buffered reader
// (eg bufio.Reader, bytes.Buffer). // (eg bufio.Reader, bytes.Buffer).
func NewDecoder(r io.Reader, h Handle) (d *Decoder) { func NewDecoder(r io.Reader, h Handle) *Decoder {
d = &Decoder{hh: h, h: h.getBasicHandle(), be: h.isBinary()} d := newDecoder(h)
// d.s = d.sa[:0] d.Reset(r)
return d
}
// NewDecoderBytes returns a Decoder which efficiently decodes directly
// from a byte slice with zero copying.
func NewDecoderBytes(in []byte, h Handle) *Decoder {
d := newDecoder(h)
d.ResetBytes(in)
return d
}
func newDecoder(h Handle) *Decoder {
d := &Decoder{hh: h, h: h.getBasicHandle(), be: h.isBinary()}
n := &d.n
// n.rs = n.ra[:0]
n.ms = n.ma[:0]
n.is = n.ia[:0]
n.ns = n.na[:0]
n.ss = n.sa[:0]
_, d.js = h.(*JsonHandle)
if d.h.InternString {
d.is = make(map[string]string, 32)
}
d.d = h.newDecDriver(d)
d.cr, _ = d.d.(containerStateRecv)
// d.d = h.newDecDriver(decReaderT{true, &d.rb, &d.ri})
return d
}
func (d *Decoder) resetCommon() {
d.n.reset()
d.d.reset()
// reset all things which were cached from the Handle,
// but could be changed.
d.mtid, d.stid = 0, 0
if d.h.MapType != nil {
d.mtid = reflect.ValueOf(d.h.MapType).Pointer()
}
if d.h.SliceType != nil {
d.stid = reflect.ValueOf(d.h.SliceType).Pointer()
}
}
func (d *Decoder) Reset(r io.Reader) {
d.ri.x = &d.b d.ri.x = &d.b
// d.s = d.sa[:0]
d.ri.bs.r = r d.ri.bs.r = r
var ok bool var ok bool
d.ri.br, ok = r.(decReaderByteScanner) d.ri.br, ok = r.(decReaderByteScanner)
...@@ -1052,31 +1312,22 @@ func NewDecoder(r io.Reader, h Handle) (d *Decoder) { ...@@ -1052,31 +1312,22 @@ func NewDecoder(r io.Reader, h Handle) (d *Decoder) {
d.ri.br = &d.ri.bs d.ri.br = &d.ri.bs
} }
d.r = &d.ri d.r = &d.ri
if d.h.InternString { d.resetCommon()
d.is = make(map[string]string, 32)
}
_, d.js = h.(*JsonHandle)
d.d = h.newDecDriver(d)
return
} }
// NewDecoderBytes returns a Decoder which efficiently decodes directly func (d *Decoder) ResetBytes(in []byte) {
// from a byte slice with zero copying.
func NewDecoderBytes(in []byte, h Handle) (d *Decoder) {
d = &Decoder{hh: h, h: h.getBasicHandle(), be: h.isBinary(), bytes: true}
// d.s = d.sa[:0] // d.s = d.sa[:0]
d.rb.b = in d.rb.reset(in)
d.rb.a = len(in)
d.r = &d.rb d.r = &d.rb
if d.h.InternString { d.resetCommon()
d.is = make(map[string]string, 32)
}
_, d.js = h.(*JsonHandle)
d.d = h.newDecDriver(d)
// d.d = h.newDecDriver(decReaderT{true, &d.rb, &d.ri})
return
} }
// func (d *Decoder) sendContainerState(c containerState) {
// if d.cr != nil {
// d.cr.sendContainerState(c)
// }
// }
// Decode decodes the stream from reader and stores the result in the // Decode decodes the stream from reader and stores the result in the
// value pointed to by v. v cannot be a nil pointer. v can also be // value pointed to by v. v cannot be a nil pointer. v can also be
// a reflect.Value of a pointer. // a reflect.Value of a pointer.
...@@ -1142,9 +1393,12 @@ func (d *Decoder) swallowViaHammer() { ...@@ -1142,9 +1393,12 @@ func (d *Decoder) swallowViaHammer() {
func (d *Decoder) swallow() { func (d *Decoder) swallow() {
// smarter decode that just swallows the content // smarter decode that just swallows the content
dd := d.d dd := d.d
switch { if dd.TryDecodeAsNil() {
case dd.TryDecodeAsNil(): return
case dd.IsContainerType(valueTypeMap): }
cr := d.cr
switch dd.ContainerType() {
case valueTypeMap:
containerLen := dd.ReadMapStart() containerLen := dd.ReadMapStart()
clenGtEqualZero := containerLen >= 0 clenGtEqualZero := containerLen >= 0
for j := 0; ; j++ { for j := 0; ; j++ {
...@@ -1155,11 +1409,19 @@ func (d *Decoder) swallow() { ...@@ -1155,11 +1409,19 @@ func (d *Decoder) swallow() {
} else if dd.CheckBreak() { } else if dd.CheckBreak() {
break break
} }
if cr != nil {
cr.sendContainerState(containerMapKey)
}
d.swallow() d.swallow()
if cr != nil {
cr.sendContainerState(containerMapValue)
}
d.swallow() d.swallow()
} }
dd.ReadEnd() if cr != nil {
case dd.IsContainerType(valueTypeArray): cr.sendContainerState(containerMapEnd)
}
case valueTypeArray:
containerLenS := dd.ReadArrayStart() containerLenS := dd.ReadArrayStart()
clenGtEqualZero := containerLenS >= 0 clenGtEqualZero := containerLenS >= 0
for j := 0; ; j++ { for j := 0; ; j++ {
...@@ -1170,17 +1432,30 @@ func (d *Decoder) swallow() { ...@@ -1170,17 +1432,30 @@ func (d *Decoder) swallow() {
} else if dd.CheckBreak() { } else if dd.CheckBreak() {
break break
} }
if cr != nil {
cr.sendContainerState(containerArrayElem)
}
d.swallow() d.swallow()
} }
dd.ReadEnd() if cr != nil {
case dd.IsContainerType(valueTypeBytes): cr.sendContainerState(containerArrayEnd)
}
case valueTypeBytes:
dd.DecodeBytes(d.b[:], false, true) dd.DecodeBytes(d.b[:], false, true)
case dd.IsContainerType(valueTypeString): case valueTypeString:
dd.DecodeBytes(d.b[:], true, true) dd.DecodeBytes(d.b[:], true, true)
// dd.DecodeStringAsBytes(d.b[:]) // dd.DecodeStringAsBytes(d.b[:])
default: default:
// these are all primitives, which we can get from decodeNaked // these are all primitives, which we can get from decodeNaked
// if RawExt using Value, complete the processing.
dd.DecodeNaked() dd.DecodeNaked()
if n := &d.n; n.v == valueTypeExt && n.l == nil {
l := len(n.is)
n.is = append(n.is, nil)
v2 := &n.is[l]
n.is = n.is[:l]
d.decode(v2)
}
} }
} }
...@@ -1230,14 +1505,20 @@ func (d *Decoder) decode(iv interface{}) { ...@@ -1230,14 +1505,20 @@ func (d *Decoder) decode(iv interface{}) {
case *[]uint8: case *[]uint8:
*v = nil *v = nil
case reflect.Value: case reflect.Value:
d.chkPtrValue(v) if v.Kind() != reflect.Ptr || v.IsNil() {
d.errNotValidPtrValue(v)
}
// d.chkPtrValue(v)
v = v.Elem() v = v.Elem()
if v.IsValid() { if v.IsValid() {
v.Set(reflect.Zero(v.Type())) v.Set(reflect.Zero(v.Type()))
} }
default: default:
rv := reflect.ValueOf(iv) rv := reflect.ValueOf(iv)
d.chkPtrValue(rv) if rv.Kind() != reflect.Ptr || rv.IsNil() {
d.errNotValidPtrValue(rv)
}
// d.chkPtrValue(rv)
rv = rv.Elem() rv = rv.Elem()
if rv.IsValid() { if rv.IsValid() {
rv.Set(reflect.Zero(rv.Type())) rv.Set(reflect.Zero(rv.Type()))
...@@ -1255,7 +1536,10 @@ func (d *Decoder) decode(iv interface{}) { ...@@ -1255,7 +1536,10 @@ func (d *Decoder) decode(iv interface{}) {
v.CodecDecodeSelf(d) v.CodecDecodeSelf(d)
case reflect.Value: case reflect.Value:
d.chkPtrValue(v) if v.Kind() != reflect.Ptr || v.IsNil() {
d.errNotValidPtrValue(v)
}
// d.chkPtrValue(v)
d.decodeValueNotNil(v.Elem(), nil) d.decodeValueNotNil(v.Elem(), nil)
case *string: case *string:
...@@ -1325,7 +1609,10 @@ func (d *Decoder) preDecodeValue(rv reflect.Value, tryNil bool) (rv2 reflect.Val ...@@ -1325,7 +1609,10 @@ func (d *Decoder) preDecodeValue(rv reflect.Value, tryNil bool) (rv2 reflect.Val
func (d *Decoder) decodeI(iv interface{}, checkPtr, tryNil, checkFastpath, checkCodecSelfer bool) { func (d *Decoder) decodeI(iv interface{}, checkPtr, tryNil, checkFastpath, checkCodecSelfer bool) {
rv := reflect.ValueOf(iv) rv := reflect.ValueOf(iv)
if checkPtr { if checkPtr {
d.chkPtrValue(rv) if rv.Kind() != reflect.Ptr || rv.IsNil() {
d.errNotValidPtrValue(rv)
}
// d.chkPtrValue(rv)
} }
rv, proceed := d.preDecodeValue(rv, tryNil) rv, proceed := d.preDecodeValue(rv, tryNil)
if proceed { if proceed {
...@@ -1529,6 +1816,10 @@ func (d *Decoder) chkPtrValue(rv reflect.Value) { ...@@ -1529,6 +1816,10 @@ func (d *Decoder) chkPtrValue(rv reflect.Value) {
if rv.Kind() == reflect.Ptr && !rv.IsNil() { if rv.Kind() == reflect.Ptr && !rv.IsNil() {
return return
} }
d.errNotValidPtrValue(rv)
}
func (d *Decoder) errNotValidPtrValue(rv reflect.Value) {
if !rv.IsValid() { if !rv.IsValid() {
d.error(cannotDecodeIntoNilErr) d.error(cannotDecodeIntoNilErr)
return return
...@@ -1571,31 +1862,65 @@ func (d *Decoder) intern(s string) { ...@@ -1571,31 +1862,65 @@ func (d *Decoder) intern(s string) {
} }
} }
func (d *Decoder) nextValueBytes() []byte {
d.d.uncacheRead()
d.r.track()
d.swallow()
return d.r.stopTrack()
}
// -------------------------------------------------- // --------------------------------------------------
// decSliceHelper assists when decoding into a slice, from a map or an array in the stream. // decSliceHelper assists when decoding into a slice, from a map or an array in the stream.
// A slice can be set from a map or array in stream. This supports the MapBySlice interface. // A slice can be set from a map or array in stream. This supports the MapBySlice interface.
type decSliceHelper struct { type decSliceHelper struct {
dd decDriver d *Decoder
ct valueType // ct valueType
array bool
} }
func (d *Decoder) decSliceHelperStart() (x decSliceHelper, clen int) { func (d *Decoder) decSliceHelperStart() (x decSliceHelper, clen int) {
x.dd = d.d dd := d.d
if x.dd.IsContainerType(valueTypeArray) { ctyp := dd.ContainerType()
x.ct = valueTypeArray if ctyp == valueTypeArray {
clen = x.dd.ReadArrayStart() x.array = true
} else if x.dd.IsContainerType(valueTypeMap) { clen = dd.ReadArrayStart()
x.ct = valueTypeMap } else if ctyp == valueTypeMap {
clen = x.dd.ReadMapStart() * 2 clen = dd.ReadMapStart() * 2
} else { } else {
d.errorf("only encoded map or array can be decoded into a slice") d.errorf("only encoded map or array can be decoded into a slice (%d)", ctyp)
} }
// x.ct = ctyp
x.d = d
return return
} }
func (x decSliceHelper) End() { func (x decSliceHelper) End() {
x.dd.ReadEnd() cr := x.d.cr
if cr == nil {
return
}
if x.array {
cr.sendContainerState(containerArrayEnd)
} else {
cr.sendContainerState(containerMapEnd)
}
}
func (x decSliceHelper) ElemContainerState(index int) {
cr := x.d.cr
if cr == nil {
return
}
if x.array {
cr.sendContainerState(containerArrayElem)
} else {
if index%2 == 0 {
cr.sendContainerState(containerMapKey)
} else {
cr.sendContainerState(containerMapValue)
}
}
} }
func decByteSlice(r decReader, clen int, bs []byte) (bsOut []byte) { func decByteSlice(r decReader, clen int, bs []byte) (bsOut []byte) {
......
...@@ -62,13 +62,14 @@ type encDriver interface { ...@@ -62,13 +62,14 @@ type encDriver interface {
EncodeExt(v interface{}, xtag uint64, ext Ext, e *Encoder) EncodeExt(v interface{}, xtag uint64, ext Ext, e *Encoder)
EncodeArrayStart(length int) EncodeArrayStart(length int)
EncodeMapStart(length int) EncodeMapStart(length int)
EncodeEnd()
EncodeString(c charEncoding, v string) EncodeString(c charEncoding, v string)
EncodeSymbol(v string) EncodeSymbol(v string)
EncodeStringBytes(c charEncoding, v []byte) EncodeStringBytes(c charEncoding, v []byte)
//TODO //TODO
//encBignum(f *big.Int) //encBignum(f *big.Int)
//encStringRunes(c charEncoding, v []rune) //encStringRunes(c charEncoding, v []rune)
reset()
} }
type encDriverAsis interface { type encDriverAsis interface {
...@@ -158,6 +159,7 @@ func (o *simpleIoEncWriterWriter) Write(p []byte) (n int, err error) { ...@@ -158,6 +159,7 @@ func (o *simpleIoEncWriterWriter) Write(p []byte) (n int, err error) {
// ioEncWriter implements encWriter and can write to an io.Writer implementation // ioEncWriter implements encWriter and can write to an io.Writer implementation
type ioEncWriter struct { type ioEncWriter struct {
w ioEncWriterWriter w ioEncWriterWriter
s simpleIoEncWriterWriter
// x [8]byte // temp byte array re-used internally for efficiency // x [8]byte // temp byte array re-used internally for efficiency
} }
...@@ -382,30 +384,32 @@ func (f *encFnInfo) kSlice(rv reflect.Value) { ...@@ -382,30 +384,32 @@ func (f *encFnInfo) kSlice(rv reflect.Value) {
// (don't call rv.Bytes, rv.Slice, etc). // (don't call rv.Bytes, rv.Slice, etc).
// E.g. type struct S{B [2]byte}; // E.g. type struct S{B [2]byte};
// Encode(S{}) will bomb on "panic: slice of unaddressable array". // Encode(S{}) will bomb on "panic: slice of unaddressable array".
e := f.e
if f.seq != seqTypeArray { if f.seq != seqTypeArray {
if rv.IsNil() { if rv.IsNil() {
f.e.e.EncodeNil() e.e.EncodeNil()
return return
} }
// If in this method, then there was no extension function defined. // If in this method, then there was no extension function defined.
// So it's okay to treat as []byte. // So it's okay to treat as []byte.
if ti.rtid == uint8SliceTypId { if ti.rtid == uint8SliceTypId {
f.e.e.EncodeStringBytes(c_RAW, rv.Bytes()) e.e.EncodeStringBytes(c_RAW, rv.Bytes())
return return
} }
} }
cr := e.cr
rtelem := ti.rt.Elem() rtelem := ti.rt.Elem()
l := rv.Len() l := rv.Len()
if rtelem.Kind() == reflect.Uint8 { if ti.rtid == uint8SliceTypId || rtelem.Kind() == reflect.Uint8 {
switch f.seq { switch f.seq {
case seqTypeArray: case seqTypeArray:
// if l == 0 { f.e.e.encodeStringBytes(c_RAW, nil) } else // if l == 0 { e.e.encodeStringBytes(c_RAW, nil) } else
if rv.CanAddr() { if rv.CanAddr() {
f.e.e.EncodeStringBytes(c_RAW, rv.Slice(0, l).Bytes()) e.e.EncodeStringBytes(c_RAW, rv.Slice(0, l).Bytes())
} else { } else {
var bs []byte var bs []byte
if l <= cap(f.e.b) { if l <= cap(e.b) {
bs = f.e.b[:l] bs = e.b[:l]
} else { } else {
bs = make([]byte, l) bs = make([]byte, l)
} }
...@@ -414,12 +418,12 @@ func (f *encFnInfo) kSlice(rv reflect.Value) { ...@@ -414,12 +418,12 @@ func (f *encFnInfo) kSlice(rv reflect.Value) {
// for i := 0; i < l; i++ { // for i := 0; i < l; i++ {
// bs[i] = byte(rv.Index(i).Uint()) // bs[i] = byte(rv.Index(i).Uint())
// } // }
f.e.e.EncodeStringBytes(c_RAW, bs) e.e.EncodeStringBytes(c_RAW, bs)
} }
case seqTypeSlice: case seqTypeSlice:
f.e.e.EncodeStringBytes(c_RAW, rv.Bytes()) e.e.EncodeStringBytes(c_RAW, rv.Bytes())
case seqTypeChan: case seqTypeChan:
bs := f.e.b[:0] bs := e.b[:0]
// do not use range, so that the number of elements encoded // do not use range, so that the number of elements encoded
// does not change, and encoding does not hang waiting on someone to close chan. // does not change, and encoding does not hang waiting on someone to close chan.
// for b := range rv.Interface().(<-chan byte) { // for b := range rv.Interface().(<-chan byte) {
...@@ -429,22 +433,21 @@ func (f *encFnInfo) kSlice(rv reflect.Value) { ...@@ -429,22 +433,21 @@ func (f *encFnInfo) kSlice(rv reflect.Value) {
for i := 0; i < l; i++ { for i := 0; i < l; i++ {
bs = append(bs, <-ch) bs = append(bs, <-ch)
} }
f.e.e.EncodeStringBytes(c_RAW, bs) e.e.EncodeStringBytes(c_RAW, bs)
} }
return return
} }
if ti.mbs { if ti.mbs {
if l%2 == 1 { if l%2 == 1 {
f.e.errorf("mapBySlice requires even slice length, but got %v", l) e.errorf("mapBySlice requires even slice length, but got %v", l)
return return
} }
f.e.e.EncodeMapStart(l / 2) e.e.EncodeMapStart(l / 2)
} else { } else {
f.e.e.EncodeArrayStart(l) e.e.EncodeArrayStart(l)
} }
e := f.e
if l > 0 { if l > 0 {
for rtelem.Kind() == reflect.Ptr { for rtelem.Kind() == reflect.Ptr {
rtelem = rtelem.Elem() rtelem = rtelem.Elem()
...@@ -459,29 +462,48 @@ func (f *encFnInfo) kSlice(rv reflect.Value) { ...@@ -459,29 +462,48 @@ func (f *encFnInfo) kSlice(rv reflect.Value) {
} }
// TODO: Consider perf implication of encoding odd index values as symbols if type is string // TODO: Consider perf implication of encoding odd index values as symbols if type is string
for j := 0; j < l; j++ { for j := 0; j < l; j++ {
if cr != nil {
if ti.mbs {
if l%2 == 0 {
cr.sendContainerState(containerMapKey)
} else {
cr.sendContainerState(containerMapValue)
}
} else {
cr.sendContainerState(containerArrayElem)
}
}
if f.seq == seqTypeChan { if f.seq == seqTypeChan {
if rv2, ok2 := rv.Recv(); ok2 { if rv2, ok2 := rv.Recv(); ok2 {
e.encodeValue(rv2, fn) e.encodeValue(rv2, fn)
} else {
e.encode(nil) // WE HAVE TO DO SOMETHING, so nil if nothing received.
} }
} else { } else {
e.encodeValue(rv.Index(j), fn) e.encodeValue(rv.Index(j), fn)
} }
} }
} }
f.e.e.EncodeEnd() if cr != nil {
if ti.mbs {
cr.sendContainerState(containerMapEnd)
} else {
cr.sendContainerState(containerArrayEnd)
}
}
} }
func (f *encFnInfo) kStruct(rv reflect.Value) { func (f *encFnInfo) kStruct(rv reflect.Value) {
fti := f.ti fti := f.ti
e := f.e e := f.e
cr := e.cr
tisfi := fti.sfip tisfi := fti.sfip
toMap := !(fti.toArray || e.h.StructToArray) toMap := !(fti.toArray || e.h.StructToArray)
newlen := len(fti.sfi) newlen := len(fti.sfi)
// Use sync.Pool to reduce allocating slices unnecessarily. // Use sync.Pool to reduce allocating slices unnecessarily.
// The cost of the occasional locking is less than the cost of locking. // The cost of the occasional locking is less than the cost of new allocation.
pool, poolv, fkvs := encStructPoolGet(newlen) pool, poolv, fkvs := encStructPoolGet(newlen)
// if toMap, use the sorted array. If toArray, use unsorted array (to match sequence in struct) // if toMap, use the sorted array. If toArray, use unsorted array (to match sequence in struct)
...@@ -519,7 +541,7 @@ func (f *encFnInfo) kStruct(rv reflect.Value) { ...@@ -519,7 +541,7 @@ func (f *encFnInfo) kStruct(rv reflect.Value) {
// debugf(">>>> kStruct: newlen: %v", newlen) // debugf(">>>> kStruct: newlen: %v", newlen)
// sep := !e.be // sep := !e.be
ee := f.e.e //don't dereference everytime ee := e.e //don't dereference everytime
if toMap { if toMap {
ee.EncodeMapStart(newlen) ee.EncodeMapStart(newlen)
...@@ -527,21 +549,35 @@ func (f *encFnInfo) kStruct(rv reflect.Value) { ...@@ -527,21 +549,35 @@ func (f *encFnInfo) kStruct(rv reflect.Value) {
asSymbols := e.h.AsSymbols == AsSymbolDefault || e.h.AsSymbols&AsSymbolStructFieldNameFlag != 0 asSymbols := e.h.AsSymbols == AsSymbolDefault || e.h.AsSymbols&AsSymbolStructFieldNameFlag != 0
for j := 0; j < newlen; j++ { for j := 0; j < newlen; j++ {
kv = fkvs[j] kv = fkvs[j]
if cr != nil {
cr.sendContainerState(containerMapKey)
}
if asSymbols { if asSymbols {
ee.EncodeSymbol(kv.v) ee.EncodeSymbol(kv.v)
} else { } else {
ee.EncodeString(c_UTF8, kv.v) ee.EncodeString(c_UTF8, kv.v)
} }
if cr != nil {
cr.sendContainerState(containerMapValue)
}
e.encodeValue(kv.r, nil) e.encodeValue(kv.r, nil)
} }
if cr != nil {
cr.sendContainerState(containerMapEnd)
}
} else { } else {
ee.EncodeArrayStart(newlen) ee.EncodeArrayStart(newlen)
for j := 0; j < newlen; j++ { for j := 0; j < newlen; j++ {
kv = fkvs[j] kv = fkvs[j]
if cr != nil {
cr.sendContainerState(containerArrayElem)
}
e.encodeValue(kv.r, nil) e.encodeValue(kv.r, nil)
} }
if cr != nil {
cr.sendContainerState(containerArrayEnd)
}
} }
ee.EncodeEnd()
// do not use defer. Instead, use explicit pool return at end of function. // do not use defer. Instead, use explicit pool return at end of function.
// defer has a cost we are trying to avoid. // defer has a cost we are trying to avoid.
...@@ -578,8 +614,11 @@ func (f *encFnInfo) kMap(rv reflect.Value) { ...@@ -578,8 +614,11 @@ func (f *encFnInfo) kMap(rv reflect.Value) {
l := rv.Len() l := rv.Len()
ee.EncodeMapStart(l) ee.EncodeMapStart(l)
e := f.e e := f.e
cr := e.cr
if l == 0 { if l == 0 {
ee.EncodeEnd() if cr != nil {
cr.sendContainerState(containerMapEnd)
}
return return
} }
var asSymbols bool var asSymbols bool
...@@ -622,6 +661,9 @@ func (f *encFnInfo) kMap(rv reflect.Value) { ...@@ -622,6 +661,9 @@ func (f *encFnInfo) kMap(rv reflect.Value) {
e.kMapCanonical(rtkeyid, rtkey, rv, mks, valFn, asSymbols) e.kMapCanonical(rtkeyid, rtkey, rv, mks, valFn, asSymbols)
} else { } else {
for j := range mks { for j := range mks {
if cr != nil {
cr.sendContainerState(containerMapKey)
}
if keyTypeIsString { if keyTypeIsString {
if asSymbols { if asSymbols {
ee.EncodeSymbol(mks[j].String()) ee.EncodeSymbol(mks[j].String())
...@@ -631,15 +673,20 @@ func (f *encFnInfo) kMap(rv reflect.Value) { ...@@ -631,15 +673,20 @@ func (f *encFnInfo) kMap(rv reflect.Value) {
} else { } else {
e.encodeValue(mks[j], keyFn) e.encodeValue(mks[j], keyFn)
} }
if cr != nil {
cr.sendContainerState(containerMapValue)
}
e.encodeValue(rv.MapIndex(mks[j]), valFn) e.encodeValue(rv.MapIndex(mks[j]), valFn)
} }
} }
if cr != nil {
ee.EncodeEnd() cr.sendContainerState(containerMapEnd)
}
} }
func (e *Encoder) kMapCanonical(rtkeyid uintptr, rtkey reflect.Type, rv reflect.Value, mks []reflect.Value, valFn *encFn, asSymbols bool) { func (e *Encoder) kMapCanonical(rtkeyid uintptr, rtkey reflect.Type, rv reflect.Value, mks []reflect.Value, valFn *encFn, asSymbols bool) {
ee := e.e ee := e.e
cr := e.cr
// we previously did out-of-band if an extension was registered. // we previously did out-of-band if an extension was registered.
// This is not necessary, as the natural kind is sufficient for ordering. // This is not necessary, as the natural kind is sufficient for ordering.
...@@ -652,7 +699,13 @@ func (e *Encoder) kMapCanonical(rtkeyid uintptr, rtkey reflect.Type, rv reflect. ...@@ -652,7 +699,13 @@ func (e *Encoder) kMapCanonical(rtkeyid uintptr, rtkey reflect.Type, rv reflect.
} }
sort.Sort(bytesRvSlice(mksv)) sort.Sort(bytesRvSlice(mksv))
for i := range mksv { for i := range mksv {
if cr != nil {
cr.sendContainerState(containerMapKey)
}
ee.EncodeStringBytes(c_RAW, mksv[i].v) ee.EncodeStringBytes(c_RAW, mksv[i].v)
if cr != nil {
cr.sendContainerState(containerMapValue)
}
e.encodeValue(rv.MapIndex(mksv[i].r), valFn) e.encodeValue(rv.MapIndex(mksv[i].r), valFn)
} }
} else { } else {
...@@ -666,7 +719,13 @@ func (e *Encoder) kMapCanonical(rtkeyid uintptr, rtkey reflect.Type, rv reflect. ...@@ -666,7 +719,13 @@ func (e *Encoder) kMapCanonical(rtkeyid uintptr, rtkey reflect.Type, rv reflect.
} }
sort.Sort(boolRvSlice(mksv)) sort.Sort(boolRvSlice(mksv))
for i := range mksv { for i := range mksv {
if cr != nil {
cr.sendContainerState(containerMapKey)
}
ee.EncodeBool(mksv[i].v) ee.EncodeBool(mksv[i].v)
if cr != nil {
cr.sendContainerState(containerMapValue)
}
e.encodeValue(rv.MapIndex(mksv[i].r), valFn) e.encodeValue(rv.MapIndex(mksv[i].r), valFn)
} }
case reflect.String: case reflect.String:
...@@ -678,11 +737,17 @@ func (e *Encoder) kMapCanonical(rtkeyid uintptr, rtkey reflect.Type, rv reflect. ...@@ -678,11 +737,17 @@ func (e *Encoder) kMapCanonical(rtkeyid uintptr, rtkey reflect.Type, rv reflect.
} }
sort.Sort(stringRvSlice(mksv)) sort.Sort(stringRvSlice(mksv))
for i := range mksv { for i := range mksv {
if cr != nil {
cr.sendContainerState(containerMapKey)
}
if asSymbols { if asSymbols {
ee.EncodeSymbol(mksv[i].v) ee.EncodeSymbol(mksv[i].v)
} else { } else {
ee.EncodeString(c_UTF8, mksv[i].v) ee.EncodeString(c_UTF8, mksv[i].v)
} }
if cr != nil {
cr.sendContainerState(containerMapValue)
}
e.encodeValue(rv.MapIndex(mksv[i].r), valFn) e.encodeValue(rv.MapIndex(mksv[i].r), valFn)
} }
case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint, reflect.Uintptr: case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint, reflect.Uintptr:
...@@ -694,7 +759,13 @@ func (e *Encoder) kMapCanonical(rtkeyid uintptr, rtkey reflect.Type, rv reflect. ...@@ -694,7 +759,13 @@ func (e *Encoder) kMapCanonical(rtkeyid uintptr, rtkey reflect.Type, rv reflect.
} }
sort.Sort(uintRvSlice(mksv)) sort.Sort(uintRvSlice(mksv))
for i := range mksv { for i := range mksv {
if cr != nil {
cr.sendContainerState(containerMapKey)
}
ee.EncodeUint(mksv[i].v) ee.EncodeUint(mksv[i].v)
if cr != nil {
cr.sendContainerState(containerMapValue)
}
e.encodeValue(rv.MapIndex(mksv[i].r), valFn) e.encodeValue(rv.MapIndex(mksv[i].r), valFn)
} }
case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int: case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
...@@ -706,7 +777,13 @@ func (e *Encoder) kMapCanonical(rtkeyid uintptr, rtkey reflect.Type, rv reflect. ...@@ -706,7 +777,13 @@ func (e *Encoder) kMapCanonical(rtkeyid uintptr, rtkey reflect.Type, rv reflect.
} }
sort.Sort(intRvSlice(mksv)) sort.Sort(intRvSlice(mksv))
for i := range mksv { for i := range mksv {
if cr != nil {
cr.sendContainerState(containerMapKey)
}
ee.EncodeInt(mksv[i].v) ee.EncodeInt(mksv[i].v)
if cr != nil {
cr.sendContainerState(containerMapValue)
}
e.encodeValue(rv.MapIndex(mksv[i].r), valFn) e.encodeValue(rv.MapIndex(mksv[i].r), valFn)
} }
case reflect.Float32: case reflect.Float32:
...@@ -718,7 +795,13 @@ func (e *Encoder) kMapCanonical(rtkeyid uintptr, rtkey reflect.Type, rv reflect. ...@@ -718,7 +795,13 @@ func (e *Encoder) kMapCanonical(rtkeyid uintptr, rtkey reflect.Type, rv reflect.
} }
sort.Sort(floatRvSlice(mksv)) sort.Sort(floatRvSlice(mksv))
for i := range mksv { for i := range mksv {
if cr != nil {
cr.sendContainerState(containerMapKey)
}
ee.EncodeFloat32(float32(mksv[i].v)) ee.EncodeFloat32(float32(mksv[i].v))
if cr != nil {
cr.sendContainerState(containerMapValue)
}
e.encodeValue(rv.MapIndex(mksv[i].r), valFn) e.encodeValue(rv.MapIndex(mksv[i].r), valFn)
} }
case reflect.Float64: case reflect.Float64:
...@@ -730,7 +813,13 @@ func (e *Encoder) kMapCanonical(rtkeyid uintptr, rtkey reflect.Type, rv reflect. ...@@ -730,7 +813,13 @@ func (e *Encoder) kMapCanonical(rtkeyid uintptr, rtkey reflect.Type, rv reflect.
} }
sort.Sort(floatRvSlice(mksv)) sort.Sort(floatRvSlice(mksv))
for i := range mksv { for i := range mksv {
if cr != nil {
cr.sendContainerState(containerMapKey)
}
ee.EncodeFloat64(mksv[i].v) ee.EncodeFloat64(mksv[i].v)
if cr != nil {
cr.sendContainerState(containerMapValue)
}
e.encodeValue(rv.MapIndex(mksv[i].r), valFn) e.encodeValue(rv.MapIndex(mksv[i].r), valFn)
} }
default: default:
...@@ -749,7 +838,13 @@ func (e *Encoder) kMapCanonical(rtkeyid uintptr, rtkey reflect.Type, rv reflect. ...@@ -749,7 +838,13 @@ func (e *Encoder) kMapCanonical(rtkeyid uintptr, rtkey reflect.Type, rv reflect.
} }
sort.Sort(bytesRvSlice(mksbv)) sort.Sort(bytesRvSlice(mksbv))
for j := range mksbv { for j := range mksbv {
if cr != nil {
cr.sendContainerState(containerMapKey)
}
e.asis(mksbv[j].v) e.asis(mksbv[j].v)
if cr != nil {
cr.sendContainerState(containerMapValue)
}
e.encodeValue(rv.MapIndex(mksbv[j].r), valFn) e.encodeValue(rv.MapIndex(mksbv[j].r), valFn)
} }
} }
...@@ -787,12 +882,15 @@ type Encoder struct { ...@@ -787,12 +882,15 @@ type Encoder struct {
wi ioEncWriter wi ioEncWriter
wb bytesEncWriter wb bytesEncWriter
h *BasicHandle h *BasicHandle
hh Handle
cr containerStateRecv
as encDriverAsis as encDriverAsis
hh Handle
f map[uintptr]*encFn f map[uintptr]*encFn
b [scratchByteArrayLen]byte b [scratchByteArrayLen]byte
} }
// NewEncoder returns an Encoder for encoding into an io.Writer. // NewEncoder returns an Encoder for encoding into an io.Writer.
...@@ -800,20 +898,8 @@ type Encoder struct { ...@@ -800,20 +898,8 @@ type Encoder struct {
// For efficiency, Users are encouraged to pass in a memory buffered writer // For efficiency, Users are encouraged to pass in a memory buffered writer
// (eg bufio.Writer, bytes.Buffer). // (eg bufio.Writer, bytes.Buffer).
func NewEncoder(w io.Writer, h Handle) *Encoder { func NewEncoder(w io.Writer, h Handle) *Encoder {
e := &Encoder{hh: h, h: h.getBasicHandle(), be: h.isBinary()} e := newEncoder(h)
ww, ok := w.(ioEncWriterWriter) e.Reset(w)
if !ok {
sww := simpleIoEncWriterWriter{w: w}
sww.bw, _ = w.(io.ByteWriter)
sww.sw, _ = w.(ioEncStringWriter)
ww = &sww
//ww = bufio.NewWriterSize(w, defEncByteBufSize)
}
e.wi.w = ww
e.w = &e.wi
_, e.js = h.(*JsonHandle)
e.e = h.newEncDriver(e)
e.as, _ = e.e.(encDriverAsis)
return e return e
} }
...@@ -823,19 +909,56 @@ func NewEncoder(w io.Writer, h Handle) *Encoder { ...@@ -823,19 +909,56 @@ func NewEncoder(w io.Writer, h Handle) *Encoder {
// It will potentially replace the output byte slice pointed to. // It will potentially replace the output byte slice pointed to.
// After encoding, the out parameter contains the encoded contents. // After encoding, the out parameter contains the encoded contents.
func NewEncoderBytes(out *[]byte, h Handle) *Encoder { func NewEncoderBytes(out *[]byte, h Handle) *Encoder {
e := newEncoder(h)
e.ResetBytes(out)
return e
}
func newEncoder(h Handle) *Encoder {
e := &Encoder{hh: h, h: h.getBasicHandle(), be: h.isBinary()} e := &Encoder{hh: h, h: h.getBasicHandle(), be: h.isBinary()}
_, e.js = h.(*JsonHandle)
e.e = h.newEncDriver(e)
e.as, _ = e.e.(encDriverAsis)
e.cr, _ = e.e.(containerStateRecv)
return e
}
// Reset the Encoder with a new output stream.
//
// This accomodates using the state of the Encoder,
// where it has "cached" information about sub-engines.
func (e *Encoder) Reset(w io.Writer) {
ww, ok := w.(ioEncWriterWriter)
if ok {
e.wi.w = ww
} else {
sww := &e.wi.s
sww.w = w
sww.bw, _ = w.(io.ByteWriter)
sww.sw, _ = w.(ioEncStringWriter)
e.wi.w = sww
//ww = bufio.NewWriterSize(w, defEncByteBufSize)
}
e.w = &e.wi
e.e.reset()
}
func (e *Encoder) ResetBytes(out *[]byte) {
in := *out in := *out
if in == nil { if in == nil {
in = make([]byte, defEncByteBufSize) in = make([]byte, defEncByteBufSize)
} }
e.wb.b, e.wb.out = in, out e.wb.b, e.wb.out, e.wb.c = in, out, 0
e.w = &e.wb e.w = &e.wb
_, e.js = h.(*JsonHandle) e.e.reset()
e.e = h.newEncDriver(e)
e.as, _ = e.e.(encDriverAsis)
return e
} }
// func (e *Encoder) sendContainerState(c containerState) {
// if e.cr != nil {
// e.cr.sendContainerState(c)
// }
// }
// Encode writes an object into a stream. // Encode writes an object into a stream.
// //
// Encoding can be configured via the struct tag for the fields. // Encoding can be configured via the struct tag for the fields.
...@@ -1020,26 +1143,24 @@ func (e *Encoder) encodeI(iv interface{}, checkFastpath, checkCodecSelfer bool) ...@@ -1020,26 +1143,24 @@ func (e *Encoder) encodeI(iv interface{}, checkFastpath, checkCodecSelfer bool)
} }
func (e *Encoder) preEncodeValue(rv reflect.Value) (rv2 reflect.Value, proceed bool) { func (e *Encoder) preEncodeValue(rv reflect.Value) (rv2 reflect.Value, proceed bool) {
LOOP: // use a goto statement instead of a recursive function for ptr/interface.
for { TOP:
switch rv.Kind() { switch rv.Kind() {
case reflect.Ptr, reflect.Interface: case reflect.Ptr, reflect.Interface:
if rv.IsNil() { if rv.IsNil() {
e.e.EncodeNil()
return
}
rv = rv.Elem()
continue LOOP
case reflect.Slice, reflect.Map:
if rv.IsNil() {
e.e.EncodeNil()
return
}
case reflect.Invalid, reflect.Func:
e.e.EncodeNil() e.e.EncodeNil()
return return
} }
break rv = rv.Elem()
goto TOP
case reflect.Slice, reflect.Map:
if rv.IsNil() {
e.e.EncodeNil()
return
}
case reflect.Invalid, reflect.Func:
e.e.EncodeNil()
return
} }
return rv, true return rv, true
......
This source diff could not be displayed because it is too large. You can view the blob instead.
// //+build ignore // +build !notfastpath
// Copyright (c) 2012-2015 Ugorji Nwoke. All rights reserved. // 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. // Use of this source code is governed by a MIT license found in the LICENSE file.
...@@ -106,6 +106,9 @@ func init() { ...@@ -106,6 +106,9 @@ func init() {
// -- -- fast path type switch // -- -- fast path type switch
func fastpathEncodeTypeSwitch(iv interface{}, e *Encoder) bool { func fastpathEncodeTypeSwitch(iv interface{}, e *Encoder) bool {
if !fastpathEnabled {
return false
}
switch v := iv.(type) { switch v := iv.(type) {
{{range .Values}}{{if not .Primitive}}{{if not .MapKey }} {{range .Values}}{{if not .Primitive}}{{if not .MapKey }}
case []{{ .Elem }}:{{else}} case []{{ .Elem }}:{{else}}
...@@ -116,13 +119,16 @@ func fastpathEncodeTypeSwitch(iv interface{}, e *Encoder) bool { ...@@ -116,13 +119,16 @@ func fastpathEncodeTypeSwitch(iv interface{}, e *Encoder) bool {
fastpathTV.{{ .MethodNamePfx "Enc" false }}V(*v, fastpathCheckNilTrue, e) fastpathTV.{{ .MethodNamePfx "Enc" false }}V(*v, fastpathCheckNilTrue, e)
{{end}}{{end}} {{end}}{{end}}
default: default:
_ = v // TODO: workaround https://github.com/golang/go/issues/12927 (remove after go 1.6 release) _ = v // TODO: workaround https://github.com/golang/go/issues/12927 (remove after go 1.6 release)
return false return false
} }
return true return true
} }
func fastpathEncodeTypeSwitchSlice(iv interface{}, e *Encoder) bool { func fastpathEncodeTypeSwitchSlice(iv interface{}, e *Encoder) bool {
if !fastpathEnabled {
return false
}
switch v := iv.(type) { switch v := iv.(type) {
{{range .Values}}{{if not .Primitive}}{{if not .MapKey }} {{range .Values}}{{if not .Primitive}}{{if not .MapKey }}
case []{{ .Elem }}: case []{{ .Elem }}:
...@@ -131,12 +137,16 @@ func fastpathEncodeTypeSwitchSlice(iv interface{}, e *Encoder) bool { ...@@ -131,12 +137,16 @@ func fastpathEncodeTypeSwitchSlice(iv interface{}, e *Encoder) bool {
fastpathTV.{{ .MethodNamePfx "Enc" false }}V(*v, fastpathCheckNilTrue, e) fastpathTV.{{ .MethodNamePfx "Enc" false }}V(*v, fastpathCheckNilTrue, e)
{{end}}{{end}}{{end}} {{end}}{{end}}{{end}}
default: default:
_ = v // TODO: workaround https://github.com/golang/go/issues/12927 (remove after go 1.6 release)
return false return false
} }
return true return true
} }
func fastpathEncodeTypeSwitchMap(iv interface{}, e *Encoder) bool { func fastpathEncodeTypeSwitchMap(iv interface{}, e *Encoder) bool {
if !fastpathEnabled {
return false
}
switch v := iv.(type) { switch v := iv.(type) {
{{range .Values}}{{if not .Primitive}}{{if .MapKey }} {{range .Values}}{{if not .Primitive}}{{if .MapKey }}
case map[{{ .MapKey }}]{{ .Elem }}: case map[{{ .MapKey }}]{{ .Elem }}:
...@@ -145,6 +155,7 @@ func fastpathEncodeTypeSwitchMap(iv interface{}, e *Encoder) bool { ...@@ -145,6 +155,7 @@ func fastpathEncodeTypeSwitchMap(iv interface{}, e *Encoder) bool {
fastpathTV.{{ .MethodNamePfx "Enc" false }}V(*v, fastpathCheckNilTrue, e) fastpathTV.{{ .MethodNamePfx "Enc" false }}V(*v, fastpathCheckNilTrue, e)
{{end}}{{end}}{{end}} {{end}}{{end}}{{end}}
default: default:
_ = v // TODO: workaround https://github.com/golang/go/issues/12927 (remove after go 1.6 release)
return false return false
} }
return true return true
...@@ -157,16 +168,18 @@ func (f *encFnInfo) {{ .MethodNamePfx "fastpathEnc" false }}R(rv reflect.Value) ...@@ -157,16 +168,18 @@ func (f *encFnInfo) {{ .MethodNamePfx "fastpathEnc" false }}R(rv reflect.Value)
fastpathTV.{{ .MethodNamePfx "Enc" false }}V(rv.Interface().([]{{ .Elem }}), fastpathCheckNilFalse, f.e) fastpathTV.{{ .MethodNamePfx "Enc" false }}V(rv.Interface().([]{{ .Elem }}), fastpathCheckNilFalse, f.e)
} }
func (_ fastpathT) {{ .MethodNamePfx "Enc" false }}V(v []{{ .Elem }}, checkNil bool, e *Encoder) { func (_ fastpathT) {{ .MethodNamePfx "Enc" false }}V(v []{{ .Elem }}, checkNil bool, e *Encoder) {
ee := e.e ee := e.e
cr := e.cr
if checkNil && v == nil { if checkNil && v == nil {
ee.EncodeNil() ee.EncodeNil()
return return
} }
ee.EncodeArrayStart(len(v)) ee.EncodeArrayStart(len(v))
for _, v2 := range v { for _, v2 := range v {
if cr != nil { cr.sendContainerState(containerArrayElem) }
{{ encmd .Elem "v2"}} {{ encmd .Elem "v2"}}
} }
ee.EncodeEnd() if cr != nil { cr.sendContainerState(containerArrayEnd) }{{/* ee.EncodeEnd() */}}
} }
{{end}}{{end}}{{end}} {{end}}{{end}}{{end}}
...@@ -178,6 +191,7 @@ func (f *encFnInfo) {{ .MethodNamePfx "fastpathEnc" false }}R(rv reflect.Value) ...@@ -178,6 +191,7 @@ func (f *encFnInfo) {{ .MethodNamePfx "fastpathEnc" false }}R(rv reflect.Value)
} }
func (_ fastpathT) {{ .MethodNamePfx "Enc" false }}V(v map[{{ .MapKey }}]{{ .Elem }}, checkNil bool, e *Encoder) { func (_ fastpathT) {{ .MethodNamePfx "Enc" false }}V(v map[{{ .MapKey }}]{{ .Elem }}, checkNil bool, e *Encoder) {
ee := e.e ee := e.e
cr := e.cr
if checkNil && v == nil { if checkNil && v == nil {
ee.EncodeNil() ee.EncodeNil()
return return
...@@ -201,7 +215,9 @@ func (_ fastpathT) {{ .MethodNamePfx "Enc" false }}V(v map[{{ .MapKey }}]{{ .Ele ...@@ -201,7 +215,9 @@ func (_ fastpathT) {{ .MethodNamePfx "Enc" false }}V(v map[{{ .MapKey }}]{{ .Ele
} }
sort.Sort(bytesISlice(v2)) sort.Sort(bytesISlice(v2))
for j := range v2 { for j := range v2 {
if cr != nil { cr.sendContainerState(containerMapKey) }
e.asis(v2[j].v) e.asis(v2[j].v)
if cr != nil { cr.sendContainerState(containerMapValue) }
e.encode(v[v2[j].i]) e.encode(v[v2[j].i])
} {{else}}{{ $x := sorttype .MapKey true}}v2 := make([]{{ $x }}, len(v)) } {{else}}{{ $x := sorttype .MapKey true}}v2 := make([]{{ $x }}, len(v))
var i int var i int
...@@ -211,24 +227,28 @@ func (_ fastpathT) {{ .MethodNamePfx "Enc" false }}V(v map[{{ .MapKey }}]{{ .Ele ...@@ -211,24 +227,28 @@ func (_ fastpathT) {{ .MethodNamePfx "Enc" false }}V(v map[{{ .MapKey }}]{{ .Ele
} }
sort.Sort({{ sorttype .MapKey false}}(v2)) sort.Sort({{ sorttype .MapKey false}}(v2))
for _, k2 := range v2 { for _, k2 := range v2 {
if cr != nil { cr.sendContainerState(containerMapKey) }
{{if eq .MapKey "string"}}if asSymbols { {{if eq .MapKey "string"}}if asSymbols {
ee.EncodeSymbol(k2) ee.EncodeSymbol(k2)
} else { } else {
ee.EncodeString(c_UTF8, k2) ee.EncodeString(c_UTF8, k2)
}{{else}}{{ $y := printf "%s(k2)" .MapKey }}{{ encmd .MapKey $y }}{{end}} }{{else}}{{ $y := printf "%s(k2)" .MapKey }}{{ encmd .MapKey $y }}{{end}}
if cr != nil { cr.sendContainerState(containerMapValue) }
{{ $y := printf "v[%s(k2)]" .MapKey }}{{ encmd .Elem $y }} {{ $y := printf "v[%s(k2)]" .MapKey }}{{ encmd .Elem $y }}
} {{end}} } {{end}}
} else { } else {
for k2, v2 := range v { for k2, v2 := range v {
if cr != nil { cr.sendContainerState(containerMapKey) }
{{if eq .MapKey "string"}}if asSymbols { {{if eq .MapKey "string"}}if asSymbols {
ee.EncodeSymbol(k2) ee.EncodeSymbol(k2)
} else { } else {
ee.EncodeString(c_UTF8, k2) ee.EncodeString(c_UTF8, k2)
}{{else}}{{ encmd .MapKey "k2"}}{{end}} }{{else}}{{ encmd .MapKey "k2"}}{{end}}
if cr != nil { cr.sendContainerState(containerMapValue) }
{{ encmd .Elem "v2"}} {{ encmd .Elem "v2"}}
} }
} }
ee.EncodeEnd() if cr != nil { cr.sendContainerState(containerMapEnd) }{{/* ee.EncodeEnd() */}}
} }
{{end}}{{end}}{{end}} {{end}}{{end}}{{end}}
...@@ -237,6 +257,9 @@ func (_ fastpathT) {{ .MethodNamePfx "Enc" false }}V(v map[{{ .MapKey }}]{{ .Ele ...@@ -237,6 +257,9 @@ func (_ fastpathT) {{ .MethodNamePfx "Enc" false }}V(v map[{{ .MapKey }}]{{ .Ele
// -- -- fast path type switch // -- -- fast path type switch
func fastpathDecodeTypeSwitch(iv interface{}, d *Decoder) bool { func fastpathDecodeTypeSwitch(iv interface{}, d *Decoder) bool {
if !fastpathEnabled {
return false
}
switch v := iv.(type) { switch v := iv.(type) {
{{range .Values}}{{if not .Primitive}}{{if not .MapKey }} {{range .Values}}{{if not .Primitive}}{{if not .MapKey }}
case []{{ .Elem }}:{{else}} case []{{ .Elem }}:{{else}}
...@@ -250,6 +273,7 @@ func fastpathDecodeTypeSwitch(iv interface{}, d *Decoder) bool { ...@@ -250,6 +273,7 @@ func fastpathDecodeTypeSwitch(iv interface{}, d *Decoder) bool {
} }
{{end}}{{end}} {{end}}{{end}}
default: default:
_ = v // TODO: workaround https://github.com/golang/go/issues/12927 (remove after go 1.6 release)
return false return false
} }
return true return true
...@@ -283,8 +307,7 @@ func (f fastpathT) {{ .MethodNamePfx "Dec" false }}X(vp *[]{{ .Elem }}, checkNil ...@@ -283,8 +307,7 @@ func (f fastpathT) {{ .MethodNamePfx "Dec" false }}X(vp *[]{{ .Elem }}, checkNil
*vp = v *vp = v
} }
} }
func (_ fastpathT) {{ .MethodNamePfx "Dec" false }}V(v []{{ .Elem }}, checkNil bool, canChange bool, func (_ fastpathT) {{ .MethodNamePfx "Dec" false }}V(v []{{ .Elem }}, checkNil bool, canChange bool, d *Decoder) (_ []{{ .Elem }}, changed bool) {
d *Decoder) (_ []{{ .Elem }}, changed bool) {
dd := d.d dd := d.d
{{/* // if dd.isContainerType(valueTypeNil) { dd.TryDecodeAsNil() */}} {{/* // if dd.isContainerType(valueTypeNil) { dd.TryDecodeAsNil() */}}
if checkNil && dd.TryDecodeAsNil() { if checkNil && dd.TryDecodeAsNil() {
...@@ -295,28 +318,22 @@ func (_ fastpathT) {{ .MethodNamePfx "Dec" false }}V(v []{{ .Elem }}, checkNil b ...@@ -295,28 +318,22 @@ func (_ fastpathT) {{ .MethodNamePfx "Dec" false }}V(v []{{ .Elem }}, checkNil b
} }
slh, containerLenS := d.decSliceHelperStart() slh, containerLenS := d.decSliceHelperStart()
x2read := containerLenS
var xtrunc bool
if canChange && v == nil {
var xlen int
if xlen, xtrunc = decInferLen(containerLenS, d.h.MaxInitLen, {{ .Size }}); xtrunc {
x2read = xlen
}
v = make([]{{ .Elem }}, xlen)
changed = true
}
if containerLenS == 0 { if containerLenS == 0 {
if canChange && len(v) != 0 { if canChange {
v = v[:0] if v == nil {
changed = true v = []{{ .Elem }}{}
}{{/* } else if len(v) != 0 {
// slh.End() // dd.ReadArrayEnd() v = v[:0]
*/}} }
return v, changed changed = true
}
slh.End()
return
} }
{{/* // for j := 0; j < containerLenS; j++ { */}}
if containerLenS > 0 { if containerLenS > 0 {
x2read := containerLenS
var xtrunc bool
if containerLenS > cap(v) { if containerLenS > cap(v) {
if canChange { {{/* if canChange { {{/*
// fast-path is for "basic" immutable types, so no need to copy them over // fast-path is for "basic" immutable types, so no need to copy them over
...@@ -324,37 +341,64 @@ func (_ fastpathT) {{ .MethodNamePfx "Dec" false }}V(v []{{ .Elem }}, checkNil b ...@@ -324,37 +341,64 @@ func (_ fastpathT) {{ .MethodNamePfx "Dec" false }}V(v []{{ .Elem }}, checkNil b
// copy(s, v[:cap(v)]) // copy(s, v[:cap(v)])
// v = s */}} // v = s */}}
var xlen int var xlen int
if xlen, xtrunc = decInferLen(containerLenS, d.h.MaxInitLen, {{ .Size }}); xtrunc { xlen, xtrunc = decInferLen(containerLenS, d.h.MaxInitLen, {{ .Size }})
x2read = xlen if xtrunc {
if xlen <= cap(v) {
v = v[:xlen]
} else {
v = make([]{{ .Elem }}, xlen)
}
} else {
v = make([]{{ .Elem }}, xlen)
} }
v = make([]{{ .Elem }}, xlen)
changed = true changed = true
} else { } else {
d.arrayCannotExpand(len(v), containerLenS) d.arrayCannotExpand(len(v), containerLenS)
x2read = len(v)
} }
x2read = len(v)
} else if containerLenS != len(v) { } else if containerLenS != len(v) {
v = v[:containerLenS] if canChange {
changed = true v = v[:containerLenS]
} changed = true
{{/* // all checks done. cannot go past len. */}} }
} {{/* // all checks done. cannot go past len. */}}
j := 0 j := 0
for ; j < x2read; j++ { for ; j < x2read; j++ {
slh.ElemContainerState(j)
{{ if eq .Elem "interface{}" }}d.decode(&v[j]){{ else }}v[j] = {{ decmd .Elem }}{{ end }} {{ if eq .Elem "interface{}" }}d.decode(&v[j]){{ else }}v[j] = {{ decmd .Elem }}{{ end }}
} }
if xtrunc { {{/* // means canChange=true, changed=true already. */}} if xtrunc { {{/* // means canChange=true, changed=true already. */}}
for ; j < containerLenS; j++ { for ; j < containerLenS; j++ {
v = append(v, {{ zerocmd .Elem }}) v = append(v, {{ zerocmd .Elem }})
slh.ElemContainerState(j)
{{ if eq .Elem "interface{}" }}d.decode(&v[j]){{ else }}v[j] = {{ decmd .Elem }}{{ end }} {{ if eq .Elem "interface{}" }}d.decode(&v[j]){{ else }}v[j] = {{ decmd .Elem }}{{ end }}
} }
} else if !canChange { } else if !canChange {
for ; j < containerLenS; j++ { for ; j < containerLenS; j++ {
slh.ElemContainerState(j)
d.swallow() d.swallow()
} }
} }
} else { } else {
j := 0 breakFound := dd.CheckBreak() {{/* check break first, so we can initialize v with a capacity of 4 if necessary */}}
for ; !dd.CheckBreak(); j++ { if breakFound {
if canChange {
if v == nil {
v = []{{ .Elem }}{}
} else if len(v) != 0 {
v = v[:0]
}
changed = true
}
slh.End()
return
}
if cap(v) == 0 {
v = make([]{{ .Elem }}, 1, 4)
changed = true
}
j := 0
for ; !breakFound; j++ {
if j >= len(v) { if j >= len(v) {
if canChange { if canChange {
v = append(v, {{ zerocmd .Elem }}) v = append(v, {{ zerocmd .Elem }})
...@@ -362,16 +406,22 @@ func (_ fastpathT) {{ .MethodNamePfx "Dec" false }}V(v []{{ .Elem }}, checkNil b ...@@ -362,16 +406,22 @@ func (_ fastpathT) {{ .MethodNamePfx "Dec" false }}V(v []{{ .Elem }}, checkNil b
} else { } else {
d.arrayCannotExpand(len(v), j+1) d.arrayCannotExpand(len(v), j+1)
} }
} }
slh.ElemContainerState(j)
if j < len(v) { {{/* // all checks done. cannot go past len. */}} if j < len(v) { {{/* // all checks done. cannot go past len. */}}
{{ if eq .Elem "interface{}" }}d.decode(&v[j]) {{ if eq .Elem "interface{}" }}d.decode(&v[j])
{{ else }}v[j] = {{ decmd .Elem }}{{ end }} {{ else }}v[j] = {{ decmd .Elem }}{{ end }}
} else { } else {
d.swallow() d.swallow()
} }
breakFound = dd.CheckBreak()
}
if canChange && j < len(v) {
v = v[:j]
changed = true
} }
slh.End()
} }
slh.End()
return v, changed return v, changed
} }
...@@ -405,6 +455,7 @@ func (f fastpathT) {{ .MethodNamePfx "Dec" false }}X(vp *map[{{ .MapKey }}]{{ .E ...@@ -405,6 +455,7 @@ func (f fastpathT) {{ .MethodNamePfx "Dec" false }}X(vp *map[{{ .MapKey }}]{{ .E
func (_ fastpathT) {{ .MethodNamePfx "Dec" false }}V(v map[{{ .MapKey }}]{{ .Elem }}, checkNil bool, canChange bool, func (_ fastpathT) {{ .MethodNamePfx "Dec" false }}V(v map[{{ .MapKey }}]{{ .Elem }}, checkNil bool, canChange bool,
d *Decoder) (_ map[{{ .MapKey }}]{{ .Elem }}, changed bool) { d *Decoder) (_ map[{{ .MapKey }}]{{ .Elem }}, changed bool) {
dd := d.d dd := d.d
cr := d.cr
{{/* // if dd.isContainerType(valueTypeNil) {dd.TryDecodeAsNil() */}} {{/* // if dd.isContainerType(valueTypeNil) {dd.TryDecodeAsNil() */}}
if checkNil && dd.TryDecodeAsNil() { if checkNil && dd.TryDecodeAsNil() {
if v != nil { if v != nil {
...@@ -424,11 +475,13 @@ func (_ fastpathT) {{ .MethodNamePfx "Dec" false }}V(v map[{{ .MapKey }}]{{ .Ele ...@@ -424,11 +475,13 @@ func (_ fastpathT) {{ .MethodNamePfx "Dec" false }}V(v map[{{ .MapKey }}]{{ .Ele
var mv {{ .Elem }} var mv {{ .Elem }}
if containerLen > 0 { if containerLen > 0 {
for j := 0; j < containerLen; j++ { for j := 0; j < containerLen; j++ {
if cr != nil { cr.sendContainerState(containerMapKey) }
{{ if eq .MapKey "interface{}" }}mk = nil {{ if eq .MapKey "interface{}" }}mk = nil
d.decode(&mk) d.decode(&mk)
if bv, bok := mk.([]byte); bok { if bv, bok := mk.([]byte); bok {
mk = d.string(bv) {{/* // maps cannot have []byte as key. switch to string. */}} mk = d.string(bv) {{/* // maps cannot have []byte as key. switch to string. */}}
}{{ else }}mk = {{ decmd .MapKey }}{{ end }} }{{ else }}mk = {{ decmd .MapKey }}{{ end }}
if cr != nil { cr.sendContainerState(containerMapValue) }
{{ if eq .Elem "interface{}" }}if mapGet { mv = v[mk] } else { mv = nil } {{ if eq .Elem "interface{}" }}if mapGet { mv = v[mk] } else { mv = nil }
d.decode(&mv){{ else }}mv = {{ decmd .Elem }}{{ end }} d.decode(&mv){{ else }}mv = {{ decmd .Elem }}{{ end }}
if v != nil { if v != nil {
...@@ -437,19 +490,21 @@ func (_ fastpathT) {{ .MethodNamePfx "Dec" false }}V(v map[{{ .MapKey }}]{{ .Ele ...@@ -437,19 +490,21 @@ func (_ fastpathT) {{ .MethodNamePfx "Dec" false }}V(v map[{{ .MapKey }}]{{ .Ele
} }
} else if containerLen < 0 { } else if containerLen < 0 {
for j := 0; !dd.CheckBreak(); j++ { for j := 0; !dd.CheckBreak(); j++ {
if cr != nil { cr.sendContainerState(containerMapKey) }
{{ if eq .MapKey "interface{}" }}mk = nil {{ if eq .MapKey "interface{}" }}mk = nil
d.decode(&mk) d.decode(&mk)
if bv, bok := mk.([]byte); bok { if bv, bok := mk.([]byte); bok {
mk = d.string(bv) {{/* // maps cannot have []byte as key. switch to string. */}} mk = d.string(bv) {{/* // maps cannot have []byte as key. switch to string. */}}
}{{ else }}mk = {{ decmd .MapKey }}{{ end }} }{{ else }}mk = {{ decmd .MapKey }}{{ end }}
if cr != nil { cr.sendContainerState(containerMapValue) }
{{ if eq .Elem "interface{}" }}if mapGet { mv = v[mk] } else { mv = nil } {{ if eq .Elem "interface{}" }}if mapGet { mv = v[mk] } else { mv = nil }
d.decode(&mv){{ else }}mv = {{ decmd .Elem }}{{ end }} d.decode(&mv){{ else }}mv = {{ decmd .Elem }}{{ end }}
if v != nil { if v != nil {
v[mk] = mv v[mk] = mv
} }
} }
dd.ReadEnd()
} }
if cr != nil { cr.sendContainerState(containerMapEnd) }
return v, changed return v, changed
} }
......
// +build notfastpath
package codec
import "reflect"
// The generated fast-path code is very large, and adds a few seconds to the build time.
// This causes test execution, execution of small tools which use codec, etc
// to take a long time.
//
// To mitigate, we now support the notfastpath tag.
// 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 }
type fastpathT struct{}
type fastpathE struct {
rtid uintptr
rt reflect.Type
encfn func(*encFnInfo, reflect.Value)
decfn func(*decFnInfo, reflect.Value)
}
type fastpathA [0]fastpathE
func (x fastpathA) index(rtid uintptr) int { return -1 }
var fastpathAV fastpathA
var fastpathTV fastpathT
{{var "v"}} := {{ if not isArray}}*{{ end }}{{ .Varname }} {{var "v"}} := {{if not isArray}}*{{end}}{{ .Varname }}
{{var "h"}}, {{var "l"}} := z.DecSliceHelperStart() {{/* // helper, containerLenS */}} {{var "h"}}, {{var "l"}} := z.DecSliceHelperStart() {{/* // helper, containerLenS */}}
var {{var "c"}} bool {{/* // changed */}}
var {{var "rr"}}, {{var "rl"}} int {{/* // num2read, length of slice/array/chan */}} if {{var "l"}} == 0 {
var {{var "c"}}, {{var "rt"}} bool {{/* // changed, truncated */}} {{if isSlice }}if {{var "v"}} == nil {
_, _, _ = {{var "c"}}, {{var "rt"}}, {{var "rl"}} {{var "v"}} = []{{ .Typ }}{}
{{var "rr"}} = {{var "l"}} {{var "c"}} = true
{{/* rl is NOT used. Only used for getting DecInferLen. len(r) used directly in code */}} } else if len({{var "v"}}) != 0 {
{{var "v"}} = {{var "v"}}[:0]
{{ if not isArray }}if {{var "v"}} == nil { {{var "c"}} = true
if {{var "rl"}}, {{var "rt"}} = z.DecInferLen({{var "l"}}, z.DecBasicHandle().MaxInitLen, {{ .Size }}); {{var "rt"}} { } {{end}} {{if isChan }}if {{var "v"}} == nil {
{{var "rr"}} = {{var "rl"}} {{var "v"}} = make({{ .CTyp }}, 0)
} {{var "c"}} = true
{{var "v"}} = make({{ .CTyp }}, {{var "rl"}}) } {{end}}
{{var "c"}} = true
}
{{ end }}
if {{var "l"}} == 0 { {{ if isSlice }}
if len({{var "v"}}) != 0 {
{{var "v"}} = {{var "v"}}[:0]
{{var "c"}} = true
} {{ end }}
} else if {{var "l"}} > 0 { } else if {{var "l"}} > 0 {
{{ if isChan }} {{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"}}++ { for {{var "r"}} := 0; {{var "r"}} < {{var "l"}}; {{var "r"}}++ {
{{var "h"}}.ElemContainerState({{var "r"}})
var {{var "t"}} {{ .Typ }} var {{var "t"}} {{ .Typ }}
{{ $x := printf "%st%s" .TempVar .Rand }}{{ decLineVar $x }} {{ $x := printf "%st%s" .TempVar .Rand }}{{ decLineVar $x }}
{{var "v"}} <- {{var "t"}} {{var "v"}} <- {{var "t"}}
{{ else }} }
{{ else }} var {{var "rr"}}, {{var "rl"}} int {{/* // num2read, length of slice/array/chan */}}
var {{var "rt"}} bool {{/* truncated */}}
if {{var "l"}} > cap({{var "v"}}) { if {{var "l"}} > cap({{var "v"}}) {
{{ if isArray }}z.DecArrayCannotExpand(len({{var "v"}}), {{var "l"}}) {{if isArray }}z.DecArrayCannotExpand(len({{var "v"}}), {{var "l"}})
{{ else }}{{var "rl"}}, {{var "rt"}} = z.DecInferLen({{var "l"}}, z.DecBasicHandle().MaxInitLen, {{ .Size }}) {{ else }}{{if not .Immutable }}
{{ if .Immutable }} {{var "rg"}} := len({{var "v"}}) > 0
{{var "v2"}} := {{var "v"}} {{var "v2"}} := {{var "v"}} {{end}}
{{var "v"}} = make([]{{ .Typ }}, {{var "rl"}}) {{var "rl"}}, {{var "rt"}} = z.DecInferLen({{var "l"}}, z.DecBasicHandle().MaxInitLen, {{ .Size }})
if len({{var "v"}}) > 0 { if {{var "rt"}} {
copy({{var "v"}}, {{var "v2"}}[:cap({{var "v2"}})]) if {{var "rl"}} <= cap({{var "v"}}) {
{{var "v"}} = {{var "v"}}[:{{var "rl"}}]
} else {
{{var "v"}} = make([]{{ .Typ }}, {{var "rl"}})
}
} else {
{{var "v"}} = make([]{{ .Typ }}, {{var "rl"}})
} }
{{ else }}{{var "v"}} = make([]{{ .Typ }}, {{var "rl"}}) {{var "c"}} = true
{{ end }}{{var "c"}} = true {{var "rr"}} = len({{var "v"}}) {{if not .Immutable }}
{{ end }} if {{var "rg"}} { copy({{var "v"}}, {{var "v2"}}) } {{end}} {{end}}{{/* end not Immutable, isArray */}}
{{var "rr"}} = len({{var "v"}}) } {{if isSlice }} else if {{var "l"}} != len({{var "v"}}) {
} else if {{var "l"}} != len({{var "v"}}) { {{var "v"}} = {{var "v"}}[:{{var "l"}}]
{{ if isSlice }}{{var "v"}} = {{var "v"}}[:{{var "l"}}] {{var "c"}} = true
{{var "c"}} = true {{ end }} } {{end}} {{/* end isSlice:47 */}}
}
{{var "j"}} := 0 {{var "j"}} := 0
for ; {{var "j"}} < {{var "rr"}} ; {{var "j"}}++ { 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 }} {{ $x := printf "%[1]vv%[2]v[%[1]vj%[2]v]" .TempVar .Rand }}{{ decLineVar $x }}
} }
{{ if isArray }}for ; {{var "j"}} < {{var "l"}} ; {{var "j"}}++ { {{if isArray }}for ; {{var "j"}} < {{var "l"}} ; {{var "j"}}++ {
{{var "h"}}.ElemContainerState({{var "j"}})
z.DecSwallow() z.DecSwallow()
} }
{{ else }}if {{var "rt"}} { {{/* means that it is mutable and slice */}} {{ else }}if {{var "rt"}} {
for ; {{var "j"}} < {{var "l"}} ; {{var "j"}}++ { for ; {{var "j"}} < {{var "l"}} ; {{var "j"}}++ {
{{var "v"}} = append({{var "v"}}, {{ zero}}) {{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 }} {{ $x := printf "%[1]vv%[2]v[%[1]vj%[2]v]" .TempVar .Rand }}{{ decLineVar $x }}
} }
} } {{end}} {{/* end isArray:56 */}}
{{ end }} {{end}} {{/* end isChan:16 */}}
{{ end }}{{/* closing 'if not chan' */}} } else { {{/* len < 0 */}}
} else { {{var "j"}} := 0
for {{var "j"}} := 0; !r.CheckBreak(); {{var "j"}}++ { for ; !r.CheckBreak(); {{var "j"}}++ {
if {{var "j"}} >= len({{var "v"}}) { {{if isChan }}
{{ if isArray }}z.DecArrayCannotExpand(len({{var "v"}}), {{var "j"}}+1) {{var "h"}}.ElemContainerState({{var "j"}})
{{ else if isSlice}}{{var "v"}} = append({{var "v"}}, {{zero}})// var {{var "z"}} {{ .Typ }}
{{var "c"}} = true {{ end }}
}
{{ if isChan}}
var {{var "t"}} {{ .Typ }} var {{var "t"}} {{ .Typ }}
{{ $x := printf "%st%s" .TempVar .Rand }}{{ decLineVar $x }} {{ $x := printf "%st%s" .TempVar .Rand }}{{ decLineVar $x }}
{{var "v"}} <- {{var "t"}} {{var "v"}} <- {{var "t"}}
{{ else }} {{ else }}
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}}
}
{{var "h"}}.ElemContainerState({{var "j"}})
if {{var "j"}} < len({{var "v"}}) { if {{var "j"}} < len({{var "v"}}) {
{{ $x := printf "%[1]vv%[2]v[%[1]vj%[2]v]" .TempVar .Rand }}{{ decLineVar $x }} {{ $x := printf "%[1]vv%[2]v[%[1]vj%[2]v]" .TempVar .Rand }}{{ decLineVar $x }}
} else { } else {
z.DecSwallow() z.DecSwallow()
} }
{{ end }} {{end}}
} }
{{var "h"}}.End() {{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 "c"}} = true
}{{end}}
} }
{{ if not isArray }}if {{var "c"}} { {{var "h"}}.End()
{{if not isArray }}if {{var "c"}} {
*{{ .Varname }} = {{var "v"}} *{{ .Varname }} = {{var "v"}}
}{{ end }} }{{end}}
...@@ -8,7 +8,7 @@ if {{var "v"}} == nil { ...@@ -8,7 +8,7 @@ if {{var "v"}} == nil {
} }
var {{var "mk"}} {{ .KTyp }} var {{var "mk"}} {{ .KTyp }}
var {{var "mv"}} {{ .Typ }} var {{var "mv"}} {{ .Typ }}
var {{var "mg"}} bool var {{var "mg"}} {{if decElemKindPtr}}, {{var "ms"}}, {{var "mok"}}{{end}} bool
if {{var "bh"}}.MapValueReset { if {{var "bh"}}.MapValueReset {
{{if decElemKindPtr}}{{var "mg"}} = true {{if decElemKindPtr}}{{var "mg"}} = true
{{else if decElemKindIntf}}if !{{var "bh"}}.InterfaceReset { {{var "mg"}} = true } {{else if decElemKindIntf}}if !{{var "bh"}}.InterfaceReset { {{var "mg"}} = true }
...@@ -16,31 +16,43 @@ if {{var "bh"}}.MapValueReset { ...@@ -16,31 +16,43 @@ if {{var "bh"}}.MapValueReset {
{{end}} } {{end}} }
if {{var "l"}} > 0 { if {{var "l"}} > 0 {
for {{var "j"}} := 0; {{var "j"}} < {{var "l"}}; {{var "j"}}++ { for {{var "j"}} := 0; {{var "j"}} < {{var "l"}}; {{var "j"}}++ {
z.DecSendContainerState(codecSelfer_containerMapKey{{ .Sfx }})
{{ $x := printf "%vmk%v" .TempVar .Rand }}{{ decLineVarK $x }} {{ $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"}} { {{ 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"}}) {{var "mk"}} = string({{var "bv"}})
}{{ end }} }{{ end }}{{if decElemKindPtr}}
{{var "ms"}} = true{{end}}
if {{var "mg"}} { if {{var "mg"}} {
{{var "mv"}} = {{var "v"}}[{{var "mk"}}] {{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}} } {{if not decElemKindImmutable}}else { {{var "mv"}} = {{decElemZero}} }{{end}}
z.DecSendContainerState(codecSelfer_containerMapValue{{ .Sfx }})
{{ $x := printf "%vmv%v" .TempVar .Rand }}{{ decLineVar $x }} {{ $x := printf "%vmv%v" .TempVar .Rand }}{{ decLineVar $x }}
if {{var "v"}} != nil { if {{if decElemKindPtr}} {{var "ms"}} && {{end}} {{var "v"}} != nil {
{{var "v"}}[{{var "mk"}}] = {{var "mv"}} {{var "v"}}[{{var "mk"}}] = {{var "mv"}}
} }
} }
} else if {{var "l"}} < 0 { } else if {{var "l"}} < 0 {
for {{var "j"}} := 0; !r.CheckBreak(); {{var "j"}}++ { for {{var "j"}} := 0; !r.CheckBreak(); {{var "j"}}++ {
z.DecSendContainerState(codecSelfer_containerMapKey{{ .Sfx }})
{{ $x := printf "%vmk%v" .TempVar .Rand }}{{ decLineVarK $x }} {{ $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"}} { {{ 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"}}) {{var "mk"}} = string({{var "bv"}})
}{{ end }} }{{ end }}{{if decElemKindPtr}}
{{var "ms"}} = true {{ end }}
if {{var "mg"}} { if {{var "mg"}} {
{{var "mv"}} = {{var "v"}}[{{var "mk"}}] {{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}} } {{if not decElemKindImmutable}}else { {{var "mv"}} = {{decElemZero}} }{{end}}
z.DecSendContainerState(codecSelfer_containerMapValue{{ .Sfx }})
{{ $x := printf "%vmv%v" .TempVar .Rand }}{{ decLineVar $x }} {{ $x := printf "%vmv%v" .TempVar .Rand }}{{ decLineVar $x }}
if {{var "v"}} != nil { if {{if decElemKindPtr}} {{var "ms"}} && {{end}} {{var "v"}} != nil {
{{var "v"}}[{{var "mk"}}] = {{var "mv"}} {{var "v"}}[{{var "mk"}}] = {{var "mv"}}
} }
} }
r.ReadEnd()
} // else len==0: TODO: Should we clear map entries? } // else len==0: TODO: Should we clear map entries?
z.DecSendContainerState(codecSelfer_containerMapEnd{{ .Sfx }})
...@@ -116,6 +116,15 @@ func (f genHelperEncoder) EncExt(v interface{}) (r bool) { ...@@ -116,6 +116,15 @@ func (f genHelperEncoder) EncExt(v interface{}) (r bool) {
} }
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* // 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*
func (f genHelperDecoder) DecBasicHandle() *BasicHandle { func (f genHelperDecoder) DecBasicHandle() *BasicHandle {
return f.d.h return f.d.h
} }
...@@ -167,11 +176,8 @@ func (f genHelperDecoder) DecTextUnmarshal(tm encoding.TextUnmarshaler) { ...@@ -167,11 +176,8 @@ func (f genHelperDecoder) DecTextUnmarshal(tm encoding.TextUnmarshaler) {
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperDecoder) DecJSONUnmarshal(tm jsonUnmarshaler) { func (f genHelperDecoder) DecJSONUnmarshal(tm jsonUnmarshaler) {
// bs := f.dd.DecodeBytes(f.d.b[:], true, true) // bs := f.dd.DecodeBytes(f.d.b[:], true, true)
f.d.r.track() // grab the bytes to be read, as UnmarshalJSON needs the full JSON so as to unmarshal it itself.
f.d.swallow() fnerr := tm.UnmarshalJSON(f.d.nextValueBytes())
bs := f.d.r.stopTrack()
// fmt.Printf(">>>>>> CODECGEN JSON: %s\n", bs)
fnerr := tm.UnmarshalJSON(bs)
if fnerr != nil { if fnerr != nil {
panic(fnerr) panic(fnerr)
} }
...@@ -218,3 +224,10 @@ func (f genHelperDecoder) DecExt(v interface{}) (r bool) { ...@@ -218,3 +224,10 @@ func (f genHelperDecoder) DecExt(v interface{}) (r bool) {
func (f genHelperDecoder) DecInferLen(clen, maxlen, unit int) (rvlen int, truncated bool) { func (f genHelperDecoder) DecInferLen(clen, maxlen, unit int) (rvlen int, truncated bool) {
return decInferLen(clen, maxlen, unit) 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)
}
}
...@@ -106,6 +106,14 @@ func (f genHelperEncoder) EncExt(v interface{}) (r bool) { ...@@ -106,6 +106,14 @@ func (f genHelperEncoder) EncExt(v interface{}) (r bool) {
} }
return false 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* // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperDecoder) DecBasicHandle() *BasicHandle { func (f genHelperDecoder) DecBasicHandle() *BasicHandle {
...@@ -150,11 +158,8 @@ func (f genHelperDecoder) DecTextUnmarshal(tm encoding.TextUnmarshaler) { ...@@ -150,11 +158,8 @@ func (f genHelperDecoder) DecTextUnmarshal(tm encoding.TextUnmarshaler) {
// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
func (f genHelperDecoder) DecJSONUnmarshal(tm jsonUnmarshaler) { func (f genHelperDecoder) DecJSONUnmarshal(tm jsonUnmarshaler) {
// bs := f.dd.DecodeBytes(f.d.b[:], true, true) // bs := f.dd.DecodeBytes(f.d.b[:], true, true)
f.d.r.track() // grab the bytes to be read, as UnmarshalJSON needs the full JSON so as to unmarshal it itself.
f.d.swallow() fnerr := tm.UnmarshalJSON(f.d.nextValueBytes())
bs := f.d.r.stopTrack()
// fmt.Printf(">>>>>> CODECGEN JSON: %s\n", bs)
fnerr := tm.UnmarshalJSON(bs)
if fnerr != nil { if fnerr != nil {
panic(fnerr) panic(fnerr)
} }
...@@ -195,6 +200,12 @@ func (f genHelperDecoder) DecExt(v interface{}) (r bool) { ...@@ -195,6 +200,12 @@ func (f genHelperDecoder) DecExt(v interface{}) (r bool) {
func (f genHelperDecoder) DecInferLen(clen, maxlen, unit int) (rvlen int, truncated bool) { func (f genHelperDecoder) DecInferLen(clen, maxlen, unit int) (rvlen int, truncated bool) {
return decInferLen(clen, maxlen, unit) 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)
}
}
{{/* {{/*
......
...@@ -16,7 +16,7 @@ if {{var "v"}} == nil { ...@@ -16,7 +16,7 @@ if {{var "v"}} == nil {
} }
var {{var "mk"}} {{ .KTyp }} var {{var "mk"}} {{ .KTyp }}
var {{var "mv"}} {{ .Typ }} var {{var "mv"}} {{ .Typ }}
var {{var "mg"}} bool var {{var "mg"}} {{if decElemKindPtr}}, {{var "ms"}}, {{var "mok"}}{{end}} bool
if {{var "bh"}}.MapValueReset { if {{var "bh"}}.MapValueReset {
{{if decElemKindPtr}}{{var "mg"}} = true {{if decElemKindPtr}}{{var "mg"}} = true
{{else if decElemKindIntf}}if !{{var "bh"}}.InterfaceReset { {{var "mg"}} = true } {{else if decElemKindIntf}}if !{{var "bh"}}.InterfaceReset { {{var "mg"}} = true }
...@@ -24,122 +24,149 @@ if {{var "bh"}}.MapValueReset { ...@@ -24,122 +24,149 @@ if {{var "bh"}}.MapValueReset {
{{end}} } {{end}} }
if {{var "l"}} > 0 { if {{var "l"}} > 0 {
for {{var "j"}} := 0; {{var "j"}} < {{var "l"}}; {{var "j"}}++ { for {{var "j"}} := 0; {{var "j"}} < {{var "l"}}; {{var "j"}}++ {
z.DecSendContainerState(codecSelfer_containerMapKey{{ .Sfx }})
{{ $x := printf "%vmk%v" .TempVar .Rand }}{{ decLineVarK $x }} {{ $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"}} { {{ 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"}}) {{var "mk"}} = string({{var "bv"}})
}{{ end }} }{{ end }}{{if decElemKindPtr}}
{{var "ms"}} = true{{end}}
if {{var "mg"}} { if {{var "mg"}} {
{{var "mv"}} = {{var "v"}}[{{var "mk"}}] {{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}} } {{if not decElemKindImmutable}}else { {{var "mv"}} = {{decElemZero}} }{{end}}
z.DecSendContainerState(codecSelfer_containerMapValue{{ .Sfx }})
{{ $x := printf "%vmv%v" .TempVar .Rand }}{{ decLineVar $x }} {{ $x := printf "%vmv%v" .TempVar .Rand }}{{ decLineVar $x }}
if {{var "v"}} != nil { if {{if decElemKindPtr}} {{var "ms"}} && {{end}} {{var "v"}} != nil {
{{var "v"}}[{{var "mk"}}] = {{var "mv"}} {{var "v"}}[{{var "mk"}}] = {{var "mv"}}
} }
} }
} else if {{var "l"}} < 0 { } else if {{var "l"}} < 0 {
for {{var "j"}} := 0; !r.CheckBreak(); {{var "j"}}++ { for {{var "j"}} := 0; !r.CheckBreak(); {{var "j"}}++ {
z.DecSendContainerState(codecSelfer_containerMapKey{{ .Sfx }})
{{ $x := printf "%vmk%v" .TempVar .Rand }}{{ decLineVarK $x }} {{ $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"}} { {{ 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"}}) {{var "mk"}} = string({{var "bv"}})
}{{ end }} }{{ end }}{{if decElemKindPtr}}
{{var "ms"}} = true {{ end }}
if {{var "mg"}} { if {{var "mg"}} {
{{var "mv"}} = {{var "v"}}[{{var "mk"}}] {{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}} } {{if not decElemKindImmutable}}else { {{var "mv"}} = {{decElemZero}} }{{end}}
z.DecSendContainerState(codecSelfer_containerMapValue{{ .Sfx }})
{{ $x := printf "%vmv%v" .TempVar .Rand }}{{ decLineVar $x }} {{ $x := printf "%vmv%v" .TempVar .Rand }}{{ decLineVar $x }}
if {{var "v"}} != nil { if {{if decElemKindPtr}} {{var "ms"}} && {{end}} {{var "v"}} != nil {
{{var "v"}}[{{var "mk"}}] = {{var "mv"}} {{var "v"}}[{{var "mk"}}] = {{var "mv"}}
} }
} }
r.ReadEnd()
} // else len==0: TODO: Should we clear map entries? } // else len==0: TODO: Should we clear map entries?
z.DecSendContainerState(codecSelfer_containerMapEnd{{ .Sfx }})
` `
const genDecListTmpl = ` const genDecListTmpl = `
{{var "v"}} := {{ if not isArray}}*{{ end }}{{ .Varname }} {{var "v"}} := {{if not isArray}}*{{end}}{{ .Varname }}
{{var "h"}}, {{var "l"}} := z.DecSliceHelperStart() {{/* // helper, containerLenS */}} {{var "h"}}, {{var "l"}} := z.DecSliceHelperStart() {{/* // helper, containerLenS */}}
var {{var "c"}} bool {{/* // changed */}}
var {{var "rr"}}, {{var "rl"}} int {{/* // num2read, length of slice/array/chan */}} if {{var "l"}} == 0 {
var {{var "c"}}, {{var "rt"}} bool {{/* // changed, truncated */}} {{if isSlice }}if {{var "v"}} == nil {
_, _, _ = {{var "c"}}, {{var "rt"}}, {{var "rl"}} {{var "v"}} = []{{ .Typ }}{}
{{var "rr"}} = {{var "l"}} {{var "c"}} = true
{{/* rl is NOT used. Only used for getting DecInferLen. len(r) used directly in code */}} } else if len({{var "v"}}) != 0 {
{{var "v"}} = {{var "v"}}[:0]
{{ if not isArray }}if {{var "v"}} == nil { {{var "c"}} = true
if {{var "rl"}}, {{var "rt"}} = z.DecInferLen({{var "l"}}, z.DecBasicHandle().MaxInitLen, {{ .Size }}); {{var "rt"}} { } {{end}} {{if isChan }}if {{var "v"}} == nil {
{{var "rr"}} = {{var "rl"}} {{var "v"}} = make({{ .CTyp }}, 0)
} {{var "c"}} = true
{{var "v"}} = make({{ .CTyp }}, {{var "rl"}}) } {{end}}
{{var "c"}} = true
}
{{ end }}
if {{var "l"}} == 0 { {{ if isSlice }}
if len({{var "v"}}) != 0 {
{{var "v"}} = {{var "v"}}[:0]
{{var "c"}} = true
} {{ end }}
} else if {{var "l"}} > 0 { } else if {{var "l"}} > 0 {
{{ if isChan }} {{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"}}++ { for {{var "r"}} := 0; {{var "r"}} < {{var "l"}}; {{var "r"}}++ {
{{var "h"}}.ElemContainerState({{var "r"}})
var {{var "t"}} {{ .Typ }} var {{var "t"}} {{ .Typ }}
{{ $x := printf "%st%s" .TempVar .Rand }}{{ decLineVar $x }} {{ $x := printf "%st%s" .TempVar .Rand }}{{ decLineVar $x }}
{{var "v"}} <- {{var "t"}} {{var "v"}} <- {{var "t"}}
{{ else }} }
{{ else }} var {{var "rr"}}, {{var "rl"}} int {{/* // num2read, length of slice/array/chan */}}
var {{var "rt"}} bool {{/* truncated */}}
if {{var "l"}} > cap({{var "v"}}) { if {{var "l"}} > cap({{var "v"}}) {
{{ if isArray }}z.DecArrayCannotExpand(len({{var "v"}}), {{var "l"}}) {{if isArray }}z.DecArrayCannotExpand(len({{var "v"}}), {{var "l"}})
{{ else }}{{var "rl"}}, {{var "rt"}} = z.DecInferLen({{var "l"}}, z.DecBasicHandle().MaxInitLen, {{ .Size }}) {{ else }}{{if not .Immutable }}
{{ if .Immutable }} {{var "rg"}} := len({{var "v"}}) > 0
{{var "v2"}} := {{var "v"}} {{var "v2"}} := {{var "v"}} {{end}}
{{var "v"}} = make([]{{ .Typ }}, {{var "rl"}}) {{var "rl"}}, {{var "rt"}} = z.DecInferLen({{var "l"}}, z.DecBasicHandle().MaxInitLen, {{ .Size }})
if len({{var "v"}}) > 0 { if {{var "rt"}} {
copy({{var "v"}}, {{var "v2"}}[:cap({{var "v2"}})]) if {{var "rl"}} <= cap({{var "v"}}) {
{{var "v"}} = {{var "v"}}[:{{var "rl"}}]
} else {
{{var "v"}} = make([]{{ .Typ }}, {{var "rl"}})
}
} else {
{{var "v"}} = make([]{{ .Typ }}, {{var "rl"}})
} }
{{ else }}{{var "v"}} = make([]{{ .Typ }}, {{var "rl"}}) {{var "c"}} = true
{{ end }}{{var "c"}} = true {{var "rr"}} = len({{var "v"}}) {{if not .Immutable }}
{{ end }} if {{var "rg"}} { copy({{var "v"}}, {{var "v2"}}) } {{end}} {{end}}{{/* end not Immutable, isArray */}}
{{var "rr"}} = len({{var "v"}}) } {{if isSlice }} else if {{var "l"}} != len({{var "v"}}) {
} else if {{var "l"}} != len({{var "v"}}) { {{var "v"}} = {{var "v"}}[:{{var "l"}}]
{{ if isSlice }}{{var "v"}} = {{var "v"}}[:{{var "l"}}] {{var "c"}} = true
{{var "c"}} = true {{ end }} } {{end}} {{/* end isSlice:47 */}}
}
{{var "j"}} := 0 {{var "j"}} := 0
for ; {{var "j"}} < {{var "rr"}} ; {{var "j"}}++ { 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 }} {{ $x := printf "%[1]vv%[2]v[%[1]vj%[2]v]" .TempVar .Rand }}{{ decLineVar $x }}
} }
{{ if isArray }}for ; {{var "j"}} < {{var "l"}} ; {{var "j"}}++ { {{if isArray }}for ; {{var "j"}} < {{var "l"}} ; {{var "j"}}++ {
{{var "h"}}.ElemContainerState({{var "j"}})
z.DecSwallow() z.DecSwallow()
} }
{{ else }}if {{var "rt"}} { {{/* means that it is mutable and slice */}} {{ else }}if {{var "rt"}} {
for ; {{var "j"}} < {{var "l"}} ; {{var "j"}}++ { for ; {{var "j"}} < {{var "l"}} ; {{var "j"}}++ {
{{var "v"}} = append({{var "v"}}, {{ zero}}) {{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 }} {{ $x := printf "%[1]vv%[2]v[%[1]vj%[2]v]" .TempVar .Rand }}{{ decLineVar $x }}
} }
} } {{end}} {{/* end isArray:56 */}}
{{ end }} {{end}} {{/* end isChan:16 */}}
{{ end }}{{/* closing 'if not chan' */}} } else { {{/* len < 0 */}}
} else { {{var "j"}} := 0
for {{var "j"}} := 0; !r.CheckBreak(); {{var "j"}}++ { for ; !r.CheckBreak(); {{var "j"}}++ {
if {{var "j"}} >= len({{var "v"}}) { {{if isChan }}
{{ if isArray }}z.DecArrayCannotExpand(len({{var "v"}}), {{var "j"}}+1) {{var "h"}}.ElemContainerState({{var "j"}})
{{ else if isSlice}}{{var "v"}} = append({{var "v"}}, {{zero}})// var {{var "z"}} {{ .Typ }}
{{var "c"}} = true {{ end }}
}
{{ if isChan}}
var {{var "t"}} {{ .Typ }} var {{var "t"}} {{ .Typ }}
{{ $x := printf "%st%s" .TempVar .Rand }}{{ decLineVar $x }} {{ $x := printf "%st%s" .TempVar .Rand }}{{ decLineVar $x }}
{{var "v"}} <- {{var "t"}} {{var "v"}} <- {{var "t"}}
{{ else }} {{ else }}
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}}
}
{{var "h"}}.ElemContainerState({{var "j"}})
if {{var "j"}} < len({{var "v"}}) { if {{var "j"}} < len({{var "v"}}) {
{{ $x := printf "%[1]vv%[2]v[%[1]vj%[2]v]" .TempVar .Rand }}{{ decLineVar $x }} {{ $x := printf "%[1]vv%[2]v[%[1]vj%[2]v]" .TempVar .Rand }}{{ decLineVar $x }}
} else { } else {
z.DecSwallow() z.DecSwallow()
} }
{{ end }} {{end}}
} }
{{var "h"}}.End() {{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 "c"}} = true
}{{end}}
} }
{{ if not isArray }}if {{var "c"}} { {{var "h"}}.End()
{{if not isArray }}if {{var "c"}} {
*{{ .Varname }} = {{var "v"}} *{{ .Varname }} = {{var "v"}}
}{{ end }} }{{end}}
` `
...@@ -91,7 +91,8 @@ import ( ...@@ -91,7 +91,8 @@ import (
// v3: Changes for Kubernetes: // v3: Changes for Kubernetes:
// changes in signature of some unpublished helper methods and codecgen cmdline arguments. // changes in signature of some unpublished helper methods and codecgen cmdline arguments.
// v4: Removed separator support from (en|de)cDriver, and refactored codec(gen) // v4: Removed separator support from (en|de)cDriver, and refactored codec(gen)
const GenVersion = 4 // v5: changes to support faster json decoding. Let encoder/decoder maintain state of collections.
const GenVersion = 5
const ( const (
genCodecPkg = "codec1978" genCodecPkg = "codec1978"
...@@ -110,6 +111,14 @@ const ( ...@@ -110,6 +111,14 @@ const (
genUseOneFunctionForDecStructMap = true genUseOneFunctionForDecStructMap = true
) )
type genStructMapStyle uint8
const (
genStructMapStyleConsolidated genStructMapStyle = iota
genStructMapStyleLenPrefix
genStructMapStyleCheckBreak
)
var ( var (
genAllTypesSamePkgErr = errors.New("All types must be in the same package") genAllTypesSamePkgErr = errors.New("All types must be in the same package")
genExpectArrayOrMapErr = errors.New("unexpected type. Expecting array/map/slice") genExpectArrayOrMapErr = errors.New("unexpected type. Expecting array/map/slice")
...@@ -230,10 +239,18 @@ func Gen(w io.Writer, buildTags, pkgName, uid string, useUnsafe bool, ti *TypeIn ...@@ -230,10 +239,18 @@ func Gen(w io.Writer, buildTags, pkgName, uid string, useUnsafe bool, ti *TypeIn
x.line("") x.line("")
x.line("const (") x.line("const (")
x.linef("// ----- content types ----")
x.linef("codecSelferC_UTF8%s = %v", x.xs, int64(c_UTF8)) x.linef("codecSelferC_UTF8%s = %v", x.xs, int64(c_UTF8))
x.linef("codecSelferC_RAW%s = %v", x.xs, int64(c_RAW)) x.linef("codecSelferC_RAW%s = %v", x.xs, int64(c_RAW))
x.linef("// ----- value types used ----")
x.linef("codecSelferValueTypeArray%s = %v", x.xs, int64(valueTypeArray)) x.linef("codecSelferValueTypeArray%s = %v", x.xs, int64(valueTypeArray))
x.linef("codecSelferValueTypeMap%s = %v", x.xs, int64(valueTypeMap)) x.linef("codecSelferValueTypeMap%s = %v", x.xs, int64(valueTypeMap))
x.linef("// ----- containerStateValues ----")
x.linef("codecSelfer_containerMapKey%s = %v", x.xs, int64(containerMapKey))
x.linef("codecSelfer_containerMapValue%s = %v", x.xs, int64(containerMapValue))
x.linef("codecSelfer_containerMapEnd%s = %v", x.xs, int64(containerMapEnd))
x.linef("codecSelfer_containerArrayElem%s = %v", x.xs, int64(containerArrayElem))
x.linef("codecSelfer_containerArrayEnd%s = %v", x.xs, int64(containerArrayEnd))
x.line(")") x.line(")")
x.line("var (") x.line("var (")
x.line("codecSelferBitsize" + x.xs + " = uint8(reflect.TypeOf(uint(0)).Bits())") x.line("codecSelferBitsize" + x.xs + " = uint8(reflect.TypeOf(uint(0)).Bits())")
...@@ -255,8 +272,6 @@ func Gen(w io.Writer, buildTags, pkgName, uid string, useUnsafe bool, ti *TypeIn ...@@ -255,8 +272,6 @@ func Gen(w io.Writer, buildTags, pkgName, uid string, useUnsafe bool, ti *TypeIn
x.line(`err := fmt.Errorf("codecgen version mismatch: current: %v, need %v. Re-generate file: %v", `) 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.line("panic(err)")
// x.linef(`panic(fmt.Errorf("Re-run codecgen due to version mismatch: `+
// `current: %%v, need %%v, file: %%v", %v, %sGenVersion, file))`, GenVersion, x.cpfx)
x.linef("}") x.linef("}")
x.line("if false { // reference the types, but skip this branch at build/run time") x.line("if false { // reference the types, but skip this branch at build/run time")
var n int var n int
...@@ -515,21 +530,21 @@ func (x *genRunner) selfer(encode bool) { ...@@ -515,21 +530,21 @@ func (x *genRunner) selfer(encode bool) {
x.out(fnSigPfx) x.out(fnSigPfx)
x.line(") codecDecodeSelfFromMap(l int, d *" + x.cpfx + "Decoder) {") x.line(") codecDecodeSelfFromMap(l int, d *" + x.cpfx + "Decoder) {")
x.genRequiredMethodVars(false) x.genRequiredMethodVars(false)
x.decStructMap(genTopLevelVarName, "l", reflect.ValueOf(t0).Pointer(), t0, 0) x.decStructMap(genTopLevelVarName, "l", reflect.ValueOf(t0).Pointer(), t0, genStructMapStyleConsolidated)
x.line("}") x.line("}")
x.line("") x.line("")
} else { } else {
x.out(fnSigPfx) x.out(fnSigPfx)
x.line(") codecDecodeSelfFromMapLenPrefix(l int, d *" + x.cpfx + "Decoder) {") x.line(") codecDecodeSelfFromMapLenPrefix(l int, d *" + x.cpfx + "Decoder) {")
x.genRequiredMethodVars(false) x.genRequiredMethodVars(false)
x.decStructMap(genTopLevelVarName, "l", reflect.ValueOf(t0).Pointer(), t0, 1) x.decStructMap(genTopLevelVarName, "l", reflect.ValueOf(t0).Pointer(), t0, genStructMapStyleLenPrefix)
x.line("}") x.line("}")
x.line("") x.line("")
x.out(fnSigPfx) x.out(fnSigPfx)
x.line(") codecDecodeSelfFromMapCheckBreak(l int, d *" + x.cpfx + "Decoder) {") x.line(") codecDecodeSelfFromMapCheckBreak(l int, d *" + x.cpfx + "Decoder) {")
x.genRequiredMethodVars(false) x.genRequiredMethodVars(false)
x.decStructMap(genTopLevelVarName, "l", reflect.ValueOf(t0).Pointer(), t0, 2) x.decStructMap(genTopLevelVarName, "l", reflect.ValueOf(t0).Pointer(), t0, genStructMapStyleCheckBreak)
x.line("}") x.line("}")
x.line("") x.line("")
} }
...@@ -548,10 +563,8 @@ func (x *genRunner) selfer(encode bool) { ...@@ -548,10 +563,8 @@ func (x *genRunner) selfer(encode bool) {
func (x *genRunner) xtraSM(varname string, encode bool, t reflect.Type) { func (x *genRunner) xtraSM(varname string, encode bool, t reflect.Type) {
if encode { if encode {
x.linef("h.enc%s((%s%s)(%s), e)", x.genMethodNameT(t), x.arr2str(t, "*"), x.genTypeName(t), varname) x.linef("h.enc%s((%s%s)(%s), e)", x.genMethodNameT(t), x.arr2str(t, "*"), x.genTypeName(t), varname)
// x.line("h.enc" + x.genMethodNameT(t) + "(" + x.genTypeName(t) + "(" + varname + "), e)")
} else { } else {
x.linef("h.dec%s((*%s)(%s), d)", x.genMethodNameT(t), x.genTypeName(t), varname) x.linef("h.dec%s((*%s)(%s), d)", x.genMethodNameT(t), x.genTypeName(t), varname)
// x.line("h.dec" + x.genMethodNameT(t) + "((*" + x.genTypeName(t) + ")(" + varname + "), d)")
} }
if _, ok := x.tm[t]; !ok { if _, ok := x.tm[t]; !ok {
x.tm[t] = struct{}{} x.tm[t] = struct{}{}
...@@ -815,12 +828,14 @@ func (x *genRunner) encStruct(varname string, rtid uintptr, t reflect.Type) { ...@@ -815,12 +828,14 @@ func (x *genRunner) encStruct(varname string, rtid uintptr, t reflect.Type) {
} }
x.linef("%s[%v] = %s", numfieldsvar, j, omitline) x.linef("%s[%v] = %s", numfieldsvar, j, omitline)
} }
x.linef("var %snn%s int", genTempVarPfx, i)
x.linef("if %s || %s {", ti2arrayvar, struct2arrvar) // if ti.toArray { x.linef("if %s || %s {", ti2arrayvar, struct2arrvar) // if ti.toArray {
x.line("r.EncodeArrayStart(" + strconv.FormatInt(int64(len(tisfi)), 10) + ")") x.line("r.EncodeArrayStart(" + strconv.FormatInt(int64(len(tisfi)), 10) + ")")
x.linef("} else {") // if not ti.toArray x.linef("} else {") // if not ti.toArray
x.linef("var %snn%s int = %v", genTempVarPfx, i, nn) x.linef("%snn%s = %v", genTempVarPfx, i, nn)
x.linef("for _, b := range %s { if b { %snn%s++ } }", numfieldsvar, genTempVarPfx, i) x.linef("for _, b := range %s { if b { %snn%s++ } }", numfieldsvar, genTempVarPfx, i)
x.linef("r.EncodeMapStart(%snn%s)", 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) + ")") // x.line("r.EncodeMapStart(" + strconv.FormatInt(int64(len(tisfi)), 10) + ")")
x.line("}") // close if not StructToArray x.line("}") // close if not StructToArray
...@@ -864,11 +879,9 @@ func (x *genRunner) encStruct(varname string, rtid uintptr, t reflect.Type) { ...@@ -864,11 +879,9 @@ func (x *genRunner) encStruct(varname string, rtid uintptr, t reflect.Type) {
if labelUsed { if labelUsed {
x.line("if " + isNilVarName + " { r.EncodeNil() } else { ") x.line("if " + isNilVarName + " { r.EncodeNil() } else { ")
} }
x.linef("z.EncSendContainerState(codecSelfer_containerArrayElem%s)", x.xs)
if si.omitEmpty { if si.omitEmpty {
x.linef("if %s[%v] {", numfieldsvar, j) x.linef("if %s[%v] {", numfieldsvar, j)
// omitEmptyVarNameX := genTempVarPfx + "ov" + i
// x.line("var " + omitEmptyVarNameX + " " + x.genTypeName(t2.Type))
// x.encVar(omitEmptyVarNameX, t2.Type)
} }
x.encVar(varname+"."+t2.Name, t2.Type) x.encVar(varname+"."+t2.Name, t2.Type)
if si.omitEmpty { if si.omitEmpty {
...@@ -879,21 +892,15 @@ func (x *genRunner) encStruct(varname string, rtid uintptr, t reflect.Type) { ...@@ -879,21 +892,15 @@ func (x *genRunner) encStruct(varname string, rtid uintptr, t reflect.Type) {
if labelUsed { if labelUsed {
x.line("}") x.line("}")
} }
x.linef("} else {") // if not ti.toArray x.linef("} else {") // if not ti.toArray
// omitEmptyVar := genTempVarPfx + "x" + i + t2.Name
// x.line("const " + omitEmptyVar + " bool = " + strconv.FormatBool(si.omitEmpty))
// doOmitEmpty := si.omitEmpty && t2.Type.Kind() != reflect.Struct
if si.omitEmpty { if si.omitEmpty {
x.linef("if %s[%v] {", numfieldsvar, j) x.linef("if %s[%v] {", numfieldsvar, j)
// x.linef(`println("Encoding field: %v")`, j)
// x.out("if ")
// if labelUsed {
// x.out("!" + isNilVarName + " && ")
// }
// x.line(varname + "." + t2.Name + " != " + genZeroValueR(t2.Type, x.tc) + " {")
} }
// x.line("r.EncodeString(codecSelferC_UTF8" + x.xs + ", string(\"" + t2.Name + "\"))") x.linef("z.EncSendContainerState(codecSelfer_containerMapKey%s)", x.xs)
x.line("r.EncodeString(codecSelferC_UTF8" + x.xs + ", string(\"" + si.encName + "\"))") x.line("r.EncodeString(codecSelferC_UTF8" + x.xs + ", string(\"" + si.encName + "\"))")
x.linef("z.EncSendContainerState(codecSelfer_containerMapValue%s)", x.xs)
if labelUsed { if labelUsed {
x.line("if " + isNilVarName + " { r.EncodeNil() } else { ") x.line("if " + isNilVarName + " { r.EncodeNil() } else { ")
x.encVar(varname+"."+t2.Name, t2.Type) x.encVar(varname+"."+t2.Name, t2.Type)
...@@ -906,9 +913,12 @@ func (x *genRunner) encStruct(varname string, rtid uintptr, t reflect.Type) { ...@@ -906,9 +913,12 @@ func (x *genRunner) encStruct(varname string, rtid uintptr, t reflect.Type) {
} }
x.linef("} ") // end if/else ti.toArray x.linef("} ") // end if/else ti.toArray
} }
x.line("if " + sepVarname + " {") x.linef("if %s || %s {", ti2arrayvar, struct2arrvar) // if ti.toArray {
x.line("r.EncodeEnd()") x.linef("z.EncSendContainerState(codecSelfer_containerArrayEnd%s)", x.xs)
x.line("} else {")
x.linef("z.EncSendContainerState(codecSelfer_containerMapEnd%s)", x.xs)
x.line("}") x.line("}")
} }
func (x *genRunner) encListFallback(varname string, t reflect.Type) { func (x *genRunner) encListFallback(varname string, t reflect.Type) {
...@@ -917,14 +927,16 @@ func (x *genRunner) encListFallback(varname string, t reflect.Type) { ...@@ -917,14 +927,16 @@ func (x *genRunner) encListFallback(varname string, t reflect.Type) {
x.line("r.EncodeArrayStart(len(" + varname + "))") x.line("r.EncodeArrayStart(len(" + varname + "))")
if t.Kind() == reflect.Chan { 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("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.linef("%sv%s := <-%s", g, i, varname) x.linef("%sv%s := <-%s", g, i, varname)
} else { } else {
// x.linef("for %si%s, %sv%s := range %s {", genTempVarPfx, i, genTempVarPfx, i, varname) // 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("for _, %sv%s := range %s {", genTempVarPfx, i, varname)
x.linef("z.EncSendContainerState(codecSelfer_containerArrayElem%s)", x.xs)
} }
x.encVar(genTempVarPfx+"v"+i, t.Elem()) x.encVar(genTempVarPfx+"v"+i, t.Elem())
x.line("}") x.line("}")
x.line("r.EncodeEnd()") x.linef("z.EncSendContainerState(codecSelfer_containerArrayEnd%s)", x.xs)
} }
func (x *genRunner) encMapFallback(varname string, t reflect.Type) { func (x *genRunner) encMapFallback(varname string, t reflect.Type) {
...@@ -933,10 +945,12 @@ func (x *genRunner) encMapFallback(varname string, t reflect.Type) { ...@@ -933,10 +945,12 @@ func (x *genRunner) encMapFallback(varname string, t reflect.Type) {
x.line("r.EncodeMapStart(len(" + varname + "))") x.line("r.EncodeMapStart(len(" + varname + "))")
x.linef("for %sk%s, %sv%s := range %s {", genTempVarPfx, i, genTempVarPfx, i, 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.line("for " + genTempVarPfx + "k" + i + ", " + genTempVarPfx + "v" + i + " := range " + varname + " {")
x.linef("z.EncSendContainerState(codecSelfer_containerMapKey%s)", x.xs)
x.encVar(genTempVarPfx+"k"+i, t.Key()) x.encVar(genTempVarPfx+"k"+i, t.Key())
x.linef("z.EncSendContainerState(codecSelfer_containerMapValue%s)", x.xs)
x.encVar(genTempVarPfx+"v"+i, t.Elem()) x.encVar(genTempVarPfx+"v"+i, t.Elem())
x.line("}") x.line("}")
x.line("r.EncodeEnd()") x.linef("z.EncSendContainerState(codecSelfer_containerMapEnd%s)", x.xs)
} }
func (x *genRunner) decVar(varname string, t reflect.Type, canBeNil bool) { func (x *genRunner) decVar(varname string, t reflect.Type, canBeNil bool) {
...@@ -954,8 +968,6 @@ func (x *genRunner) decVar(varname string, t reflect.Type, canBeNil bool) { ...@@ -954,8 +968,6 @@ func (x *genRunner) decVar(varname string, t reflect.Type, canBeNil bool) {
x.line("if r.TryDecodeAsNil() {") x.line("if r.TryDecodeAsNil() {")
if t.Kind() == reflect.Ptr { if t.Kind() == reflect.Ptr {
x.line("if " + varname + " != nil { ") x.line("if " + varname + " != nil { ")
// x.line("var " + genTempVarPfx + i + " " + x.genTypeName(t.Elem()))
// x.line("*" + varname + " = " + genTempVarPfx + i)
// if varname is a field of a struct (has a dot in it), // if varname is a field of a struct (has a dot in it),
// then just set it to nil // then just set it to nil
...@@ -964,12 +976,8 @@ func (x *genRunner) decVar(varname string, t reflect.Type, canBeNil bool) { ...@@ -964,12 +976,8 @@ func (x *genRunner) decVar(varname string, t reflect.Type, canBeNil bool) {
} else { } else {
x.line("*" + varname + " = " + x.genZeroValueR(t.Elem())) x.line("*" + varname + " = " + x.genZeroValueR(t.Elem()))
} }
// x.line("*" + varname + " = nil")
x.line("}") x.line("}")
} else { } else {
// x.line("var " + genTempVarPfx + i + " " + x.genTypeName(t))
// x.line(varname + " = " + genTempVarPfx + i)
x.line(varname + " = " + x.genZeroValueR(t)) x.line(varname + " = " + x.genZeroValueR(t))
} }
x.line("} else {") x.line("} else {")
...@@ -1149,8 +1157,6 @@ func (x *genRunner) dec(varname string, t reflect.Type) { ...@@ -1149,8 +1157,6 @@ func (x *genRunner) dec(varname string, t reflect.Type) {
} else if fastpathAV.index(rtid) != -1 { } else if fastpathAV.index(rtid) != -1 {
g := x.newGenV(t) 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 + ", false, d)")
// x.line("z." + g.MethodNamePfx("Dec", false) + "(" + varname + ")")
// x.line(g.FastpathName(false) + "(" + varname + ", d)")
} else { } else {
x.xtraSM(varname, false, t) x.xtraSM(varname, false, t)
// x.decListFallback(varname, rtid, false, t) // x.decListFallback(varname, rtid, false, t)
...@@ -1163,8 +1169,6 @@ func (x *genRunner) dec(varname string, t reflect.Type) { ...@@ -1163,8 +1169,6 @@ func (x *genRunner) dec(varname string, t reflect.Type) {
if fastpathAV.index(rtid) != -1 { if fastpathAV.index(rtid) != -1 {
g := x.newGenV(t) 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 + ", false, d)")
// x.line("z." + g.MethodNamePfx("Dec", false) + "(" + varname + ")")
// x.line(g.FastpathName(false) + "(" + varname + ", d)")
} else { } else {
x.xtraSM(varname, false, t) x.xtraSM(varname, false, t)
// x.decMapFallback(varname, rtid, t) // x.decMapFallback(varname, rtid, t)
...@@ -1294,6 +1298,7 @@ func (x *genRunner) decListFallback(varname string, rtid uintptr, t reflect.Type ...@@ -1294,6 +1298,7 @@ func (x *genRunner) decListFallback(varname string, rtid uintptr, t reflect.Type
func (x *genRunner) decMapFallback(varname string, rtid uintptr, t reflect.Type) { func (x *genRunner) decMapFallback(varname string, rtid uintptr, t reflect.Type) {
type tstruc struct { type tstruc struct {
TempVar string TempVar string
Sfx string
Rand string Rand string
Varname string Varname string
KTyp string KTyp string
...@@ -1303,7 +1308,7 @@ func (x *genRunner) decMapFallback(varname string, rtid uintptr, t reflect.Type) ...@@ -1303,7 +1308,7 @@ func (x *genRunner) decMapFallback(varname string, rtid uintptr, t reflect.Type)
telem := t.Elem() telem := t.Elem()
tkey := t.Key() tkey := t.Key()
ts := tstruc{ ts := tstruc{
genTempVarPfx, x.varsfx(), varname, x.genTypeName(tkey), genTempVarPfx, x.xs, x.varsfx(), varname, x.genTypeName(tkey),
x.genTypeName(telem), int(telem.Size() + tkey.Size()), x.genTypeName(telem), int(telem.Size() + tkey.Size()),
} }
...@@ -1359,6 +1364,7 @@ func (x *genRunner) decStructMapSwitch(kName string, varname string, rtid uintpt ...@@ -1359,6 +1364,7 @@ func (x *genRunner) decStructMapSwitch(kName string, varname string, rtid uintpt
if si.i != -1 { if si.i != -1 {
t2 = t.Field(int(si.i)) t2 = t.Field(int(si.i))
} else { } else {
//we must accomodate anonymous fields, where the embedded field is a nil pointer in the value.
// t2 = t.FieldByIndex(si.is) // t2 = t.FieldByIndex(si.is)
t2typ := t t2typ := t
varname3 := varname varname3 := varname
...@@ -1370,8 +1376,7 @@ func (x *genRunner) decStructMapSwitch(kName string, varname string, rtid uintpt ...@@ -1370,8 +1376,7 @@ func (x *genRunner) decStructMapSwitch(kName string, varname string, rtid uintpt
t2typ = t2.Type t2typ = t2.Type
varname3 = varname3 + "." + t2.Name varname3 = varname3 + "." + t2.Name
if t2typ.Kind() == reflect.Ptr { if t2typ.Kind() == reflect.Ptr {
x.line("if " + varname3 + " == nil {" + x.linef("if %s == nil { %s = new(%s) }", varname3, varname3, x.genTypeName(t2typ.Elem()))
varname3 + " = new(" + x.genTypeName(t2typ.Elem()) + ") }")
} }
} }
} }
...@@ -1380,11 +1385,10 @@ func (x *genRunner) decStructMapSwitch(kName string, varname string, rtid uintpt ...@@ -1380,11 +1385,10 @@ func (x *genRunner) decStructMapSwitch(kName string, varname string, rtid uintpt
x.line("default:") x.line("default:")
// pass the slice here, so that the string will not escape, and maybe save allocation // pass the slice here, so that the string will not escape, and maybe save allocation
x.line("z.DecStructFieldNotFound(-1, " + kName + ")") x.line("z.DecStructFieldNotFound(-1, " + kName + ")")
// x.line("z.DecStructFieldNotFoundB(" + kName + "Slc)")
x.line("} // end switch " + kName) x.line("} // end switch " + kName)
} }
func (x *genRunner) decStructMap(varname, lenvarname string, rtid uintptr, t reflect.Type, style uint8) { func (x *genRunner) decStructMap(varname, lenvarname string, rtid uintptr, t reflect.Type, style genStructMapStyle) {
tpfx := genTempVarPfx tpfx := genTempVarPfx
i := x.varsfx() i := x.varsfx()
kName := tpfx + "s" + i kName := tpfx + "s" + i
...@@ -1406,14 +1410,11 @@ func (x *genRunner) decStructMap(varname, lenvarname string, rtid uintptr, t ref ...@@ -1406,14 +1410,11 @@ func (x *genRunner) decStructMap(varname, lenvarname string, rtid uintptr, t ref
x.line("var " + kName + "Slc = z.DecScratchBuffer() // default slice to decode into") x.line("var " + kName + "Slc = z.DecScratchBuffer() // default slice to decode into")
// x.line("var " + kName + " string // default string to decode into")
// x.line("_ = " + kName)
x.line("_ = " + kName + "Slc") x.line("_ = " + kName + "Slc")
// x.linef("var %sb%s bool", tpfx, i) // break
switch style { switch style {
case 1: case genStructMapStyleLenPrefix:
x.linef("for %sj%s := 0; %sj%s < %s; %sj%s++ {", tpfx, i, tpfx, i, lenvarname, tpfx, i) x.linef("for %sj%s := 0; %sj%s < %s; %sj%s++ {", tpfx, i, tpfx, i, lenvarname, tpfx, i)
case 2: case genStructMapStyleCheckBreak:
x.linef("for %sj%s := 0; !r.CheckBreak(); %sj%s++ {", tpfx, i, tpfx, i) x.linef("for %sj%s := 0; !r.CheckBreak(); %sj%s++ {", tpfx, i, tpfx, i)
default: // 0, otherwise. default: // 0, otherwise.
x.linef("var %shl%s bool = %s >= 0", tpfx, i, lenvarname) // has length x.linef("var %shl%s bool = %s >= 0", tpfx, i, lenvarname) // has length
...@@ -1421,11 +1422,9 @@ func (x *genRunner) decStructMap(varname, lenvarname string, rtid uintptr, t ref ...@@ -1421,11 +1422,9 @@ 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.linef("if %shl%s { if %sj%s >= %s { break }", tpfx, i, tpfx, i, lenvarname)
x.line("} else { if r.CheckBreak() { break }; }") x.line("} else { if r.CheckBreak() { break }; }")
} }
// x.line(kName + " = z.ReadStringAsBytes(" + kName + ")") x.linef("z.DecSendContainerState(codecSelfer_containerMapKey%s)", x.xs)
// x.line(kName + " = z.ReadString()")
x.line(kName + "Slc = r.DecodeBytes(" + kName + "Slc, true, true)") x.line(kName + "Slc = r.DecodeBytes(" + kName + "Slc, true, true)")
// let string be scoped to this loop alone, so it doesn't escape. // let string be scoped to this loop alone, so it doesn't escape.
// x.line(kName + " := " + x.cpfx + "GenBytesToStringRO(" + kName + "Slc)")
if x.unsafe { if x.unsafe {
x.line(kName + "SlcHdr := codecSelferUnsafeString" + x.xs + "{uintptr(unsafe.Pointer(&" + x.line(kName + "SlcHdr := codecSelferUnsafeString" + x.xs + "{uintptr(unsafe.Pointer(&" +
kName + "Slc[0])), len(" + kName + "Slc)}") kName + "Slc[0])), len(" + kName + "Slc)}")
...@@ -1433,16 +1432,11 @@ func (x *genRunner) decStructMap(varname, lenvarname string, rtid uintptr, t ref ...@@ -1433,16 +1432,11 @@ func (x *genRunner) decStructMap(varname, lenvarname string, rtid uintptr, t ref
} else { } else {
x.line(kName + " := string(" + kName + "Slc)") x.line(kName + " := string(" + kName + "Slc)")
} }
x.linef("z.DecSendContainerState(codecSelfer_containerMapValue%s)", x.xs)
x.decStructMapSwitch(kName, varname, rtid, t) x.decStructMapSwitch(kName, varname, rtid, t)
x.line("} // end for " + tpfx + "j" + i) x.line("} // end for " + tpfx + "j" + i)
switch style { x.linef("z.DecSendContainerState(codecSelfer_containerMapEnd%s)", x.xs)
case 1:
case 2:
x.line("r.ReadEnd()")
default:
x.linef("if !%shl%s { r.ReadEnd() }", tpfx, i)
}
} }
func (x *genRunner) decStructArray(varname, lenvarname, breakString string, rtid uintptr, t reflect.Type) { func (x *genRunner) decStructArray(varname, lenvarname, breakString string, rtid uintptr, t reflect.Type) {
...@@ -1451,25 +1445,37 @@ func (x *genRunner) decStructArray(varname, lenvarname, breakString string, rtid ...@@ -1451,25 +1445,37 @@ func (x *genRunner) decStructArray(varname, lenvarname, breakString string, rtid
ti := x.ti.get(rtid, t) ti := x.ti.get(rtid, t)
tisfi := ti.sfip // always use sequence from file. decStruct expects same thing. tisfi := ti.sfip // always use sequence from file. decStruct expects same thing.
x.linef("var %sj%s int", tpfx, i) x.linef("var %sj%s int", tpfx, i)
x.linef("var %sb%s bool", tpfx, i) // break x.linef("var %sb%s bool", tpfx, i) // break
// x.linef("var %sl%s := r.ReadArrayStart()", tpfx, i)
x.linef("var %shl%s bool = %s >= 0", tpfx, i, lenvarname) // has length x.linef("var %shl%s bool = %s >= 0", tpfx, i, lenvarname) // has length
for _, si := range tisfi { for _, si := range tisfi {
var t2 reflect.StructField var t2 reflect.StructField
if si.i != -1 { if si.i != -1 {
t2 = t.Field(int(si.i)) t2 = t.Field(int(si.i))
} else { } else {
t2 = t.FieldByIndex(si.is) //we must accomodate 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 t2typ.Kind() == reflect.Ptr {
t2typ = t2typ.Elem()
}
t2 = t2typ.Field(ix)
t2typ = t2.Type
varname3 = varname3 + "." + t2.Name
if t2typ.Kind() == reflect.Ptr {
x.linef("if %s == nil { %s = new(%s) }", varname3, varname3, x.genTypeName(t2typ.Elem()))
}
}
} }
x.linef("%sj%s++; if %shl%s { %sb%s = %sj%s > %s } else { %sb%s = r.CheckBreak() }", 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, tpfx, i, tpfx, i,
tpfx, i, lenvarname, tpfx, i) tpfx, i, lenvarname, tpfx, i)
// x.line("if " + tpfx + "j" + i + "++; " + tpfx + "j" + x.linef("if %sb%s { z.DecSendContainerState(codecSelfer_containerArrayEnd%s); %s }",
// i + " <= " + tpfx + "l" + i + " {") tpfx, i, x.xs, breakString)
x.linef("if %sb%s { r.ReadEnd(); %s }", tpfx, i, breakString) x.linef("z.DecSendContainerState(codecSelfer_containerArrayElem%s)", x.xs)
x.decVar(varname+"."+t2.Name, t2.Type, true) x.decVar(varname+"."+t2.Name, t2.Type, true)
// x.line("} // end if " + tpfx + "j" + i + " <= " + tpfx + "l" + i)
} }
// read remaining values and throw away. // read remaining values and throw away.
x.line("for {") x.line("for {")
...@@ -1477,19 +1483,20 @@ func (x *genRunner) decStructArray(varname, lenvarname, breakString string, rtid ...@@ -1477,19 +1483,20 @@ func (x *genRunner) decStructArray(varname, lenvarname, breakString string, rtid
tpfx, i, tpfx, i, tpfx, i, tpfx, i, tpfx, i, tpfx, i,
tpfx, i, lenvarname, tpfx, i) tpfx, i, lenvarname, tpfx, i)
x.linef("if %sb%s { break }", tpfx, i) x.linef("if %sb%s { break }", tpfx, i)
x.linef("z.DecSendContainerState(codecSelfer_containerArrayElem%s)", x.xs)
x.linef(`z.DecStructFieldNotFound(%sj%s - 1, "")`, tpfx, i) x.linef(`z.DecStructFieldNotFound(%sj%s - 1, "")`, tpfx, i)
x.line("}") x.line("}")
x.line("r.ReadEnd()") x.linef("z.DecSendContainerState(codecSelfer_containerArrayEnd%s)", x.xs)
} }
func (x *genRunner) decStruct(varname string, rtid uintptr, t reflect.Type) { func (x *genRunner) decStruct(varname string, rtid uintptr, t reflect.Type) {
// if container is map // if container is map
// x.line("if z.DecContainerIsMap() { ")
i := x.varsfx() i := x.varsfx()
x.line("if r.IsContainerType(codecSelferValueTypeMap" + x.xs + ") {") x.linef("%sct%s := r.ContainerType()", genTempVarPfx, i)
x.linef("if %sct%s == codecSelferValueTypeMap%s {", genTempVarPfx, i, x.xs)
x.line(genTempVarPfx + "l" + i + " := r.ReadMapStart()") x.line(genTempVarPfx + "l" + i + " := r.ReadMapStart()")
x.linef("if %sl%s == 0 {", genTempVarPfx, i) x.linef("if %sl%s == 0 {", genTempVarPfx, i)
x.line("r.ReadEnd()") x.linef("z.DecSendContainerState(codecSelfer_containerMapEnd%s)", x.xs)
if genUseOneFunctionForDecStructMap { if genUseOneFunctionForDecStructMap {
x.line("} else { ") x.line("} else { ")
x.linef("x.codecDecodeSelfFromMap(%sl%s, d)", genTempVarPfx, i) x.linef("x.codecDecodeSelfFromMap(%sl%s, d)", genTempVarPfx, i)
...@@ -1502,18 +1509,16 @@ func (x *genRunner) decStruct(varname string, rtid uintptr, t reflect.Type) { ...@@ -1502,18 +1509,16 @@ func (x *genRunner) decStruct(varname string, rtid uintptr, t reflect.Type) {
x.line("}") x.line("}")
// else if container is array // else if container is array
// x.line("} else if z.DecContainerIsArray() { ") x.linef("} else if %sct%s == codecSelferValueTypeArray%s {", genTempVarPfx, i, x.xs)
x.line("} else if r.IsContainerType(codecSelferValueTypeArray" + x.xs + ") {")
x.line(genTempVarPfx + "l" + i + " := r.ReadArrayStart()") x.line(genTempVarPfx + "l" + i + " := r.ReadArrayStart()")
x.linef("if %sl%s == 0 {", genTempVarPfx, i) x.linef("if %sl%s == 0 {", genTempVarPfx, i)
x.line("r.ReadEnd()") x.linef("z.DecSendContainerState(codecSelfer_containerArrayEnd%s)", x.xs)
x.line("} else { ") x.line("} else { ")
x.linef("x.codecDecodeSelfFromArray(%sl%s, d)", genTempVarPfx, i) x.linef("x.codecDecodeSelfFromArray(%sl%s, d)", genTempVarPfx, i)
x.line("}") x.line("}")
// else panic // else panic
x.line("} else { ") x.line("} else { ")
x.line("panic(codecSelferOnlyMapOrArrayEncodeToStructErr" + x.xs + ")") x.line("panic(codecSelferOnlyMapOrArrayEncodeToStructErr" + x.xs + ")")
// x.line("panic(`only encoded map or array can be decoded into a struct`)")
x.line("} ") x.line("} ")
} }
...@@ -1849,10 +1854,6 @@ func genInternalInit() { ...@@ -1849,10 +1854,6 @@ func genInternalInit() {
"float64": 8, "float64": 8,
"bool": 1, "bool": 1,
} }
// mapvaltypes2 := make(map[string]bool)
// for _, s := range mapvaltypes {
// mapvaltypes2[s] = true
// }
var gt genInternal var gt genInternal
// For each slice or map type, there must be a (symetrical) Encode and Decode fast-path function // For each slice or map type, there must be a (symetrical) Encode and Decode fast-path function
......
...@@ -112,8 +112,6 @@ import ( ...@@ -112,8 +112,6 @@ import (
"strings" "strings"
"sync" "sync"
"time" "time"
"unicode"
"unicode/utf8"
) )
const ( const (
...@@ -194,14 +192,6 @@ const ( ...@@ -194,14 +192,6 @@ const (
type seqType uint8 type seqType uint8
// mirror json.Marshaler and json.Unmarshaler here, so we don't import the encoding/json package
type jsonMarshaler interface {
MarshalJSON() ([]byte, error)
}
type jsonUnmarshaler interface {
UnmarshalJSON([]byte) error
}
const ( const (
_ seqType = iota _ seqType = iota
seqTypeArray seqTypeArray
...@@ -209,13 +199,43 @@ const ( ...@@ -209,13 +199,43 @@ const (
seqTypeChan seqTypeChan
) )
// note that containerMapStart and containerArraySend are not sent.
// This is because the ReadXXXStart and EncodeXXXStart already does these.
type containerState uint8
const (
_ containerState = iota
containerMapStart // slot left open, since Driver method already covers it
containerMapKey
containerMapValue
containerMapEnd
containerArrayStart // slot left open, since Driver methods already cover it
containerArrayElem
containerArrayEnd
)
type containerStateRecv interface {
sendContainerState(containerState)
}
// mirror json.Marshaler and json.Unmarshaler here,
// so we don't import the encoding/json package
type jsonMarshaler interface {
MarshalJSON() ([]byte, error)
}
type jsonUnmarshaler interface {
UnmarshalJSON([]byte) error
}
var ( var (
bigen = binary.BigEndian bigen = binary.BigEndian
structInfoFieldName = "_struct" structInfoFieldName = "_struct"
// mapStrIntfTyp = reflect.TypeOf(map[string]interface{}(nil)) mapStrIntfTyp = reflect.TypeOf(map[string]interface{}(nil))
intfSliceTyp = reflect.TypeOf([]interface{}(nil)) mapIntfIntfTyp = reflect.TypeOf(map[interface{}]interface{}(nil))
intfTyp = intfSliceTyp.Elem() intfSliceTyp = reflect.TypeOf([]interface{}(nil))
intfTyp = intfSliceTyp.Elem()
stringTyp = reflect.TypeOf("") stringTyp = reflect.TypeOf("")
timeTyp = reflect.TypeOf(time.Time{}) timeTyp = reflect.TypeOf(time.Time{})
...@@ -241,6 +261,9 @@ var ( ...@@ -241,6 +261,9 @@ var (
timeTypId = reflect.ValueOf(timeTyp).Pointer() timeTypId = reflect.ValueOf(timeTyp).Pointer()
stringTypId = reflect.ValueOf(stringTyp).Pointer() stringTypId = reflect.ValueOf(stringTyp).Pointer()
mapStrIntfTypId = reflect.ValueOf(mapStrIntfTyp).Pointer()
mapIntfIntfTypId = reflect.ValueOf(mapIntfIntfTyp).Pointer()
intfSliceTypId = reflect.ValueOf(intfSliceTyp).Pointer()
// mapBySliceTypId = reflect.ValueOf(mapBySliceTyp).Pointer() // mapBySliceTypId = reflect.ValueOf(mapBySliceTyp).Pointer()
intBitsize uint8 = uint8(reflect.TypeOf(int(0)).Bits()) intBitsize uint8 = uint8(reflect.TypeOf(int(0)).Bits())
...@@ -283,7 +306,7 @@ type MapBySlice interface { ...@@ -283,7 +306,7 @@ type MapBySlice interface {
type BasicHandle struct { type BasicHandle struct {
// TypeInfos is used to get the type info for any type. // TypeInfos is used to get the type info for any type.
// //
// If not configure, the default TypeInfos is used, which uses struct tag keys: codec, json // If not configured, the default TypeInfos is used, which uses struct tag keys: codec, json
TypeInfos *TypeInfos TypeInfos *TypeInfos
extHandle extHandle
...@@ -332,6 +355,8 @@ type RawExt struct { ...@@ -332,6 +355,8 @@ type RawExt struct {
// It is used by codecs (e.g. binc, msgpack, simple) which do custom serialization of the types. // It is used by codecs (e.g. binc, msgpack, simple) which do custom serialization of the types.
type BytesExt interface { type BytesExt interface {
// WriteExt converts a value to a []byte. // WriteExt converts a value to a []byte.
//
// Note: v *may* be a pointer to the extension type, if the extension type was a struct or array.
WriteExt(v interface{}) []byte WriteExt(v interface{}) []byte
// ReadExt updates a value from a []byte. // ReadExt updates a value from a []byte.
...@@ -344,6 +369,8 @@ type BytesExt interface { ...@@ -344,6 +369,8 @@ type BytesExt interface {
// It is used by codecs (e.g. cbor, json) which use the format to do custom serialization of the types. // It is used by codecs (e.g. cbor, json) which use the format to do custom serialization of the types.
type InterfaceExt interface { type InterfaceExt interface {
// ConvertExt converts a value into a simpler interface for easy encoding e.g. convert time.Time to int64. // ConvertExt converts a value into a simpler interface for easy encoding e.g. convert time.Time to int64.
//
// Note: v *may* be a pointer to the extension type, if the extension type was a struct or array.
ConvertExt(v interface{}) interface{} ConvertExt(v interface{}) interface{}
// UpdateExt updates a value from a simpler interface for easy decoding e.g. convert int64 to time.Time. // UpdateExt updates a value from a simpler interface for easy decoding e.g. convert int64 to time.Time.
...@@ -363,7 +390,6 @@ type addExtWrapper struct { ...@@ -363,7 +390,6 @@ type addExtWrapper struct {
} }
func (x addExtWrapper) WriteExt(v interface{}) []byte { func (x addExtWrapper) WriteExt(v interface{}) []byte {
// fmt.Printf(">>>>>>>>>> WriteExt: %T, %v\n", v, v)
bs, err := x.encFn(reflect.ValueOf(v)) bs, err := x.encFn(reflect.ValueOf(v))
if err != nil { if err != nil {
panic(err) panic(err)
...@@ -372,7 +398,6 @@ func (x addExtWrapper) WriteExt(v interface{}) []byte { ...@@ -372,7 +398,6 @@ func (x addExtWrapper) WriteExt(v interface{}) []byte {
} }
func (x addExtWrapper) ReadExt(v interface{}, bs []byte) { func (x addExtWrapper) ReadExt(v interface{}, bs []byte) {
// fmt.Printf(">>>>>>>>>> ReadExt: %T, %v\n", v, v)
if err := x.decFn(reflect.ValueOf(v), bs); err != nil { if err := x.decFn(reflect.ValueOf(v), bs); err != nil {
panic(err) panic(err)
} }
...@@ -474,7 +499,7 @@ type extTypeTagFn struct { ...@@ -474,7 +499,7 @@ type extTypeTagFn struct {
ext Ext ext Ext
} }
type extHandle []*extTypeTagFn type extHandle []extTypeTagFn
// DEPRECATED: Use SetBytesExt or SetInterfaceExt on the Handle instead. // DEPRECATED: Use SetBytesExt or SetInterfaceExt on the Handle instead.
// //
...@@ -513,12 +538,17 @@ func (o *extHandle) SetExt(rt reflect.Type, tag uint64, ext Ext) (err error) { ...@@ -513,12 +538,17 @@ func (o *extHandle) SetExt(rt reflect.Type, tag uint64, ext Ext) (err error) {
} }
} }
*o = append(*o, &extTypeTagFn{rtid, rt, tag, ext}) if *o == nil {
*o = make([]extTypeTagFn, 0, 4)
}
*o = append(*o, extTypeTagFn{rtid, rt, tag, ext})
return return
} }
func (o extHandle) getExt(rtid uintptr) *extTypeTagFn { func (o extHandle) getExt(rtid uintptr) *extTypeTagFn {
for _, v := range o { var v *extTypeTagFn
for i := range o {
v = &o[i]
if v.rtid == rtid { if v.rtid == rtid {
return v return v
} }
...@@ -527,7 +557,9 @@ func (o extHandle) getExt(rtid uintptr) *extTypeTagFn { ...@@ -527,7 +557,9 @@ func (o extHandle) getExt(rtid uintptr) *extTypeTagFn {
} }
func (o extHandle) getExtForTag(tag uint64) *extTypeTagFn { func (o extHandle) getExtForTag(tag uint64) *extTypeTagFn {
for _, v := range o { var v *extTypeTagFn
for i := range o {
v = &o[i]
if v.tag == tag { if v.tag == tag {
return v return v
} }
...@@ -650,6 +682,8 @@ type typeInfo struct { ...@@ -650,6 +682,8 @@ type typeInfo struct {
rt reflect.Type rt reflect.Type
rtid uintptr rtid uintptr
numMeth uint16 // number of methods
// baseId gives pointer to the base reflect.Type, after deferencing // baseId gives pointer to the base reflect.Type, after deferencing
// the pointers. E.g. base type of ***time.Time is time.Time. // the pointers. E.g. base type of ***time.Time is time.Time.
base reflect.Type base reflect.Type
...@@ -746,14 +780,10 @@ func (x *TypeInfos) get(rtid uintptr, rt reflect.Type) (pti *typeInfo) { ...@@ -746,14 +780,10 @@ func (x *TypeInfos) get(rtid uintptr, rt reflect.Type) (pti *typeInfo) {
return return
} }
x.mu.Lock() // do not hold lock while computing this.
defer x.mu.Unlock() // it may lead to duplication, but that's ok.
if pti, ok = x.infos[rtid]; ok {
return
}
ti := typeInfo{rt: rt, rtid: rtid} ti := typeInfo{rt: rt, rtid: rtid}
pti = &ti ti.numMeth = uint16(rt.NumMethod())
var indir int8 var indir int8
if ok, indir = implementsIntf(rt, binaryMarshalerTyp); ok { if ok, indir = implementsIntf(rt, binaryMarshalerTyp); ok {
...@@ -813,7 +843,13 @@ func (x *TypeInfos) get(rtid uintptr, rt reflect.Type) (pti *typeInfo) { ...@@ -813,7 +843,13 @@ func (x *TypeInfos) get(rtid uintptr, rt reflect.Type) (pti *typeInfo) {
copy(ti.sfi, sfip) copy(ti.sfi, sfip)
} }
// sfi = sfip // sfi = sfip
x.infos[rtid] = pti
x.mu.Lock()
if pti, ok = x.infos[rtid]; !ok {
pti = &ti
x.infos[rtid] = pti
}
x.mu.Unlock()
return return
} }
...@@ -822,45 +858,49 @@ func (x *TypeInfos) rget(rt reflect.Type, indexstack []int, fnameToHastag map[st ...@@ -822,45 +858,49 @@ func (x *TypeInfos) rget(rt reflect.Type, indexstack []int, fnameToHastag map[st
) { ) {
for j := 0; j < rt.NumField(); j++ { for j := 0; j < rt.NumField(); j++ {
f := rt.Field(j) f := rt.Field(j)
// func types are skipped. fkind := f.Type.Kind()
if tk := f.Type.Kind(); tk == reflect.Func { // skip if a func type, or is unexported, or structTag value == "-"
if fkind == reflect.Func {
continue continue
} }
stag := x.structTag(f.Tag) // if r1, _ := utf8.DecodeRuneInString(f.Name); r1 == utf8.RuneError || !unicode.IsUpper(r1) {
if stag == "-" { if f.PkgPath != "" && !f.Anonymous { // unexported, not embedded
continue continue
} }
if r1, _ := utf8.DecodeRuneInString(f.Name); r1 == utf8.RuneError || !unicode.IsUpper(r1) { stag := x.structTag(f.Tag)
if stag == "-" {
continue continue
} }
var si *structFieldInfo var si *structFieldInfo
// if anonymous and there is no struct tag (or it's blank) // if anonymous and no struct tag (or it's blank), and a struct (or pointer to struct), inline it.
// and its a struct (or pointer to struct), inline it. if f.Anonymous && fkind != reflect.Interface {
var doInline bool doInline := stag == ""
if f.Anonymous && f.Type.Kind() != reflect.Interface {
doInline = stag == ""
if !doInline { if !doInline {
si = parseStructFieldInfo("", stag) si = parseStructFieldInfo("", stag)
doInline = si.encName == "" doInline = si.encName == ""
// doInline = si.isZero() // doInline = si.isZero()
// fmt.Printf(">>>> doInline for si.isZero: %s: %v\n", f.Name, doInline) }
if doInline {
ft := f.Type
for ft.Kind() == reflect.Ptr {
ft = ft.Elem()
}
if ft.Kind() == reflect.Struct {
indexstack2 := make([]int, len(indexstack)+1, len(indexstack)+4)
copy(indexstack2, indexstack)
indexstack2[len(indexstack)] = j
// indexstack2 := append(append(make([]int, 0, len(indexstack)+4), indexstack...), j)
x.rget(ft, indexstack2, fnameToHastag, sfi, siInfo)
continue
}
} }
} }
if doInline { // after the anonymous dance: if an unexported field, skip
ft := f.Type if f.PkgPath != "" { // unexported
for ft.Kind() == reflect.Ptr { continue
ft = ft.Elem()
}
if ft.Kind() == reflect.Struct {
indexstack2 := make([]int, len(indexstack)+1, len(indexstack)+4)
copy(indexstack2, indexstack)
indexstack2[len(indexstack)] = j
// indexstack2 := append(append(make([]int, 0, len(indexstack)+4), indexstack...), j)
x.rget(ft, indexstack2, fnameToHastag, sfi, siInfo)
continue
}
} }
// do not let fields with same name in embedded structs override field at higher level. // do not let fields with same name in embedded structs override field at higher level.
// this must be done after anonymous check, to allow anonymous field // this must be done after anonymous check, to allow anonymous field
// still include their child fields // still include their child fields
......
...@@ -30,8 +30,6 @@ package codec ...@@ -30,8 +30,6 @@ package codec
// Top-level methods of json(End|Dec)Driver (which are implementations of (en|de)cDriver // Top-level methods of json(End|Dec)Driver (which are implementations of (en|de)cDriver
// MUST not call one-another. // MUST not call one-another.
// They all must call sep(), and sep() MUST NOT be called more than once for each read.
// If sep() is called and read is not done, you MUST call retryRead so separator wouldn't be read/written twice.
import ( import (
"bytes" "bytes"
...@@ -39,7 +37,6 @@ import ( ...@@ -39,7 +37,6 @@ import (
"fmt" "fmt"
"reflect" "reflect"
"strconv" "strconv"
"sync"
"unicode/utf16" "unicode/utf16"
"unicode/utf8" "unicode/utf8"
) )
...@@ -60,12 +57,13 @@ var jsonUint64Pow10 = [...]uint64{ ...@@ -60,12 +57,13 @@ var jsonUint64Pow10 = [...]uint64{
} }
const ( const (
// if jsonTrackSkipWhitespace, we track Whitespace and reduce the number of redundant checks. // jsonUnreadAfterDecNum controls whether we unread after decoding a number.
// Make it a const flag, so that it can be elided during linking if false.
// //
// It is not a clear win, because we continually set a flag behind a pointer // instead of unreading, just update d.tok (iff it's not a whitespace char)
// and then check it each time, as opposed to just 4 conditionals on a stack variable. // However, doing this means that we may HOLD onto some data which belongs to another stream.
jsonTrackSkipWhitespace = true // Thus, it is safest to unread the data when done.
// keep behind a constant flag for now.
jsonUnreadAfterDecNum = true
// If !jsonValidateSymbols, decoding will be faster, by skipping some checks: // If !jsonValidateSymbols, decoding will be faster, by skipping some checks:
// - If we see first character of null, false or true, // - If we see first character of null, false or true,
...@@ -89,100 +87,6 @@ const ( ...@@ -89,100 +87,6 @@ const (
// jsonNumDigitsUint64Largest = 19 // jsonNumDigitsUint64Largest = 19
) )
// A stack is used to keep track of where we are in the tree.
// This is necessary, as the Handle must know whether to consume or emit a separator.
type jsonStackElem struct {
st byte // top of stack (either '}' or ']' or 0 for map, array or neither).
sf bool // NOT first time in that container at top of stack
so bool // stack ctr odd
sr bool // value has NOT been read, so do not re-send separator
}
func (x *jsonStackElem) retryRead() {
if x != nil && !x.sr {
x.sr = true
}
}
func (x *jsonStackElem) sep() (c byte) {
// do not use switch, so it's a candidate for inlining.
// to inline effectively, this must not be called from within another method.
// v := j.st
if x == nil || x.st == 0 {
return
}
if x.sr {
x.sr = false
return
}
// v == '}' OR ']'
if x.st == '}' {
// put , or : depending on if even or odd respectively
if x.so {
c = ':'
if !x.sf {
x.sf = true
}
} else if x.sf {
c = ','
}
} else {
if x.sf {
c = ','
} else {
x.sf = true
}
}
x.so = !x.so
// Note: Anything more, and this function doesn't inline. Keep it tight.
// if x.sr {
// x.sr = false
// }
return
}
const jsonStackPoolArrayLen = 32
// pool used to prevent constant allocation of stacks.
var jsonStackPool = sync.Pool{
New: func() interface{} {
return new([jsonStackPoolArrayLen]jsonStackElem)
},
}
// jsonStack contains the stack for tracking the state of the container (branch).
// The same data structure is used during encode and decode, as it is similar functionality.
type jsonStack struct {
s []jsonStackElem // stack for map or array end tag. map=}, array=]
sc *jsonStackElem // pointer to current (top) element on the stack.
sp *[jsonStackPoolArrayLen]jsonStackElem
}
func (j *jsonStack) start(c byte) {
if j.s == nil {
// j.s = make([]jsonStackElem, 0, 8)
j.sp = jsonStackPool.Get().(*[jsonStackPoolArrayLen]jsonStackElem)
j.s = j.sp[:0]
}
j.s = append(j.s, jsonStackElem{st: c})
j.sc = &(j.s[len(j.s)-1])
}
func (j *jsonStack) end() {
l := len(j.s) - 1 // length of new stack after pop'ing
if l == 0 {
jsonStackPool.Put(j.sp)
j.s = nil
j.sp = nil
j.sc = nil
} else {
j.s = j.s[:l]
j.sc = &(j.s[l-1])
}
//j.sc = &(j.s[len(j.s)-1])
}
type jsonEncDriver struct { type jsonEncDriver struct {
e *Encoder e *Encoder
w encWriter w encWriter
...@@ -190,21 +94,35 @@ type jsonEncDriver struct { ...@@ -190,21 +94,35 @@ type jsonEncDriver struct {
b [64]byte // scratch b [64]byte // scratch
bs []byte // scratch bs []byte // scratch
se setExtWrapper se setExtWrapper
s jsonStack c containerState
noBuiltInTypes noBuiltInTypes
} }
func (e *jsonEncDriver) EncodeNil() { func (e *jsonEncDriver) sendContainerState(c containerState) {
if c := e.s.sc.sep(); c != 0 { // determine whether to output separators
e.w.writen1(c) if c == containerMapKey {
if e.c != containerMapStart {
e.w.writen1(',')
}
} else if c == containerMapValue {
e.w.writen1(':')
} else if c == containerMapEnd {
e.w.writen1('}')
} else if c == containerArrayElem {
if e.c != containerArrayStart {
e.w.writen1(',')
}
} else if c == containerArrayEnd {
e.w.writen1(']')
} }
e.c = c
}
func (e *jsonEncDriver) EncodeNil() {
e.w.writeb(jsonLiterals[9:13]) // null e.w.writeb(jsonLiterals[9:13]) // null
} }
func (e *jsonEncDriver) EncodeBool(b bool) { func (e *jsonEncDriver) EncodeBool(b bool) {
if c := e.s.sc.sep(); c != 0 {
e.w.writen1(c)
}
if b { if b {
e.w.writeb(jsonLiterals[0:4]) // true e.w.writeb(jsonLiterals[0:4]) // true
} else { } else {
...@@ -213,94 +131,56 @@ func (e *jsonEncDriver) EncodeBool(b bool) { ...@@ -213,94 +131,56 @@ func (e *jsonEncDriver) EncodeBool(b bool) {
} }
func (e *jsonEncDriver) EncodeFloat32(f float32) { func (e *jsonEncDriver) EncodeFloat32(f float32) {
if c := e.s.sc.sep(); c != 0 {
e.w.writen1(c)
}
e.w.writeb(strconv.AppendFloat(e.b[:0], float64(f), 'E', -1, 32)) e.w.writeb(strconv.AppendFloat(e.b[:0], float64(f), 'E', -1, 32))
} }
func (e *jsonEncDriver) EncodeFloat64(f float64) { func (e *jsonEncDriver) EncodeFloat64(f float64) {
if c := e.s.sc.sep(); c != 0 {
e.w.writen1(c)
}
// e.w.writestr(strconv.FormatFloat(f, 'E', -1, 64)) // e.w.writestr(strconv.FormatFloat(f, 'E', -1, 64))
e.w.writeb(strconv.AppendFloat(e.b[:0], f, 'E', -1, 64)) e.w.writeb(strconv.AppendFloat(e.b[:0], f, 'E', -1, 64))
} }
func (e *jsonEncDriver) EncodeInt(v int64) { func (e *jsonEncDriver) EncodeInt(v int64) {
if c := e.s.sc.sep(); c != 0 {
e.w.writen1(c)
}
e.w.writeb(strconv.AppendInt(e.b[:0], v, 10)) e.w.writeb(strconv.AppendInt(e.b[:0], v, 10))
} }
func (e *jsonEncDriver) EncodeUint(v uint64) { func (e *jsonEncDriver) EncodeUint(v uint64) {
if c := e.s.sc.sep(); c != 0 {
e.w.writen1(c)
}
e.w.writeb(strconv.AppendUint(e.b[:0], v, 10)) e.w.writeb(strconv.AppendUint(e.b[:0], v, 10))
} }
func (e *jsonEncDriver) EncodeExt(rv interface{}, xtag uint64, ext Ext, en *Encoder) { func (e *jsonEncDriver) EncodeExt(rv interface{}, xtag uint64, ext Ext, en *Encoder) {
if c := e.s.sc.sep(); c != 0 {
e.w.writen1(c)
}
if v := ext.ConvertExt(rv); v == nil { if v := ext.ConvertExt(rv); v == nil {
e.w.writeb(jsonLiterals[9:13]) // null // e.EncodeNil() e.w.writeb(jsonLiterals[9:13]) // null // e.EncodeNil()
} else { } else {
e.s.sc.retryRead()
en.encode(v) en.encode(v)
} }
} }
func (e *jsonEncDriver) EncodeRawExt(re *RawExt, en *Encoder) { func (e *jsonEncDriver) EncodeRawExt(re *RawExt, en *Encoder) {
if c := e.s.sc.sep(); c != 0 {
e.w.writen1(c)
}
// only encodes re.Value (never re.Data) // only encodes re.Value (never re.Data)
if re.Value == nil { if re.Value == nil {
e.w.writeb(jsonLiterals[9:13]) // null // e.EncodeNil() e.w.writeb(jsonLiterals[9:13]) // null // e.EncodeNil()
} else { } else {
e.s.sc.retryRead()
en.encode(re.Value) en.encode(re.Value)
} }
} }
func (e *jsonEncDriver) EncodeArrayStart(length int) { func (e *jsonEncDriver) EncodeArrayStart(length int) {
if c := e.s.sc.sep(); c != 0 {
e.w.writen1(c)
}
e.s.start(']')
e.w.writen1('[') e.w.writen1('[')
e.c = containerArrayStart
} }
func (e *jsonEncDriver) EncodeMapStart(length int) { func (e *jsonEncDriver) EncodeMapStart(length int) {
if c := e.s.sc.sep(); c != 0 {
e.w.writen1(c)
}
e.s.start('}')
e.w.writen1('{') e.w.writen1('{')
} e.c = containerMapStart
func (e *jsonEncDriver) EncodeEnd() {
b := e.s.sc.st
e.s.end()
e.w.writen1(b)
} }
func (e *jsonEncDriver) EncodeString(c charEncoding, v string) { func (e *jsonEncDriver) EncodeString(c charEncoding, v string) {
// e.w.writestr(strconv.Quote(v)) // e.w.writestr(strconv.Quote(v))
if c := e.s.sc.sep(); c != 0 {
e.w.writen1(c)
}
e.quoteStr(v) e.quoteStr(v)
} }
func (e *jsonEncDriver) EncodeSymbol(v string) { func (e *jsonEncDriver) EncodeSymbol(v string) {
// e.EncodeString(c_UTF8, v) // e.EncodeString(c_UTF8, v)
if c := e.s.sc.sep(); c != 0 {
e.w.writen1(c)
}
e.quoteStr(v) e.quoteStr(v)
} }
...@@ -310,14 +190,8 @@ func (e *jsonEncDriver) EncodeStringBytes(c charEncoding, v []byte) { ...@@ -310,14 +190,8 @@ func (e *jsonEncDriver) EncodeStringBytes(c charEncoding, v []byte) {
e.EncodeExt(v, 0, &e.se, e.e) e.EncodeExt(v, 0, &e.se, e.e)
return return
} }
if c := e.s.sc.sep(); c != 0 {
e.w.writen1(c)
}
if c == c_RAW { if c == c_RAW {
slen := base64.StdEncoding.EncodedLen(len(v)) slen := base64.StdEncoding.EncodedLen(len(v))
if e.bs == nil {
e.bs = e.b[:]
}
if cap(e.bs) >= slen { if cap(e.bs) >= slen {
e.bs = e.bs[:slen] e.bs = e.bs[:slen]
} else { } else {
...@@ -334,9 +208,6 @@ func (e *jsonEncDriver) EncodeStringBytes(c charEncoding, v []byte) { ...@@ -334,9 +208,6 @@ func (e *jsonEncDriver) EncodeStringBytes(c charEncoding, v []byte) {
} }
func (e *jsonEncDriver) EncodeAsis(v []byte) { func (e *jsonEncDriver) EncodeAsis(v []byte) {
if c := e.s.sc.sep(); c != 0 {
e.w.writen1(c)
}
e.w.writeb(v) e.w.writeb(v)
} }
...@@ -491,185 +362,219 @@ func (x *jsonNum) floatVal() (f float64, parseUsingStrConv bool) { ...@@ -491,185 +362,219 @@ func (x *jsonNum) floatVal() (f float64, parseUsingStrConv bool) {
} }
type jsonDecDriver struct { type jsonDecDriver struct {
d *Decoder noBuiltInTypes
h *JsonHandle d *Decoder
r decReader // *bytesDecReader decReader h *JsonHandle
ct valueType // container type. one of unset, array or map. r decReader
bstr [8]byte // scratch used for string \UXXX parsing
b [64]byte // scratch, used for parsing strings or numbers
b2 [64]byte // scratch, used only for decodeBytes (after base64)
bs []byte // scratch. Initialized from b. Used for parsing strings or numbers.
wsSkipped bool // whitespace skipped c containerState
// tok is used to store the token read right after skipWhiteSpace.
tok uint8
se setExtWrapper bstr [8]byte // scratch used for string \UXXX parsing
b [64]byte // scratch, used for parsing strings or numbers
b2 [64]byte // scratch, used only for decodeBytes (after base64)
bs []byte // scratch. Initialized from b. Used for parsing strings or numbers.
s jsonStack se setExtWrapper
n jsonNum n jsonNum
noBuiltInTypes
} }
// This will skip whitespace characters and return the next byte to read. func jsonIsWS(b byte) bool {
// The next byte determines what the value will be one of. return b == ' ' || b == '\t' || b == '\r' || b == '\n'
func (d *jsonDecDriver) skipWhitespace(unread bool) (b byte) { }
// as initReadNext is not called all the time, we set ct to unSet whenever
// we skipwhitespace, as this is the signal that something new is about to be read. // // This will skip whitespace characters and return the next byte to read.
d.ct = valueTypeUnset // // The next byte determines what the value will be one of.
b = d.r.readn1() // func (d *jsonDecDriver) skipWhitespace() {
if !jsonTrackSkipWhitespace || !d.wsSkipped { // // fast-path: do not enter loop. Just check first (in case no whitespace).
for ; b == ' ' || b == '\t' || b == '\r' || b == '\n'; b = d.r.readn1() { // b := d.r.readn1()
// if jsonIsWS(b) {
// r := d.r
// for b = r.readn1(); jsonIsWS(b); b = r.readn1() {
// }
// }
// d.tok = b
// }
func (d *jsonDecDriver) uncacheRead() {
if d.tok != 0 {
d.r.unreadn1()
d.tok = 0
}
}
func (d *jsonDecDriver) sendContainerState(c containerState) {
if d.tok == 0 {
var b byte
r := d.r
for b = r.readn1(); jsonIsWS(b); b = r.readn1() {
}
d.tok = b
}
var xc uint8 // char expected
if c == containerMapKey {
if d.c != containerMapStart {
xc = ','
} }
if jsonTrackSkipWhitespace { } else if c == containerMapValue {
d.wsSkipped = true xc = ':'
} else if c == containerMapEnd {
xc = '}'
} else if c == containerArrayElem {
if d.c != containerArrayStart {
xc = ','
} }
} else if c == containerArrayEnd {
xc = ']'
} }
if unread { if xc != 0 {
d.r.unreadn1() if d.tok != xc {
d.d.errorf("json: expect char '%c' but got char '%c'", xc, d.tok)
}
d.tok = 0
} }
return b d.c = c
} }
func (d *jsonDecDriver) CheckBreak() bool { func (d *jsonDecDriver) CheckBreak() bool {
b := d.skipWhitespace(true) if d.tok == 0 {
return b == '}' || b == ']' var b byte
r := d.r
for b = r.readn1(); jsonIsWS(b); b = r.readn1() {
}
d.tok = b
}
if d.tok == '}' || d.tok == ']' {
// d.tok = 0 // only checking, not consuming
return true
}
return false
} }
func (d *jsonDecDriver) readStrIdx(fromIdx, toIdx uint8) { func (d *jsonDecDriver) readStrIdx(fromIdx, toIdx uint8) {
bs := d.r.readx(int(toIdx - fromIdx)) bs := d.r.readx(int(toIdx - fromIdx))
d.tok = 0
if jsonValidateSymbols { if jsonValidateSymbols {
if !bytes.Equal(bs, jsonLiterals[fromIdx:toIdx]) { if !bytes.Equal(bs, jsonLiterals[fromIdx:toIdx]) {
d.d.errorf("json: expecting %s: got %s", jsonLiterals[fromIdx:toIdx], bs) d.d.errorf("json: expecting %s: got %s", jsonLiterals[fromIdx:toIdx], bs)
return return
} }
} }
if jsonTrackSkipWhitespace {
d.wsSkipped = false
}
} }
func (d *jsonDecDriver) TryDecodeAsNil() bool { func (d *jsonDecDriver) TryDecodeAsNil() bool {
// we mustn't consume the state here, and end up trying to read separator twice. if d.tok == 0 {
// Instead, we keep track of the state and restore it if we couldn't decode as nil. var b byte
r := d.r
if c := d.s.sc.sep(); c != 0 { for b = r.readn1(); jsonIsWS(b); b = r.readn1() {
d.expectChar(c) }
d.tok = b
} }
b := d.skipWhitespace(false) if d.tok == 'n' {
if b == 'n' {
d.readStrIdx(10, 13) // ull d.readStrIdx(10, 13) // ull
d.ct = valueTypeNil
return true return true
} }
d.r.unreadn1()
d.s.sc.retryRead()
return false return false
} }
func (d *jsonDecDriver) DecodeBool() bool { func (d *jsonDecDriver) DecodeBool() bool {
if c := d.s.sc.sep(); c != 0 { if d.tok == 0 {
d.expectChar(c) var b byte
r := d.r
for b = r.readn1(); jsonIsWS(b); b = r.readn1() {
}
d.tok = b
} }
b := d.skipWhitespace(false) if d.tok == 'f' {
if b == 'f' {
d.readStrIdx(5, 9) // alse d.readStrIdx(5, 9) // alse
return false return false
} }
if b == 't' { if d.tok == 't' {
d.readStrIdx(1, 4) // rue d.readStrIdx(1, 4) // rue
return true return true
} }
d.d.errorf("json: decode bool: got first char %c", b) d.d.errorf("json: decode bool: got first char %c", d.tok)
return false // "unreachable" return false // "unreachable"
} }
func (d *jsonDecDriver) ReadMapStart() int { func (d *jsonDecDriver) ReadMapStart() int {
if c := d.s.sc.sep(); c != 0 { if d.tok == 0 {
d.expectChar(c) var b byte
r := d.r
for b = r.readn1(); jsonIsWS(b); b = r.readn1() {
}
d.tok = b
} }
d.s.start('}') if d.tok != '{' {
d.expectChar('{') d.d.errorf("json: expect char '%c' but got char '%c'", '{', d.tok)
d.ct = valueTypeMap
return -1
}
func (d *jsonDecDriver) ReadArrayStart() int {
if c := d.s.sc.sep(); c != 0 {
d.expectChar(c)
} }
d.s.start(']') d.tok = 0
d.expectChar('[') d.c = containerMapStart
d.ct = valueTypeArray
return -1 return -1
} }
func (d *jsonDecDriver) ReadEnd() { func (d *jsonDecDriver) ReadArrayStart() int {
b := d.s.sc.st if d.tok == 0 {
d.s.end() var b byte
d.expectChar(b) r := d.r
} for b = r.readn1(); jsonIsWS(b); b = r.readn1() {
}
func (d *jsonDecDriver) expectChar(c uint8) { d.tok = b
b := d.skipWhitespace(false)
if b != c {
d.d.errorf("json: expect char '%c' but got char '%c'", c, b)
return
} }
if jsonTrackSkipWhitespace { if d.tok != '[' {
d.wsSkipped = false d.d.errorf("json: expect char '%c' but got char '%c'", '[', d.tok)
} }
d.tok = 0
d.c = containerArrayStart
return -1
} }
// func (d *jsonDecDriver) maybeChar(c uint8) { func (d *jsonDecDriver) ContainerType() (vt valueType) {
// b := d.skipWhitespace(false)
// if b != c {
// d.r.unreadn1()
// return
// }
// if jsonTrackSkipWhitespace {
// d.wsSkipped = false
// }
// }
func (d *jsonDecDriver) IsContainerType(vt valueType) bool {
// check container type by checking the first char // check container type by checking the first char
if d.ct == valueTypeUnset { if d.tok == 0 {
b := d.skipWhitespace(true) var b byte
if b == '{' { r := d.r
d.ct = valueTypeMap for b = r.readn1(); jsonIsWS(b); b = r.readn1() {
} else if b == '[' {
d.ct = valueTypeArray
} else if b == 'n' {
d.ct = valueTypeNil
} else if b == '"' {
d.ct = valueTypeString
} }
} d.tok = b
if vt == valueTypeNil || vt == valueTypeBytes || vt == valueTypeString || }
vt == valueTypeArray || vt == valueTypeMap { if b := d.tok; b == '{' {
return d.ct == vt return valueTypeMap
} } else if b == '[' {
// ugorji: made switch into conditionals, so that IsContainerType can be inlined. return valueTypeArray
// switch vt { } else if b == 'n' {
// case valueTypeNil, valueTypeBytes, valueTypeString, valueTypeArray, valueTypeMap: return valueTypeNil
// return d.ct == vt } else if b == '"' {
// } return valueTypeString
d.d.errorf("isContainerType: unsupported parameter: %v", vt) }
return false // "unreachable" return valueTypeUnset
// d.d.errorf("isContainerType: unsupported parameter: %v", vt)
// return false // "unreachable"
} }
func (d *jsonDecDriver) decNum(storeBytes bool) { func (d *jsonDecDriver) decNum(storeBytes bool) {
// If it is has a . or an e|E, decode as a float; else decode as an int. // If it is has a . or an e|E, decode as a float; else decode as an int.
b := d.skipWhitespace(false) if d.tok == 0 {
var b byte
r := d.r
for b = r.readn1(); jsonIsWS(b); b = r.readn1() {
}
d.tok = b
}
b := d.tok
if !(b == '+' || b == '-' || b == '.' || (b >= '0' && b <= '9')) { if !(b == '+' || b == '-' || b == '.' || (b >= '0' && b <= '9')) {
d.d.errorf("json: decNum: got first char '%c'", b) d.d.errorf("json: decNum: got first char '%c'", b)
return return
} }
d.tok = 0
const cutoff = (1<<64-1)/uint64(10) + 1 // cutoff64(base) const cutoff = (1<<64-1)/uint64(10) + 1 // cutoff64(base)
const jsonNumUintMaxVal = 1<<uint64(64) - 1 const jsonNumUintMaxVal = 1<<uint64(64) - 1
n := &d.n n := &d.n
r := d.r
n.reset() n.reset()
d.bs = d.bs[:0] d.bs = d.bs[:0]
...@@ -690,7 +595,7 @@ LOOP: ...@@ -690,7 +595,7 @@ LOOP:
case 0: case 0:
state = 2 state = 2
// do not add sign to the slice ... // do not add sign to the slice ...
b, eof = d.r.readn1eof() b, eof = r.readn1eof()
continue continue
case 6: // typ = jsonNumFloat case 6: // typ = jsonNumFloat
state = 7 state = 7
...@@ -703,7 +608,7 @@ LOOP: ...@@ -703,7 +608,7 @@ LOOP:
state = 2 state = 2
n.neg = true n.neg = true
// do not add sign to the slice ... // do not add sign to the slice ...
b, eof = d.r.readn1eof() b, eof = r.readn1eof()
continue continue
case 6: // typ = jsonNumFloat case 6: // typ = jsonNumFloat
eNeg = true eNeg = true
...@@ -769,7 +674,7 @@ LOOP: ...@@ -769,7 +674,7 @@ LOOP:
if storeBytes { if storeBytes {
d.bs = append(d.bs, b) d.bs = append(d.bs, b)
} }
b, eof = d.r.readn1eof() b, eof = r.readn1eof()
} }
if jsonTruncateMantissa && n.mantissa != 0 { if jsonTruncateMantissa && n.mantissa != 0 {
...@@ -790,10 +695,13 @@ LOOP: ...@@ -790,10 +695,13 @@ LOOP:
// d.n = n // d.n = n
if !eof { if !eof {
d.r.unreadn1() if jsonUnreadAfterDecNum {
} r.unreadn1()
if jsonTrackSkipWhitespace { } else {
d.wsSkipped = false if !jsonIsWS(b) {
d.tok = b
}
}
} }
// fmt.Printf("1: n: bytes: %s, neg: %v, dot: %v, exponent: %v, mantissaEndIndex: %v\n", // fmt.Printf("1: n: bytes: %s, neg: %v, dot: %v, exponent: %v, mantissaEndIndex: %v\n",
// n.bytes, n.neg, n.dot, n.exponent, n.mantissaEndIndex) // n.bytes, n.neg, n.dot, n.exponent, n.mantissaEndIndex)
...@@ -801,9 +709,6 @@ LOOP: ...@@ -801,9 +709,6 @@ LOOP:
} }
func (d *jsonDecDriver) DecodeInt(bitsize uint8) (i int64) { func (d *jsonDecDriver) DecodeInt(bitsize uint8) (i int64) {
if c := d.s.sc.sep(); c != 0 {
d.expectChar(c)
}
d.decNum(false) d.decNum(false)
n := &d.n n := &d.n
if n.manOverflow { if n.manOverflow {
...@@ -851,9 +756,6 @@ func (d *jsonDecDriver) floatVal() (f float64) { ...@@ -851,9 +756,6 @@ func (d *jsonDecDriver) floatVal() (f float64) {
} }
func (d *jsonDecDriver) DecodeUint(bitsize uint8) (u uint64) { func (d *jsonDecDriver) DecodeUint(bitsize uint8) (u uint64) {
if c := d.s.sc.sep(); c != 0 {
d.expectChar(c)
}
d.decNum(false) d.decNum(false)
n := &d.n n := &d.n
if n.neg { if n.neg {
...@@ -885,9 +787,6 @@ func (d *jsonDecDriver) DecodeUint(bitsize uint8) (u uint64) { ...@@ -885,9 +787,6 @@ func (d *jsonDecDriver) DecodeUint(bitsize uint8) (u uint64) {
} }
func (d *jsonDecDriver) DecodeFloat(chkOverflow32 bool) (f float64) { func (d *jsonDecDriver) DecodeFloat(chkOverflow32 bool) (f float64) {
if c := d.s.sc.sep(); c != 0 {
d.expectChar(c)
}
d.decNum(true) d.decNum(true)
f = d.floatVal() f = d.floatVal()
if chkOverflow32 && chkOvf.Float32(f) { if chkOverflow32 && chkOvf.Float32(f) {
...@@ -898,10 +797,6 @@ func (d *jsonDecDriver) DecodeFloat(chkOverflow32 bool) (f float64) { ...@@ -898,10 +797,6 @@ func (d *jsonDecDriver) DecodeFloat(chkOverflow32 bool) (f float64) {
} }
func (d *jsonDecDriver) DecodeExt(rv interface{}, xtag uint64, ext Ext) (realxtag uint64) { func (d *jsonDecDriver) DecodeExt(rv interface{}, xtag uint64, ext Ext) (realxtag uint64) {
// No need to call sep here, as d.d.decode() handles it
// if c := d.s.sc.sep(); c != 0 {
// d.expectChar(c)
// }
if ext == nil { if ext == nil {
re := rv.(*RawExt) re := rv.(*RawExt)
re.Tag = xtag re.Tag = xtag
...@@ -921,9 +816,6 @@ func (d *jsonDecDriver) DecodeBytes(bs []byte, isstring, zerocopy bool) (bsOut [ ...@@ -921,9 +816,6 @@ func (d *jsonDecDriver) DecodeBytes(bs []byte, isstring, zerocopy bool) (bsOut [
d.DecodeExt(&bsOut, 0, &d.se) d.DecodeExt(&bsOut, 0, &d.se)
return return
} }
if c := d.s.sc.sep(); c != 0 {
d.expectChar(c)
}
d.appendStringAsBytes() d.appendStringAsBytes()
// if isstring, then just return the bytes, even if it is using the scratch buffer. // if isstring, then just return the bytes, even if it is using the scratch buffer.
// the bytes will be converted to a string as needed. // the bytes will be converted to a string as needed.
...@@ -951,30 +843,36 @@ func (d *jsonDecDriver) DecodeBytes(bs []byte, isstring, zerocopy bool) (bsOut [ ...@@ -951,30 +843,36 @@ func (d *jsonDecDriver) DecodeBytes(bs []byte, isstring, zerocopy bool) (bsOut [
} }
func (d *jsonDecDriver) DecodeString() (s string) { func (d *jsonDecDriver) DecodeString() (s string) {
if c := d.s.sc.sep(); c != 0 {
d.expectChar(c)
}
return d.decString()
}
func (d *jsonDecDriver) decString() (s string) {
d.appendStringAsBytes() d.appendStringAsBytes()
if x := d.s.sc; x != nil && x.st == '}' && x.so { // map key // if x := d.s.sc; x != nil && x.so && x.st == '}' { // map key
if d.c == containerMapKey {
return d.d.string(d.bs) return d.d.string(d.bs)
} }
return string(d.bs) return string(d.bs)
} }
func (d *jsonDecDriver) appendStringAsBytes() { func (d *jsonDecDriver) appendStringAsBytes() {
d.expectChar('"') if d.tok == 0 {
var b byte
r := d.r
for b = r.readn1(); jsonIsWS(b); b = r.readn1() {
}
d.tok = b
}
if d.tok != '"' {
d.d.errorf("json: expect char '%c' but got char '%c'", '"', d.tok)
}
d.tok = 0
v := d.bs[:0] v := d.bs[:0]
var c uint8 var c uint8
r := d.r
for { for {
c = d.r.readn1() c = r.readn1()
if c == '"' { if c == '"' {
break break
} else if c == '\\' { } else if c == '\\' {
c = d.r.readn1() c = r.readn1()
switch c { switch c {
case '"', '\\', '/', '\'': case '"', '\\', '/', '\'':
v = append(v, c) v = append(v, c)
...@@ -1003,21 +901,19 @@ func (d *jsonDecDriver) appendStringAsBytes() { ...@@ -1003,21 +901,19 @@ func (d *jsonDecDriver) appendStringAsBytes() {
v = append(v, c) v = append(v, c)
} }
} }
if jsonTrackSkipWhitespace {
d.wsSkipped = false
}
d.bs = v d.bs = v
} }
func (d *jsonDecDriver) jsonU4(checkSlashU bool) rune { func (d *jsonDecDriver) jsonU4(checkSlashU bool) rune {
if checkSlashU && !(d.r.readn1() == '\\' && d.r.readn1() == 'u') { r := d.r
if checkSlashU && !(r.readn1() == '\\' && r.readn1() == 'u') {
d.d.errorf(`json: unquoteStr: invalid unicode sequence. Expecting \u`) d.d.errorf(`json: unquoteStr: invalid unicode sequence. Expecting \u`)
return 0 return 0
} }
// u, _ := strconv.ParseUint(string(d.bstr[:4]), 16, 64) // u, _ := strconv.ParseUint(string(d.bstr[:4]), 16, 64)
var u uint32 var u uint32
for i := 0; i < 4; i++ { for i := 0; i < 4; i++ {
v := d.r.readn1() v := r.readn1()
if '0' <= v && v <= '9' { if '0' <= v && v <= '9' {
v = v - '0' v = v - '0'
} else if 'a' <= v && v <= 'z' { } else if 'a' <= v && v <= 'z' {
...@@ -1033,75 +929,83 @@ func (d *jsonDecDriver) jsonU4(checkSlashU bool) rune { ...@@ -1033,75 +929,83 @@ func (d *jsonDecDriver) jsonU4(checkSlashU bool) rune {
return rune(u) return rune(u)
} }
func (d *jsonDecDriver) DecodeNaked() (v interface{}, vt valueType, decodeFurther bool) { func (d *jsonDecDriver) DecodeNaked() {
if c := d.s.sc.sep(); c != 0 { z := &d.d.n
d.expectChar(c) // var decodeFurther bool
if d.tok == 0 {
var b byte
r := d.r
for b = r.readn1(); jsonIsWS(b); b = r.readn1() {
}
d.tok = b
} }
n := d.skipWhitespace(true) switch d.tok {
switch n {
case 'n': case 'n':
d.readStrIdx(9, 13) // null d.readStrIdx(10, 13) // ull
vt = valueTypeNil z.v = valueTypeNil
case 'f': case 'f':
d.readStrIdx(4, 9) // false d.readStrIdx(5, 9) // alse
vt = valueTypeBool z.v = valueTypeBool
v = false z.b = false
case 't': case 't':
d.readStrIdx(0, 4) // true d.readStrIdx(1, 4) // rue
vt = valueTypeBool z.v = valueTypeBool
v = true z.b = true
case '{': case '{':
vt = valueTypeMap z.v = valueTypeMap
decodeFurther = true // d.tok = 0 // don't consume. kInterfaceNaked will call ReadMapStart
// decodeFurther = true
case '[': case '[':
vt = valueTypeArray z.v = valueTypeArray
decodeFurther = true // d.tok = 0 // don't consume. kInterfaceNaked will call ReadArrayStart
// decodeFurther = true
case '"': case '"':
vt = valueTypeString z.v = valueTypeString
v = d.decString() // same as d.DecodeString(), but skipping sep() call. z.s = d.DecodeString()
default: // number default: // number
d.decNum(true) d.decNum(true)
n := &d.n n := &d.n
// if the string had a any of [.eE], then decode as float. // if the string had a any of [.eE], then decode as float.
switch { switch {
case n.explicitExponent, n.dot, n.exponent < 0, n.manOverflow: case n.explicitExponent, n.dot, n.exponent < 0, n.manOverflow:
vt = valueTypeFloat z.v = valueTypeFloat
v = d.floatVal() z.f = d.floatVal()
case n.exponent == 0: case n.exponent == 0:
u := n.mantissa u := n.mantissa
switch { switch {
case n.neg: case n.neg:
vt = valueTypeInt z.v = valueTypeInt
v = -int64(u) z.i = -int64(u)
case d.h.SignedInteger: case d.h.SignedInteger:
vt = valueTypeInt z.v = valueTypeInt
v = int64(u) z.i = int64(u)
default: default:
vt = valueTypeUint z.v = valueTypeUint
v = u z.u = u
} }
default: default:
u, overflow := n.uintExp() u, overflow := n.uintExp()
switch { switch {
case overflow: case overflow:
vt = valueTypeFloat z.v = valueTypeFloat
v = d.floatVal() z.f = d.floatVal()
case n.neg: case n.neg:
vt = valueTypeInt z.v = valueTypeInt
v = -int64(u) z.i = -int64(u)
case d.h.SignedInteger: case d.h.SignedInteger:
vt = valueTypeInt z.v = valueTypeInt
v = int64(u) z.i = int64(u)
default: default:
vt = valueTypeUint z.v = valueTypeUint
v = u z.u = u
} }
} }
// fmt.Printf("DecodeNaked: Number: %T, %v\n", v, v) // fmt.Printf("DecodeNaked: Number: %T, %v\n", v, v)
} }
if decodeFurther { // if decodeFurther {
d.s.sc.retryRead() // d.s.sc.retryRead()
} // }
return return
} }
...@@ -1124,15 +1028,20 @@ func (d *jsonDecDriver) DecodeNaked() (v interface{}, vt valueType, decodeFurthe ...@@ -1124,15 +1028,20 @@ func (d *jsonDecDriver) DecodeNaked() (v interface{}, vt valueType, decodeFurthe
// For example, a user can read a json value, then a cbor value, then a msgpack value, // For example, a user can read a json value, then a cbor value, then a msgpack value,
// all from the same stream in sequence. // all from the same stream in sequence.
type JsonHandle struct { type JsonHandle struct {
BasicHandle
textEncodingType textEncodingType
BasicHandle
// RawBytesExt, if configured, is used to encode and decode raw bytes in a custom way. // RawBytesExt, if configured, is used to encode and decode raw bytes in a custom way.
// If not configured, raw bytes are encoded to/from base64 text. // If not configured, raw bytes are encoded to/from base64 text.
RawBytesExt InterfaceExt RawBytesExt InterfaceExt
} }
func (h *JsonHandle) SetInterfaceExt(rt reflect.Type, tag uint64, ext InterfaceExt) (err error) {
return h.SetExt(rt, tag, &setExtWrapper{i: ext})
}
func (h *JsonHandle) newEncDriver(e *Encoder) encDriver { func (h *JsonHandle) newEncDriver(e *Encoder) encDriver {
hd := jsonEncDriver{e: e, w: e.w, h: h} hd := jsonEncDriver{e: e, w: e.w, h: h}
hd.bs = hd.b[:0]
hd.se.i = h.RawBytesExt hd.se.i = h.RawBytesExt
return &hd return &hd
} }
...@@ -1145,8 +1054,12 @@ func (h *JsonHandle) newDecDriver(d *Decoder) decDriver { ...@@ -1145,8 +1054,12 @@ func (h *JsonHandle) newDecDriver(d *Decoder) decDriver {
return &hd return &hd
} }
func (h *JsonHandle) SetInterfaceExt(rt reflect.Type, tag uint64, ext InterfaceExt) (err error) { func (e *jsonEncDriver) reset() {
return h.SetExt(rt, tag, &setExtWrapper{i: ext}) e.w = e.e.w
}
func (d *jsonDecDriver) reset() {
d.r = d.d.r
} }
var jsonEncodeTerminate = []byte{' '} var jsonEncodeTerminate = []byte{' '}
......
...@@ -103,11 +103,11 @@ var ( ...@@ -103,11 +103,11 @@ var (
//--------------------------------------------- //---------------------------------------------
type msgpackEncDriver struct { type msgpackEncDriver struct {
noBuiltInTypes
encNoSeparator
e *Encoder e *Encoder
w encWriter w encWriter
h *MsgpackHandle h *MsgpackHandle
noBuiltInTypes
encNoSeparator
x [8]byte x [8]byte
} }
...@@ -271,7 +271,6 @@ type msgpackDecDriver struct { ...@@ -271,7 +271,6 @@ type msgpackDecDriver struct {
bd byte bd byte
bdRead bool bdRead bool
br bool // bytes reader br bool // bytes reader
bdType valueType
noBuiltInTypes noBuiltInTypes
noStreamingCodec noStreamingCodec
decNoSeparator decNoSeparator
...@@ -282,106 +281,100 @@ type msgpackDecDriver struct { ...@@ -282,106 +281,100 @@ type msgpackDecDriver struct {
// It is called when a nil interface{} is passed, leaving it up to the DecDriver // It is called when a nil interface{} is passed, leaving it up to the DecDriver
// to introspect the stream and decide how best to decode. // to introspect the stream and decide how best to decode.
// It deciphers the value by looking at the stream first. // It deciphers the value by looking at the stream first.
func (d *msgpackDecDriver) DecodeNaked() (v interface{}, vt valueType, decodeFurther bool) { func (d *msgpackDecDriver) DecodeNaked() {
if !d.bdRead { if !d.bdRead {
d.readNextBd() d.readNextBd()
} }
bd := d.bd bd := d.bd
n := &d.d.n
var decodeFurther bool
switch bd { switch bd {
case mpNil: case mpNil:
vt = valueTypeNil n.v = valueTypeNil
d.bdRead = false d.bdRead = false
case mpFalse: case mpFalse:
vt = valueTypeBool n.v = valueTypeBool
v = false n.b = false
case mpTrue: case mpTrue:
vt = valueTypeBool n.v = valueTypeBool
v = true n.b = true
case mpFloat: case mpFloat:
vt = valueTypeFloat n.v = valueTypeFloat
v = float64(math.Float32frombits(bigen.Uint32(d.r.readx(4)))) n.f = float64(math.Float32frombits(bigen.Uint32(d.r.readx(4))))
case mpDouble: case mpDouble:
vt = valueTypeFloat n.v = valueTypeFloat
v = math.Float64frombits(bigen.Uint64(d.r.readx(8))) n.f = math.Float64frombits(bigen.Uint64(d.r.readx(8)))
case mpUint8: case mpUint8:
vt = valueTypeUint n.v = valueTypeUint
v = uint64(d.r.readn1()) n.u = uint64(d.r.readn1())
case mpUint16: case mpUint16:
vt = valueTypeUint n.v = valueTypeUint
v = uint64(bigen.Uint16(d.r.readx(2))) n.u = uint64(bigen.Uint16(d.r.readx(2)))
case mpUint32: case mpUint32:
vt = valueTypeUint n.v = valueTypeUint
v = uint64(bigen.Uint32(d.r.readx(4))) n.u = uint64(bigen.Uint32(d.r.readx(4)))
case mpUint64: case mpUint64:
vt = valueTypeUint n.v = valueTypeUint
v = uint64(bigen.Uint64(d.r.readx(8))) n.u = uint64(bigen.Uint64(d.r.readx(8)))
case mpInt8: case mpInt8:
vt = valueTypeInt n.v = valueTypeInt
v = int64(int8(d.r.readn1())) n.i = int64(int8(d.r.readn1()))
case mpInt16: case mpInt16:
vt = valueTypeInt n.v = valueTypeInt
v = int64(int16(bigen.Uint16(d.r.readx(2)))) n.i = int64(int16(bigen.Uint16(d.r.readx(2))))
case mpInt32: case mpInt32:
vt = valueTypeInt n.v = valueTypeInt
v = int64(int32(bigen.Uint32(d.r.readx(4)))) n.i = int64(int32(bigen.Uint32(d.r.readx(4))))
case mpInt64: case mpInt64:
vt = valueTypeInt n.v = valueTypeInt
v = int64(int64(bigen.Uint64(d.r.readx(8)))) n.i = int64(int64(bigen.Uint64(d.r.readx(8))))
default: default:
switch { switch {
case bd >= mpPosFixNumMin && bd <= mpPosFixNumMax: case bd >= mpPosFixNumMin && bd <= mpPosFixNumMax:
// positive fixnum (always signed) // positive fixnum (always signed)
vt = valueTypeInt n.v = valueTypeInt
v = int64(int8(bd)) n.i = int64(int8(bd))
case bd >= mpNegFixNumMin && bd <= mpNegFixNumMax: case bd >= mpNegFixNumMin && bd <= mpNegFixNumMax:
// negative fixnum // negative fixnum
vt = valueTypeInt n.v = valueTypeInt
v = int64(int8(bd)) n.i = int64(int8(bd))
case bd == mpStr8, bd == mpStr16, bd == mpStr32, bd >= mpFixStrMin && bd <= mpFixStrMax: case bd == mpStr8, bd == mpStr16, bd == mpStr32, bd >= mpFixStrMin && bd <= mpFixStrMax:
if d.h.RawToString { if d.h.RawToString {
var rvm string n.v = valueTypeString
vt = valueTypeString n.s = d.DecodeString()
v = &rvm
} else { } else {
var rvm = zeroByteSlice n.v = valueTypeBytes
vt = valueTypeBytes n.l = d.DecodeBytes(nil, false, false)
v = &rvm
} }
decodeFurther = true
case bd == mpBin8, bd == mpBin16, bd == mpBin32: case bd == mpBin8, bd == mpBin16, bd == mpBin32:
var rvm = zeroByteSlice n.v = valueTypeBytes
vt = valueTypeBytes n.l = d.DecodeBytes(nil, false, false)
v = &rvm
decodeFurther = true
case bd == mpArray16, bd == mpArray32, bd >= mpFixArrayMin && bd <= mpFixArrayMax: case bd == mpArray16, bd == mpArray32, bd >= mpFixArrayMin && bd <= mpFixArrayMax:
vt = valueTypeArray n.v = valueTypeArray
decodeFurther = true decodeFurther = true
case bd == mpMap16, bd == mpMap32, bd >= mpFixMapMin && bd <= mpFixMapMax: case bd == mpMap16, bd == mpMap32, bd >= mpFixMapMin && bd <= mpFixMapMax:
vt = valueTypeMap n.v = valueTypeMap
decodeFurther = true decodeFurther = true
case bd >= mpFixExt1 && bd <= mpFixExt16, bd >= mpExt8 && bd <= mpExt32: case bd >= mpFixExt1 && bd <= mpFixExt16, bd >= mpExt8 && bd <= mpExt32:
n.v = valueTypeExt
clen := d.readExtLen() clen := d.readExtLen()
var re RawExt n.u = uint64(d.r.readn1())
re.Tag = uint64(d.r.readn1()) n.l = d.r.readx(clen)
re.Data = d.r.readx(clen)
v = &re
vt = valueTypeExt
default: default:
d.d.errorf("Nil-Deciphered DecodeValue: %s: hex: %x, dec: %d", msgBadDesc, bd, bd) d.d.errorf("Nil-Deciphered DecodeValue: %s: hex: %x, dec: %d", msgBadDesc, bd, bd)
return
} }
} }
if !decodeFurther { if !decodeFurther {
d.bdRead = false d.bdRead = false
} }
if vt == valueTypeUint && d.h.SignedInteger { if n.v == valueTypeUint && d.h.SignedInteger {
d.bdType = valueTypeInt n.v = valueTypeInt
v = int64(v.(uint64)) n.i = int64(n.v)
} }
return return
} }
...@@ -566,28 +559,27 @@ func (d *msgpackDecDriver) DecodeString() (s string) { ...@@ -566,28 +559,27 @@ func (d *msgpackDecDriver) DecodeString() (s string) {
func (d *msgpackDecDriver) readNextBd() { func (d *msgpackDecDriver) readNextBd() {
d.bd = d.r.readn1() d.bd = d.r.readn1()
d.bdRead = true d.bdRead = true
d.bdType = valueTypeUnset
} }
func (d *msgpackDecDriver) IsContainerType(vt valueType) bool { func (d *msgpackDecDriver) ContainerType() (vt valueType) {
bd := d.bd bd := d.bd
switch vt { if bd == mpNil {
case valueTypeNil: return valueTypeNil
return bd == mpNil } else if bd == mpBin8 || bd == mpBin16 || bd == mpBin32 ||
case valueTypeBytes: (!d.h.RawToString &&
return bd == mpBin8 || bd == mpBin16 || bd == mpBin32 || (bd == mpStr8 || bd == mpStr16 || bd == mpStr32 || (bd >= mpFixStrMin && bd <= mpFixStrMax))) {
(!d.h.RawToString && return valueTypeBytes
(bd == mpStr8 || bd == mpStr16 || bd == mpStr32 || (bd >= mpFixStrMin && bd <= mpFixStrMax))) } else if d.h.RawToString &&
case valueTypeString: (bd == mpStr8 || bd == mpStr16 || bd == mpStr32 || (bd >= mpFixStrMin && bd <= mpFixStrMax)) {
return d.h.RawToString && return valueTypeString
(bd == mpStr8 || bd == mpStr16 || bd == mpStr32 || (bd >= mpFixStrMin && bd <= mpFixStrMax)) } else if bd == mpArray16 || bd == mpArray32 || (bd >= mpFixArrayMin && bd <= mpFixArrayMax) {
case valueTypeArray: return valueTypeArray
return bd == mpArray16 || bd == mpArray32 || (bd >= mpFixArrayMin && bd <= mpFixArrayMax) } else if bd == mpMap16 || bd == mpMap32 || (bd >= mpFixMapMin && bd <= mpFixMapMax) {
case valueTypeMap: return valueTypeMap
return bd == mpMap16 || bd == mpMap32 || (bd >= mpFixMapMin && bd <= mpFixMapMax) } else {
} // d.d.errorf("isContainerType: unsupported parameter: %v", vt)
d.d.errorf("isContainerType: unsupported parameter: %v", vt) }
return false // "unreachable" return valueTypeUnset
} }
func (d *msgpackDecDriver) TryDecodeAsNil() (v bool) { func (d *msgpackDecDriver) TryDecodeAsNil() (v bool) {
...@@ -701,7 +693,6 @@ func (d *msgpackDecDriver) decodeExtV(verifyTag bool, tag byte) (xtag byte, xbs ...@@ -701,7 +693,6 @@ func (d *msgpackDecDriver) decodeExtV(verifyTag bool, tag byte) (xtag byte, xbs
//MsgpackHandle is a Handle for the Msgpack Schema-Free Encoding Format. //MsgpackHandle is a Handle for the Msgpack Schema-Free Encoding Format.
type MsgpackHandle struct { type MsgpackHandle struct {
BasicHandle BasicHandle
binaryEncodingType
// RawToString controls how raw bytes are decoded into a nil interface{}. // RawToString controls how raw bytes are decoded into a nil interface{}.
RawToString bool RawToString bool
...@@ -717,6 +708,11 @@ type MsgpackHandle struct { ...@@ -717,6 +708,11 @@ type MsgpackHandle struct {
// type is provided (e.g. decoding into a nil interface{}), you get back // type is provided (e.g. decoding into a nil interface{}), you get back
// a []byte or string based on the setting of RawToString. // a []byte or string based on the setting of RawToString.
WriteExt bool WriteExt bool
binaryEncodingType
}
func (h *MsgpackHandle) SetBytesExt(rt reflect.Type, tag uint64, ext BytesExt) (err error) {
return h.SetExt(rt, tag, &setExtWrapper{b: ext})
} }
func (h *MsgpackHandle) newEncDriver(e *Encoder) encDriver { func (h *MsgpackHandle) newEncDriver(e *Encoder) encDriver {
...@@ -727,8 +723,12 @@ func (h *MsgpackHandle) newDecDriver(d *Decoder) decDriver { ...@@ -727,8 +723,12 @@ func (h *MsgpackHandle) newDecDriver(d *Decoder) decDriver {
return &msgpackDecDriver{d: d, r: d.r, h: h, br: d.bytes} return &msgpackDecDriver{d: d, r: d.r, h: h, br: d.bytes}
} }
func (h *MsgpackHandle) SetBytesExt(rt reflect.Type, tag uint64, ext BytesExt) (err error) { func (e *msgpackEncDriver) reset() {
return h.SetExt(rt, tag, &setExtWrapper{b: ext}) e.w = e.e.w
}
func (d *msgpackDecDriver) reset() {
d.r = d.d.r
} }
//-------------------------------------------------- //--------------------------------------------------
......
...@@ -38,21 +38,26 @@ type noopHandle struct { ...@@ -38,21 +38,26 @@ type noopHandle struct {
} }
type noopDrv struct { type noopDrv struct {
d *Decoder
e *Encoder
i int i int
S []string S []string
B [][]byte B [][]byte
mks []bool // stack. if map (true), else if array (false) mks []bool // stack. if map (true), else if array (false)
mk bool // top of stack. what container are we on? map or array? mk bool // top of stack. what container are we on? map or array?
ct valueType // last request for IsContainerType. ct valueType // last response for IsContainerType.
cb bool // last response for IsContainerType. cb int // counter for ContainerType
rand *rand.Rand rand *rand.Rand
} }
func (h *noopDrv) r(v int) int { return h.rand.Intn(v) } func (h *noopDrv) r(v int) int { return h.rand.Intn(v) }
func (h *noopDrv) m(v int) int { h.i++; return h.i % v } func (h *noopDrv) m(v int) int { h.i++; return h.i % v }
func (h *noopDrv) newEncDriver(_ *Encoder) encDriver { return h } func (h *noopDrv) newEncDriver(e *Encoder) encDriver { h.e = e; return h }
func (h *noopDrv) newDecDriver(_ *Decoder) decDriver { return h } func (h *noopDrv) newDecDriver(d *Decoder) decDriver { h.d = d; return h }
func (h *noopDrv) reset() {}
func (h *noopDrv) uncacheRead() {}
// --- encDriver // --- encDriver
...@@ -111,18 +116,48 @@ func (h *noopDrv) ReadEnd() { h.end() } ...@@ -111,18 +116,48 @@ func (h *noopDrv) ReadEnd() { h.end() }
func (h *noopDrv) ReadMapStart() int { h.start(true); return h.m(10) } func (h *noopDrv) ReadMapStart() int { h.start(true); return h.m(10) }
func (h *noopDrv) ReadArrayStart() int { h.start(false); return h.m(10) } func (h *noopDrv) ReadArrayStart() int { h.start(false); return h.m(10) }
func (h *noopDrv) IsContainerType(vt valueType) bool { func (h *noopDrv) ContainerType() (vt valueType) {
// return h.m(2) == 0 // return h.m(2) == 0
// handle kStruct // handle kStruct, which will bomb is it calls this and doesn't get back a map or array.
if h.ct == valueTypeMap && vt == valueTypeArray || h.ct == valueTypeArray && vt == valueTypeMap { // consequently, if the return value is not map or array, reset it to one of them based on h.m(7) % 2
h.cb = !h.cb // for kstruct: at least one out of every 2 times, return one of valueTypeMap or Array (else kstruct bombs)
h.ct = vt // however, every 10th time it is called, we just return something else.
return h.cb var vals = [...]valueType{valueTypeArray, valueTypeMap}
} // ------------ TAKE ------------
// go in a loop and check it. // if h.cb%2 == 0 {
h.ct = vt // if h.ct == valueTypeMap || h.ct == valueTypeArray {
h.cb = h.m(7) == 0 // } else {
return h.cb // h.ct = vals[h.m(2)]
// }
// } else if h.cb%5 == 0 {
// h.ct = valueType(h.m(8))
// } else {
// h.ct = vals[h.m(2)]
// }
// ------------ TAKE ------------
// if h.cb%16 == 0 {
// h.ct = valueType(h.cb % 8)
// } else {
// h.ct = vals[h.cb%2]
// }
h.ct = vals[h.cb%2]
h.cb++
return h.ct
// if h.ct == valueTypeNil || h.ct == valueTypeString || h.ct == valueTypeBytes {
// return h.ct
// }
// return valueTypeUnset
// TODO: may need to tweak this so it works.
// if h.ct == valueTypeMap && vt == valueTypeArray || h.ct == valueTypeArray && vt == valueTypeMap {
// h.cb = !h.cb
// h.ct = vt
// return h.cb
// }
// // go in a loop and check it.
// h.ct = vt
// h.cb = h.m(7) == 0
// return h.cb
} }
func (h *noopDrv) TryDecodeAsNil() bool { func (h *noopDrv) TryDecodeAsNil() bool {
if h.mk { if h.mk {
...@@ -135,7 +170,7 @@ func (h *noopDrv) DecodeExt(rv interface{}, xtag uint64, ext Ext) uint64 { ...@@ -135,7 +170,7 @@ func (h *noopDrv) DecodeExt(rv interface{}, xtag uint64, ext Ext) uint64 {
return 0 return 0
} }
func (h *noopDrv) DecodeNaked() (v interface{}, vt valueType, decodeFurther bool) { func (h *noopDrv) DecodeNaked() {
// use h.r (random) not h.m() because h.m() could cause the same value to be given. // use h.r (random) not h.m() because h.m() could cause the same value to be given.
var sk int var sk int
if h.mk { if h.mk {
...@@ -144,32 +179,35 @@ func (h *noopDrv) DecodeNaked() (v interface{}, vt valueType, decodeFurther bool ...@@ -144,32 +179,35 @@ func (h *noopDrv) DecodeNaked() (v interface{}, vt valueType, decodeFurther bool
} else { } else {
sk = h.r(12) sk = h.r(12)
} }
n := &h.d.n
switch sk { switch sk {
case 0: case 0:
vt = valueTypeNil n.v = valueTypeNil
case 1: case 1:
vt, v = valueTypeBool, false n.v, n.b = valueTypeBool, false
case 2: case 2:
vt, v = valueTypeBool, true n.v, n.b = valueTypeBool, true
case 3: case 3:
vt, v = valueTypeInt, h.DecodeInt(64) n.v, n.i = valueTypeInt, h.DecodeInt(64)
case 4: case 4:
vt, v = valueTypeUint, h.DecodeUint(64) n.v, n.u = valueTypeUint, h.DecodeUint(64)
case 5: case 5:
vt, v = valueTypeFloat, h.DecodeFloat(true) n.v, n.f = valueTypeFloat, h.DecodeFloat(true)
case 6: case 6:
vt, v = valueTypeFloat, h.DecodeFloat(false) n.v, n.f = valueTypeFloat, h.DecodeFloat(false)
case 7: case 7:
vt, v = valueTypeString, h.DecodeString() n.v, n.s = valueTypeString, h.DecodeString()
case 8: case 8:
vt, v = valueTypeBytes, h.B[h.m(len(h.B))] n.v, n.l = valueTypeBytes, h.B[h.m(len(h.B))]
case 9: case 9:
vt, decodeFurther = valueTypeArray, true n.v = valueTypeArray
case 10: case 10:
vt, decodeFurther = valueTypeMap, true n.v = valueTypeMap
default: default:
vt, v = valueTypeExt, &RawExt{Tag: h.DecodeUint(64), Data: h.B[h.m(len(h.B))]} n.v = valueTypeExt
n.u = h.DecodeUint(64)
n.l = h.B[h.m(len(h.B))]
} }
h.ct = vt h.ct = n.v
return return
} }
...@@ -49,7 +49,8 @@ _build() { ...@@ -49,7 +49,8 @@ _build() {
# [ -e "safe${_gg}" ] && mv safe${_gg} safe${_gg}__${_zts}.bak # [ -e "safe${_gg}" ] && mv safe${_gg} safe${_gg}__${_zts}.bak
# [ -e "unsafe${_gg}" ] && mv unsafe${_gg} unsafe${_gg}__${_zts}.bak # [ -e "unsafe${_gg}" ] && mv unsafe${_gg} unsafe${_gg}__${_zts}.bak
else else
rm -f fast-path.generated.go gen.generated.go gen-helper.generated.go *safe.generated.go *_generated_test.go *.generated_ffjson_expose.go rm -f fast-path.generated.go gen.generated.go gen-helper.generated.go \
*safe.generated.go *_generated_test.go *.generated_ffjson_expose.go
fi fi
cat > gen.generated.go <<EOF cat > gen.generated.go <<EOF
...@@ -77,27 +78,6 @@ EOF ...@@ -77,27 +78,6 @@ EOF
\` \`
EOF EOF
# All functions, variables which must exist are put in this file.
# This way, build works before we generate the right things.
cat > fast-path.generated.go <<EOF
package codec
import "reflect"
// func GenBytesToStringRO(b []byte) string { return string(b) }
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 }
type fastpathE struct {
rtid uintptr
rt reflect.Type
encfn func(*encFnInfo, reflect.Value)
decfn func(*decFnInfo, reflect.Value)
}
type fastpathA [0]fastpathE
func (x fastpathA) index(rtid uintptr) int { return -1 }
var fastpathAV fastpathA
EOF
cat > gen-from-tmpl.codec.generated.go <<EOF cat > gen-from-tmpl.codec.generated.go <<EOF
package codec package codec
...@@ -137,7 +117,7 @@ run("gen-helper.go.tmpl", "gen-helper.generated.go", false) ...@@ -137,7 +117,7 @@ run("gen-helper.go.tmpl", "gen-helper.generated.go", false)
} }
EOF EOF
go run gen-from-tmpl.generated.go && \ go run -tags=notfastpath gen-from-tmpl.generated.go && \
rm -f gen-from-tmpl.*generated.go rm -f gen-from-tmpl.*generated.go
} }
...@@ -152,15 +132,18 @@ _codegenerators() { ...@@ -152,15 +132,18 @@ _codegenerators() {
# Consequently, we should start msgp and ffjson first, and also put a small time latency before # Consequently, we should start msgp and ffjson first, and also put a small time latency before
# starting codecgen. # starting codecgen.
# Without this, ffjson chokes on one of the temporary files from codecgen. # Without this, ffjson chokes on one of the temporary files from codecgen.
echo "ffjson ... " && \ if [[ $zexternal == "1" ]]
ffjson -w values_ffjson${zsfx} $zfin & then
zzzIdFF=$! echo "ffjson ... " && \
echo "msgp ... " && \ ffjson -w values_ffjson${zsfx} $zfin &
msgp -tests=false -pkg=codec -o=values_msgp${zsfx} -file=$zfin & zzzIdFF=$!
zzzIdMsgp=$! echo "msgp ... " && \
msgp -tests=false -o=values_msgp${zsfx} -file=$zfin &
sleep 1 # give ffjson and msgp some buffer time. see note above. zzzIdMsgp=$!
sleep 1 # give ffjson and msgp some buffer time. see note above.
fi
echo "codecgen - !unsafe ... " && \ echo "codecgen - !unsafe ... " && \
codecgen -rt codecgen -t 'x,codecgen,!unsafe' -o values_codecgen${zsfx} -d 19780 $zfin & codecgen -rt codecgen -t 'x,codecgen,!unsafe' -o values_codecgen${zsfx} -d 19780 $zfin &
zzzIdC=$! zzzIdC=$!
...@@ -169,8 +152,11 @@ _codegenerators() { ...@@ -169,8 +152,11 @@ _codegenerators() {
zzzIdCU=$! zzzIdCU=$!
wait $zzzIdC $zzzIdCU $zzzIdMsgp $zzzIdFF && \ wait $zzzIdC $zzzIdCU $zzzIdMsgp $zzzIdFF && \
# remove (M|Unm)arshalJSON implementations, so they don't conflict with encoding/json bench \ # remove (M|Unm)arshalJSON implementations, so they don't conflict with encoding/json bench \
sed -i 's+ MarshalJSON(+ _MarshalJSON(+g' values_ffjson${zsfx} && \ if [[ $zexternal == "1" ]]
sed -i 's+ UnmarshalJSON(+ _UnmarshalJSON(+g' values_ffjson${zsfx} && \ then
sed -i 's+ MarshalJSON(+ _MarshalJSON(+g' values_ffjson${zsfx} && \
sed -i 's+ UnmarshalJSON(+ _UnmarshalJSON(+g' values_ffjson${zsfx}
fi && \
echo "generators done!" && \ echo "generators done!" && \
true true
fi fi
...@@ -179,11 +165,12 @@ _codegenerators() { ...@@ -179,11 +165,12 @@ _codegenerators() {
# _init reads the arguments and sets up the flags # _init reads the arguments and sets up the flags
_init() { _init() {
OPTIND=1 OPTIND=1
while getopts "fb" flag while getopts "fbx" flag
do do
case "x$flag" in case "x$flag" in
'xf') zforce=1;; 'xf') zforce=1;;
'xb') zbak=1;; 'xb') zbak=1;;
'xx') zexternal=1;;
*) echo "prebuild.sh accepts [-fb] only"; return 1;; *) echo "prebuild.sh accepts [-fb] only"; return 1;;
esac esac
done done
......
...@@ -29,12 +29,12 @@ const ( ...@@ -29,12 +29,12 @@ const (
) )
type simpleEncDriver struct { type simpleEncDriver struct {
noBuiltInTypes
encNoSeparator
e *Encoder e *Encoder
h *SimpleHandle h *SimpleHandle
w encWriter w encWriter
noBuiltInTypes
b [8]byte b [8]byte
encNoSeparator
} }
func (e *simpleEncDriver) EncodeNil() { func (e *simpleEncDriver) EncodeNil() {
...@@ -153,7 +153,6 @@ type simpleDecDriver struct { ...@@ -153,7 +153,6 @@ type simpleDecDriver struct {
h *SimpleHandle h *SimpleHandle
r decReader r decReader
bdRead bool bdRead bool
bdType valueType
bd byte bd byte
br bool // bytes reader br bool // bytes reader
noBuiltInTypes noBuiltInTypes
...@@ -165,28 +164,27 @@ type simpleDecDriver struct { ...@@ -165,28 +164,27 @@ type simpleDecDriver struct {
func (d *simpleDecDriver) readNextBd() { func (d *simpleDecDriver) readNextBd() {
d.bd = d.r.readn1() d.bd = d.r.readn1()
d.bdRead = true d.bdRead = true
d.bdType = valueTypeUnset }
}
func (d *simpleDecDriver) ContainerType() (vt valueType) {
func (d *simpleDecDriver) IsContainerType(vt valueType) bool { if d.bd == simpleVdNil {
switch vt { return valueTypeNil
case valueTypeNil: } else if d.bd == simpleVdByteArray || d.bd == simpleVdByteArray+1 ||
return d.bd == simpleVdNil d.bd == simpleVdByteArray+2 || d.bd == simpleVdByteArray+3 || d.bd == simpleVdByteArray+4 {
case valueTypeBytes: return valueTypeBytes
const x uint8 = simpleVdByteArray } else if d.bd == simpleVdString || d.bd == simpleVdString+1 ||
return d.bd == x || d.bd == x+1 || d.bd == x+2 || d.bd == x+3 || d.bd == x+4 d.bd == simpleVdString+2 || d.bd == simpleVdString+3 || d.bd == simpleVdString+4 {
case valueTypeString: return valueTypeString
const x uint8 = simpleVdString } else if d.bd == simpleVdArray || d.bd == simpleVdArray+1 ||
return d.bd == x || d.bd == x+1 || d.bd == x+2 || d.bd == x+3 || d.bd == x+4 d.bd == simpleVdArray+2 || d.bd == simpleVdArray+3 || d.bd == simpleVdArray+4 {
case valueTypeArray: return valueTypeArray
const x uint8 = simpleVdArray } else if d.bd == simpleVdMap || d.bd == simpleVdMap+1 ||
return d.bd == x || d.bd == x+1 || d.bd == x+2 || d.bd == x+3 || d.bd == x+4 d.bd == simpleVdMap+2 || d.bd == simpleVdMap+3 || d.bd == simpleVdMap+4 {
case valueTypeMap: return valueTypeMap
const x uint8 = simpleVdMap } else {
return d.bd == x || d.bd == x+1 || d.bd == x+2 || d.bd == x+3 || d.bd == x+4 // d.d.errorf("isContainerType: unsupported parameter: %v", vt)
} }
d.d.errorf("isContainerType: unsupported parameter: %v", vt) return valueTypeUnset
return false // "unreachable"
} }
func (d *simpleDecDriver) TryDecodeAsNil() bool { func (d *simpleDecDriver) TryDecodeAsNil() bool {
...@@ -410,59 +408,59 @@ func (d *simpleDecDriver) decodeExtV(verifyTag bool, tag byte) (xtag byte, xbs [ ...@@ -410,59 +408,59 @@ func (d *simpleDecDriver) decodeExtV(verifyTag bool, tag byte) (xtag byte, xbs [
return return
} }
func (d *simpleDecDriver) DecodeNaked() (v interface{}, vt valueType, decodeFurther bool) { func (d *simpleDecDriver) DecodeNaked() {
if !d.bdRead { if !d.bdRead {
d.readNextBd() d.readNextBd()
} }
n := &d.d.n
var decodeFurther bool
switch d.bd { switch d.bd {
case simpleVdNil: case simpleVdNil:
vt = valueTypeNil n.v = valueTypeNil
case simpleVdFalse: case simpleVdFalse:
vt = valueTypeBool n.v = valueTypeBool
v = false n.b = false
case simpleVdTrue: case simpleVdTrue:
vt = valueTypeBool n.v = valueTypeBool
v = true n.b = true
case simpleVdPosInt, simpleVdPosInt + 1, simpleVdPosInt + 2, simpleVdPosInt + 3: case simpleVdPosInt, simpleVdPosInt + 1, simpleVdPosInt + 2, simpleVdPosInt + 3:
if d.h.SignedInteger { if d.h.SignedInteger {
vt = valueTypeInt n.v = valueTypeInt
v = d.DecodeInt(64) n.i = d.DecodeInt(64)
} else { } else {
vt = valueTypeUint n.v = valueTypeUint
v = d.DecodeUint(64) n.u = d.DecodeUint(64)
} }
case simpleVdNegInt, simpleVdNegInt + 1, simpleVdNegInt + 2, simpleVdNegInt + 3: case simpleVdNegInt, simpleVdNegInt + 1, simpleVdNegInt + 2, simpleVdNegInt + 3:
vt = valueTypeInt n.v = valueTypeInt
v = d.DecodeInt(64) n.i = d.DecodeInt(64)
case simpleVdFloat32: case simpleVdFloat32:
vt = valueTypeFloat n.v = valueTypeFloat
v = d.DecodeFloat(true) n.f = d.DecodeFloat(true)
case simpleVdFloat64: case simpleVdFloat64:
vt = valueTypeFloat n.v = valueTypeFloat
v = d.DecodeFloat(false) n.f = d.DecodeFloat(false)
case simpleVdString, simpleVdString + 1, simpleVdString + 2, simpleVdString + 3, simpleVdString + 4: case simpleVdString, simpleVdString + 1, simpleVdString + 2, simpleVdString + 3, simpleVdString + 4:
vt = valueTypeString n.v = valueTypeString
v = d.DecodeString() n.s = d.DecodeString()
case simpleVdByteArray, simpleVdByteArray + 1, simpleVdByteArray + 2, simpleVdByteArray + 3, simpleVdByteArray + 4: case simpleVdByteArray, simpleVdByteArray + 1, simpleVdByteArray + 2, simpleVdByteArray + 3, simpleVdByteArray + 4:
vt = valueTypeBytes n.v = valueTypeBytes
v = d.DecodeBytes(nil, false, false) n.l = d.DecodeBytes(nil, false, false)
case simpleVdExt, simpleVdExt + 1, simpleVdExt + 2, simpleVdExt + 3, simpleVdExt + 4: case simpleVdExt, simpleVdExt + 1, simpleVdExt + 2, simpleVdExt + 3, simpleVdExt + 4:
vt = valueTypeExt n.v = valueTypeExt
l := d.decLen() l := d.decLen()
var re RawExt n.u = uint64(d.r.readn1())
re.Tag = uint64(d.r.readn1()) n.l = d.r.readx(l)
re.Data = d.r.readx(l)
v = &re
case simpleVdArray, simpleVdArray + 1, simpleVdArray + 2, simpleVdArray + 3, simpleVdArray + 4: case simpleVdArray, simpleVdArray + 1, simpleVdArray + 2, simpleVdArray + 3, simpleVdArray + 4:
vt = valueTypeArray n.v = valueTypeArray
decodeFurther = true decodeFurther = true
case simpleVdMap, simpleVdMap + 1, simpleVdMap + 2, simpleVdMap + 3, simpleVdMap + 4: case simpleVdMap, simpleVdMap + 1, simpleVdMap + 2, simpleVdMap + 3, simpleVdMap + 4:
vt = valueTypeMap n.v = valueTypeMap
decodeFurther = true decodeFurther = true
default: default:
d.d.errorf("decodeNaked: Unrecognized d.bd: 0x%x", d.bd) d.d.errorf("decodeNaked: Unrecognized d.bd: 0x%x", d.bd)
return
} }
if !decodeFurther { if !decodeFurther {
...@@ -496,6 +494,10 @@ type SimpleHandle struct { ...@@ -496,6 +494,10 @@ type SimpleHandle struct {
binaryEncodingType binaryEncodingType
} }
func (h *SimpleHandle) SetBytesExt(rt reflect.Type, tag uint64, ext BytesExt) (err error) {
return h.SetExt(rt, tag, &setExtWrapper{b: ext})
}
func (h *SimpleHandle) newEncDriver(e *Encoder) encDriver { func (h *SimpleHandle) newEncDriver(e *Encoder) encDriver {
return &simpleEncDriver{e: e, w: e.w, h: h} return &simpleEncDriver{e: e, w: e.w, h: h}
} }
...@@ -504,8 +506,12 @@ func (h *SimpleHandle) newDecDriver(d *Decoder) decDriver { ...@@ -504,8 +506,12 @@ func (h *SimpleHandle) newDecDriver(d *Decoder) decDriver {
return &simpleDecDriver{d: d, r: d.r, h: h, br: d.bytes} return &simpleDecDriver{d: d, r: d.r, h: h, br: d.bytes}
} }
func (h *SimpleHandle) SetBytesExt(rt reflect.Type, tag uint64, ext BytesExt) (err error) { func (e *simpleEncDriver) reset() {
return h.SetExt(rt, tag, &setExtWrapper{b: ext}) e.w = e.e.w
}
func (d *simpleDecDriver) reset() {
d.r = d.d.r
} }
var _ decDriver = (*simpleDecDriver)(nil) var _ decDriver = (*simpleDecDriver)(nil)
......
...@@ -4,22 +4,29 @@ ...@@ -4,22 +4,29 @@
# This helps ensure that nothing gets broken. # This helps ensure that nothing gets broken.
_run() { _run() {
# 1. VARIATIONS: regular (t), canonical (c), IO R/W (i), binc-nosymbols (n), struct2array (s) # 1. VARIATIONS: regular (t), canonical (c), IO R/W (i),
# 2. MODE: reflection (r), codecgen (x), codecgen+unsafe (u) # binc-nosymbols (n), struct2array (s), intern string (e),
# 2. MODE: reflection (r), external (x), codecgen (g), unsafe (u), notfastpath (f)
# 3. OPTIONS: verbose (v), reset (z), must (m),
# #
# Typically, you would run a combination of one value from a and b. # Use combinations of mode to get exactly what you want,
# and then pass the variations you need.
ztags="" ztags=""
zargs=""
local OPTIND local OPTIND
OPTIND=1 OPTIND=1
while getopts "xurtcinsvg" flag while getopts "xurtcinsvgzmef" flag
do do
case "x$flag" in case "x$flag" in
'xr') ;; 'xr') ;;
'xf') ztags="$ztags notfastpath" ;;
'xg') ztags="$ztags codecgen" ;; 'xg') ztags="$ztags codecgen" ;;
'xx') ztags="$ztags x" ;; 'xx') ztags="$ztags x" ;;
'xu') ztags="$ztags unsafe" ;; 'xu') ztags="$ztags unsafe" ;;
'xv') zverbose="-tv" ;; 'xv') zargs="$zargs -tv" ;;
'xz') zargs="$zargs -tr" ;;
'xm') zargs="$zargs -tm" ;;
*) ;; *) ;;
esac esac
done done
...@@ -28,14 +35,15 @@ _run() { ...@@ -28,14 +35,15 @@ _run() {
# echo ">>>>>>> TAGS: $ztags" # echo ">>>>>>> TAGS: $ztags"
OPTIND=1 OPTIND=1
while getopts "xurtcinsvg" flag while getopts "xurtcinsvgzmef" flag
do do
case "x$flag" in case "x$flag" in
'xt') printf ">>>>>>> REGULAR : "; go test "-tags=$ztags" "$zverbose" ; sleep 2 ;; 'xt') printf ">>>>>>> REGULAR : "; go test "-tags=$ztags" $zargs ; sleep 2 ;;
'xc') printf ">>>>>>> CANONICAL : "; go test "-tags=$ztags" "$zverbose" -tc; sleep 2 ;; 'xc') printf ">>>>>>> CANONICAL : "; go test "-tags=$ztags" $zargs -tc; sleep 2 ;;
'xi') printf ">>>>>>> I/O : "; go test "-tags=$ztags" "$zverbose" -ti; sleep 2 ;; 'xi') printf ">>>>>>> I/O : "; go test "-tags=$ztags" $zargs -ti; sleep 2 ;;
'xn') printf ">>>>>>> NO_SYMBOLS : "; go test "-tags=$ztags" "$zverbose" -tn; sleep 2 ;; 'xn') printf ">>>>>>> NO_SYMBOLS : "; go test "-tags=$ztags" $zargs -tn; sleep 2 ;;
'xs') printf ">>>>>>> TO_ARRAY : "; go test "-tags=$ztags" "$zverbose" -ts; 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 ;;
*) ;; *) ;;
esac esac
done done
...@@ -46,11 +54,21 @@ _run() { ...@@ -46,11 +54,21 @@ _run() {
# echo ">>>>>>> RUNNING VARIATIONS OF TESTS" # echo ">>>>>>> RUNNING VARIATIONS OF TESTS"
if [[ "x$@" = "x" ]]; then if [[ "x$@" = "x" ]]; then
# r, x, g, gu # All: r, x, g, gu
_run "-rtcins" _run "-rtcinsm" # regular
_run "-xtcins" _run "-rtcinsmz" # regular with reset
_run "-gtcins" _run "-rtcinsmf" # regular with no fastpath (notfastpath)
_run "-gutcins" _run "-xtcinsm" # external
_run "-gxtcinsm" # codecgen: requires external
_run "-gxutcinsm" # codecgen + unsafe
elif [[ "x$@" = "x-Z" ]]; then
# Regular
_run "-rtcinsm" # regular
_run "-rtcinsmz" # regular with reset
elif [[ "x$@" = "x-F" ]]; then
# regular with notfastpath
_run "-rtcinsmf" # regular
_run "-rtcinsmzf" # regular with reset
else else
_run "$@" _run "$@"
fi fi
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
package codec package codec
import ( import (
"fmt"
"time" "time"
) )
...@@ -11,6 +12,34 @@ var ( ...@@ -11,6 +12,34 @@ var (
timeDigits = [...]byte{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'} timeDigits = [...]byte{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'}
) )
type timeExt struct{}
func (x timeExt) WriteExt(v interface{}) (bs []byte) {
switch v2 := v.(type) {
case time.Time:
bs = encodeTime(v2)
case *time.Time:
bs = encodeTime(*v2)
default:
panic(fmt.Errorf("unsupported format for time conversion: expecting time.Time; got %T", v2))
}
return
}
func (x timeExt) ReadExt(v interface{}, bs []byte) {
tt, err := decodeTime(bs)
if err != nil {
panic(err)
}
*(v.(*time.Time)) = tt
}
func (x timeExt) ConvertExt(v interface{}) interface{} {
return x.WriteExt(v)
}
func (x timeExt) UpdateExt(v interface{}, src interface{}) {
x.ReadExt(v, src.([]byte))
}
// EncodeTime encodes a time.Time as a []byte, including // EncodeTime encodes a time.Time as a []byte, including
// information on the instant in time and UTC offset. // information on the instant in time and UTC offset.
// //
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment