Skip to content

Commit b3d4257

Browse files
committed
constify comparison traits on slices
This currently involves manually inlining chaining_impl() to avoid a dependency on const closures.
1 parent acbcbdc commit b3d4257

File tree

1 file changed

+146
-67
lines changed

1 file changed

+146
-67
lines changed

library/core/src/slice/cmp.rs

Lines changed: 146 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -23,18 +23,20 @@ where
2323
}
2424

2525
#[stable(feature = "rust1", since = "1.0.0")]
26-
impl<T: Eq> Eq for [T] {}
26+
#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
27+
impl<T: [const] Eq> const Eq for [T] {}
2728

2829
/// Implements comparison of slices [lexicographically](Ord#lexicographical-comparison).
2930
#[stable(feature = "rust1", since = "1.0.0")]
30-
impl<T: Ord> Ord for [T] {
31+
#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
32+
impl<T: [const] Ord> const Ord for [T] {
3133
fn cmp(&self, other: &[T]) -> Ordering {
3234
SliceOrd::compare(self, other)
3335
}
3436
}
3537

3638
#[inline]
37-
fn as_underlying(x: ControlFlow<bool>) -> u8 {
39+
const fn as_underlying(x: ControlFlow<bool>) -> u8 {
3840
// SAFETY: This will only compile if `bool` and `ControlFlow<bool>` have the same
3941
// size (which isn't guaranteed but this is libcore). Because they have the same
4042
// size, it's a niched implementation, which in one byte means there can't be
@@ -46,7 +48,8 @@ fn as_underlying(x: ControlFlow<bool>) -> u8 {
4648

4749
/// Implements comparison of slices [lexicographically](Ord#lexicographical-comparison).
4850
#[stable(feature = "rust1", since = "1.0.0")]
49-
impl<T: PartialOrd> PartialOrd for [T] {
51+
#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
52+
impl<T: [const] PartialOrd> const PartialOrd for [T] {
5053
#[inline]
5154
fn partial_cmp(&self, other: &[T]) -> Option<Ordering> {
5255
SlicePartialOrd::partial_compare(self, other)
@@ -95,9 +98,8 @@ impl<T: PartialOrd> PartialOrd for [T] {
9598

9699
#[doc(hidden)]
97100
// intermediate trait for specialization of slice's PartialEq
98-
#[const_trait]
99101
#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
100-
trait SlicePartialEq<B> {
102+
const trait SlicePartialEq<B> {
101103
fn equal(&self, other: &[B]) -> bool;
102104

103105
fn not_equal(&self, other: &[B]) -> bool {
@@ -155,68 +157,123 @@ where
155157
}
156158

157159
#[doc(hidden)]
160+
#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
158161
// intermediate trait for specialization of slice's PartialOrd
159-
trait SlicePartialOrd: Sized {
162+
const trait SlicePartialOrd: Sized {
160163
fn partial_compare(left: &[Self], right: &[Self]) -> Option<Ordering>;
161164
}
162165

163166
#[doc(hidden)]
167+
#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
164168
// intermediate trait for specialization of slice's PartialOrd chaining methods
165-
trait SliceChain: Sized {
169+
const trait SliceChain: Sized {
166170
fn chaining_lt(left: &[Self], right: &[Self]) -> ControlFlow<bool>;
167171
fn chaining_le(left: &[Self], right: &[Self]) -> ControlFlow<bool>;
168172
fn chaining_gt(left: &[Self], right: &[Self]) -> ControlFlow<bool>;
169173
fn chaining_ge(left: &[Self], right: &[Self]) -> ControlFlow<bool>;
170174
}
171175

172-
type AlwaysBreak<B> = ControlFlow<B, crate::convert::Infallible>;
173-
174-
impl<A: PartialOrd> SlicePartialOrd for A {
176+
#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
177+
impl<A: [const] PartialOrd> const SlicePartialOrd for A {
175178
default fn partial_compare(left: &[A], right: &[A]) -> Option<Ordering> {
176-
let elem_chain = |a, b| match PartialOrd::partial_cmp(a, b) {
177-
Some(Ordering::Equal) => ControlFlow::Continue(()),
178-
non_eq => ControlFlow::Break(non_eq),
179-
};
180-
let len_chain = |a: &_, b: &_| ControlFlow::Break(usize::partial_cmp(a, b));
181-
let AlwaysBreak::Break(b) = chaining_impl(left, right, elem_chain, len_chain);
182-
b
179+
let l = cmp::min(left.len(), right.len());
180+
181+
// Slice to the loop iteration range to enable bound check
182+
// elimination in the compiler
183+
let lhs = &left[..l];
184+
let rhs = &right[..l];
185+
186+
let mut i = 0;
187+
while i < l {
188+
match PartialOrd::partial_cmp(&lhs[i], &rhs[i]) {
189+
Some(Ordering::Equal) => {}
190+
non_eq => return non_eq,
191+
}
192+
i += 1;
193+
}
194+
195+
usize::partial_cmp(&left.len(), &right.len())
183196
}
184197
}
185198

186-
impl<A: PartialOrd> SliceChain for A {
199+
#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
200+
impl<A: [const] PartialOrd> const SliceChain for A {
187201
default fn chaining_lt(left: &[Self], right: &[Self]) -> ControlFlow<bool> {
188-
chaining_impl(left, right, PartialOrd::__chaining_lt, usize::__chaining_lt)
202+
let l = cmp::min(left.len(), right.len());
203+
204+
// Slice to the loop iteration range to enable bound check
205+
// elimination in the compiler
206+
let lhs = &left[..l];
207+
let rhs = &right[..l];
208+
209+
let mut i = 0;
210+
while i < l {
211+
match PartialOrd::__chaining_lt(&lhs[i], &rhs[i]) {
212+
ControlFlow::Continue(()) => {}
213+
ControlFlow::Break(b) => return ControlFlow::Break(b),
214+
}
215+
i += 1;
216+
}
217+
218+
usize::__chaining_lt(&left.len(), &right.len())
189219
}
190220
default fn chaining_le(left: &[Self], right: &[Self]) -> ControlFlow<bool> {
191-
chaining_impl(left, right, PartialOrd::__chaining_le, usize::__chaining_le)
221+
let l = cmp::min(left.len(), right.len());
222+
223+
// Slice to the loop iteration range to enable bound check
224+
// elimination in the compiler
225+
let lhs = &left[..l];
226+
let rhs = &right[..l];
227+
228+
let mut i = 0;
229+
while i < l {
230+
match PartialOrd::__chaining_le(&lhs[i], &rhs[i]) {
231+
ControlFlow::Continue(()) => {}
232+
ControlFlow::Break(b) => return ControlFlow::Break(b),
233+
}
234+
i += 1;
235+
}
236+
237+
usize::__chaining_le(&left.len(), &right.len())
192238
}
193239
default fn chaining_gt(left: &[Self], right: &[Self]) -> ControlFlow<bool> {
194-
chaining_impl(left, right, PartialOrd::__chaining_gt, usize::__chaining_gt)
240+
let l = cmp::min(left.len(), right.len());
241+
242+
// Slice to the loop iteration range to enable bound check
243+
// elimination in the compiler
244+
let lhs = &left[..l];
245+
let rhs = &right[..l];
246+
247+
let mut i = 0;
248+
while i < l {
249+
match PartialOrd::__chaining_gt(&lhs[i], &rhs[i]) {
250+
ControlFlow::Continue(()) => {}
251+
ControlFlow::Break(b) => return ControlFlow::Break(b),
252+
}
253+
i += 1;
254+
}
255+
256+
usize::__chaining_gt(&left.len(), &right.len())
195257
}
196258
default fn chaining_ge(left: &[Self], right: &[Self]) -> ControlFlow<bool> {
197-
chaining_impl(left, right, PartialOrd::__chaining_ge, usize::__chaining_ge)
198-
}
199-
}
200-
201-
#[inline]
202-
fn chaining_impl<'l, 'r, A: PartialOrd, B, C>(
203-
left: &'l [A],
204-
right: &'r [A],
205-
elem_chain: impl Fn(&'l A, &'r A) -> ControlFlow<B>,
206-
len_chain: impl for<'a> FnOnce(&'a usize, &'a usize) -> ControlFlow<B, C>,
207-
) -> ControlFlow<B, C> {
208-
let l = cmp::min(left.len(), right.len());
209-
210-
// Slice to the loop iteration range to enable bound check
211-
// elimination in the compiler
212-
let lhs = &left[..l];
213-
let rhs = &right[..l];
259+
let l = cmp::min(left.len(), right.len());
260+
261+
// Slice to the loop iteration range to enable bound check
262+
// elimination in the compiler
263+
let lhs = &left[..l];
264+
let rhs = &right[..l];
265+
266+
let mut i = 0;
267+
while i < l {
268+
match PartialOrd::__chaining_ge(&lhs[i], &rhs[i]) {
269+
ControlFlow::Continue(()) => {}
270+
ControlFlow::Break(b) => return ControlFlow::Break(b),
271+
}
272+
i += 1;
273+
}
214274

215-
for i in 0..l {
216-
elem_chain(&lhs[i], &rhs[i])?;
275+
usize::__chaining_ge(&left.len(), &right.len())
217276
}
218-
219-
len_chain(&left.len(), &right.len())
220277
}
221278

222279
// This is the impl that we would like to have. Unfortunately it's not sound.
@@ -232,46 +289,65 @@ where
232289
}
233290
*/
234291

235-
impl<A: AlwaysApplicableOrd> SlicePartialOrd for A {
292+
#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
293+
impl<A: [const] AlwaysApplicableOrd> const SlicePartialOrd for A {
236294
fn partial_compare(left: &[A], right: &[A]) -> Option<Ordering> {
237295
Some(SliceOrd::compare(left, right))
238296
}
239297
}
240298

241299
#[rustc_specialization_trait]
242-
trait AlwaysApplicableOrd: SliceOrd + Ord {}
300+
#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
301+
const trait AlwaysApplicableOrd: [const] SliceOrd + [const] Ord {}
243302

244303
macro_rules! always_applicable_ord {
245304
($([$($p:tt)*] $t:ty,)*) => {
246-
$(impl<$($p)*> AlwaysApplicableOrd for $t {})*
305+
$(
306+
#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
307+
impl<$($p)*> const AlwaysApplicableOrd for $t {}
308+
)*
247309
}
248310
}
249311

250312
always_applicable_ord! {
251313
[] u8, [] u16, [] u32, [] u64, [] u128, [] usize,
252314
[] i8, [] i16, [] i32, [] i64, [] i128, [] isize,
253315
[] bool, [] char,
254-
[T: ?Sized] *const T, [T: ?Sized] *mut T,
255-
[T: AlwaysApplicableOrd] &T,
256-
[T: AlwaysApplicableOrd] &mut T,
257-
[T: AlwaysApplicableOrd] Option<T>,
316+
[T: [const] AlwaysApplicableOrd] &T,
317+
[T: [const] AlwaysApplicableOrd] &mut T,
318+
[T: [const] AlwaysApplicableOrd] Option<T>,
258319
}
259320

321+
impl<T: ?Sized> AlwaysApplicableOrd for *const T {}
322+
impl<T: ?Sized> AlwaysApplicableOrd for *mut T {}
323+
260324
#[doc(hidden)]
261325
// intermediate trait for specialization of slice's Ord
262-
trait SliceOrd: Sized {
326+
#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
327+
const trait SliceOrd: Sized {
263328
fn compare(left: &[Self], right: &[Self]) -> Ordering;
264329
}
265330

266-
impl<A: Ord> SliceOrd for A {
331+
#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
332+
impl<A: [const] Ord> const SliceOrd for A {
267333
default fn compare(left: &[Self], right: &[Self]) -> Ordering {
268-
let elem_chain = |a, b| match Ord::cmp(a, b) {
269-
Ordering::Equal => ControlFlow::Continue(()),
270-
non_eq => ControlFlow::Break(non_eq),
271-
};
272-
let len_chain = |a: &_, b: &_| ControlFlow::Break(usize::cmp(a, b));
273-
let AlwaysBreak::Break(b) = chaining_impl(left, right, elem_chain, len_chain);
274-
b
334+
let l = cmp::min(left.len(), right.len());
335+
336+
// Slice to the loop iteration range to enable bound check
337+
// elimination in the compiler
338+
let lhs = &left[..l];
339+
let rhs = &right[..l];
340+
341+
let mut i = 0;
342+
while i < l {
343+
match Ord::cmp(&lhs[i], &rhs[i]) {
344+
Ordering::Equal => {}
345+
non_eq => return non_eq,
346+
}
347+
i += 1;
348+
}
349+
350+
usize::cmp(&left.len(), &right.len())
275351
}
276352
}
277353

@@ -283,17 +359,19 @@ impl<A: Ord> SliceOrd for A {
283359
/// * For every `x` and `y` of this type, `Ord(x, y)` must return the same
284360
/// value as `Ord::cmp(transmute::<_, u8>(x), transmute::<_, u8>(y))`.
285361
#[rustc_specialization_trait]
286-
unsafe trait UnsignedBytewiseOrd: Ord {}
362+
#[const_trait]
363+
unsafe trait UnsignedBytewiseOrd: [const] Ord {}
287364

288-
unsafe impl UnsignedBytewiseOrd for bool {}
289-
unsafe impl UnsignedBytewiseOrd for u8 {}
290-
unsafe impl UnsignedBytewiseOrd for NonZero<u8> {}
291-
unsafe impl UnsignedBytewiseOrd for Option<NonZero<u8>> {}
292-
unsafe impl UnsignedBytewiseOrd for ascii::Char {}
365+
unsafe impl const UnsignedBytewiseOrd for bool {}
366+
unsafe impl const UnsignedBytewiseOrd for u8 {}
367+
unsafe impl const UnsignedBytewiseOrd for NonZero<u8> {}
368+
unsafe impl const UnsignedBytewiseOrd for Option<NonZero<u8>> {}
369+
unsafe impl const UnsignedBytewiseOrd for ascii::Char {}
293370

294371
// `compare_bytes` compares a sequence of unsigned bytes lexicographically, so
295372
// use it if the requirements for `UnsignedBytewiseOrd` are fulfilled.
296-
impl<A: Ord + UnsignedBytewiseOrd> SliceOrd for A {
373+
#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
374+
impl<A: [const] Ord + [const] UnsignedBytewiseOrd> const SliceOrd for A {
297375
#[inline]
298376
fn compare(left: &[Self], right: &[Self]) -> Ordering {
299377
// Since the length of a slice is always less than or equal to
@@ -318,7 +396,8 @@ impl<A: Ord + UnsignedBytewiseOrd> SliceOrd for A {
318396
}
319397

320398
// Don't generate our own chaining loops for `memcmp`-able things either.
321-
impl<A: PartialOrd + UnsignedBytewiseOrd> SliceChain for A {
399+
#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
400+
impl<A: [const] PartialOrd + [const] UnsignedBytewiseOrd> const SliceChain for A {
322401
#[inline]
323402
fn chaining_lt(left: &[Self], right: &[Self]) -> ControlFlow<bool> {
324403
match SliceOrd::compare(left, right) {

0 commit comments

Comments
 (0)