From 849004e8387488e923b3f1b834df95c3ec27ac8f Mon Sep 17 00:00:00 2001 From: Bas Zalmstra Date: Fri, 22 Apr 2022 21:11:04 +0200 Subject: [PATCH 1/4] refactor: add inclusive and exclusive bounds to Range --- src/internal/small_vec.rs | 8 + src/range.rs | 630 ++++++++++++++++++++++---------------- src/term.rs | 3 +- 3 files changed, 377 insertions(+), 264 deletions(-) diff --git a/src/internal/small_vec.rs b/src/internal/small_vec.rs index 2c3fe4f4..ae412170 100644 --- a/src/internal/small_vec.rs +++ b/src/internal/small_vec.rs @@ -1,4 +1,5 @@ use std::fmt; +use std::hash::{Hash, Hasher}; use std::ops::Deref; #[derive(Clone)] @@ -108,6 +109,13 @@ impl fmt::Debug for SmallVec { } } +impl Hash for SmallVec { + fn hash(&self, state: &mut H) { + self.len().hash(state); + Hash::hash_slice(self.as_slice(), state); + } +} + #[cfg(feature = "serde")] impl serde::Serialize for SmallVec { fn serialize(&self, s: S) -> Result { diff --git a/src/range.rs b/src/range.rs index b0ca3bc4..28f7b016 100644 --- a/src/range.rs +++ b/src/range.rs @@ -14,48 +14,26 @@ //! - [strictly_lower_than(v)](Range::strictly_lower_than): the set defined by `versions < v` //! - [between(v1, v2)](Range::between): the set defined by `v1 <= versions < v2` -use std::cmp::Ordering; -use std::fmt; -use std::ops::{Bound, RangeBounds}; - -use crate::internal::small_vec::SmallVec; -use crate::version::Version; -use crate::version_set::VersionSet; - -impl VersionSet for Range { - type V = V; - // Constructors - fn empty() -> Self { - Range::none() - } - fn singleton(v: Self::V) -> Self { - Range::exact(v) - } - // Operations - fn complement(&self) -> Self { - self.negate() - } - fn intersection(&self, other: &Self) -> Self { - self.intersection(other) - } - // Membership - fn contains(&self, v: &Self::V) -> bool { - self.contains(v) - } -} - -/// A Range is a set of versions. -#[derive(Debug, Clone, Eq, PartialEq)] +use crate::{internal::small_vec::SmallVec, version_set::VersionSet}; +use std::{ + cmp::Ordering, + fmt::{Debug, Display, Formatter}, + ops::Bound::{self, Excluded, Included, Unbounded}, +}; +use std::ops::RangeBounds; + +/// A Range represents multiple intervals of a continuous range of monotone increasing +/// values. +#[derive(Debug, Clone, Eq, PartialEq, Hash)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", serde(transparent))] -pub struct Range { +pub struct Range { segments: SmallVec>, } -type Interval = (V, Option); +type Interval = (Bound, Bound); -// Range building blocks. -impl Range { +impl Range { /// Empty set of versions. pub fn none() -> Self { Self { @@ -63,298 +41,394 @@ impl Range { } } - /// Set of all possible versions. + /// Set of all possible versions pub fn any() -> Self { - Self::higher_than(V::lowest()) + Self { + segments: SmallVec::one((Unbounded, Unbounded)), + } } - /// Set containing exactly one version. - pub fn exact(v: impl Into) -> Self { - let v = v.into(); + /// Set of all versions higher or equal to some version + pub fn higher_than(v: impl Into) -> Self { Self { - segments: SmallVec::one((v.clone(), Some(v.bump()))), + segments: SmallVec::one((Included(v.into()), Unbounded)), } } - /// Set of all versions higher or equal to some version. - pub fn higher_than(v: impl Into) -> Self { + /// Set of all versions higher to some version + pub fn strictly_higher_than(v: impl Into) -> Self { Self { - segments: SmallVec::one((v.into(), None)), + segments: SmallVec::one((Excluded(v.into()), Unbounded)), } } - /// Set of all versions strictly lower than some version. + /// Set of all versions lower to some version pub fn strictly_lower_than(v: impl Into) -> Self { - let v = v.into(); - if v == V::lowest() { - Self::none() - } else { - Self { - segments: SmallVec::one((V::lowest(), Some(v))), - } + Self { + segments: SmallVec::one((Unbounded, Excluded(v.into()))), } } - /// Set of all versions comprised between two given versions. - /// The lower bound is included and the higher bound excluded. - /// `v1 <= v < v2`. - pub fn between(v1: impl Into, v2: impl Into) -> Self { - let v1 = v1.into(); - let v2 = v2.into(); - if v1 < v2 { - Self { - segments: SmallVec::one((v1, Some(v2))), - } - } else { - Self::none() + /// Set of all versions lower or equal to some version + pub fn lower_than(v: impl Into) -> Self { + Self { + segments: SmallVec::one((Unbounded, Included(v.into()))), } } - /// Construct a simple range from anything that impls [RangeBounds] like `v1..v2`. - pub fn from_range_bounds(bounds: R) -> Self - where - R: RangeBounds, - for<'a> &'a IV: Into, - { - let start = match bounds.start_bound() { - Bound::Included(s) => s.into(), - Bound::Excluded(s) => s.into().bump(), - Bound::Unbounded => V::lowest(), - }; - let end = match bounds.end_bound() { - Bound::Included(e) => Some(e.into().bump()), - Bound::Excluded(e) => Some(e.into()), - Bound::Unbounded => None, - }; - if end.is_some() && end.as_ref() <= Some(&start) { - Self::none() - } else { - Self { - segments: SmallVec::one((start, end)), - } + /// Set of versions greater or equal to `v1` but less than `v2`. + pub fn between(v1: impl Into, v2: impl Into) -> Self { + Self { + segments: SmallVec::one((Included(v1.into()), Excluded(v2.into()))), } } } -// Set operations. -impl Range { - // Negate ################################################################## +impl Range { + /// Set containing exactly one version + pub fn exact(v: impl Into) -> Self { + let v = v.into(); + Self { + segments: SmallVec::one((Included(v.clone()), Included(v))), + } + } + + /// Set containing all versions expect one + pub fn not_equal(v: impl Into) -> Self { + let v = v.into(); + Self { + segments: SmallVec::Two([(Unbounded, Excluded(v.clone())), (Excluded(v), Unbounded)]), + } + } - /// Compute the complement set of versions. + /// Convert to something that can be used with + /// [BTreeMap::range](std::collections::BTreeMap::range). + /// All versions contained in self, will be in the output, + /// but there may be versions in the output that are not contained in self. + /// Returns None if the range is empty. + pub fn bounding_range(&self) -> Option<(Bound<&V>, Bound<&V>)> { + self.segments.first().map(|(start, _)| { + let end = self + .segments + .last() + .expect("if there is a first element, there must be a last element"); + (bounds_as_ref(start), bounds_as_ref(&end.1)) + }) + } + + /// Returns the complement of this Range. pub fn negate(&self) -> Self { match self.segments.first() { - None => Self::any(), // Complement of ∅ is * + // Complement of ∅ is ∞ + None => Self::any(), + + // Complement of ∞ is ∅ + Some((Unbounded, Unbounded)) => Self::none(), // First high bound is +∞ - Some((v, None)) => { - // Complement of * is ∅ - if v == &V::lowest() { - Self::none() - // Complement of "v <= _" is "_ < v" - } else { - Self::strictly_lower_than(v.clone()) - } - } + Some((Included(v), Unbounded)) => Self::strictly_lower_than(v.clone()), + Some((Excluded(v), Unbounded)) => Self::lower_than(v.clone()), - // First high bound is not +∞ - Some((v1, Some(v2))) => { - if v1 == &V::lowest() { - Self::negate_segments(v2.clone(), &self.segments[1..]) - } else { - Self::negate_segments(V::lowest(), &self.segments) - } + Some((Unbounded, Included(v))) => { + Self::negate_segments(Excluded(v.clone()), &self.segments[1..]) + } + Some((Unbounded, Excluded(v))) => { + Self::negate_segments(Included(v.clone()), &self.segments[1..]) } + Some((Included(_), Included(_))) + | Some((Included(_), Excluded(_))) + | Some((Excluded(_), Included(_))) + | Some((Excluded(_), Excluded(_))) => Self::negate_segments(Unbounded, &self.segments), } } /// Helper function performing the negation of intervals in segments. - /// For example: - /// [ (v1, None) ] => [ (start, Some(v1)) ] - /// [ (v1, Some(v2)) ] => [ (start, Some(v1)), (v2, None) ] - fn negate_segments(start: V, segments: &[Interval]) -> Range { - let mut complement_segments = SmallVec::empty(); - let mut start = Some(start); - for (v1, maybe_v2) in segments { - // start.unwrap() is fine because `segments` is not exposed, - // and our usage guaranties that only the last segment may contain a None. - complement_segments.push((start.unwrap(), Some(v1.to_owned()))); - start = maybe_v2.to_owned(); - } - if let Some(last) = start { - complement_segments.push((last, None)); + fn negate_segments(start: Bound, segments: &[Interval]) -> Self { + let mut complement_segments: SmallVec> = SmallVec::empty(); + let mut start = start; + for (v1, v2) in segments { + complement_segments.push(( + start, + match v1 { + Included(v) => Excluded(v.clone()), + Excluded(v) => Included(v.clone()), + Unbounded => unreachable!(), + }, + )); + start = match v2 { + Included(v) => Excluded(v.clone()), + Excluded(v) => Included(v.clone()), + Unbounded => Unbounded, + } + } + if !matches!(start, Unbounded) { + complement_segments.push((start, Unbounded)); } Self { segments: complement_segments, } } +} - // Union and intersection ################################################## +impl Range { + /// Returns true if the this Range contains the specified value. + pub fn contains(&self, v: &V) -> bool { + for segment in self.segments.iter() { + if match segment { + (Unbounded, Unbounded) => true, + (Unbounded, Included(end)) => v <= end, + (Unbounded, Excluded(end)) => v < end, + (Included(start), Unbounded) => v >= start, + (Included(start), Included(end)) => v >= start && v <= end, + (Included(start), Excluded(end)) => v >= start && v < end, + (Excluded(start), Unbounded) => v > start, + (Excluded(start), Included(end)) => v > start && v <= end, + (Excluded(start), Excluded(end)) => v > start && v < end, + } { + return true; + } + } + false + } - /// Compute the union of two sets of versions. + /// Construct a simple range from anything that impls [RangeBounds] like `v1..v2`. + pub fn from_range_bounds(bounds: R) -> Self + where + R: RangeBounds, + IV: Clone + Into + { + let start = match bounds.start_bound() { + Included(v) => Included(v.clone().into()), + Excluded(v) => Excluded(v.clone().into()), + Unbounded => Unbounded + }; + let end = match bounds.end_bound() { + Included(v) => Included(v.clone().into()), + Excluded(v) => Excluded(v.clone().into()), + Unbounded => Unbounded + }; + match (start, end) { + (Included(a), Included(b)) if b < a => Self::none(), + (Excluded(a), Excluded(b)) if b < a => Self::none(), + (Included(a), Excluded(b)) if b <= a => Self::none(), + (Excluded(a), Included(b)) if b <= a => Self::none(), + (a,b) => Self { + segments: SmallVec::one((a,b)) + } + } + } +} + +/// Implementation of [`Bounds::as_ref`] which is currently marked as unstable. +fn bounds_as_ref(bounds: &Bound) -> Bound<&V> { + match bounds { + Included(v) => Included(v), + Excluded(v) => Excluded(v), + Unbounded => Unbounded + } +} + +impl Range { + /// Computes the union of two sets of versions. pub fn union(&self, other: &Self) -> Self { self.negate().intersection(&other.negate()).negate() } - /// Compute the intersection of two sets of versions. + /// Computes the intersection of two sets of versions. pub fn intersection(&self, other: &Self) -> Self { - let mut segments = SmallVec::empty(); + let mut segments: SmallVec> = SmallVec::empty(); let mut left_iter = self.segments.iter(); let mut right_iter = other.segments.iter(); let mut left = left_iter.next(); let mut right = right_iter.next(); - loop { - match (left, right) { - // Both left and right still contain a finite interval: - (Some((l1, Some(l2))), Some((r1, Some(r2)))) => { - if l2 <= r1 { - // Intervals are disjoint, progress on the left. + while let (Some((left_lower, left_upper)), Some((right_lower, right_upper))) = (left, right) + { + // Check if the left range completely smaller than the right range. + if let ( + Included(left_upper_version) | Excluded(left_upper_version), + Included(right_lower_version) | Excluded(right_lower_version), + ) = (left_upper, right_lower) + { + match left_upper_version.cmp(right_lower_version) { + Ordering::Less => { + // Left range is disjoint from the right range. left = left_iter.next(); - } else if r2 <= l1 { - // Intervals are disjoint, progress on the right. - right = right_iter.next(); - } else { - // Intervals are not disjoint. - let start = l1.max(r1).to_owned(); - if l2 < r2 { - segments.push((start, Some(l2.to_owned()))); + continue; + } + Ordering::Equal => { + if !matches!((left_upper, right_lower), (Included(_), Included(_))) { + // Left and right are overlapping exactly, but one of the bounds is exclusive, therefor the ranges are disjoint left = left_iter.next(); - } else { - segments.push((start, Some(r2.to_owned()))); - right = right_iter.next(); + continue; } } + Ordering::Greater => { + // Left upper bound is greater than right lower bound, so the lower bound is the right lower bound + } } - - // Right contains an infinite interval: - (Some((l1, Some(l2))), Some((r1, None))) => match l2.cmp(r1) { + } + // Check if the right range completely smaller than the left range. + if let ( + Included(left_lower_version) | Excluded(left_lower_version), + Included(right_upper_version) | Excluded(right_upper_version), + ) = (left_lower, right_upper) + { + match right_upper_version.cmp(left_lower_version) { Ordering::Less => { - left = left_iter.next(); + // Right range is disjoint from the left range. + right = right_iter.next(); + continue; } Ordering::Equal => { - for l in left_iter.cloned() { - segments.push(l) + if !matches!((right_upper, left_lower), (Included(_), Included(_))) { + // Left and right are overlapping exactly, but one of the bounds is exclusive, therefor the ranges are disjoint + right = right_iter.next(); + continue; } - break; } Ordering::Greater => { - let start = l1.max(r1).to_owned(); - segments.push((start, Some(l2.to_owned()))); - for l in left_iter.cloned() { - segments.push(l) - } - break; + // Right upper bound is greater than left lower bound, so the lower bound is the left lower bound } + } + } + + // At this point we know there is an overlap between the versions, find the lowest bound + let lower = match (left_lower, right_lower) { + (Unbounded, Included(_) | Excluded(_)) => right_lower.clone(), + (Included(_) | Excluded(_), Unbounded) => left_lower.clone(), + (Unbounded, Unbounded) => Unbounded, + (Included(l) | Excluded(l), Included(r) | Excluded(r)) => match l.cmp(r) { + Ordering::Less => right_lower.clone(), + Ordering::Equal => match (left_lower, right_lower) { + (Included(_), Excluded(v)) => Excluded(v.clone()), + (Excluded(_), Excluded(v)) => Excluded(v.clone()), + (Excluded(v), Included(_)) => Excluded(v.clone()), + (Included(_), Included(v)) => Included(v.clone()), + _ => unreachable!(), + }, + Ordering::Greater => left_lower.clone(), }, + }; - // Left contains an infinite interval: - (Some((l1, None)), Some((r1, Some(r2)))) => match r2.cmp(l1) { + // At this point we know there is an overlap between the versions, find the lowest bound + let upper = match (left_upper, right_upper) { + (Unbounded, Included(_) | Excluded(_)) => { + right = right_iter.next(); + right_upper.clone() + } + (Included(_) | Excluded(_), Unbounded) => { + left = left_iter.next(); + left_upper.clone() + } + (Unbounded, Unbounded) => { + left = left_iter.next(); + right = right_iter.next(); + Unbounded + } + (Included(l) | Excluded(l), Included(r) | Excluded(r)) => match l.cmp(r) { Ordering::Less => { - right = right_iter.next(); + left = left_iter.next(); + left_upper.clone() } - Ordering::Equal => { - for r in right_iter.cloned() { - segments.push(r) + Ordering::Equal => match (left_upper, right_upper) { + (Included(_), Excluded(v)) => { + right = right_iter.next(); + Excluded(v.clone()) } - break; - } - Ordering::Greater => { - let start = l1.max(r1).to_owned(); - segments.push((start, Some(r2.to_owned()))); - for r in right_iter.cloned() { - segments.push(r) + (Excluded(_), Excluded(v)) => { + left = left_iter.next(); + right = right_iter.next(); + Excluded(v.clone()) + } + (Excluded(v), Included(_)) => { + left = left_iter.next(); + Excluded(v.clone()) } - break; + (Included(_), Included(v)) => { + left = left_iter.next(); + right = right_iter.next(); + Included(v.clone()) + } + _ => unreachable!(), + }, + Ordering::Greater => { + right = right_iter.next(); + right_upper.clone() } }, + }; - // Both sides contain an infinite interval: - (Some((l1, None)), Some((r1, None))) => { - let start = l1.max(r1).to_owned(); - segments.push((start, None)); - break; - } - - // Left or right has ended. - _ => { - break; - } - } + segments.push((lower, upper)); } Self { segments } } } -// Other useful functions. -impl Range { - /// Check if a range contains a given version. - pub fn contains(&self, version: &V) -> bool { - for (v1, maybe_v2) in &self.segments { - match maybe_v2 { - None => return v1 <= version, - Some(v2) => { - if version < v1 { - return false; - } else if version < v2 { - return true; - } - } - } - } - false +impl VersionSet for Range { + type V = T; + + fn empty() -> Self { + Range::none() } - /// Return the lowest version in the range (if there is one). - pub fn lowest_version(&self) -> Option { - self.segments.first().map(|(start, _)| start).cloned() + fn singleton(v: Self::V) -> Self { + Range::exact(v) } - /// Convert to something that can be used with - /// [BTreeMap::range](std::collections::BTreeMap::range). - /// All versions contained in self, will be in the output, - /// but there may be versions in the output that are not contained in self. - /// Returns None if the range is empty. - pub fn bounding_range(&self) -> Option<(Bound<&V>, Bound<&V>)> { - self.segments.first().map(|(start, _)| { - let end = { - self.segments - .last() - .and_then(|(_, l)| l.as_ref()) - .map(Bound::Excluded) - .unwrap_or(Bound::Unbounded) - }; - (Bound::Included(start), end) - }) + fn complement(&self) -> Self { + Range::negate(self) + } + + fn intersection(&self, other: &Self) -> Self { + Range::intersection(self, other) + } + + fn contains(&self, v: &Self::V) -> bool { + Range::contains(self, v) + } + + fn full() -> Self { + Range::any() + } + + fn union(&self, other: &Self) -> Self { + Range::union(self, other) } } // REPORT ###################################################################### -impl fmt::Display for Range { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.segments.as_slice() { - [] => write!(f, "∅"), - [(start, None)] if start == &V::lowest() => write!(f, "∗"), - [(start, None)] => write!(f, "{} <= v", start), - [(start, Some(end))] if end == &start.bump() => write!(f, "{}", start), - [(start, Some(end))] if start == &V::lowest() => write!(f, "v < {}", end), - [(start, Some(end))] => write!(f, "{} <= v < {}", start, end), - more_than_one_interval => { - let string_intervals: Vec<_> = more_than_one_interval - .iter() - .map(interval_to_string) - .collect(); - write!(f, "{}", string_intervals.join(" ")) +impl Display for Range { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + if self.segments.is_empty() { + write!(f, "∅")?; + } else { + for (idx, segment) in self.segments.iter().enumerate() { + if idx > 0 { + write!(f, ", ")?; + } + match segment { + (Unbounded, Unbounded) => write!(f, "*")?, + (Unbounded, Included(v)) => write!(f, "<={v}")?, + (Unbounded, Excluded(v)) => write!(f, "<{v}")?, + (Included(v), Unbounded) => write!(f, ">={v}")?, + (Included(v), Included(b)) => { + if v == b { + write!(f, "{v}")? + } else { + write!(f, ">={v},<={b}")? + } + } + (Included(v), Excluded(b)) => write!(f, ">={v}, <{b}")?, + (Excluded(v), Unbounded) => write!(f, ">{v}")?, + (Excluded(v), Included(b)) => write!(f, ">{v}, <={b}")?, + (Excluded(v), Excluded(b)) => write!(f, ">{v}, <{b}")?, + }; } } - } -} - -fn interval_to_string((start, maybe_end): &Interval) -> String { - match maybe_end { - Some(end) => format!("[ {}, {} [", start, end), - None => format!("[ {}, ∞ [", start), + Ok(()) } } @@ -363,29 +437,61 @@ fn interval_to_string((start, maybe_end): &Interval) -> String { #[cfg(test)] pub mod tests { use proptest::prelude::*; - - use crate::version::NumberVersion; + use proptest::test_runner::TestRng; use super::*; - pub fn strategy() -> impl Strategy> { - prop::collection::vec(any::(), 0..10).prop_map(|mut vec| { - vec.sort_unstable(); - vec.dedup(); - let mut pair_iter = vec.chunks_exact(2); - let mut segments = SmallVec::empty(); - while let Some([v1, v2]) = pair_iter.next() { - segments.push((NumberVersion(*v1), Some(NumberVersion(*v2)))); - } - if let [v] = pair_iter.remainder() { - segments.push((NumberVersion(*v), None)); - } - Range { segments } - }) + pub fn strategy() -> impl Strategy> { + prop::collection::vec(any::(), 0..10) + .prop_map(|mut vec| { + vec.sort_unstable(); + vec.dedup(); + vec + }) + .prop_perturb(|vec, mut rng| { + let mut segments = SmallVec::empty(); + let mut iter = vec.into_iter().peekable(); + if let Some(first) = iter.next() { + fn next_bound>( + iter: &mut I, + rng: &mut TestRng, + ) -> Bound { + if let Some(next) = iter.next() { + if rng.gen_bool(0.5) { + Included(next) + } else { + Excluded(next) + } + } else { + Unbounded + } + } + + let start = if rng.gen_bool(0.3) { + Unbounded + } else { + if rng.gen_bool(0.5) { + Included(first) + } else { + Excluded(first) + } + }; + + let end = next_bound(&mut iter, &mut rng); + segments.push((start, end)); + + while iter.peek().is_some() { + let start = next_bound(&mut iter, &mut rng); + let end = next_bound(&mut iter, &mut rng); + segments.push((start, end)); + } + } + return Range { segments }; + }) } - fn version_strat() -> impl Strategy { - any::().prop_map(NumberVersion) + fn version_strat() -> impl Strategy { + any::() } proptest! { @@ -482,14 +588,14 @@ pub mod tests { #[test] fn from_range_bounds(range in any::<(Bound, Bound)>(), version in version_strat()) { - let rv: Range = Range::from_range_bounds(range); - assert_eq!(range.contains(&version.0), rv.contains(&version)); + let rv: Range = Range::from_range_bounds(range); + assert_eq!(range.contains(&version), rv.contains(&version)); } #[test] fn from_range_bounds_round_trip(range in any::<(Bound, Bound)>()) { - let rv: Range = Range::from_range_bounds(range); - let rv2: Range = rv.bounding_range().map(Range::from_range_bounds::<_, NumberVersion>).unwrap_or_else(Range::none); + let rv: Range = Range::from_range_bounds(range); + let rv2: Range = rv.bounding_range().map(Range::from_range_bounds::<_, u32>).unwrap_or_else(Range::none); assert_eq!(rv, rv2); } } diff --git a/src/term.rs b/src/term.rs index 3028dbe1..cf7aa6f7 100644 --- a/src/term.rs +++ b/src/term.rs @@ -182,10 +182,9 @@ impl Display for Term { pub mod tests { use super::*; use crate::range::Range; - use crate::version::NumberVersion; use proptest::prelude::*; - pub fn strategy() -> impl Strategy>> { + pub fn strategy() -> impl Strategy>> { prop_oneof![ crate::range::tests::strategy().prop_map(Term::Positive), crate::range::tests::strategy().prop_map(Term::Negative), From d3e0c22fe4918e8f0f440192ce1e2450a78f1cde Mon Sep 17 00:00:00 2001 From: Bas Zalmstra Date: Sat, 21 May 2022 22:34:20 +0200 Subject: [PATCH 2/4] fix: formatting and doc comment --- src/range.rs | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/range.rs b/src/range.rs index 28f7b016..b7ee42d6 100644 --- a/src/range.rs +++ b/src/range.rs @@ -15,12 +15,12 @@ //! - [between(v1, v2)](Range::between): the set defined by `v1 <= versions < v2` use crate::{internal::small_vec::SmallVec, version_set::VersionSet}; +use std::ops::RangeBounds; use std::{ cmp::Ordering, fmt::{Debug, Display, Formatter}, ops::Bound::{self, Excluded, Included, Unbounded}, }; -use std::ops::RangeBounds; /// A Range represents multiple intervals of a continuous range of monotone increasing /// values. @@ -194,38 +194,38 @@ impl Range { /// Construct a simple range from anything that impls [RangeBounds] like `v1..v2`. pub fn from_range_bounds(bounds: R) -> Self - where - R: RangeBounds, - IV: Clone + Into + where + R: RangeBounds, + IV: Clone + Into, { let start = match bounds.start_bound() { Included(v) => Included(v.clone().into()), Excluded(v) => Excluded(v.clone().into()), - Unbounded => Unbounded + Unbounded => Unbounded, }; let end = match bounds.end_bound() { Included(v) => Included(v.clone().into()), Excluded(v) => Excluded(v.clone().into()), - Unbounded => Unbounded + Unbounded => Unbounded, }; match (start, end) { (Included(a), Included(b)) if b < a => Self::none(), (Excluded(a), Excluded(b)) if b < a => Self::none(), (Included(a), Excluded(b)) if b <= a => Self::none(), (Excluded(a), Included(b)) if b <= a => Self::none(), - (a,b) => Self { - segments: SmallVec::one((a,b)) - } + (a, b) => Self { + segments: SmallVec::one((a, b)), + }, } } } -/// Implementation of [`Bounds::as_ref`] which is currently marked as unstable. +/// Implementation of [`Bound::as_ref`] which is currently marked as unstable. fn bounds_as_ref(bounds: &Bound) -> Bound<&V> { match bounds { Included(v) => Included(v), Excluded(v) => Excluded(v), - Unbounded => Unbounded + Unbounded => Unbounded, } } From e3421624a79dd5ee32462a1bd900653c083c26c2 Mon Sep 17 00:00:00 2001 From: Bas Zalmstra Date: Sat, 21 May 2022 22:56:20 +0200 Subject: [PATCH 3/4] chore: add both DiscreteRange and BoundedRange --- examples/branching_error_reporting.rs | 24 +- examples/caching_dependency_provider.rs | 4 +- examples/doc_interface.rs | 10 +- examples/doc_interface_error.rs | 32 +- examples/doc_interface_semantic.rs | 28 +- examples/linear_error_reporting.rs | 16 +- src/{range.rs => bounded_range.rs} | 50 +- src/discrete_range.rs | 496 ++ src/internal/incompatibility.rs | 6 +- src/lib.rs | 21 +- src/solver.rs | 4 +- src/term.rs | 8 +- .../large_case_u16_bounded_NumberVersion.ron | 5524 +++++++++++++++++ ...large_case_u16_discrete_NumberVersion.ron} | 0 tests/examples.rs | 66 +- tests/proptest.rs | 38 +- tests/tests.rs | 18 +- 17 files changed, 6194 insertions(+), 151 deletions(-) rename src/{range.rs => bounded_range.rs} (93%) create mode 100644 src/discrete_range.rs create mode 100644 test-examples/large_case_u16_bounded_NumberVersion.ron rename test-examples/{large_case_u16_NumberVersion.ron => large_case_u16_discrete_NumberVersion.ron} (100%) diff --git a/examples/branching_error_reporting.rs b/examples/branching_error_reporting.rs index d4dfb719..682e725b 100644 --- a/examples/branching_error_reporting.rs +++ b/examples/branching_error_reporting.rs @@ -1,12 +1,12 @@ // SPDX-License-Identifier: MPL-2.0 +use pubgrub::bounded_range::BoundedRange; use pubgrub::error::PubGrubError; -use pubgrub::range::Range; use pubgrub::report::{DefaultStringReporter, Reporter}; use pubgrub::solver::{resolve, OfflineDependencyProvider}; use pubgrub::version::SemanticVersion; -type SemVS = Range; +type SemVS = BoundedRange; // https://github.com/dart-lang/pub/blob/master/doc/solver.md#branching-error-reporting fn main() { @@ -14,16 +14,16 @@ fn main() { #[rustfmt::skip] // root 1.0.0 depends on foo ^1.0.0 dependency_provider.add_dependencies( - "root", (1, 0, 0), - [("foo", Range::from_range_bounds((1, 0, 0)..(2, 0, 0)))], + "root", (1, 0, 0), + [("foo", BoundedRange::from_range_bounds((1, 0, 0)..(2, 0, 0)))], ); #[rustfmt::skip] // foo 1.0.0 depends on a ^1.0.0 and b ^1.0.0 dependency_provider.add_dependencies( "foo", (1, 0, 0), [ - ("a", Range::from_range_bounds((1, 0, 0)..(2, 0, 0))), - ("b", Range::from_range_bounds((1, 0, 0)..(2, 0, 0))), + ("a", BoundedRange::from_range_bounds((1, 0, 0)..(2, 0, 0))), + ("b", BoundedRange::from_range_bounds((1, 0, 0)..(2, 0, 0))), ], ); #[rustfmt::skip] @@ -31,15 +31,15 @@ fn main() { dependency_provider.add_dependencies( "foo", (1, 1, 0), [ - ("x", Range::from_range_bounds((1, 0, 0)..(2, 0, 0))), - ("y", Range::from_range_bounds((1, 0, 0)..(2, 0, 0))), + ("x", BoundedRange::from_range_bounds((1, 0, 0)..(2, 0, 0))), + ("y", BoundedRange::from_range_bounds((1, 0, 0)..(2, 0, 0))), ], ); #[rustfmt::skip] // a 1.0.0 depends on b ^2.0.0 dependency_provider.add_dependencies( - "a", (1, 0, 0), - [("b", Range::from_range_bounds((2, 0, 0)..(3, 0, 0)))], + "a", (1, 0, 0), + [("b", BoundedRange::from_range_bounds((2, 0, 0)..(3, 0, 0)))], ); // b 1.0.0 and 2.0.0 have no dependencies. dependency_provider.add_dependencies("b", (1, 0, 0), []); @@ -47,8 +47,8 @@ fn main() { #[rustfmt::skip] // x 1.0.0 depends on y ^2.0.0. dependency_provider.add_dependencies( - "x", (1, 0, 0), - [("y", Range::from_range_bounds((2, 0, 0)..(3, 0, 0)))], + "x", (1, 0, 0), + [("y", BoundedRange::from_range_bounds((2, 0, 0)..(3, 0, 0)))], ); // y 1.0.0 and 2.0.0 have no dependencies. dependency_provider.add_dependencies("y", (1, 0, 0), []); diff --git a/examples/caching_dependency_provider.rs b/examples/caching_dependency_provider.rs index cb278942..5b3c2836 100644 --- a/examples/caching_dependency_provider.rs +++ b/examples/caching_dependency_provider.rs @@ -3,13 +3,13 @@ use std::cell::RefCell; use std::error::Error; +use pubgrub::bounded_range::BoundedRange; use pubgrub::package::Package; -use pubgrub::range::Range; use pubgrub::solver::{resolve, Dependencies, DependencyProvider, OfflineDependencyProvider}; use pubgrub::version::NumberVersion; use pubgrub::version_set::VersionSet; -type NumVS = Range; +type NumVS = BoundedRange; // An example implementing caching dependency provider that will // store queried dependencies in memory and check them before querying more from remote. diff --git a/examples/doc_interface.rs b/examples/doc_interface.rs index d409dcce..768bcb09 100644 --- a/examples/doc_interface.rs +++ b/examples/doc_interface.rs @@ -1,10 +1,10 @@ // SPDX-License-Identifier: MPL-2.0 -use pubgrub::range::Range; +use pubgrub::bounded_range::BoundedRange; use pubgrub::solver::{resolve, OfflineDependencyProvider}; use pubgrub::version::NumberVersion; -type NumVS = Range; +type NumVS = BoundedRange; // `root` depends on `menu` and `icons` // `menu` depends on `dropdown` @@ -14,10 +14,10 @@ type NumVS = Range; fn main() { let mut dependency_provider = OfflineDependencyProvider::<&str, NumVS>::new(); dependency_provider.add_dependencies( - "root", 1, [("menu", Range::any()), ("icons", Range::any())], + "root", 1, [("menu", BoundedRange::any()), ("icons", BoundedRange::any())], ); - dependency_provider.add_dependencies("menu", 1, [("dropdown", Range::any())]); - dependency_provider.add_dependencies("dropdown", 1, [("icons", Range::any())]); + dependency_provider.add_dependencies("menu", 1, [("dropdown", BoundedRange::any())]); + dependency_provider.add_dependencies("dropdown", 1, [("icons", BoundedRange::any())]); dependency_provider.add_dependencies("icons", 1, []); // Run the algorithm. diff --git a/examples/doc_interface_error.rs b/examples/doc_interface_error.rs index a3d7e61e..77bac976 100644 --- a/examples/doc_interface_error.rs +++ b/examples/doc_interface_error.rs @@ -1,12 +1,12 @@ // SPDX-License-Identifier: MPL-2.0 +use pubgrub::bounded_range::BoundedRange; use pubgrub::error::PubGrubError; -use pubgrub::range::Range; use pubgrub::report::{DefaultStringReporter, Reporter}; use pubgrub::solver::{resolve, OfflineDependencyProvider}; use pubgrub::version::SemanticVersion; -type SemVS = Range; +type SemVS = BoundedRange; // `root` depends on `menu`, `icons 1.0.0` and `intl 5.0.0` // `menu 1.0.0` depends on `dropdown < 2.0.0` @@ -20,46 +20,46 @@ fn main() { let mut dependency_provider = OfflineDependencyProvider::<&str, SemVS>::new(); // Direct dependencies: menu and icons. dependency_provider.add_dependencies("root", (1, 0, 0), [ - ("menu", Range::any()), - ("icons", Range::exact((1, 0, 0))), - ("intl", Range::exact((5, 0, 0))), + ("menu", BoundedRange::any()), + ("icons", BoundedRange::exact((1, 0, 0))), + ("intl", BoundedRange::exact((5, 0, 0))), ]); // Dependencies of the menu lib. dependency_provider.add_dependencies("menu", (1, 0, 0), [ - ("dropdown", Range::from_range_bounds(..(2, 0, 0))), + ("dropdown", BoundedRange::from_range_bounds(..(2, 0, 0))), ]); dependency_provider.add_dependencies("menu", (1, 1, 0), [ - ("dropdown", Range::from_range_bounds((2, 0, 0)..)), + ("dropdown", BoundedRange::from_range_bounds((2, 0, 0)..)), ]); dependency_provider.add_dependencies("menu", (1, 2, 0), [ - ("dropdown", Range::from_range_bounds((2, 0, 0)..)), + ("dropdown", BoundedRange::from_range_bounds((2, 0, 0)..)), ]); dependency_provider.add_dependencies("menu", (1, 3, 0), [ - ("dropdown", Range::from_range_bounds((2, 0, 0)..)), + ("dropdown", BoundedRange::from_range_bounds((2, 0, 0)..)), ]); dependency_provider.add_dependencies("menu", (1, 4, 0), [ - ("dropdown", Range::from_range_bounds((2, 0, 0)..)), + ("dropdown", BoundedRange::from_range_bounds((2, 0, 0)..)), ]); dependency_provider.add_dependencies("menu", (1, 5, 0), [ - ("dropdown", Range::from_range_bounds((2, 0, 0)..)), + ("dropdown", BoundedRange::from_range_bounds((2, 0, 0)..)), ]); // Dependencies of the dropdown lib. dependency_provider.add_dependencies("dropdown", (1, 8, 0), [ - ("intl", Range::exact((3, 0, 0))), + ("intl", BoundedRange::exact((3, 0, 0))), ]); dependency_provider.add_dependencies("dropdown", (2, 0, 0), [ - ("icons", Range::exact((2, 0, 0))), + ("icons", BoundedRange::exact((2, 0, 0))), ]); dependency_provider.add_dependencies("dropdown", (2, 1, 0), [ - ("icons", Range::exact((2, 0, 0))), + ("icons", BoundedRange::exact((2, 0, 0))), ]); dependency_provider.add_dependencies("dropdown", (2, 2, 0), [ - ("icons", Range::exact((2, 0, 0))), + ("icons", BoundedRange::exact((2, 0, 0))), ]); dependency_provider.add_dependencies("dropdown", (2, 3, 0), [ - ("icons", Range::exact((2, 0, 0))), + ("icons", BoundedRange::exact((2, 0, 0))), ]); // Icons have no dependencies. diff --git a/examples/doc_interface_semantic.rs b/examples/doc_interface_semantic.rs index cce059bc..ea823b87 100644 --- a/examples/doc_interface_semantic.rs +++ b/examples/doc_interface_semantic.rs @@ -1,12 +1,12 @@ // SPDX-License-Identifier: MPL-2.0 +use pubgrub::bounded_range::BoundedRange; use pubgrub::error::PubGrubError; -use pubgrub::range::Range; use pubgrub::report::{DefaultStringReporter, Reporter}; use pubgrub::solver::{resolve, OfflineDependencyProvider}; use pubgrub::version::SemanticVersion; -type SemVS = Range; +type SemVS = BoundedRange; // `root` depends on `menu` and `icons 1.0.0` // `menu 1.0.0` depends on `dropdown < 2.0.0` @@ -19,43 +19,43 @@ fn main() { let mut dependency_provider = OfflineDependencyProvider::<&str, SemVS>::new(); // Direct dependencies: menu and icons. dependency_provider.add_dependencies("root", (1, 0, 0), [ - ("menu", Range::any()), - ("icons", Range::exact((1, 0, 0))), + ("menu", BoundedRange::any()), + ("icons", BoundedRange::exact((1, 0, 0))), ]); // Dependencies of the menu lib. dependency_provider.add_dependencies("menu", (1, 0, 0), [ - ("dropdown", Range::from_range_bounds(..(2, 0, 0))), + ("dropdown", BoundedRange::from_range_bounds(..(2, 0, 0))), ]); dependency_provider.add_dependencies("menu", (1, 1, 0), [ - ("dropdown", Range::from_range_bounds((2, 0, 0)..)), + ("dropdown", BoundedRange::from_range_bounds((2, 0, 0)..)), ]); dependency_provider.add_dependencies("menu", (1, 2, 0), [ - ("dropdown", Range::from_range_bounds((2, 0, 0)..)), + ("dropdown", BoundedRange::from_range_bounds((2, 0, 0)..)), ]); dependency_provider.add_dependencies("menu", (1, 3, 0), [ - ("dropdown", Range::from_range_bounds((2, 0, 0)..)), + ("dropdown", BoundedRange::from_range_bounds((2, 0, 0)..)), ]); dependency_provider.add_dependencies("menu", (1, 4, 0), [ - ("dropdown", Range::from_range_bounds((2, 0, 0)..)), + ("dropdown", BoundedRange::from_range_bounds((2, 0, 0)..)), ]); dependency_provider.add_dependencies("menu", (1, 5, 0), [ - ("dropdown", Range::from_range_bounds((2, 0, 0)..)), + ("dropdown", BoundedRange::from_range_bounds((2, 0, 0)..)), ]); // Dependencies of the dropdown lib. dependency_provider.add_dependencies("dropdown", (1, 8, 0), []); dependency_provider.add_dependencies("dropdown", (2, 0, 0), [ - ("icons", Range::exact((2, 0, 0))), + ("icons", BoundedRange::exact((2, 0, 0))), ]); dependency_provider.add_dependencies("dropdown", (2, 1, 0), [ - ("icons", Range::exact((2, 0, 0))), + ("icons", BoundedRange::exact((2, 0, 0))), ]); dependency_provider.add_dependencies("dropdown", (2, 2, 0), [ - ("icons", Range::exact((2, 0, 0))), + ("icons", BoundedRange::exact((2, 0, 0))), ]); dependency_provider.add_dependencies("dropdown", (2, 3, 0), [ - ("icons", Range::exact((2, 0, 0))), + ("icons", BoundedRange::exact((2, 0, 0))), ]); // Icons has no dependency. diff --git a/examples/linear_error_reporting.rs b/examples/linear_error_reporting.rs index 8624fe2a..32f1d4d2 100644 --- a/examples/linear_error_reporting.rs +++ b/examples/linear_error_reporting.rs @@ -1,12 +1,12 @@ // SPDX-License-Identifier: MPL-2.0 +use pubgrub::bounded_range::BoundedRange; use pubgrub::error::PubGrubError; -use pubgrub::range::Range; use pubgrub::report::{DefaultStringReporter, Reporter}; use pubgrub::solver::{resolve, OfflineDependencyProvider}; use pubgrub::version::SemanticVersion; -type SemVS = Range; +type SemVS = BoundedRange; // https://github.com/dart-lang/pub/blob/master/doc/solver.md#linear-error-reporting fn main() { @@ -16,21 +16,21 @@ fn main() { dependency_provider.add_dependencies( "root", (1, 0, 0), [ - ("foo", Range::from_range_bounds((1, 0, 0)..(2, 0, 0))), - ("baz", Range::from_range_bounds((1, 0, 0)..(2, 0, 0))), + ("foo", BoundedRange::from_range_bounds((1, 0, 0)..(2, 0, 0))), + ("baz", BoundedRange::from_range_bounds((1, 0, 0)..(2, 0, 0))), ], ); #[rustfmt::skip] // foo 1.0.0 depends on bar ^2.0.0 dependency_provider.add_dependencies( - "foo", (1, 0, 0), - [("bar", Range::from_range_bounds((2, 0, 0)..(3, 0, 0)))], + "foo", (1, 0, 0), + [("bar", BoundedRange::from_range_bounds((2, 0, 0)..(3, 0, 0)))], ); #[rustfmt::skip] // bar 2.0.0 depends on baz ^3.0.0 dependency_provider.add_dependencies( - "bar", (2, 0, 0), - [("baz", Range::from_range_bounds((3, 0, 0)..(4, 0, 0)))], + "bar", (2, 0, 0), + [("baz", BoundedRange::from_range_bounds((3, 0, 0)..(4, 0, 0)))], ); // baz 1.0.0 and 3.0.0 have no dependencies dependency_provider.add_dependencies("baz", (1, 0, 0), []); diff --git a/src/range.rs b/src/bounded_range.rs similarity index 93% rename from src/range.rs rename to src/bounded_range.rs index b7ee42d6..14da412d 100644 --- a/src/range.rs +++ b/src/bounded_range.rs @@ -27,13 +27,13 @@ use std::{ #[derive(Debug, Clone, Eq, PartialEq, Hash)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", serde(transparent))] -pub struct Range { +pub struct BoundedRange { segments: SmallVec>, } type Interval = (Bound, Bound); -impl Range { +impl BoundedRange { /// Empty set of versions. pub fn none() -> Self { Self { @@ -84,7 +84,7 @@ impl Range { } } -impl Range { +impl BoundedRange { /// Set containing exactly one version pub fn exact(v: impl Into) -> Self { let v = v.into(); @@ -171,7 +171,7 @@ impl Range { } } -impl Range { +impl BoundedRange { /// Returns true if the this Range contains the specified value. pub fn contains(&self, v: &V) -> bool { for segment in self.segments.iter() { @@ -229,7 +229,7 @@ fn bounds_as_ref(bounds: &Bound) -> Bound<&V> { } } -impl Range { +impl BoundedRange { /// Computes the union of two sets of versions. pub fn union(&self, other: &Self) -> Self { self.negate().intersection(&other.negate()).negate() @@ -366,41 +366,41 @@ impl Range { } } -impl VersionSet for Range { +impl VersionSet for BoundedRange { type V = T; fn empty() -> Self { - Range::none() + BoundedRange::none() } fn singleton(v: Self::V) -> Self { - Range::exact(v) + BoundedRange::exact(v) } fn complement(&self) -> Self { - Range::negate(self) + BoundedRange::negate(self) } fn intersection(&self, other: &Self) -> Self { - Range::intersection(self, other) + BoundedRange::intersection(self, other) } fn contains(&self, v: &Self::V) -> bool { - Range::contains(self, v) + BoundedRange::contains(self, v) } fn full() -> Self { - Range::any() + BoundedRange::any() } fn union(&self, other: &Self) -> Self { - Range::union(self, other) + BoundedRange::union(self, other) } } // REPORT ###################################################################### -impl Display for Range { +impl Display for BoundedRange { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { if self.segments.is_empty() { write!(f, "∅")?; @@ -441,7 +441,7 @@ pub mod tests { use super::*; - pub fn strategy() -> impl Strategy> { + pub fn strategy() -> impl Strategy> { prop::collection::vec(any::(), 0..10) .prop_map(|mut vec| { vec.sort_unstable(); @@ -486,7 +486,7 @@ pub mod tests { segments.push((start, end)); } } - return Range { segments }; + return BoundedRange { segments }; }) } @@ -522,12 +522,12 @@ pub mod tests { #[test] fn intersection_with_any_is_identity(range in strategy()) { - assert_eq!(Range::any().intersection(&range), range); + assert_eq!(BoundedRange::any().intersection(&range), range); } #[test] fn intersection_with_none_is_none(range in strategy()) { - assert_eq!(Range::none().intersection(&range), Range::none()); + assert_eq!(BoundedRange::none().intersection(&range), BoundedRange::none()); } #[test] @@ -542,7 +542,7 @@ pub mod tests { #[test] fn intesection_of_complements_is_none(range in strategy()) { - assert_eq!(range.negate().intersection(&range), Range::none()); + assert_eq!(range.negate().intersection(&range), BoundedRange::none()); } #[test] @@ -554,7 +554,7 @@ pub mod tests { #[test] fn union_of_complements_is_any(range in strategy()) { - assert_eq!(range.negate().union(&range), Range::any()); + assert_eq!(range.negate().union(&range), BoundedRange::any()); } #[test] @@ -566,7 +566,7 @@ pub mod tests { #[test] fn always_contains_exact(version in version_strat()) { - assert!(Range::exact(version).contains(&version)); + assert!(BoundedRange::exact(version).contains(&version)); } #[test] @@ -576,7 +576,7 @@ pub mod tests { #[test] fn contains_intersection(range in strategy(), version in version_strat()) { - assert_eq!(range.contains(&version), range.intersection(&Range::exact(version)) != Range::none()); + assert_eq!(range.contains(&version), range.intersection(&BoundedRange::exact(version)) != BoundedRange::none()); } #[test] @@ -588,14 +588,14 @@ pub mod tests { #[test] fn from_range_bounds(range in any::<(Bound, Bound)>(), version in version_strat()) { - let rv: Range = Range::from_range_bounds(range); + let rv: BoundedRange = BoundedRange::from_range_bounds(range); assert_eq!(range.contains(&version), rv.contains(&version)); } #[test] fn from_range_bounds_round_trip(range in any::<(Bound, Bound)>()) { - let rv: Range = Range::from_range_bounds(range); - let rv2: Range = rv.bounding_range().map(Range::from_range_bounds::<_, u32>).unwrap_or_else(Range::none); + let rv: BoundedRange = BoundedRange::from_range_bounds(range); + let rv2: BoundedRange = rv.bounding_range().map(BoundedRange::from_range_bounds::<_, u32>).unwrap_or_else(BoundedRange::none); assert_eq!(rv, rv2); } } diff --git a/src/discrete_range.rs b/src/discrete_range.rs new file mode 100644 index 00000000..229f25da --- /dev/null +++ b/src/discrete_range.rs @@ -0,0 +1,496 @@ +// SPDX-License-Identifier: MPL-2.0 + +//! Ranges are constraints defining sets of versions. +//! +//! Concretely, those constraints correspond to any set of versions +//! representable as the concatenation, union, and complement +//! of the ranges building blocks. +//! +//! Those building blocks are: +//! - [none()](Range::none): the empty set +//! - [any()](Range::any): the set of all possible versions +//! - [exact(v)](Range::exact): the set containing only the version v +//! - [higher_than(v)](Range::higher_than): the set defined by `v <= versions` +//! - [strictly_lower_than(v)](Range::strictly_lower_than): the set defined by `versions < v` +//! - [between(v1, v2)](Range::between): the set defined by `v1 <= versions < v2` + +use std::cmp::Ordering; +use std::fmt; +use std::ops::{Bound, RangeBounds}; + +use crate::internal::small_vec::SmallVec; +use crate::version::Version; +use crate::version_set::VersionSet; + +impl VersionSet for DiscreteRange { + type V = V; + // Constructors + fn empty() -> Self { + DiscreteRange::none() + } + fn singleton(v: Self::V) -> Self { + DiscreteRange::exact(v) + } + // Operations + fn complement(&self) -> Self { + self.negate() + } + fn intersection(&self, other: &Self) -> Self { + self.intersection(other) + } + // Membership + fn contains(&self, v: &Self::V) -> bool { + self.contains(v) + } +} + +/// A Range is a set of versions. +#[derive(Debug, Clone, Eq, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(transparent))] +pub struct DiscreteRange { + segments: SmallVec>, +} + +type Interval = (V, Option); + +// Range building blocks. +impl DiscreteRange { + /// Empty set of versions. + pub fn none() -> Self { + Self { + segments: SmallVec::empty(), + } + } + + /// Set of all possible versions. + pub fn any() -> Self { + Self::higher_than(V::lowest()) + } + + /// Set containing exactly one version. + pub fn exact(v: impl Into) -> Self { + let v = v.into(); + Self { + segments: SmallVec::one((v.clone(), Some(v.bump()))), + } + } + + /// Set of all versions higher or equal to some version. + pub fn higher_than(v: impl Into) -> Self { + Self { + segments: SmallVec::one((v.into(), None)), + } + } + + /// Set of all versions strictly lower than some version. + pub fn strictly_lower_than(v: impl Into) -> Self { + let v = v.into(); + if v == V::lowest() { + Self::none() + } else { + Self { + segments: SmallVec::one((V::lowest(), Some(v))), + } + } + } + + /// Set of all versions comprised between two given versions. + /// The lower bound is included and the higher bound excluded. + /// `v1 <= v < v2`. + pub fn between(v1: impl Into, v2: impl Into) -> Self { + let v1 = v1.into(); + let v2 = v2.into(); + if v1 < v2 { + Self { + segments: SmallVec::one((v1, Some(v2))), + } + } else { + Self::none() + } + } + + /// Construct a simple range from anything that impls [RangeBounds] like `v1..v2`. + pub fn from_range_bounds(bounds: R) -> Self + where + R: RangeBounds, + for<'a> &'a IV: Into, + { + let start = match bounds.start_bound() { + Bound::Included(s) => s.into(), + Bound::Excluded(s) => s.into().bump(), + Bound::Unbounded => V::lowest(), + }; + let end = match bounds.end_bound() { + Bound::Included(e) => Some(e.into().bump()), + Bound::Excluded(e) => Some(e.into()), + Bound::Unbounded => None, + }; + if end.is_some() && end.as_ref() <= Some(&start) { + Self::none() + } else { + Self { + segments: SmallVec::one((start, end)), + } + } + } +} + +// Set operations. +impl DiscreteRange { + // Negate ################################################################## + + /// Compute the complement set of versions. + pub fn negate(&self) -> Self { + match self.segments.first() { + None => Self::any(), // Complement of ∅ is * + + // First high bound is +∞ + Some((v, None)) => { + // Complement of * is ∅ + if v == &V::lowest() { + Self::none() + // Complement of "v <= _" is "_ < v" + } else { + Self::strictly_lower_than(v.clone()) + } + } + + // First high bound is not +∞ + Some((v1, Some(v2))) => { + if v1 == &V::lowest() { + Self::negate_segments(v2.clone(), &self.segments[1..]) + } else { + Self::negate_segments(V::lowest(), &self.segments) + } + } + } + } + + /// Helper function performing the negation of intervals in segments. + /// For example: + /// [ (v1, None) ] => [ (start, Some(v1)) ] + /// [ (v1, Some(v2)) ] => [ (start, Some(v1)), (v2, None) ] + fn negate_segments(start: V, segments: &[Interval]) -> DiscreteRange { + let mut complement_segments = SmallVec::empty(); + let mut start = Some(start); + for (v1, maybe_v2) in segments { + // start.unwrap() is fine because `segments` is not exposed, + // and our usage guaranties that only the last segment may contain a None. + complement_segments.push((start.unwrap(), Some(v1.to_owned()))); + start = maybe_v2.to_owned(); + } + if let Some(last) = start { + complement_segments.push((last, None)); + } + + Self { + segments: complement_segments, + } + } + + // Union and intersection ################################################## + + /// Compute the union of two sets of versions. + pub fn union(&self, other: &Self) -> Self { + self.negate().intersection(&other.negate()).negate() + } + + /// Compute the intersection of two sets of versions. + pub fn intersection(&self, other: &Self) -> Self { + let mut segments = SmallVec::empty(); + let mut left_iter = self.segments.iter(); + let mut right_iter = other.segments.iter(); + let mut left = left_iter.next(); + let mut right = right_iter.next(); + loop { + match (left, right) { + // Both left and right still contain a finite interval: + (Some((l1, Some(l2))), Some((r1, Some(r2)))) => { + if l2 <= r1 { + // Intervals are disjoint, progress on the left. + left = left_iter.next(); + } else if r2 <= l1 { + // Intervals are disjoint, progress on the right. + right = right_iter.next(); + } else { + // Intervals are not disjoint. + let start = l1.max(r1).to_owned(); + if l2 < r2 { + segments.push((start, Some(l2.to_owned()))); + left = left_iter.next(); + } else { + segments.push((start, Some(r2.to_owned()))); + right = right_iter.next(); + } + } + } + + // Right contains an infinite interval: + (Some((l1, Some(l2))), Some((r1, None))) => match l2.cmp(r1) { + Ordering::Less => { + left = left_iter.next(); + } + Ordering::Equal => { + for l in left_iter.cloned() { + segments.push(l) + } + break; + } + Ordering::Greater => { + let start = l1.max(r1).to_owned(); + segments.push((start, Some(l2.to_owned()))); + for l in left_iter.cloned() { + segments.push(l) + } + break; + } + }, + + // Left contains an infinite interval: + (Some((l1, None)), Some((r1, Some(r2)))) => match r2.cmp(l1) { + Ordering::Less => { + right = right_iter.next(); + } + Ordering::Equal => { + for r in right_iter.cloned() { + segments.push(r) + } + break; + } + Ordering::Greater => { + let start = l1.max(r1).to_owned(); + segments.push((start, Some(r2.to_owned()))); + for r in right_iter.cloned() { + segments.push(r) + } + break; + } + }, + + // Both sides contain an infinite interval: + (Some((l1, None)), Some((r1, None))) => { + let start = l1.max(r1).to_owned(); + segments.push((start, None)); + break; + } + + // Left or right has ended. + _ => { + break; + } + } + } + + Self { segments } + } +} + +// Other useful functions. +impl DiscreteRange { + /// Check if a range contains a given version. + pub fn contains(&self, version: &V) -> bool { + for (v1, maybe_v2) in &self.segments { + match maybe_v2 { + None => return v1 <= version, + Some(v2) => { + if version < v1 { + return false; + } else if version < v2 { + return true; + } + } + } + } + false + } + + /// Return the lowest version in the range (if there is one). + pub fn lowest_version(&self) -> Option { + self.segments.first().map(|(start, _)| start).cloned() + } + + /// Convert to something that can be used with + /// [BTreeMap::range](std::collections::BTreeMap::range). + /// All versions contained in self, will be in the output, + /// but there may be versions in the output that are not contained in self. + /// Returns None if the range is empty. + pub fn bounding_range(&self) -> Option<(Bound<&V>, Bound<&V>)> { + self.segments.first().map(|(start, _)| { + let end = { + self.segments + .last() + .and_then(|(_, l)| l.as_ref()) + .map(Bound::Excluded) + .unwrap_or(Bound::Unbounded) + }; + (Bound::Included(start), end) + }) + } +} + +// REPORT ###################################################################### + +impl fmt::Display for DiscreteRange { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self.segments.as_slice() { + [] => write!(f, "∅"), + [(start, None)] if start == &V::lowest() => write!(f, "∗"), + [(start, None)] => write!(f, "{} <= v", start), + [(start, Some(end))] if end == &start.bump() => write!(f, "{}", start), + [(start, Some(end))] if start == &V::lowest() => write!(f, "v < {}", end), + [(start, Some(end))] => write!(f, "{} <= v < {}", start, end), + more_than_one_interval => { + let string_intervals: Vec<_> = more_than_one_interval + .iter() + .map(interval_to_string) + .collect(); + write!(f, "{}", string_intervals.join(" ")) + } + } + } +} + +fn interval_to_string((start, maybe_end): &Interval) -> String { + match maybe_end { + Some(end) => format!("[ {}, {} [", start, end), + None => format!("[ {}, ∞ [", start), + } +} + +// TESTS ####################################################################### + +#[cfg(test)] +pub mod tests { + use proptest::prelude::*; + + use crate::version::NumberVersion; + + use super::*; + + pub fn strategy() -> impl Strategy> { + prop::collection::vec(any::(), 0..10).prop_map(|mut vec| { + vec.sort_unstable(); + vec.dedup(); + let mut pair_iter = vec.chunks_exact(2); + let mut segments = SmallVec::empty(); + while let Some([v1, v2]) = pair_iter.next() { + segments.push((NumberVersion(*v1), Some(NumberVersion(*v2)))); + } + if let [v] = pair_iter.remainder() { + segments.push((NumberVersion(*v), None)); + } + DiscreteRange { segments } + }) + } + + fn version_strat() -> impl Strategy { + any::().prop_map(NumberVersion) + } + + proptest! { + + // Testing negate ---------------------------------- + + #[test] + fn negate_is_different(range in strategy()) { + assert_ne!(range.negate(), range); + } + + #[test] + fn double_negate_is_identity(range in strategy()) { + assert_eq!(range.negate().negate(), range); + } + + #[test] + fn negate_contains_opposite(range in strategy(), version in version_strat()) { + assert_ne!(range.contains(&version), range.negate().contains(&version)); + } + + // Testing intersection ---------------------------- + + #[test] + fn intersection_is_symmetric(r1 in strategy(), r2 in strategy()) { + assert_eq!(r1.intersection(&r2), r2.intersection(&r1)); + } + + #[test] + fn intersection_with_any_is_identity(range in strategy()) { + assert_eq!(DiscreteRange::any().intersection(&range), range); + } + + #[test] + fn intersection_with_none_is_none(range in strategy()) { + assert_eq!(DiscreteRange::none().intersection(&range), DiscreteRange::none()); + } + + #[test] + fn intersection_is_idempotent(r1 in strategy(), r2 in strategy()) { + assert_eq!(r1.intersection(&r2).intersection(&r2), r1.intersection(&r2)); + } + + #[test] + fn intersection_is_associative(r1 in strategy(), r2 in strategy(), r3 in strategy()) { + assert_eq!(r1.intersection(&r2).intersection(&r3), r1.intersection(&r2.intersection(&r3))); + } + + #[test] + fn intesection_of_complements_is_none(range in strategy()) { + assert_eq!(range.negate().intersection(&range), DiscreteRange::none()); + } + + #[test] + fn intesection_contains_both(r1 in strategy(), r2 in strategy(), version in version_strat()) { + assert_eq!(r1.intersection(&r2).contains(&version), r1.contains(&version) && r2.contains(&version)); + } + + // Testing union ----------------------------------- + + #[test] + fn union_of_complements_is_any(range in strategy()) { + assert_eq!(range.negate().union(&range), DiscreteRange::any()); + } + + #[test] + fn union_contains_either(r1 in strategy(), r2 in strategy(), version in version_strat()) { + assert_eq!(r1.union(&r2).contains(&version), r1.contains(&version) || r2.contains(&version)); + } + + // Testing contains -------------------------------- + + #[test] + fn always_contains_exact(version in version_strat()) { + assert!(DiscreteRange::exact(version).contains(&version)); + } + + #[test] + fn contains_negation(range in strategy(), version in version_strat()) { + assert_ne!(range.contains(&version), range.negate().contains(&version)); + } + + #[test] + fn contains_intersection(range in strategy(), version in version_strat()) { + assert_eq!(range.contains(&version), range.intersection(&DiscreteRange::exact(version)) != DiscreteRange::none()); + } + + #[test] + fn contains_bounding_range(range in strategy(), version in version_strat()) { + if range.contains(&version) { + assert!(range.bounding_range().map(|b| b.contains(&version)).unwrap_or(false)); + } + } + + #[test] + fn from_range_bounds(range in any::<(Bound, Bound)>(), version in version_strat()) { + let rv: DiscreteRange = DiscreteRange::from_range_bounds(range); + assert_eq!(range.contains(&version.0), rv.contains(&version)); + } + + #[test] + fn from_range_bounds_round_trip(range in any::<(Bound, Bound)>()) { + let rv: DiscreteRange = DiscreteRange::from_range_bounds(range); + let rv2: DiscreteRange = rv.bounding_range().map(DiscreteRange::from_range_bounds::<_, NumberVersion>).unwrap_or_else(DiscreteRange::none); + assert_eq!(rv, rv2); + } + } +} diff --git a/src/internal/incompatibility.rs b/src/internal/incompatibility.rs index dd093a08..ff3a4143 100644 --- a/src/internal/incompatibility.rs +++ b/src/internal/incompatibility.rs @@ -257,7 +257,7 @@ impl fmt::Display for Incompatibility { #[cfg(test)] pub mod tests { use super::*; - use crate::range::Range; + use crate::bounded_range::BoundedRange; use crate::term::tests::strategy as term_strat; use crate::type_aliases::Map; use proptest::prelude::*; @@ -276,12 +276,12 @@ pub mod tests { let mut store = Arena::new(); let i1 = store.alloc(Incompatibility { package_terms: SmallMap::Two([("p1", t1.clone()), ("p2", t2.negate())]), - kind: Kind::UnavailableDependencies("0", Range::any()) + kind: Kind::UnavailableDependencies("0", BoundedRange::any()) }); let i2 = store.alloc(Incompatibility { package_terms: SmallMap::Two([("p2", t2), ("p3", t3.clone())]), - kind: Kind::UnavailableDependencies("0", Range::any()) + kind: Kind::UnavailableDependencies("0", BoundedRange::any()) }); let mut i3 = Map::default(); diff --git a/src/lib.rs b/src/lib.rs index bc34599b..900fd802 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -48,17 +48,17 @@ //! ``` //! # use pubgrub::solver::{OfflineDependencyProvider, resolve}; //! # use pubgrub::version::NumberVersion; -//! # use pubgrub::range::Range; +//! # use pubgrub::bounded_range::BoundedRange; //! -//! type NumVS = Range; +//! type NumVS = BoundedRange; //! //! let mut dependency_provider = OfflineDependencyProvider::<&str, NumVS>::new(); //! //! dependency_provider.add_dependencies( -//! "root", 1, [("menu", Range::any()), ("icons", Range::any())], +//! "root", 1, [("menu", BoundedRange::any()), ("icons", BoundedRange::any())], //! ); -//! dependency_provider.add_dependencies("menu", 1, [("dropdown", Range::any())]); -//! dependency_provider.add_dependencies("dropdown", 1, [("icons", Range::any())]); +//! dependency_provider.add_dependencies("menu", 1, [("dropdown", BoundedRange::any())]); +//! dependency_provider.add_dependencies("dropdown", 1, [("icons", BoundedRange::any())]); //! dependency_provider.add_dependencies("icons", 1, []); //! //! // Run the algorithm. @@ -79,14 +79,14 @@ //! ``` //! # use pubgrub::solver::{DependencyProvider, Dependencies}; //! # use pubgrub::version::SemanticVersion; -//! # use pubgrub::range::Range; +//! # use pubgrub::bounded_range::BoundedRange; //! # use pubgrub::type_aliases::Map; //! # use std::error::Error; //! # use std::borrow::Borrow; //! # //! # struct MyDependencyProvider; //! # -//! type SemVS = Range; +//! type SemVS = BoundedRange; //! //! impl DependencyProvider for MyDependencyProvider { //! fn choose_package_version, U: Borrow>(&self,packages: impl Iterator) -> Result<(T, Option), Box> { @@ -177,9 +177,9 @@ //! # use pubgrub::report::{DefaultStringReporter, Reporter}; //! # use pubgrub::error::PubGrubError; //! # use pubgrub::version::NumberVersion; -//! # use pubgrub::range::Range; +//! # use pubgrub::bounded_range::BoundedRange; //! # -//! # type NumVS = Range; +//! # type NumVS = BoundedRange; //! # //! # let dependency_provider = OfflineDependencyProvider::<&str, NumVS>::new(); //! # let root_package = "root"; @@ -216,9 +216,10 @@ #![allow(clippy::rc_buffer)] #![warn(missing_docs)] +pub mod bounded_range; +pub mod discrete_range; pub mod error; pub mod package; -pub mod range; pub mod report; pub mod solver; pub mod term; diff --git a/src/solver.rs b/src/solver.rs index 846f220c..fb469978 100644 --- a/src/solver.rs +++ b/src/solver.rs @@ -44,9 +44,9 @@ //! # use pubgrub::solver::{resolve, OfflineDependencyProvider}; //! # use pubgrub::version::NumberVersion; //! # use pubgrub::error::PubGrubError; -//! # use pubgrub::range::Range; +//! # use pubgrub::bounded_range::BoundedRange; //! # -//! # type NumVS = Range; +//! # type NumVS = BoundedRange; //! # //! # fn try_main() -> Result<(), PubGrubError<&'static str, NumVS>> { //! # let dependency_provider = OfflineDependencyProvider::<&str, NumVS>::new(); diff --git a/src/term.rs b/src/term.rs index cf7aa6f7..2ce6fb0c 100644 --- a/src/term.rs +++ b/src/term.rs @@ -181,13 +181,13 @@ impl Display for Term { #[cfg(test)] pub mod tests { use super::*; - use crate::range::Range; + use crate::bounded_range::BoundedRange; use proptest::prelude::*; - pub fn strategy() -> impl Strategy>> { + pub fn strategy() -> impl Strategy>> { prop_oneof![ - crate::range::tests::strategy().prop_map(Term::Positive), - crate::range::tests::strategy().prop_map(Term::Negative), + crate::bounded_range::tests::strategy().prop_map(Term::Positive), + crate::bounded_range::tests::strategy().prop_map(Term::Negative), ] } diff --git a/test-examples/large_case_u16_bounded_NumberVersion.ron b/test-examples/large_case_u16_bounded_NumberVersion.ron new file mode 100644 index 00000000..7f7204df --- /dev/null +++ b/test-examples/large_case_u16_bounded_NumberVersion.ron @@ -0,0 +1,5524 @@ +{ + 0: { + 0: { + 13: [ + (Included(0), Excluded(13)), + ], + 96: [ + (Included(0), Excluded(15)), + ], + 344: [ + (Included(0), Excluded(15)), + ], + 475: [ + (Included(3), Excluded(4)), + ], + 479: [ + (Included(0), Unbounded), + ], + 523: [ + (Included(0), Excluded(10)), + ], + 600: [ + (Included(0), Unbounded), + ], + }, + }, + 13: { + 10: { + 215: [ + (Included(1), Excluded(14)), + ], + 227: [ + (Included(0), Unbounded), + ], + 505: [ + (Included(0), Excluded(14)), + ], + }, + 12: { + 100: [ + (Included(6), Unbounded), + ], + 124: [ + (Included(0), Excluded(15)), + ], + 208: [ + (Included(0), Excluded(8)), + ], + 287: [ + (Included(3), Excluded(6)), + ], + 396: [ + (Included(9), Excluded(12)), + ], + 405: [ + (Included(2), Unbounded), + ], + 574: [ + (Included(0), Excluded(10)), + ], + }, + 13: { + 171: [ + (Included(2), Excluded(12)), + ], + 441: [ + (Included(0), Excluded(3)), + ], + 505: [ + (Included(1), Excluded(18)), + ], + 547: [ + (Included(8), Unbounded), + ], + }, + }, + 96: { + 10: { + 169: [ + (Included(9), Excluded(11)), + ], + 259: [ + (Included(0), Excluded(1)), + ], + 341: [ + (Included(2), Excluded(15)), + ], + 344: [ + (Included(3), Excluded(14)), + ], + 418: [ + (Included(8), Excluded(16)), + ], + 443: [ + (Included(0), Excluded(15)), + ], + 447: [ + (Included(3), Unbounded), + ], + 500: [ + (Included(5), Excluded(13)), + ], + 619: [ + (Included(4), Excluded(15)), + ], + }, + 12: { + 128: [ + (Included(5), Excluded(14)), + ], + 249: [ + (Included(0), Unbounded), + ], + 352: [ + (Included(0), Excluded(17)), + ], + 405: [ + (Included(6), Excluded(12)), + ], + 595: [ + (Included(5), Unbounded), + ], + 600: [ + (Included(8), Excluded(10)), + ], + 613: [ + (Included(0), Excluded(11)), + ], + }, + 14: { + 171: [ + (Included(0), Excluded(3)), + ], + 242: [ + (Included(5), Excluded(14)), + ], + 255: [ + (Included(8), Unbounded), + ], + 370: [ + (Included(6), Unbounded), + ], + 559: [ + (Included(0), Excluded(9)), + ], + 574: [ + (Included(0), Excluded(2)), + ], + 593: [ + (Included(3), Unbounded), + ], + 599: [ + (Included(0), Excluded(15)), + ], + }, + }, + 128: { + 5: { + 541: [ + (Included(0), Excluded(14)), + ], + }, + 8: { + 316: [ + (Included(3), Excluded(18)), + ], + 349: [ + (Included(0), Excluded(11)), + ], + 410: [ + (Included(5), Excluded(6)), + ], + 523: [ + (Included(8), Excluded(11)), + ], + 547: [ + (Included(3), Excluded(18)), + ], + 595: [ + (Included(6), Unbounded), + ], + 619: [ + (Included(2), Unbounded), + ], + }, + 9: { + 250: [ + (Included(7), Excluded(19)), + ], + 259: [ + (Included(0), Unbounded), + ], + 265: [ + (Included(0), Excluded(8)), + ], + 287: [ + (Included(2), Excluded(13)), + ], + 447: [ + (Included(0), Unbounded), + ], + 455: [ + (Included(2), Excluded(16)), + ], + 505: [ + (Included(1), Excluded(18)), + ], + 541: [ + (Included(0), Excluded(7)), + ], + 574: [ + (Included(0), Excluded(15)), + ], + }, + 11: { + 190: [ + (Included(0), Excluded(1)), + ], + 242: [ + (Included(5), Excluded(10)), + ], + 265: [ + (Included(1), Excluded(13)), + ], + 287: [ + (Included(1), Excluded(3)), + ], + 316: [ + (Included(4), Unbounded), + ], + 335: [ + (Included(2), Excluded(4)), + ], + 344: [ + (Included(6), Unbounded), + ], + 349: [ + (Included(4), Excluded(15)), + ], + 418: [ + (Included(3), Excluded(4)), + ], + 477: [ + (Included(0), Unbounded), + ], + 595: [ + (Included(6), Excluded(17)), + ], + 606: [ + (Included(6), Unbounded), + ], + 635: [ + (Included(0), Excluded(18)), + ], + }, + 12: { + 190: [ + (Included(3), Excluded(14)), + ], + 250: [ + (Included(5), Excluded(8)), + ], + 328: [ + (Included(0), Excluded(16)), + ], + 484: [ + (Included(6), Excluded(8)), + ], + 500: [ + (Included(0), Excluded(3)), + ], + 547: [ + (Included(4), Excluded(17)), + ], + }, + 13: { + 190: [ + (Included(3), Excluded(6)), + ], + 312: [ + (Included(0), Excluded(11)), + ], + 341: [ + (Included(0), Excluded(7)), + ], + 348: [ + (Included(0), Unbounded), + ], + 484: [ + (Included(4), Excluded(9)), + ], + 495: [ + (Included(5), Excluded(12)), + ], + }, + 15: { + 205: [ + (Included(5), Excluded(13)), + ], + 312: [ + (Included(0), Excluded(13)), + ], + 335: [ + (Included(2), Excluded(7)), + ], + 346: [ + (Included(0), Unbounded), + ], + 385: [ + (Included(0), Excluded(4)), + ], + 589: [ + (Included(0), Excluded(9)), + ], + }, + }, + 190: { + 0: { + 202: [ + (Included(9), Excluded(10)), + ], + 251: [ + (Included(0), Excluded(18)), + ], + 265: [ + (Included(8), Unbounded), + ], + 293: [ + (Included(7), Excluded(12)), + ], + 328: [ + (Included(2), Excluded(13)), + ], + 535: [ + (Included(3), Excluded(14)), + ], + }, + 3: { + 400: [ + (Included(0), Excluded(1)), + ], + 441: [ + (Included(0), Unbounded), + ], + }, + 5: { + 250: [ + (Included(4), Excluded(19)), + ], + 619: [ + (Included(4), Excluded(7)), + ], + 627: [ + (Included(4), Unbounded), + ], + }, + 8: { + 265: [ + (Included(0), Excluded(8)), + ], + 541: [ + (Included(0), Excluded(7)), + ], + 560: [ + (Included(0), Excluded(5)), + ], + 600: [ + (Included(6), Unbounded), + ], + }, + 9: { + 199: [ + (Included(3), Excluded(16)), + ], + 208: [ + (Included(0), Unbounded), + ], + 227: [ + (Included(4), Excluded(16)), + ], + 287: [ + (Included(1), Excluded(12)), + ], + 334: [ + (Included(0), Excluded(6)), + ], + 341: [ + (Included(0), Excluded(12)), + ], + 348: [ + (Included(7), Unbounded), + ], + 396: [ + (Included(4), Excluded(19)), + ], + 400: [ + (Included(4), Excluded(5)), + ], + 523: [ + (Included(8), Excluded(9)), + ], + 547: [ + (Included(2), Excluded(17)), + ], + }, + 11: { + 210: [ + (Included(8), Excluded(15)), + ], + 334: [ + (Included(5), Excluded(6)), + ], + 345: [ + (Included(1), Excluded(12)), + ], + 349: [ + (Included(3), Unbounded), + ], + 370: [ + (Included(0), Unbounded), + ], + 484: [ + (Included(0), Excluded(8)), + ], + 495: [ + (Included(1), Excluded(13)), + ], + 594: [ + (Included(1), Unbounded), + ], + }, + 12: { + 645: [ + (Included(6), Excluded(17)), + ], + }, + 13: { + 205: [ + (Included(2), Excluded(13)), + ], + 287: [ + (Included(4), Unbounded), + ], + 328: [ + (Included(2), Excluded(14)), + ], + 450: [ + (Included(3), Excluded(17)), + ], + 491: [ + (Included(2), Excluded(4)), + ], + 660: [ + (Included(0), Excluded(4)), + ], + }, + 17: { + 245: [ + (Included(2), Excluded(4)), + ], + 250: [ + (Included(0), Excluded(12)), + ], + 364: [ + (Included(9), Unbounded), + ], + 559: [ + (Included(0), Excluded(13)), + ], + 576: [ + (Included(7), Excluded(9)), + ], + }, + 19: { + 316: [ + (Included(3), Excluded(17)), + ], + 589: [ + (Included(7), Unbounded), + ], + 600: [ + (Included(6), Excluded(9)), + ], + 608: [ + (Included(6), Excluded(7)), + ], + 627: [ + (Included(4), Excluded(15)), + ], + 662: [ + (Included(8), Excluded(17)), + ], + }, + }, + 215: { + 8: { + 245: [ + (Included(0), Excluded(2)), + ], + 334: [ + (Included(0), Excluded(6)), + ], + 341: [ + (Included(0), Excluded(12)), + ], + 450: [ + (Included(0), Excluded(18)), + ], + 606: [ + (Included(0), Unbounded), + ], + 608: [ + (Included(0), Excluded(10)), + ], + }, + 11: { + 228: [ + (Included(0), Excluded(15)), + ], + 245: [ + (Included(0), Excluded(4)), + ], + 316: [ + (Included(3), Excluded(18)), + ], + 505: [ + (Included(1), Excluded(14)), + ], + 559: [ + (Included(1), Excluded(13)), + ], + 601: [ + (Included(8), Excluded(13)), + ], + 613: [ + (Included(8), Excluded(11)), + ], + }, + 13: { + 450: [ + (Included(3), Excluded(5)), + ], + 662: [ + (Included(6), Excluded(19)), + ], + }, + 15: { + 349: [ + (Included(0), Excluded(12)), + ], + 619: [ + (Included(0), Excluded(7)), + ], + }, + }, + 227: { + 3: { + 348: [ + (Included(0), Excluded(3)), + ], + 448: [ + (Included(2), Excluded(13)), + ], + 559: [ + (Included(9), Excluded(11)), + ], + 594: [ + (Included(1), Excluded(12)), + ], + 650: [ + (Included(0), Excluded(15)), + ], + }, + 4: { + 264: [ + (Included(0), Excluded(4)), + ], + 344: [ + (Included(6), Excluded(7)), + ], + 479: [ + (Included(0), Unbounded), + ], + 562: [ + (Included(4), Excluded(5)), + ], + }, + 5: { + 265: [ + (Included(7), Excluded(10)), + ], + 316: [ + (Included(4), Excluded(17)), + ], + 405: [ + (Included(2), Excluded(8)), + ], + 471: [ + (Included(0), Unbounded), + ], + 593: [ + (Included(4), Unbounded), + ], + }, + 6: { + 448: [ + (Included(0), Excluded(13)), + ], + 625: [ + (Included(0), Excluded(7)), + ], + }, + 8: { + 328: [ + (Included(3), Excluded(16)), + ], + 462: [ + (Included(7), Excluded(8)), + ], + 495: [ + (Included(0), Excluded(5)), + ], + 613: [ + (Included(0), Excluded(4)), + ], + 627: [ + (Included(0), Excluded(2)), + ], + 660: [ + (Included(0), Excluded(10)), + ], + }, + 9: { + 334: [ + (Included(1), Unbounded), + ], + 351: [ + (Included(0), Excluded(7)), + ], + 410: [ + (Included(5), Excluded(8)), + ], + 574: [ + (Included(2), Excluded(15)), + ], + 599: [ + (Included(2), Excluded(13)), + ], + }, + 10: { + 230: [ + (Included(7), Excluded(17)), + ], + 242: [ + (Included(4), Unbounded), + ], + 287: [ + (Included(1), Excluded(7)), + ], + 650: [ + (Included(4), Unbounded), + ], + }, + 14: { + 455: [ + (Included(9), Excluded(18)), + ], + 625: [ + (Included(8), Excluded(9)), + ], + }, + 15: { + 450: [ + (Included(0), Excluded(4)), + ], + 523: [ + (Included(1), Excluded(14)), + ], + }, + 16: { + 255: [ + (Included(1), Excluded(14)), + ], + 589: [ + (Included(1), Unbounded), + ], + }, + 17: { + 312: [ + (Included(6), Excluded(12)), + ], + 348: [ + (Included(9), Excluded(15)), + ], + 371: [ + (Included(2), Excluded(19)), + ], + 455: [ + (Included(4), Excluded(13)), + ], + 495: [ + (Included(3), Excluded(9)), + ], + 547: [ + (Included(6), Unbounded), + ], + 562: [ + (Included(4), Excluded(13)), + ], + }, + 18: { + 312: [ + (Included(5), Unbounded), + ], + 584: [ + (Included(3), Unbounded), + ], + 660: [ + (Included(0), Unbounded), + ], + }, + }, + 228: { + 6: { + 293: [ + (Included(7), Excluded(11)), + ], + 341: [ + (Included(0), Excluded(2)), + ], + 559: [ + (Included(8), Unbounded), + ], + 608: [ + (Included(6), Unbounded), + ], + 613: [ + (Included(8), Excluded(11)), + ], + }, + 7: { + 523: [ + (Included(9), Unbounded), + ], + 595: [ + (Included(0), Excluded(15)), + ], + 662: [ + (Included(6), Excluded(17)), + ], + }, + 14: { + 371: [ + (Included(0), Excluded(12)), + ], + 491: [ + (Included(0), Unbounded), + ], + }, + 15: { + 250: [ + (Included(4), Excluded(18)), + ], + 265: [ + (Included(0), Excluded(13)), + ], + 606: [ + (Included(7), Excluded(17)), + ], + }, + 17: { + 341: [ + (Included(0), Excluded(15)), + ], + 535: [ + (Included(2), Excluded(13)), + ], + 559: [ + (Included(1), Unbounded), + ], + }, + }, + 245: { + 1: { + 334: [ + (Included(5), Excluded(9)), + ], + 613: [ + (Included(0), Excluded(9)), + ], + }, + 2: { + 268: [ + (Included(9), Excluded(14)), + ], + 541: [ + (Included(7), Excluded(16)), + ], + }, + 3: { + 293: [ + (Included(0), Excluded(8)), + ], + 335: [ + (Included(0), Excluded(7)), + ], + 364: [ + (Included(2), Excluded(13)), + ], + 547: [ + (Included(2), Excluded(17)), + ], + 569: [ + (Included(8), Excluded(13)), + ], + }, + 5: { + 450: [ + (Included(0), Excluded(14)), + ], + 495: [ + (Included(8), Excluded(12)), + ], + 576: [ + (Included(8), Unbounded), + ], + 660: [ + (Included(0), Excluded(10)), + ], + }, + }, + 249: { + 9: { + 251: [ + (Included(0), Unbounded), + ], + 477: [ + (Included(3), Unbounded), + ], + 523: [ + (Included(0), Excluded(11)), + ], + 560: [ + (Included(4), Excluded(7)), + ], + }, + 10: { + 341: [ + (Included(6), Excluded(11)), + ], + 349: [ + (Included(6), Unbounded), + ], + 645: [ + (Included(2), Excluded(6)), + ], + }, + 15: { + 250: [ + (Included(4), Excluded(6)), + ], + 312: [ + (Included(1), Excluded(13)), + ], + 448: [ + (Included(2), Unbounded), + ], + 547: [ + (Included(0), Excluded(3)), + ], + 613: [ + (Included(0), Excluded(9)), + ], + }, + }, + 250: { + 2: { + 345: [ + (Included(7), Excluded(10)), + ], + 441: [ + (Included(0), Excluded(16)), + ], + 448: [ + (Included(0), Excluded(13)), + ], + 450: [ + (Included(0), Excluded(18)), + ], + 455: [ + (Included(0), Excluded(18)), + ], + 495: [ + (Included(3), Excluded(9)), + ], + 505: [ + (Included(3), Excluded(18)), + ], + 595: [ + (Included(2), Excluded(15)), + ], + 613: [ + (Included(0), Unbounded), + ], + }, + 4: { + 462: [ + (Included(4), Excluded(15)), + ], + 471: [ + (Included(0), Excluded(3)), + ], + 559: [ + (Included(0), Unbounded), + ], + 560: [ + (Included(4), Unbounded), + ], + 584: [ + (Included(0), Unbounded), + ], + 660: [ + (Included(9), Unbounded), + ], + }, + 5: { + 349: [ + (Included(1), Excluded(5)), + ], + 495: [ + (Included(3), Excluded(10)), + ], + 547: [ + (Included(5), Excluded(12)), + ], + 660: [ + (Included(0), Excluded(2)), + ], + }, + 7: { + 600: [ + (Included(6), Excluded(10)), + ], + 660: [ + (Included(3), Unbounded), + ], + }, + 9: { + 334: [ + (Included(6), Excluded(12)), + ], + 348: [ + (Included(0), Excluded(4)), + ], + 650: [ + (Included(2), Excluded(8)), + ], + }, + 10: { + 287: [ + (Included(0), Excluded(10)), + ], + 297: [ + (Included(7), Unbounded), + ], + 334: [ + (Included(0), Excluded(16)), + ], + 364: [ + (Included(0), Excluded(11)), + ], + 370: [ + (Included(0), Unbounded), + ], + }, + 11: { + 410: [ + (Included(9), Excluded(17)), + ], + 445: [ + (Included(0), Excluded(6)), + ], + 523: [ + (Included(6), Excluded(10)), + ], + 595: [ + (Included(0), Excluded(11)), + ], + }, + 12: { + 293: [ + (Included(7), Excluded(11)), + ], + 335: [ + (Included(1), Excluded(16)), + ], + }, + 14: { + 287: [ + (Included(8), Excluded(10)), + ], + 462: [ + (Included(2), Excluded(13)), + ], + 477: [ + (Included(7), Excluded(8)), + ], + 523: [ + (Included(0), Excluded(7)), + ], + }, + 15: { + 352: [ + (Included(7), Unbounded), + ], + 484: [ + (Included(1), Unbounded), + ], + 627: [ + (Included(2), Excluded(13)), + ], + }, + 17: { + 341: [ + (Included(2), Excluded(7)), + ], + 450: [ + (Included(6), Unbounded), + ], + 479: [ + (Included(0), Unbounded), + ], + 560: [ + (Included(0), Excluded(3)), + ], + 574: [ + (Included(9), Excluded(11)), + ], + }, + 18: { + 265: [ + (Included(0), Excluded(10)), + ], + 312: [ + (Included(2), Excluded(14)), + ], + 491: [ + (Included(2), Excluded(4)), + ], + 593: [ + (Included(8), Excluded(10)), + ], + 600: [ + (Included(9), Unbounded), + ], + 608: [ + (Included(0), Excluded(10)), + ], + }, + 19: { + 335: [ + (Included(2), Excluded(16)), + ], + 349: [ + (Included(1), Excluded(6)), + ], + 405: [ + (Included(0), Unbounded), + ], + }, + }, + 255: { + 5: { + 348: [ + (Included(4), Excluded(5)), + ], + 396: [ + (Included(7), Unbounded), + ], + 441: [ + (Included(8), Excluded(9)), + ], + 535: [ + (Included(0), Excluded(7)), + ], + }, + 8: { + 312: [ + (Included(2), Excluded(14)), + ], + }, + 11: { + 349: [ + (Included(1), Excluded(13)), + ], + 448: [ + (Included(0), Excluded(13)), + ], + 462: [ + (Included(3), Excluded(8)), + ], + 535: [ + (Included(2), Excluded(14)), + ], + }, + 13: { + 405: [ + (Included(9), Excluded(10)), + ], + 574: [ + (Included(0), Excluded(19)), + ], + 608: [ + (Included(2), Unbounded), + ], + 645: [ + (Included(6), Excluded(17)), + ], + }, + 14: { + 265: [ + (Included(2), Excluded(13)), + ], + 348: [ + (Included(9), Unbounded), + ], + 370: [ + (Included(0), Unbounded), + ], + 541: [ + (Included(7), Excluded(9)), + ], + }, + 16: { + 348: [ + (Included(3), Excluded(17)), + ], + 349: [ + (Included(4), Unbounded), + ], + 625: [ + (Included(6), Unbounded), + ], + }, + }, + 259: { + 0: { + 341: [ + (Included(0), Excluded(2)), + ], + 348: [ + (Included(2), Excluded(18)), + ], + 349: [ + (Included(1), Unbounded), + ], + 535: [ + (Included(5), Excluded(13)), + ], + 593: [ + (Included(4), Excluded(9)), + ], + 600: [ + (Included(9), Unbounded), + ], + 601: [ + (Included(4), Excluded(7)), + ], + }, + 5: { + 262: [ + (Included(5), Unbounded), + ], + 287: [ + (Included(1), Unbounded), + ], + }, + 10: { + 662: [ + (Included(7), Excluded(9)), + ], + }, + 11: { + 341: [ + (Included(7), Excluded(15)), + ], + 345: [ + (Included(1), Excluded(4)), + ], + 405: [ + (Included(0), Excluded(15)), + ], + 448: [ + (Included(1), Excluded(17)), + ], + 593: [ + (Included(4), Unbounded), + ], + }, + 12: { + 352: [ + (Included(0), Excluded(15)), + ], + 541: [ + (Included(5), Excluded(17)), + ], + 601: [ + (Included(2), Unbounded), + ], + }, + }, + 265: { + 6: { + 405: [ + (Included(7), Excluded(11)), + ], + 455: [ + (Included(5), Excluded(16)), + ], + 462: [ + (Included(4), Unbounded), + ], + 576: [ + (Included(0), Excluded(16)), + ], + }, + 7: { + 455: [ + (Included(0), Excluded(9)), + ], + 535: [ + (Included(5), Excluded(16)), + ], + 613: [ + (Included(0), Excluded(4)), + ], + 619: [ + (Included(2), Excluded(9)), + ], + 650: [ + (Included(0), Excluded(8)), + ], + }, + 9: { + 448: [ + (Included(5), Excluded(16)), + ], + 523: [ + (Included(0), Excluded(19)), + ], + 562: [ + (Included(4), Excluded(13)), + ], + 601: [ + (Included(4), Excluded(16)), + ], + }, + 11: { + 316: [ + (Included(6), Excluded(11)), + ], + }, + 12: { + 352: [ + (Included(0), Excluded(15)), + ], + 593: [ + (Included(1), Excluded(14)), + ], + 601: [ + (Included(5), Unbounded), + ], + 619: [ + (Included(0), Excluded(9)), + ], + }, + 18: { + 335: [ + (Included(6), Excluded(19)), + ], + 345: [ + (Included(1), Excluded(11)), + ], + 349: [ + (Included(0), Excluded(7)), + ], + 574: [ + (Included(1), Excluded(9)), + ], + }, + 19: { + 396: [ + (Included(4), Excluded(16)), + ], + 462: [ + (Included(2), Excluded(13)), + ], + }, + }, + 287: { + 0: { + 400: [ + (Included(4), Unbounded), + ], + 576: [ + (Included(6), Excluded(18)), + ], + }, + 1: { + 437: [ + (Included(0), Unbounded), + ], + 500: [ + (Included(0), Excluded(3)), + ], + 505: [ + (Included(6), Excluded(14)), + ], + 589: [ + (Included(1), Excluded(7)), + ], + }, + 2: { + 312: [ + (Included(9), Excluded(11)), + ], + }, + 3: { + 328: [ + (Included(9), Unbounded), + ], + 418: [ + (Included(0), Excluded(1)), + ], + }, + 5: { + 335: [ + (Included(6), Unbounded), + ], + 495: [ + (Included(5), Unbounded), + ], + 595: [ + (Included(0), Unbounded), + ], + 662: [ + (Included(7), Excluded(19)), + ], + }, + 6: { + 364: [ + (Included(4), Unbounded), + ], + 441: [ + (Included(0), Excluded(14)), + ], + 589: [ + (Included(6), Excluded(11)), + ], + }, + 8: { + 341: [ + (Included(0), Excluded(11)), + ], + 349: [ + (Included(0), Excluded(6)), + ], + 523: [ + (Included(0), Excluded(1)), + ], + }, + 9: { + 477: [ + (Included(1), Excluded(13)), + ], + 484: [ + (Included(7), Excluded(18)), + ], + 584: [ + (Included(1), Unbounded), + ], + 601: [ + (Included(6), Excluded(18)), + ], + }, + 11: { + 312: [ + (Included(0), Excluded(11)), + ], + 341: [ + (Included(0), Excluded(8)), + ], + 346: [ + (Included(2), Excluded(14)), + ], + 371: [ + (Included(2), Excluded(19)), + ], + 385: [ + (Included(9), Unbounded), + ], + 569: [ + (Included(0), Excluded(19)), + ], + }, + 12: { + 335: [ + (Included(1), Excluded(3)), + ], + 349: [ + (Included(0), Excluded(13)), + ], + 462: [ + (Included(2), Unbounded), + ], + 541: [ + (Included(5), Unbounded), + ], + 562: [ + (Included(1), Unbounded), + ], + }, + 13: { + 316: [ + (Included(0), Excluded(4)), + ], + 334: [ + (Included(6), Excluded(16)), + ], + 396: [ + (Included(9), Excluded(15)), + ], + }, + 14: { + 334: [ + (Included(3), Excluded(8)), + ], + 335: [ + (Included(1), Excluded(7)), + ], + 341: [ + (Included(6), Excluded(12)), + ], + 410: [ + (Included(7), Excluded(17)), + ], + 535: [ + (Included(0), Unbounded), + ], + 562: [ + (Included(8), Unbounded), + ], + 593: [ + (Included(8), Excluded(12)), + ], + }, + 16: { + 562: [ + (Included(4), Excluded(9)), + ], + }, + 19: { + 328: [ + (Included(9), Unbounded), + ], + 396: [ + (Included(5), Excluded(19)), + ], + 562: [ + (Included(4), Excluded(9)), + ], + }, + }, + 293: { + 3: { + 344: [ + (Included(9), Unbounded), + ], + 443: [ + (Included(4), Unbounded), + ], + 600: [ + (Included(6), Excluded(13)), + ], + }, + 7: { + 593: [ + (Included(4), Excluded(9)), + ], + }, + 10: { + 328: [ + (Included(3), Excluded(14)), + ], + 450: [ + (Included(6), Excluded(8)), + ], + 574: [ + (Included(4), Excluded(11)), + ], + }, + 11: { + 364: [ + (Included(2), Excluded(13)), + ], + 443: [ + (Included(2), Excluded(15)), + ], + 662: [ + (Included(0), Unbounded), + ], + }, + 12: { + 326: [ + (Included(0), Excluded(16)), + ], + 334: [ + (Included(3), Excluded(16)), + ], + 455: [ + (Included(8), Excluded(16)), + ], + }, + }, + 312: { + 0: { + 326: [ + (Included(6), Unbounded), + ], + 505: [ + (Included(1), Excluded(18)), + ], + }, + 1: { + 448: [ + (Included(0), Excluded(17)), + ], + }, + 2: { + 462: [ + (Included(3), Excluded(7)), + ], + 523: [ + (Included(3), Excluded(15)), + ], + 560: [ + (Included(0), Excluded(9)), + ], + 593: [ + (Included(1), Excluded(13)), + ], + 594: [ + (Included(1), Excluded(12)), + ], + 599: [ + (Included(1), Excluded(2)), + ], + 627: [ + (Included(4), Excluded(16)), + ], + }, + 3: { + 348: [ + (Included(8), Excluded(14)), + ], + 455: [ + (Included(8), Unbounded), + ], + 535: [ + (Included(5), Excluded(6)), + ], + 541: [ + (Included(0), Excluded(8)), + ], + 569: [ + (Included(6), Excluded(10)), + ], + 589: [ + (Included(7), Excluded(11)), + ], + 599: [ + (Included(1), Excluded(15)), + ], + 601: [ + (Included(9), Unbounded), + ], + 627: [ + (Included(1), Excluded(18)), + ], + }, + 4: { + 335: [ + (Included(0), Excluded(9)), + ], + 500: [ + (Included(2), Excluded(13)), + ], + 547: [ + (Included(0), Excluded(14)), + ], + 584: [ + (Included(1), Excluded(12)), + ], + 594: [ + (Included(4), Unbounded), + ], + 606: [ + (Included(9), Unbounded), + ], + 619: [ + (Included(4), Excluded(15)), + ], + }, + 6: { + 445: [ + (Included(5), Excluded(9)), + ], + 491: [ + (Included(3), Excluded(6)), + ], + 523: [ + (Included(1), Excluded(19)), + ], + 599: [ + (Included(1), Excluded(3)), + ], + 635: [ + (Included(1), Excluded(18)), + ], + }, + 9: { + 547: [ + (Included(3), Excluded(18)), + ], + 559: [ + (Included(8), Excluded(10)), + ], + 662: [ + (Included(6), Excluded(18)), + ], + }, + 10: { + 448: [ + (Included(3), Unbounded), + ], + 601: [ + (Included(6), Excluded(9)), + ], + }, + 11: { + 316: [ + (Included(0), Excluded(3)), + ], + 523: [ + (Included(9), Excluded(11)), + ], + 560: [ + (Included(0), Excluded(9)), + ], + 593: [ + (Included(8), Excluded(12)), + ], + 608: [ + (Included(7), Unbounded), + ], + }, + 12: { + 341: [ + (Included(6), Unbounded), + ], + 443: [ + (Included(2), Unbounded), + ], + }, + 13: { + 345: [ + (Included(4), Excluded(11)), + ], + 348: [ + (Included(4), Excluded(17)), + ], + 484: [ + (Included(0), Excluded(15)), + ], + 562: [ + (Included(0), Excluded(15)), + ], + 594: [ + (Included(0), Excluded(2)), + ], + 619: [ + (Included(8), Excluded(15)), + ], + }, + 15: { + 352: [ + (Included(0), Excluded(15)), + ], + }, + 16: { + 335: [ + (Included(2), Unbounded), + ], + 352: [ + (Included(4), Unbounded), + ], + 462: [ + (Included(2), Excluded(4)), + ], + 484: [ + (Included(4), Excluded(15)), + ], + 562: [ + (Included(0), Excluded(13)), + ], + 589: [ + (Included(0), Excluded(11)), + ], + 599: [ + (Included(6), Excluded(13)), + ], + 619: [ + (Included(0), Excluded(15)), + ], + }, + }, + 316: { + 2: { + 396: [ + (Included(5), Excluded(11)), + ], + 448: [ + (Included(1), Unbounded), + ], + 505: [ + (Included(2), Excluded(3)), + ], + 574: [ + (Included(4), Excluded(19)), + ], + 601: [ + (Included(6), Excluded(7)), + ], + 625: [ + (Included(8), Unbounded), + ], + }, + 3: { + 619: [ + (Included(2), Excluded(9)), + ], + 662: [ + (Included(7), Excluded(19)), + ], + }, + 6: { + 450: [ + (Included(6), Unbounded), + ], + 635: [ + (Included(5), Excluded(15)), + ], + }, + 10: { + 349: [ + (Included(6), Excluded(8)), + ], + 500: [ + (Included(5), Excluded(13)), + ], + 505: [ + (Included(0), Excluded(14)), + ], + 627: [ + (Included(1), Excluded(19)), + ], + }, + 13: { + 346: [ + (Included(2), Excluded(17)), + ], + 396: [ + (Included(5), Excluded(18)), + ], + 410: [ + (Included(0), Excluded(10)), + ], + 450: [ + (Included(6), Excluded(15)), + ], + 475: [ + (Included(0), Unbounded), + ], + 494: [ + (Included(0), Excluded(6)), + ], + }, + 14: { + 662: [ + (Included(7), Unbounded), + ], + }, + 16: { + 484: [ + (Included(1), Unbounded), + ], + 495: [ + (Included(5), Excluded(12)), + ], + 505: [ + (Included(6), Excluded(10)), + ], + }, + 17: { + 335: [ + (Included(2), Unbounded), + ], + 344: [ + (Included(6), Excluded(10)), + ], + 541: [ + (Included(3), Unbounded), + ], + }, + 19: { + 341: [ + (Included(6), Excluded(11)), + ], + 370: [ + (Included(0), Unbounded), + ], + 371: [ + (Included(2), Excluded(14)), + ], + 495: [ + (Included(1), Excluded(13)), + ], + 600: [ + (Included(6), Unbounded), + ], + }, + }, + 328: { + 0: { + 352: [ + (Included(5), Unbounded), + ], + 541: [ + (Included(6), Excluded(17)), + ], + }, + 1: { + 334: [ + (Included(3), Excluded(9)), + ], + 650: [ + (Included(0), Excluded(3)), + ], + }, + 5: { + 396: [ + (Included(7), Excluded(19)), + ], + }, + 9: { + 345: [ + (Included(0), Excluded(4)), + ], + 448: [ + (Included(1), Unbounded), + ], + 450: [ + (Included(7), Unbounded), + ], + 535: [ + (Included(8), Excluded(13)), + ], + 600: [ + (Included(6), Excluded(8)), + ], + }, + 12: {}, + 13: { + 410: [ + (Included(5), Excluded(10)), + ], + 441: [ + (Included(3), Excluded(16)), + ], + 595: [ + (Included(0), Excluded(16)), + ], + 627: [ + (Included(0), Unbounded), + ], + }, + 15: { + 348: [ + (Included(3), Excluded(14)), + ], + 396: [ + (Included(7), Excluded(15)), + ], + 455: [ + (Included(2), Excluded(17)), + ], + 589: [ + (Included(6), Excluded(8)), + ], + }, + 18: { + 396: [ + (Included(0), Excluded(12)), + ], + 450: [ + (Included(3), Excluded(4)), + ], + 455: [ + (Included(8), Excluded(11)), + ], + 535: [ + (Included(3), Unbounded), + ], + 569: [ + (Included(8), Excluded(10)), + ], + 584: [ + (Included(5), Unbounded), + ], + 594: [ + (Included(0), Excluded(6)), + ], + 601: [ + (Included(5), Excluded(18)), + ], + 613: [ + (Included(8), Excluded(11)), + ], + }, + }, + 334: { + 0: { + 405: [ + (Included(0), Excluded(10)), + ], + 599: [ + (Included(2), Excluded(15)), + ], + 613: [ + (Included(6), Unbounded), + ], + }, + 1: { + 396: [ + (Included(7), Excluded(19)), + ], + 477: [ + (Included(1), Excluded(16)), + ], + 484: [ + (Included(4), Unbounded), + ], + 491: [ + (Included(8), Unbounded), + ], + 541: [ + (Included(6), Excluded(15)), + ], + 662: [ + (Included(3), Excluded(8)), + ], + }, + 3: { + 450: [ + (Included(7), Excluded(15)), + ], + 477: [ + (Included(1), Excluded(14)), + ], + 535: [ + (Included(5), Excluded(16)), + ], + 569: [ + (Included(2), Excluded(19)), + ], + 645: [ + (Included(2), Excluded(7)), + ], + }, + 5: { + 418: [ + (Included(0), Unbounded), + ], + 455: [ + (Included(4), Excluded(10)), + ], + }, + 6: { + 410: [ + (Included(5), Excluded(14)), + ], + 418: [ + (Included(0), Excluded(4)), + ], + 462: [ + (Included(2), Excluded(5)), + ], + }, + 7: { + 405: [ + (Included(2), Excluded(7)), + ], + 593: [ + (Included(0), Unbounded), + ], + 662: [ + (Included(0), Excluded(4)), + ], + }, + 8: { + 348: [ + (Included(4), Unbounded), + ], + 437: [ + (Included(0), Excluded(16)), + ], + 484: [ + (Included(1), Excluded(15)), + ], + 491: [ + (Included(0), Excluded(4)), + ], + 627: [ + (Included(2), Unbounded), + ], + }, + 11: { + 349: [ + (Included(1), Excluded(12)), + ], + 491: [ + (Included(5), Excluded(7)), + ], + 660: [ + (Included(0), Excluded(2)), + ], + }, + 15: { + 364: [ + (Included(4), Excluded(13)), + ], + 601: [ + (Included(6), Excluded(18)), + ], + 662: [ + (Included(5), Excluded(17)), + ], + }, + 19: { + 647: [ + (Included(1), Unbounded), + ], + }, + }, + 335: { + 0: { + 601: [ + (Included(1), Unbounded), + ], + }, + 1: { + 455: [ + (Included(0), Excluded(18)), + ], + 495: [ + (Included(3), Excluded(13)), + ], + 569: [ + (Included(6), Excluded(19)), + ], + }, + 2: { + 448: [ + (Included(1), Excluded(17)), + ], + 625: [ + (Included(0), Excluded(9)), + ], + 660: [ + (Included(0), Excluded(4)), + ], + }, + 3: { + 346: [ + (Included(2), Excluded(15)), + ], + 443: [ + (Included(2), Unbounded), + ], + 455: [ + (Included(4), Excluded(9)), + ], + 475: [ + (Included(9), Unbounded), + ], + 523: [ + (Included(0), Excluded(9)), + ], + }, + 6: { + 345: [ + (Included(3), Excluded(15)), + ], + 396: [ + (Included(0), Excluded(4)), + ], + 505: [ + (Included(0), Excluded(7)), + ], + }, + 7: { + 455: [ + (Included(7), Unbounded), + ], + 477: [ + (Included(3), Excluded(14)), + ], + }, + 8: { + 599: [ + (Included(7), Excluded(14)), + ], + }, + 11: { + 547: [ + (Included(3), Excluded(6)), + ], + 600: [ + (Included(0), Excluded(9)), + ], + 627: [ + (Included(7), Unbounded), + ], + }, + 12: { + 445: [ + (Included(0), Excluded(9)), + ], + }, + 15: { + 462: [ + (Included(4), Unbounded), + ], + }, + 16: { + 405: [ + (Included(7), Unbounded), + ], + 471: [ + (Included(0), Excluded(3)), + ], + 627: [ + (Included(7), Excluded(12)), + ], + }, + 17: { + 396: [ + (Included(0), Excluded(18)), + ], + 418: [ + (Included(3), Excluded(19)), + ], + 574: [ + (Included(1), Excluded(19)), + ], + 645: [ + (Included(5), Unbounded), + ], + }, + 18: { + 345: [ + (Included(0), Excluded(15)), + ], + 471: [ + (Included(0), Excluded(2)), + ], + 584: [ + (Included(0), Excluded(12)), + ], + 589: [ + (Included(8), Excluded(9)), + ], + }, + 19: { + 344: [ + (Included(3), Excluded(16)), + ], + 345: [ + (Included(9), Unbounded), + ], + 547: [ + (Included(7), Unbounded), + ], + 574: [ + (Included(4), Unbounded), + ], + 584: [ + (Included(3), Unbounded), + ], + }, + }, + 341: { + 1: { + 348: [ + (Included(6), Excluded(18)), + ], + 370: [ + (Included(0), Unbounded), + ], + 479: [ + (Included(0), Unbounded), + ], + 574: [ + (Included(4), Excluded(11)), + ], + 593: [ + (Included(1), Unbounded), + ], + }, + 2: { + 346: [ + (Included(0), Excluded(5)), + ], + 364: [ + (Included(9), Excluded(12)), + ], + 450: [ + (Included(6), Excluded(15)), + ], + }, + 6: { + 348: [ + (Included(0), Excluded(13)), + ], + 484: [ + (Included(4), Unbounded), + ], + 494: [ + (Included(5), Unbounded), + ], + 595: [ + (Included(4), Unbounded), + ], + }, + 7: { + 447: [ + (Included(1), Unbounded), + ], + 627: [ + (Included(7), Excluded(12)), + ], + }, + 10: { + 505: [ + (Included(2), Unbounded), + ], + 576: [ + (Included(0), Excluded(16)), + ], + }, + 11: { + 348: [ + (Included(0), Excluded(11)), + ], + 364: [ + (Included(4), Excluded(8)), + ], + 541: [ + (Included(7), Excluded(8)), + ], + }, + 14: { + 348: [ + (Included(4), Excluded(16)), + ], + 445: [ + (Included(8), Unbounded), + ], + 448: [ + (Included(3), Excluded(16)), + ], + 600: [ + (Included(2), Excluded(13)), + ], + }, + 16: { + 535: [ + (Included(6), Unbounded), + ], + 547: [ + (Included(0), Excluded(19)), + ], + 601: [ + (Included(6), Unbounded), + ], + }, + 17: { + 396: [ + (Included(4), Excluded(16)), + ], + 477: [ + (Included(4), Excluded(16)), + ], + 569: [ + (Included(3), Unbounded), + ], + }, + }, + 344: { + 2: { + 396: [ + (Included(4), Excluded(19)), + ], + 477: [ + (Included(4), Unbounded), + ], + 576: [ + (Included(8), Excluded(11)), + ], + 647: [ + (Included(0), Excluded(4)), + ], + }, + 3: { + 405: [ + (Included(1), Excluded(14)), + ], + 574: [ + (Included(8), Excluded(11)), + ], + }, + 6: { + 364: [ + (Included(5), Excluded(13)), + ], + 599: [ + (Included(7), Excluded(15)), + ], + }, + 9: { + 450: [ + (Included(3), Excluded(17)), + ], + }, + 13: { + 345: [ + (Included(4), Excluded(12)), + ], + 352: [ + (Included(0), Excluded(10)), + ], + 475: [ + (Included(3), Unbounded), + ], + 560: [ + (Included(4), Excluded(9)), + ], + 594: [ + (Included(4), Excluded(12)), + ], + }, + 14: { + 348: [ + (Included(0), Excluded(12)), + ], + 441: [ + (Included(0), Excluded(9)), + ], + 443: [ + (Included(2), Unbounded), + ], + 462: [ + (Included(4), Unbounded), + ], + 523: [ + (Included(0), Excluded(12)), + ], + 599: [ + (Included(7), Excluded(14)), + ], + }, + 15: { + 349: [ + (Included(7), Excluded(13)), + ], + 437: [ + (Included(5), Unbounded), + ], + }, + 19: { + 352: [ + (Included(9), Excluded(16)), + ], + 625: [ + (Included(6), Excluded(9)), + ], + }, + }, + 345: { + 0: { + 441: [ + (Included(8), Unbounded), + ], + 601: [ + (Included(0), Excluded(5)), + ], + 635: [ + (Included(1), Unbounded), + ], + }, + 1: { + 349: [ + (Included(5), Excluded(11)), + ], + 364: [ + (Included(5), Excluded(11)), + ], + 371: [ + (Included(0), Excluded(12)), + ], + 491: [ + (Included(0), Excluded(4)), + ], + 569: [ + (Included(8), Excluded(19)), + ], + 627: [ + (Included(2), Excluded(18)), + ], + }, + 3: { + 405: [ + (Included(4), Excluded(11)), + ], + 450: [ + (Included(0), Excluded(17)), + ], + 475: [ + (Included(0), Unbounded), + ], + 541: [ + (Included(8), Excluded(15)), + ], + }, + 4: { + 349: [ + (Included(0), Excluded(13)), + ], + 405: [ + (Included(0), Excluded(14)), + ], + 418: [ + (Included(0), Excluded(9)), + ], + 462: [ + (Included(3), Excluded(5)), + ], + 523: [ + (Included(1), Excluded(2)), + ], + 535: [ + (Included(5), Unbounded), + ], + 595: [ + (Included(0), Excluded(16)), + ], + }, + 6: { + 455: [ + (Included(7), Excluded(18)), + ], + 495: [ + (Included(0), Excluded(10)), + ], + 569: [ + (Included(3), Excluded(17)), + ], + }, + 7: { + 471: [ + (Included(2), Unbounded), + ], + 535: [ + (Included(6), Excluded(14)), + ], + }, + 9: { + 447: [ + (Included(8), Excluded(12)), + ], + 595: [ + (Included(0), Excluded(16)), + ], + }, + 10: { + 396: [ + (Included(3), Excluded(8)), + ], + 455: [ + (Included(0), Excluded(17)), + ], + 523: [ + (Included(0), Excluded(14)), + ], + 562: [ + (Included(1), Excluded(12)), + ], + }, + 11: {}, + 13: { + 562: [ + (Included(0), Excluded(18)), + ], + }, + 14: { + 346: [ + (Included(2), Excluded(13)), + ], + 445: [ + (Included(0), Unbounded), + ], + 484: [ + (Included(6), Unbounded), + ], + }, + 17: { + 364: [ + (Included(5), Excluded(13)), + ], + }, + 18: { + 349: [ + (Included(1), Excluded(8)), + ], + 410: [ + (Included(0), Excluded(14)), + ], + 448: [ + (Included(3), Unbounded), + ], + 491: [ + (Included(6), Unbounded), + ], + 627: [ + (Included(1), Excluded(12)), + ], + }, + 19: { + 437: [ + (Included(0), Unbounded), + ], + 523: [ + (Included(0), Unbounded), + ], + 541: [ + (Included(8), Unbounded), + ], + 601: [ + (Included(6), Excluded(13)), + ], + 662: [ + (Included(7), Excluded(19)), + ], + }, + }, + 346: { + 1: { + 400: [ + (Included(4), Excluded(5)), + ], + 560: [ + (Included(4), Excluded(5)), + ], + 574: [ + (Included(0), Excluded(15)), + ], + 662: [ + (Included(5), Excluded(17)), + ], + }, + 2: { + 396: [ + (Included(9), Excluded(16)), + ], + 455: [ + (Included(8), Excluded(10)), + ], + 484: [ + (Included(0), Excluded(17)), + ], + 535: [ + (Included(3), Excluded(14)), + ], + }, + 4: { + 455: [ + (Included(4), Excluded(5)), + ], + 484: [ + (Included(2), Excluded(17)), + ], + 495: [ + (Included(4), Excluded(10)), + ], + 535: [ + (Included(6), Excluded(13)), + ], + 608: [ + (Included(0), Unbounded), + ], + }, + 6: { + 349: [ + (Included(1), Excluded(5)), + ], + 599: [ + (Included(4), Unbounded), + ], + 608: [ + (Included(6), Excluded(13)), + ], + 635: [ + (Included(7), Unbounded), + ], + }, + 10: {}, + 12: { + 505: [ + (Included(3), Excluded(18)), + ], + 627: [ + (Included(7), Excluded(15)), + ], + }, + 13: { + 352: [ + (Included(0), Excluded(16)), + ], + 437: [ + (Included(0), Excluded(12)), + ], + 448: [ + (Included(6), Excluded(17)), + ], + 600: [ + (Included(9), Excluded(10)), + ], + 635: [ + (Included(5), Unbounded), + ], + 662: [ + (Included(0), Excluded(18)), + ], + }, + 14: { + 500: [ + (Included(5), Excluded(13)), + ], + 589: [ + (Included(7), Excluded(11)), + ], + }, + 16: { + 418: [ + (Included(3), Excluded(17)), + ], + 455: [ + (Included(8), Excluded(17)), + ], + 660: [ + (Included(3), Excluded(10)), + ], + }, + 18: { + 666: [ + (Included(0), Unbounded), + ], + }, + 19: { + 349: [ + (Included(4), Excluded(9)), + ], + 351: [ + (Included(0), Excluded(7)), + ], + 450: [ + (Included(6), Excluded(17)), + ], + }, + }, + 348: { + 2: { + 484: [ + (Included(0), Excluded(5)), + ], + }, + 3: { + 385: [ + (Included(5), Unbounded), + ], + 400: [ + (Included(0), Unbounded), + ], + 477: [ + (Included(1), Excluded(13)), + ], + 608: [ + (Included(0), Unbounded), + ], + 613: [ + (Included(0), Unbounded), + ], + }, + 4: { + 484: [ + (Included(7), Excluded(11)), + ], + 491: [ + (Included(0), Unbounded), + ], + 593: [ + (Included(0), Excluded(13)), + ], + 619: [ + (Included(2), Unbounded), + ], + 627: [ + (Included(1), Excluded(19)), + ], + }, + 7: { + 370: [ + (Included(6), Unbounded), + ], + 418: [ + (Included(9), Unbounded), + ], + 500: [ + (Included(5), Excluded(13)), + ], + 547: [ + (Included(1), Excluded(14)), + ], + 594: [ + (Included(4), Excluded(6)), + ], + 595: [ + (Included(2), Excluded(11)), + ], + }, + 8: { + 505: [ + (Included(3), Unbounded), + ], + 547: [ + (Included(2), Excluded(4)), + ], + 559: [ + (Included(8), Excluded(9)), + ], + 560: [ + (Included(2), Unbounded), + ], + 562: [ + (Included(0), Excluded(12)), + ], + 594: [ + (Included(1), Unbounded), + ], + }, + 9: { + 418: [ + (Included(0), Excluded(19)), + ], + 477: [ + (Included(8), Unbounded), + ], + 505: [ + (Included(0), Excluded(11)), + ], + 574: [ + (Included(1), Unbounded), + ], + }, + 10: { + 349: [ + (Included(5), Excluded(13)), + ], + 471: [ + (Included(2), Excluded(3)), + ], + }, + 11: { + 494: [ + (Included(0), Excluded(2)), + ], + }, + 12: { + 541: [ + (Included(6), Unbounded), + ], + 599: [ + (Included(1), Excluded(8)), + ], + }, + 13: { + 600: [ + (Included(6), Excluded(10)), + ], + 635: [ + (Included(1), Unbounded), + ], + 650: [ + (Included(7), Unbounded), + ], + }, + 14: { + 437: [ + (Included(0), Excluded(12)), + ], + 594: [ + (Included(1), Excluded(12)), + ], + }, + 15: { + 477: [ + (Included(1), Excluded(3)), + ], + 500: [ + (Included(6), Unbounded), + ], + }, + 16: { + 405: [ + (Included(4), Excluded(15)), + ], + 523: [ + (Included(8), Excluded(11)), + ], + 595: [ + (Included(0), Unbounded), + ], + 606: [ + (Included(7), Excluded(8)), + ], + 625: [ + (Included(0), Excluded(2)), + ], + }, + 17: { + 495: [ + (Included(9), Unbounded), + ], + }, + 18: {}, + }, + 349: { + 0: { + 352: [ + (Included(0), Excluded(17)), + ], + 599: [ + (Included(1), Excluded(14)), + ], + 601: [ + (Included(4), Excluded(17)), + ], + }, + 1: { + 559: [ + (Included(9), Excluded(13)), + ], + 593: [ + (Included(0), Excluded(12)), + ], + }, + 2: { + 396: [ + (Included(4), Excluded(12)), + ], + 600: [ + (Included(9), Unbounded), + ], + }, + 3: {}, + 4: { + 450: [ + (Included(3), Excluded(6)), + ], + 505: [ + (Included(1), Excluded(3)), + ], + 547: [ + (Included(0), Excluded(3)), + ], + }, + 5: { + 484: [ + (Included(4), Excluded(5)), + ], + 541: [ + (Included(5), Excluded(16)), + ], + 627: [ + (Included(7), Excluded(8)), + ], + }, + 6: { + 500: [ + (Included(0), Excluded(6)), + ], + 625: [ + (Included(6), Excluded(9)), + ], + }, + 7: { + 418: [ + (Included(9), Unbounded), + ], + 541: [ + (Included(7), Excluded(9)), + ], + 601: [ + (Included(7), Unbounded), + ], + }, + 8: { + 445: [ + (Included(0), Excluded(6)), + ], + 450: [ + (Included(4), Excluded(8)), + ], + 541: [ + (Included(8), Excluded(9)), + ], + 547: [ + (Included(3), Excluded(13)), + ], + 600: [ + (Included(8), Unbounded), + ], + 601: [ + (Included(0), Excluded(5)), + ], + 619: [ + (Included(0), Excluded(5)), + ], + }, + 9: { + 396: [ + (Included(0), Excluded(15)), + ], + 405: [ + (Included(1), Excluded(2)), + ], + }, + 10: { + 627: [ + (Included(7), Excluded(18)), + ], + }, + 11: { + 495: [ + (Included(0), Excluded(9)), + ], + 523: [ + (Included(8), Excluded(11)), + ], + }, + 12: { + 477: [ + (Included(0), Excluded(3)), + ], + }, + 14: { + 385: [ + (Included(0), Excluded(6)), + ], + 576: [ + (Included(8), Excluded(18)), + ], + 589: [ + (Included(0), Excluded(8)), + ], + 608: [ + (Included(0), Excluded(7)), + ], + 662: [ + (Included(3), Excluded(8)), + ], + }, + 17: { + 396: [ + (Included(5), Excluded(18)), + ], + 455: [ + (Included(4), Excluded(16)), + ], + }, + }, + 352: { + 5: {}, + 6: { + 477: [ + (Included(9), Excluded(14)), + ], + 562: [ + (Included(2), Unbounded), + ], + }, + 9: { + 601: [ + (Included(1), Excluded(6)), + ], + }, + 10: { + 574: [ + (Included(8), Excluded(10)), + ], + }, + 14: { + 437: [ + (Included(5), Excluded(16)), + ], + 584: [ + (Included(3), Excluded(12)), + ], + 647: [ + (Included(0), Unbounded), + ], + }, + 15: { + 477: [ + (Included(1), Excluded(14)), + ], + 560: [ + (Included(0), Excluded(7)), + ], + 594: [ + (Included(1), Unbounded), + ], + }, + 16: { + 613: [ + (Included(8), Unbounded), + ], + }, + 17: { + 477: [ + (Included(2), Excluded(14)), + ], + 484: [ + (Included(6), Excluded(18)), + ], + 547: [ + (Included(0), Excluded(5)), + ], + 593: [ + (Included(4), Excluded(13)), + ], + 613: [ + (Included(0), Unbounded), + ], + }, + }, + 364: { + 0: { + 562: [ + (Included(8), Excluded(18)), + ], + }, + 4: { + 523: [ + (Included(1), Excluded(7)), + ], + }, + 5: { + 601: [ + (Included(4), Excluded(9)), + ], + 645: [ + (Included(6), Unbounded), + ], + }, + 7: { + 396: [ + (Included(3), Excluded(11)), + ], + }, + 9: { + 595: [ + (Included(2), Excluded(15)), + ], + }, + 10: {}, + 11: {}, + 12: { + 437: [ + (Included(0), Unbounded), + ], + 455: [ + (Included(0), Excluded(18)), + ], + 484: [ + (Included(8), Excluded(11)), + ], + 601: [ + (Included(1), Excluded(13)), + ], + }, + 14: { + 589: [ + (Included(7), Excluded(8)), + ], + }, + }, + 371: { + 9: { + 400: [ + (Included(0), Excluded(1)), + ], + 455: [ + (Included(0), Excluded(9)), + ], + 477: [ + (Included(9), Excluded(16)), + ], + 645: [ + (Included(0), Excluded(7)), + ], + }, + 11: { + 405: [ + (Included(5), Excluded(7)), + ], + 410: [ + (Included(0), Excluded(6)), + ], + 547: [ + (Included(2), Excluded(13)), + ], + 574: [ + (Included(2), Excluded(12)), + ], + 576: [ + (Included(0), Excluded(18)), + ], + 589: [ + (Included(6), Excluded(8)), + ], + }, + 12: { + 443: [ + (Included(0), Excluded(15)), + ], + 475: [ + (Included(0), Excluded(4)), + ], + 547: [ + (Included(0), Excluded(14)), + ], + 562: [ + (Included(0), Excluded(18)), + ], + }, + 13: { + 400: [ + (Included(0), Excluded(1)), + ], + 601: [ + (Included(4), Excluded(15)), + ], + }, + 18: { + 455: [ + (Included(7), Excluded(13)), + ], + 627: [ + (Included(0), Excluded(16)), + ], + }, + 19: { + 495: [ + (Included(0), Excluded(10)), + ], + 505: [ + (Included(0), Excluded(11)), + ], + 523: [ + (Included(1), Excluded(15)), + ], + }, + }, + 396: { + 1: { + 477: [ + (Included(4), Excluded(10)), + ], + 574: [ + (Included(1), Excluded(19)), + ], + 606: [ + (Included(6), Unbounded), + ], + }, + 3: { + 562: [ + (Included(8), Excluded(18)), + ], + 569: [ + (Included(0), Excluded(17)), + ], + 576: [ + (Included(5), Unbounded), + ], + }, + 4: { + 535: [ + (Included(8), Excluded(14)), + ], + 589: [ + (Included(1), Excluded(9)), + ], + 627: [ + (Included(7), Unbounded), + ], + }, + 5: { + 484: [ + (Included(4), Excluded(18)), + ], + }, + 7: { + 562: [ + (Included(2), Unbounded), + ], + 608: [ + (Included(0), Unbounded), + ], + }, + 9: { + 448: [ + (Included(5), Excluded(17)), + ], + 523: [ + (Included(9), Excluded(10)), + ], + 660: [ + (Included(0), Unbounded), + ], + }, + 10: { + 484: [ + (Included(0), Excluded(15)), + ], + 547: [ + (Included(1), Excluded(13)), + ], + 619: [ + (Included(2), Excluded(9)), + ], + }, + 11: { + 441: [ + (Included(8), Excluded(16)), + ], + 589: [ + (Included(7), Excluded(11)), + ], + }, + 14: { + 535: [ + (Included(2), Unbounded), + ], + 650: [ + (Included(2), Excluded(15)), + ], + }, + 15: { + 418: [ + (Included(8), Unbounded), + ], + 495: [ + (Included(1), Excluded(13)), + ], + 523: [ + (Included(8), Excluded(14)), + ], + 547: [ + (Included(1), Excluded(19)), + ], + 627: [ + (Included(7), Unbounded), + ], + 650: [ + (Included(0), Excluded(15)), + ], + }, + 17: { + 441: [ + (Included(5), Unbounded), + ], + }, + 18: { + 443: [ + (Included(0), Excluded(1)), + ], + 662: [ + (Included(6), Excluded(18)), + ], + }, + 19: { + 443: [ + (Included(2), Excluded(15)), + ], + 593: [ + (Included(0), Excluded(5)), + ], + }, + }, + 400: { + 0: { + 443: [ + (Included(0), Excluded(13)), + ], + 462: [ + (Included(4), Excluded(5)), + ], + }, + 4: { + 666: [ + (Included(0), Unbounded), + ], + }, + 9: { + 462: [ + (Included(4), Unbounded), + ], + 599: [ + (Included(0), Excluded(3)), + ], + 600: [ + (Included(6), Excluded(8)), + ], + }, + }, + 405: { + 0: { + 455: [ + (Included(8), Excluded(9)), + ], + 599: [ + (Included(7), Excluded(15)), + ], + 625: [ + (Included(6), Excluded(7)), + ], + }, + 1: { + 484: [ + (Included(6), Excluded(17)), + ], + 594: [ + (Included(1), Excluded(6)), + ], + 662: [ + (Included(6), Excluded(18)), + ], + }, + 2: { + 410: [ + (Included(0), Unbounded), + ], + 477: [ + (Included(2), Excluded(16)), + ], + 484: [ + (Included(4), Excluded(9)), + ], + 601: [ + (Included(2), Excluded(17)), + ], + }, + 4: { + 450: [ + (Included(4), Excluded(17)), + ], + 462: [ + (Included(2), Excluded(7)), + ], + 495: [ + (Included(0), Unbounded), + ], + 559: [ + (Included(0), Unbounded), + ], + 562: [ + (Included(8), Excluded(13)), + ], + }, + 5: { + 447: [ + (Included(8), Excluded(12)), + ], + 477: [ + (Included(2), Unbounded), + ], + 600: [ + (Included(6), Unbounded), + ], + }, + 6: { + 495: [ + (Included(0), Excluded(6)), + ], + 594: [ + (Included(2), Unbounded), + ], + 635: [ + (Included(4), Excluded(16)), + ], + }, + 7: { + 547: [ + (Included(2), Excluded(12)), + ], + 562: [ + (Included(0), Excluded(15)), + ], + }, + 9: { + 635: [ + (Included(4), Excluded(10)), + ], + }, + 10: { + 547: [ + (Included(5), Excluded(19)), + ], + 559: [ + (Included(0), Excluded(12)), + ], + }, + 11: {}, + 13: { + 450: [ + (Included(3), Excluded(17)), + ], + 523: [ + (Included(9), Excluded(15)), + ], + 562: [ + (Included(1), Excluded(15)), + ], + 574: [ + (Included(0), Unbounded), + ], + 627: [ + (Included(7), Excluded(19)), + ], + }, + 14: { + 600: [ + (Included(0), Excluded(9)), + ], + 650: [ + (Included(7), Excluded(15)), + ], + }, + 17: { + 450: [ + (Included(7), Excluded(17)), + ], + 491: [ + (Included(0), Excluded(6)), + ], + 505: [ + (Included(2), Excluded(10)), + ], + }, + }, + 410: { + 3: { + 475: [ + (Included(0), Excluded(4)), + ], + 484: [ + (Included(0), Excluded(18)), + ], + 505: [ + (Included(1), Excluded(18)), + ], + 660: [ + (Included(3), Excluded(10)), + ], + }, + 5: { + 447: [ + (Included(8), Unbounded), + ], + 477: [ + (Included(1), Excluded(13)), + ], + }, + 7: {}, + 9: { + 569: [ + (Included(2), Excluded(19)), + ], + }, + 13: { + 491: [ + (Included(5), Excluded(6)), + ], + 541: [ + (Included(8), Unbounded), + ], + }, + 16: { + 484: [ + (Included(0), Excluded(15)), + ], + 523: [ + (Included(0), Excluded(14)), + ], + 601: [ + (Included(4), Excluded(15)), + ], + }, + 18: { + 477: [ + (Included(1), Excluded(14)), + ], + 595: [ + (Included(0), Excluded(14)), + ], + }, + }, + 418: { + 0: { + 627: [ + (Included(3), Excluded(15)), + ], + }, + 3: { + 450: [ + (Included(3), Excluded(6)), + ], + 535: [ + (Included(3), Excluded(16)), + ], + 627: [ + (Included(7), Excluded(13)), + ], + }, + 8: { + 484: [ + (Included(7), Excluded(8)), + ], + 574: [ + (Included(0), Excluded(12)), + ], + 601: [ + (Included(2), Excluded(18)), + ], + }, + 15: { + 441: [ + (Included(0), Excluded(16)), + ], + 450: [ + (Included(4), Unbounded), + ], + }, + 16: { + 662: [ + (Included(0), Unbounded), + ], + }, + 18: { + 437: [ + (Included(0), Excluded(16)), + ], + 576: [ + (Included(8), Excluded(9)), + ], + 595: [ + (Included(3), Excluded(17)), + ], + }, + 19: { + 505: [ + (Included(0), Excluded(2)), + ], + }, + }, + 437: { + 11: { + 450: [ + (Included(6), Excluded(11)), + ], + }, + 15: { + 535: [ + (Included(8), Unbounded), + ], + 541: [ + (Included(3), Excluded(16)), + ], + 593: [ + (Included(9), Excluded(12)), + ], + 600: [ + (Included(0), Excluded(8)), + ], + 635: [ + (Included(9), Unbounded), + ], + }, + 16: { + 450: [ + (Included(4), Excluded(17)), + ], + 475: [ + (Included(9), Unbounded), + ], + 500: [ + (Included(0), Excluded(3)), + ], + 547: [ + (Included(3), Excluded(17)), + ], + 593: [ + (Included(8), Excluded(13)), + ], + }, + }, + 441: { + 2: {}, + 8: { + 462: [ + (Included(3), Excluded(8)), + ], + 491: [ + (Included(3), Excluded(6)), + ], + }, + 13: { + 445: [ + (Included(8), Unbounded), + ], + 569: [ + (Included(0), Excluded(13)), + ], + }, + 15: { + 455: [ + (Included(4), Excluded(5)), + ], + 505: [ + (Included(6), Excluded(14)), + ], + }, + 16: { + 560: [ + (Included(8), Unbounded), + ], + 589: [ + (Included(8), Excluded(11)), + ], + }, + }, + 443: { + 0: { + 447: [ + (Included(0), Excluded(12)), + ], + 500: [ + (Included(0), Unbounded), + ], + 505: [ + (Included(0), Excluded(18)), + ], + 547: [ + (Included(3), Unbounded), + ], + }, + 12: { + 523: [ + (Included(6), Excluded(19)), + ], + 562: [ + (Included(0), Excluded(13)), + ], + 606: [ + (Included(0), Excluded(7)), + ], + }, + 14: { + 450: [ + (Included(3), Excluded(15)), + ], + 574: [ + (Included(0), Excluded(2)), + ], + 595: [ + (Included(2), Excluded(14)), + ], + }, + 17: { + 569: [ + (Included(6), Unbounded), + ], + }, + }, + 447: { + 1: { + 541: [ + (Included(8), Unbounded), + ], + }, + 8: { + 645: [ + (Included(0), Excluded(1)), + ], + }, + 11: { + 541: [ + (Included(6), Excluded(9)), + ], + }, + 13: { + 606: [ + (Included(6), Excluded(17)), + ], + 662: [ + (Included(6), Unbounded), + ], + }, + 14: { + 450: [ + (Included(6), Excluded(15)), + ], + 500: [ + (Included(0), Unbounded), + ], + 541: [ + (Included(6), Excluded(15)), + ], + }, + }, + 448: { + 3: { + 562: [ + (Included(8), Excluded(11)), + ], + 662: [ + (Included(6), Excluded(18)), + ], + }, + 11: { + 450: [ + (Included(0), Excluded(17)), + ], + 455: [ + (Included(0), Excluded(16)), + ], + 477: [ + (Included(0), Unbounded), + ], + 505: [ + (Included(1), Excluded(7)), + ], + 601: [ + (Included(1), Excluded(5)), + ], + 625: [ + (Included(4), Excluded(7)), + ], + 650: [ + (Included(0), Excluded(15)), + ], + 660: [ + (Included(0), Unbounded), + ], + }, + 12: { + 562: [ + (Included(0), Excluded(15)), + ], + }, + 13: { + 455: [ + (Included(7), Unbounded), + ], + 650: [ + (Included(4), Excluded(15)), + ], + }, + 15: {}, + 16: { + 660: [ + (Included(0), Excluded(4)), + ], + }, + 19: { + 484: [ + (Included(7), Excluded(8)), + ], + 601: [ + (Included(4), Excluded(7)), + ], + }, + }, + 450: { + 2: { + 601: [ + (Included(1), Excluded(18)), + ], + }, + 3: { + 505: [ + (Included(1), Excluded(2)), + ], + }, + 4: {}, + 5: { + 484: [ + (Included(8), Excluded(17)), + ], + 547: [ + (Included(4), Excluded(13)), + ], + 576: [ + (Included(8), Unbounded), + ], + 594: [ + (Included(4), Unbounded), + ], + }, + 6: { + 645: [ + (Included(5), Unbounded), + ], + }, + 7: { + 477: [ + (Included(0), Excluded(5)), + ], + 593: [ + (Included(9), Unbounded), + ], + 645: [ + (Included(6), Unbounded), + ], + }, + 10: {}, + 13: { + 495: [ + (Included(3), Excluded(5)), + ], + }, + 14: { + 471: [ + (Included(2), Unbounded), + ], + 495: [ + (Included(9), Excluded(12)), + ], + 562: [ + (Included(2), Excluded(15)), + ], + 619: [ + (Included(2), Excluded(7)), + ], + }, + 16: { + 500: [ + (Included(0), Unbounded), + ], + 535: [ + (Included(2), Excluded(14)), + ], + 594: [ + (Included(4), Excluded(12)), + ], + }, + 17: { + 560: [ + (Included(0), Excluded(9)), + ], + 562: [ + (Included(1), Unbounded), + ], + 599: [ + (Included(0), Excluded(2)), + ], + }, + 19: { + 471: [ + (Included(2), Unbounded), + ], + 523: [ + (Included(0), Excluded(14)), + ], + 576: [ + (Included(0), Excluded(16)), + ], + 645: [ + (Included(2), Unbounded), + ], + 662: [ + (Included(7), Excluded(9)), + ], + }, + }, + 455: { + 2: { + 491: [ + (Included(0), Excluded(1)), + ], + 559: [ + (Included(0), Excluded(12)), + ], + 560: [ + (Included(0), Unbounded), + ], + }, + 4: { + 600: [ + (Included(0), Excluded(13)), + ], + }, + 7: { + 484: [ + (Included(4), Excluded(17)), + ], + 574: [ + (Included(2), Excluded(15)), + ], + 595: [ + (Included(0), Excluded(2)), + ], + }, + 8: { + 560: [ + (Included(6), Unbounded), + ], + 574: [ + (Included(4), Excluded(12)), + ], + 599: [ + (Included(7), Excluded(14)), + ], + }, + 9: { + 562: [ + (Included(4), Excluded(18)), + ], + 595: [ + (Included(0), Excluded(14)), + ], + 601: [ + (Included(0), Excluded(6)), + ], + }, + 10: { + 600: [ + (Included(6), Excluded(8)), + ], + 613: [ + (Included(6), Unbounded), + ], + 662: [ + (Included(3), Excluded(9)), + ], + }, + 12: { + 666: [ + (Included(0), Unbounded), + ], + }, + 15: { + 666: [ + (Included(0), Unbounded), + ], + }, + 16: { + 495: [ + (Included(3), Excluded(4)), + ], + 599: [ + (Included(2), Excluded(3)), + ], + 650: [ + (Included(2), Unbounded), + ], + }, + 17: { + 491: [ + (Included(9), Excluded(10)), + ], + 569: [ + (Included(3), Excluded(19)), + ], + 662: [ + (Included(7), Excluded(19)), + ], + }, + 19: {}, + }, + 462: { + 1: {}, + 2: { + 477: [ + (Included(0), Excluded(10)), + ], + 574: [ + (Included(2), Excluded(12)), + ], + 601: [ + (Included(4), Excluded(17)), + ], + 606: [ + (Included(6), Unbounded), + ], + 625: [ + (Included(4), Excluded(9)), + ], + }, + 3: { + 589: [ + (Included(8), Excluded(11)), + ], + 608: [ + (Included(9), Unbounded), + ], + }, + 4: { + 479: [ + (Included(0), Excluded(6)), + ], + 635: [ + (Included(1), Excluded(5)), + ], + }, + 6: { + 535: [ + (Included(6), Unbounded), + ], + 599: [ + (Included(2), Excluded(14)), + ], + 608: [ + (Included(0), Excluded(5)), + ], + 613: [ + (Included(8), Excluded(11)), + ], + }, + 7: { + 484: [ + (Included(2), Excluded(18)), + ], + 574: [ + (Included(4), Excluded(19)), + ], + 606: [ + (Included(6), Excluded(17)), + ], + }, + 12: { + 477: [ + (Included(1), Excluded(8)), + ], + 547: [ + (Included(4), Excluded(18)), + ], + 574: [ + (Included(9), Unbounded), + ], + 593: [ + (Included(8), Excluded(14)), + ], + }, + 14: { + 491: [ + (Included(3), Excluded(7)), + ], + }, + 16: { + 608: [ + (Included(0), Excluded(7)), + ], + }, + }, + 471: { + 1: { + 484: [ + (Included(2), Excluded(9)), + ], + 569: [ + (Included(8), Excluded(10)), + ], + 599: [ + (Included(1), Excluded(13)), + ], + }, + 2: { + 494: [ + (Included(0), Unbounded), + ], + 608: [ + (Included(0), Unbounded), + ], + }, + 18: { + 484: [ + (Included(4), Excluded(18)), + ], + 523: [ + (Included(9), Excluded(10)), + ], + 576: [ + (Included(7), Excluded(18)), + ], + 662: [ + (Included(8), Excluded(18)), + ], + }, + }, + 475: { + 0: { + 500: [ + (Included(6), Unbounded), + ], + 560: [ + (Included(4), Unbounded), + ], + 569: [ + (Included(2), Unbounded), + ], + 589: [ + (Included(8), Excluded(11)), + ], + 608: [ + (Included(6), Excluded(10)), + ], + }, + 3: { + 599: [ + (Included(1), Excluded(8)), + ], + 619: [ + (Included(2), Excluded(15)), + ], + }, + 9: { + 593: [ + (Included(4), Excluded(13)), + ], + }, + }, + 477: { + 0: { + 505: [ + (Included(1), Excluded(18)), + ], + 562: [ + (Included(0), Excluded(13)), + ], + }, + 1: { + 523: [ + (Included(0), Excluded(15)), + ], + }, + 2: { + 484: [ + (Included(0), Excluded(12)), + ], + 608: [ + (Included(0), Excluded(13)), + ], + }, + 4: { + 541: [ + (Included(4), Excluded(16)), + ], + 601: [ + (Included(0), Excluded(1)), + ], + }, + 7: { + 569: [ + (Included(0), Excluded(19)), + ], + 600: [ + (Included(0), Unbounded), + ], + }, + 9: { + 484: [ + (Included(2), Excluded(15)), + ], + 569: [ + (Included(8), Excluded(19)), + ], + 608: [ + (Included(9), Excluded(13)), + ], + 645: [ + (Included(5), Excluded(7)), + ], + 650: [ + (Included(7), Excluded(15)), + ], + 660: [ + (Included(0), Excluded(4)), + ], + }, + 12: {}, + 13: { + 495: [ + (Included(3), Excluded(6)), + ], + 535: [ + (Included(5), Excluded(7)), + ], + 595: [ + (Included(3), Excluded(16)), + ], + }, + 15: { + 635: [ + (Included(5), Excluded(18)), + ], + }, + 18: { + 495: [ + (Included(3), Excluded(10)), + ], + 562: [ + (Included(4), Excluded(15)), + ], + 574: [ + (Included(1), Excluded(19)), + ], + 613: [ + (Included(8), Excluded(11)), + ], + }, + 19: { + 584: [ + (Included(0), Excluded(12)), + ], + 600: [ + (Included(9), Excluded(13)), + ], + 608: [ + (Included(0), Excluded(5)), + ], + }, + }, + 479: { + 5: { + 523: [ + (Included(0), Unbounded), + ], + }, + 14: { + 484: [ + (Included(0), Excluded(8)), + ], + 589: [ + (Included(1), Excluded(7)), + ], + }, + }, + 484: { + 0: { + 594: [ + (Included(0), Excluded(12)), + ], + }, + 2: { + 505: [ + (Included(9), Excluded(14)), + ], + 535: [ + (Included(3), Unbounded), + ], + 560: [ + (Included(2), Excluded(9)), + ], + 574: [ + (Included(2), Excluded(5)), + ], + }, + 4: { + 574: [ + (Included(0), Excluded(1)), + ], + }, + 6: { + 662: [ + (Included(5), Excluded(17)), + ], + }, + 7: { + 491: [ + (Included(3), Excluded(4)), + ], + 613: [ + (Included(0), Excluded(4)), + ], + }, + 8: { + 541: [ + (Included(6), Unbounded), + ], + }, + 10: {}, + 11: { + 541: [ + (Included(6), Excluded(17)), + ], + }, + 14: { + 645: [ + (Included(0), Unbounded), + ], + }, + 16: { + 491: [ + (Included(3), Unbounded), + ], + 600: [ + (Included(8), Unbounded), + ], + 613: [ + (Included(0), Excluded(4)), + ], + }, + 17: { + 635: [ + (Included(9), Excluded(18)), + ], + }, + 18: { + 495: [ + (Included(5), Excluded(10)), + ], + 574: [ + (Included(0), Excluded(12)), + ], + 601: [ + (Included(0), Excluded(19)), + ], + }, + }, + 491: { + 0: {}, + 2: { + 595: [ + (Included(6), Unbounded), + ], + 662: [ + (Included(5), Excluded(17)), + ], + }, + 3: { + 547: [ + (Included(7), Excluded(19)), + ], + }, + 5: { + 595: [ + (Included(4), Excluded(16)), + ], + 647: [ + (Included(0), Excluded(4)), + ], + }, + 6: { + 662: [ + (Included(6), Excluded(18)), + ], + }, + 9: { + 662: [ + (Included(6), Unbounded), + ], + }, + 18: { + 569: [ + (Included(6), Excluded(13)), + ], + 594: [ + (Included(5), Excluded(6)), + ], + 595: [ + (Included(0), Excluded(17)), + ], + 635: [ + (Included(4), Unbounded), + ], + 662: [ + (Included(7), Unbounded), + ], + }, + }, + 494: { + 1: { + 547: [ + (Included(1), Excluded(19)), + ], + 562: [ + (Included(0), Unbounded), + ], + 599: [ + (Included(2), Excluded(8)), + ], + 619: [ + (Included(6), Excluded(11)), + ], + }, + 5: { + 574: [ + (Included(8), Unbounded), + ], + 601: [ + (Included(0), Excluded(19)), + ], + }, + 12: { + 495: [ + (Included(1), Unbounded), + ], + 601: [ + (Included(6), Unbounded), + ], + 645: [ + (Included(6), Excluded(7)), + ], + }, + }, + 495: { + 1: {}, + 3: { + 608: [ + (Included(6), Excluded(13)), + ], + }, + 4: {}, + 5: { + 595: [ + (Included(5), Excluded(17)), + ], + 650: [ + (Included(4), Excluded(15)), + ], + }, + 8: { + 576: [ + (Included(0), Excluded(9)), + ], + }, + 9: {}, + 11: { + 547: [ + (Included(6), Excluded(13)), + ], + 559: [ + (Included(8), Excluded(12)), + ], + 594: [ + (Included(1), Unbounded), + ], + 613: [ + (Included(8), Unbounded), + ], + 645: [ + (Included(0), Excluded(7)), + ], + }, + 12: { + 662: [ + (Included(0), Excluded(4)), + ], + }, + 16: { + 608: [ + (Included(9), Unbounded), + ], + }, + }, + 500: { + 2: { + 613: [ + (Included(8), Unbounded), + ], + }, + 5: { + 594: [ + (Included(0), Unbounded), + ], + }, + 12: {}, + 16: { + 601: [ + (Included(6), Excluded(13)), + ], + 627: [ + (Included(7), Unbounded), + ], + }, + }, + 505: { + 0: { + 535: [ + (Included(0), Excluded(14)), + ], + }, + 1: { + 666: [ + (Included(0), Unbounded), + ], + }, + 2: { + 535: [ + (Included(8), Excluded(13)), + ], + 619: [ + (Included(0), Excluded(5)), + ], + 662: [ + (Included(7), Excluded(19)), + ], + }, + 6: { + 559: [ + (Included(1), Excluded(12)), + ], + }, + 9: {}, + 10: { + 589: [ + (Included(1), Excluded(2)), + ], + 595: [ + (Included(0), Unbounded), + ], + }, + 13: { + 584: [ + (Included(1), Excluded(12)), + ], + 589: [ + (Included(0), Excluded(8)), + ], + 595: [ + (Included(0), Excluded(16)), + ], + 600: [ + (Included(0), Excluded(13)), + ], + 619: [ + (Included(4), Excluded(15)), + ], + }, + 17: { + 589: [ + (Included(7), Excluded(8)), + ], + 619: [ + (Included(6), Excluded(9)), + ], + }, + 18: { + 547: [ + (Included(6), Excluded(12)), + ], + }, + }, + 523: { + 0: { + 613: [ + (Included(0), Unbounded), + ], + }, + 1: { + 608: [ + (Included(0), Excluded(13)), + ], + 662: [ + (Included(7), Excluded(19)), + ], + }, + 6: {}, + 8: { + 594: [ + (Included(0), Excluded(12)), + ], + 600: [ + (Included(6), Excluded(10)), + ], + }, + 9: { + 562: [ + (Included(7), Unbounded), + ], + 569: [ + (Included(6), Excluded(17)), + ], + }, + 10: {}, + 11: { + 535: [ + (Included(8), Unbounded), + ], + 576: [ + (Included(8), Excluded(16)), + ], + 619: [ + (Included(4), Excluded(5)), + ], + }, + 13: { + 593: [ + (Included(6), Excluded(14)), + ], + }, + 14: { + 645: [ + (Included(6), Unbounded), + ], + }, + 18: { + 619: [ + (Included(0), Excluded(5)), + ], + 625: [ + (Included(4), Unbounded), + ], + 627: [ + (Included(4), Excluded(16)), + ], + }, + 19: { + 535: [ + (Included(0), Excluded(14)), + ], + 650: [ + (Included(0), Unbounded), + ], + }, + }, + 535: { + 1: { + 599: [ + (Included(6), Excluded(11)), + ], + }, + 5: { + 547: [ + (Included(2), Excluded(14)), + ], + 559: [ + (Included(0), Excluded(10)), + ], + }, + 6: { + 541: [ + (Included(0), Unbounded), + ], + }, + 8: {}, + 12: {}, + 13: { + 635: [ + (Included(5), Excluded(10)), + ], + 662: [ + (Included(7), Excluded(9)), + ], + }, + 15: { + 608: [ + (Included(0), Excluded(7)), + ], + }, + 16: { + 625: [ + (Included(4), Excluded(9)), + ], + 627: [ + (Included(8), Unbounded), + ], + }, + }, + 541: { + 1: { + 601: [ + (Included(1), Excluded(15)), + ], + }, + 6: {}, + 7: { + 547: [ + (Included(4), Excluded(19)), + ], + 593: [ + (Included(4), Excluded(9)), + ], + 650: [ + (Included(4), Unbounded), + ], + }, + 8: { + 625: [ + (Included(4), Excluded(7)), + ], + }, + 13: { + 574: [ + (Included(2), Excluded(15)), + ], + 589: [ + (Included(1), Unbounded), + ], + 635: [ + (Included(4), Unbounded), + ], + }, + 14: { + 547: [ + (Included(6), Unbounded), + ], + 599: [ + (Included(2), Excluded(13)), + ], + 627: [ + (Included(7), Excluded(19)), + ], + }, + 15: { + 547: [ + (Included(0), Excluded(14)), + ], + 576: [ + (Included(0), Unbounded), + ], + 662: [ + (Included(0), Excluded(4)), + ], + }, + 16: { + 645: [ + (Included(2), Excluded(7)), + ], + }, + 17: { + 650: [ + (Included(4), Unbounded), + ], + }, + }, + 547: { + 0: { + 650: [ + (Included(2), Excluded(15)), + ], + }, + 2: { + 635: [ + (Included(0), Excluded(15)), + ], + }, + 3: {}, + 4: { + 635: [ + (Included(5), Excluded(15)), + ], + 645: [ + (Included(6), Excluded(17)), + ], + }, + 5: {}, + 6: {}, + 11: { + 574: [ + (Included(1), Excluded(5)), + ], + 584: [ + (Included(3), Excluded(4)), + ], + 662: [ + (Included(0), Excluded(19)), + ], + }, + 12: {}, + 13: { + 589: [ + (Included(8), Excluded(11)), + ], + 601: [ + (Included(4), Excluded(16)), + ], + }, + 14: { + 601: [ + (Included(5), Excluded(17)), + ], + }, + 16: {}, + 17: { + 574: [ + (Included(9), Excluded(15)), + ], + 650: [ + (Included(7), Excluded(15)), + ], + 662: [ + (Included(3), Excluded(19)), + ], + }, + 18: { + 569: [ + (Included(0), Unbounded), + ], + 662: [ + (Included(0), Excluded(8)), + ], + }, + 19: {}, + }, + 559: { + 8: { + 650: [ + (Included(4), Unbounded), + ], + }, + 9: { + 560: [ + (Included(4), Excluded(9)), + ], + }, + 10: {}, + 11: { + 574: [ + (Included(1), Unbounded), + ], + }, + 12: {}, + 18: { + 601: [ + (Included(1), Excluded(15)), + ], + }, + }, + 560: { + 0: { + 589: [ + (Included(1), Excluded(11)), + ], + 613: [ + (Included(0), Excluded(9)), + ], + }, + 2: { + 593: [ + (Included(0), Excluded(13)), + ], + }, + 4: {}, + 6: { + 600: [ + (Included(0), Excluded(8)), + ], + }, + 8: { + 600: [ + (Included(8), Excluded(13)), + ], + 635: [ + (Included(4), Unbounded), + ], + }, + 16: {}, + }, + 562: { + 0: { + 576: [ + (Included(6), Excluded(17)), + ], + 593: [ + (Included(6), Unbounded), + ], + }, + 4: { + 608: [ + (Included(0), Excluded(5)), + ], + }, + 8: { + 606: [ + (Included(0), Excluded(17)), + ], + 645: [ + (Included(0), Excluded(3)), + ], + }, + 10: {}, + 11: { + 574: [ + (Included(8), Unbounded), + ], + 647: [ + (Included(0), Unbounded), + ], + }, + 12: {}, + 14: { + 569: [ + (Included(0), Excluded(10)), + ], + 635: [ + (Included(0), Unbounded), + ], + }, + 17: {}, + 18: { + 635: [ + (Included(5), Excluded(15)), + ], + 662: [ + (Included(8), Excluded(9)), + ], + }, + }, + 569: { + 3: { + 574: [ + (Included(0), Excluded(10)), + ], + }, + 6: { + 595: [ + (Included(0), Excluded(17)), + ], + 601: [ + (Included(8), Excluded(13)), + ], + 635: [ + (Included(9), Excluded(16)), + ], + }, + 8: { + 635: [ + (Included(4), Excluded(16)), + ], + 647: [ + (Included(0), Unbounded), + ], + }, + 9: { + 584: [ + (Included(1), Unbounded), + ], + }, + 12: { + 627: [ + (Included(0), Excluded(13)), + ], + }, + 13: { + 589: [ + (Included(0), Unbounded), + ], + }, + 16: { + 599: [ + (Included(2), Excluded(8)), + ], + 645: [ + (Included(0), Excluded(17)), + ], + }, + 18: { + 574: [ + (Included(4), Excluded(15)), + ], + 645: [ + (Included(6), Excluded(17)), + ], + 647: [ + (Included(0), Unbounded), + ], + }, + 19: { + 574: [ + (Included(0), Unbounded), + ], + 589: [ + (Included(8), Excluded(11)), + ], + }, + }, + 574: { + 0: { + 593: [ + (Included(0), Excluded(5)), + ], + }, + 1: { + 600: [ + (Included(9), Unbounded), + ], + }, + 2: { + 589: [ + (Included(6), Unbounded), + ], + 650: [ + (Included(4), Excluded(15)), + ], + }, + 4: {}, + 8: { + 635: [ + (Included(4), Excluded(18)), + ], + }, + 9: {}, + 10: {}, + 11: { + 601: [ + (Included(8), Excluded(16)), + ], + 625: [ + (Included(4), Excluded(5)), + ], + }, + 14: { + 576: [ + (Included(5), Excluded(17)), + ], + 593: [ + (Included(8), Unbounded), + ], + 601: [ + (Included(4), Unbounded), + ], + }, + 18: { + 650: [ + (Included(0), Excluded(8)), + ], + }, + 19: {}, + }, + 576: { + 4: { + 645: [ + (Included(5), Unbounded), + ], + }, + 7: {}, + 8: {}, + 10: { + 601: [ + (Included(0), Excluded(15)), + ], + }, + 15: { + 593: [ + (Included(4), Excluded(12)), + ], + 594: [ + (Included(0), Excluded(12)), + ], + }, + 16: { + 599: [ + (Included(4), Unbounded), + ], + }, + 17: { + 625: [ + (Included(4), Excluded(7)), + ], + }, + 19: {}, + }, + 584: { + 1: { + 599: [ + (Included(0), Excluded(2)), + ], + 600: [ + (Included(7), Excluded(13)), + ], + }, + 3: {}, + 11: {}, + 15: {}, + }, + 589: { + 0: { + 595: [ + (Included(4), Unbounded), + ], + }, + 1: {}, + 6: { + 619: [ + (Included(8), Excluded(9)), + ], + 660: [ + (Included(3), Excluded(10)), + ], + }, + 7: { + 635: [ + (Included(0), Excluded(2)), + ], + }, + 8: { + 600: [ + (Included(8), Unbounded), + ], + }, + 10: {}, + 15: { + 599: [ + (Included(4), Unbounded), + ], + 645: [ + (Included(2), Excluded(6)), + ], + }, + }, + 593: { + 0: { + 595: [ + (Included(0), Excluded(14)), + ], + 608: [ + (Included(2), Unbounded), + ], + }, + 4: { + 650: [ + (Included(4), Unbounded), + ], + }, + 6: { + 625: [ + (Included(0), Unbounded), + ], + }, + 8: {}, + 9: {}, + 11: {}, + 12: {}, + 13: {}, + 15: { + 635: [ + (Included(9), Excluded(15)), + ], + }, + }, + 594: { + 0: { + 613: [ + (Included(8), Unbounded), + ], + 619: [ + (Included(2), Unbounded), + ], + 662: [ + (Included(6), Excluded(19)), + ], + }, + 1: { + 625: [ + (Included(0), Unbounded), + ], + 647: [ + (Included(0), Excluded(4)), + ], + }, + 4: {}, + 5: {}, + 11: { + 619: [ + (Included(2), Unbounded), + ], + 662: [ + (Included(6), Excluded(16)), + ], + }, + 12: {}, + }, + 595: { + 1: {}, + 2: {}, + 10: {}, + 13: { + 599: [ + (Included(7), Excluded(11)), + ], + }, + 14: { + 619: [ + (Included(2), Excluded(15)), + ], + }, + 15: {}, + 16: {}, + 19: {}, + }, + 599: { + 0: { + 635: [ + (Included(1), Excluded(10)), + ], + }, + 1: { + 635: [ + (Included(0), Excluded(10)), + ], + }, + 2: {}, + 6: { + 625: [ + (Included(6), Excluded(9)), + ], + }, + 7: {}, + 10: { + 662: [ + (Included(3), Excluded(7)), + ], + }, + 12: {}, + 13: { + 600: [ + (Included(6), Unbounded), + ], + }, + 14: { + 601: [ + (Included(5), Excluded(18)), + ], + }, + 18: { + 627: [ + (Included(5), Excluded(18)), + ], + }, + }, + 600: { + 5: { + 625: [ + (Included(8), Unbounded), + ], + }, + 6: {}, + 7: {}, + 8: {}, + 9: { + 660: [ + (Included(3), Excluded(4)), + ], + }, + 12: {}, + 18: { + 601: [ + (Included(5), Excluded(9)), + ], + 635: [ + (Included(1), Excluded(6)), + ], + }, + }, + 601: { + 0: { + 608: [ + (Included(0), Excluded(10)), + ], + }, + 1: { + 625: [ + (Included(6), Excluded(7)), + ], + }, + 4: {}, + 5: { + 650: [ + (Included(4), Unbounded), + ], + }, + 6: { + 650: [ + (Included(2), Unbounded), + ], + }, + 8: {}, + 12: {}, + 14: {}, + 15: { + 608: [ + (Included(9), Excluded(13)), + ], + }, + 16: { + 650: [ + (Included(0), Excluded(15)), + ], + }, + 17: {}, + 18: {}, + 19: {}, + }, + 606: { + 3: { + 619: [ + (Included(8), Excluded(15)), + ], + }, + 6: {}, + 7: {}, + 16: {}, + 19: { + 662: [ + (Included(6), Excluded(16)), + ], + }, + }, + 608: { + 4: {}, + 6: { + 635: [ + (Included(5), Excluded(18)), + ], + }, + 9: {}, + 12: { + 662: [ + (Included(7), Unbounded), + ], + }, + 17: {}, + }, + 613: { + 3: {}, + 8: { + 627: [ + (Included(7), Excluded(15)), + ], + 662: [ + (Included(0), Excluded(4)), + ], + }, + 10: { + 635: [ + (Included(1), Excluded(16)), + ], + }, + 16: { + 619: [ + (Included(4), Excluded(9)), + ], + 635: [ + (Included(4), Excluded(18)), + ], + }, + }, + 619: { + 1: {}, + 2: { + 625: [ + (Included(6), Unbounded), + ], + }, + 4: { + 650: [ + (Included(0), Unbounded), + ], + }, + 6: {}, + 8: {}, + 10: {}, + 14: { + 645: [ + (Included(2), Unbounded), + ], + 662: [ + (Included(0), Excluded(8)), + ], + }, + 15: {}, + }, + 625: { + 1: { + 627: [ + (Included(2), Excluded(19)), + ], + }, + 4: {}, + 6: { + 647: [ + (Included(0), Unbounded), + ], + }, + 8: {}, + 10: {}, + }, + 627: { + 1: {}, + 3: {}, + 7: {}, + 11: {}, + 12: {}, + 14: {}, + 15: { + 650: [ + (Included(2), Excluded(15)), + ], + }, + 17: { + 662: [ + (Included(8), Excluded(19)), + ], + }, + 18: {}, + 19: { + 635: [ + (Included(4), Unbounded), + ], + }, + }, + 635: { + 0: {}, + 1: {}, + 4: { + 660: [ + (Included(0), Unbounded), + ], + }, + 5: {}, + 9: {}, + 14: { + 662: [ + (Included(5), Excluded(19)), + ], + }, + 15: {}, + 17: {}, + 18: {}, + }, + 645: { + 0: {}, + 2: { + 660: [ + (Included(3), Unbounded), + ], + }, + 5: {}, + 6: {}, + 16: {}, + 17: {}, + }, + 647: { + 3: {}, + 11: {}, + }, + 650: { + 0: {}, + 2: {}, + 7: {}, + 14: {}, + 16: { + 660: [ + (Included(0), Unbounded), + ], + }, + }, + 660: { + 1: {}, + 3: {}, + 9: { + 662: [ + (Included(3), Excluded(19)), + ], + }, + 15: {}, + }, + 662: { + 2: {}, + 3: {}, + 6: {}, + 7: {}, + 8: {}, + 15: {}, + 16: {}, + 17: {}, + 18: {}, + 19: {}, + }, +} diff --git a/test-examples/large_case_u16_NumberVersion.ron b/test-examples/large_case_u16_discrete_NumberVersion.ron similarity index 100% rename from test-examples/large_case_u16_NumberVersion.ron rename to test-examples/large_case_u16_discrete_NumberVersion.ron diff --git a/tests/examples.rs b/tests/examples.rs index 9040bc23..6bf02fc6 100644 --- a/tests/examples.rs +++ b/tests/examples.rs @@ -1,12 +1,12 @@ // SPDX-License-Identifier: MPL-2.0 -use pubgrub::range::Range; +use pubgrub::bounded_range::BoundedRange; use pubgrub::solver::{resolve, OfflineDependencyProvider}; use pubgrub::type_aliases::Map; use pubgrub::version::{NumberVersion, SemanticVersion}; -type NumVS = Range; -type SemVS = Range; +type NumVS = BoundedRange; +type SemVS = BoundedRange; use log::LevelFilter; use std::io::Write; @@ -26,13 +26,13 @@ fn no_conflict() { let mut dependency_provider = OfflineDependencyProvider::<&str, SemVS>::new(); #[rustfmt::skip] dependency_provider.add_dependencies( - "root", (1, 0, 0), - [("foo", Range::between((1, 0, 0), (2, 0, 0)))], + "root", (1, 0, 0), + [("foo", BoundedRange::between((1, 0, 0), (2, 0, 0)))], ); #[rustfmt::skip] dependency_provider.add_dependencies( - "foo", (1, 0, 0), - [("bar", Range::between((1, 0, 0), (2, 0, 0)))], + "foo", (1, 0, 0), + [("bar", BoundedRange::between((1, 0, 0), (2, 0, 0)))], ); dependency_provider.add_dependencies("bar", (1, 0, 0), []); dependency_provider.add_dependencies("bar", (2, 0, 0), []); @@ -59,14 +59,14 @@ fn avoiding_conflict_during_decision_making() { dependency_provider.add_dependencies( "root", (1, 0, 0), [ - ("foo", Range::between((1, 0, 0), (2, 0, 0))), - ("bar", Range::between((1, 0, 0), (2, 0, 0))), + ("foo", BoundedRange::between((1, 0, 0), (2, 0, 0))), + ("bar", BoundedRange::between((1, 0, 0), (2, 0, 0))), ], ); #[rustfmt::skip] dependency_provider.add_dependencies( - "foo", (1, 1, 0), - [("bar", Range::between((2, 0, 0), (3, 0, 0)))], + "foo", (1, 1, 0), + [("bar", BoundedRange::between((2, 0, 0), (3, 0, 0)))], ); dependency_provider.add_dependencies("foo", (1, 0, 0), []); dependency_provider.add_dependencies("bar", (1, 0, 0), []); @@ -93,19 +93,19 @@ fn conflict_resolution() { let mut dependency_provider = OfflineDependencyProvider::<&str, SemVS>::new(); #[rustfmt::skip] dependency_provider.add_dependencies( - "root", (1, 0, 0), - [("foo", Range::higher_than((1, 0, 0)))], + "root", (1, 0, 0), + [("foo", BoundedRange::higher_than((1, 0, 0)))], ); #[rustfmt::skip] dependency_provider.add_dependencies( - "foo", (2, 0, 0), - [("bar", Range::between((1, 0, 0), (2, 0, 0)))], + "foo", (2, 0, 0), + [("bar", BoundedRange::between((1, 0, 0), (2, 0, 0)))], ); dependency_provider.add_dependencies("foo", (1, 0, 0), []); #[rustfmt::skip] dependency_provider.add_dependencies( - "bar", (1, 0, 0), - [("foo", Range::between((1, 0, 0), (2, 0, 0)))], + "bar", (1, 0, 0), + [("foo", BoundedRange::between((1, 0, 0), (2, 0, 0)))], ); // Run the algorithm. @@ -130,8 +130,8 @@ fn conflict_with_partial_satisfier() { dependency_provider.add_dependencies( "root", (1, 0, 0), [ - ("foo", Range::between((1, 0, 0), (2, 0, 0))), - ("target", Range::between((2, 0, 0), (3, 0, 0))), + ("foo", BoundedRange::between((1, 0, 0), (2, 0, 0))), + ("target", BoundedRange::between((2, 0, 0), (3, 0, 0))), ], ); #[rustfmt::skip] @@ -139,29 +139,29 @@ fn conflict_with_partial_satisfier() { dependency_provider.add_dependencies( "foo", (1, 1, 0), [ - ("left", Range::between((1, 0, 0), (2, 0, 0))), - ("right", Range::between((1, 0, 0), (2, 0, 0))), + ("left", BoundedRange::between((1, 0, 0), (2, 0, 0))), + ("right", BoundedRange::between((1, 0, 0), (2, 0, 0))), ], ); dependency_provider.add_dependencies("foo", (1, 0, 0), []); #[rustfmt::skip] // left 1.0.0 depends on shared >=1.0.0 dependency_provider.add_dependencies( - "left", (1, 0, 0), - [("shared", Range::higher_than((1, 0, 0)))], + "left", (1, 0, 0), + [("shared", BoundedRange::higher_than((1, 0, 0)))], ); #[rustfmt::skip] // right 1.0.0 depends on shared <2.0.0 dependency_provider.add_dependencies( - "right", (1, 0, 0), - [("shared", Range::strictly_lower_than((2, 0, 0)))], + "right", (1, 0, 0), + [("shared", BoundedRange::strictly_lower_than((2, 0, 0)))], ); dependency_provider.add_dependencies("shared", (2, 0, 0), []); #[rustfmt::skip] // shared 1.0.0 depends on target ^1.0.0 dependency_provider.add_dependencies( - "shared", (1, 0, 0), - [("target", Range::between((1, 0, 0), (2, 0, 0)))], + "shared", (1, 0, 0), + [("target", BoundedRange::between((1, 0, 0), (2, 0, 0)))], ); dependency_provider.add_dependencies("target", (2, 0, 0), []); dependency_provider.add_dependencies("target", (1, 0, 0), []); @@ -191,11 +191,15 @@ fn conflict_with_partial_satisfier() { fn double_choices() { init_log(); let mut dependency_provider = OfflineDependencyProvider::<&str, NumVS>::new(); - dependency_provider.add_dependencies("a", 0, [("b", Range::any()), ("c", Range::any())]); - dependency_provider.add_dependencies("b", 0, [("d", Range::exact(0))]); - dependency_provider.add_dependencies("b", 1, [("d", Range::exact(1))]); + dependency_provider.add_dependencies( + "a", + 0, + [("b", BoundedRange::any()), ("c", BoundedRange::any())], + ); + dependency_provider.add_dependencies("b", 0, [("d", BoundedRange::exact(0))]); + dependency_provider.add_dependencies("b", 1, [("d", BoundedRange::exact(1))]); dependency_provider.add_dependencies("c", 0, []); - dependency_provider.add_dependencies("c", 1, [("d", Range::exact(2))]); + dependency_provider.add_dependencies("c", 1, [("d", BoundedRange::exact(2))]); dependency_provider.add_dependencies("d", 0, []); // Solution. diff --git a/tests/proptest.rs b/tests/proptest.rs index fa775720..c94f9dc3 100644 --- a/tests/proptest.rs +++ b/tests/proptest.rs @@ -4,7 +4,6 @@ use std::{collections::BTreeSet as Set, error::Error}; use pubgrub::error::PubGrubError; use pubgrub::package::Package; -use pubgrub::range::Range; use pubgrub::report::{DefaultStringReporter, Reporter}; use pubgrub::solver::{ choose_package_with_fewest_versions, resolve, Dependencies, DependencyProvider, @@ -90,14 +89,16 @@ impl> DependencyProvid } } -type NumVS = Range; -type SemVS = Range; +// type NumVS = pubgrub::discrete_range::DiscreteRange; +// type SemVS = pubgrub::discrete_range::DiscreteRange; +type NumVS = pubgrub::bounded_range::BoundedRange; +type SemVS = pubgrub::bounded_range::BoundedRange; #[test] #[should_panic] fn should_cancel_can_panic() { let mut dependency_provider = OfflineDependencyProvider::<_, NumVS>::new(); - dependency_provider.add_dependencies(0, 0, [(666, Range::any())]); + dependency_provider.add_dependencies(0, 0, [(666, NumVS::any())]); // Run the algorithm. let _ = resolve( @@ -197,15 +198,15 @@ pub fn registry_strategy( deps.push(( dep_name, if c == 0 && d == s_last_index { - Range::any() + NumVS::any() } else if c == 0 { - Range::strictly_lower_than(s[d].0 + 1) + NumVS::strictly_lower_than(s[d].0 + 1) } else if d == s_last_index { - Range::higher_than(s[c].0) + NumVS::higher_than(s[c].0) } else if c == d { - Range::exact(s[c].0) + NumVS::exact(s[c].0) } else { - Range::between(s[c].0, s[d].0 + 1) + NumVS::between(s[c].0, s[d].0 + 1) }, )) } @@ -227,7 +228,7 @@ pub fn registry_strategy( dependency_provider.add_dependencies( name, ver, - deps.unwrap_or_else(|| vec![(bad_name.clone(), Range::any())]), + deps.unwrap_or_else(|| vec![(bad_name.clone(), NumVS::any())]), ); } @@ -488,8 +489,21 @@ fn large_case() { let name = case.file_name().unwrap().to_string_lossy(); eprintln!("{}", name); let data = std::fs::read_to_string(&case).unwrap(); - if name.ends_with("u16_NumberVersion.ron") { - let dependency_provider: OfflineDependencyProvider = + if name.ends_with("u16_discrete_NumberVersion.ron") { + let dependency_provider: OfflineDependencyProvider> = + ron::de::from_str(&data).unwrap(); + let mut sat = SatResolve::new(&dependency_provider); + for p in dependency_provider.packages() { + for n in dependency_provider.versions(p).unwrap() { + if let Ok(s) = resolve(&dependency_provider, p.clone(), n.clone()) { + assert!(sat.sat_is_valid_solution(&s)); + } else { + assert!(!sat.sat_resolve(p, &n)); + } + } + } + } else if name.ends_with("u16_bounded_NumberVersion.ron") { + let dependency_provider: OfflineDependencyProvider> = ron::de::from_str(&data).unwrap(); let mut sat = SatResolve::new(&dependency_provider); for p in dependency_provider.packages() { diff --git a/tests/tests.rs b/tests/tests.rs index 77e4385b..0cd5e975 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -1,11 +1,11 @@ // SPDX-License-Identifier: MPL-2.0 +use pubgrub::bounded_range::BoundedRange; use pubgrub::error::PubGrubError; -use pubgrub::range::Range; use pubgrub::solver::{resolve, OfflineDependencyProvider}; use pubgrub::version::NumberVersion; -type NumVS = Range; +type NumVS = BoundedRange; #[test] fn same_result_on_repeated_runs() { @@ -14,9 +14,13 @@ fn same_result_on_repeated_runs() { dependency_provider.add_dependencies("c", 0, []); dependency_provider.add_dependencies("c", 2, []); dependency_provider.add_dependencies("b", 0, []); - dependency_provider.add_dependencies("b", 1, [("c", Range::between(0, 1))]); + dependency_provider.add_dependencies("b", 1, [("c", BoundedRange::between(0, 1))]); - dependency_provider.add_dependencies("a", 0, [("b", Range::any()), ("c", Range::any())]); + dependency_provider.add_dependencies( + "a", + 0, + [("b", BoundedRange::any()), ("c", BoundedRange::any())], + ); let name = "a"; let ver = NumberVersion(0); @@ -32,13 +36,13 @@ fn same_result_on_repeated_runs() { #[test] fn should_always_find_a_satisfier() { let mut dependency_provider = OfflineDependencyProvider::<_, NumVS>::new(); - dependency_provider.add_dependencies("a", 0, [("b", Range::none())]); + dependency_provider.add_dependencies("a", 0, [("b", BoundedRange::none())]); assert!(matches!( resolve(&dependency_provider, "a", 0), Err(PubGrubError::DependencyOnTheEmptySet { .. }) )); - dependency_provider.add_dependencies("c", 0, [("a", Range::any())]); + dependency_provider.add_dependencies("c", 0, [("a", BoundedRange::any())]); assert!(matches!( resolve(&dependency_provider, "c", 0), Err(PubGrubError::DependencyOnTheEmptySet { .. }) @@ -48,7 +52,7 @@ fn should_always_find_a_satisfier() { #[test] fn cannot_depend_on_self() { let mut dependency_provider = OfflineDependencyProvider::<_, NumVS>::new(); - dependency_provider.add_dependencies("a", 0, [("a", Range::any())]); + dependency_provider.add_dependencies("a", 0, [("a", BoundedRange::any())]); assert!(matches!( resolve(&dependency_provider, "a", 0), Err(PubGrubError::SelfDependency { .. }) From 366dec499f32b4d326d04358f1a4d80b100f0be7 Mon Sep 17 00:00:00 2001 From: Bas Zalmstra Date: Sat, 21 May 2022 23:08:05 +0200 Subject: [PATCH 4/4] chore: fixed and added benchmark for bounded and discrete ranges --- benches/large_case.rs | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/benches/large_case.rs b/benches/large_case.rs index 476228c8..14e8d497 100644 --- a/benches/large_case.rs +++ b/benches/large_case.rs @@ -4,16 +4,21 @@ use std::time::Duration; extern crate criterion; use self::criterion::*; +use pubgrub::bounded_range::BoundedRange; +use pubgrub::discrete_range::DiscreteRange; use pubgrub::package::Package; use pubgrub::solver::{resolve, OfflineDependencyProvider}; use pubgrub::version::{NumberVersion, SemanticVersion, Version}; +use pubgrub::version_set::VersionSet; use serde::de::Deserialize; use std::hash::Hash; -fn bench<'a, P: Package + Deserialize<'a>, V: Version + Hash + Deserialize<'a>>( +fn bench<'a, P: Package + Deserialize<'a>, V: VersionSet + Deserialize<'a>>( b: &mut Bencher, case: &'a str, -) { +) where + ::V: Deserialize<'a>, +{ let dependency_provider: OfflineDependencyProvider = ron::de::from_str(&case).unwrap(); b.iter(|| { @@ -33,13 +38,17 @@ fn bench_nested(c: &mut Criterion) { let case = case.unwrap().path(); let name = case.file_name().unwrap().to_string_lossy(); let data = std::fs::read_to_string(&case).unwrap(); - if name.ends_with("u16_NumberVersion.ron") { + if name.ends_with("u16_discrete_NumberVersion.ron") { group.bench_function(name, |b| { - bench::(b, &data); + bench::>(b, &data); + }); + } else if name.ends_with("u16_bounded_NumberVersion.ron") { + group.bench_function(name, |b| { + bench::>(b, &data); }); } else if name.ends_with("str_SemanticVersion.ron") { group.bench_function(name, |b| { - bench::<&str, SemanticVersion>(b, &data); + bench::<&str, DiscreteRange>(b, &data); }); } }