pub const MAX_WIDTH: usize = 15;
const SIZE_MASK: u64 = 0xF;
use crate::{leaf_trait::TreePermutation, suffix::PermutationProvider};
struct PermuterUtils;
impl PermuterUtils {
const fn compute_initial_value<const WIDTH: usize>() -> u64 {
let mut value: u64 = 0;
let mut i: usize = 0;
while i < WIDTH {
let slot: u64 = (WIDTH - 1 - i) as u64;
value |= slot << ((i * 4) + 4);
i += 1;
}
value
}
const fn compute_sorted_value<const WIDTH: usize>() -> u64 {
let mut value: u64 = 0;
let mut i: usize = 0;
while i < WIDTH {
value |= (i as u64) << ((i * 4) + 4);
i += 1;
}
value
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct Permuter<const WIDTH: usize = 15> {
value: u64,
}
impl<const WIDTH: usize> Permuter<WIDTH> {
const WIDTH_CHECK: () = {
assert!(WIDTH > 0, "WIDTH must be at least 1");
assert!(
WIDTH <= MAX_WIDTH,
"WIDTH must be at most 15 (u64 encoding limit)"
);
};
pub const INITIAL: u64 = PermuterUtils::compute_initial_value::<WIDTH>();
const SORTED: u64 = PermuterUtils::compute_sorted_value::<WIDTH>();
const WIDTH_MASK: u64 = {
let width_shift: usize = (WIDTH + 1) * 4;
if width_shift >= 64 {
u64::MAX
} else {
(1u64 << width_shift) - 1
}
};
}
impl<const WIDTH: usize> Default for Permuter<WIDTH> {
#[inline(always)]
fn default() -> Self {
Self::empty()
}
}
pub type Permuter15 = Permuter<15>;
impl<const WIDTH: usize> Permuter<WIDTH> {
#[must_use]
#[inline(always)]
pub const fn empty() -> Self {
let _: () = Self::WIDTH_CHECK;
Self {
value: Self::INITIAL,
}
}
#[must_use]
pub fn make_sorted(n: usize) -> Self {
debug_assert!(n <= WIDTH, "make_sorted: n ({n}) > WIDTH ({WIDTH})");
if n == WIDTH {
return Self {
value: Self::SORTED | (WIDTH as u64),
};
}
let sorted: u64 = Self::SORTED;
let mut value: u64 = n as u64;
let sorted_mask: u64 = ((1u64 << (n * 4)) - 1) << 4;
value |= sorted & sorted_mask;
let mut pos: usize = n;
while pos < WIDTH {
let slot: u64 = (WIDTH - 1 - (pos - n)) as u64;
value |= slot << ((pos * 4) + 4);
pos += 1;
}
Self { value }
}
#[must_use]
#[inline(always)]
pub const fn size(&self) -> usize {
(self.value & SIZE_MASK) as usize
}
#[must_use]
#[inline(always)]
pub const fn get(&self, i: usize) -> usize {
debug_assert!(i < WIDTH, "get: index out of bounds");
((self.value >> ((i * 4) + 4)) & 0xF) as usize
}
#[must_use]
#[inline(always)]
pub const fn back(&self) -> usize {
self.get(WIDTH - 1)
}
#[must_use]
#[inline(always)]
pub const fn back_at_offset(&self, offset: usize) -> usize {
debug_assert!(
self.size() + offset < WIDTH,
"back_at_offset: offset exceeds free slots"
);
self.get(WIDTH - 1 - offset)
}
#[must_use]
#[inline(always)]
pub const fn value(&self) -> u64 {
self.value
}
#[must_use]
#[inline(always)]
pub const fn from_value(value: u64) -> Self {
Self { value }
}
#[inline(always)]
pub fn set_size(&mut self, n: usize) {
debug_assert!(n <= WIDTH, "set_size: n ({n}) > WIDTH ({WIDTH})");
self.value = (self.value & !SIZE_MASK) | (n as u64);
}
#[inline(always)]
pub fn set(&mut self, i: usize, slot: usize) {
debug_assert!(i < WIDTH, "set: position {i} >= WIDTH {WIDTH}");
debug_assert!(slot < WIDTH, "set: slot {slot} >= WIDTH {WIDTH}");
let shift: usize = (i + 1) * 4;
let mask: u64 = 0xFu64 << shift;
self.value = (self.value & !mask) | ((slot as u64) << shift);
}
#[inline(always)]
pub fn swap_free_slots(&mut self, pos_i: usize, pos_j: usize) {
let size: usize = self.size();
debug_assert!(
pos_i >= size,
"swap_free_slots: pos_i ({pos_i}) must be >= size ({size})"
);
debug_assert!(
pos_j >= size,
"swap_free_slots: pos_j ({pos_j}) must be >= size ({size})"
);
debug_assert!(pos_i < WIDTH, "swap_free_slots: pos_i out of range");
debug_assert!(pos_j < WIDTH, "swap_free_slots: pos_j out of range");
if pos_i == pos_j {
return; }
let i_shift: usize = (pos_i + 1) * 4;
let j_shift: usize = (pos_j + 1) * 4;
let diff: u64 = ((self.value >> i_shift) ^ (self.value >> j_shift)) & 0xF;
self.value ^= (diff << i_shift) | (diff << j_shift);
}
#[must_use]
#[inline(always)]
pub fn insert_from_back(&mut self, i: usize) -> usize {
debug_assert!(i <= self.size(), "insert_from_back: i > size");
debug_assert!(self.size() < WIDTH, "insert_from_back: permuter full");
let slot: usize = self.back();
let i_shift: usize = (i * 4) + 4;
let low_mask: u64 = (1u64 << i_shift) - 1;
self.value = ((self.value + 1) & low_mask)
| ((slot as u64) << i_shift)
| ((self.value << 4) & !(low_mask | (0xF << i_shift)));
#[cfg(debug_assertions)]
self.debug_assert_valid();
slot
}
#[must_use]
#[inline(always)]
pub fn insert_from_back_immutable(&self, i: usize) -> (Self, usize) {
debug_assert!(i <= self.size(), "insert_from_back_immutable: i > size");
debug_assert!(
self.size() < WIDTH,
"insert_from_back_immutable: permuter full"
);
let slot: usize = self.back();
let i_shift: usize = (i * 4) + 4;
let low_mask: u64 = (1u64 << i_shift) - 1;
let new_value: u64 = ((self.value + 1) & low_mask)
| ((slot as u64) << i_shift)
| ((self.value << 4) & !(low_mask | (0xF << i_shift)));
let new_perm = Self { value: new_value };
#[cfg(debug_assertions)]
new_perm.debug_assert_valid();
(new_perm, slot)
}
#[inline(always)]
pub fn remove_to_back(&mut self, i: usize) {
debug_assert!(i < self.size(), "remove_to_back: i >= size");
let i_shift: usize = (i + 1) * 4;
let mask: u64 = !((1u64 << i_shift) - 1);
let x: u64 = self.value & Self::WIDTH_MASK;
let shift_to_back: usize = (WIDTH - i - 1) * 4;
self.value = ((x - 1) & !mask) | ((x >> 4) & mask) | ((x & mask) << shift_to_back);
#[cfg(debug_assertions)]
self.debug_assert_valid();
}
#[inline(always)]
pub fn remove(&mut self, i: usize) {
let size: usize = self.size();
debug_assert!(i < size, "remove: i >= size");
if size == i + 1 {
self.value -= 1;
#[cfg(debug_assertions)]
self.debug_assert_valid();
return;
}
let rot_amount: usize = (size - i - 1) * 4;
let rot_mask: u64 = (((1u64 << rot_amount) << 4) - 1) << ((i + 1) * 4);
self.value = ((self.value - 1) & !rot_mask)
| (((self.value & rot_mask) >> 4) & rot_mask)
| (((self.value & rot_mask) << rot_amount) & rot_mask);
#[cfg(debug_assertions)]
self.debug_assert_valid();
}
#[inline(always)]
pub fn remove_slot(&mut self, slot: usize) {
let size = self.size();
for i in 0..size {
if self.get(i) == slot {
self.remove(i);
return;
}
}
debug_assert!(false, "remove_slot: slot {slot} not in permutation");
}
#[inline(always)]
pub fn exchange(&mut self, i: usize, j: usize) {
debug_assert!(i < WIDTH, "exchange: i >= WIDTH");
debug_assert!(j < WIDTH, "exchange: j >= WIDTH");
if i == j {
return;
}
let i_shift: usize = (i + 1) * 4;
let j_shift: usize = (j + 1) * 4;
let diff: u64 = ((self.value >> i_shift) ^ (self.value >> j_shift)) & 0xF;
self.value ^= (diff << i_shift) | (diff << j_shift);
#[cfg(debug_assertions)]
self.debug_assert_valid();
}
#[inline(always)]
pub fn rotate(&mut self, i: usize, j: usize) {
debug_assert!(i <= j, "rotate: i > j");
debug_assert!(j <= WIDTH, "rotate: j > WIDTH");
if i == j || i == WIDTH {
return;
}
let i_shift: usize = (i + 1) * 4;
let mask: u64 = (1u64 << i_shift) - 1;
let x: u64 = self.value & Self::WIDTH_MASK;
let rotate_amount: usize = (j - i) * 4;
let rotate_back: usize = (WIDTH - j) * 4;
self.value = (x & mask) | ((x >> rotate_amount) & !mask) | ((x & !mask) << rotate_back);
#[cfg(debug_assertions)]
self.debug_assert_valid();
}
#[cfg(debug_assertions)]
pub fn debug_assert_valid(&self) {
let size: usize = self.size();
assert!(size <= WIDTH, "invalid size: {size} > {WIDTH}");
let mut seen: u16 = 0;
for i in 0..WIDTH {
let slot: usize = self.get(i);
assert!(slot < WIDTH, "invalid slot index: {slot}");
let bit: u16 = 1u16 << slot;
assert!(seen & bit == 0, "duplicate slot index: {slot}");
seen |= bit;
}
assert_eq!(seen, (1u16 << WIDTH) - 1, "missing slot indices");
}
#[inline]
#[cfg(not(debug_assertions))]
pub const fn debug_assert_valid(&self) {}
}
impl<const WIDTH: usize> PermutationProvider for Permuter<WIDTH> {
#[inline(always)]
fn size(&self) -> usize {
self.size()
}
#[inline(always)]
fn get(&self, i: usize) -> usize {
self.get(i)
}
}
use std::sync::atomic::{AtomicU64, Ordering};
#[derive(Debug)]
#[repr(transparent)]
pub struct AtomicPermuter<const WIDTH: usize = 15> {
inner: AtomicU64,
}
impl<const WIDTH: usize> AtomicPermuter<WIDTH> {
#[must_use]
#[inline(always)]
pub const fn new() -> Self {
Self {
inner: AtomicU64::new(Permuter::<WIDTH>::INITIAL),
}
}
#[must_use]
#[inline(always)]
pub const fn from_permuter(perm: Permuter<WIDTH>) -> Self {
Self {
inner: AtomicU64::new(perm.value),
}
}
#[inline(always)]
pub fn load(&self, order: Ordering) -> Permuter<WIDTH> {
Permuter::from_value(self.inner.load(order))
}
#[inline(always)]
pub fn store(&self, val: Permuter<WIDTH>, order: Ordering) {
self.inner.store(val.value, order);
}
#[inline(always)]
pub fn compare_exchange(
&self,
expected: Permuter<WIDTH>,
new: Permuter<WIDTH>,
success: Ordering,
failure: Ordering,
) -> Result<Permuter<WIDTH>, Permuter<WIDTH>> {
self.inner
.compare_exchange(expected.value, new.value, success, failure)
.map(Permuter::from_value)
.map_err(Permuter::from_value)
}
#[inline(always)]
pub fn compare_exchange_weak(
&self,
expected: Permuter<WIDTH>,
new: Permuter<WIDTH>,
success: Ordering,
failure: Ordering,
) -> Result<Permuter<WIDTH>, Permuter<WIDTH>> {
self.inner
.compare_exchange_weak(expected.value, new.value, success, failure)
.map(Permuter::from_value)
.map_err(Permuter::from_value)
}
#[inline(always)]
pub fn load_raw(&self, order: Ordering) -> u64 {
self.inner.load(order)
}
#[inline(always)]
pub fn store_raw(&self, val: u64, order: Ordering) {
self.inner.store(val, order);
}
#[inline(always)]
pub fn compare_exchange_raw(
&self,
expected: u64,
new: u64,
success: Ordering,
failure: Ordering,
) -> Result<u64, u64> {
self.inner.compare_exchange(expected, new, success, failure)
}
}
impl<const WIDTH: usize> Default for AtomicPermuter<WIDTH> {
fn default() -> Self {
Self::new()
}
}
pub type AtomicPermuter15 = AtomicPermuter<15>;
impl<const WIDTH: usize> TreePermutation for Permuter<WIDTH> {
type Raw = u64;
const WIDTH: usize = WIDTH;
#[inline(always)]
fn empty() -> Self {
Self::empty()
}
#[inline(always)]
fn make_sorted(n: usize) -> Self {
Self::make_sorted(n)
}
#[inline(always)]
fn from_value(raw: u64) -> Self {
Self::from_value(raw)
}
#[inline(always)]
fn value(&self) -> u64 {
self.value
}
#[inline(always)]
fn size(&self) -> usize {
self.size()
}
#[inline(always)]
fn get(&self, i: usize) -> usize {
self.get(i)
}
#[inline(always)]
fn back(&self) -> usize {
self.back()
}
#[inline(always)]
fn back_at_offset(&self, offset: usize) -> usize {
self.back_at_offset(offset)
}
#[inline(always)]
fn insert_from_back(&mut self, i: usize) -> usize {
Self::insert_from_back(self, i)
}
#[inline(always)]
fn insert_from_back_immutable(&self, i: usize) -> (Self, usize) {
Self::insert_from_back_immutable(self, i)
}
#[inline(always)]
fn swap_free_slots(&mut self, pos_i: usize, pos_j: usize) {
Self::swap_free_slots(self, pos_i, pos_j);
}
#[inline(always)]
fn set_size(&mut self, n: usize) {
Self::set_size(self, n);
}
#[inline(always)]
fn remove(&mut self, i: usize) {
Self::remove(self, i);
}
}
#[cfg(test)]
mod unit_tests;