use enum_like::EnumLike;
use std::fmt;
use std::iter::{FromIterator, repeat};
use std::marker::PhantomData;
use std::ops::Range;
use std::hash::{Hash, Hasher};
use std::cmp;
type StorageBlock = u16;
type Storage = Vec<StorageBlock>;
const STORAGE_BLOCK_SIZE: usize = 16;
#[derive(Clone)]
pub struct EnumVec<T: EnumLike> {
storage: Storage,
num_elements: usize,
phantom: PhantomData<T>,
}
#[allow(missing_docs)]
impl<T: EnumLike> EnumVec<T> {
const BITS_PER_ELEM: usize = (T::NUM_VARIANTS > (1 << 0)) as usize
+ (T::NUM_VARIANTS > (1 << 1)) as usize
+ (T::NUM_VARIANTS > (1 << 2)) as usize
+ (T::NUM_VARIANTS > (1 << 3)) as usize
+ (T::NUM_VARIANTS > (1 << 4)) as usize
+ (T::NUM_VARIANTS > (1 << 5)) as usize
+ (T::NUM_VARIANTS > (1 << 6)) as usize
+ (T::NUM_VARIANTS > (1 << 7)) as usize
+ (T::NUM_VARIANTS > (1 << 8)) as usize
+ (T::NUM_VARIANTS > (1 << 9)) as usize
+ (T::NUM_VARIANTS > (1 << 10)) as usize
+ (T::NUM_VARIANTS > (1 << 11)) as usize
+ (T::NUM_VARIANTS > (1 << 12)) as usize
+ (T::NUM_VARIANTS > (1 << 13)) as usize
+ (T::NUM_VARIANTS > (1 << 14)) as usize
+ (T::NUM_VARIANTS > (1 << 15)) as usize
+ (T::NUM_VARIANTS > (1 << 16)) as usize
+ (T::NUM_VARIANTS > (1 << 17)) as usize
+ (T::NUM_VARIANTS > (1 << 18)) as usize
+ (T::NUM_VARIANTS > (1 << 19)) as usize
+ (T::NUM_VARIANTS > (1 << 20)) as usize
+ (T::NUM_VARIANTS > (1 << 21)) as usize
+ (T::NUM_VARIANTS > (1 << 22)) as usize
+ (T::NUM_VARIANTS > (1 << 23)) as usize
+ (T::NUM_VARIANTS > (1 << 24)) as usize
+ (T::NUM_VARIANTS > (1 << 25)) as usize
+ (T::NUM_VARIANTS > (1 << 26)) as usize
+ (T::NUM_VARIANTS > (1 << 27)) as usize
+ (T::NUM_VARIANTS > (1 << 28)) as usize
+ (T::NUM_VARIANTS > (1 << 29)) as usize
+ (T::NUM_VARIANTS > (1 << 30)) as usize
+ (T::NUM_VARIANTS > (1 << 31)) as usize
+ Self::ERROR_TOO_MANY_VARIANTS
+ Self::ERROR_ZERO_SIZED;
const ERROR_TOO_MANY_VARIANTS: usize = 0 - ((T::NUM_VARIANTS as u64 > (1 << STORAGE_BLOCK_SIZE) ) as usize);
const ERROR_ZERO_SIZED: usize = 0
- ((T::NUM_VARIANTS <= 1) as usize);
const ELEMS_PER_BLOCK: usize = STORAGE_BLOCK_SIZE / Self::BITS_PER_ELEM;
const ELEMENT_MASK: StorageBlock = ((1u64 << Self::BITS_PER_ELEM) - 1) as StorageBlock;
pub fn new() -> Self {
Default::default()
}
pub fn with_capacity(n: usize) -> Self {
Self {
storage: Storage::with_capacity(Self::blocks_for_elements(n)),
num_elements: 0,
phantom: PhantomData,
}
}
pub fn capacity(&self) -> usize {
self.storage
.capacity()
.saturating_mul(Self::ELEMS_PER_BLOCK)
}
pub fn get(&self, i: usize) -> Option<T> {
self.get_raw(i).map(|x| T::from_discr(x))
}
pub fn set(&mut self, i: usize, x: T) {
self.set_raw(i, x.to_discr());
}
pub fn reserve(&mut self, additional: usize) {
let desired_cap = self
.len()
.checked_add(additional)
.expect("capacity overflow");
self.storage.resize(desired_cap / Self::ELEMS_PER_BLOCK + 1, 0);
}
pub fn shrink_to_fit(&mut self) {
self.fix_storage();
self.storage.shrink_to_fit();
}
pub fn truncate(&mut self, len: usize) {
if len < self.num_elements {
unsafe {
self.set_len(len);
}
}
}
pub fn swap_remove(&mut self, index: usize) -> T {
let length = self.len();
self.swap(index, length - 1);
self.pop().unwrap()
}
pub fn insert(&mut self, index: usize, element: T) {
let shift_storage = |block: &mut StorageBlock, at_zero: StorageBlock| {
let last_bit_offset = (Self::ELEMS_PER_BLOCK - 1) * Self::BITS_PER_ELEM;
let last = *block >> last_bit_offset & Self::ELEMENT_MASK;
*block <<= Self::BITS_PER_ELEM;
*block |= at_zero;
last
};
self.push(element);
let slow_insert = index % Self::ELEMS_PER_BLOCK;
let self_len = self.len();
let mut prev = element.to_discr();
let mut i = index;
if slow_insert > 0 {
let slow_limit = index - slow_insert + Self::ELEMS_PER_BLOCK;
let slow_limit = cmp::min(slow_limit, self_len);
while i < slow_limit {
unsafe {
let next = self.get_raw_unchecked(i);
self.set_raw_unchecked(i, prev);
prev = next;
}
i += 1;
}
}
if i < self.len() {
let (ib, _) = Self::block_index(i);
let (last_ib, _) = Self::block_index(self.len() - 1);
let mut prev = prev as StorageBlock;
for i in ib..(last_ib + 1) {
prev = shift_storage(&mut self.storage[i], prev);
}
}
}
pub fn remove(&mut self, index: usize) -> T {
let x = self.get(index).unwrap();
let shift_storage = |block: &mut StorageBlock, at_zero: StorageBlock| {
let last = *block & Self::ELEMENT_MASK;
let end_bit_offset = (Self::ELEMS_PER_BLOCK - 1) * Self::BITS_PER_ELEM;
*block >>= Self::BITS_PER_ELEM;
*block |= at_zero << end_bit_offset;
last
};
let mut i = index;
let length = self.len() - 1;
let block_limit = (1 + Self::block_index(i).0) * Self::ELEMS_PER_BLOCK;
let slow_limit = cmp::min(length, block_limit);
while i < slow_limit {
unsafe { let next = self.get_raw_unchecked(i + 1);
self.set_raw_unchecked(i, next);
}
i += 1;
}
let prev = unsafe {
self.get_raw_unchecked(self.len() - 1)
};
self.num_elements -= 1;
if i < self.len() {
let (ib, _) = Self::block_index(i);
let (last_ib, _) = Self::block_index(self.len() - 1);
let mut prev = prev as StorageBlock;
for i in (ib..(last_ib + 1)).rev() {
prev = shift_storage(&mut self.storage[i], prev);
}
}
x
}
pub fn retain<F>(&mut self, mut f: F)
where
F: FnMut(&T) -> bool
{
let mut i_get = 0;
let mut i_set = 0;
let l = self.len();
while i_get < l {
let x = self.get(i_get).unwrap();
if f(&x) {
self.set(i_set, x);
i_set += 1;
}
i_get += 1;
}
unsafe {
self.set_len(i_set);
}
}
pub fn push(&mut self, x: T) {
self.grow_if_needed();
let idx = self.num_elements;
self.num_elements =
self.num_elements.checked_add(1).expect("capacity overflow");
self.set(idx, x);
}
pub fn pop(&mut self) -> Option<T> {
if self.is_empty() {
None
} else {
let x = self.get(self.num_elements - 1).unwrap();
self.num_elements -= 1;
Some(x)
}
}
pub fn append(&mut self, other: &mut Self) {
let other_len = other.len();
let self_len = self.len();
if self.len() % Self::ELEMS_PER_BLOCK == 0 {
self.fix_storage();
other.fix_storage();
self.storage.append(&mut other.storage);
self.num_elements += other_len;
} else {
self.reserve(other_len);
unsafe { self.set_len(self_len + other_len);
for i in 0..other_len {
self.set_raw_unchecked(self_len + i, other.get_raw_unchecked(i));
}
}
other.clear();
}
}
pub fn clear(&mut self) {
self.truncate(0);
}
pub fn len(&self) -> usize {
self.num_elements
}
pub unsafe fn set_len(&mut self, len: usize) {
self.num_elements = len;
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn split_off(&mut self, at: usize) -> Self {
assert!(at <= self.len(), "`at` out of bounds");
let other_len = self.len() - at;
let mut other = Self::with_capacity(other_len);
unsafe {
other.set_len(other_len);
for i in 0..other_len {
other.set_raw_unchecked(i, self.get_raw_unchecked(at + i));
}
self.set_len(at);
}
other
}
pub fn resize(&mut self, new_len: usize, value: T)
{
let len = self.len();
if new_len > len {
self.extend_with_value(value, new_len - len);
} else {
self.truncate(new_len);
}
}
fn extend_with_value(&mut self, value: T, count: usize) {
if count <= 4 * Self::ELEMS_PER_BLOCK {
self.extend(repeat(value).take(count));
} else {
let to_insert_first = Self::ELEMS_PER_BLOCK -
(self.len() % Self::ELEMS_PER_BLOCK);
self.extend(repeat(value).take(to_insert_first));
let count_end = count - to_insert_first;
let count_blocks = count_end / Self::ELEMS_PER_BLOCK;
let to_insert_mid = count_blocks * Self::ELEMS_PER_BLOCK;
let to_insert_last = count - (to_insert_first + to_insert_mid);
let d = value.to_discr();
let mut block_value = d as StorageBlock;
let mut i = Self::BITS_PER_ELEM;
while i < STORAGE_BLOCK_SIZE {
block_value |= block_value << i;
i *= 2;
}
let old_len = self.len();
self.fix_storage();
self.storage.reserve(count_blocks + (to_insert_last > 0) as usize);
for _ in 0..count_blocks {
let storage_len = self.storage.len();
self.storage.resize(storage_len + count_blocks, block_value);
}
unsafe {
self.set_len(old_len + count_blocks * Self::ELEMS_PER_BLOCK);
}
self.extend(repeat(value).take(to_insert_last));
}
}
fn get_raw(&self, i: usize) -> Option<usize> {
if i >= self.len() {
return None;
}
let discr = unsafe { self.get_raw_unchecked(i) };
Some(discr)
}
pub unsafe fn get_raw_unchecked(&self, i: usize) -> usize {
let (idx_w, idx_b) = Self::block_index(i);
let block = self.storage.get_unchecked(idx_w);
let discr = (block >> idx_b) & Self::ELEMENT_MASK;
discr as usize
}
fn set_raw(&mut self, i: usize, discr: usize) {
if i >= self.len() {
panic!("index out of bounds: {} >= {}", i, self.len());
}
unsafe {
self.set_raw_unchecked(i, discr);
}
}
pub unsafe fn set_raw_unchecked(&mut self, i: usize, discr: usize) {
let (idx_w, idx_b) = Self::block_index(i);
let block = self.storage.get_unchecked_mut(idx_w);
*block &= !(Self::ELEMENT_MASK << idx_b);
*block |= (discr as StorageBlock) << idx_b;
}
pub fn swap(&mut self, ia: usize, ib: usize) {
let a = self.get_raw(ia).unwrap();
let b = self.get_raw(ib).unwrap();
self.set_raw(ia, b);
self.set_raw(ib, a);
}
fn grow_if_needed(&mut self) {
if (self.len() % Self::ELEMS_PER_BLOCK == 0)
&& (Self::blocks_for_elements(self.len()) == self.storage.len())
{
self.storage.push(0);
}
}
fn fix_storage(&mut self) {
let len = Self::blocks_for_elements(self.len());
self.storage.truncate(len);
}
fn block_index(i: usize) -> (usize, usize) {
(
i / Self::ELEMS_PER_BLOCK,
(i % Self::ELEMS_PER_BLOCK) * Self::BITS_PER_ELEM,
)
}
fn blocks_for_elements(n: usize) -> usize {
n.saturating_add(Self::ELEMS_PER_BLOCK - 1) / Self::ELEMS_PER_BLOCK
}
pub fn iter<'a>(&'a self) -> EnumVecIter<'a, T> {
(&self).into_iter()
}
pub fn for_each<F>(&mut self, mut f: F)
where
F: FnMut(&mut T),
{
let l = self.len();
for i in 0..l {
let mut x = self.get(i).unwrap();
f(&mut x);
self.set(i, x);
}
}
pub fn to_vec(&self) -> Vec<T> {
let mut v = Vec::with_capacity(self.len());
v.extend(self.iter());
v
}
pub fn from_elem(x: T, n: usize) -> Self
{
let mut v = EnumVec::new();
v.extend_with_value(x, n);
v
}
pub fn from_slice(x: &[T]) -> Self
{
let mut v = EnumVec::new();
v.extend(x.iter().cloned());
v
}
pub fn storage(&self) -> &Storage {
&self.storage
}
pub unsafe fn storage_mut(&mut self) -> &mut Storage {
&mut self.storage
}
pub fn any(&self, x: T) -> bool {
if self.is_empty() {
return false;
}
let (last_block, last_elem_shift) = Self::block_index(self.len());
let num_variants_p2 = Self::ELEMENT_MASK;
let one_mask = (!0 / num_variants_p2) >> (STORAGE_BLOCK_SIZE % Self::BITS_PER_ELEM);
let high_mask = one_mask << (Self::BITS_PER_ELEM - 1);
let x = x.to_discr();
let x_mask = x as StorageBlock * one_mask;
let haszero = |v: StorageBlock| -> bool {
((v.wrapping_sub(one_mask as StorageBlock)) & !v & high_mask) != 0
};
for i in 0..last_block {
if haszero(self.storage[i] ^ x_mask) {
return true;
}
}
if last_elem_shift != 0 {
let last_block_mask = !0 << (last_elem_shift);
if haszero((self.storage[last_block] ^ x_mask) | last_block_mask) {
return true;
}
}
false
}
pub fn all(&self, x: T) -> bool {
if self.is_empty() {
return true;
}
let (last_block, last_elem_shift) = Self::block_index(self.len());
let valid_mask = !0 >> (STORAGE_BLOCK_SIZE % Self::BITS_PER_ELEM);
let num_variants_p2 = Self::ELEMENT_MASK;
let one_mask = (!0 / num_variants_p2) >> (STORAGE_BLOCK_SIZE % Self::BITS_PER_ELEM);
let x = x.to_discr();
let x_mask = x as StorageBlock * one_mask;
for i in 0..last_block {
if self.storage[i] & valid_mask != x_mask {
return false;
}
}
if last_elem_shift != 0 {
let last_block_mask = !(!0 << (last_elem_shift));
if self.storage[last_block] & last_block_mask != x_mask & last_block_mask {
return false;
}
}
true
}
}
impl<T: EnumLike + fmt::Debug> fmt::Debug for EnumVec<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_list().entries(self.iter()).finish()
}
}
impl<T: EnumLike> Default for EnumVec<T> {
fn default() -> Self {
Self {
storage: Storage::new(),
num_elements: 0,
phantom: PhantomData,
}
}
}
impl<T: EnumLike> Extend<T> for EnumVec<T> {
fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
let mut iter = iter.into_iter();
let iter_len = iter.size_hint().0;
let self_len = self.len();
self.reserve(iter_len);
self.num_elements += iter_len;
for i in 0..iter_len {
self.set(self_len + i, iter.next().unwrap());
}
for elem in iter {
self.push(elem);
}
}
}
impl<T: EnumLike> FromIterator<T> for EnumVec<T> {
fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
let mut v = EnumVec::new();
v.extend(iter);
v
}
}
impl<T: EnumLike> From<Vec<T>> for EnumVec<T> {
fn from(v: Vec<T>) -> Self {
EnumVec::from_iter(v)
}
}
impl<T: EnumLike> Into<Vec<T>> for EnumVec<T> {
fn into(self) -> Vec<T> {
self.to_vec()
}
}
impl<'a, T: EnumLike> IntoIterator for &'a EnumVec<T> {
type Item = T;
type IntoIter = EnumVecIter<'a, T>;
fn into_iter(self) -> Self::IntoIter {
let l = self.len();
EnumVecIter {
v: &self,
range: 0..l,
}
}
}
impl<T: EnumLike> IntoIterator for EnumVec<T> {
type Item = T;
type IntoIter = EnumVecIntoIter<T>;
fn into_iter(self) -> Self::IntoIter {
let l = self.len();
EnumVecIntoIter {
v: self,
range: 0..l,
}
}
}
pub struct EnumVecIter<'a, T: 'a + EnumLike> {
v: &'a EnumVec<T>,
range: Range<usize>,
}
impl<'a, T: EnumLike> Iterator for EnumVecIter<'a, T> {
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
self.range.next().map(|x| self.v.get(x).unwrap())
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.range.size_hint()
}
fn count(self) -> usize {
self.size_hint().0
}
fn nth(&mut self, n: usize) -> Option<Self::Item> {
self.range.nth(n).map(|x| self.v.get(x).unwrap())
}
}
impl<'a, T: EnumLike> DoubleEndedIterator for EnumVecIter<'a, T> {
fn next_back(&mut self) -> Option<Self::Item> {
self.range.next_back().map(|x| self.v.get(x).unwrap())
}
}
impl<'a, T: EnumLike> ExactSizeIterator for EnumVecIter<'a, T> {}
pub struct EnumVecIntoIter<T: EnumLike> {
v: EnumVec<T>,
range: Range<usize>,
}
impl<T: EnumLike> Iterator for EnumVecIntoIter<T> {
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
self.range.next().map(|x| self.v.get(x).unwrap())
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.range.size_hint()
}
fn count(self) -> usize {
self.size_hint().0
}
fn nth(&mut self, n: usize) -> Option<Self::Item> {
self.range.nth(n).map(|x| self.v.get(x).unwrap())
}
}
impl<T: EnumLike> DoubleEndedIterator for EnumVecIntoIter<T> {
fn next_back(&mut self) -> Option<Self::Item> {
self.range.next_back().map(|x| self.v.get(x).unwrap())
}
}
impl<T: EnumLike> ExactSizeIterator for EnumVecIntoIter<T> {}
impl<T: EnumLike> PartialEq for EnumVec<T> {
fn eq(&self, other: &EnumVec<T>) -> bool {
if self.len() == other.len() {
let l = self.len();
for i in 0..l {
unsafe { if self.get_raw_unchecked(i) != other.get_raw_unchecked(i) {
return false;
}
}
}
true
} else {
false
}
}
}
impl<T: EnumLike> Eq for EnumVec<T> {}
impl<T: EnumLike> Hash for EnumVec<T> {
fn hash<H: Hasher>(&self, state: &mut H) {
let l = self.len();
for i in 0..l {
let x = unsafe { self.get_raw_unchecked(i) };
x.hash(state);
}
}
}
pub type BitVec = EnumVec<bool>;
#[cfg(test)]
mod tests {
use super::*;
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
enum ABC {
A,
B,
C,
}
unsafe impl EnumLike for ABC {
const NUM_VARIANTS: usize = 3;
fn to_discr(self) -> usize {
match self {
ABC::A => 0,
ABC::B => 1,
ABC::C => 2,
}
}
fn from_discr(x: usize) -> Self {
match x {
0 => ABC::A,
1 => ABC::B,
2 => ABC::C,
_ => panic!("Enum ABC has no variant {}", x),
}
}
}
#[test]
fn abc_push_pop() {
let mut v = EnumVec::new();
v.push(ABC::A);
v.push(ABC::B);
v.push(ABC::C);
v.push(ABC::A);
assert_eq!(v.pop().unwrap(), ABC::A);
assert_eq!(v.pop().unwrap(), ABC::C);
assert_eq!(v.pop().unwrap(), ABC::B);
assert_eq!(v.pop().unwrap(), ABC::A);
assert!(v.pop().is_none());
}
#[test]
fn option_abc() {
let mut v = EnumVec::new();
v.push(None);
v.push(Some(ABC::A));
v.push(Some(ABC::B));
v.push(Some(ABC::C));
v.push(Some(ABC::A));
assert_eq!(v.pop().unwrap().unwrap(), ABC::A);
assert_eq!(v.pop().unwrap().unwrap(), ABC::C);
assert_eq!(v.pop().unwrap().unwrap(), ABC::B);
assert_eq!(v.pop().unwrap().unwrap(), ABC::A);
assert_eq!(v.pop().unwrap(), None);
assert_eq!(v.pop(), None);
}
#[test]
fn get_set() {
let mut v = EnumVec::new();
for _ in 0..10 {
v.push(ABC::A);
}
v.set(3, ABC::C);
v.set(5, ABC::B);
for i in 0..10 {
let expected = match i {
3 => ABC::C,
5 => ABC::B,
_ => ABC::A,
};
assert_eq!(v.get(i).unwrap(), expected);
}
}
#[test]
fn insert_remove() {
let mut v = EnumVec::new();
for _ in 0..10 {
v.push(ABC::B);
}
v.insert(0, ABC::C);
v.insert(0, ABC::C);
v.insert(0, ABC::C);
v.insert(0, ABC::C);
v.insert(0, ABC::C);
v.insert(10, ABC::A);
v.insert(10, ABC::A);
v.insert(10, ABC::A);
v.insert(10, ABC::A);
v.insert(10, ABC::A);
for i in 0..5 {
assert_eq!(v.get(i).unwrap(), ABC::C);
}
for i in 5..10 {
assert_eq!(v.get(i).unwrap(), ABC::B);
}
for i in 10..15 {
assert_eq!(v.get(i).unwrap(), ABC::A);
}
for i in 15..20 {
assert_eq!(v.get(i).unwrap(), ABC::B);
}
v.remove(0);
v.remove(0);
v.remove(0);
v.remove(0);
v.remove(0);
v.insert(0, ABC::C);
v.insert(0, ABC::C);
v.insert(0, ABC::C);
v.insert(0, ABC::C);
v.insert(0, ABC::C);
v.remove(15);
v.remove(15);
v.remove(15);
v.remove(15);
v.remove(15);
v.insert(15, ABC::B);
v.insert(15, ABC::B);
v.insert(15, ABC::B);
v.insert(15, ABC::B);
v.insert(15, ABC::B);
for i in 0..5 {
assert_eq!(v.get(i).unwrap(), ABC::C);
}
for i in 5..10 {
assert_eq!(v.get(i).unwrap(), ABC::B);
}
for i in 10..15 {
assert_eq!(v.get(i).unwrap(), ABC::A);
}
for i in 15..20 {
assert_eq!(v.get(i).unwrap(), ABC::B);
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
struct Digit {
x: u8, }
unsafe impl EnumLike for Digit {
const NUM_VARIANTS: usize = 10;
fn to_discr(self) -> usize {
self.x as usize
}
fn from_discr(x: usize) -> Self {
let x = x as u8;
Self { x }
}
}
#[test]
fn digit_test() {
let mut v = EnumVec::new();
v.push(Digit { x: 3 });
v.push(Digit { x: 4 });
v.push(Digit { x: 5 });
v.push(Digit { x: 6 });
v.push(Digit { x: 3 });
v.push(Digit { x: 4 });
v.push(Digit { x: 5 });
v.push(Digit { x: 6 });
v.push(Digit { x: 3 });
assert_eq!(v.pop().unwrap().x, 3);
assert_eq!(v.pop().unwrap().x, 6);
assert_eq!(v.pop().unwrap().x, 5);
assert_eq!(v.pop().unwrap().x, 4);
assert_eq!(v.pop().unwrap().x, 3);
assert_eq!(v.pop().unwrap().x, 6);
assert_eq!(v.pop().unwrap().x, 5);
assert_eq!(v.pop().unwrap().x, 4);
assert_eq!(v.pop().unwrap().x, 3);
assert!(v.pop().is_none());
}
#[test]
fn digit_uses_4_bits() {
let mut v = EnumVec::new();
v.push(Digit { x: 0x3B });
let got = v.pop().unwrap().x;
assert_eq!(got, 0x0B);
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
struct TwoDigits {
tens: Digit,
ones: Digit,
}
unsafe impl EnumLike for TwoDigits {
const NUM_VARIANTS: usize = Digit::NUM_VARIANTS * Digit::NUM_VARIANTS;
fn to_discr(self) -> usize {
self.tens.to_discr() * Digit::NUM_VARIANTS + self.ones.to_discr()
}
fn from_discr(x: usize) -> Self {
let tens = Digit::from_discr(x / Digit::NUM_VARIANTS);
let ones = Digit::from_discr(x % Digit::NUM_VARIANTS);
Self { tens, ones }
}
}
#[test]
fn two_digit_test() {
let mut ev = EnumVec::new();
let mut v = Vec::new();
for i in 0..10 {
let d = TwoDigits {
tens: Digit { x: i },
ones: Digit { x: 9 - i },
};
ev.push(d);
v.push(d);
}
for i in 0..10 {
assert_eq!((i, v[i]), (i, ev.get(i).unwrap()));
}
for i in 0..10 {
let mut d = ev.get(i).unwrap();
d.tens.x = (d.tens.x + 3) % 10;
d.ones.x = (d.ones.x * 2 + 1) % 10;
ev.set(i, d);
assert_eq!(d, ev.get(i).unwrap());
}
}
#[test]
fn from_vec() {
let a = vec![ABC::C, ABC::A, ABC::A, ABC::B, ABC::C];
let mut v = EnumVec::new();
v.extend(a.clone());
for i in 0..a.len() {
assert_eq!(a[i], v.get(i).unwrap());
}
}
#[test]
fn macro_enum_vec() {
let a = vec![ABC::C, ABC::A, ABC::A, ABC::B, ABC::C];
let b = enum_vec![ABC::C, ABC::A, ABC::A, ABC::B, ABC::C];
assert_eq!(a, b.to_vec());
let c = vec![ABC::C; 10];
let d = enum_vec![ABC::C; 10];
assert_eq!(c, d.to_vec());
}
#[test]
fn clone_push_segfault() {
let a: EnumVec<bool> = vec![false].into();
let mut b = a.clone();
b.push(true);
}
#[test]
fn reserve_modifies_storage() {
let mut ev = EnumVec::new();
ev.reserve(1);
assert_eq!(ev.len(), 0);
assert!(ev.storage().len() > 0);
ev.push(true);
assert_eq!(ev.len(), 1);
let mut a: EnumVec<bool> = EnumVec::new();
unsafe { a.reserve(1);
a.set_raw_unchecked(0, 0);
a.set_len(1);
}
assert_eq!(a.len(), 1);
assert_eq!(a.pop().unwrap(), false);
}
#[test]
fn storage_resize() {
let mut ev = EnumVec::new();
unsafe {
let s = ev.storage_mut();
assert_eq!(s.len(), 0);
s.resize(1, 0);
assert_eq!(s.len(), 1);
}
ev.push(false);
}
#[test]
fn any_magic_constants() {
for bits_per_elem in 1..=STORAGE_BLOCK_SIZE {
let num_variants_p2 = if bits_per_elem == STORAGE_BLOCK_SIZE { !0 } else { (1 << bits_per_elem) - 1 };
let elems_per_block = STORAGE_BLOCK_SIZE / bits_per_elem;
let wasted_bits = STORAGE_BLOCK_SIZE % bits_per_elem;
let mut one_mask = 0;
let mut high_mask = 0;
for i in 0..elems_per_block {
one_mask |= 1 << (i * bits_per_elem);
high_mask |= 1 << (((i + 1) * bits_per_elem) - 1);
}
println!("bits_per_elem: {}", bits_per_elem);
assert_eq!(one_mask, (!0/num_variants_p2) >> wasted_bits);
assert_eq!(high_mask, one_mask << (bits_per_elem - 1));
let haszero = |v: StorageBlock| -> bool {
((v.wrapping_sub(one_mask as StorageBlock)) & !v & high_mask) != 0
};
assert_eq!(haszero(one_mask), false);
assert_eq!(haszero(high_mask), false);
assert_eq!(haszero(0), true);
assert_eq!(haszero(one_mask - 1), true);
assert_eq!(haszero(high_mask << 1), true);
assert_eq!(haszero((high_mask << 1).wrapping_sub(one_mask)), false);
assert_eq!(haszero((high_mask << 1).wrapping_sub(one_mask)), false);
}
}
#[test]
fn false_positive_any_all() {
let mut v = EnumVec::new();
for _ in 0..1000 {
v.push(None);
println!("v.len(): {}", v.len());
assert_eq!(v.any(Some(true)), false);
assert_eq!(v.all(Some(true)), false);
assert_eq!(v.any(Some(false)), false);
assert_eq!(v.all(Some(false)), false);
assert_eq!(v.any(None), true);
assert_eq!(v.all(None), true);
}
let v: EnumVec<_> = vec![None; 1000].into();
assert_eq!(v.any(Some(false)), false);
assert_eq!(v.any(Some(true)), false);
}
}