Skip to content

Instantly share code, notes, and snippets.

@ivan-pi
Created March 5, 2021 18:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ivan-pi/e2181b4335a1d93cbeb3d422c6732cfa to your computer and use it in GitHub Desktop.
Save ivan-pi/e2181b4335a1d93cbeb3d422c6732cfa to your computer and use it in GitHub Desktop.
Fortran experiment with a fixed-size integer list
module integer_list_mod
implicit none
private
public :: integer_list
type :: index_t
private
integer :: idx
contains
procedure :: as_int
end type
! This container has a fixed maximum-size
type :: integer_list
integer :: n = 0
!! Actual size
integer :: values(100)
!! The underlying integer storage
integer :: index_ref = 0
!! Integer pointer to index array.
contains
procedure :: insert_int
procedure :: insert_index
generic :: insert => insert_int, insert_index
procedure :: get_int
procedure :: get_idx
generic :: get => get_int, get_idx
procedure :: end => list_end
end type
type(index_t), allocatable, target :: index_array(:)
integer :: next_free = 0
contains
subroutine insert_int(list,num)
class(integer_list), intent(inout) :: list
integer, intent(in) :: num
if (list%index_ref > 0) then
associate(pos => list%n + 1)
if (pos > 100) then
print *, "List full."
return
end if
list%n = pos
list%values(pos) = num
index_array(list%index_ref)%idx = list%n
end associate
else
list%index_ref = free_index_array_position()
list%n = 1
list%values(1) = num
index_array(list%index_ref)%idx = list%n
end if
end subroutine
integer function free_index_array_position() result(ref)
if (allocated(index_array)) then
if (next_free > size(index_array)) then
resize: block
type(index_t), allocatable :: new_index_array(:)
allocate(new_index_array(2*size(index_array)))
new_index_array(1:size(index_array)) = index_array
call move_alloc(from=new_index_array,to=index_array)
end block resize
end if
ref = next_free
next_free = next_free + 1
else
allocate(index_array(10))
next_free = 1
ref = next_free
end if
end function
subroutine insert_index(list,idx)
class(integer_list), intent(inout) :: list
type(index_t), intent(in) :: idx
call insert_int(list,idx%idx)
end subroutine
integer function get_int(list,i)
class(integer_list), intent(in) :: list
integer, intent(in) :: i
get_int = list%values(i)
end function
integer function get_idx(list,idx)
class(integer_list), intent(in) :: list
type(index_t), intent(in) :: idx
get_idx = list%values(idx%idx)
end function
function list_end(list) result(index_ptr)
class(integer_list), intent(inout) :: list
type(index_t), pointer :: index_ptr
if (list%index_ref == 0) then
list%index_ref = free_index_array_position()
end if
index_ptr => index_array(list%index_ref)
end function
pure integer function as_int(self)
class(index_t), intent(in) :: self
as_int = self%idx
end function
end module
program test
use integer_list_mod
implicit none
type(integer_list) :: ilist
integer :: i
associate(end => ilist%end())
call ilist%insert(1)
call ilist%insert(2)
call ilist%insert(3)
print *, ilist%get(end)
call ilist%insert(4)
print *, ilist%get(end)
print *, ilist%get(end%as_int())
! Append 4 additional values: 5, 6, 7, 8
do i = 1, end%as_int()
call ilist%insert(i+4)
end do
print *, ilist%values(1:end%as_int())
end associate
end program
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment