use bitvec::prelude::*;
use std::collections::{HashMap, HashSet};
use std::hash::{Hash, Hasher};
use std::iter::Iterator;
use std::ptr;
use std::rc::Rc;
#[derive(PartialEq, Eq, Clone, Debug)]
pub struct AttributeSet<T>
where
T: Hash + Eq,
{
indexes: HashMap<T, usize>,
}
impl<T: Hash + Eq> AttributeSet<T> {
pub fn from_capacity<U>(set: U, capacity: usize) -> Rc<Self>
where
U: IntoIterator<Item = T>,
{
let mut hashset = HashSet::<T>::with_capacity(capacity);
set.into_iter().for_each(|item| {
hashset.insert(item);
});
let mut indexes = HashMap::<T, usize>::with_capacity(hashset.len());
hashset.into_iter().enumerate().for_each(|(i, val)| {
indexes.insert(val, i);
});
Rc::new(Self { indexes })
}
pub fn from<U>(set: U) -> Rc<Self>
where
U: IntoIterator<Item = T>,
{
Self::from_capacity(set, 0)
}
pub fn len(&self) -> usize {
self.indexes.len()
}
pub fn is_empty(&self) -> bool {
self.indexes.is_empty()
}
pub fn contains(&self, value: &T) -> bool {
self.indexes.contains_key(value)
}
pub fn empty_subset(self: &Rc<Self>) -> AttributeSubset<T> {
AttributeSubset::<T>::from(self)
}
pub fn subset_with<U>(self: &Rc<Self>, items: U) -> AttributeSubset<T>
where
U: IntoIterator<Item = T>,
{
let mut subset = self.empty_subset();
for item in items {
subset.try_insert(&item).ok();
}
subset
}
pub fn subset_from<'a, U>(self: &Rc<Self>, items: U) -> AttributeSubset<T>
where
U: Iterator<Item = &'a T>,
T: 'a,
{
let mut subset = self.empty_subset();
for item in items {
subset.try_insert(&item).ok();
}
subset
}
pub fn iter(&self) -> impl Iterator<Item = &T> {
self.indexes.keys()
}
fn index_of(&self, value: &T) -> Option<&usize> {
self.indexes.get(value)
}
fn map_iter(&self) -> impl Iterator<Item = (&T, &usize)> {
self.indexes.iter()
}
}
pub struct AttributeSubset<T>
where
T: Hash + Eq,
{
parent: Rc<AttributeSet<T>>,
items: BitVec,
}
impl<T> PartialEq for AttributeSubset<T>
where
T: Hash + Eq,
{
fn eq(&self, other: &Self) -> bool {
Rc::ptr_eq(&self.parent, &other.parent) && self.items == other.items
}
}
impl<T> Eq for AttributeSubset<T> where T: Hash + Eq {}
impl<T> Hash for AttributeSubset<T>
where
T: Hash + Eq,
{
fn hash<H: Hasher>(&self, state: &mut H) {
ptr::hash(Rc::as_ptr(&self.parent), state);
self.items.hash(state);
}
}
impl<T> AttributeSubset<T>
where
T: Hash + Eq,
{
pub(self) fn from(set: &Rc<AttributeSet<T>>) -> Self {
let items = BitVec::repeat(false, set.len());
Self {
parent: set.clone(),
items,
}
}
pub fn try_insert(&mut self, item: &T) -> Result<(), &'static str> {
let index = self.parent.index_of(item);
match index {
Some(index) => {
*self.items.get_mut(*index).unwrap() = true;
Ok(())
}
None => Err("Could not add the item -- it was not part of the parent set"),
}
}
pub fn remove(&mut self, item: &T) {
let index = self.parent.index_of(item);
if let Some(index) = index {
*self.items.get_mut(*index).unwrap() = false;
}
}
pub fn contains(&self, item: &T) -> bool {
let index = self.parent.index_of(item);
match index {
Some(index) => *self.items.get(*index).unwrap(),
None => false,
}
}
pub fn clear(&mut self) {
self.items.set_all(false);
}
pub fn items(&self) -> impl Iterator<Item = &T> {
let items = &self.items;
self.parent
.map_iter()
.filter(move |(_item, i)| *items.get(**i).unwrap())
.map(|(item, _i)| item)
}
pub fn copy_from(&mut self, other: &AttributeSubset<T>) -> Result<(), &'static str> {
if !Rc::ptr_eq(&self.parent, &other.parent) {
return Err("The AttributeSubset does not spawn from the same parent set!");
}
self.items.copy_from_bitslice(&other.items);
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn duplicates() {
let vec_set = vec![5, 5, 5, 5, 2, 4];
let size = vec_set.len();
let set = AttributeSet::<i32>::from_capacity(vec_set, size);
assert_eq!(*set.map_iter().map(|(_num, index)| index).max().unwrap(), 2);
}
}