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

Introduce Vec::resize_with method (see #41758) #49559

Merged
merged 1 commit into from
Apr 5, 2018

Conversation

djc
Copy link
Contributor

@djc djc commented Apr 1, 2018

In #41758, the libs team decided they preferred Vec::resize_with over Vec::resize_default(). Here is an implementation to get this moving forward.

I don't know what the removal process for Vec::resize_default() should be, so I've left it in place for now. Would be happy to follow up with its removal.

@TimNN
Copy link
Contributor

TimNN commented Apr 1, 2018

Your PR failed on Travis. Through arcane magic we have determined that the following fragments from the build log may contain information about the problem.

Click to expand the log.
[00:00:46] configure: rust.quiet-tests     := True
---
[00:41:36] .........................................................................i..........................
[00:41:42] ................i...................................................................................
---
[00:42:18] ............................................................................................i.......
[00:42:25] ................................................................i...................................
---
[00:43:21] .............................................i......................................................
---
[00:47:19] .............................i......................................................................
[00:47:33] ..............................................................i.....................................
[00:47:49] ...............................................i....................................................
[00:48:10] ....................................................................................................
[00:48:32] ....................................................................................................
[00:48:53] ....................................................................................................
[00:49:18] .i................................................................................................i.
[00:49:45] .................................................................................test [run-pass] run-pass/mir_heavy_promoted.rs has been running for over 60 seconds
[00:49:55] ...................
[00:50:25] ....................................................................................................
[00:51:02] ...............................................................ii...................................
[00:51:46] ..........................i....................................................i.ii.test [run-pass] run-pass/saturating-float-casts.rs has been running for over 60 seconds
[00:51:52] ................
[00:52:32] .......................................................................................iiiiiii......
---
[00:54:36] ....................................i...............................................................
[00:54:43] ....................................................................................................
[00:54:51] ..................i............................................................ii.iii...............
[00:54:58] ....................................................................................................
[00:55:06] ........i..............................i............................................................
[00:55:13] ....................................................................................................
[00:55:20] .....................i..............................................................................
[00:55:28] ....................................................................................................
[00:55:38] ....................................................................................................
[00:55:48] ....................................................................................................
[00:55:59] ....................................................................................................
[00:56:13] ....................................................................................................
[00:56:22] ..............i.....................................................................................
[00:56:31] .................i..ii..............................................................................
[00:56:41] ....................................................................................................
[00:56:51] ....................................................................................................
[00:57:01] ....................................................................................i...............
[00:57:11] ..............................i.....................................................................
---
[00:57:48] ............................i.......................................................................
[00:57:49] ....................................................................i...............................
[00:57:51] ................i.......................................................
---
[00:58:05] ...........i........................
---
[00:58:35] i...i..ii....i.............ii........iii......i..i...i...ii..i..i..ii.....
---
[00:58:38] i.......i......................i......
---
[00:59:14] iiii.......i..i........i..i.i.............i..........iiii...........i...i..........ii.i.i.......ii..
[00:59:15] ....ii...
---
[01:08:35] ...i................................................................................................
---
[01:10:29] ......................................i.............................................................
[01:10:50] ....................................................................................................
[01:11:10] .............................................i......................................................
[01:11:31] .............................................................................F......................
[01:11:40] .................................
[01:11:40] failures:
[01:11:40]
[01:11:40] ---- vec.rs - vec::Vec<T>::resize_with (line 1322) stdout ----
[01:11:40]  thread 'rustc' panicked at 'test executable failed:
[01:11:40]
[01:11:40] thread 'main' panicked at 'attempt to subtract with overflow', /checkout/src/liballoc/vec.rs:1341:20
---
[01:11:40] command did not execute successfully: "/checkout/obj/build/x86_64-unknown-linux-gnu/stage0/bin/cargo" "test" "--target" "x86_64-unknown-linux-gnu" "--release" "--locked" "--color" "always" "--features" "panic-unwind jemalloc backtrace" "--manifest-path" "/checkout/src/libstd/Cargo.toml" "-p" "alloc" "--" "--quiet"
[01:11:40] expected success, got: exit code: 101
[01:11:40]
[01:11:40]
[01:11:40] failed to run: /checkout/obj/build/bootstrap/debug/bootstrap test
[01:11:40] Build completed unsuccessfully in 0:30:57
[01:11:40] make: *** [check] Error 1
[01:11:40] Makefile:58: recipe for target 'check' failed
---
$ cat obj/tmp/sccache.log
---
$ ls -lat $HOME/Library/Logs/DiagnosticReports/
ls: cannot access /home/travis/Library/Logs/DiagnosticReports/: No such file or directory
travis_time:end:003979e0:start=1522599165089047585,finish=1522599165096796100,duration=7748515
travis_fold:end:after_failure.4
travis_fold:start:after_failure.5
travis_time:start:08e71f78
$ find $HOME/Library/Logs/DiagnosticReports -type f -name '*.crash' -not -name '*.stage2-*.crash' -not -name 'com.apple.CoreSimulator.CoreSimulatorService-*.crash' -exec printf travis_fold":start:crashlog\n\033[31;1m%s\033[0m\n" {} \; -exec head -750 {} \; -exec echo travis_fold":"end:crashlog \; || true
find: `/home/travis/Library/Logs/DiagnosticReports': No such file or directory
travis_time:end:08e71f78:start=1522599165102762553,finish=1522599165109019496,duration=6256943
travis_fold:end:after_failure.5
travis_fold:start:after_failure.6
travis_time:start:176b8fa7
$ dmesg | grep -i kill
[   10.716396] init: failsafe main process (1092) killed by TERM signal

I'm a bot! I can only do what humans tell me to, so if this was not helpful or you have suggestions for improvements, please ping or otherwise contact @TimNN.

/// let mut vec = vec![1, 2, 3, 4];
/// vec.resize_with(2, Default::default);
/// assert_eq!(vec, [1, 2]);
/// ```
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since it's FnMut, consider adding an example that uses state of some kind. Perhaps

let mut vec = vec![];
let mut p = 1;
vec.resize_with(4, || { p *= 2; p });
assert_eq!(vec, [2, 4, 8, 16]);

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup, that was on my list but forgot about it. I've updated it now, using your example.

pub fn resize_with<F>(&mut self, new_len: usize, mut f: F)
where F: FnMut() -> T
{
let len = self.len();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should the be implemented using extend_with, like the other two are? Something like

struct ExtendFunc<F>(F);
impl<T, F: FnMut() -> T> ExtendWith<T> for ExtendFunct<F> {
    fn next(&self) -> T { (self.0)() }
    fn last(self) -> T { (self.0)() }
}

(Would it ever be possible for a closure to implement its FnOnce differently from its FnMut, to take advantage of the difference here the way ExtendElement does?)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As I understand it, the value returned by f is already moved into place for each iteration in the current implementation of resize_with(), so it seems like the ExtendWith mechanism doesn't make sense here.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this should use ExtendWith: ExtendWith is not only used to generalize and avoid the last clone, extend_with is also implemented in a way that makes optimizations more likely, as I understand the code.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, coming up.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I think that runs into mutability problems. ExtendWith::next() is defined as taking &self, in which case the mutability of the FnMut seems inaccessible through implementing ExtendFunc the way @scottmcm proposes. I don't think I see a way out of that...

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point! ExtendWith is non-pub, though, so maybe just change it to take &mut self? It doesn't look like an instance of it ever needs to be shared...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That works, I guess.

Copy link
Contributor

@TimNN TimNN left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cc @rust-lang/libs: Do you want / need an FCP for this?

///
/// If `new_len` is greater than `len`, the `Vec` is extended by the
/// difference, with each additional slot filled with the result of
/// closure `f`. If `new_len` is less than `len`, the `Vec` is simply
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: I'd make this "[...] with the result of calling the closure f".

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense, done.

@@ -1306,6 +1306,49 @@ impl<T> Vec<T> {
}
other
}

/// Resizes the `Vec` in-place so that `len` is equal to `new_len`.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd mention in the docs the order in which the elements are inserted / f is called, since that is something people would want to rely on, I imagine.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added "The return values from f will end up in the Vec in the order they have been generated." The wording here feels a little awkward to me, maybe someone (a native speaker) can tighten it up?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The "end up in" is maybe a bit colloquial, but it's easily understandable, so I'm happy.

@@ -1333,7 +1376,8 @@ impl<T: Clone> Vec<T> {
///
/// [`Clone`]: ../../std/clone/trait.Clone.html
/// [`Default`]: ../../std/default/trait.Default.html
/// [`resize_default`]: #method.resize_default
/// ['Default::default`]: ../../std/default/trait.Default.html#method.default
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't believe this link is used.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice catch, removed.

pub fn resize_with<F>(&mut self, new_len: usize, mut f: F)
where F: FnMut() -> T
{
let len = self.len();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this should use ExtendWith: ExtendWith is not only used to generalize and avoid the last clone, extend_with is also implemented in a way that makes optimizations more likely, as I understand the code.

@alexcrichton
Copy link
Member

Oh since this is unstable it's fine to not need FCP to land this

@djc
Copy link
Contributor Author

djc commented Apr 2, 2018

@TimNN @alexcrichton any suggestions on how to handle resize_default() after this?

@alexcrichton
Copy link
Member

@djc could resize_default() delegate to this method?

@pietroalbini pietroalbini added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Apr 2, 2018
@djc
Copy link
Contributor Author

djc commented Apr 3, 2018

@alexcrichton (or other Libs team members) it probably could. My question is more: given the discussion in the tracking issue, supposedly resize_default() should be removed at some point when resize_with() is added, since this was the decision of the Libs team. How does that process work? Should I just remove it now, or does it get deprecated for a while before being removed?

@alexcrichton
Copy link
Member

@djc oh we'd want the replacement to be stable before taking any action, so for this I think it's fine to just add the new method unstable and leave resize_default as is

@TimNN
Copy link
Contributor

TimNN commented Apr 3, 2018

@bors r+

@bors
Copy link
Contributor

bors commented Apr 3, 2018

📌 Commit da0ceef has been approved by TimNN

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Apr 3, 2018
kennytm added a commit to kennytm/rust that referenced this pull request Apr 4, 2018
Introduce Vec::resize_with method (see rust-lang#41758)

In rust-lang#41758, the libs team decided they preferred `Vec::resize_with` over `Vec::resize_default()`. Here is an implementation to get this moving forward.

I don't know what the removal process for `Vec::resize_default()` should be, so I've left it in place for now. Would be happy to follow up with its removal.
bors added a commit that referenced this pull request Apr 4, 2018
Rollup of 25 pull requests

Successful merges:

 - #49179 (Handle future deprecation annotations )
 - #49512 (Add support for variant and types fields for intra links)
 - #49515 (fix targetted value background)
 - #49516 (Add missing anchor for union type fields)
 - #49532 (Add test for rustdoc ignore test)
 - #49533 (Add #[must_use] to a few standard library methods)
 - #49540 (Fix miri Discriminant() for non-ADT)
 - #49559 (Introduce Vec::resize_with method (see #41758))
 - #49570 (avoid IdxSets containing garbage above the universe length)
 - #49577 (Stabilize String::replace_range)
 - #49599 (Fix typo)
 - #49603 (Fix url for intra link provided method)
 - #49607 (Stabilize iterator methods in 1.27)
 - #49609 (run-pass/attr-stmt-expr: expand test cases)
 - #49612 (Fix "since" version for getpid feature.)
 - #49618 (Fix build error when compiling libcore for 16bit targets)
 - #49619 (tweak core::fmt docs)
 - #49637 (Stabilize parent_id())
 - #49639 (Update Cargo)
 - #49628 (Re-write the documentation index)
 - #49594 (Add some performance guidance to std::fs and std::io docs)
 - #49625 (miri: add public alloc_kind accessor)
 - #49634 (Add a test for the fix to issue #43058)
 - #49641 (Regression test for #46314)
 - #49547 (Unignore borrowck test)

Failed merges:
@alexcrichton alexcrichton merged commit da0ceef into rust-lang:master Apr 5, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants