summaryrefslogtreecommitdiffstats
path: root/library/core/src/array
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:18:32 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:18:32 +0000
commit4547b622d8d29df964fa2914213088b148c498fc (patch)
tree9fc6b25f3c3add6b745be9a2400a6e96140046e9 /library/core/src/array
parentReleasing progress-linux version 1.66.0+dfsg1-1~progress7.99u1. (diff)
downloadrustc-4547b622d8d29df964fa2914213088b148c498fc.tar.xz
rustc-4547b622d8d29df964fa2914213088b148c498fc.zip
Merging upstream version 1.67.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'library/core/src/array')
-rw-r--r--library/core/src/array/mod.rs88
1 files changed, 64 insertions, 24 deletions
diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs
index eae0e1c76..94a1a1d32 100644
--- a/library/core/src/array/mod.rs
+++ b/library/core/src/array/mod.rs
@@ -23,7 +23,8 @@ mod iter;
#[stable(feature = "array_value_iter", since = "1.51.0")]
pub use iter::IntoIter;
-/// Creates an array `[T; N]` where each array element `T` is returned by the `cb` call.
+/// Creates an array of type [T; N], where each element `T` is the returned value from `cb`
+/// using that element's index.
///
/// # Arguments
///
@@ -36,8 +37,18 @@ pub use iter::IntoIter;
/// // elements to produce is the length of array down there: only arrays of
/// // equal lengths can be compared, so the const generic parameter `N` is
/// // inferred to be 5, thus creating array of 5 elements.
+///
/// let array = core::array::from_fn(|i| i);
+/// // indexes are: 0 1 2 3 4
/// assert_eq!(array, [0, 1, 2, 3, 4]);
+///
+/// let array2: [usize; 8] = core::array::from_fn(|i| i * 2);
+/// // indexes are: 0 1 2 3 4 5 6 7
+/// assert_eq!(array2, [0, 2, 4, 6, 8, 10, 12, 14]);
+///
+/// let bool_arr = core::array::from_fn::<_, 5, _>(|i| i % 2 == 0);
+/// // indexes are: 0 1 2 3 4
+/// assert_eq!(bool_arr, [true, false, true, false, true]);
/// ```
#[inline]
#[stable(feature = "array_from_fn", since = "1.63.0")]
@@ -865,24 +876,6 @@ where
return Ok(Try::from_output(unsafe { mem::zeroed() }));
}
- struct Guard<'a, T, const N: usize> {
- array_mut: &'a mut [MaybeUninit<T>; N],
- initialized: usize,
- }
-
- impl<T, const N: usize> Drop for Guard<'_, T, N> {
- fn drop(&mut self) {
- debug_assert!(self.initialized <= N);
-
- // SAFETY: this slice will contain only initialized objects.
- unsafe {
- crate::ptr::drop_in_place(MaybeUninit::slice_assume_init_mut(
- &mut self.array_mut.get_unchecked_mut(..self.initialized),
- ));
- }
- }
- }
-
let mut array = MaybeUninit::uninit_array::<N>();
let mut guard = Guard { array_mut: &mut array, initialized: 0 };
@@ -896,13 +889,11 @@ where
ControlFlow::Continue(elem) => elem,
};
- // SAFETY: `guard.initialized` starts at 0, is increased by one in the
- // loop and the loop is aborted once it reaches N (which is
- // `array.len()`).
+ // SAFETY: `guard.initialized` starts at 0, which means push can be called
+ // at most N times, which this loop does.
unsafe {
- guard.array_mut.get_unchecked_mut(guard.initialized).write(item);
+ guard.push_unchecked(item);
}
- guard.initialized += 1;
}
None => {
let alive = 0..guard.initialized;
@@ -920,6 +911,55 @@ where
Ok(Try::from_output(output))
}
+/// Panic guard for incremental initialization of arrays.
+///
+/// Disarm the guard with `mem::forget` once the array has been initialized.
+///
+/// # Safety
+///
+/// All write accesses to this structure are unsafe and must maintain a correct
+/// count of `initialized` elements.
+///
+/// To minimize indirection fields are still pub but callers should at least use
+/// `push_unchecked` to signal that something unsafe is going on.
+pub(crate) struct Guard<'a, T, const N: usize> {
+ /// The array to be initialized.
+ pub array_mut: &'a mut [MaybeUninit<T>; N],
+ /// The number of items that have been initialized so far.
+ pub initialized: usize,
+}
+
+impl<T, const N: usize> Guard<'_, T, N> {
+ /// Adds an item to the array and updates the initialized item counter.
+ ///
+ /// # Safety
+ ///
+ /// No more than N elements must be initialized.
+ #[inline]
+ pub unsafe fn push_unchecked(&mut self, item: T) {
+ // SAFETY: If `initialized` was correct before and the caller does not
+ // invoke this method more than N times then writes will be in-bounds
+ // and slots will not be initialized more than once.
+ unsafe {
+ self.array_mut.get_unchecked_mut(self.initialized).write(item);
+ self.initialized = self.initialized.unchecked_add(1);
+ }
+ }
+}
+
+impl<T, const N: usize> Drop for Guard<'_, T, N> {
+ fn drop(&mut self) {
+ debug_assert!(self.initialized <= N);
+
+ // SAFETY: this slice will contain only initialized objects.
+ unsafe {
+ crate::ptr::drop_in_place(MaybeUninit::slice_assume_init_mut(
+ &mut self.array_mut.get_unchecked_mut(..self.initialized),
+ ));
+ }
+ }
+}
+
/// Returns the next chunk of `N` items from the iterator or errors with an
/// iterator over the remainder. Used for `Iterator::next_chunk`.
#[inline]