MODFLOW 6  version 6.5.0.dev2
MODFLOW 6 Code Documentation
List.f90
Go to the documentation of this file.
1 module listmodule
2  use kindmodule, only: dp, i4b
3  use errorutilmodule, only: pstop
4  use constantsmodule, only: linelength
5  implicit none
6  private
7  public :: listtype, listnodetype, isequaliface
8 
9  !> @brief A generic heterogeneous doubly-linked list.
10  type :: listtype
11  ! -- Public members
12  type(listnodetype), pointer, public :: firstnode => null()
13  character(len=20), public :: name = ' '
14  ! -- Private members
15  type(listnodetype), pointer, private :: lastnode => null()
16  type(listnodetype), pointer, private :: currentnode => null()
17  integer(I4B), private :: currentnodeindex = 0
18  integer(I4B), private :: nodecount = 0
19  contains
20  ! -- Public procedures
21  procedure, public :: add
22  procedure, public :: clear
23  procedure, public :: count
24  procedure, public :: containsobject
25  procedure, public :: deallocatebackward
26  procedure, public :: getindex
27  procedure, public :: getnextitem
28  procedure, public :: getpreviousitem
30  procedure, public :: insertafter
31  procedure, public :: insertbefore
32  procedure, public :: next
33  procedure, public :: previous
34  procedure, public :: reset
35  generic, public :: removenode => remove_node_by_index, remove_this_node
36  ! -- Private procedures
37  procedure, private :: get_current_item
38  procedure, private :: get_item_by_index
39  procedure, private :: get_node_by_index
40  procedure, private :: remove_node_by_index
41  procedure, private :: remove_this_node
42  ! Finalization is not supported in gfortran (as of 4.10.0)
43  !final :: clear_list
44  end type listtype
45 
46  type :: listnodetype
47  ! -- Public members
48  type(listnodetype), pointer, public :: nextnode => null()
49  type(listnodetype), pointer, public :: prevnode => null()
50  ! -- Private members
51  class(*), pointer, private :: Value => null()
52  contains
53  ! -- Public procedure
54  procedure, public :: getitem
55  ! -- Private procedures
56  procedure, private :: deallocvalue
57  end type listnodetype
58 
59  interface
60  function isequaliface(obj1, obj2) result(isEqual)
61  class(*), pointer :: obj1, obj2
62  logical :: isequal
63  end function
64  end interface
65 
66 contains
67 
68  !> @brief Append the given item to the list
69  subroutine add(this, objptr)
70  ! -- dummy variables
71  class(listtype), intent(inout) :: this
72  class(*), pointer, intent(inout) :: objptr
73  !
74  if (.not. associated(this%firstNode)) then
75  allocate (this%firstNode)
76  this%firstNode%Value => objptr
77  this%firstNode%prevNode => null()
78  this%lastNode => this%firstNode
79  else
80  allocate (this%lastNode%nextNode)
81  this%lastNode%nextNode%prevNode => this%lastNode
82  this%lastNode%nextNode%value => objptr
83  this%lastNode => this%lastNode%nextNode
84  end if
85  this%nodeCount = this%nodeCount + 1
86  end subroutine add
87 
88  !> @brief Deallocate all items in list
89  subroutine clear(this, destroy)
90  ! -- dummy variables
91  class(listtype) :: this
92  logical, intent(in), optional :: destroy
93  ! -- local
94  logical :: destroyLocal
95  type(listnodetype), pointer :: current => null()
96  type(listnodetype), pointer :: next => null()
97  !
98  destroylocal = .false.
99  if (present(destroy)) then
100  destroylocal = destroy
101  end if
102  !
103  if (.not. associated(this%firstNode)) return
104  ! -- The last node will be deallocated in the loop below.
105  ! Just nullify the pointer to the last node to avoid
106  ! having a dangling pointer. Also nullify currentNode.
107  nullify (this%lastNode)
108  nullify (this%currentNode)
109  !
110  current => this%firstNode
111  do while (associated(current))
112  ! -- Assign a pointer to the next node in the list
113  next => current%nextNode
114  ! -- Deallocate the object stored in the current node
115  call current%DeallocValue(destroylocal)
116  ! -- Deallocate the current node
117  deallocate (current)
118  this%firstNode => next
119  this%nodeCount = this%nodeCount - 1
120  ! -- Advance to the next node
121  current => next
122  end do
123  !
124  call this%Reset()
125 
126  end subroutine clear
127 
128  !> @brief Return number of nodes in list
129  function count(this)
130  integer(I4B) :: count
131  class(listtype) :: this
132  count = this%nodeCount
133  end function count
134 
135  !> @brief Determine whether the list contains the given object.
136  function containsobject(this, obj, isEqual) result(hasObj)
137  class(listtype), intent(inout) :: this
138  class(*), pointer :: obj
139  procedure(isequaliface), pointer, intent(in), optional :: isequal
140  logical :: hasobj
141  ! local
142  type(listnodetype), pointer :: current => null()
143 
144  hasobj = .false.
145  current => this%firstNode
146  do while (associated(current))
147  if (present(isequal)) then
148  if (isequal(current%Value, obj)) then
149  hasobj = .true.
150  return
151  end if
152  else
153  if (associated(current%Value, obj)) then
154  hasobj = .true.
155  return
156  end if
157  end if
158 
159  ! -- Advance to the next node
160  current => current%nextNode
161  end do
162 
163  end function
164 
165  !> @brief Deallocate fromNode and all previous nodes, and reassign firstNode.
166  subroutine deallocatebackward(this, fromNode)
167  ! -- dummy
168  class(listtype), target, intent(inout) :: this
169  type(listnodetype), pointer, intent(inout) :: fromNode
170  ! -- local
171  type(listnodetype), pointer :: current => null()
172  type(listnodetype), pointer :: prev => null()
173  !
174  if (associated(fromnode)) then
175  ! -- reassign firstNode
176  if (associated(fromnode%nextNode)) then
177  this%firstNode => fromnode%nextNode
178  else
179  this%firstNode => null()
180  end if
181  ! -- deallocate fromNode and all previous nodes
182  current => fromnode
183  do while (associated(current))
184  prev => current%prevNode
185  call current%DeallocValue(.true.)
186  deallocate (current)
187  this%nodeCount = this%nodeCount - 1
188  current => prev
189  end do
190  fromnode => null()
191  end if
192 
193  end subroutine deallocatebackward
194 
195  !> @brief Get the index of the given item in the list.
196  function getindex(this, obj) result(idx)
197  class(listtype), target, intent(inout) :: this
198  class(*), pointer :: obj
199  integer(I4B) :: idx
200  ! local
201  integer(I4B) :: i
202  class(*), pointer :: obj_in_list
203 
204  idx = -1
205  do i = 1, this%Count()
206  obj_in_list => this%GetItem(i)
207  if (associated(obj, obj_in_list)) then
208  idx = i
209  exit
210  end if
211  end do
212 
213  end function getindex
214 
215  !> @brief Get the next item in the list
216  function getnextitem(this) result(resultobj)
217  class(listtype), target, intent(inout) :: this
218  class(*), pointer :: resultobj
219  call this%Next()
220  resultobj => this%get_current_item()
221  end function getnextitem
222 
223  !> @brief Get the previous item in the list
224  function getpreviousitem(this) result(resultobj)
225  class(listtype), target, intent(inout) :: this
226  class(*), pointer :: resultobj
227  call this%Previous()
228  resultobj => this%get_current_item()
229  end function getpreviousitem
230 
231  !> @brief Insert the given item after the given index.
232  subroutine insertafter(this, objptr, indx)
233  ! -- dummy
234  class(listtype), intent(inout) :: this
235  class(*), pointer, intent(inout) :: objptr
236  integer(I4B), intent(in) :: indx
237  ! -- local
238  integer(I4B) :: numnodes
239  type(listnodetype), pointer :: precedingNode => null()
240  type(listnodetype), pointer :: followingNode => null()
241  type(listnodetype), pointer :: newNode => null()
242  !
243  numnodes = this%Count()
244  if (indx >= numnodes) then
245  call this%Add(objptr)
246  else
247  precedingnode => this%get_node_by_index(indx)
248  if (associated(precedingnode%nextNode)) then
249  followingnode => precedingnode%nextNode
250  allocate (newnode)
251  newnode%Value => objptr
252  newnode%nextNode => followingnode
253  newnode%prevNode => precedingnode
254  precedingnode%nextNode => newnode
255  followingnode%prevNode => newnode
256  this%nodeCount = this%nodeCount + 1
257  else
258  call pstop(1, 'Programming error in ListType%insert_after')
259  end if
260  end if
261 
262  end subroutine insertafter
263 
264  !> @brief Insert the given item before the given node.
265  subroutine insertbefore(this, objptr, targetNode)
266  ! -- dummy
267  class(listtype), intent(inout) :: this
268  class(*), pointer, intent(inout) :: objptr
269  type(listnodetype), pointer, intent(inout) :: targetNode
270  ! -- local
271  type(listnodetype), pointer :: newNode => null()
272  !
273  if (.not. associated(targetnode)) &
274  call pstop(1, 'Programming error in ListType%InsertBefore')
275  !
276  ! Allocate a new list node and point its Value member to the object
277  allocate (newnode)
278  newnode%Value => objptr
279  !
280  ! Do the insertion
281  newnode%nextNode => targetnode
282  if (associated(targetnode%prevNode)) then
283  ! Insert between two nodes
284  targetnode%prevNode%nextNode => newnode
285  newnode%prevNode => targetnode%prevNode
286  else
287  ! Insert before first node
288  this%firstNode => newnode
289  newnode%prevNode => null()
290  end if
291  targetnode%prevNode => newnode
292  this%nodeCount = this%nodeCount + 1
293 
294  end subroutine insertbefore
295 
296  !> @brief Move the list's current node pointer and index one node forwards.
297  subroutine next(this)
298  class(listtype), target, intent(inout) :: this
299 
300  if (this%currentNodeIndex == 0) then
301  if (associated(this%firstNode)) then
302  this%currentNode => this%firstNode
303  this%currentNodeIndex = 1
304  else
305  this%currentNode => null()
306  this%currentNodeIndex = 0
307  end if
308  else
309  if (associated(this%currentNode%nextNode)) then
310  this%currentNode => this%currentNode%nextNode
311  this%currentNodeIndex = this%currentNodeIndex + 1
312  else
313  this%currentNode => null()
314  this%currentNodeIndex = 0
315  end if
316  end if
317  end subroutine next
318 
319  !> @brief Move the list's current node pointer and index one node backwards.
320  subroutine previous(this)
321  class(listtype), target, intent(inout) :: this
322  if (this%currentNodeIndex <= 1) then
323  call this%Reset()
324  else
325  this%currentNode => this%currentNode%prevNode
326  this%currentNodeIndex = this%currentNodeIndex - 1
327  end if
328  end subroutine previous
329 
330  !> @brief Reset the list's current node pointer and index.
331  subroutine reset(this)
332  class(listtype), target, intent(inout) :: this
333  this%currentNode => null()
334  this%currentNodeIndex = 0
335  end subroutine reset
336 
337  !> @brief Remove the node at the given index, optionally destroying its value.
338  subroutine remove_node_by_index(this, i, destroyValue)
339  ! -- dummy
340  class(listtype), intent(inout) :: this
341  integer(I4B), intent(in) :: i
342  logical, intent(in) :: destroyValue
343  ! -- local
344  type(listnodetype), pointer :: node
345  !
346  node => null()
347  node => this%get_node_by_index(i)
348  if (associated(node)) then
349  call this%remove_this_node(node, destroyvalue)
350  end if
351 
352  end subroutine remove_node_by_index
353 
354  !> @brief Remove the given node, optionally destroying its value.
355  subroutine remove_this_node(this, node, destroyValue)
356  ! -- dummy
357  class(listtype), intent(inout) :: this
358  type(listnodetype), pointer, intent(inout) :: node
359  logical, intent(in) :: destroyValue
360  ! -- local
361  !
362  logical :: first, last
363  !
364  first = .false.
365  last = .false.
366  if (associated(node)) then
367  if (associated(node%prevNode)) then
368  if (associated(node%nextNode)) then
369  node%nextNode%prevNode => node%prevNode
370  else
371  node%prevNode%nextNode => null()
372  this%lastNode => node%prevNode
373  end if
374  else
375  first = .true.
376  end if
377  if (associated(node%nextNode)) then
378  if (associated(node%prevNode)) then
379  node%prevNode%nextNode => node%nextNode
380  else
381  node%nextNode%prevNode => null()
382  this%firstNode => node%nextNode
383  end if
384  else
385  last = .true.
386  end if
387  if (destroyvalue) then
388  call node%DeallocValue(destroyvalue)
389  end if
390  deallocate (node)
391  this%nodeCount = this%nodeCount - 1
392  if (first .and. last) then
393  this%firstNode => null()
394  this%lastNode => null()
395  this%currentNode => null()
396  end if
397  call this%Reset()
398  end if
399 
400  end subroutine remove_this_node
401 
402  ! -- Private type-bound procedures for ListType
403 
404  !> @brief Get a pointer to the item at the current node.
405  function get_current_item(this) result(resultobj)
406  class(listtype), target, intent(inout) :: this
407  ! result
408  class(*), pointer :: resultobj
409  !
410  resultobj => null()
411  if (associated(this%currentNode)) then
412  resultobj => this%currentNode%Value
413  end if
414  end function get_current_item
415 
416  !> @brief Get a pointer to the item at the given index.
417  function get_item_by_index(this, indx) result(resultobj)
418  ! -- dummy
419  class(listtype), intent(inout) :: this
420  integer(I4B), intent(in) :: indx
421  ! result
422  class(*), pointer :: resultobj
423  ! -- local
424  integer(I4B) :: i
425  !
426  ! -- Initialize
427  resultobj => null()
428  !
429  ! -- Ensure that this%currentNode is associated
430  if (.not. associated(this%currentNode)) then
431  this%currentNodeIndex = 0
432  end if
433  if (this%currentNodeIndex == 0) then
434  if (associated(this%firstNode)) then
435  this%currentNode => this%firstNode
436  this%currentNodeIndex = 1
437  end if
438  end if
439  !
440  ! -- Check indx position relative to current node index
441  i = 0
442  if (indx < this%currentNodeIndex) then
443  ! Start at beginning of list
444  call this%Reset()
445  if (associated(this%firstNode)) then
446  this%currentNode => this%firstNode
447  this%currentNodeIndex = 1
448  i = 1
449  end if
450  else
451  i = this%currentNodeIndex
452  end if
453  if (i == 0) return
454  !
455  ! -- If current node is requested node,
456  ! assign pointer and return
457  if (i == indx) then
458  resultobj => this%currentNode%Value
459  return
460  end if
461  !
462  ! -- Iterate from current node to requested node
463  do while (associated(this%currentNode%nextNode))
464  this%currentNode => this%currentNode%nextNode
465  this%currentNodeIndex = this%currentNodeIndex + 1
466  if (this%currentNodeIndex == indx) then
467  resultobj => this%currentNode%Value
468  return
469  end if
470  end do
471  end function get_item_by_index
472 
473  !> @brief Get the node at the given index
474  function get_node_by_index(this, indx) result(resultnode)
475  ! -- dummy
476  class(listtype), intent(inout) :: this
477  integer(I4B), intent(in) :: indx
478  ! result
479  type(listnodetype), pointer :: resultnode
480  ! -- local
481  integer(I4B) :: i
482  !
483  ! -- Initialize
484  resultnode => null()
485  !
486  ! -- Ensure that this%currentNode is associated
487  if (this%currentNodeIndex == 0) then
488  if (associated(this%firstNode)) then
489  this%currentNode => this%firstNode
490  this%currentNodeIndex = 1
491  end if
492  end if
493  !
494  ! -- Check indx position relative to current node index
495  i = 0
496  if (indx < this%currentNodeIndex) then
497  ! Start at beginning of list
498  call this%Reset()
499  if (associated(this%firstNode)) then
500  this%currentNode => this%firstNode
501  this%currentNodeIndex = 1
502  i = 1
503  end if
504  else
505  i = this%currentNodeIndex
506  end if
507  if (i == 0) return
508  !
509  ! -- If current node is requested node,
510  ! assign pointer and return
511  if (i == indx) then
512  resultnode => this%currentNode
513  return
514  end if
515  !
516  ! -- Iterate from current node to requested node
517  do while (associated(this%currentNode%nextNode))
518  this%currentNode => this%currentNode%nextNode
519  this%currentNodeIndex = this%currentNodeIndex + 1
520  if (this%currentNodeIndex == indx) then
521  resultnode => this%currentNode
522  return
523  end if
524  end do
525  end function get_node_by_index
526 
527  ! -- Type-bound procedures for ListNodeType
528 
529  !> @brief Return a pointer to this node's value.
530  function getitem(this) result(valueObject)
531  class(listnodetype), intent(inout) :: this
532  class(*), pointer :: valueobject
533  valueobject => this%Value
534  end function getitem
535 
536  !> @brief Nullify (optionally deallocating) this node's value.
537  subroutine deallocvalue(this, destroy)
538  class(listnodetype), intent(inout) :: this
539  logical, intent(in), optional :: destroy
540 
541  if (associated(this%Value)) then
542  if (present(destroy)) then
543  if (destroy) then
544  deallocate (this%Value)
545  end if
546  end if
547  nullify (this%Value)
548  end if
549  end subroutine deallocvalue
550 
551 end module listmodule
This module contains simulation constants.
Definition: Constants.f90:9
integer(i4b), parameter linelength
maximum length of a standard line
Definition: Constants.f90:44
subroutine pstop(status, message)
Stop the program, optionally specifying an error status code.
Definition: ErrorUtil.f90:24
This module defines variable data types.
Definition: kind.f90:8
subroutine deallocvalue(this, destroy)
Nullify (optionally deallocating) this node's value.
Definition: List.f90:538
integer(i4b) function count(this)
Return number of nodes in list.
Definition: List.f90:130
subroutine insertbefore(this, objptr, targetNode)
Insert the given item before the given node.
Definition: List.f90:266
subroutine remove_node_by_index(this, i, destroyValue)
Remove the node at the given index, optionally destroying its value.
Definition: List.f90:339
subroutine reset(this)
Reset the list's current node pointer and index.
Definition: List.f90:332
class(*) function, pointer getitem(this)
Return a pointer to this node's value.
Definition: List.f90:531
class(*) function, pointer getpreviousitem(this)
Get the previous item in the list.
Definition: List.f90:225
class(*) function, pointer get_item_by_index(this, indx)
Get a pointer to the item at the given index.
Definition: List.f90:418
logical function containsobject(this, obj, isEqual)
Determine whether the list contains the given object.
Definition: List.f90:137
subroutine add(this, objptr)
Append the given item to the list.
Definition: List.f90:70
subroutine clear(this, destroy)
Deallocate all items in list.
Definition: List.f90:90
class(*) function, pointer get_current_item(this)
Get a pointer to the item at the current node.
Definition: List.f90:406
subroutine previous(this)
Move the list's current node pointer and index one node backwards.
Definition: List.f90:321
subroutine next(this)
Move the list's current node pointer and index one node forwards.
Definition: List.f90:298
integer(i4b) function getindex(this, obj)
Get the index of the given item in the list.
Definition: List.f90:197
class(*) function, pointer getnextitem(this)
Get the next item in the list.
Definition: List.f90:217
subroutine deallocatebackward(this, fromNode)
Deallocate fromNode and all previous nodes, and reassign firstNode.
Definition: List.f90:167
type(listnodetype) function, pointer get_node_by_index(this, indx)
Get the node at the given index.
Definition: List.f90:475
subroutine remove_this_node(this, node, destroyValue)
Remove the given node, optionally destroying its value.
Definition: List.f90:356
subroutine insertafter(this, objptr, indx)
Insert the given item after the given index.
Definition: List.f90:233
A generic heterogeneous doubly-linked list.
Definition: List.f90:10