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
|