use crate::util::bit;
use crate::util::slab::{Generation, INITIAL_PAGE_SIZE, MAX_PAGES, MAX_THREADS};
use std::usize;
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub(crate) struct Address(usize);
const PAGE_INDEX_SHIFT: u32 = INITIAL_PAGE_SIZE.trailing_zeros() + 1;
const SLOT: bit::Pack = bit::Pack::least_significant(MAX_PAGES as u32 + PAGE_INDEX_SHIFT);
const THREAD: bit::Pack = SLOT.then(MAX_THREADS.trailing_zeros() + 1);
const GENERATION: bit::Pack = THREAD
.then(bit::pointer_width().wrapping_sub(RESERVED.width() + THREAD.width() + SLOT.width()));
const RESERVED: bit::Pack = bit::Pack::most_significant(5);
impl Address {
pub(crate) const NULL: usize = usize::MAX >> 1;
pub(super) const GENERATION_WIDTH: u32 = GENERATION.width();
pub(super) fn new(shard_index: usize, generation: Generation) -> Address {
let mut repr = 0;
repr = SLOT.pack(shard_index, repr);
repr = GENERATION.pack(generation.to_usize(), repr);
Address(repr)
}
pub(crate) fn from_usize(src: usize) -> Address {
assert_ne!(src, Self::NULL);
Address(src)
}
pub(crate) fn to_usize(self) -> usize {
self.0
}
pub(crate) fn generation(self) -> Generation {
Generation::new(GENERATION.unpack(self.0))
}
pub(super) fn page(self) -> usize {
let slot_shifted = (self.slot() + INITIAL_PAGE_SIZE) >> PAGE_INDEX_SHIFT;
(bit::pointer_width() - slot_shifted.leading_zeros()) as usize
}
pub(super) fn slot(self) -> usize {
SLOT.unpack(self.0)
}
}
#[cfg(test)]
cfg_not_loom! {
use proptest::proptest;
#[test]
fn test_pack_format() {
assert_eq!(5, RESERVED.width());
assert_eq!(0b11111, RESERVED.max_value());
}
proptest! {
#[test]
fn address_roundtrips(
slot in 0usize..SLOT.max_value(),
generation in 0usize..Generation::MAX,
) {
let address = Address::new(slot, Generation::new(generation));
let address = Address::from_usize(address.to_usize());
assert_eq!(address.slot(), slot);
assert_eq!(address.generation().to_usize(), generation);
}
}
}