Blame external/pybind11/include/pybind11/functional.h

Packit 534379
/*
Packit 534379
    pybind11/functional.h: std::function<> support
Packit 534379
Packit 534379
    Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
Packit 534379
Packit 534379
    All rights reserved. Use of this source code is governed by a
Packit 534379
    BSD-style license that can be found in the LICENSE file.
Packit 534379
*/
Packit 534379
Packit 534379
#pragma once
Packit 534379
Packit 534379
#include "pybind11.h"
Packit 534379
#include <functional>
Packit 534379
Packit 534379
NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
Packit 534379
NAMESPACE_BEGIN(detail)
Packit 534379
Packit 534379
template <typename Return, typename... Args>
Packit 534379
struct type_caster<std::function<Return(Args...)>> {
Packit 534379
    using type = std::function<Return(Args...)>;
Packit 534379
    using retval_type = conditional_t<std::is_same<Return, void>::value, void_type, Return>;
Packit 534379
    using function_type = Return (*) (Args...);
Packit 534379
Packit 534379
public:
Packit 534379
    bool load(handle src, bool convert) {
Packit 534379
        if (src.is_none()) {
Packit 534379
            // Defer accepting None to other overloads (if we aren't in convert mode):
Packit 534379
            if (!convert) return false;
Packit 534379
            return true;
Packit 534379
        }
Packit 534379
Packit 534379
        if (!isinstance<function>(src))
Packit 534379
            return false;
Packit 534379
Packit 534379
        auto func = reinterpret_borrow<function>(src);
Packit 534379
Packit 534379
        /*
Packit 534379
           When passing a C++ function as an argument to another C++
Packit 534379
           function via Python, every function call would normally involve
Packit 534379
           a full C++ -> Python -> C++ roundtrip, which can be prohibitive.
Packit 534379
           Here, we try to at least detect the case where the function is
Packit 534379
           stateless (i.e. function pointer or lambda function without
Packit 534379
           captured variables), in which case the roundtrip can be avoided.
Packit 534379
         */
Packit 534379
        if (auto cfunc = func.cpp_function()) {
Packit 534379
            auto c = reinterpret_borrow<capsule>(PyCFunction_GET_SELF(cfunc.ptr()));
Packit 534379
            auto rec = (function_record *) c;
Packit 534379
Packit 534379
            if (rec && rec->is_stateless &&
Packit 534379
                    same_type(typeid(function_type), *reinterpret_cast<const std::type_info *>(rec->data[1]))) {
Packit 534379
                struct capture { function_type f; };
Packit 534379
                value = ((capture *) &rec->data)->f;
Packit 534379
                return true;
Packit 534379
            }
Packit 534379
        }
Packit 534379
Packit 534379
        // ensure GIL is held during functor destruction
Packit 534379
        struct func_handle {
Packit 534379
            function f;
Packit 534379
            func_handle(function&& f_) : f(std::move(f_)) {}
Packit 534379
            func_handle(const func_handle&) = default;
Packit 534379
            ~func_handle() {
Packit 534379
                gil_scoped_acquire acq;
Packit 534379
                function kill_f(std::move(f));
Packit 534379
            }
Packit 534379
        };
Packit 534379
Packit 534379
        // to emulate 'move initialization capture' in C++11
Packit 534379
        struct func_wrapper {
Packit 534379
            func_handle hfunc;
Packit 534379
            func_wrapper(func_handle&& hf): hfunc(std::move(hf)) {}
Packit 534379
            Return operator()(Args... args) const {
Packit 534379
                gil_scoped_acquire acq;
Packit 534379
                object retval(hfunc.f(std::forward<Args>(args)...));
Packit 534379
                /* Visual studio 2015 parser issue: need parentheses around this expression */
Packit 534379
                return (retval.template cast<Return>());
Packit 534379
            }
Packit 534379
        };
Packit 534379
Packit 534379
        value = func_wrapper(func_handle(std::move(func)));
Packit 534379
        return true;
Packit 534379
    }
Packit 534379
Packit 534379
    template <typename Func>
Packit 534379
    static handle cast(Func &&f_, return_value_policy policy, handle /* parent */) {
Packit 534379
        if (!f_)
Packit 534379
            return none().inc_ref();
Packit 534379
Packit 534379
        auto result = f_.template target<function_type>();
Packit 534379
        if (result)
Packit 534379
            return cpp_function(*result, policy).release();
Packit 534379
        else
Packit 534379
            return cpp_function(std::forward<Func>(f_), policy).release();
Packit 534379
    }
Packit 534379
Packit 534379
    PYBIND11_TYPE_CASTER(type, _("Callable[[") + concat(make_caster<Args>::name...) + _("], ")
Packit 534379
                               + make_caster<retval_type>::name + _("]"));
Packit 534379
};
Packit 534379
Packit 534379
NAMESPACE_END(detail)
Packit 534379
NAMESPACE_END(PYBIND11_NAMESPACE)