Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move OrdComparator, OrdStoredKey to default mod #14

Merged
merged 1 commit into from
Jan 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,6 @@ This crate defines a number of feature flags, none of which are enabled by defau
[`TotalOrder`]: https://docs.rs/copse/latest/copse/trait.TotalOrder.html
[TotalOrder::OrderedType]: https://docs.rs/copse/latest/copse/trait.TotalOrder.html#associatedtype.OrderedType
[`LookupKey<O>`]: https://docs.rs/copse/latest/copse/trait.LookupKey.html
[`OrdTotalOrder`]: https://docs.rs/copse/latest/copse/struct.OrdTotalOrder.html
[`OrdStoredKey`]: https://docs.rs/copse/latest/copse/trait.OrdStoredKey.html
[OrdStoredKey::DefaultComparisonKey]: https://docs.rs/copse/latest/copse/trait.OrdStoredKey.html#associatedtype.DefaultComparisonKey
[`OrdTotalOrder`]: https://docs.rs/copse/latest/copse/default/struct.OrdTotalOrder.html
[`OrdStoredKey`]: https://docs.rs/copse/latest/copse/default/trait.OrdStoredKey.html
[OrdStoredKey::DefaultComparisonKey]: https://docs.rs/copse/latest/copse/default/trait.OrdStoredKey.html#associatedtype.DefaultComparisonKey
131 changes: 131 additions & 0 deletions src/default.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
//! Defaults that enable copse's collections to behave as per those of the standard
//! library, namely using the [`Ord`] trait for comparisons rather than any user-
//! supplied [`Comparator`].
//!
//! Use of these defaults negates the purpose of the copse crate, and indicates that
//! you should probably be using the standard library's collections instead.

use crate::{LookupKey, TotalOrder};
use alloc::{boxed::Box, vec::Vec};
use core::{borrow::Borrow, cmp::Ordering, marker::PhantomData};

/// A zero-sized total order that delegates to the [`Ord`] implementation
/// of its type parameter `T`.
pub struct OrdTotalOrder<T: ?Sized + Ord>(PhantomData<fn(&T)>);

impl<T: ?Sized + Ord> Default for OrdTotalOrder<T> {
fn default() -> Self {
Self(PhantomData)
}
}

impl<T: ?Sized + Ord> Clone for OrdTotalOrder<T> {
fn clone(&self) -> Self {
Self(PhantomData)
}
}

impl<T: ?Sized + Ord> Copy for OrdTotalOrder<T> {}

impl<T: ?Sized + Ord> TotalOrder for OrdTotalOrder<T> {
type OrderedType = T;

// Delegate to `T`'s implementation of [`Ord`].
fn cmp(&self, this: &T, that: &T) -> Ordering {
this.cmp(that)
}

// The default implementations of the following methods are overidden so that
// they delegate to `T`'s implementations of [`PartialEq`] and [`PartialOrd`]
// rather than merely using its implementation of [`Ord`].
//
// If, as required by those traits, `T`'s implementations are consistent with
// one another, then these overrides will have no effect. They are provided
// for (erroneous) cases where the implementations are inconsistent (such as
// in `liballoc::collections::binary_heap::tests::panic_safe`), thus enabling
// copse to imitate liballoc with greater fidelity.

fn eq(&self, this: &T, that: &T) -> bool {
this == that
}
fn ne(&self, this: &T, that: &T) -> bool {
this != that
}

fn ge(&self, this: &T, that: &T) -> bool {
this >= that
}
fn gt(&self, this: &T, that: &T) -> bool {
this > that
}
fn le(&self, this: &T, that: &T) -> bool {
this <= that
}
fn lt(&self, this: &T, that: &T) -> bool {
this < that
}
}

impl<T: ?Sized + Ord, K: ?Sized + Borrow<T>> LookupKey<OrdTotalOrder<T>> for K {
fn key(&self) -> &T {
self.borrow()
}
}

/// A helper trait implemented on potential storage key types, used to identify their default
/// comparison type for [`Ord`]-based comparisons.
///
/// This is only really used when collections are left to select the default [`OrdTotalOrder`]
/// total order, which essentially converts copse's collections into those already provided by
/// the standard library. This trait is therefore a convenience, but of relatively little value.
///
/// For example, a collection that stores [`String`] under the default total order will use
/// [`str`] as the comparison type owing to the implementation of this trait for [`String`].
pub trait OrdStoredKey: LookupKey<OrdTotalOrder<Self::DefaultComparisonKey>> {
/// The comparison type to be used by collections storing keys of `Self` type and using the
/// default [`OrdTotalOrder`] total order.
type DefaultComparisonKey: ?Sized + Ord;
}

macro_rules! ord_keys {
// end of recursion
() => {};

// implement type and recurse
($(#[$attrs:meta])* $({$($g:tt)+})? $t:ty => $m:ty $(, $($rest:tt)*)?) => {
$(#[$attrs])*
impl$(<$($g)+>)? OrdStoredKey for $t {
type DefaultComparisonKey = $m;
}

$(ord_keys!($($rest)*);)?
};

// delegate to a reflexive implementation if no State is specified
($(#[$attrs:meta])* $({$($g:tt)+})? $t:ty $(, $($rest:tt)*)?) => {
ord_keys!($(#[$attrs])* $({$($g)+})? $t => Self $(, $($rest)*)?);
};
}

ord_keys! {
(),
bool, char,
i8, u8,
i16, u16,
i32, u32,
i64, u64,
i128, u128,
isize, usize,
alloc::string::String => str, str,
alloc::ffi::CString => core::ffi::CStr, core::ffi::CStr,
{B: ?Sized + Ord + Clone} alloc::borrow::Cow<'_, B> => B,
{T: ?Sized + Ord} &T => T,
{T: ?Sized + Ord} &mut T => T,
{T: ?Sized + Ord} alloc::rc::Rc<T> => T,
{T: ?Sized + Ord} alloc::sync::Arc<T> => T,
{T: Ord, const N: usize} [T; N] => [T], {T: Ord} [T],
#[cfg(feature = "std")] std::ffi::OsString => std::ffi::OsStr, #[cfg(feature = "std")] std::ffi::OsStr,
#[cfg(feature = "std")] std::path::PathBuf => std::path::Path, #[cfg(feature = "std")] std::path::Path,
{T: Ord, #[cfg(feature = "allocator_api")] A: alloc::alloc::Allocator} A!(Vec<T, A>) => [T],
{T: Ord + ?Sized, #[cfg(feature = "allocator_api")] A: alloc::alloc::Allocator} A!(Box<T, A>) => T,
}
129 changes: 6 additions & 123 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,10 @@
//! [`Borrow<Q>`]: std::borrow::Borrow
//! [`Ord`]: std::cmp::Ord
//! [`Ord::cmp`]: std::cmp::Ord::cmp
//! [`OrdComparator`]: default::OrdComparator
//! [`OrdStoredKey`]: default::OrdStoredKey
//! [OrdStoredKey::DefaultComparisonKey]: default::OrdStoredKey::DefaultComparisonKey
//! [`OrdTotalOrder`]: default::OrdTotalOrder
//! [`OsString`]: std::ffi::OsString
//! [`PathBuf`]: std::path::PathBuf

Expand Down Expand Up @@ -123,11 +127,11 @@
#[macro_use]
extern crate alloc;

use alloc::{boxed::Box, vec::Vec};
use core::{borrow::Borrow, cmp::Ordering, marker::PhantomData};
use core::cmp::Ordering;

#[macro_use]
mod polyfill;
pub mod default;

// port of stdlib implementation
mod liballoc;
Expand Down Expand Up @@ -217,63 +221,6 @@ pub trait TotalOrder {
}
}

/// A zero-sized total order that delegates to the [`Ord`] implementation
/// of its type parameter `T`.
pub struct OrdTotalOrder<T: ?Sized + Ord>(PhantomData<fn(&T)>);

impl<T: ?Sized + Ord> Default for OrdTotalOrder<T> {
fn default() -> Self {
Self(PhantomData)
}
}

impl<T: ?Sized + Ord> Clone for OrdTotalOrder<T> {
fn clone(&self) -> Self {
Self(PhantomData)
}
}

impl<T: ?Sized + Ord> Copy for OrdTotalOrder<T> {}

impl<T: ?Sized + Ord> TotalOrder for OrdTotalOrder<T> {
type OrderedType = T;

// Delegate to `T`'s implementation of [`Ord`].
fn cmp(&self, this: &T, that: &T) -> Ordering {
this.cmp(that)
}

// The default implementations of the following methods are overidden so that
// they delegate to `T`'s implementations of [`PartialEq`] and [`PartialOrd`]
// rather than merely using its implementation of [`Ord`].
//
// If, as required by those traits, `T`'s implementations are consistent with
// one another, then these overrides will have no effect. They are provided
// for (erroneous) cases where the implementations are inconsistent (such as
// in `liballoc::collections::binary_heap::tests::panic_safe`), thus enabling
// copse to imitate liballoc with greater fidelity.

fn eq(&self, this: &T, that: &T) -> bool {
this == that
}
fn ne(&self, this: &T, that: &T) -> bool {
this != that
}

fn ge(&self, this: &T, that: &T) -> bool {
this >= that
}
fn gt(&self, this: &T, that: &T) -> bool {
this > that
}
fn le(&self, this: &T, that: &T) -> bool {
this <= that
}
fn lt(&self, this: &T, that: &T) -> bool {
this < that
}
}

/// A type that can be used as a lookup key in collections that are sorted by total orders
/// of type parameter `O`.
///
Expand All @@ -286,67 +233,3 @@ pub trait LookupKey<O: TotalOrder> {
/// Return the key by which `self` is ordered under total orders of type `O`.
fn key(&self) -> &O::OrderedType;
}

impl<T: ?Sized + Ord, K: ?Sized + Borrow<T>> LookupKey<OrdTotalOrder<T>> for K {
fn key(&self) -> &T {
self.borrow()
}
}

/// A helper trait implemented on potential storage key types, used to identify their default
/// comparison type for [`Ord`]-based comparisons.
///
/// This is only really used when collections are left to select the default [`OrdTotalOrder`]
/// total order, which essentially converts copse's collections into those already provided by
/// the standard library. This trait is therefore a convenience, but of relatively little value.
///
/// For example, a collection that stores [`String`] under the default total order will use
/// [`str`] as the comparison type owing to the implementation of this trait for [`String`].
pub trait OrdStoredKey: LookupKey<OrdTotalOrder<Self::DefaultComparisonKey>> {
/// The comparison type to be used by collections storing keys of `Self` type and using the
/// default [`OrdTotalOrder`] total order.
type DefaultComparisonKey: ?Sized + Ord;
}

macro_rules! ord_keys {
// end of recursion
() => {};

// implement type and recurse
($(#[$attrs:meta])* $({$($g:tt)+})? $t:ty => $m:ty $(, $($rest:tt)*)?) => {
$(#[$attrs])*
impl$(<$($g)+>)? OrdStoredKey for $t {
type DefaultComparisonKey = $m;
}

$(ord_keys!($($rest)*);)?
};

// delegate to a reflexive implementation if no State is specified
($(#[$attrs:meta])* $({$($g:tt)+})? $t:ty $(, $($rest:tt)*)?) => {
ord_keys!($(#[$attrs])* $({$($g)+})? $t => Self $(, $($rest)*)?);
};
}

ord_keys! {
(),
bool, char,
i8, u8,
i16, u16,
i32, u32,
i64, u64,
i128, u128,
isize, usize,
alloc::string::String => str, str,
alloc::ffi::CString => core::ffi::CStr, core::ffi::CStr,
{B: ?Sized + Ord + Clone} alloc::borrow::Cow<'_, B> => B,
{T: ?Sized + Ord} &T => T,
{T: ?Sized + Ord} &mut T => T,
{T: ?Sized + Ord} alloc::rc::Rc<T> => T,
{T: ?Sized + Ord} alloc::sync::Arc<T> => T,
{T: Ord, const N: usize} [T; N] => [T], {T: Ord} [T],
#[cfg(feature = "std")] std::ffi::OsString => std::ffi::OsStr, #[cfg(feature = "std")] std::ffi::OsStr,
#[cfg(feature = "std")] std::path::PathBuf => std::path::Path, #[cfg(feature = "std")] std::path::Path,
{T: Ord, #[cfg(feature = "allocator_api")] A: alloc::alloc::Allocator} A!(Vec<T, A>) => [T],
{T: Ord + ?Sized, #[cfg(feature = "allocator_api")] A: alloc::alloc::Allocator} A!(Box<T, A>) => T,
}
5 changes: 4 additions & 1 deletion src/liballoc/collections/binary_heap/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,10 @@ use alloc::vec::{self, Vec};
use cfg_if::cfg_if;

use super::SpecExtend;
use crate::{LookupKey, OrdStoredKey, OrdTotalOrder, TotalOrder};
use crate::{
default::{OrdStoredKey, OrdTotalOrder},
LookupKey, TotalOrder,
};

#[cfg(test)]
mod tests;
Expand Down
8 changes: 6 additions & 2 deletions src/liballoc/collections/btree/map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,11 @@ use core::mem::{self, ManuallyDrop};
use core::ops::{Index, RangeBounds};
use core::ptr;

use crate::{polyfill::*, LookupKey, OrdStoredKey, OrdTotalOrder, TotalOrder};
use crate::{
default::{OrdStoredKey, OrdTotalOrder},
polyfill::*,
LookupKey, TotalOrder,
};

use super::borrow::DormantMutRef;
use super::dedup_sorted_iter::DedupSortedIter;
Expand Down Expand Up @@ -652,7 +656,7 @@ impl<K, V, O, A: Allocator + Clone> BTreeMap<K, V, O, A> {
///
/// ```
/// # #![feature(allocator_api)]
/// use copse::{BTreeMap, OrdTotalOrder};
/// use copse::{BTreeMap, default::OrdTotalOrder};
/// use std::alloc::Global;
///
/// let mut map = BTreeMap::new_in(OrdTotalOrder::default(), Global);
Expand Down
2 changes: 1 addition & 1 deletion src/liballoc/collections/btree/map/entry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use core::fmt::{self, Debug};
use core::marker::PhantomData;
use core::mem;

use crate::{polyfill::*, OrdStoredKey, OrdTotalOrder};
use crate::{polyfill::*, default::{OrdStoredKey, OrdTotalOrder}};

use super::super::borrow::DormantMutRef;
use super::super::node::{marker, Handle, NodeRef};
Expand Down
7 changes: 5 additions & 2 deletions src/liballoc/collections/btree/set.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
// This is pretty much entirely stolen from TreeSet, since BTreeMap has an identical interface
// to TreeMap

use crate::{LookupKey, OrdStoredKey, OrdTotalOrder, TotalOrder};
use crate::{
default::{OrdStoredKey, OrdTotalOrder},
LookupKey, TotalOrder,
};
use alloc::vec::Vec;
use core::cmp::Ordering::{self, Equal, Greater, Less};
use core::cmp::{max, min};
Expand Down Expand Up @@ -382,7 +385,7 @@ impl<T, O, A: Allocator + Clone> BTreeSet<T, O, A> {
///
/// ```
/// # #![feature(allocator_api)]
/// use copse::{BTreeSet, OrdTotalOrder};
/// use copse::{BTreeSet, default::OrdTotalOrder};
/// use std::alloc::Global;
///
/// let mut set = BTreeSet::<_>::new_in(OrdTotalOrder::default(), Global);
Expand Down
2 changes: 1 addition & 1 deletion src/liballoc/testing/crash_test.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// We avoid relying on anything else in the crate, apart from the `Debug` and `OrdStoredKey` traits.
use crate::OrdStoredKey;
use crate::default::OrdStoredKey;
use alloc::fmt::Debug;
use std::cmp::Ordering;
use std::sync::atomic::{AtomicUsize, Ordering::SeqCst};
Expand Down
2 changes: 1 addition & 1 deletion src/liballoc/testing/ord_chaos.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::OrdStoredKey;
use crate::default::OrdStoredKey;
use std::cell::Cell;
use std::cmp::Ordering::{self, *};
use std::ptr;
Expand Down