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