diff --git a/sources/hash.F90 b/sources/hash.F90 index b3c63e1..5b11be6 100644 --- a/sources/hash.F90 +++ b/sources/hash.F90 @@ -55,7 +55,7 @@ module hash ! declare public subroutines ! - public :: xxh64_integer, xxh64_long, xxh64_double, xxh64_complex + public :: xxh64, xxh64_integer, xxh64_long, xxh64_double, xxh64_complex !- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ! @@ -70,6 +70,113 @@ module hash ! !=============================================================================== ! +! function XXH64: +! -------------- +! +! Function calculates XXH64 hash for a given sequence of bytes. +! +! Arguments: +! +! input - the input sequence of bytes; +! +!=============================================================================== +! + integer(kind=8) function xxh64(input) result(hash) + + implicit none + +! subroutine arguments +! + integer(kind=1), dimension(:), intent(in) :: input + +! local variables +! + integer(kind=8) :: length, remaining, offset + +! local arrays +! + integer(kind=8), dimension(4) :: lane, chunk + +!------------------------------------------------------------------------------- +! + length = size(input) + hash = 0_8 + offset = 1_8 + remaining = length + + if (remaining >= 32_8) then + lane(1) = seed + prime1 + prime2 + lane(2) = seed + prime2 + lane(3) = seed + 0_8 + lane(4) = seed - prime1 + + do while (remaining >= 32_8) + chunk(1:4) = transfer(input(offset:offset+31), 1_8, 4) + + lane(1) = xxh64_round(lane(1), chunk(1)) + lane(2) = xxh64_round(lane(2), chunk(2)) + lane(3) = xxh64_round(lane(3), chunk(3)) + lane(4) = xxh64_round(lane(4), chunk(4)) + + offset = offset + 32_8 + remaining = remaining - 32_8 + end do + + hash = xxh64_rotl(lane(1), 1) + xxh64_rotl(lane(2), 7) + & + xxh64_rotl(lane(3), 12) + xxh64_rotl(lane(4), 18) + + hash = xxh64_merge(hash, lane(1)) + hash = xxh64_merge(hash, lane(2)) + hash = xxh64_merge(hash, lane(3)) + hash = xxh64_merge(hash, lane(4)) + + else + hash = seed + prime5 + end if + + hash = hash + length + + do while (remaining >= 8_8) + chunk(1) = transfer(input(offset:offset+7), 1_8) + hash = ieor(hash, xxh64_round(0_8, chunk(1))) + hash = xxh64_rotl(hash, 27) + hash = hash * prime1 + prime4 + + offset = offset + 8_8 + remaining = remaining - 8_8 + end do + + if (remaining >= 4) then + chunk(1) = transfer((/ input(offset:offset+3), 0_1, 0_1, 0_1, 0_1 /), 1_8) + hash = ieor(hash, chunk(1) * prime1) + hash = xxh64_rotl(hash, 23) + hash = hash * prime2 + prime3 + + offset = offset + 4_8 + remaining = remaining - 4_8 + end if + + do while (remaining > 0_8) + chunk(1) = transfer((/ input(offset), 0_1, 0_1, 0_1, & + 0_1, 0_1, 0_1, 0_1 /), 1_8) + hash = ieor(hash, chunk(1) * prime5) + hash = xxh64_rotl(hash, 11) + hash = hash * prime1 + + offset = offset + 1_8 + remaining = remaining - 1_8 + end do + + hash = xxh64_aval(hash) + + return + +!------------------------------------------------------------------------------- +! + end function xxh64 +! +!=============================================================================== +! ! function XXH64_INTEGER: ! ---------------------- !