(git:374b731)
Loading...
Searching...
No Matches
callgraph.F
Go to the documentation of this file.
1!--------------------------------------------------------------------------------------------------!
2! CP2K: A general program to perform molecular dynamics simulations !
3! Copyright 2000-2024 CP2K developers group <https://cp2k.org> !
4! !
5! SPDX-License-Identifier: GPL-2.0-or-later !
6!--------------------------------------------------------------------------------------------------!
8 USE kinds, ONLY: int_4, int_8
10#include "../base/base_uses.f90"
11
12 IMPLICIT NONE
13 PRIVATE
14
15
16! **************************************************************************************************
17!> \brief A hash map (also known as hashtable or dictionary).
18!> Internally the hash map uses an array to holds its data.
19!> If this array reaches a load-factor of 75%, a new array with twice the
20!> size will be allocated and the items are then copied over.
21!> This ensures that the dictionary will perform operations in O(1).
22!> \par History
23!> 12.2012 first version [Ole Schuett]
24!> 08.2019 refactored for Fypp [Ole Schuett]
25!> \author Ole Schuett
26! ***************************************************************************************************
27
28 PUBLIC :: callgraph_init
29 PUBLIC :: callgraph_items
30 PUBLIC :: callgraph_haskey
31 PUBLIC :: callgraph_set
32 PUBLIC :: callgraph_get
33 PUBLIC :: callgraph_size
34 PUBLIC :: callgraph_destroy
35 PUBLIC :: callgraph_type
36 PUBLIC :: callgraph_item_type
37
38!this is an internal type
39!Calculating hashes might be expensive, therefore they are stored
40!for use during change_capacity().
41 TYPE private_item_type
42 PRIVATE
43 INTEGER(kind=int_4), DIMENSION(2) :: key = 0_int_4
44 TYPE(call_stat_type), POINTER :: value => null()
45 INTEGER(KIND=int_8) :: hash = 0_int_8
46 TYPE(private_item_type), POINTER :: next => null()
47 END TYPE private_item_type
48
49!this is an internal type
50 TYPE private_item_p_type
51 PRIVATE
52 TYPE(private_item_type), POINTER :: p => null()
53 END TYPE private_item_p_type
54
55! this is the public type, which holds a hash map instance
57 PRIVATE
58 TYPE(private_item_p_type), DIMENSION(:), POINTER :: buckets => null()
59 INTEGER :: size = -1
60 END TYPE callgraph_type
61
62! this is a public type, its returned by callgraph_items()
64 INTEGER(kind=int_4), DIMENSION(2) :: key = 0_int_4
65 TYPE(call_stat_type), POINTER :: value => null()
66 END TYPE callgraph_item_type
67
68 CONTAINS
69
70
71! **************************************************************************************************
72!> \brief Allocates the internal data-structures of the given hash map.
73!> \param hash_map ...
74!> \param initial_capacity The initial size of the internal array (default=11).
75!> \author Ole Schuett
76! **************************************************************************************************
77 SUBROUTINE callgraph_init(hash_map, initial_capacity)
78 TYPE(callgraph_type), INTENT(inout) :: hash_map
79 INTEGER, INTENT(in), OPTIONAL :: initial_capacity
80
81 INTEGER :: initial_capacity_
82
83 IF (PRESENT(initial_capacity)) THEN
84 initial_capacity_ = initial_capacity
85 ELSE
86 initial_capacity_ = 11
87 END IF
88
89 IF (initial_capacity_ < 1) &
90 cpabort("initial_capacity < 1")
91
92 IF (ASSOCIATED(hash_map%buckets)) &
93 cpabort("hash map is already initialized.")
94
95 ALLOCATE (hash_map%buckets(initial_capacity_))
96 hash_map%size = 0
97
98 END SUBROUTINE callgraph_init
99
100! **************************************************************************************************
101!> \brief Test if the given hash map has been initialized.
102!> \param hash_map ...
103!> \return ...
104!> \author Ole Schuett
105! **************************************************************************************************
106 FUNCTION callgraph_isready(hash_map) RESULT(res)
107 TYPE(callgraph_type), INTENT(inout) :: hash_map
108 LOGICAL :: res
109 res = ASSOCIATED(hash_map%buckets)
110 END FUNCTION callgraph_isready
111
112! **************************************************************************************************
113!> \brief Deallocated the internal data-structures if the given hash map.
114!> Caution: If the stored keys or values are pointers, their targets will
115!> not get deallocated by this routine.
116!> \param hash_map ...
117!> \author Ole Schuett
118! **************************************************************************************************
119 SUBROUTINE callgraph_destroy(hash_map)
120 TYPE(callgraph_type), INTENT(inout) :: hash_map
121 TYPE(private_item_type), POINTER :: item, prev_item
122 INTEGER :: i
123
124 cpassert(ASSOCIATED(hash_map%buckets))
125
126 DO i = 1, size(hash_map%buckets)
127 item => hash_map%buckets(i)%p
128 DO WHILE (ASSOCIATED(item))
129 prev_item => item
130 item => item%next
131 DEALLOCATE (prev_item)
132 END DO
133 END DO
134
135 DEALLOCATE (hash_map%buckets)
136 hash_map%size = -1
137 END SUBROUTINE callgraph_destroy
138
139! **************************************************************************************************
140!> \brief Stores, and possibly overwrites, a given value under a given key.
141!> \param hash_map ...
142!> \param key ...
143!> \param value ...
144!> \author Ole Schuett
145! **************************************************************************************************
146 SUBROUTINE callgraph_set(hash_map, key, value)
147 TYPE(callgraph_type), INTENT(inout) :: hash_map
148 INTEGER(kind=int_4), DIMENSION(2), INTENT(in) :: key
149 TYPE(call_stat_type), POINTER, INTENT(in) :: value
150 INTEGER(KIND=int_8) :: hash
151 cpassert(ASSOCIATED(hash_map%buckets))
152
153 hash = callgraph_hash_function(key)
154 CALL callgraph_set_hashed(hash_map, key, value, hash)
155 END SUBROUTINE callgraph_set
156
157! **************************************************************************************************
158!> \brief Common code used internally by callgraph_set() and callgraph_change_capacity().
159!> \param hash_map ...
160!> \param key ...
161!> \param value ...
162!> \param hash ...
163!> \author Ole Schuett
164! **************************************************************************************************
165 RECURSIVE SUBROUTINE callgraph_set_hashed(hash_map, key, value, hash)
166 TYPE(callgraph_type), INTENT(inout) :: hash_map
167 INTEGER(kind=int_4), DIMENSION(2), intent(in) :: key
168 TYPE(call_stat_type), POINTER, intent(in) :: value
169 INTEGER(KIND=int_8), intent(in) :: hash
170 TYPE(private_item_type), POINTER :: item, new_item
171 INTEGER(KIND=int_8) :: idx
172
173 idx = mod(hash, int(size(hash_map%buckets), kind=int_8)) + 1
174
175 ! if already in hash map just update its value
176 item => hash_map%buckets(idx)%p
177 DO WHILE (ASSOCIATED(item))
178 IF (item%hash == hash) THEN
179 IF (callgraph_keys_equal(item%key, key)) THEN
180 item%value =>value
181 RETURN
182 END IF
183 END IF
184 item => item%next
185 END DO
186
187 ! check load-factor
188 IF (4*hash_map%size > 3*size(hash_map%buckets)) THEN ! load-factor > 75%
189 call callgraph_change_capacity(hash_map, 2*size(hash_map%buckets)) !double capacity
190 idx = mod(hash, int(size(hash_map%buckets), kind=int_8)) + 1
191 END IF
192
193 ! create a new item
194 allocate (new_item)
195 new_item%hash = hash
196 new_item%key =key
197 new_item%value =>value
198 new_item%next => hash_map%buckets(idx)%p
199 hash_map%buckets(idx)%p => new_item
200 hash_map%size = hash_map%size + 1
201
202 END SUBROUTINE callgraph_set_hashed
203
204! **************************************************************************************************
205!> \brief Internal routine for changing the hash map's capacity.
206!> \param hash_map ...
207!> \param new_capacity ...
208!> \author Ole Schuett
209! **************************************************************************************************
210 RECURSIVE SUBROUTINE callgraph_change_capacity(hash_map, new_capacity)
211 TYPE(callgraph_type), INTENT(inout) :: hash_map
212 INTEGER, INTENT(in) :: new_capacity
213 INTEGER :: i, old_size, new_cap
214 TYPE(private_item_type), POINTER :: item, prev_item
215 TYPE(private_item_p_type), DIMENSION(:), POINTER :: old_buckets
216 new_cap = new_capacity
217 ! pre checks
218 IF (new_cap > huge(i)) THEN
219 IF (size(hash_map%buckets) == huge(i)) RETURN ! reached maximum - stay there.
220 new_cap = huge(i) ! grow as far as possible
221 END IF
222 cpassert(new_cap >= 1)
223 cpassert(4*hash_map%size < 3*new_cap)
224
225 old_size = hash_map%size
226 old_buckets => hash_map%buckets
227 ALLOCATE (hash_map%buckets(new_capacity))
228 hash_map%size = 0
229 DO i = 1, size(old_buckets)
230 item => old_buckets(i)%p
231 DO WHILE (ASSOCIATED(item))
232 CALL callgraph_set_hashed(hash_map, item%key, item%value, item%hash)
233 prev_item => item
234 item => item%next
235 DEALLOCATE (prev_item)
236 END DO
237 END DO
238
239 DEALLOCATE (old_buckets)
240
241 cpassert(old_size == hash_map%size)
242 END SUBROUTINE callgraph_change_capacity
243
244! **************************************************************************************************
245!> \brief Gets a value for a given key from the hash map.
246!> If the key is not found the default_value will be returned.
247!> If the key is not found and default_value was not provided the program stops.
248!> \param hash_map ...
249!> \param key ...
250!> \param default_value ...
251!> \return ...
252!> \author Ole Schuett
253! **************************************************************************************************
254 FUNCTION callgraph_get(hash_map, key, default_value) RESULT(value)
255 TYPE(callgraph_type), INTENT(in) :: hash_map
256 INTEGER(kind=int_4), DIMENSION(2), INTENT(in) :: key
257 TYPE(call_stat_type), POINTER, INTENT(in), OPTIONAL :: default_value
258 TYPE(call_stat_type), POINTER :: value
259 TYPE(private_item_type), POINTER :: item
260 INTEGER(KIND=int_8) :: hash, idx
261
262 cpassert(ASSOCIATED(hash_map%buckets))
263
264 hash = callgraph_hash_function(key)
265 idx = mod(hash, int(size(hash_map%buckets), kind=int_8)) + 1
266
267 item => hash_map%buckets(idx)%p
268 DO WHILE (ASSOCIATED(item))
269 IF (item%hash == hash) THEN
270 IF (callgraph_keys_equal(item%key, key)) THEN
271 value =>item%value
272 RETURN
273 END IF
274 END IF
275 item => item%next
276 END DO
277
278 IF (PRESENT(default_value)) THEN
279 value =>default_value
280 RETURN
281 END IF
282
283 cpabort("Key not found.")
284 END FUNCTION callgraph_get
285
286! **************************************************************************************************
287!> \brief Remove the value for a given key from the hash map.
288!> If the key is not found the program stops.
289!> \param hash_map ...
290!> \param key ...
291!> \author Ole Schuett
292! **************************************************************************************************
293 SUBROUTINE callgraph_del(hash_map, key)
294 TYPE(callgraph_type), INTENT(inout) :: hash_map
295 INTEGER(kind=int_4), DIMENSION(2), INTENT(in) :: key
296 TYPE(private_item_type), POINTER :: item, prev_item
297 INTEGER(KIND=int_8) :: hash, idx
298
299 cpassert(ASSOCIATED(hash_map%buckets))
300
301 hash = callgraph_hash_function(key)
302 idx = mod(hash, int(size(hash_map%buckets), kind=int_8)) + 1
303
304 item => hash_map%buckets(idx)%p
305 prev_item => null()
306 DO WHILE (ASSOCIATED(item))
307 IF (item%hash == hash) THEN
308 IF (callgraph_keys_equal(item%key, key)) THEN
309 IF (ASSOCIATED(prev_item)) THEN
310 prev_item%next => item%next
311 ELSE
312 hash_map%buckets(idx)%p => item%next
313 END IF
314 DEALLOCATE (item)
315 hash_map%size = hash_map%size - 1
316 RETURN
317 END IF
318 END IF
319 prev_item => item
320 item => item%next
321 END DO
322
323 cpabort("Key not found.")
324 END SUBROUTINE callgraph_del
325
326! **************************************************************************************************
327!> \brief Returns the number of key/value-items currently stored in the hash map.
328!> \param hash_map ...
329!> \return ...
330!> \author Ole Schuett
331! **************************************************************************************************
332 FUNCTION callgraph_size(hash_map) RESULT(size)
333 TYPE(callgraph_type), INTENT(IN) :: hash_map
334 INTEGER :: size
335
336 cpassert(ASSOCIATED(hash_map%buckets))
337 size = hash_map%size
338 END FUNCTION callgraph_size
339
340! **************************************************************************************************
341!> \brief Checks whether a given key is currently stored in the hash_map.
342!> \param hash_map ...
343!> \param key ...
344!> \return ...
345!> \author Ole Schuett
346! **************************************************************************************************
347 FUNCTION callgraph_haskey(hash_map, key) RESULT(res)
348 TYPE(callgraph_type), INTENT(IN) :: hash_map
349 INTEGER(kind=int_4), DIMENSION(2), INTENT(IN) :: key
350 LOGICAL :: res
351 TYPE(private_item_type), POINTER :: item
352 INTEGER(KIND=int_8) :: hash, idx
353
354 cpassert(ASSOCIATED(hash_map%buckets))
355
356 res = .false.
357 IF (hash_map%size == 0) RETURN
358
359 hash = callgraph_hash_function(key)
360 idx = mod(hash, int(size(hash_map%buckets), kind=int_8)) + 1
361
362 item => hash_map%buckets(idx)%p
363 DO WHILE (ASSOCIATED(item))
364 IF (item%hash == hash) THEN
365 IF (callgraph_keys_equal(item%key, key)) THEN
366 res = .true.
367 return
368 END IF
369 END IF
370 item => item%next
371 END DO
372
373 END FUNCTION callgraph_haskey
374
375! **************************************************************************************************
376!> \brief Returns a pointer to an array of all key/value-items stored in the hash map.
377!> Caution: The caller is responsible for deallocating targeted array after usage.
378!> \param hash_map ...
379!> \return ...
380!> \author Ole Schuett
381! **************************************************************************************************
382 FUNCTION callgraph_items(hash_map) RESULT(items)
383 TYPE(callgraph_type), INTENT(IN) :: hash_map
384 TYPE(callgraph_item_type), DIMENSION(:), POINTER :: items
385
386 TYPE(private_item_type), POINTER :: item
387 INTEGER :: i, j
388
389 cpassert(ASSOCIATED(hash_map%buckets))
390
391 ALLOCATE (items(hash_map%size))
392 j = 1
393 DO i = 1, size(hash_map%buckets)
394 item => hash_map%buckets(i)%p
395 DO WHILE (ASSOCIATED(item))
396 items(j)%key =item%key
397 items(j)%value =>item%value
398 j = j + 1
399 item => item%next
400 END DO
401 END DO
402
403 cpassert(j == hash_map%size + 1)
404 END FUNCTION callgraph_items
405
406! **************************************************************************************************
407!> \brief Copies all key/values-items from one hash map to another.
408!> Afterwards hash_map will contain all items from the from_hash_map and
409!> additionally all its previous items, which were not overwritten.
410!> The two hash maps have to be of the same type.
411!> \param hash_map destination of items
412!> \param from_hash_map source of items - will not be change
413!> \author Ole Schuett
414! **************************************************************************************************
415 SUBROUTINE callgraph_update(hash_map, from_hash_map)
416 TYPE(callgraph_type), INTENT(inout) :: hash_map
417 TYPE(callgraph_type), INTENT(in) :: from_hash_map
418 TYPE(callgraph_item_type), DIMENSION(:), POINTER :: from_items
419 INTEGER :: i
420
421 cpassert(ASSOCIATED(hash_map%buckets))
422 cpassert(ASSOCIATED(from_hash_map%buckets))
423
424 from_items => callgraph_items(from_hash_map)
425 DO i = 1, size(from_items)
426 CALL callgraph_set(hash_map, from_items(i)%key, from_items(i)%value)
427 END DO
428 DEALLOCATE (from_items)
429 END SUBROUTINE callgraph_update
430
431
432! **************************************************************************************************
433!> \brief ...
434!> \param key ...
435!> \return ...
436! **************************************************************************************************
437 PURE FUNCTION callgraph_hash_function(key) RESULT(hash)
438 INTEGER(kind=int_4), DIMENSION(2), INTENT(in) :: key
439 INTEGER(KIND=int_8) :: hash
440
441 INTEGER(kind=int_8) :: k1, k2
442 k1 = key(1) ! cast to int_8
443 k2 = key(2)
444 hash = ior(k1, ishft(k2, 32))
445 END FUNCTION callgraph_hash_function
446
447! **************************************************************************************************
448!> \brief ...
449!> \param key ...
450!> \return ...
451! **************************************************************************************************
452 PURE FUNCTION callgraph_keys_equal(key1, key2) RESULT(res)
453 INTEGER(kind=int_4), DIMENSION(2), INTENT(in) :: key1, key2
454 LOGICAL :: res
455
456 res = all(key1 == key2)
457 END FUNCTION callgraph_keys_equal
458
459END MODULE callgraph
static unsigned int hash(const dbm_task_t task)
Private hash function based on Szudzik's elegant pairing. Using unsigned int to return a positive num...
static GRID_HOST_DEVICE int idx(const orbital a)
Return coset index of given orbital angular momentum.
subroutine, public callgraph_destroy(hash_map)
Deallocated the internal data-structures if the given hash map. Caution: If the stored keys or values...
Definition callgraph.F:120
integer function, public callgraph_size(hash_map)
Returns the number of key/value-items currently stored in the hash map.
Definition callgraph.F:333
subroutine, public callgraph_init(hash_map, initial_capacity)
Allocates the internal data-structures of the given hash map.
Definition callgraph.F:78
type(callgraph_item_type) function, dimension(:), pointer, public callgraph_items(hash_map)
Returns a pointer to an array of all key/value-items stored in the hash map. Caution: The caller is r...
Definition callgraph.F:383
logical function, public callgraph_haskey(hash_map, key)
Checks whether a given key is currently stored in the hash_map.
Definition callgraph.F:348
type(call_stat_type) function, pointer, public callgraph_get(hash_map, key, default_value)
Gets a value for a given key from the hash map. If the key is not found the default_value will be ret...
Definition callgraph.F:255
subroutine, public callgraph_set(hash_map, key, value)
Stores, and possibly overwrites, a given value under a given key.
Definition callgraph.F:147
Defines the basic variable types.
Definition kinds.F:23
integer, parameter, public int_8
Definition kinds.F:54
integer, parameter, public int_4
Definition kinds.F:51
Types used by timings.F and timings_report.F The types in this module are used within dict or list,...