LCOV - code coverage report
Current view: top level - src/api - hsd_mutators.f90 (source / functions) Coverage Total Hit
Test: coverage.info Lines: 100.0 % 162 162
Test Date: 2026-02-04 13:26:36 Functions: 100.0 % 12 12

            Line data    Source code
       1              : !> HSD data mutators (setters)
       2              : !>
       3              : !> This module provides interfaces and implementations for modifying HSD tables.
       4              : !> It supports type-safe setting of scalars and arrays, with automatic path
       5              : !> creation for nested structures.
       6              : module hsd_mutators
       7              :   use hsd_constants, only: dp, sp
       8              :   use hsd_utils, only: to_lower
       9              :   use hsd_error, only: HSD_STAT_OK, HSD_STAT_NOT_FOUND
      10              :   use hsd_types, only: hsd_node, hsd_table, hsd_value, new_table, new_value
      11              :   implicit none (type, external)
      12              :   private
      13              : 
      14              :   ! Public interface
      15              :   public :: hsd_set
      16              : 
      17              :   !> Generic interface for setting values by path
      18              :   interface hsd_set
      19              :     module procedure :: hsd_set_string
      20              :     module procedure :: hsd_set_integer
      21              :     module procedure :: hsd_set_real_dp
      22              :     module procedure :: hsd_set_real_sp
      23              :     module procedure :: hsd_set_logical
      24              :     module procedure :: hsd_set_complex_dp
      25              :     module procedure :: hsd_set_integer_array
      26              :     module procedure :: hsd_set_real_dp_array
      27              :     module procedure :: hsd_set_real_sp_array
      28              :     module procedure :: hsd_set_logical_array
      29              :     module procedure :: hsd_set_complex_dp_array
      30              :   end interface hsd_set
      31              : 
      32              : contains
      33              : 
      34              :   !> Set string value by path
      35            5 :   subroutine hsd_set_string(table, path, val, stat)
      36              :     type(hsd_table), intent(inout) :: table
      37              :     character(len=*), intent(in) :: path
      38              :     character(len=*), intent(in) :: val
      39              :     integer, intent(out), optional :: stat
      40              : 
      41              :     class(hsd_node), pointer :: child
      42            5 :     integer :: local_stat
      43              : 
      44            5 :     call get_or_create_child(table, path, child, local_stat)
      45              : 
      46            5 :     if (local_stat /= 0) then
      47            1 :       if (present(stat)) stat = local_stat
      48            1 :       return
      49              :     end if
      50              : 
      51              :     select type (child)
      52              :     type is (hsd_value)
      53            4 :       call child%set_string(val)
      54              :     end select
      55              : 
      56            4 :     if (present(stat)) stat = HSD_STAT_OK
      57              : 
      58            5 :   end subroutine hsd_set_string
      59              : 
      60              :   !> Set integer value by path
      61         1014 :   subroutine hsd_set_integer(table, path, val, stat)
      62              :     type(hsd_table), intent(inout) :: table
      63              :     character(len=*), intent(in) :: path
      64              :     integer, intent(in) :: val
      65              :     integer, intent(out), optional :: stat
      66              : 
      67              :     class(hsd_node), pointer :: child
      68         1014 :     integer :: local_stat
      69              : 
      70         1014 :     call get_or_create_child(table, path, child, local_stat)
      71              : 
      72         1014 :     if (local_stat /= 0) then
      73            4 :       if (present(stat)) stat = local_stat
      74            4 :       return
      75              :     end if
      76              : 
      77              :     select type (child)
      78              :     type is (hsd_value)
      79         1010 :       call child%set_integer(val)
      80              :     end select
      81              : 
      82         1010 :     if (present(stat)) stat = HSD_STAT_OK
      83              : 
      84         1019 :   end subroutine hsd_set_integer
      85              : 
      86              :   !> Set double precision real value by path
      87           11 :   subroutine hsd_set_real_dp(table, path, val, stat)
      88              :     type(hsd_table), intent(inout) :: table
      89              :     character(len=*), intent(in) :: path
      90              :     real(dp), intent(in) :: val
      91              :     integer, intent(out), optional :: stat
      92              : 
      93              :     class(hsd_node), pointer :: child
      94           11 :     integer :: local_stat
      95              : 
      96           11 :     call get_or_create_child(table, path, child, local_stat)
      97              : 
      98           11 :     if (local_stat /= 0) then
      99            2 :       if (present(stat)) stat = local_stat
     100            2 :       return
     101              :     end if
     102              : 
     103              :     select type (child)
     104              :     type is (hsd_value)
     105            9 :       call child%set_real(val)
     106              :     end select
     107              : 
     108            9 :     if (present(stat)) stat = HSD_STAT_OK
     109              : 
     110         1025 :   end subroutine hsd_set_real_dp
     111              : 
     112              :   !> Set single precision real value by path
     113            5 :   subroutine hsd_set_real_sp(table, path, val, stat)
     114              :     type(hsd_table), intent(inout) :: table
     115              :     character(len=*), intent(in) :: path
     116              :     real(sp), intent(in) :: val
     117              :     integer, intent(out), optional :: stat
     118              : 
     119            5 :     call hsd_set_real_dp(table, path, real(val, dp), stat)
     120              : 
     121           11 :   end subroutine hsd_set_real_sp
     122              : 
     123              :   !> Set logical value by path
     124            5 :   subroutine hsd_set_logical(table, path, val, stat)
     125              :     type(hsd_table), intent(inout) :: table
     126              :     character(len=*), intent(in) :: path
     127              :     logical, intent(in) :: val
     128              :     integer, intent(out), optional :: stat
     129              : 
     130              :     class(hsd_node), pointer :: child
     131            5 :     integer :: local_stat
     132              : 
     133            5 :     call get_or_create_child(table, path, child, local_stat)
     134              : 
     135            5 :     if (local_stat /= 0) then
     136            1 :       if (present(stat)) stat = local_stat
     137            1 :       return
     138              :     end if
     139              : 
     140              :     select type (child)
     141              :     type is (hsd_value)
     142            4 :       call child%set_logical(val)
     143              :     end select
     144              : 
     145            4 :     if (present(stat)) stat = HSD_STAT_OK
     146              : 
     147           10 :   end subroutine hsd_set_logical
     148              : 
     149              :   !> Set complex value by path
     150            3 :   subroutine hsd_set_complex_dp(table, path, val, stat)
     151              :     type(hsd_table), intent(inout) :: table
     152              :     character(len=*), intent(in) :: path
     153              :     complex(dp), intent(in) :: val
     154              :     integer, intent(out), optional :: stat
     155              : 
     156              :     class(hsd_node), pointer :: child
     157            3 :     integer :: local_stat
     158              : 
     159            3 :     call get_or_create_child(table, path, child, local_stat)
     160              : 
     161            3 :     if (local_stat /= 0) then
     162            1 :       if (present(stat)) stat = local_stat
     163            1 :       return
     164              :     end if
     165              : 
     166              :     select type (child)
     167              :     type is (hsd_value)
     168            2 :       call child%set_complex(val)
     169              :     end select
     170              : 
     171            2 :     if (present(stat)) stat = HSD_STAT_OK
     172              : 
     173            8 :   end subroutine hsd_set_complex_dp
     174              : 
     175              :   !> Set integer array by path
     176            6 :   subroutine hsd_set_integer_array(table, path, val, stat)
     177              :     type(hsd_table), intent(inout) :: table
     178              :     character(len=*), intent(in) :: path
     179              :     integer, intent(in) :: val(:)
     180              :     integer, intent(out), optional :: stat
     181              : 
     182              :     class(hsd_node), pointer :: child
     183            3 :     integer :: local_stat, i
     184            3 :     character(len=:), allocatable :: text
     185              :     character(len=32) :: buffer
     186              : 
     187            3 :     call get_or_create_child(table, path, child, local_stat)
     188              : 
     189            3 :     if (local_stat /= 0) then
     190            1 :       if (present(stat)) stat = local_stat
     191            1 :       return
     192              :     end if
     193              : 
     194              :     select type (child)
     195              :     type is (hsd_value)
     196              :       ! Convert array to space-separated string
     197            2 :       text = ""
     198           12 :       do i = 1, size(val)
     199           10 :         write(buffer, '(I0)') val(i)
     200           18 :         if (i > 1) text = text // " "
     201           12 :         text = text // trim(adjustl(buffer))
     202              :       end do
     203            4 :       call child%set_raw(text)
     204              :     end select
     205              : 
     206            2 :     if (present(stat)) stat = HSD_STAT_OK
     207              : 
     208            9 :   end subroutine hsd_set_integer_array
     209              : 
     210              :   !> Set double precision real array by path
     211           14 :   subroutine hsd_set_real_dp_array(table, path, val, stat)
     212              :     type(hsd_table), intent(inout) :: table
     213              :     character(len=*), intent(in) :: path
     214              :     real(dp), intent(in) :: val(:)
     215              :     integer, intent(out), optional :: stat
     216              : 
     217              :     class(hsd_node), pointer :: child
     218            7 :     integer :: local_stat, i
     219            7 :     character(len=:), allocatable :: text
     220              :     character(len=32) :: buffer
     221              : 
     222            7 :     call get_or_create_child(table, path, child, local_stat)
     223              : 
     224            7 :     if (local_stat /= 0) then
     225            2 :       if (present(stat)) stat = local_stat
     226            2 :       return
     227              :     end if
     228              : 
     229              :     select type (child)
     230              :     type is (hsd_value)
     231              :       ! Convert array to space-separated string
     232            5 :       text = ""
     233           19 :       do i = 1, size(val)
     234           14 :         write(buffer, '(G0)') val(i)
     235           23 :         if (i > 1) text = text // " "
     236           19 :         text = text // trim(adjustl(buffer))
     237              :       end do
     238           10 :       call child%set_raw(text)
     239              :     end select
     240              : 
     241            5 :     if (present(stat)) stat = HSD_STAT_OK
     242              : 
     243           17 :   end subroutine hsd_set_real_dp_array
     244              : 
     245              :   !> Set single precision real array by path
     246            8 :   subroutine hsd_set_real_sp_array(table, path, val, stat)
     247              :     type(hsd_table), intent(inout) :: table
     248              :     character(len=*), intent(in) :: path
     249              :     real(sp), intent(in) :: val(:)
     250              :     integer, intent(out), optional :: stat
     251              : 
     252            4 :     real(dp), allocatable :: val_dp(:)
     253              : 
     254            4 :     allocate(val_dp(size(val)))
     255           14 :     val_dp = real(val, dp)
     256            4 :     call hsd_set_real_dp_array(table, path, val_dp, stat)
     257              : 
     258           11 :   end subroutine hsd_set_real_sp_array
     259              : 
     260              :   !> Set logical array by path
     261            6 :   subroutine hsd_set_logical_array(table, path, val, stat)
     262              :     type(hsd_table), intent(inout) :: table
     263              :     character(len=*), intent(in) :: path
     264              :     logical, intent(in) :: val(:)
     265              :     integer, intent(out), optional :: stat
     266              : 
     267              :     class(hsd_node), pointer :: child
     268            3 :     integer :: local_stat, i
     269            3 :     character(len=:), allocatable :: text
     270              : 
     271            3 :     call get_or_create_child(table, path, child, local_stat)
     272              : 
     273            3 :     if (local_stat /= 0) then
     274            1 :       if (present(stat)) stat = local_stat
     275            1 :       return
     276              :     end if
     277              : 
     278              :     select type (child)
     279              :     type is (hsd_value)
     280              :       ! Convert array to space-separated string
     281            2 :       text = ""
     282            8 :       do i = 1, size(val)
     283           10 :         if (i > 1) text = text // " "
     284            8 :         if (val(i)) then
     285            4 :           text = text // "Yes"
     286              :         else
     287            2 :           text = text // "No"
     288              :         end if
     289              :       end do
     290            4 :       call child%set_raw(text)
     291              :     end select
     292              : 
     293            2 :     if (present(stat)) stat = HSD_STAT_OK
     294              : 
     295           10 :   end subroutine hsd_set_logical_array
     296              : 
     297              :   !> Set complex array by path
     298            6 :   subroutine hsd_set_complex_dp_array(table, path, val, stat)
     299              :     type(hsd_table), intent(inout) :: table
     300              :     character(len=*), intent(in) :: path
     301              :     complex(dp), intent(in) :: val(:)
     302              :     integer, intent(out), optional :: stat
     303              : 
     304              :     class(hsd_node), pointer :: child
     305            3 :     integer :: local_stat, i
     306            3 :     character(len=:), allocatable :: text
     307              :     character(len=64) :: buffer
     308              : 
     309            3 :     call get_or_create_child(table, path, child, local_stat)
     310              : 
     311            3 :     if (local_stat /= 0) then
     312            1 :       if (present(stat)) stat = local_stat
     313            1 :       return
     314              :     end if
     315              : 
     316              :     select type (child)
     317              :     type is (hsd_value)
     318              :       ! Convert array to space-separated string in a+bi format
     319            2 :       text = ""
     320            8 :       do i = 1, size(val)
     321           10 :         if (i > 1) text = text // " "
     322            6 :         if (aimag(val(i)) >= 0.0_dp) then
     323            5 :           write(buffer, '(G0,"+",G0,"i")') real(val(i)), aimag(val(i))
     324              :         else
     325            1 :           write(buffer, '(G0,G0,"i")') real(val(i)), aimag(val(i))
     326              :         end if
     327            8 :         text = text // trim(adjustl(buffer))
     328              :       end do
     329            4 :       call child%set_raw(text)
     330              :     end select
     331              : 
     332            2 :     if (present(stat)) stat = HSD_STAT_OK
     333              : 
     334            9 :   end subroutine hsd_set_complex_dp_array
     335              : 
     336              :   !> Get or create a child node by path, creating intermediate tables as needed
     337         1054 :   subroutine get_or_create_child(table, path, child, stat)
     338              :     type(hsd_table), intent(inout), target :: table
     339              :     character(len=*), intent(in) :: path
     340              :     class(hsd_node), pointer, intent(out) :: child
     341              :     integer, intent(out), optional :: stat
     342              : 
     343         1054 :     character(len=:), allocatable :: remaining, segment
     344              :     class(hsd_node), pointer :: current
     345              :     type(hsd_table), pointer :: current_table
     346         1054 :     type(hsd_table) :: new_tbl
     347         1054 :     type(hsd_value) :: new_val
     348         1054 :     integer :: sep_pos, i
     349              : 
     350         1054 :     child => null()
     351         1054 :     remaining = path
     352         1054 :     current_table => table
     353              : 
     354         1062 :     do while (len_trim(remaining) > 0)
     355              :       ! Get next segment
     356         1061 :       sep_pos = index(remaining, "/")
     357         1061 :       if (sep_pos > 0) then
     358           21 :         segment = remaining(1:sep_pos-1)
     359           21 :         remaining = remaining(sep_pos+1:)
     360              :       else
     361         1040 :         segment = remaining
     362         1040 :         remaining = ""
     363              :       end if
     364              : 
     365              :       ! Look for existing child
     366         1061 :       call current_table%get_child_by_name(segment, current, case_insensitive=.true.)
     367              : 
     368         1061 :       if (.not. associated(current)) then
     369              :         ! Need to create node
     370         1046 :         if (len_trim(remaining) > 0) then
     371              :           ! More path segments: create table
     372            8 :           call new_table(new_tbl, name=segment)
     373            8 :           call current_table%add_child(new_tbl)
     374              :           ! Get the newly added child
     375            8 :           do i = current_table%num_children, 1, -1
     376            8 :             call current_table%get_child(i, current)
     377            8 :             if (associated(current)) then
     378            8 :               if (allocated(current%name)) then
     379            8 :                 if (to_lower(current%name) == to_lower(segment)) exit
     380              :               end if
     381              :             end if
     382              :           end do
     383              :         else
     384              :           ! Final segment: create value node
     385         1038 :           call new_value(new_val, name=segment)
     386         1038 :           call current_table%add_child(new_val)
     387              :           ! Get the newly added child
     388         1038 :           do i = current_table%num_children, 1, -1
     389         1038 :             call current_table%get_child(i, current)
     390         1038 :             if (associated(current)) then
     391         1038 :               if (allocated(current%name)) then
     392         1038 :                 if (to_lower(current%name) == to_lower(segment)) exit
     393              :               end if
     394              :             end if
     395              :           end do
     396         1038 :           child => current
     397         1038 :           if (present(stat)) stat = HSD_STAT_OK
     398         1038 :           return
     399              :         end if
     400              :       end if
     401              : 
     402              :       ! Navigate deeper if more path remains
     403           23 :       if (len_trim(remaining) > 0) then
     404              :         select type (current)
     405              :         type is (hsd_table)
     406            8 :           current_table => current
     407              :         class default
     408              :           ! Path segment is not a table, cannot navigate
     409           13 :           if (present(stat)) stat = HSD_STAT_NOT_FOUND
     410           13 :           return
     411              :         end select
     412              :       else
     413            2 :         child => current
     414            2 :         if (present(stat)) stat = HSD_STAT_OK
     415            2 :         return
     416              :       end if
     417              :     end do
     418              : 
     419            1 :     if (present(stat)) stat = HSD_STAT_NOT_FOUND
     420              : 
     421         2147 :   end subroutine get_or_create_child
     422              : 
     423         1143 : end module hsd_mutators
        

Generated by: LCOV version 2.0-1