// Copyright (c) Microsoft Corporation. // Licensed under the MIT License. use super::{BitVec, BitwiseNeutralElement, BorrowAsBitIterator, FromBits, OverlapWeight}; use crate::bits::{are_supports_equal, Bitwise, BitwiseBinaryOps, Dot, IndexAssignable}; use crate::NeutralElement; use sorted_iter::{assume::AssumeSortedByItemExt, SortedIterator}; use sorted_vec::SortedSet; #[must_use] #[derive(PartialEq, Eq, Clone, Debug, Hash)] pub struct IndexSet { indexes: SortedSet, } impl IndexSet { pub fn new() -> IndexSet { IndexSet { indexes: SortedSet::new(), } } pub fn singleton(value: usize) -> Self { IndexSet { indexes: unsafe { SortedSet::from_sorted(vec![value]) }, } } } impl Default for IndexSet { fn default() -> Self { Self::new() } } impl FromIterator for IndexSet { fn from_iter>(iterator: Iterator) -> Self { let indexes = SortedSet::from_unsorted(iterator.into_iter().collect()); IndexSet { indexes } } } impl IntoIterator for IndexSet { type Item = usize; type IntoIter = std::vec::IntoIter; fn into_iter(self) -> Self::IntoIter { self.indexes.into_vec().into_iter() } } impl Bitwise for IndexSet { fn index(&self, index: usize) -> bool { self.indexes.contains(&index) } fn weight(&self) -> usize { self.indexes.len() } fn support(&self) -> impl SortedIterator { self.indexes.iter().copied().assume_sorted_by_item() } } impl BitwiseBinaryOps for IndexSet { fn assign(&mut self, other: &Bits) { let indexes: Vec = other.support().collect(); self.indexes = indexes.into(); } fn bitxor_assign(&mut self, other: &Bits) { for index in other.support() { let found = self.indexes.find_or_insert(index); if found.is_found() { self.indexes.remove_index(found.index()); } } } fn bitand_assign(&mut self, other: &Bits) { let self_support = self.indexes.iter().copied().assume_sorted_by_item(); let other_support = other.support(); let indexes: Vec = self_support.intersection(other_support).collect(); self.indexes = indexes.into(); } } impl IndexAssignable for IndexSet { fn assign_index(&mut self, index: usize, to: bool) { if to { self.indexes.push(index); } else { self.indexes.remove_item(&index); } } fn negate_index(&mut self, index: usize) { if self.indexes.contains(&index) { self.indexes.remove_item(&index); } else { self.indexes.push(index); } } fn clear_bits(&mut self) { self.indexes.clear(); } } impl Dot for IndexSet { fn dot(&self, other: &Bits) -> bool { debug_assert!(is_sorted(self.support())); debug_assert!(is_sorted(other.support())); let mut res = false; for index in self.support() { res ^= other.index(index); } res } } impl Dot for T { fn dot(&self, other: &IndexSet) -> bool { other.dot(self) } } impl OverlapWeight for IndexSet { fn and_weight(&self, other: &Bits) -> usize { let mut res = 0usize; for index in self.support() { if other.index(index) { res += 1; } } res } fn or_weight(&self, other: &Bits) -> usize { self.weight() + other.weight() - self.and_weight(other) } } impl OverlapWeight for T { fn and_weight(&self, other: &IndexSet) -> usize { other.and_weight(self) } fn or_weight(&self, other: &IndexSet) -> usize { other.or_weight(self) } } fn is_sorted>(items: Items) -> bool { items.into_iter().is_sorted() } impl BitwiseBinaryOps for T { #[allow(clippy::explicit_iter_loop)] fn assign(&mut self, other: &IndexSet) { self.clear_bits(); for index in other.indexes.iter() { self.assign_index(*index, true); } } fn bitxor_assign(&mut self, other: &IndexSet) { for index in other.support() { self.negate_index(index); } } fn bitand_assign(&mut self, other: &IndexSet) { let intersection: Vec = self.support().intersection(other.support()).collect(); self.clear_bits(); for k in intersection { self.assign_index(k, true); } } } impl PartialEq for IndexSet { fn eq(&self, other: &T) -> bool { are_supports_equal(self, other) } } impl FromBits for IndexSet { fn from_bits(other: &Other) -> Self { IndexSet { indexes: other.support().collect::>().into(), } } } impl NeutralElement for IndexSet { type NeutralElementType = IndexSet; fn neutral_element(&self) -> Self::NeutralElementType { IndexSet::new() } fn default_size_neutral_element() -> Self::NeutralElementType { IndexSet::new() } fn neutral_element_of_size(_size: usize) -> Self::NeutralElementType { IndexSet::new() } } impl BitwiseNeutralElement for IndexSet {} impl<'life, const WORD_COUNT: usize> From<&'life BitVec> for IndexSet { fn from(value: &'life BitVec) -> Self { unsafe { IndexSet { indexes: SortedSet::from_sorted(value.support().collect::>()), } } } } pub fn remapped(bits: &IndexSet, support: &[usize]) -> IndexSet { bits.support().map(|id| support[id]).collect() } impl From for IndexSet where T: SortedIterator, { fn from(value: T) -> Self { unsafe { IndexSet { indexes: SortedSet::from_sorted(value.collect::>()), } } } }