Merge from rustc · model-checking/verify-rust-std@cf231e8 (original) (raw)
`@@ -3,7 +3,7 @@ use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable, TrustedF
`
3
3
`use crate::num::NonZero;
`
4
4
`use crate::ops::Try;
`
5
5
`use core::array;
`
6
``
`-
use core::mem::{ManuallyDrop, MaybeUninit};
`
``
6
`+
use core::mem::MaybeUninit;
`
7
7
`use core::ops::ControlFlow;
`
8
8
``
9
9
`` /// An iterator that filters the elements of iter
with predicate
.
``
`@@ -27,6 +27,42 @@ impl<I, P> Filter<I, P> {
`
27
27
`}
`
28
28
`}
`
29
29
``
``
30
`+
impl<I, P> Filter<I, P>
`
``
31
`+
where
`
``
32
`+
I: Iterator,
`
``
33
`+
P: FnMut(&I::Item) -> bool,
`
``
34
`+
{
`
``
35
`+
#[inline]
`
``
36
`+
fn next_chunk_dropless(
`
``
37
`+
&mut self,
`
``
38
`+
) -> Result<[I::Item; N], array::IntoIter<I::Item, N>> {
`
``
39
`+
let mut array: [MaybeUninit<I::Item>; N] = [const { MaybeUninit::uninit() }; N];
`
``
40
`+
let mut initialized = 0;
`
``
41
+
``
42
`+
let result = self.iter.try_for_each(|element| {
`
``
43
`+
let idx = initialized;
`
``
44
`+
// branchless index update combined with unconditionally copying the value even when
`
``
45
`+
// it is filtered reduces branching and dependencies in the loop.
`
``
46
`+
initialized = idx + (self.predicate)(&element) as usize;
`
``
47
`+
// SAFETY: Loop conditions ensure the index is in bounds.
`
``
48
`+
unsafe { array.get_unchecked_mut(idx) }.write(element);
`
``
49
+
``
50
`+
if initialized < N { ControlFlow::Continue(()) } else { ControlFlow::Break(()) }
`
``
51
`+
});
`
``
52
+
``
53
`+
match result {
`
``
54
`+
ControlFlow::Break(()) => {
`
``
55
`+
// SAFETY: The loop above is only explicitly broken when the array has been fully initialized
`
``
56
`+
Ok(unsafe { MaybeUninit::array_assume_init(array) })
`
``
57
`+
}
`
``
58
`+
ControlFlow::Continue(()) => {
`
``
59
`+
// SAFETY: The range is in bounds since the loop breaks when reaching N elements.
`
``
60
`+
Err(unsafe { array::IntoIter::new_unchecked(array, 0..initialized) })
`
``
61
`+
}
`
``
62
`+
}
`
``
63
`+
}
`
``
64
`+
}
`
``
65
+
30
66
`#[stable(feature = "core_impl_debug", since = "1.9.0")]
`
31
67
`impl<I: fmt::Debug, P> fmt::Debug for Filter<I, P> {
`
32
68
`fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
`
`@@ -64,52 +100,16 @@ where
`
64
100
`fn next_chunk(
`
65
101
`&mut self,
`
66
102
`) -> Result<[Self::Item; N], array::IntoIter<Self::Item, N>> {
`
67
``
`-
let mut array: [MaybeUninitSelf::Item; N] = [const { MaybeUninit::uninit() }; N];
`
68
``
-
69
``
`-
struct Guard<'a, T> {
`
70
``
`-
array: &'a mut [MaybeUninit],
`
71
``
`-
initialized: usize,
`
72
``
`-
}
`
73
``
-
74
``
`-
impl Drop for Guard<'_, T> {
`
75
``
`-
#[inline]
`
76
``
`-
fn drop(&mut self) {
`
77
``
`-
if const { crate::mem::needs_drop::() } {
`
78
``
`-
// SAFETY: self.initialized is always <= N, which also is the length of the array.
`
79
``
`-
unsafe {
`
80
``
`-
core::ptr::drop_in_place(MaybeUninit::slice_assume_init_mut(
`
81
``
`-
self.array.get_unchecked_mut(..self.initialized),
`
82
``
`-
));
`
83
``
`-
}
`
84
``
`-
}
`
``
103
`+
// avoid codegen for the dead branch
`
``
104
`+
let fun = const {
`
``
105
`+
if crate::mem::needs_drop::<I::Item>() {
`
``
106
`+
array::iter_next_chunk::<I::Item, N>
`
``
107
`+
} else {
`
``
108
`+
Self::next_chunk_dropless::
`
85
109
`}
`
86
``
`-
}
`
87
``
-
88
``
`-
let mut guard = Guard { array: &mut array, initialized: 0 };
`
89
``
-
90
``
`-
let result = self.iter.try_for_each(|element| {
`
91
``
`-
let idx = guard.initialized;
`
92
``
`-
guard.initialized = idx + (self.predicate)(&element) as usize;
`
93
``
-
94
``
`-
// SAFETY: Loop conditions ensure the index is in bounds.
`
95
``
`-
unsafe { guard.array.get_unchecked_mut(idx) }.write(element);
`
96
``
-
97
``
`-
if guard.initialized < N { ControlFlow::Continue(()) } else { ControlFlow::Break(()) }
`
98
``
`-
});
`
``
110
`+
};
`
99
111
``
100
``
`-
let guard = ManuallyDrop::new(guard);
`
101
``
-
102
``
`-
match result {
`
103
``
`-
ControlFlow::Break(()) => {
`
104
``
`-
// SAFETY: The loop above is only explicitly broken when the array has been fully initialized
`
105
``
`-
Ok(unsafe { MaybeUninit::array_assume_init(array) })
`
106
``
`-
}
`
107
``
`-
ControlFlow::Continue(()) => {
`
108
``
`-
let initialized = guard.initialized;
`
109
``
`-
// SAFETY: The range is in bounds since the loop breaks when reaching N elements.
`
110
``
`-
Err(unsafe { array::IntoIter::new_unchecked(array, 0..initialized) })
`
111
``
`-
}
`
112
``
`-
}
`
``
112
`+
fun(self)
`
113
113
`}
`
114
114
``
115
115
`#[inline]
`