diff --git a/Cargo.lock b/Cargo.lock index bcfa1b29..4029cdde 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -449,6 +449,7 @@ dependencies = [ "codspeed-criterion-compat", "egraph-serialize", "env_logger", + "foldhash", "generic_symbolic_expressions", "getrandom", "glob", @@ -543,6 +544,12 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" +[[package]] +name = "foldhash" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f81ec6369c545a7d40e4589b5597581fa1c441fe1cce96dd1de43159910a36a2" + [[package]] name = "generic-array" version = "0.14.7" diff --git a/Cargo.toml b/Cargo.toml index c1664496..4ed63d39 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -38,6 +38,7 @@ num-integer = "0.1.45" num-rational = "0.4.1" num-traits = "0.2.15" smallvec = "1.11" +foldhash = "0.1.3" generic_symbolic_expressions = "5.0.4" diff --git a/src/function/table.rs b/src/function/table.rs index 300cd851..178f03a5 100644 --- a/src/function/table.rs +++ b/src/function/table.rs @@ -35,7 +35,7 @@ use std::{ use hashbrown::raw::RawTable; use super::binary_search::binary_search_table_by_key; -use crate::{util::BuildHasher as BH, TupleOutput, Value, ValueVec}; +use crate::{util::BuildFxHasher as BH, TupleOutput, Value, ValueVec}; type Offset = usize; diff --git a/src/util.rs b/src/util.rs index 47191c23..db74b186 100644 --- a/src/util.rs +++ b/src/util.rs @@ -1,18 +1,32 @@ #![allow(unused)] -use std::fmt::Display; +use std::{fmt::Display, hash::BuildHasher}; use crate::core::SpecializedPrimitive; #[allow(unused_imports)] use crate::*; -pub(crate) type BuildHasher = std::hash::BuildHasherDefault; +pub(crate) type BuildFxHasher = std::hash::BuildHasherDefault; -pub(crate) type HashMap = hashbrown::HashMap; -pub(crate) type HashSet = hashbrown::HashSet; +#[derive(Debug, Clone, Default)] +pub struct DeterministicHashBuilder; -pub type IndexMap = indexmap::IndexMap; -pub type IndexSet = indexmap::IndexSet; +impl BuildHasher for DeterministicHashBuilder { + type Hasher = foldhash::fast::FoldHasher; + fn build_hasher(&self) -> Self::Hasher { + foldhash::fast::FixedState::with_seed(0).build_hasher() + } +} + +/// Use deterministic hasher to make egglog deterministic +/// when rule application order matters. +pub(crate) type HashMap = hashbrown::HashMap; +pub(crate) type HashSet = hashbrown::HashSet; + +/// Index maps don't need deterministic hashing, +/// since iteration order is guaranteed to be insertion order. +pub type IndexMap = indexmap::IndexMap; +pub type IndexSet = indexmap::IndexSet; pub(crate) fn concat_vecs(to: &mut Vec, mut from: Vec) { if to.len() < from.len() {