mirror of
https://github.com/c-cube/ocaml-containers.git
synced 2026-03-07 21:27:55 -05:00
The implementation uses multiply-then-XOR order, which is FNV-1. FNV-1a would XOR first, then multiply. The constants (offset_basis and prime) are the same for both variants; only the operation order differs. Fix comments in cc_stubs.c, CCInt.ml, and CCHash.ml. No behavioral change — just correcting the documentation.
53 lines
1.7 KiB
C
53 lines
1.7 KiB
C
#include <caml/mlvalues.h>
|
|
#include <stdint.h>
|
|
|
|
/* FNV-1 hash for a 64-bit integer.
|
|
https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function
|
|
|
|
FNV-1 order: multiply then XOR (as opposed to FNV-1a which XORs first).
|
|
Uses the standard 64-bit FNV parameters:
|
|
offset_basis = 0xcbf29ce484222325
|
|
prime = 0x00000100000001b3
|
|
|
|
Core routine: operates on all 8 bytes of an int64_t. */
|
|
|
|
static inline int64_t cc_fnv_hash_int64(int64_t n) {
|
|
uint64_t un = (uint64_t)n;
|
|
uint64_t h = UINT64_C(0xcbf29ce484222325);
|
|
const uint64_t prime = UINT64_C(0x100000001b3);
|
|
for (int k = 0; k < 8; k++) {
|
|
h *= prime;
|
|
h ^= (un >> (k * 8)) & 0xff;
|
|
}
|
|
return (int64_t)h;
|
|
}
|
|
|
|
/* --- CCInt.hash entry points (int -> int) --- */
|
|
|
|
/* Mask to the OCaml int range (63 bits on 64-bit, 31 on 32-bit)
|
|
before hashing, so negative OCaml ints hash the same as
|
|
the unsigned representation seen by OCaml's [lsr]. */
|
|
#define OCAML_INT_MASK ((UINT64_C(1) << (8 * sizeof(value) - 1)) - 1)
|
|
|
|
/* native: untagged int in, untagged int out */
|
|
CAMLprim intnat caml_cc_hash_int(intnat n) {
|
|
int64_t projected = (int64_t)((uint64_t)n & OCAML_INT_MASK);
|
|
return (intnat)((uint64_t)cc_fnv_hash_int64(projected) & Max_long);
|
|
}
|
|
|
|
/* bytecode: boxed value in, boxed value out */
|
|
CAMLprim value caml_cc_hash_int_byte(value v_n) {
|
|
return Val_long(caml_cc_hash_int(Long_val(v_n)));
|
|
}
|
|
|
|
/* --- int64 hash entry points (int64 -> int) --- */
|
|
|
|
/* native: unboxed int64 in, untagged int out */
|
|
CAMLprim intnat caml_cc_hash_int64(int64_t n) {
|
|
return (intnat)((uint64_t)cc_fnv_hash_int64(n) & Max_long);
|
|
}
|
|
|
|
/* bytecode: boxed int64 value in, boxed value out */
|
|
CAMLprim value caml_cc_hash_int64_byte(value v_n) {
|
|
return Val_long(caml_cc_hash_int64(Int64_val(v_n)));
|
|
}
|