function.cpp
来自「Boost provides free peer-reviewed portab」· C++ 代码 · 共 762 行 · 第 1/2 页
CPP
762 行
// Copyright David Abrahams 2001.// Distributed under the Boost Software License, Version 1.0. (See// accompanying file LICENSE_1_0.txt or copy at// http://www.boost.org/LICENSE_1_0.txt)#include <boost/python/docstring_options.hpp>#include <boost/python/object/function_object.hpp>#include <boost/python/object/function_handle.hpp>#include <boost/python/object/function_doc_signature.hpp>#include <boost/python/errors.hpp>#include <boost/python/str.hpp>#include <boost/python/object_attributes.hpp>#include <boost/python/args.hpp>#include <boost/python/refcount.hpp>#include <boost/python/extract.hpp>#include <boost/python/tuple.hpp>#include <boost/python/list.hpp>#include <boost/python/ssize_t.hpp>#include <boost/python/detail/signature.hpp>#include <boost/python/detail/none.hpp>#include <boost/mpl/vector/vector10.hpp>#include <boost/bind.hpp>#include <algorithm>#include <cstring>#if BOOST_PYTHON_DEBUG_ERROR_MESSAGES# include <cstdio>#endifnamespace boost { namespace python { volatile bool docstring_options::show_user_defined_ = true; volatile bool docstring_options::show_cpp_signatures_ = true;#ifndef BOOST_PYTHON_NO_PY_SIGNATURES volatile bool docstring_options::show_py_signatures_ = true;#else volatile bool docstring_options::show_py_signatures_ = false;#endif}}namespace boost { namespace python { namespace objects { py_function_impl_base::~py_function_impl_base(){}unsigned py_function_impl_base::max_arity() const{ return this->min_arity();}extern PyTypeObject function_type;function::function( py_function const& implementation#if BOOST_WORKAROUND(__EDG_VERSION__, == 245) , python::detail::keyword const* names_and_defaults#else , python::detail::keyword const* const names_and_defaults#endif , unsigned num_keywords ) : m_fn(implementation) , m_nkeyword_values(0){ if (names_and_defaults != 0) { unsigned int max_arity = m_fn.max_arity(); unsigned int keyword_offset = max_arity > num_keywords ? max_arity - num_keywords : 0; ssize_t tuple_size = num_keywords ? max_arity : 0; m_arg_names = object(handle<>(PyTuple_New(tuple_size))); if (num_keywords != 0) { for (unsigned j = 0; j < keyword_offset; ++j) PyTuple_SET_ITEM(m_arg_names.ptr(), j, incref(Py_None)); } for (unsigned i = 0; i < num_keywords; ++i) { tuple kv; python::detail::keyword const* const p = names_and_defaults + i; if (p->default_value) { kv = make_tuple(p->name, p->default_value); ++m_nkeyword_values; } else { kv = make_tuple(p->name); } PyTuple_SET_ITEM( m_arg_names.ptr() , i + keyword_offset , incref(kv.ptr()) ); } } PyObject* p = this; if (function_type.ob_type == 0) { function_type.ob_type = &PyType_Type; ::PyType_Ready(&function_type); } (void)( // warning suppression for GCC PyObject_INIT(p, &function_type) );}function::~function(){}PyObject* function::call(PyObject* args, PyObject* keywords) const{ std::size_t n_unnamed_actual = PyTuple_GET_SIZE(args); std::size_t n_keyword_actual = keywords ? PyDict_Size(keywords) : 0; std::size_t n_actual = n_unnamed_actual + n_keyword_actual; function const* f = this; // Try overloads looking for a match do { // Check for a plausible number of arguments unsigned min_arity = f->m_fn.min_arity(); unsigned max_arity = f->m_fn.max_arity(); if (n_actual + f->m_nkeyword_values >= min_arity && n_actual <= max_arity) { // This will be the args that actually get passed handle<>inner_args(allow_null(borrowed(args))); if (n_keyword_actual > 0 // Keyword arguments were supplied || n_actual < min_arity) // or default keyword values are needed { if (f->m_arg_names.ptr() == Py_None) { // this overload doesn't accept keywords inner_args = handle<>(); } else { // "all keywords are none" is a special case // indicating we will accept any number of keyword // arguments if (PyTuple_Size(f->m_arg_names.ptr()) == 0) { // no argument preprocessing } else if (n_actual > max_arity) { // too many arguments inner_args = handle<>(); } else { // build a new arg tuple, will adjust its size later assert(max_arity <= ssize_t_max); inner_args = handle<>( PyTuple_New(static_cast<ssize_t>(max_arity))); // Fill in the positional arguments for (std::size_t i = 0; i < n_unnamed_actual; ++i) PyTuple_SET_ITEM(inner_args.get(), i, incref(PyTuple_GET_ITEM(args, i))); // Grab remaining arguments by name from the keyword dictionary std::size_t n_actual_processed = n_unnamed_actual; for (std::size_t arg_pos = n_unnamed_actual; arg_pos < max_arity ; ++arg_pos) { // Get the keyword[, value pair] corresponding PyObject* kv = PyTuple_GET_ITEM(f->m_arg_names.ptr(), arg_pos); // If there were any keyword arguments, // look up the one we need for this // argument position PyObject* value = n_keyword_actual ? PyDict_GetItem(keywords, PyTuple_GET_ITEM(kv, 0)) : 0; if (!value) { // Not found; check if there's a default value if (PyTuple_GET_SIZE(kv) > 1) value = PyTuple_GET_ITEM(kv, 1); if (!value) { // still not found; matching fails PyErr_Clear(); inner_args = handle<>(); break; } } else { ++n_actual_processed; } PyTuple_SET_ITEM(inner_args.get(), arg_pos, incref(value)); } if (inner_args.get()) { //check if we proccessed all the arguments if(n_actual_processed < n_actual) inner_args = handle<>(); } } } } // Call the function. Pass keywords in case it's a // function accepting any number of keywords PyObject* result = inner_args ? f->m_fn(inner_args.get(), keywords) : 0; // If the result is NULL but no error was set, m_fn failed // the argument-matching test. // This assumes that all other error-reporters are // well-behaved and never return NULL to python without // setting an error. if (result != 0 || PyErr_Occurred()) return result; } f = f->m_overloads.get(); } while (f); // None of the overloads matched; time to generate the error message argument_error(args, keywords); return 0;}object function::signature(bool show_return_type) const{ py_function const& impl = m_fn; python::detail::signature_element const* return_type = impl.signature(); python::detail::signature_element const* s = return_type + 1; list formal_params; if (impl.max_arity() == 0) formal_params.append("void"); for (unsigned n = 0; n < impl.max_arity(); ++n) { if (s[n].basename == 0) { formal_params.append("..."); break; } str param(s[n].basename); if (s[n].lvalue) param += " {lvalue}"; if (m_arg_names) // None or empty tuple will test false { object kv(m_arg_names[n]); if (kv) { char const* const fmt = len(kv) > 1 ? " %s=%r" : " %s"; param += fmt % kv; } } formal_params.append(param); } if (show_return_type) return "%s(%s) -> %s" % make_tuple( m_name, str(", ").join(formal_params), return_type->basename); return "%s(%s)" % make_tuple( m_name, str(", ").join(formal_params));}object function::signatures(bool show_return_type) const{ list result; for (function const* f = this; f; f = f->m_overloads.get()) { result.append(f->signature(show_return_type)); } return result;}void function::argument_error(PyObject* args, PyObject* /*keywords*/) const{ static handle<> exception( PyErr_NewException("Boost.Python.ArgumentError", PyExc_TypeError, 0)); object message = "Python argument types in\n %s.%s(" % make_tuple(this->m_namespace, this->m_name); list actual_args; for (ssize_t i = 0; i < PyTuple_Size(args); ++i) { char const* name = PyTuple_GetItem(args, i)->ob_type->tp_name; actual_args.append(str(name)); } message += str(", ").join(actual_args); message += ")\ndid not match C++ signature:\n "; message += str("\n ").join(signatures());#if BOOST_PYTHON_DEBUG_ERROR_MESSAGES std::printf("\n--------\n%s\n--------\n", extract<const char*>(message)());#endif PyErr_SetObject(exception.get(), message.ptr()); throw_error_already_set();}void function::add_overload(handle<function> const& overload_){ function* parent = this; while (parent->m_overloads) parent = parent->m_overloads.get(); parent->m_overloads = overload_; // If we have no documentation, get the docs from the overload if (!m_doc) m_doc = overload_->m_doc;}namespace{ char const* const binary_operator_names[] = { "add__", "and__", "div__", "divmod__", "eq__", "floordiv__", "ge__", "gt__", "le__", "lshift__", "lt__", "mod__", "mul__", "ne__", "or__", "pow__", "radd__", "rand__", "rdiv__", "rdivmod__", "rfloordiv__", "rlshift__", "rmod__", "rmul__", "ror__", "rpow__", "rrshift__", "rshift__", "rsub__", "rtruediv__", "rxor__", "sub__", "truediv__", "xor__" }; struct less_cstring { bool operator()(char const* x, char const* y) const { return BOOST_CSTD_::strcmp(x,y) < 0; }
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?