diff options
author | neksard <neksard@yandex-team.ru> | 2022-02-10 16:45:23 +0300 |
---|---|---|
committer | Daniil Cherednik <dcherednik@yandex-team.ru> | 2022-02-10 16:45:23 +0300 |
commit | 8f7cf138264e0caa318144bf8a2c950e0b0a8593 (patch) | |
tree | 83bf5c8c8047c42d8475e6095df90ccdc3d1b57f /contrib/restricted/boost/libs/python/src/object/function.cpp | |
parent | d3a398281c6fd1d3672036cb2d63f842d2cb28c5 (diff) | |
download | ydb-8f7cf138264e0caa318144bf8a2c950e0b0a8593.tar.gz |
Restoring authorship annotation for <neksard@yandex-team.ru>. Commit 1 of 2.
Diffstat (limited to 'contrib/restricted/boost/libs/python/src/object/function.cpp')
-rw-r--r-- | contrib/restricted/boost/libs/python/src/object/function.cpp | 1578 |
1 files changed, 789 insertions, 789 deletions
diff --git a/contrib/restricted/boost/libs/python/src/object/function.cpp b/contrib/restricted/boost/libs/python/src/object/function.cpp index e15eb3ffc0..d1f9be3319 100644 --- a/contrib/restricted/boost/libs/python/src/object/function.cpp +++ b/contrib/restricted/boost/libs/python/src/object/function.cpp @@ -1,794 +1,794 @@ -// Copyright David Abrahams 2001. -// Distributed under the Boost Software License, Version 1.0. (See -// accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) - -#include <boost/python/docstring_options.hpp> -#include <boost/python/object/function_object.hpp> -#include <boost/python/object/function_handle.hpp> -#include <boost/python/object/function_doc_signature.hpp> -#include <boost/python/errors.hpp> -#include <boost/python/str.hpp> -#include <boost/python/object_attributes.hpp> -#include <boost/python/args.hpp> -#include <boost/python/refcount.hpp> -#include <boost/python/extract.hpp> -#include <boost/python/tuple.hpp> -#include <boost/python/list.hpp> -#include <boost/python/ssize_t.hpp> - -#include <boost/python/detail/signature.hpp> -#include <boost/python/detail/none.hpp> -#include <boost/mpl/vector/vector10.hpp> - -#include <boost/bind.hpp> - -#include <algorithm> -#include <cstring> - -#if BOOST_PYTHON_DEBUG_ERROR_MESSAGES -# include <cstdio> -#endif - -namespace boost { namespace python { - volatile bool docstring_options::show_user_defined_ = true; - volatile bool docstring_options::show_cpp_signatures_ = true; -#ifndef BOOST_PYTHON_NO_PY_SIGNATURES - volatile bool docstring_options::show_py_signatures_ = true; -#else - volatile bool docstring_options::show_py_signatures_ = false; -#endif -}} - -namespace boost { namespace python { namespace objects { - -py_function_impl_base::~py_function_impl_base() -{ -} - -unsigned py_function_impl_base::max_arity() const -{ - return this->min_arity(); -} - -extern PyTypeObject function_type; - -function::function( - py_function const& implementation -#if BOOST_WORKAROUND(__EDG_VERSION__, == 245) - , python::detail::keyword const* names_and_defaults -#else - , python::detail::keyword const* const names_and_defaults -#endif - , unsigned num_keywords - ) - : m_fn(implementation) - , m_nkeyword_values(0) -{ - if (names_and_defaults != 0) - { - unsigned int max_arity = m_fn.max_arity(); - unsigned int keyword_offset - = max_arity > num_keywords ? max_arity - num_keywords : 0; - - - ssize_t tuple_size = num_keywords ? max_arity : 0; - m_arg_names = object(handle<>(PyTuple_New(tuple_size))); - - if (num_keywords != 0) - { - for (unsigned j = 0; j < keyword_offset; ++j) - PyTuple_SET_ITEM(m_arg_names.ptr(), j, incref(Py_None)); - } - - for (unsigned i = 0; i < num_keywords; ++i) - { - tuple kv; - - python::detail::keyword const* const p = names_and_defaults + i; - if (p->default_value) - { - kv = make_tuple(p->name, p->default_value); - ++m_nkeyword_values; - } - else - { - kv = make_tuple(p->name); - } - - PyTuple_SET_ITEM( - m_arg_names.ptr() - , i + keyword_offset - , incref(kv.ptr()) - ); - } - } - - PyObject* p = this; - if (Py_TYPE(&function_type) == 0) - { - Py_TYPE(&function_type) = &PyType_Type; - ::PyType_Ready(&function_type); - } - - (void)( // warning suppression for GCC - PyObject_INIT(p, &function_type) - ); -} - -function::~function() -{ -} - -PyObject* function::call(PyObject* args, PyObject* keywords) const -{ - std::size_t n_unnamed_actual = PyTuple_GET_SIZE(args); - std::size_t n_keyword_actual = keywords ? PyDict_Size(keywords) : 0; - std::size_t n_actual = n_unnamed_actual + n_keyword_actual; - - function const* f = this; - - // Try overloads looking for a match - do - { - // Check for a plausible number of arguments - unsigned min_arity = f->m_fn.min_arity(); - unsigned max_arity = f->m_fn.max_arity(); - - if (n_actual + f->m_nkeyword_values >= min_arity - && n_actual <= max_arity) - { - // This will be the args that actually get passed - handle<>inner_args(allow_null(borrowed(args))); - - if (n_keyword_actual > 0 // Keyword arguments were supplied - || n_actual < min_arity) // or default keyword values are needed - { - if (f->m_arg_names.is_none()) - { - // this overload doesn't accept keywords - inner_args = handle<>(); - } - else - { - // "all keywords are none" is a special case - // indicating we will accept any number of keyword - // arguments - if (PyTuple_Size(f->m_arg_names.ptr()) == 0) - { - // no argument preprocessing - } - else if (n_actual > max_arity) - { - // too many arguments - inner_args = handle<>(); - } - else - { - // build a new arg tuple, will adjust its size later - assert(max_arity <= static_cast<std::size_t>(ssize_t_max)); - inner_args = handle<>( - PyTuple_New(static_cast<ssize_t>(max_arity))); - - // Fill in the positional arguments - for (std::size_t i = 0; i < n_unnamed_actual; ++i) - PyTuple_SET_ITEM(inner_args.get(), i, incref(PyTuple_GET_ITEM(args, i))); - - // Grab remaining arguments by name from the keyword dictionary - std::size_t n_actual_processed = n_unnamed_actual; - - for (std::size_t arg_pos = n_unnamed_actual; arg_pos < max_arity ; ++arg_pos) - { - // Get the keyword[, value pair] corresponding - PyObject* kv = PyTuple_GET_ITEM(f->m_arg_names.ptr(), arg_pos); - - // If there were any keyword arguments, - // look up the one we need for this - // argument position - PyObject* value = n_keyword_actual - ? PyDict_GetItem(keywords, PyTuple_GET_ITEM(kv, 0)) - : 0; - - if (!value) - { - // Not found; check if there's a default value - if (PyTuple_GET_SIZE(kv) > 1) - value = PyTuple_GET_ITEM(kv, 1); - - if (!value) - { - // still not found; matching fails - PyErr_Clear(); - inner_args = handle<>(); - break; - } - } - else - { - ++n_actual_processed; - } - - PyTuple_SET_ITEM(inner_args.get(), arg_pos, incref(value)); - } - - if (inner_args.get()) - { - //check if we proccessed all the arguments - if(n_actual_processed < n_actual) - inner_args = handle<>(); - } - } - } - } - - // Call the function. Pass keywords in case it's a - // function accepting any number of keywords - PyObject* result = inner_args ? f->m_fn(inner_args.get(), keywords) : 0; - - // If the result is NULL but no error was set, m_fn failed - // the argument-matching test. - - // This assumes that all other error-reporters are - // well-behaved and never return NULL to python without - // setting an error. - if (result != 0 || PyErr_Occurred()) - return result; - } - f = f->m_overloads.get(); - } - while (f); - // None of the overloads matched; time to generate the error message - argument_error(args, keywords); - return 0; -} - -object function::signature(bool show_return_type) const -{ - py_function const& impl = m_fn; - - python::detail::signature_element const* return_type = impl.signature(); - python::detail::signature_element const* s = return_type + 1; - - list formal_params; - if (impl.max_arity() == 0) - formal_params.append("void"); - - for (unsigned n = 0; n < impl.max_arity(); ++n) - { - if (s[n].basename == 0) - { - formal_params.append("..."); - break; - } - - str param(s[n].basename); - if (s[n].lvalue) - param += " {lvalue}"; - - if (m_arg_names) // None or empty tuple will test false - { - object kv(m_arg_names[n]); - if (kv) - { - char const* const fmt = len(kv) > 1 ? " %s=%r" : " %s"; - param += fmt % kv; - } - } - - formal_params.append(param); - } - - if (show_return_type) - return "%s(%s) -> %s" % make_tuple( - m_name, str(", ").join(formal_params), return_type->basename); - return "%s(%s)" % make_tuple( - m_name, str(", ").join(formal_params)); -} - -object function::signatures(bool show_return_type) const -{ - list result; - for (function const* f = this; f; f = f->m_overloads.get()) { - result.append(f->signature(show_return_type)); - } - return result; -} - -void function::argument_error(PyObject* args, PyObject* /*keywords*/) const -{ - static handle<> exception( - PyErr_NewException(const_cast<char*>("Boost.Python.ArgumentError"), PyExc_TypeError, 0)); - - object message = "Python argument types in\n %s.%s(" - % make_tuple(this->m_namespace, this->m_name); - - list actual_args; - for (ssize_t i = 0; i < PyTuple_Size(args); ++i) - { - char const* name = PyTuple_GetItem(args, i)->ob_type->tp_name; - actual_args.append(str(name)); - } - message += str(", ").join(actual_args); - message += ")\ndid not match C++ signature:\n "; - message += str("\n ").join(signatures()); - -#if BOOST_PYTHON_DEBUG_ERROR_MESSAGES - std::printf("\n--------\n%s\n--------\n", extract<const char*>(message)()); +// Copyright David Abrahams 2001. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include <boost/python/docstring_options.hpp> +#include <boost/python/object/function_object.hpp> +#include <boost/python/object/function_handle.hpp> +#include <boost/python/object/function_doc_signature.hpp> +#include <boost/python/errors.hpp> +#include <boost/python/str.hpp> +#include <boost/python/object_attributes.hpp> +#include <boost/python/args.hpp> +#include <boost/python/refcount.hpp> +#include <boost/python/extract.hpp> +#include <boost/python/tuple.hpp> +#include <boost/python/list.hpp> +#include <boost/python/ssize_t.hpp> + +#include <boost/python/detail/signature.hpp> +#include <boost/python/detail/none.hpp> +#include <boost/mpl/vector/vector10.hpp> + +#include <boost/bind.hpp> + +#include <algorithm> +#include <cstring> + +#if BOOST_PYTHON_DEBUG_ERROR_MESSAGES +# include <cstdio> #endif - PyErr_SetObject(exception.get(), message.ptr()); - throw_error_already_set(); -} - -void function::add_overload(handle<function> const& overload_) -{ - function* parent = this; - - while (parent->m_overloads) - parent = parent->m_overloads.get(); - - parent->m_overloads = overload_; - - // If we have no documentation, get the docs from the overload - if (!m_doc) - m_doc = overload_->m_doc; -} - -namespace -{ - char const* const binary_operator_names[] = - { - "add__", - "and__", - "div__", - "divmod__", - "eq__", - "floordiv__", - "ge__", - "gt__", - "le__", - "lshift__", - "lt__", - "mod__", - "mul__", - "ne__", - "or__", - "pow__", - "radd__", - "rand__", - "rdiv__", - "rdivmod__", - "rfloordiv__", - "rlshift__", - "rmod__", - "rmul__", - "ror__", - "rpow__", - "rrshift__", - "rshift__", - "rsub__", - "rtruediv__", - "rxor__", - "sub__", - "truediv__", - "xor__" - }; - - struct less_cstring - { - bool operator()(char const* x, char const* y) const - { - return BOOST_CSTD_::strcmp(x,y) < 0; - } - }; - - inline bool is_binary_operator(char const* name) - { - return name[0] == '_' - && name[1] == '_' - && std::binary_search( - &binary_operator_names[0] - , binary_operator_names + sizeof(binary_operator_names)/sizeof(*binary_operator_names) - , name + 2 - , less_cstring() - ); - } - - // Something for the end of the chain of binary operators - PyObject* not_implemented(PyObject*, PyObject*) - { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - handle<function> not_implemented_function() - { - - static object keeper( - function_object( - py_function(¬_implemented, mpl::vector1<void>(), 2) - , python::detail::keyword_range()) - ); - return handle<function>(borrowed(downcast<function>(keeper.ptr()))); - } -} - -void function::add_to_namespace( - object const& name_space, char const* name_, object const& attribute) -{ - add_to_namespace(name_space, name_, attribute, 0); -} - -namespace detail -{ - extern char py_signature_tag[]; - extern char cpp_signature_tag[]; -} - -void function::add_to_namespace( - object const& name_space, char const* name_, object const& attribute, char const* doc) -{ - str const name(name_); - PyObject* const ns = name_space.ptr(); - - if (attribute.ptr()->ob_type == &function_type) - { - function* new_func = downcast<function>(attribute.ptr()); - handle<> dict; - -#if PY_VERSION_HEX < 0x03000000 - // Old-style class gone in Python 3 - if (PyClass_Check(ns)) - dict = handle<>(borrowed(((PyClassObject*)ns)->cl_dict)); - else -#endif - if (PyType_Check(ns)) - dict = handle<>(borrowed(((PyTypeObject*)ns)->tp_dict)); - else - dict = handle<>(PyObject_GetAttrString(ns, const_cast<char*>("__dict__"))); - - if (dict == 0) - throw_error_already_set(); - + +namespace boost { namespace python { + volatile bool docstring_options::show_user_defined_ = true; + volatile bool docstring_options::show_cpp_signatures_ = true; +#ifndef BOOST_PYTHON_NO_PY_SIGNATURES + volatile bool docstring_options::show_py_signatures_ = true; +#else + volatile bool docstring_options::show_py_signatures_ = false; +#endif +}} + +namespace boost { namespace python { namespace objects { + +py_function_impl_base::~py_function_impl_base() +{ +} + +unsigned py_function_impl_base::max_arity() const +{ + return this->min_arity(); +} + +extern PyTypeObject function_type; + +function::function( + py_function const& implementation +#if BOOST_WORKAROUND(__EDG_VERSION__, == 245) + , python::detail::keyword const* names_and_defaults +#else + , python::detail::keyword const* const names_and_defaults +#endif + , unsigned num_keywords + ) + : m_fn(implementation) + , m_nkeyword_values(0) +{ + if (names_and_defaults != 0) + { + unsigned int max_arity = m_fn.max_arity(); + unsigned int keyword_offset + = max_arity > num_keywords ? max_arity - num_keywords : 0; + + + ssize_t tuple_size = num_keywords ? max_arity : 0; + m_arg_names = object(handle<>(PyTuple_New(tuple_size))); + + if (num_keywords != 0) + { + for (unsigned j = 0; j < keyword_offset; ++j) + PyTuple_SET_ITEM(m_arg_names.ptr(), j, incref(Py_None)); + } + + for (unsigned i = 0; i < num_keywords; ++i) + { + tuple kv; + + python::detail::keyword const* const p = names_and_defaults + i; + if (p->default_value) + { + kv = make_tuple(p->name, p->default_value); + ++m_nkeyword_values; + } + else + { + kv = make_tuple(p->name); + } + + PyTuple_SET_ITEM( + m_arg_names.ptr() + , i + keyword_offset + , incref(kv.ptr()) + ); + } + } + + PyObject* p = this; + if (Py_TYPE(&function_type) == 0) + { + Py_TYPE(&function_type) = &PyType_Type; + ::PyType_Ready(&function_type); + } + + (void)( // warning suppression for GCC + PyObject_INIT(p, &function_type) + ); +} + +function::~function() +{ +} + +PyObject* function::call(PyObject* args, PyObject* keywords) const +{ + std::size_t n_unnamed_actual = PyTuple_GET_SIZE(args); + std::size_t n_keyword_actual = keywords ? PyDict_Size(keywords) : 0; + std::size_t n_actual = n_unnamed_actual + n_keyword_actual; + + function const* f = this; + + // Try overloads looking for a match + do + { + // Check for a plausible number of arguments + unsigned min_arity = f->m_fn.min_arity(); + unsigned max_arity = f->m_fn.max_arity(); + + if (n_actual + f->m_nkeyword_values >= min_arity + && n_actual <= max_arity) + { + // This will be the args that actually get passed + handle<>inner_args(allow_null(borrowed(args))); + + if (n_keyword_actual > 0 // Keyword arguments were supplied + || n_actual < min_arity) // or default keyword values are needed + { + if (f->m_arg_names.is_none()) + { + // this overload doesn't accept keywords + inner_args = handle<>(); + } + else + { + // "all keywords are none" is a special case + // indicating we will accept any number of keyword + // arguments + if (PyTuple_Size(f->m_arg_names.ptr()) == 0) + { + // no argument preprocessing + } + else if (n_actual > max_arity) + { + // too many arguments + inner_args = handle<>(); + } + else + { + // build a new arg tuple, will adjust its size later + assert(max_arity <= static_cast<std::size_t>(ssize_t_max)); + inner_args = handle<>( + PyTuple_New(static_cast<ssize_t>(max_arity))); + + // Fill in the positional arguments + for (std::size_t i = 0; i < n_unnamed_actual; ++i) + PyTuple_SET_ITEM(inner_args.get(), i, incref(PyTuple_GET_ITEM(args, i))); + + // Grab remaining arguments by name from the keyword dictionary + std::size_t n_actual_processed = n_unnamed_actual; + + for (std::size_t arg_pos = n_unnamed_actual; arg_pos < max_arity ; ++arg_pos) + { + // Get the keyword[, value pair] corresponding + PyObject* kv = PyTuple_GET_ITEM(f->m_arg_names.ptr(), arg_pos); + + // If there were any keyword arguments, + // look up the one we need for this + // argument position + PyObject* value = n_keyword_actual + ? PyDict_GetItem(keywords, PyTuple_GET_ITEM(kv, 0)) + : 0; + + if (!value) + { + // Not found; check if there's a default value + if (PyTuple_GET_SIZE(kv) > 1) + value = PyTuple_GET_ITEM(kv, 1); + + if (!value) + { + // still not found; matching fails + PyErr_Clear(); + inner_args = handle<>(); + break; + } + } + else + { + ++n_actual_processed; + } + + PyTuple_SET_ITEM(inner_args.get(), arg_pos, incref(value)); + } + + if (inner_args.get()) + { + //check if we proccessed all the arguments + if(n_actual_processed < n_actual) + inner_args = handle<>(); + } + } + } + } + + // Call the function. Pass keywords in case it's a + // function accepting any number of keywords + PyObject* result = inner_args ? f->m_fn(inner_args.get(), keywords) : 0; + + // If the result is NULL but no error was set, m_fn failed + // the argument-matching test. + + // This assumes that all other error-reporters are + // well-behaved and never return NULL to python without + // setting an error. + if (result != 0 || PyErr_Occurred()) + return result; + } + f = f->m_overloads.get(); + } + while (f); + // None of the overloads matched; time to generate the error message + argument_error(args, keywords); + return 0; +} + +object function::signature(bool show_return_type) const +{ + py_function const& impl = m_fn; + + python::detail::signature_element const* return_type = impl.signature(); + python::detail::signature_element const* s = return_type + 1; + + list formal_params; + if (impl.max_arity() == 0) + formal_params.append("void"); + + for (unsigned n = 0; n < impl.max_arity(); ++n) + { + if (s[n].basename == 0) + { + formal_params.append("..."); + break; + } + + str param(s[n].basename); + if (s[n].lvalue) + param += " {lvalue}"; + + if (m_arg_names) // None or empty tuple will test false + { + object kv(m_arg_names[n]); + if (kv) + { + char const* const fmt = len(kv) > 1 ? " %s=%r" : " %s"; + param += fmt % kv; + } + } + + formal_params.append(param); + } + + if (show_return_type) + return "%s(%s) -> %s" % make_tuple( + m_name, str(", ").join(formal_params), return_type->basename); + return "%s(%s)" % make_tuple( + m_name, str(", ").join(formal_params)); +} + +object function::signatures(bool show_return_type) const +{ + list result; + for (function const* f = this; f; f = f->m_overloads.get()) { + result.append(f->signature(show_return_type)); + } + return result; +} + +void function::argument_error(PyObject* args, PyObject* /*keywords*/) const +{ + static handle<> exception( + PyErr_NewException(const_cast<char*>("Boost.Python.ArgumentError"), PyExc_TypeError, 0)); + + object message = "Python argument types in\n %s.%s(" + % make_tuple(this->m_namespace, this->m_name); + + list actual_args; + for (ssize_t i = 0; i < PyTuple_Size(args); ++i) + { + char const* name = PyTuple_GetItem(args, i)->ob_type->tp_name; + actual_args.append(str(name)); + } + message += str(", ").join(actual_args); + message += ")\ndid not match C++ signature:\n "; + message += str("\n ").join(signatures()); + +#if BOOST_PYTHON_DEBUG_ERROR_MESSAGES + std::printf("\n--------\n%s\n--------\n", extract<const char*>(message)()); +#endif + PyErr_SetObject(exception.get(), message.ptr()); + throw_error_already_set(); +} + +void function::add_overload(handle<function> const& overload_) +{ + function* parent = this; + + while (parent->m_overloads) + parent = parent->m_overloads.get(); + + parent->m_overloads = overload_; + + // If we have no documentation, get the docs from the overload + if (!m_doc) + m_doc = overload_->m_doc; +} + +namespace +{ + char const* const binary_operator_names[] = + { + "add__", + "and__", + "div__", + "divmod__", + "eq__", + "floordiv__", + "ge__", + "gt__", + "le__", + "lshift__", + "lt__", + "mod__", + "mul__", + "ne__", + "or__", + "pow__", + "radd__", + "rand__", + "rdiv__", + "rdivmod__", + "rfloordiv__", + "rlshift__", + "rmod__", + "rmul__", + "ror__", + "rpow__", + "rrshift__", + "rshift__", + "rsub__", + "rtruediv__", + "rxor__", + "sub__", + "truediv__", + "xor__" + }; + + struct less_cstring + { + bool operator()(char const* x, char const* y) const + { + return BOOST_CSTD_::strcmp(x,y) < 0; + } + }; + + inline bool is_binary_operator(char const* name) + { + return name[0] == '_' + && name[1] == '_' + && std::binary_search( + &binary_operator_names[0] + , binary_operator_names + sizeof(binary_operator_names)/sizeof(*binary_operator_names) + , name + 2 + , less_cstring() + ); + } + + // Something for the end of the chain of binary operators + PyObject* not_implemented(PyObject*, PyObject*) + { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + + handle<function> not_implemented_function() + { + + static object keeper( + function_object( + py_function(¬_implemented, mpl::vector1<void>(), 2) + , python::detail::keyword_range()) + ); + return handle<function>(borrowed(downcast<function>(keeper.ptr()))); + } +} + +void function::add_to_namespace( + object const& name_space, char const* name_, object const& attribute) +{ + add_to_namespace(name_space, name_, attribute, 0); +} + +namespace detail +{ + extern char py_signature_tag[]; + extern char cpp_signature_tag[]; +} + +void function::add_to_namespace( + object const& name_space, char const* name_, object const& attribute, char const* doc) +{ + str const name(name_); + PyObject* const ns = name_space.ptr(); + + if (attribute.ptr()->ob_type == &function_type) + { + function* new_func = downcast<function>(attribute.ptr()); + handle<> dict; + +#if PY_VERSION_HEX < 0x03000000 + // Old-style class gone in Python 3 + if (PyClass_Check(ns)) + dict = handle<>(borrowed(((PyClassObject*)ns)->cl_dict)); + else +#endif + if (PyType_Check(ns)) + dict = handle<>(borrowed(((PyTypeObject*)ns)->tp_dict)); + else + dict = handle<>(PyObject_GetAttrString(ns, const_cast<char*>("__dict__"))); + + if (dict == 0) + throw_error_already_set(); + assert(!PyErr_Occurred()); - handle<> existing(allow_null(::PyObject_GetItem(dict.get(), name.ptr()))); + handle<> existing(allow_null(::PyObject_GetItem(dict.get(), name.ptr()))); PyErr_Clear(); - - if (existing) - { - if (existing->ob_type == &function_type) - { - new_func->add_overload( - handle<function>( - borrowed( - downcast<function>(existing.get()) - ) - ) - ); - } - else if (existing->ob_type == &PyStaticMethod_Type) - { - char const* name_space_name = extract<char const*>(name_space.attr("__name__")); - - ::PyErr_Format( - PyExc_RuntimeError - , "Boost.Python - All overloads must be exported " - "before calling \'class_<...>(\"%s\").staticmethod(\"%s\")\'" - , name_space_name - , name_ - ); - throw_error_already_set(); - } - } - else if (is_binary_operator(name_)) - { - // Binary operators need an additional overload which - // returns NotImplemented, so that Python will try the - // __rxxx__ functions on the other operand. We add this - // when no overloads for the operator already exist. - new_func->add_overload(not_implemented_function()); - } - - // A function is named the first time it is added to a namespace. - if (new_func->name().is_none()) - new_func->m_name = name; - + + if (existing) + { + if (existing->ob_type == &function_type) + { + new_func->add_overload( + handle<function>( + borrowed( + downcast<function>(existing.get()) + ) + ) + ); + } + else if (existing->ob_type == &PyStaticMethod_Type) + { + char const* name_space_name = extract<char const*>(name_space.attr("__name__")); + + ::PyErr_Format( + PyExc_RuntimeError + , "Boost.Python - All overloads must be exported " + "before calling \'class_<...>(\"%s\").staticmethod(\"%s\")\'" + , name_space_name + , name_ + ); + throw_error_already_set(); + } + } + else if (is_binary_operator(name_)) + { + // Binary operators need an additional overload which + // returns NotImplemented, so that Python will try the + // __rxxx__ functions on the other operand. We add this + // when no overloads for the operator already exist. + new_func->add_overload(not_implemented_function()); + } + + // A function is named the first time it is added to a namespace. + if (new_func->name().is_none()) + new_func->m_name = name; + assert(!PyErr_Occurred()); - handle<> name_space_name( - allow_null(::PyObject_GetAttrString(name_space.ptr(), const_cast<char*>("__name__")))); + handle<> name_space_name( + allow_null(::PyObject_GetAttrString(name_space.ptr(), const_cast<char*>("__name__")))); PyErr_Clear(); - - if (name_space_name) - new_func->m_namespace = object(name_space_name); - } - - if (PyObject_SetAttr(ns, name.ptr(), attribute.ptr()) < 0) - throw_error_already_set(); - - object mutable_attribute(attribute); -/* - if (doc != 0 && docstring_options::show_user_defined_) - { - // Accumulate documentation - - if ( - PyObject_HasAttrString(mutable_attribute.ptr(), "__doc__") - && mutable_attribute.attr("__doc__")) - { - mutable_attribute.attr("__doc__") += "\n\n"; - mutable_attribute.attr("__doc__") += doc; - } - else { - mutable_attribute.attr("__doc__") = doc; - } - } - - if (docstring_options::show_signatures_) - { - if ( PyObject_HasAttrString(mutable_attribute.ptr(), "__doc__") - && mutable_attribute.attr("__doc__")) { - mutable_attribute.attr("__doc__") += ( - mutable_attribute.attr("__doc__")[-1] != "\n" ? "\n\n" : "\n"); - } - else { - mutable_attribute.attr("__doc__") = ""; - } - function* f = downcast<function>(attribute.ptr()); - mutable_attribute.attr("__doc__") += str("\n ").join(make_tuple( - "C++ signature:", f->signature(true))); - } - */ - str _doc; - - if (docstring_options::show_py_signatures_) - { - _doc += str(const_cast<const char*>(detail::py_signature_tag)); - } - if (doc != 0 && docstring_options::show_user_defined_) - _doc += doc; - - if (docstring_options::show_cpp_signatures_) - { - _doc += str(const_cast<const char*>(detail::cpp_signature_tag)); - } - if(_doc) - { - object mutable_attribute(attribute); - mutable_attribute.attr("__doc__")= _doc; - } -} - -BOOST_PYTHON_DECL void add_to_namespace( - object const& name_space, char const* name, object const& attribute) -{ - function::add_to_namespace(name_space, name, attribute, 0); -} - -BOOST_PYTHON_DECL void add_to_namespace( - object const& name_space, char const* name, object const& attribute, char const* doc) -{ - function::add_to_namespace(name_space, name, attribute, doc); -} - - -namespace -{ - struct bind_return - { - bind_return(PyObject*& result, function const* f, PyObject* args, PyObject* keywords) - : m_result(result) - , m_f(f) - , m_args(args) - , m_keywords(keywords) - {} - - void operator()() const - { - m_result = m_f->call(m_args, m_keywords); - } - - private: - PyObject*& m_result; - function const* m_f; - PyObject* m_args; - PyObject* m_keywords; - }; -} - -extern "C" -{ - // Stolen from Python's funcobject.c - static PyObject * - function_descr_get(PyObject *func, PyObject *obj, PyObject *type_) - { -#if PY_VERSION_HEX >= 0x03000000 - // The implement is different in Python 3 because of the removal of unbound method - if (obj == Py_None || obj == NULL) { - Py_INCREF(func); - return func; - } - return PyMethod_New(func, obj); -#else - if (obj == Py_None) - obj = NULL; - return PyMethod_New(func, obj, type_); -#endif - } - - static void - function_dealloc(PyObject* p) - { - delete static_cast<function*>(p); - } - - static PyObject * - function_call(PyObject *func, PyObject *args, PyObject *kw) - { - PyObject* result = 0; - handle_exception(bind_return(result, static_cast<function*>(func), args, kw)); - return result; - } - - // - // Here we're using the function's tp_getset rather than its - // tp_members to set up __doc__ and __name__, because tp_members - // really depends on having a POD object type (it relies on - // offsets). It might make sense to reformulate function as a POD - // at some point, but this is much more expedient. - // - static PyObject* function_get_doc(PyObject* op, void*) - { - function* f = downcast<function>(op); - list signatures = function_doc_signature_generator::function_doc_signatures(f); - if(!signatures) return python::detail::none(); - signatures.reverse(); - return python::incref( str("\n").join(signatures).ptr()); - } - - static int function_set_doc(PyObject* op, PyObject* doc, void*) - { - function* f = downcast<function>(op); - f->doc(doc ? object(python::detail::borrowed_reference(doc)) : object()); - return 0; - } - - static PyObject* function_get_name(PyObject* op, void*) - { - function* f = downcast<function>(op); - if (f->name().is_none()) -#if PY_VERSION_HEX >= 0x03000000 - return PyUnicode_InternFromString("<unnamed Boost.Python function>"); -#else - return PyString_InternFromString("<unnamed Boost.Python function>"); -#endif - else - return python::incref(f->name().ptr()); - } - - // We add a dummy __class__ attribute in order to fool PyDoc into - // treating these as built-in functions and scanning their - // documentation - static PyObject* function_get_class(PyObject* /*op*/, void*) - { - return python::incref(upcast<PyObject>(&PyCFunction_Type)); - } - - static PyObject* function_get_module(PyObject* op, void*) - { - function* f = downcast<function>(op); - object const& ns = f->get_namespace(); - if (!ns.is_none()) { - return python::incref(ns.ptr()); - } - PyErr_SetString( - PyExc_AttributeError, const_cast<char*>( - "Boost.Python function __module__ unknown.")); - return 0; - } -} - -static PyGetSetDef function_getsetlist[] = { - {const_cast<char*>("__name__"), (getter)function_get_name, 0, 0, 0 }, - {const_cast<char*>("func_name"), (getter)function_get_name, 0, 0, 0 }, - {const_cast<char*>("__module__"), (getter)function_get_module, 0, 0, 0 }, - {const_cast<char*>("func_module"), (getter)function_get_module, 0, 0, 0 }, - {const_cast<char*>("__class__"), (getter)function_get_class, 0, 0, 0 }, // see note above - {const_cast<char*>("__doc__"), (getter)function_get_doc, (setter)function_set_doc, 0, 0}, - {const_cast<char*>("func_doc"), (getter)function_get_doc, (setter)function_set_doc, 0, 0}, - {NULL, 0, 0, 0, 0} /* Sentinel */ -}; - -PyTypeObject function_type = { - PyVarObject_HEAD_INIT(NULL, 0) - const_cast<char*>("Boost.Python.function"), - sizeof(function), - 0, - (destructor)function_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - 0, //(reprfunc)func_repr, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - function_call, /* tp_call */ - 0, /* tp_str */ - 0, // PyObject_GenericGetAttr, /* tp_getattro */ - 0, // PyObject_GenericSetAttr, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT /* | Py_TPFLAGS_HAVE_GC */,/* tp_flags */ - 0, /* tp_doc */ - 0, // (traverseproc)func_traverse, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, //offsetof(PyFunctionObject, func_weakreflist), /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - 0, /* tp_methods */ - 0, // func_memberlist, /* tp_members */ - function_getsetlist, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - function_descr_get, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, //offsetof(PyFunctionObject, func_dict), /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - 0, /* tp_new */ - 0, /* tp_free */ - 0, /* tp_is_gc */ - 0, /* tp_bases */ - 0, /* tp_mro */ - 0, /* tp_cache */ - 0, /* tp_subclasses */ - 0, /* tp_weaklist */ -#if PYTHON_API_VERSION >= 1012 - 0 /* tp_del */ -#endif -}; - -object function_object( - py_function const& f - , python::detail::keyword_range const& keywords) -{ - return python::object( - python::detail::new_non_null_reference( - new function( - f, keywords.first, keywords.second - keywords.first))); -} - -object function_object(py_function const& f) -{ - return function_object(f, python::detail::keyword_range()); -} - - -handle<> function_handle_impl(py_function const& f) -{ - return python::handle<>( - allow_null( - new function(f, 0, 0))); -} - -} // namespace objects - -namespace detail -{ - object BOOST_PYTHON_DECL make_raw_function(objects::py_function f) - { - static keyword k; - - return objects::function_object( - f - , keyword_range(&k,&k)); - } - void BOOST_PYTHON_DECL pure_virtual_called() - { - PyErr_SetString( - PyExc_RuntimeError, const_cast<char*>("Pure virtual function called")); - throw_error_already_set(); - } -} - -}} // namespace boost::python + + if (name_space_name) + new_func->m_namespace = object(name_space_name); + } + + if (PyObject_SetAttr(ns, name.ptr(), attribute.ptr()) < 0) + throw_error_already_set(); + + object mutable_attribute(attribute); +/* + if (doc != 0 && docstring_options::show_user_defined_) + { + // Accumulate documentation + + if ( + PyObject_HasAttrString(mutable_attribute.ptr(), "__doc__") + && mutable_attribute.attr("__doc__")) + { + mutable_attribute.attr("__doc__") += "\n\n"; + mutable_attribute.attr("__doc__") += doc; + } + else { + mutable_attribute.attr("__doc__") = doc; + } + } + + if (docstring_options::show_signatures_) + { + if ( PyObject_HasAttrString(mutable_attribute.ptr(), "__doc__") + && mutable_attribute.attr("__doc__")) { + mutable_attribute.attr("__doc__") += ( + mutable_attribute.attr("__doc__")[-1] != "\n" ? "\n\n" : "\n"); + } + else { + mutable_attribute.attr("__doc__") = ""; + } + function* f = downcast<function>(attribute.ptr()); + mutable_attribute.attr("__doc__") += str("\n ").join(make_tuple( + "C++ signature:", f->signature(true))); + } + */ + str _doc; + + if (docstring_options::show_py_signatures_) + { + _doc += str(const_cast<const char*>(detail::py_signature_tag)); + } + if (doc != 0 && docstring_options::show_user_defined_) + _doc += doc; + + if (docstring_options::show_cpp_signatures_) + { + _doc += str(const_cast<const char*>(detail::cpp_signature_tag)); + } + if(_doc) + { + object mutable_attribute(attribute); + mutable_attribute.attr("__doc__")= _doc; + } +} + +BOOST_PYTHON_DECL void add_to_namespace( + object const& name_space, char const* name, object const& attribute) +{ + function::add_to_namespace(name_space, name, attribute, 0); +} + +BOOST_PYTHON_DECL void add_to_namespace( + object const& name_space, char const* name, object const& attribute, char const* doc) +{ + function::add_to_namespace(name_space, name, attribute, doc); +} + + +namespace +{ + struct bind_return + { + bind_return(PyObject*& result, function const* f, PyObject* args, PyObject* keywords) + : m_result(result) + , m_f(f) + , m_args(args) + , m_keywords(keywords) + {} + + void operator()() const + { + m_result = m_f->call(m_args, m_keywords); + } + + private: + PyObject*& m_result; + function const* m_f; + PyObject* m_args; + PyObject* m_keywords; + }; +} + +extern "C" +{ + // Stolen from Python's funcobject.c + static PyObject * + function_descr_get(PyObject *func, PyObject *obj, PyObject *type_) + { +#if PY_VERSION_HEX >= 0x03000000 + // The implement is different in Python 3 because of the removal of unbound method + if (obj == Py_None || obj == NULL) { + Py_INCREF(func); + return func; + } + return PyMethod_New(func, obj); +#else + if (obj == Py_None) + obj = NULL; + return PyMethod_New(func, obj, type_); +#endif + } + + static void + function_dealloc(PyObject* p) + { + delete static_cast<function*>(p); + } + + static PyObject * + function_call(PyObject *func, PyObject *args, PyObject *kw) + { + PyObject* result = 0; + handle_exception(bind_return(result, static_cast<function*>(func), args, kw)); + return result; + } + + // + // Here we're using the function's tp_getset rather than its + // tp_members to set up __doc__ and __name__, because tp_members + // really depends on having a POD object type (it relies on + // offsets). It might make sense to reformulate function as a POD + // at some point, but this is much more expedient. + // + static PyObject* function_get_doc(PyObject* op, void*) + { + function* f = downcast<function>(op); + list signatures = function_doc_signature_generator::function_doc_signatures(f); + if(!signatures) return python::detail::none(); + signatures.reverse(); + return python::incref( str("\n").join(signatures).ptr()); + } + + static int function_set_doc(PyObject* op, PyObject* doc, void*) + { + function* f = downcast<function>(op); + f->doc(doc ? object(python::detail::borrowed_reference(doc)) : object()); + return 0; + } + + static PyObject* function_get_name(PyObject* op, void*) + { + function* f = downcast<function>(op); + if (f->name().is_none()) +#if PY_VERSION_HEX >= 0x03000000 + return PyUnicode_InternFromString("<unnamed Boost.Python function>"); +#else + return PyString_InternFromString("<unnamed Boost.Python function>"); +#endif + else + return python::incref(f->name().ptr()); + } + + // We add a dummy __class__ attribute in order to fool PyDoc into + // treating these as built-in functions and scanning their + // documentation + static PyObject* function_get_class(PyObject* /*op*/, void*) + { + return python::incref(upcast<PyObject>(&PyCFunction_Type)); + } + + static PyObject* function_get_module(PyObject* op, void*) + { + function* f = downcast<function>(op); + object const& ns = f->get_namespace(); + if (!ns.is_none()) { + return python::incref(ns.ptr()); + } + PyErr_SetString( + PyExc_AttributeError, const_cast<char*>( + "Boost.Python function __module__ unknown.")); + return 0; + } +} + +static PyGetSetDef function_getsetlist[] = { + {const_cast<char*>("__name__"), (getter)function_get_name, 0, 0, 0 }, + {const_cast<char*>("func_name"), (getter)function_get_name, 0, 0, 0 }, + {const_cast<char*>("__module__"), (getter)function_get_module, 0, 0, 0 }, + {const_cast<char*>("func_module"), (getter)function_get_module, 0, 0, 0 }, + {const_cast<char*>("__class__"), (getter)function_get_class, 0, 0, 0 }, // see note above + {const_cast<char*>("__doc__"), (getter)function_get_doc, (setter)function_set_doc, 0, 0}, + {const_cast<char*>("func_doc"), (getter)function_get_doc, (setter)function_set_doc, 0, 0}, + {NULL, 0, 0, 0, 0} /* Sentinel */ +}; + +PyTypeObject function_type = { + PyVarObject_HEAD_INIT(NULL, 0) + const_cast<char*>("Boost.Python.function"), + sizeof(function), + 0, + (destructor)function_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, //(reprfunc)func_repr, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + function_call, /* tp_call */ + 0, /* tp_str */ + 0, // PyObject_GenericGetAttr, /* tp_getattro */ + 0, // PyObject_GenericSetAttr, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT /* | Py_TPFLAGS_HAVE_GC */,/* tp_flags */ + 0, /* tp_doc */ + 0, // (traverseproc)func_traverse, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, //offsetof(PyFunctionObject, func_weakreflist), /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, // func_memberlist, /* tp_members */ + function_getsetlist, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + function_descr_get, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, //offsetof(PyFunctionObject, func_dict), /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + 0, /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ +#if PYTHON_API_VERSION >= 1012 + 0 /* tp_del */ +#endif +}; + +object function_object( + py_function const& f + , python::detail::keyword_range const& keywords) +{ + return python::object( + python::detail::new_non_null_reference( + new function( + f, keywords.first, keywords.second - keywords.first))); +} + +object function_object(py_function const& f) +{ + return function_object(f, python::detail::keyword_range()); +} + + +handle<> function_handle_impl(py_function const& f) +{ + return python::handle<>( + allow_null( + new function(f, 0, 0))); +} + +} // namespace objects + +namespace detail +{ + object BOOST_PYTHON_DECL make_raw_function(objects::py_function f) + { + static keyword k; + + return objects::function_object( + f + , keyword_range(&k,&k)); + } + void BOOST_PYTHON_DECL pure_virtual_called() + { + PyErr_SetString( + PyExc_RuntimeError, const_cast<char*>("Pure virtual function called")); + throw_error_already_set(); + } +} + +}} // namespace boost::python |