use std::borrow::Borrow;
use std::collections::hash_map::RandomState;
use std::collections::{self, BTreeSet};
use std::fmt::{Debug, Error, Formatter};
use std::hash::{BuildHasher, Hash};
use std::iter::{FromIterator, FusedIterator, Sum};
use std::ops::{Add, Deref, Mul};
use archery::{SharedPointer, SharedPointerKind};
use crate::nodes::hamt::{hash_key, Drain as NodeDrain, HashValue, Iter as NodeIter, Node};
use crate::ordset::GenericOrdSet;
use crate::shared_ptr::DefaultSharedPtr;
use crate::GenericVector;
#[macro_export]
macro_rules! hashset {
() => { $crate::hashset::HashSet::new() };
( $($x:expr),* ) => {{
let mut l = $crate::hashset::HashSet::new();
$(
l.insert($x);
)*
l
}};
( $($x:expr ,)* ) => {{
let mut l = $crate::hashset::HashSet::new();
$(
l.insert($x);
)*
l
}};
}
pub type HashSet<A> = GenericHashSet<A, RandomState, DefaultSharedPtr>;
pub struct GenericHashSet<A, S, P: SharedPointerKind> {
hasher: S,
root: Option<SharedPointer<Node<Value<A>, P>, P>>,
size: usize,
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
struct Value<A>(A);
impl<A> Deref for Value<A> {
type Target = A;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<A> HashValue for Value<A>
where
A: Hash + Eq,
{
type Key = A;
fn extract_key(&self) -> &Self::Key {
&self.0
}
fn ptr_eq(&self, _other: &Self) -> bool {
false
}
}
impl<A, S, P> GenericHashSet<A, S, P>
where
A: Hash + Eq + Clone,
S: BuildHasher + Default + Clone,
P: SharedPointerKind,
{
#[inline]
#[must_use]
pub fn unit(a: A) -> Self {
GenericHashSet::new().update(a)
}
}
impl<A, S, P: SharedPointerKind> GenericHashSet<A, S, P> {
#[must_use]
pub fn new() -> Self
where
S: Default,
{
Self::default()
}
#[inline]
#[must_use]
pub fn is_empty(&self) -> bool {
self.len() == 0
}
#[inline]
#[must_use]
pub fn len(&self) -> usize {
self.size
}
pub fn ptr_eq(&self, other: &Self) -> bool {
match (&self.root, &other.root) {
(Some(a), Some(b)) => SharedPointer::ptr_eq(a, b),
(None, None) => true,
_ => false,
}
}
#[inline]
#[must_use]
pub fn with_hasher(hasher: S) -> Self {
GenericHashSet {
size: 0,
root: None,
hasher,
}
}
#[must_use]
pub fn hasher(&self) -> &S {
&self.hasher
}
#[inline]
#[must_use]
pub fn new_from<A2>(&self) -> GenericHashSet<A2, S, P>
where
A2: Hash + Eq + Clone,
S: Clone,
{
GenericHashSet {
size: 0,
root: None,
hasher: self.hasher.clone(),
}
}
pub fn clear(&mut self) {
self.root = None;
self.size = 0;
}
#[must_use]
pub fn iter(&self) -> Iter<'_, A, P> {
Iter {
it: NodeIter::new(self.root.as_deref(), self.size),
}
}
}
impl<A, S, P> GenericHashSet<A, S, P>
where
A: Hash + Eq,
S: BuildHasher,
P: SharedPointerKind,
{
fn test_eq<S2: BuildHasher, P2: SharedPointerKind>(
&self,
other: &GenericHashSet<A, S2, P2>,
) -> bool {
if self.len() != other.len() {
return false;
}
let mut seen = collections::HashSet::new();
for value in self.iter() {
if !other.contains(value) {
return false;
}
seen.insert(value);
}
for value in other.iter() {
if !seen.contains(&value) {
return false;
}
}
true
}
#[must_use]
pub fn contains<BA>(&self, a: &BA) -> bool
where
BA: Hash + Eq + ?Sized,
A: Borrow<BA>,
{
if let Some(root) = &self.root {
root.get(hash_key(&self.hasher, a), 0, a).is_some()
} else {
false
}
}
#[must_use]
pub fn is_subset<RS>(&self, other: RS) -> bool
where
RS: Borrow<Self>,
{
let o = other.borrow();
self.iter().all(|a| o.contains(a))
}
#[must_use]
pub fn is_proper_subset<RS>(&self, other: RS) -> bool
where
RS: Borrow<Self>,
{
self.len() != other.borrow().len() && self.is_subset(other)
}
}
impl<A, S, P> GenericHashSet<A, S, P>
where
A: Hash + Eq + Clone,
S: BuildHasher + Clone,
P: SharedPointerKind,
{
#[inline]
pub fn insert(&mut self, a: A) -> Option<A> {
let hash = hash_key(&self.hasher, &a);
let root = SharedPointer::make_mut(self.root.get_or_insert_with(Default::default));
match root.insert(hash, 0, Value(a)) {
None => {
self.size += 1;
None
}
Some(Value(old_value)) => Some(old_value),
}
}
pub fn remove<BA>(&mut self, a: &BA) -> Option<A>
where
BA: Hash + Eq + ?Sized,
A: Borrow<BA>,
{
let root = SharedPointer::make_mut(self.root.get_or_insert_with(Default::default));
let result = root.remove(hash_key(&self.hasher, a), 0, a);
if result.is_some() {
self.size -= 1;
}
result.map(|v| v.0)
}
#[must_use]
pub fn update(&self, a: A) -> Self {
let mut out = self.clone();
out.insert(a);
out
}
#[must_use]
pub fn without<BA>(&self, a: &BA) -> Self
where
BA: Hash + Eq + ?Sized,
A: Borrow<BA>,
{
let mut out = self.clone();
out.remove(a);
out
}
pub fn retain<F>(&mut self, mut f: F)
where
F: FnMut(&A) -> bool,
{
let Some(root) = &mut self.root else {
return;
};
let old_root = root.clone();
let root = SharedPointer::make_mut(root);
for (value, hash) in NodeIter::new(Some(&old_root), self.size) {
if !f(value) && root.remove(hash, 0, value).is_some() {
self.size -= 1;
}
}
}
#[must_use]
pub fn union(self, other: Self) -> Self {
let (mut to_mutate, to_consume) = if self.len() >= other.len() {
(self, other)
} else {
(other, self)
};
for value in to_consume {
to_mutate.insert(value);
}
to_mutate
}
#[must_use]
pub fn unions<I>(i: I) -> Self
where
I: IntoIterator<Item = Self>,
S: Default,
{
i.into_iter().fold(Self::default(), Self::union)
}
#[deprecated(
since = "2.0.1",
note = "to avoid conflicting behaviors between std and imbl, the `difference` alias for `symmetric_difference` will be removed."
)]
#[must_use]
pub fn difference(self, other: Self) -> Self {
self.symmetric_difference(other)
}
#[must_use]
pub fn symmetric_difference(mut self, other: Self) -> Self {
for value in other {
if self.remove(&value).is_none() {
self.insert(value);
}
}
self
}
#[must_use]
pub fn relative_complement(mut self, other: Self) -> Self {
for value in other {
let _ = self.remove(&value);
}
self
}
#[must_use]
pub fn intersection(self, other: Self) -> Self {
let mut out = self.new_from();
for value in other {
if self.contains(&value) {
out.insert(value);
}
}
out
}
}
impl<A, S, P: SharedPointerKind> Clone for GenericHashSet<A, S, P>
where
A: Clone,
S: Clone,
P: SharedPointerKind,
{
#[inline]
fn clone(&self) -> Self {
GenericHashSet {
hasher: self.hasher.clone(),
root: self.root.clone(),
size: self.size,
}
}
}
impl<A, S1, P1, S2, P2> PartialEq<GenericHashSet<A, S2, P2>> for GenericHashSet<A, S1, P1>
where
A: Hash + Eq,
S1: BuildHasher,
S2: BuildHasher,
P1: SharedPointerKind,
P2: SharedPointerKind,
{
fn eq(&self, other: &GenericHashSet<A, S2, P2>) -> bool {
self.test_eq(other)
}
}
impl<A, S, P> Eq for GenericHashSet<A, S, P>
where
A: Hash + Eq,
S: BuildHasher,
P: SharedPointerKind,
{
}
impl<A, S, P> Default for GenericHashSet<A, S, P>
where
S: Default,
P: SharedPointerKind,
{
fn default() -> Self {
GenericHashSet {
hasher: Default::default(),
root: None,
size: 0,
}
}
}
impl<A, S, P> Add for GenericHashSet<A, S, P>
where
A: Hash + Eq + Clone,
S: BuildHasher + Clone,
P: SharedPointerKind,
{
type Output = GenericHashSet<A, S, P>;
fn add(self, other: Self) -> Self::Output {
self.union(other)
}
}
impl<A, S, P> Mul for GenericHashSet<A, S, P>
where
A: Hash + Eq + Clone,
S: BuildHasher + Clone,
P: SharedPointerKind,
{
type Output = GenericHashSet<A, S, P>;
fn mul(self, other: Self) -> Self::Output {
self.intersection(other)
}
}
impl<A, S, P> Add for &GenericHashSet<A, S, P>
where
A: Hash + Eq + Clone,
S: BuildHasher + Clone,
P: SharedPointerKind,
{
type Output = GenericHashSet<A, S, P>;
fn add(self, other: Self) -> Self::Output {
self.clone().union(other.clone())
}
}
impl<A, S, P> Mul for &GenericHashSet<A, S, P>
where
A: Hash + Eq + Clone,
S: BuildHasher + Clone,
P: SharedPointerKind,
{
type Output = GenericHashSet<A, S, P>;
fn mul(self, other: Self) -> Self::Output {
self.clone().intersection(other.clone())
}
}
impl<A, S, P: SharedPointerKind> Sum for GenericHashSet<A, S, P>
where
A: Hash + Eq + Clone,
S: BuildHasher + Default + Clone,
P: SharedPointerKind,
{
fn sum<I>(it: I) -> Self
where
I: Iterator<Item = Self>,
{
it.fold(Self::default(), |a, b| a + b)
}
}
impl<A, S, R, P: SharedPointerKind> Extend<R> for GenericHashSet<A, S, P>
where
A: Hash + Eq + Clone + From<R>,
S: BuildHasher + Clone,
{
fn extend<I>(&mut self, iter: I)
where
I: IntoIterator<Item = R>,
{
for value in iter {
self.insert(From::from(value));
}
}
}
impl<A, S, P> Debug for GenericHashSet<A, S, P>
where
A: Hash + Eq + Debug,
S: BuildHasher,
P: SharedPointerKind,
{
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
f.debug_set().entries(self.iter()).finish()
}
}
pub struct Iter<'a, A, P: SharedPointerKind> {
it: NodeIter<'a, Value<A>, P>,
}
impl<'a, A, P: SharedPointerKind> Clone for Iter<'a, A, P> {
fn clone(&self) -> Self {
Iter {
it: self.it.clone(),
}
}
}
impl<'a, A, P> Iterator for Iter<'a, A, P>
where
A: 'a,
P: SharedPointerKind,
{
type Item = &'a A;
fn next(&mut self) -> Option<Self::Item> {
self.it.next().map(|(v, _)| &v.0)
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.it.size_hint()
}
}
impl<'a, A, P: SharedPointerKind> ExactSizeIterator for Iter<'a, A, P> {}
impl<'a, A, P: SharedPointerKind> FusedIterator for Iter<'a, A, P> {}
pub struct ConsumingIter<A, P>
where
A: Hash + Eq + Clone,
P: SharedPointerKind,
{
it: NodeDrain<Value<A>, P>,
}
impl<A, P> Iterator for ConsumingIter<A, P>
where
A: Hash + Eq + Clone,
P: SharedPointerKind,
{
type Item = A;
fn next(&mut self) -> Option<Self::Item> {
self.it.next().map(|(v, _)| v.0)
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.it.size_hint()
}
}
impl<A, P> ExactSizeIterator for ConsumingIter<A, P>
where
A: Hash + Eq + Clone,
P: SharedPointerKind,
{
}
impl<A, P> FusedIterator for ConsumingIter<A, P>
where
A: Hash + Eq + Clone,
P: SharedPointerKind,
{
}
impl<A, RA, S, P> FromIterator<RA> for GenericHashSet<A, S, P>
where
A: Hash + Eq + Clone + From<RA>,
S: BuildHasher + Default + Clone,
P: SharedPointerKind,
{
fn from_iter<T>(i: T) -> Self
where
T: IntoIterator<Item = RA>,
{
let mut set = Self::default();
for value in i {
set.insert(From::from(value));
}
set
}
}
impl<'a, A, S, P> IntoIterator for &'a GenericHashSet<A, S, P>
where
A: Hash + Eq,
S: BuildHasher,
P: SharedPointerKind,
{
type Item = &'a A;
type IntoIter = Iter<'a, A, P>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl<A, S, P> IntoIterator for GenericHashSet<A, S, P>
where
A: Hash + Eq + Clone,
S: BuildHasher,
P: SharedPointerKind,
{
type Item = A;
type IntoIter = ConsumingIter<Self::Item, P>;
fn into_iter(self) -> Self::IntoIter {
ConsumingIter {
it: NodeDrain::new(self.root, self.size),
}
}
}
impl<A, OA, SA, SB, P1, P2> From<&GenericHashSet<&A, SA, P1>> for GenericHashSet<OA, SB, P2>
where
A: ToOwned<Owned = OA> + Hash + Eq + ?Sized,
OA: Borrow<A> + Hash + Eq + Clone,
SA: BuildHasher,
SB: BuildHasher + Default + Clone,
P1: SharedPointerKind,
P2: SharedPointerKind,
{
fn from(set: &GenericHashSet<&A, SA, P1>) -> Self {
set.iter().map(|a| (*a).to_owned()).collect()
}
}
impl<A, S, const N: usize, P> From<[A; N]> for GenericHashSet<A, S, P>
where
A: Hash + Eq + Clone,
S: BuildHasher + Default + Clone,
P: SharedPointerKind,
{
fn from(arr: [A; N]) -> Self {
IntoIterator::into_iter(arr).collect()
}
}
impl<'a, A, S, P> From<&'a [A]> for GenericHashSet<A, S, P>
where
A: Hash + Eq + Clone,
S: BuildHasher + Default + Clone,
P: SharedPointerKind,
{
fn from(slice: &'a [A]) -> Self {
slice.iter().cloned().collect()
}
}
impl<A, S, P> From<Vec<A>> for GenericHashSet<A, S, P>
where
A: Hash + Eq + Clone,
S: BuildHasher + Default + Clone,
P: SharedPointerKind,
{
fn from(vec: Vec<A>) -> Self {
vec.into_iter().collect()
}
}
impl<A, S, P> From<&Vec<A>> for GenericHashSet<A, S, P>
where
A: Hash + Eq + Clone,
S: BuildHasher + Default + Clone,
P: SharedPointerKind,
{
fn from(vec: &Vec<A>) -> Self {
vec.iter().cloned().collect()
}
}
impl<A, S, P1, P2> From<GenericVector<A, P2>> for GenericHashSet<A, S, P1>
where
A: Hash + Eq + Clone,
S: BuildHasher + Default + Clone,
P1: SharedPointerKind,
P2: SharedPointerKind,
{
fn from(vector: GenericVector<A, P2>) -> Self {
vector.into_iter().collect()
}
}
impl<A, S, P1, P2> From<&GenericVector<A, P2>> for GenericHashSet<A, S, P1>
where
A: Hash + Eq + Clone,
S: BuildHasher + Default + Clone,
P1: SharedPointerKind,
P2: SharedPointerKind,
{
fn from(vector: &GenericVector<A, P2>) -> Self {
vector.iter().cloned().collect()
}
}
impl<A, S, P> From<collections::HashSet<A>> for GenericHashSet<A, S, P>
where
A: Eq + Hash + Clone,
S: BuildHasher + Default + Clone,
P: SharedPointerKind,
{
fn from(hash_set: collections::HashSet<A>) -> Self {
hash_set.into_iter().collect()
}
}
impl<A, S, P> From<&collections::HashSet<A>> for GenericHashSet<A, S, P>
where
A: Eq + Hash + Clone,
S: BuildHasher + Default + Clone,
P: SharedPointerKind,
{
fn from(hash_set: &collections::HashSet<A>) -> Self {
hash_set.iter().cloned().collect()
}
}
impl<A, S, P> From<&BTreeSet<A>> for GenericHashSet<A, S, P>
where
A: Hash + Eq + Clone,
S: BuildHasher + Default + Clone,
P: SharedPointerKind,
{
fn from(btree_set: &BTreeSet<A>) -> Self {
btree_set.iter().cloned().collect()
}
}
impl<A, S, P1, P2> From<GenericOrdSet<A, P2>> for GenericHashSet<A, S, P1>
where
A: Ord + Hash + Eq + Clone,
S: BuildHasher + Default + Clone,
P1: SharedPointerKind,
P2: SharedPointerKind,
{
fn from(ordset: GenericOrdSet<A, P2>) -> Self {
ordset.into_iter().collect()
}
}
impl<A, S, P1, P2> From<&GenericOrdSet<A, P2>> for GenericHashSet<A, S, P1>
where
A: Ord + Hash + Eq + Clone,
S: BuildHasher + Default + Clone,
P1: SharedPointerKind,
P2: SharedPointerKind,
{
fn from(ordset: &GenericOrdSet<A, P2>) -> Self {
ordset.into_iter().cloned().collect()
}
}
#[cfg(any(test, feature = "proptest"))]
#[doc(hidden)]
pub mod proptest {
#[deprecated(
since = "14.3.0",
note = "proptest strategies have moved to imbl::proptest"
)]
pub use crate::proptest::hash_set;
}
#[cfg(test)]
mod test {
use super::proptest::*;
use super::*;
use crate::test::LolHasher;
use ::proptest::num::i16;
use ::proptest::proptest;
use static_assertions::{assert_impl_all, assert_not_impl_any};
use std::hash::BuildHasherDefault;
assert_impl_all!(HashSet<i32>: Send, Sync);
assert_not_impl_any!(HashSet<*const i32>: Send, Sync);
assert_covariant!(HashSet<T> in T);
#[test]
fn insert_failing() {
let mut set: GenericHashSet<i16, BuildHasherDefault<LolHasher>, DefaultSharedPtr> =
Default::default();
set.insert(14658);
assert_eq!(1, set.len());
set.insert(-19198);
assert_eq!(2, set.len());
}
#[test]
fn match_strings_with_string_slices() {
let mut set: HashSet<String> = From::from(&hashset!["foo", "bar"]);
set = set.without("bar");
assert!(!set.contains("bar"));
set.remove("foo");
assert!(!set.contains("foo"));
}
#[test]
fn macro_allows_trailing_comma() {
let set1 = hashset! {"foo", "bar"};
let set2 = hashset! {
"foo",
"bar",
};
assert_eq!(set1, set2);
}
#[test]
fn issue_60_drain_iterator_memory_corruption() {
use crate::test::MetroHashBuilder;
for i in 0..1000 {
let mut lhs = vec![0, 1, 2];
lhs.sort_unstable();
let hasher = MetroHashBuilder::new(i);
let mut iset: GenericHashSet<_, MetroHashBuilder, DefaultSharedPtr> =
GenericHashSet::with_hasher(hasher);
for &i in &lhs {
iset.insert(i);
}
let mut rhs: Vec<_> = iset.clone().into_iter().collect();
rhs.sort_unstable();
if lhs != rhs {
println!("iteration: {}", i);
println!("seed: {}", hasher.seed());
println!("lhs: {}: {:?}", lhs.len(), &lhs);
println!("rhs: {}: {:?}", rhs.len(), &rhs);
panic!();
}
}
}
proptest! {
#[test]
fn proptest_a_set(ref s in hash_set(".*", 10..100)) {
assert!(s.len() < 100);
assert!(s.len() >= 10);
}
}
}