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 2016/02/25 00:07:34 UTC
[07/20] lucy-clownfish git commit: Conversion routines from Python to
Clownfish.
Conversion routines from Python to Clownfish.
Project: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/commit/99d6bc0f
Tree: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/tree/99d6bc0f
Diff: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/diff/99d6bc0f
Branch: refs/heads/master
Commit: 99d6bc0fe89382c8492d97825fc03ca82eac051f
Parents: 999b39f
Author: Marvin Humphrey <ma...@rectangular.com>
Authored: Wed Jan 27 15:35:08 2016 -0800
Committer: Marvin Humphrey <ma...@rectangular.com>
Committed: Tue Feb 23 18:22:03 2016 -0800
----------------------------------------------------------------------
runtime/python/cfext/CFBind.c | 196 +++++++++++++++++++++++++++++++++++++
runtime/python/cfext/CFBind.h | 34 +++++++
2 files changed, 230 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/99d6bc0f/runtime/python/cfext/CFBind.c
----------------------------------------------------------------------
diff --git a/runtime/python/cfext/CFBind.c b/runtime/python/cfext/CFBind.c
index d3c39c2..501c342 100644
--- a/runtime/python/cfext/CFBind.c
+++ b/runtime/python/cfext/CFBind.c
@@ -37,6 +37,7 @@
#include "Clownfish/String.h"
#include "Clownfish/TestHarness/TestUtils.h"
#include "Clownfish/Util/Memory.h"
+#include "Clownfish/Util/StringHelper.h"
#include "Clownfish/Vector.h"
static bool Err_initialized;
@@ -85,6 +86,201 @@ CFBind_reraise_pyerr(cfish_Class *err_klass, cfish_String *mess) {
cfish_Err_throw_mess(err_klass, new_mess);
}
+static cfish_Vector*
+S_py_list_to_vector(PyObject *list) {
+ Py_ssize_t size = PyList_GET_SIZE(list);
+ cfish_Vector *vec = cfish_Vec_new(size);
+ for (Py_ssize_t i = 0; i < size; i++) {
+ CFISH_Vec_Store(vec, i, CFBind_py_to_cfish(PyList_GET_ITEM(list, i), NULL));
+ }
+ return vec;
+}
+
+static cfish_Hash*
+S_py_dict_to_hash(PyObject *dict) {
+ Py_ssize_t pos = 0;
+ PyObject *key, *value;
+ cfish_Hash *hash = cfish_Hash_new(PyDict_Size(dict));
+ while (PyDict_Next(dict, &pos, &key, &value)) {
+ char *ptr;
+ Py_ssize_t size;
+ PyObject *stringified = key;
+ if (!PyUnicode_CheckExact(key)) {
+ stringified = PyObject_Str(key);
+ }
+ ptr = PyUnicode_AsUTF8AndSize(stringified, &size);
+ if (!ptr) {
+ cfish_String *mess
+ = CFISH_MAKE_MESS("Failed to stringify as UTF-8");
+ CFBind_reraise_pyerr(CFISH_ERR, mess);
+ }
+ CFISH_Hash_Store_Utf8(hash, ptr, size, CFBind_py_to_cfish(value, NULL));
+ if (stringified != key) {
+ Py_DECREF(stringified);
+ }
+ }
+ return hash;
+}
+
+static cfish_Obj*
+S_maybe_increment(void *vobj, bool increment) {
+ if (increment) {
+ return CFISH_INCREF((cfish_Obj*)vobj);
+ }
+ return (cfish_Obj*)vobj;
+}
+
+static bool
+S_maybe_py_to_cfish(PyObject *py_obj, cfish_Class *klass, bool increment,
+ bool nullable, void *allocation, cfish_Obj **obj_ptr) {
+ CFISH_UNUSED_VAR(allocation); // FIXME implement stack strings
+
+ if (!py_obj || py_obj == Py_None) {
+ *obj_ptr = NULL;
+ return nullable;
+ }
+
+ // Default to accepting any type.
+ if (klass == NULL) {
+ klass = CFISH_OBJ;
+ }
+
+ if (S_py_obj_is_a(py_obj, klass)) {
+ *obj_ptr = S_maybe_increment(py_obj, increment);
+ return true;
+ }
+ else if (py_obj == Py_True) {
+ if (klass != CFISH_BOOLEAN && klass != CFISH_OBJ) {
+ return false;
+ }
+ *obj_ptr = S_maybe_increment(CFISH_TRUE, increment);
+ return true;
+ }
+ else if (py_obj == Py_False) {
+ if (klass != CFISH_BOOLEAN && klass != CFISH_OBJ) {
+ return false;
+ }
+ *obj_ptr = S_maybe_increment(CFISH_FALSE, increment);
+ return true;
+ }
+ else if (klass == CFISH_BOOLEAN) {
+ int truthiness = PyObject_IsTrue(py_obj);
+ if (truthiness == 1) {
+ *obj_ptr = S_maybe_increment(CFISH_TRUE, increment);
+ }
+ else if (truthiness == 0) {
+ *obj_ptr = S_maybe_increment(CFISH_FALSE, increment);
+ }
+ else {
+ return false;
+ }
+ return true;
+ }
+
+ // From here on out, we're going to return a new Clownfish object. The
+ // caller has to take ownership of a refcount; if they don't want to, then
+ // fail rather than attempt to return an object with a refcount of 0.
+ if (!increment) {
+ return false;
+ }
+
+ if (PyUnicode_CheckExact(py_obj)) {
+ if (klass != CFISH_STRING && klass != CFISH_OBJ) {
+ return false;
+ }
+ // TODO: Allow Clownfish String to wrap buffer of Python str?
+ Py_ssize_t size;
+ char *ptr = PyUnicode_AsUTF8AndSize(py_obj, &size);
+ // TODO: Can we guarantee that Python will always supply valid UTF-8?
+ if (!ptr || !cfish_StrHelp_utf8_valid(ptr, size)) {
+ return false;
+ }
+ *obj_ptr = (cfish_Obj*)cfish_Str_new_from_trusted_utf8(ptr, size);
+ return true;
+ }
+ else if (PyBytes_CheckExact(py_obj)) {
+ if (klass != CFISH_BLOB && klass != CFISH_OBJ) {
+ return false;
+ }
+ char *ptr = PyBytes_AS_STRING(py_obj);
+ Py_ssize_t size = PyBytes_GET_SIZE(py_obj);
+ *obj_ptr = (cfish_Obj*)cfish_BB_new_bytes(ptr, size);
+ return true;
+ }
+ else if (PyList_CheckExact(py_obj)) {
+ if (klass != CFISH_VECTOR && klass != CFISH_OBJ) {
+ return false;
+ }
+ *obj_ptr = (cfish_Obj*)S_py_list_to_vector(py_obj);
+ return true;
+ }
+ else if (PyDict_CheckExact(py_obj)) {
+ if (klass != CFISH_HASH && klass != CFISH_OBJ) {
+ return false;
+ }
+ *obj_ptr = (cfish_Obj*)S_py_dict_to_hash(py_obj);
+ return true;
+ }
+ else if (PyLong_CheckExact(py_obj)) {
+ if (klass != CFISH_INTEGER && klass != CFISH_OBJ) {
+ return false;
+ }
+ // Raises ValueError on overflow.
+ int64_t value = PyLong_AsLongLong(py_obj);
+ if (PyErr_Occurred()) {
+ return false;
+ }
+ *obj_ptr = (cfish_Obj*)cfish_Int_new(value);
+ return true;
+ }
+ else if (PyFloat_CheckExact(py_obj)) {
+ if (klass != CFISH_FLOAT && klass != CFISH_OBJ) {
+ return false;
+ }
+ double value = PyFloat_AsDouble(py_obj);
+ if (PyErr_Occurred()) {
+ return false;
+ }
+ *obj_ptr = (cfish_Obj*)cfish_Float_new(value);
+ return true;
+ }
+
+ // The value did not meet the required spec, so return false to indicate
+ // failure.
+ return false;
+}
+
+cfish_Obj*
+CFBind_py_to_cfish_nullable(PyObject *py_obj, cfish_Class *klass) {
+ cfish_Obj *retval;
+ bool success = S_maybe_py_to_cfish(py_obj, klass, true, true, NULL, &retval);
+ if (!success) {
+ CFISH_THROW(CFISH_ERR, "Can't convert to %o", klass);
+ }
+ return retval;
+}
+
+cfish_Obj*
+CFBind_py_to_cfish(PyObject *py_obj, cfish_Class *klass) {
+ cfish_Obj *retval;
+ bool success = S_maybe_py_to_cfish(py_obj, klass, true, false, NULL, &retval);
+ if (!success) {
+ CFISH_THROW(CFISH_ERR, "Can't convert to %o", klass);
+ }
+ return retval;
+}
+
+cfish_Obj*
+CFBind_py_to_cfish_noinc(PyObject *py_obj, cfish_Class *klass,
+ void *allocation) {
+ cfish_Obj *retval;
+ bool success = S_maybe_py_to_cfish(py_obj, klass, false, false, allocation, &retval);
+ if (!success) {
+ CFISH_THROW(CFISH_ERR, "Can't convert to %o", klass);
+ }
+ return retval;
+}
+
static int
S_convert_sint(PyObject *py_obj, void *ptr, bool nullable, unsigned width) {
if (py_obj == Py_None) {
http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/99d6bc0f/runtime/python/cfext/CFBind.h
----------------------------------------------------------------------
diff --git a/runtime/python/cfext/CFBind.h b/runtime/python/cfext/CFBind.h
index 6637fca..e4e0f23 100644
--- a/runtime/python/cfext/CFBind.h
+++ b/runtime/python/cfext/CFBind.h
@@ -66,6 +66,40 @@ CFBind_cfish_to_py_zeroref(struct cfish_Obj *obj) {
}
}
+/** Perform recursive conversion of Python objects to Clownfish, return an
+ * incremented Clownfish Obj.
+ *
+ * string -> String
+ * bytes -> Blob
+ * None -> NULL
+ * bool -> Boolean
+ * int -> Integer
+ * float -> Float
+ * list -> Vector
+ * dict -> Hash
+ *
+ * Python dict keys will be stringified. Other Clownfish objects will be
+ * left intact. Anything else will be stringified.
+ */
+cfish_Obj*
+CFBind_py_to_cfish(PyObject *py_obj, cfish_Class *klass);
+
+/** As CFBind_py_to_cfish above, but returns NULL if the PyObject is None
+ * or NULL.
+ */
+cfish_Obj*
+CFBind_py_to_cfish_nullable(PyObject *py_obj, cfish_Class *klass);
+
+/** As CFBind_py_to_cfish above, but returns an object that can be used for a
+ * while with no need to decref.
+ *
+ * If `klass` is STRING or OBJ, `allocation` must point to stack-allocated
+ * memory that can hold a String. Otherwise, `allocation` should be NULL.
+ */
+cfish_Obj*
+CFBind_py_to_cfish_noinc(PyObject *py_obj, cfish_Class *klass,
+ void *allocation);
+
/* ParseTuple conversion routines for primitive numeric types.
*
* If the value of `input` is out of range for the an integer C type, an