aboutsummaryrefslogtreecommitdiff
path: root/src/3rd/flibs/src/datastructures/dictionary.f90
diff options
context:
space:
mode:
Diffstat (limited to 'src/3rd/flibs/src/datastructures/dictionary.f90')
-rwxr-xr-xsrc/3rd/flibs/src/datastructures/dictionary.f90269
1 files changed, 269 insertions, 0 deletions
diff --git a/src/3rd/flibs/src/datastructures/dictionary.f90 b/src/3rd/flibs/src/datastructures/dictionary.f90
new file mode 100755
index 0000000..4f0e1de
--- /dev/null
+++ b/src/3rd/flibs/src/datastructures/dictionary.f90
@@ -0,0 +1,269 @@
+! dictionary.f90 --
+! Include file for defining dictionaries:
+! a mapping of strings to some data
+!
+! See the example/test program for the way to use this
+!
+! Note:
+! Use is made of a hash table. This should speed up most
+! operations. The algorithm for determining the hashkey
+! is taken from Kernighan and Pike: The Practice of Programming
+!
+! Note:
+! - Define the length of the strings as
+! parameter "DICT_KEY_LENGTH"
+! - Define a derived type for the data
+! to be stored
+! - Also define a "null" value - DICT_NULL
+! of type DICT_DATA, for use when the
+! key is not found.
+! - Put both in a separate module, that
+! will be used.
+!
+! $Id: dictionary.f90,v 1.5 2013-03-05 12:08:29 arjenmarkus Exp $
+!
+type LIST_DATA
+ character(len=DICT_KEY_LENGTH) :: key
+ type(DICT_DATA) :: value
+end type LIST_DATA
+
+type HASH_LIST
+ type(LINKED_LIST), pointer :: list
+end type HASH_LIST
+
+type DICT_STRUCT
+ private
+ type(HASH_LIST), pointer, dimension(:) :: table
+end type DICT_STRUCT
+
+!
+! We do not want everything to be public
+!
+private :: LIST_DATA
+private :: HASH_LIST
+private :: LINKED_LIST
+private :: list_create
+private :: list_destroy
+private :: list_count
+private :: list_next
+private :: list_insert
+private :: list_insert_head
+private :: list_delete_element
+private :: list_get_data
+private :: list_put_data
+private :: dict_get_elem
+private :: dict_hashkey
+
+integer, parameter, private :: hash_size = 4993
+integer, parameter, private :: multiplier = 31
+
+include 'linkedlist.f90'
+
+!
+! Routines and functions specific to dictionaries
+!
+
+! dict_create --
+! Create and initialise a dictionary
+! Arguments:
+! dict Pointer to new dictionary
+! key Key for the first element
+! value Value for the first element
+! Note:
+! This version assumes a shallow copy is enough
+! (that is, there are no pointers within the data
+! to be stored)
+! It also assumes the argument list does not already
+! refer to a list. Use dict_destroy first to
+! destroy up an old list.
+!
+subroutine dict_create( dict, key, value )
+ type(DICT_STRUCT), pointer :: dict
+ character(len=*), intent(in) :: key
+ type(DICT_DATA), intent(in) :: value
+
+ type(LIST_DATA) :: data
+ integer :: i
+ integer :: hash
+
+ allocate( dict )
+ allocate( dict%table(hash_size) )
+
+ do i = 1,hash_size
+ dict%table(i)%list => null()
+ enddo
+
+ data%key = key
+ data%value = value
+
+ hash = dict_hashkey( trim(key ) )
+ call list_create( dict%table(hash)%list, data )
+
+end subroutine dict_create
+
+! dict_destroy --
+! Destroy an entire dictionary
+! Arguments:
+! dict Pointer to the dictionary to be destroyed
+! Note:
+! This version assumes that there are no
+! pointers within the data that need deallocation
+!
+subroutine dict_destroy( dict )
+ type(DICT_STRUCT), pointer :: dict
+
+ integer :: i
+
+ do i = 1,size(dict%table)
+ if ( associated( dict%table(i)%list ) ) then
+ call list_destroy( dict%table(i)%list )
+ endif
+ enddo
+ deallocate( dict%table )
+ deallocate( dict )
+
+end subroutine dict_destroy
+
+! dict_add_key
+! Add a new key
+! Arguments:
+! dict Pointer to the dictionary
+! key Key for the new element
+! value Value for the new element
+! Note:
+! If the key already exists, the
+! key's value is simply replaced
+!
+subroutine dict_add_key( dict, key, value )
+ type(DICT_STRUCT), pointer :: dict
+ character(len=*), intent(in) :: key
+ type(DICT_DATA), intent(in) :: value
+
+ type(LIST_DATA) :: data
+ type(LINKED_LIST), pointer :: elem
+ integer :: hash
+
+ elem => dict_get_elem( dict, key )
+
+ if ( associated(elem) ) then
+ elem%data%value = value
+ else
+ data%key = key
+ data%value = value
+ hash = dict_hashkey( trim(key) )
+ if ( associated( dict%table(hash)%list ) ) then
+ call list_insert( dict%table(hash)%list, data )
+ else
+ call list_create( dict%table(hash)%list, data )
+ endif
+ endif
+
+end subroutine dict_add_key
+
+! dict_delete_key
+! Delete a key-value pair from the dictionary
+! Arguments:
+! dict Dictionary in question
+! key Key to be removed
+!
+subroutine dict_delete_key( dict, key )
+ type(DICT_STRUCT), pointer :: dict
+ character(len=*), intent(in) :: key
+
+ type(LINKED_LIST), pointer :: elem
+ integer :: hash
+
+ elem => dict_get_elem( dict, key )
+
+ if ( associated(elem) ) then
+ hash = dict_hashkey( trim(key) )
+ call list_delete_element( dict%table(hash)%list, elem )
+ endif
+end subroutine dict_delete_key
+
+! dict_get_key
+! Get the value belonging to a key
+! Arguments:
+! dict Pointer to the dictionary
+! key Key for which the values are sought
+!
+function dict_get_key( dict, key ) result(value)
+ type(DICT_STRUCT), pointer :: dict
+ character(len=*), intent(in) :: key
+ type(DICT_DATA) :: value
+
+ type(LIST_DATA) :: data
+ type(LINKED_LIST), pointer :: elem
+
+ elem => dict_get_elem( dict, key )
+
+ if ( associated(elem) ) then
+ value = elem%data%value
+ else
+ value = DICT_NULL
+ endif
+end function dict_get_key
+
+! dict_has_key
+! Check if the dictionary has a particular key
+! Arguments:
+! dict Pointer to the dictionary
+! key Key to be sought
+!
+function dict_has_key( dict, key ) result(has)
+ type(DICT_STRUCT), pointer :: dict
+ character(len=*), intent(in) :: key
+ logical :: has
+
+ type(LINKED_LIST), pointer :: elem
+
+ elem => dict_get_elem( dict, key )
+
+ has = associated(elem)
+end function dict_has_key
+
+! dict_get_elem
+! Find the element with a particular key
+! Arguments:
+! dict Pointer to the dictionary
+! key Key to be sought
+!
+function dict_get_elem( dict, key ) result(elem)
+ type(DICT_STRUCT), pointer :: dict
+ character(len=*), intent(in) :: key
+
+ type(LINKED_LIST), pointer :: elem
+ integer :: hash
+
+ hash = dict_hashkey( trim(key) )
+
+ elem => dict%table(hash)%list
+ do while ( associated(elem) )
+ if ( elem%data%key .eq. key ) then
+ exit
+ else
+ elem => list_next( elem )
+ endif
+ enddo
+end function dict_get_elem
+
+! dict_hashkey
+! Determine the hash value from the string
+! Arguments:
+! key String to be examined
+!
+integer function dict_hashkey( key )
+ character(len=*), intent(in) :: key
+
+ integer :: hash
+ integer :: i
+
+ dict_hashkey = 0
+
+ do i = 1,len(key)
+ dict_hashkey = modulo( multiplier * dict_hashkey + ichar(key(i:i)), hash_size )
+ enddo
+
+ dict_hashkey = 1 + modulo( dict_hashkey-1, hash_size )
+end function dict_hashkey
+