Version Bumps

This commit is contained in:
George Shammas
2019-03-18 23:19:26 +00:00
parent a8a41f114c
commit 95006a78e2
152 changed files with 17999 additions and 8460 deletions

View File

@@ -12,7 +12,6 @@ import (
"runtime"
"sort"
"strconv"
"sync"
"time"
)
@@ -49,13 +48,12 @@ 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
// Deprecated: 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
// Deprecated: use EncodeStringBytesRaw instead
EncodeStringBytes(c charEncoding, v []byte)
EncodeStringEnc(c charEncoding, v string) // c cannot be cRAW
// EncodeSymbol(v string)
EncodeStringBytesRaw(v []byte)
EncodeTime(time.Time)
//encBignum(f *big.Int)
@@ -170,6 +168,19 @@ type EncodeOptions struct {
// If unset, we error out.
Raw bool
// StringToRaw controls how strings are encoded.
//
// As a go string is just an (immutable) sequence of bytes,
// it can be encoded either as raw bytes or as a UTF string.
//
// By default, strings are encoded as UTF-8.
// but can be treated as []byte during an encode.
//
// Note that things which we know (by definition) to be UTF-8
// are ALWAYS encoded as UTF-8 strings.
// These include encoding.TextMarshaler, time.Format calls, struct field names, etc.
StringToRaw bool
// // AsSymbols defines what should be encoded as symbols.
// //
// // Encoding as symbols can reduce the encoded size significantly.
@@ -280,10 +291,18 @@ type bufioEncWriter struct {
buf []byte
w io.Writer
n int
sz int // buf size
// Extensions can call Encode() within a current Encode() call.
// We need to know when the top level Encode() call returns,
// so we can decide whether to Release() or not.
calls uint16 // what depth in mustDecode are we in now.
_ [6]uint8 // padding
bytesBufPooler
_ [3]uint64 // padding
_ [1]uint64 // padding
// a int
// b [4]byte
// err
@@ -292,29 +311,39 @@ type bufioEncWriter struct {
func (z *bufioEncWriter) reset(w io.Writer, bufsize int) {
z.w = w
z.n = 0
z.calls = 0
if bufsize <= 0 {
bufsize = defEncByteBufSize
}
z.sz = bufsize
if cap(z.buf) >= bufsize {
z.buf = z.buf[:cap(z.buf)]
} else {
z.bytesBufPooler.end() // potentially return old one to pool
z.buf = z.bytesBufPooler.get(bufsize)
// z.buf = make([]byte, bufsize)
}
}
func (z *bufioEncWriter) release() {
z.buf = nil
z.bytesBufPooler.end()
}
//go:noinline - flush only called intermittently
func (z *bufioEncWriter) flush() {
func (z *bufioEncWriter) flushErr() (err error) {
n, err := z.w.Write(z.buf[:z.n])
z.n -= n
if z.n > 0 && err == nil {
err = io.ErrShortWrite
}
if err != nil {
if n > 0 && z.n > 0 {
copy(z.buf, z.buf[n:z.n+n])
}
if n > 0 && z.n > 0 {
copy(z.buf, z.buf[n:z.n+n])
}
return err
}
func (z *bufioEncWriter) flush() {
if err := z.flushErr(); err != nil {
panic(err)
}
}
@@ -361,10 +390,11 @@ func (z *bufioEncWriter) writen2(b1, b2 byte) {
z.n += 2
}
func (z *bufioEncWriter) end() {
func (z *bufioEncWriter) endErr() (err error) {
if z.n > 0 {
z.flush()
err = z.flushErr()
}
return
}
// ---------------------------------------------
@@ -387,8 +417,9 @@ func (z *bytesEncAppender) writen1(b1 byte) {
func (z *bytesEncAppender) writen2(b1, b2 byte) {
z.b = append(z.b, b1, b2)
}
func (z *bytesEncAppender) end() {
func (z *bytesEncAppender) endErr() error {
*(z.out) = z.b
return nil
}
func (z *bytesEncAppender) reset(in []byte, out *[]byte) {
z.b = in[:0]
@@ -624,15 +655,13 @@ func (e *Encoder) kStructNoOmitempty(f *codecFnInfo, rv reflect.Value) {
if e.esep {
for _, si := range tisfi {
ee.WriteMapElemKey()
// ee.EncodeStringEnc(cUTF8, si.encName)
e.kStructFieldKey(fti.keyType, si)
e.kStructFieldKey(fti.keyType, si.encNameAsciiAlphaNum, si.encName)
ee.WriteMapElemValue()
e.encodeValue(sfn.field(si), nil, true)
}
} else {
for _, si := range tisfi {
// ee.EncodeStringEnc(cUTF8, si.encName)
e.kStructFieldKey(fti.keyType, si)
e.kStructFieldKey(fti.keyType, si.encNameAsciiAlphaNum, si.encName)
e.encodeValue(sfn.field(si), nil, true)
}
}
@@ -653,40 +682,8 @@ func (e *Encoder) kStructNoOmitempty(f *codecFnInfo, rv reflect.Value) {
}
}
func (e *Encoder) kStructFieldKey(keyType valueType, s *structFieldInfo) {
var m must
// use if-else-if, not switch (which compiles to binary-search)
// since keyType is typically valueTypeString, branch prediction is pretty good.
if keyType == valueTypeString {
if e.js && s.encNameAsciiAlphaNum { // keyType == valueTypeString
e.w.writen1('"')
e.w.writestr(s.encName)
e.w.writen1('"')
} else { // keyType == valueTypeString
e.e.EncodeStringEnc(cUTF8, s.encName)
}
} else if keyType == valueTypeInt {
e.e.EncodeInt(m.Int(strconv.ParseInt(s.encName, 10, 64)))
} else if keyType == valueTypeUint {
e.e.EncodeUint(m.Uint(strconv.ParseUint(s.encName, 10, 64)))
} else if keyType == valueTypeFloat {
e.e.EncodeFloat64(m.Float(strconv.ParseFloat(s.encName, 64)))
}
}
func (e *Encoder) kStructFieldKeyName(keyType valueType, encName string) {
var m must
// 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.EncodeStringEnc(cUTF8, encName)
} else if keyType == valueTypeInt {
e.e.EncodeInt(m.Int(strconv.ParseInt(encName, 10, 64)))
} else if keyType == valueTypeUint {
e.e.EncodeUint(m.Uint(strconv.ParseUint(encName, 10, 64)))
} else if keyType == valueTypeFloat {
e.e.EncodeFloat64(m.Float(strconv.ParseFloat(encName, 64)))
}
func (e *Encoder) kStructFieldKey(keyType valueType, encNameAsciiAlphaNum bool, encName string) {
encStructFieldKey(encName, e.e, e.w, keyType, encNameAsciiAlphaNum, e.js)
}
func (e *Encoder) kStruct(f *codecFnInfo, rv reflect.Value) {
@@ -731,30 +728,9 @@ func (e *Encoder) kStruct(f *codecFnInfo, rv reflect.Value) {
// The cost is that of locking sometimes, but sync.Pool is efficient
// enough to reduce thread contention.
var spool *sync.Pool
var poolv interface{}
var fkvs []sfiRv
// fmt.Printf(">>>>>>>>>>>>>> encode.kStruct: newlen: %d\n", newlen)
if newlen < 0 { // bounds-check-elimination
// cannot happen // here for bounds-check-elimination
} else if newlen <= 8 {
spool, poolv = pool.sfiRv8()
fkvs = poolv.(*[8]sfiRv)[:newlen]
} else if newlen <= 16 {
spool, poolv = pool.sfiRv16()
fkvs = poolv.(*[16]sfiRv)[:newlen]
} else if newlen <= 32 {
spool, poolv = pool.sfiRv32()
fkvs = poolv.(*[32]sfiRv)[:newlen]
} else if newlen <= 64 {
spool, poolv = pool.sfiRv64()
fkvs = poolv.(*[64]sfiRv)[:newlen]
} else if newlen <= 128 {
spool, poolv = pool.sfiRv128()
fkvs = poolv.(*[128]sfiRv)[:newlen]
} else {
fkvs = make([]sfiRv, newlen)
}
var spool sfiRvPooler
var fkvs = spool.get(newlen)
var kv sfiRv
recur := e.h.RecursiveEmptyCheck
@@ -773,7 +749,8 @@ func (e *Encoder) kStruct(f *codecFnInfo, rv reflect.Value) {
// if a reference or struct, set to nil (so you do not output too much)
if si.omitEmpty() && isEmptyValue(kv.r, e.h.TypeInfos, recur, recur) {
switch kv.r.Kind() {
case reflect.Struct, reflect.Interface, reflect.Ptr, reflect.Array, reflect.Map, reflect.Slice:
case reflect.Struct, reflect.Interface, reflect.Ptr,
reflect.Array, reflect.Map, reflect.Slice:
kv.r = reflect.Value{} //encode as nil
}
}
@@ -803,23 +780,21 @@ func (e *Encoder) kStruct(f *codecFnInfo, rv reflect.Value) {
for j = 0; j < len(fkvs); j++ {
kv = fkvs[j]
ee.WriteMapElemKey()
// ee.EncodeStringEnc(cUTF8, kv.v)
e.kStructFieldKey(fti.keyType, kv.v)
e.kStructFieldKey(fti.keyType, kv.v.encNameAsciiAlphaNum, kv.v.encName)
ee.WriteMapElemValue()
e.encodeValue(kv.r, nil, true)
}
} else {
for j = 0; j < len(fkvs); j++ {
kv = fkvs[j]
// ee.EncodeStringEnc(cUTF8, kv.v)
e.kStructFieldKey(fti.keyType, kv.v)
e.kStructFieldKey(fti.keyType, kv.v.encNameAsciiAlphaNum, kv.v.encName)
e.encodeValue(kv.r, nil, true)
}
}
// now, add the others
for k, v := range mf {
ee.WriteMapElemKey()
e.kStructFieldKeyName(fti.keyType, k)
e.kStructFieldKey(fti.keyType, false, k)
ee.WriteMapElemValue()
e.encode(v)
}
@@ -842,9 +817,7 @@ func (e *Encoder) kStruct(f *codecFnInfo, rv reflect.Value) {
// do not use defer. Instead, use explicit pool return at end of function.
// defer has a cost we are trying to avoid.
// If there is a panic and these slices are not returned, it is ok.
if spool != nil {
spool.Put(poolv)
}
spool.end()
}
func (e *Encoder) kMap(f *codecFnInfo, rv reflect.Value) {
@@ -906,7 +879,11 @@ func (e *Encoder) kMap(f *codecFnInfo, rv reflect.Value) {
ee.WriteMapElemKey()
}
if keyTypeIsString {
ee.EncodeStringEnc(cUTF8, mks[j].String())
if e.h.StringToRaw {
ee.EncodeStringBytesRaw(bytesView(mks[j].String()))
} else {
ee.EncodeStringEnc(cUTF8, mks[j].String())
}
} else {
e.encodeValue(mks[j], keyFn, true)
}
@@ -956,7 +933,11 @@ func (e *Encoder) kMapCanonical(rtkey reflect.Type, rv reflect.Value, mks []refl
if elemsep {
ee.WriteMapElemKey()
}
ee.EncodeStringEnc(cUTF8, mksv[i].v)
if e.h.StringToRaw {
ee.EncodeStringBytesRaw(bytesView(mksv[i].v))
} else {
ee.EncodeStringEnc(cUTF8, mksv[i].v)
}
if elemsep {
ee.WriteMapElemValue()
}
@@ -1128,11 +1109,16 @@ func (z *encWriterSwitch) writen2(b1, b2 byte) {
z.wf.writen2(b1, b2)
}
}
func (z *encWriterSwitch) end() {
func (z *encWriterSwitch) endErr() error {
if z.bytes {
z.wb.end()
} else {
z.wf.end()
return z.wb.endErr()
}
return z.wf.endErr()
}
func (z *encWriterSwitch) end() {
if err := z.endErr(); err != nil {
panic(err)
}
}
@@ -1258,12 +1244,7 @@ type Encoder struct {
ci set
// Extensions can call Encode() within a current Encode() call.
// We need to know when the top level Encode() call returns,
// so we can decide whether to Release() or not.
calls uint16 // what depth in mustEncode are we in now.
b [(5 * 8) - 2]byte // for encoding chan or (non-addressable) [N]byte
b [(5 * 8)]byte // for encoding chan or (non-addressable) [N]byte
// ---- writable fields during execution --- *try* to keep in sep cache line
@@ -1319,7 +1300,6 @@ func (e *Encoder) resetCommon() {
_, e.js = e.hh.(*JsonHandle)
e.e.reset()
e.err = nil
e.calls = 0
}
// Reset resets the Encoder with a new output stream.
@@ -1471,8 +1451,13 @@ func (e *Encoder) Encode(v interface{}) (err error) {
}
if recoverPanicToErr {
defer func() {
e.w.end()
if x := recover(); x != nil {
// if error occurred during encoding, return that error;
// else if error occurred on end'ing (i.e. during flush), return that error.
err = e.w.endErr()
x := recover()
if x == nil {
e.err = err
} else {
panicValToErr(e, x, &e.err)
err = e.err
}
@@ -1494,13 +1479,26 @@ func (e *Encoder) MustEncode(v interface{}) {
}
func (e *Encoder) mustEncode(v interface{}) {
e.calls++
if e.wf == nil {
e.encode(v)
e.e.atEndOfEncode()
e.w.end()
return
}
if e.wf.buf == nil {
e.wf.buf = e.wf.bytesBufPooler.get(e.wf.sz)
}
e.wf.calls++
e.encode(v)
e.e.atEndOfEncode()
e.w.end()
e.calls--
if !e.h.ExplicitRelease && e.calls == 0 {
e.Release()
e.wf.calls--
if !e.h.ExplicitRelease && e.wf.calls == 0 {
e.wf.release()
}
}
@@ -1525,12 +1523,8 @@ func (e *Encoder) finalize() {
// It is important to call Release() when done with an Encoder, so those resources
// are released instantly for use by subsequently created Encoders.
func (e *Encoder) Release() {
if useFinalizers && removeFinalizerOnRelease {
runtime.SetFinalizer(e, nil)
}
if e.wf != nil {
e.wf.buf = nil
e.wf.bytesBufPooler.end()
e.wf.release()
}
}
@@ -1552,7 +1546,11 @@ func (e *Encoder) encode(iv interface{}) {
e.encodeValue(v, nil, true)
case string:
e.e.EncodeStringEnc(cUTF8, v)
if e.h.StringToRaw {
e.e.EncodeStringBytesRaw(bytesView(v))
} else {
e.e.EncodeStringEnc(cUTF8, v)
}
case bool:
e.e.EncodeBool(v)
case int:
@@ -1590,7 +1588,11 @@ func (e *Encoder) encode(iv interface{}) {
e.rawBytes(*v)
case *string:
e.e.EncodeStringEnc(cUTF8, *v)
if e.h.StringToRaw {
e.e.EncodeStringBytesRaw(bytesView(*v))
} else {
e.e.EncodeStringEnc(cUTF8, *v)
}
case *bool:
e.e.EncodeBool(*v)
case *int:
@@ -1709,7 +1711,7 @@ TOP:
// } else if asis {
// e.asis(bs)
// } else {
// e.e.EncodeStringBytes(c, bs)
// e.e.EncodeStringBytesRaw(bs)
// }
// }
@@ -1765,3 +1767,42 @@ func (e *Encoder) rawBytes(vv Raw) {
func (e *Encoder) wrapErr(v interface{}, err *error) {
*err = encodeError{codecError{name: e.hh.Name(), err: v}}
}
func encStructFieldKey(encName string, ee encDriver, w *encWriterSwitch,
keyType valueType, encNameAsciiAlphaNum bool, js bool) {
var m must
// use if-else-if, not switch (which compiles to binary-search)
// since keyType is typically valueTypeString, branch prediction is pretty good.
if keyType == valueTypeString {
if js && encNameAsciiAlphaNum { // keyType == valueTypeString
// w.writen1('"')
// w.writestr(encName)
// w.writen1('"')
// ----
// 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)
} else { // keyType == valueTypeString
ee.EncodeStringEnc(cUTF8, encName)
}
} else if keyType == valueTypeInt {
ee.EncodeInt(m.Int(strconv.ParseInt(encName, 10, 64)))
} else if keyType == valueTypeUint {
ee.EncodeUint(m.Uint(strconv.ParseUint(encName, 10, 64)))
} else if keyType == valueTypeFloat {
ee.EncodeFloat64(m.Float(strconv.ParseFloat(encName, 64)))
}
}
// func encStringAsRawBytesMaybe(ee encDriver, s string, stringToRaw bool) {
// if stringToRaw {
// ee.EncodeStringBytesRaw(bytesView(s))
// } else {
// ee.EncodeStringEnc(cUTF8, s)
// }
// }