arraykit 1.2.0__cp314-cp314t-win_amd64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,251 @@
1
+ # include "Python.h"
2
+
3
+ # define NO_IMPORT_ARRAY
4
+ # define PY_ARRAY_UNIQUE_SYMBOL AK_ARRAY_API
5
+ # define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
6
+
7
+ # include "numpy/arrayobject.h"
8
+
9
+ # include "array_to_tuple.h"
10
+ # include "utilities.h"
11
+
12
+ // Given a 1D or 2D array, return a 1D object array of tuples.
13
+ PyObject *
14
+ array_to_tuple_array(PyObject *Py_UNUSED(m), PyObject *a)
15
+ {
16
+ AK_CHECK_NUMPY_ARRAY(a);
17
+ PyArrayObject *input_array = (PyArrayObject *)a;
18
+ int ndim = PyArray_NDIM(input_array);
19
+ if (ndim != 1 && ndim != 2) {
20
+ return PyErr_Format(PyExc_NotImplementedError,
21
+ "Expected 1D or 2D array, not %i.",
22
+ ndim);
23
+ }
24
+
25
+ npy_intp num_rows = PyArray_DIM(input_array, 0);
26
+ npy_intp dims[] = {num_rows};
27
+ // NOTE: this initializes values to NULL, not None
28
+ PyObject* output = PyArray_SimpleNew(1, dims, NPY_OBJECT);
29
+ if (output == NULL) {
30
+ return NULL;
31
+ }
32
+
33
+ PyObject** output_data = (PyObject**)PyArray_DATA((PyArrayObject*)output);
34
+ PyObject** p = output_data;
35
+ PyObject** p_end = p + num_rows;
36
+ npy_intp i = 0;
37
+ PyObject* tuple;
38
+ PyObject* item;
39
+
40
+ if (ndim == 2) {
41
+ npy_intp num_cols = PyArray_DIM(input_array, 1);
42
+ npy_intp j;
43
+ while (p < p_end) {
44
+ tuple = PyTuple_New(num_cols);
45
+ if (tuple == NULL) {
46
+ goto error;
47
+ }
48
+ for (j = 0; j < num_cols; ++j) {
49
+ // cannot assume input_array is contiguous
50
+ item = PyArray_ToScalar(PyArray_GETPTR2(input_array, i, j), input_array);
51
+ if (item == NULL) {
52
+ Py_DECREF(tuple);
53
+ goto error;
54
+ }
55
+ PyTuple_SET_ITEM(tuple, j, item); // steals reference to item
56
+ }
57
+ *p++ = tuple; // assign with new ref, no incr needed
58
+ i++;
59
+ }
60
+ }
61
+ else if (PyArray_TYPE(input_array) != NPY_OBJECT) { // ndim == 1, not object
62
+ while (p < p_end) {
63
+ tuple = PyTuple_New(1);
64
+ if (tuple == NULL) {
65
+ goto error;
66
+ }
67
+ // scalar returned in is native PyObject from object arrays
68
+ item = PyArray_ToScalar(PyArray_GETPTR1(input_array, i), input_array);
69
+ if (item == NULL) {
70
+ Py_DECREF(tuple);
71
+ goto error;
72
+ }
73
+ PyTuple_SET_ITEM(tuple, 0, item); // steals reference to item
74
+ *p++ = tuple; // assign with new ref, no incr needed
75
+ i++;
76
+ }
77
+ }
78
+ else { // ndim == 1, object
79
+ while (p < p_end) {
80
+ item = *(PyObject**)PyArray_GETPTR1(input_array, i);
81
+ Py_INCREF(item); // always incref
82
+ if (PyTuple_Check(item)) {
83
+ tuple = item; // do not double pack
84
+ }
85
+ else {
86
+ tuple = PyTuple_New(1);
87
+ if (tuple == NULL) {
88
+ goto error;
89
+ }
90
+ PyTuple_SET_ITEM(tuple, 0, item); // steals reference to item
91
+ }
92
+ *p++ = tuple; // assign with new ref, no incr needed
93
+ i++;
94
+ }
95
+ }
96
+ PyArray_CLEARFLAGS((PyArrayObject *)output, NPY_ARRAY_WRITEABLE);
97
+ return output;
98
+ error:
99
+ p = output_data;
100
+ p_end = p + num_rows;
101
+ while (p < p_end) { // decref all tuples within array
102
+ Py_XDECREF(*p++); // xdec as might be NULL
103
+ }
104
+ Py_DECREF(output);
105
+ return NULL;
106
+ }
107
+
108
+ //------------------------------------------------------------------------------
109
+ // ArrayToTupleIterator
110
+
111
+ static PyTypeObject ATTType;
112
+
113
+ typedef struct ATTObject {
114
+ PyObject_HEAD
115
+ PyArrayObject* array;
116
+ npy_intp num_rows;
117
+ npy_intp num_cols;
118
+ Py_ssize_t pos; // current index state, mutated in-place
119
+ } ATTObject;
120
+
121
+ static inline PyObject *
122
+ ATT_new(PyArrayObject* array,
123
+ npy_intp num_rows,
124
+ npy_intp num_cols) {
125
+ ATTObject* a2dt = PyObject_New(ATTObject, &ATTType);
126
+ if (!a2dt) {
127
+ return NULL;
128
+ }
129
+ Py_INCREF((PyObject*)array);
130
+ a2dt->array = array;
131
+ a2dt->num_rows = num_rows;
132
+ a2dt->num_cols = num_cols; // -1 for 1D array
133
+ a2dt->pos = 0;
134
+ return (PyObject *)a2dt;
135
+ }
136
+
137
+ static inline void
138
+ ATT_dealloc(ATTObject *self) {
139
+ Py_DECREF((PyObject*)self->array);
140
+ PyObject_Del((PyObject*)self);
141
+ }
142
+
143
+ static inline PyObject*
144
+ ATT_iter(ATTObject *self) {
145
+ Py_INCREF(self);
146
+ return (PyObject*)self;
147
+ }
148
+
149
+ static inline PyObject *
150
+ ATT_iternext(ATTObject *self) {
151
+ Py_ssize_t i = self->pos;
152
+ if (i < self->num_rows) {
153
+ npy_intp num_cols = self->num_cols;
154
+ PyArrayObject* array = self->array;
155
+ PyObject* item;
156
+ PyObject* tuple;
157
+
158
+ if (num_cols > -1) { // ndim == 2
159
+ tuple = PyTuple_New(num_cols);
160
+ if (tuple == NULL) {
161
+ return NULL;
162
+ }
163
+ for (npy_intp j = 0; j < num_cols; ++j) {
164
+ // cannot assume array is contiguous
165
+ item = PyArray_ToScalar(PyArray_GETPTR2(array, i, j), array);
166
+ if (item == NULL) {
167
+ Py_DECREF(tuple);
168
+ return NULL;
169
+ }
170
+ PyTuple_SET_ITEM(tuple, j, item); // steals ref
171
+ }
172
+ }
173
+ else if (PyArray_TYPE(array) != NPY_OBJECT) { // ndim == 1, not object
174
+ tuple = PyTuple_New(1);
175
+ if (tuple == NULL) {
176
+ return NULL;
177
+ }
178
+ item = PyArray_ToScalar(PyArray_GETPTR1(array, i), array);
179
+ if (item == NULL) {
180
+ Py_DECREF(tuple);
181
+ return NULL;
182
+ }
183
+ PyTuple_SET_ITEM(tuple, 0, item); // steals ref
184
+ }
185
+ else { // ndim == 1, object
186
+ item = *(PyObject**)PyArray_GETPTR1(array, i);
187
+ Py_INCREF(item); // always incref
188
+ if (PyTuple_Check(item)) {
189
+ tuple = item; // do not double pack
190
+ }
191
+ else {
192
+ tuple = PyTuple_New(1);
193
+ if (tuple == NULL) {
194
+ Py_DECREF(item);
195
+ return NULL;
196
+ }
197
+ PyTuple_SET_ITEM(tuple, 0, item); // steals ref
198
+ }
199
+ }
200
+ self->pos++;
201
+ return tuple;
202
+ }
203
+ return NULL;
204
+ }
205
+
206
+ // static PyObject *
207
+ // ATT_reversed(ATTObject *self) {
208
+ // return ATT_new(self->bi, !self->reversed);
209
+ // }
210
+
211
+ static inline PyObject *
212
+ ATT_length_hint(ATTObject *self) {
213
+ Py_ssize_t len = Py_MAX(0, self->num_rows - self->pos);
214
+ return PyLong_FromSsize_t(len);
215
+ }
216
+
217
+ static PyMethodDef ATT_methods[] = {
218
+ {"__length_hint__", (PyCFunction)ATT_length_hint, METH_NOARGS, NULL},
219
+ // {"__reversed__", (PyCFunction)ATT_reversed, METH_NOARGS, NULL},
220
+ {NULL},
221
+ };
222
+
223
+ static PyTypeObject ATTType = {
224
+ PyVarObject_HEAD_INIT(NULL, 0)
225
+ .tp_basicsize = sizeof(ATTObject),
226
+ .tp_dealloc = (destructor) ATT_dealloc,
227
+ .tp_iter = (getiterfunc) ATT_iter,
228
+ .tp_iternext = (iternextfunc) ATT_iternext,
229
+ .tp_methods = ATT_methods,
230
+ .tp_name = "arraykit.ATTIterator",
231
+ };
232
+
233
+ // Given a 2D array, return an iterator of row tuples.
234
+ PyObject *
235
+ array_to_tuple_iter(PyObject *Py_UNUSED(m), PyObject *a)
236
+ {
237
+ AK_CHECK_NUMPY_ARRAY(a);
238
+ PyArrayObject *array = (PyArrayObject *)a;
239
+ int ndim = PyArray_NDIM(array);
240
+ if (ndim != 1 && ndim != 2) {
241
+ return PyErr_Format(PyExc_NotImplementedError,
242
+ "Expected 1D or 2D array, not %i.",
243
+ ndim);
244
+ }
245
+ npy_intp num_rows = PyArray_DIM(array, 0);
246
+ npy_intp num_cols = -1; // indicate 1d
247
+ if (ndim == 2) {
248
+ num_cols = PyArray_DIM(array, 1);
249
+ }
250
+ return ATT_new(array, num_rows, num_cols);
251
+ }
@@ -0,0 +1,14 @@
1
+ # ifndef ARRAYKIT_SRC_ARRAY_TO_TUPLE_H_
2
+ # define ARRAYKIT_SRC_ARRAY_TO_TUPLE_H_
3
+
4
+ # include "Python.h"
5
+
6
+ // Given a 1D or 2D array, return a 1D object array of tuples.
7
+ PyObject *
8
+ array_to_tuple_array(PyObject *Py_UNUSED(m), PyObject *a);
9
+
10
+ // Given a 2D array, return an iterator of row tuples.
11
+ PyObject *
12
+ array_to_tuple_iter(PyObject *Py_UNUSED(m), PyObject *a);
13
+
14
+ # endif // ARRAYKIT_SRC_ARRAY_TO_TUPLE_H_