From a3abf40bc224356c0ccfc65284bf649c98d0f62c Mon Sep 17 00:00:00 2001 From: Simon Cruanes Date: Mon, 22 Aug 2022 17:48:21 +0000 Subject: [PATCH] add `CCInt64.{hash,hash_to_int64}` --- src/core/CCInt64.ml | 18 +++++++++++++++++- src/core/CCInt64.mli | 9 +++++++-- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/src/core/CCInt64.ml b/src/core/CCInt64.ml index d8802983..e94cccc2 100644 --- a/src/core/CCInt64.ml +++ b/src/core/CCInt64.ml @@ -5,9 +5,25 @@ include Int64 let min : t -> t -> t = Stdlib.min let max : t -> t -> t = Stdlib.max -let hash x = Stdlib.abs (to_int x) let sign i = compare i zero +(* use FNV: + https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function *) +let hash_to_int64 (n : t) = + let offset_basis = 0xcbf29ce484222325L in + let prime = 0x100000001b3L in + + let h = ref offset_basis in + for k = 0 to 7 do + h := mul !h prime; + (* h := h xor (k-th bit of n) *) + h := logxor !h (logand (shift_left n (k * 8)) 0xffL) + done; + logand !h max_int + +let[@inline] hash (n : t) : int = + to_int (hash_to_int64 n) land CCShims_.Stdlib.max_int + (* see {!CCInt.popcount} for more details *) let[@inline] popcount (b : t) : int = let m1 = 0x5555555555555555L in diff --git a/src/core/CCInt64.mli b/src/core/CCInt64.mli index 56dbecae..5fdd6770 100644 --- a/src/core/CCInt64.mli +++ b/src/core/CCInt64.mli @@ -27,8 +27,13 @@ val max : t -> t -> t @since 3.0 *) val hash : t -> int -(** [hash x] computes the hash of [x]. - Like {!Stdlib.abs (to_int x)}. *) +(** [hash x] computes the hash of [x], a non-negative integer. + Uses FNV since NEXT_RELEASE *) + +val hash_to_int64 : t -> t +(** Like {!hash} but does not truncate. + Uses FNV. + @since NEXT_RELEASE *) val popcount : t -> int (** Number of bits set to 1.