ocaml-containers/src/core/cc_stubs.c
Simon Cruanes d493f6696b Fix FNV variant in comments: this is FNV-1, not FNV-1a
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.
2026-02-16 12:48:12 +00:00

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)));
}