_____
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)