about summary refs log tree commit diff
path: root/src/libcore/tests
AgeCommit message (Collapse)AuthorLines
2020-07-27mv std libs to library/mark-14441/+0
2020-07-25Auto merge of #74510 - LukasKalbertodt:fix-range-from-index-panic, ↵bors-1/+1
r=hanna-kruppe Fix panic message when `RangeFrom` index is out of bounds Before, the `Range` method was called with `end = slice.len()`. Unfortunately, because `Range::index` first checks the order of the indices (start has to be smaller than end), an out of bounds index leads to `core::slice::slice_index_order_fail` being called. This prints the message 'slice index starts at 27 but ends at 10', which is worse than 'index 27 out of range for slice of length 10'. This is not only useful to normal users reading panic messages, but also for people inspecting assembly and being confused by `slice_index_order_fail` calls. You can see the produced assembly [here](https://rust.godbolt.org/z/GzMGWf) and try on Playground [here](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=aada5996b2f3848075a6d02cf4055743). (By the way. this is only about which panic function is called; I'm pretty sure it does not improve anything about performance).
2020-07-24Rollup merge of #74367 - Neutron3529:patch-1, r=nagisaManish Goregaokar-1/+57
Rearrange the pipeline of `pow` to gain efficiency The check of the `exp` parameter seems useless if we execute the while-loop more than once. The original implementation of `pow` function using one more comparison if the `exp==0` and may break the pipeline of the cpu, which may generate a slower code. The performance gap between the old and the new implementation may be small, but IMO, at least the newer one looks more beautiful. --- bench prog: ``` #![feature(test)] extern crate test; #[macro_export]macro_rules! timing{ ($a:expr)=>{let time=std::time::Instant::now();{$a;}print!("{:?} ",time.elapsed())}; ($a:expr,$b:literal)=>{let time=std::time::Instant::now();let mut a=0;for _ in 0..$b{a^=$a;}print!("{:?} {} ",time.elapsed(),a)} } #[inline] pub fn pow_rust(x:i64, mut exp: u32) -> i64 { let mut base = x; let mut acc = 1; while exp > 1 { if (exp & 1) == 1 { acc = acc * base; } exp /= 2; base = base * base; } if exp == 1 { acc = acc * base; } acc } #[inline] pub fn pow_new(x:i64, mut exp: u32) -> i64 { if exp==0{ 1 }else{ let mut base = x; let mut acc = 1; while exp > 1 { if (exp & 1) == 1 { acc = acc * base; } exp >>= 1; base = base * base; } acc * base } } fn main(){ let a=2i64; let b=1_u32; println!(); timing!(test::black_box(a).pow(test::black_box(b)),100000000); timing!(pow_new(test::black_box(a),test::black_box(b)),100000000); timing!(pow_rust(test::black_box(a),test::black_box(b)),100000000); println!(); timing!(test::black_box(a).pow(test::black_box(b)),100000000); timing!(pow_new(test::black_box(a),test::black_box(b)),100000000); timing!(pow_rust(test::black_box(a),test::black_box(b)),100000000); println!(); timing!(test::black_box(a).pow(test::black_box(b)),100000000); timing!(pow_new(test::black_box(a),test::black_box(b)),100000000); timing!(pow_rust(test::black_box(a),test::black_box(b)),100000000); println!(); timing!(test::black_box(a).pow(test::black_box(b)),100000000); timing!(pow_new(test::black_box(a),test::black_box(b)),100000000); timing!(pow_rust(test::black_box(a),test::black_box(b)),100000000); println!(); timing!(test::black_box(a).pow(test::black_box(b)),100000000); timing!(pow_new(test::black_box(a),test::black_box(b)),100000000); timing!(pow_rust(test::black_box(a),test::black_box(b)),100000000); println!(); timing!(test::black_box(a).pow(test::black_box(b)),100000000); timing!(pow_new(test::black_box(a),test::black_box(b)),100000000); timing!(pow_rust(test::black_box(a),test::black_box(b)),100000000); println!(); timing!(test::black_box(a).pow(test::black_box(b)),100000000); timing!(pow_new(test::black_box(a),test::black_box(b)),100000000); timing!(pow_rust(test::black_box(a),test::black_box(b)),100000000); println!(); timing!(test::black_box(a).pow(test::black_box(b)),100000000); timing!(pow_new(test::black_box(a),test::black_box(b)),100000000); timing!(pow_rust(test::black_box(a),test::black_box(b)),100000000); println!(); } ``` bench in my laptop: ``` neutron@Neutron:/me/rust$ rc commit.rs rustc commit.rs && ./commit 3.978419716s 0 4.079765171s 0 3.964630622s 0 3.997127013s 0 4.260304804s 0 3.997638211s 0 3.963195544s 0 4.11657718s 0 4.176054164s 0 3.830128579s 0 3.980396122s 0 3.937258567s 0 3.986055948s 0 4.127804162s 0 4.018943411s 0 4.185568857s 0 4.217512517s 0 3.98313603s 0 3.863018225s 0 4.030447988s 0 3.694878237s 0 4.206987927s 0 4.137608047s 0 4.115564664s 0 neutron@Neutron:/me/rust$ rc commit.rs -O rustc commit.rs -O && ./commit 162.111993ms 0 165.107125ms 0 166.26924ms 0 175.20479ms 0 205.062565ms 0 176.278791ms 0 174.408975ms 0 166.526899ms 0 201.857604ms 0 146.190062ms 0 168.592821ms 0 154.61411ms 0 199.678912ms 0 168.411598ms 0 162.129996ms 0 147.420765ms 0 209.759326ms 0 154.807907ms 0 165.507134ms 0 188.476239ms 0 157.351524ms 0 121.320123ms 0 126.401229ms 0 114.86428ms 0 ```
2020-07-23Rearrange the pipeline of `pow` to gain efficiencyNeutron3529-1/+57
The check of the `exp` parameter seems useless if we execute the while-loop more than once. The original implementation of `pow` function using one more comparison if the `exp==0` and may break the pipeline of the cpu, which may generate a slower code. The performance gap between the old and the new implementation may be small, but IMO, at least the newer one looks more beautiful. --- bench prog: ``` extern crate test; ($a:expr)=>{let time=std::time::Instant::now();{$a;}print!("{:?} ",time.elapsed())}; ($a:expr,$b:literal)=>{let time=std::time::Instant::now();let mut a=0;for _ in 0..$b{a^=$a;}print!("{:?} {} ",time.elapsed(),a)} } pub fn pow_rust(x:i64, mut exp: u32) -> i64 { let mut base = x; let mut acc = 1; while exp > 1 { if (exp & 1) == 1 { acc = acc * base; } exp /= 2; base = base * base; } if exp == 1 { acc = acc * base; } acc } pub fn pow_new(x:i64, mut exp: u32) -> i64 { if exp==0{ 1 }else{ let mut base = x; let mut acc = 1; while exp > 1 { if (exp & 1) == 1 { acc = acc * base; } exp >>= 1; base = base * base; } acc * base } } fn main(){ let a=2i64; let b=1_u32; println!(); timing!(test::black_box(a).pow(test::black_box(b)),100000000); timing!(pow_new(test::black_box(a),test::black_box(b)),100000000); timing!(pow_rust(test::black_box(a),test::black_box(b)),100000000); println!(); timing!(test::black_box(a).pow(test::black_box(b)),100000000); timing!(pow_new(test::black_box(a),test::black_box(b)),100000000); timing!(pow_rust(test::black_box(a),test::black_box(b)),100000000); println!(); timing!(test::black_box(a).pow(test::black_box(b)),100000000); timing!(pow_new(test::black_box(a),test::black_box(b)),100000000); timing!(pow_rust(test::black_box(a),test::black_box(b)),100000000); println!(); timing!(test::black_box(a).pow(test::black_box(b)),100000000); timing!(pow_new(test::black_box(a),test::black_box(b)),100000000); timing!(pow_rust(test::black_box(a),test::black_box(b)),100000000); println!(); timing!(test::black_box(a).pow(test::black_box(b)),100000000); timing!(pow_new(test::black_box(a),test::black_box(b)),100000000); timing!(pow_rust(test::black_box(a),test::black_box(b)),100000000); println!(); timing!(test::black_box(a).pow(test::black_box(b)),100000000); timing!(pow_new(test::black_box(a),test::black_box(b)),100000000); timing!(pow_rust(test::black_box(a),test::black_box(b)),100000000); println!(); timing!(test::black_box(a).pow(test::black_box(b)),100000000); timing!(pow_new(test::black_box(a),test::black_box(b)),100000000); timing!(pow_rust(test::black_box(a),test::black_box(b)),100000000); println!(); timing!(test::black_box(a).pow(test::black_box(b)),100000000); timing!(pow_new(test::black_box(a),test::black_box(b)),100000000); timing!(pow_rust(test::black_box(a),test::black_box(b)),100000000); println!(); } ``` bench in my laptop: ``` neutron@Neutron:/me/rust$ rc commit.rs rustc commit.rs && ./commit 3.978419716s 0 4.079765171s 0 3.964630622s 0 3.997127013s 0 4.260304804s 0 3.997638211s 0 3.963195544s 0 4.11657718s 0 4.176054164s 0 3.830128579s 0 3.980396122s 0 3.937258567s 0 3.986055948s 0 4.127804162s 0 4.018943411s 0 4.185568857s 0 4.217512517s 0 3.98313603s 0 3.863018225s 0 4.030447988s 0 3.694878237s 0 4.206987927s 0 4.137608047s 0 4.115564664s 0 neutron@Neutron:/me/rust$ rc commit.rs -O rustc commit.rs -O && ./commit 162.111993ms 0 165.107125ms 0 166.26924ms 0 175.20479ms 0 205.062565ms 0 176.278791ms 0 174.408975ms 0 166.526899ms 0 201.857604ms 0 146.190062ms 0 168.592821ms 0 154.61411ms 0 199.678912ms 0 168.411598ms 0 162.129996ms 0 147.420765ms 0 209.759326ms 0 154.807907ms 0 165.507134ms 0 188.476239ms 0 157.351524ms 0 121.320123ms 0 126.401229ms 0 114.86428ms 0 ``` delete an unnecessary semicolon... Sorry for the typo. delete trailing whitespace Sorry, too.. Sorry for the missing... I checked all the implementations, and finally found that there is one function that does not check whether `exp == 0` add extra tests add extra tests. finished adding the extra tests to prevent further typo add pow(2) to negative exp add whitespace. add whitespace add whitespace delete extra line
2020-07-19Fix panic message when `RangeFrom` index is out of boundsLukas Kalbertodt-1/+1
Before, the `Range` method was called with `end = slice.len()`. Unfortunately, because `Range::index` first checks the order of the indices (start has to be smaller than end), an out of bounds index leads to `core::slice::slice_index_order_fail` being called. This prints the message 'slice index starts at 27 but ends at 10', which is worse than 'index 27 out of range for slice of length 10'. This is not only useful to normal users reading panic messages, but also for people inspecting assembly and being confused by `slice_index_order_fail` calls.
2020-07-17integrate Lazy into std layoutAshley Mannix-0/+126
This commit refactors the initial implementation to fit into std and makes some other changes: - use MaybeUninit internally in SyncOnceCell - correctly impl Drop for lazy::Once - port Lazy::take from once_cell from: https://github.com/matklad/once_cell/pull/100 Co-Authored-By: Paul Dicker <pitdicker@users.noreply.github.com>
2020-07-11Rollup merge of #74066 - thomcc:optimize-is-ascii, r=nagisaManish Goregaokar-0/+56
Optimize is_ascii for str and [u8]. This optimizes the `is_ascii` function for `[u8]` and `str`. I've been surprised this wasn't done for a while, so I just did it. Benchmarks comparing before/after look like: ``` test ascii::long_readonly::is_ascii_slice_iter_all ... bench: 174 ns/iter (+/- 79) = 40172 MB/s test ascii::long_readonly::is_ascii_slice_libcore ... bench: 16 ns/iter (+/- 5) = 436875 MB/s test ascii::medium_readonly::is_ascii_slice_iter_all ... bench: 12 ns/iter (+/- 3) = 2666 MB/s test ascii::medium_readonly::is_ascii_slice_libcore ... bench: 2 ns/iter (+/- 0) = 16000 MB/s test ascii::short_readonly::is_ascii_slice_iter_all ... bench: 3 ns/iter (+/- 0) = 2333 MB/s test ascii::short_readonly::is_ascii_slice_libcore ... bench: 4 ns/iter (+/- 0) = 1750 MB/s ``` (Taken on a x86_64 macbook 2.9 GHz Intel Core i9 with 6 cores) Where `is_ascii_slice_iter_all` is the old version, and `is_ascii_slice_libcore` is the new. I tried to document the code well, so hopefully it's understandable. It has fairly exhaustive tests ensuring size/align doesn't get violated -- because `miri` doesn't really help a lot for this sort of code right now, I tried to `debug_assert` all the safety invariants I'm depending on. (Of course, none of them are required for correctness or soundness -- just allows us to test that this sort of pointer manipulation is sound and such). Anyway, thanks. Let me know if you have questions/desired changes.
2020-07-10Rollup merge of #73887 - DutchGhost:master, r=oli-obkManish Goregaokar-1/+0
stabilize const mem::forget Stabilizes const `mem::forget` as implemented in https://github.com/rust-lang/rust/pull/69617 and tracked in https://github.com/rust-lang/rust/issues/69616. Closes https://github.com/rust-lang/rust/issues/69616
2020-07-05Optimize is_ascii for &str and &[u8]Thom Chiovoloni-0/+56
2020-06-30Deny unsafe ops in unsafe fns, part 3LeSeulArtichaut-0/+2
2020-06-30stabilize const mem::forgetDodo-1/+0
2020-06-29Auto merge of #73032 - yoshuawuyts:stabilize-leading_trailing_ones, r=Amanieubors-1/+0
stabilize leading_trailing_ones This PR stabilizes the `leading_trailing_ones` feature. It's been available on nightly since the start of the year, and hasn't had any issues since. It seems unlikely we'll want to change this, so following up on @djc's suggestion in https://github.com/rust-lang/rust/issues/57969#issuecomment-638405264 I'd like to put forward this PR to stabilize the feature and make it part of `1.46.0`. Thanks! cc/ @djc @rust-lang/libs
2020-06-28Rollup merge of #73577 - VillSnow:master, r=AmanieuManish Goregaokar-0/+41
Add partition_point Add partition_point in C++. Although existing binary_search in rust does not suitable when the slice has multiple hits, this function returns exact point of partition. The definition of this function is very clear and able to accept general matter, therefore you can easily get index which you want like lower/upper_bound. https://github.com/rust-lang/rfcs/issues/2184
2020-06-25Auto merge of #72717 - poliorcetics:try-from-int-to-nzint, r=dtolnaybors-0/+19
Add TryFrom<{int}> for NonZero{int} Adds `TryFrom<{int}> for NonZero{int}`. It uses the existing `NonZero{int}::new()` and `Option::ok_or()` functions, meaning the checks are not repeated. I also added tests, I tried to follow the convention I saw in the test file. I also used `#[stable(feature = "nzint_try_from_int_conv", since = "1.46.0")]`, but I have no idea if the feature/version are correctly named or even correct.
2020-06-22add: testsVillSnow-0/+41
2020-06-19Rollup merge of #71420 - RalfJung:specialization-incomplete, r=matthewjasperManish Goregaokar-1/+1
Specialization is unsound As discussed in https://github.com/rust-lang/rust/issues/31844#issuecomment-617013949, it might be a good idea to warn users of specialization that the feature they are using is unsound. I also expanded the "incomplete feature" warning to link the user to the tracking issue.
2020-06-18Rollup merge of #72628 - MikailBag:array-default-tests, r=shepmasterManish Goregaokar-0/+49
Add tests for 'impl Default for [T; N]' Related: #71690. This pull request adds two tests: - Even it T::default() panics, no leaks occur. - [T; 0] is Default even if T is not. I believe at some moment `Default` impl for arrays will be rewritten to use const generics instead of macros, and these tests will help to prevent behavior changes.
2020-06-16libcore tests: use min_specializationRalf Jung-1/+1
2020-06-10Migrate to numeric associated constsLzu Tao-19/+19
2020-06-08Fix test call for error caseAlexis Bourget-9/+9
2020-06-08Correctly format the tests and import TryFromAlexis Bourget-1/+2
2020-06-05stabilize leading_trailing_onesYoshua Wuyts-1/+0
2020-05-31Miri tests: skip parts of test_char_rangeRalf Jung-2/+5
2020-05-29Auto merge of #72756 - RalfJung:rollup-tbjmtx2, r=RalfJungbors-0/+12
Rollup of 9 pull requests Successful merges: - #67460 (Tweak impl signature mismatch errors involving `RegionKind::ReVar` lifetimes) - #71095 (impl From<[T; N]> for Box<[T]>) - #71500 (Make pointer offset methods/intrinsics const) - #71804 (linker: Support `-static-pie` and `-static -shared`) - #71862 (Implement RFC 2585: unsafe blocks in unsafe fn) - #72103 (borrowck `DefId` -> `LocalDefId`) - #72407 (Various minor improvements to Ipv6Addr::Display) - #72413 (impl Step for char (make Range*<char> iterable)) - #72439 (NVPTX support for new asm!) Failed merges: r? @ghost
2020-05-29Rollup merge of #72310 - jyn514:peekable-next-if, r=dtolnayDylan DPC-0/+25
Add Peekable::next_if Prior art: `rust_analyzer` uses [`Parser::eat`](https://github.com/rust-analyzer/rust-analyzer/blob/50f4ae798b7c54d417ee88455b87fd0477473150/crates/ra_parser/src/parser.rs#L94), which is `next_if` specialized to `|y| self.next_if(|x| x == y)`. Basically every other parser I've run into in Rust has an equivalent of `Parser::eat`; see for example - [cranelift](https://github.com/bytecodealliance/wasmtime/blob/94190d57244b26baf36629c88104b0ba516510cf/cranelift/reader/src/parser.rs#L498) - [rcc](https://github.com/jyn514/rcc/blob/a8159c3904a0c950fbba817bf9109023fad69033/src/parse/mod.rs#L231) - [crunch](https://github.com/Kixiron/crunch-lang/blob/8521874fab8a7d62bfa7dea8bd1da94b63e31be8/crates/crunch-parser/src/parser/mod.rs#L213-L241) Possible extensions: A specialization of `next_if` to using `Eq::eq`. The only difficulty here is the naming - maybe `next_if_eq`? Alternatives: - Instead of `func: impl FnOnce(&I::Item) -> bool`, use `func: impl FnOnce(I::Item) -> Option<I::Item>`. This has the advantage that `func` can move the value if necessary, but means that there is no guarantee `func` will return the same value it was given. - Instead of `fn next_if(...) -> Option<I::Item>`, use `fn next_if(...) -> bool`. This makes the common case of `iter.next_if(f).is_some()` easier, but makes the unusual case impossible. Bikeshedding on naming: - `next_if` could be renamed to `consume_if` (to match `eat`, but a little more formally) - `next_if_eq` could be renamed to `consume`. This is more concise but less self-explanatory if you haven't written a lot of parsers. - Both of the above, but with `consume` replaced by `eat`.
2020-05-29Added tests for the implementationsAlexis Bourget-1/+19
2020-05-28Skip leak test on targets without panic=unwindMikail Bagishov-0/+8
2020-05-28FIx off-by-one in char::steps_betweenCAD97-0/+2
2020-05-26Add Peekable::next_ifJoshua Nelson-0/+25
Prior art: `rust_analyzer` uses [`Parser::eat`](https://github.com/rust-analyzer/rust-analyzer/blob/50f4ae798b7c54d417ee88455b87fd0477473150/crates/ra_parser/src/parser.rs#L94), which is `next_if` specialized to `|y| next_if(|x| x == y)`. Basically every other parser I've run into in Rust has an equivalent of Parser::eat; see for example - [cranelift](https://github.com/bytecodealliance/wasmtime/blob/94190d57244b26baf36629c88104b0ba516510cf/cranelift/reader/src/parser.rs#L498) - [rcc](https://github.com/jyn514/rcc/blob/a8159c3904a0c950fbba817bf9109023fad69033/src/parse/mod.rs#L231) - [crunch](https://github.com/Kixiron/crunch-lang/blob/8521874fab8a7d62bfa7dea8bd1da94b63e31be8/crates/crunch-parser/src/parser/mod.rs#L213-L241)
2020-05-27Add tests for 'impl Default for [T; N]'Mikail Bagishov-0/+41
2020-05-21Add a test for char rangesCAD97-0/+10
2020-05-19Rollup merge of #71886 - t-rapp:tr-saturating-funcs, r=dtolnayDylan DPC-1/+0
Stabilize saturating_abs and saturating_neg Stabilizes the following signed integer functions with saturation mechanics: * saturating_abs() * saturating_neg() Closes #59983
2020-05-15Auto merge of #69659 - CAD97:step-rework-take-3, r=Amanieubors-27/+95
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-04Stabilize saturating_abs and saturating_negTobias Rapp-1/+0
Stabilizes the following signed integer functions with saturation mechanics: * saturating_abs() * saturating_neg() Closes #59983
2020-04-25Rollup merge of #69813 - thomcc:nonzero-bitor, r=AmanieuDylan DPC-0/+35
Implement BitOr and BitOrAssign for the NonZero integer types This provides overloaded operators for `NonZero$Int | NonZero$Int`, `NonZero$Int | $Int`, and `$Int | NonZero$Int`. It also provides `BitOrAssign` where `self` is `NonZero$Int`, for symmetry. It's a pretty small conceptual addition, but is good becasue but avoids a case where the operation is obviously sound, but you'd otherwise need unsafe to do it. In crates trying to minimize `unsafe` usage, this is unfortunate and makes working with `NonZero` types often not worth it, even if the operations you're doing are clearly sound. I've marked these as stable as I've been told in the past that trait impls are automatically stable. I'm happy to change it to unstable if this wasn't correct information. I'm not entirely confident what version I should have put down, so I followed https://www.whatrustisit.com. Hopefully it's correct for this. Apologies in advance if this has come up before, but I couldn't find it.
2020-04-24Rollup merge of #71476 - RalfJung:miri-test-sizes, r=kennytmDylan DPC-30/+16
more compact way to adjust test sizes for Miri Inspired by @dtolnay
2020-04-23libcore: more compact way to adjust test sizes for MiriRalf Jung-30/+16
2020-04-21Don't fuse Chain in its second iteratorJosh Stone-25/+40
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-08Adjust Step::forward_checked docs for large typesCAD97-10/+2
Co-Authored-By: Nadrieril Feneanar <nadrieril@users.noreply.github.com>
2020-04-08Redesign the Step traitCAD97-29/+105
2020-04-06Use integer assoc consts in libcoreLinus Färnstrand-5/+5
2020-04-06Use assoc float consts in libcoreLinus Färnstrand-26/+18
2020-04-05Stop importing int/float modules in libcoreLinus Färnstrand-37/+23
2020-03-21Rollup merge of #70038 - DutchGhost:const-forget-tests, r=RalfJungMazdak Farrokhzad-18/+0
Remove the call that makes miri fail Fixes the concern raised in https://github.com/rust-lang/rust/pull/69645/files#r392884274 cc @RalfJung
2020-03-18Move the const-forget test into ui testsDutchGhost-18/+0
2020-03-18Auto merge of #68915 - timvermeulen:non_fused_iter, r=Amanieubors-0/+72
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-17Add testsTim Vermeulen-0/+72
2020-03-16rather than removing const_forget_box, stick an attribute on it and explain ↵DutchGhost-0/+12
it cant be called in ctfe yet
2020-03-16The const_forget_box was unused, and doesns't add anything to test by itself.DutchGhost-8/+0
2020-03-16Remove the call that makes miri failDutchGhost-4/+0