mirror of
https://github.com/boostorg/python.git
synced 2026-01-23 05:42:30 +00:00
Added complex support, and support for user-defined conversions of classic instances
[SVN r12938]
This commit is contained in:
@@ -8,6 +8,7 @@
|
||||
# include <boost/python/detail/wrap_python.hpp>
|
||||
# include <boost/python/detail/none.hpp>
|
||||
# include <string>
|
||||
# include <complex>
|
||||
|
||||
namespace boost { namespace python {
|
||||
|
||||
@@ -58,6 +59,9 @@ BOOST_PYTHON_TO_PYTHON_BY_VALUE(float, PyFloat_FromDouble(x))
|
||||
BOOST_PYTHON_TO_PYTHON_BY_VALUE(double, PyFloat_FromDouble(x))
|
||||
BOOST_PYTHON_TO_PYTHON_BY_VALUE(long double, PyFloat_FromDouble(x))
|
||||
BOOST_PYTHON_TO_PYTHON_BY_VALUE(PyObject*, x ? x : detail::none())
|
||||
BOOST_PYTHON_TO_PYTHON_BY_VALUE(std::complex<float>, PyComplex_FromDoubles(x.real(), x.imag()))
|
||||
BOOST_PYTHON_TO_PYTHON_BY_VALUE(std::complex<double>, PyComplex_FromDoubles(x.real(), x.imag()))
|
||||
BOOST_PYTHON_TO_PYTHON_BY_VALUE(std::complex<long double>, PyComplex_FromDoubles(x.real(), x.imag()))
|
||||
|
||||
namespace converter
|
||||
{
|
||||
|
||||
@@ -10,8 +10,10 @@
|
||||
#include <boost/python/converter/from_python_data.hpp>
|
||||
#include <boost/python/converter/registry.hpp>
|
||||
#include <boost/python/reference.hpp>
|
||||
#include <boost/python/errors.hpp>
|
||||
#include <boost/cast.hpp>
|
||||
#include <string>
|
||||
#include <complex>
|
||||
|
||||
namespace boost { namespace python { namespace converter {
|
||||
|
||||
@@ -73,15 +75,18 @@ namespace
|
||||
|
||||
// For floating types, return the float conversion slot to avoid
|
||||
// creating a new object. We'll handle that below
|
||||
if (PyObject_TypeCheck(obj, &PyFloat_Type) && number_methods->nb_float)
|
||||
if (PyFloat_Check(obj))
|
||||
return &number_methods->nb_float;
|
||||
|
||||
|
||||
if (PyInstance_Check(obj) && !PyObject_HasAttrString(obj, "__int__"))
|
||||
return 0;
|
||||
|
||||
return &number_methods->nb_int;
|
||||
}
|
||||
|
||||
static long extract(PyObject* intermediate)
|
||||
{
|
||||
if (PyObject_TypeCheck(intermediate, &PyFloat_Type))
|
||||
if (PyFloat_Check(intermediate))
|
||||
{
|
||||
return numeric_cast<long>(PyFloat_AS_DOUBLE(intermediate));
|
||||
}
|
||||
@@ -93,22 +98,23 @@ namespace
|
||||
};
|
||||
|
||||
|
||||
// identity_unaryfunc/non_null -- manufacture a unaryfunc "slot"
|
||||
// which just returns its argument. Used for bool conversions, since
|
||||
// all Python objects are directly convertible to bool
|
||||
// identity_unaryfunc/py_object_identity -- manufacture a unaryfunc
|
||||
// "slot" which just returns its argument. Used for bool
|
||||
// conversions, since all Python objects are directly convertible to
|
||||
// bool
|
||||
extern "C" PyObject* identity_unaryfunc(PyObject* x)
|
||||
{
|
||||
Py_INCREF(x);
|
||||
return x;
|
||||
}
|
||||
unaryfunc non_null = identity_unaryfunc;
|
||||
unaryfunc py_object_identity = identity_unaryfunc;
|
||||
|
||||
// A SlotPolicy for extracting bool from a Python object
|
||||
struct bool_rvalue_from_python
|
||||
{
|
||||
static unaryfunc* get_slot(PyObject*)
|
||||
{
|
||||
return &non_null;
|
||||
return &py_object_identity;
|
||||
}
|
||||
|
||||
static bool extract(PyObject* intermediate)
|
||||
@@ -127,17 +133,19 @@ namespace
|
||||
return 0;
|
||||
|
||||
// For integer types, return the tp_int conversion slot to avoid
|
||||
// creating a new object. We'll handle that in
|
||||
// py_float_or_int_as_double, below
|
||||
if (PyObject_TypeCheck(obj, &PyInt_Type) && number_methods->nb_int)
|
||||
// creating a new object. We'll handle that below
|
||||
if (PyInt_Check(obj))
|
||||
return &number_methods->nb_int;
|
||||
|
||||
if (PyInstance_Check(obj) && !PyObject_HasAttrString(obj, "__float__"))
|
||||
return 0;
|
||||
|
||||
return &number_methods->nb_float;
|
||||
}
|
||||
|
||||
static double extract(PyObject* intermediate)
|
||||
{
|
||||
if (PyObject_TypeCheck(intermediate, &PyInt_Type))
|
||||
if (PyInt_Check(intermediate))
|
||||
{
|
||||
return PyInt_AS_LONG(intermediate);
|
||||
}
|
||||
@@ -154,6 +162,9 @@ namespace
|
||||
// If the underlying object is "string-able" this will succeed
|
||||
static unaryfunc* get_slot(PyObject* obj)
|
||||
{
|
||||
if (PyInstance_Check(obj) && !PyObject_HasAttrString(obj, "__str__"))
|
||||
return 0;
|
||||
|
||||
return &obj->ob_type->tp_str;
|
||||
};
|
||||
|
||||
@@ -163,6 +174,64 @@ namespace
|
||||
return PyString_AsString(intermediate);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// identity_unaryfunc/non_null -- manufacture a unaryfunc "slot"
|
||||
// which just returns its argument. Used for bool conversions, since
|
||||
// all Python objects are directly convertible to bool
|
||||
extern "C" PyObject* to_complex_unaryfunc(PyObject* x)
|
||||
{
|
||||
return PyObject_CallMethod(x, "__complex__", const_cast<char*>("()"));
|
||||
}
|
||||
unaryfunc py_object_to_complex = to_complex_unaryfunc;
|
||||
|
||||
struct complex_rvalue_from_python
|
||||
{
|
||||
static unaryfunc* get_slot(PyObject* obj)
|
||||
{
|
||||
|
||||
if (PyComplex_Check(obj))
|
||||
return &py_object_identity;
|
||||
|
||||
PyNumberMethods* number_methods = obj->ob_type->tp_as_number;
|
||||
|
||||
// For integer types, return the tp_int conversion slot to avoid
|
||||
// creating a new object. We'll handle that below
|
||||
if (PyInt_Check(obj) && number_methods)
|
||||
return &number_methods->nb_int;
|
||||
|
||||
if (PyFloat_Check(obj) && number_methods)
|
||||
return &number_methods->nb_float;
|
||||
|
||||
if (!PyObject_HasAttrString((PyObject*)obj, "__complex__"))
|
||||
return 0;
|
||||
|
||||
return &py_object_to_complex;
|
||||
}
|
||||
|
||||
static std::complex<double> extract(PyObject* intermediate)
|
||||
{
|
||||
if (PyComplex_Check(intermediate))
|
||||
{
|
||||
return std::complex<double>(
|
||||
PyComplex_RealAsDouble(intermediate)
|
||||
, PyComplex_ImagAsDouble(intermediate));
|
||||
}
|
||||
else if (PyInt_Check(intermediate))
|
||||
{
|
||||
return PyInt_AS_LONG(intermediate);
|
||||
}
|
||||
else if (PyFloat_Check(intermediate))
|
||||
{
|
||||
return PyFloat_AS_DOUBLE(intermediate);
|
||||
}
|
||||
else
|
||||
{
|
||||
PyErr_SetString(PyExc_TypeError, "__complex__ method did not return a Complex object");
|
||||
throw error_already_set();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#define REGISTER_INT_CONVERTERS(U) slot_rvalue_from_python<U,int_rvalue_from_python>()
|
||||
@@ -184,6 +253,10 @@ void initialize_builtin_converters()
|
||||
slot_rvalue_from_python<double,float_rvalue_from_python>();
|
||||
slot_rvalue_from_python<long double,float_rvalue_from_python>();
|
||||
|
||||
slot_rvalue_from_python<std::complex<float>,complex_rvalue_from_python>();
|
||||
slot_rvalue_from_python<std::complex<double>,complex_rvalue_from_python>();
|
||||
slot_rvalue_from_python<std::complex<long double>,complex_rvalue_from_python>();
|
||||
|
||||
// Add an lvalue converter for char which gets us char const*
|
||||
registry::insert(convert_to_cstring,undecorated_type_id<char>());
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
// to its suitability for any purpose.
|
||||
#include <string>
|
||||
#include <boost/python/module.hpp>
|
||||
|
||||
#include <complex>
|
||||
|
||||
template <class T>
|
||||
struct by_value
|
||||
@@ -41,6 +41,9 @@ BOOST_PYTHON_MODULE_INIT(builtin_converters_ext)
|
||||
.def("rewrap_value_float", by_value<float>::rewrap)
|
||||
.def("rewrap_value_double", by_value<double>::rewrap)
|
||||
.def("rewrap_value_long_double", by_value<long double>::rewrap)
|
||||
.def("rewrap_value_complex_float", by_value<std::complex<float> >::rewrap)
|
||||
.def("rewrap_value_complex_double", by_value<std::complex<double> >::rewrap)
|
||||
.def("rewrap_value_complex_long_double", by_value<std::complex<long double> >::rewrap)
|
||||
.def("rewrap_value_string", by_value<std::string>::rewrap)
|
||||
.def("rewrap_value_cstring", by_value<char const*>::rewrap)
|
||||
|
||||
@@ -57,6 +60,9 @@ BOOST_PYTHON_MODULE_INIT(builtin_converters_ext)
|
||||
.def("rewrap_const_reference_float", by_const_reference<float>::rewrap)
|
||||
.def("rewrap_const_reference_double", by_const_reference<double>::rewrap)
|
||||
.def("rewrap_const_reference_long_double", by_const_reference<long double>::rewrap)
|
||||
.def("rewrap_const_reference_complex_float", by_const_reference<std::complex<float> >::rewrap)
|
||||
.def("rewrap_const_reference_complex_double", by_const_reference<std::complex<double> >::rewrap)
|
||||
.def("rewrap_const_reference_complex_long_double", by_const_reference<std::complex<long double> >::rewrap)
|
||||
.def("rewrap_const_reference_string", by_const_reference<std::string>::rewrap)
|
||||
.def("rewrap_const_reference_cstring", by_const_reference<char const*>::rewrap)
|
||||
|
||||
|
||||
@@ -30,6 +30,13 @@
|
||||
>>> rewrap_value_long_double(4.2) - 4.2
|
||||
0.0
|
||||
|
||||
>>> abs(rewrap_value_complex_float(4+.2j) - (4+.2j)) < .000001
|
||||
1
|
||||
>>> abs(rewrap_value_complex_double(4+.2j) - (4+.2j)) < .000001
|
||||
1
|
||||
>>> abs(rewrap_value_complex_long_double(4+.2j) - (4+.2j)) < .000001
|
||||
1
|
||||
|
||||
>>> rewrap_value_cstring('hello, world')
|
||||
'hello, world'
|
||||
>>> rewrap_value_string('yo, wassup?')
|
||||
@@ -57,6 +64,7 @@
|
||||
42
|
||||
>>> rewrap_const_reference_unsigned_long(42)
|
||||
42
|
||||
|
||||
>>> abs(rewrap_const_reference_float(4.2) - 4.2) < .000001
|
||||
1
|
||||
>>> rewrap_const_reference_double(4.2) - 4.2
|
||||
@@ -64,6 +72,13 @@
|
||||
>>> rewrap_const_reference_long_double(4.2) - 4.2
|
||||
0.0
|
||||
|
||||
>>> abs(rewrap_const_reference_complex_float(4+.2j) - (4+.2j)) < .000001
|
||||
1
|
||||
>>> abs(rewrap_const_reference_complex_double(4+.2j) - (4+.2j)) < .000001
|
||||
1
|
||||
>>> abs(rewrap_const_reference_complex_long_double(4+.2j) - (4+.2j)) < .000001
|
||||
1
|
||||
|
||||
>>> rewrap_const_reference_cstring('hello, world')
|
||||
'hello, world'
|
||||
>>> rewrap_const_reference_string('yo, wassup?')
|
||||
@@ -83,6 +98,27 @@ Now check implicit conversions between floating/integer types
|
||||
>>> rewrap_value_int(42.0)
|
||||
42
|
||||
|
||||
Check that classic classes also work
|
||||
|
||||
>>> class FortyTwo:
|
||||
... def __int__(self):
|
||||
... return 42
|
||||
... def __float__(self):
|
||||
... return 42.0
|
||||
... def __complex__(self):
|
||||
... return complex(4+.2j)
|
||||
... def __str__(self):
|
||||
... return '42'
|
||||
|
||||
>>> rewrap_const_reference_float(FortyTwo())
|
||||
42.0
|
||||
>>> rewrap_value_int(FortyTwo())
|
||||
42
|
||||
>>> rewrap_const_reference_string(FortyTwo())
|
||||
'42'
|
||||
>>> abs(rewrap_value_complex_double(FortyTwo()) - (4+.2j)) < .000001
|
||||
1
|
||||
|
||||
"""
|
||||
def run(args = None):
|
||||
import sys
|
||||
|
||||
Reference in New Issue
Block a user