Skip to content

Commit 70946c5

Browse files
authored
Merge pull request #153 from swig-fortran/deferred-array-typemaps
Add deferred-size array typemaps
2 parents 15fd4a9 + 3dbad61 commit 70946c5

File tree

4 files changed

+113
-18
lines changed

4 files changed

+113
-18
lines changed

Examples/test-suite/fortran/fortran_array_typemap_runme.F90

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ program fortran_array_typemap_runme
77

88
call test_ptr_size
99
call test_fixed
10+
call test_deferred
11+
call test_deferred_2d
1012

1113
contains
1214

@@ -26,7 +28,7 @@ subroutine test_ptr_size
2628
ASSERT(accum(int_values) == 2 * 4)
2729
end subroutine
2830

29-
! Test two-argument (pointer + size) -> dynamic
31+
! Test hard-coded dimensions
3032
subroutine test_fixed
3133
use fortran_array_typemap
3234
use ISO_C_BINDING
@@ -52,6 +54,36 @@ subroutine test_fixed
5254
ASSERT(cpp_sum(dbl_values) == sum(dbl_values))
5355
end subroutine
5456

55-
end program
57+
! Test deferred-size arrays
58+
subroutine test_deferred
59+
use fortran_array_typemap
60+
use ISO_C_BINDING
61+
implicit none
62+
real(C_DOUBLE), dimension(5) :: dbl_values
63+
integer :: i
5664

65+
dbl_values = [(i * 2.0d0, i = 1, size(dbl_values))]
5766

67+
ASSERT(cpp_dynamic_sum(size(dbl_values), dbl_values) == sum(dbl_values))
68+
69+
end subroutine
70+
71+
! Test deferred-size arrays
72+
subroutine test_deferred_2d
73+
use fortran_array_typemap
74+
use ISO_C_BINDING
75+
implicit none
76+
real(C_DOUBLE), dimension(3,2) :: points
77+
real(C_DOUBLE), dimension(3) :: avg_points = [-1, -1, -1]
78+
79+
points(:,1) = [-10, 10, 4]
80+
points(:,2) = [10, 10, 0]
81+
call average_points(size(points, 2), points, avg_points)
82+
83+
ASSERT(avg_points(1) == 0.0d0)
84+
ASSERT(avg_points(2) == 10.0d0)
85+
ASSERT(avg_points(3) == 2.0d0)
86+
87+
end subroutine
88+
89+
end program

Examples/test-suite/fortran_array_typemap.i

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,3 +58,46 @@ double cpp_sum(const double inp[3][2]) {
5858
}
5959
%}
6060

61+
/* Test variable-size arguments */
62+
63+
%apply SWIGTYPE ARRAY[] { const double* inp, const double inpv[] };
64+
65+
%inline %{
66+
double cpp_dynamic_sum(int count, const double *inp) {
67+
const double *end = inp + count;
68+
const double *v;
69+
double value = 0;
70+
for (v = inp; v != end; ++v) {
71+
value += *v;
72+
}
73+
return value;
74+
}
75+
76+
double cpp_dynamic_sum_arr(int inpc, const double inpv[]) {
77+
return cpp_dynamic_sum(inpc, inpv);
78+
}
79+
%}
80+
81+
/* Test mixed fixed/variable size */
82+
83+
%apply SWIGTYPE ARRAY[][ANY] { const double points[][3] };
84+
%apply SWIGTYPE ARRAY[ANY] { double avg[3] };
85+
86+
%inline %{
87+
void average_points(int count, const double points[][3], double avg[3]) {
88+
int i, j;
89+
double norm;
90+
avg[0] = avg[1] = avg[2] = 0.0;
91+
for (i = 0; i < count; ++i) {
92+
for (j = 0; j < 3; ++j) {
93+
avg[j] += points[i][j];
94+
}
95+
}
96+
97+
norm = 1.0 / (double)count;
98+
for (j = 0; j < 3; ++j) {
99+
avg[j] *= norm;
100+
}
101+
}
102+
%}
103+

