| | |
| | |
| | |
| |
|
| | package reflect |
| |
|
| | import ( |
| | "internal/abi" |
| | "internal/race" |
| | "internal/runtime/maps" |
| | "internal/runtime/sys" |
| | "unsafe" |
| | ) |
| |
|
| | func (t *rtype) Key() Type { |
| | if t.Kind() != Map { |
| | panic("reflect: Key of non-map type " + t.String()) |
| | } |
| | tt := (*abi.MapType)(unsafe.Pointer(t)) |
| | return toType(tt.Key) |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | func MapOf(key, elem Type) Type { |
| | ktyp := key.common() |
| | etyp := elem.common() |
| |
|
| | if ktyp.Equal == nil { |
| | panic("reflect.MapOf: invalid key type " + stringFor(ktyp)) |
| | } |
| |
|
| | |
| | ckey := cacheKey{Map, ktyp, etyp, 0} |
| | if mt, ok := lookupCache.Load(ckey); ok { |
| | return mt.(Type) |
| | } |
| |
|
| | |
| | s := "map[" + stringFor(ktyp) + "]" + stringFor(etyp) |
| | for _, tt := range typesByString(s) { |
| | mt := (*abi.MapType)(unsafe.Pointer(tt)) |
| | if mt.Key == ktyp && mt.Elem == etyp { |
| | ti, _ := lookupCache.LoadOrStore(ckey, toRType(tt)) |
| | return ti.(Type) |
| | } |
| | } |
| |
|
| | group, slot := groupAndSlotOf(key, elem) |
| |
|
| | |
| | |
| | |
| | var imap any = (map[unsafe.Pointer]unsafe.Pointer)(nil) |
| | mt := **(**abi.MapType)(unsafe.Pointer(&imap)) |
| | mt.Str = resolveReflectName(newName(s, "", false, false)) |
| | mt.TFlag = abi.TFlagDirectIface |
| | mt.Hash = fnv1(etyp.Hash, 'm', byte(ktyp.Hash>>24), byte(ktyp.Hash>>16), byte(ktyp.Hash>>8), byte(ktyp.Hash)) |
| | mt.Key = ktyp |
| | mt.Elem = etyp |
| | mt.Group = group.common() |
| | mt.Hasher = func(p unsafe.Pointer, seed uintptr) uintptr { |
| | return typehash(ktyp, p, seed) |
| | } |
| | mt.GroupSize = mt.Group.Size() |
| | mt.SlotSize = slot.Size() |
| | mt.ElemOff = slot.Field(1).Offset |
| | mt.Flags = 0 |
| | if needKeyUpdate(ktyp) { |
| | mt.Flags |= abi.MapNeedKeyUpdate |
| | } |
| | if hashMightPanic(ktyp) { |
| | mt.Flags |= abi.MapHashMightPanic |
| | } |
| | if ktyp.Size_ > abi.MapMaxKeyBytes { |
| | mt.Flags |= abi.MapIndirectKey |
| | } |
| | if etyp.Size_ > abi.MapMaxKeyBytes { |
| | mt.Flags |= abi.MapIndirectElem |
| | } |
| | mt.PtrToThis = 0 |
| |
|
| | ti, _ := lookupCache.LoadOrStore(ckey, toRType(&mt.Type)) |
| | return ti.(Type) |
| | } |
| |
|
| | func groupAndSlotOf(ktyp, etyp Type) (Type, Type) { |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | if ktyp.Size() > abi.MapMaxKeyBytes { |
| | ktyp = PointerTo(ktyp) |
| | } |
| | if etyp.Size() > abi.MapMaxElemBytes { |
| | etyp = PointerTo(etyp) |
| | } |
| |
|
| | fields := []StructField{ |
| | { |
| | Name: "Key", |
| | Type: ktyp, |
| | }, |
| | { |
| | Name: "Elem", |
| | Type: etyp, |
| | }, |
| | } |
| | slot := StructOf(fields) |
| |
|
| | fields = []StructField{ |
| | { |
| | Name: "Ctrl", |
| | Type: TypeFor[uint64](), |
| | }, |
| | { |
| | Name: "Slots", |
| | Type: ArrayOf(abi.MapGroupSlots, slot), |
| | }, |
| | } |
| | group := StructOf(fields) |
| | return group, slot |
| | } |
| |
|
| | var stringType = rtypeOf("") |
| |
|
| | |
| | |
| | |
| | |
| | func (v Value) MapIndex(key Value) Value { |
| | v.mustBe(Map) |
| | tt := (*abi.MapType)(unsafe.Pointer(v.typ())) |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | var e unsafe.Pointer |
| | if (tt.Key == stringType || key.kind() == String) && tt.Key == key.typ() && tt.Elem.Size() <= abi.MapMaxElemBytes { |
| | k := *(*string)(key.ptr) |
| | e = mapaccess_faststr(v.typ(), v.pointer(), k) |
| | } else { |
| | key = key.assignTo("reflect.Value.MapIndex", tt.Key, nil) |
| | var k unsafe.Pointer |
| | if key.flag&flagIndir != 0 { |
| | k = key.ptr |
| | } else { |
| | k = unsafe.Pointer(&key.ptr) |
| | } |
| | e = mapaccess(v.typ(), v.pointer(), k) |
| | } |
| | if e == nil { |
| | return Value{} |
| | } |
| | typ := tt.Elem |
| | fl := (v.flag | key.flag).ro() |
| | fl |= flag(typ.Kind()) |
| | return copyVal(typ, fl, e) |
| | } |
| |
|
| | |
| | |
| | |
| | func mapIterStart(t *abi.MapType, m *maps.Map, it *maps.Iter) { |
| | if race.Enabled && m != nil { |
| | callerpc := sys.GetCallerPC() |
| | race.ReadPC(unsafe.Pointer(m), callerpc, abi.FuncPCABIInternal(mapIterStart)) |
| | } |
| |
|
| | it.Init(t, m) |
| | it.Next() |
| | } |
| |
|
| | |
| | |
| | |
| | func mapIterNext(it *maps.Iter) { |
| | if race.Enabled { |
| | callerpc := sys.GetCallerPC() |
| | race.ReadPC(unsafe.Pointer(it.Map()), callerpc, abi.FuncPCABIInternal(mapIterNext)) |
| | } |
| |
|
| | it.Next() |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | func (v Value) MapKeys() []Value { |
| | v.mustBe(Map) |
| | tt := (*abi.MapType)(unsafe.Pointer(v.typ())) |
| | keyType := tt.Key |
| |
|
| | fl := v.flag.ro() | flag(keyType.Kind()) |
| |
|
| | |
| | |
| | |
| | mptr := abi.NoEscape(v.pointer()) |
| | m := (*maps.Map)(mptr) |
| | mlen := int(0) |
| | if m != nil { |
| | mlen = maplen(mptr) |
| | } |
| | var it maps.Iter |
| | mapIterStart(tt, m, &it) |
| | a := make([]Value, mlen) |
| | var i int |
| | for i = 0; i < len(a); i++ { |
| | key := it.Key() |
| | if key == nil { |
| | |
| | |
| | |
| | break |
| | } |
| | a[i] = copyVal(keyType, fl, key) |
| | mapIterNext(&it) |
| | } |
| | return a[:i] |
| | } |
| |
|
| | |
| | |
| | type MapIter struct { |
| | m Value |
| | hiter maps.Iter |
| | } |
| |
|
| | |
| | func (iter *MapIter) Key() Value { |
| | if !iter.hiter.Initialized() { |
| | panic("MapIter.Key called before Next") |
| | } |
| | iterkey := iter.hiter.Key() |
| | if iterkey == nil { |
| | panic("MapIter.Key called on exhausted iterator") |
| | } |
| |
|
| | t := (*abi.MapType)(unsafe.Pointer(iter.m.typ())) |
| | ktype := t.Key |
| | return copyVal(ktype, iter.m.flag.ro()|flag(ktype.Kind()), iterkey) |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | func (v Value) SetIterKey(iter *MapIter) { |
| | if !iter.hiter.Initialized() { |
| | panic("reflect: Value.SetIterKey called before Next") |
| | } |
| | iterkey := iter.hiter.Key() |
| | if iterkey == nil { |
| | panic("reflect: Value.SetIterKey called on exhausted iterator") |
| | } |
| |
|
| | v.mustBeAssignable() |
| | var target unsafe.Pointer |
| | if v.kind() == Interface { |
| | target = v.ptr |
| | } |
| |
|
| | t := (*abi.MapType)(unsafe.Pointer(iter.m.typ())) |
| | ktype := t.Key |
| |
|
| | iter.m.mustBeExported() |
| | key := Value{ktype, iterkey, iter.m.flag | flag(ktype.Kind()) | flagIndir} |
| | key = key.assignTo("reflect.MapIter.SetKey", v.typ(), target) |
| | typedmemmove(v.typ(), v.ptr, key.ptr) |
| | } |
| |
|
| | |
| | func (iter *MapIter) Value() Value { |
| | if !iter.hiter.Initialized() { |
| | panic("MapIter.Value called before Next") |
| | } |
| | iterelem := iter.hiter.Elem() |
| | if iterelem == nil { |
| | panic("MapIter.Value called on exhausted iterator") |
| | } |
| |
|
| | t := (*abi.MapType)(unsafe.Pointer(iter.m.typ())) |
| | vtype := t.Elem |
| | return copyVal(vtype, iter.m.flag.ro()|flag(vtype.Kind()), iterelem) |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | func (v Value) SetIterValue(iter *MapIter) { |
| | if !iter.hiter.Initialized() { |
| | panic("reflect: Value.SetIterValue called before Next") |
| | } |
| | iterelem := iter.hiter.Elem() |
| | if iterelem == nil { |
| | panic("reflect: Value.SetIterValue called on exhausted iterator") |
| | } |
| |
|
| | v.mustBeAssignable() |
| | var target unsafe.Pointer |
| | if v.kind() == Interface { |
| | target = v.ptr |
| | } |
| |
|
| | t := (*abi.MapType)(unsafe.Pointer(iter.m.typ())) |
| | vtype := t.Elem |
| |
|
| | iter.m.mustBeExported() |
| | elem := Value{vtype, iterelem, iter.m.flag | flag(vtype.Kind()) | flagIndir} |
| | elem = elem.assignTo("reflect.MapIter.SetValue", v.typ(), target) |
| | typedmemmove(v.typ(), v.ptr, elem.ptr) |
| | } |
| |
|
| | |
| | |
| | |
| | func (iter *MapIter) Next() bool { |
| | if !iter.m.IsValid() { |
| | panic("MapIter.Next called on an iterator that does not have an associated map Value") |
| | } |
| | if !iter.hiter.Initialized() { |
| | t := (*abi.MapType)(unsafe.Pointer(iter.m.typ())) |
| | m := (*maps.Map)(iter.m.pointer()) |
| | mapIterStart(t, m, &iter.hiter) |
| | } else { |
| | if iter.hiter.Key() == nil { |
| | panic("MapIter.Next called on exhausted iterator") |
| | } |
| | mapIterNext(&iter.hiter) |
| | } |
| | return iter.hiter.Key() != nil |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | func (iter *MapIter) Reset(v Value) { |
| | if v.IsValid() { |
| | v.mustBe(Map) |
| | } |
| | iter.m = v |
| | iter.hiter = maps.Iter{} |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | func (v Value) MapRange() *MapIter { |
| | |
| | |
| | |
| | |
| | if v.kind() != Map { |
| | v.panicNotMap() |
| | } |
| | return &MapIter{m: v} |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | func (v Value) SetMapIndex(key, elem Value) { |
| | v.mustBe(Map) |
| | v.mustBeExported() |
| | key.mustBeExported() |
| | tt := (*abi.MapType)(unsafe.Pointer(v.typ())) |
| |
|
| | if (tt.Key == stringType || key.kind() == String) && tt.Key == key.typ() && tt.Elem.Size() <= abi.MapMaxElemBytes { |
| | k := *(*string)(key.ptr) |
| | if elem.typ() == nil { |
| | mapdelete_faststr(v.typ(), v.pointer(), k) |
| | return |
| | } |
| | elem.mustBeExported() |
| | elem = elem.assignTo("reflect.Value.SetMapIndex", tt.Elem, nil) |
| | var e unsafe.Pointer |
| | if elem.flag&flagIndir != 0 { |
| | e = elem.ptr |
| | } else { |
| | e = unsafe.Pointer(&elem.ptr) |
| | } |
| | mapassign_faststr(v.typ(), v.pointer(), k, e) |
| | return |
| | } |
| |
|
| | key = key.assignTo("reflect.Value.SetMapIndex", tt.Key, nil) |
| | var k unsafe.Pointer |
| | if key.flag&flagIndir != 0 { |
| | k = key.ptr |
| | } else { |
| | k = unsafe.Pointer(&key.ptr) |
| | } |
| | if elem.typ() == nil { |
| | mapdelete(v.typ(), v.pointer(), k) |
| | return |
| | } |
| | elem.mustBeExported() |
| | elem = elem.assignTo("reflect.Value.SetMapIndex", tt.Elem, nil) |
| | var e unsafe.Pointer |
| | if elem.flag&flagIndir != 0 { |
| | e = elem.ptr |
| | } else { |
| | e = unsafe.Pointer(&elem.ptr) |
| | } |
| | mapassign(v.typ(), v.pointer(), k, e) |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | func (f flag) panicNotMap() { |
| | f.mustBe(Map) |
| | } |
| |
|