use alloc::vec::Vec;
#[derive(Debug)]
pub struct PackedArray<const BITS: u32> {
words: Vec<usize>,
len: usize,
}
impl<const BITS: u32> PackedArray<BITS> {
#[inline(always)]
fn items_per_word() -> usize {
(usize::BITS / BITS) as usize
}
#[inline(always)]
fn mask() -> usize {
(1usize << BITS) - 1
}
#[inline(always)]
fn word_of(index: usize) -> usize {
index / Self::items_per_word()
}
#[inline(always)]
fn offset_of(index: usize) -> usize {
(index % Self::items_per_word()) * BITS as usize
}
#[inline(always)]
fn words_for(len: usize) -> usize {
if len == 0 {
0
} else {
Self::word_of(len - 1) + 1
}
}
const WIDTH_OK: () = assert!(
BITS == 1 || BITS == 2 || BITS == 4,
"PackedArray BITS must be 1, 2 or 4"
);
#[inline]
pub fn new() -> Self {
let () = Self::WIDTH_OK;
Self {
words: Vec::new(),
len: 0,
}
}
#[inline]
pub fn with_capacity(capacity: usize) -> Self {
let () = Self::WIDTH_OK;
Self {
words: Vec::with_capacity(Self::words_for(capacity)),
len: 0,
}
}
#[inline]
pub fn len(&self) -> usize {
self.len
}
#[inline]
pub fn is_empty(&self) -> bool {
self.len == 0
}
#[inline]
pub fn capacity(&self) -> usize {
self.words.capacity().saturating_mul(Self::items_per_word())
}
pub fn reserve(&mut self, additional: usize) {
let target_words = Self::words_for(self.len.saturating_add(additional));
if target_words > self.words.capacity() {
self.words.reserve(target_words - self.words.len());
}
}
pub fn reserve_exact(&mut self, additional: usize) {
let target_words = Self::words_for(self.len.saturating_add(additional));
if target_words > self.words.capacity() {
self.words.reserve_exact(target_words - self.words.len());
}
}
pub fn shrink_to_fit(&mut self) {
self.words.truncate(Self::words_for(self.len));
self.words.shrink_to_fit();
}
#[inline]
pub unsafe fn set_len(&mut self, new_len: usize) {
debug_assert!(Self::words_for(new_len) <= self.words.len());
self.len = new_len;
}
#[inline]
pub fn get(&self, index: usize) -> usize {
assert!(
index < self.len,
"index out of bounds: the len is {} but the index is {}",
self.len,
index
);
unsafe { self.get_unchecked(index) }
}
#[inline]
pub fn set(&mut self, index: usize, value: usize) {
assert!(
index < self.len,
"index out of bounds: the len is {} but the index is {}",
self.len,
index
);
unsafe { self.set_unchecked(index, value) }
}
#[inline(always)]
pub unsafe fn get_unchecked(&self, index: usize) -> usize {
debug_assert!(
Self::word_of(index) < self.words.len(),
"lane {index} has no backing word"
);
let word = unsafe { *self.words.get_unchecked(Self::word_of(index)) };
(word >> Self::offset_of(index)) & Self::mask()
}
#[inline(always)]
pub unsafe fn set_unchecked(&mut self, index: usize, value: usize) {
debug_assert!(
Self::word_of(index) < self.words.len(),
"lane {index} has no backing word"
);
let off = Self::offset_of(index);
let slot =
unsafe { self.words.get_unchecked_mut(Self::word_of(index)) };
*slot &= !(Self::mask() << off);
*slot |= (value & Self::mask()) << off;
}
#[inline]
pub fn push(&mut self, value: usize) {
let off = Self::offset_of(self.len);
let bits = (value & Self::mask()) << off;
if let Some(w) = self.words.get_mut(Self::word_of(self.len)) {
*w = (*w & !(Self::mask() << off)) | bits;
} else {
debug_assert!(off == 0);
self.words.push(bits);
}
self.len += 1;
}
#[inline]
pub fn pop(&mut self) -> Option<usize> {
if self.len == 0 {
return None;
}
let value = unsafe { self.get_unchecked(self.len - 1) };
self.len -= 1;
self.words.truncate(Self::words_for(self.len));
Some(value)
}
pub fn truncate(&mut self, new_len: usize) {
if new_len >= self.len {
return;
}
self.len = new_len;
self.words.truncate(Self::words_for(new_len));
}
pub fn clear(&mut self) {
self.words.clear();
self.len = 0;
}
pub fn append(&mut self, other: &mut Self) {
let other_len = other.len;
if other_len == 0 {
return;
}
self.extend_from_packed(other, 0, other_len);
other.clear();
}
pub fn extend_from_packed(
&mut self,
other: &Self,
start: usize,
len: usize,
) {
assert!(
start <= other.len && len <= other.len - start,
"source range out of bounds: the len is {} but the range is \
{start}..{start}+{len}",
other.len
);
if len == 0 {
return;
}
let per = Self::items_per_word();
let new_len = match self.len.checked_add(len) {
Some(new_len) => new_len,
None => capacity_overflow(),
};
self.words.truncate(Self::words_for(self.len));
if self.len % per == 0 && start % per == 0 {
let first = start / per;
self.words.extend_from_slice(
&other.words[first..first + Self::words_for(len)],
);
} else {
let b = BITS as usize;
self.words.resize(Self::words_for(new_len), 0);
copy_bits_between(
&other.words,
start * b,
&mut self.words,
self.len * b,
len * b,
);
}
self.len = new_len;
}
pub fn extend_lanes<I: IntoIterator<Item = usize>>(&mut self, lanes: I) {
let mut lanes = lanes.into_iter();
let per = Self::items_per_word();
let mask = Self::mask();
self.reserve(lanes.size_hint().0);
while self.len % per != 0 {
match lanes.next() {
Some(v) => self.push(v),
None => return,
}
}
self.words.truncate(Self::words_for(self.len));
let mut word = 0usize;
let mut filled = 0usize;
for v in lanes {
word |= (v & mask) << (filled * BITS as usize);
filled += 1;
if filled == per {
self.words.push(word);
self.len += per;
word = 0;
filled = 0;
}
}
if filled != 0 {
self.words.push(word);
self.len += filled;
}
}
pub fn extend_fill(&mut self, value: usize, count: usize) {
if count == 0 {
return;
}
let start = self.len;
let new_len = match start.checked_add(count) {
Some(new_len) => new_len,
None => capacity_overflow(),
};
self.words.resize(Self::words_for(new_len), 0);
self.len = new_len;
self.fill_range(start, count, value);
}
pub fn copy_from_packed(
&mut self,
other: &Self,
other_start: usize,
start: usize,
count: usize,
) {
assert!(
other_start <= other.len
&& count <= other.len - other_start
&& start <= self.len
&& count <= self.len - start,
"copy range out of bounds: the source len is {} and the range is \
{other_start}..{other_start}+{count}, the destination len is {} \
and the range is {start}..{start}+{count}",
other.len,
self.len
);
let b = BITS as usize;
copy_bits_between(
&other.words,
other_start * b,
&mut self.words,
start * b,
count * b,
);
}
pub fn fill_range(&mut self, start: usize, len: usize, value: usize) {
assert!(
start <= self.len && len <= self.len - start,
"fill range out of bounds: the len is {} but the range is \
{start}..{start}+{len}",
self.len
);
if len == 0 {
return;
}
let mask = Self::mask();
let rep = (value & mask).wrapping_mul(usize::MAX / mask);
let end = start + len;
let mut wi = Self::word_of(start);
let last = Self::word_of(end - 1);
let head_lo = Self::offset_of(start);
let tail_hi = Self::offset_of(end - 1) + BITS as usize;
let word_bits = usize::BITS as usize;
if wi == last {
let m = bit_span_mask(head_lo, tail_hi);
let w = &mut self.words[wi];
*w = (*w & !m) | (rep & m);
return;
}
if head_lo != 0 {
let m = bit_span_mask(head_lo, word_bits);
let w = &mut self.words[wi];
*w = (*w & !m) | (rep & m);
wi += 1;
}
let interior_end = if tail_hi == word_bits { last + 1 } else { last };
for w in &mut self.words[wi..interior_end] {
*w = rep;
}
if tail_hi != word_bits {
let m = bit_span_mask(0, tail_hi);
let w = &mut self.words[last];
*w = (*w & !m) | (rep & m);
}
}
pub fn copy_lanes(&mut self, src: usize, dst: usize, count: usize) {
assert!(
src <= self.len
&& count <= self.len - src
&& dst <= self.len
&& count <= self.len - dst,
"copy range out of bounds: the len is {} but the ranges are \
{src}..{src}+{count} and {dst}..{dst}+{count}",
self.len
);
let b = BITS as usize;
copy_bits_within(&mut self.words, src * b, dst * b, count * b);
}
pub fn range_eq(
&self,
start: usize,
other: &Self,
other_start: usize,
len: usize,
) -> bool {
assert!(
start <= self.len
&& len <= self.len - start
&& other_start <= other.len
&& len <= other.len - other_start,
"compare range out of bounds"
);
if len == 0 {
return true;
}
let per = Self::items_per_word();
if start % per != 0 || other_start % per != 0 {
let b = BITS as usize;
let word_bits = usize::BITS as usize;
let (sbit, obit) = (start * b, other_start * b);
let total = len * b;
let mut done = 0;
while done < total {
let n = word_bits.min(total - done);
if read_bits(&self.words, sbit + done, n)
!= read_bits(&other.words, obit + done, n)
{
return false;
}
done += n;
}
return true;
}
let (sw, ow) = (start / per, other_start / per);
let full = len / per;
if self.words[sw..sw + full] != other.words[ow..ow + full] {
return false;
}
let tail = len % per;
if tail == 0 {
return true;
}
let mask = (1usize << (tail * BITS as usize)) - 1;
(self.words[sw + full] & mask) == (other.words[ow + full] & mask)
}
pub fn count_in(&self, start: usize, len: usize, value: usize) -> usize {
assert!(
start <= self.len && len <= self.len - start,
"count range out of bounds: the len is {} but the range is \
{start}..{start}+{len}",
self.len
);
if len == 0 {
return 0;
}
let mask = Self::mask();
let value = value & mask;
let filler = (value ^ mask).wrapping_mul(usize::MAX / mask);
let end = start + len;
let first = Self::word_of(start);
let last = Self::word_of(end - 1);
let head_lo = Self::offset_of(start);
let tail_hi = Self::offset_of(end - 1) + BITS as usize;
let word_bits = usize::BITS as usize;
if first == last {
let keep = bit_span_mask(head_lo, tail_hi);
let w = (self.words[first] & keep) | (filler & !keep);
return count_word_in::<BITS>(w, value);
}
let keep = bit_span_mask(head_lo, word_bits);
let head = (self.words[first] & keep) | (filler & !keep);
let keep = bit_span_mask(0, tail_hi);
let tail = (self.words[last] & keep) | (filler & !keep);
let mut total = count_word_in::<BITS>(head, value)
+ count_word_in::<BITS>(tail, value);
for &w in &self.words[first + 1..last] {
total += count_word_in::<BITS>(w, value);
}
total
}
}
#[cold]
#[inline(never)]
fn capacity_overflow() -> ! {
panic!("capacity overflow")
}
#[inline(always)]
fn bit_span_mask(lo: usize, hi: usize) -> usize {
let width = hi - lo;
if width == usize::BITS as usize {
usize::MAX
} else {
((1usize << width) - 1) << lo
}
}
#[inline(always)]
fn read_bits(words: &[usize], bit: usize, n: usize) -> usize {
let word_bits = usize::BITS as usize;
let w = bit / word_bits;
let r = bit % word_bits;
let val = if r == 0 {
words[w]
} else if r + n <= word_bits {
words[w] >> r
} else {
(words[w] >> r) | (words[w + 1] << (word_bits - r))
};
if n == word_bits {
val
} else {
val & ((1usize << n) - 1)
}
}
#[inline(always)]
fn merge_bits(word: usize, val: usize, lo: usize, hi: usize) -> usize {
let m = bit_span_mask(lo, hi);
(word & !m) | ((val << lo) & m)
}
fn copy_bits_within(words: &mut [usize], src: usize, dst: usize, nbits: usize) {
if nbits == 0 || src == dst {
return;
}
let wb = usize::BITS as usize;
let first = dst / wb;
let last = (dst + nbits - 1) / wb;
let lo = dst % wb;
let hi = (dst + nbits - 1) % wb + 1;
if first == last {
let v = read_bits(words, src, nbits);
words[first] = merge_bits(words[first], v, lo, hi);
return;
}
let s0 = src + (first + 1) * wb - dst;
let (j0, r) = (s0 / wb, s0 % wb);
let head = |words: &mut [usize]| {
let v = read_bits(words, src, wb - lo);
words[first] = merge_bits(words[first], v, lo, wb);
};
let tail = |words: &mut [usize]| {
let v = read_bits(words, src + nbits - hi, hi);
words[last] = merge_bits(words[last], v, 0, hi);
};
let middle = |words: &mut [usize], w: usize| {
let j = j0 + (w - first - 1);
words[w] = if r == 0 {
words[j]
} else {
(words[j] >> r) | (words[j + 1] << (wb - r))
};
};
if dst < src {
head(words);
for w in first + 1..last {
middle(words, w);
}
tail(words);
} else {
tail(words);
for w in (first + 1..last).rev() {
middle(words, w);
}
head(words);
}
}
fn copy_bits_between(
src: &[usize],
src_bit: usize,
dst: &mut [usize],
dst_bit: usize,
nbits: usize,
) {
if nbits == 0 {
return;
}
let wb = usize::BITS as usize;
let first = dst_bit / wb;
let last = (dst_bit + nbits - 1) / wb;
let lo = dst_bit % wb;
let hi = (dst_bit + nbits - 1) % wb + 1;
if first == last {
let v = read_bits(src, src_bit, nbits);
dst[first] = merge_bits(dst[first], v, lo, hi);
return;
}
let v = read_bits(src, src_bit, wb - lo);
dst[first] = merge_bits(dst[first], v, lo, wb);
let s0 = src_bit + (first + 1) * wb - dst_bit;
let (j0, r) = (s0 / wb, s0 % wb);
if r == 0 {
dst[first + 1..last].copy_from_slice(&src[j0..j0 + (last - first - 1)]);
} else {
for (i, w) in dst[first + 1..last].iter_mut().enumerate() {
let j = j0 + i;
*w = (src[j] >> r) | (src[j + 1] << (wb - r));
}
}
let v = read_bits(src, src_bit + nbits - hi, hi);
dst[last] = merge_bits(dst[last], v, 0, hi);
}
#[doc(hidden)]
#[inline]
pub fn count_word_in<const BITS: u32>(word: usize, value: usize) -> usize {
if BITS == 1 {
if value != 0 {
word.count_ones() as usize
} else {
word.count_zeros() as usize
}
} else {
let mask = (1usize << BITS) - 1;
let rep1 = usize::MAX / mask;
let highrep = rep1 << (BITS - 1);
let target = value & mask;
let rep_target = target.wrapping_mul(rep1);
let u = word ^ rep_target;
let mut collapsed = u & rep1;
let mut j: u32 = 1;
while j < BITS {
collapsed |= (u >> j) & rep1;
j += 1;
}
let nz_high = collapsed << (BITS - 1);
let matches = !nz_high & highrep;
matches.count_ones() as usize
}
}
impl<const BITS: u32> Default for PackedArray<BITS> {
#[inline]
fn default() -> Self {
Self::new()
}
}
impl<const BITS: u32> Clone for PackedArray<BITS> {
fn clone(&self) -> Self {
Self {
words: self.words.clone(),
len: self.len,
}
}
}
pub trait BitPack: Clone + Default + core::fmt::Debug + Sized {
const BITS: u32;
fn new() -> Self;
fn with_capacity(capacity: usize) -> Self;
fn len(&self) -> usize;
fn is_empty(&self) -> bool;
fn capacity(&self) -> usize;
fn reserve(&mut self, additional: usize);
fn reserve_exact(&mut self, additional: usize);
fn shrink_to_fit(&mut self);
fn truncate(&mut self, new_len: usize);
unsafe fn set_len(&mut self, new_len: usize);
fn get(&self, index: usize) -> usize;
unsafe fn get_unchecked(&self, index: usize) -> usize;
fn word(&self, index: usize) -> usize;
fn set(&mut self, index: usize, value: usize);
unsafe fn set_unchecked(&mut self, index: usize, value: usize);
fn push(&mut self, value: usize);
fn pop(&mut self) -> Option<usize>;
fn clear(&mut self);
fn append(&mut self, other: &mut Self);
fn extend_from_packed(&mut self, other: &Self, start: usize, len: usize);
fn extend_lanes<I: IntoIterator<Item = usize>>(&mut self, lanes: I);
fn extend_fill(&mut self, value: usize, count: usize);
fn copy_from_packed(
&mut self,
other: &Self,
other_start: usize,
start: usize,
count: usize,
);
fn fill_range(&mut self, start: usize, len: usize, value: usize);
fn copy_lanes(&mut self, src: usize, dst: usize, count: usize);
fn range_eq(
&self,
start: usize,
other: &Self,
other_start: usize,
len: usize,
) -> bool;
fn count_in(&self, start: usize, len: usize, value: usize) -> usize;
}
impl<const BITS: u32> BitPack for PackedArray<BITS> {
const BITS: u32 = BITS;
#[inline]
fn new() -> Self {
PackedArray::new()
}
#[inline]
fn with_capacity(capacity: usize) -> Self {
PackedArray::with_capacity(capacity)
}
#[inline]
fn len(&self) -> usize {
PackedArray::len(self)
}
#[inline]
fn is_empty(&self) -> bool {
PackedArray::is_empty(self)
}
#[inline]
fn capacity(&self) -> usize {
PackedArray::capacity(self)
}
#[inline]
fn reserve(&mut self, additional: usize) {
PackedArray::reserve(self, additional);
}
#[inline]
fn reserve_exact(&mut self, additional: usize) {
PackedArray::reserve_exact(self, additional);
}
#[inline]
fn shrink_to_fit(&mut self) {
PackedArray::shrink_to_fit(self);
}
#[inline]
fn truncate(&mut self, new_len: usize) {
PackedArray::truncate(self, new_len);
}
#[inline]
unsafe fn set_len(&mut self, new_len: usize) {
unsafe { PackedArray::set_len(self, new_len) };
}
#[inline]
fn get(&self, index: usize) -> usize {
PackedArray::get(self, index)
}
#[inline(always)]
unsafe fn get_unchecked(&self, index: usize) -> usize {
unsafe { PackedArray::get_unchecked(self, index) }
}
#[inline]
fn word(&self, index: usize) -> usize {
debug_assert!(index < self.words.len());
self.words[index]
}
#[inline]
fn set(&mut self, index: usize, value: usize) {
PackedArray::set(self, index, value);
}
#[inline(always)]
unsafe fn set_unchecked(&mut self, index: usize, value: usize) {
unsafe { PackedArray::set_unchecked(self, index, value) };
}
#[inline]
fn push(&mut self, value: usize) {
PackedArray::push(self, value);
}
#[inline]
fn pop(&mut self) -> Option<usize> {
PackedArray::pop(self)
}
#[inline]
fn clear(&mut self) {
PackedArray::clear(self);
}
#[inline]
fn append(&mut self, other: &mut Self) {
PackedArray::append(self, other);
}
#[inline]
fn extend_from_packed(&mut self, other: &Self, start: usize, len: usize) {
PackedArray::extend_from_packed(self, other, start, len);
}
#[inline]
fn extend_lanes<I: IntoIterator<Item = usize>>(&mut self, lanes: I) {
PackedArray::extend_lanes(self, lanes);
}
#[inline]
fn extend_fill(&mut self, value: usize, count: usize) {
PackedArray::extend_fill(self, value, count);
}
#[inline]
fn copy_from_packed(
&mut self,
other: &Self,
other_start: usize,
start: usize,
count: usize,
) {
PackedArray::copy_from_packed(self, other, other_start, start, count);
}
#[inline]
fn fill_range(&mut self, start: usize, len: usize, value: usize) {
PackedArray::fill_range(self, start, len, value);
}
#[inline]
fn copy_lanes(&mut self, src: usize, dst: usize, count: usize) {
PackedArray::copy_lanes(self, src, dst, count);
}
#[inline]
fn range_eq(
&self,
start: usize,
other: &Self,
other_start: usize,
len: usize,
) -> bool {
PackedArray::range_eq(self, start, other, other_start, len)
}
#[inline]
fn count_in(&self, start: usize, len: usize, value: usize) -> usize {
PackedArray::count_in(self, start, len, value)
}
}