mirror of
https://github.com/rust-lang/rust
synced 2024-11-05 20:45:15 +00:00
Rollup merge of #127748 - scottmcm:option_len, r=joboet
Use Option's discriminant as its size hint I was looking at this in MIR after a question on discord, and noticed that it ends up with a switch in MIR (<https://rust.godbolt.org/z/3q4cYnnb3>), which it doesn't need because (as `Option::as_slice` uses) the discriminant is already the length.
This commit is contained in:
commit
6f7fa03a06
2 changed files with 51 additions and 8 deletions
|
@ -770,6 +770,13 @@ pub const fn as_pin_mut(self: Pin<&mut Self>) -> Option<Pin<&mut T>> {
|
|||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
const fn len(&self) -> usize {
|
||||
// Using the intrinsic avoids emitting a branch to get the 0 or 1.
|
||||
let discriminant: isize = crate::intrinsics::discriminant_value(self);
|
||||
discriminant as usize
|
||||
}
|
||||
|
||||
/// Returns a slice of the contained value, if any. If this is `None`, an
|
||||
/// empty slice is returned. This can be useful to have a single type of
|
||||
/// iterator over an `Option` or slice.
|
||||
|
@ -812,7 +819,7 @@ pub const fn as_slice(&self) -> &[T] {
|
|||
unsafe {
|
||||
slice::from_raw_parts(
|
||||
(self as *const Self).byte_add(core::mem::offset_of!(Self, Some.0)).cast(),
|
||||
self.is_some() as usize,
|
||||
self.len(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -869,7 +876,7 @@ pub const fn as_mut_slice(&mut self) -> &mut [T] {
|
|||
unsafe {
|
||||
slice::from_raw_parts_mut(
|
||||
(self as *mut Self).byte_add(core::mem::offset_of!(Self, Some.0)).cast(),
|
||||
self.is_some() as usize,
|
||||
self.len(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -2242,10 +2249,8 @@ fn next(&mut self) -> Option<A> {
|
|||
|
||||
#[inline]
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
match self.opt {
|
||||
Some(_) => (1, Some(1)),
|
||||
None => (0, Some(0)),
|
||||
}
|
||||
let len = self.len();
|
||||
(len, Some(len))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2256,7 +2261,12 @@ fn next_back(&mut self) -> Option<A> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<A> ExactSizeIterator for Item<A> {}
|
||||
impl<A> ExactSizeIterator for Item<A> {
|
||||
#[inline]
|
||||
fn len(&self) -> usize {
|
||||
self.opt.len()
|
||||
}
|
||||
}
|
||||
impl<A> FusedIterator for Item<A> {}
|
||||
unsafe impl<A> TrustedLen for Item<A> {}
|
||||
|
||||
|
|
|
@ -14,6 +14,14 @@ pub fn u64_opt_as_slice(o: &Option<u64>) -> &[u64] {
|
|||
// CHECK-NOT: br
|
||||
// CHECK-NOT: switch
|
||||
// CHECK-NOT: icmp
|
||||
// CHECK: %[[LEN:.+]] = load i64,{{.+}} !range ![[META_U64:.+]], !noundef
|
||||
// CHECK-NOT: select
|
||||
// CHECK-NOT: br
|
||||
// CHECK-NOT: switch
|
||||
// CHECK-NOT: icmp
|
||||
// CHECK: %[[T0:.+]] = insertvalue { ptr, i64 } poison, ptr %{{.+}}, 0
|
||||
// CHECK-NEXT: %[[T1:.+]] = insertvalue { ptr, i64 } %[[T0]], i64 %[[LEN]], 1
|
||||
// CHECK-NEXT: ret { ptr, i64 } %[[T1]]
|
||||
o.as_slice()
|
||||
}
|
||||
|
||||
|
@ -25,10 +33,35 @@ pub fn nonzero_u64_opt_as_slice(o: &Option<NonZero<u64>>) -> &[NonZero<u64>] {
|
|||
// CHECK-NOT: switch
|
||||
// CHECK-NOT: icmp
|
||||
// CHECK: %[[NZ:.+]] = icmp ne i64 %{{.+}}, 0
|
||||
// CHECK-NEXT: zext i1 %[[NZ]] to i64
|
||||
// CHECK-NEXT: %[[LEN:.+]] = zext i1 %[[NZ]] to i64
|
||||
// CHECK-NOT: select
|
||||
// CHECK-NOT: br
|
||||
// CHECK-NOT: switch
|
||||
// CHECK-NOT: icmp
|
||||
// CHECK: %[[T0:.+]] = insertvalue { ptr, i64 } poison, ptr %o, 0
|
||||
// CHECK-NEXT: %[[T1:.+]] = insertvalue { ptr, i64 } %[[T0]], i64 %[[LEN]], 1
|
||||
// CHECK-NEXT: ret { ptr, i64 } %[[T1]]
|
||||
o.as_slice()
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @u8_opt_as_slice
|
||||
#[no_mangle]
|
||||
pub fn u8_opt_as_slice(o: &Option<u8>) -> &[u8] {
|
||||
// CHECK-NOT: select
|
||||
// CHECK-NOT: br
|
||||
// CHECK-NOT: switch
|
||||
// CHECK-NOT: icmp
|
||||
// CHECK: %[[TAG:.+]] = load i8,{{.+}} !range ![[META_U8:.+]], !noundef
|
||||
// CHECK: %[[LEN:.+]] = zext{{.*}} i8 %[[TAG]] to i64
|
||||
// CHECK-NOT: select
|
||||
// CHECK-NOT: br
|
||||
// CHECK-NOT: switch
|
||||
// CHECK-NOT: icmp
|
||||
// CHECK: %[[T0:.+]] = insertvalue { ptr, i64 } poison, ptr %{{.+}}, 0
|
||||
// CHECK-NEXT: %[[T1:.+]] = insertvalue { ptr, i64 } %[[T0]], i64 %[[LEN]], 1
|
||||
// CHECK-NEXT: ret { ptr, i64 } %[[T1]]
|
||||
o.as_slice()
|
||||
}
|
||||
|
||||
// CHECK: ![[META_U64]] = !{i64 0, i64 2}
|
||||
// CHECK: ![[META_U8]] = !{i8 0, i8 2}
|
||||
|
|
Loading…
Reference in a new issue