functional.h revision 12037
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 1511986Sandreas.sandberg@arm.comNAMESPACE_BEGIN(pybind11) 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: 2511986Sandreas.sandberg@arm.com bool load(handle src_, bool) { 2611986Sandreas.sandberg@arm.com if (src_.is_none()) 2711986Sandreas.sandberg@arm.com return true; 2811986Sandreas.sandberg@arm.com 2911986Sandreas.sandberg@arm.com src_ = detail::get_function(src_); 3011986Sandreas.sandberg@arm.com if (!src_ || !PyCallable_Check(src_.ptr())) 3111986Sandreas.sandberg@arm.com return false; 3211986Sandreas.sandberg@arm.com 3311986Sandreas.sandberg@arm.com /* 3411986Sandreas.sandberg@arm.com When passing a C++ function as an argument to another C++ 3511986Sandreas.sandberg@arm.com function via Python, every function call would normally involve 3611986Sandreas.sandberg@arm.com a full C++ -> Python -> C++ roundtrip, which can be prohibitive. 3711986Sandreas.sandberg@arm.com Here, we try to at least detect the case where the function is 3811986Sandreas.sandberg@arm.com stateless (i.e. function pointer or lambda function without 3911986Sandreas.sandberg@arm.com captured variables), in which case the roundtrip can be avoided. 4011986Sandreas.sandberg@arm.com */ 4111986Sandreas.sandberg@arm.com if (PyCFunction_Check(src_.ptr())) { 4212037Sandreas.sandberg@arm.com auto c = reinterpret_borrow<capsule>(PyCFunction_GET_SELF(src_.ptr())); 4311986Sandreas.sandberg@arm.com auto rec = (function_record *) c; 4411986Sandreas.sandberg@arm.com 4512037Sandreas.sandberg@arm.com if (rec && rec->is_stateless && rec->data[1] == &typeid(function_type)) { 4612037Sandreas.sandberg@arm.com struct capture { function_type f; }; 4711986Sandreas.sandberg@arm.com value = ((capture *) &rec->data)->f; 4811986Sandreas.sandberg@arm.com return true; 4911986Sandreas.sandberg@arm.com } 5011986Sandreas.sandberg@arm.com } 5111986Sandreas.sandberg@arm.com 5211986Sandreas.sandberg@arm.com auto src = reinterpret_borrow<object>(src_); 5311986Sandreas.sandberg@arm.com value = [src](Args... args) -> Return { 5411986Sandreas.sandberg@arm.com gil_scoped_acquire acq; 5512037Sandreas.sandberg@arm.com object retval(src(std::forward<Args>(args)...)); 5611986Sandreas.sandberg@arm.com /* Visual studio 2015 parser issue: need parentheses around this expression */ 5711986Sandreas.sandberg@arm.com return (retval.template cast<Return>()); 5811986Sandreas.sandberg@arm.com }; 5911986Sandreas.sandberg@arm.com return true; 6011986Sandreas.sandberg@arm.com } 6111986Sandreas.sandberg@arm.com 6211986Sandreas.sandberg@arm.com template <typename Func> 6311986Sandreas.sandberg@arm.com static handle cast(Func &&f_, return_value_policy policy, handle /* parent */) { 6411986Sandreas.sandberg@arm.com if (!f_) 6511986Sandreas.sandberg@arm.com return none().inc_ref(); 6611986Sandreas.sandberg@arm.com 6712037Sandreas.sandberg@arm.com auto result = f_.template target<function_type>(); 6811986Sandreas.sandberg@arm.com if (result) 6911986Sandreas.sandberg@arm.com return cpp_function(*result, policy).release(); 7011986Sandreas.sandberg@arm.com else 7111986Sandreas.sandberg@arm.com return cpp_function(std::forward<Func>(f_), policy).release(); 7211986Sandreas.sandberg@arm.com } 7311986Sandreas.sandberg@arm.com 7411986Sandreas.sandberg@arm.com PYBIND11_TYPE_CASTER(type, _("Callable[[") + 7511986Sandreas.sandberg@arm.com argument_loader<Args...>::arg_names() + _("], ") + 7612037Sandreas.sandberg@arm.com make_caster<retval_type>::name() + 7711986Sandreas.sandberg@arm.com _("]")); 7811986Sandreas.sandberg@arm.com}; 7911986Sandreas.sandberg@arm.com 8011986Sandreas.sandberg@arm.comNAMESPACE_END(detail) 8111986Sandreas.sandberg@arm.comNAMESPACE_END(pybind11) 82