diff --git a/library/alloc/src/collections/btree/cmp.rs b/library/alloc/src/collections/btree/cmp.rs new file mode 100644 index 0000000000000..69ea71cf8b926 --- /dev/null +++ b/library/alloc/src/collections/btree/cmp.rs @@ -0,0 +1,52 @@ +//! Complements to the [`core::cmp`] module + +use core::borrow::Borrow; +use core::cmp::Ordering; + +/// Key equivalence trait. +/// +/// This trait allows hash table lookup to be customized. It has one blanket +/// implementation that uses the regular solution with `Borrow` and `Eq`, just +/// like `HashMap` does, so that you can pass `&str` to lookup into a map with +/// `String` keys and so on. +/// +/// # Contract +/// +/// The implementor **must** hash like `Q`, if it is hashable. +pub(crate) trait Equivalent { + // /// Compare self to `key` and return `true` if they are equal. + // fn equivalent(&self, key: &Q) -> bool; +} + +impl Equivalent for K +where + K: Borrow, + Q: Eq, +{ + // #[inline] + // fn equivalent(&self, key: &Q) -> bool { + // PartialEq::eq(self.borrow(), key) + // } +} + +/// Key ordering trait. +/// +/// This trait allows ordered map lookup to be customized. It has one blanket +/// implementation that uses the regular solution with `Borrow` and `Ord`, just +/// like `BTreeMap` does, so that you can pass `&str` to lookup into a map with +/// `String` keys and so on. +pub(crate) trait Comparable: Equivalent { + /// Compare self to `key` and return their ordering. + fn compare(&self, key: &Q) -> Ordering; +} + +impl Comparable for K +where + K: Borrow, + Q: Ord, +{ + #[inline] + fn compare(&self, key: &Q) -> Ordering { + Ord::cmp(self.borrow(), key) + } +} diff --git a/library/alloc/src/collections/btree/mod.rs b/library/alloc/src/collections/btree/mod.rs index 6651480667391..0bd9efcbe889d 100644 --- a/library/alloc/src/collections/btree/mod.rs +++ b/library/alloc/src/collections/btree/mod.rs @@ -1,5 +1,6 @@ mod append; mod borrow; +mod cmp; mod dedup_sorted_iter; mod fix; pub(super) mod map; diff --git a/library/alloc/src/collections/btree/navigate.rs b/library/alloc/src/collections/btree/navigate.rs index b2a7de74875d9..ec276c136e05e 100644 --- a/library/alloc/src/collections/btree/navigate.rs +++ b/library/alloc/src/collections/btree/navigate.rs @@ -1,7 +1,7 @@ -use core::borrow::Borrow; use core::ops::RangeBounds; use core::{hint, ptr}; +use super::cmp::Comparable; use super::node::ForceResult::*; use super::node::{Handle, NodeRef, marker}; use super::search::SearchBound; @@ -267,7 +267,7 @@ impl NodeRef LeafRange where Q: Ord, - K: Borrow, + K: Comparable, R: RangeBounds, { match self.search_tree_for_bifurcation(&range) { @@ -316,7 +316,7 @@ impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::LeafOrInternal> pub(super) fn range_search(self, range: R) -> LeafRange, K, V> where Q: ?Sized + Ord, - K: Borrow, + K: Comparable, R: RangeBounds, { // SAFETY: our borrow type is immutable. @@ -342,7 +342,7 @@ impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::LeafOrInternal> pub(super) fn range_search(self, range: R) -> LeafRange, K, V> where Q: ?Sized + Ord, - K: Borrow, + K: Comparable, R: RangeBounds, { unsafe { self.find_leaf_edges_spanning_range(range) } @@ -746,8 +746,7 @@ impl NodeRef, ) -> Handle, marker::Edge> where - Q: Ord, - K: Borrow, + K: Comparable, { let mut node = self; loop { @@ -769,8 +768,7 @@ impl NodeRef, ) -> Handle, marker::Edge> where - Q: Ord, - K: Borrow, + K: Comparable, { let mut node = self; loop { diff --git a/library/alloc/src/collections/btree/search.rs b/library/alloc/src/collections/btree/search.rs index 96e5bf108024b..5d9cb5ffb9c11 100644 --- a/library/alloc/src/collections/btree/search.rs +++ b/library/alloc/src/collections/btree/search.rs @@ -1,10 +1,10 @@ -use core::borrow::Borrow; use core::cmp::Ordering; use core::ops::{Bound, RangeBounds}; use SearchBound::*; use SearchResult::*; +use super::cmp::Comparable; use super::node::ForceResult::*; use super::node::{Handle, NodeRef, marker}; @@ -51,8 +51,7 @@ impl NodeRef SearchResult where - Q: Ord, - K: Borrow, + K: Comparable, { loop { self = match self.search_node(key) { @@ -95,7 +94,7 @@ impl NodeRef where Q: Ord, - K: Borrow, + K: Comparable, R: RangeBounds, { // Determine if map or set is being searched @@ -161,8 +160,8 @@ impl NodeRef, ) -> (Handle, SearchBound<&'r Q>) where - Q: ?Sized + Ord, - K: Borrow, + Q: ?Sized, + K: Comparable, { let (edge_idx, bound) = self.find_lower_bound_index(bound); let edge = unsafe { Handle::new_edge(self, edge_idx) }; @@ -175,8 +174,8 @@ impl NodeRef, ) -> (Handle, SearchBound<&'r Q>) where - Q: ?Sized + Ord, - K: Borrow, + Q: ?Sized, + K: Comparable, { let (edge_idx, bound) = unsafe { self.find_upper_bound_index(bound, 0) }; let edge = unsafe { Handle::new_edge(self, edge_idx) }; @@ -197,8 +196,7 @@ impl NodeRef { key: &Q, ) -> SearchResult where - Q: Ord, - K: Borrow, + K: Comparable, { match unsafe { self.find_key_index(key, 0) } { IndexResult::KV(idx) => Found(unsafe { Handle::new_kv(self, idx) }), @@ -216,17 +214,16 @@ impl NodeRef { /// `start_index` must be a valid edge index for the node. unsafe fn find_key_index(&self, key: &Q, start_index: usize) -> IndexResult where - Q: Ord, - K: Borrow, + K: Comparable, { let node = self.reborrow(); let keys = node.keys(); debug_assert!(start_index <= keys.len()); for (offset, k) in unsafe { keys.get_unchecked(start_index..) }.iter().enumerate() { - match key.cmp(k.borrow()) { - Ordering::Greater => {} + match k.compare(key) { + Ordering::Less => {} Ordering::Equal => return IndexResult::KV(start_index + offset), - Ordering::Less => return IndexResult::Edge(start_index + offset), + Ordering::Greater => return IndexResult::Edge(start_index + offset), } } IndexResult::Edge(keys.len()) @@ -242,8 +239,8 @@ impl NodeRef { bound: SearchBound<&'r Q>, ) -> (usize, SearchBound<&'r Q>) where - Q: ?Sized + Ord, - K: Borrow, + Q: ?Sized, + K: Comparable, { match bound { Included(key) => match unsafe { self.find_key_index(key, 0) } { @@ -270,8 +267,8 @@ impl NodeRef { start_index: usize, ) -> (usize, SearchBound<&'r Q>) where - Q: ?Sized + Ord, - K: Borrow, + Q: ?Sized, + K: Comparable, { match bound { Included(key) => match unsafe { self.find_key_index(key, start_index) } {