Skip to content

Commit 76f7a7b

Browse files
committed
Squash all commits into 1.
1 parent 50bb0bf commit 76f7a7b

4 files changed

Lines changed: 106 additions & 37 deletions

File tree

include/pybind11/functional.h

Lines changed: 46 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,50 @@
1515

1616
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
1717
PYBIND11_NAMESPACE_BEGIN(detail)
18+
PYBIND11_NAMESPACE_BEGIN(type_caster_std_function_specializations)
19+
20+
// ensure GIL is held during functor destruction
21+
struct func_handle {
22+
function f;
23+
#if !(defined(_MSC_VER) && _MSC_VER == 1916 && defined(PYBIND11_CPP17))
24+
// This triggers a syntax error under very special conditions (very weird indeed).
25+
explicit
26+
#endif
27+
func_handle(function &&f_) noexcept
28+
: f(std::move(f_)) {
29+
}
30+
func_handle(const func_handle &f_) { operator=(f_); }
31+
func_handle &operator=(const func_handle &f_) {
32+
gil_scoped_acquire acq;
33+
f = f_.f;
34+
return *this;
35+
}
36+
~func_handle() {
37+
gil_scoped_acquire acq;
38+
function kill_f(std::move(f));
39+
}
40+
};
41+
42+
// to emulate 'move initialization capture' in C++11
43+
struct func_wrapper_base {
44+
func_handle hfunc;
45+
return_value_policy_pack rvpp;
46+
explicit func_wrapper_base(func_handle &&hf, const return_value_policy_pack &rvpp) noexcept
47+
: hfunc(hf), rvpp(rvpp) {}
48+
};
49+
50+
template <typename Return, typename... Args>
51+
struct func_wrapper : func_wrapper_base {
52+
using func_wrapper_base::func_wrapper_base;
53+
Return operator()(Args... args) const {
54+
gil_scoped_acquire acq;
55+
// casts the returned object as a rvalue to the return type
56+
return hfunc.f.call_with_policies(rvpp, std::forward<Args>(args)...)
57+
.template cast<Return>();
58+
}
59+
};
60+
61+
PYBIND11_NAMESPACE_END(type_caster_std_function_specializations)
1862

1963
template <typename Return, typename... Args>
2064
struct type_caster<std::function<Return(Args...)>> {
@@ -77,43 +121,8 @@ struct type_caster<std::function<Return(Args...)>> {
77121
// See PR #1413 for full details
78122
}
79123

80-
// ensure GIL is held during functor destruction
81-
struct func_handle {
82-
function f;
83-
#if !(defined(_MSC_VER) && _MSC_VER == 1916 && defined(PYBIND11_CPP17))
84-
// This triggers a syntax error under very special conditions (very weird indeed).
85-
explicit
86-
#endif
87-
func_handle(function &&f_) noexcept
88-
: f(std::move(f_)) {
89-
}
90-
func_handle(const func_handle &f_) { operator=(f_); }
91-
func_handle &operator=(const func_handle &f_) {
92-
gil_scoped_acquire acq;
93-
f = f_.f;
94-
return *this;
95-
}
96-
~func_handle() {
97-
gil_scoped_acquire acq;
98-
function kill_f(std::move(f));
99-
}
100-
};
101-
102-
// to emulate 'move initialization capture' in C++11
103-
struct func_wrapper {
104-
func_handle hfunc;
105-
return_value_policy_pack rvpp;
106-
func_wrapper(func_handle &&hf, const return_value_policy_pack &rvpp) noexcept
107-
: hfunc(std::move(hf)), rvpp(rvpp) {}
108-
Return operator()(Args... args) const {
109-
gil_scoped_acquire acq;
110-
// casts the returned object as a rvalue to the return type
111-
return hfunc.f.call_with_policies(rvpp, std::forward<Args>(args)...)
112-
.template cast<Return>();
113-
}
114-
};
115-
116-
value = func_wrapper(func_handle(std::move(func)), fpp.rvpp);
124+
value = type_caster_std_function_specializations::func_wrapper<Return, Args...>(
125+
type_caster_std_function_specializations::func_handle(std::move(func)), fpp.rvpp);
117126
return true;
118127
}
119128

tests/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,7 @@ set(PYBIND11_TEST_FILES
180180
test_thread
181181
test_type_caster_odr_guard_1
182182
test_type_caster_odr_guard_2
183+
test_type_caster_std_function_specializations
183184
test_union
184185
test_virtual_functions)
185186

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
#include <pybind11/functional.h>
2+
#include <pybind11/pybind11.h>
3+
4+
#include "pybind11_tests.h"
5+
6+
namespace py = pybind11;
7+
8+
namespace {
9+
10+
struct SpecialReturn {
11+
int value = 99;
12+
};
13+
14+
} // namespace
15+
16+
namespace pybind11 {
17+
namespace detail {
18+
namespace type_caster_std_function_specializations {
19+
20+
template <typename... Args>
21+
struct func_wrapper<SpecialReturn, Args...> : func_wrapper_base {
22+
using func_wrapper_base::func_wrapper_base;
23+
SpecialReturn operator()(Args... args) const {
24+
gil_scoped_acquire acq;
25+
SpecialReturn result;
26+
try {
27+
result = hfunc.f(std::forward<Args>(args)...).template cast<SpecialReturn>();
28+
} catch (error_already_set &) {
29+
result.value += 1;
30+
}
31+
result.value += 100;
32+
return result;
33+
}
34+
};
35+
36+
} // namespace type_caster_std_function_specializations
37+
} // namespace detail
38+
} // namespace pybind11
39+
40+
TEST_SUBMODULE(type_caster_std_function_specializations, m) {
41+
py::class_<SpecialReturn>(m, "SpecialReturn")
42+
.def(py::init<>())
43+
.def_readwrite("value", &SpecialReturn::value);
44+
m.def("call_callback_with_special_return",
45+
[](const std::function<SpecialReturn()> &func) { return func(); });
46+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
from pybind11_tests import type_caster_std_function_specializations as m
2+
3+
4+
def test_callback_with_special_return():
5+
def return_special():
6+
return m.SpecialReturn()
7+
8+
def raise_exception():
9+
raise ValueError("called raise_exception.")
10+
11+
assert return_special().value == 99
12+
assert m.call_callback_with_special_return(return_special).value == 199
13+
assert m.call_callback_with_special_return(raise_exception).value == 200

0 commit comments

Comments
 (0)