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