![]() |
ObjexxFCL 3.0 |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
FArrayThe FArray class template hierarchy provides Fortran-compatible arrays with these attributes of Fortran 77 arrays:
and these capabilities not provided by Fortran 77 arrays:
The FArrays are not intended to be a complete numerical matrix class library. A number of general purpose matrix libraries are available for C++ and Objexx Engineering can provide interfacing to those libraries. Objexx Engineering can also provide linear algebra functions and solvers for the FArray classes to meet project requirements. There are five types of FArrays:
The FArrays are class templates. Shorthand (typedef) names are provided for the common value types in the FArray forward declaration headers so, for example, we use FArray2D_int instead of FArray2D< int > on this page. DimensionsThe ObjexxFCL supports automated dynamic array dimensioning based around Dimension parameter objects, as described in the Dimensions section. Index RangesAs in Fortran arrays, the dimensions of FArrays can be an arbitrary index range. These ranges are described in the Index Ranges section. Each FArray class contains a typedef named IR that is the correct IndexRange type for that FArray type: DynamicIndexRange for real and proxy FArrays and StaticIndexRange for argument FArrays, and IndexRange for abstract FArray base classes. SubscriptingFArray elements can be accessed, as in Fortran, by passing a list of indices:
This type of subscripting can add significant overhead in inner loop computations, especially for higher rank arrays. For faster access to array elements when the elements are contiguous or the stride is known the FArrays provide an index member function that returns a zero-based linear index for subscripting via a C-style [] operator, as in:
The index calls return an unsigned value of type FArrayND::size_type but they can be assigned to a signed or smaller integer type if there are no concerns about exceeding the range of that type. To support index math, index doesn't check that the subscript is in bounds for the FArray but linear subscripting accesses to an FArray's elements are bounds-checked via assertions in a debug build: these checks can only determine if the index is within the linear extent of the data array, so the index range checking of each dimension is sacrificed for speed. AssignmentFArrays support the whole-array assignment of any FArray of the same rank and dimensions with the operators {=, +=, -=}:
and the whole-array assignment of any value that is assignment-compatible with the FArray's value type with the operators {=, +=, -=, *=, /=}:
The FArray whole-array assignment operators are supported for value types that support those operators. FArrays also support assignment of different dimensioned arrays of the same rank with the operator = functions:
This will redimension the array if necessary before assigning the values of the other array. For an argument or proxy FArray this redimensioning only changes the view into the data array to which it is attached. Individual FArray elements can be assigned in the usual fashion using multidimensional or linear subscripting:
Warning!: Assignment between real FArrays and (argument or proxy FArray) proxies of them or between proxies of the same real FArray can lead to unexpected results and should be avoided. Base FArraysBase FArrays are the abstract base class for the three concrete types of FArrays of the same rank and value type. Base FArrays classes have names of the form FArrayN<type> with shorthand names of the form FArrayN_type where N is the rank of the array and type is the value type the array hold. Functions written with pass by reference or const reference base FArray arguments can be passed any FArrays of its rank and value type. Real FArraysReal FArrays are normal arrays that own their data. Real FArrays have names of the form FArrayND<type> with shorthand names of the form FArrayND_type where N is the rank of the array and type is the value type the array hold. ConstructionReal FArrays can be constructed in a number of ways. Default construction is not possible with Fortran 77 arrays but is for FArrays:
Default constructed real FArrays can be later dimensioned and allocated with a dimension call as described below. Index range construction is analogous to Fortran 77 array declaration:
To specify an index range with a lower index other than 1 an explicit index range must be specified, as in Fortran. DRange is a shorthand name for DynamicIndexRange, which is the type of index range that a real FArray uses. Copy constructors accept any FArray of the same rank that has an data type that is assignable to the FArray being constructed:
InitializationAs in Fortran, for run-time efficiency arrays are uninitialized by default. An optional final initializer constructor argument can be used to specify a uniform initializer value:
Or an initializer function for non-uniform initialization:
Initializer functions are any void functions that take a non-const reference to the FArray type. Initializer values should be of the exact value type of the FArray to avoid any potential C++ ambiguity when the value is zero of a different type that could be equally well converted to the value type or to a function pointer. Initializers are automatically reapplied when a real FArray is automatically resized because a Dimension that it depends on is modified. Initializer functions for FArrays that may go through such automatic resizing should therefore be written to initialize within the FArray's current dimensional bounds, using the lN and uN functions to access the lower and upper index ranges of dimension N. Explicit resizing with a dimension call (see below) will remove the initializer but a variant dimension call with an extra initializer argument can be used. Data-preserving redimension calls (see below) also remove the initializer. The intializer value or function can be explicitly set with initializer calls and cleared with initializer_clear:
FArrays without initializer values or functions can be default initialized to the default-constructed value of the data type (zero for numeric types) by defining the OBJEXXFCL_FARRAY_INIT macro when compiling (this is done with a -DOBJEXXFCL_FARRAY_INIT switch to GCC and some other compilers). All source files must be compiled with this definition if any are or undefined behavior may result. There could be a significant performance cost to initializing all arrays this way and it can mask initialization errors so this is recommended primarily for transitional use while migrating and debugging code that depended on a Fortran compiler (such as g77) that did (non-standard) zero-initialization of arrays. Explicit DimensioningAlthough Fortran 77 does not provide array resizing real FArrays can be dynamically (re)sized via the dimension member function using a syntax similar to their constructors:
The basic dimension call discards the data that was in the real FArray, removes any initializer associated with it, and does not initialize the redimensioned array (unless the code was compiled with OBJEXXFCL_FARRAY_INIT defined). Real FArrays have a variant of dimension that is analogous to the constructors with an extra initializer argument. The redimension call preserves the data in the real FArray that overlaps with the new dimensions. The elements in any added portions are not initialized unless the redimension variant with a fill value is used:
The redimension calls removes any initializer associated with the real FArray (a fill value is not treated as a new initializer). A new initializer can be assigned to the FArray by an explicit initializer call (see above). Real FArrays can also be dimensioned and redimensioned to match the dimensions of another array:
Warning!: Resizing a real FArray invalidates any argument FArrays attached to it and any proxy FArrays attached to its elements or sections. Proxy FArraysProxy FArrays behave in most ways like a real FArray but they attach to the data of another FArray and do not allocate or own their array data. Proxy FArrays can attach to all or part of FArrays of any rank and dimensions. Typically, they may provide a smaller, lower rank "view" of a slice of a larger array or simply a lower rank "view" of a whole array. This provides the ability to mimic Fortran array passing “tricks” and the memory sharing of a Fortran EQUIVALENCE between two arrays or array sections. Proxy FArrays will automatically redimension themselves if a Dimension they depend on is changed. Proxy FArrays attached to whole FArrays will automatically reattach themselves to the array data if the source array is reallocated. Proxy FArrays have names of the form FArrayNP<type> with shorthand names of the form FArrayNP_type where N is the rank of the array and type is the value type the array hold. ConstructionProxy FArrays can be constructed in a number of ways. Default construction creates an undimensioned proxy FArray that is not attached to another FArray:
Default-constructed proxy FArrays can be later attached and dimensioned with attach and dimension calls as described below. Whole array construction attaches the proxy FArray to the whole source FArray:
You can also construct a whole-array proxy FArray and specify its dimensions with multi-argument constructors:
Proxy FArrays can be constructed from elements of another FArray to create a view of a portion of the array:
The S array is passed an element using the a subscripting function, which creates an FArraySection object that knows its size, which allows bounds error detection in debug builds but at some cost in construction time. When single-argument constructors are used, as when creating a proxy FArray via pass-by-value, default proxy FArray dimensions are used:
Index ranges are specified the same as for real FArrays: DynamicIndexRange is also the index range type used by proxy FArrays.
Attach/DetachProxy FArrays can be dynamically attached and detached from source arrays:
A call to detach detaches a proxy FArray from its source array. It isn't necessary to explicitly detach before attaching to a new source array. The dimension calls (see below) are chained after the attach calls to set the dimensions. The active member function will tell you whether a proxy FArray is currently attached to a source array. Explicit DimensioningProxy FArrays can be dynamically (re)sized via the dimension member function using a syntax similar to their constructors:
Dimensioning proxy FArrays only changes the perceived size of the proxys' view and doesn't cause reallocation of a data array, so no initializing variants of dimension are provided. From the proxys' perspective the elements are reflowed in column-major order to fill the new dimensions, unlike a data-preserving redimension call on a real FArray, which keeps elements in their original index positions as the dimensions change. Attempting to dimension a proxy FArray to a size that exceeds the actual size of the associated data array, if known, will trigger an assertion failure in debug builds. Proxy FArrays can also be dimensioned to match the dimensions of another array:
An assumed-size (upper-unbounded) dimension can be specified for the last dimension by using the ObjexxFCL::star object:
The use of ObjexxFCL::star for the last dimension is analogous to Fortran's assumed-size array dimensioning. If the actual array size is known then the last dimension will be set appropriately so that bounds errors can be caught by assertion failures in debug builds, but if an array element is passed by the fast method the last dimension will have an unbounded upper extent and the array size will be unbounded. The dim function can be used to dimension a const proxy FArray, such as one created via a pass-by-value argument:
Warning!: Resizing a real FArray invalidates any proxy FArrays that are attached to its its elements or sections. Const-CorrectnessProxy and argument FArrays have proxy semantics and share the const-correctness semantics of pointers. The constness of the proxy and the data it is a proxy for are distinct and both are needed to get full constness:
One approach sometimes used to address this issue is to provide always-const versions of the proxy classes. This has the benefit of compile-time const correctness checks but forces a lot of code changes and limits the legal attach operations. The approach used in the ObjexxFCL is different. If the macro OBJEXXFCL_PROXY_CONST_CHECKS is defined when compiling the ObjexxFCL and application code in debug mode (either via a #define in the code or on the compile command line, typically with -DOBJEXXFCL_PROXY_CONST_CHECKS) the proxy FArrays remember if they were attached to const data and, if so, any operations that would alter the array data will trigger assertion failures. This gives the user the choice as to whether strict proxy const-correctness is enforced but only detects violations at runtime via assertion tests. When using GCC on Linux you can set OBJEXXFCL_PROXY_CONST_CHECKS to a value of 2 to turn on a report-only mode that sends backtraces for each violation to stderr but does not abort. Argument FArrays (see below) are typically created via pass-by-value function arguments. If the functions do not need to alter the array values then qualify them with const in the function declaration so that the const array subscript operators will be used, avoiding const-correctness violations. Alternatively, a const reference to the argument FArrays can be used for subscripting operations. Argument FArraysArgument FArrays are very similar to proxy FArrays but are designed for very fast construction as pass-by-value function arguments and, for efficiency, do not automatically redimension when Dimensions used in their index ranges change or automatically reattach to reallocated source arrays. Argument FArrays have names of the form FArrayNA<type> with shorthand names of the form FArrayNA_type where N is the rank of the array and type is the value type the array hold. Construction, assignment, attach/detach, explicit dimensioning and other functions are analogous to those of proxy FArrays. Index ranges are specified the same as for real and proxy FArrays except that StaticIndexRange is the index range type used by argument FArrays. Here is an example of a real FArray of three dimensions being passed to an argument FArray of two dimensions:
When an argument FArray is declared as a pass-by-value argument of a function the actual argument passed becomes the constructor argument to the argument FArray. Argument FArrays must be passed by value to create a proxy of the passed array, but they can also be passed by reference when proxy creation isn't needed (no change to rank or dimensions is required). Although there is no copying of the array data when argument FArrays are constructed there is a small construction cost.
The dim function is like dimension but can be used to set up the argument FArray dimensions even if it is const: this is needed since we can't set the desired dimensions in the argument declaration. Warning!: Resizing a real FArray invalidates any argument FArrays that are attached to its data. Key FArraysKey FArrays are real FArrays that are accessed by key index objects rather than integer indices. Any key type that the Key FArray is able to convert to an integer will work: if the integer index for a key is a protected or private conversion then the Key FArray will have to be a friend of the key type. FArray PassingReal FArrays can be used as function arguments that are declared as passed by value (expensive), reference, or const reference. Within the functions those FArrays have the same rank and dimensions as the passed FArray. To pass FArrays of different rank or dimensions or size or to pass FArray elements as the starting point of an FArray section or slice the function argument must be a proxy or argument FArray declared as pass-by-value. These arrays are constructed at the time of the function call but the underlying data is not copied: since they are proxies for the passed arrays data so the construction cost is modest. Argument FArrays do not automatically redimension themselves when Dimensions used in their index ranges change and do not automatically reattach to source arrays that are reallocated so they are less expensive to construct than proxy FArrays. Arrays and array elements of any rank and size FArray can be passed to a proxy or argument FArray. Although the array data is not copied, the construction of proxy or argument FArrays at each function call can add significant overhead for heavily called functions compared with passing FArrays by reference. If a function will always be passed arrays of the rank and dimensions used by the function it is more efficient for the array arguments to be passed by reference. To support passing all types of FArray of a given rank and value type to a function the arguments should be declared references to the base FArray class of that rank and value type:
Base FArrays support all FArray operations except those with semantics that are specific to the concrete FArray type, such as dimension or attach. FArray Element PassingThere are two ways to pass an array element to an argument array, faster or safer:
The faster method is transparent in the call statement but does not provide the function information about the actual size of the underlying array. The safer method uses the argument member function, a, to provide a proxy for the array tail section starting at the specified element that allows the function to check for array bounds errors in debug builds. FArray SizeFArray sizes are limited to 2N-2 where N is the bit size of std::size_t, so very large arrays are supported on 64-bit platforms where std::size_t is 64 bits. The index range for each dimension is indexed by int, which is still 32 bits on 64-bit platforms, so the size along each dimension is more limited than the total array size on 64-bit platforms. Attempting to create an array with a dimension or total size exceeding these limits is caught by assertion-enabled debug builds. The operating system on a given platform may further limit the allocatable size. The size of an FArray can be obtained via the size member function. For real FArrays this is the actual array data size and for argument and proxy FArrays this is the size of the active array part that it is using, which may be unknown/unbounded. The size_bounded and size_unbounded member functions can be used to test whether the active array has unbounded/unknown extent. The size of the actual array data can be obtained via the array_size member function, and the array_size_bounded and array_size_unbounded member functions can be used to test whether the actual array data has unknown/unbounded extent. FArray Size ReportsFArrays with size greater than or equal to S bytes can be reported to std::cout at the time of construction or re-dimensioning by compiling with a macro defined using one of these methods:
The array name or location of creation isn't known at the point of reporting but the report includes the value type, element count, and index ranges to aid in the identification of the associated array. The value type held by the FArray is the typeid's name() string for that type, which varies by compiler. The codes used by GCC 3.4.x are:
The size is computed as the number of elements times the sizeof the FArray's value type, so FArrays holding value types that have associated heap memory do not show the full memory they use. FArray Activity StateThe active member function can be called to determine whether a real FArray is allocated or whether a proxy or argument FArray is attached to another FArray. Generator FunctionsOperator functions that generate FArrays include the unary minus function and sums and differences of FArrays of the same rank and dimensions and of FArrays and scalar values:
These operators accept all types of FArrays but always produce real FArrays. Special FunctionsFArray1D arrays have the length and length_squared member functions to compute their L2 norm length and squared length and the normalize function to normalize the array to unit length. The dot_product function computes the dot (inner) product of two FArray1Ds. The cross_product function computes the cross product of two FArray1Ds of size 3. FArray2D arrays have the boolean square function to test whether the array is square, the to_identity function to make a square array into the identity matrix and the to_diag function to make a square array into a diagonal matrix with a uniform value. The transpose function transposes a square array and the transposed function returns a transposed copy of the array. The identity and diag static functions are named constructors to create identity and diagonal matrices, respectively. The swap functions allow two real FArrays of the same rank to efficiently swap their contents. There is a single-argument swap member function and a two-argument swap non-member function. Use A.swap( B ) or swap( A, B ) (using std::swap( A, B ) wil be slower on compilers that don't support the provided overloaded function templates). FArray DebuggingFor Fortran-like performance, the FArray classes don't check for array bounds errors in release builds (when NDEBUG is defined). It is therefore important to test assertion-enabled debug builds of code using the FArray classes. To get all proxy/argument FArrays bounds checked it would be necessary to use the safer array element passing method described above, but at some cost to the performance of release builds. FArray OutputStream output operators are provided in separate FArrayN.io.hh header files for FArrays of rank N and, for convenience, a master FArray.io.hh header file that includes the headers for every rank FArray. FArray HeadersHeaders are provided for each FArray rank and type:
Headers for each rank and type of FArray that are used more than "in name" must be included. Because of the inclusion dependencies between the FArray headers you can just include the first header in this sequence that has all the FArray types used to its left: |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| | | | | | | | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Copyright © 2000-2009 Objexx Engineering, Inc. All Rights Reserved. | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||