2 use iso_fortran_env, only: int64
6 integer(kind=int64) :: key
7 integer(kind=int64) :: value
11 type(kv_type), allocatable :: kv
12 type(node_type), pointer :: next => null()
15 ! If kv is not allocated, allocate and set to the key, value passed in.
16 ! If key is present and the same as the key passed in, overwrite the value.
17 ! Otherwise, defer to the next node (allocate if not allocated)
20 ! If kv is not allocated, fail and return 0.
21 ! If key is present and the same as the key passed in, return the value in kv.
22 ! If next pointer is associated, delegate to it.
23 ! Otherwise, fail and return 0.
26 ! If kv is not allocated, fail and return
27 ! If key is present and node is first in bucket, set first node in bucket to
28 ! the next node of first. Return success
29 ! If key is present and the node is another member of the linked list, link the
30 ! previous node's next node to this node's next node, deallocate this node,
33 ! Deallocate kv is allocated.
34 ! Call the clear method of the next node if the next pointer associated.
35 ! Deallocate and nullify the next pointer.
36 procedure :: node_clear
38 ! Return the length of the linked list start from the current node.
39 procedure :: node_depth
44 integer(kind=int64) :: n_buckets = 0
45 integer(kind=int64) :: n_keys = 0
46 type(node_type), allocatable :: buckets(:)
48 procedure, public :: bucket_count
49 procedure, public :: n_collisions
50 ! Returns number of keys.
51 procedure, public :: key_count
52 ! Set the value at a given a key.
53 procedure, public :: set
54 procedure, public :: set_all
55 procedure, public :: set_all_idx
56 ! Get the value at the given key.
57 procedure, public :: get
58 ! Clear all the allocated memory (must be called to prevent memory leak).
59 procedure, public :: clear
60 ! Private hashing function
61 procedure, private :: hash
66 function hash(this,key_value) result(bucket)
68 class(hash_t), intent(inout) :: this
69 integer(kind=int64), intent(in) :: key_value
70 integer(kind=int64) bucket
76 function bucket_count(this)
77 class(hash_t), intent(inout) :: this
78 integer(kind=int64) bucket_count
80 bucket_count = this%n_buckets
81 end function bucket_count
83 function n_collisions(this)
84 class(hash_t), intent(inout) :: this
85 integer(kind=int64) n_collisions
89 do i = 1, this%n_buckets
90 n_collisions = n_collisions + node_depth(this%buckets(i)) - 1
92 end function n_collisions
94 recursive function node_depth(this) result(depth)
95 class(node_type), intent(inout) :: this
96 integer(kind=int64) depth
98 if (.not. associated(this%next)) then
101 depth = 1 + node_depth(this%next)
103 end function node_depth
105 pure function key_count(this)
106 class(hash_t), intent(in) :: this
107 integer(kind=int64) key_count
109 key_count = this%n_keys
110 end function key_count
112 subroutine set(this, key, value)
113 class(hash_t), intent(inout) :: this
114 integer(kind=int64), intent(in) :: key
115 integer(kind=int64), intent(in) :: value
116 integer(kind=int64) bucket_id
119 bucket_id = modulo(this%hash(key), this%n_buckets) + 1
121 call this%buckets(bucket_id)%node_set(key, value)
123 if (is_new) this%n_keys = this%n_keys + 1
126 subroutine set_all_idx(this, keys, length)
127 class(hash_t), intent(inout) :: this
128 integer(kind=int64), intent(in) :: keys(:)
129 integer, optional, intent(in) :: length
130 integer(kind=int64) :: i
131 integer(kind=int64) bucket_id, n
133 if(present(length)) then
140 allocate(this%buckets(n))
143 bucket_id = modulo(this%hash(keys(i)),this%n_buckets) + 1
144 call this%buckets(bucket_id)%node_set(keys(i), i)
145 this%n_keys = this%n_keys + 1
147 end subroutine set_all_idx
149 subroutine set_all(this, keys, values)
150 class(hash_t), intent(inout) :: this
151 integer(kind=int64), intent(in) :: keys(:)
152 integer(kind=int64), intent(in) :: values(:)
153 integer(kind=int64) bucket_id, i, n
158 allocate(this%buckets(n))
161 bucket_id = modulo(this%hash(keys(i)), this%n_buckets) + 1
162 call this%buckets(bucket_id)%node_set(keys(i), values(i))
163 this%n_keys = this%n_keys + 1
165 end subroutine set_all
167 recursive subroutine node_set(this, key, value)
168 class(node_type), intent(inout) :: this
169 integer(kind=int64), intent(in) :: key
170 integer(kind=int64), intent(in) :: value
172 if (.not. allocated(this%kv)) then
175 this%kv%value = value
176 else if (this%kv%key == key) then
177 this%kv%value = this%kv%value
179 if (.not. associated(this%next)) then
182 call this%next%node_set(key, value)
184 end subroutine node_set
186 subroutine get(this, key, value, success)
187 class(hash_t), intent(inout) :: this
188 integer(kind=int64), intent(in) :: key
189 integer(kind=int64), intent(out) :: value
190 logical, intent(out) :: success
191 integer(kind=int64) bucket_id
194 if(this%n_buckets == 0) return
195 bucket_id = modulo(key,this%n_buckets) + 1
196 call this%buckets(bucket_id)%node_get(key, value, success)
199 recursive subroutine node_get(this, key, value, success)
200 class(node_type), intent(inout) :: this
201 integer(kind=int64), intent(in) :: key
202 integer(kind=int64), intent(out) :: value
203 logical, intent(out) :: success
207 if (.not. allocated(this%kv)) then
208 ! Not found. (Initial node in the bucket not set)
210 else if (this%kv%key == key) then
211 value = this%kv%value
213 else if (associated(this%next)) then
214 call this%next%node_get(key, value, success)
218 end subroutine node_get
220 subroutine clear(this)
221 class(hash_t), intent(inout) :: this
222 integer(kind=int64) i
224 if (.not. allocated(this%buckets)) return
226 do i = 1, size(this%buckets)
227 if (associated(this%buckets(i)%next)) then
228 call this%buckets(i)%next%node_clear()
229 deallocate(this%buckets(i)%next)
230 if(allocated(this%buckets(i)%kv)) then
231 deallocate(this%buckets(i)%kv)
235 deallocate(this%buckets)
240 recursive subroutine node_clear(this)
241 class(node_type), intent(inout) :: this
243 if (associated(this%next)) then
244 call this%next%node_clear()
245 deallocate(this%next)
249 end subroutine node_clear