mirror of
https://github.com/openmc-dev/openmc.git
synced 2026-07-29 06:35:48 -04:00
Added rewritten dictionary, list, and set modules. Need refactor.
This commit is contained in:
parent
c03f94cc86
commit
3c51315c33
5 changed files with 1000 additions and 0 deletions
|
|
@ -242,6 +242,8 @@ interpolation.o: global.o
|
|||
interpolation.o: search.o
|
||||
interpolation.o: string.o
|
||||
|
||||
list_header.o: constants.o
|
||||
|
||||
main.o: constants.o
|
||||
main.o: eigenvalue.o
|
||||
main.o: finalize.o
|
||||
|
|
@ -312,6 +314,8 @@ random_lcg.o: global.o
|
|||
search.o: error.o
|
||||
search.o: global.o
|
||||
|
||||
set_header.o: list_header.o
|
||||
|
||||
source.o: bank_header.o
|
||||
source.o: constants.o
|
||||
source.o: error.o
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ constants.o \
|
|||
cross_section.o \
|
||||
datatypes.o \
|
||||
datatypes_header.o \
|
||||
dict_header.o \
|
||||
doppler.o \
|
||||
eigenvalue.o \
|
||||
endf.o \
|
||||
|
|
@ -33,6 +34,7 @@ hdf5_interface.o \
|
|||
initialize.o \
|
||||
interpolation.o \
|
||||
input_xml.o \
|
||||
list_header.o \
|
||||
main.o \
|
||||
material_header.o \
|
||||
math.o \
|
||||
|
|
@ -46,6 +48,7 @@ plot_header.o \
|
|||
ppmlib.o \
|
||||
random_lcg.o \
|
||||
search.o \
|
||||
set_header.o \
|
||||
source.o \
|
||||
source_header.o \
|
||||
state_point.o \
|
||||
|
|
|
|||
418
src/dict_header.F90
Normal file
418
src/dict_header.F90
Normal file
|
|
@ -0,0 +1,418 @@
|
|||
module dict_header
|
||||
|
||||
!===============================================================================
|
||||
! DICT_HEADER module
|
||||
!
|
||||
! This module provides an implementation of a dictionary that has (key,value)
|
||||
! pairs. This data structure is used to provide lookup features, e.g. cells and
|
||||
! surfaces by name.
|
||||
!
|
||||
! The original version was roughly based on capabilities in the 'flibs' open
|
||||
! source package. However, it was rewritten from scratch so that it could be
|
||||
! used stand-alone without relying on the implementation of lists. As with
|
||||
! lists, it was considered writing a single dictionary used unlimited
|
||||
! polymorphism, but again compiler support is spotty and doesn't always prevent
|
||||
! duplication of code.
|
||||
!===============================================================================
|
||||
|
||||
implicit none
|
||||
|
||||
integer, parameter, private :: HASH_SIZE = 4993
|
||||
integer, parameter, private :: HASH_MULTIPLIER = 31
|
||||
integer, parameter, private :: DICT_NULL = -huge(0)
|
||||
integer, parameter :: DICT_KEY_LENGTH = 255
|
||||
|
||||
!===============================================================================
|
||||
! ELEMKEYVALUE* contains (key,value) pairs and a pointer to the next (key,value)
|
||||
! pair
|
||||
!===============================================================================
|
||||
|
||||
type ElemKeyValueCI
|
||||
type(ElemKeyValueCI), pointer :: next => null()
|
||||
character(len=DICT_KEY_LENGTH) :: key
|
||||
integer :: value
|
||||
end type ElemKeyValueCI
|
||||
|
||||
type ElemKeyValueII
|
||||
type(ElemKeyValueII), pointer :: next => null()
|
||||
integer :: key
|
||||
integer :: value
|
||||
end type ElemKeyValueII
|
||||
|
||||
!===============================================================================
|
||||
! HASHLIST* types contain a single pointer to a linked list of (key,value)
|
||||
! pairs. This type is necesssary so that the Dict types can be dynamically
|
||||
! allocated.
|
||||
!===============================================================================
|
||||
|
||||
type, private :: HashListCI
|
||||
type(ElemKeyValueCI), pointer :: list => null()
|
||||
end type HashListCI
|
||||
|
||||
type, private :: HashListII
|
||||
type(ElemKeyValueII), pointer :: list => null()
|
||||
end type HashListII
|
||||
|
||||
!===============================================================================
|
||||
! DICT* is a dictionary of (key,value) pairs with convenience methods as
|
||||
! type-bound procedures. DictCharInt has character(*) keys and integer values,
|
||||
! and DictIntInt has integer keys and values.
|
||||
!===============================================================================
|
||||
|
||||
type, public :: DictCharInt
|
||||
private
|
||||
type(HashListCI), pointer :: table(:) => null()
|
||||
contains
|
||||
procedure :: add_key => dict_add_key_ci
|
||||
procedure :: delete => dict_delete_ci
|
||||
procedure :: get_key => dict_get_key_ci
|
||||
procedure :: has_key => dict_has_key_ci
|
||||
procedure, private :: get_elem => dict_get_elem_ci
|
||||
end type DictCharInt
|
||||
|
||||
type, public :: DictIntInt
|
||||
private
|
||||
type(HashListII), pointer :: table(:) => null()
|
||||
contains
|
||||
procedure :: add_key => dict_add_key_ii
|
||||
procedure :: delete => dict_delete_ii
|
||||
procedure :: get_key => dict_get_key_ii
|
||||
procedure :: has_key => dict_has_key_ii
|
||||
procedure, private :: get_elem => dict_get_elem_ii
|
||||
end type DictIntInt
|
||||
|
||||
contains
|
||||
|
||||
!===============================================================================
|
||||
! DICT_ADD_KEY adds a (key,value) entry to a dictionary. If the key is already
|
||||
! in the dictionary, the value is replaced by the new specified value.
|
||||
!===============================================================================
|
||||
|
||||
subroutine dict_add_key_ci(this, key, value)
|
||||
|
||||
class(DictCharInt) :: this
|
||||
character(*), intent(in) :: key
|
||||
integer, intent(in) :: value
|
||||
|
||||
integer :: hash
|
||||
type(ElemKeyValueCI), pointer :: elem => null()
|
||||
type(ElemKeyValueCI), pointer :: new_elem => null()
|
||||
|
||||
elem => this % get_elem(key)
|
||||
|
||||
if (associated(elem)) then
|
||||
elem % value = value
|
||||
else
|
||||
! Get hash
|
||||
hash = dict_hash_key_ci(key)
|
||||
|
||||
! Create new element
|
||||
allocate(new_elem)
|
||||
new_elem % key = key
|
||||
new_elem % value = value
|
||||
|
||||
! Add element to front of list
|
||||
new_elem % next => this % table(hash) % list
|
||||
this % table(hash) % list => new_elem
|
||||
end if
|
||||
|
||||
end subroutine dict_add_key_ci
|
||||
|
||||
subroutine dict_add_key_ii(this, key, value)
|
||||
|
||||
class(DictIntInt) :: this
|
||||
integer, intent(in) :: key
|
||||
integer, intent(in) :: value
|
||||
|
||||
integer :: hash
|
||||
type(ElemKeyValueII), pointer :: elem => null()
|
||||
type(ElemKeyValueII), pointer :: new_elem => null()
|
||||
|
||||
elem => this % get_elem(key)
|
||||
|
||||
if (associated(elem)) then
|
||||
elem % value = value
|
||||
else
|
||||
! Get hash
|
||||
hash = dict_hash_key_ii(key)
|
||||
|
||||
! Create new element
|
||||
allocate(new_elem)
|
||||
new_elem % key = key
|
||||
new_elem % value = value
|
||||
|
||||
! Add element to front of list
|
||||
new_elem % next => this % table(hash) % list
|
||||
this % table(hash) % list => new_elem
|
||||
end if
|
||||
|
||||
end subroutine dict_add_key_ii
|
||||
|
||||
!===============================================================================
|
||||
! DICT_DELETE deletes all (key,value) pairs from the dictionary
|
||||
!===============================================================================
|
||||
|
||||
subroutine dict_delete_ci(this)
|
||||
|
||||
class(DictCharInt) :: this
|
||||
|
||||
integer :: i
|
||||
type(ElemKeyValueCI), pointer :: current
|
||||
type(ElemKeyValueCI), pointer :: next
|
||||
|
||||
if (associated(this % table)) then
|
||||
do i = 1, size(this % table)
|
||||
current => this % table(i) % list
|
||||
do while (associated(current))
|
||||
next => current % next
|
||||
deallocate(current)
|
||||
current => next
|
||||
end do
|
||||
nullify(this % table(i) % list)
|
||||
end do
|
||||
end if
|
||||
|
||||
end subroutine dict_delete_ci
|
||||
|
||||
subroutine dict_delete_ii(this)
|
||||
|
||||
class(DictIntInt) :: this
|
||||
|
||||
integer :: i
|
||||
type(ElemKeyValueII), pointer :: current
|
||||
type(ElemKeyValueII), pointer :: next
|
||||
|
||||
if (associated(this % table)) then
|
||||
do i = 1, size(this % table)
|
||||
current => this % table(i) % list
|
||||
do while (associated(current))
|
||||
next => current % next
|
||||
deallocate(current)
|
||||
current => next
|
||||
end do
|
||||
nullify(this % table(i) % list)
|
||||
end do
|
||||
end if
|
||||
|
||||
end subroutine dict_delete_ii
|
||||
|
||||
!===============================================================================
|
||||
! DICT_GET_KEY returns the value matching a given key. If the dictionary does
|
||||
! not contain the key, the value DICT_NULL is returned.
|
||||
!===============================================================================
|
||||
|
||||
function dict_get_key_ci(this, key) result(value)
|
||||
|
||||
class(DictCharInt) :: this
|
||||
character(*), intent(in) :: key
|
||||
integer :: value
|
||||
|
||||
type(ElemKeyValueCI), pointer :: elem
|
||||
|
||||
elem => this % get_elem(key)
|
||||
|
||||
if (associated(elem)) then
|
||||
value = elem % value
|
||||
else
|
||||
value = DICT_NULL
|
||||
end if
|
||||
|
||||
end function dict_get_key_ci
|
||||
|
||||
function dict_get_key_ii(this, key) result(value)
|
||||
|
||||
class(DictIntInt) :: this
|
||||
integer, intent(in) :: key
|
||||
integer :: value
|
||||
|
||||
type(ElemKeyValueII), pointer :: elem
|
||||
|
||||
elem => this % get_elem(key)
|
||||
|
||||
if (associated(elem)) then
|
||||
value = elem % value
|
||||
else
|
||||
value = DICT_NULL
|
||||
end if
|
||||
|
||||
end function dict_get_key_ii
|
||||
|
||||
!===============================================================================
|
||||
! DICT_HAS_KEY determines whether a dictionary has a (key,value) pair with a
|
||||
! given key.
|
||||
!===============================================================================
|
||||
|
||||
function dict_has_key_ci(this, key) result(has)
|
||||
|
||||
class(DictCharInt) :: this
|
||||
character(*), intent(in) :: key
|
||||
logical :: has
|
||||
|
||||
type(ElemKeyValueCI), pointer :: elem
|
||||
|
||||
elem => this % get_elem(key)
|
||||
has = associated(elem)
|
||||
|
||||
end function dict_has_key_ci
|
||||
|
||||
function dict_has_key_ii(this, key) result(has)
|
||||
|
||||
class(DictIntInt) :: this
|
||||
integer, intent(in) :: key
|
||||
logical :: has
|
||||
|
||||
type(ElemKeyValueII), pointer :: elem
|
||||
|
||||
elem => this % get_elem(key)
|
||||
has = associated(elem)
|
||||
|
||||
end function dict_has_key_ii
|
||||
|
||||
!===============================================================================
|
||||
! DICT_GET_ELEM returns a pointer to the (key,value) pair for a given key. This
|
||||
! method is private.
|
||||
!===============================================================================
|
||||
|
||||
function dict_get_elem_ci(this, key) result(elem)
|
||||
|
||||
class(DictCharInt) :: this
|
||||
character(*), intent(in) :: key
|
||||
type(ElemKeyValueCI), pointer :: elem
|
||||
|
||||
integer :: hash
|
||||
|
||||
! Check for dictionary not being allocated
|
||||
if (.not. associated(this % table)) then
|
||||
allocate(this % table(HASH_SIZE))
|
||||
end if
|
||||
|
||||
hash = dict_hash_key_ci(key)
|
||||
elem => this % table(hash) % list
|
||||
do while (associated(elem))
|
||||
if (elem % key == key) exit
|
||||
elem => elem % next
|
||||
end do
|
||||
|
||||
end function dict_get_elem_ci
|
||||
|
||||
function dict_get_elem_ii(this, key) result(elem)
|
||||
|
||||
class(DictIntInt) :: this
|
||||
integer, intent(in) :: key
|
||||
type(ElemKeyValueII), pointer :: elem
|
||||
|
||||
integer :: hash
|
||||
|
||||
! Check for dictionary not being allocated
|
||||
if (.not. associated(this % table)) then
|
||||
allocate(this % table(HASH_SIZE))
|
||||
end if
|
||||
|
||||
hash = dict_hash_key_ii(key)
|
||||
elem => this % table(hash) % list
|
||||
do while (associated(elem))
|
||||
if (elem % key == key) exit
|
||||
elem => elem % next
|
||||
end do
|
||||
|
||||
end function dict_get_elem_ii
|
||||
|
||||
!===============================================================================
|
||||
! DICT_HASH_KEY returns the hash value for a given key
|
||||
!===============================================================================
|
||||
|
||||
function dict_hash_key_ci(key) result(val)
|
||||
|
||||
character(*), intent(in) :: key
|
||||
integer :: val
|
||||
|
||||
integer :: i
|
||||
|
||||
val = 0
|
||||
|
||||
do i = 1, len_trim(key)
|
||||
val = HASH_MULTIPLIER * val + ichar(key(i:i))
|
||||
end do
|
||||
|
||||
! Added the absolute val on val-1 since the sum in the do loop is
|
||||
! susceptible to integer overflow
|
||||
val = 1 + mod(abs(val-1), HASH_SIZE)
|
||||
|
||||
end function dict_hash_key_ci
|
||||
|
||||
function dict_hash_key_ii(key) result(val)
|
||||
|
||||
integer, intent(in) :: key
|
||||
integer :: val
|
||||
|
||||
val = 0
|
||||
|
||||
! Added the absolute val on val-1 since the sum in the do loop is
|
||||
! susceptible to integer overflow
|
||||
val = 1 + mod(abs(key-1), HASH_SIZE)
|
||||
|
||||
end function dict_hash_key_ii
|
||||
|
||||
!===============================================================================
|
||||
! DICT_KEYS returns a pointer to a linked list containig the (key,values)
|
||||
!===============================================================================
|
||||
|
||||
function dict_keys_ci(this) result(head)
|
||||
|
||||
class(DictCharInt) :: this
|
||||
type(ElemKeyValueCI), pointer :: head
|
||||
type(ElemKeyValueCI), pointer :: current => null()
|
||||
type(ElemKeyValueCI), pointer :: elem => null()
|
||||
|
||||
integer :: i
|
||||
|
||||
head => null()
|
||||
|
||||
do i = 1, size(this % table)
|
||||
elem => this % table(i) % list
|
||||
do while (associated(elem))
|
||||
if (.not. associated(head)) then
|
||||
allocate(head)
|
||||
current => head
|
||||
else
|
||||
allocate(current % next)
|
||||
current => current % next
|
||||
end if
|
||||
current % key = elem % key
|
||||
current % value = elem % value
|
||||
elem => elem % next
|
||||
end do
|
||||
end do
|
||||
|
||||
end function dict_keys_ci
|
||||
|
||||
function dict_keys_ii(this) result(head)
|
||||
|
||||
class(DictIntInt) :: this
|
||||
type(ElemKeyValueII), pointer :: head
|
||||
type(ElemKeyValueII), pointer :: current => null()
|
||||
type(ElemKeyValueII), pointer :: elem => null()
|
||||
|
||||
integer :: i
|
||||
|
||||
head => null()
|
||||
|
||||
do i = 1, size(this % table)
|
||||
elem => this % table(i) % list
|
||||
do while (associated(elem))
|
||||
if (.not. associated(head)) then
|
||||
allocate(head)
|
||||
current => head
|
||||
else
|
||||
allocate(current % next)
|
||||
current => current % next
|
||||
end if
|
||||
current % key = elem % key
|
||||
current % value = elem % value
|
||||
elem => elem%next
|
||||
end do
|
||||
end do
|
||||
|
||||
end function dict_keys_ii
|
||||
|
||||
end module dict_header
|
||||
474
src/list_header.F90
Normal file
474
src/list_header.F90
Normal file
|
|
@ -0,0 +1,474 @@
|
|||
module list_header
|
||||
|
||||
!===============================================================================
|
||||
! LIST_HEADER module
|
||||
!
|
||||
! This module contains a linked list structure with convenience methods such as
|
||||
! append, contains, remove, index, get_item, size, etc. This is an updated
|
||||
! implementation with type-bound procedures (F2003).
|
||||
!===============================================================================
|
||||
|
||||
use constants, only: ERROR_INT, ERROR_REAL
|
||||
|
||||
implicit none
|
||||
|
||||
!===============================================================================
|
||||
! LISTELEM* types hold one piece of data and a pointer to the next piece of data
|
||||
!===============================================================================
|
||||
|
||||
type :: ListElemInt
|
||||
integer :: data
|
||||
type(ListElemInt), pointer :: next => null()
|
||||
end type ListElemInt
|
||||
|
||||
type :: ListElemReal
|
||||
real(8) :: data
|
||||
type(ListElemReal), pointer :: next => null()
|
||||
end type ListElemReal
|
||||
|
||||
!===============================================================================
|
||||
! LIST* types contain the linked list with convenience methods. We originally
|
||||
! considered using unlimited polymorphism to provide a single type, but compiler
|
||||
! support is still spotty, and in many cases it doesn't prevent duplication of
|
||||
! code. For the time being, a separate derived type exists for each datatype.
|
||||
!===============================================================================
|
||||
|
||||
type, public :: ListInt
|
||||
private
|
||||
integer :: count = 0 ! Number of elements in list
|
||||
|
||||
! Used in get_item for fast sequential lookups
|
||||
integer :: last_index = huge(0)
|
||||
type(ListElemInt), pointer :: last_elem => null()
|
||||
|
||||
! Pointers to beginning and end of list
|
||||
type(ListElemInt), public, pointer :: head => null()
|
||||
type(ListElemInt), public, pointer :: tail => null()
|
||||
contains
|
||||
procedure :: append => list_append_int ! Add item to end of list
|
||||
procedure :: contains => list_contains_int ! Does list contain?
|
||||
procedure :: get_item => list_get_item_int ! Get i-th item in list
|
||||
procedure :: index => list_index_int ! Determine index of given item
|
||||
procedure :: insert => list_insert_int ! Insert item in i-th position
|
||||
procedure :: remove => list_remove_int ! Remove specified item
|
||||
procedure :: size => list_size_int ! Size of list
|
||||
end type ListInt
|
||||
|
||||
type, public :: ListReal
|
||||
private
|
||||
integer :: count = 0 ! Number of elements in list
|
||||
|
||||
! Used in get_item for fast sequential lookups
|
||||
integer :: last_index = huge(0)
|
||||
type(ListElemReal), pointer :: last_elem => null()
|
||||
|
||||
! Pointers to beginning and end of list
|
||||
type(ListElemReal), public, pointer :: head => null()
|
||||
type(ListElemReal), public, pointer :: tail => null()
|
||||
contains
|
||||
procedure :: append => list_append_real ! Add item to end of list
|
||||
procedure :: contains => list_contains_real ! Does list contain?
|
||||
procedure :: get_item => list_get_item_real ! Get i-th item in list
|
||||
procedure :: index => list_index_real ! Determine index of given item
|
||||
procedure :: insert => list_insert_real ! Insert item in i-th position
|
||||
procedure :: remove => list_remove_real ! Remove specified item
|
||||
procedure :: size => list_size_real ! Size of list
|
||||
end type ListReal
|
||||
|
||||
contains
|
||||
|
||||
!===============================================================================
|
||||
! LIST_APPEND appends an item to the end of the list. If the list is empty, it
|
||||
! becomes the first item.
|
||||
!===============================================================================
|
||||
|
||||
subroutine list_append_int(this, data)
|
||||
class(ListInt) :: this
|
||||
integer :: data
|
||||
|
||||
type(ListElemInt), pointer :: elem
|
||||
|
||||
! Create element and set dat
|
||||
allocate(elem)
|
||||
elem % data = data
|
||||
|
||||
if (.not. associated(this % head)) then
|
||||
! If list is empty, set head and tail to new element
|
||||
this % head => elem
|
||||
this % tail => elem
|
||||
else
|
||||
! Otherwise append element at end of list
|
||||
this % tail % next => elem
|
||||
this % tail => this % tail % next
|
||||
end if
|
||||
|
||||
this % count = this % count + 1
|
||||
|
||||
end subroutine list_append_int
|
||||
|
||||
subroutine list_append_real(this, data)
|
||||
class(ListReal) :: this
|
||||
real(8) :: data
|
||||
|
||||
type(ListElemReal), pointer :: elem
|
||||
|
||||
! Create element and set dat
|
||||
allocate(elem)
|
||||
elem % data = data
|
||||
|
||||
if (.not. associated(this % head)) then
|
||||
! If list is empty, set head and tail to new element
|
||||
this % head => elem
|
||||
this % tail => elem
|
||||
else
|
||||
! Otherwise append element at end of list
|
||||
this % tail % next => elem
|
||||
this % tail => this % tail % next
|
||||
end if
|
||||
|
||||
this % count = this % count + 1
|
||||
|
||||
end subroutine list_append_real
|
||||
|
||||
!===============================================================================
|
||||
! LIST_CONTAINS determines whether the list contains a specified item. Since it
|
||||
! relies on the index method, it is O(n).
|
||||
!===============================================================================
|
||||
|
||||
function list_contains_int(this, data) result(in_list)
|
||||
class(ListInt) :: this
|
||||
integer :: data
|
||||
logical :: in_list
|
||||
|
||||
in_list = (this % index(data) > 0)
|
||||
|
||||
end function list_contains_int
|
||||
|
||||
function list_contains_real(this, data) result(in_list)
|
||||
class(ListReal) :: this
|
||||
real(8) :: data
|
||||
logical :: in_list
|
||||
|
||||
in_list = (this % index(data) > 0)
|
||||
|
||||
end function list_contains_real
|
||||
|
||||
!===============================================================================
|
||||
! LIST_GET_ITEM returns the item in the list at position 'i_list'. If the index
|
||||
! is out of bounds, an error code is returned.
|
||||
! ===============================================================================
|
||||
|
||||
function list_get_item_int(this, i_list) result(data)
|
||||
class(ListInt) :: this
|
||||
integer :: i_list
|
||||
integer :: data
|
||||
|
||||
integer :: last_index
|
||||
|
||||
if (i_list < 1 .or. i_list > this % count) then
|
||||
! Check for index out of bounds
|
||||
data = ERROR_INT
|
||||
elseif (i_list == 1) then
|
||||
data = this % head % data
|
||||
this % last_index = 1
|
||||
this % last_elem => this % head
|
||||
elseif (i_list == this % count) then
|
||||
data = this % tail % data
|
||||
this % last_index = this % count
|
||||
this % last_elem => this % tail
|
||||
else
|
||||
if (i_list < this % last_index) then
|
||||
this % last_index = 1
|
||||
this % last_elem => this % head
|
||||
end if
|
||||
|
||||
do last_index = this % last_index + 1, i_list
|
||||
this % last_elem => this % last_elem % next
|
||||
this % last_index = last_index
|
||||
end do
|
||||
data = this % last_elem % data
|
||||
end if
|
||||
|
||||
end function list_get_item_int
|
||||
|
||||
function list_get_item_real(this, i_list) result(data)
|
||||
class(ListReal) :: this
|
||||
integer :: i_list
|
||||
real(8) :: data
|
||||
|
||||
integer :: last_index
|
||||
|
||||
if (i_list < 1 .or. i_list > this % count) then
|
||||
! Check for index out of bounds
|
||||
data = ERROR_REAL
|
||||
elseif (i_list == 1) then
|
||||
data = this % head % data
|
||||
this % last_index = 1
|
||||
this % last_elem => this % head
|
||||
elseif (i_list == this % count) then
|
||||
data = this % tail % data
|
||||
this % last_index = this % count
|
||||
this % last_elem => this % tail
|
||||
else
|
||||
if (i_list < this % last_index) then
|
||||
this % last_index = 1
|
||||
this % last_elem => this % head
|
||||
end if
|
||||
|
||||
do last_index = this % last_index + 1, i_list
|
||||
this % last_elem => this % last_elem % next
|
||||
this % last_index = last_index
|
||||
end do
|
||||
data = this % last_elem % data
|
||||
end if
|
||||
|
||||
end function list_get_item_real
|
||||
|
||||
!===============================================================================
|
||||
! LIST_INDEX determines the first index in the list that contains 'data'. If
|
||||
! 'data' is not present in the list, the return value is -1.
|
||||
!===============================================================================
|
||||
|
||||
function list_index_int(this, data) result(i_list)
|
||||
|
||||
class(ListInt) :: this
|
||||
integer :: data
|
||||
integer :: i_list
|
||||
|
||||
type(ListElemInt), pointer :: elem
|
||||
|
||||
i_list = 0
|
||||
elem => this % head
|
||||
do while (associated(elem))
|
||||
i_list = i_list + 1
|
||||
if (data == elem % data) exit
|
||||
elem => elem % next
|
||||
end do
|
||||
|
||||
! Check if we reached the end of the list
|
||||
if (.not. associated(elem)) i_list = -1
|
||||
|
||||
end function list_index_int
|
||||
|
||||
function list_index_real(this, data) result(i_list)
|
||||
|
||||
class(ListReal) :: this
|
||||
real(8) :: data
|
||||
integer :: i_list
|
||||
|
||||
type(ListElemReal), pointer :: elem
|
||||
|
||||
i_list = 0
|
||||
elem => this % head
|
||||
do while (associated(elem))
|
||||
i_list = i_list + 1
|
||||
if (data == elem % data) exit
|
||||
elem => elem % next
|
||||
end do
|
||||
|
||||
! Check if we reached the end of the list
|
||||
if (.not. associated(elem)) i_list = -1
|
||||
|
||||
end function list_index_real
|
||||
|
||||
!===============================================================================
|
||||
! LIST_INSERT inserts 'data' at index 'i_list' within the list. If 'i_list'
|
||||
! exceeds the size of the list, the data is appends at the end of the list.
|
||||
!===============================================================================
|
||||
|
||||
subroutine list_insert_int(this, i_list, data)
|
||||
|
||||
class(ListInt) :: this
|
||||
integer :: i_list
|
||||
integer :: data
|
||||
|
||||
integer :: i
|
||||
type(ListElemInt), pointer :: elem => null()
|
||||
type(ListElemInt), pointer :: new_elem => null()
|
||||
|
||||
if (i_list > this % count) then
|
||||
! Check whether specified index is greater than number of elements -- if
|
||||
! so, just append it to the end of the list
|
||||
call this % append(data)
|
||||
|
||||
else if (i_list == 1) then
|
||||
! Check for new head element
|
||||
allocate(new_elem)
|
||||
new_elem % data = data
|
||||
new_elem % next => this % head
|
||||
this % head => new_elem
|
||||
this % count = this % count + 1
|
||||
|
||||
else
|
||||
! Default case with new element somewhere in middle of list
|
||||
i = 0
|
||||
elem => this % head
|
||||
do while (associated(elem))
|
||||
i = i + 1
|
||||
if (i == i_list - 1) then
|
||||
! Allocate new element
|
||||
allocate(new_elem)
|
||||
new_elem % data = data
|
||||
|
||||
! Put it before the i-th element
|
||||
new_elem % next => elem % next
|
||||
elem % next => new_elem
|
||||
this % count = this % count + 1
|
||||
exit
|
||||
end if
|
||||
end do
|
||||
end if
|
||||
|
||||
end subroutine list_insert_int
|
||||
|
||||
subroutine list_insert_real(this, i_list, data)
|
||||
|
||||
class(ListReal) :: this
|
||||
integer :: i_list
|
||||
real(8) :: data
|
||||
|
||||
integer :: i
|
||||
type(ListElemReal), pointer :: elem => null()
|
||||
type(ListElemReal), pointer :: new_elem => null()
|
||||
|
||||
if (i_list > this % count) then
|
||||
! Check whether specified index is greater than number of elements -- if
|
||||
! so, just append it to the end of the list
|
||||
call this % append(data)
|
||||
|
||||
else if (i_list == 1) then
|
||||
! Check for new head element
|
||||
allocate(new_elem)
|
||||
new_elem % data = data
|
||||
new_elem % next => this % head
|
||||
this % head => new_elem
|
||||
this % count = this % count + 1
|
||||
|
||||
else
|
||||
! Default case with new element somewhere in middle of list
|
||||
i = 0
|
||||
elem => this % head
|
||||
do while (associated(elem))
|
||||
i = i + 1
|
||||
if (i == i_list - 1) then
|
||||
! Allocate new element
|
||||
allocate(new_elem)
|
||||
new_elem % data = data
|
||||
|
||||
! Put it before the i-th element
|
||||
new_elem % next => elem % next
|
||||
elem % next => new_elem
|
||||
this % count = this % count + 1
|
||||
exit
|
||||
end if
|
||||
end do
|
||||
end if
|
||||
|
||||
end subroutine list_insert_real
|
||||
|
||||
!===============================================================================
|
||||
! LIST_REMOVE removes the first item in the list that contains 'data'. If 'data'
|
||||
! is not in the list, no action is taken.
|
||||
!===============================================================================
|
||||
|
||||
subroutine list_remove_int(this, data)
|
||||
|
||||
class(ListInt) :: this
|
||||
integer :: data
|
||||
|
||||
type(ListElemInt), pointer :: elem => null()
|
||||
type(ListElemInt), pointer :: prev => null()
|
||||
|
||||
elem => this % head
|
||||
do while (associated(elem))
|
||||
! Check for matching data
|
||||
if (elem % data == data) then
|
||||
|
||||
! Determine whether the current element is the head, tail, or a middle
|
||||
! element
|
||||
if (associated(elem, this % head)) then
|
||||
this % head => elem % next
|
||||
if (associated(elem, this % tail)) nullify(this % tail)
|
||||
deallocate(elem)
|
||||
else if (associated(elem, this % tail)) then
|
||||
this % tail => prev
|
||||
deallocate(this % tail % next)
|
||||
else
|
||||
prev % next => elem % next
|
||||
deallocate(elem)
|
||||
end if
|
||||
|
||||
! Decrease count and exit
|
||||
this % count = this % count - 1
|
||||
exit
|
||||
end if
|
||||
|
||||
! Advance pointers
|
||||
prev => elem
|
||||
elem => elem % next
|
||||
end do
|
||||
|
||||
end subroutine list_remove_int
|
||||
|
||||
subroutine list_remove_real(this, data)
|
||||
|
||||
class(ListReal) :: this
|
||||
real(8) :: data
|
||||
|
||||
type(ListElemReal), pointer :: elem => null()
|
||||
type(ListElemReal), pointer :: prev => null()
|
||||
|
||||
elem => this % head
|
||||
do while (associated(elem))
|
||||
! Check for matching data
|
||||
if (elem % data == data) then
|
||||
|
||||
! Determine whether the current element is the head, tail, or a middle
|
||||
! element
|
||||
if (associated(elem, this % head)) then
|
||||
this % head => elem % next
|
||||
if (associated(elem, this % tail)) nullify(this % tail)
|
||||
deallocate(elem)
|
||||
else if (associated(elem, this % tail)) then
|
||||
this % tail => prev
|
||||
deallocate(this % tail % next)
|
||||
else
|
||||
prev % next => elem % next
|
||||
deallocate(elem)
|
||||
end if
|
||||
|
||||
! Decrease count and exit
|
||||
this % count = this % count - 1
|
||||
exit
|
||||
end if
|
||||
|
||||
! Advance pointers
|
||||
prev => elem
|
||||
elem => elem % next
|
||||
end do
|
||||
|
||||
end subroutine list_remove_real
|
||||
|
||||
!===============================================================================
|
||||
! LIST_SIZE returns the number of elements in the list
|
||||
!===============================================================================
|
||||
|
||||
function list_size_int(this) result(size)
|
||||
|
||||
class(ListInt) :: this
|
||||
integer :: size
|
||||
|
||||
size = this % count
|
||||
|
||||
end function list_size_int
|
||||
|
||||
function list_size_real(this) result(size)
|
||||
|
||||
class(ListReal) :: this
|
||||
integer :: size
|
||||
|
||||
size = this % count
|
||||
|
||||
end function list_size_real
|
||||
|
||||
end module list_header
|
||||
101
src/set_header.F90
Normal file
101
src/set_header.F90
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
module set_header
|
||||
|
||||
!===============================================================================
|
||||
! SET_HEADER module
|
||||
!
|
||||
! This module provides an implementation of sets based on the list
|
||||
! implementation in list_header. The underlying datatype is a list, so adding an
|
||||
! element just checks if the element is already in the list, and if not it's
|
||||
! added. This results in much worse performance than an implementation based on
|
||||
! hash tables or binary trees, but for our purposes, we don't expect to have
|
||||
! gigantic sets where performance is critical.
|
||||
!===============================================================================
|
||||
|
||||
use list_header
|
||||
|
||||
implicit none
|
||||
|
||||
!===============================================================================
|
||||
! SET contains a list of elements and methods to add, remove, and perform other
|
||||
! basic tasks.
|
||||
!===============================================================================
|
||||
|
||||
type :: SetInt
|
||||
private
|
||||
type(ListInt) :: elements
|
||||
contains
|
||||
procedure :: add => set_add_int
|
||||
procedure :: contains => set_contains_int
|
||||
procedure :: get_item => set_get_item_int
|
||||
procedure :: remove => set_remove_int
|
||||
procedure :: size => set_size_int
|
||||
end type SetInt
|
||||
|
||||
contains
|
||||
|
||||
!===============================================================================
|
||||
! SET_ADD adds an item to a set if it is not already present in the set
|
||||
!===============================================================================
|
||||
|
||||
subroutine set_add_int(this, data)
|
||||
class(SetInt) :: this
|
||||
integer :: data
|
||||
|
||||
if (.not. this % elements % contains(data)) then
|
||||
call this % elements % append(data)
|
||||
end if
|
||||
|
||||
end subroutine set_add_int
|
||||
|
||||
!===============================================================================
|
||||
! SET_CONTAINS determines if a specified item is in a set
|
||||
!===============================================================================
|
||||
|
||||
function set_contains_int(this, data) result(in_set)
|
||||
class(SetInt) :: this
|
||||
integer :: data
|
||||
logical :: in_set
|
||||
|
||||
in_set = this % elements % contains(data)
|
||||
|
||||
end function set_contains_int
|
||||
|
||||
!===============================================================================
|
||||
! SET_GET_ITEM returns the i-th item in the set
|
||||
!===============================================================================
|
||||
|
||||
function set_get_item_int(this, i_list) result(data)
|
||||
class(SetInt) :: this
|
||||
integer :: i_list
|
||||
integer :: data
|
||||
|
||||
data = this % elements % get_item(i_list)
|
||||
|
||||
end function set_get_item_int
|
||||
|
||||
!===============================================================================
|
||||
! SET_REMOVE removes the specified item from the set. If it is not in the set,
|
||||
! no action is taken.
|
||||
!===============================================================================
|
||||
|
||||
subroutine set_remove_int(this, data)
|
||||
class(SetInt) :: this
|
||||
integer :: data
|
||||
|
||||
call this % elements % remove(data)
|
||||
|
||||
end subroutine set_remove_int
|
||||
|
||||
!===============================================================================
|
||||
! SET_SIZE returns the number of elements in the set
|
||||
!===============================================================================
|
||||
|
||||
function set_size_int(this) result(size)
|
||||
class(SetInt) :: this
|
||||
integer :: size
|
||||
|
||||
size = this % elements % size()
|
||||
|
||||
end function set_size_int
|
||||
|
||||
end module set_header
|
||||
Loading…
Add table
Add a link
Reference in a new issue