Skip to content

Commit ee3566a

Browse files
committed
string: unify with h5fortran, incl. UTF8 passthrough
1 parent 26d709f commit ee3566a

12 files changed

+346
-169
lines changed

CMakeLists.txt

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,26 @@ endif()
5050

5151
# --- HDF5-MPI object oriented API
5252

53+
add_library(h5mpi)
54+
target_include_directories(h5mpi PUBLIC
55+
$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/include>
56+
$<INSTALL_INTERFACE:include>
57+
)
58+
target_link_libraries(h5mpi PUBLIC HDF5::HDF5 MPI::MPI_Fortran)
59+
set_target_properties(h5mpi PROPERTIES
60+
Fortran_MODULE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/include
61+
LABELS core
62+
VERSION ${PROJECT_VERSION}
63+
)
64+
65+
# GLOBAL needed for use by FetchContent
66+
add_library(h5mpi::h5mpi INTERFACE IMPORTED GLOBAL)
67+
target_link_libraries(h5mpi::h5mpi INTERFACE h5mpi)
68+
69+
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/include/h5mpi.mod TYPE INCLUDE)
70+
71+
install(TARGETS h5mpi EXPORT ${PROJECT_NAME}-targets)
72+
5373
add_subdirectory(src)
5474

5575
if(${PROJECT_NAME}_BUILD_TESTING)

cmake/hdf5.cmake

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ INACTIVITY_TIMEOUT 60
8484
file(MAKE_DIRECTORY ${HDF5_INCLUDE_DIRS})
8585
# avoid race condition
8686

87-
# this GLOBAL is required to be visible via other project's FetchContent of h5fortran
87+
# this GLOBAL is required to be visible via other project's FetchContent
8888
add_library(HDF5::HDF5 INTERFACE IMPORTED GLOBAL)
8989
target_include_directories(HDF5::HDF5 INTERFACE "${HDF5_INCLUDE_DIRS}")
9090
target_link_libraries(HDF5::HDF5 INTERFACE "${HDF5_LIBRARIES}")

src/CMakeLists.txt

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,11 @@ hdf5_compression_flag()
44
configure_file(hdf5_config.f90.in hdf5_config.f90 @ONLY)
55

66
# main library
7-
add_library(h5mpi
7+
target_sources(h5mpi PRIVATE
88
utils.f90
99
${CMAKE_CURRENT_BINARY_DIR}/hdf5_config.f90
10-
read.f90 read_scalar.f90 reader.f90
10+
read.f90 read_scalar.f90 read_scalar_ascii.f90 reader.f90
1111
write.f90 write_scalar.f90 writer.f90
1212
interface.f90
1313
attr.f90 attr_read.f90 attr_write.f90
1414
)
15-
target_link_libraries(h5mpi PRIVATE HDF5::HDF5 MPI::MPI_Fortran)
16-
set_target_properties(h5mpi PROPERTIES Fortran_MODULE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/include)
17-
target_include_directories(h5mpi PUBLIC
18-
$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/include>
19-
$<INSTALL_INTERFACE:include>
20-
)
21-
22-
install(TARGETS h5mpi EXPORT ${PROJECT_NAME}-targets)
23-
24-
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/include/h5mpi.mod TYPE INCLUDE)

src/read_scalar.f90

Lines changed: 37 additions & 110 deletions
Original file line numberDiff line numberDiff line change
@@ -1,53 +1,39 @@
11
submodule (h5mpi:hdf5_read) read_scalar
22

3-
use h5lt, only : h5ltread_dataset_string_f
4-
use hdf5, only : h5dread_f, h5dget_space_f, h5dvlen_get_max_len_f, h5dread_vl_f, h5dvlen_reclaim_f,&
5-
h5tis_variable_str_f, &
6-
h5sclose_f, &
7-
H5T_STR_NULLTERM_F
3+
use hdf5, only : H5Dread_f, &
4+
H5Sclose_f
85

96
implicit none (type, external)
107

8+
interface
9+
10+
module subroutine read_scalar_char(A, dset_id, file_space_id, mem_space_id, dims)
11+
class(*), intent(inout) :: A
12+
integer(HID_T), intent(in) :: dset_id, file_space_id
13+
integer(HID_T), intent(inout) :: mem_space_id
14+
integer(HSIZE_T), intent(in) :: dims(:)
15+
end subroutine
16+
17+
end interface
18+
1119
contains
1220

1321

1422
module procedure h5read_scalar
1523

1624
integer(HSIZE_T) :: dims(0)
17-
integer(SIZE_T) :: dsize
18-
integer(HID_T) :: dset_id, type_id, xfer_id, space_id
19-
integer :: dclass, ier, i, pad_type
25+
integer(HID_T) :: dset_id, xfer_id, file_space_id, mem_space_id
26+
integer :: dclass, ier
2027

