Skip to content

Commit 77f98dc

Browse files
committedFeb 13, 2021
Implement non-fancy functional string type
- support all intrinsic operators for character variables (llt, lgt, lle, lge, len, len_trim, trim, adjustl, adjustr, index, scan, verify, repeat, char, ichar, iachar) - support derived type IO (formatted and unformatted) - implement assignment from character values - implement constructing string from character values
1 parent a1c911c commit 77f98dc

13 files changed

+3197
-0
lines changed
 

‎doc/specs/index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ This is and index/directory of the specifications (specs) for each new module/fe
2020
- [quadrature](./stdlib_quadrature.html) - Numerical integration
2121
- [stats](./stdlib_stats.html) - Descriptive Statistics
2222
- [stats_distribution_PRNG](./stdlib_stats_distribution_PRNG.html) - Probability Distributions random number generator
23+
- [string\_type](./stdlib_string_type.html) - Basic string support
2324

2425
## Missing specs
2526

‎doc/specs/stdlib_string_type.md

Lines changed: 1607 additions & 0 deletions
Large diffs are not rendered by default.

‎src/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ set(SRC
4141
stdlib_error.f90
4242
stdlib_kinds.f90
4343
stdlib_logger.f90
44+
stdlib_string_type.f90
4445
stdlib_system.F90
4546
${outFiles}
4647
)

‎src/Makefile.manual

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ SRC = f18estop.f90 \
2525
stdlib_error.f90 \
2626
stdlib_kinds.f90 \
2727
stdlib_logger.f90 \
28+
stdlib_string_type.f90 \
2829
$(SRCGEN)
2930

3031
LIB = libstdlib.a

‎src/stdlib_string_type.f90

Lines changed: 1102 additions & 0 deletions
Large diffs are not rendered by default.

‎src/tests/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ add_subdirectory(linalg)
1313
add_subdirectory(logger)
1414
add_subdirectory(optval)
1515
add_subdirectory(stats)
16+
add_subdirectory(string)
1617
add_subdirectory(system)
1718
add_subdirectory(quadrature)
1819

‎src/tests/Makefile.manual

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ all:
88
$(MAKE) -f Makefile.manual --directory=optval
99
$(MAKE) -f Makefile.manual --directory=quadrature
1010
$(MAKE) -f Makefile.manual --directory=stats
11+
$(MAKE) -f Makefile.manual --directory=string
1112

1213
test:
1314
$(MAKE) -f Makefile.manual --directory=ascii test
@@ -17,6 +18,7 @@ test:
1718
$(MAKE) -f Makefile.manual --directory=optval test
1819
$(MAKE) -f Makefile.manual --directory=quadrature test
1920
$(MAKE) -f Makefile.manual --directory=stats test
21+
$(MAKE) -f Makefile.manual --directory=string test
2022

2123
clean:
2224
$(MAKE) -f Makefile.manual --directory=ascii clean
@@ -25,3 +27,4 @@ clean:
2527
$(MAKE) -f Makefile.manual --directory=logger clean
2628
$(MAKE) -f Makefile.manual --directory=optval clean
2729
$(MAKE) -f Makefile.manual --directory=stats clean
30+
$(MAKE) -f Makefile.manual --directory=string clean

‎src/tests/string/CMakeLists.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
ADDTEST(string_assignment)
2+
ADDTEST(string_operator)
3+
ADDTEST(string_intrinsic)
4+
ADDTEST(string_derivedtype_io)
5+

