/* C */ double * sidl_double__array_first(const struct sidl_double__array *src); // C++ double* first() throw(); C FORTRAN 77 subroutine sidl_double__array_access_f(array, ref, lower, upper, $ stride, index) integer*8 array, index integer*4 lower(), upper(), stride() integer*4 ref()
This method provides direct access to the element data. Using this pointer and the stride information, you can perform your own array accesses without function calls. This method isn't available for arrays of strings, interface and objects because of memory/reference management issues. There is no equivalent of this function in Java or Python. To see how to get direct array access in Fortran 90, see Chapter 9.
The Fortran versions of the method return the lower, upper and stride information in three arrays, each with enough elements to hold an entry for each dimension of array. Because FORTRAN 77 does not have pointers, you must pass in a reference array, array. Upon exit, ref(index) is the first element of the array. The type of ref depends on the type of the array.
WARNING: While calling the Fortran direct access routines, there is a possibility of an alignment error between your reference pointer, ref, and the pointer to the first element of the array data. The problem is more likely with arrays of double or dcomplex; although, it could occur with any type on some future platform. If index is zero on return, an alignment error occurred. If an alignment error occurs, you may be able to solve it by recompiling your Fortran files with flags to force doubles to be aligned on 8 byte boundaries. For example, the -malign-double flag for g77 forces doubles to be aligned on 64-bit boundaries. An alignment error occurs when (char *)ref minus (char *)sidl_double__array_first(array) is not integer divisible by sizeof(datatype) where ref refers to the address of the reference array.
Here is an example FORTRAN 77 subroutine to output each element of a 1-dimensional array of doubles using the direct access routine. Fortran 90 has a pointer in the array derived type when direct access is possible.
C This subroutine will print each element of an array of doubles subroutine print_array(dblarray) implicit none integer*8 dblarray, index real*8 refarray(1) integer*4 lower(1), upper(1), stride(1), dimen, i if (dblarray .ne. 0) then call sidl_double__array_dimen_f(dblarray, dimen) if (dimen .eq. 1) then call sidl_double__array_access_f(dblarray, refarray, $ lower, upper, stride, index) if (index .ne. 0) then do i = lower(1), upper(1) write(*,*) refarray(index + (i-lower(1))*stride(1)) enddo else write(*,*) 'Alignment error occured' endif endif endif end
For a 2-dimensional array, the loop and array access is
do i = lower(1), upper(1) do j = lower(2), upper(2) write(*,*) refarray(index+(i-lower(1))*stride(1)+ $ (j - lower(2))*stride(2)) enddo enddo
Suppose you are wrapping a legacy Fortran application and you need to pass a SIDL array to a Fortran subroutine. Further suppose there is a FORTRAN 77 and Fortran 90 version of the subroutine. For example, the FORTRAN 77 subroutine has a signature such as:
subroutine TriedAndTrue(x, n) integer n real*8 x(n) C insert wonderful, efficient, debugged code here end
The Fortran 90 subroutine has basically the same signature as follows:
subroutine TriedAndTrue(x, n) integer (selected_int_kind(9)) :: n real (selected_real_kind(17, 308)) :: x(n) ! insert wonderful, efficient, debugged code here end subroutine TriedAndTrue
Here is one way to wrap this method using SIDL. First of all, the SIDL method definition specifies that the array must be a 1-dimensional, column-major ordered array. This forces the incoming array to be a dense column.
static void TriedAndTrue(inout array<double,1,column-major> arg);
Given that method definition in a class named Class and a package named Pkg, the implementation of the wrapper should look something like the following for FORTRAN 77:
subroutine Pkg_Class_TriedAndTrue_fi(arg) implicit none integer*8 arg C DO-NOT-DELETE splicer.begin(Pkg.Class.TriedAndTrue) real*8 refarray(1) integer*4 lower(1), upper(1), stride(1) integer*8 index integer n call sidl_double__array_access_f(arg, refarray, $ lower, upper, stride, index) if (index .ne. 0) then c we can assume stride(1) = 1 because of column-major specification n = 1 + upper(1) - lower(1) call TriedAndTrue(refarray(index), n) else write(*,*) 'ERROR: array alignment' endif C DO-NOT-DELETE splicer.end(Pkg.Class.TriedAndTrue) end
Similarly, it should look something like the following for Fortran 90, where the include statements are required at the top of the Impl file to ensure proper handling of subroutine names that have automatically been mangled by the Babel compiler:
#include "Pkg_Class_fAbbrev.h" #include "sidl_BaseClass_fAbbrev.h" #include "sidl_BaseInterface_fAbbrev.h" ! DO-NOT-DELETE splicer.begin(_miscellaneous_code_start) #include "sidl_double_fAbbrev.h" ! DO-NOT-DELETE splicer.end(_miscellaneous_code_start) . . . subroutine Pkg_Class_TriedAndTrue_mi(arg) ! DO-NOT-DELETE splicer.begin(Pkg.Class.TriedAndTrue.use) use SIDL_double_array ! DO-NOT-DELETE splicer.end(Pkg.Class.TriedAndTrue.use) implicit none type(sidl_double_a) :: arg ! DO-NOT-DELETE splicer.begin(Pkg.Class.TriedAndTrue) real (selected_real_kind(17,308)), dimension(1) :: refarray integer (selected_int_kind(8)), dimension(1) :: low, up, str integer (selected_int_kind(8)) :: index, n call access(arg, refarray, low, up, str, index) if (index .ne. 0) then ! We can assume stride(1) = 1 because of column-major specification n = 1 + upper(1) - lower(1) call TriedAndTrue(refarray(index), n) else write(*,*) 'ERROR: array alignment' endif ! DO-NOT-DELETE splicer.end(Pkg.Class.TriedAndTrue) end subroutine Pkg_Class_TriedAndTrue_mi