Fortran hash table  0.1
 All Classes Namespaces Files Functions Variables
dictionary_m.f90
Go to the documentation of this file.
1 
3 
11 
13  implicit none
14 
15  private
16 
17  public :: dictionary_t
18 
20  type entry_t
21  character(len=:), allocatable :: key
22  character(len=:), allocatable :: value
23  end type entry_t
24 
26  type bucket_t
27  type(entry_t), allocatable :: entries(:)
28  integer :: current_size = 0
29  integer :: current_idx = 0
30  contains
31  procedure :: find
32  end type bucket_t
33 
36  type(bucket_t), allocatable :: buckets(:)
37  integer :: dict_size = 0
38  contains
39  procedure :: djb2
40  procedure :: set
41  procedure :: get
42  procedure :: init
43  procedure :: show
44  end type dictionary_t
45 
46  integer, parameter :: BUCKET_EMPTY = -2
47  integer, parameter :: BUCKET_ENTRY_NOT_FOUND = -4
48 
49 contains
50 
57  function djb2(this, s) result(r)
58  class(dictionary_t), intent(in) :: this
59  character(len=*), intent(in) :: s
60  integer :: r
61 
62  integer :: i, l
63 
64  l = len(s)
65 
66  r = 5381
67 
68  do i = 1, l
69  r = r*33 + ichar(s(i:i))
70  end do
71 
72  r = modulo(r, this%dict_size)
73 
74  end function djb2
75 
81  subroutine set(this, k, v)
82  class(dictionary_t), intent(inout) :: this
83  character(len=*), intent(in) :: k
84  character(len=*), intent(in) :: v
85 
86  type(bucket_t) :: tmp_bucket
87 
88  integer :: h, i, b_idx
89 
90  h = this%djb2(k) + 1
91 
92  b_idx = this%buckets(h)%find(k)
93 
94  if (b_idx == bucket_empty) then
95  ! allocate bucket for 1 entry
96  ! also, means we can take the first entry
97  allocate(this%buckets(h)%entries(1))
98  this%buckets(h)%current_size = 1
99  this%buckets(h)%current_idx = 1
100  b_idx = 1
101  this%buckets(h)%entries(1)%key = trim(k)
102  this%buckets(h)%entries(1)%value = trim(v)
103  ! the values are registered, exit
104  return
105  end if
106 
107  if (b_idx == bucket_entry_not_found) then
108  ! copy and grow bucket entries
109 
110  allocate(tmp_bucket%entries(this%buckets(h)%current_size + 1))
111  tmp_bucket%current_size = this%buckets(h)%current_size + 1
112  tmp_bucket%current_idx = this%buckets(h)%current_idx + 1
113 
114  do i = 1, this%buckets(h)%current_size
115  tmp_bucket%entries(i)%key = this%buckets(h)%entries(i)%key
116  tmp_bucket%entries(i)%value = this%buckets(h)%entries(i)%value
117  end do
118 
119  deallocate(this%buckets(h)%entries)
120  allocate(this%buckets(h)%entries, source=tmp_bucket%entries)
121  deallocate(tmp_bucket%entries)
122 
123  this%buckets(h)%current_size = tmp_bucket%current_size
124  this%buckets(h)%current_idx = tmp_bucket%current_idx
125  b_idx = this%buckets(h)%current_idx
126  end if
127 
128  if (b_idx > 0) then
129  this%buckets(h)%entries(b_idx)%key = k
130  this%buckets(h)%entries(b_idx)%value = v
131  end if
132 
133  end subroutine set
134 
139  subroutine init(this, dict_size)
140  class(dictionary_t), intent(out) :: this
141  integer, intent(in) :: dict_size
142 
143  allocate(this%buckets(dict_size))
144  this%dict_size = dict_size
145 
146  end subroutine init
147 
151  subroutine show(this)
152  class(dictionary_t), intent(in) :: this
153 
154  integer :: i, j, s
155  integer :: n
156 
157  n = 0
158  do i = 1, this%dict_size
159  s = this%buckets(i)%current_idx
160  if (s > 0) then
161  write(*,*) 'bucket : ', i, ' size ', s
162  do j = 1, s
163  write(*,*) 'key : ', this%buckets(i)%entries(j)%key
164  write(*,*) 'value : ', this%buckets(i)%entries(j)%value
165  end do
166  end if
167  end do
168 
169  end subroutine show
170 
179  function find(this, k) result(r)
180  class(bucket_t), intent(in) :: this
181  character(len=*), intent(in) :: k
182  integer :: r
183 
184  integer :: i
185 
186  if (this%current_size == 0) then
187  r = bucket_empty
188  return
189  end if
190 
191  r = bucket_entry_not_found
192  do i = 1, this%current_size
193  if (this%entries(i)%key == trim(k)) then
194  r = i
195  exit
196  end if
197  end do
198 
199  end function find
200 
207  function get(this, k) result(r)
208  class(dictionary_t), intent(in) :: this
209  character(len=*), intent(in) :: k
210 
211  character(len=:), allocatable :: r
212 
213  integer :: h, b_idx
214 
215  h = this%djb2(k) + 1
216 
217  b_idx = this%buckets(h)%find(k)
218 
219  if ( (b_idx == bucket_empty) .or. &
220  (b_idx == bucket_entry_not_found) ) then
221  r = ''
222  return
223  end if
224 
225  if (b_idx>0) then
226  r = this%buckets(h)%entries(b_idx)%value
227  end if
228 
229  end function get
230 
231 end module dictionary_m
A bucket contains several entries.
Single entry in the dictionary.
The dictionary contains dict_size buckets (defined at run time)
Dictionary type that uses strings for the keys and values.