• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //! Macros used by iterators of slice.
2 
3 // Shrinks the iterator when T is a ZST, setting the length to `new_len`.
4 // `new_len` must not exceed `self.len()`.
5 macro_rules! zst_set_len {
6     ($self: ident, $new_len: expr) => {{
7         #![allow(unused_unsafe)] // we're sometimes used within an unsafe block
8 
9         // SAFETY: same as `invalid(_mut)`, but the macro doesn't know
10         // which versions of that function to call, so open-code it.
11         $self.end = unsafe { mem::transmute::<usize, _>($new_len) };
12     }};
13 }
14 
15 // Shrinks the iterator when T is a ZST, reducing the length by `n`.
16 // `n` must not exceed `self.len()`.
17 macro_rules! zst_shrink {
18     ($self: ident, $n: ident) => {
19         let new_len = $self.end.addr() - $n;
20         zst_set_len!($self, new_len);
21     };
22 }
23 
24 // Inlining is_empty and len makes a huge performance difference
25 macro_rules! is_empty {
26     ($self: ident) => {
27         if T::IS_ZST { $self.end.addr() == 0 } else { $self.ptr.as_ptr() as *const _ == $self.end }
28     };
29 }
30 
31 macro_rules! len {
32     ($self: ident) => {{
33         #![allow(unused_unsafe)] // we're sometimes used within an unsafe block
34 
35         if T::IS_ZST {
36             $self.end.addr()
37         } else {
38             // To get rid of some bounds checks (see `position`), we use ptr_sub instead of
39             // offset_from (Tested by `codegen/slice-position-bounds-check`.)
40             // SAFETY: by the type invariant pointers are aligned and `start <= end`
41             unsafe { $self.end.sub_ptr($self.ptr.as_ptr()) }
42         }
43     }};
44 }
45 
46 // The shared definition of the `Iter` and `IterMut` iterators
47 macro_rules! iterator {
48     (
49         struct $name:ident -> $ptr:ty,
50         $elem:ty,
51         $raw_mut:tt,
52         {$( $mut_:tt )?},
53         {$($extra:tt)*}
54     ) => {
55         // Returns the first element and moves the start of the iterator forwards by 1.
56         // Greatly improves performance compared to an inlined function. The iterator
57         // must not be empty.
58         macro_rules! next_unchecked {
59             ($self: ident) => {& $( $mut_ )? *$self.post_inc_start(1)}
60         }
61 
62         // Returns the last element and moves the end of the iterator backwards by 1.
63         // Greatly improves performance compared to an inlined function. The iterator
64         // must not be empty.
65         macro_rules! next_back_unchecked {
66             ($self: ident) => {& $( $mut_ )? *$self.pre_dec_end(1)}
67         }
68 
69         impl<'a, T> $name<'a, T> {
70             // Helper function for creating a slice from the iterator.
71             #[inline(always)]
72             fn make_slice(&self) -> &'a [T] {
73                 // SAFETY: the iterator was created from a slice with pointer
74                 // `self.ptr` and length `len!(self)`. This guarantees that all
75                 // the prerequisites for `from_raw_parts` are fulfilled.
76                 unsafe { from_raw_parts(self.ptr.as_ptr(), len!(self)) }
77             }
78 
79             // Helper function for moving the start of the iterator forwards by `offset` elements,
80             // returning the old start.
81             // Unsafe because the offset must not exceed `self.len()`.
82             #[inline(always)]
83             unsafe fn post_inc_start(&mut self, offset: usize) -> * $raw_mut T {
84                 let old = self.ptr;
85                 if T::IS_ZST {
86                     zst_shrink!(self, offset);
87                 } else {
88                     // SAFETY: the caller guarantees that `offset` doesn't exceed `self.len()`,
89                     // so this new pointer is inside `self` and thus guaranteed to be non-null.
90                     self.ptr = unsafe { self.ptr.add(offset) };
91                 }
92                 old.as_ptr()
93             }
94 
95             // Helper function for moving the end of the iterator backwards by `offset` elements,
96             // returning the new end.
97             // Unsafe because the offset must not exceed `self.len()`.
98             #[inline(always)]
99             unsafe fn pre_dec_end(&mut self, offset: usize) -> * $raw_mut T {
100                 if T::IS_ZST {
101                     zst_shrink!(self, offset);
102                     self.ptr.as_ptr()
103                 } else {
104                     // SAFETY: the caller guarantees that `offset` doesn't exceed `self.len()`,
105                     // which is guaranteed to not overflow an `isize`. Also, the resulting pointer
106                     // is in bounds of `slice`, which fulfills the other requirements for `offset`.
107                     self.end = unsafe { self.end.sub(offset) };
108                     self.end
109                 }
110             }
111         }
112 
113         #[stable(feature = "rust1", since = "1.0.0")]
114         impl<T> ExactSizeIterator for $name<'_, T> {
115             #[inline(always)]
116             fn len(&self) -> usize {
117                 len!(self)
118             }
119 
120             #[inline(always)]
121             fn is_empty(&self) -> bool {
122                 is_empty!(self)
123             }
124         }
125 
126         #[stable(feature = "rust1", since = "1.0.0")]
127         impl<'a, T> Iterator for $name<'a, T> {
128             type Item = $elem;
129 
130             #[inline]
131             fn next(&mut self) -> Option<$elem> {
132                 // could be implemented with slices, but this avoids bounds checks
133 
134                 // SAFETY: `assume` call is safe because slices over non-ZSTs must
135                 // have a non-null end pointer. The call to `next_unchecked!` is
136                 // safe since we check if the iterator is empty first.
137                 unsafe {
138                     if !<T>::IS_ZST {
139                         assume(!self.end.is_null());
140                     }
141                     if is_empty!(self) {
142                         None
143                     } else {
144                         Some(next_unchecked!(self))
145                     }
146                 }
147             }
148 
149             #[inline]
150             fn size_hint(&self) -> (usize, Option<usize>) {
151                 let exact = len!(self);
152                 (exact, Some(exact))
153             }
154 
155             #[inline]
156             fn count(self) -> usize {
157                 len!(self)
158             }
159 
160             #[inline]
161             fn nth(&mut self, n: usize) -> Option<$elem> {
162                 if n >= len!(self) {
163                     // This iterator is now empty.
164                     if T::IS_ZST {
165                         zst_set_len!(self, 0);
166                     } else {
167                         // SAFETY: end can't be 0 if T isn't ZST because ptr isn't 0 and end >= ptr
168                         unsafe {
169                             self.ptr = NonNull::new_unchecked(self.end as *mut T);
170                         }
171                     }
172                     return None;
173                 }
174                 // SAFETY: We are in bounds. `post_inc_start` does the right thing even for ZSTs.
175                 unsafe {
176                     self.post_inc_start(n);
177                     Some(next_unchecked!(self))
178                 }
179             }
180 
181             #[inline]
182             fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
183                 let advance = cmp::min(len!(self), n);
184                 // SAFETY: By construction, `advance` does not exceed `self.len()`.
185                 unsafe { self.post_inc_start(advance) };
186                 NonZeroUsize::new(n - advance).map_or(Ok(()), Err)
187             }
188 
189             #[inline]
190             fn last(mut self) -> Option<$elem> {
191                 self.next_back()
192             }
193 
194             #[inline]
195             fn fold<B, F>(self, init: B, mut f: F) -> B
196                 where
197                     F: FnMut(B, Self::Item) -> B,
198             {
199                 // this implementation consists of the following optimizations compared to the
200                 // default implementation:
201                 // - do-while loop, as is llvm's preferred loop shape,
202                 //   see https://releases.llvm.org/16.0.0/docs/LoopTerminology.html#more-canonical-loops
203                 // - bumps an index instead of a pointer since the latter case inhibits
204                 //   some optimizations, see #111603
205                 // - avoids Option wrapping/matching
206                 if is_empty!(self) {
207                     return init;
208                 }
209                 let mut acc = init;
210                 let mut i = 0;
211                 let len = len!(self);
212                 loop {
213                     // SAFETY: the loop iterates `i in 0..len`, which always is in bounds of
214                     // the slice allocation
215                     acc = f(acc, unsafe { & $( $mut_ )? *self.ptr.add(i).as_ptr() });
216                     // SAFETY: `i` can't overflow since it'll only reach usize::MAX if the
217                     // slice had that length, in which case we'll break out of the loop
218                     // after the increment
219                     i = unsafe { i.unchecked_add(1) };
220                     if i == len {
221                         break;
222                     }
223                 }
224                 acc
225             }
226 
227             // We override the default implementation, which uses `try_fold`,
228             // because this simple implementation generates less LLVM IR and is
229             // faster to compile.
230             #[inline]
231             fn for_each<F>(mut self, mut f: F)
232             where
233                 Self: Sized,
234                 F: FnMut(Self::Item),
235             {
236                 while let Some(x) = self.next() {
237                     f(x);
238                 }
239             }
240 
241             // We override the default implementation, which uses `try_fold`,
242             // because this simple implementation generates less LLVM IR and is
243             // faster to compile.
244             #[inline]
245             fn all<F>(&mut self, mut f: F) -> bool
246             where
247                 Self: Sized,
248                 F: FnMut(Self::Item) -> bool,
249             {
250                 while let Some(x) = self.next() {
251                     if !f(x) {
252                         return false;
253                     }
254                 }
255                 true
256             }
257 
258             // We override the default implementation, which uses `try_fold`,
259             // because this simple implementation generates less LLVM IR and is
260             // faster to compile.
261             #[inline]
262             fn any<F>(&mut self, mut f: F) -> bool
263             where
264                 Self: Sized,
265                 F: FnMut(Self::Item) -> bool,
266             {
267                 while let Some(x) = self.next() {
268                     if f(x) {
269                         return true;
270                     }
271                 }
272                 false
273             }
274 
275             // We override the default implementation, which uses `try_fold`,
276             // because this simple implementation generates less LLVM IR and is
277             // faster to compile.
278             #[inline]
279             fn find<P>(&mut self, mut predicate: P) -> Option<Self::Item>
280             where
281                 Self: Sized,
282                 P: FnMut(&Self::Item) -> bool,
283             {
284                 while let Some(x) = self.next() {
285                     if predicate(&x) {
286                         return Some(x);
287                     }
288                 }
289                 None
290             }
291 
292             // We override the default implementation, which uses `try_fold`,
293             // because this simple implementation generates less LLVM IR and is
294             // faster to compile.
295             #[inline]
296             fn find_map<B, F>(&mut self, mut f: F) -> Option<B>
297             where
298                 Self: Sized,
299                 F: FnMut(Self::Item) -> Option<B>,
300             {
301                 while let Some(x) = self.next() {
302                     if let Some(y) = f(x) {
303                         return Some(y);
304                     }
305                 }
306                 None
307             }
308 
309             // We override the default implementation, which uses `try_fold`,
310             // because this simple implementation generates less LLVM IR and is
311             // faster to compile. Also, the `assume` avoids a bounds check.
312             #[inline]
313             #[rustc_inherit_overflow_checks]
314             fn position<P>(&mut self, mut predicate: P) -> Option<usize> where
315                 Self: Sized,
316                 P: FnMut(Self::Item) -> bool,
317             {
318                 let n = len!(self);
319                 let mut i = 0;
320                 while let Some(x) = self.next() {
321                     if predicate(x) {
322                         // SAFETY: we are guaranteed to be in bounds by the loop invariant:
323                         // when `i >= n`, `self.next()` returns `None` and the loop breaks.
324                         unsafe { assume(i < n) };
325                         return Some(i);
326                     }
327                     i += 1;
328                 }
329                 None
330             }
331 
332             // We override the default implementation, which uses `try_fold`,
333             // because this simple implementation generates less LLVM IR and is
334             // faster to compile. Also, the `assume` avoids a bounds check.
335             #[inline]
336             fn rposition<P>(&mut self, mut predicate: P) -> Option<usize> where
337                 P: FnMut(Self::Item) -> bool,
338                 Self: Sized + ExactSizeIterator + DoubleEndedIterator
339             {
340                 let n = len!(self);
341                 let mut i = n;
342                 while let Some(x) = self.next_back() {
343                     i -= 1;
344                     if predicate(x) {
345                         // SAFETY: `i` must be lower than `n` since it starts at `n`
346                         // and is only decreasing.
347                         unsafe { assume(i < n) };
348                         return Some(i);
349                     }
350                 }
351                 None
352             }
353 
354             #[inline]
355             unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item {
356                 // SAFETY: the caller must guarantee that `i` is in bounds of
357                 // the underlying slice, so `i` cannot overflow an `isize`, and
358                 // the returned references is guaranteed to refer to an element
359                 // of the slice and thus guaranteed to be valid.
360                 //
361                 // Also note that the caller also guarantees that we're never
362                 // called with the same index again, and that no other methods
363                 // that will access this subslice are called, so it is valid
364                 // for the returned reference to be mutable in the case of
365                 // `IterMut`
366                 unsafe { & $( $mut_ )? * self.ptr.as_ptr().add(idx) }
367             }
368 
369             $($extra)*
370         }
371 
372         #[stable(feature = "rust1", since = "1.0.0")]
373         impl<'a, T> DoubleEndedIterator for $name<'a, T> {
374             #[inline]
375             fn next_back(&mut self) -> Option<$elem> {
376                 // could be implemented with slices, but this avoids bounds checks
377 
378                 // SAFETY: `assume` call is safe because slices over non-ZSTs must
379                 // have a non-null end pointer. The call to `next_back_unchecked!`
380                 // is safe since we check if the iterator is empty first.
381                 unsafe {
382                     if !<T>::IS_ZST {
383                         assume(!self.end.is_null());
384                     }
385                     if is_empty!(self) {
386                         None
387                     } else {
388                         Some(next_back_unchecked!(self))
389                     }
390                 }
391             }
392 
393             #[inline]
394             fn nth_back(&mut self, n: usize) -> Option<$elem> {
395                 if n >= len!(self) {
396                     // This iterator is now empty.
397                     if T::IS_ZST {
398                         zst_set_len!(self, 0);
399                     } else {
400                         self.end = self.ptr.as_ptr();
401                     }
402                     return None;
403                 }
404                 // SAFETY: We are in bounds. `pre_dec_end` does the right thing even for ZSTs.
405                 unsafe {
406                     self.pre_dec_end(n);
407                     Some(next_back_unchecked!(self))
408                 }
409             }
410 
411             #[inline]
412             fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
413                 let advance = cmp::min(len!(self), n);
414                 // SAFETY: By construction, `advance` does not exceed `self.len()`.
415                 unsafe { self.pre_dec_end(advance) };
416                 NonZeroUsize::new(n - advance).map_or(Ok(()), Err)
417             }
418         }
419 
420         #[stable(feature = "fused", since = "1.26.0")]
421         impl<T> FusedIterator for $name<'_, T> {}
422 
423         #[unstable(feature = "trusted_len", issue = "37572")]
424         unsafe impl<T> TrustedLen for $name<'_, T> {}
425 
426         impl<'a, T> UncheckedIterator for $name<'a, T> {
427             unsafe fn next_unchecked(&mut self) -> $elem {
428                 // SAFETY: The caller promised there's at least one more item.
429                 unsafe {
430                     next_unchecked!(self)
431                 }
432             }
433         }
434 
435         #[stable(feature = "default_iters", since = "1.70.0")]
436         impl<T> Default for $name<'_, T> {
437             /// Creates an empty slice iterator.
438             ///
439             /// ```
440             #[doc = concat!("# use core::slice::", stringify!($name), ";")]
441             #[doc = concat!("let iter: ", stringify!($name<'_, u8>), " = Default::default();")]
442             /// assert_eq!(iter.len(), 0);
443             /// ```
444             fn default() -> Self {
445                 (& $( $mut_ )? []).into_iter()
446             }
447         }
448     }
449 }
450 
451 macro_rules! forward_iterator {
452     ($name:ident: $elem:ident, $iter_of:ty) => {
453         #[stable(feature = "rust1", since = "1.0.0")]
454         impl<'a, $elem, P> Iterator for $name<'a, $elem, P>
455         where
456             P: FnMut(&T) -> bool,
457         {
458             type Item = $iter_of;
459 
460             #[inline]
461             fn next(&mut self) -> Option<$iter_of> {
462                 self.inner.next()
463             }
464 
465             #[inline]
466             fn size_hint(&self) -> (usize, Option<usize>) {
467                 self.inner.size_hint()
468             }
469         }
470 
471         #[stable(feature = "fused", since = "1.26.0")]
472         impl<'a, $elem, P> FusedIterator for $name<'a, $elem, P> where P: FnMut(&T) -> bool {}
473     };
474 }
475