summaryrefslogtreecommitdiff
path: root/libs/python/src/object
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@baserock.org>2013-06-25 22:59:01 +0000
committer <>2013-09-27 11:49:28 +0000
commit8c4528713d907ee2cfd3bfcbbad272c749867f84 (patch)
treec09e2ce80f47b90c85cc720f5139089ad9c8cfff /libs/python/src/object
downloadboost-tarball-baserock/morph.tar.gz
Imported from /home/lorry/working-area/delta_boost-tarball/boost_1_54_0.tar.bz2.boost_1_54_0baserock/morph
Diffstat (limited to 'libs/python/src/object')
-rw-r--r--libs/python/src/object/class.cpp764
-rw-r--r--libs/python/src/object/enum.cpp246
-rw-r--r--libs/python/src/object/function.cpp793
-rw-r--r--libs/python/src/object/function_doc_signature.cpp344
-rw-r--r--libs/python/src/object/inheritance.cpp495
-rw-r--r--libs/python/src/object/iterator.cpp39
-rw-r--r--libs/python/src/object/life_support.cpp121
-rw-r--r--libs/python/src/object/pickle_support.cpp78
-rw-r--r--libs/python/src/object/stl_iterator.cpp48
9 files changed, 2928 insertions, 0 deletions
diff --git a/libs/python/src/object/class.cpp b/libs/python/src/object/class.cpp
new file mode 100644
index 000000000..aeef688e2
--- /dev/null
+++ b/libs/python/src/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 <boost/python/detail/prefix.hpp>
+#include <boost/mpl/lambda.hpp> // #including this first is an intel6 workaround
+
+#include <boost/python/object/class.hpp>
+#include <boost/python/object/instance.hpp>
+#include <boost/python/object/class_detail.hpp>
+#include <boost/python/scope.hpp>
+#include <boost/python/converter/registry.hpp>
+#include <boost/python/object/find_instance.hpp>
+#include <boost/python/object/pickle_support.hpp>
+#include <boost/python/detail/map_entry.hpp>
+#include <boost/python/object.hpp>
+#include <boost/python/object_protocol.hpp>
+#include <boost/detail/binary_search.hpp>
+#include <boost/python/self.hpp>
+#include <boost/python/dict.hpp>
+#include <boost/python/str.hpp>
+#include <boost/python/ssize_t.hpp>
+#include <functional>
+#include <vector>
+#include <cstddef>
+#include <new>
+#include <structmember.h>
+
+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<char **>(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<char*>("()"));
+ }
+
+ 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<char*>("()"));
+ else
+ res = PyObject_CallFunction(func, const_cast<char*>("(O)"), value);
+ if (res == NULL)
+ return -1;
+ Py_DECREF(res);
+ return 0;
+ }
+}
+
+static PyTypeObject static_data_object = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ const_cast<char*>("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<PyObject>(&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<PyTypeObject>(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<char*>("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<void*>(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<char*>("__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<int>(offsetof(instance<>,storage) + instance_size));
+ }
+ return (PyObject*)result;
+ }
+
+ static PyObject* instance_get_dict(PyObject* op, void*)
+ {
+ instance<>* inst = downcast<instance<> >(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<instance<> >(op);
+ python::xdecref(inst->dict);
+ inst->dict = python::incref(dict);
+ return 0;
+ }
+
+ }
+
+
+ static PyGetSetDef instance_getsets[] = {
+ {const_cast<char*>("__dict__"), instance_get_dict, instance_set_dict, NULL, 0},
+ {0, 0, 0, 0, 0}
+ };
+
+
+ static PyMemberDef instance_members[] = {
+ {const_cast<char*>("__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<char*>("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<instance<>*>(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<PyObject>(&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<std::size_t>(1));
+ handle<> bases(PyTuple_New(num_bases));
+
+ for (ssize_t i = 1; i <= num_bases; ++i)
+ {
+ type_handle c = (i >= static_cast<ssize_t>(num_types)) ? class_type() : get_class(types[i]);
+ // PyTuple_SET_ITEM steals this reference
+ PyTuple_SET_ITEM(bases.get(), static_cast<ssize_t>(i - 1), upcast<PyObject>(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::registration&>(
+ 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::registration&>(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<char*>("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<char*>("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<char*>("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<char*>("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<char*>(name), x.ptr()) < 0)
+ throw_error_already_set();
+ }
+
+ namespace
+ {
+ extern "C" PyObject* no_init(PyObject*, PyObject*)
+ {
+ ::PyErr_SetString(::PyExc_RuntimeError, const_cast<char*>("This class cannot be instantiated from Python"));
+ return NULL;
+ }
+ static ::PyMethodDef no_init_def = {
+ const_cast<char*>("__init__"), no_init, METH_VARARGS,
+ const_cast<char*>("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<char*>("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<PyTypeObject>(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/libs/python/src/object/enum.cpp b/libs/python/src/object/enum.cpp
new file mode 100644
index 000000000..3063320cb
--- /dev/null
+++ b/libs/python/src/object/enum.cpp
@@ -0,0 +1,246 @@
+// Copyright David Abrahams 2002.
+// Distributed under the Boost Software License, Version 1.0. (See
+// accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#include <boost/python/object/enum_base.hpp>
+#include <boost/python/cast.hpp>
+#include <boost/python/scope.hpp>
+#include <boost/python/object.hpp>
+#include <boost/python/tuple.hpp>
+#include <boost/python/dict.hpp>
+#include <boost/python/str.hpp>
+#include <boost/python/extract.hpp>
+#include <boost/python/object_protocol.hpp>
+#include <structmember.h>
+
+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<char*>("name"), T_OBJECT_EX, offsetof(enum_object,name),READONLY, 0},
+ {0, 0, 0, 0, 0}
+};
+
+
+extern "C"
+{
+ static PyObject* enum_repr(PyObject* self_)
+ {
+ // XXX(bhy) Potentional memory leak here since PyObject_GetAttrString returns a new reference
+ // const char *mod = PyString_AsString(PyObject_GetAttrString( self_, const_cast<char*>("__module__")));
+ PyObject *mod = PyObject_GetAttrString( self_, "__module__");
+ enum_object* self = downcast<enum_object>(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<enum_object>(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<char*>("Boost.Python.enum"),
+ sizeof(enum_object), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* 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::registration&>(
+ converter::registry::lookup(id));
+
+ converters.m_class_object = downcast<PyTypeObject>(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<dict>(this->attr("values"))();
+ d[value] = x;
+
+ // Set the name field in the new enum instanec
+ enum_object* p = downcast<enum_object>(x.ptr());
+ Py_XDECREF(p->name);
+ p->name = incref(name.ptr());
+
+ dict names_dict = extract<dict>(this->attr("names"))();
+ names_dict[x.attr("name")] = x;
+}
+
+void enum_base::export_values()
+{
+ dict d = extract<dict>(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<dict>(type.attr("values"))();
+ object v = d.get(x, object());
+ return incref(
+ (v == object() ? type(x) : v).ptr());
+}
+
+}}} // namespace boost::python::object
diff --git a/libs/python/src/object/function.cpp b/libs/python/src/object/function.cpp
new file mode 100644
index 000000000..5c59cc779
--- /dev/null
+++ b/libs/python/src/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 <boost/python/docstring_options.hpp>
+#include <boost/python/object/function_object.hpp>
+#include <boost/python/object/function_handle.hpp>
+#include <boost/python/object/function_doc_signature.hpp>
+#include <boost/python/errors.hpp>
+#include <boost/python/str.hpp>
+#include <boost/python/object_attributes.hpp>
+#include <boost/python/args.hpp>
+#include <boost/python/refcount.hpp>
+#include <boost/python/extract.hpp>
+#include <boost/python/tuple.hpp>
+#include <boost/python/list.hpp>
+#include <boost/python/ssize_t.hpp>
+
+#include <boost/python/detail/signature.hpp>
+#include <boost/python/detail/none.hpp>
+#include <boost/mpl/vector/vector10.hpp>
+
+#include <boost/bind.hpp>
+
+#include <algorithm>
+#include <cstring>
+
+#if BOOST_PYTHON_DEBUG_ERROR_MESSAGES
+# include <cstdio>
+#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<std::size_t>(ssize_t_max));
+ inner_args = handle<>(
+ PyTuple_New(static_cast<ssize_t>(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<char*>("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<const char*>(message)());
+#endif
+ PyErr_SetObject(exception.get(), message.ptr());
+ throw_error_already_set();
+}
+
+void function::add_overload(handle<function> 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<function> not_implemented_function()
+ {
+
+ static object keeper(
+ function_object(
+ py_function(&not_implemented, mpl::vector1<void>(), 2)
+ , python::detail::keyword_range())
+ );
+ return handle<function>(borrowed(downcast<function>(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<function>(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<char*>("__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<function>(
+ borrowed(
+ downcast<function>(existing.get())
+ )
+ )
+ );
+ }
+ else if (existing->ob_type == &PyStaticMethod_Type)
+ {
+ char const* name_space_name = extract<char const*>(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<char*>("__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<function>(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<const char*>(detail::py_signature_tag));
+ }
+ if (doc != 0 && docstring_options::show_user_defined_)
+ _doc += doc;
+
+ if (docstring_options::show_cpp_signatures_)
+ {
+ _doc += str(const_cast<const char*>(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<function*>(p);
+ }
+
+ static PyObject *
+ function_call(PyObject *func, PyObject *args, PyObject *kw)
+ {
+ PyObject* result = 0;
+ handle_exception(bind_return(result, static_cast<function*>(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<function>(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<function>(op);
+ f->doc(doc ? object(python::detail::borrowed_reference(doc)) : object());
+ return 0;
+ }
+
+ static PyObject* function_get_name(PyObject* op, void*)
+ {
+ function* f = downcast<function>(op);
+ if (f->name().is_none())
+#if PY_VERSION_HEX >= 0x03000000
+ return PyUnicode_InternFromString("<unnamed Boost.Python function>");
+#else
+ return PyString_InternFromString("<unnamed Boost.Python function>");
+#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<PyObject>(&PyCFunction_Type));
+ }
+
+ static PyObject* function_get_module(PyObject* op, void*)
+ {
+ function* f = downcast<function>(op);
+ object const& ns = f->get_namespace();
+ if (!ns.is_none()) {
+ return python::incref(ns.ptr());
+ }
+ PyErr_SetString(
+ PyExc_AttributeError, const_cast<char*>(
+ "Boost.Python function __module__ unknown."));
+ return 0;
+ }
+}
+
+static PyGetSetDef function_getsetlist[] = {
+ {const_cast<char*>("__name__"), (getter)function_get_name, 0, 0, 0 },
+ {const_cast<char*>("func_name"), (getter)function_get_name, 0, 0, 0 },
+ {const_cast<char*>("__module__"), (getter)function_get_module, 0, 0, 0 },
+ {const_cast<char*>("func_module"), (getter)function_get_module, 0, 0, 0 },
+ {const_cast<char*>("__class__"), (getter)function_get_class, 0, 0, 0 }, // see note above
+ {const_cast<char*>("__doc__"), (getter)function_get_doc, (setter)function_set_doc, 0, 0},
+ {const_cast<char*>("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<char*>("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<char*>("Pure virtual function called"));
+ throw_error_already_set();
+ }
+}
+
+}} // namespace boost::python
diff --git a/libs/python/src/object/function_doc_signature.cpp b/libs/python/src/object/function_doc_signature.cpp
new file mode 100644
index 000000000..41695285a
--- /dev/null
+++ b/libs/python/src/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 <boost/python/converter/registrations.hpp>
+#include <boost/python/object/function_doc_signature.hpp>
+#include <boost/python/errors.hpp>
+#include <boost/python/str.hpp>
+#include <boost/python/args.hpp>
+#include <boost/python/tuple.hpp>
+
+#include <boost/python/detail/signature.hpp>
+
+#include <vector>
+
+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 const*> function_doc_signature_generator::flatten(function const *f)
+ {
+ object name = f->name();
+
+ std::vector<function const*> 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 const*> function_doc_signature_generator::split_seq_overloads( const std::vector<function const *> &funcs, bool split_on_doc_change)
+ {
+ std::vector<function const*> res;
+
+ std::vector<function const*>::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<function const*> funcs = flatten( f);
+ std::vector<function const*> split_funcs = split_seq_overloads( funcs, true);
+ std::vector<function const*>::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/libs/python/src/object/inheritance.cpp b/libs/python/src/object/inheritance.cpp
new file mode 100644
index 000000000..7dc9db1cd
--- /dev/null
+++ b/libs/python/src/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 <boost/python/object/inheritance.hpp>
+#include <boost/python/type_id.hpp>
+#include <boost/graph/breadth_first_search.hpp>
+#if _MSC_FULL_VER >= 13102171 && _MSC_FULL_VER <= 13102179
+# include <boost/graph/reverse_graph.hpp>
+#endif
+#include <boost/graph/adjacency_list.hpp>
+#include <boost/graph/reverse_graph.hpp>
+#include <boost/property_map/property_map.hpp>
+#include <boost/bind.hpp>
+#include <boost/integer_traits.hpp>
+#include <boost/tuple/tuple.hpp>
+#include <boost/tuple/tuple_comparison.hpp>
+#include <queue>
+#include <vector>
+#include <functional>
+
+//
+// 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 <class T> 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<vecS,vecS, bidirectionalS, no_property
+
+ // edge index property allows us to look up edges in the connectivity matrix
+ , property<edge_index_t,std::size_t
+
+ // The function which casts a void* from the edge's source type
+ // to its destination type.
+ , property<edge_cast_t,cast_function> > >
+#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<std::size_t>::const_iterator node_distance_map;
+
+ typedef std::pair<cast_graph::out_edge_iterator
+ , cast_graph::out_edge_iterator> 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<std::size_t>::max)());
+ m_known_vertices = n;
+ }
+
+ std::vector<std::size_t>::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<cast_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<std::size_t> 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<index_entry> type_index_t;
+
+
+ type_index_t& type_index()
+ {
+ static type_index_t x;
+ return x;
+ }
+
+ template <class Tuple>
+ 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<bool>(std::less<class_id>()
+ , boost::bind<class_id>(select1st<entry>(), _1)
+ , boost::bind<class_id>(select1st<entry>(), _2)));
+ }
+
+ inline index_entry* seek_type(class_id type)
+ {
+ type_index_t::iterator p = type_position(type);
+ if (p == type_index().end() || tuples::get<ksrc_static_t>(*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<ksrc_static_t>(*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_t::iterator, type_index_t::iterator>
+ 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<std::size_t>::max)())
+ return 0;
+
+ typedef property_map<cast_graph,edge_cast_t>::const_type cast_map;
+ cast_map casts = get(edge_cast, g.topology());
+
+ typedef std::pair<vertex_t,void*> search_state;
+ typedef std::vector<search_state> visited_t;
+ visited_t visited;
+ std::priority_queue<q_elt> 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<std::ptrdiff_t>::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_element> 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<kdynamic_id>(*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<kvertex>(*src_p)
+ , tuples::get<kvertex>(*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<kvertex>(*types.first);
+ vertex_t dst = tuples::get<kvertex>(*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<kdynamic_id>(*demand_type(static_id)) = get_dynamic_id;
+}
+
+}}} // namespace boost::python::objects
diff --git a/libs/python/src/object/iterator.cpp b/libs/python/src/object/iterator.cpp
new file mode 100644
index 000000000..3f6c4adac
--- /dev/null
+++ b/libs/python/src/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 <boost/python/object/iterator_core.hpp>
+#include <boost/python/object/function_object.hpp>
+#include <boost/bind.hpp>
+#include <boost/mpl/vector/vector10.hpp>
+
+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<PyObject*,PyObject*>())
+ )
+ );
+ return result;
+}
+
+void stop_iteration_error()
+{
+ PyErr_SetObject(PyExc_StopIteration, Py_None);
+ throw_error_already_set();
+}
+
+}}} // namespace boost::python::objects
diff --git a/libs/python/src/object/life_support.cpp b/libs/python/src/object/life_support.cpp
new file mode 100644
index 000000000..b7e9aa861
--- /dev/null
+++ b/libs/python/src/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 <boost/python/object/life_support.hpp>
+#include <boost/python/detail/none.hpp>
+#include <boost/python/refcount.hpp>
+
+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<char*>("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/libs/python/src/object/pickle_support.cpp b/libs/python/src/object/pickle_support.cpp
new file mode 100644
index 000000000..428c07b6c
--- /dev/null
+++ b/libs/python/src/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 <boost/python/make_function.hpp>
+#include <boost/python/object/class.hpp>
+#include <boost/python/tuple.hpp>
+#include <boost/python/list.hpp>
+#include <boost/python/dict.hpp>
+#include <boost/python/str.hpp>
+
+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/libs/python/src/object/stl_iterator.cpp b/libs/python/src/object/stl_iterator.cpp
new file mode 100644
index 000000000..e32d32145
--- /dev/null
+++ b/libs/python/src/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 <boost/python/object.hpp>
+#include <boost/python/handle.hpp>
+#include <boost/python/object/stl_iterator_core.hpp>
+
+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