Optimize color::try_parse_rgb()

The function was repeatedly calling `s.char_at(n)` which is O(1) only for UTF-32
strings (so not a problem at the moment). But it was also calling `hex_digit(n)`
twice for each `n` in the 3-digit case, causing unnecessary repeated parsing of
individual characters into their radix-16 numeric equivalents, which could be
avoided just by reusing the already calculated result.
This commit is contained in:
Mahmoud Al-Qudsi 2024-05-07 12:53:44 -05:00
parent ebbba10608
commit 5b79f267d6

View file

@ -257,34 +257,36 @@ impl RgbColor {
/// - `FA3` /// - `FA3`
/// - `F3A035` /// - `F3A035`
/// Parses input in the form of `#RGB` or `#RRGGBB` with an optional single leading `#` into
/// an instance of [`RgbColor`].
///
/// Returns `None` if the input contains invalid hexadecimal characters or is not in the
/// expected `#RGB` or `#RRGGBB` formats.
fn try_parse_rgb(mut s: &wstr) -> Option<Self> { fn try_parse_rgb(mut s: &wstr) -> Option<Self> {
// Skip any leading #. // Skip one leading #
if s.chars().next()? == '#' { if s.chars().next()? == '#' {
s = &s[1..]; s = &s[1..];
} }
let hex_digit = |i| -> Option<u8> { let mut hex = s.chars().map_while(|c| c.to_digit(16).map(|b| b as u8));
s.char_at(i)
.to_digit(16)
.map(|n| n.try_into().expect("hex digit should always be < 256"))
};
let r; let (r, g, b) = if s.len() == 3 {
let g; // Expected format: FA3
let b; (
if s.len() == 3 { hex.next().map(|d| d * 16 + d)?,
// Format: FA3 hex.next().map(|d| d * 16 + d)?,
r = hex_digit(0)? * 16 + hex_digit(0)?; hex.next().map(|d| d * 16 + d)?,
g = hex_digit(1)? * 16 + hex_digit(1)?; )
b = hex_digit(2)? * 16 + hex_digit(2)?;
} else if s.len() == 6 { } else if s.len() == 6 {
// Format: F3A035 // Expected format: F3A035
r = hex_digit(0)? * 16 + hex_digit(1)?; (
g = hex_digit(2)? * 16 + hex_digit(3)?; hex.next()? * 16 + hex.next()?,
b = hex_digit(4)? * 16 + hex_digit(5)?; hex.next()? * 16 + hex.next()?,
hex.next()? * 16 + hex.next()?,
)
} else { } else {
return None; return None;
} };
Some(RgbColor::from_rgb(r, g, b)) Some(RgbColor::from_rgb(r, g, b))
} }