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