Browse Source

codec: refactor for better inlining, improve intf for string encoding, and fix some vet/staticcheck/false-sharing concerns

refactor to support mid-stack inlining and inlining of any form.

    - Do not use encReader/encWriter anymore, but folks have access to the *Switch directly.
      This allows future mid-stack inlining optimizations, and replaces interface calls with a call+switch
    - commented out encWriter and decReader interfaces (use the *Switch instead).
    - Use ioDecReaderCommon common type (common to ioDecReader and bufioDecReader) to host common fields and functions
    - manually inline bufioDecReader.search and remove unnecessary code in each one
    - add comment for changes to take advantage of inlining
    - make ioDecReader.(skip,readTo,readUntil) inlineable (use goto to replace for loop)
    - use switch statements in decReaderSwitch methods, as they could perform better than if/else-if/else

deprecate EncodeStringBytes(...) and EncodeString(...)

    replace with EncodeStringBytesRaw(...) and EncodeStringEnc(...)

    - each handle will have implementations of both
    - old functions stay in, for backward compatibility (with old auto generated code)
    - new codebase doesn't use those old ones at all

Fix some vet and static check warnings (found from analyze script)

    - ensure all lines <= 100 characters
    - replace time.Now().Sub with time.Since
    - ensure type in const declarations are explicit (when intended to be)
    - replace for k, _ := range with for k := range
    - ensure no empty blocks
    - alignment/padding - to prevent false-sharing

update copyright year end range to 2018
Ugorji Nwoke 7 years ago
parent
commit
92b7607989

+ 4 - 10
codec/0doc.go

@@ -39,7 +39,7 @@ Rich Feature Set includes:
   - Careful selected use of 'unsafe' for targeted performance gains.
   - Careful selected use of 'unsafe' for targeted performance gains.
     100% mode exists where 'unsafe' is not used at all.
     100% mode exists where 'unsafe' is not used at all.
   - Lock-free (sans mutex) concurrency for scaling to 100's of cores
   - Lock-free (sans mutex) concurrency for scaling to 100's of cores
-  - In-place updates during decode, with option to zero the value in maps and slices prior to decode
+  - In-place updates during decode, with option to zero value in maps and slices prior to decode
   - Coerce types where appropriate
   - Coerce types where appropriate
     e.g. decode an int in the stream into a float, decode numbers from formatted strings, etc
     e.g. decode an int in the stream into a float, decode numbers from formatted strings, etc
   - Corner Cases:
   - Corner Cases:
@@ -226,15 +226,9 @@ with some caveats. See Encode documentation.
 package codec
 package codec
 
 
 // TODO:
 // TODO:
-//   - For Go 1.11, 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
-//     instead of encWriter and decReader.
-//     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.
+//   - When mid-stack inlining is enabled, do the following:
+//     - if 41<=inlineExtraCallCost<=56, make ioEncWriter.{writen1,writen2,writestr,writeb,atEndOfEncode} go:noinline
+//     - if <=40, do nothing
 //
 //
 // PUNTED:
 // PUNTED:
 //   - To make Handle comparable, make extHandle in BasicHandle a non-embedded pointer,
 //   - To make Handle comparable, make extHandle in BasicHandle a non-embedded pointer,

+ 46 - 18
codec/binc.go

