diff options
author | Damian Gryski <[email protected]> | 2023-02-25 14:24:39 -0800 |
---|---|---|
committer | Ayke <[email protected]> | 2023-02-28 13:10:40 -0800 |
commit | f6ee470eda281c776d5d8d75038bd1aeb54e4ef7 (patch) | |
tree | 9a49292af38d7774f27969e9e6b27c267d1bf5a6 | |
parent | d0f4702f8b5f4c1d05adb3368d75c2190e1520d4 (diff) | |
download | tinygo-f6ee470eda281c776d5d8d75038bd1aeb54e4ef7.tar.gz tinygo-f6ee470eda281c776d5d8d75038bd1aeb54e4ef7.zip |
reflect: add MapRange/MapIter
-rw-r--r-- | src/reflect/value.go | 38 | ||||
-rw-r--r-- | src/reflect/value_test.go | 45 |
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 } |