mirror of
https://github.com/boostorg/python.git
synced 2026-01-22 17:32:55 +00:00
This commit was manufactured by cvs2svn to create branch 'newbpl'.
[SVN r8341]
This commit is contained in:
884
src/classes.cpp
884
src/classes.cpp
@@ -1,884 +0,0 @@
|
||||
// (C) Copyright David Abrahams 2000. Permission to copy, use, modify, sell and
|
||||
// distribute this software is granted provided this copyright notice appears
|
||||
// in all copies. This software is provided "as is" without express or implied
|
||||
// warranty, and with no claim as to its suitability for any purpose.
|
||||
//
|
||||
// The author gratefully acknowleges the support of Dragon Systems, Inc., in
|
||||
// producing this work.
|
||||
|
||||
#include <boost/python/classes.hpp>
|
||||
#include <boost/python/detail/functions.hpp>
|
||||
#include <boost/python/detail/singleton.hpp>
|
||||
#include <cstddef>
|
||||
#include <boost/python/callback.hpp>
|
||||
#include <cstring>
|
||||
#include <boost/python/module_builder.hpp>
|
||||
|
||||
namespace boost { namespace python {
|
||||
|
||||
namespace detail {
|
||||
void enable_named_method(boost::python::detail::class_base* type_obj, const char* name);
|
||||
}
|
||||
|
||||
namespace {
|
||||
// Add the name of the module currently being loaded to the name_space with the
|
||||
// key "__module__". If no module is being loaded, or if name_space already has
|
||||
// a key "__module", has no effect. This is not really a useful public
|
||||
// interface; it's just used for class_t<>::class_t() below.
|
||||
void add_current_module_name(dictionary&);
|
||||
|
||||
bool is_prefix(const char* s1, const char* s2);
|
||||
bool is_special_name(const char* name);
|
||||
void enable_special_methods(boost::python::detail::class_base* derived, const tuple& bases, const dictionary& name_space);
|
||||
|
||||
void report_ignored_exception(PyObject* source)
|
||||
{
|
||||
// This bit of code copied wholesale from classobject.c in the Python source.
|
||||
PyObject *f, *t, *v, *tb;
|
||||
PyErr_Fetch(&t, &v, &tb);
|
||||
f = PySys_GetObject(const_cast<char*>("stderr"));
|
||||
if (f != NULL)
|
||||
{
|
||||
PyFile_WriteString(const_cast<char*>("Exception "), f);
|
||||
if (t) {
|
||||
PyFile_WriteObject(t, f, Py_PRINT_RAW);
|
||||
if (v && v != Py_None) {
|
||||
PyFile_WriteString(const_cast<char*>(": "), f);
|
||||
PyFile_WriteObject(v, f, 0);
|
||||
}
|
||||
}
|
||||
PyFile_WriteString(const_cast<char*>(" in "), f);
|
||||
PyFile_WriteObject(source, f, 0);
|
||||
PyFile_WriteString(const_cast<char*>(" ignored\n"), f);
|
||||
PyErr_Clear(); /* Just in case */
|
||||
}
|
||||
Py_XDECREF(t);
|
||||
Py_XDECREF(v);
|
||||
Py_XDECREF(tb);
|
||||
}
|
||||
|
||||
//
|
||||
// pickle support courtesy of "Ralf W. Grosse-Kunstleve" <rwgk@cci.lbl.gov>
|
||||
//
|
||||
PyObject* class_reduce(PyObject* klass)
|
||||
{
|
||||
return PyObject_GetAttrString(klass, const_cast<char*>("__name__"));
|
||||
}
|
||||
|
||||
ref global_class_reduce()
|
||||
{
|
||||
static ref result(detail::new_wrapped_function(class_reduce));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
tuple instance_reduce(PyObject* obj)
|
||||
{
|
||||
ref instance_class(PyObject_GetAttrString(obj, const_cast<char*>("__class__")));
|
||||
|
||||
ref getinitargs(PyObject_GetAttrString(obj, const_cast<char*>("__getinitargs__")),
|
||||
ref::null_ok);
|
||||
PyErr_Clear();
|
||||
ref initargs;
|
||||
if (getinitargs.get() != 0)
|
||||
{
|
||||
initargs = ref(PyEval_CallObject(getinitargs.get(), NULL));
|
||||
initargs = ref(PySequence_Tuple(initargs.get()));
|
||||
}
|
||||
else
|
||||
{
|
||||
initargs = ref(PyTuple_New(0));
|
||||
}
|
||||
|
||||
ref getstate(PyObject_GetAttrString(obj, const_cast<char*>("__getstate__")),
|
||||
ref::null_ok);
|
||||
PyErr_Clear();
|
||||
if (getstate.get() != 0)
|
||||
{
|
||||
ref state = ref(PyEval_CallObject(getstate.get(), NULL));
|
||||
return tuple(instance_class, initargs, state);
|
||||
}
|
||||
|
||||
ref state(PyObject_GetAttrString(obj, const_cast<char*>("__dict__")), ref::null_ok);
|
||||
PyErr_Clear();
|
||||
if (state.get() != 0 && dictionary(state).size() > 0)
|
||||
{
|
||||
return tuple(instance_class, initargs, state);
|
||||
}
|
||||
|
||||
return tuple(instance_class, initargs);
|
||||
}
|
||||
|
||||
ref global_instance_reduce()
|
||||
{
|
||||
static ref result(detail::new_wrapped_function(instance_reduce));
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
namespace detail {
|
||||
|
||||
class_base::class_base(PyTypeObject* meta_class_obj, string name, tuple bases, const dictionary& name_space)
|
||||
: type_object_base(meta_class_obj),
|
||||
m_name(name),
|
||||
m_bases(bases),
|
||||
m_name_space(name_space)
|
||||
{
|
||||
this->tp_name = const_cast<char*>(name.c_str());
|
||||
enable(type_object_base::getattr);
|
||||
enable(type_object_base::setattr);
|
||||
add_current_module_name(m_name_space);
|
||||
static const boost::python::string docstr("__doc__", boost::python::string::interned);
|
||||
if (PyDict_GetItem(m_name_space.get(), docstr.get())== 0)
|
||||
{
|
||||
PyDict_SetItem(m_name_space.get(), docstr.get(), Py_None);
|
||||
}
|
||||
enable_special_methods(this, bases, name_space);
|
||||
}
|
||||
|
||||
void class_base::add_base(ref base)
|
||||
{
|
||||
tuple new_bases(m_bases.size() + 1);
|
||||
for (std::size_t i = 0; i < m_bases.size(); ++i)
|
||||
new_bases.set_item(i, m_bases[i]);
|
||||
new_bases.set_item(m_bases.size(), base);
|
||||
m_bases = new_bases;
|
||||
}
|
||||
|
||||
PyObject* class_base::getattr(const char* name)
|
||||
{
|
||||
if (!BOOST_CSTD_::strcmp(name, "__dict__"))
|
||||
{
|
||||
PyObject* result = m_name_space.get();
|
||||
Py_INCREF(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
if (!BOOST_CSTD_::strcmp(name, "__bases__"))
|
||||
{
|
||||
PyObject* result = m_bases.get();
|
||||
Py_INCREF(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
if (!BOOST_CSTD_::strcmp(name, "__name__"))
|
||||
{
|
||||
PyObject* result = m_name.get();
|
||||
Py_INCREF(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
// pickle support courtesy of "Ralf W. Grosse-Kunstleve" <rwgk@cci.lbl.gov>
|
||||
if (!BOOST_CSTD_::strcmp(name, "__safe_for_unpickling__"))
|
||||
{
|
||||
return PyInt_FromLong(1);
|
||||
}
|
||||
if (!BOOST_CSTD_::strcmp(name, "__reduce__"))
|
||||
{
|
||||
ref target(as_object(this), ref::increment_count);
|
||||
return new bound_function(target, global_class_reduce());
|
||||
}
|
||||
|
||||
ref local_attribute = m_name_space.get_item(string(name).reference());
|
||||
|
||||
if (local_attribute.get())
|
||||
return local_attribute.release();
|
||||
|
||||
// In case there are no bases...
|
||||
PyErr_SetString(PyExc_AttributeError, name);
|
||||
|
||||
// Check bases
|
||||
for (std::size_t i = 0; i < m_bases.size(); ++i)
|
||||
{
|
||||
if (PyErr_ExceptionMatches(PyExc_AttributeError))
|
||||
PyErr_Clear(); // we're going to try a base class
|
||||
else if (PyErr_Occurred())
|
||||
break; // Other errors count, though!
|
||||
|
||||
PyObject* base_attribute = PyObject_GetAttrString(m_bases[i].get(), const_cast<char*>(name));
|
||||
|
||||
if (base_attribute != 0)
|
||||
{
|
||||
// Unwind the actual underlying function from unbound Python class
|
||||
// methods in case of multiple inheritance from real Python
|
||||
// classes. Python stubbornly insists that the first argument to a
|
||||
// method must be a true Python instance object otherwise. Do not
|
||||
// unwrap bound methods; that would interfere with intended semantics.
|
||||
if (PyMethod_Check(base_attribute)
|
||||
&& reinterpret_cast<PyMethodObject*>(base_attribute)->im_self == 0)
|
||||
{
|
||||
PyObject* function
|
||||
= reinterpret_cast<PyMethodObject*>(base_attribute)->im_func;
|
||||
Py_INCREF(function);
|
||||
Py_DECREF(base_attribute);
|
||||
return function;
|
||||
}
|
||||
else
|
||||
{
|
||||
return base_attribute;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Mostly copied wholesale from Python's classobject.c
|
||||
PyObject* class_base::repr() const
|
||||
{
|
||||
PyObject *mod = PyDict_GetItemString(
|
||||
m_name_space.get(), const_cast<char*>("__module__"));
|
||||
unsigned long address = reinterpret_cast<unsigned long>(this);
|
||||
string result = (mod == NULL || !PyString_Check(mod))
|
||||
? string("<extension class %s at %lx>") % tuple(m_name, address)
|
||||
: string("<extension class %s.%s at %lx>") % tuple(ref(mod, ref::increment_count), m_name, address);
|
||||
return result.reference().release();
|
||||
}
|
||||
|
||||
|
||||
int class_base::setattr(const char* name, PyObject* value)
|
||||
{
|
||||
if (is_special_name(name)
|
||||
&& BOOST_CSTD_::strcmp(name, "__doc__") != 0
|
||||
&& BOOST_CSTD_::strcmp(name, "__name__") != 0)
|
||||
{
|
||||
boost::python::string message("Special attribute names other than '__doc__' and '__name__' are read-only, in particular: ");
|
||||
PyErr_SetObject(PyExc_TypeError, (message + name).get());
|
||||
throw error_already_set();
|
||||
}
|
||||
|
||||
if (PyCallable_Check(value))
|
||||
detail::enable_named_method(this, name);
|
||||
|
||||
return PyDict_SetItemString(
|
||||
m_name_space.reference().get(), const_cast<char*>(name), value);
|
||||
}
|
||||
|
||||
bool class_base::initialize_instance(instance* obj, PyObject* args, PyObject* keywords)
|
||||
{
|
||||
// Getting the init function off the obj should result in a
|
||||
// bound method.
|
||||
PyObject* const init_function = obj->getattr("__init__", false);
|
||||
|
||||
if (init_function == 0)
|
||||
{
|
||||
if (PyErr_Occurred() && PyErr_ExceptionMatches(PyExc_AttributeError)) {
|
||||
PyErr_Clear(); // no __init__? That's legal.
|
||||
}
|
||||
else {
|
||||
return false; // Something else? Keep the error
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Manage the reference to the bound function
|
||||
ref init_function_holder(init_function);
|
||||
|
||||
// Declare a ref to manage the result of calling __init__ (which should be None).
|
||||
ref init_result(
|
||||
PyEval_CallObjectWithKeywords(init_function, args, keywords));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void class_base::instance_dealloc(PyObject* obj) const
|
||||
{
|
||||
Py_INCREF(obj); // This allows a __del__ function to revive the obj
|
||||
|
||||
PyObject* exc_type;
|
||||
PyObject* exc_value;
|
||||
PyObject* exc_traceback;
|
||||
PyErr_Fetch(&exc_type, &exc_value, &exc_traceback);
|
||||
|
||||
// This scope ensures that the reference held by del_function doesn't release
|
||||
// the last reference and delete the object recursively (infinitely).
|
||||
{
|
||||
ref del_function;
|
||||
try {
|
||||
instance* const target = boost::python::downcast<boost::python::instance>(obj);
|
||||
del_function = ref(target->getattr("__del__", false), ref::null_ok);
|
||||
}
|
||||
catch(...) {
|
||||
}
|
||||
|
||||
if (del_function.get() != 0)
|
||||
{
|
||||
ref result(PyEval_CallObject(del_function.get(), (PyObject *)NULL), ref::null_ok);
|
||||
|
||||
if (result.get() == NULL)
|
||||
report_ignored_exception(del_function.get());
|
||||
}
|
||||
}
|
||||
PyErr_Restore(exc_type, exc_value, exc_traceback);
|
||||
|
||||
if (--obj->ob_refcnt <= 0)
|
||||
delete_instance(obj);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
instance::instance(PyTypeObject* class_)
|
||||
: boost::python::detail::base_object<PyObject>(class_)
|
||||
{
|
||||
}
|
||||
|
||||
instance::~instance()
|
||||
{
|
||||
}
|
||||
|
||||
PyObject* instance::getattr(const char* name, bool use_special_function)
|
||||
{
|
||||
if (!BOOST_CSTD_::strcmp(name, "__dict__"))
|
||||
{
|
||||
if (PyEval_GetRestricted()) {
|
||||
PyErr_SetString(PyExc_RuntimeError,
|
||||
"instance.__dict__ not accessible in restricted mode");
|
||||
return 0;
|
||||
}
|
||||
Py_INCREF(m_name_space.get());
|
||||
return m_name_space.get();
|
||||
}
|
||||
|
||||
if (!BOOST_CSTD_::strcmp(name, "__class__"))
|
||||
{
|
||||
Py_INCREF(this->ob_type);
|
||||
return as_object(this->ob_type);
|
||||
}
|
||||
|
||||
if (!BOOST_CSTD_::strcmp(name, "__reduce__"))
|
||||
{
|
||||
return new detail::bound_function(ref(this, ref::increment_count), global_instance_reduce());
|
||||
}
|
||||
|
||||
ref local_attribute = m_name_space.get_item(string(name).reference());
|
||||
|
||||
if (local_attribute.get())
|
||||
return local_attribute.release();
|
||||
|
||||
// Check its class.
|
||||
PyObject* function =
|
||||
PyObject_GetAttrString(as_object(this->ob_type), const_cast<char*>(name));
|
||||
|
||||
if (function == 0 && !use_special_function)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
ref class_attribute;
|
||||
if (function != 0)
|
||||
{
|
||||
// This will throw if the attribute wasn't found
|
||||
class_attribute = ref(function);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Clear the error while we try special methods method (if any).
|
||||
PyErr_Clear();
|
||||
|
||||
// First we try the special method that comes from concatenating
|
||||
// "__getattr__" and <name> and 2 trailing underscores. This is an
|
||||
// extension to regular Python class functionality.
|
||||
const string specific_getattr_name(detail::getattr_string() + name + "__");
|
||||
PyObject* getattr_method = PyObject_GetAttr(
|
||||
as_object(this->ob_type), specific_getattr_name.get());
|
||||
|
||||
// Use just the first arg to PyEval_CallFunction if found
|
||||
char* arg_format = const_cast<char*>("(O)");
|
||||
|
||||
// Try for the regular __getattr__ method if not found
|
||||
if (getattr_method == 0)
|
||||
{
|
||||
PyErr_Clear();
|
||||
getattr_method = PyObject_GetAttrString(
|
||||
as_object(this->ob_type), const_cast<char*>("__getattr__"));
|
||||
|
||||
// Use both args to PyEval_CallFunction
|
||||
arg_format = const_cast<char*>("(Os)");
|
||||
}
|
||||
|
||||
// If there is no such method, throw now.
|
||||
if (PyErr_Occurred())
|
||||
{
|
||||
PyErr_SetString(PyExc_AttributeError, name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Take ownership of the method
|
||||
ref owner(getattr_method);
|
||||
|
||||
// Call it to get the attribute.
|
||||
return PyEval_CallFunction(getattr_method, arg_format, this, name);
|
||||
}
|
||||
|
||||
if (!PyCallable_Check(class_attribute.get()))
|
||||
{
|
||||
PyErr_Clear();
|
||||
return class_attribute.release();
|
||||
}
|
||||
else
|
||||
{
|
||||
return detail::bound_function::create(ref(this, ref::increment_count), class_attribute);
|
||||
}
|
||||
}
|
||||
|
||||
// instance::setattr_dict
|
||||
//
|
||||
// Implements setattr() functionality for the "__dict__" attribute
|
||||
//
|
||||
int instance::setattr_dict(PyObject* value)
|
||||
{
|
||||
if (PyEval_GetRestricted())
|
||||
{
|
||||
PyErr_SetString(PyExc_RuntimeError,
|
||||
"__dict__ not accessible in restricted mode");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (value == 0 || !PyDict_Check(value))
|
||||
{
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"__dict__ must be set to a dictionary");
|
||||
return -1;
|
||||
}
|
||||
m_name_space = dictionary(ref(value, ref::increment_count));
|
||||
return 0;
|
||||
}
|
||||
|
||||
// instance::setattr -
|
||||
//
|
||||
// Implements the setattr() and delattr() functionality for our own instance
|
||||
// objects, using the standard Python interface: if value == 0, we are deleting
|
||||
// the attribute, and returns 0 unless an error occurred.
|
||||
int instance::setattr(const char* name, PyObject* value)
|
||||
{
|
||||
if (BOOST_CSTD_::strcmp(name, "__class__") == 0)
|
||||
{
|
||||
PyErr_SetString(PyExc_TypeError, "__class__ attribute is read-only");
|
||||
throw error_already_set();
|
||||
}
|
||||
|
||||
if (BOOST_CSTD_::strcmp(name, "__dict__") == 0)
|
||||
return setattr_dict(value);
|
||||
|
||||
// Try to find an appropriate "specific" setter or getter method, either
|
||||
// __setattr__<name>__(value) or __delattr__<name>__(). This is an extension
|
||||
// to regular Python class functionality.
|
||||
const string& base_name = value ? detail::setattr_string() : detail::delattr_string();
|
||||
const string specific_method_name(base_name + name + "__");
|
||||
|
||||
ref special_method(
|
||||
PyObject_GetAttr(as_object(this->ob_type), specific_method_name.get()),
|
||||
ref::null_ok);
|
||||
|
||||
PyObject* result_object = 0;
|
||||
if (special_method.get() != 0)
|
||||
{
|
||||
// The specific function was found; call it now. Note that if value is
|
||||
// not included in the format string, it is ignored.
|
||||
char* format_string = const_cast<char*>(value ? "(OO)" : "(O)");
|
||||
result_object = PyEval_CallFunction(special_method.get(), format_string, this, value);
|
||||
}
|
||||
else
|
||||
{
|
||||
// If not found, try the usual __setattr__(name, value) or
|
||||
// __delattr__(name) functions.
|
||||
PyErr_Clear();
|
||||
special_method.reset(
|
||||
PyObject_GetAttr(as_object(this->ob_type), base_name.get()),
|
||||
ref::null_ok);
|
||||
|
||||
if (special_method.get() != 0)
|
||||
{
|
||||
// The special function was found; call it now. Note that if value
|
||||
// is not included in the format string, it is ignored.
|
||||
char* format_string = const_cast<char*>(value ? "(OsO)" : "(Os)");
|
||||
result_object = PyEval_CallFunction(
|
||||
special_method.get(), format_string, this, name, value);
|
||||
}
|
||||
}
|
||||
|
||||
// If we found an appropriate special method, handle the return value.
|
||||
if (special_method.get() != 0)
|
||||
{
|
||||
ref manage_result(result_object);
|
||||
return 0;
|
||||
}
|
||||
|
||||
PyErr_Clear(); // Nothing was found; clear the python error state
|
||||
|
||||
if (value == 0) // Try to remove the attribute from our name space
|
||||
{
|
||||
const int result = PyDict_DelItemString(m_name_space.reference().get(),
|
||||
const_cast<char*>(name));
|
||||
if (result < 0)
|
||||
{
|
||||
PyErr_Clear();
|
||||
PyErr_SetString(PyExc_AttributeError, "delete non-existing instance attribute");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
else // Change the specified item in our name space
|
||||
{
|
||||
return PyDict_SetItemString(m_name_space.reference().get(),
|
||||
const_cast<char*>(name), value);
|
||||
}
|
||||
}
|
||||
|
||||
PyObject* instance::call(PyObject* args, PyObject* keywords)
|
||||
{
|
||||
return PyEval_CallObjectWithKeywords(
|
||||
ref(getattr("__call__")).get(), // take possession of the result from getattr()
|
||||
args, keywords);
|
||||
}
|
||||
|
||||
PyObject* instance::repr()
|
||||
{
|
||||
return callback<PyObject*>::call_method(this, "__repr__");
|
||||
}
|
||||
|
||||
int instance::compare(PyObject* other)
|
||||
{
|
||||
return callback<int>::call_method(this, "__cmp__", other);
|
||||
}
|
||||
|
||||
PyObject* instance::str()
|
||||
{
|
||||
return callback<PyObject*>::call_method(this, "__str__");
|
||||
}
|
||||
|
||||
long instance::hash()
|
||||
{
|
||||
return callback<long>::call_method(this, "__hash__");
|
||||
}
|
||||
|
||||
int instance::length()
|
||||
{
|
||||
return callback<int>::call_method(this, "__len__");
|
||||
}
|
||||
|
||||
PyObject* instance::get_subscript(PyObject* key)
|
||||
{
|
||||
return callback<PyObject*>::call_method(this, "__getitem__", key);
|
||||
}
|
||||
|
||||
void instance::set_subscript(PyObject* key, PyObject* value)
|
||||
{
|
||||
if (value == 0)
|
||||
callback<void>::call_method(this, "__delitem__", key);
|
||||
else
|
||||
callback<void>::call_method(this, "__setitem__", key, value);
|
||||
}
|
||||
|
||||
PyObject* instance::get_slice(int start, int finish)
|
||||
{
|
||||
return callback<PyObject*>::call_method(this, "__getslice__", start, finish);
|
||||
}
|
||||
|
||||
void instance::set_slice(int start, int finish, PyObject* value)
|
||||
{
|
||||
if (value == 0)
|
||||
callback<void>::call_method(this, "__delslice__", start, finish);
|
||||
else
|
||||
callback<void>::call_method(this, "__setslice__", start, finish, value);
|
||||
}
|
||||
|
||||
PyObject* instance::add(PyObject* other)
|
||||
{
|
||||
return callback<PyObject*>::call_method(this, "__add__", other);
|
||||
}
|
||||
|
||||
PyObject* instance::subtract(PyObject* other)
|
||||
{
|
||||
return callback<PyObject*>::call_method(this, "__sub__", other);
|
||||
}
|
||||
|
||||
PyObject* instance::multiply(PyObject* other)
|
||||
{
|
||||
return callback<PyObject*>::call_method(this, "__mul__", other);
|
||||
}
|
||||
|
||||
PyObject* instance::divide(PyObject* other)
|
||||
{
|
||||
return callback<PyObject*>::call_method(this, "__div__", other);
|
||||
}
|
||||
|
||||
PyObject* instance::remainder(PyObject* other)
|
||||
{
|
||||
return callback<PyObject*>::call_method(this, "__mod__", other);
|
||||
}
|
||||
|
||||
PyObject* instance::divmod(PyObject* other)
|
||||
{
|
||||
return callback<PyObject*>::call_method(this, "__divmod__", other);
|
||||
}
|
||||
|
||||
PyObject* instance::power(PyObject* exponent, PyObject* modulus)
|
||||
{
|
||||
if (as_object(modulus->ob_type) == Py_None)
|
||||
return callback<PyObject*>::call_method(this, "__pow__", exponent);
|
||||
else
|
||||
return callback<PyObject*>::call_method(this, "__pow__", exponent, modulus);
|
||||
}
|
||||
|
||||
PyObject* instance::negative()
|
||||
{
|
||||
return callback<PyObject*>::call_method(this, "__neg__");
|
||||
}
|
||||
|
||||
PyObject* instance::positive()
|
||||
{
|
||||
return callback<PyObject*>::call_method(this, "__pos__");
|
||||
}
|
||||
|
||||
PyObject* instance::absolute()
|
||||
{
|
||||
return callback<PyObject*>::call_method(this, "__abs__");
|
||||
}
|
||||
|
||||
int instance::nonzero()
|
||||
{
|
||||
return callback<bool>::call_method(this, "__nonzero__");
|
||||
}
|
||||
|
||||
PyObject* instance::invert()
|
||||
{
|
||||
return callback<PyObject*>::call_method(this, "__invert__");
|
||||
}
|
||||
|
||||
PyObject* instance::lshift(PyObject* other)
|
||||
{
|
||||
return callback<PyObject*>::call_method(this, "__lshift__", other);
|
||||
}
|
||||
|
||||
PyObject* instance::rshift(PyObject* other)
|
||||
{
|
||||
return callback<PyObject*>::call_method(this, "__rshift__", other);
|
||||
}
|
||||
|
||||
PyObject* instance::do_and(PyObject* other)
|
||||
{
|
||||
return callback<PyObject*>::call_method(this, "__and__", other);
|
||||
}
|
||||
|
||||
PyObject* instance::do_xor(PyObject* other)
|
||||
{
|
||||
return callback<PyObject*>::call_method(this, "__xor__", other);
|
||||
}
|
||||
|
||||
PyObject* instance::do_or(PyObject* other)
|
||||
{
|
||||
return callback<PyObject*>::call_method(this, "__or__", other);
|
||||
}
|
||||
|
||||
int instance::coerce(PyObject** x, PyObject** y)
|
||||
{
|
||||
assert(this == *x);
|
||||
|
||||
// Coerce must return a tuple
|
||||
tuple result(callback<tuple>::call_method(this, "__coerce__", *y));
|
||||
|
||||
*x = result[0].release();
|
||||
*y = result[1].release();
|
||||
return 0;
|
||||
}
|
||||
|
||||
PyObject* instance::as_int()
|
||||
{
|
||||
return callback<PyObject*>::call_method(this, "__int__");
|
||||
}
|
||||
|
||||
PyObject* instance::as_long()
|
||||
{
|
||||
return callback<PyObject*>::call_method(this, "__long__");
|
||||
}
|
||||
|
||||
PyObject* instance::as_float()
|
||||
{
|
||||
return callback<PyObject*>::call_method(this, "__float__");
|
||||
}
|
||||
|
||||
PyObject* instance::oct()
|
||||
{
|
||||
return callback<PyObject*>::call_method(this, "__oct__");
|
||||
}
|
||||
|
||||
PyObject* instance::hex()
|
||||
{
|
||||
return callback<PyObject*>::call_method(this, "__hex__");
|
||||
}
|
||||
|
||||
namespace {
|
||||
struct named_capability
|
||||
{
|
||||
const char* name;
|
||||
detail::type_object_base::capability capability;
|
||||
};
|
||||
|
||||
const named_capability enablers[] =
|
||||
{
|
||||
{ "__hash__", detail::type_object_base::hash },
|
||||
{ "__cmp__", detail::type_object_base::compare },
|
||||
{ "__repr__", detail::type_object_base::repr },
|
||||
{ "__str__", detail::type_object_base::str },
|
||||
{ "__call__", detail::type_object_base::call },
|
||||
{ "__getattr__", detail::type_object_base::getattr },
|
||||
{ "__setattr__", detail::type_object_base::setattr },
|
||||
{ "__len__", detail::type_object_base::mapping_length },
|
||||
{ "__len__", detail::type_object_base::sequence_length },
|
||||
{ "__getitem__", detail::type_object_base::mapping_subscript },
|
||||
{ "__getitem__", detail::type_object_base::sequence_item },
|
||||
{ "__setitem__", detail::type_object_base::mapping_ass_subscript },
|
||||
{ "__setitem__", detail::type_object_base::sequence_ass_item },
|
||||
{ "__delitem__", detail::type_object_base::mapping_ass_subscript },
|
||||
{ "__delitem__", detail::type_object_base::sequence_ass_item },
|
||||
{ "__getslice__", detail::type_object_base::sequence_slice },
|
||||
{ "__setslice__", detail::type_object_base::sequence_ass_slice },
|
||||
{ "__delslice__", detail::type_object_base::sequence_ass_slice },
|
||||
{ "__add__", detail::type_object_base::number_add },
|
||||
{ "__sub__", detail::type_object_base::number_subtract },
|
||||
{ "__mul__", detail::type_object_base::number_multiply },
|
||||
{ "__div__", detail::type_object_base::number_divide },
|
||||
{ "__mod__", detail::type_object_base::number_remainder },
|
||||
{ "__divmod__", detail::type_object_base::number_divmod },
|
||||
{ "__pow__", detail::type_object_base::number_power },
|
||||
{ "__neg__", detail::type_object_base::number_negative },
|
||||
{ "__pos__", detail::type_object_base::number_positive },
|
||||
{ "__abs__", detail::type_object_base::number_absolute },
|
||||
{ "__nonzero__", detail::type_object_base::number_nonzero },
|
||||
{ "__invert__", detail::type_object_base::number_invert },
|
||||
{ "__lshift__", detail::type_object_base::number_lshift },
|
||||
{ "__rshift__", detail::type_object_base::number_rshift },
|
||||
{ "__and__", detail::type_object_base::number_and },
|
||||
{ "__xor__", detail::type_object_base::number_xor },
|
||||
{ "__or__", detail::type_object_base::number_or },
|
||||
{ "__coerce__", detail::type_object_base::number_coerce },
|
||||
{ "__int__", detail::type_object_base::number_int },
|
||||
{ "__long__", detail::type_object_base::number_long },
|
||||
{ "__float__", detail::type_object_base::number_float },
|
||||
{ "__oct__", detail::type_object_base::number_oct },
|
||||
{ "__hex__", detail::type_object_base::number_hex }
|
||||
};
|
||||
|
||||
bool is_prefix(const char* s1, const char* s2)
|
||||
{
|
||||
while (*s1 != 0 && *s2 != 0 && *s1 == *s2)
|
||||
++s1, ++s2;
|
||||
return *s1 == 0;
|
||||
}
|
||||
|
||||
bool is_special_name(const char* name)
|
||||
{
|
||||
if (name[0] != '_' || name[1] != '_' || name[2] == 0 || name[3] == 0)
|
||||
return false;
|
||||
|
||||
std::size_t name_length = BOOST_CSTD_::strlen(name);
|
||||
return name[name_length - 1] == '_' && name[name_length - 2] == '_';
|
||||
}
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
// Enable the special handler for methods of the given name, if any.
|
||||
void enable_named_method(boost::python::detail::class_base* type_obj, const char* name)
|
||||
{
|
||||
const std::size_t num_enablers = sizeof(enablers) / sizeof(enablers[0]);
|
||||
|
||||
// Make sure this ends with "__" since we'll only compare the head of the
|
||||
// string. This is done to make the __getattr__<name>__/__setattr__<name>__
|
||||
// extension work.
|
||||
if (!is_special_name(name))
|
||||
return;
|
||||
|
||||
for (std::size_t i = 0; i < num_enablers; ++i)
|
||||
{
|
||||
if (is_prefix(enablers[i].name + 2, name + 2))
|
||||
{
|
||||
type_obj->enable(enablers[i].capability);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
// Enable any special methods which are enabled in the base class.
|
||||
void enable_special_methods(boost::python::detail::class_base* derived, const tuple& bases, const dictionary& name_space)
|
||||
{
|
||||
for (std::size_t i = 0; i < bases.size(); ++i)
|
||||
{
|
||||
PyObject* base = bases[i].get();
|
||||
|
||||
for (std::size_t n = 0; n < PY_ARRAY_LENGTH(enablers); ++n)
|
||||
{
|
||||
ref attribute(
|
||||
PyObject_GetAttrString(base, const_cast<char*>(enablers[n].name)),
|
||||
ref::null_ok);
|
||||
PyErr_Clear();
|
||||
if (attribute.get() != 0 && PyCallable_Check(attribute.get()))
|
||||
detail::add_capability(enablers[n].capability, derived);
|
||||
}
|
||||
}
|
||||
|
||||
list keys(name_space.keys());
|
||||
for (std::size_t j = 0, len = keys.size(); j < len; ++j)
|
||||
{
|
||||
string name_obj(keys.get_item(j));
|
||||
const char* name = name_obj.c_str();
|
||||
|
||||
if (!is_special_name(name))
|
||||
continue;
|
||||
|
||||
for (std::size_t i = 0; i < PY_ARRAY_LENGTH(enablers); ++i)
|
||||
{
|
||||
if (is_prefix(enablers[i].name + 2, name + 2))
|
||||
{
|
||||
detail::add_capability(enablers[i].capability, derived);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void add_current_module_name(dictionary& name_space)
|
||||
{
|
||||
static string module_key("__module__", string::interned);
|
||||
name_space.set_item(module_key, module_builder::name());
|
||||
}
|
||||
}
|
||||
|
||||
void adjust_slice_indices(PyObject* obj, int& start, int& finish)
|
||||
{
|
||||
int length = callback<int>::call_method(obj, "__len__");
|
||||
|
||||
// This is standard Python class behavior.
|
||||
if (start < 0)
|
||||
start += length;
|
||||
if (finish < 0)
|
||||
finish += length;
|
||||
|
||||
// This is not
|
||||
if (start < 0)
|
||||
start = 0;
|
||||
if (finish < 0)
|
||||
finish = 0;
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
const string& setattr_string()
|
||||
{
|
||||
static string x("__setattr__", string::interned);
|
||||
return x;
|
||||
}
|
||||
|
||||
const string& getattr_string()
|
||||
{
|
||||
static string x("__getattr__", string::interned);
|
||||
return x;
|
||||
}
|
||||
|
||||
const string& delattr_string()
|
||||
{
|
||||
static string x("__delattr__", string::interned);
|
||||
return x;
|
||||
}
|
||||
}
|
||||
|
||||
}} // namespace boost::python
|
||||
@@ -1,241 +0,0 @@
|
||||
// (C) Copyright David Abrahams 2000. Permission to copy, use, modify, sell and
|
||||
// distribute this software is granted provided this copyright notice appears
|
||||
// in all copies. This software is provided "as is" without express or implied
|
||||
// warranty, and with no claim as to its suitability for any purpose.
|
||||
//
|
||||
// The author gratefully acknowleges the support of Dragon Systems, Inc., in
|
||||
// producing this work.
|
||||
|
||||
#include <boost/python/conversions.hpp>
|
||||
#include <typeinfo>
|
||||
#include <exception>
|
||||
#ifndef BOOST_NO_LIMITS
|
||||
# include <boost/cast.hpp>
|
||||
#endif
|
||||
|
||||
namespace boost { namespace python {
|
||||
|
||||
// IMPORTANT: this function may only be called from within a catch block!
|
||||
void handle_exception()
|
||||
{
|
||||
try {
|
||||
// re-toss the current exception so we can find out what type it is.
|
||||
// NOTE: a heinous bug in MSVC6 causes exception objects re-thrown in
|
||||
// this way to be double-destroyed. Thus, you must only use objects that
|
||||
// can tolerate double-destruction with that compiler. Metrowerks
|
||||
// Codewarrior doesn't suffer from this problem.
|
||||
throw;
|
||||
}
|
||||
catch(const boost::python::error_already_set&)
|
||||
{
|
||||
// The python error reporting has already been handled.
|
||||
}
|
||||
catch(const std::bad_alloc&)
|
||||
{
|
||||
PyErr_NoMemory();
|
||||
}
|
||||
catch(const std::exception& x)
|
||||
{
|
||||
PyErr_SetString(PyExc_RuntimeError, x.what());
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
PyErr_SetString(PyExc_RuntimeError, "unidentifiable C++ exception");
|
||||
}
|
||||
}
|
||||
|
||||
}} // namespace boost::python
|
||||
|
||||
BOOST_PYTHON_BEGIN_CONVERSION_NAMESPACE
|
||||
|
||||
long from_python(PyObject* p, boost::python::type<long>)
|
||||
{
|
||||
// Why am I clearing the error here before trying to convert? I know there's a reason...
|
||||
long result;
|
||||
{
|
||||
result = PyInt_AsLong(p);
|
||||
if (PyErr_Occurred())
|
||||
throw boost::python::argument_error();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
double from_python(PyObject* p, boost::python::type<double>)
|
||||
{
|
||||
double result;
|
||||
{
|
||||
result = PyFloat_AsDouble(p);
|
||||
if (PyErr_Occurred())
|
||||
throw boost::python::argument_error();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
T integer_from_python(PyObject* p, boost::python::type<T>)
|
||||
{
|
||||
const long long_result = from_python(p, boost::python::type<long>());
|
||||
|
||||
#ifndef BOOST_NO_LIMITS
|
||||
try
|
||||
{
|
||||
return boost::numeric_cast<T>(long_result);
|
||||
}
|
||||
catch(const boost::bad_numeric_cast&)
|
||||
#else
|
||||
if (static_cast<T>(long_result) == long_result)
|
||||
{
|
||||
return static_cast<T>(long_result);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
char buffer[256];
|
||||
const char message[] = "%ld out of range for %s";
|
||||
sprintf(buffer, message, long_result, typeid(T).name());
|
||||
PyErr_SetString(PyExc_ValueError, buffer);
|
||||
throw boost::python::argument_error();
|
||||
}
|
||||
#if defined(__MWERKS__) && __MWERKS__ <= 0x2400
|
||||
return 0; // Not smart enough to know that the catch clause always rethrows
|
||||
#endif
|
||||
}
|
||||
|
||||
template <class T>
|
||||
PyObject* integer_to_python(T value)
|
||||
{
|
||||
long value_as_long;
|
||||
|
||||
#ifndef BOOST_NO_LIMITS
|
||||
try
|
||||
{
|
||||
value_as_long = boost::numeric_cast<long>(value);
|
||||
}
|
||||
catch(const boost::bad_numeric_cast&)
|
||||
#else
|
||||
value_as_long = static_cast<long>(value);
|
||||
if (value_as_long != value)
|
||||
#endif
|
||||
{
|
||||
const char message[] = "value out of range for Python int";
|
||||
PyErr_SetString(PyExc_ValueError, message);
|
||||
throw boost::python::error_already_set();
|
||||
}
|
||||
|
||||
return to_python(value_as_long);
|
||||
}
|
||||
|
||||
int from_python(PyObject* p, boost::python::type<int> type)
|
||||
{
|
||||
return integer_from_python(p, type);
|
||||
}
|
||||
|
||||
PyObject* to_python(unsigned int i)
|
||||
{
|
||||
return integer_to_python(i);
|
||||
}
|
||||
|
||||
unsigned int from_python(PyObject* p, boost::python::type<unsigned int> type)
|
||||
{
|
||||
return integer_from_python(p, type);
|
||||
}
|
||||
|
||||
short from_python(PyObject* p, boost::python::type<short> type)
|
||||
{
|
||||
return integer_from_python(p, type);
|
||||
}
|
||||
|
||||
float from_python(PyObject* p, boost::python::type<float>)
|
||||
{
|
||||
return static_cast<float>(from_python(p, boost::python::type<double>()));
|
||||
}
|
||||
|
||||
PyObject* to_python(unsigned short i)
|
||||
{
|
||||
return integer_to_python(i);
|
||||
}
|
||||
|
||||
unsigned short from_python(PyObject* p, boost::python::type<unsigned short> type)
|
||||
{
|
||||
return integer_from_python(p, type);
|
||||
}
|
||||
|
||||
PyObject* to_python(unsigned char i)
|
||||
{
|
||||
return integer_to_python(i);
|
||||
}
|
||||
|
||||
unsigned char from_python(PyObject* p, boost::python::type<unsigned char> type)
|
||||
{
|
||||
return integer_from_python(p, type);
|
||||
}
|
||||
|
||||
PyObject* to_python(signed char i)
|
||||
{
|
||||
return integer_to_python(i);
|
||||
}
|
||||
|
||||
signed char from_python(PyObject* p, boost::python::type<signed char> type)
|
||||
{
|
||||
return integer_from_python(p, type);
|
||||
}
|
||||
|
||||
PyObject* to_python(unsigned long x)
|
||||
{
|
||||
return integer_to_python(x);
|
||||
}
|
||||
|
||||
unsigned long from_python(PyObject* p, boost::python::type<unsigned long> type)
|
||||
{
|
||||
return integer_from_python(p, type);
|
||||
}
|
||||
|
||||
void from_python(PyObject* p, boost::python::type<void>)
|
||||
{
|
||||
if (p != Py_None) {
|
||||
PyErr_SetString(PyExc_TypeError, "expected argument of type None");
|
||||
throw boost::python::argument_error();
|
||||
}
|
||||
}
|
||||
|
||||
const char* from_python(PyObject* p, boost::python::type<const char*>)
|
||||
{
|
||||
const char* s = PyString_AsString(p);
|
||||
if (!s)
|
||||
throw boost::python::argument_error();
|
||||
return s;
|
||||
}
|
||||
|
||||
PyObject* to_python(const std::string& s)
|
||||
{
|
||||
return PyString_FromString(s.c_str());
|
||||
}
|
||||
|
||||
std::string from_python(PyObject* p, boost::python::type<std::string>)
|
||||
{
|
||||
return std::string(from_python(p, boost::python::type<const char*>()));
|
||||
}
|
||||
|
||||
bool from_python(PyObject* p, boost::python::type<bool>)
|
||||
{
|
||||
int value = from_python(p, boost::python::type<int>());
|
||||
if (value == 0)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef BOOST_MSVC6_OR_EARLIER
|
||||
// An optimizer bug prevents these from being inlined.
|
||||
PyObject* to_python(double d)
|
||||
{
|
||||
return PyFloat_FromDouble(d);
|
||||
}
|
||||
|
||||
PyObject* to_python(float f)
|
||||
{
|
||||
return PyFloat_FromDouble(f);
|
||||
}
|
||||
#endif // BOOST_MSVC6_OR_EARLIER
|
||||
|
||||
BOOST_PYTHON_END_CONVERSION_NAMESPACE
|
||||
|
||||
@@ -1,683 +0,0 @@
|
||||
// (C) Copyright David Abrahams 2000. Permission to copy, use, modify, sell and
|
||||
// distribute this software is granted provided this copyright notice appears
|
||||
// in all copies. This software is provided "as is" without express or implied
|
||||
// warranty, and with no claim as to its suitability for any purpose.
|
||||
//
|
||||
// The author gratefully acknowleges the support of Dragon Systems, Inc., in
|
||||
// producing this work.
|
||||
|
||||
#include <boost/python/detail/extension_class.hpp>
|
||||
#include <cstring>
|
||||
#include <boost/utility.hpp>
|
||||
|
||||
namespace boost { namespace python {
|
||||
namespace detail {
|
||||
|
||||
struct operator_dispatcher
|
||||
: public PyObject
|
||||
{
|
||||
static PyTypeObject type_obj;
|
||||
static PyNumberMethods number_methods;
|
||||
|
||||
static operator_dispatcher* create(const ref& o, const ref& s);
|
||||
|
||||
ref m_object;
|
||||
ref m_self;
|
||||
|
||||
// data members for allocation/deallocation optimization
|
||||
operator_dispatcher* m_free_list_link;
|
||||
static operator_dispatcher* free_list;
|
||||
|
||||
private:
|
||||
// only accessible through create()
|
||||
operator_dispatcher(const ref& o, const ref& s);
|
||||
};
|
||||
|
||||
operator_dispatcher* operator_dispatcher::free_list = 0;
|
||||
|
||||
}}} // namespace boost::python::detail
|
||||
|
||||
BOOST_PYTHON_BEGIN_CONVERSION_NAMESPACE
|
||||
|
||||
inline PyObject* to_python(boost::python::detail::operator_dispatcher* n) { return n; }
|
||||
|
||||
BOOST_PYTHON_END_CONVERSION_NAMESPACE
|
||||
|
||||
|
||||
namespace boost { namespace python {
|
||||
|
||||
namespace detail {
|
||||
|
||||
tuple extension_class_coerce(ref l, ref r)
|
||||
{
|
||||
// Introduced sequence points for exception-safety.
|
||||
ref first(operator_dispatcher::create(l, l));
|
||||
ref second;
|
||||
|
||||
if(r->ob_type == &operator_dispatcher::type_obj)
|
||||
{
|
||||
second = r;
|
||||
}
|
||||
else
|
||||
{
|
||||
second = ref(operator_dispatcher::create(r, ref()));
|
||||
}
|
||||
return boost::python::tuple(first, second);
|
||||
}
|
||||
|
||||
enum { unwrap_exception_code = -1000 };
|
||||
|
||||
int unwrap_args(PyObject* left, PyObject* right, PyObject*& self, PyObject*& other)
|
||||
{
|
||||
if (left->ob_type != &operator_dispatcher::type_obj ||
|
||||
right->ob_type != &operator_dispatcher::type_obj)
|
||||
{
|
||||
PyErr_SetString(PyExc_RuntimeError, "operator_dispatcher::unwrap_args(): expecting operator_dispatcher arguments only!");
|
||||
return unwrap_exception_code;
|
||||
}
|
||||
|
||||
typedef reference<operator_dispatcher> DPtr;
|
||||
DPtr lwrapper(static_cast<operator_dispatcher*>(left), DPtr::increment_count);
|
||||
DPtr rwrapper(static_cast<operator_dispatcher*>(right), DPtr::increment_count);
|
||||
|
||||
if (lwrapper->m_self.get() != 0)
|
||||
{
|
||||
self = lwrapper->m_self.get();
|
||||
other = rwrapper->m_object.get();
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
self = rwrapper->m_self.get();
|
||||
other = lwrapper->m_object.get();
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
int unwrap_pow_args(PyObject* left, PyObject* right, PyObject* m,
|
||||
PyObject*& self, PyObject*& first, PyObject*& second)
|
||||
{
|
||||
if (left->ob_type != &operator_dispatcher::type_obj ||
|
||||
right->ob_type != &operator_dispatcher::type_obj ||
|
||||
m->ob_type != &operator_dispatcher::type_obj)
|
||||
{
|
||||
PyErr_SetString(PyExc_RuntimeError, "operator_dispatcher::unwrap_pow_args(): expecting operator_dispatcher arguments only!");
|
||||
return unwrap_exception_code;
|
||||
}
|
||||
|
||||
typedef reference<operator_dispatcher> DPtr;
|
||||
DPtr lwrapper(static_cast<operator_dispatcher*>(left), DPtr::increment_count);
|
||||
DPtr rwrapper(static_cast<operator_dispatcher*>(right), DPtr::increment_count);
|
||||
DPtr mwrapper(static_cast<operator_dispatcher*>(m), DPtr::increment_count);
|
||||
|
||||
if (lwrapper->m_self.get() != 0)
|
||||
{
|
||||
self = lwrapper->m_self.get();
|
||||
first = rwrapper->m_object.get();
|
||||
second = mwrapper->m_object.get();
|
||||
return 0;
|
||||
}
|
||||
else if (rwrapper->m_self.get() != 0)
|
||||
{
|
||||
self = rwrapper->m_self.get();
|
||||
first = lwrapper->m_object.get();
|
||||
second = mwrapper->m_object.get();
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
self = mwrapper->m_self.get();
|
||||
first = lwrapper->m_object.get();
|
||||
second = rwrapper->m_object.get();
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
extension_instance* get_extension_instance(PyObject* p)
|
||||
{
|
||||
// The object's type will just be some class_t<extension_instance> object,
|
||||
// but if its meta-type is right, then it is an extension_instance.
|
||||
if (p->ob_type->ob_type != extension_meta_class())
|
||||
{
|
||||
PyErr_SetString(PyExc_TypeError, p->ob_type->tp_name);
|
||||
throw boost::python::argument_error();
|
||||
}
|
||||
return static_cast<extension_instance*>(p);
|
||||
}
|
||||
|
||||
void
|
||||
extension_instance::add_implementation(std::auto_ptr<instance_holder_base> holder)
|
||||
{
|
||||
for (held_objects::const_iterator p = m_wrapped_objects.begin();
|
||||
p != m_wrapped_objects.end(); ++p)
|
||||
{
|
||||
if (typeid(*holder) == typeid(**p))
|
||||
{
|
||||
PyErr_SetString(PyExc_RuntimeError, "Base class already initialized");
|
||||
throw error_already_set();
|
||||
}
|
||||
}
|
||||
m_wrapped_objects.push_back(holder.release());
|
||||
}
|
||||
|
||||
extension_instance::extension_instance(PyTypeObject* class_)
|
||||
: instance(class_)
|
||||
{
|
||||
}
|
||||
|
||||
extension_instance::~extension_instance()
|
||||
{
|
||||
for (held_objects::const_iterator p = m_wrapped_objects.begin(),
|
||||
finish = m_wrapped_objects.end();
|
||||
p != finish; ++p)
|
||||
{
|
||||
delete *p;
|
||||
}
|
||||
}
|
||||
|
||||
meta_class<extension_instance>* extension_meta_class()
|
||||
{
|
||||
static meta_class<extension_instance> result;
|
||||
return &result;
|
||||
}
|
||||
|
||||
typedef class_t<extension_instance> extension_class_t;
|
||||
|
||||
bool is_subclass(const extension_class_t* derived,
|
||||
const PyObject* possible_base)
|
||||
{
|
||||
|
||||
tuple bases = derived->bases();
|
||||
|
||||
for (std::size_t i = 0, size = bases.size(); i < size; ++i)
|
||||
{
|
||||
const PyObject* base = bases[i].get();
|
||||
|
||||
if (base == possible_base)
|
||||
return true;
|
||||
|
||||
if (base->ob_type == extension_meta_class())
|
||||
{
|
||||
const extension_class_t* base_class = downcast<const extension_class_t>(base);
|
||||
if (is_subclass(base_class, possible_base))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Return true iff obj is an obj of target_class
|
||||
bool is_instance(extension_instance* obj,
|
||||
class_t<extension_instance>* target_class)
|
||||
{
|
||||
if (obj->ob_type == target_class)
|
||||
return true;
|
||||
else
|
||||
{
|
||||
return is_subclass(
|
||||
downcast<class_t<extension_instance> >(obj->ob_type).get(),
|
||||
as_object(target_class));
|
||||
}
|
||||
}
|
||||
|
||||
void two_string_error(PyObject* exception_object, const char* format, const char* s1, const char* s2)
|
||||
{
|
||||
char buffer[256];
|
||||
std::size_t format_length = BOOST_CSTD_::strlen(format);
|
||||
std::size_t length1 = BOOST_CSTD_::strlen(s1);
|
||||
std::size_t length2 = BOOST_CSTD_::strlen(s2);
|
||||
|
||||
std::size_t additional_length = length1 + length2;
|
||||
if (additional_length + format_length > format_length - 1)
|
||||
{
|
||||
std::size_t difference = sizeof(buffer) - 1 - additional_length;
|
||||
length1 -= difference / 2;
|
||||
additional_length -= difference / 2;
|
||||
}
|
||||
|
||||
sprintf(buffer, format, length1, s1, length2, s2);
|
||||
|
||||
PyErr_SetString(exception_object, buffer);
|
||||
if (exception_object == PyExc_TypeError)
|
||||
throw argument_error();
|
||||
else
|
||||
throw error_already_set();
|
||||
}
|
||||
|
||||
// This is called when an attempt has been made to convert the given obj to
|
||||
// a C++ type for which it doesn't have any obj data. In that case, either
|
||||
// the obj was not derived from the target_class, or the appropriate
|
||||
// __init__ function wasn't called to initialize the obj data of the target class.
|
||||
void report_missing_instance_data(
|
||||
extension_instance* obj, // The object being converted
|
||||
class_t<extension_instance>* target_class, // the extension class of the C++ type
|
||||
const std::type_info& target_typeid, // The typeid of the C++ type
|
||||
bool target_is_ptr)
|
||||
{
|
||||
char buffer[256];
|
||||
if (is_instance(obj, target_class))
|
||||
{
|
||||
if (target_is_ptr)
|
||||
{
|
||||
two_string_error(PyExc_RuntimeError,
|
||||
"Object of extension class '%.*s' does not wrap <%.*s>.",
|
||||
obj->ob_type->tp_name, target_typeid.name());
|
||||
}
|
||||
else
|
||||
{
|
||||
const char message[] = "__init__ function for extension class '%.*s' was never called.";
|
||||
sprintf(buffer, message, sizeof(buffer) - sizeof(message) - 1,
|
||||
target_class->tp_name);
|
||||
}
|
||||
PyErr_SetString(PyExc_RuntimeError, buffer);
|
||||
}
|
||||
else if (target_class == 0)
|
||||
{
|
||||
const char message[] = "Cannot convert to <%.*s>; its Python class was never created or has been deleted.";
|
||||
sprintf(buffer, message, sizeof(buffer) - sizeof(message) - 1, target_typeid.name());
|
||||
PyErr_SetString(PyExc_RuntimeError, buffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
two_string_error(PyExc_TypeError, "extension class '%.*s' is not convertible into '%.*s'.",
|
||||
obj->ob_type->tp_name, target_class->tp_name);
|
||||
}
|
||||
}
|
||||
|
||||
void report_missing_instance_data(
|
||||
extension_instance* obj, // The object being converted
|
||||
class_t<extension_instance>* target_class, // the extension class of the C++ type
|
||||
const std::type_info& target_typeid) // The typeid of the C++ type
|
||||
{
|
||||
report_missing_instance_data(obj, target_class, target_typeid, false);
|
||||
}
|
||||
|
||||
void report_missing_ptr_data(
|
||||
extension_instance* obj, // The object being converted
|
||||
class_t<extension_instance>* target_class, // the extension class of the C++ type
|
||||
const std::type_info& target_typeid) // The typeid of the C++ type
|
||||
{
|
||||
report_missing_instance_data(obj, target_class, target_typeid, true);
|
||||
}
|
||||
|
||||
void report_missing_class_object(const std::type_info& info)
|
||||
{
|
||||
char buffer[256];
|
||||
const char message[] = "Cannot convert <%.*s> to python; its Python class was never created or has been deleted.";
|
||||
sprintf(buffer, message, sizeof(buffer) - sizeof(message) - 1, info.name());
|
||||
PyErr_SetString(PyExc_RuntimeError, buffer);
|
||||
throw error_already_set();
|
||||
}
|
||||
|
||||
void report_released_smart_pointer(const std::type_info& info)
|
||||
{
|
||||
char buffer[256];
|
||||
const char message[] = "Converting from python, pointer or smart pointer to <%.*s> is NULL.";
|
||||
sprintf(buffer, message, sizeof(buffer) - sizeof(message) - 1, info.name());
|
||||
PyErr_SetString(PyExc_RuntimeError, buffer);
|
||||
throw argument_error();
|
||||
}
|
||||
|
||||
read_only_setattr_function::read_only_setattr_function(const char* name)
|
||||
: m_name(name)
|
||||
{
|
||||
}
|
||||
|
||||
PyObject* read_only_setattr_function::do_call(PyObject* /*args*/, PyObject* /*keywords*/) const
|
||||
{
|
||||
PyErr_SetObject(PyExc_AttributeError, ("'" + m_name + "' attribute is read-only").get());
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char* read_only_setattr_function::description() const
|
||||
{
|
||||
return "uncallable";
|
||||
}
|
||||
|
||||
extension_class_base::extension_class_base(const char* name)
|
||||
: class_t<extension_instance>(
|
||||
extension_meta_class(), string(name), tuple(), dictionary())
|
||||
{
|
||||
}
|
||||
|
||||
// This function is used in from_python() to convert wrapped classes that are
|
||||
// related by inheritance. The problem is this: although C++ provides all necessary
|
||||
// conversion operators, source and target of a conversion must be known at compile
|
||||
// time. However, in Python we want to convert classes at runtime. The solution is to
|
||||
// generate conversion functions at compile time, register them within the appropriate
|
||||
// class objects and call them when a particular runtime conversion is required.
|
||||
|
||||
// If functions for any possible conversion have to be stored, their number will grow
|
||||
// qudratically. To reduce this number, we actually store only conversion functions
|
||||
// between adjacent levels in the inheritance tree. By traversing the tree recursively,
|
||||
// we can build any allowed conversion as a concatenation of simple conversions. This
|
||||
// traversal is done in the functions try_base_class_conversions() and
|
||||
// try_derived_class_conversions(). If a particular conversion is impossible, all
|
||||
// conversion functions will return a NULL pointer.
|
||||
|
||||
// The function extract_object_from_holder() attempts to actually extract the pointer
|
||||
// to the contained object from an instance_holder_base (a wrapper class). A conversion
|
||||
// of the held object to 'T *' is allowed when the conversion
|
||||
// 'dynamic_cast<instance_holder<T> *>(an_instance_holder_base)' succeeds.
|
||||
void* extension_class_base::try_class_conversions(instance_holder_base* object) const
|
||||
{
|
||||
void* result = try_derived_class_conversions(object);
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
if (!object->held_by_value())
|
||||
return try_base_class_conversions(object);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
void* extension_class_base::try_base_class_conversions(instance_holder_base* object) const
|
||||
{
|
||||
for (std::size_t i = 0; i < base_classes().size(); ++i)
|
||||
{
|
||||
if (base_classes()[i].convert == 0)
|
||||
continue;
|
||||
void* result1 = base_classes()[i].class_object->extract_object_from_holder(object);
|
||||
if (result1)
|
||||
return (*base_classes()[i].convert)(result1);
|
||||
|
||||
void* result2 = base_classes()[i].class_object->try_base_class_conversions(object);
|
||||
if (result2)
|
||||
return (*base_classes()[i].convert)(result2);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void* extension_class_base::try_derived_class_conversions(instance_holder_base* object) const
|
||||
{
|
||||
for (std::size_t i = 0; i < derived_classes().size(); ++i)
|
||||
{
|
||||
void* result1 = derived_classes()[i].class_object->extract_object_from_holder(object);
|
||||
if (result1)
|
||||
return (*derived_classes()[i].convert)(result1);
|
||||
|
||||
void* result2 = derived_classes()[i].class_object->try_derived_class_conversions(object);
|
||||
if (result2)
|
||||
return (*derived_classes()[i].convert)(result2);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void extension_class_base::add_method(function* method, const char* name)
|
||||
{
|
||||
add_method(reference<function>(method), name);
|
||||
}
|
||||
|
||||
void extension_class_base::add_method(reference<function> method, const char* name)
|
||||
{
|
||||
// Add the attribute to the computed target
|
||||
function::add_to_namespace(method, name, this->dict().get());
|
||||
|
||||
// If it is a special member function it should be enabled both here and there.
|
||||
detail::enable_named_method(this, name);
|
||||
}
|
||||
|
||||
void extension_class_base::add_constructor_object(function* init_fn)
|
||||
{
|
||||
add_method(init_fn, "__init__");
|
||||
}
|
||||
|
||||
void extension_class_base::add_setter_method(function* setter_, const char* name)
|
||||
{
|
||||
reference<function> setter(setter_);
|
||||
add_method(setter, (detail::setattr_string() + name + "__").c_str());
|
||||
}
|
||||
|
||||
void extension_class_base::add_getter_method(function* getter_, const char* name)
|
||||
{
|
||||
reference<function> getter(getter_);
|
||||
add_method(getter, (detail::getattr_string() + name + "__").c_str());
|
||||
}
|
||||
|
||||
void extension_class_base::set_attribute(const char* name, PyObject* x_)
|
||||
{
|
||||
ref x(x_);
|
||||
set_attribute(name, x);
|
||||
}
|
||||
|
||||
void extension_class_base::set_attribute(const char* name, ref x)
|
||||
{
|
||||
dict().set_item(string(name), x);
|
||||
if (PyCallable_Check(x.get()))
|
||||
detail::enable_named_method(this, name);
|
||||
}
|
||||
|
||||
operator_dispatcher::operator_dispatcher(const ref& o, const ref& s)
|
||||
: m_object(o), m_self(s), m_free_list_link(0)
|
||||
|
||||
{
|
||||
ob_refcnt = 1;
|
||||
ob_type = &type_obj;
|
||||
}
|
||||
|
||||
operator_dispatcher*
|
||||
operator_dispatcher::create(const ref& object, const ref& self)
|
||||
{
|
||||
operator_dispatcher* const result = free_list;
|
||||
if (result == 0)
|
||||
return new operator_dispatcher(object, self);
|
||||
|
||||
free_list = result->m_free_list_link;
|
||||
result->m_object = object;
|
||||
result->m_self = self;
|
||||
Py_INCREF(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
||||
void operator_dispatcher_dealloc(PyObject* self)
|
||||
{
|
||||
operator_dispatcher* obj = static_cast<operator_dispatcher*>(self);
|
||||
obj->m_free_list_link = operator_dispatcher::free_list;
|
||||
operator_dispatcher::free_list = obj;
|
||||
obj->m_object.reset();
|
||||
obj->m_self.reset();
|
||||
}
|
||||
|
||||
int operator_dispatcher_coerce(PyObject** l, PyObject** r)
|
||||
{
|
||||
Py_INCREF(*l);
|
||||
try
|
||||
{
|
||||
*r = operator_dispatcher::create(ref(*r, ref::increment_count), ref());
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
handle_exception();
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#define PY_DEFINE_OPERATOR(id, symbol) \
|
||||
PyObject* operator_dispatcher_call_##id(PyObject* left, PyObject* right) \
|
||||
{ \
|
||||
/* unwrap the arguments from their OperatorDispatcher */ \
|
||||
PyObject* self; \
|
||||
PyObject* other; \
|
||||
int reverse = unwrap_args(left, right, self, other); \
|
||||
if (reverse == unwrap_exception_code) \
|
||||
return 0; \
|
||||
\
|
||||
/* call the function */ \
|
||||
PyObject* result = \
|
||||
PyEval_CallMethod(self, \
|
||||
const_cast<char*>(reverse ? "__r" #id "__" : "__" #id "__"), \
|
||||
const_cast<char*>("(O)"), \
|
||||
other); \
|
||||
if (result == 0 && PyErr_GivenExceptionMatches(PyErr_Occurred(), PyExc_AttributeError)) \
|
||||
{ \
|
||||
PyErr_Clear(); \
|
||||
PyErr_SetString(PyExc_TypeError, "bad operand type(s) for " #symbol); \
|
||||
} \
|
||||
return result; \
|
||||
}
|
||||
|
||||
PY_DEFINE_OPERATOR(add, +)
|
||||
PY_DEFINE_OPERATOR(sub, -)
|
||||
PY_DEFINE_OPERATOR(mul, *)
|
||||
PY_DEFINE_OPERATOR(div, /)
|
||||
PY_DEFINE_OPERATOR(mod, %)
|
||||
PY_DEFINE_OPERATOR(divmod, divmod)
|
||||
PY_DEFINE_OPERATOR(lshift, <<)
|
||||
PY_DEFINE_OPERATOR(rshift, >>)
|
||||
PY_DEFINE_OPERATOR(and, &)
|
||||
PY_DEFINE_OPERATOR(xor, ^)
|
||||
PY_DEFINE_OPERATOR(or, |)
|
||||
|
||||
/* coercion rules for heterogeneous pow():
|
||||
pow(Foo, int): left, right coerced; m: None => reverse = 0
|
||||
pow(int, Foo): left, right coerced; m: None => reverse = 1
|
||||
pow(Foo, int, int): left, right, m coerced => reverse = 0
|
||||
pow(int, Foo, int): left, right, m coerced => reverse = 1
|
||||
pow(int, int, Foo): left, right, m coerced => reverse = 2
|
||||
pow(Foo, Foo, int): left, right coerced; m coerced twice => reverse = 0
|
||||
pow(Foo, int, Foo): left, right, m coerced => reverse = 0
|
||||
pow(int, Foo, Foo): left, right, m coerced => reverse = 1
|
||||
*/
|
||||
PyObject* operator_dispatcher_call_pow(PyObject* left, PyObject* right, PyObject* m)
|
||||
{
|
||||
int reverse;
|
||||
PyObject* self;
|
||||
PyObject* first;
|
||||
PyObject* second;
|
||||
|
||||
if (m->ob_type == Py_None->ob_type)
|
||||
{
|
||||
reverse = unwrap_args(left, right, self, first);
|
||||
second = m;
|
||||
}
|
||||
else
|
||||
{
|
||||
reverse = unwrap_pow_args(left, right, m, self, first, second);
|
||||
}
|
||||
|
||||
if (reverse == unwrap_exception_code)
|
||||
return 0;
|
||||
|
||||
// call the function
|
||||
PyObject* result =
|
||||
PyEval_CallMethod(self,
|
||||
const_cast<char*>((reverse == 0)
|
||||
? "__pow__"
|
||||
: (reverse == 1)
|
||||
? "__rpow__"
|
||||
: "__rrpow__"),
|
||||
const_cast<char*>("(OO)"),
|
||||
first, second);
|
||||
if (result == 0 &&
|
||||
(PyErr_GivenExceptionMatches(PyErr_Occurred(), PyExc_TypeError) ||
|
||||
PyErr_GivenExceptionMatches(PyErr_Occurred(), PyExc_AttributeError)))
|
||||
{
|
||||
PyErr_Clear();
|
||||
PyErr_SetString(PyExc_TypeError, "bad operand type(s) for pow()");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int operator_dispatcher_call_cmp(PyObject* left, PyObject* right)
|
||||
{
|
||||
// unwrap the arguments from their OperatorDispatcher
|
||||
PyObject* self;
|
||||
PyObject* other;
|
||||
int reverse = unwrap_args(left, right, self, other);
|
||||
if (reverse == unwrap_exception_code)
|
||||
return -1;
|
||||
|
||||
// call the function
|
||||
PyObject* result =
|
||||
PyEval_CallMethod(self,
|
||||
const_cast<char*>(reverse ? "__rcmp__" : "__cmp__"),
|
||||
const_cast<char*>("(O)"),
|
||||
other);
|
||||
if (result == 0)
|
||||
{
|
||||
PyErr_Clear();
|
||||
PyErr_SetString(PyExc_TypeError, "bad operand type(s) for cmp() or <");
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
return BOOST_PYTHON_CONVERSION::from_python(result, type<int>());
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
PyErr_Clear();
|
||||
PyErr_SetString(PyExc_TypeError, "cmp() didn't return int");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
|
||||
PyTypeObject operator_dispatcher::type_obj =
|
||||
{
|
||||
PyObject_HEAD_INIT(&PyType_Type)
|
||||
0,
|
||||
const_cast<char*>("operator_dispatcher"),
|
||||
sizeof(operator_dispatcher),
|
||||
0,
|
||||
&operator_dispatcher_dealloc,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
&operator_dispatcher_call_cmp,
|
||||
0,
|
||||
&operator_dispatcher::number_methods,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
};
|
||||
|
||||
PyNumberMethods operator_dispatcher::number_methods =
|
||||
{
|
||||
&operator_dispatcher_call_add,
|
||||
&operator_dispatcher_call_sub,
|
||||
&operator_dispatcher_call_mul,
|
||||
&operator_dispatcher_call_div,
|
||||
&operator_dispatcher_call_mod,
|
||||
&operator_dispatcher_call_divmod,
|
||||
&operator_dispatcher_call_pow,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
&operator_dispatcher_call_lshift,
|
||||
&operator_dispatcher_call_rshift,
|
||||
&operator_dispatcher_call_and,
|
||||
&operator_dispatcher_call_xor,
|
||||
&operator_dispatcher_call_or,
|
||||
&operator_dispatcher_coerce,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
}} // namespace boost::python
|
||||
@@ -1,167 +0,0 @@
|
||||
// (C) Copyright David Abrahams 2000. Permission to copy, use, modify, sell and
|
||||
// distribute this software is granted provided this copyright notice appears
|
||||
// in all copies. This software is provided "as is" without express or implied
|
||||
// warranty, and with no claim as to its suitability for any purpose.
|
||||
//
|
||||
// The author gratefully acknowleges the support of Dragon Systems, Inc., in
|
||||
// producing this work.
|
||||
|
||||
#include <boost/python/detail/functions.hpp>
|
||||
#include <boost/python/detail/types.hpp>
|
||||
#include <boost/python/detail/singleton.hpp>
|
||||
#include <boost/python/objects.hpp>
|
||||
#include <boost/python/errors.hpp>
|
||||
|
||||
namespace boost { namespace python { namespace detail {
|
||||
|
||||
struct function::type_object :
|
||||
singleton<function::type_object, callable<boost::python::detail::type_object<function> > >
|
||||
{
|
||||
type_object() : singleton_base(&PyType_Type) {}
|
||||
};
|
||||
|
||||
|
||||
void function::add_to_namespace(reference<function> new_function, const char* name, PyObject* dict)
|
||||
{
|
||||
dictionary d(ref(dict, ref::increment_count));
|
||||
string key(name);
|
||||
|
||||
ref existing_object = d.get_item(key.reference());
|
||||
if (existing_object.get() == 0)
|
||||
{
|
||||
d[key] = ref(new_function.get(), ref::increment_count);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (existing_object->ob_type == type_object::instance())
|
||||
{
|
||||
function* f = static_cast<function*>(existing_object.get());
|
||||
while (f->m_overloads.get() != 0)
|
||||
f = f->m_overloads.get();
|
||||
f->m_overloads = new_function;
|
||||
}
|
||||
else
|
||||
{
|
||||
PyErr_SetObject(PyExc_RuntimeError,
|
||||
(string("Attempt to overload ") + name
|
||||
+ " failed. The existing attribute has type "
|
||||
+ existing_object->ob_type->tp_name).get());
|
||||
throw error_already_set();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function::function()
|
||||
: python_object(type_object::instance())
|
||||
{
|
||||
}
|
||||
|
||||
PyObject* function::call(PyObject* args, PyObject* keywords) const
|
||||
{
|
||||
for (const function* f = this; f != 0; f = f->m_overloads.get())
|
||||
{
|
||||
PyErr_Clear();
|
||||
try
|
||||
{
|
||||
PyObject* const result = f->do_call(args, keywords);
|
||||
if (result != 0)
|
||||
return result;
|
||||
}
|
||||
catch(const argument_error&)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
if (m_overloads.get() == 0)
|
||||
return 0;
|
||||
|
||||
PyErr_Clear();
|
||||
string message("No overloaded functions match (");
|
||||
tuple arguments(ref(args, ref::increment_count));
|
||||
for (std::size_t i = 0; i < arguments.size(); ++i)
|
||||
{
|
||||
if (i != 0)
|
||||
message += ", ";
|
||||
message += arguments[i]->ob_type->tp_name;
|
||||
}
|
||||
|
||||
message += "). Candidates are:\n";
|
||||
for (const function* f1 = this; f1 != 0; f1 = f1->m_overloads.get())
|
||||
{
|
||||
if (f1 != this)
|
||||
message += "\n";
|
||||
message += f1->description();
|
||||
}
|
||||
|
||||
PyErr_SetObject(PyExc_TypeError, message.get());
|
||||
return 0;
|
||||
}
|
||||
|
||||
bound_function* bound_function::create(const ref& target, const ref& fn)
|
||||
{
|
||||
bound_function* const result = free_list;
|
||||
if (result == 0)
|
||||
return new bound_function(target, fn);
|
||||
|
||||
free_list = result->m_free_list_link;
|
||||
result->m_target = target;
|
||||
result->m_unbound_function = fn;
|
||||
Py_INCREF(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
// The instance class whose obj represents the type of bound_function
|
||||
// objects in Python. bound_functions must be GetAttrable so the __doc__
|
||||
// attribute of built-in Python functions can be accessed when bound.
|
||||
struct bound_function::type_object :
|
||||
singleton<bound_function::type_object,
|
||||
getattrable<callable<boost::python::detail::type_object<bound_function> > > >
|
||||
{
|
||||
type_object() : singleton_base(&PyType_Type) {}
|
||||
|
||||
private: // type_object<bound_function> hook override
|
||||
void dealloc(bound_function*) const;
|
||||
};
|
||||
|
||||
bound_function::bound_function(const ref& target, const ref& fn)
|
||||
: python_object(type_object::instance()),
|
||||
m_target(target),
|
||||
m_unbound_function(fn),
|
||||
m_free_list_link(0)
|
||||
{
|
||||
}
|
||||
|
||||
PyObject*
|
||||
bound_function::call(PyObject* args, PyObject* keywords) const
|
||||
{
|
||||
// Build a new tuple which prepends the target to the arguments
|
||||
tuple tail_arguments(ref(args, ref::increment_count));
|
||||
ref all_arguments(PyTuple_New(tail_arguments.size() + 1));
|
||||
|
||||
PyTuple_SET_ITEM(all_arguments.get(), 0, m_target.get());
|
||||
Py_INCREF(m_target.get());
|
||||
for (std::size_t i = 0; i < tail_arguments.size(); ++i)
|
||||
{
|
||||
PyTuple_SET_ITEM(all_arguments.get(), i + 1, tail_arguments[i].get());
|
||||
Py_INCREF(tail_arguments[i].get());
|
||||
}
|
||||
|
||||
return PyEval_CallObjectWithKeywords(m_unbound_function.get(), all_arguments.get(), keywords);
|
||||
}
|
||||
|
||||
PyObject* bound_function::getattr(const char* name) const
|
||||
{
|
||||
return PyObject_GetAttrString(m_unbound_function.get(), const_cast<char*>(name));
|
||||
}
|
||||
|
||||
void bound_function::type_object::dealloc(bound_function* obj) const
|
||||
{
|
||||
obj->m_free_list_link = free_list;
|
||||
free_list = obj;
|
||||
obj->m_target.reset();
|
||||
obj->m_unbound_function.reset();
|
||||
}
|
||||
|
||||
bound_function* bound_function::free_list;
|
||||
|
||||
}}} // namespace boost::python::detail
|
||||
@@ -1,26 +0,0 @@
|
||||
from gen_callback import *
|
||||
from gen_caller import *
|
||||
from gen_init_function import *
|
||||
from gen_signatures import *
|
||||
from gen_singleton import *
|
||||
from gen_extclass import *
|
||||
|
||||
def gen_all(args):
|
||||
open('callback.h', 'w').write(gen_callback(args))
|
||||
open('caller.h', 'w').write(gen_caller(args))
|
||||
open('init_function.h', 'w').write(gen_init_function(args))
|
||||
open('signatures.h', 'w').write(gen_signatures(args))
|
||||
open('instance.h', 'w').write(gen_singleton(args))
|
||||
open('extclass.h', 'w').write(gen_extclass(args))
|
||||
|
||||
if __name__ == '__main__':
|
||||
import sys
|
||||
|
||||
if len(sys.argv) == 1:
|
||||
args = 10
|
||||
else:
|
||||
args = int(sys.argv[1])
|
||||
|
||||
print gen_all(args)
|
||||
|
||||
|
||||
@@ -1,124 +0,0 @@
|
||||
from gen_function import *
|
||||
import string
|
||||
|
||||
def gen_callback(args):
|
||||
return (
|
||||
"""// (C) Copyright David Abrahams 2000. Permission to copy, use, modify, sell and
|
||||
// distribute this software is granted provided this copyright notice appears
|
||||
// in all copies. This software is provided "as is" without express or implied
|
||||
// warranty, and with no claim as to its suitability for any purpose.
|
||||
//
|
||||
// The author gratefully acknowleges the support of Dragon Systems, Inc., in
|
||||
// producing this work.
|
||||
//
|
||||
// This file was generated for %d-argument python callbacks by gen_callback.python
|
||||
|
||||
#ifndef CALLBACK_DWA_052100_H_
|
||||
# define CALLBACK_DWA_052100_H_
|
||||
|
||||
# include <boost/python/detail/config.hpp>
|
||||
# include <boost/python/conversions.hpp>
|
||||
|
||||
namespace boost { namespace python {
|
||||
|
||||
namespace detail {
|
||||
template <class T>
|
||||
inline void callback_adjust_refcount(PyObject*, type<T>) {}
|
||||
|
||||
inline void callback_adjust_refcount(PyObject* p, type<PyObject*>)
|
||||
{ Py_INCREF(p); }
|
||||
}
|
||||
|
||||
// Calling Python from C++
|
||||
template <class R>
|
||||
struct callback
|
||||
{""" % args
|
||||
|
||||
+ gen_functions('''
|
||||
%{ template <%(class A%n%:, %)>
|
||||
%} static R call_method(PyObject* self, const char* name%(, const A%n& a%n%))
|
||||
{%(
|
||||
ref p%n(to_python(a%n));%)
|
||||
ref result(PyEval_CallMethod(self, const_cast<char*>(name),
|
||||
const_cast<char*>("(%(O%))")%(,
|
||||
p%n.get()%)));
|
||||
detail::callback_adjust_refcount(result.get(), type<R>());
|
||||
return from_python(result.get(), type<R>());
|
||||
}
|
||||
|
||||
%{ template <%(class A%n%:, %)>
|
||||
%} static R call(PyObject* self%(, const A%n& a%n%))
|
||||
{%(
|
||||
ref p%n(to_python(a%n));%)
|
||||
ref result(PyEval_CallFunction(self, const_cast<char*>("(%(O%))")%(,
|
||||
p%n.get()%)));
|
||||
detail::callback_adjust_refcount(result.get(), type<R>());
|
||||
return from_python(result.get(), type<R>());
|
||||
}
|
||||
''', args)
|
||||
+
|
||||
"""};
|
||||
|
||||
// This specialization wouldn't be needed, but MSVC6 doesn't correctly allow the following:
|
||||
// void g();
|
||||
// void f() { return g(); }
|
||||
template <>
|
||||
struct callback<void>
|
||||
{
|
||||
"""
|
||||
+ gen_functions('''
|
||||
%{ template <%(class A%n%:, %)>
|
||||
%} static void call_method(PyObject* self, const char* name%(, const A%n& a%n%))
|
||||
{%(
|
||||
ref p%n(to_python(a%n));%)
|
||||
ref result(PyEval_CallMethod(self, const_cast<char*>(name),
|
||||
const_cast<char*>("(%(O%))")%(,
|
||||
p%n.get()%)));
|
||||
}
|
||||
|
||||
%{ template <%(class A%n%:, %)>
|
||||
%} static void call(PyObject* self%(, const A%n& a%n%))
|
||||
{%(
|
||||
ref p%n(to_python(a%n));%)
|
||||
ref result(PyEval_CallFunction(self, const_cast<char*>("(%(O%))")%(,
|
||||
p%n.get()%)));
|
||||
}
|
||||
''', args)
|
||||
+
|
||||
"""};
|
||||
|
||||
// Make it a compile-time error to try to return a const char* from a virtual
|
||||
// function. The standard conversion
|
||||
//
|
||||
// from_python(PyObject* string, boost::python::type<const char*>)
|
||||
//
|
||||
// returns a pointer to the character array which is internal to string. The
|
||||
// problem with trying to do this in a standard callback function is that the
|
||||
// Python string would likely be destroyed upon return from the calling function
|
||||
// (boost::python::callback<const char*>::call[_method]) when its reference count is
|
||||
// decremented. If you absolutely need to do this and you're sure it's safe (it
|
||||
// usually isn't), you can use
|
||||
//
|
||||
// boost::python::string result(boost::python::callback<boost::python::string>::call[_method](...args...));
|
||||
// ...result.c_str()... // access the char* array
|
||||
template <>
|
||||
struct callback<const char*>
|
||||
{
|
||||
// Try hard to generate a readable error message
|
||||
typedef struct unsafe_since_python_string_may_be_destroyed {} call, call_method;
|
||||
};
|
||||
|
||||
}} // namespace boost::python
|
||||
|
||||
#endif // CALLBACK_DWA_052100_H_
|
||||
""")
|
||||
|
||||
if __name__ == '__main__':
|
||||
import sys
|
||||
|
||||
if len(sys.argv) == 1:
|
||||
args = 5
|
||||
else:
|
||||
args = int(sys.argv[1])
|
||||
|
||||
print gen_callback(args)
|
||||
@@ -1,138 +0,0 @@
|
||||
# (C) Copyright David Abrahams 2000. Permission to copy, use, modify, sell and
|
||||
# distribute this software is granted provided this copyright notice appears
|
||||
# in all copies. This software is provided "as is" without express or implied
|
||||
# warranty, and with no claim as to its suitability for any purpose.
|
||||
#
|
||||
# The author gratefully acknowleges the support of Dragon Systems, Inc., in
|
||||
# producing this work.
|
||||
|
||||
from gen_function import *
|
||||
import string
|
||||
|
||||
header = '''// (C) Copyright David Abrahams 2000. Permission to copy, use, modify, sell and
|
||||
// distribute this software is granted provided this copyright notice appears
|
||||
// in all copies. This software is provided "as is" without express or implied
|
||||
// warranty, and with no claim as to its suitability for any purpose.
|
||||
//
|
||||
// The author gratefully acknowleges the support of Dragon Systems, Inc., in
|
||||
// producing this work.
|
||||
//
|
||||
// This file generated for %d-argument member functions and %d-argument free
|
||||
// functions by gen_caller.python
|
||||
'''
|
||||
|
||||
body_sections = (
|
||||
'''
|
||||
#ifndef CALLER_DWA05090_H_
|
||||
# define CALLER_DWA05090_H_
|
||||
|
||||
# include <boost/python/detail/config.hpp>
|
||||
# include <boost/python/detail/wrap_python.hpp>
|
||||
# include <boost/config.hpp>
|
||||
# include <boost/python/detail/signatures.hpp>
|
||||
# include <boost/python/detail/none.hpp>
|
||||
|
||||
namespace boost { namespace python {
|
||||
|
||||
// Calling C++ from Python
|
||||
template <class R>
|
||||
struct caller
|
||||
{
|
||||
''',
|
||||
'''
|
||||
''',
|
||||
''' // Free functions
|
||||
''',
|
||||
'''};
|
||||
|
||||
template <>
|
||||
struct caller<void>
|
||||
{
|
||||
''',
|
||||
'''
|
||||
''',
|
||||
'''
|
||||
// Free functions
|
||||
''',
|
||||
'''};
|
||||
|
||||
}} // namespace boost::python
|
||||
|
||||
#endif
|
||||
''')
|
||||
|
||||
#'
|
||||
|
||||
member_function = ''' template <class T%(, class A%n%)>
|
||||
static PyObject* call(%1 (T::*pmf)(%(A%n%:, %))%2, PyObject* args, PyObject* /* keywords */ ) {
|
||||
PyObject* self;
|
||||
%( PyObject* a%n;
|
||||
%) if (!PyArg_ParseTuple(args, const_cast<char*>("O%(O%)"), &self%(, &a%n%)))
|
||||
return 0;
|
||||
T& target = from_python(self, type<T&>());
|
||||
%3(target.*pmf)(%(from_python(a%n, type<A%n>())%:,
|
||||
%))%4
|
||||
}
|
||||
|
||||
'''
|
||||
|
||||
free_function = '''%{ template <%(class A%n%:, %)>
|
||||
%} static PyObject* call(%1 (*f)(%(A%n%:, %)), PyObject* args, PyObject* /* keywords */ ) {
|
||||
%( PyObject* a%n;
|
||||
%) if (!PyArg_ParseTuple(args, const_cast<char*>("%(O%)")%(, &a%n%)))
|
||||
return 0;
|
||||
%2f(%(from_python(a%n, type<A%n>())%:,
|
||||
%))%3
|
||||
}
|
||||
|
||||
'''
|
||||
|
||||
def gen_caller(member_function_args, free_function_args = None):
|
||||
if free_function_args is None:
|
||||
free_function_args = member_function_args + 1
|
||||
|
||||
return_none = ''';
|
||||
return detail::none();'''
|
||||
|
||||
return (header % (member_function_args, free_function_args)
|
||||
+ body_sections[0]
|
||||
+ gen_functions(member_function, member_function_args,
|
||||
'R', '', 'return to_python(', ');')
|
||||
+ body_sections[1]
|
||||
+ gen_functions(member_function, member_function_args,
|
||||
'R', ' const', 'return to_python(', ');')
|
||||
+ body_sections[2]
|
||||
|
||||
+ gen_functions(free_function, free_function_args,
|
||||
'R', 'return to_python(', ');')
|
||||
+ body_sections[3]
|
||||
|
||||
# specialized part for void return values begins here
|
||||
+ gen_functions(member_function, member_function_args,
|
||||
'void', '', '', return_none)
|
||||
+ body_sections[4]
|
||||
+ gen_functions(member_function, member_function_args,
|
||||
'void', ' const', '', return_none)
|
||||
+ body_sections[5]
|
||||
|
||||
+ gen_functions(free_function, free_function_args,
|
||||
'void', '', return_none)
|
||||
+ body_sections[6]
|
||||
)
|
||||
|
||||
if __name__ == '__main__':
|
||||
import sys
|
||||
|
||||
if len(sys.argv) == 1:
|
||||
member_function_args = 5
|
||||
free_function_args = 6
|
||||
else:
|
||||
member_function_args = int(sys.argv[1])
|
||||
if len(sys.argv) > 2:
|
||||
free_function_args = int(sys.argv[2])
|
||||
else:
|
||||
free_function_args = member_function_args
|
||||
|
||||
print gen_caller(member_function_args, free_function_args)
|
||||
|
||||
|
||||
@@ -1,830 +0,0 @@
|
||||
from gen_function import *
|
||||
import string
|
||||
|
||||
def gen_extclass(args):
|
||||
return (
|
||||
"""// (C) Copyright David Abrahams 2000. Permission to copy, use, modify, sell and
|
||||
// distribute this software is granted provided this copyright notice appears
|
||||
// in all copies. This software is provided "as is" without express or implied
|
||||
// warranty, and with no claim as to its suitability for any purpose.
|
||||
//
|
||||
// The author gratefully acknowleges the support of Dragon Systems, Inc., in
|
||||
// producing this work.
|
||||
//
|
||||
// This file automatically generated for %d-argument constructors by
|
||||
// gen_extclass.python
|
||||
|
||||
#ifndef EXTENSION_CLASS_DWA052000_H_
|
||||
# define EXTENSION_CLASS_DWA052000_H_
|
||||
|
||||
# include <boost/python/detail/config.hpp>
|
||||
# include <boost/python/classes.hpp>
|
||||
# include <vector>
|
||||
# include <boost/python/detail/none.hpp>
|
||||
# include <boost/python/objects.hpp>
|
||||
# include <boost/python/detail/functions.hpp>
|
||||
# include <memory>
|
||||
# include <boost/python/detail/init_function.hpp>
|
||||
# include <typeinfo>
|
||||
# include <boost/smart_ptr.hpp>
|
||||
|
||||
namespace boost { namespace python {
|
||||
|
||||
// forward declarations
|
||||
template <long which, class operand> struct operators;
|
||||
template <class T> struct left_operand;
|
||||
template <class T> struct right_operand;
|
||||
|
||||
enum without_downcast_t { without_downcast };
|
||||
|
||||
namespace detail {
|
||||
|
||||
// forward declarations
|
||||
class extension_instance;
|
||||
class extension_class_base;
|
||||
template <class T> class instance_holder;
|
||||
template <class T, class U> class instance_value_holder;
|
||||
template <class ref, class T> class instance_ptr_holder;
|
||||
template <class Specified> struct operand_select;
|
||||
template <long> struct choose_op;
|
||||
template <long> struct choose_rop;
|
||||
template <long> struct choose_unary_op;
|
||||
template <long> struct define_operator;
|
||||
|
||||
meta_class<extension_instance>* extension_meta_class();
|
||||
extension_instance* get_extension_instance(PyObject* p);
|
||||
void report_missing_instance_data(extension_instance*, class_t<extension_instance>*, const std::type_info&);
|
||||
void report_missing_ptr_data(extension_instance*, class_t<extension_instance>*, const std::type_info&);
|
||||
void report_missing_class_object(const std::type_info&);
|
||||
void report_released_smart_pointer(const std::type_info&);
|
||||
|
||||
template <class T>
|
||||
T* check_non_null(T* p)
|
||||
{
|
||||
if (p == 0)
|
||||
report_released_smart_pointer(typeid(T));
|
||||
return p;
|
||||
}
|
||||
|
||||
template <class T> class held_instance;
|
||||
|
||||
typedef void* (*conversion_function_ptr)(void*);
|
||||
|
||||
struct base_class_info
|
||||
{
|
||||
base_class_info(extension_class_base* t, conversion_function_ptr f)
|
||||
:class_object(t), convert(f)
|
||||
{}
|
||||
|
||||
extension_class_base* class_object;
|
||||
conversion_function_ptr convert;
|
||||
};
|
||||
|
||||
typedef base_class_info derived_class_info;
|
||||
|
||||
struct add_operator_base;
|
||||
|
||||
class extension_class_base : public class_t<extension_instance>
|
||||
{
|
||||
public:
|
||||
extension_class_base(const char* name);
|
||||
|
||||
public:
|
||||
// the purpose of try_class_conversions() and its related functions
|
||||
// is explained in extclass.cpp
|
||||
void* try_class_conversions(instance_holder_base*) const;
|
||||
void* try_base_class_conversions(instance_holder_base*) const;
|
||||
void* try_derived_class_conversions(instance_holder_base*) const;
|
||||
|
||||
void set_attribute(const char* name, PyObject* x);
|
||||
void set_attribute(const char* name, ref x);
|
||||
|
||||
private:
|
||||
virtual void* extract_object_from_holder(instance_holder_base* v) const = 0;
|
||||
virtual std::vector<base_class_info> const& base_classes() const = 0;
|
||||
virtual std::vector<derived_class_info> const& derived_classes() const = 0;
|
||||
|
||||
protected:
|
||||
friend struct add_operator_base;
|
||||
void add_method(reference<function> method, const char* name);
|
||||
void add_method(function* method, const char* name);
|
||||
|
||||
void add_constructor_object(function*);
|
||||
void add_setter_method(function*, const char* name);
|
||||
void add_getter_method(function*, const char* name);
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class class_registry
|
||||
{
|
||||
public:
|
||||
static extension_class_base* class_object()
|
||||
{ return static_class_object; }
|
||||
|
||||
// Register/unregister the Python class object corresponding to T
|
||||
static void register_class(extension_class_base*);
|
||||
static void unregister_class(extension_class_base*);
|
||||
|
||||
// Establish C++ inheritance relationships
|
||||
static void register_base_class(base_class_info const&);
|
||||
static void register_derived_class(derived_class_info const&);
|
||||
|
||||
// Query the C++ inheritance relationships
|
||||
static std::vector<base_class_info> const& base_classes();
|
||||
static std::vector<derived_class_info> const& derived_classes();
|
||||
private:
|
||||
static extension_class_base* static_class_object;
|
||||
static std::vector<base_class_info> static_base_class_info;
|
||||
static std::vector<derived_class_info> static_derived_class_info;
|
||||
};
|
||||
|
||||
}}} // namespace boost::python::detail
|
||||
|
||||
BOOST_PYTHON_BEGIN_CONVERSION_NAMESPACE
|
||||
|
||||
// This class' only job is to define from_python and to_python converters for T
|
||||
// and U. T is the class the user really intends to wrap. U is a class derived
|
||||
// from T with some virtual function overriding boilerplate, or if there are no
|
||||
// virtual functions, U = held_instance<T>.
|
||||
template <class T, class U = boost::python::detail::held_instance<T> >
|
||||
class python_extension_class_converters
|
||||
{
|
||||
public:
|
||||
// Get an object which can be used to convert T to/from python. This is used
|
||||
// as a kind of concept check by the global template
|
||||
//
|
||||
// PyObject* to_python(const T& x)
|
||||
//
|
||||
// below this class, to prevent the confusing messages that would otherwise
|
||||
// pop up. Now, if T hasn't been wrapped as an extension class, the user
|
||||
// will see an error message about the lack of an eligible
|
||||
// py_extension_class_converters() function.
|
||||
friend python_extension_class_converters py_extension_class_converters(boost::python::type<T>)
|
||||
{
|
||||
return python_extension_class_converters();
|
||||
}
|
||||
|
||||
// This is a member function because in a conforming implementation, friend
|
||||
// funcitons defined inline in the class body are all instantiated as soon
|
||||
// as the enclosing class is instantiated. If T is not copyable, that causes
|
||||
// a compiler error. Instead, we access this function through the global
|
||||
// template
|
||||
//
|
||||
// PyObject* to_python(const T& x)
|
||||
//
|
||||
// defined below this class. Since template functions are instantiated only
|
||||
// on demand, errors will be avoided unless T is noncopyable and the user
|
||||
// writes code which causes us to try to copy a T.
|
||||
PyObject* to_python(const T& x) const
|
||||
{
|
||||
boost::python::reference<boost::python::detail::extension_instance> result(create_instance());
|
||||
result->add_implementation(
|
||||
std::auto_ptr<boost::python::detail::instance_holder_base>(
|
||||
new boost::python::detail::instance_value_holder<T,U>(result.get(), x)));
|
||||
return result.release();
|
||||
}
|
||||
|
||||
// Convert to T*
|
||||
friend T* from_python(PyObject* obj, boost::python::type<T*>)
|
||||
{
|
||||
// downcast to an extension_instance, then find the actual T
|
||||
boost::python::detail::extension_instance* self = boost::python::detail::get_extension_instance(obj);
|
||||
typedef std::vector<boost::python::detail::instance_holder_base*>::const_iterator iterator;
|
||||
for (iterator p = self->wrapped_objects().begin();
|
||||
p != self->wrapped_objects().end(); ++p)
|
||||
{
|
||||
boost::python::detail::instance_holder<T>* held = dynamic_cast<boost::python::detail::instance_holder<T>*>(*p);
|
||||
if (held != 0)
|
||||
return held->target();
|
||||
|
||||
// see extclass.cpp for an explanation of try_class_conversions()
|
||||
void* target = boost::python::detail::class_registry<T>::class_object()->try_class_conversions(*p);
|
||||
if(target)
|
||||
return static_cast<T*>(target);
|
||||
}
|
||||
boost::python::detail::report_missing_instance_data(self, boost::python::detail::class_registry<T>::class_object(), typeid(T));
|
||||
throw boost::python::argument_error();
|
||||
}
|
||||
|
||||
// Convert to PtrType, where PtrType can be dereferenced to obtain a T.
|
||||
template <class PtrType>
|
||||
static PtrType& ptr_from_python(PyObject* obj, boost::python::type<PtrType>)
|
||||
{
|
||||
// downcast to an extension_instance, then find the actual T
|
||||
boost::python::detail::extension_instance* self = boost::python::detail::get_extension_instance(obj);
|
||||
typedef std::vector<boost::python::detail::instance_holder_base*>::const_iterator iterator;
|
||||
for (iterator p = self->wrapped_objects().begin();
|
||||
p != self->wrapped_objects().end(); ++p)
|
||||
{
|
||||
boost::python::detail::instance_ptr_holder<PtrType, T>* held =
|
||||
dynamic_cast<boost::python::detail::instance_ptr_holder<PtrType, T>*>(*p);
|
||||
if (held != 0)
|
||||
return held->ptr();
|
||||
}
|
||||
boost::python::detail::report_missing_ptr_data(self, boost::python::detail::class_registry<T>::class_object(), typeid(T));
|
||||
throw boost::python::argument_error();
|
||||
}
|
||||
|
||||
template <class PtrType>
|
||||
static PyObject* ptr_to_python(PtrType x)
|
||||
{
|
||||
boost::python::reference<boost::python::detail::extension_instance> result(create_instance());
|
||||
result->add_implementation(
|
||||
std::auto_ptr<boost::python::detail::instance_holder_base>(
|
||||
new boost::python::detail::instance_ptr_holder<PtrType,T>(x)));
|
||||
return result.release();
|
||||
}
|
||||
|
||||
static boost::python::reference<boost::python::detail::extension_instance> create_instance()
|
||||
{
|
||||
PyTypeObject* class_object = boost::python::detail::class_registry<T>::class_object();
|
||||
if (class_object == 0)
|
||||
boost::python::detail::report_missing_class_object(typeid(T));
|
||||
|
||||
return boost::python::reference<boost::python::detail::extension_instance>(
|
||||
new boost::python::detail::extension_instance(class_object));
|
||||
}
|
||||
|
||||
// Convert to const T*
|
||||
friend const T* from_python(PyObject* p, boost::python::type<const T*>)
|
||||
{ return from_python(p, boost::python::type<T*>()); }
|
||||
|
||||
// Convert to const T* const&
|
||||
friend const T* from_python(PyObject* p, boost::python::type<const T*const&>)
|
||||
{ return from_python(p, boost::python::type<const T*>()); }
|
||||
|
||||
// Convert to T* const&
|
||||
friend T* from_python(PyObject* p, boost::python::type<T* const&>)
|
||||
{ return from_python(p, boost::python::type<T*>()); }
|
||||
|
||||
// Convert to T&
|
||||
friend T& from_python(PyObject* p, boost::python::type<T&>)
|
||||
{ return *boost::python::detail::check_non_null(from_python(p, boost::python::type<T*>())); }
|
||||
|
||||
// Convert to const T&
|
||||
friend const T& from_python(PyObject* p, boost::python::type<const T&>)
|
||||
{ return from_python(p, boost::python::type<T&>()); }
|
||||
|
||||
// Convert to T
|
||||
friend const T& from_python(PyObject* p, boost::python::type<T>)
|
||||
{ return from_python(p, boost::python::type<T&>()); }
|
||||
|
||||
friend std::auto_ptr<T>& from_python(PyObject* p, boost::python::type<std::auto_ptr<T>&>)
|
||||
{ return ptr_from_python(p, boost::python::type<std::auto_ptr<T> >()); }
|
||||
|
||||
friend std::auto_ptr<T>& from_python(PyObject* p, boost::python::type<std::auto_ptr<T> >)
|
||||
{ return ptr_from_python(p, boost::python::type<std::auto_ptr<T> >()); }
|
||||
|
||||
friend const std::auto_ptr<T>& from_python(PyObject* p, boost::python::type<const std::auto_ptr<T>&>)
|
||||
{ return ptr_from_python(p, boost::python::type<std::auto_ptr<T> >()); }
|
||||
|
||||
friend PyObject* to_python(std::auto_ptr<T> x)
|
||||
{ return ptr_to_python(x); }
|
||||
|
||||
friend boost::shared_ptr<T>& from_python(PyObject* p, boost::python::type<boost::shared_ptr<T>&>)
|
||||
{ return ptr_from_python(p, boost::python::type<boost::shared_ptr<T> >()); }
|
||||
|
||||
friend boost::shared_ptr<T>& from_python(PyObject* p, boost::python::type<boost::shared_ptr<T> >)
|
||||
{ return ptr_from_python(p, boost::python::type<boost::shared_ptr<T> >()); }
|
||||
|
||||
friend const boost::shared_ptr<T>& from_python(PyObject* p, boost::python::type<const boost::shared_ptr<T>&>)
|
||||
{ return ptr_from_python(p, boost::python::type<boost::shared_ptr<T> >()); }
|
||||
|
||||
friend PyObject* to_python(boost::shared_ptr<T> x)
|
||||
{ return ptr_to_python(x); }
|
||||
};
|
||||
|
||||
// Convert T to_python, instantiated on demand and only if there isn't a
|
||||
// non-template overload for this function. This version is the one invoked when
|
||||
// T is a wrapped class. See the first 2 functions declared in
|
||||
// python_extension_class_converters above for more info.
|
||||
template <class T>
|
||||
PyObject* to_python(const T& x)
|
||||
{
|
||||
return py_extension_class_converters(boost::python::type<T>()).to_python(x);
|
||||
}
|
||||
|
||||
BOOST_PYTHON_END_CONVERSION_NAMESPACE
|
||||
|
||||
namespace boost { namespace python {
|
||||
|
||||
BOOST_PYTHON_IMPORT_CONVERSION(python_extension_class_converters);
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <class T> class instance_holder;
|
||||
|
||||
class read_only_setattr_function : public function
|
||||
{
|
||||
public:
|
||||
read_only_setattr_function(const char* name);
|
||||
PyObject* do_call(PyObject* args, PyObject* keywords) const;
|
||||
const char* description() const;
|
||||
private:
|
||||
string m_name;
|
||||
};
|
||||
|
||||
template <class From, class To>
|
||||
struct define_conversion
|
||||
{
|
||||
static void* upcast_ptr(void* v)
|
||||
{
|
||||
return static_cast<To*>(static_cast<From*>(v));
|
||||
}
|
||||
|
||||
static void* downcast_ptr(void* v)
|
||||
{
|
||||
return dynamic_cast<To*>(static_cast<From*>(v));
|
||||
}
|
||||
};
|
||||
|
||||
// An easy way to make an extension base class which wraps T. Note that Python
|
||||
// subclasses of this class will simply be class_t<extension_instance> objects.
|
||||
//
|
||||
// U should be a class derived from T which overrides virtual functions with
|
||||
// boilerplate code to call back into Python. See extclass_demo.h for examples.
|
||||
//
|
||||
// U is optional, but you won't be able to override any member functions in
|
||||
// Python which are called from C++ if you don't supply it. If you just want to
|
||||
// be able to use T in python without overriding member functions, you can omit
|
||||
// U.
|
||||
template <class T, class U = held_instance<T> >
|
||||
class extension_class
|
||||
: public python_extension_class_converters<T, U>, // This generates the to_python/from_python functions
|
||||
public extension_class_base
|
||||
{
|
||||
public:
|
||||
typedef T wrapped_type;
|
||||
typedef U callback_type;
|
||||
|
||||
// Construct with a name that comes from typeid(T).name(). The name only
|
||||
// affects the objects of this class are represented through repr()
|
||||
extension_class();
|
||||
|
||||
// Construct with the given name. The name only affects the objects of this
|
||||
// class are represented through repr()
|
||||
extension_class(const char* name);
|
||||
|
||||
~extension_class();
|
||||
|
||||
// define constructors
|
||||
""" % args
|
||||
+ gen_function(
|
||||
""" template <%(class A%n%:, %)>
|
||||
inline void def(constructor<%(A%n%:, %)>)
|
||||
// The following incantation builds a signature1, signature2,... object. It
|
||||
// should _all_ get optimized away.
|
||||
{ add_constructor(
|
||||
%(prepend(type<A%n>::id(),
|
||||
%) signature0()%()%));
|
||||
}
|
||||
""", args)
|
||||
+
|
||||
"""
|
||||
|
||||
// export homogeneous operators (type of both lhs and rhs is 'operator')
|
||||
// usage: foo_class.def(boost::python::operators<(boost::python::op_add | boost::python::op_sub), Foo>());
|
||||
|
||||
// export homogeneous operators (type of both lhs and rhs is 'T const&')
|
||||
// usage: foo_class.def(boost::python::operators<(boost::python::op_add | boost::python::op_sub)>());
|
||||
template <long which, class Operand>
|
||||
inline void def(operators<which,Operand>)
|
||||
{
|
||||
typedef typename operand_select<Operand>::template wrapped<T>::type true_operand;
|
||||
def_operators(operators<which,true_operand>());
|
||||
}
|
||||
|
||||
// export heterogeneous operators (type of lhs: 'left', of rhs: 'right')
|
||||
// usage: foo_class.def(boost::python::operators<(boost::python::op_add | boost::python::op_sub), Foo>(),
|
||||
// boost::python::right_operand<int const&>());
|
||||
|
||||
// export heterogeneous operators (type of lhs: 'T const&', of rhs: 'right')
|
||||
// usage: foo_class.def(boost::python::operators<(boost::python::op_add | boost::python::op_sub)>(),
|
||||
// boost::python::right_operand<int const&>());
|
||||
template <long which, class Left, class Right>
|
||||
inline void def(operators<which,Left>, right_operand<Right> r)
|
||||
{
|
||||
typedef typename operand_select<Left>::template wrapped<T>::type true_left;
|
||||
def_operators(operators<which,true_left>(), r);
|
||||
}
|
||||
|
||||
// export heterogeneous reverse-argument operators
|
||||
// (type of lhs: 'left', of rhs: 'right')
|
||||
// usage: foo_class.def(boost::python::operators<(boost::python::op_add | boost::python::op_sub), Foo>(),
|
||||
// boost::python::left_operand<int const&>());
|
||||
|
||||
// export heterogeneous reverse-argument operators
|
||||
// (type of lhs: 'left', of rhs: 'T const&')
|
||||
// usage: foo_class.def(boost::python::operators<(boost::python::op_add | boost::python::op_sub)>(),
|
||||
// boost::python::left_operand<int const&>());
|
||||
template <long which, class Left, class Right>
|
||||
inline void def(operators<which,Right>, left_operand<Left> l)
|
||||
{
|
||||
typedef typename operand_select<Right>::template wrapped<T>::type true_right;
|
||||
def_operators(operators<which,true_right>(), l);
|
||||
}
|
||||
|
||||
// define a function that passes Python arguments and keywords
|
||||
// to C++ verbatim (as a 'tuple const&' and 'dictionary const&'
|
||||
// respectively). This is useful for manual argument passing.
|
||||
// It's also the only possibility to pass keyword arguments to C++.
|
||||
// Fn must have a signatur that is compatible to
|
||||
// PyObject* (*)(PyObject* aTuple, PyObject* aDictionary)
|
||||
template <class Fn>
|
||||
inline void def_raw(Fn fn, const char* name)
|
||||
{
|
||||
this->add_method(new_raw_arguments_function(fn), name);
|
||||
}
|
||||
|
||||
// define member functions. In fact this works for free functions, too -
|
||||
// they act like static member functions, or if they start with the
|
||||
// appropriate self argument (as a pointer), they can be used just like
|
||||
// ordinary member functions -- just like Python!
|
||||
template <class Fn>
|
||||
inline void def(Fn fn, const char* name)
|
||||
{
|
||||
this->add_method(new_wrapped_function(fn), name);
|
||||
}
|
||||
|
||||
// Define a virtual member function with a default implementation.
|
||||
// default_fn should be a function which provides the default implementation.
|
||||
// Be careful that default_fn does not in fact call fn virtually!
|
||||
template <class Fn, class DefaultFn>
|
||||
inline void def(Fn fn, const char* name, DefaultFn default_fn)
|
||||
{
|
||||
this->add_method(new_virtual_function(type<T>(), fn, default_fn), name);
|
||||
}
|
||||
|
||||
// Provide a function which implements x.<name>, reading from the given
|
||||
// member (pm) of the T obj
|
||||
template <class MemberType>
|
||||
inline void def_getter(MemberType T::*pm, const char* name)
|
||||
{
|
||||
this->add_getter_method(new getter_function<T, MemberType>(pm), name);
|
||||
}
|
||||
|
||||
// Provide a function which implements assignment to x.<name>, writing to
|
||||
// the given member (pm) of the T obj
|
||||
template <class MemberType>
|
||||
inline void def_setter(MemberType T::*pm, const char* name)
|
||||
{
|
||||
this->add_setter_method(new setter_function<T, MemberType>(pm), name);
|
||||
}
|
||||
|
||||
// Expose the given member (pm) of the T obj as a read-only attribute
|
||||
template <class MemberType>
|
||||
inline void def_readonly(MemberType T::*pm, const char* name)
|
||||
{
|
||||
this->add_setter_method(new read_only_setattr_function(name), name);
|
||||
this->def_getter(pm, name);
|
||||
}
|
||||
|
||||
// Expose the given member (pm) of the T obj as a read/write attribute
|
||||
template <class MemberType>
|
||||
inline void def_read_write(MemberType T::*pm, const char* name)
|
||||
{
|
||||
this->def_getter(pm, name);
|
||||
this->def_setter(pm, name);
|
||||
}
|
||||
|
||||
// define the standard coercion needed for operator overloading
|
||||
void def_standard_coerce();
|
||||
|
||||
// declare the given class a base class of this one and register
|
||||
// up and down conversion functions
|
||||
template <class S, class V>
|
||||
void declare_base(extension_class<S, V>* base)
|
||||
{
|
||||
// see extclass.cpp for an explanation of why we need to register
|
||||
// conversion functions
|
||||
base_class_info baseInfo(base,
|
||||
&define_conversion<S, T>::downcast_ptr);
|
||||
class_registry<T>::register_base_class(baseInfo);
|
||||
add_base(ref(as_object(base), ref::increment_count));
|
||||
|
||||
derived_class_info derivedInfo(this,
|
||||
&define_conversion<T, S>::upcast_ptr);
|
||||
class_registry<S>::register_derived_class(derivedInfo);
|
||||
}
|
||||
|
||||
// declare the given class a base class of this one and register
|
||||
// only up conversion function
|
||||
template <class S, class V>
|
||||
void declare_base(extension_class<S, V>* base, without_downcast_t)
|
||||
{
|
||||
// see extclass.cpp for an explanation of why we need to register
|
||||
// conversion functions
|
||||
base_class_info baseInfo(base, 0);
|
||||
class_registry<T>::register_base_class(baseInfo);
|
||||
add_base(ref(as_object(base), ref::increment_count));
|
||||
|
||||
derived_class_info derivedInfo(this,
|
||||
&define_conversion<T, S>::upcast_ptr);
|
||||
class_registry<S>::register_derived_class(derivedInfo);
|
||||
}
|
||||
|
||||
private: // types
|
||||
typedef instance_value_holder<T,U> holder;
|
||||
|
||||
private: // extension_class_base virtual function implementations
|
||||
std::vector<base_class_info> const& base_classes() const;
|
||||
std::vector<derived_class_info> const& derived_classes() const;
|
||||
void* extract_object_from_holder(instance_holder_base* v) const;
|
||||
|
||||
private: // Utility functions
|
||||
template <long which, class Operand>
|
||||
inline void def_operators(operators<which,Operand>)
|
||||
{
|
||||
def_standard_coerce();
|
||||
|
||||
// for some strange reason, this prevents MSVC from having an
|
||||
// "unrecoverable block scoping error"!
|
||||
typedef choose_op<(which & op_add)> choose_add;
|
||||
|
||||
choose_op<(which & op_add)>::template args<Operand>::add(this);
|
||||
choose_op<(which & op_sub)>::template args<Operand>::add(this);
|
||||
choose_op<(which & op_mul)>::template args<Operand>::add(this);
|
||||
choose_op<(which & op_div)>::template args<Operand>::add(this);
|
||||
choose_op<(which & op_mod)>::template args<Operand>::add(this);
|
||||
choose_op<(which & op_divmod)>::template args<Operand>::add(this);
|
||||
choose_op<(which & op_pow)>::template args<Operand>::add(this);
|
||||
choose_op<(which & op_lshift)>::template args<Operand>::add(this);
|
||||
choose_op<(which & op_rshift)>::template args<Operand>::add(this);
|
||||
choose_op<(which & op_and)>::template args<Operand>::add(this);
|
||||
choose_op<(which & op_xor)>::template args<Operand>::add(this);
|
||||
choose_op<(which & op_or)>::template args<Operand>::add(this);
|
||||
choose_unary_op<(which & op_neg)>::template args<Operand>::add(this);
|
||||
choose_unary_op<(which & op_pos)>::template args<Operand>::add(this);
|
||||
choose_unary_op<(which & op_abs)>::template args<Operand>::add(this);
|
||||
choose_unary_op<(which & op_invert)>::template args<Operand>::add(this);
|
||||
choose_unary_op<(which & op_int)>::template args<Operand>::add(this);
|
||||
choose_unary_op<(which & op_long)>::template args<Operand>::add(this);
|
||||
choose_unary_op<(which & op_float)>::template args<Operand>::add(this);
|
||||
choose_op<(which & op_cmp)>::template args<Operand>::add(this);
|
||||
choose_unary_op<(which & op_str)>::template args<Operand>::add(this);
|
||||
}
|
||||
|
||||
template <long which, class Left, class Right>
|
||||
inline void def_operators(operators<which,Left>, right_operand<Right>)
|
||||
{
|
||||
def_standard_coerce();
|
||||
|
||||
choose_op<(which & op_add)>::template args<Left,Right>::add(this);
|
||||
choose_op<(which & op_sub)>::template args<Left,Right>::add(this);
|
||||
choose_op<(which & op_mul)>::template args<Left,Right>::add(this);
|
||||
choose_op<(which & op_div)>::template args<Left,Right>::add(this);
|
||||
choose_op<(which & op_mod)>::template args<Left,Right>::add(this);
|
||||
choose_op<(which & op_divmod)>::template args<Left,Right>::add(this);
|
||||
choose_op<(which & op_pow)>::template args<Left,Right>::add(this);
|
||||
choose_op<(which & op_lshift)>::template args<Left,Right>::add(this);
|
||||
choose_op<(which & op_rshift)>::template args<Left,Right>::add(this);
|
||||
choose_op<(which & op_and)>::template args<Left,Right>::add(this);
|
||||
choose_op<(which & op_xor)>::template args<Left,Right>::add(this);
|
||||
choose_op<(which & op_or)>::template args<Left,Right>::add(this);
|
||||
choose_op<(which & op_cmp)>::template args<Left,Right>::add(this);
|
||||
}
|
||||
|
||||
template <long which, class Left, class Right>
|
||||
inline void def_operators(operators<which,Right>, left_operand<Left>)
|
||||
{
|
||||
def_standard_coerce();
|
||||
|
||||
choose_rop<(which & op_add)>::template args<Left,Right>::add(this);
|
||||
choose_rop<(which & op_sub)>::template args<Left,Right>::add(this);
|
||||
choose_rop<(which & op_mul)>::template args<Left,Right>::add(this);
|
||||
choose_rop<(which & op_div)>::template args<Left,Right>::add(this);
|
||||
choose_rop<(which & op_mod)>::template args<Left,Right>::add(this);
|
||||
choose_rop<(which & op_divmod)>::template args<Left,Right>::add(this);
|
||||
choose_rop<(which & op_pow)>::template args<Left,Right>::add(this);
|
||||
choose_rop<(which & op_lshift)>::template args<Left,Right>::add(this);
|
||||
choose_rop<(which & op_rshift)>::template args<Left,Right>::add(this);
|
||||
choose_rop<(which & op_and)>::template args<Left,Right>::add(this);
|
||||
choose_rop<(which & op_xor)>::template args<Left,Right>::add(this);
|
||||
choose_rop<(which & op_or)>::template args<Left,Right>::add(this);
|
||||
choose_rop<(which & op_cmp)>::template args<Left,Right>::add(this);
|
||||
}
|
||||
|
||||
template <class signature>
|
||||
void add_constructor(signature sig)
|
||||
{
|
||||
this->add_constructor_object(init_function<holder>::create(sig));
|
||||
}
|
||||
};
|
||||
|
||||
// A simple wrapper over a T which allows us to use extension_class<T> with a
|
||||
// single template parameter only. See extension_class<T>, above.
|
||||
template <class T>
|
||||
class held_instance : public T
|
||||
{
|
||||
// There are no member functions: we want to avoid inadvertently overriding
|
||||
// any virtual functions in T.
|
||||
public:"""
|
||||
+ gen_functions("""%{
|
||||
template <%(class A%n%:, %)>%}
|
||||
held_instance(PyObject*%(, A%n% a%n%)) : T(%(a%n%:, %)) {}""", args)
|
||||
+ """
|
||||
};
|
||||
|
||||
// Abstract base class for all obj holders. Base for template class
|
||||
// instance_holder<>, below.
|
||||
class instance_holder_base
|
||||
{
|
||||
public:
|
||||
virtual ~instance_holder_base() {}
|
||||
virtual bool held_by_value() = 0;
|
||||
};
|
||||
|
||||
// Abstract base class which holds a Held, somehow. Provides a uniform way to
|
||||
// get a pointer to the held object
|
||||
template <class Held>
|
||||
class instance_holder : public instance_holder_base
|
||||
{
|
||||
public:
|
||||
virtual Held*target() = 0;
|
||||
};
|
||||
|
||||
// Concrete class which holds a Held by way of a wrapper class Wrapper. If Held
|
||||
// can be constructed with arguments (A1...An), Wrapper must have a
|
||||
// corresponding constructor for arguments (PyObject*, A1...An). Wrapper is
|
||||
// neccessary to implement virtual function callbacks (there must be a
|
||||
// back-pointer to the actual Python object so that we can call any
|
||||
// overrides). held_instance (above) is used as a default Wrapper class when
|
||||
// there are no virtual functions.
|
||||
template <class Held, class Wrapper>
|
||||
class instance_value_holder : public instance_holder<Held>
|
||||
{
|
||||
public:
|
||||
Held* target() { return &m_held; }
|
||||
Wrapper* value_target() { return &m_held; }
|
||||
"""
|
||||
+ gen_functions("""%{
|
||||
template <%(class A%n%:, %)>%}
|
||||
instance_value_holder(extension_instance* p%(, A%n a%n%)) :
|
||||
m_held(p%(, a%n%)) {}""", args)
|
||||
+ """
|
||||
|
||||
public: // implementation of instance_holder_base required interface
|
||||
bool held_by_value() { return true; }
|
||||
|
||||
private:
|
||||
Wrapper m_held;
|
||||
};
|
||||
|
||||
// Concrete class which holds a HeldType by way of a (possibly smart) pointer
|
||||
// PtrType. By default, these are only generated for PtrType ==
|
||||
// std::auto_ptr<HeldType> and PtrType == boost::shared_ptr<HeldType>.
|
||||
template <class PtrType, class HeldType>
|
||||
class instance_ptr_holder : public instance_holder<HeldType>
|
||||
{
|
||||
public:
|
||||
HeldType* target() { return &*m_ptr; }
|
||||
PtrType& ptr() { return m_ptr; }
|
||||
|
||||
instance_ptr_holder(PtrType ptr) : m_ptr(ptr) {}
|
||||
|
||||
public: // implementation of instance_holder_base required interface
|
||||
bool held_by_value() { return false; }
|
||||
private:
|
||||
PtrType m_ptr;
|
||||
};
|
||||
|
||||
class extension_instance : public instance
|
||||
{
|
||||
public:
|
||||
extension_instance(PyTypeObject* class_);
|
||||
~extension_instance();
|
||||
|
||||
void add_implementation(std::auto_ptr<instance_holder_base> holder);
|
||||
|
||||
typedef std::vector<instance_holder_base*> held_objects;
|
||||
const held_objects& wrapped_objects() const
|
||||
{ return m_wrapped_objects; }
|
||||
private:
|
||||
held_objects m_wrapped_objects;
|
||||
};
|
||||
|
||||
//
|
||||
// Template function implementations
|
||||
//
|
||||
|
||||
tuple extension_class_coerce(ref l, ref r);
|
||||
|
||||
template <class T, class U>
|
||||
extension_class<T, U>::extension_class()
|
||||
: extension_class_base(typeid(T).name())
|
||||
{
|
||||
class_registry<T>::register_class(this);
|
||||
}
|
||||
|
||||
template <class T, class U>
|
||||
extension_class<T, U>::extension_class(const char* name)
|
||||
: extension_class_base(name)
|
||||
{
|
||||
class_registry<T>::register_class(this);
|
||||
}
|
||||
|
||||
template <class T, class U>
|
||||
void extension_class<T, U>::def_standard_coerce()
|
||||
{
|
||||
ref coerce_fct = dict().get_item(string("__coerce__"));
|
||||
|
||||
if(coerce_fct.get() == 0) // not yet defined
|
||||
this->def(&extension_class_coerce, "__coerce__");
|
||||
}
|
||||
|
||||
template <class T, class U>
|
||||
inline
|
||||
std::vector<base_class_info> const&
|
||||
extension_class<T, U>::base_classes() const
|
||||
{
|
||||
return class_registry<T>::base_classes();
|
||||
}
|
||||
|
||||
template <class T, class U>
|
||||
inline
|
||||
std::vector<derived_class_info> const&
|
||||
extension_class<T, U>::derived_classes() const
|
||||
{
|
||||
return class_registry<T>::derived_classes();
|
||||
}
|
||||
|
||||
template <class T, class U>
|
||||
void* extension_class<T, U>::extract_object_from_holder(instance_holder_base* v) const
|
||||
{
|
||||
instance_holder<T>* held = dynamic_cast<instance_holder<T>*>(v);
|
||||
if(held)
|
||||
return held->target();
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <class T, class U>
|
||||
extension_class<T, U>::~extension_class()
|
||||
{
|
||||
class_registry<T>::unregister_class(this);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline void class_registry<T>::register_class(extension_class_base* p)
|
||||
{
|
||||
// You're not expected to create more than one of these!
|
||||
assert(static_class_object == 0);
|
||||
static_class_object = p;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline void class_registry<T>::unregister_class(extension_class_base* p)
|
||||
{
|
||||
// The user should be destroying the same object they created.
|
||||
assert(static_class_object == p);
|
||||
(void)p; // unused in shipping version
|
||||
static_class_object = 0;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void class_registry<T>::register_base_class(base_class_info const& i)
|
||||
{
|
||||
static_base_class_info.push_back(i);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void class_registry<T>::register_derived_class(derived_class_info const& i)
|
||||
{
|
||||
static_derived_class_info.push_back(i);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
std::vector<base_class_info> const& class_registry<T>::base_classes()
|
||||
{
|
||||
return static_base_class_info;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
std::vector<derived_class_info> const& class_registry<T>::derived_classes()
|
||||
{
|
||||
return static_derived_class_info;
|
||||
}
|
||||
|
||||
//
|
||||
// Static data member declaration.
|
||||
//
|
||||
template <class T>
|
||||
extension_class_base* class_registry<T>::static_class_object;
|
||||
template <class T>
|
||||
std::vector<base_class_info> class_registry<T>::static_base_class_info;
|
||||
template <class T>
|
||||
std::vector<derived_class_info> class_registry<T>::static_derived_class_info;
|
||||
|
||||
}}} // namespace boost::python::detail
|
||||
|
||||
#endif // EXTENSION_CLASS_DWA052000_H_
|
||||
""")
|
||||
|
||||
if __name__ == '__main__':
|
||||
import sys
|
||||
|
||||
if len(sys.argv) == 1:
|
||||
args = 5
|
||||
else:
|
||||
args = int(sys.argv[1])
|
||||
|
||||
print gen_extclass(args)
|
||||
@@ -1,184 +0,0 @@
|
||||
import string
|
||||
|
||||
def _find(s, sub, start=0, end=None):
|
||||
"""Just like string.find, except it returns end or len(s) when not found.
|
||||
"""
|
||||
if end == None:
|
||||
end = len(s)
|
||||
|
||||
pos = string.find(s, sub, start, end)
|
||||
if pos < 0:
|
||||
return end
|
||||
else:
|
||||
return pos
|
||||
|
||||
def _gen_common_key(key, n, args):
|
||||
if len(key) > 0 and key in '123456789':
|
||||
return str(args[int(key) - 1])
|
||||
elif key == 'x':
|
||||
return str(n)
|
||||
else:
|
||||
return key
|
||||
|
||||
def _gen_arg(template, n, args, delimiter = '%'):
|
||||
result = ''
|
||||
i = 0
|
||||
while i < len(template): # until the template is consumed
|
||||
# consume everything up to the first delimiter
|
||||
delimiter_pos = _find(template, delimiter, i)
|
||||
result = result + template[i:delimiter_pos]
|
||||
|
||||
# The start position of whatever comes after the delimiter+key
|
||||
start = delimiter_pos + 2
|
||||
key = template[start - 1 : start] # the key character. If there were no
|
||||
# delimiters left, key will be empty
|
||||
|
||||
if key == 'n':
|
||||
result = result + `n`
|
||||
else:
|
||||
result = result + _gen_common_key(key, n, args)
|
||||
|
||||
i = start
|
||||
|
||||
return result
|
||||
|
||||
def gen_function(template, n, *args, **keywords):
|
||||
r"""gen_function(template, n, [args...] ) -> string
|
||||
|
||||
Generate a function declaration based on the given template.
|
||||
|
||||
Sections of the template between '%(', '%)' pairs are repeated n times. If '%:'
|
||||
appears in the middle, it denotes the beginning of a delimiter.
|
||||
|
||||
Sections of the template between '%{', '%}' pairs are ommitted if n == 0.
|
||||
|
||||
%n is transformed into the string representation of 1..n for each repetition
|
||||
of n.
|
||||
|
||||
%x, where x is a digit, is transformed into the corresponding additional
|
||||
argument.
|
||||
|
||||
for example,
|
||||
|
||||
>>> gen_function('%1 abc(%(int a%n%:, %));%{ // all args are ints%}', 2, 'void')
|
||||
'void abc(int a1, int a2); // all args are ints'
|
||||
>>> gen_function('%1 abc(%(int a%n%:, %));%{ // all args are ints%}', 0, 'x')
|
||||
'x abc();'
|
||||
|
||||
|
||||
>>> template = ''' template <class T%(, class A%n%)>
|
||||
... static PyObject* call( %1(T::*pmf)(%(A%n%:, %))%2, PyObject* args, PyObject* /* keywords */ ) {
|
||||
... PyObject* self;
|
||||
... %( PyObject* a%n;
|
||||
... %) if (!PyArg_ParseTuple(args, const_cast<char*>("O%(O%)"), &self%(, &a%n%)))
|
||||
... return 0;
|
||||
... T& target = from_python(self, type<T&>());
|
||||
... %3to_python((target.*pmf)(%(
|
||||
... from_python(a%n, type<A%n>())%:,%)
|
||||
... ));%4
|
||||
... }'''
|
||||
|
||||
>>> print gen_function(template, 0, 'R ', '', 'return ', '')
|
||||
template <class T>
|
||||
static PyObject* call( R (T::*pmf)(), PyObject* args, PyObject* /* keywords */ ) {
|
||||
PyObject* self;
|
||||
if (!PyArg_ParseTuple(args, const_cast<char*>("O"), &self))
|
||||
return 0;
|
||||
T& target = from_python(self, type<T&>());
|
||||
return to_python((target.*pmf)(
|
||||
));
|
||||
}
|
||||
|
||||
>>> print gen_function(template, 2, 'R ', '', 'return ', '')
|
||||
template <class T, class A1, class A2>
|
||||
static PyObject* call( R (T::*pmf)(A1, A2), PyObject* args, PyObject* /* keywords */ ) {
|
||||
PyObject* self;
|
||||
PyObject* a1;
|
||||
PyObject* a2;
|
||||
if (!PyArg_ParseTuple(args, const_cast<char*>("OOO"), &self, &a1, &a2))
|
||||
return 0;
|
||||
T& target = from_python(self, type<T&>());
|
||||
return to_python((target.*pmf)(
|
||||
from_python(a1, type<A1>()),
|
||||
from_python(a2, type<A2>())
|
||||
));
|
||||
}
|
||||
|
||||
>>> print gen_function(template, 3, 'void ', ' const', '', '\n'+8*' ' + 'return none();')
|
||||
template <class T, class A1, class A2, class A3>
|
||||
static PyObject* call( void (T::*pmf)(A1, A2, A3) const, PyObject* args, PyObject* /* keywords */ ) {
|
||||
PyObject* self;
|
||||
PyObject* a1;
|
||||
PyObject* a2;
|
||||
PyObject* a3;
|
||||
if (!PyArg_ParseTuple(args, const_cast<char*>("OOOO"), &self, &a1, &a2, &a3))
|
||||
return 0;
|
||||
T& target = from_python(self, type<T&>());
|
||||
to_python((target.*pmf)(
|
||||
from_python(a1, type<A1>()),
|
||||
from_python(a2, type<A2>()),
|
||||
from_python(a3, type<A3>())
|
||||
));
|
||||
return none();
|
||||
}
|
||||
"""
|
||||
delimiter = keywords.get('delimiter', '%')
|
||||
result = ''
|
||||
i = 0
|
||||
while i < len(template): # until the template is consumed
|
||||
# consume everything up to the first delimiter
|
||||
delimiter_pos = _find(template, delimiter, i)
|
||||
result = result + template[i:delimiter_pos]
|
||||
|
||||
# The start position of whatever comes after the delimiter+key
|
||||
start = delimiter_pos + 2
|
||||
key = template[start - 1 : start] # the key character. If there were no
|
||||
# delimiters left, key will be empty
|
||||
|
||||
pairs = { '(':')', '{':'}' }
|
||||
|
||||
if key in pairs.keys():
|
||||
end = string.find(template, delimiter + pairs[key], start)
|
||||
assert end >= 0, "Matching '" + delimiter + pairs[key] +"' not found!"
|
||||
delimiter_pos = end
|
||||
|
||||
if key == '{':
|
||||
if n > 0:
|
||||
result = result + gen_function(template[start:end], n, args, delimiter)
|
||||
else:
|
||||
separator_pos = _find(template, delimiter + ':', start, end)
|
||||
separator = template[separator_pos+2 : end]
|
||||
|
||||
for x in range(1, n + 1):
|
||||
result = result + _gen_arg(template[start:separator_pos], x, args,
|
||||
delimiter)
|
||||
if x != n:
|
||||
result = result + separator
|
||||
|
||||
else:
|
||||
result = result + _gen_common_key(key, n, args)
|
||||
|
||||
i = delimiter_pos + 2
|
||||
|
||||
return result
|
||||
|
||||
def gen_functions(template, n, *args):
|
||||
r"""gen_functions(template, n, [args...]) -> string
|
||||
|
||||
Call gen_function repeatedly with from 0..n and the given optional
|
||||
arguments.
|
||||
|
||||
>>> print gen_functions('%1 abc(%(int a%n%:, %));%{ // all args are ints%}\n', 2, 'void'),
|
||||
void abc();
|
||||
void abc(int a1); // all args are ints
|
||||
void abc(int a1, int a2); // all args are ints
|
||||
|
||||
"""
|
||||
result = ''
|
||||
for x in range(n + 1):
|
||||
result = result + apply(gen_function, (template, x) + args)
|
||||
return result
|
||||
|
||||
if __name__ == '__main__':
|
||||
import doctest
|
||||
doctest.testmod()
|
||||
@@ -1,166 +0,0 @@
|
||||
from gen_function import *
|
||||
import string
|
||||
|
||||
def gen_init_function(args):
|
||||
|
||||
return (
|
||||
"""// (C) Copyright David Abrahams 2000. Permission to copy, use, modify, sell and
|
||||
// distribute this software is granted provided this copyright notice appears
|
||||
// in all copies. This software is provided "as is" without express or implied
|
||||
// warranty, and with no claim as to its suitability for any purpose.
|
||||
//
|
||||
// The author gratefully acknowleges the support of Dragon Systems, Inc., in
|
||||
// producing this work.
|
||||
//
|
||||
// This file was generated for %d-argument constructors by gen_init_function.python
|
||||
|
||||
#ifndef INIT_FUNCTION_DWA052000_H_
|
||||
# define INIT_FUNCTION_DWA052000_H_
|
||||
|
||||
# include <boost/python/detail/config.hpp>
|
||||
# include <boost/python/detail/functions.hpp>
|
||||
# include <boost/python/detail/signatures.hpp>
|
||||
# include <typeinfo>
|
||||
|
||||
namespace boost { namespace python {
|
||||
|
||||
namespace detail {
|
||||
|
||||
// parameter_traits - so far, this is a way to pass a const T& when we can be
|
||||
// sure T is not a reference type, and a raw T otherwise. This should be
|
||||
// rolled into boost::call_traits. Ordinarily, parameter_traits would be
|
||||
// written:
|
||||
//
|
||||
// template <class T> struct parameter_traits
|
||||
// {
|
||||
// typedef const T& const_reference;
|
||||
// };
|
||||
//
|
||||
// template <class T> struct parameter_traits<T&>
|
||||
// {
|
||||
// typedef T& const_reference;
|
||||
// };
|
||||
//
|
||||
// template <> struct parameter_traits<void>
|
||||
// {
|
||||
// typedef void const_reference;
|
||||
// };
|
||||
//
|
||||
// ...but since we can't partially specialize on reference types, we need this
|
||||
// long-winded but equivalent incantation.
|
||||
|
||||
// const_ref_selector -- an implementation detail of parameter_traits (below). This uses
|
||||
// the usual "poor man's partial specialization" hack for MSVC.
|
||||
template <bool is_ref>
|
||||
struct const_ref_selector
|
||||
{
|
||||
template <class T>
|
||||
struct const_ref
|
||||
{
|
||||
typedef const T& type;
|
||||
};
|
||||
};
|
||||
|
||||
template <>
|
||||
struct const_ref_selector<true>
|
||||
{
|
||||
template <class T>
|
||||
struct const_ref
|
||||
{
|
||||
typedef T type;
|
||||
};
|
||||
};
|
||||
|
||||
# ifdef BOOST_MSVC
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable: 4181)
|
||||
# endif // BOOST_MSVC
|
||||
template <class T>
|
||||
struct parameter_traits
|
||||
{
|
||||
private:
|
||||
typedef const_ref_selector<boost::is_reference<T>::value> selector;
|
||||
public:
|
||||
typedef typename selector::template const_ref<T>::type const_reference;
|
||||
};
|
||||
# ifdef BOOST_MSVC
|
||||
# pragma warning(pop)
|
||||
# endif // BOOST_MSVC
|
||||
|
||||
// Full spcialization for void
|
||||
template <>
|
||||
struct parameter_traits<void>
|
||||
{
|
||||
typedef void const_reference;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class reference_parameter
|
||||
{
|
||||
typedef typename parameter_traits<T>::const_reference const_reference;
|
||||
public:
|
||||
reference_parameter(const_reference value)
|
||||
: value(value) {}
|
||||
operator const_reference() { return value; }
|
||||
private:
|
||||
const_reference value;
|
||||
};
|
||||
|
||||
class extension_instance;
|
||||
class instance_holder_base;
|
||||
|
||||
class init;
|
||||
"""
|
||||
+ gen_functions('template <class T%(, class A%n%)> struct init%x;\n', args)
|
||||
+ """
|
||||
template <class T>
|
||||
struct init_function
|
||||
{
|
||||
""" + gen_functions("""%{
|
||||
template <%(class A%n%:, %)>
|
||||
%} static init* create(signature%x%{<%(A%n%:, %)>%}) {
|
||||
return new init%x<T%(,
|
||||
detail::parameter_traits<A%n>::const_reference%)>;
|
||||
}
|
||||
""", args)+"""};
|
||||
|
||||
class init : public function
|
||||
{
|
||||
private: // override function hook
|
||||
PyObject* do_call(PyObject* args, PyObject* keywords) const;
|
||||
private:
|
||||
virtual instance_holder_base* create_holder(extension_instance* self, PyObject* tail_args, PyObject* keywords) const = 0;
|
||||
};
|
||||
""" + gen_functions("""
|
||||
|
||||
template <class T%(, class A%n%)>
|
||||
struct init%x : init
|
||||
{
|
||||
virtual instance_holder_base* create_holder(extension_instance* self, PyObject* args, PyObject* /*keywords*/) const
|
||||
{
|
||||
%(PyObject* a%n;
|
||||
%)if (!PyArg_ParseTuple(args, const_cast<char*>("%(O%)")%(, &a%n%)))
|
||||
throw argument_error();
|
||||
return new T(self%(,
|
||||
boost::python::detail::reference_parameter<A%n>(from_python(a%n, type<A%n>()))%)
|
||||
);
|
||||
}
|
||||
const char* description() const
|
||||
{ return typeid(void (*)(T&%(, A%n%%))).name(); }
|
||||
};""", args) + """
|
||||
|
||||
}}} // namespace boost::python::detail
|
||||
|
||||
#endif // INIT_FUNCTION_DWA052000_H_
|
||||
""")
|
||||
|
||||
if __name__ == '__main__':
|
||||
import sys
|
||||
|
||||
if len(sys.argv) == 1:
|
||||
args = 5
|
||||
else:
|
||||
args = int(sys.argv[1])
|
||||
|
||||
print gen_init_function(args)
|
||||
|
||||
@@ -1,158 +0,0 @@
|
||||
from gen_function import *
|
||||
import string
|
||||
|
||||
def gen_struct_signatures(args):
|
||||
result = ''
|
||||
for n in range(args, -1, -1):
|
||||
result = (
|
||||
result + gen_function("""%{template <%(class T%n%:, %)>
|
||||
%}struct signature%x {};
|
||||
|
||||
""", n)
|
||||
# + ((n == args) and [""] or
|
||||
# [gen_function("""
|
||||
# template <class X>
|
||||
# static inline signature%1<X%(, T%n%)> prepend(type<X>)
|
||||
# { return signature%1<X%(, T%n%)>(); }""",
|
||||
# n, (str(n+1),))
|
||||
# ]
|
||||
# )[0]
|
||||
#
|
||||
# + ((n != 0) and [""] or
|
||||
# ["""
|
||||
# // This one terminates the chain. Prepending void_t to the head of a void_t
|
||||
# // signature results in a void_t signature again.
|
||||
# static inline signature0 prepend(void_t) { return signature0(); }"""]
|
||||
# )[0]
|
||||
# + """
|
||||
#};
|
||||
#
|
||||
#"""
|
||||
+ ((n == args) and [""] or
|
||||
[gen_function(
|
||||
"""template <%(class T%n%, %)class X>
|
||||
inline signature%1<X%(, T%n%)> prepend(type<X>, signature%x%{<%(T%n%:, %)>%})
|
||||
{ return signature%1<X%(, T%n%)>(); }
|
||||
|
||||
""", n, str(n+1))
|
||||
]
|
||||
)[0]
|
||||
)
|
||||
return result
|
||||
|
||||
def gen_signatures(args):
|
||||
return (
|
||||
"""// (C) Copyright David Abrahams 2000. Permission to copy, use, modify, sell and
|
||||
// distribute this software is granted provided this copyright notice appears
|
||||
// in all copies. This software is provided "as is" without express or implied
|
||||
// warranty, and with no claim as to its suitability for any purpose.
|
||||
//
|
||||
// The author gratefully acknowleges the support of Dragon Systems, Inc., in
|
||||
// producing this work.
|
||||
//
|
||||
// This file automatically generated by gen_signatures.python for %d arguments.
|
||||
#ifndef SIGNATURES_DWA050900_H_
|
||||
# define SIGNATURES_DWA050900_H_
|
||||
|
||||
# include <boost/python/detail/config.hpp>
|
||||
|
||||
namespace boost { namespace python {
|
||||
|
||||
namespace detail {
|
||||
// A stand-in for the built-in void. This one can be passed to functions and
|
||||
// (under MSVC, which has a bug, be used as a default template type parameter).
|
||||
struct void_t {};
|
||||
}
|
||||
|
||||
// An envelope in which type information can be delivered for the purposes
|
||||
// of selecting an overloaded from_python() function. This is needed to work
|
||||
// around MSVC's lack of partial specialiation/ordering. Where normally we'd
|
||||
// want to form a function call like void f<const T&>(), We instead pass
|
||||
// type<const T&> as one of the function parameters to select a particular
|
||||
// overload.
|
||||
//
|
||||
// The id typedef helps us deal with the lack of partial ordering by generating
|
||||
// unique types for constructor signatures. In general, type<T>::id is type<T>,
|
||||
// but type<void_t>::id is just void_t.
|
||||
template <class T>
|
||||
struct type
|
||||
{
|
||||
typedef type id;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct type<boost::python::detail::void_t>
|
||||
{
|
||||
typedef boost::python::detail::void_t id;
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
// These basically encapsulate a chain of types, , used to make the syntax of
|
||||
// add(constructor<T1, ...>()) work. We need to produce a unique type for each number
|
||||
// of non-default parameters to constructor<>. Q: why not use a recursive
|
||||
// formulation for infinite extensibility? A: MSVC6 seems to choke on constructs
|
||||
// that involve recursive template nesting.
|
||||
//
|
||||
// signature chaining
|
||||
""" % args
|
||||
+ gen_struct_signatures(args)
|
||||
+ """
|
||||
// This one terminates the chain. Prepending void_t to the head of a void_t
|
||||
// signature results in a void_t signature again.
|
||||
inline signature0 prepend(void_t, signature0) { return signature0(); }
|
||||
|
||||
} // namespace detail
|
||||
"""
|
||||
+ gen_function("""
|
||||
template <%(class A%n% = detail::void_t%:, %)>
|
||||
struct constructor
|
||||
{
|
||||
};
|
||||
""", args)
|
||||
+ """
|
||||
namespace detail {
|
||||
// Return value extraction:
|
||||
|
||||
// This is just another little envelope for carrying a typedef (see type,
|
||||
// above). I could have re-used type, but that has a very specific purpose. I
|
||||
// thought this would be clearer.
|
||||
template <class T>
|
||||
struct return_value_select { typedef T type; };
|
||||
|
||||
// free functions"""
|
||||
+ gen_functions("""
|
||||
template <class R%(, class A%n%)>
|
||||
return_value_select<R> return_value(R (*)(%(A%n%:, %))) { return return_value_select<R>(); }
|
||||
""", args)
|
||||
|
||||
+
|
||||
"""
|
||||
// TODO(?): handle 'const void'
|
||||
|
||||
// member functions"""
|
||||
+ gen_functions("""
|
||||
template <class R, class T%(, class A%n%)>
|
||||
return_value_select<R> return_value(R (T::*)(%(A%n%:, %))) { return return_value_select<R>(); }
|
||||
""", args)
|
||||
|
||||
+ gen_functions("""
|
||||
template <class R, class T%(, class A%n%)>
|
||||
return_value_select<R> return_value(R (T::*)(%(A%n%:, %)) const) { return return_value_select<R>(); }
|
||||
""", args)
|
||||
|
||||
+ """
|
||||
}}} // namespace boost::python::detail
|
||||
|
||||
#endif
|
||||
""")
|
||||
|
||||
if __name__ == '__main__':
|
||||
import sys
|
||||
|
||||
if len(sys.argv) == 1:
|
||||
args = 5
|
||||
else:
|
||||
args = int(sys.argv[1])
|
||||
|
||||
print gen_signatures(args)
|
||||
|
||||
@@ -1,58 +0,0 @@
|
||||
from gen_function import *
|
||||
import string
|
||||
|
||||
def gen_singleton(args):
|
||||
return (
|
||||
"""// (C) Copyright David Abrahams 2000. Permission to copy, use, modify, sell and
|
||||
// distribute this software is granted provided this copyright notice appears
|
||||
// in all copies. This software is provided "as is" without express or implied
|
||||
// warranty, and with no claim as to its suitability for any purpose.
|
||||
//
|
||||
// The author gratefully acknowleges the support of Dragon Systems, Inc., in
|
||||
// producing this work.
|
||||
|
||||
#ifndef SINGLETON_DWA051900_H_
|
||||
# define SINGLETON_DWA051900_H_
|
||||
|
||||
# include <boost/python/detail/config.hpp>
|
||||
|
||||
namespace boost { namespace python { namespace detail {
|
||||
|
||||
struct empty {};
|
||||
template <class Derived, class Base = empty>
|
||||
struct singleton : Base
|
||||
{
|
||||
typedef singleton singleton_base; // Convenience type for derived class constructors
|
||||
|
||||
static Derived* instance();
|
||||
|
||||
// Pass-through constructors
|
||||
"""
|
||||
+ gen_functions("""%{
|
||||
template <%(class A%n%:, %)>
|
||||
%} singleton(%(const A%n& a%n%:, %)) : Base(%(a%n%:, %)) {}
|
||||
""", args)
|
||||
+ """
|
||||
};
|
||||
|
||||
template <class Derived, class Base>
|
||||
Derived* singleton<Derived,Base>::instance()
|
||||
{
|
||||
static Derived x;
|
||||
return &x;
|
||||
}
|
||||
|
||||
}}} // namespace boost::python::detail
|
||||
|
||||
#endif
|
||||
""")
|
||||
|
||||
if __name__ == '__main__':
|
||||
import sys
|
||||
|
||||
if len(sys.argv) == 1:
|
||||
args = 5
|
||||
else:
|
||||
args = int(sys.argv[1])
|
||||
|
||||
print gen_singleton(args)
|
||||
@@ -1,36 +0,0 @@
|
||||
// (C) Copyright David Abrahams 2000. Permission to copy, use, modify, sell and
|
||||
// distribute this software is granted provided this copyright notice appears
|
||||
// in all copies. This software is provided "as is" without express or implied
|
||||
// warranty, and with no claim as to its suitability for any purpose.
|
||||
//
|
||||
// The author gratefully acknowleges the support of Dragon Systems, Inc., in
|
||||
// producing this work.
|
||||
|
||||
#include <boost/python/detail/init_function.hpp>
|
||||
#include <boost/python/objects.hpp>
|
||||
#include <boost/python/detail/extension_class.hpp>
|
||||
#include <utility>
|
||||
|
||||
namespace boost { namespace python { namespace detail {
|
||||
|
||||
PyObject* init::do_call(PyObject* args_, PyObject* keywords) const
|
||||
{
|
||||
tuple args(ref(args_, ref::increment_count));
|
||||
if (args[0]->ob_type->ob_type != extension_meta_class())
|
||||
{
|
||||
PyErr_SetString(PyExc_TypeError, "argument 1 to __init__ must be an ExtensionInstance");
|
||||
return 0;
|
||||
}
|
||||
|
||||
extension_instance *self = static_cast<extension_instance*>(args[0].get());
|
||||
|
||||
tuple ctor_args = args.slice(1, args.size());
|
||||
|
||||
std::auto_ptr<instance_holder_base> result(
|
||||
create_holder(self, ctor_args.get(), keywords));
|
||||
|
||||
self->add_implementation(result);
|
||||
return none();
|
||||
}
|
||||
|
||||
}}} // namespace boost::python::detail
|
||||
@@ -1,52 +0,0 @@
|
||||
// (C) Copyright David Abrahams 2000. Permission to copy, use, modify, sell and
|
||||
// distribute this software is granted provided this copyright notice appears
|
||||
// in all copies. This software is provided "as is" without express or implied
|
||||
// warranty, and with no claim as to its suitability for any purpose.
|
||||
//
|
||||
// The author gratefully acknowleges the support of Dragon Systems, Inc., in
|
||||
// producing this work.
|
||||
|
||||
#include <boost/python/module_builder.hpp>
|
||||
|
||||
namespace boost { namespace python {
|
||||
|
||||
namespace {
|
||||
ref name_holder;
|
||||
}
|
||||
|
||||
string module_builder::name()
|
||||
{
|
||||
// If this fails, you haven't created a module_builder object
|
||||
assert(name_holder.get() != 0);
|
||||
return string(name_holder);
|
||||
}
|
||||
|
||||
module_builder::module_builder(const char* name)
|
||||
: m_module(Py_InitModule(const_cast<char*>(name), initial_methods))
|
||||
{
|
||||
// If this fails, you've created more than 1 module_builder object in your module
|
||||
assert(name_holder.get() == 0);
|
||||
name_holder = ref(PyObject_GetAttrString(m_module, const_cast<char*>("__name__")));
|
||||
}
|
||||
|
||||
void
|
||||
module_builder::add(detail::function* x, const char* name)
|
||||
{
|
||||
reference<detail::function> f(x); // First take possession of the object.
|
||||
detail::function::add_to_namespace(f, name, PyModule_GetDict(m_module));
|
||||
}
|
||||
|
||||
void module_builder::add(ref x, const char* name)
|
||||
{
|
||||
PyObject* dictionary = PyModule_GetDict(m_module);
|
||||
PyDict_SetItemString(dictionary, const_cast<char*>(name), x.get());
|
||||
}
|
||||
|
||||
void module_builder::add(PyTypeObject* x, const char* name /*= 0*/)
|
||||
{
|
||||
this->add(ref(as_object(x)), name ? name : x->tp_name);
|
||||
}
|
||||
|
||||
PyMethodDef module_builder::initial_methods[] = { { 0, 0, 0, 0 } };
|
||||
|
||||
}} // namespace boost::python
|
||||
485
src/objects.cpp
485
src/objects.cpp
@@ -1,485 +0,0 @@
|
||||
// (C) Copyright David Abrahams 2000. Permission to copy, use, modify, sell and
|
||||
// distribute this software is granted provided this copyright notice appears
|
||||
// in all copies. This software is provided "as is" without express or implied
|
||||
// warranty, and with no claim as to its suitability for any purpose.
|
||||
//
|
||||
// The author gratefully acknowleges the support of Dragon Systems, Inc., in
|
||||
// producing this work.
|
||||
|
||||
// TODO: Move inline implementations from objects.cpp here
|
||||
|
||||
#include <boost/python/objects.hpp>
|
||||
#include <boost/python/detail/none.hpp>
|
||||
|
||||
namespace boost { namespace python {
|
||||
|
||||
template <class T>
|
||||
T object_from_python(PyObject* p, type<T>)
|
||||
{
|
||||
ref x(p, ref::increment_count);
|
||||
if (!T::accepts(x))
|
||||
{
|
||||
PyErr_SetString(PyExc_TypeError, p->ob_type->tp_name);
|
||||
throw error_already_set();
|
||||
}
|
||||
return T(x);
|
||||
}
|
||||
|
||||
inline PyObject* object_to_python(const object& x)
|
||||
{
|
||||
return x.reference().release();
|
||||
}
|
||||
|
||||
object::object(ref p)
|
||||
: m_p(p) {}
|
||||
|
||||
// Return a reference to the held object
|
||||
ref object::reference() const
|
||||
{
|
||||
return m_p;
|
||||
}
|
||||
|
||||
// Return a raw pointer to the held object
|
||||
PyObject* object::get() const
|
||||
{
|
||||
return m_p.get();
|
||||
}
|
||||
|
||||
}} // namespace boost::python
|
||||
|
||||
BOOST_PYTHON_BEGIN_CONVERSION_NAMESPACE
|
||||
|
||||
PyObject* to_python(const boost::python::tuple& x)
|
||||
{
|
||||
return object_to_python(x);
|
||||
}
|
||||
|
||||
boost::python::tuple from_python(PyObject* p, boost::python::type<boost::python::tuple> type)
|
||||
{
|
||||
return boost::python::object_from_python(p, type);
|
||||
}
|
||||
|
||||
PyObject* to_python(const boost::python::list& x)
|
||||
{
|
||||
return object_to_python(x);
|
||||
}
|
||||
|
||||
boost::python::list from_python(PyObject* p, boost::python::type<boost::python::list> type)
|
||||
{
|
||||
return boost::python::object_from_python(p, type);
|
||||
}
|
||||
|
||||
PyObject* to_python(const boost::python::dictionary& x)
|
||||
{
|
||||
return object_to_python(x);
|
||||
}
|
||||
|
||||
boost::python::dictionary from_python(PyObject* p, boost::python::type<boost::python::dictionary> type)
|
||||
{
|
||||
return boost::python::object_from_python(p, type);
|
||||
}
|
||||
|
||||
PyObject* to_python(const boost::python::string& x)
|
||||
{
|
||||
return object_to_python(x);
|
||||
}
|
||||
|
||||
boost::python::string from_python(PyObject* p, boost::python::type<boost::python::string> type)
|
||||
{
|
||||
return boost::python::object_from_python(p, type);
|
||||
}
|
||||
|
||||
BOOST_PYTHON_END_CONVERSION_NAMESPACE
|
||||
|
||||
namespace boost { namespace python {
|
||||
|
||||
tuple::tuple(std::size_t n)
|
||||
: object(ref(PyTuple_New(n)))
|
||||
{
|
||||
for (std::size_t i = 0; i < n; ++i)
|
||||
PyTuple_SET_ITEM(get(), i, detail::none());
|
||||
}
|
||||
|
||||
tuple::tuple(ref p)
|
||||
: object(p)
|
||||
{
|
||||
assert(accepts(p));
|
||||
if (!accepts(p))
|
||||
{
|
||||
PyErr_SetString(PyExc_TypeError, p->ob_type->tp_name);
|
||||
throw error_already_set();
|
||||
}
|
||||
}
|
||||
|
||||
PyTypeObject* tuple::type_obj()
|
||||
{
|
||||
return &PyTuple_Type;
|
||||
}
|
||||
|
||||
bool tuple::accepts(ref p)
|
||||
{
|
||||
return PyTuple_Check(p.get());
|
||||
}
|
||||
|
||||
std::size_t tuple::size() const
|
||||
{
|
||||
return PyTuple_Size(get());
|
||||
}
|
||||
|
||||
ref tuple::operator[](std::size_t pos) const
|
||||
{
|
||||
return ref(PyTuple_GetItem(get(), static_cast<int>(pos)),
|
||||
ref::increment_count);
|
||||
}
|
||||
|
||||
void tuple::set_item(std::size_t pos, const ref& rhs)
|
||||
{
|
||||
int failed = PyTuple_SetItem(
|
||||
get(), static_cast<int>(pos), ref(rhs).release()); // A reference is stolen here.
|
||||
(void)failed;
|
||||
assert(failed == 0);
|
||||
}
|
||||
|
||||
tuple tuple::slice(int low, int high) const
|
||||
{
|
||||
return tuple(ref(PyTuple_GetSlice(get(), low, high)));
|
||||
}
|
||||
|
||||
tuple& tuple::operator+=(const tuple& rhs)
|
||||
{
|
||||
return *this = *this + rhs;
|
||||
}
|
||||
|
||||
|
||||
// Construct from an owned PyObject*.
|
||||
// Precondition: p must point to a python string.
|
||||
string::string(ref p)
|
||||
: object(p)
|
||||
{
|
||||
assert(accepts(p));
|
||||
if (!accepts(p))
|
||||
{
|
||||
PyErr_SetString(PyExc_TypeError, p->ob_type->tp_name);
|
||||
throw error_already_set();
|
||||
}
|
||||
}
|
||||
|
||||
string::string(const char* s)
|
||||
: object(ref(PyString_FromString(s))) {}
|
||||
|
||||
string::string(const char* s, std::size_t length)
|
||||
: object(ref(PyString_FromStringAndSize(s, length))) {}
|
||||
|
||||
string::string(const char* s, interned_t)
|
||||
: object(ref(PyString_InternFromString(s))) {}
|
||||
|
||||
#if 0
|
||||
string::string(const char* s, std::size_t length, interned_t)
|
||||
: object(ref(PyString_InternFromStringAndSize(s, length))) {}
|
||||
#endif
|
||||
|
||||
string::string(const string& rhs)
|
||||
: object(rhs.reference()) {}
|
||||
|
||||
// Get the type object for Strings
|
||||
PyTypeObject* string::type_obj()
|
||||
{ return &PyString_Type; }
|
||||
|
||||
// Return true if the given object is a python string
|
||||
bool string::accepts(ref o)
|
||||
{ return PyString_Check(o.get()); }
|
||||
|
||||
// Return the length of the string.
|
||||
std::size_t string::size() const
|
||||
{
|
||||
int size = PyString_GET_SIZE(get());
|
||||
assert(size >= 0);
|
||||
return static_cast<std::size_t>(size);
|
||||
}
|
||||
|
||||
// Returns a null-terminated representation of the contents of string.
|
||||
// The pointer refers to the internal buffer of string, not a copy.
|
||||
// The data must not be modified in any way. It must not be de-allocated.
|
||||
const char* string::c_str() const
|
||||
{ return PyString_AS_STRING(get()); }
|
||||
|
||||
void string::intern()
|
||||
{ // UNTESTED!!
|
||||
*this = string(ref(PyString_InternFromString(c_str()), ref::increment_count));
|
||||
}
|
||||
|
||||
string& string::operator*=(unsigned int repeat_count)
|
||||
{
|
||||
*this = string(ref(PySequence_Repeat(get(), repeat_count)));
|
||||
return *this;
|
||||
}
|
||||
|
||||
dictionary::dictionary(ref p)
|
||||
: object(p)
|
||||
{
|
||||
assert(accepts(p));
|
||||
if (!accepts(p))
|
||||
{
|
||||
PyErr_SetString(PyExc_TypeError, p->ob_type->tp_name);
|
||||
throw error_already_set();
|
||||
}
|
||||
}
|
||||
|
||||
dictionary::dictionary()
|
||||
: object(ref(PyDict_New())) {}
|
||||
|
||||
PyTypeObject* dictionary::type_obj()
|
||||
{ return &PyDict_Type; }
|
||||
|
||||
bool dictionary::accepts(ref p)
|
||||
{ return PyDict_Check(p.get()); }
|
||||
|
||||
void dictionary::clear()
|
||||
{ PyDict_Clear(get()); }
|
||||
|
||||
const ref& dictionary::proxy::operator=(const ref& rhs)
|
||||
{
|
||||
if (PyDict_SetItem(m_dict.get(), m_key.get(), rhs.get()) == -1)
|
||||
throw error_already_set();
|
||||
return rhs;
|
||||
}
|
||||
|
||||
dictionary::proxy::operator ref() const
|
||||
{
|
||||
return ref(m_dict->ob_type->tp_as_mapping->mp_subscript(m_dict.get(), m_key.get()),
|
||||
ref::increment_count);
|
||||
}
|
||||
|
||||
dictionary::proxy::proxy(const ref& dict, const ref& key)
|
||||
: m_dict(dict), m_key(key) {}
|
||||
|
||||
dictionary::proxy dictionary::operator[](ref key)
|
||||
{ return proxy(reference(), key); }
|
||||
|
||||
ref dictionary::operator[](ref key) const {
|
||||
// An odd MSVC bug causes the ".operator Ptr()" to be needed
|
||||
return proxy(reference(), key).operator ref();
|
||||
}
|
||||
|
||||
|
||||
ref dictionary::get_item(const ref& key) const
|
||||
{
|
||||
return get_item(key, ref());
|
||||
}
|
||||
|
||||
ref dictionary::get_item(const ref& key, const ref& default_) const
|
||||
{
|
||||
PyObject* value_or_null = PyDict_GetItem(get(), key.get());
|
||||
if (value_or_null == 0 && !PyErr_Occurred())
|
||||
return default_;
|
||||
else
|
||||
return ref(value_or_null, ref::increment_count); // Will throw if there was another error
|
||||
}
|
||||
|
||||
void dictionary::set_item(const ref& key, const ref& value)
|
||||
{
|
||||
if (PyDict_SetItem(get(), key.get(), value.get()) == -1)
|
||||
throw error_already_set();
|
||||
}
|
||||
|
||||
void dictionary::erase(ref key) {
|
||||
if (PyDict_DelItem(get(), key.get()) == -1)
|
||||
throw error_already_set();
|
||||
}
|
||||
|
||||
list dictionary::items() const { return list(ref(PyDict_Items(get()))); }
|
||||
list dictionary::keys() const { return list(ref(PyDict_Keys(get()))); }
|
||||
list dictionary::values() const { return list(ref(PyDict_Values(get()))); }
|
||||
|
||||
std::size_t dictionary::size() const { return static_cast<std::size_t>(PyDict_Size(get())); }
|
||||
|
||||
string operator+(string x, string y)
|
||||
{
|
||||
PyObject* io_string = x.reference().release();
|
||||
PyString_Concat(&io_string, y.get());
|
||||
return string(ref(io_string));
|
||||
}
|
||||
|
||||
string& string::operator+=(const string& rhs)
|
||||
{
|
||||
return *this = *this + rhs;
|
||||
}
|
||||
|
||||
string& string::operator+=(const char* y)
|
||||
{
|
||||
return *this += string(y);
|
||||
}
|
||||
|
||||
string operator%(const string& format, const tuple& args)
|
||||
{
|
||||
return string(ref(PyString_Format(format.get(), args.reference().get())));
|
||||
}
|
||||
|
||||
string operator+(string x, const char* y)
|
||||
{
|
||||
return x + string(y);
|
||||
}
|
||||
|
||||
string operator+(const char* x, string y)
|
||||
{
|
||||
return string(x) + y;
|
||||
}
|
||||
|
||||
tuple operator+(const tuple& x, const tuple& y)
|
||||
{
|
||||
tuple result(x.size() + y.size());
|
||||
for (std::size_t xi = 0; xi < x.size(); ++xi)
|
||||
result.set_item(xi, x[xi]);
|
||||
for (std::size_t yi = 0; yi < y.size(); ++yi)
|
||||
result.set_item(yi + x.size(), y[yi]);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
list::list(ref p)
|
||||
: object(p)
|
||||
{
|
||||
assert(accepts(p));
|
||||
if (!accepts(p))
|
||||
{
|
||||
PyErr_SetString(PyExc_TypeError, p->ob_type->tp_name);
|
||||
throw error_already_set();
|
||||
}
|
||||
}
|
||||
|
||||
list::list(std::size_t sz)
|
||||
: object(ref(PyList_New(sz)))
|
||||
{
|
||||
}
|
||||
|
||||
PyTypeObject* list::type_obj()
|
||||
{
|
||||
return &PyList_Type;
|
||||
}
|
||||
|
||||
bool list::accepts(ref p)
|
||||
{
|
||||
return PyList_Check(p.get());
|
||||
}
|
||||
|
||||
std::size_t list::size()
|
||||
{
|
||||
return PyList_Size(get());
|
||||
}
|
||||
|
||||
ref list::operator[](std::size_t pos) const
|
||||
{
|
||||
return ref(PyList_GetItem(get(), pos), ref::increment_count);
|
||||
}
|
||||
|
||||
list::proxy list::operator[](std::size_t pos)
|
||||
{
|
||||
return proxy(reference(), pos);
|
||||
}
|
||||
|
||||
void list::insert(std::size_t index, const ref& item)
|
||||
{
|
||||
if (PyList_Insert(get(), index, item.get()) == -1)
|
||||
throw error_already_set();
|
||||
}
|
||||
|
||||
void list::push_back(const ref& item)
|
||||
{
|
||||
if (PyList_Append(get(), item.get()) == -1)
|
||||
throw error_already_set();
|
||||
}
|
||||
|
||||
void list::append(const ref& item)
|
||||
{
|
||||
this->push_back(item);
|
||||
}
|
||||
|
||||
list list::slice(int low, int high) const
|
||||
{
|
||||
return list(ref(PyList_GetSlice(get(), low, high)));
|
||||
}
|
||||
|
||||
list::slice_proxy list::slice(int low, int high)
|
||||
{
|
||||
return slice_proxy(reference(), low, high);
|
||||
}
|
||||
|
||||
void list::sort()
|
||||
{
|
||||
if (PyList_Sort(get()) == -1)
|
||||
throw error_already_set();
|
||||
}
|
||||
|
||||
void list::reverse()
|
||||
{
|
||||
if (PyList_Reverse(get()) == -1)
|
||||
throw error_already_set();
|
||||
}
|
||||
|
||||
tuple list::as_tuple() const
|
||||
{
|
||||
return tuple(ref(PyList_AsTuple(get())));
|
||||
}
|
||||
|
||||
const ref& list::proxy::operator=(const ref& rhs)
|
||||
{
|
||||
m_list.set_item(m_index, rhs);
|
||||
return rhs;
|
||||
}
|
||||
|
||||
list::proxy::operator ref() const
|
||||
{
|
||||
return ref(PyList_GetItem(m_list.get(), m_index), ref::increment_count);
|
||||
}
|
||||
|
||||
ref list::get_item(std::size_t pos) const
|
||||
{
|
||||
return ref(PyList_GetItem(this->get(), pos), ref::increment_count);
|
||||
}
|
||||
|
||||
void list::set_item(std::size_t pos, const ref& rhs)
|
||||
{
|
||||
int result = PyList_SetItem(this->get(), pos, rhs.get());
|
||||
if (result == -1)
|
||||
throw error_already_set();
|
||||
Py_INCREF(rhs.get());
|
||||
}
|
||||
|
||||
list::proxy::proxy(const ref& list, std::size_t index)
|
||||
: m_list(list), m_index(index)
|
||||
{
|
||||
}
|
||||
|
||||
const list& list::slice_proxy::operator=(const list& rhs)
|
||||
{
|
||||
if (PyList_SetSlice(m_list.get(), m_low, m_high, rhs.get()) == -1)
|
||||
throw error_already_set();
|
||||
return rhs;
|
||||
}
|
||||
|
||||
list::slice_proxy::operator ref() const
|
||||
{
|
||||
return ref(PyList_GetSlice(m_list.get(), m_low, m_high));
|
||||
}
|
||||
|
||||
list::slice_proxy::operator list() const
|
||||
{
|
||||
return list(this->operator ref());
|
||||
}
|
||||
|
||||
std::size_t list::slice_proxy::size()
|
||||
{
|
||||
return this->operator list().size();
|
||||
}
|
||||
|
||||
ref list::slice_proxy::operator[](std::size_t pos) const
|
||||
{
|
||||
return this->operator list()[pos].operator ref();
|
||||
}
|
||||
|
||||
list::slice_proxy::slice_proxy(const ref& list, int low, int high)
|
||||
: m_list(list), m_low(low), m_high(high)
|
||||
{
|
||||
}
|
||||
|
||||
}} // namespace boost::python
|
||||
1097
src/types.cpp
1097
src/types.cpp
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user