| 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 |