-
Notifications
You must be signed in to change notification settings - Fork 12.9k
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
Stabilize copy_within #61398
Stabilize copy_within #61398
Conversation
(rust_highfive has picked a reviewer for you, use r? to override) |
Stabilization reportThe let mut sl = [0, 1, 2, 3, 4, 5, 600, 700, 800, 900, 1000];
sl.copy_within(7..=9, 2);
assert_eq!(sl, [0, 1, 700, 800, 900, 5, 600, 700, 800, 900, 1000]); The Test cases can be found in rust/src/libcore/tests/slice.rs Lines 1494 to 1538 in db4c783
There is a minor suggestion for a non-panicking version. However, all other slice methods like |
@rfcbot fcp merge |
Team member @SimonSapin has proposed to merge this. The next step is review by the rest of the tagged team members: No concerns currently listed. Once a majority of reviewers approve (and at most 2 approvals are outstanding), this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up! See this document for info about what commands tagged team members can give me. |
Thanks for the stabilization report @kennytm ! |
I'd caution that my crate has seen very little usage since it was published. I only use it in a couple places, and I only see one other calling crate on crates.io. So if someone did have other ideas about how the API should look, I wouldn't feel like we have a ton of usage evidence to argue either way. But on the other hand, it's a pretty simple API :) I also notice that we might want to add tests for the overflow-panic cases that are possible with nonstandard ranges. |
🔔 This is now entering its final comment period, as per the review above. 🔔 |
/// let mut bytes = *b"Hello, World!"; | ||
/// | ||
/// bytes.copy_within(1..5, 8); | ||
/// | ||
/// assert_eq!(&bytes, b"Hello, Wello!"); | ||
/// ``` | ||
#[unstable(feature = "copy_within", issue = "54236")] | ||
#[stable(feature = "copy_within", since = "1.37.0")] | ||
pub fn copy_within<R: ops::RangeBounds<usize>>(&mut self, src: R, dest: usize) | ||
where | ||
T: Copy, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
drive-by unrelated to stabilization: seems like we shouldn't be monomorphizing this whole function on R
, given that we only need .start_bound()
and .end_bound()
, which we can call first and pass into a non-generic version.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wouldn’t the method still be generic over T
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LLVM will deduplicate identical functions anyway. Hard to see this coming at a compilation time cost and if it ever does in practice, it would be great to fix it in general rather than implementing hacks for specific functions in libcore.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@nagisa the point is that they wouldn't be identical functions because they'd have different types for R
. So we'd generate separate copies for Range
, RangeFrom
, RangeTo
, RangeInclusive
, etc...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@cramertj if the generated IR after inlining is identical, it will get merged. LLVM does not care about the type system.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My point is that I don't think the generated IR would be identical. RangeFrom<T>
and Range<T>
don't have the same representation, so converting them to start and end bounds would need to be split out into a separate function in order for the inner body of the functions to be unified.
Before the end of FCP I'd like to confirm one thing: would restricting the bound from I don't think we're interested in supporting code like slice.copy_within((Bound::Excluded(1), Bound::Excluded(3)), 6); The implementation could then also be shortened as: pub fn copy_within<R: SliceIndex<[T], Output=[T]>>(&mut self, src: R, dest: usize)
where
T: Copy,
{
let src = &self[src];
let count = src.len();
assert!(dest <= self.len() - count, "dest is out of bounds");
unsafe {
ptr::copy(
src.as_ptr(),
self.get_unchecked_mut(dest),
count,
);
}
} |
This shortened code looks like it might have UB in case the source and destination ranges have overlap, since Regardless, being used for arguments like this is the point of |
I've tried checking with Miri but no errors were reported about overlapping ranges (unlike The code should be changed to let mut x = [1, 2, 3];
x.copy_within(1..1, 3); |
This ensures we won't accidentally read *src or *dest even when count = 0.
Co-Authored-By: Jack O'Connor <oconnor663@gmail.com>
I agree with @SimonSapin that putting |
This doesn't block stabilization, but something like this refactoring (example branch in the pub fn copy_within<R: ops::RangeBounds<usize>>(&mut self, src: R, dest: usize)
where
T: Copy,
{
let (src_ptr, src_len) = {
let src_slice = self.get_range(src); // <-- here's where a lot gets factored out
(src_slice.as_ptr(), src_slice.len())
};
assert!(dest <= self.len() - src_len, "dest is out of bounds");
unsafe {
let dest_ptr = self.as_mut_ptr().add(dest);
ptr::copy(src_ptr, dest_ptr, src_len);
}
} Here's a godbolt output suggesting that the optimizer is still happy. |
Is the Maybe forcing early conversion to raw pointers would could be enough to avoid UB? let src: *const [T] = self.get(src);
let dest: *mut T = self.get_mut(dest); |
I don't think there's a blanket impl of |
The final comment period, with a disposition to merge, as per the review above, is now complete. As the automated representative of the governance process, I would like to thank the author for their work and everyone else who contributed. The RFC will be merged soon. |
I assume the nominated label was a request for FCP, which has happened. @bors r+ |
📌 Commit 427f1a4 has been approved by |
…monSapin Stabilize copy_within Closes rust-lang#54236.
…monSapin Stabilize copy_within Closes rust-lang#54236.
Rollup of 9 pull requests Successful merges: - #60376 (Stabilize Option::xor) - #61398 (Stabilize copy_within) - #61629 (Hygienize macros in the standard library) - #61675 (Include frame pointer for bare metal RISC-V targets) - #61750 (Fix x.py install) - #61761 (Add an alias for x86_64-sun-solaris target tuple) - #61762 (rustbuild: fix libtest_stamp) - #61763 (ci: fix ci stats upload condition) - #61776 (Fix typos in error_codes) Failed merges: r? @ghost
Closes #54236.