Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rebased const Iterator #1

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
148 changes: 90 additions & 58 deletions library/core/src/array/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use crate::error::Error;
use crate::fmt;
use crate::hash::{self, Hash};
use crate::iter::TrustedLen;
use crate::marker::Destruct;
use crate::mem::{self, MaybeUninit};
use crate::ops::{
ChangeOutputType, ControlFlow, FromResidual, Index, IndexMut, NeverShortCircuit, Residual, Try,
Expand Down Expand Up @@ -841,6 +842,62 @@ where
}
}

/// 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.
#[cfg(not(bootstrap))]
pub(crate) struct Guard<'a, T: ~const Destruct, 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,
}
#[cfg(bootstrap)]
pub(crate) struct Guard<'a, T: Destruct, 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 Destruct, const N: usize> const 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),
));
}
}
}
/// Pulls `N` items from `iter` and returns them as an array. If the iterator
/// yields fewer than `N` items, `Err` is returned containing an iterator over
/// the already yielded items.
Expand All @@ -852,23 +909,27 @@ where
/// If `iter.next()` panicks, all items already yielded by the iterator are
/// dropped.
#[inline]
fn try_collect_into_array<I, T, R, const N: usize>(
const fn try_collect_into_array<I, T, R, const N: usize>(
iter: &mut I,
) -> Result<R::TryType, IntoIter<T, N>>
where
I: Iterator,
I::Item: Try<Output = T, Residual = R>,
R: Residual<[T; N]>,
I: ~const Iterator,
I::Item: ~const Try<Output = T, Residual = R>,
R: ~const Residual<[T; N]>,
T: ~const Destruct,
R::TryType: ~const Try, // #[cfg(bootstrap)]
{
if N == 0 {
// SAFETY: An empty array is always inhabited and has no validity invariants.
return Ok(Try::from_output(unsafe { mem::zeroed() }));
return Ok(Try::from_output(unsafe { MaybeUninit::zeroed().assume_init() }));
}

let mut array = MaybeUninit::uninit_array::<N>();
let mut guard = Guard { array_mut: &mut array, initialized: 0 };

for _ in 0..N {
let mut i = 0;
// FIXME(const_trait_impl): replace with `for` loop
while i < N {
match iter.next() {
Some(item_rslt) => {
let item = match item_rslt.branch() {
Expand All @@ -878,11 +939,13 @@ where
ControlFlow::Continue(elem) => elem,
};

// SAFETY: `guard.initialized` starts at 0, which means push can be called
// at most N times, which this loop does.
// 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()`).
unsafe {
guard.push_unchecked(item);
guard.array_mut.get_unchecked_mut(guard.initialized).write(item);
}
guard.initialized += 1;
}
None => {
let alive = 0..guard.initialized;
Expand All @@ -892,66 +955,35 @@ where
return Err(unsafe { IntoIter::new_unchecked(array, alive) });
}
}
i += 1;
}

mem::forget(guard);
// SAFETY: All elements of the array were populated in the loop above.
let output = unsafe { array.transpose().assume_init() };
let output = unsafe { MaybeUninit::array_assume_init(array) };
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);
/// Returns the next chunk of `N` items from the iterator or errors with an
/// iterator over the remainder. Used for `Iterator::next_chunk`.
#[inline]
#[cfg(not(bootstrap))]
pub(crate) const fn iter_next_chunk<I, const N: usize>(
iter: &mut I,
) -> Result<[I::Item; N], IntoIter<I::Item, N>>
where
I: ~const Iterator,
I::Item: ~const Destruct,
{
let mut map = iter.map(NeverShortCircuit);

// 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),
));
}
match try_collect_into_array(&mut map) {
Ok(NeverShortCircuit(x)) => Ok(x),
Err(e) => Err(e),
}
}

/// Returns the next chunk of `N` items from the iterator or errors with an
/// iterator over the remainder. Used for `Iterator::next_chunk`.
#[inline]
#[cfg(bootstrap)]
pub(crate) fn iter_next_chunk<I, const N: usize>(
iter: &mut I,
) -> Result<[I::Item; N], IntoIter<I::Item, N>>
Expand Down
23 changes: 16 additions & 7 deletions library/core/src/cmp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@

