(git:98357aa)
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-2026 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) THEN
90 cpabort("initial_capacity < 1")
91 END IF
92
93 IF (ASSOCIATED(hash_map%buckets)) THEN
94 cpabort("hash map is already initialized.")
95 END IF
96
97 ALLOCATE (hash_map%buckets(initial_capacity_))
98 hash_map%size = 0
99
100 END SUBROUTINE callgraph_init
101
102! **************************************************************************************************
103!> \brief Test if the given hash map has been initialized.
104!> \param hash_map ...
105!> \return ...
106!> \author Ole Schuett
107! **************************************************************************************************
108 FUNCTION callgraph_isready(hash_map) RESULT(res)
109 TYPE(callgraph_type), INTENT(inout) :: hash_map
110 LOGICAL :: res
111 res = ASSOCIATED(hash_map%buckets)
112 END FUNCTION callgraph_isready
113
114! **************************************************************************************************
115!> \brief Deallocated the internal data-structures if the given hash map.
116!> Caution: If the stored keys or values are pointers, their targets will
117!> not get deallocated by this routine.
118!> \param hash_map ...
119!> \author Ole Schuett
120! **************************************************************************************************
121 SUBROUTINE callgraph_destroy(hash_map)
122 TYPE(callgraph_type), INTENT(inout) :: hash_map
123 TYPE(private_item_type), POINTER :: item, prev_item
124 INTEGER :: i
125
126 cpassert(ASSOCIATED(hash_map%buckets))
127
128 DO i = 1, size(hash_map%buckets)
129 item => hash_map%buckets(i)%p
130 DO WHILE (ASSOCIATED(item))
131 prev_item => item
132 item => item%next
133 DEALLOCATE (prev_item)
134 END DO
135 END DO
136
137 DEALLOCATE (hash_map%buckets)
138 hash_map%size = -1
139 END SUBROUTINE callgraph_destroy
140
141! **************************************************************************************************
142!> \brief Stores, and possibly overwrites, a given value under a given key.
143!> \param hash_map ...
144!> \param key ...
145!> \param value ...
146!> \author Ole Schuett
147! **************************************************************************************************
148 SUBROUTINE callgraph_set(hash_map, key, value)
149 TYPE(callgraph_type), INTENT(inout) :: hash_map
150 INTEGER(kind=int_4), DIMENSION(2), INTENT(in) :: key
151 TYPE(call_stat_type), POINTER, INTENT(in) :: value
152 INTEGER(KIND=int_8) :: hash
153 cpassert(ASSOCIATED(hash_map%buckets))
154
155 hash = callgraph_hash_function(key)
156 CALL callgraph_set_hashed(hash_map, key, value, hash)
157 END SUBROUTINE callgraph_set
158
159! **************************************************************************************************
160!> \brief Common code used internally by callgraph_set() and callgraph_change_capacity().
161!> \param hash_map ...
162!> \param key ...
163!> \param value ...
164!> \param hash ...
165!> \author Ole Schuett
166! **************************************************************************************************
167 RECURSIVE SUBROUTINE callgraph_set_hashed(hash_map, key, value, hash)
168 TYPE(callgraph_type), INTENT(inout) :: hash_map
169 INTEGER(kind=int_4), DIMENSION(2), intent(in) :: key
170 TYPE(call_stat_type), POINTER, intent(in) :: value
171 INTEGER(KIND=int_8), intent(in) :: hash
172 TYPE(private_item_type), POINTER :: item, new_item
173 INTEGER(KIND=int_8) :: idx
174
175 idx = mod(hash, int(size(hash_map%buckets), kind=int_8)) + 1
176
177 ! if already in hash map just update its value
178 item => hash_map%buckets(idx)%p
179 DO WHILE (ASSOCIATED(item))
180 IF (item%hash == hash) THEN
181 IF (callgraph_keys_equal(item%key, key)) THEN
182 item%value =>value
183 RETURN
184 END IF
185 END IF
186 item => item%next
187 END DO
188
189 ! check load-factor
190 IF (4*hash_map%size > 3*size(hash_map%buckets)) THEN ! load-factor > 75%
191 call callgraph_change_capacity(hash_map, 2*size(hash_map%buckets)) !double capacity
192 idx = mod(hash, int(size(hash_map%buckets), kind=int_8)) + 1
193 END IF
194
195 ! create a new item
196 allocate (new_item)
197 new_item%hash = hash
198 new_item%key =key
199 new_item%value =>value
200 new_item%next => hash_map%buckets(idx)%p
201 hash_map%buckets(idx)%p => new_item
202 hash_map%size = hash_map%size + 1
203
204 END SUBROUTINE callgraph_set_hashed
205
206! **************************************************************************************************
207!> \brief Internal routine for changing the hash map's capacity.
208!> \param hash_map ...
209!> \param new_capacity ...
210!> \author Ole Schuett
211! **************************************************************************************************
212 RECURSIVE SUBROUTINE callgraph_change_capacity(hash_map, new_capacity)
213 TYPE(callgraph_type), INTENT(inout) :: hash_map
214 INTEGER, INTENT(in) :: new_capacity
215 INTEGER :: i, old_size, new_cap
216 TYPE(private_item_type), POINTER :: item, prev_item
217 TYPE(private_item_p_type), DIMENSION(:), POINTER :: old_buckets
218 new_cap = new_capacity
219 ! pre checks
220 IF (new_cap > huge(i)) THEN
221 IF (size(hash_map%buckets) == huge(i)) RETURN ! reached maximum - stay there.
222 new_cap = huge(i) ! grow as far as possible
223 END IF
224 cpassert(new_cap >= 1)
225 cpassert(4*hash_map%size < 3*new_cap)
226
227 old_size = hash_map%size
228 old_buckets => hash_map%buckets
229 ALLOCATE (hash_map%buckets(new_capacity))
230 hash_map%size = 0
231 DO i = 1, size(old_buckets)
232 item => old_buckets(i)%p
233 DO WHILE (ASSOCIATED(item))
234 CALL callgraph_set_hashed(hash_map, item%key, item%value, item%hash)
235 prev_item => item
236 item => item%next
237 DEALLOCATE (prev_item)
238 END DO
239 END DO
240
241 DEALLOCATE (old_buckets)
242
243 cpassert(old_size == hash_map%size)
244 END SUBROUTINE callgraph_change_capacity
245
246! **************************************************************************************************
247!> \brief Gets a value for a given key from the hash map.
248!> If the key is not found the default_value will be returned.
249!> If the key is not found and default_value was not provided the program stops.
250!> \param hash_map ...
251!> \param key ...
252!> \param default_value ...
253!> \return ...
254!> \author Ole Schuett
255! **************************************************************************************************
256 FUNCTION callgraph_get(hash_map, key, default_value) RESULT(value)
257 TYPE(callgraph_type), INTENT(in) :: hash_map
258 INTEGER(kind=int_4), DIMENSION(2), INTENT(in) :: key
259 TYPE(call_stat_type), POINTER, INTENT(in), OPTIONAL :: default_value
260 TYPE(call_stat_type), POINTER :: value
261 TYPE(private_item_type), POINTER :: item
262 INTEGER(KIND=int_8) :: hash, idx
263
264 cpassert(ASSOCIATED(hash_map%buckets))
265
266 hash = callgraph_hash_function(key)
267 idx = mod(hash, int(size(hash_map%buckets), kind=int_8)) + 1
268
269 item => hash_map%buckets(idx)%p
270 DO WHILE (ASSOCIATED(item))
271 IF (item%hash == hash) THEN
272 IF (callgraph_keys_equal(item%key, key)) THEN
273 value =>item%value
274 RETURN
275 END IF
276 END IF
277 item => item%next
278 END DO
279
280 IF (PRESENT(default_value)) THEN
281 value =>default_value
282 RETURN
283 END IF
284
285 cpabort("Key not found.")
286 END FUNCTION callgraph_get
287
288! **************************************************************************************************
289!> \brief Remove the value for a given key from the hash map.
290!> If the key is not found the program stops.
291!> \param hash_map ...
292!> \param key ...
293!> \author Ole Schuett
294! **************************************************************************************************
295 SUBROUTINE callgraph_del(hash_map, key)
296 TYPE(callgraph_type), INTENT(inout) :: hash_map
297 INTEGER(kind=int_4), DIMENSION(2), INTENT(in) :: key
298 TYPE(private_item_type), POINTER :: item, prev_item
299 INTEGER(KIND=int_8) :: hash, idx
300
301 cpassert(ASSOCIATED(hash_map%buckets))
302
303 hash = callgraph_hash_function(key)
304 idx = mod(hash, int(size(hash_map%buckets), kind=int_8)) + 1
305
306 item => hash_map%buckets(idx)%p
307 prev_item => null()
308 DO WHILE (ASSOCIATED(item))
309 IF (item%hash == hash) THEN
310 IF (callgraph_keys_equal(item%key, key)) THEN
311 IF (ASSOCIATED(prev_item)) THEN
312 prev_item%next => item%next
313 ELSE
314 hash_map%buckets(idx)%p => item%next
315 END IF
316 DEALLOCATE (item)
317 hash_map%size = hash_map%size - 1
318 RETURN
319 END IF
320 END IF
321 prev_item => item
322 item => item%next
323 END DO
324
325 cpabort("Key not found.")
326 END SUBROUTINE callgraph_del
327
328! **************************************************************************************************
329!> \brief Returns the number of key/value-items currently stored in the hash map.
330!> \param hash_map ...
331!> \return ...
332!> \author Ole Schuett
333! **************************************************************************************************
334 FUNCTION callgraph_size(hash_map) RESULT(size)
335 TYPE(callgraph_type), INTENT(IN) :: hash_map
336 INTEGER :: size
337
338 cpassert(ASSOCIATED(hash_map%buckets))
339 size = hash_map%size
340 END FUNCTION callgraph_size
341
342! **************************************************************************************************
343!> \brief Checks whether a given key is currently stored in the hash_map.
344!> \param hash_map ...
345!> \param key ...
346!> \return ...
347!> \author Ole Schuett
348! **************************************************************************************************
349 FUNCTION callgraph_haskey(hash_map, key) RESULT(res)
350 TYPE(callgraph_type), INTENT(IN) :: hash_map
351 INTEGER(kind=int_4), DIMENSION(2), INTENT(IN) :: key
352 LOGICAL :: res
353 TYPE(private_item_type), POINTER :: item
354 INTEGER(KIND=int_8) :: hash, idx
355
356 cpassert(ASSOCIATED(hash_map%buckets))
357
358 res = .false.
359 IF (hash_map%size == 0) RETURN
360
361 hash = callgraph_hash_function(key)
362 idx = mod(hash, int(size(hash_map%buckets), kind=int_8)) + 1
363
364 item => hash_map%buckets(idx)%p
365 DO WHILE (ASSOCIATED(item))
366 IF (item%hash == hash) THEN
367 IF (callgraph_keys_equal(item%key, key)) THEN
368 res = .true.
369 return
370 END IF
371 END IF
372 item => item%next
373 END DO
374
375 END FUNCTION callgraph_haskey
376
377! **************************************************************************************************
378!> \brief Returns a pointer to an array of all key/value-items stored in the hash map.
379!> Caution: The caller is responsible for deallocating targeted array after usage.
380!> \param hash_map ...
381!> \return ...
382!> \author Ole Schuett
383! **************************************************************************************************
384 FUNCTION callgraph_items(hash_map) RESULT(items)
385 TYPE(callgraph_type), INTENT(IN) :: hash_map
386 TYPE(callgraph_item_type), DIMENSION(:), POINTER :: items
387
388 TYPE(private_item_type), POINTER :: item
389 INTEGER :: i, j
390
391 cpassert(ASSOCIATED(hash_map%buckets))
392
393 ALLOCATE (items(hash_map%size))
394 j = 1
395 DO i = 1, size(hash_map%buckets)
396 item => hash_map%buckets(i)%p
397 DO WHILE (ASSOCIATED(item))
398 items(j)%key =item%key
399 items(j)%value =>item%value
400 j = j + 1
401 item => item%next
402 END DO
403 END DO
404
405 cpassert(j == hash_map%size + 1)
406 END FUNCTION callgraph_items
407
408! **************************************************************************************************
409!> \brief Copies all key/values-items from one hash map to another.
410!> Afterwards hash_map will contain all items from the from_hash_map and
411!> additionally all its previous items, which were not overwritten.
412!> The two hash maps have to be of the same type.
413!> \param hash_map destination of items
414!> \param from_hash_map source of items - will not be change
415!> \author Ole Schuett
416! **************************************************************************************************
417 SUBROUTINE callgraph_update(hash_map, from_hash_map)
418 TYPE(callgraph_type), INTENT(inout) :: hash_map
419 TYPE(callgraph_type), INTENT(in) :: from_hash_map
420 TYPE(callgraph_item_type), DIMENSION(:), POINTER :: from_items
421 INTEGER :: i
422
423 cpassert(ASSOCIATED(hash_map%buckets))
424 cpassert(ASSOCIATED(from_hash_map%buckets))
425
426 from_items => callgraph_items(from_hash_map)
427 DO i = 1, size(from_items)
428 CALL callgraph_set(hash_map, from_items(i)%key, from_items(i)%value)
429 END DO
430 DEALLOCATE (from_items)
431 END SUBROUTINE callgraph_update
432
433
434! **************************************************************************************************
435!> \brief ...
436!> \param key ...
437!> \return ...
438! **************************************************************************************************
439 PURE FUNCTION callgraph_hash_function(key) RESULT(hash)
440 INTEGER(kind=int_4), DIMENSION(2), INTENT(in) :: key
441 INTEGER(KIND=int_8) :: hash
442
443 INTEGER(kind=int_8) :: k1, k2
444 k1 = key(1) ! cast to int_8
445 k2 = key(2)
446 hash = ior(k1, ishft(k2, 32))
447 END FUNCTION callgraph_hash_function
448
449! **************************************************************************************************
450!> \brief ...
451!> \param key ...
452!> \return ...
453! **************************************************************************************************
454 PURE FUNCTION callgraph_keys_equal(key1, key2) RESULT(res)
455 INTEGER(kind=int_4), DIMENSION(2), INTENT(in) :: key1, key2
456 LOGICAL :: res
457
458 res = all(key1 == key2)
459 END FUNCTION callgraph_keys_equal
460
461END 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:122
integer function, public callgraph_size(hash_map)
Returns the number of key/value-items currently stored in the hash map.
Definition callgraph.F:335
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:385
logical function, public callgraph_haskey(hash_map, key)
Checks whether a given key is currently stored in the hash_map.
Definition callgraph.F:350
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:257
subroutine, public callgraph_set(hash_map, key, value)
Stores, and possibly overwrites, a given value under a given key.
Definition callgraph.F:149
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,...