Skip to content

Commit 6b07eec

Browse files
add token stream back and move pre-allocation (#260)
1 parent f1b6891 commit 6b07eec

File tree

2 files changed

+57
-6
lines changed

2 files changed

+57
-6
lines changed

crates/djls-templates/src/lexer.rs

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use djls_source::Span;
22

33
use crate::tokens::TagDelimiter;
44
use crate::tokens::Token;
5+
use crate::tokens::TokenStream;
56

67
pub struct Lexer {
78
source: String,
@@ -20,11 +21,7 @@ impl Lexer {
2021
}
2122

2223
pub fn tokenize(&mut self) -> Vec<Token> {
23-
// Conservative estimate: most templates have 1 token per 15-20 chars
24-
// Min 32 to avoid reallocation for tiny templates
25-
// Max 1024 to avoid over-allocation for huge templates
26-
let estimated_tokens = (self.source.len() / 15).clamp(32, 1024);
27-
let mut tokens = Vec::with_capacity(estimated_tokens);
24+
let mut tokens = TokenStream::with_estimated_capacity(&self.source);
2825

2926
while !self.is_at_end() {
3027
self.start = self.current;
@@ -59,7 +56,7 @@ impl Lexer {
5956

6057
tokens.push(Token::Eof);
6158

62-
tokens
59+
tokens.into()
6360
}
6461

6562
fn lex_django_tag(

crates/djls-templates/src/tokens.rs

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,3 +289,57 @@ impl TokenSnapshotVec {
289289
self.0.iter().map(Token::to_snapshot).collect()
290290
}
291291
}
292+
293+
#[derive(Debug, Clone)]
294+
pub struct TokenStream(Vec<Token>);
295+
296+
impl TokenStream {
297+
const CHARS_PER_TOKEN: usize = 6;
298+
const MIN_CAPACITY: usize = 32;
299+
const MAX_CAPACITY: usize = 1024;
300+
301+
#[must_use]
302+
pub fn with_estimated_capacity(source: &str) -> Self {
303+
let capacity =
304+
(source.len() / Self::CHARS_PER_TOKEN).clamp(Self::MIN_CAPACITY, Self::MAX_CAPACITY);
305+
Self(Vec::with_capacity(capacity))
306+
}
307+
308+
#[inline]
309+
pub fn push(&mut self, token: Token) {
310+
self.0.push(token);
311+
}
312+
313+
/// Get the number of tokens in the stream.
314+
#[must_use]
315+
pub fn len(&self) -> usize {
316+
self.0.len()
317+
}
318+
319+
/// Get the number of content tokens (excluding EOF).
320+
#[must_use]
321+
pub fn content_len(&self) -> usize {
322+
self.0.len().saturating_sub(1)
323+
}
324+
325+
/// Check if stream is empty.
326+
#[must_use]
327+
pub fn is_empty(&self) -> bool {
328+
self.0.is_empty()
329+
}
330+
}
331+
332+
impl From<TokenStream> for Vec<Token> {
333+
fn from(val: TokenStream) -> Self {
334+
val.0
335+
}
336+
}
337+
338+
impl IntoIterator for TokenStream {
339+
type Item = Token;
340+
type IntoIter = std::vec::IntoIter<Token>;
341+
342+
fn into_iter(self) -> Self::IntoIter {
343+
self.0.into_iter()
344+
}
345+
}

0 commit comments

Comments
 (0)