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 + -
显示快捷键?