Lib/fortran/typemaps.i

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ $2 = $input->size;
3535
*
3636
* To apply these to a function `void foo(const int x[4]);`:
3737
*
38-
* %apply SWIGTYPE ARRAY[ANY] {const int x[4] };
38+
* %apply SWIGTYPE ARRAY[ANY] {const int x[4] };
3939
*/
4040

4141
%apply FORTRAN_INTRINSIC_TYPE& { SWIGTYPE ARRAY[ANY], SWIGTYPE ARRAY[ANY][ANY], SWIGTYPE ARRAY[ANY][ANY][ANY] }
@@ -69,3 +69,15 @@ $result = $1_temp}
6969
"$typemap(bindc, $1_basetype), dimension($1_dim2,$1_dim1,$1_dim0)"
7070

7171

72+
/* -------------------------------------------------------------------------
73+
* Interact natively with Fortran deferred-size arrays.
74+
*
75+
* To apply these to a function `void foo(const int* x);`:
76+
*
77+
* %apply SWIGTYPE ARRAY[] {const int* x };
78+
*/
79+
80+
%apply SWIGTYPE ARRAY[ANY] { SWIGTYPE ARRAY[] };
81+
%apply SWIGTYPE ARRAY[ANY][ANY] { SWIGTYPE ARRAY[][ANY] };
82+
%apply SWIGTYPE ARRAY[ANY][ANY][ANY] { SWIGTYPE ARRAY[][ANY][ANY] };
83+

Source/Modules/fortran.cxx

Lines changed: 23 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -136,24 +136,32 @@ int fix_fortran_dims(Node *n, const char *tmap_name, String *typemap) {
136136
if (!is_checkdims)
137137
return SWIG_OK;
138138

139-
SwigType* t = Getattr(n, "type");
140-
ASSERT_OR_PRINT_NODE(SwigType_isarray(t), n);
141-
int ndim = SwigType_array_ndim(t);
142-
for (int i = 0; i < ndim; i++) {
143-
String *dim = SwigType_array_getdim(t, i);
144-
if (dim && Len(dim) > 0 && !is_fortran_intexpr(dim)) {
145-
Swig_warning(WARN_LANG_IDENTIFIER, input_file, line_number,
146-
"Array dimension expression '%s' is incompatible with Fortran\n",
147-
dim);
139+
SwigType *t = Getattr(n, "type");
140+
141+
if (SwigType_isarray(t)) {
142+
int ndim = SwigType_array_ndim(t);
143+
for (int i = 0; i < ndim; i++) {
144+
String *dim = SwigType_array_getdim(t, i);
145+
if (dim && Len(dim) > 0 && !is_fortran_intexpr(dim)) {
146+
Swig_warning(WARN_LANG_IDENTIFIER, input_file, line_number, "Array dimension expression '%s' is incompatible with Fortran\n", dim);
147+
Delete(dim);
148+
return SWIG_ERROR;
149+
}
148150
Delete(dim);
149-
return SWIG_ERROR;
150151
}
151-
Delete(dim);
152-
}
153152

154-
// Replace empty dimensions with assumed-size dimension
155-
Replaceall(typemap, "dimension()", "dimension(*)");
156-
Replaceall(typemap, ",)", ",*)");
153+
// Replace empty dimensions with assumed-size dimension
154+
Replaceall(typemap, "dimension()", "dimension(*)");
155+
Replaceall(typemap, ",)", ",*)");
156+
} else if (SwigType_ispointer(t)) {
157+
// Note that we use `imname` instead of `lname` since it was temporarily changed for typemap matching for ftype. Pointers should only have a single
158+
// dimension, so we replace with deferred size.
159+
String *dimname = NewStringf("%s_dim0", Getattr(n, "imname"));
160+
Replaceall(typemap, dimname, "*");
161+
Delete(dimname);
162+
} else {
163+
ASSERT_OR_PRINT_NODE(false, n);
164+
}
157165

158166
return SWIG_OK;
159167
}

0 commit comments

Comments
 (0)