📄 function.cpp
字号:
"rrshift__",
"rshift__",
"rsub__",
"rtruediv__",
"rxor__",
"sub__",
"truediv__",
"xor__"
};
struct less_cstring
{
bool operator()(char const* x, char const* y) const
{
return BOOST_CSTD_::strcmp(x,y) < 0;
}
};
inline bool is_binary_operator(char const* name)
{
return name[0] == '_'
&& name[1] == '_'
&& std::binary_search(
&binary_operator_names[0]
, binary_operator_names + sizeof(binary_operator_names)/sizeof(*binary_operator_names)
, name + 2
, less_cstring()
);
}
// Something for the end of the chain of binary operators
PyObject* not_implemented(PyObject*, PyObject*)
{
Py_INCREF(Py_NotImplemented);
return Py_NotImplemented;
}
handle<function> not_implemented_function()
{
static object keeper(
function_object(
py_function(¬_implemented, mpl::vector1<void>(), 2)
, python::detail::keyword_range())
);
return handle<function>(borrowed(downcast<function>(keeper.ptr())));
}
}
void function::add_to_namespace(
object const& name_space, char const* name_, object const& attribute)
{
str const name(name_);
PyObject* const ns = name_space.ptr();
if (attribute.ptr()->ob_type == &function_type)
{
function* new_func = downcast<function>(attribute.ptr());
PyObject* dict = 0;
if (PyClass_Check(ns))
dict = ((PyClassObject*)ns)->cl_dict;
else if (PyType_Check(ns))
dict = ((PyTypeObject*)ns)->tp_dict;
else
dict = PyObject_GetAttrString(ns, "__dict__");
if (dict == 0)
throw_error_already_set();
handle<> existing(allow_null(::PyObject_GetItem(dict, name.ptr())));
if (existing)
{
if (existing->ob_type == &function_type)
{
new_func->add_overload(
handle<function>(
borrowed(
downcast<function>(existing.get())
)
)
);
}
else if (existing->ob_type == &PyStaticMethod_Type)
{
char const* name_space_name = extract<char const*>(name_space.attr("__name__"));
::PyErr_Format(
PyExc_RuntimeError
, "Boost.Python - All overloads must be exported "
"before calling \'class_<...>(\"%s\").staticmethod(\"%s\")\'"
, name_space_name
, name_
);
throw_error_already_set();
}
}
else if (is_binary_operator(name_))
{
// Binary operators need an additional overload which
// returns NotImplemented, so that Python will try the
// __rxxx__ functions on the other operand. We add this
// when no overloads for the operator already exist.
new_func->add_overload(not_implemented_function());
}
// A function is named the first time it is added to a namespace.
if (new_func->name().ptr() == Py_None)
new_func->m_name = name;
handle<> name_space_name(
allow_null(::PyObject_GetAttrString(name_space.ptr(), "__name__")));
if (name_space_name)
new_func->m_namespace = object(name_space_name);
}
// The PyObject_GetAttrString() or PyObject_GetItem calls above may
// have left an active error
PyErr_Clear();
if (PyObject_SetAttr(ns, name.ptr(), attribute.ptr()) < 0)
throw_error_already_set();
}
void function::add_to_namespace(
object const& name_space, char const* name_, object const& attribute, char const* doc)
{
add_to_namespace(name_space, name_, attribute);
if (doc != 0)
{
// Accumulate documentation
object mutable_attribute(attribute);
if (
PyObject_HasAttrString(mutable_attribute.ptr(), "__doc__")
&& mutable_attribute.attr("__doc__"))
{
mutable_attribute.attr("__doc__") += "\n\n";
mutable_attribute.attr("__doc__") += doc;
}
else
mutable_attribute.attr("__doc__") = doc;
}
}
BOOST_PYTHON_DECL void add_to_namespace(
object const& name_space, char const* name, object const& attribute)
{
function::add_to_namespace(name_space, name, attribute);
}
BOOST_PYTHON_DECL void add_to_namespace(
object const& name_space, char const* name, object const& attribute, char const* doc)
{
function::add_to_namespace(name_space, name, attribute, doc);
}
namespace
{
struct bind_return
{
bind_return(PyObject*& result, function const* f, PyObject* args, PyObject* keywords)
: m_result(result)
, m_f(f)
, m_args(args)
, m_keywords(keywords)
{}
void operator()() const
{
m_result = m_f->call(m_args, m_keywords);
}
private:
PyObject*& m_result;
function const* m_f;
PyObject* m_args;
PyObject* m_keywords;
};
}
extern "C"
{
// Stolen from Python's funcobject.c
static PyObject *
function_descr_get(PyObject *func, PyObject *obj, PyObject *type_)
{
if (obj == Py_None)
obj = NULL;
return PyMethod_New(func, obj, type_);
}
static void
function_dealloc(PyObject* p)
{
delete static_cast<function*>(p);
}
static PyObject *
function_call(PyObject *func, PyObject *args, PyObject *kw)
{
PyObject* result = 0;
handle_exception(bind_return(result, static_cast<function*>(func), args, kw));
return result;
}
//
// Here we're using the function's tp_getset rather than its
// tp_members to set up __doc__ and __name__, because tp_members
// really depends on having a POD object type (it relies on
// offsets). It might make sense to reformulate function as a POD
// at some point, but this is much more expedient.
//
static PyObject* function_get_doc(PyObject* op, void*)
{
function* f = downcast<function>(op);
return python::incref(f->doc().ptr());
}
static int function_set_doc(PyObject* op, PyObject* doc, void*)
{
function* f = downcast<function>(op);
f->doc(doc ? object(python::detail::borrowed_reference(doc)) : object());
return 0;
}
static PyObject* function_get_name(PyObject* op, void*)
{
function* f = downcast<function>(op);
if (f->name().ptr() == Py_None)
return PyString_InternFromString("<unnamed Boost.Python function>");
else
return python::incref(f->name().ptr());
}
// We add a dummy __class__ attribute in order to fool PyDoc into
// treating these as built-in functions and scanning their
// documentation
static PyObject* function_get_class(PyObject* op, void*)
{
return python::incref(upcast<PyObject>(&PyCFunction_Type));
}
}
static PyGetSetDef function_getsetlist[] = {
{"__name__", (getter)function_get_name, 0 },
{"func_name", (getter)function_get_name, 0 },
{"__class__", (getter)function_get_class, 0 }, // see note above
{"__doc__", (getter)function_get_doc, (setter)function_set_doc},
{"func_doc", (getter)function_get_doc, (setter)function_set_doc},
{NULL} /* Sentinel */
};
PyTypeObject function_type = {
PyObject_HEAD_INIT(0)
0,
"Boost.Python.function",
sizeof(function),
0,
(destructor)function_dealloc, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_compare */
0, //(reprfunc)func_repr, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
0, /* tp_hash */
function_call, /* tp_call */
0, /* tp_str */
0, // PyObject_GenericGetAttr, /* tp_getattro */
0, // PyObject_GenericSetAttr, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT /* | Py_TPFLAGS_HAVE_GC */,/* tp_flags */
0, /* tp_doc */
0, // (traverseproc)func_traverse, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, //offsetof(PyFunctionObject, func_weakreflist), /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
0, /* tp_methods */
0, // func_memberlist, /* tp_members */
function_getsetlist, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
function_descr_get, /* tp_descr_get */
0, /* tp_descr_set */
0, //offsetof(PyFunctionObject, func_dict), /* tp_dictoffset */
0, /* tp_init */
0, /* tp_alloc */
0,
0 /* tp_new */
};
object function_object(
py_function const& f
, python::detail::keyword_range const& keywords)
{
return python::object(
python::detail::new_non_null_reference(
new function(
f, keywords.first, keywords.second - keywords.first)));
}
object function_object(py_function const& f)
{
return function_object(f, python::detail::keyword_range());
}
handle<> function_handle_impl(py_function const& f)
{
return python::handle<>(
allow_null(
new function(f, 0, 0)));
}
} // namespace objects
namespace detail
{
object BOOST_PYTHON_DECL make_raw_function(objects::py_function f)
{
static keyword k;
return objects::function_object(
f
, keyword_range(&k,&k));
}
void BOOST_PYTHON_DECL pure_virtual_called()
{
PyErr_SetString(PyExc_RuntimeError, "Pure virtual function called");
throw_error_already_set();
}
}
}} // namespace boost::python
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -