about summary refs log tree commit diff
path: root/src/libcore/iter
AgeCommit message (Collapse)AuthorLines
2020-05-26Add remark regarding DoubleEndedIteratorphilipp-0/+26
2020-05-18Add some more `rfold` implementations.Nicholas Nethercote-0/+68
2020-05-18Tweak `partition`, `unzip`, `try_find`.Nicholas Nethercote-7/+7
Many default iterator methods use `try_fold` or `fold`, and these ones can too.
2020-05-18Make `fold` standalone.Nicholas Nethercote-13/+124
`fold` is currently implemented via `try_fold`, but implementing it directly results in slightly less LLVM IR being generated, speeding up compilation of some benchmarks. (And likewise for `rfold`.) The commit adds `fold` implementations to all the iterators that lack one but do have a `try_fold` implementation. Most of these just call the `try_fold` implementation directly.
2020-05-16Rollup merge of #72166 - nnethercote:simpler-slice-Iterator-methods, r=cuviperDylan DPC-1/+1
Simpler slice `Iterator` methods These reduce the amount of LLVM IR generated, helping compile times. r? @cuviper
2020-05-15Auto merge of #69659 - CAD97:step-rework-take-3, r=Amanieubors-171/+411
Rework the std::iter::Step trait Previous attempts: #43127 #62886 #68807 Tracking issue: #42168 This PR reworks the `Step` trait to be phrased in terms of the *successor* and *predecessor* operations. With this, `Step` hopefully has a consistent identity that can have a path towards stabilization. The proposed trait: ```rust /// Objects that have a notion of *successor* and *predecessor* operations. /// /// The *successor* operation moves towards values that compare greater. /// The *predecessor* operation moves towards values that compare lesser. /// /// # Safety /// /// This trait is `unsafe` because its implementation must be correct for /// the safety of `unsafe trait TrustedLen` implementations, and the results /// of using this trait can otherwise be trusted by `unsafe` code to be correct /// and fulful the listed obligations. pub unsafe trait Step: Clone + PartialOrd + Sized { /// Returns the number of *successor* steps required to get from `start` to `end`. /// /// Returns `None` if the number of steps would overflow `usize` /// (or is infinite, or if `end` would never be reached). /// /// # Invariants /// /// For any `a`, `b`, and `n`: /// /// * `steps_between(&a, &b) == Some(n)` if and only if `Step::forward(&a, n) == Some(b)` /// * `steps_between(&a, &b) == Some(n)` if and only if `Step::backward(&a, n) == Some(a)` /// * `steps_between(&a, &b) == Some(n)` only if `a <= b` /// * Corollary: `steps_between(&a, &b) == Some(0)` if and only if `a == b` /// * Note that `a <= b` does _not_ imply `steps_between(&a, &b) != None`; /// this is the case wheen it would require more than `usize::MAX` steps to get to `b` /// * `steps_between(&a, &b) == None` if `a > b` fn steps_between(start: &Self, end: &Self) -> Option<usize>; /// Returns the value that would be obtained by taking the *successor* /// of `self` `count` times. /// /// If this would overflow the range of values supported by `Self`, returns `None`. /// /// # Invariants /// /// For any `a`, `n`, and `m`: /// /// * `Step::forward_checked(a, n).and_then(|x| Step::forward_checked(x, m)) == Step::forward_checked(a, m).and_then(|x| Step::forward_checked(x, n))` /// /// For any `a`, `n`, and `m` where `n + m` does not overflow: /// /// * `Step::forward_checked(a, n).and_then(|x| Step::forward_checked(x, m)) == Step::forward_checked(a, n + m)` /// /// For any `a` and `n`: /// /// * `Step::forward_checked(a, n) == (0..n).try_fold(a, |x, _| Step::forward_checked(&x, 1))` /// * Corollary: `Step::forward_checked(&a, 0) == Some(a)` fn forward_checked(start: Self, count: usize) -> Option<Self>; /// Returns the value that would be obtained by taking the *successor* /// of `self` `count` times. /// /// If this would overflow the range of values supported by `Self`, /// this function is allowed to panic, wrap, or saturate. /// The suggested behavior is to panic when debug assertions are enabled, /// and to wrap or saturate otherwise. /// /// Unsafe code should not rely on the correctness of behavior after overflow. /// /// # Invariants /// /// For any `a`, `n`, and `m`, where no overflow occurs: /// /// * `Step::forward(Step::forward(a, n), m) == Step::forward(a, n + m)` /// /// For any `a` and `n`, where no overflow occurs: /// /// * `Step::forward_checked(a, n) == Some(Step::forward(a, n))` /// * `Step::forward(a, n) == (0..n).fold(a, |x, _| Step::forward(x, 1))` /// * Corollary: `Step::forward(a, 0) == a` /// * `Step::forward(a, n) >= a` /// * `Step::backward(Step::forward(a, n), n) == a` fn forward(start: Self, count: usize) -> Self { Step::forward_checked(start, count).expect("overflow in `Step::forward`") } /// Returns the value that would be obtained by taking the *successor* /// of `self` `count` times. /// /// # Safety /// /// It is undefined behavior for this operation to overflow the /// range of values supported by `Self`. If you cannot guarantee that this /// will not overflow, use `forward` or `forward_checked` instead. /// /// # Invariants /// /// For any `a`: /// /// * if there exists `b` such that `b > a`, it is safe to call `Step::forward_unchecked(a, 1)` /// * if there exists `b`, `n` such that `steps_between(&a, &b) == Some(n)`, /// it is safe to call `Step::forward_unchecked(a, m)` for any `m <= n`. /// /// For any `a` and `n`, where no overflow occurs: /// /// * `Step::forward_unchecked(a, n)` is equivalent to `Step::forward(a, n)` #[unstable(feature = "unchecked_math", reason = "niche optimization path", issue = "none")] unsafe fn forward_unchecked(start: Self, count: usize) -> Self { Step::forward(start, count) } /// Returns the value that would be obtained by taking the *successor* /// of `self` `count` times. /// /// If this would overflow the range of values supported by `Self`, returns `None`. /// /// # Invariants /// /// For any `a`, `n`, and `m`: /// /// * `Step::backward_checked(a, n).and_then(|x| Step::backward_checked(x, m)) == n.checked_add(m).and_then(|x| Step::backward_checked(a, x))` /// * `Step::backward_checked(a, n).and_then(|x| Step::backward_checked(x, m)) == try { Step::backward_checked(a, n.checked_add(m)?) }` /// /// For any `a` and `n`: /// /// * `Step::backward_checked(a, n) == (0..n).try_fold(a, |x, _| Step::backward_checked(&x, 1))` /// * Corollary: `Step::backward_checked(&a, 0) == Some(a)` fn backward_checked(start: Self, count: usize) -> Option<Self>; /// Returns the value that would be obtained by taking the *predecessor* /// of `self` `count` times. /// /// If this would overflow the range of values supported by `Self`, /// this function is allowed to panic, wrap, or saturate. /// The suggested behavior is to panic when debug assertions are enabled, /// and to wrap or saturate otherwise. /// /// Unsafe code should not rely on the correctness of behavior after overflow. /// /// # Invariants /// /// For any `a`, `n`, and `m`, where no overflow occurs: /// /// * `Step::backward(Step::backward(a, n), m) == Step::backward(a, n + m)` /// /// For any `a` and `n`, where no overflow occurs: /// /// * `Step::backward_checked(a, n) == Some(Step::backward(a, n))` /// * `Step::backward(a, n) == (0..n).fold(a, |x, _| Step::backward(x, 1))` /// * Corollary: `Step::backward(a, 0) == a` /// * `Step::backward(a, n) <= a` /// * `Step::forward(Step::backward(a, n), n) == a` fn backward(start: Self, count: usize) -> Self { Step::backward_checked(start, count).expect("overflow in `Step::backward`") } /// Returns the value that would be obtained by taking the *predecessor* /// of `self` `count` times. /// /// # Safety /// /// It is undefined behavior for this operation to overflow the /// range of values supported by `Self`. If you cannot guarantee that this /// will not overflow, use `backward` or `backward_checked` instead. /// /// # Invariants /// /// For any `a`: /// /// * if there exists `b` such that `b < a`, it is safe to call `Step::backward_unchecked(a, 1)` /// * if there exists `b`, `n` such that `steps_between(&b, &a) == Some(n)`, /// it is safe to call `Step::backward_unchecked(a, m)` for any `m <= n`. /// /// For any `a` and `n`, where no overflow occurs: /// /// * `Step::backward_unchecked(a, n)` is equivalent to `Step::backward(a, n)` #[unstable(feature = "unchecked_math", reason = "niche optimization path", issue = "none")] unsafe fn backward_unchecked(start: Self, count: usize) -> Self { Step::backward(start, count) } } ``` Note that all of these are associated functions and not callable via method syntax; the calling syntax is always `Step::forward(start, n)`. This version of the trait additionally changes the stepping functions to talk their arguments by value. As opposed to previous attempts which provided a "step by one" method directly, this version of the trait only exposes "step by n". There are a few reasons for this: - `Range*`, the primary consumer of `Step`, assumes that the "step by n" operation is cheap. If a single step function is provided, it will be a lot more enticing to implement "step by n" as n repeated calls to "step by one". While this is not strictly incorrect, this behavior would be surprising for anyone used to using `Range<{primitive integer}>`. - With a trivial default impl, this can be easily added backwards-compatibly later. - The debug-wrapping "step by n" needs to exist for `RangeFrom` to be consistent between "step by n" and "step by one" operation. (Note: the behavior is not changed by this PR, but making the behavior consistent is made tenable by this PR.) Three "kinds" of step are provided: `_checked`, which returns an `Option` indicating attempted overflow; (unsuffixed), which provides "safe overflow" behavior (is allowed to panic, wrap, or saturate, depending on what is most convenient for a given type); and `_unchecked`, which is a version which assumes overflow does not happen. Review is appreciated to check that: - The invariants as described on the `Step` functions are enough to specify the "common sense" consistency for successor/predecessor. - Implementation of `Step` functions is correct in the face of overflow and the edges of representable integers. - Added tests of `Step` functions are asserting the correct behavior (and not just the implemented behavior).
2020-05-14improve step_integer_impls macroCAD97-29/+6
2020-05-13Improve Step::forward/backward for optimizationCAD97-14/+12
The previous definition did not optimize down to a single add operation, but this version does appear to.
2020-05-13Improve comments in iter::StepCAD97-3/+3
2020-05-13Change `Iterator::nth` to use `self.next()` in a `while` loop.Nicholas Nethercote-1/+1
Currently it uses `for x in self`, which seems dubious within an iterator method. Furthermore, `self.next()` is used in all the other iterator methods.
2020-04-26Use min_specialization in liballocMatthew Jasper-0/+2
- Remove a type parameter from `[A]RcFromIter`. - Remove an implementation of `[A]RcFromIter` that didn't actually specialize anything. - Remove unused implementation of `IsZero` for `Option<&mut T>`. - Change specializations of `[A]RcEqIdent` to use a marker trait version of `Eq`. - Remove `BTreeClone`. I couldn't find a way to make this work with `min_specialization`. - Add `rustc_unsafe_specialization_marker` to `Copy` and `TrustedLen`.
2020-04-25Bump rustfmt to most recently shippedMark Rousskov-1/+1
2020-04-24Rollup merge of #71492 - LeSeulArtichaut:document-unsafe-2, r=Mark-SimulacrumDylan DPC-2/+8
Document unsafety in core::{panicking, alloc::layout, hint, iter::adapters::zip} Helps with #66219. r? @Mark-Simulacrum do you want to continue reading safety comments? :D
2020-04-24Document unsafety in `core::{panicking, alloc::layout, hint, ↵LeSeulArtichaut-2/+8
iter::adapters::zip}`
2020-04-23Rollup merge of #71404 - cuviper:chain-unfused, r=scottmcmDylan DPC-10/+22
Don't fuse Chain in its second iterator Only the "first" iterator is actually set `None` when exhausted, depending on whether you iterate forward or backward. This restores behavior similar to the former `ChainState`, where it would transition from `Both` to `Front`/`Back` and only continue from that side. However, if you mix directions, then this may still set both sides to `None`, totally fusing the iterator. Fixes #71375 r? @scottmcm
2020-04-21Don't fuse Chain in its second iteratorJosh Stone-10/+22
Only the "first" iterator is actually set `None` when exhausted, depending on whether you iterate forward or backward. This restores behavior similar to the former `ChainState`, where it would transition from `Both` to `Front`/`Back` and only continue from that side. However, if you mix directions, then this may still set both sides to `None`, totally fusing the iterator.
2020-04-20Stop accessing module level int consts via crate::<Ty>Linus Färnstrand-3/+0
2020-04-17Rollup merge of #71220 - cuviper:std_or_patterns, r=Mark-SimulacrumDylan DPC-2/+2
Dogfood or_patterns in the standard library We can start using `or_patterns` in the standard library as a step toward stabilization. cc #54883 @Centril
2020-04-17Rollup merge of #70910 - rakshith-ravi:master, r=cuviperDylan DPC-63/+244
Hides default fns inside Fuse impl to avoid exposing it to any crate Fixes #70796 @cuviper I've added some default, private traits to do the job for us. If required, I can expose them to a specific visibility if you want to call these functions for #70332 r? @cuviper
2020-04-16Dogfood or_patterns in the standard libraryJosh Stone-2/+2
2020-04-16Inlined everything into a single trait and trait implRakshith Ravi-126/+141
2020-04-10Added comments.Rakshith Ravi-21/+16
Removed unnecessarry empty impls. Moved code to organise it better
2020-04-08Adjust Step::forward_checked docs for large typesCAD97-2/+5
Co-Authored-By: Nadrieril Feneanar <nadrieril@users.noreply.github.com>
2020-04-08Redesign the Step traitCAD97-172/+434
2020-04-08Added FuseIteratorImpl, FustDoubleEndedIteratorImpl and ↵Rakshith Ravi-79/+250
FuseExactSizeIteratorImpl to avoid exposing default functions outside of the current crate.
2020-04-07Avoid extra &mut in Chain::fold and try_foldJosh Stone-2/+2
2020-04-07Reduce callsites in Chain::last()Josh Stone-11/+10
2020-04-07Reduce callsites in Chain::count()Josh Stone-6/+9
2020-04-07Implement Chain with Option fusesJosh Stone-149/+106
The iterators are now "fused" with `Option` so we don't need separate state to track which part is already exhausted, and we may also get niche layout for `None`. We don't use the real `Fuse` adapter because its specialization for `FusedIterator` unconditionally descends into the iterator, and that could be expensive to keep revisiting stuff like nested chains. It also hurts compiler performance to add more iterator layers to `Chain`.
2020-04-06Rollup merge of #70750 - cuviper:direct-fuse, r=scottmcmMazdak Farrokhzad-74/+63
Match options directly in the Fuse implementation Rather than using `as_ref()`, `as_mut()`, and `?`, we can use `match` directly to save a lot of generated code. This was mentioned as a possibility in https://github.com/rust-lang/rust/pull/70366#issuecomment-603462546, and I found that it had a very large impact on #70332 using `Fuse` within `Chain`. Let's evaluate this change on its own first.
2020-04-03Use a macro to expand the specialized FuseJosh Stone-41/+23
2020-04-03Open-code Fuse's Option matchesJosh Stone-35/+42
2020-04-03Replace float module consts with assoc consts in documentationLinus Färnstrand-3/+3
2020-04-03Replace max/min_value() with MAX/MIN assoc constsLinus Färnstrand-1/+1
2020-03-27remove unused importdylan_DPC-1/+0
2020-03-27simplify testdylan_DPC-4/+1
2020-03-26fix docsdylan_DPC-2/+5
2020-03-26Add fold_selfNathan West-16/+40
- Added `Iterator::fold_first`, which is like `fold`, but uses the first element in the iterator as the initial accumulator - Includes doc and doctest - Rebase commit; see #65222 for details Co-Authored-By: Tim Vermeulen <tvermeulen@me.com>
2020-03-25impl TrustedRandomAccess for Fuse without FusedIteratorJosh Stone-2/+6
2020-03-24Implement Fuse with OptionJosh Stone-255/+340
The former `done` flag was roughly similar to an `Option` tag, but left the possibity of misuse. By using a real `Option`, we can set `None` when the iterator is exhausted, removing any way to call it again. We also allow niche layout this way, so the `Fuse` may be smaller. The `FusedIterator` specialization does want to ignore the possibility of exhaustion though, so it uses `unsafe { intrinsics::unreachable() }` to optimize that branch away. The entire `Fuse` implementation is now isolated in its own module to contain that unsafety.
2020-03-22Auto merge of #68820 - WaffleLapkin:remove_finished_from_map_while, ↵bors-57/+32
r=LukasKalbertodt Remove `finished` flag from `MapWhile` This PR removes `finished` flag from `MapWhile` as been proposed in https://github.com/rust-lang/rust/pull/66577#discussion_r370958025. This also resolves open questions of the tracking issue (#68537): - `MapWhile` can't implement both + `DoubleEndedIterator` (discussed in https://github.com/rust-lang/rust/pull/66577#discussion_r370947990 and following comments) + `FusedIterator` (this pr removes `finished` flag, so `MapWhile` isn't fused anymore) - Debug output (this pr removes `finished` flag, so there is no question in including it in debug output) r? @Mark-Simulacrum
2020-03-21slightly change the `Iterator::map_while` docsWaffle-14/+4
2020-03-18Auto merge of #68915 - timvermeulen:non_fused_iter, r=Amanieubors-9/+18
Fix bugs in Peekable and Flatten when using non-fused iterators I fixed a couple of bugs with regard to the `Peekable` and `Flatten`/`FlatMap` iterators when the underlying iterator isn't fused. For testing, I also added a `NonFused` iterator wrapper that panics when `next` or `next_back` is called on an iterator that has returned `None` before, which will hopefully make it easier to spot these mistakes in the future. ### Peekable `Peekable::next_back` was implemented as ```rust self.iter.next_back().or_else(|| self.peeked.take().and_then(|x| x)) ``` which is incorrect because when the `peeked` field is `Some(None)`, then `None` has already been returned from the inner iterator and what it returns from `next_back` can no longer be relied upon. `test_peekable_non_fused` tests this. ### Flatten When a `FlattenCompat` instance only has a `backiter` remaining (i.e. `self.frontiter` is `None` and `self.iter` is empty), then `next` will call `self.iter.next()` every time, so the `iter` field needs to be fused. I fixed it by giving it the type `Fuse<I>` instead of `I`, I think this is the only way to fix it. `test_flatten_non_fused_outer` tests this. Furthermore, previously `FlattenCompat::next` did not set `self.frontiter` to `None` after it returned `None`, which is incorrect when the inner iterator type isn't fused. I just delegated it to `try_fold` because that already handles it correctly. `test_flatten_non_fused_inner` tests this. r? @scottmcm
2020-03-17Fix FlattenCompat::{next, next_back}Tim Vermeulen-4/+6
2020-03-11Rollup merge of #69625 - Stebalien:feat/iter-copy-specialize, r=KodrAusMazdak Farrokhzad-0/+12
Implement nth, last, and count for iter::Copied Implement nth, last and count for iter::Copied.
2020-03-10Rollup merge of #69514 - GuillaumeGomez:remove-spotlight, r=kinnisonMazdak Farrokhzad-1/+0
Remove spotlight I had a few comments saying that this feature was at best misunderstood or not even used so I decided to organize a poll about on [twitter](https://twitter.com/imperioworld_/status/1232769353503956994). After 87 votes, the result is very clear: it's not useful. Considering the amount of code we have just to run it, I think it's definitely worth it to remove it. r? @kinnison cc @ollie27
2020-03-03Rollup merge of #69621 - matthiaskrgr:q, r=petrochenkovDylan DPC-6/+2
use question mark operator in a few places.
2020-03-03use question mark operator in a few places.Matthias Krüger-6/+2
2020-03-03Rollup merge of #69213 - LeSeulArtichaut:improve-doc-iter, r=steveklabnikYuki Okushi-2/+5
Improve documentation on iterators length Attempts to resolve #66491. @the8472 does this help? r? @steveklabnik
2020-03-02Apply suggestions from code reviewLeSeulArtichaut-2/+3