Skip to content

Commit

Permalink
PartialOrder with Rhs type parameter (#565)
Browse files Browse the repository at this point in the history
* 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 <[email protected]>

* Address feedback

Signed-off-by: Moritz Hoffmann <[email protected]>

---------

Signed-off-by: Moritz Hoffmann <[email protected]>
  • Loading branch information
antiguru authored May 23, 2024
1 parent f3ca4ba commit 5112400
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 16 deletions.
24 changes: 17 additions & 7 deletions timely/src/order.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Rhs: ?Sized = Self>: PartialEq<Rhs> {
/// 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.
Expand Down Expand Up @@ -97,9 +97,14 @@ mod product {
}

use super::PartialOrder;
impl<TOuter: PartialOrder, TInner: PartialOrder> PartialOrder for Product<TOuter, TInner> {
impl<TOuter, TOuter2, TInner, TInner2> PartialOrder<Product<TOuter2, TInner2>> for Product<TOuter, TInner>
where
TOuter: PartialOrder<TOuter2>,
TInner: PartialOrder<TInner2>,
Self: PartialEq<Product<TOuter2, TInner2>>,
{
#[inline]
fn less_equal(&self, other: &Self) -> bool {
fn less_equal(&self, other: &Product<TOuter2, TInner2>) -> bool {
self.outer.less_equal(&other.outer) && self.inner.less_equal(&other.inner)
}
}
Expand Down Expand Up @@ -189,9 +194,14 @@ mod product {
mod tuple {

use super::PartialOrder;
impl<TOuter: PartialOrder, TInner: PartialOrder> PartialOrder for (TOuter, TInner) {
impl<TOuter, TOuter2, TInner, TInner2> PartialOrder<(TOuter2, TInner2)> for (TOuter, TInner)
where
TOuter: PartialOrder<TOuter2>,
TInner: PartialOrder<TInner2>,
(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))
}
Expand Down
44 changes: 35 additions & 9 deletions timely/src/progress/frontier.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,32 @@ impl<T: PartialOrder> Antichain<T> {
}
}

/// 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_with(&2, |x| *x));
/// assert!(!frontier.insert(3));
///```
pub fn insert_with<O: PartialOrder<T>, F: FnOnce(&O) -> T>(&mut self, element: &O, to_owned: F) -> bool where T: PartialOrder<O> {
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);
Expand Down Expand Up @@ -450,9 +476,9 @@ impl<T> MutableAntichain<T> {
/// assert!(frontier.less_than(&2));
///```
#[inline]
pub fn less_than(&self, time: &T) -> bool
pub fn less_than<O>(&self, time: &O) -> bool
where
T: PartialOrder,
T: PartialOrder<O>,
{
self.frontier().less_than(time)
}
Expand All @@ -470,9 +496,9 @@ impl<T> MutableAntichain<T> {
/// assert!(frontier.less_equal(&2));
///```
#[inline]
pub fn less_equal(&self, time: &T) -> bool
pub fn less_equal<O>(&self, time: &O) -> bool
where
T: PartialOrder,
T: PartialOrder<O>,
{
self.frontier().less_equal(time)
}
Expand Down Expand Up @@ -549,9 +575,9 @@ impl<T> MutableAntichain<T> {
}

/// Reports the count for a queried time.
pub fn count_for(&self, query_time: &T) -> i64
pub fn count_for<O>(&self, query_time: &O) -> i64
where
T: Ord,
T: PartialEq<O>,
{
self.updates
.unstable_internal_updates()
Expand Down Expand Up @@ -679,7 +705,7 @@ impl<'a, T: 'a> AntichainRef<'a, T> {
}
}

impl<'a, T: 'a+PartialOrder> AntichainRef<'a, T> {
impl<T> AntichainRef<'_, T> {

/// Returns true if any item in the `AntichainRef` is strictly less than the argument.
///
Expand All @@ -694,7 +720,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<O>(&self, time: &O) -> bool where T: PartialOrder<O> {
self.iter().any(|x| x.less_than(time))
}

Expand All @@ -711,7 +737,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<O>(&self, time: &O) -> bool where T: PartialOrder<O> {
self.iter().any(|x| x.less_equal(time))
}
}
Expand Down

0 comments on commit 5112400

Please sign in to comment.