Loading...
Searching...
No Matches
dc_hash.f90
Go to the documentation of this file.
1!== Hash module
2!
3! Authors:: Yasuhiro MORIKAWA
4! Version:: $Id: dc_hash.f90,v 1.1 2009-03-20 09:09:53 morikawa Exp $
5! Tag Name:: $Name: $
6! Copyright:: Copyright (C) GFD Dennou Club, 2005. All rights reserved.
7! License:: See COPYRIGHT[link:../../COPYRIGHT]
8!
9
10module dc_hash
11 !
12 !== Overview
13 !
14 ! スクリプト言語ではおなじみとなっているハッシュ
15 ! (連想配列) を提供します.
16 !
17 ! ただし, 現在「値」として与えられるのは文字型のみです.
18 !
19 !== List
20 !
21 ! DCHashPut :: ハッシュにキーと値を付加
22 ! DCHashGet :: キーを与え, ハッシュ内の関連する値を取得
23 ! DCHashRewind :: ハッシュ内全体を探査するための初期化
24 ! DCHashNext :: Rewind 参照
25 ! DCHashDelete :: キーを与え, ハッシュ内の関連する値を削除
26 ! DCHashNumber :: ハッシュのサイズを返す
27 ! DCHashPutLine :: ハッシュの内容を標準出力に出力 (デバック用)
28 !
29 !
30 !== Usage
31 !
32 ! use dc_types
33 ! use dc_hash
34 ! type(HASH):: hashv
35 ! character(len = STRING):: key, value
36 ! logical:: end
37 !
38 ! call DCHashPut( hashv = hashv, & ! (out)
39 ! & key = 'key1', value = 'val1') ! (in)
40 ! call DCHashPut( hashv = hashv, & ! (inout)
41 ! & key = 'key2', value = 'val2') ! (in)
42 ! call DCHashPut( hashv = hashv, & ! (inout)
43 ! & key = 'key3', value = 'val3') ! (in)
44 !
45 ! call DCHashGet( hashv = hashv, & ! (inout)
46 ! & key = 'key1', & ! (in)
47 ! & value = value ) ! (out)
48 ! write(*,*) 'key=' // 'key1' // ', value=' // trim(value)
49 !
50 ! write(*,*) 'number(hashv)=', DCHashNumber( hashv )
51 !
52 ! call DCHashDelete( hashv = hashv, & ! (inout)
53 ! & key = 'key1') ! (in)
54 !
55 ! call DCHashRewind( hashv ) ! (inout)
56 ! do
57 ! call DCHashNext( hashv = hashv, & ! (inout)
58 ! & key = key, value = value, end = end) ! (out)
59 ! if (end) exit
60 ! write(*,*) 'key=' // trim(key) // ', value=' // trim(value)
61 ! enddo
62 !
63 ! call DCHashDelete( hashv ) ! (inout)
64 !
65 ! 以下のように出力されます.
66 !
67 ! key=key1, value=val1
68 ! number(hashv)= 3
69 ! key=key2, value=val2
70 ! key=key3, value=val3
71 !
72 !== Note
73 !
74 !=== 「ハッシュ」という命名について
75 !
76 ! スクリプト言語 Ruby では, 連想配列の内部にデータ検索
77 ! アルゴリズム「ハッシュ」が利用されることから,
78 ! そのクラス名に「Hash」という名前がついている.
79 ! 従ってアルゴリズムとしてハッシュを用いていないこのモジュールの名称
80 ! が「dc_hash」であることは本来ふさわしくないのだが,
81 ! 適切な英名が無い事から, このような名称となっている.
82 !
83 !=== 後方互換
84 !
85 ! バージョン 20071009 以前に利用可能だった以下の手続きは,
86 ! 後方互換のため, しばらくは利用可能です.
87 !
88 ! * Put, PutLine, Get, Rewind, Next, Delete, Number
89 !
90 !
91 use dc_types, only : string
92 implicit none
93 private
94
95 public:: hash
98
99 !-----------------------------------------------
100 ! 後方互換用
101 ! For backward compatibility
102 public:: put, putline, get, rewind, next, delete, number
103
104 type hash
105 !
106 ! 利用法に関しては dc_hash を参照してください.
107 !
108 private
109 type(HASH_INTERNAL), pointer :: hash_table(:) => null()
110 integer :: search_index = 0
111 end type hash
112
113 type hash_internal
114 private
115 character(STRING) :: key
116 character(STRING) :: value
117 end type hash_internal
118
119 interface dchashput
120 module procedure dchashput0
121 end interface
122
123 interface dchashnumber
124 module procedure dchashnumber0
125 end interface
126
128 module procedure dchashputline0
129 end interface
130
131 interface dchashrewind
132 module procedure dchashrewind0
133 end interface
134
135 interface dchashnext
136 module procedure dchashnext0
137 end interface
138
139 interface dchashget
140 module procedure dchashget0
141 end interface
142
143 interface dchashdelete
144 module procedure dchashdelete0
145 end interface
146
147 !-----------------------------------------------
148 ! 後方互換用
149 ! For backward compatibility
150 interface put
151 module procedure dchashput0
152 end interface
153
154 interface number
155 module procedure dchashnumber0
156 end interface
157
158 interface putline
159 module procedure dchashputline0
160 end interface
161
162 interface rewind
163 module procedure dchashrewind0
164 end interface
165
166 interface next
167 module procedure dchashnext0
168 end interface
169
170 interface get
171 module procedure dchashget0
172 end interface
173
174 interface delete
175 module procedure dchashdelete0
176 end interface
177
178contains
179
180 subroutine dchashput0(hashv, key, value)
181 !
182 ! *hashv* のキー *key* に値 *value* を関連付けます.
183 !
184 implicit none
185 type(hash), intent(inout) :: hashv
186 character(*), intent(in) :: key, value
187 type(hash_internal), pointer :: hash_table_tmp(:) => null()
188 integer :: table_size, new_index, i
189 logical :: found
190 character(STRING) :: search_value
191 continue
192 call dchashget(hashv, key, search_value, found)
193 if (.not. found) then
194 table_size = dchashnumber(hashv)
195 if (table_size > 0) then
196 allocate(hash_table_tmp(table_size))
197 hash_table_tmp = hashv % hash_table
198 deallocate(hashv % hash_table)
199 allocate(hashv % hash_table(table_size + 1))
200 hashv % hash_table(1:table_size) = hash_table_tmp(1:table_size)
201 deallocate(hash_table_tmp)
202 new_index = table_size + 1
203 else
204 allocate(hashv % hash_table(1))
205 new_index = 1
206 end if
207
208 hashv % hash_table(new_index) % key = key
209 hashv % hash_table(new_index) % value = value
210 else
211 do i = 1, size(hashv % hash_table)
212 if (trim(hashv % hash_table(i) % key) == trim(key)) then
213 hashv % hash_table(i) % value = value
214 end if
215 end do
216 end if
217
218 end subroutine dchashput0
219
220
221 function dchashnumber0(hashv) result(result)
222 !
223 ! *hashv* のサイズを返します.
224 !
225 implicit none
226 type(hash), intent(in) :: hashv
227 integer :: result
228 continue
229 if (associated(hashv % hash_table)) then
230 result = size(hashv % hash_table)
231 else
232 result = 0
233 end if
234 end function dchashnumber0
235
236 subroutine dchashrewind0(hashv)
237 !
238 ! 主にハッシュの内容を取り出すことを目的として,
239 ! *hashv* の巻き戻しを行います. DCHashNext との組み合わせによって
240 ! キーと値のリストを取得すること可能です.
241 !
242 ! 以下のサンプルソースコードを参照ください.
243 !
244 ! program hash_sample
245 ! use dc_type
246 ! use dc_hash
247 ! type(HASH):: hashv
248 ! character(len = STRING):: key, value
249 ! logical:: end
250 !
251 ! call DCHashRewind( hashv ) ! (inout)
252 ! do
253 ! call DCHashNext( hashv = hashv, & ! (inout)
254 ! & key = key, value = value, end = end) ! (out)
255 ! if (end) exit
256 ! write(*,*) 'key=' // trim(key) // ', value=' // trim(value)
257 ! enddo
258 ! end program hash_sample
259 !
260 implicit none
261 type(hash), intent(inout) :: hashv
262 continue
263 hashv % search_index = 1
264 end subroutine dchashrewind0
265
266 subroutine dchashnext0(hashv, key, value, end)
267 !
268
269 ! *hashv* の内容を *key* と *value* に返します.
270 ! 詳しくは DCHashRewind を参照してください.
271 !
272 implicit none
273 type(hash), intent(inout) :: hashv
274 character(*), intent(out) :: key
275 character(*), intent(out), optional :: value
276 logical, intent(out) :: end
277 integer :: table_size
278 character(STRING) :: value_tmp
279 continue
280 table_size = dchashnumber(hashv)
281 if (table_size < hashv % search_index) then
282 key = ''
283 value_tmp = ''
284 end = .true.
285 else
286 key = hashv % hash_table(hashv % search_index) % key
287 value_tmp = hashv % hash_table(hashv % search_index) % value
288 end = .false.
289 hashv % search_index = hashv % search_index + 1
290 end if
291 if (present(value)) then
292 value = value_tmp
293 end if
294
295 end subroutine dchashnext0
296
297
298 subroutine dchashputline0(hashv)
299 !
300 ! *hashv* の内容を標準出力に表示します.
301 !
302 use dc_types, only: string
303 use dc_string, only: printf, joinchar
304 implicit none
305 type(hash), intent(in) :: hashv
306 type(hash) :: hashv_tmp
307 character(len = STRING):: key, value
308 logical:: end
309 continue
310 hashv_tmp = hashv
311
312 call printf(6, '#<HASH:: ')
313 call dchashrewind(hashv_tmp)
314 do
315 call dchashnext(hashv_tmp, key, value, end)
316 if (end) exit
317 call printf(6, ' "%c" -> "%c",', &
318 & c1=trim(key), c2=trim(value))
319 enddo
320 call printf(6, '> ')
321
322 end subroutine dchashputline0
323
324
325 subroutine dchashget0(hashv, key, value, found)
326 !
327 ! *hashv* のキー *key* に関連する値を *value* に返します.
328 ! *key* に関連する値が存在しない場合は *value* に
329 ! 空文字を返します.
330 !
331 ! *found* を与えると, *key* に関連する値が見つからなかった
332 ! 場合に .false. を返します.
333 !
334 use dc_types, only: string
335 implicit none
336 type(hash), intent(inout) :: hashv
337 character(*), intent(in) :: key
338 character(*), intent(out) :: value
339 logical, intent(out), optional :: found
340 character(STRING) :: search_key, search_value
341 logical :: end
342 continue
343 call dchashrewind(hashv)
344 do
345 call dchashnext(hashv, search_key, search_value, end)
346 if (end) then
347 value = ''
348 if (present(found)) found = .false.
349 exit
350 end if
351
352 if (trim(search_key) == trim(key)) then
353 value = search_value
354 if (present(found)) found = .true.
355 exit
356 end if
357 enddo
358
359 end subroutine dchashget0
360
361 subroutine dchashdelete0(hashv, key)
362 !
363 ! *hashv* のキー *key* およびその関連する値を削除します.
364 ! *hashv* 内に *key* が見つからない場合には何もしません.
365 !
366 ! *key* が省略される場合には *hashv* 内の全てのキーと値を
367 ! 削除します.
368 !
369 implicit none
370 type(hash), intent(inout) :: hashv
371 character(*), intent(in), optional :: key
372 type(hash_internal), pointer :: hash_table_tmp(:) => null()
373 integer :: table_size, i, j
374 logical :: found
375 character(STRING) :: search_value
376 continue
377 if (present(key)) then
378 call dchashget(hashv, key, search_value, found)
379 table_size = dchashnumber(hashv)
380 if (found .and. table_size > 1) then
381 allocate(hash_table_tmp(table_size))
382 hash_table_tmp = hashv % hash_table
383 deallocate(hashv % hash_table)
384 allocate(hashv % hash_table(table_size - 1))
385 j = 1
386 do i = 1, table_size
387 if (trim(hash_table_tmp(i) % key) /= trim(key)) then
388 hashv % hash_table(j) % key = hash_table_tmp(i) % key
389 hashv % hash_table(j) % value = hash_table_tmp(i) % value
390 j = j + 1
391 end if
392 end do
393
394 deallocate(hash_table_tmp)
395 elseif (found .and. table_size == 1) then
396 deallocate(hashv % hash_table)
397 end if
398 else
399 if (associated(hashv % hash_table)) deallocate(hashv % hash_table)
400 end if
401
402 end subroutine dchashdelete0
403
404end module dc_hash
Provides kind type parameter values.
Definition dc_types.f90:49
integer, parameter, public string
Character length for string
Definition dc_types.f90:118