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]

`