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