use std::borrow::Borrow;
use std::cmp::Ordering;
use std::collections::hash_map::RandomState;
use std::collections::{self, BTreeSet};
use std::fmt::{Debug, Error, Formatter};
use std::hash::{BuildHasher, Hash, Hasher};
use std::iter::FusedIterator;
use std::iter::{FromIterator, IntoIterator, Sum};
use std::ops::{Add, Deref, Mul};
use crate::nodes::hamt::{
    hash_key, Drain as NodeDrain, HashValue, Iter as NodeIter, IterMut as NodeIterMut, Node,
};
use crate::ordset::OrdSet;
use crate::util::Ref;
#[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 struct HashSet<A, S = RandomState> {
    hasher: Ref<S>,
    root: Ref<Node<Value<A>>>,
    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> HashSet<A, RandomState> {
    
    #[must_use]
    pub fn new() -> Self {
        Self::default()
    }
}
impl<A> HashSet<A, RandomState>
where
    A: Hash + Eq + Clone,
{
    
    
    
    
    
    #[inline]
    #[must_use]
    #[deprecated(since = "12.3.0", note = "renamed to `unit` for consistency")]
    pub fn singleton(a: A) -> Self {
        Self::unit(a)
    }
    
    
    
    
    
    
    
    
    
    
    
    
    
    #[inline]
    #[must_use]
    pub fn unit(a: A) -> Self {
        HashSet::new().update(a)
    }
}
impl<A, S> HashSet<A, S> {
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    #[inline]
    #[must_use]
    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }
    
    
    
    
    
    
    
    
    
    
    
    
    
    #[inline]
    #[must_use]
    pub fn len(&self) -> usize {
        self.size
    }
    
    #[inline]
    #[must_use]
    pub fn with_hasher<RS>(hasher: RS) -> Self
    where
        Ref<S>: From<RS>,
    {
        HashSet {
            size: 0,
            root: Ref::new(Node::new()),
            hasher: From::from(hasher),
        }
    }
    
    
    
    #[must_use]
    pub fn hasher(&self) -> &Ref<S> {
        &self.hasher
    }
    
    #[inline]
    #[must_use]
    pub fn new_from<A1>(&self) -> HashSet<A1, S>
    where
        A1: Hash + Eq + Clone,
    {
        HashSet {
            size: 0,
            root: Ref::new(Node::new()),
            hasher: self.hasher.clone(),
        }
    }
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    pub fn clear(&mut self) {
        if !self.is_empty() {
            self.root = Default::default();
            self.size = 0;
        }
    }
    
    
    
    
    
    
    
    #[must_use]
    pub fn iter(&self) -> Iter<'_, A> {
        Iter {
            it: NodeIter::new(&self.root, self.size),
        }
    }
}
impl<A, S> HashSet<A, S>
where
    A: Hash + Eq,
    S: BuildHasher,
{
    fn test_eq(&self, other: &Self) -> 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>,
    {
        self.root.get(hash_key(&*self.hasher, a), 0, a).is_some()
    }
    
    
    
    
    #[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> HashSet<A, S>
where
    A: Hash + Eq + Clone,
    S: BuildHasher,
{
    
    
    
    
    
    
    #[must_use]
    pub fn iter_mut(&mut self) -> IterMut<'_, A> {
        let root = Ref::make_mut(&mut self.root);
        IterMut {
            it: NodeIterMut::new(root, self.size),
        }
    }
    
    
    
    #[inline]
    pub fn insert(&mut self, a: A) -> Option<A> {
        let hash = hash_key(&*self.hasher, &a);
        let root = Ref::make_mut(&mut self.root);
        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 = Ref::make_mut(&mut self.root);
        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 old_root = self.root.clone();
        let root = Ref::make_mut(&mut self.root);
        for (value, hash) in NodeIter::new(&old_root, self.size) {
            if !f(value) && root.remove(hash, 0, value).is_some() {
                self.size -= 1;
            }
        }
    }
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    #[must_use]
    pub fn union(mut self, other: Self) -> Self {
        for value in other {
            self.insert(value);
        }
        self
    }
    
    
    
    #[must_use]
    pub fn unions<I>(i: I) -> Self
    where
        I: IntoIterator<Item = Self>,
        S: Default,
    {
        i.into_iter().fold(Self::default(), Self::union)
    }
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    #[must_use]
    pub fn difference(mut self, other: Self) -> Self {
        for value in other {
            if self.remove(&value).is_none() {
                self.insert(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> Clone for HashSet<A, S>
where
    A: Clone,
{
    fn clone(&self) -> Self {
        HashSet {
            hasher: self.hasher.clone(),
            root: self.root.clone(),
            size: self.size,
        }
    }
}
impl<A, S> PartialEq for HashSet<A, S>
where
    A: Hash + Eq,
    S: BuildHasher + Default,
{
    fn eq(&self, other: &Self) -> bool {
        self.test_eq(other)
    }
}
impl<A, S> Eq for HashSet<A, S>
where
    A: Hash + Eq,
    S: BuildHasher + Default,
{
}
impl<A, S> PartialOrd for HashSet<A, S>
where
    A: Hash + Eq + Clone + PartialOrd,
    S: BuildHasher + Default,
{
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        if Ref::ptr_eq(&self.hasher, &other.hasher) {
            return self.iter().partial_cmp(other.iter());
        }
        let m1: ::std::collections::HashSet<A> = self.iter().cloned().collect();
        let m2: ::std::collections::HashSet<A> = other.iter().cloned().collect();
        m1.iter().partial_cmp(m2.iter())
    }
}
impl<A, S> Ord for HashSet<A, S>
where
    A: Hash + Eq + Clone + Ord,
    S: BuildHasher + Default,
{
    fn cmp(&self, other: &Self) -> Ordering {
        if Ref::ptr_eq(&self.hasher, &other.hasher) {
            return self.iter().cmp(other.iter());
        }
        let m1: ::std::collections::HashSet<A> = self.iter().cloned().collect();
        let m2: ::std::collections::HashSet<A> = other.iter().cloned().collect();
        m1.iter().cmp(m2.iter())
    }
}
impl<A, S> Hash for HashSet<A, S>
where
    A: Hash + Eq,
    S: BuildHasher + Default,
{
    fn hash<H>(&self, state: &mut H)
    where
        H: Hasher,
    {
        for i in self.iter() {
            i.hash(state);
        }
    }
}
impl<A, S> Default for HashSet<A, S>
where
    S: BuildHasher + Default,
{
    fn default() -> Self {
        HashSet {
            hasher: Ref::<S>::default(),
            root: Ref::new(Node::new()),
            size: 0,
        }
    }
}
impl<A, S> Add for HashSet<A, S>
where
    A: Hash + Eq + Clone,
    S: BuildHasher,
{
    type Output = HashSet<A, S>;
    fn add(self, other: Self) -> Self::Output {
        self.union(other)
    }
}
impl<A, S> Mul for HashSet<A, S>
where
    A: Hash + Eq + Clone,
    S: BuildHasher,
{
    type Output = HashSet<A, S>;
    fn mul(self, other: Self) -> Self::Output {
        self.intersection(other)
    }
}
impl<'a, A, S> Add for &'a HashSet<A, S>
where
    A: Hash + Eq + Clone,
    S: BuildHasher,
{
    type Output = HashSet<A, S>;
    fn add(self, other: Self) -> Self::Output {
        self.clone().union(other.clone())
    }
}
impl<'a, A, S> Mul for &'a HashSet<A, S>
where
    A: Hash + Eq + Clone,
    S: BuildHasher,
{
    type Output = HashSet<A, S>;
    fn mul(self, other: Self) -> Self::Output {
        self.clone().intersection(other.clone())
    }
}
impl<A, S> Sum for HashSet<A, S>
where
    A: Hash + Eq + Clone,
    S: BuildHasher + Default,
{
    fn sum<I>(it: I) -> Self
    where
        I: Iterator<Item = Self>,
    {
        it.fold(Self::default(), |a, b| a + b)
    }
}
impl<A, S, R> Extend<R> for HashSet<A, S>
where
    A: Hash + Eq + Clone + From<R>,
    S: BuildHasher,
{
    fn extend<I>(&mut self, iter: I)
    where
        I: IntoIterator<Item = R>,
    {
        for value in iter {
            self.insert(From::from(value));
        }
    }
}
#[cfg(not(has_specialisation))]
impl<A, S> Debug for HashSet<A, S>
where
    A: Hash + Eq + Debug,
    S: BuildHasher,
{
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        f.debug_set().entries(self.iter()).finish()
    }
}
#[cfg(has_specialisation)]
impl<A, S> Debug for HashSet<A, S>
where
    A: Hash + Eq + Debug,
    S: BuildHasher,
{
    default fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        f.debug_set().entries(self.iter()).finish()
    }
}
#[cfg(has_specialisation)]
impl<A, S> Debug for HashSet<A, S>
where
    A: Hash + Eq + Debug + Ord,
    S: BuildHasher,
{
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        f.debug_set().entries(self.iter()).finish()
    }
}
pub struct Iter<'a, A>
where
    A: 'a,
{
    it: NodeIter<'a, Value<A>>,
}
impl<'a, A> Iterator for Iter<'a, A>
where
    A: 'a,
{
    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> ExactSizeIterator for Iter<'a, A> {}
impl<'a, A> FusedIterator for Iter<'a, A> {}
pub struct IterMut<'a, A>
where
    A: 'a,
{
    it: NodeIterMut<'a, Value<A>>,
}
impl<'a, A> Iterator for IterMut<'a, A>
where
    A: 'a + Clone,
{
    type Item = &'a mut A;
    fn next(&mut self) -> Option<Self::Item> {
        self.it.next().map(|(v, _)| &mut v.0)
    }
    fn size_hint(&self) -> (usize, Option<usize>) {
        self.it.size_hint()
    }
}
impl<'a, A> ExactSizeIterator for IterMut<'a, A> where A: Clone {}
impl<'a, A> FusedIterator for IterMut<'a, A> where A: Clone {}
pub struct ConsumingIter<A>
where
    A: Hash + Eq + Clone,
{
    it: NodeDrain<Value<A>>,
}
impl<A> Iterator for ConsumingIter<A>
where
    A: Hash + Eq + Clone,
{
    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> ExactSizeIterator for ConsumingIter<A> where A: Hash + Eq + Clone {}
impl<A> FusedIterator for ConsumingIter<A> where A: Hash + Eq + Clone {}
impl<A, RA, S> FromIterator<RA> for HashSet<A, S>
where
    A: Hash + Eq + Clone + From<RA>,
    S: BuildHasher + Default,
{
    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> IntoIterator for &'a HashSet<A, S>
where
    A: Hash + Eq,
    S: BuildHasher,
{
    type Item = &'a A;
    type IntoIter = Iter<'a, A>;
    fn into_iter(self) -> Self::IntoIter {
        self.iter()
    }
}
impl<A, S> IntoIterator for HashSet<A, S>
where
    A: Hash + Eq + Clone,
    S: BuildHasher,
{
    type Item = A;
    type IntoIter = ConsumingIter<Self::Item>;
    fn into_iter(self) -> Self::IntoIter {
        ConsumingIter {
            it: NodeDrain::new(self.root, self.size),
        }
    }
}
impl<'s, 'a, A, OA, SA, SB> From<&'s HashSet<&'a A, SA>> for HashSet<OA, SB>
where
    A: ToOwned<Owned = OA> + Hash + Eq + ?Sized,
    OA: Borrow<A> + Hash + Eq + Clone,
    SA: BuildHasher,
    SB: BuildHasher + Default,
{
    fn from(set: &HashSet<&A, SA>) -> Self {
        set.iter().map(|a| (*a).to_owned()).collect()
    }
}
impl<'a, A, S> From<&'a [A]> for HashSet<A, S>
where
    A: Hash + Eq + Clone,
    S: BuildHasher + Default,
{
    fn from(slice: &'a [A]) -> Self {
        slice.iter().cloned().collect()
    }
}
impl<A, S> From<Vec<A>> for HashSet<A, S>
where
    A: Hash + Eq + Clone,
    S: BuildHasher + Default,
{
    fn from(vec: Vec<A>) -> Self {
        vec.into_iter().collect()
    }
}
impl<'a, A, S> From<&'a Vec<A>> for HashSet<A, S>
where
    A: Hash + Eq + Clone,
    S: BuildHasher + Default,
{
    fn from(vec: &Vec<A>) -> Self {
        vec.iter().cloned().collect()
    }
}
impl<A, S> From<collections::HashSet<A>> for HashSet<A, S>
where
    A: Eq + Hash + Clone,
    S: BuildHasher + Default,
{
    fn from(hash_set: collections::HashSet<A>) -> Self {
        hash_set.into_iter().collect()
    }
}
impl<'a, A, S> From<&'a collections::HashSet<A>> for HashSet<A, S>
where
    A: Eq + Hash + Clone,
    S: BuildHasher + Default,
{
    fn from(hash_set: &collections::HashSet<A>) -> Self {
        hash_set.iter().cloned().collect()
    }
}
impl<'a, A, S> From<&'a BTreeSet<A>> for HashSet<A, S>
where
    A: Hash + Eq + Clone,
    S: BuildHasher + Default,
{
    fn from(btree_set: &BTreeSet<A>) -> Self {
        btree_set.iter().cloned().collect()
    }
}
impl<A, S> From<OrdSet<A>> for HashSet<A, S>
where
    A: Ord + Hash + Eq + Clone,
    S: BuildHasher + Default,
{
    fn from(ordset: OrdSet<A>) -> Self {
        ordset.into_iter().collect()
    }
}
impl<'a, A, S> From<&'a OrdSet<A>> for HashSet<A, S>
where
    A: Ord + Hash + Eq + Clone,
    S: BuildHasher + Default,
{
    fn from(ordset: &OrdSet<A>) -> Self {
        ordset.into_iter().cloned().collect()
    }
}
#[cfg(all(threadsafe, feature = "quickcheck"))]
use quickcheck::{Arbitrary, Gen};
#[cfg(all(threadsafe, feature = "quickcheck"))]
impl<A, S> Arbitrary for HashSet<A, S>
where
    A: Hash + Eq + Arbitrary + Sync,
    S: BuildHasher + Default + Send + Sync + 'static,
{
    fn arbitrary<G: Gen>(g: &mut G) -> Self {
        HashSet::from_iter(Vec::<A>::arbitrary(g))
    }
}
#[cfg(any(test, feature = "proptest"))]
pub mod proptest {
    use super::*;
    use ::proptest::strategy::{BoxedStrategy, Strategy, ValueTree};
    use std::ops::Range;
    
    
    
    
    
    
    
    
    
    
    
    
    
    pub fn hash_set<A: Strategy + 'static>(
        element: A,
        size: Range<usize>,
    ) -> BoxedStrategy<HashSet<<A::Tree as ValueTree>::Value>>
    where
        <A::Tree as ValueTree>::Value: Hash + Eq + Clone,
    {
        ::proptest::collection::vec(element, size.clone())
            .prop_map(HashSet::from)
            .prop_filter("HashSet minimum size".to_owned(), move |s| {
                s.len() >= size.start
            })
            .boxed()
    }
}
#[cfg(test)]
mod test {
    use super::proptest::*;
    use super::*;
    use crate::test::LolHasher;
    use ::proptest::num::i16;
    use ::proptest::proptest;
    use std::hash::BuildHasherDefault;
    #[test]
    fn insert_failing() {
        let mut set: HashSet<i16, BuildHasherDefault<LolHasher>> = 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();
            let hasher = Ref::from(MetroHashBuilder::new(i));
            let mut iset: HashSet<_, MetroHashBuilder> = HashSet::with_hasher(hasher.clone());
            for &i in &lhs {
                iset.insert(i);
            }
            let mut rhs: Vec<_> = iset.clone().into_iter().collect();
            rhs.sort();
            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);
        }
    }
}