FE-Project
Loading...
Searching...
No Matches
scale_linkedlist.F90
Go to the documentation of this file.
1
10#include "scaleFElib.h"
12 !-----------------------------------------------------------------------------
13 !
14 !++ Used modules
15 !
16 use scale_precision
17 use scale_io
18
19 !-----------------------------------------------------------------------------
20 implicit none
21 private
22 !-----------------------------------------------------------------------------
23 !
24 !++ Public type & procedures
25 !
26
27 !---
28 type, abstract, public :: linkedlistkey
29 contains
30 procedure(key_equal_func), private, deferred :: key_equal
31 generic, public :: operator(==) => key_equal
32 end type linkedlistkey
33
34 abstract interface
35 pure elemental logical function key_equal_func( item1, item2 )
36 import linkedlistkey
37 class(linkedlistkey), intent(in) :: item1
38 class(linkedlistkey), intent(in) :: item2
39 end function key_equal_func
40 end interface
41
42 !---
43 type :: node
44 private
45 class(*), allocatable :: key
46 class(*), pointer :: value => null()
47 logical :: destroy_on_delete
48 type(node), pointer :: next => null()
49 type(node), pointer :: previous => null()
50 contains
51 procedure, public :: init => node_init
52 procedure, public :: final => node_final
53 procedure, public :: getdata => node_get_data
54 end type
55
56
57 type, public :: linkedlist
58 type(node), pointer, private :: head
59 type(node), pointer, private :: tail
60 integer, private :: counter
61 contains
62 procedure, public :: init => linkedlist_init
63 procedure, public :: final => linkedlist_final
64 procedure, public :: addbypointer => linkedlist_add_by_pointer
65 procedure, public :: removebypointer => linkedlist_remove_by_pointer
66 procedure, public :: remove => linkedlist_remove_by_key
67 procedure, public :: addbyclone => linkedlist_add_by_clone
68 procedure, public :: getnode => linkedlist_get_node
69 procedure, public :: get => linkedlist_get_data
70 procedure, public :: traverselist => linkedlist_traverse_list
71 procedure, public :: traverse => linkedlist_traverse
72
73 procedure, private :: keysequal => linkedlist_keys_eqaul
74 end type
75
76 !-----------------------------------------------------------------------------
77 !
78 !++ Public parameters & variables
79 !
80
81 !-----------------------------------------------------------------------------
82 !
83 !++ Private procedures & variables
84 !
85 !------------------
86
87 abstract interface
88 subroutine iterator_func(this, done)
89 import :: node
90 implicit none
91 type(node), pointer :: this
92 logical, intent(out) :: done
93 end subroutine iterator_func
94
95 subroutine key_iterator(key, value, done)
96 implicit none
97 class(*), intent(in) :: key
98 class(*), pointer :: value
99 logical, intent(out) :: done
100 end subroutine key_iterator
101 end interface
102
103contains
104 subroutine node_init( this, key, value, previous_node, destroy_on_delete )
105 implicit none
106 class(node) :: this
107 class(*), intent(in) :: key
108 class(*), pointer, intent(in) :: value
109 type(node), pointer :: previous_node
110 logical, intent(in) :: destroy_on_delete
111 !---------------------------------------------
112
113 allocate( this%key, source=key )
114 this%value => value
115 this%previous => previous_node
116 this%destroy_on_delete = destroy_on_delete
117
118 return
119 end subroutine node_init
120
121 subroutine node_final( this )
122 implicit none
123 class(node), intent(inout) :: this
124 !---------------------------------------------
125
126 if( allocated( this%key ) ) deallocate( this%key )
127 if ( this%destroy_on_delete ) then
128 if (associated( this%value) ) deallocate( this%value )
129 end if
130
131 return
132 end subroutine node_final
133
134 subroutine node_get_data( this, value )
135 implicit none
136 class(node) :: this
137 class(*), pointer, intent(out) :: value
138 !---------------------------------------------
139
140 if ( associated(this%value) )then
141 value => this%value
142 else
143 log_error(" Node_get_data",*) "The pointer into data of node is not associated. Check!"
144 end if
145
146 return
147 end subroutine node_get_data
148
149 !-------------------------------------------------------
150
151 subroutine linkedlist_init( this )
152 implicit none
153 class(linkedlist), intent(inout) :: this
154 !---------------------------------------------
155
156 this%counter = 0
157 nullify( this%head, this%tail )
158
159 return
160 end subroutine linkedlist_init
161
162 subroutine linkedlist_final( this )
163 implicit none
164 class(linkedlist), intent(inout) :: this
165 !---------------------------------------------
166
167 this%counter = 0
168 if ( associated(this%head) ) call destroy_subsequent_nodes( this%head )
169
170 return
171 end subroutine linkedlist_final
172
173 recursive subroutine destroy_subsequent_nodes( this_node )
174 implicit none
175 type(node), pointer, intent(inout) :: this_node
176
177 !---------------------------------------------
178 if ( associated(this_node) ) then
179 call this_node%Final()
180 call destroy_subsequent_nodes( this_node%next )
181 nullify( this_node%previous )
182 deallocate( this_node )
183 nullify( this_node )
184 end if
185
186 return
187 end subroutine destroy_subsequent_nodes
188
189
190 function linkedlist_has_key( this, key ) result(has_key)
191 implicit none
192 class(linkedlist), intent(inout) :: this
193 class(*), intent(in) :: key
194 logical :: has_key
195 !---------------------------------------------
196
197 has_key = .false.
198 call this%TraverseList( key_search )
199 return
200 contains
201 subroutine key_search(ptr, done)
202 implicit none
203 type(node), pointer :: ptr
204 logical, intent(out) :: done
205 !-------------------------------------------------
206 has_key = this%keysEqual(ptr%key, key)
207 done = has_key
208 return
209 end subroutine key_search
210 end function linkedlist_has_key
211
212 subroutine linkedlist_traverse_list( &
213 this, iterator )
214
215 implicit none
216 class(linkedlist), intent(inout) :: this
217 procedure(iterator_func) :: iterator
218
219 type(node), pointer :: ptr
220 logical :: done
221 !----------------------------------------------------
222
223 done = .false.
224 ptr => this%head
225
226 do
227 if (associated(ptr)) then
228 call iterator( ptr, done )
229 if (done) exit
230 ptr => ptr%next
231 else
232 exit
233 end if
234 end do
235
236 return
237 end subroutine linkedlist_traverse_list
238
239 subroutine linkedlist_traverse( &
240 this, iterator )
241
242 implicit none
243 class(linkedlist), intent(inout) :: this
244 procedure(key_iterator) :: iterator
245
246 !----------------------------------------------------
247
248 call this%TraverseList( key_iterator_wrapper )
249 return
250
251 contains
252 subroutine key_iterator_wrapper( this_node, done )
253 implicit none
254 type(node), pointer :: this_node
255 logical, intent(out) :: done
256 !----------------------------------------------------
257
258 call iterator( this_node%key, this_node%value, done )
259 return
260 end subroutine key_iterator_wrapper
261
262 end subroutine linkedlist_traverse
263
264 subroutine linkedlist_add_by_pointer( &
265 this, key, value, destroy_on_delete )
266
267 implicit none
268 class(linkedlist), intent(inout) :: this
269 class(*), intent(in) :: key
270 class(*), pointer, intent(in) :: value
271 logical, intent(in), optional :: destroy_on_delete
272
273 type(node), pointer :: pNode
274 logical :: destroy_on_delete_ = .false.
275 !---------------------------------------------
276
277 select type (key)
278 type is (integer)
279 type is (character(len=*))
280! class is (LinkedListKey)
281 class default
282 log_error("LinkedList_add_by_pointer",*) "The type of key is invalid. Check!"
283 end select
284
285 call this%GetNode( key, pnode )
286 if ( associated(pnode) ) call this%RemoveByPointer( pnode )
287
288 allocate( pnode )
289 if (present(destroy_on_delete)) then
290 destroy_on_delete_ = destroy_on_delete
291 end if
292 call pnode%Init( key, value, this%tail, destroy_on_delete_ )
293
294 if ( associated(this%tail) ) then
295 this%tail%next => pnode
296 else
297 this%head => pnode
298 end if
299 this%tail => pnode
300 this%counter = this%counter + 1
301
302 return
303 end subroutine linkedlist_add_by_pointer
304
305 subroutine linkedlist_add_by_clone( this, key, value )
306 implicit none
307 class(linkedlist), intent(inout) :: this
308 class(*), intent(in) :: key
309 class(*), intent(in) :: value
310
311 class(*), pointer :: ptr_value
312 !---------------------------------------------
313
314 allocate(ptr_value, source=value)
315 call this%AddByPointer( key, ptr_value, destroy_on_delete=.true. )
316
317 return
318 end subroutine linkedlist_add_by_clone
319
320 subroutine linkedlist_remove_by_key( this, key )
321 implicit none
322 class(linkedlist), intent(inout) :: this
323 class(*), intent(in) :: key
324
325 type(node), pointer :: pNode
326 !---------------------------------------------
327
328 call this%GetNode( key, pnode )
329 call this%RemoveByPointer( pnode )
330
331 return
332 end subroutine linkedlist_remove_by_key
333
334 subroutine linkedlist_remove_by_pointer( this, pNode )
335 implicit none
336 class(linkedlist), intent(inout) :: this
337 type(node), pointer :: pNode
338
339 logical :: has_next
340 logical :: has_previous
341 !---------------------------------------------
342
343 if ( associated(pnode) ) then
344 has_next = associated( pnode%next )
345 has_previous = associated( pnode%previous )
346
347 if ( has_next .and. has_previous ) then
348 pnode%previous%next => pnode%next
349 pnode%next%previous => pnode%previous
350 else if ( has_next .and. .not. has_previous ) then
351 this%head => pnode%next
352 nullify( this%head%previous )
353 else if ( .not. has_next .and. has_previous ) then
354 this%tail => pnode%previous
355 nullify( this%tail%next )
356 else if ( .not. (has_next .or. has_previous) ) then
357 nullify( this%head, this%tail )
358 end if
359
360 call pnode%Final()
361 deallocate( pnode )
362 nullify( pnode )
363
364 this%counter = this%counter - 1
365 end if
366
367 return
368 end subroutine linkedlist_remove_by_pointer
369
370 subroutine linkedlist_get_node( this, key, ptr_node )
371 implicit none
372 class(linkedlist), intent(in) :: this
373 class(*), intent(in) :: key
374 type(node), pointer, intent(out) :: ptr_node
375
376 type(node), pointer :: ptr
377 !---------------------------------------------
378
379 nullify( ptr_node )
380
381 ptr => this%head
382 do
383 if ( associated(ptr) ) then
384 if (this%keysEqual(ptr%key, key)) then
385 ptr_node => ptr
386 return
387 end if
388 ptr => ptr%next
389 else
390 return
391 end if
392 end do
393
394 end subroutine linkedlist_get_node
395
396 subroutine linkedlist_get_data( this, key, ptr_value )
397 implicit none
398 class(linkedlist), intent(in) :: this
399 class(*), intent(in) :: key
400 class(*), pointer, intent(out) :: ptr_value
401
402 type(node), pointer :: ptr
403 !---------------------------------------------
404
405 call this%GetNode( key, ptr )
406 if ( associated(ptr) ) then
407 ptr_value => ptr%value
408 else
409 nullify( ptr_value )
410 end if
411
412 return
413 end subroutine linkedlist_get_data
414
415 function linkedlist_keys_eqaul( this, key1, key2 ) result(is_keys_eqaul)
416 implicit none
417 class(linkedlist), intent(in) :: this
418 class(*), intent(in) :: key1
419 class(*), intent(in) :: key2
420 logical :: is_keys_eqaul
421
422 !---------------------------------------------
423
424 is_keys_eqaul = .false.
425
426 if ( same_type_as(key1, key2) ) then
427 select type (key1)
428 type is (integer)
429 select type(key2)
430 type is (integer)
431 is_keys_eqaul = (key1 == key2)
432 end select
433 type is (character(len=*))
434 select type(key2)
435 type is (character(len=*))
436 is_keys_eqaul = (key1 == key2)
437 end select
438 ! class is (LinkedListKey)
439 ! select type(key2)
440 ! class is (LinkedListKey)
441 ! is_keys_eqaul = (key1 == key2)
442 ! end select
443 end select
444 end if
445
446 return
447 end function linkedlist_keys_eqaul
448
449end module scale_linkedlist
module common / data collection