Browse Source

codec: re-design implementation of fast-path functions.

Now, all short-circuit functions are stored in fast-path.go.
They are also registered in maps.

At encode or decode time, we also check if there is a
dedicated reflection-bypassing func for a given slice or map type,
and use that in place of the generic kMap or kSlice.

It simplifies encode and decode because they do not have to
explicitly know and call shortcircuit functions again.

Also, map/slice encode/decode grabs encFn/decFn for key/val/elem type just once.
This effectively bypasses some reflection calls,
only doing it once, instead of each iteration of its collection.

Also, include gen-fast-path.go to auto-generate the fast-path.go file.
Design fast-path.go so it can be excluded (for smaller lib/binary) using a +buid ignore.
Ugorji Nwoke 11 years ago
parent
commit
aab1bb9243
8 changed files with 2770 additions and 483 deletions
  1. 2 2
      codec/bench_test.go
  2. 5 2
      codec/codecs_test.go
  3. 57 235
      codec/decode.go
  4. 68 177
      codec/encode.go
  5. 1 1
      codec/ext_dep_test.go
  6. 2287 0
      codec/fast-path.go
  7. 337 0
      codec/gen-fast-path.go
  8. 13 66
      codec/helper.go

+ 2 - 2
codec/bench_test.go

@@ -294,11 +294,11 @@ func Benchmark__Binc_Sym___Decode(b *testing.B) {
 	fnBenchmarkDecode(b, "binc", benchTs, fnBincSymEncodeFn, fnBincSymDecodeFn, fnBenchNewTs)
 }
 
