aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorDamian Gryski <[email protected]>2023-02-25 14:41:30 -0800
committerAyke <[email protected]>2023-02-28 13:10:40 -0800
commit828c3169ab688039e1b869b059b9696e27d4ec19 (patch)
tree8ecf5c15fa5044b5196b5a53e313f3e48027e08f
parentf6ee470eda281c776d5d8d75038bd1aeb54e4ef7 (diff)
downloadtinygo-828c3169ab688039e1b869b059b9696e27d4ec19.tar.gz
tinygo-828c3169ab688039e1b869b059b9696e27d4ec19.zip
reflect: add SetMapIndex()
-rw-r--r--src/reflect/value.go64
-rw-r--r--src/reflect/value_test.go11
2 files changed, 74 insertions, 1 deletions
diff --git a/src/reflect/value.go b/src/reflect/value.go
index 8b98fef1a..b9db1c421 100644
--- a/src/reflect/value.go
+++ b/src/reflect/value.go
@@ -972,8 +972,70 @@ func AppendSlice(s, t Value) Value {
}
}
+//go:linkname hashmapStringSet runtime.hashmapStringSetUnsafePointer
+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 hashmapStringDelete runtime.hashmapStringDeleteUnsafePointer
+func hashmapStringDelete(m unsafe.Pointer, key string)
+
+//go:linkname hashmapBinaryDelete runtime.hashmapBinaryDeleteUnsafePointer
+func hashmapBinaryDelete(m unsafe.Pointer, key unsafe.Pointer)
+
func (v Value) SetMapIndex(key, elem Value) {
- panic("unimplemented: (reflect.Value).SetMapIndex()")
+ if v.Kind() != Map {
+ panic(&ValueError{Method: "SetMapIndex", Kind: v.Kind()})
+ }
+
+ // compare key type with actual key type of map
+ if key.typecode != v.typecode.key() {
+ panic("reflect.Value.SetMapIndex: incompatible types for key")
+ }
+
+ // if elem is the zero Value, it means delete
+ del := elem == Value{}
+
+ if !del && elem.typecode != v.typecode.elem() {
+ panic("reflect.Value.SetMapIndex: incompatible types for value")
+ }
+
+ if key.Kind() == String {
+ if del {
+ hashmapStringDelete(v.pointer(), *(*string)(key.value))
+ } else {
+ var elemptr unsafe.Pointer
+ if elem.isIndirect() || elem.typecode.Size() > unsafe.Sizeof(uintptr(0)) {
+ elemptr = elem.value
+ } else {
+ elemptr = unsafe.Pointer(&elem.value)
+ }
+ hashmapStringSet(v.pointer(), *(*string)(key.value), elemptr)
+ }
+
+ } else if key.typecode.isBinary() {
+ var keyptr unsafe.Pointer
+ if key.isIndirect() || key.typecode.Size() > unsafe.Sizeof(uintptr(0)) {
+ keyptr = key.value
+ } else {
+ keyptr = unsafe.Pointer(&key.value)
+ }
+
+ if del {
+ hashmapBinaryDelete(v.pointer(), keyptr)
+ } else {
+ var elemptr unsafe.Pointer
+ if elem.isIndirect() || elem.typecode.Size() > unsafe.Sizeof(uintptr(0)) {
+ elemptr = elem.value
+ } else {
+ elemptr = unsafe.Pointer(&elem.value)
+ }
+ hashmapBinarySet(v.pointer(), keyptr, elemptr)
+ }
+ } else {
+ panic("unimplemented: (reflect.Value).MapIndex()")
+ }
}
// FieldByIndex returns the nested field corresponding to index.
diff --git a/src/reflect/value_test.go b/src/reflect/value_test.go
index 95e7ec2a4..630cf516f 100644
--- a/src/reflect/value_test.go
+++ b/src/reflect/value_test.go
@@ -85,6 +85,17 @@ func TestMap(t *testing.T) {
if !equal(gotKeys, wantKeys) {
t.Errorf("MapRange return unexpected keys: got %v, want %v", gotKeys, wantKeys)
}
+
+ mref.SetMapIndex(ValueOf("bar"), Value{})
+ if _, ok := m["bar"]; ok {
+ t.Errorf("SetMapIndex failed to delete `bar`")
+ }
+
+ mref.SetMapIndex(ValueOf("baz"), ValueOf(6))
+ if got, want := m["baz"], 6; got != want {
+ t.Errorf("SetMapIndex(bar, 6) got %v, want %v", got, want)
+ }
+
}
func equal[T comparable](a, b []T) bool {