MODFLOW 6  version 6.5.0.dev2
MODFLOW 6 Code Documentation
HashTable.f90
Go to the documentation of this file.
1 !> @brief A chaining hash map for integers.
2 !!
3 !! Convenient for use as an index into arrays of arbitrary
4 !! data type. The implementation is based on Arjen Markus'
5 !! dictionary in the Flibs collection of Fortran utilities.
6 !<
8 
9  use kindmodule, only: dp, i4b
10 
11  implicit none
12 
13  private
14  public hashtabletype
15  public hash_table_cr
16  public hash_table_da
17 
18  integer, parameter, private :: hash_size = 4993
19  integer, parameter, private :: multiplier = 31
20 
21  type :: nodetype
22  character(len=:), allocatable :: key
23  integer(I4B) :: value
24  type(nodetype), pointer :: next => null()
25  contains
26  procedure :: add => list_add
27  end type nodetype
28 
29  type :: buckettype
30  type(nodetype), pointer :: list => null()
31  end type buckettype
32 
33  type :: hashtabletype
34  private
35  type(buckettype), pointer :: buckets(:) => null()
36  contains
37  procedure :: add => ht_add
38  procedure :: get => ht_get
39  procedure, private :: find_node
40  end type hashtabletype
41 
42 contains
43 
44  !> @brief Create a hash table
45  subroutine hash_table_cr(map)
46  ! -- dummy
47  type(hashtabletype), pointer :: map
48  ! -- local
49  integer(I4B) :: i
50 
51  ! -- allocate
52  allocate (map)
53  allocate (map%buckets(hash_size))
54 
55  ! -- initialize nul buckets
56  do i = 1, hash_size
57  map%buckets(i)%list => null()
58  end do
59 
60  end subroutine hash_table_cr
61 
62  !> @brief Deallocate the hash table
63  subroutine hash_table_da(map)
64  ! -- dummy
65  type(hashtabletype), pointer :: map
66  ! -- local
67  integer(I4B) :: i
68 
69  ! -- deallocate each bucket
70  do i = 1, size(map%buckets)
71  if (associated(map%buckets(i)%list)) then
72  call list_da(map%buckets(i)%list)
73  end if
74  end do
75 
76  ! -- deallocate bucket array and hash table
77  deallocate (map%buckets)
78  deallocate (map)
79 
80  end subroutine hash_table_da
81 
82  !> @brief Associate the given key and value
83  subroutine ht_add(this, k, v)
84  ! -- dummy
85  class(hashtabletype) :: this
86  character(len=*), intent(in) :: k
87  integer(I4B), intent(in) :: v
88  ! -- local
89  type(nodetype), pointer :: node
90  integer(I4B) :: h
91 
92  ! -- find the element corresponding to this key and replace index or
93  ! get an unassociated elem that corresponds to this key
94  node => this%find_node(k)
95 
96  ! -- replace index or create new entry
97  if (associated(node)) then
98  node%value = v
99  else
100  h = hash(trim(k))
101  if (associated(this%buckets(h)%list)) then
102  call this%buckets(h)%list%add(k, v)
103  else
104  call list_cr(this%buckets(h)%list, k, v)
105  end if
106  end if
107 
108  end subroutine ht_add
109 
110  !> @brief Find the node containing the given key
111  function find_node(this, k) result(node)
112  ! -- dummy
113  class(hashtabletype) :: this !< the hash map
114  character(len=*), intent(in) :: k !< the key
115  ! -- local
116  type(nodetype), pointer :: node
117  integer(I4B) :: h
118 
119  h = hash(trim(k))
120  node => this%buckets(h)%list
121 
122  ! -- search bucket for node with matching key
123  do while (associated(node))
124  if (node%key == k) then
125  exit
126  else
127  node => node%next
128  end if
129  end do
130 
131  end function find_node
132 
133  !> @brief Get the value for the given key if it exists, otherwise return zero.
134  function ht_get(this, k) result(v)
135  ! -- dummy
136  class(hashtabletype) :: this !< the hash map
137  character(len=*), intent(in) :: k !< the key
138  ! -- return
139  integer(I4B) :: v
140  ! -- local
141  type(nodetype), pointer :: node
142 
143  node => this%find_node(k)
144  if (associated(node)) then
145  v = node%value
146  else
147  v = 0
148  end if
149 
150  end function ht_get
151 
152  !> @brief Create a list with the given key/value pair
153  subroutine list_cr(list, k, v)
154  ! -- dummy
155  type(nodetype), pointer :: list !< pointer to the list
156  character(len=*), intent(in) :: k !< the first key
157  integer(I4B), intent(in) :: v !< the first value
158 
159  allocate (list)
160  list%next => null()
161  list%key = k
162  list%value = v
163 
164  end subroutine list_cr
165 
166  !> @brief Add a key/value pair to the list
167  subroutine list_add(this, k, v)
168  ! -- dummy
169  class(nodetype) :: this !< the list
170  character(len=*), intent(in) :: k !< the key
171  integer(I4B), intent(in) :: v !< the value
172  ! -- local
173  type(nodetype), pointer :: next
174 
175  allocate (next)
176  next%key = k
177  next%value = v
178  next%next => this%next
179  this%next => next
180 
181  end subroutine list_add
182 
183  !> @brief Deallocate the list
184  subroutine list_da(list)
185  ! -- dummy
186  type(nodetype), pointer, intent(in) :: list !< the list
187  ! -- local
188  type(nodetype), pointer :: curr
189  type(nodetype), pointer :: node
190 
191  node => list
192  do while (associated(node))
193  curr => node
194  node => curr%next
195  deallocate (curr)
196  end do
197 
198  end subroutine list_da
199 
200  !> @brief Map a character string to an integer
201  function hash(k) result(h)
202  ! -- dummy
203  character(len=*), intent(in) :: k !< the key
204  ! -- local
205  integer(I4B) :: h
206  integer(I4B) :: i
207 
208  h = 0
209  do i = 1, len(k)
210  h = modulo(multiplier * h + ichar(k(i:i)), hash_size)
211  end do
212  h = 1 + modulo(h - 1, hash_size)
213 
214  end function hash
215 
216 end module hashtablemodule
A chaining hash map for integers.
Definition: HashTable.f90:7
subroutine list_da(list)
Deallocate the list.
Definition: HashTable.f90:185
subroutine list_cr(list, k, v)
Create a list with the given key/value pair.
Definition: HashTable.f90:154
type(nodetype) function, pointer find_node(this, k)
Find the node containing the given key.
Definition: HashTable.f90:112
integer, parameter, private hash_size
Definition: HashTable.f90:18
integer(i4b) function ht_get(this, k)
Get the value for the given key if it exists, otherwise return zero.
Definition: HashTable.f90:135
subroutine ht_add(this, k, v)
Associate the given key and value.
Definition: HashTable.f90:84
integer(i4b) function hash(k)
Map a character string to an integer.
Definition: HashTable.f90:202
subroutine, public hash_table_cr(map)
Create a hash table.
Definition: HashTable.f90:46
subroutine list_add(this, k, v)
Add a key/value pair to the list.
Definition: HashTable.f90:168
integer, parameter, private multiplier
Definition: HashTable.f90:19
subroutine, public hash_table_da(map)
Deallocate the hash table.
Definition: HashTable.f90:64
This module defines variable data types.
Definition: kind.f90:8