diff --git a/kdlibcpp b/kdlibcpp index bb585ed..e1636b6 160000 --- a/kdlibcpp +++ b/kdlibcpp @@ -1 +1 @@ -Subproject commit bb585ed1a55f75c50688d803f19fdfc1733b58c6 +Subproject commit e1636b672d7fe886da7ae76587d4fbcef9f78a29 diff --git a/pykd/boost.python/boost_python-src.dict.cpp b/pykd/boost.python/boost_python-src.dict.cpp new file mode 100644 index 0000000..0134390 --- /dev/null +++ b/pykd/boost.python/boost_python-src.dict.cpp @@ -0,0 +1,5 @@ +#define _SCL_SECURE_NO_WARNINGS +#define _CRT_SECURE_NO_WARNINGS +#pragma warning(disable: 4244 4503 4752 4800 4996) +#define BOOST_PYTHON_SOURCE +#include "dict.cpp" diff --git a/pykd/boost.python/boost_python-src.errors.cpp b/pykd/boost.python/boost_python-src.errors.cpp new file mode 100644 index 0000000..2e07ffd --- /dev/null +++ b/pykd/boost.python/boost_python-src.errors.cpp @@ -0,0 +1,5 @@ +#define _SCL_SECURE_NO_WARNINGS +#define _CRT_SECURE_NO_WARNINGS +#pragma warning(disable: 4244 4503 4752 4800 4996) +#define BOOST_PYTHON_SOURCE +#include "errors.cpp" diff --git a/pykd/boost.python/boost_python-src.exec.cpp b/pykd/boost.python/boost_python-src.exec.cpp new file mode 100644 index 0000000..ea11bdb --- /dev/null +++ b/pykd/boost.python/boost_python-src.exec.cpp @@ -0,0 +1,5 @@ +#define _SCL_SECURE_NO_WARNINGS +#define _CRT_SECURE_NO_WARNINGS +#pragma warning(disable: 4244 4503 4752 4800 4996) +#define BOOST_PYTHON_SOURCE +#include "exec.cpp" diff --git a/pykd/boost.python/boost_python-src.import.cpp b/pykd/boost.python/boost_python-src.import.cpp new file mode 100644 index 0000000..cb15f74 --- /dev/null +++ b/pykd/boost.python/boost_python-src.import.cpp @@ -0,0 +1,5 @@ +#define _SCL_SECURE_NO_WARNINGS +#define _CRT_SECURE_NO_WARNINGS +#pragma warning(disable: 4244 4503 4752 4800 4996) +#define BOOST_PYTHON_SOURCE +#include "import.cpp" diff --git a/pykd/boost.python/boost_python-src.list.cpp b/pykd/boost.python/boost_python-src.list.cpp new file mode 100644 index 0000000..4ef9dbf --- /dev/null +++ b/pykd/boost.python/boost_python-src.list.cpp @@ -0,0 +1,5 @@ +#define _SCL_SECURE_NO_WARNINGS +#define _CRT_SECURE_NO_WARNINGS +#pragma warning(disable: 4244 4503 4752 4800 4996) +#define BOOST_PYTHON_SOURCE +#include "list.cpp" diff --git a/pykd/boost.python/boost_python-src.long.cpp b/pykd/boost.python/boost_python-src.long.cpp new file mode 100644 index 0000000..a1f9e37 --- /dev/null +++ b/pykd/boost.python/boost_python-src.long.cpp @@ -0,0 +1,5 @@ +#define _SCL_SECURE_NO_WARNINGS +#define _CRT_SECURE_NO_WARNINGS +#pragma warning(disable: 4244 4503 4752 4800 4996) +#define BOOST_PYTHON_SOURCE +#include "long.cpp" diff --git a/pykd/boost.python/boost_python-src.module.cpp b/pykd/boost.python/boost_python-src.module.cpp new file mode 100644 index 0000000..470e296 --- /dev/null +++ b/pykd/boost.python/boost_python-src.module.cpp @@ -0,0 +1,5 @@ +#define _SCL_SECURE_NO_WARNINGS +#define _CRT_SECURE_NO_WARNINGS +#pragma warning(disable: 4244 4503 4752 4800 4996) +#define BOOST_PYTHON_SOURCE +#include "module.cpp" diff --git a/pykd/boost.python/boost_python-src.object_operators.cpp b/pykd/boost.python/boost_python-src.object_operators.cpp new file mode 100644 index 0000000..81acc34 --- /dev/null +++ b/pykd/boost.python/boost_python-src.object_operators.cpp @@ -0,0 +1,5 @@ +#define _SCL_SECURE_NO_WARNINGS +#define _CRT_SECURE_NO_WARNINGS +#pragma warning(disable: 4244 4503 4752 4800 4996) +#define BOOST_PYTHON_SOURCE +#include "object_operators.cpp" diff --git a/pykd/boost.python/boost_python-src.object_protocol.cpp b/pykd/boost.python/boost_python-src.object_protocol.cpp new file mode 100644 index 0000000..cafe3ea --- /dev/null +++ b/pykd/boost.python/boost_python-src.object_protocol.cpp @@ -0,0 +1,5 @@ +#define _SCL_SECURE_NO_WARNINGS +#define _CRT_SECURE_NO_WARNINGS +#pragma warning(disable: 4244 4503 4752 4800 4996) +#define BOOST_PYTHON_SOURCE +#include "object_protocol.cpp" diff --git a/pykd/boost.python/boost_python-src.slice.cpp b/pykd/boost.python/boost_python-src.slice.cpp new file mode 100644 index 0000000..c8d7ffe --- /dev/null +++ b/pykd/boost.python/boost_python-src.slice.cpp @@ -0,0 +1,5 @@ +#define _SCL_SECURE_NO_WARNINGS +#define _CRT_SECURE_NO_WARNINGS +#pragma warning(disable: 4244 4503 4752 4800 4996) +#define BOOST_PYTHON_SOURCE +#include "slice.cpp" diff --git a/pykd/boost.python/boost_python-src.str.cpp b/pykd/boost.python/boost_python-src.str.cpp new file mode 100644 index 0000000..1e7300c --- /dev/null +++ b/pykd/boost.python/boost_python-src.str.cpp @@ -0,0 +1,5 @@ +#define _SCL_SECURE_NO_WARNINGS +#define _CRT_SECURE_NO_WARNINGS +#pragma warning(disable: 4244 4503 4752 4800 4996) +#define BOOST_PYTHON_SOURCE +#include "str.cpp" diff --git a/pykd/boost.python/boost_python-src.tuple.cpp b/pykd/boost.python/boost_python-src.tuple.cpp new file mode 100644 index 0000000..045db47 --- /dev/null +++ b/pykd/boost.python/boost_python-src.tuple.cpp @@ -0,0 +1,5 @@ +#define _SCL_SECURE_NO_WARNINGS +#define _CRT_SECURE_NO_WARNINGS +#pragma warning(disable: 4244 4503 4752 4800 4996) +#define BOOST_PYTHON_SOURCE +#include "tuple.cpp" diff --git a/pykd/boost.python/boost_python-src.wrapper.cpp b/pykd/boost.python/boost_python-src.wrapper.cpp new file mode 100644 index 0000000..75b1f4d --- /dev/null +++ b/pykd/boost.python/boost_python-src.wrapper.cpp @@ -0,0 +1,5 @@ +#define _SCL_SECURE_NO_WARNINGS +#define _CRT_SECURE_NO_WARNINGS +#pragma warning(disable: 4244 4503 4752 4800 4996) +#define BOOST_PYTHON_SOURCE +#include "wrapper.cpp" diff --git a/pykd/boost.python/converter/arg_to_python_base.cpp b/pykd/boost.python/converter/arg_to_python_base.cpp new file mode 100644 index 0000000..d872314 --- /dev/null +++ b/pykd/boost.python/converter/arg_to_python_base.cpp @@ -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 +#include +#include +#include +#include + +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 diff --git a/pykd/boost.python/converter/boost_python-src.converter.arg_to_python_base.cpp b/pykd/boost.python/converter/boost_python-src.converter.arg_to_python_base.cpp new file mode 100644 index 0000000..dd9752a --- /dev/null +++ b/pykd/boost.python/converter/boost_python-src.converter.arg_to_python_base.cpp @@ -0,0 +1,5 @@ +#define _SCL_SECURE_NO_WARNINGS +#define _CRT_SECURE_NO_WARNINGS +#pragma warning(disable: 4244 4503 4752 4800 4996) +#define BOOST_PYTHON_SOURCE +#include "arg_to_python_base.cpp" diff --git a/pykd/boost.python/converter/boost_python-src.converter.builtin_converters.cpp b/pykd/boost.python/converter/boost_python-src.converter.builtin_converters.cpp new file mode 100644 index 0000000..df31ccf --- /dev/null +++ b/pykd/boost.python/converter/boost_python-src.converter.builtin_converters.cpp @@ -0,0 +1,5 @@ +#define _SCL_SECURE_NO_WARNINGS +#define _CRT_SECURE_NO_WARNINGS +#pragma warning(disable: 4244 4503 4752 4800 4996) +#define BOOST_PYTHON_SOURCE +#include "builtin_converters.cpp" diff --git a/pykd/boost.python/converter/boost_python-src.converter.from_python.cpp b/pykd/boost.python/converter/boost_python-src.converter.from_python.cpp new file mode 100644 index 0000000..fc71566 --- /dev/null +++ b/pykd/boost.python/converter/boost_python-src.converter.from_python.cpp @@ -0,0 +1,5 @@ +#define _SCL_SECURE_NO_WARNINGS +#define _CRT_SECURE_NO_WARNINGS +#pragma warning(disable: 4244 4503 4752 4800 4996) +#define BOOST_PYTHON_SOURCE +#include "from_python.cpp" diff --git a/pykd/boost.python/converter/boost_python-src.converter.registry.cpp b/pykd/boost.python/converter/boost_python-src.converter.registry.cpp new file mode 100644 index 0000000..7cc2cf8 --- /dev/null +++ b/pykd/boost.python/converter/boost_python-src.converter.registry.cpp @@ -0,0 +1,5 @@ +#define _SCL_SECURE_NO_WARNINGS +#define _CRT_SECURE_NO_WARNINGS +#pragma warning(disable: 4244 4503 4752 4800 4996) +#define BOOST_PYTHON_SOURCE +#include "registry.cpp" diff --git a/pykd/boost.python/converter/boost_python-src.converter.type_id.cpp b/pykd/boost.python/converter/boost_python-src.converter.type_id.cpp new file mode 100644 index 0000000..afaf12b --- /dev/null +++ b/pykd/boost.python/converter/boost_python-src.converter.type_id.cpp @@ -0,0 +1,5 @@ +#define _SCL_SECURE_NO_WARNINGS +#define _CRT_SECURE_NO_WARNINGS +#pragma warning(disable: 4244 4503 4752 4800 4996) +#define BOOST_PYTHON_SOURCE +#include "type_id.cpp" diff --git a/pykd/boost.python/converter/builtin_converters.cpp b/pykd/boost.python/converter/builtin_converters.cpp new file mode 100644 index 0000000..ee2d5b4 --- /dev/null +++ b/pykd/boost.python/converter/builtin_converters.cpp @@ -0,0 +1,592 @@ +// 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 +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +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; + } +#elif PY_VERSION_HEX < 0x03070000 + void* convert_to_cstring(PyObject* obj) + { + return PyUnicode_Check(obj) ? _PyUnicode_AsString(obj) : 0; + } +#else + void* convert_to_cstring(PyObject* obj) + { + return PyUnicode_Check(obj) ? const_cast(reinterpret_cast(_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 + struct slot_rvalue_from_python + { + public: + slot_rvalue_from_python() + { + registry::insert( + &slot_rvalue_from_python::convertible + , &slot_rvalue_from_python::construct + , type_id() + , &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(data->convertible); + handle<> intermediate(creator(obj)); + + // Get the location in which to construct + void* storage = ((rvalue_from_python_storage*)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 + 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(x); + } + }; + + template + 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(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 + 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(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 + 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(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(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(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) + { + // On Windows, with Python >= 3.3, PyObject_Length cannot be used to get + // the size of the wchar_t string, because it will count the number of + // *code points*, but some characters not on the BMP will use two UTF-16 + // *code units* (surrogate pairs). + // This is not a problem on Unix, since wchar_t is 32-bit. +#if defined(_WIN32) && PY_VERSION_HEX >= 0x03030000 + BOOST_STATIC_ASSERT(sizeof(wchar_t) == 2); + + Py_ssize_t size = 0; + wchar_t *buf = PyUnicode_AsWideCharString(intermediate, &size); + if (buf == NULL) { + boost::python::throw_error_already_set(); + } + std::wstring result(buf, size); + PyMem_Free(buf); +#else + 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(); + } +#endif + 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 extract(PyObject* intermediate) + { + if (PyComplex_Check(intermediate)) + { + return std::complex( + 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 \ + >() + +#define REGISTER_INT_CONVERTERS2(U) \ + REGISTER_INT_CONVERTERS(signed, U); \ + REGISTER_INT_CONVERTERS(unsigned, U) + +void initialize_builtin_converters() +{ + // booleans + slot_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(); + slot_rvalue_from_python(); +# endif + + // floating types + slot_rvalue_from_python(); + slot_rvalue_from_python(); + slot_rvalue_from_python(); + + slot_rvalue_from_python,complex_rvalue_from_python>(); + slot_rvalue_from_python,complex_rvalue_from_python>(); + slot_rvalue_from_python,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(),&converter::wrap_pytype<&PyString_Type>::get_pytype); +#else + registry::insert(convert_to_cstring,type_id(),&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(); +# endif + slot_rvalue_from_python(); + +} + +}}} // namespace boost::python::converter diff --git a/pykd/boost.python/converter/from_python.cpp b/pykd/boost.python/converter/from_python.cpp new file mode 100644 index 0000000..9678be1 --- /dev/null +++ b/pykd/boost.python/converter/from_python.cpp @@ -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 +#include +#include + +#include + +#include +#include +#include + +#include +#include + +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, +// 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 object, where T is the +// target type of the conversion. +// +// Requires: data.convertible == ®istered::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(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 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(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 diff --git a/pykd/boost.python/converter/registry.cpp b/pykd/boost.python/converter/registry.cpp new file mode 100644 index 0000000..aa20c3f --- /dev/null +++ b/pykd/boost.python/converter/registry.cpp @@ -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 +#include +#include + +#include +#include + +#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 +#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 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("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(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 // +{ + typedef registration entry; + + typedef std::set 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 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(&*pos_ins.first); + } +} // namespace + +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(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 diff --git a/pykd/boost.python/converter/type_id.cpp b/pykd/boost.python/converter/type_id.cpp new file mode 100644 index 0000000..c6a8bf7 --- /dev/null +++ b/pykd/boost.python/converter/type_id.cpp @@ -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 +#include +#include +#include +#include +#include +#include +#include + +#if defined(__QNXNTO__) +# include +#else /* defined(__QNXNTO__) */ + +#if !defined(__GNUC__) || __GNUC__ >= 3 || __SGI_STL_PORT || __EDG_VERSION__ +# include +#else +# include +#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 +# 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 + 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 + > 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 diff --git a/pykd/boost.python/dict.cpp b/pykd/boost.python/dict.cpp new file mode 100644 index 0000000..77d840d --- /dev/null +++ b/pykd/boost.python/dict.cpp @@ -0,0 +1,184 @@ +// Copyright David Abrahams 2004. 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 +#include + +namespace boost { namespace python { namespace detail { +namespace +{ + // When returning list objects from methods, it may turn out that the + // derived class is returning something else, perhaps something not + // even derived from list. Since it is generally harmless for a + // Boost.Python wrapper object to hold an object of a different + // type, and because calling list() with an object may in fact + // perform a conversion, the least-bad alternative is to assume that + // we have a Python list object and stuff it into the list result. + list assume_list(object const& o) + { + return list(detail::borrowed_reference(o.ptr())); + } + + // No PyDict_CheckExact; roll our own. + inline bool check_exact(dict_base const* p) + { + return p->ptr()->ob_type == &PyDict_Type; + } +} + +detail::new_reference dict_base::call(object const& arg_) +{ + return (detail::new_reference)PyObject_CallFunction( + (PyObject*)&PyDict_Type, const_cast("(O)"), + arg_.ptr()); +} + +dict_base::dict_base() + : object(detail::new_reference(PyDict_New())) +{} + +dict_base::dict_base(object_cref data) + : object(call(data)) +{} + +void dict_base::clear() +{ + if (check_exact(this)) + PyDict_Clear(this->ptr()); + else + this->attr("clear")(); +} + +dict dict_base::copy() +{ + if (check_exact(this)) + { + return dict(detail::new_reference( + PyDict_Copy(this->ptr()))); + } + else + { + return dict(detail::borrowed_reference( + this->attr("copy")().ptr() + )); + } +} + +object dict_base::get(object_cref k) const +{ + if (check_exact(this)) + { + PyObject* result = PyDict_GetItem(this->ptr(),k.ptr()); + return object(detail::borrowed_reference(result ? result : Py_None)); + } + else + { + return this->attr("get")(k); + } +} + +object dict_base::get(object_cref k, object_cref d) const +{ + return this->attr("get")(k,d); +} + +bool dict_base::has_key(object_cref k) const +{ + return extract(this->contains(k)); +} + +list dict_base::items() const +{ + if (check_exact(this)) + { + return list(detail::new_reference( + PyDict_Items(this->ptr()))); + } + else + { + return assume_list(this->attr("items")()); + } +} + +object dict_base::iteritems() const +{ + return this->attr("iteritems")(); +} + +object dict_base::iterkeys() const +{ + return this->attr("iterkeys")(); +} + +object dict_base::itervalues() const +{ + return this->attr("itervalues")(); +} + +list dict_base::keys() const +{ + if (check_exact(this)) + { + return list(detail::new_reference( + PyDict_Keys(this->ptr()))); + } + else + { + return assume_list(this->attr("keys")()); + } +} + +tuple dict_base::popitem() +{ + return tuple(detail::borrowed_reference( + this->attr("popitem")().ptr() + )); +} + +object dict_base::setdefault(object_cref k) +{ + return this->attr("setdefault")(k); +} + +object dict_base::setdefault(object_cref k, object_cref d) +{ + return this->attr("setdefault")(k,d); +} + +void dict_base::update(object_cref other) +{ + if (check_exact(this)) + { + if (PyDict_Update(this->ptr(),other.ptr()) == -1) + throw_error_already_set(); + } + else + { + this->attr("update")(other); + } +} + +list dict_base::values() const +{ + if (check_exact(this)) + { + return list(detail::new_reference( + PyDict_Values(this->ptr()))); + } + else + { + return assume_list(this->attr("values")()); + } +} + +static struct register_dict_pytype_ptr +{ + register_dict_pytype_ptr() + { + const_cast( + converter::registry::lookup(boost::python::type_id()) + ).m_class_object = &PyDict_Type; + } +}register_dict_pytype_ptr_; + +}}} // namespace boost::python diff --git a/pykd/boost.python/errors.cpp b/pykd/boost.python/errors.cpp new file mode 100644 index 0000000..34ea22f --- /dev/null +++ b/pykd/boost.python/errors.cpp @@ -0,0 +1,105 @@ +// 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) + +#ifndef BOOST_PYTHON_SOURCE +# define BOOST_PYTHON_SOURCE +#endif + +#include +#include +#include + +namespace boost { namespace python { + +error_already_set::~error_already_set() {} + +// IMPORTANT: this function may only be called from within a catch block! +BOOST_PYTHON_DECL bool handle_exception_impl(function0 f) +{ + try + { + if (detail::exception_handler::chain) + return detail::exception_handler::chain->handle(f); + f(); + return false; + } + catch(const boost::python::error_already_set&) + { + // The python error reporting has already been handled. + } + catch(const std::bad_alloc&) + { + PyErr_NoMemory(); + } + catch(const bad_numeric_cast& x) + { + PyErr_SetString(PyExc_OverflowError, x.what()); + } + catch(const std::out_of_range& x) + { + PyErr_SetString(PyExc_IndexError, x.what()); + } + catch(const std::invalid_argument& x) + { + PyErr_SetString(PyExc_ValueError, x.what()); + } + catch(const std::exception& x) + { + PyErr_SetString(PyExc_RuntimeError, x.what()); + } + catch(...) + { + PyErr_SetString(PyExc_RuntimeError, "unidentifiable C++ exception"); + } + return true; +} + +void BOOST_PYTHON_DECL throw_error_already_set() +{ + throw error_already_set(); +} + +namespace detail { + +bool exception_handler::operator()(function0 const& f) const +{ + if (m_next) + { + return m_next->handle(f); + } + else + { + f(); + return false; + } +} + +exception_handler::exception_handler(handler_function const& impl) + : m_impl(impl) + , m_next(0) +{ + if (chain != 0) + tail->m_next = this; + else + chain = this; + tail = this; +} + +exception_handler* exception_handler::chain; +exception_handler* exception_handler::tail; + +BOOST_PYTHON_DECL void register_exception_handler(handler_function const& f) +{ + // the constructor links the new object into a handler chain, so + // this object isn't actaully leaked (until, of course, the + // interpreter exits). + new exception_handler(f); +} + +} // namespace boost::python::detail + +}} // namespace boost::python + + diff --git a/pykd/boost.python/exec.cpp b/pykd/boost.python/exec.cpp new file mode 100644 index 0000000..171c6f4 --- /dev/null +++ b/pykd/boost.python/exec.cpp @@ -0,0 +1,129 @@ +// Copyright Stefan Seefeld 2005. +// 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 +#include +#include +#include +#include + +namespace boost +{ +namespace python +{ + +object BOOST_PYTHON_DECL eval(str string, object global, object local) +{ + return eval(python::extract(string), global, local); +} + +object BOOST_PYTHON_DECL eval(char const *string, object global, object local) +{ + // Set suitable default values for global and local dicts. + if (global.is_none()) + { + if (PyObject *g = PyEval_GetGlobals()) + global = object(detail::borrowed_reference(g)); + else + global = dict(); + } + if (local.is_none()) local = global; + // should be 'char const *' but older python versions don't use 'const' yet. + char *s = const_cast(string); + PyObject* result = PyRun_String(s, Py_eval_input, global.ptr(), local.ptr()); + if (!result) throw_error_already_set(); + return object(detail::new_reference(result)); +} + +object BOOST_PYTHON_DECL exec(str string, object global, object local) +{ + return exec(python::extract(string), global, local); +} + +object BOOST_PYTHON_DECL exec(char const *string, object global, object local) +{ + // Set suitable default values for global and local dicts. + if (global.is_none()) + { + if (PyObject *g = PyEval_GetGlobals()) + global = object(detail::borrowed_reference(g)); + else + global = dict(); + } + if (local.is_none()) local = global; + // should be 'char const *' but older python versions don't use 'const' yet. + char *s = const_cast(string); + PyObject* result = PyRun_String(s, Py_file_input, global.ptr(), local.ptr()); + if (!result) throw_error_already_set(); + return object(detail::new_reference(result)); +} + +object BOOST_PYTHON_DECL exec_statement(str string, object global, object local) +{ + return exec_statement(python::extract(string), global, local); +} + +object BOOST_PYTHON_DECL exec_statement(char const *string, object global, object local) +{ + // Set suitable default values for global and local dicts. + if (global.is_none()) + { + if (PyObject *g = PyEval_GetGlobals()) + global = object(detail::borrowed_reference(g)); + else + global = dict(); + } + if (local.is_none()) local = global; + // should be 'char const *' but older python versions don't use 'const' yet. + char *s = const_cast(string); + PyObject* result = PyRun_String(s, Py_single_input, global.ptr(), local.ptr()); + if (!result) throw_error_already_set(); + return object(detail::new_reference(result)); +} + +// Execute python source code from file filename. +// global and local are the global and local scopes respectively, +// used during execution. +object BOOST_PYTHON_DECL exec_file(str filename, object global, object local) +{ + return exec_file(python::extract(filename), global, local); +} + +object BOOST_PYTHON_DECL exec_file(char const *filename, object global, object local) +{ + // Set suitable default values for global and local dicts. + if (global.is_none()) + { + if (PyObject *g = PyEval_GetGlobals()) + global = object(detail::borrowed_reference(g)); + else + global = dict(); + } + if (local.is_none()) local = global; + // should be 'char const *' but older python versions don't use 'const' yet. + char *f = const_cast(filename); + // Let python open the file to avoid potential binary incompatibilities. +#if PY_VERSION_HEX >= 0x03040000 + FILE *fs = _Py_fopen(f, "r"); +#elif PY_VERSION_HEX >= 0x03000000 + PyObject *fo = Py_BuildValue("s", f); + FILE *fs = _Py_fopen(fo, "r"); + Py_DECREF(fo); +#else + PyObject *pyfile = PyFile_FromString(f, const_cast("r")); + if (!pyfile) throw std::invalid_argument(std::string(f) + " : no such file"); + python::handle<> file(pyfile); + FILE *fs = PyFile_AsFile(file.get()); +#endif + PyObject* result = PyRun_File(fs, + f, + Py_file_input, + global.ptr(), local.ptr()); + if (!result) throw_error_already_set(); + return object(detail::new_reference(result)); +} + +} // namespace boost::python +} // namespace boost diff --git a/pykd/boost.python/fabscript b/pykd/boost.python/fabscript new file mode 100644 index 0000000..0ebeac6 --- /dev/null +++ b/pykd/boost.python/fabscript @@ -0,0 +1,58 @@ +# -*- python -*- +# +# Copyright (c) 2016 Stefan Seefeld +# All rights reserved. +# +# 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) + +from faber.feature import set +from faber.artefacts.library import library +from faber.tools.compiler import define + +root = module('..') + +bpl = library('boost_python' + root.py_suffix, + ['list.cpp', + 'long.cpp', + 'dict.cpp', + 'tuple.cpp', + 'str.cpp', + 'slice.cpp', + 'converter/from_python.cpp', + 'converter/registry.cpp', + 'converter/type_id.cpp', + 'object/enum.cpp', + 'object/class.cpp', + 'object/function.cpp', + 'object/inheritance.cpp', + 'object/life_support.cpp', + 'object/pickle_support.cpp', + 'errors.cpp', + 'module.cpp', + 'converter/builtin_converters.cpp', + 'converter/arg_to_python_base.cpp', + 'object/iterator.cpp', + 'object/stl_iterator.cpp', + 'object_protocol.cpp', + 'object_operators.cpp', + 'wrapper.cpp', + 'import.cpp', + 'exec.cpp', + 'object/function_doc_signature.cpp'], + dependencies=root.config, + features=features + define('BOOST_PYTHON_SOURCE')) + +bnl = library('boost_numpy' + root.py_suffix, + ['numpy/dtype.cpp', + 'numpy/matrix.cpp', + 'numpy/ndarray.cpp', + 'numpy/numpy.cpp', + 'numpy/scalars.cpp', + 'numpy/ufunc.cpp', + bpl], + dependencies=root.config, + features=features + define('BOOST_NUMPY_SOURCE'), + condition=set.define.contains('HAS_NUMPY')) +default = [bpl, bnl] diff --git a/pykd/boost.python/import.cpp b/pykd/boost.python/import.cpp new file mode 100644 index 0000000..0add79e --- /dev/null +++ b/pykd/boost.python/import.cpp @@ -0,0 +1,25 @@ +// Copyright Stefan Seefeld 2005. +// 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 +#include +#include +#include + +namespace boost +{ +namespace python +{ + +object BOOST_PYTHON_DECL import(str name) +{ + // should be 'char const *' but older python versions don't use 'const' yet. + char *n = python::extract(name); + python::handle<> module(PyImport_ImportModule(n)); + return python::object(module); +} + +} // namespace boost::python +} // namespace boost diff --git a/pykd/boost.python/list.cpp b/pykd/boost.python/list.cpp new file mode 100644 index 0000000..77e6168 --- /dev/null +++ b/pykd/boost.python/list.cpp @@ -0,0 +1,170 @@ +// 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 +#include + +namespace boost { namespace python { namespace detail { + + +detail::new_non_null_reference list_base::call(object const& arg_) +{ + return (detail::new_non_null_reference) + (expect_non_null)( + PyObject_CallFunction( + (PyObject*)&PyList_Type, const_cast("(O)"), + arg_.ptr())); +} + +list_base::list_base() + : object(detail::new_reference(PyList_New(0))) +{} + +list_base::list_base(object_cref sequence) + : object(list_base::call(sequence)) +{} + +void list_base::append(object_cref x) +{ + if (PyList_CheckExact(this->ptr())) + { + if (PyList_Append(this->ptr(), x.ptr()) == -1) + throw_error_already_set(); + } + else + { + this->attr("append")(x); + } +} + +//long list_base::count(object_cref value) const; + +void list_base::extend(object_cref sequence) +{ + this->attr("extend")(sequence); +} + +long list_base::index(object_cref value) const +{ + object result_obj(this->attr("index")(value)); +#if PY_VERSION_HEX >= 0x03000000 + ssize_t result = PyLong_AsSsize_t(result_obj.ptr()); +#else + long result = PyInt_AsLong(result_obj.ptr()); +#endif + if (result == -1) + throw_error_already_set(); + return result; +} + +void list_base::insert(ssize_t index, object_cref item) +{ + if (PyList_CheckExact(this->ptr())) + { + if (PyList_Insert(this->ptr(), index, item.ptr()) == -1) + throw_error_already_set(); + } + else + { + this->attr("insert")(index, item); + } +} + +void list_base::insert(object const& index, object_cref x) +{ +#if PY_VERSION_HEX >= 0x03000000 + ssize_t index_ = PyLong_AsSsize_t(index.ptr()); +#else + long index_ = PyInt_AsLong(index.ptr()); +#endif + if (index_ == -1 && PyErr_Occurred()) + throw_error_already_set(); + this->insert(index_, x); +} + +object list_base::pop() +{ + return this->attr("pop")(); +} + +object list_base::pop(ssize_t index) +{ + return this->pop(object(index)); +} + +object list_base::pop(object const& index) +{ + return this->attr("pop")(index); +} + +void list_base::remove(object_cref value) +{ + this->attr("remove")(value); +} + +void list_base::reverse() +{ + if (PyList_CheckExact(this->ptr())) + { + if (PyList_Reverse(this->ptr()) == -1) + throw_error_already_set(); + } + else + { + this->attr("reverse")(); + } +} + +void list_base::sort() +{ + if (PyList_CheckExact(this->ptr())) + { + if (PyList_Sort(this->ptr()) == -1) + throw_error_already_set(); + } + else + { + this->attr("sort")(); + } +} + +#if PY_VERSION_HEX >= 0x03000000 +void list_base::sort(args_proxy const &args, + kwds_proxy const &kwds) +{ + this->attr("sort")(args, kwds); +} +#else +void list_base::sort(object_cref cmpfunc) +{ + this->attr("sort")(cmpfunc); +} +#endif + +// For some reason, moving this to the end of the TU suppresses an ICE +// with vc6. +ssize_t list_base::count(object_cref value) const +{ + object result_obj(this->attr("count")(value)); +#if PY_VERSION_HEX >= 0x03000000 + ssize_t result = PyLong_AsSsize_t(result_obj.ptr()); +#else + long result = PyInt_AsLong(result_obj.ptr()); +#endif + if (result == -1) + throw_error_already_set(); + return result; +} + +static struct register_list_pytype_ptr +{ + register_list_pytype_ptr() + { + const_cast( + converter::registry::lookup(boost::python::type_id()) + ).m_class_object = &PyList_Type; + } +}register_list_pytype_ptr_; + +}}} // namespace boost::python diff --git a/pykd/boost.python/long.cpp b/pykd/boost.python/long.cpp new file mode 100644 index 0000000..1ec8ebc --- /dev/null +++ b/pykd/boost.python/long.cpp @@ -0,0 +1,39 @@ +// 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 + +namespace boost { namespace python { namespace detail { + +new_non_null_reference long_base::call(object const& arg_) +{ + return (detail::new_non_null_reference)PyObject_CallFunction( + (PyObject*)&PyLong_Type, const_cast("(O)"), + arg_.ptr()); +} + +new_non_null_reference long_base::call(object const& arg_, object const& base) +{ + return (detail::new_non_null_reference)PyObject_CallFunction( + (PyObject*)&PyLong_Type, const_cast("(OO)"), + arg_.ptr(), base.ptr()); +} + +long_base::long_base() + : object( + detail::new_reference( + PyObject_CallFunction((PyObject*)&PyLong_Type, const_cast("()"))) + ) +{} + +long_base::long_base(object_cref arg) + : object(long_base::call(arg)) +{} + +long_base::long_base(object_cref arg, object_cref base) + : object(long_base::call(arg, base)) +{} + + +}}} // namespace boost::python diff --git a/pykd/boost.python/module.cpp b/pykd/boost.python/module.cpp new file mode 100644 index 0000000..9628481 --- /dev/null +++ b/pykd/boost.python/module.cpp @@ -0,0 +1,73 @@ +// (C) Copyright David Abrahams 2000. +// 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) +// +// The author gratefully acknowleges the support of Dragon Systems, Inc., in +// producing this work. + +#include +#include + +namespace boost { namespace python { namespace detail { + +namespace +{ + PyObject* init_module_in_scope(PyObject* m, void(*init_function)()) + { + if (m != 0) + { + // Create the current module scope + object m_obj(((borrowed_reference_t*)m)); + scope current_module(m_obj); + + handle_exception(init_function); + } + + return m; + } +} + +BOOST_PYTHON_DECL void scope_setattr_doc(char const* name, object const& x, char const* doc) +{ + // Use function::add_to_namespace to achieve overloading if + // appropriate. + scope current; + objects::add_to_namespace(current, name, x, doc); +} + +#if PY_VERSION_HEX >= 0x03000000 + +BOOST_PYTHON_DECL PyObject* init_module(PyModuleDef& moduledef, void(*init_function)()) +{ + return init_module_in_scope( + PyModule_Create(&moduledef), + init_function); +} + +#else + +namespace +{ + PyMethodDef initial_methods[] = { { 0, 0, 0, 0 } }; +} + +BOOST_PYTHON_DECL PyObject* init_module(char const* name, void(*init_function)()) +{ + return init_module_in_scope( + Py_InitModule(const_cast(name), initial_methods), + init_function); +} + +#endif + +}}} // namespace boost::python::detail + +namespace boost { namespace python { + +namespace detail +{ + BOOST_PYTHON_DECL PyObject* current_scope = 0; +} + +}} diff --git a/pykd/boost.python/object/boost_python-src.object.class.cpp b/pykd/boost.python/object/boost_python-src.object.class.cpp new file mode 100644 index 0000000..08c1ef8 --- /dev/null +++ b/pykd/boost.python/object/boost_python-src.object.class.cpp @@ -0,0 +1,5 @@ +#define _SCL_SECURE_NO_WARNINGS +#define _CRT_SECURE_NO_WARNINGS +#pragma warning(disable: 4244 4503 4752 4800 4996) +#define BOOST_PYTHON_SOURCE +#include "class.cpp" diff --git a/pykd/boost.python/object/boost_python-src.object.enum.cpp b/pykd/boost.python/object/boost_python-src.object.enum.cpp new file mode 100644 index 0000000..798abca --- /dev/null +++ b/pykd/boost.python/object/boost_python-src.object.enum.cpp @@ -0,0 +1,5 @@ +#define _SCL_SECURE_NO_WARNINGS +#define _CRT_SECURE_NO_WARNINGS +#pragma warning(disable: 4244 4503 4752 4800 4996) +#define BOOST_PYTHON_SOURCE +#include "enum.cpp" diff --git a/pykd/boost.python/object/boost_python-src.object.function.cpp b/pykd/boost.python/object/boost_python-src.object.function.cpp new file mode 100644 index 0000000..961a417 --- /dev/null +++ b/pykd/boost.python/object/boost_python-src.object.function.cpp @@ -0,0 +1,5 @@ +#define _SCL_SECURE_NO_WARNINGS +#define _CRT_SECURE_NO_WARNINGS +#pragma warning(disable: 4244 4503 4752 4800 4996) +#define BOOST_PYTHON_SOURCE +#include "function.cpp" diff --git a/pykd/boost.python/object/boost_python-src.object.function_doc_signature.cpp b/pykd/boost.python/object/boost_python-src.object.function_doc_signature.cpp new file mode 100644 index 0000000..86af1d5 --- /dev/null +++ b/pykd/boost.python/object/boost_python-src.object.function_doc_signature.cpp @@ -0,0 +1,5 @@ +#define _SCL_SECURE_NO_WARNINGS +#define _CRT_SECURE_NO_WARNINGS +#pragma warning(disable: 4244 4503 4752 4800 4996) +#define BOOST_PYTHON_SOURCE +#include "function_doc_signature.cpp" diff --git a/pykd/boost.python/object/boost_python-src.object.inheritance.cpp b/pykd/boost.python/object/boost_python-src.object.inheritance.cpp new file mode 100644 index 0000000..0725431 --- /dev/null +++ b/pykd/boost.python/object/boost_python-src.object.inheritance.cpp @@ -0,0 +1,5 @@ +#define _SCL_SECURE_NO_WARNINGS +#define _CRT_SECURE_NO_WARNINGS +#pragma warning(disable: 4244 4503 4752 4800 4996) +#define BOOST_PYTHON_SOURCE +#include "inheritance.cpp" diff --git a/pykd/boost.python/object/boost_python-src.object.iterator.cpp b/pykd/boost.python/object/boost_python-src.object.iterator.cpp new file mode 100644 index 0000000..9cfb3c2 --- /dev/null +++ b/pykd/boost.python/object/boost_python-src.object.iterator.cpp @@ -0,0 +1,5 @@ +#define _SCL_SECURE_NO_WARNINGS +#define _CRT_SECURE_NO_WARNINGS +#pragma warning(disable: 4244 4503 4752 4800 4996) +#define BOOST_PYTHON_SOURCE +#include "iterator.cpp" diff --git a/pykd/boost.python/object/boost_python-src.object.life_support.cpp b/pykd/boost.python/object/boost_python-src.object.life_support.cpp new file mode 100644 index 0000000..54d4422 --- /dev/null +++ b/pykd/boost.python/object/boost_python-src.object.life_support.cpp @@ -0,0 +1,5 @@ +#define _SCL_SECURE_NO_WARNINGS +#define _CRT_SECURE_NO_WARNINGS +#pragma warning(disable: 4244 4503 4752 4800 4996) +#define BOOST_PYTHON_SOURCE +#include "life_support.cpp" diff --git a/pykd/boost.python/object/boost_python-src.object.pickle_support.cpp b/pykd/boost.python/object/boost_python-src.object.pickle_support.cpp new file mode 100644 index 0000000..b3bc57a --- /dev/null +++ b/pykd/boost.python/object/boost_python-src.object.pickle_support.cpp @@ -0,0 +1,5 @@ +#define _SCL_SECURE_NO_WARNINGS +#define _CRT_SECURE_NO_WARNINGS +#pragma warning(disable: 4244 4503 4752 4800 4996) +#define BOOST_PYTHON_SOURCE +#include "pickle_support.cpp" diff --git a/pykd/boost.python/object/boost_python-src.object.stl_iterator.cpp b/pykd/boost.python/object/boost_python-src.object.stl_iterator.cpp new file mode 100644 index 0000000..e27520e --- /dev/null +++ b/pykd/boost.python/object/boost_python-src.object.stl_iterator.cpp @@ -0,0 +1,5 @@ +#define _SCL_SECURE_NO_WARNINGS +#define _CRT_SECURE_NO_WARNINGS +#pragma warning(disable: 4244 4503 4752 4800 4996) +#define BOOST_PYTHON_SOURCE +#include "stl_iterator.cpp" diff --git a/pykd/boost.python/object/class.cpp b/pykd/boost.python/object/class.cpp new file mode 100644 index 0000000..aeef688 --- /dev/null +++ b/pykd/boost.python/object/class.cpp @@ -0,0 +1,764 @@ +// 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 +#include // #including this first is an intel6 workaround + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost { namespace python { + +# ifdef BOOST_PYTHON_SELF_IS_CLASS +namespace self_ns +{ + self_t self; +} +# endif + +instance_holder::instance_holder() + : m_next(0) +{ +} + +instance_holder::~instance_holder() +{ +} + +extern "C" +{ + // This is copied from typeobject.c in the Python sources. Even though + // class_metatype_object doesn't set Py_TPFLAGS_HAVE_GC, that bit gets + // filled in by the base class initialization process in + // PyType_Ready(). However, tp_is_gc is *not* copied from the base + // type, making it assume that classes are GC-able even if (like + // class_type_object) they're statically allocated. + static int + type_is_gc(PyTypeObject *python_type) + { + return python_type->tp_flags & Py_TPFLAGS_HEAPTYPE; + } + + // This is also copied from the Python sources. We can't implement + // static_data as a subclass property effectively without it. + typedef struct { + PyObject_HEAD + PyObject *prop_get; + PyObject *prop_set; + PyObject *prop_del; + PyObject *prop_doc; + int getter_doc; + } propertyobject; + + // Copied from Python source and removed the part for setting docstring, + // since we don't have a setter for __doc__ and trying to set it will + // cause the init fail. + static int property_init(PyObject *self, PyObject *args, PyObject *kwds) + { + PyObject *get = NULL, *set = NULL, *del = NULL, *doc = NULL; + static const char *kwlist[] = {"fget", "fset", "fdel", "doc", 0}; + propertyobject *prop = (propertyobject *)self; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OOOO:property", + const_cast(kwlist), &get, &set, &del, &doc)) + return -1; + + if (get == Py_None) + get = NULL; + if (set == Py_None) + set = NULL; + if (del == Py_None) + del = NULL; + + Py_XINCREF(get); + Py_XINCREF(set); + Py_XINCREF(del); + Py_XINCREF(doc); + + prop->prop_get = get; + prop->prop_set = set; + prop->prop_del = del; + prop->prop_doc = doc; + prop->getter_doc = 0; + + return 0; + } + + + static PyObject * + static_data_descr_get(PyObject *self, PyObject * /*obj*/, PyObject * /*type*/) + { + propertyobject *gs = (propertyobject *)self; + + return PyObject_CallFunction(gs->prop_get, const_cast("()")); + } + + static int + static_data_descr_set(PyObject *self, PyObject * /*obj*/, PyObject *value) + { + propertyobject *gs = (propertyobject *)self; + PyObject *func, *res; + + if (value == NULL) + func = gs->prop_del; + else + func = gs->prop_set; + if (func == NULL) { + PyErr_SetString(PyExc_AttributeError, + value == NULL ? + "can't delete attribute" : + "can't set attribute"); + return -1; + } + if (value == NULL) + res = PyObject_CallFunction(func, const_cast("()")); + else + res = PyObject_CallFunction(func, const_cast("(O)"), value); + if (res == NULL) + return -1; + Py_DECREF(res); + return 0; + } +} + +static PyTypeObject static_data_object = { + PyVarObject_HEAD_INIT(NULL, 0) + const_cast("Boost.Python.StaticProperty"), + sizeof(propertyobject), + 0, + 0, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT // | Py_TPFLAGS_HAVE_GC + | Py_TPFLAGS_BASETYPE, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, //&PyProperty_Type, /* tp_base */ + 0, /* tp_dict */ + static_data_descr_get, /* tp_descr_get */ + static_data_descr_set, /* tp_descr_set */ + 0, /* tp_dictoffset */ + property_init, /* tp_init */ + 0, /* tp_alloc */ + 0, // filled in with type_new /* tp_new */ + 0, // filled in with __PyObject_GC_Del /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ +#if PYTHON_API_VERSION >= 1012 + 0 /* tp_del */ +#endif +}; + +namespace objects +{ +#if PY_VERSION_HEX < 0x03000000 + // XXX Not sure why this run into compiling error in Python 3 + extern "C" + { + // This declaration needed due to broken Python 2.2 headers + extern DL_IMPORT(PyTypeObject) PyProperty_Type; + } +#endif + + BOOST_PYTHON_DECL PyObject* static_data() + { + if (static_data_object.tp_dict == 0) + { + Py_TYPE(&static_data_object) = &PyType_Type; + static_data_object.tp_base = &PyProperty_Type; + if (PyType_Ready(&static_data_object)) + return 0; + } + return upcast(&static_data_object); + } +} + +extern "C" +{ + // Ordinarily, descriptors have a certain assymetry: you can use + // them to read attributes off the class object they adorn, but + // writing the same attribute on the class object always replaces + // the descriptor in the class __dict__. In order to properly + // represent C++ static data members, we need to allow them to be + // written through the class instance. This function of the + // metaclass makes it possible. + static int + class_setattro(PyObject *obj, PyObject *name, PyObject* value) + { + // Must use "private" Python implementation detail + // _PyType_Lookup instead of PyObject_GetAttr because the + // latter will always end up calling the descr_get function on + // any descriptor it finds; we need the unadulterated + // descriptor here. + PyObject* a = _PyType_Lookup(downcast(obj), name); + + // a is a borrowed reference or 0 + + // If we found a static data descriptor, call it directly to + // force it to set the static data member + if (a != 0 && PyObject_IsInstance(a, objects::static_data())) + return Py_TYPE(a)->tp_descr_set(a, obj, value); + else + return PyType_Type.tp_setattro(obj, name, value); + } +} + +static PyTypeObject class_metatype_object = { + PyVarObject_HEAD_INIT(NULL, 0) + const_cast("Boost.Python.class"), + PyType_Type.tp_basicsize, + 0, + 0, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + class_setattro, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT // | Py_TPFLAGS_HAVE_GC + | Py_TPFLAGS_BASETYPE, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, //&PyType_Type, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + 0, // filled in with type_new /* tp_new */ + 0, // filled in with __PyObject_GC_Del /* tp_free */ + (inquiry)type_is_gc, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ +#if PYTHON_API_VERSION >= 1012 + 0 /* tp_del */ +#endif +}; + +// Install the instance data for a C++ object into a Python instance +// object. +void instance_holder::install(PyObject* self) throw() +{ + assert(PyType_IsSubtype(Py_TYPE(Py_TYPE(self)), &class_metatype_object)); + m_next = ((objects::instance<>*)self)->objects; + ((objects::instance<>*)self)->objects = this; +} + + +namespace objects +{ +// Get the metatype object for all extension classes. + BOOST_PYTHON_DECL type_handle class_metatype() + { + if (class_metatype_object.tp_dict == 0) + { + Py_TYPE(&class_metatype_object) = &PyType_Type; + class_metatype_object.tp_base = &PyType_Type; + if (PyType_Ready(&class_metatype_object)) + return type_handle(); + } + return type_handle(borrowed(&class_metatype_object)); + } + extern "C" + { + static void instance_dealloc(PyObject* inst) + { + instance<>* kill_me = (instance<>*)inst; + + for (instance_holder* p = kill_me->objects, *next; p != 0; p = next) + { + next = p->next(); + p->~instance_holder(); + instance_holder::deallocate(inst, dynamic_cast(p)); + } + + // Python 2.2.1 won't add weak references automatically when + // tp_itemsize > 0, so we need to manage that + // ourselves. Accordingly, we also have to clean up the + // weakrefs ourselves. + if (kill_me->weakrefs != NULL) + PyObject_ClearWeakRefs(inst); + + Py_XDECREF(kill_me->dict); + + Py_TYPE(inst)->tp_free(inst); + } + + static PyObject * + instance_new(PyTypeObject* type_, PyObject* /*args*/, PyObject* /*kw*/) + { + // Attempt to find the __instance_size__ attribute. If not present, no problem. + PyObject* d = type_->tp_dict; + PyObject* instance_size_obj = PyObject_GetAttrString(d, const_cast("__instance_size__")); + + ssize_t instance_size = instance_size_obj ? +#if PY_VERSION_HEX >= 0x03000000 + PyLong_AsSsize_t(instance_size_obj) : 0; +#else + PyInt_AsLong(instance_size_obj) : 0; +#endif + + if (instance_size < 0) + instance_size = 0; + + PyErr_Clear(); // Clear any errors that may have occurred. + + instance<>* result = (instance<>*)type_->tp_alloc(type_, instance_size); + if (result) + { + // Guido says we can use ob_size for any purpose we + // like, so we'll store the total size of the object + // there. A negative number indicates that the extra + // instance memory is not yet allocated to any holders. +#if PY_VERSION_HEX >= 0x02060000 + Py_SIZE(result) = +#else + result->ob_size = +#endif + -(static_cast(offsetof(instance<>,storage) + instance_size)); + } + return (PyObject*)result; + } + + static PyObject* instance_get_dict(PyObject* op, void*) + { + instance<>* inst = downcast >(op); + if (inst->dict == 0) + inst->dict = PyDict_New(); + return python::xincref(inst->dict); + } + + static int instance_set_dict(PyObject* op, PyObject* dict, void*) + { + instance<>* inst = downcast >(op); + python::xdecref(inst->dict); + inst->dict = python::incref(dict); + return 0; + } + + } + + + static PyGetSetDef instance_getsets[] = { + {const_cast("__dict__"), instance_get_dict, instance_set_dict, NULL, 0}, + {0, 0, 0, 0, 0} + }; + + + static PyMemberDef instance_members[] = { + {const_cast("__weakref__"), T_OBJECT, offsetof(instance<>, weakrefs), 0, 0}, + {0, 0, 0, 0, 0} + }; + + static PyTypeObject class_type_object = { + PyVarObject_HEAD_INIT(NULL, 0) + const_cast("Boost.Python.instance"), + offsetof(instance<>,storage), /* tp_basicsize */ + 1, /* tp_itemsize */ + instance_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT // | Py_TPFLAGS_HAVE_GC + | Py_TPFLAGS_BASETYPE, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + offsetof(instance<>,weakrefs), /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + instance_members, /* tp_members */ + instance_getsets, /* tp_getset */ + 0, //&PyBaseObject_Type, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + offsetof(instance<>,dict), /* tp_dictoffset */ + 0, /* tp_init */ + PyType_GenericAlloc, /* tp_alloc */ + instance_new, /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ +#if PYTHON_API_VERSION >= 1012 + 0 /* tp_del */ +#endif + }; + + BOOST_PYTHON_DECL type_handle class_type() + { + if (class_type_object.tp_dict == 0) + { + Py_TYPE(&class_type_object) = incref(class_metatype().get()); + class_type_object.tp_base = &PyBaseObject_Type; + if (PyType_Ready(&class_type_object)) + return type_handle(); +// class_type_object.tp_setattro = class_setattro; + } + return type_handle(borrowed(&class_type_object)); + } + + BOOST_PYTHON_DECL void* + find_instance_impl(PyObject* inst, type_info type, bool null_shared_ptr_only) + { + if (!Py_TYPE(Py_TYPE(inst)) || + !PyType_IsSubtype(Py_TYPE(Py_TYPE(inst)), &class_metatype_object)) + return 0; + + instance<>* self = reinterpret_cast*>(inst); + + for (instance_holder* match = self->objects; match != 0; match = match->next()) + { + void* const found = match->holds(type, null_shared_ptr_only); + if (found) + return found; + } + return 0; + } + + object module_prefix() + { + return object( + PyObject_IsInstance(scope().ptr(), upcast(&PyModule_Type)) + ? object(scope().attr("__name__")) + : api::getattr(scope(), "__module__", str()) + ); + } + + namespace + { + // Find a registered class object corresponding to id. Return a + // null handle if no such class is registered. + inline type_handle query_class(type_info id) + { + converter::registration const* p = converter::registry::query(id); + return type_handle( + python::borrowed( + python::allow_null(p ? p->m_class_object : 0)) + ); + } + + // Find a registered class corresponding to id. If not found, + // throw an appropriate exception. + type_handle get_class(type_info id) + { + type_handle result(query_class(id)); + + if (result.get() == 0) + { + object report("extension class wrapper for base class "); + report = report + id.name() + " has not been created yet"; + PyErr_SetObject(PyExc_RuntimeError, report.ptr()); + throw_error_already_set(); + } + return result; + } + + // class_base constructor + // + // name - the name of the new Python class + // + // num_types - one more than the number of declared bases + // + // types - array of python::type_info, the first item + // corresponding to the class being created, and the + // rest corresponding to its declared bases. + // + inline object + new_class(char const* name, std::size_t num_types, type_info const* const types, char const* doc) + { + assert(num_types >= 1); + + // Build a tuple of the base Python type objects. If no bases + // were declared, we'll use our class_type() as the single base + // class. + ssize_t const num_bases = (std::max)(num_types - 1, static_cast(1)); + handle<> bases(PyTuple_New(num_bases)); + + for (ssize_t i = 1; i <= num_bases; ++i) + { + type_handle c = (i >= static_cast(num_types)) ? class_type() : get_class(types[i]); + // PyTuple_SET_ITEM steals this reference + PyTuple_SET_ITEM(bases.get(), static_cast(i - 1), upcast(c.release())); + } + + // Call the class metatype to create a new class + dict d; + + object m = module_prefix(); + if (m) d["__module__"] = m; + + if (doc != 0) + d["__doc__"] = doc; + + object result = object(class_metatype())(name, bases, d); + assert(PyType_IsSubtype(Py_TYPE(result.ptr()), &PyType_Type)); + + if (scope().ptr() != Py_None) + scope().attr(name) = result; + + // For pickle. Will lead to informative error messages if pickling + // is not enabled. + result.attr("__reduce__") = object(make_instance_reduce_function()); + + return result; + } + } + + class_base::class_base( + char const* name, std::size_t num_types, type_info const* const types, char const* doc) + : object(new_class(name, num_types, types, doc)) + { + // Insert the new class object in the registry + converter::registration& converters = const_cast( + converter::registry::lookup(types[0])); + + // Class object is leaked, for now + converters.m_class_object = (PyTypeObject*)incref(this->ptr()); + } + + BOOST_PYTHON_DECL void copy_class_object(type_info const& src, type_info const& dst) + { + converter::registration& dst_converters + = const_cast(converter::registry::lookup(dst)); + + converter::registration const& src_converters = converter::registry::lookup(src); + + dst_converters.m_class_object = src_converters.m_class_object; + } + + void class_base::set_instance_size(std::size_t instance_size) + { + this->attr("__instance_size__") = instance_size; + } + + void class_base::add_property( + char const* name, object const& fget, char const* docstr) + { + object property( + (python::detail::new_reference) + PyObject_CallFunction((PyObject*)&PyProperty_Type, const_cast("Osss"), fget.ptr(), 0, 0, docstr)); + + this->setattr(name, property); + } + + void class_base::add_property( + char const* name, object const& fget, object const& fset, char const* docstr) + { + object property( + (python::detail::new_reference) + PyObject_CallFunction((PyObject*)&PyProperty_Type, const_cast("OOss"), fget.ptr(), fset.ptr(), 0, docstr)); + + this->setattr(name, property); + } + + void class_base::add_static_property(char const* name, object const& fget) + { + object property( + (python::detail::new_reference) + PyObject_CallFunction(static_data(), const_cast("O"), fget.ptr()) + ); + + this->setattr(name, property); + } + + void class_base::add_static_property(char const* name, object const& fget, object const& fset) + { + object property( + (python::detail::new_reference) + PyObject_CallFunction(static_data(), const_cast("OO"), fget.ptr(), fset.ptr())); + + this->setattr(name, property); + } + + void class_base::setattr(char const* name, object const& x) + { + if (PyObject_SetAttrString(this->ptr(), const_cast(name), x.ptr()) < 0) + throw_error_already_set(); + } + + namespace + { + extern "C" PyObject* no_init(PyObject*, PyObject*) + { + ::PyErr_SetString(::PyExc_RuntimeError, const_cast("This class cannot be instantiated from Python")); + return NULL; + } + static ::PyMethodDef no_init_def = { + const_cast("__init__"), no_init, METH_VARARGS, + const_cast("Raises an exception\n" + "This class cannot be instantiated from Python\n") + }; + } + + void class_base::def_no_init() + { + handle<> f(::PyCFunction_New(&no_init_def, 0)); + this->setattr("__init__", object(f)); + } + + void class_base::enable_pickling_(bool getstate_manages_dict) + { + setattr("__safe_for_unpickling__", object(true)); + + if (getstate_manages_dict) + { + setattr("__getstate_manages_dict__", object(true)); + } + } + + namespace + { + PyObject* callable_check(PyObject* callable) + { + if (PyCallable_Check(expect_non_null(callable))) + return callable; + + ::PyErr_Format( + PyExc_TypeError + , const_cast("staticmethod expects callable object; got an object of type %s, which is not callable") + , Py_TYPE(callable)->tp_name + ); + + throw_error_already_set(); + return 0; + } + } + + void class_base::make_method_static(const char * method_name) + { + PyTypeObject* self = downcast(this->ptr()); + dict d((handle<>(borrowed(self->tp_dict)))); + + object method(d[method_name]); + + this->attr(method_name) = object( + handle<>( + PyStaticMethod_New((callable_check)(method.ptr()) ) + )); + } + + BOOST_PYTHON_DECL type_handle registered_class_object(type_info id) + { + return query_class(id); + } +} // namespace objects + + +void* instance_holder::allocate(PyObject* self_, std::size_t holder_offset, std::size_t holder_size) +{ + assert(PyType_IsSubtype(Py_TYPE(Py_TYPE(self_)), &class_metatype_object)); + objects::instance<>* self = (objects::instance<>*)self_; + + int total_size_needed = holder_offset + holder_size; + + if (-Py_SIZE(self) >= total_size_needed) + { + // holder_offset should at least point into the variable-sized part + assert(holder_offset >= offsetof(objects::instance<>,storage)); + + // Record the fact that the storage is occupied, noting where it starts + Py_SIZE(self) = holder_offset; + return (char*)self + holder_offset; + } + else + { + void* const result = PyMem_Malloc(holder_size); + if (result == 0) + throw std::bad_alloc(); + return result; + } +} + +void instance_holder::deallocate(PyObject* self_, void* storage) throw() +{ + assert(PyType_IsSubtype(Py_TYPE(Py_TYPE(self_)), &class_metatype_object)); + objects::instance<>* self = (objects::instance<>*)self_; + if (storage != (char*)self + Py_SIZE(self)) + { + PyMem_Free(storage); + } +} + +}} // namespace boost::python diff --git a/pykd/boost.python/object/enum.cpp b/pykd/boost.python/object/enum.cpp new file mode 100644 index 0000000..10122ad --- /dev/null +++ b/pykd/boost.python/object/enum.cpp @@ -0,0 +1,252 @@ +// 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost { namespace python { namespace objects { + +struct enum_object +{ +#if PY_VERSION_HEX >= 0x03000000 + PyLongObject base_object; +#else + PyIntObject base_object; +#endif + PyObject* name; +}; + +static PyMemberDef enum_members[] = { + {const_cast("name"), T_OBJECT_EX, offsetof(enum_object,name),READONLY, 0}, + {0, 0, 0, 0, 0} +}; + + +extern "C" +{ + static void + enum_dealloc(enum_object* self) + { + Py_XDECREF(self->name); + Py_TYPE(self)->tp_free((PyObject*)self); + } + + static PyObject* enum_repr(PyObject* self_) + { + PyObject *mod = PyObject_GetAttrString( self_, "__module__"); + object auto_free = object(handle<>(mod)); + enum_object* self = downcast(self_); + if (!self->name) + { + return +#if PY_VERSION_HEX >= 0x03000000 + PyUnicode_FromFormat("%S.%s(%ld)", mod, self_->ob_type->tp_name, PyLong_AsLong(self_)); +#else + PyString_FromFormat("%s.%s(%ld)", PyString_AsString(mod), self_->ob_type->tp_name, PyInt_AS_LONG(self_)); +#endif + } + else + { + PyObject* name = self->name; + if (name == 0) + return 0; + + return +#if PY_VERSION_HEX >= 0x03000000 + PyUnicode_FromFormat("%S.%s.%S", mod, self_->ob_type->tp_name, name); +#else + PyString_FromFormat("%s.%s.%s", + PyString_AsString(mod), self_->ob_type->tp_name, PyString_AsString(name)); +#endif + } + } + + static PyObject* enum_str(PyObject* self_) + { + enum_object* self = downcast(self_); + if (!self->name) + { +#if PY_VERSION_HEX >= 0x03000000 + return PyLong_Type.tp_str(self_); +#else + return PyInt_Type.tp_str(self_); +#endif + } + else + { + return incref(self->name); + } + } +} + +static PyTypeObject enum_type_object = { + PyVarObject_HEAD_INIT(NULL, 0) // &PyType_Type + const_cast("Boost.Python.enum"), + sizeof(enum_object), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor) enum_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + enum_repr, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + enum_str, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT +#if PY_VERSION_HEX < 0x03000000 + | Py_TPFLAGS_CHECKTYPES +#endif + | Py_TPFLAGS_HAVE_GC + | Py_TPFLAGS_BASETYPE, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + enum_members, /* tp_members */ + 0, /* tp_getset */ + 0, //&PyInt_Type, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + 0, /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ +#if PYTHON_API_VERSION >= 1012 + 0 /* tp_del */ +#endif +}; + +object module_prefix(); + +namespace +{ + object new_enum_type(char const* name, char const *doc) + { + if (enum_type_object.tp_dict == 0) + { + Py_TYPE(&enum_type_object) = incref(&PyType_Type); +#if PY_VERSION_HEX >= 0x03000000 + enum_type_object.tp_base = &PyLong_Type; +#else + enum_type_object.tp_base = &PyInt_Type; +#endif + if (PyType_Ready(&enum_type_object)) + throw_error_already_set(); + } + + type_handle metatype(borrowed(&PyType_Type)); + type_handle base(borrowed(&enum_type_object)); + + // suppress the instance __dict__ in these enum objects. There + // may be a slicker way, but this'll do for now. + dict d; + d["__slots__"] = tuple(); + d["values"] = dict(); + d["names"] = dict(); + + object module_name = module_prefix(); + if (module_name) + d["__module__"] = module_name; + if (doc) + d["__doc__"] = doc; + + object result = (object(metatype))(name, make_tuple(base), d); + + scope().attr(name) = result; + + return result; + } +} + +enum_base::enum_base( + char const* name + , converter::to_python_function_t to_python + , converter::convertible_function convertible + , converter::constructor_function construct + , type_info id + , char const *doc + ) + : object(new_enum_type(name, doc)) +{ + converter::registration& converters + = const_cast( + converter::registry::lookup(id)); + + converters.m_class_object = downcast(this->ptr()); + converter::registry::insert(to_python, id); + converter::registry::insert(convertible, construct, id); +} + +void enum_base::add_value(char const* name_, long value) +{ + // Convert name to Python string + object name(name_); + + // Create a new enum instance by calling the class with a value + object x = (*this)(value); + + // Store the object in the enum class + (*this).attr(name_) = x; + + dict d = extract(this->attr("values"))(); + d[value] = x; + + // Set the name field in the new enum instanec + enum_object* p = downcast(x.ptr()); + Py_XDECREF(p->name); + p->name = incref(name.ptr()); + + dict names_dict = extract(this->attr("names"))(); + names_dict[x.attr("name")] = x; +} + +void enum_base::export_values() +{ + dict d = extract(this->attr("names"))(); + list items = d.items(); + scope current; + + for (unsigned i = 0, max = len(items); i < max; ++i) + api::setattr(current, items[i][0], items[i][1]); + } + +PyObject* enum_base::to_python(PyTypeObject* type_, long x) +{ + object type((type_handle(borrowed(type_)))); + + dict d = extract(type.attr("values"))(); + object v = d.get(x, object()); + return incref( + (v == object() ? type(x) : v).ptr()); +} + +}}} // namespace boost::python::object diff --git a/pykd/boost.python/object/function.cpp b/pykd/boost.python/object/function.cpp new file mode 100644 index 0000000..5c59cc7 --- /dev/null +++ b/pykd/boost.python/object/function.cpp @@ -0,0 +1,793 @@ +// 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include + +#if BOOST_PYTHON_DEBUG_ERROR_MESSAGES +# include +#endif + +namespace boost { namespace python { + volatile bool docstring_options::show_user_defined_ = true; + volatile bool docstring_options::show_cpp_signatures_ = true; +#ifndef BOOST_PYTHON_NO_PY_SIGNATURES + volatile bool docstring_options::show_py_signatures_ = true; +#else + volatile bool docstring_options::show_py_signatures_ = false; +#endif +}} + +namespace boost { namespace python { namespace objects { + +py_function_impl_base::~py_function_impl_base() +{ +} + +unsigned py_function_impl_base::max_arity() const +{ + return this->min_arity(); +} + +extern PyTypeObject function_type; + +function::function( + py_function const& implementation +#if BOOST_WORKAROUND(__EDG_VERSION__, == 245) + , python::detail::keyword const* names_and_defaults +#else + , python::detail::keyword const* const names_and_defaults +#endif + , unsigned num_keywords + ) + : m_fn(implementation) + , m_nkeyword_values(0) +{ + if (names_and_defaults != 0) + { + unsigned int max_arity = m_fn.max_arity(); + unsigned int keyword_offset + = max_arity > num_keywords ? max_arity - num_keywords : 0; + + + ssize_t tuple_size = num_keywords ? max_arity : 0; + m_arg_names = object(handle<>(PyTuple_New(tuple_size))); + + if (num_keywords != 0) + { + for (unsigned j = 0; j < keyword_offset; ++j) + PyTuple_SET_ITEM(m_arg_names.ptr(), j, incref(Py_None)); + } + + for (unsigned i = 0; i < num_keywords; ++i) + { + tuple kv; + + python::detail::keyword const* const p = names_and_defaults + i; + if (p->default_value) + { + kv = make_tuple(p->name, p->default_value); + ++m_nkeyword_values; + } + else + { + kv = make_tuple(p->name); + } + + PyTuple_SET_ITEM( + m_arg_names.ptr() + , i + keyword_offset + , incref(kv.ptr()) + ); + } + } + + PyObject* p = this; + if (Py_TYPE(&function_type) == 0) + { + Py_TYPE(&function_type) = &PyType_Type; + ::PyType_Ready(&function_type); + } + + (void)( // warning suppression for GCC + PyObject_INIT(p, &function_type) + ); +} + +function::~function() +{ +} + +PyObject* function::call(PyObject* args, PyObject* keywords) const +{ + std::size_t n_unnamed_actual = PyTuple_GET_SIZE(args); + std::size_t n_keyword_actual = keywords ? PyDict_Size(keywords) : 0; + std::size_t n_actual = n_unnamed_actual + n_keyword_actual; + + function const* f = this; + + // Try overloads looking for a match + do + { + // Check for a plausible number of arguments + unsigned min_arity = f->m_fn.min_arity(); + unsigned max_arity = f->m_fn.max_arity(); + + if (n_actual + f->m_nkeyword_values >= min_arity + && n_actual <= max_arity) + { + // This will be the args that actually get passed + handle<>inner_args(allow_null(borrowed(args))); + + if (n_keyword_actual > 0 // Keyword arguments were supplied + || n_actual < min_arity) // or default keyword values are needed + { + if (f->m_arg_names.is_none()) + { + // this overload doesn't accept keywords + inner_args = handle<>(); + } + else + { + // "all keywords are none" is a special case + // indicating we will accept any number of keyword + // arguments + if (PyTuple_Size(f->m_arg_names.ptr()) == 0) + { + // no argument preprocessing + } + else if (n_actual > max_arity) + { + // too many arguments + inner_args = handle<>(); + } + else + { + // build a new arg tuple, will adjust its size later + assert(max_arity <= static_cast(ssize_t_max)); + inner_args = handle<>( + PyTuple_New(static_cast(max_arity))); + + // Fill in the positional arguments + for (std::size_t i = 0; i < n_unnamed_actual; ++i) + PyTuple_SET_ITEM(inner_args.get(), i, incref(PyTuple_GET_ITEM(args, i))); + + // Grab remaining arguments by name from the keyword dictionary + std::size_t n_actual_processed = n_unnamed_actual; + + for (std::size_t arg_pos = n_unnamed_actual; arg_pos < max_arity ; ++arg_pos) + { + // Get the keyword[, value pair] corresponding + PyObject* kv = PyTuple_GET_ITEM(f->m_arg_names.ptr(), arg_pos); + + // If there were any keyword arguments, + // look up the one we need for this + // argument position + PyObject* value = n_keyword_actual + ? PyDict_GetItem(keywords, PyTuple_GET_ITEM(kv, 0)) + : 0; + + if (!value) + { + // Not found; check if there's a default value + if (PyTuple_GET_SIZE(kv) > 1) + value = PyTuple_GET_ITEM(kv, 1); + + if (!value) + { + // still not found; matching fails + PyErr_Clear(); + inner_args = handle<>(); + break; + } + } + else + { + ++n_actual_processed; + } + + PyTuple_SET_ITEM(inner_args.get(), arg_pos, incref(value)); + } + + if (inner_args.get()) + { + //check if we proccessed all the arguments + if(n_actual_processed < n_actual) + inner_args = handle<>(); + } + } + } + } + + // Call the function. Pass keywords in case it's a + // function accepting any number of keywords + PyObject* result = inner_args ? f->m_fn(inner_args.get(), keywords) : 0; + + // If the result is NULL but no error was set, m_fn failed + // the argument-matching test. + + // This assumes that all other error-reporters are + // well-behaved and never return NULL to python without + // setting an error. + if (result != 0 || PyErr_Occurred()) + return result; + } + f = f->m_overloads.get(); + } + while (f); + // None of the overloads matched; time to generate the error message + argument_error(args, keywords); + return 0; +} + +object function::signature(bool show_return_type) const +{ + py_function const& impl = m_fn; + + python::detail::signature_element const* return_type = impl.signature(); + python::detail::signature_element const* s = return_type + 1; + + list formal_params; + if (impl.max_arity() == 0) + formal_params.append("void"); + + for (unsigned n = 0; n < impl.max_arity(); ++n) + { + if (s[n].basename == 0) + { + formal_params.append("..."); + break; + } + + str param(s[n].basename); + if (s[n].lvalue) + param += " {lvalue}"; + + if (m_arg_names) // None or empty tuple will test false + { + object kv(m_arg_names[n]); + if (kv) + { + char const* const fmt = len(kv) > 1 ? " %s=%r" : " %s"; + param += fmt % kv; + } + } + + formal_params.append(param); + } + + if (show_return_type) + return "%s(%s) -> %s" % make_tuple( + m_name, str(", ").join(formal_params), return_type->basename); + return "%s(%s)" % make_tuple( + m_name, str(", ").join(formal_params)); +} + +object function::signatures(bool show_return_type) const +{ + list result; + for (function const* f = this; f; f = f->m_overloads.get()) { + result.append(f->signature(show_return_type)); + } + return result; +} + +void function::argument_error(PyObject* args, PyObject* /*keywords*/) const +{ + static handle<> exception( + PyErr_NewException(const_cast("Boost.Python.ArgumentError"), PyExc_TypeError, 0)); + + object message = "Python argument types in\n %s.%s(" + % make_tuple(this->m_namespace, this->m_name); + + list actual_args; + for (ssize_t i = 0; i < PyTuple_Size(args); ++i) + { + char const* name = PyTuple_GetItem(args, i)->ob_type->tp_name; + actual_args.append(str(name)); + } + message += str(", ").join(actual_args); + message += ")\ndid not match C++ signature:\n "; + message += str("\n ").join(signatures()); + +#if BOOST_PYTHON_DEBUG_ERROR_MESSAGES + std::printf("\n--------\n%s\n--------\n", extract(message)()); +#endif + PyErr_SetObject(exception.get(), message.ptr()); + throw_error_already_set(); +} + +void function::add_overload(handle const& overload_) +{ + function* parent = this; + + while (parent->m_overloads) + parent = parent->m_overloads.get(); + + parent->m_overloads = overload_; + + // If we have no documentation, get the docs from the overload + if (!m_doc) + m_doc = overload_->m_doc; +} + +namespace +{ + char const* const binary_operator_names[] = + { + "add__", + "and__", + "div__", + "divmod__", + "eq__", + "floordiv__", + "ge__", + "gt__", + "le__", + "lshift__", + "lt__", + "mod__", + "mul__", + "ne__", + "or__", + "pow__", + "radd__", + "rand__", + "rdiv__", + "rdivmod__", + "rfloordiv__", + "rlshift__", + "rmod__", + "rmul__", + "ror__", + "rpow__", + "rrshift__", + "rshift__", + "rsub__", + "rtruediv__", + "rxor__", + "sub__", + "truediv__", + "xor__" + }; + + struct less_cstring + { + bool operator()(char const* x, char const* y) const + { + return BOOST_CSTD_::strcmp(x,y) < 0; + } + }; + + inline bool is_binary_operator(char const* name) + { + return name[0] == '_' + && name[1] == '_' + && std::binary_search( + &binary_operator_names[0] + , binary_operator_names + sizeof(binary_operator_names)/sizeof(*binary_operator_names) + , name + 2 + , less_cstring() + ); + } + + // Something for the end of the chain of binary operators + PyObject* not_implemented(PyObject*, PyObject*) + { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + + handle not_implemented_function() + { + + static object keeper( + function_object( + py_function(¬_implemented, mpl::vector1(), 2) + , python::detail::keyword_range()) + ); + return handle(borrowed(downcast(keeper.ptr()))); + } +} + +void function::add_to_namespace( + object const& name_space, char const* name_, object const& attribute) +{ + add_to_namespace(name_space, name_, attribute, 0); +} + +namespace detail +{ + extern char py_signature_tag[]; + extern char cpp_signature_tag[]; +} + +void function::add_to_namespace( + object const& name_space, char const* name_, object const& attribute, char const* doc) +{ + str const name(name_); + PyObject* const ns = name_space.ptr(); + + if (attribute.ptr()->ob_type == &function_type) + { + function* new_func = downcast(attribute.ptr()); + handle<> dict; + +#if PY_VERSION_HEX < 0x03000000 + // Old-style class gone in Python 3 + if (PyClass_Check(ns)) + dict = handle<>(borrowed(((PyClassObject*)ns)->cl_dict)); + else +#endif + if (PyType_Check(ns)) + dict = handle<>(borrowed(((PyTypeObject*)ns)->tp_dict)); + else + dict = handle<>(PyObject_GetAttrString(ns, const_cast("__dict__"))); + + if (dict == 0) + throw_error_already_set(); + + handle<> existing(allow_null(::PyObject_GetItem(dict.get(), name.ptr()))); + + if (existing) + { + if (existing->ob_type == &function_type) + { + new_func->add_overload( + handle( + borrowed( + downcast(existing.get()) + ) + ) + ); + } + else if (existing->ob_type == &PyStaticMethod_Type) + { + char const* name_space_name = extract(name_space.attr("__name__")); + + ::PyErr_Format( + PyExc_RuntimeError + , "Boost.Python - All overloads must be exported " + "before calling \'class_<...>(\"%s\").staticmethod(\"%s\")\'" + , name_space_name + , name_ + ); + throw_error_already_set(); + } + } + else if (is_binary_operator(name_)) + { + // Binary operators need an additional overload which + // returns NotImplemented, so that Python will try the + // __rxxx__ functions on the other operand. We add this + // when no overloads for the operator already exist. + new_func->add_overload(not_implemented_function()); + } + + // A function is named the first time it is added to a namespace. + if (new_func->name().is_none()) + new_func->m_name = name; + + handle<> name_space_name( + allow_null(::PyObject_GetAttrString(name_space.ptr(), const_cast("__name__")))); + + if (name_space_name) + new_func->m_namespace = object(name_space_name); + } + + // The PyObject_GetAttrString() or PyObject_GetItem calls above may + // have left an active error + PyErr_Clear(); + if (PyObject_SetAttr(ns, name.ptr(), attribute.ptr()) < 0) + throw_error_already_set(); + + object mutable_attribute(attribute); +/* + if (doc != 0 && docstring_options::show_user_defined_) + { + // Accumulate documentation + + if ( + PyObject_HasAttrString(mutable_attribute.ptr(), "__doc__") + && mutable_attribute.attr("__doc__")) + { + mutable_attribute.attr("__doc__") += "\n\n"; + mutable_attribute.attr("__doc__") += doc; + } + else { + mutable_attribute.attr("__doc__") = doc; + } + } + + if (docstring_options::show_signatures_) + { + if ( PyObject_HasAttrString(mutable_attribute.ptr(), "__doc__") + && mutable_attribute.attr("__doc__")) { + mutable_attribute.attr("__doc__") += ( + mutable_attribute.attr("__doc__")[-1] != "\n" ? "\n\n" : "\n"); + } + else { + mutable_attribute.attr("__doc__") = ""; + } + function* f = downcast(attribute.ptr()); + mutable_attribute.attr("__doc__") += str("\n ").join(make_tuple( + "C++ signature:", f->signature(true))); + } + */ + str _doc; + + if (docstring_options::show_py_signatures_) + { + _doc += str(const_cast(detail::py_signature_tag)); + } + if (doc != 0 && docstring_options::show_user_defined_) + _doc += doc; + + if (docstring_options::show_cpp_signatures_) + { + _doc += str(const_cast(detail::cpp_signature_tag)); + } + if(_doc) + { + object mutable_attribute(attribute); + mutable_attribute.attr("__doc__")= _doc; + } +} + +BOOST_PYTHON_DECL void add_to_namespace( + object const& name_space, char const* name, object const& attribute) +{ + function::add_to_namespace(name_space, name, attribute, 0); +} + +BOOST_PYTHON_DECL void add_to_namespace( + object const& name_space, char const* name, object const& attribute, char const* doc) +{ + function::add_to_namespace(name_space, name, attribute, doc); +} + + +namespace +{ + struct bind_return + { + bind_return(PyObject*& result, function const* f, PyObject* args, PyObject* keywords) + : m_result(result) + , m_f(f) + , m_args(args) + , m_keywords(keywords) + {} + + void operator()() const + { + m_result = m_f->call(m_args, m_keywords); + } + + private: + PyObject*& m_result; + function const* m_f; + PyObject* m_args; + PyObject* m_keywords; + }; +} + +extern "C" +{ + // Stolen from Python's funcobject.c + static PyObject * + function_descr_get(PyObject *func, PyObject *obj, PyObject *type_) + { +#if PY_VERSION_HEX >= 0x03000000 + // The implement is different in Python 3 because of the removal of unbound method + if (obj == Py_None || obj == NULL) { + Py_INCREF(func); + return func; + } + return PyMethod_New(func, obj); +#else + if (obj == Py_None) + obj = NULL; + return PyMethod_New(func, obj, type_); +#endif + } + + static void + function_dealloc(PyObject* p) + { + delete static_cast(p); + } + + static PyObject * + function_call(PyObject *func, PyObject *args, PyObject *kw) + { + PyObject* result = 0; + handle_exception(bind_return(result, static_cast(func), args, kw)); + return result; + } + + // + // Here we're using the function's tp_getset rather than its + // tp_members to set up __doc__ and __name__, because tp_members + // really depends on having a POD object type (it relies on + // offsets). It might make sense to reformulate function as a POD + // at some point, but this is much more expedient. + // + static PyObject* function_get_doc(PyObject* op, void*) + { + function* f = downcast(op); + list signatures = function_doc_signature_generator::function_doc_signatures(f); + if(!signatures) return python::detail::none(); + signatures.reverse(); + return python::incref( str("\n").join(signatures).ptr()); + } + + static int function_set_doc(PyObject* op, PyObject* doc, void*) + { + function* f = downcast(op); + f->doc(doc ? object(python::detail::borrowed_reference(doc)) : object()); + return 0; + } + + static PyObject* function_get_name(PyObject* op, void*) + { + function* f = downcast(op); + if (f->name().is_none()) +#if PY_VERSION_HEX >= 0x03000000 + return PyUnicode_InternFromString(""); +#else + return PyString_InternFromString(""); +#endif + else + return python::incref(f->name().ptr()); + } + + // We add a dummy __class__ attribute in order to fool PyDoc into + // treating these as built-in functions and scanning their + // documentation + static PyObject* function_get_class(PyObject* /*op*/, void*) + { + return python::incref(upcast(&PyCFunction_Type)); + } + + static PyObject* function_get_module(PyObject* op, void*) + { + function* f = downcast(op); + object const& ns = f->get_namespace(); + if (!ns.is_none()) { + return python::incref(ns.ptr()); + } + PyErr_SetString( + PyExc_AttributeError, const_cast( + "Boost.Python function __module__ unknown.")); + return 0; + } +} + +static PyGetSetDef function_getsetlist[] = { + {const_cast("__name__"), (getter)function_get_name, 0, 0, 0 }, + {const_cast("func_name"), (getter)function_get_name, 0, 0, 0 }, + {const_cast("__module__"), (getter)function_get_module, 0, 0, 0 }, + {const_cast("func_module"), (getter)function_get_module, 0, 0, 0 }, + {const_cast("__class__"), (getter)function_get_class, 0, 0, 0 }, // see note above + {const_cast("__doc__"), (getter)function_get_doc, (setter)function_set_doc, 0, 0}, + {const_cast("func_doc"), (getter)function_get_doc, (setter)function_set_doc, 0, 0}, + {NULL, 0, 0, 0, 0} /* Sentinel */ +}; + +PyTypeObject function_type = { + PyVarObject_HEAD_INIT(NULL, 0) + const_cast("Boost.Python.function"), + sizeof(function), + 0, + (destructor)function_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, //(reprfunc)func_repr, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + function_call, /* tp_call */ + 0, /* tp_str */ + 0, // PyObject_GenericGetAttr, /* tp_getattro */ + 0, // PyObject_GenericSetAttr, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT /* | Py_TPFLAGS_HAVE_GC */,/* tp_flags */ + 0, /* tp_doc */ + 0, // (traverseproc)func_traverse, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, //offsetof(PyFunctionObject, func_weakreflist), /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, // func_memberlist, /* tp_members */ + function_getsetlist, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + function_descr_get, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, //offsetof(PyFunctionObject, func_dict), /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + 0, /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ +#if PYTHON_API_VERSION >= 1012 + 0 /* tp_del */ +#endif +}; + +object function_object( + py_function const& f + , python::detail::keyword_range const& keywords) +{ + return python::object( + python::detail::new_non_null_reference( + new function( + f, keywords.first, keywords.second - keywords.first))); +} + +object function_object(py_function const& f) +{ + return function_object(f, python::detail::keyword_range()); +} + + +handle<> function_handle_impl(py_function const& f) +{ + return python::handle<>( + allow_null( + new function(f, 0, 0))); +} + +} // namespace objects + +namespace detail +{ + object BOOST_PYTHON_DECL make_raw_function(objects::py_function f) + { + static keyword k; + + return objects::function_object( + f + , keyword_range(&k,&k)); + } + void BOOST_PYTHON_DECL pure_virtual_called() + { + PyErr_SetString( + PyExc_RuntimeError, const_cast("Pure virtual function called")); + throw_error_already_set(); + } +} + +}} // namespace boost::python diff --git a/pykd/boost.python/object/function_doc_signature.cpp b/pykd/boost.python/object/function_doc_signature.cpp new file mode 100644 index 0000000..4169528 --- /dev/null +++ b/pykd/boost.python/object/function_doc_signature.cpp @@ -0,0 +1,344 @@ +// Copyright Nikolay Mladenov 2007. +// 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) + +// boost::python::make_tuple below are for gcc 4.4 -std=c++0x compatibility +// (Intel C++ 10 and 11 with -std=c++0x don't need the full qualification). + +#include +#include +#include +#include +#include +#include + +#include + +#include + +namespace boost { namespace python { namespace objects { + + bool function_doc_signature_generator::arity_cmp( function const *f1, function const *f2 ) + { + return f1->m_fn.max_arity() < f2->m_fn.max_arity(); + } + + bool function_doc_signature_generator::are_seq_overloads( function const *f1, function const *f2 , bool check_docs) + { + py_function const & impl1 = f1->m_fn; + py_function const & impl2 = f2->m_fn; + + //the number of parameters differs by 1 + if (impl2.max_arity()-impl1.max_arity() != 1) + return false; + + // if check docs then f1 shold not have docstring or have the same docstring as f2 + if (check_docs && f2->doc() != f1->doc() && f1->doc()) + return false; + + python::detail::signature_element const* s1 = impl1.signature(); + python::detail::signature_element const* s2 = impl2.signature(); + + unsigned size = impl1.max_arity()+1; + + for (unsigned i = 0; i != size; ++i) + { + //check if the argument types are the same + if (s1[i].basename != s2[i].basename) + return false; + + //return type + if (!i) continue; + + //check if the argument default values are the same + bool f1_has_names = bool(f1->m_arg_names); + bool f2_has_names = bool(f2->m_arg_names); + if ( (f1_has_names && f2_has_names && f2->m_arg_names[i-1]!=f1->m_arg_names[i-1]) + || (f1_has_names && !f2_has_names) + || (!f1_has_names && f2_has_names && f2->m_arg_names[i-1]!=python::object()) + ) + return false; + } + return true; + } + + std::vector function_doc_signature_generator::flatten(function const *f) + { + object name = f->name(); + + std::vector res; + + while (f) { + + //this if takes out the not_implemented_function + if (f->name() == name) + res.push_back(f); + + f=f->m_overloads.get(); + } + + //std::sort(res.begin(),res.end(), &arity_cmp); + + return res; + } + std::vector function_doc_signature_generator::split_seq_overloads( const std::vector &funcs, bool split_on_doc_change) + { + std::vector res; + + std::vector::const_iterator fi = funcs.begin(); + + function const * last = *fi; + + while (++fi != funcs.end()){ + + //check if fi starts a new chain of overloads + if (!are_seq_overloads( last, *fi, split_on_doc_change )) + res.push_back(last); + + last = *fi; + } + + if (last) + res.push_back(last); + + return res; + } + + str function_doc_signature_generator::raw_function_pretty_signature(function const *f, size_t n_overloads, bool cpp_types ) + { + str res("object"); + + res = str("%s %s(%s)" % make_tuple( res, f->m_name, str("tuple args, dict kwds")) ); + + return res; + } + + const char * function_doc_signature_generator::py_type_str(const python::detail::signature_element &s) + { + if (s.basename==std::string("void")){ + static const char * none = "None"; + return none; + } + + PyTypeObject const * py_type = s.pytype_f?s.pytype_f():0; + if ( py_type ) + return py_type->tp_name; + else{ + static const char * object = "object"; + return object; + } + } + + str function_doc_signature_generator::parameter_string(py_function const &f, size_t n, object arg_names, bool cpp_types) + { + str param; + + python::detail::signature_element const * s = f.signature(); + if (cpp_types) + { + if(!n) + s = &f.get_return_type(); + if (s[n].basename == 0) + { + return str("..."); + } + + param = str(s[n].basename); + + if (s[n].lvalue) + param += " {lvalue}"; + + } + else + { + if (n) //we are processing an argument and trying to come up with a name for it + { + object kv; + if ( arg_names && (kv = arg_names[n-1]) ) + param = str( " (%s)%s" % make_tuple(py_type_str(s[n]),kv[0]) ); + else + param = str(" (%s)%s%d" % make_tuple(py_type_str(s[n]),"arg", n) ); + } + else //we are processing the return type + param = py_type_str(f.get_return_type()); + } + + //an argument - check for default value and append it + if(n && arg_names) + { + object kv(arg_names[n-1]); + if (kv && len(kv) == 2) + { + param = str("%s=%r" % make_tuple(param, kv[1])); + } + } + return param; + } + + str function_doc_signature_generator::pretty_signature(function const *f, size_t n_overloads, bool cpp_types ) + { + py_function + const& impl = f->m_fn; + ; + + + unsigned arity = impl.max_arity(); + + if(arity == unsigned(-1))// is this the proper raw function test? + { + return raw_function_pretty_signature(f,n_overloads,cpp_types); + } + + list formal_params; + + size_t n_extra_default_args=0; + + for (unsigned n = 0; n <= arity; ++n) + { + str param; + + formal_params.append( + parameter_string(impl, n, f->m_arg_names, cpp_types) + ); + + // find all the arguments with default values preceeding the arity-n_overloads + if (n && f->m_arg_names) + { + object kv(f->m_arg_names[n-1]); + + if (kv && len(kv) == 2) + { + //default argument preceeding the arity-n_overloads + if( n <= arity-n_overloads) + ++n_extra_default_args; + } + else + //argument without default, preceeding the arity-n_overloads + if( n <= arity-n_overloads) + n_extra_default_args = 0; + } + } + + n_overloads+=n_extra_default_args; + + if (!arity && cpp_types) + formal_params.append("void"); + + str ret_type (formal_params.pop(0)); + if (cpp_types ) + { + return str( + "%s %s(%s%s%s%s)" + % boost::python::make_tuple // workaround, see top + ( ret_type + , f->m_name + , str(",").join(formal_params.slice(0,arity-n_overloads)) + , n_overloads ? (n_overloads!=arity?str(" [,"):str("[ ")) : str() + , str(" [,").join(formal_params.slice(arity-n_overloads,arity)) + , std::string(n_overloads,']') + )); + }else{ + return str( + "%s(%s%s%s%s) -> %s" + % boost::python::make_tuple // workaround, see top + ( f->m_name + , str(",").join(formal_params.slice(0,arity-n_overloads)) + , n_overloads ? (n_overloads!=arity?str(" [,"):str("[ ")) : str() + , str(" [,").join(formal_params.slice(arity-n_overloads,arity)) + , std::string(n_overloads,']') + , ret_type + )); + } + + return str( + "%s %s(%s%s%s%s) %s" + % boost::python::make_tuple // workaround, see top + ( cpp_types?ret_type:str("") + , f->m_name + , str(",").join(formal_params.slice(0,arity-n_overloads)) + , n_overloads ? (n_overloads!=arity?str(" [,"):str("[ ")) : str() + , str(" [,").join(formal_params.slice(arity-n_overloads,arity)) + , std::string(n_overloads,']') + , cpp_types?str(""):ret_type + )); + + } + + namespace detail { + char py_signature_tag[] = "PY signature :"; + char cpp_signature_tag[] = "C++ signature :"; + } + + list function_doc_signature_generator::function_doc_signatures( function const * f) + { + list signatures; + std::vector funcs = flatten( f); + std::vector split_funcs = split_seq_overloads( funcs, true); + std::vector::const_iterator sfi=split_funcs.begin(), fi; + size_t n_overloads=0; + for (fi=funcs.begin(); fi!=funcs.end(); ++fi) + { + if(*sfi == *fi){ + if((*fi)->doc()) + { + str func_doc = str((*fi)->doc()); + + int doc_len = len(func_doc); + + bool show_py_signature = doc_len >= int(sizeof(detail::py_signature_tag)/sizeof(char)-1) + && str(detail::py_signature_tag) == func_doc.slice(0, int(sizeof(detail::py_signature_tag)/sizeof(char))-1); + if(show_py_signature) + { + func_doc = str(func_doc.slice(int(sizeof(detail::py_signature_tag)/sizeof(char))-1, _)); + doc_len = len(func_doc); + } + + bool show_cpp_signature = doc_len >= int(sizeof(detail::cpp_signature_tag)/sizeof(char)-1) + && str(detail::cpp_signature_tag) == func_doc.slice( 1-int(sizeof(detail::cpp_signature_tag)/sizeof(char)), _); + + if(show_cpp_signature) + { + func_doc = str(func_doc.slice(_, 1-int(sizeof(detail::cpp_signature_tag)/sizeof(char)))); + doc_len = len(func_doc); + } + + str res="\n"; + str pad = "\n"; + + if(show_py_signature) + { + str sig = pretty_signature(*fi, n_overloads,false); + res+=sig; + if(doc_len || show_cpp_signature )res+=" :"; + pad+= str(" "); + } + + if(doc_len) + { + if(show_py_signature) + res+=pad; + res+= pad.join(func_doc.split("\n")); + } + + if( show_cpp_signature) + { + if(len(res)>1) + res+="\n"+pad; + res+=detail::cpp_signature_tag+pad+" "+pretty_signature(*fi, n_overloads,true); + } + + signatures.append(res); + } + ++sfi; + n_overloads = 0; + }else + ++n_overloads ; + } + + return signatures; + } + + +}}} + diff --git a/pykd/boost.python/object/inheritance.cpp b/pykd/boost.python/object/inheritance.cpp new file mode 100644 index 0000000..7dc9db1 --- /dev/null +++ b/pykd/boost.python/object/inheritance.cpp @@ -0,0 +1,495 @@ +// 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 +#include +#include +#if _MSC_FULL_VER >= 13102171 && _MSC_FULL_VER <= 13102179 +# include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// +// Procedure: +// +// The search is a BFS over the space of (type,address) pairs +// guided by the edges of the casting graph whose nodes +// correspond to classes, and whose edges are traversed by +// applying associated cast functions to an address. We use +// vertex distance to the goal node in the cast_graph to rate the +// paths. The vertex distance to any goal node is calculated on +// demand and outdated by the addition of edges to the graph. + +namespace boost { +namespace +{ + enum edge_cast_t { edge_cast = 8010 }; + template inline void unused_variable(const T&) { } +} + +// Install properties +BOOST_INSTALL_PROPERTY(edge, cast); + +namespace +{ + typedef void*(*cast_function)(void*); + + // + // Here we put together the low-level data structures of the + // casting graph representation. + // + typedef python::type_info class_id; + + // represents a graph of available casts + +#if 0 + struct cast_graph + : +#else + typedef +#endif + adjacency_list > > +#if 0 + {}; +#else + cast_graph; +#endif + + typedef cast_graph::vertex_descriptor vertex_t; + typedef cast_graph::edge_descriptor edge_t; + + struct smart_graph + { + typedef std::vector::const_iterator node_distance_map; + + typedef std::pair out_edges_t; + + // Return a map of the distances from any node to the given + // target node + node_distance_map distances_to(vertex_t target) const + { + std::size_t n = num_vertices(m_topology); + if (m_distances.size() != n * n) + { + m_distances.clear(); + m_distances.resize(n * n, (std::numeric_limits::max)()); + m_known_vertices = n; + } + + std::vector::iterator to_target = m_distances.begin() + n * target; + + // this node hasn't been used as a target yet + if (to_target[target] != 0) + { + typedef reverse_graph reverse_cast_graph; + reverse_cast_graph reverse_topology(m_topology); + + to_target[target] = 0; + + breadth_first_search( + reverse_topology, target + , visitor( + make_bfs_visitor( + record_distances( + make_iterator_property_map( + to_target + , get(vertex_index, reverse_topology) +# ifdef BOOST_NO_STD_ITERATOR_TRAITS + , *to_target +# endif + ) + , on_tree_edge() + )))); + } + + return to_target; + } + + cast_graph& topology() { return m_topology; } + cast_graph const& topology() const { return m_topology; } + + smart_graph() + : m_known_vertices(0) + {} + + private: + cast_graph m_topology; + mutable std::vector m_distances; + mutable std::size_t m_known_vertices; + }; + + smart_graph& full_graph() + { + static smart_graph x; + return x; + } + + smart_graph& up_graph() + { + static smart_graph x; + return x; + } + + // + // Our index of class types + // + using boost::python::objects::dynamic_id_function; + typedef tuples::tuple< + class_id // static type + , vertex_t // corresponding vertex + , dynamic_id_function // dynamic_id if polymorphic, or 0 + > + index_entry_interface; + typedef index_entry_interface::inherited index_entry; + enum { ksrc_static_t, kvertex, kdynamic_id }; + + typedef std::vector type_index_t; + + + type_index_t& type_index() + { + static type_index_t x; + return x; + } + + template + struct select1st + { + typedef typename tuples::element<0, Tuple>::type result_type; + + result_type const& operator()(Tuple const& x) const + { + return tuples::get<0>(x); + } + }; + + // map a type to a position in the index + inline type_index_t::iterator type_position(class_id type) + { + typedef index_entry entry; + + return std::lower_bound( + type_index().begin(), type_index().end() + , boost::make_tuple(type, vertex_t(), dynamic_id_function(0)) + , boost::bind(std::less() + , boost::bind(select1st(), _1) + , boost::bind(select1st(), _2))); + } + + inline index_entry* seek_type(class_id type) + { + type_index_t::iterator p = type_position(type); + if (p == type_index().end() || tuples::get(*p) != type) + return 0; + else + return &*p; + } + + // Get the entry for a type, inserting if necessary + inline type_index_t::iterator demand_type(class_id type) + { + type_index_t::iterator p = type_position(type); + + if (p != type_index().end() && tuples::get(*p) == type) + return p; + + vertex_t v = add_vertex(full_graph().topology()); + vertex_t v2 = add_vertex(up_graph().topology()); + unused_variable(v2); + assert(v == v2); + return type_index().insert(p, boost::make_tuple(type, v, dynamic_id_function(0))); + } + + // Map a two types to a vertex in the graph, inserting if necessary + typedef std::pair + type_index_iterator_pair; + + inline type_index_iterator_pair + demand_types(class_id t1, class_id t2) + { + // be sure there will be no reallocation + type_index().reserve(type_index().size() + 2); + type_index_t::iterator first = demand_type(t1); + type_index_t::iterator second = demand_type(t2); + if (first == second) + ++first; + return std::make_pair(first, second); + } + + struct q_elt + { + q_elt(std::size_t distance + , void* src_address + , vertex_t target + , cast_function cast + ) + : distance(distance) + , src_address(src_address) + , target(target) + , cast(cast) + {} + + std::size_t distance; + void* src_address; + vertex_t target; + cast_function cast; + + bool operator<(q_elt const& rhs) const + { + return distance < rhs.distance; + } + }; + + // Optimization: + // + // Given p, src_t, dst_t + // + // Get a pointer pd to the most-derived object + // if it's polymorphic, dynamic_cast to void* + // otherwise pd = p + // + // Get the most-derived typeid src_td + // + // ptrdiff_t offset = p - pd + // + // Now we can keep a cache, for [src_t, offset, src_td, dst_t] of + // the cast transformation function to use on p and the next src_t + // in the chain. src_td, dst_t don't change throughout this + // process. In order to represent unreachability, when a pair is + // found to be unreachable, we stick a 0-returning "dead-cast" + // function in the cache. + + // This is needed in a few places below + inline void* identity_cast(void* p) + { + return p; + } + + void* search(smart_graph const& g, void* p, vertex_t src, vertex_t dst) + { + // I think this test was thoroughly bogus -- dwa + // If we know there's no path; bail now. + // if (src > g.known_vertices() || dst > g.known_vertices()) + // return 0; + + smart_graph::node_distance_map d(g.distances_to(dst)); + + if (d[src] == (std::numeric_limits::max)()) + return 0; + + typedef property_map::const_type cast_map; + cast_map casts = get(edge_cast, g.topology()); + + typedef std::pair search_state; + typedef std::vector visited_t; + visited_t visited; + std::priority_queue q; + + q.push(q_elt(d[src], p, src, identity_cast)); + while (!q.empty()) + { + q_elt top = q.top(); + q.pop(); + + // Check to see if we have a real state + void* dst_address = top.cast(top.src_address); + if (dst_address == 0) + continue; + + if (top.target == dst) + return dst_address; + + search_state s(top.target,dst_address); + + visited_t::iterator pos = std::lower_bound( + visited.begin(), visited.end(), s); + + // If already visited, continue + if (pos != visited.end() && *pos == s) + continue; + + visited.insert(pos, s); // mark it + + // expand it: + smart_graph::out_edges_t edges = out_edges(s.first, g.topology()); + for (cast_graph::out_edge_iterator p = edges.first + , finish = edges.second + ; p != finish + ; ++p + ) + { + edge_t e = *p; + q.push(q_elt( + d[target(e, g.topology())] + , dst_address + , target(e, g.topology()) + , boost::get(casts, e))); + } + } + return 0; + } + + struct cache_element + { + typedef tuples::tuple< + class_id // source static type + , class_id // target type + , std::ptrdiff_t // offset within source object + , class_id // source dynamic type + >::inherited key_type; + + cache_element(key_type const& k) + : key(k) + , offset(0) + {} + + key_type key; + std::ptrdiff_t offset; + + BOOST_STATIC_CONSTANT( + std::ptrdiff_t, not_found = integer_traits::const_min); + + bool operator<(cache_element const& rhs) const + { + return this->key < rhs.key; + } + + bool unreachable() const + { + return offset == not_found; + } + }; + + enum { kdst_t = ksrc_static_t + 1, koffset, ksrc_dynamic_t }; + typedef std::vector cache_t; + + cache_t& cache() + { + static cache_t x; + return x; + } + + inline void* convert_type(void* const p, class_id src_t, class_id dst_t, bool polymorphic) + { + // Quickly rule out unregistered types + index_entry* src_p = seek_type(src_t); + if (src_p == 0) + return 0; + + index_entry* dst_p = seek_type(dst_t); + if (dst_p == 0) + return 0; + + // Look up the dynamic_id function and call it to get the dynamic + // info + boost::python::objects::dynamic_id_t dynamic_id = polymorphic + ? tuples::get(*src_p)(p) + : std::make_pair(p, src_t); + + // Look in the cache first for a quickie address translation + std::ptrdiff_t offset = (char*)p - (char*)dynamic_id.first; + + cache_element seek(boost::make_tuple(src_t, dst_t, offset, dynamic_id.second)); + cache_t& c = cache(); + cache_t::iterator const cache_pos + = std::lower_bound(c.begin(), c.end(), seek); + + + // if found in the cache, we're done + if (cache_pos != c.end() && cache_pos->key == seek.key) + { + return cache_pos->offset == cache_element::not_found + ? 0 : (char*)p + cache_pos->offset; + } + + // If we are starting at the most-derived type, only look in the up graph + smart_graph const& g = polymorphic && dynamic_id.second != src_t + ? full_graph() : up_graph(); + + void* result = search( + g, p, tuples::get(*src_p) + , tuples::get(*dst_p)); + + // update the cache + c.insert(cache_pos, seek)->offset + = (result == 0) ? cache_element::not_found : (char*)result - (char*)p; + + return result; + } +} + +namespace python { namespace objects { + +BOOST_PYTHON_DECL void* find_dynamic_type(void* p, class_id src_t, class_id dst_t) +{ + return convert_type(p, src_t, dst_t, true); +} + +BOOST_PYTHON_DECL void* find_static_type(void* p, class_id src_t, class_id dst_t) +{ + return convert_type(p, src_t, dst_t, false); +} + +BOOST_PYTHON_DECL void add_cast( + class_id src_t, class_id dst_t, cast_function cast, bool is_downcast) +{ + // adding an edge will invalidate any record of unreachability in + // the cache. + static std::size_t expected_cache_len = 0; + cache_t& c = cache(); + if (c.size() > expected_cache_len) + { + c.erase(std::remove_if( + c.begin(), c.end(), + mem_fn(&cache_element::unreachable)) + , c.end()); + + // If any new cache entries get added, we'll have to do this + // again when the next edge is added + expected_cache_len = c.size(); + } + + type_index_iterator_pair types = demand_types(src_t, dst_t); + vertex_t src = tuples::get(*types.first); + vertex_t dst = tuples::get(*types.second); + + cast_graph* const g[2] = { &up_graph().topology(), &full_graph().topology() }; + + for (cast_graph*const* p = g + (is_downcast ? 1 : 0); p < g + 2; ++p) + { + edge_t e; + bool added; + + tie(e, added) = add_edge(src, dst, **p); + assert(added); + + put(get(edge_cast, **p), e, cast); + put(get(edge_index, **p), e, num_edges(full_graph().topology()) - 1); + } +} + +BOOST_PYTHON_DECL void register_dynamic_id_aux( + class_id static_id, dynamic_id_function get_dynamic_id) +{ + tuples::get(*demand_type(static_id)) = get_dynamic_id; +} + +}}} // namespace boost::python::objects diff --git a/pykd/boost.python/object/iterator.cpp b/pykd/boost.python/object/iterator.cpp new file mode 100644 index 0000000..3f6c4ad --- /dev/null +++ b/pykd/boost.python/object/iterator.cpp @@ -0,0 +1,39 @@ +// 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 +#include +#include +#include + +namespace boost { namespace python { namespace objects { + +namespace +{ + PyObject* identity(PyObject* args_, PyObject*) + { + PyObject* x = PyTuple_GET_ITEM(args_,0); + Py_INCREF(x); + return x; + } +} + +BOOST_PYTHON_DECL object const& identity_function() +{ + static object result( + function_object( + py_function(&identity, mpl::vector2()) + ) + ); + return result; +} + +void stop_iteration_error() +{ + PyErr_SetObject(PyExc_StopIteration, Py_None); + throw_error_already_set(); +} + +}}} // namespace boost::python::objects diff --git a/pykd/boost.python/object/life_support.cpp b/pykd/boost.python/object/life_support.cpp new file mode 100644 index 0000000..b7e9aa8 --- /dev/null +++ b/pykd/boost.python/object/life_support.cpp @@ -0,0 +1,121 @@ +// 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 +#include +#include + +namespace boost { namespace python { namespace objects { + +struct life_support +{ + PyObject_HEAD + PyObject* patient; +}; + +extern "C" +{ + static void + life_support_dealloc(PyObject* self) + { + Py_XDECREF(((life_support*)self)->patient); + self->ob_type->tp_free(self); + } + + static PyObject * + life_support_call(PyObject *self, PyObject *arg, PyObject * /*kw*/) + { + // Let the patient die now + Py_XDECREF(((life_support*)self)->patient); + ((life_support*)self)->patient = 0; + // Let the weak reference die. This probably kills us. + Py_XDECREF(PyTuple_GET_ITEM(arg, 0)); + return ::boost::python::detail::none(); + } +} + +PyTypeObject life_support_type = { + PyVarObject_HEAD_INIT(NULL, 0)//(&PyType_Type) + const_cast("Boost.Python.life_support"), + sizeof(life_support), + 0, + life_support_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, //(reprfunc)func_repr, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + life_support_call, /* tp_call */ + 0, /* tp_str */ + 0, // PyObject_GenericGetAttr, /* tp_getattro */ + 0, // PyObject_GenericSetAttr, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT /* | Py_TPFLAGS_HAVE_GC */,/* tp_flags */ + 0, /* tp_doc */ + 0, // (traverseproc)func_traverse, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, //offsetof(PyLife_SupportObject, func_weakreflist), /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, // func_memberlist, /* tp_members */ + 0, //func_getsetlist, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, //offsetof(PyLife_SupportObject, func_dict), /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + 0, /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ +#if PYTHON_API_VERSION >= 1012 + 0 /* tp_del */ +#endif +}; + +PyObject* make_nurse_and_patient(PyObject* nurse, PyObject* patient) +{ + if (nurse == Py_None || nurse == patient) + return nurse; + + if (Py_TYPE(&life_support_type) == 0) + { + Py_TYPE(&life_support_type) = &PyType_Type; + PyType_Ready(&life_support_type); + } + + life_support* system = PyObject_New(life_support, &life_support_type); + if (!system) + return 0; + + system->patient = 0; + + // We're going to leak this reference, but don't worry; the + // life_support system decrements it when the nurse dies. + PyObject* weakref = PyWeakref_NewRef(nurse, (PyObject*)system); + + // weakref has either taken ownership, or we have to release it + // anyway + Py_DECREF(system); + if (!weakref) + return 0; + + system->patient = patient; + Py_XINCREF(patient); // hang on to the patient until death + return weakref; +} + +}}} // namespace boost::python::objects diff --git a/pykd/boost.python/object/pickle_support.cpp b/pykd/boost.python/object/pickle_support.cpp new file mode 100644 index 0000000..428c07b --- /dev/null +++ b/pykd/boost.python/object/pickle_support.cpp @@ -0,0 +1,78 @@ +// (C) Copyright R.W. Grosse-Kunstleve 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 +#include +#include +#include +#include +#include + +namespace boost { namespace python { + +namespace { + + tuple instance_reduce(object instance_obj) + { + list result; + object instance_class(instance_obj.attr("__class__")); + result.append(instance_class); + object none; + if (!getattr(instance_obj, "__safe_for_unpickling__", none)) + { + str type_name(getattr(instance_class, "__name__")); + str module_name(getattr(instance_class, "__module__", object(""))); + if (module_name) + module_name += "."; + + PyErr_SetObject( + PyExc_RuntimeError, + ( "Pickling of \"%s\" instances is not enabled" + " (http://www.boost.org/libs/python/doc/v2/pickle.html)" + % (module_name+type_name)).ptr() + ); + + throw_error_already_set(); + } + object getinitargs = getattr(instance_obj, "__getinitargs__", none); + tuple initargs; + if (!getinitargs.is_none()) { + initargs = tuple(getinitargs()); + } + result.append(initargs); + object getstate = getattr(instance_obj, "__getstate__", none); + object instance_dict = getattr(instance_obj, "__dict__", none); + long len_instance_dict = 0; + if (!instance_dict.is_none()) { + len_instance_dict = len(instance_dict); + } + if (!getstate.is_none()) { + if (len_instance_dict > 0) { + object getstate_manages_dict = getattr( + instance_obj, "__getstate_manages_dict__", none); + if (getstate_manages_dict.is_none()) { + PyErr_SetString(PyExc_RuntimeError, + "Incomplete pickle support" + " (__getstate_manages_dict__ not set)"); + throw_error_already_set(); + } + } + result.append(getstate()); + } + else if (len_instance_dict > 0) { + result.append(instance_dict); + } + return tuple(result); + } + +} // namespace + +object const& make_instance_reduce_function() +{ + static object result(&instance_reduce); + return result; +} + +}} // namespace boost::python diff --git a/pykd/boost.python/object/stl_iterator.cpp b/pykd/boost.python/object/stl_iterator.cpp new file mode 100644 index 0000000..e32d321 --- /dev/null +++ b/pykd/boost.python/object/stl_iterator.cpp @@ -0,0 +1,48 @@ +// Copyright Eric Niebler 2005. +// 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) +// +// Credits: +// Andreas Kl\:ockner for fixing increment() to handle +// error conditions. + +#include +#include +#include + +namespace boost { namespace python { namespace objects +{ + +stl_input_iterator_impl::stl_input_iterator_impl() + : it_() + , ob_() +{ +} + +stl_input_iterator_impl::stl_input_iterator_impl(boost::python::object const &ob) + : it_(ob.attr("__iter__")()) + , ob_() +{ + this->increment(); +} + +void stl_input_iterator_impl::increment() +{ + this->ob_ = boost::python::handle<>( + boost::python::allow_null(PyIter_Next(this->it_.ptr()))); + if (PyErr_Occurred()) + throw boost::python::error_already_set(); +} + +bool stl_input_iterator_impl::equal(stl_input_iterator_impl const &that) const +{ + return !this->ob_ == !that.ob_; +} + +boost::python::handle<> const &stl_input_iterator_impl::current() const +{ + return this->ob_; +} + +}}} // namespace boost::python::objects diff --git a/pykd/boost.python/object_operators.cpp b/pykd/boost.python/object_operators.cpp new file mode 100644 index 0000000..b993245 --- /dev/null +++ b/pykd/boost.python/object_operators.cpp @@ -0,0 +1,85 @@ +// 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 +#include + +namespace boost { namespace python { namespace api { + +# define BOOST_PYTHON_COMPARE_OP(op, opid) \ +BOOST_PYTHON_DECL object operator op(object const& l, object const& r) \ +{ \ + return object( \ + detail::new_reference( \ + PyObject_RichCompare( \ + l.ptr(), r.ptr(), opid)) \ + ); \ +} +BOOST_PYTHON_COMPARE_OP(>, Py_GT) +BOOST_PYTHON_COMPARE_OP(>=, Py_GE) +BOOST_PYTHON_COMPARE_OP(<, Py_LT) +BOOST_PYTHON_COMPARE_OP(<=, Py_LE) +BOOST_PYTHON_COMPARE_OP(==, Py_EQ) +BOOST_PYTHON_COMPARE_OP(!=, Py_NE) +# undef BOOST_PYTHON_COMPARE_OP + + +#define BOOST_PYTHON_BINARY_OPERATOR(op, name) \ +BOOST_PYTHON_DECL object operator op(object const& l, object const& r) \ +{ \ + return object( \ + detail::new_reference( \ + PyNumber_##name(l.ptr(), r.ptr())) \ + ); \ +} + +BOOST_PYTHON_BINARY_OPERATOR(+, Add) +BOOST_PYTHON_BINARY_OPERATOR(-, Subtract) +BOOST_PYTHON_BINARY_OPERATOR(*, Multiply) +#if PY_VERSION_HEX >= 0x03000000 +// We choose FloorDivide instead of TrueDivide to keep the semantic +// conform with C/C++'s '/' operator +BOOST_PYTHON_BINARY_OPERATOR(/, FloorDivide) +#else +BOOST_PYTHON_BINARY_OPERATOR(/, Divide) +#endif +BOOST_PYTHON_BINARY_OPERATOR(%, Remainder) +BOOST_PYTHON_BINARY_OPERATOR(<<, Lshift) +BOOST_PYTHON_BINARY_OPERATOR(>>, Rshift) +BOOST_PYTHON_BINARY_OPERATOR(&, And) +BOOST_PYTHON_BINARY_OPERATOR(^, Xor) +BOOST_PYTHON_BINARY_OPERATOR(|, Or) +#undef BOOST_PYTHON_BINARY_OPERATOR + +#define BOOST_PYTHON_INPLACE_OPERATOR(op, name) \ +BOOST_PYTHON_DECL object& operator op##=(object& l, object const& r) \ +{ \ + return l = object( \ + (detail::new_reference) \ + PyNumber_InPlace##name(l.ptr(), r.ptr())); \ +} + +BOOST_PYTHON_INPLACE_OPERATOR(+, Add) +BOOST_PYTHON_INPLACE_OPERATOR(-, Subtract) +BOOST_PYTHON_INPLACE_OPERATOR(*, Multiply) +#if PY_VERSION_HEX >= 0x03000000 +// Same reason as above for choosing FloorDivide instead of TrueDivide +BOOST_PYTHON_INPLACE_OPERATOR(/, FloorDivide) +#else +BOOST_PYTHON_INPLACE_OPERATOR(/, Divide) +#endif +BOOST_PYTHON_INPLACE_OPERATOR(%, Remainder) +BOOST_PYTHON_INPLACE_OPERATOR(<<, Lshift) +BOOST_PYTHON_INPLACE_OPERATOR(>>, Rshift) +BOOST_PYTHON_INPLACE_OPERATOR(&, And) +BOOST_PYTHON_INPLACE_OPERATOR(^, Xor) +BOOST_PYTHON_INPLACE_OPERATOR(|, Or) +#undef BOOST_PYTHON_INPLACE_OPERATOR + +object::object(handle<> const& x) + : object_base(python::incref(python::expect_non_null(x.get()))) +{} + +}}} // namespace boost::python diff --git a/pykd/boost.python/object_protocol.cpp b/pykd/boost.python/object_protocol.cpp new file mode 100644 index 0000000..95c8c73 --- /dev/null +++ b/pykd/boost.python/object_protocol.cpp @@ -0,0 +1,197 @@ +// 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 +#include +#include +#include + +namespace boost { namespace python { namespace api { + +BOOST_PYTHON_DECL object getattr(object const& target, object const& key) +{ + return object(detail::new_reference(PyObject_GetAttr(target.ptr(), key.ptr()))); +} + +BOOST_PYTHON_DECL object getattr(object const& target, object const& key, object const& default_) +{ + PyObject* result = PyObject_GetAttr(target.ptr(), key.ptr()); + if (result == NULL && PyErr_ExceptionMatches(PyExc_AttributeError)) + { + PyErr_Clear(); + return default_; + } + return object(detail::new_reference(result)); +} + +BOOST_PYTHON_DECL void setattr(object const& target, object const& key, object const& value) +{ + if (PyObject_SetAttr(target.ptr(), key.ptr(), value.ptr()) == -1) + throw_error_already_set(); +} + +BOOST_PYTHON_DECL void delattr(object const& target, object const& key) +{ + if (PyObject_DelAttr(target.ptr(), key.ptr()) == -1) + throw_error_already_set(); +} + +BOOST_PYTHON_DECL object getattr(object const& target, char const* key) +{ + return object( + detail::new_reference( + PyObject_GetAttrString(target.ptr(), const_cast(key)) + )); +} + +BOOST_PYTHON_DECL object getattr(object const& target, char const* key, object const& default_) +{ + PyObject* result = PyObject_GetAttrString(target.ptr(), const_cast(key)); + if (result == NULL && PyErr_ExceptionMatches(PyExc_AttributeError)) + { + PyErr_Clear(); + return default_; + } + return object(detail::new_reference(result)); + +} +BOOST_PYTHON_DECL void setattr(object const& target, char const* key, object const& value) +{ + if (PyObject_SetAttrString( + target.ptr(), const_cast(key), value.ptr()) == -1 + ) + { + throw_error_already_set(); + } +} + +BOOST_PYTHON_DECL void delattr(object const& target, char const* key) +{ + if (PyObject_DelAttrString( + target.ptr(), const_cast(key)) == -1 + ) + { + throw_error_already_set(); + } +} + +BOOST_PYTHON_DECL object getitem(object const& target, object const& key) +{ + return object(detail::new_reference( + PyObject_GetItem(target.ptr(), key.ptr()))); +} + +BOOST_PYTHON_DECL void setitem(object const& target, object const& key, object const& value) +{ + if (PyObject_SetItem(target.ptr(), key.ptr(), value.ptr()) == -1) + throw_error_already_set(); +} + +BOOST_PYTHON_DECL void delitem(object const& target, object const& key) +{ + if (PyObject_DelItem(target.ptr(), key.ptr()) == -1) + throw_error_already_set(); +} + +namespace // slicing code copied directly out of the Python implementation +{ + #undef ISINT + #define ISINT(x) ((x) == NULL || PyInt_Check(x) || PyLong_Check(x)) + + static PyObject * + apply_slice(PyObject *u, PyObject *v, PyObject *w) /* return u[v:w] */ + { +#if PY_VERSION_HEX < 0x03000000 + PyTypeObject *tp = u->ob_type; + PySequenceMethods *sq = tp->tp_as_sequence; + + if (sq && sq->sq_slice && ISINT(v) && ISINT(w)) { + ssize_t ilow = 0, ihigh = ssize_t_max; + if (!_PyEval_SliceIndex(v, &ilow)) + return NULL; + if (!_PyEval_SliceIndex(w, &ihigh)) + return NULL; + return PySequence_GetSlice(u, ilow, ihigh); + } + else +#endif + { + PyObject *slice = PySlice_New(v, w, NULL); + if (slice != NULL) { + PyObject *res = PyObject_GetItem(u, slice); + Py_DECREF(slice); + return res; + } + else + return NULL; + } + } + + static int + assign_slice(PyObject *u, PyObject *v, PyObject *w, PyObject *x) + /* u[v:w] = x */ + { +#if PY_VERSION_HEX < 0x03000000 + PyTypeObject *tp = u->ob_type; + PySequenceMethods *sq = tp->tp_as_sequence; + + if (sq && sq->sq_slice && ISINT(v) && ISINT(w)) { + ssize_t ilow = 0, ihigh = ssize_t_max; + if (!_PyEval_SliceIndex(v, &ilow)) + return -1; + if (!_PyEval_SliceIndex(w, &ihigh)) + return -1; + if (x == NULL) + return PySequence_DelSlice(u, ilow, ihigh); + else + return PySequence_SetSlice(u, ilow, ihigh, x); + } + else +#endif + { + PyObject *slice = PySlice_New(v, w, NULL); + if (slice != NULL) { + int res; + if (x != NULL) + res = PyObject_SetItem(u, slice, x); + else + res = PyObject_DelItem(u, slice); + Py_DECREF(slice); + return res; + } + else + return -1; + } + } +} + +BOOST_PYTHON_DECL object getslice(object const& target, handle<> const& begin, handle<> const& end) +{ + return object( + detail::new_reference( + apply_slice(target.ptr(), begin.get(), end.get()))); +} + +BOOST_PYTHON_DECL void setslice(object const& target, handle<> const& begin, handle<> const& end, object const& value) +{ + if (assign_slice( + target.ptr(), begin.get(), end.get(), value.ptr()) == -1 + ) + { + throw_error_already_set(); + } +} + +BOOST_PYTHON_DECL void delslice(object const& target, handle<> const& begin, handle<> const& end) +{ + if (assign_slice( + target.ptr(), begin.get(), end.get(), 0) == -1 + ) + { + throw_error_already_set(); + } +} + +}}} // namespace boost::python::api diff --git a/pykd/boost.python/slice.cpp b/pykd/boost.python/slice.cpp new file mode 100644 index 0000000..ee55f94 --- /dev/null +++ b/pykd/boost.python/slice.cpp @@ -0,0 +1,37 @@ +#include "boost/python/slice.hpp" + +// Copyright (c) 2004 Jonathan Brandmeyer +// Use, modification and distribution are subject to 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) + + +namespace boost { namespace python { namespace detail { + +slice_base::slice_base(PyObject* start, PyObject* stop, PyObject* step) + : object(detail::new_reference( PySlice_New(start, stop, step))) +{ +} + +object +slice_base::start() const +{ + return object( detail::borrowed_reference( + ((PySliceObject*)this->ptr())->start)); +} + +object +slice_base::stop() const +{ + return object( detail::borrowed_reference( + ((PySliceObject*)this->ptr())->stop)); +} + +object +slice_base::step() const +{ + return object( detail::borrowed_reference( + ((PySliceObject*)this->ptr())->step)); +} + +} } } // !namespace boost::python::detail diff --git a/pykd/boost.python/str.cpp b/pykd/boost.python/str.cpp new file mode 100644 index 0000000..5122f7f --- /dev/null +++ b/pykd/boost.python/str.cpp @@ -0,0 +1,419 @@ +// Copyright David Abrahams 2004. 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 +#include +#include + +namespace boost { namespace python { namespace detail { + +detail::new_reference str_base::call(object const& arg_) +{ + return (detail::new_reference)PyObject_CallFunction( +#if PY_VERSION_HEX >= 0x03000000 + (PyObject*)&PyUnicode_Type, +#else + (PyObject*)&PyString_Type, +#endif + const_cast("(O)"), + arg_.ptr()); +} + +str_base::str_base() + : object(detail::new_reference( +#if PY_VERSION_HEX >= 0x03000000 + ::PyUnicode_FromString("") +#else + ::PyString_FromString("") +#endif + )) +{} + +str_base::str_base(const char* s) + : object(detail::new_reference( +#if PY_VERSION_HEX >= 0x03000000 + ::PyUnicode_FromString(s) +#else + ::PyString_FromString(s) +#endif + )) +{} + +namespace { + + ssize_t str_size_as_py_ssize_t(std::size_t n) + { + if (n > static_cast(ssize_t_max)) + { + throw std::range_error("str size > ssize_t_max"); + } + return static_cast(n); + } + +} // namespace + +str_base::str_base(char const* start, char const* finish) + : object( + detail::new_reference( +#if PY_VERSION_HEX >= 0x03000000 + ::PyUnicode_FromStringAndSize +#else + ::PyString_FromStringAndSize +#endif + (start, str_size_as_py_ssize_t(finish - start)) + ) + ) +{} + +str_base::str_base(char const* start, std::size_t length) // new str + : object( + detail::new_reference( +#if PY_VERSION_HEX >= 0x03000000 + ::PyUnicode_FromStringAndSize +#else + ::PyString_FromStringAndSize +#endif + ( start, str_size_as_py_ssize_t(length) ) + ) + ) +{} + +str_base::str_base(object_cref other) + : object(str_base::call(other)) +{} + +#define BOOST_PYTHON_FORMAT_OBJECT(z, n, data) "O" +#define BOOST_PYTHON_OBJECT_PTR(z, n, data) , x##n .ptr() + +#define BOOST_PYTHON_DEFINE_STR_METHOD(name, arity) \ +str str_base:: name ( BOOST_PP_ENUM_PARAMS(arity, object_cref x) ) const \ +{ \ + return str(new_reference( \ + expect_non_null( \ + PyObject_CallMethod( \ + this->ptr(), const_cast( #name ), \ + const_cast( \ + "(" BOOST_PP_REPEAT(arity, BOOST_PYTHON_FORMAT_OBJECT, _) ")") \ + BOOST_PP_REPEAT_1(arity, BOOST_PYTHON_OBJECT_PTR, _))))); \ +} + +BOOST_PYTHON_DEFINE_STR_METHOD(capitalize, 0) +BOOST_PYTHON_DEFINE_STR_METHOD(center, 1) + +long str_base::count(object_cref sub) const +{ + return extract(this->attr("count")(sub)); +} + +long str_base::count(object_cref sub, object_cref start) const +{ + return extract(this->attr("count")(sub,start)); +} + +long str_base::count(object_cref sub, object_cref start, object_cref end) const +{ + return extract(this->attr("count")(sub,start,end)); +} + +#if PY_VERSION_HEX < 0x03000000 +object str_base::decode() const +{ + return this->attr("decode")(); +} + +object str_base::decode(object_cref encoding) const +{ + return this->attr("decode")(encoding); +} + +object str_base::decode(object_cref encoding, object_cref errors) const +{ + return this->attr("decode")(encoding,errors); +} +#endif + +object str_base::encode() const +{ + return this->attr("encode")(); +} + +object str_base::encode(object_cref encoding) const +{ + return this->attr("encode")(encoding); +} + +object str_base::encode(object_cref encoding, object_cref errors) const +{ + return this->attr("encode")(encoding,errors); +} + + +#if PY_VERSION_HEX >= 0x03000000 + #define _BOOST_PYTHON_ASLONG PyLong_AsLong +#else + #define _BOOST_PYTHON_ASLONG PyInt_AsLong +#endif + +bool str_base::endswith(object_cref suffix) const +{ + bool result = _BOOST_PYTHON_ASLONG(this->attr("endswith")(suffix).ptr()); + if (PyErr_Occurred()) + throw_error_already_set(); + return result; +} + +bool str_base::endswith(object_cref suffix, object_cref start) const +{ + bool result = _BOOST_PYTHON_ASLONG(this->attr("endswith")(suffix,start).ptr()); + if (PyErr_Occurred()) + throw_error_already_set(); + return result; +} + +bool str_base::endswith(object_cref suffix, object_cref start, object_cref end) const +{ + bool result = _BOOST_PYTHON_ASLONG(this->attr("endswith")(suffix,start,end).ptr()); + if (PyErr_Occurred()) + throw_error_already_set(); + return result; +} + +BOOST_PYTHON_DEFINE_STR_METHOD(expandtabs, 0) +BOOST_PYTHON_DEFINE_STR_METHOD(expandtabs, 1) + +long str_base::find(object_cref sub) const +{ + long result = _BOOST_PYTHON_ASLONG(this->attr("find")(sub).ptr()); + if (PyErr_Occurred()) + throw_error_already_set(); + return result; +} + +long str_base::find(object_cref sub, object_cref start) const +{ + long result = _BOOST_PYTHON_ASLONG(this->attr("find")(sub,start).ptr()); + if (PyErr_Occurred()) + throw_error_already_set(); + return result; +} + +long str_base::find(object_cref sub, object_cref start, object_cref end) const +{ + long result = _BOOST_PYTHON_ASLONG(this->attr("find")(sub,start,end).ptr()); + if (PyErr_Occurred()) + throw_error_already_set(); + return result; +} + +long str_base::index(object_cref sub) const +{ + long result = _BOOST_PYTHON_ASLONG(this->attr("index")(sub).ptr()); + if (PyErr_Occurred()) + throw_error_already_set(); + return result; +} + +long str_base::index(object_cref sub, object_cref start) const +{ + long result = _BOOST_PYTHON_ASLONG(this->attr("index")(sub,start).ptr()); + if (PyErr_Occurred()) + throw_error_already_set(); + return result; +} + +long str_base::index(object_cref sub, object_cref start, object_cref end) const +{ + long result = _BOOST_PYTHON_ASLONG(this->attr("index")(sub,start,end).ptr()); + if (PyErr_Occurred()) + throw_error_already_set(); + return result; +} + +bool str_base::isalnum() const +{ + bool result = _BOOST_PYTHON_ASLONG(this->attr("isalnum")().ptr()); + if (PyErr_Occurred()) + throw_error_already_set(); + return result; +} + +bool str_base::isalpha() const +{ + bool result = _BOOST_PYTHON_ASLONG(this->attr("isalpha")().ptr()); + if (PyErr_Occurred()) + throw_error_already_set(); + return result; +} + +bool str_base::isdigit() const +{ + bool result = _BOOST_PYTHON_ASLONG(this->attr("isdigit")().ptr()); + if (PyErr_Occurred()) + throw_error_already_set(); + return result; +} + +bool str_base::islower() const +{ + bool result = _BOOST_PYTHON_ASLONG(this->attr("islower")().ptr()); + if (PyErr_Occurred()) + throw_error_already_set(); + return result; +} + +bool str_base::isspace() const +{ + bool result = _BOOST_PYTHON_ASLONG(this->attr("isspace")().ptr()); + if (PyErr_Occurred()) + throw_error_already_set(); + return result; +} + +bool str_base::istitle() const +{ + bool result = _BOOST_PYTHON_ASLONG(this->attr("istitle")().ptr()); + if (PyErr_Occurred()) + throw_error_already_set(); + return result; +} + +bool str_base::isupper() const +{ + bool result = _BOOST_PYTHON_ASLONG(this->attr("isupper")().ptr()); + if (PyErr_Occurred()) + throw_error_already_set(); + return result; +} + +BOOST_PYTHON_DEFINE_STR_METHOD(join, 1) +BOOST_PYTHON_DEFINE_STR_METHOD(ljust, 1) +BOOST_PYTHON_DEFINE_STR_METHOD(lower, 0) +BOOST_PYTHON_DEFINE_STR_METHOD(lstrip, 0) +BOOST_PYTHON_DEFINE_STR_METHOD(replace, 2) +BOOST_PYTHON_DEFINE_STR_METHOD(replace, 3) + +long str_base::rfind(object_cref sub) const +{ + long result = _BOOST_PYTHON_ASLONG(this->attr("rfind")(sub).ptr()); + if (PyErr_Occurred()) + throw_error_already_set(); + return result; +} + +long str_base::rfind(object_cref sub, object_cref start) const +{ + long result = _BOOST_PYTHON_ASLONG(this->attr("rfind")(sub,start).ptr()); + if (PyErr_Occurred()) + throw_error_already_set(); + return result; +} + +long str_base::rfind(object_cref sub, object_cref start, object_cref end) const +{ + long result = _BOOST_PYTHON_ASLONG(this->attr("rfind")(sub,start,end).ptr()); + if (PyErr_Occurred()) + throw_error_already_set(); + return result; +} + +long str_base::rindex(object_cref sub) const +{ + long result = _BOOST_PYTHON_ASLONG(this->attr("rindex")(sub).ptr()); + if (PyErr_Occurred()) + throw_error_already_set(); + return result; +} + +long str_base::rindex(object_cref sub, object_cref start) const +{ + long result = _BOOST_PYTHON_ASLONG(this->attr("rindex")(sub,start).ptr()); + if (PyErr_Occurred()) + throw_error_already_set(); + return result; +} + +long str_base::rindex(object_cref sub, object_cref start, object_cref end) const +{ + long result = _BOOST_PYTHON_ASLONG(this->attr("rindex")(sub,start,end).ptr()); + if (PyErr_Occurred()) + throw_error_already_set(); + return result; +} + +BOOST_PYTHON_DEFINE_STR_METHOD(rjust, 1) +BOOST_PYTHON_DEFINE_STR_METHOD(rstrip, 0) + +list str_base::split() const +{ + return list(this->attr("split")()); +} + +list str_base::split(object_cref sep) const +{ + return list(this->attr("split")(sep)); +} + +list str_base::split(object_cref sep, object_cref maxsplit) const +{ + return list(this->attr("split")(sep,maxsplit)); +} + +list str_base::splitlines() const +{ + return list(this->attr("splitlines")()); +} + +list str_base::splitlines(object_cref keepends) const +{ + return list(this->attr("splitlines")(keepends)); +} + +bool str_base::startswith(object_cref prefix) const +{ + bool result = _BOOST_PYTHON_ASLONG(this->attr("startswith")(prefix).ptr()); + if (PyErr_Occurred()) + throw_error_already_set(); + return result; +} + +bool str_base::startswith(object_cref prefix, object_cref start) const +{ + bool result = _BOOST_PYTHON_ASLONG(this->attr("startswith")(prefix,start).ptr()); + if (PyErr_Occurred()) + throw_error_already_set(); + return result; +} + +bool str_base::startswith(object_cref prefix, object_cref start, object_cref end) const +{ + bool result = _BOOST_PYTHON_ASLONG(this->attr("startswith")(prefix,start,end).ptr()); + if (PyErr_Occurred()) + throw_error_already_set(); + return result; +} + +#undef _BOOST_PYTHON_ASLONG + +BOOST_PYTHON_DEFINE_STR_METHOD(strip, 0) +BOOST_PYTHON_DEFINE_STR_METHOD(swapcase, 0) +BOOST_PYTHON_DEFINE_STR_METHOD(title, 0) +BOOST_PYTHON_DEFINE_STR_METHOD(translate, 1) +BOOST_PYTHON_DEFINE_STR_METHOD(translate, 2) +BOOST_PYTHON_DEFINE_STR_METHOD(upper, 0) + +static struct register_str_pytype_ptr +{ + register_str_pytype_ptr() + { + const_cast( + converter::registry::lookup(boost::python::type_id()) + ) +#if PY_VERSION_HEX >= 0x03000000 + .m_class_object = &PyUnicode_Type; +#else + .m_class_object = &PyString_Type; +#endif + } +}register_str_pytype_ptr_; + +}}} // namespace boost::python diff --git a/pykd/boost.python/tuple.cpp b/pykd/boost.python/tuple.cpp new file mode 100644 index 0000000..6719713 --- /dev/null +++ b/pykd/boost.python/tuple.cpp @@ -0,0 +1,35 @@ +// Copyright David Abrahams 2004. +// 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 + +namespace boost { namespace python { namespace detail { + +detail::new_reference tuple_base::call(object const& arg_) +{ + return (detail::new_reference)PyObject_CallFunction( + (PyObject*)&PyTuple_Type, const_cast("(O)"), + arg_.ptr()); +} + +tuple_base::tuple_base() + : object(detail::new_reference(PyTuple_New(0))) +{} + +tuple_base::tuple_base(object_cref sequence) + : object(call(sequence)) +{} + +static struct register_tuple_pytype_ptr +{ + register_tuple_pytype_ptr() + { + const_cast( + converter::registry::lookup(boost::python::type_id()) + ).m_class_object = &PyTuple_Type; + } +}register_tuple_pytype_ptr_; + + +}}} // namespace boost::python diff --git a/pykd/boost.python/wrapper.cpp b/pykd/boost.python/wrapper.cpp new file mode 100644 index 0000000..f8feaef --- /dev/null +++ b/pykd/boost.python/wrapper.cpp @@ -0,0 +1,66 @@ +// Copyright David Abrahams 2004. 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 + +namespace boost { namespace python { + +namespace detail +{ + override wrapper_base::get_override( + char const* name + , PyTypeObject* class_object + ) const + { + if (this->m_self) + { + if (handle<> m = handle<>( + python::allow_null( + ::PyObject_GetAttrString( + this->m_self, const_cast(name)))) + ) + { + PyObject* borrowed_f = 0; + + if ( + PyMethod_Check(m.get()) + && ((PyMethodObject*)m.get())->im_self == this->m_self + && class_object->tp_dict != 0 + ) + { + borrowed_f = ::PyDict_GetItemString( + class_object->tp_dict, const_cast(name)); + + + } + if (borrowed_f != ((PyMethodObject*)m.get())->im_func) + return override(m); + } + } + return override(handle<>(detail::none())); + } +} + +#if 0 +namespace converter +{ + PyObject* BOOST_PYTHON_DECL do_polymorphic_ref_to_python( + python::detail::wrapper_base const volatile* x, type_info src + ) + { + if (x == 0) + { + ::PyErr_Format( + PyExc_TypeError + , "Attempting to returning pointer or reference to instance of %s\n" + "for which no corresponding Python object exists. Wrap this function" + "with a return return value policy" + ) + } + } + +} +#endif + +}} // namespace boost::python::detail diff --git a/pykd/packages.config b/pykd/packages.config index f040cb9..ae20f2a 100644 --- a/pykd/packages.config +++ b/pykd/packages.config @@ -1,11 +1,12 @@  - - - - - - + + + + + + + diff --git a/pykd/pykd.vcxproj b/pykd/pykd.vcxproj index f7f637a..642e069 100644 --- a/pykd/pykd.vcxproj +++ b/pykd/pykd.vcxproj @@ -311,8 +311,8 @@ Use Level3 Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;PYKD_EXPORTS;%(PreprocessorDefinitions) - $(SolutionDir)\kdlibcpp\kdlib\include; + WIN32;BOOST_PYTHON_STATIC_LIB;BOOST_PYTHON_NO_LIB;_DEBUG;_WINDOWS;_USRDLL;PYKD_EXPORTS;%(PreprocessorDefinitions);BOOST_PYTHON_NUMPY_INTERNAL + $(SolutionDir)\kdlibcpp\kdlib\include;$(SolutionDir)\numpy\include; MultiThreadedDebugDLL @@ -334,8 +334,8 @@ Use Level3 Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;PYKD_EXPORTS;%(PreprocessorDefinitions) - $(SolutionDir)\kdlibcpp\kdlib\include; + WIN32;BOOST_PYTHON_STATIC_LIB;BOOST_PYTHON_NO_LIB;_DEBUG;_WINDOWS;_USRDLL;PYKD_EXPORTS;%(PreprocessorDefinitions);BOOST_PYTHON_NUMPY_INTERNAL + $(SolutionDir)\kdlibcpp\kdlib\include;$(SolutionDir)\numpy\include; Windows @@ -356,8 +356,8 @@ Use Level3 Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;PYKD_EXPORTS;%(PreprocessorDefinitions) - $(SolutionDir)\kdlibcpp\kdlib\include; + WIN32;BOOST_PYTHON_STATIC_LIB;BOOST_PYTHON_NO_LIB;_DEBUG;_WINDOWS;_USRDLL;PYKD_EXPORTS;%(PreprocessorDefinitions);BOOST_PYTHON_NUMPY_INTERNAL + $(SolutionDir)\kdlibcpp\kdlib\include;$(SolutionDir)\numpy\include; Windows @@ -378,8 +378,8 @@ Use Level3 Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;PYKD_EXPORTS;%(PreprocessorDefinitions) - $(SolutionDir)\kdlibcpp\kdlib\include; + WIN32;BOOST_PYTHON_STATIC_LIB;BOOST_PYTHON_NO_LIB;_DEBUG;_WINDOWS;_USRDLL;PYKD_EXPORTS;%(PreprocessorDefinitions);BOOST_PYTHON_NUMPY_INTERNAL + $(SolutionDir)\kdlibcpp\kdlib\include;$(SolutionDir)\numpy\include; Windows @@ -400,8 +400,8 @@ Use Level3 Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;PYKD_EXPORTS;%(PreprocessorDefinitions) - $(SolutionDir)\kdlibcpp\kdlib\include; + WIN32;BOOST_PYTHON_STATIC_LIB;BOOST_PYTHON_NO_LIB;_DEBUG;_WINDOWS;_USRDLL;PYKD_EXPORTS;%(PreprocessorDefinitions);BOOST_PYTHON_NUMPY_INTERNAL + $(SolutionDir)\kdlibcpp\kdlib\include;$(SolutionDir)\numpy\include; Windows @@ -422,8 +422,8 @@ Use Level3 Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;PYKD_EXPORTS;%(PreprocessorDefinitions) - $(SolutionDir)\kdlibcpp\kdlib\include; + WIN32;BOOST_PYTHON_STATIC_LIB;BOOST_PYTHON_NO_LIB;_DEBUG;_WINDOWS;_USRDLL;PYKD_EXPORTS;%(PreprocessorDefinitions);BOOST_PYTHON_NUMPY_INTERNAL + $(SolutionDir)\kdlibcpp\kdlib\include;$(SolutionDir)\numpy\include; Windows @@ -446,8 +446,8 @@ MaxSpeed true true - WIN32;NDEBUG;_WINDOWS;_USRDLL;PYKD_EXPORTS;%(PreprocessorDefinitions) - $(SolutionDir)\kdlibcpp\kdlib\include; + WIN32;BOOST_PYTHON_STATIC_LIB;BOOST_PYTHON_NO_LIB;NDEBUG;_WINDOWS;_USRDLL;PYKD_EXPORTS;%(PreprocessorDefinitions);BOOST_PYTHON_NUMPY_INTERNAL + $(SolutionDir)\kdlibcpp\kdlib\include;$(SolutionDir)\numpy\include; MultiThreaded @@ -469,8 +469,8 @@ MaxSpeed true true - WIN32;NDEBUG;_WINDOWS;_USRDLL;PYKD_EXPORTS;%(PreprocessorDefinitions) - $(SolutionDir)\kdlibcpp\kdlib\include; + WIN32;BOOST_PYTHON_STATIC_LIB;BOOST_PYTHON_NO_LIB;NDEBUG;_WINDOWS;_USRDLL;PYKD_EXPORTS;%(PreprocessorDefinitions);BOOST_PYTHON_NUMPY_INTERNAL + $(SolutionDir)\kdlibcpp\kdlib\include;$(SolutionDir)\numpy\include; MultiThreaded @@ -492,8 +492,8 @@ MaxSpeed true true - WIN32;NDEBUG;_WINDOWS;_USRDLL;PYKD_EXPORTS;%(PreprocessorDefinitions) - $(SolutionDir)\kdlibcpp\kdlib\include; + WIN32;BOOST_PYTHON_STATIC_LIB;BOOST_PYTHON_NO_LIB;NDEBUG;_WINDOWS;_USRDLL;PYKD_EXPORTS;%(PreprocessorDefinitions); + $(SolutionDir)\kdlibcpp\kdlib\include;$(SolutionDir)\numpy\include; MultiThreaded @@ -515,8 +515,8 @@ MaxSpeed true true - WIN32;NDEBUG;_WINDOWS;_USRDLL;PYKD_EXPORTS;%(PreprocessorDefinitions) - $(SolutionDir)\kdlibcpp\kdlib\include; + WIN32;BOOST_PYTHON_STATIC_LIB;BOOST_PYTHON_NO_LIB;NDEBUG;_WINDOWS;_USRDLL;PYKD_EXPORTS;%(PreprocessorDefinitions);BOOST_PYTHON_NUMPY_INTERNAL + $(SolutionDir)\kdlibcpp\kdlib\include;$(SolutionDir)\numpy\include; MultiThreaded @@ -538,8 +538,8 @@ MaxSpeed true true - WIN32;NDEBUG;_WINDOWS;_USRDLL;PYKD_EXPORTS;%(PreprocessorDefinitions) - $(SolutionDir)\kdlibcpp\kdlib\include; + WIN32;BOOST_PYTHON_STATIC_LIB;BOOST_PYTHON_NO_LIB;NDEBUG;_WINDOWS;_USRDLL;PYKD_EXPORTS;%(PreprocessorDefinitions);BOOST_PYTHON_NUMPY_INTERNAL + $(SolutionDir)\kdlibcpp\kdlib\include;$(SolutionDir)\numpy\include; MultiThreaded @@ -561,8 +561,8 @@ MaxSpeed true true - WIN32;NDEBUG;_WINDOWS;_USRDLL;PYKD_EXPORTS;%(PreprocessorDefinitions) - $(SolutionDir)\kdlibcpp\kdlib\include; + WIN32;BOOST_PYTHON_STATIC_LIB;BOOST_PYTHON_NO_LIB;NDEBUG;_WINDOWS;_USRDLL;PYKD_EXPORTS;%(PreprocessorDefinitions); + $(SolutionDir)\kdlibcpp\kdlib\include;$(SolutionDir)\numpy\include; MultiThreaded @@ -603,6 +603,384 @@ + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + @@ -658,32 +1036,34 @@ - - - - - - - - - - - + + + + + + + + + + + + This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - - - - - - - - - + + + + + + + + + + + + \ No newline at end of file diff --git a/pykd/pykd.vcxproj.filters b/pykd/pykd.vcxproj.filters index f6c5649..55e9996 100644 --- a/pykd/pykd.vcxproj.filters +++ b/pykd/pykd.vcxproj.filters @@ -13,6 +13,9 @@ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + {ac5baff8-a82c-4a5d-8086-380454aee92a} + @@ -128,6 +131,186 @@ Source Files + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + boost.python + + + boost.python + + + boost.python + + + boost.python + + + boost.python + + + boost.python + + + boost.python + + + boost.python + + + boost.python + + + boost.python + + + boost.python + + + boost.python + + + boost.python + + + boost.python + + + boost.python + + + boost.python + + + boost.python + + + boost.python + + + boost.python + + + boost.python + + + boost.python + + + boost.python + + + boost.python + + + boost.python + + + boost.python + + + boost.python + + + boost.python + diff --git a/test/scripts/pykdtest.pyproj b/test/scripts/pykdtest.pyproj index 98caed6..67bf6d4 100644 --- a/test/scripts/pykdtest.pyproj +++ b/test/scripts/pykdtest.pyproj @@ -8,7 +8,7 @@ pykdtest.py - ..\..\out\x64\Debug_2.7 + ..\..\out\x64\Debug_3.6 . pykdtest pykdtest @@ -19,7 +19,7 @@ False False - Global|PythonCore|2.7 + Global|PythonCore|3.6 true @@ -60,6 +60,7 @@ +