use crate::{AbstractVecSet, VecSet};
use core::{
fmt,
fmt::{Debug, Write},
hash::Hash,
mem,
ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Not, Sub, SubAssign},
};
#[cfg(feature = "serde")]
use serde::{
de::{Deserialize, Deserializer},
ser::{Serialize, Serializer},
};
use smallvec::Array;
pub struct TotalVecSet<A: Array> {
elements: VecSet<A>,
negated: bool,
}
pub type TotalVecSet2<T> = TotalVecSet<[T; 2]>;
#[cfg(feature = "serde")]
impl<A: Array> Serialize for TotalVecSet<A>
where
A::Item: Serialize,
{
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
(&self.elements, &self.negated).serialize(serializer)
}
}
#[cfg(feature = "serde")]
impl<'de, A: Array> Deserialize<'de> for TotalVecSet<A>
where
A::Item: Deserialize<'de> + Ord + PartialEq + Clone,
{
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
let (elements, negated) = <(VecSet<A>, bool)>::deserialize(deserializer)?;
Ok(Self::new(elements, negated))
}
}
impl<T: Clone, A: Array<Item = T>> Clone for TotalVecSet<A> {
fn clone(&self) -> Self {
Self {
elements: self.elements.clone(),
negated: self.negated,
}
}
}
impl<T: Hash, A: Array<Item = T>> Hash for TotalVecSet<A> {
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
self.elements.hash(state);
self.negated.hash(state);
}
}
impl<T: PartialEq, A: Array<Item = T>> PartialEq for TotalVecSet<A> {
fn eq(&self, other: &Self) -> bool {
self.elements == other.elements && self.negated == other.negated
}
}
impl<T: Eq, A: Array<Item = T>> Eq for TotalVecSet<A> {}
impl<T: Debug, A: Array<Item = T>> Debug for TotalVecSet<A> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.negated {
f.write_char('!')?;
}
f.debug_set().entries(self.elements.iter()).finish()
}
}
impl<T, A: Array<Item = T>> TotalVecSet<A> {
fn new(elements: VecSet<A>, negated: bool) -> Self {
Self { elements, negated }
}
pub fn is_empty(&self) -> bool {
!self.negated && self.elements.is_empty()
}
pub fn is_all(&self) -> bool {
self.negated && self.elements.is_empty()
}
pub fn constant(value: bool) -> Self {
Self::new(VecSet::empty(), value)
}
pub fn empty() -> Self {
false.into()
}
pub fn all() -> Self {
true.into()
}
pub fn shrink_to_fit(&mut self) {
self.elements.shrink_to_fit()
}
}
impl<T, A: Array<Item = T>> From<bool> for TotalVecSet<A> {
fn from(value: bool) -> Self {
Self::constant(value)
}
}
impl<T, A: Array<Item = T>> From<VecSet<A>> for TotalVecSet<A> {
fn from(value: VecSet<A>) -> Self {
Self::new(value, false)
}
}
impl<T: Ord, A: Array<Item = T>> TotalVecSet<A> {
pub fn contains(&self, value: &T) -> bool {
self.negated ^ self.elements.contains(value)
}
pub fn insert(&mut self, that: T) {
if !self.negated {
self.elements.insert(that);
} else {
self.elements.remove(&that);
}
}
pub fn is_superset(&self, that: &Self) -> bool {
!self.is_subset(that)
}
pub fn is_subset(&self, that: &Self) -> bool {
match (self.negated, that.negated) {
(false, false) => self.elements.is_subset(&that.elements),
(false, true) => self.elements.is_disjoint(&that.elements),
(true, false) => false,
(true, true) => self.elements.is_superset(&that.elements),
}
}
pub fn is_disjoint(&self, that: &Self) -> bool {
match (self.negated, that.negated) {
(false, false) => self.elements.is_disjoint(&that.elements),
(false, true) => self.elements.is_subset(&that.elements),
(true, false) => self.elements.is_superset(&that.elements),
(true, true) => false,
}
}
}
impl<T: Ord + Clone, A: Array<Item = T>> TotalVecSet<A> {
pub fn remove(&mut self, that: &T) {
if self.negated {
self.elements.insert(that.clone());
} else {
self.elements.remove(that);
}
}
}
impl<T: Ord + Clone, A: Array<Item = T>> BitAnd for &TotalVecSet<A> {
type Output = TotalVecSet<A>;
fn bitand(self, that: Self) -> Self::Output {
match (self.negated, that.negated) {
(false, false) => Self::Output::new(&self.elements & &that.elements, false),
(false, true) => Self::Output::new(&self.elements - &that.elements, false),
(true, false) => Self::Output::new(&that.elements - &self.elements, false),
(true, true) => Self::Output::new(&that.elements | &self.elements, true),
}
}
}
impl<T: Ord, A: Array<Item = T>> BitAndAssign for TotalVecSet<A> {
fn bitand_assign(&mut self, that: Self) {
match (self.negated, that.negated) {
(false, false) => {
self.elements &= that.elements;
self.negated = false;
}
(false, true) => {
self.elements -= that.elements;
self.negated = false;
}
(true, false) => {
let mut that = that;
mem::swap(&mut that.elements, &mut self.elements);
self.elements -= that.elements;
self.negated = false;
}
(true, true) => {
self.elements |= that.elements;
self.negated = true;
}
};
}
}
impl<T: Ord + Clone, A: Array<Item = T>> BitOr for &TotalVecSet<A> {
type Output = TotalVecSet<A>;
fn bitor(self, that: Self) -> Self::Output {
match (self.negated, that.negated) {
(false, false) => Self::Output::new(&self.elements | &that.elements, false),
(false, true) => Self::Output::new(&that.elements - &self.elements, true),
(true, false) => Self::Output::new(&self.elements - &that.elements, true),
(true, true) => Self::Output::new(&that.elements & &self.elements, true),
}
}
}
impl<T: Ord, A: Array<Item = T>> BitOrAssign for TotalVecSet<A> {
fn bitor_assign(&mut self, that: Self) {
match (self.negated, that.negated) {
(false, false) => {
self.elements |= that.elements;
self.negated = false;
}
(false, true) => {
let mut that = that;
mem::swap(&mut that.elements, &mut self.elements);
self.elements -= that.elements;
self.negated = true;
}
(true, false) => {
self.elements -= that.elements;
self.negated = true;
}
(true, true) => {
self.elements &= that.elements;
self.negated = true;
}
};
}
}
impl<T: Ord + Clone, A: Array<Item = T>> BitXor for &TotalVecSet<A> {
type Output = TotalVecSet<A>;
fn bitxor(self, that: Self) -> Self::Output {
Self::Output::new(&self.elements ^ &that.elements, self.negated ^ that.negated)
}
}
impl<T: Ord, A: Array<Item = T>> BitXorAssign for TotalVecSet<A> {
fn bitxor_assign(&mut self, that: Self) {
self.elements ^= that.elements;
self.negated ^= that.negated;
}
}
#[allow(clippy::suspicious_arithmetic_impl)]
impl<T: Ord + Clone, A: Array<Item = T>> Sub for &TotalVecSet<A> {
type Output = TotalVecSet<A>;
fn sub(self, that: Self) -> Self::Output {
match (self.negated, that.negated) {
(false, false) => Self::Output::new(&self.elements - &that.elements, false),
(false, true) => Self::Output::new(&self.elements & &that.elements, false),
(true, false) => Self::Output::new(&self.elements | &that.elements, true),
(true, true) => Self::Output::new(&that.elements - &self.elements, false),
}
}
}
impl<T: Ord, A: Array<Item = T>> SubAssign for TotalVecSet<A> {
fn sub_assign(&mut self, that: Self) {
match (self.negated, that.negated) {
(false, false) => {
self.elements -= that.elements;
self.negated = false;
}
(false, true) => {
self.elements &= that.elements;
self.negated = false;
}
(true, false) => {
self.elements |= that.elements;
self.negated = true;
}
(true, true) => {
let mut that = that;
mem::swap(&mut that.elements, &mut self.elements);
self.elements -= that.elements;
self.negated = false;
}
}
}
}
impl<T: Ord + Clone, A: Array<Item = T>> Not for &TotalVecSet<A> {
type Output = TotalVecSet<A>;
fn not(self) -> Self::Output {
Self::Output::new(self.elements.clone(), !self.negated)
}
}
impl<T: Ord, A: Array<Item = T>> Not for TotalVecSet<A> {
type Output = TotalVecSet<A>;
fn not(self) -> Self::Output {
Self::Output::new(self.elements, !self.negated)
}
}
#[cfg(test)]
mod tests {
#![allow(dead_code)]
use super::*;
use obey::*;
use quickcheck::*;
use std::collections::BTreeSet;
type Test = TotalVecSet<[i64; 2]>;
impl<T: Arbitrary + Ord + Copy + Default + Debug> Arbitrary for TotalVecSet<[T; 2]> {
fn arbitrary<G: Gen>(g: &mut G) -> Self {
let mut elements: Vec<T> = Arbitrary::arbitrary(g);
elements.truncate(2);
let negated: bool = Arbitrary::arbitrary(g);
TotalVecSet::new(elements.into(), negated)
}
}
fn print_on_failure_unary<E: Debug, R: Eq + Debug>(x: E, expected: R, actual: R) -> bool {
let res = expected == actual;
if !res {
println!("x:{:?} expected:{:?}Â actual:{:?}", x, expected, actual);
}
res
}
fn binary_op(a: &Test, b: &Test, r: &Test, op: impl Fn(bool, bool) -> bool) -> bool {
let mut samples: BTreeSet<i64> = BTreeSet::new();
samples.extend(a.elements.as_ref().iter().cloned());
samples.extend(b.elements.as_ref().iter().cloned());
samples.insert(core::i64::MIN);
samples.iter().all(|e| {
let expected = op(a.contains(e), b.contains(e));
let actual = r.contains(e);
if expected != actual {
println!(
"{:?}!={:?} at {:?} {:?} {:?} {:?}",
expected, actual, e, a, b, r
);
}
expected == actual
})
}
fn binary_property(a: &Test, b: &Test, r: bool, op: impl Fn(bool, bool) -> bool) -> bool {
let mut samples: BTreeSet<i64> = BTreeSet::new();
samples.extend(a.elements.as_ref().iter().cloned());
samples.extend(b.elements.as_ref().iter().cloned());
samples.insert(core::i64::MIN);
if r {
samples.iter().all(|e| {
let expected = op(a.contains(e), b.contains(e));
if !expected {
println!(
"{:?} is false at {:?}\na {:?}\nb {:?}\nr {:?}",
expected, e, a, b, r
);
}
expected
})
} else {
samples.iter().any(|e| !op(a.contains(e), b.contains(e)))
}
}
quickcheck! {
#[cfg(feature = "serde")]
fn serde_roundtrip(reference: Test) -> bool {
let bytes = serde_json::to_vec(&reference).unwrap();
let deser = serde_json::from_slice(&bytes).unwrap();
reference == deser
}
fn is_disjoint_sample(a: Test, b: Test) -> bool {
binary_property(&a, &b, a.is_disjoint(&b), |a, b| !(a & b))
}
fn is_subset_sample(a: Test, b: Test) -> bool {
binary_property(&a, &b, a.is_subset(&b), |a, b| !a | b)
}
fn union_sample(a: Test, b: Test) -> bool {
binary_op(&a, &b, &(&a | &b), |a, b| a | b)
}
fn intersection_sample(a: Test, b: Test) -> bool {
binary_op(&a, &b, &(&a & &b), |a, b| a & b)
}
fn xor_sample(a: Test, b: Test) -> bool {
binary_op(&a, &b, &(&a ^ &b), |a, b| a ^ b)
}
fn diff_sample(a: Test, b: Test) -> bool {
binary_op(&a, &b, &(&a - &b), |a, b| a & !b)
}
}
bitop_assign_consistent!(Test);
bitop_symmetry!(Test);
bitop_empty!(Test);
bitop_sub_not_all!(Test);
}