const GENERATION_MASK: u64 = u32::MAX as u64;
const RECOVERY_SHIFT: u32 = 32;
const RECOVERY_MASK: u64 = ((1_u64 << 28) - 1) << RECOVERY_SHIFT;
const TRANSITION_SHIFT: u32 = 60;
const TRANSITION_MASK: u64 = 0b111 << TRANSITION_SHIFT;
const HAD_DELETE_MASK: u64 = 1_u64 << 63;
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
#[repr(u8)]
pub enum EpochTransition {
Initial,
Growth,
TombstoneCleanup,
ExplicitResize,
Clear,
PlacementRecovery,
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct EpochSnapshot {
pub generation: u64,
pub distinct_insertions: usize,
pub had_delete: bool,
pub placement_recoveries: u64,
pub transition: EpochTransition,
}
#[derive(Clone, Copy, Debug)]
pub(crate) struct EpochState {
deletions: usize,
lifecycle: u64,
}
impl EpochState {
pub(crate) const fn initial() -> Self {
Self {
deletions: 0,
lifecycle: 0,
}
}
#[inline]
pub(crate) fn note_delete(&mut self) {
self.deletions = self.deletions.saturating_add(1);
self.lifecycle |= HAD_DELETE_MASK;
}
pub(crate) fn start(&mut self, transition: EpochTransition, _survivor_insertions: usize) {
let generation = self.generation().saturating_add(1);
self.lifecycle = (self.lifecycle & RECOVERY_MASK)
| u64::from(generation)
| (transition_bits(transition) << TRANSITION_SHIFT);
self.deletions = 0;
}
pub(crate) fn start_placement_recovery(&mut self, survivor_insertions: usize) {
self.start_with_placement_recovery(EpochTransition::PlacementRecovery, survivor_insertions);
}
pub(crate) fn start_with_placement_recovery(
&mut self,
transition: EpochTransition,
survivor_insertions: usize,
) {
let recoveries = self.placement_recoveries().saturating_add(1);
self.lifecycle =
(self.lifecycle & !RECOVERY_MASK) | (u64::from(recoveries) << RECOVERY_SHIFT);
self.start(transition, survivor_insertions);
}
pub(crate) const fn snapshot(self, live_entries: usize) -> EpochSnapshot {
EpochSnapshot {
generation: self.generation() as u64,
distinct_insertions: live_entries.saturating_add(self.deletions),
had_delete: self.lifecycle & HAD_DELETE_MASK != 0,
placement_recoveries: self.placement_recoveries() as u64,
transition: transition_from_bits(
(self.lifecycle & TRANSITION_MASK) >> TRANSITION_SHIFT,
),
}
}
const fn generation(self) -> u32 {
(self.lifecycle & GENERATION_MASK) as u32
}
const fn placement_recoveries(self) -> u32 {
((self.lifecycle & RECOVERY_MASK) >> RECOVERY_SHIFT) as u32
}
}
const fn transition_bits(transition: EpochTransition) -> u64 {
match transition {
EpochTransition::Initial => 0,
EpochTransition::Growth => 1,
EpochTransition::TombstoneCleanup => 2,
EpochTransition::ExplicitResize => 3,
EpochTransition::Clear => 4,
EpochTransition::PlacementRecovery => 5,
}
}
const fn transition_from_bits(bits: u64) -> EpochTransition {
match bits {
1 => EpochTransition::Growth,
2 => EpochTransition::TombstoneCleanup,
3 => EpochTransition::ExplicitResize,
4 => EpochTransition::Clear,
5 => EpochTransition::PlacementRecovery,
_ => EpochTransition::Initial,
}
}