21-
logical :: vector_scalar, vstatus
28+
logical :: is_scalar
2229

23-
real(real32) :: buf_r32(1)
24-
real(real64) :: buf_r64(1)
25-
integer(int32) :: buf_i32(1)
26-
integer(int64) :: buf_i64(1)
30+
file_space_id = H5S_ALL_F
31+
mem_space_id = H5S_ALL_F
2732

28-
call hdf_rank_check(self, dname, rank(A), vector_scalar)
29-
if(vector_scalar) then
30-
select type(A)
31-
type is (real(real32))
32-
call h5read_1d(self, dname, buf_r32)
33-
A = buf_r32(1)
34-
type is (real(real64))
35-
call h5read_1d(self, dname, buf_r64)
36-
A = buf_r64(1)
37-
type is (integer(int32))
38-
call h5read_1d(self, dname, buf_i32)
39-
A = buf_i32(1)
40-
type is (integer(int64))
41-
call h5read_1d(self, dname, buf_i64)
42-
A = buf_i64(1)
43-
class default
44-
error stop "h5fortran:read:vector_scalar: unknown memory variable type" // dname
45-
end select
46-
return
47-
endif
33+
call hdf_rank_check(self, dname, rank(A), is_scalar)
4834

49-
call h5dopen_f(self%file_id, dname, dset_id, ier)
50-
if(ier/=0) error stop 'h5fortran:reader: ' // dname // ' could not be opened in ' // self%filename
35+
call H5Dopen_f(self%file_id, dname, dset_id, ier)
36+
if(ier/=0) error stop 'ERROR:h5fortran:reader: ' // dname // ' could not be opened in ' // self%filename
5137

5238
call get_dset_class(self, dname, dclass, dset_id)
5339

@@ -62,99 +48,40 @@
6248
if(dclass == H5T_FLOAT_F) then
6349
select type(A)
6450
type is (real(real64))
65-
call h5dread_f(dset_id, H5T_NATIVE_DOUBLE, A, dims, ier)
51+
call H5Dread_f(dset_id, H5T_NATIVE_DOUBLE, A, dims, ier)
6652
type is (real(real32))
67-
call h5dread_f(dset_id, H5T_NATIVE_REAL, A, dims, ier)
53+
call H5Dread_f(dset_id, H5T_NATIVE_REAL, A, dims, ier)
6854
class default
69-
error stop 'h5fortran:read: real disk dataset ' // dname // ' needs real memory variable'
55+
error stop 'ERROR:h5fortran:read: real disk dataset ' // dname // ' needs real memory variable'
7056
end select
7157
elseif(dclass == H5T_INTEGER_F) then
7258
select type(A)
7359
type is (integer(int32))
74-
call h5dread_f(dset_id, H5T_NATIVE_INTEGER, A, dims, ier)
60+
call H5Dread_f(dset_id, H5T_NATIVE_INTEGER, A, dims, ier)
7561
type is (integer(int64))
76-
call h5dread_f(dset_id, H5T_STD_I64LE, A, dims, ier)
62+
call H5Dread_f(dset_id, H5T_STD_I64LE, A, dims, ier)
7763
class default
78-
error stop 'h5fortran:read: integer disk dataset ' // dname // ' needs integer memory variable'
64+
error stop 'ERROR:h5fortran:read: integer disk dataset ' // dname // ' needs integer memory variable'
7965
end select
8066
elseif(dclass == H5T_STRING_F) then
81-
select type(A)
82-
type is (character(*))
83-
call H5Dget_type_f(dset_id, type_id, ier)
84-
if(ier/=0) error stop "h5fortran:read:h5tget_type " // dname // " in " // self%filename
85-
call h5tis_variable_str_f(type_id, vstatus, ier)
86-
if(ier/=0) error stop "h5fortran:read:h5tis_variable_str " // dname // " in " // self%filename
87-
88-
if(vstatus) then
89-
call H5Dget_space_f(dset_id, space_id, ier)
90-
if(ier/=0) error stop "h5fortran:read:h5dget_space " // dname // " in " // self%filename
91-
!call h5dvlen_get_max_len_f(dset_id, type_id, space_id, dsize, ier)
92-
!if(ier/=0) error stop "h5fortran:read:h5dvlen_get_max_len " // dname // " in " // self%filename
93-
94-
block
95-
character(10000) :: buf_char(1)
96-
!! TODO: dynamically determine buffer size
97-
integer(HSIZE_T) :: vldims(2)
98-
integer(SIZE_T) :: vlen(1)
99-
100-
vldims = [len(buf_char), 1]
101-
102-
call h5dread_vl_f(dset_id, type_id, buf_char, vldims, vlen, hdferr=ier, mem_space_id=space_id)
103-
if(ier/=0) error stop "h5fortran:read:h5dread_vl " // dname // " in " // self%filename
104-
105-
i = index(buf_char(1), c_null_char) - 1
106-
if (i == -1) i = len_trim(buf_char(1))
107-
108-
A = buf_char(1)(:i)
109-
110-
! call h5dvlen_reclaim_f(type_id, H5S_ALL_F, H5P_DEFAULT_F, buf_char, ier)
111-
end block
112-
113-
call h5sclose_f(space_id, ier)
114-
if(ier/=0) error stop "h5fortran:read:h5sclose " // dname // " in " // self%filename
115-
else
116-
call H5Tget_strpad_f(type_id, pad_type, ier)
117-
if(ier/=0) error stop "h5fortran:read:h5tget_strpad " // dname // " in " // self%filename
118-
119-
call H5Tget_size_f(type_id, dsize, ier) !< only for non-variable
120-
if(ier/=0) error stop "h5fortran:read:h5tget_size " // dname // " in " // self%filename
121-
122-
if(dsize > len(A)) then
123-
write(stderr,'(a,i0,a3,i0,1x,a)') "h5fortran:read:string: buffer too small: ", dsize, " > ", len(A), &
124-
dname // " in " // self%filename
125-
error stop
126-
endif
127-
128-
block
129-
character(dsize) :: buf_char
130-
131-
call h5ltread_dataset_string_f(self%file_id, dname, buf_char, ier)
132-
if(ier/=0) error stop "h5fortran:read:h5l5read_dataset_string " // dname // " in " // self%filename
133-
134-
i = index(buf_char, c_null_char) - 1
135-
if (i == -1) i = len_trim(buf_char)
136-
137-
A = buf_char(:i)
138-
end block
139-
endif
140-
141-
call h5tclose_f(type_id, ier)
142-
if(ier/=0) error stop "h5fortran:read:h5tclose " // dname // " in " // self%filename
143-
144-
class default
145-
error stop "h5fortran:read: character disk dataset " // dname // " needs character memory variable"
146-
end select
67+
call read_scalar_char(A, dset_id, file_space_id, mem_space_id, dims)
14768
else
14869
error stop 'ERROR:h5fortran:reader: non-handled datatype--please reach out to developers.'
14970
end if
15071
if(ier/=0) error stop 'ERROR:h5fortran:reader: reading ' // dname // ' from ' // self%filename
15172

