github.com/bytedance/sonic@v1.11.7-0.20240517092252-d2edb31b167b/internal/encoder/mapiter.go (about) 1 /* 2 * Copyright 2021 ByteDance Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package encoder 18 19 import ( 20 "encoding" 21 "reflect" 22 "sync" 23 "unsafe" 24 25 "github.com/bytedance/sonic/internal/native" 26 "github.com/bytedance/sonic/internal/rt" 27 ) 28 29 type _MapPair struct { 30 k string // when the map key is integer, k is pointed to m 31 v unsafe.Pointer 32 m [32]byte 33 } 34 35 type _MapIterator struct { 36 it rt.GoMapIterator // must be the first field 37 kv rt.GoSlice // slice of _MapPair 38 ki int 39 } 40 41 var ( 42 iteratorPool = sync.Pool{} 43 iteratorPair = rt.UnpackType(reflect.TypeOf(_MapPair{})) 44 ) 45 46 func init() { 47 if unsafe.Offsetof(_MapIterator{}.it) != 0 { 48 panic("_MapIterator.it is not the first field") 49 } 50 } 51 52 53 func newIterator() *_MapIterator { 54 if v := iteratorPool.Get(); v == nil { 55 return new(_MapIterator) 56 } else { 57 return resetIterator(v.(*_MapIterator)) 58 } 59 } 60 61 func resetIterator(p *_MapIterator) *_MapIterator { 62 p.ki = 0 63 p.it = rt.GoMapIterator{} 64 p.kv.Len = 0 65 return p 66 } 67 68 func (self *_MapIterator) at(i int) *_MapPair { 69 return (*_MapPair)(unsafe.Pointer(uintptr(self.kv.Ptr) + uintptr(i) * unsafe.Sizeof(_MapPair{}))) 70 } 71 72 func (self *_MapIterator) add() (p *_MapPair) { 73 p = self.at(self.kv.Len) 74 self.kv.Len++ 75 return 76 } 77 78 func (self *_MapIterator) data() (p []_MapPair) { 79 *(*rt.GoSlice)(unsafe.Pointer(&p)) = self.kv 80 return 81 } 82 83 func (self *_MapIterator) append(t *rt.GoType, k unsafe.Pointer, v unsafe.Pointer) (err error) { 84 p := self.add() 85 p.v = v 86 87 /* check for strings */ 88 if tk := t.Kind(); tk != reflect.String { 89 return self.appendGeneric(p, t, tk, k) 90 } 91 92 /* fast path for strings */ 93 p.k = *(*string)(k) 94 return nil 95 } 96 97 func (self *_MapIterator) appendGeneric(p *_MapPair, t *rt.GoType, v reflect.Kind, k unsafe.Pointer) error { 98 switch v { 99 case reflect.Int : p.k = rt.Mem2Str(p.m[:native.I64toa(&p.m[0], int64(*(*int)(k)))]) ; return nil 100 case reflect.Int8 : p.k = rt.Mem2Str(p.m[:native.I64toa(&p.m[0], int64(*(*int8)(k)))]) ; return nil 101 case reflect.Int16 : p.k = rt.Mem2Str(p.m[:native.I64toa(&p.m[0], int64(*(*int16)(k)))]) ; return nil 102 case reflect.Int32 : p.k = rt.Mem2Str(p.m[:native.I64toa(&p.m[0], int64(*(*int32)(k)))]) ; return nil 103 case reflect.Int64 : p.k = rt.Mem2Str(p.m[:native.I64toa(&p.m[0], *(*int64)(k))]) ; return nil 104 case reflect.Uint : p.k = rt.Mem2Str(p.m[:native.U64toa(&p.m[0], uint64(*(*uint)(k)))]) ; return nil 105 case reflect.Uint8 : p.k = rt.Mem2Str(p.m[:native.U64toa(&p.m[0], uint64(*(*uint8)(k)))]) ; return nil 106 case reflect.Uint16 : p.k = rt.Mem2Str(p.m[:native.U64toa(&p.m[0], uint64(*(*uint16)(k)))]) ; return nil 107 case reflect.Uint32 : p.k = rt.Mem2Str(p.m[:native.U64toa(&p.m[0], uint64(*(*uint32)(k)))]) ; return nil 108 case reflect.Uint64 : p.k = rt.Mem2Str(p.m[:native.U64toa(&p.m[0], *(*uint64)(k))]) ; return nil 109 case reflect.Uintptr : p.k = rt.Mem2Str(p.m[:native.U64toa(&p.m[0], uint64(*(*uintptr)(k)))]) ; return nil 110 case reflect.Interface : return self.appendInterface(p, t, k) 111 case reflect.Struct, reflect.Ptr : return self.appendConcrete(p, t, k) 112 default : panic("unexpected map key type") 113 } 114 } 115 116 func (self *_MapIterator) appendConcrete(p *_MapPair, t *rt.GoType, k unsafe.Pointer) (err error) { 117 // compiler has already checked that the type implements the encoding.MarshalText interface 118 if !t.Indirect() { 119 k = *(*unsafe.Pointer)(k) 120 } 121 eface := rt.GoEface{Value: k, Type: t}.Pack() 122 out, err := eface.(encoding.TextMarshaler).MarshalText() 123 if err != nil { 124 return err 125 } 126 p.k = rt.Mem2Str(out) 127 return 128 } 129 130 func (self *_MapIterator) appendInterface(p *_MapPair, t *rt.GoType, k unsafe.Pointer) (err error) { 131 if len(rt.IfaceType(t).Methods) == 0 { 132 panic("unexpected map key type") 133 } else if p.k, err = asText(k); err == nil { 134 return nil 135 } else { 136 return 137 } 138 } 139 140 func iteratorStop(p *_MapIterator) { 141 iteratorPool.Put(p) 142 } 143 144 func iteratorNext(p *_MapIterator) { 145 i := p.ki 146 t := &p.it 147 148 /* check for unordered iteration */ 149 if i < 0 { 150 mapiternext(t) 151 return 152 } 153 154 /* check for end of iteration */ 155 if p.ki >= p.kv.Len { 156 t.K = nil 157 t.V = nil 158 return 159 } 160 161 /* update the key-value pair, and increase the pointer */ 162 t.K = unsafe.Pointer(&p.at(p.ki).k) 163 t.V = p.at(p.ki).v 164 p.ki++ 165 } 166 167 func iteratorStart(t *rt.GoMapType, m *rt.GoMap, fv uint64) (*_MapIterator, error) { 168 it := newIterator() 169 mapiterinit(t, m, &it.it) 170 171 /* check for key-sorting, empty map don't need sorting */ 172 if m.Count == 0 || (fv & uint64(SortMapKeys)) == 0 { 173 it.ki = -1 174 return it, nil 175 } 176 177 /* pre-allocate space if needed */ 178 if m.Count > it.kv.Cap { 179 it.kv = rt.GrowSlice(iteratorPair, it.kv, m.Count) 180 } 181 182 /* dump all the key-value pairs */ 183 for ; it.it.K != nil; mapiternext(&it.it) { 184 if err := it.append(t.Key, it.it.K, it.it.V); err != nil { 185 iteratorStop(it) 186 return nil, err 187 } 188 } 189 190 /* sort the keys, map with only 1 item don't need sorting */ 191 if it.ki = 1; m.Count > 1 { 192 radixQsort(it.data(), 0, maxDepth(it.kv.Len)) 193 } 194 195 /* load the first pair into iterator */ 196 it.it.V = it.at(0).v 197 it.it.K = unsafe.Pointer(&it.at(0).k) 198 return it, nil 199 }