diff options
author | Damian Gryski <[email protected]> | 2023-02-25 14:41:30 -0800 |
---|---|---|
committer | Ayke <[email protected]> | 2023-02-28 13:10:40 -0800 |
commit | 828c3169ab688039e1b869b059b9696e27d4ec19 (patch) | |
tree | 8ecf5c15fa5044b5196b5a53e313f3e48027e08f | |
parent | f6ee470eda281c776d5d8d75038bd1aeb54e4ef7 (diff) | |
download | tinygo-828c3169ab688039e1b869b059b9696e27d4ec19.tar.gz tinygo-828c3169ab688039e1b869b059b9696e27d4ec19.zip |
reflect: add SetMapIndex()
-rw-r--r-- | src/reflect/value.go | 64 | ||||
-rw-r--r-- | src/reflect/value_test.go | 11 |
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 { |