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