Skip to content

Commit 725c11e

Browse files
committed
Add SmallStr
1 parent ea0a31f commit 725c11e

File tree

4 files changed

+90
-1
lines changed

4 files changed

+90
-1
lines changed

compiler/rustc_data_structures/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ stable_deref_trait = "1.0.0"
2020
rayon = { version = "0.3.2", package = "rustc-rayon" }
2121
rayon-core = { version = "0.3.2", package = "rustc-rayon-core" }
2222
rustc-hash = "1.1.0"
23-
smallvec = { version = "1.6.1", features = ["union", "may_dangle"] }
23+
smallvec = { version = "1.6.1", features = ["const_generics", "union", "may_dangle"] }
2424
rustc_index = { path = "../rustc_index", package = "rustc_index" }
2525
bitflags = "1.2.1"
2626
measureme = "10.0.0"

compiler/rustc_data_structures/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ pub mod obligation_forest;
8080
pub mod owning_ref;
8181
pub mod sip128;
8282
pub mod small_c_str;
83+
pub mod small_str;
8384
pub mod snapshot_map;
8485
pub mod stable_map;
8586
pub mod svh;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
use smallvec::SmallVec;
2+
3+
#[cfg(test)]
4+
mod tests;
5+
6+
/// Like SmallVec but for strings.
7+
#[derive(Default)]
8+
pub struct SmallStr<const N: usize>(SmallVec<[u8; N]>);
9+
10+
impl<const N: usize> SmallStr<N> {
11+
#[inline]
12+
pub fn new() -> Self {
13+
SmallStr(SmallVec::default())
14+
}
15+
16+
#[inline]
17+
pub fn push_str(&mut self, s: &str) {
18+
self.0.extend_from_slice(s.as_bytes());
19+
}
20+
21+
#[inline]
22+
pub fn empty(&self) -> bool {
23+
self.0.is_empty()
24+
}
25+
26+
#[inline]
27+
pub fn spilled(&self) -> bool {
28+
self.0.spilled()
29+
}
30+
31+
#[inline]
32+
pub fn as_str(&self) -> &str {
33+
unsafe { std::str::from_utf8_unchecked(self.0.as_slice()) }
34+
}
35+
}
36+
37+
impl<const N: usize> std::ops::Deref for SmallStr<N> {
38+
type Target = str;
39+
40+
#[inline]
41+
fn deref(&self) -> &str {
42+
self.as_str()
43+
}
44+
}
45+
46+
impl<const N: usize, A: AsRef<str>> FromIterator<A> for SmallStr<N> {
47+
#[inline]
48+
fn from_iter<T>(iter: T) -> Self
49+
where
50+
T: IntoIterator<Item = A>,
51+
{
52+
let mut s = SmallStr::default();
53+
s.extend(iter);
54+
s
55+
}
56+
}
57+
58+
impl<const N: usize, A: AsRef<str>> Extend<A> for SmallStr<N> {
59+
#[inline]
60+
fn extend<T>(&mut self, iter: T)
61+
where
62+
T: IntoIterator<Item = A>,
63+
{
64+
for a in iter.into_iter() {
65+
self.push_str(a.as_ref());
66+
}
67+
}
68+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
use super::*;
2+
3+
#[test]
4+
fn empty() {
5+
let s = SmallStr::<1>::new();
6+
assert!(s.empty());
7+
assert_eq!("", s.as_str());
8+
assert!(!s.spilled());
9+
}
10+
11+
#[test]
12+
fn from_iter() {
13+
let s = ["aa", "bb", "cc"].iter().collect::<SmallStr<6>>();
14+
assert_eq!("aabbcc", s.as_str());
15+
assert!(!s.spilled());
16+
17+
let s = ["aa", "bb", "cc", "dd"].iter().collect::<SmallStr<6>>();
18+
assert_eq!("aabbccdd", s.as_str());
19+
assert!(s.spilled());
20+
}

0 commit comments

Comments
 (0)