Degenerate Conic

Algorithms • Modern Fortran Programming • Orbital Mechanics

Oct 17, 2015

Transfer

Fortran's TRANSFER function (introduced in Fortran 95) is a somewhat strange function that can be used to do some interesting things not otherwise possible in earlier versions of the language. In fact, it can be used to achieve a sort of poor-man's polymorphism. It can also still be useful in modern Fortran.

All this function does is transfers the bitwise representation of one variable into another variable. This is different from casting a variable of one type to another. For example:

program transfer_example  
use iso_fortran_env

integer(int64) :: i  
real(real64) :: d

i = 1

d = i !d is 1.0000000000000000  
d = transfer(i,d) !d is 4.9406564584124654E-324

end program transfer_example  

The following example shows how to use TRANSFER to create a hash function that can operate on any variable or derived type. The dummy argument of the hash_anything function is an unlimited polymorphic variable (class(*)). The bitwise representation of this variable is then transferred into a character string big enough to hold it (making use of the Fortran 2008 STORAGE_SIZE intrinsic), which can then be hashed using any hash function that takes a character string as an input (a basic DJB method is used here).

module hash_module

!integer kind to use for the hash:  
use iso_fortran_env, only: ip => INT32

implicit none

contains

function hash_anything(v) result(hash)  
!! Hash anything, using unlimited  
!! polymorphic variable and transfer()

class(*),intent(in) :: v  
integer(ip) :: hash

!!a default character string  
!!with the same size as v:  
character(len=ceiling(dble(storage_size(v))/&  
    dble(storage_size(' ')))) :: str

str = transfer(v,str) !transfer bits of v into  
!string of the same size  
hash = djb_hash(str) !hash it

end function hash_anything

function djb_hash(str) result(hash)  
!! Character string hashing with  
!! the DJB algorithm. From [1].

character(len=*),intent(in) :: str  
integer(ip) :: hash

integer :: i

hash = 5381_ip

do i=1,len(str)  
    hash = (ishft(hash,5_ip) + hash) + &  
           ichar(str(i:i))  
end do

end function djb_hash

end module hash_module  

See also

  1. Fortran hashing algorithm, July 6, 2013 [Fortran Dev]
  2. Hash table example [Fortran Wiki]