SCALE-RM
scale_hash.F90
Go to the documentation of this file.
1 !-------------------------------------------------------------------------------
10 #include "scalelib.h"
11 module scale_hash
12  !-----------------------------------------------------------------------------
13  !
14  !++ used modules
15  !
16  use scale_precision
17  use scale_io
18 
19  use scale_prc, only: &
20  myrank => prc_myrank, &
21  prc_abort
22  !-----------------------------------------------------------------------------
23  implicit none
24  private
25  !-----------------------------------------------------------------------------
26  !
27  !++ Public procedure
28  !
29  type :: hash_entry
30 #if defined(__GFORTRAN__) && __GNUC__ < 7
31  character(len=128), pointer :: key
32 #else
33  character(len=:), pointer :: key
34 #endif
35  class(*), pointer :: val
36  integer :: cnt = 0
37  integer :: hash
38  type(hash_entry), pointer :: next => null()
39  end type hash_entry
40 
41  type :: hash_entry_ptr
42  type(hash_entry), pointer :: ptr => null()
43  end type hash_entry_ptr
44 
45  type, public :: hash_table
46  type(hash_entry_ptr), allocatable :: table(:)
47  integer :: size
48  integer :: len
49  integer :: max_len
50  contains
51  procedure :: destroy => destroy
52  procedure :: length => length
53  procedure :: has_key => has_key
54  procedure :: max_key_len => max_key_len
55  procedure :: keys => keys
56  procedure :: get => get
57  procedure :: get_with_cnt => get_with_cnt
58  procedure :: put => put
59  procedure :: accumurate => accumurate
60  procedure :: debug => debug
61  end type hash_table
62 
63  interface hash_table
64  module procedure :: table_new
65  end interface hash_table
66 
67  !-----------------------------------------------------------------------------
68  !
69  !++ Public parameters & variables
70  !
71  !-----------------------------------------------------------------------------
72  !
73  !++ Private parameters & variables
74  !
75  integer, parameter :: init_size = 64
76  integer, parameter :: hash_p = 19
77  integer, parameter :: hash_max = 124901413
78  integer, parameter :: size_max = 2**26 ! 26 = floor(log_2(HASH_MAX))
79 
80 contains
81 
82  !-----------------------------------------------------------------------------
84  type(hash_table) function table_new() result(tbl)
85  allocate( tbl%table(init_size) )
86  tbl%size = init_size
87  tbl%len = 0
88  tbl%max_len = 0
89 
90  return
91  end function table_new
92 
93  !-----------------------------------------------------------------------------
95  subroutine destroy(self)
96  class(hash_table), intent(inout) :: self
97  type(hash_entry), pointer :: e, e_old
98  integer :: idx
99 
100  do idx = 1, self%size
101  e => self%table(idx)%ptr
102  do while ( associated(e) )
103  deallocate( e%key, e%val )
104  e_old => e
105  e => e%next
106  deallocate( e_old )
107  end do
108  end do
109 
110  deallocate( self%table )
111  self%size = 0
112  self%len = 0
113  self%max_len = 0
114 
115  return
116  end subroutine destroy
117 
118  ! methods
119 
120  !-----------------------------------------------------------------------------
122  integer function length(self)
123  class(hash_table), intent(in) :: self
124 
125  length = self%len
126 
127  end function length
128 
129  !-----------------------------------------------------------------------------
131  logical function has_key(self, key) result(res)
132  class(hash_table), intent(in) :: self
133  character(len=*), intent(in) :: key
134 
135  type(hash_entry), pointer :: e
136  integer :: hash
137  integer :: idx
138 
139  hash = get_hash(key)
140  idx = get_index(hash, self%size)
141  e => self%table(idx)%ptr
142  do while ( associated(e) )
143  if ( e%key == key ) then
144  res = .true.
145  return
146  end if
147  e => e%next
148  end do
149  res = .false.
150  end function has_key
151 
152  !-----------------------------------------------------------------------------
154  integer function max_key_len(self, key)
155  class(hash_table), intent(in) :: self
156  character(len=*), intent(in) :: key
157 
158  max_key_len = self%max_len
159 
160  end function max_key_len
161 
162  !-----------------------------------------------------------------------------
164  subroutine keys(self, ary)
165  class(hash_table), intent(in) :: self
166  character(len=*), intent(out) :: ary(:)
167  type(hash_entry), pointer :: e
168  integer :: idx, i
169 
170  if ( size(ary) < self%len ) then
171  write(*,*) "size of ary is not enough: ", self%len
172  call abort()
173  end if
174 
175  i = 1
176  do idx = 1, self%size
177  e => self%table(idx)%ptr
178  do while ( associated(e) )
179  ary(i) = e%key
180  i = i+1
181  e => e%next
182  end do
183  end do
184 
185  end subroutine keys
186 
187  !-----------------------------------------------------------------------------
189  function get(self, key) result(val)
190  class(hash_table), intent(in) :: self
191  character(len=*), intent(in) :: key
192  class(*), pointer :: val
193 
194  type(hash_entry), pointer :: e
195  integer :: hash
196  integer :: idx
197 
198  hash = get_hash(key)
199  idx = get_index(hash, self%size)
200  e => self%table(idx)%ptr
201  do while ( associated(e) )
202  if ( e%key == key ) then
203  val => e%val
204  return
205  end if
206  e => e%next
207  end do
208  nullify(val)
209 
210  end function get
211 
212  !-----------------------------------------------------------------------------
214  subroutine get_with_cnt(self, key, val, cnt)
215  class(hash_table), intent(in) :: self
216  character(len=*), intent(in) :: key
217  class(*), pointer, intent(out) :: val
218  integer, intent(out) :: cnt
219 
220  type(hash_entry), pointer :: e
221  integer :: hash
222  integer :: idx
223 
224  hash = get_hash(key)
225  idx = get_index(hash, self%size)
226  e => self%table(idx)%ptr
227  do while ( associated(e) )
228  if ( e%key == key ) then
229  val => e%val
230  cnt = e%cnt
231  return
232  end if
233  e => e%next
234  end do
235 
236  end subroutine get_with_cnt
237 
238  !-----------------------------------------------------------------------------
240  subroutine put(self, key, val)
241  class(hash_table), intent(inout) :: self
242  character(len=*), intent(in) :: key
243  class(*), intent(in) :: val
244 
245  type(hash_entry), pointer :: e
246  integer :: hash
247  integer :: idx
248 
249  hash = get_hash(key)
250  idx = get_index(hash, self%size)
251 
252  ! try to find exist entry
253  e => self%table(idx)%ptr
254  do while ( associated(e) )
255  if ( e%key == key ) then
256  deallocate( e%val )
257  allocate( e%val, source=val )
258  return
259  end if
260  e => e%next
261  end do
262 
263  ! if not found
264  call new_entry(self, idx, hash, key, val)
265 
266  return
267  end subroutine put
268 
269  !-----------------------------------------------------------------------------
271  subroutine accumurate(self, key, val)
272  class(hash_table), intent(inout) :: self
273  character(len=*), intent(in) :: key
274  real(rp), intent(in) :: val
275 
276  type(hash_entry), pointer :: e
277  integer :: hash
278  integer :: idx
279 
280  hash = get_hash(key)
281  idx = get_index(hash, self%size)
282 
283  ! try to find exist entry
284  e => self%table(idx)%ptr
285  do while ( associated(e) )
286  if ( e%key == key ) then
287  select type ( v => e%val )
288  type is ( integer )
289  v = v + val
290  type is ( real(rp) )
291  v = v + val
292  class default
293  write(*,*) "type is invalid"
294  call abort()
295  end select
296  e%cnt = e%cnt + 1
297  return
298  end if
299  e => e%next
300  end do
301 
302  call new_entry(self, idx, hash, key, val)
303 
304  return
305  end subroutine accumurate
306 
307 
308  ! private methods
309 
310  function get_hash(key) result(hash)
311  character(len=*), intent(in) :: key
312  integer :: hash
313 
314  integer :: i
315 
316  hash = 0
317  do i = 1, len_trim(key)
318  hash = mod( hash * hash_p + ichar(key(i:i)), hash_max)
319  end do
320 
321  end function get_hash
322 
323  function get_index(hash, size) result(idx)
324  integer, intent(in) :: hash
325  integer, intent(in) :: size
326  integer :: idx
327 
328  idx = iand(hash, size-1) + 1
329  !write(*,*)"hash", hash, "idx", idx
330 
331  end function get_index
332 
333  subroutine new_entry(self, idx, hash, key, val)
334  class(hash_table), intent(inout) :: self
335  integer, intent(in) :: idx, hash
336  character(len=*), intent(in) :: key
337  class(*), intent(in) :: val
338 
339  type(hash_entry), pointer :: e_new
340  integer :: new_size
341  integer :: key_len
342 
343  ! new entry
344  allocate( e_new )
345  key_len = len_trim(key)
346 #if defined(__GFORTRAN__) && __GNUC__ < 7
347  if ( key_len > 128 ) then
348  log_error("new_entry",*) 'length of the key must be <=128: ', key_len
349  call prc_abort
350  endif
351 #endif
352  allocate( e_new%key, source=key )
353  allocate( e_new%val, source=val )
354  e_new%cnt = 1
355  e_new%hash = hash
356  e_new%next => self%table(idx)%ptr
357  self%table(idx)%ptr => e_new
358  self%len = self%len + 1
359  self%max_len = max(self%max_len, key_len)
360 
361  ! resize
362  if ( self%len * 2 >= self%size ) then
363  if ( self%size == size_max ) return
364  new_size = min( self%size * 2, size_max )
365  block
366  type(hash_entry_ptr) :: table(new_size)
367  type(hash_entry), pointer :: e, next
368  integer :: i, idx_new
369 
370  do i = 1, self%size
371  e => self%table(i)%ptr
372  do while ( associated(e) )
373  next => e%next
374  idx_new = get_index(e%hash, new_size)
375  e%next => table(idx_new)%ptr
376  table(idx_new)%ptr => e
377  e => next
378  end do
379  end do
380  deallocate( self%table )
381  allocate( self%table(new_size) )
382  do i = 1, new_size
383  self%table(i)%ptr => table(i)%ptr
384  end do
385  self%size = new_size
386  end block
387  end if
388 
389  return
390  end subroutine new_entry
391 
392  subroutine debug(self)
393  class(hash_table), intent(in) :: self
394  type(hash_entry), pointer :: e
395  integer :: idx, i
396 
397  write(*,'(a5,a32,a3,a8,a15,a2,a4,a10)') 'id', "key", " ", "val", "cnt", ", ", "idx", "hash"
398  i = 1
399  do idx = 1, self%size
400  e => self%table(idx)%ptr
401  do while ( associated(e) )
402  select type(v => e%val)
403  type is ( real(rp) )
404  write(*,'(i5,a32,a3,f15.3,i8,a2,i4,i10)') i, trim(e%key), " => ", v, e%cnt, ", ", idx, e%hash
405  type is ( integer )
406  write(*,'(i5,a32,a3,i15,i8,a2,i4,i10)') i, trim(e%key), " => ", v, e%cnt, ", ", idx, e%hash
407  class default
408  write(*,'(i5,a32,a3,a15,i8,a2,i4,i10)') i, trim(e%key), " => ", "type", e%cnt, ", ", idx, e%hash
409  end select
410  i = i+1
411  e => e%next
412  end do
413  end do
414 
415  end subroutine debug
416 
417 end module scale_hash
scale_prc::prc_abort
subroutine, public prc_abort
Abort Process.
Definition: scale_prc.F90:350
scale_hash
module CONSTANT
Definition: scale_hash.F90:11
scale_precision
module PRECISION
Definition: scale_precision.F90:14
scale_prc::prc_myrank
integer, public prc_myrank
process num in local communicator
Definition: scale_prc.F90:91
scale_hash::hash_table
Definition: scale_hash.F90:45
scale_prc
module PROCESS
Definition: scale_prc.F90:11
scale_io
module STDIO
Definition: scale_io.F90:10