-func Benchmark__Simple____Encode(b *testing.B) {
+func Benchmark__Simple_____Encode(b *testing.B) {
 	fnBenchmarkEncode(b, "simple", benchTs, fnSimpleEncodeFn)
 }
 
-func Benchmark__Simple____Decode(b *testing.B) {
+func Benchmark__Simple_____Decode(b *testing.B) {
 	fnBenchmarkDecode(b, "simple", benchTs, fnSimpleEncodeFn, fnSimpleDecodeFn, fnBenchNewTs)
 }
 

+ 5 - 2
codec/codecs_test.go

@@ -55,6 +55,8 @@ var (
 	_                         = fmt.Printf
 	skipVerifyVal interface{} = &(struct{}{})
 
+	testMapStrIntfTyp = reflect.TypeOf(map[string]interface{}(nil))
+
 	// For Go Time, do not use a descriptive timezone.
 	// It's unnecessary, and makes it harder to do a reflect.DeepEqual.
 	// The Offset already tells what the offset should be, if not on UTC and unknown zone name.
@@ -584,7 +586,8 @@ func testCodecTableOne(t *testing.T, h Handle) {
 	// func TestMsgpackNilStringMap(t *testing.T) {
 	var oldMapType reflect.Type
 	v := h.getBasicHandle()
-	oldMapType, v.MapType = v.MapType, mapStrIntfTyp
+
+	oldMapType, v.MapType = v.MapType, testMapStrIntfTyp
 
 	//skip time.Time, []interface{} containing time.Time, last map, and newStruc
 	doTestCodecTableOne(t, true, h, table[:idxTime], tableTestNilVerify[:idxTime])
@@ -856,7 +859,7 @@ func doTestMsgpackPythonGenStreams(t *testing.T) {
 			failT(t)
 			continue
 		}
-		testMsgpackH.MapType = mapStrIntfTyp
+		testMsgpackH.MapType = testMapStrIntfTyp
 
 		var v1 interface{}
 		if err = testUnmarshal(&v1, bss, testMsgpackH); err != nil {

+ 57 - 235
codec/decode.go

@@ -16,6 +16,9 @@ const (
 	msgDecCannotExpandArr = "cannot expand go array from %v to stream length: %v"
 )
 
+// fastpathsEnc holds the rtid (reflect.Type Pointer) to fast decode function for a selected slice/map type.
+var fastpathsDec = make(map[uintptr]func(*decFnInfo, reflect.Value))
+
 // decReader abstracts the reading source, allowing implementations that can
 // read from an io.Reader or directly off a byte slice with zero-copying.
 type decReader interface {
@@ -185,6 +188,13 @@ type decFnInfo struct {
 	array bool
 }
 
+// ----------------------------------------
+
+type decFn struct {
+	i *decFnInfo
+	f func(*decFnInfo, reflect.Value)
+}
+
 func (f *decFnInfo) builtin(rv reflect.Value) {
 	f.dd.decodeBuiltin(f.ti.rtid, rv.Addr().Interface())
 }
@@ -294,7 +304,7 @@ func (f *decFnInfo) kUint16(rv reflect.Value) {
 func (f *decFnInfo) kInterface(rv reflect.Value) {
 	// debugf("\t===> kInterface")
 	if !rv.IsNil() {
-		f.d.decodeValue(rv.Elem())
+		f.d.decodeValue(rv.Elem(), decFn{})
 		return
 	}
 	// nil interface:
@@ -343,7 +353,7 @@ func (f *decFnInfo) kInterface(rv reflect.Value) {
 	}
 	if decodeFurther {
 		if useRvn {
-			f.d.decodeValue(rvn)
+			f.d.decodeValue(rvn, decFn{})
 		} else if v != nil {
 			// this v is a pointer, so we need to dereference it when done
 			f.d.decode(v)
@@ -375,7 +385,7 @@ func (f *decFnInfo) kStruct(rv reflect.Value) {
 			if k := fti.indexForEncName(rvkencname); k > -1 {
 				sfik := tisfi[k]
 				if sfik.i != -1 {
-					f.d.decodeValue(rv.Field(int(sfik.i)))
+					f.d.decodeValue(rv.Field(int(sfik.i)), decFn{})
 				} else {
 					f.d.decEmbeddedField(rv, sfik.is)
 				}
@@ -386,7 +396,7 @@ func (f *decFnInfo) kStruct(rv reflect.Value) {
 						rvkencname)
 				} else {
 					var nilintf0 interface{}
-					f.d.decodeValue(reflect.ValueOf(&nilintf0).Elem())
+					f.d.decodeValue(reflect.ValueOf(&nilintf0).Elem(), decFn{})
 				}
 			}
 		}
@@ -400,7 +410,7 @@ func (f *decFnInfo) kStruct(rv reflect.Value) {
 				break
 			}
 			if si.i != -1 {
-				f.d.decodeValue(rv.Field(int(si.i)))
+				f.d.decodeValue(rv.Field(int(si.i)), decFn{})
 			} else {
 				f.d.decEmbeddedField(rv, si.is)
 			}
@@ -409,7 +419,7 @@ func (f *decFnInfo) kStruct(rv reflect.Value) {
 			// read remaining values and throw away
 			for j := len(fti.sfip); j < containerLen; j++ {
 				var nilintf0 interface{}
-				f.d.decodeValue(reflect.ValueOf(&nilintf0).Elem())
+				f.d.decodeValue(reflect.ValueOf(&nilintf0).Elem(), decFn{})
 			}
 		}
 	} else {
@@ -432,23 +442,6 @@ func (f *decFnInfo) kSlice(rv reflect.Value) {
 		}
 	}
 
-	if shortCircuitReflectToFastPath && rv.CanAddr() {
-		switch f.ti.rtid {
-		case intfSliceTypId:
-			f.d.decSliceIntf(rv.Addr().Interface().(*[]interface{}), currEncodedType, f.array)
-			return
-		case uint64SliceTypId:
-			f.d.decSliceUint64(rv.Addr().Interface().(*[]uint64), currEncodedType, f.array)
-			return
-		case int64SliceTypId:
-			f.d.decSliceInt64(rv.Addr().Interface().(*[]int64), currEncodedType, f.array)
-			return
-		case strSliceTypId:
-			f.d.decSliceStr(rv.Addr().Interface().(*[]string), currEncodedType, f.array)
-			return
-		}
-	}
-
 	containerLen, containerLenS := decContLens(f.dd, currEncodedType)
 
 	// an array can never return a nil slice. so no need to check f.array here.
@@ -474,8 +467,13 @@ func (f *decFnInfo) kSlice(rv reflect.Value) {
 		rv.SetLen(containerLenS)
 	}
 
+	rtelem := f.ti.rt.Elem()
+	for rtelem.Kind() == reflect.Ptr {
+		rtelem = rtelem.Elem()
+	}
+	fn := f.d.getDecFn(rtelem)
 	for j := 0; j < containerLenS; j++ {
-		f.d.decodeValue(rv.Index(j))
+		f.d.decodeValue(rv.Index(j), fn)
 	}
 }
 
@@ -485,23 +483,6 @@ func (f *decFnInfo) kArray(rv reflect.Value) {
 }
 
 func (f *decFnInfo) kMap(rv reflect.Value) {
-	if shortCircuitReflectToFastPath && rv.CanAddr() {
-		switch f.ti.rtid {
-		case mapStrIntfTypId:
-			f.d.decMapStrIntf(rv.Addr().Interface().(*map[string]interface{}))
-			return
-		case mapIntfIntfTypId:
-			f.d.decMapIntfIntf(rv.Addr().Interface().(*map[interface{}]interface{}))
-			return
-		case mapInt64IntfTypId:
-			f.d.decMapInt64Intf(rv.Addr().Interface().(*map[int64]interface{}))
-			return
-		case mapUint64IntfTypId:
-			f.d.decMapUint64Intf(rv.Addr().Interface().(*map[uint64]interface{}))
-			return
-		}
-	}
-
 	containerLen := f.dd.readMapLen()
 
 	if rv.IsNil() {
@@ -514,12 +495,19 @@ func (f *decFnInfo) kMap(rv reflect.Value) {
 
 	ktype, vtype := f.ti.rt.Key(), f.ti.rt.Elem()
 	ktypeId := reflect.ValueOf(ktype).Pointer()
+	var keyFn, valFn decFn
+	var xtyp reflect.Type
+	for xtyp = ktype; xtyp.Kind() == reflect.Ptr; xtyp = xtyp.Elem() {
+	}
+	keyFn = f.d.getDecFn(xtyp)
+	for xtyp = vtype; xtyp.Kind() == reflect.Ptr; xtyp = xtyp.Elem() {
+	}
+	valFn = f.d.getDecFn(xtyp)
 	for j := 0; j < containerLen; j++ {
 		rvk := reflect.New(ktype).Elem()
-		f.d.decodeValue(rvk)
+		f.d.decodeValue(rvk, keyFn)
 
 		// special case if a byte array.
-		// if ktype == intfTyp {
 		if ktypeId == intfTypId {
 			rvk = rvk.Elem()
 			if rvk.Type() == uint8SliceTyp {
@@ -531,18 +519,11 @@ func (f *decFnInfo) kMap(rv reflect.Value) {
 			rvv = reflect.New(vtype).Elem()
 		}
 
-		f.d.decodeValue(rvv)
+		f.d.decodeValue(rvv, valFn)
 		rv.SetMapIndex(rvk, rvv)
 	}
 }
 
-// ----------------------------------------
-
-type decFn struct {
-	i *decFnInfo
-	f func(*decFnInfo, reflect.Value)
-}
-
 // A Decoder reads and decodes an object from an input stream in the codec format.
 type Decoder struct {
 	r decReader
@@ -640,7 +621,7 @@ func (d *Decoder) decode(iv interface{}) {
 
 	case reflect.Value:
 		d.chkPtrValue(v)
-		d.decodeValue(v.Elem())
+		d.decodeValue(v.Elem(), decFn{})
 
 	case *string:
 		*v = d.d.decodeString()
@@ -673,34 +654,17 @@ func (d *Decoder) decode(iv interface{}) {
 	case *[]byte:
 		*v, _ = d.d.decodeBytes(*v)
 
-	case *[]interface{}:
-		d.decSliceIntf(v, valueTypeInvalid, false)
-	case *[]uint64:
-		d.decSliceUint64(v, valueTypeInvalid, false)
-	case *[]int64:
-		d.decSliceInt64(v, valueTypeInvalid, false)
-	case *[]string:
-		d.decSliceStr(v, valueTypeInvalid, false)
-	case *map[string]interface{}:
-		d.decMapStrIntf(v)
-	case *map[interface{}]interface{}:
-		d.decMapIntfIntf(v)
-	case *map[uint64]interface{}:
-		d.decMapUint64Intf(v)
-	case *map[int64]interface{}:
-		d.decMapInt64Intf(v)
-
 	case *interface{}:
-		d.decodeValue(reflect.ValueOf(iv).Elem())
+		d.decodeValue(reflect.ValueOf(iv).Elem(), decFn{})
 
 	default:
 		rv := reflect.ValueOf(iv)
 		d.chkPtrValue(rv)
-		d.decodeValue(rv.Elem())
+		d.decodeValue(rv.Elem(), decFn{})
 	}
 }
 
-func (d *Decoder) decodeValue(rv reflect.Value) {
+func (d *Decoder) decodeValue(rv reflect.Value, fn decFn) {
 	d.d.initReadNext()
 
 	if d.d.tryDecodeAsNil() {
@@ -729,14 +693,20 @@ func (d *Decoder) decodeValue(rv reflect.Value) {
 		rv = rv.Elem()
 	}
 
-	rt := rv.Type()
+	if fn.i == nil {
+		fn = d.getDecFn(rv.Type())
+	}
+	fn.f(fn.i, rv)
+	return
+}
+
+func (d *Decoder) getDecFn(rt reflect.Type) (fn decFn) {
 	rtid := reflect.ValueOf(rt).Pointer()
 
 	// retrieve or register a focus'ed function for this type
 	// to eliminate need to do the retrieval multiple times
 
 	// if d.f == nil && d.s == nil { debugf("---->Creating new dec f map for type: %v\n", rt) }
-	var fn decFn
 	var ok bool
 	if useMapForCodecCache {
 		fn, ok = d.f[rtid]
@@ -770,6 +740,10 @@ func (d *Decoder) decodeValue(rv reflect.Value) {
 			fn.f = (*decFnInfo).ext
 		} else if supportBinaryMarshal && fi.ti.unm {
 			fn.f = (*decFnInfo).binaryMarshal
+		} else if xxf := fastDec(rtid); xxf != nil {
+			fn.f = xxf
+			// } else if xxf, xxok := fastpathsDec[rtid]; xxok {
+			// 	fn.f = xxf
 		} else {
 			switch rk := rt.Kind(); rk {
 			case reflect.String:
@@ -828,8 +802,6 @@ func (d *Decoder) decodeValue(rv reflect.Value) {
 		}
 	}
 
-	fn.f(fn.i, rv)
-
 	return
 }
 
@@ -862,169 +834,11 @@ func (d *Decoder) decEmbeddedField(rv reflect.Value, index []int) {
 		}
 		rv = rv.Field(j)
 	}
-	d.decodeValue(rv)
+	d.decodeValue(rv, decFn{})
 }
 
 // --------------------------------------------------
 
-// short circuit functions for common maps and slices
-
-func (d *Decoder) decSliceIntf(v *[]interface{}, currEncodedType valueType, doNotReset bool) {
-	_, containerLenS := decContLens(d.d, currEncodedType)
-	s := *v
-	if s == nil {
-		s = make([]interface{}, containerLenS, containerLenS)
-	} else if containerLenS > cap(s) {
-		if doNotReset {
-			decErr(msgDecCannotExpandArr, cap(s), containerLenS)
-		}
-		s = make([]interface{}, containerLenS, containerLenS)
-		copy(s, *v)
-	} else if containerLenS > len(s) {
-		s = s[:containerLenS]
-	}
-	for j := 0; j < containerLenS; j++ {
-		d.decode(&s[j])
-	}
-	*v = s
-}
-
-func (d *Decoder) decSliceInt64(v *[]int64, currEncodedType valueType, doNotReset bool) {
-	_, containerLenS := decContLens(d.d, currEncodedType)
-	s := *v
-	if s == nil {
-		s = make([]int64, containerLenS, containerLenS)
-	} else if containerLenS > cap(s) {
-		if doNotReset {
-			decErr(msgDecCannotExpandArr, cap(s), containerLenS)
-		}
-		s = make([]int64, containerLenS, containerLenS)
-		copy(s, *v)
-	} else if containerLenS > len(s) {
-		s = s[:containerLenS]
-	}
-	for j := 0; j < containerLenS; j++ {
-		// d.decode(&s[j])
-		d.d.initReadNext()
-		s[j] = d.d.decodeInt(intBitsize)
-	}
-	*v = s
-}
-
-func (d *Decoder) decSliceUint64(v *[]uint64, currEncodedType valueType, doNotReset bool) {
-	_, containerLenS := decContLens(d.d, currEncodedType)
-	s := *v
-	if s == nil {
-		s = make([]uint64, containerLenS, containerLenS)
-	} else if containerLenS > cap(s) {
-		if doNotReset {
-			decErr(msgDecCannotExpandArr, cap(s), containerLenS)
-		}
-		s = make([]uint64, containerLenS, containerLenS)
-		copy(s, *v)
-	} else if containerLenS > len(s) {
-		s = s[:containerLenS]
-	}
-	for j := 0; j < containerLenS; j++ {
-		// d.decode(&s[j])
-		d.d.initReadNext()
-		s[j] = d.d.decodeUint(intBitsize)
-	}
-	*v = s
-}
-
-func (d *Decoder) decSliceStr(v *[]string, currEncodedType valueType, doNotReset bool) {
-	_, containerLenS := decContLens(d.d, currEncodedType)
-	s := *v
-	if s == nil {
-		s = make([]string, containerLenS, containerLenS)
-	} else if containerLenS > cap(s) {
-		if doNotReset {
-			decErr(msgDecCannotExpandArr, cap(s), containerLenS)
-		}
-		s = make([]string, containerLenS, containerLenS)
-		copy(s, *v)
-	} else if containerLenS > len(s) {
-		s = s[:containerLenS]
-	}
-	for j := 0; j < containerLenS; j++ {
-		// d.decode(&s[j])
-		d.d.initReadNext()
-		s[j] = d.d.decodeString()
-	}
-	*v = s
-}
-
-func (d *Decoder) decMapIntfIntf(v *map[interface{}]interface{}) {
-	containerLen := d.d.readMapLen()
-	m := *v
-	if m == nil {
-		m = make(map[interface{}]interface{}, containerLen)
-		*v = m
-	}
-	for j := 0; j < containerLen; j++ {
-		var mk interface{}
-		d.decode(&mk)
-		// special case if a byte array.
-		if bv, bok := mk.([]byte); bok {
-			mk = string(bv)
-		}
-		mv := m[mk]
-		d.decode(&mv)
-		m[mk] = mv
-	}
-}
-
-func (d *Decoder) decMapInt64Intf(v *map[int64]interface{}) {
-	containerLen := d.d.readMapLen()
-	m := *v
-	if m == nil {
-		m = make(map[int64]interface{}, containerLen)
-		*v = m
-	}
-	for j := 0; j < containerLen; j++ {
-		d.d.initReadNext()
-		mk := d.d.decodeInt(intBitsize)
-		mv := m[mk]
-		d.decode(&mv)
-		m[mk] = mv
-	}
-}
-
-func (d *Decoder) decMapUint64Intf(v *map[uint64]interface{}) {
-	containerLen := d.d.readMapLen()
-	m := *v
-	if m == nil {
-		m = make(map[uint64]interface{}, containerLen)
-		*v = m
-	}
-	for j := 0; j < containerLen; j++ {
-		d.d.initReadNext()
-		mk := d.d.decodeUint(intBitsize)
-		mv := m[mk]
-		d.decode(&mv)
-		m[mk] = mv
-	}
-}
-
-func (d *Decoder) decMapStrIntf(v *map[string]interface{}) {
-	containerLen := d.d.readMapLen()
-	m := *v
-	if m == nil {
-		m = make(map[string]interface{}, containerLen)
-		*v = m
-	}
-	for j := 0; j < containerLen; j++ {
-		d.d.initReadNext()
-		mk := d.d.decodeString()
-		mv := m[mk]
-		d.decode(&mv)
-		m[mk] = mv
-	}
-}
-
-// ----------------------------------------
-
 func decContLens(dd decDriver, currEncodedType valueType) (containerLen, containerLenS int) {
 	if currEncodedType == valueTypeInvalid {
 		currEncodedType = dd.currentEncodedType()
@@ -1046,3 +860,11 @@ func decContLens(dd decDriver, currEncodedType valueType) (containerLen, contain
 func decErr(format string, params ...interface{}) {
 	doPanic(msgTagDec, format, params...)
 }
+
+func fastDec(rtid uintptr) func(*decFnInfo, reflect.Value) {
+	// Unfortunately, accessing an empty map is not free free.
+	if fastpathEnabled {
+		return fastpathsDec[rtid]
+	}
+	return nil
+}

+ 68 - 177
codec/encode.go

@@ -37,7 +37,10 @@ const (
 	AsSymbolStructFieldNameFlag
 )
 
-// encWriter abstracting writing to a byte array or to an io.Writer.
+// fastpathsEnc holds the rtid (reflect.Type Pointer) to fast encode function for a selected slice/map type.
+var fastpathsEnc = make(map[uintptr]func(*encFnInfo, reflect.Value))
+
+// encWriter abstracts writing to a byte array or to an io.Writer.
 type encWriter interface {
 	writeUint16(uint16)
 	writeUint32(uint32)
@@ -368,23 +371,6 @@ func (f *encFnInfo) kSlice(rv reflect.Value) {
 		return
 	}
 
-	if shortCircuitReflectToFastPath {
-		switch f.ti.rtid {
-		case intfSliceTypId:
-			f.e.encSliceIntf(rv.Interface().([]interface{}))
-			return
-		case strSliceTypId:
-			f.e.encSliceStr(rv.Interface().([]string))
-			return
-		case uint64SliceTypId:
-			f.e.encSliceUint64(rv.Interface().([]uint64))
-			return
-		case int64SliceTypId:
-			f.e.encSliceInt64(rv.Interface().([]int64))
-			return
-		}
-	}
-
 	// If in this method, then there was no extension function defined.
 	// So it's okay to treat as []byte.
 	if f.ti.rtid == uint8SliceTypId || f.ti.rt.Elem().Kind() == reflect.Uint8 {
@@ -404,9 +390,15 @@ func (f *encFnInfo) kSlice(rv reflect.Value) {
 	if l == 0 {
 		return
 	}
+
+	rtelem := f.ti.rt.Elem()
+	for rtelem.Kind() == reflect.Ptr {
+		rtelem = rtelem.Elem()
+	}
+	fn := f.e.getEncFn(rtelem)
 	for j := 0; j < l; j++ {
 		// TODO: Consider perf implication of encoding odd index values as symbols if type is string
-		f.e.encodeValue(rv.Index(j))
+		f.e.encodeValue(rv.Index(j), fn)
 	}
 }
 
@@ -419,7 +411,8 @@ func (f *encFnInfo) kArray(rv reflect.Value) {
 
 	l := rv.Len()
 	// Handle an array of bytes specially (in line with what is done for slices)
-	if f.ti.rt.Elem().Kind() == reflect.Uint8 {
+	rtelem := f.ti.rt.Elem()
+	if rtelem.Kind() == reflect.Uint8 {
 		if l == 0 {
 			f.ee.encodeStringBytes(c_RAW, nil)
 			return
@@ -448,9 +441,13 @@ func (f *encFnInfo) kArray(rv reflect.Value) {
 	if l == 0 {
 		return
 	}
+	for rtelem.Kind() == reflect.Ptr {
+		rtelem = rtelem.Elem()
+	}
+	fn := f.e.getEncFn(rtelem)
 	for j := 0; j < l; j++ {
 		// TODO: Consider perf implication of encoding odd index values as symbols if type is string
-		f.e.encodeValue(rv.Index(j))
+		f.e.encodeValue(rv.Index(j), fn)
 	}
 }
 
@@ -499,12 +496,12 @@ func (f *encFnInfo) kStruct(rv reflect.Value) {
 			} else {
 				ee.encodeString(c_UTF8, encnames[j])
 			}
-			e.encodeValue(rvals[j])
+			e.encodeValue(rvals[j], encFn{})
 		}
 	} else {
 		f.ee.encodeArrayPreamble(newlen)
 		for j := 0; j < newlen; j++ {
-			e.encodeValue(rvals[j])
+			e.encodeValue(rvals[j], encFn{})
 		}
 	}
 }
@@ -523,7 +520,7 @@ func (f *encFnInfo) kInterface(rv reflect.Value) {
 		f.ee.encodeNil()
 		return
 	}
-	f.e.encodeValue(rv.Elem())
+	f.e.encodeValue(rv.Elem(), encFn{})
 }
 
 func (f *encFnInfo) kMap(rv reflect.Value) {
@@ -532,37 +529,32 @@ func (f *encFnInfo) kMap(rv reflect.Value) {
 		return
 	}
 
-	if shortCircuitReflectToFastPath {
-		switch f.ti.rtid {
-		case mapIntfIntfTypId:
-			f.e.encMapIntfIntf(rv.Interface().(map[interface{}]interface{}))
-			return
-		case mapStrIntfTypId:
-			f.e.encMapStrIntf(rv.Interface().(map[string]interface{}))
-			return
-		case mapStrStrTypId:
-			f.e.encMapStrStr(rv.Interface().(map[string]string))
-			return
-		case mapInt64IntfTypId:
-			f.e.encMapInt64Intf(rv.Interface().(map[int64]interface{}))
-			return
-		case mapUint64IntfTypId:
-			f.e.encMapUint64Intf(rv.Interface().(map[uint64]interface{}))
-			return
-		}
-	}
-
 	l := rv.Len()
 	f.ee.encodeMapPreamble(l)
 	if l == 0 {
 		return
 	}
-	// keyTypeIsString := f.ti.rt.Key().Kind() == reflect.String
-	keyTypeIsString := f.ti.rt.Key() == stringTyp
 	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.
+	var keyFn, valFn encFn
+	rtkey := f.ti.rt.Key()
+	rtval := f.ti.rt.Elem()
+	// keyTypeIsString := f.ti.rt.Key().Kind() == reflect.String
+	var keyTypeIsString = rtkey == stringTyp
 	if keyTypeIsString {
 		asSymbols = f.e.h.AsSymbols&AsSymbolMapStringKeysFlag != 0
+	} else {
+		for rtkey.Kind() == reflect.Ptr {
+			rtkey = rtkey.Elem()
+		}
+		keyFn = f.e.getEncFn(rtkey)
 	}
+	for rtval.Kind() == reflect.Ptr {
+		rtval = rtval.Elem()
+	}
+	valFn = f.e.getEncFn(rtval)
 	mks := rv.MapKeys()
 	// for j, lmks := 0, len(mks); j < lmks; j++ {
 	for j := range mks {
@@ -573,9 +565,9 @@ func (f *encFnInfo) kMap(rv reflect.Value) {
 				f.ee.encodeString(c_UTF8, mks[j].String())
 			}
 		} else {
-			f.e.encodeValue(mks[j])
+			f.e.encodeValue(mks[j], keyFn)
 		}
-		f.e.encodeValue(rv.MapIndex(mks[j]))
+		f.e.encodeValue(rv.MapIndex(mks[j]), valFn)
 	}
 
 }
@@ -706,7 +698,7 @@ func (e *Encoder) encode(iv interface{}) {
 		e.e.encodeNil()
 
 	case reflect.Value:
-		e.encodeValue(v)
+		e.encodeValue(v, encFn{})
 
 	case string:
 		e.e.encodeString(c_UTF8, v)
@@ -737,28 +729,9 @@ func (e *Encoder) encode(iv interface{}) {
 	case float64:
 		e.e.encodeFloat64(v)
 
-	case []interface{}:
-		e.encSliceIntf(v)
-	case []string:
-		e.encSliceStr(v)
-	case []int64:
-		e.encSliceInt64(v)
-	case []uint64:
-		e.encSliceUint64(v)
 	case []uint8:
 		e.e.encodeStringBytes(c_RAW, v)
 
-	case map[interface{}]interface{}:
-		e.encMapIntfIntf(v)
-	case map[string]interface{}:
-		e.encMapStrIntf(v)
-	case map[string]string:
-		e.encMapStrStr(v)
-	case map[int64]interface{}:
-		e.encMapInt64Intf(v)
-	case map[uint64]interface{}:
-		e.encMapUint64Intf(v)
-
 	case *string:
 		e.e.encodeString(c_UTF8, *v)
 	case *bool:
@@ -788,34 +761,16 @@ func (e *Encoder) encode(iv interface{}) {
 	case *float64:
 		e.e.encodeFloat64(*v)
 
-	case *[]interface{}:
-		e.encSliceIntf(*v)
-	case *[]string:
-		e.encSliceStr(*v)
-	case *[]int64:
-		e.encSliceInt64(*v)
-	case *[]uint64:
-		e.encSliceUint64(*v)
 	case *[]uint8:
 		e.e.encodeStringBytes(c_RAW, *v)
 
-	case *map[interface{}]interface{}:
-		e.encMapIntfIntf(*v)
-	case *map[string]interface{}:
-		e.encMapStrIntf(*v)
-	case *map[string]string:
-		e.encMapStrStr(*v)
-	case *map[int64]interface{}:
-		e.encMapInt64Intf(*v)
-	case *map[uint64]interface{}:
-		e.encMapUint64Intf(*v)
-
 	default:
-		e.encodeValue(reflect.ValueOf(iv))
+		e.encodeValue(reflect.ValueOf(iv), encFn{})
 	}
 }
 
-func (e *Encoder) encodeValue(rv reflect.Value) {
+func (e *Encoder) encodeValue(rv reflect.Value, fn encFn) {
+	// if a valid fn is passed, it MUST BE for the dereferenced type of rv
 	for rv.Kind() == reflect.Ptr {
 		if rv.IsNil() {
 			e.e.encodeNil()
@@ -824,15 +779,22 @@ func (e *Encoder) encodeValue(rv reflect.Value) {
 		rv = rv.Elem()
 	}
 
-	rt := rv.Type()
-	rtid := reflect.ValueOf(rt).Pointer()
+	if fn.i == nil {
+		fn = e.getEncFn(rv.Type())
+	}
+	fn.f(fn.i, rv)
+}
 
+func (e *Encoder) getEncFn(rt reflect.Type) (fn encFn) {
 	// if e.f == nil && e.s == nil { debugf("---->Creating new enc f map for type: %v\n", rt) }
-	var fn encFn
+	rtid := reflect.ValueOf(rt).Pointer()
 	var ok bool
 	if useMapForCodecCache {
 		fn, ok = e.f[rtid]
 	} else {
+		// if len(e.x) > 0 && len(e.x)%10 == 0 {
+		// 	println("len(e.x) ", len(e.x))
+		// }
 		for i, v := range e.x {
 			if v == rtid {
 				fn, ok = e.s[i], true
@@ -853,6 +815,10 @@ func (e *Encoder) encodeValue(rv reflect.Value) {
 			fn.f = (*encFnInfo).ext
 		} else if supportBinaryMarshal && fi.ti.m {
 			fn.f = (*encFnInfo).binaryMarshal
+		} else if xxf := fastEnc(rtid); xxf != nil {
+			fn.f = xxf
+			// } else if xxf, xxok := fastpathsEnc[rtid]; xxok {
+			// 	fn.f = xxf
 		} else {
 			switch rk := rt.Kind(); rk {
 			case reflect.Bool:
@@ -887,7 +853,7 @@ func (e *Encoder) encodeValue(rv reflect.Value) {
 		}
 		if useMapForCodecCache {
 			if e.f == nil {
-				e.f = make(map[uintptr]encFn, 16)
+				e.f = make(map[uintptr]encFn, 64)
 			}
 			e.f[rtid] = fn
 		} else {
@@ -895,9 +861,7 @@ func (e *Encoder) encodeValue(rv reflect.Value) {
 			e.x = append(e.x, rtid)
 		}
 	}
-
-	fn.f(fn.i, rv)
-
+	return
 }
 
 func (e *Encoder) encRawExt(re RawExt) {
@@ -913,89 +877,16 @@ func (e *Encoder) encRawExt(re RawExt) {
 	}
 }
 
-// ---------------------------------------------
-// short circuit functions for common maps and slices
-
-func (e *Encoder) encSliceIntf(v []interface{}) {
-	e.e.encodeArrayPreamble(len(v))
-	for _, v2 := range v {
-		e.encode(v2)
-	}
-}
-
-func (e *Encoder) encSliceStr(v []string) {
-	e.e.encodeArrayPreamble(len(v))
-	for _, v2 := range v {
-		e.e.encodeString(c_UTF8, v2)
-	}
-}
-
-func (e *Encoder) encSliceInt64(v []int64) {
-	e.e.encodeArrayPreamble(len(v))
-	for _, v2 := range v {
-		e.e.encodeInt(v2)
-	}
-}
-
-func (e *Encoder) encSliceUint64(v []uint64) {
-	e.e.encodeArrayPreamble(len(v))
-	for _, v2 := range v {
-		e.e.encodeUint(v2)
-	}
-}
-
-func (e *Encoder) encMapStrStr(v map[string]string) {
-	e.e.encodeMapPreamble(len(v))
-	asSymbols := e.h.AsSymbols&AsSymbolMapStringKeysFlag != 0
-	for k2, v2 := range v {
-		if asSymbols {
-			e.e.encodeSymbol(k2)
-		} else {
-			e.e.encodeString(c_UTF8, k2)
-		}
-		e.e.encodeString(c_UTF8, v2)
-	}
-}
-
-func (e *Encoder) encMapStrIntf(v map[string]interface{}) {
-	e.e.encodeMapPreamble(len(v))
-	asSymbols := e.h.AsSymbols&AsSymbolMapStringKeysFlag != 0
-	for k2, v2 := range v {
-		if asSymbols {
-			e.e.encodeSymbol(k2)
-		} else {
-			e.e.encodeString(c_UTF8, k2)
-		}
-		e.encode(v2)
-	}
-}
-
-func (e *Encoder) encMapInt64Intf(v map[int64]interface{}) {
-	e.e.encodeMapPreamble(len(v))
-	for k2, v2 := range v {
-		e.e.encodeInt(k2)
-		e.encode(v2)
-	}
-}
-
-func (e *Encoder) encMapUint64Intf(v map[uint64]interface{}) {
-	e.e.encodeMapPreamble(len(v))
-	for k2, v2 := range v {
-		e.e.encodeUint(uint64(k2))
-		e.encode(v2)
-	}
-}
-
-func (e *Encoder) encMapIntfIntf(v map[interface{}]interface{}) {
-	e.e.encodeMapPreamble(len(v))
-	for k2, v2 := range v {
-		e.encode(k2)
-		e.encode(v2)
-	}
-}
-
 // ----------------------------------------
 
 func encErr(format string, params ...interface{}) {
 	doPanic(msgTagEnc, format, params...)
 }
+
+func fastEnc(rtid uintptr) func(*encFnInfo, reflect.Value) {
+	// Unfortunately, accessing an empty map is not free free.
+	if fastpathEnabled {
+		return fastpathsEnc[rtid]
+	}
+	return nil
+}

+ 1 - 1
codec/ext_dep_test.go

@@ -1,4 +1,4 @@
-// //+build ignore
+//+build ignore
 
 // Copyright (c) 2012, 2013 Ugorji Nwoke. All rights reserved.
 // Use of this source code is governed by a BSD-style license found in the LICENSE file.

+ 2287 - 0
codec/fast-path.go

@@ -0,0 +1,2287 @@
+// Copyright (c) 2012, 2013 Ugorji Nwoke. All rights reserved.
+// Use of this source code is governed by a BSD-style license found in the LICENSE file.
+
+// ************************************************************
+// DO NOT EDIT.
+// THIS FILE IS GENERATED BY RUNNING: go run gen-fast-path.go
+// ************************************************************
+
+package codec
+
+// Fast path functions try to create a fast path encode or decode implementation
+// for common maps and slices.
+//
+// We define the functions and register then in this single file
+// so as not to pollute the encode.go and decode.go, and create a dependency in there.
+// This file can be omitted without causing a build failure.
+//
+// The advantage of fast paths is:
+//    - Many calls bypass reflection altogether
+//
+// Currently support
+//    - slice of all builtin types,
+//    - map of all builtin types to string or interface value
+//    - symetrical maps of all builtin types (e.g. str-str, uint8-uint8)
+// This should provide adequate "typical" implementations.
+
+import (
+	"reflect"
+)
+
+func init() {
+	if !fastpathEnabled {
+		return // basically disable the fast path checks (since accessing empty map is basically free)
+	}
+	fdx := func(i interface{}, fd func(*decFnInfo, reflect.Value)) {
+		fastpathsDec[reflect.ValueOf(reflect.TypeOf(i)).Pointer()] = fd
+	}
+	fex := func(i interface{}, fe func(*encFnInfo, reflect.Value)) {
+		fastpathsEnc[reflect.ValueOf(reflect.TypeOf(i)).Pointer()] = fe
+	}
+
+	fex([]interface{}(nil), (*encFnInfo).fastEncSliceIntf)
+	fex([]string(nil), (*encFnInfo).fastEncSliceString)
+	fex([]float32(nil), (*encFnInfo).fastEncSliceFloat32)
+	fex([]float64(nil), (*encFnInfo).fastEncSliceFloat64)
+	fex([]uint(nil), (*encFnInfo).fastEncSliceUint)
+	fex([]uint16(nil), (*encFnInfo).fastEncSliceUint16)
+	fex([]uint32(nil), (*encFnInfo).fastEncSliceUint32)
+	fex([]uint64(nil), (*encFnInfo).fastEncSliceUint64)
+	fex([]int(nil), (*encFnInfo).fastEncSliceInt)
+	fex([]int8(nil), (*encFnInfo).fastEncSliceInt8)
+	fex([]int16(nil), (*encFnInfo).fastEncSliceInt16)
+	fex([]int32(nil), (*encFnInfo).fastEncSliceInt32)
+	fex([]int64(nil), (*encFnInfo).fastEncSliceInt64)
+	fex([]bool(nil), (*encFnInfo).fastEncSliceBool)
+
+	fex(map[interface{}]interface{}(nil), (*encFnInfo).fastEncMapIntfIntf)
+	fex(map[interface{}]string(nil), (*encFnInfo).fastEncMapIntfString)
+	fex(map[string]interface{}(nil), (*encFnInfo).fastEncMapStringIntf)
+	fex(map[string]string(nil), (*encFnInfo).fastEncMapStringString)
+	fex(map[float32]interface{}(nil), (*encFnInfo).fastEncMapFloat32Intf)
+	fex(map[float32]string(nil), (*encFnInfo).fastEncMapFloat32String)
+	fex(map[float32]float32(nil), (*encFnInfo).fastEncMapFloat32Float32)
+	fex(map[float64]interface{}(nil), (*encFnInfo).fastEncMapFloat64Intf)
+	fex(map[float64]string(nil), (*encFnInfo).fastEncMapFloat64String)
+	fex(map[float64]float64(nil), (*encFnInfo).fastEncMapFloat64Float64)
+	fex(map[uint]interface{}(nil), (*encFnInfo).fastEncMapUintIntf)
+	fex(map[uint]string(nil), (*encFnInfo).fastEncMapUintString)
+	fex(map[uint]uint(nil), (*encFnInfo).fastEncMapUintUint)
+	fex(map[uint8]interface{}(nil), (*encFnInfo).fastEncMapUint8Intf)
+	fex(map[uint8]string(nil), (*encFnInfo).fastEncMapUint8String)
+	fex(map[uint8]uint8(nil), (*encFnInfo).fastEncMapUint8Uint8)
+	fex(map[uint16]interface{}(nil), (*encFnInfo).fastEncMapUint16Intf)
+	fex(map[uint16]string(nil), (*encFnInfo).fastEncMapUint16String)
+	fex(map[uint16]uint16(nil), (*encFnInfo).fastEncMapUint16Uint16)
+	fex(map[uint32]interface{}(nil), (*encFnInfo).fastEncMapUint32Intf)
+	fex(map[uint32]string(nil), (*encFnInfo).fastEncMapUint32String)
+	fex(map[uint32]uint32(nil), (*encFnInfo).fastEncMapUint32Uint32)
+	fex(map[uint64]interface{}(nil), (*encFnInfo).fastEncMapUint64Intf)
+	fex(map[uint64]string(nil), (*encFnInfo).fastEncMapUint64String)
+	fex(map[uint64]uint64(nil), (*encFnInfo).fastEncMapUint64Uint64)
+	fex(map[int]interface{}(nil), (*encFnInfo).fastEncMapIntIntf)
+	fex(map[int]string(nil), (*encFnInfo).fastEncMapIntString)
+	fex(map[int]int(nil), (*encFnInfo).fastEncMapIntInt)
+	fex(map[int8]interface{}(nil), (*encFnInfo).fastEncMapInt8Intf)
+	fex(map[int8]string(nil), (*encFnInfo).fastEncMapInt8String)
+	fex(map[int8]int8(nil), (*encFnInfo).fastEncMapInt8Int8)
+	fex(map[int16]interface{}(nil), (*encFnInfo).fastEncMapInt16Intf)
+	fex(map[int16]string(nil), (*encFnInfo).fastEncMapInt16String)
+	fex(map[int16]int16(nil), (*encFnInfo).fastEncMapInt16Int16)
+	fex(map[int32]interface{}(nil), (*encFnInfo).fastEncMapInt32Intf)
+	fex(map[int32]string(nil), (*encFnInfo).fastEncMapInt32String)
+	fex(map[int32]int32(nil), (*encFnInfo).fastEncMapInt32Int32)
+	fex(map[int64]interface{}(nil), (*encFnInfo).fastEncMapInt64Intf)
+	fex(map[int64]string(nil), (*encFnInfo).fastEncMapInt64String)
+	fex(map[int64]int64(nil), (*encFnInfo).fastEncMapInt64Int64)
+	fex(map[bool]interface{}(nil), (*encFnInfo).fastEncMapBoolIntf)
+	fex(map[bool]string(nil), (*encFnInfo).fastEncMapBoolString)
+	fex(map[bool]bool(nil), (*encFnInfo).fastEncMapBoolBool)
+
+	fdx([]interface{}(nil), (*decFnInfo).fastDecSliceIntf)
+	fdx([]string(nil), (*decFnInfo).fastDecSliceString)
+	fdx([]float32(nil), (*decFnInfo).fastDecSliceFloat32)
+	fdx([]float64(nil), (*decFnInfo).fastDecSliceFloat64)
+	fdx([]uint(nil), (*decFnInfo).fastDecSliceUint)
+	fdx([]uint16(nil), (*decFnInfo).fastDecSliceUint16)
+	fdx([]uint32(nil), (*decFnInfo).fastDecSliceUint32)
+	fdx([]uint64(nil), (*decFnInfo).fastDecSliceUint64)
+	fdx([]int(nil), (*decFnInfo).fastDecSliceInt)
+	fdx([]int8(nil), (*decFnInfo).fastDecSliceInt8)
+	fdx([]int16(nil), (*decFnInfo).fastDecSliceInt16)
+	fdx([]int32(nil), (*decFnInfo).fastDecSliceInt32)
+	fdx([]int64(nil), (*decFnInfo).fastDecSliceInt64)
+	fdx([]bool(nil), (*decFnInfo).fastDecSliceBool)
+
+	fdx(map[interface{}]interface{}(nil), (*decFnInfo).fastDecMapIntfIntf)
+	fdx(map[interface{}]string(nil), (*decFnInfo).fastDecMapIntfString)
+	fdx(map[string]interface{}(nil), (*decFnInfo).fastDecMapStringIntf)
+	fdx(map[string]string(nil), (*decFnInfo).fastDecMapStringString)
+	fdx(map[float32]interface{}(nil), (*decFnInfo).fastDecMapFloat32Intf)
+	fdx(map[float32]string(nil), (*decFnInfo).fastDecMapFloat32String)
+	fdx(map[float32]float32(nil), (*decFnInfo).fastDecMapFloat32Float32)
+	fdx(map[float64]interface{}(nil), (*decFnInfo).fastDecMapFloat64Intf)
+	fdx(map[float64]string(nil), (*decFnInfo).fastDecMapFloat64String)
+	fdx(map[float64]float64(nil), (*decFnInfo).fastDecMapFloat64Float64)
+	fdx(map[uint]interface{}(nil), (*decFnInfo).fastDecMapUintIntf)
+	fdx(map[uint]string(nil), (*decFnInfo).fastDecMapUintString)
+	fdx(map[uint]uint(nil), (*decFnInfo).fastDecMapUintUint)
+	fdx(map[uint8]interface{}(nil), (*decFnInfo).fastDecMapUint8Intf)
+	fdx(map[uint8]string(nil), (*decFnInfo).fastDecMapUint8String)
+	fdx(map[uint8]uint8(nil), (*decFnInfo).fastDecMapUint8Uint8)
+	fdx(map[uint16]interface{}(nil), (*decFnInfo).fastDecMapUint16Intf)
+	fdx(map[uint16]string(nil), (*decFnInfo).fastDecMapUint16String)
+	fdx(map[uint16]uint16(nil), (*decFnInfo).fastDecMapUint16Uint16)
+	fdx(map[uint32]interface{}(nil), (*decFnInfo).fastDecMapUint32Intf)
+	fdx(map[uint32]string(nil), (*decFnInfo).fastDecMapUint32String)
+	fdx(map[uint32]uint32(nil), (*decFnInfo).fastDecMapUint32Uint32)
+	fdx(map[uint64]interface{}(nil), (*decFnInfo).fastDecMapUint64Intf)
+	fdx(map[uint64]string(nil), (*decFnInfo).fastDecMapUint64String)
+	fdx(map[uint64]uint64(nil), (*decFnInfo).fastDecMapUint64Uint64)
+	fdx(map[int]interface{}(nil), (*decFnInfo).fastDecMapIntIntf)
+	fdx(map[int]string(nil), (*decFnInfo).fastDecMapIntString)
+	fdx(map[int]int(nil), (*decFnInfo).fastDecMapIntInt)
+	fdx(map[int8]interface{}(nil), (*decFnInfo).fastDecMapInt8Intf)
+	fdx(map[int8]string(nil), (*decFnInfo).fastDecMapInt8String)
+	fdx(map[int8]int8(nil), (*decFnInfo).fastDecMapInt8Int8)
+	fdx(map[int16]interface{}(nil), (*decFnInfo).fastDecMapInt16Intf)
+	fdx(map[int16]string(nil), (*decFnInfo).fastDecMapInt16String)
+	fdx(map[int16]int16(nil), (*decFnInfo).fastDecMapInt16Int16)
+	fdx(map[int32]interface{}(nil), (*decFnInfo).fastDecMapInt32Intf)
+	fdx(map[int32]string(nil), (*decFnInfo).fastDecMapInt32String)
+	fdx(map[int32]int32(nil), (*decFnInfo).fastDecMapInt32Int32)
+	fdx(map[int64]interface{}(nil), (*decFnInfo).fastDecMapInt64Intf)
+	fdx(map[int64]string(nil), (*decFnInfo).fastDecMapInt64String)
+	fdx(map[int64]int64(nil), (*decFnInfo).fastDecMapInt64Int64)
+	fdx(map[bool]interface{}(nil), (*decFnInfo).fastDecMapBoolIntf)
+	fdx(map[bool]string(nil), (*decFnInfo).fastDecMapBoolString)
+	fdx(map[bool]bool(nil), (*decFnInfo).fastDecMapBoolBool)
+
+}
+
+// -- encode
+
+func (f *encFnInfo) fastEncSliceIntf(rv reflect.Value) {
+	v := rv.Interface().([]interface{})
+	f.ee.encodeArrayPreamble(len(v))
+	for _, v2 := range v {
+		f.e.encode(v2)
+	}
+}
+
+func (f *encFnInfo) fastEncSliceString(rv reflect.Value) {
+	v := rv.Interface().([]string)
+	f.ee.encodeArrayPreamble(len(v))
+	for _, v2 := range v {
+		f.ee.encodeString(c_UTF8, v2)
+	}
+}
+
+func (f *encFnInfo) fastEncSliceFloat32(rv reflect.Value) {
+	v := rv.Interface().([]float32)
+	f.ee.encodeArrayPreamble(len(v))
+	for _, v2 := range v {
+		f.ee.encodeFloat32(v2)
+	}
+}
+
+func (f *encFnInfo) fastEncSliceFloat64(rv reflect.Value) {
+	v := rv.Interface().([]float64)
+	f.ee.encodeArrayPreamble(len(v))
+	for _, v2 := range v {
+		f.ee.encodeFloat64(v2)
+	}
+}
+
+func (f *encFnInfo) fastEncSliceUint(rv reflect.Value) {
+	v := rv.Interface().([]uint)
+	f.ee.encodeArrayPreamble(len(v))
+	for _, v2 := range v {
+		f.ee.encodeUint(uint64(v2))
+	}
+}
+
+func (f *encFnInfo) fastEncSliceUint16(rv reflect.Value) {
+	v := rv.Interface().([]uint16)
+	f.ee.encodeArrayPreamble(len(v))
+	for _, v2 := range v {
+		f.ee.encodeUint(uint64(v2))
+	}
+}
+
+func (f *encFnInfo) fastEncSliceUint32(rv reflect.Value) {
+	v := rv.Interface().([]uint32)
+	f.ee.encodeArrayPreamble(len(v))
+	for _, v2 := range v {
+		f.e.encode(v2)
+	}
+}
+
+func (f *encFnInfo) fastEncSliceUint64(rv reflect.Value) {
+	v := rv.Interface().([]uint64)
+	f.ee.encodeArrayPreamble(len(v))
+	for _, v2 := range v {
+		f.ee.encodeUint(uint64(v2))
+	}
+}
+
+func (f *encFnInfo) fastEncSliceInt(rv reflect.Value) {
+	v := rv.Interface().([]int)
+	f.ee.encodeArrayPreamble(len(v))
+	for _, v2 := range v {
+		f.ee.encodeInt(int64(v2))
+	}
+}
+
+func (f *encFnInfo) fastEncSliceInt8(rv reflect.Value) {
+	v := rv.Interface().([]int8)
+	f.ee.encodeArrayPreamble(len(v))
+	for _, v2 := range v {
+		f.ee.encodeInt(int64(v2))
+	}
+}
+
+func (f *encFnInfo) fastEncSliceInt16(rv reflect.Value) {
+	v := rv.Interface().([]int16)
+	f.ee.encodeArrayPreamble(len(v))
+	for _, v2 := range v {
+		f.ee.encodeInt(int64(v2))
+	}
+}
+
+func (f *encFnInfo) fastEncSliceInt32(rv reflect.Value) {
+	v := rv.Interface().([]int32)
+	f.ee.encodeArrayPreamble(len(v))
+	for _, v2 := range v {
+		f.e.encode(v2)
+	}
+}
+
+func (f *encFnInfo) fastEncSliceInt64(rv reflect.Value) {
+	v := rv.Interface().([]int64)
+	f.ee.encodeArrayPreamble(len(v))
+	for _, v2 := range v {
+		f.ee.encodeInt(int64(v2))
+	}
+}
+
+func (f *encFnInfo) fastEncSliceBool(rv reflect.Value) {
+	v := rv.Interface().([]bool)
+	f.ee.encodeArrayPreamble(len(v))
+	for _, v2 := range v {
+		f.ee.encodeBool(v2)
+	}
+}
+
+func (f *encFnInfo) fastEncMapIntfIntf(rv reflect.Value) {
+	v := rv.Interface().(map[interface{}]interface{})
+	f.ee.encodeMapPreamble(len(v))
+
+	for k2, v2 := range v {
+		f.e.encode(k2)
+		f.e.encode(v2)
+	}
+}
+
+func (f *encFnInfo) fastEncMapIntfString(rv reflect.Value) {
+	v := rv.Interface().(map[interface{}]string)
+	f.ee.encodeMapPreamble(len(v))
+
+	for k2, v2 := range v {
+		f.e.encode(k2)
+		f.ee.encodeString(c_UTF8, v2)
+	}
+}
+
+func (f *encFnInfo) fastEncMapStringIntf(rv reflect.Value) {
+	v := rv.Interface().(map[string]interface{})
+	f.ee.encodeMapPreamble(len(v))
+	asSymbols := f.e.h.AsSymbols&AsSymbolMapStringKeysFlag != 0
+	for k2, v2 := range v {
+		if asSymbols {
+			f.ee.encodeSymbol(k2)
+		} else {
+			f.ee.encodeString(c_UTF8, k2)
+		}
+		f.e.encode(v2)
+	}
+}
+
+func (f *encFnInfo) fastEncMapStringString(rv reflect.Value) {
+	v := rv.Interface().(map[string]string)
+	f.ee.encodeMapPreamble(len(v))
+	asSymbols := f.e.h.AsSymbols&AsSymbolMapStringKeysFlag != 0
+	for k2, v2 := range v {
+		if asSymbols {
+			f.ee.encodeSymbol(k2)
+		} else {
+			f.ee.encodeString(c_UTF8, k2)
+		}
+		f.ee.encodeString(c_UTF8, v2)
+	}
+}
+
+func (f *encFnInfo) fastEncMapFloat32Intf(rv reflect.Value) {
+	v := rv.Interface().(map[float32]interface{})
+	f.ee.encodeMapPreamble(len(v))
+
+	for k2, v2 := range v {
+		f.ee.encodeFloat32(k2)
+		f.e.encode(v2)
+	}
+}
+
+func (f *encFnInfo) fastEncMapFloat32String(rv reflect.Value) {
+	v := rv.Interface().(map[float32]string)
+	f.ee.encodeMapPreamble(len(v))
+
+	for k2, v2 := range v {
+		f.ee.encodeFloat32(k2)
+		f.ee.encodeString(c_UTF8, v2)
+	}
+}
+
+func (f *encFnInfo) fastEncMapFloat32Float32(rv reflect.Value) {
+	v := rv.Interface().(map[float32]float32)
+	f.ee.encodeMapPreamble(len(v))
+
+	for k2, v2 := range v {
+		f.ee.encodeFloat32(k2)
+		f.ee.encodeFloat32(v2)
+	}
+}
+
+func (f *encFnInfo) fastEncMapFloat64Intf(rv reflect.Value) {
+	v := rv.Interface().(map[float64]interface{})
+	f.ee.encodeMapPreamble(len(v))
+
+	for k2, v2 := range v {
+		f.ee.encodeFloat64(k2)
+		f.e.encode(v2)
+	}
+}
+
+func (f *encFnInfo) fastEncMapFloat64String(rv reflect.Value) {
+	v := rv.Interface().(map[float64]string)
+	f.ee.encodeMapPreamble(len(v))
+
+	for k2, v2 := range v {
+		f.ee.encodeFloat64(k2)
+		f.ee.encodeString(c_UTF8, v2)
+	}
+}
+
+func (f *encFnInfo) fastEncMapFloat64Float64(rv reflect.Value) {
+	v := rv.Interface().(map[float64]float64)
+	f.ee.encodeMapPreamble(len(v))
+
+	for k2, v2 := range v {
+		f.ee.encodeFloat64(k2)
+		f.ee.encodeFloat64(v2)
+	}
+}
+
+func (f *encFnInfo) fastEncMapUintIntf(rv reflect.Value) {
+	v := rv.Interface().(map[uint]interface{})
+	f.ee.encodeMapPreamble(len(v))
+
+	for k2, v2 := range v {
+		f.ee.encodeUint(uint64(k2))
+		f.e.encode(v2)
+	}
+}
+
+func (f *encFnInfo) fastEncMapUintString(rv reflect.Value) {
+	v := rv.Interface().(map[uint]string)
+	f.ee.encodeMapPreamble(len(v))
+
+	for k2, v2 := range v {
+		f.ee.encodeUint(uint64(k2))
+		f.ee.encodeString(c_UTF8, v2)
+	}
+}
+
+func (f *encFnInfo) fastEncMapUintUint(rv reflect.Value) {
+	v := rv.Interface().(map[uint]uint)
+	f.ee.encodeMapPreamble(len(v))
+
+	for k2, v2 := range v {
+		f.ee.encodeUint(uint64(k2))
+		f.ee.encodeUint(uint64(v2))
+	}
+}
+
+func (f *encFnInfo) fastEncMapUint8Intf(rv reflect.Value) {
+	v := rv.Interface().(map[uint8]interface{})
+	f.ee.encodeMapPreamble(len(v))
+
+	for k2, v2 := range v {
+		f.ee.encodeUint(uint64(k2))
+		f.e.encode(v2)
+	}
+}
+
+func (f *encFnInfo) fastEncMapUint8String(rv reflect.Value) {
+	v := rv.Interface().(map[uint8]string)
+	f.ee.encodeMapPreamble(len(v))
+
+	for k2, v2 := range v {
+		f.ee.encodeUint(uint64(k2))
+		f.ee.encodeString(c_UTF8, v2)
+	}
+}
+
+func (f *encFnInfo) fastEncMapUint8Uint8(rv reflect.Value) {
+	v := rv.Interface().(map[uint8]uint8)
+	f.ee.encodeMapPreamble(len(v))
+
+	for k2, v2 := range v {
+		f.ee.encodeUint(uint64(k2))
+		f.ee.encodeUint(uint64(v2))
+	}
+}
+
+func (f *encFnInfo) fastEncMapUint16Intf(rv reflect.Value) {
+	v := rv.Interface().(map[uint16]interface{})
+	f.ee.encodeMapPreamble(len(v))
+
+	for k2, v2 := range v {
+		f.ee.encodeUint(uint64(k2))
+		f.e.encode(v2)
+	}
+}
+
+func (f *encFnInfo) fastEncMapUint16String(rv reflect.Value) {
+	v := rv.Interface().(map[uint16]string)
+	f.ee.encodeMapPreamble(len(v))
+
+	for k2, v2 := range v {
+		f.ee.encodeUint(uint64(k2))
+		f.ee.encodeString(c_UTF8, v2)
+	}
+}
+
+func (f *encFnInfo) fastEncMapUint16Uint16(rv reflect.Value) {
+	v := rv.Interface().(map[uint16]uint16)
+	f.ee.encodeMapPreamble(len(v))
+
+	for k2, v2 := range v {
+		f.ee.encodeUint(uint64(k2))
+		f.ee.encodeUint(uint64(v2))
+	}
+}
+
+func (f *encFnInfo) fastEncMapUint32Intf(rv reflect.Value) {
+	v := rv.Interface().(map[uint32]interface{})
+	f.ee.encodeMapPreamble(len(v))
+
+	for k2, v2 := range v {
+		f.e.encode(k2)
+		f.e.encode(v2)
+	}
+}
+
+func (f *encFnInfo) fastEncMapUint32String(rv reflect.Value) {
+	v := rv.Interface().(map[uint32]string)
+	f.ee.encodeMapPreamble(len(v))
+
+	for k2, v2 := range v {
+		f.e.encode(k2)
+		f.ee.encodeString(c_UTF8, v2)
+	}
+}
+
+func (f *encFnInfo) fastEncMapUint32Uint32(rv reflect.Value) {
+	v := rv.Interface().(map[uint32]uint32)
+	f.ee.encodeMapPreamble(len(v))
+
+	for k2, v2 := range v {
+		f.e.encode(k2)
+		f.e.encode(v2)
+	}
+}
+
+func (f *encFnInfo) fastEncMapUint64Intf(rv reflect.Value) {
+	v := rv.Interface().(map[uint64]interface{})
+	f.ee.encodeMapPreamble(len(v))
+
+	for k2, v2 := range v {
+		f.ee.encodeUint(uint64(k2))
+		f.e.encode(v2)
+	}
+}
+
+func (f *encFnInfo) fastEncMapUint64String(rv reflect.Value) {
+	v := rv.Interface().(map[uint64]string)
+	f.ee.encodeMapPreamble(len(v))
+
+	for k2, v2 := range v {
+		f.ee.encodeUint(uint64(k2))
+		f.ee.encodeString(c_UTF8, v2)
+	}
+}
+
+func (f *encFnInfo) fastEncMapUint64Uint64(rv reflect.Value) {
+	v := rv.Interface().(map[uint64]uint64)
+	f.ee.encodeMapPreamble(len(v))
+
+	for k2, v2 := range v {
+		f.ee.encodeUint(uint64(k2))
+		f.ee.encodeUint(uint64(v2))
+	}
+}
+
+func (f *encFnInfo) fastEncMapIntIntf(rv reflect.Value) {
+	v := rv.Interface().(map[int]interface{})
+	f.ee.encodeMapPreamble(len(v))
+
+	for k2, v2 := range v {
+		f.ee.encodeInt(int64(k2))
+		f.e.encode(v2)
+	}
+}
+
+func (f *encFnInfo) fastEncMapIntString(rv reflect.Value) {
+	v := rv.Interface().(map[int]string)
+	f.ee.encodeMapPreamble(len(v))
+
+	for k2, v2 := range v {
+		f.ee.encodeInt(int64(k2))
+		f.ee.encodeString(c_UTF8, v2)
+	}
+}
+
+func (f *encFnInfo) fastEncMapIntInt(rv reflect.Value) {
+	v := rv.Interface().(map[int]int)
+	f.ee.encodeMapPreamble(len(v))
+
+	for k2, v2 := range v {
+		f.ee.encodeInt(int64(k2))
+		f.ee.encodeInt(int64(v2))
+	}
+}
+
+func (f *encFnInfo) fastEncMapInt8Intf(rv reflect.Value) {
+	v := rv.Interface().(map[int8]interface{})
+	f.ee.encodeMapPreamble(len(v))
+
+	for k2, v2 := range v {
+		f.ee.encodeInt(int64(k2))
+		f.e.encode(v2)
+	}
+}
+
+func (f *encFnInfo) fastEncMapInt8String(rv reflect.Value) {
+	v := rv.Interface().(map[int8]string)
+	f.ee.encodeMapPreamble(len(v))
+
+	for k2, v2 := range v {
+		f.ee.encodeInt(int64(k2))
+		f.ee.encodeString(c_UTF8, v2)
+	}
+}
+
+func (f *encFnInfo) fastEncMapInt8Int8(rv reflect.Value) {
+	v := rv.Interface().(map[int8]int8)
+	f.ee.encodeMapPreamble(len(v))
+
+	for k2, v2 := range v {
+		f.ee.encodeInt(int64(k2))
+		f.ee.encodeInt(int64(v2))
+	}
+}
+
+func (f *encFnInfo) fastEncMapInt16Intf(rv reflect.Value) {
+	v := rv.Interface().(map[int16]interface{})
+	f.ee.encodeMapPreamble(len(v))
+
+	for k2, v2 := range v {
+		f.ee.encodeInt(int64(k2))
+		f.e.encode(v2)
+	}
+}
+
+func (f *encFnInfo) fastEncMapInt16String(rv reflect.Value) {
+	v := rv.Interface().(map[int16]string)
+	f.ee.encodeMapPreamble(len(v))
+
+	for k2, v2 := range v {
+		f.ee.encodeInt(int64(k2))
+		f.ee.encodeString(c_UTF8, v2)
+	}
+}
+
+func (f *encFnInfo) fastEncMapInt16Int16(rv reflect.Value) {
+	v := rv.Interface().(map[int16]int16)
+	f.ee.encodeMapPreamble(len(v))
+
+	for k2, v2 := range v {
+		f.ee.encodeInt(int64(k2))
+		f.ee.encodeInt(int64(v2))
+	}
+}
+
+func (f *encFnInfo) fastEncMapInt32Intf(rv reflect.Value) {
+	v := rv.Interface().(map[int32]interface{})
+	f.ee.encodeMapPreamble(len(v))
+
+	for k2, v2 := range v {
+		f.e.encode(k2)
+		f.e.encode(v2)
+	}
+}
+
+func (f *encFnInfo) fastEncMapInt32String(rv reflect.Value) {
+	v := rv.Interface().(map[int32]string)
+	f.ee.encodeMapPreamble(len(v))
+
+	for k2, v2 := range v {
+		f.e.encode(k2)
+		f.ee.encodeString(c_UTF8, v2)
+	}
+}
+
+func (f *encFnInfo) fastEncMapInt32Int32(rv reflect.Value) {
+	v := rv.Interface().(map[int32]int32)
+	f.ee.encodeMapPreamble(len(v))
+
+	for k2, v2 := range v {
+		f.e.encode(k2)
+		f.e.encode(v2)
+	}
+}
+
+func (f *encFnInfo) fastEncMapInt64Intf(rv reflect.Value) {
+	v := rv.Interface().(map[int64]interface{})
+	f.ee.encodeMapPreamble(len(v))
+
+	for k2, v2 := range v {
+		f.ee.encodeInt(int64(k2))
+		f.e.encode(v2)
+	}
+}
+
+func (f *encFnInfo) fastEncMapInt64String(rv reflect.Value) {
+	v := rv.Interface().(map[int64]string)
+	f.ee.encodeMapPreamble(len(v))
+
+	for k2, v2 := range v {
+		f.ee.encodeInt(int64(k2))
+		f.ee.encodeString(c_UTF8, v2)
+	}
+}
+
+func (f *encFnInfo) fastEncMapInt64Int64(rv reflect.Value) {
+	v := rv.Interface().(map[int64]int64)
+	f.ee.encodeMapPreamble(len(v))
+
+	for k2, v2 := range v {
+		f.ee.encodeInt(int64(k2))
+		f.ee.encodeInt(int64(v2))
+	}
+}
+
+func (f *encFnInfo) fastEncMapBoolIntf(rv reflect.Value) {
+	v := rv.Interface().(map[bool]interface{})
+	f.ee.encodeMapPreamble(len(v))
+
+	for k2, v2 := range v {
+		f.ee.encodeBool(k2)
+		f.e.encode(v2)
+	}
+}
+
+func (f *encFnInfo) fastEncMapBoolString(rv reflect.Value) {
+	v := rv.Interface().(map[bool]string)
+	f.ee.encodeMapPreamble(len(v))
+
+	for k2, v2 := range v {
+		f.ee.encodeBool(k2)
+		f.ee.encodeString(c_UTF8, v2)
+	}
+}
+
+func (f *encFnInfo) fastEncMapBoolBool(rv reflect.Value) {
+	v := rv.Interface().(map[bool]bool)
+	f.ee.encodeMapPreamble(len(v))
+
+	for k2, v2 := range v {
+		f.ee.encodeBool(k2)
+		f.ee.encodeBool(v2)
+	}
+}
+
+// -- decode
+
+func (f *decFnInfo) fastDecSliceIntf(rv reflect.Value) {
+	v := rv.Addr().Interface().(*[]interface{})
+	var s []interface{}
+	vtype := f.dd.currentEncodedType()
+	if vtype == valueTypeNil {
+		*v = s
+		return
+	}
+
+	_, containerLenS := decContLens(f.dd, vtype)
+	s = *v
+	if s == nil {
+		s = make([]interface{}, containerLenS, containerLenS)
+	} else if containerLenS > cap(s) {
+		if f.array {
+			decErr(msgDecCannotExpandArr, cap(s), containerLenS)
+		}
+		s = make([]interface{}, containerLenS, containerLenS)
+		copy(s, *v)
+	} else if containerLenS > len(s) {
+		s = s[:containerLenS]
+	}
+	for j := 0; j < containerLenS; j++ {
+		f.d.decode(&s[j])
+
+	}
+	*v = s
+}
+
+func (f *decFnInfo) fastDecSliceString(rv reflect.Value) {
+	v := rv.Addr().Interface().(*[]string)
+	var s []string
+	vtype := f.dd.currentEncodedType()
+	if vtype == valueTypeNil {
+		*v = s
+		return
+	}
+
+	_, containerLenS := decContLens(f.dd, vtype)
+	s = *v
+	if s == nil {
+		s = make([]string, containerLenS, containerLenS)
+	} else if containerLenS > cap(s) {
+		if f.array {
+			decErr(msgDecCannotExpandArr, cap(s), containerLenS)
+		}
+		s = make([]string, containerLenS, containerLenS)
+		copy(s, *v)
+	} else if containerLenS > len(s) {
+		s = s[:containerLenS]
+	}
+	for j := 0; j < containerLenS; j++ {
+		f.dd.initReadNext()
+		s[j] = f.dd.decodeString()
+
+	}
+	*v = s
+}
+
+func (f *decFnInfo) fastDecSliceFloat32(rv reflect.Value) {
+	v := rv.Addr().Interface().(*[]float32)
+	var s []float32
+	vtype := f.dd.currentEncodedType()
+	if vtype == valueTypeNil {
+		*v = s
+		return
+	}
+
+	_, containerLenS := decContLens(f.dd, vtype)
+	s = *v
+	if s == nil {
+		s = make([]float32, containerLenS, containerLenS)
+	} else if containerLenS > cap(s) {
+		if f.array {
+			decErr(msgDecCannotExpandArr, cap(s), containerLenS)
+		}
+		s = make([]float32, containerLenS, containerLenS)
+		copy(s, *v)
+	} else if containerLenS > len(s) {
+		s = s[:containerLenS]
+	}
+	for j := 0; j < containerLenS; j++ {
+		f.dd.initReadNext()
+		s[j] = float32(f.dd.decodeFloat(true))
+
+	}
+	*v = s
+}
+
+func (f *decFnInfo) fastDecSliceFloat64(rv reflect.Value) {
+	v := rv.Addr().Interface().(*[]float64)
+	var s []float64
+	vtype := f.dd.currentEncodedType()
+	if vtype == valueTypeNil {
+		*v = s
+		return
+	}
+
+	_, containerLenS := decContLens(f.dd, vtype)
+	s = *v
+	if s == nil {
+		s = make([]float64, containerLenS, containerLenS)
+	} else if containerLenS > cap(s) {
+		if f.array {
+			decErr(msgDecCannotExpandArr, cap(s), containerLenS)
+		}
+		s = make([]float64, containerLenS, containerLenS)
+		copy(s, *v)
+	} else if containerLenS > len(s) {
+		s = s[:containerLenS]
+	}
+	for j := 0; j < containerLenS; j++ {
+		f.dd.initReadNext()
+		s[j] = f.dd.decodeFloat(false)
+
+	}
+	*v = s
+}
+
+func (f *decFnInfo) fastDecSliceUint(rv reflect.Value) {
+	v := rv.Addr().Interface().(*[]uint)
+	var s []uint
+	vtype := f.dd.currentEncodedType()
+	if vtype == valueTypeNil {
+		*v = s
+		return
+	}
+
+	_, containerLenS := decContLens(f.dd, vtype)
+	s = *v
+	if s == nil {
+		s = make([]uint, containerLenS, containerLenS)
+	} else if containerLenS > cap(s) {
+		if f.array {
+			decErr(msgDecCannotExpandArr, cap(s), containerLenS)
+		}
+		s = make([]uint, containerLenS, containerLenS)
+		copy(s, *v)
+	} else if containerLenS > len(s) {
+		s = s[:containerLenS]
+	}
+	for j := 0; j < containerLenS; j++ {
+		f.dd.initReadNext()
+		s[j] = uint(f.dd.decodeUint(uintBitsize))
+
+	}
+	*v = s
+}
+
+func (f *decFnInfo) fastDecSliceUint16(rv reflect.Value) {
+	v := rv.Addr().Interface().(*[]uint16)
+	var s []uint16
+	vtype := f.dd.currentEncodedType()
+	if vtype == valueTypeNil {
+		*v = s
+		return
+	}
+
+	_, containerLenS := decContLens(f.dd, vtype)
+	s = *v
+	if s == nil {
+		s = make([]uint16, containerLenS, containerLenS)
+	} else if containerLenS > cap(s) {
+		if f.array {
+			decErr(msgDecCannotExpandArr, cap(s), containerLenS)
+		}
+		s = make([]uint16, containerLenS, containerLenS)
+		copy(s, *v)
+	} else if containerLenS > len(s) {
+		s = s[:containerLenS]
+	}
+	for j := 0; j < containerLenS; j++ {
+		f.dd.initReadNext()
+		s[j] = uint16(f.dd.decodeUint(16))
+
+	}
+	*v = s
+}
+
+func (f *decFnInfo) fastDecSliceUint32(rv reflect.Value) {
+	v := rv.Addr().Interface().(*[]uint32)
+	var s []uint32
+	vtype := f.dd.currentEncodedType()
+	if vtype == valueTypeNil {
+		*v = s
+		return
+	}
+
+	_, containerLenS := decContLens(f.dd, vtype)
+	s = *v
+	if s == nil {
+		s = make([]uint32, containerLenS, containerLenS)
+	} else if containerLenS > cap(s) {
+		if f.array {
+			decErr(msgDecCannotExpandArr, cap(s), containerLenS)
+		}
+		s = make([]uint32, containerLenS, containerLenS)
+		copy(s, *v)
+	} else if containerLenS > len(s) {
+		s = s[:containerLenS]
+	}
+	for j := 0; j < containerLenS; j++ {
+		f.dd.initReadNext()
+		s[j] = uint32(f.dd.decodeUint(32))
+
+	}
+	*v = s
+}
+
+func (f *decFnInfo) fastDecSliceUint64(rv reflect.Value) {
+	v := rv.Addr().Interface().(*[]uint64)
+	var s []uint64
+	vtype := f.dd.currentEncodedType()
+	if vtype == valueTypeNil {
+		*v = s
+		return
+	}
+
+	_, containerLenS := decContLens(f.dd, vtype)
+	s = *v
+	if s == nil {
+		s = make([]uint64, containerLenS, containerLenS)
+	} else if containerLenS > cap(s) {
+		if f.array {
+			decErr(msgDecCannotExpandArr, cap(s), containerLenS)
+		}
+		s = make([]uint64, containerLenS, containerLenS)
+		copy(s, *v)
+	} else if containerLenS > len(s) {
+		s = s[:containerLenS]
+	}
+	for j := 0; j < containerLenS; j++ {
+		f.dd.initReadNext()
+		s[j] = f.dd.decodeUint(64)
+
+	}
+	*v = s
+}
+
+func (f *decFnInfo) fastDecSliceInt(rv reflect.Value) {
+	v := rv.Addr().Interface().(*[]int)
+	var s []int
+	vtype := f.dd.currentEncodedType()
+	if vtype == valueTypeNil {
+		*v = s
+		return
+	}
+
+	_, containerLenS := decContLens(f.dd, vtype)
+	s = *v
+	if s == nil {
+		s = make([]int, containerLenS, containerLenS)
+	} else if containerLenS > cap(s) {
+		if f.array {
+			decErr(msgDecCannotExpandArr, cap(s), containerLenS)
+		}
+		s = make([]int, containerLenS, containerLenS)
+		copy(s, *v)
+	} else if containerLenS > len(s) {
+		s = s[:containerLenS]
+	}
+	for j := 0; j < containerLenS; j++ {
+		f.dd.initReadNext()
+		s[j] = int(f.dd.decodeInt(intBitsize))
+
+	}
+	*v = s
+}
+
+func (f *decFnInfo) fastDecSliceInt8(rv reflect.Value) {
+	v := rv.Addr().Interface().(*[]int8)
+	var s []int8
+	vtype := f.dd.currentEncodedType()
+	if vtype == valueTypeNil {
+		*v = s
+		return
+	}
+
+	_, containerLenS := decContLens(f.dd, vtype)
+	s = *v
+	if s == nil {
+		s = make([]int8, containerLenS, containerLenS)
+	} else if containerLenS > cap(s) {
+		if f.array {
+			decErr(msgDecCannotExpandArr, cap(s), containerLenS)
+		}
+		s = make([]int8, containerLenS, containerLenS)
+		copy(s, *v)
+	} else if containerLenS > len(s) {
+		s = s[:containerLenS]
+	}
+	for j := 0; j < containerLenS; j++ {
+		f.dd.initReadNext()
+		s[j] = int8(f.dd.decodeInt(8))
+
+	}
+	*v = s
+}
+
+func (f *decFnInfo) fastDecSliceInt16(rv reflect.Value) {
+	v := rv.Addr().Interface().(*[]int16)
+	var s []int16
+	vtype := f.dd.currentEncodedType()
+	if vtype == valueTypeNil {
+		*v = s
+		return
+	}
+
+	_, containerLenS := decContLens(f.dd, vtype)
+	s = *v
+	if s == nil {
+		s = make([]int16, containerLenS, containerLenS)
+	} else if containerLenS > cap(s) {
+		if f.array {
+			decErr(msgDecCannotExpandArr, cap(s), containerLenS)
+		}
+		s = make([]int16, containerLenS, containerLenS)
+		copy(s, *v)
+	} else if containerLenS > len(s) {
+		s = s[:containerLenS]
+	}
+	for j := 0; j < containerLenS; j++ {
+		f.dd.initReadNext()
+		s[j] = int16(f.dd.decodeInt(16))
+
+	}
+	*v = s
+}
+
+func (f *decFnInfo) fastDecSliceInt32(rv reflect.Value) {
+	v := rv.Addr().Interface().(*[]int32)
+	var s []int32
+	vtype := f.dd.currentEncodedType()
+	if vtype == valueTypeNil {
+		*v = s
+		return
+	}
+
+	_, containerLenS := decContLens(f.dd, vtype)
+	s = *v
+	if s == nil {
+		s = make([]int32, containerLenS, containerLenS)
+	} else if containerLenS > cap(s) {
+		if f.array {
+			decErr(msgDecCannotExpandArr, cap(s), containerLenS)
+		}
+		s = make([]int32, containerLenS, containerLenS)
+		copy(s, *v)
+	} else if containerLenS > len(s) {
+		s = s[:containerLenS]
+	}
+	for j := 0; j < containerLenS; j++ {
+		f.dd.initReadNext()
+		s[j] = int32(f.dd.decodeInt(32))
+
+	}
+	*v = s
+}
+
+func (f *decFnInfo) fastDecSliceInt64(rv reflect.Value) {
+	v := rv.Addr().Interface().(*[]int64)
+	var s []int64
+	vtype := f.dd.currentEncodedType()
+	if vtype == valueTypeNil {
+		*v = s
+		return
+	}
+
+	_, containerLenS := decContLens(f.dd, vtype)
+	s = *v
+	if s == nil {
+		s = make([]int64, containerLenS, containerLenS)
+	} else if containerLenS > cap(s) {
+		if f.array {
+			decErr(msgDecCannotExpandArr, cap(s), containerLenS)
+		}
+		s = make([]int64, containerLenS, containerLenS)
+		copy(s, *v)
+	} else if containerLenS > len(s) {
+		s = s[:containerLenS]
+	}
+	for j := 0; j < containerLenS; j++ {
+		f.dd.initReadNext()
+		s[j] = f.dd.decodeInt(64)
+
+	}
+	*v = s
+}
+
+func (f *decFnInfo) fastDecSliceBool(rv reflect.Value) {
+	v := rv.Addr().Interface().(*[]bool)
+	var s []bool
+	vtype := f.dd.currentEncodedType()
+	if vtype == valueTypeNil {
+		*v = s
+		return
+	}
+
+	_, containerLenS := decContLens(f.dd, vtype)
+	s = *v
+	if s == nil {
+		s = make([]bool, containerLenS, containerLenS)
+	} else if containerLenS > cap(s) {
+		if f.array {
+			decErr(msgDecCannotExpandArr, cap(s), containerLenS)
+		}
+		s = make([]bool, containerLenS, containerLenS)
+		copy(s, *v)
+	} else if containerLenS > len(s) {
+		s = s[:containerLenS]
+	}
+	for j := 0; j < containerLenS; j++ {
+		f.dd.initReadNext()
+		s[j] = f.dd.decodeBool()
+
+	}
+	*v = s
+}
+
+func (f *decFnInfo) fastDecMapIntfIntf(rv reflect.Value) {
+	v := rv.Addr().Interface().(*map[interface{}]interface{})
+	var m map[interface{}]interface{}
+	vtype := f.dd.currentEncodedType()
+	if vtype == valueTypeNil {
+		*v = m
+		return
+	}
+
+	containerLen := f.dd.readMapLen()
+	m = *v
+	if m == nil {
+		m = make(map[interface{}]interface{}, containerLen)
+		*v = m
+	}
+	for j := 0; j < containerLen; j++ {
+		var mk interface{}
+		f.d.decode(&mk)
+		// special case if a byte array.
+		if bv, bok := mk.([]byte); bok {
+			mk = string(bv)
+		}
+
+		mv := m[mk]
+		f.d.decode(&mv)
+
+		m[mk] = mv
+	}
+}
+
+func (f *decFnInfo) fastDecMapIntfString(rv reflect.Value) {
+	v := rv.Addr().Interface().(*map[interface{}]string)
+	var m map[interface{}]string
+	vtype := f.dd.currentEncodedType()
+	if vtype == valueTypeNil {
+		*v = m
+		return
+	}
+
+	containerLen := f.dd.readMapLen()
+	m = *v
+	if m == nil {
+		m = make(map[interface{}]string, containerLen)
+		*v = m
+	}
+	for j := 0; j < containerLen; j++ {
+		var mk interface{}
+		f.d.decode(&mk)
+		// special case if a byte array.
+		if bv, bok := mk.([]byte); bok {
+			mk = string(bv)
+		}
+
+		mv := m[mk]
+		f.dd.initReadNext()
+		mv = f.dd.decodeString()
+
+		m[mk] = mv
+	}
+}
+
+func (f *decFnInfo) fastDecMapStringIntf(rv reflect.Value) {
+	v := rv.Addr().Interface().(*map[string]interface{})
+	var m map[string]interface{}
+	vtype := f.dd.currentEncodedType()
+	if vtype == valueTypeNil {
+		*v = m
+		return
+	}
+
+	containerLen := f.dd.readMapLen()
+	m = *v
+	if m == nil {
+		m = make(map[string]interface{}, containerLen)
+		*v = m
+	}
+	for j := 0; j < containerLen; j++ {
+		f.dd.initReadNext()
+		mk := f.dd.decodeString()
+
+		mv := m[mk]
+		f.d.decode(&mv)
+
+		m[mk] = mv
+	}
+}
+
+func (f *decFnInfo) fastDecMapStringString(rv reflect.Value) {
+	v := rv.Addr().Interface().(*map[string]string)
+	var m map[string]string
+	vtype := f.dd.currentEncodedType()
+	if vtype == valueTypeNil {
+		*v = m
+		return
+	}
+
+	containerLen := f.dd.readMapLen()
+	m = *v
+	if m == nil {
+		m = make(map[string]string, containerLen)
+		*v = m
+	}
+	for j := 0; j < containerLen; j++ {
+		f.dd.initReadNext()
+		mk := f.dd.decodeString()
+
+		mv := m[mk]
+		f.dd.initReadNext()
+		mv = f.dd.decodeString()
+
+		m[mk] = mv
+	}
+}
+
+func (f *decFnInfo) fastDecMapFloat32Intf(rv reflect.Value) {
+	v := rv.Addr().Interface().(*map[float32]interface{})
+	var m map[float32]interface{}
+	vtype := f.dd.currentEncodedType()
+	if vtype == valueTypeNil {
+		*v = m
+		return
+	}
+
+	containerLen := f.dd.readMapLen()
+	m = *v
+	if m == nil {
+		m = make(map[float32]interface{}, containerLen)
+		*v = m
+	}
+	for j := 0; j < containerLen; j++ {
+		f.dd.initReadNext()
+		mk := float32(f.dd.decodeFloat(true))
+
+		mv := m[mk]
+		f.d.decode(&mv)
+
+		m[mk] = mv
+	}
+}
+
+func (f *decFnInfo) fastDecMapFloat32String(rv reflect.Value) {
+	v := rv.Addr().Interface().(*map[float32]string)
+	var m map[float32]string
+	vtype := f.dd.currentEncodedType()
+	if vtype == valueTypeNil {
+		*v = m
+		return
+	}
+
+	containerLen := f.dd.readMapLen()
+	m = *v
+	if m == nil {
+		m = make(map[float32]string, containerLen)
+		*v = m
+	}
+	for j := 0; j < containerLen; j++ {
+		f.dd.initReadNext()
+		mk := float32(f.dd.decodeFloat(true))
+
+		mv := m[mk]
+		f.dd.initReadNext()
+		mv = f.dd.decodeString()
+
+		m[mk] = mv
+	}
+}
+
+func (f *decFnInfo) fastDecMapFloat32Float32(rv reflect.Value) {
+	v := rv.Addr().Interface().(*map[float32]float32)
+	var m map[float32]float32
+	vtype := f.dd.currentEncodedType()
+	if vtype == valueTypeNil {
+		*v = m
+		return
+	}
+
+	containerLen := f.dd.readMapLen()
+	m = *v
+	if m == nil {
+		m = make(map[float32]float32, containerLen)
+		*v = m
+	}
+	for j := 0; j < containerLen; j++ {
+		f.dd.initReadNext()
+		mk := float32(f.dd.decodeFloat(true))
+
+		mv := m[mk]
+		f.dd.initReadNext()
+		mv = float32(f.dd.decodeFloat(true))
+
+		m[mk] = mv
+	}
+}
+
+func (f *decFnInfo) fastDecMapFloat64Intf(rv reflect.Value) {
+	v := rv.Addr().Interface().(*map[float64]interface{})
+	var m map[float64]interface{}
+	vtype := f.dd.currentEncodedType()
+	if vtype == valueTypeNil {
+		*v = m
+		return
+	}
+
+	containerLen := f.dd.readMapLen()
+	m = *v
+	if m == nil {
+		m = make(map[float64]interface{}, containerLen)
+		*v = m
+	}
+	for j := 0; j < containerLen; j++ {
+		f.dd.initReadNext()
+		mk := f.dd.decodeFloat(false)
+
+		mv := m[mk]
+		f.d.decode(&mv)
+
+		m[mk] = mv
+	}
+}
+
+func (f *decFnInfo) fastDecMapFloat64String(rv reflect.Value) {
+	v := rv.Addr().Interface().(*map[float64]string)
+	var m map[float64]string
+	vtype := f.dd.currentEncodedType()
+	if vtype == valueTypeNil {
+		*v = m
+		return
+	}
+
+	containerLen := f.dd.readMapLen()
+	m = *v
+	if m == nil {
+		m = make(map[float64]string, containerLen)
+		*v = m
+	}
+	for j := 0; j < containerLen; j++ {
+		f.dd.initReadNext()
+		mk := f.dd.decodeFloat(false)
+
+		mv := m[mk]
+		f.dd.initReadNext()
+		mv = f.dd.decodeString()
+
+		m[mk] = mv
+	}
+}
+
+func (f *decFnInfo) fastDecMapFloat64Float64(rv reflect.Value) {
+	v := rv.Addr().Interface().(*map[float64]float64)
+	var m map[float64]float64
+	vtype := f.dd.currentEncodedType()
+	if vtype == valueTypeNil {
+		*v = m
+		return
+	}
+
+	containerLen := f.dd.readMapLen()
+	m = *v
+	if m == nil {
+		m = make(map[float64]float64, containerLen)
+		*v = m
+	}
+	for j := 0; j < containerLen; j++ {
+		f.dd.initReadNext()
+		mk := f.dd.decodeFloat(false)
+
+		mv := m[mk]
+		f.dd.initReadNext()
+		mv = f.dd.decodeFloat(false)
+
+		m[mk] = mv
+	}
+}
+
+func (f *decFnInfo) fastDecMapUintIntf(rv reflect.Value) {
+	v := rv.Addr().Interface().(*map[uint]interface{})
+	var m map[uint]interface{}
+	vtype := f.dd.currentEncodedType()
+	if vtype == valueTypeNil {
+		*v = m
+		return
+	}
+
+	containerLen := f.dd.readMapLen()
+	m = *v
+	if m == nil {
+		m = make(map[uint]interface{}, containerLen)
+		*v = m
+	}
+	for j := 0; j < containerLen; j++ {
+		f.dd.initReadNext()
+		mk := uint(f.dd.decodeUint(uintBitsize))
+
+		mv := m[mk]
+		f.d.decode(&mv)
+
+		m[mk] = mv
+	}
+}
+
+func (f *decFnInfo) fastDecMapUintString(rv reflect.Value) {
+	v := rv.Addr().Interface().(*map[uint]string)
+	var m map[uint]string
+	vtype := f.dd.currentEncodedType()
+	if vtype == valueTypeNil {
+		*v = m
+		return
+	}
+
+	containerLen := f.dd.readMapLen()
+	m = *v
+	if m == nil {
+		m = make(map[uint]string, containerLen)
+		*v = m
+	}
+	for j := 0; j < containerLen; j++ {
+		f.dd.initReadNext()
+		mk := uint(f.dd.decodeUint(uintBitsize))
+
+		mv := m[mk]
+		f.dd.initReadNext()
+		mv = f.dd.decodeString()
+
+		m[mk] = mv
+	}
+}
+
+func (f *decFnInfo) fastDecMapUintUint(rv reflect.Value) {
+	v := rv.Addr().Interface().(*map[uint]uint)
+	var m map[uint]uint
+	vtype := f.dd.currentEncodedType()
+	if vtype == valueTypeNil {
+		*v = m
+		return
+	}
+
+	containerLen := f.dd.readMapLen()
+	m = *v
+	if m == nil {
+		m = make(map[uint]uint, containerLen)
+		*v = m
+	}
+	for j := 0; j < containerLen; j++ {
+		f.dd.initReadNext()
+		mk := uint(f.dd.decodeUint(uintBitsize))
+
+		mv := m[mk]
+		f.dd.initReadNext()
+		mv = uint(f.dd.decodeUint(uintBitsize))
+
+		m[mk] = mv
+	}
+}
+
+func (f *decFnInfo) fastDecMapUint8Intf(rv reflect.Value) {
+	v := rv.Addr().Interface().(*map[uint8]interface{})
+	var m map[uint8]interface{}
+	vtype := f.dd.currentEncodedType()
+	if vtype == valueTypeNil {
+		*v = m
+		return
+	}
+
+	containerLen := f.dd.readMapLen()
+	m = *v
+	if m == nil {
+		m = make(map[uint8]interface{}, containerLen)
+		*v = m
+	}
+	for j := 0; j < containerLen; j++ {
+		f.dd.initReadNext()
+		mk := uint8(f.dd.decodeUint(8))
+
+		mv := m[mk]
+		f.d.decode(&mv)
+
+		m[mk] = mv
+	}
+}
+
+func (f *decFnInfo) fastDecMapUint8String(rv reflect.Value) {
+	v := rv.Addr().Interface().(*map[uint8]string)
+	var m map[uint8]string
+	vtype := f.dd.currentEncodedType()
+	if vtype == valueTypeNil {
+		*v = m
+		return
+	}
+
+	containerLen := f.dd.readMapLen()
+	m = *v
+	if m == nil {
+		m = make(map[uint8]string, containerLen)
+		*v = m
+	}
+	for j := 0; j < containerLen; j++ {
+		f.dd.initReadNext()
+		mk := uint8(f.dd.decodeUint(8))
+
+		mv := m[mk]
+		f.dd.initReadNext()
+		mv = f.dd.decodeString()
+
+		m[mk] = mv
+	}
+}
+
+func (f *decFnInfo) fastDecMapUint8Uint8(rv reflect.Value) {
+	v := rv.Addr().Interface().(*map[uint8]uint8)
+	var m map[uint8]uint8
+	vtype := f.dd.currentEncodedType()
+	if vtype == valueTypeNil {
+		*v = m
+		return
+	}
+
+	containerLen := f.dd.readMapLen()
+	m = *v
+	if m == nil {
+		m = make(map[uint8]uint8, containerLen)
+		*v = m
+	}
+	for j := 0; j < containerLen; j++ {
+		f.dd.initReadNext()
+		mk := uint8(f.dd.decodeUint(8))
+
+		mv := m[mk]
+		f.dd.initReadNext()
+		mv = uint8(f.dd.decodeUint(8))
+
+		m[mk] = mv
+	}
+}
+
+func (f *decFnInfo) fastDecMapUint16Intf(rv reflect.Value) {
+	v := rv.Addr().Interface().(*map[uint16]interface{})
+	var m map[uint16]interface{}
+	vtype := f.dd.currentEncodedType()
+	if vtype == valueTypeNil {
+		*v = m
+		return
+	}
+
+	containerLen := f.dd.readMapLen()
+	m = *v
+	if m == nil {
+		m = make(map[uint16]interface{}, containerLen)
+		*v = m
+	}
+	for j := 0; j < containerLen; j++ {
+		f.dd.initReadNext()
+		mk := uint16(f.dd.decodeUint(16))
+
+		mv := m[mk]
+		f.d.decode(&mv)
+
+		m[mk] = mv
+	}
+}
+
+func (f *decFnInfo) fastDecMapUint16String(rv reflect.Value) {
+	v := rv.Addr().Interface().(*map[uint16]string)
+	var m map[uint16]string
+	vtype := f.dd.currentEncodedType()
+	if vtype == valueTypeNil {
+		*v = m
+		return
+	}
+
+	containerLen := f.dd.readMapLen()
+	m = *v
+	if m == nil {
+		m = make(map[uint16]string, containerLen)
+		*v = m
+	}
+	for j := 0; j < containerLen; j++ {
+		f.dd.initReadNext()
+		mk := uint16(f.dd.decodeUint(16))
+
+		mv := m[mk]
+		f.dd.initReadNext()
+		mv = f.dd.decodeString()
+
+		m[mk] = mv
+	}
+}
+
+func (f *decFnInfo) fastDecMapUint16Uint16(rv reflect.Value) {
+	v := rv.Addr().Interface().(*map[uint16]uint16)
+	var m map[uint16]uint16
+	vtype := f.dd.currentEncodedType()
+	if vtype == valueTypeNil {
+		*v = m
+		return
+	}
+
+	containerLen := f.dd.readMapLen()
+	m = *v
+	if m == nil {
+		m = make(map[uint16]uint16, containerLen)
+		*v = m
+	}
+	for j := 0; j < containerLen; j++ {
+		f.dd.initReadNext()
+		mk := uint16(f.dd.decodeUint(16))
+
+		mv := m[mk]
+		f.dd.initReadNext()
+		mv = uint16(f.dd.decodeUint(16))
+
+		m[mk] = mv
+	}
+}
+
+func (f *decFnInfo) fastDecMapUint32Intf(rv reflect.Value) {
+	v := rv.Addr().Interface().(*map[uint32]interface{})
+	var m map[uint32]interface{}
+	vtype := f.dd.currentEncodedType()
+	if vtype == valueTypeNil {
+		*v = m
+		return
+	}
+
+	containerLen := f.dd.readMapLen()
+	m = *v
+	if m == nil {
+		m = make(map[uint32]interface{}, containerLen)
+		*v = m
+	}
+	for j := 0; j < containerLen; j++ {
+		f.dd.initReadNext()
+		mk := uint32(f.dd.decodeUint(32))
+
+		mv := m[mk]
+		f.d.decode(&mv)
+
+		m[mk] = mv
+	}
+}
+
+func (f *decFnInfo) fastDecMapUint32String(rv reflect.Value) {
+	v := rv.Addr().Interface().(*map[uint32]string)
+	var m map[uint32]string
+	vtype := f.dd.currentEncodedType()
+	if vtype == valueTypeNil {
+		*v = m
+		return
+	}
+
+	containerLen := f.dd.readMapLen()
+	m = *v
+	if m == nil {
+		m = make(map[uint32]string, containerLen)
+		*v = m
+	}
+	for j := 0; j < containerLen; j++ {
+		f.dd.initReadNext()
+		mk := uint32(f.dd.decodeUint(32))
+
+		mv := m[mk]
+		f.dd.initReadNext()
+		mv = f.dd.decodeString()
+
+		m[mk] = mv
+	}
+}
+
+func (f *decFnInfo) fastDecMapUint32Uint32(rv reflect.Value) {
+	v := rv.Addr().Interface().(*map[uint32]uint32)
+	var m map[uint32]uint32
+	vtype := f.dd.currentEncodedType()
+	if vtype == valueTypeNil {
+		*v = m
+		return
+	}
+
+	containerLen := f.dd.readMapLen()
+	m = *v
+	if m == nil {
+		m = make(map[uint32]uint32, containerLen)
+		*v = m
+	}
+	for j := 0; j < containerLen; j++ {
+		f.dd.initReadNext()
+		mk := uint32(f.dd.decodeUint(32))
+
+		mv := m[mk]
+		f.dd.initReadNext()
+		mv = uint32(f.dd.decodeUint(32))
+
+		m[mk] = mv
+	}
+}
+
+func (f *decFnInfo) fastDecMapUint64Intf(rv reflect.Value) {
+	v := rv.Addr().Interface().(*map[uint64]interface{})
+	var m map[uint64]interface{}
+	vtype := f.dd.currentEncodedType()
+	if vtype == valueTypeNil {
+		*v = m
+		return
+	}
+
+	containerLen := f.dd.readMapLen()
+	m = *v
+	if m == nil {
+		m = make(map[uint64]interface{}, containerLen)
+		*v = m
+	}
+	for j := 0; j < containerLen; j++ {
+		f.dd.initReadNext()
+		mk := f.dd.decodeUint(64)
+
+		mv := m[mk]
+		f.d.decode(&mv)
+
+		m[mk] = mv
+	}
+}
+
+func (f *decFnInfo) fastDecMapUint64String(rv reflect.Value) {
+	v := rv.Addr().Interface().(*map[uint64]string)
+	var m map[uint64]string
+	vtype := f.dd.currentEncodedType()
+	if vtype == valueTypeNil {
+		*v = m
+		return
+	}
+
+	containerLen := f.dd.readMapLen()
+	m = *v
+	if m == nil {
+		m = make(map[uint64]string, containerLen)
+		*v = m
+	}
+	for j := 0; j < containerLen; j++ {
+		f.dd.initReadNext()
+		mk := f.dd.decodeUint(64)
+
+		mv := m[mk]
+		f.dd.initReadNext()
+		mv = f.dd.decodeString()
+
+		m[mk] = mv
+	}
+}
+
+func (f *decFnInfo) fastDecMapUint64Uint64(rv reflect.Value) {
+	v := rv.Addr().Interface().(*map[uint64]uint64)
+	var m map[uint64]uint64
+	vtype := f.dd.currentEncodedType()
+	if vtype == valueTypeNil {
+		*v = m
+		return
+	}
+
+	containerLen := f.dd.readMapLen()
+	m = *v
+	if m == nil {
+		m = make(map[uint64]uint64, containerLen)
+		*v = m
+	}
+	for j := 0; j < containerLen; j++ {
+		f.dd.initReadNext()
+		mk := f.dd.decodeUint(64)
+
+		mv := m[mk]
+		f.dd.initReadNext()
+		mv = f.dd.decodeUint(64)
+
+		m[mk] = mv
+	}
+}
+
+func (f *decFnInfo) fastDecMapIntIntf(rv reflect.Value) {
+	v := rv.Addr().Interface().(*map[int]interface{})
+	var m map[int]interface{}
+	vtype := f.dd.currentEncodedType()
+	if vtype == valueTypeNil {
+		*v = m
+		return
+	}
+
+	containerLen := f.dd.readMapLen()
+	m = *v
+	if m == nil {
+		m = make(map[int]interface{}, containerLen)
+		*v = m
+	}
+	for j := 0; j < containerLen; j++ {
+		f.dd.initReadNext()
+		mk := int(f.dd.decodeInt(intBitsize))
+
+		mv := m[mk]
+		f.d.decode(&mv)
+
+		m[mk] = mv
+	}
+}
+
+func (f *decFnInfo) fastDecMapIntString(rv reflect.Value) {
+	v := rv.Addr().Interface().(*map[int]string)
+	var m map[int]string
+	vtype := f.dd.currentEncodedType()
+	if vtype == valueTypeNil {
+		*v = m
+		return
+	}
+
+	containerLen := f.dd.readMapLen()
+	m = *v
+	if m == nil {
+		m = make(map[int]string, containerLen)
+		*v = m
+	}
+	for j := 0; j < containerLen; j++ {
+		f.dd.initReadNext()
+		mk := int(f.dd.decodeInt(intBitsize))
+
+		mv := m[mk]
+		f.dd.initReadNext()
+		mv = f.dd.decodeString()
+
+		m[mk] = mv
+	}
+}
+
+func (f *decFnInfo) fastDecMapIntInt(rv reflect.Value) {
+	v := rv.Addr().Interface().(*map[int]int)
+	var m map[int]int
+	vtype := f.dd.currentEncodedType()
+	if vtype == valueTypeNil {
+		*v = m
+		return
+	}
+
+	containerLen := f.dd.readMapLen()
+	m = *v
+	if m == nil {
+		m = make(map[int]int, containerLen)
+		*v = m
+	}
+	for j := 0; j < containerLen; j++ {
+		f.dd.initReadNext()
+		mk := int(f.dd.decodeInt(intBitsize))
+
+		mv := m[mk]
+		f.dd.initReadNext()
+		mv = int(f.dd.decodeInt(intBitsize))
+
+		m[mk] = mv
+	}
+}
+
+func (f *decFnInfo) fastDecMapInt8Intf(rv reflect.Value) {
+	v := rv.Addr().Interface().(*map[int8]interface{})
+	var m map[int8]interface{}
+	vtype := f.dd.currentEncodedType()
+	if vtype == valueTypeNil {
+		*v = m
+		return
+	}
+
+	containerLen := f.dd.readMapLen()
+	m = *v
+	if m == nil {
+		m = make(map[int8]interface{}, containerLen)
+		*v = m
+	}
+	for j := 0; j < containerLen; j++ {
+		f.dd.initReadNext()
+		mk := int8(f.dd.decodeInt(8))
+
+		mv := m[mk]
+		f.d.decode(&mv)
+
+		m[mk] = mv
+	}
+}
+
+func (f *decFnInfo) fastDecMapInt8String(rv reflect.Value) {
+	v := rv.Addr().Interface().(*map[int8]string)
+	var m map[int8]string
+	vtype := f.dd.currentEncodedType()
+	if vtype == valueTypeNil {
+		*v = m
+		return
+	}
+
+	containerLen := f.dd.readMapLen()
+	m = *v
+	if m == nil {
+		m = make(map[int8]string, containerLen)
+		*v = m
+	}
+	for j := 0; j < containerLen; j++ {
+		f.dd.initReadNext()
+		mk := int8(f.dd.decodeInt(8))
+
+		mv := m[mk]
+		f.dd.initReadNext()
+		mv = f.dd.decodeString()
+
+		m[mk] = mv
+	}
+}
+
+func (f *decFnInfo) fastDecMapInt8Int8(rv reflect.Value) {
+	v := rv.Addr().Interface().(*map[int8]int8)
+	var m map[int8]int8
+	vtype := f.dd.currentEncodedType()
+	if vtype == valueTypeNil {
+		*v = m
+		return
+	}
+
+	containerLen := f.dd.readMapLen()
+	m = *v
+	if m == nil {
+		m = make(map[int8]int8, containerLen)
+		*v = m
+	}
+	for j := 0; j < containerLen; j++ {
+		f.dd.initReadNext()
+		mk := int8(f.dd.decodeInt(8))
+
+		mv := m[mk]
+		f.dd.initReadNext()
+		mv = int8(f.dd.decodeInt(8))
+
+		m[mk] = mv
+	}
+}
+
+func (f *decFnInfo) fastDecMapInt16Intf(rv reflect.Value) {
+	v := rv.Addr().Interface().(*map[int16]interface{})
+	var m map[int16]interface{}
+	vtype := f.dd.currentEncodedType()
+	if vtype == valueTypeNil {
+		*v = m
+		return
+	}
+
+	containerLen := f.dd.readMapLen()
+	m = *v
+	if m == nil {
+		m = make(map[int16]interface{}, containerLen)
+		*v = m
+	}
+	for j := 0; j < containerLen; j++ {
+		f.dd.initReadNext()
+		mk := int16(f.dd.decodeInt(16))
+
+		mv := m[mk]
+		f.d.decode(&mv)
+
+		m[mk] = mv
+	}
+}
+
+func (f *decFnInfo) fastDecMapInt16String(rv reflect.Value) {
+	v := rv.Addr().Interface().(*map[int16]string)
+	var m map[int16]string
+	vtype := f.dd.currentEncodedType()
+	if vtype == valueTypeNil {
+		*v = m
+		return
+	}
+
+	containerLen := f.dd.readMapLen()
+	m = *v
+	if m == nil {
+		m = make(map[int16]string, containerLen)
+		*v = m
+	}
+	for j := 0; j < containerLen; j++ {
+		f.dd.initReadNext()
+		mk := int16(f.dd.decodeInt(16))
+
+		mv := m[mk]
+		f.dd.initReadNext()
+		mv = f.dd.decodeString()
+
+		m[mk] = mv
+	}
+}
+
+func (f *decFnInfo) fastDecMapInt16Int16(rv reflect.Value) {
+	v := rv.Addr().Interface().(*map[int16]int16)
+	var m map[int16]int16
+	vtype := f.dd.currentEncodedType()
+	if vtype == valueTypeNil {
+		*v = m
+		return
+	}
+
+	containerLen := f.dd.readMapLen()
+	m = *v
+	if m == nil {
+		m = make(map[int16]int16, containerLen)
+		*v = m
+	}
+	for j := 0; j < containerLen; j++ {
+		f.dd.initReadNext()
+		mk := int16(f.dd.decodeInt(16))
+
+		mv := m[mk]
+		f.dd.initReadNext()
+		mv = int16(f.dd.decodeInt(16))
+
+		m[mk] = mv
+	}
+}
+
+func (f *decFnInfo) fastDecMapInt32Intf(rv reflect.Value) {
+	v := rv.Addr().Interface().(*map[int32]interface{})
+	var m map[int32]interface{}
+	vtype := f.dd.currentEncodedType()
+	if vtype == valueTypeNil {
+		*v = m
+		return
+	}
+
+	containerLen := f.dd.readMapLen()
+	m = *v
+	if m == nil {
+		m = make(map[int32]interface{}, containerLen)
+		*v = m
+	}
+	for j := 0; j < containerLen; j++ {
+		f.dd.initReadNext()
+		mk := int32(f.dd.decodeInt(32))
+
+		mv := m[mk]
+		f.d.decode(&mv)
+
+		m[mk] = mv
+	}
+}
+
+func (f *decFnInfo) fastDecMapInt32String(rv reflect.Value) {
+	v := rv.Addr().Interface().(*map[int32]string)
+	var m map[int32]string
+	vtype := f.dd.currentEncodedType()
+	if vtype == valueTypeNil {
+		*v = m
+		return
+	}
+
+	containerLen := f.dd.readMapLen()
+	m = *v
+	if m == nil {
+		m = make(map[int32]string, containerLen)
+		*v = m
+	}
+	for j := 0; j < containerLen; j++ {
+		f.dd.initReadNext()
+		mk := int32(f.dd.decodeInt(32))
+
+		mv := m[mk]
+		f.dd.initReadNext()
+		mv = f.dd.decodeString()
+
+		m[mk] = mv
+	}
+}
+
+func (f *decFnInfo) fastDecMapInt32Int32(rv reflect.Value) {
+	v := rv.Addr().Interface().(*map[int32]int32)
+	var m map[int32]int32
+	vtype := f.dd.currentEncodedType()
+	if vtype == valueTypeNil {
+		*v = m
+		return
+	}
+
+	containerLen := f.dd.readMapLen()
+	m = *v
+	if m == nil {
+		m = make(map[int32]int32, containerLen)
+		*v = m
+	}
+	for j := 0; j < containerLen; j++ {
+		f.dd.initReadNext()
+		mk := int32(f.dd.decodeInt(32))
+
+		mv := m[mk]
+		f.dd.initReadNext()
+		mv = int32(f.dd.decodeInt(32))
+
+		m[mk] = mv
+	}
+}
+
+func (f *decFnInfo) fastDecMapInt64Intf(rv reflect.Value) {
+	v := rv.Addr().Interface().(*map[int64]interface{})
+	var m map[int64]interface{}
+	vtype := f.dd.currentEncodedType()
+	if vtype == valueTypeNil {
+		*v = m
+		return
+	}
+
+	containerLen := f.dd.readMapLen()
+	m = *v
+	if m == nil {
+		m = make(map[int64]interface{}, containerLen)
+		*v = m
+	}
+	for j := 0; j < containerLen; j++ {
+		f.dd.initReadNext()
+		mk := f.dd.decodeInt(64)
+
+		mv := m[mk]
+		f.d.decode(&mv)
+
+		m[mk] = mv
+	}
+}
+
+func (f *decFnInfo) fastDecMapInt64String(rv reflect.Value) {
+	v := rv.Addr().Interface().(*map[int64]string)
+	var m map[int64]string
+	vtype := f.dd.currentEncodedType()
+	if vtype == valueTypeNil {
+		*v = m
+		return
+	}
+
+	containerLen := f.dd.readMapLen()
+	m = *v
+	if m == nil {
+		m = make(map[int64]string, containerLen)
+		*v = m
+	}
+	for j := 0; j < containerLen; j++ {
+		f.dd.initReadNext()
+		mk := f.dd.decodeInt(64)
+
+		mv := m[mk]
+		f.dd.initReadNext()
+		mv = f.dd.decodeString()
+
+		m[mk] = mv
+	}
+}
+
+func (f *decFnInfo) fastDecMapInt64Int64(rv reflect.Value) {
+	v := rv.Addr().Interface().(*map[int64]int64)
+	var m map[int64]int64
+	vtype := f.dd.currentEncodedType()
+	if vtype == valueTypeNil {
+		*v = m
+		return
+	}
+
+	containerLen := f.dd.readMapLen()
+	m = *v
+	if m == nil {
+		m = make(map[int64]int64, containerLen)
+		*v = m
+	}
+	for j := 0; j < containerLen; j++ {
+		f.dd.initReadNext()
+		mk := f.dd.decodeInt(64)
+
+		mv := m[mk]
+		f.dd.initReadNext()
+		mv = f.dd.decodeInt(64)
+
+		m[mk] = mv
+	}
+}
+
+func (f *decFnInfo) fastDecMapBoolIntf(rv reflect.Value) {
+	v := rv.Addr().Interface().(*map[bool]interface{})
+	var m map[bool]interface{}
+	vtype := f.dd.currentEncodedType()
+	if vtype == valueTypeNil {
+		*v = m
+		return
+	}
+
+	containerLen := f.dd.readMapLen()
+	m = *v
+	if m == nil {
+		m = make(map[bool]interface{}, containerLen)
+		*v = m
+	}
+	for j := 0; j < containerLen; j++ {
+		f.dd.initReadNext()
+		mk := f.dd.decodeBool()
+
+		mv := m[mk]
+		f.d.decode(&mv)
+
+		m[mk] = mv
+	}
+}
+
+func (f *decFnInfo) fastDecMapBoolString(rv reflect.Value) {
+	v := rv.Addr().Interface().(*map[bool]string)
+	var m map[bool]string
+	vtype := f.dd.currentEncodedType()
+	if vtype == valueTypeNil {
+		*v = m
+		return
+	}
+
+	containerLen := f.dd.readMapLen()
+	m = *v
+	if m == nil {
+		m = make(map[bool]string, containerLen)
+		*v = m
+	}
+	for j := 0; j < containerLen; j++ {
+		f.dd.initReadNext()
+		mk := f.dd.decodeBool()
+
+		mv := m[mk]
+		f.dd.initReadNext()
+		mv = f.dd.decodeString()
+
+		m[mk] = mv
+	}
+}
+
+func (f *decFnInfo) fastDecMapBoolBool(rv reflect.Value) {
+	v := rv.Addr().Interface().(*map[bool]bool)
+	var m map[bool]bool
+	vtype := f.dd.currentEncodedType()
+	if vtype == valueTypeNil {
+		*v = m
+		return
+	}
+
+	containerLen := f.dd.readMapLen()
+	m = *v
+	if m == nil {
+		m = make(map[bool]bool, containerLen)
+		*v = m
+	}
+	for j := 0; j < containerLen; j++ {
+		f.dd.initReadNext()
+		mk := f.dd.decodeBool()
+
+		mv := m[mk]
+		f.dd.initReadNext()
+		mv = f.dd.decodeBool()
+
+		m[mk] = mv
+	}
+}

+ 337 - 0
codec/gen-fast-path.go

@@ -0,0 +1,337 @@
+//+build ignore
+
+// Copyright (c) 2012, 2013 Ugorji Nwoke. All rights reserved.
+// Use of this source code is governed by a BSD-style license found in the LICENSE file.
+
+package main
+
+import (
+	"bytes"
+	"go/format"
+	"os"
+	"strings"
+	"text/template"
+)
+
+const tmplstr = `
+// Copyright (c) 2012, 2013 Ugorji Nwoke. All rights reserved.
+// Use of this source code is governed by a BSD-style license found in the LICENSE file.
+
+// ************************************************************
+// DO NOT EDIT. 
+// THIS FILE IS GENERATED BY RUNNING: go run gen-fast-path.go
+// ************************************************************
+
+package codec
+
+// Fast path functions try to create a fast path encode or decode implementation
+// for common maps and slices.
+//
+// We define the functions and register then in this single file
+// so as not to pollute the encode.go and decode.go, and create a dependency in there.
+// This file can be omitted without causing a build failure.
+//
+// The advantage of fast paths is:
+//    - Many calls bypass reflection altogether
+// 
+// Currently support
+//    - slice of all builtin types,
+//    - map of all builtin types to string or interface value
+//    - symetrical maps of all builtin types (e.g. str-str, uint8-uint8)
+// This should provide adequate "typical" implementations.
+
+import (
+	"reflect"
+)
+
+func init() {
+	if !fastpathEnabled {
+		return // basically disable the fast path checks (since accessing empty map is basically free)
+	}
+	fdx := func(i interface{}, fd func(*decFnInfo, reflect.Value)) {
+		fastpathsDec[reflect.ValueOf(reflect.TypeOf(i)).Pointer()] = fd
+	}
+	fex := func(i interface{}, fe func(*encFnInfo, reflect.Value)) {
+		fastpathsEnc[reflect.ValueOf(reflect.TypeOf(i)).Pointer()] = fe
+	}
+	
+	{{range .Values}}{{if .Encode}}{{if .Slice }}
+	fex([]{{ .Elem }}(nil), (*encFnInfo).{{ .MethodName }}){{end}}{{end}}{{end}}
+
+	{{range .Values}}{{if .Encode}}{{if not .Slice }}
+	fex(map[{{ .MapKey }}]{{ .Elem }}(nil), (*encFnInfo).{{ .MethodName }}){{end}}{{end}}{{end}}
+
+	{{range .Values}}{{if not .Encode}}{{if .Slice }}
+	fdx([]{{ .Elem }}(nil), (*decFnInfo).{{ .MethodName }}){{end}}{{end}}{{end}}
+
+	{{range .Values}}{{if not .Encode}}{{if not .Slice }}
+	fdx(map[{{ .MapKey }}]{{ .Elem }}(nil), (*decFnInfo).{{ .MethodName }}){{end}}{{end}}{{end}}
+
+}
+
+// -- encode
+
+{{range .Values}}{{if .Encode}}{{if .Slice }}
+
+func (f *encFnInfo) {{ .MethodName }}(rv reflect.Value) {
+	v := rv.Interface().([]{{ .Elem }})
+	f.ee.encodeArrayPreamble(len(v))
+	for _, v2 := range v {
+		{{ encmd .Elem "v2"}}
+	}
+}
+
+{{end}}{{end}}{{end}}
+
+{{range .Values}}{{if .Encode}}{{if not .Slice }}
+
+func (f *encFnInfo) {{ .MethodName }}(rv reflect.Value) {
+	v := rv.Interface().(map[{{ .MapKey }}]{{ .Elem }})
+	f.ee.encodeMapPreamble(len(v))
+	{{if eq .MapKey "string"}}asSymbols := f.e.h.AsSymbols&AsSymbolMapStringKeysFlag != 0{{end}}
+	for k2, v2 := range v {
+		{{if eq .MapKey "string"}}if asSymbols {
+			f.ee.encodeSymbol(k2)
+		} else {
+			f.ee.encodeString(c_UTF8, k2)
+		}{{else}}{{ encmd .MapKey "k2"}}{{end}}
+		{{ encmd .Elem "v2"}}
+	}
+}
+
+{{end}}{{end}}{{end}}
+
+// -- decode
+
+{{range .Values}}{{if not .Encode}}{{if .Slice }}
+
+func (f *decFnInfo) {{ .MethodName }}(rv reflect.Value) {
+	v := rv.Addr().Interface().(*[]{{ .Elem }})
+	var s []{{ .Elem }}
+	vtype := f.dd.currentEncodedType()
+	if vtype == valueTypeNil {
+		*v = s
+		return
+	}
+
+	_, containerLenS := decContLens(f.dd, vtype)
+	s = *v
+	if s == nil {
+		s = make([]{{ .Elem }}, containerLenS, containerLenS)
+	} else if containerLenS > cap(s) {
+		if f.array {
+			decErr(msgDecCannotExpandArr, cap(s), containerLenS)
+		}
+		s = make([]{{ .Elem }}, containerLenS, containerLenS)
+		copy(s, *v)
+	} else if containerLenS > len(s) {
+		s = s[:containerLenS]
+	}
+	for j := 0; j < containerLenS; j++ {
+		{{ if eq .Elem "interface{}" }}f.d.decode(&s[j])
+		{{ else }}f.dd.initReadNext()
+		s[j] = {{ decmd .Elem }}
+		{{ end }}
+	}
+	*v = s
+}
+
+{{end}}{{end}}{{end}}
+
+
+{{range .Values}}{{if not .Encode}}{{if not .Slice }}
+
+func (f *decFnInfo) {{ .MethodName }}(rv reflect.Value) {
+	v := rv.Addr().Interface().(*map[{{ .MapKey }}]{{ .Elem }})
+	var m map[{{ .MapKey }}]{{ .Elem }}
+	vtype := f.dd.currentEncodedType()
+	if vtype == valueTypeNil {
+		*v = m
+		return
+	}
+
+	containerLen := f.dd.readMapLen()
+	m = *v
+	if m == nil {
+		m = make(map[{{ .MapKey }}]{{ .Elem }}, containerLen)
+		*v = m
+	}
+	for j := 0; j < containerLen; j++ {
+		{{ if eq .MapKey "interface{}" }}var mk interface{}
+		f.d.decode(&mk)
+		// special case if a byte array.
+		if bv, bok := mk.([]byte); bok {
+			mk = string(bv)
+		}
+		{{ else }}f.dd.initReadNext()
+		mk := {{ decmd .MapKey }}
+		{{ end }}
+		mv := m[mk]
+		{{ if eq .Elem "interface{}" }}f.d.decode(&mv)
+		{{ else }}f.dd.initReadNext()
+		mv = {{ decmd .Elem }}
+		{{ end }}
+		m[mk] = mv
+	}
+}
+
+{{end}}{{end}}{{end}}
+
+`
+
+type genInfo struct {
+	Slice  bool
+	Encode bool
+	MapKey string
+	Elem   string
+}
+
+func EncCommandAsString(s string, vname string) string {
+	switch s {
+	case "uint", "uint8", "uint16", "uint31", "uint64":
+		return "f.ee.encodeUint(uint64(" + vname + "))"
+	case "int", "int8", "int16", "int31", "int64":
+		return "f.ee.encodeInt(int64(" + vname + "))"
+	case "string":
+		return "f.ee.encodeString(c_UTF8, " + vname + ")"
+	case "float32":
+		return "f.ee.encodeFloat32(" + vname + ")"
+	case "float64":
+		return "f.ee.encodeFloat64(" + vname + ")"
+	case "bool":
+		return "f.ee.encodeBool(" + vname + ")"
+	case "symbol":
+		return "f.ee.encodeSymbol(" + vname + ")"
+	default:
+		return "f.e.encode(" + vname + ")"
+	}
+}
+
+func DecCommandAsString(s string) string {
+	switch s {
+	case "uint":
+		return "uint(f.dd.decodeUint(uintBitsize))"
+	case "uint8":
+		return "uint8(f.dd.decodeUint(8))"
+	case "uint16":
+		return "uint16(f.dd.decodeUint(16))"
+	case "uint32":
+		return "uint32(f.dd.decodeUint(32))"
+	case "uint64":
+		return "f.dd.decodeUint(64)"
+	case "int":
+		return "int(f.dd.decodeInt(intBitsize))"
+	case "int8":
+		return "int8(f.dd.decodeInt(8))"
+	case "int16":
+		return "int16(f.dd.decodeInt(16))"
+	case "int32":
+		return "int32(f.dd.decodeInt(32))"
+	case "int64":
+		return "f.dd.decodeInt(64)"
+
+	case "string":
+		return "f.dd.decodeString()"
+	case "float32":
+		return "float32(f.dd.decodeFloat(true))"
+	case "float64":
+		return "f.dd.decodeFloat(false)"
+	case "bool":
+		return "f.dd.decodeBool()"
+	default:
+		panic("unknown type for decode: " + s)
+	}
+
+}
+
+func (x *genInfo) MethodName() string {
+	var name []byte
+	name = append(name, "fast"...)
+	if x.Encode {
+		name = append(name, "Enc"...)
+	} else {
+		name = append(name, "Dec"...)
+	}
+	if x.Slice {
+		name = append(name, "Slice"...)
+	} else {
+		name = append(name, "Map"...)
+		name = append(name, titleCaseName(x.MapKey)...)
+	}
+
+	name = append(name, titleCaseName(x.Elem)...)
+	return string(name)
+}
+
+func titleCaseName(s string) string {
+	switch s {
+	case "interface{}":
+		return "Intf"
+	default:
+		return strings.ToUpper(s[0:1]) + s[1:]
+	}
+}
+
+type genTmpl struct {
+	Values []genInfo
+}
+
+func main() {
+	types := []string{
+		"interface{}",
+		"string",
+		"float32",
+		"float64",
+		"uint",
+		"uint8",
+		"uint16",
+		"uint32",
+		"uint64",
+		"int",
+		"int8",
+		"int16",
+		"int32",
+		"int64",
+		"bool",
+	}
+	var gt genTmpl
+	for _, s := range types {
+		if s != "uint8" { // do not generate fast path for slice of bytes. Treat specially already.
+			gt.Values = append(gt.Values, genInfo{true, true, "", s})
+			gt.Values = append(gt.Values, genInfo{true, false, "", s})
+		}
+		gt.Values = append(gt.Values, genInfo{false, true, s, "interface{}"})
+		gt.Values = append(gt.Values, genInfo{false, false, s, "interface{}"})
+		gt.Values = append(gt.Values, genInfo{false, true, s, "string"})
+		gt.Values = append(gt.Values, genInfo{false, false, s, "string"})
+		if s != "string" && s != "interface{}" {
+			gt.Values = append(gt.Values, genInfo{false, true, s, s})
+			gt.Values = append(gt.Values, genInfo{false, false, s, s})
+		}
+	}
+
+	funcs := make(template.FuncMap)
+	// funcs["haspfx"] = strings.HasPrefix
+	funcs["encmd"] = EncCommandAsString
+	funcs["decmd"] = DecCommandAsString
+
+	t := template.New("")
+	t = t.Funcs(funcs)
+
+	t, err := t.Parse(tmplstr)
+	if err != nil {
+		panic(err)
+	}
+
+	var out bytes.Buffer
+	err = t.Execute(&out, &gt)
+	if err != nil {
+		panic(err)
+	}
+	// os.Stdout.Write(out.Bytes())
+	bout, err := format.Source(out.Bytes())
+	if err != nil {
+		panic(err)
+	}
+	os.Stdout.Write(bout)
+}

+ 13 - 66
codec/helper.go

@@ -35,16 +35,13 @@ const (
 	// This flag (useMapForCodecCache) controls which is used.
 	useMapForCodecCache = false
 
-	// For some common container types, we can short-circuit an elaborate
-	// reflection dance and call encode/decode directly.
-	// The currently supported types are:
-	//    - slices of strings, or id's (int64,uint64) or interfaces.
-	//    - maps of str->str, str->intf, id(int64,uint64)->intf, intf->intf
-	shortCircuitReflectToFastPath = true
-
 	// for debugging, set this to false, to catch panic traces.
 	// Note that this will always cause rpc tests to fail, since they need io.EOF sent via panic.
 	recoverPanicToErr = true
+
+	// Fast path functions try to create a fast path encode or decode implementation
+	// for common maps and slices, by by-passing reflection altogether.
+	fastpathEnabled = true
 )
 
 type charEncoding uint8
@@ -89,71 +86,21 @@ var (
 	intfSliceTyp = reflect.TypeOf([]interface{}(nil))
 	intfTyp      = intfSliceTyp.Elem()
 
-	strSliceTyp     = reflect.TypeOf([]string(nil))
-	boolSliceTyp    = reflect.TypeOf([]bool(nil))
-	uintSliceTyp    = reflect.TypeOf([]uint(nil))
-	uint8SliceTyp   = reflect.TypeOf([]uint8(nil))
-	uint16SliceTyp  = reflect.TypeOf([]uint16(nil))
-	uint32SliceTyp  = reflect.TypeOf([]uint32(nil))
-	uint64SliceTyp  = reflect.TypeOf([]uint64(nil))
-	intSliceTyp     = reflect.TypeOf([]int(nil))
-	int8SliceTyp    = reflect.TypeOf([]int8(nil))
-	int16SliceTyp   = reflect.TypeOf([]int16(nil))
-	int32SliceTyp   = reflect.TypeOf([]int32(nil))
-	int64SliceTyp   = reflect.TypeOf([]int64(nil))
-	float32SliceTyp = reflect.TypeOf([]float32(nil))
-	float64SliceTyp = reflect.TypeOf([]float64(nil))
-
-	mapIntfIntfTyp = reflect.TypeOf(map[interface{}]interface{}(nil))
-	mapStrIntfTyp  = reflect.TypeOf(map[string]interface{}(nil))
-	mapStrStrTyp   = reflect.TypeOf(map[string]string(nil))
-
-	mapIntIntfTyp    = reflect.TypeOf(map[int]interface{}(nil))
-	mapInt64IntfTyp  = reflect.TypeOf(map[int64]interface{}(nil))
-	mapUintIntfTyp   = reflect.TypeOf(map[uint]interface{}(nil))
-	mapUint64IntfTyp = reflect.TypeOf(map[uint64]interface{}(nil))
-
-	stringTyp = reflect.TypeOf("")
-	timeTyp   = reflect.TypeOf(time.Time{})
-	rawExtTyp = reflect.TypeOf(RawExt{})
+	stringTyp     = reflect.TypeOf("")
+	timeTyp       = reflect.TypeOf(time.Time{})
+	rawExtTyp     = reflect.TypeOf(RawExt{})
+	uint8SliceTyp = reflect.TypeOf([]uint8(nil))
 
 	mapBySliceTyp        = reflect.TypeOf((*MapBySlice)(nil)).Elem()
 	binaryMarshalerTyp   = reflect.TypeOf((*binaryMarshaler)(nil)).Elem()
 	binaryUnmarshalerTyp = reflect.TypeOf((*binaryUnmarshaler)(nil)).Elem()
 
-	rawExtTypId = reflect.ValueOf(rawExtTyp).Pointer()
-	intfTypId   = reflect.ValueOf(intfTyp).Pointer()
-	timeTypId   = reflect.ValueOf(timeTyp).Pointer()
-
-	intfSliceTypId = reflect.ValueOf(intfSliceTyp).Pointer()
-	strSliceTypId  = reflect.ValueOf(strSliceTyp).Pointer()
-
-	boolSliceTypId    = reflect.ValueOf(boolSliceTyp).Pointer()
-	uintSliceTypId    = reflect.ValueOf(uintSliceTyp).Pointer()
-	uint8SliceTypId   = reflect.ValueOf(uint8SliceTyp).Pointer()
-	uint16SliceTypId  = reflect.ValueOf(uint16SliceTyp).Pointer()
-	uint32SliceTypId  = reflect.ValueOf(uint32SliceTyp).Pointer()
-	uint64SliceTypId  = reflect.ValueOf(uint64SliceTyp).Pointer()
-	intSliceTypId     = reflect.ValueOf(intSliceTyp).Pointer()
-	int8SliceTypId    = reflect.ValueOf(int8SliceTyp).Pointer()
-	int16SliceTypId   = reflect.ValueOf(int16SliceTyp).Pointer()
-	int32SliceTypId   = reflect.ValueOf(int32SliceTyp).Pointer()
-	int64SliceTypId   = reflect.ValueOf(int64SliceTyp).Pointer()
-	float32SliceTypId = reflect.ValueOf(float32SliceTyp).Pointer()
-	float64SliceTypId = reflect.ValueOf(float64SliceTyp).Pointer()
-
-	mapStrStrTypId     = reflect.ValueOf(mapStrStrTyp).Pointer()
-	mapIntfIntfTypId   = reflect.ValueOf(mapIntfIntfTyp).Pointer()
-	mapStrIntfTypId    = reflect.ValueOf(mapStrIntfTyp).Pointer()
-	mapIntIntfTypId    = reflect.ValueOf(mapIntIntfTyp).Pointer()
-	mapInt64IntfTypId  = reflect.ValueOf(mapInt64IntfTyp).Pointer()
-	mapUintIntfTypId   = reflect.ValueOf(mapUintIntfTyp).Pointer()
-	mapUint64IntfTypId = reflect.ValueOf(mapUint64IntfTyp).Pointer()
-	// Id = reflect.ValueOf().Pointer()
-	// mapBySliceTypId  = reflect.ValueOf(mapBySliceTyp).Pointer()
+	uint8SliceTypId = reflect.ValueOf(uint8SliceTyp).Pointer()
+	rawExtTypId     = reflect.ValueOf(rawExtTyp).Pointer()
+	intfTypId       = reflect.ValueOf(intfTyp).Pointer()
+	timeTypId       = reflect.ValueOf(timeTyp).Pointer()
 
-	binaryMarshalerTypId   = reflect.ValueOf(binaryMarshalerTyp).Pointer()
-	binaryUnmarshalerTypId = reflect.ValueOf(binaryUnmarshalerTyp).Pointer()
+	// mapBySliceTypId  = reflect.ValueOf(mapBySliceTyp).Pointer()
 
 	intBitsize  uint8 = uint8(reflect.TypeOf(int(0)).Bits())
 	uintBitsize uint8 = uint8(reflect.TypeOf(uint(0)).Bits())