Update dependency on ugorji/go/codec.

pull/6/head
Wojciech Tyczynski 2015-10-14 11:24:58 +02:00
parent f3e0bb0d41
commit 6a035833ac
13 changed files with 9509 additions and 2092 deletions

2
Godeps/Godeps.json generated
View File

@ -564,7 +564,7 @@
},
{
"ImportPath": "github.com/ugorji/go/codec",
"Rev": "2f4b94206aae781e63846a9bf02ad83c387d5296"
"Rev": "8a2a3a8c488c3ebd98f422a965260278267a0551"
},
{
"ImportPath": "github.com/vaughan0/go-ini",

View File

@ -41,10 +41,6 @@ package {{ $.PackageName }}
import (
{{ if not .CodecPkgFiles }}{{ .CodecPkgName }} "{{ .CodecImportPath }}"{{ end }}
{{/*
{{ if .Types }}"{{ .ImportPath }}"{{ end }}
"io"
*/}}
"os"
"reflect"
"bytes"
@ -52,14 +48,6 @@ import (
"go/format"
)
{{/* This is not used anymore. Remove it.
func write(w io.Writer, s string) {
if _, err := io.WriteString(w, s); err != nil {
panic(err)
}
}
*/}}
func CodecGenTempWrite{{ .RandString }}() {
fout, err := os.Create("{{ .OutFile }}")
if err != nil {

View File

@ -95,6 +95,14 @@ type DecodeOptions struct {
// If nil, we use []interface{}
SliceType reflect.Type
// MaxInitLen defines the initial length that we "make" a collection (slice, chan or map) with.
// If 0 or negative, we default to a sensible value based on the size of an element in the collection.
//
// For example, when decoding, a stream may say that it has MAX_UINT elements.
// We should not auto-matically provision a slice of that length, to prevent Out-Of-Memory crash.
// Instead, we provision up to MaxInitLen, fill that up, and start appending after that.
MaxInitLen int
// If ErrorIfNoField, return an error when decoding a map
// from a codec stream into a struct, and no matching struct field is found.
ErrorIfNoField bool
@ -107,13 +115,42 @@ type DecodeOptions struct {
// If SignedInteger, use the int64 during schema-less decoding of unsigned values (not uint64).
SignedInteger bool
// MaxInitLen defines the initial length that we "make" a collection (slice, chan or map) with.
// If 0 or negative, we default to a sensible value based on the size of an element in the collection.
// MapValueReset controls how we decode into a map value.
//
// For example, when decoding, a stream may say that it has MAX_UINT elements.
// We should not auto-matically provision a slice of that length, to prevent Out-Of-Memory crash.
// Instead, we provision up to MaxInitLen, fill that up, and start appending after that.
MaxInitLen int
// By default, we MAY retrieve the mapping for a key, and then decode into that.
// However, especially with big maps, that retrieval may be expensive and unnecessary
// if the stream already contains all that is necessary to recreate the value.
//
// If true, we will never retrieve the previous mapping,
// but rather decode into a new value and set that in the map.
//
// If false, we will retrieve the previous mapping if necessary e.g.
// the previous mapping is a pointer, or is a struct or array with pre-set state,
// or is an interface.
MapValueReset bool
// InterfaceReset controls how we decode into an interface.
//
// By default, when we see a field that is an interface{...},
// or a map with interface{...} value, we will attempt decoding into the
// "contained" value.
//
// However, this prevents us from reading a string into an interface{}
// that formerly contained a number.
//
// If true, we will decode into a new "blank" value, and set that in the interface.
// If false, we will decode into whatever is contained in the interface.
InterfaceReset bool
// InternString controls interning of strings during decoding.
//
// Some handles, e.g. json, typically will read map keys as strings.
// If the set of keys are finite, it may help reduce allocation to
// look them up from a map (than to allocate them afresh).
//
// Note: Handles will be smart when using the intern functionality.
// So everything will not be interned.
InternString bool
}
// ------------------------------------
@ -582,25 +619,34 @@ func (f *decFnInfo) kInterface(rv reflect.Value) {
// to decode into what was there before.
// We do not replace with a generic value (as got from decodeNaked).
var rvn reflect.Value
if rv.IsNil() {
rvn := f.kInterfaceNaked()
rvn = f.kInterfaceNaked()
if rvn.IsValid() {
rv.Set(rvn)
}
} else if f.d.h.InterfaceReset {
rvn = f.kInterfaceNaked()
if rvn.IsValid() {
rv.Set(rvn)
} else {
// reset to zero value based on current type in there.
rv.Set(reflect.Zero(rv.Elem().Type()))
}
} else {
rve := rv.Elem()
rvn = rv.Elem()
// Note: interface{} is settable, but underlying type may not be.
// Consequently, we have to set the reflect.Value directly.
// if underlying type is settable (e.g. ptr or interface),
// we just decode into it.
// Else we create a settable value, decode into it, and set on the interface.
if rve.CanSet() {
f.d.decodeValue(rve, nil)
if rvn.CanSet() {
f.d.decodeValue(rvn, nil)
} else {
rve2 := reflect.New(rve.Type()).Elem()
rve2.Set(rve)
f.d.decodeValue(rve2, nil)
rv.Set(rve2)
rvn2 := reflect.New(rvn.Type()).Elem()
rvn2.Set(rvn)
f.d.decodeValue(rvn2, nil)
rv.Set(rvn2)
}
}
}
@ -887,22 +933,45 @@ func (f *decFnInfo) kMap(rv reflect.Value) {
for xtyp = vtype; xtyp.Kind() == reflect.Ptr; xtyp = xtyp.Elem() {
}
valFn = d.getDecFn(xtyp, true, true)
var mapGet bool
if !f.d.h.MapValueReset {
// if pointer, mapGet = true
// if interface, mapGet = true if !DecodeNakedAlways (else false)
// if builtin, mapGet = false
// else mapGet = true
vtypeKind := vtype.Kind()
if vtypeKind == reflect.Ptr {
mapGet = true
} else if vtypeKind == reflect.Interface {
if !f.d.h.InterfaceReset {
mapGet = true
}
} else if !isImmutableKind(vtypeKind) {
mapGet = true
}
}
var rvk, rvv reflect.Value
// for j := 0; j < containerLen; j++ {
if containerLen > 0 {
for j := 0; j < containerLen; j++ {
rvk := reflect.New(ktype).Elem()
rvk = reflect.New(ktype).Elem()
d.decodeValue(rvk, keyFn)
// special case if a byte array.
if ktypeId == intfTypId {
rvk = rvk.Elem()
if rvk.Type() == uint8SliceTyp {
rvk = reflect.ValueOf(string(rvk.Bytes()))
rvk = reflect.ValueOf(d.string(rvk.Bytes()))
}
}
rvv := rv.MapIndex(rvk)
// TODO: is !IsValid check required?
if !rvv.IsValid() {
if mapGet {
rvv = rv.MapIndex(rvk)
if !rvv.IsValid() {
rvv = reflect.New(vtype).Elem()
}
} else {
rvv = reflect.New(vtype).Elem()
}
d.decodeValue(rvv, valFn)
@ -910,18 +979,22 @@ func (f *decFnInfo) kMap(rv reflect.Value) {
}
} else {
for j := 0; !dd.CheckBreak(); j++ {
rvk := reflect.New(ktype).Elem()
rvk = reflect.New(ktype).Elem()
d.decodeValue(rvk, keyFn)
// special case if a byte array.
if ktypeId == intfTypId {
rvk = rvk.Elem()
if rvk.Type() == uint8SliceTyp {
rvk = reflect.ValueOf(string(rvk.Bytes()))
rvk = reflect.ValueOf(d.string(rvk.Bytes()))
}
}
rvv := rv.MapIndex(rvk)
if !rvv.IsValid() {
if mapGet {
rvv = rv.MapIndex(rvk)
if !rvv.IsValid() {
rvv = reflect.New(vtype).Elem()
}
} else {
rvv = reflect.New(vtype).Elem()
}
d.decodeValue(rvv, valFn)
@ -957,6 +1030,8 @@ type Decoder struct {
ri ioDecReader
f map[uintptr]*decFn
is map[string]string // used for interning strings
// _ uintptr // for alignment purposes, so next one starts from a cache line
b [scratchByteArrayLen]byte
@ -977,6 +1052,9 @@ func NewDecoder(r io.Reader, h Handle) (d *Decoder) {
d.ri.br = &d.ri.bs
}
d.r = &d.ri
if d.h.InternString {
d.is = make(map[string]string, 32)
}
_, d.js = h.(*JsonHandle)
d.d = h.newDecDriver(d)
return
@ -990,6 +1068,9 @@ func NewDecoderBytes(in []byte, h Handle) (d *Decoder) {
d.rb.b = in
d.rb.a = len(in)
d.r = &d.rb
if d.h.InternString {
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})
@ -1472,6 +1553,24 @@ func (d *Decoder) errorf(format string, params ...interface{}) {
panic(err)
}
func (d *Decoder) string(v []byte) (s string) {
if d.is != nil {
s, ok := d.is[string(v)] // no allocation here.
if !ok {
s = string(v)
d.is[s] = s
}
return s
}
return string(v) // don't return stringView, as we need a real string here.
}
func (d *Decoder) intern(s string) {
if d.is != nil {
d.is[s] = s
}
}
// --------------------------------------------------
// decSliceHelper assists when decoding into a slice, from a map or an array in the stream.

View File

@ -4,7 +4,6 @@
package codec
import (
"bytes"
"encoding"
"fmt"
"io"
@ -80,17 +79,6 @@ type encNoSeparator struct{}
func (_ encNoSeparator) EncodeEnd() {}
type encStructFieldBytesV struct {
b []byte
v reflect.Value
}
type encStructFieldBytesVslice []encStructFieldBytesV
func (p encStructFieldBytesVslice) Len() int { return len(p) }
func (p encStructFieldBytesVslice) Less(i, j int) bool { return bytes.Compare(p[i].b, p[j].b) == -1 }
func (p encStructFieldBytesVslice) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
type ioEncWriterWriter interface {
WriteByte(c byte) error
WriteString(s string) (n int, err error)
@ -109,8 +97,16 @@ type EncodeOptions struct {
// sequence of bytes.
//
// This only affects maps, as the iteration order for maps is random.
// In this case, the map keys will first be encoded into []byte, and then sorted,
// before writing the sorted keys and the corresponding map values to the stream.
//
// The implementation MAY use the natural sort order for the map keys if possible:
//
// - If there is a natural sort order (ie for number, bool, string or []byte keys),
// then the map keys are first sorted in natural order and then written
// with corresponding map values to the strema.
// - If there is no natural sort order, then the map keys will first be
// encoded into []byte, and then sorted,
// before writing the sorted keys and the corresponding map values to the stream.
//
Canonical bool
// AsSymbols defines what should be encoded as symbols.
@ -493,27 +489,27 @@ func (f *encFnInfo) kStruct(rv reflect.Value) {
tisfi = fti.sfi
}
newlen = 0
var kv encStructFieldKV
var kv stringRv
for _, si := range tisfi {
kv.v = 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 si.omitEmpty && isEmptyValue(kv.v) {
if si.omitEmpty && isEmptyValue(kv.r) {
continue
}
kv.k = si.encName
kv.v = si.encName
} else {
// use the zero value.
// if a reference or struct, set to nil (so you do not output too much)
if si.omitEmpty && isEmptyValue(kv.v) {
switch kv.v.Kind() {
if si.omitEmpty && isEmptyValue(kv.r) {
switch kv.r.Kind() {
case reflect.Struct, reflect.Interface, reflect.Ptr, reflect.Array,
reflect.Map, reflect.Slice:
kv.v = reflect.Value{} //encode as nil
kv.r = reflect.Value{} //encode as nil
}
}
}
@ -532,17 +528,17 @@ func (f *encFnInfo) kStruct(rv reflect.Value) {
for j := 0; j < newlen; j++ {
kv = fkvs[j]
if asSymbols {
ee.EncodeSymbol(kv.k)
ee.EncodeSymbol(kv.v)
} else {
ee.EncodeString(c_UTF8, kv.k)
ee.EncodeString(c_UTF8, kv.v)
}
e.encodeValue(kv.v, nil)
e.encodeValue(kv.r, nil)
}
} else {
ee.EncodeArrayStart(newlen)
for j := 0; j < newlen; j++ {
kv = fkvs[j]
e.encodeValue(kv.v, nil)
e.encodeValue(kv.r, nil)
}
}
ee.EncodeEnd()
@ -621,24 +617,9 @@ func (f *encFnInfo) kMap(rv reflect.Value) {
}
mks := rv.MapKeys()
// for j, lmks := 0, len(mks); j < lmks; j++ {
if e.h.Canonical {
// first encode each key to a []byte first, then sort them, then record
// println(">>>>>>>> CANONICAL <<<<<<<<")
var mksv []byte = make([]byte, 0, len(mks)*16) // temporary byte slice for the encoding
e2 := NewEncoderBytes(&mksv, e.hh)
mksbv := make([]encStructFieldBytesV, len(mks))
for i, k := range mks {
l := len(mksv)
e2.MustEncode(k)
mksbv[i].v = k
mksbv[i].b = mksv[l:]
// fmt.Printf(">>>>> %s\n", mksv[l:])
}
sort.Sort(encStructFieldBytesVslice(mksbv))
for j := range mksbv {
e.asis(mksbv[j].b)
e.encodeValue(rv.MapIndex(mksbv[j].v), valFn)
}
e.kMapCanonical(rtkeyid, rtkey, rv, mks, valFn, asSymbols)
} else {
for j := range mks {
if keyTypeIsString {
@ -653,9 +634,128 @@ func (f *encFnInfo) kMap(rv reflect.Value) {
e.encodeValue(rv.MapIndex(mks[j]), valFn)
}
}
ee.EncodeEnd()
}
func (e *Encoder) kMapCanonical(rtkeyid uintptr, rtkey reflect.Type, rv reflect.Value, mks []reflect.Value, valFn *encFn, asSymbols bool) {
ee := e.e
// we previously did out-of-band if an extension was registered.
// This is not necessary, as the natural kind is sufficient for ordering.
if rtkeyid == uint8SliceTypId {
mksv := make([]bytesRv, len(mks))
for i, k := range mks {
v := &mksv[i]
v.r = k
v.v = k.Bytes()
}
sort.Sort(bytesRvSlice(mksv))
for i := range mksv {
ee.EncodeStringBytes(c_RAW, mksv[i].v)
e.encodeValue(rv.MapIndex(mksv[i].r), valFn)
}
} else {
switch rtkey.Kind() {
case reflect.Bool:
mksv := make([]boolRv, len(mks))
for i, k := range mks {
v := &mksv[i]
v.r = k
v.v = k.Bool()
}
sort.Sort(boolRvSlice(mksv))
for i := range mksv {
ee.EncodeBool(mksv[i].v)
e.encodeValue(rv.MapIndex(mksv[i].r), valFn)
}
case reflect.String:
mksv := make([]stringRv, len(mks))
for i, k := range mks {
v := &mksv[i]
v.r = k
v.v = k.String()
}
sort.Sort(stringRvSlice(mksv))
for i := range mksv {
if asSymbols {
ee.EncodeSymbol(mksv[i].v)
} else {
ee.EncodeString(c_UTF8, mksv[i].v)
}
e.encodeValue(rv.MapIndex(mksv[i].r), valFn)
}
case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint, reflect.Uintptr:
mksv := make([]uintRv, len(mks))
for i, k := range mks {
v := &mksv[i]
v.r = k
v.v = k.Uint()
}
sort.Sort(uintRvSlice(mksv))
for i := range mksv {
ee.EncodeUint(mksv[i].v)
e.encodeValue(rv.MapIndex(mksv[i].r), valFn)
}
case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
mksv := make([]intRv, len(mks))
for i, k := range mks {
v := &mksv[i]
v.r = k
v.v = k.Int()
}
sort.Sort(intRvSlice(mksv))
for i := range mksv {
ee.EncodeInt(mksv[i].v)
e.encodeValue(rv.MapIndex(mksv[i].r), valFn)
}
case reflect.Float32:
mksv := make([]floatRv, len(mks))
for i, k := range mks {
v := &mksv[i]
v.r = k
v.v = k.Float()
}
sort.Sort(floatRvSlice(mksv))
for i := range mksv {
ee.EncodeFloat32(float32(mksv[i].v))
e.encodeValue(rv.MapIndex(mksv[i].r), valFn)
}
case reflect.Float64:
mksv := make([]floatRv, len(mks))
for i, k := range mks {
v := &mksv[i]
v.r = k
v.v = k.Float()
}
sort.Sort(floatRvSlice(mksv))
for i := range mksv {
ee.EncodeFloat64(mksv[i].v)
e.encodeValue(rv.MapIndex(mksv[i].r), valFn)
}
default:
// out-of-band
// first encode each key to a []byte first, then sort them, then record
var mksv []byte = make([]byte, 0, len(mks)*16) // temporary byte slice for the encoding
e2 := NewEncoderBytes(&mksv, e.hh)
mksbv := make([]bytesRv, len(mks))
for i, k := range mks {
v := &mksbv[i]
l := len(mksv)
e2.MustEncode(k)
v.r = k
v.v = mksv[l:]
// fmt.Printf(">>>>> %s\n", mksv[l:])
}
sort.Sort(bytesRvSlice(mksbv))
for j := range mksbv {
e.asis(mksbv[j].v)
e.encodeValue(rv.MapIndex(mksbv[j].r), valFn)
}
}
}
}
// --------------------------------------------------
// encFn encapsulates the captured variables and the encode function.
@ -903,16 +1003,9 @@ func (e *Encoder) encode(iv interface{}) {
e.e.EncodeStringBytes(c_RAW, *v)
default:
// canonical mode is not supported for fastpath of maps (but is fine for slices)
const checkCodecSelfer1 = true // in case T is passed, where *T is a Selfer, still checkCodecSelfer
if e.h.Canonical {
if !fastpathEncodeTypeSwitchSlice(iv, e) {
e.encodeI(iv, false, checkCodecSelfer1)
}
} else {
if !fastpathEncodeTypeSwitch(iv, e) {
e.encodeI(iv, false, checkCodecSelfer1)
}
if !fastpathEncodeTypeSwitch(iv, e) {
e.encodeI(iv, false, checkCodecSelfer1)
}
}
}
@ -1019,8 +1112,7 @@ func (e *Encoder) getEncFn(rtid uintptr, rt reflect.Type, checkFastpath, checkCo
fn.f = (*encFnInfo).textMarshal
} else {
rk := rt.Kind()
// if fastpathEnabled && checkFastpath && (rk == reflect.Map || rk == reflect.Slice) {
if fastpathEnabled && checkFastpath && (rk == reflect.Slice || (rk == reflect.Map && !e.h.Canonical)) {
if fastpathEnabled && checkFastpath && (rk == reflect.Map || rk == reflect.Slice) {
if rt.PkgPath() == "" {
if idx := fastpathAV.index(rtid); idx != -1 {
fn.f = fastpathAV[idx].encfn
@ -1114,11 +1206,6 @@ func (e *Encoder) errorf(format string, params ...interface{}) {
// ----------------------------------------
type encStructFieldKV struct {
k string
v reflect.Value
}
const encStructPoolLen = 5
// encStructPool is an array of sync.Pool.
@ -1133,33 +1220,33 @@ const encStructPoolLen = 5
var encStructPool [encStructPoolLen]sync.Pool
func init() {
encStructPool[0].New = func() interface{} { return new([8]encStructFieldKV) }
encStructPool[1].New = func() interface{} { return new([16]encStructFieldKV) }
encStructPool[2].New = func() interface{} { return new([32]encStructFieldKV) }
encStructPool[3].New = func() interface{} { return new([64]encStructFieldKV) }
encStructPool[4].New = func() interface{} { return new([128]encStructFieldKV) }
encStructPool[0].New = func() interface{} { return new([8]stringRv) }
encStructPool[1].New = func() interface{} { return new([16]stringRv) }
encStructPool[2].New = func() interface{} { return new([32]stringRv) }
encStructPool[3].New = func() interface{} { return new([64]stringRv) }
encStructPool[4].New = func() interface{} { return new([128]stringRv) }
}
func encStructPoolGet(newlen int) (p *sync.Pool, v interface{}, s []encStructFieldKV) {
func encStructPoolGet(newlen int) (p *sync.Pool, v interface{}, s []stringRv) {
// if encStructPoolLen != 5 { // constant chec, so removed at build time.
// panic(errors.New("encStructPoolLen must be equal to 4")) // defensive, in case it is changed
// }
// idxpool := newlen / 8
// if pool == nil {
// fkvs = make([]encStructFieldKV, newlen)
// fkvs = make([]stringRv, newlen)
// } else {
// poolv = pool.Get()
// switch vv := poolv.(type) {
// case *[8]encStructFieldKV:
// case *[8]stringRv:
// fkvs = vv[:newlen]
// case *[16]encStructFieldKV:
// case *[16]stringRv:
// fkvs = vv[:newlen]
// case *[32]encStructFieldKV:
// case *[32]stringRv:
// fkvs = vv[:newlen]
// case *[64]encStructFieldKV:
// case *[64]stringRv:
// fkvs = vv[:newlen]
// case *[128]encStructFieldKV:
// case *[128]stringRv:
// fkvs = vv[:newlen]
// }
// }
@ -1167,25 +1254,25 @@ func encStructPoolGet(newlen int) (p *sync.Pool, v interface{}, s []encStructFie
if newlen <= 8 {
p = &encStructPool[0]
v = p.Get()
s = v.(*[8]encStructFieldKV)[:newlen]
s = v.(*[8]stringRv)[:newlen]
} else if newlen <= 16 {
p = &encStructPool[1]
v = p.Get()
s = v.(*[16]encStructFieldKV)[:newlen]
s = v.(*[16]stringRv)[:newlen]
} else if newlen <= 32 {
p = &encStructPool[2]
v = p.Get()
s = v.(*[32]encStructFieldKV)[:newlen]
s = v.(*[32]stringRv)[:newlen]
} else if newlen <= 64 {
p = &encStructPool[3]
v = p.Get()
s = v.(*[64]encStructFieldKV)[:newlen]
s = v.(*[64]stringRv)[:newlen]
} else if newlen <= 128 {
p = &encStructPool[4]
v = p.Get()
s = v.(*[128]encStructFieldKV)[:newlen]
s = v.(*[128]stringRv)[:newlen]
} else {
s = make([]encStructFieldKV, newlen)
s = make([]stringRv, newlen)
}
return
}

File diff suppressed because it is too large Load Diff

View File

@ -116,6 +116,7 @@ func fastpathEncodeTypeSwitch(iv interface{}, e *Encoder) bool {
fastpathTV.{{ .MethodNamePfx "Enc" false }}V(*v, fastpathCheckNilTrue, e)
{{end}}{{end}}
default:
_ = v // TODO: workaround https://github.com/golang/go/issues/12927 (remove after go 1.6 release)
return false
}
return true
@ -182,14 +183,50 @@ func (_ fastpathT) {{ .MethodNamePfx "Enc" false }}V(v map[{{ .MapKey }}]{{ .Ele
return
}
ee.EncodeMapStart(len(v))
{{if eq .MapKey "string"}}asSymbols := e.h.AsSymbols&AsSymbolMapStringKeysFlag != 0{{end}}
for k2, v2 := range v {
{{if eq .MapKey "string"}}if asSymbols {
ee.EncodeSymbol(k2)
} else {
ee.EncodeString(c_UTF8, k2)
}{{else}}{{ encmd .MapKey "k2"}}{{end}}
{{ encmd .Elem "v2"}}
{{if eq .MapKey "string"}}asSymbols := e.h.AsSymbols&AsSymbolMapStringKeysFlag != 0
{{end}}if e.h.Canonical {
{{if eq .MapKey "interface{}"}}{{/* out of band
*/}}var mksv []byte = make([]byte, 0, len(v)*16) // temporary byte slice for the encoding
e2 := NewEncoderBytes(&mksv, e.hh)
v2 := make([]bytesI, len(v))
var i, l int
var vp *bytesI {{/* put loop variables outside. seems currently needed for better perf */}}
for k2, _ := range v {
l = len(mksv)
e2.MustEncode(k2)
vp = &v2[i]
vp.v = mksv[l:]
vp.i = k2
i++
}
sort.Sort(bytesISlice(v2))
for j := range v2 {
e.asis(v2[j].v)
e.encode(v[v2[j].i])
} {{else}}{{ $x := sorttype .MapKey true}}v2 := make([]{{ $x }}, len(v))
var i int
for k, _ := range v {
v2[i] = {{ $x }}(k)
i++
}
sort.Sort({{ sorttype .MapKey false}}(v2))
for _, k2 := range v2 {
{{if eq .MapKey "string"}}if asSymbols {
ee.EncodeSymbol(k2)
} else {
ee.EncodeString(c_UTF8, k2)
}{{else}}{{ $y := printf "%s(k2)" .MapKey }}{{ encmd .MapKey $y }}{{end}}
{{ $y := printf "v[%s(k2)]" .MapKey }}{{ encmd .Elem $y }}
} {{end}}
} else {
for k2, v2 := range v {
{{if eq .MapKey "string"}}if asSymbols {
ee.EncodeSymbol(k2)
} else {
ee.EncodeString(c_UTF8, k2)
}{{else}}{{ encmd .MapKey "k2"}}{{end}}
{{ encmd .Elem "v2"}}
}
}
ee.EncodeEnd()
}
@ -382,30 +419,31 @@ func (_ fastpathT) {{ .MethodNamePfx "Dec" false }}V(v map[{{ .MapKey }}]{{ .Ele
v = make(map[{{ .MapKey }}]{{ .Elem }}, xlen)
changed = true
}
{{ if eq .Elem "interface{}" }}mapGet := !d.h.MapValueReset && !d.h.InterfaceReset{{end}}
var mk {{ .MapKey }}
var mv {{ .Elem }}
if containerLen > 0 {
for j := 0; j < containerLen; j++ {
{{ if eq .MapKey "interface{}" }}var mk interface{}
{{ if eq .MapKey "interface{}" }}mk = nil
d.decode(&mk)
if bv, bok := mk.([]byte); bok {
mk = string(bv) {{/* // maps cannot have []byte as key. switch to string. */}}
}{{ else }}mk := {{ decmd .MapKey }}{{ end }}
mv := v[mk]
{{ if eq .Elem "interface{}" }}d.decode(&mv)
{{ else }}mv = {{ decmd .Elem }}{{ end }}
mk = d.string(bv) {{/* // maps cannot have []byte as key. switch to string. */}}
}{{ else }}mk = {{ decmd .MapKey }}{{ end }}
{{ if eq .Elem "interface{}" }}if mapGet { mv = v[mk] } else { mv = nil }
d.decode(&mv){{ else }}mv = {{ decmd .Elem }}{{ end }}
if v != nil {
v[mk] = mv
}
}
} else if containerLen < 0 {
for j := 0; !dd.CheckBreak(); j++ {
{{ if eq .MapKey "interface{}" }}var mk interface{}
{{ if eq .MapKey "interface{}" }}mk = nil
d.decode(&mk)
if bv, bok := mk.([]byte); bok {
mk = string(bv) {{/* // maps cannot have []byte as key. switch to string. */}}
}{{ else }}mk := {{ decmd .MapKey }}{{ end }}
mv := v[mk]
{{ if eq .Elem "interface{}" }}d.decode(&mv)
{{ else }}mv = {{ decmd .Elem }}{{ end }}
mk = d.string(bv) {{/* // maps cannot have []byte as key. switch to string. */}}
}{{ else }}mk = {{ decmd .MapKey }}{{ end }}
{{ if eq .Elem "interface{}" }}if mapGet { mv = v[mk] } else { mv = nil }
d.decode(&mv){{ else }}mv = {{ decmd .Elem }}{{ end }}
if v != nil {
v[mk] = mv
}

View File

@ -1,20 +1,28 @@
{{var "v"}} := *{{ .Varname }}
{{var "l"}} := r.ReadMapStart()
{{var "bh"}} := z.DecBasicHandle()
if {{var "v"}} == nil {
{{var "rl"}}, _ := z.DecInferLen({{var "l"}}, z.DecBasicHandle().MaxInitLen, {{ .Size }})
{{var "rl"}}, _ := z.DecInferLen({{var "l"}}, {{var "bh"}}.MaxInitLen, {{ .Size }})
{{var "v"}} = make(map[{{ .KTyp }}]{{ .Typ }}, {{var "rl"}})
*{{ .Varname }} = {{var "v"}}
}
var {{var "mk"}} {{ .KTyp }}
var {{var "mv"}} {{ .Typ }}
var {{var "mg"}} bool
if {{var "bh"}}.MapValueReset {
{{if decElemKindPtr}}{{var "mg"}} = true
{{else if decElemKindIntf}}if !{{var "bh"}}.InterfaceReset { {{var "mg"}} = true }
{{else if not decElemKindImmutable}}{{var "mg"}} = true
{{end}} }
if {{var "l"}} > 0 {
for {{var "j"}} := 0; {{var "j"}} < {{var "l"}}; {{var "j"}}++ {
var {{var "mk"}} {{ .KTyp }}
{{ $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"}})
}
{{ end }}
{{var "mv"}} := {{var "v"}}[{{var "mk"}}]
}{{ end }}
if {{var "mg"}} {
{{var "mv"}} = {{var "v"}}[{{var "mk"}}]
} {{if not decElemKindImmutable}}else { {{var "mv"}} = {{decElemZero}} }{{end}}
{{ $x := printf "%vmv%v" .TempVar .Rand }}{{ decLineVar $x }}
if {{var "v"}} != nil {
{{var "v"}}[{{var "mk"}}] = {{var "mv"}}
@ -22,14 +30,13 @@ for {{var "j"}} := 0; {{var "j"}} < {{var "l"}}; {{var "j"}}++ {
}
} else if {{var "l"}} < 0 {
for {{var "j"}} := 0; !r.CheckBreak(); {{var "j"}}++ {
var {{var "mk"}} {{ .KTyp }}
{{ $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"}})
}
{{ end }}
{{var "mv"}} := {{var "v"}}[{{var "mk"}}]
}{{ end }}
if {{var "mg"}} {
{{var "mv"}} = {{var "v"}}[{{var "mk"}}]
} {{if not decElemKindImmutable}}else { {{var "mv"}} = {{decElemZero}} }{{end}}
{{ $x := printf "%vmv%v" .TempVar .Rand }}{{ decLineVar $x }}
if {{var "v"}} != nil {
{{var "v"}}[{{var "mk"}}] = {{var "mv"}}

View File

@ -8,21 +8,29 @@ package codec
const genDecMapTmpl = `
{{var "v"}} := *{{ .Varname }}
{{var "l"}} := r.ReadMapStart()
{{var "bh"}} := z.DecBasicHandle()
if {{var "v"}} == nil {
{{var "rl"}}, _ := z.DecInferLen({{var "l"}}, z.DecBasicHandle().MaxInitLen, {{ .Size }})
{{var "rl"}}, _ := z.DecInferLen({{var "l"}}, {{var "bh"}}.MaxInitLen, {{ .Size }})
{{var "v"}} = make(map[{{ .KTyp }}]{{ .Typ }}, {{var "rl"}})
*{{ .Varname }} = {{var "v"}}
}
var {{var "mk"}} {{ .KTyp }}
var {{var "mv"}} {{ .Typ }}
var {{var "mg"}} bool
if {{var "bh"}}.MapValueReset {
{{if decElemKindPtr}}{{var "mg"}} = true
{{else if decElemKindIntf}}if !{{var "bh"}}.InterfaceReset { {{var "mg"}} = true }
{{else if not decElemKindImmutable}}{{var "mg"}} = true
{{end}} }
if {{var "l"}} > 0 {
for {{var "j"}} := 0; {{var "j"}} < {{var "l"}}; {{var "j"}}++ {
var {{var "mk"}} {{ .KTyp }}
{{ $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"}})
}
{{ end }}
{{var "mv"}} := {{var "v"}}[{{var "mk"}}]
}{{ end }}
if {{var "mg"}} {
{{var "mv"}} = {{var "v"}}[{{var "mk"}}]
} {{if not decElemKindImmutable}}else { {{var "mv"}} = {{decElemZero}} }{{end}}
{{ $x := printf "%vmv%v" .TempVar .Rand }}{{ decLineVar $x }}
if {{var "v"}} != nil {
{{var "v"}}[{{var "mk"}}] = {{var "mv"}}
@ -30,14 +38,13 @@ for {{var "j"}} := 0; {{var "j"}} < {{var "l"}}; {{var "j"}}++ {
}
} else if {{var "l"}} < 0 {
for {{var "j"}} := 0; !r.CheckBreak(); {{var "j"}}++ {
var {{var "mk"}} {{ .KTyp }}
{{ $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"}})
}
{{ end }}
{{var "mv"}} := {{var "v"}}[{{var "mk"}}]
}{{ end }}
if {{var "mg"}} {
{{var "mv"}} = {{var "v"}}[{{var "mk"}}]
} {{if not decElemKindImmutable}}else { {{var "mv"}} = {{decElemZero}} }{{end}}
{{ $x := printf "%vmv%v" .TempVar .Rand }}{{ decLineVar $x }}
if {{var "v"}} != nil {
{{var "v"}}[{{var "mk"}}] = {{var "mv"}}

View File

@ -169,7 +169,7 @@ func Gen(w io.Writer, buildTags, pkgName, uid string, useUnsafe bool, ti *TypeIn
ts: []reflect.Type{},
bp: genImportPath(typ[0]),
xs: uid,
ti: ti, //TODO: make it configurable
ti: ti,
}
if x.ti == nil {
x.ti = defTypeInfos
@ -928,6 +928,7 @@ func (x *genRunner) encListFallback(varname string, t reflect.Type) {
}
func (x *genRunner) encMapFallback(varname string, t reflect.Type) {
// TODO: expand this to handle canonical.
i := x.varsfx()
x.line("r.EncodeMapStart(len(" + varname + "))")
x.linef("for %sk%s, %sv%s := range %s {", genTempVarPfx, i, genTempVarPfx, i, varname)
@ -1301,8 +1302,24 @@ func (x *genRunner) decMapFallback(varname string, rtid uintptr, t reflect.Type)
}
telem := t.Elem()
tkey := t.Key()
ts := tstruc{genTempVarPfx, x.varsfx(), varname, x.genTypeName(tkey), x.genTypeName(telem), int(telem.Size() + tkey.Size())}
ts := tstruc{
genTempVarPfx, x.varsfx(), varname, x.genTypeName(tkey),
x.genTypeName(telem), int(telem.Size() + tkey.Size()),
}
funcs := make(template.FuncMap)
funcs["decElemZero"] = func() string {
return x.genZeroValueR(telem)
}
funcs["decElemKindImmutable"] = func() bool {
return genIsImmutable(telem)
}
funcs["decElemKindPtr"] = func() bool {
return telem.Kind() == reflect.Ptr
}
funcs["decElemKindIntf"] = func() bool {
return telem.Kind() == reflect.Interface
}
funcs["decLineVarK"] = func(varname string) string {
x.decVar(varname, tkey, false)
return ""
@ -1726,6 +1743,8 @@ func genInternalDecCommandAsString(s string) string {
return "uint32(dd.DecodeUint(32))"
case "uint64":
return "dd.DecodeUint(64)"
case "uintptr":
return "uintptr(dd.DecodeUint(uintBitsize))"
case "int":
return "int(dd.DecodeInt(intBitsize))"
case "int8":
@ -1746,9 +1765,24 @@ func genInternalDecCommandAsString(s string) string {
case "bool":
return "dd.DecodeBool()"
default:
panic(errors.New("unknown type for decode: " + s))
panic(errors.New("gen internal: unknown type for decode: " + s))
}
}
func genInternalSortType(s string, elem bool) string {
for _, v := range [...]string{"int", "uint", "float", "bool", "string"} {
if strings.HasPrefix(s, v) {
if elem {
if v == "int" || v == "uint" || v == "float" {
return v + "64"
} else {
return v
}
}
return v + "Slice"
}
}
panic("sorttype: unexpected type: " + s)
}
// var genInternalMu sync.Mutex
@ -1767,6 +1801,7 @@ func genInternalInit() {
"uint16",
"uint32",
"uint64",
"uintptr",
"int",
"int8",
"int16",
@ -1784,6 +1819,7 @@ func genInternalInit() {
"uint16",
"uint32",
"uint64",
"uintptr",
"int",
"int8",
"int16",
@ -1803,6 +1839,7 @@ func genInternalInit() {
"uint16": 2,
"uint32": 4,
"uint64": 8,
"uintptr": 1 * wordSizeBytes,
"int": 1 * wordSizeBytes,
"int8": 1,
"int16": 2,
@ -1837,16 +1874,18 @@ func genInternalInit() {
funcs["encmd"] = genInternalEncCommandAsString
funcs["decmd"] = genInternalDecCommandAsString
funcs["zerocmd"] = genInternalZeroValue
funcs["hasprefix"] = strings.HasPrefix
funcs["sorttype"] = genInternalSortType
genInternalV = gt
genInternalTmplFuncs = funcs
}
// GenInternalGoFile is used to generate source files from templates.
// genInternalGoFile is used to generate source files from templates.
// It is run by the program author alone.
// Unfortunately, it has to be exported so that it can be called from a command line tool.
// *** DO NOT USE ***
func GenInternalGoFile(r io.Reader, w io.Writer, safe bool) (err error) {
func genInternalGoFile(r io.Reader, w io.Writer, safe bool) (err error) {
genInternalOnce.Do(genInternalInit)
gt := genInternalV

View File

@ -101,6 +101,7 @@ package codec
// check for these error conditions.
import (
"bytes"
"encoding"
"encoding/binary"
"errors"
@ -975,3 +976,114 @@ func (_ checkOverflow) SignedInt(v uint64) (i int64, overflow bool) {
i = int64(v)
return
}
// ------------------ SORT -----------------
func isNaN(f float64) bool { return f != f }
// -----------------------
type intSlice []int64
type uintSlice []uint64
type floatSlice []float64
type boolSlice []bool
type stringSlice []string
type bytesSlice [][]byte
func (p intSlice) Len() int { return len(p) }
func (p intSlice) Less(i, j int) bool { return p[i] < p[j] }
func (p intSlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
func (p uintSlice) Len() int { return len(p) }
func (p uintSlice) Less(i, j int) bool { return p[i] < p[j] }
func (p uintSlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
func (p floatSlice) Len() int { return len(p) }
func (p floatSlice) Less(i, j int) bool {
return p[i] < p[j] || isNaN(p[i]) && !isNaN(p[j])
}
func (p floatSlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
func (p stringSlice) Len() int { return len(p) }
func (p stringSlice) Less(i, j int) bool { return p[i] < p[j] }
func (p stringSlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
func (p bytesSlice) Len() int { return len(p) }
func (p bytesSlice) Less(i, j int) bool { return bytes.Compare(p[i], p[j]) == -1 }
func (p bytesSlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
func (p boolSlice) Len() int { return len(p) }
func (p boolSlice) Less(i, j int) bool { return !p[i] && p[j] }
func (p boolSlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
// ---------------------
type intRv struct {
v int64
r reflect.Value
}
type intRvSlice []intRv
type uintRv struct {
v uint64
r reflect.Value
}
type uintRvSlice []uintRv
type floatRv struct {
v float64
r reflect.Value
}
type floatRvSlice []floatRv
type boolRv struct {
v bool
r reflect.Value
}
type boolRvSlice []boolRv
type stringRv struct {
v string
r reflect.Value
}
type stringRvSlice []stringRv
type bytesRv struct {
v []byte
r reflect.Value
}
type bytesRvSlice []bytesRv
func (p intRvSlice) Len() int { return len(p) }
func (p intRvSlice) Less(i, j int) bool { return p[i].v < p[j].v }
func (p intRvSlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
func (p uintRvSlice) Len() int { return len(p) }
func (p uintRvSlice) Less(i, j int) bool { return p[i].v < p[j].v }
func (p uintRvSlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
func (p floatRvSlice) Len() int { return len(p) }
func (p floatRvSlice) Less(i, j int) bool {
return p[i].v < p[j].v || isNaN(p[i].v) && !isNaN(p[j].v)
}
func (p floatRvSlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
func (p stringRvSlice) Len() int { return len(p) }
func (p stringRvSlice) Less(i, j int) bool { return p[i].v < p[j].v }
func (p stringRvSlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
func (p bytesRvSlice) Len() int { return len(p) }
func (p bytesRvSlice) Less(i, j int) bool { return bytes.Compare(p[i].v, p[j].v) == -1 }
func (p bytesRvSlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
func (p boolRvSlice) Len() int { return len(p) }
func (p boolRvSlice) Less(i, j int) bool { return !p[i].v && p[j].v }
func (p boolRvSlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
// -----------------
type bytesI struct {
v []byte
i interface{}
}
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] }

View File

@ -411,7 +411,7 @@ func (e *jsonEncDriver) quoteStr(s string) {
//--------------------------------
type jsonNum struct {
bytes []byte // may have [+-.eE0-9]
// bytes []byte // may have [+-.eE0-9]
mantissa uint64 // where mantissa ends, and maybe dot begins.
exponent int16 // exponent value.
manOverflow bool
@ -421,7 +421,6 @@ type jsonNum struct {
}
func (x *jsonNum) reset() {
x.bytes = x.bytes[:0]
x.manOverflow = false
x.neg = false
x.dot = false
@ -454,29 +453,26 @@ func (x *jsonNum) uintExp() (n uint64, overflow bool) {
// return
}
func (x *jsonNum) floatVal() (f float64) {
// these constants are only used withn floatVal.
// They are brought out, so that floatVal can be inlined.
const (
jsonUint64MantissaBits = 52
jsonMaxExponent = int16(len(jsonFloat64Pow10)) - 1
)
func (x *jsonNum) floatVal() (f float64, parseUsingStrConv bool) {
// We do not want to lose precision.
// Consequently, we will delegate to strconv.ParseFloat if any of the following happen:
// - There are more digits than in math.MaxUint64: 18446744073709551615 (20 digits)
// We expect up to 99.... (19 digits)
// - The mantissa cannot fit into a 52 bits of uint64
// - The exponent is beyond our scope ie beyong 22.
const uint64MantissaBits = 52
const maxExponent = int16(len(jsonFloat64Pow10)) - 1
parseUsingStrConv = x.manOverflow ||
x.exponent > jsonMaxExponent ||
(x.exponent < 0 && -(x.exponent) > jsonMaxExponent) ||
x.mantissa>>jsonUint64MantissaBits != 0
parseUsingStrConv := x.manOverflow ||
x.exponent > maxExponent ||
(x.exponent < 0 && -(x.exponent) > maxExponent) ||
x.mantissa>>uint64MantissaBits != 0
if parseUsingStrConv {
var err error
if f, err = strconv.ParseFloat(stringView(x.bytes), 64); err != nil {
panic(fmt.Errorf("parse float: %s, %v", x.bytes, err))
return
}
if x.neg {
f = -f
}
return
}
@ -500,8 +496,9 @@ type jsonDecDriver struct {
r decReader // *bytesDecReader decReader
ct valueType // container type. one of unset, array or map.
bstr [8]byte // scratch used for string \UXXX parsing
b [64]byte // scratch
b2 [64]byte
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
@ -662,8 +659,6 @@ func (d *jsonDecDriver) IsContainerType(vt valueType) bool {
}
func (d *jsonDecDriver) decNum(storeBytes bool) {
// storeBytes = true // TODO: remove.
// If it is has a . or an e|E, decode as a float; else decode as an int.
b := d.skipWhitespace(false)
if !(b == '+' || b == '-' || b == '.' || (b >= '0' && b <= '9')) {
@ -674,10 +669,9 @@ func (d *jsonDecDriver) decNum(storeBytes bool) {
const cutoff = (1<<64-1)/uint64(10) + 1 // cutoff64(base)
const jsonNumUintMaxVal = 1<<uint64(64) - 1
// var n jsonNum // create stack-copy jsonNum, and set to pointer at end.
// n.bytes = d.n.bytes[:0]
n := &d.n
n.reset()
d.bs = d.bs[:0]
// The format of a number is as below:
// parsing: sign? digit* dot? digit* e? sign? digit*
@ -773,7 +767,7 @@ LOOP:
break LOOP
}
if storeBytes {
n.bytes = append(n.bytes, b)
d.bs = append(d.bs, b)
}
b, eof = d.r.readn1eof()
}
@ -834,13 +828,28 @@ func (d *jsonDecDriver) DecodeInt(bitsize uint8) (i int64) {
i = -i
}
if chkOvf.Int(i, bitsize) {
d.d.errorf("json: overflow %v bits: %s", bitsize, n.bytes)
d.d.errorf("json: overflow %v bits: %s", bitsize, d.bs)
return
}
// fmt.Printf("DecodeInt: %v\n", i)
return
}
// floatVal MUST only be called after a decNum, as d.bs now contains the bytes of the number
func (d *jsonDecDriver) floatVal() (f float64) {
f, useStrConv := d.n.floatVal()
if useStrConv {
var err error
if f, err = strconv.ParseFloat(stringView(d.bs), 64); err != nil {
panic(fmt.Errorf("parse float: %s, %v", d.bs, err))
}
if d.n.neg {
f = -f
}
}
return
}
func (d *jsonDecDriver) DecodeUint(bitsize uint8) (u uint64) {
if c := d.s.sc.sep(); c != 0 {
d.expectChar(c)
@ -868,7 +877,7 @@ func (d *jsonDecDriver) DecodeUint(bitsize uint8) (u uint64) {
}
}
if chkOvf.Uint(u, bitsize) {
d.d.errorf("json: overflow %v bits: %s", bitsize, n.bytes)
d.d.errorf("json: overflow %v bits: %s", bitsize, d.bs)
return
}
// fmt.Printf("DecodeUint: %v\n", u)
@ -880,10 +889,9 @@ func (d *jsonDecDriver) DecodeFloat(chkOverflow32 bool) (f float64) {
d.expectChar(c)
}
d.decNum(true)
n := &d.n
f = n.floatVal()
f = d.floatVal()
if chkOverflow32 && chkOvf.Float32(f) {
d.d.errorf("json: overflow float32: %v, %s", f, n.bytes)
d.d.errorf("json: overflow float32: %v, %s", f, d.bs)
return
}
return
@ -916,12 +924,13 @@ func (d *jsonDecDriver) DecodeBytes(bs []byte, isstring, zerocopy bool) (bsOut [
if c := d.s.sc.sep(); c != 0 {
d.expectChar(c)
}
bs0 := d.appendStringAsBytes(d.b[:0])
d.appendStringAsBytes()
// 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.
if isstring {
return bs0
return d.bs
}
bs0 := d.bs
slen := base64.StdEncoding.DecodedLen(len(bs0))
if slen <= cap(bs) {
bsOut = bs[:slen]
@ -945,13 +954,23 @@ func (d *jsonDecDriver) DecodeString() (s string) {
if c := d.s.sc.sep(); c != 0 {
d.expectChar(c)
}
return string(d.appendStringAsBytes(d.b[:0]))
return d.decString()
}
func (d *jsonDecDriver) appendStringAsBytes(v []byte) []byte {
func (d *jsonDecDriver) decString() (s string) {
d.appendStringAsBytes()
if x := d.s.sc; x != nil && x.st == '}' && x.so { // map key
return d.d.string(d.bs)
}
return string(d.bs)
}
func (d *jsonDecDriver) appendStringAsBytes() {
d.expectChar('"')
v := d.bs[:0]
var c uint8
for {
c := d.r.readn1()
c = d.r.readn1()
if c == '"' {
break
} else if c == '\\' {
@ -979,7 +998,6 @@ func (d *jsonDecDriver) appendStringAsBytes(v []byte) []byte {
v = append(v, d.bstr[:w2]...)
default:
d.d.errorf("json: unsupported escaped value: %c", c)
return nil
}
} else {
v = append(v, c)
@ -988,7 +1006,7 @@ func (d *jsonDecDriver) appendStringAsBytes(v []byte) []byte {
if jsonTrackSkipWhitespace {
d.wsSkipped = false
}
return v
d.bs = v
}
func (d *jsonDecDriver) jsonU4(checkSlashU bool) rune {
@ -1040,7 +1058,7 @@ func (d *jsonDecDriver) DecodeNaked() (v interface{}, vt valueType, decodeFurthe
decodeFurther = true
case '"':
vt = valueTypeString
v = string(d.appendStringAsBytes(d.b[:0])) // same as d.DecodeString(), but skipping sep() call.
v = d.decString() // same as d.DecodeString(), but skipping sep() call.
default: // number
d.decNum(true)
n := &d.n
@ -1048,7 +1066,7 @@ func (d *jsonDecDriver) DecodeNaked() (v interface{}, vt valueType, decodeFurthe
switch {
case n.explicitExponent, n.dot, n.exponent < 0, n.manOverflow:
vt = valueTypeFloat
v = n.floatVal()
v = d.floatVal()
case n.exponent == 0:
u := n.mantissa
switch {
@ -1067,7 +1085,7 @@ func (d *jsonDecDriver) DecodeNaked() (v interface{}, vt valueType, decodeFurthe
switch {
case overflow:
vt = valueTypeFloat
v = n.floatVal()
v = d.floatVal()
case n.neg:
vt = valueTypeInt
v = -int64(u)
@ -1122,8 +1140,8 @@ func (h *JsonHandle) newEncDriver(e *Encoder) encDriver {
func (h *JsonHandle) newDecDriver(d *Decoder) decDriver {
// d := jsonDecDriver{r: r.(*bytesDecReader), h: h}
hd := jsonDecDriver{d: d, r: d.r, h: h}
hd.bs = hd.b[:0]
hd.se.i = h.RawBytesExt
hd.n.bytes = d.b[:]
return &hd
}

View File

@ -99,6 +99,14 @@ var fastpathAV fastpathA
EOF
cat > gen-from-tmpl.codec.generated.go <<EOF
package codec
import "io"
func GenInternalGoFile(r io.Reader, w io.Writer, safe bool) error {
return genInternalGoFile(r, w, safe)
}
EOF
cat > gen-from-tmpl.generated.go <<EOF
//+build ignore
@ -130,7 +138,7 @@ run("gen-helper.go.tmpl", "gen-helper.generated.go", false)
EOF
go run gen-from-tmpl.generated.go && \
rm -f gen-from-tmpl.generated.go
rm -f gen-from-tmpl.*generated.go
}
_codegenerators() {
@ -140,15 +148,26 @@ _codegenerators() {
"1" == $( _needgen "values_ffjson${zsfx}" ) ||
1 == 0 ]]
then
true && \
echo "codecgen - !unsafe ... " && \
codecgen -rt codecgen -t 'x,codecgen,!unsafe' -o values_codecgen${zsfx} -d 1978 $zfin && \
echo "codecgen - unsafe ... " && \
codecgen -u -rt codecgen -t 'x,codecgen,unsafe' -o values_codecgen_unsafe${zsfx} -d 1978 $zfin && \
echo "msgp ... " && \
msgp -tests=false -pkg=codec -o=values_msgp${zsfx} -file=$zfin && \
echo "ffjson ... " && \
ffjson -w values_ffjson${zsfx} $zfin && \
# codecgen creates some temporary files in the directory (main, pkg).
# Consequently, we should start msgp and ffjson first, and also put a small time latency before
# starting codecgen.
# Without this, ffjson chokes on one of the temporary files from codecgen.
echo "ffjson ... " && \
ffjson -w values_ffjson${zsfx} $zfin &
zzzIdFF=$!
echo "msgp ... " && \
msgp -tests=false -pkg=codec -o=values_msgp${zsfx} -file=$zfin &
zzzIdMsgp=$!
sleep 1 # give ffjson and msgp some buffer time. see note above.
echo "codecgen - !unsafe ... " && \
codecgen -rt codecgen -t 'x,codecgen,!unsafe' -o values_codecgen${zsfx} -d 19780 $zfin &
zzzIdC=$!
echo "codecgen - unsafe ... " && \
codecgen -u -rt codecgen -t 'x,codecgen,unsafe' -o values_codecgen_unsafe${zsfx} -d 19781 $zfin &
zzzIdCU=$!
wait $zzzIdC $zzzIdCU $zzzIdMsgp $zzzIdFF && \
# remove (M|Unm)arshalJSON implementations, so they don't conflict with encoding/json bench \
sed -i 's+ MarshalJSON(+ _MarshalJSON(+g' values_ffjson${zsfx} && \
sed -i 's+ UnmarshalJSON(+ _UnmarshalJSON(+g' values_ffjson${zsfx} && \

View File

@ -45,7 +45,7 @@ _run() {
}
# echo ">>>>>>> RUNNING VARIATIONS OF TESTS"
if [[ "x$@" = x ]]; then
if [[ "x$@" = "x" ]]; then
# r, x, g, gu
_run "-rtcins"
_run "-xtcins"