mirror of https://github.com/rust-lang/rust.git
Split StableCompare trait out of StableOrd trait.
StableCompare is a companion trait to `StableOrd`. Some types like `Symbol` can be compared in a cross-session stable way, but their `Ord` implementation is not stable. In such cases, a `StableOrd` implementation can be provided to offer a lightweight way for stable sorting. (The more heavyweight option is to sort via `ToStableHashKey`, but then sorting needs to have access to a stable hashing context and `ToStableHashKey` can also be expensive as in the case of `Symbol` where it has to allocate a `String`.)
This commit is contained in:
parent
090d5eac72
commit
739e5ef49e
|
@ -245,6 +245,32 @@ unsafe impl<T: StableOrd> StableOrd for &T {
|
|||
const CAN_USE_UNSTABLE_SORT: bool = T::CAN_USE_UNSTABLE_SORT;
|
||||
}
|
||||
|
||||
/// This is a companion trait to `StableOrd`. Some types like `Symbol` can be
|
||||
/// compared in a cross-session stable way, but their `Ord` implementation is
|
||||
/// not stable. In such cases, a `StableOrd` implementation can be provided
|
||||
/// to offer a lightweight way for stable sorting. (The more heavyweight option
|
||||
/// is to sort via `ToStableHashKey`, but then sorting needs to have access to
|
||||
/// a stable hashing context and `ToStableHashKey` can also be expensive as in
|
||||
/// the case of `Symbol` where it has to allocate a `String`.)
|
||||
///
|
||||
/// See the documentation of [StableOrd] for how stable sort order is defined.
|
||||
/// The same definition applies here. Be careful when implementing this trait.
|
||||
pub trait StableCompare {
|
||||
const CAN_USE_UNSTABLE_SORT: bool;
|
||||
|
||||
fn stable_cmp(&self, other: &Self) -> std::cmp::Ordering;
|
||||
}
|
||||
|
||||
/// `StableOrd` denotes that the type's `Ord` implementation is stable, so
|
||||
/// we can implement `StableCompare` by just delegating to `Ord`.
|
||||
impl<T: StableOrd> StableCompare for T {
|
||||
const CAN_USE_UNSTABLE_SORT: bool = T::CAN_USE_UNSTABLE_SORT;
|
||||
|
||||
fn stable_cmp(&self, other: &Self) -> std::cmp::Ordering {
|
||||
self.cmp(other)
|
||||
}
|
||||
}
|
||||
|
||||
/// Implement HashStable by just calling `Hash::hash()`. Also implement `StableOrd` for the type since
|
||||
/// that has the same requirements.
|
||||
///
|
||||
|
|
|
@ -14,7 +14,7 @@ use std::{
|
|||
|
||||
use crate::{
|
||||
fingerprint::Fingerprint,
|
||||
stable_hasher::{HashStable, StableHasher, StableOrd, ToStableHashKey},
|
||||
stable_hasher::{HashStable, StableCompare, StableHasher, ToStableHashKey},
|
||||
};
|
||||
|
||||
/// `UnordItems` is the order-less version of `Iterator`. It only contains methods
|
||||
|
@ -134,7 +134,7 @@ impl<'a, T: Copy + 'a, I: Iterator<Item = &'a T>> UnordItems<&'a T, I> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: Ord, I: Iterator<Item = T>> UnordItems<T, I> {
|
||||
impl<T, I: Iterator<Item = T>> UnordItems<T, I> {
|
||||
pub fn into_sorted<HCX>(self, hcx: &HCX) -> Vec<T>
|
||||
where
|
||||
T: ToStableHashKey<HCX>,
|
||||
|
@ -147,13 +147,36 @@ impl<T: Ord, I: Iterator<Item = T>> UnordItems<T, I> {
|
|||
#[inline]
|
||||
pub fn into_sorted_stable_ord(self) -> Vec<T>
|
||||
where
|
||||
T: Ord + StableOrd,
|
||||
T: StableCompare,
|
||||
{
|
||||
let mut items: Vec<T> = self.0.collect();
|
||||
if !T::CAN_USE_UNSTABLE_SORT {
|
||||
items.sort();
|
||||
items.sort_by(T::stable_cmp);
|
||||
} else {
|
||||
items.sort_unstable()
|
||||
items.sort_unstable_by(T::stable_cmp)
|
||||
}
|
||||
items
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn into_sorted_stable_ord_by_key<K, C>(self, project_to_key: C) -> Vec<T>
|
||||
where
|
||||
K: StableCompare,
|
||||
C: for<'a> Fn(&'a T) -> &'a K,
|
||||
{
|
||||
let mut items: Vec<T> = self.0.collect();
|
||||
if !K::CAN_USE_UNSTABLE_SORT {
|
||||
items.sort_by(|a, b| {
|
||||
let a_key = project_to_key(a);
|
||||
let b_key = project_to_key(b);
|
||||
a_key.stable_cmp(b_key)
|
||||
});
|
||||
} else {
|
||||
items.sort_unstable_by(|a, b| {
|
||||
let a_key = project_to_key(a);
|
||||
let b_key = project_to_key(b);
|
||||
a_key.stable_cmp(b_key)
|
||||
});
|
||||
}
|
||||
items
|
||||
}
|
||||
|
@ -268,16 +291,30 @@ impl<V: Eq + Hash> UnordSet<V> {
|
|||
}
|
||||
|
||||
/// Returns the items of this set in stable sort order (as defined by
|
||||
/// `StableOrd`). This method is much more efficient than
|
||||
/// `StableCompare`). This method is much more efficient than
|
||||
/// `into_sorted` because it does not need to transform keys to their
|
||||
/// `ToStableHashKey` equivalent.
|
||||
#[inline]
|
||||
pub fn to_sorted_stable_ord(&self) -> Vec<V>
|
||||
pub fn to_sorted_stable_ord(&self) -> Vec<&V>
|
||||
where
|
||||
V: Ord + StableOrd + Clone,
|
||||
V: StableCompare,
|
||||
{
|
||||
let mut items: Vec<V> = self.inner.iter().cloned().collect();
|
||||
items.sort_unstable();
|
||||
let mut items: Vec<&V> = self.inner.iter().collect();
|
||||
items.sort_unstable_by(|a, b| a.stable_cmp(*b));
|
||||
items
|
||||
}
|
||||
|
||||
/// Returns the items of this set in stable sort order (as defined by
|
||||
/// `StableCompare`). This method is much more efficient than
|
||||
/// `into_sorted` because it does not need to transform keys to their
|
||||
/// `ToStableHashKey` equivalent.
|
||||
#[inline]
|
||||
pub fn into_sorted_stable_ord(self) -> Vec<V>
|
||||
where
|
||||
V: StableCompare,
|
||||
{
|
||||
let mut items: Vec<V> = self.inner.into_iter().collect();
|
||||
items.sort_unstable_by(V::stable_cmp);
|
||||
items
|
||||
}
|
||||
|
||||
|
@ -483,16 +520,16 @@ impl<K: Eq + Hash, V> UnordMap<K, V> {
|
|||
to_sorted_vec(hcx, self.inner.iter(), cache_sort_key, |&(k, _)| k)
|
||||
}
|
||||
|
||||
/// Returns the entries of this map in stable sort order (as defined by `StableOrd`).
|
||||
/// Returns the entries of this map in stable sort order (as defined by `StableCompare`).
|
||||
/// This method can be much more efficient than `into_sorted` because it does not need
|
||||
/// to transform keys to their `ToStableHashKey` equivalent.
|
||||
#[inline]
|
||||
pub fn to_sorted_stable_ord(&self) -> Vec<(K, &V)>
|
||||
pub fn to_sorted_stable_ord(&self) -> Vec<(&K, &V)>
|
||||
where
|
||||
K: Ord + StableOrd + Copy,
|
||||
K: StableCompare,
|
||||
{
|
||||
let mut items: Vec<(K, &V)> = self.inner.iter().map(|(&k, v)| (k, v)).collect();
|
||||
items.sort_unstable_by_key(|&(k, _)| k);
|
||||
let mut items: Vec<_> = self.inner.iter().collect();
|
||||
items.sort_unstable_by(|(a, _), (b, _)| a.stable_cmp(*b));
|
||||
items
|
||||
}
|
||||
|
||||
|
@ -510,6 +547,19 @@ impl<K: Eq + Hash, V> UnordMap<K, V> {
|
|||
to_sorted_vec(hcx, self.inner.into_iter(), cache_sort_key, |(k, _)| k)
|
||||
}
|
||||
|
||||
/// Returns the entries of this map in stable sort order (as defined by `StableCompare`).
|
||||
/// This method can be much more efficient than `into_sorted` because it does not need
|
||||
/// to transform keys to their `ToStableHashKey` equivalent.
|
||||
#[inline]
|
||||
pub fn into_sorted_stable_ord(self) -> Vec<(K, V)>
|
||||
where
|
||||
K: StableCompare,
|
||||
{
|
||||
let mut items: Vec<(K, V)> = self.inner.into_iter().collect();
|
||||
items.sort_unstable_by(|a, b| a.0.stable_cmp(&b.0));
|
||||
items
|
||||
}
|
||||
|
||||
/// Returns the values of this map in stable sort order (as defined by K's
|
||||
/// `ToStableHashKey` implementation).
|
||||
///
|
||||
|
|
|
@ -913,7 +913,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
for ((span, add_where_or_comma), obligations) in type_params.into_iter() {
|
||||
restrict_type_params = true;
|
||||
// #74886: Sort here so that the output is always the same.
|
||||
let obligations = obligations.to_sorted_stable_ord();
|
||||
let obligations = obligations.into_sorted_stable_ord();
|
||||
err.span_suggestion_verbose(
|
||||
span,
|
||||
format!(
|
||||
|
|
|
@ -912,7 +912,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
drop_order: bool,
|
||||
) -> MigrationWarningReason {
|
||||
MigrationWarningReason {
|
||||
auto_traits: auto_trait_reasons.to_sorted_stable_ord(),
|
||||
auto_traits: auto_trait_reasons.into_sorted_stable_ord(),
|
||||
drop_order,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -473,7 +473,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
|
|||
assert_eq!(fcx_typeck_results.hir_owner, self.typeck_results.hir_owner);
|
||||
|
||||
let fcx_coercion_casts = fcx_typeck_results.coercion_casts().to_sorted_stable_ord();
|
||||
for local_id in fcx_coercion_casts {
|
||||
for &local_id in fcx_coercion_casts {
|
||||
self.typeck_results.set_coercion_cast(local_id);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -103,7 +103,7 @@ pub fn save_work_product_index(
|
|||
// deleted during invalidation. Some object files don't change their
|
||||
// content, they are just not needed anymore.
|
||||
let previous_work_products = dep_graph.previous_work_products();
|
||||
for (id, wp) in previous_work_products.to_sorted_stable_ord().iter() {
|
||||
for (id, wp) in previous_work_products.to_sorted_stable_ord() {
|
||||
if !new_work_products.contains_key(id) {
|
||||
work_product::delete_workproduct_files(sess, wp);
|
||||
debug_assert!(
|
||||
|
|
|
@ -9,7 +9,9 @@ pub use self::Level::*;
|
|||
use rustc_ast::node_id::NodeId;
|
||||
use rustc_ast::{AttrId, Attribute};
|
||||
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
|
||||
use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey};
|
||||
use rustc_data_structures::stable_hasher::{
|
||||
HashStable, StableCompare, StableHasher, ToStableHashKey,
|
||||
};
|
||||
use rustc_error_messages::{DiagnosticMessage, MultiSpan};
|
||||
use rustc_hir::HashStableContext;
|
||||
use rustc_hir::HirId;
|
||||
|
@ -541,6 +543,14 @@ impl<HCX> ToStableHashKey<HCX> for LintId {
|
|||
}
|
||||
}
|
||||
|
||||
impl StableCompare for LintId {
|
||||
const CAN_USE_UNSTABLE_SORT: bool = true;
|
||||
|
||||
fn stable_cmp(&self, other: &Self) -> std::cmp::Ordering {
|
||||
self.lint_name_raw().cmp(&other.lint_name_raw())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct AmbiguityErrorDiag {
|
||||
pub msg: String,
|
||||
|
|
|
@ -527,7 +527,7 @@ impl<'a, V> LocalTableInContext<'a, V> {
|
|||
}
|
||||
|
||||
pub fn items_in_stable_order(&self) -> Vec<(ItemLocalId, &'a V)> {
|
||||
self.data.to_sorted_stable_ord()
|
||||
self.data.items().map(|(&k, v)| (k, v)).into_sorted_stable_ord_by_key(|(k, _)| k)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4,7 +4,9 @@
|
|||
|
||||
use rustc_arena::DroplessArena;
|
||||
use rustc_data_structures::fx::FxIndexSet;
|
||||
use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey};
|
||||
use rustc_data_structures::stable_hasher::{
|
||||
HashStable, StableCompare, StableHasher, ToStableHashKey,
|
||||
};
|
||||
use rustc_data_structures::sync::Lock;
|
||||
use rustc_macros::HashStable_Generic;
|
||||
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
|
||||
|
@ -2103,6 +2105,14 @@ impl<CTX> ToStableHashKey<CTX> for Symbol {
|
|||
}
|
||||
}
|
||||
|
||||
impl StableCompare for Symbol {
|
||||
const CAN_USE_UNSTABLE_SORT: bool = true;
|
||||
|
||||
fn stable_cmp(&self, other: &Self) -> std::cmp::Ordering {
|
||||
self.as_str().cmp(other.as_str())
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct Interner(Lock<InternerInner>);
|
||||
|
||||
// The `&'static str`s in this type actually point into the arena.
|
||||
|
|
Loading…
Reference in New Issue