Skip to content

Commit

Permalink
feat(variadics): add variadic hash set
Browse files Browse the repository at this point in the history
  • Loading branch information
MingweiSamuel authored and jhellerstein committed Sep 16, 2024
1 parent f8ff17f commit 775e367
Show file tree
Hide file tree
Showing 4 changed files with 123 additions and 2 deletions.
43 changes: 43 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion variadics/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ documentation = "https://docs.rs/variadics/"
description = "Variadic generics on stable Rust using tuple lists"

[dependencies]
sealed = "0.5"
sealed = "0.5.0"
hashbrown = "0.14.0"

[dev-dependencies]
trybuild = "1.0"
75 changes: 75 additions & 0 deletions variadics/src/hash_set.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
use std::hash::{BuildHasher, Hash, Hasher, RandomState};

use hashbrown::hash_table::{Entry, HashTable};

use crate::{PartialEqVariadic, VariadicExt};

pub struct VariadicHashSet<T, S = RandomState> {
table: HashTable<T>,
hasher: S,
}
impl<T> VariadicHashSet<T> {
pub fn new() -> Self {
Self {
table: HashTable::new(),
hasher: RandomState::default(),
}
}
}
impl<T, S> VariadicHashSet<T, S>
where
T: VariadicExt + PartialEqVariadic,
for<'a> T::AsRefVar<'a>: Hash,
S: BuildHasher,
{
fn get_hash(hasher: &S, ref_var: T::AsRefVar<'_>) -> u64 {
let mut hasher = hasher.build_hasher();
ref_var.hash(&mut hasher);
hasher.finish()
}

pub fn get<'a>(&'a self, ref_var: T::AsRefVar<'_>) -> Option<&'a T> {
let hash = Self::get_hash(&self.hasher, ref_var);
self.table.find(hash, |item| {
<T as PartialEqVariadic>::eq_ref(ref_var, item.as_ref_var())
})
}

pub fn insert(&mut self, element: T) -> bool {
let hash = Self::get_hash(&self.hasher, element.as_ref_var());
let entry = self.table.entry(
hash,
|item| <T as PartialEqVariadic>::eq(&element, &item),
|item| Self::get_hash(&self.hasher, item.as_ref_var()),
);
match entry {
Entry::Occupied(_occupied_entry) => false,
Entry::Vacant(vacant_entry) => {
vacant_entry.insert(element);
true
}
}
}

pub fn len(&self) -> usize {
self.table.len()
}

pub fn iter<'a>(&'a self) -> impl Iterator<Item = T::AsRefVar<'a>> {
self.table.iter().map(|item| item.as_ref_var())
}
}
impl<T, S> VariadicHashSet<T, S> {
pub fn with_hasher(hasher: S) -> Self {
Self {
table: HashTable::new(),
hasher,
}
}
pub fn with_capacity_and_hasher(capacity: usize, hasher: S) -> Self {
Self {
table: HashTable::with_capacity(capacity),
hasher,
}
}
}
4 changes: 3 additions & 1 deletion variadics/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
//! ## [`var_args!`]
#![doc = include_str!("../var_args.md")]

pub mod hash_set;

use std::any::Any;

use sealed::sealed;
Expand Down Expand Up @@ -545,7 +547,7 @@ impl CloneVariadic for () {
fn clone_var_ref(_this: Self::AsRefVar<'_>) -> Self {}
}

/// A variadic where all item implement `PartialEq`.
/// A variadic where all item implement [`PartialEq`].
#[sealed]
pub trait PartialEqVariadic: VariadicExt {
/// `PartialEq` between a referenced variadic and a variadic of references, of the same types.
Expand Down

0 comments on commit 775e367

Please sign in to comment.