use std::simd::{LaneCount, Simd, SupportedLaneCount};
use crate::data::TeamSeed;
#[derive(Clone, Copy, PartialEq)]
pub struct TeamSet {
data: u16,
}
impl TeamSet {
#[inline(always)]
pub const fn new() -> Self {
Self { data: 0 }
}
#[inline(always)]
pub const fn full() -> Self {
Self { data: u16::MAX }
}
#[inline(always)]
pub fn insert(&mut self, index: TeamSeed) -> bool {
let old = self.data;
self.data |= 1 << index;
old != self.data
}
#[inline(always)]
pub fn remove(&mut self, index: &TeamSeed) -> bool {
let old = self.data;
self.data &= !(1 << index);
old != self.data
}
#[inline(always)]
pub fn contains(&self, index: &TeamSeed) -> bool {
(self.data & (1 << index)) != 0
}
#[inline(always)]
pub fn is_empty(&self) -> bool {
self.data == 0
}
#[inline(always)]
pub fn iter(&self) -> TeamSetIter {
TeamSetIter { set: *self }
}
#[inline(always)]
pub fn splat<const N: usize>(&self) -> Simd<u16, N>
where
LaneCount<N>: SupportedLaneCount,
{
Simd::splat(self.data)
}
}
impl std::fmt::Debug for TeamSet {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_set().entries(self.iter()).finish()
}
}
impl<const N: usize> From<[TeamSeed; N]> for TeamSet {
fn from(seeds: [TeamSeed; N]) -> Self {
let mut set = Self::new();
for seed in seeds {
set.insert(seed);
}
set
}
}
pub struct TeamSetIter {
set: TeamSet,
}
impl Iterator for TeamSetIter {
type Item = TeamSeed;
#[inline(always)]
fn next(&mut self) -> Option<Self::Item> {
if self.set.is_empty() {
None
} else {
let next = self.set.data.trailing_zeros() as TeamSeed;
self.set.data &= self.set.data - 1;
Some(next)
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn compare_std_hashset() {
use std::collections::HashSet;
let samples = [
vec![0, 1, 2, 3],
vec![15, 14, 13, 12],
vec![0, 2, 4, 6, 8, 10, 12, 14],
vec![1, 3, 5, 7, 9, 11, 13, 15],
vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
];
for sample in samples {
let mut reference = HashSet::new();
let mut set = TeamSet::new();
assert_eq!(set.is_empty(), reference.is_empty());
for i in &sample {
assert_eq!(set.insert(*i), reference.insert(*i));
}
for i in 0..16 {
assert_eq!(set.contains(&i), reference.contains(&i));
}
assert_eq!(set.iter().collect::<HashSet<_>>(), reference);
assert_eq!(set.is_empty(), reference.is_empty());
for i in &sample {
assert_eq!(set.remove(i), reference.remove(i));
}
for i in 0..16 {
assert_eq!(set.contains(&i), reference.contains(&i));
}
assert_eq!(set.is_empty(), reference.is_empty());
}
}
}