stdlib_hash_32bit.fypp Source File


Source Code

#! Integer kinds to be considered during templating
#:set INT_KINDS = ["int8", "int16", "int32", "int64"]

module stdlib_hash_32bit

    use, intrinsic :: iso_fortran_env, only : &
        character_storage_size

    use stdlib_kinds, only: &
        dp,                 &
        int8,               &
        int16,              &
        int32,              &
        int64

    implicit none

    private

    integer, parameter, public :: &
        int_hash     = int32
!! The number of bits in the output hash

! pow32_over_phi is the odd integer that most closely approximates 2**32/phi,
! where phi is the golden ratio 1.618...
    integer(int32), parameter ::                 &
        pow32_over_phi = int( z'9E3779B9', int32 )

! The number of bits used by each integer type
    integer, parameter ::               &
! Should be 8
        bits_int8  = bit_size(0_int8),  &
! Should be 16
        bits_int16 = bit_size(0_int16), &
! Should be 32
        bits_int32 = bit_size(0_int32), &
! Should be 64
        bits_int64 = bit_size(0_int64)

    integer, parameter ::                   &
! Should be 1
        bytes_int8  = bits_int8/bits_int8,  &
! Should be 2
        bytes_int16 = bits_int16/bits_int8, &
! Should be 4
        bytes_int32 = bits_int32/bits_int8, &
! Should be 8
        bytes_int64 = bits_int64/bits_int8

    integer, parameter ::                   &
        bits_char = character_storage_size, &
        bytes_char = bits_char/bits_int8

! Dealing with different endians
    logical, parameter, public ::                                    &
        little_endian = ( 1 == transfer([1_int8, 0_int8], 0_int16) )

    public ::               &
        fibonacci_hash,     &
        fnv_1_hash,         &
        fnv_1a_hash,        &
        new_nmhash32_seed,  &
        new_nmhash32x_seed, &
        new_water_hash_seed,&
        nmhash32,           &
        nmhash32x,          &
        odd_random_integer, &
        universal_mult_hash,&
        water_hash


    interface fnv_1_hash
