| Safe Haskell | None |
|---|---|
| Language | Haskell2010 |
DataFrame.Internal.Hash
Description
A poor-man's hash used by Grouping to bucket rows
without depending on the hashable package.
Each value is folded into an Int accumulator with an FxHash-style step
(rotate, xor, multiply). It is intentionally small and not cryptographically
strong — it only needs to spread group-key tuples well enough that
IntMap bucketing produces sensible groups.
Documentation
Sentinel mixed in for a null slot of a nullable column, so that a
Nothing does not hash to the same value as a present Just x that happens to
store the same underlying bits (notably Just 0). A fixed distinctive constant
(the 64-bit golden-ratio mix constant) keeps null hashing deterministic; a real
value equal to it collides only as rarely as any other hash collision.
mixInt :: Int -> Int -> Int Source #
Mix an Int into the accumulator.
An FxHash-style step (rotate the accumulator, xor the value, multiply by a large
odd constant). The rotate diffuses each value's bits across all positions before
the next is folded in, so small/adjacent integers — common as group keys — do
not produce the structured collisions that a plain (acc does
once several columns are combined. Grouping trusts hash equality, so this
robustness is what keeps distinct rows in distinct groups.xor x) * prime
mixDouble :: Int -> Double -> Int Source #
Mix a Double into the accumulator. Loses sub-millisecond precision
but matches the bucketing the old hashable-based code used.
mixText :: Int -> Text -> Int Source #
Mix a Text value into the accumulator over its raw UTF-8 bytes,
eight at a time. Reading a whole Word64 per step (rather than decoding and
mixing one codepoint at a time) cuts the multiply count ~8x on long keys while
staying collision-equivalent: UTF-8 is injective, so equal Texts mix to the
same value and distinct ones almost never collide. The trailing len
bytes are folded in individually.mod 8