Skip to content

Commit

Permalink
Improve performance + memory usage
Browse files Browse the repository at this point in the history
  • Loading branch information
alexvbrdn committed Aug 30, 2024
1 parent 23d06ae commit ef2f44c
Show file tree
Hide file tree
Showing 5 changed files with 48 additions and 62 deletions.
3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "irange"
version = "1.0.0"
version = "1.1.0"
edition = "2021"
authors = ["Alexandre van Beurden"]
repository = "https://github.com/alexvbrdn/irange"
Expand All @@ -17,6 +17,7 @@ readme = "README.md"

[dev-dependencies]
criterion = { version = "0.5", features = ["html_reports"] }
rand = "0.8"

[[bench]]
name = "my_benchmark"
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ Supported types: `u8`, `u16`, `u32`, `u64`, `u128`, `usize`, `i8`, `i16`, `i32`,
## Examples

```rust
use irange::RangeSet;

let range1 = RangeSet::<i64>::new_from_ranges(&[AnyRange::from(3..=4), AnyRange::from(7..9)]);
let range2 = RangeSet::<i64>::new_from_range(-2..=4);

Expand Down
20 changes: 19 additions & 1 deletion benches/my_benchmark.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use criterion::{criterion_group, criterion_main, Criterion};
use irange::RangeSet;
use irange::{range::AnyRange, RangeSet};
use rand::{seq::SliceRandom, thread_rng};

fn criterion_benchmark(c: &mut Criterion) {
let range_regex_small_w = RangeSet(vec![
Expand Down Expand Up @@ -133,6 +134,23 @@ fn criterion_benchmark(c: &mut Criterion) {
125264, 125273, 130032, 130041,
]);

let mut new_from_ranges =
Vec::with_capacity(range_regex_small_w.0.len() / 2 + range_regex_small_d.0.len() / 2);
for i in (0..range_regex_small_w.0.len()).step_by(2) {
let (min, max) = (range_regex_small_w.0[i], range_regex_small_w.0[i + 1]);
new_from_ranges.push(AnyRange::new(min, max));
}
for i in (0..range_regex_small_d.0.len()).step_by(2) {
let (min, max) = (range_regex_small_d.0[i], range_regex_small_d.0[i + 1]);
new_from_ranges.push(AnyRange::new(min, max));
}
let mut rng = thread_rng();
new_from_ranges.shuffle(&mut rng);

c.bench_function("new_from_ranges", |b| {
b.iter(|| RangeSet::new_from_ranges(&new_from_ranges))
});

c.bench_function("union", |b| {
b.iter(|| range_regex_small_w.union(&range_regex_small_d))
});
Expand Down
19 changes: 16 additions & 3 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ impl<T: NumericInteger> RangeSet<T> {
.iter()
.map(|range| range.get_bounds())
.filter(|(min, max)| max >= min)
.copied()
.collect();
ranges.sort_by(|r1, r2| r1.0.cmp(&r2.0));

Expand All @@ -161,6 +162,7 @@ impl<T: NumericInteger> RangeSet<T> {
}
}

bounds.shrink_to_fit();
RangeSet(bounds)
}

Expand Down Expand Up @@ -330,7 +332,7 @@ impl<T: NumericInteger> RangeSet<T> {
return self.clone();
}

let mut new_range = vec![];
let mut new_range = Vec::with_capacity(self.0.len() + that.0.len());

let mut self_i = 0;
let mut that_i = 0;
Expand Down Expand Up @@ -375,6 +377,7 @@ impl<T: NumericInteger> RangeSet<T> {
current_max = new_range[current_i.unwrap() + 1];
}

new_range.shrink_to_fit();
RangeSet(new_range)
}

Expand Down Expand Up @@ -429,7 +432,15 @@ impl<T: NumericInteger> RangeSet<T> {
/// let intersection = range1.intersection(&range2);
/// ```
pub fn intersection(&self, that: &RangeSet<T>) -> RangeSet<T> {
let mut new_range: Vec<T> = Vec::new();
if self.is_empty() || that.is_empty() {
return RangeSet::empty();
} else if self.is_total() {
return that.clone();
} else if that.is_total() {
return self.clone();
}

let mut new_range = Vec::with_capacity(self.0.len() + that.0.len());

let mut i = 0;
let mut j = 0;
Expand All @@ -456,6 +467,7 @@ impl<T: NumericInteger> RangeSet<T> {
}
}

