-
Notifications
You must be signed in to change notification settings - Fork 3
/
main.f90
356 lines (355 loc) · 10.6 KB
/
main.f90
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
module anylist_m
!
! Module for a list type that can contain items with any scalar value.
! Values are copied into the list items.
!
! A list item can be in at most one list at a time.
!
implicit none
private
public :: anylist, anyitem, newitem
!
! type(anylist) is the list header type.
!
type anylist
class(anyitem), pointer, private :: firstptr => null()
contains
procedure, non_overridable :: append
procedure, non_overridable :: count_list
procedure, non_overridable :: delete_list
procedure, non_overridable :: first
procedure, non_overridable :: last
procedure, non_overridable :: prepend
procedure, non_overridable :: print_list
end type
!
! type(anyitem) is the list item type.
! These are allocated by newitem.
!
type anyitem
class(*), allocatable :: value
class(anyitem), pointer, private :: nextptr => null(), prevptr => null()
class(anylist), pointer, private :: upptr => null()
contains
procedure, non_overridable :: change
procedure, non_overridable :: delete
procedure, non_overridable :: list
procedure, non_overridable :: next
procedure, non_overridable :: prev
procedure :: print
procedure, non_overridable :: remove
end type
contains
!
! Create a new (orphaned) list item.
!
function newitem(something)
class(*), intent(in) :: something
class(anyitem), pointer :: newitem
allocate (newitem)
allocate (newitem%value, source=something)
newitem%prevptr => newitem
end function
!
! Append an item to a list.
!
subroutine append(list, item)
class(anylist), intent(inout), target :: list
class(anyitem), target :: item
class(anyitem), pointer :: last
if (associated(item%upptr)) call remove(item)
item%upptr => list
if (associated(list%firstptr)) then
last => list%firstptr%prevptr
last%nextptr => item
item%prevptr => last
list%firstptr%prevptr => item
else
list%firstptr => item
item%prevptr => item
end if
end subroutine
!
! Count how many items there are in a list.
!
integer function count_list(list)
class(anylist), intent(in) :: list
class(anyitem), pointer :: p
count_list = 0
p => list%firstptr
do
if (.not.associated(p)) exit
count_list = count_list + 1
p => p%nextptr
end do
end function
!
! Delete the contents of a list.
!
subroutine delete_list(list)
class(anylist), intent(inout) :: list
do
if (.not.associated(list%firstptr)) exit
call delete(list%firstptr)
end do
end subroutine
!
! Return the first element of a list.
!
function first(list)
class(anylist), intent(in) :: list
class(anyitem), pointer :: first
first => list%firstptr
end function
!
! Return the last element of a list
!
function last(list)
class(anylist), intent(in) :: list
class(anyitem), pointer :: last
last => list%firstptr
if (associated(last)) last => last%prevptr
end function
!
! Insert an item at the beginning of a list.
!
subroutine prepend(list, item)
class(anylist), intent(inout), target :: list
class(anyitem), target :: item
if (associated(item%upptr)) call remove(item)
item%upptr => list
if (associated(list%firstptr)) then
item%prevptr => list%firstptr%prevptr
item%nextptr => list%firstptr
list%firstptr%prevptr => item
else
item%prevptr => item
end if
list%firstptr => item
end subroutine
!
! Print the items in a list.
!
subroutine print_list(list, show_item_numbers, show_empty_list)
class(anylist), intent(in) :: list
logical, intent(in), optional :: show_item_numbers, show_empty_list
class(anyitem), pointer :: p
integer i
logical :: show_numbers
if (present(show_item_numbers)) then
show_numbers = show_item_numbers
else
show_numbers = .true.
end if
p => list%firstptr
if (.not.associated(p)) then
if (present(show_empty_list)) then
if (show_empty_list) print *, 'List is empty.'
else
print *, 'List is empty.'
end if
else
do i=1, huge(i)-1
if (show_numbers) write (*, 1, advance='no') i
1 format(1x, 'Item ', i0, ':')
call p%print
p => p%nextptr
if (.not.associated(p)) exit
end do
end if
end subroutine
!
! Change the value of an item.
!
subroutine change(item, newvalue)
class(anyitem), intent(inout) :: item
class(*), intent(in) :: newvalue
deallocate (item%value)
allocate (item%value, source=newvalue)
end subroutine
!
! Delete an item: removes it from the list and deallocates it.
!
subroutine delete(item)
class(anyitem), target :: item
class(anyitem), pointer :: temp
temp => item
call remove(item)
deallocate (temp)
end subroutine
!
! Return the list that an item is a member of. Null if an orphan.
!
function list(item)
class(anyitem), intent(in) :: item
class(anylist), pointer :: list
list => item%upptr
end function
!
! Return the next item in the list.
!
function next(item)
class(anyitem), intent(in) :: item
class(anyitem), pointer :: next
next => item%nextptr
end function
!
! Return the previous item in the list,
! or the last item if this one is the first.
!
function prev(item)
class(anyitem), intent(in) :: item
class(anyitem), pointer :: prev
prev => item%prevptr
end function
!
! Print an item. This is overridable.
!
subroutine print(this)
class(anyitem), intent(in) :: this
integer length
select type (v=>this%value)
type is (character(*))
length = len(v)
if (length>40) then
print 1, length, v(:36)
1 format(1x, 'character(len=', i0, ') = "', a, '"...')
else
print *, 'character = "', v, '"'
end if
type is (complex)
print *, 'complex', v
type is (complex(kind(0d0)))
print 2, kind(v), v
2 format(1x, 'complex(kind=', i0, ') = (', es23.16, ', ', es23.16, ')')
type is (real(kind(0d0)))
print 3, kind(v), v
3 format(1x, 'real(kind=', i0, ') = ', es23.16)
type is (integer)
print *, 'integer = ', v
type is (real)
print *, 'real = ', v
type is (logical)
print *, 'logical = ', v
class default
print *, 'unrecognised item type - cannot display value'
end select
end subroutine
!
! Remove an item from a list (but keep it and its value).
!
subroutine remove(item)
class(anyitem), intent(inout), target :: item
class(anylist), pointer :: list
list => item%upptr
if (associated(list)) then
if (associated(item%prevptr, item)) then
! Single item in list.
nullify(list%firstptr)
else if (.not.associated(item%nextptr)) then
! Last item in list.
list%firstptr%prevptr => item%prevptr
nullify(item%prevptr%nextptr)
else if (associated(list%firstptr, item)) then
! First item in list.
list%firstptr => item%nextptr ! first = next.
item%prevptr%prevptr => item%nextptr ! last%prev = item%next.
item%nextptr%prevptr => item%prevptr ! next%prev = last.
else
item%prevptr%nextptr => item%nextptr ! last%next = item%next.
item%nextptr%prevptr => item%prevptr ! next%prev = item%last.
end if
item%prevptr => item
end if
nullify(item%upptr)
end subroutine
end module
!
! Module to demonstrate extending anyitem to handle a user-defined type.
!
module myitem_list_m
use anylist_m
implicit none
type, extends(anyitem) :: myitem
contains
procedure :: print => myprint
end type
type rational
integer :: numerator = 0
integer :: denominator = 1
end type
contains
!
! Version of print that will handle type rational.
!
subroutine myprint(this)
class(myitem), intent(in) :: this
select type (v=>this%value)
class is (rational)
print *, 'rational =', v%numerator, '/', v%denominator
class default
call this%anyitem%print
end select
end subroutine
function new_myitem(anything)
class(*), intent(in) :: anything
class(myitem), pointer :: new_myitem
allocate (new_myitem)
allocate (new_myitem%value, source=anything)
end function
end module
!
! Demonstration program.
!
program demonstration
use myitem_list_m
implicit none
type(anylist) :: list
class(anyitem), pointer :: p
!
! First demonstrate the most basic workings of a list.
print *, 'The initial list has', list%count_list(), 'items.'
call list%append(newitem(17))
print *, 'The list now has', list%count_list(), 'items.'
call list%append(newitem('world'))
print *, 'The list now has', list%count_list(), 'items.'
call list%prepend(newitem('hello'))
print *, 'The list now has', list%count_list(), 'items.'
call list%append(newitem(2.25))
print *, 'The list now has', list%count_list(), 'items.'
write (*, '(1x, a)', advance='no') 'The first element is: '
p => list%first()
call p%print
write (*, '(1x, a)', advance='no') 'The last element is: '
p => list%last()
call p%print
print *, 'After deleting the last element, the list contents are:'
call p%delete
call list%print_list
!
! Now delete the old list and make a new one,
! with some values from myitem_list_m.
!
call list%delete_list
call list%append(new_myitem('The next value is one third.'))
call list%append(new_myitem(rational(1,3)))
call list%append(new_myitem('Where did this number come from?'))
call list%append(new_myitem(rational(173,13)))
print *, 'The contents of our new list are:'
call list%print_list
!
! Now test some of the other procedures, just to prove they work.
!
p => list%first()
p => p%prev() ! Test prev(), this will be the last item.
call p%remove ! Remove the last item.
call list%prepend(p) ! Put it back, at the beginning of the list.
p => p%next() ! Test next(), this will be the second item,
! the one with the string "...third.".
call p%change((0,1)) ! Replace it with a complex number.
print *, 'Revised list contents:'
call list%print_list
call list%prepend(p) ! Move new item to top
print *, 'Afer moving item 2 to top, list contents:'
call list%print_list
end program