Skip to content

Instantly share code, notes, and snippets.

@mhseiden
Created June 5, 2017 05:43
Show Gist options
  • Save mhseiden/254ca2426b90f7572a02a466232e3b8a to your computer and use it in GitHub Desktop.
Save mhseiden/254ca2426b90f7572a02a466232e3b8a to your computer and use it in GitHub Desktop.
A basic and incomplete implementation of a compact string.
use std::{fmt, mem, slice, str};
use std::ops::Deref;
const HEAP_STRING_FLAG: u8 = 1u8 << 7;
const MAX_INLINE_LENGTH: usize = 15;
#[repr(packed)]
#[derive(Default)]
pub struct CompactString {
flag: u8, // 1 byte
data: [u8; MAX_INLINE_LENGTH], // 15 bytes
}
#[repr(packed)]
struct CompactHeapString {
_flag: u8, // 1 byte
len: u32, // 4 bytes
ptr: *const u8, // 8 bytes
_padding: [u8; 3], // 3 bytes
}
impl CompactString {
fn new(s: &str) -> CompactString {
if s.is_empty() {
CompactString::default()
} else if s.len() <= MAX_INLINE_LENGTH {
let mut data = [0u8; MAX_INLINE_LENGTH];
data[0..s.len()].copy_from_slice(s.as_bytes());
CompactString {
flag: s.len() as u8,
data: data,
}
} else {
let heap_data = s.as_bytes().to_vec();
let len = s.len();
let ptr = heap_data.as_ptr();
mem::forget(heap_data);
unsafe {
mem::transmute(CompactHeapString {
_flag: HEAP_STRING_FLAG,
len: len as u32,
ptr: ptr,
_padding: Default::default(),
})
}
}
}
}
impl Deref for CompactString {
type Target = str;
fn deref(&self) -> &Self::Target {
if 0 != (self.flag & HEAP_STRING_FLAG) {
unsafe {
let chs = mem::transmute::<_, &CompactHeapString>(self);
let bytes = slice::from_raw_parts(chs.ptr, chs.len as usize);
str::from_utf8_unchecked(bytes)
}
} else {
unsafe {
let bytes = slice::from_raw_parts(self.data.as_ptr(), self.flag as usize);
str::from_utf8_unchecked(bytes)
}
}
}
}
impl fmt::Display for CompactString {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(f, "{}", self.deref())
}
}
impl fmt::Debug for CompactString {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(f, "{:?}", self.deref())
}
}
fn main() {
let short_string = "hello world";
let short_compact_string = CompactString::new(short_string);
println!("{}", short_compact_string);
assert_eq!(short_string, &*short_compact_string);
let long_string = "the quick brown fox jumped over the lazy dog";
let long_compact_string = CompactString::new(long_string);
println!("{}", long_compact_string);
assert_eq!(long_string, &*long_compact_string);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment