1#ifndef SOURCEMETA_CORE_UNICODE_H_
2#define SOURCEMETA_CORE_UNICODE_H_
4#ifndef SOURCEMETA_CORE_UNICODE_EXPORT
5#include <sourcemeta/core/unicode_export.h>
8#include <sourcemeta/core/unicode_ucd.h>
28namespace sourcemeta::core {
41SOURCEMETA_CORE_UNICODE_EXPORT
58SOURCEMETA_CORE_UNICODE_EXPORT
74SOURCEMETA_CORE_UNICODE_EXPORT
91SOURCEMETA_CORE_UNICODE_EXPORT
92auto utf8_to_utf32(std::istream &input) -> std::optional<std::u32string>;
106SOURCEMETA_CORE_UNICODE_EXPORT
108 -> std::optional<std::u32string>;
122SOURCEMETA_CORE_UNICODE_EXPORT
144SOURCEMETA_CORE_UNICODE_EXPORT
162SOURCEMETA_CORE_UNICODE_EXPORT
176SOURCEMETA_CORE_UNICODE_EXPORT
189SOURCEMETA_CORE_UNICODE_EXPORT
214 if (
byte >= 0xC2 &&
byte <= 0xDF) {
217 if (
byte >= 0xE0 &&
byte <= 0xEF) {
220 if (
byte >= 0xF0 &&
byte <= 0xF4) {
249 const std::size_t position,
250 const unsigned char byte) ->
bool {
251 const unsigned char lower{
static_cast<unsigned char>(
253 : (lead == 0xE0 ? 0xA0 : (lead == 0xF0 ? 0x90 : 0x80)))};
254 const unsigned char upper{
static_cast<unsigned char>(
256 : (lead == 0xED ? 0x9F : (lead == 0xF4 ? 0x8F : 0xBF)))};
257 return byte >= lower &&
byte <= upper;
279 const auto lead{
static_cast<unsigned char>(input.front())};
281 if (size == 0 || input.size() < size) {
285 for (std::size_t index{1}; index < size; index += 1) {
286 if (!
is_utf8_tail(lead, index,
static_cast<unsigned char>(input[index]))) {
308 return byte >= 0x80 &&
byte <= 0xBF;
325 std::size_t count{0};
326 for (
const auto byte : input) {
351 const std::size_t minimum,
352 const std::size_t maximum) ->
bool {
353 const auto bytes{input.size()};
357 if (bytes < minimum) {
363 const auto lower_bound{(bytes + 3) / 4};
364 if (lower_bound > maximum) {
370 if (bytes <= maximum && lower_bound >= minimum) {
377 std::size_t count{0};
378 for (
const auto byte : input) {
381 if (count > maximum) {
387 return count >= minimum;
405 return codepoint >= 0xD800 && codepoint <= 0xDFFF;
423 return codepoint <= 0x10FFFF && !
is_surrogate(codepoint);
441inline constexpr auto is_ucschar(
const char32_t codepoint) ->
bool {
442 if (codepoint >= 0xA0 && codepoint <= 0xD7FF) {
445 if (codepoint >= 0xF900 && codepoint <= 0xFDCF) {
448 if (codepoint >= 0xFDF0 && codepoint <= 0xFFEF) {
454 if (codepoint < 0x10000 || codepoint > 0xEFFFD) {
457 if (codepoint >= 0xE0000 && codepoint < 0xE1000) {
460 return (codepoint & 0xFFFFU) <= 0xFFFDU;
477inline constexpr auto is_iprivate(
const char32_t codepoint) ->
bool {
478 if (codepoint >= 0xE000 && codepoint <= 0xF8FF) {
481 if (codepoint >= 0xF0000 && codepoint <= 0xFFFFD) {
484 if (codepoint >= 0x100000 && codepoint <= 0x10FFFD) {
507 if (codepoint < 0x80) {
510 if (codepoint < 0x800) {
513 if (codepoint < 0x10000) {
532SOURCEMETA_CORE_UNICODE_EXPORT
551SOURCEMETA_CORE_UNICODE_EXPORT
570SOURCEMETA_CORE_UNICODE_EXPORT
589SOURCEMETA_CORE_UNICODE_EXPORT
606SOURCEMETA_CORE_UNICODE_EXPORT
625SOURCEMETA_CORE_UNICODE_EXPORT
645SOURCEMETA_CORE_UNICODE_EXPORT
647 -> std::u32string_view;
666SOURCEMETA_CORE_UNICODE_EXPORT
668 const char32_t combining)
noexcept
669 -> std::optional<char32_t>;
683SOURCEMETA_CORE_UNICODE_EXPORT
684auto nfc(
const std::u32string_view input) -> std::u32string;
700SOURCEMETA_CORE_UNICODE_EXPORT
701auto is_nfc(
const std::u32string_view input) -> bool;
722 const std::string_view::size_type position)
724 if (position >= input.size()) {
727 const auto byte_0{
static_cast<unsigned char>(input[position])};
729 if (size == 0 || position + size > input.size()) {
739 const auto byte_1{
static_cast<unsigned char>(input[position + 1])};
740 bool byte_1_ok{
false};
743 }
else if (size == 3) {
744 if (byte_0 == 0xE0) {
745 byte_1_ok = byte_1 >= 0xA0 && byte_1 <= 0xBF;
746 }
else if (byte_0 == 0xED) {
747 byte_1_ok = byte_1 >= 0x80 && byte_1 <= 0x9F;
752 if (byte_0 == 0xF0) {
753 byte_1_ok = byte_1 >= 0x90 && byte_1 <= 0xBF;
754 }
else if (byte_0 == 0xF4) {
755 byte_1_ok = byte_1 >= 0x80 && byte_1 <= 0x8F;
767 for (std::size_t index{2}; index < size; ++index) {
769 static_cast<unsigned char>(input[position + index]))) {
795 const std::string_view::size_type position)
796 -> std::optional<std::pair<char32_t, std::size_t>> {
802 const auto lead{
static_cast<unsigned char>(input[position])};
803 char32_t codepoint{0};
805 codepoint =
static_cast<char32_t>(lead);
806 }
else if (size == 2) {
807 codepoint =
static_cast<char32_t>(lead & 0x1FU);
808 }
else if (size == 3) {
809 codepoint =
static_cast<char32_t>(lead & 0x0FU);
811 codepoint =
static_cast<char32_t>(lead & 0x07U);
814 for (std::size_t index{1}; index < size; ++index) {
815 const auto continuation{
816 static_cast<unsigned char>(input[position + index])};
817 codepoint = (codepoint << 6) | static_cast<char32_t>(continuation & 0x3FU);
820 return std::make_pair(codepoint, size);
constexpr auto utf8_lead_byte_size(const unsigned char byte) -> std::uint8_t
Definition unicode.h:209
SOURCEMETA_CORE_UNICODE_EXPORT auto nfc(const std::u32string_view input) -> std::u32string
SOURCEMETA_CORE_UNICODE_EXPORT auto utf8_to_wide(const std::string_view input) -> std::wstring
constexpr auto is_ucschar(const char32_t codepoint) -> bool
Definition unicode.h:441
SOURCEMETA_CORE_UNICODE_EXPORT auto codepoint_to_utf8(const char32_t codepoint) -> std::string
constexpr auto utf8_codepoint_count(const std::string_view input) -> std::size_t
Definition unicode.h:323
constexpr auto utf8_sequence_size(const std::string_view input) -> std::size_t
Definition unicode.h:273
SOURCEMETA_CORE_UNICODE_EXPORT auto canonical_decomposition(const char32_t codepoint) noexcept -> std::u32string_view
SOURCEMETA_CORE_UNICODE_EXPORT auto utf32_to_utf8_lenient(const std::u32string_view input) -> std::string
JoiningType
Definition unicode_ucd.h:21
constexpr auto is_surrogate(const char32_t codepoint) -> bool
Definition unicode.h:404
SOURCEMETA_CORE_UNICODE_EXPORT auto is_nfc(const std::u32string_view input) -> bool
SOURCEMETA_CORE_UNICODE_EXPORT auto wide_to_utf8(const std::wstring_view input) -> std::string
constexpr auto utf8_codepoint_byte_count(const char32_t codepoint) -> std::uint8_t
Definition unicode.h:505
SOURCEMETA_CORE_UNICODE_EXPORT auto utf8_to_utf32(std::istream &input) -> std::optional< std::u32string >
SOURCEMETA_CORE_UNICODE_EXPORT auto bidi_class(const char32_t codepoint) noexcept -> BidiClass
constexpr auto is_utf8_tail(const unsigned char lead, const std::size_t position, const unsigned char byte) -> bool
Definition unicode.h:248
UnicodeScript
Definition unicode_ucd.h:252
SOURCEMETA_CORE_UNICODE_EXPORT auto joining_type(const char32_t codepoint) noexcept -> JoiningType
constexpr auto utf8_decode(const std::string_view input, const std::string_view::size_type position) -> std::optional< std::pair< char32_t, std::size_t > >
Definition unicode.h:794
BidiClass
Definition unicode_ucd.h:59
constexpr auto is_utf8_continuation(const unsigned char byte) -> bool
Definition unicode.h:307
SOURCEMETA_CORE_UNICODE_EXPORT auto script(const char32_t codepoint) noexcept -> UnicodeScript
constexpr auto utf8_codepoint_length(const std::string_view input, const std::string_view::size_type position) -> std::size_t
Definition unicode.h:721
SOURCEMETA_CORE_UNICODE_EXPORT auto is_combining_mark(const char32_t codepoint) noexcept -> bool
constexpr auto is_iprivate(const char32_t codepoint) -> bool
Definition unicode.h:477
constexpr auto is_valid_codepoint(const char32_t codepoint) -> bool
Definition unicode.h:422
NFCQuickCheck
Definition unicode_ucd.h:270
SOURCEMETA_CORE_UNICODE_EXPORT auto to_valid_utf8(const std::string_view input) -> std::string
constexpr auto utf8_codepoint_within(const std::string_view input, const std::size_t minimum, const std::size_t maximum) -> bool
Definition unicode.h:350
SOURCEMETA_CORE_UNICODE_EXPORT auto nfc_quick_check(const char32_t codepoint) noexcept -> NFCQuickCheck
SOURCEMETA_CORE_UNICODE_EXPORT auto combining_class(const char32_t codepoint) noexcept -> std::uint8_t
SOURCEMETA_CORE_UNICODE_EXPORT auto utf32_to_utf8(const std::u32string_view input) -> std::string
SOURCEMETA_CORE_UNICODE_EXPORT auto canonical_composition(const char32_t starter, const char32_t combining) noexcept -> std::optional< char32_t >