From fe0cf8b73b8e068c205e062c779eb694b194d6b4 Mon Sep 17 00:00:00 2001 From: Bruce Merry Date: Wed, 17 May 2017 10:52:33 +0200 Subject: [PATCH] Support pointers to member functions in def_buffer. Closes #857, by adding overloads to def_buffer that match pointers to member functions and wrap them in lambdas. --- include/pybind11/pybind11.h | 10 +++++++++ tests/test_buffers.cpp | 43 +++++++++++++++++++++++++++++++++++++ tests/test_buffers.py | 12 ++++++++++- 3 files changed, 64 insertions(+), 1 deletion(-) diff --git a/include/pybind11/pybind11.h b/include/pybind11/pybind11.h index ca4b05894..1f36308c9 100644 --- a/include/pybind11/pybind11.h +++ b/include/pybind11/pybind11.h @@ -1020,6 +1020,16 @@ public: return *this; } + template + class_ &def_buffer(Return (Class::*func)(Args...)) { + return def_buffer([func] (type &obj) { return (obj.*func)(); }); + } + + template + class_ &def_buffer(Return (Class::*func)(Args...) const) { + return def_buffer([func] (const type &obj) { return (obj.*func)(); }); + } + template class_ &def_readwrite(const char *name, D C::*pm, const Extra&... extra) { cpp_function fget([pm](const C &c) -> const D &{ return c.*pm; }, is_method(*this)), diff --git a/tests/test_buffers.cpp b/tests/test_buffers.cpp index 6b5b75551..1a18f7949 100644 --- a/tests/test_buffers.cpp +++ b/tests/test_buffers.cpp @@ -74,6 +74,32 @@ private: float *m_data; }; +struct PTMFBuffer { + int32_t value = 0; + + py::buffer_info get_buffer_info() { + return py::buffer_info(&value, sizeof(value), + py::format_descriptor::format(), 1); + } +}; + +class ConstPTMFBuffer { + std::unique_ptr value; + +public: + int32_t get_value() const { return *value; } + void set_value(int32_t v) { *value = v; } + + py::buffer_info get_buffer_info() const { + return py::buffer_info(value.get(), sizeof(*value), + py::format_descriptor::format(), 1); + } + + ConstPTMFBuffer() : value(new int32_t{0}) { }; +}; + +struct DerivedPTMFBuffer : public PTMFBuffer { }; + test_initializer buffers([](py::module &m) { py::class_ mtx(m, "Matrix", py::buffer_protocol()); @@ -114,4 +140,21 @@ test_initializer buffers([](py::module &m) { ); }) ; + + py::class_(m, "PTMFBuffer", py::buffer_protocol()) + .def(py::init<>()) + .def_readwrite("value", &PTMFBuffer::value) + .def_buffer(&PTMFBuffer::get_buffer_info); + + py::class_(m, "ConstPTMFBuffer", py::buffer_protocol()) + .def(py::init<>()) + .def_property("value", &ConstPTMFBuffer::get_value, &ConstPTMFBuffer::set_value) + .def_buffer(&ConstPTMFBuffer::get_buffer_info); + + // Tests that passing a pointer to member to the base class works in + // the derived class. + py::class_(m, "DerivedPTMFBuffer", py::buffer_protocol()) + .def(py::init<>()) + .def_readwrite("value", (int32_t DerivedPTMFBuffer::*) &DerivedPTMFBuffer::value) + .def_buffer(&DerivedPTMFBuffer::get_buffer_info); }); diff --git a/tests/test_buffers.py b/tests/test_buffers.py index 24843d95a..66a9909bc 100644 --- a/tests/test_buffers.py +++ b/tests/test_buffers.py @@ -1,5 +1,6 @@ +import struct import pytest -from pybind11_tests import Matrix, ConstructorStats +from pybind11_tests import Matrix, ConstructorStats, PTMFBuffer, ConstPTMFBuffer, DerivedPTMFBuffer pytestmark = pytest.requires_numpy @@ -60,3 +61,12 @@ def test_to_python(): # assert cstats.move_constructions >= 0 # Don't invoke any assert cstats.copy_assignments == 0 assert cstats.move_assignments == 0 + + +@pytest.unsupported_on_pypy +def test_ptmf(): + for cls in [PTMFBuffer, ConstPTMFBuffer, DerivedPTMFBuffer]: + buf = cls() + buf.value = 0x12345678 + value = struct.unpack('i', bytearray(buf))[0] + assert value == 0x12345678