File: | /tmp/pyrefcon/scipy/scipy/sparse/sparsetools/sparsetools.cxx |
Warning: | line 569, column 9 PyObject ownership leak with reference count of 1 |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* | |||
2 | * sparsetools.cxx | |||
3 | * | |||
4 | * Python module wrapping the sparsetools C++ routines. | |||
5 | * | |||
6 | * Each C++ routine is templated vs. an integer (I) and a data (T) parameter. | |||
7 | * The `generate_sparsetools.py` script generates `*_impl.h` headers | |||
8 | * that contain thunk functions with a datatype-based switch statement calling | |||
9 | * each templated instantiation. | |||
10 | * | |||
11 | * `generate_sparsetools.py` also generates a PyMethodDef list of Python | |||
12 | * routines and the corresponding functions call the thunk functions via | |||
13 | * `call_thunk`. | |||
14 | * | |||
15 | * The `call_thunk` function below determines the templated I and T data types | |||
16 | * based on the Python arguments. It then allocates arrays with pointers to | |||
17 | * the raw data, with appropriate types, and calls the thunk function after | |||
18 | * that. | |||
19 | * | |||
20 | * The types of arguments are specified by a "spec". This is given in a format | |||
21 | * where one character represents one argument. The one-character values are | |||
22 | * listed below in the call_spec function. | |||
23 | */ | |||
24 | ||||
25 | #define PY_ARRAY_UNIQUE_SYMBOL_scipy_sparse_sparsetools_ARRAY_API _scipy_sparse_sparsetools_ARRAY_API | |||
26 | ||||
27 | #include <Python.h> | |||
28 | ||||
29 | #include <string> | |||
30 | #include <stdexcept> | |||
31 | #include <vector> | |||
32 | #include <cstdlib> | |||
33 | ||||
34 | #include "numpy/ndarrayobject.h" | |||
35 | ||||
36 | #include "sparsetools.h" | |||
37 | #include "util.h" | |||
38 | ||||
39 | #define MAX_ARGS16 16 | |||
40 | ||||
41 | #if NPY_API_VERSION0x0000000D >= 0x0000000c | |||
42 | #define HAVE_WRITEBACKIFCOPY | |||
43 | #endif | |||
44 | ||||
45 | static const int supported_I_typenums[] = {NPY_INT32NPY_INT, NPY_INT64NPY_LONG}; | |||
46 | static const int n_supported_I_typenums = sizeof(supported_I_typenums) / sizeof(int); | |||
47 | ||||
48 | static const int supported_T_typenums[] = {NPY_BOOL, | |||
49 | NPY_BYTE, NPY_UBYTE, | |||
50 | NPY_SHORT, NPY_USHORT, | |||
51 | NPY_INT, NPY_UINT, | |||
52 | NPY_LONG, NPY_ULONG, | |||
53 | NPY_LONGLONG, NPY_ULONGLONG, | |||
54 | NPY_FLOAT, NPY_DOUBLE, NPY_LONGDOUBLE, | |||
55 | NPY_CFLOAT, NPY_CDOUBLE, NPY_CLONGDOUBLE}; | |||
56 | static const int n_supported_T_typenums = sizeof(supported_T_typenums) / sizeof(int); | |||
57 | ||||
58 | static PyObject *array_from_std_vector_and_free(int typenum, void *p); | |||
59 | static void *allocate_std_vector_typenum(int typenum); | |||
60 | static void free_std_vector_typenum(int typenum, void *p); | |||
61 | static PyObject *c_array_from_object(PyObject *obj, int typenum, int is_output); | |||
62 | ||||
63 | ||||
64 | /* | |||
65 | * Call a thunk function, dealing with input and output arrays. | |||
66 | * | |||
67 | * Resolves the templated <integer> and <data> dtypes from the `args` argument | |||
68 | * list. | |||
69 | * | |||
70 | * Parameters | |||
71 | * ---------- | |||
72 | * ret_spec : {'i', 'v'} | |||
73 | * Return value spec. 'i' for integer, 'v' for void. | |||
74 | * spec | |||
75 | * String whose each character specifies a types of an | |||
76 | * argument: | |||
77 | * | |||
78 | * 'i': <integer> scalar | |||
79 | * 'I': <integer> array | |||
80 | * 'T': <data> array | |||
81 | * 'V': std::vector<integer> | |||
82 | * 'W': std::vector<data> | |||
83 | * 'B': npy_bool array | |||
84 | * '*': indicates that the next argument is an output argument | |||
85 | * thunk : PY_LONG_LONG thunk(int I_typenum, int T_typenum, void **) | |||
86 | * Thunk function to call. It is passed a void** array of pointers to | |||
87 | * arguments, constructed according to `spec`. The types of data pointed | |||
88 | * to by each element agree with I_typenum and T_typenum, or are bools. | |||
89 | * args | |||
90 | * Python tuple containing unprocessed arguments. | |||
91 | * | |||
92 | * Returns | |||
93 | * ------- | |||
94 | * return_value | |||
95 | * The Python return value | |||
96 | * | |||
97 | */ | |||
98 | NPY_VISIBILITY_HIDDEN__attribute__((visibility("hidden"))) PyObject * | |||
99 | call_thunk(char ret_spec, const char *spec, thunk_t *thunk, PyObject *args) | |||
100 | { | |||
101 | void *arg_list[MAX_ARGS16]; | |||
102 | PyObject *arg_arrays[MAX_ARGS16]; | |||
103 | int is_output[MAX_ARGS16]; | |||
104 | PyObject *return_value = NULL__null; | |||
105 | int I_typenum = NPY_INT32NPY_INT; | |||
106 | int T_typenum = -1; | |||
107 | int VW_count = 0; | |||
108 | int I_in_arglist = 0; | |||
109 | int T_in_arglist = 0; | |||
110 | int next_is_output = 0; | |||
111 | int j, k, arg_j; | |||
112 | const char *p; | |||
113 | PY_LONG_LONGlong long ret; | |||
114 | Py_ssize_t max_array_size = 0; | |||
115 | NPY_BEGIN_THREADS_DEFPyThreadState *_save=__null;; | |||
116 | ||||
117 | if (!PyTuple_Check(args)((((((PyObject*)(args))->ob_type))->tp_flags & ((1UL << 26))) != 0)) { | |||
118 | PyErr_SetString(PyExc_ValueError, "args is not a tuple"); | |||
119 | return NULL__null; | |||
120 | } | |||
121 | ||||
122 | for (j = 0; j < MAX_ARGS16; ++j) { | |||
123 | arg_list[j] = NULL__null; | |||
124 | arg_arrays[j] = NULL__null; | |||
125 | is_output[j] = 0; | |||
126 | } | |||
127 | ||||
128 | ||||
129 | /* | |||
130 | * Detect data types in the signature | |||
131 | */ | |||
132 | arg_j = 0; | |||
133 | j = 0; | |||
134 | for (p = spec; *p != '\0'; ++p, ++j, ++arg_j) { | |||
135 | const int *supported_typenums; | |||
136 | int n_supported_typenums; | |||
137 | int cur_typenum; | |||
138 | PyObject *arg; | |||
139 | ||||
140 | if (j >= MAX_ARGS16) { | |||
141 | PyErr_SetString(PyExc_ValueError, | |||
142 | "internal error: too many arguments in spec"); | |||
143 | goto fail; | |||
144 | } | |||
145 | ||||
146 | is_output[j] = next_is_output; | |||
147 | next_is_output = 0; | |||
148 | ||||
149 | switch (*p) { | |||
150 | case '*': | |||
151 | next_is_output = 1; | |||
152 | --j; | |||
153 | --arg_j; | |||
154 | continue; | |||
155 | case 'i': | |||
156 | case 'l': | |||
157 | /* Integer scalars */ | |||
158 | arg = PyTuple_GetItem(args, arg_j); | |||
159 | if (arg == NULL__null) { | |||
160 | goto fail; | |||
161 | } | |||
162 | Py_INCREF(arg)_Py_INCREF(((PyObject*)(arg))); | |||
163 | arg_arrays[j] = arg; | |||
164 | continue; | |||
165 | case 'I': | |||
166 | /* Integer arrays */ | |||
167 | supported_typenums = supported_I_typenums; | |||
168 | n_supported_typenums = n_supported_I_typenums; | |||
169 | cur_typenum = I_typenum; | |||
170 | I_in_arglist = 1; | |||
171 | break; | |||
172 | case 'T': | |||
173 | /* Data arrays */ | |||
174 | supported_typenums = supported_T_typenums; | |||
175 | n_supported_typenums = n_supported_T_typenums; | |||
176 | cur_typenum = T_typenum; | |||
177 | T_in_arglist = 1; | |||
178 | break; | |||
179 | case 'B': | |||
180 | /* Boolean arrays */ | |||
181 | arg = PyTuple_GetItem(args, arg_j); | |||
182 | if (arg == NULL__null) { | |||
183 | goto fail; | |||
184 | } | |||
185 | arg_arrays[j] = c_array_from_object(arg, NPY_BOOL, is_output[j]); | |||
186 | if (arg_arrays[j] == NULL__null) { | |||
187 | goto fail; | |||
188 | } | |||
189 | continue; | |||
190 | case 'V': | |||
191 | /* std::vector integer output array */ | |||
192 | I_in_arglist = 1; | |||
193 | --arg_j; | |||
194 | VW_count += 1; | |||
195 | continue; | |||
196 | case 'W': | |||
197 | /* std::vector data output array */ | |||
198 | T_in_arglist = 1; | |||
199 | --arg_j; | |||
200 | VW_count += 1; | |||
201 | continue; | |||
202 | default: | |||
203 | PyErr_SetString(PyExc_ValueError, "unknown character in spec"); | |||
204 | goto fail; | |||
205 | } | |||
206 | ||||
207 | arg = PyTuple_GetItem(args, arg_j); | |||
208 | if (arg == NULL__null) { | |||
209 | goto fail; | |||
210 | } | |||
211 | arg_arrays[j] = c_array_from_object(arg, -1, is_output[j]); | |||
212 | if (arg_arrays[j] == NULL__null) { | |||
213 | goto fail; | |||
214 | } | |||
215 | ||||
216 | /* Find a compatible supported data type */ | |||
217 | ||||
218 | for (k = 0; k < n_supported_typenums; ++k) { | |||
219 | if (PyArray_CanCastSafely(*(int (*)(int, int)) _scipy_sparse_sparsetools_ARRAY_API[52] )(PyArray_TYPE((PyArrayObject *)arg_arrays[j]), supported_typenums[k]) && | |||
220 | (cur_typenum == -1 || PyArray_CanCastSafely(*(int (*)(int, int)) _scipy_sparse_sparsetools_ARRAY_API[52] )(cur_typenum, supported_typenums[k]))) | |||
221 | { | |||
222 | cur_typenum = supported_typenums[k]; | |||
223 | break; | |||
224 | } | |||
225 | } | |||
226 | if (k == n_supported_typenums) { | |||
227 | PyErr_SetString(PyExc_ValueError, | |||
228 | "unsupported data types in input"); | |||
229 | goto fail; | |||
230 | } | |||
231 | ||||
232 | if (*p == 'I') { | |||
233 | I_typenum = cur_typenum; | |||
234 | } | |||
235 | else { | |||
236 | T_typenum = cur_typenum; | |||
237 | } | |||
238 | } | |||
239 | ||||
240 | if (arg_j != PyTuple_Size(args)) { | |||
241 | PyErr_SetString(PyExc_ValueError, "too many arguments"); | |||
242 | goto fail; | |||
243 | } | |||
244 | ||||
245 | if ((I_in_arglist && I_typenum == -1) || | |||
246 | (T_in_arglist && T_typenum == -1)) { | |||
247 | PyErr_SetString(PyExc_ValueError, | |||
248 | "unsupported data types in input"); | |||
249 | goto fail; | |||
250 | } | |||
251 | ||||
252 | ||||
253 | /* | |||
254 | * Cast and extract argument arrays | |||
255 | */ | |||
256 | j = 0; | |||
257 | for (p = spec; *p != '\0'; ++p, ++j) { | |||
258 | PyObject *arg; | |||
259 | int cur_typenum; | |||
260 | ||||
261 | if (*p == '*') { | |||
262 | --j; | |||
263 | continue; | |||
264 | } | |||
265 | else if (*p == 'i' || *p == 'l') { | |||
266 | /* Integer scalars */ | |||
267 | PY_LONG_LONGlong long value; | |||
268 | ||||
269 | value = PyLong_AsLongLong(arg_arrays[j]); | |||
270 | if (PyErr_Occurred()) { | |||
271 | goto fail; | |||
272 | } | |||
273 | ||||
274 | if ((*p == 'l' || PyArray_EquivTypenums(*(unsigned char (*)(int, int)) _scipy_sparse_sparsetools_ARRAY_API [191])(I_typenum, NPY_INT64NPY_LONG)) | |||
275 | && value == (npy_int64)value) { | |||
276 | arg_list[j] = std::malloc(sizeof(npy_int64)); | |||
277 | *(npy_int64*)arg_list[j] = (npy_int64)value; | |||
278 | } | |||
279 | else if (*p == 'i' && PyArray_EquivTypenums(*(unsigned char (*)(int, int)) _scipy_sparse_sparsetools_ARRAY_API [191])(I_typenum, NPY_INT32NPY_INT) | |||
280 | && value == (npy_int32)value) { | |||
281 | arg_list[j] = std::malloc(sizeof(npy_int32)); | |||
282 | *(npy_int32*)arg_list[j] = (npy_int32)value; | |||
283 | } | |||
284 | else { | |||
285 | PyErr_SetString(PyExc_ValueError, | |||
286 | "could not convert integer scalar"); | |||
287 | goto fail; | |||
288 | } | |||
289 | continue; | |||
290 | } | |||
291 | else if (*p == 'B') { | |||
292 | /* Boolean arrays already cast */ | |||
293 | } | |||
294 | else if (*p == 'V') { | |||
295 | arg_list[j] = allocate_std_vector_typenum(I_typenum); | |||
296 | if (arg_list[j] == NULL__null) { | |||
297 | goto fail; | |||
298 | } | |||
299 | continue; | |||
300 | } | |||
301 | else if (*p == 'W') { | |||
302 | arg_list[j] = allocate_std_vector_typenum(T_typenum); | |||
303 | if (arg_list[j] == NULL__null) { | |||
304 | goto fail; | |||
305 | } | |||
306 | continue; | |||
307 | } | |||
308 | else { | |||
309 | cur_typenum = (*p == 'I' || *p == 'i') ? I_typenum : T_typenum; | |||
310 | ||||
311 | /* Cast if necessary */ | |||
312 | arg = arg_arrays[j]; | |||
313 | if (PyArray_EquivTypenums(*(unsigned char (*)(int, int)) _scipy_sparse_sparsetools_ARRAY_API [191])(PyArray_TYPE((PyArrayObject *)arg), cur_typenum)) { | |||
314 | /* No cast needed. */ | |||
315 | } | |||
316 | else if (!is_output[j] || PyArray_CanCastSafely(*(int (*)(int, int)) _scipy_sparse_sparsetools_ARRAY_API[52] )(cur_typenum, PyArray_TYPE((PyArrayObject *)arg))) { | |||
317 | /* Cast needed. Output arrays require safe cast back. */ | |||
318 | arg_arrays[j] = c_array_from_object(arg, cur_typenum, is_output[j]); | |||
319 | Py_DECREF(arg)_Py_DECREF(((PyObject*)(arg))); | |||
320 | if (arg_arrays[j] == NULL__null) { | |||
321 | goto fail; | |||
322 | } | |||
323 | } | |||
324 | else { | |||
325 | /* Cast back into output array was not safe. */ | |||
326 | PyErr_SetString(PyExc_ValueError, | |||
327 | "Output dtype not compatible with inputs."); | |||
328 | goto fail; | |||
329 | } | |||
330 | } | |||
331 | ||||
332 | /* Grab value */ | |||
333 | arg_list[j] = PyArray_DATA((PyArrayObject *)arg_arrays[j]); | |||
334 | ||||
335 | /* Find maximum array size */ | |||
336 | if (PyArray_SIZE((PyArrayObject *)arg_arrays[j])(*(npy_intp (*)(npy_intp const *, int)) _scipy_sparse_sparsetools_ARRAY_API [158])(PyArray_DIMS((PyArrayObject *)arg_arrays[j]), PyArray_NDIM ((PyArrayObject *)arg_arrays[j])) > max_array_size) { | |||
337 | max_array_size = PyArray_SIZE((PyArrayObject *)arg_arrays[j])(*(npy_intp (*)(npy_intp const *, int)) _scipy_sparse_sparsetools_ARRAY_API [158])(PyArray_DIMS((PyArrayObject *)arg_arrays[j]), PyArray_NDIM ((PyArrayObject *)arg_arrays[j])); | |||
338 | } | |||
339 | } | |||
340 | ||||
341 | ||||
342 | /* | |||
343 | * Call thunk | |||
344 | */ | |||
345 | if (max_array_size > 100) { | |||
346 | /* Threshold GIL release: it's not a free operation */ | |||
347 | NPY_BEGIN_THREADSdo {_save = PyEval_SaveThread();} while (0);; | |||
348 | } | |||
349 | try { | |||
350 | ret = thunk(I_typenum, T_typenum, arg_list); | |||
351 | NPY_END_THREADSdo { if (_save) { PyEval_RestoreThread(_save); _save = __null ;} } while (0);; | |||
352 | } catch (const std::bad_alloc &e) { | |||
353 | NPY_END_THREADSdo { if (_save) { PyEval_RestoreThread(_save); _save = __null ;} } while (0);; | |||
354 | PyErr_SetString(PyExc_MemoryError, e.what()); | |||
355 | goto fail; | |||
356 | } catch (const std::exception &e) { | |||
357 | NPY_END_THREADSdo { if (_save) { PyEval_RestoreThread(_save); _save = __null ;} } while (0);; | |||
358 | PyErr_SetString(PyExc_RuntimeError, e.what()); | |||
359 | goto fail; | |||
360 | } | |||
361 | ||||
362 | /* | |||
363 | * Generate return value; | |||
364 | */ | |||
365 | ||||
366 | switch (ret_spec) { | |||
367 | case 'i': | |||
368 | case 'l': | |||
369 | return_value = PyLong_FromLongLong(ret); | |||
370 | break; | |||
371 | case 'v': | |||
372 | Py_INCREF(Py_None)_Py_INCREF(((PyObject*)((&_Py_NoneStruct)))); | |||
373 | return_value = Py_None(&_Py_NoneStruct); | |||
374 | break; | |||
375 | default: | |||
376 | PyErr_SetString(PyExc_ValueError, | |||
377 | "internal error: invalid return value spec"); | |||
378 | } | |||
379 | ||||
380 | /* | |||
381 | * Convert any std::vector output arrays to arrays | |||
382 | */ | |||
383 | if (VW_count > 0) { | |||
384 | PyObject *new_ret; | |||
385 | PyObject *old_ret = return_value; | |||
386 | int pos; | |||
387 | ||||
388 | return_value = NULL__null; | |||
389 | ||||
390 | new_ret = PyTuple_New(VW_count + (old_ret == Py_None(&_Py_NoneStruct) ? 0 : 1)); | |||
391 | if (new_ret == NULL__null) { | |||
392 | goto fail; | |||
393 | } | |||
394 | if (old_ret != Py_None(&_Py_NoneStruct)) { | |||
395 | PyTuple_SET_ITEM(new_ret, 0, old_ret)PyTuple_SetItem(new_ret, 0, old_ret); | |||
396 | pos = 1; | |||
397 | } | |||
398 | else { | |||
399 | Py_DECREF(old_ret)_Py_DECREF(((PyObject*)(old_ret))); | |||
400 | pos = 0; | |||
401 | } | |||
402 | ||||
403 | j = 0; | |||
404 | for (p = spec; *p != '\0'; ++p, ++j) { | |||
405 | if (*p == '*') { | |||
406 | --j; | |||
407 | continue; | |||
408 | } | |||
409 | else if (*p == 'V' || *p == 'W') { | |||
410 | PyObject *arg; | |||
411 | if (*p == 'V') { | |||
412 | arg = array_from_std_vector_and_free(I_typenum, arg_list[j]); | |||
413 | } else { | |||
414 | arg = array_from_std_vector_and_free(T_typenum, arg_list[j]); | |||
415 | } | |||
416 | arg_list[j] = NULL__null; | |||
417 | if (arg == NULL__null) { | |||
418 | Py_XDECREF(new_ret)_Py_XDECREF(((PyObject*)(new_ret))); | |||
419 | goto fail; | |||
420 | } | |||
421 | PyTuple_SET_ITEM(new_ret, pos, arg)PyTuple_SetItem(new_ret, pos, arg); | |||
422 | ++pos; | |||
423 | } | |||
424 | } | |||
425 | ||||
426 | return_value = new_ret; | |||
427 | } | |||
428 | ||||
429 | ||||
430 | fail: | |||
431 | /* | |||
432 | * Cleanup | |||
433 | */ | |||
434 | for (j = 0, p = spec; *p != '\0'; ++p, ++j) { | |||
435 | if (*p == '*') { | |||
436 | --j; | |||
437 | continue; | |||
438 | } | |||
439 | #ifdef HAVE_WRITEBACKIFCOPY | |||
440 | if (is_output[j] && arg_arrays[j] != NULL__null && PyArray_Check(arg_arrays[j])((((PyObject*)(arg_arrays[j]))->ob_type) == (&(*(PyTypeObject *)_scipy_sparse_sparsetools_ARRAY_API[2])) || PyType_IsSubtype ((((PyObject*)(arg_arrays[j]))->ob_type), (&(*(PyTypeObject *)_scipy_sparse_sparsetools_ARRAY_API[2]))))) { | |||
441 | PyArray_ResolveWritebackIfCopy(*(int (*)(PyArrayObject *)) _scipy_sparse_sparsetools_ARRAY_API [302])((PyArrayObject *)arg_arrays[j]); | |||
442 | } | |||
443 | #endif | |||
444 | Py_XDECREF(arg_arrays[j])_Py_XDECREF(((PyObject*)(arg_arrays[j]))); | |||
445 | if ((*p == 'i' || *p == 'l') && arg_list[j] != NULL__null) { | |||
446 | std::free(arg_list[j]); | |||
447 | } | |||
448 | else if (*p == 'V' && arg_list[j] != NULL__null) { | |||
449 | free_std_vector_typenum(I_typenum, arg_list[j]); | |||
450 | } | |||
451 | else if (*p == 'W' && arg_list[j] != NULL__null) { | |||
452 | free_std_vector_typenum(T_typenum, arg_list[j]); | |||
453 | } | |||
454 | } | |||
455 | return return_value; | |||
456 | } | |||
457 | ||||
458 | ||||
459 | /* | |||
460 | * Helper functions for dealing with std::vector templated instantiation. | |||
461 | */ | |||
462 | ||||
463 | static void *allocate_std_vector_typenum(int typenum) | |||
464 | { | |||
465 | #define PROCESS(ntype, ctype) \ | |||
466 | if (PyArray_EquivTypenums(*(unsigned char (*)(int, int)) _scipy_sparse_sparsetools_ARRAY_API [191])(typenum, ntype)) { \ | |||
467 | return (void*)(new std::vector<ctype>()); \ | |||
468 | } | |||
469 | ||||
470 | try { | |||
471 | SPTOOLS_FOR_EACH_DATA_TYPE_CODE(PROCESS)PROCESS(NPY_BOOL, npy_bool_wrapper) PROCESS(NPY_BYTE, npy_byte ) PROCESS(NPY_UBYTE, npy_ubyte) PROCESS(NPY_SHORT, npy_short) PROCESS(NPY_USHORT, npy_ushort) PROCESS(NPY_INT, npy_int) PROCESS (NPY_UINT, npy_uint) PROCESS(NPY_LONG, npy_long) PROCESS(NPY_ULONG , npy_ulong) PROCESS(NPY_LONGLONG, npy_longlong) PROCESS(NPY_ULONGLONG , npy_ulonglong) PROCESS(NPY_FLOAT, npy_float) PROCESS(NPY_DOUBLE , npy_double) PROCESS(NPY_LONGDOUBLE, npy_longdouble) PROCESS (NPY_CFLOAT, npy_cfloat_wrapper) PROCESS(NPY_CDOUBLE, npy_cdouble_wrapper ) PROCESS(NPY_CLONGDOUBLE, npy_clongdouble_wrapper) | |||
472 | } catch (std::exception &e) { | |||
473 | /* failed */ | |||
474 | } | |||
475 | ||||
476 | #undef PROCESS | |||
477 | ||||
478 | PyErr_SetString(PyExc_RuntimeError, | |||
479 | "failed to allocate std::vector"); | |||
480 | return NULL__null; | |||
481 | } | |||
482 | ||||
483 | static void free_std_vector_typenum(int typenum, void *p) | |||
484 | { | |||
485 | #define PROCESS(ntype, ctype) \ | |||
486 | if (PyArray_EquivTypenums(*(unsigned char (*)(int, int)) _scipy_sparse_sparsetools_ARRAY_API [191])(typenum, ntype)) { \ | |||
487 | delete ((std::vector<ctype>*)p); \ | |||
488 | return; \ | |||
489 | } | |||
490 | ||||
491 | SPTOOLS_FOR_EACH_DATA_TYPE_CODE(PROCESS)PROCESS(NPY_BOOL, npy_bool_wrapper) PROCESS(NPY_BYTE, npy_byte ) PROCESS(NPY_UBYTE, npy_ubyte) PROCESS(NPY_SHORT, npy_short) PROCESS(NPY_USHORT, npy_ushort) PROCESS(NPY_INT, npy_int) PROCESS (NPY_UINT, npy_uint) PROCESS(NPY_LONG, npy_long) PROCESS(NPY_ULONG , npy_ulong) PROCESS(NPY_LONGLONG, npy_longlong) PROCESS(NPY_ULONGLONG , npy_ulonglong) PROCESS(NPY_FLOAT, npy_float) PROCESS(NPY_DOUBLE , npy_double) PROCESS(NPY_LONGDOUBLE, npy_longdouble) PROCESS (NPY_CFLOAT, npy_cfloat_wrapper) PROCESS(NPY_CDOUBLE, npy_cdouble_wrapper ) PROCESS(NPY_CLONGDOUBLE, npy_clongdouble_wrapper) | |||
492 | ||||
493 | #undef PROCESS | |||
494 | } | |||
495 | ||||
496 | static PyObject *array_from_std_vector_and_free(int typenum, void *p) | |||
497 | { | |||
498 | #define PROCESS(ntype, ctype) \ | |||
499 | if (PyArray_EquivTypenums(*(unsigned char (*)(int, int)) _scipy_sparse_sparsetools_ARRAY_API [191])(typenum, ntype)) { \ | |||
500 | std::vector<ctype> *v = (std::vector<ctype>*)p; \ | |||
501 | npy_intp length = v->size(); \ | |||
502 | PyObject *obj = PyArray_SimpleNew(1, &length, typenum)(*(PyObject * (*)(PyTypeObject *, int, npy_intp const *, int, npy_intp const *, void *, int, int, PyObject *)) _scipy_sparse_sparsetools_ARRAY_API [93])(&(*(PyTypeObject *)_scipy_sparse_sparsetools_ARRAY_API [2]), 1, &length, typenum, __null, __null, 0, 0, __null); \ | |||
503 | if (length > 0) { \ | |||
504 | memcpy(PyArray_DATA((PyArrayObject *)obj), &((*v)[0]), \ | |||
505 | sizeof(ctype)*length); \ | |||
506 | } \ | |||
507 | delete v; \ | |||
508 | return obj; \ | |||
509 | } | |||
510 | ||||
511 | SPTOOLS_FOR_EACH_DATA_TYPE_CODE(PROCESS)PROCESS(NPY_BOOL, npy_bool_wrapper) PROCESS(NPY_BYTE, npy_byte ) PROCESS(NPY_UBYTE, npy_ubyte) PROCESS(NPY_SHORT, npy_short) PROCESS(NPY_USHORT, npy_ushort) PROCESS(NPY_INT, npy_int) PROCESS (NPY_UINT, npy_uint) PROCESS(NPY_LONG, npy_long) PROCESS(NPY_ULONG , npy_ulong) PROCESS(NPY_LONGLONG, npy_longlong) PROCESS(NPY_ULONGLONG , npy_ulonglong) PROCESS(NPY_FLOAT, npy_float) PROCESS(NPY_DOUBLE , npy_double) PROCESS(NPY_LONGDOUBLE, npy_longdouble) PROCESS (NPY_CFLOAT, npy_cfloat_wrapper) PROCESS(NPY_CDOUBLE, npy_cdouble_wrapper ) PROCESS(NPY_CLONGDOUBLE, npy_clongdouble_wrapper) | |||
512 | ||||
513 | #undef PROCESS | |||
514 | ||||
515 | PyErr_SetString(PyExc_RuntimeError, | |||
516 | "failed to convert std::vector output array"); | |||
517 | return NULL__null; | |||
518 | } | |||
519 | ||||
520 | static PyObject *c_array_from_object(PyObject *obj, int typenum, int is_output) | |||
521 | { | |||
522 | if (!is_output) { | |||
523 | if (typenum == -1) { | |||
524 | return PyArray_FROM_OF(obj, NPY_ARRAY_C_CONTIGUOUS|NPY_ARRAY_NOTSWAPPED)(*(PyObject * (*)(PyObject *, PyArray_Descr *, int, int, int, PyObject *)) _scipy_sparse_sparsetools_ARRAY_API[108])(obj, __null , 0, 0, 0x0001|0x0200, __null); | |||
525 | } | |||
526 | else { | |||
527 | return PyArray_FROM_OTF(obj, typenum, NPY_ARRAY_C_CONTIGUOUS|NPY_ARRAY_NOTSWAPPED)(*(PyObject * (*)(PyObject *, PyArray_Descr *, int, int, int, PyObject *)) _scipy_sparse_sparsetools_ARRAY_API[69])(obj, ( *(PyArray_Descr * (*)(int)) _scipy_sparse_sparsetools_ARRAY_API [45])(typenum), 0, 0, (((0x0001|0x0200) & 0x0020) ? ((0x0001 |0x0200) | ((0x0001 | (0x0100 | 0x0400)))) : (0x0001|0x0200)) , __null); | |||
528 | } | |||
529 | } | |||
530 | else { | |||
531 | #ifdef HAVE_WRITEBACKIFCOPY | |||
532 | int flags = NPY_ARRAY_C_CONTIGUOUS0x0001|NPY_ARRAY_WRITEABLE0x0400|NPY_ARRAY_WRITEBACKIFCOPY0x2000|NPY_ARRAY_NOTSWAPPED0x0200; | |||
533 | #else | |||
534 | int flags = NPY_ARRAY_C_CONTIGUOUS0x0001|NPY_ARRAY_WRITEABLE0x0400|NPY_UPDATEIFCOPY|NPY_ARRAY_NOTSWAPPED0x0200; | |||
535 | #endif | |||
536 | if (typenum == -1) { | |||
537 | return PyArray_FROM_OF(obj, flags)(*(PyObject * (*)(PyObject *, PyArray_Descr *, int, int, int, PyObject *)) _scipy_sparse_sparsetools_ARRAY_API[108])(obj, __null , 0, 0, flags, __null); | |||
538 | } | |||
539 | else { | |||
540 | return PyArray_FROM_OTF(obj, typenum, flags)(*(PyObject * (*)(PyObject *, PyArray_Descr *, int, int, int, PyObject *)) _scipy_sparse_sparsetools_ARRAY_API[69])(obj, ( *(PyArray_Descr * (*)(int)) _scipy_sparse_sparsetools_ARRAY_API [45])(typenum), 0, 0, (((flags) & 0x0020) ? ((flags) | (( 0x0001 | (0x0100 | 0x0400)))) : (flags)), __null); | |||
541 | } | |||
542 | } | |||
543 | } | |||
544 | ||||
545 | ||||
546 | /* | |||
547 | * Python module initialization | |||
548 | */ | |||
549 | ||||
550 | extern "C" { | |||
551 | ||||
552 | #include "sparsetools_impl.h" | |||
553 | ||||
554 | static struct PyModuleDef moduledef = { | |||
555 | PyModuleDef_HEAD_INIT{ { 1, __null }, __null, 0, __null, }, | |||
556 | "_sparsetools", | |||
557 | NULL__null, | |||
558 | -1, | |||
559 | sparsetools_methods, | |||
560 | NULL__null, | |||
561 | NULL__null, | |||
562 | NULL__null, | |||
563 | NULL__null | |||
564 | }; | |||
565 | ||||
566 | PyObject *PyInit__sparsetools(void) | |||
567 | { | |||
568 | PyObject *m; | |||
569 | m = PyModule_Create(&moduledef)PyModule_Create2(&moduledef, 1013); | |||
| ||||
| ||||
570 | import_array(){if (_import_array() < 0) {PyErr_Print(); PyErr_SetString( PyExc_ImportError, "numpy.core.multiarray failed to import"); return __null; } }; | |||
571 | return m; | |||
572 | } | |||
573 | ||||
574 | } /* extern "C" */ |
1 | #ifndef PyModule_Create2 |
2 | struct _object; |
3 | typedef struct _object PyObject; |
4 | PyObject* clang_analyzer_PyObject_New_Reference(); |
5 | PyObject* PyModule_Create2(PyModuleDef *def, int module_api_version) { |
6 | return clang_analyzer_PyObject_New_Reference(); |
7 | } |
8 | #else |
9 | #warning "API PyModule_Create2 is defined as a macro." |
10 | #endif |