1#[cfg(not(feature = "ferrocene_subset"))]
2use crate::iter::{FusedIterator, TrustedLen};
3use crate::num::NonZero;
4use crate::ops::{NeverShortCircuit, Try};
5use crate::ub_checks;
6
7#[cfg_attr(not(feature = "ferrocene_subset"), derive(Debug))]
14#[cfg_attr(not(feature = "ferrocene_subset"), derive_const(Clone, Eq, PartialEq))]
15#[cfg_attr(feature = "ferrocene_subset", derive_const(Clone, PartialEq))]
16pub(crate) struct IndexRange {
17 start: usize,
18 end: usize,
19}
20
21#[cfg_attr(feature = "ferrocene_subset", expect(dead_code))]
22impl IndexRange {
23 #[inline]
26 #[track_caller]
27 pub(crate) const unsafe fn new_unchecked(start: usize, end: usize) -> Self {
28 ub_checks::assert_unsafe_precondition!(
29 check_library_ub,
30 "IndexRange::new_unchecked requires `start <= end`",
31 (start: usize = start, end: usize = end) => start <= end,
32 );
33 IndexRange { start, end }
34 }
35
36 #[inline]
37 pub(crate) const fn zero_to(end: usize) -> Self {
38 IndexRange { start: 0, end }
39 }
40
41 #[inline]
42 pub(crate) const fn start(&self) -> usize {
43 self.start
44 }
45
46 #[inline]
47 pub(crate) const fn end(&self) -> usize {
48 self.end
49 }
50
51 #[inline]
52 pub(crate) const fn len(&self) -> usize {
53 unsafe { crate::intrinsics::unchecked_sub(self.end, self.start) }
56 }
57
58 #[inline]
61 const unsafe fn next_unchecked(&mut self) -> usize {
62 debug_assert!(self.start < self.end);
63
64 let value = self.start;
65 self.start = unsafe { value.unchecked_add(1) };
67 value
68 }
69
70 #[inline]
73 const unsafe fn next_back_unchecked(&mut self) -> usize {
74 debug_assert!(self.start < self.end);
75
76 let value = unsafe { self.end.unchecked_sub(1) };
78 self.end = value;
79 value
80 }
81
82 #[inline]
88 pub(crate) fn take_prefix(&mut self, n: usize) -> Self {
89 let mid = if n <= self.len() {
90 unsafe { crate::intrinsics::unchecked_add(self.start, n) }
94 } else {
95 self.end
96 };
97 let prefix = Self { start: self.start, end: mid };
98 self.start = mid;
99 prefix
100 }
101
102 #[inline]
108 pub(crate) fn take_suffix(&mut self, n: usize) -> Self {
109 let mid = if n <= self.len() {
110 unsafe { crate::intrinsics::unchecked_sub(self.end, n) }
114 } else {
115 self.start
116 };
117 let suffix = Self { start: mid, end: self.end };
118 self.end = mid;
119 suffix
120 }
121
122 #[inline]
123 const fn assume_range(&self) {
124 unsafe { crate::hint::assert_unchecked(self.start <= self.end) }
126 }
127}
128
129impl Iterator for IndexRange {
130 type Item = usize;
131
132 #[inline]
133 fn next(&mut self) -> Option<usize> {
134 if self.len() > 0 {
135 unsafe { Some(self.next_unchecked()) }
137 } else {
138 None
139 }
140 }
141
142 #[inline]
143 fn size_hint(&self) -> (usize, Option<usize>) {
144 let len = self.len();
145 (len, Some(len))
146 }
147
148 #[inline]
149 fn advance_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
150 let taken = self.take_prefix(n);
151 NonZero::new(n - taken.len()).map_or(Ok(()), Err)
152 }
153
154 #[inline]
155 fn fold<B, F: FnMut(B, usize) -> B>(mut self, init: B, f: F) -> B {
156 self.try_fold(init, NeverShortCircuit::wrap_mut_2(f)).0
157 }
158
159 #[inline]
160 fn try_fold<B, F, R>(&mut self, mut accum: B, mut f: F) -> R
161 where
162 Self: Sized,
163 F: FnMut(B, Self::Item) -> R,
164 R: Try<Output = B>,
165 {
166 self.assume_range();
170 while self.start != self.end {
171 let i = unsafe { self.next_unchecked() };
173 accum = f(accum, i)?;
174 }
175 try { accum }
176 }
177}
178
179impl DoubleEndedIterator for IndexRange {
180 #[inline]
181 fn next_back(&mut self) -> Option<usize> {
182 if self.len() > 0 {
183 unsafe { Some(self.next_back_unchecked()) }
185 } else {
186 None
187 }
188 }
189
190 #[inline]
191 fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
192 let taken = self.take_suffix(n);
193 NonZero::new(n - taken.len()).map_or(Ok(()), Err)
194 }
195
196 #[inline]
197 fn rfold<B, F: FnMut(B, usize) -> B>(mut self, init: B, f: F) -> B {
198 self.try_rfold(init, NeverShortCircuit::wrap_mut_2(f)).0
199 }
200
201 #[inline]
202 fn try_rfold<B, F, R>(&mut self, mut accum: B, mut f: F) -> R
203 where
204 Self: Sized,
205 F: FnMut(B, Self::Item) -> R,
206 R: Try<Output = B>,
207 {
208 self.assume_range();
212 while self.start != self.end {
213 let i = unsafe { self.next_back_unchecked() };
215 accum = f(accum, i)?;
216 }
217 try { accum }
218 }
219}
220
221#[cfg(not(feature = "ferrocene_subset"))]
222impl ExactSizeIterator for IndexRange {
223 #[inline]
224 fn len(&self) -> usize {
225 self.len()
226 }
227}
228
229#[cfg(not(feature = "ferrocene_subset"))]
231unsafe impl TrustedLen for IndexRange {}
232
233#[cfg(not(feature = "ferrocene_subset"))]
234impl FusedIterator for IndexRange {}