Skip to content

Commit c8fb27d

Browse files
authored
Rollup merge of rust-lang#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%.
2 parents 4d96185 + 23cb1d5 commit c8fb27d

File tree

3 files changed

+27
-4
lines changed

3 files changed

+27
-4
lines changed

src/librustc_codegen_llvm/back/lto.rs

+1-3
Original file line numberDiff line numberDiff line change
@@ -53,9 +53,7 @@ fn prepare_lto(cgcx: &CodegenContext<LlvmCodegenBackend>,
5353

5454
let symbol_filter = &|&(ref name, level): &(String, SymbolExportLevel)| {
5555
if level.is_below_threshold(export_threshold) {
56-
let mut bytes = Vec::with_capacity(name.len() + 1);
57-
bytes.extend(name.bytes());
58-
Some(CString::new(bytes).unwrap())
56+
Some(CString::new(name.as_str()).unwrap())
5957
} else {
6058
None
6159
}

src/libstd/ffi/c_str.rs

+25-1
Original file line numberDiff line numberDiff line change
@@ -327,7 +327,31 @@ impl CString {
327327
/// [`NulError`]: struct.NulError.html
328328
#[stable(feature = "rust1", since = "1.0.0")]
329329
pub fn new<T: Into<Vec<u8>>>(t: T) -> Result<CString, NulError> {
330-
Self::_new(t.into())
330+
trait SpecIntoVec {
331+
fn into_vec(self) -> Vec<u8>;
332+
}
333+
impl<T: Into<Vec<u8>>> SpecIntoVec for T {
334+
default fn into_vec(self) -> Vec<u8> {
335+
self.into()
336+
}
337+
}
338+
// Specialization for avoiding reallocation.
339+
impl SpecIntoVec for &'_ [u8] {
340+
fn into_vec(self) -> Vec<u8> {
341+
let mut v = Vec::with_capacity(self.len() + 1);
342+
v.extend(self);
343+
v
344+
}
345+
}
346+
impl SpecIntoVec for &'_ str {
347+
fn into_vec(self) -> Vec<u8> {
348+
let mut v = Vec::with_capacity(self.len() + 1);
349+
v.extend(self.as_bytes());
350+
v
351+
}
352+
}
353+
354+
Self::_new(SpecIntoVec::into_vec(t))
331355
}
332356

333357
fn _new(bytes: Vec<u8>) -> Result<CString, NulError> {

src/libstd/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,7 @@
297297
#![feature(slice_concat_ext)]
298298
#![feature(slice_internals)]
299299
#![feature(slice_patterns)]
300+
#![feature(specialization)]
300301
#![feature(staged_api)]
301302
#![feature(std_internals)]
302303
#![feature(stdsimd)]

0 commit comments

Comments
 (0)