gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

map.go (7048B)


      1 package decoder
      2 
      3 import (
      4 	"reflect"
      5 	"unsafe"
      6 
      7 	"github.com/goccy/go-json/internal/errors"
      8 	"github.com/goccy/go-json/internal/runtime"
      9 )
     10 
     11 type mapDecoder struct {
     12 	mapType                 *runtime.Type
     13 	keyType                 *runtime.Type
     14 	valueType               *runtime.Type
     15 	canUseAssignFaststrType bool
     16 	keyDecoder              Decoder
     17 	valueDecoder            Decoder
     18 	structName              string
     19 	fieldName               string
     20 }
     21 
     22 func newMapDecoder(mapType *runtime.Type, keyType *runtime.Type, keyDec Decoder, valueType *runtime.Type, valueDec Decoder, structName, fieldName string) *mapDecoder {
     23 	return &mapDecoder{
     24 		mapType:                 mapType,
     25 		keyDecoder:              keyDec,
     26 		keyType:                 keyType,
     27 		canUseAssignFaststrType: canUseAssignFaststrType(keyType, valueType),
     28 		valueType:               valueType,
     29 		valueDecoder:            valueDec,
     30 		structName:              structName,
     31 		fieldName:               fieldName,
     32 	}
     33 }
     34 
     35 const (
     36 	mapMaxElemSize = 128
     37 )
     38 
     39 // See detail: https://github.com/goccy/go-json/pull/283
     40 func canUseAssignFaststrType(key *runtime.Type, value *runtime.Type) bool {
     41 	indirectElem := value.Size() > mapMaxElemSize
     42 	if indirectElem {
     43 		return false
     44 	}
     45 	return key.Kind() == reflect.String
     46 }
     47 
     48 //go:linkname makemap reflect.makemap
     49 func makemap(*runtime.Type, int) unsafe.Pointer
     50 
     51 //nolint:golint
     52 //go:linkname mapassign_faststr runtime.mapassign_faststr
     53 //go:noescape
     54 func mapassign_faststr(t *runtime.Type, m unsafe.Pointer, s string) unsafe.Pointer
     55 
     56 //go:linkname mapassign reflect.mapassign
     57 //go:noescape
     58 func mapassign(t *runtime.Type, m unsafe.Pointer, k, v unsafe.Pointer)
     59 
     60 func (d *mapDecoder) mapassign(t *runtime.Type, m, k, v unsafe.Pointer) {
     61 	if d.canUseAssignFaststrType {
     62 		mapV := mapassign_faststr(t, m, *(*string)(k))
     63 		typedmemmove(d.valueType, mapV, v)
     64 	} else {
     65 		mapassign(t, m, k, v)
     66 	}
     67 }
     68 
     69 func (d *mapDecoder) DecodeStream(s *Stream, depth int64, p unsafe.Pointer) error {
     70 	depth++
     71 	if depth > maxDecodeNestingDepth {
     72 		return errors.ErrExceededMaxDepth(s.char(), s.cursor)
     73 	}
     74 
     75 	switch s.skipWhiteSpace() {
     76 	case 'n':
     77 		if err := nullBytes(s); err != nil {
     78 			return err
     79 		}
     80 		**(**unsafe.Pointer)(unsafe.Pointer(&p)) = nil
     81 		return nil
     82 	case '{':
     83 	default:
     84 		return errors.ErrExpected("{ character for map value", s.totalOffset())
     85 	}
     86 	mapValue := *(*unsafe.Pointer)(p)
     87 	if mapValue == nil {
     88 		mapValue = makemap(d.mapType, 0)
     89 	}
     90 	s.cursor++
     91 	if s.skipWhiteSpace() == '}' {
     92 		*(*unsafe.Pointer)(p) = mapValue
     93 		s.cursor++
     94 		return nil
     95 	}
     96 	for {
     97 		k := unsafe_New(d.keyType)
     98 		if err := d.keyDecoder.DecodeStream(s, depth, k); err != nil {
     99 			return err
    100 		}
    101 		s.skipWhiteSpace()
    102 		if !s.equalChar(':') {
    103 			return errors.ErrExpected("colon after object key", s.totalOffset())
    104 		}
    105 		s.cursor++
    106 		v := unsafe_New(d.valueType)
    107 		if err := d.valueDecoder.DecodeStream(s, depth, v); err != nil {
    108 			return err
    109 		}
    110 		d.mapassign(d.mapType, mapValue, k, v)
    111 		s.skipWhiteSpace()
    112 		if s.equalChar('}') {
    113 			**(**unsafe.Pointer)(unsafe.Pointer(&p)) = mapValue
    114 			s.cursor++
    115 			return nil
    116 		}
    117 		if !s.equalChar(',') {
    118 			return errors.ErrExpected("comma after object value", s.totalOffset())
    119 		}
    120 		s.cursor++
    121 	}
    122 }
    123 
    124 func (d *mapDecoder) Decode(ctx *RuntimeContext, cursor, depth int64, p unsafe.Pointer) (int64, error) {
    125 	buf := ctx.Buf
    126 	depth++
    127 	if depth > maxDecodeNestingDepth {
    128 		return 0, errors.ErrExceededMaxDepth(buf[cursor], cursor)
    129 	}
    130 
    131 	cursor = skipWhiteSpace(buf, cursor)
    132 	buflen := int64(len(buf))
    133 	if buflen < 2 {
    134 		return 0, errors.ErrExpected("{} for map", cursor)
    135 	}
    136 	switch buf[cursor] {
    137 	case 'n':
    138 		if err := validateNull(buf, cursor); err != nil {
    139 			return 0, err
    140 		}
    141 		cursor += 4
    142 		**(**unsafe.Pointer)(unsafe.Pointer(&p)) = nil
    143 		return cursor, nil
    144 	case '{':
    145 	default:
    146 		return 0, errors.ErrExpected("{ character for map value", cursor)
    147 	}
    148 	cursor++
    149 	cursor = skipWhiteSpace(buf, cursor)
    150 	mapValue := *(*unsafe.Pointer)(p)
    151 	if mapValue == nil {
    152 		mapValue = makemap(d.mapType, 0)
    153 	}
    154 	if buf[cursor] == '}' {
    155 		**(**unsafe.Pointer)(unsafe.Pointer(&p)) = mapValue
    156 		cursor++
    157 		return cursor, nil
    158 	}
    159 	for {
    160 		k := unsafe_New(d.keyType)
    161 		keyCursor, err := d.keyDecoder.Decode(ctx, cursor, depth, k)
    162 		if err != nil {
    163 			return 0, err
    164 		}
    165 		cursor = skipWhiteSpace(buf, keyCursor)
    166 		if buf[cursor] != ':' {
    167 			return 0, errors.ErrExpected("colon after object key", cursor)
    168 		}
    169 		cursor++
    170 		v := unsafe_New(d.valueType)
    171 		valueCursor, err := d.valueDecoder.Decode(ctx, cursor, depth, v)
    172 		if err != nil {
    173 			return 0, err
    174 		}
    175 		d.mapassign(d.mapType, mapValue, k, v)
    176 		cursor = skipWhiteSpace(buf, valueCursor)
    177 		if buf[cursor] == '}' {
    178 			**(**unsafe.Pointer)(unsafe.Pointer(&p)) = mapValue
    179 			cursor++
    180 			return cursor, nil
    181 		}
    182 		if buf[cursor] != ',' {
    183 			return 0, errors.ErrExpected("comma after object value", cursor)
    184 		}
    185 		cursor++
    186 	}
    187 }
    188 
    189 func (d *mapDecoder) DecodePath(ctx *RuntimeContext, cursor, depth int64) ([][]byte, int64, error) {
    190 	buf := ctx.Buf
    191 	depth++
    192 	if depth > maxDecodeNestingDepth {
    193 		return nil, 0, errors.ErrExceededMaxDepth(buf[cursor], cursor)
    194 	}
    195 
    196 	cursor = skipWhiteSpace(buf, cursor)
    197 	buflen := int64(len(buf))
    198 	if buflen < 2 {
    199 		return nil, 0, errors.ErrExpected("{} for map", cursor)
    200 	}
    201 	switch buf[cursor] {
    202 	case 'n':
    203 		if err := validateNull(buf, cursor); err != nil {
    204 			return nil, 0, err
    205 		}
    206 		cursor += 4
    207 		return [][]byte{nullbytes}, cursor, nil
    208 	case '{':
    209 	default:
    210 		return nil, 0, errors.ErrExpected("{ character for map value", cursor)
    211 	}
    212 	cursor++
    213 	cursor = skipWhiteSpace(buf, cursor)
    214 	if buf[cursor] == '}' {
    215 		cursor++
    216 		return nil, cursor, nil
    217 	}
    218 	keyDecoder, ok := d.keyDecoder.(*stringDecoder)
    219 	if !ok {
    220 		return nil, 0, &errors.UnmarshalTypeError{
    221 			Value:  "string",
    222 			Type:   reflect.TypeOf(""),
    223 			Offset: cursor,
    224 			Struct: d.structName,
    225 			Field:  d.fieldName,
    226 		}
    227 	}
    228 	ret := [][]byte{}
    229 	for {
    230 		key, keyCursor, err := keyDecoder.decodeByte(buf, cursor)
    231 		if err != nil {
    232 			return nil, 0, err
    233 		}
    234 		cursor = skipWhiteSpace(buf, keyCursor)
    235 		if buf[cursor] != ':' {
    236 			return nil, 0, errors.ErrExpected("colon after object key", cursor)
    237 		}
    238 		cursor++
    239 		child, found, err := ctx.Option.Path.Field(string(key))
    240 		if err != nil {
    241 			return nil, 0, err
    242 		}
    243 		if found {
    244 			if child != nil {
    245 				oldPath := ctx.Option.Path.node
    246 				ctx.Option.Path.node = child
    247 				paths, c, err := d.valueDecoder.DecodePath(ctx, cursor, depth)
    248 				if err != nil {
    249 					return nil, 0, err
    250 				}
    251 				ctx.Option.Path.node = oldPath
    252 				ret = append(ret, paths...)
    253 				cursor = c
    254 			} else {
    255 				start := cursor
    256 				end, err := skipValue(buf, cursor, depth)
    257 				if err != nil {
    258 					return nil, 0, err
    259 				}
    260 				ret = append(ret, buf[start:end])
    261 				cursor = end
    262 			}
    263 		} else {
    264 			c, err := skipValue(buf, cursor, depth)
    265 			if err != nil {
    266 				return nil, 0, err
    267 			}
    268 			cursor = c
    269 		}
    270 		cursor = skipWhiteSpace(buf, cursor)
    271 		if buf[cursor] == '}' {
    272 			cursor++
    273 			return ret, cursor, nil
    274 		}
    275 		if buf[cursor] != ',' {
    276 			return nil, 0, errors.ErrExpected("comma after object value", cursor)
    277 		}
    278 		cursor++
    279 	}
    280 }