!! Version: experimental
!!
!! FNV_1 interfaces
!! ([Specification](../page/specs/stdlib_hash_procedures.html#fnv_1_hash-calculates-a-hash-code-from-a-key))
        #:for k1 in INT_KINDS
          pure module function ${k1}$_fnv_1( key ) result(hash_code)
!! FNV_1 hash function for rank 1 array keys of kind ${k1}$
              integer(${k1}$), intent(in) :: key(:)
              integer(int_hash)           :: hash_code
          end function ${k1}$_fnv_1

        #:endfor

        elemental module function character_fnv_1( key ) result(hash_code)
!! FNV_1 hash function for default character string keys
            character(*), intent(in)      :: key
            integer(int_hash)             :: hash_code
        end function character_fnv_1

    end interface fnv_1_hash

    interface fnv_1a_hash
!! Version: experimental
!!
!! FNV_1A interfaces
!! ([Specification](../page/specs/stdlib_hash_procedures.html#fnv_1a_hash-calculates-a-hash-code-from-a-key))
        #:for k1 in INT_KINDS
          pure module function ${k1}$_fnv_1a( key ) result(hash_value)
!! FNV_1A hash function for rank 1 array keys of kind ${k1}$
              integer(${k1}$), intent(in)   :: key(:)
              integer(int_hash)             :: hash_value
          end function ${k1}$_fnv_1a

        #:endfor

        elemental module function character_fnv_1a( key ) result(hash_value)
!! FNV_1A hash function for default character string keys
            character(*), intent(in)      :: key
            integer(int_hash)             :: hash_value
        end function character_fnv_1a

    end interface fnv_1a_hash

    interface nmhash32
!! Version: experimental
!!
!! NMHASH32 interfaces
!! ([Specification](../page/specs/stdlib_hash_procedures.html#nmhash32-calculates-a-hash-code-from-a-key-and-a-seed))
        #:for k1 in INT_KINDS
          pure module function ${k1}$_nmhash32( key, seed ) &
              result(hash_value)
!! NMHASH32 hash function for rank 1 array keys of kind ${k1}$
              integer(${k1}$), intent(in)   :: key(0:)
              integer(int32), intent(in) :: seed
              integer(int32)             :: hash_value
          end function ${k1}$_nmhash32

        #:endfor

        elemental module function character_nmhash32( key, seed ) &
            result(hash_value)
!! NMHASH32 hash function for default character string keys
            character(*), intent(in)      :: key
            integer(int32), intent(in) :: seed
            integer(int32) :: hash_value
        end function character_nmhash32

    end interface nmhash32

    interface nmhash32x
!! Version: experimental
!!
!! NMHASH32X interfaces
!! ([Specification](file:///home/jvandenp/stdlib/API-doc/page/specs/stdlib_hash_procedures.html#nmhash32x-calculates-a-hash-code-from-a-key-and-a-seed))
        #:for k1 in INT_KINDS
          pure module function ${k1}$_nmhash32x( key, seed ) &
              result(hash_value)
!! NMHASH32 hash function for rank 1 array keys of kind ${k1}$
              integer(${k1}$), intent(in) :: key(0:)
              integer(int32), intent(in) :: seed
              integer(int32)             :: hash_value
          end function ${k1}$_nmhash32x

        #:endfor

        elemental module function character_nmhash32x( key, seed ) &
            result(hash_value)
!! NMHASH32 hash function for default character string keys
            character(*), intent(in)      :: key
            integer(int32), intent(in) :: seed
            integer(int32) :: hash_value
        end function character_nmhash32x

    end interface nmhash32x

    interface water_hash
!! Version: experimental
!!
!! WATER_HASH interfaces
!! ([Specification](../page/specs/stdlib_hash_procedures.html#water_hash-calculates-a-hash-code-from-a-key-and-a-seed))
        #:for k1 in INT_KINDS
          pure module function ${k1}$_water_hash( key, seed ) &
              result(hash_code)
!! WATER HASH function for rank 1 array keys of kind ${k1}$
              integer(${k1}$), intent(in) :: key(0:)
              integer(int64), intent(in)  :: seed
              integer(int_hash)           :: hash_code
          end function ${k1}$_water_hash
        #:endfor

        elemental module function character_water_hash( key, seed ) &
            result(hash_code)
!! WATER hash function for default character string keys
            character(*), intent(in)   :: key
            integer(int64), intent(in) :: seed
            integer(int_hash)          :: hash_code
        end function character_water_hash

    end interface water_hash

    interface new_water_hash_seed
!! Version: experimental
!!
!! ([Specification](file:///home/jvandenp/stdlib/API-doc/page/specs/stdlib_hash_procedures.html#new_water_hash_seed-returns-a-valid-input-seed-for-water_hash))
        module subroutine new_water_hash_seed( seed )
            integer(int64), intent(inout) :: seed
        end subroutine new_water_hash_seed

    end interface new_water_hash_seed

    interface new_nmhash32_seed
!! Version: experimental
!!
!! ([Specification](../page/specs/stdlib_hash_procedures.html#new_nmhash32_seed-returns-a-valid-input-seed-for-nmhash32)

        module subroutine new_nmhash32_seed( seed )
            integer(int32), intent(inout) :: seed
        end subroutine new_nmhash32_seed

    end interface new_nmhash32_seed

    interface new_nmhash32x_seed
!! Version: experimental
!!
!! ([Specification](../page/specs/stdlib_hash_procedures.html#new_nmhash32x_seed-returns-a-valid-input-seed-for-nmhash32x))

        module subroutine new_nmhash32x_seed( seed )
            integer(int32), intent(inout) :: seed
        end subroutine new_nmhash32x_seed

    end interface new_nmhash32x_seed

contains

    elemental function fibonacci_hash( key, nbits ) result( sample )
!! Version: experimental
!!
!! Maps the 32 bit integer `key` to an unsigned integer value with only `nbits`
!! bits where `nbits` is less than 32
!! ([Specification](../page/specs/stdlib_hash_procedures.html#fibonacci_hash-maps-an-integer-to-a-smaller-number-of-bits))

        integer(int32), intent(in) :: key
        integer, intent(in)        :: nbits
        integer(int32)             :: sample

        sample = ishft( key*pow32_over_phi, -32 + nbits )

    end function fibonacci_hash

    elemental function universal_mult_hash( key, seed, nbits ) result( sample )
!! Version: experimental
!!
!! Uses the "random" odd 32 bit integer `seed` to map the 32 bit integer `key` to
!! an unsigned integer value with only `nbits` bits where `nbits` is less than 32
!! ([Specification](../page/specs/stdlib_hash_procedures.html#universal_mult_hash-maps-an-integer-to-a-smaller-number-of-bits))
        integer(int32), intent(in) :: key
        integer(int32), intent(in) :: seed
        integer, intent(in)        :: nbits
        integer(int32)             :: sample

        sample = ishft( key*seed, -32 + nbits )

    end function universal_mult_hash

    subroutine odd_random_integer( harvest )
!! Version: experimental
!!
!! Returns a 32 bit pseudo random integer, `harvest`, distributed uniformly over
!! the odd integers of the `int32` kind.
!! ([Specification](../page/specs/stdlib_hash_procedures.html#odd_random_integer-returns-an-odd-integer))
        integer(int32), intent(out) :: harvest
        real(dp) :: sample

        call random_number( sample )
        harvest = int( floor( sample * 2_int64**32, int64 ) - 2_int64**31, &
            int32 )
        harvest = ishft( harvest, 1 ) + 1_int32

    end subroutine odd_random_integer

end module stdlib_hash_32bit