|
@@ -30,6 +30,7 @@ var errEncoderNotInitialized = errors.New("Encoder not initialized")
|
|
|
type encWriter interface {
|
|
type encWriter interface {
|
|
|
writeb([]byte)
|
|
writeb([]byte)
|
|
|
writestr(string)
|
|
writestr(string)
|
|
|
|
|
+ writeqstr(string) // write string wrapped in quotes ie "..."
|
|
|
writen1(byte)
|
|
writen1(byte)
|
|
|
writen2(byte, byte)
|
|
writen2(byte, byte)
|
|
|
end()
|
|
end()
|
|
@@ -250,6 +251,10 @@ func (z *ioEncWriter) writestr(s string) {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+func (z *ioEncWriter) writeqstr(s string) {
|
|
|
|
|
+ writestr("\"" + s + "\"")
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
func (z *ioEncWriter) writen1(b byte) {
|
|
func (z *ioEncWriter) writen1(b byte) {
|
|
|
if err := z.bw.WriteByte(b); err != nil {
|
|
if err := z.bw.WriteByte(b); err != nil {
|
|
|
panic(err)
|
|
panic(err)
|
|
@@ -288,21 +293,27 @@ func (z *ioEncWriter) end() {
|
|
|
|
|
|
|
|
// bufioEncWriter
|
|
// bufioEncWriter
|
|
|
type bufioEncWriter struct {
|
|
type bufioEncWriter struct {
|
|
|
|
|
+ w io.Writer
|
|
|
|
|
+
|
|
|
buf []byte
|
|
buf []byte
|
|
|
- w io.Writer
|
|
|
|
|
- n int
|
|
|
|
|
- sz int // buf size
|
|
|
|
|
|
|
+
|
|
|
|
|
+ n int
|
|
|
|
|
|
|
|
// Extensions can call Encode() within a current Encode() call.
|
|
// Extensions can call Encode() within a current Encode() call.
|
|
|
// We need to know when the top level Encode() call returns,
|
|
// We need to know when the top level Encode() call returns,
|
|
|
// so we can decide whether to Release() or not.
|
|
// so we can decide whether to Release() or not.
|
|
|
calls uint16 // what depth in mustDecode are we in now.
|
|
calls uint16 // what depth in mustDecode are we in now.
|
|
|
|
|
|
|
|
- _ [6]uint8 // padding
|
|
|
|
|
|
|
+ sz int // buf size
|
|
|
|
|
+ // _ uint64 // padding (cache-aligned)
|
|
|
|
|
+
|
|
|
|
|
+ // ---- cache line
|
|
|
|
|
|
|
|
|
|
+ // write-most fields below
|
|
|
|
|
+
|
|
|
|
|
+ // less used fields
|
|
|
bytesBufPooler
|
|
bytesBufPooler
|
|
|
|
|
|
|
|
- _ [1]uint64 // padding
|
|
|
|
|
// a int
|
|
// a int
|
|
|
// b [4]byte
|
|
// b [4]byte
|
|
|
// err
|
|
// err
|
|
@@ -373,6 +384,29 @@ LOOP:
|
|
|
z.n += copy(z.buf[z.n:], s)
|
|
z.n += copy(z.buf[z.n:], s)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+func (z *bufioEncWriter) writeqstr(s string) {
|
|
|
|
|
+ // z.writen1('"')
|
|
|
|
|
+ // z.writestr(s)
|
|
|
|
|
+ // z.writen1('"')
|
|
|
|
|
+
|
|
|
|
|
+ if z.n+len(s)+2 > len(z.buf) {
|
|
|
|
|
+ z.flush()
|
|
|
|
|
+ }
|
|
|
|
|
+ z.buf[z.n] = '"'
|
|
|
|
|
+ z.n++
|
|
|
|
|
+LOOP:
|
|
|
|
|
+ a := len(z.buf) - z.n
|
|
|
|
|
+ if len(s)+1 > a {
|
|
|
|
|
+ z.n += copy(z.buf[z.n:], s[:a])
|
|
|
|
|
+ s = s[a:]
|
|
|
|
|
+ z.flush()
|
|
|
|
|
+ goto LOOP
|
|
|
|
|
+ }
|
|
|
|
|
+ z.n += copy(z.buf[z.n:], s)
|
|
|
|
|
+ z.buf[z.n] = '"'
|
|
|
|
|
+ z.n++
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
func (z *bufioEncWriter) writen1(b1 byte) {
|
|
func (z *bufioEncWriter) writen1(b1 byte) {
|
|
|
if 1 > len(z.buf)-z.n {
|
|
if 1 > len(z.buf)-z.n {
|
|
|
z.flush()
|
|
z.flush()
|
|
@@ -411,6 +445,15 @@ func (z *bytesEncAppender) writeb(s []byte) {
|
|
|
func (z *bytesEncAppender) writestr(s string) {
|
|
func (z *bytesEncAppender) writestr(s string) {
|
|
|
z.b = append(z.b, s...)
|
|
z.b = append(z.b, s...)
|
|
|
}
|
|
}
|
|
|
|
|
+func (z *bytesEncAppender) writeqstr(s string) {
|
|
|
|
|
+ // z.writen1('"')
|
|
|
|
|
+ // z.writestr(s)
|
|
|
|
|
+ // z.writen1('"')
|
|
|
|
|
+ z.b = append(append(append(z.b, '"'), s...), '"')
|
|
|
|
|
+ // z.b = append(z.b, '"')
|
|
|
|
|
+ // z.b = append(z.b, s...)
|
|
|
|
|
+ // z.b = append(z.b, '"')
|
|
|
|
|
+}
|
|
|
func (z *bytesEncAppender) writen1(b1 byte) {
|
|
func (z *bytesEncAppender) writen1(b1 byte) {
|
|
|
z.b = append(z.b, b1)
|
|
z.b = append(z.b, b1)
|
|
|
}
|
|
}
|
|
@@ -1071,12 +1114,12 @@ type encWriterSwitch struct {
|
|
|
wb bytesEncAppender
|
|
wb bytesEncAppender
|
|
|
wf *bufioEncWriter
|
|
wf *bufioEncWriter
|
|
|
// typ entryType
|
|
// typ entryType
|
|
|
- bytes bool // encoding to []byte
|
|
|
|
|
- esep bool // whether it has elem separators
|
|
|
|
|
- isas bool // whether e.as != nil
|
|
|
|
|
- js bool // is json encoder?
|
|
|
|
|
- be bool // is binary encoder?
|
|
|
|
|
- _ [2]byte // padding
|
|
|
|
|
|
|
+ bytes bool // encoding to []byte
|
|
|
|
|
+ esep bool // whether it has elem separators
|
|
|
|
|
+ isas bool // whether e.as != nil
|
|
|
|
|
+ js bool // is json encoder?
|
|
|
|
|
+ be bool // is binary encoder?
|
|
|
|
|
+ // _ [2]byte // padding
|
|
|
// _ [2]uint64 // padding
|
|
// _ [2]uint64 // padding
|
|
|
// _ uint64 // padding
|
|
// _ uint64 // padding
|
|
|
}
|
|
}
|
|
@@ -1088,6 +1131,13 @@ func (z *encWriterSwitch) writeb(s []byte) {
|
|
|
z.wf.writeb(s)
|
|
z.wf.writeb(s)
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
+func (z *encWriterSwitch) writeqstr(s string) {
|
|
|
|
|
+ if z.bytes {
|
|
|
|
|
+ z.wb.writeqstr(s)
|
|
|
|
|
+ } else {
|
|
|
|
|
+ z.wf.writeqstr(s)
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
func (z *encWriterSwitch) writestr(s string) {
|
|
func (z *encWriterSwitch) writestr(s string) {
|
|
|
if z.bytes {
|
|
if z.bytes {
|
|
|
z.wb.writestr(s)
|
|
z.wb.writestr(s)
|
|
@@ -1235,18 +1285,19 @@ type Encoder struct {
|
|
|
// bw *bufio.Writer
|
|
// bw *bufio.Writer
|
|
|
as encDriverAsis
|
|
as encDriverAsis
|
|
|
|
|
|
|
|
- err error
|
|
|
|
|
-
|
|
|
|
|
h *BasicHandle
|
|
h *BasicHandle
|
|
|
hh Handle
|
|
hh Handle
|
|
|
|
|
+
|
|
|
// ---- cpu cache line boundary? + 3
|
|
// ---- cpu cache line boundary? + 3
|
|
|
encWriterSwitch
|
|
encWriterSwitch
|
|
|
|
|
|
|
|
- ci set
|
|
|
|
|
-
|
|
|
|
|
- b [(5 * 8)]byte // for encoding chan or (non-addressable) [N]byte
|
|
|
|
|
|
|
+ err error
|
|
|
|
|
|
|
|
|
|
+ // ---- cpu cache line boundary
|
|
|
// ---- writable fields during execution --- *try* to keep in sep cache line
|
|
// ---- writable fields during execution --- *try* to keep in sep cache line
|
|
|
|
|
+ ci set
|
|
|
|
|
+
|
|
|
|
|
+ b [(5 * 8)]byte // for encoding chan byte, (non-addressable) [N]byte, etc
|
|
|
|
|
|
|
|
// ---- cpu cache line boundary?
|
|
// ---- cpu cache line boundary?
|
|
|
// b [scratchByteArrayLen]byte
|
|
// b [scratchByteArrayLen]byte
|
|
@@ -1456,10 +1507,14 @@ func (e *Encoder) Encode(v interface{}) (err error) {
|
|
|
err = e.w.endErr()
|
|
err = e.w.endErr()
|
|
|
x := recover()
|
|
x := recover()
|
|
|
if x == nil {
|
|
if x == nil {
|
|
|
- e.err = err
|
|
|
|
|
|
|
+ if e.err != err {
|
|
|
|
|
+ e.err = err
|
|
|
|
|
+ }
|
|
|
} else {
|
|
} else {
|
|
|
panicValToErr(e, x, &e.err)
|
|
panicValToErr(e, x, &e.err)
|
|
|
- err = e.err
|
|
|
|
|
|
|
+ if e.err != err {
|
|
|
|
|
+ err = e.err
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
}()
|
|
}()
|
|
|
}
|
|
}
|
|
@@ -1777,18 +1832,20 @@ func encStructFieldKey(encName string, ee encDriver, w *encWriterSwitch,
|
|
|
// since keyType is typically valueTypeString, branch prediction is pretty good.
|
|
// since keyType is typically valueTypeString, branch prediction is pretty good.
|
|
|
if keyType == valueTypeString {
|
|
if keyType == valueTypeString {
|
|
|
if js && encNameAsciiAlphaNum { // keyType == valueTypeString
|
|
if js && encNameAsciiAlphaNum { // keyType == valueTypeString
|
|
|
|
|
+ w.writeqstr(encName)
|
|
|
|
|
+ // ----
|
|
|
// w.writen1('"')
|
|
// w.writen1('"')
|
|
|
// w.writestr(encName)
|
|
// w.writestr(encName)
|
|
|
// w.writen1('"')
|
|
// w.writen1('"')
|
|
|
// ----
|
|
// ----
|
|
|
// w.writestr(`"` + encName + `"`)
|
|
// w.writestr(`"` + encName + `"`)
|
|
|
// ----
|
|
// ----
|
|
|
- // do concat myself, so it is faster than the generic string concat
|
|
|
|
|
- b := make([]byte, len(encName)+2)
|
|
|
|
|
- copy(b[1:], encName)
|
|
|
|
|
- b[0] = '"'
|
|
|
|
|
- b[len(b)-1] = '"'
|
|
|
|
|
- w.writeb(b)
|
|
|
|
|
|
|
+ // // do concat myself, so it is faster than the generic string concat
|
|
|
|
|
+ // b := make([]byte, len(encName)+2)
|
|
|
|
|
+ // copy(b[1:], encName)
|
|
|
|
|
+ // b[0] = '"'
|
|
|
|
|
+ // b[len(b)-1] = '"'
|
|
|
|
|
+ // w.writeb(b)
|
|
|
} else { // keyType == valueTypeString
|
|
} else { // keyType == valueTypeString
|
|
|
ee.EncodeStringEnc(cUTF8, encName)
|
|
ee.EncodeStringEnc(cUTF8, encName)
|
|
|
}
|
|
}
|