Skip to content

Commit

Permalink
Merge pull request #562 from Nugine/improve-try-parse
Browse files Browse the repository at this point in the history
Improve `try_parse` and `encode` performance
  • Loading branch information
KodrAus committed Nov 14, 2021
2 parents b9c4a08 + 19b8386 commit 3a6aeb1
Show file tree
Hide file tree
Showing 3 changed files with 188 additions and 131 deletions.
125 changes: 68 additions & 57 deletions shared/parser.rs
Expand Up @@ -11,63 +11,78 @@

use crate::error::InvalidUuid;

#[inline]
pub const fn try_parse(input: &str) -> Result<[u8; 16], InvalidUuid> {
const fn parse_blocks<'a>(
s: &'a [u8],
hyphenated: bool,
) -> Option<[u8; 16]> {
let block_table = if hyphenated {
match (s[8], s[13], s[18], s[23]) {
(b'-', b'-', b'-', b'-') => [0, 4, 9, 14, 19, 24, 28, 32],
_ => return None,
}
} else {
[0, 4, 8, 12, 16, 20, 24, 28]
};

let mut buf = [0; 16];
let mut j = 0;
while j < 8 {
let i = block_table[j];
// Check 4 bytes at a time
let h1 = HEX_TABLE[s[i] as usize];
let h2 = HEX_TABLE[s[i + 1] as usize];
let h3 = HEX_TABLE[s[i + 2] as usize];
let h4 = HEX_TABLE[s[i + 3] as usize];
// If any of the bytes aren't valid, they will be 0xff, making this
// fail
if h1 | h2 | h3 | h4 == 0xff {
return None;
}
buf[j * 2] = SHL4_TABLE[h1 as usize] | h2;
buf[j * 2 + 1] = SHL4_TABLE[h3 as usize] | h4;
j += 1;
}
Some(buf)
}

let b = input.as_bytes();
let maybe_parsed = match (b.len(), b) {
(32, s) => parse_blocks(s, false),
let result = match (input.len(), input.as_bytes()) {
(32, s) => parse_simple(s),
(36, s)
| (38, [b'{', s @ .., b'}'])
| (
45,
[b'u', b'r', b'n', b':', b'u', b'u', b'i', b'd', b':', s @ ..],
) => parse_blocks(s, true),
_ => None,
) => parse_hyphenated(s),
_ => Err(()),
};
match maybe_parsed {
Some(b) => Ok(b),
None => Err(InvalidUuid(input)),
match result {
Ok(b) => Ok(b),
Err(()) => Err(InvalidUuid(input)),
}
}

#[inline]
const fn parse_simple(s: &[u8]) -> Result<[u8; 16], ()> {
if s.len() != 32 {
return Err(());
}

let mut buf: [u8; 16] = [0; 16];
let mut i = 0;
while i < 16 {
let h1 = HEX_TABLE[s[i * 2] as usize];
let h2 = HEX_TABLE[s[i * 2 + 1] as usize];
if h1 | h2 == 0xff {
return Err(());
}
buf[i] = SHL4_TABLE[h1 as usize] | h2;
i += 1;
}
Ok(buf)
}

type Table = [u8; 256];
#[inline]
const fn parse_hyphenated(s: &[u8]) -> Result<[u8; 16], ()> {
if s.len() != 36 {
return Err(());
}

match [s[8], s[13], s[18], s[23]] {
[b'-', b'-', b'-', b'-'] => {}
_ => return Err(()),
}

let positions: [u8; 8] = [0, 4, 9, 14, 19, 24, 28, 32];
let mut buf: [u8; 16] = [0; 16];
let mut j = 0;
while j < 8 {
let i = positions[j];
let h1 = HEX_TABLE[s[i as usize] as usize];
let h2 = HEX_TABLE[s[(i + 1) as usize] as usize];
let h3 = HEX_TABLE[s[(i + 2) as usize] as usize];
let h4 = HEX_TABLE[s[(i + 3) as usize] as usize];
if h1 | h2 | h3 | h4 == 0xff {
return Err(());
}
buf[j * 2] = SHL4_TABLE[h1 as usize] | h2;
buf[j * 2 + 1] = SHL4_TABLE[h3 as usize] | h4;
j += 1;
}

const fn generate_lookup_table() -> Table {
let mut buf = [0u8; 256];
let mut i = 0u8;
Ok(buf)
}

const HEX_TABLE: &[u8; 256] = &{
let mut buf = [0; 256];
let mut i: u8 = 0;
loop {
buf[i as usize] = match i {
b'0'..=b'9' => i - b'0',
Expand All @@ -76,24 +91,20 @@ const fn generate_lookup_table() -> Table {
_ => 0xff,
};
if i == 255 {
return buf;
break buf;
}
i += 1
}
}
};

const HEX_TABLE: Table = generate_lookup_table();

const fn generate_shl4_table() -> Table {
let mut buf = [0u8; 256];
let mut i = 0u8;
const SHL4_TABLE: &[u8; 256] = &{
let mut buf = [0; 256];
let mut i: u8 = 0;
loop {
buf[i as usize] = i.wrapping_shl(4);
if i == 255 {
return buf;
break buf;
}
i += 1;
}
}

const SHL4_TABLE: Table = generate_shl4_table();
};

0 comments on commit 3a6aeb1

Please sign in to comment.