File indexing completed on 2025-02-16 05:12:16

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 #include <functional>
0014 
0015 PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
0016 PYBIND11_NAMESPACE_BEGIN(detail)
0017 
0018 template <typename Return, typename... Args>
0019 struct type_caster<std::function<Return(Args...)>> {
0020     using type = std::function<Return(Args...)>;
0021     using retval_type = conditional_t<std::is_same<Return, void>::value, void_type, Return>;
0022     using function_type = Return (*) (Args...);
0023 
0024 public:
0025     bool load(handle src, bool convert) {
0026         if (src.is_none()) {
0027             // Defer accepting None to other overloads (if we aren't in convert mode):
0028             if (!convert) return false;
0029             return true;
0030         }
0031 
0032         if (!isinstance<function>(src))
0033             return false;
0034 
0035         auto func = reinterpret_borrow<function>(src);
0036 
0037         /*
0038            When passing a C++ function as an argument to another C++
0039            function via Python, every function call would normally involve
0040            a full C++ -> Python -> C++ roundtrip, which can be prohibitive.
0041            Here, we try to at least detect the case where the function is
0042            stateless (i.e. function pointer or lambda function without
0043            captured variables), in which case the roundtrip can be avoided.
0044          */
0045         if (auto cfunc = func.cpp_function()) {
0046             auto cfunc_self = PyCFunction_GET_SELF(cfunc.ptr());
0047             if (isinstance<capsule>(cfunc_self)) {
0048                 auto c = reinterpret_borrow<capsule>(cfunc_self);
0049                 auto rec = (function_record *) c;
0050 
0051                 while (rec != nullptr) {
0052                     if (rec->is_stateless
0053                         && same_type(typeid(function_type),
0054                                      *reinterpret_cast<const std::type_info *>(rec->data[1]))) {
0055                         struct capture {
0056                             function_type f;
0057                         };
0058                         value = ((capture *) &rec->data)->f;
0059                         return true;
0060                     }
0061                     rec = rec->next;
0062                 }
0063             }
0064             // PYPY segfaults here when passing builtin function like sum.
0065             // Raising an fail exception here works to prevent the segfault, but only on gcc.
0066             // See PR #1413 for full details
0067         }
0068 
0069         // ensure GIL is held during functor destruction
0070         struct func_handle {
0071             function f;
0072 #if !(defined(_MSC_VER) && _MSC_VER == 1916 && defined(PYBIND11_CPP17))
0073             // This triggers a syntax error under very special conditions (very weird indeed).
0074             explicit
0075 #endif
0076             func_handle(function &&f_) noexcept : f(std::move(f_)) {}
0077             func_handle(const func_handle &f_) { operator=(f_); }
0078             func_handle &operator=(const func_handle &f_) {
0079                 gil_scoped_acquire acq;
0080                 f = f_.f;
0081                 return *this;
0082             }
0083             ~func_handle() {
0084                 gil_scoped_acquire acq;
0085                 function kill_f(std::move(f));
0086             }
0087         };
0088 
0089         // to emulate 'move initialization capture' in C++11
0090         struct func_wrapper {
0091             func_handle hfunc;
0092             explicit func_wrapper(func_handle &&hf) noexcept : hfunc(std::move(hf)) {}
0093             Return operator()(Args... args) const {
0094                 gil_scoped_acquire acq;
0095                 object retval(hfunc.f(std::forward<Args>(args)...));
0096                 /* Visual studio 2015 parser issue: need parentheses around this expression */
0097                 return (retval.template cast<Return>());
0098             }
0099         };
0100 
0101         value = func_wrapper(func_handle(std::move(func)));
0102         return true;
0103     }
0104 
0105     template <typename Func>
0106     static handle cast(Func &&f_, return_value_policy policy, handle /* parent */) {
0107         if (!f_)
0108             return none().inc_ref();
0109 
0110         auto result = f_.template target<function_type>();
0111         if (result)
0112             return cpp_function(*result, policy).release();
0113         return cpp_function(std::forward<Func>(f_), policy).release();
0114     }
0115 
0116     PYBIND11_TYPE_CASTER(type, const_name("Callable[[") + concat(make_caster<Args>::name...) + const_name("], ")
0117                                + make_caster<retval_type>::name + const_name("]"));
0118 };
0119 
0120 PYBIND11_NAMESPACE_END(detail)
0121 PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)