Skip to content

Commit

Permalink
Use SmallVec for SmallCStr
Browse files Browse the repository at this point in the history
  • Loading branch information
llogiq committed Aug 23, 2018
1 parent e5284b0 commit 25a83e3
Showing 1 changed file with 39 additions and 48 deletions.
87 changes: 39 additions & 48 deletions src/librustc_data_structures/small_c_str.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,69 +11,61 @@
use std::ffi;
use std::ops::Deref;

const SIZE: usize = 38;
use smallvec::SmallVec;

const SIZE: usize = 36;

/// Like SmallVec but for C strings.
#[derive(Clone)]
pub enum SmallCStr {
OnStack {
data: [u8; SIZE],
len_with_nul: u8,
},
OnHeap {
data: ffi::CString,
}
pub struct SmallCStr {
data: SmallVec<[u8; SIZE]>,
}

impl SmallCStr {
#[inline]
pub fn new(s: &str) -> SmallCStr {
if s.len() < SIZE {
let mut data = [0; SIZE];
data[.. s.len()].copy_from_slice(s.as_bytes());
let len_with_nul = s.len() + 1;

// Make sure once that this is a valid CStr
if let Err(e) = ffi::CStr::from_bytes_with_nul(&data[.. len_with_nul]) {
panic!("The string \"{}\" cannot be converted into a CStr: {}", s, e);
}

SmallCStr::OnStack {
data,
len_with_nul: len_with_nul as u8,
}
let len = s.len();
let len1 = len + 1;
let data = if len < SIZE {
let mut buf = [0; SIZE];
buf[..len].copy_from_slice(s.as_bytes());
SmallVec::from_buf_and_len(buf, len1)
} else {
SmallCStr::OnHeap {
data: ffi::CString::new(s).unwrap()
}
let mut data = Vec::with_capacity(len1);
data.extend_from_slice(s.as_bytes());
data.push(0);
SmallVec::from_vec(data)
};
if let Err(e) = ffi::CStr::from_bytes_with_nul(&data) {
panic!("The string \"{}\" cannot be converted into a CStr: {}", s, e);
}
SmallCStr { data }
}

#[inline]
pub fn new_with_nul(s: &str) -> SmallCStr {
let b = s.as_bytes();
if let Err(e) = ffi::CStr::from_bytes_with_nul(b) {
panic!("The string \"{}\" cannot be converted into a CStr: {}", s, e);
}
SmallCStr { data: SmallVec::from_slice(s.as_bytes()) }
}


#[inline]
pub fn as_c_str(&self) -> &ffi::CStr {
match *self {
SmallCStr::OnStack { ref data, len_with_nul } => {
unsafe {
let slice = &data[.. len_with_nul as usize];
ffi::CStr::from_bytes_with_nul_unchecked(slice)
}
}
SmallCStr::OnHeap { ref data } => {
data.as_c_str()
}
unsafe {
ffi::CStr::from_bytes_with_nul_unchecked(&self.data[..])
}
}

#[inline]
pub fn len_with_nul(&self) -> usize {
match *self {
SmallCStr::OnStack { len_with_nul, .. } => {
len_with_nul as usize
}
SmallCStr::OnHeap { ref data } => {
data.as_bytes_with_nul().len()
}
}
self.data.len()
}

pub fn spilled(&self) -> bool {
self.data.spilled()
}
}

Expand All @@ -85,7 +77,6 @@ impl Deref for SmallCStr {
}
}


#[test]
fn short() {
const TEXT: &str = "abcd";
Expand All @@ -95,7 +86,7 @@ fn short() {

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

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

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

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

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

#[test]
Expand Down

0 comments on commit 25a83e3

Please sign in to comment.