1
0
mirror of https://github.com/golang/go synced 2024-11-20 02:34:42 -07:00

reflection for maps

R=r
DELTA=304  (248 added, 34 deleted, 22 changed)
OCL=31345
CL=31347
This commit is contained in:
Russ Cox 2009-07-08 13:55:57 -07:00
parent 0ae7882b5c
commit 764b6ec1aa
8 changed files with 272 additions and 54 deletions

View File

@ -2,6 +2,7 @@
# Use of this source code is governed by a BSD-style # Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file. # license that can be found in the LICENSE file.
# DO NOT EDIT. Automatically generated by gobuild. # DO NOT EDIT. Automatically generated by gobuild.
# gobuild -m >Makefile # gobuild -m >Makefile
@ -20,7 +21,7 @@ test: packages
coverage: packages coverage: packages
gotest gotest
6cov -g `pwd` | grep -v '_test\.go:' 6cov -g $$(pwd) | grep -v '_test\.go:'
%.$O: %.go %.$O: %.go
$(GC) -I_obj $*.go $(GC) -I_obj $*.go

View File

@ -597,3 +597,57 @@ func TestNilPtrValueSub(t *testing.T) {
t.Error("NewValue((*int)(nil)).(*PtrValue).Elem() != nil"); 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);
}
}

View File

