use std::collections::HashSet;
use std::hash::BuildHasher;
use std::marker::PhantomData;
use rapidhash::RapidBuildHasher;
use sux::bits::bit_vec::BitVec;
use sux::traits::{BitVecOps, BitVecOpsMut};
const PROMOTION_THRESHOLD: usize = 64;
pub type NodeId = usize;
pub trait ReadNodeSet {
fn contains(&self, node: NodeId) -> bool;
}
pub trait NodeSet: ReadNodeSet {
fn insert(&mut self, node: NodeId);
}
pub struct EmptyNodeSet;
impl ReadNodeSet for EmptyNodeSet {
#[inline(always)]
fn contains(&self, _node: usize) -> bool {
false
}
}
impl IntoIterator for EmptyNodeSet {
type Item = NodeId;
type IntoIter = std::iter::Empty<NodeId>;
#[inline(always)]
fn into_iter(self) -> Self::IntoIter {
std::iter::empty()
}
}
impl<S: BuildHasher> NodeSet for HashSet<usize, S> {
#[inline(always)]
fn insert(&mut self, node: usize) {
HashSet::insert(self, node);
}
}
impl<S: BuildHasher> ReadNodeSet for HashSet<usize, S> {
#[inline(always)]
fn contains(&self, node: usize) -> bool {
HashSet::contains(self, &node)
}
}
impl NodeSet for BitVec {
#[inline(always)]
fn insert(&mut self, node: usize) {
self.set(node, true);
}
}
impl ReadNodeSet for BitVec {
#[inline(always)]
fn contains(&self, node: usize) -> bool {
self.get(node)
}
}
#[derive(Debug, PartialEq, Eq)]
pub struct SortedSlice<Item: Ord, S: AsRef<[Item]> + ?Sized> {
pub marker: PhantomData<Item>,
pub slice: S,
}
impl<Item: Ord, S: AsRef<[Item]>> SortedSlice<Item, S> {
pub fn new(slice: S) -> Self {
SortedSlice {
marker: PhantomData,
slice,
}
}
}
impl<S: AsRef<[NodeId]> + ?Sized> ReadNodeSet for SortedSlice<NodeId, S> {
#[inline(always)]
fn contains(&self, node: NodeId) -> bool {
self.slice.as_ref().binary_search(&node).is_ok()
}
}
impl<Item: Ord, S: AsRef<[Item]>> std::ops::Deref for SortedSlice<Item, S> {
type Target = S;
fn deref(&self) -> &Self::Target {
&self.slice
}
}
impl<'a, Item: Ord + Copy> IntoIterator for SortedSlice<Item, &'a [Item]> {
type Item = Item;
type IntoIter = std::iter::Copied<std::slice::Iter<'a, Item>>;
fn into_iter(self) -> Self::IntoIter {
self.slice.iter().copied()
}
}
impl<'a, Item: Ord, S: AsRef<[Item]>> From<&'a SortedSlice<Item, S>>
for SortedSlice<Item, &'a [Item]>
{
fn from(v: &'a SortedSlice<Item, S>) -> Self {
SortedSlice {
marker: PhantomData,
slice: v.slice.as_ref(),
}
}
}
#[derive(Debug)]
pub enum AdaptiveNodeSet {
Sparse {
max_items: usize,
data: HashSet<NodeId, RapidBuildHasher>,
},
Dense {
data: BitVec,
},
}
impl AdaptiveNodeSet {
#[inline(always)]
pub fn new(max_items: usize) -> Self {
AdaptiveNodeSet::Sparse {
max_items,
data: HashSet::with_hasher(RapidBuildHasher::default()),
}
}
#[inline(always)]
pub fn with_capacity(max_items: usize, capacity: usize) -> Self {
if capacity > max_items / PROMOTION_THRESHOLD {
AdaptiveNodeSet::Dense {
data: BitVec::new(max_items),
}
} else {
AdaptiveNodeSet::Sparse {
max_items,
data: HashSet::with_capacity_and_hasher(capacity, RapidBuildHasher::default()),
}
}
}
}
impl NodeSet for AdaptiveNodeSet {
#[inline(always)]
fn insert(&mut self, node: usize) {
match self {
AdaptiveNodeSet::Sparse { max_items, data } => {
data.insert(node);
if data.len() > *max_items / PROMOTION_THRESHOLD {
let mut new_data = BitVec::new(*max_items);
for node in data.iter() {
new_data.insert(*node);
}
*self = AdaptiveNodeSet::Dense { data: new_data };
}
}
AdaptiveNodeSet::Dense { data } => data.insert(node),
}
}
}
impl ReadNodeSet for AdaptiveNodeSet {
#[inline(always)]
fn contains(&self, node: usize) -> bool {
match self {
AdaptiveNodeSet::Sparse { max_items: _, data } => data.contains(&node),
AdaptiveNodeSet::Dense { data } => data.contains(node),
}
}
}