Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

perf: using Arc<str> instead of String #84

Merged
merged 3 commits into from
Mar 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 14 additions & 13 deletions src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use std::env;
use std::fs;
use std::io::Read;
use std::path::{Path, PathBuf};
use std::sync::Arc;

use debugid::DebugId;
use rustc_hash::FxHashMap;
Expand All @@ -19,14 +20,14 @@ use crate::types::{RawToken, SourceMap, Token};
/// objects is generally not very comfortable. As a general aid this
/// type can help.
pub struct SourceMapBuilder {
file: Option<String>,
name_map: FxHashMap<String, u32>,
names: Vec<String>,
file: Option<Arc<str>>,
name_map: FxHashMap<Arc<str>, u32>,
names: Vec<Arc<str>>,
tokens: Vec<RawToken>,
source_map: FxHashMap<String, u32>,
source_root: Option<String>,
sources: Vec<String>,
source_contents: Vec<Option<String>>,
source_map: FxHashMap<Arc<str>, u32>,
source_root: Option<Arc<str>>,
sources: Vec<Arc<str>>,
source_contents: Vec<Option<Arc<str>>>,
sources_mapping: Vec<u32>,
debug_id: Option<DebugId>,
}
Expand All @@ -52,7 +53,7 @@ impl SourceMapBuilder {
/// Creates a new source map builder and sets the file.
pub fn new(file: Option<&str>) -> SourceMapBuilder {
SourceMapBuilder {
file: file.map(str::to_owned),
file: file.map(Into::into),
name_map: FxHashMap::default(),
names: vec![],
tokens: vec![],
Expand All @@ -71,7 +72,7 @@ impl SourceMapBuilder {
}

/// Sets the file for the sourcemap (optional)
pub fn set_file<T: Into<String>>(&mut self, value: Option<T>) {
pub fn set_file<T: Into<Arc<str>>>(&mut self, value: Option<T>) {
self.file = value.map(Into::into);
}

Expand All @@ -81,7 +82,7 @@ impl SourceMapBuilder {
}

/// Sets a new value for the source_root.
pub fn set_source_root<T: Into<String>>(&mut self, value: Option<T>) {
pub fn set_source_root<T: Into<Arc<str>>>(&mut self, value: Option<T>) {
self.source_root = value.map(Into::into);
}

Expand All @@ -108,7 +109,7 @@ impl SourceMapBuilder {
/// Changes the source name for an already set source.
pub fn set_source(&mut self, src_id: u32, src: &str) {
assert!(src_id != !0, "Cannot set sources for tombstone source id");
self.sources[src_id as usize] = src.to_string();
self.sources[src_id as usize] = src.into();
}

/// Looks up a source name for an ID.
Expand All @@ -122,7 +123,7 @@ impl SourceMapBuilder {
if self.sources.len() > self.source_contents.len() {
self.source_contents.resize(self.sources.len(), None);
}
self.source_contents[src_id as usize] = contents.map(str::to_owned);
self.source_contents[src_id as usize] = contents.map(Into::into);
}

/// Returns the current source contents for a source.
Expand Down Expand Up @@ -272,7 +273,7 @@ impl SourceMapBuilder {
prefix.push('/');
}
if source.starts_with(&prefix) {
*source = source[prefix.len()..].to_string();
*source = source[prefix.len()..].into();
break;
}
}
Expand Down
20 changes: 14 additions & 6 deletions src/decoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -187,26 +187,34 @@ pub fn decode_regular(rsm: RawSourceMap) -> Result<SourceMap> {
}
}

let sources = sources.into_iter().map(Option::unwrap_or_default).collect();
let sources = sources
.into_iter()
.map(Option::unwrap_or_default)
.map(Into::into)
.collect();

// apparently we can encounter some non string types in real world
// sourcemaps :(
let names = names
.into_iter()
.map(|val| match val {
Value::String(s) => s,
Value::Number(num) => num.to_string(),
Value::String(s) => s.into(),
Value::Number(num) => num.to_string().into(),
_ => "".into(),
})
.collect::<Vec<String>>();
.collect::<Vec<_>>();

// file sometimes is not a string for unexplicable reasons
let file = rsm.file.map(|val| match val {
Value::String(s) => s,
Value::String(s) => s.into(),
_ => "<invalid>".into(),
});

let mut sm = SourceMap::new(file, tokens, names, sources, rsm.sources_content);
let source_content = rsm
.sources_content
.map(|x| x.into_iter().map(|v| v.map(Into::into)).collect::<Vec<_>>());

let mut sm = SourceMap::new(file, tokens, names, sources, source_content);
sm.set_source_root(rsm.source_root);
sm.set_debug_id(rsm.debug_id);

Expand Down
10 changes: 5 additions & 5 deletions src/ram_bundle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,9 @@ impl<'a> RamBundleModule<'a> {
/// Returns a source view of the data.
///
/// This operation fails if the source code is not valid UTF-8.
pub fn source_view(&self) -> Result<SourceView<'a>> {
pub fn source_view(&self) -> Result<SourceView> {
match std::str::from_utf8(self.data) {
Ok(s) => Ok(SourceView::new(s)),
Ok(s) => Ok(SourceView::new(s.into())),
Err(e) => Err(Error::Utf8(e)),
}
}
Expand Down Expand Up @@ -361,7 +361,7 @@ impl<'a> SplitRamBundleModuleIter<'a> {
fn split_module(
&self,
module: RamBundleModule<'a>,
) -> Result<Option<(String, SourceView<'a>, SourceMap)>> {
) -> Result<Option<(String, SourceView, SourceMap)>> {
let module_offset = self
.offsets
.get(module.id())
Expand All @@ -377,7 +377,7 @@ impl<'a> SplitRamBundleModuleIter<'a> {
return Err(Error::InvalidRamBundleEntry);
}

let source: SourceView<'a> = module.source_view()?;
let source: SourceView = module.source_view()?;
let line_count = source.line_count() as u32;
let ending_line = starting_line + line_count;
let last_line_len = source
Expand Down Expand Up @@ -416,7 +416,7 @@ impl<'a> SplitRamBundleModuleIter<'a> {
}

impl<'a> Iterator for SplitRamBundleModuleIter<'a> {
type Item = Result<(String, SourceView<'a>, SourceMap)>;
type Item = Result<(String, SourceView, SourceMap)>;

fn next(&mut self) -> Option<Self::Item> {
while let Some(module_result) = self.ram_bundle_iter.next() {
Expand Down
55 changes: 23 additions & 32 deletions src/sourceview.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use std::borrow::Cow;
use std::fmt;
use std::slice;
use std::str;
use std::sync::atomic::AtomicUsize;
use std::sync::atomic::Ordering;
use std::sync::Arc;
use std::sync::Mutex;

use if_chain::if_chain;
Expand All @@ -14,19 +14,13 @@ use crate::js_identifiers::{get_javascript_token, is_valid_javascript_identifier
use crate::types::{idx_from_token, sourcemap_from_token, Token};

/// An iterator that iterates over tokens in reverse.
pub struct RevTokenIter<'view, 'viewbase, 'map>
where
'viewbase: 'view,
{
sv: &'view SourceView<'viewbase>,
pub struct RevTokenIter<'view, 'map> {
sv: &'view SourceView,
token: Option<Token<'map>>,
source_line: Option<(&'view str, usize, usize, usize)>,
}

impl<'view, 'viewbase, 'map> Iterator for RevTokenIter<'view, 'viewbase, 'map>
where
'viewbase: 'view,
{
impl<'view, 'map> Iterator for RevTokenIter<'view, 'map> {
type Item = (Token<'map>, Option<&'view str>);

fn next(&mut self) -> Option<(Token<'map>, Option<&'view str>)> {
Expand Down Expand Up @@ -118,7 +112,7 @@ where
}

pub struct Lines<'a> {
sv: &'a SourceView<'a>,
sv: &'a SourceView,
idx: u32,
}

Expand All @@ -139,14 +133,14 @@ impl<'a> Iterator for Lines<'a> {
///
/// This type is used to implement fairly efficient source mapping
/// operations.
pub struct SourceView<'a> {
source: Cow<'a, str>,
pub struct SourceView {
source: Arc<str>,
processed_until: AtomicUsize,
lines: Mutex<Vec<&'static str>>,
}

impl<'a> Clone for SourceView<'a> {
fn clone(&self) -> SourceView<'a> {
impl Clone for SourceView {
fn clone(&self) -> SourceView {
SourceView {
source: self.source.clone(),
processed_until: AtomicUsize::new(0),
Expand All @@ -155,28 +149,28 @@ impl<'a> Clone for SourceView<'a> {
}
}

impl<'a> fmt::Debug for SourceView<'a> {
impl fmt::Debug for SourceView {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("SourceView")
.field("source", &self.source())
.finish()
}
}

impl<'a> SourceView<'a> {
impl SourceView {
/// Creates an optimized view of a given source.
pub fn new(source: &'a str) -> SourceView<'a> {
pub fn new(source: Arc<str>) -> SourceView {
SourceView {
source: Cow::Borrowed(source),
source,
processed_until: AtomicUsize::new(0),
lines: Mutex::new(vec![]),
}
}

/// Creates an optimized view from a given source string
pub fn from_string(source: String) -> SourceView<'static> {
pub fn from_string(source: String) -> SourceView {
SourceView {
source: Cow::Owned(source),
source: source.into(),
processed_until: AtomicUsize::new(0),
lines: Mutex::new(vec![]),
}
Expand Down Expand Up @@ -264,7 +258,7 @@ impl<'a> SourceView<'a> {
}

/// Returns an iterator over all lines.
pub fn lines(&'a self) -> Lines<'a> {
pub fn lines(&self) -> Lines {
Lines { sv: self, idx: 0 }
}

Expand All @@ -273,10 +267,7 @@ impl<'a> SourceView<'a> {
&self.source
}

fn rev_token_iter<'this, 'map>(
&'this self,
token: Token<'map>,
) -> RevTokenIter<'this, 'a, 'map> {
fn rev_token_iter<'this, 'map>(&'this self, token: Token<'map>) -> RevTokenIter<'this, 'map> {
RevTokenIter {
sv: self,
token: Some(token),
Expand Down Expand Up @@ -332,7 +323,7 @@ impl<'a> SourceView<'a> {
#[test]
#[allow(clippy::cognitive_complexity)]
fn test_minified_source_view() {
let view = SourceView::new("a\nb\nc");
let view = SourceView::new("a\nb\nc".into());
assert_eq!(view.get_line(0), Some("a"));
assert_eq!(view.get_line(0), Some("a"));
assert_eq!(view.get_line(2), Some("c"));
Expand All @@ -341,7 +332,7 @@ fn test_minified_source_view() {

assert_eq!(view.line_count(), 3);

let view = SourceView::new("a\r\nb\r\nc");
let view = SourceView::new("a\r\nb\r\nc".into());
assert_eq!(view.get_line(0), Some("a"));
assert_eq!(view.get_line(0), Some("a"));
assert_eq!(view.get_line(2), Some("c"));
Expand All @@ -350,7 +341,7 @@ fn test_minified_source_view() {

assert_eq!(view.line_count(), 3);

let view = SourceView::new("abc👌def\nblah");
let view = SourceView::new("abc👌def\nblah".into());
assert_eq!(view.get_line_slice(0, 0, 3), Some("abc"));
assert_eq!(view.get_line_slice(0, 3, 1), Some("👌"));
assert_eq!(view.get_line_slice(0, 3, 2), Some("👌"));
Expand All @@ -362,7 +353,7 @@ fn test_minified_source_view() {
assert_eq!(view.get_line_slice(1, 0, 5), None);
assert_eq!(view.get_line_slice(1, 0, 12), None);

let view = SourceView::new("a\nb\nc\n");
let view = SourceView::new("a\nb\nc\n".into());
assert_eq!(view.get_line(0), Some("a"));
assert_eq!(view.get_line(1), Some("b"));
assert_eq!(view.get_line(2), Some("c"));
Expand All @@ -371,6 +362,6 @@ fn test_minified_source_view() {

fn is_send<T: Send>() {}
fn is_sync<T: Sync>() {}
is_send::<SourceView<'static>>();
is_sync::<SourceView<'static>>();
is_send::<SourceView>();
is_sync::<SourceView>();
}
Loading
Loading