Back to home page

EIC code displayed by LXR

 
 

    


Warning, file /include/pybind11/functional.h was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

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