mirror of
https://github.com/danbulant/oxc
synced 2026-05-19 12:19:15 +00:00
feat(sourcemap): add ConcatSourceMapBuilder::from_sourcemaps (#4639)
Introduce new method `ConcatSourceMapBuilder::from_sourcemaps`.
Where all the sourcemaps being concatenated exist at time that you
create `ConcatSourceMapBuilder`, it's faster to use `from_sourcemaps`,
because it pre-allocates enough space for the data it will hold and so
avoids memory copying.
Before:
```rs
let mut builder = ConcatSourceMapBuilder::default();
builder.add_sourcemap(&sourcemap1, 0);
builder.add_sourcemap(&sourcemap2, 100);
builder.add_sourcemap(&sourcemap3, 100);
let combined = builder.into_sourcemap();
```
After:
```rs
let builder = ConcatSourceMapBuilder::from_sourcemaps(&[
(&sourcemap1, 0),
(&sourcemap2, 100),
(&sourcemap3, 200),
]);
let combined = builder.into_sourcemap();
```
This commit is contained in:
parent
9be29af9d4
commit
e42ac3a2a0
2 changed files with 84 additions and 9 deletions
|
|
@ -16,6 +16,66 @@ pub struct ConcatSourceMapBuilder {
|
|||
|
||||
#[allow(clippy::cast_possible_truncation)]
|
||||
impl ConcatSourceMapBuilder {
|
||||
/// Create new `ConcatSourceMapBuilder` with pre-allocated capacity.
|
||||
///
|
||||
/// Allocating capacity before adding sourcemaps with `add_sourcemap` avoids memory copies
|
||||
/// and increases performance.
|
||||
///
|
||||
/// Alternatively, use `from_sourcemaps`.
|
||||
pub fn with_capacity(
|
||||
names_len: usize,
|
||||
sources_len: usize,
|
||||
tokens_len: usize,
|
||||
token_chunks_len: usize,
|
||||
) -> Self {
|
||||
Self {
|
||||
names: Vec::with_capacity(names_len),
|
||||
sources: Vec::with_capacity(sources_len),
|
||||
source_contents: Vec::with_capacity(sources_len),
|
||||
tokens: Vec::with_capacity(tokens_len),
|
||||
token_chunks: Vec::with_capacity(token_chunks_len),
|
||||
token_chunk_prev_name_id: 0,
|
||||
}
|
||||
}
|
||||
|
||||
/// Create new `ConcatSourceMapBuilder` from an array of `SourceMap`s and line offsets.
|
||||
///
|
||||
/// This avoids memory copies versus creating builder with `ConcatSourceMapBuilder::default()`
|
||||
/// and then adding sourcemaps individually with `add_sourcemap`.
|
||||
///
|
||||
/// # Example
|
||||
/// ```
|
||||
/// let builder = ConcatSourceMapBuilder::from_sourcemaps(&[
|
||||
/// (&sourcemap1, 0),
|
||||
/// (&sourcemap2, 100),
|
||||
/// ]);
|
||||
/// let combined_sourcemap = builder.into_sourcemap();
|
||||
/// ```
|
||||
pub fn from_sourcemaps(sourcemap_and_line_offsets: &[(&SourceMap, u32)]) -> Self {
|
||||
// Calculate length of `Vec`s required
|
||||
let mut names_len = 0;
|
||||
let mut sources_len = 0;
|
||||
let mut tokens_len = 0;
|
||||
for (sourcemap, _) in sourcemap_and_line_offsets {
|
||||
names_len += sourcemap.names.len();
|
||||
sources_len += sourcemap.sources.len();
|
||||
tokens_len += sourcemap.tokens.len();
|
||||
}
|
||||
|
||||
let mut builder = Self::with_capacity(
|
||||
names_len,
|
||||
sources_len,
|
||||
tokens_len,
|
||||
sourcemap_and_line_offsets.len(),
|
||||
);
|
||||
|
||||
for (sourcemap, line_offset) in sourcemap_and_line_offsets.iter().copied() {
|
||||
builder.add_sourcemap(sourcemap, line_offset);
|
||||
}
|
||||
|
||||
builder
|
||||
}
|
||||
|
||||
pub fn add_sourcemap(&mut self, sourcemap: &SourceMap, line_offset: u32) {
|
||||
let source_offset = self.sources.len() as u32;
|
||||
let name_offset = self.names.len() as u32;
|
||||
|
|
@ -92,9 +152,27 @@ impl ConcatSourceMapBuilder {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "concurrent")]
|
||||
#[test]
|
||||
fn test_concat_sourcemap_builder() {
|
||||
run_test(|sourcemap_and_line_offsets| {
|
||||
let mut builder = ConcatSourceMapBuilder::default();
|
||||
for (sourcemap, line_offset) in sourcemap_and_line_offsets.iter().copied() {
|
||||
builder.add_sourcemap(sourcemap, line_offset);
|
||||
}
|
||||
builder
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_concat_sourcemap_builder_from_sourcemaps() {
|
||||
run_test(ConcatSourceMapBuilder::from_sourcemaps);
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
fn run_test<F>(create_builder: F)
|
||||
where
|
||||
F: Fn(&[(&SourceMap, u32)]) -> ConcatSourceMapBuilder,
|
||||
{
|
||||
let sm1 = SourceMap::new(
|
||||
None,
|
||||
vec!["foo".into(), "foo2".into()],
|
||||
|
|
@ -123,10 +201,7 @@ fn test_concat_sourcemap_builder() {
|
|||
None,
|
||||
);
|
||||
|
||||
let mut builder = ConcatSourceMapBuilder::default();
|
||||
builder.add_sourcemap(&sm1, 0);
|
||||
builder.add_sourcemap(&sm2, 2);
|
||||
builder.add_sourcemap(&sm3, 2);
|
||||
let builder = create_builder(&[(&sm1, 0), (&sm2, 2), (&sm3, 2)]);
|
||||
|
||||
let sm = SourceMap::new(
|
||||
None,
|
||||
|
|
|
|||
|
|
@ -27,10 +27,10 @@ fn bench_sourcemap(criterion: &mut Criterion) {
|
|||
.enable_source_map(file.file_name.as_str(), source_text)
|
||||
.build(&ret.program);
|
||||
if let Some(sourcemap) = source_map {
|
||||
let mut concat_sourcemap_builder = ConcatSourceMapBuilder::default();
|
||||
for i in 0..2 {
|
||||
concat_sourcemap_builder.add_sourcemap(&sourcemap, lines * i);
|
||||
}
|
||||
let concat_sourcemap_builder = ConcatSourceMapBuilder::from_sourcemaps(&[
|
||||
(&sourcemap, 0),
|
||||
(&sourcemap, lines),
|
||||
]);
|
||||
concat_sourcemap_builder.into_sourcemap().to_json_string();
|
||||
}
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in a new issue