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