use core::panic;
use std::fmt;
use std::hash::BuildHasher;
use std::hash::Hash;
use std::hash::Hasher;
use std::ops::Deref;
use std::ops::Index;
use std::ops::IndexMut;
use hashbrown::Equivalent;
use hashbrown::HashSet;
use rustc_hash::FxBuildHasher;
use crate::GenerationCounter;
use crate::GenerationalIndex;
use crate::NoHasherBuilder;
#[repr(transparent)]
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Default)]
pub struct SetIndex(GenerationalIndex<usize>);
impl Deref for SetIndex {
type Target = usize;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl fmt::Debug for SetIndex {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "SetIndex({})", self.0)
}
}
impl fmt::Display for SetIndex {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}
pub struct IndexedSet<T, S = FxBuildHasher> {
table: Vec<IndexSetEntry<T>>,
index: HashSet<IndexEntry, NoHasherBuilder>,
free: Option<usize>,
generation_counter: GenerationCounter,
hasher: S,
}
enum IndexSetEntry<T> {
Filled(T),
Empty(usize),
}
impl<T, S: BuildHasher + Default> IndexedSet<T, S> {
pub fn new() -> IndexedSet<T, S> {
IndexedSet {
table: Vec::default(),
index: HashSet::with_hasher(NoHasherBuilder),
free: None,
generation_counter: GenerationCounter::new(),
hasher: S::default(),
}
}
}
impl<T, S> IndexedSet<T, S> {
pub fn with_hasher(hash_builder: S) -> IndexedSet<T, S> {
IndexedSet {
table: Vec::default(),
index: HashSet::with_hasher(NoHasherBuilder),
free: None,
generation_counter: GenerationCounter::new(),
hasher: hash_builder,
}
}
pub fn len(&self) -> usize {
self.table.len()
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn get(&self, index: SetIndex) -> Option<&T> {
if let Some(entry) = self.table.get(self.generation_counter.get_index(index.0)) {
match entry {
IndexSetEntry::Filled(element) => Some(element),
IndexSetEntry::Empty(_) => None,
}
} else {
None
}
}
pub fn capacity(&self) -> usize {
self.table.capacity()
}
pub fn iter(&self) -> Iter<'_, T, S> {
Iter {
reference: self,
index: 0,
generation_counter: &self.generation_counter,
}
}
}
impl<T: Clone, S> IndexedSet<T, S> {
pub fn to_vec(&self) -> Vec<T> {
self.iter().map(|(_, entry)| entry.clone()).collect()
}
}
impl<T: Hash + Eq, S: BuildHasher> IndexedSet<T, S> {
pub fn insert_equiv<'a, Q>(&mut self, value: &'a Q) -> (SetIndex, bool)
where
Q: Hash + Equivalent<T>,
T: From<&'a Q>,
{
let equivalent = IndexValueEquivalent::new(value, &self.hasher, &self.table);
if let Some(entry) = self.index.get(&equivalent) {
return (SetIndex(self.generation_counter.recall_index(entry.index)), false);
}
let value: T = value.into();
let hash = self.hasher.hash_one(&value);
debug_assert_eq!(hash, equivalent.hash(), "Hash values should be the same");
let index = match self.free {
Some(first) => {
let next = match self.table[first] {
IndexSetEntry::Empty(x) => x,
IndexSetEntry::Filled(_) => panic!("The free list contains a filled element"),
};
if first == next {
self.free = None;
} else {
self.free = Some(next);
}
self.table[first] = IndexSetEntry::Filled(value);
first
}
None => {
self.table.push(IndexSetEntry::Filled(value));
self.table.len() - 1
}
};
self.index.insert(IndexEntry::new(index, hash));
(SetIndex(self.generation_counter.create_index(index)), true)
}
pub fn insert(&mut self, value: T) -> (SetIndex, bool) {
let equivalent = IndexValueEquivalent::new(&value, &self.hasher, &self.table);
if let Some(entry) = self.index.get(&equivalent) {
return (SetIndex(self.generation_counter.recall_index(entry.index)), false);
}
let hash = equivalent.hash();
let index = match self.free {
Some(first) => {
let next = match self.table[first] {
IndexSetEntry::Empty(x) => x,
IndexSetEntry::Filled(_) => panic!("The free list contains a filled element"),
};
if first == next {
self.free = None;
} else {
self.free = Some(next);
}
self.table[first] = IndexSetEntry::Filled(value);
first
}
None => {
self.table.push(IndexSetEntry::Filled(value));
self.table.len() - 1
}
};
self.index.insert(IndexEntry::new(index, hash));
(SetIndex(self.generation_counter.create_index(index)), true)
}
pub fn index<Q>(&self, key: &Q) -> Option<SetIndex>
where
Q: Hash + Equivalent<T>,
{
let equivalent = IndexValueEquivalent::new(key, &self.hasher, &self.table);
self.index
.get(&equivalent)
.map(|entry| SetIndex(self.generation_counter.recall_index(entry.index)))
}
pub fn retain_mut<F>(&mut self, mut f: F)
where
F: FnMut(SetIndex, &mut T) -> bool,
{
for (index, element) in self.table.iter_mut().enumerate() {
if let IndexSetEntry::Filled(value) = element {
if !f(SetIndex(self.generation_counter.recall_index(index)), value) {
let entry_to_remove = self.index.iter().find(|entry| entry.index == index).cloned();
if let Some(entry) = entry_to_remove {
self.index.remove(&entry);
}
match self.free {
Some(next) => {
*element = IndexSetEntry::Empty(next);
}
None => {
*element = IndexSetEntry::Empty(index);
}
};
self.free = Some(index);
}
};
}
}
pub fn remove(&mut self, element: &T) -> bool {
let equivalent = IndexValueEquivalent::new(element, &self.hasher, &self.table);
if let Some(entry) = self.index.take(&equivalent) {
let next = match self.free {
Some(next) => next,
None => entry.index,
};
self.table[entry.index] = IndexSetEntry::Empty(next);
self.free = Some(entry.index);
true
} else {
false
}
}
pub fn contains<Q>(&self, element: &Q) -> bool
where
Q: Hash + Equivalent<T>,
{
let equivalent = IndexValueEquivalent::new(element, &self.hasher, &self.table);
self.index.contains(&equivalent)
}
}
impl<T, S> fmt::Debug for IndexedSet<T, S>
where
T: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_list().entries(self.iter()).finish()
}
}
impl<T, S: BuildHasher + Default> Default for IndexedSet<T, S> {
fn default() -> IndexedSet<T, S> {
IndexedSet::new()
}
}
impl<T, S> Index<SetIndex> for IndexedSet<T, S> {
type Output = T;
fn index(&self, index: SetIndex) -> &Self::Output {
cast!(&self.table[*index], IndexSetEntry::Filled)
}
}
impl<T, S: BuildHasher> IndexMut<SetIndex> for IndexedSet<T, S> {
fn index_mut(&mut self, index: SetIndex) -> &mut Self::Output {
cast!(&mut self.table[*index], IndexSetEntry::Filled)
}
}
#[derive(Copy, Clone, PartialEq, Eq)]
struct IndexEntry {
index: usize,
hash: u64,
}
impl IndexEntry {
fn new(index: usize, hash: u64) -> Self {
Self { index, hash }
}
}
impl Hash for IndexEntry {
fn hash<H: Hasher>(&self, state: &mut H) {
state.write_u64(self.hash);
}
}
struct IndexValueEquivalent<'a, T, Q> {
value: &'a Q,
hash: u64,
table: &'a Vec<IndexSetEntry<T>>,
}
impl<T, Q> IndexValueEquivalent<'_, T, Q> {
fn hash(&self) -> u64 {
self.hash
}
}
impl<'a, T, Q: Hash> IndexValueEquivalent<'a, T, Q> {
fn new<S: BuildHasher>(value: &'a Q, hasher: &S, table: &'a Vec<IndexSetEntry<T>>) -> Self {
Self {
value,
table,
hash: hasher.hash_one(value),
}
}
}
impl<T, Q: Equivalent<T>> Equivalent<IndexEntry> for IndexValueEquivalent<'_, T, Q> {
fn equivalent(&self, key: &IndexEntry) -> bool {
if let Some(IndexSetEntry::Filled(element)) = self.table.get(key.index) {
self.value.equivalent(element)
} else {
false
}
}
}
impl<T, Q> Hash for IndexValueEquivalent<'_, T, Q> {
fn hash<H: Hasher>(&self, state: &mut H) {
state.write_u64(self.hash);
}
}
pub struct Iter<'a, T, S> {
reference: &'a IndexedSet<T, S>,
index: usize,
generation_counter: &'a GenerationCounter,
}
impl<'a, T, S> Iterator for Iter<'a, T, S> {
type Item = (SetIndex, &'a T);
fn next(&mut self) -> Option<Self::Item> {
while self.index < self.reference.table.len() {
let current_index = self.index;
self.index += 1;
if let IndexSetEntry::Filled(element) = &self.reference.table[current_index] {
return Some((SetIndex(self.generation_counter.recall_index(current_index)), element));
}
}
None
}
}
impl<'a, T, S> IntoIterator for &'a IndexedSet<T, S> {
type Item = (SetIndex, &'a T);
type IntoIter = Iter<'a, T, S>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
#[cfg(test)]
mod tests {
use crate::random_test;
use super::*;
use rand::Rng;
use std::collections::HashMap;
#[test]
fn test_random_indexed_set_construction() {
random_test(100, |rng| {
let mut input = vec![];
for _ in 0..100 {
input.push(rng.random_range(0..32) as usize);
}
let mut indices: HashMap<usize, SetIndex> = HashMap::default();
let mut set: IndexedSet<usize> = IndexedSet::default();
for element in &input {
let index = set.insert(*element).0;
indices.insert(*element, index);
}
for (index, value) in &set {
assert_eq!(
indices[value], index,
"The resulting index does not match the returned value"
);
}
for value in &mut input.iter().take(10) {
set.remove(value);
indices.remove(value);
}
for (index, value) in &set {
assert_eq!(
indices[value], index,
"The resulting index does not match the returned value"
);
}
for (value, index) in &indices {
assert!(
set.get(*index) == Some(value),
"Index {} should still match element {:?}",
*index,
value
);
}
for value in &input {
let contains = indices.contains_key(value);
assert_eq!(
set.contains(value),
contains,
"The contains function returned an incorrect result for value {:?}",
value
);
}
})
}
}