aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorDamian Gryski <[email protected]>2023-02-25 14:24:39 -0800
committerAyke <[email protected]>2023-02-28 13:10:40 -0800
commitf6ee470eda281c776d5d8d75038bd1aeb54e4ef7 (patch)
tree9a49292af38d7774f27969e9e6b27c267d1bf5a6
parentd0f4702f8b5f4c1d05adb3368d75c2190e1520d4 (diff)
downloadtinygo-f6ee470eda281c776d5d8d75038bd1aeb54e4ef7.tar.gz
tinygo-f6ee470eda281c776d5d8d75038bd1aeb54e4ef7.zip
reflect: add MapRange/MapIter
-rw-r--r--src/reflect/value.go38
-rw-r--r--src/reflect/value_test.go45
2 files changed, 79 insertions, 4 deletions
diff --git a/src/reflect/value.go b/src/reflect/value.go
index 2759d8048..8b98fef1a 100644
--- a/src/reflect/value.go
+++ b/src/reflect/value.go
@@ -687,23 +687,53 @@ func (v Value) MapIndex(key Value) Value {
panic("unimplemented: (reflect.Value).MapIndex()")
}
+//go:linkname hashmapNewIterator runtime.hashmapNewIterator
+func hashmapNewIterator() unsafe.Pointer
+
+//go:linkname hashmapNext runtime.hashmapNextUnsafePointer
+func hashmapNext(m unsafe.Pointer, it unsafe.Pointer, key, value unsafe.Pointer) bool
+
func (v Value) MapRange() *MapIter {
- panic("unimplemented: (reflect.Value).MapRange()")
+ if v.Kind() != Map {
+ panic(&ValueError{Method: "MapRange", Kind: v.Kind()})
+ }
+
+ return &MapIter{
+ m: v,
+ it: hashmapNewIterator(),
+ key: New(v.typecode.Key()),
+ val: New(v.typecode.Elem()),
+ }
}
type MapIter struct {
+ m Value
+ it unsafe.Pointer
+ key Value
+ val Value
+
+ valid bool
}
func (it *MapIter) Key() Value {
- panic("unimplemented: (*reflect.MapIter).Key()")
+ if !it.valid {
+ panic("reflect.MapIter.Key called on invalid iterator")
+ }
+
+ return it.key.Elem()
}
func (it *MapIter) Value() Value {
- panic("unimplemented: (*reflect.MapIter).Value()")
+ if !it.valid {
+ panic("reflect.MapIter.Value called on invalid iterator")
+ }
+
+ return it.val.Elem()
}
func (it *MapIter) Next() bool {
- panic("unimplemented: (*reflect.MapIter).Next()")
+ it.valid = hashmapNext(it.m.pointer(), it.it, it.key.value, it.val.value)
+ return it.valid
}
func (v Value) Set(x Value) {
diff --git a/src/reflect/value_test.go b/src/reflect/value_test.go
index f78f542fe..95e7ec2a4 100644
--- a/src/reflect/value_test.go
+++ b/src/reflect/value_test.go
@@ -2,6 +2,7 @@ package reflect_test
import (
. "reflect"
+ "sort"
"testing"
)
@@ -53,4 +54,48 @@ func TestMap(t *testing.T) {
if got, want := two.Interface().(int), 2; got != want {
t.Errorf("MapIndex(`foo`)=%v, want %v", got, want)
}
+
+ m["bar"] = 3
+ m["baz"] = 4
+ m["qux"] = 5
+
+ it := mref.MapRange()
+
+ var gotKeys []string
+ for it.Next() {
+ k := it.Key()
+ v := it.Value()
+
+ kstr := k.Interface().(string)
+ vint := v.Interface().(int)
+
+ gotKeys = append(gotKeys, kstr)
+
+ if m[kstr] != vint {
+ t.Errorf("m[%v]=%v, want %v", kstr, vint, m[kstr])
+ }
+ }
+ var wantKeys []string
+ for k := range m {
+ wantKeys = append(wantKeys, k)
+ }
+ sort.Strings(gotKeys)
+ sort.Strings(wantKeys)
+
+ if !equal(gotKeys, wantKeys) {
+ t.Errorf("MapRange return unexpected keys: got %v, want %v", gotKeys, wantKeys)
+ }
+}
+
+func equal[T comparable](a, b []T) bool {
+ if len(a) != len(b) {
+ return false
+ }
+
+ for i, aa := range a {
+ if b[i] != aa {
+ return false
+ }
+ }
+ return true
}