diff --git a/vlib/hash/fnv1a/fnv1a.v b/vlib/hash/fnv1a/fnv1a.v index 275c8a2382..73d0899ac6 100644 --- a/vlib/hash/fnv1a/fnv1a.v +++ b/vlib/hash/fnv1a/fnv1a.v @@ -1,5 +1,8 @@ module fnv1a +// This module implements a FNV-1a hash. +// (see https://en.wikipedia.org/wiki/Fowler–Noll–Vo_hash_function) + const ( fnv64_prime = u64(1099511628211) fnv64_offset_basis = u64(14695981039346656037) @@ -7,7 +10,8 @@ const ( fnv32_prime = u32(16777619) ) -[inline] +// sum32 returns a fnv1a hash of the string, described by `data` +[direct_array_access; inline] pub fn sum32_string(data string) u32 { mut hash := fnv1a.fnv32_offset_basis for i in 0 .. data.len { @@ -16,7 +20,9 @@ pub fn sum32_string(data string) u32 { return hash } -[inline] +// sum32 returns a fnv1a hash of the memory block, described by the dynamic +// byte array `data`. +[direct_array_access; inline] pub fn sum32(data []byte) u32 { mut hash := fnv1a.fnv32_offset_basis for i in 0 .. data.len { @@ -25,7 +31,19 @@ pub fn sum32(data []byte) u32 { return hash } -[inline] +// sum32_bytes returns a fnv1a hash of `data_len` bytes starting at +// the address in the given &byte pointer `data`. +[direct_array_access; inline; unsafe] +pub fn sum32_bytes(data &byte, data_len int) u32 { + mut hash := fnv1a.fnv32_offset_basis + for i in 0 .. data_len { + hash = unsafe { (hash ^ u32(data[i])) * fnv1a.fnv32_prime } + } + return hash +} + +// sum64 returns a fnv1a hash of the string, described by `data` +[direct_array_access; inline] pub fn sum64_string(data string) u64 { mut hash := fnv1a.fnv64_offset_basis for i in 0 .. data.len { @@ -34,7 +52,9 @@ pub fn sum64_string(data string) u64 { return hash } -[inline] +// sum64 returns a fnv1a hash of the memory block, described by the dynamic +// byte array `data`. +[direct_array_access; inline] pub fn sum64(data []byte) u64 { mut hash := fnv1a.fnv64_offset_basis for i in 0 .. data.len { @@ -42,3 +62,14 @@ pub fn sum64(data []byte) u64 { } return hash } + +// sum64_bytes returns a fnv1a hash of `data_len` bytes starting at +// the address in the given &byte pointer `data`. +[direct_array_access; inline; unsafe] +pub fn sum64_bytes(data &byte, data_len int) u64 { + mut hash := fnv1a.fnv64_offset_basis + for i in 0 .. data_len { + hash = unsafe { (hash ^ u64(data[i])) * fnv1a.fnv64_prime } + } + return hash +} diff --git a/vlib/hash/fnv1a/fnv1a_test.v b/vlib/hash/fnv1a/fnv1a_test.v index f775ab1b5a..9a979b6737 100644 --- a/vlib/hash/fnv1a/fnv1a_test.v +++ b/vlib/hash/fnv1a/fnv1a_test.v @@ -1,12 +1,29 @@ import hash.fnv1a -fn test_fnv1a() { +fn test_fnv1a_sum32() { + $if windows { + return + } + ahash := '10bc2abf' + a := 'apple' + b := fnv1a.sum32_string(a) + c := fnv1a.sum32(a.bytes()) + d := unsafe { fnv1a.sum32_bytes(a.str, a.len) } + assert b.hex() == ahash + assert c.hex() == ahash + assert d.hex() == ahash +} + +fn test_fnv1a_sum64() { $if windows { return } a := 'apple' + ahash := 'f74a62a458befdbf' b := fnv1a.sum64_string(a) c := fnv1a.sum64(a.bytes()) - assert b.hex() == 'f74a62a458befdbf' - assert c.hex() == 'f74a62a458befdbf' + d := unsafe { fnv1a.sum64_bytes(a.str, a.len) } + assert b.hex() == ahash + assert c.hex() == ahash + assert d.hex() == ahash }