|
1 | 1 | use core::async_iter::AsyncIterator;
|
2 |
| -use core::iter::FusedIterator; |
| 2 | +use core::iter::{self, FusedIterator, TrustedLen, TrustedRandomAccessNoCoerce}; |
| 3 | +use core::mem::MaybeUninit; |
| 4 | +use core::num::NonZero; |
| 5 | +use core::ops::IndexRange; |
3 | 6 | use core::pin::Pin;
|
4 |
| -use core::slice; |
5 | 7 | use core::task::{Context, Poll};
|
| 8 | +use core::{ptr, slice}; |
6 | 9 |
|
7 | 10 | use crate::alloc::Allocator;
|
8 | 11 | #[cfg(not(no_global_oom_handling))]
|
9 | 12 | use crate::borrow::Cow;
|
10 | 13 | use crate::boxed::Box;
|
11 | 14 | #[cfg(not(no_global_oom_handling))]
|
12 | 15 | use crate::string::String;
|
13 |
| -use crate::vec; |
14 | 16 | #[cfg(not(no_global_oom_handling))]
|
15 | 17 | use crate::vec::Vec;
|
| 18 | +use crate::{fmt, vec}; |
16 | 19 |
|
17 | 20 | #[stable(feature = "rust1", since = "1.0.0")]
|
18 | 21 | impl<I: Iterator + ?Sized, A: Allocator> Iterator for Box<I, A> {
|
@@ -208,6 +211,275 @@ impl<'a, const N: usize, I, A: Allocator> !Iterator for &'a Box<[I; N], A> {}
|
208 | 211 | #[stable(feature = "boxed_array_value_iter", since = "CURRENT_RUSTC_VERSION")]
|
209 | 212 | impl<'a, const N: usize, I, A: Allocator> !Iterator for &'a mut Box<[I; N], A> {}
|
210 | 213 |
|
| 214 | +/// A by-value `Box<[T; N]>` iterator. |
| 215 | +#[stable(feature = "boxed_array_value_iter", since = "CURRENT_RUSTC_VERSION")] |
| 216 | +#[rustc_insignificant_dtor] |
| 217 | +pub struct BoxedArrayIntoIter<T, const N: usize, A: Allocator> { |
| 218 | + /// This is the array we are iterating over. |
| 219 | + /// |
| 220 | + /// Elements with index `i` where `alive.start <= i < alive.end` have not |
| 221 | + /// been yielded yet and are valid array entries. Elements with indices `i |
| 222 | + /// < alive.start` or `i >= alive.end` have been yielded already and must |
| 223 | + /// not be accessed anymore! Those dead elements might even be in a |
| 224 | + /// completely uninitialized state! |
| 225 | + /// |
| 226 | + /// So the invariants are: |
| 227 | + /// - `data[alive]` is alive (i.e. contains valid elements) |
| 228 | + /// - `data[..alive.start]` and `data[alive.end..]` are dead (i.e. the |
| 229 | + /// elements were already read and must not be touched anymore!) |
| 230 | + data: Box<[MaybeUninit<T>; N], A>, |
| 231 | + |
| 232 | + /// The elements in `data` that have not been yielded yet. |
| 233 | + /// |
| 234 | + /// Invariants: |
| 235 | + /// - `alive.end <= N` |
| 236 | + /// |
| 237 | + /// (And the `IndexRange` type requires `alive.start <= alive.end`.) |
| 238 | + alive: IndexRange, |
| 239 | +} |
| 240 | + |
| 241 | +impl<T, const N: usize, A: Allocator> BoxedArrayIntoIter<T, N, A> { |
| 242 | + /// Returns an immutable slice of all elements that have not been yielded |
| 243 | + /// yet. |
| 244 | + #[stable(feature = "boxed_array_value_iter", since = "CURRENT_RUSTC_VERSION")] |
| 245 | + pub fn as_slice(&self) -> &[T] { |
| 246 | + // SAFETY: We know that all elements within `alive` are properly initialized. |
| 247 | + unsafe { |
| 248 | + let slice = self.data.get_unchecked(self.alive.clone()); |
| 249 | + MaybeUninit::slice_assume_init_ref(slice) |
| 250 | + } |
| 251 | + } |
| 252 | + |
| 253 | + /// Returns a mutable slice of all elements that have not been yielded yet. |
| 254 | + #[stable(feature = "boxed_array_value_iter", since = "CURRENT_RUSTC_VERSION")] |
| 255 | + pub fn as_mut_slice(&mut self) -> &mut [T] { |
| 256 | + // SAFETY: We know that all elements within `alive` are properly initialized. |
| 257 | + unsafe { |
| 258 | + let slice = self.data.get_unchecked_mut(self.alive.clone()); |
| 259 | + MaybeUninit::slice_assume_init_mut(slice) |
| 260 | + } |
| 261 | + } |
| 262 | +} |
| 263 | + |
| 264 | +#[stable(feature = "boxed_array_value_iter", since = "CURRENT_RUSTC_VERSION")] |
| 265 | +impl<T, const N: usize, A: Allocator> Iterator for BoxedArrayIntoIter<T, N, A> { |
| 266 | + type Item = T; |
| 267 | + fn next(&mut self) -> Option<Self::Item> { |
| 268 | + // Get the next index from the front. |
| 269 | + // |
| 270 | + // Increasing `alive.start` by 1 maintains the invariant regarding |
| 271 | + // `alive`. However, due to this change, for a short time, the alive |
| 272 | + // zone is not `data[alive]` anymore, but `data[idx..alive.end]`. |
| 273 | + self.alive.next().map(|idx| { |
| 274 | + // Read the element from the array. |
| 275 | + // SAFETY: `idx` is an index into the former "alive" region of the |
| 276 | + // array. Reading this element means that `data[idx]` is regarded as |
| 277 | + // dead now (i.e. do not touch). As `idx` was the start of the |
| 278 | + // alive-zone, the alive zone is now `data[alive]` again, restoring |
| 279 | + // all invariants. |
| 280 | + unsafe { self.data.get_unchecked(idx).assume_init_read() } |
| 281 | + }) |
| 282 | + } |
| 283 | + |
| 284 | + fn size_hint(&self) -> (usize, Option<usize>) { |
| 285 | + let len = self.len(); |
| 286 | + (len, Some(len)) |
| 287 | + } |
| 288 | + |
| 289 | + #[inline] |
| 290 | + fn fold<Acc, Fold>(mut self, init: Acc, mut fold: Fold) -> Acc |
| 291 | + where |
| 292 | + Fold: FnMut(Acc, Self::Item) -> Acc, |
| 293 | + { |
| 294 | + let data = &mut self.data; |
| 295 | + iter::ByRefSized(&mut self.alive).fold(init, |acc, idx| { |
| 296 | + // SAFETY: idx is obtained by folding over the `alive` range, which implies the |
| 297 | + // value is currently considered alive but as the range is being consumed each value |
| 298 | + // we read here will only be read once and then considered dead. |
| 299 | + fold(acc, unsafe { data.get_unchecked(idx).assume_init_read() }) |
| 300 | + }) |
| 301 | + } |
| 302 | + |
| 303 | + fn count(self) -> usize { |
| 304 | + self.len() |
| 305 | + } |
| 306 | + |
| 307 | + fn last(mut self) -> Option<Self::Item> { |
| 308 | + self.next_back() |
| 309 | + } |
| 310 | + |
| 311 | + fn advance_by(&mut self, n: usize) -> Result<(), NonZero<usize>> { |
| 312 | + // This also moves the start, which marks them as conceptually "dropped", |
| 313 | + // so if anything goes bad then our drop impl won't double-free them. |
| 314 | + let range_to_drop = self.alive.take_prefix(n); |
| 315 | + let remaining = n - range_to_drop.len(); |
| 316 | + |
| 317 | + // SAFETY: These elements are currently initialized, so it's fine to drop them. |
| 318 | + unsafe { |
| 319 | + let slice = self.data.get_unchecked_mut(range_to_drop); |
| 320 | + ptr::drop_in_place(MaybeUninit::slice_assume_init_mut(slice)); |
| 321 | + } |
| 322 | + |
| 323 | + NonZero::new(remaining).map_or(Ok(()), Err) |
| 324 | + } |
| 325 | + |
| 326 | + #[inline] |
| 327 | + unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item { |
| 328 | + // SAFETY: The caller must provide an idx that is in bound of the remainder. |
| 329 | + unsafe { self.data.as_ptr().add(self.alive.start()).add(idx).cast::<T>().read() } |
| 330 | + } |
| 331 | +} |
| 332 | + |
| 333 | +#[stable(feature = "boxed_array_value_iter", since = "CURRENT_RUSTC_VERSION")] |
| 334 | +impl<T, const N: usize, A: Allocator> DoubleEndedIterator for BoxedArrayIntoIter<T, N, A> { |
| 335 | + fn next_back(&mut self) -> Option<Self::Item> { |
| 336 | + // Get the next index from the back. |
| 337 | + // |
| 338 | + // Decreasing `alive.end` by 1 maintains the invariant regarding |
| 339 | + // `alive`. However, due to this change, for a short time, the alive |
| 340 | + // zone is not `data[alive]` anymore, but `data[alive.start..=idx]`. |
| 341 | + self.alive.next_back().map(|idx| { |
| 342 | + // Read the element from the array. |
| 343 | + // SAFETY: `idx` is an index into the former "alive" region of the |
| 344 | + // array. Reading this element means that `data[idx]` is regarded as |
| 345 | + // dead now (i.e. do not touch). As `idx` was the end of the |
| 346 | + // alive-zone, the alive zone is now `data[alive]` again, restoring |
| 347 | + // all invariants. |
| 348 | + unsafe { self.data.get_unchecked(idx).assume_init_read() } |
| 349 | + }) |
| 350 | + } |
| 351 | + |
| 352 | + #[inline] |
| 353 | + fn rfold<Acc, Fold>(mut self, init: Acc, mut rfold: Fold) -> Acc |
| 354 | + where |
| 355 | + Fold: FnMut(Acc, Self::Item) -> Acc, |
| 356 | + { |
| 357 | + let data = &mut self.data; |
| 358 | + iter::ByRefSized(&mut self.alive).rfold(init, |acc, idx| { |
| 359 | + // SAFETY: idx is obtained by folding over the `alive` range, which implies the |
| 360 | + // value is currently considered alive but as the range is being consumed each value |
| 361 | + // we read here will only be read once and then considered dead. |
| 362 | + rfold(acc, unsafe { data.get_unchecked(idx).assume_init_read() }) |
| 363 | + }) |
| 364 | + } |
| 365 | + |
| 366 | + fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero<usize>> { |
| 367 | + // This also moves the end, which marks them as conceptually "dropped", |
| 368 | + // so if anything goes bad then our drop impl won't double-free them. |
| 369 | + let range_to_drop = self.alive.take_suffix(n); |
| 370 | + let remaining = n - range_to_drop.len(); |
| 371 | + |
| 372 | + // SAFETY: These elements are currently initialized, so it's fine to drop them. |
| 373 | + unsafe { |
| 374 | + let slice = self.data.get_unchecked_mut(range_to_drop); |
| 375 | + ptr::drop_in_place(MaybeUninit::slice_assume_init_mut(slice)); |
| 376 | + } |
| 377 | + |
| 378 | + NonZero::new(remaining).map_or(Ok(()), Err) |
| 379 | + } |
| 380 | +} |
| 381 | + |
| 382 | +#[stable(feature = "boxed_array_value_iter", since = "CURRENT_RUSTC_VERSION")] |
| 383 | +impl<T, const N: usize, A: Allocator> Drop for BoxedArrayIntoIter<T, N, A> { |
| 384 | + fn drop(&mut self) { |
| 385 | + // SAFETY: This is safe: `as_mut_slice` returns exactly the sub-slice |
| 386 | + // of elements that have not been moved out yet and that remain |
| 387 | + // to be dropped. |
| 388 | + unsafe { ptr::drop_in_place(self.as_mut_slice()) } |
| 389 | + } |
| 390 | +} |
| 391 | + |
| 392 | +#[stable(feature = "boxed_array_value_iter", since = "CURRENT_RUSTC_VERSION")] |
| 393 | +impl<T, const N: usize, A: Allocator> ExactSizeIterator for BoxedArrayIntoIter<T, N, A> { |
| 394 | + fn len(&self) -> usize { |
| 395 | + self.alive.len() |
| 396 | + } |
| 397 | + fn is_empty(&self) -> bool { |
| 398 | + self.alive.is_empty() |
| 399 | + } |
| 400 | +} |
| 401 | + |
| 402 | +#[stable(feature = "boxed_array_value_iter", since = "CURRENT_RUSTC_VERSION")] |
| 403 | +impl<T, const N: usize, A: Allocator> FusedIterator for BoxedArrayIntoIter<T, N, A> {} |
| 404 | + |
| 405 | +// The iterator indeed reports the correct length. The number of "alive" |
| 406 | +// elements (that will still be yielded) is the length of the range `alive`. |
| 407 | +// This range is decremented in length in either `next` or `next_back`. It is |
| 408 | +// always decremented by 1 in those methods, but only if `Some(_)` is returned. |
| 409 | +#[stable(feature = "boxed_array_value_iter", since = "CURRENT_RUSTC_VERSION")] |
| 410 | +unsafe impl<T, const N: usize, A: Allocator> TrustedLen for BoxedArrayIntoIter<T, N, A> {} |
| 411 | + |
| 412 | +#[doc(hidden)] |
| 413 | +#[unstable(issue = "none", feature = "std_internals")] |
| 414 | +#[rustc_unsafe_specialization_marker] |
| 415 | +pub trait NonDrop {} |
| 416 | + |
| 417 | +// T: Copy as approximation for !Drop since get_unchecked does not advance self.alive |
| 418 | +// and thus we can't implement drop-handling |
| 419 | +#[unstable(issue = "none", feature = "std_internals")] |
| 420 | +impl<T: Copy> NonDrop for T {} |
| 421 | + |
| 422 | +#[doc(hidden)] |
| 423 | +#[unstable(issue = "none", feature = "std_internals")] |
| 424 | +unsafe impl<T, const N: usize, A: Allocator> TrustedRandomAccessNoCoerce |
| 425 | + for BoxedArrayIntoIter<T, N, A> |
| 426 | +where |
| 427 | + T: NonDrop, |
| 428 | +{ |
| 429 | + const MAY_HAVE_SIDE_EFFECT: bool = false; |
| 430 | +} |
| 431 | + |
| 432 | +#[stable(feature = "boxed_array_value_iter", since = "CURRENT_RUSTC_VERSION")] |
| 433 | +impl<T: Clone, const N: usize, A: Clone + Allocator> Clone for BoxedArrayIntoIter<T, N, A> { |
| 434 | + fn clone(&self) -> Self { |
| 435 | + // Note, we don't really need to match the exact same alive range, so |
| 436 | + // we can just clone into offset 0 regardless of where `self` is. |
| 437 | + |
| 438 | + let mut new = Self { |
| 439 | + data: Box::new_in( |
| 440 | + [const { MaybeUninit::uninit() }; N], |
| 441 | + Box::allocator(&self.data).clone(), |
| 442 | + ), |
| 443 | + alive: IndexRange::zero_to(0), |
| 444 | + }; |
| 445 | + |
| 446 | + // Clone all alive elements. |
| 447 | + for (src, dst) in iter::zip(self.as_slice(), &mut new.data) { |
| 448 | + // Write a clone into the new array, then update its alive range. |
| 449 | + // If cloning panics, we'll correctly drop the previous items. |
| 450 | + dst.write(src.clone()); |
| 451 | + // This addition cannot overflow as we're iterating a slice |
| 452 | + new.alive = IndexRange::zero_to(new.alive.end() + 1); |
| 453 | + } |
| 454 | + |
| 455 | + new |
| 456 | + } |
| 457 | +} |
| 458 | + |
| 459 | +#[stable(feature = "boxed_array_value_iter", since = "CURRENT_RUSTC_VERSION")] |
| 460 | +impl<T: fmt::Debug, const N: usize, A: Allocator> fmt::Debug for BoxedArrayIntoIter<T, N, A> { |
| 461 | + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| 462 | + // Only print the elements that were not yielded yet: we cannot |
| 463 | + // access the yielded elements anymore. |
| 464 | + f.debug_tuple("IntoIter").field(&self.as_slice()).finish() |
| 465 | + } |
| 466 | +} |
| 467 | + |
| 468 | +#[stable(feature = "boxed_array_value_iter", since = "CURRENT_RUSTC_VERSION")] |
| 469 | +impl<T, const N: usize, A: Allocator> IntoIterator for Box<[T; N], A> { |
| 470 | + type IntoIter = BoxedArrayIntoIter<T, N, A>; |
| 471 | + type Item = T; |
| 472 | + fn into_iter(self) -> BoxedArrayIntoIter<T, N, A> { |
| 473 | + // SAFETY: This essentially does a transmute of `[T; N]` -> `[MaybeUninit<T>; N]`, |
| 474 | + // this is explicitly allowed as by the `MaybeUninit` docs. |
| 475 | + let data = unsafe { |
| 476 | + let (ptr, alloc) = Box::into_non_null_with_allocator(self); |
| 477 | + Box::from_non_null_in(ptr.cast(), alloc) |
| 478 | + }; |
| 479 | + BoxedArrayIntoIter { data, alive: IndexRange::zero_to(N) } |
| 480 | + } |
| 481 | +} |
| 482 | + |
211 | 483 | #[stable(feature = "boxed_array_value_iter", since = "CURRENT_RUSTC_VERSION")]
|
212 | 484 | impl<'a, T, const N: usize, A: Allocator> IntoIterator for &'a Box<[T; N], A> {
|
213 | 485 | type IntoIter = slice::Iter<'a, T>;
|
|
0 commit comments