Skip to content

Commit 290eccd

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 645acea commit 290eccd

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
@@ -36,6 +36,9 @@ subroutine %fortrantm(fout, bool)(imout, fout)
3636
end subroutine
3737
}
3838

39+
//////////////////////////////////////////////////////////////////////////////////////////////////
40+
// Structure to hold a reference to a 1D array
41+
3942
#ifdef __cplusplus
4043
%fragment("SwigArrayWrapper", "header", fragment="<stdlib.h>") %{
4144
struct SwigArrayWrapper {
@@ -68,6 +71,45 @@ SWIGINTERN SwigArrayWrapper SwigArrayWrapper_uninitialized() {
6871
integer(C_SIZE_T), public :: size = 0
6972
end type}
7073

74+
//////////////////////////////////////////////////////////////////////////////////////////////////
75+
// Structure to hold a reference to a 2D array in contiguous memory
76+
77+
#ifdef __cplusplus
78+
%fragment("Swig2DArrayWrapper", "header", fragment="<stdlib.h>") %{
79+
struct Swig2DArrayWrapper {
80+
void* data;
81+
size_t rows;
82+
size_t cols;
83+
};
84+
%}
85+
#else
86+
%fragment("Swig2DArrayWrapper", "header", fragment="<stdlib.h>") %{
87+
typedef struct {
88+
void* data;
89+
size_t rows;
90+
size_t cols;
91+
} Swig2DArrayWrapper;
92+
%}
93+
#endif
94+
95+
%fragment("Swig2DArrayWrapper_uninitialized", "header", fragment="Swig2DArrayWrapper") %{
96+
SWIGINTERN Swig2DArrayWrapper Swig2DArrayWrapper_uninitialized() {
97+
Swig2DArrayWrapper result;
98+
result.data = NULL;
99+
result.rows = 0;
100+
result.cols = 0;
101+
return result;
102+
}
103+
%}
104+
105+
// Add 2D array wrapper to Fortran types when used
106+
%fragment("Swig2DArrayWrapper_f", "fdecl", noblock=1)
107+
{ type, bind(C) :: Swig2DArrayWrapper
108+
type(C_PTR), public :: data = C_NULL_PTR
109+
integer(C_SIZE_T), public :: rows = 0
110+
integer(C_SIZE_T), public :: cols = 0
111+
end type}
112+
71113

72114
/* -------------------------------------------------------------------------
73115
* MACROS
@@ -155,6 +197,9 @@ SWIGINTERN SwigArrayWrapper SwigArrayWrapper_uninitialized() {
155197

156198
%typemap(bindc) CTYPE* = FORTRAN_INTRINSIC_TYPE*;
157199

200+
////////////////////////////////////////////////////////////////////////////////////////////////
201+
// 1D Arrays
202+
158203
// 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
159204
// ISO C.
160205
%fragment("SWIG_fin"{CTYPE[]}, "fsubprograms", fragment="SwigArrayWrapper_f", noblock=1)
@@ -195,6 +240,54 @@ end subroutine}
195240
call %fortrantm(fout, CTYPE[])($1, $input)
196241
}
197242
%typemap(fargout) CTYPE const ARRAY[] = CTYPE ARRAY[];
243+
244+
////////////////////////////////////////////////////////////////////////////////////////////////
245+
// 2D Arrays
246+
247+
// 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
248+
// ISO C.
249+
%fragment("SWIG_fin"{CTYPE[][]}, "fsubprograms", fragment="Swig2DArrayWrapper_f", noblock=1)
250+
{subroutine %fortrantm(fin, CTYPE[][])(finp, iminp)
251+
use, intrinsic :: ISO_C_BINDING
252+
FTYPE(FKIND), dimension(:,:), intent(in), target :: finp
253+
type(Swig2DArrayWrapper), intent(out) :: iminp
254+
integer(C_SIZE_T) :: sz
255+
FTYPE(FKIND), pointer :: imtemp
256+
257+
sz = size(finp, kind=C_SIZE_T)
258+
if (sz > 0_c_size_t) then
259+
imtemp => finp(1,1)
260+
iminp%data = c_loc(imtemp)
261+
iminp%rows = size(finp, 1, kind=C_SIZE_T)
262+
iminp%cols = size(finp, 2, kind=C_SIZE_T)
263+
else
264+
iminp%data = c_null_ptr
265+
iminp%rows = 0
266+
iminp%cols = 0
267+
end if
268+
end subroutine}
269+
270+
// Fragment for converting 2D array wrapper to a Fortran 2D array
271+
%fragment("SWIG_fout"{CTYPE[][]}, "fsubprograms", noblock=1)
272+
{subroutine %fortrantm(fout, CTYPE[][])(imout, fout)
273+
use, intrinsic :: ISO_C_BINDING
274+
type(Swig2DArrayWrapper), intent(in) :: imout
275+
FTYPE(FKIND), dimension(:,:), pointer, intent(out) :: fout
276+
277+
if (imout%size > 0) then
278+
call c_f_pointer(imout%data, fout, [imout%rows, imout%cols])
279+
else
280+
fout => NULL()
281+
endif
282+
end subroutine}
283+
284+
// Define proxy code typemaps for a 2D array of this type
285+
%fortran_typemap_finout(CTYPE[][], CTYPE ARRAY[][])
286+
%typemap(fargout, fragment="SWIG_fout"{CTYPE[][]}, noblock=1) CTYPE ARRAY[][] {
287+
call %fortrantm(fout, CTYPE[][])($1, $input)
288+
}
289+
%typemap(fargout) CTYPE const ARRAY[][] = CTYPE ARRAY[][];
290+
198291
%enddef
199292

200293
/*!

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)