bump(ugorji/go): 4a79e5b7b21e51ae8d61641bca20399b79735a32

This commit is contained in:
Jordan Liggitt 2016-02-02 15:45:07 -05:00
parent 1e6784edb4
commit 6445aaadcc
14 changed files with 431 additions and 146 deletions

2
Godeps/Godeps.json generated
View File

@ -931,7 +931,7 @@
}, },
{ {
"ImportPath": "github.com/ugorji/go/codec", "ImportPath": "github.com/ugorji/go/codec",
"Rev": "f1f1a805ed361a0e078bb537e4ea78cd37dcf065" "Rev": "4a79e5b7b21e51ae8d61641bca20399b79735a32"
}, },
{ {
"ImportPath": "github.com/vishvananda/netlink", "ImportPath": "github.com/vishvananda/netlink",

View File

@ -64,6 +64,7 @@ Rich Feature Set includes:
- Never silently skip data when decoding. - Never silently skip data when decoding.
User decides whether to return an error or silently skip data when keys or indexes User decides whether to return an error or silently skip data when keys or indexes
in the data stream do not map to fields in the struct. in the data stream do not map to fields in the struct.
- Detect and error when encoding a cyclic reference (instead of stack overflow shutdown)
- Encode/Decode from/to chan types (for iterative streaming support) - Encode/Decode from/to chan types (for iterative streaming support)
- Drop-in replacement for encoding/json. `json:` key in struct tag supported. - Drop-in replacement for encoding/json. `json:` key in struct tag supported.
- Provides a RPC Server and Client Codec for net/rpc communication protocol. - Provides a RPC Server and Client Codec for net/rpc communication protocol.
@ -171,6 +172,8 @@ package codec
// TODO: // TODO:
// //
// - optimization for codecgen:
// if len of entity is <= 3 words, then support a value receiver for encode.
// - (En|De)coder should store an error when it occurs. // - (En|De)coder should store an error when it occurs.
// Until reset, subsequent calls return that error that was stored. // Until reset, subsequent calls return that error that was stored.
// This means that free panics must go away. // This means that free panics must go away.
@ -190,4 +193,7 @@ package codec
// - Consider making Handle used AS-IS within the encoding/decoding session. // - 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, // This means that we don't cache Handle information within the (En|De)coder,
// except we really need it at Reset(...) // except we really need it at Reset(...)
// - Handle recursive types during encoding/decoding? // - Consider adding math/big support
// - Consider reducing the size of the generated functions:
// Maybe use one loop, and put the conditionals in the loop.
// for ... { if cLen > 0 { if j == cLen { break } } else if dd.CheckBreak() { break } }

View File

@ -908,10 +908,14 @@ func (h *BincHandle) newDecDriver(d *Decoder) decDriver {
func (e *bincEncDriver) reset() { func (e *bincEncDriver) reset() {
e.w = e.e.w e.w = e.e.w
e.s = 0
e.m = nil
} }
func (d *bincDecDriver) reset() { func (d *bincDecDriver) reset() {
d.r = d.d.r d.r = d.d.r
d.s = nil
d.bd, d.bdRead, d.vd, d.vs = 0, false, 0, 0
} }
var _ decDriver = (*bincDecDriver)(nil) var _ decDriver = (*bincDecDriver)(nil)

View File

@ -578,6 +578,7 @@ func (e *cborEncDriver) reset() {
func (d *cborDecDriver) reset() { func (d *cborDecDriver) reset() {
d.r = d.d.r d.r = d.d.r
d.bd, d.bdRead = 0, false
} }
var _ decDriver = (*cborDecDriver)(nil) var _ decDriver = (*cborDecDriver)(nil)

View File

@ -1862,6 +1862,7 @@ func (d *Decoder) intern(s string) {
} }
} }
// nextValueBytes returns the next value in the stream as a set of bytes.
func (d *Decoder) nextValueBytes() []byte { func (d *Decoder) nextValueBytes() []byte {
d.d.uncacheRead() d.d.uncacheRead()
d.r.track() d.r.track()

View File

@ -110,6 +110,15 @@ type EncodeOptions struct {
// //
Canonical bool Canonical bool
// CheckCircularRef controls whether we check for circular references
// and error fast during an encode.
//
// If enabled, an error is received if a pointer to a struct
// references itself either directly or through one of its fields (iteratively).
//
// This is opt-in, as there may be a performance hit to checking circular references.
CheckCircularRef bool
// AsSymbols defines what should be encoded as symbols. // AsSymbols defines what should be encoded as symbols.
// //
// Encoding as symbols can reduce the encoded size significantly. // Encoding as symbols can reduce the encoded size significantly.
@ -503,7 +512,7 @@ func (f *encFnInfo) kStruct(rv reflect.Value) {
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 new allocation. // The cost of sync.Pool 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)
@ -514,11 +523,6 @@ func (f *encFnInfo) kStruct(rv reflect.Value) {
var kv stringRv var kv stringRv
for _, si := range tisfi { for _, si := range tisfi {
kv.r = si.field(rv, false) kv.r = si.field(rv, false)
// if si.i != -1 {
// rvals[newlen] = rv.Field(int(si.i))
// } else {
// rvals[newlen] = rv.FieldByIndex(si.is)
// }
if toMap { if toMap {
if si.omitEmpty && isEmptyValue(kv.r) { if si.omitEmpty && isEmptyValue(kv.r) {
continue continue
@ -596,13 +600,15 @@ func (f *encFnInfo) kStruct(rv reflect.Value) {
// f.e.encodeValue(rv.Elem()) // f.e.encodeValue(rv.Elem())
// } // }
func (f *encFnInfo) kInterface(rv reflect.Value) { // func (f *encFnInfo) kInterface(rv reflect.Value) {
if rv.IsNil() { // println("kInterface called")
f.e.e.EncodeNil() // debug.PrintStack()
return // if rv.IsNil() {
} // f.e.e.EncodeNil()
f.e.encodeValue(rv.Elem(), nil) // return
} // }
// f.e.encodeValue(rv.Elem(), nil)
// }
func (f *encFnInfo) kMap(rv reflect.Value) { func (f *encFnInfo) kMap(rv reflect.Value) {
ee := f.e.e ee := f.e.e
@ -877,6 +883,7 @@ type Encoder struct {
// as the handler MAY need to do some coordination. // as the handler MAY need to do some coordination.
w encWriter w encWriter
s []encRtidFn s []encRtidFn
ci set
be bool // is binary encoding be bool // is binary encoding
js bool // is json handle js bool // is json handle
@ -1133,20 +1140,23 @@ func (e *Encoder) encode(iv interface{}) {
} }
} }
func (e *Encoder) encodeI(iv interface{}, checkFastpath, checkCodecSelfer bool) { func (e *Encoder) preEncodeValue(rv reflect.Value) (rv2 reflect.Value, sptr uintptr, proceed bool) {
if rv, proceed := e.preEncodeValue(reflect.ValueOf(iv)); proceed {
rt := rv.Type()
rtid := reflect.ValueOf(rt).Pointer()
fn := e.getEncFn(rtid, rt, checkFastpath, checkCodecSelfer)
fn.f(&fn.i, rv)
}
}
func (e *Encoder) preEncodeValue(rv reflect.Value) (rv2 reflect.Value, proceed bool) {
// use a goto statement instead of a recursive function for ptr/interface. // use a goto statement instead of a recursive function for ptr/interface.
TOP: TOP:
switch rv.Kind() { switch rv.Kind() {
case reflect.Ptr, reflect.Interface: case reflect.Ptr:
if rv.IsNil() {
e.e.EncodeNil()
return
}
rv = rv.Elem()
if e.h.CheckCircularRef && rv.Kind() == reflect.Struct {
// TODO: Movable pointers will be an issue here. Future problem.
sptr = rv.UnsafeAddr()
break TOP
}
goto TOP
case reflect.Interface:
if rv.IsNil() { if rv.IsNil() {
e.e.EncodeNil() e.e.EncodeNil()
return return
@ -1163,18 +1173,39 @@ TOP:
return return
} }
return rv, true proceed = true
rv2 = rv
return
} }
func (e *Encoder) encodeValue(rv reflect.Value, fn *encFn) { func (e *Encoder) doEncodeValue(rv reflect.Value, fn *encFn, sptr uintptr,
// if a valid fn is passed, it MUST BE for the dereferenced type of rv checkFastpath, checkCodecSelfer bool) {
if rv, proceed := e.preEncodeValue(rv); proceed { if sptr != 0 {
if (&e.ci).add(sptr) {
e.errorf("circular reference found: # %d", sptr)
}
}
if fn == nil { if fn == nil {
rt := rv.Type() rt := rv.Type()
rtid := reflect.ValueOf(rt).Pointer() rtid := reflect.ValueOf(rt).Pointer()
fn = e.getEncFn(rtid, rt, true, true) fn = e.getEncFn(rtid, rt, true, true)
} }
fn.f(&fn.i, rv) fn.f(&fn.i, rv)
if sptr != 0 {
(&e.ci).remove(sptr)
}
}
func (e *Encoder) encodeI(iv interface{}, checkFastpath, checkCodecSelfer bool) {
if rv, sptr, proceed := e.preEncodeValue(reflect.ValueOf(iv)); proceed {
e.doEncodeValue(rv, nil, sptr, checkFastpath, checkCodecSelfer)
}
}
func (e *Encoder) encodeValue(rv reflect.Value, fn *encFn) {
// if a valid fn is passed, it MUST BE for the dereferenced type of rv
if rv, sptr, proceed := e.preEncodeValue(rv); proceed {
e.doEncodeValue(rv, fn, sptr, true, true)
} }
} }
@ -1284,10 +1315,11 @@ func (e *Encoder) getEncFn(rtid uintptr, rt reflect.Type, checkFastpath, checkCo
fn.f = (*encFnInfo).kSlice fn.f = (*encFnInfo).kSlice
case reflect.Struct: case reflect.Struct:
fn.f = (*encFnInfo).kStruct fn.f = (*encFnInfo).kStruct
// reflect.Ptr and reflect.Interface are handled already by preEncodeValue
// case reflect.Ptr: // case reflect.Ptr:
// fn.f = (*encFnInfo).kPtr // fn.f = (*encFnInfo).kPtr
case reflect.Interface: // case reflect.Interface:
fn.f = (*encFnInfo).kInterface // fn.f = (*encFnInfo).kInterface
case reflect.Map: case reflect.Map:
fn.f = (*encFnInfo).kMap fn.f = (*encFnInfo).kMap
default: default:
@ -1353,25 +1385,6 @@ func encStructPoolGet(newlen int) (p *sync.Pool, v interface{}, s []stringRv) {
// panic(errors.New("encStructPoolLen must be equal to 4")) // defensive, in case it is changed // panic(errors.New("encStructPoolLen must be equal to 4")) // defensive, in case it is changed
// } // }
// idxpool := newlen / 8 // idxpool := newlen / 8
// if pool == nil {
// fkvs = make([]stringRv, newlen)
// } else {
// poolv = pool.Get()
// switch vv := poolv.(type) {
// case *[8]stringRv:
// fkvs = vv[:newlen]
// case *[16]stringRv:
// fkvs = vv[:newlen]
// case *[32]stringRv:
// fkvs = vv[:newlen]
// case *[64]stringRv:
// fkvs = vv[:newlen]
// case *[128]stringRv:
// fkvs = vv[:newlen]
// }
// }
if newlen <= 8 { if newlen <= 8 {
p = &encStructPool[0] p = &encStructPool[0]
v = p.Get() v = p.Get()

View File

@ -17712,7 +17712,7 @@ func (_ fastpathT) DecSliceIntfV(v []interface{}, checkNil bool, canChange bool,
changed = true changed = true
} }
slh.End() slh.End()
return return v, changed
} }
if containerLenS > 0 { if containerLenS > 0 {
@ -17771,7 +17771,7 @@ func (_ fastpathT) DecSliceIntfV(v []interface{}, checkNil bool, canChange bool,
changed = true changed = true
} }
slh.End() slh.End()
return return v, changed
} }
if cap(v) == 0 { if cap(v) == 0 {
v = make([]interface{}, 1, 4) v = make([]interface{}, 1, 4)
@ -17846,7 +17846,7 @@ func (_ fastpathT) DecSliceStringV(v []string, checkNil bool, canChange bool, d
changed = true changed = true
} }
slh.End() slh.End()
return return v, changed
} }
if containerLenS > 0 { if containerLenS > 0 {
@ -17905,7 +17905,7 @@ func (_ fastpathT) DecSliceStringV(v []string, checkNil bool, canChange bool, d
changed = true changed = true
} }
slh.End() slh.End()
return return v, changed
} }
if cap(v) == 0 { if cap(v) == 0 {
v = make([]string, 1, 4) v = make([]string, 1, 4)
@ -17979,7 +17979,7 @@ func (_ fastpathT) DecSliceFloat32V(v []float32, checkNil bool, canChange bool,
changed = true changed = true
} }
slh.End() slh.End()
return return v, changed
} }
if containerLenS > 0 { if containerLenS > 0 {
@ -18038,7 +18038,7 @@ func (_ fastpathT) DecSliceFloat32V(v []float32, checkNil bool, canChange bool,
changed = true changed = true
} }
slh.End() slh.End()
return return v, changed
} }
if cap(v) == 0 { if cap(v) == 0 {
v = make([]float32, 1, 4) v = make([]float32, 1, 4)
@ -18112,7 +18112,7 @@ func (_ fastpathT) DecSliceFloat64V(v []float64, checkNil bool, canChange bool,
changed = true changed = true
} }
slh.End() slh.End()
return return v, changed
} }
if containerLenS > 0 { if containerLenS > 0 {
@ -18171,7 +18171,7 @@ func (_ fastpathT) DecSliceFloat64V(v []float64, checkNil bool, canChange bool,
changed = true changed = true
} }
slh.End() slh.End()
return return v, changed
} }
if cap(v) == 0 { if cap(v) == 0 {
v = make([]float64, 1, 4) v = make([]float64, 1, 4)
@ -18245,7 +18245,7 @@ func (_ fastpathT) DecSliceUintV(v []uint, checkNil bool, canChange bool, d *Dec
changed = true changed = true
} }
slh.End() slh.End()
return return v, changed
} }
if containerLenS > 0 { if containerLenS > 0 {
@ -18304,7 +18304,7 @@ func (_ fastpathT) DecSliceUintV(v []uint, checkNil bool, canChange bool, d *Dec
changed = true changed = true
} }
slh.End() slh.End()
return return v, changed
} }
if cap(v) == 0 { if cap(v) == 0 {
v = make([]uint, 1, 4) v = make([]uint, 1, 4)
@ -18378,7 +18378,7 @@ func (_ fastpathT) DecSliceUint16V(v []uint16, checkNil bool, canChange bool, d
changed = true changed = true
} }
slh.End() slh.End()
return return v, changed
} }
if containerLenS > 0 { if containerLenS > 0 {
@ -18437,7 +18437,7 @@ func (_ fastpathT) DecSliceUint16V(v []uint16, checkNil bool, canChange bool, d
changed = true changed = true
} }
slh.End() slh.End()
return return v, changed
} }
if cap(v) == 0 { if cap(v) == 0 {
v = make([]uint16, 1, 4) v = make([]uint16, 1, 4)
@ -18511,7 +18511,7 @@ func (_ fastpathT) DecSliceUint32V(v []uint32, checkNil bool, canChange bool, d
changed = true changed = true
} }
slh.End() slh.End()
return return v, changed
} }
if containerLenS > 0 { if containerLenS > 0 {
@ -18570,7 +18570,7 @@ func (_ fastpathT) DecSliceUint32V(v []uint32, checkNil bool, canChange bool, d
changed = true changed = true
} }
slh.End() slh.End()
return return v, changed
} }
if cap(v) == 0 { if cap(v) == 0 {
v = make([]uint32, 1, 4) v = make([]uint32, 1, 4)
@ -18644,7 +18644,7 @@ func (_ fastpathT) DecSliceUint64V(v []uint64, checkNil bool, canChange bool, d
changed = true changed = true
} }
slh.End() slh.End()
return return v, changed
} }
if containerLenS > 0 { if containerLenS > 0 {
@ -18703,7 +18703,7 @@ func (_ fastpathT) DecSliceUint64V(v []uint64, checkNil bool, canChange bool, d
changed = true changed = true
} }
slh.End() slh.End()
return return v, changed
} }
if cap(v) == 0 { if cap(v) == 0 {
v = make([]uint64, 1, 4) v = make([]uint64, 1, 4)
@ -18777,7 +18777,7 @@ func (_ fastpathT) DecSliceUintptrV(v []uintptr, checkNil bool, canChange bool,
changed = true changed = true
} }
slh.End() slh.End()
return return v, changed
} }
if containerLenS > 0 { if containerLenS > 0 {
@ -18836,7 +18836,7 @@ func (_ fastpathT) DecSliceUintptrV(v []uintptr, checkNil bool, canChange bool,
changed = true changed = true
} }
slh.End() slh.End()
return return v, changed
} }
if cap(v) == 0 { if cap(v) == 0 {
v = make([]uintptr, 1, 4) v = make([]uintptr, 1, 4)
@ -18910,7 +18910,7 @@ func (_ fastpathT) DecSliceIntV(v []int, checkNil bool, canChange bool, d *Decod
changed = true changed = true
} }
slh.End() slh.End()
return return v, changed
} }
if containerLenS > 0 { if containerLenS > 0 {
@ -18969,7 +18969,7 @@ func (_ fastpathT) DecSliceIntV(v []int, checkNil bool, canChange bool, d *Decod
changed = true changed = true
} }
slh.End() slh.End()
return return v, changed
} }
if cap(v) == 0 { if cap(v) == 0 {
v = make([]int, 1, 4) v = make([]int, 1, 4)
@ -19043,7 +19043,7 @@ func (_ fastpathT) DecSliceInt8V(v []int8, checkNil bool, canChange bool, d *Dec
changed = true changed = true
} }
slh.End() slh.End()
return return v, changed
} }
if containerLenS > 0 { if containerLenS > 0 {
@ -19102,7 +19102,7 @@ func (_ fastpathT) DecSliceInt8V(v []int8, checkNil bool, canChange bool, d *Dec
changed = true changed = true
} }
slh.End() slh.End()
return return v, changed
} }
if cap(v) == 0 { if cap(v) == 0 {
v = make([]int8, 1, 4) v = make([]int8, 1, 4)
@ -19176,7 +19176,7 @@ func (_ fastpathT) DecSliceInt16V(v []int16, checkNil bool, canChange bool, d *D
changed = true changed = true
} }
slh.End() slh.End()
return return v, changed
} }
if containerLenS > 0 { if containerLenS > 0 {
@ -19235,7 +19235,7 @@ func (_ fastpathT) DecSliceInt16V(v []int16, checkNil bool, canChange bool, d *D
changed = true changed = true
} }
slh.End() slh.End()
return return v, changed
} }
if cap(v) == 0 { if cap(v) == 0 {
v = make([]int16, 1, 4) v = make([]int16, 1, 4)
@ -19309,7 +19309,7 @@ func (_ fastpathT) DecSliceInt32V(v []int32, checkNil bool, canChange bool, d *D
changed = true changed = true
} }
slh.End() slh.End()
return return v, changed
} }
if containerLenS > 0 { if containerLenS > 0 {
@ -19368,7 +19368,7 @@ func (_ fastpathT) DecSliceInt32V(v []int32, checkNil bool, canChange bool, d *D
changed = true changed = true
} }
slh.End() slh.End()
return return v, changed
} }
if cap(v) == 0 { if cap(v) == 0 {
v = make([]int32, 1, 4) v = make([]int32, 1, 4)
@ -19442,7 +19442,7 @@ func (_ fastpathT) DecSliceInt64V(v []int64, checkNil bool, canChange bool, d *D
changed = true changed = true
} }
slh.End() slh.End()
return return v, changed
} }
if containerLenS > 0 { if containerLenS > 0 {
@ -19501,7 +19501,7 @@ func (_ fastpathT) DecSliceInt64V(v []int64, checkNil bool, canChange bool, d *D
changed = true changed = true
} }
slh.End() slh.End()
return return v, changed
} }
if cap(v) == 0 { if cap(v) == 0 {
v = make([]int64, 1, 4) v = make([]int64, 1, 4)
@ -19575,7 +19575,7 @@ func (_ fastpathT) DecSliceBoolV(v []bool, checkNil bool, canChange bool, d *Dec
changed = true changed = true
} }
slh.End() slh.End()
return return v, changed
} }
if containerLenS > 0 { if containerLenS > 0 {
@ -19634,7 +19634,7 @@ func (_ fastpathT) DecSliceBoolV(v []bool, checkNil bool, canChange bool, d *Dec
changed = true changed = true
} }
slh.End() slh.End()
return return v, changed
} }
if cap(v) == 0 { if cap(v) == 0 {
v = make([]bool, 1, 4) v = make([]bool, 1, 4)

View File

@ -328,7 +328,7 @@ func (_ fastpathT) {{ .MethodNamePfx "Dec" false }}V(v []{{ .Elem }}, checkNil b
changed = true changed = true
} }
slh.End() slh.End()
return return v, changed
} }
if containerLenS > 0 { if containerLenS > 0 {
@ -391,7 +391,7 @@ func (_ fastpathT) {{ .MethodNamePfx "Dec" false }}V(v []{{ .Elem }}, checkNil b
changed = true changed = true
} }
slh.End() slh.End()
return return v, changed
} }
if cap(v) == 0 { if cap(v) == 0 {
v = make([]{{ .Elem }}, 1, 4) v = make([]{{ .Elem }}, 1, 4)

View File

@ -155,8 +155,10 @@ const (
resetSliceElemToZeroValue bool = false resetSliceElemToZeroValue bool = false
) )
var oneByteArr = [1]byte{0} var (
var zeroByteSlice = oneByteArr[:0:0] oneByteArr = [1]byte{0}
zeroByteSlice = oneByteArr[:0:0]
)
type charEncoding uint8 type charEncoding uint8
@ -215,6 +217,24 @@ const (
containerArrayEnd containerArrayEnd
) )
type rgetPoolT struct {
encNames [8]string
fNames [8]string
etypes [8]uintptr
sfis [8]*structFieldInfo
}
var rgetPool = sync.Pool{
New: func() interface{} { return new(rgetPoolT) },
}
type rgetT struct {
fNames []string
encNames []string
etypes []uintptr
sfis []*structFieldInfo
}
type containerStateRecv interface { type containerStateRecv interface {
sendContainerState(containerState) sendContainerState(containerState)
} }
@ -833,14 +853,17 @@ func (x *TypeInfos) get(rtid uintptr, rt reflect.Type) (pti *typeInfo) {
siInfo = parseStructFieldInfo(structInfoFieldName, x.structTag(f.Tag)) siInfo = parseStructFieldInfo(structInfoFieldName, x.structTag(f.Tag))
ti.toArray = siInfo.toArray ti.toArray = siInfo.toArray
} }
sfip := make([]*structFieldInfo, 0, rt.NumField()) pi := rgetPool.Get()
x.rget(rt, nil, make(map[string]bool, 16), &sfip, siInfo) pv := pi.(*rgetPoolT)
pv.etypes[0] = ti.baseId
ti.sfip = make([]*structFieldInfo, len(sfip)) vv := rgetT{pv.fNames[:0], pv.encNames[:0], pv.etypes[:1], pv.sfis[:0]}
ti.sfi = make([]*structFieldInfo, len(sfip)) x.rget(rt, rtid, nil, &vv, siInfo)
copy(ti.sfip, sfip) ti.sfip = make([]*structFieldInfo, len(vv.sfis))
sort.Sort(sfiSortedByEncName(sfip)) ti.sfi = make([]*structFieldInfo, len(vv.sfis))
copy(ti.sfi, sfip) copy(ti.sfip, vv.sfis)
sort.Sort(sfiSortedByEncName(vv.sfis))
copy(ti.sfi, vv.sfis)
rgetPool.Put(pi)
} }
// sfi = sfip // sfi = sfip
@ -853,16 +876,37 @@ func (x *TypeInfos) get(rtid uintptr, rt reflect.Type) (pti *typeInfo) {
return return
} }
func (x *TypeInfos) rget(rt reflect.Type, indexstack []int, fnameToHastag map[string]bool, func (x *TypeInfos) rget(rt reflect.Type, rtid uintptr,
sfi *[]*structFieldInfo, siInfo *structFieldInfo, indexstack []int, pv *rgetT, siInfo *structFieldInfo,
) { ) {
for j := 0; j < rt.NumField(); j++ { // This will read up the fields and store how to access the value.
// It uses the go language's rules for embedding, as below:
// - if a field has been seen while traversing, skip it
// - if an encName has been seen while traversing, skip it
// - if an embedded type has been seen, skip it
//
// Also, per Go's rules, embedded fields must be analyzed AFTER all top-level fields.
//
// Note: we consciously use slices, not a map, to simulate a set.
// Typically, types have < 16 fields, and iteration using equals is faster than maps there
type anonField struct {
ft reflect.Type
idx int
}
var anonFields []anonField
LOOP:
for j, jlen := 0, rt.NumField(); j < jlen; j++ {
f := rt.Field(j) f := rt.Field(j)
fkind := f.Type.Kind() fkind := f.Type.Kind()
// skip if a func type, or is unexported, or structTag value == "-" // skip if a func type, or is unexported, or structTag value == "-"
if fkind == reflect.Func { switch fkind {
continue case reflect.Func, reflect.Complex64, reflect.Complex128, reflect.UnsafePointer:
continue LOOP
} }
// if r1, _ := utf8.DecodeRuneInString(f.Name); r1 == utf8.RuneError || !unicode.IsUpper(r1) { // if r1, _ := utf8.DecodeRuneInString(f.Name); r1 == utf8.RuneError || !unicode.IsUpper(r1) {
if f.PkgPath != "" && !f.Anonymous { // unexported, not embedded if f.PkgPath != "" && !f.Anonymous { // unexported, not embedded
continue continue
@ -886,11 +930,8 @@ func (x *TypeInfos) rget(rt reflect.Type, indexstack []int, fnameToHastag map[st
ft = ft.Elem() ft = ft.Elem()
} }
if ft.Kind() == reflect.Struct { if ft.Kind() == reflect.Struct {
indexstack2 := make([]int, len(indexstack)+1, len(indexstack)+4) // handle anonymous fields after handling all the non-anon fields
copy(indexstack2, indexstack) anonFields = append(anonFields, anonField{ft, j})
indexstack2[len(indexstack)] = j
// indexstack2 := append(append(make([]int, 0, len(indexstack)+4), indexstack...), j)
x.rget(ft, indexstack2, fnameToHastag, sfi, siInfo)
continue continue
} }
} }
@ -901,26 +942,39 @@ func (x *TypeInfos) rget(rt reflect.Type, indexstack []int, fnameToHastag map[st
continue continue
} }
// 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
// still include their child fields
if _, ok := fnameToHastag[f.Name]; ok {
continue
}
if f.Name == "" { if f.Name == "" {
panic(noFieldNameToStructFieldInfoErr) panic(noFieldNameToStructFieldInfoErr)
} }
for _, k := range pv.fNames {
if k == f.Name {
continue LOOP
}
}
pv.fNames = append(pv.fNames, f.Name)
if si == nil { if si == nil {
si = parseStructFieldInfo(f.Name, stag) si = parseStructFieldInfo(f.Name, stag)
} else if si.encName == "" { } else if si.encName == "" {
si.encName = f.Name si.encName = f.Name
} }
for _, k := range pv.encNames {
if k == si.encName {
continue LOOP
}
}
pv.encNames = append(pv.encNames, si.encName)
// si.ikind = int(f.Type.Kind()) // si.ikind = int(f.Type.Kind())
if len(indexstack) == 0 { if len(indexstack) == 0 {
si.i = int16(j) si.i = int16(j)
} else { } else {
si.i = -1 si.i = -1
si.is = append(append(make([]int, 0, len(indexstack)+4), indexstack...), j) si.is = make([]int, len(indexstack)+1)
copy(si.is, indexstack)
si.is[len(indexstack)] = j
// si.is = append(append(make([]int, 0, len(indexstack)+4), indexstack...), j)
} }
if siInfo != nil { if siInfo != nil {
@ -928,8 +982,26 @@ func (x *TypeInfos) rget(rt reflect.Type, indexstack []int, fnameToHastag map[st
si.omitEmpty = true si.omitEmpty = true
} }
} }
*sfi = append(*sfi, si) pv.sfis = append(pv.sfis, si)
fnameToHastag[f.Name] = stag != "" }
// now handle anonymous fields
LOOP2:
for _, af := range anonFields {
// if etypes contains this, then do not call rget again (as the fields are already seen here)
ftid := reflect.ValueOf(af.ft).Pointer()
for _, k := range pv.etypes {
if k == ftid {
continue LOOP2
}
}
pv.etypes = append(pv.etypes, ftid)
indexstack2 := make([]int, len(indexstack)+1)
copy(indexstack2, indexstack)
indexstack2[len(indexstack)] = af.idx
// indexstack2 := append(append(make([]int, 0, len(indexstack)+4), indexstack...), j)
x.rget(af.ft, ftid, indexstack2, pv, siInfo)
} }
} }
@ -1127,3 +1199,73 @@ type bytesISlice []bytesI
func (p bytesISlice) Len() int { return len(p) } func (p bytesISlice) Len() int { return len(p) }
func (p bytesISlice) Less(i, j int) bool { return bytes.Compare(p[i].v, p[j].v) == -1 } func (p bytesISlice) Less(i, j int) bool { return bytes.Compare(p[i].v, p[j].v) == -1 }
func (p bytesISlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] } func (p bytesISlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
// -----------------
type set []uintptr
func (s *set) add(v uintptr) (exists bool) {
// e.ci is always nil, or len >= 1
// defer func() { fmt.Printf("$$$$$$$$$$$ cirRef Add: %v, exists: %v\n", v, exists) }()
x := *s
if x == nil {
x = make([]uintptr, 1, 8)
x[0] = v
*s = x
return
}
// typically, length will be 1. make this perform.
if len(x) == 1 {
if j := x[0]; j == 0 {
x[0] = v
} else if j == v {
exists = true
} else {
x = append(x, v)
*s = x
}
return
}
// check if it exists
for _, j := range x {
if j == v {
exists = true
return
}
}
// try to replace a "deleted" slot
for i, j := range x {
if j == 0 {
x[i] = v
return
}
}
// if unable to replace deleted slot, just append it.
x = append(x, v)
*s = x
return
}
func (s *set) remove(v uintptr) (exists bool) {
// defer func() { fmt.Printf("$$$$$$$$$$$ cirRef Rm: %v, exists: %v\n", v, exists) }()
x := *s
if len(x) == 0 {
return
}
if len(x) == 1 {
if x[0] == v {
x[0] = 0
}
return
}
for i, j := range x {
if j == v {
exists = true
x[i] = 0 // set it to 0, as way to delete it.
// copy(x[i:], x[i+1:])
// x = x[:len(x)-1]
return
}
}
return
}

View File

@ -43,19 +43,24 @@ import (
//-------------------------------- //--------------------------------
var jsonLiterals = [...]byte{'t', 'r', 'u', 'e', 'f', 'a', 'l', 's', 'e', 'n', 'u', 'l', 'l'} var (
jsonLiterals = [...]byte{'t', 'r', 'u', 'e', 'f', 'a', 'l', 's', 'e', 'n', 'u', 'l', 'l'}
var jsonFloat64Pow10 = [...]float64{ jsonFloat64Pow10 = [...]float64{
1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9,
1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19,
1e20, 1e21, 1e22, 1e20, 1e21, 1e22,
} }
var jsonUint64Pow10 = [...]uint64{ jsonUint64Pow10 = [...]uint64{
1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9,
1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19,
} }
// jsonTabs and jsonSpaces are used as caches for indents
jsonTabs, jsonSpaces string
)
const ( const (
// jsonUnreadAfterDecNum controls whether we unread after decoding a number. // jsonUnreadAfterDecNum controls whether we unread after decoding a number.
// //
@ -85,8 +90,23 @@ const (
jsonNumUintMaxVal = 1<<uint64(64) - 1 jsonNumUintMaxVal = 1<<uint64(64) - 1
// jsonNumDigitsUint64Largest = 19 // jsonNumDigitsUint64Largest = 19
jsonSpacesOrTabsLen = 128
) )
func init() {
var bs [jsonSpacesOrTabsLen]byte
for i := 0; i < jsonSpacesOrTabsLen; i++ {
bs[i] = ' '
}
jsonSpaces = string(bs[:])
for i := 0; i < jsonSpacesOrTabsLen; i++ {
bs[i] = '\t'
}
jsonTabs = string(bs[:])
}
type jsonEncDriver struct { type jsonEncDriver struct {
e *Encoder e *Encoder
w encWriter w encWriter
@ -94,30 +114,76 @@ type jsonEncDriver struct {
b [64]byte // scratch b [64]byte // scratch
bs []byte // scratch bs []byte // scratch
se setExtWrapper se setExtWrapper
ds string // indent string
dl uint16 // indent level
dt bool // indent using tabs
d bool // indent
c containerState c containerState
noBuiltInTypes noBuiltInTypes
} }
// indent is done as below:
// - newline and indent are added before each mapKey or arrayElem
// - newline and indent are added before each ending,
// except there was no entry (so we can have {} or [])
func (e *jsonEncDriver) sendContainerState(c containerState) { func (e *jsonEncDriver) sendContainerState(c containerState) {
// determine whether to output separators // determine whether to output separators
if c == containerMapKey { if c == containerMapKey {
if e.c != containerMapStart { if e.c != containerMapStart {
e.w.writen1(',') e.w.writen1(',')
} }
if e.d {
e.writeIndent()
}
} else if c == containerMapValue { } else if c == containerMapValue {
if e.d {
e.w.writen2(':', ' ')
} else {
e.w.writen1(':') e.w.writen1(':')
}
} else if c == containerMapEnd { } else if c == containerMapEnd {
if e.d {
e.dl--
if e.c != containerMapStart {
e.writeIndent()
}
}
e.w.writen1('}') e.w.writen1('}')
} else if c == containerArrayElem { } else if c == containerArrayElem {
if e.c != containerArrayStart { if e.c != containerArrayStart {
e.w.writen1(',') e.w.writen1(',')
} }
if e.d {
e.writeIndent()
}
} else if c == containerArrayEnd { } else if c == containerArrayEnd {
if e.d {
e.dl--
if e.c != containerArrayStart {
e.writeIndent()
}
}
e.w.writen1(']') e.w.writen1(']')
} }
e.c = c e.c = c
} }
func (e *jsonEncDriver) writeIndent() {
e.w.writen1('\n')
if x := len(e.ds) * int(e.dl); x <= jsonSpacesOrTabsLen {
if e.dt {
e.w.writestr(jsonTabs[:x])
} else {
e.w.writestr(jsonSpaces[:x])
}
} else {
for i := uint16(0); i < e.dl; i++ {
e.w.writestr(e.ds)
}
}
}
func (e *jsonEncDriver) EncodeNil() { func (e *jsonEncDriver) EncodeNil() {
e.w.writeb(jsonLiterals[9:13]) // null e.w.writeb(jsonLiterals[9:13]) // null
} }
@ -165,11 +231,17 @@ func (e *jsonEncDriver) EncodeRawExt(re *RawExt, en *Encoder) {
} }
func (e *jsonEncDriver) EncodeArrayStart(length int) { func (e *jsonEncDriver) EncodeArrayStart(length int) {
if e.d {
e.dl++
}
e.w.writen1('[') e.w.writen1('[')
e.c = containerArrayStart e.c = containerArrayStart
} }
func (e *jsonEncDriver) EncodeMapStart(length int) { func (e *jsonEncDriver) EncodeMapStart(length int) {
if e.d {
e.dl++
}
e.w.writen1('{') e.w.writen1('{')
e.c = containerMapStart e.c = containerMapStart
} }
@ -1033,6 +1105,11 @@ type JsonHandle struct {
// 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
// Indent indicates how a value is encoded.
// - If positive, indent by that number of spaces.
// - If negative, indent by that number of tabs.
Indent int8
} }
func (h *JsonHandle) SetInterfaceExt(rt reflect.Type, tag uint64, ext InterfaceExt) (err error) { func (h *JsonHandle) SetInterfaceExt(rt reflect.Type, tag uint64, ext InterfaceExt) (err error) {
@ -1040,26 +1117,48 @@ func (h *JsonHandle) SetInterfaceExt(rt reflect.Type, tag uint64, ext InterfaceE
} }
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, h: h}
hd.bs = hd.b[:0] hd.bs = hd.b[:0]
hd.se.i = h.RawBytesExt
hd.reset()
return &hd return &hd
} }
func (h *JsonHandle) newDecDriver(d *Decoder) decDriver { func (h *JsonHandle) newDecDriver(d *Decoder) decDriver {
// d := jsonDecDriver{r: r.(*bytesDecReader), h: h} // d := jsonDecDriver{r: r.(*bytesDecReader), h: h}
hd := jsonDecDriver{d: d, r: d.r, h: h} hd := jsonDecDriver{d: d, h: h}
hd.bs = hd.b[:0] hd.bs = hd.b[:0]
hd.se.i = h.RawBytesExt hd.reset()
return &hd return &hd
} }
func (e *jsonEncDriver) reset() { func (e *jsonEncDriver) reset() {
e.w = e.e.w e.w = e.e.w
e.se.i = e.h.RawBytesExt
if e.bs != nil {
e.bs = e.bs[:0]
}
e.d, e.dt, e.dl, e.ds = false, false, 0, ""
e.c = 0
if e.h.Indent > 0 {
e.d = true
e.ds = jsonSpaces[:e.h.Indent]
} else if e.h.Indent < 0 {
e.d = true
e.dt = true
e.ds = jsonTabs[:-(e.h.Indent)]
}
} }
func (d *jsonDecDriver) reset() { func (d *jsonDecDriver) reset() {
d.r = d.d.r d.r = d.d.r
d.se.i = d.h.RawBytesExt
if d.bs != nil {
d.bs = d.bs[:0]
}
d.c, d.tok = 0, 0
d.n.reset()
} }
var jsonEncodeTerminate = []byte{' '} var jsonEncodeTerminate = []byte{' '}

