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