use crate::const_closure::ConstFnMutClosure;
use crate::marker::Destruct;
use crate::marker::StructuralEq;
use crate::marker::StructuralPartialEq;

use self::Ordering::*;
Expand Down Expand Up @@ -280,7 +281,8 @@ pub macro PartialEq($item:item) {
#[doc(alias = "!=")]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_diagnostic_item = "Eq"]
pub trait Eq: PartialEq<Self> {
#[const_trait]
pub trait Eq: ~const PartialEq<Self> {
// this method is used solely by #[deriving] to assert
// that every component of a type implements #[deriving]
// itself, the current deriving infrastructure means doing this
Expand Down Expand Up @@ -330,7 +332,7 @@ pub struct AssertParamIsEq<T: Eq + ?Sized> {
/// let result = 2.cmp(&1);
/// assert_eq!(Ordering::Greater, result);
/// ```
#[derive(Clone, Copy, Eq, Debug, Hash)]
#[derive(Clone, Copy, Debug, Hash)]
#[stable(feature = "rust1", since = "1.0.0")]
#[repr(i8)]
pub enum Ordering {
Expand Down Expand Up @@ -578,6 +580,9 @@ impl Ordering {
}
}

#[stable(feature = "rust1", since = "1.0.0")]
impl StructuralEq for Ordering {}

/// A helper struct for reverse ordering.
///
/// This struct is a helper to be used with functions like [`Vec::sort_by_key`] and
Expand Down Expand Up @@ -760,7 +765,7 @@ impl<T: Clone> Clone for Reverse<T> {
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_diagnostic_item = "Ord"]
#[const_trait]
pub trait Ord: Eq + PartialOrd<Self> {
pub trait Ord: ~const Eq + ~const PartialOrd<Self> {
/// This method returns an [`Ordering`] between `self` and `other`.
///
/// By convention, `self.cmp(&other)` returns the ordering matching the expression
Expand Down Expand Up @@ -888,6 +893,10 @@ impl const PartialEq for Ordering {
}
}

#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_cmp", issue = "92391")]
impl const Eq for Ordering {}

#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_cmp", issue = "92391")]
impl const Ord for Ordering {
Expand Down Expand Up @@ -1227,7 +1236,6 @@ pub const fn min<T: ~const Ord + ~const Destruct>(v1: T, v2: T) -> T {
pub const fn min_by<T, F: ~const FnOnce(&T, &T) -> Ordering>(v1: T, v2: T, compare: F) -> T
where
T: ~const Destruct,
F: ~const Destruct,
{
match compare(&v1, &v2) {
Ordering::Less | Ordering::Equal => v1,
Expand Down Expand Up @@ -1312,7 +1320,6 @@ pub const fn max<T: ~const Ord + ~const Destruct>(v1: T, v2: T) -> T {
pub const fn max_by<T, F: ~const FnOnce(&T, &T) -> Ordering>(v1: T, v2: T, compare: F) -> T
where
T: ~const Destruct,
F: ~const Destruct,
{
match compare(&v1, &v2) {
Ordering::Less | Ordering::Equal => v2,
Expand Down Expand Up @@ -1393,7 +1400,8 @@ mod impls {
macro_rules! eq_impl {
($($t:ty)*) => ($(
#[stable(feature = "rust1", since = "1.0.0")]
impl Eq for $t {}
#[rustc_const_unstable(feature = "const_cmp", issue = "92391")]
impl const Eq for $t {}
)*)
}

Expand Down Expand Up @@ -1517,7 +1525,8 @@ mod impls {
}

#[unstable(feature = "never_type", issue = "35121")]
impl Eq for ! {}
#[rustc_const_unstable(feature = "const_cmp", issue = "92391")]
impl const Eq for ! {}

#[unstable(feature = "never_type", issue = "35121")]
#[rustc_const_unstable(feature = "const_cmp", issue = "92391")]
Expand Down
2 changes: 1 addition & 1 deletion library/core/src/iter/adapters/array_chunks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ where
I: Iterator,
{
#[track_caller]
pub(in crate::iter) fn new(iter: I) -> Self {
pub(in crate::iter) const fn new(iter: I) -> Self {
assert!(N != 0, "chunk size must be non-zero");
Self { iter, remainder: None }
}
Expand Down
25 changes: 15 additions & 10 deletions library/core/src/iter/adapters/by_ref_sized.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use crate::{
const_closure::ConstFnMutClosure,
ops::{NeverShortCircuit, Try},
};
use crate::const_closure::ConstFnMutClosure;
use crate::marker::Destruct;
use crate::ops::{NeverShortCircuit, Try};

/// Like `Iterator::by_ref`, but requiring `Sized` so it can forward generics.
///
Expand All @@ -15,7 +14,7 @@ pub struct ByRefSized<'a, I>(pub &'a mut I);
// to avoid accidentally calling the `&mut Iterator` implementations.

#[unstable(feature = "std_internals", issue = "none")]
impl<I: Iterator> Iterator for ByRefSized<'_, I> {
impl<I: ~const Iterator> const Iterator for ByRefSized<'_, I> {
type Item = I::Item;

#[inline]
Expand All @@ -29,19 +28,25 @@ impl<I: Iterator> Iterator for ByRefSized<'_, I> {
}

#[inline]
fn advance_by(&mut self, n: usize) -> Result<(), usize> {
fn advance_by(&mut self, n: usize) -> Result<(), usize>
where
I::Item: ~const Destruct,
{
I::advance_by(self.0, n)
}

#[inline]
fn nth(&mut self, n: usize) -> Option<Self::Item> {
fn nth(&mut self, n: usize) -> Option<Self::Item>
where
I::Item: ~const Destruct,
{
I::nth(self.0, n)
}

#[inline]
fn fold<B, F>(self, init: B, mut f: F) -> B
where
F: FnMut(B, Self::Item) -> B,
F: ~const FnMut(B, Self::Item) -> B + ~const Destruct,
{
// `fold` needs ownership, so this can't forward directly.
I::try_fold(self.0, init, ConstFnMutClosure::new(&mut f, NeverShortCircuit::wrap_mut_2_imp))
Expand All @@ -51,8 +56,8 @@ impl<I: Iterator> Iterator for ByRefSized<'_, I> {
#[inline]
fn try_fold<B, F, R>(&mut self, init: B, f: F) -> R
where
F: FnMut(B, Self::Item) -> R,
R: Try<Output = B>,
F: ~const FnMut(B, Self::Item) -> R + ~const Destruct,
R: ~const Try<Output = B>,
{
I::try_fold(self.0, init, f)
}
Expand Down
2 changes: 1 addition & 1 deletion library/core/src/iter/adapters/chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ pub struct Chain<A, B> {
b: Option<B>,
}
impl<A, B> Chain<A, B> {
pub(in super::super) fn new(a: A, b: B) -> Chain<A, B> {
pub(in super::super) const fn new(a: A, b: B) -> Chain<A, B> {
Chain { a: Some(a), b: Some(b) }
}
}
Expand Down
2 changes: 1 addition & 1 deletion library/core/src/iter/adapters/cloned.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ pub struct Cloned<I> {
}

impl<I> Cloned<I> {
pub(in crate::iter) fn new(it: I) -> Cloned<I> {
pub(in crate::iter) const fn new(it: I) -> Cloned<I> {
Cloned { it }
}
}
Expand Down
2 changes: 1 addition & 1 deletion library/core/src/iter/adapters/copied.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ pub struct Copied<I> {
}

impl<I> Copied<I> {
pub(in crate::iter) fn new(it: I) -> Copied<I> {
pub(in crate::iter) const fn new(it: I) -> Copied<I> {
Copied { it }
}
}
Expand Down
Loading