new_range.shrink_to_fit();
RangeSet(new_range)
}

Expand All @@ -478,7 +490,7 @@ impl<T: NumericInteger> RangeSet<T> {
return Self::empty();
}

let mut new_range = vec![];
let mut new_range = Vec::with_capacity(self.0.len());

for i in (0..self.0.len()).step_by(2) {
let (min, max) = (self.0[i], self.0[i + 1]);
Expand All @@ -499,6 +511,7 @@ impl<T: NumericInteger> RangeSet<T> {
new_range.push(T::max_value());
}

new_range.shrink_to_fit();
RangeSet(new_range)
}

Expand Down
66 changes: 9 additions & 57 deletions src/range.rs
Original file line number Diff line number Diff line change
@@ -1,67 +1,19 @@
use std::ops::{
Range, RangeBounds, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive,
};
use std::ops::RangeBounds;

use crate::{integer::NumericInteger, range_to_bounds};

pub enum AnyRange<T: NumericInteger> {
Range(Range<T>),
RangeInclusive(RangeInclusive<T>),
RangeFrom(RangeFrom<T>),
RangeTo(RangeTo<T>),
RangeToInclusive(RangeToInclusive<T>),
RangeFull,
}
pub struct AnyRange<T: NumericInteger>((T, T));

impl<T: NumericInteger> AnyRange<T> {
pub fn from<R: RangeBounds<T> + Into<AnyRange<T>>>(range: R) -> AnyRange<T> {
range.into()
}

pub fn get_bounds(&self) -> (T, T) {
match self {
AnyRange::Range(r) => range_to_bounds(r),
AnyRange::RangeInclusive(r) => range_to_bounds(r),
AnyRange::RangeFrom(r) => range_to_bounds(r),
AnyRange::RangeTo(r) => range_to_bounds(r),
AnyRange::RangeToInclusive(r) => range_to_bounds(r),
AnyRange::RangeFull => (T::min_value(), T::max_value()),
}
}
}

impl<T: NumericInteger> From<Range<T>> for AnyRange<T> {
fn from(range: Range<T>) -> Self {
AnyRange::Range(range)
}
}

impl<T: NumericInteger> From<RangeInclusive<T>> for AnyRange<T> {
fn from(range: RangeInclusive<T>) -> Self {
AnyRange::RangeInclusive(range)
pub fn new(min: T, max: T) -> AnyRange<T> {
AnyRange((min, max))
}
}

impl<T: NumericInteger> From<RangeFrom<T>> for AnyRange<T> {
fn from(range: RangeFrom<T>) -> Self {
AnyRange::RangeFrom(range)
}
}

impl<T: NumericInteger> From<RangeTo<T>> for AnyRange<T> {
fn from(range: RangeTo<T>) -> Self {
AnyRange::RangeTo(range)

pub fn from<R: RangeBounds<T>>(range: R) -> AnyRange<T> {
AnyRange(range_to_bounds(&range))
}
}

impl<T: NumericInteger> From<RangeToInclusive<T>> for AnyRange<T> {
fn from(range: RangeToInclusive<T>) -> Self {
AnyRange::RangeToInclusive(range)
}
}

impl<T: NumericInteger> From<RangeFull> for AnyRange<T> {
fn from(_range: RangeFull) -> Self {
AnyRange::RangeFull
pub fn get_bounds(&self) -> &(T, T) {
&self.0
}
}

0 comments on commit ef2f44c

Please sign in to comment.