Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-01-08 10:22:54

0001 /*
0002     pybind11/functional.h: std::function<> support
0003 
0004     Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
0005 
0006     All rights reserved. Use of this source code is governed by a
0007     BSD-style license that can be found in the LICENSE file.
0008 */
0009 
0010 #pragma once
0011 
0012 #include "pybind11.h"
0013 
0014 #include <functional>
0015 
0016 PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
0017 PYBIND11_NAMESPACE_BEGIN(detail)
0018 PYBIND11_NAMESPACE_BEGIN(type_caster_std_function_specializations)
0019 
0020 // ensure GIL is held during functor destruction
0021 struct func_handle {
0022     function f;
0023 #if !(defined(_MSC_VER) && _MSC_VER == 1916 && defined(PYBIND11_CPP17))
0024     // This triggers a syntax error under very special conditions (very weird indeed).
0025     explicit
0026 #endif
0027         func_handle(function &&f_) noexcept
0028         : f(std::move(f_)) {
0029     }
0030     func_handle(const func_handle &f_) { operator=(f_); }
0031     func_handle &operator=(const func_handle &f_) {
0032         gil_scoped_acquire acq;
0033         f = f_.f;
0034         return *this;
0035     }
0036     ~func_handle() {
0037         gil_scoped_acquire acq;
0038         function kill_f(std::move(f));
0039     }
0040 };
0041 
0042 // to emulate 'move initialization capture' in C++11
0043 struct func_wrapper_base {
0044     func_handle hfunc;
0045     explicit func_wrapper_base(func_handle &&hf) noexcept : hfunc(hf) {}
0046 };
0047 
0048 template <typename Return, typename... Args>
0049 struct func_wrapper : func_wrapper_base {
0050     using func_wrapper_base::func_wrapper_base;
0051     Return operator()(Args... args) const { // NOLINT(performance-unnecessary-value-param)
0052         gil_scoped_acquire acq;
0053         // casts the returned object as a rvalue to the return type
0054         return hfunc.f(std::forward<Args>(args)...).template cast<Return>();
0055     }
0056 };
0057 
0058 PYBIND11_NAMESPACE_END(type_caster_std_function_specializations)
0059 
0060 template <typename Return, typename... Args>
0061 struct type_caster<std::function<Return(Args...)>> {
0062     using type = std::function<Return(Args...)>;
0063     using retval_type = conditional_t<std::is_same<Return, void>::value, void_type, Return>;
0064     using function_type = Return (*)(Args...);
0065 
0066 public:
0067     bool load(handle src, bool convert) {
0068         if (src.is_none()) {
0069             // Defer accepting None to other overloads (if we aren't in convert mode):
0070             if (!convert) {
0071                 return false;
0072             }
0073             return true;
0074         }
0075 
0076         if (!isinstance<function>(src)) {
0077             return false;
0078         }
0079 
0080         auto func = reinterpret_borrow<function>(src);
0081 
0082         /*
0083            When passing a C++ function as an argument to another C++
0084            function via Python, every function call would normally involve
0085            a full C++ -> Python -> C++ roundtrip, which can be prohibitive.
0086            Here, we try to at least detect the case where the function is
0087            stateless (i.e. function pointer or lambda function without
0088            captured variables), in which case the roundtrip can be avoided.
0089          */
0090         if (auto cfunc = func.cpp_function()) {
0091             auto *cfunc_self = PyCFunction_GET_SELF(cfunc.ptr());
0092             if (cfunc_self == nullptr) {
0093                 PyErr_Clear();
0094             } else {
0095                 function_record *rec = function_record_ptr_from_PyObject(cfunc_self);
0096                 while (rec != nullptr) {
0097                     if (rec->is_stateless
0098                         && same_type(typeid(function_type),
0099                                      *reinterpret_cast<const std::type_info *>(rec->data[1]))) {
0100                         struct capture {
0101                             function_type f;
0102 
0103                             static capture *from_data(void **data) {
0104                                 return PYBIND11_STD_LAUNDER(reinterpret_cast<capture *>(data));
0105                             }
0106                         };
0107                         PYBIND11_ENSURE_PRECONDITION_FOR_FUNCTIONAL_H_PERFORMANCE_OPTIMIZATIONS(
0108                             std::is_standard_layout<capture>::value);
0109                         value = capture::from_data(rec->data)->f;
0110                         return true;
0111                     }
0112                     rec = rec->next;
0113                 }
0114             }
0115             // PYPY segfaults here when passing builtin function like sum.
0116             // Raising an fail exception here works to prevent the segfault, but only on gcc.
0117             // See PR #1413 for full details
0118         }
0119 
0120         value = type_caster_std_function_specializations::func_wrapper<Return, Args...>(
0121             type_caster_std_function_specializations::func_handle(std::move(func)));
0122         return true;
0123     }
0124 
0125     template <typename Func>
0126     static handle cast(Func &&f_, return_value_policy policy, handle /* parent */) {
0127         if (!f_) {
0128             return none().release();
0129         }
0130 
0131         auto result = f_.template target<function_type>();
0132         if (result) {
0133             return cpp_function(*result, policy).release();
0134         }
0135         return cpp_function(std::forward<Func>(f_), policy).release();
0136     }
0137 
0138     PYBIND11_TYPE_CASTER(
0139         type,
0140         const_name("collections.abc.Callable[[")
0141             + ::pybind11::detail::concat(::pybind11::detail::arg_descr(make_caster<Args>::name)...)
0142             + const_name("], ") + ::pybind11::detail::return_descr(make_caster<retval_type>::name)
0143             + const_name("]"));
0144 };
0145 
0146 PYBIND11_NAMESPACE_END(detail)
0147 PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)