瀏覽代碼

codec: clean up, improved symbol handling and numeric overflow support

Binc Handling and Symbols

    codec: remove AsSymbols from EncodeOption, and allow a modified version for binc only

    Currently, encDriver defines an EncodeSymbol function, that is only called
    when writing struct fields or map keys of string type. If we take out the differentiation,
    this can easily be handled by a specific handle, as it can track what the current
    containerState is.

    Instead, we remove all vestiges of Symbol support from encode.go and have it
    be something unique to binc.

    This also reduces the work that is done for all handles.

codec: remove overflow checking from Handles - manage it at the framework

    This means the following:
    - change decDriver DecodeUint and DecodeInt to just DecodeUint64 and DecodeInt64
    - add overflow check logic into checkOverflow type
    - use the overflow check logic in one-line statements across codebase

codec: fast-path: hoist conditional check out of loop

Misc cleanup
- clean up panic calls
- clean up some comments
- clean up error messages
- optimize tracking TypeInfos by reusing same array if possible
Ugorji Nwoke 8 年之前
父節點
當前提交
6e9891a451

+ 7 - 7
codec/0doc.go

@@ -225,11 +225,11 @@ package codec
 //   - In Go 1.10, when mid-stack inlining is enabled,
 //     we should use committed functions for writeXXX and readXXX calls.
 //     This involves uncommenting the methods for decReaderSwitch and encWriterSwitch
-//     and using those (decReaderSwitch and encWriterSwitch in all handles
+//     and using those (decReaderSwitch and encWriterSwitch) in all handles
 //     instead of encWriter and decReader.
-//   - removing conditionals used to avoid calling no-op functions via interface calls.
-//     esep, etc.
-//     It *should* make the code cleaner, and maybe more performant,
-//     as conditional branches are expensive.
-//     However, per https://groups.google.com/forum/#!topic/golang-nuts/DNELyNnTzFA ,
-//     there is no optimization if calling an empty function via an interface.
+//     The benefit is that, for the (En|De)coder over []byte, the encWriter/decReader
+//     will be inlined, giving a performance bump for that typical case.
+//     However, it will only  be inlined if mid-stack inlining is enabled,
+//     as we call panic to raise errors, and panic currently prevents inlining.
+//   - Clean up comments in the codebase
+//     Remove all unnecesssary comments, so code is clean.

+ 36 - 19
codec/binc.go

