Skip to content

Commit 4891416

Browse files
committed
Added fortran typemaps for 2D (contiguous) arrays.
* Added macros for 2D arrays in fortranarray.swg * Added prox struct to hold reference to a 2D array (pointer, # of rows, and # of cols) in fundamental.swg * Added fragments and typemaps for 2D array proxy in fundamental.swg * Added typemaps for the 2D arrays in typemaps.i To apply the typemaps to a function like: void foo(double* x, int x_rows, int x_cols); Use: %apply (SWIGTYPE *DATA, size_t ROWS, size_t COLS) { (double *x, int x_rows, int x_cols) };
1 parent 5a3bb15 commit 4891416

File tree

3 files changed

+206
-0
lines changed

3 files changed

+206
-0
lines changed

Lib/fortran/fortranarray.swg

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,3 +102,88 @@ end subroutine}
102102
%typemap(fargout, noblock=1) const CPPTYPE& {};
103103
%enddef
104104

105+
/* -------------------------------------------------------------------------
106+
* Additional macros for 2D arrays
107+
/* -------------------------------------------------------------------------
108+
/*!
109+
* \def %fortran_2d_array
110+
*
111+
* Use the \c Swig2DArrayWrapper for the ISO C binding layer.
112+
*
113+
* Based on fortran_array macro.
114+
*/
115+
%define %fortran_2d_array(CPPTYPE...)
116+
// C wrapper type: pointer to templated array wrapper
117+
%typemap(ctype, in="Swig2DArrayWrapper*",
118+
null="Swig2DArrayWrapper_uninitialized()",
119+
fragment="Swig2DArrayWrapper_uninitialized", noblock=1) CPPTYPE
120+
"Swig2DArrayWrapper"
121+
122+
// Interface type: fortran equivalent of "ctype"
123+
// Since the type is declared in the module, it's necessary to use the
124+
// fortran "import" statement to bring it into scope.
125+
%typemap(imtype, fragment="Swig2DArrayWrapper_f", noblock=1) CPPTYPE
126+
"type(Swig2DArrayWrapper)"
127+
%enddef
128+
129+
/* ------------------------------------------------------------------------- */
130+
/*!
131+
* \def %fortran_2d_array_pointer
132+
*
133+
* Wrap intermediate data values as array pointers.
134+
*
135+
* This defines:
136+
* - C type interface
137+
* - IM type interface
138+
* - FIN/FOUT
139+
* - FTYPE array pointer
140+
*/
141+
%define %fortran_2d_array_pointer(VTYPE, CPPTYPE...)
142+
%fortran_2d_array(CPPTYPE)
143+
144+
// Fortran proxy code: input is target 2D array
145+
%typemap(ftype, in="$typemap(imtype, " #VTYPE "), dimension(:,:), target", noblock=1) CPPTYPE {
146+
$typemap(imtype, VTYPE), dimension(:,:), pointer
147+
}
148+
149+
// Look up typemaps defined by %fortran_intrinsic
150+
%typemap(fin, noblock=1) CPPTYPE {$typemap(fin, VTYPE ARRAY[][])}
151+
%typemap(fout, noblock=1) CPPTYPE {$typemap(fout, VTYPE ARRAY[][])}
152+
%enddef
153+
154+
/* ------------------------------------------------------------------------- */
155+
/*!
156+
* \def %fortran_2d_array_handle
157+
*
158+
* Convert a C++ input argument to an array pointer.
159+
*
160+
* For example, the function
161+
* \code
162+
void f(double** data, size_t* rows, size_t* cols);
163+
\endcode
164+
* would take a Fortran array pointer as an (INOUT) argument.
165+
*
166+
* This defines:
167+
* - C type interface
168+
* - IM type interface
169+
* - FIN
170+
* - FTYPE array pointer
171+
*
172+
* which means you still must define the C++ <--> C conversions elsewhere.
173+
* Make sure to add the `match="in"` keyword to the `argout` typemap.
174+
*/
175+
%define %fortran_2d_array_handle(VTYPE, CPPTYPE...)
176+
177+
// Input arguments for pointer-by-ref are the same
178+
%typemap(ftype, in="$typemap(imtype, " #VTYPE "), dimension(:,:), pointer, intent(inout)", noblock=1) CPPTYPE& {
179+
$typemap(imtype, VTYPE), dimension(:,:), pointer
180+
}
181+
%typemap(fin, match="ftype", noblock=1) CPPTYPE& {$typemap(fin, VTYPE ARRAY[][])}
182+
%typemap(imtype) CPPTYPE& = CPPTYPE;
183+
%typemap(ctype) CPPTYPE& = CPPTYPE;
184+
185+
// Update the resulting Fortran pointer, but only by reference (not const ref)
186+
%typemap(fargout, match="fin", noblock=1) CPPTYPE& = VTYPE ARRAY[][];
187+
%typemap(fargout, noblock=1) const CPPTYPE& {};
188+
%enddef
189+

