use crate::ir::{BufferDecl, DataType, Expr, Node, Program};
use crate::ops::AlgebraicLaw;
use crate::ops::{OpSpec, BYTES_TO_U32_OUTPUTS};
pub const EMPTY_HASH: u32 = FNV_OFFSET_BASIS;
#[must_use]
pub fn fnv1a_program() -> Program {
Program::new(
vec![
BufferDecl::read("input", 0, DataType::Bytes),
BufferDecl::output("out", 1, DataType::U32),
],
[1, 1, 1],
vec![
Node::let_bind("hash", Expr::u32(FNV_OFFSET_BASIS)),
Node::loop_for(
"pos",
Expr::u32(0),
Expr::buf_len("input"),
vec![Node::assign(
"hash",
Expr::mul(
Expr::bitxor(Expr::var("hash"), input_byte(Expr::var("pos"))),
Expr::u32(FNV_PRIME),
),
)],
),
Node::if_then(
Expr::lt(Expr::u32(0), Expr::buf_len("out")),
vec![Node::store("out", Expr::u32(0), Expr::var("hash"))],
),
],
)
}
pub const FNV_OFFSET_BASIS: u32 = 2_166_136_261;
pub const FNV_PRIME: u32 = 16_777_619;
pub fn input_byte(index: Expr) -> Expr {
Expr::bitand(Expr::load("input", index), Expr::u32(0xff))
}
pub const INPUTS: &[DataType] = &[DataType::Bytes];
pub const LAWS: &[AlgebraicLaw] = &[AlgebraicLaw::Bounded {
lo: 0,
hi: u32::MAX,
}];
#[must_use]
pub const fn single_byte_hash(byte: u32) -> u32 {
(FNV_OFFSET_BASIS ^ (byte & 0xff)).wrapping_mul(FNV_PRIME)
}
pub const SPEC: OpSpec = OpSpec::composition(
"hash.fnv1a32",
INPUTS,
BYTES_TO_U32_OUTPUTS,
LAWS,
fnv1a_program,
);