contents   index   previous   next



Creating Safe Arrays

 

As explained earlier in the chapter, you use Safe Array handles or Fortran Safe Array Structures to manipulate Safe Arrays in your Fortran applications and subroutines. The most elemental way to create a Safe Array in Fortran is to use f90VB’s SafeArrayCreate. The basic syntax for calling this subroutine is as follows [10]:

 

call SafeArrayCreate(SARef, vtType, nDims, IdxBounds)

 

SARef can be either a null Safe Array handle or an empty Fortran Safe Array Structure. Argument vtType is used to indicate the type of the elements in the Safe Array. f90VB defines several constants (globally referred to as VT-Types) that identify these types as shown in Table 2.1.

 

Argument nDims is the number of dimensions in the array. Argument IdxBounds is an array of SafeArrayBound that defines the bounds (i.e. lower bound and the number of elements) for each dimension of the array. SafeArrayBound has the following definition:

 

type SafeArrayBound
    integer(4)::nElements
    integer(4)::LowerBound
end type SafeArrayBound

 

To create a Safe Array of only one dimension, you can also use the following syntax to call SafeArrayCreate:

 

Call SafeArrayCreate(SARef, vtType, 1, LowerBound, nElements)

 

For 2-dimensional arrays, you can use:

 

call SafeArrayCreate(SARef, vtType, 2, LowerBound1, nElements1, &
                    LowerBound2, nElements2)

 

LowerBound1 and nElements1 are the bounds for the first dimension, and LowerBound2 and nElements2 are the bounds for the second dimension.

 

Safe Arrays created with SafeArrayCreate have some limitations. They are always dynamic arrays (i.e. they can be redimensioned) and you cannot create arrays of User Defined Types (UDT). Changing a dynamic array into a static array is easy, all you need to do is call SafeArraySetFeatures and change the array attributes to static (see the section entitled Setting and Reading Safe Array Features).

 

To work around the limitation regarding UDTs, you use a three-step approach to create the Safe Arrays; first you request an empty Array Descriptor from the OS (calling SafeArrayAllocDescriptor); second, you fill out the descriptor, indicating the characteristics of the Safe Array (including the size in bytes of your UDT); finally you request that the OS allocate the data-block for the Safe Array (calling SafeArrayAllocData).

 

Example 2.4 shows a short program that creates a Safe Array using the traditional method (i.e. calling SafeArrayCreate) and the three-step method. The program first creates a Safe Array (SAHndlA) using SafeArrayCreate and then initializes the array data using SafeArrayPutElement. The second section of the program creates a similar Safe Array, but this time uses the three-step method. This second Safe Array is accessed and initialized using SafeArrayAccessData, which is explained later in this chapter.

 

 

 

 

 

Example 2.4

 

program Example24

 

!Demonstrates several methods to create 

!and access Safe Arrays with f90VB

 

use f90VBDefs

use f90VBSafeArrays

implicit none

 

integer(SAFEARRAY_KIND)::SAHndlA, SAHndlB

 

integer(LONG_KIND)::i,j,LBound, UBound

integer(HRESULT_KIND)::iRet

integer(SHORT_KIND)::vtType

real(REAL_KIND)::rValue

real(REAL_KIND),pointer::R4MappedMatrix(:,:)

 

 

!This section of code illustrates the use of 

!SafeArrayCreate to create a Safe Array matrix 

!of single precision reals

 

!Allocate the Safe Array (3x4)

Call SafeArrayCreate(SAHndlA,VT_R4, 1, 3, 1, 4)

 

!Print the information in the new descriptor

print *,'SAHndlA Descriptor:'

print *,'Handle:',SAHndlA

print *,'Dimensions:',SafeArrayGetDim(SAHndlA)

print *,'Element size:',SafeArrayGetElementSize(SAHndlA)

call SafeArrayGetVarType(SAHndlA,vtType,iRet)

print *,'Data Type:', vtType

print *,'Dimension Bounds:'

call SafeArrayGetLBound(SAHndlA,1,LBound,iRet)

call SafeArrayGetUBound(SAHndlA,1,UBound,iRet)

print *,'Dimension 1:',LBound,' to ', UBound

call SafeArrayGetLBound(SAHndlA,2,LBound,iRet)

call SafeArrayGetUBound(SAHndlA,2,UBound,iRet)

print *,'Dimension 2:',LBound,' to ', UBound

 

!Initialize all elements

call random_seed

do i=1,3

    do j=1,4

        rValue=i*10+j

        call SafeArrayPutElement(SAHndlA,rValue,i,j,iRet)

    enddo

enddo 

 

!print array values

do i=1,3

    do j=1,4

        call SafeArrayGetElement(SAHndlA,rValue,i,j,iRet)

        write(*,'(a1,i1,a1,i1,a2,f10.7)') &

             '(',i,',',j,')=',rValue

    enddo

enddo 

 

!This section of code illustrates the 

!three-step method to create a Safe Array 

!matrix of single precision reals

 

!Allocate the array descriptor

call SafeArrayAllocDescriptor(SAHndlB, VT_R4, 2, iRet)

 

!Set the element size

call SafeArraySetElementSize(SAHndlB,4,iRet)

 

!Set the indexes for the dimensions

call SafeArraySetBounds(SAHndlB,1,1,3,iRet)

call SafeArraySetBounds(SAHndlB,2,1,4,iRet)

 

!Allocate the data block of the Safe Array

call SafeArrayAllocData(SAHndlB,iRet)

 

!Print the information in the new descriptor

print *,''

print *,'SAHndlB Descriptor:'

print *,'Handle:',SAHndlB

print *,'Dimensions:',SafeArrayGetDim(SAHndlB)

print *,'Element size:',SafeArrayGetElementSize(SAHndlB)

call SafeArrayGetVarType(SAHndlB,vtType,iRet)

print *,'Data Type:', vtType

print *,'Dimension Bounds:'

call SafeArrayGetLBound(SAHndlB,1,LBound,iRet)

call SafeArrayGetUBound(SAHndlB,1,UBound,iRet)

print *,'Dimension 1:',LBound,' to ', UBound

call SafeArrayGetLBound(SAHndlB,2,LBound,iRet)

call SafeArrayGetUBound(SAHndlB,2,UBound,iRet)

print *,'Dimension 2:',LBound,' to ', UBound

 

!Map R4MappedMatrix to the Safe Array

call SafeArrayAccessData(SAHndlB,R4MappedMatrix,iRet)

 

!Initialize elements in the Safe Array 

!using mapped matrix

do i=1,3

    do j=1,4

        R4MappedMatrix(i,j)=i*10+j

    enddo

enddo 

 

!Print Safe Array using SafeArrayGetElement

do i=1,3

    do j=1,4

        call SafeArrayGetElement(SAHndlB,rValue,i,j,iRet)

        write(*,'(a1,i1,a1,i1,a2,f10.7)') &

             '(',i,',',j,')=',rValue

 

    enddo

enddo 

 

!But because R4MappedMatrix and SAHndlB share 

!the same data, it would be easier and faster 

!to print the Safe Array as:

print *,''

print *,'SAHndlB accessed through mapped array'

do i=1,3

    write(*,'(4(f10.7,1x))') (R4MappedMatrix(i,j),j=1,4)

enddo

 

!Break the mapping and unlock the safe array

call SafeArrayUnAccessData(SAHndlB,iRet)

 

!Release memory used by mapped matrix

deallocate(R4MappedMatrix)

 

!Release memory used by the Safe Array

call SafeArrayDestroy(SAHndlA, iRet)

call SafeArrayDestroy(SAHndlB, iRet)

 

stop

end