@ -6,6 +6,7 @@ package reflect
import ( import (
"reflect"; "reflect";
"runtime";
"unsafe"; "unsafe";
) )
@ -58,8 +59,12 @@ type Value interface {
// It is for advanced clients that also // It is for advanced clients that also
// import the "unsafe" package. // import the "unsafe" package.
Addr() uintptr; Addr() uintptr;
getAddr() addr;
} }
func MakeZero(typ Type) Value
type value struct { type value struct {
typ Type; typ Type;
addr addr; addr addr;
@ -74,6 +79,10 @@ func (v *value) Addr() uintptr {
return uintptr(v.addr); return uintptr(v.addr);
} }
func (v *value) getAddr() addr {
return v.addr;
}
type InterfaceValue struct type InterfaceValue struct
type StructValue struct type StructValue struct
@ -742,21 +751,77 @@ func (v *MapValue) Set(x *MapValue) {
*(*uintptr)(v.addr) = *(*uintptr)(x.addr); *(*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. // It returns nil if key is not found in the map.
func (v *MapValue) Elem(key Value) Value { func (v *MapValue) Get(key Value) Value {
panic("unimplemented: map Elem"); 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. // Len returns the number of keys in the map v.
func (v *MapValue) Len() int { 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, // Keys returns a slice containing all the keys present in the map,
// in unspecified order. // in unspecified order.
func (v *MapValue) Keys() []Value { 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 @@ func newFuncValue(typ Type, addr addr) *FuncValue {
return newValue(typ, addr, true).(*FuncValue); 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 { func MakeZero(typ Type) Value {
// TODO: this will have to move into // TODO: this will have to move into
// the runtime proper in order to play nicely // the runtime proper in order to play nicely

View File

@ -60,6 +60,7 @@ OFILES=\
msize.$O\ msize.$O\
print.$O\ print.$O\
proc.$O\ proc.$O\
reflect.$O\
rune.$O\ rune.$O\
runtime.$O\ runtime.$O\
rt0.$O\ rt0.$O\

View File

@ -662,16 +662,14 @@ donothing(uint32 s, void *a, void *b)
USED(b); USED(b);
} }
typedef struct hash Hmap;
static int32 debug = 0; static int32 debug = 0;
// newmap(keysize uint32, valsize uint32, // newmap(keysize uint32, valsize uint32,
// keyalg uint32, valalg uint32, // keyalg uint32, valalg uint32,
// hint uint32) (hmap *map[any]any); // hint uint32) (hmap *map[any]any);
void Hmap*
sys·newmap(uint32 keysize, uint32 valsize, makemap(uint32 keysize, uint32 valsize,
uint32 keyalg, uint32 valalg, uint32 hint, uint32 keyalg, uint32 valalg, uint32 hint)
Hmap* ret)
{ {
Hmap *h; Hmap *h;
@ -721,13 +719,39 @@ sys·newmap(uint32 keysize, uint32 valsize,
h->vo2 = rnd(h->ko2+keysize, valsize); h->vo2 = rnd(h->ko2+keysize, valsize);
h->po2 = rnd(h->vo2+valsize, 1); h->po2 = rnd(h->vo2+valsize, 1);
ret = h;
FLUSH(&ret);
if(debug) { if(debug) {
printf("newmap: map=%p; keysize=%d; valsize=%d; keyalg=%d; valalg=%d; offsets=%d,%d; %d,%d,%d; %d,%d,%d\n", 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); 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); // mapaccess1(hmap *map[any]any, key any) (val any);
@ -735,17 +759,14 @@ void
sys·mapaccess1(Hmap *h, ...) sys·mapaccess1(Hmap *h, ...)
{ {
byte *ak, *av; byte *ak, *av;
byte *res; bool pres;
int32 hit;
ak = (byte*)&h + h->ko1; ak = (byte*)&h + h->ko1;
av = (byte*)&h + h->vo1; av = (byte*)&h + h->vo1;
res = nil; mapaccess(h, ak, av, &pres);
hit = hash_lookup(h, ak, (void**)&res); if(!pres)
if(!hit)
throw("sys·mapaccess1: key not in map"); throw("sys·mapaccess1: key not in map");
h->valalg->copy(h->valsize, av, res+h->datavo);
if(debug) { if(debug) {
prints("sys·mapaccess1: map="); prints("sys·mapaccess1: map=");
@ -754,10 +775,8 @@ sys·mapaccess1(Hmap *h, ...)
h->keyalg->print(h->keysize, ak); h->keyalg->print(h->keysize, ak);
prints("; val="); prints("; val=");
h->valalg->print(h->valsize, av); h->valalg->print(h->valsize, av);
prints("; hit="); prints("; pres=");
sys·printint(hit); sys·printbool(pres);
prints("; res=");
sys·printpointer(res);
prints("\n"); prints("\n");
} }
} }
@ -767,22 +786,12 @@ void
sys·mapaccess2(Hmap *h, ...) sys·mapaccess2(Hmap *h, ...)
{ {
byte *ak, *av, *ap; byte *ak, *av, *ap;
byte *res;
int32 hit;
ak = (byte*)&h + h->ko1; ak = (byte*)&h + h->ko1;
av = (byte*)&h + h->vo1; av = (byte*)&h + h->vo1;
ap = (byte*)&h + h->po1; ap = (byte*)&h + h->po1;
res = nil; mapaccess(h, ak, av, ap);
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);
}
if(debug) { if(debug) {
prints("sys·mapaccess2: map="); prints("sys·mapaccess2: map=");
@ -791,23 +800,24 @@ sys·mapaccess2(Hmap *h, ...)
h->keyalg->print(h->keysize, ak); h->keyalg->print(h->keysize, ak);
prints("; val="); prints("; val=");
h->valalg->print(h->valsize, av); h->valalg->print(h->valsize, av);
prints("; hit=");
sys·printint(hit);
prints("; res=");
sys·printpointer(res);
prints("; pres="); prints("; pres=");
sys·printbool(*ap); sys·printbool(*ap);
prints("\n"); prints("\n");
} }
} }
static void void
mapassign(Hmap *h, byte *ak, byte *av) mapassign(Hmap *h, byte *ak, byte *av)
{ {
byte *res; byte *res;
int32 hit; int32 hit;
res = nil; res = nil;
if(av == nil) {
hash_remove(h, ak, (void**)&res);
return;
}
hit = hash_insert(h, ak, (void**)&res); hit = hash_insert(h, ak, (void**)&res);
h->keyalg->copy(h->keysize, res, ak); h->keyalg->copy(h->keysize, res, ak);
h->valalg->copy(h->valsize, res+h->datavo, av); h->valalg->copy(h->valsize, res+h->datavo, av);
@ -844,31 +854,21 @@ void
sys·mapassign2(Hmap *h, ...) sys·mapassign2(Hmap *h, ...)
{ {
byte *ak, *av, *ap; byte *ak, *av, *ap;
byte *res;
int32 hit;
ak = (byte*)&h + h->ko2; ak = (byte*)&h + h->ko2;
av = (byte*)&h + h->vo2; av = (byte*)&h + h->vo2;
ap = (byte*)&h + h->po2; ap = (byte*)&h + h->po2;
if(*ap == true) { if(*ap == false)
// assign av = nil; // delete
mapassign(h, ak, av);
return;
}
// delete mapassign(h, ak, av);
hit = hash_remove(h, ak, (void**)&res);
if(debug) { if(debug) {
prints("mapassign2: map="); prints("mapassign2: map=");
sys·printpointer(h); sys·printpointer(h);
prints("; key="); prints("; key=");
h->keyalg->print(h->keysize, ak); h->keyalg->print(h->keysize, ak);
prints("; hit=");
sys·printint(hit);
prints("; res=");
sys·printpointer(res);
prints("\n"); prints("\n");
} }
} }
@ -894,6 +894,16 @@ sys·mapiterinit(Hmap *h, struct hash_iter *it)
} }
} }
struct hash_iter*
mapiterinit(Hmap *h)
{
struct hash_iter *it;
it = mal(sizeof *it);
sys·mapiterinit(h, it);
return it;
}
// mapiternext(hiter *any); // mapiternext(hiter *any);
void void
sys·mapiternext(struct hash_iter *it) sys·mapiternext(struct hash_iter *it)
@ -908,6 +918,12 @@ sys·mapiternext(struct hash_iter *it)
} }
} }
void
mapiternext(struct hash_iter *it)
{
sys·mapiternext(it);
}
// mapiter1(hiter *any) (key any); // mapiter1(hiter *any) (key any);
void void
sys·mapiter1(struct hash_iter *it, ...) sys·mapiter1(struct hash_iter *it, ...)
@ -933,6 +949,20 @@ sys·mapiter1(struct hash_iter *it, ...)
} }
} }
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); // mapiter2(hiter *any) (key any, val any);
void void
sys·mapiter2(struct hash_iter *it, ...) sys·mapiter2(struct hash_iter *it, ...)

View File

@ -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);
}

View File

@ -60,6 +60,7 @@ typedef struct Itab Itab;
typedef struct Eface Eface; typedef struct Eface Eface;
typedef struct Type Type; typedef struct Type Type;
typedef struct Defer Defer; typedef struct Defer Defer;
typedef struct hash Hmap;
/* /*
* per cpu declaration * per cpu declaration
@ -457,3 +458,10 @@ float64 ldexp(float64 d, int32 e);
float64 modf(float64 d, float64 *ip); float64 modf(float64 d, float64 *ip);
void semacquire(uint32*); void semacquire(uint32*);
void semrelease(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);

View File

@ -11,6 +11,7 @@ typedef struct UncommonType UncommonType;
typedef struct InterfaceType InterfaceType; typedef struct InterfaceType InterfaceType;
typedef struct Method Method; typedef struct Method Method;
typedef struct IMethod IMethod; typedef struct IMethod IMethod;
typedef struct MapType MapType;
struct CommonType struct CommonType
{ {
@ -63,3 +64,10 @@ struct InterfaceType
Array mhdr; Array mhdr;
IMethod m[]; IMethod m[];
}; };
struct MapType
{
Type;
Type *key;
Type *elem;
};