Skip to content

Instantly share code, notes, and snippets.

@CoffeeVampir3
Last active March 16, 2023 07:22
Show Gist options
  • Save CoffeeVampir3/362a8420f116b865b8e6f727d84b3a04 to your computer and use it in GitHub Desktop.
Save CoffeeVampir3/362a8420f116b865b8e6f727d84b3a04 to your computer and use it in GitHub Desktop.
N Length Bit Set
mod testing_suite;
use std::ops::{BitAnd, BitOr};
use std::marker::PhantomData;
#[derive(Debug, Clone, PartialEq, Eq)]
struct EnumSet<E, const N: usize = 2> {
flags: [u64; N],
_phantom: PhantomData<E>,
}
impl<E: Copy + Into<u64>, const N: usize> EnumSet<E, N> {
pub fn new(tags: &[E]) -> Self {
let mut seq = Self {
flags: [0; N],
_phantom: PhantomData,
};
seq.add_many(tags);
seq
}
pub fn default() -> Self {
Self {
flags: [0; N],
_phantom: PhantomData,
}
}
fn add(&mut self, item: E) {
let (idx, pos) = self.enum_to_pos(item);
self.flags[idx] |= 1 << pos;
}
pub fn add_many(&mut self, tags: &[E]) {
for tag in tags {
self.add(*tag);
}
}
fn remove(&mut self, item: E) {
let (idx, pos) = self.enum_to_pos(item);
self.flags[idx] &= !(1 << pos);
}
pub fn remove_many(&mut self, tags: &[E]) {
for tag in tags {
self.remove(*tag);
}
}
pub fn contains_many(&self, tags: &[E]) -> bool {
tags.iter().all(|tag| self.contains(*tag))
}
fn contains(&self, item: E) -> bool {
let (idx, pos) = self.enum_to_pos(item);
self.flags[idx] & (1 << pos) != 0
}
pub fn is_subset_of(&self, other: &Self) -> bool {
self.flags.iter().zip(other.flags.iter()).all(|(a, b)| a & b == *a)
}
pub fn is_superset_of(&self, other: &Self) -> bool {
other.is_subset_of(self)
}
pub fn has_any_of(&self, other: &EnumSet<E, N>) -> bool {
for i in 0..N {
if self.flags[i] & other.flags[i] != 0 {
return true;
}
}
false
}
fn enum_to_pos(&self, item: E) -> (usize, u64) {
let pos = item.into();
(pos as usize / 64, pos % 64)
}
}
impl<E: Copy + Into<u64>, const N: usize> BitAnd for EnumSet<E, N> {
type Output = Self;
fn bitand(self, rhs: Self) -> Self::Output {
let mut flags = [0; N];
for i in 0..N {
flags[i] = self.flags[i] & rhs.flags[i];
}
Self {
flags,
_phantom: PhantomData,
}
}
}
impl<E: Copy + Into<u64>, const N: usize> BitOr for EnumSet<E, N> {
type Output = Self;
fn bitor(self, rhs: Self) -> Self::Output {
let mut flags = [0; N];
for i in 0..N {
flags[i] = self.flags[i] | rhs.flags[i];
}
Self {
flags,
_phantom: PhantomData,
}
}
}
impl<E: Copy + Into<u64>, const N: usize> BitAnd for &EnumSet<E, N> {
type Output = EnumSet<E, N>;
fn bitand(self, rhs: Self) -> Self::Output {
let mut flags = [0; N];
for i in 0..N {
flags[i] = self.flags[i] & rhs.flags[i];
}
Self::Output {
flags,
_phantom: PhantomData,
}
}
}
impl<E: Copy + Into<u64>, const N: usize> BitOr for &EnumSet<E, N> {
type Output = EnumSet<E, N>;
fn bitor(self, rhs: Self) -> Self::Output {
let mut flags = [0; N];
for i in 0..N {
flags[i] = self.flags[i] | rhs.flags[i];
}
Self::Output {
flags,
_phantom: PhantomData,
}
}
}
fn main() {
}
#[cfg(test)]
mod tests {
use crate::*;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TestTag {
Placeholder,
Creature,
Villian,
Last = 127,
}
impl From<TestTag> for u64 {
fn from(value: TestTag) -> Self {
value as u64
}
}
#[test]
fn test_subset_superset_operations() {
fn test_is_subset_of_n<const N: usize>() {
let seq1 = EnumSet::<TestTag, N>::new(&[TestTag::Creature, TestTag::Villian, TestTag::Last]);
let seq2 = EnumSet::<TestTag, N>::new(&[TestTag::Creature, TestTag::Villian]);
let seq3 = EnumSet::<TestTag, N>::new(&[TestTag::Placeholder, TestTag::Last]);
assert_eq!(seq2.is_subset_of(&seq1), true);
assert_eq!(seq3.is_subset_of(&seq1), false);
}
fn test_is_superset_of_n<const N: usize>() {
let seq1 = EnumSet::<TestTag, N>::new(&[TestTag::Creature, TestTag::Villian, TestTag::Last]);
let seq2 = EnumSet::<TestTag, N>::new(&[TestTag::Creature, TestTag::Villian]);
let seq3 = EnumSet::<TestTag, N>::new(&[TestTag::Placeholder, TestTag::Last]);
assert_eq!(seq1.is_superset_of(&seq2), true);
assert_eq!(seq1.is_superset_of(&seq3), false);
}
test_is_subset_of_n::<2>();
test_is_subset_of_n::<4>();
test_is_subset_of_n::<8>();
test_is_superset_of_n::<2>();
test_is_superset_of_n::<4>();
test_is_superset_of_n::<8>();
}
#[test]
fn test_add() {
fn test_add_n<const N: usize>() {
let mut seq = EnumSet::<TestTag, N>::default();
seq.add(TestTag::Creature);
assert_eq!(seq.contains(TestTag::Creature), true);
}
test_add_n::<1>();
test_add_n::<2>();
test_add_n::<8>();
test_add_n::<16>();
}
fn test_remove_n<const N: usize>() {
let mut seq = EnumSet::<TestTag, N>::new(&[TestTag::Creature]);
seq.remove(TestTag::Creature);
assert_eq!(seq.contains(TestTag::Creature), false);
}
#[test]
fn test_remove() {
test_remove_n::<1>();
test_remove_n::<2>();
test_remove_n::<4>();
test_remove_n::<8>();
test_remove_n::<16>();
}
#[test]
fn test_has_any_of() {
fn test_has_any_of_n<const N: usize>() {
let seq1 = EnumSet::<TestTag, N>::new(&[TestTag::Creature, TestTag::Villian, TestTag::Last]);
let seq2 = EnumSet::<TestTag, N>::new(&[TestTag::Creature, TestTag::Villian]);
let seq3 = EnumSet::<TestTag, N>::new(&[TestTag::Placeholder, TestTag::Last]);
let seq4 = EnumSet::<TestTag, N>::new(&[TestTag::Placeholder]);
assert_eq!(seq1.has_any_of(&seq2), true);
assert_eq!(seq1.has_any_of(&seq3), true);
assert_eq!(seq1.has_any_of(&seq4), false);
}
test_has_any_of_n::<2>();
test_has_any_of_n::<4>();
test_has_any_of_n::<8>();
test_has_any_of_n::<16>();
}
#[test]
fn test_contains() {
fn test_contains_n<const N: usize>() {
let seq = EnumSet::<TestTag, N>::new(&[TestTag::Creature, TestTag::Villian]);
assert_eq!(seq.contains(TestTag::Creature), true);
assert_eq!(seq.contains(TestTag::Villian), true);
assert_eq!(seq.contains(TestTag::Placeholder), false);
}
test_contains_n::<1>();
test_contains_n::<2>();
test_contains_n::<4>();
test_contains_n::<8>();
test_contains_n::<16>();
}
#[test]
fn test_bitwise_operations() {
fn test_bitwise_operations_n<const N: usize>() {
let seq1 = EnumSet::<TestTag, N>::new(&[TestTag::Creature, TestTag::Villian]);
let mut seq2 = EnumSet::<TestTag, N>::default();
seq2.add(TestTag::Creature);
seq2.add(TestTag::Placeholder);
let intersection = &seq1 & &seq2;
let union = &seq1 | &seq2;
assert_eq!(intersection.contains(TestTag::Creature), true);
assert_eq!(intersection.contains(TestTag::Villian), false);
assert_eq!(intersection.contains(TestTag::Placeholder), false);
assert_eq!(union.contains(TestTag::Creature), true);
assert_eq!(union.contains(TestTag::Villian), true);
assert_eq!(union.contains(TestTag::Placeholder), true);
}
test_bitwise_operations_n::<2>();
test_bitwise_operations_n::<4>();
test_bitwise_operations_n::<8>();
test_bitwise_operations_n::<16>();
}
#[test]
fn test_add_many() {
fn test_add_many_n<const N: usize>() {
let tags = [TestTag::Placeholder, TestTag::Creature, TestTag::Villian, TestTag::Last];
let mut seq = EnumSet::<TestTag, N>::default();
seq.add_many(&tags);
for tag in tags.iter() {
assert_eq!(seq.contains(*tag), true);
}
}
test_add_many_n::<2>();
test_add_many_n::<4>();
test_add_many_n::<8>();
test_add_many_n::<16>();
}
#[test]
fn test_remove_many() {
fn test_remove_many_n<const N: usize>() {
let tags = [TestTag::Placeholder, TestTag::Creature, TestTag::Villian, TestTag::Last];
let mut seq = EnumSet::<TestTag, N>::default();
seq.add_many(&tags);
seq.remove_many(&tags);
for tag in tags.iter() {
assert_eq!(seq.contains(*tag), false);
}
}
test_remove_many_n::<2>();
test_remove_many_n::<4>();
test_remove_many_n::<8>();
test_remove_many_n::<16>();
}
#[test]
fn test_contains_many() {
fn test_contains_many_n<const N: usize>() {
let tags = [TestTag::Placeholder, TestTag::Creature, TestTag::Villian, TestTag::Last];
let seq = EnumSet::<TestTag, N>::new(&tags);
assert_eq!(seq.contains_many(&tags), true);
}
test_contains_many_n::<2>();
test_contains_many_n::<4>();
test_contains_many_n::<8>();
test_contains_many_n::<16>();
}
#[test]
fn test_bit_operations() {
fn test_bit_operations_n<const N: usize>() {
let tags1 = [TestTag::Placeholder, TestTag::Creature];
let tags2 = [TestTag::Creature, TestTag::Villian, TestTag::Last];
let seq1 = EnumSet::<TestTag, N>::new(&tags1);
let seq2 = EnumSet::<TestTag, N>::new(&tags2);
let intersection = &seq1 & &seq2;
let union = &seq1 | &seq2;
assert_eq!(intersection.contains(TestTag::Creature), true);
assert_eq!(intersection.contains(TestTag::Placeholder), false);
assert_eq!(intersection.contains(TestTag::Villian), false);
assert_eq!(intersection.contains(TestTag::Last), false);
assert_eq!(union.contains(TestTag::Creature), true);
assert_eq!(union.contains(TestTag::Placeholder), true);
assert_eq!(union.contains(TestTag::Villian), true);
assert_eq!(union.contains(TestTag::Last), true);
}
test_bit_operations_n::<2>();
test_bit_operations_n::<4>();
test_bit_operations_n::<8>();
test_bit_operations_n::<16>();
}
#[test]
fn test_bit_and() {
let seq1 = EnumSet::<TestTag, 2>::new(&[TestTag::Placeholder, TestTag::Creature]);
let seq2 = EnumSet::<TestTag, 2>::new(&[TestTag::Creature, TestTag::Villian]);
let intersection = seq1 & seq2;
assert_eq!(intersection.contains(TestTag::Creature), true);
assert_eq!(intersection.contains(TestTag::Placeholder), false);
assert_eq!(intersection.contains(TestTag::Villian), false);
}
#[test]
fn test_bit_or() {
let seq1 = EnumSet::<TestTag, 2>::new(&[TestTag::Placeholder, TestTag::Creature]);
let seq2 = EnumSet::<TestTag, 2>::new(&[TestTag::Creature, TestTag::Villian]);
let union = seq1 | seq2;
assert_eq!(union.contains(TestTag::Creature), true);
assert_eq!(union.contains(TestTag::Placeholder), true);
assert_eq!(union.contains(TestTag::Villian), true);
}
#[test]
fn test_empty() {
let seq = EnumSet::<TestTag, 2>::default();
assert_eq!(seq.contains(TestTag::Creature), false);
assert_eq!(seq.contains(TestTag::Placeholder), false);
assert_eq!(seq.contains(TestTag::Villian), false);
}
#[test]
fn test_add_all() {
let mut seq = EnumSet::<TestTag, 2>::default();
seq.add(TestTag::Placeholder);
seq.add(TestTag::Creature);
seq.add(TestTag::Villian);
assert_eq!(seq.contains(TestTag::Creature), true);
assert_eq!(seq.contains(TestTag::Placeholder), true);
assert_eq!(seq.contains(TestTag::Villian), true);
}
#[test]
fn test_boundary_conditions() {
fn test_boundary_conditions_n<const N: usize>() {
let seq = EnumSet::<TestTag, N>::new(&[TestTag::Placeholder, TestTag::Creature]);
let boundary_element = TestTag::Last;
let mut seq_boundary = EnumSet::<TestTag, 2>::default();
seq_boundary.add(boundary_element);
assert_eq!(seq.contains(TestTag::Placeholder), true);
assert_eq!(seq.contains(TestTag::Creature), true);
assert_eq!(seq.contains(boundary_element), false);
assert_eq!(seq_boundary.contains(boundary_element), true);
assert_eq!(seq_boundary.contains(TestTag::Creature), false);
assert_eq!(seq_boundary.contains(TestTag::Placeholder), false);
}
test_boundary_conditions_n::<2>();
test_boundary_conditions_n::<4>();
test_boundary_conditions_n::<8>();
test_boundary_conditions_n::<16>();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment