Browse Source

codec: clean up new Encoder initialization, and add (unused commented out) copyHandle function

Also, expand TODO notes to make changes for mid-stack inlining and attempt more branchless optimizations
Ugorji Nwoke 8 năm trước cách đây
mục cha
commit
f0aa215a7d
3 tập tin đã thay đổi với 77 bổ sung38 xóa
  1. 6 1
      codec/0doc.go
  2. 19 20
      codec/encode.go
  3. 52 17
      codec/helper.go

+ 6 - 1
codec/0doc.go

@@ -225,4 +225,9 @@ package codec
 //     This involves uncommenting the methods for decReaderSwitch and encWriterSwitch
 //     and using those (decReaderSwitch and encWriterSwitch in all handles
 //     instead of encWriter and decReader.
-//
+//   - removing conditionals used to avoid calling no-op functions via interface calls.
+//     esep, etc.
+//     It *should* make the code cleaner, and maybe more performant,
+//     as conditional branches are expensive.
+//     However, per https://groups.google.com/forum/#!topic/golang-nuts/DNELyNnTzFA ,
+//     there is no optimization if calling an empty function via an interface.

+ 19 - 20
codec/encode.go

@@ -1016,8 +1016,10 @@ type encWriterSwitch struct {
 	wi ioEncWriter
 	// ---- cpu cache line boundary?
 	// wb bytesEncWriter
-	wb bytesEncAppender
-	wx bool // if bytes, wx=true
+	wb   bytesEncAppender
+	wx   bool // if bytes, wx=true
+	esep bool // whether it has elem separators
+	isas bool // whether e.as != nil
 }
 
 // TODO: Uncomment after mid-stack inlining enabled in go 1.10
