PyAPI: replace PyC_FromArray with typed functions

This was meant to be generic but introduced possible type errors
and unnecessary complication.
Replace with typed PyC_Tuple_PackArray_* functions.

Also add PyC_Tuple_Pack_* macro which replaces some uses of
Py_BuildValue, with the advantage of not having to parse a string.
This commit is contained in:
2017-08-22 18:02:58 +10:00
parent 049932c4c3
commit 691ed21842
12 changed files with 90 additions and 83 deletions

View File

@@ -127,54 +127,52 @@ int PyC_AsArray(
return ret;
}
/* -------------------------------------------------------------------- */
/** \name Typed Tuple Packing
*
* \note See #PyC_Tuple_Pack_* macros that take multiple arguments.
*
* \{ */
/* array utility function */
PyObject *PyC_FromArray(const void *array, int length, const PyTypeObject *type,
const bool is_double, const char *error_prefix)
PyObject *PyC_Tuple_PackArray_F32(const float *array, uint len)
{
PyObject *tuple;
int i;
tuple = PyTuple_New(length);
/* for each type */
if (type == &PyFloat_Type) {
if (is_double) {
const double *array_double = array;
for (i = 0; i < length; ++i) {
PyTuple_SET_ITEM(tuple, i, PyFloat_FromDouble(array_double[i]));
}
}
else {
const float *array_float = array;
for (i = 0; i < length; ++i) {
PyTuple_SET_ITEM(tuple, i, PyFloat_FromDouble(array_float[i]));
}
}
PyObject *tuple = PyTuple_New(len);
for (uint i = 0; i < len; i++) {
PyTuple_SET_ITEM(tuple, i, PyFloat_FromDouble(array[i]));
}
else if (type == &PyLong_Type) {
/* could use is_double for 'long int' but no use now */
const int *array_int = array;
for (i = 0; i < length; ++i) {
PyTuple_SET_ITEM(tuple, i, PyLong_FromLong(array_int[i]));
}
}
else if (type == &PyBool_Type) {
const int *array_bool = array;
for (i = 0; i < length; ++i) {
PyTuple_SET_ITEM(tuple, i, PyBool_FromLong(array_bool[i]));
}
}
else {
Py_DECREF(tuple);
PyErr_Format(PyExc_TypeError,
"%s: internal error %s is invalid",
error_prefix, type->tp_name);
return NULL;
}
return tuple;
}
PyObject *PyC_Tuple_PackArray_I32(const int *array, uint len)
{
PyObject *tuple = PyTuple_New(len);
for (uint i = 0; i < len; i++) {
PyTuple_SET_ITEM(tuple, i, PyLong_FromLong(array[i]));
}
return tuple;
}
PyObject *PyC_Tuple_PackArray_I32FromBool(const int *array, uint len)
{
PyObject *tuple = PyTuple_New(len);
for (uint i = 0; i < len; i++) {
PyTuple_SET_ITEM(tuple, i, PyBool_FromLong(array[i]));
}
return tuple;
}
PyObject *PyC_Tuple_PackArray_Bool(const bool *array, uint len)
{
PyObject *tuple = PyTuple_New(len);
for (uint i = 0; i < len; i++) {
PyTuple_SET_ITEM(tuple, i, PyBool_FromLong(array[i]));
}
return tuple;
}
/** \} */
/**
* Caller needs to ensure tuple is uninitialized.
* Handy for filling a tuple with None for eg.

View File

@@ -45,8 +45,21 @@ int PyC_AsArray_FAST(
int PyC_AsArray(
void *array, PyObject *value, const Py_ssize_t length,
const PyTypeObject *type, const bool is_double, const char *error_prefix);
PyObject * PyC_FromArray(const void *array, int length, const PyTypeObject *type,
const bool is_double, const char *error_prefix);
PyObject *PyC_Tuple_PackArray_F32(const float *array, uint len);
PyObject *PyC_Tuple_PackArray_I32(const int *array, uint len);
PyObject *PyC_Tuple_PackArray_I32FromBool(const int *array, uint len);
PyObject *PyC_Tuple_PackArray_Bool(const bool *array, uint len);
#define PyC_Tuple_Pack_F32(...) \
PyC_Tuple_PackArray_F32(((const float []){__VA_ARGS__}), (sizeof((const float []){__VA_ARGS__}) / sizeof(float)))
#define PyC_Tuple_Pack_I32(...) \
PyC_Tuple_PackArray_I32(((const int []){__VA_ARGS__}), (sizeof((const int []){__VA_ARGS__}) / sizeof(int)))
#define PyC_Tuple_Pack_I32FromBool(...) \
PyC_Tuple_PackArray_I32FromBool(((const int []){__VA_ARGS__}), (sizeof((const int []){__VA_ARGS__}) / sizeof(int)))
#define PyC_Tuple_Pack_Bool(...) \
PyC_Tuple_PackArray_Bool(((const bool []){__VA_ARGS__}), (sizeof((const bool []){__VA_ARGS__}) / sizeof(bool)))
void PyC_Tuple_Fill(PyObject *tuple, PyObject *value);
void PyC_List_Fill(PyObject *list, PyObject *value);