From 179d6f76647e26169318f4a6a5ff3804e48f3caa Mon Sep 17 00:00:00 2001 From: Moritz Hoffmann Date: Wed, 22 May 2024 15:55:27 -0400 Subject: [PATCH] PartialOrder generic over right-hand side Change the `PartialOrder` trait to have an optional right-hand side type. This allows us to implement partial order for unequal types, which comes in handy when working with complex timestamp times that a container might store as a GAT instead of the actual type. Signed-off-by: Moritz Hoffmann --- timely/src/order.rs | 24 ++++++++++++----- timely/src/progress/frontier.rs | 46 ++++++++++++++++++++++++++------- 2 files changed, 54 insertions(+), 16 deletions(-) diff --git a/timely/src/order.rs b/timely/src/order.rs index 45cdda7d7..cd4796fae 100644 --- a/timely/src/order.rs +++ b/timely/src/order.rs @@ -5,13 +5,13 @@ /// This trait is distinct from Rust's `PartialOrd` trait, because the implementation /// of that trait precludes a distinct `Ord` implementation. We need an independent /// trait if we want to have a partially ordered type that can also be sorted. -pub trait PartialOrder : Eq { +pub trait PartialOrder: PartialEq { /// Returns true iff one element is strictly less than the other. - fn less_than(&self, other: &Self) -> bool { + fn less_than(&self, other: &Rhs) -> bool { self.less_equal(other) && self != other } /// Returns true iff one element is less than or equal to the other. - fn less_equal(&self, other: &Self) -> bool; + fn less_equal(&self, other: &Rhs) -> bool; } /// A type that is totally ordered. @@ -97,9 +97,14 @@ mod product { } use super::PartialOrder; - impl PartialOrder for Product { + impl PartialOrder> for Product + where + TOuter: PartialOrder, + TInner: PartialOrder, + Self: PartialEq>, + { #[inline] - fn less_equal(&self, other: &Self) -> bool { + fn less_equal(&self, other: &Product) -> bool { self.outer.less_equal(&other.outer) && self.inner.less_equal(&other.inner) } } @@ -189,9 +194,14 @@ mod product { mod tuple { use super::PartialOrder; - impl PartialOrder for (TOuter, TInner) { + impl PartialOrder<(TOuter2, TInner2)> for (TOuter, TInner) + where + TOuter: PartialOrder, + TInner: PartialOrder, + (TOuter, TInner): PartialEq<(TOuter2, TInner2)>, + { #[inline] - fn less_equal(&self, other: &Self) -> bool { + fn less_equal(&self, other: &(TOuter2, TInner2)) -> bool { // We avoid Rust's `PartialOrd` implementation, for reasons of correctness. self.0.less_than(&other.0) || (self.0.eq(&other.0) && self.1.less_equal(&other.1)) } diff --git a/timely/src/progress/frontier.rs b/timely/src/progress/frontier.rs index ba44de481..5579b5b43 100644 --- a/timely/src/progress/frontier.rs +++ b/timely/src/progress/frontier.rs @@ -69,6 +69,32 @@ impl Antichain { } } + /// Updates the `Antichain` if the element is not greater than or equal to some present element. + /// If the antichain needs updating, it uses the `to_owned` closure to convert the element into + /// a `T`. + /// + /// Returns true if element is added to the set + /// + /// # Examples + /// + ///``` + /// use timely::progress::frontier::Antichain; + /// + /// let mut frontier = Antichain::new(); + /// assert!(frontier.insert_or_else(&2, |x| *x)); + /// assert!(!frontier.insert(3)); + ///``` + pub fn insert_or_else, F: FnOnce(&O) -> T>(&mut self, element: &O, to_owned: F) -> bool where T: Clone + PartialOrder { + if !self.elements.iter().any(|x| x.less_equal(element)) { + self.elements.retain(|x| !element.less_equal(x)); + self.elements.push(to_owned(element)); + true + } + else { + false + } + } + /// Reserves capacity for at least additional more elements to be inserted in the given `Antichain` pub fn reserve(&mut self, additional: usize) { self.elements.reserve(additional); @@ -450,9 +476,10 @@ impl MutableAntichain { /// assert!(frontier.less_than(&2)); ///``` #[inline] - pub fn less_than(&self, time: &T) -> bool + pub fn less_than(&self, time: &O) -> bool where - T: PartialOrder, + O: PartialOrder, + T: PartialOrder, { self.frontier().less_than(time) } @@ -470,9 +497,10 @@ impl MutableAntichain { /// assert!(frontier.less_equal(&2)); ///``` #[inline] - pub fn less_equal(&self, time: &T) -> bool + pub fn less_equal(&self, time: &O) -> bool where - T: PartialOrder, + O: PartialOrder, + T: PartialOrder, { self.frontier().less_equal(time) } @@ -549,9 +577,9 @@ impl MutableAntichain { } /// Reports the count for a queried time. - pub fn count_for(&self, query_time: &T) -> i64 + pub fn count_for(&self, query_time: &O) -> i64 where - T: Ord, + T: PartialEq, { self.updates .unstable_internal_updates() @@ -679,7 +707,7 @@ impl<'a, T: 'a> AntichainRef<'a, T> { } } -impl<'a, T: 'a+PartialOrder> AntichainRef<'a, T> { +impl AntichainRef<'_, T> { /// Returns true if any item in the `AntichainRef` is strictly less than the argument. /// @@ -694,7 +722,7 @@ impl<'a, T: 'a+PartialOrder> AntichainRef<'a, T> { /// assert!(frontier.less_than(&2)); ///``` #[inline] - pub fn less_than(&self, time: &T) -> bool { + pub fn less_than(&self, time: &O) -> bool where T: PartialOrder { self.iter().any(|x| x.less_than(time)) } @@ -711,7 +739,7 @@ impl<'a, T: 'a+PartialOrder> AntichainRef<'a, T> { /// assert!(frontier.less_equal(&1)); /// assert!(frontier.less_equal(&2)); ///``` - pub fn less_equal(&self, time: &T) -> bool { + pub fn less_equal(&self, time: &O) -> bool where T: PartialOrder { self.iter().any(|x| x.less_equal(time)) } }