reflect: add support for remaining map types

Этот коммит содержится в:
Damian Gryski 2023-03-03 22:19:49 -08:00 коммит произвёл Damian Gryski
родитель a6084767b3
коммит 69e5c5088d
3 изменённых файлов: 56 добавлений и 5 удалений

Просмотреть файл

@ -785,6 +785,9 @@ func hashmapStringGet(m unsafe.Pointer, key string, value unsafe.Pointer, valueS
//go:linkname hashmapBinaryGet runtime.hashmapBinaryGetUnsafePointer //go:linkname hashmapBinaryGet runtime.hashmapBinaryGetUnsafePointer
func hashmapBinaryGet(m unsafe.Pointer, key, value unsafe.Pointer, valueSize uintptr) bool func hashmapBinaryGet(m unsafe.Pointer, key, value unsafe.Pointer, valueSize uintptr) bool
//go:linkname hashmapInterfaceGet runtime.hashmapInterfaceGetUnsafePointer
func hashmapInterfaceGet(m unsafe.Pointer, key interface{}, value unsafe.Pointer, valueSize uintptr) bool
func (v Value) MapIndex(key Value) Value { func (v Value) MapIndex(key Value) Value {
if v.Kind() != Map { if v.Kind() != Map {
panic(&ValueError{Method: "MapIndex", Kind: v.Kind()}) panic(&ValueError{Method: "MapIndex", Kind: v.Kind()})
@ -816,10 +819,12 @@ func (v Value) MapIndex(key Value) Value {
return Value{} return Value{}
} }
return elem.Elem() return elem.Elem()
} else {
if ok := hashmapInterfaceGet(v.pointer(), key.Interface(), elem.value, elemType.Size()); !ok {
return Value{}
}
return elem.Elem()
} }
// TODO(dgryski): Add other map types. For now, just string and binary types are supported.
panic("unimplemented: (reflect.Value).MapIndex()")
} }
//go:linkname hashmapNewIterator runtime.hashmapNewIterator //go:linkname hashmapNewIterator runtime.hashmapNewIterator
@ -1292,12 +1297,18 @@ func hashmapStringSet(m unsafe.Pointer, key string, value unsafe.Pointer)
//go:linkname hashmapBinarySet runtime.hashmapBinarySetUnsafePointer //go:linkname hashmapBinarySet runtime.hashmapBinarySetUnsafePointer
func hashmapBinarySet(m unsafe.Pointer, key, value unsafe.Pointer) func hashmapBinarySet(m unsafe.Pointer, key, value unsafe.Pointer)
//go:linkname hashmapInterfaceSet runtime.hashmapInterfaceSetUnsafePointer
func hashmapInterfaceSet(m unsafe.Pointer, key interface{}, value unsafe.Pointer)
//go:linkname hashmapStringDelete runtime.hashmapStringDeleteUnsafePointer //go:linkname hashmapStringDelete runtime.hashmapStringDeleteUnsafePointer
func hashmapStringDelete(m unsafe.Pointer, key string) func hashmapStringDelete(m unsafe.Pointer, key string)
//go:linkname hashmapBinaryDelete runtime.hashmapBinaryDeleteUnsafePointer //go:linkname hashmapBinaryDelete runtime.hashmapBinaryDeleteUnsafePointer
func hashmapBinaryDelete(m unsafe.Pointer, key unsafe.Pointer) func hashmapBinaryDelete(m unsafe.Pointer, key unsafe.Pointer)
//go:linkname hashmapInterfaceDelete runtime.hashmapInterfaceDeleteUnsafePointer
func hashmapInterfaceDelete(m unsafe.Pointer, key interface{})
func (v Value) SetMapIndex(key, elem Value) { func (v Value) SetMapIndex(key, elem Value) {
if v.Kind() != Map { if v.Kind() != Map {
panic(&ValueError{Method: "SetMapIndex", Kind: v.Kind()}) panic(&ValueError{Method: "SetMapIndex", Kind: v.Kind()})
@ -1348,7 +1359,18 @@ func (v Value) SetMapIndex(key, elem Value) {
hashmapBinarySet(v.pointer(), keyptr, elemptr) hashmapBinarySet(v.pointer(), keyptr, elemptr)
} }
} else { } else {
panic("unimplemented: (reflect.Value).MapIndex()") if del {
hashmapInterfaceDelete(v.pointer(), key.Interface())
} else {
var elemptr unsafe.Pointer
if elem.isIndirect() || elem.typecode.Size() > unsafe.Sizeof(uintptr(0)) {
elemptr = elem.value
} else {
elemptr = unsafe.Pointer(&elem.value)
}
hashmapInterfaceSet(v.pointer(), key.Interface(), elemptr)
}
} }
} }
@ -1398,7 +1420,7 @@ func MakeMapWithSize(typ Type, n int) Value {
} else if key.isBinary() { } else if key.isBinary() {
alg = hashmapAlgorithmBinary alg = hashmapAlgorithmBinary
} else { } else {
panic("reflect.MakeMap: unimplemented key type") alg = hashmapAlgorithmInterface
} }
m := hashmapMake(key.Size(), val.Size(), uintptr(n), alg) m := hashmapMake(key.Size(), val.Size(), uintptr(n), alg)

