const NFKC_BITS: u32 = const { letmut accu = 0; letmut i = 0; while i < 0x20 { if TABLE[i] != 0 {
accu |= 1 << (i as u32);
}
i += 1;
}
accu
};
const NFD_BITS: u64 = const { letmut accu = 0; letmut i = 0x20; while i < TABLE.len() { if TABLE[i] != 0 {
accu |= 1 << ((i - 0x20) as u32);
}
i += 1;
}
accu
};
const NFKD_BITS: u128 = const { letmut accu = 0; letmut i = 0; while i < TABLE.len() { if TABLE[i] != 0 {
accu |= 1 << ((i + 0x20) as u32);
}
i += 1;
}
accu
};
/// Writes the compatibility decomposition of `c` to `sink`. #[inline] fn compatibility_decomposition(val: u16) -> &'static [u16] {
debug_assert!(val <= 0xFF); let len = val & 0b11; let index = val >> 2;
COMPATIBILITY_DECOMPOSITIONS
.get(index as usize..index as usize + len as usize)
.unwrap_or_else(|| { // Internal bug, not even GIGO, never supposed to happen
debug_assert!(false);
&[]
})
}
/// Normalize Latin1 `text` to NFD UTF-16 written to `sink`. #[inline] pubfn normalize_nfd_to<W: Write16 + ?Sized>(text: &[u16], sink: &mut W) -> core::fmt::Result { // Indexing is OK, because the index is statically in range. #[expect(clippy::indexing_slicing)] let table = &TABLE[0x20..]; letmut text_left = text; letmut iter = text_left.iter(); whilelet Some(u) = iter.next() { let c = *u; if c < 0xC0 { continue;
} iflet Some(val) = table.get(c.wrapping_sub(0xC0) as usize) { let v = *val; if v != 0 { let remaining = iter.as_slice(); // Indexing is OK by construction. #[expect(clippy::indexing_slicing)]
sink.write_slice(&text_left[..text_left.len() - remaining.len() - 1])?;
text_left = remaining;
sink.write_slice(&[v >> 8, (v & 0xFF) + 0x0300])?;
}
}
}
sink.write_slice(text_left)?;
Ok(())
}
/// Normalize Latin1 `text` to NFKD UTF-16 written to `sink`. #[inline] pubfn normalize_nfkd_to<W: Write16 + ?Sized>(text: &[u16], sink: &mutW) -> core::fmt::Result { letmut text_left = text; letmut iter = text_left.iter(); whilelet Some(u) = iter.next() { let c = *u; if c < 0xA0 { continue;
} iflet Some(val) = TABLE.get(c.wrapping_sub(0xA0) as usize) { let v = *val; if v != 0 { let remaining = iter.as_slice(); // Indexing is OK by construction. #[expect(clippy::indexing_slicing)]
sink.write_slice(&text_left[..text_left.len() - remaining.len() - 1])?;
text_left = remaining; let hi = v >> 8; if hi != 0 {
sink.write_slice(&[hi, (v & 0xFF) + 0x0300])?;
} else {
sink.write_slice(compatibility_decomposition(v))?;
}
}
}
}
sink.write_slice(text_left)?;
Ok(())
}
/// Normalize Latin1 `text` to NFKC UTF-16 written to `sink`. #[inline] pubfn normalize_nfkc_to<W: Write16 + ?Sized>(text: &[u16], sink: &mutW) -> core::fmt::Result { // Indexing is OK, because the index is statically in range. #[expect(clippy::indexing_slicing)] let table = &TABLE[..0x20]; letmut text_left = text; letmut iter = text_left.iter(); whilelet Some(u) = iter.next() { let c = *u; if c < 0xA0 { continue;
} iflet Some(val) = table.get(c.wrapping_sub(0xA0) as usize) { let v = *val; if v != 0 { let remaining = iter.as_slice(); // Indexing is OK by construction. #[expect(clippy::indexing_slicing)]
sink.write_slice(&text_left[..text_left.len() - remaining.len() - 1])?;
text_left = remaining;
sink.write_slice(compatibility_decomposition(v))?;
}
}
}
sink.write_slice(text_left)?;
Ok(())
}
/// Split Latin1 `text` into `(head, tail)` such that the first /// byte of `tail` is the first byte of input that is not in NFD. /// If `text` is fully in NFD, `tail` is empty. #[inline] pubfn split_normalized_nfd(text: &[u8]) -> (&[u8], &[u8]) { letmut iter = text.iter(); whilelet Some(c) = iter.next() { let b = *c; iflet Some(shifted) = 1u64.checked_shl(u32::from(b.wrapping_sub(0xC0))) { if (NFD_BITS & shifted) != 0 { let tail = iter.as_slice(); return text
.split_at_checked(text.len() - tail.len() - 1)
.unwrap_or_else(|| { // Internal bug, not even GIGO, never supposed to happen
debug_assert!(false);
(&[], text)
});
}
}
}
(text, &[])
}
/// Split Latin1 `text` into `(head, tail)` such that the first /// byte of `tail` is the first byte of input that is not in NFKD. /// If `text` is fully in NFKD, `tail` is empty. #[inline] pubfn split_normalized_nfkd(text: &[u8]) -> (&[u8], &[u8]) { letmut iter = text.iter(); whilelet Some(c) = iter.next() { let b = *c; iflet Some(shifted) = 1u128.checked_shl(u32::from(b.wrapping_sub(0x80))) { if (NFKD_BITS & shifted) != 0 { let tail = iter.as_slice(); return text
.split_at_checked(text.len() - tail.len() - 1)
.unwrap_or_else(|| { // Internal bug, not even GIGO, never supposed to happen
debug_assert!(false);
(&[], text)
});
}
}
}
(text, &[])
}
/// Split Latin1 `text` into `(head, tail)` such that the first /// byte of `tail` is the first byte of input that is not in NFKC. /// If `text` is fully in NFKC, `tail` is empty. #[inline] pubfn split_normalized_nfkc(text: &[u8]) -> (&[u8], &[u8]) { letmut iter = text.iter(); whilelet Some(c) = iter.next() { let b = *c; // Make ASCII go one instruction faster. if b < 0xA0 { continue;
} iflet Some(shifted) = 1u32.checked_shl(u32::from(b.wrapping_sub(0xA0))) { if (NFKC_BITS & shifted) != 0 { let tail = iter.as_slice(); return text
.split_at_checked(text.len() - tail.len() - 1)
.unwrap_or_else(|| { // Internal bug, not even GIGO, never supposed to happen
debug_assert!(false);
(&[], text)
});
}
}
}
(text, &[])
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.