#[derive(Clone, Copy)]
enum Fold {
Below(u32),
Is(u32, u32),
Add(u32, i32),
Or1(u32),
Mod(u32, u32, u32, i32),
}
fn fold_simple(c: u32) -> u32 {
for rule in FOLD {
match rule {
Fold::Below(limit) if c < limit => return c,
Fold::Is(from, to) if c == from => return to,
Fold::Add(limit, offset) if c <= limit => return c.wrapping_add_signed(offset),
Fold::Or1(limit) if c <= limit => return c | 1,
Fold::Mod(limit, m, r, offset) if c <= limit && c.checked_rem(m) == Some(r) => {
return c.wrapping_add_signed(offset);
}
_ => {}
}
}
c
}
fn fold_dwarf(c: u32) -> u32 {
if c == 0x130 || c == 0x131 {
return u32::from(b'i');
}
fold_simple(c)
}
#[must_use]
pub(crate) fn hash(name: &[u8]) -> u32 {
let mut h: u32 = 5381;
if name.is_ascii() {
for &c in name {
h = h
.wrapping_mul(33)
.wrapping_add(u32::from(c.to_ascii_lowercase()));
}
return h;
}
let mut buf = [0u8; 4];
for c in String::from_utf8_lossy(name).chars() {
let folded = char::from_u32(fold_dwarf(u32::from(c))).unwrap_or(c);
for &b in folded.encode_utf8(&mut buf).as_bytes() {
h = h.wrapping_mul(33).wrapping_add(u32::from(b));
}
}
h
}
const FOLD: [Fold; 295] = [
Fold::Below(0x0041),
Fold::Add(0x005a, 32),
Fold::Is(0x00b5, 0x03bc),
Fold::Below(0x00c0),
Fold::Add(0x00d6, 32),
Fold::Below(0x00d8),
Fold::Add(0x00de, 32),
Fold::Below(0x0100),
Fold::Or1(0x012e),
Fold::Below(0x0132),
Fold::Or1(0x0136),
Fold::Below(0x0139),
Fold::Mod(0x0147, 2, 1, 1),
Fold::Below(0x014a),
Fold::Or1(0x0176),
Fold::Is(0x0178, 0x00ff),
Fold::Below(0x0179),
Fold::Mod(0x017d, 2, 1, 1),
Fold::Is(0x017f, 0x0073),
Fold::Is(0x0181, 0x0253),
Fold::Below(0x0182),
Fold::Or1(0x0184),
Fold::Is(0x0186, 0x0254),
Fold::Is(0x0187, 0x0188),
Fold::Below(0x0189),
Fold::Add(0x018a, 205),
Fold::Is(0x018b, 0x018c),
Fold::Is(0x018e, 0x01dd),
Fold::Is(0x018f, 0x0259),
Fold::Is(0x0190, 0x025b),
Fold::Is(0x0191, 0x0192),
Fold::Is(0x0193, 0x0260),
Fold::Is(0x0194, 0x0263),
Fold::Is(0x0196, 0x0269),
Fold::Is(0x0197, 0x0268),
Fold::Is(0x0198, 0x0199),
Fold::Is(0x019c, 0x026f),
Fold::Is(0x019d, 0x0272),
Fold::Is(0x019f, 0x0275),
Fold::Below(0x01a0),
Fold::Or1(0x01a4),
Fold::Is(0x01a6, 0x0280),
Fold::Is(0x01a7, 0x01a8),
Fold::Is(0x01a9, 0x0283),
Fold::Is(0x01ac, 0x01ad),
Fold::Is(0x01ae, 0x0288),
Fold::Is(0x01af, 0x01b0),
Fold::Below(0x01b1),
Fold::Add(0x01b2, 217),
Fold::Below(0x01b3),
Fold::Mod(0x01b5, 2, 1, 1),
Fold::Is(0x01b7, 0x0292),
Fold::Below(0x01b8),
Fold::Mod(0x01bc, 4, 0, 1),
Fold::Is(0x01c4, 0x01c6),
Fold::Is(0x01c5, 0x01c6),
Fold::Is(0x01c7, 0x01c9),
Fold::Is(0x01c8, 0x01c9),
Fold::Is(0x01ca, 0x01cc),
Fold::Below(0x01cb),
Fold::Mod(0x01db, 2, 1, 1),
Fold::Below(0x01de),
Fold::Or1(0x01ee),
Fold::Is(0x01f1, 0x01f3),
Fold::Below(0x01f2),
Fold::Or1(0x01f4),
Fold::Is(0x01f6, 0x0195),
Fold::Is(0x01f7, 0x01bf),
Fold::Below(0x01f8),
Fold::Or1(0x021e),
Fold::Is(0x0220, 0x019e),
Fold::Below(0x0222),
Fold::Or1(0x0232),
Fold::Is(0x023a, 0x2c65),
Fold::Is(0x023b, 0x023c),
Fold::Is(0x023d, 0x019a),
Fold::Is(0x023e, 0x2c66),
Fold::Is(0x0241, 0x0242),
Fold::Is(0x0243, 0x0180),
Fold::Is(0x0244, 0x0289),
Fold::Is(0x0245, 0x028c),
Fold::Below(0x0246),
Fold::Or1(0x024e),
Fold::Is(0x0345, 0x03b9),
Fold::Below(0x0370),
Fold::Or1(0x0372),
Fold::Is(0x0376, 0x0377),
Fold::Is(0x037f, 0x03f3),
Fold::Is(0x0386, 0x03ac),
Fold::Below(0x0388),
Fold::Add(0x038a, 37),
Fold::Is(0x038c, 0x03cc),
Fold::Below(0x038e),
Fold::Add(0x038f, 63),
Fold::Below(0x0391),
Fold::Add(0x03a1, 32),
Fold::Below(0x03a3),
Fold::Add(0x03ab, 32),
Fold::Is(0x03c2, 0x03c3),
Fold::Is(0x03cf, 0x03d7),
Fold::Is(0x03d0, 0x03b2),
Fold::Is(0x03d1, 0x03b8),
Fold::Is(0x03d5, 0x03c6),
Fold::Is(0x03d6, 0x03c0),
Fold::Below(0x03d8),
Fold::Or1(0x03ee),
Fold::Is(0x03f0, 0x03ba),
Fold::Is(0x03f1, 0x03c1),
Fold::Is(0x03f4, 0x03b8),
Fold::Is(0x03f5, 0x03b5),
Fold::Is(0x03f7, 0x03f8),
Fold::Is(0x03f9, 0x03f2),
Fold::Is(0x03fa, 0x03fb),
Fold::Below(0x03fd),
Fold::Add(0x03ff, -130),
Fold::Below(0x0400),
Fold::Add(0x040f, 80),
Fold::Below(0x0410),
Fold::Add(0x042f, 32),
Fold::Below(0x0460),
Fold::Or1(0x0480),
Fold::Below(0x048a),
Fold::Or1(0x04be),
Fold::Is(0x04c0, 0x04cf),
Fold::Below(0x04c1),
Fold::Mod(0x04cd, 2, 1, 1),
Fold::Below(0x04d0),
Fold::Or1(0x052e),
Fold::Below(0x0531),
Fold::Add(0x0556, 48),
Fold::Below(0x10a0),
Fold::Add(0x10c5, 7264),
Fold::Below(0x10c7),
Fold::Mod(0x10cd, 6, 5, 7264),
Fold::Below(0x13f8),
Fold::Add(0x13fd, -8),
Fold::Is(0x1c80, 0x0432),
Fold::Is(0x1c81, 0x0434),
Fold::Is(0x1c82, 0x043e),
Fold::Below(0x1c83),
Fold::Add(0x1c84, -6210),
Fold::Is(0x1c85, 0x0442),
Fold::Is(0x1c86, 0x044a),
Fold::Is(0x1c87, 0x0463),
Fold::Is(0x1c88, 0xa64b),
Fold::Below(0x1c90),
Fold::Add(0x1cba, -3008),
Fold::Below(0x1cbd),
Fold::Add(0x1cbf, -3008),
Fold::Below(0x1e00),
Fold::Or1(0x1e94),
Fold::Is(0x1e9b, 0x1e61),
Fold::Is(0x1e9e, 0x00df),
Fold::Below(0x1ea0),
Fold::Or1(0x1efe),
Fold::Below(0x1f08),
Fold::Add(0x1f0f, -8),
Fold::Below(0x1f18),
Fold::Add(0x1f1d, -8),
Fold::Below(0x1f28),
Fold::Add(0x1f2f, -8),
Fold::Below(0x1f38),
Fold::Add(0x1f3f, -8),
Fold::Below(0x1f48),
Fold::Add(0x1f4d, -8),
Fold::Below(0x1f59),
Fold::Mod(0x1f5f, 2, 1, -8),
Fold::Below(0x1f68),
Fold::Add(0x1f6f, -8),
Fold::Below(0x1f88),
Fold::Add(0x1f8f, -8),
Fold::Below(0x1f98),
Fold::Add(0x1f9f, -8),
Fold::Below(0x1fa8),
Fold::Add(0x1faf, -8),
Fold::Below(0x1fb8),
Fold::Add(0x1fb9, -8),
Fold::Below(0x1fba),
Fold::Add(0x1fbb, -74),
Fold::Is(0x1fbc, 0x1fb3),
Fold::Is(0x1fbe, 0x03b9),
Fold::Below(0x1fc8),
Fold::Add(0x1fcb, -86),
Fold::Is(0x1fcc, 0x1fc3),
Fold::Is(0x1fd3, 0x0390),
Fold::Below(0x1fd8),
Fold::Add(0x1fd9, -8),
Fold::Below(0x1fda),
Fold::Add(0x1fdb, -100),
Fold::Is(0x1fe3, 0x03b0),
Fold::Below(0x1fe8),
Fold::Add(0x1fe9, -8),
Fold::Below(0x1fea),
Fold::Add(0x1feb, -112),
Fold::Is(0x1fec, 0x1fe5),
Fold::Below(0x1ff8),
Fold::Add(0x1ff9, -128),
Fold::Below(0x1ffa),
Fold::Add(0x1ffb, -126),
Fold::Is(0x1ffc, 0x1ff3),
Fold::Is(0x2126, 0x03c9),
Fold::Is(0x212a, 0x006b),
Fold::Is(0x212b, 0x00e5),
Fold::Is(0x2132, 0x214e),
Fold::Below(0x2160),
Fold::Add(0x216f, 16),
Fold::Is(0x2183, 0x2184),
Fold::Below(0x24b6),
Fold::Add(0x24cf, 26),
Fold::Below(0x2c00),
Fold::Add(0x2c2f, 48),
Fold::Is(0x2c60, 0x2c61),
Fold::Is(0x2c62, 0x026b),
Fold::Is(0x2c63, 0x1d7d),
Fold::Is(0x2c64, 0x027d),
Fold::Below(0x2c67),
Fold::Mod(0x2c6b, 2, 1, 1),
Fold::Is(0x2c6d, 0x0251),
Fold::Is(0x2c6e, 0x0271),
Fold::Is(0x2c6f, 0x0250),
Fold::Is(0x2c70, 0x0252),
Fold::Below(0x2c72),
Fold::Mod(0x2c75, 3, 2, 1),
Fold::Below(0x2c7e),
Fold::Add(0x2c7f, -10815),
Fold::Below(0x2c80),
Fold::Or1(0x2ce2),
Fold::Below(0x2ceb),
Fold::Mod(0x2ced, 2, 1, 1),
Fold::Below(0x2cf2),
Fold::Mod(0xa640, 31054, 11506, 1),
Fold::Below(0xa642),
Fold::Or1(0xa66c),
Fold::Below(0xa680),
Fold::Or1(0xa69a),
Fold::Below(0xa722),
Fold::Or1(0xa72e),
Fold::Below(0xa732),
Fold::Or1(0xa76e),
Fold::Below(0xa779),
Fold::Mod(0xa77b, 2, 1, 1),
Fold::Is(0xa77d, 0x1d79),
Fold::Below(0xa77e),
Fold::Or1(0xa786),
Fold::Is(0xa78b, 0xa78c),
Fold::Is(0xa78d, 0x0265),
Fold::Below(0xa790),
Fold::Or1(0xa792),
Fold::Below(0xa796),
Fold::Or1(0xa7a8),
Fold::Is(0xa7aa, 0x0266),
Fold::Is(0xa7ab, 0x025c),
Fold::Is(0xa7ac, 0x0261),
Fold::Is(0xa7ad, 0x026c),
Fold::Is(0xa7ae, 0x026a),
Fold::Is(0xa7b0, 0x029e),
Fold::Is(0xa7b1, 0x0287),
Fold::Is(0xa7b2, 0x029d),
Fold::Is(0xa7b3, 0xab53),
Fold::Below(0xa7b4),
Fold::Or1(0xa7c2),
Fold::Is(0xa7c4, 0xa794),
Fold::Is(0xa7c5, 0x0282),
Fold::Is(0xa7c6, 0x1d8e),
Fold::Below(0xa7c7),
Fold::Mod(0xa7c9, 2, 1, 1),
Fold::Below(0xa7d0),
Fold::Mod(0xa7d6, 6, 0, 1),
Fold::Below(0xa7d8),
Fold::Mod(0xa7f5, 29, 19, 1),
Fold::Below(0xab70),
Fold::Add(0xabbf, -38864),
Fold::Is(0xfb05, 0xfb06),
Fold::Below(0xff21),
Fold::Add(0xff3a, 32),
Fold::Below(0x10400),
Fold::Add(0x10427, 40),
Fold::Below(0x104b0),
Fold::Add(0x104d3, 40),
Fold::Below(0x10570),
Fold::Add(0x1057a, 39),
Fold::Below(0x1057c),
Fold::Add(0x1058a, 39),
Fold::Below(0x1058c),
Fold::Add(0x10592, 39),
Fold::Below(0x10594),
Fold::Add(0x10595, 39),
Fold::Below(0x10c80),
Fold::Add(0x10cb2, 64),
Fold::Below(0x118a0),
Fold::Add(0x118bf, 32),
Fold::Below(0x16e40),
Fold::Add(0x16e5f, 32),
Fold::Below(0x1e900),
Fold::Add(0x1e921, 34),
];
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn ascii_names_fold_case() {
assert_eq!(hash(b""), 5381);
assert_eq!(hash(b"main"), hash(b"MAIN"));
assert_eq!(hash(b"a"), 5381 * 33 + 97);
}
#[test]
fn unicode_names_fold_case() {
assert_eq!(hash("ÉTÉ".as_bytes()), hash("été".as_bytes()));
assert_eq!(hash("ΣΑΣ".as_bytes()), hash("σασ".as_bytes()));
assert_eq!(hash("İ".as_bytes()), hash(b"i"));
assert_eq!(fold_simple(0xb5), 0x3bc);
assert_eq!(fold_simple(0x1e9e), 0xdf);
assert_eq!(fold_simple(0x10400), 0x10428);
}
}