Skip to content

Commit 78d0e23

Browse files
committed
perf(printf): optimize shell metacharacter lookup with O(1) lookup table
Replace linear search through SHELL_META_CHARS string with a const lookup table for O(1) character classification. This improves performance for the printf %q implementation without changing behavior. - Add SHELL_META_LOOKUP static array initialized at compile time - Add is_shell_meta() helper using the lookup table - Remove unused SHELL_META_CHARS constant
1 parent ee02b5e commit 78d0e23

File tree

2 files changed

+20
-6
lines changed

2 files changed

+20
-6
lines changed

.vscode/cspell.dictionaries/jargon.wordlist.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ lossily
8484
lstat
8585
mebi
8686
mebibytes
87+
metacharacter
8788
metacharacters
8889
mergeable
8990
microbenchmark

src/uucore/src/lib/features/quoting_style/printf_quoter.rs

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,26 +14,39 @@
1414
1515
use super::Quoter;
1616

17-
/// Characters that need escaping in shell context
17+
/// Lookup table for shell metacharacters (for O(1) lookup)
1818
/// Note: Tilde (~) is NOT escaped by bash printf %q
19-
const SHELL_META_CHARS: &str = " \t\n'\"\\`$&|;()<>[]{}*?!#";
19+
static SHELL_META_LOOKUP: [bool; 256] = const {
20+
let mut lookup = [false; 256];
21+
let meta = b" \t\n'\"\\`$&|;()<>[]{}*?!#";
22+
let mut i = 0;
23+
while i < meta.len() {
24+
lookup[meta[i] as usize] = true;
25+
i += 1;
26+
}
27+
lookup
28+
};
2029

2130
/// Check if a byte is a control character
2231
#[inline]
2332
fn is_control(b: u8) -> bool {
2433
b < 0x20 || b == 0x7F
2534
}
2635

36+
/// Check if a byte is a shell metacharacter
37+
#[inline]
38+
fn is_shell_meta(b: u8) -> bool {
39+
SHELL_META_LOOKUP[b as usize]
40+
}
41+
2742
/// Check if string contains any control characters
2843
fn has_control_chars(s: &[u8]) -> bool {
2944
s.iter().any(|&b| is_control(b))
3045
}
3146

3247
/// Check if string needs any quoting at all
3348
fn needs_quoting(s: &[u8]) -> bool {
34-
s.is_empty()
35-
|| s.iter()
36-
.any(|&b| SHELL_META_CHARS.as_bytes().contains(&b) || is_control(b))
49+
s.is_empty() || s.iter().any(|&b| is_shell_meta(b) || is_control(b))
3750
}
3851

3952
pub(super) struct PrintfQuoter;
@@ -65,7 +78,7 @@ impl PrintfQuoter {
6578
let mut result = Vec::with_capacity(input.len() * 2);
6679

6780
for &b in input {
68-
if SHELL_META_CHARS.as_bytes().contains(&b) {
81+
if is_shell_meta(b) {
6982
result.push(b'\\');
7083
}
7184
result.push(b);

0 commit comments

Comments
 (0)