diff --git a/src/reflect/value.go b/src/reflect/value.go index 770d1831..f27db349 100644 --- a/src/reflect/value.go +++ b/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) diff --git a/src/reflect/value_test.go b/src/reflect/value_test.go index 51f38ac8..b3d222e0 100644 --- a/src/reflect/value_test.go +++ b/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) { diff --git a/src/runtime/hashmap.go b/src/runtime/hashmap.go index e6d16b13..ab85aee8 100644 --- a/src/runtime/hashmap.go +++ b/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) +}