From 618677ff40a121f7ad79c49e0b4f4f2e4ab957dd Mon Sep 17 00:00:00 2001 From: Nicholas Mazzuca Date: Sat, 19 Dec 2015 15:45:48 -0800 Subject: [PATCH 01/11] std::slice::{ copy, set }; --- text/0000-slice-copy-set.md | 60 +++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 text/0000-slice-copy-set.md diff --git a/text/0000-slice-copy-set.md b/text/0000-slice-copy-set.md new file mode 100644 index 00000000000..a8a453f7c5a --- /dev/null +++ b/text/0000-slice-copy-set.md @@ -0,0 +1,60 @@ +- Feature Name: std::slice::{ copy, set }; +- Start Date: (fill me in with today's date, YYYY-MM-DD) +- RFC PR: (leave this empty) +- Rust Issue: (leave this empty) + +# Summary +[summary]: #summary + +Safe `memcpy` from one slice to another of the same type and length, and a safe +`memset` of a slice of type `T: Copy`. + +# Motivation +[motivation]: #motivation + +Currently, the only way to quickly copy from one non-`u8` slice to another is to +use a loop, or unsafe methods like `std::ptr::copy_nonoverlapping`. This allows +us to guarantee a `memcpy` for `Copy` types, and is safe. The only way to +`memset` a slice, currently, is a loop, and we should expose a method to allow +people to do this. This also completely gets rid of the point of +`std::slice::bytes`, which means we can remove this deprecated and useless +module. + +# Detailed design +[design]: #detailed-design + +Add two functions to `std::slice`. + +```rust +pub fn set(slice: &mut [T], value: T); +pub fn copy(src: &[T], dst: &mut [T]); +``` + +`set` loops through slice, setting each member to value. This will lower to a +memset in all cases possible. + +`copy` panics if `src.len() != dst.len()`, then `memcpy`s the members from +`src` to `dst`. + +# Drawbacks +[drawbacks]: #drawbacks + +Two new functions in `std::slice`. + +# Alternatives +[alternatives]: #alternatives + +We could name these functions something different. + +`memcpy` is also pretty weird, here. Panicking if the lengths differ is +different from what came before; I believe it to be the safest path, because I +think I'd want to know, personally, if I'm passing the wrong lengths to copy. +However, `std::slice::bytes::copy_memory`, the function I'm basing this on, only +panics if `dst.len() < src.len()`. So... room for discussion, here. + +However, these are necessary functions. + +# Unresolved questions +[unresolved]: #unresolved-questions + +None, as far as I can tell. From 08a87e4ac99dcecec973ceef249c8305239529ba Mon Sep 17 00:00:00 2001 From: Nicholas Mazzuca Date: Sat, 19 Dec 2015 16:21:29 -0800 Subject: [PATCH 02/11] Change a few things --- text/0000-slice-copy-set.md | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/text/0000-slice-copy-set.md b/text/0000-slice-copy-set.md index a8a453f7c5a..6cd41da9d49 100644 --- a/text/0000-slice-copy-set.md +++ b/text/0000-slice-copy-set.md @@ -31,7 +31,7 @@ pub fn copy(src: &[T], dst: &mut [T]); ``` `set` loops through slice, setting each member to value. This will lower to a -memset in all cases possible. +memset in all possible cases. `copy` panics if `src.len() != dst.len()`, then `memcpy`s the members from `src` to `dst`. @@ -39,7 +39,15 @@ memset in all cases possible. # Drawbacks [drawbacks]: #drawbacks -Two new functions in `std::slice`. +Two new functions in `std::slice`. `std::slice::set` *will not* be lowered to a +`memset` in any case where the bytes of `value` are not all the same, as in + +```rust +// let points: [f32; 16]; +std::slice::set(&mut points, 1.0); // This is not lowered to a memset + // (However, it is lowered to a simd loop, + // which is what a memset is, in reality) +``` # Alternatives [alternatives]: #alternatives @@ -52,7 +60,7 @@ think I'd want to know, personally, if I'm passing the wrong lengths to copy. However, `std::slice::bytes::copy_memory`, the function I'm basing this on, only panics if `dst.len() < src.len()`. So... room for discussion, here. -However, these are necessary functions. +These are necessary functions, in the opinion of the author. # Unresolved questions [unresolved]: #unresolved-questions From ff919f110a1437f41b0d820312a79645c8ff447a Mon Sep 17 00:00:00 2001 From: Nicholas Mazzuca Date: Sat, 19 Dec 2015 19:30:54 -0800 Subject: [PATCH 03/11] Switch to fill, Add some language specifically about being defined for slices with uninitialized values Also add some language about alternatives --- ...ce-copy-set.md => 0000-slice-copy-fill.md} | 36 +++++++++++++------ 1 file changed, 25 insertions(+), 11 deletions(-) rename text/{0000-slice-copy-set.md => 0000-slice-copy-fill.md} (60%) diff --git a/text/0000-slice-copy-set.md b/text/0000-slice-copy-fill.md similarity index 60% rename from text/0000-slice-copy-set.md rename to text/0000-slice-copy-fill.md index 6cd41da9d49..4c3ff0dfac0 100644 --- a/text/0000-slice-copy-set.md +++ b/text/0000-slice-copy-fill.md @@ -1,4 +1,4 @@ -- Feature Name: std::slice::{ copy, set }; +- Feature Name: std::slice::copy, slice::fill - Start Date: (fill me in with today's date, YYYY-MM-DD) - RFC PR: (leave this empty) - Rust Issue: (leave this empty) @@ -23,15 +23,23 @@ module. # Detailed design [design]: #detailed-design -Add two functions to `std::slice`. +Add one function to `std::slice`. ```rust -pub fn set(slice: &mut [T], value: T); pub fn copy(src: &[T], dst: &mut [T]); ``` -`set` loops through slice, setting each member to value. This will lower to a -memset in all possible cases. +and one function to Primitive Type `slice`. + +```rust +impl [T] where T: Copy { + pub fn fill(&mut self, value: T); +} +``` + +`fill` loops through slice, setting each member to value. This will lower to a +memset in all possible cases. It is defined to call `fill` on a slice which has +uninitialized members. `copy` panics if `src.len() != dst.len()`, then `memcpy`s the members from `src` to `dst`. @@ -39,20 +47,21 @@ memset in all possible cases. # Drawbacks [drawbacks]: #drawbacks -Two new functions in `std::slice`. `std::slice::set` *will not* be lowered to a -`memset` in any case where the bytes of `value` are not all the same, as in +One new function in `std::slice`, and one new method on `slice`. `[T]::fill` +*will not* be lowered to a `memset` in any case where the bytes of `value` are +not all the same, as in ```rust // let points: [f32; 16]; -std::slice::set(&mut points, 1.0); // This is not lowered to a memset - // (However, it is lowered to a simd loop, - // which is what a memset is, in reality) +points.fill(1.0); // This is not lowered to a memset (However, it is lowered to + // a simd loop, which is what a memset is, in reality) ``` # Alternatives [alternatives]: #alternatives -We could name these functions something different. +We could name these functions something else. `fill`, for example, could be +called `set`. `memcpy` is also pretty weird, here. Panicking if the lengths differ is different from what came before; I believe it to be the safest path, because I @@ -60,6 +69,11 @@ think I'd want to know, personally, if I'm passing the wrong lengths to copy. However, `std::slice::bytes::copy_memory`, the function I'm basing this on, only panics if `dst.len() < src.len()`. So... room for discussion, here. +`fill` could be a free function, and `copy` could be a method. It is the +opinion of the author that `copy` is best as a free function, as it is +non-obvious which should be the "owner", `dst` or `src`. `fill` is more +obviously a method. + These are necessary functions, in the opinion of the author. # Unresolved questions From 094f5568e5eb9e106163f208366ed0be7fb617a4 Mon Sep 17 00:00:00 2001 From: Nicholas Mazzuca Date: Sun, 20 Dec 2015 05:50:25 -0800 Subject: [PATCH 04/11] More edits from the crowd --- text/0000-slice-copy-fill.md | 55 +++++++++++++++++++++++------------- 1 file changed, 36 insertions(+), 19 deletions(-) diff --git a/text/0000-slice-copy-fill.md b/text/0000-slice-copy-fill.md index 4c3ff0dfac0..e80bbc6e9be 100644 --- a/text/0000-slice-copy-fill.md +++ b/text/0000-slice-copy-fill.md @@ -23,33 +23,40 @@ module. # Detailed design [design]: #detailed-design -Add one function to `std::slice`. - -```rust -pub fn copy(src: &[T], dst: &mut [T]); -``` - -and one function to Primitive Type `slice`. +Add two methods to Primitive Type `slice`. ```rust impl [T] where T: Copy { pub fn fill(&mut self, value: T); + pub fn copy_from(&mut self, src: &[T]); } ``` `fill` loops through slice, setting each member to value. This will lower to a -memset in all possible cases. It is defined to call `fill` on a slice which has -uninitialized members. +memset in all possible cases. It is defined behavior to call `fill` on a slice +which has uninitialized members, and `dst` is guaranteed to be fully filled +afterwards. + +`copy` panics if `src.len() != dst.len()`, then `memcpy`s the members into +`dst` from `src`. Calling `copy_from` is semantically equivalent to a `memcpy`, +`dst` can have uninitialized members, and `dst` is guaranteed to be fully filled +afterwards. This means, for example, that the following is fully defined: -`copy` panics if `src.len() != dst.len()`, then `memcpy`s the members from -`src` to `dst`. +```rust +let s1: [u8; 16] = unsafe { std::mem::uninitialized() }; +let s2: [u8; 16] = unsafe { std::mem::uninitialized() }; +s1.fill(42); +s2.copy_from(s1); +println!("{}", s2); +``` + +And the program will print 16 '8's. # Drawbacks [drawbacks]: #drawbacks -One new function in `std::slice`, and one new method on `slice`. `[T]::fill` -*will not* be lowered to a `memset` in any case where the bytes of `value` are -not all the same, as in +Two new methods on `slice`. `[T]::fill` *will not* be lowered to a `memset` in +any case where the bytes of `value` are not all the same, as in ```rust // let points: [f32; 16]; @@ -57,24 +64,34 @@ points.fill(1.0); // This is not lowered to a memset (However, it is lowered to // a simd loop, which is what a memset is, in reality) ``` +Also, `copy_from` has it's arguments in a different order from it's most similar +`unsafe` alternative, `std::ptr::copy_nonoverlapping`. This is due to an +unfortunate error that cannot be solved with the now stable +`copy_nonoverlapping`, and the design decision should not be extended to +`copy_from`. + # Alternatives [alternatives]: #alternatives We could name these functions something else. `fill`, for example, could be called `set`. +`copy_from` could be called `copy_to`, and have the order of the arguments +switched around. This is a bad idea, as `copy_from` has a natural connection to +`dst = src` syntax. + `memcpy` is also pretty weird, here. Panicking if the lengths differ is different from what came before; I believe it to be the safest path, because I think I'd want to know, personally, if I'm passing the wrong lengths to copy. However, `std::slice::bytes::copy_memory`, the function I'm basing this on, only panics if `dst.len() < src.len()`. So... room for discussion, here. -`fill` could be a free function, and `copy` could be a method. It is the -opinion of the author that `copy` is best as a free function, as it is -non-obvious which should be the "owner", `dst` or `src`. `fill` is more -obviously a method. +`fill` and `copy_from` could both be free functions, and were in the original +draft of this document. However, overwhelming support for these as methods has +meant that these have become methods. -These are necessary functions, in the opinion of the author. +These are necessary, in the opinion of the author. Much unsafe code has been +written because these do not exist. # Unresolved questions [unresolved]: #unresolved-questions From 509a559c461c768b2b3d81228c27fab6c1fd486d Mon Sep 17 00:00:00 2001 From: Nicholas Mazzuca Date: Sun, 20 Dec 2015 06:32:30 -0800 Subject: [PATCH 05/11] Rename `fill` to `fill_with` --- text/0000-slice-copy-fill.md | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/text/0000-slice-copy-fill.md b/text/0000-slice-copy-fill.md index e80bbc6e9be..30519ca0e27 100644 --- a/text/0000-slice-copy-fill.md +++ b/text/0000-slice-copy-fill.md @@ -27,25 +27,25 @@ Add two methods to Primitive Type `slice`. ```rust impl [T] where T: Copy { - pub fn fill(&mut self, value: T); + pub fn fill_with(&mut self, value: T); pub fn copy_from(&mut self, src: &[T]); } ``` -`fill` loops through slice, setting each member to value. This will lower to a -memset in all possible cases. It is defined behavior to call `fill` on a slice -which has uninitialized members, and `dst` is guaranteed to be fully filled +`fill_with` loops through slice, setting each member to value. This will lower to a +memset in all possible cases. It is defined behavior to call `fill_with` on a slice +which has uninitialized members, and `self` is guaranteed to be fully filled afterwards. -`copy` panics if `src.len() != dst.len()`, then `memcpy`s the members into -`dst` from `src`. Calling `copy_from` is semantically equivalent to a `memcpy`, -`dst` can have uninitialized members, and `dst` is guaranteed to be fully filled +`copy` panics if `src.len() != self.len()`, then `memcpy`s the members into +`self` from `src`. Calling `copy_from` is semantically equivalent to a `memcpy`; +`self` can have uninitialized members, and `self` is guaranteed to be fully filled afterwards. This means, for example, that the following is fully defined: ```rust let s1: [u8; 16] = unsafe { std::mem::uninitialized() }; let s2: [u8; 16] = unsafe { std::mem::uninitialized() }; -s1.fill(42); +s1.fill_with(42); s2.copy_from(s1); println!("{}", s2); ``` @@ -55,13 +55,13 @@ And the program will print 16 '8's. # Drawbacks [drawbacks]: #drawbacks -Two new methods on `slice`. `[T]::fill` *will not* be lowered to a `memset` in +Two new methods on `slice`. `[T]::fill_with` *will not* be lowered to a `memset` in any case where the bytes of `value` are not all the same, as in ```rust // let points: [f32; 16]; -points.fill(1.0); // This is not lowered to a memset (However, it is lowered to - // a simd loop, which is what a memset is, in reality) +points.fill_with(1.0); // This is not lowered to a memset (However, it is lowered to + // a simd loop, which is what a memset is, in reality) ``` Also, `copy_from` has it's arguments in a different order from it's most similar @@ -73,8 +73,8 @@ unfortunate error that cannot be solved with the now stable # Alternatives [alternatives]: #alternatives -We could name these functions something else. `fill`, for example, could be -called `set`. +We could name these functions something else. `fill_with`, for example, could be +called `set` or `fill`. `copy_from` could be called `copy_to`, and have the order of the arguments switched around. This is a bad idea, as `copy_from` has a natural connection to @@ -86,12 +86,12 @@ think I'd want to know, personally, if I'm passing the wrong lengths to copy. However, `std::slice::bytes::copy_memory`, the function I'm basing this on, only panics if `dst.len() < src.len()`. So... room for discussion, here. -`fill` and `copy_from` could both be free functions, and were in the original -draft of this document. However, overwhelming support for these as methods has -meant that these have become methods. +`fill_with` and `copy_from` could both be free functions, and were in the +original draft of this document. However, overwhelming support for these as +methods has meant that these have become methods. -These are necessary, in the opinion of the author. Much unsafe code has been -written because these do not exist. +These are necessary, in my opinion. Much unsafe code has been written because +these do not exist. # Unresolved questions [unresolved]: #unresolved-questions From 824d43c131f99b30faa6537dc038e9780e57d46c Mon Sep 17 00:00:00 2001 From: Nicholas Mazzuca Date: Sun, 20 Dec 2015 17:41:02 -0800 Subject: [PATCH 06/11] Final name change; back to `fill` --- text/0000-slice-copy-fill.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/text/0000-slice-copy-fill.md b/text/0000-slice-copy-fill.md index 30519ca0e27..7e96e577950 100644 --- a/text/0000-slice-copy-fill.md +++ b/text/0000-slice-copy-fill.md @@ -27,13 +27,13 @@ Add two methods to Primitive Type `slice`. ```rust impl [T] where T: Copy { - pub fn fill_with(&mut self, value: T); + pub fn fill(&mut self, value: T); pub fn copy_from(&mut self, src: &[T]); } ``` -`fill_with` loops through slice, setting each member to value. This will lower to a -memset in all possible cases. It is defined behavior to call `fill_with` on a slice +`fill` loops through slice, setting each member to value. This will lower to a +memset in all possible cases. It is defined behavior to call `fill` on a slice which has uninitialized members, and `self` is guaranteed to be fully filled afterwards. @@ -45,7 +45,7 @@ afterwards. This means, for example, that the following is fully defined: ```rust let s1: [u8; 16] = unsafe { std::mem::uninitialized() }; let s2: [u8; 16] = unsafe { std::mem::uninitialized() }; -s1.fill_with(42); +s1.fill(42); s2.copy_from(s1); println!("{}", s2); ``` @@ -55,12 +55,12 @@ And the program will print 16 '8's. # Drawbacks [drawbacks]: #drawbacks -Two new methods on `slice`. `[T]::fill_with` *will not* be lowered to a `memset` in +Two new methods on `slice`. `[T]::fill` *will not* be lowered to a `memset` in any case where the bytes of `value` are not all the same, as in ```rust // let points: [f32; 16]; -points.fill_with(1.0); // This is not lowered to a memset (However, it is lowered to +points.fill(1.0); // This is not lowered to a memset (However, it is lowered to // a simd loop, which is what a memset is, in reality) ``` @@ -73,8 +73,8 @@ unfortunate error that cannot be solved with the now stable # Alternatives [alternatives]: #alternatives -We could name these functions something else. `fill_with`, for example, could be -called `set` or `fill`. +We could name these functions something else. `fill`, for example, could be +called `set`, `fill_from`, or `fill_with`. `copy_from` could be called `copy_to`, and have the order of the arguments switched around. This is a bad idea, as `copy_from` has a natural connection to @@ -86,7 +86,7 @@ think I'd want to know, personally, if I'm passing the wrong lengths to copy. However, `std::slice::bytes::copy_memory`, the function I'm basing this on, only panics if `dst.len() < src.len()`. So... room for discussion, here. -`fill_with` and `copy_from` could both be free functions, and were in the +`fill` and `copy_from` could both be free functions, and were in the original draft of this document. However, overwhelming support for these as methods has meant that these have become methods. From a7bf742db2af8f5be06322a139171d8819ead929 Mon Sep 17 00:00:00 2001 From: Nicholas Mazzuca Date: Mon, 21 Dec 2015 00:17:58 -0800 Subject: [PATCH 07/11] Correction from bluss --- text/0000-slice-copy-fill.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/text/0000-slice-copy-fill.md b/text/0000-slice-copy-fill.md index 7e96e577950..b2f9ca761f5 100644 --- a/text/0000-slice-copy-fill.md +++ b/text/0000-slice-copy-fill.md @@ -46,7 +46,7 @@ afterwards. This means, for example, that the following is fully defined: let s1: [u8; 16] = unsafe { std::mem::uninitialized() }; let s2: [u8; 16] = unsafe { std::mem::uninitialized() }; s1.fill(42); -s2.copy_from(s1); +s2.copy_from(&s1); println!("{}", s2); ``` From b8625ae9f02dfdbe07e0b9f53ba82fc3974ca8d4 Mon Sep 17 00:00:00 2001 From: Nicholas Mazzuca Date: Mon, 28 Dec 2015 23:06:09 -0800 Subject: [PATCH 08/11] Fix most of nagisa's complaints --- text/0000-slice-copy-fill.md | 25 +++++++------------------ 1 file changed, 7 insertions(+), 18 deletions(-) diff --git a/text/0000-slice-copy-fill.md b/text/0000-slice-copy-fill.md index b2f9ca761f5..fb8a45a6752 100644 --- a/text/0000-slice-copy-fill.md +++ b/text/0000-slice-copy-fill.md @@ -1,4 +1,4 @@ -- Feature Name: std::slice::copy, slice::fill +- Feature Name: slice\_copy\_fill - Start Date: (fill me in with today's date, YYYY-MM-DD) - RFC PR: (leave this empty) - Rust Issue: (leave this empty) @@ -37,7 +37,7 @@ memset in all possible cases. It is defined behavior to call `fill` on a slice which has uninitialized members, and `self` is guaranteed to be fully filled afterwards. -`copy` panics if `src.len() != self.len()`, then `memcpy`s the members into +`copy_from` panics if `src.len() != self.len()`, then `memcpy`s the members into `self` from `src`. Calling `copy_from` is semantically equivalent to a `memcpy`; `self` can have uninitialized members, and `self` is guaranteed to be fully filled afterwards. This means, for example, that the following is fully defined: @@ -64,12 +64,6 @@ points.fill(1.0); // This is not lowered to a memset (However, it is lowered to // a simd loop, which is what a memset is, in reality) ``` -Also, `copy_from` has it's arguments in a different order from it's most similar -`unsafe` alternative, `std::ptr::copy_nonoverlapping`. This is due to an -unfortunate error that cannot be solved with the now stable -`copy_nonoverlapping`, and the design decision should not be extended to -`copy_from`. - # Alternatives [alternatives]: #alternatives @@ -77,22 +71,17 @@ We could name these functions something else. `fill`, for example, could be called `set`, `fill_from`, or `fill_with`. `copy_from` could be called `copy_to`, and have the order of the arguments -switched around. This is a bad idea, as `copy_from` has a natural connection to -`dst = src` syntax. +switched around. This would follow `ptr::copy_nonoverlapping` ordering, and not +`dst = src` or `.clone_from()` ordering. -`memcpy` is also pretty weird, here. Panicking if the lengths differ is -different from what came before; I believe it to be the safest path, because I -think I'd want to know, personally, if I'm passing the wrong lengths to copy. -However, `std::slice::bytes::copy_memory`, the function I'm basing this on, only -panics if `dst.len() < src.len()`. So... room for discussion, here. +`copy_from` could panic only if `dst.len() < src.len()`. This would be the same +as what came before, but we would also lose the guarantee that an uninitialized +slice would be fully initialized. `fill` and `copy_from` could both be free functions, and were in the original draft of this document. However, overwhelming support for these as methods has meant that these have become methods. -These are necessary, in my opinion. Much unsafe code has been written because -these do not exist. - # Unresolved questions [unresolved]: #unresolved-questions From 3ef78eb1a10db93d953bf80fdff4b26bfa28d482 Mon Sep 17 00:00:00 2001 From: Nicholas Mazzuca Date: Tue, 29 Dec 2015 00:32:15 -0800 Subject: [PATCH 09/11] Tone down the stuff about lowering to memset --- text/0000-slice-copy-fill.md | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/text/0000-slice-copy-fill.md b/text/0000-slice-copy-fill.md index fb8a45a6752..25f554bdd88 100644 --- a/text/0000-slice-copy-fill.md +++ b/text/0000-slice-copy-fill.md @@ -32,10 +32,11 @@ impl [T] where T: Copy { } ``` -`fill` loops through slice, setting each member to value. This will lower to a -memset in all possible cases. It is defined behavior to call `fill` on a slice -which has uninitialized members, and `self` is guaranteed to be fully filled -afterwards. +`fill` loops through slice, setting each member to value. This will usually +lower to a memset in optimized builds. It is likely that this is only the +initial implementation, and will be optimized later to be almost as fast as, or +as fast as, memset. It is defined behavior to call `fill` on a slice which has +uninitialized members, and `self` is guaranteed to be fully filled afterwards. `copy_from` panics if `src.len() != self.len()`, then `memcpy`s the members into `self` from `src`. Calling `copy_from` is semantically equivalent to a `memcpy`; @@ -56,13 +57,7 @@ And the program will print 16 '8's. [drawbacks]: #drawbacks Two new methods on `slice`. `[T]::fill` *will not* be lowered to a `memset` in -any case where the bytes of `value` are not all the same, as in - -```rust -// let points: [f32; 16]; -points.fill(1.0); // This is not lowered to a memset (However, it is lowered to - // a simd loop, which is what a memset is, in reality) -``` +all cases. # Alternatives [alternatives]: #alternatives From da75c9b284504f4b404bb3ac714021a75258cc94 Mon Sep 17 00:00:00 2001 From: Nicholas Mazzuca Date: Tue, 26 Jan 2016 17:51:19 -0800 Subject: [PATCH 10/11] Take out `[T]::fill` --- text/0000-slice-copy-fill.md | 83 ------------------------------------ text/0000-slice-copy.md | 58 +++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 83 deletions(-) delete mode 100644 text/0000-slice-copy-fill.md create mode 100644 text/0000-slice-copy.md diff --git a/text/0000-slice-copy-fill.md b/text/0000-slice-copy-fill.md deleted file mode 100644 index 25f554bdd88..00000000000 --- a/text/0000-slice-copy-fill.md +++ /dev/null @@ -1,83 +0,0 @@ -- Feature Name: slice\_copy\_fill -- Start Date: (fill me in with today's date, YYYY-MM-DD) -- RFC PR: (leave this empty) -- Rust Issue: (leave this empty) - -# Summary -[summary]: #summary - -Safe `memcpy` from one slice to another of the same type and length, and a safe -`memset` of a slice of type `T: Copy`. - -# Motivation -[motivation]: #motivation - -Currently, the only way to quickly copy from one non-`u8` slice to another is to -use a loop, or unsafe methods like `std::ptr::copy_nonoverlapping`. This allows -us to guarantee a `memcpy` for `Copy` types, and is safe. The only way to -`memset` a slice, currently, is a loop, and we should expose a method to allow -people to do this. This also completely gets rid of the point of -`std::slice::bytes`, which means we can remove this deprecated and useless -module. - -# Detailed design -[design]: #detailed-design - -Add two methods to Primitive Type `slice`. - -```rust -impl [T] where T: Copy { - pub fn fill(&mut self, value: T); - pub fn copy_from(&mut self, src: &[T]); -} -``` - -`fill` loops through slice, setting each member to value. This will usually -lower to a memset in optimized builds. It is likely that this is only the -initial implementation, and will be optimized later to be almost as fast as, or -as fast as, memset. It is defined behavior to call `fill` on a slice which has -uninitialized members, and `self` is guaranteed to be fully filled afterwards. - -`copy_from` panics if `src.len() != self.len()`, then `memcpy`s the members into -`self` from `src`. Calling `copy_from` is semantically equivalent to a `memcpy`; -`self` can have uninitialized members, and `self` is guaranteed to be fully filled -afterwards. This means, for example, that the following is fully defined: - -```rust -let s1: [u8; 16] = unsafe { std::mem::uninitialized() }; -let s2: [u8; 16] = unsafe { std::mem::uninitialized() }; -s1.fill(42); -s2.copy_from(&s1); -println!("{}", s2); -``` - -And the program will print 16 '8's. - -# Drawbacks -[drawbacks]: #drawbacks - -Two new methods on `slice`. `[T]::fill` *will not* be lowered to a `memset` in -all cases. - -# Alternatives -[alternatives]: #alternatives - -We could name these functions something else. `fill`, for example, could be -called `set`, `fill_from`, or `fill_with`. - -`copy_from` could be called `copy_to`, and have the order of the arguments -switched around. This would follow `ptr::copy_nonoverlapping` ordering, and not -`dst = src` or `.clone_from()` ordering. - -`copy_from` could panic only if `dst.len() < src.len()`. This would be the same -as what came before, but we would also lose the guarantee that an uninitialized -slice would be fully initialized. - -`fill` and `copy_from` could both be free functions, and were in the -original draft of this document. However, overwhelming support for these as -methods has meant that these have become methods. - -# Unresolved questions -[unresolved]: #unresolved-questions - -None, as far as I can tell. diff --git a/text/0000-slice-copy.md b/text/0000-slice-copy.md new file mode 100644 index 00000000000..f49da7f0b95 --- /dev/null +++ b/text/0000-slice-copy.md @@ -0,0 +1,58 @@ +- Feature Name: slice\_copy\_from +- Start Date: (fill me in with today's date, YYYY-MM-DD) +- RFC PR: (leave this empty) +- Rust Issue: (leave this empty) + +# Summary +[summary]: #summary + +Safe `memcpy` from one slice to another of the same type and length. + +# Motivation +[motivation]: #motivation + +Currently, the only way to quickly copy from one non-`u8` slice to another is to +use a loop, or unsafe methods like `std::ptr::copy_nonoverlapping`. This allows +us to guarantee a `memcpy` for `Copy` types, and is safe. + +# Detailed design +[design]: #detailed-design + +Add one method to Primitive Type `slice`. + +```rust +impl [T] where T: Copy { + pub fn copy_from(&mut self, src: &[T]); +} +``` + +`copy_from` asserts that `src.len() == self.len()`, then `memcpy`s the members into +`self` from `src`. Calling `copy_from` is semantically equivalent to a `memcpy`. +`self` shall have exactly the same members as `src` after a call to `copy_from`. + +# Drawbacks +[drawbacks]: #drawbacks + +One new method on `slice`. + +# Alternatives +[alternatives]: #alternatives + +`copy_from` could be known as `copy_from_slice`, which would follow +`clone_from_slice`. + +`copy_from` could be called `copy_to`, and have the order of the arguments +switched around. This would follow `ptr::copy_nonoverlapping` ordering, and not +`dst = src` or `.clone_from()` ordering. + +`copy_from` could panic only if `dst.len() < src.len()`. This would be the same +as what came before, but we would also lose the guarantee that an uninitialized +slice would be fully initialized. + +`copy_from` could be a free function, as it was in the original draft of this +document. However, there was overwhelming support for it as a method. + +# Unresolved questions +[unresolved]: #unresolved-questions + +None, as far as I can tell. From ea0ad1c79e38ab798f598c198f5713a795d91b34 Mon Sep 17 00:00:00 2001 From: Nicholas Mazzuca Date: Fri, 12 Feb 2016 21:30:39 -0800 Subject: [PATCH 11/11] Rename copy_from -> copy_from_slice --- text/0000-slice-copy.md | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/text/0000-slice-copy.md b/text/0000-slice-copy.md index f49da7f0b95..f53f0324abe 100644 --- a/text/0000-slice-copy.md +++ b/text/0000-slice-copy.md @@ -22,13 +22,14 @@ Add one method to Primitive Type `slice`. ```rust impl [T] where T: Copy { - pub fn copy_from(&mut self, src: &[T]); + pub fn copy_from_slice(&mut self, src: &[T]); } ``` -`copy_from` asserts that `src.len() == self.len()`, then `memcpy`s the members into -`self` from `src`. Calling `copy_from` is semantically equivalent to a `memcpy`. -`self` shall have exactly the same members as `src` after a call to `copy_from`. +`copy_from_slice` asserts that `src.len() == self.len()`, then `memcpy`s the +members into `self` from `src`. Calling `copy_from_slice` is semantically +equivalent to a `memcpy`. `self` shall have exactly the same members as `src` +after a call to `copy_from_slice`. # Drawbacks [drawbacks]: #drawbacks @@ -38,19 +39,20 @@ One new method on `slice`. # Alternatives [alternatives]: #alternatives -`copy_from` could be known as `copy_from_slice`, which would follow -`clone_from_slice`. - -`copy_from` could be called `copy_to`, and have the order of the arguments +`copy_from_slice` could be called `copy_to`, and have the order of the arguments switched around. This would follow `ptr::copy_nonoverlapping` ordering, and not -`dst = src` or `.clone_from()` ordering. +`dst = src` or `.clone_from_slice()` ordering. + +`copy_from_slice` could panic only if `dst.len() < src.len()`. This would be the +same as what came before, but we would also lose the guarantee that an +uninitialized slice would be fully initialized. -`copy_from` could panic only if `dst.len() < src.len()`. This would be the same -as what came before, but we would also lose the guarantee that an uninitialized -slice would be fully initialized. +`copy_from_slice` could be a free function, as it was in the original draft of +this document. However, there was overwhelming support for it as a method. -`copy_from` could be a free function, as it was in the original draft of this -document. However, there was overwhelming support for it as a method. +`copy_from_slice` could be not merged, and `clone_from_slice` could be +specialized to `memcpy` in cases of `T: Copy`. I think it's good to have a +specific function to do this, however, which asserts that `T: Copy`. # Unresolved questions [unresolved]: #unresolved-questions