LCOV - code coverage report
Current view: top level - src - hsd_types.f90 (source / functions) Coverage Total Hit
Test: coverage.info Lines: 100.0 % 26 26
Test Date: 2026-03-19 13:06:14 Functions: 50.0 % 8 4

            Line data    Source code
       1              : !> Data types for HSD nodes
       2              : !>
       3              : !> This module provides the tree structure for representing parsed HSD data.
       4              : !> The main types are:
       5              : !> - hsd_node_t     - Unified concrete node (table or value)
       6              : !> - hsd_node_ptr_t - Pointer wrapper for child storage
       7              : !> - hsd_iterator_t - Iterator for traversing table children
       8              : !>
       9              : !> ## Memory Ownership Semantics
      10              : !>
      11              : !> The HSD tree uses a **copy-on-add** ownership model:
      12              : !>
      13              : !> - **table_add_child**: Creates a deep copy of the node via
      14              : !>   `allocate(source=child)`. The caller retains ownership of the
      15              : !>   original node.
      16              : !>
      17              : !> - **table_get_child, table_get_child_by_name**: Return pointers to
      18              : !>   nodes owned by the table. Do NOT deallocate returned pointers.
      19              : !>
      20              : !> - **table_remove_child**: Deallocates the removed node. Any pointers
      21              : !>   previously obtained via get_child become invalid.
      22              : !>
      23              : !> - **destroy**: Recursively deallocates all children. Must be
      24              : !>   called explicitly to avoid memory leaks.
      25              : !>
      26              : !> ## Module Structure
      27              : !>
      28              : !> Type definitions and constructors live in this parent module.
      29              : !> Implementations are split across two submodules for maintainability:
      30              : !> - **hsd_table_ops** — table and iterator operations
      31              : !> - **hsd_value_ops** — value setters, getters, and parse helpers
      32              : module hsd_types
      33              :   use hsd_constants, only: dp
      34              :   use hsd_utils, only: to_lower
      35              :   use hsd_error, only: HSD_STAT_OK, HSD_STAT_TYPE_ERROR, &
      36              :       & HSD_STAT_NOT_FOUND
      37              :   implicit none (type, external)
      38              :   private
      39              : 
      40              :   public :: hsd_node_t, hsd_node_ptr_t, hsd_iterator_t
      41              :   public :: new_table, new_value
      42              :   public :: NODE_TYPE_TABLE, NODE_TYPE_VALUE
      43              :   public :: VALUE_TYPE_NONE, VALUE_TYPE_STRING, VALUE_TYPE_INTEGER
      44              :   public :: VALUE_TYPE_REAL, VALUE_TYPE_LOGICAL, VALUE_TYPE_ARRAY
      45              :   public :: VALUE_TYPE_COMPLEX
      46              : 
      47              :   !> Node type enumeration
      48              :   integer, parameter :: NODE_TYPE_TABLE = 1
      49              :   integer, parameter :: NODE_TYPE_VALUE = 2
      50              : 
      51              :   !> Value type enumeration
      52              :   integer, parameter :: VALUE_TYPE_NONE = 0
      53              :   integer, parameter :: VALUE_TYPE_STRING = 1
      54              :   integer, parameter :: VALUE_TYPE_INTEGER = 2
      55              :   integer, parameter :: VALUE_TYPE_REAL = 3
      56              :   integer, parameter :: VALUE_TYPE_LOGICAL = 4
      57              :   integer, parameter :: VALUE_TYPE_ARRAY = 5
      58              :   integer, parameter :: VALUE_TYPE_COMPLEX = 6
      59              : 
      60              :   !> Pointer wrapper for node storage
      61              :   !>
      62              :   !> Uses a pointer (not allocatable) so that when the children array
      63              :   !> is reallocated during growth, pointers to child nodes obtained via
      64              :   !> get_child/get_child_by_name remain valid.
      65              :   type :: hsd_node_ptr_t
      66              :     type(hsd_node_t), pointer :: node => null()
      67              :   end type hsd_node_ptr_t
      68              : 
      69              :   !> Unified HSD node type (table or value)
      70              :   type :: hsd_node_t
      71              :     !> Node name (tag name)
      72              :     character(len=:), allocatable :: name
      73              :     !> Optional attribute (e.g., unit)
      74              :     character(len=:), allocatable :: attrib
      75              :     !> Line number where this node was defined (for error messages)
      76              :     integer :: line = 0
      77              :     !> Whether this node has been accessed/processed
      78              :     logical :: processed = .false.
      79              :     !> Node type discriminator (NODE_TYPE_TABLE or NODE_TYPE_VALUE)
      80              :     integer :: node_type = 0
      81              :     !> Child nodes (table only)
      82              :     type(hsd_node_ptr_t), allocatable :: children(:)
      83              :     !> Number of children (table only)
      84              :     integer :: num_children = 0
      85              :     !> Type of value stored (value only)
      86              :     integer :: value_type = VALUE_TYPE_NONE
      87              :     !> String representation of the value (value only)
      88              :     character(len=:), allocatable :: string_value
      89              :   contains
      90              :     ! Common
      91              :     procedure :: has_attrib => node_has_attrib
      92              :     procedure :: get_attrib => node_get_attrib
      93              :     ! Table operations
      94              :     procedure :: add_child => table_add_child
      95              :     procedure :: get_child => table_get_child
      96              :     procedure :: get_child_by_name => table_get_child_by_name
      97              :     procedure :: has_child => table_has_child
      98              :     procedure :: num_children_func => table_num_children
      99              :     procedure :: remove_child => table_remove_child
     100              :     procedure :: remove_child_by_name => table_remove_child_by_name
     101              :     procedure :: get_keys => table_get_keys
     102              :     ! Value operations
     103              :     procedure :: set_string => value_set_string
     104              :     procedure :: set_integer => value_set_integer
     105              :     procedure :: set_real => value_set_real
     106              :     procedure :: set_logical => value_set_logical
     107              :     procedure :: set_complex => value_set_complex
     108              :     procedure :: set_raw => value_set_raw
     109              :     procedure :: get_string => value_get_string
     110              :     procedure :: get_integer => value_get_integer
     111              :     procedure :: get_real => value_get_real
     112              :     procedure :: get_logical => value_get_logical
     113              :     procedure :: get_complex => value_get_complex
     114              :     procedure :: get_int_array => value_get_int_array
     115              :     procedure :: get_real_array => value_get_real_array
     116              :     procedure :: get_logical_array => value_get_logical_array
     117              :     procedure :: get_string_array => value_get_string_array
     118              :     procedure :: get_complex_array => value_get_complex_array
     119              :     procedure :: get_int_matrix => value_get_int_matrix
     120              :     procedure :: get_real_matrix => value_get_real_matrix
     121              :     procedure :: get_complex_matrix => value_get_complex_matrix
     122              :     ! Destroy
     123              :     procedure :: destroy => node_destroy
     124              :   end type hsd_node_t
     125              : 
     126              :   !> Iterator for traversing table children
     127              :   type :: hsd_iterator_t
     128              :     !> Reference to the table being iterated
     129              :     type(hsd_node_t), pointer :: table => null()
     130              :     !> Current position (0 = before first)
     131              :     integer :: pos = 0
     132              :   contains
     133              :     procedure :: init => iterator_init
     134              :     procedure :: next => iterator_next
     135              :     procedure :: reset => iterator_reset
     136              :     procedure :: has_next => iterator_has_next
     137              :   end type hsd_iterator_t
     138              : 
     139              :   ! =================================================================
     140              :   ! Submodule procedure interfaces
     141              :   ! =================================================================
     142              : 
     143              :   interface
     144              : 
     145              :     ! --- Table operations (submodule hsd_table_ops) ---
     146              : 
     147              :     module subroutine table_add_child(self, child)
     148              :       implicit none (type, external)
     149              :       class(hsd_node_t), intent(inout) :: self
     150              :       type(hsd_node_t), intent(in) :: child
     151              :     end subroutine table_add_child
     152              : 
     153              :     module subroutine table_get_child( &
     154              :         & self, index, child)
     155              :       implicit none (type, external)
     156              :       class(hsd_node_t), intent(in), target :: self
     157              :       integer, intent(in) :: index
     158              :       type(hsd_node_t), pointer, intent(out) :: child
     159              :     end subroutine table_get_child
     160              : 
     161              :     module subroutine table_get_child_by_name( &
     162              :         & self, name, child)
     163              :       implicit none (type, external)
     164              :       class(hsd_node_t), intent(in), target :: self
     165              :       character(len=*), intent(in) :: name
     166              :       type(hsd_node_t), pointer, intent(out) :: child
     167              :     end subroutine table_get_child_by_name
     168              : 
     169              :     module function table_has_child( &
     170              :         & self, name) result(has)
     171              :       implicit none (type, external)
     172              :       class(hsd_node_t), intent(in) :: self
     173              :       character(len=*), intent(in) :: name
     174              :       logical :: has
     175              :     end function table_has_child
     176              : 
     177              :     pure module function table_num_children( &
     178              :         & self) result(n)
     179              :       implicit none (type, external)
     180              :       class(hsd_node_t), intent(in) :: self
     181              :       integer :: n
     182              :     end function table_num_children
     183              : 
     184              :     module subroutine table_get_keys(self, keys)
     185              :       implicit none (type, external)
     186              :       class(hsd_node_t), intent(in) :: self
     187              :       character(len=:), allocatable, intent(out) :: keys(:)
     188              :     end subroutine table_get_keys
     189              : 
     190              :     module subroutine table_remove_child( &
     191              :         & self, index, stat)
     192              :       implicit none (type, external)
     193              :       class(hsd_node_t), intent(inout) :: self
     194              :       integer, intent(in) :: index
     195              :       integer, intent(out), optional :: stat
     196              :     end subroutine table_remove_child
     197              : 
     198              :     module subroutine table_remove_child_by_name( &
     199              :         & self, name, stat)
     200              :       implicit none (type, external)
     201              :       class(hsd_node_t), intent(inout) :: self
     202              :       character(len=*), intent(in) :: name
     203              :       integer, intent(out), optional :: stat
     204              :     end subroutine table_remove_child_by_name
     205              : 
     206              :     recursive module subroutine node_destroy(self)
     207              :       implicit none (type, external)
     208              :       class(hsd_node_t), intent(inout) :: self
     209              :     end subroutine node_destroy
     210              : 
     211              :     ! --- Iterator operations (submodule hsd_table_ops) ---
     212              : 
     213              :     module subroutine iterator_init(self, table)
     214              :       implicit none (type, external)
     215              :       class(hsd_iterator_t), intent(inout) :: self
     216              :       type(hsd_node_t), target, intent(in) :: table
     217              :     end subroutine iterator_init
     218              : 
     219              :     module function iterator_next(self, child) &
     220              :         & result(has_more)
     221              :       implicit none (type, external)
     222              :       class(hsd_iterator_t), intent(inout) :: self
     223              :       type(hsd_node_t), pointer, intent(out) :: child
     224              :       logical :: has_more
     225              :     end function iterator_next
     226              : 
     227              :     module subroutine iterator_reset(self)
     228              :       implicit none (type, external)
     229              :       class(hsd_iterator_t), intent(inout) :: self
     230              :     end subroutine iterator_reset
     231              : 
     232              :     module function iterator_has_next( &
     233              :         & self) result(has_more)
     234              :       implicit none (type, external)
     235              :       class(hsd_iterator_t), intent(in) :: self
     236              :       logical :: has_more
     237              :     end function iterator_has_next
     238              : 
     239              :     ! --- Value setters (submodule hsd_value_ops) ---
     240              : 
     241              :     module subroutine value_set_string(self, val)
     242              :       implicit none (type, external)
     243              :       class(hsd_node_t), intent(inout) :: self
     244              :       character(len=*), intent(in) :: val
     245              :     end subroutine value_set_string
     246              : 
     247              :     module subroutine value_set_integer(self, val)
     248              :       implicit none (type, external)
     249              :       class(hsd_node_t), intent(inout) :: self
     250              :       integer, intent(in) :: val
     251              :     end subroutine value_set_integer
     252              : 
     253              :     module subroutine value_set_real(self, val)
     254              :       implicit none (type, external)
     255              :       class(hsd_node_t), intent(inout) :: self
     256              :       real(dp), intent(in) :: val
     257              :     end subroutine value_set_real
     258              : 
     259              :     module subroutine value_set_logical(self, val)
     260              :       implicit none (type, external)
     261              :       class(hsd_node_t), intent(inout) :: self
     262              :       logical, intent(in) :: val
     263              :     end subroutine value_set_logical
     264              : 
     265              :     module subroutine value_set_complex(self, val)
     266              :       implicit none (type, external)
     267              :       class(hsd_node_t), intent(inout) :: self
     268              :       complex(dp), intent(in) :: val
     269              :     end subroutine value_set_complex
     270              : 
     271              :     module subroutine value_set_raw(self, text)
     272              :       implicit none (type, external)
     273              :       class(hsd_node_t), intent(inout) :: self
     274              :       character(len=*), intent(in) :: text
     275              :     end subroutine value_set_raw
     276              : 
     277              :     ! --- Value getters (submodule hsd_value_ops) ---
     278              : 
     279              :     module subroutine value_get_string( &
     280              :         & self, val, stat)
     281              :       implicit none (type, external)
     282              :       class(hsd_node_t), intent(in) :: self
     283              :       character(len=:), allocatable, intent(out) :: val
     284              :       integer, intent(out), optional :: stat
     285              :     end subroutine value_get_string
     286              : 
     287              :     module subroutine value_get_integer( &
     288              :         & self, val, stat)
     289              :       implicit none (type, external)
     290              :       class(hsd_node_t), intent(in) :: self
     291              :       integer, intent(out) :: val
     292              :       integer, intent(out), optional :: stat
     293              :     end subroutine value_get_integer
     294              : 
     295              :     module subroutine value_get_real( &
     296              :         & self, val, stat)
     297              :       implicit none (type, external)
     298              :       class(hsd_node_t), intent(in) :: self
     299              :       real(dp), intent(out) :: val
     300              :       integer, intent(out), optional :: stat
     301              :     end subroutine value_get_real
     302              : 
     303              :     module subroutine value_get_logical( &
     304              :         & self, val, stat)
     305              :       implicit none (type, external)
     306              :       class(hsd_node_t), intent(in) :: self
     307              :       logical, intent(out) :: val
     308              :       integer, intent(out), optional :: stat
     309              :     end subroutine value_get_logical
     310              : 
     311              :     module subroutine value_get_complex( &
     312              :         & self, val, stat)
     313              :       implicit none (type, external)
     314              :       class(hsd_node_t), intent(in) :: self
     315              :       complex(dp), intent(out) :: val
     316              :       integer, intent(out), optional :: stat
     317              :     end subroutine value_get_complex
     318              : 
     319              :     ! --- Array getters (submodule hsd_value_ops) ---
     320              : 
     321              :     module subroutine value_get_int_array( &
     322              :         & self, val, stat)
     323              :       implicit none (type, external)
     324              :       class(hsd_node_t), intent(in) :: self
     325              :       integer, allocatable, intent(out) :: val(:)
     326              :       integer, intent(out), optional :: stat
     327              :     end subroutine value_get_int_array
     328              : 
     329              :     module subroutine value_get_real_array( &
     330              :         & self, val, stat)
     331              :       implicit none (type, external)
     332              :       class(hsd_node_t), intent(in) :: self
     333              :       real(dp), allocatable, intent(out) :: val(:)
     334              :       integer, intent(out), optional :: stat
     335              :     end subroutine value_get_real_array
     336              : 
     337              :     module subroutine value_get_logical_array( &
     338              :         & self, val, stat)
     339              :       implicit none (type, external)
     340              :       class(hsd_node_t), intent(in) :: self
     341              :       logical, allocatable, intent(out) :: val(:)
     342              :       integer, intent(out), optional :: stat
     343              :     end subroutine value_get_logical_array
     344              : 
     345              :     module subroutine value_get_string_array( &
     346              :         & self, val, stat)
     347              :       implicit none (type, external)
     348              :       class(hsd_node_t), intent(in) :: self
     349              :       character(len=:), allocatable, intent(out) :: val(:)
     350              :       integer, intent(out), optional :: stat
     351              :     end subroutine value_get_string_array
     352              : 
     353              :     module subroutine value_get_complex_array( &
     354              :         & self, val, stat)
     355              :       implicit none (type, external)
     356              :       class(hsd_node_t), intent(in) :: self
     357              :       complex(dp), allocatable, intent(out) :: val(:)
     358              :       integer, intent(out), optional :: stat
     359              :     end subroutine value_get_complex_array
     360              : 
     361              :     ! --- Matrix getters (submodule hsd_value_ops) ---
     362              : 
     363              :     module subroutine value_get_int_matrix( &
     364              :         & self, val, nrows, ncols, stat)
     365              :       implicit none (type, external)
     366              :       class(hsd_node_t), intent(in) :: self
     367              :       integer, allocatable, intent(out) :: val(:,:)
     368              :       integer, intent(out) :: nrows, ncols
     369              :       integer, intent(out), optional :: stat
     370              :     end subroutine value_get_int_matrix
     371              : 
     372              :     module subroutine value_get_real_matrix( &
     373              :         & self, val, nrows, ncols, stat)
     374              :       implicit none (type, external)
     375              :       class(hsd_node_t), intent(in) :: self
     376              :       real(dp), allocatable, intent(out) :: val(:,:)
     377              :       integer, intent(out) :: nrows, ncols
     378              :       integer, intent(out), optional :: stat
     379              :     end subroutine value_get_real_matrix
     380              : 
     381              :     module subroutine value_get_complex_matrix( &
     382              :         & self, val, nrows, ncols, stat)
     383              :       implicit none (type, external)
     384              :       class(hsd_node_t), intent(in) :: self
     385              :       complex(dp), allocatable, intent(out) :: val(:,:)
     386              :       integer, intent(out) :: nrows, ncols
     387              :       integer, intent(out), optional :: stat
     388              :     end subroutine value_get_complex_matrix
     389              : 
     390              :   end interface
     391              : 
     392              : contains
     393              : 
     394              :   !> Check if node has an attribute
     395         1169 :   pure function node_has_attrib(self) result(has)
     396              :     class(hsd_node_t), intent(in) :: self
     397              :     logical :: has
     398         1169 :     has = allocated(self%attrib)
     399         2338 :   end function node_has_attrib
     400              : 
     401              :   !> Get node attribute (empty string if not set)
     402           10 :   pure function node_get_attrib(self) result(attrib)
     403              :     class(hsd_node_t), intent(in) :: self
     404              :     character(len=:), allocatable :: attrib
     405           10 :     if (allocated(self%attrib)) then
     406            9 :       attrib = self%attrib
     407              :     else
     408            1 :       attrib = ""
     409              :     end if
     410         1169 :   end function node_get_attrib
     411              : 
     412              :   !> Create a new table node
     413         2176 :   subroutine new_table(table, name, attrib, line)
     414              :     type(hsd_node_t), intent(out) :: table
     415              :     character(len=*), intent(in), optional :: name
     416              :     character(len=*), intent(in), optional :: attrib
     417              :     integer, intent(in), optional :: line
     418              : 
     419         1088 :     table%node_type = NODE_TYPE_TABLE
     420         1088 :     if (present(name)) table%name = to_lower(name)
     421         1088 :     if (present(attrib)) then
     422          507 :       if (len_trim(attrib) > 0) table%attrib = attrib
     423              :     end if
     424         1088 :     if (present(line)) table%line = line
     425              : 
     426         5440 :     allocate(table%children(4))
     427         1088 :     table%num_children = 0
     428              : 
     429           10 :   end subroutine new_table
     430              : 
     431              :   !> Create a new value node
     432         5102 :   subroutine new_value(val, name, attrib, line)
     433              :     type(hsd_node_t), intent(out) :: val
     434              :     character(len=*), intent(in), optional :: name
     435              :     character(len=*), intent(in), optional :: attrib
     436              :     integer, intent(in), optional :: line
     437              : 
     438         2551 :     val%node_type = NODE_TYPE_VALUE
     439         2551 :     if (present(name)) val%name = to_lower(name)
     440         2551 :     if (present(attrib)) then
     441         1016 :       if (len_trim(attrib) > 0) val%attrib = attrib
     442              :     end if
     443         2551 :     if (present(line)) val%line = line
     444         2551 :     val%value_type = VALUE_TYPE_NONE
     445              : 
     446         1088 :   end subroutine new_value
     447              : 
     448         2551 : end module hsd_types
        

Generated by: LCOV version 2.0-1