GCC Code Coverage Report


Directory: src/
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 0.0% 0 / 0 / 235
Functions: 0.0% 0 / 0 / 17
Branches: 0.0% 0 / 0 / 313

other/s_tables.f90
Line Branch Exec Source
1 submodule(m_tables) s_tables
2 implicit none
3 contains
4
5 module subroutine print_table(array1, array2, array3, array4, array5, &
6 & title1, title2, title3, title4, title5, &
7 & fmt1, fmt2, fmt3, fmt4, fmt5, fname, separator, &
8 & index_column, index_title, skip_horizontal_line)
9 use, intrinsic :: iso_fortran_env, only: stdout => output_unit
10
11 implicit none
12 class(*), dimension(:), intent(in) :: array1
13 class(*), dimension(:), intent(in), optional :: array2, array3, array4, array5
14 character(len=*), intent(in), optional :: title1, title2, title3, title4, title5
15 character(len=*), intent(in), optional :: fmt1, fmt2, fmt3, fmt4, fmt5
16 character(len=*), intent(in), optional :: fname
17 character(len=*), intent(in), optional :: separator
18 logical, intent(in), optional :: index_column
19 character(len=*), intent(in), optional :: index_title
20 logical, intent(in), optional :: skip_horizontal_line
21
22 integer :: out_unit, ierr, i, n_rows, n_cols, total_cols, idx_offset
23 integer :: col_widths(6)
24 character(len=3) :: sep
25 character(len=20) :: col_format(6)
26 character(len=50) :: col_title(6)
27 logical :: has_titles, use_index
28 character(len=20) :: idx_title
29 logical :: skip_horizontal_line_
30
31 ! --- Error checking for array lengths and presence order ---
32 n_rows = size(array1)
33 if (present(array2)) then
34 if (size(array2) /= n_rows) then
35 write (*, *) 'print_array error: array2 length does not match array1.'
36 return
37 end if
38 end if
39 if (present(array3)) then
40 if (.not. present(array2)) then
41 write (*, *) 'print_array error: array3 is present but array2 is not.'
42 return
43 end if
44 if (size(array3) /= n_rows) then
45 write (*, *) 'print_array error: array3 length does not match array1.'
46 return
47 end if
48 end if
49 if (present(array4)) then
50 if (.not. present(array3)) then
51 write (*, *) 'print_array error: array4 is present but array3 is not.'
52 return
53 end if
54 if (size(array4) /= n_rows) then
55 write (*, *) 'print_array error: array4 length does not match array1.'
56 return
57 end if
58 end if
59 if (present(array5)) then
60 if (.not. present(array4)) then
61 write (*, *) 'print_array error: array5 is present but array4 is not.'
62 return
63 end if
64 if (size(array5) /= n_rows) then
65 write (*, *) 'print_array error: array5 length does not match array1.'
66 return
67 end if
68 end if
69
70 ! Determine separator (default is multiple spaces for better readability)
71 if (present(separator)) then
72 sep = separator
73 else
74 sep = ' '
75 end if
76
77 ! Determine if we're using an index column
78 use_index = .false.
79 if (present(index_column)) use_index = index_column
80
81 ! Set up index offset: 0 if no index column, 1 if index column
82 idx_offset = 0
83 if (use_index) idx_offset = 1
84
85 ! Set up index column title
86 if (use_index) then
87 if (present(index_title)) then
88 idx_title = index_title
89 else
90 idx_title = 'Index'
91 end if
92 end if
93
94 ! Open output file or use stdout
95 if (present(fname)) then
96 open (newunit=out_unit, file=fname, status='replace', action='write', iostat=ierr)
97 if (ierr /= 0) then
98 write (*, *) 'Error opening file: ', fname
99 return
100 end if
101 else
102 out_unit = stdout
103 end if
104
105 if (present(skip_horizontal_line)) then
106 skip_horizontal_line_ = skip_horizontal_line
107 else
108 skip_horizontal_line_ = .false.
109 end if
110
111 ! Determine number of rows (all arrays must have same size)
112 n_rows = size(array1)
113
114 ! Determine number of columns
115 n_cols = 1
116 if (present(array2)) n_cols = 2
117 if (present(array3)) n_cols = 3
118 if (present(array4)) n_cols = 4
119 if (present(array5)) n_cols = 5
120
121 ! Calculate total columns including index column if present
122 total_cols = n_cols + idx_offset
123
124 ! Calculate column widths
125 if (use_index) then
126 ! Calculate width for index column (considering the number of rows)
127 write (idx_title, '(I0)') n_rows
128 col_widths(1) = max(len_trim(idx_title), len_trim(adjustl(idx_title)))
129 if (present(index_title)) then
130 col_widths(1) = max(col_widths(1), len_trim(index_title))
131 else
132 col_widths(1) = max(col_widths(1), len_trim('Index'))
133 end if
134 col_format(1) = '(I0)'
135 end if
136
137 ! Calculate widths for data columns (with offset)
138 col_widths(1 + idx_offset) = calculate_column_width(array1, title1, fmt1)
139 if (n_cols >= 2) col_widths(2 + idx_offset) = calculate_column_width(array2, title2, fmt2)
140 if (n_cols >= 3) col_widths(3 + idx_offset) = calculate_column_width(array3, title3, fmt3)
141 if (n_cols >= 4) col_widths(4 + idx_offset) = calculate_column_width(array4, title4, fmt4)
142 if (n_cols >= 5) col_widths(5 + idx_offset) = calculate_column_width(array5, title5, fmt5)
143
144 ! Set up column formats (with offset for data columns)
145 col_format(1 + idx_offset) = get_format(fmt1)
146 if (n_cols >= 2) col_format(2 + idx_offset) = get_format(fmt2)
147 if (n_cols >= 3) col_format(3 + idx_offset) = get_format(fmt3)
148 if (n_cols >= 4) col_format(4 + idx_offset) = get_format(fmt4)
149 if (n_cols >= 5) col_format(5 + idx_offset) = get_format(fmt5)
150
151 ! Set up column titles
152 has_titles = .false.
153
154 if (use_index) then
155 if (present(index_title)) then
156 col_title(1) = index_title
157 else
158 col_title(1) = 'Index'
159 end if
160 has_titles = .true.
161 end if
162
163 if (present(title1)) then
164 col_title(1 + idx_offset) = title1
165 has_titles = .true.
166 else
167 col_title(1 + idx_offset) = ''
168 end if
169
170 if (present(title2) .and. n_cols >= 2) then
171 col_title(2 + idx_offset) = title2
172 has_titles = .true.
173 else
174 col_title(2 + idx_offset) = ''
175 end if
176
177 if (present(title3) .and. n_cols >= 3) then
178 col_title(3 + idx_offset) = title3
179 has_titles = .true.
180 else
181 col_title(3 + idx_offset) = ''
182 end if
183
184 if (present(title4) .and. n_cols >= 4) then
185 col_title(4 + idx_offset) = title4
186 has_titles = .true.
187 else
188 col_title(4 + idx_offset) = ''
189 end if
190
191 if (present(title5) .and. n_cols >= 5) then
192 col_title(5 + idx_offset) = title5
193 has_titles = .true.
194 else
195 col_title(5 + idx_offset) = ''
196 end if
197
198 ! Print titles if any are provided
199 if (has_titles) then
200 call print_row(out_unit, col_title, total_cols, sep, col_widths, .true.)
201 if (.not. skip_horizontal_line_) then
202 call print_separator_line(out_unit, total_cols, sep, col_widths)
203 end if
204 end if
205
206 ! Print data rows
207 do i = 1, n_rows
208 select case (n_cols)
209 case (1)
210 call print_data_row_1(out_unit, i, array1(i), col_format, sep, col_widths, use_index)
211 case (2)
212 call print_data_row_2(out_unit, i, array1(i), array2(i), col_format, sep, col_widths, use_index)
213 case (3)
214 call print_data_row_3(out_unit, i, array1(i), array2(i), array3(i), col_format, sep, col_widths, use_index)
215 case (4)
216 call print_data_row_4(out_unit, i, array1(i), array2(i), array3(i), array4(i), col_format, sep, col_widths, use_index)
217 case (5)
218 call print_data_row_5(out_unit, i, array1(i), array2(i), array3(i), array4(i), array5(i), col_format, sep, col_widths, &
219 & use_index)
220 end select
221 end do
222
223 ! Close file if it was opened
224 if (present(fname)) then
225 close (out_unit)
226 end if
227
228 end subroutine print_table
229
230 function any_to_char_string(value, fmt) result(str)
231 implicit none
232 class(*), intent(in) :: value
233 character(len=*), intent(in), optional :: fmt
234 character(len=32) :: str
235 logical :: use_default_fmt
236
237 use_default_fmt = .true.
238 if (present(fmt)) then
239 if (len_trim(fmt) > 0) use_default_fmt = .false.
240 end if
241
242 select type (value)
243 type is (integer)
244 if (use_default_fmt) then
245 write (str, '(I0)') value
246 else
247 write (str, fmt) value
248 end if
249 type is (real)
250 if (use_default_fmt) then
251 write (str, '(F8.2)') value
252 else
253 write (str, fmt) value
254 end if
255 type is (double precision)
256 if (use_default_fmt) then
257 write (str, '(F8.2)') value
258 else
259 write (str, fmt) value
260 end if
261 type is (logical)
262 if (use_default_fmt) then
263 if (value) then
264 str = 'T'
265 else
266 str = 'F'
267 end if
268 else
269 write (str, fmt) value
270 end if
271 type is (complex)
272 if (use_default_fmt) then
273 write (str, '(F8.2,SP,F8.2,"i")') value
274 else
275 write (str, fmt) value
276 end if
277 type is (character(len=*))
278 if (use_default_fmt) then
279 str = value
280 else
281 write (str, fmt) value
282 end if
283 class default
284 str = 'Unsupported Type'
285 end select
286
287 str = adjustl(str)
288 end function any_to_char_string
289
290 function get_format(fmt) result(format_str)
291 implicit none
292 character(len=*), intent(in), optional :: fmt
293 character(len=20) :: format_str
294
295 if (present(fmt)) then
296 format_str = fmt
297 else
298 format_str = ''
299 end if
300 end function get_format
301
302 function calculate_column_width(array, title, fmt) result(width)
303 implicit none
304 class(*), dimension(:), intent(in) :: array
305 character(len=*), intent(in), optional :: title
306 character(len=*), intent(in), optional :: fmt
307 integer :: width
308
309 integer :: i, n_rows
310 character(len=32) :: temp_str
311 character(len=20) :: col_format
312
313 width = 0
314 n_rows = size(array)
315 col_format = get_format(fmt)
316
317 if (present(title)) then
318 width = max(width, len_trim(title))
319 end if
320
321 do i = 1, n_rows
322 temp_str = any_to_char_string(array(i), col_format)
323 width = max(width, len_trim(temp_str))
324 end do
325
326 width = max(width, 1)
327 end function calculate_column_width
328
329 subroutine print_row(unit, titles, n_cols, sep, col_widths, is_title)
330 implicit none
331 integer, intent(in) :: unit, n_cols
332 character(len=*), intent(in) :: titles(:)
333 character(len=*), intent(in) :: sep
334 integer, intent(in) :: col_widths(:)
335 logical, intent(in) :: is_title
336 integer :: i
337 character(len=50) :: formatted_title
338
339 if (is_title) continue
340
341 do i = 1, n_cols
342 if (i > 1) write (unit, '(A)', advance='no') trim(sep)
343 write (formatted_title, '(A)') titles(i)
344 write (unit, '(A)', advance='no') ' '//adjustl(formatted_title(:col_widths(i)))//' '
345 end do
346 write (unit, *)
347 end subroutine print_row
348
349 subroutine print_separator_line(unit, n_cols, sep, col_widths)
350 implicit none
351 integer, intent(in) :: unit, n_cols
352 character(len=*), intent(in) :: sep
353 integer, intent(in) :: col_widths(:)
354 integer :: i, sep_len
355
356 sep_len = len_trim(sep)
357
358 do i = 1, n_cols
359 if (i > 1) then
360 write (unit, '(A)', advance='no') repeat('-', sep_len)
361 end if
362 write (unit, '(A)', advance='no') repeat('-', col_widths(i) + 2)
363 end do
364 write (unit, *)
365 end subroutine print_separator_line
366
367 subroutine print_data_row_1(unit, idx, val1, fmt_array, sep, col_widths, use_index)
368 implicit none
369 integer, intent(in) :: unit, idx
370 class(*), intent(in) :: val1
371 character(len=*), intent(in) :: fmt_array(:)
372 character(len=*), intent(in) :: sep
373 integer, intent(in) :: col_widths(:)
374 logical, intent(in) :: use_index
375 character(len=32) :: formatted_val
376 integer :: data_offset
377
378 data_offset = 0
379 if (use_index) data_offset = 1
380
381 if (use_index) then
382 write (formatted_val, '(I0)') idx
383 write (unit, '(A)', advance='no') ' '//adjustl(formatted_val(:col_widths(1)))//' '
384 write (unit, '(A)', advance='no') trim(sep)
385 end if
386
387 formatted_val = any_to_char_string(val1, fmt_array(1 + data_offset))
388 write (unit, '(A)') ' '//adjustl(formatted_val(:col_widths(1 + data_offset)))//' '
389 end subroutine print_data_row_1
390
391 subroutine print_data_row_2(unit, idx, val1, val2, fmt_array, sep, col_widths, use_index)
392 implicit none
393 integer, intent(in) :: unit, idx
394 class(*), intent(in) :: val1, val2
395 character(len=*), intent(in) :: fmt_array(:)
396 character(len=*), intent(in) :: sep
397 integer, intent(in) :: col_widths(:)
398 logical, intent(in) :: use_index
399 character(len=32) :: formatted_val
400 integer :: data_offset
401
402 data_offset = 0
403 if (use_index) data_offset = 1
404
405 if (use_index) then
406 write (formatted_val, '(I0)') idx
407 write (unit, '(A)', advance='no') ' '//adjustl(formatted_val(:col_widths(1)))//' '
408 write (unit, '(A)', advance='no') trim(sep)
409 end if
410
411 formatted_val = any_to_char_string(val1, fmt_array(1 + data_offset))
412 write (unit, '(A)', advance='no') ' '//adjustl(formatted_val(:col_widths(1 + data_offset)))//' '
413 write (unit, '(A)', advance='no') trim(sep)
414 formatted_val = any_to_char_string(val2, fmt_array(2 + data_offset))
415 write (unit, '(A)') ' '//adjustl(formatted_val(:col_widths(2 + data_offset)))//' '
416 end subroutine print_data_row_2
417
418 subroutine print_data_row_3(unit, idx, val1, val2, val3, fmt_array, sep, col_widths, use_index)
419 implicit none
420 integer, intent(in) :: unit, idx
421 class(*), intent(in) :: val1, val2, val3
422 character(len=*), intent(in) :: fmt_array(:)
423 character(len=*), intent(in) :: sep
424 integer, intent(in) :: col_widths(:)
425 logical, intent(in) :: use_index
426 character(len=32) :: formatted_val
427 integer :: data_offset
428
429 data_offset = 0
430 if (use_index) data_offset = 1
431
432 if (use_index) then
433 write (formatted_val, '(I0)') idx
434 write (unit, '(A)', advance='no') ' '//adjustl(formatted_val(:col_widths(1)))//' '
435 write (unit, '(A)', advance='no') trim(sep)
436 end if
437
438 formatted_val = any_to_char_string(val1, fmt_array(1 + data_offset))
439 write (unit, '(A)', advance='no') ' '//adjustl(formatted_val(:col_widths(1 + data_offset)))//' '
440 write (unit, '(A)', advance='no') trim(sep)
441 formatted_val = any_to_char_string(val2, fmt_array(2 + data_offset))
442 write (unit, '(A)', advance='no') ' '//adjustl(formatted_val(:col_widths(2 + data_offset)))//' '
443 write (unit, '(A)', advance='no') trim(sep)
444 formatted_val = any_to_char_string(val3, fmt_array(3 + data_offset))
445 write (unit, '(A)') ' '//adjustl(formatted_val(:col_widths(3 + data_offset)))//' '
446 end subroutine print_data_row_3
447
448 subroutine print_data_row_4(unit, idx, val1, val2, val3, val4, fmt_array, sep, col_widths, use_index)
449 implicit none
450 integer, intent(in) :: unit, idx
451 class(*), intent(in) :: val1, val2, val3, val4
452 character(len=*), intent(in) :: fmt_array(:)
453 character(len=*), intent(in) :: sep
454 integer, intent(in) :: col_widths(:)
455 logical, intent(in) :: use_index
456 character(len=32) :: formatted_val
457 integer :: data_offset
458
459 data_offset = 0
460 if (use_index) data_offset = 1
461
462 if (use_index) then
463 write (formatted_val, '(I0)') idx
464 write (unit, '(A)', advance='no') ' '//adjustl(formatted_val(:col_widths(1)))//' '
465 write (unit, '(A)', advance='no') trim(sep)
466 end if
467
468 formatted_val = any_to_char_string(val1, fmt_array(1 + data_offset))
469 write (unit, '(A)', advance='no') ' '//adjustl(formatted_val(:col_widths(1 + data_offset)))//' '
470 write (unit, '(A)', advance='no') trim(sep)
471 formatted_val = any_to_char_string(val2, fmt_array(2 + data_offset))
472 write (unit, '(A)', advance='no') ' '//adjustl(formatted_val(:col_widths(2 + data_offset)))//' '
473 write (unit, '(A)', advance='no') trim(sep)
474 formatted_val = any_to_char_string(val3, fmt_array(3 + data_offset))
475 write (unit, '(A)', advance='no') ' '//adjustl(formatted_val(:col_widths(3 + data_offset)))//' '
476 write (unit, '(A)', advance='no') trim(sep)
477 formatted_val = any_to_char_string(val4, fmt_array(4 + data_offset))
478 write (unit, '(A)') ' '//adjustl(formatted_val(:col_widths(4 + data_offset)))//' '
479 end subroutine print_data_row_4
480
481 subroutine print_data_row_5(unit, idx, val1, val2, val3, val4, val5, fmt_array, sep, col_widths, use_index)
482 implicit none
483 integer, intent(in) :: unit, idx
484 class(*), intent(in) :: val1, val2, val3, val4, val5
485 character(len=*), intent(in) :: fmt_array(:)
486 character(len=*), intent(in) :: sep
487 integer, intent(in) :: col_widths(:)
488 logical, intent(in) :: use_index
489 character(len=32) :: formatted_val
490 integer :: data_offset
491
492 data_offset = 0
493 if (use_index) data_offset = 1
494
495 if (use_index) then
496 write (formatted_val, '(I0)') idx
497 write (unit, '(A)', advance='no') ' '//adjustl(formatted_val(:col_widths(1)))//' '
498 write (unit, '(A)', advance='no') trim(sep)
499 end if
500
501 formatted_val = any_to_char_string(val1, fmt_array(1 + data_offset))
502 write (unit, '(A)', advance='no') ' '//adjustl(formatted_val(:col_widths(1 + data_offset)))//' '
503 write (unit, '(A)', advance='no') trim(sep)
504 formatted_val = any_to_char_string(val2, fmt_array(2 + data_offset))
505 write (unit, '(A)', advance='no') ' '//adjustl(formatted_val(:col_widths(2 + data_offset)))//' '
506 write (unit, '(A)', advance='no') trim(sep)
507 formatted_val = any_to_char_string(val3, fmt_array(3 + data_offset))
508 write (unit, '(A)', advance='no') ' '//adjustl(formatted_val(:col_widths(3 + data_offset)))//' '
509 write (unit, '(A)', advance='no') trim(sep)
510 formatted_val = any_to_char_string(val4, fmt_array(4 + data_offset))
511 write (unit, '(A)', advance='no') ' '//adjustl(formatted_val(:col_widths(4 + data_offset)))//' '
512 write (unit, '(A)', advance='no') trim(sep)
513 formatted_val = any_to_char_string(val5, fmt_array(5 + data_offset))
514 write (unit, '(A)') ' '//adjustl(formatted_val(:col_widths(5 + data_offset)))//' '
515 end subroutine print_data_row_5
516
517 end submodule s_tables
518