mirror of
https://github.com/saitohirga/WSJT-X.git
synced 2026-07-30 14:04:12 -04:00
Merge commit '4ebe6417a5fce5f0994fc0c31bebf732be96a07c' as 'boost'
This commit is contained in:
@@ -0,0 +1,28 @@
|
||||
// Copyright David Abrahams 2002.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/python/converter/arg_to_python_base.hpp>
|
||||
#include <boost/python/errors.hpp>
|
||||
#include <boost/python/converter/registrations.hpp>
|
||||
#include <boost/python/handle.hpp>
|
||||
#include <boost/python/refcount.hpp>
|
||||
|
||||
namespace boost { namespace python { namespace converter {
|
||||
|
||||
namespace detail
|
||||
{
|
||||
arg_to_python_base::arg_to_python_base(
|
||||
void const volatile* source, registration const& converters)
|
||||
# if !defined(BOOST_MSVC) || BOOST_MSVC <= 1300 || _MSC_FULL_VER > 13102179
|
||||
: handle<>
|
||||
# else
|
||||
: m_ptr
|
||||
# endif
|
||||
(converters.to_python(source))
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
}}} // namespace boost::python::converter
|
||||
@@ -0,0 +1,570 @@
|
||||
// Copyright David Abrahams 2002.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/python/handle.hpp>
|
||||
#include <boost/python/type_id.hpp>
|
||||
#include <boost/python/errors.hpp>
|
||||
#include <boost/python/refcount.hpp>
|
||||
|
||||
#include <boost/python/detail/config.hpp>
|
||||
#include <boost/python/detail/wrap_python.hpp>
|
||||
|
||||
#include <boost/python/converter/builtin_converters.hpp>
|
||||
#include <boost/python/converter/rvalue_from_python_data.hpp>
|
||||
#include <boost/python/converter/registry.hpp>
|
||||
#include <boost/python/converter/registrations.hpp>
|
||||
#include <boost/python/converter/shared_ptr_deleter.hpp>
|
||||
#include <boost/python/converter/pytype_function.hpp>
|
||||
|
||||
#include <boost/cast.hpp>
|
||||
#include <string>
|
||||
#include <complex>
|
||||
|
||||
namespace boost { namespace python { namespace converter {
|
||||
|
||||
shared_ptr_deleter::shared_ptr_deleter(handle<> owner)
|
||||
: owner(owner)
|
||||
{}
|
||||
|
||||
shared_ptr_deleter::~shared_ptr_deleter() {}
|
||||
|
||||
void shared_ptr_deleter::operator()(void const*)
|
||||
{
|
||||
owner.reset();
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
// An lvalue conversion function which extracts a char const* from a
|
||||
// Python String.
|
||||
#if PY_VERSION_HEX < 0x03000000
|
||||
void* convert_to_cstring(PyObject* obj)
|
||||
{
|
||||
return PyString_Check(obj) ? PyString_AsString(obj) : 0;
|
||||
}
|
||||
#else
|
||||
void* convert_to_cstring(PyObject* obj)
|
||||
{
|
||||
return PyUnicode_Check(obj) ? _PyUnicode_AsString(obj) : 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Given a target type and a SlotPolicy describing how to perform a
|
||||
// given conversion, registers from_python converters which use the
|
||||
// SlotPolicy to extract the type.
|
||||
template <class T, class SlotPolicy>
|
||||
struct slot_rvalue_from_python
|
||||
{
|
||||
public:
|
||||
slot_rvalue_from_python()
|
||||
{
|
||||
registry::insert(
|
||||
&slot_rvalue_from_python<T,SlotPolicy>::convertible
|
||||
, &slot_rvalue_from_python<T,SlotPolicy>::construct
|
||||
, type_id<T>()
|
||||
, &SlotPolicy::get_pytype
|
||||
);
|
||||
}
|
||||
|
||||
private:
|
||||
static void* convertible(PyObject* obj)
|
||||
{
|
||||
unaryfunc* slot = SlotPolicy::get_slot(obj);
|
||||
return slot && *slot ? slot : 0;
|
||||
}
|
||||
|
||||
static void construct(PyObject* obj, rvalue_from_python_stage1_data* data)
|
||||
{
|
||||
// Get the (intermediate) source object
|
||||
unaryfunc creator = *static_cast<unaryfunc*>(data->convertible);
|
||||
handle<> intermediate(creator(obj));
|
||||
|
||||
// Get the location in which to construct
|
||||
void* storage = ((rvalue_from_python_storage<T>*)data)->storage.bytes;
|
||||
# ifdef _MSC_VER
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable:4244)
|
||||
# endif
|
||||
new (storage) T( SlotPolicy::extract(intermediate.get()) );
|
||||
|
||||
# ifdef _MSC_VER
|
||||
# pragma warning(pop)
|
||||
# endif
|
||||
// record successful construction
|
||||
data->convertible = storage;
|
||||
}
|
||||
};
|
||||
|
||||
// identity_unaryfunc/py_object_identity -- manufacture a unaryfunc
|
||||
// "slot" which just returns its argument.
|
||||
extern "C" PyObject* identity_unaryfunc(PyObject* x)
|
||||
{
|
||||
Py_INCREF(x);
|
||||
return x;
|
||||
}
|
||||
unaryfunc py_object_identity = identity_unaryfunc;
|
||||
|
||||
#if PY_VERSION_HEX >= 0x03000000
|
||||
// As in Python 3 there is only one integer type, we can have much
|
||||
// simplified logic.
|
||||
// XXX(bhy) maybe the code will work with 2.6 or even 2.5?
|
||||
struct int_rvalue_from_python_base
|
||||
{
|
||||
static unaryfunc* get_slot(PyObject* obj)
|
||||
{
|
||||
return PyLong_Check(obj) ? &py_object_identity : 0;
|
||||
}
|
||||
static PyTypeObject const* get_pytype() {return &PyLong_Type;}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct signed_int_rvalue_from_python : int_rvalue_from_python_base
|
||||
{
|
||||
static T extract(PyObject* intermediate)
|
||||
{
|
||||
long x = PyLong_AsLong(intermediate);
|
||||
if (PyErr_Occurred())
|
||||
throw_error_already_set();
|
||||
return numeric_cast<T>(x);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct unsigned_int_rvalue_from_python : int_rvalue_from_python_base
|
||||
{
|
||||
static T extract(PyObject* intermediate)
|
||||
{
|
||||
unsigned long x = PyLong_AsUnsignedLong(intermediate);
|
||||
if (PyErr_Occurred())
|
||||
throw_error_already_set();
|
||||
return numeric_cast<T>(x);
|
||||
}
|
||||
};
|
||||
#else // PY_VERSION_HEX >= 0x03000000
|
||||
// A SlotPolicy for extracting signed integer types from Python objects
|
||||
struct signed_int_rvalue_from_python_base
|
||||
{
|
||||
static unaryfunc* get_slot(PyObject* obj)
|
||||
{
|
||||
PyNumberMethods* number_methods = obj->ob_type->tp_as_number;
|
||||
if (number_methods == 0)
|
||||
return 0;
|
||||
|
||||
return (
|
||||
#if PY_VERSION_HEX >= 0x02040000 && defined(BOOST_PYTHON_BOOL_INT_STRICT)
|
||||
!PyBool_Check(obj) &&
|
||||
#endif
|
||||
(PyInt_Check(obj) || PyLong_Check(obj)))
|
||||
|
||||
? &number_methods->nb_int : 0;
|
||||
}
|
||||
static PyTypeObject const* get_pytype() { return &PyInt_Type;}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct signed_int_rvalue_from_python : signed_int_rvalue_from_python_base
|
||||
{
|
||||
static T extract(PyObject* intermediate)
|
||||
{
|
||||
long x = PyInt_AsLong(intermediate);
|
||||
if (PyErr_Occurred())
|
||||
throw_error_already_set();
|
||||
return numeric_cast<T>(x);
|
||||
}
|
||||
};
|
||||
|
||||
// A SlotPolicy for extracting unsigned integer types from Python objects
|
||||
struct unsigned_int_rvalue_from_python_base
|
||||
{
|
||||
static unaryfunc* get_slot(PyObject* obj)
|
||||
{
|
||||
PyNumberMethods* number_methods = obj->ob_type->tp_as_number;
|
||||
if (number_methods == 0)
|
||||
return 0;
|
||||
|
||||
return (
|
||||
#if PY_VERSION_HEX >= 0x02040000 && defined(BOOST_PYTHON_BOOL_INT_STRICT)
|
||||
!PyBool_Check(obj) &&
|
||||
#endif
|
||||
(PyInt_Check(obj) || PyLong_Check(obj)))
|
||||
? &py_object_identity : 0;
|
||||
}
|
||||
static PyTypeObject const* get_pytype() { return &PyInt_Type;}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct unsigned_int_rvalue_from_python : unsigned_int_rvalue_from_python_base
|
||||
{
|
||||
static T extract(PyObject* intermediate)
|
||||
{
|
||||
if (PyLong_Check(intermediate)) {
|
||||
// PyLong_AsUnsignedLong() checks for negative overflow, so no
|
||||
// need to check it here.
|
||||
unsigned long result = PyLong_AsUnsignedLong(intermediate);
|
||||
if (PyErr_Occurred())
|
||||
throw_error_already_set();
|
||||
return numeric_cast<T>(result);
|
||||
} else {
|
||||
// None of PyInt_AsUnsigned*() functions check for negative
|
||||
// overflow, so use PyInt_AS_LONG instead and check if number is
|
||||
// negative, issuing the exception appropriately.
|
||||
long result = PyInt_AS_LONG(intermediate);
|
||||
if (PyErr_Occurred())
|
||||
throw_error_already_set();
|
||||
if (result < 0) {
|
||||
PyErr_SetString(PyExc_OverflowError, "can't convert negative"
|
||||
" value to unsigned");
|
||||
throw_error_already_set();
|
||||
}
|
||||
return numeric_cast<T>(result);
|
||||
}
|
||||
}
|
||||
};
|
||||
#endif // PY_VERSION_HEX >= 0x03000000
|
||||
|
||||
// Checking Python's macro instead of Boost's - we don't seem to get
|
||||
// the config right all the time. Furthermore, Python's is defined
|
||||
// when long long is absent but __int64 is present.
|
||||
|
||||
#ifdef HAVE_LONG_LONG
|
||||
// A SlotPolicy for extracting long long types from Python objects
|
||||
|
||||
struct long_long_rvalue_from_python_base
|
||||
{
|
||||
static unaryfunc* get_slot(PyObject* obj)
|
||||
{
|
||||
#if PY_VERSION_HEX >= 0x03000000
|
||||
return PyLong_Check(obj) ? &py_object_identity : 0;
|
||||
#else
|
||||
PyNumberMethods* number_methods = obj->ob_type->tp_as_number;
|
||||
if (number_methods == 0)
|
||||
return 0;
|
||||
|
||||
// Return the identity conversion slot to avoid creating a
|
||||
// new object. We'll handle that in the extract function
|
||||
if (PyInt_Check(obj))
|
||||
return &number_methods->nb_int;
|
||||
else if (PyLong_Check(obj))
|
||||
return &number_methods->nb_long;
|
||||
else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
static PyTypeObject const* get_pytype() { return &PyLong_Type;}
|
||||
};
|
||||
|
||||
struct long_long_rvalue_from_python : long_long_rvalue_from_python_base
|
||||
{
|
||||
static BOOST_PYTHON_LONG_LONG extract(PyObject* intermediate)
|
||||
{
|
||||
#if PY_VERSION_HEX < 0x03000000
|
||||
if (PyInt_Check(intermediate))
|
||||
{
|
||||
return PyInt_AS_LONG(intermediate);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
BOOST_PYTHON_LONG_LONG result = PyLong_AsLongLong(intermediate);
|
||||
|
||||
if (PyErr_Occurred())
|
||||
throw_error_already_set();
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct unsigned_long_long_rvalue_from_python : long_long_rvalue_from_python_base
|
||||
{
|
||||
static unsigned BOOST_PYTHON_LONG_LONG extract(PyObject* intermediate)
|
||||
{
|
||||
#if PY_VERSION_HEX < 0x03000000
|
||||
if (PyInt_Check(intermediate))
|
||||
{
|
||||
return numeric_cast<unsigned BOOST_PYTHON_LONG_LONG>(PyInt_AS_LONG(intermediate));
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
unsigned BOOST_PYTHON_LONG_LONG result = PyLong_AsUnsignedLongLong(intermediate);
|
||||
|
||||
if (PyErr_Occurred())
|
||||
throw_error_already_set();
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
// A SlotPolicy for extracting bool from a Python object
|
||||
struct bool_rvalue_from_python
|
||||
{
|
||||
static unaryfunc* get_slot(PyObject* obj)
|
||||
{
|
||||
#if PY_VERSION_HEX >= 0x03000000
|
||||
return obj == Py_None || PyLong_Check(obj) ? &py_object_identity : 0;
|
||||
#elif PY_VERSION_HEX >= 0x02040000 && defined(BOOST_PYTHON_BOOL_INT_STRICT)
|
||||
return obj == Py_None || PyBool_Check(obj) ? &py_object_identity : 0;
|
||||
#else
|
||||
return obj == Py_None || PyInt_Check(obj) ? &py_object_identity : 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool extract(PyObject* intermediate)
|
||||
{
|
||||
return PyObject_IsTrue(intermediate);
|
||||
}
|
||||
|
||||
static PyTypeObject const* get_pytype()
|
||||
{
|
||||
#if PY_VERSION_HEX >= 0x02030000
|
||||
return &PyBool_Type;
|
||||
#else
|
||||
return &PyInt_Type;
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
// A SlotPolicy for extracting floating types from Python objects.
|
||||
struct float_rvalue_from_python
|
||||
{
|
||||
static unaryfunc* get_slot(PyObject* obj)
|
||||
{
|
||||
PyNumberMethods* number_methods = obj->ob_type->tp_as_number;
|
||||
if (number_methods == 0)
|
||||
return 0;
|
||||
|
||||
// For integer types, return the tp_int conversion slot to avoid
|
||||
// creating a new object. We'll handle that below
|
||||
#if PY_VERSION_HEX < 0x03000000
|
||||
if (PyInt_Check(obj))
|
||||
return &number_methods->nb_int;
|
||||
#endif
|
||||
|
||||
return (PyLong_Check(obj) || PyFloat_Check(obj))
|
||||
? &number_methods->nb_float : 0;
|
||||
}
|
||||
|
||||
static double extract(PyObject* intermediate)
|
||||
{
|
||||
#if PY_VERSION_HEX < 0x03000000
|
||||
if (PyInt_Check(intermediate))
|
||||
{
|
||||
return PyInt_AS_LONG(intermediate);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
return PyFloat_AS_DOUBLE(intermediate);
|
||||
}
|
||||
}
|
||||
static PyTypeObject const* get_pytype() { return &PyFloat_Type;}
|
||||
};
|
||||
|
||||
#if PY_VERSION_HEX >= 0x03000000
|
||||
unaryfunc py_unicode_as_string_unaryfunc = PyUnicode_AsUTF8String;
|
||||
#endif
|
||||
|
||||
// A SlotPolicy for extracting C++ strings from Python objects.
|
||||
struct string_rvalue_from_python
|
||||
{
|
||||
// If the underlying object is "string-able" this will succeed
|
||||
static unaryfunc* get_slot(PyObject* obj)
|
||||
{
|
||||
#if PY_VERSION_HEX >= 0x03000000
|
||||
return (PyUnicode_Check(obj)) ? &py_unicode_as_string_unaryfunc :
|
||||
PyBytes_Check(obj) ? &py_object_identity : 0;
|
||||
#else
|
||||
return (PyString_Check(obj)) ? &obj->ob_type->tp_str : 0;
|
||||
|
||||
#endif
|
||||
};
|
||||
|
||||
// Remember that this will be used to construct the result object
|
||||
#if PY_VERSION_HEX >= 0x03000000
|
||||
static std::string extract(PyObject* intermediate)
|
||||
{
|
||||
return std::string(PyBytes_AsString(intermediate),PyBytes_Size(intermediate));
|
||||
}
|
||||
static PyTypeObject const* get_pytype() { return &PyUnicode_Type;}
|
||||
#else
|
||||
static std::string extract(PyObject* intermediate)
|
||||
{
|
||||
return std::string(PyString_AsString(intermediate),PyString_Size(intermediate));
|
||||
}
|
||||
static PyTypeObject const* get_pytype() { return &PyString_Type;}
|
||||
#endif
|
||||
};
|
||||
|
||||
#if defined(Py_USING_UNICODE) && !defined(BOOST_NO_STD_WSTRING)
|
||||
// encode_string_unaryfunc/py_encode_string -- manufacture a unaryfunc
|
||||
// "slot" which encodes a Python string using the default encoding
|
||||
extern "C" PyObject* encode_string_unaryfunc(PyObject* x)
|
||||
{
|
||||
return PyUnicode_FromEncodedObject( x, 0, 0 );
|
||||
}
|
||||
unaryfunc py_encode_string = encode_string_unaryfunc;
|
||||
|
||||
// A SlotPolicy for extracting C++ strings from Python objects.
|
||||
struct wstring_rvalue_from_python
|
||||
{
|
||||
// If the underlying object is "string-able" this will succeed
|
||||
static unaryfunc* get_slot(PyObject* obj)
|
||||
{
|
||||
return PyUnicode_Check(obj)
|
||||
? &py_object_identity
|
||||
#if PY_VERSION_HEX >= 0x03000000
|
||||
: PyBytes_Check(obj)
|
||||
#else
|
||||
: PyString_Check(obj)
|
||||
#endif
|
||||
? &py_encode_string
|
||||
: 0;
|
||||
};
|
||||
|
||||
// Remember that this will be used to construct the result object
|
||||
static std::wstring extract(PyObject* intermediate)
|
||||
{
|
||||
std::wstring result(::PyObject_Length(intermediate), L' ');
|
||||
if (!result.empty())
|
||||
{
|
||||
int err = PyUnicode_AsWideChar(
|
||||
#if PY_VERSION_HEX < 0x03020000
|
||||
(PyUnicodeObject *)
|
||||
#endif
|
||||
intermediate
|
||||
, &result[0]
|
||||
, result.size());
|
||||
|
||||
if (err == -1)
|
||||
throw_error_already_set();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
static PyTypeObject const* get_pytype() { return &PyUnicode_Type;}
|
||||
};
|
||||
#endif
|
||||
|
||||
struct complex_rvalue_from_python
|
||||
{
|
||||
static unaryfunc* get_slot(PyObject* obj)
|
||||
{
|
||||
if (PyComplex_Check(obj))
|
||||
return &py_object_identity;
|
||||
else
|
||||
return float_rvalue_from_python::get_slot(obj);
|
||||
}
|
||||
|
||||
static std::complex<double> extract(PyObject* intermediate)
|
||||
{
|
||||
if (PyComplex_Check(intermediate))
|
||||
{
|
||||
return std::complex<double>(
|
||||
PyComplex_RealAsDouble(intermediate)
|
||||
, PyComplex_ImagAsDouble(intermediate));
|
||||
}
|
||||
#if PY_VERSION_HEX < 0x03000000
|
||||
else if (PyInt_Check(intermediate))
|
||||
{
|
||||
return PyInt_AS_LONG(intermediate);
|
||||
}
|
||||
#endif
|
||||
else
|
||||
{
|
||||
return PyFloat_AS_DOUBLE(intermediate);
|
||||
}
|
||||
}
|
||||
static PyTypeObject const* get_pytype() { return &PyComplex_Type;}
|
||||
};
|
||||
}
|
||||
|
||||
BOOST_PYTHON_DECL PyObject* do_return_to_python(char x)
|
||||
{
|
||||
#if PY_VERSION_HEX >= 0x03000000
|
||||
return PyUnicode_FromStringAndSize(&x, 1);
|
||||
#else
|
||||
return PyString_FromStringAndSize(&x, 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
BOOST_PYTHON_DECL PyObject* do_return_to_python(char const* x)
|
||||
{
|
||||
#if PY_VERSION_HEX >= 0x03000000
|
||||
return x ? PyUnicode_FromString(x) : boost::python::detail::none();
|
||||
#else
|
||||
return x ? PyString_FromString(x) : boost::python::detail::none();
|
||||
#endif
|
||||
}
|
||||
|
||||
BOOST_PYTHON_DECL PyObject* do_return_to_python(PyObject* x)
|
||||
{
|
||||
return x ? x : boost::python::detail::none();
|
||||
}
|
||||
|
||||
BOOST_PYTHON_DECL PyObject* do_arg_to_python(PyObject* x)
|
||||
{
|
||||
if (x == 0)
|
||||
return boost::python::detail::none();
|
||||
|
||||
Py_INCREF(x);
|
||||
return x;
|
||||
}
|
||||
|
||||
#define REGISTER_INT_CONVERTERS(signedness, U) \
|
||||
slot_rvalue_from_python< \
|
||||
signedness U \
|
||||
,signedness##_int_rvalue_from_python<signedness U> \
|
||||
>()
|
||||
|
||||
#define REGISTER_INT_CONVERTERS2(U) \
|
||||
REGISTER_INT_CONVERTERS(signed, U); \
|
||||
REGISTER_INT_CONVERTERS(unsigned, U)
|
||||
|
||||
void initialize_builtin_converters()
|
||||
{
|
||||
// booleans
|
||||
slot_rvalue_from_python<bool,bool_rvalue_from_python>();
|
||||
|
||||
// integer types
|
||||
REGISTER_INT_CONVERTERS2(char);
|
||||
REGISTER_INT_CONVERTERS2(short);
|
||||
REGISTER_INT_CONVERTERS2(int);
|
||||
REGISTER_INT_CONVERTERS2(long);
|
||||
|
||||
// using Python's macro instead of Boost's - we don't seem to get the
|
||||
// config right all the time.
|
||||
# ifdef HAVE_LONG_LONG
|
||||
slot_rvalue_from_python<signed BOOST_PYTHON_LONG_LONG,long_long_rvalue_from_python>();
|
||||
slot_rvalue_from_python<unsigned BOOST_PYTHON_LONG_LONG,unsigned_long_long_rvalue_from_python>();
|
||||
# endif
|
||||
|
||||
// floating types
|
||||
slot_rvalue_from_python<float,float_rvalue_from_python>();
|
||||
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*
|
||||
#if PY_VERSION_HEX < 0x03000000
|
||||
registry::insert(convert_to_cstring,type_id<char>(),&converter::wrap_pytype<&PyString_Type>::get_pytype);
|
||||
#else
|
||||
registry::insert(convert_to_cstring,type_id<char>(),&converter::wrap_pytype<&PyUnicode_Type>::get_pytype);
|
||||
#endif
|
||||
|
||||
// Register by-value converters to std::string, std::wstring
|
||||
#if defined(Py_USING_UNICODE) && !defined(BOOST_NO_STD_WSTRING)
|
||||
slot_rvalue_from_python<std::wstring, wstring_rvalue_from_python>();
|
||||
# endif
|
||||
slot_rvalue_from_python<std::string, string_rvalue_from_python>();
|
||||
|
||||
}
|
||||
|
||||
}}} // namespace boost::python::converter
|
||||
@@ -0,0 +1,303 @@
|
||||
// Copyright David Abrahams 2002.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/python/converter/from_python.hpp>
|
||||
#include <boost/python/converter/registrations.hpp>
|
||||
#include <boost/python/converter/rvalue_from_python_data.hpp>
|
||||
|
||||
#include <boost/python/object/find_instance.hpp>
|
||||
|
||||
#include <boost/python/handle.hpp>
|
||||
#include <boost/python/detail/raw_pyobject.hpp>
|
||||
#include <boost/python/cast.hpp>
|
||||
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
namespace boost { namespace python { namespace converter {
|
||||
|
||||
// rvalue_from_python_stage1 -- do the first stage of a conversion
|
||||
// from a Python object to a C++ rvalue.
|
||||
//
|
||||
// source - the Python object to be converted
|
||||
// converters - the registry entry for the target type T
|
||||
//
|
||||
// Postcondition: where x is the result, one of:
|
||||
//
|
||||
// 1. x.convertible == 0, indicating failure
|
||||
//
|
||||
// 2. x.construct == 0, x.convertible is the address of an object of
|
||||
// type T. Indicates a successful lvalue conversion
|
||||
//
|
||||
// 3. where y is of type rvalue_from_python_data<T>,
|
||||
// x.construct(source, y) constructs an object of type T
|
||||
// in y.storage.bytes and then sets y.convertible == y.storage.bytes,
|
||||
// or else throws an exception and has no effect.
|
||||
BOOST_PYTHON_DECL rvalue_from_python_stage1_data rvalue_from_python_stage1(
|
||||
PyObject* source
|
||||
, registration const& converters)
|
||||
{
|
||||
rvalue_from_python_stage1_data data;
|
||||
|
||||
// First check to see if it's embedded in an extension class
|
||||
// instance, as a special case.
|
||||
data.convertible = objects::find_instance_impl(source, converters.target_type, converters.is_shared_ptr);
|
||||
data.construct = 0;
|
||||
if (!data.convertible)
|
||||
{
|
||||
for (rvalue_from_python_chain const* chain = converters.rvalue_chain;
|
||||
chain != 0;
|
||||
chain = chain->next)
|
||||
{
|
||||
void* r = chain->convertible(source);
|
||||
if (r != 0)
|
||||
{
|
||||
data.convertible = r;
|
||||
data.construct = chain->construct;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
// rvalue_result_from_python -- return the address of a C++ object which
|
||||
// can be used as the result of calling a Python function.
|
||||
//
|
||||
// src - the Python object to be converted
|
||||
//
|
||||
// data - a reference to the base part of a
|
||||
// rvalue_from_python_data<T> object, where T is the
|
||||
// target type of the conversion.
|
||||
//
|
||||
// Requires: data.convertible == ®istered<T>::converters
|
||||
//
|
||||
BOOST_PYTHON_DECL void* rvalue_result_from_python(
|
||||
PyObject* src, rvalue_from_python_stage1_data& data)
|
||||
{
|
||||
// Retrieve the registration
|
||||
// Cast in two steps for less-capable compilers
|
||||
void const* converters_ = data.convertible;
|
||||
registration const& converters = *static_cast<registration const*>(converters_);
|
||||
|
||||
// Look for an eligible converter
|
||||
data = rvalue_from_python_stage1(src, converters);
|
||||
return rvalue_from_python_stage2(src, data, converters);
|
||||
}
|
||||
|
||||
BOOST_PYTHON_DECL void* rvalue_from_python_stage2(
|
||||
PyObject* source, rvalue_from_python_stage1_data& data, registration const& converters)
|
||||
{
|
||||
if (!data.convertible)
|
||||
{
|
||||
handle<> msg(
|
||||
#if PY_VERSION_HEX >= 0x03000000
|
||||
::PyUnicode_FromFormat
|
||||
#else
|
||||
::PyString_FromFormat
|
||||
#endif
|
||||
(
|
||||
"No registered converter was able to produce a C++ rvalue of type %s from this Python object of type %s"
|
||||
, converters.target_type.name()
|
||||
, source->ob_type->tp_name
|
||||
));
|
||||
|
||||
PyErr_SetObject(PyExc_TypeError, msg.get());
|
||||
throw_error_already_set();
|
||||
}
|
||||
|
||||
// If a construct function was registered (i.e. we found an
|
||||
// rvalue conversion), call it now.
|
||||
if (data.construct != 0)
|
||||
data.construct(source, &data);
|
||||
|
||||
// Return the address of the resulting C++ object
|
||||
return data.convertible;
|
||||
}
|
||||
|
||||
BOOST_PYTHON_DECL void* get_lvalue_from_python(
|
||||
PyObject* source
|
||||
, registration const& converters)
|
||||
{
|
||||
// Check to see if it's embedded in a class instance
|
||||
void* x = objects::find_instance_impl(source, converters.target_type);
|
||||
if (x)
|
||||
return x;
|
||||
|
||||
lvalue_from_python_chain const* chain = converters.lvalue_chain;
|
||||
for (;chain != 0; chain = chain->next)
|
||||
{
|
||||
void* r = chain->convert(source);
|
||||
if (r != 0)
|
||||
return r;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
// Prevent looping in implicit conversions. This could/should be
|
||||
// much more efficient, but will work for now.
|
||||
typedef std::vector<rvalue_from_python_chain const*> visited_t;
|
||||
static visited_t visited;
|
||||
|
||||
inline bool visit(rvalue_from_python_chain const* chain)
|
||||
{
|
||||
visited_t::iterator const p = std::lower_bound(visited.begin(), visited.end(), chain);
|
||||
if (p != visited.end() && *p == chain)
|
||||
return false;
|
||||
visited.insert(p, chain);
|
||||
return true;
|
||||
}
|
||||
|
||||
// RAII class for managing global visited marks.
|
||||
struct unvisit
|
||||
{
|
||||
unvisit(rvalue_from_python_chain const* chain)
|
||||
: chain(chain) {}
|
||||
|
||||
~unvisit()
|
||||
{
|
||||
visited_t::iterator const p = std::lower_bound(visited.begin(), visited.end(), chain);
|
||||
assert(p != visited.end());
|
||||
visited.erase(p);
|
||||
}
|
||||
private:
|
||||
rvalue_from_python_chain const* chain;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
BOOST_PYTHON_DECL bool implicit_rvalue_convertible_from_python(
|
||||
PyObject* source
|
||||
, registration const& converters)
|
||||
{
|
||||
if (objects::find_instance_impl(source, converters.target_type))
|
||||
return true;
|
||||
|
||||
rvalue_from_python_chain const* chain = converters.rvalue_chain;
|
||||
|
||||
if (!visit(chain))
|
||||
return false;
|
||||
|
||||
unvisit protect(chain);
|
||||
|
||||
for (;chain != 0; chain = chain->next)
|
||||
{
|
||||
if (chain->convertible(source))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
void throw_no_lvalue_from_python(PyObject* source, registration const& converters, char const* ref_type)
|
||||
{
|
||||
handle<> msg(
|
||||
#if PY_VERSION_HEX >= 0x03000000
|
||||
::PyUnicode_FromFormat
|
||||
#else
|
||||
::PyString_FromFormat
|
||||
#endif
|
||||
(
|
||||
"No registered converter was able to extract a C++ %s to type %s"
|
||||
" from this Python object of type %s"
|
||||
, ref_type
|
||||
, converters.target_type.name()
|
||||
, source->ob_type->tp_name
|
||||
));
|
||||
|
||||
PyErr_SetObject(PyExc_TypeError, msg.get());
|
||||
|
||||
throw_error_already_set();
|
||||
}
|
||||
|
||||
void* lvalue_result_from_python(
|
||||
PyObject* source
|
||||
, registration const& converters
|
||||
, char const* ref_type)
|
||||
{
|
||||
handle<> holder(source);
|
||||
if (source->ob_refcnt <= 1)
|
||||
{
|
||||
handle<> msg(
|
||||
#if PY_VERSION_HEX >= 0x3000000
|
||||
::PyUnicode_FromFormat
|
||||
#else
|
||||
::PyString_FromFormat
|
||||
#endif
|
||||
(
|
||||
"Attempt to return dangling %s to object of type: %s"
|
||||
, ref_type
|
||||
, converters.target_type.name()));
|
||||
|
||||
PyErr_SetObject(PyExc_ReferenceError, msg.get());
|
||||
|
||||
throw_error_already_set();
|
||||
}
|
||||
|
||||
void* result = get_lvalue_from_python(source, converters);
|
||||
if (!result)
|
||||
(throw_no_lvalue_from_python)(source, converters, ref_type);
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
BOOST_PYTHON_DECL void throw_no_pointer_from_python(PyObject* source, registration const& converters)
|
||||
{
|
||||
(throw_no_lvalue_from_python)(source, converters, "pointer");
|
||||
}
|
||||
|
||||
BOOST_PYTHON_DECL void throw_no_reference_from_python(PyObject* source, registration const& converters)
|
||||
{
|
||||
(throw_no_lvalue_from_python)(source, converters, "reference");
|
||||
}
|
||||
|
||||
BOOST_PYTHON_DECL void* reference_result_from_python(
|
||||
PyObject* source
|
||||
, registration const& converters)
|
||||
{
|
||||
return (lvalue_result_from_python)(source, converters, "reference");
|
||||
}
|
||||
|
||||
BOOST_PYTHON_DECL void* pointer_result_from_python(
|
||||
PyObject* source
|
||||
, registration const& converters)
|
||||
{
|
||||
if (source == Py_None)
|
||||
{
|
||||
Py_DECREF(source);
|
||||
return 0;
|
||||
}
|
||||
return (lvalue_result_from_python)(source, converters, "pointer");
|
||||
}
|
||||
|
||||
BOOST_PYTHON_DECL void void_result_from_python(PyObject* o)
|
||||
{
|
||||
Py_DECREF(expect_non_null(o));
|
||||
}
|
||||
|
||||
} // namespace boost::python::converter
|
||||
|
||||
BOOST_PYTHON_DECL PyObject*
|
||||
pytype_check(PyTypeObject* type_, PyObject* source)
|
||||
{
|
||||
if (!PyObject_IsInstance(source, python::upcast<PyObject>(type_)))
|
||||
{
|
||||
::PyErr_Format(
|
||||
PyExc_TypeError
|
||||
, "Expecting an object of type %s; got an object of type %s instead"
|
||||
, type_->tp_name
|
||||
, source->ob_type->tp_name
|
||||
);
|
||||
throw_error_already_set();
|
||||
}
|
||||
return source;
|
||||
}
|
||||
|
||||
}} // namespace boost::python
|
||||
@@ -0,0 +1,306 @@
|
||||
// Copyright David Abrahams 2001.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
#include <boost/python/converter/registry.hpp>
|
||||
#include <boost/python/converter/registrations.hpp>
|
||||
#include <boost/python/converter/builtin_converters.hpp>
|
||||
|
||||
#include <set>
|
||||
#include <stdexcept>
|
||||
|
||||
#if defined(__APPLE__) && defined(__MACH__) && defined(__GNUC__) \
|
||||
&& __GNUC__ == 3 && __GNUC_MINOR__ <= 4 && !defined(__APPLE_CC__)
|
||||
# define BOOST_PYTHON_CONVERTER_REGISTRY_APPLE_MACH_WORKAROUND
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_PYTHON_TRACE_REGISTRY) \
|
||||
|| defined(BOOST_PYTHON_CONVERTER_REGISTRY_APPLE_MACH_WORKAROUND)
|
||||
# include <iostream>
|
||||
#endif
|
||||
|
||||
namespace boost { namespace python { namespace converter {
|
||||
BOOST_PYTHON_DECL PyTypeObject const* registration::expected_from_python_type() const
|
||||
{
|
||||
if (this->m_class_object != 0)
|
||||
return this->m_class_object;
|
||||
|
||||
std::set<PyTypeObject const*> pool;
|
||||
|
||||
for(rvalue_from_python_chain* r = rvalue_chain; r ; r=r->next)
|
||||
if(r->expected_pytype)
|
||||
pool.insert(r->expected_pytype());
|
||||
|
||||
//for now I skip the search for common base
|
||||
if (pool.size()==1)
|
||||
return *pool.begin();
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
BOOST_PYTHON_DECL PyTypeObject const* registration::to_python_target_type() const
|
||||
{
|
||||
if (this->m_class_object != 0)
|
||||
return this->m_class_object;
|
||||
|
||||
if (this->m_to_python_target_type != 0)
|
||||
return this->m_to_python_target_type();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
BOOST_PYTHON_DECL PyTypeObject* registration::get_class_object() const
|
||||
{
|
||||
if (this->m_class_object == 0)
|
||||
{
|
||||
::PyErr_Format(
|
||||
PyExc_TypeError
|
||||
, const_cast<char*>("No Python class registered for C++ class %s")
|
||||
, this->target_type.name());
|
||||
|
||||
throw_error_already_set();
|
||||
}
|
||||
|
||||
return this->m_class_object;
|
||||
}
|
||||
|
||||
BOOST_PYTHON_DECL PyObject* registration::to_python(void const volatile* source) const
|
||||
{
|
||||
if (this->m_to_python == 0)
|
||||
{
|
||||
handle<> msg(
|
||||
#if PY_VERSION_HEX >= 0x3000000
|
||||
::PyUnicode_FromFormat
|
||||
#else
|
||||
::PyString_FromFormat
|
||||
#endif
|
||||
(
|
||||
"No to_python (by-value) converter found for C++ type: %s"
|
||||
, this->target_type.name()
|
||||
)
|
||||
);
|
||||
|
||||
PyErr_SetObject(PyExc_TypeError, msg.get());
|
||||
|
||||
throw_error_already_set();
|
||||
}
|
||||
|
||||
return source == 0
|
||||
? incref(Py_None)
|
||||
: this->m_to_python(const_cast<void*>(source));
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
template< typename T >
|
||||
void delete_node( T* node )
|
||||
{
|
||||
if( !!node && !!node->next )
|
||||
delete_node( node->next );
|
||||
delete node;
|
||||
}
|
||||
}
|
||||
|
||||
registration::~registration()
|
||||
{
|
||||
delete_node(lvalue_chain);
|
||||
delete_node(rvalue_chain);
|
||||
}
|
||||
|
||||
|
||||
namespace // <unnamed>
|
||||
{
|
||||
typedef registration entry;
|
||||
|
||||
typedef std::set<entry> registry_t;
|
||||
|
||||
#ifndef BOOST_PYTHON_CONVERTER_REGISTRY_APPLE_MACH_WORKAROUND
|
||||
registry_t& entries()
|
||||
{
|
||||
static registry_t registry;
|
||||
|
||||
# ifndef BOOST_PYTHON_SUPPRESS_REGISTRY_INITIALIZATION
|
||||
static bool builtin_converters_initialized = false;
|
||||
if (!builtin_converters_initialized)
|
||||
{
|
||||
// Make this true early because registering the builtin
|
||||
// converters will cause recursion.
|
||||
builtin_converters_initialized = true;
|
||||
|
||||
initialize_builtin_converters();
|
||||
}
|
||||
# ifdef BOOST_PYTHON_TRACE_REGISTRY
|
||||
std::cout << "registry: ";
|
||||
for (registry_t::iterator p = registry.begin(); p != registry.end(); ++p)
|
||||
{
|
||||
std::cout << p->target_type << "; ";
|
||||
}
|
||||
std::cout << '\n';
|
||||
# endif
|
||||
# endif
|
||||
return registry;
|
||||
}
|
||||
#else
|
||||
registry_t& static_registry()
|
||||
{
|
||||
static registry_t result;
|
||||
return result;
|
||||
}
|
||||
|
||||
bool static_builtin_converters_initialized()
|
||||
{
|
||||
static bool result = false;
|
||||
if (result == false) {
|
||||
result = true;
|
||||
std::cout << std::flush;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
registry_t& entries()
|
||||
{
|
||||
# ifndef BOOST_PYTHON_SUPPRESS_REGISTRY_INITIALIZATION
|
||||
if (!static_builtin_converters_initialized())
|
||||
{
|
||||
initialize_builtin_converters();
|
||||
}
|
||||
# ifdef BOOST_PYTHON_TRACE_REGISTRY
|
||||
std::cout << "registry: ";
|
||||
for (registry_t::iterator p = static_registry().begin(); p != static_registry().end(); ++p)
|
||||
{
|
||||
std::cout << p->target_type << "; ";
|
||||
}
|
||||
std::cout << '\n';
|
||||
# endif
|
||||
# endif
|
||||
return static_registry();
|
||||
}
|
||||
#endif // BOOST_PYTHON_CONVERTER_REGISTRY_APPLE_MACH_WORKAROUND
|
||||
|
||||
entry* get(type_info type, bool is_shared_ptr = false)
|
||||
{
|
||||
# ifdef BOOST_PYTHON_TRACE_REGISTRY
|
||||
registry_t::iterator p = entries().find(entry(type));
|
||||
|
||||
std::cout << "looking up " << type << ": "
|
||||
<< (p == entries().end() || p->target_type != type
|
||||
? "...NOT found\n" : "...found\n");
|
||||
# endif
|
||||
std::pair<registry_t::const_iterator,bool> pos_ins
|
||||
= entries().insert(entry(type,is_shared_ptr));
|
||||
|
||||
# if __MWERKS__ >= 0x3000
|
||||
// do a little invariant checking if a change was made
|
||||
if ( pos_ins.second )
|
||||
assert(entries().invariants());
|
||||
# endif
|
||||
return const_cast<entry*>(&*pos_ins.first);
|
||||
}
|
||||
} // namespace <unnamed>
|
||||
|
||||
namespace registry
|
||||
{
|
||||
void insert(to_python_function_t f, type_info source_t, PyTypeObject const* (*to_python_target_type)())
|
||||
{
|
||||
# ifdef BOOST_PYTHON_TRACE_REGISTRY
|
||||
std::cout << "inserting to_python " << source_t << "\n";
|
||||
# endif
|
||||
entry* slot = get(source_t);
|
||||
|
||||
assert(slot->m_to_python == 0); // we have a problem otherwise
|
||||
if (slot->m_to_python != 0)
|
||||
{
|
||||
std::string msg = (
|
||||
std::string("to-Python converter for ")
|
||||
+ source_t.name()
|
||||
+ " already registered; second conversion method ignored."
|
||||
);
|
||||
|
||||
if ( ::PyErr_Warn( NULL, const_cast<char*>(msg.c_str()) ) )
|
||||
{
|
||||
throw_error_already_set();
|
||||
}
|
||||
}
|
||||
slot->m_to_python = f;
|
||||
slot->m_to_python_target_type = to_python_target_type;
|
||||
}
|
||||
|
||||
// Insert an lvalue from_python converter
|
||||
void insert(convertible_function convert, type_info key, PyTypeObject const* (*exp_pytype)())
|
||||
{
|
||||
# ifdef BOOST_PYTHON_TRACE_REGISTRY
|
||||
std::cout << "inserting lvalue from_python " << key << "\n";
|
||||
# endif
|
||||
entry* found = get(key);
|
||||
lvalue_from_python_chain *registration = new lvalue_from_python_chain;
|
||||
registration->convert = convert;
|
||||
registration->next = found->lvalue_chain;
|
||||
found->lvalue_chain = registration;
|
||||
|
||||
insert(convert, 0, key,exp_pytype);
|
||||
}
|
||||
|
||||
// Insert an rvalue from_python converter
|
||||
void insert(convertible_function convertible
|
||||
, constructor_function construct
|
||||
, type_info key
|
||||
, PyTypeObject const* (*exp_pytype)())
|
||||
{
|
||||
# ifdef BOOST_PYTHON_TRACE_REGISTRY
|
||||
std::cout << "inserting rvalue from_python " << key << "\n";
|
||||
# endif
|
||||
entry* found = get(key);
|
||||
rvalue_from_python_chain *registration = new rvalue_from_python_chain;
|
||||
registration->convertible = convertible;
|
||||
registration->construct = construct;
|
||||
registration->expected_pytype = exp_pytype;
|
||||
registration->next = found->rvalue_chain;
|
||||
found->rvalue_chain = registration;
|
||||
}
|
||||
|
||||
// Insert an rvalue from_python converter
|
||||
void push_back(convertible_function convertible
|
||||
, constructor_function construct
|
||||
, type_info key
|
||||
, PyTypeObject const* (*exp_pytype)())
|
||||
{
|
||||
# ifdef BOOST_PYTHON_TRACE_REGISTRY
|
||||
std::cout << "push_back rvalue from_python " << key << "\n";
|
||||
# endif
|
||||
rvalue_from_python_chain** found = &get(key)->rvalue_chain;
|
||||
while (*found != 0)
|
||||
found = &(*found)->next;
|
||||
|
||||
rvalue_from_python_chain *registration = new rvalue_from_python_chain;
|
||||
registration->convertible = convertible;
|
||||
registration->construct = construct;
|
||||
registration->expected_pytype = exp_pytype;
|
||||
registration->next = 0;
|
||||
*found = registration;
|
||||
}
|
||||
|
||||
registration const& lookup(type_info key)
|
||||
{
|
||||
return *get(key);
|
||||
}
|
||||
|
||||
registration const& lookup_shared_ptr(type_info key)
|
||||
{
|
||||
return *get(key, true);
|
||||
}
|
||||
|
||||
registration const* query(type_info type)
|
||||
{
|
||||
registry_t::iterator p = entries().find(entry(type));
|
||||
# ifdef BOOST_PYTHON_TRACE_REGISTRY
|
||||
std::cout << "querying " << type
|
||||
<< (p == entries().end() || p->target_type != type
|
||||
? "...NOT found\n" : "...found\n");
|
||||
# endif
|
||||
return (p == entries().end() || p->target_type != type) ? 0 : &*p;
|
||||
}
|
||||
} // namespace registry
|
||||
|
||||
}}} // namespace boost::python::converter
|
||||
@@ -0,0 +1,212 @@
|
||||
// Copyright David Abrahams 2001.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/python/type_id.hpp>
|
||||
#include <boost/python/detail/decorated_type_id.hpp>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
||||
#if defined(__QNXNTO__)
|
||||
# include <ostream>
|
||||
#else /* defined(__QNXNTO__) */
|
||||
|
||||
#if !defined(__GNUC__) || __GNUC__ >= 3 || __SGI_STL_PORT || __EDG_VERSION__
|
||||
# include <ostream>
|
||||
#else
|
||||
# include <ostream.h>
|
||||
#endif
|
||||
|
||||
# ifdef BOOST_PYTHON_HAVE_GCC_CP_DEMANGLE
|
||||
# if defined(__GNUC__) && __GNUC__ >= 3
|
||||
|
||||
// http://lists.debian.org/debian-gcc/2003/09/msg00055.html notes
|
||||
// that, in cxxabi.h of gcc-3.x for x < 4, this type is used before it
|
||||
// is declared.
|
||||
# if __GNUC__ == 3 && __GNUC_MINOR__ < 4
|
||||
class __class_type_info;
|
||||
# endif
|
||||
|
||||
# include <cxxabi.h>
|
||||
# endif
|
||||
# endif
|
||||
#endif /* defined(__QNXNTO__) */
|
||||
|
||||
namespace boost { namespace python {
|
||||
|
||||
# ifdef BOOST_PYTHON_HAVE_GCC_CP_DEMANGLE
|
||||
|
||||
# if defined(__QNXNTO__)
|
||||
namespace cxxabi {
|
||||
extern "C" char* __cxa_demangle(char const*, char*, std::size_t*, int*);
|
||||
}
|
||||
# else /* defined(__QNXNTO__) */
|
||||
|
||||
# ifdef __GNUC__
|
||||
# if __GNUC__ < 3
|
||||
|
||||
namespace cxxabi = :: ;
|
||||
extern "C" char* __cxa_demangle(char const*, char*, std::size_t*, int*);
|
||||
# else
|
||||
|
||||
namespace cxxabi = ::abi; // GCC 3.1 and later
|
||||
|
||||
# if __GNUC__ == 3 && __GNUC_MINOR__ == 0
|
||||
namespace abi
|
||||
{
|
||||
extern "C" char* __cxa_demangle(char const*, char*, std::size_t*, int*);
|
||||
}
|
||||
# endif /* __GNUC__ == 3 && __GNUC_MINOR__ == 0 */
|
||||
# endif /* __GNUC__ < 3 */
|
||||
# endif /* __GNUC__ */
|
||||
# endif /* defined(__QNXNTO__) */
|
||||
|
||||
namespace
|
||||
{
|
||||
struct compare_first_cstring
|
||||
{
|
||||
template <class T>
|
||||
bool operator()(T const& x, T const& y)
|
||||
{
|
||||
return std::strcmp(x.first,y.first) < 0;
|
||||
}
|
||||
};
|
||||
|
||||
struct free_mem
|
||||
{
|
||||
free_mem(char*p)
|
||||
: p(p) {}
|
||||
|
||||
~free_mem()
|
||||
{
|
||||
std::free(p);
|
||||
}
|
||||
char* p;
|
||||
};
|
||||
}
|
||||
|
||||
bool cxxabi_cxa_demangle_is_broken()
|
||||
{
|
||||
static bool was_tested = false;
|
||||
static bool is_broken = false;
|
||||
if (!was_tested) {
|
||||
int status;
|
||||
free_mem keeper(cxxabi::__cxa_demangle("b", 0, 0, &status));
|
||||
was_tested = true;
|
||||
if (status == -2 || strcmp(keeper.p, "bool") != 0) {
|
||||
is_broken = true;
|
||||
}
|
||||
}
|
||||
return is_broken;
|
||||
}
|
||||
|
||||
namespace detail
|
||||
{
|
||||
BOOST_PYTHON_DECL char const* gcc_demangle(char const* mangled)
|
||||
{
|
||||
typedef std::vector<
|
||||
std::pair<char const*, char const*>
|
||||
> mangling_map;
|
||||
|
||||
static mangling_map demangler;
|
||||
mangling_map::iterator p
|
||||
= std::lower_bound(
|
||||
demangler.begin(), demangler.end()
|
||||
, std::make_pair(mangled, (char const*)0)
|
||||
, compare_first_cstring());
|
||||
|
||||
if (p == demangler.end() || strcmp(p->first, mangled))
|
||||
{
|
||||
int status;
|
||||
free_mem keeper(
|
||||
cxxabi::__cxa_demangle(mangled, 0, 0, &status)
|
||||
);
|
||||
|
||||
assert(status != -3); // invalid argument error
|
||||
|
||||
if (status == -1)
|
||||
{
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
else
|
||||
{
|
||||
char const* demangled
|
||||
= status == -2
|
||||
// Invalid mangled name. Best we can do is to
|
||||
// return it intact.
|
||||
? mangled
|
||||
: keeper.p;
|
||||
|
||||
// Ult Mundane, 2005 Aug 17
|
||||
// Contributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
// The __cxa_demangle function is supposed to translate
|
||||
// builtin types from their one-character mangled names,
|
||||
// but it doesn't in gcc 3.3.5 and gcc 3.4.x.
|
||||
if (cxxabi_cxa_demangle_is_broken()
|
||||
&& status == -2 && strlen(mangled) == 1)
|
||||
{
|
||||
// list from
|
||||
// http://www.codesourcery.com/cxx-abi/abi.html
|
||||
switch (mangled[0])
|
||||
{
|
||||
case 'v': demangled = "void"; break;
|
||||
case 'w': demangled = "wchar_t"; break;
|
||||
case 'b': demangled = "bool"; break;
|
||||
case 'c': demangled = "char"; break;
|
||||
case 'a': demangled = "signed char"; break;
|
||||
case 'h': demangled = "unsigned char"; break;
|
||||
case 's': demangled = "short"; break;
|
||||
case 't': demangled = "unsigned short"; break;
|
||||
case 'i': demangled = "int"; break;
|
||||
case 'j': demangled = "unsigned int"; break;
|
||||
case 'l': demangled = "long"; break;
|
||||
case 'm': demangled = "unsigned long"; break;
|
||||
case 'x': demangled = "long long"; break;
|
||||
case 'y': demangled = "unsigned long long"; break;
|
||||
case 'n': demangled = "__int128"; break;
|
||||
case 'o': demangled = "unsigned __int128"; break;
|
||||
case 'f': demangled = "float"; break;
|
||||
case 'd': demangled = "double"; break;
|
||||
case 'e': demangled = "long double"; break;
|
||||
case 'g': demangled = "__float128"; break;
|
||||
case 'z': demangled = "..."; break;
|
||||
}
|
||||
}
|
||||
|
||||
p = demangler.insert(p, std::make_pair(mangled, demangled));
|
||||
keeper.p = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return p->second;
|
||||
}
|
||||
}
|
||||
# endif
|
||||
|
||||
BOOST_PYTHON_DECL std::ostream& operator<<(std::ostream& os, type_info const& x)
|
||||
{
|
||||
return os << x.name();
|
||||
}
|
||||
|
||||
namespace detail
|
||||
{
|
||||
BOOST_PYTHON_DECL std::ostream& operator<<(std::ostream& os, detail::decorated_type_info const& x)
|
||||
{
|
||||
os << x.m_base_type;
|
||||
if (x.m_decoration & decorated_type_info::const_)
|
||||
os << " const";
|
||||
if (x.m_decoration & decorated_type_info::volatile_)
|
||||
os << " volatile";
|
||||
if (x.m_decoration & decorated_type_info::reference)
|
||||
os << "&";
|
||||
return os;
|
||||
}
|
||||
}
|
||||
}} // namespace boost::python::converter
|
||||
Reference in New Issue
Block a user