use std::hash::{BuildHasher, Hash, Hasher};
use hashbrown::{HashMap, hash_map::RawEntryMut};
use rapidhash::quality::RandomState;
use serde::{Deserialize, Serialize};
mod basic;
mod convert;
mod iter;
mod ops;
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
#[cfg_attr(feature = "fast-binary", derive(bitcode::Encode, bitcode::Decode))]
#[repr(transparent)]
pub struct NodeId(u32);
impl NodeId {
pub const EMPTY: Self = Self(0);
pub const UNIVERSAL: Self = Self(1);
pub(crate) const MAX: Self = Self(u32::MAX);
pub(crate) fn new(idx: u32, neg: bool) -> Self {
Self((idx << 1) | (if neg { 1 } else { 0 }))
}
pub(crate) fn raw(&self) -> u32 {
self.0
}
pub(crate) fn idx(&self) -> usize {
(self.0 >> 1) as usize
}
pub(crate) fn is_neg(&self) -> bool {
(self.0 & 1) == 1
}
pub(crate) fn not(&self) -> Self {
Self(self.0 ^ 1)
}
}
#[derive(Hash, PartialEq, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "fast-binary", derive(bitcode::Encode, bitcode::Decode))]
pub enum Node<T> {
Empty,
Set(T),
Union(Vec<NodeId>),
Intersection(Vec<NodeId>),
}
#[derive(Serialize, Deserialize)]
#[serde(from = "ExpressionShadow<T>")]
#[serde(bound = "T: Serialize + for<'a> Deserialize<'a> + Hash + PartialEq")]
#[cfg_attr(feature = "fast-binary", derive(bitcode::Encode))]
pub struct Expression<T> {
pub(crate) nodes: Vec<Node<T>>,
pub(crate) roots: Vec<NodeId>,
#[serde(skip, default = "default_cache")]
#[cfg_attr(feature = "fast-binary", bitcode(skip))]
pub(crate) cache: HashMap<NodeId, (), RandomState>,
pub(crate) uuid: u128,
pub(crate) generation: u64,
}
impl<T> Default for Expression<T> {
fn default() -> Self {
Self {
nodes: vec![Node::Empty], roots: Vec::new(),
cache: default_cache(),
uuid: generate_uuid(),
generation: 0,
}
}
}
impl<T: Clone + Hash + PartialEq> Clone for Expression<T> {
fn clone(&self) -> Self {
let nodes = self.nodes.clone();
let cache = build_cache(&nodes);
Self {
nodes,
roots: self.roots.clone(),
cache,
uuid: generate_uuid(),
generation: self.generation,
}
}
}
fn default_cache() -> HashMap<NodeId, (), RandomState> {
HashMap::with_hasher(RandomState::new())
}
fn generate_uuid() -> u128 {
let low = RandomState::new();
let mut hash_low = low.build_hasher();
hash_low.write_usize(&low as *const _ as usize);
let low = hash_low.finish() as u128;
let high = RandomState::new();
let mut hash_high = high.build_hasher();
hash_high.write_usize(&high as *const _ as usize);
let high = hash_high.finish() as u128;
(high << 64) | low
}
#[derive(Deserialize)]
#[cfg_attr(feature = "fast-binary", derive(bitcode::Decode))]
struct ExpressionShadow<T> {
nodes: Vec<Node<T>>,
roots: Vec<NodeId>,
uuid: u128,
generation: u64,
}
impl<T: Hash + PartialEq> From<ExpressionShadow<T>> for Expression<T> {
fn from(value: ExpressionShadow<T>) -> Self {
let cache = build_cache(&value.nodes);
Self {
nodes: value.nodes,
roots: value.roots,
cache,
uuid: value.uuid,
generation: value.generation,
}
}
}
fn build_cache<T: Hash + PartialEq>(nodes: &[Node<T>]) -> HashMap<NodeId, (), RandomState> {
let mut cache = HashMap::with_hasher(RandomState::new());
let hasher_builder = *cache.hasher();
for (i, node) in nodes.iter().enumerate() {
if let Node::Empty = node {
continue;
}
let hash = hasher_builder.hash_one(node);
let id = NodeId::new(i as u32, false);
let entry = cache.raw_entry_mut().from_hash(hash, |_| false);
if let RawEntryMut::Vacant(entry) = entry {
entry.insert_with_hasher(hash, id, (), |&id| {
hasher_builder.hash_one(&nodes[id.idx()])
});
}
}
cache
}