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