123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199 |
- /*
- * Copyright 2021 ByteDance Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- package encoder
- import (
- "encoding"
- "reflect"
- "sync"
- "unsafe"
- "github.com/bytedance/sonic/internal/native"
- "github.com/bytedance/sonic/internal/rt"
- )
- type _MapPair struct {
- k string // when the map key is integer, k is pointed to m
- v unsafe.Pointer
- m [32]byte
- }
- type _MapIterator struct {
- it rt.GoMapIterator // must be the first field
- kv rt.GoSlice // slice of _MapPair
- ki int
- }
- var (
- iteratorPool = sync.Pool{}
- iteratorPair = rt.UnpackType(reflect.TypeOf(_MapPair{}))
- )
- func init() {
- if unsafe.Offsetof(_MapIterator{}.it) != 0 {
- panic("_MapIterator.it is not the first field")
- }
- }
- func newIterator() *_MapIterator {
- if v := iteratorPool.Get(); v == nil {
- return new(_MapIterator)
- } else {
- return resetIterator(v.(*_MapIterator))
- }
- }
- func resetIterator(p *_MapIterator) *_MapIterator {
- p.ki = 0
- p.it = rt.GoMapIterator{}
- p.kv.Len = 0
- return p
- }
- func (self *_MapIterator) at(i int) *_MapPair {
- return (*_MapPair)(unsafe.Pointer(uintptr(self.kv.Ptr) + uintptr(i) * unsafe.Sizeof(_MapPair{})))
- }
- func (self *_MapIterator) add() (p *_MapPair) {
- p = self.at(self.kv.Len)
- self.kv.Len++
- return
- }
- func (self *_MapIterator) data() (p []_MapPair) {
- *(*rt.GoSlice)(unsafe.Pointer(&p)) = self.kv
- return
- }
- func (self *_MapIterator) append(t *rt.GoType, k unsafe.Pointer, v unsafe.Pointer) (err error) {
- p := self.add()
- p.v = v
- /* check for strings */
- if tk := t.Kind(); tk != reflect.String {
- return self.appendGeneric(p, t, tk, k)
- }
- /* fast path for strings */
- p.k = *(*string)(k)
- return nil
- }
- func (self *_MapIterator) appendGeneric(p *_MapPair, t *rt.GoType, v reflect.Kind, k unsafe.Pointer) error {
- switch v {
- case reflect.Int : p.k = rt.Mem2Str(p.m[:native.I64toa(&p.m[0], int64(*(*int)(k)))]) ; return nil
- case reflect.Int8 : p.k = rt.Mem2Str(p.m[:native.I64toa(&p.m[0], int64(*(*int8)(k)))]) ; return nil
- case reflect.Int16 : p.k = rt.Mem2Str(p.m[:native.I64toa(&p.m[0], int64(*(*int16)(k)))]) ; return nil
- case reflect.Int32 : p.k = rt.Mem2Str(p.m[:native.I64toa(&p.m[0], int64(*(*int32)(k)))]) ; return nil
- case reflect.Int64 : p.k = rt.Mem2Str(p.m[:native.I64toa(&p.m[0], *(*int64)(k))]) ; return nil
- case reflect.Uint : p.k = rt.Mem2Str(p.m[:native.U64toa(&p.m[0], uint64(*(*uint)(k)))]) ; return nil
- case reflect.Uint8 : p.k = rt.Mem2Str(p.m[:native.U64toa(&p.m[0], uint64(*(*uint8)(k)))]) ; return nil
- case reflect.Uint16 : p.k = rt.Mem2Str(p.m[:native.U64toa(&p.m[0], uint64(*(*uint16)(k)))]) ; return nil
- case reflect.Uint32 : p.k = rt.Mem2Str(p.m[:native.U64toa(&p.m[0], uint64(*(*uint32)(k)))]) ; return nil
- case reflect.Uint64 : p.k = rt.Mem2Str(p.m[:native.U64toa(&p.m[0], *(*uint64)(k))]) ; return nil
- case reflect.Uintptr : p.k = rt.Mem2Str(p.m[:native.U64toa(&p.m[0], uint64(*(*uintptr)(k)))]) ; return nil
- case reflect.Interface : return self.appendInterface(p, t, k)
- case reflect.Struct, reflect.Ptr : return self.appendConcrete(p, t, k)
- default : panic("unexpected map key type")
- }
- }
- func (self *_MapIterator) appendConcrete(p *_MapPair, t *rt.GoType, k unsafe.Pointer) (err error) {
- // compiler has already checked that the type implements the encoding.MarshalText interface
- if !t.Indirect() {
- k = *(*unsafe.Pointer)(k)
- }
- eface := rt.GoEface{Value: k, Type: t}.Pack()
- out, err := eface.(encoding.TextMarshaler).MarshalText()
- if err != nil {
- return err
- }
- p.k = rt.Mem2Str(out)
- return
- }
- func (self *_MapIterator) appendInterface(p *_MapPair, t *rt.GoType, k unsafe.Pointer) (err error) {
- if len(rt.IfaceType(t).Methods) == 0 {
- panic("unexpected map key type")
- } else if p.k, err = asText(k); err == nil {
- return nil
- } else {
- return
- }
- }
- func iteratorStop(p *_MapIterator) {
- iteratorPool.Put(p)
- }
- func iteratorNext(p *_MapIterator) {
- i := p.ki
- t := &p.it
- /* check for unordered iteration */
- if i < 0 {
- mapiternext(t)
- return
- }
- /* check for end of iteration */
- if p.ki >= p.kv.Len {
- t.K = nil
- t.V = nil
- return
- }
- /* update the key-value pair, and increase the pointer */
- t.K = unsafe.Pointer(&p.at(p.ki).k)
- t.V = p.at(p.ki).v
- p.ki++
- }
- func iteratorStart(t *rt.GoMapType, m *rt.GoMap, fv uint64) (*_MapIterator, error) {
- it := newIterator()
- mapiterinit(t, m, &it.it)
- /* check for key-sorting, empty map don't need sorting */
- if m.Count == 0 || (fv & uint64(SortMapKeys)) == 0 {
- it.ki = -1
- return it, nil
- }
- /* pre-allocate space if needed */
- if m.Count > it.kv.Cap {
- it.kv = growslice(iteratorPair, it.kv, m.Count)
- }
- /* dump all the key-value pairs */
- for ; it.it.K != nil; mapiternext(&it.it) {
- if err := it.append(t.Key, it.it.K, it.it.V); err != nil {
- iteratorStop(it)
- return nil, err
- }
- }
- /* sort the keys, map with only 1 item don't need sorting */
- if it.ki = 1; m.Count > 1 {
- radixQsort(it.data(), 0, maxDepth(it.kv.Len))
- }
- /* load the first pair into iterator */
- it.it.V = it.at(0).v
- it.it.K = unsafe.Pointer(&it.at(0).k)
- return it, nil
- }
|