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