internal/lib/reflect: makemap

This commit is contained in:
visualfc
2024-11-27 10:32:19 +08:00
parent ecba13c38e
commit 2412760f1c
2 changed files with 101 additions and 6 deletions

View File

@@ -1463,6 +1463,79 @@ func funcStr(ft *funcType) string {
return string(repr)
}
// MapOf returns the map type with the given key and element types.
// For example, if k represents int and e represents string,
// MapOf(k, e) represents map[int]string.
//
// If the key type is not a valid map key type (that is, if it does
// not implement Go's == operator), MapOf panics.
func MapOf(key, elem Type) Type {
ktyp := key.common()
etyp := elem.common()
if ktyp.Equal == nil {
panic("reflect.MapOf: invalid key type " + stringFor(ktyp))
}
// Look in cache.
ckey := cacheKey{Map, ktyp, etyp, 0}
if mt, ok := lookupCache.Load(ckey); ok {
return mt.(Type)
}
// Look in known types.
s := "map[" + stringFor(ktyp) + "]" + stringFor(etyp)
// for _, tt := range typesByString(s) {
// mt := (*mapType)(unsafe.Pointer(tt))
// if mt.Key == ktyp && mt.Elem == etyp {
// ti, _ := lookupCache.LoadOrStore(ckey, toRType(tt))
// return ti.(Type)
// }
// }
// Make a map type.
// Note: flag values must match those used in the TMAP case
// in ../cmd/compile/internal/reflectdata/reflect.go:writeType.
var imap any = (map[unsafe.Pointer]unsafe.Pointer)(nil)
mt := **(**mapType)(unsafe.Pointer(&imap))
mt.Str_ = s
mt.TFlag = 0
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.Bucket = bucketOf(ktyp, etyp)
mt.Hasher = func(p unsafe.Pointer, seed uintptr) uintptr {
return typehash(ktyp, p, seed)
}
mt.Flags = 0
if ktyp.Size_ > maxKeySize {
mt.KeySize = uint8(goarch.PtrSize)
mt.Flags |= 1 // indirect key
} else {
mt.KeySize = uint8(ktyp.Size_)
}
if etyp.Size_ > maxValSize {
mt.ValueSize = uint8(goarch.PtrSize)
mt.Flags |= 2 // indirect value
} else {
mt.MapType.ValueSize = uint8(etyp.Size_)
}
mt.MapType.BucketSize = uint16(mt.Bucket.Size_)
if isReflexive(ktyp) {
mt.Flags |= 4
}
if needKeyUpdate(ktyp) {
mt.Flags |= 8
}
if hashMightPanic(ktyp) {
mt.Flags |= 16
}
mt.PtrToThis_ = nil
ti, _ := lookupCache.LoadOrStore(ckey, toRType(&mt.Type))
return ti.(Type)
}
// isReflexive reports whether the == operation on the type is reflexive.
// That is, x == x for all values x of type t.
func isReflexive(t *abi.Type) bool {

View File

@@ -2297,9 +2297,9 @@ func (v Value) MapIndex(key Value) Value {
} else {
k = unsafe.Pointer(&key.ptr)
}
e = mapaccess(v.typ(), v.pointer(), k)
// }
if e == nil {
var ok bool
e, ok = mapaccess(v.typ(), v.pointer(), k)
if !ok {
return Value{}
}
typ := tt.Elem
@@ -2519,7 +2519,7 @@ func (v Value) MapRange() *MapIter {
// Force slow panicking path not inlined, so it won't add to the
// inlining budget of the caller.
// TODO: undo when the inliner is no longer bottom-up only.
// TODO undo when the inliner is no longer bottom-up only.
//
//go:noinline
func (f flag) panicNotMap() {
@@ -2587,11 +2587,14 @@ func chancap(ch unsafe.Pointer) int
//go:linkname chanlen github.com/goplus/llgo/internal/runtime.ChanLen
func chanlen(ch unsafe.Pointer) int
//go:linkname makemap github.com/goplus/llgo/internal/runtime.MakeMap
func makemap(t *abi.Type, cap int) (m unsafe.Pointer)
//go:linkname maplen github.com/goplus/llgo/internal/runtime.MapLen
func maplen(ch unsafe.Pointer) int
//go:linkname mapaccess github.com/goplus/llgo/internal/runtime.MapAccess1
func mapaccess(t *abi.Type, m unsafe.Pointer, key unsafe.Pointer) (val unsafe.Pointer)
//go:linkname mapaccess github.com/goplus/llgo/internal/runtime.MapAccess2
func mapaccess(t *abi.Type, m unsafe.Pointer, key unsafe.Pointer) (val unsafe.Pointer, ok bool)
//go:linkname mapassign0 github.com/goplus/llgo/internal/runtime.MapAssign
func mapassign0(t *abi.Type, m unsafe.Pointer, key unsafe.Pointer) unsafe.Pointer
@@ -2635,6 +2638,9 @@ func mapiternext(it *hiter)
//go:linkname mapclear github.com/goplus/llgo/internal/runtime.mapclear
func mapclear(t *abi.Type, m unsafe.Pointer)
//go:linkname typehash github.com/goplus/llgo/internal/runtime.typehash
func typehash(t *abi.Type, p unsafe.Pointer, h uintptr) uintptr
// MakeSlice creates a new zero-initialized slice value
// for the specified slice type, length, and capacity.
func MakeSlice(typ Type, len, cap int) Value {
@@ -2655,6 +2661,22 @@ func MakeSlice(typ Type, len, cap int) Value {
return Value{&typ.(*rtype).t, unsafe.Pointer(&s), flagIndir | flag(Slice)}
}
// MakeMap creates a new map with the specified type.
func MakeMap(typ Type) Value {
return MakeMapWithSize(typ, 0)
}
// MakeMapWithSize creates a new map with the specified type
// and initial space for approximately n elements.
func MakeMapWithSize(typ Type, n int) Value {
if typ.Kind() != Map {
panic("reflect.MakeMapWithSize of non-map type")
}
t := typ.common()
m := makemap(t, n)
return Value{t, m, flag(Map)}
}
func ifaceE2I(t *abi.Type, src any, dst unsafe.Pointer) {
panic("todo: reflect.ifaceE2I")
}