Lib/fortran/fundamental.swg

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@ subroutine %fortrantm(fout, bool)(imout, fout)
4848
end subroutine
4949
}
5050

51+
//////////////////////////////////////////////////////////////////////////////////////////////////
52+
// Structure to hold a reference to a 1D array
53+
5154
#ifdef __cplusplus
5255
%fragment("SwigArrayWrapper", "header", fragment="<stdlib.h>") %{
5356
struct SwigArrayWrapper {
@@ -80,6 +83,45 @@ SWIGINTERN SwigArrayWrapper SwigArrayWrapper_uninitialized() {
8083
integer(C_SIZE_T), public :: size = 0
8184
end type}
8285

86+
//////////////////////////////////////////////////////////////////////////////////////////////////
87+
// Structure to hold a reference to a 2D array in contiguous memory
88+
89+
#ifdef __cplusplus
90+
%fragment("Swig2DArrayWrapper", "header", fragment="<stdlib.h>") %{
91+
struct Swig2DArrayWrapper {
92+
void* data;
93+
size_t rows;
94+
size_t cols;
95+
};
96+
%}
97+
#else
98+
%fragment("Swig2DArrayWrapper", "header", fragment="<stdlib.h>") %{
99+
typedef struct {
100+
void* data;
101+
size_t rows;
102+
size_t cols;
103+
} Swig2DArrayWrapper;
104+
%}
105+
#endif
106+
107+
%fragment("Swig2DArrayWrapper_uninitialized", "header", fragment="Swig2DArrayWrapper") %{
108+
SWIGINTERN Swig2DArrayWrapper Swig2DArrayWrapper_uninitialized() {
109+
Swig2DArrayWrapper result;
110+
result.data = NULL;
111+
result.rows = 0;
112+
result.cols = 0;
113+
return result;
114+
}
115+
%}
116+
117+
// Add 2D array wrapper to Fortran types when used
118+
%fragment("Swig2DArrayWrapper_f", "fdecl", noblock=1)
119+
{ type, bind(C) :: Swig2DArrayWrapper
120+
type(C_PTR), public :: data = C_NULL_PTR
121+
integer(C_SIZE_T), public :: rows = 0
122+
integer(C_SIZE_T), public :: cols = 0
123+
end type}
124+
83125

84126
/* -------------------------------------------------------------------------
85127
* MACROS
@@ -167,6 +209,9 @@ SWIGINTERN SwigArrayWrapper SwigArrayWrapper_uninitialized() {
167209

168210
%typemap(bindc) CTYPE* = FORTRAN_INTRINSIC_TYPE*;
169211

212+
////////////////////////////////////////////////////////////////////////////////////////////////
213+
// 1D Arrays
214+
170215
// Fragment for converting array to array wrapper. This needs the intermediate step of assigning the first element to an array pointer to be compatible with
171216
// ISO C.
172217
%fragment("SWIG_fin"{CTYPE[]}, "fsubprograms", fragment="SwigArrayWrapper_f", noblock=1)
@@ -207,6 +252,54 @@ end subroutine}
207252
call %fortrantm(fout, CTYPE[])($1, $input)
208253
}
209254
%typemap(fargout) CTYPE const ARRAY[] = CTYPE ARRAY[];
255+
256+
////////////////////////////////////////////////////////////////////////////////////////////////
257+
// 2D Arrays
258+
259+
// Fragment for converting a 2D array to a 2D array wrapper. This needs the intermediate step of assigning the first element to an array pointer to be compatible with
260+
// ISO C.
261+
%fragment("SWIG_fin"{CTYPE[][]}, "fsubprograms", fragment="Swig2DArrayWrapper_f", noblock=1)
262+
{subroutine %fortrantm(fin, CTYPE[][])(finp, iminp)
263+
use, intrinsic :: ISO_C_BINDING
264+
FTYPE(FKIND), dimension(:,:), intent(in), target :: finp
265+
type(Swig2DArrayWrapper), intent(out) :: iminp
266+
integer(C_SIZE_T) :: sz
267+
FTYPE(FKIND), pointer :: imtemp
268+
269+
sz = size(finp, kind=C_SIZE_T)
270+
if (sz > 0_c_size_t) then
271+
imtemp => finp(1,1)
272+
iminp%data = c_loc(imtemp)
273+
iminp%rows = size(finp, 1, kind=C_SIZE_T)
274+
iminp%cols = size(finp, 2, kind=C_SIZE_T)
275+
else
276+
iminp%data = c_null_ptr
277+
iminp%rows = 0
278+
iminp%cols = 0
279+
end if
280+
end subroutine}
281+
282+
// Fragment for converting 2D array wrapper to a Fortran 2D array
283+
%fragment("SWIG_fout"{CTYPE[][]}, "fsubprograms", noblock=1)
284+
{subroutine %fortrantm(fout, CTYPE[][])(imout, fout)
285+
use, intrinsic :: ISO_C_BINDING
286+
type(Swig2DArrayWrapper), intent(in) :: imout
287+
FTYPE(FKIND), dimension(:,:), pointer, intent(out) :: fout
288+
289+
if (imout%size > 0) then
290+
call c_f_pointer(imout%data, fout, [imout%rows, imout%cols])
291+
else
292+
fout => NULL()
293+
endif
294+
end subroutine}
295+
296+
// Define proxy code typemaps for a 2D array of this type
297+
%fortran_typemap_finout(CTYPE[][], CTYPE ARRAY[][])
298+
%typemap(fargout, fragment="SWIG_fout"{CTYPE[][]}, noblock=1) CTYPE ARRAY[][] {
299+
call %fortrantm(fout, CTYPE[][])($1, $input)
300+
}
301+
%typemap(fargout) CTYPE const ARRAY[][] = CTYPE ARRAY[][];
302+
210303
%enddef
211304

212305
/*!

Lib/fortran/typemaps.i

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,34 @@ $2 = $input->size;
3030
$typemap(imtype, $*1_ltype), dimension(:), pointer
3131
}
3232

33+
/* -------------------------------------------------------------------------
34+
* Enable seamless translation of consecutive pointer/size1/size2 arguments
35+
* to Fortran 2D array views.
36+
*
37+
* To apply these to a function `void foo(double* x, int x_rows, int x_cols);`:
38+
*
39+
* %apply (SWIGTYPE *DATA, size_t ROWS, size_t COLS) { (double *x, int x_rows, int x_cols) };
40+
*/
41+
42+
43+
/* Transform the two-argument typemap into an array pointer */
44+
%fortran_2d_array_pointer($*1_ltype, %arg((SWIGTYPE *DATA, size_t ROWS, size_t COLS)))
45+
46+
/* Transform (Swig2DArrayWrapper *$input) -> (SWIGTYPE *DATA, size_t ROWS, size_t COLS) */
47+
%typemap(in, noblock=1) (SWIGTYPE *DATA, size_t ROWS, size_t COLS) {
48+
$1 = ($1_ltype)$input->data;
49+
$2 = $input->rows;
50+
$3 = $input->cols;
51+
}
52+
53+
/* Apply the typemaps to const versions as well */
54+
%apply (SWIGTYPE *DATA, size_t ROWS, size_t COLS) { (const SWIGTYPE *DATA, size_t ROWS, size_t COLS) };
55+
56+
/* Add 'intent(in)' for const arrays */
57+
%typemap(ftype, in="$typemap(imtype, $*1_ltype), dimension(:,:), intent(in), target", noblock=1) (const SWIGTYPE *DATA, size_t ROWS, size_t COLS) {
58+
$typemap(imtype, $*1_ltype), dimension(:,:), pointer
59+
}
60+
3361
/* -------------------------------------------------------------------------
3462
* Interact natively with Fortran fixed-size arrays.
3563
*

0 commit comments

Comments
 (0)