Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
TupleOfInstances.cxx
Go to the documentation of this file.
1#include "Python.h"
2#include "cppjit_interop.h"
3
4// Bindings
5#include "cpyrt.h"
6
7using namespace cppjit;
8#include "ProxyWrappers.h"
9#include "TupleOfInstances.h"
10
11namespace {
12
13typedef struct {
14 PyObject_HEAD interop::TCppScope_t ia_klass;
15 void* ia_array_start;
16 Py_ssize_t ia_pos;
17 Py_ssize_t ia_len;
18 Py_ssize_t ia_stride;
19} ia_iterobject;
20
21static PyObject* ia_iternext(ia_iterobject* ia) {
22 if (ia->ia_len != (Py_ssize_t)-1 && ia->ia_pos >= ia->ia_len) {
23 ia->ia_pos = 0; // debatable, but since the iterator is cached, this
24 return nullptr; // allows for multiple conversions to e.g. a tuple
25 } else if (ia->ia_stride == 0 && ia->ia_pos != 0) {
26 PyErr_SetString(PyExc_ReferenceError, "no stride available for indexing");
27 return nullptr;
28 }
30 (char*)ia->ia_array_start + ia->ia_pos * ia->ia_stride, ia->ia_klass);
31 ia->ia_pos += 1;
32 return result;
33}
34
35static int ia_traverse(ia_iterobject*, visitproc, void*) { return 0; }
36
37static PyObject* ia_getsize(ia_iterobject* ia, void*) {
38 return PyLong_FromSsize_t(ia->ia_len);
39}
40
41static int ia_setsize(ia_iterobject* ia, PyObject* pysize, void*) {
42 Py_ssize_t size = PyLong_AsSsize_t(pysize);
43 if (size == (Py_ssize_t)-1 && PyErr_Occurred())
44 return -1;
45 ia->ia_len = size;
46 return 0;
47}
48
49static PyGetSetDef ia_getset[] = {
50 {(char*)"size", (getter)ia_getsize, (setter)ia_setsize,
51 (char*)"set size of array to which this iterator refers", nullptr},
52 {(char*)nullptr, nullptr, nullptr, nullptr, nullptr}};
53
54static Py_ssize_t ia_length(ia_iterobject* ia) { return ia->ia_len; }
55
56static PyObject* ia_subscript(ia_iterobject* ia, PyObject* pyidx) {
57 // Subscripting the iterator allows direct access through indexing on arrays
58 // that do not have a defined length. This way, the return from accessing such
59 // an array as a data member can both be used in a loop and directly.
60 Py_ssize_t idx = PyLong_AsSsize_t(pyidx);
61 if (idx == (Py_ssize_t)-1 && PyErr_Occurred())
62 return nullptr;
63
64 if (ia->ia_len != (Py_ssize_t)-1 && (idx < 0 || ia->ia_len <= idx)) {
65 PyErr_SetString(PyExc_IndexError, "index out of range");
66 return nullptr;
67 }
68
70 (char*)ia->ia_array_start + ia->ia_pos * ia->ia_stride, ia->ia_klass);
71}
72
73static PyMappingMethods ia_as_mapping = {
74 (lenfunc)ia_length, // mp_length
75 (binaryfunc)ia_subscript, // mp_subscript
76 (objobjargproc) nullptr, // mp_ass_subscript
77};
78
79} // unnamed namespace
80
81namespace cppjit::cpyrt {
82
83PyTypeObject InstanceArrayIter_Type = {
84 PyVarObject_HEAD_INIT(&PyType_Type,
85 0)(char*) "cppjit.instancearrayiter", // tp_name
86 sizeof(ia_iterobject), // tp_basicsize
87 0,
88 (destructor)PyObject_GC_Del, // tp_dealloc
89 0,
90 0,
91 0,
92 0,
93 0,
94 0,
95 0,
96 &ia_as_mapping, // tp_as_mapping
97 0,
98 0,
99 0,
100 0,
101 0,
102 0,
103 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, // tp_flags
104 0,
105 (traverseproc)ia_traverse, // tp_traverse
106 0,
107 0,
108 0,
109 PyObject_SelfIter, // tp_iter
110 (iternextfunc)ia_iternext, // tp_iternext
111 0,
112 0,
113 ia_getset, // tp_getset
114 0,
115 0,
116 0,
117 0,
118 0,
119 0,
120 0,
121 0,
122 0,
123 0,
124 0,
125 0,
126 0,
127 0,
128 0,
129 0, // tp_del
130 0, // tp_version_tag
131 0, // tp_finalize
132 0 // tp_vectorcall
134
135//= support for C-style arrays of objects ====================================
137 interop::TCppScope_t klass, cdims_t dims) {
138 // recursively set up tuples of instances on all dimensions
139 if (dims.ndim() == UNKNOWN_SIZE ||
140 dims[0] == UNKNOWN_SIZE /* unknown shape or size */) {
141 // no known length ... return an iterable object and let the user figure it
142 // out
143 ia_iterobject* ia = PyObject_GC_New(ia_iterobject, &InstanceArrayIter_Type);
144 if (!ia)
145 return nullptr;
146
147 ia->ia_klass = klass;
148 ia->ia_array_start = address.data;
149 ia->ia_pos = 0;
150 ia->ia_len = -1;
151 ia->ia_stride = interop::SizeOf(klass);
152
153 PyObject_GC_Track(ia);
154 return (PyObject*)ia;
155 } else if (1 < dims.ndim()) {
156 // not the innermost dimension, descend one level
157 size_t block_size = 1;
158 for (Py_ssize_t i = 1; i < dims.ndim(); ++i) {
159 if (dims[i] != 0)
160 block_size *= (size_t)dims[i];
161 }
162 block_size *= interop::SizeOf(klass);
163
164 Py_ssize_t nelems = dims[0];
165 PyObject* tup = PyTuple_New(nelems);
166 for (Py_ssize_t i = 0; i < nelems; ++i) {
167 PyTuple_SetItem(
168 tup, i,
169 TupleOfInstances_New(((char*)address.data) + i * block_size, klass,
170 dims.sub()));
171 }
172 return tup;
173 } else {
174 // innermost dimension: construct tuple
175 int nelems = (int)dims[0];
176 size_t block_size = interop::SizeOf(klass);
177 if (block_size == 0) {
178 PyErr_Format(PyExc_TypeError,
179 "can not determine size of type \"%s\" for array indexing",
180 interop::GetScopedFinalName(klass).c_str());
181 return nullptr;
182 }
183
184 // TODO: the extra copy is inefficient, but it appears that the only way to
185 // initialize a subclass of a tuple is through a sequence
186 PyObject* tup = PyTuple_New(nelems);
187 for (int i = 0; i < nelems; ++i) {
188 // TODO: there's an assumption here that there is no padding, which is
189 // bound to be incorrect in certain cases
190 PyTuple_SetItem(
191 tup, i,
192 BindCppObjectNoCast(((char*)address.data) + i * block_size, klass));
193 // Note: objects are bound as pointers, yet since the pointer value stays
194 // in place, updates propagate just as if they were bound by-reference
195 }
196
197 PyObject* args = PyTuple_New(1);
198 Py_INCREF(tup);
199 PyTuple_SET_ITEM(args, 0, tup);
200 PyObject* arr = PyTuple_Type.tp_new(&TupleOfInstances_Type, args, nullptr);
201
202 Py_DECREF(args);
203 // tup ref eaten by SET_ITEM on args
204
205 return arr;
206 }
207
208 // never get here
209 return nullptr;
210}
211
212//= cpyrt custom tuple-like array type ====================================
213PyTypeObject TupleOfInstances_Type = {
214 PyVarObject_HEAD_INIT(&PyType_Type,
215 0)(char*) "cppjit.InstancesArray", // tp_name
216 0, // tp_basicsize
217 0, // tp_itemsize
218 0, // tp_dealloc
219 0, // tp_vectorcall_offset / tp_print
220 0, // tp_getattr
221 0, // tp_setattr
222 0, // tp_as_async / tp_compare
223 0, // tp_repr
224 0, // tp_as_number
225 0, // tp_as_sequence
226 0, // tp_as_mapping
227 0, // tp_hash
228 0, // tp_call
229 0, // tp_str
230 0, // tp_getattro
231 0, // tp_setattro
232 0, // tp_as_buffer
233 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, // tp_flags
234 (char*)"array of C++ instances", // tp_doc
235 0, // tp_traverse
236 0, // tp_clear
237 0, // tp_richcompare
238 0, // tp_weaklistoffset
239 0, // tp_iter
240 0, // tp_iternext
241 0, // tp_methods
242 0, // tp_members
243 0, // tp_getset
244 &PyTuple_Type, // tp_base
245 0, // tp_dict
246 0, // tp_descr_get
247 0, // tp_descr_set
248 0, // tp_dictoffset
249 0, // tp_init
250 0, // tp_alloc
251 0, // tp_new
252 0, // tp_free
253 0, // tp_is_gc
254 0, // tp_bases
255 0, // tp_mro
256 0, // tp_cache
257 0, // tp_subclasses
258 0, // tp_weaklist
259 0, // tp_del
260 0, // tp_version_tag
261 0, // tp_finalize
262 0 // tp_vectorcall
264
265} // namespace cppjit::cpyrt
_object PyObject
size_t size(const MatrixT &matrix)
retrieve the size of a square matrix
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t result
Dimensions sub() const
Definition Dimensions.h:80
#define CPYRT_PYTYPE_TAIL
Definition cpyrt.h:159
PyTypeObject TupleOfInstances_Type
Representation of C-style array of instances.
PyTypeObject InstanceArrayIter_Type
PyObject * TupleOfInstances_New(interop::TCppObject_t address, interop::TCppScope_t klass, cdims_t dims)
static const dim_t UNKNOWN_SIZE
Definition Dimensions.h:16
PyObject * BindCppObjectNoCast(interop::TCppObject_t object, interop::TCppScope_t klass, const unsigned flags=0)
Cpp::ObjectRef TCppObject_t
Definition API.h:43
size_t SizeOf(TCppScope_t klass)
std::string GetScopedFinalName(TCppScope_t type)
Cpp::DeclRef TCppScope_t
Definition API.h:41
Definition API.cxx:34