152-
call h5dclose_f(dset_id, ier)
153-
if(ier /= 0) error stop "ERROR:h5fortran:reader: closing dataset: " // dname // " in " // self%filename
73+
call H5Dclose_f(dset_id, ier)
74+
if(ier /= 0) error stop "ERROR:h5fortran:read_scalar: closing dataset: " // dname // " in " // self%filename
15475

155-
if(self%use_mpi) call h5pclose_f(xfer_id, ier)
76+
if(self%use_mpi) call H5Pclose_f(xfer_id, ier)
15677
if(ier /= 0) error stop "ERROR:h5fortran:writer closing property: " // dname // " in " // self%filename
15778

79+
if(mem_space_id /= H5S_ALL_F) call H5Sclose_f(mem_space_id, ier)
80+
if(ier /= 0) error stop "ERROR:h5fortran:read_scalar closing memory dataspace: " // dname // " in " // self%filename
81+
82+
if(file_space_id /= H5S_ALL_F) call H5Sclose_f(file_space_id, ier)
83+
if(ier /= 0) error stop "ERROR:h5fortran:read_scalar closing file dataspace: " // dname // " in " // self%filename
84+
15885
end procedure h5read_scalar
15986

16087
end submodule read_scalar

src/read_scalar_ascii.f90

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
submodule (h5mpi:read_scalar) read_scalar_ascii
2+
3+
use, intrinsic :: iso_c_binding, only : C_CHAR, C_F_POINTER
4+
use hdf5, only : H5T_STR_NULLTERM_F, &
5+
H5Dget_space_f, H5Dvlen_get_max_len_f, H5Dread_vl_f, H5Dvlen_reclaim_f, &
6+
H5Sget_simple_extent_dims_f, &
7+
H5Tis_variable_str_f
8+
9+
implicit none (type, external)
10+
11+
contains
12+
13+
module procedure read_scalar_char
14+
15+
integer(HID_T) :: type_id
16+
integer :: ier, i, pad_type, L
17+
integer(SIZE_T) :: dsize
18+
logical :: vstatus
19+
20+
!> variable length string
21+
integer(HSIZE_T) :: dset_dims(1), maxdims(2)
22+
TYPE(C_PTR), DIMENSION(:), ALLOCATABLE, TARGET :: cbuf
23+
TYPE(C_PTR) :: f_ptr
24+
25+
CHARACTER(10000, kind=c_char), POINTER :: cstr !< arbitrary maximum variable length string
26+
character(:), allocatable :: buf_char !< fixed length read
27+
character(1000) :: dset_name !< no specific maximum length for dataset name
28+
29+
dset_name = id2name(dset_id)
30+
dset_dims = [1]
31+
32+
select type(A)
33+
type is (character(*)) !< kind=c_char too
34+
L = len(A)
35+
class default
36+
error stop 'ERROR:h5fortran:read: character disk dataset ' // trim(dset_name) // ' needs character memory variable'
37+
end select
38+
39+
call H5Dget_type_f(dset_id, type_id, ier)
40+
if(ier/=0) error stop "ERROR:h5fortran:read:H5Tget_type " // trim(dset_name)
41+
call H5Tis_variable_str_f(type_id, vstatus, ier)
42+
if(ier/=0) error stop "ERROR:h5fortran:read:H5Tis_variable_str " // trim(dset_name)
43+
44+
if(vstatus) then
45+
if(mem_space_id == H5S_ALL_F) call H5Dget_space_f(dset_id, mem_space_id, ier)
46+
if(ier/=0) error stop "ERROR:h5fortran:read:vlen_char:H5Dget_space " // trim(dset_name)
47+
!call H5Dvlen_get_max_len_f(dset_id, type_id, space_id, dsize, ier)
48+
!if(ier/=0) error stop "h5fortran:read:H5Dvlen_get_max_len " // trim(dset_name)
49+
50+
call H5Sget_simple_extent_dims_f(mem_space_id, dset_dims, maxdims, ier)
51+
if(ier/=0) error stop "h5fortran:read:vlen_char:H5Sget_simple_extent_dim " // trim(dset_name)
52+
53+
allocate(cbuf(1:dset_dims(1)))
54+
f_ptr = C_LOC(cbuf(1))
55+
56+
call H5Dread_f(dset_id, type_id, f_ptr, ier)
57+
if(ier/=0) error stop "h5fortran:read:vlen_char:H5Dread " // trim(dset_name)
58+
59+
call C_F_POINTER(cbuf(1), cstr)
60+
61+
i = index(cstr, c_null_char) - 1
62+
if (i == -1) i = len_trim(cstr)
63+
if(i > L) then
64+
write(stderr,'(a,i0,a3,i0,1x,a)') "ERROR:h5fortran:read:vlen_char: buffer too small: ", i, " > ", L, trim(dset_name)
65+
error stop
66+
endif
67+
68+
select type(A)
69+
type is (character(*)) !< kind=c_char too
70+
A = cstr(:i)
71+
end select
72+
else
73+
call H5Tget_strpad_f(type_id, pad_type, ier)
74+
if(ier/=0) error stop "ERROR:h5fortran:read:H5Tget_strpad " // trim(dset_name)
75+
76+
call H5Tget_size_f(type_id, dsize, ier) !< only for non-variable
77+
if(ier/=0) error stop "ERROR:h5fortran:read:H5Tget_size " // trim(dset_name)
78+
79+
if(dsize > L) then
80+
write(stderr,'(a,i0,a3,i0,1x,a)') "ERROR:h5fortran:read:string: buffer too small: ", dsize, " > ", L, trim(dset_name)
81+
error stop
82+
endif
83+
84+
allocate(character(dsize) :: buf_char)
85+
86+
call H5Dread_f(dset_id, type_id, buf_char, dims, ier, mem_space_id, file_space_id)
87+
if(ier/=0) error stop "ERROR:h5fortran:read:H5Dread character " // trim(dset_name)
88+
89+
i = index(buf_char, c_null_char) - 1
90+
if (i == -1) i = len_trim(buf_char)
91+
92+
select type(A)
93+
type is (character(*)) !< kind=c_char too
94+
A = buf_char(:i)
95+
end select
96+
endif
97+
98+
call H5Tclose_f(type_id, ier)
99+
if(ier/=0) error stop "ERROR:h5fortran:read:H5Tclose " // trim(dset_name)
100+
101+
end procedure read_scalar_char
102+
103+
end submodule read_scalar_ascii

src/write.f90

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
H5P_DATASET_CREATE_F, &
99
h5gopen_f, h5gcreate_f, h5gclose_f, &
1010
H5Lcreate_soft_f, h5lexists_f, &
11-
h5tcopy_f, h5tset_size_f, &
11+
h5tcopy_f, h5tclose_f, h5tset_size_f, &
1212
H5S_SCALAR_F, &
1313
H5D_COMPACT_F, &
1414
H5F_SCOPE_GLOBAL_F

0 commit comments

Comments
 (0)