Browse Source

reflect: add support for remaining map types

pull/2444/merge
Damian Gryski 2 years ago
committed by Damian Gryski
parent
commit
69e5c5088d
  1. 32
      src/reflect/value.go
  2. 17
      src/reflect/value_test.go
  3. 12
      src/runtime/hashmap.go

32
src/reflect/value.go

@ -785,6 +785,9 @@ func hashmapStringGet(m unsafe.Pointer, key string, value unsafe.Pointer, valueS
//go:linkname hashmapBinaryGet runtime.hashmapBinaryGetUnsafePointer
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 {
if v.Kind() != Map {
panic(&ValueError{Method: "MapIndex", Kind: v.Kind()})
@ -816,10 +819,12 @@ func (v Value) MapIndex(key Value) Value {
return Value{}
}
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
@ -1292,12 +1297,18 @@ func hashmapStringSet(m unsafe.Pointer, key string, value unsafe.Pointer)
//go:linkname hashmapBinarySet runtime.hashmapBinarySetUnsafePointer
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
func hashmapStringDelete(m unsafe.Pointer, key string)
//go:linkname hashmapBinaryDelete runtime.hashmapBinaryDeleteUnsafePointer
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) {
if v.Kind() != Map {
panic(&ValueError{Method: "SetMapIndex", Kind: v.Kind()})
@ -1348,7 +1359,18 @@ func (v Value) SetMapIndex(key, elem Value) {
hashmapBinarySet(v.pointer(), keyptr, elemptr)
}
} 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() {
alg = hashmapAlgorithmBinary
} else {
panic("reflect.MakeMap: unimplemented key type")
alg = hashmapAlgorithmInterface
}
m := hashmapMake(key.Size(), val.Size(), uintptr(n), alg)

17
src/reflect/value_test.go

@ -115,6 +115,23 @@ func TestMap(t *testing.T) {
if m2["foo"] != 2 {
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) {

12
src/runtime/hashmap.go

@ -616,6 +616,10 @@ func hashmapInterfaceSet(m *hashmap, key interface{}, value unsafe.Pointer) {
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 {
if m == nil {
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)
}
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{}) {
if m == nil {
return
@ -632,3 +640,7 @@ func hashmapInterfaceDelete(m *hashmap, key interface{}) {
hash := hashmapInterfaceHash(key, m.seed)
hashmapDelete(m, unsafe.Pointer(&key), hash)
}
func hashmapInterfaceDeleteUnsafePointer(m unsafe.Pointer, key interface{}) {
hashmapInterfaceDelete((*hashmap)(m), key)
}

Loading…
Cancel
Save