@@ -1059,11 +1061,10 @@ type Encoder struct {
 	// as the handler MAY need to do some coordination.
 	w encWriter
 
+	// ho Handle // original handle
 	hh Handle
 	h  *BasicHandle
 
-	esep bool // whether it has elem separators
-
 	// ---- cpu cache line boundary?
 	// cr containerStateRecv
 	as encDriverAsis
@@ -1108,13 +1109,19 @@ func NewEncoderBytes(out *[]byte, h Handle) *Encoder {
 
 func newEncoder(h Handle) *Encoder {
 	e := &Encoder{hh: h, h: h.getBasicHandle(), err: errEncoderNotInitialized}
+	e.esep = h.hasElemSeparators()
 	e.e = h.newEncDriver(e)
-	e.as, _ = e.e.(encDriverAsis)
-	e.esep = e.hh.hasElemSeparators()
+	e.as, e.isas = e.e.(encDriverAsis)
 	// e.cr, _ = e.e.(containerStateRecv)
 	return e
 }
 
+func (e *Encoder) postReset() {
+	e.e.reset()
+	e.cf.reset(e.hh)
+	e.err = nil
+}
+
 // Reset resets the Encoder with a new output stream.
 //
 // This accommodates using the state of the Encoder,
@@ -1144,9 +1151,7 @@ func (e *Encoder) Reset(w io.Writer) {
 		e.wi.ww = w
 	}
 	e.w = &e.wi
-	e.e.reset()
-	e.cf.reset(e.hh)
-	e.err = nil
+	e.postReset()
 }
 
 // ResetBytes resets the Encoder with a new destination output []byte.
@@ -1164,9 +1169,7 @@ func (e *Encoder) ResetBytes(out *[]byte) {
 	e.wx = true
 	e.wb.reset(in, out)
 	e.w = &e.wb
-	e.e.reset()
-	e.cf.reset(e.hh)
-	e.err = nil
+	e.postReset()
 }
 
 // Encode writes an object into a stream.
@@ -1427,10 +1430,10 @@ func (e *Encoder) marshal(bs []byte, fnerr error, asis bool, c charEncoding) {
 }
 
 func (e *Encoder) asis(v []byte) {
-	if e.as == nil {
-		e.w.writeb(v)
-	} else {
+	if e.isas {
 		e.as.EncodeAsis(v)
+	} else {
+		e.w.writeb(v)
 	}
 }
 
@@ -1439,11 +1442,7 @@ func (e *Encoder) rawBytes(vv Raw) {
 	if !e.h.Raw {
 		e.errorf("Raw values cannot be encoded: %v", v)
 	}
-	if e.as == nil {
-		e.w.writeb(v)
-	} else {
-		e.as.EncodeAsis(v)
-	}
+	e.asis(v)
 }
 
 func (e *Encoder) errorf(format string, params ...interface{}) {

+ 52 - 17
codec/helper.go

@@ -416,6 +416,15 @@ type BasicHandle struct {
 	noBuiltInTypeChecker
 }
 
+// func (x *BasicHandle) postCopy() {
+// 	if len(x.extHandle) == 0 {
+// 		return
+// 	}
+// 	v := make(extHandle, len(x.extHandle))
+// 	copy(v, x.extHandle)
+// 	x.extHandle = v
+// }
+
 func (x *BasicHandle) getBasicHandle() *BasicHandle {
 	return x
 }
@@ -441,6 +450,33 @@ type Handle interface {
 	IsBuiltinType(rtid uintptr) bool
 }
 
+// func copyHandle(h Handle) (h2 Handle) {
+// 	_ = h.getBasicHandle().postCopy // ensure postCopy function on basicHandle isn't commented
+// 	switch hh := h.(type) {
+// 	case *JsonHandle:
+// 		hh2 := *hh
+// 		hh2.postCopy()
+// 		h2 = &hh2
+// 	case *SimpleHandle:
+// 		hh2 := *hh
+// 		hh2.postCopy()
+// 		h2 = &hh2
+// 	case *CborHandle:
+// 		hh2 := *hh
+// 		hh2.postCopy()
+// 		h2 = &hh2
+// 	case *MsgpackHandle:
+// 		hh2 := *hh
+// 		hh2.postCopy()
+// 		h2 = &hh2
+// 	case *BincHandle:
+// 		hh2 := *hh
+// 		hh2.postCopy()
+// 		h2 = &hh2
+// 	}
+// 	return
+// }
+
 // Raw represents raw formatted bytes.
 // We "blindly" store it during encode and retrieve the raw bytes during decode.
 // Note: it is dangerous during encode, so we may gate the behaviour behind an Encode flag which must be explicitly set.
@@ -728,31 +764,30 @@ func (si *structFieldInfo) field(v reflect.Value, update bool) (rv2 reflect.Valu
 // 	return v
 // }
 
-func parseStructFieldInfo(fname string, stag string) *structFieldInfo {
+func parseStructFieldInfo(fname string, stag string) (si *structFieldInfo) {
 	// if fname == "" {
 	// 	panic(errNoFieldNameToStructFieldInfo)
 	// }
-	si := structFieldInfo{
-		encName: fname,
-	}
+	si = &structFieldInfo{encName: fname}
 
-	if stag != "" {
-		for i, s := range strings.Split(stag, ",") {
-			if i == 0 {
-				if s != "" {
-					si.encName = s
-				}
-			} else {
-				if s == "omitempty" {
-					si.omitEmpty = true
-				} else if s == "toarray" {
-					si.toArray = true
-				}
+	if stag == "" {
+		return
+	}
+	for i, s := range strings.Split(stag, ",") {
+		if i == 0 {
+			if s != "" {
+				si.encName = s
+			}
+		} else {
+			if s == "omitempty" {
+				si.omitEmpty = true
+			} else if s == "toarray" {
+				si.toArray = true
 			}
 		}
 	}
 	// si.encNameBs = []byte(si.encName)
-	return &si
+	return
 }
 
 type sfiSortedByEncName []*structFieldInfo