Skip to content

Commit

Permalink
feat(utils): Inplace operations and std traits (#41)
Browse files Browse the repository at this point in the history
* move traits into submodules

* add inplace methods and std ops

* impl for references

* fix symmetric difference
  • Loading branch information
sinui0 authored Oct 8, 2024
1 parent 83a9554 commit 6f62968
Show file tree
Hide file tree
Showing 6 changed files with 476 additions and 133 deletions.
205 changes: 142 additions & 63 deletions utils/src/range/difference.rs
Original file line number Diff line number Diff line change
@@ -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<T: Copy + Ord> Difference<Range<T>> for Range<T> {
type Output = RangeSet<T>;

fn difference(&self, other: &Range<T>) -> 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<Rhs> {
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<T: Copy + Ord> Difference<RangeSet<T>> for Range<T>
where
RangeSet<T>: Difference<Range<T>, Output = RangeSet<T>>,
{
type Output = RangeSet<T>;

fn difference(&self, other: &RangeSet<T>) -> 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<Rhs> {
/// Subtracts `other` from `self`.
fn difference_mut(&mut self, other: &Rhs);
}

impl<T: Copy + Ord> Difference<Range<T>> for RangeSet<T> {
type Output = RangeSet<T>;

fn difference(&self, other: &Range<T>) -> Self::Output {
impl<T: Copy + Ord> DifferenceMut<Range<T>> for RangeSet<T> {
fn difference_mut(&mut self, other: &Range<T>) {
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 {
Expand Down Expand Up @@ -106,27 +64,148 @@ impl<T: Copy + Ord> Difference<Range<T>> for RangeSet<T> {

i += 1;
}
}
}

RangeSet { ranges }
impl<T: Copy + Ord> DifferenceMut<RangeSet<T>> for RangeSet<T> {
fn difference_mut(&mut self, other: &RangeSet<T>) {
for range in &other.ranges {
self.difference_mut(range);
}
}
}

impl<T: Copy + Ord> Difference<RangeSet<T>> for RangeSet<T> {
impl<T: Copy + Ord> Difference<Range<T>> for Range<T> {
type Output = RangeSet<T>;

fn difference(&self, other: &RangeSet<T>) -> Self::Output {
fn difference(&self, other: &Range<T>) -> 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<T: Copy + Ord> Difference<Range<T>> for RangeSet<T> {
type Output = RangeSet<T>;

fn difference(&self, other: &Range<T>) -> Self::Output {
let mut diff = self.clone();
diff.difference_mut(other);
diff
}
}

impl<T: Copy + Ord> Difference<RangeSet<T>> for Range<T> {
type Output = RangeSet<T>;

fn difference(&self, other: &RangeSet<T>) -> Self::Output {
let mut diff = RangeSet {
ranges: vec![self.clone()],
};
diff.difference_mut(other);
diff
}
}

impl<T: Copy + Ord> Difference<RangeSet<T>> for RangeSet<T> {
type Output = RangeSet<T>;

fn difference(&self, other: &RangeSet<T>) -> Self::Output {
let mut diff = self.clone();
diff.difference_mut(other);
diff
}
}

impl<T: Copy + Ord> SubAssign<Range<T>> for RangeSet<T> {
fn sub_assign(&mut self, rhs: Range<T>) {
self.difference_mut(&rhs);
}
}

impl<T: Copy + Ord> SubAssign<&Range<T>> for RangeSet<T> {
fn sub_assign(&mut self, rhs: &Range<T>) {
self.difference_mut(rhs);
}
}

impl<T: Copy + Ord> Sub<Range<T>> for RangeSet<T> {
type Output = RangeSet<T>;

fn sub(mut self, rhs: Range<T>) -> Self::Output {
self.difference_mut(&rhs);
self
}
}

impl<T: Copy + Ord> Sub<&Range<T>> for RangeSet<T> {
type Output = RangeSet<T>;

fn sub(mut self, rhs: &Range<T>) -> Self::Output {
self.difference_mut(rhs);
self
}
}

impl<T: Copy + Ord> SubAssign<RangeSet<T>> for RangeSet<T> {
fn sub_assign(&mut self, rhs: RangeSet<T>) {
self.difference_mut(&rhs);
}
}

impl<T: Copy + Ord> SubAssign<&RangeSet<T>> for RangeSet<T> {
fn sub_assign(&mut self, rhs: &RangeSet<T>) {
self.difference_mut(rhs);
}
}

impl<T: Copy + Ord> Sub<RangeSet<T>> for RangeSet<T> {
type Output = RangeSet<T>;

fn sub(mut self, rhs: RangeSet<T>) -> Self::Output {
self.difference_mut(&rhs);
self
}
}

impl<T: Copy + Ord> Sub<&RangeSet<T>> for RangeSet<T> {
type Output = RangeSet<T>;

fn sub(mut self, rhs: &RangeSet<T>) -> Self::Output {
self.difference_mut(rhs);
self
}
}

#[cfg(test)]
#[allow(clippy::all)]
mod tests {
use super::*;
use crate::range::Union;

use itertools::iproduct;

Expand Down
84 changes: 83 additions & 1 deletion utils/src/range/intersection.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,14 @@
use crate::range::{Intersection, Range, RangeSet};
use std::ops::{BitAnd, BitAndAssign};

use crate::range::{Range, RangeSet};

pub trait Intersection<Rhs> {
type Output;

/// Returns the set intersection of `self` and `other`.
#[must_use]
fn intersection(&self, other: &Rhs) -> Self::Output;
}

impl<T: Copy + Ord> Intersection<Range<T>> for Range<T> {
type Output = Option<Range<T>>;
Expand Down Expand Up @@ -82,6 +92,78 @@ impl<T: Copy + Ord> Intersection<RangeSet<T>> for RangeSet<T> {
}
}

impl<T: Copy + Ord> BitAndAssign<Range<T>> for RangeSet<T> {
fn bitand_assign(&mut self, other: Range<T>) {
*self = self.intersection(&other);
}
}

impl<T: Copy + Ord> BitAndAssign<&Range<T>> for RangeSet<T> {
fn bitand_assign(&mut self, other: &Range<T>) {
*self = self.intersection(other);
}
}

impl<T: Copy + Ord> BitAnd<RangeSet<T>> for Range<T> {
type Output = RangeSet<T>;

fn bitand(self, other: RangeSet<T>) -> Self::Output {
self.intersection(&other)
}
}

impl<T: Copy + Ord> BitAnd<&RangeSet<T>> for Range<T> {
type Output = RangeSet<T>;

fn bitand(self, other: &RangeSet<T>) -> Self::Output {
self.intersection(other)
}
}

impl<T: Copy + Ord> BitAnd<Range<T>> for RangeSet<T> {
type Output = RangeSet<T>;

fn bitand(self, other: Range<T>) -> Self::Output {
other.intersection(&self)
}
}

impl<T: Copy + Ord> BitAnd<&Range<T>> for RangeSet<T> {
type Output = RangeSet<T>;

fn bitand(self, other: &Range<T>) -> Self::Output {
other.intersection(&self)
}
}

impl<T: Copy + Ord> BitAndAssign<RangeSet<T>> for RangeSet<T> {
fn bitand_assign(&mut self, other: RangeSet<T>) {
*self = self.intersection(&other);
}
}

impl<T: Copy + Ord> BitAndAssign<&RangeSet<T>> for RangeSet<T> {
fn bitand_assign(&mut self, other: &RangeSet<T>) {
*self = self.intersection(other);
}
}

impl<T: Copy + Ord> BitAnd<RangeSet<T>> for RangeSet<T> {
type Output = RangeSet<T>;

fn bitand(self, other: RangeSet<T>) -> Self::Output {
self.intersection(&other)
}
}

impl<T: Copy + Ord> BitAnd<&RangeSet<T>> for RangeSet<T> {
type Output = RangeSet<T>;

fn bitand(self, other: &RangeSet<T>) -> Self::Output {
self.intersection(other)
}
}

#[cfg(test)]
mod tests {
use std::collections::HashSet;
Expand Down
Loading

0 comments on commit 6f62968

Please sign in to comment.