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 {
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.
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
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
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,
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
121};
122
123
124//= support for C-style arrays of objects ====================================
127{
128// recursively set up tuples of instances on all dimensions
129 if (dims.ndim() == UNKNOWN_SIZE || dims[0] == UNKNOWN_SIZE /* unknown shape or size */) {
130 // no known length ... return an iterable object and let the user figure it out
131 ia_iterobject* ia = PyObject_GC_New(ia_iterobject, &InstanceArrayIter_Type);
132 if (!ia) return nullptr;
133
134 ia->ia_klass = klass;
135 ia->ia_array_start = address;
136 ia->ia_pos = 0;
137 ia->ia_len = -1;
138 ia->ia_stride = Cppyy::SizeOf(klass);
139
141 return (PyObject*)ia;
142 } else if (1 < dims.ndim()) {
143 // not the innermost dimension, descend one level
144 size_t block_size = 0;
145 for (Py_ssize_t i = 1; i < dims.ndim(); ++i) block_size += (size_t)dims[i];
147
150 for (Py_ssize_t i = 0; i < nelems; ++i) {
152 (char*)address + i*block_size, klass, dims.sub()));
153 }
154 return tup;
155 } else {
156 // innermost dimension: construct tuple
157 int nelems = (int)dims[0];
159 if (block_size == 0) {
161 "can not determine size of type \"%s\" for array indexing",
163 return nullptr;
164 }
165
166 // TODO: the extra copy is inefficient, but it appears that the only way to
167 // initialize a subclass of a tuple is through a sequence
169 for (int i = 0; i < nelems; ++i) {
170 // TODO: there's an assumption here that there is no padding, which is bound
171 // to be incorrect in certain cases
173 BindCppObjectNoCast((char*)address + i*block_size, klass));
174 // Note: objects are bound as pointers, yet since the pointer value stays in
175 // place, updates propagate just as if they were bound by-reference
176 }
177
178 PyObject* args = PyTuple_New(1);
179 Py_INCREF(tup); PyTuple_SET_ITEM(args, 0, tup);
180 PyObject* arr = PyTuple_Type.tp_new(&TupleOfInstances_Type, args, nullptr);
181
182 Py_DECREF(args);
183 // tup ref eaten by SET_ITEM on args
184
185 return arr;
186 }
187
188// never get here
189 return nullptr;
190}
191
192//= CPyCppyy custom tuple-like array type ====================================
195 (char*)"cppyy.InstancesArray", // tp_name
196 0, // tp_basicsize
197 0, // tp_itemsize
198 0, // tp_dealloc
199 0, // tp_vectorcall_offset / tp_print
200 0, // tp_getattr
201 0, // tp_setattr
202 0, // tp_as_async / tp_compare
203 0, // tp_repr
204 0, // tp_as_number
205 0, // tp_as_sequence
206 0, // tp_as_mapping
207 0, // tp_hash
208 0, // tp_call
209 0, // tp_str
210 0, // tp_getattro
211 0, // tp_setattro
212 0, // tp_as_buffer
214 Py_TPFLAGS_BASETYPE, // tp_flags
215 (char*)"array of C++ instances", // tp_doc
216 0, // tp_traverse
217 0, // tp_clear
218 0, // tp_richcompare
219 0, // tp_weaklistoffset
220 0, // tp_iter
221 0, // tp_iternext
222 0, // tp_methods
223 0, // tp_members
224 0, // tp_getset
225 &PyTuple_Type, // tp_base
226 0, // tp_dict
227 0, // tp_descr_get
228 0, // tp_descr_set
229 0, // tp_dictoffset
230 0, // tp_init
231 0, // tp_alloc
232 0, // tp_new
233 0, // tp_free
234 0, // tp_is_gc
235 0, // tp_bases
236 0, // tp_mro
237 0, // tp_cache
238 0, // tp_subclasses
239 0 // tp_weaklist
240#if PY_VERSION_HEX >= 0x02030000
241 , 0 // tp_del
242#endif
243#if PY_VERSION_HEX >= 0x02060000
244 , 0 // tp_version_tag
245#endif
246#if PY_VERSION_HEX >= 0x03040000
247 , 0 // tp_finalize
248#endif
249#if PY_VERSION_HEX >= 0x03080000
250 , 0 // tp_vectorcall
251#endif
253};
254
255} // 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 CPYCPPYY_PYTYPE_TAIL
Definition CPyCppyy.h:412
#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
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
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
PyObject * BindCppObjectNoCast(Cppyy::TCppObject_t object, Cppyy::TCppType_t klass, const unsigned flags=0)
static const dim_t UNKNOWN_SIZE
Definition Dimensions.h:14
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:37
TCppScope_t TCppType_t
Definition cpp_cppyy.h:35
RPY_EXPORTED std::string GetScopedFinalName(TCppType_t type)