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