REAL
Regular Expression Algorithmic Library — constexpr C++20 regex
Loading...
Searching...
No Matches
utf8_ranges.hpp
Go to the documentation of this file.
1
11#ifndef REAL_UTF8_RANGES_HPP
12#define REAL_UTF8_RANGES_HPP
13
14// Internal — do not include directly.
15// Users: #include <real/real.hpp> (or the documented opt-ins <real/dfa.hpp>, <real/std/regex.hpp>).
16
17#include <cstddef>
18#include <cstdint>
19#include <vector>
20
21namespace real::detail {
22
25 {
26 std::uint8_t lo {};
27 std::uint8_t hi {};
28 };
29
32 {
34 std::size_t length {};
35 };
36
38 constexpr std::size_t encode_utf8_bytes(std::uint32_t cp,
39 std::uint8_t (&out)[4])
40 {
41 if (cp < 0x80U) {
42 out[0] = static_cast<std::uint8_t>(cp);
43 return 1;
44 }
45 if (cp < 0x800U) {
46 out[0] = static_cast<std::uint8_t>(0xC0U | (cp >> 6U));
47 out[1] = static_cast<std::uint8_t>(0x80U | (cp & 0x3FU));
48 return 2;
49 }
50 if (cp < 0x10000U) {
51 out[0] = static_cast<std::uint8_t>(0xE0U | (cp >> 12U));
52 out[1] = static_cast<std::uint8_t>(0x80U | ((cp >> 6U) & 0x3FU));
53 out[2] = static_cast<std::uint8_t>(0x80U | (cp & 0x3FU));
54 return 3;
55 }
56 out[0] = static_cast<std::uint8_t>(0xF0U | (cp >> 18U));
57 out[1] = static_cast<std::uint8_t>(0x80U | ((cp >> 12U) & 0x3FU));
58 out[2] = static_cast<std::uint8_t>(0x80U | ((cp >> 6U) & 0x3FU));
59 out[3] = static_cast<std::uint8_t>(0x80U | (cp & 0x3FU));
60 return 4;
61 }
62
69 constexpr void utf8_push_range(std::uint32_t start,
70 std::uint32_t end,
71 std::vector<utf8_byte_seq>& out)
72 {
73 if (start > end) {
74 return;
75 }
76 constexpr std::uint32_t length_max[4] {0x7FU, 0x7FFU, 0xFFFFU, 0x10FFFFU};
77 for (const std::uint32_t max : length_max) {
78 if (start <= max && max < end) { // range spans a UTF-8 length boundary: split there
79 utf8_push_range(start, max, out);
80 utf8_push_range(max + 1, end, out);
81 return;
82 }
83 }
84 for (unsigned i = 1; i < 4; ++i) { // split so each continuation byte covers a contiguous sub-range
85 const std::uint32_t mask {(1U << (6U * i)) - 1U};
86 if ((start & ~mask) != (end & ~mask)) {
87 if ((start & mask) != 0U) {
88 utf8_push_range(start, start | mask, out);
89 utf8_push_range((start | mask) + 1U, end, out);
90 return;
91 }
92 if ((end & mask) != mask) {
93 utf8_push_range(start, (end & ~mask) - 1U, out);
94 utf8_push_range(end & ~mask, end, out);
95 return;
96 }
97 }
98 }
99 std::uint8_t start_bytes[4] {};
100 std::uint8_t end_bytes[4] {};
101 const std::size_t n {encode_utf8_bytes(start, start_bytes)};
102 encode_utf8_bytes(end, end_bytes);
103 utf8_byte_seq seq {};
104 seq.length = n;
105 for (std::size_t j = 0; j < n; ++j) {
106 seq.parts[j] = {.lo = start_bytes[j], .hi = end_bytes[j]};
107 }
108 out.push_back(seq);
109 }
110
113 constexpr std::vector<utf8_byte_seq> utf8_range_sequences(std::uint32_t lo,
114 std::uint32_t hi)
115 {
116 std::vector<utf8_byte_seq> out;
117 if (hi < 0xD800U || lo > 0xDFFFU) {
118 utf8_push_range(lo, hi, out); // no surrogate overlap
119 }
120 else {
121 if (lo <= 0xD7FFU) {
122 utf8_push_range(lo, 0xD7FFU, out);
123 }
124 if (hi >= 0xE000U) {
125 utf8_push_range(0xE000U, hi, out);
126 }
127 }
128 return out;
129 }
130} // namespace real::detail
131
132#endif // REAL_UTF8_RANGES_HPP
constexpr std::vector< utf8_byte_seq > utf8_range_sequences(std::uint32_t lo, std::uint32_t hi)
Canonical UTF-8 byte-range sequences for the code-point range [lo, hi], excluding the surrogate block...
constexpr void utf8_push_range(std::uint32_t start, std::uint32_t end, std::vector< utf8_byte_seq > &out)
Splits [start, end] (same UTF-8 length after the length-boundary split) into contiguous byte-range se...
constexpr std::size_t encode_utf8_bytes(std::uint32_t cp, std::uint8_t(&out)[4])
Encodes cp to its UTF-8 bytes in out, returning the length (1–4).
One byte-range step [lo, hi] of a UTF-8 sequence produced by the code-point-range algorithm.
std::uint8_t hi
High byte (inclusive).
std::uint8_t lo
Low byte (inclusive).
A canonical UTF-8 byte-range sequence (1–4 steps) covering part of a code-point range.
std::size_t length
Number of active steps (1–4).
utf8_byte_range parts[4]
The per-byte ranges.