@@ -57,13 +57,15 @@ const (
 
 type bincEncDriver struct {
 	e *Encoder
+	h *BincHandle
 	w encWriter
 	m map[string]uint16 // symbols
 	b [scratchByteArrayLen]byte
 	s uint16 // symbols sequencer
-	// encNoSeparator
-	encDriverNoopContainerWriter
+	// c containerState
+	encDriverTrackContainerWriter
 	noBuiltInTypes
+	// encNoSeparator
 }
 
 // func (e *bincEncDriver) IsBuiltinType(rt uintptr) bool {
@@ -201,13 +203,19 @@ func (e *bincEncDriver) encodeExtPreamble(xtag byte, length int) {
 
 func (e *bincEncDriver) WriteArrayStart(length int) {
 	e.encLen(bincVdArray<<4, uint64(length))
+	e.c = containerArrayStart
 }
 
 func (e *bincEncDriver) WriteMapStart(length int) {
 	e.encLen(bincVdMap<<4, uint64(length))
+	e.c = containerMapStart
 }
 
 func (e *bincEncDriver) EncodeString(c charEncoding, v string) {
+	if e.c == containerMapKey && c == cUTF8 && (e.h.AsSymbols == 0 || e.h.AsSymbols == 1) {
+		e.EncodeSymbol(v)
+		return
+	}
 	l := uint64(len(v))
 	e.encBytesLen(c, l)
 	if l > 0 {
@@ -522,34 +530,22 @@ func (d *bincDecDriver) decCheckInteger() (ui uint64, neg bool) {
 	return
 }
 
-func (d *bincDecDriver) DecodeInt(bitsize uint8) (i int64) {
+func (d *bincDecDriver) DecodeInt64() (i int64) {
 	ui, neg := d.decCheckInteger()
-	i, overflow := chkOvf.SignedInt(ui)
-	if overflow {
-		d.d.errorf("simple: overflow converting %v to signed integer", ui)
-		return
-	}
+	i = chkOvf.SignedIntV(ui)
 	if neg {
 		i = -i
 	}
-	if chkOvf.Int(i, bitsize) {
-		d.d.errorf("binc: overflow integer: %v for num bits: %v", i, bitsize)
-		return
-	}
 	d.bdRead = false
 	return
 }
 
-func (d *bincDecDriver) DecodeUint(bitsize uint8) (ui uint64) {
+func (d *bincDecDriver) DecodeUint64() (ui uint64) {
 	ui, neg := d.decCheckInteger()
 	if neg {
 		d.d.errorf("Assigning negative signed value to unsigned type")
 		return
 	}
-	if chkOvf.Uint(ui, bitsize) {
-		d.d.errorf("binc: overflow integer: %v", ui)
-		return
-	}
 	d.bdRead = false
 	return
 }
@@ -576,7 +572,7 @@ func (d *bincDecDriver) DecodeFloat64() (f float64) {
 	} else if vd == bincVdFloat {
 		f = d.decFloat()
 	} else {
-		f = float64(d.DecodeInt(64))
+		f = float64(d.DecodeInt64())
 	}
 	d.bdRead = false
 	return
@@ -932,6 +928,26 @@ type BincHandle struct {
 	BasicHandle
 	binaryEncodingType
 	noElemSeparators
+
+	// AsSymbols defines what should be encoded as symbols.
+	//
+	// Encoding as symbols can reduce the encoded size significantly.
+	//
+	// However, during decoding, each string to be encoded as a symbol must
+	// be checked to see if it has been seen before. Consequently, encoding time
+	// will increase if using symbols, because string comparisons has a clear cost.
+	//
+	// Values:
+	// - 0: default: library uses best judgement
+	// - 1: use symbols
+	// - 2: do not use symbols
+	AsSymbols byte
+
+	// AsSymbols: may later on introduce more options ...
+	// - m: map keys
+	// - s: struct fields
+	// - n: none
+	// - a: all: same as m, s, ...
 }
 
 // Name returns the name of the handle: binc
@@ -943,7 +959,7 @@ func (h *BincHandle) SetBytesExt(rt reflect.Type, tag uint64, ext BytesExt) (err
 }
 
 func (h *BincHandle) newEncDriver(e *Encoder) encDriver {
-	return &bincEncDriver{e: e, w: e.w}
+	return &bincEncDriver{e: e, h: h, w: e.w}
 }
 
 func (h *BincHandle) newDecDriver(d *Decoder) decDriver {
@@ -959,6 +975,7 @@ func (h *BincHandle) newDecDriver(d *Decoder) decDriver {
 func (e *bincEncDriver) reset() {
 	e.w = e.e.w
 	e.s = 0
+	e.c = 0
 	e.m = nil
 }
 

+ 15 - 31
codec/cbor.go

@@ -193,9 +193,9 @@ func (e *cborEncDriver) WriteArrayEnd() {
 	}
 }
 
-func (e *cborEncDriver) EncodeSymbol(v string) {
-	e.encStringBytesS(cborBaseString, v)
-}
+// func (e *cborEncDriver) EncodeSymbol(v string) {
+// 	e.encStringBytesS(cborBaseString, v)
+// }
 
 func (e *cborEncDriver) EncodeString(c charEncoding, v string) {
 	e.encStringBytesS(cborBaseString, v)
@@ -350,41 +350,25 @@ func (d *cborDecDriver) decCheckInteger() (neg bool) {
 	return
 }
 
-func (d *cborDecDriver) DecodeInt(bitsize uint8) (i int64) {
+func (d *cborDecDriver) DecodeInt64() (i int64) {
 	neg := d.decCheckInteger()
 	ui := d.decUint()
 	// check if this number can be converted to an int without overflow
-	var overflow bool
 	if neg {
-		if i, overflow = chkOvf.SignedInt(ui + 1); overflow {
-			d.d.errorf("cbor: overflow converting %v to signed integer", ui+1)
-			return
-		}
-		i = -i
+		i = -(chkOvf.SignedIntV(ui + 1))
 	} else {
-		if i, overflow = chkOvf.SignedInt(ui); overflow {
-			d.d.errorf("cbor: overflow converting %v to signed integer", ui)
-			return
-		}
-	}
-	if chkOvf.Int(i, bitsize) {
-		d.d.errorf("cbor: overflow integer: %v", i)
-		return
+		i = chkOvf.SignedIntV(ui)
 	}
 	d.bdRead = false
 	return
 }
 
-func (d *cborDecDriver) DecodeUint(bitsize uint8) (ui uint64) {
+func (d *cborDecDriver) DecodeUint64() (ui uint64) {
 	if d.decCheckInteger() {
 		d.d.errorf("Assigning negative signed value to unsigned type")
 		return
 	}
 	ui = d.decUint()
-	if chkOvf.Uint(ui, bitsize) {
-		d.d.errorf("cbor: overflow integer: %v", ui)
-		return
-	}
 	d.bdRead = false
 	return
 }
@@ -400,7 +384,7 @@ func (d *cborDecDriver) DecodeFloat64() (f float64) {
 	} else if bd == cborBdFloat64 {
 		f = math.Float64frombits(bigen.Uint64(d.r.readx(8)))
 	} else if bd >= cborBaseUint && bd < cborBaseBytes {
-		f = float64(d.DecodeInt(64))
+		f = float64(d.DecodeInt64())
 	} else {
 		d.d.errorf("Float only valid from float16/32/64: Invalid descriptor: %v", bd)
 		return
@@ -458,7 +442,7 @@ func (d *cborDecDriver) decAppendIndefiniteBytes(bs []byte) []byte {
 			break
 		}
 		if major := d.bd >> 5; major != cborMajorBytes && major != cborMajorText {
-			d.d.errorf("cbor: expect bytes or string major type in indefinite string/bytes; got: %v, byte: %v", major, d.bd)
+			d.d.errorf("expect bytes or string major type in indefinite string/bytes; got: %v, byte: %v", major, d.bd)
 			return nil
 		}
 		n := d.decLen()
@@ -553,12 +537,12 @@ func (d *cborDecDriver) decodeTime(xtag uint64) (t time.Time) {
 			f1, f2 := math.Modf(d.DecodeFloat64())
 			t = time.Unix(int64(f1), int64(f2*1e9))
 		case d.bd >= cborBaseUint && d.bd < cborBaseNegInt, d.bd >= cborBaseNegInt && d.bd < cborBaseBytes:
-			t = time.Unix(d.DecodeInt(64), 0)
+			t = time.Unix(d.DecodeInt64(), 0)
 		default:
-			d.d.errorf("cbor: time.Time can only be decoded from a number (or RFC3339 string)")
+			d.d.errorf("time.Time can only be decoded from a number (or RFC3339 string)")
 		}
 	default:
-		d.d.errorf("cbor: invalid tag for time.Time - expecting 0 or 1, got 0x%x", xtag)
+		d.d.errorf("invalid tag for time.Time - expecting 0 or 1, got 0x%x", xtag)
 	}
 	t = t.UTC().Round(time.Microsecond)
 	return
@@ -624,14 +608,14 @@ func (d *cborDecDriver) DecodeNaked() {
 		case d.bd >= cborBaseUint && d.bd < cborBaseNegInt:
 			if d.h.SignedInteger {
 				n.v = valueTypeInt
-				n.i = d.DecodeInt(64)
+				n.i = d.DecodeInt64()
 			} else {
 				n.v = valueTypeUint
-				n.u = d.DecodeUint(64)
+				n.u = d.DecodeUint64()
 			}
 		case d.bd >= cborBaseNegInt && d.bd < cborBaseBytes:
 			n.v = valueTypeInt
-			n.i = d.DecodeInt(64)
+			n.i = d.DecodeInt64()
 		case d.bd >= cborBaseBytes && d.bd < cborBaseString:
 			n.v = valueTypeBytes
 			n.l = d.DecodeBytes(nil, false)

+ 21 - 18
codec/codec_test.go

@@ -346,8 +346,8 @@ func testInit() {
 		// pre-fill them first
 		bh.EncodeOptions = testEncodeOptions
 		bh.DecodeOptions = testDecodeOptions
-		// bh.InterfaceReset = true // TODO: remove
-		// bh.PreferArrayOverSlice = true // TODO: remove
+		// bh.InterfaceReset = true
+		// bh.PreferArrayOverSlice = true
 		// modify from flag'ish things
 		bh.InternString = testInternStr
 		bh.Canonical = testCanonical
@@ -1878,8 +1878,6 @@ func doTestLargeContainerLen(t *testing.T, h Handle) {
 	testUnmarshalErr(m2, bs, h, t, "-")
 	testDeepEqualErr(m, m2, t, "-")
 
-	// TODO: skip rest if 32-bit
-
 	// do same tests for large strings (encoded as symbols or not)
 	// skip if 32-bit or not using unsafe mode
 	if safeMode || (32<<(^uint(0)>>63)) < 64 {
@@ -1891,10 +1889,11 @@ func doTestLargeContainerLen(t *testing.T, h Handle) {
 	// to do this, we create a simple one-field struct,
 	// use use flags to switch from symbols to non-symbols
 
-	bh := h.getBasicHandle()
-	oldAsSymbols := bh.AsSymbols
-	defer func() { bh.AsSymbols = oldAsSymbols }()
-
+	hbinc, okbinc := h.(*BincHandle)
+	if okbinc {
+		oldAsSymbols := hbinc.AsSymbols
+		defer func() { hbinc.AsSymbols = oldAsSymbols }()
+	}
 	var out []byte = make([]byte, 0, math.MaxUint16*3/2)
 	var in []byte = make([]byte, math.MaxUint16*3/2)
 	for i := range in {
@@ -1915,7 +1914,9 @@ func doTestLargeContainerLen(t *testing.T, h Handle) {
 		// fmt.Printf("testcontainerlen: large string: i: %v, |%s|\n", i, s1)
 		m1[s1] = true
 
-		bh.AsSymbols = AsSymbolNone
+		if okbinc {
+			hbinc.AsSymbols = 2
+		}
 		out = out[:0]
 		e.ResetBytes(&out)
 		e.MustEncode(m1)
@@ -1924,15 +1925,17 @@ func doTestLargeContainerLen(t *testing.T, h Handle) {
 		testUnmarshalErr(m2, out, h, t, "no-symbols")
 		testDeepEqualErr(m1, m2, t, "no-symbols")
 
-		// now, do as symbols
-		bh.AsSymbols = AsSymbolAll
-		out = out[:0]
-		e.ResetBytes(&out)
-		e.MustEncode(m1)
-		// bs, _ = testMarshalErr(m1, h, t, "-")
-		m2 = make(map[string]bool, 1)
-		testUnmarshalErr(m2, out, h, t, "symbols")
-		testDeepEqualErr(m1, m2, t, "symbols")
+		if okbinc {
+			// now, do as symbols
+			hbinc.AsSymbols = 1
+			out = out[:0]
+			e.ResetBytes(&out)
+			e.MustEncode(m1)
+			// bs, _ = testMarshalErr(m1, h, t, "-")
+			m2 = make(map[string]bool, 1)
+			testUnmarshalErr(m2, out, h, t, "symbols")
+			testDeepEqualErr(m1, m2, t, "symbols")
+		}
 	}
 
 }

+ 49 - 27
codec/decode.go

@@ -27,6 +27,8 @@ var (
 	errmsgExpandSliceOverflow     = "expand slice: slice overflow"
 	errmsgExpandSliceCannotChange = "expand slice: cannot change"
 
+	errDecoderNotInitialized = errors.New("Decoder not initialized")
+
 	errDecUnreadByteNothingToRead   = errors.New("cannot unread - nothing has been read")
 	errDecUnreadByteLastByteNotRead = errors.New("cannot unread - last byte has not been read")
 	errDecUnreadByteUnknown         = errors.New("cannot unread - reason unknown")
@@ -80,8 +82,12 @@ type decDriver interface {
 	// kInterface will extract the detached byte slice if it has to pass it outside its realm.
 	DecodeNaked()
 
-	DecodeInt(bitsize uint8) (i int64)
-	DecodeUint(bitsize uint8) (ui uint64)
+	// Deprecated: use DecodeInt64 and DecodeUint64 instead
+	// DecodeInt(bitsize uint8) (i int64)
+	// DecodeUint(bitsize uint8) (ui uint64)
+
+	DecodeInt64() (i int64)
+	DecodeUint64() (ui uint64)
 
 	DecodeFloat64() (f float64)
 	DecodeBool() (b bool)
@@ -1076,7 +1082,7 @@ func (d *Decoder) kInterfaceNaked(f *codecFnInfo) (rvn reflect.Value) {
 	case valueTypeTime:
 		rvn = n.rr[decNakedTimeIdx] // d.np.get(&n.t)
 	default:
-		panic(fmt.Errorf("kInterfaceNaked: unexpected valueType: %d", n.v))
+		panicv.errorf("kInterfaceNaked: unexpected valueType: %d", n.v)
 	}
 	return
 }
@@ -1131,19 +1137,35 @@ func (d *Decoder) kInterface(f *codecFnInfo, rv reflect.Value) {
 }
 
 func decStructFieldKey(dd decDriver, keyType valueType, b *[scratchByteArrayLen]byte) (rvkencname []byte) {
-	switch keyType {
-	case valueTypeString:
-		rvkencname = (dd.DecodeStringAsBytes())
-	case valueTypeInt:
-		rvkencname = (strconv.AppendInt(b[:0], dd.DecodeInt(64), 10))
-	case valueTypeUint:
-		rvkencname = (strconv.AppendUint(b[:0], dd.DecodeUint(64), 10))
-	case valueTypeFloat:
-		rvkencname = (strconv.AppendFloat(b[:0], dd.DecodeFloat64(), 'f', -1, 64))
-	default: // string
-		rvkencname = (dd.DecodeStringAsBytes())
-	}
-	return
+	// use if-else-if, not switch (which compiles to binary-search)
+	// since keyType is typically valueTypeString, branch prediction is pretty good.
+
+	if keyType == valueTypeString {
+		rvkencname = dd.DecodeStringAsBytes()
+	} else if keyType == valueTypeInt {
+		rvkencname = strconv.AppendInt(b[:0], dd.DecodeInt64(), 10)
+	} else if keyType == valueTypeUint {
+		rvkencname = strconv.AppendUint(b[:0], dd.DecodeUint64(), 10)
+	} else if keyType == valueTypeFloat {
+		rvkencname = strconv.AppendFloat(b[:0], dd.DecodeFloat64(), 'f', -1, 64)
+	} else {
+		rvkencname = dd.DecodeStringAsBytes()
+	}
+	return rvkencname
+
+	// switch keyType {
+	// case valueTypeString:
+	// 	return dd.DecodeStringAsBytes()
+	// case valueTypeInt:
+	// 	return strconv.AppendInt(b[:0], dd.DecodeInt64(), 10)
+	// case valueTypeUint:
+	// 	return strconv.AppendUint(b[:0], dd.DecodeUint64(), 10)
+	// case valueTypeFloat:
+	// 	return strconv.AppendFloat(b[:0], dd.DecodeFloat64(), 'f', -1, 64)
+	// 	// default: // string
+	// 	// 	return dd.DecodeStringAsBytes()
+	// }
+	// return dd.DecodeStringAsBytes()
 }
 
 func (d *Decoder) kStruct(f *codecFnInfo, rv reflect.Value) {
@@ -1846,7 +1868,7 @@ func NewDecoderBytes(in []byte, h Handle) *Decoder {
 var defaultDecNaked decNaked
 
 func newDecoder(h Handle) *Decoder {
-	d := &Decoder{hh: h, h: h.getBasicHandle()}
+	d := &Decoder{hh: h, h: h.getBasicHandle(), err: errDecoderNotInitialized}
 	d.be = h.isBinary()
 	// NOTE: do not initialize d.n here. It is lazily initialized in d.naked()
 	var jh *JsonHandle
@@ -2154,25 +2176,25 @@ func (d *Decoder) decode(iv interface{}) {
 	case *bool:
 		*v = d.d.DecodeBool()
 	case *int:
-		*v = int(d.d.DecodeInt(intBitsize))
+		*v = int(chkOvf.IntV(d.d.DecodeInt64(), intBitsize))
 	case *int8:
-		*v = int8(d.d.DecodeInt(8))
+		*v = int8(chkOvf.IntV(d.d.DecodeInt64(), 8))
 	case *int16:
-		*v = int16(d.d.DecodeInt(16))
+		*v = int16(chkOvf.IntV(d.d.DecodeInt64(), 16))
 	case *int32:
-		*v = int32(d.d.DecodeInt(32))
+		*v = int32(chkOvf.IntV(d.d.DecodeInt64(), 32))
 	case *int64:
-		*v = d.d.DecodeInt(64)
+		*v = d.d.DecodeInt64()
 	case *uint:
-		*v = uint(d.d.DecodeUint(uintBitsize))
+		*v = uint(chkOvf.UintV(d.d.DecodeUint64(), uintBitsize))
 	case *uint8:
-		*v = uint8(d.d.DecodeUint(8))
+		*v = uint8(chkOvf.UintV(d.d.DecodeUint64(), 8))
 	case *uint16:
-		*v = uint16(d.d.DecodeUint(16))
+		*v = uint16(chkOvf.UintV(d.d.DecodeUint64(), 16))
 	case *uint32:
-		*v = uint32(d.d.DecodeUint(32))
+		*v = uint32(chkOvf.UintV(d.d.DecodeUint64(), 32))
 	case *uint64:
-		*v = d.d.DecodeUint(64)
+		*v = d.d.DecodeUint64()
 	case *float32:
 		f64 := d.d.DecodeFloat64()
 		if chkOvf.Float32(f64) {

+ 90 - 75
codec/encode.go

@@ -20,25 +20,25 @@ const defEncByteBufSize = 1 << 6 // 4:16, 6:64, 8:256, 10:1024
 
 var errEncoderNotInitialized = errors.New("Encoder not initialized")
 
-// AsSymbolFlag defines what should be encoded as symbols.
-type AsSymbolFlag uint8
+// // AsSymbolFlag defines what should be encoded as symbols.
+// type AsSymbolFlag uint8
 
-const (
-	// AsSymbolDefault means only encode struct field names as symbols.
-	AsSymbolDefault AsSymbolFlag = iota
+// const (
+// 	// AsSymbolDefault means only encode struct field names as symbols.
+// 	AsSymbolDefault AsSymbolFlag = iota
 
-	// AsSymbolAll means encode anything which could be a symbol as a symbol.
-	AsSymbolAll = 0xfe
+// 	// AsSymbolAll means encode anything which could be a symbol as a symbol.
+// 	AsSymbolAll = 0xfe
 
-	// AsSymbolNone means do not encode anything as a symbol.
-	AsSymbolNone = 1 << iota
+// 	// AsSymbolNone means do not encode anything as a symbol.
+// 	AsSymbolNone = 1 << iota
 
-	// AsSymbolMapStringKeysFlag means encode keys in map[string]XXX as symbols.
-	AsSymbolMapStringKeysFlag
+// 	// AsSymbolMapStringKeysFlag means encode keys in map[string]XXX as symbols.
+// 	AsSymbolMapStringKeysFlag
 
-	// AsSymbolStructFieldNameFlag means encode struct field names as symbols.
-	AsSymbolStructFieldNameFlag
-)
+// 	// AsSymbolStructFieldNameFlag means encode struct field names as symbols.
+// 	AsSymbolStructFieldNameFlag
+// )
 
 // encWriter abstracts writing to a byte array or to an io.Writer.
 type encWriter interface {
@@ -53,8 +53,8 @@ type encWriter interface {
 type encDriver interface {
 	// IsBuiltinType(rt uintptr) bool
 
-	// Deprecated: left here for now so that old codecgen'ed filed will work. TODO: remove.
-	EncodeBuiltin(rt uintptr, v interface{})
+	// Deprecated: left here for now so that old codecgen'ed filed will work.
+	// EncodeBuiltin(rt uintptr, v interface{})
 
 	EncodeNil()
 	EncodeInt(i int64)
@@ -65,6 +65,12 @@ type encDriver interface {
 	// encodeExtPreamble(xtag byte, length int)
 	EncodeRawExt(re *RawExt, e *Encoder)
 	EncodeExt(v interface{}, xtag uint64, ext Ext, e *Encoder)
+	EncodeString(c charEncoding, v string)
+	// EncodeSymbol(v string)
+	EncodeStringBytes(c charEncoding, v []byte)
+	EncodeTime(time.Time)
+	//encBignum(f *big.Int)
+	//encStringRunes(c charEncoding, v []rune)
 	WriteArrayStart(length int)
 	WriteArrayElem()
 	WriteArrayEnd()
@@ -72,13 +78,6 @@ type encDriver interface {
 	WriteMapElemKey()
 	WriteMapElemValue()
 	WriteMapEnd()
-	EncodeString(c charEncoding, v string)
-	EncodeSymbol(v string)
-	EncodeStringBytes(c charEncoding, v []byte)
-	EncodeTime(time.Time)
-	//TODO
-	//encBignum(f *big.Int)
-	//encStringRunes(c charEncoding, v []rune)
 
 	reset()
 	atEndOfEncode()
@@ -103,6 +102,19 @@ func (encDriverNoopContainerWriter) WriteMapElemValue()         {}
 func (encDriverNoopContainerWriter) WriteMapEnd()               {}
 func (encDriverNoopContainerWriter) atEndOfEncode()             {}
 
+type encDriverTrackContainerWriter struct {
+	c containerState
+}
+
+func (e *encDriverTrackContainerWriter) WriteArrayStart(length int) { e.c = containerArrayStart }
+func (e *encDriverTrackContainerWriter) WriteArrayElem()            { e.c = containerArrayElem }
+func (e *encDriverTrackContainerWriter) WriteArrayEnd()             { e.c = containerArrayEnd }
+func (e *encDriverTrackContainerWriter) WriteMapStart(length int)   { e.c = containerMapStart }
+func (e *encDriverTrackContainerWriter) WriteMapElemKey()           { e.c = containerMapKey }
+func (e *encDriverTrackContainerWriter) WriteMapElemValue()         { e.c = containerMapValue }
+func (e *encDriverTrackContainerWriter) WriteMapEnd()               { e.c = containerMapEnd }
+func (e *encDriverTrackContainerWriter) atEndOfEncode()             {}
+
 // type ioEncWriterWriter interface {
 // 	WriteByte(c byte) error
 // 	WriteString(s string) (n int, err error)
@@ -152,20 +164,20 @@ type EncodeOptions struct {
 	// If unset, we error out.
 	Raw bool
 
-	// AsSymbols defines what should be encoded as symbols.
-	//
-	// Encoding as symbols can reduce the encoded size significantly.
-	//
-	// However, during decoding, each string to be encoded as a symbol must
-	// be checked to see if it has been seen before. Consequently, encoding time
-	// will increase if using symbols, because string comparisons has a clear cost.
-	//
-	// Sample values:
-	//   AsSymbolNone
-	//   AsSymbolAll
-	//   AsSymbolMapStringKeys
-	//   AsSymbolMapStringKeysFlag | AsSymbolStructFieldNameFlag
-	AsSymbols AsSymbolFlag
+	// // AsSymbols defines what should be encoded as symbols.
+	// //
+	// // Encoding as symbols can reduce the encoded size significantly.
+	// //
+	// // However, during decoding, each string to be encoded as a symbol must
+	// // be checked to see if it has been seen before. Consequently, encoding time
+	// // will increase if using symbols, because string comparisons has a clear cost.
+	// //
+	// // Sample values:
+	// //   AsSymbolNone
+	// //   AsSymbolAll
+	// //   AsSymbolMapStringKeys
+	// //   AsSymbolMapStringKeysFlag | AsSymbolStructFieldNameFlag
+	// AsSymbols AsSymbolFlag
 
 	// WriterBufferSize is the size of the buffer used when writing.
 	//
@@ -422,7 +434,6 @@ func (e *Encoder) kSlice(f *codecFnInfo, rv reflect.Value) {
 		if rtelem.Kind() != reflect.Interface {
 			fn = e.cf.get(rtelem, true, true)
 		}
-		// TODO: Consider perf implication of encoding odd index values as symbols if type is string
 		for j := 0; j < l; j++ {
 			if elemsep {
 				if ti.mbs {
@@ -468,17 +479,19 @@ func (e *Encoder) kStructNoOmitempty(f *codecFnInfo, rv reflect.Value) {
 	if toMap {
 		ee.WriteMapStart(len(tisfi))
 		// asSymbols := e.h.AsSymbols&AsSymbolStructFieldNameFlag != 0
-		asSymbols := e.h.AsSymbols == AsSymbolDefault || e.h.AsSymbols&AsSymbolStructFieldNameFlag != 0
+		// asSymbols := e.h.AsSymbols == AsSymbolDefault || e.h.AsSymbols&AsSymbolStructFieldNameFlag != 0
 		if elemsep {
 			for _, si := range tisfi {
 				ee.WriteMapElemKey()
-				encStructFieldKey(ee, fti.keyType, si.encName, asSymbols)
+				// ee.EncodeString(cUTF8, si.encName)
+				encStructFieldKey(ee, fti.keyType, si.encName)
 				ee.WriteMapElemValue()
 				e.encodeValue(sfn.field(si), nil, true)
 			}
 		} else {
 			for _, si := range tisfi {
-				encStructFieldKey(ee, fti.keyType, si.encName, asSymbols)
+				// ee.EncodeString(cUTF8, si.encName)
+				encStructFieldKey(ee, fti.keyType, si.encName)
 				e.encodeValue(sfn.field(si), nil, true)
 			}
 		}
@@ -499,28 +512,36 @@ func (e *Encoder) kStructNoOmitempty(f *codecFnInfo, rv reflect.Value) {
 	}
 }
 
-func encStructFieldKey(ee encDriver, keyType valueType, s string, asSymbols bool) {
+func encStructFieldKey(ee encDriver, keyType valueType, s string) {
 	var m must
-	switch keyType {
-	case valueTypeString:
-		if asSymbols {
-			ee.EncodeSymbol(s)
-		} else {
-			ee.EncodeString(cUTF8, s)
-		}
-	case valueTypeInt:
+
+	// use if-else-if, not switch (which compiles to binary-search)
+	// since keyType is typically valueTypeString, branch prediction is pretty good.
+
+	if keyType == valueTypeString {
+		ee.EncodeString(cUTF8, s)
+	} else if keyType == valueTypeInt {
 		ee.EncodeInt(m.Int(strconv.ParseInt(s, 10, 64)))
-	case valueTypeUint:
+	} else if keyType == valueTypeUint {
 		ee.EncodeUint(m.Uint(strconv.ParseUint(s, 10, 64)))
-	case valueTypeFloat:
+	} else if keyType == valueTypeFloat {
 		ee.EncodeFloat64(m.Float(strconv.ParseFloat(s, 64)))
-	default: // string
-		if asSymbols {
-			ee.EncodeSymbol(s)
-		} else {
-			ee.EncodeString(cUTF8, s)
-		}
+	} else {
+		ee.EncodeString(cUTF8, s)
 	}
+
+	// switch keyType {
+	// case valueTypeString:
+	// 	ee.EncodeString(cUTF8, s)
+	// case valueTypeInt:
+	// 	ee.EncodeInt(m.Int(strconv.ParseInt(s, 10, 64)))
+	// case valueTypeUint:
+	// 	ee.EncodeUint(m.Uint(strconv.ParseUint(s, 10, 64)))
+	// case valueTypeFloat:
+	// 	ee.EncodeFloat64(m.Float(strconv.ParseFloat(s, 64)))
+	// default: // string
+	// 	ee.EncodeString(cUTF8, s)
+	// }
 }
 
 func (e *Encoder) kStruct(f *codecFnInfo, rv reflect.Value) {
@@ -598,19 +619,21 @@ func (e *Encoder) kStruct(f *codecFnInfo, rv reflect.Value) {
 	if toMap {
 		ee.WriteMapStart(newlen)
 		// asSymbols := e.h.AsSymbols&AsSymbolStructFieldNameFlag != 0
-		asSymbols := e.h.AsSymbols == AsSymbolDefault || e.h.AsSymbols&AsSymbolStructFieldNameFlag != 0
+		// asSymbols := e.h.AsSymbols == AsSymbolDefault || e.h.AsSymbols&AsSymbolStructFieldNameFlag != 0
 		if elemsep {
 			for j := 0; j < newlen; j++ {
 				kv = fkvs[j]
 				ee.WriteMapElemKey()
-				encStructFieldKey(ee, fti.keyType, kv.v, asSymbols)
+				// ee.EncodeString(cUTF8, kv.v)
+				encStructFieldKey(ee, fti.keyType, kv.v)
 				ee.WriteMapElemValue()
 				e.encodeValue(kv.r, nil, true)
 			}
 		} else {
 			for j := 0; j < newlen; j++ {
 				kv = fkvs[j]
-				encStructFieldKey(ee, fti.keyType, kv.v, asSymbols)
+				// ee.EncodeString(cUTF8, kv.v)
+				encStructFieldKey(ee, fti.keyType, kv.v)
 				e.encodeValue(kv.r, nil, true)
 			}
 		}
@@ -652,7 +675,7 @@ func (e *Encoder) kMap(f *codecFnInfo, rv reflect.Value) {
 		ee.WriteMapEnd()
 		return
 	}
-	var asSymbols bool
+	// var asSymbols bool
 	// determine the underlying key and val encFn's for the map.
 	// This eliminates some work which is done for each loop iteration i.e.
 	// rv.Type(), ref.ValueOf(rt).Pointer(), then check map/list for fn.
@@ -676,14 +699,14 @@ func (e *Encoder) kMap(f *codecFnInfo, rv reflect.Value) {
 	mks := rv.MapKeys()
 
 	if e.h.Canonical {
-		e.kMapCanonical(rtkey, rv, mks, valFn, asSymbols)
+		e.kMapCanonical(rtkey, rv, mks, valFn)
 		ee.WriteMapEnd()
 		return
 	}
 
 	var keyTypeIsString = stringTypId == rt2id(rtkey0) // rtkeyid
 	if keyTypeIsString {
-		asSymbols = e.h.AsSymbols&AsSymbolMapStringKeysFlag != 0
+		// asSymbols = e.h.AsSymbols&AsSymbolMapStringKeysFlag != 0
 	} else {
 		for rtkey.Kind() == reflect.Ptr {
 			rtkey = rtkey.Elem()
@@ -700,11 +723,7 @@ func (e *Encoder) kMap(f *codecFnInfo, rv reflect.Value) {
 			ee.WriteMapElemKey()
 		}
 		if keyTypeIsString {
-			if asSymbols {
-				ee.EncodeSymbol(mks[j].String())
-			} else {
-				ee.EncodeString(cUTF8, mks[j].String())
-			}
+			ee.EncodeString(cUTF8, mks[j].String())
 		} else {
 			e.encodeValue(mks[j], keyFn, true)
 		}
@@ -717,7 +736,7 @@ func (e *Encoder) kMap(f *codecFnInfo, rv reflect.Value) {
 	ee.WriteMapEnd()
 }
 
-func (e *Encoder) kMapCanonical(rtkey reflect.Type, rv reflect.Value, mks []reflect.Value, valFn *codecFn, asSymbols bool) {
+func (e *Encoder) kMapCanonical(rtkey reflect.Type, rv reflect.Value, mks []reflect.Value, valFn *codecFn) {
 	ee := e.e
 	elemsep := e.esep
 	// we previously did out-of-band if an extension was registered.
@@ -776,11 +795,7 @@ func (e *Encoder) kMapCanonical(rtkey reflect.Type, rv reflect.Value, mks []refl
 			if elemsep {
 				ee.WriteMapElemKey()
 			}
-			if asSymbols {
-				ee.EncodeSymbol(mksv[i].v)
-			} else {
-				ee.EncodeString(cUTF8, mksv[i].v)
-			}
+			ee.EncodeString(cUTF8, mksv[i].v)
 			if elemsep {
 				ee.WriteMapElemValue()
 			}

文件差異過大導致無法顯示
+ 369 - 193
codec/fast-path.generated.go


+ 76 - 22
codec/fast-path.go.tmpl

@@ -118,7 +118,7 @@ func fastpathEncodeTypeSwitch(iv interface{}, e *Encoder) bool {
 */}}{{end}}{{end}}{{end}}
 
 	default:
-        _ = v // TODO: workaround https://github.com/golang/go/issues/12927 (remove after go 1.6 release)
+        _ = v // workaround https://github.com/golang/go/issues/12927 seen in go1.4
 		return false
 	}
 	return true
@@ -142,7 +142,7 @@ func fastpathEncodeTypeSwitchSlice(iv interface{}, e *Encoder) bool {
 		fastpathTV.{{ .MethodNamePfx "Enc" false }}V(*v, e)
 {{end}}{{end}}{{end}}
 	default:
-        _ = v // TODO: workaround https://github.com/golang/go/issues/12927 (remove after go 1.6 release)
+        _ = v // workaround https://github.com/golang/go/issues/12927 seen in go1.4
 		return false
 	}
 	return true
@@ -157,7 +157,7 @@ func fastpathEncodeTypeSwitchMap(iv interface{}, e *Encoder) bool {
 		fastpathTV.{{ .MethodNamePfx "Enc" false }}V(*v, e)
 {{end}}{{end}}{{end}}
 	default:
-        _ = v // TODO: workaround https://github.com/golang/go/issues/12927 (remove after go 1.6 release)
+        _ = v // workaround https://github.com/golang/go/issues/12927 seen in go1.4
 		return false
 	}
 	return true
@@ -185,10 +185,20 @@ func (_ fastpathT) {{ .MethodNamePfx "Enc" false }}V(v []{{ .Elem }}, e *Encoder
 	if v == nil { e.e.EncodeNil(); return }
 	ee, esep := e.e, e.hh.hasElemSeparators()
 	ee.WriteArrayStart(len(v))
+	if esep {
+		for _, v2 := range v {
+			ee.WriteArrayElem()
+			{{ encmd .Elem "v2"}}
+		}
+	} else {
+		for _, v2 := range v {
+			{{ encmd .Elem "v2"}}
+		}
+	} {{/*
 	for _, v2 := range v {
 		if esep { ee.WriteArrayElem() }
 		{{ encmd .Elem "v2"}}
-	}
+	} */}}
 	ee.WriteArrayEnd()
 }
 func (_ fastpathT) {{ .MethodNamePfx "EncAsMap" false }}V(v []{{ .Elem }}, e *Encoder) {
@@ -198,6 +208,20 @@ func (_ fastpathT) {{ .MethodNamePfx "EncAsMap" false }}V(v []{{ .Elem }}, e *En
 		return
 	}
 	ee.WriteMapStart(len(v) / 2)
+	if esep {
+		for j, v2 := range v {
+			if j%2 == 0 {
+				ee.WriteMapElemKey()
+			} else {
+				ee.WriteMapElemValue()
+			}
+			{{ encmd .Elem "v2"}}
+		}
+	} else {
+		for _, v2 := range v {
+			{{ encmd .Elem "v2"}}
+		}
+	} {{/*
 	for j, v2 := range v {
 		if esep {
 			if j%2 == 0 {
@@ -207,7 +231,7 @@ func (_ fastpathT) {{ .MethodNamePfx "EncAsMap" false }}V(v []{{ .Elem }}, e *En
 			}
 		}
 		{{ encmd .Elem "v2"}}
-	}
+	} */}}
 	ee.WriteMapEnd()
 }
 {{end}}{{end}}{{end}}
@@ -220,8 +244,7 @@ func (_ fastpathT) {{ .MethodNamePfx "Enc" false }}V(v map[{{ .MapKey }}]{{ .Ele
 	if v == nil { e.e.EncodeNil(); return }
 	ee, esep := e.e, e.hh.hasElemSeparators() 
 	ee.WriteMapStart(len(v))
-	{{if eq .MapKey "string"}}asSymbols := e.h.AsSymbols&AsSymbolMapStringKeysFlag != 0
-	{{end}}if e.h.Canonical {
+	if 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)
@@ -237,39 +260,70 @@ func (_ fastpathT) {{ .MethodNamePfx "Enc" false }}V(v map[{{ .MapKey }}]{{ .Ele
 			i++
 		}
 		sort.Sort(bytesISlice(v2))
+		if esep {
+			for j := range v2 {
+				ee.WriteMapElemKey()
+				e.asis(v2[j].v)
+				ee.WriteMapElemValue()
+				e.encode(v[v2[j].i])
+			}
+		} else {
+			for j := range v2 {
+				e.asis(v2[j].v)
+				e.encode(v[v2[j].i])
+			}
+		} {{/*
 		for j := range v2 {
 			if esep { ee.WriteMapElemKey() }
 			e.asis(v2[j].v)
 			if esep { ee.WriteMapElemValue() }
 			e.encode(v[v2[j].i])
-		} {{else}}{{ $x := sorttype .MapKey true}}v2 := make([]{{ $x }}, len(v))
+		} */}} {{else}}{{ $x := sorttype .MapKey true}}v2 := make([]{{ $x }}, len(v))
 		var i int 
 		for k, _ := range v {
 			v2[i] = {{ $x }}(k)
 			i++
 		}
 		sort.Sort({{ sorttype .MapKey false}}(v2))
+		if esep {
+			for _, k2 := range v2 {
+				ee.WriteMapElemKey()
+				{{if eq .MapKey "string"}}ee.EncodeString(cUTF8, k2){{else}}{{ $y := printf "%s(k2)" .MapKey }}{{ encmd .MapKey $y }}{{end}}
+				ee.WriteMapElemValue()
+				{{ $y := printf "v[%s(k2)]" .MapKey }}{{ encmd .Elem $y }}
+			} 
+		} else {
+			for _, k2 := range v2 {
+				{{if eq .MapKey "string"}}ee.EncodeString(cUTF8, k2){{else}}{{ $y := printf "%s(k2)" .MapKey }}{{ encmd .MapKey $y }}{{end}}
+				{{ $y := printf "v[%s(k2)]" .MapKey }}{{ encmd .Elem $y }}
+			} 
+		} {{/*
 		for _, k2 := range v2 {
 			if esep { ee.WriteMapElemKey() }
-			{{if eq .MapKey "string"}}if asSymbols {
-				ee.EncodeSymbol(k2)
-			} else {
-				ee.EncodeString(cUTF8, k2)
-			}{{else}}{{ $y := printf "%s(k2)" .MapKey }}{{ encmd .MapKey $y }}{{end}}
+			{{if eq .MapKey "string"}}ee.EncodeString(cUTF8, k2){{else}}{{ $y := printf "%s(k2)" .MapKey }}{{ encmd .MapKey $y }}{{end}}
 			if esep { ee.WriteMapElemValue() }
 			{{ $y := printf "v[%s(k2)]" .MapKey }}{{ encmd .Elem $y }}
-		} {{end}}
+		} */}} {{end}}
 	} else {
+		if esep {
+			for k2, v2 := range v {
+				ee.WriteMapElemKey()
+				{{if eq .MapKey "string"}}ee.EncodeString(cUTF8, k2){{else}}{{ encmd .MapKey "k2"}}{{end}}
+				ee.WriteMapElemValue()
+				{{ encmd .Elem "v2"}}
+			}
+		} else {
+			for k2, v2 := range v {
+				{{if eq .MapKey "string"}}ee.EncodeString(cUTF8, k2){{else}}{{ encmd .MapKey "k2"}}{{end}}
+				{{ encmd .Elem "v2"}}
+			}
+		} {{/*
 		for k2, v2 := range v {
 			if esep { ee.WriteMapElemKey() }
-			{{if eq .MapKey "string"}}if asSymbols {
-				ee.EncodeSymbol(k2)
-			} else {
-				ee.EncodeString(cUTF8, k2)
-			}{{else}}{{ encmd .MapKey "k2"}}{{end}}
+			{{if eq .MapKey "string"}}ee.EncodeString(cUTF8, k2){{else}}{{ encmd .MapKey "k2"}}{{end}}
 			if esep { ee.WriteMapElemValue() }
 			{{ encmd .Elem "v2"}}
-		}
+		} */}}
 	}
 	ee.WriteMapEnd()
 }
@@ -308,7 +362,7 @@ func fastpathDecodeTypeSwitch(iv interface{}, d *Decoder) bool {
 		}{{/*
 */}}{{end}}{{end}}{{end}}
 	default:
-        _ = v // TODO: workaround https://github.com/golang/go/issues/12927 (remove after go 1.6 release)
+        _ = v // workaround https://github.com/golang/go/issues/12927 seen in go1.4
 		return false
 	}
 	return true
@@ -325,7 +379,7 @@ func fastpathDecodeSetZeroTypeSwitch(iv interface{}) bool {
 		*v = nil {{/*
 */}}{{end}}{{end}}{{end}}
 	default:
-        _ = v // TODO: workaround https://github.com/golang/go/issues/12927 (remove after go 1.6 release)
+        _ = v // workaround https://github.com/golang/go/issues/12927 seen in go1.4
 		return false
 	}
 	return true

+ 30 - 19
codec/gen-helper.generated.go

@@ -25,23 +25,51 @@ const GenVersion = 8
 // When static codecs are created for types, they will use this value
 // to perform encoding or decoding of primitives or known slice or map types.
 
+// GenHelperEncoder is exported so that it can be used externally by codecgen.
+//
+// Library users: DO NOT USE IT DIRECTLY. IT WILL CHANGE CONTINOUSLY WITHOUT NOTICE.
+func GenHelperEncoder(e *Encoder) (ge genHelperEncoder, ee genHelperEncDriver) {
+	ge = genHelperEncoder{e: e}
+	ee = genHelperEncDriver{encDriver: e.e}
+	return
+}
+
+// GenHelperDecoder is exported so that it can be used externally by codecgen.
+//
+// Library users: DO NOT USE IT DIRECTLY. IT WILL CHANGE CONTINOUSLY WITHOUT NOTICE.
+func GenHelperDecoder(d *Decoder) (gd genHelperDecoder, dd genHelperDecDriver) {
+	gd = genHelperDecoder{d: d}
+	dd = genHelperDecDriver{decDriver: d.d}
+	return
+}
+
 type genHelperEncDriver struct {
 	encDriver
 }
 
 func (x genHelperEncDriver) EncodeBuiltin(rt uintptr, v interface{}) {}
 func (x genHelperEncDriver) EncStructFieldKey(keyType valueType, s string) {
-	encStructFieldKey(x.encDriver, keyType, s, false)
+	encStructFieldKey(x.encDriver, keyType, s)
+}
+func (x genHelperEncDriver) EncodeSymbol(s string) {
+	x.encDriver.EncodeString(cUTF8, s)
 }
 
 type genHelperDecDriver struct {
 	decDriver
+	c checkOverflow
 }
 
 func (x genHelperDecDriver) DecodeBuiltin(rt uintptr, v interface{}) {}
 func (x genHelperDecDriver) DecStructFieldKey(keyType valueType, buf *[scratchByteArrayLen]byte) []byte {
 	return decStructFieldKey(x.decDriver, keyType, buf)
 }
+func (x genHelperDecDriver) DecodeInt(bitsize uint8) (i int64) {
+	return x.c.IntV(x.decDriver.DecodeInt64(), bitsize)
+}
+func (x genHelperDecDriver) DecodeUint(bitsize uint8) (ui uint64) {
+	return x.c.UintV(x.decDriver.DecodeUint64(), bitsize)
+}
 func (x genHelperDecDriver) DecodeFloat(chkOverflow32 bool) (f float64) {
 	f = x.DecodeFloat64()
 	if chkOverflow32 && chkOvf.Float32(f) {
@@ -57,24 +85,6 @@ func (x genHelperDecDriver) DecodeFloat32As64() (f float64) {
 	return
 }
 
-// GenHelperEncoder is exported so that it can be used externally by codecgen.
-//
-// Library users: DO NOT USE IT DIRECTLY. IT WILL CHANGE CONTINOUSLY WITHOUT NOTICE.
-func GenHelperEncoder(e *Encoder) (ge genHelperEncoder, ee genHelperEncDriver) {
-	ge = genHelperEncoder{e: e}
-	ee = genHelperEncDriver{e.e}
-	return
-}
-
-// GenHelperDecoder is exported so that it can be used externally by codecgen.
-//
-// Library users: DO NOT USE IT DIRECTLY. IT WILL CHANGE CONTINOUSLY WITHOUT NOTICE.
-func GenHelperDecoder(d *Decoder) (gd genHelperDecoder, dd genHelperDecDriver) {
-	gd = genHelperDecoder{d: d}
-	dd = genHelperDecDriver{d.d}
-	return
-}
-
 // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
 type genHelperEncoder struct {
 	e *Encoder
@@ -83,6 +93,7 @@ type genHelperEncoder struct {
 
 // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
 type genHelperDecoder struct {
+	c checkOverflow
 	d *Decoder
 	F fastpathT
 }

+ 30 - 19
codec/gen-helper.go.tmpl

@@ -25,23 +25,51 @@ const GenVersion = {{ .Version }}
 // When static codecs are created for types, they will use this value
 // to perform encoding or decoding of primitives or known slice or map types.
 
+// GenHelperEncoder is exported so that it can be used externally by codecgen.
+//
+// Library users: DO NOT USE IT DIRECTLY. IT WILL CHANGE CONTINOUSLY WITHOUT NOTICE.
+func GenHelperEncoder(e *Encoder) (ge genHelperEncoder, ee genHelperEncDriver) {
+	ge = genHelperEncoder{e: e}
+	ee = genHelperEncDriver{encDriver: e.e}
+	return 
+}
+
+// GenHelperDecoder is exported so that it can be used externally by codecgen.
+//
+// Library users: DO NOT USE IT DIRECTLY. IT WILL CHANGE CONTINOUSLY WITHOUT NOTICE.
+func GenHelperDecoder(d *Decoder) (gd genHelperDecoder, dd genHelperDecDriver) {
+	gd = genHelperDecoder{d: d}
+	dd = genHelperDecDriver{decDriver: d.d}
+	return
+}
+
 type genHelperEncDriver struct {
 	encDriver
 }
 
 func (x genHelperEncDriver) EncodeBuiltin(rt uintptr, v interface{}) {}
 func (x genHelperEncDriver) EncStructFieldKey(keyType valueType, s string) {
-	encStructFieldKey(x.encDriver, keyType, s, false)
+	encStructFieldKey(x.encDriver, keyType, s)
+}
+func (x genHelperEncDriver) EncodeSymbol(s string) {
+	x.encDriver.EncodeString(cUTF8, s)
 }
 
 type genHelperDecDriver struct {
 	decDriver
+	c checkOverflow
 }
 
 func (x genHelperDecDriver) DecodeBuiltin(rt uintptr, v interface{}) {}
 func (x genHelperDecDriver) DecStructFieldKey(keyType valueType, buf *[scratchByteArrayLen]byte) []byte {
 	return decStructFieldKey(x.decDriver, keyType, buf)
 }
+func (x genHelperDecDriver) DecodeInt(bitsize uint8) (i int64) {
+	return x.c.IntV(x.decDriver.DecodeInt64(), bitsize)
+}
+func (x genHelperDecDriver) DecodeUint(bitsize uint8) (ui uint64) {
+	return x.c.UintV(x.decDriver.DecodeUint64(), bitsize)
+}
 func (x genHelperDecDriver) DecodeFloat(chkOverflow32 bool) (f float64) {
 	f = x.DecodeFloat64()
 	if chkOverflow32 && chkOvf.Float32(f) {
@@ -57,24 +85,6 @@ func (x genHelperDecDriver) DecodeFloat32As64() (f float64) {
 	return
 }
 
-// GenHelperEncoder is exported so that it can be used externally by codecgen.
-//
-// Library users: DO NOT USE IT DIRECTLY. IT WILL CHANGE CONTINOUSLY WITHOUT NOTICE.
-func GenHelperEncoder(e *Encoder) (ge genHelperEncoder, ee genHelperEncDriver) {
-	ge = genHelperEncoder{e:e}
-	ee = genHelperEncDriver{e.e}
-	return 
-}
-
-// GenHelperDecoder is exported so that it can be used externally by codecgen.
-//
-// Library users: DO NOT USE IT DIRECTLY. IT WILL CHANGE CONTINOUSLY WITHOUT NOTICE.
-func GenHelperDecoder(d *Decoder) (gd genHelperDecoder, dd genHelperDecDriver) {
-	gd = genHelperDecoder{d:d}
-	dd = genHelperDecDriver{d.d}
-	return
-}
-
 // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
 type genHelperEncoder struct {
 	e *Encoder
@@ -83,6 +93,7 @@ type genHelperEncoder struct {
 
 // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
 type genHelperDecoder struct {
+	c checkOverflow
 	d *Decoder
 	F fastpathT 
 }

+ 36 - 36
codec/gen.go

@@ -1211,38 +1211,38 @@ func (x *genRunner) dec(varname string, t reflect.Type) {
 	// Since these are pointers, we cannot share, and have to use them one by one
 	switch t.Kind() {
 	case reflect.Int:
-		x.line("*((*int)(" + varname + ")) = int(r.DecodeInt(codecSelferBitsize" + x.xs + "))")
+		x.line("*((*int)(" + varname + ")) = int(z.c.IntV(r.DecodeInt64(), codecSelferBitsize" + x.xs + "))")
 		// x.line("z.DecInt((*int)(" + varname + "))")
 	case reflect.Int8:
-		x.line("*((*int8)(" + varname + ")) = int8(r.DecodeInt(8))")
+		x.line("*((*int8)(" + varname + ")) = int8(z.c.IntV(r.DecodeInt64(), 8))")
 		// x.line("z.DecInt8((*int8)(" + varname + "))")
 	case reflect.Int16:
-		x.line("*((*int16)(" + varname + ")) = int16(r.DecodeInt(16))")
+		x.line("*((*int16)(" + varname + ")) = int16(z.c.IntV(r.DecodeInt64(), 16))")
 		// x.line("z.DecInt16((*int16)(" + varname + "))")
 	case reflect.Int32:
-		x.line("*((*int32)(" + varname + ")) = int32(r.DecodeInt(32))")
+		x.line("*((*int32)(" + varname + ")) = int32(z.c.IntV(r.DecodeInt64(), 32))")
 		// x.line("z.DecInt32((*int32)(" + varname + "))")
 	case reflect.Int64:
-		x.line("*((*int64)(" + varname + ")) = int64(r.DecodeInt(64))")
+		x.line("*((*int64)(" + varname + ")) = int64(r.DecodeInt64())")
 		// x.line("z.DecInt64((*int64)(" + varname + "))")
 
 	case reflect.Uint:
-		x.line("*((*uint)(" + varname + ")) = uint(r.DecodeUint(codecSelferBitsize" + x.xs + "))")
+		x.line("*((*uint)(" + varname + ")) = uint(z.c.UintV(r.DecodeUint64(), codecSelferBitsize" + x.xs + "))")
 		// x.line("z.DecUint((*uint)(" + varname + "))")
 	case reflect.Uint8:
-		x.line("*((*uint8)(" + varname + ")) = uint8(r.DecodeUint(8))")
+		x.line("*((*uint8)(" + varname + ")) = uint8(z.c.UintV(r.DecodeUint64(), 8))")
 		// x.line("z.DecUint8((*uint8)(" + varname + "))")
 	case reflect.Uint16:
-		x.line("*((*uint16)(" + varname + ")) = uint16(r.DecodeUint(16))")
+		x.line("*((*uint16)(" + varname + ")) = uint16(z.c.UintV(r.DecodeUint64(), 16))")
 		//x.line("z.DecUint16((*uint16)(" + varname + "))")
 	case reflect.Uint32:
-		x.line("*((*uint32)(" + varname + ")) = uint32(r.DecodeUint(32))")
+		x.line("*((*uint32)(" + varname + ")) = uint32(z.c.UintV(r.DecodeUint64(), 32))")
 		//x.line("z.DecUint32((*uint32)(" + varname + "))")
 	case reflect.Uint64:
-		x.line("*((*uint64)(" + varname + ")) = uint64(r.DecodeUint(64))")
+		x.line("*((*uint64)(" + varname + ")) = uint64(r.DecodeUint64())")
 		//x.line("z.DecUint64((*uint64)(" + varname + "))")
 	case reflect.Uintptr:
-		x.line("*((*uintptr)(" + varname + ")) = uintptr(r.DecodeUint(codecSelferBitsize" + x.xs + "))")
+		x.line("*((*uintptr)(" + varname + ")) = uintptr(z.c.UintV(r.DecodeUint64(), codecSelferBitsize" + x.xs + "))")
 
 	case reflect.Float32:
 		x.line("*((*float32)(" + varname + ")) = float32(r.DecodeFloat32As64())")
@@ -1314,28 +1314,28 @@ func (x *genRunner) decTryAssignPrimitive(varname string, t reflect.Type) (tryAs
 
 	switch t.Kind() {
 	case reflect.Int:
-		x.linef("%s = r.DecodeInt(codecSelferBitsize%s)", varname, x.xs)
+		x.linef("%s = z.c.IntV(r.DecodeInt64(), codecSelferBitsize%s)", varname, x.xs)
 	case reflect.Int8:
-		x.linef("%s = r.DecodeInt(8)", varname)
+		x.linef("%s = z.c.IntV(r.DecodeInt64(), 8)", varname)
 	case reflect.Int16:
-		x.linef("%s = r.DecodeInt(16)", varname)
+		x.linef("%s = z.c.IntV(r.DecodeInt64(), 16)", varname)
 	case reflect.Int32:
-		x.linef("%s = r.DecodeInt(32)", varname)
+		x.linef("%s = z.c.IntV(r.DecodeInt64(), 32)", varname)
 	case reflect.Int64:
-		x.linef("%s = r.DecodeInt(64)", varname)
+		x.linef("%s = r.DecodeInt64()", varname)
 
 	case reflect.Uint:
-		x.linef("%s = r.DecodeUint(codecSelferBitsize%s)", varname, x.xs)
+		x.linef("%s = z.c.UintV(r.DecodeUint64(), codecSelferBitsize%s)", varname, x.xs)
 	case reflect.Uint8:
-		x.linef("%s = r.DecodeUint(8)", varname)
+		x.linef("%s = z.c.UintV(r.DecodeUint64(), 8)", varname)
 	case reflect.Uint16:
-		x.linef("%s = r.DecodeUint(16)", varname)
+		x.linef("%s = z.c.UintV(r.DecodeUint64(), 16)", varname)
 	case reflect.Uint32:
-		x.linef("%s = r.DecodeUint(32)", varname)
+		x.linef("%s = z.c.UintV(r.DecodeUint64(), 32)", varname)
 	case reflect.Uint64:
-		x.linef("%s = r.DecodeUint(64)", varname)
+		x.linef("%s = r.DecodeUint64()", varname)
 	case reflect.Uintptr:
-		x.linef("%s = r.DecodeUint(codecSelferBitsize%s)", varname, x.xs)
+		x.linef("%s = z.c.UintV(r.DecodeUint64(), codecSelferBitsize%s)", varname, x.xs)
 
 	case reflect.Float32:
 		x.linef("%s = r.DecodeFloat32As64()", varname)
@@ -1865,8 +1865,8 @@ func genInternalEncCommandAsString(s string, vname string) string {
 		return "ee.EncodeFloat64(" + vname + ")"
 	case "bool":
 		return "ee.EncodeBool(" + vname + ")"
-	case "symbol":
-		return "ee.EncodeSymbol(" + vname + ")"
+	// case "symbol":
+	// 	return "ee.EncodeSymbol(" + vname + ")"
 	default:
 		return "e.encode(" + vname + ")"
 	}
@@ -1875,32 +1875,32 @@ func genInternalEncCommandAsString(s string, vname string) string {
 func genInternalDecCommandAsString(s string) string {
 	switch s {
 	case "uint":
-		return "uint(dd.DecodeUint(uintBitsize))"
+		return "uint(chkOvf.UintV(dd.DecodeUint64(), uintBitsize))"
 	case "uint8":
-		return "uint8(dd.DecodeUint(8))"
+		return "uint8(chkOvf.UintV(dd.DecodeUint64(), 8))"
 	case "uint16":
-		return "uint16(dd.DecodeUint(16))"
+		return "uint16(chkOvf.UintV(dd.DecodeUint64(), 16))"
 	case "uint32":
-		return "uint32(dd.DecodeUint(32))"
+		return "uint32(chkOvf.UintV(dd.DecodeUint64(), 32))"
 	case "uint64":
-		return "dd.DecodeUint(64)"
+		return "dd.DecodeUint64()"
 	case "uintptr":
-		return "uintptr(dd.DecodeUint(uintBitsize))"
+		return "uintptr(chkOvf.UintV(dd.DecodeUint64(), uintBitsize))"
 	case "int":
-		return "int(dd.DecodeInt(intBitsize))"
+		return "int(chkOvf.IntV(dd.DecodeInt64(), intBitsize))"
 	case "int8":
-		return "int8(dd.DecodeInt(8))"
+		return "int8(chkOvf.IntV(dd.DecodeInt64(), 8))"
 	case "int16":
-		return "int16(dd.DecodeInt(16))"
+		return "int16(chkOvf.IntV(dd.DecodeInt64(), 16))"
 	case "int32":
-		return "int32(dd.DecodeInt(32))"
+		return "int32(chkOvf.IntV(dd.DecodeInt64(), 32))"
 	case "int64":
-		return "dd.DecodeInt(64)"
+		return "dd.DecodeInt64()"
 
 	case "string":
 		return "dd.DecodeString()"
 	case "float32":
-		return "float32(chkFloat32(dd.DecodeFloat64()))"
+		return "float32(chkOvf.Float32V(dd.DecodeFloat64()))"
 	case "float64":
 		return "dd.DecodeFloat64()"
 	case "bool":

+ 61 - 33
codec/helper.go

@@ -565,7 +565,7 @@ type setExtWrapper struct {
 
 func (x *setExtWrapper) check(v bool, s string) {
 	if v {
-		panic(fmt.Errorf("%s is not supported", s))
+		panicv.errorf("%s is not supported", s)
 	}
 }
 func (x *setExtWrapper) WriteExt(v interface{}) []byte {
@@ -1072,7 +1072,7 @@ func (x *TypeInfos) get(rtid uintptr, rt reflect.Type) (pti *typeInfo) {
 	rk := rt.Kind()
 
 	if rk == reflect.Ptr { // || (rk == reflect.Interface && rtid != intfTypId) {
-		panic(fmt.Errorf("invalid kind passed to TypeInfos.get: %v - %v", rk, rt))
+		panicv.errorf("invalid kind passed to TypeInfos.get: %v - %v", rk, rt)
 	}
 
 	// do not hold lock while computing this.
@@ -1110,25 +1110,38 @@ func (x *TypeInfos) get(rtid uintptr, rt reflect.Type) (pti *typeInfo) {
 	}
 	// sfi = sfip
 
-	var vs []rtid2ti
 	x.mu.Lock()
 	sp = x.infos.load()
 	if sp == nil {
 		pti = &ti
-		vs = []rtid2ti{{rtid, pti}}
+		vs := append(make([]rtid2ti, 0, 16), rtid2ti{rtid, pti})
 		x.infos.store(&vs)
 	} else {
 		idx, pti = x.find(sp, rtid)
 		if pti == nil {
-			s := *sp
 			pti = &ti
-			vs = make([]rtid2ti, len(s)+1)
-			copy(vs, s[:idx])
+			vs := append(*sp, rtid2ti{})
+			copy(vs[idx+1:], vs[idx:])
 			vs[idx] = rtid2ti{rtid, pti}
-			copy(vs[idx+1:], s[idx:])
 			x.infos.store(&vs)
 		}
 	}
+	// if sp == nil {
+	// 	pti = &ti
+	// 	vs := []rtid2ti{{rtid, pti}}
+	// 	x.infos.store(&vs)
+	// } else {
+	// 	idx, pti = x.find(sp, rtid)
+	// 	if pti == nil {
+	// 		s := *sp
+	// 		pti = &ti
+	// 		vs := make([]rtid2ti, len(s)+1)
+	// 		copy(vs, s[:idx])
+	// 		vs[idx] = rtid2ti{rtid, pti}
+	// 		copy(vs[idx+1:], s[idx:])
+	// 		x.infos.store(&vs)
+	// 	}
+	// }
 	x.mu.Unlock()
 	return
 }
@@ -1146,7 +1159,7 @@ func (x *TypeInfos) rget(rt reflect.Type, rtid uintptr, omitEmpty bool,
 	//       and iteration using equals is faster than maps there
 	flen := rt.NumField()
 	if flen > (1<<maxLevelsEmbedding - 1) {
-		panic(fmt.Errorf("codec: types with more than %v fields are not supported - has %v fields", (1<<maxLevelsEmbedding - 1), flen))
+		panicv.errorf("codec: types with more than %v fields are not supported - has %v fields", (1<<maxLevelsEmbedding - 1), flen)
 	}
 LOOP:
 	for j, jlen := uint16(0), uint16(flen); j < jlen; j++ {
@@ -1243,7 +1256,7 @@ LOOP:
 
 		// si.ikind = int(f.Type.Kind())
 		if len(indexstack) > maxLevelsEmbedding-1 {
-			panic(fmt.Errorf("codec: only supports up to %v depth of embedding - type has %v depth", maxLevelsEmbedding-1, len(indexstack)))
+			panicv.errorf("codec: only supports up to %v depth of embedding - type has %v depth", maxLevelsEmbedding-1, len(indexstack))
 		}
 		si.nis = uint8(len(indexstack)) + 1
 		copy(si.is[:], indexstack)
@@ -1261,7 +1274,7 @@ LOOP:
 func rgetResolveSFI(x []*structFieldInfo, pv []sfiIdx) (y, z []*structFieldInfo, anyOmitEmpty bool) {
 	var n int
 	for i, v := range x {
-		xn := v.encName // TODO: fieldName or encName? use encName for now.
+		xn := v.encName // fieldName or encName? use encName for now.
 		var found bool
 		for j, k := range pv {
 			if k.name == xn {
@@ -1353,7 +1366,8 @@ func panicValToErr(h errstrDecorator, v interface{}, err *error) {
 	case error:
 		switch xerr {
 		case nil:
-		case io.EOF, io.ErrUnexpectedEOF, errEncoderNotInitialized: // treat as special (bubble up)
+		case io.EOF, io.ErrUnexpectedEOF, errEncoderNotInitialized, errDecoderNotInitialized:
+			// treat as special (bubble up)
 			*err = xerr
 		default:
 			h.wrapErrstr(xerr.Error(), err)
@@ -1362,6 +1376,10 @@ func panicValToErr(h errstrDecorator, v interface{}, err *error) {
 		if xerr != "" {
 			h.wrapErrstr(xerr, err)
 		}
+	case fmt.Stringer:
+		if xerr != nil {
+			h.wrapErrstr(xerr.String(), err)
+		}
 	default:
 		h.wrapErrstr(v, err)
 	}
@@ -1371,7 +1389,7 @@ func panicValToErr(h errstrDecorator, v interface{}, err *error) {
 // 	params2 := make([]interface{}, len(params)+1)
 // 	params2[0] = tag
 // 	copy(params2[1:], params)
-// 	panic(fmt.Errorf("%s: "+format, params2...))
+// 	panicv.errorf("%s: "+format, params2...)
 // }
 
 func isImmutableKind(k reflect.Kind) (v bool) {
@@ -1673,14 +1691,6 @@ func (c *codecFner) get(rt reflect.Type, checkFastpath, checkCodecSelfer bool) (
 
 // ----
 
-func chkFloat32(f float64) (f32 float32) {
-	// f32 = float32(f)
-	if chkOvf.Float32(f) {
-		panicv.errorf("float32 overflow: %v", f)
-	}
-	return float32(f)
-}
-
 // these "checkOverflow" functions must be inlinable, and not call anybody.
 // Overflow means that the value cannot be represented without wrapping/overflow.
 // Overflow=false does not mean that the value can be represented without losing precision
@@ -1696,13 +1706,12 @@ type checkOverflow struct{}
 // 	return math.MaxFloat32 < f && f <= math.MaxFloat64
 // }
 
-func (checkOverflow) Float32(f float64) (overflow bool) {
-	if f < 0 {
-		f = -f
+func (checkOverflow) Float32(v float64) (overflow bool) {
+	if v < 0 {
+		v = -v
 	}
-	return math.MaxFloat32 < f && f <= math.MaxFloat64
+	return math.MaxFloat32 < v && v <= math.MaxFloat64
 }
-
 func (checkOverflow) Uint(v uint64, bitsize uint8) (overflow bool) {
 	if bitsize == 0 || bitsize >= 64 || v == 0 {
 		return
@@ -1712,7 +1721,6 @@ func (checkOverflow) Uint(v uint64, bitsize uint8) (overflow bool) {
 	}
 	return
 }
-
 func (checkOverflow) Int(v int64, bitsize uint8) (overflow bool) {
 	if bitsize == 0 || bitsize >= 64 || v == 0 {
 		return
@@ -1722,27 +1730,47 @@ func (checkOverflow) Int(v int64, bitsize uint8) (overflow bool) {
 	}
 	return
 }
-
-func (checkOverflow) SignedInt(v uint64) (i int64, overflow bool) {
+func (checkOverflow) SignedInt(v uint64) (overflow bool) {
 	//e.g. -127 to 128 for int8
 	pos := (v >> 63) == 0
 	ui2 := v & 0x7fffffffffffffff
 	if pos {
 		if ui2 > math.MaxInt64 {
 			overflow = true
-		} else {
-			i = int64(v)
 		}
 	} else {
 		if ui2 > math.MaxInt64-1 {
 			overflow = true
-		} else {
-			i = int64(v)
 		}
 	}
 	return
 }
 
+func (x checkOverflow) Float32V(v float64) float64 {
+	if x.Float32(v) {
+		panicv.errorf("float32 overflow: %v", v)
+	}
+	return v
+}
+func (x checkOverflow) UintV(v uint64, bitsize uint8) uint64 {
+	if x.Uint(v, bitsize) {
+		panicv.errorf("uint64 overflow: %v", v)
+	}
+	return v
+}
+func (x checkOverflow) IntV(v int64, bitsize uint8) int64 {
+	if x.Int(v, bitsize) {
+		panicv.errorf("int64 overflow: %v", v)
+	}
+	return v
+}
+func (x checkOverflow) SignedIntV(v uint64) int64 {
+	if x.SignedInt(v) {
+		panicv.errorf("uint64 to int64 overflow: %v", v)
+	}
+	return int64(v)
+}
+
 // ------------------ SORT -----------------
 
 func isNaN(f float64) bool { return f != f }

+ 11 - 11
codec/helper_not_unsafe.go

@@ -129,47 +129,47 @@ func (d *Decoder) kFloat64(f *codecFnInfo, rv reflect.Value) {
 }
 
 func (d *Decoder) kInt(f *codecFnInfo, rv reflect.Value) {
-	rv.SetInt(d.d.DecodeInt(intBitsize))
+	rv.SetInt(chkOvf.IntV(d.d.DecodeInt64(), intBitsize))
 }
 
 func (d *Decoder) kInt8(f *codecFnInfo, rv reflect.Value) {
-	rv.SetInt(d.d.DecodeInt(8))
+	rv.SetInt(chkOvf.IntV(d.d.DecodeInt64(), 8))
 }
 
 func (d *Decoder) kInt16(f *codecFnInfo, rv reflect.Value) {
-	rv.SetInt(d.d.DecodeInt(16))
+	rv.SetInt(chkOvf.IntV(d.d.DecodeInt64(), 16))
 }
 
 func (d *Decoder) kInt32(f *codecFnInfo, rv reflect.Value) {
-	rv.SetInt(d.d.DecodeInt(32))
+	rv.SetInt(chkOvf.IntV(d.d.DecodeInt64(), 32))
 }
 
 func (d *Decoder) kInt64(f *codecFnInfo, rv reflect.Value) {
-	rv.SetInt(d.d.DecodeInt(64))
+	rv.SetInt(d.d.DecodeInt64())
 }
 
 func (d *Decoder) kUint(f *codecFnInfo, rv reflect.Value) {
-	rv.SetUint(d.d.DecodeUint(uintBitsize))
+	rv.SetUint(chkOvf.UintV(d.d.DecodeUint64(), uintBitsize))
 }
 
 func (d *Decoder) kUintptr(f *codecFnInfo, rv reflect.Value) {
-	rv.SetUint(d.d.DecodeUint(uintBitsize))
+	rv.SetUint(chkOvf.UintV(d.d.DecodeUint64(), uintBitsize))
 }
 
 func (d *Decoder) kUint8(f *codecFnInfo, rv reflect.Value) {
-	rv.SetUint(d.d.DecodeUint(8))
+	rv.SetUint(chkOvf.UintV(d.d.DecodeUint64(), 8))
 }
 
 func (d *Decoder) kUint16(f *codecFnInfo, rv reflect.Value) {
-	rv.SetUint(d.d.DecodeUint(16))
+	rv.SetUint(chkOvf.UintV(d.d.DecodeUint64(), 16))
 }
 
 func (d *Decoder) kUint32(f *codecFnInfo, rv reflect.Value) {
-	rv.SetUint(d.d.DecodeUint(32))
+	rv.SetUint(chkOvf.UintV(d.d.DecodeUint64(), 32))
 }
 
 func (d *Decoder) kUint64(f *codecFnInfo, rv reflect.Value) {
-	rv.SetUint(d.d.DecodeUint(64))
+	rv.SetUint(d.d.DecodeUint64())
 }
 
 // ----------------

+ 11 - 11
codec/helper_unsafe.go

@@ -189,57 +189,57 @@ func (d *Decoder) kFloat64(f *codecFnInfo, rv reflect.Value) {
 
 func (d *Decoder) kInt(f *codecFnInfo, rv reflect.Value) {
 	urv := (*unsafeReflectValue)(unsafe.Pointer(&rv))
-	*(*int)(urv.ptr) = int(d.d.DecodeInt(intBitsize))
+	*(*int)(urv.ptr) = int(chkOvf.IntV(d.d.DecodeInt64(), intBitsize))
 }
 
 func (d *Decoder) kInt8(f *codecFnInfo, rv reflect.Value) {
 	urv := (*unsafeReflectValue)(unsafe.Pointer(&rv))
-	*(*int8)(urv.ptr) = int8(d.d.DecodeInt(8))
+	*(*int8)(urv.ptr) = int8(chkOvf.IntV(d.d.DecodeInt64(), 8))
 }
 
 func (d *Decoder) kInt16(f *codecFnInfo, rv reflect.Value) {
 	urv := (*unsafeReflectValue)(unsafe.Pointer(&rv))
-	*(*int16)(urv.ptr) = int16(d.d.DecodeInt(16))
+	*(*int16)(urv.ptr) = int16(chkOvf.IntV(d.d.DecodeInt64(), 16))
 }
 
 func (d *Decoder) kInt32(f *codecFnInfo, rv reflect.Value) {
 	urv := (*unsafeReflectValue)(unsafe.Pointer(&rv))
-	*(*int32)(urv.ptr) = int32(d.d.DecodeInt(32))
+	*(*int32)(urv.ptr) = int32(chkOvf.IntV(d.d.DecodeInt64(), 32))
 }
 
 func (d *Decoder) kInt64(f *codecFnInfo, rv reflect.Value) {
 	urv := (*unsafeReflectValue)(unsafe.Pointer(&rv))
-	*(*int64)(urv.ptr) = d.d.DecodeInt(64)
+	*(*int64)(urv.ptr) = d.d.DecodeInt64()
 }
 
 func (d *Decoder) kUint(f *codecFnInfo, rv reflect.Value) {
 	urv := (*unsafeReflectValue)(unsafe.Pointer(&rv))
-	*(*uint)(urv.ptr) = uint(d.d.DecodeUint(uintBitsize))
+	*(*uint)(urv.ptr) = uint(chkOvf.UintV(d.d.DecodeUint64(), uintBitsize))
 }
 
 func (d *Decoder) kUintptr(f *codecFnInfo, rv reflect.Value) {
 	urv := (*unsafeReflectValue)(unsafe.Pointer(&rv))
-	*(*uintptr)(urv.ptr) = uintptr(d.d.DecodeUint(uintBitsize))
+	*(*uintptr)(urv.ptr) = uintptr(chkOvf.UintV(d.d.DecodeUint64(), uintBitsize))
 }
 
 func (d *Decoder) kUint8(f *codecFnInfo, rv reflect.Value) {
 	urv := (*unsafeReflectValue)(unsafe.Pointer(&rv))
-	*(*uint8)(urv.ptr) = uint8(d.d.DecodeUint(8))
+	*(*uint8)(urv.ptr) = uint8(chkOvf.UintV(d.d.DecodeUint64(), 8))
 }
 
 func (d *Decoder) kUint16(f *codecFnInfo, rv reflect.Value) {
 	urv := (*unsafeReflectValue)(unsafe.Pointer(&rv))
-	*(*uint16)(urv.ptr) = uint16(d.d.DecodeUint(16))
+	*(*uint16)(urv.ptr) = uint16(chkOvf.UintV(d.d.DecodeUint64(), 16))
 }
 
 func (d *Decoder) kUint32(f *codecFnInfo, rv reflect.Value) {
 	urv := (*unsafeReflectValue)(unsafe.Pointer(&rv))
-	*(*uint32)(urv.ptr) = uint32(d.d.DecodeUint(32))
+	*(*uint32)(urv.ptr) = uint32(chkOvf.UintV(d.d.DecodeUint64(), 32))
 }
 
 func (d *Decoder) kUint64(f *codecFnInfo, rv reflect.Value) {
 	urv := (*unsafeReflectValue)(unsafe.Pointer(&rv))
-	*(*uint64)(urv.ptr) = d.d.DecodeUint(64)
+	*(*uint64)(urv.ptr) = d.d.DecodeUint64()
 }
 
 // ------------

+ 62 - 60
codec/json.go

@@ -87,7 +87,8 @@ var (
 	jsonNumSet            bitset256
 	// jsonIsFloatSet        bitset256
 
-	jsonU4Set [256]byte
+	jsonU4Set        [256]byte
+	jsonContainerSet [256]valueType
 )
 
 const (
@@ -156,6 +157,21 @@ func init() {
 		// 	jsonIsFloatSet.set(i)
 		// }
 	}
+	for j := range jsonContainerSet {
+		switch i = byte(j); i {
+		case '{':
+			jsonContainerSet[j] = valueTypeMap
+		case '[':
+			jsonContainerSet[j] = valueTypeArray
+		case 'n':
+			jsonContainerSet[j] = valueTypeNil
+		case '"':
+			jsonContainerSet[j] = valueTypeString
+		default:
+			jsonContainerSet[j] = valueTypeUnset
+		}
+	}
+
 	// jsonU4Set[255] = jsonU4SetErrVal
 }
 
@@ -312,6 +328,9 @@ func (e *jsonEncDriver) EncodeBool(b bool) {
 
 func (e *jsonEncDriver) EncodeFloat32(f float32) {
 	// e.encodeFloat(float64(f), 32)
+	// always encode all floats as IEEE 64-bit floating point.
+	// It also ensures that we can decode in full precision even if into a float32,
+	// as what is written is always to float64 precision.
 	e.EncodeFloat64(float64(f))
 }
 
@@ -347,42 +366,6 @@ func (e *jsonEncDriver) EncodeFloat64(f float64) {
 	e.w.writeb(e.b[:blen])
 }
 
-// func (e *jsonEncDriver) EncodeFloat64(f float64) {
-// 	e.encodeFloat(f, 64)
-// }
-
-// func (e *jsonEncDriver) encodeFloat(f float64, bits int) {
-// 	var blen int
-// 	// instead of using 'g', specify whether to use 'e' or 'f'
-// 	var abs = math.Abs(f)
-// 	var fmt byte
-// 	var prec int = -1
-// 	if abs != 0 && (bits == 64 && (abs < 1e-6 || abs >= 1e21) || bits == 32 && (float32(abs) < 1e-6 || float32(abs) >= 1e21)) {
-// 		fmt = 'e'
-// 	} else {
-// 		fmt = 'f'
-// 		// set prec to 1 iff mod is 0.
-// 		//     better than using jsonIsFloatBytesB2 to check if a . or E in the float bytes.
-// 		// this ensures that every float has an e or .0 in it.
-// 		if abs <= 1 {
-// 			if abs == 0 || abs == 1 {
-// 				prec = 1
-// 			}
-// 		} else if _, mod := math.Modf(abs); mod == 0 {
-// 			prec = 1
-// 		}
-// 	}
-
-// 	if e.h.MapKeyAsString && e.c == containerMapKey {
-// 		blen = 2 + len(strconv.AppendFloat(e.b[1:1], f, fmt, prec, bits))
-// 		e.b[0] = '"'
-// 		e.b[blen-1] = '"'
-// 	} else {
-// 		blen = len(strconv.AppendFloat(e.b[:0], f, fmt, prec, bits))
-// 	}
-// 	e.w.writeb(e.b[:blen])
-// }
-
 func (e *jsonEncDriver) EncodeInt(v int64) {
 	x := e.h.IntegerAsString
 	if x == 'A' || x == 'L' && (v > 1<<53 || v < -(1<<53)) || (e.h.MapKeyAsString && e.c == containerMapKey) {
@@ -428,9 +411,9 @@ func (e *jsonEncDriver) EncodeString(c charEncoding, v string) {
 	e.quoteStr(v)
 }
 
-func (e *jsonEncDriver) EncodeSymbol(v string) {
-	e.quoteStr(v)
-}
+// func (e *jsonEncDriver) EncodeSymbol(v string) {
+// 	e.quoteStr(v)
+// }
 
 func (e *jsonEncDriver) EncodeStringBytes(c charEncoding, v []byte) {
 	// if encoding raw bytes and RawBytesExt is configured, use it to encode
@@ -582,7 +565,7 @@ func (d *jsonDecDriver) ReadMapStart() int {
 	}
 	const xc uint8 = '{'
 	if d.tok != xc {
-		d.d.errorf("json: expect char '%c' but got char '%c'", xc, d.tok)
+		d.d.errorf("expect char '%c' but got char '%c'", xc, d.tok)
 	}
 	d.tok = 0
 	d.c = containerMapStart
@@ -595,7 +578,7 @@ func (d *jsonDecDriver) ReadArrayStart() int {
 	}
 	const xc uint8 = '['
 	if d.tok != xc {
-		d.d.errorf("json: expect char '%c' but got char '%c'", xc, d.tok)
+		d.d.errorf("expect char '%c' but got char '%c'", xc, d.tok)
 	}
 	d.tok = 0
 	d.c = containerArrayStart
@@ -616,7 +599,7 @@ func (d *jsonDecDriver) ReadArrayElem() {
 	if d.c != containerArrayStart {
 		const xc uint8 = ','
 		if d.tok != xc {
-			d.d.errorf("json: expect char '%c' but got char '%c'", xc, d.tok)
+			d.d.errorf("expect char '%c' but got char '%c'", xc, d.tok)
 		}
 		d.tok = 0
 	}
@@ -629,7 +612,7 @@ func (d *jsonDecDriver) ReadArrayEnd() {
 	}
 	const xc uint8 = ']'
 	if d.tok != xc {
-		d.d.errorf("json: expect char '%c' but got char '%c'", xc, d.tok)
+		d.d.errorf("expect char '%c' but got char '%c'", xc, d.tok)
 	}
 	d.tok = 0
 	d.c = containerArrayEnd
@@ -642,7 +625,7 @@ func (d *jsonDecDriver) ReadMapElemKey() {
 	if d.c != containerMapStart {
 		const xc uint8 = ','
 		if d.tok != xc {
-			d.d.errorf("json: expect char '%c' but got char '%c'", xc, d.tok)
+			d.d.errorf("expect char '%c' but got char '%c'", xc, d.tok)
 		}
 		d.tok = 0
 	}
@@ -655,7 +638,7 @@ func (d *jsonDecDriver) ReadMapElemValue() {
 	}
 	const xc uint8 = ':'
 	if d.tok != xc {
-		d.d.errorf("json: expect char '%c' but got char '%c'", xc, d.tok)
+		d.d.errorf("expect char '%c' but got char '%c'", xc, d.tok)
 	}
 	d.tok = 0
 	d.c = containerMapValue
@@ -667,7 +650,7 @@ func (d *jsonDecDriver) ReadMapEnd() {
 	}
 	const xc uint8 = '}'
 	if d.tok != xc {
-		d.d.errorf("json: expect char '%c' but got char '%c'", xc, d.tok)
+		d.d.errorf("expect char '%c' but got char '%c'", xc, d.tok)
 	}
 	d.tok = 0
 	d.c = containerMapEnd
@@ -679,7 +662,7 @@ func (d *jsonDecDriver) ReadMapEnd() {
 // 	}
 // 	if check {
 // 		if d.tok != xc {
-// 			d.d.errorf("json: expect char '%c' but got char '%c'", xc, d.tok)
+// 			d.d.errorf("expect char '%c' but got char '%c'", xc, d.tok)
 // 		}
 // 		d.tok = 0
 // 	}
@@ -690,7 +673,7 @@ func (d *jsonDecDriver) readLit(length, fromIdx uint8) {
 	bs := d.r.readx(int(length))
 	d.tok = 0
 	if jsonValidateSymbols && !bytes.Equal(bs, jsonLiterals[fromIdx:fromIdx+length]) {
-		d.d.errorf("json: expecting %s: got %s", jsonLiterals[fromIdx:fromIdx+length], bs)
+		d.d.errorf("expecting %s: got %s", jsonLiterals[fromIdx:fromIdx+length], bs)
 		return
 	}
 }
@@ -724,7 +707,7 @@ func (d *jsonDecDriver) DecodeBool() (v bool) {
 		d.readLit(3, jsonLitTrue+1) // (t)rue
 		v = true
 	default:
-		d.d.errorf("json: decode bool: got first char %c", d.tok)
+		d.d.errorf("decode bool: got first char %c", d.tok)
 		// v = false // "unreachable"
 	}
 	if fquot {
@@ -751,6 +734,24 @@ func (d *jsonDecDriver) ContainerType() (vt valueType) {
 	if d.tok == 0 {
 		d.tok = d.r.skip(&jsonCharWhitespaceSet)
 	}
+
+	// optimize this, so we don't do 4 checks but do one computation.
+	// return jsonContainerSet[d.tok]
+
+	// switch d.tok {
+	// case '{':
+	// 	return valueTypeMap
+	// case '[':
+	// 	return valueTypeArray
+	// case 'n':
+	// 	return valueTypeNil
+	// case '"':
+	// 	return valueTypeString
+	// }
+	// return valueTypeUnset
+
+	// ContainerType is mostly called for Map and Array,
+	// so this conditional is good enough (max 2 checks typically)
 	if b := d.tok; b == '{' {
 		return valueTypeMap
 	} else if b == '[' {
@@ -761,6 +762,7 @@ func (d *jsonDecDriver) ContainerType() (vt valueType) {
 		return valueTypeString
 	}
 	return valueTypeUnset
+
 	// d.d.errorf("isContainerType: unsupported parameter: %v", vt)
 	// return false // "unreachable"
 }
@@ -781,19 +783,19 @@ func (d *jsonDecDriver) decNumBytes() (bs []byte) {
 	return bs
 }
 
-func (d *jsonDecDriver) DecodeUint(bitsize uint8) (u uint64) {
+func (d *jsonDecDriver) DecodeUint64() (u uint64) {
 	bs := d.decNumBytes()
-	u, err := strconv.ParseUint(stringView(bs), 10, int(bitsize))
+	u, err := strconv.ParseUint(stringView(bs), 10, 64)
 	if err != nil {
-		d.d.errorf("json: decode uint from %s: %v", bs, err)
+		d.d.errorf("decode uint from %s: %v", bs, err)
 		return
 	}
 	return
 }
 
-func (d *jsonDecDriver) DecodeInt(bitsize uint8) (i int64) {
+func (d *jsonDecDriver) DecodeInt64() (i int64) {
 	bs := d.decNumBytes()
-	i, err := strconv.ParseInt(stringView(bs), 10, int(bitsize))
+	i, err := strconv.ParseInt(stringView(bs), 10, 64)
 	if err != nil {
 		d.d.errorv(err)
 	}
@@ -859,7 +861,7 @@ func (d *jsonDecDriver) DecodeBytes(bs []byte, zerocopy bool) (bsOut []byte) {
 	}
 	slen2, err := base64.StdEncoding.Decode(bsOut, bs0)
 	if err != nil {
-		d.d.errorf("json: error decoding base64 binary '%s': %v", bs0, err)
+		d.d.errorf("error decoding base64 binary '%s': %v", bs0, err)
 		return nil
 	}
 	if slen != slen2 {
@@ -885,7 +887,7 @@ func (d *jsonDecDriver) appendStringAsBytes() {
 
 	d.fnull = false
 	if d.tok != '"' {
-		// d.d.errorf("json: expect char '%c' but got char '%c'", '"', d.tok)
+		// d.d.errorf("expect char '%c' but got char '%c'", '"', d.tok)
 		// handle non-string scalar: null, true, false or a number
 		switch d.tok {
 		case 'n':
@@ -1002,7 +1004,7 @@ func (d *jsonDecDriver) appendStringAsBytes() {
 			w2 := utf8.EncodeRune(d.bstr[:], r)
 			v = append(v, d.bstr[:w2]...)
 		default:
-			d.d.errorf("json: unsupported escaped value: %c", c)
+			d.d.errorf("unsupported escaped value: %c", c)
 		}
 		i++
 		cursor = i
@@ -1089,11 +1091,11 @@ func (d *jsonDecDriver) DecodeNaked() {
 	default: // number
 		bs := d.decNumBytes()
 		if len(bs) == 0 {
-			d.d.errorf("json: decode number from empty string")
+			d.d.errorf("decode number from empty string")
 			return
 		}
 		if err := d.nakedNum(z, bs); err != nil {
-			d.d.errorf("json: decode number from %s: %v", bs, err)
+			d.d.errorf("decode number from %s: %v", bs, err)
 			return
 		}
 	}

+ 49 - 49
codec/mammoth2_codecgen_generated_test.go

@@ -20584,7 +20584,7 @@ func (x *TestMammoth2) codecDecodeSelfFromMap(l int, d *Decoder) {
 				_ = yym21
 				if false {
 				} else {
-					*((*uint)(yyv20)) = uint(r.DecodeUint(codecSelferBitsize19781))
+					*((*uint)(yyv20)) = uint(z.c.UintV(r.DecodeUint64(), codecSelferBitsize19781))
 				}
 			}
 		case "FptrUint":
@@ -20603,7 +20603,7 @@ func (x *TestMammoth2) codecDecodeSelfFromMap(l int, d *Decoder) {
 				_ = yym23
 				if false {
 				} else {
-					*((*uint)(x.FptrUint)) = uint(r.DecodeUint(codecSelferBitsize19781))
+					*((*uint)(x.FptrUint)) = uint(z.c.UintV(r.DecodeUint64(), codecSelferBitsize19781))
 				}
 			}
 		case "FUint8":
@@ -20615,7 +20615,7 @@ func (x *TestMammoth2) codecDecodeSelfFromMap(l int, d *Decoder) {
 				_ = yym25
 				if false {
 				} else {
-					*((*uint8)(yyv24)) = uint8(r.DecodeUint(8))
+					*((*uint8)(yyv24)) = uint8(z.c.UintV(r.DecodeUint64(), 8))
 				}
 			}
 		case "FptrUint8":
@@ -20634,7 +20634,7 @@ func (x *TestMammoth2) codecDecodeSelfFromMap(l int, d *Decoder) {
 				_ = yym27
 				if false {
 				} else {
-					*((*uint8)(x.FptrUint8)) = uint8(r.DecodeUint(8))
+					*((*uint8)(x.FptrUint8)) = uint8(z.c.UintV(r.DecodeUint64(), 8))
 				}
 			}
 		case "FUint16":
@@ -20646,7 +20646,7 @@ func (x *TestMammoth2) codecDecodeSelfFromMap(l int, d *Decoder) {
 				_ = yym29
 				if false {
 				} else {
-					*((*uint16)(yyv28)) = uint16(r.DecodeUint(16))
+					*((*uint16)(yyv28)) = uint16(z.c.UintV(r.DecodeUint64(), 16))
 				}
 			}
 		case "FptrUint16":
@@ -20665,7 +20665,7 @@ func (x *TestMammoth2) codecDecodeSelfFromMap(l int, d *Decoder) {
 				_ = yym31
 				if false {
 				} else {
-					*((*uint16)(x.FptrUint16)) = uint16(r.DecodeUint(16))
+					*((*uint16)(x.FptrUint16)) = uint16(z.c.UintV(r.DecodeUint64(), 16))
 				}
 			}
 		case "FUint32":
@@ -20677,7 +20677,7 @@ func (x *TestMammoth2) codecDecodeSelfFromMap(l int, d *Decoder) {
 				_ = yym33
 				if false {
 				} else {
-					*((*uint32)(yyv32)) = uint32(r.DecodeUint(32))
+					*((*uint32)(yyv32)) = uint32(z.c.UintV(r.DecodeUint64(), 32))
 				}
 			}
 		case "FptrUint32":
@@ -20696,7 +20696,7 @@ func (x *TestMammoth2) codecDecodeSelfFromMap(l int, d *Decoder) {
 				_ = yym35
 				if false {
 				} else {
-					*((*uint32)(x.FptrUint32)) = uint32(r.DecodeUint(32))
+					*((*uint32)(x.FptrUint32)) = uint32(z.c.UintV(r.DecodeUint64(), 32))
 				}
 			}
 		case "FUint64":
@@ -20708,7 +20708,7 @@ func (x *TestMammoth2) codecDecodeSelfFromMap(l int, d *Decoder) {
 				_ = yym37
 				if false {
 				} else {
-					*((*uint64)(yyv36)) = uint64(r.DecodeUint(64))
+					*((*uint64)(yyv36)) = uint64(r.DecodeUint64())
 				}
 			}
 		case "FptrUint64":
@@ -20727,7 +20727,7 @@ func (x *TestMammoth2) codecDecodeSelfFromMap(l int, d *Decoder) {
 				_ = yym39
 				if false {
 				} else {
-					*((*uint64)(x.FptrUint64)) = uint64(r.DecodeUint(64))
+					*((*uint64)(x.FptrUint64)) = uint64(r.DecodeUint64())
 				}
 			}
 		case "FUintptr":
@@ -20739,7 +20739,7 @@ func (x *TestMammoth2) codecDecodeSelfFromMap(l int, d *Decoder) {
 				_ = yym41
 				if false {
 				} else {
-					*((*uintptr)(yyv40)) = uintptr(r.DecodeUint(codecSelferBitsize19781))
+					*((*uintptr)(yyv40)) = uintptr(z.c.UintV(r.DecodeUint64(), codecSelferBitsize19781))
 				}
 			}
 		case "FptrUintptr":
@@ -20758,7 +20758,7 @@ func (x *TestMammoth2) codecDecodeSelfFromMap(l int, d *Decoder) {
 				_ = yym43
 				if false {
 				} else {
-					*((*uintptr)(x.FptrUintptr)) = uintptr(r.DecodeUint(codecSelferBitsize19781))
+					*((*uintptr)(x.FptrUintptr)) = uintptr(z.c.UintV(r.DecodeUint64(), codecSelferBitsize19781))
 				}
 			}
 		case "FInt":
@@ -20770,7 +20770,7 @@ func (x *TestMammoth2) codecDecodeSelfFromMap(l int, d *Decoder) {
 				_ = yym45
 				if false {
 				} else {
-					*((*int)(yyv44)) = int(r.DecodeInt(codecSelferBitsize19781))
+					*((*int)(yyv44)) = int(z.c.IntV(r.DecodeInt64(), codecSelferBitsize19781))
 				}
 			}
 		case "FptrInt":
@@ -20789,7 +20789,7 @@ func (x *TestMammoth2) codecDecodeSelfFromMap(l int, d *Decoder) {
 				_ = yym47
 				if false {
 				} else {
-					*((*int)(x.FptrInt)) = int(r.DecodeInt(codecSelferBitsize19781))
+					*((*int)(x.FptrInt)) = int(z.c.IntV(r.DecodeInt64(), codecSelferBitsize19781))
 				}
 			}
 		case "FInt8":
@@ -20801,7 +20801,7 @@ func (x *TestMammoth2) codecDecodeSelfFromMap(l int, d *Decoder) {
 				_ = yym49
 				if false {
 				} else {
-					*((*int8)(yyv48)) = int8(r.DecodeInt(8))
+					*((*int8)(yyv48)) = int8(z.c.IntV(r.DecodeInt64(), 8))
 				}
 			}
 		case "FptrInt8":
@@ -20820,7 +20820,7 @@ func (x *TestMammoth2) codecDecodeSelfFromMap(l int, d *Decoder) {
 				_ = yym51
 				if false {
 				} else {
-					*((*int8)(x.FptrInt8)) = int8(r.DecodeInt(8))
+					*((*int8)(x.FptrInt8)) = int8(z.c.IntV(r.DecodeInt64(), 8))
 				}
 			}
 		case "FInt16":
@@ -20832,7 +20832,7 @@ func (x *TestMammoth2) codecDecodeSelfFromMap(l int, d *Decoder) {
 				_ = yym53
 				if false {
 				} else {
-					*((*int16)(yyv52)) = int16(r.DecodeInt(16))
+					*((*int16)(yyv52)) = int16(z.c.IntV(r.DecodeInt64(), 16))
 				}
 			}
 		case "FptrInt16":
@@ -20851,7 +20851,7 @@ func (x *TestMammoth2) codecDecodeSelfFromMap(l int, d *Decoder) {
 				_ = yym55
 				if false {
 				} else {
-					*((*int16)(x.FptrInt16)) = int16(r.DecodeInt(16))
+					*((*int16)(x.FptrInt16)) = int16(z.c.IntV(r.DecodeInt64(), 16))
 				}
 			}
 		case "FInt32":
@@ -20863,7 +20863,7 @@ func (x *TestMammoth2) codecDecodeSelfFromMap(l int, d *Decoder) {
 				_ = yym57
 				if false {
 				} else {
-					*((*int32)(yyv56)) = int32(r.DecodeInt(32))
+					*((*int32)(yyv56)) = int32(z.c.IntV(r.DecodeInt64(), 32))
 				}
 			}
 		case "FptrInt32":
@@ -20882,7 +20882,7 @@ func (x *TestMammoth2) codecDecodeSelfFromMap(l int, d *Decoder) {
 				_ = yym59
 				if false {
 				} else {
-					*((*int32)(x.FptrInt32)) = int32(r.DecodeInt(32))
+					*((*int32)(x.FptrInt32)) = int32(z.c.IntV(r.DecodeInt64(), 32))
 				}
 			}
 		case "FInt64":
@@ -20894,7 +20894,7 @@ func (x *TestMammoth2) codecDecodeSelfFromMap(l int, d *Decoder) {
 				_ = yym61
 				if false {
 				} else {
-					*((*int64)(yyv60)) = int64(r.DecodeInt(64))
+					*((*int64)(yyv60)) = int64(r.DecodeInt64())
 				}
 			}
 		case "FptrInt64":
@@ -20913,7 +20913,7 @@ func (x *TestMammoth2) codecDecodeSelfFromMap(l int, d *Decoder) {
 				_ = yym63
 				if false {
 				} else {
-					*((*int64)(x.FptrInt64)) = int64(r.DecodeInt(64))
+					*((*int64)(x.FptrInt64)) = int64(r.DecodeInt64())
 				}
 			}
 		case "FBool":
@@ -29616,7 +29616,7 @@ func (x *TestMammoth2) codecDecodeSelfFromArray(l int, d *Decoder) {
 		_ = yym1174
 		if false {
 		} else {
-			*((*uint)(yyv1173)) = uint(r.DecodeUint(codecSelferBitsize19781))
+			*((*uint)(yyv1173)) = uint(z.c.UintV(r.DecodeUint64(), codecSelferBitsize19781))
 		}
 	}
 	if x.FptrUint == nil {
@@ -29645,7 +29645,7 @@ func (x *TestMammoth2) codecDecodeSelfFromArray(l int, d *Decoder) {
 		_ = yym1176
 		if false {
 		} else {
-			*((*uint)(x.FptrUint)) = uint(r.DecodeUint(codecSelferBitsize19781))
+			*((*uint)(x.FptrUint)) = uint(z.c.UintV(r.DecodeUint64(), codecSelferBitsize19781))
 		}
 	}
 	yyj1156++
@@ -29667,7 +29667,7 @@ func (x *TestMammoth2) codecDecodeSelfFromArray(l int, d *Decoder) {
 		_ = yym1178
 		if false {
 		} else {
-			*((*uint8)(yyv1177)) = uint8(r.DecodeUint(8))
+			*((*uint8)(yyv1177)) = uint8(z.c.UintV(r.DecodeUint64(), 8))
 		}
 	}
 	if x.FptrUint8 == nil {
@@ -29696,7 +29696,7 @@ func (x *TestMammoth2) codecDecodeSelfFromArray(l int, d *Decoder) {
 		_ = yym1180
 		if false {
 		} else {
-			*((*uint8)(x.FptrUint8)) = uint8(r.DecodeUint(8))
+			*((*uint8)(x.FptrUint8)) = uint8(z.c.UintV(r.DecodeUint64(), 8))
 		}
 	}
 	yyj1156++
@@ -29718,7 +29718,7 @@ func (x *TestMammoth2) codecDecodeSelfFromArray(l int, d *Decoder) {
 		_ = yym1182
 		if false {
 		} else {
-			*((*uint16)(yyv1181)) = uint16(r.DecodeUint(16))
+			*((*uint16)(yyv1181)) = uint16(z.c.UintV(r.DecodeUint64(), 16))
 		}
 	}
 	if x.FptrUint16 == nil {
@@ -29747,7 +29747,7 @@ func (x *TestMammoth2) codecDecodeSelfFromArray(l int, d *Decoder) {
 		_ = yym1184
 		if false {
 		} else {
-			*((*uint16)(x.FptrUint16)) = uint16(r.DecodeUint(16))
+			*((*uint16)(x.FptrUint16)) = uint16(z.c.UintV(r.DecodeUint64(), 16))
 		}
 	}
 	yyj1156++
@@ -29769,7 +29769,7 @@ func (x *TestMammoth2) codecDecodeSelfFromArray(l int, d *Decoder) {
 		_ = yym1186
 		if false {
 		} else {
-			*((*uint32)(yyv1185)) = uint32(r.DecodeUint(32))
+			*((*uint32)(yyv1185)) = uint32(z.c.UintV(r.DecodeUint64(), 32))
 		}
 	}
 	if x.FptrUint32 == nil {
@@ -29798,7 +29798,7 @@ func (x *TestMammoth2) codecDecodeSelfFromArray(l int, d *Decoder) {
 		_ = yym1188
 		if false {
 		} else {
-			*((*uint32)(x.FptrUint32)) = uint32(r.DecodeUint(32))
+			*((*uint32)(x.FptrUint32)) = uint32(z.c.UintV(r.DecodeUint64(), 32))
 		}
 	}
 	yyj1156++
@@ -29820,7 +29820,7 @@ func (x *TestMammoth2) codecDecodeSelfFromArray(l int, d *Decoder) {
 		_ = yym1190
 		if false {
 		} else {
-			*((*uint64)(yyv1189)) = uint64(r.DecodeUint(64))
+			*((*uint64)(yyv1189)) = uint64(r.DecodeUint64())
 		}
 	}
 	if x.FptrUint64 == nil {
@@ -29849,7 +29849,7 @@ func (x *TestMammoth2) codecDecodeSelfFromArray(l int, d *Decoder) {
 		_ = yym1192
 		if false {
 		} else {
-			*((*uint64)(x.FptrUint64)) = uint64(r.DecodeUint(64))
+			*((*uint64)(x.FptrUint64)) = uint64(r.DecodeUint64())
 		}
 	}
 	yyj1156++
@@ -29871,7 +29871,7 @@ func (x *TestMammoth2) codecDecodeSelfFromArray(l int, d *Decoder) {
 		_ = yym1194
 		if false {
 		} else {
-			*((*uintptr)(yyv1193)) = uintptr(r.DecodeUint(codecSelferBitsize19781))
+			*((*uintptr)(yyv1193)) = uintptr(z.c.UintV(r.DecodeUint64(), codecSelferBitsize19781))
 		}
 	}
 	if x.FptrUintptr == nil {
@@ -29900,7 +29900,7 @@ func (x *TestMammoth2) codecDecodeSelfFromArray(l int, d *Decoder) {
 		_ = yym1196
 		if false {
 		} else {
-			*((*uintptr)(x.FptrUintptr)) = uintptr(r.DecodeUint(codecSelferBitsize19781))
+			*((*uintptr)(x.FptrUintptr)) = uintptr(z.c.UintV(r.DecodeUint64(), codecSelferBitsize19781))
 		}
 	}
 	yyj1156++
@@ -29922,7 +29922,7 @@ func (x *TestMammoth2) codecDecodeSelfFromArray(l int, d *Decoder) {
 		_ = yym1198
 		if false {
 		} else {
-			*((*int)(yyv1197)) = int(r.DecodeInt(codecSelferBitsize19781))
+			*((*int)(yyv1197)) = int(z.c.IntV(r.DecodeInt64(), codecSelferBitsize19781))
 		}
 	}
 	if x.FptrInt == nil {
@@ -29951,7 +29951,7 @@ func (x *TestMammoth2) codecDecodeSelfFromArray(l int, d *Decoder) {
 		_ = yym1200
 		if false {
 		} else {
-			*((*int)(x.FptrInt)) = int(r.DecodeInt(codecSelferBitsize19781))
+			*((*int)(x.FptrInt)) = int(z.c.IntV(r.DecodeInt64(), codecSelferBitsize19781))
 		}
 	}
 	yyj1156++
@@ -29973,7 +29973,7 @@ func (x *TestMammoth2) codecDecodeSelfFromArray(l int, d *Decoder) {
 		_ = yym1202
 		if false {
 		} else {
-			*((*int8)(yyv1201)) = int8(r.DecodeInt(8))
+			*((*int8)(yyv1201)) = int8(z.c.IntV(r.DecodeInt64(), 8))
 		}
 	}
 	if x.FptrInt8 == nil {
@@ -30002,7 +30002,7 @@ func (x *TestMammoth2) codecDecodeSelfFromArray(l int, d *Decoder) {
 		_ = yym1204
 		if false {
 		} else {
-			*((*int8)(x.FptrInt8)) = int8(r.DecodeInt(8))
+			*((*int8)(x.FptrInt8)) = int8(z.c.IntV(r.DecodeInt64(), 8))
 		}
 	}
 	yyj1156++
@@ -30024,7 +30024,7 @@ func (x *TestMammoth2) codecDecodeSelfFromArray(l int, d *Decoder) {
 		_ = yym1206
 		if false {
 		} else {
-			*((*int16)(yyv1205)) = int16(r.DecodeInt(16))
+			*((*int16)(yyv1205)) = int16(z.c.IntV(r.DecodeInt64(), 16))
 		}
 	}
 	if x.FptrInt16 == nil {
@@ -30053,7 +30053,7 @@ func (x *TestMammoth2) codecDecodeSelfFromArray(l int, d *Decoder) {
 		_ = yym1208
 		if false {
 		} else {
-			*((*int16)(x.FptrInt16)) = int16(r.DecodeInt(16))
+			*((*int16)(x.FptrInt16)) = int16(z.c.IntV(r.DecodeInt64(), 16))
 		}
 	}
 	yyj1156++
@@ -30075,7 +30075,7 @@ func (x *TestMammoth2) codecDecodeSelfFromArray(l int, d *Decoder) {
 		_ = yym1210
 		if false {
 		} else {
-			*((*int32)(yyv1209)) = int32(r.DecodeInt(32))
+			*((*int32)(yyv1209)) = int32(z.c.IntV(r.DecodeInt64(), 32))
 		}
 	}
 	if x.FptrInt32 == nil {
@@ -30104,7 +30104,7 @@ func (x *TestMammoth2) codecDecodeSelfFromArray(l int, d *Decoder) {
 		_ = yym1212
 		if false {
 		} else {
-			*((*int32)(x.FptrInt32)) = int32(r.DecodeInt(32))
+			*((*int32)(x.FptrInt32)) = int32(z.c.IntV(r.DecodeInt64(), 32))
 		}
 	}
 	yyj1156++
@@ -30126,7 +30126,7 @@ func (x *TestMammoth2) codecDecodeSelfFromArray(l int, d *Decoder) {
 		_ = yym1214
 		if false {
 		} else {
-			*((*int64)(yyv1213)) = int64(r.DecodeInt(64))
+			*((*int64)(yyv1213)) = int64(r.DecodeInt64())
 		}
 	}
 	if x.FptrInt64 == nil {
@@ -30155,7 +30155,7 @@ func (x *TestMammoth2) codecDecodeSelfFromArray(l int, d *Decoder) {
 		_ = yym1216
 		if false {
 		} else {
-			*((*int64)(x.FptrInt64)) = int64(r.DecodeInt(64))
+			*((*int64)(x.FptrInt64)) = int64(r.DecodeInt64())
 		}
 	}
 	yyj1156++
@@ -44125,7 +44125,7 @@ func (x *testMammoth2Binary) CodecDecodeSelf(d *Decoder) {
 	} else if yym1 {
 		z.DecBinaryUnmarshal(x)
 	} else {
-		*((*uint64)(x)) = uint64(r.DecodeUint(64))
+		*((*uint64)(x)) = uint64(r.DecodeUint64())
 	}
 }
 
@@ -44157,7 +44157,7 @@ func (x *testMammoth2Text) CodecDecodeSelf(d *Decoder) {
 	} else if !yym1 {
 		z.DecTextUnmarshal(x)
 	} else {
-		*((*uint64)(x)) = uint64(r.DecodeUint(64))
+		*((*uint64)(x)) = uint64(r.DecodeUint64())
 	}
 }
 
@@ -44189,7 +44189,7 @@ func (x *testMammoth2Json) CodecDecodeSelf(d *Decoder) {
 	} else if !yym1 && z.IsJSONHandle() {
 		z.DecJSONUnmarshal(x)
 	} else {
-		*((*uint64)(x)) = uint64(r.DecodeUint(64))
+		*((*uint64)(x)) = uint64(r.DecodeUint64())
 	}
 }
 
@@ -44738,7 +44738,7 @@ func (x codecSelfer19781) dectestMammoth2Basic(v *testMammoth2Basic, d *Decoder)
 					_ = yym3
 					if false {
 					} else {
-						*((*uint64)(yyv2)) = uint64(r.DecodeUint(64))
+						*((*uint64)(yyv2)) = uint64(r.DecodeUint64())
 					}
 				}
 
@@ -44979,7 +44979,7 @@ func (x codecSelfer19781) decArray4int64(v *[4]int64, d *Decoder) {
 					_ = yym3
 					if false {
 					} else {
-						*((*int64)(yyv2)) = int64(r.DecodeInt(64))
+						*((*int64)(yyv2)) = int64(r.DecodeInt64())
 					}
 				}
 

+ 6 - 20
codec/msgpack.go

@@ -291,9 +291,9 @@ func (e *msgpackEncDriver) EncodeString(c charEncoding, s string) {
 	}
 }
 
-func (e *msgpackEncDriver) EncodeSymbol(v string) {
-	e.EncodeString(cUTF8, v)
-}
+// func (e *msgpackEncDriver) EncodeSymbol(v string) {
+// 	e.EncodeString(cUTF8, v)
+// }
 
 func (e *msgpackEncDriver) EncodeStringBytes(c charEncoding, bs []byte) {
 	if bs == nil {
@@ -450,7 +450,7 @@ func (d *msgpackDecDriver) DecodeNaked() {
 }
 
 // int can be decoded from msgpack type: intXXX or uintXXX
-func (d *msgpackDecDriver) DecodeInt(bitsize uint8) (i int64) {
+func (d *msgpackDecDriver) DecodeInt64() (i int64) {
 	if !d.bdRead {
 		d.readNextBd()
 	}
@@ -482,19 +482,12 @@ func (d *msgpackDecDriver) DecodeInt(bitsize uint8) (i int64) {
 			return
 		}
 	}
-	// check overflow (logic adapted from std pkg reflect/value.go OverflowUint()
-	if bitsize > 0 {
-		if trunc := (i << (64 - bitsize)) >> (64 - bitsize); i != trunc {
-			d.d.errorf("Overflow int value: %v", i)
-			return
-		}
-	}
 	d.bdRead = false
 	return
 }
 
 // uint can be decoded from msgpack type: intXXX or uintXXX
-func (d *msgpackDecDriver) DecodeUint(bitsize uint8) (ui uint64) {
+func (d *msgpackDecDriver) DecodeUint64() (ui uint64) {
 	if !d.bdRead {
 		d.readNextBd()
 	}
@@ -547,13 +540,6 @@ func (d *msgpackDecDriver) DecodeUint(bitsize uint8) (ui uint64) {
 			return
 		}
 	}
-	// check overflow (logic adapted from std pkg reflect/value.go OverflowUint()
-	if bitsize > 0 {
-		if trunc := (ui << (64 - bitsize)) >> (64 - bitsize); ui != trunc {
-			d.d.errorf("Overflow uint value: %v", ui)
-			return
-		}
-	}
 	d.bdRead = false
 	return
 }
@@ -568,7 +554,7 @@ func (d *msgpackDecDriver) DecodeFloat64() (f float64) {
 	} else if d.bd == mpDouble {
 		f = math.Float64frombits(bigen.Uint64(d.r.readx(8)))
 	} else {
-		f = float64(d.DecodeInt(0))
+		f = float64(d.DecodeInt64())
 	}
 	d.bdRead = false
 	return

+ 3 - 2
codec/noop.go

@@ -91,8 +91,9 @@ func (h *noopDrv) EncodeArrayStart(length int)             { h.start(true) }
 func (h *noopDrv) EncodeMapStart(length int)               { h.start(false) }
 func (h *noopDrv) EncodeEnd()                              { h.end() }
 
-func (h *noopDrv) EncodeString(c charEncoding, v string)      {}
-func (h *noopDrv) EncodeSymbol(v string)                      {}
+func (h *noopDrv) EncodeString(c charEncoding, v string) {}
+
+// func (h *noopDrv) EncodeSymbol(v string)                      {}
 func (h *noopDrv) EncodeStringBytes(c charEncoding, v []byte) {}
 
 func (h *noopDrv) EncodeExt(rv interface{}, xtag uint64, ext Ext, e *Encoder) {}

+ 15 - 46
codec/simple.go

@@ -33,13 +33,14 @@ const (
 
 type simpleEncDriver struct {
 	noBuiltInTypes
-	encDriverNoopContainerWriter
 	// encNoSeparator
 	e *Encoder
 	h *SimpleHandle
 	w encWriter
 	b [8]byte
-	c containerState
+	// c containerState
+	encDriverTrackContainerWriter
+	// encDriverNoopContainerWriter
 }
 
 func (e *simpleEncDriver) EncodeNil() {
@@ -150,31 +151,11 @@ func (e *simpleEncDriver) WriteArrayStart(length int) {
 	e.encLen(simpleVdArray, length)
 }
 
-func (e *simpleEncDriver) WriteArrayElem() {
-	e.c = containerArrayElem
-}
-
-func (e *simpleEncDriver) WriteArrayEnd() {
-	e.c = containerArrayEnd
-}
-
 func (e *simpleEncDriver) WriteMapStart(length int) {
 	e.c = containerMapStart
 	e.encLen(simpleVdMap, length)
 }
 
-func (e *simpleEncDriver) WriteMapElemKey() {
-	e.c = containerMapKey
-}
-
-func (e *simpleEncDriver) WriteMapElemValue() {
-	e.c = containerMapValue
-}
-
-func (e *simpleEncDriver) WriteMapEnd() {
-	e.c = containerMapEnd
-}
-
 func (e *simpleEncDriver) EncodeString(c charEncoding, v string) {
 	if false && e.h.EncZeroValuesAsNil && e.c != containerMapKey && v == "" {
 		e.EncodeNil()
@@ -184,9 +165,9 @@ func (e *simpleEncDriver) EncodeString(c charEncoding, v string) {
 	e.w.writestr(v)
 }
 
-func (e *simpleEncDriver) EncodeSymbol(v string) {
-	e.EncodeString(cUTF8, v)
-}
+// func (e *simpleEncDriver) EncodeSymbol(v string) {
+// 	e.EncodeString(cUTF8, v)
+// }
 
 func (e *simpleEncDriver) EncodeStringBytes(c charEncoding, v []byte) {
 	// if e.h.EncZeroValuesAsNil && e.c != containerMapKey && v == nil {
@@ -314,34 +295,22 @@ func (d *simpleDecDriver) decCheckInteger() (ui uint64, neg bool) {
 	return
 }
 
-func (d *simpleDecDriver) DecodeInt(bitsize uint8) (i int64) {
+func (d *simpleDecDriver) DecodeInt64() (i int64) {
 	ui, neg := d.decCheckInteger()
-	i, overflow := chkOvf.SignedInt(ui)
-	if overflow {
-		d.d.errorf("simple: overflow converting %v to signed integer", ui)
-		return
-	}
+	i = chkOvf.SignedIntV(ui)
 	if neg {
 		i = -i
 	}
-	if chkOvf.Int(i, bitsize) {
-		d.d.errorf("simple: overflow integer: %v", i)
-		return
-	}
 	d.bdRead = false
 	return
 }
 
-func (d *simpleDecDriver) DecodeUint(bitsize uint8) (ui uint64) {
+func (d *simpleDecDriver) DecodeUint64() (ui uint64) {
 	ui, neg := d.decCheckInteger()
 	if neg {
 		d.d.errorf("Assigning negative signed value to unsigned type")
 		return
 	}
-	if chkOvf.Uint(ui, bitsize) {
-		d.d.errorf("simple: overflow integer: %v", ui)
-		return
-	}
 	d.bdRead = false
 	return
 }
@@ -356,7 +325,7 @@ func (d *simpleDecDriver) DecodeFloat64() (f float64) {
 		f = math.Float64frombits(bigen.Uint64(d.r.readx(8)))
 	} else {
 		if d.bd >= simpleVdPosInt && d.bd <= simpleVdNegInt+3 {
-			f = float64(d.DecodeInt(64))
+			f = float64(d.DecodeInt64())
 		} else {
 			d.d.errorf("Float only valid from float32/64: Invalid descriptor: %v", d.bd)
 			return
@@ -431,14 +400,14 @@ func (d *simpleDecDriver) decLen() int {
 	case 3:
 		ui := uint64(bigen.Uint32(d.r.readx(4)))
 		if chkOvf.Uint(ui, intBitsize) {
-			d.d.errorf("simple: overflow integer: %v", ui)
+			d.d.errorf("overflow integer: %v", ui)
 			return 0
 		}
 		return int(ui)
 	case 4:
 		ui := bigen.Uint64(d.r.readx(8))
 		if chkOvf.Uint(ui, intBitsize) {
-			d.d.errorf("simple: overflow integer: %v", ui)
+			d.d.errorf("overflow integer: %v", ui)
 			return 0
 		}
 		return int(ui)
@@ -562,14 +531,14 @@ func (d *simpleDecDriver) DecodeNaked() {
 	case simpleVdPosInt, simpleVdPosInt + 1, simpleVdPosInt + 2, simpleVdPosInt + 3:
 		if d.h.SignedInteger {
 			n.v = valueTypeInt
-			n.i = d.DecodeInt(64)
+			n.i = d.DecodeInt64()
 		} else {
 			n.v = valueTypeUint
-			n.u = d.DecodeUint(64)
+			n.u = d.DecodeUint64()
 		}
 	case simpleVdNegInt, simpleVdNegInt + 1, simpleVdNegInt + 2, simpleVdNegInt + 3:
 		n.v = valueTypeInt
-		n.i = d.DecodeInt(64)
+		n.i = d.DecodeInt64()
 	case simpleVdFloat32:
 		n.v = valueTypeFloat
 		n.f = d.DecodeFloat64()

+ 5 - 5
codec/z_all_test.go

@@ -81,7 +81,7 @@ func testSuite(t *testing.T, f func(t *testing.T)) {
 	t.Run("optionsTrue-deepstruct", f)
 	testDepth = 0
 
-	testEncodeOptions.AsSymbols = AsSymbolAll
+	// testEncodeOptions.AsSymbols = AsSymbolAll
 	testUseIoWrapper = true
 	testReinit()
 	t.Run("optionsTrue-ioWrapper", f)
@@ -408,17 +408,17 @@ func TestCodecSuite(t *testing.T) {
 	t.Run("cbor-rfc3339", testCborGroup)
 	testCborH.TimeRFC3339 = oldTimeRFC3339
 
-	oldSymbols := testBincH.getBasicHandle().AsSymbols
+	oldSymbols := testBincH.AsSymbols
 
-	testBincH.getBasicHandle().AsSymbols = AsSymbolNone
+	testBincH.AsSymbols = 2 // AsSymbolNone
 	testReinit()
 	t.Run("binc-no-symbols", testBincGroup)
 
-	testBincH.getBasicHandle().AsSymbols = AsSymbolAll
+	testBincH.AsSymbols = 1 // AsSymbolAll
 	testReinit()
 	t.Run("binc-all-symbols", testBincGroup)
 
-	testBincH.getBasicHandle().AsSymbols = oldSymbols
+	testBincH.AsSymbols = oldSymbols
 
 	oldWriteExt := testMsgpackH.WriteExt
 	oldNoFixedNum := testMsgpackH.NoFixedNum

部分文件因文件數量過多而無法顯示