LAL 7.7.0.1-eeff03c
SWIGPython.i
Go to the documentation of this file.
1//
2// Copyright (C) 2011--2014, 2022 Karl Wette
3//
4// This program is free software; you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation; either version 2 of the License, or
7// (at your option) any later version.
8//
9// This program is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with with program; see the file COPYING. If not, write to the
16// Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
17// MA 02110-1301 USA
18//
19
20// SWIG interface code specific to Python.
21// Author: Karl Wette
22
23//
24// General SWIG directives and interface code
25//
26
27// In SWIG Python modules, everything is namespaced, so it makes sense to rename symbols to remove
28// superfluous C-API prefixes.
29#define SWIGLAL_MODULE_RENAME_CONSTANTS
30#define SWIGLAL_MODULE_RENAME_FUNCTIONS
31#define SWIGLAL_MODULE_RENAME_TDSTRUCTS
32#define SWIGLAL_MODULE_RENAME_VARIABLES
33
34// Include SWIG Python headers.
35%include <pycomplex.swg>
36
37// Include NumPy headers in wrapping code, and ensure that NumPy array module is loaded along with
38// this module.
39%header %{
40#include <numpy/arrayobject.h>
41
42/*
43 * Allow compiling on NumPy 1.x.
44 * FIXME: drop once we do all builds against Numpy 2.x (although we may still
45 * support Numpy 1.x and 2.x at runtime).
46 * See hhttps://numpy.org/devdocs/numpy_2_0_migration_guide.html#c-api-changes.
47 */
48#if NPY_ABI_VERSION < 0x02000000
49 /*
50 * Define 2.0 feature version as it is needed below to decide whether we
51 * compile for both 1.x and 2.x (defining it gaurantees 1.x only).
52 */
53 #define NPY_2_0_API_VERSION 0x00000012
54 /*
55 * If we are compiling with NumPy 1.x, PyArray_RUNTIME_VERSION so we
56 * pretend the `PyArray_RUNTIME_VERSION` is `NPY_FEATURE_VERSION`.
57 * This allows downstream to use `PyArray_RUNTIME_VERSION` if they need to.
58 */
59 #define PyArray_RUNTIME_VERSION NPY_FEATURE_VERSION
60 /* Compiling on NumPy 1.x where these are the same: */
61 #define PyArray_DescrProto PyArray_Descr
62#endif
63%}
64%init %{
65#if defined(import_array1)
66import_array1(0);
67#else
68import_array();
69#endif
70%}
71
72// Evaluates true if a PyObject is not empty, false otherwise.
73%header %{
74#define swiglal_not_empty(v) ((v) != NULL)
75%}
76
77// Name of PyObject containing the SWIG wrapping of the struct whose members are being accessed.
78%header %{
79#define swiglal_self() (self)
80#define swiglal_no_self() (NULL)
81%}
82
83// Name of PyObject containing the SWIG wrapping of the first argument to a function.
84%header %{
85#define swiglal_1starg() (obj0)
86%}
87
88// Return a reference to the supplied PyObject; increment its reference count, then return it.
89%header %{
90SWIGINTERNINLINE PyObject* swiglal_get_reference(PyObject* v) { Py_XINCREF(v); return v; }
91%}
92
93// Remove the first argument (i.e. the XLAL error code) from the output argument list of a
94// Python SWIG-wrapped function, if the list has more than one output argument.
95%header %{
96SWIGINTERN PyObject* swiglal_py_remove_first_output(PyObject *result) {
97 PySequence_DelItem(result, 0);
98 if (PySequence_Size(result) == 1) {
99 PyObject *obj = result;
100 result = PySequence_GetItem(obj, 0);
101 Py_DECREF(obj);
102 }
103 return result;
104}
105#define swiglal_maybe_return_int() \
106 if (PySequence_Check(resultobj) && PySequence_Size(resultobj) > 1) resultobj = swiglal_py_remove_first_output(resultobj)
107%}
108
109// Evaluates true if a PyObject represents a null pointer, false otherwise.
110%header %{
111#define swiglal_null_ptr(v) ((v) == Py_None)
112%}
113
114// Python-specific function for standard output/error redirection
115%header %{
116SWIGINTERN int swiglal_output_stdouterr(void) {
117
118 // Flush and rewind temporary files
119 fflush(swiglal_tmp_stdout);
120 rewind(swiglal_tmp_stdout);
121 fflush(swiglal_tmp_stderr);
122 rewind(swiglal_tmp_stderr);
123
124 // Write standard output
125 {
126 char buf[512];
127 while (fgets(buf, sizeof(buf), swiglal_tmp_stdout) != NULL) {
128 PySys_WriteStdout("%s", buf);
129 }
130 }
131
132 // Write standard error
133 {
134 char buf[512];
135 while (fgets(buf, sizeof(buf), swiglal_tmp_stderr) != NULL) {
136 PySys_WriteStderr("%s", buf);
137 }
138 }
139
140 // Close temporary files
141 fclose(swiglal_tmp_stdout);
142 fclose(swiglal_tmp_stderr);
143
144 return 1;
145
146}
147%}
148
149//
150// SWIG directives for operators
151//
152
153// These macros apply the correct python:slot directives to map Python __operator__ functions (which
154// may be defined in %extend) to the correct PyTypeObject slots.
155
156// Unary operators which do not return a new object.
157%define %swiglal_py_ury_op(NAME, FUNCTYPE, SLOT)
158%pythonmaybecall *::__##NAME##__;
159%feature("python:slot", #SLOT, functype=#FUNCTYPE) *::__##NAME##__;
160%feature("kwargs", 0) *::__##NAME##__;
161%enddef
162%swiglal_py_ury_op(float, unaryfunc, nb_float);
163%swiglal_py_ury_op(hash, hashfunc, tp_hash);
164%swiglal_py_ury_op(int, unaryfunc, nb_int);
165%swiglal_py_ury_op(long, unaryfunc, nb_long);
166%swiglal_py_ury_op(nonzero, inquiry, nb_nonzero);
167%swiglal_py_ury_op(repr, reprfunc, tp_repr);
168%swiglal_py_ury_op(str, reprfunc, tp_str);
169
170// Unary operators which return a new object, and thus require %newobject to be set.
171%define %swiglal_py_urn_op(NAME, FUNCTYPE, SLOT)
172%newobject *::__##NAME##__;
173%pythonmaybecall *::__##NAME##__;
174%feature("python:slot", #SLOT, functype=#FUNCTYPE) *::__##NAME##__;
175%feature("kwargs", 0) *::__##NAME##__;
176%enddef
177%swiglal_py_urn_op(abs, unaryfunc, nb_absolute);
178%swiglal_py_urn_op(neg, unaryfunc, nb_negative);
179%swiglal_py_urn_op(pos, unaryfunc, nb_positive);
180
181// Binary operators, which always must return a new object, and thus require %newobject to be
182// set. The SWIG Python module with -builtin does not support reverse operators, so they are removed
183// from the interface.
184%define %swiglal_py_bin_op(NAME, FUNCTYPE, SLOT)
185%newobject *::__##NAME##__;
186%pythonmaybecall *::__##NAME##__;
187%feature("python:slot", #SLOT, functype=#FUNCTYPE) *::__##NAME##__;
188%feature("kwargs", 0) *::__##NAME##__;
189%ignore *::__r##NAME##__;
190%enddef
191%swiglal_py_bin_op(add, binaryfunc, nb_add);
192%swiglal_py_bin_op(and, binaryfunc, nb_and);
193%swiglal_py_bin_op(div, binaryfunc, nb_divide);
194%swiglal_py_bin_op(lshift, binaryfunc, nb_lshift);
195%swiglal_py_bin_op(mod, binaryfunc, nb_remainder);
196%swiglal_py_bin_op(mul, binaryfunc, nb_multiply);
197%swiglal_py_bin_op(or, binaryfunc, nb_or);
198%swiglal_py_bin_op(pow, ternaryfunc, nb_power);
199%swiglal_py_bin_op(rshift, binaryfunc, nb_rshift);
200%swiglal_py_bin_op(sub, binaryfunc, nb_subtract);
201%swiglal_py_bin_op(xor, binaryfunc, nb_xor);
202
203// Python __pow__() operator must accept 3 arguments, but we do not use the 3rd.
204%typemap(in) void* SWIGLAL_OP_POW_3RDARG {
205 if ($input != Py_None) {
206 %argument_fail(SWIG_TypeError, "$type", $symname, $argnum);
207 }
208}
209
210// SWIG's SWIGPY_HASHFUNC_CLOSURE() macro requires the return of a __hash__()
211// function to be of PyLong type, which is not guaranteed by SWIG_from_long()
212// (which may return a PyInt), so use this custom typemap to guarantee this.
213%typemap(out, noblock=1) long __hash__ {
214 %set_output(PyLong_FromLong($1));
215}
216
217// Comparison operators.
218%typemap(in, numinputs=0, noblock=1) int SWIGLAL_CMP_OP_RETN_HACK "";
219%define %swiglal_py_cmp_op(NAME, COMPTYPE)
220%pythonmaybecall *::__##NAME##__;
221%feature("python:compare", #COMPTYPE) *::__##NAME##__;
222%feature("kwargs", 0) *::__##NAME##__;
223%feature("new", 1) *::__##NAME##__;
224%typemap(out, noblock=1, fragment=SWIG_From_frag(bool)) bool __##NAME##__ {
225 return SWIG_From_bool($1);
226}
227%typemap(freearg, noblock=1) int SWIGLAL_CMP_OP_RETN_HACK {
228 PyErr_Clear();
229 Py_INCREF(Py_NotImplemented);
230 return Py_NotImplemented;
231}
232%enddef
233%swiglal_py_cmp_op(eq, Py_EQ);
234%swiglal_py_cmp_op(ge, Py_GE);
235%swiglal_py_cmp_op(gt, Py_GT);
236%swiglal_py_cmp_op(le, Py_LE);
237%swiglal_py_cmp_op(lt, Py_LT);
238%swiglal_py_cmp_op(ne, Py_NE);
239
240//
241// Python-specific extensions to structs
242//
243
244// Mark all SWIG wrappings of C structs as "non-dynamic", so that they do not
245// allow arbitrary attributes to be set. This prevents bugs due to trivial
246// typos/misspellings of C struct fields; without %pythonnondynamic, if a C
247// struct has a field "foo" but one misspells it as "Foo" in assigning the field
248// in Python, SWIG will silently store "Foo" somewhere in the Python wrapper but
249// will not modify the underlying C struct field "foo".
250%pythonnondynamic;
251
252// Extend a struct TAGNAME.
253%define %swiglal_struct_extend_specific(TAGNAME, OPAQUE, DTORFUNC)
254
255// Create shallow copy function __copy__() for the use of Python's copy.copy() function. It is
256// always defined but will fail for opaque structs, which cannot be copied.
257#if !OPAQUE
258%extend TAGNAME {
259 struct TAGNAME *__copy__() {
260 return %swiglal_new_copy(*$self, struct TAGNAME);
261 }
262}
263#else
264%extend TAGNAME {
265 struct TAGNAME *__copy__() {
266 XLALSetErrno(XLAL_ENOSYS); /* Silently signal an error to wrapper function */
267 return NULL;
268 }
269}
270#endif
271
272// Create deep copy function __deepcopy__() for the use of Python's copy.deepcopy() function. It is
273// always defined but will fail for opaque structs, which cannot be copied, and for structs with a
274// destructor, which presumably cannot be trivially copied with memcpy().
275#if !OPAQUE && #DTORFUNC == ""
276%extend TAGNAME {
277 %typemap(in, noblock=1) const void *memo "";
278 struct TAGNAME *__deepcopy__(const void *memo) {
279 return %swiglal_new_copy(*$self, struct TAGNAME);
280 }
281 %clear const void *memo;
282}
283#else
284%extend TAGNAME {
285 %typemap(in, noblock=1) const void *memo "";
286 struct TAGNAME *__deepcopy__(const void *memo) {
287 XLALSetErrno(XLAL_ENOSYS); /* Silently signal an error to wrapper function */
288 return NULL;
289 }
290 %clear const void *memo;
291}
292#endif
293
294%enddef // %swiglal_struct_extend_specific
295
296//
297// General fragments, typemaps, and macros
298//
299
300// SWIG conversion fragments and typemaps for GSL complex numbers.
301%swig_cplxflt_convn(gsl_complex_float, gsl_complex_float_rect, GSL_REAL, GSL_IMAG);
302%swig_cplxdbl_convn(gsl_complex, gsl_complex_rect, GSL_REAL, GSL_IMAG);
303%typemaps_primitive(%checkcode(CPLXFLT), gsl_complex_float);
304%typemaps_primitive(%checkcode(CPLXDBL), gsl_complex);
305
306// SWIG conversion fragments and typemaps for LAL complex numbers.
307%swig_cplxflt_convn(COMPLEX8, crectf, crealf, cimagf);
308%swig_cplxdbl_convn(COMPLEX16, crect, creal, cimag);
309%typemaps_primitive(%checkcode(CPLXFLT), COMPLEX8);
310%typemaps_primitive(%checkcode(CPLXDBL), COMPLEX16);
311
312// Handle NumPy fixed-width integer/float types
313// - Since all SWIG integer type conversions ultimately use either SWIG_AsVal_long() or
314// SWIG_AsVal_unsigned_SS_long(), and all SWIG floating-point type conversions ultimately use
315// SWIG_AsVal_float() or SWIG_AsVal_double(), it is most straightforward to replace those
316// functions with custom versions using C preprocessor macros
317// - SWIGLAL maps complex floating-point types to COMPLEX{8|16} via %swig_cplx{flt|dbl}_convn()
318%fragment(SWIG_AsVal_frag(long));
319%fragment(SWIG_AsVal_frag(unsigned long));
320%fragment(SWIG_AsVal_frag(float));
321%fragment(SWIG_AsVal_frag(double));
322%fragment(SWIG_AsVal_frag(COMPLEX8));
323%fragment(SWIG_AsVal_frag(COMPLEX16));
324%header %{
325SWIGINTERN int swiglal_SWIG_AsVal_long(PyObject *obj, long* val) {
326 if (PyArray_IsScalar(obj, Integer)) {
327 /* handle NumPy signed integer types */
328 if (val) {
329 PyArray_Descr *longDescr = PyArray_DescrFromType(NPY_LONG);
330 PyArray_CastScalarToCtype(obj, (void*)val, longDescr);
331 Py_DECREF(longDescr);
332 }
333 return SWIG_OK;
334 }
335 /* fall back to SWIG default behaviour */
336 return SWIG_AsVal_long(obj, val);
337}
338SWIGINTERN int swiglal_SWIG_AsVal_unsigned_SS_long(PyObject *obj, unsigned long *val) {
339 if (PyArray_IsScalar(obj, Integer)) {
340 /* handle NumPy unsigned integer types */
341 if (val) {
342 PyArray_Descr *ulongDescr = PyArray_DescrFromType(NPY_ULONG);
343 PyArray_CastScalarToCtype(obj, (void*)val, ulongDescr);
344 Py_DECREF(ulongDescr);
345 }
346 return SWIG_OK;
347 }
348 /* fall back to SWIG default behaviour */
349 return SWIG_AsVal_unsigned_SS_long(obj, val);
350}
351SWIGINTERN int swiglal_SWIG_AsVal_float(PyObject *obj, float* val) {
352 if (PyArray_IsScalar(obj, Integer) || PyArray_IsScalar(obj, Floating)) {
353 /* handle NumPy signed integer types */
354 if (val) {
355 PyArray_Descr *floatDescr = PyArray_DescrFromType(NPY_FLOAT);
356 PyArray_CastScalarToCtype(obj, (void*)val, floatDescr);
357 Py_DECREF(floatDescr);
358 }
359 return SWIG_OK;
360 }
361 /* fall back to SWIG default behaviour */
362 return SWIG_AsVal_float(obj, val);
363}
364SWIGINTERN int swiglal_SWIG_AsVal_double(PyObject *obj, double* val) {
365 if (PyArray_IsScalar(obj, Integer) || PyArray_IsScalar(obj, Floating)) {
366 /* handle NumPy signed integer types */
367 if (val) {
368 PyArray_Descr *doubleDescr = PyArray_DescrFromType(NPY_DOUBLE);
369 PyArray_CastScalarToCtype(obj, (void*)val, doubleDescr);
370 Py_DECREF(doubleDescr);
371 }
372 return SWIG_OK;
373 }
374 /* fall back to SWIG default behaviour */
375 return SWIG_AsVal_double(obj, val);
376}
377SWIGINTERN int swiglal_SWIG_AsVal_COMPLEX8(PyObject *obj, COMPLEX8* val) {
378 if (PyArray_IsScalar(obj, Integer) || PyArray_IsScalar(obj, Floating) || PyArray_IsScalar(obj, ComplexFloating)) {
379 /* handle NumPy signed integer types */
380 if (val) {
381 PyArray_Descr *floatComplexDescr = PyArray_DescrFromType(NPY_COMPLEX64);
382 PyArray_CastScalarToCtype(obj, (void*)val, floatComplexDescr);
383 Py_DECREF(floatComplexDescr);
384 }
385 return SWIG_OK;
386 }
387 /* fall back to SWIG default behaviour */
388 return SWIG_AsVal_COMPLEX8(obj, val);
389}
390SWIGINTERN int swiglal_SWIG_AsVal_COMPLEX16(PyObject *obj, COMPLEX16* val) {
391 if (PyArray_IsScalar(obj, Integer) || PyArray_IsScalar(obj, Floating) || PyArray_IsScalar(obj, ComplexFloating)) {
392 /* handle NumPy signed integer types */
393 if (val) {
394 PyArray_Descr *doubleComplexDescr = PyArray_DescrFromType(NPY_COMPLEX128);
395 PyArray_CastScalarToCtype(obj, (void*)val, doubleComplexDescr);
396 Py_DECREF(doubleComplexDescr);
397 }
398 return SWIG_OK;
399 }
400 /* fall back to SWIG default behaviour */
401 return SWIG_AsVal_COMPLEX16(obj, val);
402}
403#define SWIG_AsVal_long(obj, val) swiglal_SWIG_AsVal_long(obj, val)
404#define SWIG_AsVal_unsigned_SS_long(obj, val) swiglal_SWIG_AsVal_unsigned_SS_long(obj, val)
405#define SWIG_AsVal_float(obj, val) swiglal_SWIG_AsVal_float(obj, val)
406#define SWIG_AsVal_double(obj, val) swiglal_SWIG_AsVal_double(obj, val)
407#define SWIG_AsVal_COMPLEX8(obj, val) swiglal_SWIG_AsVal_COMPLEX8(obj, val)
408#define SWIG_AsVal_COMPLEX16(obj, val) swiglal_SWIG_AsVal_COMPLEX16(obj, val)
409%}
410
411// Typemaps which convert to/from the C broken-down date/time struct.
412%typemap(in) struct tm* (struct tm temptm) {
413
414 // Set 'tm' struct to zero
415 memset(&temptm, 0, sizeof(temptm));
416
417 if ($input != NULL && $input != Py_None) {
418
419 // Check that the $input PyObject is a sequence of 9 integer elements
420 if (!PySequence_Check($input)) {
421 %argument_fail(SWIG_ValueError, "$type (not a sequence)", $symname, $argnum);
422 }
423 if (PySequence_Size($input) != 9) {
424 %argument_fail(SWIG_ValueError, "$type (must have 9 elements)", $symname, $argnum);
425 }
426 PyObject *seq = PySequence_Fast($input, "$type (not a sequence)");
427 temptm.tm_year = %static_cast(PyInt_AsLong(PySequence_Fast_GET_ITEM($input, 0)), int);
428 temptm.tm_mon = %static_cast(PyInt_AsLong(PySequence_Fast_GET_ITEM($input, 1)), int);
429 temptm.tm_mday = %static_cast(PyInt_AsLong(PySequence_Fast_GET_ITEM($input, 2)), int);
430 temptm.tm_hour = %static_cast(PyInt_AsLong(PySequence_Fast_GET_ITEM($input, 3)), int);
431 temptm.tm_min = %static_cast(PyInt_AsLong(PySequence_Fast_GET_ITEM($input, 4)), int);
432 temptm.tm_sec = %static_cast(PyInt_AsLong(PySequence_Fast_GET_ITEM($input, 5)), int);
433 temptm.tm_wday = %static_cast(PyInt_AsLong(PySequence_Fast_GET_ITEM($input, 6)), int);
434 temptm.tm_yday = %static_cast(PyInt_AsLong(PySequence_Fast_GET_ITEM($input, 7)), int);
435 temptm.tm_isdst = %static_cast(PyInt_AsLong(PySequence_Fast_GET_ITEM($input, 8)), int);
436 Py_CLEAR(seq);
437 if (PyErr_Occurred()) { // Catch any errors while converting items to integers
438 SWIG_fail;
439 }
440
441 // Convert Python date ranges to 'tm' struct date ranges
442 // Python: 1900 = year 1900, January = month 1, Monday = week day 0,
443 // January 1st = year day 1
444 // C: 1900 = year 0, January = month 0, Monday = week day 1, January
445 // 1st = year day 0
446 temptm.tm_year -= 1900;
447 temptm.tm_mon -= 1;
448 temptm.tm_wday = (temptm.tm_wday + 8) % 7;
449 temptm.tm_yday -= 1;
450 }
451
452 $1 = &temptm;
453
454}
455%typemap(freearg) struct tm* "";
456%typemap(out) struct tm* {
457
458 // Convert 'tm' struct date ranges to Python date ranges
459 // Python: 1900 = year 1900, January = month 1, Monday = week day 0,
460 // January 1st = year day 1
461 // C: 1900 = year 0, January = month 0, Monday = week day 1, January 1st
462 // = year day 0
463 $1->tm_year += 1900;
464 $1->tm_mon += 1;
465 $1->tm_wday = ($1->tm_wday + 6) % 7;
466 $1->tm_yday += 1;
467
468 // Build a 9-element tuple (Python struct_time is immutable)
469 $result = Py_BuildValue("(iiiiiiiii)",
470 $1->tm_year, $1->tm_mon, $1->tm_mday,
471 $1->tm_hour, $1->tm_min, $1->tm_sec,
472 $1->tm_wday, $1->tm_yday, $1->tm_isdst);
473
474}
475
476//
477// Interface code to track object parents
478//
479
480// Interface code which tracks the parent structs of SWIG-wrapped struct members, so that the parent
481// struct is not destroyed as long as a SWIG-wrapped object containing any of its members exists.
482%header %{
483
484// Internal map from member pointers to PyObjects containing the member parent struct, as well as an
485// internal reference count of how many SWIG-wrapped member objects are extant.
486static PyObject *parent_map = NULL;
487
488// Store a reference to the parent of ptr in the internal map. If there is already such a reference,
489// increment the internal reference count instead.
490SWIGINTERN void swiglal_store_parent(void* ptr, PyObject* parent) {
491 PyObject *pyerr_type = NULL, *pyerr_value = NULL, *pyerr_traceback = NULL;
492 PyErr_Fetch(&pyerr_type, &pyerr_value, &pyerr_traceback);
493 int ecode;
494 assert(ptr != NULL);
495 assert(parent != NULL);
496 PyObject* key = PyLong_FromVoidPtr(ptr);
497 assert(key != NULL);
498 PyObject* parent_tuple = PyDict_GetItem(parent_map, key);
499 if (parent_tuple == NULL) {
500 const long ref_count = 1;
501 parent_tuple = Py_BuildValue("Ol", parent, ref_count);
502 assert(parent_tuple != NULL);
503 ecode = PyDict_SetItem(parent_map, key, parent_tuple);
504 assert(ecode == 0);
505 Py_CLEAR(parent_tuple);
506 }
507 else {
508 Py_INCREF(parent_tuple);
509 PyObject* stored_parent = NULL;
510 long ref_count = 0;
511 ecode = PyArg_ParseTuple(parent_tuple, "Ol", &stored_parent, &ref_count);
512 assert(ecode);
513 ++ref_count;
514 Py_INCREF(stored_parent);
515 Py_CLEAR(parent_tuple);
516 parent_tuple = Py_BuildValue("Nl", stored_parent, ref_count);
517 assert(parent_tuple != NULL);
518 ecode = PyDict_SetItem(parent_map, key, parent_tuple);
519 assert(ecode == 0);
520 Py_CLEAR(parent_tuple);
521 }
522 Py_CLEAR(key);
523 assert(PyErr_Occurred() == NULL);
524 PyErr_Restore(pyerr_type, pyerr_value, pyerr_traceback);
525}
526
527// Check if ptr stored a reference to a parent struct. If there is no parent object, then ptr
528// *really* owns its memory, and it's okay for it to destroy it (so return true). Otherwise,
529// decrement the internal reference count, erase the parent map entry if it reaches zero, and
530// return false to prevent any destructors being called.
531SWIGINTERN bool swiglal_release_parent(void *ptr) {
532 PyObject *pyerr_type = NULL, *pyerr_value = NULL, *pyerr_traceback = NULL;
533 PyErr_Fetch(&pyerr_type, &pyerr_value, &pyerr_traceback);
534 int ecode;
535 bool retn = true;
536 assert(ptr != NULL);
537 PyObject* key = PyLong_FromVoidPtr(ptr);
538 assert(key != NULL);
539 PyObject* parent_tuple = PyDict_GetItem(parent_map, key);
540 if (parent_tuple != NULL) {
541 Py_INCREF(parent_tuple);
542 retn = false;
543 PyObject* stored_parent = NULL;
544 long ref_count = 0;
545 ecode = PyArg_ParseTuple(parent_tuple, "Ol", &stored_parent, &ref_count);
546 assert(ecode);
547 Py_INCREF(stored_parent);
548 Py_CLEAR(parent_tuple);
549 if (--ref_count == 0) {
550 ecode = PyDict_DelItem(parent_map, key);
551 assert(ecode == 0);
552 }
553 else {
554 parent_tuple = Py_BuildValue("Ol", stored_parent, ref_count);
555 ecode = PyDict_SetItem(parent_map, key, parent_tuple);
556 assert(ecode == 0);
557 Py_CLEAR(parent_tuple);
558 }
559 Py_CLEAR(stored_parent);
560 }
561 Py_CLEAR(key);
562 assert(PyErr_Occurred() == NULL);
563 PyErr_Restore(pyerr_type, pyerr_value, pyerr_traceback);
564 return retn;
565}
566
567%} // %header
568%init %{
569
570// Get a pointer to the internal parent map. Look for an attribute 'parent_map' of an internal
571// module 'swiglal_runtime_data'; if it does not exist, create a new map and assign the module
572// attribute, otherwise store the attribute's value. In this way each wrapping module gets a pointer
573// to the same map.
574{
575 const char *const module_name = "swiglal_runtime_data";
576 const char *const parent_map_name = "parent_map";
577#if PY_VERSION_HEX >= 0x03000000
578 PyObject* module = PyImport_AddModule(module_name);
579#else
580 PyObject* module = Py_InitModule(module_name, NULL);
581#endif
582 assert(module != NULL);
583 if (PyObject_HasAttrString(module, parent_map_name)) {
584 parent_map = PyObject_GetAttrString(module, parent_map_name);
585 }
586 else {
587 parent_map = PyDict_New();
588 PyObject_SetAttrString(module, parent_map_name, parent_map);
589 }
590 assert(parent_map != NULL);
591 Py_INCREF(parent_map);
592}
593
594%} // %init
595
596//
597// Fragments and typemaps for arrays
598//
599
600// This section implements array conversion functions for basic C array types, and custom NumPy
601// array descriptors for viewing C arrays of object, e.g. structs.
602
603// Fragment defining helper functions for the array conversion functions.
604%fragment("swiglal_py_array_helpers", "header") {
605
606 // Compute the scalar index of the C array element, and return a pointer to the element itself.
607 void* swiglal_py_get_element_ptr(void* ptr,
608 const size_t esize,
609 const size_t ndims,
610 const size_t strides[],
611 npy_intp idx[])
612 {
613 size_t elemidx = 0;
614 for (size_t j = 0; j < ndims; ++j) {
615 elemidx += ((size_t)idx[j]) * strides[j];
616 }
617 return %reinterpret_cast(%reinterpret_cast(ptr, char*) + elemidx*esize, void*);
618 }
619
620 // Increment the NumPy array index in row-major order, to match the ordering of the C array.
621 void swiglal_py_increment_idx(const size_t ndims,
622 const size_t dims[],
623 npy_intp idx[])
624 {
625 for (int j = ((int)ndims) - 1; j >= 0; --j) {
626 if (++idx[j] < ((npy_intp)dims[j])) {
627 break;
628 }
629 idx[j] = 0;
630 }
631 }
632
633 } // fragment swiglal_py_array_helpers
634
635// Fragment defining helper functions for the NumPy object-view array descriptors.
636%fragment("swiglal_py_array_objview", "header") {
637
638 // Struct which associates a SWIG type descriptor with two NumPy array descriptors, one for arrays
639 // of data blocks (_noptr), and one for arrays of pointers (_isptr).
640 typedef struct {
641 swig_type_info* tinfo;
642 PyArray_Descr* descr_noptr;
643 PyArray_Descr* descr_isptr;
644 } swiglal_py_array_type_pair;
645
646 // Static array of SWIG type/NumPy array descriptor pairs. This array should always be long enough
647 // to accommodate all possible swig_type_info*, since they are always members of the
648 // SWIG-generated global array swig_types[]. This array in turn is always one longer than the
649 // total number of types, so there should always be a sentinal NULL element at the end.
650 static swiglal_py_array_type_pair swiglal_py_array_types[sizeof(swig_types) / sizeof(swig_types[0])];
651
652 // This function maps a SWIG type descriptor to a NumPy array descriptor, or returns the first
653 // NULL element if a mapping doesn't exist yet.
654 SWIGINTERN PyArray_Descr** swiglal_py_array_descr_from_tinfo(const bool isptr, swig_type_info* tinfo) {
655 size_t i = 0;
656 while (swiglal_py_array_types[i].tinfo != NULL && swiglal_py_array_types[i].tinfo != tinfo)
657 ++i;
658 if (swiglal_py_array_types[i].tinfo == NULL)
659 swiglal_py_array_types[i].tinfo = tinfo;
660 return isptr ? &swiglal_py_array_types[i].descr_isptr : &swiglal_py_array_types[i].descr_noptr;
661 }
662
663 // This function maps a NumPy array descriptor to a SWIG type descriptor, or returns NULL element
664 // if a mapping doesn't exist.
665 SWIGINTERN void swiglal_py_array_tinfo_from_descr(bool *isptr, swig_type_info** tinfo, PyArray_Descr* descr) {
666 size_t i = 0;
667 while ( ( swiglal_py_array_types[i].descr_noptr != NULL || swiglal_py_array_types[i].descr_isptr != NULL ) &&
668 ( swiglal_py_array_types[i].descr_noptr != descr && swiglal_py_array_types[i].descr_isptr != descr ) )
669 ++i;
670 *isptr = (swiglal_py_array_types[i].descr_isptr == descr);
671 *tinfo = swiglal_py_array_types[i].tinfo;
672 }
673
674 // Array of NumPy types that a NumPy object-view array can be safely cast to.
675 static int swiglal_py_array_objview_copyswap_cancastto[2] = {NPY_OBJECT, NPY_NOTYPE};
676
677 // NumPy array descriptor function for copying/byte-swapping an array element.
678 static void swiglal_py_array_objview_copyswap(void* dst, void* src, int swap, void* arr) {
679
680 // Check input.
681 assert(arr != NULL);
682 PyArrayObject* nparr = (PyArrayObject*)arr;
683 assert(PyArray_DESCR(nparr) != NULL);
684
685 // Copy array element.
686 if (src != NULL) {
687 memcpy(dst, src, PyArray_ITEMSIZE(nparr));
688 }
689
690 // Byte-swap array element, if required.
691 if (swap) {
692 const size_t n = PyArray_ITEMSIZE(nparr) / 2;
693 char *a, *b, c;
694 a = (char *)dst;
695 b = a + (PyArray_ITEMSIZE(nparr)-1);
696 for (size_t i = 0; i < n; i++) {
697 c = *a;
698 *a++ = *b;
699 *b-- = c;
700 }
701 }
702
703 }
704
705} // fragment swiglal_py_array_objview
706
707// Name of fragment containing a NumPy object-view array descriptor for type ACFTYPE.
708#define %swiglal_py_array_objview_frag(ACFTYPE) "swiglal_py_array_objview_" %str(ACFTYPE)
709
710// Name of fragment containing NumPy object-view array descriptor initialisation code for type
711// ACFTYPE.
712#define %swiglal_py_array_objview_init_frag(ACFTYPE) "swiglal_py_array_objview_init_" %str(ACFTYPE)
713
714// Macro which generates fragments containing a NumPy object-view array descriptor for type ACFTYPE.
715// - IN/OUTFRAG are names of fragments required by the in/out conversion functions IN/OUTCALL.
716%define %swiglal_py_array_objview(ACFTYPE, INFRAG, OUTFRAG, INCALL, OUTCALL)
717
718// Fragment containing NumPy object-view array descriptor initialisation code for type ACFTYPE.
719%fragment(%swiglal_py_array_objview_init_frag(ACFTYPE), "init") {
720 swiglal_py_array_objview_##ACFTYPE##_arrfuncs.cast[NPY_OBJECT] =
721 (PyArray_VectorUnaryFunc*)swiglal_py_array_objview_##ACFTYPE##_cast_to_object;
722}
723
724// Fragment containing a NumPy object-view array descriptor for type ACFTYPE.
725%fragment(%swiglal_py_array_objview_frag(ACFTYPE), "header",
726 fragment="swiglal_py_array_objview",
727 fragment=%swiglal_py_array_objview_init_frag(ACFTYPE),
728 fragment=INFRAG, fragment=OUTFRAG)
729{
730
731 // NumPy array descriptor function which gets an element from the viewed array.
732 static PyObject* swiglal_py_array_objview_##ACFTYPE##_getitem(void* elemptr, void* arr) {
733
734 // Check input.
735 assert(elemptr != NULL);
736 assert(arr != NULL);
737 PyArrayObject* nparr = (PyArrayObject*)arr;
738 assert(PyArray_DESCR(nparr) != NULL);
739
740 // Look up the SWIG type descriptor for this array.
741 bool isptr;
742 swig_type_info* tinfo = NULL;
743 swiglal_py_array_tinfo_from_descr(&isptr, &tinfo, PyArray_DESCR(nparr));
744 assert(tinfo != NULL);
745
746 // Get the Python object wrapping the C array element.
747 const bool copyobj = false;
748 const size_t esize = PyArray_ITEMSIZE(nparr);
749 const int tflags = 0;
750 PyObject* parent = PyArray_BASE(nparr);
751 return OUTCALL;
752
753 }
754
755 // NumPy array descriptor function which assigns an element in the viewed array.
756 static int swiglal_py_array_objview_##ACFTYPE##_setitem(PyObject* objelem, void* elemptr, void* arr) {
757
758 // Check input.
759 assert(elemptr != NULL);
760 assert(arr != NULL);
761 PyArrayObject* nparr = (PyArrayObject*)arr;
762 assert(PyArray_DESCR(nparr) != NULL);
763
764 // Look up the SWIG type descriptor for this array.
765 bool isptr;
766 swig_type_info* tinfo = NULL;
767 swiglal_py_array_tinfo_from_descr(&isptr, &tinfo, PyArray_DESCR(nparr));
768 assert(tinfo != NULL);
769
770 // When assigning Python objects to a C array of pointers, assume the struct
771 // who owns the C array takes ownership of the memory of the C array element.
772 // The Python object wrapping the C array element should therefore disown the
773 // underlying memory.
774 // When assigning Python objects to a C array of data blocks, however, the C
775 // array just struct-copies the object rather than taking ownership of its
776 // pointer, and so the Python object should not be disowned so that it can
777 // be garbage-collected later.
778 const int tflags = isptr ? SWIG_POINTER_DISOWN : 0;
779
780 // Set the C array element to the supplied Python object.
781 const size_t esize = PyArray_ITEMSIZE(nparr);
782 PyObject* parent = PyArray_BASE(nparr);
783 int elemalloc = 0;
784 int *pelemalloc = &elemalloc;
785 int res = INCALL;
786 if (!SWIG_IsOK(res)) {
787 SWIG_Error(res, "failure in swiglal_py_array_objview_" #ACFTYPE "_setitem()");
788 return -1;
789 }
790 return 0;
791
792 }
793
794 // NumPy array descriptor function which casts elements of the viewed array to NPY_OBJECTs.
795 static void swiglal_py_array_objview_##ACFTYPE##_cast_to_object(void *from, void *to, npy_intp n, void *fromarr, void *toarr) {
796
797 // Check input.
798 assert(fromarr != NULL);
799 PyArrayObject* npfromarr = (PyArrayObject*)fromarr;
800 assert(PyArray_DESCR(npfromarr) != NULL);
801 assert(toarr != NULL);
802 PyArrayObject* nptoarr = (PyArrayObject*)toarr;
803 assert(PyArray_DESCR(nptoarr) != NULL);
804
805 // 'toarr' should be an array of pointers to PyObjects.
806 assert(PyArray_ITEMSIZE(nptoarr) == sizeof(PyObject*));
807
808 // Loop over 'n' elements, and assign each element of 'toarr' the Python object wrapping the
809 // corresponding element of 'fromarr'.
810 char* fromelem = (void*)from;
811 PyObject** toelem = (PyObject**)to;
812 while (--n >= 0) {
813 *toelem = swiglal_py_array_objview_##ACFTYPE##_getitem(fromelem, fromarr);
814 fromelem += PyArray_ITEMSIZE(npfromarr);
815 ++toelem;
816 }
817
818 }
819
820 // NumPy array descriptor function table for type ACFTYPE.
821 static PyArray_ArrFuncs swiglal_py_array_objview_##ACFTYPE##_arrfuncs = {
822 {(PyArray_VectorUnaryFunc*)NULL}, // cast
823 (PyArray_GetItemFunc*)&swiglal_py_array_objview_##ACFTYPE##_getitem, // getitem
824 (PyArray_SetItemFunc*)&swiglal_py_array_objview_##ACFTYPE##_setitem, // setitem
825 (PyArray_CopySwapNFunc*)NULL, // copyswapn
826 (PyArray_CopySwapFunc*)&swiglal_py_array_objview_copyswap, // copyswap
827 (PyArray_CompareFunc*)NULL, // compare
828 (PyArray_ArgFunc*)NULL, // argmax
829 (PyArray_DotFunc*)NULL, // dotfunc
830 (PyArray_ScanFunc*)NULL, // scanfunc
831 (PyArray_FromStrFunc*)NULL, // fromstr
832 (PyArray_NonzeroFunc*)NULL, // nonzero
833 (PyArray_FillFunc*)NULL, // fill
834 (PyArray_FillWithScalarFunc*)NULL, // fillwithscalar
835 {(PyArray_SortFunc*)NULL}, // sort
836 {(PyArray_ArgSortFunc*)NULL}, // argsort
837 (PyObject*)NULL, // castdict
838 (PyArray_ScalarKindFunc*)NULL, // scalarkind
839 (int**)NULL, // cancastscalarkindto
840 (int*)swiglal_py_array_objview_copyswap_cancastto, // cancastto
841 (void*)NULL, // fastclip, deprecated and unused
842 (void*)NULL, // fastputmask, deprecated and unused
843 (void*)NULL, // fasttake, deprecated and unused
844 };
845
846 // This function returns the NumPy array descriptor appropriate for the supplied SWIG type
847 // descriptor. If no array descriptor exists, it creates one from the array descriptor for type
848 // ACFTYPE.
849 //
850 // Returns a new reference.
851 SWIGINTERN PyArray_Descr* swiglal_py_array_objview_##ACFTYPE##_descr(const bool isptr, swig_type_info* tinfo, const int esize) {
852
853 // Lookup existing NumPy array descriptor for SWIG type descriptor.
854 PyArray_Descr* *pdescr = swiglal_py_array_descr_from_tinfo(isptr, tinfo);
855 if (*pdescr == NULL) {
856 // Create NumPy array descriptor if none yet exists.
857
858 // Note that PyArray_DescrProto structs are supposed to be immortal. They
859 // must not be Py_DECREF'ed. See
860 // https://github.com/numpy/numpy/issues/26763#issuecomment-2181177478.
861 PyArray_DescrProto *proto = PyObject_Malloc(sizeof(PyArray_DescrProto));
862 if (proto == NULL) {
863 PyErr_NoMemory();
864 } else {
865 PyArray_DescrProto src = {
866 PyObject_HEAD_INIT(&PyArrayDescr_Type)
867#if SWIG_VERSION >= 0x040400
868 .typeobj = SwigPyObject_Type(),
869#else
870 .typeobj = SwigPyObject_type(),
871#endif
872 .kind = 'V',
873 .type = 'V',
874 .byteorder = '=',
875 .flags = NPY_LIST_PICKLE | NPY_NEEDS_INIT | NPY_NEEDS_PYAPI | NPY_USE_GETITEM | NPY_USE_SETITEM,
876 .elsize = esize,
877 .alignment = 1,
878 .f = &swiglal_py_array_objview_##ACFTYPE##_arrfuncs,
879 .hash = -1
880 };
881 *proto = src;
882
883 int typenum = PyArray_RegisterDataType(proto);
884 // FIXME: In Numpy 1.x, PyArray_RegisterDataType steals a reference,
885 // whereas in Numpy 2.x, it does not. See
886 // https://github.com/numpy/numpy/issues/26763
887 if (typenum < 0 || PyArray_RUNTIME_VERSION >= NPY_2_0_API_VERSION) {
888 PyObject_Free(proto);
889 }
890
891 if (typenum >= 0) {
892 *pdescr = PyArray_DescrFromType(typenum);
893 }
894 }
895 }
896
897 // PyArray_NewFromDescr steals a reference to the descriptor passed to it:
898 // https://numpy.org/devdocs/reference/c-api/array.html#from-scratch
899 // so a reference count increment is needed here.
900 Py_XINCREF(*pdescr);
901
902 return *pdescr;
903 }
904
905} // %swiglal_py_array_objview_frag(ACFTYPE)
906
907%enddef // %swiglal_py_array_objview
908
909// Macro which generates fragments which define ACFTYPE-specific array view classes and conversion
910// functions:
911// - IN/OUTFRAG are names of fragments required by the in/out conversion functions IN/OUTCALL.
912// - VIEWFRAG is the name of a fragment needed for array views.
913// - NPYTYPE/NPYDESCR is the appropriate NumPy array typenum/descriptor.
914%define %swiglal_py_array_frags(ACFTYPE, INFRAG, OUTFRAG, INCALL, OUTCALL, VIEWFRAG, NPYTYPE, NPYDESCR)
915
916// Input copy conversion fragment for arrays of type ACFTYPE.
917%fragment(%swiglal_array_copyin_frag(ACFTYPE), "header",
918 fragment="swiglal_py_array_helpers", fragment=INFRAG)
919{
920 SWIGINTERN int %swiglal_array_copyin_func(ACFTYPE)(PyObject* parent,
921 PyObject* obj,
922 void* ptr,
923 int *pelemalloc,
924 const size_t esize,
925 const size_t ndims,
926 const size_t dims[],
927 const size_t strides[],
928 const bool isptr,
929 swig_type_info *tinfo,
930 const int tflags)
931 {
932 PyArrayObject* nparr = NULL;
933 int res = 0;
934 npy_intp idx[ndims];
935
936 // Check that C array pointer is valid.
937 if (ptr == NULL) {
938 return SWIG_MemoryError;
939 }
940
941 // Convert the input Python object to a NumPy array.
942 if (PyArray_Converter(obj, (PyObject**)&nparr) != NPY_SUCCEED) {
943 return SWIG_ValueError;
944 }
945
946 // Check that NumPy array dimensions are consistent with C array dimensions.
947 if (((size_t)PyArray_NDIM(nparr)) != ndims) {
948 res = SWIG_ValueError;
949 goto end;
950 }
951 size_t nelem = 1;
952 for (size_t i = 0; i < ndims; ++i) {
953 if (((size_t)PyArray_DIM(nparr, i)) != dims[i]) {
954 res = SWIG_ValueError;
955 goto end;
956 }
957 nelem *= dims[i];
958 }
959
960 // Iterate over all elements in the C array.
961 memset(idx, 0, ndims*sizeof(npy_intp));
962 for (size_t i = 0; i < nelem; ++i) {
963
964 // Get a pointer to the element of the C array.
965 void* elemptr = swiglal_py_get_element_ptr(ptr, esize, ndims, strides, idx);
966
967 // Copy the NumPy array element to the C array.
968 PyObject* objelem = PyArray_GETITEM(nparr, PyArray_GetPtr((PyArrayObject*)nparr, idx));
969 res = INCALL;
970 if (!SWIG_IsOK(res)) {
971 goto end;
972 }
973 Py_CLEAR(objelem);
974
975 // Increment the NumPy array index.
976 swiglal_py_increment_idx(ndims, dims, idx);
977
978 }
979
980 res = SWIG_OK;
981
982 end:
983 Py_CLEAR(nparr);
984 return res;
985
986 }
987}
988
989// Output copy conversion fragment for arrays of type ACFTYPE.
990%fragment(%swiglal_array_copyout_frag(ACFTYPE), "header",
991 fragment="swiglal_py_array_helpers", fragment=OUTFRAG)
992{
993 SWIGINTERN PyObject* %swiglal_array_copyout_func(ACFTYPE)(PyObject* parent,
994 void* ptr,
995 const size_t esize,
996 const size_t ndims,
997 const size_t dims[],
998 const size_t strides[],
999 const bool isptr,
1000 swig_type_info *tinfo,
1001 const int tflags)
1002 {
1003 PyArrayObject* nparr = NULL;
1004 npy_intp objdims[ndims];
1005 npy_intp idx[ndims];
1006
1007 // Check that C array pointer is valid.
1008 if (ptr == NULL) {
1009 goto fail;
1010 }
1011
1012 // Copy C array dimensions.
1013 size_t nelem = 1;
1014 for (size_t i = 0; i < ndims; ++i) {
1015 objdims[i] = dims[i];
1016 nelem *= dims[i];
1017 }
1018
1019 // Create new NumPy array.
1020 nparr = (PyArrayObject*)PyArray_EMPTY(ndims, objdims, NPYTYPE, 0);
1021 if (nparr == NULL) {
1022 goto fail;
1023 }
1024
1025 // Iterate over all elements in the C array.
1026 memset(idx, 0, ndims*sizeof(npy_intp));
1027 for (size_t i = 0; i < nelem; ++i) {
1028
1029 // Get a pointer to the element of the C array.
1030 void* elemptr = swiglal_py_get_element_ptr(ptr, esize, ndims, strides, idx);
1031
1032 // Copy the C array element to the NumPy array.
1033 const bool copyobj = true;
1034 PyObject* objelem = OUTCALL;
1035 PyArray_SETITEM(nparr, PyArray_GetPtr((PyArrayObject*)nparr, idx), objelem);
1036 Py_CLEAR(objelem);
1037
1038 // Increment the NumPy array index.
1039 swiglal_py_increment_idx(ndims, dims, idx);
1040
1041 }
1042
1043 return (PyObject*)nparr;
1044
1045 fail:
1046 Py_CLEAR(nparr);
1047 Py_INCREF(Py_None);
1048 return Py_None;
1049
1050 }
1051}
1052
1053// Input view conversion fragment for arrays of type ACFTYPE.
1054%fragment(%swiglal_array_viewin_frag(ACFTYPE), "header",
1055 fragment="swiglal_py_array_helpers", fragment=INFRAG)
1056{
1057 SWIGINTERN int %swiglal_array_viewin_func(ACFTYPE)(PyObject* parent,
1058 PyObject* obj,
1059 void** ptr,
1060 const size_t esize,
1061 const size_t ndims,
1062 size_t dims[],
1063 const bool isptr,
1064 swig_type_info *tinfo,
1065 const int tflags)
1066 {
1067 PyArrayObject* nparr = NULL;
1068 int res = 0;
1069
1070 // Check that C array pointer is valid.
1071 if (ptr == NULL) {
1072 return SWIG_MemoryError;
1073 }
1074
1075 // Convert the input Python object to a NumPy array.
1076 if (PyArray_Converter(obj, (PyObject**)&nparr) != NPY_SUCCEED) {
1077 return SWIG_ValueError;
1078 }
1079
1080 // Check that 'nparr' has the correct number of dimensions.
1081 if (((size_t)PyArray_NDIM(nparr)) != ndims) {
1082 res = SWIG_ValueError;
1083 goto end;
1084 }
1085
1086 // Return dimensions of Python array.
1087 for (size_t i = 0; i < ndims; ++i) {
1088 dims[i] = PyArray_DIM(nparr, i);
1089 }
1090
1091 // Cannot view an object which is not a NumPy array.
1092 if (!PyArray_Check(obj)) {
1093 res = SWIG_TypeError;
1094 goto end;
1095 }
1096
1097 // Cannot view an array of pointers.
1098 if (isptr) {
1099 res = SWIG_TypeError;
1100 goto end;
1101 }
1102
1103 // Cannot view an array of objects.
1104 if (NPYTYPE == NPY_OBJECT) {
1105 res = SWIG_TypeError;
1106 goto end;
1107 }
1108
1109 // Cannot view an array which is not in C-array order.
1110 if (!PyArray_ISCARRAY(nparr)) {
1111 res = SWIG_TypeError;
1112 goto end;
1113 }
1114
1115 // Check that 'nparr' is of the correct type.
1116 if (PyArray_TYPE(nparr) != NPYTYPE) {
1117 res = SWIG_TypeError;
1118 goto end;
1119 }
1120
1121 // Check that the elements of 'nparr' have the correct size.
1122 if (((size_t)PyArray_ITEMSIZE(nparr)) != esize) {
1123 res = SWIG_TypeError;
1124 goto end;
1125 }
1126
1127 // Get pointer to Python array data.
1128 *ptr = PyArray_DATA(nparr);
1129 if (*ptr == NULL) {
1130 res = SWIG_ValueError;
1131 goto end;
1132 }
1133
1134 res = SWIG_OK;
1135
1136 end:
1137 Py_CLEAR(nparr);
1138 return res;
1139
1140 }
1141}
1142
1143// Output view conversion fragment for arrays of type ACFTYPE.
1144%fragment(%swiglal_array_viewout_frag(ACFTYPE), "header",
1145 fragment="swiglal_py_array_helpers", fragment=VIEWFRAG, fragment=OUTFRAG)
1146{
1147 SWIGINTERN PyObject* %swiglal_array_viewout_func(ACFTYPE)(PyObject* parent,
1148 void* ptr,
1149 const size_t esize,
1150 const size_t ndims,
1151 const size_t dims[],
1152 const size_t strides[],
1153 const bool isptr,
1154 swig_type_info *tinfo,
1155 const int tflags)
1156 {
1157 PyArrayObject* nparr = NULL;
1158 npy_intp objdims[ndims];
1159 npy_intp objstrides[ndims];
1160
1161 // Check that C array pointer is valid.
1162 if (ptr == NULL) {
1163 goto fail;
1164 }
1165
1166 // Copy C array dimensions and strides.
1167 for (size_t i = 0; i < ndims; ++i) {
1168 objdims[i] = dims[i];
1169 objstrides[i] = strides[i] * esize;
1170 }
1171
1172 // Create a new NumPy array view.
1173 PyArray_Descr* descr = NPYDESCR;
1174 if (descr == NULL) {
1175 goto fail;
1176 }
1177 nparr = (PyArrayObject*)PyArray_NewFromDescr(&PyArray_Type, descr, ndims, objdims, objstrides, ptr, NPY_ARRAY_WRITEABLE, NULL);
1178 if (nparr == NULL) {
1179 goto fail;
1180 }
1181
1182 // Set the NumPy array view parent, if given.
1183 if (parent) {
1184 Py_INCREF(parent);
1185 PyArray_SetBaseObject(nparr, parent);
1186 }
1187
1188 return (PyObject*)nparr;
1189
1190 fail:
1191 Py_CLEAR(nparr);
1192 Py_INCREF(Py_None);
1193 return Py_None;
1194
1195 }
1196}
1197
1198%enddef // %swiglal_py_array_frags
1199
1200// Macro which generates array conversion function fragments to/from Python arrays for object
1201// arrays, which require additional code for views.
1202%define %swiglal_py_array_objview_frags(ACFTYPE, INFRAG, OUTFRAG, INCALL, OUTCALL)
1203%swiglal_py_array_objview(ACFTYPE, INFRAG, OUTFRAG, INCALL, OUTCALL);
1204%swiglal_py_array_frags(ACFTYPE, INFRAG, OUTFRAG, INCALL, OUTCALL,
1205 %swiglal_py_array_objview_frag(ACFTYPE),
1206 NPY_OBJECT, %arg(swiglal_py_array_objview_##ACFTYPE##_descr(isptr, tinfo, esize)));
1207%enddef
1208
1209// Array conversion fragments for generic arrays, e.g. SWIG-wrapped types.
1210%swiglal_py_array_objview_frags(SWIGTYPE, "swiglal_as_SWIGTYPE", "swiglal_from_SWIGTYPE",
1211 %arg(swiglal_as_SWIGTYPE(parent, objelem, elemptr, esize, isptr, tinfo, tflags)),
1212 %arg(swiglal_from_SWIGTYPE(parent, copyobj, elemptr, esize, isptr, tinfo, tflags)));
1213
1214// Array conversion fragments for arrays of LAL strings.
1215%swiglal_py_array_objview_frags(LALchar, "SWIG_AsLALcharPtrAndSize", "SWIG_FromLALcharPtr",
1216 %arg(SWIG_AsLALcharPtrAndSize(objelem, %reinterpret_cast(elemptr, char**), 0, pelemalloc)),
1217 %arg(SWIG_FromLALcharPtr(*%reinterpret_cast(elemptr, char**))));
1218
1219// Macro which generates array conversion function fragments to/from Python arrays for real/fragment
1220// TYPEs which use SWIG_AsVal/From fragments.
1221%define %swiglal_py_array_asvalfrom_frags(TYPE, NPYTYPE)
1222%swiglal_py_array_frags(TYPE, SWIG_AsVal_frag(TYPE), SWIG_From_frag(TYPE),
1223 %arg(SWIG_AsVal(TYPE)(objelem, %reinterpret_cast(elemptr, TYPE*))),
1224 %arg(SWIG_From(TYPE)(*%reinterpret_cast(elemptr, TYPE*))),
1225 "swiglal_empty_frag", NPYTYPE, PyArray_DescrFromType(NPYTYPE));
1226%enddef
1227
1228// Array conversion fragments for integer arrays.
1229%swiglal_py_array_asvalfrom_frags(int8_t, NPY_INT8);
1230%swiglal_py_array_asvalfrom_frags(uint8_t, NPY_UINT8);
1231%swiglal_py_array_asvalfrom_frags(int16_t, NPY_INT16);
1232%swiglal_py_array_asvalfrom_frags(uint16_t, NPY_UINT16);
1233%swiglal_py_array_asvalfrom_frags(int32_t, NPY_INT32);
1234%swiglal_py_array_asvalfrom_frags(uint32_t, NPY_UINT32);
1235%swiglal_py_array_asvalfrom_frags(int64_t, NPY_INT64);
1236%swiglal_py_array_asvalfrom_frags(uint64_t, NPY_UINT64);
1237
1238// Array conversion fragments for floating-precision real arrays.
1239%swiglal_py_array_asvalfrom_frags(float, NPY_FLOAT);
1240%swiglal_py_array_asvalfrom_frags(double, NPY_DOUBLE);
1241
1242// Array conversion fragments for floating-precision complex arrays.
1243%swiglal_py_array_asvalfrom_frags(gsl_complex_float, NPY_CFLOAT);
1244%swiglal_py_array_asvalfrom_frags(gsl_complex, NPY_CDOUBLE);
1245%swiglal_py_array_asvalfrom_frags(COMPLEX8, NPY_CFLOAT);
1246%swiglal_py_array_asvalfrom_frags(COMPLEX16, NPY_CDOUBLE);
1247
1248// Local Variables:
1249// mode: c
1250// End:
#define TYPE
static size_t hash(const char *s)
Definition: LALDict.c:51
static _LAL_INLINE_ int lt(void *params, const void *a, const void *b, int(*compar)(void *, const void *, const void *))
Definition: SearchSorted.c:7
#define crect(re, im)
Construct a COMPLEX16 from real and imaginary parts.
double complex COMPLEX16
Double-precision floating-point complex number (16 bytes total)
#define crectf(re, im)
Construct a COMPLEX8 from real and imaginary parts.
float complex COMPLEX8
Single-precision floating-point complex number (8 bytes total)
static const INT4 a
Definition: Random.c:79
int XLALSetErrno(int errnum)
Sets the XLAL error number to errnum, returns the new value.
Definition: XLALError.c:327
@ XLAL_ENOSYS
Function not implemented.
Definition: XLALError.h:412