use std::cell::UnsafeCell;
use crate::solver_id::{IdMap, IdSet, SolverId};
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub(crate) enum SolvableIdOrRoot<S> {
Root,
Solvable(S),
}
impl<S> SolvableIdOrRoot<S> {
pub(crate) const fn root() -> Self {
Self::Root
}
pub(crate) fn solvable(self) -> Option<S> {
match self {
Self::Root => None,
Self::Solvable(solvable) => Some(solvable),
}
}
}
impl<S> From<S> for SolvableIdOrRoot<S> {
fn from(value: S) -> Self {
Self::Solvable(value)
}
}
pub(crate) struct WithRootSet<S: SolverId> {
root: bool,
solvables: S::Set,
}
impl<S: SolverId> Default for WithRootSet<S> {
fn default() -> Self {
Self {
root: false,
solvables: Default::default(),
}
}
}
impl<S: SolverId> IdSet<SolvableIdOrRoot<S>> for WithRootSet<S> {
fn contains(&self, key: SolvableIdOrRoot<S>) -> bool {
match key {
SolvableIdOrRoot::Root => self.root,
SolvableIdOrRoot::Solvable(solvable) => self.solvables.contains(solvable),
}
}
fn insert(&mut self, key: SolvableIdOrRoot<S>) -> bool {
match key {
SolvableIdOrRoot::Root => {
let was_present = self.root;
self.root = true;
!was_present
}
SolvableIdOrRoot::Solvable(solvable) => self.solvables.insert(solvable),
}
}
}
pub(crate) struct Frozen<T>(UnsafeCell<T>);
impl<T: Default> Default for Frozen<T> {
fn default() -> Self {
Self(UnsafeCell::new(T::default()))
}
}
impl<T> Frozen<T> {
pub(crate) fn get<K, V: Copy + Default>(&self, key: K) -> V
where
T: IdMap<K, V>,
{
unsafe { (*self.0.get()).get(key) }
}
pub(crate) fn set<K, V: Copy + Default>(&self, key: K, value: V)
where
T: IdMap<K, V>,
{
unsafe { (*self.0.get()).set(key, value) }
}
}
#[cfg(test)]
pub mod tests {
use super::*;
use std::num::NonZeroU32;
#[test]
fn nich_optimization_applies() {
assert!(
std::mem::size_of::<SolvableIdOrRoot<NonZeroU32>>()
== std::mem::size_of::<NonZeroU32>()
);
}
}