diff options
| author | Mazdak Farrokhzad <twingoow@gmail.com> | 2019-10-20 12:40:16 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2019-10-20 12:40:16 +0200 |
| commit | 766073aeb4735bda885026731b56919c5cf932ad (patch) | |
| tree | 72e4c064d9c9c983df7ddff5d858c7499634b08c | |
| parent | f01ffbc7f14c5e80c130d679e99c3507591e4bab (diff) | |
| parent | 23cb1d520bbe943b9dfae54c6a8f2f1fe4748872 (diff) | |
| download | rust-766073aeb4735bda885026731b56919c5cf932ad.tar.gz rust-766073aeb4735bda885026731b56919c5cf932ad.zip | |
Rollup merge of #65551 - sinkuu:cstring_spec, r=sfackler
Avoid realloc in `CString::new` If `&[u8]` or `&str` is given, `CString::new` allocates a new `Vec` with the exact capacity, and then `CString::from_vec_unchecked` calls `.reserve_exact(1)` for nul byte. This PR avoids the reallocation by allocationg `len + 1` bytes beforehand. In microbenchmark this PR speeds up `CString::new(&[u8])` by 30%.
| -rw-r--r-- | src/librustc_codegen_llvm/back/lto.rs | 4 | ||||
| -rw-r--r-- | src/libstd/ffi/c_str.rs | 26 | ||||
| -rw-r--r-- | src/libstd/lib.rs | 1 |
3 files changed, 27 insertions, 4 deletions
diff --git a/src/librustc_codegen_llvm/back/lto.rs b/src/librustc_codegen_llvm/back/lto.rs index 7437b1e3c8a..b3be3d09f17 100644 --- a/src/librustc_codegen_llvm/back/lto.rs +++ b/src/librustc_codegen_llvm/back/lto.rs @@ -53,9 +53,7 @@ fn prepare_lto(cgcx: &CodegenContext<LlvmCodegenBackend>, let symbol_filter = &|&(ref name, level): &(String, SymbolExportLevel)| { if level.is_below_threshold(export_threshold) { - let mut bytes = Vec::with_capacity(name.len() + 1); - bytes.extend(name.bytes()); - Some(CString::new(bytes).unwrap()) + Some(CString::new(name.as_str()).unwrap()) } else { None } diff --git a/src/libstd/ffi/c_str.rs b/src/libstd/ffi/c_str.rs index 483f2ba52ec..6dcda986310 100644 --- a/src/libstd/ffi/c_str.rs +++ b/src/libstd/ffi/c_str.rs @@ -327,7 +327,31 @@ impl CString { /// [`NulError`]: struct.NulError.html #[stable(feature = "rust1", since = "1.0.0")] pub fn new<T: Into<Vec<u8>>>(t: T) -> Result<CString, NulError> { - Self::_new(t.into()) + trait SpecIntoVec { + fn into_vec(self) -> Vec<u8>; + } + impl<T: Into<Vec<u8>>> SpecIntoVec for T { + default fn into_vec(self) -> Vec<u8> { + self.into() + } + } + // Specialization for avoiding reallocation. + impl SpecIntoVec for &'_ [u8] { + fn into_vec(self) -> Vec<u8> { + let mut v = Vec::with_capacity(self.len() + 1); + v.extend(self); + v + } + } + impl SpecIntoVec for &'_ str { + fn into_vec(self) -> Vec<u8> { + let mut v = Vec::with_capacity(self.len() + 1); + v.extend(self.as_bytes()); + v + } + } + + Self::_new(SpecIntoVec::into_vec(t)) } fn _new(bytes: Vec<u8>) -> Result<CString, NulError> { diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index af6cb656444..50a1226cc1d 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -297,6 +297,7 @@ #![feature(slice_concat_ext)] #![feature(slice_internals)] #![feature(slice_patterns)] +#![feature(specialization)] #![feature(staged_api)] #![feature(std_internals)] #![feature(stdsimd)] |
