summaryrefslogtreecommitdiff
path: root/ext/pybind11/include/pybind11/functional.h
diff options
context:
space:
mode:
Diffstat (limited to 'ext/pybind11/include/pybind11/functional.h')
-rw-r--r--ext/pybind11/include/pybind11/functional.h79
1 files changed, 79 insertions, 0 deletions
diff --git a/ext/pybind11/include/pybind11/functional.h b/ext/pybind11/include/pybind11/functional.h
new file mode 100644
index 000000000..f1b0ebbbf
--- /dev/null
+++ b/ext/pybind11/include/pybind11/functional.h
@@ -0,0 +1,79 @@
+/*
+ pybind11/functional.h: std::function<> support
+
+ Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
+
+ All rights reserved. Use of this source code is governed by a
+ BSD-style license that can be found in the LICENSE file.
+*/
+
+#pragma once
+
+#include "pybind11.h"
+#include <functional>
+
+NAMESPACE_BEGIN(pybind11)
+NAMESPACE_BEGIN(detail)
+
+template <typename Return, typename... Args> struct type_caster<std::function<Return(Args...)>> {
+ typedef std::function<Return(Args...)> type;
+ typedef typename std::conditional<std::is_same<Return, void>::value, void_type, Return>::type retval_type;
+public:
+ bool load(handle src_, bool) {
+ if (src_.is_none())
+ return true;
+
+ src_ = detail::get_function(src_);
+ if (!src_ || !PyCallable_Check(src_.ptr()))
+ return false;
+
+ /*
+ When passing a C++ function as an argument to another C++
+ function via Python, every function call would normally involve
+ a full C++ -> Python -> C++ roundtrip, which can be prohibitive.
+ Here, we try to at least detect the case where the function is
+ stateless (i.e. function pointer or lambda function without
+ captured variables), in which case the roundtrip can be avoided.
+ */
+ if (PyCFunction_Check(src_.ptr())) {
+ auto c = reinterpret_borrow<capsule>(PyCFunction_GetSelf(src_.ptr()));
+ auto rec = (function_record *) c;
+ using FunctionType = Return (*) (Args...);
+
+ if (rec && rec->is_stateless && rec->data[1] == &typeid(FunctionType)) {
+ struct capture { FunctionType f; };
+ value = ((capture *) &rec->data)->f;
+ return true;
+ }
+ }
+
+ auto src = reinterpret_borrow<object>(src_);
+ value = [src](Args... args) -> Return {
+ gil_scoped_acquire acq;
+ object retval(src(std::move(args)...));
+ /* Visual studio 2015 parser issue: need parentheses around this expression */
+ return (retval.template cast<Return>());
+ };
+ return true;
+ }
+
+ template <typename Func>
+ static handle cast(Func &&f_, return_value_policy policy, handle /* parent */) {
+ if (!f_)
+ return none().inc_ref();
+
+ auto result = f_.template target<Return (*)(Args...)>();
+ if (result)
+ return cpp_function(*result, policy).release();
+ else
+ return cpp_function(std::forward<Func>(f_), policy).release();
+ }
+
+ PYBIND11_TYPE_CASTER(type, _("Callable[[") +
+ argument_loader<Args...>::arg_names() + _("], ") +
+ type_caster<retval_type>::name() +
+ _("]"));
+};
+
+NAMESPACE_END(detail)
+NAMESPACE_END(pybind11)