!== Hash module ! ! Authors:: Yasuhiro MORIKAWA ! Version:: $Id: dc_hash.f90,v 1.4 2006/10/09 11:00:06 morikawa Exp $ ! Tag Name:: $Name: gt4f90io-20070101 $ ! Copyright:: Copyright (C) GFD Dennou Club, 2005. All rights reserved. ! License:: See COPYRIGHT[link:../../COPYRIGHT] ! ! This file provides dc_hash ! module dc_hash ! !== Overview ! ! スクリプト言語ではおなじみとなっている ハッシュ (連想配列) ! を提供します. ! ! ただし, 現在「値」として与えられるのは文字型のみです. ! !== List ! ! Put :: ハッシュにキーと値を付加 ! Get :: キーを与え, ハッシュ内の関連する値を取得 ! Rewind :: ハッシュ内全体を探査するための初期化 ! Next :: Rewind 参照 ! Delete :: キーを与え, ハッシュ内の関連する値を削除 ! Number :: ハッシュのサイズを返す ! Put_Line :: ハッシュの内容を標準出力に出力 (デバック用) ! ! !== Usage ! ! use dc_types ! use dc_hash ! type(HASH):: hashv ! character(len = STRING):: key, value ! logical:: end ! ! call Put(hashv, 'key1', 'val1') ! call Put(hashv, 'key2', 'val2') ! call Put(hashv, 'key3', 'val3') ! ! call Get(hashv, 'key1', value) ! write(*,*) 'key=' // 'key1' // ', value=' // trim(value) ! ! write(*,*) 'number(hashv)=', Number(hashv) ! ! call Delete(hashv, 'key1') ! ! call Rewind(hashv) ! do ! call Next(hashv, key, value, end) ! if (end) exit ! write(*,*) 'key=' // trim(key) // ', value=' // trim(value) ! enddo ! ! call Delete(hashv) ! cleaning ! ! 以下のように出力されます. ! ! key=key1, value=val1 ! number(hashv)= 3 ! key=key2, value=val2 ! key=key3, value=val3 ! ! use dc_types, only : STRING implicit none private public:: HASH public:: Put, Put_Line, Get, Rewind, Next, Delete, Number type HASH ! !=== ハッシュ構造体 ! ! 利用法に関しては dc_hash を参照してください. ! private type(HASH_INTERNAL), pointer :: hash_table(:) => null() integer :: search_index = 0 end type HASH type HASH_INTERNAL private character(STRING) :: key character(STRING) :: value end type HASH_INTERNAL interface Put module procedure DCHashPut end interface interface Number module procedure DCHashNumber end interface interface Put_Line module procedure DCHashPut_Line end interface interface Rewind module procedure DCHashRewind end interface interface Next module procedure DCHashNext end interface interface Get module procedure DCHashGet end interface interface Delete module procedure DCHashDelete end interface contains subroutine DCHashPut(hashv, key, value) ! !=== ハッシュへ代入 ! ! *hashv* のキー *key* に値 *value* を関連付けます. ! ! implicit none type(HASH), intent(inout) :: hashv character(*), intent(in) :: key, value type(HASH_INTERNAL), pointer :: hash_table_tmp(:) => null() integer :: table_size, new_index, i logical :: found character(STRING) :: search_value continue call DCHashGet(hashv, key, search_value, found) if (.not. found) then table_size = DCHashNumber(hashv) if (table_size > 0) then allocate(hash_table_tmp(table_size)) hash_table_tmp = hashv % hash_table deallocate(hashv % hash_table) allocate(hashv % hash_table(table_size + 1)) hashv % hash_table(1:table_size) = hash_table_tmp(1:table_size) deallocate(hash_table_tmp) new_index = table_size + 1 else allocate(hashv % hash_table(1)) new_index = 1 end if hashv % hash_table(new_index) % key = key hashv % hash_table(new_index) % value = value else do i = 1, size(hashv % hash_table) if (trim(hashv % hash_table(i) % key) == trim(key)) then hashv % hash_table(i) % value = value end if end do end if end subroutine DCHashPut function DCHashNumber(hashv) result(result) ! !=== ハッシュのサイズ ! ! *hashv* のサイズを返します. ! implicit none type(HASH), intent(in) :: hashv integer :: result continue if (associated(hashv % hash_table)) then result = size(hashv % hash_table) else result = 0 end if end function DCHashNumber subroutine DCHashRewind(hashv) ! !=== ハッシュの内容を取り出すための初期化 (巻き戻し) ! ! *hashv* の巻き戻しを行います. Next との組み合わせによって ! キーと値のリストを取得すること可能です. ! ! 以下のサンプルソースコードを参照ください. ! ! ! ハッシュ一覧の取得 ! use dc_type ! use dc_hash ! type(HASH):: hashv ! character(len = STRING):: key, value ! logical:: end ! ! call Rewind(hashv) ! do ! call Next(hashv, key, value, end) ! if (end) exit ! write(*,*) 'key=' // trim(key) // ', value=' // trim(value) ! enddo ! implicit none type(HASH), intent(inout) :: hashv continue hashv % search_index = 1 end subroutine DCHashRewind subroutine DCHashNext(hashv, key, value, end) ! !=== ハッシュの内容を取得 ! ! *hashv* の内容を *key* と *value* に返します. ! 詳しくは Rewind を参照してください. ! implicit none type(HASH), intent(inout) :: hashv character(*), intent(out) :: key character(*), intent(out), optional :: value logical, intent(out) :: end integer :: table_size character(STRING) :: value_tmp continue table_size = DCHashNumber(hashv) if (table_size < hashv % search_index) then key = '' value_tmp = '' end = .true. else key = hashv % hash_table(hashv % search_index) % key value_tmp = hashv % hash_table(hashv % search_index) % value end = .false. hashv % search_index = hashv % search_index + 1 end if if (present(value)) then value = value_tmp end if end subroutine DCHashNext subroutine DCHashPut_Line(hashv) ! !=== ハッシュの内容を印字 ! ! *hashv* の内容を標準出力に表示します. ! use dc_types, only: STRING use dc_string, only: Printf, JoinChar implicit none type(HASH), intent(in) :: hashv type(HASH) :: hashv_tmp character(len = STRING):: key, value logical:: end continue hashv_tmp = hashv call Printf(6, '# "%c",', & & c1=trim(key), c2=trim(value)) enddo call Printf(6, '> ') end subroutine DCHashPut_Line subroutine DCHashGet(hashv, key, value, found) ! !=== ハッシュの値を取得 ! ! *hashv* のキー *key* に関連する値を *value* に返します. ! *key* に関連する値が存在しない場合は *value* に ! 空文字を返します. ! ! *found* を与えると, *key* に関連する値が見つからなかった ! 場合に .false. を返します. ! use dc_types, only: STRING implicit none type(HASH), intent(inout) :: hashv character(*), intent(in) :: key character(*), intent(out) :: value logical, intent(out), optional :: found character(STRING) :: search_key, search_value logical :: end continue call DCHashRewind(hashv) do call DCHashNext(hashv, search_key, search_value, end) if (end) then value = '' if (present(found)) found = .false. exit end if if (trim(search_key) == trim(key)) then value = search_value if (present(found)) found = .true. exit end if enddo end subroutine DCHashGet subroutine DCHashDelete(hashv, key) ! !=== ハッシュ内の値の削除 ! ! *hashv* のキー *key* およびその関連する値を削除します. ! *hashv* 内に *key* が見つからない場合には何もしません. ! ! *key* が省略される場合には *hashv* 内の全てのキーと値を ! 削除します. ! implicit none type(HASH), intent(inout) :: hashv character(*), intent(in), optional :: key type(HASH_INTERNAL), pointer :: hash_table_tmp(:) => null() integer :: table_size, i, j logical :: found character(STRING) :: search_value continue if (present(key)) then call DCHashGet(hashv, key, search_value, found) table_size = DCHashNumber(hashv) if (found .and. table_size > 1) then allocate(hash_table_tmp(table_size)) hash_table_tmp = hashv % hash_table deallocate(hashv % hash_table) allocate(hashv % hash_table(table_size - 1)) j = 1 do i = 1, table_size if (trim(hash_table_tmp(i) % key) /= trim(key)) then hashv % hash_table(j) % key = hash_table_tmp(i) % key hashv % hash_table(j) % value = hash_table_tmp(i) % value j = j + 1 end if end do deallocate(hash_table_tmp) elseif (found .and. table_size == 1) then deallocate(hashv % hash_table) end if else if (associated(hashv % hash_table)) deallocate(hashv % hash_table) end if end subroutine DCHashDelete end module dc_hash