Working with arrays
Contents
Working with arrays#
TOML supports array data types: flat, ordered containers holding multiple values. Arrays are dynamically sized (i.e. do not need specify the number of elements before using an array) and can contain elements of any type supported by TOML.
The following program parses and stores an array of integers then prints the values to stdout:
program array
use tomlf, only : toml_table, toml_array, get_value, &
& toml_parse, toml_error, len
implicit none
integer, dimension(:), allocatable :: arr_data
integer :: data_len, io, i
type(toml_table), allocatable :: table
type(toml_array), pointer :: arr
type(toml_error), allocatable :: parse_error
open(newunit=io, file="array.toml")
call toml_parse(table, io, parse_error)
close(unit=io)
if (allocated(parse_error)) then
print*, "Error parsing table:"//parse_error%message
end if
! Get the value of "data" by parsing the array and then looping over its
! elements
call get_value(table, "data", arr)
if (associated(arr)) then
data_len = len(arr)
allocate(arr_data(data_len))
do i = 1,data_len
call get_value(arr, i, arr_data(i))
end do
end if
print*, "data = ", arr_data
end program
The simplest way to parse an array-valued key in TOML Fortran is to use the get_value
interface, which has an overload to handle arrays.
First, we need to use a temporary variable arr
(of type toml_array
), as the array’s elements can be of potentially any type.
arr
is automatically associated and allocated by get_value
, which we can use to determine how much space is needed to store the array’s contents.
Finally, we must iterate over all elements of the temporary toml_array
and assign them to an element in our final data structure arr_data
(which is a standard Fortran array).
As a test, let’s run the above program using the following TOML table (array.toml
):
data=[1,2,3,4]
This produces the following output:
data = 1 2 3 4
As mentioned above, TOML arrays can contain elements of any type supported by TOML.
The TOML standard even supports heterogeneous arrays containing elements of multiple different types.
TOML Fortran supports this through the generic toml_array
type.
Elements of toml_array
may be of any value but require extra processing before they can be used in most Fortran programs, since Fortran arrays must only contain elements of a single type known at compile time.
This is achieved through the generic get_value
interface, which automatically coerces elements of the toml_array
to the correct type based on the variable it is copied to.
Tipp
The value in get_value
is an intent(out)
argument, in case the input and output parameter are incompatible, it is not initialized and the actual value is dependent on the compiler settings.
By passing an integer value to the optional stat argument, the procedure will return a non-zero value to indicate an error.
Accessing whole arrays#
If the entries of an array are all of the same type or can be safely casted to a common type it is possible to retrieve a whole array using a single call to get_value
.
program array
use tomlf, only : toml_table, toml_array, get_value, &
& toml_parse, toml_error, len
implicit none
integer, dimension(:), allocatable :: arr_data
integer :: data_len, io, i
type(toml_table), allocatable :: table
type(toml_array), pointer :: arr
type(toml_error), allocatable :: parse_error
open(newunit=io, file="array.toml")
call toml_parse(table, io, parse_error)
close(unit=io)
if (allocated(parse_error)) then
print*, "Error parsing table:"//parse_error%message
end if
call get_value(table, "data", arr)
if (associated(arr)) then
call get_value(arr, arr_data)
end if
print*, "data = ", arr_data
end program
The build interface will allocate the array to the correct size and then iterate over all elements and assign them to the array.
Accessing nested arrays#
TOML arrays can be nested to produce an array-of-arrays. Both the top-level and nested child arrays are potentially variable-length and can contain any TOML data-type (including further nested arrays).
The following program reads a TOML file with an array-of-arrays nested a single level deep, and prints its values to stdout:
program array
use tomlf, only : toml_table, toml_array, get_value, &
& toml_parse, toml_error, len
implicit none
integer :: top_len, nested_len, io, i, j, elem
type(toml_table), allocatable :: table
type(toml_array), pointer :: top_array, nested_array
type(toml_error), allocatable :: parse_error
open(newunit=io, file="nested_array.toml")
call toml_parse(table, io, parse_error)
close(unit=io)
if (allocated(parse_error)) then
print*, "Error parsing table:"//parse_error%message
end if
! Get the top-level array and loop over its elements. Each element is an
! array of variable size
call get_value(table, "data", top_array)
if (associated(top_array)) then
top_len = len(top_array)
do i = 1,top_len
! Now get a pointer to the i'th nested array
call get_value(top_array, i, nested_array)
if (associated(nested_array)) then
nested_len = len(nested_array)
! And get the elements of the nested array
do j = 1,nested_len
call get_value(nested_array, j, elem)
! Do something with "elem" here
write(*,'(A5,i1,A1,i1,A3,i2)') "data(",i,",",j,") = ",elem
end do
end if
end do
end if
end program
First, we need to call get_value
to get a pointer to the top-level array then iterate through its elements, calling get_value
on each to get a pointer to the child array.
Finally, we iterate through the individual sub-arrays and process their elements one-by-one.
This approach has the advantage of being able to deal with nested arrays of arbitrary length, such as the TOML table below:
data=[[1,2,3], [4,5], [6]]
Which produces the following output:
data(1,1) = 1
data(1,2) = 2
data(1,3) = 3
data(2,1) = 4
data(2,2) = 5
data(3,1) = 6
Tipp
A TOML array-of-arrays does not necessarily map cleanly to a regular Fortran multidimensional array. Multidimensional Fortran arrays must be rectangular (i.e. rows must contain the same number of elements), so an array-of-arrays with variable sized nested arrays cannot be directly mapped to a primitive Fortran type and must be represented using a compound data type.