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)
 	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)
 	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)
 	fnBenchmarkDecode(b, "simple", benchTs, fnSimpleEncodeFn, fnSimpleDecodeFn, fnBenchNewTs)
 }
 }
 
 

+ 5 - 2
codec/codecs_test.go

@@ -55,6 +55,8 @@ var (
 	_                         = fmt.Printf
 	_                         = fmt.Printf
 	skipVerifyVal interface{} = &(struct{}{})
 	skipVerifyVal interface{} = &(struct{}{})
 
 
+	testMapStrIntfTyp = reflect.TypeOf(map[string]interface{}(nil))
+
 	// For Go Time, do not use a descriptive timezone.
 	// For Go Time, do not use a descriptive timezone.
 	// It's unnecessary, and makes it harder to do a reflect.DeepEqual.
 	// 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.
 	// 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) {
 	// func TestMsgpackNilStringMap(t *testing.T) {
 	var oldMapType reflect.Type
 	var oldMapType reflect.Type
 	v := h.getBasicHandle()
 	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
 	//skip time.Time, []interface{} containing time.Time, last map, and newStruc
 	doTestCodecTableOne(t, true, h, table[:idxTime], tableTestNilVerify[:idxTime])
 	doTestCodecTableOne(t, true, h, table[:idxTime], tableTestNilVerify[:idxTime])
@@ -856,7 +859,7 @@ func doTestMsgpackPythonGenStreams(t *testing.T) {
 			failT(t)
 			failT(t)
 			continue
 			continue
 		}
 		}
