Skip to content

Commit 2aa38ae

Browse files
authored
perf: Use memchr to optimize get_text_slice (#344)
1 parent f1c2e66 commit 2aa38ae

File tree

3 files changed

+64
-44
lines changed

3 files changed

+64
-44
lines changed

fluent-syntax/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ include = [
2525
]
2626

2727
[dependencies]
28+
memchr = "2.0"
2829
serde = { workspace = true, optional = true, features = ["derive"] }
2930
serde_json = { workspace = true, optional = true }
3031
thiserror.workspace = true

fluent-syntax/src/parser/macros.rs

+6
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,9 @@ macro_rules! get_current_byte {
99
$s.source.as_ref().as_bytes().get($s.ptr)
1010
};
1111
}
12+
13+
macro_rules! get_remaining_bytes {
14+
($s:expr) => {
15+
$s.source.as_ref().as_bytes().get($s.ptr..)
16+
};
17+
}

fluent-syntax/src/parser/pattern.rs

+57-44
Original file line numberDiff line numberDiff line change
@@ -157,51 +157,64 @@ where
157157
&mut self,
158158
) -> Result<(usize, usize, TextElementType, TextElementTermination)> {
159159
let start_pos = self.ptr;
160-
let mut text_element_type = TextElementType::Blank;
161-
162-
while let Some(b) = get_current_byte!(self) {
163-
match b {
164-
b' ' => self.ptr += 1,
165-
b'\n' => {
166-
self.ptr += 1;
167-
return Ok((
168-
start_pos,
169-
self.ptr,
170-
text_element_type,
171-
TextElementTermination::LineFeed,
172-
));
173-
}
174-
b'\r' if self.is_byte_at(b'\n', self.ptr + 1) => {
175-
self.ptr += 1;
176-
return Ok((
177-
start_pos,
178-
self.ptr - 1,
179-
text_element_type,
180-
TextElementTermination::Crlf,
181-
));
182-
}
183-
b'{' => {
184-
return Ok((
185-
start_pos,
186-
self.ptr,
187-
text_element_type,
188-
TextElementTermination::PlaceableStart,
189-
));
190-
}
191-
b'}' => {
192-
return error!(ErrorKind::UnbalancedClosingBrace, self.ptr);
193-
}
194-
_ => {
195-
text_element_type = TextElementType::NonBlank;
196-
self.ptr += 1
197-
}
160+
let Some(rest) = get_remaining_bytes!(self) else {
161+
return Ok((
162+
start_pos,
163+
self.ptr,
164+
TextElementType::Blank,
165+
TextElementTermination::Eof,
166+
));
167+
};
168+
let end = memchr::memchr3(b'\n', b'{', b'}', rest);
169+
let element_type = |text: &[u8]| {
170+
if text.iter().any(|&c| c != b' ') {
171+
TextElementType::NonBlank
172+
} else {
173+
TextElementType::Blank
174+
}
175+
};
176+
match end.map(|p| &rest[..=p]) {
177+
Some([text @ .., b'}']) => {
178+
self.ptr += text.len();
179+
error!(ErrorKind::UnbalancedClosingBrace, self.ptr)
180+
}
181+
Some([text @ .., b'\r', b'\n']) => {
182+
self.ptr += text.len() + 1;
183+
Ok((
184+
start_pos,
185+
self.ptr - 1,
186+
element_type(text),
187+
TextElementTermination::Crlf,
188+
))
189+
}
190+
Some([text @ .., b'\n']) => {
191+
self.ptr += text.len() + 1;
192+
Ok((
193+
start_pos,
194+
self.ptr,
195+
element_type(text),
196+
TextElementTermination::LineFeed,
197+
))
198+
}
199+
Some([text @ .., b'{']) => {
200+
self.ptr += text.len();
201+
Ok((
202+
start_pos,
203+
self.ptr,
204+
element_type(text),
205+
TextElementTermination::PlaceableStart,
206+
))
207+
}
208+
None => {
209+
self.ptr += rest.len();
210+
Ok((
211+
start_pos,
212+
self.ptr,
213+
element_type(rest),
214+
TextElementTermination::Eof,
215+
))
198216
}
217+
_ => unreachable!(),
199218
}
200-
Ok((
201-
start_pos,
202-
self.ptr,
203-
text_element_type,
204-
TextElementTermination::Eof,
205-
))
206219
}
207220
}

0 commit comments

Comments
 (0)