From 1fa5b2ffbc0f1dd3cfc45adff0329e1bdd46c131 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Wed, 8 Aug 2018 20:25:35 +0300 Subject: [PATCH] smol strings --- src/lib.rs | 1 + src/smol_str.rs | 60 +++++++++++++++++++++++++++++++++++++++++++++ src/yellow/green.rs | 7 +++--- 3 files changed, 65 insertions(+), 3 deletions(-) create mode 100644 src/smol_str.rs diff --git a/src/lib.rs b/src/lib.rs index 0ae8082f12..91b0c9c552 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -35,6 +35,7 @@ mod grammar; mod parser_impl; mod syntax_kinds; +mod smol_str; mod yellow; /// Utilities for simple uses of the parser. pub mod utils; diff --git a/src/smol_str.rs b/src/smol_str.rs new file mode 100644 index 0000000000..2a330c343d --- /dev/null +++ b/src/smol_str.rs @@ -0,0 +1,60 @@ +use std::{sync::Arc}; + +const INLINE_CAP: usize = 22; + +#[derive(Clone, Debug)] +pub(crate) enum SmolStr { + Heap(Arc), + Inline { + len: u8, + buf: [u8; INLINE_CAP], + }, +} + +impl SmolStr { + pub fn new(text: &str) -> SmolStr { + let len = text.len(); + if len <= INLINE_CAP { + let mut buf = [0; INLINE_CAP]; + buf[..len].copy_from_slice(text.as_bytes()); + SmolStr::Inline { len: len as u8, buf } + } else { + SmolStr::Heap( + text.to_string().into_boxed_str().into() + ) + } + } + + pub fn as_str(&self) -> &str { + match self { + SmolStr::Heap(data) => &*data, + SmolStr::Inline { len, buf } => { + let len = *len as usize; + let buf = &buf[..len]; + unsafe { ::std::str::from_utf8_unchecked(buf) } + } + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + #[cfg(target_pointer_width = "64")] + fn smol_str_is_smol() { + assert_eq!(::std::mem::size_of::(), 8 + 8 + 8) + } + + #[test] + fn test_round_trip() { + let mut text = String::new(); + for n in 0..256 { + let smol = SmolStr::new(&text); + assert_eq!(smol.as_str(), text.as_str()); + text.push_str(&n.to_string()); + } + } +} + diff --git a/src/yellow/green.rs b/src/yellow/green.rs index 3ade46f458..26df76af68 100644 --- a/src/yellow/green.rs +++ b/src/yellow/green.rs @@ -1,5 +1,6 @@ use std::sync::Arc; use { + smol_str::SmolStr, SyntaxKind::{self, *}, TextUnit, }; @@ -116,7 +117,7 @@ pub(crate) enum GreenLeaf { }, Token { kind: SyntaxKind, - text: Option>, + text: Option, }, } @@ -137,7 +138,7 @@ impl GreenLeaf { debug_assert_eq!(t, text); None } - None => Some(text.to_owned().into_boxed_str().into()), + None => Some(SmolStr::new(text)), }; GreenLeaf::Token { kind, text } } @@ -159,7 +160,7 @@ impl GreenLeaf { } GreenLeaf::Token { kind, text } => match text { None => kind.static_text().unwrap(), - Some(t) => t, + Some(t) => t.as_str(), }, } }