Skip to content

Commit 45ab00e

Browse files
committed
Port py_adaptors to pybind11
1 parent fb4d7c3 commit 45ab00e

File tree

4 files changed

+87
-118
lines changed

4 files changed

+87
-118
lines changed

src/_backend_agg_wrapper.cpp

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ static void
111111
PyRendererAgg_draw_path_collection(RendererAgg *self,
112112
GCAgg &gc,
113113
agg::trans_affine master_transform,
114-
py::object paths_obj,
114+
mpl::PathGenerator paths,
115115
py::object transforms_obj,
116116
py::object offsets_obj,
117117
agg::trans_affine offset_trans,
@@ -124,17 +124,13 @@ PyRendererAgg_draw_path_collection(RendererAgg *self,
124124
// offset position is no longer used
125125
py::object Py_UNUSED(offset_position_obj))
126126
{
127-
mpl::PathGenerator paths;
128127
numpy::array_view<const double, 3> transforms;
129128
numpy::array_view<const double, 2> offsets;
130129
numpy::array_view<const double, 2> facecolors;
131130
numpy::array_view<const double, 2> edgecolors;
132131
numpy::array_view<const double, 1> linewidths;
133132
numpy::array_view<const uint8_t, 1> antialiaseds;
134133

135-
if (!convert_pathgen(paths_obj.ptr(), &paths)) {
136-
throw py::error_already_set();
137-
}
138134
if (!convert_transforms(transforms_obj.ptr(), &transforms)) {
139135
throw py::error_already_set();
140136
}

src/_path_wrapper.cpp

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -123,17 +123,13 @@ Py_update_path_extents(mpl::PathIterator path, agg::trans_affine trans,
123123

124124
static py::tuple
125125
Py_get_path_collection_extents(agg::trans_affine master_transform,
126-
py::object paths_obj, py::object transforms_obj,
126+
mpl::PathGenerator paths, py::object transforms_obj,
127127
py::object offsets_obj, agg::trans_affine offset_trans)
128128
{
129-
mpl::PathGenerator paths;
130129
numpy::array_view<const double, 3> transforms;
131130
numpy::array_view<const double, 2> offsets;
132131
extent_limits e;
133132

134-
if (!convert_pathgen(paths_obj.ptr(), &paths)) {
135-
throw py::error_already_set();
136-
}
137133
if (!convert_transforms(transforms_obj.ptr(), &transforms)) {
138134
throw py::error_already_set();
139135
}
@@ -161,18 +157,14 @@ Py_get_path_collection_extents(agg::trans_affine master_transform,
161157

162158
static py::object
163159
Py_point_in_path_collection(double x, double y, double radius,
164-
agg::trans_affine master_transform, py::object paths_obj,
160+
agg::trans_affine master_transform, mpl::PathGenerator paths,
165161
py::object transforms_obj, py::object offsets_obj,
166162
agg::trans_affine offset_trans, bool filled)
167163
{
168-
mpl::PathGenerator paths;
169164
numpy::array_view<const double, 3> transforms;
170165
numpy::array_view<const double, 2> offsets;
171166
std::vector<int> result;
172167

173-
if (!convert_pathgen(paths_obj.ptr(), &paths)) {
174-
throw py::error_already_set();
175-
}
176168
if (!convert_transforms(transforms_obj.ptr(), &transforms)) {
177169
throw py::error_already_set();
178170
}

src/py_adaptors.h

Lines changed: 84 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,12 @@
88
* structures to C++ and Agg-friendly interfaces.
99
*/
1010

11-
#include <Python.h>
12-
13-
#include "numpy/arrayobject.h"
11+
#include <pybind11/pybind11.h>
12+
#include <pybind11/numpy.h>
1413

1514
#include "agg_basics.h"
16-
#include "py_exceptions.h"
1715

18-
extern "C" {
19-
int convert_path(PyObject *obj, void *pathp);
20-
}
16+
namespace py = pybind11;
2117

2218
namespace mpl {
2319

@@ -35,8 +31,8 @@ class PathIterator
3531
underlying data arrays, so that Python reference counting
3632
can work.
3733
*/
38-
PyArrayObject *m_vertices;
39-
PyArrayObject *m_codes;
34+
py::array_t<double> m_vertices;
35+
py::array_t<uint8_t> m_codes;
4036

4137
unsigned m_iterator;
4238
unsigned m_total_vertices;
@@ -50,38 +46,29 @@ class PathIterator
5046

5147
public:
5248
inline PathIterator()
53-
: m_vertices(NULL),
54-
m_codes(NULL),
55-
m_iterator(0),
49+
: m_iterator(0),
5650
m_total_vertices(0),
5751
m_should_simplify(false),
5852
m_simplify_threshold(1.0 / 9.0)
5953
{
6054
}
6155

62-
inline PathIterator(PyObject *vertices,
63-
PyObject *codes,
64-
bool should_simplify,
56+
inline PathIterator(py::object vertices, py::object codes, bool should_simplify,
6557
double simplify_threshold)
66-
: m_vertices(NULL), m_codes(NULL), m_iterator(0)
58+
: m_iterator(0)
6759
{
68-
if (!set(vertices, codes, should_simplify, simplify_threshold))
69-
throw mpl::exception();
60+
set(vertices, codes, should_simplify, simplify_threshold);
7061
}
7162

72-
inline PathIterator(PyObject *vertices, PyObject *codes)
73-
: m_vertices(NULL), m_codes(NULL), m_iterator(0)
63+
inline PathIterator(py::object vertices, py::object codes)
64+
: m_iterator(0)
7465
{
75-
if (!set(vertices, codes))
76-
throw mpl::exception();
66+
set(vertices, codes);
7767
}
7868

7969
inline PathIterator(const PathIterator &other)
8070
{
81-
Py_XINCREF(other.m_vertices);
8271
m_vertices = other.m_vertices;
83-
84-
Py_XINCREF(other.m_codes);
8572
m_codes = other.m_codes;
8673

8774
m_iterator = 0;
@@ -91,47 +78,45 @@ class PathIterator
9178
m_simplify_threshold = other.m_simplify_threshold;
9279
}
9380

94-
~PathIterator()
95-
{
96-
Py_XDECREF(m_vertices);
97-
Py_XDECREF(m_codes);
98-
}
99-
100-
inline int
101-
set(PyObject *vertices, PyObject *codes, bool should_simplify, double simplify_threshold)
81+
inline void
82+
set(py::object vertices, py::object codes, bool should_simplify, double simplify_threshold)
10283
{
10384
m_should_simplify = should_simplify;
10485
m_simplify_threshold = simplify_threshold;
10586

106-
Py_XDECREF(m_vertices);
107-
m_vertices = (PyArrayObject *)PyArray_FromObject(vertices, NPY_DOUBLE, 2, 2);
108-
109-
if (!m_vertices || PyArray_DIM(m_vertices, 1) != 2) {
110-
PyErr_SetString(PyExc_ValueError, "Invalid vertices array");
111-
return 0;
87+
m_vertices = vertices.cast<py::array_t<double>>();
88+
if (m_vertices.ndim() != 2 || m_vertices.shape(1) != 2) {
89+
throw py::value_error("Invalid vertices array");
11290
}
91+
m_total_vertices = m_vertices.shape(0);
11392

114-
Py_XDECREF(m_codes);
115-
m_codes = NULL;
116-
117-
if (codes != NULL && codes != Py_None) {
118-
m_codes = (PyArrayObject *)PyArray_FromObject(codes, NPY_UINT8, 1, 1);
119-
120-
if (!m_codes || PyArray_DIM(m_codes, 0) != PyArray_DIM(m_vertices, 0)) {
121-
PyErr_SetString(PyExc_ValueError, "Invalid codes array");
122-
return 0;
93+
m_codes.release().dec_ref();
94+
if (!codes.is_none()) {
95+
m_codes = codes.cast<py::array_t<uint8_t>>();
96+
if (m_codes.ndim() != 1 || m_codes.shape(0) != m_total_vertices) {
97+
throw py::value_error("Invalid codes array");
12398
}
12499
}
125100

126-
m_total_vertices = (unsigned)PyArray_DIM(m_vertices, 0);
127101
m_iterator = 0;
102+
}
128103

104+
inline int
105+
set(PyObject *vertices, PyObject *codes, bool should_simplify, double simplify_threshold)
106+
{
107+
try {
108+
set(py::reinterpret_borrow<py::object>(vertices),
109+
py::reinterpret_borrow<py::object>(codes),
110+
should_simplify, simplify_threshold);
111+
} catch(const py::error_already_set &) {
112+
return 0;
113+
}
129114
return 1;
130115
}
131116

132-
inline int set(PyObject *vertices, PyObject *codes)
117+
inline void set(py::object vertices, py::object codes)
133118
{
134-
return set(vertices, codes, false, 0.0);
119+
set(vertices, codes, false, 0.0);
135120
}
136121

137122
inline unsigned vertex(double *x, double *y)
@@ -144,12 +129,11 @@ class PathIterator
144129

145130
const size_t idx = m_iterator++;
146131

147-
char *pair = (char *)PyArray_GETPTR2(m_vertices, idx, 0);
148-
*x = *(double *)pair;
149-
*y = *(double *)(pair + PyArray_STRIDE(m_vertices, 1));
132+
*x = *m_vertices.data(idx, 0);
133+
*y = *m_vertices.data(idx, 1);
150134

151-
if (m_codes != NULL) {
152-
return (unsigned)(*(char *)PyArray_GETPTR1(m_codes, idx));
135+
if (m_codes) {
136+
return *m_codes.data(idx);
153137
} else {
154138
return idx == 0 ? agg::path_cmd_move_to : agg::path_cmd_line_to;
155139
}
@@ -177,42 +161,38 @@ class PathIterator
177161

178162
inline bool has_codes() const
179163
{
180-
return m_codes != NULL;
164+
return bool(m_codes);
181165
}
182166

183167
inline void *get_id()
184168
{
185-
return (void *)m_vertices;
169+
return (void *)m_vertices.ptr();
186170
}
187171
};
188172

189173
class PathGenerator
190174
{
191-
PyObject *m_paths;
175+
py::sequence m_paths;
192176
Py_ssize_t m_npaths;
193177

194178
public:
195179
typedef PathIterator path_iterator;
196180

197-
PathGenerator() : m_paths(NULL), m_npaths(0) {}
181+
PathGenerator() : m_npaths(0) {}
198182

199-
~PathGenerator()
183+
void set(py::object obj)
200184
{
201-
Py_XDECREF(m_paths);
185+
m_paths = obj.cast<py::sequence>();
186+
m_npaths = m_paths.size();
202187
}
203188

204189
int set(PyObject *obj)
205190
{
206-
if (!PySequence_Check(obj)) {
191+
try {
192+
set(py::reinterpret_borrow<py::object>(obj));
193+
} catch(const py::error_already_set &) {
207194
return 0;
208195
}
209-
210-
Py_XDECREF(m_paths);
211-
m_paths = obj;
212-
Py_INCREF(m_paths);
213-
214-
m_npaths = PySequence_Size(m_paths);
215-
216196
return 1;
217197
}
218198

@@ -229,20 +209,44 @@ class PathGenerator
229209
path_iterator operator()(size_t i)
230210
{
231211
path_iterator path;
232-
PyObject *item;
233212

234-
item = PySequence_GetItem(m_paths, i % m_npaths);
235-
if (item == NULL) {
236-
throw mpl::exception();
237-
}
238-
if (!convert_path(item, &path)) {
239-
Py_DECREF(item);
240-
throw mpl::exception();
241-
}
242-
Py_DECREF(item);
213+
auto item = m_paths[i % m_npaths];
214+
path = item.cast<path_iterator>();
243215
return path;
244216
}
245217
};
246218
}
247219

220+
namespace PYBIND11_NAMESPACE { namespace detail {
221+
template <> struct type_caster<mpl::PathIterator> {
222+
public:
223+
PYBIND11_TYPE_CASTER(mpl::PathIterator, const_name("PathIterator"));
224+
225+
bool load(handle src, bool) {
226+
if (src.is_none()) {
227+
return true;
228+
}
229+
230+
py::object vertices = src.attr("vertices");
231+
py::object codes = src.attr("codes");
232+
auto should_simplify = src.attr("should_simplify").cast<bool>();
233+
auto simplify_threshold = src.attr("simplify_threshold").cast<double>();
234+
235+
value.set(vertices, codes, should_simplify, simplify_threshold);
236+
237+
return true;
238+
}
239+
};
240+
241+
template <> struct type_caster<mpl::PathGenerator> {
242+
public:
243+
PYBIND11_TYPE_CASTER(mpl::PathGenerator, const_name("PathGenerator"));
244+
245+
bool load(handle src, bool) {
246+
value.set(py::reinterpret_borrow<py::object>(src));
247+
return true;
248+
}
249+
};
250+
}} // namespace PYBIND11_NAMESPACE::detail
251+
248252
#endif

src/py_converters_11.h

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -167,29 +167,6 @@ namespace PYBIND11_NAMESPACE { namespace detail {
167167
return true;
168168
}
169169
};
170-
171-
template <> struct type_caster<mpl::PathIterator> {
172-
public:
173-
PYBIND11_TYPE_CASTER(mpl::PathIterator, const_name("PathIterator"));
174-
175-
bool load(handle src, bool) {
176-
if (src.is_none()) {
177-
return true;
178-
}
179-
180-
py::object vertices = src.attr("vertices");
181-
py::object codes = src.attr("codes");
182-
auto should_simplify = src.attr("should_simplify").cast<bool>();
183-
auto simplify_threshold = src.attr("simplify_threshold").cast<double>();
184-
185-
if (!value.set(vertices.inc_ref().ptr(), codes.inc_ref().ptr(),
186-
should_simplify, simplify_threshold)) {
187-
throw py::error_already_set();
188-
}
189-
190-
return true;
191-
}
192-
};
193170
#endif
194171

195172
/* Remove all this macro magic after dropping NumPy usage and just include `_backend_agg_basic_types.h`. */

0 commit comments

Comments
 (0)