diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index e972985bceb..736ac9c9992 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -931,7 +931,7 @@ }, { "ImportPath": "github.com/ugorji/go/codec", - "Rev": "f1f1a805ed361a0e078bb537e4ea78cd37dcf065" + "Rev": "4a79e5b7b21e51ae8d61641bca20399b79735a32" }, { "ImportPath": "github.com/vishvananda/netlink", diff --git a/Godeps/_workspace/src/github.com/ugorji/go/codec/0doc.go b/Godeps/_workspace/src/github.com/ugorji/go/codec/0doc.go index caa7e0a3b50..7f71f0ecbfe 100644 --- a/Godeps/_workspace/src/github.com/ugorji/go/codec/0doc.go +++ b/Godeps/_workspace/src/github.com/ugorji/go/codec/0doc.go @@ -64,6 +64,7 @@ Rich Feature Set includes: - Never silently skip data when decoding. User decides whether to return an error or silently skip data when keys or indexes in the data stream do not map to fields in the struct. + - Detect and error when encoding a cyclic reference (instead of stack overflow shutdown) - Encode/Decode from/to chan types (for iterative streaming support) - Drop-in replacement for encoding/json. `json:` key in struct tag supported. - Provides a RPC Server and Client Codec for net/rpc communication protocol. @@ -171,6 +172,8 @@ package codec // TODO: // +// - optimization for codecgen: +// if len of entity is <= 3 words, then support a value receiver for encode. // - (En|De)coder should store an error when it occurs. // Until reset, subsequent calls return that error that was stored. // This means that free panics must go away. @@ -190,4 +193,7 @@ package codec // - 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? +// - 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 } } diff --git a/Godeps/_workspace/src/github.com/ugorji/go/codec/binc.go b/Godeps/_workspace/src/github.com/ugorji/go/codec/binc.go index c884d14dce5..766d26cf6d7 100644 --- a/Godeps/_workspace/src/github.com/ugorji/go/codec/binc.go +++ b/Godeps/_workspace/src/github.com/ugorji/go/codec/binc.go @@ -908,10 +908,14 @@ func (h *BincHandle) newDecDriver(d *Decoder) decDriver { func (e *bincEncDriver) reset() { e.w = e.e.w + e.s = 0 + e.m = nil } func (d *bincDecDriver) reset() { d.r = d.d.r + d.s = nil + d.bd, d.bdRead, d.vd, d.vs = 0, false, 0, 0 } var _ decDriver = (*bincDecDriver)(nil) diff --git a/Godeps/_workspace/src/github.com/ugorji/go/codec/cbor.go b/Godeps/_workspace/src/github.com/ugorji/go/codec/cbor.go index 0e5d32b2ea9..cfd89b7a434 100644 --- a/Godeps/_workspace/src/github.com/ugorji/go/codec/cbor.go +++ b/Godeps/_workspace/src/github.com/ugorji/go/codec/cbor.go @@ -578,6 +578,7 @@ func (e *cborEncDriver) reset() { func (d *cborDecDriver) reset() { d.r = d.d.r + d.bd, d.bdRead = 0, false } var _ decDriver = (*cborDecDriver)(nil) diff --git a/Godeps/_workspace/src/github.com/ugorji/go/codec/decode.go b/Godeps/_workspace/src/github.com/ugorji/go/codec/decode.go index b3b99f03670..d842a24ba88 100644 --- a/Godeps/_workspace/src/github.com/ugorji/go/codec/decode.go +++ b/Godeps/_workspace/src/github.com/ugorji/go/codec/decode.go @@ -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 { d.d.uncacheRead() d.r.track() diff --git a/Godeps/_workspace/src/github.com/ugorji/go/codec/encode.go b/Godeps/_workspace/src/github.com/ugorji/go/codec/encode.go index 99af6fa555a..d7ad330201c 100644 --- a/Godeps/_workspace/src/github.com/ugorji/go/codec/encode.go +++ b/Godeps/_workspace/src/github.com/ugorji/go/codec/encode.go @@ -110,6 +110,15 @@ type EncodeOptions struct { // 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. // // Encoding as symbols can reduce the encoded size significantly. @@ -503,7 +512,7 @@ func (f *encFnInfo) kStruct(rv reflect.Value) { newlen := len(fti.sfi) // 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) // 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 for _, si := range tisfi { 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 si.omitEmpty && isEmptyValue(kv.r) { continue @@ -596,13 +600,15 @@ func (f *encFnInfo) kStruct(rv reflect.Value) { // f.e.encodeValue(rv.Elem()) // } -func (f *encFnInfo) kInterface(rv reflect.Value) { - if rv.IsNil() { - f.e.e.EncodeNil() - return - } - f.e.encodeValue(rv.Elem(), nil) -} +// func (f *encFnInfo) kInterface(rv reflect.Value) { +// println("kInterface called") +// debug.PrintStack() +// if rv.IsNil() { +// f.e.e.EncodeNil() +// return +// } +// f.e.encodeValue(rv.Elem(), nil) +// } func (f *encFnInfo) kMap(rv reflect.Value) { ee := f.e.e @@ -877,6 +883,7 @@ type Encoder struct { // as the handler MAY need to do some coordination. w encWriter s []encRtidFn + ci set be bool // is binary encoding js bool // is json handle @@ -1133,20 +1140,23 @@ func (e *Encoder) encode(iv interface{}) { } } -func (e *Encoder) encodeI(iv interface{}, checkFastpath, checkCodecSelfer 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) { +func (e *Encoder) preEncodeValue(rv reflect.Value) (rv2 reflect.Value, sptr uintptr, proceed bool) { // use a goto statement instead of a recursive function for ptr/interface. TOP: 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() { e.e.EncodeNil() return @@ -1163,18 +1173,39 @@ TOP: return } - return rv, true + proceed = true + rv2 = rv + return +} + +func (e *Encoder) doEncodeValue(rv reflect.Value, fn *encFn, sptr uintptr, + checkFastpath, checkCodecSelfer bool) { + if sptr != 0 { + if (&e.ci).add(sptr) { + e.errorf("circular reference found: # %d", sptr) + } + } + if fn == nil { + rt := rv.Type() + rtid := reflect.ValueOf(rt).Pointer() + fn = e.getEncFn(rtid, rt, true, true) + } + 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, proceed := e.preEncodeValue(rv); proceed { - if fn == nil { - rt := rv.Type() - rtid := reflect.ValueOf(rt).Pointer() - fn = e.getEncFn(rtid, rt, true, true) - } - fn.f(&fn.i, 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 case reflect.Struct: fn.f = (*encFnInfo).kStruct + // reflect.Ptr and reflect.Interface are handled already by preEncodeValue // case reflect.Ptr: // fn.f = (*encFnInfo).kPtr - case reflect.Interface: - fn.f = (*encFnInfo).kInterface + // case reflect.Interface: + // fn.f = (*encFnInfo).kInterface case reflect.Map: fn.f = (*encFnInfo).kMap 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 // } // 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 { p = &encStructPool[0] v = p.Get() diff --git a/Godeps/_workspace/src/github.com/ugorji/go/codec/fast-path.generated.go b/Godeps/_workspace/src/github.com/ugorji/go/codec/fast-path.generated.go index d968a500fde..5cac047aff2 100644 --- a/Godeps/_workspace/src/github.com/ugorji/go/codec/fast-path.generated.go +++ b/Godeps/_workspace/src/github.com/ugorji/go/codec/fast-path.generated.go @@ -17712,7 +17712,7 @@ func (_ fastpathT) DecSliceIntfV(v []interface{}, checkNil bool, canChange bool, changed = true } slh.End() - return + return v, changed } if containerLenS > 0 { @@ -17771,7 +17771,7 @@ func (_ fastpathT) DecSliceIntfV(v []interface{}, checkNil bool, canChange bool, changed = true } slh.End() - return + return v, changed } if cap(v) == 0 { v = make([]interface{}, 1, 4) @@ -17846,7 +17846,7 @@ func (_ fastpathT) DecSliceStringV(v []string, checkNil bool, canChange bool, d changed = true } slh.End() - return + return v, changed } if containerLenS > 0 { @@ -17905,7 +17905,7 @@ func (_ fastpathT) DecSliceStringV(v []string, checkNil bool, canChange bool, d changed = true } slh.End() - return + return v, changed } if cap(v) == 0 { v = make([]string, 1, 4) @@ -17979,7 +17979,7 @@ func (_ fastpathT) DecSliceFloat32V(v []float32, checkNil bool, canChange bool, changed = true } slh.End() - return + return v, changed } if containerLenS > 0 { @@ -18038,7 +18038,7 @@ func (_ fastpathT) DecSliceFloat32V(v []float32, checkNil bool, canChange bool, changed = true } slh.End() - return + return v, changed } if cap(v) == 0 { v = make([]float32, 1, 4) @@ -18112,7 +18112,7 @@ func (_ fastpathT) DecSliceFloat64V(v []float64, checkNil bool, canChange bool, changed = true } slh.End() - return + return v, changed } if containerLenS > 0 { @@ -18171,7 +18171,7 @@ func (_ fastpathT) DecSliceFloat64V(v []float64, checkNil bool, canChange bool, changed = true } slh.End() - return + return v, changed } if cap(v) == 0 { v = make([]float64, 1, 4) @@ -18245,7 +18245,7 @@ func (_ fastpathT) DecSliceUintV(v []uint, checkNil bool, canChange bool, d *Dec changed = true } slh.End() - return + return v, changed } if containerLenS > 0 { @@ -18304,7 +18304,7 @@ func (_ fastpathT) DecSliceUintV(v []uint, checkNil bool, canChange bool, d *Dec changed = true } slh.End() - return + return v, changed } if cap(v) == 0 { v = make([]uint, 1, 4) @@ -18378,7 +18378,7 @@ func (_ fastpathT) DecSliceUint16V(v []uint16, checkNil bool, canChange bool, d changed = true } slh.End() - return + return v, changed } if containerLenS > 0 { @@ -18437,7 +18437,7 @@ func (_ fastpathT) DecSliceUint16V(v []uint16, checkNil bool, canChange bool, d changed = true } slh.End() - return + return v, changed } if cap(v) == 0 { v = make([]uint16, 1, 4) @@ -18511,7 +18511,7 @@ func (_ fastpathT) DecSliceUint32V(v []uint32, checkNil bool, canChange bool, d changed = true } slh.End() - return + return v, changed } if containerLenS > 0 { @@ -18570,7 +18570,7 @@ func (_ fastpathT) DecSliceUint32V(v []uint32, checkNil bool, canChange bool, d changed = true } slh.End() - return + return v, changed } if cap(v) == 0 { v = make([]uint32, 1, 4) @@ -18644,7 +18644,7 @@ func (_ fastpathT) DecSliceUint64V(v []uint64, checkNil bool, canChange bool, d changed = true } slh.End() - return + return v, changed } if containerLenS > 0 { @@ -18703,7 +18703,7 @@ func (_ fastpathT) DecSliceUint64V(v []uint64, checkNil bool, canChange bool, d changed = true } slh.End() - return + return v, changed } if cap(v) == 0 { v = make([]uint64, 1, 4) @@ -18777,7 +18777,7 @@ func (_ fastpathT) DecSliceUintptrV(v []uintptr, checkNil bool, canChange bool, changed = true } slh.End() - return + return v, changed } if containerLenS > 0 { @@ -18836,7 +18836,7 @@ func (_ fastpathT) DecSliceUintptrV(v []uintptr, checkNil bool, canChange bool, changed = true } slh.End() - return + return v, changed } if cap(v) == 0 { v = make([]uintptr, 1, 4) @@ -18910,7 +18910,7 @@ func (_ fastpathT) DecSliceIntV(v []int, checkNil bool, canChange bool, d *Decod changed = true } slh.End() - return + return v, changed } if containerLenS > 0 { @@ -18969,7 +18969,7 @@ func (_ fastpathT) DecSliceIntV(v []int, checkNil bool, canChange bool, d *Decod changed = true } slh.End() - return + return v, changed } if cap(v) == 0 { v = make([]int, 1, 4) @@ -19043,7 +19043,7 @@ func (_ fastpathT) DecSliceInt8V(v []int8, checkNil bool, canChange bool, d *Dec changed = true } slh.End() - return + return v, changed } if containerLenS > 0 { @@ -19102,7 +19102,7 @@ func (_ fastpathT) DecSliceInt8V(v []int8, checkNil bool, canChange bool, d *Dec changed = true } slh.End() - return + return v, changed } if cap(v) == 0 { v = make([]int8, 1, 4) @@ -19176,7 +19176,7 @@ func (_ fastpathT) DecSliceInt16V(v []int16, checkNil bool, canChange bool, d *D changed = true } slh.End() - return + return v, changed } if containerLenS > 0 { @@ -19235,7 +19235,7 @@ func (_ fastpathT) DecSliceInt16V(v []int16, checkNil bool, canChange bool, d *D changed = true } slh.End() - return + return v, changed } if cap(v) == 0 { v = make([]int16, 1, 4) @@ -19309,7 +19309,7 @@ func (_ fastpathT) DecSliceInt32V(v []int32, checkNil bool, canChange bool, d *D changed = true } slh.End() - return + return v, changed } if containerLenS > 0 { @@ -19368,7 +19368,7 @@ func (_ fastpathT) DecSliceInt32V(v []int32, checkNil bool, canChange bool, d *D changed = true } slh.End() - return + return v, changed } if cap(v) == 0 { v = make([]int32, 1, 4) @@ -19442,7 +19442,7 @@ func (_ fastpathT) DecSliceInt64V(v []int64, checkNil bool, canChange bool, d *D changed = true } slh.End() - return + return v, changed } if containerLenS > 0 { @@ -19501,7 +19501,7 @@ func (_ fastpathT) DecSliceInt64V(v []int64, checkNil bool, canChange bool, d *D changed = true } slh.End() - return + return v, changed } if cap(v) == 0 { v = make([]int64, 1, 4) @@ -19575,7 +19575,7 @@ func (_ fastpathT) DecSliceBoolV(v []bool, checkNil bool, canChange bool, d *Dec changed = true } slh.End() - return + return v, changed } if containerLenS > 0 { @@ -19634,7 +19634,7 @@ func (_ fastpathT) DecSliceBoolV(v []bool, checkNil bool, canChange bool, d *Dec changed = true } slh.End() - return + return v, changed } if cap(v) == 0 { v = make([]bool, 1, 4) diff --git a/Godeps/_workspace/src/github.com/ugorji/go/codec/fast-path.go.tmpl b/Godeps/_workspace/src/github.com/ugorji/go/codec/fast-path.go.tmpl index 58cc6df4c54..3f43dc68780 100644 --- a/Godeps/_workspace/src/github.com/ugorji/go/codec/fast-path.go.tmpl +++ b/Godeps/_workspace/src/github.com/ugorji/go/codec/fast-path.go.tmpl @@ -328,7 +328,7 @@ func (_ fastpathT) {{ .MethodNamePfx "Dec" false }}V(v []{{ .Elem }}, checkNil b changed = true } slh.End() - return + return v, changed } if containerLenS > 0 { @@ -391,7 +391,7 @@ func (_ fastpathT) {{ .MethodNamePfx "Dec" false }}V(v []{{ .Elem }}, checkNil b changed = true } slh.End() - return + return v, changed } if cap(v) == 0 { v = make([]{{ .Elem }}, 1, 4) diff --git a/Godeps/_workspace/src/github.com/ugorji/go/codec/helper.go b/Godeps/_workspace/src/github.com/ugorji/go/codec/helper.go index 560014ae393..40065a01c8b 100644 --- a/Godeps/_workspace/src/github.com/ugorji/go/codec/helper.go +++ b/Godeps/_workspace/src/github.com/ugorji/go/codec/helper.go @@ -155,8 +155,10 @@ const ( resetSliceElemToZeroValue bool = false ) -var oneByteArr = [1]byte{0} -var zeroByteSlice = oneByteArr[:0:0] +var ( + oneByteArr = [1]byte{0} + zeroByteSlice = oneByteArr[:0:0] +) type charEncoding uint8 @@ -215,6 +217,24 @@ const ( 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 { sendContainerState(containerState) } @@ -833,14 +853,17 @@ func (x *TypeInfos) get(rtid uintptr, rt reflect.Type) (pti *typeInfo) { siInfo = parseStructFieldInfo(structInfoFieldName, x.structTag(f.Tag)) ti.toArray = siInfo.toArray } - sfip := make([]*structFieldInfo, 0, rt.NumField()) - x.rget(rt, nil, make(map[string]bool, 16), &sfip, siInfo) - - ti.sfip = make([]*structFieldInfo, len(sfip)) - ti.sfi = make([]*structFieldInfo, len(sfip)) - copy(ti.sfip, sfip) - sort.Sort(sfiSortedByEncName(sfip)) - copy(ti.sfi, sfip) + pi := rgetPool.Get() + pv := pi.(*rgetPoolT) + pv.etypes[0] = ti.baseId + vv := rgetT{pv.fNames[:0], pv.encNames[:0], pv.etypes[:1], pv.sfis[:0]} + x.rget(rt, rtid, nil, &vv, siInfo) + ti.sfip = make([]*structFieldInfo, len(vv.sfis)) + ti.sfi = make([]*structFieldInfo, len(vv.sfis)) + copy(ti.sfip, vv.sfis) + sort.Sort(sfiSortedByEncName(vv.sfis)) + copy(ti.sfi, vv.sfis) + rgetPool.Put(pi) } // sfi = sfip @@ -853,16 +876,37 @@ func (x *TypeInfos) get(rtid uintptr, rt reflect.Type) (pti *typeInfo) { return } -func (x *TypeInfos) rget(rt reflect.Type, indexstack []int, fnameToHastag map[string]bool, - sfi *[]*structFieldInfo, siInfo *structFieldInfo, +func (x *TypeInfos) rget(rt reflect.Type, rtid uintptr, + 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) fkind := f.Type.Kind() // skip if a func type, or is unexported, or structTag value == "-" - if fkind == reflect.Func { - continue + switch fkind { + case reflect.Func, reflect.Complex64, reflect.Complex128, reflect.UnsafePointer: + continue LOOP } + // if r1, _ := utf8.DecodeRuneInString(f.Name); r1 == utf8.RuneError || !unicode.IsUpper(r1) { if f.PkgPath != "" && !f.Anonymous { // unexported, not embedded continue @@ -886,11 +930,8 @@ func (x *TypeInfos) rget(rt reflect.Type, indexstack []int, fnameToHastag map[st 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) + // handle anonymous fields after handling all the non-anon fields + anonFields = append(anonFields, anonField{ft, j}) continue } } @@ -901,26 +942,39 @@ func (x *TypeInfos) rget(rt reflect.Type, indexstack []int, fnameToHastag map[st 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 == "" { panic(noFieldNameToStructFieldInfoErr) } + + for _, k := range pv.fNames { + if k == f.Name { + continue LOOP + } + } + pv.fNames = append(pv.fNames, f.Name) + if si == nil { si = parseStructFieldInfo(f.Name, stag) } else if si.encName == "" { 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()) if len(indexstack) == 0 { si.i = int16(j) } else { 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 { @@ -928,8 +982,26 @@ func (x *TypeInfos) rget(rt reflect.Type, indexstack []int, fnameToHastag map[st si.omitEmpty = true } } - *sfi = append(*sfi, si) - fnameToHastag[f.Name] = stag != "" + pv.sfis = append(pv.sfis, si) + } + + // 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) 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] } + +// ----------------- + +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 +} diff --git a/Godeps/_workspace/src/github.com/ugorji/go/codec/json.go b/Godeps/_workspace/src/github.com/ugorji/go/codec/json.go index a18a5f7063e..142d5b52a85 100644 --- a/Godeps/_workspace/src/github.com/ugorji/go/codec/json.go +++ b/Godeps/_workspace/src/github.com/ugorji/go/codec/json.go @@ -43,18 +43,23 @@ 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{ - 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, - 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, - 1e20, 1e21, 1e22, -} + jsonFloat64Pow10 = [...]float64{ + 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, + 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, + 1e20, 1e21, 1e22, + } -var jsonUint64Pow10 = [...]uint64{ - 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, - 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, -} + jsonUint64Pow10 = [...]uint64{ + 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, + 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, + } + + // jsonTabs and jsonSpaces are used as caches for indents + jsonTabs, jsonSpaces string +) const ( // jsonUnreadAfterDecNum controls whether we unread after decoding a number. @@ -85,8 +90,23 @@ const ( jsonNumUintMaxVal = 1< 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() { 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{' '} diff --git a/Godeps/_workspace/src/github.com/ugorji/go/codec/msgpack.go b/Godeps/_workspace/src/github.com/ugorji/go/codec/msgpack.go index 5eb4c96368c..f9f87236277 100644 --- a/Godeps/_workspace/src/github.com/ugorji/go/codec/msgpack.go +++ b/Godeps/_workspace/src/github.com/ugorji/go/codec/msgpack.go @@ -374,7 +374,7 @@ func (d *msgpackDecDriver) DecodeNaked() { } if n.v == valueTypeUint && d.h.SignedInteger { n.v = valueTypeInt - n.i = int64(n.v) + n.i = int64(n.u) } return } @@ -729,6 +729,7 @@ func (e *msgpackEncDriver) reset() { func (d *msgpackDecDriver) reset() { d.r = d.d.r + d.bd, d.bdRead = 0, false } //-------------------------------------------------- diff --git a/Godeps/_workspace/src/github.com/ugorji/go/codec/simple.go b/Godeps/_workspace/src/github.com/ugorji/go/codec/simple.go index c1504965095..7c0ba7affc7 100644 --- a/Godeps/_workspace/src/github.com/ugorji/go/codec/simple.go +++ b/Godeps/_workspace/src/github.com/ugorji/go/codec/simple.go @@ -512,6 +512,7 @@ func (e *simpleEncDriver) reset() { func (d *simpleDecDriver) reset() { d.r = d.d.r + d.bd, d.bdRead = 0, false } var _ decDriver = (*simpleDecDriver)(nil) diff --git a/Godeps/_workspace/src/github.com/ugorji/go/codec/tests.sh b/Godeps/_workspace/src/github.com/ugorji/go/codec/tests.sh index b1602ea7e75..00857b6209a 100644 --- a/Godeps/_workspace/src/github.com/ugorji/go/codec/tests.sh +++ b/Godeps/_workspace/src/github.com/ugorji/go/codec/tests.sh @@ -6,6 +6,7 @@ _run() { # 1. VARIATIONS: regular (t), canonical (c), IO R/W (i), # binc-nosymbols (n), struct2array (s), intern string (e), + # json-indent (d), circular (l) # 2. MODE: reflection (r), external (x), codecgen (g), unsafe (u), notfastpath (f) # 3. OPTIONS: verbose (v), reset (z), must (m), # @@ -16,7 +17,7 @@ _run() { zargs="" local OPTIND OPTIND=1 - while getopts "xurtcinsvgzmef" flag + while getopts "_xurtcinsvgzmefdl" flag do case "x$flag" in 'xr') ;; @@ -27,6 +28,7 @@ _run() { 'xv') zargs="$zargs -tv" ;; 'xz') zargs="$zargs -tr" ;; 'xm') zargs="$zargs -tm" ;; + 'xl') zargs="$zargs -tl" ;; *) ;; esac done @@ -35,15 +37,19 @@ _run() { # echo ">>>>>>> TAGS: $ztags" OPTIND=1 - while getopts "xurtcinsvgzmef" flag + while getopts "_xurtcinsvgzmefdl" flag do case "x$flag" in 'xt') printf ">>>>>>> REGULAR : "; go test "-tags=$ztags" $zargs ; sleep 2 ;; 'xc') printf ">>>>>>> CANONICAL : "; go test "-tags=$ztags" $zargs -tc; sleep 2 ;; 'xi') printf ">>>>>>> I/O : "; go test "-tags=$ztags" $zargs -ti; sleep 2 ;; - 'xn') printf ">>>>>>> NO_SYMBOLS : "; go test "-tags=$ztags" $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 ;; 'xe') printf ">>>>>>> INTERN : "; go test "-tags=$ztags" $zargs -te; sleep 2 ;; + 'xd') printf ">>>>>>> INDENT : "; + go test "-tags=$ztags" -run=JsonCodecsTable -td=-1 $zargs; + go test "-tags=$ztags" -run=JsonCodecsTable -td=8 $zargs; + sleep 2 ;; *) ;; esac done @@ -55,20 +61,20 @@ _run() { # echo ">>>>>>> RUNNING VARIATIONS OF TESTS" if [[ "x$@" = "x" ]]; then # All: r, x, g, gu - _run "-rtcinsm" # regular - _run "-rtcinsmz" # regular with reset - _run "-rtcinsmf" # regular with no fastpath (notfastpath) - _run "-xtcinsm" # external - _run "-gxtcinsm" # codecgen: requires external - _run "-gxutcinsm" # codecgen + unsafe + _run "-_tcinsed_ml" # regular + _run "-_tcinsed_ml_z" # regular with reset + _run "-_tcinsed_ml_f" # regular with no fastpath (notfastpath) + _run "-x_tcinsed_ml" # external + _run "-gx_tcinsed_ml" # codecgen: requires external + _run "-gxu_tcinsed_ml" # codecgen + unsafe elif [[ "x$@" = "x-Z" ]]; then # Regular - _run "-rtcinsm" # regular - _run "-rtcinsmz" # regular with reset + _run "-_tcinsed_ml" # regular + _run "-_tcinsed_ml_z" # regular with reset elif [[ "x$@" = "x-F" ]]; then # regular with notfastpath - _run "-rtcinsmf" # regular - _run "-rtcinsmzf" # regular with reset + _run "-_tcinsed_ml_f" # regular + _run "-_tcinsed_ml_zf" # regular with reset else _run "$@" fi diff --git a/Godeps/_workspace/src/github.com/ugorji/go/codec/time.go b/Godeps/_workspace/src/github.com/ugorji/go/codec/time.go index fc4c63e1def..718b731ec58 100644 --- a/Godeps/_workspace/src/github.com/ugorji/go/codec/time.go +++ b/Godeps/_workspace/src/github.com/ugorji/go/codec/time.go @@ -5,11 +5,22 @@ package codec import ( "fmt" + "reflect" "time" ) 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{}