Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 10:17:47

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