@@ -102,7 +102,7 @@ func bincdesc(vd, vs byte) string {
 type bincEncDriver struct {
 type bincEncDriver struct {
 	e *Encoder
 	e *Encoder
 	h *BincHandle
 	h *BincHandle
-	w encWriter
+	w *encWriterSwitch
 	m map[string]uint16 // symbols
 	m map[string]uint16 // symbols
 	b [16]byte          // scratch, used for encoding numbers - bigendian style
 	b [16]byte          // scratch, used for encoding numbers - bigendian style
 	s uint16            // symbols sequencer
 	s uint16            // symbols sequencer
@@ -243,18 +243,6 @@ func (e *bincEncDriver) WriteMapStart(length int) {
 	e.c = containerMapStart
 	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 {
-		e.w.writestr(v)
-	}
-}
-
 func (e *bincEncDriver) EncodeSymbol(v string) {
 func (e *bincEncDriver) EncodeSymbol(v string) {
 	// if WriteSymbolsNoRefs {
 	// if WriteSymbolsNoRefs {
 	// 	e.encodeString(cUTF8, v)
 	// 	e.encodeString(cUTF8, v)
@@ -319,6 +307,31 @@ func (e *bincEncDriver) EncodeSymbol(v string) {
 	}
 	}
 }
 }
 
 
+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 {
+		e.w.writestr(v)
+	}
+}
+
+func (e *bincEncDriver) EncodeStringEnc(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.encLen(bincVdString<<4, l) // e.encBytesLen(c, l)
+	if l > 0 {
+		e.w.writestr(v)
+	}
+
+}
+
 func (e *bincEncDriver) EncodeStringBytes(c charEncoding, v []byte) {
 func (e *bincEncDriver) EncodeStringBytes(c charEncoding, v []byte) {
 	if v == nil {
 	if v == nil {
 		e.EncodeNil()
 		e.EncodeNil()
@@ -331,6 +344,18 @@ func (e *bincEncDriver) EncodeStringBytes(c charEncoding, v []byte) {
 	}
 	}
 }
 }
 
 
+func (e *bincEncDriver) EncodeStringBytesRaw(v []byte) {
+	if v == nil {
+		e.EncodeNil()
+		return
+	}
+	l := uint64(len(v))
+	e.encLen(bincVdByteArray<<4, l) // e.encBytesLen(c, l)
+	if l > 0 {
+		e.w.writeb(v)
+	}
+}
+
 func (e *bincEncDriver) encBytesLen(c charEncoding, length uint64) {
 func (e *bincEncDriver) encBytesLen(c charEncoding, length uint64) {
 	//TODO: support bincUnicodeOther (for now, just use string or bytearray)
 	//TODO: support bincUnicodeOther (for now, just use string or bytearray)
 	if c == cRAW {
 	if c == cRAW {
@@ -377,7 +402,7 @@ type bincDecDriver struct {
 
 
 	d      *Decoder
 	d      *Decoder
 	h      *BincHandle
 	h      *BincHandle
-	r      decReader
+	r      *decReaderSwitch
 	br     bool // bytes reader
 	br     bool // bytes reader
 	bdRead bool
 	bdRead bool
 	bd     byte
 	bd     byte
@@ -391,7 +416,7 @@ type bincDecDriver struct {
 	// noStreamingCodec
 	// noStreamingCodec
 	// decNoSeparator
 	// decNoSeparator
 
 
-	b [8 * 8]byte // scratch
+	b [(8 + 1) * 8]byte // scratch
 }
 }
 
 
 func (d *bincDecDriver) readNextBd() {
 func (d *bincDecDriver) readNextBd() {
@@ -485,7 +510,8 @@ func (d *bincDecDriver) decFloat() (f float64) {
 		d.decFloatPre(d.vs, 8)
 		d.decFloatPre(d.vs, 8)
 		f = math.Float64frombits(bigen.Uint64(d.b[0:8]))
 		f = math.Float64frombits(bigen.Uint64(d.b[0:8]))
 	} else {
 	} else {
-		d.d.errorf("read float - only float32 and float64 are supported - %s %x-%x/%s", msgBadDesc, d.vd, d.vs, bincdesc(d.vd, d.vs))
+		d.d.errorf("read float - only float32 and float64 are supported - %s %x-%x/%s",
+			msgBadDesc, d.vd, d.vs, bincdesc(d.vd, d.vs))
 		return
 		return
 	}
 	}
 	return
 	return
@@ -837,7 +863,8 @@ func (d *bincDecDriver) decodeExtV(verifyTag bool, tag byte) (xtag byte, xbs []b
 	} else if d.vd == bincVdByteArray {
 	} else if d.vd == bincVdByteArray {
 		xbs = d.DecodeBytes(nil, true)
 		xbs = d.DecodeBytes(nil, true)
 	} else {
 	} else {
-		d.d.errorf("ext - expecting extensions or byte array - %s %x-%x/%s", msgBadDesc, d.vd, d.vs, bincdesc(d.vd, d.vs))
+		d.d.errorf("ext - expecting extensions or byte array - %s %x-%x/%s",
+			msgBadDesc, d.vd, d.vs, bincdesc(d.vd, d.vs))
 		return
 		return
 	}
 	}
 	d.bdRead = false
 	d.bdRead = false
@@ -882,7 +909,8 @@ func (d *bincDecDriver) DecodeNaked() {
 			n.v = valueTypeInt
 			n.v = valueTypeInt
 			n.i = int64(-1) // int8(-1)
 			n.i = int64(-1) // int8(-1)
 		default:
 		default:
-			d.d.errorf("cannot infer value - unrecognized special value from descriptor %x-%x/%s", d.vd, d.vs, bincdesc(d.vd, d.vs))
+			d.d.errorf("cannot infer value - unrecognized special value from descriptor %x-%x/%s",
+				d.vd, d.vs, bincdesc(d.vd, d.vs))
 		}
 		}
 	case bincVdSmallInt:
 	case bincVdSmallInt:
 		n.v = valueTypeUint
 		n.v = valueTypeUint

+ 1 - 1
codec/build.sh

@@ -59,7 +59,7 @@ _build() {
     cat > gen.generated.go <<EOF
     cat > gen.generated.go <<EOF
 // +build codecgen.exec
 // +build codecgen.exec
 
 
-// Copyright (c) 2012-2015 Ugorji Nwoke. All rights reserved.
+// Copyright (c) 2012-2018 Ugorji Nwoke. All rights reserved.
 // Use of this source code is governed by a MIT license found in the LICENSE file.
 // Use of this source code is governed by a MIT license found in the LICENSE file.
 
 
 package codec
 package codec

+ 32 - 19
codec/cbor.go

@@ -33,31 +33,31 @@ const (
 
 
 const (
 const (
 	cborBdIndefiniteBytes  byte = 0x5f
 	cborBdIndefiniteBytes  byte = 0x5f
-	cborBdIndefiniteString      = 0x7f
-	cborBdIndefiniteArray       = 0x9f
-	cborBdIndefiniteMap         = 0xbf
-	cborBdBreak                 = 0xff
+	cborBdIndefiniteString byte = 0x7f
+	cborBdIndefiniteArray  byte = 0x9f
+	cborBdIndefiniteMap    byte = 0xbf
+	cborBdBreak            byte = 0xff
 )
 )
 
 
 // These define some in-stream descriptors for
 // These define some in-stream descriptors for
 // manual encoding e.g. when doing explicit indefinite-length
 // manual encoding e.g. when doing explicit indefinite-length
 const (
 const (
 	CborStreamBytes  byte = 0x5f
 	CborStreamBytes  byte = 0x5f
-	CborStreamString      = 0x7f
-	CborStreamArray       = 0x9f
-	CborStreamMap         = 0xbf
-	CborStreamBreak       = 0xff
+	CborStreamString byte = 0x7f
+	CborStreamArray  byte = 0x9f
+	CborStreamMap    byte = 0xbf
+	CborStreamBreak  byte = 0xff
 )
 )
 
 
 const (
 const (
 	cborBaseUint   byte = 0x00
 	cborBaseUint   byte = 0x00
-	cborBaseNegInt      = 0x20
-	cborBaseBytes       = 0x40
-	cborBaseString      = 0x60
-	cborBaseArray       = 0x80
-	cborBaseMap         = 0xa0
-	cborBaseTag         = 0xc0
-	cborBaseSimple      = 0xe0
+	cborBaseNegInt byte = 0x20
+	cborBaseBytes  byte = 0x40
+	cborBaseString byte = 0x60
+	cborBaseArray  byte = 0x80
+	cborBaseMap    byte = 0xa0
+	cborBaseTag    byte = 0xc0
+	cborBaseSimple byte = 0xe0
 )
 )
 
 
 func cbordesc(bd byte) string {
 func cbordesc(bd byte) string {
@@ -106,7 +106,7 @@ type cborEncDriver struct {
 	noBuiltInTypes
 	noBuiltInTypes
 	encDriverNoopContainerWriter
 	encDriverNoopContainerWriter
 	e *Encoder
 	e *Encoder
-	w encWriter
+	w *encWriterSwitch
 	h *CborHandle
 	h *CborHandle
 	x [8]byte
 	x [8]byte
 	// _ [3]uint64 // padding
 	// _ [3]uint64 // padding
@@ -172,7 +172,7 @@ func (e *cborEncDriver) EncodeTime(t time.Time) {
 		e.EncodeNil()
 		e.EncodeNil()
 	} else if e.h.TimeRFC3339 {
 	} else if e.h.TimeRFC3339 {
 		e.encUint(0, cborBaseTag)
 		e.encUint(0, cborBaseTag)
-		e.EncodeString(cUTF8, t.Format(time.RFC3339Nano))
+		e.EncodeStringEnc(cUTF8, t.Format(time.RFC3339Nano))
 	} else {
 	} else {
 		e.encUint(1, cborBaseTag)
 		e.encUint(1, cborBaseTag)
 		t = t.UTC().Round(time.Microsecond)
 		t = t.UTC().Round(time.Microsecond)
@@ -239,6 +239,10 @@ func (e *cborEncDriver) EncodeString(c charEncoding, v string) {
 	e.encStringBytesS(cborBaseString, v)
 	e.encStringBytesS(cborBaseString, v)
 }
 }
 
 
+func (e *cborEncDriver) EncodeStringEnc(c charEncoding, v string) {
+	e.encStringBytesS(cborBaseString, v)
+}
+
 func (e *cborEncDriver) EncodeStringBytes(c charEncoding, v []byte) {
 func (e *cborEncDriver) EncodeStringBytes(c charEncoding, v []byte) {
 	if v == nil {
 	if v == nil {
 		e.EncodeNil()
 		e.EncodeNil()
@@ -249,6 +253,14 @@ func (e *cborEncDriver) EncodeStringBytes(c charEncoding, v []byte) {
 	}
 	}
 }
 }
 
 
+func (e *cborEncDriver) EncodeStringBytesRaw(v []byte) {
+	if v == nil {
+		e.EncodeNil()
+	} else {
+		e.encStringBytesS(cborBaseBytes, stringView(v))
+	}
+}
+
 func (e *cborEncDriver) encStringBytesS(bb byte, v string) {
 func (e *cborEncDriver) encStringBytesS(bb byte, v string) {
 	if e.h.IndefiniteLength {
 	if e.h.IndefiniteLength {
 		if bb == cborBaseBytes {
 		if bb == cborBaseBytes {
@@ -286,7 +298,7 @@ func (e *cborEncDriver) encStringBytesS(bb byte, v string) {
 type cborDecDriver struct {
 type cborDecDriver struct {
 	d      *Decoder
 	d      *Decoder
 	h      *CborHandle
 	h      *CborHandle
-	r      decReader
+	r      *decReaderSwitch
 	br     bool // bytes reader
 	br     bool // bytes reader
 	bdRead bool
 	bdRead bool
 	bd     byte
 	bd     byte
@@ -382,7 +394,8 @@ func (d *cborDecDriver) decCheckInteger() (neg bool) {
 	} else if major == cborMajorNegInt {
 	} else if major == cborMajorNegInt {
 		neg = true
 		neg = true
 	} else {
 	} else {
-		d.d.errorf("not an integer - invalid major %v from descriptor %x/%s", major, d.bd, cbordesc(d.bd))
+		d.d.errorf("not an integer - invalid major %v from descriptor %x/%s",
+			major, d.bd, cbordesc(d.bd))
 		return
 		return
 	}
 	}
 	return
 	return

+ 8 - 4
codec/codec_test.go

@@ -2565,7 +2565,8 @@ func TestBufioDecReader(t *testing.T) {
 	var s = strings.Repeat("01234'56789      ", 5)
 	var s = strings.Repeat("01234'56789      ", 5)
 	// fmt.Printf("s: %s\n", s)
 	// fmt.Printf("s: %s\n", s)
 	var r = strings.NewReader(s)
 	var r = strings.NewReader(s)
-	var br = &bufioDecReader{r: r, buf: make([]byte, 0, 13)}
+	var br = &bufioDecReader{buf: make([]byte, 0, 13)}
+	br.r = r
 	b, err := ioutil.ReadAll(br)
 	b, err := ioutil.ReadAll(br)
 	if err != nil {
 	if err != nil {
 		panic(err)
 		panic(err)
@@ -2581,7 +2582,8 @@ func TestBufioDecReader(t *testing.T) {
 	// readUntil: see: 56789
 	// readUntil: see: 56789
 	var out []byte
 	var out []byte
 	var token byte
 	var token byte
-	br = &bufioDecReader{r: strings.NewReader(s), buf: make([]byte, 0, 7)}
+	br = &bufioDecReader{buf: make([]byte, 0, 7)}
+	br.r = strings.NewReader(s)
 	// println()
 	// println()
 	for _, v2 := range [...]string{
 	for _, v2 := range [...]string{
 		`01234'`,
 		`01234'`,
@@ -2593,7 +2595,8 @@ func TestBufioDecReader(t *testing.T) {
 		testDeepEqualErr(string(out), v2, t, "-")
 		testDeepEqualErr(string(out), v2, t, "-")
 		// fmt.Printf("readUntil: out: `%s`\n", out)
 		// fmt.Printf("readUntil: out: `%s`\n", out)
 	}
 	}
-	br = &bufioDecReader{r: strings.NewReader(s), buf: make([]byte, 0, 7)}
+	br = &bufioDecReader{buf: make([]byte, 0, 7)}
+	br.r = strings.NewReader(s)
 	// println()
 	// println()
 	for range [4]struct{}{} {
 	for range [4]struct{}{} {
 		out = br.readTo(nil, &jsonNumSet)
 		out = br.readTo(nil, &jsonNumSet)
@@ -2610,7 +2613,8 @@ func TestBufioDecReader(t *testing.T) {
 		// fmt.Printf("readUntil: out: `%s`\n", out)
 		// fmt.Printf("readUntil: out: `%s`\n", out)
 		br.UnreadByte()
 		br.UnreadByte()
 	}
 	}
-	br = &bufioDecReader{r: strings.NewReader(s), buf: make([]byte, 0, 7)}
+	br = &bufioDecReader{buf: make([]byte, 0, 7)}
+	br.r = strings.NewReader(s)
 	// println()
 	// println()
 	for range [4]struct{}{} {
 	for range [4]struct{}{} {
 		out = br.readUntil(nil, ' ')
 		out = br.readUntil(nil, ' ')

File diff suppressed because it is too large
+ 509 - 231
codec/decode.go


+ 74 - 33
codec/encode.go

@@ -21,7 +21,10 @@ const defEncByteBufSize = 1 << 6 // 4:16, 6:64, 8:256, 10:1024
 var errEncoderNotInitialized = errors.New("Encoder not initialized")
 var errEncoderNotInitialized = errors.New("Encoder not initialized")
 
 
 // encWriter abstracts writing to a byte array or to an io.Writer.
 // encWriter abstracts writing to a byte array or to an io.Writer.
-type encWriter interface {
+//
+//
+// Deprecated: Use encWriterSwitch instead.
+type __encWriter interface {
 	writeb([]byte)
 	writeb([]byte)
 	writestr(string)
 	writestr(string)
 	writen1(byte)
 	writen1(byte)
@@ -40,9 +43,14 @@ type encDriver interface {
 	// encodeExtPreamble(xtag byte, length int)
 	// encodeExtPreamble(xtag byte, length int)
 	EncodeRawExt(re *RawExt, e *Encoder)
 	EncodeRawExt(re *RawExt, e *Encoder)
 	EncodeExt(v interface{}, xtag uint64, ext Ext, e *Encoder)
 	EncodeExt(v interface{}, xtag uint64, ext Ext, e *Encoder)
+	// Deprecated: try to use EncodeStringEnc instead
 	EncodeString(c charEncoding, v string)
 	EncodeString(c charEncoding, v string)
+	// c cannot be cRAW
+	EncodeStringEnc(c charEncoding, v string)
 	// EncodeSymbol(v string)
 	// EncodeSymbol(v string)
+	// Deprecated: try to use EncodeStringBytesRaw instead
 	EncodeStringBytes(c charEncoding, v []byte)
 	EncodeStringBytes(c charEncoding, v []byte)
+	EncodeStringBytesRaw(v []byte)
 	EncodeTime(time.Time)
 	EncodeTime(time.Time)
 	//encBignum(f *big.Int)
 	//encBignum(f *big.Int)
 	//encStringRunes(c charEncoding, v []rune)
 	//encStringRunes(c charEncoding, v []rune)
@@ -233,6 +241,7 @@ func (z *ioEncWriter) writen2(b1, b2 byte) {
 // 	}
 // 	}
 // }
 // }
 
 
+//go:noinline (so *encWriterSwitch.XXX has the bytesEncAppender.XXX inlined)
 func (z *ioEncWriter) atEndOfEncode() {
 func (z *ioEncWriter) atEndOfEncode() {
 	if z.fw != nil {
 	if z.fw != nil {
 		if err := z.fw.Flush(); err != nil {
 		if err := z.fw.Flush(); err != nil {
@@ -285,17 +294,17 @@ func (e *Encoder) selferMarshal(f *codecFnInfo, rv reflect.Value) {
 
 
 func (e *Encoder) binaryMarshal(f *codecFnInfo, rv reflect.Value) {
 func (e *Encoder) binaryMarshal(f *codecFnInfo, rv reflect.Value) {
 	bs, fnerr := rv2i(rv).(encoding.BinaryMarshaler).MarshalBinary()
 	bs, fnerr := rv2i(rv).(encoding.BinaryMarshaler).MarshalBinary()
-	e.marshal(bs, fnerr, false, cRAW)
+	e.marshalRaw(bs, fnerr)
 }
 }
 
 
 func (e *Encoder) textMarshal(f *codecFnInfo, rv reflect.Value) {
 func (e *Encoder) textMarshal(f *codecFnInfo, rv reflect.Value) {
 	bs, fnerr := rv2i(rv).(encoding.TextMarshaler).MarshalText()
 	bs, fnerr := rv2i(rv).(encoding.TextMarshaler).MarshalText()
-	e.marshal(bs, fnerr, false, cUTF8)
+	e.marshalUtf8(bs, fnerr)
 }
 }
 
 
 func (e *Encoder) jsonMarshal(f *codecFnInfo, rv reflect.Value) {
 func (e *Encoder) jsonMarshal(f *codecFnInfo, rv reflect.Value) {
 	bs, fnerr := rv2i(rv).(jsonMarshaler).MarshalJSON()
 	bs, fnerr := rv2i(rv).(jsonMarshaler).MarshalJSON()
-	e.marshal(bs, fnerr, true, cUTF8)
+	e.marshalAsis(bs, fnerr)
 }
 }
 
 
 func (e *Encoder) raw(f *codecFnInfo, rv reflect.Value) {
 func (e *Encoder) raw(f *codecFnInfo, rv reflect.Value) {
@@ -325,7 +334,7 @@ func (e *Encoder) kSlice(f *codecFnInfo, rv reflect.Value) {
 		// If in this method, then there was no extension function defined.
 		// If in this method, then there was no extension function defined.
 		// So it's okay to treat as []byte.
 		// So it's okay to treat as []byte.
 		if ti.rtid == uint8SliceTypId {
 		if ti.rtid == uint8SliceTypId {
-			ee.EncodeStringBytes(cRAW, rv.Bytes())
+			ee.EncodeStringBytesRaw(rv.Bytes())
 			return
 			return
 		}
 		}
 	}
 	}
@@ -340,11 +349,11 @@ func (e *Encoder) kSlice(f *codecFnInfo, rv reflect.Value) {
 	if rtelemIsByte {
 	if rtelemIsByte {
 		switch f.seq {
 		switch f.seq {
 		case seqTypeSlice:
 		case seqTypeSlice:
-			ee.EncodeStringBytes(cRAW, rv.Bytes())
+			ee.EncodeStringBytesRaw(rv.Bytes())
 		case seqTypeArray:
 		case seqTypeArray:
 			l = rv.Len()
 			l = rv.Len()
 			if rv.CanAddr() {
 			if rv.CanAddr() {
-				ee.EncodeStringBytes(cRAW, rv.Slice(0, l).Bytes())
+				ee.EncodeStringBytesRaw(rv.Slice(0, l).Bytes())
 			} else {
 			} else {
 				var bs []byte
 				var bs []byte
 				if l <= cap(e.b) {
 				if l <= cap(e.b) {
@@ -353,7 +362,7 @@ func (e *Encoder) kSlice(f *codecFnInfo, rv reflect.Value) {
 					bs = make([]byte, l)
 					bs = make([]byte, l)
 				}
 				}
 				reflect.Copy(reflect.ValueOf(bs), rv)
 				reflect.Copy(reflect.ValueOf(bs), rv)
-				ee.EncodeStringBytes(cRAW, bs)
+				ee.EncodeStringBytesRaw(bs)
 			}
 			}
 		case seqTypeChan:
 		case seqTypeChan:
 			// do not use range, so that the number of elements encoded
 			// do not use range, so that the number of elements encoded
@@ -400,7 +409,7 @@ func (e *Encoder) kSlice(f *codecFnInfo, rv reflect.Value) {
 				}
 				}
 			}
 			}
 
 
-			ee.EncodeStringBytes(cRAW, bs)
+			ee.EncodeStringBytesRaw(bs)
 		}
 		}
 		return
 		return
 	}
 	}
@@ -499,14 +508,14 @@ func (e *Encoder) kStructNoOmitempty(f *codecFnInfo, rv reflect.Value) {
 		if elemsep {
 		if elemsep {
 			for _, si := range tisfi {
 			for _, si := range tisfi {
 				ee.WriteMapElemKey()
 				ee.WriteMapElemKey()
-				// ee.EncodeString(cUTF8, si.encName)
+				// ee.EncodeStringEnc(cUTF8, si.encName)
 				e.kStructFieldKey(fti.keyType, si)
 				e.kStructFieldKey(fti.keyType, si)
 				ee.WriteMapElemValue()
 				ee.WriteMapElemValue()
 				e.encodeValue(sfn.field(si), nil, true)
 				e.encodeValue(sfn.field(si), nil, true)
 			}
 			}
 		} else {
 		} else {
 			for _, si := range tisfi {
 			for _, si := range tisfi {
-				// ee.EncodeString(cUTF8, si.encName)
+				// ee.EncodeStringEnc(cUTF8, si.encName)
 				e.kStructFieldKey(fti.keyType, si)
 				e.kStructFieldKey(fti.keyType, si)
 				e.encodeValue(sfn.field(si), nil, true)
 				e.encodeValue(sfn.field(si), nil, true)
 			}
 			}
@@ -538,7 +547,7 @@ func (e *Encoder) kStructFieldKey(keyType valueType, s *structFieldInfo) {
 			e.w.writestr(s.encName)
 			e.w.writestr(s.encName)
 			e.w.writen1('"')
 			e.w.writen1('"')
 		} else { // keyType == valueTypeString
 		} else { // keyType == valueTypeString
-			e.e.EncodeString(cUTF8, s.encName)
+			e.e.EncodeStringEnc(cUTF8, s.encName)
 		}
 		}
 	} else if keyType == valueTypeInt {
 	} else if keyType == valueTypeInt {
 		e.e.EncodeInt(m.Int(strconv.ParseInt(s.encName, 10, 64)))
 		e.e.EncodeInt(m.Int(strconv.ParseInt(s.encName, 10, 64)))
@@ -554,7 +563,7 @@ func (e *Encoder) kStructFieldKeyName(keyType valueType, encName string) {
 	// use if-else-if, not switch (which compiles to binary-search)
 	// use if-else-if, not switch (which compiles to binary-search)
 	// since keyType is typically valueTypeString, branch prediction is pretty good.
 	// since keyType is typically valueTypeString, branch prediction is pretty good.
 	if keyType == valueTypeString {
 	if keyType == valueTypeString {
-		e.e.EncodeString(cUTF8, encName)
+		e.e.EncodeStringEnc(cUTF8, encName)
 	} else if keyType == valueTypeInt {
 	} else if keyType == valueTypeInt {
 		e.e.EncodeInt(m.Int(strconv.ParseInt(encName, 10, 64)))
 		e.e.EncodeInt(m.Int(strconv.ParseInt(encName, 10, 64)))
 	} else if keyType == valueTypeUint {
 	} else if keyType == valueTypeUint {
@@ -674,7 +683,7 @@ func (e *Encoder) kStruct(f *codecFnInfo, rv reflect.Value) {
 			for j := 0; j < newlen; j++ {
 			for j := 0; j < newlen; j++ {
 				kv = fkvs[j]
 				kv = fkvs[j]
 				ee.WriteMapElemKey()
 				ee.WriteMapElemKey()
-				// ee.EncodeString(cUTF8, kv.v)
+				// ee.EncodeStringEnc(cUTF8, kv.v)
 				e.kStructFieldKey(fti.keyType, kv.v)
 				e.kStructFieldKey(fti.keyType, kv.v)
 				ee.WriteMapElemValue()
 				ee.WriteMapElemValue()
 				e.encodeValue(kv.r, nil, true)
 				e.encodeValue(kv.r, nil, true)
@@ -682,7 +691,7 @@ func (e *Encoder) kStruct(f *codecFnInfo, rv reflect.Value) {
 		} else {
 		} else {
 			for j := 0; j < newlen; j++ {
 			for j := 0; j < newlen; j++ {
 				kv = fkvs[j]
 				kv = fkvs[j]
-				// ee.EncodeString(cUTF8, kv.v)
+				// ee.EncodeStringEnc(cUTF8, kv.v)
 				e.kStructFieldKey(fti.keyType, kv.v)
 				e.kStructFieldKey(fti.keyType, kv.v)
 				e.encodeValue(kv.r, nil, true)
 				e.encodeValue(kv.r, nil, true)
 			}
 			}
@@ -778,7 +787,7 @@ func (e *Encoder) kMap(f *codecFnInfo, rv reflect.Value) {
 			ee.WriteMapElemKey()
 			ee.WriteMapElemKey()
 		}
 		}
 		if keyTypeIsString {
 		if keyTypeIsString {
-			ee.EncodeString(cUTF8, mks[j].String())
+			ee.EncodeStringEnc(cUTF8, mks[j].String())
 		} else {
 		} else {
 			e.encodeValue(mks[j], keyFn, true)
 			e.encodeValue(mks[j], keyFn, true)
 		}
 		}
@@ -828,7 +837,7 @@ func (e *Encoder) kMapCanonical(rtkey reflect.Type, rv reflect.Value, mks []refl
 			if elemsep {
 			if elemsep {
 				ee.WriteMapElemKey()
 				ee.WriteMapElemKey()
 			}
 			}
-			ee.EncodeString(cUTF8, mksv[i].v)
+			ee.EncodeStringEnc(cUTF8, mksv[i].v)
 			if elemsep {
 			if elemsep {
 				ee.WriteMapElemValue()
 				ee.WriteMapElemValue()
 			}
 			}
@@ -969,8 +978,6 @@ type encWriterSwitch struct {
 	_    [2]uint64 // padding
 	_    [2]uint64 // padding
 }
 }
 
 
-/*
-
 func (z *encWriterSwitch) writeb(s []byte) {
 func (z *encWriterSwitch) writeb(s []byte) {
 	if z.wx {
 	if z.wx {
 		z.wb.writeb(s)
 		z.wb.writeb(s)
@@ -1007,27 +1014,27 @@ func (z *encWriterSwitch) atEndOfEncode() {
 	}
 	}
 }
 }
 
 
-*/
-
 // An Encoder writes an object to an output stream in the codec format.
 // An Encoder writes an object to an output stream in the codec format.
 type Encoder struct {
 type Encoder struct {
 	panicHdl
 	panicHdl
 	// hopefully, reduce derefencing cost by laying the encWriter inside the Encoder
 	// hopefully, reduce derefencing cost by laying the encWriter inside the Encoder
 	e encDriver
 	e encDriver
+
 	// NOTE: Encoder shouldn't call it's write methods,
 	// NOTE: Encoder shouldn't call it's write methods,
 	// as the handler MAY need to do some coordination.
 	// as the handler MAY need to do some coordination.
-	w encWriter
+	w *encWriterSwitch
 
 
 	// bw *bufio.Writer
 	// bw *bufio.Writer
 	as encDriverAsis
 	as encDriverAsis
 
 
 	err error
 	err error
 
 
+	h *BasicHandle
+
 	// ---- cpu cache line boundary?
 	// ---- cpu cache line boundary?
 	encWriterSwitch
 	encWriterSwitch
 
 
 	// ---- cpu cache line boundary?
 	// ---- cpu cache line boundary?
-	h *BasicHandle
 	codecFnPooler
 	codecFnPooler
 	ci set
 	ci set
 
 
@@ -1036,7 +1043,7 @@ type Encoder struct {
 	// ---- cpu cache line boundary?
 	// ---- cpu cache line boundary?
 	// b [scratchByteArrayLen]byte
 	// b [scratchByteArrayLen]byte
 	// _ [cacheLineSize - scratchByteArrayLen]byte // padding
 	// _ [cacheLineSize - scratchByteArrayLen]byte // padding
-	b [cacheLineSize - 0]byte // used for encoding a chan or (non-addressable) array of bytes
+	b [cacheLineSize + 8]byte // used for encoding a chan or (non-addressable) array of bytes
 }
 }
 
 
 // NewEncoder returns an Encoder for encoding into an io.Writer.
 // NewEncoder returns an Encoder for encoding into an io.Writer.
@@ -1062,6 +1069,7 @@ func NewEncoderBytes(out *[]byte, h Handle) *Encoder {
 
 
 func newEncoder(h Handle) *Encoder {
 func newEncoder(h Handle) *Encoder {
 	e := &Encoder{h: h.getBasicHandle(), err: errEncoderNotInitialized}
 	e := &Encoder{h: h.getBasicHandle(), err: errEncoderNotInitialized}
+	e.w = &e.encWriterSwitch
 	e.hh = h
 	e.hh = h
 	e.esep = h.hasElemSeparators()
 	e.esep = h.hasElemSeparators()
 	return e
 	return e
@@ -1110,7 +1118,7 @@ func (e *Encoder) Reset(w io.Writer) {
 		e.wi.fw, _ = w.(ioFlusher)
 		e.wi.fw, _ = w.(ioFlusher)
 		e.wi.ww = w
 		e.wi.ww = w
 	}
 	}
-	e.w = e.wi
+	// e.w = e.wi
 	e.resetCommon()
 	e.resetCommon()
 }
 }
 
 
@@ -1128,7 +1136,7 @@ func (e *Encoder) ResetBytes(out *[]byte) {
 	}
 	}
 	e.wx = true
 	e.wx = true
 	e.wb.reset(in, out)
 	e.wb.reset(in, out)
-	e.w = &e.wb
+	// e.w = &e.wb
 	e.resetCommon()
 	e.resetCommon()
 }
 }
 
 
@@ -1267,7 +1275,7 @@ func (e *Encoder) encode(iv interface{}) {
 		e.encodeValue(v, nil, true)
 		e.encodeValue(v, nil, true)
 
 
 	case string:
 	case string:
-		e.e.EncodeString(cUTF8, v)
+		e.e.EncodeStringEnc(cUTF8, v)
 	case bool:
 	case bool:
 		e.e.EncodeBool(v)
 		e.e.EncodeBool(v)
 	case int:
 	case int:
@@ -1299,13 +1307,13 @@ func (e *Encoder) encode(iv interface{}) {
 	case time.Time:
 	case time.Time:
 		e.e.EncodeTime(v)
 		e.e.EncodeTime(v)
 	case []uint8:
 	case []uint8:
-		e.e.EncodeStringBytes(cRAW, v)
+		e.e.EncodeStringBytesRaw(v)
 
 
 	case *Raw:
 	case *Raw:
 		e.rawBytes(*v)
 		e.rawBytes(*v)
 
 
 	case *string:
 	case *string:
-		e.e.EncodeString(cUTF8, *v)
+		e.e.EncodeStringEnc(cUTF8, *v)
 	case *bool:
 	case *bool:
 		e.e.EncodeBool(*v)
 		e.e.EncodeBool(*v)
 	case *int:
 	case *int:
@@ -1338,7 +1346,7 @@ func (e *Encoder) encode(iv interface{}) {
 		e.e.EncodeTime(*v)
 		e.e.EncodeTime(*v)
 
 
 	case *[]uint8:
 	case *[]uint8:
-		e.e.EncodeStringBytes(cRAW, *v)
+		e.e.EncodeStringBytesRaw(*v)
 
 
 	default:
 	default:
 		if !fastpathEncodeTypeSwitch(iv, e) {
 		if !fastpathEncodeTypeSwitch(iv, e) {
@@ -1413,16 +1421,49 @@ TOP:
 	}
 	}
 }
 }
 
 
-func (e *Encoder) marshal(bs []byte, fnerr error, asis bool, c charEncoding) {
+// func (e *Encoder) marshal(bs []byte, fnerr error, asis bool, c charEncoding) {
+// 	if fnerr != nil {
+// 		panic(fnerr)
+// 	}
+// 	if bs == nil {
+// 		e.e.EncodeNil()
+// 	} else if asis {
+// 		e.asis(bs)
+// 	} else {
+// 		e.e.EncodeStringBytes(c, bs)
+// 	}
+// }
+
+func (e *Encoder) marshalUtf8(bs []byte, fnerr error) {
+	if fnerr != nil {
+		panic(fnerr)
+	}
+	if bs == nil {
+		e.e.EncodeNil()
+	} else {
+		e.e.EncodeStringEnc(cUTF8, stringView(bs))
+	}
+}
+
+func (e *Encoder) marshalAsis(bs []byte, fnerr error) {
 	if fnerr != nil {
 	if fnerr != nil {
 		panic(fnerr)
 		panic(fnerr)
 	}
 	}
 	if bs == nil {
 	if bs == nil {
 		e.e.EncodeNil()
 		e.e.EncodeNil()
-	} else if asis {
+	} else {
 		e.asis(bs)
 		e.asis(bs)
+	}
+}
+
+func (e *Encoder) marshalRaw(bs []byte, fnerr error) {
+	if fnerr != nil {
+		panic(fnerr)
+	}
+	if bs == nil {
+		e.e.EncodeNil()
 	} else {
 	} else {
-		e.e.EncodeStringBytes(c, bs)
+		e.e.EncodeStringBytesRaw(bs)
 	}
 	}
 }
 }
 
 

File diff suppressed because it is too large
+ 124 - 124
codec/fast-path.generated.go


+ 9 - 9
codec/fast-path.go.tmpl

@@ -1,6 +1,6 @@
 // +build !notfastpath
 // +build !notfastpath
 
 
-// Copyright (c) 2012-2015 Ugorji Nwoke. All rights reserved.
+// Copyright (c) 2012-2018 Ugorji Nwoke. All rights reserved.
 // Use of this source code is governed by a MIT license found in the LICENSE file.
 // Use of this source code is governed by a MIT license found in the LICENSE file.
 
 
 // Code generated from fast-path.go.tmpl - DO NOT EDIT.
 // Code generated from fast-path.go.tmpl - DO NOT EDIT.
@@ -251,7 +251,7 @@ func (_ fastpathT) {{ .MethodNamePfx "Enc" false }}V(v map[{{ .MapKey }}]{{ .Ele
 		v2 := make([]bytesI, len(v))
 		v2 := make([]bytesI, len(v))
 		var i, l int
 		var i, l int
 		var vp *bytesI {{/* put loop variables outside. seems currently needed for better perf */}}
 		var vp *bytesI {{/* put loop variables outside. seems currently needed for better perf */}}
-		for k2, _ := range v {
+		for k2 := range v {
 			l = len(mksv)
 			l = len(mksv)
 			e2.MustEncode(k2)
 			e2.MustEncode(k2)
 			vp = &v2[i]
 			vp = &v2[i]
@@ -280,7 +280,7 @@ func (_ fastpathT) {{ .MethodNamePfx "Enc" false }}V(v map[{{ .MapKey }}]{{ .Ele
 			e.encode(v[v2[j].i])
 			e.encode(v[v2[j].i])
 		} */}} {{else}}{{ $x := sorttype .MapKey true}}v2 := make([]{{ $x }}, len(v))
 		} */}} {{else}}{{ $x := sorttype .MapKey true}}v2 := make([]{{ $x }}, len(v))
 		var i int 
 		var i int 
-		for k, _ := range v {
+		for k := range v {
 			v2[i] = {{ $x }}(k)
 			v2[i] = {{ $x }}(k)
 			i++
 			i++
 		}
 		}
@@ -288,19 +288,19 @@ func (_ fastpathT) {{ .MethodNamePfx "Enc" false }}V(v map[{{ .MapKey }}]{{ .Ele
 		if esep {
 		if esep {
 			for _, k2 := range v2 {
 			for _, k2 := range v2 {
 				ee.WriteMapElemKey()
 				ee.WriteMapElemKey()
-				{{if eq .MapKey "string"}}ee.EncodeString(cUTF8, k2){{else}}{{ $y := printf "%s(k2)" .MapKey }}{{ encmd .MapKey $y }}{{end}}
+				{{if eq .MapKey "string"}}ee.EncodeStringEnc(cUTF8, k2){{else}}{{ $y := printf "%s(k2)" .MapKey }}{{ encmd .MapKey $y }}{{end}}
 				ee.WriteMapElemValue()
 				ee.WriteMapElemValue()
 				{{ $y := printf "v[%s(k2)]" .MapKey }}{{ encmd .Elem $y }}
 				{{ $y := printf "v[%s(k2)]" .MapKey }}{{ encmd .Elem $y }}
 			} 
 			} 
 		} else {
 		} else {
 			for _, k2 := range v2 {
 			for _, k2 := range v2 {
-				{{if eq .MapKey "string"}}ee.EncodeString(cUTF8, k2){{else}}{{ $y := printf "%s(k2)" .MapKey }}{{ encmd .MapKey $y }}{{end}}
+				{{if eq .MapKey "string"}}ee.EncodeStringEnc(cUTF8, k2){{else}}{{ $y := printf "%s(k2)" .MapKey }}{{ encmd .MapKey $y }}{{end}}
 				{{ $y := printf "v[%s(k2)]" .MapKey }}{{ encmd .Elem $y }}
 				{{ $y := printf "v[%s(k2)]" .MapKey }}{{ encmd .Elem $y }}
 			} 
 			} 
 		} {{/*
 		} {{/*
 		for _, k2 := range v2 {
 		for _, k2 := range v2 {
 			if esep { ee.WriteMapElemKey() }
 			if esep { ee.WriteMapElemKey() }
-			{{if eq .MapKey "string"}}ee.EncodeString(cUTF8, k2){{else}}{{ $y := printf "%s(k2)" .MapKey }}{{ encmd .MapKey $y }}{{end}}
+			{{if eq .MapKey "string"}}ee.EncodeStringEnc(cUTF8, k2){{else}}{{ $y := printf "%s(k2)" .MapKey }}{{ encmd .MapKey $y }}{{end}}
 			if esep { ee.WriteMapElemValue() }
 			if esep { ee.WriteMapElemValue() }
 			{{ $y := printf "v[%s(k2)]" .MapKey }}{{ encmd .Elem $y }}
 			{{ $y := printf "v[%s(k2)]" .MapKey }}{{ encmd .Elem $y }}
 		} */}} {{end}}
 		} */}} {{end}}
@@ -308,19 +308,19 @@ func (_ fastpathT) {{ .MethodNamePfx "Enc" false }}V(v map[{{ .MapKey }}]{{ .Ele
 		if esep {
 		if esep {
 			for k2, v2 := range v {
 			for k2, v2 := range v {
 				ee.WriteMapElemKey()
 				ee.WriteMapElemKey()
-				{{if eq .MapKey "string"}}ee.EncodeString(cUTF8, k2){{else}}{{ encmd .MapKey "k2"}}{{end}}
+				{{if eq .MapKey "string"}}ee.EncodeStringEnc(cUTF8, k2){{else}}{{ encmd .MapKey "k2"}}{{end}}
 				ee.WriteMapElemValue()
 				ee.WriteMapElemValue()
 				{{ encmd .Elem "v2"}}
 				{{ encmd .Elem "v2"}}
 			}
 			}
 		} else {
 		} else {
 			for k2, v2 := range v {
 			for k2, v2 := range v {
-				{{if eq .MapKey "string"}}ee.EncodeString(cUTF8, k2){{else}}{{ encmd .MapKey "k2"}}{{end}}
+				{{if eq .MapKey "string"}}ee.EncodeStringEnc(cUTF8, k2){{else}}{{ encmd .MapKey "k2"}}{{end}}
 				{{ encmd .Elem "v2"}}
 				{{ encmd .Elem "v2"}}
 			}
 			}
 		} {{/*
 		} {{/*
 		for k2, v2 := range v {
 		for k2, v2 := range v {
 			if esep { ee.WriteMapElemKey() }
 			if esep { ee.WriteMapElemKey() }
-			{{if eq .MapKey "string"}}ee.EncodeString(cUTF8, k2){{else}}{{ encmd .MapKey "k2"}}{{end}}
+			{{if eq .MapKey "string"}}ee.EncodeStringEnc(cUTF8, k2){{else}}{{ encmd .MapKey "k2"}}{{end}}
 			if esep { ee.WriteMapElemValue() }
 			if esep { ee.WriteMapElemValue() }
 			{{ encmd .Elem "v2"}}
 			{{ encmd .Elem "v2"}}
 		} */}}
 		} */}}

+ 7 - 7
codec/gen-helper.generated.go

@@ -1,6 +1,6 @@
 /* // +build ignore */
 /* // +build ignore */
 
 
-// Copyright (c) 2012-2015 Ugorji Nwoke. All rights reserved.
+// Copyright (c) 2012-2018 Ugorji Nwoke. All rights reserved.
 // Use of this source code is governed by a MIT license found in the LICENSE file.
 // Use of this source code is governed by a MIT license found in the LICENSE file.
 
 
 // Code generated from gen-helper.go.tmpl - DO NOT EDIT.
 // Code generated from gen-helper.go.tmpl - DO NOT EDIT.
@@ -14,7 +14,7 @@ import (
 )
 )
 
 
 // GenVersion is the current version of codecgen.
 // GenVersion is the current version of codecgen.
-const GenVersion = 8
+const GenVersion = 10
 
 
 // This file is used to generate helper code for codecgen.
 // This file is used to generate helper code for codecgen.
 // The values here i.e. genHelper(En|De)coder are not to be used directly by
 // The values here i.e. genHelper(En|De)coder are not to be used directly by
@@ -52,7 +52,7 @@ func (x genHelperEncDriver) EncodeBuiltin(rt uintptr, v interface{}) {}
 func (x genHelperEncDriver) EncStructFieldKey(keyType valueType, s string) {
 func (x genHelperEncDriver) EncStructFieldKey(keyType valueType, s string) {
 	var m must
 	var m must
 	if keyType == valueTypeString {
 	if keyType == valueTypeString {
-		x.encDriver.EncodeString(cUTF8, s)
+		x.encDriver.EncodeStringEnc(cUTF8, s)
 	} else if keyType == valueTypeInt {
 	} else if keyType == valueTypeInt {
 		x.encDriver.EncodeInt(m.Int(strconv.ParseInt(s, 10, 64)))
 		x.encDriver.EncodeInt(m.Int(strconv.ParseInt(s, 10, 64)))
 	} else if keyType == valueTypeUint {
 	} else if keyType == valueTypeUint {
@@ -63,7 +63,7 @@ func (x genHelperEncDriver) EncStructFieldKey(keyType valueType, s string) {
 	// encStructFieldKey(x.encDriver, keyType, s)
 	// encStructFieldKey(x.encDriver, keyType, s)
 }
 }
 func (x genHelperEncDriver) EncodeSymbol(s string) {
 func (x genHelperEncDriver) EncodeSymbol(s string) {
-	x.encDriver.EncodeString(cUTF8, s)
+	x.encDriver.EncodeStringEnc(cUTF8, s)
 }
 }
 
 
 type genHelperDecDriver struct {
 type genHelperDecDriver struct {
@@ -135,19 +135,19 @@ func (f genHelperEncoder) EncFallback(iv interface{}) {
 // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
 // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
 func (f genHelperEncoder) EncTextMarshal(iv encoding.TextMarshaler) {
 func (f genHelperEncoder) EncTextMarshal(iv encoding.TextMarshaler) {
 	bs, fnerr := iv.MarshalText()
 	bs, fnerr := iv.MarshalText()
-	f.e.marshal(bs, fnerr, false, cUTF8)
+	f.e.marshalUtf8(bs, fnerr)
 }
 }
 
 
 // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
 // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
 func (f genHelperEncoder) EncJSONMarshal(iv jsonMarshaler) {
 func (f genHelperEncoder) EncJSONMarshal(iv jsonMarshaler) {
 	bs, fnerr := iv.MarshalJSON()
 	bs, fnerr := iv.MarshalJSON()
-	f.e.marshal(bs, fnerr, true, cUTF8)
+	f.e.marshalAsis(bs, fnerr)
 }
 }
 
 
 // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
 // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
 func (f genHelperEncoder) EncBinaryMarshal(iv encoding.BinaryMarshaler) {
 func (f genHelperEncoder) EncBinaryMarshal(iv encoding.BinaryMarshaler) {
 	bs, fnerr := iv.MarshalBinary()
 	bs, fnerr := iv.MarshalBinary()
-	f.e.marshal(bs, fnerr, false, cRAW)
+	f.e.marshalRaw(bs, fnerr)
 }
 }
 
 
 // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
 // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*

+ 6 - 6
codec/gen-helper.go.tmpl

@@ -1,6 +1,6 @@
 /* // +build ignore */
 /* // +build ignore */
 
 
-// Copyright (c) 2012-2015 Ugorji Nwoke. All rights reserved.
+// Copyright (c) 2012-2018 Ugorji Nwoke. All rights reserved.
 // Use of this source code is governed by a MIT license found in the LICENSE file.
 // Use of this source code is governed by a MIT license found in the LICENSE file.
 
 
 // Code generated from gen-helper.go.tmpl - DO NOT EDIT.
 // Code generated from gen-helper.go.tmpl - DO NOT EDIT.
@@ -52,7 +52,7 @@ func (x genHelperEncDriver) EncodeBuiltin(rt uintptr, v interface{}) {}
 func (x genHelperEncDriver) EncStructFieldKey(keyType valueType, s string) {
 func (x genHelperEncDriver) EncStructFieldKey(keyType valueType, s string) {
 	var m must
 	var m must
 	if keyType == valueTypeString {
 	if keyType == valueTypeString {
-		x.encDriver.EncodeString(cUTF8, s)
+		x.encDriver.EncodeStringEnc(cUTF8, s)
 	} else if keyType == valueTypeInt {
 	} else if keyType == valueTypeInt {
 		x.encDriver.EncodeInt(m.Int(strconv.ParseInt(s, 10, 64)))
 		x.encDriver.EncodeInt(m.Int(strconv.ParseInt(s, 10, 64)))
 	} else if keyType == valueTypeUint {
 	} else if keyType == valueTypeUint {
@@ -63,7 +63,7 @@ func (x genHelperEncDriver) EncStructFieldKey(keyType valueType, s string) {
 	// encStructFieldKey(x.encDriver, keyType, s)
 	// encStructFieldKey(x.encDriver, keyType, s)
 }
 }
 func (x genHelperEncDriver) EncodeSymbol(s string) {
 func (x genHelperEncDriver) EncodeSymbol(s string) {
-	x.encDriver.EncodeString(cUTF8, s)
+	x.encDriver.EncodeStringEnc(cUTF8, s)
 }
 }
 
 
 type genHelperDecDriver struct {
 type genHelperDecDriver struct {
@@ -131,17 +131,17 @@ func (f genHelperEncoder) EncFallback(iv interface{}) {
 // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
 // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
 func (f genHelperEncoder) EncTextMarshal(iv encoding.TextMarshaler) {
 func (f genHelperEncoder) EncTextMarshal(iv encoding.TextMarshaler) {
 	bs, fnerr := iv.MarshalText()
 	bs, fnerr := iv.MarshalText()
-	f.e.marshal(bs, fnerr, false, cUTF8)
+	f.e.marshalUtf8(bs, fnerr)
 }
 }
 // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
 // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
 func (f genHelperEncoder) EncJSONMarshal(iv jsonMarshaler) {
 func (f genHelperEncoder) EncJSONMarshal(iv jsonMarshaler) {
 	bs, fnerr := iv.MarshalJSON()
 	bs, fnerr := iv.MarshalJSON()
-	f.e.marshal(bs, fnerr, true, cUTF8)
+	f.e.marshalAsis(bs, fnerr)
 }
 }
 // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
 // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
 func (f genHelperEncoder) EncBinaryMarshal(iv encoding.BinaryMarshaler) {
 func (f genHelperEncoder) EncBinaryMarshal(iv encoding.BinaryMarshaler) {
 	bs, fnerr := iv.MarshalBinary()
 	bs, fnerr := iv.MarshalBinary()
-	f.e.marshal(bs, fnerr, false, cRAW)
+	f.e.marshalRaw(bs, fnerr)
 }
 }
 // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
 // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
 func (f genHelperEncoder) EncRaw(iv Raw) { f.e.rawBytes(iv) }
 func (f genHelperEncoder) EncRaw(iv Raw) { f.e.rawBytes(iv) }

+ 1 - 1
codec/gen.generated.go

@@ -1,6 +1,6 @@
 // +build codecgen.exec
 // +build codecgen.exec
 
 
-// Copyright (c) 2012-2015 Ugorji Nwoke. All rights reserved.
+// Copyright (c) 2012-2018 Ugorji Nwoke. All rights reserved.
 // Use of this source code is governed by a MIT license found in the LICENSE file.
 // Use of this source code is governed by a MIT license found in the LICENSE file.
 
 
 package codec
 package codec

+ 13 - 11
codec/gen.go

@@ -104,7 +104,9 @@ import (
 // v6: removed unsafe from gen, and now uses codecgen.exec tag
 // v6: removed unsafe from gen, and now uses codecgen.exec tag
 // v7:
 // v7:
 // v8: current - we now maintain compatibility with old generated code.
 // v8: current - we now maintain compatibility with old generated code.
-const genVersion = 8
+// v9: skipped
+// v10: modified encDriver and decDriver interfaces. Remove deprecated methods after Jan 1, 2019
+const genVersion = 10
 
 
 const (
 const (
 	genCodecPkg        = "codec1978"
 	genCodecPkg        = "codec1978"
@@ -299,7 +301,7 @@ func Gen(w io.Writer, buildTags, pkgName, uid string, noExtensions bool,
 	// x.out(`panic(fmt.Errorf("codecgen version mismatch: current: %v, need %v. Re-generate file: %v", `)
 	// x.out(`panic(fmt.Errorf("codecgen version mismatch: current: %v, need %v. Re-generate file: %v", `)
 	// x.linef(`%v, %sGenVersion, file))`, genVersion, x.cpfx)
 	// x.linef(`%v, %sGenVersion, file))`, genVersion, x.cpfx)
 	x.linef("}")
 	x.linef("}")
-	x.line("if false { // reference the types, but skip this branch at build/run time")
+	x.line("if false { var _ byte = 0; // reference the types, but skip this branch at build/run time")
 	// x.line("_ = strconv.ParseInt")
 	// x.line("_ = strconv.ParseInt")
 	var n int
 	var n int
 	// for k, t := range x.im {
 	// for k, t := range x.im {
@@ -796,7 +798,7 @@ func (x *genRunner) enc(varname string, t reflect.Type) {
 	case reflect.Bool:
 	case reflect.Bool:
 		x.line("r.EncodeBool(bool(" + varname + "))")
 		x.line("r.EncodeBool(bool(" + varname + "))")
 	case reflect.String:
 	case reflect.String:
-		x.line("r.EncodeString(codecSelferCcUTF8" + x.xs + ", string(" + varname + "))")
+		x.line("r.EncodeStringEnc(codecSelferCcUTF8" + x.xs + ", string(" + varname + "))")
 	case reflect.Chan:
 	case reflect.Chan:
 		x.xtraSM(varname, t, true, false)
 		x.xtraSM(varname, t, true, false)
 		// x.encListFallback(varname, rtid, t)
 		// x.encListFallback(varname, rtid, t)
@@ -810,7 +812,7 @@ func (x *genRunner) enc(varname string, t reflect.Type) {
 		// - if elements are primitives or Selfers, call dedicated function on each member.
 		// - if elements are primitives or Selfers, call dedicated function on each member.
 		// - else call Encoder.encode(XXX) on it.
 		// - else call Encoder.encode(XXX) on it.
 		if rtid == uint8SliceTypId {
 		if rtid == uint8SliceTypId {
-			x.line("r.EncodeStringBytes(codecSelferCcRAW" + x.xs + ", []byte(" + varname + "))")
+			x.line("r.EncodeStringBytesRaw([]byte(" + varname + "))")
 		} else if fastpathAV.index(rtid) != -1 {
 		} else if fastpathAV.index(rtid) != -1 {
 			g := x.newGenV(t)
 			g := x.newGenV(t)
 			x.line("z.F." + g.MethodNamePfx("Enc", false) + "V(" + varname + ", e)")
 			x.line("z.F." + g.MethodNamePfx("Enc", false) + "V(" + varname + ", e)")
@@ -860,7 +862,7 @@ func (x *genRunner) encZero(t reflect.Type) {
 	case reflect.Bool:
 	case reflect.Bool:
 		x.line("r.EncodeBool(false)")
 		x.line("r.EncodeBool(false)")
 	case reflect.String:
 	case reflect.String:
-		x.line("r.EncodeString(codecSelferCcUTF8" + x.xs + `, "")`)
+		x.line("r.EncodeStringEnc(codecSelferCcUTF8" + x.xs + `, "")`)
 	default:
 	default:
 		x.line("r.EncodeNil()")
 		x.line("r.EncodeNil()")
 	}
 	}
@@ -1049,7 +1051,7 @@ func (x *genRunner) encStruct(varname string, rtid uintptr, t reflect.Type) {
 		}
 		}
 		x.line("r.WriteMapElemKey()")
 		x.line("r.WriteMapElemKey()")
 
 
-		// x.line("r.EncodeString(codecSelferCcUTF8" + x.xs + ", `" + si.encName + "`)")
+		// x.line("r.EncodeStringEnc(codecSelferCcUTF8" + x.xs + ", `" + si.encName + "`)")
 		// emulate EncStructFieldKey
 		// emulate EncStructFieldKey
 		switch ti.keyType {
 		switch ti.keyType {
 		case valueTypeInt:
 		case valueTypeInt:
@@ -1062,7 +1064,7 @@ func (x *genRunner) encStruct(varname string, rtid uintptr, t reflect.Type) {
 			if si.encNameAsciiAlphaNum {
 			if si.encNameAsciiAlphaNum {
 				x.linef(`if z.IsJSONHandle() { z.WriteStr("\"%s\"") } else { `, si.encName)
 				x.linef(`if z.IsJSONHandle() { z.WriteStr("\"%s\"") } else { `, si.encName)
 			}
 			}
-			x.linef("r.EncodeString(codecSelferCcUTF8%s, `%s`)", x.xs, si.encName)
+			x.linef("r.EncodeStringEnc(codecSelferCcUTF8%s, `%s`)", x.xs, si.encName)
 			if si.encNameAsciiAlphaNum {
 			if si.encNameAsciiAlphaNum {
 				x.linef("}")
 				x.linef("}")
 			}
 			}
@@ -1092,11 +1094,11 @@ func (x *genRunner) encStruct(varname string, rtid uintptr, t reflect.Type) {
 func (x *genRunner) encListFallback(varname string, t reflect.Type) {
 func (x *genRunner) encListFallback(varname string, t reflect.Type) {
 	elemBytes := t.Elem().Kind() == reflect.Uint8
 	elemBytes := t.Elem().Kind() == reflect.Uint8
 	if t.AssignableTo(uint8SliceTyp) {
 	if t.AssignableTo(uint8SliceTyp) {
-		x.linef("r.EncodeStringBytes(codecSelferCcRAW%s, []byte(%s))", x.xs, varname)
+		x.linef("r.EncodeStringBytesRaw([]byte(%s))", varname)
 		return
 		return
 	}
 	}
 	if t.Kind() == reflect.Array && elemBytes {
 	if t.Kind() == reflect.Array && elemBytes {
-		x.linef("r.EncodeStringBytes(codecSelferCcRAW%s, ((*[%d]byte)(%s))[:])", x.xs, t.Len(), varname)
+		x.linef("r.EncodeStringBytesRaw(((*[%d]byte)(%s))[:])", t.Len(), varname)
 		return
 		return
 	}
 	}
 	i := x.varsfx()
 	i := x.varsfx()
@@ -1116,7 +1118,7 @@ func (x *genRunner) encListFallback(varname string, t reflect.Type) {
 		}
 		}
 		// x.linef("%s = sch%s", varname, i)
 		// x.linef("%s = sch%s", varname, i)
 		if elemBytes {
 		if elemBytes {
-			x.linef("r.EncodeStringBytes(codecSelferCcRAW%s, []byte(%s))", x.xs, "sch"+i)
+			x.linef("r.EncodeStringBytesRaw([]byte(%s))", "sch"+i)
 			x.line("}")
 			x.line("}")
 			return
 			return
 		}
 		}
@@ -1935,7 +1937,7 @@ func genInternalEncCommandAsString(s string, vname string) string {
 	case "int", "int8", "int16", "int32", "int64":
 	case "int", "int8", "int16", "int32", "int64":
 		return "ee.EncodeInt(int64(" + vname + "))"
 		return "ee.EncodeInt(int64(" + vname + "))"
 	case "string":
 	case "string":
-		return "ee.EncodeString(cUTF8, " + vname + ")"
+		return "ee.EncodeStringEnc(cUTF8, " + vname + ")"
 	case "float32":
 	case "float32":
 		return "ee.EncodeFloat32(" + vname + ")"
 		return "ee.EncodeFloat32(" + vname + ")"
 	case "float64":
 	case "float64":

+ 9 - 8
codec/helper.go

@@ -166,12 +166,14 @@ type clsErr struct {
 type charEncoding uint8
 type charEncoding uint8
 
 
 const (
 const (
-	cRAW charEncoding = iota
+	_ charEncoding = iota // make 0 unset
 	cUTF8
 	cUTF8
 	cUTF16LE
 	cUTF16LE
 	cUTF16BE
 	cUTF16BE
 	cUTF32LE
 	cUTF32LE
 	cUTF32BE
 	cUTF32BE
+	// Deprecated: not a true char encoding value
+	cRAW charEncoding = 255
 )
 )
 
 
 // valueType is the stream type
 // valueType is the stream type
@@ -698,7 +700,7 @@ func (noElemSeparators) recreateEncDriver(e encDriver) (v bool) { return }
 // Users must already slice the x completely, because we will not reslice.
 // Users must already slice the x completely, because we will not reslice.
 type bigenHelper struct {
 type bigenHelper struct {
 	x []byte // must be correctly sliced to appropriate len. slicing is a cost.
 	x []byte // must be correctly sliced to appropriate len. slicing is a cost.
-	w encWriter
+	w *encWriterSwitch
 }
 }
 
 
 func (z bigenHelper) writeUint16(v uint16) {
 func (z bigenHelper) writeUint16(v uint16) {
@@ -2419,12 +2421,11 @@ func (panicHdl) errorstr(message string) {
 }
 }
 
 
 func (panicHdl) errorf(format string, params ...interface{}) {
 func (panicHdl) errorf(format string, params ...interface{}) {
-	if format != "" {
-		if len(params) == 0 {
-			panic(format)
-		} else {
-			panic(fmt.Sprintf(format, params...))
-		}
+	if format == "" {
+	} else if len(params) == 0 {
+		panic(format)
+	} else {
+		panic(fmt.Sprintf(format, params...))
 	}
 	}
 }
 }
 
 

+ 1 - 1
codec/helper_not_unsafe.go

@@ -211,7 +211,7 @@ func (e *Encoder) kTime(f *codecFnInfo, rv reflect.Value) {
 }
 }
 
 
 func (e *Encoder) kString(f *codecFnInfo, rv reflect.Value) {
 func (e *Encoder) kString(f *codecFnInfo, rv reflect.Value) {
-	e.e.EncodeString(cUTF8, rv.String())
+	e.e.EncodeStringEnc(cUTF8, rv.String())
 }
 }
 
 
 func (e *Encoder) kFloat64(f *codecFnInfo, rv reflect.Value) {
 func (e *Encoder) kFloat64(f *codecFnInfo, rv reflect.Value) {

+ 2 - 2
codec/helper_unsafe.go

@@ -184,7 +184,7 @@ func isEmptyValue(v reflect.Value, tinfos *TypeInfos, deref, checkStruct bool) b
 // We now just atomically store and load the pointer to the value directly.
 // We now just atomically store and load the pointer to the value directly.
 
 
 type atomicTypeInfoSlice struct { // expected to be 2 words
 type atomicTypeInfoSlice struct { // expected to be 2 words
-	l int            // length of the data array (must be first in struct, for 64-bit alignment necessary for 386)
+	l int            // length of data array (must be first in struct, for 64-bit alignment in i386)
 	v unsafe.Pointer // data array - Pointer (not uintptr) to maintain GC reference
 	v unsafe.Pointer // data array - Pointer (not uintptr) to maintain GC reference
 }
 }
 
 
@@ -322,7 +322,7 @@ func (e *Encoder) kTime(f *codecFnInfo, rv reflect.Value) {
 
 
 func (e *Encoder) kString(f *codecFnInfo, rv reflect.Value) {
 func (e *Encoder) kString(f *codecFnInfo, rv reflect.Value) {
 	v := (*unsafeReflectValue)(unsafe.Pointer(&rv))
 	v := (*unsafeReflectValue)(unsafe.Pointer(&rv))
-	e.e.EncodeString(cUTF8, *(*string)(v.ptr))
+	e.e.EncodeStringEnc(cUTF8, *(*string)(v.ptr))
 }
 }
 
 
 func (e *Encoder) kFloat64(f *codecFnInfo, rv reflect.Value) {
 func (e *Encoder) kFloat64(f *codecFnInfo, rv reflect.Value) {

+ 34 - 8
codec/json.go

@@ -115,7 +115,7 @@ func init() {
 // ----------------
 // ----------------
 
 
 type jsonEncDriverTypical struct {
 type jsonEncDriverTypical struct {
-	w  encWriter
+	w  *encWriterSwitch
 	b  *[jsonScratchArrayLen]byte
 	b  *[jsonScratchArrayLen]byte
 	tw bool // term white space
 	tw bool // term white space
 	c  containerState
 	c  containerState
@@ -203,7 +203,7 @@ func (e *jsonEncDriverTypical) atEndOfEncode() {
 // ----------------
 // ----------------
 
 
 type jsonEncDriverGeneric struct {
 type jsonEncDriverGeneric struct {
-	w encWriter
+	w *encWriterSwitch
 	b *[jsonScratchArrayLen]byte
 	b *[jsonScratchArrayLen]byte
 	c containerState
 	c containerState
 	// ds string // indent string
 	// ds string // indent string
@@ -405,7 +405,7 @@ type jsonEncDriver struct {
 	noBuiltInTypes
 	noBuiltInTypes
 	e  *Encoder
 	e  *Encoder
 	h  *JsonHandle
 	h  *JsonHandle
-	ew encWriter
+	ew *encWriterSwitch
 	se extWrapper
 	se extWrapper
 	// ---- cpu cache line boundary?
 	// ---- cpu cache line boundary?
 	bs []byte // scratch
 	bs []byte // scratch
@@ -462,6 +462,10 @@ func (e *jsonEncDriver) EncodeString(c charEncoding, v string) {
 	e.quoteStr(v)
 	e.quoteStr(v)
 }
 }
 
 
+func (e *jsonEncDriver) EncodeStringEnc(c charEncoding, v string) {
+	e.quoteStr(v)
+}
+
 func (e *jsonEncDriver) EncodeStringBytes(c charEncoding, v []byte) {
 func (e *jsonEncDriver) EncodeStringBytes(c charEncoding, v []byte) {
 	// if encoding raw bytes and RawBytesExt is configured, use it to encode
 	// if encoding raw bytes and RawBytesExt is configured, use it to encode
 	if v == nil {
 	if v == nil {
@@ -489,6 +493,29 @@ func (e *jsonEncDriver) EncodeStringBytes(c charEncoding, v []byte) {
 	}
 	}
 }
 }
 
 
+func (e *jsonEncDriver) EncodeStringBytesRaw(v []byte) {
+	// if encoding raw bytes and RawBytesExt is configured, use it to encode
+	if v == nil {
+		e.EncodeNil()
+		return
+	}
+	if e.se.InterfaceExt != nil {
+		e.EncodeExt(v, 0, &e.se, e.e)
+		return
+	}
+
+	slen := base64.StdEncoding.EncodedLen(len(v))
+	if cap(e.bs) >= slen+2 {
+		e.bs = e.bs[:slen+2]
+	} else {
+		e.bs = make([]byte, slen+2)
+	}
+	e.bs[0] = '"'
+	base64.StdEncoding.Encode(e.bs[1:], v)
+	e.bs[slen+1] = '"'
+	e.ew.writeb(e.bs)
+}
+
 func (e *jsonEncDriver) EncodeAsis(v []byte) {
 func (e *jsonEncDriver) EncodeAsis(v []byte) {
 	e.ew.writeb(v)
 	e.ew.writeb(v)
 }
 }
@@ -568,7 +595,7 @@ type jsonDecDriver struct {
 	noBuiltInTypes
 	noBuiltInTypes
 	d  *Decoder
 	d  *Decoder
 	h  *JsonHandle
 	h  *JsonHandle
-	r  decReader
+	r  *decReaderSwitch
 	se extWrapper
 	se extWrapper
 
 
 	// ---- writable fields during execution --- *try* to keep in sep cache line
 	// ---- writable fields during execution --- *try* to keep in sep cache line
@@ -583,7 +610,7 @@ type jsonDecDriver struct {
 	b  [jsonScratchArrayLen]byte // scratch 1, used for parsing strings or numbers or time.Time
 	b  [jsonScratchArrayLen]byte // scratch 1, used for parsing strings or numbers or time.Time
 	b2 [jsonScratchArrayLen]byte // scratch 2, used only for readUntil, decNumBytes
 	b2 [jsonScratchArrayLen]byte // scratch 2, used only for readUntil, decNumBytes
 
 
-	_ [3]uint64 // padding
+	// _ [3]uint64 // padding
 	// n jsonNum
 	// n jsonNum
 }
 }
 
 
@@ -712,7 +739,6 @@ func (d *jsonDecDriver) readLit(length, fromIdx uint8) {
 	d.tok = 0
 	d.tok = 0
 	if jsonValidateSymbols && !bytes.Equal(bs, jsonLiterals[fromIdx:fromIdx+length]) {
 	if jsonValidateSymbols && !bytes.Equal(bs, jsonLiterals[fromIdx:fromIdx+length]) {
 		d.d.errorf("expecting %s: got %s", jsonLiterals[fromIdx:fromIdx+length], bs)
 		d.d.errorf("expecting %s: got %s", jsonLiterals[fromIdx:fromIdx+length], bs)
-		return
 	}
 	}
 }
 }
 
 
@@ -1321,7 +1347,7 @@ func (h *JsonHandle) SetInterfaceExt(rt reflect.Type, tag uint64, ext InterfaceE
 type jsonEncDriverTypicalImpl struct {
 type jsonEncDriverTypicalImpl struct {
 	jsonEncDriver
 	jsonEncDriver
 	jsonEncDriverTypical
 	jsonEncDriverTypical
-	_ [3]uint64 // padding
+	_ [1]uint64 // padding
 }
 }
 
 
 func (x *jsonEncDriverTypicalImpl) reset() {
 func (x *jsonEncDriverTypicalImpl) reset() {
@@ -1332,7 +1358,7 @@ func (x *jsonEncDriverTypicalImpl) reset() {
 type jsonEncDriverGenericImpl struct {
 type jsonEncDriverGenericImpl struct {
 	jsonEncDriver
 	jsonEncDriver
 	jsonEncDriverGeneric
 	jsonEncDriverGeneric
-	_ [2]uint64 // padding
+	// _ [2]uint64 // padding
 }
 }
 
 
 func (x *jsonEncDriverGenericImpl) reset() {
 func (x *jsonEncDriverGenericImpl) reset() {

+ 1 - 1
codec/mammoth-test.go.tmpl

@@ -1,4 +1,4 @@
-// Copyright (c) 2012-2015 Ugorji Nwoke. All rights reserved.
+// Copyright (c) 2012-2018 Ugorji Nwoke. All rights reserved.
 // Use of this source code is governed by a MIT license found in the LICENSE file.
 // Use of this source code is governed by a MIT license found in the LICENSE file.
 
 
 // Code generated from mammoth-test.go.tmpl - DO NOT EDIT.
 // Code generated from mammoth-test.go.tmpl - DO NOT EDIT.

+ 1 - 1
codec/mammoth2-test.go.tmpl

@@ -1,6 +1,6 @@
 // +build !notfastpath
 // +build !notfastpath
 
 
-// Copyright (c) 2012-2015 Ugorji Nwoke. All rights reserved.
+// Copyright (c) 2012-2018 Ugorji Nwoke. All rights reserved.
 // Use of this source code is governed by a MIT license found in the LICENSE file.
 // Use of this source code is governed by a MIT license found in the LICENSE file.
 
 
 // Code generated from mammoth2-test.go.tmpl - DO NOT EDIT.
 // Code generated from mammoth2-test.go.tmpl - DO NOT EDIT.

File diff suppressed because it is too large
+ 114 - 113
codec/mammoth2_codecgen_generated_test.go


+ 1 - 1
codec/mammoth2_generated_test.go

@@ -1,6 +1,6 @@
 // +build !notfastpath
 // +build !notfastpath
 
 
-// Copyright (c) 2012-2015 Ugorji Nwoke. All rights reserved.
+// Copyright (c) 2012-2018 Ugorji Nwoke. All rights reserved.
 // Use of this source code is governed by a MIT license found in the LICENSE file.
 // Use of this source code is governed by a MIT license found in the LICENSE file.
 
 
 // Code generated from mammoth2-test.go.tmpl - DO NOT EDIT.
 // Code generated from mammoth2-test.go.tmpl - DO NOT EDIT.

+ 1 - 1
codec/mammoth_generated_test.go

@@ -1,4 +1,4 @@
-// Copyright (c) 2012-2015 Ugorji Nwoke. All rights reserved.
+// Copyright (c) 2012-2018 Ugorji Nwoke. All rights reserved.
 // Use of this source code is governed by a MIT license found in the LICENSE file.
 // Use of this source code is governed by a MIT license found in the LICENSE file.
 
 
 // Code generated from mammoth-test.go.tmpl - DO NOT EDIT.
 // Code generated from mammoth-test.go.tmpl - DO NOT EDIT.

+ 72 - 48
codec/msgpack.go

@@ -30,53 +30,53 @@ import (
 
 
 const (
 const (
 	mpPosFixNumMin byte = 0x00
 	mpPosFixNumMin byte = 0x00
-	mpPosFixNumMax      = 0x7f
-	mpFixMapMin         = 0x80
-	mpFixMapMax         = 0x8f
-	mpFixArrayMin       = 0x90
-	mpFixArrayMax       = 0x9f
-	mpFixStrMin         = 0xa0
-	mpFixStrMax         = 0xbf
-	mpNil               = 0xc0
-	_                   = 0xc1
-	mpFalse             = 0xc2
-	mpTrue              = 0xc3
-	mpFloat             = 0xca
-	mpDouble            = 0xcb
-	mpUint8             = 0xcc
-	mpUint16            = 0xcd
-	mpUint32            = 0xce
-	mpUint64            = 0xcf
-	mpInt8              = 0xd0
-	mpInt16             = 0xd1
-	mpInt32             = 0xd2
-	mpInt64             = 0xd3
+	mpPosFixNumMax byte = 0x7f
+	mpFixMapMin    byte = 0x80
+	mpFixMapMax    byte = 0x8f
+	mpFixArrayMin  byte = 0x90
+	mpFixArrayMax  byte = 0x9f
+	mpFixStrMin    byte = 0xa0
+	mpFixStrMax    byte = 0xbf
+	mpNil          byte = 0xc0
+	_              byte = 0xc1
+	mpFalse        byte = 0xc2
+	mpTrue         byte = 0xc3
+	mpFloat        byte = 0xca
+	mpDouble       byte = 0xcb
+	mpUint8        byte = 0xcc
+	mpUint16       byte = 0xcd
+	mpUint32       byte = 0xce
+	mpUint64       byte = 0xcf
+	mpInt8         byte = 0xd0
+	mpInt16        byte = 0xd1
+	mpInt32        byte = 0xd2
+	mpInt64        byte = 0xd3
 
 
 	// extensions below
 	// extensions below
-	mpBin8     = 0xc4
-	mpBin16    = 0xc5
-	mpBin32    = 0xc6
-	mpExt8     = 0xc7
-	mpExt16    = 0xc8
-	mpExt32    = 0xc9
-	mpFixExt1  = 0xd4
-	mpFixExt2  = 0xd5
-	mpFixExt4  = 0xd6
-	mpFixExt8  = 0xd7
-	mpFixExt16 = 0xd8
-
-	mpStr8  = 0xd9 // new
-	mpStr16 = 0xda
-	mpStr32 = 0xdb
-
-	mpArray16 = 0xdc
-	mpArray32 = 0xdd
-
-	mpMap16 = 0xde
-	mpMap32 = 0xdf
-
-	mpNegFixNumMin = 0xe0
-	mpNegFixNumMax = 0xff
+	mpBin8     byte = 0xc4
+	mpBin16    byte = 0xc5
+	mpBin32    byte = 0xc6
+	mpExt8     byte = 0xc7
+	mpExt16    byte = 0xc8
+	mpExt32    byte = 0xc9
+	mpFixExt1  byte = 0xd4
+	mpFixExt2  byte = 0xd5
+	mpFixExt4  byte = 0xd6
+	mpFixExt8  byte = 0xd7
+	mpFixExt16 byte = 0xd8
+
+	mpStr8  byte = 0xd9 // new
+	mpStr16 byte = 0xda
+	mpStr32 byte = 0xdb
+
+	mpArray16 byte = 0xdc
+	mpArray32 byte = 0xdd
+
+	mpMap16 byte = 0xde
+	mpMap32 byte = 0xdf
+
+	mpNegFixNumMin byte = 0xe0
+	mpNegFixNumMax byte = 0xff
 )
 )
 
 
 var mpTimeExtTag int8 = -1
 var mpTimeExtTag int8 = -1
@@ -199,7 +199,7 @@ type msgpackEncDriver struct {
 	encDriverNoopContainerWriter
 	encDriverNoopContainerWriter
 	// encNoSeparator
 	// encNoSeparator
 	e *Encoder
 	e *Encoder
-	w encWriter
+	w *encWriterSwitch
 	h *MsgpackHandle
 	h *MsgpackHandle
 	x [8]byte
 	x [8]byte
 	// _ [3]uint64 // padding
 	// _ [3]uint64 // padding
@@ -325,7 +325,7 @@ func (e *msgpackEncDriver) EncodeExt(v interface{}, xtag uint64, ext Ext, _ *Enc
 		e.encodeExtPreamble(uint8(xtag), len(bs))
 		e.encodeExtPreamble(uint8(xtag), len(bs))
 		e.w.writeb(bs)
 		e.w.writeb(bs)
 	} else {
 	} else {
-		e.EncodeStringBytes(cRAW, bs)
+		e.EncodeStringBytesRaw(bs)
 	}
 	}
 }
 }
 
 
@@ -379,6 +379,14 @@ func (e *msgpackEncDriver) EncodeString(c charEncoding, s string) {
 	}
 	}
 }
 }
 
 
+func (e *msgpackEncDriver) EncodeStringEnc(c charEncoding, s string) {
+	slen := len(s)
+	e.writeContainerLen(msgpackContainerStr, slen)
+	if slen > 0 {
+		e.w.writestr(s)
+	}
+}
+
 func (e *msgpackEncDriver) EncodeStringBytes(c charEncoding, bs []byte) {
 func (e *msgpackEncDriver) EncodeStringBytes(c charEncoding, bs []byte) {
 	if bs == nil {
 	if bs == nil {
 		e.EncodeNil()
 		e.EncodeNil()
@@ -395,6 +403,22 @@ func (e *msgpackEncDriver) EncodeStringBytes(c charEncoding, bs []byte) {
 	}
 	}
 }
 }
 
 
+func (e *msgpackEncDriver) EncodeStringBytesRaw(bs []byte) {
+	if bs == nil {
+		e.EncodeNil()
+		return
+	}
+	slen := len(bs)
+	if e.h.WriteExt {
+		e.writeContainerLen(msgpackContainerBin, slen)
+	} else {
+		e.writeContainerLen(msgpackContainerStr, slen)
+	}
+	if slen > 0 {
+		e.w.writeb(bs)
+	}
+}
+
 func (e *msgpackEncDriver) writeContainerLen(ct msgpackContainerType, l int) {
 func (e *msgpackEncDriver) writeContainerLen(ct msgpackContainerType, l int) {
 	if ct.hasFixMin && l < ct.fixCutoff {
 	if ct.hasFixMin && l < ct.fixCutoff {
 		e.w.writen1(ct.bFixMin | byte(l))
 		e.w.writen1(ct.bFixMin | byte(l))
@@ -413,7 +437,7 @@ func (e *msgpackEncDriver) writeContainerLen(ct msgpackContainerType, l int) {
 
 
 type msgpackDecDriver struct {
 type msgpackDecDriver struct {
 	d *Decoder
 	d *Decoder
-	r decReader
+	r *decReaderSwitch
 	h *MsgpackHandle
 	h *MsgpackHandle
 	// b      [scratchByteArrayLen]byte
 	// b      [scratchByteArrayLen]byte
 	bd     byte
 	bd     byte

+ 1 - 1
codec/rpc.go

@@ -10,7 +10,7 @@ import (
 	"net/rpc"
 	"net/rpc"
 )
 )
 
 
-var errRpcJsonNeedsTermWhitespace = errors.New("rpc requires a JsonHandle with TermWhitespace set to true")
+var errRpcJsonNeedsTermWhitespace = errors.New("rpc requires JsonHandle with TermWhitespace=true")
 
 
 // Rpc provides a rpc Server or Client Codec for rpc communication.
 // Rpc provides a rpc Server or Client Codec for rpc communication.
 type Rpc interface {
 type Rpc interface {

+ 14 - 6
codec/simple.go

@@ -36,7 +36,7 @@ type simpleEncDriver struct {
 	// encNoSeparator
 	// encNoSeparator
 	e *Encoder
 	e *Encoder
 	h *SimpleHandle
 	h *SimpleHandle
-	w encWriter
+	w *encWriterSwitch
 	b [8]byte
 	b [8]byte
 	// c containerState
 	// c containerState
 	encDriverTrackContainerWriter
 	encDriverTrackContainerWriter
@@ -157,7 +157,11 @@ func (e *simpleEncDriver) WriteMapStart(length int) {
 	e.encLen(simpleVdMap, length)
 	e.encLen(simpleVdMap, length)
 }
 }
 
 
-func (e *simpleEncDriver) EncodeString(c charEncoding, v string) {
+// func (e *simpleEncDriver) EncodeSymbol(v string) {
+// 	e.EncodeString(cUTF8, v)
+// }
+
+func (e *simpleEncDriver) EncodeStringEnc(c charEncoding, v string) {
 	if false && e.h.EncZeroValuesAsNil && e.c != containerMapKey && v == "" {
 	if false && e.h.EncZeroValuesAsNil && e.c != containerMapKey && v == "" {
 		e.EncodeNil()
 		e.EncodeNil()
 		return
 		return
@@ -166,11 +170,15 @@ func (e *simpleEncDriver) EncodeString(c charEncoding, v string) {
 	e.w.writestr(v)
 	e.w.writestr(v)
 }
 }
 
 
-// func (e *simpleEncDriver) EncodeSymbol(v string) {
-// 	e.EncodeString(cUTF8, v)
-// }
+func (e *simpleEncDriver) EncodeString(c charEncoding, v string) {
+	e.EncodeStringEnc(c, v)
+}
 
 
 func (e *simpleEncDriver) EncodeStringBytes(c charEncoding, v []byte) {
 func (e *simpleEncDriver) EncodeStringBytes(c charEncoding, v []byte) {
+	e.EncodeStringBytesRaw(v)
+}
+
+func (e *simpleEncDriver) EncodeStringBytesRaw(v []byte) {
 	// if e.h.EncZeroValuesAsNil && e.c != containerMapKey && v == nil {
 	// if e.h.EncZeroValuesAsNil && e.c != containerMapKey && v == nil {
 	if v == nil {
 	if v == nil {
 		e.EncodeNil()
 		e.EncodeNil()
@@ -201,7 +209,7 @@ func (e *simpleEncDriver) EncodeTime(t time.Time) {
 type simpleDecDriver struct {
 type simpleDecDriver struct {
 	d      *Decoder
 	d      *Decoder
 	h      *SimpleHandle
 	h      *SimpleHandle
-	r      decReader
+	r      *decReaderSwitch
 	bdRead bool
 	bdRead bool
 	bd     byte
 	bd     byte
 	br     bool // a bytes reader?
 	br     bool // a bytes reader?

+ 1 - 0
codec/values_test.go

@@ -351,6 +351,7 @@ func populateTestStrucCommon(ts *TestStrucCommon, n int, bench, useInterface, us
 		// ts.Iptrslice = nil
 		// ts.Iptrslice = nil
 	}
 	}
 	if !useStringKeyOnly {
 	if !useStringKeyOnly {
+		var _ byte = 0 // so this empty branch doesn't flag a warning
 		// ts.AnonInTestStruc.AMU32F64 = map[uint32]float64{1: 1, 2: 2, 3: 3} // Json/Bson barf
 		// ts.AnonInTestStruc.AMU32F64 = map[uint32]float64{1: 1, 2: 2, 3: 3} // Json/Bson barf
 	}
 	}
 }
 }

Some files were not shown because too many files changed in this diff