‎src/tests/string/Makefile.manual

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
PROGS_SRC = test_string_assignment.f90 \
2+
test_string_derivedtype_io.f90 \
3+
test_string_intrinsic.f90 \
4+
test_string_operator.f90
5+
6+
7+
include ../Makefile.manual.test.mk
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
! SPDX-Identifier: MIT
2+
module test_string_assignment
3+
use stdlib_error, only : check
4+
use stdlib_string_type, only : string_type, assignment(=), len
5+
implicit none
6+
7+
contains
8+
9+
subroutine test_assignment
10+
type(string_type) :: string
11+
12+
call check(len(string) == 0)
13+
14+
string = "Sequence"
15+
call check(len(string) == 8)
16+
end subroutine test_assignment
17+
18+
end module test_string_assignment
19+
20+
program tester
21+
use test_string_assignment
22+
implicit none
23+
24+
call test_assignment
25+
26+
end program tester
27+
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
! SPDX-Identifer: MIT
2+
module test_string_derivedtype_io
3+
use stdlib_error, only : check
4+
use stdlib_string_type, only : string_type, assignment(=), len, &
5+
write(formatted), read(formatted), write(unformatted), read(unformatted), &
6+
operator(.eq.)
7+
implicit none
8+
9+
contains
10+
11+
subroutine test_listdirected_io
12+
type(string_type) :: string
13+
integer :: io, stat
14+
string = "Important saved value"
15+
16+
open(newunit=io, form="formatted", status="scratch")
17+
write(io, *) string
18+
write(io, *) ! Pad with a newline or we might run into EOF while reading
19+
20+
string = ""
21+
rewind(io)
22+
23+
read(io, *, iostat=stat) string
24+
close(io)
25+
26+
call check(stat == 0)
27+
call check(len(string) == 21)
28+
call check(string == "Important saved value")
29+
end subroutine test_listdirected_io
30+
31+
subroutine test_formatted_io
32+
type(string_type) :: string
33+
integer :: io, stat
34+
string = "Important saved value"
35+
36+
!open(newunit=io, form="formatted", status="scratch")
37+
open(newunit=io, form="formatted", file="scratch.txt")
38+
write(io, '(dt)') string
39+
write(io, '(a)') ! Pad with a newline or we might run into EOF while reading
40+
41+
string = ""
42+
rewind(io)
43+
44+
read(io, *, iostat=stat) string
45+
close(io)
46+
47+
call check(stat == 0)
48+
call check(len(string) == 21)
49+
call check(string == "Important saved value")
50+
end subroutine test_formatted_io
51+
52+
subroutine test_unformatted_io
53+
type(string_type) :: string
54+
integer :: io
55+
string = "Important saved value"
56+
57+
open(newunit=io, form="unformatted", status="scratch")
58+
write(io) string
59+
60+
string = ""
61+
rewind(io)
62+
63+
read(io) string
64+
close(io)
65+
66+
call check(len(string) == 21)
67+
call check(string == "Important saved value")
68+
end subroutine test_unformatted_io
69+
70+
end module test_string_derivedtype_io
71+
72+
program tester
73+
use test_string_derivedtype_io
74+
implicit none
75+
76+
call test_listdirected_io
77+
call test_formatted_io
78+
call test_unformatted_io
79+
80+
end program tester
Lines changed: 239 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,239 @@
1+
! SPDX-Identifer: MIT
2+
module test_string_intrinsic
3+
use stdlib_error, only : check
4+
use stdlib_string_type
5+
implicit none
6+
7+
contains
8+
9+
subroutine test_lgt
10+
type(string_type) :: string
11+
logical :: res
12+
13+
string = "bcd"
14+
res = lgt(string, "abc")
15+
call check(res .eqv. .true.)
16+
17+
res = lgt(string, "bcd")
18+
call check(res .eqv. .false.)
19+
20+
res = lgt(string, "cde")
21+
call check(res .eqv. .false.)
22+
end subroutine test_lgt
23+
24+
subroutine test_llt
25+
type(string_type) :: string
26+
logical :: res
27+
28+
string = "bcd"
29+
res = llt(string, "abc")
30+
call check(res .eqv. .false.)
31+
32+
res = llt(string, "bcd")
33+
call check(res .eqv. .false.)
34+
35+
res = llt(string, "cde")
36+
call check(res .eqv. .true.)
37+
end subroutine test_llt
38+
39+
subroutine test_lge
40+
type(string_type) :: string
41+
logical :: res
42+
43+
string = "bcd"
44+
res = lge(string, "abc")
45+
call check(res .eqv. .true.)
46+
47+
res = lge(string, "bcd")
48+
call check(res .eqv. .true.)
49+
50+
res = lge(string, "cde")
51+
call check(res .eqv. .false.)
52+
end subroutine test_lge
53+
54+
subroutine test_lle
55+
type(string_type) :: string
56+
logical :: res
57+
58+
string = "bcd"
59+
res = lle(string, "abc")
60+
call check(res .eqv. .false.)
61+
62+
res = lle(string, "bcd")
63+
call check(res .eqv. .true.)
64+
65+
res = lle(string, "cde")
66+
call check(res .eqv. .true.)
67+
end subroutine test_lle
68+
69+
subroutine test_trim
70+
type(string_type) :: string, trimmed_str
71+
72+
string = "Whitespace "
73+
trimmed_str = trim(string)
74+
call check(len(trimmed_str) == 10)
75+
end subroutine test_trim
76+
77+
subroutine test_len
78+
type(string_type) :: string
79+
integer :: length
80+
81+
string = "Some longer sentence for this example."
82+
length = len(string)
83+
call check(length == 38)
84+
85+
string = "Whitespace "
86+
length = len(string)
87+
call check(length == 38)
88+
end subroutine test_len
89+
90+
subroutine test_len_trim
91+
type(string_type) :: string
92+
integer :: length
93+
94+
string = "Some longer sentence for this example."
95+
length = len_trim(string)
96+
call check(length == 38)
97+
98+
string = "Whitespace "
99+
length = len_trim(string)
100+
call check(length == 10)
101+
end subroutine test_len_trim
102+
103+
subroutine test_adjustl
104+
type(string_type) :: string
105+
106+
string = " Whitespace"
107+
string = adjustl(string)
108+
call check(char(string) == "Whitespace ")
109+
end subroutine test_adjustl
110+
111+
subroutine test_adjustr
112+
type(string_type) :: string
113+
114+
string = "Whitespace "
115+
string = adjustr(string)
116+
call check(char(string) == " Whitespace")
117+
end subroutine test_adjustr
118+
119+
subroutine test_scan
120+
type(string_type) :: string
121+
integer :: pos
122+
123+
string = "fortran"
124+
pos = scan(string, "ao")
125+
call check(pos == 2)
126+
127+
pos = scan(string, "ao", .true.)
128+
call check(pos == 6)
129+
130+
pos = scan(string, "c++")
131+
call check(pos == 0)
132+
end subroutine test_scan
133+
134+
subroutine test_verify
135+
type(string_type) :: string
136+
integer :: pos
137+
138+
string = "fortran"
139+
pos = verify(string, "ao")
140+
call check(pos == 1)
141+
142+
pos = verify(string, "fo")
143+
call check(pos == 3)
144+
145+
pos = verify(string, "c++")
146+
call check(pos == 1)
147+
148+
pos = verify(string, "c++", back=.true.)
149+
call check(pos == 7)
150+
151+
pos = verify(string, string)
152+
call check(pos == 0)
153+
end subroutine test_verify
154+
155+
subroutine test_repeat
156+
type(string_type) :: string
157+
158+
string = "What? "
159+
string = repeat(string, 3)
160+
call check(string == "What? What? What? ")
161+
end subroutine test_repeat
162+
163+
subroutine test_index
164+
type(string_type) :: string
165+
integer :: pos
166+
167+
string = "Search this string for this expression"
168+
pos = index(string, "this")
169+
call check(pos == 8)
170+
171+
pos = index(string, "this", back=.true.)
172+
call check(pos == 24)
173+
174+
pos = index(string, "This")
175+
call check(pos == 0)
176+
end subroutine test_index
177+
178+
subroutine test_char
179+
type(string_type) :: string
180+
character(len=:), allocatable :: dlc
181+
character(len=1), allocatable :: chars(:)
182+
183+
string = "Character sequence"
184+
dlc = char(string)
185+
call check(dlc == "Character sequence")
186+
187+
dlc = char(string, 3)
188+
call check(dlc == "a")
189+
chars = char(string, [3, 5, 8, 12, 14, 15, 18])
190+
call check(all(chars == ["a", "a", "e", "e", "u", "e", "e"]))
191+
192+
string = "Fortran"
193+
dlc = char(string, 1, 4)
194+
call check(dlc == "Fort")
195+
end subroutine test_char
196+
197+
subroutine test_ichar
198+
type(string_type) :: string
199+
integer :: code
200+
201+
string = "Fortran"
202+
code = ichar(string)
203+
call check(code == ichar("F"))
204+
end subroutine test_ichar
205+
206+
subroutine test_iachar
207+
type(string_type) :: string
208+
integer :: code
209+
210+
string = "Fortran"
211+
code = iachar(string)
212+
call check(code == iachar("F"))
213+
end subroutine test_iachar
214+
215+
end module test_string_intrinsic
216+
217+
program tester
218+
use test_string_intrinsic
219+
implicit none
220+
221+
call test_lgt
222+
call test_llt
223+
call test_lge
224+
call test_lle
225+
call test_trim
226+
call test_len
227+
call test_len_trim
228+
call test_adjustl
229+
call test_adjustr
230+
call test_scan
231+
call test_verify
232+
call test_repeat
233+
call test_index
234+
call test_char
235+
call test_ichar
236+
call test_iachar
237+
238+
end program tester
239+
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
! SPDX-Identifer: MIT
2+
module test_string_operator
3+
use stdlib_error, only : check
4+
use stdlib_string_type, only : string_type, assignment(=), len, &
5+
operator(.gt.), operator(.lt.), operator(.ge.), operator(.le.), &
6+
operator(.ne.), operator(.eq.), operator(//)
7+
implicit none
8+
9+
contains
10+
11+
subroutine test_gt
12+
type(string_type) :: string
13+
logical :: res
14+
15+
string = "bcd"
16+
res = string > "abc"
17+
call check(res .eqv. .true.)
18+
19+
res = string > "bcd"
20+
call check(res .eqv. .false.)
21+
22+
res = string > "cde"
23+
call check(res .eqv. .false.)
24+
end subroutine test_gt
25+
26+
subroutine test_lt
27+
type(string_type) :: string
28+
logical :: res
29+
30+
string = "bcd"
31+
res = string < "abc"
32+
call check(res .eqv. .false.)
33+
34+
res = string < "bcd"
35+
call check(res .eqv. .false.)
36+
37+
res = string < "cde"
38+
call check(res .eqv. .true.)
39+
end subroutine test_lt
40+
41+
subroutine test_ge
42+
type(string_type) :: string
43+
logical :: res
44+
45+
string = "bcd"
46+
res = string >= "abc"
47+
call check(res .eqv. .true.)
48+
49+
res = string >= "bcd"
50+
call check(res .eqv. .true.)
51+
52+
res = string >= "cde"
53+
call check(res .eqv. .false.)
54+
end subroutine test_ge
55+
56+
subroutine test_le
57+
type(string_type) :: string
58+
logical :: res
59+
60+
string = "bcd"
61+
res = string <= "abc"
62+
call check(res .eqv. .false.)
63+
64+
res = string <= "bcd"
65+
call check(res .eqv. .true.)
66+
67+
res = string <= "cde"
68+
call check(res .eqv. .true.)
69+
end subroutine test_le
70+
71+
subroutine test_eq
72+
type(string_type) :: string
73+
logical :: res
74+
75+
string = "bcd"
76+
res = string == "abc"
77+
call check(res .eqv. .false.)
78+
79+
res = string == "bcd"
80+
call check(res .eqv. .true.)
81+
82+
res = string == "cde"
83+
call check(res .eqv. .false.)
84+
end subroutine test_eq
85+
86+
subroutine test_ne
87+
type(string_type) :: string
88+
logical :: res
89+
90+
string = "bcd"
91+
res = string /= "abc"
92+
call check(res .eqv. .true.)
93+
94+
res = string /= "bcd"
95+
call check(res .eqv. .false.)
96+
97+
res = string /= "cde"
98+
call check(res .eqv. .true.)
99+
end subroutine test_ne
100+
101+
subroutine test_concat
102+
type(string_type) :: string
103+
104+
string = "Hello, "
105+
string = string // "World!"
106+
call check(len(string) == 13)
107+
end subroutine test_concat
108+
109+
end module test_string_operator
110+
111+
program tester
112+
use test_string_operator
113+
implicit none
114+
115+
call test_gt
116+
call test_lt
117+
call test_ge
118+
call test_le
119+
call test_eq
120+
call test_ne
121+
call test_concat
122+
123+
end program tester

0 commit comments

Comments
 (0)
Please sign in to comment.