LAL 7.7.1.1-bf6a62b
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// Runtime data
478//
479
480%fragment("SWIG_AsCharPtrAndSize");
481%fragment("SWIG_FromCharPtr");
482%init %{
483
484// Get a pointer to an internal module to store runtime data.
485PyObject* swiglal_runtime_data_module = NULL;
486{
487 const char *const module_name = "swiglal_runtime_data";
488#if PY_VERSION_HEX >= 0x03000000
489 swiglal_runtime_data_module = PyImport_AddModule(module_name);
490#else
491 swiglal_runtime_data_module = Py_InitModule(module_name, NULL);
492#endif
493 assert(swiglal_runtime_data_module != NULL);
494}
495
496// Check for consistent SWIG runtime version number between SWIGLAL wrappers.
497{
498 const char *const swig_runtime_version_name = "swig_runtime_version";
499 const char* const last_swiglal_wrapper_name = "last_swiglal_wrapper";
500 PyObject *swig_runtime_version = NULL;
501 PyObject *last_swiglal_wrapper = NULL;
502 if (PyObject_HasAttrString(swiglal_runtime_data_module, swig_runtime_version_name)) {
503 swig_runtime_version = PyObject_GetAttrString(swiglal_runtime_data_module, swig_runtime_version_name);
504 char *swig_runtime_version_str = NULL;
505 int alloc = 0;
506 int res = SWIG_AsCharPtrAndSize(swig_runtime_version, &swig_runtime_version_str, NULL, &alloc);
507 assert(SWIG_IsOK(res));
508 last_swiglal_wrapper = PyObject_GetAttrString(swiglal_runtime_data_module, last_swiglal_wrapper_name);
509 char *last_swiglal_wrapper_str = NULL;
510 int alloc2 = 0;
511 int res2 = SWIG_AsCharPtrAndSize(last_swiglal_wrapper, &last_swiglal_wrapper_str, NULL, &alloc2);
512 assert(SWIG_IsOK(res2));
513 if (strcmp(swig_runtime_version_str, SWIG_RUNTIME_VERSION) != 0) {
514 PyErr_Format(
515 PyExc_RuntimeError,
516 "Mismatch in SWIG runtime versions: %s is version %s, but %s has already been loaded with version %s",
517 SWIGLAL_PACKAGE, SWIG_RUNTIME_VERSION, last_swiglal_wrapper_str, swig_runtime_version_str
518 );
519 if (alloc) {
520 free(swig_runtime_version_str);
521 }
522 if (alloc2) {
523 free(last_swiglal_wrapper_str);
524 }
525#if SWIG_VERSION >= 0x040400 // int SWIG_mod_exec()
526 return 0;
527#elif PY_VERSION_HEX >= 0x03000000 // PyObject* SWIG_init()
528 return NULL;
529#else // void SWIG_init()
530 return;
531#endif
532 }
533 if (alloc) {
534 free(swig_runtime_version_str);
535 }
536 if (alloc2) {
537 free(last_swiglal_wrapper_str);
538 }
539 Py_DECREF(swig_runtime_version);
540 } else {
541 swig_runtime_version = SWIG_FromCharPtr(SWIG_RUNTIME_VERSION);
542 PyObject_SetAttrString(swiglal_runtime_data_module, swig_runtime_version_name, swig_runtime_version);
543 }
544 last_swiglal_wrapper = SWIG_FromCharPtr(SWIGLAL_PACKAGE);
545 PyObject_SetAttrString(swiglal_runtime_data_module, last_swiglal_wrapper_name, last_swiglal_wrapper);
546}
547
548%} // %init
549
550//
551// Interface code to track object parents
552//
553
554// Interface code which tracks the parent structs of SWIG-wrapped struct members, so that the parent
555// struct is not destroyed as long as a SWIG-wrapped object containing any of its members exists.
556%header %{
557
558// Internal map from member pointers to PyObjects containing the member parent struct, as well as an
559// internal reference count of how many SWIG-wrapped member objects are extant.
560static PyObject *parent_map = NULL;
561
562// Store a reference to the parent of ptr in the internal map. If there is already such a reference,
563// increment the internal reference count instead.
564SWIGINTERN void swiglal_store_parent(void* ptr, PyObject* parent) {
565 PyObject *pyerr_type = NULL, *pyerr_value = NULL, *pyerr_traceback = NULL;
566 PyErr_Fetch(&pyerr_type, &pyerr_value, &pyerr_traceback);
567 int ecode;
568 assert(ptr != NULL);
569 assert(parent != NULL);
570 PyObject* key = PyLong_FromVoidPtr(ptr);
571 assert(key != NULL);
572 PyObject* parent_tuple = PyDict_GetItem(parent_map, key);
573 if (parent_tuple == NULL) {
574 const long ref_count = 1;
575 parent_tuple = Py_BuildValue("Ol", parent, ref_count);
576 assert(parent_tuple != NULL);
577 ecode = PyDict_SetItem(parent_map, key, parent_tuple);
578 assert(ecode == 0);
579 Py_CLEAR(parent_tuple);
580 }
581 else {
582 Py_INCREF(parent_tuple);
583 PyObject* stored_parent = NULL;
584 long ref_count = 0;
585 ecode = PyArg_ParseTuple(parent_tuple, "Ol", &stored_parent, &ref_count);
586 assert(ecode);
587 ++ref_count;
588 Py_INCREF(stored_parent);
589 Py_CLEAR(parent_tuple);
590 parent_tuple = Py_BuildValue("Nl", stored_parent, ref_count);
591 assert(parent_tuple != NULL);
592 ecode = PyDict_SetItem(parent_map, key, parent_tuple);
593 assert(ecode == 0);
594 Py_CLEAR(parent_tuple);
595 }
596 Py_CLEAR(key);
597 assert(PyErr_Occurred() == NULL);
598 PyErr_Restore(pyerr_type, pyerr_value, pyerr_traceback);
599}
600
601// Check if ptr stored a reference to a parent struct. If there is no parent object, then ptr
602// *really* owns its memory, and it's okay for it to destroy it (so return true). Otherwise,
603// decrement the internal reference count, erase the parent map entry if it reaches zero, and
604// return false to prevent any destructors being called.
605SWIGINTERN bool swiglal_release_parent(void *ptr) {
606 PyObject *pyerr_type = NULL, *pyerr_value = NULL, *pyerr_traceback = NULL;
607 PyErr_Fetch(&pyerr_type, &pyerr_value, &pyerr_traceback);
608 int ecode;
609 bool retn = true;
610 assert(ptr != NULL);
611 PyObject* key = PyLong_FromVoidPtr(ptr);
612 assert(key != NULL);
613 PyObject* parent_tuple = PyDict_GetItem(parent_map, key);
614 if (parent_tuple != NULL) {
615 Py_INCREF(parent_tuple);
616 retn = false;
617 PyObject* stored_parent = NULL;
618 long ref_count = 0;
619 ecode = PyArg_ParseTuple(parent_tuple, "Ol", &stored_parent, &ref_count);
620 assert(ecode);
621 Py_INCREF(stored_parent);
622 Py_CLEAR(parent_tuple);
623 if (--ref_count == 0) {
624 ecode = PyDict_DelItem(parent_map, key);
625 assert(ecode == 0);
626 }
627 else {
628 parent_tuple = Py_BuildValue("Ol", stored_parent, ref_count);
629 ecode = PyDict_SetItem(parent_map, key, parent_tuple);
630 assert(ecode == 0);
631 Py_CLEAR(parent_tuple);
632 }
633 Py_CLEAR(stored_parent);
634 }
635 Py_CLEAR(key);
636 assert(PyErr_Occurred() == NULL);
637 PyErr_Restore(pyerr_type, pyerr_value, pyerr_traceback);
638 return retn;
639}
640
641%} // %header
642%init %{
643
644// Get a pointer to the internal parent map. Look for an attribute 'parent_map' of the runtime
645// data module; if it does not exist, create a new map and assign the module attribute,
646// otherwise store the attribute's value. In this way each wrapping module gets a pointer to
647// the same map.
648{
649 const char *const parent_map_name = "parent_map";
650 if (PyObject_HasAttrString(swiglal_runtime_data_module, parent_map_name)) {
651 parent_map = PyObject_GetAttrString(swiglal_runtime_data_module, parent_map_name);
652 }
653 else {
654 parent_map = PyDict_New();
655 PyObject_SetAttrString(swiglal_runtime_data_module, parent_map_name, parent_map);
656 }
657 assert(parent_map != NULL);
658}
659
660%} // %init
661
662//
663// Fragments and typemaps for arrays
664//
665
666// This section implements array conversion functions for basic C array types, and custom NumPy
667// array descriptors for viewing C arrays of object, e.g. structs.
668
669// Fragment defining helper functions for the array conversion functions.
670%fragment("swiglal_py_array_helpers", "header") {
671
672 // Compute the scalar index of the C array element, and return a pointer to the element itself.
673 void* swiglal_py_get_element_ptr(void* ptr,
674 const size_t esize,
675 const size_t ndims,
676 const size_t strides[],
677 npy_intp idx[])
678 {
679 size_t elemidx = 0;
680 for (size_t j = 0; j < ndims; ++j) {
681 elemidx += ((size_t)idx[j]) * strides[j];
682 }
683 return %reinterpret_cast(%reinterpret_cast(ptr, char*) + elemidx*esize, void*);
684 }
685
686 // Increment the NumPy array index in row-major order, to match the ordering of the C array.
687 void swiglal_py_increment_idx(const size_t ndims,
688 const size_t dims[],
689 npy_intp idx[])
690 {
691 for (int j = ((int)ndims) - 1; j >= 0; --j) {
692 if (++idx[j] < ((npy_intp)dims[j])) {
693 break;
694 }
695 idx[j] = 0;
696 }
697 }
698
699 } // fragment swiglal_py_array_helpers
700
701// Fragment defining helper functions for the NumPy object-view array descriptors.
702%fragment("swiglal_py_array_objview", "header") {
703
704 // Struct which associates a SWIG type descriptor with two NumPy array descriptors, one for arrays
705 // of data blocks (_noptr), and one for arrays of pointers (_isptr).
706 typedef struct {
707 swig_type_info* tinfo;
708 PyArray_Descr* descr_noptr;
709 PyArray_Descr* descr_isptr;
710 } swiglal_py_array_type_pair;
711
712 // Static array of SWIG type/NumPy array descriptor pairs. This array should always be long enough
713 // to accommodate all possible swig_type_info*, since they are always members of the
714 // SWIG-generated global array swig_types[]. This array in turn is always one longer than the
715 // total number of types, so there should always be a sentinal NULL element at the end.
716 static swiglal_py_array_type_pair swiglal_py_array_types[sizeof(swig_types) / sizeof(swig_types[0])];
717
718 // This function maps a SWIG type descriptor to a NumPy array descriptor, or returns the first
719 // NULL element if a mapping doesn't exist yet.
720 SWIGINTERN PyArray_Descr** swiglal_py_array_descr_from_tinfo(const bool isptr, swig_type_info* tinfo) {
721 size_t i = 0;
722 while (swiglal_py_array_types[i].tinfo != NULL && swiglal_py_array_types[i].tinfo != tinfo)
723 ++i;
724 if (swiglal_py_array_types[i].tinfo == NULL)
725 swiglal_py_array_types[i].tinfo = tinfo;
726 return isptr ? &swiglal_py_array_types[i].descr_isptr : &swiglal_py_array_types[i].descr_noptr;
727 }
728
729 // This function maps a NumPy array descriptor to a SWIG type descriptor, or returns NULL element
730 // if a mapping doesn't exist.
731 SWIGINTERN void swiglal_py_array_tinfo_from_descr(bool *isptr, swig_type_info** tinfo, PyArray_Descr* descr) {
732 size_t i = 0;
733 while ( ( swiglal_py_array_types[i].descr_noptr != NULL || swiglal_py_array_types[i].descr_isptr != NULL ) &&
734 ( swiglal_py_array_types[i].descr_noptr != descr && swiglal_py_array_types[i].descr_isptr != descr ) )
735 ++i;
736 *isptr = (swiglal_py_array_types[i].descr_isptr == descr);
737 *tinfo = swiglal_py_array_types[i].tinfo;
738 }
739
740 // Array of NumPy types that a NumPy object-view array can be safely cast to.
741 static int swiglal_py_array_objview_copyswap_cancastto[2] = {NPY_OBJECT, NPY_NOTYPE};
742
743 // NumPy array descriptor function for copying/byte-swapping an array element.
744 static void swiglal_py_array_objview_copyswap(void* dst, void* src, int swap, void* arr) {
745
746 // Check input.
747 assert(arr != NULL);
748 PyArrayObject* nparr = (PyArrayObject*)arr;
749 assert(PyArray_DESCR(nparr) != NULL);
750
751 // Copy array element.
752 if (src != NULL) {
753 memcpy(dst, src, PyArray_ITEMSIZE(nparr));
754 }
755
756 // Byte-swap array element, if required.
757 if (swap) {
758 const size_t n = PyArray_ITEMSIZE(nparr) / 2;
759 char *a, *b, c;
760 a = (char *)dst;
761 b = a + (PyArray_ITEMSIZE(nparr)-1);
762 for (size_t i = 0; i < n; i++) {
763 c = *a;
764 *a++ = *b;
765 *b-- = c;
766 }
767 }
768
769 }
770
771} // fragment swiglal_py_array_objview
772
773// Name of fragment containing a NumPy object-view array descriptor for type ACFTYPE.
774#define %swiglal_py_array_objview_frag(ACFTYPE) "swiglal_py_array_objview_" %str(ACFTYPE)
775
776// Name of fragment containing NumPy object-view array descriptor initialisation code for type
777// ACFTYPE.
778#define %swiglal_py_array_objview_init_frag(ACFTYPE) "swiglal_py_array_objview_init_" %str(ACFTYPE)
779
780// Macro which generates fragments containing a NumPy object-view array descriptor for type ACFTYPE.
781// - IN/OUTFRAG are names of fragments required by the in/out conversion functions IN/OUTCALL.
782%define %swiglal_py_array_objview(ACFTYPE, INFRAG, OUTFRAG, INCALL, OUTCALL)
783
784// Fragment containing NumPy object-view array descriptor initialisation code for type ACFTYPE.
785%fragment(%swiglal_py_array_objview_init_frag(ACFTYPE), "init") {
786 swiglal_py_array_objview_##ACFTYPE##_arrfuncs.cast[NPY_OBJECT] =
787 (PyArray_VectorUnaryFunc*)swiglal_py_array_objview_##ACFTYPE##_cast_to_object;
788}
789
790// Fragment containing a NumPy object-view array descriptor for type ACFTYPE.
791%fragment(%swiglal_py_array_objview_frag(ACFTYPE), "header",
792 fragment="swiglal_py_array_objview",
793 fragment=%swiglal_py_array_objview_init_frag(ACFTYPE),
794 fragment=INFRAG, fragment=OUTFRAG)
795{
796
797 // NumPy array descriptor function which gets an element from the viewed array.
798 static PyObject* swiglal_py_array_objview_##ACFTYPE##_getitem(void* elemptr, void* arr) {
799
800 // Check input.
801 assert(elemptr != NULL);
802 assert(arr != NULL);
803 PyArrayObject* nparr = (PyArrayObject*)arr;
804 assert(PyArray_DESCR(nparr) != NULL);
805
806 // Look up the SWIG type descriptor for this array.
807 bool isptr;
808 swig_type_info* tinfo = NULL;
809 swiglal_py_array_tinfo_from_descr(&isptr, &tinfo, PyArray_DESCR(nparr));
810 assert(tinfo != NULL);
811
812 // Get the Python object wrapping the C array element.
813 const bool copyobj = false;
814 const size_t esize = PyArray_ITEMSIZE(nparr);
815 const int tflags = 0;
816 PyObject* parent = PyArray_BASE(nparr);
817 return OUTCALL;
818
819 }
820
821 // NumPy array descriptor function which assigns an element in the viewed array.
822 static int swiglal_py_array_objview_##ACFTYPE##_setitem(PyObject* objelem, void* elemptr, void* arr) {
823
824 // Check input.
825 assert(elemptr != NULL);
826 assert(arr != NULL);
827 PyArrayObject* nparr = (PyArrayObject*)arr;
828 assert(PyArray_DESCR(nparr) != NULL);
829
830 // Look up the SWIG type descriptor for this array.
831 bool isptr;
832 swig_type_info* tinfo = NULL;
833 swiglal_py_array_tinfo_from_descr(&isptr, &tinfo, PyArray_DESCR(nparr));
834 assert(tinfo != NULL);
835
836 // When assigning Python objects to a C array of pointers, assume the struct
837 // who owns the C array takes ownership of the memory of the C array element.
838 // The Python object wrapping the C array element should therefore disown the
839 // underlying memory.
840 // When assigning Python objects to a C array of data blocks, however, the C
841 // array just struct-copies the object rather than taking ownership of its
842 // pointer, and so the Python object should not be disowned so that it can
843 // be garbage-collected later.
844 const int tflags = isptr ? SWIG_POINTER_DISOWN : 0;
845
846 // Set the C array element to the supplied Python object.
847 const size_t esize = PyArray_ITEMSIZE(nparr);
848 PyObject* parent = PyArray_BASE(nparr);
849 int elemalloc = 0;
850 int *pelemalloc = &elemalloc;
851 int res = INCALL;
852 if (!SWIG_IsOK(res)) {
853 SWIG_Error(res, "failure in swiglal_py_array_objview_" #ACFTYPE "_setitem()");
854 return -1;
855 }
856 return 0;
857
858 }
859
860 // NumPy array descriptor function which casts elements of the viewed array to NPY_OBJECTs.
861 static void swiglal_py_array_objview_##ACFTYPE##_cast_to_object(void *from, void *to, npy_intp n, void *fromarr, void *toarr) {
862
863 // Check input.
864 assert(fromarr != NULL);
865 PyArrayObject* npfromarr = (PyArrayObject*)fromarr;
866 assert(PyArray_DESCR(npfromarr) != NULL);
867 assert(toarr != NULL);
868 PyArrayObject* nptoarr = (PyArrayObject*)toarr;
869 assert(PyArray_DESCR(nptoarr) != NULL);
870
871 // 'toarr' should be an array of pointers to PyObjects.
872 assert(PyArray_ITEMSIZE(nptoarr) == sizeof(PyObject*));
873
874 // Loop over 'n' elements, and assign each element of 'toarr' the Python object wrapping the
875 // corresponding element of 'fromarr'.
876 char* fromelem = (void*)from;
877 PyObject** toelem = (PyObject**)to;
878 while (--n >= 0) {
879 *toelem = swiglal_py_array_objview_##ACFTYPE##_getitem(fromelem, fromarr);
880 fromelem += PyArray_ITEMSIZE(npfromarr);
881 ++toelem;
882 }
883
884 }
885
886 // NumPy array descriptor function table for type ACFTYPE.
887 static PyArray_ArrFuncs swiglal_py_array_objview_##ACFTYPE##_arrfuncs = {
888 {(PyArray_VectorUnaryFunc*)NULL}, // cast
889 (PyArray_GetItemFunc*)&swiglal_py_array_objview_##ACFTYPE##_getitem, // getitem
890 (PyArray_SetItemFunc*)&swiglal_py_array_objview_##ACFTYPE##_setitem, // setitem
891 (PyArray_CopySwapNFunc*)NULL, // copyswapn
892 (PyArray_CopySwapFunc*)&swiglal_py_array_objview_copyswap, // copyswap
893 (PyArray_CompareFunc*)NULL, // compare
894 (PyArray_ArgFunc*)NULL, // argmax
895 (PyArray_DotFunc*)NULL, // dotfunc
896 (PyArray_ScanFunc*)NULL, // scanfunc
897 (PyArray_FromStrFunc*)NULL, // fromstr
898 (PyArray_NonzeroFunc*)NULL, // nonzero
899 (PyArray_FillFunc*)NULL, // fill
900 (PyArray_FillWithScalarFunc*)NULL, // fillwithscalar
901 {(PyArray_SortFunc*)NULL}, // sort
902 {(PyArray_ArgSortFunc*)NULL}, // argsort
903 (PyObject*)NULL, // castdict
904 (PyArray_ScalarKindFunc*)NULL, // scalarkind
905 (int**)NULL, // cancastscalarkindto
906 (int*)swiglal_py_array_objview_copyswap_cancastto, // cancastto
907 (void*)NULL, // fastclip, deprecated and unused
908 (void*)NULL, // fastputmask, deprecated and unused
909 (void*)NULL, // fasttake, deprecated and unused
910 };
911
912 // This function returns the NumPy array descriptor appropriate for the supplied SWIG type
913 // descriptor. If no array descriptor exists, it creates one from the array descriptor for type
914 // ACFTYPE.
915 //
916 // Returns a new reference.
917 SWIGINTERN PyArray_Descr* swiglal_py_array_objview_##ACFTYPE##_descr(const bool isptr, swig_type_info* tinfo, const int esize) {
918
919 // Lookup existing NumPy array descriptor for SWIG type descriptor.
920 PyArray_Descr* *pdescr = swiglal_py_array_descr_from_tinfo(isptr, tinfo);
921 if (*pdescr == NULL) {
922 // Create NumPy array descriptor if none yet exists.
923
924 // Note that PyArray_DescrProto structs are supposed to be immortal. They
925 // must not be Py_DECREF'ed. See
926 // https://github.com/numpy/numpy/issues/26763#issuecomment-2181177478.
927 PyArray_DescrProto *proto = PyObject_Malloc(sizeof(PyArray_DescrProto));
928 if (proto == NULL) {
929 PyErr_NoMemory();
930 } else {
931 PyArray_DescrProto src = {
932 PyObject_HEAD_INIT(&PyArrayDescr_Type)
933#if SWIG_VERSION >= 0x040400
934 .typeobj = SwigPyObject_Type(),
935#else
936 .typeobj = SwigPyObject_type(),
937#endif
938 .kind = 'V',
939 .type = 'V',
940 .byteorder = '=',
941 .flags = NPY_LIST_PICKLE | NPY_NEEDS_INIT | NPY_NEEDS_PYAPI | NPY_USE_GETITEM | NPY_USE_SETITEM,
942 .elsize = esize,
943 .alignment = 1,
944 .f = &swiglal_py_array_objview_##ACFTYPE##_arrfuncs,
945 .hash = -1
946 };
947 *proto = src;
948
949 int typenum = PyArray_RegisterDataType(proto);
950 // FIXME: In Numpy 1.x, PyArray_RegisterDataType steals a reference,
951 // whereas in Numpy 2.x, it does not. See
952 // https://github.com/numpy/numpy/issues/26763
953 if (typenum < 0 || PyArray_RUNTIME_VERSION >= NPY_2_0_API_VERSION) {
954 PyObject_Free(proto);
955 }
956
957 if (typenum >= 0) {
958 *pdescr = PyArray_DescrFromType(typenum);
959 }
960 }
961 }
962
963 // PyArray_NewFromDescr steals a reference to the descriptor passed to it:
964 // https://numpy.org/devdocs/reference/c-api/array.html#from-scratch
965 // so a reference count increment is needed here.
966 Py_XINCREF(*pdescr);
967
968 return *pdescr;
969 }
970
971} // %swiglal_py_array_objview_frag(ACFTYPE)
972
973%enddef // %swiglal_py_array_objview
974
975// Macro which generates fragments which define ACFTYPE-specific array view classes and conversion
976// functions:
977// - IN/OUTFRAG are names of fragments required by the in/out conversion functions IN/OUTCALL.
978// - VIEWFRAG is the name of a fragment needed for array views.
979// - NPYTYPE/NPYDESCR is the appropriate NumPy array typenum/descriptor.
980%define %swiglal_py_array_frags(ACFTYPE, INFRAG, OUTFRAG, INCALL, OUTCALL, VIEWFRAG, NPYTYPE, NPYDESCR)
981
982// Input copy conversion fragment for arrays of type ACFTYPE.
983%fragment(%swiglal_array_copyin_frag(ACFTYPE), "header",
984 fragment="swiglal_py_array_helpers", fragment=INFRAG)
985{
986 SWIGINTERN int %swiglal_array_copyin_func(ACFTYPE)(PyObject* parent,
987 PyObject* obj,
988 void* ptr,
989 int *pelemalloc,
990 const size_t esize,
991 const size_t ndims,
992 const size_t dims[],
993 const size_t strides[],
994 const bool isptr,
995 swig_type_info *tinfo,
996 const int tflags)
997 {
998 PyArrayObject* nparr = NULL;
999 int res = 0;
1000 npy_intp idx[ndims];
1001
1002 // Check that C array pointer is valid.
1003 if (ptr == NULL) {
1004 return SWIG_MemoryError;
1005 }
1006
1007 // Convert the input Python object to a NumPy array.
1008 if (PyArray_Converter(obj, (PyObject**)&nparr) != NPY_SUCCEED) {
1009 return SWIG_ValueError;
1010 }
1011
1012 // Check that NumPy array dimensions are consistent with C array dimensions.
1013 if (((size_t)PyArray_NDIM(nparr)) != ndims) {
1014 res = SWIG_ValueError;
1015 goto end;
1016 }
1017 size_t nelem = 1;
1018 for (size_t i = 0; i < ndims; ++i) {
1019 if (((size_t)PyArray_DIM(nparr, i)) != dims[i]) {
1020 res = SWIG_ValueError;
1021 goto end;
1022 }
1023 nelem *= dims[i];
1024 }
1025
1026 // Iterate over all elements in the C array.
1027 memset(idx, 0, ndims*sizeof(npy_intp));
1028 for (size_t i = 0; i < nelem; ++i) {
1029
1030 // Get a pointer to the element of the C array.
1031 void* elemptr = swiglal_py_get_element_ptr(ptr, esize, ndims, strides, idx);
1032
1033 // Copy the NumPy array element to the C array.
1034 PyObject* objelem = PyArray_GETITEM(nparr, PyArray_GetPtr((PyArrayObject*)nparr, idx));
1035 res = INCALL;
1036 if (!SWIG_IsOK(res)) {
1037 goto end;
1038 }
1039 Py_CLEAR(objelem);
1040
1041 // Increment the NumPy array index.
1042 swiglal_py_increment_idx(ndims, dims, idx);
1043
1044 }
1045
1046 res = SWIG_OK;
1047
1048 end:
1049 Py_CLEAR(nparr);
1050 return res;
1051
1052 }
1053}
1054
1055// Output copy conversion fragment for arrays of type ACFTYPE.
1056%fragment(%swiglal_array_copyout_frag(ACFTYPE), "header",
1057 fragment="swiglal_py_array_helpers", fragment=OUTFRAG)
1058{
1059 SWIGINTERN PyObject* %swiglal_array_copyout_func(ACFTYPE)(PyObject* parent,
1060 void* ptr,
1061 const size_t esize,
1062 const size_t ndims,
1063 const size_t dims[],
1064 const size_t strides[],
1065 const bool isptr,
1066 swig_type_info *tinfo,
1067 const int tflags)
1068 {
1069 PyArrayObject* nparr = NULL;
1070 npy_intp objdims[ndims];
1071 npy_intp idx[ndims];
1072
1073 // Check that C array pointer is valid.
1074 if (ptr == NULL) {
1075 goto fail;
1076 }
1077
1078 // Copy C array dimensions.
1079 size_t nelem = 1;
1080 for (size_t i = 0; i < ndims; ++i) {
1081 objdims[i] = dims[i];
1082 nelem *= dims[i];
1083 }
1084
1085 // Create new NumPy array.
1086 nparr = (PyArrayObject*)PyArray_EMPTY(ndims, objdims, NPYTYPE, 0);
1087 if (nparr == NULL) {
1088 goto fail;
1089 }
1090
1091 // Iterate over all elements in the C array.
1092 memset(idx, 0, ndims*sizeof(npy_intp));
1093 for (size_t i = 0; i < nelem; ++i) {
1094
1095 // Get a pointer to the element of the C array.
1096 void* elemptr = swiglal_py_get_element_ptr(ptr, esize, ndims, strides, idx);
1097
1098 // Copy the C array element to the NumPy array.
1099 const bool copyobj = true;
1100 PyObject* objelem = OUTCALL;
1101 PyArray_SETITEM(nparr, PyArray_GetPtr((PyArrayObject*)nparr, idx), objelem);
1102 Py_CLEAR(objelem);
1103
1104 // Increment the NumPy array index.
1105 swiglal_py_increment_idx(ndims, dims, idx);
1106
1107 }
1108
1109 return (PyObject*)nparr;
1110
1111 fail:
1112 Py_CLEAR(nparr);
1113 Py_INCREF(Py_None);
1114 return Py_None;
1115
1116 }
1117}
1118
1119// Input view conversion fragment for arrays of type ACFTYPE.
1120%fragment(%swiglal_array_viewin_frag(ACFTYPE), "header",
1121 fragment="swiglal_py_array_helpers", fragment=INFRAG)
1122{
1123 SWIGINTERN int %swiglal_array_viewin_func(ACFTYPE)(PyObject* parent,
1124 PyObject* obj,
1125 void** ptr,
1126 const size_t esize,
1127 const size_t ndims,
1128 size_t dims[],
1129 const bool isptr,
1130 swig_type_info *tinfo,
1131 const int tflags)
1132 {
1133 PyArrayObject* nparr = NULL;
1134 int res = 0;
1135
1136 // Check that C array pointer is valid.
1137 if (ptr == NULL) {
1138 return SWIG_MemoryError;
1139 }
1140
1141 // Convert the input Python object to a NumPy array.
1142 if (PyArray_Converter(obj, (PyObject**)&nparr) != NPY_SUCCEED) {
1143 return SWIG_ValueError;
1144 }
1145
1146 // Check that 'nparr' has the correct number of dimensions.
1147 if (((size_t)PyArray_NDIM(nparr)) != ndims) {
1148 res = SWIG_ValueError;
1149 goto end;
1150 }
1151
1152 // Return dimensions of Python array.
1153 for (size_t i = 0; i < ndims; ++i) {
1154 dims[i] = PyArray_DIM(nparr, i);
1155 }
1156
1157 // Cannot view an object which is not a NumPy array.
1158 if (!PyArray_Check(obj)) {
1159 res = SWIG_TypeError;
1160 goto end;
1161 }
1162
1163 // Cannot view an array of pointers.
1164 if (isptr) {
1165 res = SWIG_TypeError;
1166 goto end;
1167 }
1168
1169 // Cannot view an array of objects.
1170 if (NPYTYPE == NPY_OBJECT) {
1171 res = SWIG_TypeError;
1172 goto end;
1173 }
1174
1175 // Cannot view an array which is not in C-array order.
1176 if (!PyArray_ISCARRAY(nparr)) {
1177 res = SWIG_TypeError;
1178 goto end;
1179 }
1180
1181 // Check that 'nparr' is of the correct type.
1182 if (PyArray_TYPE(nparr) != NPYTYPE) {
1183 res = SWIG_TypeError;
1184 goto end;
1185 }
1186
1187 // Check that the elements of 'nparr' have the correct size.
1188 if (((size_t)PyArray_ITEMSIZE(nparr)) != esize) {
1189 res = SWIG_TypeError;
1190 goto end;
1191 }
1192
1193 // Get pointer to Python array data.
1194 *ptr = PyArray_DATA(nparr);
1195 if (*ptr == NULL) {
1196 res = SWIG_ValueError;
1197 goto end;
1198 }
1199
1200 res = SWIG_OK;
1201
1202 end:
1203 Py_CLEAR(nparr);
1204 return res;
1205
1206 }
1207}
1208
1209// Output view conversion fragment for arrays of type ACFTYPE.
1210%fragment(%swiglal_array_viewout_frag(ACFTYPE), "header",
1211 fragment="swiglal_py_array_helpers", fragment=VIEWFRAG, fragment=OUTFRAG)
1212{
1213 SWIGINTERN PyObject* %swiglal_array_viewout_func(ACFTYPE)(PyObject* parent,
1214 void* ptr,
1215 const size_t esize,
1216 const size_t ndims,
1217 const size_t dims[],
1218 const size_t strides[],
1219 const bool isptr,
1220 swig_type_info *tinfo,
1221 const int tflags)
1222 {
1223 PyArrayObject* nparr = NULL;
1224 npy_intp objdims[ndims];
1225 npy_intp objstrides[ndims];
1226
1227 // Check that C array pointer is valid.
1228 if (ptr == NULL) {
1229 goto fail;
1230 }
1231
1232 // Copy C array dimensions and strides.
1233 for (size_t i = 0; i < ndims; ++i) {
1234 objdims[i] = dims[i];
1235 objstrides[i] = strides[i] * esize;
1236 }
1237
1238 // Create a new NumPy array view.
1239 PyArray_Descr* descr = NPYDESCR;
1240 if (descr == NULL) {
1241 goto fail;
1242 }
1243 nparr = (PyArrayObject*)PyArray_NewFromDescr(&PyArray_Type, descr, ndims, objdims, objstrides, ptr, NPY_ARRAY_WRITEABLE, NULL);
1244 if (nparr == NULL) {
1245 goto fail;
1246 }
1247
1248 // Set the NumPy array view parent, if given.
1249 if (parent) {
1250 Py_INCREF(parent);
1251 PyArray_SetBaseObject(nparr, parent);
1252 }
1253
1254 return (PyObject*)nparr;
1255
1256 fail:
1257 Py_CLEAR(nparr);
1258 Py_INCREF(Py_None);
1259 return Py_None;
1260
1261 }
1262}
1263
1264%enddef // %swiglal_py_array_frags
1265
1266// Macro which generates array conversion function fragments to/from Python arrays for object
1267// arrays, which require additional code for views.
1268%define %swiglal_py_array_objview_frags(ACFTYPE, INFRAG, OUTFRAG, INCALL, OUTCALL)
1269%swiglal_py_array_objview(ACFTYPE, INFRAG, OUTFRAG, INCALL, OUTCALL);
1270%swiglal_py_array_frags(ACFTYPE, INFRAG, OUTFRAG, INCALL, OUTCALL,
1271 %swiglal_py_array_objview_frag(ACFTYPE),
1272 NPY_OBJECT, %arg(swiglal_py_array_objview_##ACFTYPE##_descr(isptr, tinfo, esize)));
1273%enddef
1274
1275// Array conversion fragments for generic arrays, e.g. SWIG-wrapped types.
1276%swiglal_py_array_objview_frags(SWIGTYPE, "swiglal_as_SWIGTYPE", "swiglal_from_SWIGTYPE",
1277 %arg(swiglal_as_SWIGTYPE(parent, objelem, elemptr, esize, isptr, tinfo, tflags)),
1278 %arg(swiglal_from_SWIGTYPE(parent, copyobj, elemptr, esize, isptr, tinfo, tflags)));
1279
1280// Array conversion fragments for arrays of LAL strings.
1281%swiglal_py_array_objview_frags(LALchar, "SWIG_AsLALcharPtrAndSize", "SWIG_FromLALcharPtr",
1282 %arg(SWIG_AsLALcharPtrAndSize(objelem, %reinterpret_cast(elemptr, char**), 0, pelemalloc)),
1283 %arg(SWIG_FromLALcharPtr(*%reinterpret_cast(elemptr, char**))));
1284
1285// Macro which generates array conversion function fragments to/from Python arrays for real/fragment
1286// TYPEs which use SWIG_AsVal/From fragments.
1287%define %swiglal_py_array_asvalfrom_frags(TYPE, NPYTYPE)
1288%swiglal_py_array_frags(TYPE, SWIG_AsVal_frag(TYPE), SWIG_From_frag(TYPE),
1289 %arg(SWIG_AsVal(TYPE)(objelem, %reinterpret_cast(elemptr, TYPE*))),
1290 %arg(SWIG_From(TYPE)(*%reinterpret_cast(elemptr, TYPE*))),
1291 "swiglal_empty_frag", NPYTYPE, PyArray_DescrFromType(NPYTYPE));
1292%enddef
1293
1294// Array conversion fragments for integer arrays.
1295%swiglal_py_array_asvalfrom_frags(int8_t, NPY_INT8);
1296%swiglal_py_array_asvalfrom_frags(uint8_t, NPY_UINT8);
1297%swiglal_py_array_asvalfrom_frags(int16_t, NPY_INT16);
1298%swiglal_py_array_asvalfrom_frags(uint16_t, NPY_UINT16);
1299%swiglal_py_array_asvalfrom_frags(int32_t, NPY_INT32);
1300%swiglal_py_array_asvalfrom_frags(uint32_t, NPY_UINT32);
1301%swiglal_py_array_asvalfrom_frags(int64_t, NPY_INT64);
1302%swiglal_py_array_asvalfrom_frags(uint64_t, NPY_UINT64);
1303
1304// Array conversion fragments for floating-precision real arrays.
1305%swiglal_py_array_asvalfrom_frags(float, NPY_FLOAT);
1306%swiglal_py_array_asvalfrom_frags(double, NPY_DOUBLE);
1307
1308// Array conversion fragments for floating-precision complex arrays.
1309%swiglal_py_array_asvalfrom_frags(gsl_complex_float, NPY_CFLOAT);
1310%swiglal_py_array_asvalfrom_frags(gsl_complex, NPY_CDOUBLE);
1311%swiglal_py_array_asvalfrom_frags(COMPLEX8, NPY_CFLOAT);
1312%swiglal_py_array_asvalfrom_frags(COMPLEX16, NPY_CDOUBLE);
1313
1314// Local Variables:
1315// mode: c
1316// 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