Skip to content

Commit 843c68a

Browse files
committed
Preliminary implementation of stringlist module
This commit introduces a very preliminary version of a module to handle lists of strings (that is: a structure containing strings of varying lengths)
1 parent c371a16 commit 843c68a

File tree

5 files changed

+214
-0
lines changed

5 files changed

+214
-0
lines changed

src/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ set(SRC
3737
stdlib_error.f90
3838
stdlib_kinds.f90
3939
stdlib_logger.f90
40+
stdlib_stringlist.f90
4041
stdlib_system.F90
4142
${outFiles}
4243
)

src/stdlib_stringlist.f90

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
! stringlist.f90 --
2+
! Module for storing and manipulating lists of strings
3+
! The strings may have arbitrary lengths, not necessarily the same
4+
!
5+
! Note: very preliminary
6+
!
7+
module stdlib_stringlists
8+
implicit none
9+
10+
private
11+
integer, parameter, public :: list_head = 0
12+
integer, parameter, public :: list_end = -1
13+
public :: t_stringlist
14+
15+
16+
integer, parameter :: initial_size = 20
17+
18+
type t_string
19+
character(len=:), allocatable :: value
20+
end type t_string
21+
22+
type t_stringlist
23+
private
24+
integer :: size = 0
25+
type(t_string), dimension(:), allocatable :: string
26+
contains
27+
procedure :: insert => insert_string
28+
procedure :: get => get_string
29+
procedure :: length => length_list
30+
end type t_stringlist
31+
32+
contains
33+
34+
! length_list --
35+
! Return the size (length) of the list
36+
!
37+
! Arguments:
38+
! list The list of strings to retrieve the string from
39+
!
40+
integer function length_list( list )
41+
class(t_stringlist), intent(in) :: list
42+
43+
length_list = list%size
44+
end function length_list
45+
46+
! insert_string --
47+
! Insert a new string into the list
48+
!
49+
! Arguments:
50+
! list The list of strings where the new string should be inserted
51+
! idx Index after which to insert the string
52+
! string The string in question
53+
!
54+
subroutine insert_string( list, idx, string )
55+
class(t_stringlist), intent(inout) :: list
56+
integer, intent(in) :: idx
57+
character(len=*), intent(in) :: string
58+
59+
integer :: i
60+
integer :: idxnew
61+
type(t_string) :: new_element
62+
type(t_string), dimension(:), allocatable :: empty_strings
63+
64+
!
65+
! Initialise the list if necessary
66+
!
67+
if ( .not. allocated(list%string) ) then
68+
allocate( list%string(initial_size) )
69+
do i = 1,size(list%string)
70+
list%string(i)%value = ''
71+
enddo
72+
endif
73+
74+
!
75+
! Check the index:
76+
! - if the index is list_head, then shift the entire array
77+
! - if the index is list_end or negative in general, determine the absolute index
78+
! - if the index is large than the registered size, expand the list
79+
! - shift everything after the absolute index
80+
!
81+
new_element%value = string
82+
83+
if ( idx == list_head ) then
84+
list%size = list%size + 1
85+
list%string = [new_element, list%string]
86+
else
87+
idxnew = idx
88+
if ( idx <= list_end ) then
89+
idxnew = list%size - (abs(idx) - 1)
90+
if ( idxnew <= 0 ) then
91+
idxnew = 0
92+
endif
93+
endif
94+
95+
if ( idxnew <= size(list%string) ) then
96+
list%size = max( idxnew+1, list%size + 1 )
97+
list%string = [list%string(1:idxnew), new_element, list%string(idxnew+1:)]
98+
else
99+
allocate( empty_strings(idxnew-size(list%string)) )
100+
do i = 1,size(empty_strings)
101+
empty_strings(i)%value = ''
102+
enddo
103+
list%string = [list%string, empty_strings, new_element]
104+
list%size = idxnew + 1
105+
endif
106+
endif
107+
end subroutine insert_string
108+
109+
! get_string --
110+
! Get the string at a particular index
111+
!
112+
! Arguments:
113+
! list The list of strings to retrieve the string from
114+
! idx Index after which to insert the string
115+
!
116+
function get_string( list, idx )
117+
class(t_stringlist), intent(inout) :: list
118+
integer, intent(in) :: idx
119+
character(len=:), allocatable :: get_string
120+
121+
integer :: idxnew
122+
type(t_string) :: new_element
123+
124+
!
125+
! Examine the actual index:
126+
! - if the index is larger than the size, return an empty string
127+
! - if the index is equal to list_head, interpret it as index 1
128+
! - if the index is negative, calculate the absolute index
129+
!
130+
if ( idx > list%size ) then
131+
get_string = ''
132+
else
133+
idxnew = idx
134+
if ( idx == list_head ) then
135+
idxnew = 1
136+
elseif ( idx <= list_end ) then
137+
idxnew = list%size - (abs(idx) - 1)
138+
endif
139+
140+
if ( idxnew < 1 ) then
141+
get_string = ''
142+
else
143+
get_string = list%string(idxnew)%value
144+
endif
145+
endif
146+
end function get_string
147+
148+
end module stdlib_stringlists

src/tests/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ add_subdirectory(optval)
1515
add_subdirectory(stats)
1616
add_subdirectory(system)
1717
add_subdirectory(quadrature)
18+
add_subdirectory(stringlist)
1819

1920
ADDTEST(always_skip)
2021
set_tests_properties(always_skip PROPERTIES SKIP_RETURN_CODE 77)

src/tests/stringlist/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
ADDTEST(stringlist)
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
! test_stringlist.f90 --
2+
! Test program for the stdlib_stringlist module
3+
!
4+
! Straightforward test program: try to cover "all" special cases
5+
!
6+
program test_stringlists
7+
use stdlib_stringlists
8+
9+
implicit none
10+
11+
type(t_stringlist) :: list
12+
integer :: i
13+
14+
!
15+
! The straightforward cases: insert a few strings and retrieve them
16+
!
17+
call list%insert( list_head, "C" )
18+
call list%insert( list_head, "B" )
19+
call list%insert( list_head, "A" )
20+
21+
!
22+
! Now insert a string at an arbitrary location - it will be at position 11
23+
!
24+
call list%insert( 10, "Number 10" )
25+
26+
!
27+
! Append a string to the end of the list - that will be position 12
28+
!
29+
call list%insert( list_end, "Appended" )
30+
31+
!
32+
! Insert a string near the end of the list - that will be position 12-2+1
33+
!
34+
call list%insert( list_end-2, "Appended 2" )
35+
36+
!
37+
! Insert a string beyond the beginning - that should appear at the start
38+
!
39+
call list%insert( list_end-30, "Effectively prepended" )
40+
41+
!
42+
! Print the result
43+
!
44+
do i = 1,list%length()
45+
write(*,*) i, '>', list%get(i), '<'
46+
enddo
47+
48+
!
49+
! And select two elements at the end
50+
!
51+
write(*,*) 'end-1' , '>', list%get(list_end-1), '<'
52+
write(*,*) 'end' , '>', list%get(list_end), '<'
53+
write(*,*) 'end-30', '>', list%get(list_end-30), '<'
54+
55+
!
56+
! Okay, finally set an element really far and read it back
57+
!
58+
call list%insert( 40, "Really far away" )
59+
write(*,*) '40', '>', list%get(40), '<'
60+
write(*,*) '41', '>', list%get(41), '<'
61+
write(*,*) list%length()
62+
63+
end program test_stringlists

0 commit comments

Comments
 (0)