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]
Posted in Programming Tagged with: ,
One comment on “Transfer
  1. Stefano says:

    Hi Jacob,
    I think that the *transfer* function is a really useful built-in function often not completely exploited. I do it for a simple Base64 encoding https://github.com/szaghi/BeFoR64/blob/master/src/Lib_Base64.f90#L444

    Before switching to unlimited polymorphic class(*) I also used it for a generic list.

    See you soon.

Leave a Reply

Your email address will not be published. Required fields are marked *

*