|
@@ -109,6 +109,7 @@ import (
|
|
|
"strconv"
|
|
"strconv"
|
|
|
"strings"
|
|
"strings"
|
|
|
"sync"
|
|
"sync"
|
|
|
|
|
+ "sync/atomic"
|
|
|
"time"
|
|
"time"
|
|
|
)
|
|
)
|
|
|
|
|
|
|
@@ -522,6 +523,11 @@ type BasicHandle struct {
|
|
|
|
|
|
|
|
intf2impls
|
|
intf2impls
|
|
|
|
|
|
|
|
|
|
+ inited uint32
|
|
|
|
|
+ _ uint32 // padding
|
|
|
|
|
+
|
|
|
|
|
+ // ---- cache line
|
|
|
|
|
+
|
|
|
RPCOptions
|
|
RPCOptions
|
|
|
|
|
|
|
|
// TimeNotBuiltin configures whether time.Time should be treated as a builtin type.
|
|
// TimeNotBuiltin configures whether time.Time should be treated as a builtin type.
|
|
@@ -553,6 +559,11 @@ type BasicHandle struct {
|
|
|
// runtime.SetFinalizer(d, (*Decoder).Close)
|
|
// runtime.SetFinalizer(d, (*Decoder).Close)
|
|
|
DoNotClose bool
|
|
DoNotClose bool
|
|
|
|
|
|
|
|
|
|
+ be bool // is handle a binary encoding?
|
|
|
|
|
+ js bool // is handle javascript handler?
|
|
|
|
|
+ n byte // first letter of handle name
|
|
|
|
|
+ _ uint16 // padding
|
|
|
|
|
+
|
|
|
// ---- cache line
|
|
// ---- cache line
|
|
|
|
|
|
|
|
DecodeOptions
|
|
DecodeOptions
|
|
@@ -562,6 +573,21 @@ type BasicHandle struct {
|
|
|
EncodeOptions
|
|
EncodeOptions
|
|
|
|
|
|
|
|
// noBuiltInTypeChecker
|
|
// noBuiltInTypeChecker
|
|
|
|
|
+
|
|
|
|
|
+ rtidFns atomicRtidFnSlice
|
|
|
|
|
+ mu sync.Mutex
|
|
|
|
|
+ // r []uintptr // rtids mapped to s above
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// basicHandle returns an initialized BasicHandle from the Handle.
|
|
|
|
|
+func basicHandle(hh Handle) (x *BasicHandle) {
|
|
|
|
|
+ x = hh.getBasicHandle()
|
|
|
|
|
+ if atomic.CompareAndSwapUint32(&x.inited, 0, 1) {
|
|
|
|
|
+ x.be = hh.isBinary()
|
|
|
|
|
+ _, x.js = hh.(*JsonHandle)
|
|
|
|
|
+ x.n = hh.Name()[0]
|
|
|
|
|
+ }
|
|
|
|
|
+ return
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
func (x *BasicHandle) getBasicHandle() *BasicHandle {
|
|
func (x *BasicHandle) getBasicHandle() *BasicHandle {
|
|
@@ -575,6 +601,243 @@ func (x *BasicHandle) getTypeInfo(rtid uintptr, rt reflect.Type) (pti *typeInfo)
|
|
|
return x.TypeInfos.get(rtid, rt)
|
|
return x.TypeInfos.get(rtid, rt)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+func findFn(s []codecRtidFn, rtid uintptr) (i uint, fn *codecFn) {
|
|
|
|
|
+ // binary search. adapted from sort/search.go.
|
|
|
|
|
+ // Note: we use goto (instead of for loop) so this can be inlined.
|
|
|
|
|
+
|
|
|
|
|
+ // h, i, j := 0, 0, len(s)
|
|
|
|
|
+ var h uint // var h, i uint
|
|
|
|
|
+ var j = uint(len(s))
|
|
|
|
|
+LOOP:
|
|
|
|
|
+ if i < j {
|
|
|
|
|
+ h = i + (j-i)/2
|
|
|
|
|
+ if s[h].rtid < rtid {
|
|
|
|
|
+ i = h + 1
|
|
|
|
|
+ } else {
|
|
|
|
|
+ j = h
|
|
|
|
|
+ }
|
|
|
|
|
+ goto LOOP
|
|
|
|
|
+ }
|
|
|
|
|
+ if i < uint(len(s)) && s[i].rtid == rtid {
|
|
|
|
|
+ fn = s[i].fn
|
|
|
|
|
+ }
|
|
|
|
|
+ return
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (c *BasicHandle) fn(rt reflect.Type, checkFastpath, checkCodecSelfer bool) (fn *codecFn) {
|
|
|
|
|
+ rtid := rt2id(rt)
|
|
|
|
|
+ sp := c.rtidFns.load()
|
|
|
|
|
+ if sp != nil {
|
|
|
|
|
+ if _, fn = findFn(sp, rtid); fn != nil {
|
|
|
|
|
+ // xdebugf("<<<< %c: found fn for %v in rtidfns of size: %v", c.n, rt, len(sp))
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ // xdebugf("#### for %c: load fn for %v in rtidfns of size: %v", c.n, rt, len(sp))
|
|
|
|
|
+ fn = new(codecFn)
|
|
|
|
|
+ fi := &(fn.i)
|
|
|
|
|
+ ti := c.getTypeInfo(rtid, rt)
|
|
|
|
|
+ fi.ti = ti
|
|
|
|
|
+
|
|
|
|
|
+ rk := reflect.Kind(ti.kind)
|
|
|
|
|
+
|
|
|
|
|
+ if checkCodecSelfer && (ti.cs || ti.csp) {
|
|
|
|
|
+ fn.fe = (*Encoder).selferMarshal
|
|
|
|
|
+ fn.fd = (*Decoder).selferUnmarshal
|
|
|
|
|
+ fi.addrF = true
|
|
|
|
|
+ fi.addrD = ti.csp
|
|
|
|
|
+ fi.addrE = ti.csp
|
|
|
|
|
+ } else if rtid == timeTypId && !c.TimeNotBuiltin {
|
|
|
|
|
+ fn.fe = (*Encoder).kTime
|
|
|
|
|
+ fn.fd = (*Decoder).kTime
|
|
|
|
|
+ } else if rtid == rawTypId {
|
|
|
|
|
+ fn.fe = (*Encoder).raw
|
|
|
|
|
+ fn.fd = (*Decoder).raw
|
|
|
|
|
+ } else if rtid == rawExtTypId {
|
|
|
|
|
+ fn.fe = (*Encoder).rawExt
|
|
|
|
|
+ fn.fd = (*Decoder).rawExt
|
|
|
|
|
+ fi.addrF = true
|
|
|
|
|
+ fi.addrD = true
|
|
|
|
|
+ fi.addrE = true
|
|
|
|
|
+ } else if xfFn := c.getExt(rtid); xfFn != nil {
|
|
|
|
|
+ fi.xfTag, fi.xfFn = xfFn.tag, xfFn.ext
|
|
|
|
|
+ fn.fe = (*Encoder).ext
|
|
|
|
|
+ fn.fd = (*Decoder).ext
|
|
|
|
|
+ fi.addrF = true
|
|
|
|
|
+ fi.addrD = true
|
|
|
|
|
+ if rk == reflect.Struct || rk == reflect.Array {
|
|
|
|
|
+ fi.addrE = true
|
|
|
|
|
+ }
|
|
|
|
|
+ } else if supportMarshalInterfaces && c.be && (ti.bm || ti.bmp) && (ti.bu || ti.bup) {
|
|
|
|
|
+ fn.fe = (*Encoder).binaryMarshal
|
|
|
|
|
+ fn.fd = (*Decoder).binaryUnmarshal
|
|
|
|
|
+ fi.addrF = true
|
|
|
|
|
+ fi.addrD = ti.bup
|
|
|
|
|
+ fi.addrE = ti.bmp
|
|
|
|
|
+ } else if supportMarshalInterfaces && !c.be && c.js && (ti.jm || ti.jmp) && (ti.ju || ti.jup) {
|
|
|
|
|
+ //If JSON, we should check JSONMarshal before textMarshal
|
|
|
|
|
+ fn.fe = (*Encoder).jsonMarshal
|
|
|
|
|
+ fn.fd = (*Decoder).jsonUnmarshal
|
|
|
|
|
+ fi.addrF = true
|
|
|
|
|
+ fi.addrD = ti.jup
|
|
|
|
|
+ fi.addrE = ti.jmp
|
|
|
|
|
+ } else if supportMarshalInterfaces && !c.be && (ti.tm || ti.tmp) && (ti.tu || ti.tup) {
|
|
|
|
|
+ fn.fe = (*Encoder).textMarshal
|
|
|
|
|
+ fn.fd = (*Decoder).textUnmarshal
|
|
|
|
|
+ fi.addrF = true
|
|
|
|
|
+ fi.addrD = ti.tup
|
|
|
|
|
+ fi.addrE = ti.tmp
|
|
|
|
|
+ } else {
|
|
|
|
|
+ if fastpathEnabled && checkFastpath && (rk == reflect.Map || rk == reflect.Slice) {
|
|
|
|
|
+ if ti.pkgpath == "" { // un-named slice or map
|
|
|
|
|
+ if idx := fastpathAV.index(rtid); idx != -1 {
|
|
|
|
|
+ fn.fe = fastpathAV[idx].encfn
|
|
|
|
|
+ fn.fd = fastpathAV[idx].decfn
|
|
|
|
|
+ fi.addrD = true
|
|
|
|
|
+ fi.addrF = false
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // use mapping for underlying type if there
|
|
|
|
|
+ var rtu reflect.Type
|
|
|
|
|
+ if rk == reflect.Map {
|
|
|
|
|
+ rtu = reflect.MapOf(ti.key, ti.elem)
|
|
|
|
|
+ } else {
|
|
|
|
|
+ rtu = reflect.SliceOf(ti.elem)
|
|
|
|
|
+ }
|
|
|
|
|
+ rtuid := rt2id(rtu)
|
|
|
|
|
+ if idx := fastpathAV.index(rtuid); idx != -1 {
|
|
|
|
|
+ xfnf := fastpathAV[idx].encfn
|
|
|
|
|
+ xrt := fastpathAV[idx].rt
|
|
|
|
|
+ fn.fe = func(e *Encoder, xf *codecFnInfo, xrv reflect.Value) {
|
|
|
|
|
+ xfnf(e, xf, xrv.Convert(xrt))
|
|
|
|
|
+ }
|
|
|
|
|
+ fi.addrD = true
|
|
|
|
|
+ fi.addrF = false // meaning it can be an address(ptr) or a value
|
|
|
|
|
+ xfnf2 := fastpathAV[idx].decfn
|
|
|
|
|
+ fn.fd = func(d *Decoder, xf *codecFnInfo, xrv reflect.Value) {
|
|
|
|
|
+ if xrv.Kind() == reflect.Ptr {
|
|
|
|
|
+ xfnf2(d, xf, xrv.Convert(reflect.PtrTo(xrt)))
|
|
|
|
|
+ } else {
|
|
|
|
|
+ xfnf2(d, xf, xrv.Convert(xrt))
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ if fn.fe == nil && fn.fd == nil {
|
|
|
|
|
+ switch rk {
|
|
|
|
|
+ case reflect.Bool:
|
|
|
|
|
+ fn.fe = (*Encoder).kBool
|
|
|
|
|
+ fn.fd = (*Decoder).kBool
|
|
|
|
|
+ case reflect.String:
|
|
|
|
|
+ fn.fe = (*Encoder).kString
|
|
|
|
|
+ fn.fd = (*Decoder).kString
|
|
|
|
|
+ case reflect.Int:
|
|
|
|
|
+ fn.fd = (*Decoder).kInt
|
|
|
|
|
+ fn.fe = (*Encoder).kInt
|
|
|
|
|
+ case reflect.Int8:
|
|
|
|
|
+ fn.fe = (*Encoder).kInt8
|
|
|
|
|
+ fn.fd = (*Decoder).kInt8
|
|
|
|
|
+ case reflect.Int16:
|
|
|
|
|
+ fn.fe = (*Encoder).kInt16
|
|
|
|
|
+ fn.fd = (*Decoder).kInt16
|
|
|
|
|
+ case reflect.Int32:
|
|
|
|
|
+ fn.fe = (*Encoder).kInt32
|
|
|
|
|
+ fn.fd = (*Decoder).kInt32
|
|
|
|
|
+ case reflect.Int64:
|
|
|
|
|
+ fn.fe = (*Encoder).kInt64
|
|
|
|
|
+ fn.fd = (*Decoder).kInt64
|
|
|
|
|
+ case reflect.Uint:
|
|
|
|
|
+ fn.fd = (*Decoder).kUint
|
|
|
|
|
+ fn.fe = (*Encoder).kUint
|
|
|
|
|
+ case reflect.Uint8:
|
|
|
|
|
+ fn.fe = (*Encoder).kUint8
|
|
|
|
|
+ fn.fd = (*Decoder).kUint8
|
|
|
|
|
+ case reflect.Uint16:
|
|
|
|
|
+ fn.fe = (*Encoder).kUint16
|
|
|
|
|
+ fn.fd = (*Decoder).kUint16
|
|
|
|
|
+ case reflect.Uint32:
|
|
|
|
|
+ fn.fe = (*Encoder).kUint32
|
|
|
|
|
+ fn.fd = (*Decoder).kUint32
|
|
|
|
|
+ case reflect.Uint64:
|
|
|
|
|
+ fn.fe = (*Encoder).kUint64
|
|
|
|
|
+ fn.fd = (*Decoder).kUint64
|
|
|
|
|
+ case reflect.Uintptr:
|
|
|
|
|
+ fn.fe = (*Encoder).kUintptr
|
|
|
|
|
+ fn.fd = (*Decoder).kUintptr
|
|
|
|
|
+ case reflect.Float32:
|
|
|
|
|
+ fn.fe = (*Encoder).kFloat32
|
|
|
|
|
+ fn.fd = (*Decoder).kFloat32
|
|
|
|
|
+ case reflect.Float64:
|
|
|
|
|
+ fn.fe = (*Encoder).kFloat64
|
|
|
|
|
+ fn.fd = (*Decoder).kFloat64
|
|
|
|
|
+ case reflect.Invalid:
|
|
|
|
|
+ fn.fe = (*Encoder).kInvalid
|
|
|
|
|
+ fn.fd = (*Decoder).kErr
|
|
|
|
|
+ case reflect.Chan:
|
|
|
|
|
+ fi.seq = seqTypeChan
|
|
|
|
|
+ fn.fe = (*Encoder).kSlice
|
|
|
|
|
+ fn.fd = (*Decoder).kSlice
|
|
|
|
|
+ case reflect.Slice:
|
|
|
|
|
+ fi.seq = seqTypeSlice
|
|
|
|
|
+ fn.fe = (*Encoder).kSlice
|
|
|
|
|
+ fn.fd = (*Decoder).kSlice
|
|
|
|
|
+ case reflect.Array:
|
|
|
|
|
+ fi.seq = seqTypeArray
|
|
|
|
|
+ fn.fe = (*Encoder).kSlice
|
|
|
|
|
+ fi.addrF = false
|
|
|
|
|
+ fi.addrD = false
|
|
|
|
|
+ rt2 := reflect.SliceOf(ti.elem)
|
|
|
|
|
+ fn.fd = func(d *Decoder, xf *codecFnInfo, xrv reflect.Value) {
|
|
|
|
|
+ d.h.fn(rt2, true, false).fd(d, xf, xrv.Slice(0, xrv.Len()))
|
|
|
|
|
+ }
|
|
|
|
|
+ // fn.fd = (*Decoder).kArray
|
|
|
|
|
+ case reflect.Struct:
|
|
|
|
|
+ if ti.anyOmitEmpty || ti.mf || ti.mfp {
|
|
|
|
|
+ fn.fe = (*Encoder).kStruct
|
|
|
|
|
+ } else {
|
|
|
|
|
+ fn.fe = (*Encoder).kStructNoOmitempty
|
|
|
|
|
+ }
|
|
|
|
|
+ fn.fd = (*Decoder).kStruct
|
|
|
|
|
+ case reflect.Map:
|
|
|
|
|
+ fn.fe = (*Encoder).kMap
|
|
|
|
|
+ fn.fd = (*Decoder).kMap
|
|
|
|
|
+ case reflect.Interface:
|
|
|
|
|
+ // encode: reflect.Interface are handled already by preEncodeValue
|
|
|
|
|
+ fn.fd = (*Decoder).kInterface
|
|
|
|
|
+ fn.fe = (*Encoder).kErr
|
|
|
|
|
+ default:
|
|
|
|
|
+ // reflect.Ptr and reflect.Interface are handled already by preEncodeValue
|
|
|
|
|
+ fn.fe = (*Encoder).kErr
|
|
|
|
|
+ fn.fd = (*Decoder).kErr
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ c.mu.Lock()
|
|
|
|
|
+ var sp2 []codecRtidFn
|
|
|
|
|
+ sp = c.rtidFns.load()
|
|
|
|
|
+ if sp == nil {
|
|
|
|
|
+ sp2 = []codecRtidFn{{rtid, fn}}
|
|
|
|
|
+ c.rtidFns.store(sp2)
|
|
|
|
|
+ // xdebugf(">>>> adding rt: %v to rtidfns of size: %v", rt, len(sp2))
|
|
|
|
|
+ // xdebugf(">>>> loading stored rtidfns of size: %v", len(c.rtidFns.load()))
|
|
|
|
|
+ } else {
|
|
|
|
|
+ idx, fn2 := findFn(sp, rtid)
|
|
|
|
|
+ if fn2 == nil {
|
|
|
|
|
+ sp2 = make([]codecRtidFn, len(sp)+1)
|
|
|
|
|
+ copy(sp2, sp[:idx])
|
|
|
|
|
+ copy(sp2[idx+1:], sp[idx:])
|
|
|
|
|
+ sp2[idx] = codecRtidFn{rtid, fn}
|
|
|
|
|
+ c.rtidFns.store(sp2)
|
|
|
|
|
+ // xdebugf(">>>> adding rt: %v to rtidfns of size: %v", rt, len(sp2))
|
|
|
|
|
+
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ c.mu.Unlock()
|
|
|
|
|
+ return
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
// Handle defines a specific encoding format. It also stores any runtime state
|
|
// Handle defines a specific encoding format. It also stores any runtime state
|
|
|
// used during an Encoding or Decoding session e.g. stored state about Types, etc.
|
|
// used during an Encoding or Decoding session e.g. stored state about Types, etc.
|
|
|
//
|
|
//
|
|
@@ -589,6 +852,8 @@ func (x *BasicHandle) getTypeInfo(rtid uintptr, rt reflect.Type) (pti *typeInfo)
|
|
|
// Such a pre-configured Handle is safe for concurrent access.
|
|
// Such a pre-configured Handle is safe for concurrent access.
|
|
|
type Handle interface {
|
|
type Handle interface {
|
|
|
Name() string
|
|
Name() string
|
|
|
|
|
+ // return the basic handle. It may not have been inited.
|
|
|
|
|
+ // Prefer to use basicHandle() helper function that ensures it has been inited.
|
|
|
getBasicHandle() *BasicHandle
|
|
getBasicHandle() *BasicHandle
|
|
|
recreateEncDriver(encDriver) bool
|
|
recreateEncDriver(encDriver) bool
|
|
|
newEncDriver(w *Encoder) encDriver
|
|
newEncDriver(w *Encoder) encDriver
|
|
@@ -1245,7 +1510,7 @@ func (x *TypeInfos) structTag(t reflect.StructTag) (s string) {
|
|
|
return
|
|
return
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-func (x *TypeInfos) find(s []rtid2ti, rtid uintptr) (i uint, ti *typeInfo) {
|
|
|
|
|
|
|
+func findTypeInfo(s []rtid2ti, rtid uintptr) (i uint, ti *typeInfo) {
|
|
|
// binary search. adapted from sort/search.go.
|
|
// binary search. adapted from sort/search.go.
|
|
|
// Note: we use goto (instead of for loop) so this can be inlined.
|
|
// Note: we use goto (instead of for loop) so this can be inlined.
|
|
|
|
|
|
|
@@ -1276,7 +1541,7 @@ LOOP:
|
|
|
func (x *TypeInfos) get(rtid uintptr, rt reflect.Type) (pti *typeInfo) {
|
|
func (x *TypeInfos) get(rtid uintptr, rt reflect.Type) (pti *typeInfo) {
|
|
|
sp := x.infos.load()
|
|
sp := x.infos.load()
|
|
|
if sp != nil {
|
|
if sp != nil {
|
|
|
- _, pti = x.find(sp, rtid)
|
|
|
|
|
|
|
+ _, pti = findTypeInfo(sp, rtid)
|
|
|
if pti != nil {
|
|
if pti != nil {
|
|
|
return
|
|
return
|
|
|
}
|
|
}
|
|
@@ -1356,20 +1621,21 @@ func (x *TypeInfos) get(rtid uintptr, rt reflect.Type) (pti *typeInfo) {
|
|
|
|
|
|
|
|
x.mu.Lock()
|
|
x.mu.Lock()
|
|
|
sp = x.infos.load()
|
|
sp = x.infos.load()
|
|
|
|
|
+ var sp2 []rtid2ti
|
|
|
if sp == nil {
|
|
if sp == nil {
|
|
|
pti = &ti
|
|
pti = &ti
|
|
|
- vs := []rtid2ti{{rtid, pti}}
|
|
|
|
|
- x.infos.store(vs)
|
|
|
|
|
|
|
+ sp2 = []rtid2ti{{rtid, pti}}
|
|
|
|
|
+ x.infos.store(sp2)
|
|
|
} else {
|
|
} else {
|
|
|
var idx uint
|
|
var idx uint
|
|
|
- idx, pti = x.find(sp, rtid)
|
|
|
|
|
|
|
+ idx, pti = findTypeInfo(sp, rtid)
|
|
|
if pti == nil {
|
|
if pti == nil {
|
|
|
pti = &ti
|
|
pti = &ti
|
|
|
- vs := make([]rtid2ti, len(sp)+1)
|
|
|
|
|
- copy(vs, sp[:idx])
|
|
|
|
|
- copy(vs[idx+1:], sp[idx:])
|
|
|
|
|
- vs[idx] = rtid2ti{rtid, pti}
|
|
|
|
|
- x.infos.store(vs)
|
|
|
|
|
|
|
+ sp2 = make([]rtid2ti, len(sp)+1)
|
|
|
|
|
+ copy(sp2, sp[:idx])
|
|
|
|
|
+ copy(sp2[idx+1:], sp[idx:])
|
|
|
|
|
+ sp2[idx] = rtid2ti{rtid, pti}
|
|
|
|
|
+ x.infos.store(sp2)
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
x.mu.Unlock()
|
|
x.mu.Unlock()
|
|
@@ -1738,7 +2004,6 @@ type codecFnInfo struct {
|
|
|
addrD bool
|
|
addrD bool
|
|
|
addrF bool // if addrD, this says whether decode function can take a value or a ptr
|
|
addrF bool // if addrD, this says whether decode function can take a value or a ptr
|
|
|
addrE bool
|
|
addrE bool
|
|
|
- ready bool // ready to use
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// codecFn encapsulates the captured variables and the encode function.
|
|
// codecFn encapsulates the captured variables and the encode function.
|
|
@@ -1757,271 +2022,6 @@ type codecRtidFn struct {
|
|
|
fn *codecFn
|
|
fn *codecFn
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-type codecFner struct {
|
|
|
|
|
- // hh Handle
|
|
|
|
|
- h *BasicHandle
|
|
|
|
|
- s []codecRtidFn
|
|
|
|
|
- be bool
|
|
|
|
|
- js bool
|
|
|
|
|
- _ [6]byte // padding
|
|
|
|
|
- _ [3]uint64 // padding
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-func (c *codecFner) reset(hh Handle) {
|
|
|
|
|
- bh := hh.getBasicHandle()
|
|
|
|
|
- // only reset iff extensions changed or *TypeInfos changed
|
|
|
|
|
- var hhSame = true &&
|
|
|
|
|
- c.h == bh && c.h.TypeInfos == bh.TypeInfos &&
|
|
|
|
|
- len(c.h.extHandle) == len(bh.extHandle) &&
|
|
|
|
|
- (len(c.h.extHandle) == 0 || &c.h.extHandle[0] == &bh.extHandle[0])
|
|
|
|
|
- if !hhSame {
|
|
|
|
|
- // c.hh = hh
|
|
|
|
|
- c.h, bh = bh, c.h // swap both
|
|
|
|
|
- _ = bh
|
|
|
|
|
- _, c.js = hh.(*JsonHandle)
|
|
|
|
|
- c.be = hh.isBinary()
|
|
|
|
|
- if len(c.s) > 0 {
|
|
|
|
|
- c.s = c.s[:0]
|
|
|
|
|
- }
|
|
|
|
|
- // for i := range c.s {
|
|
|
|
|
- // c.s[i].fn.i.ready = false
|
|
|
|
|
- // }
|
|
|
|
|
- }
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-func (c *codecFner) get(rt reflect.Type, checkFastpath, checkCodecSelfer bool) (fn *codecFn) {
|
|
|
|
|
- rtid := rt2id(rt)
|
|
|
|
|
-
|
|
|
|
|
- for _, x := range c.s {
|
|
|
|
|
- if x.rtid == rtid {
|
|
|
|
|
- // if rtid exists, then there's a *codenFn attached (non-nil)
|
|
|
|
|
- fn = x.fn
|
|
|
|
|
- if fn.i.ready {
|
|
|
|
|
- return
|
|
|
|
|
- }
|
|
|
|
|
- break
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- var ti *typeInfo
|
|
|
|
|
- if fn == nil {
|
|
|
|
|
- fn = new(codecFn)
|
|
|
|
|
- if c.s == nil {
|
|
|
|
|
- c.s = make([]codecRtidFn, 0, 8)
|
|
|
|
|
- }
|
|
|
|
|
- c.s = append(c.s, codecRtidFn{rtid, fn})
|
|
|
|
|
- } else {
|
|
|
|
|
- ti = fn.i.ti
|
|
|
|
|
- *fn = codecFn{}
|
|
|
|
|
- fn.i.ti = ti
|
|
|
|
|
- // fn.fe, fn.fd = nil, nil
|
|
|
|
|
- }
|
|
|
|
|
- fi := &(fn.i)
|
|
|
|
|
- fi.ready = true
|
|
|
|
|
- if ti == nil {
|
|
|
|
|
- ti = c.h.getTypeInfo(rtid, rt)
|
|
|
|
|
- fi.ti = ti
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- rk := reflect.Kind(ti.kind)
|
|
|
|
|
-
|
|
|
|
|
- if checkCodecSelfer && (ti.cs || ti.csp) {
|
|
|
|
|
- fn.fe = (*Encoder).selferMarshal
|
|
|
|
|
- fn.fd = (*Decoder).selferUnmarshal
|
|
|
|
|
- fi.addrF = true
|
|
|
|
|
- fi.addrD = ti.csp
|
|
|
|
|
- fi.addrE = ti.csp
|
|
|
|
|
- } else if rtid == timeTypId && !c.h.TimeNotBuiltin {
|
|
|
|
|
- fn.fe = (*Encoder).kTime
|
|
|
|
|
- fn.fd = (*Decoder).kTime
|
|
|
|
|
- } else if rtid == rawTypId {
|
|
|
|
|
- fn.fe = (*Encoder).raw
|
|
|
|
|
- fn.fd = (*Decoder).raw
|
|
|
|
|
- } else if rtid == rawExtTypId {
|
|
|
|
|
- fn.fe = (*Encoder).rawExt
|
|
|
|
|
- fn.fd = (*Decoder).rawExt
|
|
|
|
|
- fi.addrF = true
|
|
|
|
|
- fi.addrD = true
|
|
|
|
|
- fi.addrE = true
|
|
|
|
|
- } else if xfFn := c.h.getExt(rtid); xfFn != nil {
|
|
|
|
|
- fi.xfTag, fi.xfFn = xfFn.tag, xfFn.ext
|
|
|
|
|
- fn.fe = (*Encoder).ext
|
|
|
|
|
- fn.fd = (*Decoder).ext
|
|
|
|
|
- fi.addrF = true
|
|
|
|
|
- fi.addrD = true
|
|
|
|
|
- if rk == reflect.Struct || rk == reflect.Array {
|
|
|
|
|
- fi.addrE = true
|
|
|
|
|
- }
|
|
|
|
|
- } else if supportMarshalInterfaces && c.be && (ti.bm || ti.bmp) && (ti.bu || ti.bup) {
|
|
|
|
|
- fn.fe = (*Encoder).binaryMarshal
|
|
|
|
|
- fn.fd = (*Decoder).binaryUnmarshal
|
|
|
|
|
- fi.addrF = true
|
|
|
|
|
- fi.addrD = ti.bup
|
|
|
|
|
- fi.addrE = ti.bmp
|
|
|
|
|
- } else if supportMarshalInterfaces && !c.be && c.js && (ti.jm || ti.jmp) && (ti.ju || ti.jup) {
|
|
|
|
|
- //If JSON, we should check JSONMarshal before textMarshal
|
|
|
|
|
- fn.fe = (*Encoder).jsonMarshal
|
|
|
|
|
- fn.fd = (*Decoder).jsonUnmarshal
|
|
|
|
|
- fi.addrF = true
|
|
|
|
|
- fi.addrD = ti.jup
|
|
|
|
|
- fi.addrE = ti.jmp
|
|
|
|
|
- } else if supportMarshalInterfaces && !c.be && (ti.tm || ti.tmp) && (ti.tu || ti.tup) {
|
|
|
|
|
- fn.fe = (*Encoder).textMarshal
|
|
|
|
|
- fn.fd = (*Decoder).textUnmarshal
|
|
|
|
|
- fi.addrF = true
|
|
|
|
|
- fi.addrD = ti.tup
|
|
|
|
|
- fi.addrE = ti.tmp
|
|
|
|
|
- } else {
|
|
|
|
|
- if fastpathEnabled && checkFastpath && (rk == reflect.Map || rk == reflect.Slice) {
|
|
|
|
|
- if ti.pkgpath == "" { // un-named slice or map
|
|
|
|
|
- if idx := fastpathAV.index(rtid); idx != -1 {
|
|
|
|
|
- fn.fe = fastpathAV[idx].encfn
|
|
|
|
|
- fn.fd = fastpathAV[idx].decfn
|
|
|
|
|
- fi.addrD = true
|
|
|
|
|
- fi.addrF = false
|
|
|
|
|
- }
|
|
|
|
|
- } else {
|
|
|
|
|
- // use mapping for underlying type if there
|
|
|
|
|
- var rtu reflect.Type
|
|
|
|
|
- if rk == reflect.Map {
|
|
|
|
|
- rtu = reflect.MapOf(ti.key, ti.elem)
|
|
|
|
|
- } else {
|
|
|
|
|
- rtu = reflect.SliceOf(ti.elem)
|
|
|
|
|
- }
|
|
|
|
|
- rtuid := rt2id(rtu)
|
|
|
|
|
- if idx := fastpathAV.index(rtuid); idx != -1 {
|
|
|
|
|
- xfnf := fastpathAV[idx].encfn
|
|
|
|
|
- xrt := fastpathAV[idx].rt
|
|
|
|
|
- fn.fe = func(e *Encoder, xf *codecFnInfo, xrv reflect.Value) {
|
|
|
|
|
- xfnf(e, xf, xrv.Convert(xrt))
|
|
|
|
|
- }
|
|
|
|
|
- fi.addrD = true
|
|
|
|
|
- fi.addrF = false // meaning it can be an address(ptr) or a value
|
|
|
|
|
- xfnf2 := fastpathAV[idx].decfn
|
|
|
|
|
- fn.fd = func(d *Decoder, xf *codecFnInfo, xrv reflect.Value) {
|
|
|
|
|
- if xrv.Kind() == reflect.Ptr {
|
|
|
|
|
- xfnf2(d, xf, xrv.Convert(reflect.PtrTo(xrt)))
|
|
|
|
|
- } else {
|
|
|
|
|
- xfnf2(d, xf, xrv.Convert(xrt))
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- if fn.fe == nil && fn.fd == nil {
|
|
|
|
|
- switch rk {
|
|
|
|
|
- case reflect.Bool:
|
|
|
|
|
- fn.fe = (*Encoder).kBool
|
|
|
|
|
- fn.fd = (*Decoder).kBool
|
|
|
|
|
- case reflect.String:
|
|
|
|
|
- fn.fe = (*Encoder).kString
|
|
|
|
|
- fn.fd = (*Decoder).kString
|
|
|
|
|
- case reflect.Int:
|
|
|
|
|
- fn.fd = (*Decoder).kInt
|
|
|
|
|
- fn.fe = (*Encoder).kInt
|
|
|
|
|
- case reflect.Int8:
|
|
|
|
|
- fn.fe = (*Encoder).kInt8
|
|
|
|
|
- fn.fd = (*Decoder).kInt8
|
|
|
|
|
- case reflect.Int16:
|
|
|
|
|
- fn.fe = (*Encoder).kInt16
|
|
|
|
|
- fn.fd = (*Decoder).kInt16
|
|
|
|
|
- case reflect.Int32:
|
|
|
|
|
- fn.fe = (*Encoder).kInt32
|
|
|
|
|
- fn.fd = (*Decoder).kInt32
|
|
|
|
|
- case reflect.Int64:
|
|
|
|
|
- fn.fe = (*Encoder).kInt64
|
|
|
|
|
- fn.fd = (*Decoder).kInt64
|
|
|
|
|
- case reflect.Uint:
|
|
|
|
|
- fn.fd = (*Decoder).kUint
|
|
|
|
|
- fn.fe = (*Encoder).kUint
|
|
|
|
|
- case reflect.Uint8:
|
|
|
|
|
- fn.fe = (*Encoder).kUint8
|
|
|
|
|
- fn.fd = (*Decoder).kUint8
|
|
|
|
|
- case reflect.Uint16:
|
|
|
|
|
- fn.fe = (*Encoder).kUint16
|
|
|
|
|
- fn.fd = (*Decoder).kUint16
|
|
|
|
|
- case reflect.Uint32:
|
|
|
|
|
- fn.fe = (*Encoder).kUint32
|
|
|
|
|
- fn.fd = (*Decoder).kUint32
|
|
|
|
|
- case reflect.Uint64:
|
|
|
|
|
- fn.fe = (*Encoder).kUint64
|
|
|
|
|
- fn.fd = (*Decoder).kUint64
|
|
|
|
|
- case reflect.Uintptr:
|
|
|
|
|
- fn.fe = (*Encoder).kUintptr
|
|
|
|
|
- fn.fd = (*Decoder).kUintptr
|
|
|
|
|
- case reflect.Float32:
|
|
|
|
|
- fn.fe = (*Encoder).kFloat32
|
|
|
|
|
- fn.fd = (*Decoder).kFloat32
|
|
|
|
|
- case reflect.Float64:
|
|
|
|
|
- fn.fe = (*Encoder).kFloat64
|
|
|
|
|
- fn.fd = (*Decoder).kFloat64
|
|
|
|
|
- case reflect.Invalid:
|
|
|
|
|
- fn.fe = (*Encoder).kInvalid
|
|
|
|
|
- fn.fd = (*Decoder).kErr
|
|
|
|
|
- case reflect.Chan:
|
|
|
|
|
- fi.seq = seqTypeChan
|
|
|
|
|
- fn.fe = (*Encoder).kSlice
|
|
|
|
|
- fn.fd = (*Decoder).kSlice
|
|
|
|
|
- case reflect.Slice:
|
|
|
|
|
- fi.seq = seqTypeSlice
|
|
|
|
|
- fn.fe = (*Encoder).kSlice
|
|
|
|
|
- fn.fd = (*Decoder).kSlice
|
|
|
|
|
- case reflect.Array:
|
|
|
|
|
- fi.seq = seqTypeArray
|
|
|
|
|
- fn.fe = (*Encoder).kSlice
|
|
|
|
|
- fi.addrF = false
|
|
|
|
|
- fi.addrD = false
|
|
|
|
|
- rt2 := reflect.SliceOf(ti.elem)
|
|
|
|
|
- fn.fd = func(d *Decoder, xf *codecFnInfo, xrv reflect.Value) {
|
|
|
|
|
- d.cfer().get(rt2, true, false).fd(d, xf, xrv.Slice(0, xrv.Len()))
|
|
|
|
|
- }
|
|
|
|
|
- // fn.fd = (*Decoder).kArray
|
|
|
|
|
- case reflect.Struct:
|
|
|
|
|
- if ti.anyOmitEmpty || ti.mf || ti.mfp {
|
|
|
|
|
- fn.fe = (*Encoder).kStruct
|
|
|
|
|
- } else {
|
|
|
|
|
- fn.fe = (*Encoder).kStructNoOmitempty
|
|
|
|
|
- }
|
|
|
|
|
- fn.fd = (*Decoder).kStruct
|
|
|
|
|
- case reflect.Map:
|
|
|
|
|
- fn.fe = (*Encoder).kMap
|
|
|
|
|
- fn.fd = (*Decoder).kMap
|
|
|
|
|
- case reflect.Interface:
|
|
|
|
|
- // encode: reflect.Interface are handled already by preEncodeValue
|
|
|
|
|
- fn.fd = (*Decoder).kInterface
|
|
|
|
|
- fn.fe = (*Encoder).kErr
|
|
|
|
|
- default:
|
|
|
|
|
- // reflect.Ptr and reflect.Interface are handled already by preEncodeValue
|
|
|
|
|
- fn.fe = (*Encoder).kErr
|
|
|
|
|
- fn.fd = (*Decoder).kErr
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- return
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-type codecFnPooler struct {
|
|
|
|
|
- cf *codecFner
|
|
|
|
|
- cfp *sync.Pool
|
|
|
|
|
- hh Handle
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-func (d *codecFnPooler) cfer() *codecFner {
|
|
|
|
|
- if d.cf == nil {
|
|
|
|
|
- var v interface{}
|
|
|
|
|
- d.cfp, v = pool.codecFner()
|
|
|
|
|
- d.cf = v.(*codecFner)
|
|
|
|
|
- d.cf.reset(d.hh)
|
|
|
|
|
- }
|
|
|
|
|
- return d.cf
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-func (d *codecFnPooler) end() {
|
|
|
|
|
- if d.cf != nil {
|
|
|
|
|
- d.cfp.Put(d.cf)
|
|
|
|
|
- d.cf, d.cfp = nil, nil
|
|
|
|
|
- }
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
// ----
|
|
// ----
|
|
|
|
|
|
|
|
// these "checkOverflow" functions must be inlinable, and not call anybody.
|
|
// these "checkOverflow" functions must be inlinable, and not call anybody.
|
|
@@ -2374,7 +2374,6 @@ type pooler struct {
|
|
|
|
|
|
|
|
// lifetime-scoped pooled resources
|
|
// lifetime-scoped pooled resources
|
|
|
dn sync.Pool // for decNaked
|
|
dn sync.Pool // for decNaked
|
|
|
- cfn sync.Pool // for codecFner
|
|
|
|
|
buf1k, buf2k, buf4k, buf8k, buf16k sync.Pool // for [N]byte
|
|
buf1k, buf2k, buf4k, buf8k, buf16k sync.Pool // for [N]byte
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -2396,8 +2395,6 @@ func (p *pooler) init() {
|
|
|
p.buf16k.New = func() interface{} { return new([16 * 1024]byte) }
|
|
p.buf16k.New = func() interface{} { return new([16 * 1024]byte) }
|
|
|
|
|
|
|
|
p.dn.New = func() interface{} { x := new(decNaked); x.init(); return x }
|
|
p.dn.New = func() interface{} { x := new(decNaked); x.init(); return x }
|
|
|
-
|
|
|
|
|
- p.cfn.New = func() interface{} { return new(codecFner) }
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
func (p *pooler) sfiRv8() (sp *sync.Pool, v interface{}) {
|
|
func (p *pooler) sfiRv8() (sp *sync.Pool, v interface{}) {
|
|
@@ -2435,9 +2432,6 @@ func (p *pooler) bytes16k() (sp *sync.Pool, v interface{}) {
|
|
|
func (p *pooler) decNaked() (sp *sync.Pool, v interface{}) {
|
|
func (p *pooler) decNaked() (sp *sync.Pool, v interface{}) {
|
|
|
return &p.dn, p.dn.Get()
|
|
return &p.dn, p.dn.Get()
|
|
|
}
|
|
}
|
|
|
-func (p *pooler) codecFner() (sp *sync.Pool, v interface{}) {
|
|
|
|
|
- return &p.cfn, p.cfn.Get()
|
|
|
|
|
-}
|
|
|
|
|
func (p *pooler) tiLoad() (sp *sync.Pool, v interface{}) {
|
|
func (p *pooler) tiLoad() (sp *sync.Pool, v interface{}) {
|
|
|
return &p.tiload, p.tiload.Get()
|
|
return &p.tiload, p.tiload.Get()
|
|
|
}
|
|
}
|
|
@@ -2450,18 +2444,12 @@ func (p *pooler) tiLoad() (sp *sync.Pool, v interface{}) {
|
|
|
// func (p *pooler) decNakedGet() (v interface{}) {
|
|
// func (p *pooler) decNakedGet() (v interface{}) {
|
|
|
// return p.dn.Get()
|
|
// return p.dn.Get()
|
|
|
// }
|
|
// }
|
|
|
-// func (p *pooler) codecFnerGet() (v interface{}) {
|
|
|
|
|
-// return p.cfn.Get()
|
|
|
|
|
-// }
|
|
|
|
|
// func (p *pooler) tiLoadGet() (v interface{}) {
|
|
// func (p *pooler) tiLoadGet() (v interface{}) {
|
|
|
// return p.tiload.Get()
|
|
// return p.tiload.Get()
|
|
|
// }
|
|
// }
|
|
|
// func (p *pooler) decNakedPut(v interface{}) {
|
|
// func (p *pooler) decNakedPut(v interface{}) {
|
|
|
// p.dn.Put(v)
|
|
// p.dn.Put(v)
|
|
|
// }
|
|
// }
|
|
|
-// func (p *pooler) codecFnerPut(v interface{}) {
|
|
|
|
|
-// p.cfn.Put(v)
|
|
|
|
|
-// }
|
|
|
|
|
// func (p *pooler) tiLoadPut(v interface{}) {
|
|
// func (p *pooler) tiLoadPut(v interface{}) {
|
|
|
// p.tiload.Put(v)
|
|
// p.tiload.Put(v)
|
|
|
// }
|
|
// }
|