2
0
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:
Dave Abrahams
2002-02-25 21:20:05 +00:00
parent e014765797
commit f6381e7e5e
4 changed files with 132 additions and 13 deletions

View File

@@ -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
{

View File

@@ -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>());

View File

@@ -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)

View File

@@ -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