-		testMsgpackH.MapType = mapStrIntfTyp
+		testMsgpackH.MapType = testMapStrIntfTyp
 
 
 		var v1 interface{}
 		var v1 interface{}
 		if err = testUnmarshal(&v1, bss, testMsgpackH); err != nil {
 		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"
 	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
 // decReader abstracts the reading source, allowing implementations that can
 // read from an io.Reader or directly off a byte slice with zero-copying.
 // read from an io.Reader or directly off a byte slice with zero-copying.
 type decReader interface {
 type decReader interface {
@@ -185,6 +188,13 @@ type decFnInfo struct {
 	array bool
 	array bool
 }
 }
 
 
+// ----------------------------------------
+
+type decFn struct {
+	i *decFnInfo
+	f func(*decFnInfo, reflect.Value)
+}
+
 func (f *decFnInfo) builtin(rv reflect.Value) {
 func (f *decFnInfo) builtin(rv reflect.Value) {
 	f.dd.decodeBuiltin(f.ti.rtid, rv.Addr().Interface())
 	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) {
 func (f *decFnInfo) kInterface(rv reflect.Value) {
 	// debugf("\t===> kInterface")
 	// debugf("\t===> kInterface")
 	if !rv.IsNil() {
 	if !rv.IsNil() {
-		f.d.decodeValue(rv.Elem())
+		f.d.decodeValue(rv.Elem(), decFn{})
 		return
 		return
 	}
 	}
 	// nil interface:
 	// nil interface:
@@ -343,7 +353,7 @@ func (f *decFnInfo) kInterface(rv reflect.Value) {
 	}
 	}
 	if decodeFurther {
 	if decodeFurther {
 		if useRvn {
 		if useRvn {
-			f.d.decodeValue(rvn)
+			f.d.decodeValue(rvn, decFn{})
 		} else if v != nil {
 		} else if v != nil {
 			// this v is a pointer, so we need to dereference it when done
 			// this v is a pointer, so we need to dereference it when done
 			f.d.decode(v)
 			f.d.decode(v)
@@ -375,7 +385,7 @@ func (f *decFnInfo) kStruct(rv reflect.Value) {
 			if k := fti.indexForEncName(rvkencname); k > -1 {
 			if k := fti.indexForEncName(rvkencname); k > -1 {
 				sfik := tisfi[k]
 				sfik := tisfi[k]
 				if sfik.i != -1 {
 				if sfik.i != -1 {
-					f.d.decodeValue(rv.Field(int(sfik.i)))
+					f.d.decodeValue(rv.Field(int(sfik.i)), decFn{})
 				} else {
 				} else {
 					f.d.decEmbeddedField(rv, sfik.is)
 					f.d.decEmbeddedField(rv, sfik.is)
 				}
 				}
@@ -386,7 +396,7 @@ func (f *decFnInfo) kStruct(rv reflect.Value) {
 						rvkencname)
 						rvkencname)
 				} else {
 				} else {
 					var nilintf0 interface{}
 					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
 				break
 			}
 			}
 			if si.i != -1 {
 			if si.i != -1 {
-				f.d.decodeValue(rv.Field(int(si.i)))
+				f.d.decodeValue(rv.Field(int(si.i)), decFn{})
 			} else {
 			} else {
 				f.d.decEmbeddedField(rv, si.is)
 				f.d.decEmbeddedField(rv, si.is)
 			}
 			}
@@ -409,7 +419,7 @@ func (f *decFnInfo) kStruct(rv reflect.Value) {
 			// read remaining values and throw away
 			// read remaining values and throw away
 			for j := len(fti.sfip); j < containerLen; j++ {
 			for j := len(fti.sfip); j < containerLen; j++ {
 				var nilintf0 interface{}
 				var nilintf0 interface{}
-				f.d.decodeValue(reflect.ValueOf(&nilintf0).Elem())
+				f.d.decodeValue(reflect.ValueOf(&nilintf0).Elem(), decFn{})
 			}
 			}
 		}
 		}
 	} else {
 	} 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)
 	containerLen, containerLenS := decContLens(f.dd, currEncodedType)
 
 
 	// an array can never return a nil slice. so no need to check f.array here.
 	// 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)
 		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++ {
 	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) {
 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()
 	containerLen := f.dd.readMapLen()
 
 
 	if rv.IsNil() {
 	if rv.IsNil() {
@@ -514,12 +495,19 @@ func (f *decFnInfo) kMap(rv reflect.Value) {
 
 
 	ktype, vtype := f.ti.rt.Key(), f.ti.rt.Elem()
 	ktype, vtype := f.ti.rt.Key(), f.ti.rt.Elem()
 	ktypeId := reflect.ValueOf(ktype).Pointer()
 	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++ {
 	for j := 0; j < containerLen; j++ {
 		rvk := reflect.New(ktype).Elem()
 		rvk := reflect.New(ktype).Elem()
-		f.d.decodeValue(rvk)
+		f.d.decodeValue(rvk, keyFn)
 
 
 		// special case if a byte array.
 		// special case if a byte array.
-		// if ktype == intfTyp {
 		if ktypeId == intfTypId {
 		if ktypeId == intfTypId {
 			rvk = rvk.Elem()
 			rvk = rvk.Elem()
 			if rvk.Type() == uint8SliceTyp {
 			if rvk.Type() == uint8SliceTyp {
@@ -531,18 +519,11 @@ func (f *decFnInfo) kMap(rv reflect.Value) {
 			rvv = reflect.New(vtype).Elem()
 			rvv = reflect.New(vtype).Elem()
 		}
 		}
 
 
-		f.d.decodeValue(rvv)
+		f.d.decodeValue(rvv, valFn)
 		rv.SetMapIndex(rvk, rvv)
 		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.
 // A Decoder reads and decodes an object from an input stream in the codec format.
 type Decoder struct {
 type Decoder struct {
 	r decReader
 	r decReader
@@ -640,7 +621,7 @@ func (d *Decoder) decode(iv interface{}) {
 
 
 	case reflect.Value:
 	case reflect.Value:
 		d.chkPtrValue(v)
 		d.chkPtrValue(v)
-		d.decodeValue(v.Elem())
+		d.decodeValue(v.Elem(), decFn{})
 
 
 	case *string:
 	case *string:
 		*v = d.d.decodeString()
 		*v = d.d.decodeString()
@@ -673,34 +654,17 @@ func (d *Decoder) decode(iv interface{}) {
 	case *[]byte:
 	case *[]byte:
 		*v, _ = d.d.decodeBytes(*v)
 		*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{}:
 	case *interface{}:
-		d.decodeValue(reflect.ValueOf(iv).Elem())
+		d.decodeValue(reflect.ValueOf(iv).Elem(), decFn{})
 
 
 	default:
 	default:
 		rv := reflect.ValueOf(iv)
 		rv := reflect.ValueOf(iv)
 		d.chkPtrValue(rv)
 		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()
 	d.d.initReadNext()
 
 
 	if d.d.tryDecodeAsNil() {
 	if d.d.tryDecodeAsNil() {
@@ -729,14 +693,20 @@ func (d *Decoder) decodeValue(rv reflect.Value) {
 		rv = rv.Elem()
 		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()
 	rtid := reflect.ValueOf(rt).Pointer()
 
 
 	// retrieve or register a focus'ed function for this type
 	// retrieve or register a focus'ed function for this type
 	// to eliminate need to do the retrieval multiple times
 	// 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) }
 	// if d.f == nil && d.s == nil { debugf("---->Creating new dec f map for type: %v\n", rt) }
-	var fn decFn
 	var ok bool
 	var ok bool
 	if useMapForCodecCache {
 	if useMapForCodecCache {
 		fn, ok = d.f[rtid]
 		fn, ok = d.f[rtid]
@@ -770,6 +740,10 @@ func (d *Decoder) decodeValue(rv reflect.Value) {
 			fn.f = (*decFnInfo).ext
 			fn.f = (*decFnInfo).ext
 		} else if supportBinaryMarshal && fi.ti.unm {
 		} else if supportBinaryMarshal && fi.ti.unm {
 			fn.f = (*decFnInfo).binaryMarshal
 			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 {
 		} else {
 			switch rk := rt.Kind(); rk {
 			switch rk := rt.Kind(); rk {
 			case reflect.String:
 			case reflect.String:
@@ -828,8 +802,6 @@ func (d *Decoder) decodeValue(rv reflect.Value) {
 		}
 		}
 	}
 	}
 
 
-	fn.f(fn.i, rv)
-
 	return
 	return
 }
 }
 
 
@@ -862,169 +834,11 @@ func (d *Decoder) decEmbeddedField(rv reflect.Value, index []int) {
 		}
 		}
 		rv = rv.Field(j)
 		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) {
 func decContLens(dd decDriver, currEncodedType valueType) (containerLen, containerLenS int) {
 	if currEncodedType == valueTypeInvalid {
 	if currEncodedType == valueTypeInvalid {
 		currEncodedType = dd.currentEncodedType()
 		currEncodedType = dd.currentEncodedType()
@@ -1046,3 +860,11 @@ func decContLens(dd decDriver, currEncodedType valueType) (containerLen, contain
 func decErr(format string, params ...interface{}) {
 func decErr(format string, params ...interface{}) {
 	doPanic(msgTagDec, format, params...)
 	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
 	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 {
 type encWriter interface {
 	writeUint16(uint16)
 	writeUint16(uint16)
 	writeUint32(uint32)
 	writeUint32(uint32)
@@ -368,23 +371,6 @@ func (f *encFnInfo) kSlice(rv reflect.Value) {
 		return
 		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.
 	// If in this method, then there was no extension function defined.
 	// So it's okay to treat as []byte.
 	// So it's okay to treat as []byte.
 	if f.ti.rtid == uint8SliceTypId || f.ti.rt.Elem().Kind() == reflect.Uint8 {
 	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 {
 	if l == 0 {
 		return
 		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++ {
 	for j := 0; j < l; j++ {
 		// TODO: Consider perf implication of encoding odd index values as symbols if type is string
 		// 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()
 	l := rv.Len()
 	// Handle an array of bytes specially (in line with what is done for slices)
 	// 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 {
 		if l == 0 {
 			f.ee.encodeStringBytes(c_RAW, nil)
 			f.ee.encodeStringBytes(c_RAW, nil)
 			return
 			return
@@ -448,9 +441,13 @@ func (f *encFnInfo) kArray(rv reflect.Value) {
 	if l == 0 {
 	if l == 0 {
 		return
 		return
 	}
 	}
+	for rtelem.Kind() == reflect.Ptr {
+		rtelem = rtelem.Elem()
+	}
+	fn := f.e.getEncFn(rtelem)
 	for j := 0; j < l; j++ {
 	for j := 0; j < l; j++ {
 		// TODO: Consider perf implication of encoding odd index values as symbols if type is string
 		// 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 {
 			} else {
 				ee.encodeString(c_UTF8, encnames[j])
 				ee.encodeString(c_UTF8, encnames[j])
 			}
 			}
-			e.encodeValue(rvals[j])
+			e.encodeValue(rvals[j], encFn{})
 		}
 		}
 	} else {
 	} else {
 		f.ee.encodeArrayPreamble(newlen)
 		f.ee.encodeArrayPreamble(newlen)
 		for j := 0; j < newlen; j++ {
 		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()
 		f.ee.encodeNil()
 		return
 		return
 	}
 	}
-	f.e.encodeValue(rv.Elem())
+	f.e.encodeValue(rv.Elem(), encFn{})
 }
 }
 
 
 func (f *encFnInfo) kMap(rv reflect.Value) {
 func (f *encFnInfo) kMap(rv reflect.Value) {
@@ -532,37 +529,32 @@ func (f *encFnInfo) kMap(rv reflect.Value) {
 		return
 		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()
 	l := rv.Len()
 	f.ee.encodeMapPreamble(l)
 	f.ee.encodeMapPreamble(l)
 	if l == 0 {
 	if l == 0 {
 		return
 		return
 	}
 	}
-	// keyTypeIsString := f.ti.rt.Key().Kind() == reflect.String
-	keyTypeIsString := f.ti.rt.Key() == stringTyp
 	var asSymbols bool
 	var asSymbols bool
+	// determine the underlying key and val encFn's for the map.
+	// This eliminates some work which is done for each loop iteration i.e.
+	// rv.Type(), ref.ValueOf(rt).Pointer(), then check map/list for fn.
+	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 {
 	if keyTypeIsString {
 		asSymbols = f.e.h.AsSymbols&AsSymbolMapStringKeysFlag != 0
 		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()
 	mks := rv.MapKeys()
 	// for j, lmks := 0, len(mks); j < lmks; j++ {
 	// for j, lmks := 0, len(mks); j < lmks; j++ {
 	for j := range mks {
 	for j := range mks {
@@ -573,9 +565,9 @@ func (f *encFnInfo) kMap(rv reflect.Value) {
 				f.ee.encodeString(c_UTF8, mks[j].String())
 				f.ee.encodeString(c_UTF8, mks[j].String())
 			}
 			}
 		} else {
 		} 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()
 		e.e.encodeNil()
 
 
 	case reflect.Value:
 	case reflect.Value:
-		e.encodeValue(v)
+		e.encodeValue(v, encFn{})
 
 
 	case string:
 	case string:
 		e.e.encodeString(c_UTF8, v)
 		e.e.encodeString(c_UTF8, v)
@@ -737,28 +729,9 @@ func (e *Encoder) encode(iv interface{}) {
 	case float64:
 	case float64:
 		e.e.encodeFloat64(v)
 		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:
 	case []uint8:
 		e.e.encodeStringBytes(c_RAW, v)
 		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:
 	case *string:
 		e.e.encodeString(c_UTF8, *v)
 		e.e.encodeString(c_UTF8, *v)
 	case *bool:
 	case *bool:
@@ -788,34 +761,16 @@ func (e *Encoder) encode(iv interface{}) {
 	case *float64:
 	case *float64:
 		e.e.encodeFloat64(*v)
 		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:
 	case *[]uint8:
 		e.e.encodeStringBytes(c_RAW, *v)
 		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:
 	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 {
 	for rv.Kind() == reflect.Ptr {
 		if rv.IsNil() {
 		if rv.IsNil() {
 			e.e.encodeNil()
 			e.e.encodeNil()
@@ -824,15 +779,22 @@ func (e *Encoder) encodeValue(rv reflect.Value) {
 		rv = rv.Elem()
 		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) }
 	// 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
 	var ok bool
 	if useMapForCodecCache {
 	if useMapForCodecCache {
 		fn, ok = e.f[rtid]
 		fn, ok = e.f[rtid]
 	} else {
 	} else {
+		// if len(e.x) > 0 && len(e.x)%10 == 0 {
+		// 	println("len(e.x) ", len(e.x))
+		// }
 		for i, v := range e.x {
 		for i, v := range e.x {
 			if v == rtid {
 			if v == rtid {
 				fn, ok = e.s[i], true
 				fn, ok = e.s[i], true
@@ -853,6 +815,10 @@ func (e *Encoder) encodeValue(rv reflect.Value) {
 			fn.f = (*encFnInfo).ext
 			fn.f = (*encFnInfo).ext
 		} else if supportBinaryMarshal && fi.ti.m {
 		} else if supportBinaryMarshal && fi.ti.m {
 			fn.f = (*encFnInfo).binaryMarshal
 			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 {
 		} else {
 			switch rk := rt.Kind(); rk {
 			switch rk := rt.Kind(); rk {
 			case reflect.Bool:
 			case reflect.Bool:
@@ -887,7 +853,7 @@ func (e *Encoder) encodeValue(rv reflect.Value) {
 		}
 		}
 		if useMapForCodecCache {
 		if useMapForCodecCache {
 			if e.f == nil {
 			if e.f == nil {
-				e.f = make(map[uintptr]encFn, 16)
+				e.f = make(map[uintptr]encFn, 64)
 			}
 			}
 			e.f[rtid] = fn
 			e.f[rtid] = fn
 		} else {
 		} else {
@@ -895,9 +861,7 @@ func (e *Encoder) encodeValue(rv reflect.Value) {
 			e.x = append(e.x, rtid)
 			e.x = append(e.x, rtid)
 		}
 		}
 	}
 	}
-
-	fn.f(fn.i, rv)
-
+	return
 }
 }
 
 
 func (e *Encoder) encRawExt(re RawExt) {
 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{}) {
 func encErr(format string, params ...interface{}) {
 	doPanic(msgTagEnc, format, params...)
 	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.
 // 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.
 // 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.
 	// This flag (useMapForCodecCache) controls which is used.
 	useMapForCodecCache = false
 	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.
 	// 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.
 	// Note that this will always cause rpc tests to fail, since they need io.EOF sent via panic.
 	recoverPanicToErr = true
 	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
 type charEncoding uint8
@@ -89,71 +86,21 @@ var (
 	intfSliceTyp = reflect.TypeOf([]interface{}(nil))
 	intfSliceTyp = reflect.TypeOf([]interface{}(nil))
 	intfTyp      = intfSliceTyp.Elem()
 	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()
 	mapBySliceTyp        = reflect.TypeOf((*MapBySlice)(nil)).Elem()
 	binaryMarshalerTyp   = reflect.TypeOf((*binaryMarshaler)(nil)).Elem()
 	binaryMarshalerTyp   = reflect.TypeOf((*binaryMarshaler)(nil)).Elem()
 	binaryUnmarshalerTyp = reflect.TypeOf((*binaryUnmarshaler)(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())
 	intBitsize  uint8 = uint8(reflect.TypeOf(int(0)).Bits())
 	uintBitsize uint8 = uint8(reflect.TypeOf(uint(0)).Bits())
 	uintBitsize uint8 = uint8(reflect.TypeOf(uint(0)).Bits())