Commit fb175cf7 authored by Russ Cox's avatar Russ Cox

reflect: new Type and Value definitions

Type is now an interface that implements all the possible type methods.
Instead of a type switch on a reflect.Type t, switch on t.Kind().
If a method is invoked on the wrong kind of type (for example,
calling t.Field(0) when t.Kind() != Struct), the call panics.

There is one method renaming: t.(*ChanType).Dir() is now t.ChanDir().

Value is now a struct value that implements all the possible value methods.
Instead of a type switch on a reflect.Value v, switch on v.Kind().
If a method is invoked on the wrong kind of value (for example,
calling t.Recv() when t.Kind() != Chan), the call panics.

Since Value is now a struct, not an interface, its zero value
cannot be compared to nil.  Instead of v != nil, use v.IsValid().
Instead of other uses of nil as a Value, use Value{}, the zero value.

Many methods have been renamed, most due to signature conflicts:

           OLD                          NEW

    v.(*ArrayValue).Elem             v.Index
    v.(*BoolValue).Get               v.Bool
    v.(*BoolValue).Set               v.SetBool
    v.(*ChanType).Dir                v.ChanDir
    v.(*ChanValue).Get               v.Pointer
    v.(*ComplexValue).Get            v.Complex
    v.(*ComplexValue).Overflow       v.OverflowComplex
    v.(*ComplexValue).Set            v.SetComplex
    v.(*FloatValue).Get              v.Float
    v.(*FloatValue).Overflow         v.OverflowFloat
    v.(*FloatValue).Set              v.SetFloat
    v.(*FuncValue).Get               v.Pointer
    v.(*InterfaceValue).Get          v.InterfaceData
    v.(*IntValue).Get                v.Int
    v.(*IntValue).Overflow           v.OverflowInt
    v.(*IntValue).Set                v.SetInt
    v.(*MapValue).Elem               v.MapIndex
    v.(*MapValue).Get                v.Pointer
    v.(*MapValue).Keys               v.MapKeys
    v.(*MapValue).SetElem            v.SetMapIndex
    v.(*PtrValue).Get                v.Pointer
    v.(*SliceValue).Elem             v.Index
    v.(*SliceValue).Get              v.Pointer
    v.(*StringValue).Get             v.String
    v.(*StringValue).Set             v.SetString
    v.(*UintValue).Get               v.Uint
    v.(*UintValue).Overflow          v.OverflowUint
    v.(*UintValue).Set               v.SetUint
    v.(*UnsafePointerValue).Get      v.Pointer
    v.(*UnsafePointerValue).Set      v.SetPointer

Part of the motivation for this change is to enable a more
efficient implementation of Value, one that does not allocate
memory during most operations.  To reduce the size of the CL,
this CL's implementation is a wrapper around the old API.
Later CLs will make the implementation more efficient without
changing the API.

Other CLs to be submitted at the same time as this one
add support for this change to gofix (4343047) and update
the Go source tree (4353043).

