Remove context for decoding

This commit is contained in:
Masaaki Goshima 2020-05-07 02:37:29 +09:00
parent 82e8cc766f
commit f198ef6517
12 changed files with 159 additions and 200 deletions

View File

@ -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
}

View File

@ -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")
}

View File

@ -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
}

View File

@ -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{}
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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")
}

View File

@ -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")
}

View File

@ -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
}

View File

@ -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
}