Просмотреть файл

@ -115,6 +115,23 @@ func TestMap(t *testing.T) {
if m2["foo"] != 2 { if m2["foo"] != 2 {
t.Errorf("MakeMap failed to create map") t.Errorf("MakeMap failed to create map")
} }
type stringint struct {
s string
i int
}
simap := make(map[stringint]int)
refsimap := MakeMap(TypeOf(simap))
refsimap.SetMapIndex(ValueOf(stringint{"hello", 4}), ValueOf(6))
six := refsimap.MapIndex(ValueOf(stringint{"hello", 4}))
if six.Interface().(int) != 6 {
t.Errorf("m[hello, 4]=%v, want 6", six)
}
} }
func TestSlice(t *testing.T) { func TestSlice(t *testing.T) {

Просмотреть файл

@ -616,6 +616,10 @@ func hashmapInterfaceSet(m *hashmap, key interface{}, value unsafe.Pointer) {
hashmapSet(m, unsafe.Pointer(&key), value, hash) hashmapSet(m, unsafe.Pointer(&key), value, hash)
} }
func hashmapInterfaceSetUnsafePointer(m unsafe.Pointer, key interface{}, value unsafe.Pointer) {
hashmapInterfaceSet((*hashmap)(m), key, value)
}
func hashmapInterfaceGet(m *hashmap, key interface{}, value unsafe.Pointer, valueSize uintptr) bool { func hashmapInterfaceGet(m *hashmap, key interface{}, value unsafe.Pointer, valueSize uintptr) bool {
if m == nil { if m == nil {
memzero(value, uintptr(valueSize)) memzero(value, uintptr(valueSize))
@ -625,6 +629,10 @@ func hashmapInterfaceGet(m *hashmap, key interface{}, value unsafe.Pointer, valu
return hashmapGet(m, unsafe.Pointer(&key), value, valueSize, hash) return hashmapGet(m, unsafe.Pointer(&key), value, valueSize, hash)
} }
func hashmapInterfaceGetUnsafePointer(m unsafe.Pointer, key interface{}, value unsafe.Pointer, valueSize uintptr) bool {
return hashmapInterfaceGet((*hashmap)(m), key, value, valueSize)
}
func hashmapInterfaceDelete(m *hashmap, key interface{}) { func hashmapInterfaceDelete(m *hashmap, key interface{}) {
if m == nil { if m == nil {
return return
@ -632,3 +640,7 @@ func hashmapInterfaceDelete(m *hashmap, key interface{}) {
hash := hashmapInterfaceHash(key, m.seed) hash := hashmapInterfaceHash(key, m.seed)
hashmapDelete(m, unsafe.Pointer(&key), hash) hashmapDelete(m, unsafe.Pointer(&key), hash)
} }
func hashmapInterfaceDeleteUnsafePointer(m unsafe.Pointer, key interface{}) {
hashmapInterfaceDelete((*hashmap)(m), key)
}