reflection for maps
R=r
DELTA=304 (248 added, 34 deleted, 22 changed)
OCL=31345
CL=31347
diff --git a/src/pkg/reflect/Makefile b/src/pkg/reflect/Makefile
index deaa49e..32c3509 100644
--- a/src/pkg/reflect/Makefile
+++ b/src/pkg/reflect/Makefile
@@ -2,6 +2,7 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
+
# DO NOT EDIT. Automatically generated by gobuild.
# gobuild -m >Makefile
@@ -20,7 +21,7 @@
coverage: packages
gotest
- 6cov -g `pwd` | grep -v '_test\.go:'
+ 6cov -g $$(pwd) | grep -v '_test\.go:'
%.$O: %.go
$(GC) -I_obj $*.go
diff --git a/src/pkg/reflect/all_test.go b/src/pkg/reflect/all_test.go
index 56f0deb..af1504b 100644
--- a/src/pkg/reflect/all_test.go
+++ b/src/pkg/reflect/all_test.go
@@ -597,3 +597,57 @@
t.Error("NewValue((*int)(nil)).(*PtrValue).Elem() != nil");
}
}
+
+func TestMapAccess(t *testing.T) {
+ m := map[string]int{ "a": 1, "b": 2 };
+ mv := NewValue(m).(*MapValue);
+ if n := mv.Len(); n != len(m) {
+ t.Errorf("Len = %d, want %d", n, len(m));
+ }
+ keys := mv.Keys();
+ i := 0;
+ newmap := MakeMap(mv.Type().(*MapType));
+ for k, v := range m {
+ // Check that returned Keys match keys in range.
+ // These aren't required to be in the same order,
+ // but they are in this implementation, which makes
+ // the test easier.
+ if i >= len(keys) {
+ t.Errorf("Missing key #%d %q", i, k);
+ } else if kv := keys[i].(*StringValue); kv.Get() != k {
+ t.Errorf("Keys[%d] = %q, want %q", i, kv.Get(), k);
+ }
+ i++;
+
+ // Check that value lookup is correct.
+ vv := mv.Get(NewValue(k));
+ if vi := vv.(*IntValue).Get(); vi != v {
+ t.Errorf("Key %q: have value %d, want %d", vi, v);
+ }
+
+ // Copy into new map.
+ newmap.Put(NewValue(k), NewValue(v));
+ }
+ vv := mv.Get(NewValue("not-present"));
+ if vv != nil {
+ t.Errorf("Invalid key: got non-nil value %s", valueToString(vv));
+ }
+
+ newm := newmap.Interface().(map[string]int);
+ if len(newm) != len(m) {
+ t.Errorf("length after copy: newm=%d, m=%d", newm, m);
+ }
+
+ for k, v := range newm {
+ mv, ok := m[k];
+ if mv != v {
+ t.Errorf("newm[%q] = %d, but m[%q] = %d, %v", k, v, k, mv, ok);
+ }
+ }
+
+ newmap.Put(NewValue("a"), nil);
+ v, ok := newm["a"];
+ if ok {
+ t.Errorf("newm[\"a\"] = %d after delete", v);
+ }
+}
diff --git a/src/pkg/reflect/value.go b/src/pkg/reflect/value.go
index 69e1eb3..11c07c5 100644
--- a/src/pkg/reflect/value.go
+++ b/src/pkg/reflect/value.go
@@ -6,6 +6,7 @@
import (
"reflect";
+ "runtime";
"unsafe";
)
@@ -58,8 +59,12 @@
// It is for advanced clients that also
// import the "unsafe" package.
Addr() uintptr;
+
+ getAddr() addr;
}
+func MakeZero(typ Type) Value
+
type value struct {
typ Type;
addr addr;
@@ -74,6 +79,10 @@
return uintptr(v.addr);
}
+func (v *value) getAddr() addr {
+ return v.addr;
+}
+
type InterfaceValue struct
type StructValue struct
@@ -742,21 +751,77 @@
*(*uintptr)(v.addr) = *(*uintptr)(x.addr);
}
-// Elem returns the value associated with key in the map v.
+// implemented in ../pkg/runtime/reflect.cgo
+func mapaccess(m, key, val *byte) bool
+func mapassign(m, key, val *byte)
+func maplen(m *byte) int32
+func mapiterinit(m *byte) *byte
+func mapiternext(it *byte)
+func mapiterkey(it *byte, key *byte) bool
+func makemap(t *runtime.MapType) *byte
+
+// Get returns the value associated with key in the map v.
// It returns nil if key is not found in the map.
-func (v *MapValue) Elem(key Value) Value {
- panic("unimplemented: map Elem");
+func (v *MapValue) Get(key Value) Value {
+ t := v.Type().(*MapType);
+ typesMustMatch(t.Key(), key.Type());
+ m := *(**byte)(v.addr);
+ if m == nil {
+ return nil;
+ }
+ newval := MakeZero(t.Elem());
+ if !mapaccess(m, (*byte)(key.getAddr()), (*byte)(newval.getAddr())) {
+ return nil;
+ }
+ return newval;
+}
+
+// Put sets the value associated with key in the map v to val.
+// If val is nil, Put deletes the key from map.
+func (v *MapValue) Put(key, val Value) {
+ t := v.Type().(*MapType);
+ typesMustMatch(t.Key(), key.Type());
+ var vaddr *byte;
+ if val != nil {
+ typesMustMatch(t.Elem(), val.Type());
+ vaddr = (*byte)(val.getAddr());
+ }
+ m := *(**byte)(v.addr);
+ mapassign(m, (*byte)(key.getAddr()), vaddr);
}
// Len returns the number of keys in the map v.
func (v *MapValue) Len() int {
- panic("unimplemented: map Len");
+ m := *(**byte)(v.addr);
+ if m == nil {
+ return 0;
+ }
+ return int(maplen(m));
}
// Keys returns a slice containing all the keys present in the map,
// in unspecified order.
func (v *MapValue) Keys() []Value {
- panic("unimplemented: map Keys");
+ tk := v.Type().(*MapType).Key();
+ m := *(**byte)(v.addr);
+ it := mapiterinit(m);
+ a := make([]Value, maplen(m));
+ var i int;
+ for i = 0; i < len(a); i++ {
+ k := MakeZero(tk);
+ if !mapiterkey(it, (*byte)(k.getAddr())) {
+ break;
+ }
+ a[i] = k;
+ mapiternext(it);
+ }
+ return a[0:i];
+}
+
+func MakeMap(typ *MapType) *MapValue {
+ v := MakeZero(typ).(*MapValue);
+ *(**byte)(v.addr) = makemap((*runtime.MapType)(unsafe.Pointer(typ)));
+ return v;
}
/*
@@ -946,7 +1011,7 @@
return newValue(typ, addr, true).(*FuncValue);
}
-// MakeZeroValue returns a zero Value for the specified Type.
+// MakeZero returns a zero Value for the specified Type.
func MakeZero(typ Type) Value {
// TODO: this will have to move into
// the runtime proper in order to play nicely
diff --git a/src/pkg/runtime/Makefile b/src/pkg/runtime/Makefile
index f3eb404..f9f40ba 100644
--- a/src/pkg/runtime/Makefile
+++ b/src/pkg/runtime/Makefile
@@ -60,6 +60,7 @@
msize.$O\
print.$O\
proc.$O\
+ reflect.$O\
rune.$O\
runtime.$O\
rt0.$O\
diff --git a/src/pkg/runtime/hashmap.c b/src/pkg/runtime/hashmap.c
index 1c8dd09..91be384 100644
--- a/src/pkg/runtime/hashmap.c
+++ b/src/pkg/runtime/hashmap.c
@@ -662,16 +662,14 @@
USED(b);
}
-typedef struct hash Hmap;
static int32 debug = 0;
// newmap(keysize uint32, valsize uint32,
// keyalg uint32, valalg uint32,
// hint uint32) (hmap *map[any]any);
-void
-sys·newmap(uint32 keysize, uint32 valsize,
- uint32 keyalg, uint32 valalg, uint32 hint,
- Hmap* ret)
+Hmap*
+makemap(uint32 keysize, uint32 valsize,
+ uint32 keyalg, uint32 valalg, uint32 hint)
{
Hmap *h;
@@ -721,13 +719,39 @@
h->vo2 = rnd(h->ko2+keysize, valsize);
h->po2 = rnd(h->vo2+valsize, 1);
- ret = h;
- FLUSH(&ret);
-
if(debug) {
printf("newmap: map=%p; keysize=%d; valsize=%d; keyalg=%d; valalg=%d; offsets=%d,%d; %d,%d,%d; %d,%d,%d\n",
h, keysize, valsize, keyalg, valalg, h->ko0, h->vo0, h->ko1, h->vo1, h->po1, h->ko2, h->vo2, h->po2);
}
+
+ return h;
+}
+
+// newmap(keysize uint32, valsize uint32,
+// keyalg uint32, valalg uint32,
+// hint uint32) (hmap *map[any]any);
+void
+sys·newmap(uint32 keysize, uint32 valsize,
+ uint32 keyalg, uint32 valalg, uint32 hint,
+ Hmap *ret)
+{
+ ret = makemap(keysize, valsize, keyalg, valalg, hint);
+ FLUSH(&ret);
+}
+
+void
+mapaccess(Hmap *h, byte *ak, byte *av, bool *pres)
+{
+ byte *res;
+
+ res = nil;
+ if(hash_lookup(h, ak, (void**)&res)) {
+ *pres = true;
+ h->valalg->copy(h->valsize, av, res+h->datavo);
+ } else {
+ *pres = false;
+ h->valalg->copy(h->valsize, av, nil);
+ }
}
// mapaccess1(hmap *map[any]any, key any) (val any);
@@ -735,17 +759,14 @@
sys·mapaccess1(Hmap *h, ...)
{
byte *ak, *av;
- byte *res;
- int32 hit;
+ bool pres;
ak = (byte*)&h + h->ko1;
av = (byte*)&h + h->vo1;
- res = nil;
- hit = hash_lookup(h, ak, (void**)&res);
- if(!hit)
+ mapaccess(h, ak, av, &pres);
+ if(!pres)
throw("sys·mapaccess1: key not in map");
- h->valalg->copy(h->valsize, av, res+h->datavo);
if(debug) {
prints("sys·mapaccess1: map=");
@@ -754,10 +775,8 @@
h->keyalg->print(h->keysize, ak);
prints("; val=");
h->valalg->print(h->valsize, av);
- prints("; hit=");
- sys·printint(hit);
- prints("; res=");
- sys·printpointer(res);
+ prints("; pres=");
+ sys·printbool(pres);
prints("\n");
}
}
@@ -767,22 +786,12 @@
sys·mapaccess2(Hmap *h, ...)
{
byte *ak, *av, *ap;
- byte *res;
- int32 hit;
ak = (byte*)&h + h->ko1;
av = (byte*)&h + h->vo1;
ap = (byte*)&h + h->po1;
- res = nil;
- hit = hash_lookup(h, ak, (void**)&res);
- if(!hit) {
- *ap = false;
- h->valalg->copy(h->valsize, av, nil);
- } else {
- *ap = true;
- h->valalg->copy(h->valsize, av, res+h->datavo);
- }
+ mapaccess(h, ak, av, ap);
if(debug) {
prints("sys·mapaccess2: map=");
@@ -791,23 +800,24 @@
h->keyalg->print(h->keysize, ak);
prints("; val=");
h->valalg->print(h->valsize, av);
- prints("; hit=");
- sys·printint(hit);
- prints("; res=");
- sys·printpointer(res);
prints("; pres=");
sys·printbool(*ap);
prints("\n");
}
}
-static void
+void
mapassign(Hmap *h, byte *ak, byte *av)
{
byte *res;
int32 hit;
res = nil;
+ if(av == nil) {
+ hash_remove(h, ak, (void**)&res);
+ return;
+ }
+
hit = hash_insert(h, ak, (void**)&res);
h->keyalg->copy(h->keysize, res, ak);
h->valalg->copy(h->valsize, res+h->datavo, av);
@@ -844,31 +854,21 @@
sys·mapassign2(Hmap *h, ...)
{
byte *ak, *av, *ap;
- byte *res;
- int32 hit;
ak = (byte*)&h + h->ko2;
av = (byte*)&h + h->vo2;
ap = (byte*)&h + h->po2;
- if(*ap == true) {
- // assign
- mapassign(h, ak, av);
- return;
- }
+ if(*ap == false)
+ av = nil; // delete
- // delete
- hit = hash_remove(h, ak, (void**)&res);
+ mapassign(h, ak, av);
if(debug) {
prints("mapassign2: map=");
sys·printpointer(h);
prints("; key=");
h->keyalg->print(h->keysize, ak);
- prints("; hit=");
- sys·printint(hit);
- prints("; res=");
- sys·printpointer(res);
prints("\n");
}
}
@@ -894,6 +894,16 @@
}
}
+struct hash_iter*
+mapiterinit(Hmap *h)
+{
+ struct hash_iter *it;
+
+ it = mal(sizeof *it);
+ sys·mapiterinit(h, it);
+ return it;
+}
+
// mapiternext(hiter *any);
void
sys·mapiternext(struct hash_iter *it)
@@ -908,6 +918,12 @@
}
}
+void
+mapiternext(struct hash_iter *it)
+{
+ sys·mapiternext(it);
+}
+
// mapiter1(hiter *any) (key any);
void
sys·mapiter1(struct hash_iter *it, ...)
@@ -933,6 +949,20 @@
}
}
+bool
+mapiterkey(struct hash_iter *it, void *ak)
+{
+ Hmap *h;
+ byte *res;
+
+ h = it->h;
+ res = it->data;
+ if(res == nil)
+ return false;
+ h->keyalg->copy(h->keysize, ak, res);
+ return true;
+}
+
// mapiter2(hiter *any) (key any, val any);
void
sys·mapiter2(struct hash_iter *it, ...)
diff --git a/src/pkg/runtime/reflect.cgo b/src/pkg/runtime/reflect.cgo
new file mode 100644
index 0000000..da74195
--- /dev/null
+++ b/src/pkg/runtime/reflect.cgo
@@ -0,0 +1,51 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package reflect
+#include "runtime.h"
+#include "type.h"
+
+/*
+ * Go wrappers around the C functions near the bottom of hashmap.c
+ * There's no recursion here even though it looks like there is:
+ * the names after func are in the reflect package name space
+ * but the names in the C bodies are in the standard C name space.
+ */
+
+func mapaccess(map *byte, key *byte, val *byte) (pres bool) {
+ mapaccess((Hmap*)map, key, val, &pres);
+}
+
+func mapassign(map *byte, key *byte, val *byte) {
+ mapassign((Hmap*)map, key, val);
+}
+
+func maplen(map *byte) (len int32) {
+ // length is first word of map
+ len = *(uint32*)map;
+}
+
+func mapiterinit(map *byte) (it *byte) {
+ it = (byte*)mapiterinit((Hmap*)map);
+}
+
+func mapiternext(it *byte) {
+ mapiternext((struct hash_iter*)it);
+}
+
+func mapiterkey(it *byte, key *byte) (ok bool) {
+ ok = mapiterkey((struct hash_iter*)it, key);
+}
+
+func makemap(typ *byte) (map *byte) {
+ MapType *t;
+
+ // typ is a *runtime.MapType, but the MapType
+ // defined in type.h includes an interface value header
+ // in front of the raw MapType. the -2 below backs up
+ // to the interface value header.
+ t = (MapType*)((void**)typ - 2);
+
+ map = (byte*)makemap(t->key->size, t->elem->size, t->key->alg, t->elem->alg, 0);
+}
diff --git a/src/pkg/runtime/runtime.h b/src/pkg/runtime/runtime.h
index 26dfe70..ee2f982 100644
--- a/src/pkg/runtime/runtime.h
+++ b/src/pkg/runtime/runtime.h
@@ -60,6 +60,7 @@
typedef struct Eface Eface;
typedef struct Type Type;
typedef struct Defer Defer;
+typedef struct hash Hmap;
/*
* per cpu declaration
@@ -457,3 +458,10 @@
float64 modf(float64 d, float64 *ip);
void semacquire(uint32*);
void semrelease(uint32*);
+void mapassign(Hmap*, byte*, byte*);
+void mapaccess(Hmap*, byte*, byte*, bool*);
+struct hash_iter* mapiterinit(Hmap*);
+void mapiternext(struct hash_iter*);
+bool mapiterkey(struct hash_iter*, void*);
+void mapiterkeyvalue(struct hash_iter*, void*, void*);
+Hmap* makemap(uint32, uint32, uint32, uint32, uint32);
diff --git a/src/pkg/runtime/type.h b/src/pkg/runtime/type.h
index 3b49f24..21c1dd7 100644
--- a/src/pkg/runtime/type.h
+++ b/src/pkg/runtime/type.h
@@ -11,6 +11,7 @@
typedef struct InterfaceType InterfaceType;
typedef struct Method Method;
typedef struct IMethod IMethod;
+typedef struct MapType MapType;
struct CommonType
{
@@ -63,3 +64,10 @@
Array mhdr;
IMethod m[];
};
+
+struct MapType
+{
+ Type;
+ Type *key;
+ Type *elem;
+};