FMUTIL  0.1
Fortran Miscellaneous UTILities
list.f90
Go to the documentation of this file.
1 !##############################################################################
2 ! ________ _____ ______________
3 ! / ____/ |/ / / / /_ __/ _/ /
4 ! / /_ / /|_/ / / / / / / / // /
5 ! / __/ / / / / /_/ / / / _/ // /___
6 ! /_/ /_/ /_/\____/ /_/ /___/_____/
7 !
8 ! Copyright 2020 Bharat Mahajan
9 !
10 ! Licensed under the Apache License, Version 2.0 (the "License");
11 ! you may not use this file except in compliance with the License.
12 ! You may obtain a copy of the License at
13 !
14 ! http://www.apache.org/licenses/LICENSE-2.0
15 !
16 ! Unless required by applicable law or agreed to in writing, software
17 ! distributed under the License is distributed on an "AS IS" BASIS,
18 ! WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19 ! See the License for the specific language governing permissions and
20 ! limitations under the License.
21 !
27 !
28 !##############################################################################
29 
30 
31 module lists
32 
33  use fmutilbase
34 
35  implicit none
36 
37  private
38 
40  integer, parameter :: default_newslotsallocated = 5
41 
43  type, private :: listitem
44  private
46  logical :: valid = .false.
48  class(*), pointer :: item
49  contains
50  private
52  procedure :: add_listitem
54  procedure :: del_listitem
56  procedure :: isvalid_listitem
57  end type listitem
58 
59 
60 
62  type, public :: list
63 
64  private
65 
67  integer, public :: status = 0
68 
70  integer :: usedslots = 0
71 
73  integer :: allocatedslots = 0
74 
76  integer :: newslotstoallocate = default_newslotsallocated
77 
79  type(listitem), dimension(:), allocatable :: listdata
80 
81  contains
82 
83  private
84 
85  procedure :: assignlist
86 
91  generic, public :: assignment(=) => assignlist
92 
93  ! procedure :: ConcatList
94 
95  ! !> Concatenate operator for the List type, this enables
96  ! !! concatenationo of the two lists to create a new list
97  ! !! with the combined contents.
98  ! generic, public :: assignment(//) => ConcatList
99 
100  ! Internal procedures
101  procedure :: create_newslots
102 
104  procedure, public :: size => list_size
105 
107  procedure, public :: pushback => push_back
108 
110  procedure, public :: popback => pop_back
111 
113  procedure, public :: item => item_at
114 
116  procedure, public :: front => item_front
117 
119  procedure, public :: back => item_back
120 
123  procedure, public :: insert => item_insert
124 
127  procedure, public :: erase => item_erase
128 
130  procedure, public :: shrinktofit
131 
133  procedure, public :: clear
134 
136  final :: destroy
137 
138  end type list
139 
140 
141 contains
142 
143 
144 
145 
147 pure function list_size(me)
148  implicit none
149  class(list), intent(in) :: me
150  integer :: list_size
151 
152  list_size = me%UsedSlots
153 end function list_size
154 
155 
156 
157 
158 
159 
161 function push_back(me, newitem) result(Index)
162  implicit none
163  class(list), intent(inout) :: me
165  class(*), intent(in) :: newitem
167  integer :: index
168 
169  index = 0
170 
171  if (me%UsedSlots == me%AllocatedSlots) then
172  ! allocate new slots
173  call me%create_newslots(me%NewSlotsToAllocate)
174  if (me%status /= 0) return
175  end if
176 
177  ! copy the item at the back of the list
178  call me%ListData(me%UsedSlots+1)%add_listitem(newitem)
179  me%UsedSlots = me%UsedSlots + 1
180  index = me%UsedSlots
181 end function push_back
182 
183 
184 
185 
187 function pop_back(me) result(item)
188  implicit none
189  class(list), intent(inout) :: me
190  class(*), allocatable :: item
191 
192  ! get the last item
193  allocate(item, source=me%Listdata(me%UsedSlots)%item, stat=me%status)
194 
195  ! delete this item
196  call me%ListData(me%UsedSlots)%del_listitem()
197  me%UsedSlots = me%UsedSlots - 1
198 end function pop_back
199 
200 
203 function item_at(me, Index) result(item)
204  implicit none
205  class(list), intent(inout), target :: me
207  integer, intent(in) :: index
208 
209  class(*), pointer :: item
210 
211  item => null()
212  ! check if Index is valid
213  if (index < 1 .OR. index > me%Size()) return
214  ! If element is valid, return the pointer
215  if (me%Listdata(index)%isvalid_listitem()) item=>me%Listdata(index)%item
216 end function item_at
217 
218 
219 
220 
222 function item_front(me) result(item)
223  implicit none
224  class(list), intent(inout) :: me
225  class(*), allocatable :: item
226  class(*), pointer :: ptr
227  ptr => me%Item(1)
228  allocate(item, source=ptr)
229 end function item_front
230 
231 
232 
234 function item_back(me) result(item)
235  implicit none
236  class(list), intent(inout) :: me
237  class(*), allocatable :: item
238  class(*), pointer :: ptr
239  ptr => me%Item(me%Size())
240  allocate(item, source=ptr)
241 end function item_back
242 
243 
245 subroutine item_insert(me, pos, NewItem)
246  implicit none
247  class(list), intent(inout) :: me
248  integer, intent(in) :: pos
249  class(*), intent(in) :: NewItem
250 
251  integer :: ctr
252 
253  ! parameter check
254  if (pos < 1 .OR. pos > (me%Size()+1)) then
255  me%status = -1
256  return
257  end if
258 
259  ! expand internal array if needed
260  if (me%Size() == me%AllocatedSlots) then
261  ! allocate new slots
262  call me%create_newslots(me%NewSlotsToAllocate)
263  if (me%status /= 0) return
264  end if
265 
266  ! Move the old list item pointers
267  do ctr = me%Size(), pos, -1
268  call me%ListData(ctr+1)%add_listitem(me%ListData(ctr)%item)
269  end do
270 
271  ! insert the new item
272  call me%ListData(pos)%add_listitem(newitem)
273  me%UsedSlots = me%UsedSlots + 1
274 end subroutine item_insert
275 
276 
277 
278 
280 subroutine item_erase(me, pos)
281  implicit none
282  class(list), intent(inout) :: me
283  integer, intent(in) :: pos
284 
285  integer :: ctr
286 
287  ! parameter check
288  if (pos < 1 .OR. pos > me%Size()) then
289  me%status = -1
290  return
291  end if
292 
293  ! delete the element
294  call me%ListData(pos)%del_listitem()
295 
296  ! Move the other list item pointers
297  do ctr = pos, me%Size()-1
298  call me%ListData(ctr)%add_listitem(me%ListData(ctr+1)%item)
299  end do
300  me%UsedSlots = me%UsedSlots - 1
301 end subroutine item_erase
302 
303 
304 
305 
306 
308 subroutine create_newslots(me, NumSlots)
309  implicit none
310  class(list), intent(inout) :: me
312  integer, intent(in) :: NumSlots
313 
314  type(listitem), dimension(:), allocatable :: tmp
315  integer :: ctr
316 
317  ! allocate new item array
318  allocate(tmp(me%AllocatedSlots+numslots), stat=me%status)
319 
320  if (me%status == 0) then
321  ! if List already has some slots
322  if (me%UsedSlots /= 0) then
323  ! copy the previous data pointers
324  tmp(1:me%AllocatedSlots) = me%ListData
325  end if
326  ! expand the list array
327  call move_alloc(from=tmp, to=me%ListData)
328  me%AllocatedSlots = me%AllocatedSlots + numslots
329  end if
330 end subroutine create_newslots
331 
332 
333 
334 
336 subroutine assignlist(lhs, rhs)
337  implicit none
338  class(list), intent(out) :: lhs
339  class(list), intent(in) :: rhs
340 
341  integer :: ctr
342 
343  ! we assign the contents by moving all the items of rhs to lhs
344 
345  ! allocate memory for items array
346  allocate(lhs%ListData(rhs%AllocatedSlots))
347 
348  ! copy items
349  do ctr = 1, rhs%AllocatedSlots
350  call lhs%ListData(ctr)%add_listitem(rhs%ListData(ctr)%item)
351  end do
352 
353  ! copy List state
354  lhs%status = rhs%status
355  lhs%NewSlotsToAllocate = rhs%NewSlotsToAllocate
356  lhs%UsedSlots = rhs%UsedSlots
357  lhs%AllocatedSlots = rhs%AllocatedSlots
358 end subroutine assignlist
359 
360 
361 
362 
363 
364 
366 subroutine clear(me)
367  implicit none
368  class(list), intent(inout) :: me
369 
370  integer :: ctr
371  ! clear slots
372  do ctr = 1, me%Size()
373  call me%ListData(ctr)%del_listitem()
374  end do
375  ! used slots are 0 now
376  me%UsedSlots = 0
377 end subroutine clear
378 
379 
381 subroutine shrinktofit(me)
382  implicit none
383  class(list), intent(inout) :: me
384 
385  integer :: ctr
386  type(listitem), dimension(:), allocatable :: tmp
387 
388  if (me%Size() < me%AllocatedSlots) then
389  ! destroy the slots
390  do ctr = me%Size()+1, me%AllocatedSlots
391  call me%ListData(ctr)%del_listitem()
392  end do
393  me%AllocatedSlots = me%Size()
394  end if
395 
396  if (me%AllocatedSlots < 1) then
397  if (allocated(me%ListData)) deallocate(me%ListData, stat=me%status)
398  else
399  ! shrink the list data pointer array
400  allocate(tmp(1:me%AllocatedSlots), stat=me%status)
401  if (me%status == 0) then
402  tmp = me%ListData(1:me%AllocatedSlots)
403  call move_alloc(from=tmp, to=me%ListData)
404  end if
405  end if
406 end subroutine shrinktofit
407 
408 
409 
410 
412 subroutine destroy(me)
413  implicit none
414  type(list), intent(inout) :: me
415 
416  integer :: ctr
417 
418  ! free up memory held up by all the slots
419  do ctr = 1, me%Size()
420  call me%ListData(ctr)%del_listitem()
421  end do
422 end subroutine destroy
423 
424 
425 
426 ! List Item procedures
427 
428 elemental subroutine add_listitem(me, item)
429  implicit none
430  class(listitem), intent(inout) :: me
432  class(*), intent(in) :: item
433 
434  integer :: status
435 
436  allocate(me%item, source=item, stat=status)
437  if (status == 0) then
438  me%Valid = .true.
439  else
440  me%Valid = .false.
441  if (associated(me%item)) deallocate(me%item)
442  me%item => null()
443  end if
444 end subroutine add_listitem
445 
446 
447 
448 subroutine del_listitem(me)
449  implicit none
450  class(listitem), intent(inout) :: me
451 
452  if (associated(me%item)) deallocate(me%item)
453  me%item => null()
454  me%Valid = .false.
455 end subroutine del_listitem
456 
457 
458 
459 pure elemental function isvalid_listitem(me)
460  implicit none
461  class(listitem), intent(in) :: me
462  logical :: isvalid_listitem
463  isvalid_listitem = me%Valid
464 end function isvalid_listitem
465 
466 end module lists
lists
List module.
Definition: list.f90:31
lists::item_insert
subroutine item_insert(me, pos, NewItem)
Inserts an item at the given position.
Definition: list.f90:246
lists::destroy
subroutine destroy(me)
Destructor.
Definition: list.f90:413
lists::listitem
List Item type.
Definition: list.f90:43
lists::list
List type.
Definition: list.f90:62
lists::create_newslots
subroutine create_newslots(me, NumSlots)
Subroutine to allocate storage for new slots.
Definition: list.f90:309
lists::push_back
integer function push_back(me, newitem)
Subroutine to append an element at the back of the list.
Definition: list.f90:162
lists::clear
subroutine clear(me)
Clear the contents of List.
Definition: list.f90:367
lists::pop_back
class(*) function, allocatable pop_back(me)
Function to extract the last item of List.
Definition: list.f90:188
lists::list_size
pure integer function list_size(me)
Returns the total number of items in the List.
Definition: list.f90:148
lists::item_back
class(*) function, allocatable item_back(me)
Returns the last item in List.
Definition: list.f90:235
lists::item_erase
subroutine item_erase(me, pos)
Erase an item at the given position.
Definition: list.f90:281
lists::default_newslotsallocated
integer, parameter default_newslotsallocated
Default number of slots to create on list capacity increase.
Definition: list.f90:40
lists::shrinktofit
subroutine shrinktofit(me)
Free up unused allocated memory and make List capacity equal to its size.
Definition: list.f90:382
lists::add_listitem
elemental subroutine add_listitem(me, item)
Definition: list.f90:429
lists::assignlist
subroutine assignlist(lhs, rhs)
Subroutine for List assignment operator.
Definition: list.f90:337
lists::item_front
class(*) function, allocatable item_front(me)
Returns the item with the index=1.
Definition: list.f90:223
lists::item_at
class(*) function, pointer item_at(me, Index)
Returns a pointer to the item with the requested index (1-based) Pointer will not be associated in ca...
Definition: list.f90:204
fmutilbase
FMUTIL Base Module.
Definition: fmutil_base.F90:31
lists::del_listitem
subroutine del_listitem(me)
Definition: list.f90:449
lists::isvalid_listitem
pure elemental logical function isvalid_listitem(me)
Definition: list.f90:460