111986Sandreas.sandberg@arm.com/* 211986Sandreas.sandberg@arm.com pybind11/functional.h: std::function<> support 311986Sandreas.sandberg@arm.com 411986Sandreas.sandberg@arm.com Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch> 511986Sandreas.sandberg@arm.com 611986Sandreas.sandberg@arm.com All rights reserved. Use of this source code is governed by a 711986Sandreas.sandberg@arm.com BSD-style license that can be found in the LICENSE file. 811986Sandreas.sandberg@arm.com*/ 911986Sandreas.sandberg@arm.com 1011986Sandreas.sandberg@arm.com#pragma once 1111986Sandreas.sandberg@arm.com 1211986Sandreas.sandberg@arm.com#include "pybind11.h" 1311986Sandreas.sandberg@arm.com#include <functional> 1411986Sandreas.sandberg@arm.com 1512391Sjason@lowepower.comNAMESPACE_BEGIN(PYBIND11_NAMESPACE) 1611986Sandreas.sandberg@arm.comNAMESPACE_BEGIN(detail) 1711986Sandreas.sandberg@arm.com 1812037Sandreas.sandberg@arm.comtemplate <typename Return, typename... Args> 1912037Sandreas.sandberg@arm.comstruct type_caster<std::function<Return(Args...)>> { 2012037Sandreas.sandberg@arm.com using type = std::function<Return(Args...)>; 2112037Sandreas.sandberg@arm.com using retval_type = conditional_t<std::is_same<Return, void>::value, void_type, Return>; 2212037Sandreas.sandberg@arm.com using function_type = Return (*) (Args...); 2312037Sandreas.sandberg@arm.com 2411986Sandreas.sandberg@arm.compublic: 2512391Sjason@lowepower.com bool load(handle src, bool convert) { 2612391Sjason@lowepower.com if (src.is_none()) { 2712391Sjason@lowepower.com // Defer accepting None to other overloads (if we aren't in convert mode): 2812391Sjason@lowepower.com if (!convert) return false; 2911986Sandreas.sandberg@arm.com return true; 3012391Sjason@lowepower.com } 3111986Sandreas.sandberg@arm.com 3212391Sjason@lowepower.com if (!isinstance<function>(src)) 3311986Sandreas.sandberg@arm.com return false; 3411986Sandreas.sandberg@arm.com 3512391Sjason@lowepower.com auto func = reinterpret_borrow<function>(src); 3612391Sjason@lowepower.com 3711986Sandreas.sandberg@arm.com /* 3811986Sandreas.sandberg@arm.com When passing a C++ function as an argument to another C++ 3911986Sandreas.sandberg@arm.com function via Python, every function call would normally involve 4011986Sandreas.sandberg@arm.com a full C++ -> Python -> C++ roundtrip, which can be prohibitive. 4111986Sandreas.sandberg@arm.com Here, we try to at least detect the case where the function is 4211986Sandreas.sandberg@arm.com stateless (i.e. function pointer or lambda function without 4311986Sandreas.sandberg@arm.com captured variables), in which case the roundtrip can be avoided. 4411986Sandreas.sandberg@arm.com */ 4512391Sjason@lowepower.com if (auto cfunc = func.cpp_function()) { 4612391Sjason@lowepower.com auto c = reinterpret_borrow<capsule>(PyCFunction_GET_SELF(cfunc.ptr())); 4711986Sandreas.sandberg@arm.com auto rec = (function_record *) c; 4811986Sandreas.sandberg@arm.com 4912391Sjason@lowepower.com if (rec && rec->is_stateless && 5012391Sjason@lowepower.com same_type(typeid(function_type), *reinterpret_cast<const std::type_info *>(rec->data[1]))) { 5112037Sandreas.sandberg@arm.com struct capture { function_type f; }; 5211986Sandreas.sandberg@arm.com value = ((capture *) &rec->data)->f; 5311986Sandreas.sandberg@arm.com return true; 5411986Sandreas.sandberg@arm.com } 5511986Sandreas.sandberg@arm.com } 5611986Sandreas.sandberg@arm.com 5714299Sbbruce@ucdavis.edu // ensure GIL is held during functor destruction 5814299Sbbruce@ucdavis.edu struct func_handle { 5914299Sbbruce@ucdavis.edu function f; 6014299Sbbruce@ucdavis.edu func_handle(function&& f_) : f(std::move(f_)) {} 6114299Sbbruce@ucdavis.edu func_handle(const func_handle&) = default; 6214299Sbbruce@ucdavis.edu ~func_handle() { 6314299Sbbruce@ucdavis.edu gil_scoped_acquire acq; 6414299Sbbruce@ucdavis.edu function kill_f(std::move(f)); 6514299Sbbruce@ucdavis.edu } 6611986Sandreas.sandberg@arm.com }; 6714299Sbbruce@ucdavis.edu 6814299Sbbruce@ucdavis.edu // to emulate 'move initialization capture' in C++11 6914299Sbbruce@ucdavis.edu struct func_wrapper { 7014299Sbbruce@ucdavis.edu func_handle hfunc; 7114299Sbbruce@ucdavis.edu func_wrapper(func_handle&& hf): hfunc(std::move(hf)) {} 7214299Sbbruce@ucdavis.edu Return operator()(Args... args) const { 7314299Sbbruce@ucdavis.edu gil_scoped_acquire acq; 7414299Sbbruce@ucdavis.edu object retval(hfunc.f(std::forward<Args>(args)...)); 7514299Sbbruce@ucdavis.edu /* Visual studio 2015 parser issue: need parentheses around this expression */ 7614299Sbbruce@ucdavis.edu return (retval.template cast<Return>()); 7714299Sbbruce@ucdavis.edu } 7814299Sbbruce@ucdavis.edu }; 7914299Sbbruce@ucdavis.edu 8014299Sbbruce@ucdavis.edu value = func_wrapper(func_handle(std::move(func))); 8111986Sandreas.sandberg@arm.com return true; 8211986Sandreas.sandberg@arm.com } 8311986Sandreas.sandberg@arm.com 8411986Sandreas.sandberg@arm.com template <typename Func> 8511986Sandreas.sandberg@arm.com static handle cast(Func &&f_, return_value_policy policy, handle /* parent */) { 8611986Sandreas.sandberg@arm.com if (!f_) 8711986Sandreas.sandberg@arm.com return none().inc_ref(); 8811986Sandreas.sandberg@arm.com 8912037Sandreas.sandberg@arm.com auto result = f_.template target<function_type>(); 9011986Sandreas.sandberg@arm.com if (result) 9111986Sandreas.sandberg@arm.com return cpp_function(*result, policy).release(); 9211986Sandreas.sandberg@arm.com else 9311986Sandreas.sandberg@arm.com return cpp_function(std::forward<Func>(f_), policy).release(); 9411986Sandreas.sandberg@arm.com } 9511986Sandreas.sandberg@arm.com 9614299Sbbruce@ucdavis.edu PYBIND11_TYPE_CASTER(type, _("Callable[[") + concat(make_caster<Args>::name...) + _("], ") 9714299Sbbruce@ucdavis.edu + make_caster<retval_type>::name + _("]")); 9811986Sandreas.sandberg@arm.com}; 9911986Sandreas.sandberg@arm.com 10011986Sandreas.sandberg@arm.comNAMESPACE_END(detail) 10112391Sjason@lowepower.comNAMESPACE_END(PYBIND11_NAMESPACE) 102