Skip to content

Commit

Permalink
Avoid loss of data in Range.simplify
Browse files Browse the repository at this point in the history
Co-authored-by: Zanie Blue <[email protected]>

Upstream port of #12
  • Loading branch information
konstin committed Dec 21, 2023
1 parent 526775f commit 9351e03
Showing 1 changed file with 28 additions and 9 deletions.
37 changes: 28 additions & 9 deletions src/range.rs
Original file line number Diff line number Diff line change
Expand Up @@ -415,21 +415,26 @@ impl<V: Ord + Clone> Range<V> {
Self { segments: output }.check_invariants()
}

/// Returns a simpler Range that contains the same versions
/// Returns a simpler Range that contains the same versions.
///
/// For every one of the Versions provided in versions the existing range and
/// the simplified range will agree on whether it is contained.
/// For every one of the Versions provided in versions the existing range and the simplified range will agree on whether it is contained.
/// The simplified version may include or exclude versions that are not in versions as the implementation wishes.
/// For example:
/// - If all the versions are contained in the original than the range will be simplified to `full`.
/// - If none of the versions are contained in the original than the range will be simplified to `empty`.
///
/// If versions are not sorted the correctness of this function is not guaranteed.
/// If none of the versions are contained in the original than the range will be returned unmodified.
/// If the range includes a single version, it will be returned unmodified.
/// If all the versions are contained in the original than the range will be simplified to `full`.
///
/// If the given versions are not sorted the correctness of this function is not guaranteed.
pub fn simplify<'v, I>(&self, versions: I) -> Self
where
I: Iterator<Item = &'v V> + 'v,
V: 'v,
{
// Do not simplify singletons
if self.is_singleton() {
return self.clone();
}

// Return the segment index in the range for each version in the range, None otherwise
let version_locations = versions.scan(0, move |i, v| {
while let Some(segment) = self.segments.get(*i) {
Expand All @@ -441,7 +446,13 @@ impl<V: Ord + Clone> Range<V> {
}
Some(None)
});
let kept_segments = group_adjacent_locations(version_locations);
let mut kept_segments = group_adjacent_locations(version_locations).peekable();

// Do not return null sets
if kept_segments.peek().is_none() {
return self.clone();
}

self.keep_segments(kept_segments)
}

Expand All @@ -462,6 +473,14 @@ impl<V: Ord + Clone> Range<V> {
}
Self { segments }.check_invariants()
}

/// Returns whether the range is just a single version.
pub fn is_singleton(&self) -> bool {
match self.segments.as_slice() {
[(Included(v1), Included(v2))] => v1 == v2,
_ => false,
}
}
}

impl<T: Debug + Display + Clone + Eq + Ord> VersionSet for Range<T> {
Expand Down Expand Up @@ -629,7 +648,7 @@ pub mod tests {
segments.push((start_bound, Unbounded));
}

return Range { segments }.check_invariants();
Range { segments }.check_invariants()
})
}

Expand Down

0 comments on commit 9351e03

Please sign in to comment.