From f198ef65171c95670925049dba14859baab50fd3 Mon Sep 17 00:00:00 2001 From: Masaaki Goshima Date: Thu, 7 May 2020 02:37:29 +0900 Subject: [PATCH] Remove context for decoding --- decode.go | 26 +++++-------------- decode_array.go | 24 ++++++++--------- decode_bool.go | 35 ++++++++++++------------- decode_context.go | 24 +++-------------- decode_float.go | 24 ++++++++--------- decode_int.go | 22 +++++++--------- decode_map.go | 48 +++++++++++++++++----------------- decode_ptr.go | 10 ++++--- decode_slice.go | 24 ++++++++--------- decode_string.go | 36 ++++++++++++-------------- decode_struct.go | 66 ++++++++++++++++++++++------------------------- decode_uint.go | 20 +++++++------- 12 files changed, 159 insertions(+), 200 deletions(-) diff --git a/decode.go b/decode.go index a24864f..de49f3f 100644 --- a/decode.go +++ b/decode.go @@ -23,7 +23,7 @@ type Token interface{} type Delim rune type decoder interface { - decode(*context, uintptr) error + decode([]byte, int, uintptr) (int, error) } type Decoder struct { @@ -47,17 +47,11 @@ func (m *decoderMap) set(k uintptr, dec decoder) { } var ( - ctxPool sync.Pool cachedDecoder decoderMap ) func init() { cachedDecoder = decoderMap{} - ctxPool = sync.Pool{ - New: func() interface{} { - return newContext() - }, - } } // NewDecoder returns a new decoder that reads from r. @@ -90,13 +84,9 @@ func (d *Decoder) decode(src []byte, header *interfaceHeader) error { dec = compiledDec } ptr := uintptr(header.ptr) - ctx := ctxPool.Get().(*context) - ctx.setBuf(src) - if err := dec.decode(ctx, ptr); err != nil { - ctxPool.Put(ctx) + if _, err := dec.decode(src, 0, ptr); err != nil { return err } - ctxPool.Put(ctx) return nil } @@ -133,11 +123,6 @@ func (d *Decoder) Decode(v interface{}) error { dec = compiledDec } ptr := uintptr(header.ptr) - ctx := ctxPool.Get().(*context) - defer ctxPool.Put(ctx) - d.buffered = func() io.Reader { - return bytes.NewReader(ctx.buf[ctx.cursor:]) - } for { buf := make([]byte, 1024) n, err := d.r.Read(buf) @@ -147,10 +132,13 @@ func (d *Decoder) Decode(v interface{}) error { if err != nil { return err } - ctx.setBuf(buf[:n]) - if err := dec.decode(ctx, ptr); err != nil { + cursor, err := dec.decode(buf[:n], 0, ptr) + if err != nil { return err } + d.buffered = func() io.Reader { + return bytes.NewReader(buf[cursor:]) + } } return nil } diff --git a/decode_array.go b/decode_array.go index a23e691..b501ce0 100644 --- a/decode_array.go +++ b/decode_array.go @@ -20,10 +20,8 @@ func newArrayDecoder(dec decoder, elemType *rtype, alen int) *arrayDecoder { } } -func (d *arrayDecoder) decode(ctx *context, p uintptr) error { - buf := ctx.buf - buflen := ctx.buflen - cursor := ctx.cursor +func (d *arrayDecoder) decode(buf []byte, cursor int, p uintptr) (int, error) { + buflen := len(buf) for ; cursor < buflen; cursor++ { switch buf[cursor] { case ' ', '\n', '\t', '\r': @@ -31,23 +29,25 @@ func (d *arrayDecoder) decode(ctx *context, p uintptr) error { case '[': idx := 0 for { - ctx.cursor = cursor + 1 - if err := d.valueDecoder.decode(ctx, p+uintptr(idx)*d.size); err != nil { - return err + cursor++ + c, err := d.valueDecoder.decode(buf, cursor, p+uintptr(idx)*d.size) + if err != nil { + return 0, err } - cursor = ctx.skipWhiteSpace() + cursor = c + cursor = skipWhiteSpace(buf, cursor) switch buf[cursor] { case ']': - ctx.cursor++ - return nil + cursor++ + return cursor, nil case ',': idx++ continue default: - return errors.New("syntax error array") + return 0, errors.New("syntax error array") } } } } - return errors.New("unexpected error array") + return 0, errors.New("unexpected error array") } diff --git a/decode_bool.go b/decode_bool.go index a5f0a5f..66ccf7d 100644 --- a/decode_bool.go +++ b/decode_bool.go @@ -11,44 +11,43 @@ func newBoolDecoder() *boolDecoder { return &boolDecoder{} } -func (d *boolDecoder) decode(ctx *context, p uintptr) error { - ctx.skipWhiteSpace() - buf := ctx.buf - cursor := ctx.cursor +func (d *boolDecoder) decode(buf []byte, cursor int, p uintptr) (int, error) { + buflen := len(buf) + cursor = skipWhiteSpace(buf, cursor) switch buf[cursor] { case 't': - if cursor+3 >= ctx.buflen { - return errors.New("unexpected error. invalid bool character") + if cursor+3 >= buflen { + return 0, errors.New("unexpected error. invalid bool character") } if buf[cursor+1] != 'r' { - return errors.New("unexpected error. invalid bool character") + return 0, errors.New("unexpected error. invalid bool character") } if buf[cursor+2] != 'u' { - return errors.New("unexpected error. invalid bool character") + return 0, errors.New("unexpected error. invalid bool character") } if buf[cursor+3] != 'e' { - return errors.New("unexpected error. invalid bool character") + return 0, errors.New("unexpected error. invalid bool character") } - ctx.cursor += 4 + cursor += 4 *(*bool)(unsafe.Pointer(p)) = true case 'f': - if cursor+4 >= ctx.buflen { - return errors.New("unexpected error. invalid bool character") + if cursor+4 >= buflen { + return 0, errors.New("unexpected error. invalid bool character") } if buf[cursor+1] != 'a' { - return errors.New("unexpected error. invalid bool character") + return 0, errors.New("unexpected error. invalid bool character") } if buf[cursor+2] != 'l' { - return errors.New("unexpected error. invalid bool character") + return 0, errors.New("unexpected error. invalid bool character") } if buf[cursor+3] != 's' { - return errors.New("unexpected error. invalid bool character") + return 0, errors.New("unexpected error. invalid bool character") } if buf[cursor+4] != 'e' { - return errors.New("unexpected error. invalid bool character") + return 0, errors.New("unexpected error. invalid bool character") } - ctx.cursor += 5 + cursor += 5 *(*bool)(unsafe.Pointer(p)) = false } - return nil + return cursor, nil } diff --git a/decode_context.go b/decode_context.go index af1af64..d061696 100644 --- a/decode_context.go +++ b/decode_context.go @@ -11,31 +11,13 @@ func init() { isWhiteSpace['\r'] = true } -type context struct { - cursor int - buf []byte - buflen int -} - -func (c *context) setBuf(buf []byte) { - c.buf = buf - c.buflen = len(buf) - c.cursor = 0 -} - -func (c *context) skipWhiteSpace() int { - buflen := c.buflen - buf := c.buf - for cursor := c.cursor; cursor < buflen; cursor++ { +func skipWhiteSpace(buf []byte, cursor int) int { + buflen := len(buf) + for ; cursor < buflen; cursor++ { if isWhiteSpace[buf[cursor]] { continue } - c.cursor = cursor return cursor } return buflen } - -func newContext() *context { - return &context{} -} diff --git a/decode_float.go b/decode_float.go index 43eadd1..1df0fcc 100644 --- a/decode_float.go +++ b/decode_float.go @@ -14,10 +14,8 @@ func newFloatDecoder(op func(uintptr, float64)) *floatDecoder { return &floatDecoder{op: op} } -func (d *floatDecoder) decodeByte(ctx *context) ([]byte, error) { - buf := ctx.buf - cursor := ctx.cursor - buflen := ctx.buflen +func (d *floatDecoder) decodeByte(buf []byte, cursor int) ([]byte, int, error) { + buflen := len(buf) for ; cursor < buflen; cursor++ { switch buf[cursor] { case ' ', '\n', '\t', '\r': @@ -32,24 +30,24 @@ func (d *floatDecoder) decodeByte(ctx *context) ([]byte, error) { } break } - num := ctx.buf[start:cursor] - ctx.cursor = cursor - return num, nil + num := buf[start:cursor] + return num, cursor, nil } } - return nil, errors.New("unexpected error number") + return nil, 0, errors.New("unexpected error number") } -func (d *floatDecoder) decode(ctx *context, p uintptr) error { - bytes, err := d.decodeByte(ctx) +func (d *floatDecoder) decode(buf []byte, cursor int, p uintptr) (int, error) { + bytes, c, err := d.decodeByte(buf, cursor) if err != nil { - return err + return 0, err } + cursor = c s := *(*string)(unsafe.Pointer(&bytes)) f64, err := strconv.ParseFloat(s, 64) if err != nil { - return err + return 0, err } d.op(p, f64) - return nil + return cursor, nil } diff --git a/decode_int.go b/decode_int.go index 66d8723..07e6276 100644 --- a/decode_int.go +++ b/decode_int.go @@ -38,10 +38,8 @@ func (d *intDecoder) parseInt(b []byte) int64 { return sum } -func (d *intDecoder) decodeByte(ctx *context) ([]byte, error) { - buf := ctx.buf - cursor := ctx.cursor - buflen := ctx.buflen +func (d *intDecoder) decodeByte(buf []byte, cursor int) ([]byte, int, error) { + buflen := len(buf) for ; cursor < buflen; cursor++ { switch buf[cursor] { case ' ', '\n', '\t', '\r': @@ -56,19 +54,19 @@ func (d *intDecoder) decodeByte(ctx *context) ([]byte, error) { } break } - num := ctx.buf[start:cursor] - ctx.cursor = cursor - return num, nil + num := buf[start:cursor] + return num, cursor, nil } } - return nil, errors.New("unexpected error number") + return nil, 0, errors.New("unexpected error number") } -func (d *intDecoder) decode(ctx *context, p uintptr) error { - bytes, err := d.decodeByte(ctx) +func (d *intDecoder) decode(buf []byte, cursor int, p uintptr) (int, error) { + bytes, c, err := d.decodeByte(buf, cursor) if err != nil { - return err + return 0, err } + cursor = c d.op(p, d.parseInt(bytes)) - return nil + return cursor, nil } diff --git a/decode_map.go b/decode_map.go index b68437d..e07e1c5 100644 --- a/decode_map.go +++ b/decode_map.go @@ -26,57 +26,57 @@ func makemap(*rtype, int) unsafe.Pointer //go:noescape func mapassign(t *rtype, m unsafe.Pointer, key, val unsafe.Pointer) -func (d *mapDecoder) setKey(ctx *context, key interface{}) error { +func (d *mapDecoder) setKey(buf []byte, cursor int, key interface{}) (int, error) { header := (*interfaceHeader)(unsafe.Pointer(&key)) - return d.keyDecoder.decode(ctx, uintptr(header.ptr)) + return d.keyDecoder.decode(buf, cursor, uintptr(header.ptr)) } -func (d *mapDecoder) setValue(ctx *context, key interface{}) error { +func (d *mapDecoder) setValue(buf []byte, cursor int, key interface{}) (int, error) { header := (*interfaceHeader)(unsafe.Pointer(&key)) - return d.valueDecoder.decode(ctx, uintptr(header.ptr)) + return d.valueDecoder.decode(buf, cursor, uintptr(header.ptr)) } -func (d *mapDecoder) decode(ctx *context, p uintptr) error { - ctx.skipWhiteSpace() - buf := ctx.buf - buflen := ctx.buflen - cursor := ctx.cursor +func (d *mapDecoder) decode(buf []byte, cursor int, p uintptr) (int, error) { + cursor = skipWhiteSpace(buf, cursor) + buflen := len(buf) if buflen < 2 { - return errors.New("unexpected error {}") + return 0, errors.New("unexpected error {}") } if buf[cursor] != '{' { - return errors.New("unexpected error {") + return 0, errors.New("unexpected error {") } cursor++ mapValue := makemap(d.mapType, 0) for ; cursor < buflen; cursor++ { - ctx.cursor = cursor var key interface{} - if err := d.setKey(ctx, &key); err != nil { - return err + keyCursor, err := d.setKey(buf, cursor, &key) + if err != nil { + return 0, err } - cursor = ctx.skipWhiteSpace() + cursor = keyCursor + cursor = skipWhiteSpace(buf, cursor) if buf[cursor] != ':' { - return errors.New("unexpected error invalid delimiter for object") + return 0, errors.New("unexpected error invalid delimiter for object") } cursor++ if cursor >= buflen { - return errors.New("unexpected error missing value") + return 0, errors.New("unexpected error missing value") } - ctx.cursor = cursor var value interface{} - if err := d.setValue(ctx, &value); err != nil { - return err + valueCursor, err := d.setValue(buf, cursor, &value) + if err != nil { + return 0, err } + cursor = valueCursor mapassign(d.mapType, mapValue, unsafe.Pointer(&key), unsafe.Pointer(&value)) - cursor = ctx.skipWhiteSpace() + cursor = skipWhiteSpace(buf, valueCursor) if buf[cursor] == '}' { *(*unsafe.Pointer)(unsafe.Pointer(p)) = mapValue - return nil + return cursor, nil } if buf[cursor] != ',' { - return errors.New("unexpected error ,") + return 0, errors.New("unexpected error ,") } } - return nil + return cursor, nil } diff --git a/decode_ptr.go b/decode_ptr.go index 93b5c44..0144040 100644 --- a/decode_ptr.go +++ b/decode_ptr.go @@ -16,11 +16,13 @@ func newPtrDecoder(dec decoder, typ *rtype) *ptrDecoder { //go:linkname unsafe_New reflect.unsafe_New func unsafe_New(*rtype) uintptr -func (d *ptrDecoder) decode(ctx *context, p uintptr) error { +func (d *ptrDecoder) decode(buf []byte, cursor int, p uintptr) (int, error) { newptr := unsafe_New(d.typ) - if err := d.dec.decode(ctx, newptr); err != nil { - return err + c, err := d.dec.decode(buf, cursor, newptr) + if err != nil { + return 0, err } + cursor = c *(*uintptr)(unsafe.Pointer(p)) = newptr - return nil + return cursor, nil } diff --git a/decode_slice.go b/decode_slice.go index 6bc6e2a..10d986b 100644 --- a/decode_slice.go +++ b/decode_slice.go @@ -26,10 +26,8 @@ func copySlice(elemType *rtype, dst, src reflect.SliceHeader) int //go:linkname newArray reflect.unsafe_NewArray func newArray(*rtype, int) unsafe.Pointer -func (d *sliceDecoder) decode(ctx *context, p uintptr) error { - buf := ctx.buf - buflen := ctx.buflen - cursor := ctx.cursor +func (d *sliceDecoder) decode(buf []byte, cursor int, p uintptr) (int, error) { + buflen := len(buf) for ; cursor < buflen; cursor++ { switch buf[cursor] { case ' ', '\n', '\t', '\r': @@ -39,7 +37,7 @@ func (d *sliceDecoder) decode(ctx *context, p uintptr) error { cap := 2 data := uintptr(newArray(d.elemType, cap)) for { - ctx.cursor = cursor + 1 + cursor++ if cap <= idx { src := reflect.SliceHeader{Data: data, Len: idx, Cap: cap} cap *= 2 @@ -47,10 +45,12 @@ func (d *sliceDecoder) decode(ctx *context, p uintptr) error { dst := reflect.SliceHeader{Data: data, Len: idx, Cap: cap} copySlice(d.elemType, dst, src) } - if err := d.valueDecoder.decode(ctx, data+uintptr(idx)*d.size); err != nil { - return err + c, err := d.valueDecoder.decode(buf, cursor, data+uintptr(idx)*d.size) + if err != nil { + return 0, err } - cursor = ctx.skipWhiteSpace() + cursor = c + cursor = skipWhiteSpace(buf, cursor) switch buf[cursor] { case ']': *(*reflect.SliceHeader)(unsafe.Pointer(p)) = reflect.SliceHeader{ @@ -58,16 +58,16 @@ func (d *sliceDecoder) decode(ctx *context, p uintptr) error { Len: idx + 1, Cap: cap, } - ctx.cursor++ - return nil + cursor++ + return cursor, nil case ',': idx++ continue default: - return errors.New("syntax error slice") + return 0, errors.New("syntax error slice") } } } } - return errors.New("unexpected error slice") + return 0, errors.New("unexpected error slice") } diff --git a/decode_string.go b/decode_string.go index 1be2c2b..e6a0d4e 100644 --- a/decode_string.go +++ b/decode_string.go @@ -12,19 +12,18 @@ func newStringDecoder() *stringDecoder { return &stringDecoder{} } -func (d *stringDecoder) decode(ctx *context, p uintptr) error { - bytes, err := d.decodeByte(ctx) +func (d *stringDecoder) decode(buf []byte, cursor int, p uintptr) (int, error) { + bytes, c, err := d.decodeByte(buf, cursor) if err != nil { - return err + return 0, err } + cursor = c *(*string)(unsafe.Pointer(p)) = *(*string)(unsafe.Pointer(&bytes)) - return nil + return cursor, nil } -func (d *stringDecoder) decodeByte(ctx *context) ([]byte, error) { - buf := ctx.buf - buflen := ctx.buflen - cursor := ctx.cursor +func (d *stringDecoder) decodeByte(buf []byte, cursor int) ([]byte, int, error) { + buflen := len(buf) for ; cursor < buflen; cursor++ { switch buf[cursor] { case ' ', '\n', '\t', '\r': @@ -39,27 +38,26 @@ func (d *stringDecoder) decodeByte(ctx *context) ([]byte, error) { case '"': literal := buf[start:cursor] cursor++ - ctx.cursor = cursor - return literal, nil + return literal, cursor, nil } } - return nil, errors.New("unexpected error string") + return nil, 0, errors.New("unexpected error string") case 'n': - if cursor+3 >= ctx.buflen { - return nil, errors.New("unexpected error. invalid bool character") + if cursor+3 >= buflen { + return nil, 0, errors.New("unexpected error. invalid bool character") } if buf[cursor+1] != 'u' { - return nil, errors.New("unexpected error. invalid bool character") + return nil, 0, errors.New("unexpected error. invalid bool character") } if buf[cursor+2] != 'l' { - return nil, errors.New("unexpected error. invalid bool character") + return nil, 0, errors.New("unexpected error. invalid bool character") } if buf[cursor+3] != 'l' { - return nil, errors.New("unexpected error. invalid bool character") + return nil, 0, errors.New("unexpected error. invalid bool character") } - ctx.cursor += 5 - return []byte{}, nil + cursor += 5 + return []byte{}, cursor, nil } } - return nil, errors.New("unexpected error key delimiter") + return nil, 0, errors.New("unexpected error key delimiter") } diff --git a/decode_struct.go b/decode_struct.go index 57588ae..1c4c66c 100644 --- a/decode_struct.go +++ b/decode_struct.go @@ -22,13 +22,11 @@ func newStructDecoder(fieldMap map[string]*structFieldSet) *structDecoder { } } -func (d *structDecoder) skipValue(ctx *context) error { - ctx.skipWhiteSpace() +func (d *structDecoder) skipValue(buf []byte, cursor int) (int, error) { + cursor = skipWhiteSpace(buf, cursor) braceCount := 0 bracketCount := 0 - cursor := ctx.cursor - buf := ctx.buf - buflen := ctx.buflen + buflen := len(buf) for ; cursor < buflen; cursor++ { switch buf[cursor] { case '{': @@ -38,15 +36,13 @@ func (d *structDecoder) skipValue(ctx *context) error { case '}': braceCount-- if braceCount == -1 && bracketCount == 0 { - ctx.cursor = cursor - return nil + return cursor, nil } case ']': bracketCount-- case ',': if bracketCount == 0 && braceCount == 0 { - ctx.cursor = cursor - return nil + return cursor, nil } case '"': cursor++ @@ -56,8 +52,7 @@ func (d *structDecoder) skipValue(ctx *context) error { cursor++ case '"': if bracketCount == 0 && braceCount == 0 { - ctx.cursor = cursor + 1 - return nil + return cursor + 1, nil } goto QUOTE_END } @@ -65,55 +60,56 @@ func (d *structDecoder) skipValue(ctx *context) error { QUOTE_END: } } - return errors.New("unexpected error value") + return cursor, errors.New("unexpected error value") } -func (d *structDecoder) decode(ctx *context, p uintptr) error { - ctx.skipWhiteSpace() - buf := ctx.buf - buflen := ctx.buflen - cursor := ctx.cursor +func (d *structDecoder) decode(buf []byte, cursor int, p uintptr) (int, error) { + buflen := len(buf) + cursor = skipWhiteSpace(buf, cursor) if buflen < 2 { - return errors.New("unexpected error {}") + return 0, errors.New("unexpected error {}") } if buf[cursor] != '{' { - return errors.New("unexpected error {") + return 0, errors.New("unexpected error {") } cursor++ for ; cursor < buflen; cursor++ { - ctx.cursor = cursor - key, err := d.keyDecoder.decodeByte(ctx) + key, c, err := d.keyDecoder.decodeByte(buf, cursor) if err != nil { - return err + return 0, err } - cursor = ctx.skipWhiteSpace() + cursor = c + cursor = skipWhiteSpace(buf, cursor) if buf[cursor] != ':' { - return errors.New("unexpected error invalid delimiter for object") + return 0, errors.New("unexpected error invalid delimiter for object") } cursor++ if cursor >= buflen { - return errors.New("unexpected error missing value") + return 0, errors.New("unexpected error missing value") } - ctx.cursor = cursor k := *(*string)(unsafe.Pointer(&key)) field, exists := d.fieldMap[k] if exists { - if err := field.dec.decode(ctx, p+field.offset); err != nil { - return err + c, err := field.dec.decode(buf, cursor, p+field.offset) + if err != nil { + return 0, err } + cursor = c } else { - if err := d.skipValue(ctx); err != nil { - return err + c, err := d.skipValue(buf, cursor) + if err != nil { + return 0, err } + cursor = c } - cursor = ctx.skipWhiteSpace() + cursor = skipWhiteSpace(buf, cursor) if buf[cursor] == '}' { - ctx.cursor++ - return nil + cursor++ + return cursor, nil } if buf[cursor] != ',' { - return errors.New("unexpected error ,") + return 0, errors.New("unexpected error ,") } } - return nil + return cursor, nil } diff --git a/decode_uint.go b/decode_uint.go index 3b23335..b78e7dc 100644 --- a/decode_uint.go +++ b/decode_uint.go @@ -28,10 +28,8 @@ func (d *uintDecoder) parseUint(b []byte) uint64 { return sum } -func (d *uintDecoder) decodeByte(ctx *context) ([]byte, error) { - buf := ctx.buf - buflen := ctx.buflen - cursor := ctx.cursor +func (d *uintDecoder) decodeByte(buf []byte, cursor int) ([]byte, int, error) { + buflen := len(buf) for ; cursor < buflen; cursor++ { switch buf[cursor] { case ' ', '\n', '\t', '\r': @@ -47,18 +45,18 @@ func (d *uintDecoder) decodeByte(ctx *context) ([]byte, error) { break } num := buf[start:cursor] - ctx.cursor = cursor - return num, nil + return num, cursor, nil } } - return nil, errors.New("unexpected error number") + return nil, 0, errors.New("unexpected error number") } -func (d *uintDecoder) decode(ctx *context, p uintptr) error { - bytes, err := d.decodeByte(ctx) +func (d *uintDecoder) decode(buf []byte, cursor int, p uintptr) (int, error) { + bytes, c, err := d.decodeByte(buf, cursor) if err != nil { - return err + return 0, err } + cursor = c d.op(p, d.parseUint(bytes)) - return nil + return cursor, nil }