use std::cmp::Ordering::{self, *};
use std::collections::{HashMap, HashSet};
use std::fmt::Debug;
use cc_traits::{Get, Iter, Len, Remove};
use crate::cc_traits::{GetMut, Keyed, Map, MapIter, SimpleKeyedRef};
use crate::collections::{EmptyMap, EmptySet, SingletonMap, SingletonSet};
use crate::{IsBot, IsTop, LatticeFrom, LatticeOrd, Merge};
#[derive(Copy, Clone, Debug, Default)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct MapUnionWithTombstones<Map, TombstoneSet> {
map: Map,
tombstones: TombstoneSet,
}
impl<Map, TombstoneSet> MapUnionWithTombstones<Map, TombstoneSet> {
pub fn new(map: Map, tombstones: TombstoneSet) -> Self {
Self { map, tombstones }
}
pub fn new_from(map: impl Into<Map>, tombstones: impl Into<TombstoneSet>) -> Self {
Self::new(map.into(), tombstones.into())
}
pub fn as_reveal_ref(&self) -> (&Map, &TombstoneSet) {
(&self.map, &self.tombstones)
}
pub fn as_reveal_mut(&mut self) -> (&mut Map, &mut TombstoneSet) {
(&mut self.map, &mut self.tombstones)
}
pub fn into_reveal(self) -> (Map, TombstoneSet) {
(self.map, self.tombstones)
}
}
impl<MapSelf, MapOther, K, ValSelf, ValOther, TombstoneSetSelf, TombstoneSetOther>
Merge<MapUnionWithTombstones<MapOther, TombstoneSetOther>>
for MapUnionWithTombstones<MapSelf, TombstoneSetSelf>
where
MapSelf: Keyed<Key = K, Item = ValSelf>
+ Extend<(K, ValSelf)>
+ for<'a> GetMut<&'a K, Item = ValSelf>
+ for<'b> Remove<&'b K>,
MapOther: IntoIterator<Item = (K, ValOther)>,
ValSelf: Merge<ValOther> + LatticeFrom<ValOther>,
ValOther: IsBot,
TombstoneSetSelf: Extend<K> + Len + for<'a> Get<&'a K> + Iter<Item = K>,
TombstoneSetOther: IntoIterator<Item = K>,
{
fn merge(&mut self, other: MapUnionWithTombstones<MapOther, TombstoneSetOther>) -> bool {
let mut changed = false;
let iter: Vec<_> = other
.map
.into_iter()
.filter(|(k_other, val_other)| {
!val_other.is_bot() && !self.tombstones.contains(k_other)
})
.filter_map(|(k_other, val_other)| {
match self.map.get_mut(&k_other) {
Some(mut val_self) => {
changed |= val_self.merge(val_other);
None
}
None => {
changed = true;
Some((k_other, ValSelf::lattice_from(val_other)))
}
}
})
.collect();
self.map.extend(iter);
let old_self_tombstones_len = self.tombstones.len();
self.tombstones
.extend(other.tombstones.into_iter().inspect(|k| {
self.map.remove(k);
}));
if old_self_tombstones_len != self.tombstones.len() {
changed = true;
}
changed
}
}
impl<MapSelf, MapOther, K, ValSelf, ValOther, TombstoneSetSelf, TombstoneSetOther>
LatticeFrom<MapUnionWithTombstones<MapOther, TombstoneSetOther>>
for MapUnionWithTombstones<MapSelf, TombstoneSetSelf>
where
MapSelf: Keyed<Key = K, Item = ValSelf> + FromIterator<(K, ValSelf)>,
MapOther: IntoIterator<Item = (K, ValOther)>,
ValSelf: LatticeFrom<ValOther>,
TombstoneSetSelf: FromIterator<K>,
TombstoneSetOther: IntoIterator<Item = K>,
{
fn lattice_from(other: MapUnionWithTombstones<MapOther, TombstoneSetOther>) -> Self {
Self {
map: other
.map
.into_iter()
.map(|(k_other, val_other)| (k_other, LatticeFrom::lattice_from(val_other)))
.collect(),
tombstones: other.tombstones.into_iter().collect(),
}
}
}
impl<MapSelf, MapOther, K, ValSelf, ValOther, TombstoneSetSelf, TombstoneSetOther>
PartialOrd<MapUnionWithTombstones<MapOther, TombstoneSetOther>>
for MapUnionWithTombstones<MapSelf, TombstoneSetSelf>
where
MapSelf: Map<K, ValSelf, Key = K, Item = ValSelf> + MapIter + SimpleKeyedRef,
MapOther: Map<K, ValOther, Key = K, Item = ValOther> + MapIter + SimpleKeyedRef,
ValSelf: PartialOrd<ValOther> + IsBot,
ValOther: IsBot,
TombstoneSetSelf: Len + Iter<Item = K> + for<'a> Get<&'a K>,
TombstoneSetOther: Len + Iter<Item = K> + for<'a> Get<&'a K>,
{
fn partial_cmp(
&self,
other: &MapUnionWithTombstones<MapOther, TombstoneSetOther>,
) -> Option<Ordering> {
let self_tombstones_greater = self
.tombstones
.iter()
.any(|k| !other.tombstones.contains(&*k));
let other_tombstones_greater = other
.tombstones
.iter()
.any(|k| !self.tombstones.contains(&*k));
if self_tombstones_greater && other_tombstones_greater {
return None;
}
let mut self_any_greater = false;
let mut other_any_greater = false;
let self_keys = self
.map
.iter()
.filter(|(k, v)| {
!v.is_bot() && !self.tombstones.contains(k) && !other.tombstones.contains(k)
})
.map(|(k, _v)| <MapSelf as SimpleKeyedRef>::into_ref(k));
let other_keys = other
.map
.iter()
.filter(|(k, v)| {
!v.is_bot() && !self.tombstones.contains(k) && !other.tombstones.contains(k)
})
.map(|(k, _v)| <MapOther as SimpleKeyedRef>::into_ref(k));
for k in self_keys.chain(other_keys) {
match (self.map.get(k), other.map.get(k)) {
(Some(self_value), Some(other_value)) => {
match self_value.partial_cmp(&*other_value)? {
Less => {
other_any_greater = true;
}
Greater => {
self_any_greater = true;
}
Equal => {}
}
}
(Some(_), None) => {
self_any_greater = true;
}
(None, Some(_)) => {
other_any_greater = true;
}
(None, None) => unreachable!(),
}
if self_any_greater && other_any_greater {
return None;
}
}
match (
self_any_greater,
other_any_greater,
self_tombstones_greater,
other_tombstones_greater,
) {
(false, false, false, false) => Some(Equal),
(false, false, true, false) => Some(Greater),
(false, false, false, true) => Some(Less),
(true, false, false, false) => Some(Greater),
(false, true, false, false) => Some(Less),
(true, false, true, false) => Some(Greater),
(false, true, false, true) => Some(Less),
(true, false, false, true) => None,
(false, true, true, false) => None,
(true, true, _, _) => unreachable!(),
(_, _, true, true) => unreachable!(),
}
}
}
impl<MapSelf, MapOther, TombstoneSetSelf, TombstoneSetOther>
LatticeOrd<MapUnionWithTombstones<MapOther, TombstoneSetOther>>
for MapUnionWithTombstones<MapSelf, TombstoneSetSelf>
where
Self: PartialOrd<MapUnionWithTombstones<MapOther, TombstoneSetOther>>,
{
}
impl<MapSelf, MapOther, K, ValSelf, ValOther, TombstoneSetSelf, TombstoneSetOther>
PartialEq<MapUnionWithTombstones<MapOther, TombstoneSetOther>>
for MapUnionWithTombstones<MapSelf, TombstoneSetSelf>
where
MapSelf: Map<K, ValSelf, Key = K, Item = ValSelf> + MapIter + SimpleKeyedRef,
MapOther: Map<K, ValOther, Key = K, Item = ValOther> + MapIter + SimpleKeyedRef,
ValSelf: PartialEq<ValOther> + IsBot,
ValOther: IsBot,
TombstoneSetSelf: Len + Iter<Item = K> + for<'a> Get<&'a K>,
TombstoneSetOther: Len + Iter<Item = K> + for<'b> Get<&'b K>,
{
fn eq(&self, other: &MapUnionWithTombstones<MapOther, TombstoneSetOther>) -> bool {
if self.tombstones.len() != other.tombstones.len() {
return false;
}
if self
.tombstones
.iter()
.any(|k| !other.tombstones.contains(&*k))
{
return false;
}
if other
.tombstones
.iter()
.any(|k| !self.tombstones.contains(&*k))
{
return false;
}
let self_keys = self
.map
.iter()
.filter(|(_k, v)| !v.is_bot())
.map(|(k, _v)| <MapSelf as SimpleKeyedRef>::into_ref(k));
let other_keys = other
.map
.iter()
.filter(|(_k, v)| !v.is_bot())
.map(|(k, _v)| <MapOther as SimpleKeyedRef>::into_ref(k));
for k in self_keys.chain(other_keys) {
match (self.map.get(k), other.map.get(k)) {
(Some(self_value), Some(other_value)) => {
if *self_value != *other_value {
return false;
}
}
(None, None) => unreachable!(),
_ => {
return false;
}
}
}
true
}
}
impl<MapSelf, TombstoneSetSelf> Eq for MapUnionWithTombstones<MapSelf, TombstoneSetSelf> where
Self: PartialEq
{
}
impl<Map, TombstoneSet> IsBot for MapUnionWithTombstones<Map, TombstoneSet>
where
Map: Iter,
Map::Item: IsBot,
TombstoneSet: Len,
{
fn is_bot(&self) -> bool {
self.map.iter().all(|v| v.is_bot()) && self.tombstones.is_empty()
}
}
impl<Map, TombstoneSet> IsTop for MapUnionWithTombstones<Map, TombstoneSet> {
fn is_top(&self) -> bool {
false
}
}
pub type MapUnionHashMapWithTombstoneHashSet<K, Val> =
MapUnionWithTombstones<HashMap<K, Val>, HashSet<K>>;
pub type MapUnionWithTombstonesSingletonMapOnly<K, Val> =
MapUnionWithTombstones<SingletonMap<K, Val>, EmptySet<K>>;
pub type MapUnionWithTombstonesTombstoneSingletonSetOnly<K, Val> =
MapUnionWithTombstones<EmptyMap<K, Val>, SingletonSet<K>>;
#[cfg(test)]
mod test {
use super::*;
use crate::set_union::{SetUnion, SetUnionHashSet, SetUnionSingletonSet};
use crate::test::check_all;
use crate::NaiveLatticeOrd;
#[test]
fn test_map_union() {
type K = &'static str;
type V = usize;
type M = MapUnionWithTombstones<HashMap<K, SetUnionHashSet<V>>, HashSet<K>>;
type S = MapUnionWithTombstones<SingletonMap<K, SetUnionSingletonSet<V>>, EmptySet<K>>;
type T = MapUnionWithTombstones<EmptyMap<K, SetUnion<EmptySet<V>>>, SingletonSet<K>>;
let mut my_map_a = M::default();
let my_map_b = S::new(
SingletonMap("hello", SetUnion::new(SingletonSet(100))),
Default::default(),
);
let my_map_c = T::new(Default::default(), SingletonSet("hello"));
my_map_a.merge(my_map_b);
my_map_a.merge(my_map_c);
assert!(!my_map_a.as_reveal_ref().0.contains_key("hello"));
}
#[test]
fn contrain1() {
type T = MapUnionWithTombstones<HashMap<i32, SetUnion<HashSet<i32>>>, HashSet<i32>>;
let a = T::new_from([], HashSet::from_iter([0]));
let b = T::new_from(
[(0, SetUnionHashSet::new_from([0]))],
HashSet::from_iter([]),
);
assert_eq!(a.naive_cmp(&b), Some(Greater));
assert_eq!(a.partial_cmp(&b), Some(Greater));
let a = T::new_from([], HashSet::from_iter([1]));
let b = T::new_from([(0, SetUnionHashSet::new_from([0]))], HashSet::default());
assert_eq!(a.naive_cmp(&b), None);
assert_eq!(a.partial_cmp(&b), None);
}
#[test]
fn consistency() {
type K = &'static str;
type V = SetUnion<HashSet<i32>>;
type M = MapUnionWithTombstones<HashMap<K, V>, HashSet<K>>;
let mut test_vec = Vec::new();
#[rustfmt::skip]
{
test_vec.push(M::new_from([], HashSet::from_iter([])));
test_vec.push(M::new_from([], HashSet::from_iter(["a"])));
test_vec.push(M::new_from([], HashSet::from_iter(["b"])));
test_vec.push(M::new_from([], HashSet::from_iter(["a", "b"])));
test_vec.push(M::new_from([("a", SetUnionHashSet::new_from([]))], HashSet::from_iter([])));
test_vec.push(M::new_from([("a", SetUnionHashSet::new_from([0]))], HashSet::from_iter([])));
test_vec.push(M::new_from([("a", SetUnionHashSet::new_from([1]))], HashSet::from_iter([])));
test_vec.push(M::new_from([("a", SetUnionHashSet::new_from([0, 1]))], HashSet::from_iter([])));
test_vec.push(M::new_from([("b", SetUnionHashSet::new_from([]))], HashSet::from_iter([])));
test_vec.push(M::new_from([("b", SetUnionHashSet::new_from([0]))], HashSet::from_iter([])));
test_vec.push(M::new_from([("b", SetUnionHashSet::new_from([1]))], HashSet::from_iter([])));
test_vec.push(M::new_from([("b", SetUnionHashSet::new_from([0, 1]))], HashSet::from_iter([])));
};
check_all(&test_vec);
}
#[test]
fn test_collapses_bot() {
type K = &'static str;
type V = SetUnion<HashSet<i32>>;
type A = MapUnionWithTombstones<HashMap<K, V>, HashSet<K>>;
type B = MapUnionWithTombstones<SingletonMap<K, V>, HashSet<K>>;
let map_empty = A::default();
let map_a_bot = B::new(SingletonMap("a", Default::default()), Default::default());
let map_b_bot = B::new(SingletonMap("b", Default::default()), Default::default());
assert_eq!(map_empty, map_a_bot);
assert_eq!(map_empty, map_b_bot);
assert_eq!(map_a_bot, map_b_bot);
}
}