! BSD 2-Clause License ! ! Copyright (c) 2021-2022, Hewlett Packard Enterprise ! All rights reserved. ! ! Redistribution and use in source and binary forms, with or without ! modification, are permitted provided that the following conditions are met: ! ! 1. Redistributions of source code must retain the above copyright notice, this ! list of conditions and the following disclaimer. ! ! 2. Redistributions in binary form must reproduce the above copyright notice, ! this list of conditions and the following disclaimer in the documentation ! and/or other materials provided with the distribution. ! ! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" ! AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ! IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ! DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE ! FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ! DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR ! SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER ! CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, ! OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ! OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. module smartredis_dataset use iso_c_binding, only : c_ptr, c_bool, c_null_ptr, c_char, c_int use iso_c_binding, only : c_int8_t, c_int16_t, c_int32_t, c_int64_t, c_float, c_double, c_size_t use iso_c_binding, only : c_loc, c_f_pointer use fortran_c_interop, only : enum_kind implicit none; private include 'enum_fortran.inc' include 'dataset/dataset_interfaces.inc' include 'dataset/add_tensor_interfaces.inc' include 'dataset/unpack_dataset_tensor_interfaces.inc' include 'dataset/metadata_interfaces.inc' public :: enum_kind !< The kind of integer equivalent to a C enum. According to C an Fortran !! standards this should be c_int, but is renamed here to ensure that !! users do not have to import the iso_c_binding module into their !! programs !> Contains multiple tensors and metadata used to describe an entire set of data type, public :: dataset_type type(c_ptr) :: dataset_ptr !< A pointer to the initialized dataset object contains !> Initialize a new dataset with a given name procedure :: initialize => initialize_dataset !> Add metadata to the dataset with a given field and string procedure :: add_meta_string ! procedure :: get_meta_strings ! Not supported currently !> Add a tensor to be included as part of the dataset generic :: add_tensor => add_tensor_i8, add_tensor_i16, add_tensor_i32, add_tensor_i64, & add_tensor_float, add_tensor_double !> Unpack a tensor that has previously been added to the dataset generic :: unpack_dataset_tensor => unpack_dataset_tensor_i8, unpack_dataset_tensor_i16, & unpack_dataset_tensor_i32, unpack_dataset_tensor_i64, & unpack_dataset_tensor_float, unpack_dataset_tensor_double !> Add metadata of type 'scalar' into a given field generic :: add_meta_scalar => add_meta_scalar_double, add_meta_scalar_float, add_meta_scalar_i32, add_meta_scalar_i64 !> Retrieve scalar-type metadata as a vector generic :: get_meta_scalars => get_meta_scalars_double, get_meta_scalars_float, get_meta_scalars_i32, & get_meta_scalars_i64 ! Private procedures procedure, private :: add_tensor_i8 procedure, private :: add_tensor_i16 procedure, private :: add_tensor_i32 procedure, private :: add_tensor_i64 procedure, private :: add_tensor_float procedure, private :: add_tensor_double procedure, private :: unpack_dataset_tensor_i8 procedure, private :: unpack_dataset_tensor_i16 procedure, private :: unpack_dataset_tensor_i32 procedure, private :: unpack_dataset_tensor_i64 procedure, private :: unpack_dataset_tensor_float procedure, private :: unpack_dataset_tensor_double procedure, private :: add_meta_scalar_double procedure, private :: add_meta_scalar_float procedure, private :: add_meta_scalar_i32 procedure, private :: add_meta_scalar_i64 procedure, private :: get_meta_scalars_double procedure, private :: get_meta_scalars_float procedure, private :: get_meta_scalars_i32 procedure, private :: get_meta_scalars_i64 end type dataset_type contains !> Initialize the dataset function initialize_dataset(self, name) result(code) class(dataset_type), intent(inout) :: self !< Receives the dataset character(len=*), intent(in) :: name !< Name of the dataset integer(kind=enum_kind) :: code !< Result of the operation ! Local variables integer(kind=c_size_t) :: name_length character(kind=c_char, len=len_trim(name)) :: c_name name_length = len_trim(name) c_name = trim(name) code = dataset_constructor(c_name, name_length, self%dataset_ptr) end function initialize_dataset !> Add a tensor to a dataset whose Fortran type is the equivalent 'int8' C-type function add_tensor_i8(self, name, data, dims) result(code) integer(kind=c_int8_t), dimension(..), target, intent(in) :: data !< Data to be sent class(dataset_type), intent(in) :: self !< Fortran SmartRedis dataset character(len=*), intent(in) :: name !< The unique name used to store in the database integer, dimension(:), intent(in) :: dims !< The length of each dimension integer(kind=enum_kind) :: code !< Result of the operation include 'dataset/add_tensor_methods_common.inc' ! Define the type and call the C-interface data_type = tensor_int8 code = add_tensor_c(self%dataset_ptr, c_name, name_length, data_ptr, & c_dims_ptr, c_n_dims, data_type, c_fortran_contiguous) end function add_tensor_i8 !> Add a tensor to a dataset whose Fortran type is the equivalent 'int16' C-type function add_tensor_i16(self, name, data, dims) result(code) integer(kind=c_int16_t), dimension(..), target, intent(in) :: data !< Data to be sent class(dataset_type), intent(in) :: self !< Fortran SmartRedis dataset character(len=*), intent(in) :: name !< The unique name used to store in the database integer, dimension(:), intent(in) :: dims !< The length of each dimension integer(kind=enum_kind) :: code !< Result of the operation include 'dataset/add_tensor_methods_common.inc' ! Define the type and call the C-interface data_type = tensor_int16 code = add_tensor_c(self%dataset_ptr, c_name, name_length, data_ptr, & c_dims_ptr, c_n_dims, data_type, c_fortran_contiguous) end function add_tensor_i16 !> Add a tensor to a dataset whose Fortran type is the equivalent 'int32' C-type function add_tensor_i32(self, name, data, dims) result(code) integer(kind=c_int32_t), dimension(..), target, intent(in) :: data !< Data to be sent class(dataset_type), intent(in) :: self !< Fortran SmartRedis dataset character(len=*), intent(in) :: name !< The unique name used to store in the database integer, dimension(:), intent(in) :: dims !< The length of each dimension integer(kind=enum_kind) :: code !< Result of the operation include 'dataset/add_tensor_methods_common.inc' ! Define the type and call the C-interface data_type = tensor_int32 code = add_tensor_c(self%dataset_ptr, c_name, name_length, data_ptr, & c_dims_ptr, c_n_dims, data_type, c_fortran_contiguous) end function add_tensor_i32 !> Add a tensor to a dataset whose Fortran type is the equivalent 'int64' C-type function add_tensor_i64(self, name, data, dims) result(code) integer(kind=c_int64_t), dimension(..), target, intent(in) :: data !< Data to be sent class(dataset_type), intent(in) :: self !< Fortran SmartRedis dataset character(len=*), intent(in) :: name !< The unique name used to store in the database integer, dimension(:), intent(in) :: dims !< The length of each dimension integer(kind=enum_kind) :: code !< Result of the operation include 'dataset/add_tensor_methods_common.inc' ! Define the type and call the C-interface data_type = tensor_int64 code = add_tensor_c(self%dataset_ptr, c_name, name_length, data_ptr, & c_dims_ptr, c_n_dims, data_type, c_fortran_contiguous) end function add_tensor_i64 !> Add a tensor to a dataset whose Fortran type is the equivalent 'float' C-type function add_tensor_float(self, name, data, dims) result(code) real(kind=c_float), dimension(..), target, intent(in) :: data !< Data to be sent class(dataset_type), intent(in) :: self !< Fortran SmartRedis dataset character(len=*), intent(in) :: name !< The unique name used to store in the database integer, dimension(:), intent(in) :: dims !< The length of each dimension integer(kind=enum_kind) :: code !< Result of the operation include 'dataset/add_tensor_methods_common.inc' ! Define the type and call the C-interface data_type = tensor_flt code = add_tensor_c(self%dataset_ptr, c_name, name_length, data_ptr, & c_dims_ptr, c_n_dims, data_type, c_fortran_contiguous) end function add_tensor_float !> Add a tensor to a dataset whose Fortran type is the equivalent 'double' C-type function add_tensor_double(self, name, data, dims) result(code) real(kind=c_double), dimension(..), target, intent(in) :: data !< Data to be sent class(dataset_type), intent(in) :: self !< Fortran SmartRedis dataset character(len=*), intent(in) :: name !< The unique name used to store in the database integer, dimension(:), intent(in) :: dims !< The length of each dimension integer(kind=enum_kind) :: code !< Result of the operation include 'dataset/add_tensor_methods_common.inc' ! Define the type and call the C-interface data_type = tensor_dbl code = add_tensor_c(self%dataset_ptr, c_name, name_length, data_ptr, & c_dims_ptr, c_n_dims, data_type, c_fortran_contiguous) end function add_tensor_double !> Unpack a tensor into already allocated memory whose Fortran type is the equivalent 'int8' C-type function unpack_dataset_tensor_i8(self, name, result, dims) result(code) integer(kind=c_int8_t), dimension(..), target, intent(out) :: result !< Array to be populated with data class(dataset_type), intent(in) :: self !< Pointer to the initialized dataset character(len=*), intent(in) :: name !< The name to use to place the tensor integer, dimension(:), intent(in) :: dims !< Length along each dimension of the tensor integer(kind=enum_kind) :: code include 'dataset/unpack_dataset_tensor_methods_common.inc' ! Define the type and call the C-interface data_type = tensor_int8 code = unpack_dataset_tensor_c(self%dataset_ptr, c_name, name_length, & data_ptr, c_dims_ptr, c_n_dims, data_type, mem_layout) end function unpack_dataset_tensor_i8 !> Unpack a tensor into already allocated memory whose Fortran type is the equivalent 'int16' C-type function unpack_dataset_tensor_i16(self, name, result, dims) result(code) integer(kind=c_int16_t), dimension(..), target, intent(out) :: result !< Array to be populated with data class(dataset_type), intent(in) :: self !< Pointer to the initialized dataset character(len=*), intent(in) :: name !< The name to use to place the tensor integer, dimension(:), intent(in) :: dims !< Length along each dimension of the tensor integer(kind=enum_kind) :: code include 'dataset/unpack_dataset_tensor_methods_common.inc' ! Define the type and call the C-interface data_type = tensor_int16 code = unpack_dataset_tensor_c(self%dataset_ptr, c_name, name_length, & data_ptr, c_dims_ptr, c_n_dims, data_type, mem_layout) end function unpack_dataset_tensor_i16 !> Unpack a tensor into already allocated memory whose Fortran type is the equivalent 'int32' C-type function unpack_dataset_tensor_i32(self, name, result, dims) result(code) integer(kind=c_int32_t), dimension(..), target, intent(out) :: result !< Array to be populated with data class(dataset_type), intent(in) :: self !< Pointer to the initialized dataset character(len=*), intent(in) :: name !< The name to use to place the tensor integer, dimension(:), intent(in) :: dims !< Length along each dimension of the tensor integer(kind=enum_kind) :: code include 'dataset/unpack_dataset_tensor_methods_common.inc' ! Define the type and call the C-interface data_type = tensor_int32 code = unpack_dataset_tensor_c(self%dataset_ptr, c_name, name_length, & data_ptr, c_dims_ptr, c_n_dims, data_type, mem_layout) end function unpack_dataset_tensor_i32 !> Unpack a tensor into already allocated memory whose Fortran type is the equivalent 'int64' C-type function unpack_dataset_tensor_i64(self, name, result, dims) result(code) integer(kind=c_int64_t), dimension(..), target, intent(out) :: result !< Array to be populated with data class(dataset_type), intent(in) :: self !< Pointer to the initialized dataset character(len=*), intent(in) :: name !< The name to use to place the tensor integer, dimension(:), intent(in) :: dims !< Length along each dimension of the tensor integer(kind=enum_kind) :: code include 'dataset/unpack_dataset_tensor_methods_common.inc' ! Define the type and call the C-interface data_type = tensor_int64 code = unpack_dataset_tensor_c(self%dataset_ptr, c_name, name_length, & data_ptr, c_dims_ptr, c_n_dims, data_type, mem_layout) end function unpack_dataset_tensor_i64 !> Unpack a tensor into already allocated memory whose Fortran type is the equivalent 'float' C-type function unpack_dataset_tensor_float(self, name, result, dims) result(code) real(kind=c_float), dimension(..), target, intent(out) :: result !< Array to be populated with data class(dataset_type), intent(in) :: self !< Pointer to the initialized dataset character(len=*), intent(in) :: name !< The name to use to place the tensor integer, dimension(:), intent(in) :: dims !< Length along each dimension of the tensor integer(kind=enum_kind) :: code include 'dataset/unpack_dataset_tensor_methods_common.inc' ! Define the type and call the C-interface data_type = tensor_flt code = unpack_dataset_tensor_c(self%dataset_ptr, c_name, name_length, & data_ptr, c_dims_ptr, c_n_dims, data_type, mem_layout) end function unpack_dataset_tensor_float !> Unpack a tensor into already allocated memory whose Fortran type is the equivalent 'double' C-type function unpack_dataset_tensor_double(self, name, result, dims) result(code) real(kind=c_double), dimension(..), target, intent(out) :: result !< Array to be populated with data class(dataset_type), intent(in) :: self !< Pointer to the initialized dataset character(len=*), intent(in) :: name !< The name to use to place the tensor integer, dimension(:), intent(in) :: dims !< Length along each dimension of the tensor integer(kind=enum_kind) :: code include 'dataset/unpack_dataset_tensor_methods_common.inc' ! Define the type and call the C-interface data_type = tensor_dbl code = unpack_dataset_tensor_c(self%dataset_ptr, c_name, name_length, & data_ptr, c_dims_ptr, c_n_dims, data_type, mem_layout) end function unpack_dataset_tensor_double !> Get scalar metadata whose Fortran type is the equivalent 'int32' C-type function get_meta_scalars_i32(self, name, meta) result(code) class(dataset_type), intent(in) :: self !< The dataset character(len=*), intent(in) :: name !< The name of the metadata field integer(kind=c_int32_t), dimension(:), pointer :: meta !< The actual metadata integer(kind=enum_kind) :: code !< Result of the operation ! local variables integer(kind=enum_kind) :: expected_data_type = meta_int32 include 'dataset/get_meta_scalars_common.inc' end function get_meta_scalars_i32 !> Get scalar metadata whose Fortran type is the equivalent 'int64' C-type function get_meta_scalars_i64(self, name, meta) result(code) class(dataset_type), intent(in) :: self !< The dataset character(len=*), intent(in) :: name !< The name of the metadata field integer(kind=c_int64_t), dimension(:), pointer :: meta !< The actual metadata integer(kind=enum_kind) :: code !< Result of the operation ! local variables integer(kind=enum_kind) :: expected_data_type = meta_int64 include 'dataset/get_meta_scalars_common.inc' end function get_meta_scalars_i64 !> Get scalar metadata whose Fortran type is the equivalent 'float' C-type function get_meta_scalars_float(self, name, meta) result(code) class(dataset_type), intent(in) :: self !< The dataset character(len=*), intent(in) :: name !< The name of the metadata field real(kind=c_float), dimension(:), pointer :: meta !< The actual metadata integer(kind=enum_kind) :: code !< Result of the operation ! local variables integer(kind=enum_kind) :: expected_data_type = meta_flt include 'dataset/get_meta_scalars_common.inc' end function get_meta_scalars_float !> Get scalar metadata whose Fortran type is the equivalent 'double' C-type function get_meta_scalars_double(self, name, meta) result(code) class(dataset_type), intent(in) :: self !< The dataset character(len=*), intent(in) :: name !< The name of the metadata field real(kind=c_double), dimension(:), pointer :: meta !< The actual metadata integer(kind=enum_kind) :: code !< Result of the operation ! local variables integer(kind=enum_kind) :: expected_data_type = meta_dbl include 'dataset/get_meta_scalars_common.inc' end function get_meta_scalars_double !> Add scalar metadata whose Fortran type is the equivalent 'int32' C-type function add_meta_scalar_i32(self, name, meta) result(code) class(dataset_type), intent(in) :: self !< The dataset character(len=*), intent(in) :: name !< The name of the metadata field integer(kind=c_int32_t), target, intent(in) :: meta !< The actual metadata integer(kind=enum_kind) :: code !< Result of the operation ! local variables integer(kind=enum_kind), parameter :: meta_type = meta_int32 include 'dataset/add_meta_scalar_common.inc' end function add_meta_scalar_i32 !> Add scalar metadata whose Fortran type is the equivalent 'int64' C-type function add_meta_scalar_i64(self, name, meta) result(code) class(dataset_type), intent(in) :: self !< The dataset character(len=*), intent(in) :: name !< The name of the metadata field integer(kind=c_int64_t), target, intent(in) :: meta !< The actual metadata integer(kind=enum_kind) :: code !< Result of the operation ! local variables integer(kind=enum_kind), parameter :: meta_type = meta_int64 include 'dataset/add_meta_scalar_common.inc' end function add_meta_scalar_i64 !> Add scalar metadata whose Fortran type is the equivalent 'float' C-type function add_meta_scalar_float(self, name, meta) result(code) class(dataset_type), intent(in) :: self !< The dataset character(len=*), intent(in) :: name !< The name of the metadata field real(kind=c_float), target, intent(in) :: meta !< The actual metadata integer(kind=enum_kind) :: code !< Result of the operation ! local variables integer(kind=enum_kind), parameter :: meta_type = meta_flt include 'dataset/add_meta_scalar_common.inc' end function add_meta_scalar_float !> Add scalar metadata whose Fortran type is the equivalent 'double' C-type function add_meta_scalar_double(self, name, meta) result(code) class(dataset_type), intent(in) :: self !< The dataset character(len=*), intent(in) :: name !< The name of the metadata field real(kind=c_double), target, intent(in) :: meta !< The actual metadata integer(kind=enum_kind) :: code !< Result of the operation ! local variables integer(kind=enum_kind), parameter :: meta_type = meta_dbl include 'dataset/add_meta_scalar_common.inc' end function add_meta_scalar_double !> Add string-like metadata to the dataset function add_meta_string( self, name, meta) result(code) class(dataset_type), intent(in) :: self !< The dataset character(len=*), intent(in) :: name !< The name of the metadata field character(len=*), intent(in) :: meta !< The actual metadata integer(kind=enum_kind) :: code !< Result of the operation ! local variables character(kind=c_char, len=len_trim(meta)) :: c_meta character(kind=c_char, len=len_trim(name)) :: c_name integer(kind=c_size_t) :: meta_length, name_length c_name = trim(name) c_meta = trim(meta) meta_length = len_trim(c_meta) name_length = len_trim(c_name) code = add_meta_string_c(self%dataset_ptr, c_name, name_length, c_meta, meta_length) end function add_meta_string end module smartredis_dataset