Skip to content

Commit fe0cf8b

Browse files
bmerryjagerman
authored andcommitted
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.
1 parent 37b2383 commit fe0cf8b

File tree

3 files changed

+64
-1
lines changed

3 files changed

+64
-1
lines changed

include/pybind11/pybind11.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1020,6 +1020,16 @@ class class_ : public detail::generic_type {
10201020
return *this;
10211021
}
10221022

1023+
template <typename Return, typename Class, typename... Args>
1024+
class_ &def_buffer(Return (Class::*func)(Args...)) {
1025+
return def_buffer([func] (type &obj) { return (obj.*func)(); });
1026+
}
1027+
1028+
template <typename Return, typename Class, typename... Args>
1029+
class_ &def_buffer(Return (Class::*func)(Args...) const) {
1030+
return def_buffer([func] (const type &obj) { return (obj.*func)(); });
1031+
}
1032+
10231033
template <typename C, typename D, typename... Extra>
10241034
class_ &def_readwrite(const char *name, D C::*pm, const Extra&... extra) {
10251035
cpp_function fget([pm](const C &c) -> const D &{ return c.*pm; }, is_method(*this)),

tests/test_buffers.cpp

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,32 @@ class Matrix {
7474
float *m_data;
7575
};
7676

77+
struct PTMFBuffer {
78+
int32_t value = 0;
79+
80+
py::buffer_info get_buffer_info() {
81+
return py::buffer_info(&value, sizeof(value),
82+
py::format_descriptor<int32_t>::format(), 1);
83+
}
84+
};
85+
86+
class ConstPTMFBuffer {
87+
std::unique_ptr<int32_t> value;
88+
89+
public:
90+
int32_t get_value() const { return *value; }
91+
void set_value(int32_t v) { *value = v; }
92+
93+
py::buffer_info get_buffer_info() const {
94+
return py::buffer_info(value.get(), sizeof(*value),
95+
py::format_descriptor<int32_t>::format(), 1);
96+
}
97+
98+
ConstPTMFBuffer() : value(new int32_t{0}) { };
99+
};
100+
101+
struct DerivedPTMFBuffer : public PTMFBuffer { };
102+
77103
test_initializer buffers([](py::module &m) {
78104
py::class_<Matrix> mtx(m, "Matrix", py::buffer_protocol());
79105

@@ -114,4 +140,21 @@ test_initializer buffers([](py::module &m) {
114140
);
115141
})
116142
;
143+
144+
py::class_<PTMFBuffer>(m, "PTMFBuffer", py::buffer_protocol())
145+
.def(py::init<>())
146+
.def_readwrite("value", &PTMFBuffer::value)
147+
.def_buffer(&PTMFBuffer::get_buffer_info);
148+
149+
py::class_<ConstPTMFBuffer>(m, "ConstPTMFBuffer", py::buffer_protocol())
150+
.def(py::init<>())
151+
.def_property("value", &ConstPTMFBuffer::get_value, &ConstPTMFBuffer::set_value)
152+
.def_buffer(&ConstPTMFBuffer::get_buffer_info);
153+
154+
// Tests that passing a pointer to member to the base class works in
155+
// the derived class.
156+
py::class_<DerivedPTMFBuffer>(m, "DerivedPTMFBuffer", py::buffer_protocol())
157+
.def(py::init<>())
158+
.def_readwrite("value", (int32_t DerivedPTMFBuffer::*) &DerivedPTMFBuffer::value)
159+
.def_buffer(&DerivedPTMFBuffer::get_buffer_info);
117160
});

tests/test_buffers.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1+
import struct
12
import pytest
2-
from pybind11_tests import Matrix, ConstructorStats
3+
from pybind11_tests import Matrix, ConstructorStats, PTMFBuffer, ConstPTMFBuffer, DerivedPTMFBuffer
34

45
pytestmark = pytest.requires_numpy
56

@@ -60,3 +61,12 @@ def test_to_python():
6061
# assert cstats.move_constructions >= 0 # Don't invoke any
6162
assert cstats.copy_assignments == 0
6263
assert cstats.move_assignments == 0
64+
65+
66+
@pytest.unsupported_on_pypy
67+
def test_ptmf():
68+
for cls in [PTMFBuffer, ConstPTMFBuffer, DerivedPTMFBuffer]:
69+
buf = cls()
70+
buf.value = 0x12345678
71+
value = struct.unpack('i', bytearray(buf))[0]
72+
assert value == 0x12345678

0 commit comments

Comments
 (0)