2019-03-24 16:10:05 +05:30
|
|
|
!-------------------------------------------------------------------------------------------------
|
|
|
|
!> @author Martin Diehl, Max-Planck-Institut für Eisenforschung GmbH
|
|
|
|
!> @brief linked list
|
|
|
|
!--------------------------------------------------------------------------------------------------
|
|
|
|
module list
|
2019-05-28 15:36:21 +05:30
|
|
|
use prec
|
|
|
|
use IO
|
2019-03-24 16:10:05 +05:30
|
|
|
|
|
|
|
implicit none
|
|
|
|
private
|
|
|
|
type, private :: tPartitionedString
|
|
|
|
character(len=:), allocatable :: val
|
|
|
|
integer, dimension(:), allocatable :: pos
|
|
|
|
end type tPartitionedString
|
|
|
|
|
|
|
|
type, public :: tPartitionedStringList
|
|
|
|
type(tPartitionedString) :: string
|
|
|
|
type(tPartitionedStringList), pointer :: next => null()
|
|
|
|
contains
|
|
|
|
procedure :: add => add
|
|
|
|
procedure :: show => show
|
|
|
|
procedure :: free => free
|
|
|
|
|
|
|
|
! currently, a finalize is needed for all shapes of tPartitionedStringList.
|
|
|
|
! with Fortran 2015, we can define one recursive elemental function
|
|
|
|
! https://software.intel.com/en-us/forums/intel-visual-fortran-compiler-for-windows/topic/543326
|
|
|
|
final :: finalize, &
|
|
|
|
finalizeArray
|
|
|
|
|
|
|
|
procedure :: keyExists => keyExists
|
|
|
|
procedure :: countKeys => countKeys
|
|
|
|
|
|
|
|
procedure :: getFloat => getFloat
|
|
|
|
procedure :: getInt => getInt
|
|
|
|
procedure :: getString => getString
|
|
|
|
|
|
|
|
procedure :: getFloats => getFloats
|
|
|
|
procedure :: getInts => getInts
|
|
|
|
procedure :: getStrings => getStrings
|
|
|
|
|
|
|
|
end type tPartitionedStringList
|
|
|
|
|
|
|
|
contains
|
|
|
|
|
|
|
|
!--------------------------------------------------------------------------------------------------
|
|
|
|
!> @brief add element
|
|
|
|
!> @details Adds a string together with the start/end position of chunks in this string. The new
|
|
|
|
!! element is added at the end of the list. Empty strings are not added. All strings are converted
|
|
|
|
!! to lower case. The data is not stored in the new element but in the current.
|
|
|
|
!--------------------------------------------------------------------------------------------------
|
|
|
|
subroutine add(this,string)
|
|
|
|
|
|
|
|
class(tPartitionedStringList), target, intent(in) :: this
|
|
|
|
character(len=*), intent(in) :: string
|
|
|
|
type(tPartitionedStringList), pointer :: new, temp
|
|
|
|
|
|
|
|
if (IO_isBlank(string)) return
|
|
|
|
|
|
|
|
allocate(new)
|
|
|
|
temp => this
|
|
|
|
do while (associated(temp%next))
|
|
|
|
temp => temp%next
|
|
|
|
enddo
|
|
|
|
temp%string%val = IO_lc (trim(string))
|
|
|
|
temp%string%pos = IO_stringPos(trim(string))
|
|
|
|
temp%next => new
|
|
|
|
|
|
|
|
end subroutine add
|
|
|
|
|
|
|
|
|
|
|
|
!--------------------------------------------------------------------------------------------------
|
|
|
|
!> @brief prints all elements
|
|
|
|
!> @details Strings are printed in order of insertion (FIFO)
|
|
|
|
!--------------------------------------------------------------------------------------------------
|
|
|
|
subroutine show(this)
|
|
|
|
|
|
|
|
class(tPartitionedStringList), target, intent(in) :: this
|
|
|
|
type(tPartitionedStringList), pointer :: item
|
|
|
|
|
|
|
|
item => this
|
|
|
|
do while (associated(item%next))
|
|
|
|
write(6,'(a)') ' '//trim(item%string%val)
|
|
|
|
item => item%next
|
|
|
|
enddo
|
|
|
|
|
|
|
|
end subroutine show
|
|
|
|
|
|
|
|
|
|
|
|
!--------------------------------------------------------------------------------------------------
|
|
|
|
!> @brief empties list and frees associated memory
|
|
|
|
!> @details explicit interface to reset list. Triggers final statement (and following chain reaction)
|
|
|
|
!--------------------------------------------------------------------------------------------------
|
|
|
|
subroutine free(this)
|
|
|
|
|
|
|
|
class(tPartitionedStringList), intent(inout) :: this
|
|
|
|
|
|
|
|
if(associated(this%next)) deallocate(this%next)
|
|
|
|
|
|
|
|
end subroutine free
|
|
|
|
|
|
|
|
|
|
|
|
!--------------------------------------------------------------------------------------------------
|
|
|
|
!> @brief empties list and frees associated memory
|
|
|
|
!> @details called when variable goes out of scope. Triggers chain reaction for list
|
|
|
|
!--------------------------------------------------------------------------------------------------
|
|
|
|
recursive subroutine finalize(this)
|
|
|
|
|
|
|
|
type(tPartitionedStringList), intent(inout) :: this
|
|
|
|
|
|
|
|
if(associated(this%next)) deallocate(this%next)
|
|
|
|
|
|
|
|
end subroutine finalize
|
|
|
|
|
|
|
|
|
|
|
|
!--------------------------------------------------------------------------------------------------
|
|
|
|
!> @brief cleans entire array of linke lists
|
|
|
|
!> @details called when variable goes out of scope and deallocates the list at each array entry
|
|
|
|
!--------------------------------------------------------------------------------------------------
|
|
|
|
subroutine finalizeArray(this)
|
|
|
|
|
|
|
|
integer :: i
|
|
|
|
type(tPartitionedStringList), intent(inout), dimension(:) :: this
|
|
|
|
type(tPartitionedStringList), pointer :: temp ! bug in Gfortran?
|
|
|
|
|
|
|
|
do i=1, size(this)
|
|
|
|
if (associated(this(i)%next)) then
|
|
|
|
temp => this(i)%next
|
|
|
|
!deallocate(this(i)) !internal compiler error: in gfc_build_final_call, at fortran/trans.c:975
|
|
|
|
deallocate(temp)
|
|
|
|
endif
|
|
|
|
enddo
|
|
|
|
|
|
|
|
end subroutine finalizeArray
|
|
|
|
|
|
|
|
|
|
|
|
!--------------------------------------------------------------------------------------------------
|
|
|
|
!> @brief reports wether a given key (string value at first position) exists in the list
|
|
|
|
!--------------------------------------------------------------------------------------------------
|
|
|
|
logical function keyExists(this,key)
|
|
|
|
|
|
|
|
class(tPartitionedStringList), target, intent(in) :: this
|
|
|
|
character(len=*), intent(in) :: key
|
|
|
|
type(tPartitionedStringList), pointer :: item
|
|
|
|
|
|
|
|
keyExists = .false.
|
|
|
|
|
|
|
|
item => this
|
|
|
|
do while (associated(item%next) .and. .not. keyExists)
|
|
|
|
keyExists = trim(IO_stringValue(item%string%val,item%string%pos,1)) == trim(key)
|
|
|
|
item => item%next
|
|
|
|
enddo
|
|
|
|
|
|
|
|
end function keyExists
|
|
|
|
|
|
|
|
|
|
|
|
!--------------------------------------------------------------------------------------------------
|
|
|
|
!> @brief count number of key appearances
|
|
|
|
!> @details traverses list and counts each occurrence of specified key
|
|
|
|
!--------------------------------------------------------------------------------------------------
|
|
|
|
integer function countKeys(this,key)
|
|
|
|
|
|
|
|
class(tPartitionedStringList), target, intent(in) :: this
|
|
|
|
character(len=*), intent(in) :: key
|
|
|
|
type(tPartitionedStringList), pointer :: item
|
|
|
|
|
|
|
|
countKeys = 0
|
|
|
|
|
|
|
|
item => this
|
|
|
|
do while (associated(item%next))
|
|
|
|
if (trim(IO_stringValue(item%string%val,item%string%pos,1)) == trim(key)) &
|
|
|
|
countKeys = countKeys + 1
|
|
|
|
item => item%next
|
|
|
|
enddo
|
|
|
|
|
|
|
|
end function countKeys
|
|
|
|
|
|
|
|
|
|
|
|
!--------------------------------------------------------------------------------------------------
|
|
|
|
!> @brief gets float value of for a given key from a linked list
|
|
|
|
!> @details gets the last value if the key occurs more than once. If key is not found exits with
|
|
|
|
!! error unless default is given
|
|
|
|
!--------------------------------------------------------------------------------------------------
|
|
|
|
real(pReal) function getFloat(this,key,defaultVal)
|
|
|
|
|
|
|
|
class(tPartitionedStringList), target, intent(in) :: this
|
|
|
|
character(len=*), intent(in) :: key
|
|
|
|
real(pReal), intent(in), optional :: defaultVal
|
|
|
|
type(tPartitionedStringList), pointer :: item
|
|
|
|
logical :: found
|
2019-03-28 11:22:17 +05:30
|
|
|
|
|
|
|
getFloat = huge(1.0) ! suppress warning about unitialized value
|
2019-03-24 16:10:05 +05:30
|
|
|
found = present(defaultVal)
|
|
|
|
if (found) getFloat = defaultVal
|
|
|
|
|
|
|
|
item => this
|
|
|
|
do while (associated(item%next))
|
|
|
|
if (trim(IO_stringValue(item%string%val,item%string%pos,1)) == trim(key)) then
|
|
|
|
found = .true.
|
|
|
|
if (item%string%pos(1) < 2) call IO_error(143,ext_msg=key)
|
|
|
|
getFloat = IO_FloatValue(item%string%val,item%string%pos,2)
|
|
|
|
endif
|
|
|
|
item => item%next
|
|
|
|
enddo
|
|
|
|
|
|
|
|
if (.not. found) call IO_error(140,ext_msg=key)
|
|
|
|
|
|
|
|
end function getFloat
|
|
|
|
|
|
|
|
|
|
|
|
!--------------------------------------------------------------------------------------------------
|
|
|
|
!> @brief gets integer value of for a given key from a linked list
|
|
|
|
!> @details gets the last value if the key occurs more than once. If key is not found exits with
|
|
|
|
!! error unless default is given
|
|
|
|
!--------------------------------------------------------------------------------------------------
|
|
|
|
integer function getInt(this,key,defaultVal)
|
|
|
|
|
|
|
|
class(tPartitionedStringList), target, intent(in) :: this
|
|
|
|
character(len=*), intent(in) :: key
|
|
|
|
integer, intent(in), optional :: defaultVal
|
|
|
|
type(tPartitionedStringList), pointer :: item
|
|
|
|
logical :: found
|
|
|
|
|
2019-03-28 11:22:17 +05:30
|
|
|
getInt = huge(1) ! suppress warning about unitialized value
|
2019-03-24 16:10:05 +05:30
|
|
|
found = present(defaultVal)
|
|
|
|
if (found) getInt = defaultVal
|
|
|
|
|
|
|
|
item => this
|
|
|
|
do while (associated(item%next))
|
|
|
|
if (trim(IO_stringValue(item%string%val,item%string%pos,1)) == trim(key)) then
|
|
|
|
found = .true.
|
|
|
|
if (item%string%pos(1) < 2) call IO_error(143,ext_msg=key)
|
|
|
|
getInt = IO_IntValue(item%string%val,item%string%pos,2)
|
|
|
|
endif
|
|
|
|
item => item%next
|
|
|
|
enddo
|
|
|
|
|
|
|
|
if (.not. found) call IO_error(140,ext_msg=key)
|
|
|
|
|
|
|
|
end function getInt
|
|
|
|
|
|
|
|
|
|
|
|
!--------------------------------------------------------------------------------------------------
|
|
|
|
!> @brief gets string value of for a given key from a linked list
|
|
|
|
!> @details gets the last value if the key occurs more than once. If key is not found exits with
|
|
|
|
!! error unless default is given. If raw is true, the the complete string is returned, otherwise
|
|
|
|
!! the individual chunks are returned
|
|
|
|
!--------------------------------------------------------------------------------------------------
|
2019-12-21 14:37:37 +05:30
|
|
|
character(len=pStringLen) function getString(this,key,defaultVal,raw)
|
2019-03-24 16:10:05 +05:30
|
|
|
|
|
|
|
class(tPartitionedStringList), target, intent(in) :: this
|
|
|
|
character(len=*), intent(in) :: key
|
2019-03-28 11:34:48 +05:30
|
|
|
character(len=*), intent(in), optional :: defaultVal
|
2019-03-24 16:10:05 +05:30
|
|
|
logical, intent(in), optional :: raw
|
|
|
|
type(tPartitionedStringList), pointer :: item
|
|
|
|
logical :: found, &
|
|
|
|
whole
|
|
|
|
if (present(raw)) then
|
|
|
|
whole = raw
|
|
|
|
else
|
|
|
|
whole = .false.
|
|
|
|
endif
|
|
|
|
|
|
|
|
found = present(defaultVal)
|
|
|
|
if (found) then
|
2019-03-28 11:34:48 +05:30
|
|
|
if (len_trim(defaultVal) > len(getString)) call IO_error(0,ext_msg='getString')
|
2019-03-24 16:10:05 +05:30
|
|
|
getString = trim(defaultVal)
|
|
|
|
endif
|
|
|
|
|
|
|
|
item => this
|
|
|
|
do while (associated(item%next))
|
|
|
|
if (trim(IO_stringValue(item%string%val,item%string%pos,1)) == trim(key)) then
|
|
|
|
found = .true.
|
|
|
|
if (item%string%pos(1) < 2) call IO_error(143,ext_msg=key)
|
|
|
|
|
|
|
|
if (whole) then
|
|
|
|
getString = trim(item%string%val(item%string%pos(4):)) ! raw string starting a second chunk
|
|
|
|
else
|
|
|
|
getString = IO_StringValue(item%string%val,item%string%pos,2)
|
|
|
|
endif
|
|
|
|
endif
|
|
|
|
item => item%next
|
|
|
|
enddo
|
|
|
|
|
|
|
|
if (.not. found) call IO_error(140,ext_msg=key)
|
|
|
|
|
|
|
|
end function getString
|
|
|
|
|
|
|
|
|
|
|
|
!--------------------------------------------------------------------------------------------------
|
|
|
|
!> @brief gets array of float values of for a given key from a linked list
|
|
|
|
!> @details for cumulative keys, "()", values from all occurrences are return. Otherwise only all
|
|
|
|
!! values from the last occurrence. If key is not found exits with error unless default is given.
|
|
|
|
!--------------------------------------------------------------------------------------------------
|
|
|
|
function getFloats(this,key,defaultVal,requiredSize)
|
|
|
|
|
|
|
|
real(pReal), dimension(:), allocatable :: getFloats
|
|
|
|
class(tPartitionedStringList), target, intent(in) :: this
|
|
|
|
character(len=*), intent(in) :: key
|
|
|
|
real(pReal), dimension(:), intent(in), optional :: defaultVal
|
|
|
|
integer, intent(in), optional :: requiredSize
|
|
|
|
type(tPartitionedStringList), pointer :: item
|
|
|
|
integer :: i
|
|
|
|
logical :: found, &
|
|
|
|
cumulative
|
|
|
|
|
|
|
|
cumulative = (key(1:1) == '(' .and. key(len_trim(key):len_trim(key)) == ')')
|
|
|
|
found = .false.
|
|
|
|
|
|
|
|
allocate(getFloats(0))
|
|
|
|
|
|
|
|
item => this
|
|
|
|
do while (associated(item%next))
|
|
|
|
if (trim(IO_stringValue(item%string%val,item%string%pos,1)) == trim(key)) then
|
|
|
|
found = .true.
|
|
|
|
if (.not. cumulative) getFloats = [real(pReal)::]
|
|
|
|
if (item%string%pos(1) < 2) call IO_error(143,ext_msg=key)
|
|
|
|
do i = 2, item%string%pos(1)
|
|
|
|
getFloats = [getFloats,IO_FloatValue(item%string%val,item%string%pos,i)]
|
|
|
|
enddo
|
|
|
|
endif
|
|
|
|
item => item%next
|
|
|
|
enddo
|
|
|
|
|
|
|
|
if (.not. found) then
|
|
|
|
if (present(defaultVal)) then; getFloats = defaultVal; else; call IO_error(140,ext_msg=key); endif
|
|
|
|
endif
|
|
|
|
if (present(requiredSize)) then
|
|
|
|
if(requiredSize /= size(getFloats)) call IO_error(146,ext_msg=key)
|
|
|
|
endif
|
|
|
|
|
|
|
|
end function getFloats
|
|
|
|
|
|
|
|
|
|
|
|
!--------------------------------------------------------------------------------------------------
|
|
|
|
!> @brief gets array of integer values of for a given key from a linked list
|
|
|
|
!> @details for cumulative keys, "()", values from all occurrences are return. Otherwise only all
|
|
|
|
!! values from the last occurrence. If key is not found exits with error unless default is given.
|
|
|
|
!--------------------------------------------------------------------------------------------------
|
|
|
|
function getInts(this,key,defaultVal,requiredSize)
|
|
|
|
|
|
|
|
integer, dimension(:), allocatable :: getInts
|
|
|
|
class(tPartitionedStringList), target, intent(in) :: this
|
|
|
|
character(len=*), intent(in) :: key
|
|
|
|
integer, dimension(:), intent(in), optional :: defaultVal
|
|
|
|
integer, intent(in), optional :: requiredSize
|
|
|
|
type(tPartitionedStringList), pointer :: item
|
|
|
|
integer :: i
|
|
|
|
logical :: found, &
|
|
|
|
cumulative
|
|
|
|
|
|
|
|
cumulative = (key(1:1) == '(' .and. key(len_trim(key):len_trim(key)) == ')')
|
|
|
|
found = .false.
|
|
|
|
|
|
|
|
allocate(getInts(0))
|
|
|
|
|
|
|
|
item => this
|
|
|
|
do while (associated(item%next))
|
|
|
|
if (trim(IO_stringValue(item%string%val,item%string%pos,1)) == trim(key)) then
|
|
|
|
found = .true.
|
|
|
|
if (.not. cumulative) getInts = [integer::]
|
|
|
|
if (item%string%pos(1) < 2) call IO_error(143,ext_msg=key)
|
|
|
|
do i = 2, item%string%pos(1)
|
|
|
|
getInts = [getInts,IO_IntValue(item%string%val,item%string%pos,i)]
|
|
|
|
enddo
|
|
|
|
endif
|
|
|
|
item => item%next
|
|
|
|
enddo
|
|
|
|
|
|
|
|
if (.not. found) then
|
|
|
|
if (present(defaultVal)) then; getInts = defaultVal; else; call IO_error(140,ext_msg=key); endif
|
|
|
|
endif
|
|
|
|
if (present(requiredSize)) then
|
|
|
|
if(requiredSize /= size(getInts)) call IO_error(146,ext_msg=key)
|
|
|
|
endif
|
|
|
|
|
|
|
|
end function getInts
|
|
|
|
|
|
|
|
|
|
|
|
!--------------------------------------------------------------------------------------------------
|
|
|
|
!> @brief gets array of string values of for a given key from a linked list
|
|
|
|
!> @details for cumulative keys, "()", values from all occurrences are return. Otherwise only all
|
|
|
|
!! values from the last occurrence. If key is not found exits with error unless default is given.
|
|
|
|
!! If raw is true, the the complete string is returned, otherwise the individual chunks are returned
|
|
|
|
!--------------------------------------------------------------------------------------------------
|
|
|
|
function getStrings(this,key,defaultVal,raw)
|
|
|
|
|
2019-12-21 14:37:37 +05:30
|
|
|
character(len=pStringLen),dimension(:), allocatable :: getStrings
|
2019-03-28 11:34:48 +05:30
|
|
|
class(tPartitionedStringList),target, intent(in) :: this
|
|
|
|
character(len=*), intent(in) :: key
|
|
|
|
character(len=*), dimension(:), intent(in), optional :: defaultVal
|
|
|
|
logical, intent(in), optional :: raw
|
|
|
|
type(tPartitionedStringList), pointer :: item
|
2019-12-21 14:37:37 +05:30
|
|
|
character(len=pStringLen) :: str
|
2019-03-28 11:34:48 +05:30
|
|
|
integer :: i
|
|
|
|
logical :: found, &
|
|
|
|
whole, &
|
|
|
|
cumulative
|
2019-03-24 16:10:05 +05:30
|
|
|
|
|
|
|
cumulative = (key(1:1) == '(' .and. key(len_trim(key):len_trim(key)) == ')')
|
|
|
|
if (present(raw)) then
|
|
|
|
whole = raw
|
|
|
|
else
|
|
|
|
whole = .false.
|
|
|
|
endif
|
|
|
|
found = .false.
|
|
|
|
|
|
|
|
item => this
|
|
|
|
do while (associated(item%next))
|
|
|
|
if (trim(IO_stringValue(item%string%val,item%string%pos,1)) == trim(key)) then
|
|
|
|
found = .true.
|
|
|
|
if (allocated(getStrings) .and. .not. cumulative) deallocate(getStrings)
|
|
|
|
if (item%string%pos(1) < 2) call IO_error(143,ext_msg=key)
|
|
|
|
|
|
|
|
notAllocated: if (.not. allocated(getStrings)) then
|
|
|
|
if (whole) then
|
|
|
|
str = item%string%val(item%string%pos(4):)
|
|
|
|
getStrings = [str]
|
|
|
|
else
|
|
|
|
str = IO_StringValue(item%string%val,item%string%pos,2)
|
|
|
|
allocate(getStrings(1),source=str)
|
|
|
|
do i=3,item%string%pos(1)
|
|
|
|
str = IO_StringValue(item%string%val,item%string%pos,i)
|
|
|
|
getStrings = [getStrings,str]
|
|
|
|
enddo
|
|
|
|
endif
|
|
|
|
else notAllocated
|
|
|
|
if (whole) then
|
|
|
|
str = item%string%val(item%string%pos(4):)
|
|
|
|
getStrings = [getStrings,str]
|
|
|
|
else
|
|
|
|
do i=2,item%string%pos(1)
|
|
|
|
str = IO_StringValue(item%string%val,item%string%pos,i)
|
|
|
|
getStrings = [getStrings,str]
|
|
|
|
enddo
|
|
|
|
endif
|
|
|
|
endif notAllocated
|
|
|
|
endif
|
|
|
|
item => item%next
|
|
|
|
enddo
|
|
|
|
|
|
|
|
if (.not. found) then
|
2019-03-28 11:34:48 +05:30
|
|
|
if (present(defaultVal)) then
|
|
|
|
if (len(defaultVal) > len(getStrings)) call IO_error(0,ext_msg='getStrings')
|
|
|
|
getStrings = defaultVal
|
|
|
|
else
|
|
|
|
call IO_error(140,ext_msg=key)
|
|
|
|
endif
|
2019-03-24 16:10:05 +05:30
|
|
|
endif
|
|
|
|
|
|
|
|
end function getStrings
|
|
|
|
|
|
|
|
|
|
|
|
end module list
|