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 
10 module 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 
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 
127  interface dchashputline
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 
178 contains
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 
404 end module dc_hash
integer function dchashnumber0(hashv)
Definition: dc_hash.f90:222
subroutine dchashput0(hashv, key, value)
Definition: dc_hash.f90:181
subroutine dchashget0(hashv, key, value, found)
Definition: dc_hash.f90:326
character(string) function, public joinchar(carray, expr)
Definition: dc_string.f90:861
文字型変数の操作.
Definition: dc_string.f90:24
subroutine dchashnext0(hashv, key, value, end)
Definition: dc_hash.f90:267
種別型パラメタを提供します。
Definition: dc_types.f90:49
subroutine dchashrewind0(hashv)
Definition: dc_hash.f90:237
subroutine dchashputline0(hashv)
Definition: dc_hash.f90:299
subroutine dchashdelete0(hashv, key)
Definition: dc_hash.f90:362
integer, parameter, public string
文字列を保持する 文字型変数の種別型パラメタ
Definition: dc_types.f90:118