join 1.0
lightweight network framework library
Loading...
Searching...
No Matches
utf8.hpp
Go to the documentation of this file.
1
25#ifndef JOIN_DATA_UTF8_HPP
26#define JOIN_DATA_UTF8_HPP
27
28// libjoin.
29#include <join/utils.hpp>
30
31// C++.
32#include <algorithm>
33
34// C.
35#include <cstring>
36#include <cstddef>
37#include <cstdint>
38
39namespace join
40{
41 namespace utf8
42 {
43 namespace details
44 {
48 struct alignas (64) SequenceTable
49 {
50 uint8_t data[256];
51 uint8_t lower[8];
52 uint8_t span[8];
57 constexpr SequenceTable ()
58 : data{}
59 , lower{0x80, 0xA0, 0x80, 0x90, 0x80}
60 , span{0x3F, 0x1F, 0x1F, 0x2F, 0x0F}
61 {
62 for (unsigned i = 0xC2; i < 0xE0; ++i)
63 {
64 data[i] = 2;
65 }
66 for (unsigned i = 0xE1; i < 0xF0; ++i)
67 {
68 data[i] = 3;
69 }
70 for (unsigned i = 0xF1; i < 0xF4; ++i)
71 {
72 data[i] = 4;
73 }
74 data[0xE0] = 3 | (1 << 3);
75 data[0xED] = 3 | (2 << 3);
76 data[0xF0] = 4 | (3 << 3);
77 data[0xF4] = 4 | (4 << 3);
78 }
79 };
80
85
89 struct alignas (64) OrderTable
90 {
91 uint8_t data[256];
96 constexpr OrderTable ()
97 : data{}
98 {
99 for (unsigned i = 0; i < 0xEE; ++i)
100 {
101 data[i] = static_cast<uint8_t> (i);
102 }
103 for (unsigned i = 0xF0; i < 0x100; ++i)
104 {
105 data[i] = static_cast<uint8_t> (i - 2);
106 }
107 data[0xEE] = 0xFE;
108 data[0xEF] = 0xFF;
109 }
110 };
111
116
120 constexpr uint64_t highBits = 0x8080808080808080ULL;
121
128 inline uint32_t sequenceLength (const uint8_t* cur, const uint8_t* end) noexcept
129 {
130 uint32_t entry = sequenceLookup.data[cur[0]];
131 uint32_t n = entry & 7;
132
133 if (JOIN_UNLIKELY (n == 0 || static_cast<size_t> (end - cur) < n))
134 {
135 return 0;
136 }
137
138 uint32_t range = entry >> 3;
139 uint32_t bad = static_cast<uint8_t> (cur[1] - sequenceLookup.lower[range]) > sequenceLookup.span[range];
140
141 if (JOIN_LIKELY (end - cur >= 4))
142 {
143 bad |= (n >= 3 ? (cur[2] & 0xC0) ^ 0x80 : 0) | (n == 4 ? (cur[3] & 0xC0) ^ 0x80 : 0);
144 }
145 else
146 {
147 for (uint32_t i = 2; i < n; ++i)
148 {
149 bad |= (cur[i] & 0xC0) ^ 0x80;
150 }
151 }
152
153 return bad ? 0 : n;
154 }
155
162 inline int validateMixed (const uint8_t* cur, const uint8_t* end) noexcept
163 {
164 while (cur < end)
165 {
166 if (JOIN_LIKELY (end - cur >= 8))
167 {
168 uint64_t word;
169 std::memcpy (&word, cur, 8);
170 if (JOIN_LIKELY ((word & highBits) == 0))
171 {
172 cur += 8;
173 continue;
174 }
175 }
176
177 if (*cur < 0x80)
178 {
179 ++cur;
180 continue;
181 }
182
183 do
184 {
185 uint32_t n = sequenceLength (cur, end);
186 if (JOIN_UNLIKELY (n == 0))
187 {
188 return -1;
189 }
190 cur += n;
191 }
192 while (cur < end && *cur >= 0x80);
193 }
194
195 return 0;
196 }
197 }
198
206 inline int decode (const char*& cur, const char* end, uint32_t& codepoint) noexcept
207 {
208 const uint8_t* p = reinterpret_cast<const uint8_t*> (cur);
209
210 if (JOIN_LIKELY (p[0] < 0x80))
211 {
212 codepoint = p[0];
213 ++cur;
214 return 0;
215 }
216
217 uint32_t n = details::sequenceLength (p, reinterpret_cast<const uint8_t*> (end));
218 if (JOIN_UNLIKELY (n == 0))
219 {
220 return -1;
221 }
222
223 uint32_t cp = p[0] & (0xFF >> (n + 1));
224 for (uint32_t i = 1; i < n; ++i)
225 {
226 cp = (cp << 6) | (p[i] & 0x3F);
227 }
228
229 codepoint = cp;
230 cur += n;
231 return 0;
232 }
233
240 inline size_t encode (uint32_t codepoint, char* out) noexcept
241 {
242 if (JOIN_LIKELY (codepoint < 0x80))
243 {
244 out[0] = static_cast<char> (codepoint);
245 return 1;
246 }
247
248 if (codepoint < 0x800)
249 {
250 out[0] = static_cast<char> (0xC0 | (codepoint >> 6));
251 out[1] = static_cast<char> (0x80 | (codepoint & 0x3F));
252 return 2;
253 }
254
255 if (codepoint < 0x10000)
256 {
257 out[0] = static_cast<char> (0xE0 | (codepoint >> 12));
258 out[1] = static_cast<char> (0x80 | ((codepoint >> 6) & 0x3F));
259 out[2] = static_cast<char> (0x80 | (codepoint & 0x3F));
260 return 3;
261 }
262
263 out[0] = static_cast<char> (0xF0 | (codepoint >> 18));
264 out[1] = static_cast<char> (0x80 | ((codepoint >> 12) & 0x3F));
265 out[2] = static_cast<char> (0x80 | ((codepoint >> 6) & 0x3F));
266 out[3] = static_cast<char> (0x80 | (codepoint & 0x3F));
267 return 4;
268 }
269
276 inline int validate (const char* first, const char* last) noexcept
277 {
278 const uint8_t* cur = reinterpret_cast<const uint8_t*> (first);
279 const uint8_t* end = reinterpret_cast<const uint8_t*> (last);
280 uint64_t word;
281
282 if (end - cur < 8)
283 {
284 uint32_t acc = 0;
285 for (const uint8_t* p = cur; p < end; ++p)
286 {
287 acc |= *p;
288 }
289 return JOIN_LIKELY (acc < 0x80) ? 0 : details::validateMixed (cur, end);
290 }
291
292 while (end - cur >= 8)
293 {
294 std::memcpy (&word, cur, 8);
295 if (JOIN_UNLIKELY (word & details::highBits))
296 {
297 return details::validateMixed (cur, end);
298 }
299 cur += 8;
300 }
301
302 std::memcpy (&word, end - 8, 8);
303 return JOIN_LIKELY ((word & details::highBits) == 0) ? 0 : details::validateMixed (cur, end);
304 }
305
314 inline int compareUtf16Order (const char* first1, const char* last1, const char* first2,
315 const char* last2) noexcept
316 {
317 auto mis = std::mismatch (first1, last1, first2, last2);
318
319 if (mis.first == last1)
320 {
321 return (mis.second == last2) ? 0 : -1;
322 }
323
324 if (mis.second == last2)
325 {
326 return 1;
327 }
328
329 return static_cast<int> (details::orderLookup.data[static_cast<uint8_t> (*mis.first)]) -
330 static_cast<int> (details::orderLookup.data[static_cast<uint8_t> (*mis.second)]);
331 }
332 }
333}
334
335#endif
int validateMixed(const uint8_t *cur, const uint8_t *end) noexcept
validate UTF-8 input that may contain multibyte sequences.
Definition utf8.hpp:162
constexpr uint64_t highBits
mask of the high bit of each byte of a 64 bits word.
Definition utf8.hpp:120
uint32_t sequenceLength(const uint8_t *cur, const uint8_t *end) noexcept
get the length of a multibyte sequence.
Definition utf8.hpp:128
constexpr OrderTable orderLookup
UTF-16 code unit order lookup table.
Definition utf8.hpp:115
constexpr SequenceTable sequenceLookup
UTF-8 multibyte sequences lookup table.
Definition utf8.hpp:84
int compareUtf16Order(const char *first1, const char *last1, const char *first2, const char *last2) noexcept
compare two UTF-8 inputs in UTF-16 code unit order.
Definition utf8.hpp:314
int validate(const char *first, const char *last) noexcept
validate UTF-8 input.
Definition utf8.hpp:276
int decode(const char *&cur, const char *end, uint32_t &codepoint) noexcept
decode one codepoint from UTF-8.
Definition utf8.hpp:206
size_t encode(uint32_t codepoint, char *out) noexcept
encode one codepoint to UTF-8.
Definition utf8.hpp:240
Definition acceptor.hpp:32
rank of UTF-8 bytes in UTF-16 code unit order.
Definition utf8.hpp:90
constexpr OrderTable()
create the lookup table.
Definition utf8.hpp:96
uint8_t data[256]
Definition utf8.hpp:91
UTF-8 well-formed multibyte sequences indexed by lead byte.
Definition utf8.hpp:49
constexpr SequenceTable()
create the lookup table.
Definition utf8.hpp:57
uint8_t span[8]
Definition utf8.hpp:52
uint8_t data[256]
Definition utf8.hpp:50
uint8_t lower[8]
Definition utf8.hpp:51
#define JOIN_LIKELY(x)
Definition utils.hpp:50
#define JOIN_UNLIKELY(x)
Definition utils.hpp:51