gtool5 Fortran 90/95 ライブラリ 1.0.0-rc5
English
Loading...
Searching...
No Matches
dc_hash.f90
Go to the documentation of this file.
1!-----------------------------------------------------------------------
2! Copyright (c) 2000-2026 Gtool Development Group. All rights reserved.
3!-----------------------------------------------------------------------
4!>
5!> @author Youhei SASAKI, Yasuhiro MORIKAWA
6!> @copyright Copyright (C) GFD Dennou Club, 2005-2026. All rights reserved. <br/>
7!> License is BSD-2-Clause. see [COPYRIGHT](@ref COPYRIGHT) in detail
8!> @en
9!> @brief Hash (associative array) module
10!> @details
11!> This module provides hash (associative array) which is familiar
12!> in script languages.
13!>
14!> Currently, only character type can be given as "value".
15!>
16!> @section hash_procedures Procedures List
17!>
18!> | Procedure | Description |
19!> |----------------|-----------------------------------------------------|
20!> | DCHashPut | Add key and value to hash |
21!> | DCHashGet | Get associated value from hash with key |
22!> | DCHashRewind | Initialize for searching entire hash |
23!> | DCHashNext | See Rewind |
24!> | DCHashDelete | Delete associated value from hash with key |
25!> | DCHashNumber | Return size of hash |
26!> | DCHashPutLine | Print hash contents to stdout (for debug) |
27!>
28!> @section hash_usage Usage
29!>
30!> @code{.f90}
31!> use dc_types
32!> use dc_hash
33!> type(HASH):: hashv
34!> character(len = STRING):: key, value
35!> logical:: end
36!>
37!> call DCHashPut( hashv = hashv, key = 'key1', value = 'val1')
38!> call DCHashPut( hashv = hashv, key = 'key2', value = 'val2')
39!> call DCHashPut( hashv = hashv, key = 'key3', value = 'val3')
40!>
41!> call DCHashGet( hashv = hashv, key = 'key1', value = value )
42!> write(*,*) 'key=' // 'key1' // ', value=' // trim(value)
43!>
44!> write(*,*) 'number(hashv)=', DCHashNumber( hashv )
45!>
46!> call DCHashDelete( hashv = hashv, key = 'key1')
47!>
48!> call DCHashRewind( hashv )
49!> do
50!> call DCHashNext( hashv = hashv, key = key, value = value, end = end)
51!> if (end) exit
52!> write(*,*) 'key=' // trim(key) // ', value=' // trim(value)
53!> enddo
54!>
55!> call DCHashDelete( hashv )
56!> @endcode
57!>
58!> Output:
59!>
60!> key=key1, value=val1
61!> number(hashv)= 3
62!> key=key2, value=val2
63!> key=key3, value=val3
64!>
65!> @enden
66!>
67!> @ja
68!> @brief ハッシュ (連想配列) モジュール
69!> @details
70!> スクリプト言語ではおなじみとなっているハッシュ
71!> (連想配列) を提供します.
72!>
73!> ただし, 現在「値」として与えられるのは文字型のみです.
74!>
75!> @section hash_procedures_ja 手続一覧
76!>
77!> | 手続名 | 説明 |
78!> |----------------|-----------------------------------------------------|
79!> | DCHashPut | ハッシュにキーと値を付加 |
80!> | DCHashGet | キーを与え, ハッシュ内の関連する値を取得 |
81!> | DCHashRewind | ハッシュ内全体を探査するための初期化 |
82!> | DCHashNext | Rewind 参照 |
83!> | DCHashDelete | キーを与え, ハッシュ内の関連する値を削除 |
84!> | DCHashNumber | ハッシュのサイズを返す |
85!> | DCHashPutLine | ハッシュの内容を標準出力に出力 (デバック用) |
86!>
87!> @section hash_usage_ja 使用方法
88!>
89!> @code{.f90}
90!> use dc_types
91!> use dc_hash
92!> type(HASH):: hashv
93!> character(len = STRING):: key, value
94!> logical:: end
95!>
96!> call DCHashPut( hashv = hashv, key = 'key1', value = 'val1')
97!> call DCHashPut( hashv = hashv, key = 'key2', value = 'val2')
98!> call DCHashPut( hashv = hashv, key = 'key3', value = 'val3')
99!>
100!> call DCHashGet( hashv = hashv, key = 'key1', value = value )
101!> write(*,*) 'key=' // 'key1' // ', value=' // trim(value)
102!>
103!> write(*,*) 'number(hashv)=', DCHashNumber( hashv )
104!>
105!> call DCHashDelete( hashv = hashv, key = 'key1')
106!>
107!> call DCHashRewind( hashv )
108!> do
109!> call DCHashNext( hashv = hashv, key = key, value = value, end = end)
110!> if (end) exit
111!> write(*,*) 'key=' // trim(key) // ', value=' // trim(value)
112!> enddo
113!>
114!> call DCHashDelete( hashv )
115!> @endcode
116!>
117!> 以下のように出力されます.
118!>
119!> key=key1, value=val1
120!> number(hashv)= 3
121!> key=key2, value=val2
122!> key=key3, value=val3
123!>
124!> @note 「ハッシュ」という命名について
125!>
126!> スクリプト言語 Ruby では, 連想配列の内部にデータ検索
127!> アルゴリズム「ハッシュ」が利用されることから,
128!> そのクラス名に「Hash」という名前がついている.
129!> 従ってアルゴリズムとしてハッシュを用いていないこのモジュールの名称
130!> が「dc_hash」であることは本来ふさわしくないのだが,
131!> 適切な英名が無い事から, このような名称となっている.
132!>
133!> @note 後方互換
134!>
135!> バージョン 20071009 以前に利用可能だった以下の手続きは,
136!> 後方互換のため, しばらくは利用可能です.
137!>
138!> - Put, PutLine, Get, Rewind, Next, Delete, Number
139!>
140!> @endja
141!>
142
144 use dc_types, only : string
145 implicit none
146 private
147
148 public:: hash
151
152 !-----------------------------------------------
153 ! 後方互換用
154 ! For backward compatibility
155 public:: put, putline, get, rewind, next, delete, number
156
157 !> @en
158 !> @brief Hash (associative array) derived type
159 !> @details
160 !> See dc_hash for usage.
161 !> @enden
162 !>
163 !> @ja
164 !> @brief ハッシュ (連想配列) 構造型
165 !> @details
166 !> 利用法に関しては dc_hash を参照してください.
167 !> @endja
168 type hash
169 private
170 type(HASH_INTERNAL), pointer :: hash_table(:) => null()
171 !< @en Internal hash table @enden
172 !< @ja 内部ハッシュテーブル @endja
173 integer :: search_index = 0
174 !< @en Current search index @enden
175 !< @ja 現在の検索インデックス @endja
176 end type hash
177
178 !> @en
179 !> @brief Internal type for hash entry
180 !> @enden
181 !> @ja
182 !> @brief ハッシュエントリ用内部型
183 !> @endja
184 type hash_internal
185 private
186 character(STRING) :: key
187 !< @en Key string @enden
188 !< @ja キー文字列 @endja
189 character(STRING) :: value
190 !< @en Value string @enden
191 !< @ja 値文字列 @endja
192 end type hash_internal
193
194 interface dchashput
195 module procedure dchashput0
196 end interface
197
198 interface dchashnumber
199 module procedure dchashnumber0
200 end interface
201
203 module procedure dchashputline0
204 end interface
205
206 interface dchashrewind
207 module procedure dchashrewind0
208 end interface
209
210 interface dchashnext
211 module procedure dchashnext0
212 end interface
213
214 interface dchashget
215 module procedure dchashget0
216 end interface
217
218 interface dchashdelete
219 module procedure dchashdelete0
220 end interface
221
222 !-----------------------------------------------
223 ! 後方互換用
224 ! For backward compatibility
225 interface put
226 module procedure dchashput0
227 end interface
228
229 interface number
230 module procedure dchashnumber0
231 end interface
232
233 interface putline
234 module procedure dchashputline0
235 end interface
236
237 interface rewind
238 module procedure dchashrewind0
239 end interface
240
241 interface next
242 module procedure dchashnext0
243 end interface
244
245 interface get
246 module procedure dchashget0
247 end interface
248
249 interface delete
250 module procedure dchashdelete0
251 end interface
252
253contains
254
255 !> @en
256 !> @brief Add key and value to hash
257 !> @details
258 !> Associates `value` with `key` in `hashv`.
259 !> If `key` already exists, the associated value is updated.
260 !>
261 !> @param[in,out] hashv Hash variable
262 !> @param[in] key Key string
263 !> @param[in] value Value string to associate with the key
264 !> @enden
265 !>
266 !> @ja
267 !> @brief ハッシュにキーと値を付加
268 !> @details
269 !> `hashv` のキー `key` に値 `value` を関連付けます.
270 !> `key` が既に存在する場合は, 関連する値を更新します.
271 !>
272 !> @param[in,out] hashv ハッシュ変数
273 !> @param[in] key キー文字列
274 !> @param[in] value キーに関連付ける値文字列
275 !> @endja
276 subroutine dchashput0(hashv, key, value)
277 implicit none
278 type(hash), intent(inout) :: hashv
279 character(*), intent(in) :: key, value
280 type(hash_internal), pointer :: hash_table_tmp(:) => null()
281 integer :: table_size, new_index, i
282 logical :: found
283 character(STRING) :: search_value
284 continue
285 call dchashget(hashv, key, search_value, found)
286 if (.not. found) then
287 table_size = dchashnumber(hashv)
288 if (table_size > 0) then
289 allocate(hash_table_tmp(table_size))
290 hash_table_tmp = hashv % hash_table
291 deallocate(hashv % hash_table)
292 allocate(hashv % hash_table(table_size + 1))
293 hashv % hash_table(1:table_size) = hash_table_tmp(1:table_size)
294 deallocate(hash_table_tmp)
295 new_index = table_size + 1
296 else
297 allocate(hashv % hash_table(1))
298 new_index = 1
299 end if
300
301 hashv % hash_table(new_index) % key = key
302 hashv % hash_table(new_index) % value = value
303 else
304 do i = 1, size(hashv % hash_table)
305 if (trim(hashv % hash_table(i) % key) == trim(key)) then
306 hashv % hash_table(i) % value = value
307 end if
308 end do
309 end if
310
311 end subroutine dchashput0
312
313
314 !> @en
315 !> @brief Return size of hash
316 !> @details
317 !> Returns the number of key-value pairs stored in `hashv`.
318 !>
319 !> @param[in] hashv Hash variable
320 !> @return Number of key-value pairs in the hash
321 !> @enden
322 !>
323 !> @ja
324 !> @brief ハッシュのサイズを返す
325 !> @details
326 !> `hashv` に格納されているキーと値のペア数を返します.
327 !>
328 !> @param[in] hashv ハッシュ変数
329 !> @return ハッシュ内のキーと値のペア数
330 !> @endja
331 function dchashnumber0(hashv) result(result)
332 implicit none
333 type(hash), intent(in) :: hashv
334 integer :: result
335 continue
336 if (associated(hashv % hash_table)) then
337 result = size(hashv % hash_table)
338 else
339 result = 0
340 end if
341 end function dchashnumber0
342
343 !> @en
344 !> @brief Initialize for searching entire hash
345 !> @details
346 !> Rewinds `hashv` mainly for the purpose of extracting hash contents.
347 !> Combined with DCHashNext, you can obtain a list of keys and values.
348 !>
349 !> See the following sample source code:
350 !>
351 !> @code{.f90}
352 !> program hash_sample
353 !> use dc_types
354 !> use dc_hash
355 !> type(HASH):: hashv
356 !> character(len = STRING):: key, value
357 !> logical:: end
358 !>
359 !> call DCHashRewind( hashv ) ! (inout)
360 !> do
361 !> call DCHashNext( hashv = hashv, & ! (inout)
362 !> & key = key, value = value, end = end) ! (out)
363 !> if (end) exit
364 !> write(*,*) 'key=' // trim(key) // ', value=' // trim(value)
365 !> enddo
366 !> end program hash_sample
367 !> @endcode
368 !>
369 !> @param[in,out] hashv Hash variable
370 !> @enden
371 !>
372 !> @ja
373 !> @brief ハッシュ内全体を探査するための初期化
374 !> @details
375 !> 主にハッシュの内容を取り出すことを目的として,
376 !> `hashv` の巻き戻しを行います. DCHashNext との組み合わせによって
377 !> キーと値のリストを取得することが可能です.
378 !>
379 !> 以下のサンプルソースコードを参照ください.
380 !>
381 !> @code{.f90}
382 !> program hash_sample
383 !> use dc_types
384 !> use dc_hash
385 !> type(HASH):: hashv
386 !> character(len = STRING):: key, value
387 !> logical:: end
388 !>
389 !> call DCHashRewind( hashv ) ! (inout)
390 !> do
391 !> call DCHashNext( hashv = hashv, & ! (inout)
392 !> & key = key, value = value, end = end) ! (out)
393 !> if (end) exit
394 !> write(*,*) 'key=' // trim(key) // ', value=' // trim(value)
395 !> enddo
396 !> end program hash_sample
397 !> @endcode
398 !>
399 !> @param[in,out] hashv ハッシュ変数
400 !> @endja
401 subroutine dchashrewind0(hashv)
402 implicit none
403 type(hash), intent(inout) :: hashv
404 continue
405 hashv % search_index = 1
406 end subroutine dchashrewind0
407
408 !> @en
409 !> @brief Get next key-value pair from hash
410 !> @details
411 !> Returns the contents of `hashv` to `key` and `value`.
412 !> See DCHashRewind for details.
413 !>
414 !> @param[in,out] hashv Hash variable
415 !> @param[out] key Key string
416 !> @param[out] value Value string (optional)
417 !> @param[out] end Returns .true. if all entries have been traversed
418 !> @enden
419 !>
420 !> @ja
421 !> @brief ハッシュから次のキーと値のペアを取得
422 !> @details
423 !> `hashv` の内容を `key` と `value` に返します.
424 !> 詳しくは DCHashRewind を参照してください.
425 !>
426 !> @param[in,out] hashv ハッシュ変数
427 !> @param[out] key キー文字列
428 !> @param[out] value 値文字列 (省略可能)
429 !> @param[out] end 全エントリを走査し終えた場合に .true. を返す
430 !> @endja
431 subroutine dchashnext0(hashv, key, value, end)
432 implicit none
433 type(hash), intent(inout) :: hashv
434 character(*), intent(out) :: key
435 character(*), intent(out), optional :: value
436 logical, intent(out) :: end
437 integer :: table_size
438 character(STRING) :: value_tmp
439 continue
440 table_size = dchashnumber(hashv)
441 if (table_size < hashv % search_index) then
442 key = ''
443 value_tmp = ''
444 end = .true.
445 else
446 key = hashv % hash_table(hashv % search_index) % key
447 value_tmp = hashv % hash_table(hashv % search_index) % value
448 end = .false.
449 hashv % search_index = hashv % search_index + 1
450 end if
451 if (present(value)) then
452 value = value_tmp
453 end if
454
455 end subroutine dchashnext0
456
457
458 !> @en
459 !> @brief Print hash contents to stdout
460 !> @details
461 !> Displays the contents of `hashv` to standard output.
462 !> This is mainly for debugging purposes.
463 !>
464 !> @param[in] hashv Hash variable
465 !> @enden
466 !>
467 !> @ja
468 !> @brief ハッシュの内容を標準出力に出力
469 !> @details
470 !> `hashv` の内容を標準出力に表示します.
471 !> 主にデバッグ用途に使用します.
472 !>
473 !> @param[in] hashv ハッシュ変数
474 !> @endja
475 subroutine dchashputline0(hashv)
476 use dc_types, only: string
477 use dc_string, only: printf, joinchar
478 implicit none
479 type(hash), intent(in) :: hashv
480 type(hash) :: hashv_tmp
481 character(len = STRING):: key, value
482 logical:: end
483 continue
484 hashv_tmp = hashv
485
486 call printf(6, '#<HASH:: ')
487 call dchashrewind(hashv_tmp)
488 do
489 call dchashnext(hashv_tmp, key, value, end)
490 if (end) exit
491 call printf(6, ' "%c" -> "%c",', &
492 & c1=trim(key), c2=trim(value))
493 enddo
494 call printf(6, '> ')
495
496 end subroutine dchashputline0
497
498
499 !> @en
500 !> @brief Get associated value from hash with key
501 !> @details
502 !> Returns the value associated with `key` in `hashv` to `value`.
503 !> If no value is associated with `key`, an empty string is returned
504 !> to `value`.
505 !>
506 !> If `found` is given, it returns `.false.` when no value associated
507 !> with `key` is found.
508 !>
509 !> @param[in,out] hashv Hash variable
510 !> @param[in] key Key string to search
511 !> @param[out] value Value associated with the key
512 !> @param[out] found Returns .false. if the key is not found (optional)
513 !> @enden
514 !>
515 !> @ja
516 !> @brief キーを与え, ハッシュ内の関連する値を取得
517 !> @details
518 !> `hashv` のキー `key` に関連する値を `value` に返します.
519 !> `key` に関連する値が存在しない場合は `value` に
520 !> 空文字を返します.
521 !>
522 !> `found` を与えると, `key` に関連する値が見つからなかった
523 !> 場合に `.false.` を返します.
524 !>
525 !> @param[in,out] hashv ハッシュ変数
526 !> @param[in] key 検索するキー文字列
527 !> @param[out] value キーに関連する値
528 !> @param[out] found キーが見つからない場合に .false. を返す (省略可能)
529 !> @endja
530 subroutine dchashget0(hashv, key, value, found)
531 use dc_types, only: string
532 implicit none
533 type(hash), intent(inout) :: hashv
534 character(*), intent(in) :: key
535 character(*), intent(out) :: value
536 logical, intent(out), optional :: found
537 character(STRING) :: search_key, search_value
538 logical :: end
539 continue
540 call dchashrewind(hashv)
541 do
542 call dchashnext(hashv, search_key, search_value, end)
543 if (end) then
544 value = ''
545 if (present(found)) found = .false.
546 exit
547 end if
548
549 if (trim(search_key) == trim(key)) then
550 value = search_value
551 if (present(found)) found = .true.
552 exit
553 end if
554 enddo
555
556 end subroutine dchashget0
557
558 !> @en
559 !> @brief Delete associated value from hash with key
560 !> @details
561 !> Deletes `key` and its associated value from `hashv`.
562 !> If `key` is not found in `hashv`, nothing is done.
563 !>
564 !> If `key` is omitted, all keys and values in `hashv` are deleted.
565 !>
566 !> @param[in,out] hashv Hash variable
567 !> @param[in] key Key string to delete (optional)
568 !> @enden
569 !>
570 !> @ja
571 !> @brief キーを与え, ハッシュ内の関連する値を削除
572 !> @details
573 !> `hashv` のキー `key` およびその関連する値を削除します.
574 !> `hashv` 内に `key` が見つからない場合には何もしません.
575 !>
576 !> `key` が省略される場合には `hashv` 内の全てのキーと値を
577 !> 削除します.
578 !>
579 !> @param[in,out] hashv ハッシュ変数
580 !> @param[in] key 削除するキー文字列 (省略可能)
581 !> @endja
582 subroutine dchashdelete0(hashv, key)
583 implicit none
584 type(hash), intent(inout) :: hashv
585 character(*), intent(in), optional :: key
586 type(hash_internal), pointer :: hash_table_tmp(:) => null()
587 integer :: table_size, i, j
588 logical :: found
589 character(STRING) :: search_value
590 continue
591 if (present(key)) then
592 call dchashget(hashv, key, search_value, found)
593 table_size = dchashnumber(hashv)
594 if (found .and. table_size > 1) then
595 allocate(hash_table_tmp(table_size))
596 hash_table_tmp = hashv % hash_table
597 deallocate(hashv % hash_table)
598 allocate(hashv % hash_table(table_size - 1))
599 j = 1
600 do i = 1, table_size
601 if (trim(hash_table_tmp(i) % key) /= trim(key)) then
602 hashv % hash_table(j) % key = hash_table_tmp(i) % key
603 hashv % hash_table(j) % value = hash_table_tmp(i) % value
604 j = j + 1
605 end if
606 end do
607
608 deallocate(hash_table_tmp)
609 elseif (found .and. table_size == 1) then
610 deallocate(hashv % hash_table)
611 end if
612 else
613 if (associated(hashv % hash_table)) deallocate(hashv % hash_table)
614 end if
615
616 end subroutine dchashdelete0
617
618 !> @namespace dc_hash
619end module dc_hash
ハッシュ (連想配列) モジュール
Definition dc_hash.f90:143
文字型変数の操作
Definition dc_string.f90:83
character(string) function, public joinchar(carray, expr)
種別型パラメタを提供します。
Definition dc_types.f90:55
integer, parameter, public string
文字列を保持する 文字型変数の種別型パラメタ
Definition dc_types.f90:137