REAL
Regular Expression Algorithmic Library — constexpr C++20 regex
Loading...
Searching...
No Matches
charclass.hpp
Go to the documentation of this file.
1
9#ifndef REAL_CHARCLASS_HPP
10#define REAL_CHARCLASS_HPP
11
12// Internal — do not include directly.
13// Users: #include <real/real.hpp> (or the documented opt-ins <real/dfa.hpp>, <real/std/regex.hpp>).
14
15#include "real/version.hpp"
16
17#include <array>
18#include <cstddef>
19#include <cstdint>
20
21namespace real::detail {
22
30 {
31 std::array<std::uint64_t, 4> bits {};
32
37 constexpr void set(std::uint8_t byte)
38 {
39 const unsigned bit {byte};
40 bits[bit >> 6U] |= std::uint64_t {1} << (bit & 63U);
41 }
42
48 constexpr void set_range(std::uint8_t low,
49 std::uint8_t high)
50 {
51 if (low > high) {
52 return; // callers pass low <= high (the parser rejects [z-a]); keeps the word math total
53 }
54 // Set whole 64-bit words at once (4 iterations) instead of looping byte by byte.
55 for (unsigned word = 0; word < bits.size(); ++word) {
56 const unsigned word_low {word * 64U};
57 const unsigned word_high {word_low + 63U};
58 if (high < word_low || low > word_high) {
59 continue; // this word holds no byte of [low, high]
60 }
61 const unsigned a {low > word_low ? low - word_low : 0U}; // first bit set, within the word
62 const unsigned b {high < word_high ? high - word_low : 63U}; // last bit set, within the word
63 bits[word] |= (b - a == 63U)
64 ? ~std::uint64_t {0}
65 : (((std::uint64_t {1} << (b - a + 1U)) - 1U) << a);
66 }
67 }
68
73 constexpr void merge(const char_class& other)
74 {
75 for (std::size_t i = 0; i < bits.size(); ++i) {
76 bits[i] |= other.bits[i];
77 }
78 }
79
86 constexpr void invert_ascii()
87 {
88 bits[0] = ~bits[0];
89 bits[1] = ~bits[1];
90 }
91
95 constexpr void invert()
96 {
97 for (auto& word : bits) {
98 word = ~word;
99 }
100 }
101
107 [[nodiscard]] constexpr bool test(std::uint8_t byte) const
108 {
109 const unsigned bit {byte};
110 return ((bits[bit >> 6U] >> (bit & 63U)) & 1U) != 0;
111 }
112
117 [[nodiscard]] constexpr bool empty() const
118 {
119 return (bits[0] | bits[1] | bits[2] | bits[3]) == 0;
120 }
121
122 constexpr bool operator==(const char_class&) const = default;
123 };
124
135 {
136 for (std::uint8_t upper = 'A'; upper <= 'Z'; ++upper) {
137 const auto lower {static_cast<std::uint8_t>(upper + 32)};
138 if (klass.test(upper)) {
139 klass.set(lower);
140 }
141 if (klass.test(lower)) {
142 klass.set(upper);
143 }
144 }
145 }
146
152 [[nodiscard]] constexpr bool is_ascii_word_byte(std::uint8_t byte)
153 {
154 return (byte >= '0' && byte <= '9') || (byte >= 'A' && byte <= 'Z') ||
155 (byte >= 'a' && byte <= 'z') || byte == '_';
156 }
157
163 {
164 char_class result;
165 result.set_range('0', '9');
166 return result;
167 }
168
174 {
175 char_class result;
176 result.set_range('0', '9');
177 result.set_range('A', 'Z');
178 result.set_range('a', 'z');
179 result.set('_');
180 return result;
181 }
182
193 {
194 char_class result;
195 result.set(' ');
196 result.set('\t');
197 result.set('\n');
198 result.set('\r');
199 result.set('\f');
200 result.set('\v');
201 result.set(char {0x1C}); // FS \ Python re \s also matches these four (str.isspace); the generated
202 result.set(char {0x1D}); // GS | space_ranges lists U+001C-U+001F, the ASCII set must agree — the
203 result.set(char {0x1E}); // RS | drift-guard test asserts it.
204 result.set(char {0x1F}); // US /
205 return result;
206 }
207
208 // --- UTF-8 byte-class sets -------------------------------------------------
209 // The single source of truth for how `.` and negated classes expand to bytes:
210 // the compiler emits these sets (compiler.hpp) and the prefilter recognizes
211 // the same shape (prefilter.hpp). Keeping them here keeps the two in lock-step.
212
218 {
219 char_class result;
220 result.set_range(0x80, 0xBF);
221 return result;
222 }
223
229 {
230 char_class result;
231 result.set_range(0xC2, 0xDF);
232 return result;
233 }
234
240 {
241 char_class result;
242 result.set_range(0xE0, 0xEF);
243 return result;
244 }
245
251 {
252 char_class result;
253 result.set_range(0xF0, 0xF4);
254 return result;
255 }
256} // namespace real::detail
257
258#endif // REAL_CHARCLASS_HPP
constexpr char_class digit_set()
The ASCII digit set behind \d (Python re.ASCII semantics).
constexpr char_class utf8_lead3_set()
The lead-byte set of a 3-byte UTF-8 sequence.
constexpr char_class word_set()
The ASCII word set behind \w.
constexpr void fold_ascii_case(char_class &klass)
Closes klass under ASCII case folding.
constexpr char_class utf8_lead2_set()
The lead-byte set of a 2-byte UTF-8 sequence.
constexpr char_class utf8_lead4_set()
The lead-byte set of a 4-byte UTF-8 sequence.
constexpr char_class utf8_cont_set()
The UTF-8 continuation-byte set 10xxxxxx.
constexpr bool is_ascii_word_byte(std::uint8_t byte)
Reports whether byte is an ASCII "word" byte ([0-9A-Za-z_]).
constexpr char_class space_set()
The ASCII whitespace set behind \s.
@ klass
Consume one byte in classes[arg16]; fall through to pc+1.
A set of byte values (0–255) as a 256-bit bitmap.
Definition charclass.hpp:30
constexpr void merge(const char_class &other)
Unions other into this set.
Definition charclass.hpp:73
constexpr void set_range(std::uint8_t low, std::uint8_t high)
Adds the inclusive byte range [low, high] to the set.
Definition charclass.hpp:48
constexpr bool test(std::uint8_t byte) const
Tests membership of byte byte.
constexpr void invert()
Full 256-bit complement (binary mode: raw bytes, no UTF-8).
Definition charclass.hpp:95
constexpr bool operator==(const char_class &) const =default
constexpr void set(std::uint8_t byte)
Adds byte byte to the set.
Definition charclass.hpp:37
constexpr bool empty() const
Reports whether the set has no members.
std::array< std::uint64_t, 4 > bits
Bitmap; bit byte is byte byte's membership.
Definition charclass.hpp:31
constexpr void invert_ascii()
Complements the ASCII half (bytes 0–127) only.
Definition charclass.hpp:86
REAL's version macros and the C++20 language-standard guard.