Skip to content

Commit 0009fad

Browse files
committed
Rollup merge of #53644 - llogiq:smallvec-for-small-c-str, r=estebank
Use SmallVec for SmallCStr This reuses the awesome optimizations from Servo's `SmallVec` to speed up `SmallCStr`.
2 parents 9dfb95b + 25a83e3 commit 0009fad

File tree

1 file changed

+39
-48
lines changed

1 file changed

+39
-48
lines changed

src/librustc_data_structures/small_c_str.rs

+39-48
Original file line numberDiff line numberDiff line change
@@ -11,69 +11,61 @@
1111
use std::ffi;
1212
use std::ops::Deref;
1313

14-
const SIZE: usize = 38;
14+
use smallvec::SmallVec;
15+
16+
const SIZE: usize = 36;
1517

1618
/// Like SmallVec but for C strings.
1719
#[derive(Clone)]
18-
pub enum SmallCStr {
19-
OnStack {
20-
data: [u8; SIZE],
21-
len_with_nul: u8,
22-
},
23-
OnHeap {
24-
data: ffi::CString,
25-
}
20+
pub struct SmallCStr {
21+
data: SmallVec<[u8; SIZE]>,
2622
}
2723

2824
impl SmallCStr {
2925
#[inline]
3026
pub fn new(s: &str) -> SmallCStr {
31-
if s.len() < SIZE {
32-
let mut data = [0; SIZE];
33-
data[.. s.len()].copy_from_slice(s.as_bytes());
34-
let len_with_nul = s.len() + 1;
35-
36-
// Make sure once that this is a valid CStr
37-
if let Err(e) = ffi::CStr::from_bytes_with_nul(&data[.. len_with_nul]) {
38-
panic!("The string \"{}\" cannot be converted into a CStr: {}", s, e);
39-
}
40-
41-
SmallCStr::OnStack {
42-
data,
43-
len_with_nul: len_with_nul as u8,
44-
}
27+
let len = s.len();
28+
let len1 = len + 1;
29+
let data = if len < SIZE {
30+
let mut buf = [0; SIZE];
31+
buf[..len].copy_from_slice(s.as_bytes());
32+
SmallVec::from_buf_and_len(buf, len1)
4533
} else {
46-
SmallCStr::OnHeap {
47-
data: ffi::CString::new(s).unwrap()
48-
}
34+
let mut data = Vec::with_capacity(len1);
35+
data.extend_from_slice(s.as_bytes());
36+
data.push(0);
37+
SmallVec::from_vec(data)
38+
};
39+
if let Err(e) = ffi::CStr::from_bytes_with_nul(&data) {
40+
panic!("The string \"{}\" cannot be converted into a CStr: {}", s, e);
4941
}
42+
SmallCStr { data }
5043
}
5144

45+
#[inline]
46+
pub fn new_with_nul(s: &str) -> SmallCStr {
47+
let b = s.as_bytes();
48+
if let Err(e) = ffi::CStr::from_bytes_with_nul(b) {
49+
panic!("The string \"{}\" cannot be converted into a CStr: {}", s, e);
50+
}
51+
SmallCStr { data: SmallVec::from_slice(s.as_bytes()) }
52+
}
53+
54+
5255
#[inline]
5356
pub fn as_c_str(&self) -> &ffi::CStr {
54-
match *self {
55-
SmallCStr::OnStack { ref data, len_with_nul } => {
56-
unsafe {
57-
let slice = &data[.. len_with_nul as usize];
58-
ffi::CStr::from_bytes_with_nul_unchecked(slice)
59-
}
60-
}
61-
SmallCStr::OnHeap { ref data } => {
62-
data.as_c_str()
63-
}
57+
unsafe {
58+
ffi::CStr::from_bytes_with_nul_unchecked(&self.data[..])
6459
}
6560
}
6661

6762
#[inline]
6863
pub fn len_with_nul(&self) -> usize {
69-
match *self {
70-
SmallCStr::OnStack { len_with_nul, .. } => {
71-
len_with_nul as usize
72-
}
73-
SmallCStr::OnHeap { ref data } => {
74-
data.as_bytes_with_nul().len()
75-
}
76-
}
64+
self.data.len()
65+
}
66+
67+
pub fn spilled(&self) -> bool {
68+
self.data.spilled()
7769
}
7870
}
7971

@@ -85,7 +77,6 @@ impl Deref for SmallCStr {
8577
}
8678
}
8779

88-
8980
#[test]
9081
fn short() {
9182
const TEXT: &str = "abcd";
@@ -95,7 +86,7 @@ fn short() {
9586

9687
assert_eq!(scs.len_with_nul(), TEXT.len() + 1);
9788
assert_eq!(scs.as_c_str(), reference.as_c_str());
98-
assert!(if let SmallCStr::OnStack { .. } = scs { true } else { false });
89+
assert!(!scs.spilled());
9990
}
10091

10192
#[test]
@@ -107,7 +98,7 @@ fn empty() {
10798

10899
assert_eq!(scs.len_with_nul(), TEXT.len() + 1);
109100
assert_eq!(scs.as_c_str(), reference.as_c_str());
110-
assert!(if let SmallCStr::OnStack { .. } = scs { true } else { false });
101+
assert!(!scs.spilled());
111102
}
112103

113104
#[test]
@@ -121,7 +112,7 @@ fn long() {
121112

122113
assert_eq!(scs.len_with_nul(), TEXT.len() + 1);
123114
assert_eq!(scs.as_c_str(), reference.as_c_str());
124-
assert!(if let SmallCStr::OnHeap { .. } = scs { true } else { false });
115+
assert!(scs.spilled());
125116
}
126117

127118
#[test]

0 commit comments

Comments
 (0)