tests: test recursive dispatch using visitor pattern (#3365)

This commit is contained in:
Dmitry Yershov 2021-10-22 17:09:15 -04:00 committed by GitHub
parent 606f81a966
commit 076c89fc54
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 73 additions and 0 deletions

View File

@ -174,6 +174,25 @@ struct DispatchIssue : Base {
} }
}; };
// An abstract adder class that uses visitor pattern to add two data
// objects and send the result to the visitor functor
struct AdderBase {
struct Data {};
using DataVisitor = std::function<void (const Data&)>;
virtual void operator()(const Data& first, const Data& second, const DataVisitor& visitor) const = 0;
virtual ~AdderBase() = default;
AdderBase() = default;
AdderBase(const AdderBase&) = delete;
};
struct Adder : AdderBase {
void operator()(const Data& first, const Data& second, const DataVisitor& visitor) const override {
PYBIND11_OVERRIDE_PURE_NAME(void, AdderBase, "__call__", operator(), first, second, visitor);
}
};
static void test_gil() { static void test_gil() {
{ {
py::gil_scoped_acquire lock; py::gil_scoped_acquire lock;
@ -295,6 +314,27 @@ TEST_SUBMODULE(virtual_functions, m) {
m.def("dispatch_issue_go", [](const Base * b) { return b->dispatch(); }); m.def("dispatch_issue_go", [](const Base * b) { return b->dispatch(); });
// test_recursive_dispatch_issue
// #3357: Recursive dispatch fails to find python function override
pybind11::class_<AdderBase, Adder>(m, "Adder")
.def(pybind11::init<>())
.def("__call__", &AdderBase::operator());
pybind11::class_<AdderBase::Data>(m, "Data")
.def(pybind11::init<>());
m.def("add2", [](const AdderBase::Data& first, const AdderBase::Data& second,
const AdderBase& adder, const AdderBase::DataVisitor& visitor) {
adder(first, second, visitor);
});
m.def("add3", [](const AdderBase::Data& first, const AdderBase::Data& second, const AdderBase::Data& third,
const AdderBase& adder, const AdderBase::DataVisitor& visitor) {
adder(first, second, [&] (const AdderBase::Data& first_plus_second) {
adder(first_plus_second, third, visitor);
});
});
// test_override_ref // test_override_ref
// #392/397: overriding reference-returning functions // #392/397: overriding reference-returning functions
class OverrideTest { class OverrideTest {

View File

@ -257,6 +257,39 @@ def test_dispatch_issue(msg):
assert m.dispatch_issue_go(b) == "Yay.." assert m.dispatch_issue_go(b) == "Yay.."
def test_recursive_dispatch_issue(msg):
"""#3357: Recursive dispatch fails to find python function override"""
class Data(m.Data):
def __init__(self, value):
super(Data, self).__init__()
self.value = value
class Adder(m.Adder):
def __call__(self, first, second, visitor):
# lambda is a workaround, which adds extra frame to the
# current CPython thread. Removing lambda reveals the bug
# [https://github.com/pybind/pybind11/issues/3357]
(lambda: visitor(Data(first.value + second.value)))()
class StoreResultVisitor:
def __init__(self):
self.result = None
def __call__(self, data):
self.result = data.value
store = StoreResultVisitor()
m.add2(Data(1), Data(2), Adder(), store)
assert store.result == 3
# without lambda in Adder class, this function fails with
# RuntimeError: Tried to call pure virtual function "AdderBase::__call__"
m.add3(Data(1), Data(2), Data(3), Adder(), store)
assert store.result == 6
def test_override_ref(): def test_override_ref():
"""#392/397: overriding reference-returning functions""" """#392/397: overriding reference-returning functions"""
o = m.OverrideTest("asdf") o = m.OverrideTest("asdf")