R=gri, iant, niemeyer, r, rog, gustavo, r2
CC=golang-dev
https://golang.org/cl/4281055
parent 846a368b
This diff is collapsed.
......@@ -22,8 +22,8 @@ type visit struct {
// comparisons that have already been seen, which allows short circuiting on
// recursive types.
func deepValueEqual(v1, v2 Value, visited map[uintptr]*visit, depth int) bool {
if v1 == nil || v2 == nil {
return v1 == v2
if !v1.IsValid() || !v2.IsValid() {
return v1.IsValid() == v2.IsValid()
}
if v1.Type() != v2.Type() {
return false
......@@ -56,57 +56,47 @@ func deepValueEqual(v1, v2 Value, visited map[uintptr]*visit, depth int) bool {
// Remember for later.
visited[h] = &visit{addr1, addr2, typ, seen}
switch v := v1.(type) {
case *ArrayValue:
arr1 := v
arr2 := v2.(*ArrayValue)
if arr1.Len() != arr2.Len() {
switch v1.Kind() {
case Array:
if v1.Len() != v2.Len() {
return false
}
for i := 0; i < arr1.Len(); i++ {
if !deepValueEqual(arr1.Elem(i), arr2.Elem(i), visited, depth+1) {
for i := 0; i < v1.Len(); i++ {
if !deepValueEqual(v1.Index(i), v2.Index(i), visited, depth+1) {
return false
}
}
return true
case *SliceValue:
arr1 := v
arr2 := v2.(*SliceValue)
if arr1.Len() != arr2.Len() {
case Slice:
if v1.Len() != v2.Len() {
return false
}
for i := 0; i < arr1.Len(); i++ {
if !deepValueEqual(arr1.Elem(i), arr2.Elem(i), visited, depth+1) {
for i := 0; i < v1.Len(); i++ {
if !deepValueEqual(v1.Index(i), v2.Index(i), visited, depth+1) {
return false
}
}
return true
case *InterfaceValue:
i1 := v.Interface()
i2 := v2.Interface()
if i1 == nil || i2 == nil {
return i1 == i2
case Interface:
if v1.IsNil() || v2.IsNil() {
return v1.IsNil() == v2.IsNil()
}
return deepValueEqual(NewValue(i1), NewValue(i2), visited, depth+1)
case *PtrValue:
return deepValueEqual(v.Elem(), v2.(*PtrValue).Elem(), visited, depth+1)
case *StructValue:
struct1 := v
struct2 := v2.(*StructValue)
for i, n := 0, v.NumField(); i < n; i++ {
if !deepValueEqual(struct1.Field(i), struct2.Field(i), visited, depth+1) {
return deepValueEqual(v1.Elem(), v2.Elem(), visited, depth+1)
case Ptr:
return deepValueEqual(v1.Elem(), v2.Elem(), visited, depth+1)
case Struct:
for i, n := 0, v1.NumField(); i < n; i++ {
if !deepValueEqual(v1.Field(i), v2.Field(i), visited, depth+1) {
return false
}
}
return true
case *MapValue:
map1 := v
map2 := v2.(*MapValue)
if map1.Len() != map2.Len() {
case Map:
if v1.Len() != v2.Len() {
return false
}
for _, k := range map1.Keys() {
if !deepValueEqual(map1.Elem(k), map2.Elem(k), visited, depth+1) {
for _, k := range v1.MapKeys() {
if !deepValueEqual(v1.MapIndex(k), v2.MapIndex(k), visited, depth+1) {
return false
}
}
......
......@@ -17,29 +17,29 @@ import (
// For debugging only.
func valueToString(val Value) string {
var str string
if val == nil {
return "<nil>"
if !val.IsValid() {
return "<zero Value>"
}
typ := val.Type()
switch val := val.(type) {
case *IntValue:
return strconv.Itoa64(val.Get())
case *UintValue:
return strconv.Uitoa64(val.Get())
case *FloatValue:
return strconv.Ftoa64(float64(val.Get()), 'g', -1)
case *ComplexValue:
c := val.Get()
return strconv.Ftoa64(float64(real(c)), 'g', -1) + "+" + strconv.Ftoa64(float64(imag(c)), 'g', -1) + "i"
case *StringValue:
return val.Get()
case *BoolValue:
if val.Get() {
switch val.Kind() {
case Int, Int8, Int16, Int32, Int64:
return strconv.Itoa64(val.Int())
case Uint, Uint8, Uint16, Uint32, Uint64, Uintptr:
return strconv.Uitoa64(val.Uint())
case Float32, Float64:
return strconv.Ftoa64(val.Float(), 'g', -1)
case Complex64, Complex128:
c := val.Complex()
return strconv.Ftoa64(real(c), 'g', -1) + "+" + strconv.Ftoa64(imag(c), 'g', -1) + "i"
case String:
return val.String()
case Bool:
if val.Bool() {
return "true"
} else {
return "false"
}
case *PtrValue:
case Ptr:
v := val
str = typ.String() + "("
if v.IsNil() {
......@@ -49,7 +49,7 @@ func valueToString(val Value) string {
}
str += ")"
return str
case ArrayOrSliceValue:
case Array, Slice:
v := val
str += typ.String()
str += "{"
......@@ -57,22 +57,22 @@ func valueToString(val Value) string {
if i > 0 {
str += ", "
}
str += valueToString(v.Elem(i))
str += valueToString(v.Index(i))
}
str += "}"
return str
case *MapValue:
t := typ.(*MapType)
case Map:
t := typ
str = t.String()
str += "{"
str += "<can't iterate on maps>"
str += "}"
return str
case *ChanValue:
case Chan:
str = typ.String()
return str
case *StructValue:
t := typ.(*StructType)
case Struct:
t := typ
v := val
str += t.String()
str += "{"
......@@ -84,11 +84,11 @@ func valueToString(val Value) string {
}
str += "}"
return str
case *InterfaceValue:
case Interface:
return typ.String() + "(" + valueToString(val.Elem()) + ")"
case *FuncValue:
case Func:
v := val
return typ.String() + "(" + strconv.Itoa64(int64(v.Get())) + ")"
return typ.String() + "(" + strconv.Uitoa64(uint64(v.Pointer())) + ")"
default:
panic("valueToString: can't print type " + typ.String())
}
......
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment