    MODHASH(3)                 Library Functions Manual                 MODHASH(3)
    
    NAME
           MODHASH  -  Implementation  of an ordered, automatically resizing, hash
           table for fortran 90
    
    SYNOPSYS
           use modhash
    
           subroutine init(this,m,keylen,notfound): initialize hash table
           this:  class(hashtable)
    
           m: integer, intent(in), optional: Size of table, default 100
           if m < 1 or absent : size will be 100
    
           keylen: integer, intent(in), optional: Use at least keylen and at  most
           2*keylen characters computing the hash value.
           If keylen .le. 0: use all characters.
    
           notfound:  character(len=*), intent(in), optional: Value to return from
           lookup() when key is not found
           default ""
    
           usetrim: logical, intent(in), optional: .true.: Use trim  on  keys  and
           values, else do not use trim
           default .true.
    
           Note: init can be used on an existing hashtable, the existing hashtable
           will be cleaned.
           See also: resize.
    
           function insert(this,key,val) result(r): insert key/value pair in  hash
           table
           this:  class(hashtable)
    
           key, val: character(len=*), intent(in): Key/value pair to insert in the
           hash table.
    
           r:   logical, intent(out): .true. on success
           Normally, one expects this always to be .true.
           Note: if the number of items exceeds 0.7 * the size of  the  hashtable,
           the hashtable is resized.
    
           function  lookup(this,key,success) result(val): return value associated
           with key
           this: class(hashtable)
    
           key:  character(len=*), intent(in): Key to search for.
    
           success: logical, intent(out), optional: .true. if key is  found,  else
           .false.
    
           val: character(len=:), allocatable: Value associated with key.
           If key is not found, val = notfound (see init()).
    
           subroutine delete(this,key): deletes key/value pair
           this: class(hashtable)
    
           key:  character(len=*), intent(in): Key to delete.
    
           Note:  the key/value pair is marked as deleted, if you want to optimize
           the hash table after many deletions, use resize().
    
           function find(this,key) result(j): find index of key in hash table
           this: class(hashtable)
    
           key:  character(len=*), intent(in): Key to find.
    
           j:    integer: Index to be used with getkey and getval.
           If key not found: j = 0
           Usage is not recommended.
           See also: lookup()
    
           function getkey(this,j) result(key): return key at index
           this: class(hashtable)
    
           j:    integer, intent(in): Index to use.
    
           key: character(len=:), allocatable: Key on index j.
           Note: no check is done on validity of j.
           Usage is not recommended.
           See also: lookup()
    
           function getval(this,j) result(val): return value at index
           this: class(hashtable)
    
           j:    integer, intent(in): Index to use.
    
           val: character(len=:), allocatable: Value on index j.
           Note: No check is done on validity of j.
           Usage is not recommended.
           See also: lookup()
    
           subroutine stats(this,m,items,collisions,resizes,deletions,
           keylen,notfound): statistics about the hash table
           this: class(hashtable)
    
           m:    integer, intent(out), optional: Size of hash table.
    
           items: integer, intent(out), optional: Number  of  key/value  pairs  in
           hash table, including deleted items.
    
           collisions:  integer, intent(out), optional: Total number of collisions
           (i.e. different keys with same hash value).
    
           resizes: integer, intent(out), optional: Total number of resizes of the
           hash table.
    
           deletions:  integer,  intent(out),  optional:  Total  number of deleted
           items in the hash table.
    
           keylen: integer, intent(out), optional: Keylen used, see init().
    
           notfound: character(len=:), intent(out), allocatable,  optional:  Value
           returned by lookup() if key not found.
    
           subroutine  getentry(this,  n, r, key, val, del): main purpose: Get all
           entries from the hash table.
           this: class(hashtable)
    
           n:     integer, intent(inout)
           input: index of item to visit
           output: actual index used
    
           r:     logical, intent(out): .true. if item found, else .false.
    
           del:   logical, intent(out): .true. if found item was deleted,  .false.
           otherwize
    
           key, val: character(len=:), allocatable, intent(out): key/value pair of
           item.  If not found: val = notfound (see init())
    
           Note: this subroutine can be used to list all entries in the  hash  ta‐
           ble, see example.
    
           subroutine resize(this,n): resize hash table, get rid of deletions
           this: class(hashtable)
    
           n:    integer, intent(in), optional
           if  not  present: New size is calculated to allocate space for approxi‐
           mately two times the current not-deleted items.
           == 0: New size is calculated to hold the current not-deleted items.
           != 0: The new size will be n. If this value is to low to hold the  not-
           deleted items: no resizing will be done.
    
           Note: resizing is automatically done in insert() when needed.
    
           subroutine cleanup(this) : deallocates contents of hash table
           this: class(hashtable)
    
    EXAMPLE PROGRAM
            ---->
    
            program example
              use modhash
              implicit none
              type(hashtable) :: h
              logical         :: success, del
              integer         :: j,dels,items,i
              character(len=:), allocatable :: key,val
              print *,"Initializing..."
              call h%init(notfound="NOT FOUND")
              print *,"Inserting..."
              success = h%insert("first key","first value")
              success = h%insert("2nd key","2nd value")
              success = h%insert("3rd key","3rd value")
              j = h%find("first key")   ! not recommended, use lookup
              key = h%getkey(j)         ! not recommended, use lookup
              val = h%getval(j)         ! not recommended, use lookup
              print *, "Using stats ..."
              call h%stats(deletions=dels, items=items)
              print *,"deletions:",dels,"items",items
              print *,"Using lookup ..."
              val = h%lookup("2nd key")
              print *,"2nd key: ",val
              print *,"Using lookup with not existing key ..."
              val = h%lookup("xnd key")
              print *,"xnd key: ",val
              print *,"Deleting:"
              call h%delete("first key")
              print *, "Using stats again ..."
              call h%stats(deletions=dels, items=items)
              print *,"deletions:",dels,"items",items
              print *,"All entries ..."
              i = 1
              success = .true.
              do while(success)
                 call h%getentry(i, success, key, val, del)
                 if (success) print *,"key: ",key," value: ",val," deleted:",del
                 i = i+1
              enddo
              print *,"Resizing ..."
              call h%resize(0)
              print *, "Using stats again ..."
              call h%stats(deletions=dels, items=items)
              print *,"deletions:",dels,"items",items
              print *,"removing contents of hash table ..."
              call h%cleanup
            end program example
    
            <----
    
    EXAMPLE PROGRAM USING TRANSFER
            ---->
    
           !  example  using modhash with other data types, using transfer program
           cryst
              use modhash
              implicit none
              integer(selected_int_kind(3)) :: hkl(3,2)
              type reftype
                 real e
                 real r
                 integer(selected_int_kind(2)) :: m
              end type reftype
              type(reftype)   :: a,b,c
              type(hashtable) :: h
              real            :: eps = 0.00001
    
              character(len=:), allocatable :: hc,rc
              logical                       :: success
    
              allocate(character(len=sizeof(hkl(:,1))) :: hc)
              allocate(character(len=sizeof(a))        :: rc)
    
              print *,"len hc:",len(hc)
              print *,"len rc:",len(rc)
              hkl(1,1) = 2
              hkl(2,1) = 3
              hkl(3,1) = 0
              a%e=2.1
              a%m=4
              a%r=0.3
    
              hkl(1,2) = 0
              hkl(2,2) = 7
              hkl(3,2) = 3
    
              b%e=1.8
              b%m=1
              b%r=0.2
    
              call h%init(usetrim=.false.)
    
              success = h%insert(transfer(hkl(:,1),hc),transfer(a,rc))
              success = h%insert(transfer(hkl(:,2),hc),transfer(b,rc))
    
              c = transfer(h%lookup(transfer(hkl(:,1),hc)),c)
              print *,c
              if (aboutequal(c%e, a%e) .and. &
              &   aboutequal(c%r, a%r) .and. &
              &   c%m == a%m) then
                 print *,'OK'
              else
                 stop 1
              endif
              c = transfer(h%lookup(transfer(hkl(:,2),hc)),c)
              print *,c
              if (aboutequal(c%e, b%e) .and. &
              &   aboutequal(c%r, b%r) .and. &
              &   c%m == b%m) then
                 print *,'OK'
              else
                 stop 1
              endif
              c = transfer(h%lookup(transfer([4,5,6],hc),success),c)
              if (success) then
                 print *,c
                 stop 1
              else
                 print *,"not found"
                 print *,'OK'
              endif
    
              print *,'all is well'
    
              contains
              logical function aboutequal(x,y)
                 implicit none
                 real, intent(in) :: x,y
                 real             :: eps = 0.0001
                 aboutequal = (x > y - eps .and. x < y + eps)
              end function aboutequal
    
           end program cryst
    
            <----
    
           Compile this programs like:
    
           If you installed modhash 'properly' and have pkgconfig:
    
           gfortran `pkg-config --cflags modhash` -o example example.f90 \
                    `pkg-config --libs modhash`
    
           Otherwise if modhash is installed in /home/me/software:
    
           gfortran -I/home/me/include -o example example.f90 \
                    -L/home/me/lib -lmodhash
    
    COPYRIGHT
           This is free software; see the source for copying conditions.  There is
           NO  warranty;  not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR
           PURPOSE.
    
                                         2018                           MODHASH(3)
