feat(helpers): add deterministic stringHash for stable daily selection
This commit is contained in:
parent
ac76bce5cd
commit
b0bc41291e
|
|
@ -0,0 +1,21 @@
|
|||
import {describe, it, expect} from 'vitest'
|
||||
import {stringHash} from './stringHash'
|
||||
|
||||
describe('stringHash', () => {
|
||||
it('returns a non-negative integer', () => {
|
||||
expect(stringHash('hello')).toBeGreaterThanOrEqual(0)
|
||||
expect(Number.isInteger(stringHash('hello'))).toBe(true)
|
||||
})
|
||||
|
||||
it('is deterministic for the same input', () => {
|
||||
expect(stringHash('foo')).toBe(stringHash('foo'))
|
||||
})
|
||||
|
||||
it('returns different values for different inputs', () => {
|
||||
expect(stringHash('foo')).not.toBe(stringHash('bar'))
|
||||
})
|
||||
|
||||
it('handles the empty string', () => {
|
||||
expect(stringHash('')).toBeGreaterThanOrEqual(0)
|
||||
})
|
||||
})
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
// Deterministic non-cryptographic string hash (djb2 variant).
|
||||
// Used for stable pseudo-random selection keyed on date + user + bucket.
|
||||
export function stringHash(input: string): number {
|
||||
let hash = 5381
|
||||
for (let i = 0; i < input.length; i++) {
|
||||
// hash * 33 + char, kept in 32-bit range via `| 0`.
|
||||
hash = ((hash << 5) + hash + input.charCodeAt(i)) | 0
|
||||
}
|
||||
// Ensure non-negative.
|
||||
return hash >>> 0
|
||||
}
|
||||
Loading…
Reference in New Issue