changeset 143:fe783134c61c

Fix conversion of integer types by using strictly sized integers * octave_to_python.cc (pytave::octvalue_to_pyarrobj): Convert Octave sized integer types into the corresponding NumPy sized integer types. (pytave::create_array, pytave::create_sint_array, pytave::create_uint_array): Delete unnecessary conversion heuristics. * python_to_octave.cc (pytave::copy_pyarrobj_to_octarray_boot): Convert NumPy sized integer types into the corresponding Octave sized integer types. Add special cases to convert ambiguous NPY_LONG, NPY_LONGLONG, NPY_ULONG, and NPY_ULONGLONG types. (pytave::pyarr_to_octvalue): Add missing cases for NPY_ULONG and NPY_ULONGLONG.
author Mike Miller <mtmiller@octave.org>
date Mon, 04 Apr 2016 22:51:54 -0700
parents dc2876fdbfaf
children ad964e46cd48
files octave_to_python.cc python_to_octave.cc
diffstat 2 files changed, 93 insertions(+), 137 deletions(-) [+]
line wrap: on
line diff
--- a/octave_to_python.cc	Mon Apr 04 17:54:22 2016 -0700
+++ b/octave_to_python.cc	Mon Apr 04 22:51:54 2016 -0700
@@ -26,7 +26,6 @@
 #endif
 
 #include <boost/python.hpp>
-#include <boost/type_traits/integral_constant.hpp>
 
 #include <octave/oct.h>
 #include <octave/ov.h>
@@ -37,14 +36,6 @@
 #include "exceptions.h"
 #include "octave_to_python.h"
 
-/* From docs:
- *  Note that the names of the element type constants refer to the C data
- *  types, not the Python data types. A Python int is equivalent to a C long,
- *  and a Python float corresponds to a C double . Many of the element types
- *  listed above do not have corresponding Python scalar types
- *  (e.g. NPY_INT ).
- */
-
 using namespace boost::python;
 
 namespace pytave {
@@ -134,69 +125,6 @@
       return pyarr;
    }
 
-   template <class PythonPrimitive, class OctaveBase>
-   static PyArrayObject *create_array(const OctaveBase &octarr,
-                                      int pyarraytype, boost::true_type) {
-      return create_array<PythonPrimitive, OctaveBase> (octarr, pyarraytype);
-   }
-
-   template <class PythonPrimitive, class OctaveBase>
-   static PyArrayObject *create_array(const OctaveBase &octarr,
-                                      int pyarraytype, boost::false_type) {
-      assert(0);
-      return 0;
-   }
-
-   template <class CLASS, size_t bytes>
-   inline static PyArrayObject *create_uint_array(CLASS value) {
-      if (bytes == sizeof(int)) {
-         boost::integral_constant<bool, bytes == sizeof(int)> inst;
-         return create_array<unsigned int, CLASS>(value, NPY_UINT, inst);
-      } else if (bytes == sizeof(char)) {
-         boost::integral_constant<bool, bytes == sizeof(char)> inst;
-         return create_array<unsigned char, CLASS>(value, NPY_UBYTE, inst);
-      } else if (bytes == sizeof(short)) {
-         boost::integral_constant<bool,
-            bytes == sizeof(short) && bytes != sizeof(int)> inst;
-         return create_array<unsigned short, CLASS>(value, NPY_USHORT, inst);
-      } else {
-         std::ostringstream os;
-         os << "NumPy arrays do not support unsigned " << (bytes*8)
-            << "-bit values on this architecture.";
-         throw value_convert_exception(os.str());
-      }
-   }
-
-   template <class CLASS, size_t bytes>
-   inline static PyArrayObject *create_sint_array(CLASS value) {
-      if (bytes == sizeof(int)) {
-         // We test int first since we prefer int to other datatypes of the
-         // same size.
-         boost::integral_constant<bool, bytes == sizeof(int)> inst;
-         return create_array<signed int, CLASS>(value, NPY_INT, inst);
-      }
-      else if (bytes == sizeof(long long)) {
-         boost::integral_constant<bool, bytes == sizeof(long long) && bytes != sizeof(int)> inst;
-         return create_array<long, CLASS>(value, NPY_LONGLONG, inst);
-      }
-      else if (bytes == sizeof(long)) {
-         boost::integral_constant<bool, bytes == sizeof(long) && bytes != sizeof(int) && bytes != sizeof(long long)> inst;
-         return create_array<long, CLASS>(value, NPY_LONG, inst);
-      } else if (bytes == sizeof(char)) {
-         boost::integral_constant<bool, bytes == sizeof(char)> inst;
-         return create_array<signed char, CLASS>(value, NPY_BYTE, inst);
-      } else if (bytes == sizeof(short)) {
-         boost::integral_constant<bool,
-            bytes==sizeof(short) && bytes != sizeof(int)> inst;
-         return create_array<signed short, CLASS>(value, NPY_SHORT, inst);
-      } else {
-         std::ostringstream os;
-         os << "NumPy arrays do not support signed " << (bytes*8)
-            << "-bit values on this architecture.";
-         throw value_convert_exception(os.str());
-      }
-   }
-
    static PyArrayObject *octvalue_to_pyarrobj(const octave_value &matrix) {
       if (matrix.is_double_type ()) {
          if (matrix.is_complex_type ()) {
@@ -220,34 +148,40 @@
             throw value_convert_exception("Unknown float matrix type");
       }
 
-      if (matrix.is_int64_type()) {
-         return create_sint_array<int64NDArray, sizeof(int64_t)>(
-            matrix.int64_array_value());
+      if (matrix.is_int8_type()) {
+         return create_array<int8_t, int8NDArray>(
+            matrix.int8_array_value(), NPY_INT8);
       }
-      if (matrix.is_uint32_type()) {
-         return create_uint_array<uint32NDArray, sizeof(uint32_t)>(
-            matrix.uint32_array_value());
+      if (matrix.is_int16_type()) {
+         return create_array<int16_t, int16NDArray>(
+            matrix.int16_array_value(), NPY_INT16);
       }
       if (matrix.is_int32_type()) {
-         return create_sint_array<int32NDArray, sizeof(int32_t)>(
-            matrix.int32_array_value());
+         return create_array<int32_t, int32NDArray>(
+            matrix.int32_array_value(), NPY_INT32);
+      }
+      if (matrix.is_int64_type()) {
+         return create_array<int64_t, int64NDArray>(
+            matrix.int64_array_value(), NPY_INT64);
+      }
+
+      if (matrix.is_uint8_type()) {
+         return create_array<uint8_t, uint8NDArray>(
+            matrix.uint8_array_value(), NPY_UINT8);
       }
       if (matrix.is_uint16_type()) {
-         return create_uint_array<uint16NDArray, sizeof(uint16_t)>(
-            matrix.uint16_array_value());
-      }
-      if (matrix.is_int16_type()) {
-         return create_sint_array<int16NDArray, sizeof(int16_t)>(
-            matrix.int16_array_value());
+         return create_array<uint16_t, uint16NDArray>(
+            matrix.uint16_array_value(), NPY_UINT16);
       }
-      if (matrix.is_uint8_type()) {
-         return create_uint_array<uint8NDArray, sizeof(uint8_t)>(
-            matrix.uint8_array_value());
+      if (matrix.is_uint32_type()) {
+         return create_array<uint32_t, uint32NDArray>(
+            matrix.uint32_array_value(), NPY_UINT32);
       }
-      if (matrix.is_int8_type()) {
-         return create_sint_array<int8NDArray, sizeof(int8_t)>(
-            matrix.int8_array_value());
+      if (matrix.is_uint64_type()) {
+         return create_array<uint64_t, uint64NDArray>(
+            matrix.uint64_array_value(), NPY_UINT64);
       }
+
       if (matrix.is_bool_type()) {
          return create_array<bool, boolNDArray>(
             matrix.bool_array_value(), NPY_BOOL);
--- a/python_to_octave.cc	Mon Apr 04 17:54:22 2016 -0700
+++ b/python_to_octave.cc	Mon Apr 04 22:51:54 2016 -0700
@@ -148,44 +148,60 @@
          (matrix, pyarr); \
          break; \
 
-      // Prefer int to other types of the same size.
-      // E.g. on 32-bit x86 architectures: sizeof(long) == sizeof(int).
+      // Coerce NumPy's long type into one of two possible sized integer types
       int type_num = PyArray_TYPE (pyarr);
       switch (type_num) {
          case NPY_LONG:
-            if (sizeof(long) == sizeof(int)) {
-               type_num = NPY_INT;
+            if (sizeof(npy_long) == sizeof(int64_t)) {
+               type_num = NPY_INT64;
+            }
+            else if (sizeof(npy_long) == sizeof(int32_t)) {
+               type_num = NPY_INT32;
+            }
+            break;
+         case NPY_LONGLONG:
+            if (sizeof(npy_longlong) == sizeof(int64_t)) {
+               type_num = NPY_INT64;
+            }
+            else if (sizeof(npy_longlong) == sizeof(int32_t)) {
+               type_num = NPY_INT32;
             }
             break;
-         case NPY_SHORT:
-            if (sizeof(short) == sizeof(int)) {
-               type_num = NPY_INT;
+         case NPY_ULONG:
+            if (sizeof(npy_ulong) == sizeof(uint64_t)) {
+               type_num = NPY_UINT64;
+            }
+            else if (sizeof(npy_ulong) == sizeof(uint32_t)) {
+               type_num = NPY_UINT32;
             }
             break;
-         case NPY_USHORT:
-            if (sizeof(unsigned short) == sizeof(unsigned int)) {
-               type_num = NPY_UINT;
+         case NPY_ULONGLONG:
+            if (sizeof(npy_ulonglong) == sizeof(uint64_t)) {
+               type_num = NPY_UINT64;
+            }
+            else if (sizeof(npy_ulonglong) == sizeof(uint32_t)) {
+               type_num = NPY_UINT32;
             }
             break;
       }
 
       switch (type_num) {
-         ARRAYCASE(NPY_CHAR,              char)
-         ARRAYCASE(NPY_BYTE,     signed   char)
-         ARRAYCASE(NPY_UBYTE,    unsigned char)
-         ARRAYCASE(NPY_SHORT,    signed   short)
-         ARRAYCASE(NPY_USHORT,   unsigned short)
-         ARRAYCASE(NPY_INT,      signed   int)
-         ARRAYCASE(NPY_UINT,     unsigned int)
-         ARRAYCASE(NPY_LONG,     signed   long)
-         ARRAYCASE(NPY_LONGLONG, signed   long long)
-         ARRAYCASE(NPY_FLOAT,    float)
-         ARRAYCASE(NPY_DOUBLE,   double)
-         ARRAYCASE(NPY_CFLOAT,   FloatComplex)
-         ARRAYCASE(NPY_CDOUBLE,  Complex)
-         ARRAYCASE(NPY_BOOL,     bool)
-         ARRAYCASE(NPY_STRING,   char)
-         ARRAYCASE(NPY_OBJECT,   PyObject *)
+         ARRAYCASE(NPY_INT8,    int8_t)
+         ARRAYCASE(NPY_INT16,   int16_t)
+         ARRAYCASE(NPY_INT32,   int32_t)
+         ARRAYCASE(NPY_INT64,   int64_t)
+         ARRAYCASE(NPY_UINT8,   uint8_t)
+         ARRAYCASE(NPY_UINT16,  uint16_t)
+         ARRAYCASE(NPY_UINT32,  uint32_t)
+         ARRAYCASE(NPY_UINT64,  uint64_t)
+         ARRAYCASE(NPY_FLOAT,   float)
+         ARRAYCASE(NPY_DOUBLE,  double)
+         ARRAYCASE(NPY_CFLOAT,  FloatComplex)
+         ARRAYCASE(NPY_CDOUBLE, Complex)
+         ARRAYCASE(NPY_BOOL,    bool)
+         ARRAYCASE(NPY_CHAR,    char)
+         ARRAYCASE(NPY_STRING,  char)
+         ARRAYCASE(NPY_OBJECT,  PyObject *)
 
          default:
             throw object_convert_exception(
@@ -224,22 +240,6 @@
       }
 
       switch (PyArray_TYPE (pyarr)) {
-         case NPY_UBYTE:
-         case NPY_USHORT:
-         case NPY_UINT:
-            switch (PyArray_ITEMSIZE (pyarr)) {
-               case 1:
-                  pyarrobj_to_octvalueNd<uint8NDArray>(octvalue, pyarr, dims);
-                  break;
-               case 2:
-                  pyarrobj_to_octvalueNd<uint16NDArray>(octvalue, pyarr, dims);
-                  break;
-               case 4:
-                  pyarrobj_to_octvalueNd<uint32NDArray>(octvalue, pyarr, dims);
-                  break;
-               default:
-                  throw object_convert_exception("Unknown unsigned integer.");
-            }
          case NPY_BYTE:
          case NPY_SHORT:
          case NPY_INT:
@@ -262,6 +262,28 @@
                   throw object_convert_exception("Unknown integer.");
             }
             break;
+         case NPY_UBYTE:
+         case NPY_USHORT:
+         case NPY_UINT:
+         case NPY_ULONG:
+         case NPY_ULONGLONG:
+            switch (PyArray_ITEMSIZE (pyarr)) {
+               case 1:
+                  pyarrobj_to_octvalueNd<uint8NDArray>(octvalue, pyarr, dims);
+                  break;
+               case 2:
+                  pyarrobj_to_octvalueNd<uint16NDArray>(octvalue, pyarr, dims);
+                  break;
+               case 4:
+                  pyarrobj_to_octvalueNd<uint32NDArray>(octvalue, pyarr, dims);
+                  break;
+               case 8:
+                  pyarrobj_to_octvalueNd<uint64NDArray>(octvalue, pyarr, dims);
+                  break;
+               default:
+                  throw object_convert_exception("Unknown unsigned integer.");
+            }
+            break;
          case NPY_FLOAT:
             pyarrobj_to_octvalueNd<FloatNDArray>(octvalue, pyarr, dims);
             break;
@@ -274,15 +296,15 @@
          case NPY_CDOUBLE:
             pyarrobj_to_octvalueNd<ComplexNDArray>(octvalue, pyarr, dims);
             break;
+         case NPY_BOOL:
+            pyarrobj_to_octvalueNd<boolNDArray>(octvalue, pyarr, dims);
+            break;
          case NPY_CHAR:
          case_NPY_CHAR:
             pyarrobj_to_octvalueNd<charNDArray>(octvalue, pyarr, dims);
             // FIXME: is the following needed?
             octvalue = octvalue.convert_to_str(true, true, '"');
             break;
-         case NPY_BOOL:
-            pyarrobj_to_octvalueNd<boolNDArray>(octvalue, pyarr, dims);
-            break;
          case NPY_STRING:
             {
                if (PyArray_ITEMSIZE (pyarr) == 1)