View File

@ -374,7 +374,7 @@ func (d *msgpackDecDriver) DecodeNaked() {
} }
if n.v == valueTypeUint && d.h.SignedInteger { if n.v == valueTypeUint && d.h.SignedInteger {
n.v = valueTypeInt n.v = valueTypeInt
n.i = int64(n.v) n.i = int64(n.u)
} }
return return
} }
@ -729,6 +729,7 @@ func (e *msgpackEncDriver) reset() {
func (d *msgpackDecDriver) reset() { func (d *msgpackDecDriver) reset() {
d.r = d.d.r d.r = d.d.r
d.bd, d.bdRead = 0, false
} }
//-------------------------------------------------- //--------------------------------------------------

View File

@ -512,6 +512,7 @@ func (e *simpleEncDriver) reset() {
func (d *simpleDecDriver) reset() { func (d *simpleDecDriver) reset() {
d.r = d.d.r d.r = d.d.r
d.bd, d.bdRead = 0, false
} }
var _ decDriver = (*simpleDecDriver)(nil) var _ decDriver = (*simpleDecDriver)(nil)

View File

@ -6,6 +6,7 @@
_run() { _run() {
# 1. VARIATIONS: regular (t), canonical (c), IO R/W (i), # 1. VARIATIONS: regular (t), canonical (c), IO R/W (i),
# binc-nosymbols (n), struct2array (s), intern string (e), # binc-nosymbols (n), struct2array (s), intern string (e),
# json-indent (d), circular (l)
# 2. MODE: reflection (r), external (x), codecgen (g), unsafe (u), notfastpath (f) # 2. MODE: reflection (r), external (x), codecgen (g), unsafe (u), notfastpath (f)
# 3. OPTIONS: verbose (v), reset (z), must (m), # 3. OPTIONS: verbose (v), reset (z), must (m),
# #
@ -16,7 +17,7 @@ _run() {
zargs="" zargs=""
local OPTIND local OPTIND
OPTIND=1 OPTIND=1
while getopts "xurtcinsvgzmef" flag while getopts "_xurtcinsvgzmefdl" flag
do do
case "x$flag" in case "x$flag" in
'xr') ;; 'xr') ;;
@ -27,6 +28,7 @@ _run() {
'xv') zargs="$zargs -tv" ;; 'xv') zargs="$zargs -tv" ;;
'xz') zargs="$zargs -tr" ;; 'xz') zargs="$zargs -tr" ;;
'xm') zargs="$zargs -tm" ;; 'xm') zargs="$zargs -tm" ;;
'xl') zargs="$zargs -tl" ;;
*) ;; *) ;;
esac esac
done done
@ -35,15 +37,19 @@ _run() {
# echo ">>>>>>> TAGS: $ztags" # echo ">>>>>>> TAGS: $ztags"
OPTIND=1 OPTIND=1
while getopts "xurtcinsvgzmef" flag while getopts "_xurtcinsvgzmefdl" flag
do do
case "x$flag" in case "x$flag" in
'xt') printf ">>>>>>> REGULAR : "; go test "-tags=$ztags" $zargs ; sleep 2 ;; 'xt') printf ">>>>>>> REGULAR : "; go test "-tags=$ztags" $zargs ; sleep 2 ;;
'xc') printf ">>>>>>> CANONICAL : "; go test "-tags=$ztags" $zargs -tc; sleep 2 ;; 'xc') printf ">>>>>>> CANONICAL : "; go test "-tags=$ztags" $zargs -tc; sleep 2 ;;
'xi') printf ">>>>>>> I/O : "; go test "-tags=$ztags" $zargs -ti; sleep 2 ;; 'xi') printf ">>>>>>> I/O : "; go test "-tags=$ztags" $zargs -ti; sleep 2 ;;
'xn') printf ">>>>>>> NO_SYMBOLS : "; go test "-tags=$ztags" $zargs -tn; sleep 2 ;; 'xn') printf ">>>>>>> NO_SYMBOLS : "; go test "-tags=$ztags" -run=Binc $zargs -tn; sleep 2 ;;
'xs') printf ">>>>>>> TO_ARRAY : "; go test "-tags=$ztags" $zargs -ts; sleep 2 ;; 'xs') printf ">>>>>>> TO_ARRAY : "; go test "-tags=$ztags" $zargs -ts; sleep 2 ;;
'xe') printf ">>>>>>> INTERN : "; go test "-tags=$ztags" $zargs -te; sleep 2 ;; 'xe') printf ">>>>>>> INTERN : "; go test "-tags=$ztags" $zargs -te; sleep 2 ;;
'xd') printf ">>>>>>> INDENT : ";
go test "-tags=$ztags" -run=JsonCodecsTable -td=-1 $zargs;
go test "-tags=$ztags" -run=JsonCodecsTable -td=8 $zargs;
sleep 2 ;;
*) ;; *) ;;
esac esac
done done
@ -55,20 +61,20 @@ _run() {
# echo ">>>>>>> RUNNING VARIATIONS OF TESTS" # echo ">>>>>>> RUNNING VARIATIONS OF TESTS"
if [[ "x$@" = "x" ]]; then if [[ "x$@" = "x" ]]; then
# All: r, x, g, gu # All: r, x, g, gu
_run "-rtcinsm" # regular _run "-_tcinsed_ml" # regular
_run "-rtcinsmz" # regular with reset _run "-_tcinsed_ml_z" # regular with reset
_run "-rtcinsmf" # regular with no fastpath (notfastpath) _run "-_tcinsed_ml_f" # regular with no fastpath (notfastpath)
_run "-xtcinsm" # external _run "-x_tcinsed_ml" # external
_run "-gxtcinsm" # codecgen: requires external _run "-gx_tcinsed_ml" # codecgen: requires external
_run "-gxutcinsm" # codecgen + unsafe _run "-gxu_tcinsed_ml" # codecgen + unsafe
elif [[ "x$@" = "x-Z" ]]; then elif [[ "x$@" = "x-Z" ]]; then
# Regular # Regular
_run "-rtcinsm" # regular _run "-_tcinsed_ml" # regular
_run "-rtcinsmz" # regular with reset _run "-_tcinsed_ml_z" # regular with reset
elif [[ "x$@" = "x-F" ]]; then elif [[ "x$@" = "x-F" ]]; then
# regular with notfastpath # regular with notfastpath
_run "-rtcinsmf" # regular _run "-_tcinsed_ml_f" # regular
_run "-rtcinsmzf" # regular with reset _run "-_tcinsed_ml_zf" # regular with reset
else else
_run "$@" _run "$@"
fi fi

View File

@ -5,11 +5,22 @@ package codec
import ( import (
"fmt" "fmt"
"reflect"
"time" "time"
) )
var ( 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'}
timeExtEncFn = func(rv reflect.Value) (bs []byte, err error) {
defer panicToErr(&err)
bs = timeExt{}.WriteExt(rv.Interface())
return
}
timeExtDecFn = func(rv reflect.Value, bs []byte) (err error) {
defer panicToErr(&err)
timeExt{}.ReadExt(rv.Interface(), bs)
return
}
) )
type timeExt struct{} type timeExt struct{}