1 #include "_internal.h"
2 #include "Python.h"
3
4 /* A small object that handles deallocation of some of a PyUFunc's fields */
5 typedef struct {
6 PyObject_HEAD
7 /* Borrowed reference */
8 PyUFuncObject *ufunc;
9 /* Owned reference to ancillary object */
10 PyObject *object;
11 } PyUFuncCleaner;
12
13 PyTypeObject PyUFuncCleaner_Type;
14
15
16 static PyObject *
cleaner_new(PyUFuncObject * ufunc,PyObject * object)17 cleaner_new(PyUFuncObject *ufunc, PyObject *object)
18 {
19 PyUFuncCleaner *obj = PyObject_New(PyUFuncCleaner, &PyUFuncCleaner_Type);
20 if (obj != NULL) {
21 obj->ufunc = ufunc;
22 Py_XINCREF(object);
23 obj->object = object;
24 }
25 return (PyObject *) obj;
26 }
27
28 /* Deallocate the PyArray_malloc calls */
29 static void
cleaner_dealloc(PyUFuncCleaner * self)30 cleaner_dealloc(PyUFuncCleaner *self)
31 {
32 PyUFuncObject *ufunc = self->ufunc;
33 Py_XDECREF(self->object);
34 if (ufunc->functions)
35 PyArray_free(ufunc->functions);
36 if (ufunc->types)
37 PyArray_free(ufunc->types);
38 if (ufunc->data)
39 PyArray_free(ufunc->data);
40 PyObject_Del(self);
41 }
42
43 PyTypeObject PyUFuncCleaner_Type = {
44 PyVarObject_HEAD_INIT(NULL, 0)
45 "numba._UFuncCleaner", /* tp_name*/
46 sizeof(PyUFuncCleaner), /* tp_basicsize*/
47 0, /* tp_itemsize */
48 /* methods */
49 (destructor) cleaner_dealloc, /* tp_dealloc */
50 0, /* tp_print */
51 0, /* tp_getattr */
52 0, /* tp_setattr */
53 #if defined(NPY_PY3K)
54 0, /* tp_reserved */
55 #else
56 0, /* tp_compare */
57 #endif
58 0, /* tp_repr */
59 0, /* tp_as_number */
60 0, /* tp_as_sequence */
61 0, /* tp_as_mapping */
62 0, /* tp_hash */
63 0, /* tp_call */
64 0, /* tp_str */
65 0, /* tp_getattro */
66 0, /* tp_setattro */
67 0, /* tp_as_buffer */
68 Py_TPFLAGS_DEFAULT, /* tp_flags */
69 0, /* tp_doc */
70 0, /* tp_traverse */
71 0, /* tp_clear */
72 0, /* tp_richcompare */
73 0, /* tp_weaklistoffset */
74 0, /* tp_iter */
75 0, /* tp_iternext */
76 0, /* tp_methods */
77 0, /* tp_members */
78 0, /* tp_getset */
79 0, /* tp_base */
80 0, /* tp_dict */
81 0, /* tp_descr_get */
82 0, /* tp_descr_set */
83 0, /* tp_dictoffset */
84 0, /* tp_init */
85 0, /* tp_alloc */
86 0, /* tp_new */
87 0, /* tp_free */
88 0, /* tp_is_gc */
89 0, /* tp_bases */
90 0, /* tp_mro */
91 0, /* tp_cache */
92 0, /* tp_subclasses */
93 0, /* tp_weaklist */
94 0, /* tp_del */
95 0, /* tp_version_tag */
96 };
97
98 /* ______________________________________________________________________
99 * DUFunc: A call-time (hence dynamic) specializable ufunc.
100 */
101
102 typedef struct {
103 PyObject_HEAD
104 PyObject * dispatcher;
105 PyUFuncObject * ufunc;
106 PyObject * keepalive;
107 int frozen;
108 } PyDUFuncObject;
109
110 static void
dufunc_dealloc(PyDUFuncObject * self)111 dufunc_dealloc(PyDUFuncObject *self)
112 {
113 /* Note: There is no need to call PyArray_free() on
114 self->ufunc->ptr, since ufunc_dealloc() will do it for us. */
115 Py_XDECREF(self->ufunc);
116 Py_XDECREF(self->dispatcher);
117 Py_XDECREF(self->keepalive);
118 Py_TYPE(self)->tp_free((PyObject *)self);
119 }
120
121 static PyObject *
dufunc_repr(PyDUFuncObject * dufunc)122 dufunc_repr(PyDUFuncObject *dufunc)
123 {
124 return PyString_FromFormat("<numba._DUFunc '%s'>", dufunc->ufunc->name);
125 }
126
127 static PyObject *
dufunc_call(PyDUFuncObject * self,PyObject * args,PyObject * kws)128 dufunc_call(PyDUFuncObject *self, PyObject *args, PyObject *kws)
129 {
130 PyObject *result=NULL, *method=NULL;
131
132 result = PyUFunc_Type.tp_call((PyObject *)self->ufunc, args, kws);
133 if ((!self->frozen) &&
134 (result == NULL) &&
135 (PyErr_Occurred()) &&
136 (PyErr_ExceptionMatches(PyExc_TypeError))) {
137
138 /* Break back into Python when we fail at dispatch. */
139 PyErr_Clear();
140 method = PyObject_GetAttrString((PyObject*)self, "_compile_for_args");
141
142 if (method) {
143 result = PyObject_Call(method, args, kws);
144 if (result) {
145 Py_DECREF(result);
146 result = PyUFunc_Type.tp_call((PyObject *)self->ufunc, args,
147 kws);
148 }
149 }
150 Py_XDECREF(method);
151 }
152 return result;
153 }
154
155 static Py_ssize_t
_get_nin(PyObject * py_func_obj)156 _get_nin(PyObject * py_func_obj)
157 {
158 int result = -1;
159 PyObject *inspect=NULL, *getargspec=NULL, *argspec=NULL, *args=NULL;
160
161 inspect = PyImport_ImportModule("inspect");
162 if (!inspect) goto _get_nin_cleanup;
163 getargspec = PyObject_GetAttrString(inspect, "getfullargspec");
164 if (!getargspec) goto _get_nin_cleanup;
165 argspec = PyObject_CallFunctionObjArgs(getargspec, py_func_obj, NULL);
166 if (!argspec) goto _get_nin_cleanup;
167 args = PyObject_GetAttrString(argspec, "args");
168 if (!args) goto _get_nin_cleanup;
169 result = PyList_Size(args);
170
171 _get_nin_cleanup:
172 Py_XDECREF(args);
173 Py_XDECREF(argspec);
174 Py_XDECREF(getargspec);
175 Py_XDECREF(inspect);
176 return result;
177 }
178
179 static int
dufunc_init(PyDUFuncObject * self,PyObject * args,PyObject * kws)180 dufunc_init(PyDUFuncObject *self, PyObject *args, PyObject *kws)
181 {
182 PyObject *dispatcher=NULL, *keepalive=NULL, *py_func_obj=NULL, *tmp;
183 PyUFuncObject *ufunc=NULL;
184 int identity=PyUFunc_None;
185 int nin=-1, nout=1;
186 const char *name=NULL, *doc=NULL;
187
188 static char * kwlist[] = {"dispatcher", "identity", "_keepalive", "nin",
189 "nout", NULL};
190
191 if (!PyArg_ParseTupleAndKeywords(args, kws, "O|iO!nn", kwlist,
192 &dispatcher, &identity,
193 &PyList_Type, &keepalive, &nin, &nout)) {
194 return -1;
195 }
196
197 py_func_obj = PyObject_GetAttrString(dispatcher, "py_func");
198 if (!py_func_obj) {
199 return -1;
200 }
201
202 if (nin < 0) {
203 nin = (int)_get_nin(py_func_obj);
204 if ((nin < 0) || (PyErr_Occurred())) {
205 Py_XDECREF(py_func_obj);
206 return -1;
207 }
208 }
209
210 /* Construct the UFunc. */
211 tmp = PyObject_GetAttrString(py_func_obj, "__name__");
212 if (tmp) {
213 name = PyString_AsString(tmp);
214 }
215 Py_XDECREF(tmp);
216 tmp = PyObject_GetAttrString(py_func_obj, "__doc__");
217 if (tmp && (tmp != Py_None)) {
218 doc = PyString_AsString(tmp);
219 }
220 Py_XDECREF(tmp);
221 tmp = NULL;
222 Py_XDECREF(py_func_obj);
223 py_func_obj = NULL;
224 if (!name) {
225 return -1;
226 }
227 ufunc = (PyUFuncObject *)PyUFunc_FromFuncAndData(NULL, NULL, NULL, 0,
228 nin, nout, identity,
229 name, doc, 0);
230 if (!ufunc) {
231 return -1;
232 }
233
234 /* Construct a keepalive list if none was given. */
235 if (!keepalive) {
236 keepalive = PyList_New(0);
237 if (!keepalive) {
238 Py_XDECREF(ufunc);
239 return -1;
240 }
241 } else {
242 Py_INCREF(keepalive);
243 }
244
245 tmp = self->dispatcher;
246 Py_INCREF(dispatcher);
247 self->dispatcher = dispatcher;
248 Py_XDECREF(tmp);
249
250 tmp = (PyObject*)self->ufunc;
251 self->ufunc = ufunc;
252 Py_XDECREF(tmp);
253
254 tmp = self->keepalive;
255 /* Already incref'ed, either by PyList_New(), or else clause, both above. */
256 self->keepalive = keepalive;
257 Py_XDECREF(tmp);
258
259 self->frozen = 0;
260
261 return 0;
262 }
263
264 static PyMemberDef dufunc_members[] = {
265 {"_dispatcher", T_OBJECT_EX, offsetof(PyDUFuncObject, dispatcher), 0,
266 "Dispatcher object for the core Python function."},
267 {"ufunc", T_OBJECT_EX, offsetof(PyDUFuncObject, ufunc), 0,
268 "Numpy Ufunc for the dynamic ufunc."},
269 {"_keepalive", T_OBJECT_EX, offsetof(PyDUFuncObject, keepalive), 0,
270 "List of objects to keep alive during life of dufunc."},
271 {NULL}
272 };
273
274 /* ____________________________________________________________
275 * Shims to expose ufunc methods.
276 */
277
278 static struct _ufunc_dispatch {
279 PyCFunctionWithKeywords ufunc_reduce;
280 PyCFunctionWithKeywords ufunc_accumulate;
281 PyCFunctionWithKeywords ufunc_reduceat;
282 PyCFunctionWithKeywords ufunc_outer;
283 #if NPY_API_VERSION >= 0x00000008
284 PyCFunction ufunc_at;
285 #endif
286 } ufunc_dispatch;
287
288 static int
init_ufunc_dispatch(void)289 init_ufunc_dispatch(void)
290 {
291 int result = 0;
292 PyMethodDef * crnt = PyUFunc_Type.tp_methods;
293 const char * crnt_name = NULL;
294 for (; crnt->ml_name != NULL; crnt++) {
295 crnt_name = crnt->ml_name;
296 switch(crnt_name[0]) {
297 case 'a':
298 if (strncmp(crnt_name, "accumulate", 11) == 0) {
299 ufunc_dispatch.ufunc_accumulate =
300 (PyCFunctionWithKeywords)crnt->ml_meth;
301 #if NPY_API_VERSION >= 0x00000008
302 } else if (strncmp(crnt_name, "at", 3) == 0) {
303 ufunc_dispatch.ufunc_at = crnt->ml_meth;
304 #endif
305 } else {
306 result = -1;
307 }
308 break;
309 case 'o':
310 if (strncmp(crnt_name, "outer", 6) == 0) {
311 ufunc_dispatch.ufunc_outer =
312 (PyCFunctionWithKeywords)crnt->ml_meth;
313 } else {
314 result = -1;
315 }
316 break;
317 case 'r':
318 if (strncmp(crnt_name, "reduce", 7) == 0) {
319 ufunc_dispatch.ufunc_reduce =
320 (PyCFunctionWithKeywords)crnt->ml_meth;
321 } else if (strncmp(crnt_name, "reduceat", 9) == 0) {
322 ufunc_dispatch.ufunc_reduceat =
323 (PyCFunctionWithKeywords)crnt->ml_meth;
324 } else {
325 result = -1;
326 }
327 break;
328 default:
329 result = -1; /* Unknown method */
330 }
331 if (result < 0) break;
332 }
333 if (result == 0) {
334 /* Sanity check. */
335 result = ((ufunc_dispatch.ufunc_reduce != NULL)
336 && (ufunc_dispatch.ufunc_accumulate != NULL)
337 && (ufunc_dispatch.ufunc_reduceat != NULL)
338 && (ufunc_dispatch.ufunc_outer != NULL)
339 #if NPY_API_VERSION >= 0x00000008
340 && (ufunc_dispatch.ufunc_at != NULL)
341 #endif
342 );
343 }
344 return result;
345 }
346
347 static PyObject *
dufunc_reduce(PyDUFuncObject * self,PyObject * args,PyObject * kws)348 dufunc_reduce(PyDUFuncObject * self, PyObject * args, PyObject *kws)
349 {
350 return ufunc_dispatch.ufunc_reduce((PyObject*)self->ufunc, args, kws);
351 }
352
353 static PyObject *
dufunc_accumulate(PyDUFuncObject * self,PyObject * args,PyObject * kws)354 dufunc_accumulate(PyDUFuncObject * self, PyObject * args, PyObject *kws)
355 {
356 return ufunc_dispatch.ufunc_accumulate((PyObject*)self->ufunc, args, kws);
357 }
358
359 static PyObject *
dufunc_reduceat(PyDUFuncObject * self,PyObject * args,PyObject * kws)360 dufunc_reduceat(PyDUFuncObject * self, PyObject * args, PyObject *kws)
361 {
362 return ufunc_dispatch.ufunc_reduceat((PyObject*)self->ufunc, args, kws);
363 }
364
365 static PyObject *
dufunc_outer(PyDUFuncObject * self,PyObject * args,PyObject * kws)366 dufunc_outer(PyDUFuncObject * self, PyObject * args, PyObject *kws)
367 {
368 return ufunc_dispatch.ufunc_outer((PyObject*)self->ufunc, args, kws);
369 }
370
371 #if NPY_API_VERSION >= 0x00000008
372 static PyObject *
dufunc_at(PyDUFuncObject * self,PyObject * args)373 dufunc_at(PyDUFuncObject * self, PyObject * args)
374 {
375 return ufunc_dispatch.ufunc_at((PyObject*)self->ufunc, args);
376 }
377 #endif
378
379 static PyObject *
dufunc__compile_for_args(PyDUFuncObject * self,PyObject * args,PyObject * kws)380 dufunc__compile_for_args(PyDUFuncObject * self, PyObject * args,
381 PyObject * kws)
382 {
383 PyErr_SetString(PyExc_NotImplementedError,
384 "Abstract method _DUFunc._compile_for_args() called!");
385 return NULL;
386 }
387
388 static int *
_build_arg_types_array(PyObject * type_list,Py_ssize_t nargs)389 _build_arg_types_array(PyObject * type_list, Py_ssize_t nargs)
390 {
391 int *arg_types_array=NULL;
392 Py_ssize_t idx, arg_types_size = PyList_Size(type_list);
393
394 if (arg_types_size != nargs) {
395 PyErr_SetString(
396 PyExc_ValueError,
397 "argument type list size does not equal ufunc argument count");
398 return NULL;
399 }
400 arg_types_array = PyArray_malloc(sizeof(int) * nargs);
401 if (!arg_types_array) {
402 PyErr_NoMemory();
403 return NULL;
404 }
405 for (idx = 0; idx < nargs; idx++) {
406 arg_types_array[idx] = (int)PyLong_AsLong(PyList_GET_ITEM(type_list,
407 idx));
408 }
409 if (PyErr_Occurred()) {
410 PyArray_free(arg_types_array);
411 arg_types_array = NULL;
412 }
413 return arg_types_array;
414 }
415
416 static PyObject *
dufunc__add_loop(PyDUFuncObject * self,PyObject * args)417 dufunc__add_loop(PyDUFuncObject * self, PyObject * args)
418 {
419 PyUFuncObject * ufunc=self->ufunc;
420 void *loop_ptr=NULL, *data_ptr=NULL;
421 int idx=-1, usertype=NPY_VOID;
422 int *arg_types_arr=NULL;
423 PyObject *arg_types=NULL, *loop_obj=NULL, *data_obj=NULL;
424 PyUFuncGenericFunction old_func=NULL;
425
426 if (self->frozen) {
427 PyErr_SetString(PyExc_ValueError,
428 "_DUFunc._add_loop() called for frozen dufunc");
429 return NULL;
430 }
431
432 if (!PyArg_ParseTuple(args, "O!O!|O!",
433 &PyLong_Type, &loop_obj, &PyList_Type, &arg_types,
434 &PyLong_Type, &data_obj)) {
435 return NULL;
436 }
437
438 loop_ptr = PyLong_AsVoidPtr(loop_obj);
439 if (PyErr_Occurred()) {
440 return NULL;
441 }
442 if (data_obj) {
443 data_ptr = PyLong_AsVoidPtr(data_obj);
444 if (PyErr_Occurred()) {
445 return NULL;
446 }
447 }
448
449 arg_types_arr = _build_arg_types_array(arg_types, (Py_ssize_t)ufunc->nargs);
450 if (!arg_types_arr) goto _dufunc__add_loop_fail;
451
452 /* Check to see if any of the input types are user defined dtypes.
453 If they are, we should use PyUFunc_RegisterLoopForType() since
454 dispatch on a user defined dtype uses a Python dictionary
455 keyed by usertype (and not the functions array).
456
457 For more information, see how the usertype argument is used in
458 PyUFunc_RegisterLoopForType(), defined by Numpy at
459 .../numpy/core/src/umath/ufunc_object.c
460 */
461 for (idx = 0; idx < ufunc->nargs; idx++) {
462 if (arg_types_arr[idx] >= NPY_USERDEF) {
463 usertype = arg_types_arr[idx];
464 }
465 }
466
467 if (usertype != NPY_VOID) {
468 if (PyUFunc_RegisterLoopForType(ufunc, usertype,
469 (PyUFuncGenericFunction)loop_ptr,
470 arg_types_arr, data_ptr) < 0) {
471 goto _dufunc__add_loop_fail;
472 }
473 } else if (PyUFunc_ReplaceLoopBySignature(ufunc,
474 (PyUFuncGenericFunction)loop_ptr,
475 arg_types_arr, &old_func) == 0) {
476 /* TODO: Consider freeing any memory held by the old loop (somehow) */
477 for (idx = 0; idx < ufunc->ntypes; idx++) {
478 if (ufunc->functions[idx] == (PyUFuncGenericFunction)loop_ptr) {
479 ufunc->data[idx] = data_ptr;
480 break;
481 }
482 }
483 } else {
484 /* The following is an attempt to loosely follow the allocation
485 code in Numpy. See ufunc_frompyfunc() in
486 .../numpy/core/src/umath/umathmodule.c.
487
488 The primary goal is to allocate a single chunk of memory to
489 hold the functions, data, and types loop arrays:
490
491 ptr == |<- functions ->|<- data ->|<- types ->|
492
493 */
494 int ntypes=ufunc->ntypes + 1;
495 PyUFuncGenericFunction *functions=NULL;
496 void **data=NULL;
497 char *types=NULL;
498 void *newptr=NULL, *oldptr=NULL;
499 size_t functions_size=sizeof(PyUFuncGenericFunction) * ntypes;
500 size_t data_size=sizeof(void *) * ntypes;
501 size_t type_ofs=sizeof(char) * ufunc->ntypes * ufunc->nargs;
502 size_t newsize=(functions_size + data_size +
503 (sizeof(char) * ntypes * ufunc->nargs));
504
505 oldptr = ufunc->ptr;
506 newptr = PyArray_malloc(newsize);
507 if (!newptr) {
508 PyErr_NoMemory();
509 goto _dufunc__add_loop_fail;
510 }
511 functions = (PyUFuncGenericFunction*)newptr;
512 memcpy(functions, ufunc->functions,
513 sizeof(PyUFuncGenericFunction) * ufunc->ntypes);
514 functions[ntypes - 1] = (PyUFuncGenericFunction)loop_ptr;
515 data = (void **)((char *)functions + functions_size);
516 memcpy(data, ufunc->data, sizeof(void *) * ufunc->ntypes);
517 data[ntypes - 1] = data_ptr;
518 types = (char *)data + data_size;
519 memcpy(types, ufunc->types, sizeof(char) * ufunc->ntypes *
520 ufunc->nargs);
521 for (idx = 0; idx < ufunc->nargs; idx++) {
522 types[idx + type_ofs] = (char)arg_types_arr[idx];
523 }
524
525 ufunc->ntypes = ntypes;
526 ufunc->functions = functions;
527 ufunc->types = types;
528 ufunc->data = data;
529 ufunc->ptr = newptr;
530 PyArray_free(oldptr);
531 }
532
533 PyArray_free(arg_types_arr);
534 Py_INCREF(Py_None);
535 return Py_None;
536
537 _dufunc__add_loop_fail:
538 PyArray_free(arg_types_arr);
539 return NULL;
540 }
541
542 static struct PyMethodDef dufunc_methods[] = {
543 {"reduce",
544 (PyCFunction)dufunc_reduce,
545 METH_VARARGS | METH_KEYWORDS, NULL },
546 {"accumulate",
547 (PyCFunction)dufunc_accumulate,
548 METH_VARARGS | METH_KEYWORDS, NULL },
549 {"reduceat",
550 (PyCFunction)dufunc_reduceat,
551 METH_VARARGS | METH_KEYWORDS, NULL },
552 {"outer",
553 (PyCFunction)dufunc_outer,
554 METH_VARARGS | METH_KEYWORDS, NULL},
555 #if NPY_API_VERSION >= 0x00000008
556 {"at",
557 (PyCFunction)dufunc_at,
558 METH_VARARGS, NULL},
559 #endif
560 {"_compile_for_args",
561 (PyCFunction)dufunc__compile_for_args,
562 METH_VARARGS | METH_KEYWORDS,
563 "Abstract method: subclasses should overload _compile_for_args() to compile the ufunc at the given arguments' types."},
564 {"_add_loop",
565 (PyCFunction)dufunc__add_loop,
566 METH_VARARGS,
567 NULL},
568 {NULL, NULL, 0, NULL} /* sentinel */
569 };
570
571 static PyObject *
dufunc_getfrozen(PyDUFuncObject * self,void * closure)572 dufunc_getfrozen(PyDUFuncObject * self, void * closure)
573 {
574 PyObject *result=(self->frozen) ? Py_True : Py_False;
575 Py_INCREF(result);
576 return result;
577 }
578
579 static int
dufunc_setfrozen(PyDUFuncObject * self,PyObject * value,void * closure)580 dufunc_setfrozen(PyDUFuncObject * self, PyObject * value, void * closure)
581 {
582 int result=0;
583 if (PyObject_IsTrue(value)) {
584 self->frozen = 1;
585 } else {
586 PyErr_SetString(PyExc_ValueError,
587 "cannot clear the _DUFunc.frozen flag");
588 result = -1;
589 }
590 return result;
591 }
592
593 static PyGetSetDef dufunc_getsets[] = {
594 {"_frozen",
595 (getter)dufunc_getfrozen, (setter)dufunc_setfrozen,
596 "flag indicating call-time compilation has been disabled",
597 NULL},
598 {NULL} /* Sentinel */
599 };
600
601 PyTypeObject PyDUFunc_Type = {
602 PyVarObject_HEAD_INIT(NULL, 0)
603 "numba._DUFunc", /* tp_name*/
604 sizeof(PyDUFuncObject), /* tp_basicsize*/
605 0, /* tp_itemsize */
606 /* methods */
607 (destructor) dufunc_dealloc, /* tp_dealloc */
608 0, /* tp_print */
609 0, /* tp_getattr */
610 0, /* tp_setattr */
611 0, /* tp_compare/tp_reserved */
612 (reprfunc) dufunc_repr, /* tp_repr */
613 0, /* tp_as_number */
614 0, /* tp_as_sequence */
615 0, /* tp_as_mapping */
616 0, /* tp_hash */
617 (ternaryfunc) dufunc_call, /* tp_call */
618 (reprfunc) dufunc_repr, /* tp_str */
619 0, /* tp_getattro */
620 0, /* tp_setattro */
621 0, /* tp_as_buffer */
622 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
623 0, /* tp_doc */
624 0, /* tp_traverse */
625 0, /* tp_clear */
626 0, /* tp_richcompare */
627 0, /* tp_weaklistoffset */
628 0, /* tp_iter */
629 0, /* tp_iternext */
630 dufunc_methods, /* tp_methods */
631 dufunc_members, /* tp_members */
632 dufunc_getsets, /* tp_getset */
633 0, /* tp_base */
634 0, /* tp_dict */
635 0, /* tp_descr_get */
636 0, /* tp_descr_set */
637 0, /* tp_dictoffset */
638 (initproc) dufunc_init, /* tp_init */
639 0, /* tp_alloc */
640 0, /* tp_new */
641 0, /* tp_free */
642 0, /* tp_is_gc */
643 0, /* tp_bases */
644 0, /* tp_mro */
645 0, /* tp_cache */
646 0, /* tp_subclasses */
647 0, /* tp_weaklist */
648 0, /* tp_del */
649 0, /* tp_version_tag */
650 };
651
652 /* ______________________________________________________________________
653 * Module initialization boilerplate follows.
654 */
655
656 static PyMethodDef ext_methods[] = {
657 {"fromfunc", (PyCFunction) ufunc_fromfunc, METH_VARARGS, NULL},
658 { NULL }
659 };
660
661 /* Don't remove this marker, it is used for inserting licensing code */
662 /*MARK1*/
663
MOD_INIT(_internal)664 MOD_INIT(_internal)
665 {
666 PyObject *m;
667
668 /* Don't remove this marker, it is used for inserting licensing code */
669 /*MARK2*/
670
671 import_array();
672 import_umath();
673
674 MOD_DEF(m, "_internal", "No docs",
675 ext_methods)
676
677 if (m == NULL)
678 return MOD_ERROR_VAL;
679
680 if (PyType_Ready(&PyUFuncCleaner_Type) < 0)
681 return MOD_ERROR_VAL;
682
683 PyDUFunc_Type.tp_new = PyType_GenericNew;
684 if (init_ufunc_dispatch() <= 0)
685 return MOD_ERROR_VAL;
686 if (PyType_Ready(&PyDUFunc_Type) < 0)
687 return MOD_ERROR_VAL;
688 Py_INCREF(&PyDUFunc_Type);
689 if (PyModule_AddObject(m, "_DUFunc", (PyObject *)&PyDUFunc_Type) < 0)
690 return MOD_ERROR_VAL;
691
692 if (PyModule_AddIntMacro(m, PyUFunc_One)
693 || PyModule_AddIntMacro(m, PyUFunc_Zero)
694 || PyModule_AddIntMacro(m, PyUFunc_None)
695 #if NPY_API_VERSION >= 0x00000007
696 || PyModule_AddIntMacro(m, PyUFunc_ReorderableNone)
697 #endif
698 )
699 return MOD_ERROR_VAL;
700
701 return MOD_SUCCESS_VAL(m);
702 }
703
704
705 #include "_ufunc.c"
706