Mercurial > pytave
diff oct-py-types.cc @ 352:eac35d84ef0d
Convert Octave numeric vectors into Python array.array
* oct-py-types.cc, oct-py-types.h (pytave::make_py_array): New functions to
convert an Octave numeric array into Python array object of appropriate type.
* octave_to_python.cc (pytave::octvalue_to_pyobj): Add numeric vector case.
* pycall.cc: Delete %!tests that relied on conversion to numpy array.
author | Mike Miller <mtmiller@octave.org> |
---|---|
date | Wed, 17 Aug 2016 21:19:58 -0700 |
parents | 9d95f087e5aa |
children | 8cdc94b83e98 |
line wrap: on
line diff
--- a/oct-py-types.cc Wed Aug 17 14:02:33 2016 -0700 +++ b/oct-py-types.cc Wed Aug 17 21:19:58 2016 -0700 @@ -29,6 +29,7 @@ #include <octave/quit.h> #include "exceptions.h" +#include "oct-py-eval.h" #include "oct-py-types.h" // FIXME: only here to bootstrap nested conversions needed in this file @@ -134,6 +135,112 @@ } PyObject * +make_py_array (const void *data, size_t len, char typecode) +{ + if (! typecode) + throw object_convert_exception ("unable to create array from Octave data"); + + std::string arg { typecode }; + PyObject *array = py_call_function ("array.array", ovl (arg)); + + if (len > 0) + { + // create a byte buffer containing a copy of the array binary data + const char *cdata = reinterpret_cast<const char *> (data); + PyObject *buf = PyBytes_FromStringAndSize (cdata, len); + if (! buf) + octave_throw_bad_alloc (); + + PyObject *frombytes = (PyObject_HasAttrString (array, "frombytes") ? + PyObject_GetAttrString (array, "frombytes") : + PyObject_GetAttrString (array, "fromstring")); + PyObject *args = PyTuple_Pack (1, buf); + py_call_function (frombytes, args); + Py_DECREF (args); + Py_DECREF (buf); + } + + return array; +} + +// Prefer the 'q' and 'Q' typecodes if they are available (if Python 3 and +// built with support for long long integers) + +#if (PY_VERSION_HEX >= 0x03000000) && defined (HAVE_LONG_LONG) +# define ARRAY_INT64_TYPECODE 'q' +# define ARRAY_UINT64_TYPECODE 'Q' +#elif (SIZEOF_LONG == 8) +# define ARRAY_INT64_TYPECODE 'l' +# define ARRAY_UINT64_TYPECODE 'L' +#else +# define ARRAY_INT64_TYPECODE 0 +# define ARRAY_UINT64_TYPECODE 0 +#endif + +template <typename T> +struct py_array_info { }; + +template <> +struct py_array_info<octave_int8> { static const char typecode = 'b'; }; + +template <> +struct py_array_info<octave_int16> { static const char typecode = 'h'; }; + +template <> +struct py_array_info<octave_int32> { static const char typecode = 'i'; }; + +template <> +struct py_array_info<octave_int64> +{ + static const char typecode = ARRAY_INT64_TYPECODE; +}; + +template <> +struct py_array_info<octave_uint8> { static const char typecode = 'B'; }; + +template <> +struct py_array_info<octave_uint16> { static const char typecode = 'H'; }; + +template <> +struct py_array_info<octave_uint32> { static const char typecode = 'I'; }; + +template <> +struct py_array_info<octave_uint64> { + static const char typecode = ARRAY_UINT64_TYPECODE; +}; + +PyObject * +make_py_array (const NDArray& nda) +{ + return make_py_array (nda.data (), nda.numel () * sizeof (double), 'd'); +} + +PyObject * +make_py_array (const FloatNDArray& nda) +{ + return make_py_array (nda.data (), nda.numel () * sizeof (float), 'f'); +} + +template <typename T> +PyObject * +make_py_array (const intNDArray<T>& nda) +{ + return make_py_array (nda.data (), nda.numel () * sizeof (T), + py_array_info<T>::typecode); +} + +// Instantiate all possible integer array template functions needed + +template PyObject * make_py_array<octave_int8> (const int8NDArray&); +template PyObject * make_py_array<octave_int16> (const int16NDArray&); +template PyObject * make_py_array<octave_int32> (const int32NDArray&); +template PyObject * make_py_array<octave_int64> (const int64NDArray&); +template PyObject * make_py_array<octave_uint8> (const uint8NDArray&); +template PyObject * make_py_array<octave_uint16> (const uint16NDArray&); +template PyObject * make_py_array<octave_uint32> (const uint32NDArray&); +template PyObject * make_py_array<octave_uint64> (const uint64NDArray&); + +PyObject * make_py_numeric_value (const octave_value& value) { if (value.is_scalar_type ()) @@ -169,6 +276,40 @@ return 0; } +PyObject * +make_py_array (const octave_value& value) +{ + if (value.is_numeric_type () && ! value.is_complex_type () + && value.ndims () == 2 && (value.columns () == 1 || value.rows () == 1)) + { + if (value.is_double_type ()) + return make_py_array (value.array_value ()); + else if (value.is_single_type ()) + return make_py_array (value.float_array_value ()); + + else if (value.is_int8_type ()) + return make_py_array (value.int8_array_value ()); + else if (value.is_int16_type ()) + return make_py_array (value.int16_array_value ()); + else if (value.is_int32_type ()) + return make_py_array (value.int32_array_value ()); + else if (value.is_int64_type ()) + return make_py_array (value.int64_array_value ()); + + else if (value.is_uint8_type ()) + return make_py_array (value.uint8_array_value ()); + else if (value.is_uint16_type ()) + return make_py_array (value.uint16_array_value ()); + else if (value.is_uint32_type ()) + return make_py_array (value.uint32_array_value ()); + else if (value.is_uint64_type ()) + return make_py_array (value.uint64_array_value ()); + } + + throw value_convert_exception ("unhandled Octave numeric vector type"); + return 0; +} + inline PyObject * wrap_octvalue_to_pyobj (const octave_value& value) {