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