Skip to content

Commit 6b76997

Browse files
committed
Use a static map to lookup which characters are allowed
Also improves the efficiency of descriptor checksum code.
1 parent 60fde9e commit 6b76997

File tree

2 files changed

+44
-8
lines changed

2 files changed

+44
-8
lines changed

src/descriptor/checksum.rs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
use core::fmt;
99
use core::iter::FromIterator;
1010

11-
pub use crate::expression::INPUT_CHARSET;
11+
pub use crate::expression::VALID_CHARS;
1212
use crate::prelude::*;
1313
use crate::Error;
1414

@@ -101,9 +101,14 @@ impl Engine {
101101
/// state! It is safe to continue feeding it data but the result will not be meaningful.
102102
pub fn input(&mut self, s: &str) -> Result<(), Error> {
103103
for ch in s.chars() {
104-
let pos = INPUT_CHARSET.find(ch).ok_or_else(|| {
105-
Error::BadDescriptor(format!("Invalid character in checksum: '{}'", ch))
106-
})? as u64;
104+
let pos = VALID_CHARS
105+
.get(ch as usize)
106+
.ok_or_else(|| {
107+
Error::BadDescriptor(format!("Invalid character in checksum: '{}'", ch))
108+
})?
109+
.ok_or_else(|| {
110+
Error::BadDescriptor(format!("Invalid character in checksum: '{}'", ch))
111+
})? as u64;
107112
self.c = poly_mod(self.c, pos & 31);
108113
self.cls = self.cls * 3 + (pos >> 5);
109114
self.clscount += 1;

src/expression.rs

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,26 @@ use crate::{errstr, Error, MAX_RECURSION_DEPTH};
1111
/// Allowed characters are descriptor strings.
1212
pub const INPUT_CHARSET: &str = "0123456789()[],'/*abcdefgh@:$%{}IJKLMNOPQRSTUVWXYZ&+-.;<=>?!^_|~ijklmnopqrstuvwxyzABCDEFGH`#\"\\ ";
1313

14+
/// Map of valid characters in descriptor strings.
15+
#[rustfmt::skip]
16+
pub const VALID_CHARS: [Option<u8>; 128] = [
17+
None, None, None, None, None, None, None, None, None, None, None, None, None,
18+
None, None, None, None, None, None, None, None, None, None, None, None, None,
19+
None, None, None, None, None, None, Some(94), Some(59), Some(92), Some(91),
20+
Some(28), Some(29), Some(50), Some(15), Some(10), Some(11), Some(17), Some(51),
21+
Some(14), Some(52), Some(53), Some(16), Some(0), Some(1), Some(2), Some(3),
22+
Some(4), Some(5), Some(6), Some(7), Some(8), Some(9), Some(27), Some(54),
23+
Some(55), Some(56), Some(57), Some(58), Some(26), Some(82), Some(83),
24+
Some(84), Some(85), Some(86), Some(87), Some(88), Some(89), Some(32), Some(33),
25+
Some(34), Some(35), Some(36), Some(37), Some(38), Some(39), Some(40), Some(41),
26+
Some(42), Some(43), Some(44), Some(45), Some(46), Some(47), Some(48), Some(49),
27+
Some(12), Some(93), Some(13), Some(60), Some(61), Some(90), Some(18), Some(19),
28+
Some(20), Some(21), Some(22), Some(23), Some(24), Some(25), Some(64), Some(65),
29+
Some(66), Some(67), Some(68), Some(69), Some(70), Some(71), Some(72), Some(73),
30+
Some(74), Some(75), Some(76), Some(77), Some(78), Some(79), Some(80), Some(81),
31+
Some(30), Some(62), Some(31), Some(63), None,
32+
];
33+
1434
#[derive(Debug)]
1535
/// A token of the form `x(...)` or `x`
1636
pub struct Tree<'a> {
@@ -187,10 +207,12 @@ pub fn check_valid_chars(s: &str) -> Result<(), Error> {
187207
if !ch.is_ascii() {
188208
return Err(Error::Unprintable(ch));
189209
}
190-
// TODO: Avoid linear search overhead by using OnceCell to cache this in a BTreeMap.
191-
INPUT_CHARSET
192-
.find(char::from(ch))
193-
.ok_or_else(|| Error::Unprintable(ch))?;
210+
// Index bounds: We know that ch is ASCII, so it is <= 127.
211+
if VALID_CHARS[ch as usize].is_none() {
212+
return Err(Error::Unexpected(
213+
"Only characters in INPUT_CHARSET are allowed".to_string(),
214+
));
215+
}
194216
}
195217
Ok(())
196218
}
@@ -265,4 +287,13 @@ mod tests {
265287
assert!(parse_num("+6").is_err());
266288
assert!(parse_num("-6").is_err());
267289
}
290+
291+
#[test]
292+
fn test_valid_char_map() {
293+
let mut valid_chars = [None; 128];
294+
for (i, ch) in super::INPUT_CHARSET.chars().enumerate() {
295+
valid_chars[ch as usize] = Some(i as u8);
296+
}
297+
assert_eq!(valid_chars, super::VALID_CHARS);
298+
}
268299
}

0 commit comments

Comments
 (0)