From 6f629684d0b785d9cdbcedc9b48fe8bc8b94e7fc Mon Sep 17 00:00:00 2001 From: "sinu.eth" <65924192+sinui0@users.noreply.github.com> Date: Tue, 8 Oct 2024 10:07:29 -0700 Subject: [PATCH] feat(utils): Inplace operations and std traits (#41) * move traits into submodules * add inplace methods and std ops * impl for references * fix symmetric difference --- utils/src/range/difference.rs | 205 ++++++++++++++++-------- utils/src/range/intersection.rs | 84 +++++++++- utils/src/range/mod.rs | 41 ++--- utils/src/range/subset.rs | 8 +- utils/src/range/symmetric_difference.rs | 107 +++++++++++++ utils/src/range/union.rs | 164 ++++++++++++++----- 6 files changed, 476 insertions(+), 133 deletions(-) create mode 100644 utils/src/range/symmetric_difference.rs diff --git a/utils/src/range/difference.rs b/utils/src/range/difference.rs index be18410..35f96f7 100644 --- a/utils/src/range/difference.rs +++ b/utils/src/range/difference.rs @@ -1,72 +1,30 @@ -use std::ops::Range; +use std::ops::{Range, Sub, SubAssign}; -use crate::range::{Difference, Disjoint, RangeSet, Subset, Union}; +use crate::range::{Disjoint, RangeSet, Subset}; -impl Difference> for Range { - type Output = RangeSet; - - fn difference(&self, other: &Range) -> Self::Output { - if self.is_empty() { - return RangeSet::default(); - } else if other.is_empty() { - return RangeSet::from(self.clone()); - } - - // If other contains self, return an empty set. - if self.is_subset(other) { - return RangeSet::default(); - } - - // If they are disjoint, return self. - if self.is_disjoint(other) { - return RangeSet::from(self.clone()); - } +pub trait Difference { + type Output; - let mut set = RangeSet::default(); - - if self.start < other.start { - set.ranges.push(self.start..other.start); - } - - if self.end > other.end { - set.ranges.push(other.end..self.end); - } - - set - } + /// Returns the set difference of `self` and `other`. + #[must_use] + fn difference(&self, other: &Rhs) -> Self::Output; } -impl Difference> for Range -where - RangeSet: Difference, Output = RangeSet>, -{ - type Output = RangeSet; - - fn difference(&self, other: &RangeSet) -> Self::Output { - if self.is_empty() { - return RangeSet::default(); - } - - let mut diff = RangeSet::from(self.clone()); - - for range in &other.ranges { - diff = diff.difference(range); - } - - diff - } +pub trait DifferenceMut { + /// Subtracts `other` from `self`. + fn difference_mut(&mut self, other: &Rhs); } -impl Difference> for RangeSet { - type Output = RangeSet; - - fn difference(&self, other: &Range) -> Self::Output { +impl DifferenceMut> for RangeSet { + fn difference_mut(&mut self, other: &Range) { if other.is_empty() { - return self.clone(); + return; + } else if self.ranges.is_empty() { + return; } let mut i = 0; - let mut ranges = self.ranges.clone(); + let ranges = &mut self.ranges; while i < ranges.len() { // If the current range is entirely before other if ranges[i].end <= other.start { @@ -106,27 +64,148 @@ impl Difference> for RangeSet { i += 1; } + } +} - RangeSet { ranges } +impl DifferenceMut> for RangeSet { + fn difference_mut(&mut self, other: &RangeSet) { + for range in &other.ranges { + self.difference_mut(range); + } } } -impl Difference> for RangeSet { +impl Difference> for Range { type Output = RangeSet; - fn difference(&self, other: &RangeSet) -> Self::Output { + fn difference(&self, other: &Range) -> Self::Output { + if self.is_empty() { + return RangeSet::default(); + } else if other.is_empty() { + return RangeSet::from(self.clone()); + } + + // If other contains self, return an empty set. + if self.is_subset(other) { + return RangeSet::default(); + } + + // If they are disjoint, return self. + if self.is_disjoint(other) { + return RangeSet::from(self.clone()); + } + let mut set = RangeSet::default(); - for range in &self.ranges { - set = set.union(&range.difference(other)); + + if self.start < other.start { + set.ranges.push(self.start..other.start); } + + if self.end > other.end { + set.ranges.push(other.end..self.end); + } + set } } +impl Difference> for RangeSet { + type Output = RangeSet; + + fn difference(&self, other: &Range) -> Self::Output { + let mut diff = self.clone(); + diff.difference_mut(other); + diff + } +} + +impl Difference> for Range { + type Output = RangeSet; + + fn difference(&self, other: &RangeSet) -> Self::Output { + let mut diff = RangeSet { + ranges: vec![self.clone()], + }; + diff.difference_mut(other); + diff + } +} + +impl Difference> for RangeSet { + type Output = RangeSet; + + fn difference(&self, other: &RangeSet) -> Self::Output { + let mut diff = self.clone(); + diff.difference_mut(other); + diff + } +} + +impl SubAssign> for RangeSet { + fn sub_assign(&mut self, rhs: Range) { + self.difference_mut(&rhs); + } +} + +impl SubAssign<&Range> for RangeSet { + fn sub_assign(&mut self, rhs: &Range) { + self.difference_mut(rhs); + } +} + +impl Sub> for RangeSet { + type Output = RangeSet; + + fn sub(mut self, rhs: Range) -> Self::Output { + self.difference_mut(&rhs); + self + } +} + +impl Sub<&Range> for RangeSet { + type Output = RangeSet; + + fn sub(mut self, rhs: &Range) -> Self::Output { + self.difference_mut(rhs); + self + } +} + +impl SubAssign> for RangeSet { + fn sub_assign(&mut self, rhs: RangeSet) { + self.difference_mut(&rhs); + } +} + +impl SubAssign<&RangeSet> for RangeSet { + fn sub_assign(&mut self, rhs: &RangeSet) { + self.difference_mut(rhs); + } +} + +impl Sub> for RangeSet { + type Output = RangeSet; + + fn sub(mut self, rhs: RangeSet) -> Self::Output { + self.difference_mut(&rhs); + self + } +} + +impl Sub<&RangeSet> for RangeSet { + type Output = RangeSet; + + fn sub(mut self, rhs: &RangeSet) -> Self::Output { + self.difference_mut(rhs); + self + } +} + #[cfg(test)] #[allow(clippy::all)] mod tests { use super::*; + use crate::range::Union; use itertools::iproduct; diff --git a/utils/src/range/intersection.rs b/utils/src/range/intersection.rs index e41c647..f058936 100644 --- a/utils/src/range/intersection.rs +++ b/utils/src/range/intersection.rs @@ -1,4 +1,14 @@ -use crate::range::{Intersection, Range, RangeSet}; +use std::ops::{BitAnd, BitAndAssign}; + +use crate::range::{Range, RangeSet}; + +pub trait Intersection { + type Output; + + /// Returns the set intersection of `self` and `other`. + #[must_use] + fn intersection(&self, other: &Rhs) -> Self::Output; +} impl Intersection> for Range { type Output = Option>; @@ -82,6 +92,78 @@ impl Intersection> for RangeSet { } } +impl BitAndAssign> for RangeSet { + fn bitand_assign(&mut self, other: Range) { + *self = self.intersection(&other); + } +} + +impl BitAndAssign<&Range> for RangeSet { + fn bitand_assign(&mut self, other: &Range) { + *self = self.intersection(other); + } +} + +impl BitAnd> for Range { + type Output = RangeSet; + + fn bitand(self, other: RangeSet) -> Self::Output { + self.intersection(&other) + } +} + +impl BitAnd<&RangeSet> for Range { + type Output = RangeSet; + + fn bitand(self, other: &RangeSet) -> Self::Output { + self.intersection(other) + } +} + +impl BitAnd> for RangeSet { + type Output = RangeSet; + + fn bitand(self, other: Range) -> Self::Output { + other.intersection(&self) + } +} + +impl BitAnd<&Range> for RangeSet { + type Output = RangeSet; + + fn bitand(self, other: &Range) -> Self::Output { + other.intersection(&self) + } +} + +impl BitAndAssign> for RangeSet { + fn bitand_assign(&mut self, other: RangeSet) { + *self = self.intersection(&other); + } +} + +impl BitAndAssign<&RangeSet> for RangeSet { + fn bitand_assign(&mut self, other: &RangeSet) { + *self = self.intersection(other); + } +} + +impl BitAnd> for RangeSet { + type Output = RangeSet; + + fn bitand(self, other: RangeSet) -> Self::Output { + self.intersection(&other) + } +} + +impl BitAnd<&RangeSet> for RangeSet { + type Output = RangeSet; + + fn bitand(self, other: &RangeSet) -> Self::Output { + self.intersection(other) + } +} + #[cfg(test)] mod tests { use std::collections::HashSet; diff --git a/utils/src/range/mod.rs b/utils/src/range/mod.rs index e4785d9..eb0eebd 100644 --- a/utils/src/range/mod.rs +++ b/utils/src/range/mod.rs @@ -2,9 +2,15 @@ mod difference; mod index; mod intersection; mod subset; +mod symmetric_difference; mod union; +pub use difference::{Difference, DifferenceMut}; pub use index::IndexRanges; +pub use intersection::Intersection; +pub use subset::Subset; +pub use symmetric_difference::{SymmetricDifference, SymmetricDifferenceMut}; +pub use union::{Union, UnionMut}; use std::ops::{Add, Range, Sub}; @@ -91,6 +97,11 @@ impl RangeSet { pub fn len_ranges(&self) -> usize { self.ranges.len() } + + /// Clears the set, removing all ranges. + pub fn clear(&mut self) { + self.ranges.clear(); + } } impl RangeSet { @@ -397,36 +408,6 @@ pub trait Contains { fn contains(&self, other: &Rhs) -> bool; } -pub trait Subset { - /// Returns `true` if `self` is a subset of `other`. - #[must_use] - fn is_subset(&self, other: &Rhs) -> bool; -} - -pub trait Difference { - type Output; - - /// Returns the set difference of `self` and `other`. - #[must_use] - fn difference(&self, other: &Rhs) -> Self::Output; -} - -pub trait Union { - type Output; - - /// Returns the set union of `self` and `other`. - #[must_use] - fn union(&self, other: &Rhs) -> Self::Output; -} - -pub trait Intersection { - type Output; - - /// Returns the set intersection of `self` and `other`. - #[must_use] - fn intersection(&self, other: &Rhs) -> Self::Output; -} - /// A type which successor and predecessor operations can be performed on. /// /// Similar to `std::iter::Step`, but not nightly-only. diff --git a/utils/src/range/subset.rs b/utils/src/range/subset.rs index dc3dc49..8ee27ba 100644 --- a/utils/src/range/subset.rs +++ b/utils/src/range/subset.rs @@ -1,4 +1,10 @@ -use crate::range::{Range, RangeSet, Subset}; +use crate::range::{Range, RangeSet}; + +pub trait Subset { + /// Returns `true` if `self` is a subset of `other`. + #[must_use] + fn is_subset(&self, other: &Rhs) -> bool; +} impl Subset> for Range { fn is_subset(&self, other: &Range) -> bool { diff --git a/utils/src/range/symmetric_difference.rs b/utils/src/range/symmetric_difference.rs new file mode 100644 index 0000000..ea0e399 --- /dev/null +++ b/utils/src/range/symmetric_difference.rs @@ -0,0 +1,107 @@ +use std::ops::{BitXor, BitXorAssign, Range}; + +use crate::range::{DifferenceMut, Intersection, RangeSet, UnionMut}; + +pub trait SymmetricDifferenceMut { + /// Replaces `self` with the set symmetric difference of `self` and `other`. + fn symmetric_difference_mut(&mut self, other: &Rhs); +} + +pub trait SymmetricDifference { + type Output; + + /// Returns the set symmetric difference of `self` and `other`. + fn symmetric_difference(&self, other: &Rhs) -> Self::Output; +} + +impl SymmetricDifferenceMut> for RangeSet { + fn symmetric_difference_mut(&mut self, other: &Range) { + let intersection = self.intersection(other); + self.union_mut(other); + self.difference_mut(&intersection); + } +} + +impl SymmetricDifferenceMut> for RangeSet { + fn symmetric_difference_mut(&mut self, other: &RangeSet) { + let intersection = self.intersection(other); + self.union_mut(other); + self.difference_mut(&intersection); + } +} + +impl SymmetricDifference> for RangeSet { + type Output = RangeSet; + + fn symmetric_difference(&self, other: &Range) -> Self::Output { + let mut output = self.clone(); + output.symmetric_difference_mut(other); + output + } +} + +impl SymmetricDifference> for RangeSet { + type Output = RangeSet; + + fn symmetric_difference(&self, other: &RangeSet) -> Self::Output { + let mut output = self.clone(); + output.symmetric_difference_mut(other); + output + } +} + +impl BitXor> for RangeSet { + type Output = RangeSet; + + fn bitxor(mut self, rhs: Range) -> Self::Output { + self.symmetric_difference_mut(&rhs); + self + } +} + +impl BitXor<&Range> for RangeSet { + type Output = RangeSet; + + fn bitxor(mut self, rhs: &Range) -> Self::Output { + self.symmetric_difference_mut(rhs); + self + } +} + +impl BitXor> for RangeSet { + type Output = RangeSet; + + fn bitxor(mut self, rhs: RangeSet) -> Self::Output { + self.symmetric_difference_mut(&rhs); + self + } +} + +impl BitXor<&RangeSet> for RangeSet { + type Output = RangeSet; + + fn bitxor(mut self, rhs: &RangeSet) -> Self::Output { + self.symmetric_difference_mut(rhs); + self + } +} + +impl BitXor> for &RangeSet { + type Output = RangeSet; + + fn bitxor(self, rhs: RangeSet) -> Self::Output { + self.symmetric_difference(&rhs) + } +} + +impl BitXorAssign> for RangeSet { + fn bitxor_assign(&mut self, rhs: RangeSet) { + self.symmetric_difference_mut(&rhs); + } +} + +impl BitXorAssign<&RangeSet> for RangeSet { + fn bitxor_assign(&mut self, rhs: &RangeSet) { + self.symmetric_difference_mut(rhs); + } +} diff --git a/utils/src/range/union.rs b/utils/src/range/union.rs index bf03719..6a06dc4 100644 --- a/utils/src/range/union.rs +++ b/utils/src/range/union.rs @@ -1,6 +1,66 @@ -use std::ops::Range; +use std::ops::{BitOr, BitOrAssign, Range}; -use crate::range::{Disjoint, RangeSet, Subset, Union}; +use crate::range::{Disjoint, RangeSet, Subset}; + +pub trait UnionMut { + /// Replaces `self` with the set union of `self` and `other`. + fn union_mut(&mut self, other: &Rhs); +} + +pub trait Union { + type Output; + + /// Returns the set union of `self` and `other`. + #[must_use] + fn union(&self, other: &Rhs) -> Self::Output; +} + +impl UnionMut> for RangeSet { + fn union_mut(&mut self, other: &Range) { + if other.is_empty() { + return; + } else if self.ranges.is_empty() { + self.ranges.push(other.clone()); + return; + } + + let ranges = &mut self.ranges; + + let mut i = 0; + let mut new_range = other.clone(); + while i < ranges.len() { + // If the new_range comes before the current range without overlapping + if new_range.end < ranges[i].start { + ranges.insert(i, new_range); + + return; + } + // If the new_range overlaps or is adjacent with the current range + else if new_range.start <= ranges[i].end { + // Expand new_range to include the current range + new_range.start = new_range.start.min(ranges[i].start); + new_range.end = new_range.end.max(ranges[i].end); + // Remove the current range as it is now included in new_range + ranges.remove(i); + } + // If the new_range comes after the current range + else { + i += 1; + } + } + + // If the new_range comes after all the ranges, add it to the end + ranges.push(new_range); + } +} + +impl UnionMut> for RangeSet { + fn union_mut(&mut self, other: &RangeSet) { + for range in &other.ranges { + self.union_mut(range); + } + } +} impl Union> for Range { type Output = RangeSet; @@ -38,39 +98,9 @@ impl Union> for Range { type Output = RangeSet; fn union(&self, other: &RangeSet) -> Self::Output { - if self.is_empty() { - return other.clone(); - } - - let mut ranges = other.ranges.clone(); - - let mut i = 0; - let mut new_range = self.clone(); - while i < ranges.len() { - // If the new_range comes before the current range without overlapping - if new_range.end < ranges[i].start { - ranges.insert(i, new_range); - - return RangeSet { ranges }; - } - // If the new_range overlaps or is adjacent with the current range - else if new_range.start <= ranges[i].end { - // Expand new_range to include the current range - new_range.start = new_range.start.min(ranges[i].start); - new_range.end = new_range.end.max(ranges[i].end); - // Remove the current range as it is now included in new_range - ranges.remove(i); - } - // If the new_range comes after the current range - else { - i += 1; - } - } - - // If the new_range comes after all the ranges, add it to the end - ranges.push(new_range); - - RangeSet { ranges } + let mut other = other.clone(); + other.union_mut(self); + other } } @@ -87,13 +117,71 @@ impl Union> for RangeSet { fn union(&self, other: &RangeSet) -> Self::Output { let mut union = self.clone(); - for range in &other.ranges { - union = union.union(range); - } + union.union_mut(other); union } } +impl BitOrAssign> for RangeSet { + fn bitor_assign(&mut self, other: Range) { + self.union_mut(&other); + } +} + +impl BitOrAssign<&Range> for RangeSet { + fn bitor_assign(&mut self, other: &Range) { + self.union_mut(other); + } +} + +impl BitOr> for RangeSet { + type Output = RangeSet; + + fn bitor(mut self, other: Range) -> Self::Output { + self.union_mut(&other); + self + } +} + +impl BitOr<&Range> for RangeSet { + type Output = RangeSet; + + fn bitor(mut self, other: &Range) -> Self::Output { + self.union_mut(other); + self + } +} + +impl BitOrAssign> for RangeSet { + fn bitor_assign(&mut self, other: RangeSet) { + self.union_mut(&other); + } +} + +impl BitOrAssign<&RangeSet> for RangeSet { + fn bitor_assign(&mut self, other: &RangeSet) { + self.union_mut(other); + } +} + +impl BitOr> for RangeSet { + type Output = RangeSet; + + fn bitor(mut self, other: RangeSet) -> Self::Output { + self.union_mut(&other); + self + } +} + +impl BitOr<&RangeSet> for RangeSet { + type Output = RangeSet; + + fn bitor(mut self, other: &RangeSet) -> Self::Output { + self.union_mut(other); + self + } +} + #[cfg(test)] #[allow(clippy::all)] mod tests {