Source file
src/reflect/map_swiss.go
1
2
3
4
5
6
7 package reflect
8
9 import (
10 "internal/abi"
11 "internal/runtime/maps"
12 "unsafe"
13 )
14
15
16 type mapType struct {
17 abi.SwissMapType
18 }
19
20 func (t *rtype) Key() Type {
21 if t.Kind() != Map {
22 panic("reflect: Key of non-map type " + t.String())
23 }
24 tt := (*mapType)(unsafe.Pointer(t))
25 return toType(tt.Key)
26 }
27
28
29
30
31
32
33
34 func MapOf(key, elem Type) Type {
35 ktyp := key.common()
36 etyp := elem.common()
37
38 if ktyp.Equal == nil {
39 panic("reflect.MapOf: invalid key type " + stringFor(ktyp))
40 }
41
42
43 ckey := cacheKey{Map, ktyp, etyp, 0}
44 if mt, ok := lookupCache.Load(ckey); ok {
45 return mt.(Type)
46 }
47
48
49 s := "map[" + stringFor(ktyp) + "]" + stringFor(etyp)
50 for _, tt := range typesByString(s) {
51 mt := (*mapType)(unsafe.Pointer(tt))
52 if mt.Key == ktyp && mt.Elem == etyp {
53 ti, _ := lookupCache.LoadOrStore(ckey, toRType(tt))
54 return ti.(Type)
55 }
56 }
57
58 group, slot := groupAndSlotOf(key, elem)
59
60
61
62
63 var imap any = (map[unsafe.Pointer]unsafe.Pointer)(nil)
64 mt := **(**mapType)(unsafe.Pointer(&imap))
65 mt.Str = resolveReflectName(newName(s, "", false, false))
66 mt.TFlag = 0
67 mt.Hash = fnv1(etyp.Hash, 'm', byte(ktyp.Hash>>24), byte(ktyp.Hash>>16), byte(ktyp.Hash>>8), byte(ktyp.Hash))
68 mt.Key = ktyp
69 mt.Elem = etyp
70 mt.Group = group.common()
71 mt.Hasher = func(p unsafe.Pointer, seed uintptr) uintptr {
72 return typehash(ktyp, p, seed)
73 }
74 mt.SlotSize = slot.Size()
75 mt.ElemOff = slot.Field(1).Offset
76 mt.Flags = 0
77 if needKeyUpdate(ktyp) {
78 mt.Flags |= abi.SwissMapNeedKeyUpdate
79 }
80 if hashMightPanic(ktyp) {
81 mt.Flags |= abi.SwissMapHashMightPanic
82 }
83 if ktyp.Size_ > abi.SwissMapMaxKeyBytes {
84 mt.Flags |= abi.SwissMapIndirectKey
85 }
86 if etyp.Size_ > abi.SwissMapMaxKeyBytes {
87 mt.Flags |= abi.SwissMapIndirectElem
88 }
89 mt.PtrToThis = 0
90
91 ti, _ := lookupCache.LoadOrStore(ckey, toRType(&mt.Type))
92 return ti.(Type)
93 }
94
95 func groupAndSlotOf(ktyp, etyp Type) (Type, Type) {
96
97
98
99
100
101
102
103
104 if ktyp.Size() > abi.SwissMapMaxKeyBytes {
105 ktyp = PointerTo(ktyp)
106 }
107 if etyp.Size() > abi.SwissMapMaxElemBytes {
108 etyp = PointerTo(etyp)
109 }
110
111 fields := []StructField{
112 {
113 Name: "Key",
114 Type: ktyp,
115 },
116 {
117 Name: "Elem",
118 Type: etyp,
119 },
120 }
121 slot := StructOf(fields)
122
123 fields = []StructField{
124 {
125 Name: "Ctrl",
126 Type: TypeFor[uint64](),
127 },
128 {
129 Name: "Slots",
130 Type: ArrayOf(abi.SwissMapGroupSlots, slot),
131 },
132 }
133 group := StructOf(fields)
134 return group, slot
135 }
136
137 var stringType = rtypeOf("")
138
139
140
141
142
143 func (v Value) MapIndex(key Value) Value {
144 v.mustBe(Map)
145 tt := (*mapType)(unsafe.Pointer(v.typ()))
146
147
148
149
150
151
152
153
154
155 var e unsafe.Pointer
156 if (tt.Key == stringType || key.kind() == String) && tt.Key == key.typ() && tt.Elem.Size() <= abi.SwissMapMaxElemBytes {
157 k := *(*string)(key.ptr)
158 e = mapaccess_faststr(v.typ(), v.pointer(), k)
159 } else {
160 key = key.assignTo("reflect.Value.MapIndex", tt.Key, nil)
161 var k unsafe.Pointer
162 if key.flag&flagIndir != 0 {
163 k = key.ptr
164 } else {
165 k = unsafe.Pointer(&key.ptr)
166 }
167 e = mapaccess(v.typ(), v.pointer(), k)
168 }
169 if e == nil {
170 return Value{}
171 }
172 typ := tt.Elem
173 fl := (v.flag | key.flag).ro()
174 fl |= flag(typ.Kind())
175 return copyVal(typ, fl, e)
176 }
177
178
179
180
181
182 func (v Value) MapKeys() []Value {
183 v.mustBe(Map)
184 tt := (*mapType)(unsafe.Pointer(v.typ()))
185 keyType := tt.Key
186
187 fl := v.flag.ro() | flag(keyType.Kind())
188
189 m := v.pointer()
190 mlen := int(0)
191 if m != nil {
192 mlen = maplen(m)
193 }
194 var it maps.Iter
195 mapiterinit(v.typ(), m, &it)
196 a := make([]Value, mlen)
197 var i int
198 for i = 0; i < len(a); i++ {
199 key := it.Key()
200 if key == nil {
201
202
203
204 break
205 }
206 a[i] = copyVal(keyType, fl, key)
207 mapiternext(&it)
208 }
209 return a[:i]
210 }
211
212
213
214 type MapIter struct {
215 m Value
216 hiter maps.Iter
217 }
218
219
220
221 type hiter = maps.Iter
222
223
224 func (iter *MapIter) Key() Value {
225 if !iter.hiter.Initialized() {
226 panic("MapIter.Key called before Next")
227 }
228 iterkey := iter.hiter.Key()
229 if iterkey == nil {
230 panic("MapIter.Key called on exhausted iterator")
231 }
232
233 t := (*mapType)(unsafe.Pointer(iter.m.typ()))
234 ktype := t.Key
235 return copyVal(ktype, iter.m.flag.ro()|flag(ktype.Kind()), iterkey)
236 }
237
238
239
240
241
242 func (v Value) SetIterKey(iter *MapIter) {
243 if !iter.hiter.Initialized() {
244 panic("reflect: Value.SetIterKey called before Next")
245 }
246 iterkey := iter.hiter.Key()
247 if iterkey == nil {
248 panic("reflect: Value.SetIterKey called on exhausted iterator")
249 }
250
251 v.mustBeAssignable()
252 var target unsafe.Pointer
253 if v.kind() == Interface {
254 target = v.ptr
255 }
256
257 t := (*mapType)(unsafe.Pointer(iter.m.typ()))
258 ktype := t.Key
259
260 iter.m.mustBeExported()
261 key := Value{ktype, iterkey, iter.m.flag | flag(ktype.Kind()) | flagIndir}
262 key = key.assignTo("reflect.MapIter.SetKey", v.typ(), target)
263 typedmemmove(v.typ(), v.ptr, key.ptr)
264 }
265
266
267 func (iter *MapIter) Value() Value {
268 if !iter.hiter.Initialized() {
269 panic("MapIter.Value called before Next")
270 }
271 iterelem := iter.hiter.Elem()
272 if iterelem == nil {
273 panic("MapIter.Value called on exhausted iterator")
274 }
275
276 t := (*mapType)(unsafe.Pointer(iter.m.typ()))
277 vtype := t.Elem
278 return copyVal(vtype, iter.m.flag.ro()|flag(vtype.Kind()), iterelem)
279 }
280
281
282
283
284
285 func (v Value) SetIterValue(iter *MapIter) {
286 if !iter.hiter.Initialized() {
287 panic("reflect: Value.SetIterValue called before Next")
288 }
289 iterelem := iter.hiter.Elem()
290 if iterelem == nil {
291 panic("reflect: Value.SetIterValue called on exhausted iterator")
292 }
293
294 v.mustBeAssignable()
295 var target unsafe.Pointer
296 if v.kind() == Interface {
297 target = v.ptr
298 }
299
300 t := (*mapType)(unsafe.Pointer(iter.m.typ()))
301 vtype := t.Elem
302
303 iter.m.mustBeExported()
304 elem := Value{vtype, iterelem, iter.m.flag | flag(vtype.Kind()) | flagIndir}
305 elem = elem.assignTo("reflect.MapIter.SetValue", v.typ(), target)
306 typedmemmove(v.typ(), v.ptr, elem.ptr)
307 }
308
309
310
311
312 func (iter *MapIter) Next() bool {
313 if !iter.m.IsValid() {
314 panic("MapIter.Next called on an iterator that does not have an associated map Value")
315 }
316 if !iter.hiter.Initialized() {
317 mapiterinit(iter.m.typ(), iter.m.pointer(), &iter.hiter)
318 } else {
319 if iter.hiter.Key() == nil {
320 panic("MapIter.Next called on exhausted iterator")
321 }
322 mapiternext(&iter.hiter)
323 }
324 return iter.hiter.Key() != nil
325 }
326
327
328
329
330
331 func (iter *MapIter) Reset(v Value) {
332 if v.IsValid() {
333 v.mustBe(Map)
334 }
335 iter.m = v
336 iter.hiter = maps.Iter{}
337 }
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354 func (v Value) MapRange() *MapIter {
355
356
357
358
359 if v.kind() != Map {
360 v.panicNotMap()
361 }
362 return &MapIter{m: v}
363 }
364
365
366
367
368
369
370
371 func (v Value) SetMapIndex(key, elem Value) {
372 v.mustBe(Map)
373 v.mustBeExported()
374 key.mustBeExported()
375 tt := (*mapType)(unsafe.Pointer(v.typ()))
376
377 if (tt.Key == stringType || key.kind() == String) && tt.Key == key.typ() && tt.Elem.Size() <= abi.SwissMapMaxElemBytes {
378 k := *(*string)(key.ptr)
379 if elem.typ() == nil {
380 mapdelete_faststr(v.typ(), v.pointer(), k)
381 return
382 }
383 elem.mustBeExported()
384 elem = elem.assignTo("reflect.Value.SetMapIndex", tt.Elem, nil)
385 var e unsafe.Pointer
386 if elem.flag&flagIndir != 0 {
387 e = elem.ptr
388 } else {
389 e = unsafe.Pointer(&elem.ptr)
390 }
391 mapassign_faststr(v.typ(), v.pointer(), k, e)
392 return
393 }
394
395 key = key.assignTo("reflect.Value.SetMapIndex", tt.Key, nil)
396 var k unsafe.Pointer
397 if key.flag&flagIndir != 0 {
398 k = key.ptr
399 } else {
400 k = unsafe.Pointer(&key.ptr)
401 }
402 if elem.typ() == nil {
403 mapdelete(v.typ(), v.pointer(), k)
404 return
405 }
406 elem.mustBeExported()
407 elem = elem.assignTo("reflect.Value.SetMapIndex", tt.Elem, nil)
408 var e unsafe.Pointer
409 if elem.flag&flagIndir != 0 {
410 e = elem.ptr
411 } else {
412 e = unsafe.Pointer(&elem.ptr)
413 }
414 mapassign(v.typ(), v.pointer(), k, e)
415 }
416
417
418
419
420
421
422 func (f flag) panicNotMap() {
423 f.mustBe(Map)
424 }
425
View as plain text