LCOV - code coverage report
Current view: top level - src/core - hsd_utils.f90 (source / functions) Coverage Total Hit
Test: coverage.info Lines: 100.0 % 53 53
Test Date: 2026-02-04 13:26:36 Functions: 75.0 % 8 6

            Line data    Source code
       1              : !> Utility functions and types for the HSD parser
       2              : module hsd_utils
       3              :   use hsd_constants, only: dp, sp
       4              :   implicit none (type, external)
       5              :   private
       6              : 
       7              :   public :: string_buffer_t
       8              :   public :: to_lower
       9              : 
      10              :   !> Initial buffer capacity
      11              :   integer, parameter :: BUFFER_INITIAL_CAPACITY = 256
      12              : 
      13              :   !> String buffer for efficient string building
      14              :   !>
      15              :   !> Avoids O(n²) string concatenation by pre-allocating buffer space
      16              :   !> and growing geometrically when needed.
      17              :   type :: string_buffer_t
      18              :     character(len=:), allocatable :: buffer
      19              :     integer :: length = 0
      20              :     integer :: capacity = 0
      21              :   contains
      22              :     procedure :: init => buffer_init
      23              :     procedure :: append_char => buffer_append_char
      24              :     procedure :: append_str => buffer_append_str
      25              :     procedure :: get_string => buffer_get_string
      26              :     procedure :: clear => buffer_clear
      27              :   end type string_buffer_t
      28              : 
      29              : contains
      30              : 
      31              :   !> Initialize the string buffer with given or default capacity
      32        34828 :   subroutine buffer_init(self, initial_capacity)
      33              :     class(string_buffer_t), intent(inout) :: self
      34              :     integer, intent(in), optional :: initial_capacity
      35              : 
      36        34828 :     if (present(initial_capacity)) then
      37            6 :       self%capacity = initial_capacity
      38              :     else
      39        34822 :       self%capacity = BUFFER_INITIAL_CAPACITY
      40              :     end if
      41              : 
      42        34828 :     if (allocated(self%buffer)) deallocate(self%buffer)
      43        34828 :     allocate(character(len=self%capacity) :: self%buffer)
      44        34828 :     self%length = 0
      45              : 
      46        34828 :   end subroutine buffer_init
      47              : 
      48              :   !> Append a single character to the buffer
      49       882732 :   subroutine buffer_append_char(self, ch)
      50              :     class(string_buffer_t), intent(inout) :: self
      51              :     character(len=1), intent(in) :: ch
      52              : 
      53       882732 :     character(len=:), allocatable :: new_buffer
      54       882732 :     integer :: new_capacity
      55              : 
      56              :     ! Initialize if needed
      57       882732 :     if (self%capacity == 0) call self%init()
      58              : 
      59              :     ! Grow buffer if needed (double capacity)
      60       882732 :     if (self%length >= self%capacity) then
      61          534 :       new_capacity = self%capacity * 2
      62          534 :       allocate(character(len=new_capacity) :: new_buffer)
      63          534 :       new_buffer(1:self%length) = self%buffer(1:self%length)
      64          534 :       call move_alloc(new_buffer, self%buffer)
      65          534 :       self%capacity = new_capacity
      66              :     end if
      67              : 
      68       882732 :     self%length = self%length + 1
      69       882732 :     self%buffer(self%length:self%length) = ch
      70              : 
      71       917560 :   end subroutine buffer_append_char
      72              : 
      73              :   !> Append a string to the buffer
      74           57 :   subroutine buffer_append_str(self, str)
      75              :     class(string_buffer_t), intent(inout) :: self
      76              :     character(len=*), intent(in) :: str
      77              : 
      78           57 :     character(len=:), allocatable :: new_buffer
      79           57 :     integer :: new_capacity, str_len
      80              : 
      81           57 :     str_len = len(str)
      82            1 :     if (str_len == 0) return
      83              : 
      84              :     ! Initialize if needed
      85           56 :     if (self%capacity == 0) call self%init()
      86              : 
      87              :     ! Grow buffer if needed
      88           56 :     if (self%length + str_len > self%capacity) then
      89            5 :       new_capacity = max(self%capacity * 2, self%length + str_len)
      90            5 :       allocate(character(len=new_capacity) :: new_buffer)
      91            5 :       new_buffer(1:self%length) = self%buffer(1:self%length)
      92            5 :       call move_alloc(new_buffer, self%buffer)
      93            5 :       self%capacity = new_capacity
      94              :     end if
      95              : 
      96           56 :     self%buffer(self%length+1:self%length+str_len) = str
      97           56 :     self%length = self%length + str_len
      98              : 
      99       882789 :   end subroutine buffer_append_str
     100              : 
     101              :   !> Get the accumulated string
     102        34830 :   function buffer_get_string(self) result(str)
     103              :     class(string_buffer_t), intent(in) :: self
     104              :     character(len=:), allocatable :: str
     105              : 
     106        34830 :     if (self%length > 0) then
     107        34823 :       str = self%buffer(1:self%length)
     108              :     else
     109            7 :       str = ""
     110              :     end if
     111              : 
     112           57 :   end function buffer_get_string
     113              : 
     114              :   !> Clear the buffer for reuse (keeps capacity)
     115            5 :   subroutine buffer_clear(self)
     116              :     class(string_buffer_t), intent(inout) :: self
     117            5 :     self%length = 0
     118        34830 :   end subroutine buffer_clear
     119              : 
     120              :   !> Convert a string to lowercase
     121      1670814 :   pure function to_lower(str) result(lower)
     122              :     character(len=*), intent(in) :: str
     123              :     character(len=len(str)) :: lower
     124      1670814 :     integer :: i, ic
     125              : 
     126      7858376 :     do i = 1, len(str)
     127      6187562 :       ic = ichar(str(i:i))
     128      7858376 :       if (ic >= 65 .and. ic <= 90) then
     129        40148 :         lower(i:i) = char(ic + 32)
     130              :       else
     131      6147414 :         lower(i:i) = str(i:i)
     132              :       end if
     133              :     end do
     134      3341633 :   end function to_lower
     135              : 
     136      1670814 : end module hsd_utils
        

Generated by: LCOV version 2.0-1