You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucy.apache.org by ma...@apache.org on 2015/09/11 23:14:01 UTC
[5/7] lucy-clownfish git commit: Perform nil-checking on concrete
types.
Perform nil-checking on concrete types.
Nil-checking on interface types only returns true if both the type and
value slots in the interface tuple are 0. Therefore, it is necessary to
push nil-checking down into code which knows the concrete type.
Project: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/commit/bd9f043b
Tree: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/tree/bd9f043b
Diff: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/diff/bd9f043b
Branch: refs/heads/master
Commit: bd9f043b3a4ba006cc407b4a414827a2879e0b1f
Parents: 180d963
Author: Marvin Humphrey <ma...@rectangular.com>
Authored: Fri Aug 28 18:49:34 2015 -0700
Committer: Marvin Humphrey <ma...@rectangular.com>
Committed: Tue Sep 8 19:09:25 2015 -0700
----------------------------------------------------------------------
runtime/go/clownfish/clownfish.go | 120 ++++++++++++++--------------
runtime/go/clownfish/clownfish_test.go | 14 ++--
2 files changed, 65 insertions(+), 69 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/bd9f043b/runtime/go/clownfish/clownfish.go
----------------------------------------------------------------------
diff --git a/runtime/go/clownfish/clownfish.go b/runtime/go/clownfish/clownfish.go
index b31ed5f..140f1f2 100644
--- a/runtime/go/clownfish/clownfish.go
+++ b/runtime/go/clownfish/clownfish.go
@@ -131,7 +131,7 @@ func GetClass(o Obj) Class {
}
func FetchClass(className string) Class {
- nameCF := (*C.cfish_String)(goToString(className))
+ nameCF := (*C.cfish_String)(goToString(className, false))
defer C.cfish_decref(unsafe.Pointer(nameCF))
class := C.cfish_Class_fetch_class(nameCF)
return WRAPClass(unsafe.Pointer(class))
@@ -156,7 +156,7 @@ func (c *ClassIMP) MakeObj() Obj {
}
func NewMethod(name string, callbackFunc unsafe.Pointer, offset uint32) Method {
- nameCF := (*C.cfish_String)(goToString(name))
+ nameCF := (*C.cfish_String)(goToString(name, false))
defer C.cfish_decref(unsafe.Pointer(nameCF))
methCF := C.cfish_Method_new(nameCF, C.cfish_method_t(callbackFunc),
C.uint32_t(offset));
@@ -230,10 +230,17 @@ func (o *ObjIMP)Clone() Obj {
return WRAPAny(unsafe.Pointer(dupe)).(Obj)
}
-func certifyCF(value interface{}, class *C.cfish_Class) {
- cfObj, ok := value.(Obj)
- if ok {
- if C.cfish_Obj_is_a((*C.cfish_Obj)(unsafe.Pointer(cfObj.TOPTR())), class) {
+func certifyCF(value interface{}, class *C.cfish_Class, nullable bool) {
+ if nullable && value == nil {
+ return
+ }
+ if cfObj, ok := value.(Obj); ok {
+ o := (*C.cfish_Obj)(unsafe.Pointer(cfObj.TOPTR()))
+ if o == nil {
+ if nullable {
+ return
+ }
+ } else if C.cfish_Obj_is_a(o, class) {
return
}
}
@@ -247,18 +254,6 @@ func certifyCF(value interface{}, class *C.cfish_Class) {
func GoToClownfish(value interface{}, class unsafe.Pointer, nullable bool) unsafe.Pointer {
klass := (*C.cfish_Class)(class)
- // Check for nil values.
- if value == nil {
- if nullable {
- return nil
- } else if class != nil {
- className := StringToGo(unsafe.Pointer(C.CFISH_Class_Get_Name(klass)))
- panic(NewErr("Cannot be nil, must be a valid " + className))
- } else {
- panic(NewErr("Cannot be nil"))
- }
- }
-
// Default to accepting any type.
if klass == nil {
klass = C.CFISH_OBJ
@@ -269,38 +264,46 @@ func GoToClownfish(value interface{}, class unsafe.Pointer, nullable bool) unsaf
switch v := value.(type) {
case string:
if klass == C.CFISH_STRING || klass == C.CFISH_OBJ {
- converted = goToString(value)
+ converted = goToString(value, nullable)
}
case []byte:
if klass == C.CFISH_BLOB || klass == C.CFISH_OBJ {
- converted = goToBlob(value)
+ converted = goToBlob(value, nullable)
}
case int, uint, uintptr, int64, int32, int16, int8, uint64, uint32, uint16, uint8:
if klass == C.CFISH_INTEGER || klass == C.CFISH_OBJ {
- converted = goToInteger(value)
+ converted = goToInteger(value, nullable)
}
case float32, float64:
if klass == C.CFISH_FLOAT || klass == C.CFISH_OBJ {
- converted = goToFloat(value)
+ converted = goToFloat(value, nullable)
}
case bool:
if klass == C.CFISH_BOOLEAN || klass == C.CFISH_OBJ {
- converted = goToBoolean(value)
+ converted = goToBoolean(value, nullable)
}
case []interface{}:
if klass == C.CFISH_VECTOR || klass == C.CFISH_OBJ {
- converted = goToVector(value)
+ converted = goToVector(value, nullable)
}
case map[string]interface{}:
if klass == C.CFISH_HASH || klass == C.CFISH_OBJ {
- converted = goToHash(value)
+ converted = goToHash(value, nullable)
}
case Obj:
+ certifyCF(value, klass, nullable)
converted = unsafe.Pointer(C.cfish_incref(unsafe.Pointer(v.TOPTR())))
+ case nil:
+ if nullable {
+ return nil
+ }
}
- // Confirm that we got what we were looking for and return.
- if converted != nil {
+ if converted == nil {
+ if nullable {
+ return nil
+ }
+ } else {
if C.cfish_Obj_is_a((*C.cfish_Obj)(converted), klass) {
return unsafe.Pointer(C.cfish_incref(converted))
}
@@ -330,22 +333,21 @@ func Unwrap(value Obj, name string) unsafe.Pointer {
return ptr
}
-func goToString(value interface{}) unsafe.Pointer {
+func goToString(value interface{}, nullable bool) unsafe.Pointer {
switch v := value.(type) {
case string:
size := len(v)
str := C.CString(v)
return unsafe.Pointer(C.cfish_Str_new_steal_utf8(str, C.size_t(size)))
case Obj:
- certifyCF(v, C.CFISH_STRING)
+ certifyCF(v, C.CFISH_STRING, nullable)
return unsafe.Pointer(C.cfish_incref(unsafe.Pointer(v.TOPTR())))
- default:
- mess := fmt.Sprintf("Can't convert %T to clownfish.String", v)
- panic(NewErr(mess))
}
+ mess := fmt.Sprintf("Can't convert %T to clownfish.String", value)
+ panic(NewErr(mess))
}
-func goToBlob(value interface{}) unsafe.Pointer {
+func goToBlob(value interface{}, nullable bool) unsafe.Pointer {
switch v := value.(type) {
case []byte:
size := C.size_t(len(v))
@@ -355,15 +357,14 @@ func goToBlob(value interface{}) unsafe.Pointer {
}
return unsafe.Pointer(C.cfish_Blob_new(buf, size))
case Obj:
- certifyCF(v, C.CFISH_BLOB)
+ certifyCF(v, C.CFISH_BLOB, nullable)
return unsafe.Pointer(C.cfish_incref(unsafe.Pointer(v.TOPTR())))
- default:
- mess := fmt.Sprintf("Can't convert %T to clownfish.Blob", v)
- panic(NewErr(mess))
}
+ mess := fmt.Sprintf("Can't convert %T to clownfish.Blob", value)
+ panic(NewErr(mess))
}
-func goToInteger(value interface{}) unsafe.Pointer {
+func goToInteger(value interface{}, nullable bool) unsafe.Pointer {
switch v := value.(type) {
case int:
return unsafe.Pointer(C.cfish_Int_new(C.int64_t(v)))
@@ -400,30 +401,28 @@ func goToInteger(value interface{}) unsafe.Pointer {
case int8:
return unsafe.Pointer(C.cfish_Int_new(C.int64_t(v)))
case Obj:
- certifyCF(v, C.CFISH_INTEGER)
+ certifyCF(v, C.CFISH_INTEGER, nullable)
return unsafe.Pointer(C.cfish_incref(unsafe.Pointer(v.TOPTR())))
- default:
- mess := fmt.Sprintf("Can't convert %T to clownfish.Integer", v)
- panic(NewErr(mess))
}
+ mess := fmt.Sprintf("Can't convert %T to clownfish.Integer", value)
+ panic(NewErr(mess))
}
-func goToFloat(value interface{}) unsafe.Pointer {
+func goToFloat(value interface{}, nullable bool) unsafe.Pointer {
switch v := value.(type) {
case float32:
return unsafe.Pointer(C.cfish_Float_new(C.double(v)))
case float64:
return unsafe.Pointer(C.cfish_Float_new(C.double(v)))
case Obj:
- certifyCF(v, C.CFISH_FLOAT)
+ certifyCF(v, C.CFISH_FLOAT, nullable)
return unsafe.Pointer(C.cfish_incref(unsafe.Pointer(v.TOPTR())))
- default:
- mess := fmt.Sprintf("Can't convert %T to clownfish.Float", v)
- panic(NewErr(mess))
}
+ mess := fmt.Sprintf("Can't convert %T to clownfish.Float", value)
+ panic(NewErr(mess))
}
-func goToBoolean(value interface{}) unsafe.Pointer {
+func goToBoolean(value interface{}, nullable bool) unsafe.Pointer {
switch v := value.(type) {
case bool:
if v {
@@ -432,15 +431,14 @@ func goToBoolean(value interface{}) unsafe.Pointer {
return unsafe.Pointer(C.cfish_incref(unsafe.Pointer(C.CFISH_FALSE)))
}
case Obj:
- certifyCF(v, C.CFISH_BOOLEAN)
+ certifyCF(v, C.CFISH_BOOLEAN, nullable)
return unsafe.Pointer(C.cfish_incref(unsafe.Pointer(v.TOPTR())))
- default:
- mess := fmt.Sprintf("Can't convert %T to clownfish.Boolean", v)
- panic(NewErr(mess))
}
+ mess := fmt.Sprintf("Can't convert %T to clownfish.Boolean", value)
+ panic(NewErr(mess))
}
-func goToVector(value interface{}) unsafe.Pointer {
+func goToVector(value interface{}, nullable bool) unsafe.Pointer {
switch v := value.(type) {
case []interface{}:
size := len(v)
@@ -451,15 +449,14 @@ func goToVector(value interface{}) unsafe.Pointer {
}
return unsafe.Pointer(vec)
case Obj:
- certifyCF(v, C.CFISH_VECTOR)
+ certifyCF(v, C.CFISH_VECTOR, nullable)
return unsafe.Pointer(C.cfish_incref(unsafe.Pointer(v.TOPTR())))
- default:
- mess := fmt.Sprintf("Can't convert %T to clownfish.Vector", v)
- panic(NewErr(mess))
}
+ mess := fmt.Sprintf("Can't convert %T to clownfish.Vector", value)
+ panic(NewErr(mess))
}
-func goToHash(value interface{}) unsafe.Pointer {
+func goToHash(value interface{}, nullable bool) unsafe.Pointer {
switch v := value.(type) {
case map[string]interface{}:
size := len(v)
@@ -474,12 +471,11 @@ func goToHash(value interface{}) unsafe.Pointer {
}
return unsafe.Pointer(hash)
case Obj:
- certifyCF(v, C.CFISH_HASH)
+ certifyCF(v, C.CFISH_HASH, nullable)
return unsafe.Pointer(C.cfish_incref(unsafe.Pointer(v.TOPTR())))
- default:
- mess := fmt.Sprintf("Can't convert %T to clownfish.Hash", v)
- panic(NewErr(mess))
}
+ mess := fmt.Sprintf("Can't convert %T to clownfish.Hash", value)
+ panic(NewErr(mess))
}
func ToGo(ptr unsafe.Pointer) interface{} {
http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/bd9f043b/runtime/go/clownfish/clownfish_test.go
----------------------------------------------------------------------
diff --git a/runtime/go/clownfish/clownfish_test.go b/runtime/go/clownfish/clownfish_test.go
index 69e9660..074b58b 100644
--- a/runtime/go/clownfish/clownfish_test.go
+++ b/runtime/go/clownfish/clownfish_test.go
@@ -136,7 +136,7 @@ func TestGoToNilNotNullable(t *testing.T) {
func TestGoToString(t *testing.T) {
strings := []string{"foo", "", "z\u0000z"}
for _, val := range strings {
- got := WRAPAny(goToString(val))
+ got := WRAPAny(goToString(val, false))
if _, ok := got.(String); !ok {
t.Errorf("Not a String, but a %T", got)
}
@@ -150,7 +150,7 @@ func TestGoToBlob(t *testing.T) {
strings := []string{"foo", "", "z\u0000z"}
for _, str := range strings {
val := []byte(str)
- got := WRAPAny(goToBlob(val))
+ got := WRAPAny(goToBlob(val, false))
if _, ok := got.(Blob); !ok {
t.Errorf("Not a Blob, but a %T", got)
}
@@ -193,7 +193,7 @@ func TestGoToFloat(t *testing.T) {
values := []float64{math.MaxFloat64, math.SmallestNonzeroFloat64,
0.0, -0.0, 0.5, -0.5, math.Inf(1), math.Inf(-1)}
for _, val := range values {
- got := WRAPAny(goToFloat(val))
+ got := WRAPAny(goToFloat(val, false))
if _, ok := got.(Float); !ok {
t.Errorf("Not a Float, but a %T", got)
}
@@ -203,7 +203,7 @@ func TestGoToFloat(t *testing.T) {
}
// NaN
- got = WRAPAny(goToFloat(math.NaN()))
+ got = WRAPAny(goToFloat(math.NaN(), false))
if !math.IsNaN(ToGo(unsafe.Pointer(got.TOPTR())).(float64)) {
t.Error("Didn't convert NaN cleanly")
}
@@ -217,7 +217,7 @@ func TestGoToFloat(t *testing.T) {
func TestGoToBoolean(t *testing.T) {
values := []bool{true, false}
for _, val := range values {
- got := WRAPAny(goToBoolean(val))
+ got := WRAPAny(goToBoolean(val, false))
if _, ok := got.(Boolean); !ok {
t.Errorf("Not a Boolean, but a %T", got)
}
@@ -232,7 +232,7 @@ func TestGoToHash(t *testing.T) {
"foo": int64(1),
"bar": []interface{}{},
}
- got := WRAPAny(goToHash(expected))
+ got := WRAPAny(goToHash(expected, false))
if _, ok := got.(Hash); !ok {
t.Errorf("Not a Hash, but a %T", got)
}
@@ -246,7 +246,7 @@ func TestGoToVector(t *testing.T) {
[]interface{}{},
int64(-1),
}
- got := WRAPAny(goToVector(expected))
+ got := WRAPAny(goToVector(expected, false))
if _, ok := got.(Vector); !ok {
t.Errorf("Not a Vector, but a %T", got)
}