Skip to content

Instantly share code, notes, and snippets.

@awvwgk
Created October 17, 2019 20:01
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save awvwgk/ca04adc961c53c97c328e4ddcb4f2f72 to your computer and use it in GitHub Desktop.
Save awvwgk/ca04adc961c53c97c328e4ddcb4f2f72 to your computer and use it in GitHub Desktop.
A simplistic list of atoms for easy IO
!> implemenation of a list of atoms
module tbdef_atomlist
implicit none
public :: tb_atomlist
public :: size, len, assignment(=), write(formatted), read(formatted)
private
character, parameter :: p_delimiter = ','
character, parameter :: p_skip = '-'
type :: tb_atomlist
private
logical, allocatable :: list(:)
logical :: default = .false.
character :: delimiter = p_delimiter
character :: skip = p_skip
logical :: error = .false.
contains
generic :: new => from_integers, from_logicals, from_string, from_defaults
procedure, private :: from_defaults => atomlist_defaults
procedure, private :: from_integers => atomlist_assign_integers
procedure, private :: from_logicals => atomlist_assign_logicals
procedure, private :: from_string => atomlist_assign_string
procedure, pass(self) :: to_string => string_assign_atomlist
procedure, pass(self) :: to_list => list_assign_atomlist
procedure :: switch_truth => atomlist_switch_truth
procedure :: set_truth => atomlist_set_truth
procedure :: get_truth => atomlist_get_truth
procedure :: get_error => atomlist_get_error
generic :: remove => remove_integer, remove_integers
procedure, private :: remove_integer => atomlist_remove_integer
procedure, private :: remove_integers => atomlist_remove_integers
generic :: add => add_integer, add_integers
procedure, private :: add_integer => atomlist_add_integer
procedure, private :: add_integers => atomlist_add_integers
procedure, private :: parse => atomlist_parse_string
procedure :: resize => atomlist_resize
procedure :: destroy => atomlist_destroy
final :: atomlist_finalizer
end type tb_atomlist
interface tb_atomlist
module procedure :: atomlist_from_logicals
module procedure :: atomlist_from_integers
module procedure :: atomlist_from_string
end interface tb_atomlist
interface len
module procedure :: atomlist_length
end interface len
interface size
module procedure :: atomlist_size
end interface size
interface assignment(=)
module procedure :: atomlist_assign_logicals
module procedure :: atomlist_assign_integers
module procedure :: atomlist_assign_string
module procedure :: string_assign_atomlist
module procedure :: list_assign_atomlist
end interface assignment(=)
interface write(formatted)
module procedure :: atomlist_write_formatted
end interface write(formatted)
interface read(formatted)
module procedure :: atomlist_read_formatted
end interface read(formatted)
contains
pure function atomlist_from_logicals(list, truth, delimiter, skip) result(self)
logical, intent(in) :: list(:)
logical, intent(in), optional :: truth
character, intent(in), optional :: delimiter, skip
type(tb_atomlist) :: self
if (present(truth)) self%default = .not.truth
if (present(delimiter)) self%delimiter = delimiter
if (present(skip)) self%skip = skip
call self%new(list)
end function atomlist_from_logicals
pure function atomlist_from_integers(list, truth, delimiter, skip) result(self)
integer, intent(in) :: list(:)
logical, intent(in), optional :: truth
character, intent(in), optional :: delimiter, skip
type(tb_atomlist) :: self
if (present(truth)) self%default = .not.truth
if (present(delimiter)) self%delimiter = delimiter
if (present(skip)) self%skip = skip
call self%new(list)
end function atomlist_from_integers
pure function atomlist_from_string(list, truth, delimiter, skip) result(self)
character(len=*), intent(in) :: list
logical, intent(in), optional :: truth
character, intent(in), optional :: delimiter, skip
type(tb_atomlist) :: self
if (present(truth)) self%default = .not.truth
if (present(delimiter)) self%delimiter = delimiter
if (present(skip)) self%skip = skip
call self%new(list)
end function atomlist_from_string
pure elemental subroutine atomlist_defaults(self)
class(tb_atomlist), intent(out) :: self
end subroutine atomlist_defaults
pure elemental subroutine atomlist_switch_truth(self)
class(tb_atomlist), intent(inout) :: self
self%default = .not.self%default
end subroutine atomlist_switch_truth
pure elemental subroutine atomlist_set_truth(self, truth)
class(tb_atomlist), intent(inout) :: self
logical, intent(in) :: truth
self%default = .not.truth
end subroutine atomlist_set_truth
pure elemental function atomlist_get_truth(self) result(truth)
class(tb_atomlist), intent(in) :: self
logical :: truth
truth = .not.self%default
end function atomlist_get_truth
pure elemental function atomlist_get_error(self) result(error)
class(tb_atomlist), intent(in) :: self
logical :: error
error = self%error
end function atomlist_get_error
subroutine atomlist_write_formatted(self, unit, iotype, v_list, iostat, iomsg)
class(tb_atomlist), intent(in) :: self
integer, intent(in) :: unit
character(len=*), intent(in) :: iotype
integer, intent(in) :: v_list(:)
integer, intent(out) :: iostat
character(len=*), intent(inout) :: iomsg
character(len=:), allocatable :: buffer
call self%to_string(buffer)
write(unit, '(a)', iostat=iostat, iomsg=iomsg) buffer
end subroutine atomlist_write_formatted
subroutine atomlist_read_formatted(self, unit, iotype, v_list, iostat, iomsg)
class(tb_atomlist), intent(inout) :: self
integer, intent(in) :: unit
character(len=*), intent(in) :: iotype
integer, intent(in) :: v_list(:)
integer, intent(out) :: iostat
character(len=*), intent(inout) :: iomsg
character(len=:), allocatable :: string
call get_line(unit, string, iostat)
call self%new(string)
contains
subroutine get_line(unit, line, iostat)
use iso_fortran_env, only : iostat_eor
integer, intent(in) :: unit
character(len=:), allocatable, intent(out) :: line
integer, intent(out), optional :: iostat
integer, parameter :: buffersize = 256
character(len=buffersize) :: buffer
integer :: size
integer :: err
line = ''
do
read(unit,'(a)',advance='no',iostat=err,size=size) &
& buffer
if (err.gt.0) then
if (present(iostat)) iostat=err
return ! an error occurred
endif
line = line // buffer(:size)
if (err.lt.0) then
if (err.eq.iostat_eor) err = 0
if (present(iostat)) iostat=err
return
endif
enddo
end subroutine get_line
end subroutine atomlist_read_formatted
integer pure elemental function atomlist_size(self)
class(tb_atomlist), intent(in) :: self
if (allocated(self%list)) then
atomlist_size = size(self%list)
else
atomlist_size = 0
endif
end function atomlist_size
integer pure elemental function atomlist_length(self)
class(tb_atomlist), intent(in) :: self
if (allocated(self%list)) then
atomlist_length = count(self%list.neqv.self%default)
else
atomlist_length = 0
endif
end function atomlist_length
pure subroutine atomlist_add_integer(self, item)
class(tb_atomlist), intent(inout) :: self
integer, intent(in) :: item
integer :: i
call self%resize(item)
self%list(item) = .not.self%default
end subroutine atomlist_add_integer
pure subroutine atomlist_add_integers(self, list)
class(tb_atomlist), intent(inout) :: self
integer, intent(in) :: list(:)
integer :: i
call self%resize(maxval(list))
do i = 1, size(list)
self%list(list(i)) = .not.self%default
enddo
end subroutine atomlist_add_integers
pure subroutine atomlist_remove_integer(self, item)
class(tb_atomlist), intent(inout) :: self
integer, intent(in) :: item
integer :: i
call self%resize(item)
self%list(item) = self%default
end subroutine atomlist_remove_integer
pure subroutine atomlist_remove_integers(self, list)
class(tb_atomlist), intent(inout) :: self
integer, intent(in) :: list(:)
integer :: i
call self%resize(maxval(list))
do i = 1, size(list)
self%list(list(i)) = self%default
enddo
end subroutine atomlist_remove_integers
pure subroutine list_assign_atomlist(list, self)
integer, allocatable, intent(out) :: list(:)
class(tb_atomlist), intent(in) :: self
integer :: i, j
allocate(list(len(self)), source=0)
j = 0
do i = 1, size(self)
if (self%list(i).neqv.self%default) then
j = j+1
list(j) = i
endif
enddo
end subroutine list_assign_atomlist
pure subroutine string_assign_atomlist(string, self)
character(len=:), allocatable, intent(out) :: string
class(tb_atomlist), intent(in) :: self
character(len=10) :: buffer
integer :: i, last
logical :: state, first
last = -1
first = .true.
state = .not.self%default
do i = 1, size(self)
if (state.eqv.self%list(i)) then
state = .not.state
if (state.eqv.self%default) then
last = i
write(buffer,'(i0)') i
if (first) then
first = .false.
string = trim(buffer)
else
string = string // self%delimiter // trim(buffer)
endif
else
if (i-1 .ne. last) then
write(buffer,'(i0)') i-1
string = string // self%skip // trim(buffer)
endif
endif
endif
enddo
if (state.eqv.self%default .and.last.ne.size(self)) then
write(buffer,'(i0)') size(self)
string = string // self%skip // trim(buffer)
endif
end subroutine string_assign_atomlist
pure subroutine atomlist_assign_logicals(self, list)
class(tb_atomlist), intent(inout) :: self
logical, intent(in) :: list(:)
call self%resize(size(list))
self%list = list
end subroutine atomlist_assign_logicals
pure subroutine atomlist_assign_integers(self, list)
class(tb_atomlist), intent(inout) :: self
integer, intent(in) :: list(:)
integer :: i
call self%resize(maxval(list))
do i = 1, size(list)
self%list(list(i)) = .not.self%default
enddo
end subroutine atomlist_assign_integers
pure subroutine atomlist_assign_string(self, string)
class(tb_atomlist), intent(inout) :: self
character(len=*), intent(in) :: string
character(len=:), allocatable :: buffer
integer, allocatable :: list(:)
integer :: pos, last, n
last = 0
do
pos = index(string(last+1:), self%delimiter)
if (pos > 0) then
call self%parse(string(last+1:last+pos-1))
if (self%error) exit
last = last+pos
else
call self%parse(string(last+1:))
exit
endif
enddo
end subroutine atomlist_assign_string
pure subroutine atomlist_parse_string(self, string)
class(tb_atomlist), intent(inout) :: self
character(len=*),intent(in) :: string
integer :: pos, item, begin, last, err
pos = index(string,self%skip)
if (pos.eq.0) then
read(string,*,iostat=err) item
if (err.ne.0) then
self%error = .false.
return
endif
call self%add(item)
else
read(string(:pos-1),*,iostat=err) begin
if (err.ne.0) then
self%error = .false.
return
endif
read(string(pos+1:),*,iostat=err) last
if (err.ne.0) then
self%error = .false.
return
endif
if (last.lt.begin) then
self%error = .false.
return
endif
do item = begin, last
call self%add(item)
enddo
endif
end subroutine atomlist_parse_string
pure subroutine atomlist_resize(self, n)
class(tb_atomlist), intent(inout) :: self
integer, intent(in), optional :: n
logical, allocatable :: list(:)
integer :: length, current_length
current_length = size(self)
if (current_length > 0) then
if (present(n)) then
if (n <= current_length) return
length = n
else
length = current_length + current_length/2 + 1
endif
allocate(list(length), source=self%default)
list(:current_length) = self%list(:current_length)
deallocate(self%list)
call move_alloc(list, self%list)
else
if (present(n)) then
length = n
else
length = 64
endif
allocate(self%list(length), source=self%default)
endif
end subroutine atomlist_resize
pure elemental subroutine atomlist_destroy(self)
class(tb_atomlist), intent(inout) :: self
if (allocated(self%list)) deallocate(self%list)
end subroutine atomlist_destroy
pure elemental subroutine atomlist_finalizer(self)
type(tb_atomlist), intent(inout) :: self
call self%destroy
end subroutine atomlist_finalizer
end module tbdef_atomlist
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment