From 6a8095081527af382efafdcccb6b44f51c06f9af Mon Sep 17 00:00:00 2001 From: Alan Egerton Date: Thu, 19 Jan 2023 17:39:20 +0000 Subject: [PATCH] Move OrdComparator, OrdStoredKey to `default` mod --- README.md | 6 +- src/default.rs | 131 ++++++++++++++++++++ src/lib.rs | 129 +------------------ src/liballoc/collections/binary_heap/mod.rs | 5 +- src/liballoc/collections/btree/map.rs | 8 +- src/liballoc/collections/btree/map/entry.rs | 2 +- src/liballoc/collections/btree/set.rs | 7 +- src/liballoc/testing/crash_test.rs | 2 +- src/liballoc/testing/ord_chaos.rs | 2 +- 9 files changed, 158 insertions(+), 134 deletions(-) create mode 100644 src/default.rs diff --git a/README.md b/README.md index 2c40753..d7229fb 100644 --- a/README.md +++ b/README.md @@ -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`]: 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 diff --git a/src/default.rs b/src/default.rs new file mode 100644 index 0000000..50ff543 --- /dev/null +++ b/src/default.rs @@ -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(PhantomData); + +impl Default for OrdTotalOrder { + fn default() -> Self { + Self(PhantomData) + } +} + +impl Clone for OrdTotalOrder { + fn clone(&self) -> Self { + Self(PhantomData) + } +} + +impl Copy for OrdTotalOrder {} + +impl TotalOrder for OrdTotalOrder { + 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> LookupKey> 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> { + /// 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: ?Sized + Ord} alloc::sync::Arc => 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], + {T: Ord + ?Sized, #[cfg(feature = "allocator_api")] A: alloc::alloc::Allocator} A!(Box) => T, +} diff --git a/src/lib.rs b/src/lib.rs index 4ab59e4..285797d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -93,6 +93,10 @@ //! [`Borrow`]: 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 @@ -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; @@ -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(PhantomData); - -impl Default for OrdTotalOrder { - fn default() -> Self { - Self(PhantomData) - } -} - -impl Clone for OrdTotalOrder { - fn clone(&self) -> Self { - Self(PhantomData) - } -} - -impl Copy for OrdTotalOrder {} - -impl TotalOrder for OrdTotalOrder { - 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`. /// @@ -286,67 +233,3 @@ pub trait LookupKey { /// Return the key by which `self` is ordered under total orders of type `O`. fn key(&self) -> &O::OrderedType; } - -impl> LookupKey> 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> { - /// 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: ?Sized + Ord} alloc::sync::Arc => 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], - {T: Ord + ?Sized, #[cfg(feature = "allocator_api")] A: alloc::alloc::Allocator} A!(Box) => T, -} diff --git a/src/liballoc/collections/binary_heap/mod.rs b/src/liballoc/collections/binary_heap/mod.rs index 824de3d..e2c7705 100644 --- a/src/liballoc/collections/binary_heap/mod.rs +++ b/src/liballoc/collections/binary_heap/mod.rs @@ -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; diff --git a/src/liballoc/collections/btree/map.rs b/src/liballoc/collections/btree/map.rs index 2d9305c..3a700dd 100644 --- a/src/liballoc/collections/btree/map.rs +++ b/src/liballoc/collections/btree/map.rs @@ -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; @@ -652,7 +656,7 @@ impl BTreeMap { /// /// ``` /// # #![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); diff --git a/src/liballoc/collections/btree/map/entry.rs b/src/liballoc/collections/btree/map/entry.rs index 35e1cfa..ce039a1 100644 --- a/src/liballoc/collections/btree/map/entry.rs +++ b/src/liballoc/collections/btree/map/entry.rs @@ -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}; diff --git a/src/liballoc/collections/btree/set.rs b/src/liballoc/collections/btree/set.rs index adbc5ef..75b0c26 100644 --- a/src/liballoc/collections/btree/set.rs +++ b/src/liballoc/collections/btree/set.rs @@ -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}; @@ -382,7 +385,7 @@ impl BTreeSet { /// /// ``` /// # #![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); diff --git a/src/liballoc/testing/crash_test.rs b/src/liballoc/testing/crash_test.rs index acd9f68..67654f2 100644 --- a/src/liballoc/testing/crash_test.rs +++ b/src/liballoc/testing/crash_test.rs @@ -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}; diff --git a/src/liballoc/testing/ord_chaos.rs b/src/liballoc/testing/ord_chaos.rs index 51e9702..efe2675 100644 --- a/src/liballoc/testing/ord_chaos.rs +++ b/src/liballoc/testing/ord_chaos.rs @@ -1,4 +1,4 @@ -use crate::OrdStoredKey; +use crate::default::OrdStoredKey; use std::cell::Cell; use std::cmp::Ordering::{self, *}; use std::ptr;