NAME
M_list(3f) - [M_list::INTRO] maintain simple lists
(LICENSE:PD)
SYNOPSIS
use M_list, only : insert, replace, remove, locate
use M_list, only : dictionary
DESCRIPTION
The M_list(3fm) module allows for maintaining an allocatable array of
intrinsic type (REAL, INTEGER, CHARACTER) as a sorted list. An example
is given that creates a keyword-value dictionary using the lists.
The lists are maintained as simple allocatable arrays. Each time an
entry is added or deleted the array is re-allocated. Because of the
expense of reallocating the data these routines are best suited for
maintaining small lists that do not change size frequently.
The advantage of this simplistic approach is that the dictionary
components are simple arrays of intrinsic types which can be easily
accessed with standard routines. It is easy to understand, as it
works with simple arrays. For more demanding applications this would
be implemented as a linked list, which there are a number of freely
available examples of; several are listed on the Fortran Wiki.
BASIC LIST
subroutine locate(list,value,place,ier,errmsg) finds the index where a
value is found or should
be in a sorted array and
flag if the value exists
already
subroutine insert(list,value,place) insert entry into an allocatable
array at specified position
subroutine replace(list,value,place) replace entry in an allocatable
array at specified position
subroutine remove(list,place) remove entry from an allocatable
array at specified position
EXAMPLES
Sample program
program demo_M_list
use M_list, only : insert, locate, replace, remove
! create a dictionary with character keywords, values, and value lengths
! using the routines for maintaining a list
use M_list, only : locate, insert, replace
implicit none
character(len=:),allocatable :: keywords(:)
character(len=:),allocatable :: values(:)
integer,allocatable :: counts(:)
integer :: i
! insert and replace entries
call update('b','value of b')
call update('a','value of a')
call update('c','value of c')
call update('c','value of c again')
call update('d','value of d')
call update('a','value of a again')
! show array
write(*,'(*(a,"==>","[",a,"]",/))')&
& (trim(keywords(i)),values(i)(:counts(i)),i=1,size(keywords))
! remove some entries
call update('a')
call update('c')
write(*,'(*(a,"==>","[",a,"]",/))')&
& (trim(keywords(i)),values(i)(:counts(i)),i=1,size(keywords))
! get some values
write(*,*)'get b=>',get('b')
write(*,*)'get d=>',get('d')
write(*,*)'get notthere=>',get('notthere')
!
contains
subroutine update(key,valin)
character(len=*),intent(in) :: key
character(len=*),intent(in),optional :: valin
integer :: place
integer :: ilen
character(len=:),allocatable :: val
if(present(valin))then
val=valin
ilen=len_trim(val)
! find where string is or should be
call locate(keywords,key,place)
! if string was not found insert it
if(place.lt.1)then
call insert(keywords,key,iabs(place))
call insert(values,val,iabs(place))
call insert(counts,ilen,iabs(place))
else
call replace(values,val,place)
call replace(counts,ilen,place)
endif
else
call locate(keywords,key,place)
if(place.gt.0)then
call remove(keywords,place)
call remove(values,place)
call remove(counts,place)
endif
endif
end subroutine update
function get(key) result(valout)
character(len=*),intent(in) :: key
character(len=:),allocatable :: valout
integer :: place
! find where string is or should be
call locate(keywords,key,place)
if(place.lt.1)then
valout=''
else
valout=values(place)(:counts(place))
endif
end function get
end program demo_M_list
Results
> d==>[value of d]
> c==>[value of c again]
> b==>[value of b]
> a==>[value of a again]
>
> d==>[value of d]
> b==>[value of b]
>
> get b=>value of b
> get d=>value of d
> get notthere=>
BASIC DICTIONARY
A basic dictionary that uses the basic M_list functions.
Consider using generic linked-list based dictionaries when heavy
usage is required, now that that is available in more recent versions
of Fortran.
Note: this does not work with gfortran(1) up to at least 7.4.0 but
works from at least 10.3.0 and onward.
Dictionary type definition:
type dictionary
character(len=:),allocatable :: key(:)
character(len=:),allocatable :: value(:)
integer,allocatable :: count(:)
contains
procedure,public :: get => dict_get
procedure,public :: set => dict_add
procedure,public :: del => dict_delete
procedure,public :: clr => dict_clear
end type dictionary
%get get value from type(dictionary) given an existing key
%set set or replace value for type(dictionary) given a key
%del delete an existing key from type(dictionary)
%clr empty a type(dictionary)
%ifdef test if name is defined
EXAMPLES
Sample program
program test_dictionary
use M_list, only : dictionary
implicit none
type(dictionary) :: table
!
! create a character string dictionary
!
call table%set('A','aye')
call table%set('B','bee')
call table%set('C','see')
call table%set('D','dee')
!
write(*,*)'A=',table%get('A')
write(*,*)'C=',table%get('C')
write(*,*)'notthere=',table%get('notthere')
!
call print_dict()
!
! delete dictionary entries
!
call table%del('A')
call table%del('C')
call table%del('z') ! a noop as there is no key of 'z'
!
call print_dict()
!
! clear dictionary
!
call table%clr()
!
call print_dict()
!
contains
!
subroutine print_dict()
integer :: i
! the dictionary is just three arrays
write(*,'("DICTIONARY:")')
write(*,'(*(a,"==>","[",a,"]",/))') &
& (trim(table%key(i)), &
& table%value(i)(:table%count(i)), &
& i=1,size(table%key))
!
end subroutine print_dict
!
end program test_dictionary
AUTHOR
LICENSE
Interfaces
-
private subroutine insert_c(list, value, place)
NAME
insert(3f) - [M_list] insert entry into a string array at specified position
(LICENSE:PD)
SYNOPSIS
subroutine insert(list,value,place)
character(len=*)|doubleprecision|real|integer,intent(in) :: value
character(len=:)|doubleprecision|real|integer,intent(in) :: list(:)
integer,intent(in) :: place
DESCRIPTION
Insert a value into an allocatable array at the specified index.
The list and value must be of the same type (CHARACTER, DOUBLEPRECISION,
REAL, or INTEGER)
OPTIONS
list is the list array. Must be sorted in descending order.
value the value to place in the array
PLACE is the subscript that the entry should be placed at
EXAMPLES
Find if a string is in a sorted array, and insert the string into
the list if it is not present …
program demo_insert
use M_sort, only : sort_shell
use M_list, only : locate, insert
implicit none
character(len=:),allocatable :: arr(:)
integer :: i
arr=[character(len=20) :: '', 'ZZZ', 'aaa', 'b', 'xxx' ]
! make sure sorted in descending order
call sort_shell(arr,order='d')
! add or replace values
call update(arr,'b')
call update(arr,'[')
call update(arr,'c')
call update(arr,'ZZ')
call update(arr,'ZZZ')
call update(arr,'ZZZZ')
call update(arr,'')
call update(arr,'z')
contains
subroutine update(arr,string)
character(len=:),allocatable :: arr(:)
character(len=*) :: string
integer :: place, end
end=size(arr)
! find where string is or should be
call locate(arr,string,place)
! if string was not found insert it
if(place.lt.1)then
call insert(arr,string,abs(place))
endif
! show array
end=size(arr)
write(*,'("array is now SIZE=",i0,1x,*(a,","))')end,(trim(arr(i)),i=1,end)
end subroutine update
end program demo_insert
Results
> array is now SIZE=5 xxx,b,aaa,ZZZ,,
> array is now SIZE=6 xxx,b,aaa,[,ZZZ,,
> array is now SIZE=7 xxx,c,b,aaa,[,ZZZ,,
> array is now SIZE=8 xxx,c,b,aaa,[,ZZZ,ZZ,,
> array is now SIZE=9 xxx,c,b,aaa,[,ZZZZ,ZZZ,ZZ,,
> array is now SIZE=10 z,xxx,c,b,aaa,[,ZZZZ,ZZZ,ZZ,,
AUTHOR
LICENSE
Arguments
Type |
Intent | Optional | Attributes |
|
Name |
|
character(len=:),
|
|
|
allocatable
|
:: |
list(:) |
|
character(len=*),
|
intent(in) |
|
|
:: |
value |
|
integer,
|
intent(in) |
|
|
:: |
place |
|
-
private subroutine insert_d(list, value, place)
Arguments
Type |
Intent | Optional | Attributes |
|
Name |
|
doubleprecision,
|
|
|
allocatable
|
:: |
list(:) |
|
doubleprecision,
|
intent(in) |
|
|
:: |
value |
|
integer,
|
intent(in) |
|
|
:: |
place |
|
-
private subroutine insert_r(list, value, place)
Arguments
Type |
Intent | Optional | Attributes |
|
Name |
|
real,
|
|
|
allocatable
|
:: |
list(:) |
|
real,
|
intent(in) |
|
|
:: |
value |
|
integer,
|
intent(in) |
|
|
:: |
place |
|
-
private subroutine insert_i(list, value, place)
Arguments
Type |
Intent | Optional | Attributes |
|
Name |
|
integer,
|
|
|
allocatable
|
:: |
list(:) |
|
integer,
|
intent(in) |
|
|
:: |
value |
|
integer,
|
intent(in) |
|
|
:: |
place |
|
-
private subroutine insert_l(list, value, place)
Arguments
Type |
Intent | Optional | Attributes |
|
Name |
|
logical,
|
|
|
allocatable
|
:: |
list(:) |
|
logical,
|
intent(in) |
|
|
:: |
value |
|
integer,
|
intent(in) |
|
|
:: |
place |
|
-
private subroutine locate_c(list, value, place, ier, errmsg)
NAME
locate(3f) - [M_list] finds the index where a string is found or
should be in a sorted array
(LICENSE:PD)
SYNOPSIS
subroutine locate(list,value,place,ier,errmsg)
character(len=:)|doubleprecision|real|integer,allocatable :: list(:)
character(len=*)|doubleprecision|real|integer,intent(in) :: value
integer, intent(out) :: PLACE
integer, intent(out),optional :: IER
character(len=*),intent(out),optional :: ERRMSG
DESCRIPTION
LOCATE(3f) finds the index where the VALUE is found or should
be found in an array. The array must be sorted in descending
order (highest at top). If VALUE is not found it returns the index
where the name should be placed at with a negative sign.
The array and list must be of the same type (CHARACTER, DOUBLEPRECISION,
REAL,INTEGER)
OPTIONS
VALUE the value to locate in the list.
LIST is the list array.
RETURNS
PLACE is the subscript that the entry was found at if it is
greater than zero(0).
If PLACE is negative, the absolute value of
PLACE indicates the subscript value where the
new entry should be placed in order to keep the
list alphabetized.
IER is zero(0) if no error occurs.
If an error occurs and IER is not
present, the program is stopped.
ERRMSG description of any error
EXAMPLES
Find if a string is in a sorted array, and insert the string into
the list if it is not present …
program demo_locate
use M_sort, only : sort_shell
use M_list, only : locate
implicit none
character(len=:),allocatable :: arr(:)
integer :: i
arr=[character(len=20) :: '', 'ZZZ', 'aaa', 'b', 'xxx' ]
! make sure sorted in descending order
call sort_shell(arr,order='d')
call update(arr,'b')
call update(arr,'[')
call update(arr,'c')
call update(arr,'ZZ')
call update(arr,'ZZZZ')
call update(arr,'z')
contains
subroutine update(arr,string)
character(len=:),allocatable :: arr(:)
character(len=*) :: string
integer :: place, plus, ii, end
! find where string is or should be
call locate(arr,string,place)
write(*,*)'for "'//string//'" index is ',place, size(arr)
! if string was not found insert it
if(place.lt.1)then
plus=abs(place)
ii=len(arr)
end=size(arr)
! empty array
if(end.eq.0)then
arr=[character(len=ii) :: string ]
! put in front of array
elseif(plus.eq.1)then
arr=[character(len=ii) :: string, arr]
! put at end of array
elseif(plus.eq.end)then
arr=[character(len=ii) :: arr, string ]
! put in middle of array
else
arr=[character(len=ii) :: arr(:plus-1), string,arr(plus:) ]
endif
! show array
write(*,'("SIZE=",i0,1x,*(a,","))')end,(trim(arr(i)),i=1,end)
endif
end subroutine update
end program demo_locate
Results
> for "b" index is 2 5
> for "[" index is -4 5
> SIZE=5 xxx,b,aaa,[,ZZZ,
> for "c" index is -2 6
> SIZE=6 xxx,c,b,aaa,[,ZZZ,
> for "ZZ" index is -7 7
> SIZE=7 xxx,c,b,aaa,[,ZZZ,,
> for "ZZZZ" index is -6 8
> SIZE=8 xxx,c,b,aaa,[,ZZZZ,ZZZ,,
> for "z" index is -1 9
> SIZE=9 z,xxx,c,b,aaa,[,ZZZZ,ZZZ,,
AUTHOR
LICENSE
Arguments
Type |
Intent | Optional | Attributes |
|
Name |
|
character(len=:),
|
|
|
allocatable
|
:: |
list(:) |
|
character(len=*),
|
intent(in) |
|
|
:: |
value |
|
integer,
|
intent(out) |
|
|
:: |
place |
|
integer,
|
intent(out), |
optional |
|
:: |
ier |
|
character(len=*),
|
intent(out), |
optional |
|
:: |
errmsg |
|
-
private subroutine locate_d(list, value, place, ier, errmsg)
Arguments
Type |
Intent | Optional | Attributes |
|
Name |
|
doubleprecision,
|
|
|
allocatable
|
:: |
list(:) |
|
doubleprecision,
|
intent(in) |
|
|
:: |
value |
|
integer,
|
intent(out) |
|
|
:: |
place |
|
integer,
|
intent(out), |
optional |
|
:: |
ier |
|
character(len=*),
|
intent(out), |
optional |
|
:: |
errmsg |
|
-
private subroutine locate_r(list, value, place, ier, errmsg)
Arguments
Type |
Intent | Optional | Attributes |
|
Name |
|
real,
|
|
|
allocatable
|
:: |
list(:) |
|
real,
|
intent(in) |
|
|
:: |
value |
|
integer,
|
intent(out) |
|
|
:: |
place |
|
integer,
|
intent(out), |
optional |
|
:: |
ier |
|
character(len=*),
|
intent(out), |
optional |
|
:: |
errmsg |
|
-
private subroutine locate_i(list, value, place, ier, errmsg)
Arguments
Type |
Intent | Optional | Attributes |
|
Name |
|
integer,
|
|
|
allocatable
|
:: |
list(:) |
|
integer,
|
intent(in) |
|
|
:: |
value |
|
integer,
|
intent(out) |
|
|
:: |
place |
|
integer,
|
intent(out), |
optional |
|
:: |
ier |
|
character(len=*),
|
intent(out), |
optional |
|
:: |
errmsg |
|
-
private subroutine replace_c(list, value, place)
NAME
replace(3f) - [M_list] replace entry in a string array at specified position
(LICENSE:PD)
SYNOPSIS
subroutine replace(list,value,place)
character(len=*)|doubleprecision|real|integer,intent(in) :: value
character(len=:)|doubleprecision|real|integer,intent(in) :: list(:)
integer, intent(out) :: PLACE
DESCRIPTION
replace a value in an allocatable array at the specified index. Unless
the array needs the string length to increase this is merely an assign
of a value to an array element.
The array may be of type CHARACTER, DOUBLEPRECISION, REAL, or INTEGER.
It is assumed to be sorted in descending order without duplicate
values.
The value and list must be of the same type.
OPTIONS
VALUE the value to place in the array
LIST is the array.
PLACE is the subscript that the entry should be placed at
EXAMPLES
Replace key-value pairs in a dictionary
program demo_replace
use M_list, only : insert, locate, replace
! Find if a key is in a list and insert it
! into the key list and value list if it is not present
! or replace the associated value if the key existed
implicit none
character(len=20) :: key
character(len=100) :: val
character(len=:),allocatable :: keywords(:)
character(len=:),allocatable :: values(:)
integer :: i
integer :: place
call update('b','value of b')
call update('a','value of a')
call update('c','value of c')
call update('c','value of c again')
call update('d','value of d')
call update('a','value of a again')
! show array
write(*,'(*(a,"==>",a,/))')&
&(trim(keywords(i)),trim(values(i)),i=1,size(keywords))
call locate(keywords,'a',place)
if(place.gt.0)then
write(*,*)'The value of "a" is ',trim(values(place))
else
write(*,*)'"a" not found'
endif
contains
subroutine update(key,val)
character(len=*),intent(in) :: key
character(len=*),intent(in) :: val
integer :: place
! find where string is or should be
call locate(keywords,key,place)
! if string was not found insert it
if(place.lt.1)then
call insert(keywords,key,abs(place))
call insert(values,val,abs(place))
else ! replace
call replace(values,val,place)
endif
end subroutine update
end program demo_replace
Results
> d==>value of d
> c==>value of c again
> b==>value of b
> a==>value of a again
AUTHOR
LICENSE
Arguments
Type |
Intent | Optional | Attributes |
|
Name |
|
character(len=:),
|
|
|
allocatable
|
:: |
list(:) |
|
character(len=*),
|
intent(in) |
|
|
:: |
value |
|
integer,
|
intent(in) |
|
|
:: |
place |
|
-
private subroutine replace_d(list, value, place)
Arguments
Type |
Intent | Optional | Attributes |
|
Name |
|
doubleprecision,
|
|
|
allocatable
|
:: |
list(:) |
|
doubleprecision,
|
intent(in) |
|
|
:: |
value |
|
integer,
|
intent(in) |
|
|
:: |
place |
|
-
private subroutine replace_r(list, value, place)
Arguments
Type |
Intent | Optional | Attributes |
|
Name |
|
real,
|
|
|
allocatable
|
:: |
list(:) |
|
real,
|
intent(in) |
|
|
:: |
value |
|
integer,
|
intent(in) |
|
|
:: |
place |
|
-
private subroutine replace_i(list, value, place)
Arguments
Type |
Intent | Optional | Attributes |
|
Name |
|
integer,
|
|
|
allocatable
|
:: |
list(:) |
|
integer,
|
intent(in) |
|
|
:: |
value |
|
integer,
|
intent(in) |
|
|
:: |
place |
|
-
private subroutine replace_l(list, value, place)
Arguments
Type |
Intent | Optional | Attributes |
|
Name |
|
logical,
|
|
|
allocatable
|
:: |
list(:) |
|
logical,
|
intent(in) |
|
|
:: |
value |
|
integer,
|
intent(in) |
|
|
:: |
place |
|
Derived Types
Components
Type |
Visibility | Attributes |
|
Name |
| Initial | |
integer,
|
public, |
allocatable
|
:: |
count(:) |
|
|
|
character(len=:),
|
public, |
allocatable
|
:: |
key(:) |
|
|
|
character(len=:),
|
public, |
allocatable
|
:: |
value(:) |
|
|
|
Type-Bound Procedures
procedure
, public
:: clr
=>
dict_clear
Subroutine |
|
procedure
, public
:: del
=>
dict_delete
Subroutine |
|
procedure
, public
:: get
=>
dict_get
Function |
|
procedure
, public
:: ifdef
=>
dict_ifdef
Function |
|
procedure
, public
:: set
=>
dict_add
Subroutine |
|