Mercurial > pytave
changeset 374:d362cdd1ddeb
pyobject: add conversion methods for single, intX, and uintX types
* oct-py-types.cc, oct-py-types.h (pytave::extract_py_uint64): New function.
* __py_struct_from_dict__.cc (F__py_uint64_scalar_value__): New function.
(F__py_int64_scalar_value__): Simplify and clean up style. Add %!tests.
* @pyobject/pyobject.m (pyobject.single, pyobject.int8, pyobject.int16,
pyobject.int32, pyobject.uint8, pyobject.uint16, pyobject.uint32,
pyobject.uint64): New conversion methods.
author | Mike Miller <mtmiller@octave.org> |
---|---|
date | Fri, 26 Aug 2016 18:51:42 -0700 |
parents | 0e4097c66788 |
children | d0a7f66393fc |
files | @pyobject/pyobject.m __py_struct_from_dict__.cc oct-py-types.cc oct-py-types.h |
diffstat | 4 files changed, 154 insertions(+), 17 deletions(-) [+] |
line wrap: on
line diff
--- a/@pyobject/pyobject.m Fri Aug 26 14:05:37 2016 -0700 +++ b/@pyobject/pyobject.m Fri Aug 26 18:51:42 2016 -0700 @@ -109,10 +109,42 @@ endif endfunction + function y = single (x) + y = single (double (x)); + endfunction + + function y = int8 (x) + y = int8 (__py_int64_scalar_value__ (x)); + endfunction + + function y = int16 (x) + y = int16 (__py_int64_scalar_value__ (x)); + endfunction + + function y = int32 (x) + y = int32 (__py_int64_scalar_value__ (x)); + endfunction + function y = int64 (x) y = __py_int64_scalar_value__ (x); endfunction + function y = uint8 (x) + y = uint8 (__py_uint64_scalar_value__ (x)); + endfunction + + function y = uint16 (x) + y = uint16 (__py_uint64_scalar_value__ (x)); + endfunction + + function y = uint32 (x) + y = uint32 (__py_uint64_scalar_value__ (x)); + endfunction + + function y = uint64 (x) + y = __py_uint64_scalar_value__ (x); + endfunction + function y = isa (x, typestr) assert (nargin == 2); assert (ischar (typestr) || iscellstr (typestr));
--- a/__py_struct_from_dict__.cc Fri Aug 26 14:05:37 2016 -0700 +++ b/__py_struct_from_dict__.cc Fri Aug 26 18:51:42 2016 -0700 @@ -71,48 +71,109 @@ DEFUN_DLD (__py_int64_scalar_value__, args, nargout, "-*- texinfo -*-\n\ -@deftypefn {} {} __py_int64_scalar_value__ (@var{x})\n\ +@deftypefn {} {} __py_int64_scalar_value__ (@var{x})\n\ Extract a scalar int64 value from the Python integer @var{x}.\n\ \n\ This is a private internal function not intended for direct use.\n\ @end deftypefn") { - octave_value_list retval; - - int nargin = args.length (); - if (nargin != 1) - { - print_usage (); - return retval; - } + if (args.length () != 1) + print_usage (); if (! (args(0).is_object () && args(0).class_name () == "pyobject")) error ("pyobject.int64: argument must be a Python object"); Py_Initialize (); + PyObject *obj = pytave::pyobject_unwrap_object (args(0)); + if (! obj) + error ("pyobject.int64: argument must be a valid Python object"); + + octave_int64 retval; + try { - // FIXME: PyObject *obj = look up stored pyobject reference (args(0)); - boost::python::object arg; - pytave::octvalue_to_pyobj (arg, args(0)); - PyObject *obj = arg.ptr (); - - retval(0) = octave_int64 (pytave::extract_py_int64 (obj)); + retval = pytave::extract_py_int64 (obj); } catch (pytave::object_convert_exception const &) { - error ("pyobject.int64: error in return value type conversion"); + error ("pyobject.int64: argument must be a Python int or long object"); } catch (boost::python::error_already_set const &) { std::string message = pytave::fetch_exception_message (); error ("pyobject.int64: %s", message.c_str ()); } + Py_DECREF (obj); - return retval; + return ovl (retval); } +/* +%!assert (__py_int64_scalar_value__ (pyobject (pyeval ("0"))), int64 (0)) +%!assert (__py_int64_scalar_value__ (pyobject (pyeval ("2**62"))), int64 (2^62)) +%!assert (__py_int64_scalar_value__ (pyobject (pyeval ("-2**62"))), int64 (-2^62)) +%!assert (__py_int64_scalar_value__ (pyobject (pyeval ("2**128"))), intmax ("int64")) +%!assert (__py_int64_scalar_value__ (pyobject (pyeval ("-2**128"))), intmin ("int64")) + +%!error __py_int64_scalar_value__ () +%!error __py_int64_scalar_value__ (1) +%!error __py_int64_scalar_value__ (pyeval ("None")) +%!error __py_int64_scalar_value__ (1, 2) +*/ + +DEFUN_DLD (__py_uint64_scalar_value__, args, nargout, + "-*- texinfo -*-\n\ +@deftypefn {} {} __py_uint64_scalar_value__ (@var{x})\n\ +Extract a scalar uint64 value from the Python integer @var{x}.\n\ +\n\ +This is a private internal function not intended for direct use.\n\ +@end deftypefn") +{ + if (args.length () != 1) + print_usage (); + + if (! (args(0).is_object () && args(0).class_name () == "pyobject")) + error ("pyobject.uint64: argument must be a Python object"); + + Py_Initialize (); + + PyObject *obj = pytave::pyobject_unwrap_object (args(0)); + if (! obj) + error ("pyobject.uint64: argument must be a valid Python object"); + + octave_uint64 retval; + + try + { + retval = pytave::extract_py_uint64 (obj); + } + catch (pytave::object_convert_exception const &) + { + error ("pyobject.uint64: argument must be a Python int or long object"); + } + catch (boost::python::error_already_set const &) + { + std::string message = pytave::fetch_exception_message (); + error ("pyobject.uint64: %s", message.c_str ()); + } + Py_DECREF (obj); + + return ovl (retval); +} + +/* +%!assert (__py_uint64_scalar_value__ (pyobject (pyeval ("0"))), uint64 (0)) +%!assert (__py_uint64_scalar_value__ (pyobject (pyeval ("2**62"))), uint64 (2^62)) +%!assert (__py_uint64_scalar_value__ (pyobject (pyeval ("2**128"))), intmax ("uint64")) +%!assert (__py_uint64_scalar_value__ (pyobject (pyeval ("-2**128"))), intmin ("uint64")) + +%!error __py_uint64_scalar_value__ () +%!error __py_uint64_scalar_value__ (1) +%!error __py_uint64_scalar_value__ (pyeval ("None")) +%!error __py_uint64_scalar_value__ (1, 2) +*/ + DEFUN_DLD (__py_is_none__, args, nargout, "-*- texinfo -*-\n\ @deftypefn {} {} __py_is_none__ (@var{x})\n\
--- a/oct-py-types.cc Fri Aug 26 14:05:37 2016 -0700 +++ b/oct-py-types.cc Fri Aug 26 18:51:42 2016 -0700 @@ -411,6 +411,43 @@ return 0; } +uint64_t +extract_py_uint64 (PyObject *obj) +{ + if (! obj) + throw object_convert_exception ("failed to extract integer: null object"); + + if (PyLong_Check (obj)) + { + // FIXME: if (value < 0), may be very implementation dependent + if (Py_SIZE (obj) < 0) + return 0; + +#if (defined (HAVE_LONG_LONG) && (SIZEOF_LONG_LONG == 8)) + unsigned PY_LONG_LONG value = PyLong_AsUnsignedLongLong (obj); + bool overflow = (value == static_cast<unsigned PY_LONG_LONG> (-1)); +#else + unsigned long value = PyLong_AsUnsignedLong (obj); + bool overflow = (value == static_cast<unsigned long> (-1)); +#endif + if (overflow) + { + value = std::numeric_limits<uint64_t>::max (); + PyErr_Clear (); + } + + return static_cast<uint64_t> (value); + } +#if PY_VERSION_HEX < 0x03000000 + else if (PyInt_Check (obj)) + return static_cast<uint64_t> (PyInt_AsLong (obj)); +#endif + else + throw object_convert_exception ("failed to extract integer: wrong type"); + + return 0; +} + PyObject * make_py_tuple (const Cell& cell) {
--- a/oct-py-types.h Fri Aug 26 14:05:37 2016 -0700 +++ b/oct-py-types.h Fri Aug 26 18:51:42 2016 -0700 @@ -103,6 +103,13 @@ int64_t extract_py_int64 (PyObject *obj); +//! Extract the integer value of the given Python int or long object. +//! +//! @param obj Python int or long object +//! @return integer value of @a obj +uint64_t +extract_py_uint64 (PyObject *obj); + //! Create a Python int object with the value of the given @c int32_t value. //! //! @param value integer value