/work/build/simdutf/simdutf.h
Line | Count | Source |
1 | | /* auto-generated on 2026-10-27 19:06:49 -0400. Do not edit! */ |
2 | | /* begin file include/simdutf.h */ |
3 | | #ifndef SIMDUTF_H |
4 | | #define SIMDUTF_H |
5 | | #include <cstring> |
6 | | |
7 | | /* begin file include/simdutf/compiler_check.h */ |
8 | | #ifndef SIMDUTF_COMPILER_CHECK_H |
9 | | #define SIMDUTF_COMPILER_CHECK_H |
10 | | |
11 | | #ifndef __cplusplus |
12 | | #error simdutf requires a C++ compiler |
13 | | #endif |
14 | | |
15 | | #ifndef SIMDUTF_CPLUSPLUS |
16 | | #if defined(_MSVC_LANG) && !defined(__clang__) |
17 | | #define SIMDUTF_CPLUSPLUS (_MSC_VER == 1900 ? 201103L : _MSVC_LANG) |
18 | | #else |
19 | | #define SIMDUTF_CPLUSPLUS __cplusplus |
20 | | #endif |
21 | | #endif |
22 | | |
23 | | // C++ 26 |
24 | | #if !defined(SIMDUTF_CPLUSPLUS26) && (SIMDUTF_CPLUSPLUS >= 202602L) |
25 | | #define SIMDUTF_CPLUSPLUS26 1 |
26 | | #endif |
27 | | |
28 | | // C++ 23 |
29 | | #if !defined(SIMDUTF_CPLUSPLUS23) && (SIMDUTF_CPLUSPLUS >= 202302L) |
30 | | #define SIMDUTF_CPLUSPLUS23 1 |
31 | | #endif |
32 | | |
33 | | // C++ 20 |
34 | | #if !defined(SIMDUTF_CPLUSPLUS20) && (SIMDUTF_CPLUSPLUS >= 202002L) |
35 | | #define SIMDUTF_CPLUSPLUS20 1 |
36 | | #endif |
37 | | |
38 | | // C++ 17 |
39 | | #if !defined(SIMDUTF_CPLUSPLUS17) && (SIMDUTF_CPLUSPLUS >= 201703L) |
40 | | #define SIMDUTF_CPLUSPLUS17 1 |
41 | | #endif |
42 | | |
43 | | // C++ 14 |
44 | | #if !defined(SIMDUTF_CPLUSPLUS14) && (SIMDUTF_CPLUSPLUS >= 201402L) |
45 | | #define SIMDUTF_CPLUSPLUS14 1 |
46 | | #endif |
47 | | |
48 | | // C++ 11 |
49 | | #if !defined(SIMDUTF_CPLUSPLUS11) && (SIMDUTF_CPLUSPLUS >= 201103L) |
50 | | #define SIMDUTF_CPLUSPLUS11 1 |
51 | | #endif |
52 | | |
53 | | #ifndef SIMDUTF_CPLUSPLUS17 |
54 | | #error simdutf requires a compiler compliant with the C++17 standard |
55 | | #endif |
56 | | |
57 | | #endif // SIMDUTF_COMPILER_CHECK_H |
58 | | /* end file include/simdutf/compiler_check.h */ |
59 | | /* begin file include/simdutf/common_defs.h */ |
60 | | #ifndef SIMDUTF_COMMON_DEFS_H |
61 | | #define SIMDUTF_COMMON_DEFS_H |
62 | | |
63 | | /* begin file include/simdutf/portability.h */ |
64 | | #ifndef SIMDUTF_PORTABILITY_H |
65 | | #define SIMDUTF_PORTABILITY_H |
66 | | |
67 | | |
68 | | #include <cfloat> |
69 | | #include <cstddef> |
70 | | #include <cstdint> |
71 | | #include <cstdio> |
72 | | #include <cstdlib> |
73 | | #ifndef _WIN32 |
74 | | // strcasecmp, strncasecmp |
75 | | #include <strings.h> |
76 | | #endif |
77 | | |
78 | | #if defined(__apple_build_version__) |
79 | | #if __apple_build_version__ < 14000000 |
80 | | #define SIMDUTF_SPAN_DISABLED \ |
81 | | 1 // apple-clang/13 doesn't support std::convertible_to |
82 | | #endif |
83 | | #endif |
84 | | |
85 | | #if SIMDUTF_CPLUSPLUS20 |
86 | | #include <version> |
87 | | #if __cpp_concepts >= 201907L && __cpp_lib_span >= 202002L && \ |
88 | | !defined(SIMDUTF_SPAN_DISABLED) |
89 | | #define SIMDUTF_SPAN 1 |
90 | | #endif // __cpp_concepts >= 201907L && __cpp_lib_span >= 202002L |
91 | | #if __cpp_lib_atomic_ref >= 201806L |
92 | | #define SIMDUTF_ATOMIC_REF 1 |
93 | | #endif // __cpp_lib_atomic_ref |
94 | | #if __has_cpp_attribute(maybe_unused) >= 201603L |
95 | | #define SIMDUTF_MAYBE_UNUSED_AVAILABLE 1 |
96 | | #endif // __has_cpp_attribute(maybe_unused) >= 201603L |
97 | | #endif |
98 | | |
99 | | /** |
100 | | * We want to check that it is actually a little endian system at |
101 | | * compile-time. |
102 | | */ |
103 | | |
104 | | #if defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) |
105 | | #define SIMDUTF_IS_BIG_ENDIAN (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) |
106 | | #elif defined(_WIN32) |
107 | | #define SIMDUTF_IS_BIG_ENDIAN 0 |
108 | | #else |
109 | | #if defined(__APPLE__) || \ |
110 | | defined(__FreeBSD__) // defined __BYTE_ORDER__ && defined |
111 | | // __ORDER_BIG_ENDIAN__ |
112 | | #include <machine/endian.h> |
113 | | #elif defined(sun) || \ |
114 | | defined(__sun) // defined(__APPLE__) || defined(__FreeBSD__) |
115 | | #include <sys/byteorder.h> |
116 | | #else // defined(__APPLE__) || defined(__FreeBSD__) |
117 | | |
118 | | #ifdef __has_include |
119 | | #if __has_include(<endian.h>) |
120 | | #include <endian.h> |
121 | | #endif //__has_include(<endian.h>) |
122 | | #endif //__has_include |
123 | | |
124 | | #endif // defined(__APPLE__) || defined(__FreeBSD__) |
125 | | |
126 | | #ifndef !defined(__BYTE_ORDER__) || !defined(__ORDER_LITTLE_ENDIAN__) |
127 | | #define SIMDUTF_IS_BIG_ENDIAN 0 |
128 | | #endif |
129 | | |
130 | | #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ |
131 | | #define SIMDUTF_IS_BIG_ENDIAN 0 |
132 | | #else // __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ |
133 | | #define SIMDUTF_IS_BIG_ENDIAN 1 |
134 | | #endif // __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ |
135 | | |
136 | | #endif // defined __BYTE_ORDER__ && defined __ORDER_BIG_ENDIAN__ |
137 | | |
138 | | /** |
139 | | * At this point in time, SIMDUTF_IS_BIG_ENDIAN is defined. |
140 | | */ |
141 | | |
142 | | #ifdef _MSC_VER |
143 | | #define SIMDUTF_VISUAL_STUDIO 1 |
144 | | /** |
145 | | * We want to differentiate carefully between |
146 | | * clang under visual studio and regular visual |
147 | | * studio. |
148 | | * |
149 | | * Under clang for Windows, we enable: |
150 | | * * target pragmas so that part and only part of the |
151 | | * code gets compiled for advanced instructions. |
152 | | * |
153 | | */ |
154 | | #ifdef __clang__ |
155 | | // clang under visual studio |
156 | | #define SIMDUTF_CLANG_VISUAL_STUDIO 1 |
157 | | #else |
158 | | // just regular visual studio (best guess) |
159 | | #define SIMDUTF_REGULAR_VISUAL_STUDIO 1 |
160 | | #endif // __clang__ |
161 | | #endif // _MSC_VER |
162 | | |
163 | | #ifdef SIMDUTF_REGULAR_VISUAL_STUDIO |
164 | | // https://en.wikipedia.org/wiki/C_alternative_tokens |
165 | | // This header should have no effect, except maybe |
166 | | // under Visual Studio. |
167 | | #include <iso646.h> |
168 | | #endif |
169 | | |
170 | | #if (defined(__x86_64__) || defined(_M_AMD64)) && !defined(_M_ARM64EC) |
171 | | #define SIMDUTF_IS_X86_64 1 |
172 | | #elif defined(__aarch64__) || defined(_M_ARM64) || defined(_M_ARM64EC) |
173 | | #define SIMDUTF_IS_ARM64 1 |
174 | | #elif defined(__PPC64__) || defined(_M_PPC64) |
175 | | #if defined(__VEC__) && defined(__ALTIVEC__) && defined(__POWER8_VECTOR__) |
176 | | #define SIMDUTF_IS_PPC64 1 |
177 | | #endif |
178 | | #elif defined(__s390__) |
179 | | // s390 IBM system. Big endian. |
180 | | #elif (defined(__riscv) || defined(__riscv__)) && __riscv_xlen == 64 |
181 | | // RISC-V 64-bit |
182 | | #define SIMDUTF_IS_RISCV64 1 |
183 | | |
184 | | // #if __riscv_v_intrinsic >= 1000000 |
185 | | // #define SIMDUTF_HAS_RVV_INTRINSICS 1 |
186 | | // #define SIMDUTF_HAS_RVV_TARGET_REGION 1 |
187 | | // #elif ... |
188 | | // Check for special compiler versions that implement pre v1.0 intrinsics |
189 | | #if __riscv_v_intrinsic >= 11000 |
190 | | #define SIMDUTF_HAS_RVV_INTRINSICS 1 |
191 | | #endif |
192 | | |
193 | | #define SIMDUTF_HAS_ZVBB_INTRINSICS \ |
194 | | 0 // there is currently no way to detect this |
195 | | |
196 | | #if SIMDUTF_HAS_RVV_INTRINSICS && __riscv_vector && \ |
197 | | __riscv_v_min_vlen >= 128 && __riscv_v_elen >= 64 |
198 | | // RISC-V V extension |
199 | | #define SIMDUTF_IS_RVV 1 |
200 | | #if SIMDUTF_HAS_ZVBB_INTRINSICS && __riscv_zvbb >= 1000000 |
201 | | // RISC-V Vector Basic Bit-manipulation |
202 | | #define SIMDUTF_IS_ZVBB 1 |
203 | | #endif |
204 | | #endif |
205 | | |
206 | | #elif defined(__loongarch_lp64) |
207 | | #if defined(__loongarch_sx) && defined(__loongarch_asx) |
208 | | #define SIMDUTF_IS_LSX 1 |
209 | | #define SIMDUTF_IS_LASX 1 // We can always run both |
210 | | #elif defined(__loongarch_sx) |
211 | | #define SIMDUTF_IS_LSX 1 |
212 | | // Adjust for runtime dispatching support. |
213 | | #if defined(__GNUC__) && !defined(__clang__) && \ |
214 | | !defined(__INTEL_COMPILER) && !defined(__NVCOMPILER) |
215 | | #if __GNUC__ > 15 || (__GNUC__ == 15 && __GNUC_MINOR__ >= 0) |
216 | | // We are ok, we will support runtime dispatch for LASX. |
217 | | #else |
218 | | // We disable runtime dispatch for LASX, which means that we will not be |
219 | | // able to use LASX even if it is supported by the hardware. Loongson |
220 | | // users should update to GCC 15 or better. |
221 | | #define SIMDUTF_IMPLEMENTATION_LASX 0 |
222 | | #endif |
223 | | #else |
224 | | // We are not using GCC, so we assume that we can support runtime dispatch |
225 | | // for LASX. https://godbolt.org/z/jcMnrjYhs |
226 | | #define SIMDUTF_IMPLEMENTATION_LASX 0 |
227 | | #endif |
228 | | #endif |
229 | | #else |
230 | | // The simdutf library is designed |
231 | | // for 64-bit processors and it seems that you are not |
232 | | // compiling for a known 64-bit platform. Please |
233 | | // use a 64-bit target such as x64 or 64-bit ARM for best performance. |
234 | | #define SIMDUTF_IS_32BITS 1 |
235 | | |
236 | | // We do not support 32-bit platforms, but it can be |
237 | | // handy to identify them. |
238 | | #if defined(_M_IX86) || defined(__i386__) |
239 | | #define SIMDUTF_IS_X86_32BITS 1 |
240 | | #elif defined(__arm__) || defined(_M_ARM) |
241 | | #define SIMDUTF_IS_ARM_32BITS 1 |
242 | | #elif defined(__PPC__) || defined(_M_PPC) |
243 | | #define SIMDUTF_IS_PPC_32BITS 1 |
244 | | #endif |
245 | | |
246 | | #endif // defined(__x86_64__) || defined(_M_AMD64) |
247 | | |
248 | | #ifdef SIMDUTF_IS_32BITS |
249 | | #ifndef SIMDUTF_NO_PORTABILITY_WARNING |
250 | | // In the future, we may want to warn users of 32-bit systems that |
251 | | // the simdutf does not support accelerated kernels for such systems. |
252 | | #endif // SIMDUTF_NO_PORTABILITY_WARNING |
253 | | #endif // SIMDUTF_IS_32BITS |
254 | | |
255 | | // this is almost standard? |
256 | 0 | #define SIMDUTF_STRINGIFY_IMPLEMENTATION_(a) #a |
257 | 0 | #define SIMDUTF_STRINGIFY(a) SIMDUTF_STRINGIFY_IMPLEMENTATION_(a) |
258 | | |
259 | | // Our fast kernels require 64-bit systems. |
260 | | // |
261 | | // On 32-bit x86, we lack 64-bit popcnt, lzcnt, blsr instructions. |
262 | | // Furthermore, the number of SIMD registers is reduced. |
263 | | // |
264 | | // On 32-bit ARM, we would have smaller registers. |
265 | | // |
266 | | // The simdutf users should still have the fallback kernel. It is |
267 | | // slower, but it should run everywhere. |
268 | | |
269 | | // |
270 | | // Enable valid runtime implementations, and select |
271 | | // SIMDUTF_BUILTIN_IMPLEMENTATION |
272 | | // |
273 | | |
274 | | // We are going to use runtime dispatch. |
275 | | #if defined(SIMDUTF_IS_X86_64) || defined(SIMDUTF_IS_LSX) |
276 | | #ifdef __clang__ |
277 | | // clang does not have GCC push pop |
278 | | // warning: clang attribute push can't be used within a namespace in clang |
279 | | // up til 8.0 so SIMDUTF_TARGET_REGION and SIMDUTF_UNTARGET_REGION must be |
280 | | // *outside* of a namespace. |
281 | | #define SIMDUTF_TARGET_REGION(T) \ |
282 | | _Pragma(SIMDUTF_STRINGIFY(clang attribute push( \ |
283 | | __attribute__((target(T))), apply_to = function))) |
284 | | #define SIMDUTF_UNTARGET_REGION _Pragma("clang attribute pop") |
285 | | #elif defined(__GNUC__) |
286 | | // GCC is easier |
287 | | #define SIMDUTF_TARGET_REGION(T) \ |
288 | | _Pragma("GCC push_options") _Pragma(SIMDUTF_STRINGIFY(GCC target(T))) |
289 | | #define SIMDUTF_UNTARGET_REGION _Pragma("GCC pop_options") |
290 | | #endif // clang then gcc |
291 | | |
292 | | #endif // defined(SIMDUTF_IS_X86_64) || defined(SIMDUTF_IS_LSX) |
293 | | |
294 | | // Default target region macros don't do anything. |
295 | | #ifndef SIMDUTF_TARGET_REGION |
296 | | #define SIMDUTF_TARGET_REGION(T) |
297 | | #define SIMDUTF_UNTARGET_REGION |
298 | | #endif |
299 | | |
300 | | // Is threading enabled? |
301 | | #if defined(_REENTRANT) || defined(_MT) |
302 | | #ifndef SIMDUTF_THREADS_ENABLED |
303 | | #define SIMDUTF_THREADS_ENABLED |
304 | | #endif |
305 | | #endif |
306 | | |
307 | | // workaround for large stack sizes under -O0. |
308 | | // https://github.com/simdutf/simdutf/issues/691 |
309 | | #ifdef __APPLE__ |
310 | | #ifndef __OPTIMIZE__ |
311 | | // Apple systems have small stack sizes in secondary threads. |
312 | | // Lack of compiler optimization may generate high stack usage. |
313 | | // Users may want to disable threads for safety, but only when |
314 | | // in debug mode which we detect by the fact that the __OPTIMIZE__ |
315 | | // macro is not defined. |
316 | | #undef SIMDUTF_THREADS_ENABLED |
317 | | #endif |
318 | | #endif |
319 | | |
320 | | #ifdef SIMDUTF_VISUAL_STUDIO |
321 | | // This is one case where we do not distinguish between |
322 | | // regular visual studio and clang under visual studio. |
323 | | // clang under Windows has _stricmp (like visual studio) but not strcasecmp |
324 | | // (as clang normally has) |
325 | | #define simdutf_strcasecmp _stricmp |
326 | | #define simdutf_strncasecmp _strnicmp |
327 | | #else |
328 | | // The strcasecmp, strncasecmp, and strcasestr functions do not work with |
329 | | // multibyte strings (e.g. UTF-8). So they are only useful for ASCII in our |
330 | | // context. |
331 | | // https://www.gnu.org/software/libunistring/manual/libunistring.html#char-_002a-strings |
332 | | #define simdutf_strcasecmp strcasecmp |
333 | | #define simdutf_strncasecmp strncasecmp |
334 | | #endif |
335 | | |
336 | | #if defined(__GNUC__) && !defined(__clang__) |
337 | | #if __GNUC__ >= 11 |
338 | | #define SIMDUTF_GCC11ORMORE 1 |
339 | | #endif // __GNUC__ >= 11 |
340 | | #if __GNUC__ == 10 |
341 | | #define SIMDUTF_GCC10 1 |
342 | | #endif // __GNUC__ == 10 |
343 | | #if __GNUC__ < 10 |
344 | | #define SIMDUTF_GCC9OROLDER 1 |
345 | | #endif // __GNUC__ == 10 |
346 | | #endif // defined(__GNUC__) && !defined(__clang__) |
347 | | |
348 | | #endif // SIMDUTF_PORTABILITY_H |
349 | | /* end file include/simdutf/portability.h */ |
350 | | /* begin file include/simdutf/avx512.h */ |
351 | | #ifndef SIMDUTF_AVX512_H_ |
352 | | #define SIMDUTF_AVX512_H_ |
353 | | |
354 | | /* |
355 | | It's possible to override AVX512 settings with cmake DCMAKE_CXX_FLAGS. |
356 | | |
357 | | All preprocessor directives has form `SIMDUTF_HAS_AVX512{feature}`, |
358 | | where a feature is a code name for extensions. |
359 | | |
360 | | Please see the listing below to find which are supported. |
361 | | */ |
362 | | |
363 | | #ifndef SIMDUTF_HAS_AVX512F |
364 | | #if defined(__AVX512F__) && __AVX512F__ == 1 |
365 | | #define SIMDUTF_HAS_AVX512F 1 |
366 | | #endif |
367 | | #endif |
368 | | |
369 | | #ifndef SIMDUTF_HAS_AVX512DQ |
370 | | #if defined(__AVX512DQ__) && __AVX512DQ__ == 1 |
371 | | #define SIMDUTF_HAS_AVX512DQ 1 |
372 | | #endif |
373 | | #endif |
374 | | |
375 | | #ifndef SIMDUTF_HAS_AVX512IFMA |
376 | | #if defined(__AVX512IFMA__) && __AVX512IFMA__ == 1 |
377 | | #define SIMDUTF_HAS_AVX512IFMA 1 |
378 | | #endif |
379 | | #endif |
380 | | |
381 | | #ifndef SIMDUTF_HAS_AVX512CD |
382 | | #if defined(__AVX512CD__) && __AVX512CD__ == 1 |
383 | | #define SIMDUTF_HAS_AVX512CD 1 |
384 | | #endif |
385 | | #endif |
386 | | |
387 | | #ifndef SIMDUTF_HAS_AVX512BW |
388 | | #if defined(__AVX512BW__) && __AVX512BW__ == 1 |
389 | | #define SIMDUTF_HAS_AVX512BW 1 |
390 | | #endif |
391 | | #endif |
392 | | |
393 | | #ifndef SIMDUTF_HAS_AVX512VL |
394 | | #if defined(__AVX512VL__) && __AVX512VL__ == 1 |
395 | | #define SIMDUTF_HAS_AVX512VL 1 |
396 | | #endif |
397 | | #endif |
398 | | |
399 | | #ifndef SIMDUTF_HAS_AVX512VBMI |
400 | | #if defined(__AVX512VBMI__) && __AVX512VBMI__ == 1 |
401 | | #define SIMDUTF_HAS_AVX512VBMI 1 |
402 | | #endif |
403 | | #endif |
404 | | |
405 | | #ifndef SIMDUTF_HAS_AVX512VBMI2 |
406 | | #if defined(__AVX512VBMI2__) && __AVX512VBMI2__ == 1 |
407 | | #define SIMDUTF_HAS_AVX512VBMI2 1 |
408 | | #endif |
409 | | #endif |
410 | | |
411 | | #ifndef SIMDUTF_HAS_AVX512VNNI |
412 | | #if defined(__AVX512VNNI__) && __AVX512VNNI__ == 1 |
413 | | #define SIMDUTF_HAS_AVX512VNNI 1 |
414 | | #endif |
415 | | #endif |
416 | | |
417 | | #ifndef SIMDUTF_HAS_AVX512BITALG |
418 | | #if defined(__AVX512BITALG__) && __AVX512BITALG__ == 1 |
419 | | #define SIMDUTF_HAS_AVX512BITALG 1 |
420 | | #endif |
421 | | #endif |
422 | | |
423 | | #ifndef SIMDUTF_HAS_AVX512VPOPCNTDQ |
424 | | #if defined(__AVX512VPOPCNTDQ__) && __AVX512VPOPCNTDQ__ == 1 |
425 | | #define SIMDUTF_HAS_AVX512VPOPCNTDQ 1 |
426 | | #endif |
427 | | #endif |
428 | | |
429 | | #endif // SIMDUTF_AVX512_H_ |
430 | | /* end file include/simdutf/avx512.h */ |
431 | | |
432 | | // Sometimes logging is useful, but we want it disabled by default |
433 | | // and free of any logging code in release builds. |
434 | | #ifdef SIMDUTF_LOGGING |
435 | | #include <cstdlib> |
436 | | #include <iostream> |
437 | | #define simdutf_log(msg) \ |
438 | | std::cout << "[" << __FUNCTION__ << "]: " << msg << std::endl \ |
439 | | << "\t" << __FILE__ << ":" << __LINE__ << std::endl; |
440 | | #define simdutf_log_assert(cond, msg) \ |
441 | | do { \ |
442 | | if (!(cond)) { \ |
443 | | std::cerr << "[" << __FUNCTION__ << "]: " << msg << std::endl \ |
444 | | << "\t" << __FILE__ << ":" << __LINE__ << std::endl; \ |
445 | | std::abort(); \ |
446 | | } \ |
447 | | } while (0) |
448 | | #else |
449 | | #define simdutf_log(msg) |
450 | | #define simdutf_log_assert(cond, msg) |
451 | | #endif |
452 | | |
453 | | #if SIMDUTF_CPLUSPLUS17 |
454 | | #define simdutf_unused [[maybe_unused]] |
455 | | #endif // SIMDUTF_CPLUSPLUS17 |
456 | | |
457 | | #if defined(SIMDUTF_REGULAR_VISUAL_STUDIO) |
458 | | #define SIMDUTF_DEPRECATED __declspec(deprecated) |
459 | | |
460 | | #define simdutf_really_inline __forceinline // really inline in release mode |
461 | | #define simdutf_always_inline __forceinline // always inline, no matter what |
462 | | #define simdutf_never_inline __declspec(noinline) |
463 | | |
464 | | #ifndef simdutf_unused |
465 | | #define simdutf_unused |
466 | | #endif // simdutf_unused |
467 | | #define simdutf_warn_unused |
468 | | |
469 | | #ifndef simdutf_likely |
470 | | #define simdutf_likely(x) x |
471 | | #endif |
472 | | #ifndef simdutf_unlikely |
473 | | #define simdutf_unlikely(x) x |
474 | | #endif |
475 | | |
476 | | #define SIMDUTF_PUSH_DISABLE_WARNINGS __pragma(warning(push)) |
477 | | #define SIMDUTF_PUSH_DISABLE_ALL_WARNINGS __pragma(warning(push, 0)) |
478 | | #define SIMDUTF_DISABLE_VS_WARNING(WARNING_NUMBER) \ |
479 | | __pragma(warning(disable : WARNING_NUMBER)) |
480 | | // Get rid of Intellisense-only warnings (Code Analysis) |
481 | | // Though __has_include is C++17, it is supported in Visual Studio 2017 or |
482 | | // better (_MSC_VER>=1910). |
483 | | #ifdef __has_include |
484 | | #if __has_include(<CppCoreCheck\Warnings.h>) |
485 | | #include <CppCoreCheck\Warnings.h> |
486 | | #define SIMDUTF_DISABLE_UNDESIRED_WARNINGS \ |
487 | | SIMDUTF_DISABLE_VS_WARNING(ALL_CPPCORECHECK_WARNINGS) |
488 | | #endif |
489 | | #endif |
490 | | |
491 | | #ifndef SIMDUTF_DISABLE_UNDESIRED_WARNINGS |
492 | | #define SIMDUTF_DISABLE_UNDESIRED_WARNINGS |
493 | | #endif |
494 | | |
495 | | #define SIMDUTF_DISABLE_DEPRECATED_WARNING SIMDUTF_DISABLE_VS_WARNING(4996) |
496 | | #define SIMDUTF_DISABLE_STRICT_OVERFLOW_WARNING |
497 | | #define SIMDUTF_POP_DISABLE_WARNINGS __pragma(warning(pop)) |
498 | | #define SIMDUTF_DISABLE_UNUSED_WARNING |
499 | | #else // SIMDUTF_REGULAR_VISUAL_STUDIO |
500 | | #if defined(__OPTIMIZE__) || defined(NDEBUG) |
501 | | #define simdutf_really_inline inline __attribute__((always_inline)) |
502 | | #else |
503 | | #define simdutf_really_inline inline |
504 | | #endif |
505 | | #define simdutf_always_inline \ |
506 | | inline __attribute__((always_inline)) // always inline, no matter what |
507 | | #define SIMDUTF_DEPRECATED __attribute__((deprecated)) |
508 | | #define simdutf_never_inline inline __attribute__((noinline)) |
509 | | #ifndef simdutf_unused |
510 | | #define simdutf_unused __attribute__((unused)) |
511 | | #endif // simdutf_unused |
512 | | #define simdutf_warn_unused __attribute__((warn_unused_result)) |
513 | | |
514 | | #ifndef simdutf_likely |
515 | 0 | #define simdutf_likely(x) __builtin_expect(!!(x), 1) |
516 | | #endif |
517 | | #ifndef simdutf_unlikely |
518 | 0 | #define simdutf_unlikely(x) __builtin_expect(!!(x), 0) |
519 | | #endif |
520 | | // clang-format off |
521 | | #define SIMDUTF_PUSH_DISABLE_WARNINGS _Pragma("GCC diagnostic push") |
522 | | // gcc doesn't seem to disable all warnings with all and extra, add warnings |
523 | | // here as necessary |
524 | | #define SIMDUTF_PUSH_DISABLE_ALL_WARNINGS \ |
525 | | SIMDUTF_PUSH_DISABLE_WARNINGS \ |
526 | | SIMDUTF_DISABLE_GCC_WARNING(-Weffc++) \ |
527 | | SIMDUTF_DISABLE_GCC_WARNING(-Wall) \ |
528 | | SIMDUTF_DISABLE_GCC_WARNING(-Wconversion) \ |
529 | | SIMDUTF_DISABLE_GCC_WARNING(-Wextra) \ |
530 | | SIMDUTF_DISABLE_GCC_WARNING(-Wattributes) \ |
531 | | SIMDUTF_DISABLE_GCC_WARNING(-Wimplicit-fallthrough) \ |
532 | | SIMDUTF_DISABLE_GCC_WARNING(-Wnon-virtual-dtor) \ |
533 | | SIMDUTF_DISABLE_GCC_WARNING(-Wreturn-type) \ |
534 | | SIMDUTF_DISABLE_GCC_WARNING(-Wshadow) \ |
535 | | SIMDUTF_DISABLE_GCC_WARNING(-Wunused-parameter) \ |
536 | | SIMDUTF_DISABLE_GCC_WARNING(-Wunused-variable) |
537 | | #define SIMDUTF_PRAGMA(P) _Pragma(#P) |
538 | | #define SIMDUTF_DISABLE_GCC_WARNING(WARNING) \ |
539 | | SIMDUTF_PRAGMA(GCC diagnostic ignored #WARNING) |
540 | | #if defined(SIMDUTF_CLANG_VISUAL_STUDIO) |
541 | | #define SIMDUTF_DISABLE_UNDESIRED_WARNINGS \ |
542 | | SIMDUTF_DISABLE_GCC_WARNING(-Wmicrosoft-include) |
543 | | #else |
544 | | #define SIMDUTF_DISABLE_UNDESIRED_WARNINGS |
545 | | #endif |
546 | | #define SIMDUTF_DISABLE_DEPRECATED_WARNING \ |
547 | | SIMDUTF_DISABLE_GCC_WARNING(-Wdeprecated-declarations) |
548 | | #define SIMDUTF_DISABLE_STRICT_OVERFLOW_WARNING \ |
549 | | SIMDUTF_DISABLE_GCC_WARNING(-Wstrict-overflow) |
550 | | #define SIMDUTF_POP_DISABLE_WARNINGS _Pragma("GCC diagnostic pop") |
551 | | #define SIMDUTF_DISABLE_UNUSED_WARNING \ |
552 | | SIMDUTF_PUSH_DISABLE_WARNINGS \ |
553 | | SIMDUTF_DISABLE_GCC_WARNING(-Wunused-function) \ |
554 | | SIMDUTF_DISABLE_GCC_WARNING(-Wunused-const-variable) |
555 | | // clang-format on |
556 | | |
557 | | #endif // MSC_VER |
558 | | |
559 | | // Will evaluate to constexpr in C++23 or later. This makes it possible to mark |
560 | | // functions constexpr if the "if consteval" feature is available to use. |
561 | | #if SIMDUTF_CPLUSPLUS23 |
562 | | #define simdutf_constexpr23 constexpr |
563 | | #else |
564 | | #define simdutf_constexpr23 |
565 | | #endif |
566 | | |
567 | | #ifndef SIMDUTF_DLLIMPORTEXPORT |
568 | | #if defined(SIMDUTF_VISUAL_STUDIO) // Visual Studio |
569 | | /** |
570 | | * Windows users need to do some extra work when building |
571 | | * or using a dynamic library (DLL). When building, we need |
572 | | * to set SIMDUTF_DLLIMPORTEXPORT to __declspec(dllexport). |
573 | | * When *using* the DLL, the user needs to set |
574 | | * SIMDUTF_DLLIMPORTEXPORT __declspec(dllimport). |
575 | | * |
576 | | * Static libraries not need require such work. |
577 | | * |
578 | | * It does not matter here whether you are using |
579 | | * the regular visual studio or clang under visual |
580 | | * studio, you still need to handle these issues. |
581 | | * |
582 | | * Non-Windows systems do not have this complexity. |
583 | | */ |
584 | | #if SIMDUTF_BUILDING_WINDOWS_DYNAMIC_LIBRARY |
585 | | |
586 | | // We set SIMDUTF_BUILDING_WINDOWS_DYNAMIC_LIBRARY when we build a DLL |
587 | | // under Windows. It should never happen that both |
588 | | // SIMDUTF_BUILDING_WINDOWS_DYNAMIC_LIBRARY and |
589 | | // SIMDUTF_USING_WINDOWS_DYNAMIC_LIBRARY are set. |
590 | | #define SIMDUTF_DLLIMPORTEXPORT __declspec(dllexport) |
591 | | #elif SIMDUTF_USING_WINDOWS_DYNAMIC_LIBRARY |
592 | | // Windows user who call a dynamic library should set |
593 | | // SIMDUTF_USING_WINDOWS_DYNAMIC_LIBRARY to 1. |
594 | | |
595 | | #define SIMDUTF_DLLIMPORTEXPORT __declspec(dllimport) |
596 | | #else |
597 | | // We assume by default static linkage |
598 | | #define SIMDUTF_DLLIMPORTEXPORT |
599 | | #endif |
600 | | #else // defined(SIMDUTF_VISUAL_STUDIO) |
601 | | // Non-Windows systems do not have this complexity. |
602 | | #define SIMDUTF_DLLIMPORTEXPORT |
603 | | #endif // defined(SIMDUTF_VISUAL_STUDIO) |
604 | | #endif |
605 | | |
606 | | #if SIMDUTF_MAYBE_UNUSED_AVAILABLE |
607 | | #define simdutf_maybe_unused [[maybe_unused]] |
608 | | #else |
609 | | #define simdutf_maybe_unused |
610 | | #endif |
611 | | |
612 | | #endif // SIMDUTF_COMMON_DEFS_H |
613 | | /* end file include/simdutf/common_defs.h */ |
614 | | /* begin file include/simdutf/encoding_types.h */ |
615 | | #ifndef SIMDUTF_ENCODING_TYPES_H |
616 | | #define SIMDUTF_ENCODING_TYPES_H |
617 | | #include <string_view> |
618 | | |
619 | | #if !defined(SIMDUTF_NO_STD_TEXT_ENCODING) && \ |
620 | | defined(__cpp_lib_text_encoding) && __cpp_lib_text_encoding >= 202306L |
621 | | #define SIMDUTF_HAS_STD_TEXT_ENCODING 1 |
622 | | #include <text_encoding> |
623 | | #endif |
624 | | |
625 | | namespace simdutf { |
626 | | |
627 | | enum encoding_type { |
628 | | UTF8 = 1, // BOM 0xef 0xbb 0xbf |
629 | | UTF16_LE = 2, // BOM 0xff 0xfe |
630 | | UTF16_BE = 4, // BOM 0xfe 0xff |
631 | | UTF32_LE = 8, // BOM 0xff 0xfe 0x00 0x00 |
632 | | UTF32_BE = 16, // BOM 0x00 0x00 0xfe 0xff |
633 | | Latin1 = 32, |
634 | | |
635 | | unspecified = 0 |
636 | | }; |
637 | | |
638 | | #ifndef SIMDUTF_IS_BIG_ENDIAN |
639 | | #error "SIMDUTF_IS_BIG_ENDIAN needs to be defined." |
640 | | #endif |
641 | | |
642 | | enum endianness { |
643 | | LITTLE = 0, |
644 | | BIG = 1, |
645 | | NATIVE = |
646 | | #if SIMDUTF_IS_BIG_ENDIAN |
647 | | BIG |
648 | | #else |
649 | | LITTLE |
650 | | #endif |
651 | | }; |
652 | | |
653 | | simdutf_warn_unused simdutf_really_inline constexpr bool |
654 | 0 | match_system(endianness e) { |
655 | 0 | return e == endianness::NATIVE; |
656 | 0 | } |
657 | | |
658 | | simdutf_warn_unused std::string_view to_string(encoding_type bom); |
659 | | |
660 | | // Note that BOM for UTF8 is discouraged. |
661 | | namespace BOM { |
662 | | |
663 | | /** |
664 | | * Checks for a BOM. If not, returns unspecified |
665 | | * @param byte the string to process |
666 | | * @param length the length of the string in code units |
667 | | * @return the corresponding encoding |
668 | | */ |
669 | | |
670 | | simdutf_warn_unused encoding_type check_bom(const uint8_t *byte, size_t length); |
671 | | simdutf_warn_unused encoding_type check_bom(const char *byte, size_t length); |
672 | | /** |
673 | | * Returns the size, in bytes, of the BOM for a given encoding type. |
674 | | * Note that UTF8 BOM are discouraged. |
675 | | * @param bom the encoding type |
676 | | * @return the size in bytes of the corresponding BOM |
677 | | */ |
678 | | simdutf_warn_unused size_t bom_byte_size(encoding_type bom); |
679 | | |
680 | | } // namespace BOM |
681 | | |
682 | | #ifdef SIMDUTF_HAS_STD_TEXT_ENCODING |
683 | | /** |
684 | | * Convert a simdutf encoding type to a std::text_encoding. |
685 | | * |
686 | | * @param enc the simdutf encoding type |
687 | | * @return the corresponding std::text_encoding, or |
688 | | * std::text_encoding::id::unknown for unspecified/unsupported |
689 | | */ |
690 | | simdutf_warn_unused constexpr std::text_encoding |
691 | | to_std_encoding(encoding_type enc) noexcept { |
692 | | switch (enc) { |
693 | | case UTF8: |
694 | | return std::text_encoding(std::text_encoding::id::UTF8); |
695 | | case UTF16_LE: |
696 | | return std::text_encoding(std::text_encoding::id::UTF16LE); |
697 | | case UTF16_BE: |
698 | | return std::text_encoding(std::text_encoding::id::UTF16BE); |
699 | | case UTF32_LE: |
700 | | return std::text_encoding(std::text_encoding::id::UTF32LE); |
701 | | case UTF32_BE: |
702 | | return std::text_encoding(std::text_encoding::id::UTF32BE); |
703 | | case Latin1: |
704 | | return std::text_encoding(std::text_encoding::id::ISOLatin1); |
705 | | case unspecified: |
706 | | default: |
707 | | return std::text_encoding(std::text_encoding::id::unknown); |
708 | | } |
709 | | } |
710 | | |
711 | | /** |
712 | | * Convert a std::text_encoding to a simdutf encoding type. |
713 | | * |
714 | | * @param enc the std::text_encoding |
715 | | * @return the corresponding simdutf encoding type, or |
716 | | * encoding_type::unspecified if the encoding is not supported |
717 | | */ |
718 | | simdutf_warn_unused constexpr encoding_type |
719 | | from_std_encoding(const std::text_encoding &enc) noexcept { |
720 | | switch (enc.mib()) { |
721 | | case std::text_encoding::id::UTF8: |
722 | | return UTF8; |
723 | | case std::text_encoding::id::UTF16LE: |
724 | | return UTF16_LE; |
725 | | case std::text_encoding::id::UTF16BE: |
726 | | return UTF16_BE; |
727 | | case std::text_encoding::id::UTF32LE: |
728 | | return UTF32_LE; |
729 | | case std::text_encoding::id::UTF32BE: |
730 | | return UTF32_BE; |
731 | | case std::text_encoding::id::ISOLatin1: |
732 | | return Latin1; |
733 | | default: |
734 | | return unspecified; |
735 | | } |
736 | | } |
737 | | |
738 | | /** |
739 | | * Get the native-endian UTF-16 encoding type for this system. |
740 | | * |
741 | | * @return UTF16_LE on little-endian systems, UTF16_BE on big-endian systems |
742 | | */ |
743 | | simdutf_warn_unused constexpr encoding_type native_utf16_encoding() noexcept { |
744 | | #if SIMDUTF_IS_BIG_ENDIAN |
745 | | return UTF16_BE; |
746 | | #else |
747 | | return UTF16_LE; |
748 | | #endif |
749 | | } |
750 | | |
751 | | /** |
752 | | * Get the native-endian UTF-32 encoding type for this system. |
753 | | * |
754 | | * @return UTF32_LE on little-endian systems, UTF32_BE on big-endian systems |
755 | | */ |
756 | | simdutf_warn_unused constexpr encoding_type native_utf32_encoding() noexcept { |
757 | | #if SIMDUTF_IS_BIG_ENDIAN |
758 | | return UTF32_BE; |
759 | | #else |
760 | | return UTF32_LE; |
761 | | #endif |
762 | | } |
763 | | |
764 | | /** |
765 | | * Convert a std::text_encoding to a simdutf encoding type, |
766 | | * using native endianness for UTF-16/UTF-32 without explicit endianness. |
767 | | * |
768 | | * When the input is std::text_encoding::id::UTF16 or UTF32 (without LE/BE |
769 | | * suffix), this returns the native-endian simdutf variant. |
770 | | * |
771 | | * @param enc the std::text_encoding |
772 | | * @return the corresponding simdutf encoding type, or |
773 | | * encoding_type::unspecified if the encoding is not supported |
774 | | */ |
775 | | simdutf_warn_unused constexpr encoding_type |
776 | | from_std_encoding_native(const std::text_encoding &enc) noexcept { |
777 | | switch (enc.mib()) { |
778 | | case std::text_encoding::id::UTF8: |
779 | | return UTF8; |
780 | | case std::text_encoding::id::UTF16: |
781 | | return native_utf16_encoding(); |
782 | | case std::text_encoding::id::UTF16LE: |
783 | | return UTF16_LE; |
784 | | case std::text_encoding::id::UTF16BE: |
785 | | return UTF16_BE; |
786 | | case std::text_encoding::id::UTF32: |
787 | | return native_utf32_encoding(); |
788 | | case std::text_encoding::id::UTF32LE: |
789 | | return UTF32_LE; |
790 | | case std::text_encoding::id::UTF32BE: |
791 | | return UTF32_BE; |
792 | | case std::text_encoding::id::ISOLatin1: |
793 | | return Latin1; |
794 | | default: |
795 | | return unspecified; |
796 | | } |
797 | | } |
798 | | #endif // SIMDUTF_HAS_STD_TEXT_ENCODING |
799 | | |
800 | | } // namespace simdutf |
801 | | #endif |
802 | | /* end file include/simdutf/encoding_types.h */ |
803 | | /* begin file include/simdutf/error.h */ |
804 | | #ifndef SIMDUTF_ERROR_H |
805 | | #define SIMDUTF_ERROR_H |
806 | | #include <string_view> |
807 | | |
808 | | namespace simdutf { |
809 | | |
810 | | enum error_code { |
811 | | SUCCESS = 0, |
812 | | HEADER_BITS, // Any byte must have fewer than 5 header bits. |
813 | | TOO_SHORT, // The leading byte must be followed by N-1 continuation bytes, |
814 | | // where N is the UTF-8 character length This is also the error |
815 | | // when the input is truncated. |
816 | | TOO_LONG, // We either have too many consecutive continuation bytes or the |
817 | | // string starts with a continuation byte. |
818 | | OVERLONG, // The decoded character must be above U+7F for two-byte characters, |
819 | | // U+7FF for three-byte characters, and U+FFFF for four-byte |
820 | | // characters. |
821 | | TOO_LARGE, // The decoded character must be less than or equal to |
822 | | // U+10FFFF,less than or equal than U+7F for ASCII OR less than |
823 | | // equal than U+FF for Latin1 |
824 | | SURROGATE, // The decoded character must be not be in U+D800...DFFF (UTF-8 or |
825 | | // UTF-32) |
826 | | // OR |
827 | | // a high surrogate must be followed by a low surrogate |
828 | | // and a low surrogate must be preceded by a high surrogate |
829 | | // (UTF-16) |
830 | | // OR |
831 | | // there must be no surrogate at all and one is |
832 | | // found (Latin1 functions) |
833 | | // OR |
834 | | // *specifically* for the function |
835 | | // utf8_length_from_utf16_with_replacement, a surrogate (whether |
836 | | // in error or not) has been found (I.e., whether we are in the |
837 | | // Basic Multilingual Plane or not). |
838 | | INVALID_BASE64_CHARACTER, // Found a character that cannot be part of a valid |
839 | | // base64 string. This may include a misplaced |
840 | | // padding character ('='). |
841 | | BASE64_INPUT_REMAINDER, // The base64 input terminates with a single |
842 | | // character, excluding padding (=). It is also used |
843 | | // in strict mode when padding is not adequate. |
844 | | BASE64_EXTRA_BITS, // The base64 input terminates with non-zero |
845 | | // padding bits. |
846 | | OUTPUT_BUFFER_TOO_SMALL, // The provided buffer is too small. |
847 | | OTHER // Not related to validation/transcoding. |
848 | | }; |
849 | | |
850 | 0 | inline std::string_view error_to_string(error_code code) noexcept { |
851 | 0 | switch (code) { |
852 | 0 | case SUCCESS: |
853 | 0 | return "SUCCESS"; |
854 | 0 | case HEADER_BITS: |
855 | 0 | return "HEADER_BITS"; |
856 | 0 | case TOO_SHORT: |
857 | 0 | return "TOO_SHORT"; |
858 | 0 | case TOO_LONG: |
859 | 0 | return "TOO_LONG"; |
860 | 0 | case OVERLONG: |
861 | 0 | return "OVERLONG"; |
862 | 0 | case TOO_LARGE: |
863 | 0 | return "TOO_LARGE"; |
864 | 0 | case SURROGATE: |
865 | 0 | return "SURROGATE"; |
866 | 0 | case INVALID_BASE64_CHARACTER: |
867 | 0 | return "INVALID_BASE64_CHARACTER"; |
868 | 0 | case BASE64_INPUT_REMAINDER: |
869 | 0 | return "BASE64_INPUT_REMAINDER"; |
870 | 0 | case BASE64_EXTRA_BITS: |
871 | 0 | return "BASE64_EXTRA_BITS"; |
872 | 0 | case OUTPUT_BUFFER_TOO_SMALL: |
873 | 0 | return "OUTPUT_BUFFER_TOO_SMALL"; |
874 | 0 | default: |
875 | 0 | return "OTHER"; |
876 | 0 | } |
877 | 0 | } |
878 | | |
879 | | struct result { |
880 | | error_code error; |
881 | | size_t count; // In case of error, indicates the position of the error. In |
882 | | // case of success, indicates the number of code units |
883 | | // validated/written. |
884 | | |
885 | | simdutf_really_inline simdutf_constexpr23 result() noexcept |
886 | 0 | : error{error_code::SUCCESS}, count{0} {} |
887 | | |
888 | | simdutf_really_inline simdutf_constexpr23 result(error_code err, |
889 | | size_t pos) noexcept |
890 | 22.7k | : error{err}, count{pos} {} |
891 | | |
892 | 22.7k | simdutf_really_inline simdutf_constexpr23 bool is_ok() const noexcept { |
893 | 22.7k | return error == error_code::SUCCESS; |
894 | 22.7k | } |
895 | | |
896 | 0 | simdutf_really_inline simdutf_constexpr23 bool is_err() const noexcept { |
897 | 0 | return error != error_code::SUCCESS; |
898 | 0 | } |
899 | | }; |
900 | | |
901 | | struct full_result { |
902 | | error_code error; |
903 | | size_t input_count; |
904 | | size_t output_count; |
905 | | bool padding_error = false; // true if the error is due to padding, only |
906 | | // meaningful when error is not SUCCESS |
907 | | |
908 | | simdutf_really_inline simdutf_constexpr23 full_result() noexcept |
909 | 0 | : error{error_code::SUCCESS}, input_count{0}, output_count{0} {} |
910 | | |
911 | | simdutf_really_inline simdutf_constexpr23 full_result(error_code err, |
912 | | size_t pos_in, |
913 | | size_t pos_out) noexcept |
914 | 22.6k | : error{err}, input_count{pos_in}, output_count{pos_out} {} |
915 | | simdutf_really_inline simdutf_constexpr23 full_result( |
916 | | error_code err, size_t pos_in, size_t pos_out, bool padding_err) noexcept |
917 | 36 | : error{err}, input_count{pos_in}, output_count{pos_out}, |
918 | 36 | padding_error{padding_err} {} |
919 | | |
920 | 22.7k | simdutf_really_inline simdutf_constexpr23 operator result() const noexcept { |
921 | 22.7k | if (error == error_code::SUCCESS) { |
922 | 22.1k | return result{error, output_count}; |
923 | 22.1k | } else { |
924 | 533 | return result{error, input_count}; |
925 | 533 | } |
926 | 22.7k | } |
927 | | }; |
928 | | |
929 | | struct utf8_result { |
930 | | error_code error; |
931 | | size_t input_count; |
932 | | size_t continuation_count; |
933 | | size_t four_byte_count; |
934 | | |
935 | | simdutf_really_inline simdutf_constexpr23 utf8_result() noexcept |
936 | | : error{error_code::SUCCESS}, input_count{0}, continuation_count{0}, |
937 | 0 | four_byte_count{0} {} |
938 | | |
939 | | simdutf_really_inline simdutf_constexpr23 |
940 | | utf8_result(error_code err, size_t pos_in, size_t continuation_count_, |
941 | | size_t four_byte_count_) noexcept |
942 | | : error{err}, input_count{pos_in}, |
943 | | continuation_count{continuation_count_}, |
944 | 0 | four_byte_count{four_byte_count_} {} |
945 | | |
946 | | simdutf_really_inline simdutf_constexpr23 size_t |
947 | 0 | utf16_length() const noexcept { |
948 | 0 | return input_count - continuation_count + four_byte_count; |
949 | 0 | } |
950 | | |
951 | | // The number of code points in the valid prefix, which is also the number of |
952 | | // UTF-32 code units. |
953 | | simdutf_really_inline simdutf_constexpr23 size_t |
954 | 0 | utf32_length() const noexcept { |
955 | 0 | return input_count - continuation_count; |
956 | 0 | } |
957 | | }; |
958 | | |
959 | | // UTF-16 size of a possibly ill-formed UTF-8 string, plus the first few |
960 | | // ill-formed subsequences. Pass this to convert_utf8_to_utf16_with_replacement |
961 | | // on the same bytes. error_offset entries are byte indexes from the start of |
962 | | // that input. count is always the full number of char16_t. more_errors is |
963 | | // true when the input has ill-formed subsequences past the stored ones. |
964 | | struct utf8_to_utf16_result { |
965 | | static constexpr size_t max_errors = 16; |
966 | | error_code error; |
967 | | size_t count; |
968 | | size_t error_count; |
969 | | bool more_errors; |
970 | | size_t error_offset[max_errors]; |
971 | | |
972 | | simdutf_really_inline simdutf_constexpr23 utf8_to_utf16_result() noexcept |
973 | | : error{error_code::SUCCESS}, count{0}, error_count{0}, |
974 | 0 | more_errors{false}, error_offset{} {} |
975 | | }; |
976 | | |
977 | | } // namespace simdutf |
978 | | #endif |
979 | | /* end file include/simdutf/error.h */ |
980 | | |
981 | | SIMDUTF_PUSH_DISABLE_WARNINGS |
982 | | SIMDUTF_DISABLE_UNDESIRED_WARNINGS |
983 | | |
984 | | // Public API |
985 | | /* begin file include/simdutf/simdutf_version.h */ |
986 | | // /include/simdutf/simdutf_version.h automatically generated by release.py, |
987 | | // do not change by hand |
988 | | #ifndef SIMDUTF_SIMDUTF_VERSION_H |
989 | | #define SIMDUTF_SIMDUTF_VERSION_H |
990 | | |
991 | | /** The version of simdutf being used (major.minor.revision) */ |
992 | | #define SIMDUTF_VERSION "9.3.3" |
993 | | |
994 | | namespace simdutf { |
995 | | enum { |
996 | | /** |
997 | | * The major version (MAJOR.minor.revision) of simdutf being used. |
998 | | */ |
999 | | SIMDUTF_VERSION_MAJOR = 9, |
1000 | | /** |
1001 | | * The minor version (major.MINOR.revision) of simdutf being used. |
1002 | | */ |
1003 | | SIMDUTF_VERSION_MINOR = 3, |
1004 | | /** |
1005 | | * The revision (major.minor.REVISION) of simdutf being used. |
1006 | | */ |
1007 | | SIMDUTF_VERSION_REVISION = 3 |
1008 | | }; |
1009 | | } // namespace simdutf |
1010 | | |
1011 | | #endif // SIMDUTF_SIMDUTF_VERSION_H |
1012 | | /* end file include/simdutf/simdutf_version.h */ |
1013 | | /* begin file include/simdutf/implementation.h */ |
1014 | | #ifndef SIMDUTF_IMPLEMENTATION_H |
1015 | | #define SIMDUTF_IMPLEMENTATION_H |
1016 | | #if !defined(SIMDUTF_NO_THREADS) |
1017 | | #include <atomic> |
1018 | | #endif |
1019 | | #ifdef SIMDUTF_INTERNAL_TESTS |
1020 | | #include <vector> |
1021 | | #endif |
1022 | | /* begin file include/simdutf/internal/isadetection.h */ |
1023 | | /* From |
1024 | | https://github.com/endorno/pytorch/blob/master/torch/lib/TH/generic/simd/simd.h |
1025 | | Highly modified. |
1026 | | |
1027 | | Copyright (c) 2016- Facebook, Inc (Adam Paszke) |
1028 | | Copyright (c) 2014- Facebook, Inc (Soumith Chintala) |
1029 | | Copyright (c) 2011-2014 Idiap Research Institute (Ronan Collobert) |
1030 | | Copyright (c) 2012-2014 Deepmind Technologies (Koray Kavukcuoglu) |
1031 | | Copyright (c) 2011-2012 NEC Laboratories America (Koray Kavukcuoglu) |
1032 | | Copyright (c) 2011-2013 NYU (Clement Farabet) |
1033 | | Copyright (c) 2006-2010 NEC Laboratories America (Ronan Collobert, Leon Bottou, |
1034 | | Iain Melvin, Jason Weston) Copyright (c) 2006 Idiap Research Institute |
1035 | | (Samy Bengio) Copyright (c) 2001-2004 Idiap Research Institute (Ronan Collobert, |
1036 | | Samy Bengio, Johnny Mariethoz) |
1037 | | |
1038 | | All rights reserved. |
1039 | | |
1040 | | Redistribution and use in source and binary forms, with or without |
1041 | | modification, are permitted provided that the following conditions are met: |
1042 | | |
1043 | | 1. Redistributions of source code must retain the above copyright |
1044 | | notice, this list of conditions and the following disclaimer. |
1045 | | |
1046 | | 2. Redistributions in binary form must reproduce the above copyright |
1047 | | notice, this list of conditions and the following disclaimer in the |
1048 | | documentation and/or other materials provided with the distribution. |
1049 | | |
1050 | | 3. Neither the names of Facebook, Deepmind Technologies, NYU, NEC Laboratories |
1051 | | America and IDIAP Research Institute nor the names of its contributors may be |
1052 | | used to endorse or promote products derived from this software without |
1053 | | specific prior written permission. |
1054 | | |
1055 | | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
1056 | | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
1057 | | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
1058 | | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
1059 | | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
1060 | | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
1061 | | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
1062 | | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
1063 | | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
1064 | | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
1065 | | POSSIBILITY OF SUCH DAMAGE. |
1066 | | */ |
1067 | | |
1068 | | #ifndef SIMDutf_INTERNAL_ISADETECTION_H |
1069 | | #define SIMDutf_INTERNAL_ISADETECTION_H |
1070 | | |
1071 | | #include <cstdint> |
1072 | | #include <cstdlib> |
1073 | | #if defined(_MSC_VER) |
1074 | | #include <intrin.h> |
1075 | | #elif (defined(HAVE_GCC_GET_CPUID) && defined(USE_GCC_GET_CPUID)) || \ |
1076 | | defined(__FILC__) |
1077 | | #include <cpuid.h> |
1078 | | #endif |
1079 | | |
1080 | | #ifdef __FILC__ |
1081 | | #include <stdfil.h> |
1082 | | #endif |
1083 | | |
1084 | | |
1085 | | // RISC-V ISA detection utilities |
1086 | | #if SIMDUTF_IS_RISCV64 && defined(__linux__) |
1087 | | #include <unistd.h> // for syscall |
1088 | | // We define these ourselves, for backwards compatibility |
1089 | | struct simdutf_riscv_hwprobe { |
1090 | | int64_t key; |
1091 | | uint64_t value; |
1092 | | }; |
1093 | | #define simdutf_riscv_hwprobe(...) syscall(258, __VA_ARGS__) |
1094 | | #define SIMDUTF_RISCV_HWPROBE_KEY_IMA_EXT_0 4 |
1095 | | #define SIMDUTF_RISCV_HWPROBE_IMA_V (1 << 2) |
1096 | | #define SIMDUTF_RISCV_HWPROBE_EXT_ZVBB (1 << 17) |
1097 | | #endif // SIMDUTF_IS_RISCV64 && defined(__linux__) |
1098 | | |
1099 | | #if defined(__loongarch__) && defined(__linux__) |
1100 | | #include <sys/auxv.h> |
1101 | | // bits/hwcap.h |
1102 | | // #define HWCAP_LOONGARCH_LSX (1 << 4) |
1103 | | // #define HWCAP_LOONGARCH_LASX (1 << 5) |
1104 | | #endif |
1105 | | #if defined(__aarch64__) && defined(__linux__) |
1106 | | #include <sys/auxv.h> |
1107 | | #endif |
1108 | | #if (defined(__aarch64__) || defined(_M_ARM64) || defined(_M_ARM64EC)) && \ |
1109 | | defined(_WIN32) && !defined(_WINDOWS_) |
1110 | | // We avoid including <windows.h> (macro pollution); this matches the |
1111 | | // declaration in the Windows SDK (BOOL WINAPI |
1112 | | // IsProcessorFeaturePresent(DWORD)). |
1113 | | extern "C" __declspec(dllimport) int __stdcall IsProcessorFeaturePresent( |
1114 | | unsigned long ProcessorFeature); |
1115 | | #endif |
1116 | | |
1117 | | namespace simdutf { |
1118 | | namespace internal { |
1119 | | |
1120 | | enum instruction_set { |
1121 | | DEFAULT = 0x0, |
1122 | | NEON = 0x1, |
1123 | | AVX2 = 0x4, |
1124 | | SSE42 = 0x8, |
1125 | | PCLMULQDQ = 0x10, |
1126 | | BMI1 = 0x20, |
1127 | | BMI2 = 0x40, |
1128 | | ALTIVEC = 0x80, |
1129 | | AVX512F = 0x100, |
1130 | | AVX512DQ = 0x200, |
1131 | | AVX512IFMA = 0x400, |
1132 | | AVX512PF = 0x800, |
1133 | | AVX512ER = 0x1000, |
1134 | | AVX512CD = 0x2000, |
1135 | | AVX512BW = 0x4000, |
1136 | | AVX512VL = 0x8000, |
1137 | | AVX512VBMI2 = 0x10000, |
1138 | | AVX512VPOPCNTDQ = 0x2000, |
1139 | | RVV = 0x4000, |
1140 | | ZVBB = 0x8000, |
1141 | | LSX = 0x40000, |
1142 | | LASX = 0x80000, |
1143 | | SVE = 0x100000, |
1144 | | SVE2 = 0x200000, |
1145 | | }; |
1146 | | |
1147 | | #if defined(__PPC64__) |
1148 | | |
1149 | | static inline uint32_t detect_supported_architectures() { |
1150 | | return instruction_set::ALTIVEC; |
1151 | | } |
1152 | | |
1153 | | #elif SIMDUTF_IS_RISCV64 |
1154 | | |
1155 | | static inline uint32_t detect_supported_architectures() { |
1156 | | uint32_t host_isa = instruction_set::DEFAULT; |
1157 | | #if SIMDUTF_IS_RVV |
1158 | | host_isa |= instruction_set::RVV; |
1159 | | #endif |
1160 | | #if SIMDUTF_IS_ZVBB |
1161 | | host_isa |= instruction_set::ZVBB; |
1162 | | #endif |
1163 | | #if defined(__linux__) |
1164 | | simdutf_riscv_hwprobe probes[] = {{SIMDUTF_RISCV_HWPROBE_KEY_IMA_EXT_0, 0}}; |
1165 | | long ret = simdutf_riscv_hwprobe(&probes, sizeof probes / sizeof *probes, 0, |
1166 | | nullptr, 0); |
1167 | | if (ret == 0) { |
1168 | | uint64_t extensions = probes[0].value; |
1169 | | if (extensions & SIMDUTF_RISCV_HWPROBE_IMA_V) |
1170 | | host_isa |= instruction_set::RVV; |
1171 | | if (extensions & SIMDUTF_RISCV_HWPROBE_EXT_ZVBB) |
1172 | | host_isa |= instruction_set::ZVBB; |
1173 | | } |
1174 | | #endif |
1175 | | #if defined(RUN_IN_SPIKE_SIMULATOR) |
1176 | | // Proxy Kernel does not implement yet hwprobe syscall |
1177 | | host_isa |= instruction_set::RVV; |
1178 | | #endif |
1179 | | return host_isa; |
1180 | | } |
1181 | | |
1182 | | #elif defined(__aarch64__) || defined(_M_ARM64) || defined(_M_ARM64EC) |
1183 | | |
1184 | | #if defined(__linux__) |
1185 | | // The kernel advertises SVE in AT_HWCAP and SVE2 in AT_HWCAP2. Older |
1186 | | // headers may not define these constants, so we provide the kernel's values |
1187 | | // (we deliberately do not include <asm/hwcap.h>, which is not available on |
1188 | | // all toolchains, e.g., musl without linux-headers). |
1189 | | #ifndef AT_HWCAP2 |
1190 | | #define AT_HWCAP2 26 |
1191 | | #endif |
1192 | | #ifndef HWCAP_SVE |
1193 | | #define HWCAP_SVE (1 << 22) |
1194 | | #endif |
1195 | | #ifndef HWCAP2_SVE2 |
1196 | | #define HWCAP2_SVE2 (1 << 1) |
1197 | | #endif |
1198 | | #endif // __linux__ |
1199 | | |
1200 | | #if defined(_WIN32) |
1201 | | // Only recent Windows SDKs define these processor features. |
1202 | | #ifndef PF_ARM_SVE_INSTRUCTIONS_AVAILABLE |
1203 | | #define PF_ARM_SVE_INSTRUCTIONS_AVAILABLE 46 |
1204 | | #endif |
1205 | | #ifndef PF_ARM_SVE2_INSTRUCTIONS_AVAILABLE |
1206 | | #define PF_ARM_SVE2_INSTRUCTIONS_AVAILABLE 47 |
1207 | | #endif |
1208 | | #endif // _WIN32 |
1209 | | |
1210 | | static inline uint32_t detect_supported_architectures() { |
1211 | | // NEON is mandatory on AArch64. |
1212 | | uint32_t host_isa = instruction_set::NEON; |
1213 | | #if defined(__linux__) |
1214 | | unsigned long hwcap = getauxval(AT_HWCAP); |
1215 | | unsigned long hwcap2 = getauxval(AT_HWCAP2); |
1216 | | if (hwcap & HWCAP_SVE) { |
1217 | | host_isa |= instruction_set::SVE; |
1218 | | // We only claim SVE2 when SVE is also present. Before Linux 6.14, the |
1219 | | // kernel set HWCAP2_SVE2 on processors implementing SME(2) but not SVE, |
1220 | | // because SVE2 instructions are available in streaming mode. Our SVE2 |
1221 | | // code runs in non-streaming mode and needs actual SVE. |
1222 | | if (hwcap2 & HWCAP2_SVE2) { |
1223 | | host_isa |= instruction_set::SVE2; |
1224 | | } |
1225 | | } |
1226 | | #elif defined(_WIN32) |
1227 | | if (IsProcessorFeaturePresent(PF_ARM_SVE_INSTRUCTIONS_AVAILABLE)) { |
1228 | | host_isa |= instruction_set::SVE; |
1229 | | // As on Linux, require SVE before claiming SVE2. |
1230 | | if (IsProcessorFeaturePresent(PF_ARM_SVE2_INSTRUCTIONS_AVAILABLE)) { |
1231 | | host_isa |= instruction_set::SVE2; |
1232 | | } |
1233 | | } |
1234 | | #endif |
1235 | | // On other systems (e.g., macOS, where Apple Silicon has no SVE), we only |
1236 | | // report NEON. |
1237 | | return host_isa; |
1238 | | } |
1239 | | |
1240 | | #elif defined(__x86_64__) || defined(_M_AMD64) // x64 |
1241 | | |
1242 | | namespace { |
1243 | | namespace cpuid_bit { |
1244 | | // Can be found on Intel ISA Reference for CPUID |
1245 | | |
1246 | | // EAX = 0x01 |
1247 | | constexpr uint32_t pclmulqdq = uint32_t(1) |
1248 | | << 1; ///< @private bit 1 of ECX for EAX=0x1 |
1249 | | constexpr uint32_t sse42 = uint32_t(1) |
1250 | | << 20; ///< @private bit 20 of ECX for EAX=0x1 |
1251 | | constexpr uint32_t osxsave = |
1252 | | (uint32_t(1) << 26) | |
1253 | | (uint32_t(1) << 27); ///< @private bits 26+27 of ECX for EAX=0x1 |
1254 | | |
1255 | | // EAX = 0x7f (Structured Extended Feature Flags), ECX = 0x00 (Sub-leaf) |
1256 | | // See: "Table 3-8. Information Returned by CPUID Instruction" |
1257 | | namespace ebx { |
1258 | | constexpr uint32_t bmi1 = uint32_t(1) << 3; |
1259 | | constexpr uint32_t avx2 = uint32_t(1) << 5; |
1260 | | constexpr uint32_t bmi2 = uint32_t(1) << 8; |
1261 | | constexpr uint32_t avx512f = uint32_t(1) << 16; |
1262 | | constexpr uint32_t avx512dq = uint32_t(1) << 17; |
1263 | | constexpr uint32_t avx512ifma = uint32_t(1) << 21; |
1264 | | constexpr uint32_t avx512cd = uint32_t(1) << 28; |
1265 | | constexpr uint32_t avx512bw = uint32_t(1) << 30; |
1266 | | constexpr uint32_t avx512vl = uint32_t(1) << 31; |
1267 | | } // namespace ebx |
1268 | | |
1269 | | namespace ecx { |
1270 | | constexpr uint32_t avx512vbmi = uint32_t(1) << 1; |
1271 | | constexpr uint32_t avx512vbmi2 = uint32_t(1) << 6; |
1272 | | constexpr uint32_t avx512vnni = uint32_t(1) << 11; |
1273 | | constexpr uint32_t avx512bitalg = uint32_t(1) << 12; |
1274 | | constexpr uint32_t avx512vpopcnt = uint32_t(1) << 14; |
1275 | | } // namespace ecx |
1276 | | namespace edx { |
1277 | | constexpr uint32_t avx512vp2intersect = uint32_t(1) << 8; |
1278 | | } |
1279 | | namespace xcr0_bit { |
1280 | | constexpr uint64_t avx256_saved = uint64_t(1) << 2; ///< @private bit 2 = AVX |
1281 | | constexpr uint64_t avx512_saved = |
1282 | | uint64_t(7) << 5; ///< @private bits 5,6,7 = opmask, ZMM_hi256, hi16_ZMM |
1283 | | } // namespace xcr0_bit |
1284 | | } // namespace cpuid_bit |
1285 | | } // namespace |
1286 | | |
1287 | | static inline void cpuid(uint32_t *eax, uint32_t *ebx, uint32_t *ecx, |
1288 | 2 | uint32_t *edx) { |
1289 | | #if defined(_MSC_VER) |
1290 | | int cpu_info[4]; |
1291 | | __cpuidex(cpu_info, *eax, *ecx); |
1292 | | *eax = cpu_info[0]; |
1293 | | *ebx = cpu_info[1]; |
1294 | | *ecx = cpu_info[2]; |
1295 | | *edx = cpu_info[3]; |
1296 | | #elif (defined(HAVE_GCC_GET_CPUID) && defined(USE_GCC_GET_CPUID)) || \ |
1297 | | defined(__FILC__) |
1298 | | uint32_t level = *eax; |
1299 | | __get_cpuid(level, eax, ebx, ecx, edx); |
1300 | | #else |
1301 | 2 | uint32_t a = *eax, b, c = *ecx, d; |
1302 | 2 | asm volatile("cpuid\n\t" : "+a"(a), "=b"(b), "+c"(c), "=d"(d)); |
1303 | 2 | *eax = a; |
1304 | 2 | *ebx = b; |
1305 | 2 | *ecx = c; |
1306 | 2 | *edx = d; |
1307 | 2 | #endif |
1308 | 2 | } Unexecuted instantiation: parser.cpp:simdutf::internal::cpuid(unsigned int*, unsigned int*, unsigned int*, unsigned int*) Unexecuted instantiation: base64.cpp:simdutf::internal::cpuid(unsigned int*, unsigned int*, unsigned int*, unsigned int*) simdutf.cpp:simdutf::internal::cpuid(unsigned int*, unsigned int*, unsigned int*, unsigned int*) Line | Count | Source | 1288 | 2 | uint32_t *edx) { | 1289 | | #if defined(_MSC_VER) | 1290 | | int cpu_info[4]; | 1291 | | __cpuidex(cpu_info, *eax, *ecx); | 1292 | | *eax = cpu_info[0]; | 1293 | | *ebx = cpu_info[1]; | 1294 | | *ecx = cpu_info[2]; | 1295 | | *edx = cpu_info[3]; | 1296 | | #elif (defined(HAVE_GCC_GET_CPUID) && defined(USE_GCC_GET_CPUID)) || \ | 1297 | | defined(__FILC__) | 1298 | | uint32_t level = *eax; | 1299 | | __get_cpuid(level, eax, ebx, ecx, edx); | 1300 | | #else | 1301 | 2 | uint32_t a = *eax, b, c = *ecx, d; | 1302 | 2 | asm volatile("cpuid\n\t" : "+a"(a), "=b"(b), "+c"(c), "=d"(d)); | 1303 | 2 | *eax = a; | 1304 | 2 | *ebx = b; | 1305 | 2 | *ecx = c; | 1306 | 2 | *edx = d; | 1307 | 2 | #endif | 1308 | 2 | } |
|
1309 | | |
1310 | 1 | static inline uint64_t xgetbv() { |
1311 | | #if defined(_MSC_VER) |
1312 | | return _xgetbv(0); |
1313 | | #elif defined(__FILC__) |
1314 | | return zxgetbv(); |
1315 | | #else |
1316 | 1 | uint32_t xcr0_lo, xcr0_hi; |
1317 | 1 | asm volatile("xgetbv\n\t" : "=a"(xcr0_lo), "=d"(xcr0_hi) : "c"(0)); |
1318 | 1 | return xcr0_lo | ((uint64_t)xcr0_hi << 32); |
1319 | 1 | #endif |
1320 | 1 | } Unexecuted instantiation: parser.cpp:simdutf::internal::xgetbv() Unexecuted instantiation: base64.cpp:simdutf::internal::xgetbv() simdutf.cpp:simdutf::internal::xgetbv() Line | Count | Source | 1310 | 1 | static inline uint64_t xgetbv() { | 1311 | | #if defined(_MSC_VER) | 1312 | | return _xgetbv(0); | 1313 | | #elif defined(__FILC__) | 1314 | | return zxgetbv(); | 1315 | | #else | 1316 | 1 | uint32_t xcr0_lo, xcr0_hi; | 1317 | 1 | asm volatile("xgetbv\n\t" : "=a"(xcr0_lo), "=d"(xcr0_hi) : "c"(0)); | 1318 | 1 | return xcr0_lo | ((uint64_t)xcr0_hi << 32); | 1319 | 1 | #endif | 1320 | 1 | } |
|
1321 | | |
1322 | 1 | static inline uint32_t detect_supported_architectures() { |
1323 | 1 | uint32_t eax; |
1324 | 1 | uint32_t ebx = 0; |
1325 | 1 | uint32_t ecx = 0; |
1326 | 1 | uint32_t edx = 0; |
1327 | 1 | uint32_t host_isa = 0x0; |
1328 | | |
1329 | | // EBX for EAX=0x1 |
1330 | 1 | eax = 0x1; |
1331 | 1 | cpuid(&eax, &ebx, &ecx, &edx); |
1332 | | |
1333 | 1 | if (ecx & cpuid_bit::sse42) { |
1334 | 1 | host_isa |= instruction_set::SSE42; |
1335 | 1 | } |
1336 | | |
1337 | 1 | if (ecx & cpuid_bit::pclmulqdq) { |
1338 | 1 | host_isa |= instruction_set::PCLMULQDQ; |
1339 | 1 | } |
1340 | | |
1341 | 1 | if ((ecx & cpuid_bit::osxsave) != cpuid_bit::osxsave) { |
1342 | 0 | return host_isa; |
1343 | 0 | } |
1344 | | |
1345 | | // xgetbv for checking if the OS saves registers |
1346 | 1 | uint64_t xcr0 = xgetbv(); |
1347 | | |
1348 | 1 | if ((xcr0 & cpuid_bit::xcr0_bit::avx256_saved) == 0) { |
1349 | 0 | return host_isa; |
1350 | 0 | } |
1351 | | // ECX for EAX=0x7 |
1352 | 1 | eax = 0x7; |
1353 | 1 | ecx = 0x0; // Sub-leaf = 0 |
1354 | 1 | cpuid(&eax, &ebx, &ecx, &edx); |
1355 | 1 | if (ebx & cpuid_bit::ebx::avx2) { |
1356 | 1 | host_isa |= instruction_set::AVX2; |
1357 | 1 | } |
1358 | 1 | if (ebx & cpuid_bit::ebx::bmi1) { |
1359 | 1 | host_isa |= instruction_set::BMI1; |
1360 | 1 | } |
1361 | 1 | if (ebx & cpuid_bit::ebx::bmi2) { |
1362 | 1 | host_isa |= instruction_set::BMI2; |
1363 | 1 | } |
1364 | 1 | if (!((xcr0 & cpuid_bit::xcr0_bit::avx512_saved) == |
1365 | 1 | cpuid_bit::xcr0_bit::avx512_saved)) { |
1366 | 1 | return host_isa; |
1367 | 1 | } |
1368 | 0 | if (ebx & cpuid_bit::ebx::avx512f) { |
1369 | 0 | host_isa |= instruction_set::AVX512F; |
1370 | 0 | } |
1371 | 0 | if (ebx & cpuid_bit::ebx::avx512bw) { |
1372 | 0 | host_isa |= instruction_set::AVX512BW; |
1373 | 0 | } |
1374 | 0 | if (ebx & cpuid_bit::ebx::avx512cd) { |
1375 | 0 | host_isa |= instruction_set::AVX512CD; |
1376 | 0 | } |
1377 | 0 | if (ebx & cpuid_bit::ebx::avx512dq) { |
1378 | 0 | host_isa |= instruction_set::AVX512DQ; |
1379 | 0 | } |
1380 | 0 | if (ebx & cpuid_bit::ebx::avx512vl) { |
1381 | 0 | host_isa |= instruction_set::AVX512VL; |
1382 | 0 | } |
1383 | 0 | if (ecx & cpuid_bit::ecx::avx512vbmi2) { |
1384 | 0 | host_isa |= instruction_set::AVX512VBMI2; |
1385 | 0 | } |
1386 | 0 | if (ecx & cpuid_bit::ecx::avx512vpopcnt) { |
1387 | 0 | host_isa |= instruction_set::AVX512VPOPCNTDQ; |
1388 | 0 | } |
1389 | 0 | return host_isa; |
1390 | 1 | } Unexecuted instantiation: parser.cpp:simdutf::internal::detect_supported_architectures() Unexecuted instantiation: base64.cpp:simdutf::internal::detect_supported_architectures() simdutf.cpp:simdutf::internal::detect_supported_architectures() Line | Count | Source | 1322 | 1 | static inline uint32_t detect_supported_architectures() { | 1323 | 1 | uint32_t eax; | 1324 | 1 | uint32_t ebx = 0; | 1325 | 1 | uint32_t ecx = 0; | 1326 | 1 | uint32_t edx = 0; | 1327 | 1 | uint32_t host_isa = 0x0; | 1328 | | | 1329 | | // EBX for EAX=0x1 | 1330 | 1 | eax = 0x1; | 1331 | 1 | cpuid(&eax, &ebx, &ecx, &edx); | 1332 | | | 1333 | 1 | if (ecx & cpuid_bit::sse42) { | 1334 | 1 | host_isa |= instruction_set::SSE42; | 1335 | 1 | } | 1336 | | | 1337 | 1 | if (ecx & cpuid_bit::pclmulqdq) { | 1338 | 1 | host_isa |= instruction_set::PCLMULQDQ; | 1339 | 1 | } | 1340 | | | 1341 | 1 | if ((ecx & cpuid_bit::osxsave) != cpuid_bit::osxsave) { | 1342 | 0 | return host_isa; | 1343 | 0 | } | 1344 | | | 1345 | | // xgetbv for checking if the OS saves registers | 1346 | 1 | uint64_t xcr0 = xgetbv(); | 1347 | | | 1348 | 1 | if ((xcr0 & cpuid_bit::xcr0_bit::avx256_saved) == 0) { | 1349 | 0 | return host_isa; | 1350 | 0 | } | 1351 | | // ECX for EAX=0x7 | 1352 | 1 | eax = 0x7; | 1353 | 1 | ecx = 0x0; // Sub-leaf = 0 | 1354 | 1 | cpuid(&eax, &ebx, &ecx, &edx); | 1355 | 1 | if (ebx & cpuid_bit::ebx::avx2) { | 1356 | 1 | host_isa |= instruction_set::AVX2; | 1357 | 1 | } | 1358 | 1 | if (ebx & cpuid_bit::ebx::bmi1) { | 1359 | 1 | host_isa |= instruction_set::BMI1; | 1360 | 1 | } | 1361 | 1 | if (ebx & cpuid_bit::ebx::bmi2) { | 1362 | 1 | host_isa |= instruction_set::BMI2; | 1363 | 1 | } | 1364 | 1 | if (!((xcr0 & cpuid_bit::xcr0_bit::avx512_saved) == | 1365 | 1 | cpuid_bit::xcr0_bit::avx512_saved)) { | 1366 | 1 | return host_isa; | 1367 | 1 | } | 1368 | 0 | if (ebx & cpuid_bit::ebx::avx512f) { | 1369 | 0 | host_isa |= instruction_set::AVX512F; | 1370 | 0 | } | 1371 | 0 | if (ebx & cpuid_bit::ebx::avx512bw) { | 1372 | 0 | host_isa |= instruction_set::AVX512BW; | 1373 | 0 | } | 1374 | 0 | if (ebx & cpuid_bit::ebx::avx512cd) { | 1375 | 0 | host_isa |= instruction_set::AVX512CD; | 1376 | 0 | } | 1377 | 0 | if (ebx & cpuid_bit::ebx::avx512dq) { | 1378 | 0 | host_isa |= instruction_set::AVX512DQ; | 1379 | 0 | } | 1380 | 0 | if (ebx & cpuid_bit::ebx::avx512vl) { | 1381 | 0 | host_isa |= instruction_set::AVX512VL; | 1382 | 0 | } | 1383 | 0 | if (ecx & cpuid_bit::ecx::avx512vbmi2) { | 1384 | 0 | host_isa |= instruction_set::AVX512VBMI2; | 1385 | 0 | } | 1386 | 0 | if (ecx & cpuid_bit::ecx::avx512vpopcnt) { | 1387 | 0 | host_isa |= instruction_set::AVX512VPOPCNTDQ; | 1388 | 0 | } | 1389 | 0 | return host_isa; | 1390 | 1 | } |
|
1391 | | #elif defined(__loongarch__) |
1392 | | |
1393 | | static inline uint32_t detect_supported_architectures() { |
1394 | | uint32_t host_isa = instruction_set::DEFAULT; |
1395 | | #if defined(__linux__) |
1396 | | uint64_t hwcap = 0; |
1397 | | hwcap = getauxval(AT_HWCAP); |
1398 | | if (hwcap & HWCAP_LOONGARCH_LSX) { |
1399 | | host_isa |= instruction_set::LSX; |
1400 | | } |
1401 | | if (hwcap & HWCAP_LOONGARCH_LASX) { |
1402 | | host_isa |= instruction_set::LASX; |
1403 | | } |
1404 | | #endif |
1405 | | return host_isa; |
1406 | | } |
1407 | | #else // fallback |
1408 | | |
1409 | | // includes 32-bit ARM. |
1410 | | static inline uint32_t detect_supported_architectures() { |
1411 | | return instruction_set::DEFAULT; |
1412 | | } |
1413 | | |
1414 | | #endif // end SIMD extension detection code |
1415 | | |
1416 | | } // namespace internal |
1417 | | } // namespace simdutf |
1418 | | |
1419 | | #endif // SIMDutf_INTERNAL_ISADETECTION_H |
1420 | | /* end file include/simdutf/internal/isadetection.h */ |
1421 | | |
1422 | | #include <string_view> |
1423 | | #if SIMDUTF_SPAN |
1424 | | #include <concepts> |
1425 | | #include <type_traits> |
1426 | | #include <span> |
1427 | | #include <tuple> |
1428 | | #include <utility> // for std::unreachable |
1429 | | #endif |
1430 | | // The following defines are conditionally enabled/disabled during amalgamation. |
1431 | | // By default all features are enabled, regular code shouldn't check them. Only |
1432 | | // when user code really relies of a selected subset, it's good to verify these |
1433 | | // flags, like: |
1434 | | // |
1435 | | // #if !SIMDUTF_FEATURE_UTF16 |
1436 | | // # error("Please amalgamate simdutf with UTF-16 support") |
1437 | | // #endif |
1438 | | // |
1439 | | #ifndef SIMDUTF_FEATURE_DETECT_ENCODING |
1440 | | #define SIMDUTF_FEATURE_DETECT_ENCODING 1 |
1441 | | #endif |
1442 | | #ifndef SIMDUTF_FEATURE_ASCII |
1443 | | #define SIMDUTF_FEATURE_ASCII 1 |
1444 | | #endif |
1445 | | #ifndef SIMDUTF_FEATURE_LATIN1 |
1446 | | #define SIMDUTF_FEATURE_LATIN1 1 |
1447 | | #endif |
1448 | | #ifndef SIMDUTF_FEATURE_UTF8 |
1449 | | #define SIMDUTF_FEATURE_UTF8 1 |
1450 | | #endif |
1451 | | #ifndef SIMDUTF_FEATURE_UTF16 |
1452 | | #define SIMDUTF_FEATURE_UTF16 1 |
1453 | | #endif |
1454 | | #ifndef SIMDUTF_FEATURE_UTF32 |
1455 | | #define SIMDUTF_FEATURE_UTF32 1 |
1456 | | #endif |
1457 | | #ifndef SIMDUTF_FEATURE_BASE64 |
1458 | | #define SIMDUTF_FEATURE_BASE64 1 |
1459 | | #endif |
1460 | | |
1461 | | /// helpers placed in namespace detail are not a part of the public API |
1462 | | namespace simdutf { |
1463 | | namespace detail { |
1464 | | namespace { |
1465 | | // this is to avoid including <algorithm> just for min |
1466 | 0 | constexpr std::size_t min(std::size_t a, std::size_t b) { |
1467 | 0 | return a < b ? a : b; |
1468 | 0 | } Unexecuted instantiation: parser.cpp:simdutf::detail::(anonymous namespace)::min(unsigned long, unsigned long) Unexecuted instantiation: base64.cpp:simdutf::detail::(anonymous namespace)::min(unsigned long, unsigned long) Unexecuted instantiation: simdutf.cpp:simdutf::detail::(anonymous namespace)::min(unsigned long, unsigned long) |
1469 | | template <typename T, typename U> |
1470 | | constexpr std::size_t min(const T &a, const U &b) = delete; |
1471 | | } // namespace |
1472 | | } // namespace detail |
1473 | | } // namespace simdutf |
1474 | | |
1475 | | #if SIMDUTF_CPLUSPLUS23 |
1476 | | /* begin file include/simdutf/constexpr_ptr.h */ |
1477 | | #ifndef SIMDUTF_CONSTEXPR_PTR_H |
1478 | | #define SIMDUTF_CONSTEXPR_PTR_H |
1479 | | |
1480 | | #include <cstddef> |
1481 | | |
1482 | | namespace simdutf { |
1483 | | namespace detail { |
1484 | | /** |
1485 | | * The constexpr_ptr class is a workaround for reinterpret_cast not being |
1486 | | * allowed during constant evaluation. |
1487 | | */ |
1488 | | template <typename to, typename from> |
1489 | | requires(sizeof(to) == sizeof(from)) |
1490 | | struct constexpr_ptr { |
1491 | | const from *p; |
1492 | | |
1493 | | constexpr explicit constexpr_ptr(const from *ptr) noexcept : p(ptr) {} |
1494 | | |
1495 | | constexpr to operator*() const noexcept { return static_cast<to>(*p); } |
1496 | | |
1497 | | constexpr constexpr_ptr &operator++() noexcept { |
1498 | | ++p; |
1499 | | return *this; |
1500 | | } |
1501 | | |
1502 | | constexpr constexpr_ptr operator++(int) noexcept { |
1503 | | auto old = *this; |
1504 | | ++p; |
1505 | | return old; |
1506 | | } |
1507 | | |
1508 | | constexpr constexpr_ptr &operator--() noexcept { |
1509 | | --p; |
1510 | | return *this; |
1511 | | } |
1512 | | |
1513 | | constexpr constexpr_ptr operator--(int) noexcept { |
1514 | | auto old = *this; |
1515 | | --p; |
1516 | | return old; |
1517 | | } |
1518 | | |
1519 | | constexpr constexpr_ptr &operator+=(std::ptrdiff_t n) noexcept { |
1520 | | p += n; |
1521 | | return *this; |
1522 | | } |
1523 | | |
1524 | | constexpr constexpr_ptr &operator-=(std::ptrdiff_t n) noexcept { |
1525 | | p -= n; |
1526 | | return *this; |
1527 | | } |
1528 | | |
1529 | | constexpr constexpr_ptr operator+(std::ptrdiff_t n) const noexcept { |
1530 | | return constexpr_ptr{p + n}; |
1531 | | } |
1532 | | |
1533 | | constexpr constexpr_ptr operator-(std::ptrdiff_t n) const noexcept { |
1534 | | return constexpr_ptr{p - n}; |
1535 | | } |
1536 | | |
1537 | | constexpr std::ptrdiff_t operator-(const constexpr_ptr &o) const noexcept { |
1538 | | return p - o.p; |
1539 | | } |
1540 | | |
1541 | | constexpr to operator[](std::ptrdiff_t n) const noexcept { |
1542 | | return static_cast<to>(*(p + n)); |
1543 | | } |
1544 | | |
1545 | | // to prevent compilation errors for memcpy, even if it is never |
1546 | | // called during constant evaluation |
1547 | | constexpr operator const void *() const noexcept { return p; } |
1548 | | }; |
1549 | | |
1550 | | template <typename to, typename from> |
1551 | | constexpr constexpr_ptr<to, from> constexpr_cast_ptr(from *p) noexcept { |
1552 | | return constexpr_ptr<to, from>{p}; |
1553 | | } |
1554 | | |
1555 | | /** |
1556 | | * helper type for constexpr_writeptr, so it is possible to |
1557 | | * do "*ptr = val;" |
1558 | | */ |
1559 | | template <typename SrcType, typename TargetType> |
1560 | | struct constexpr_write_ptr_proxy { |
1561 | | |
1562 | | constexpr explicit constexpr_write_ptr_proxy(TargetType *raw) : p(raw) {} |
1563 | | |
1564 | | constexpr constexpr_write_ptr_proxy &operator=(SrcType v) { |
1565 | | *p = static_cast<TargetType>(v); |
1566 | | return *this; |
1567 | | } |
1568 | | |
1569 | | TargetType *p; |
1570 | | }; |
1571 | | |
1572 | | /** |
1573 | | * helper for working around reinterpret_cast not being allowed during constexpr |
1574 | | * evaluation. will try to act as a SrcType* but actually write to the pointer |
1575 | | * given in the constructor, which is of another type TargetType |
1576 | | */ |
1577 | | template <typename SrcType, typename TargetType> struct constexpr_write_ptr { |
1578 | | constexpr explicit constexpr_write_ptr(TargetType *raw) : p(raw) {} |
1579 | | |
1580 | | constexpr constexpr_write_ptr_proxy<SrcType, TargetType> operator*() const { |
1581 | | return constexpr_write_ptr_proxy<SrcType, TargetType>{p}; |
1582 | | } |
1583 | | |
1584 | | constexpr constexpr_write_ptr_proxy<SrcType, TargetType> |
1585 | | operator[](std::ptrdiff_t n) const { |
1586 | | return constexpr_write_ptr_proxy<SrcType, TargetType>{p + n}; |
1587 | | } |
1588 | | |
1589 | | constexpr constexpr_write_ptr &operator++() { |
1590 | | ++p; |
1591 | | return *this; |
1592 | | } |
1593 | | |
1594 | | constexpr constexpr_write_ptr operator++(int) { |
1595 | | constexpr_write_ptr old = *this; |
1596 | | ++p; |
1597 | | return old; |
1598 | | } |
1599 | | |
1600 | | constexpr std::ptrdiff_t operator-(const constexpr_write_ptr &other) const { |
1601 | | return p - other.p; |
1602 | | } |
1603 | | |
1604 | | TargetType *p; |
1605 | | }; |
1606 | | |
1607 | | template <typename SrcType, typename TargetType> |
1608 | | constexpr auto constexpr_cast_writeptr(TargetType *raw) { |
1609 | | return constexpr_write_ptr<SrcType, TargetType>{raw}; |
1610 | | } |
1611 | | |
1612 | | } // namespace detail |
1613 | | } // namespace simdutf |
1614 | | #endif |
1615 | | /* end file include/simdutf/constexpr_ptr.h */ |
1616 | | #endif |
1617 | | |
1618 | | #if SIMDUTF_SPAN |
1619 | | /// helpers placed in namespace detail are not a part of the public API |
1620 | | namespace simdutf { |
1621 | | namespace detail { |
1622 | | /** |
1623 | | * matches a byte, in the many ways C++ allows. note that these |
1624 | | * are all distinct types. |
1625 | | */ |
1626 | | template <typename T> |
1627 | | concept byte_like = std::is_same_v<T, std::byte> || // |
1628 | | std::is_same_v<T, char> || // |
1629 | | std::is_same_v<T, signed char> || // |
1630 | | std::is_same_v<T, unsigned char> || // |
1631 | | std::is_same_v<T, char8_t>; |
1632 | | |
1633 | | template <typename T> |
1634 | | concept is_byte_like = byte_like<std::remove_cvref_t<T>>; |
1635 | | |
1636 | | template <typename T> |
1637 | | concept is_pointer = std::is_pointer_v<T>; |
1638 | | |
1639 | | /** |
1640 | | * matches anything that behaves like std::span and points to character-like |
1641 | | * data such as: std::byte, char, unsigned char, signed char, std::int8_t, |
1642 | | * std::uint8_t |
1643 | | */ |
1644 | | template <typename T> |
1645 | | concept input_span_of_byte_like = requires(const T &t) { |
1646 | | { t.size() } noexcept -> std::convertible_to<std::size_t>; |
1647 | | { t.data() } noexcept -> is_pointer; |
1648 | | { *t.data() } noexcept -> is_byte_like; |
1649 | | }; |
1650 | | |
1651 | | template <typename T> |
1652 | | concept is_mutable = !std::is_const_v<std::remove_reference_t<T>>; |
1653 | | |
1654 | | /** |
1655 | | * like span_of_byte_like, but for an output span (intended to be written to) |
1656 | | */ |
1657 | | template <typename T> |
1658 | | concept output_span_of_byte_like = requires(T &t) { |
1659 | | { t.size() } noexcept -> std::convertible_to<std::size_t>; |
1660 | | { t.data() } noexcept -> is_pointer; |
1661 | | { *t.data() } noexcept -> is_byte_like; |
1662 | | { *t.data() } noexcept -> is_mutable; |
1663 | | }; |
1664 | | |
1665 | | /** |
1666 | | * a pointer like object, when indexed, results in a byte like result. |
1667 | | * valid examples: char*, const char*, std::array<char,10> |
1668 | | * invalid examples: int*, std::array<int,10> |
1669 | | */ |
1670 | | template <class InputPtr> |
1671 | | concept indexes_into_byte_like = requires(InputPtr p) { |
1672 | | { std::decay_t<decltype(p[0])>{} } -> simdutf::detail::byte_like; |
1673 | | }; |
1674 | | template <class InputPtr> |
1675 | | concept indexes_into_utf16 = requires(InputPtr p) { |
1676 | | { std::decay_t<decltype(p[0])>{} } -> std::same_as<char16_t>; |
1677 | | }; |
1678 | | template <class InputPtr> |
1679 | | concept indexes_into_utf32 = requires(InputPtr p) { |
1680 | | { std::decay_t<decltype(p[0])>{} } -> std::same_as<char32_t>; |
1681 | | }; |
1682 | | |
1683 | | template <class InputPtr> |
1684 | | concept index_assignable_from_char = requires(InputPtr p, char s) { |
1685 | | { p[0] = s }; |
1686 | | }; |
1687 | | |
1688 | | /** |
1689 | | * a pointer like object that results in a uint32_t when indexed. |
1690 | | * valid examples: uint32_t* |
1691 | | */ |
1692 | | template <class InputPtr> |
1693 | | concept indexes_into_uint32 = requires(InputPtr p) { |
1694 | | { std::decay_t<decltype(p[0])>{} } -> std::same_as<std::uint32_t>; |
1695 | | }; |
1696 | | } // namespace detail |
1697 | | } // namespace simdutf |
1698 | | #endif // SIMDUTF_SPAN |
1699 | | |
1700 | | // these includes are needed for constexpr support. they are |
1701 | | // not part of the public api. |
1702 | | /* begin file include/simdutf/scalar/swap_bytes.h */ |
1703 | | #ifndef SIMDUTF_SWAP_BYTES_H |
1704 | | #define SIMDUTF_SWAP_BYTES_H |
1705 | | |
1706 | | namespace simdutf { |
1707 | | namespace scalar { |
1708 | | |
1709 | | constexpr inline simdutf_warn_unused uint16_t |
1710 | 0 | u16_swap_bytes(const uint16_t word) { |
1711 | 0 | return uint16_t((word >> 8) | (word << 8)); |
1712 | 0 | } |
1713 | | |
1714 | | constexpr inline simdutf_warn_unused uint32_t |
1715 | 995 | u32_swap_bytes(const uint32_t word) { |
1716 | 995 | return ((word >> 24) & 0xff) | // move byte 3 to byte 0 |
1717 | 995 | ((word << 8) & 0xff0000) | // move byte 1 to byte 2 |
1718 | 995 | ((word >> 8) & 0xff00) | // move byte 2 to byte 1 |
1719 | 995 | ((word << 24) & 0xff000000); // byte 0 to byte 3 |
1720 | 995 | } |
1721 | | |
1722 | | namespace utf32 { |
1723 | | template <endianness big_endian> constexpr uint32_t swap_if_needed(uint32_t c) { |
1724 | | return !match_system(big_endian) ? scalar::u32_swap_bytes(c) : c; |
1725 | | } |
1726 | | } // namespace utf32 |
1727 | | |
1728 | | namespace utf16 { |
1729 | | template <endianness big_endian> constexpr uint16_t swap_if_needed(uint16_t c) { |
1730 | | return !match_system(big_endian) ? scalar::u16_swap_bytes(c) : c; |
1731 | | } |
1732 | | } // namespace utf16 |
1733 | | |
1734 | | } // namespace scalar |
1735 | | } // namespace simdutf |
1736 | | |
1737 | | #endif |
1738 | | /* end file include/simdutf/scalar/swap_bytes.h */ |
1739 | | /* begin file include/simdutf/scalar/ascii.h */ |
1740 | | #ifndef SIMDUTF_ASCII_H |
1741 | | #define SIMDUTF_ASCII_H |
1742 | | |
1743 | | #include <cstring> |
1744 | | |
1745 | | namespace simdutf { |
1746 | | namespace scalar { |
1747 | | namespace { |
1748 | | namespace ascii { |
1749 | | |
1750 | | template <class InputPtr> |
1751 | | #if SIMDUTF_CPLUSPLUS20 |
1752 | | requires simdutf::detail::indexes_into_byte_like<InputPtr> |
1753 | | #endif |
1754 | | simdutf_warn_unused simdutf_constexpr23 bool validate(InputPtr data, |
1755 | | size_t len) noexcept { |
1756 | | uint64_t pos = 0; |
1757 | | |
1758 | | #if SIMDUTF_CPLUSPLUS23 |
1759 | | // avoid memcpy during constant evaluation |
1760 | | if !consteval |
1761 | | #endif |
1762 | | // process in blocks of 16 bytes when possible |
1763 | | { |
1764 | | for (; pos + 16 <= len; pos += 16) { |
1765 | | uint64_t v1; |
1766 | | std::memcpy(&v1, data + pos, sizeof(uint64_t)); |
1767 | | uint64_t v2; |
1768 | | std::memcpy(&v2, data + pos + sizeof(uint64_t), sizeof(uint64_t)); |
1769 | | uint64_t v{v1 | v2}; |
1770 | | if ((v & 0x8080808080808080) != 0) { |
1771 | | return false; |
1772 | | } |
1773 | | } |
1774 | | } |
1775 | | |
1776 | | // process the tail byte-by-byte |
1777 | | for (; pos < len; pos++) { |
1778 | | if (static_cast<std::uint8_t>(data[pos]) >= 0b10000000) { |
1779 | | return false; |
1780 | | } |
1781 | | } |
1782 | | return true; |
1783 | | } |
1784 | | template <class InputPtr> |
1785 | | #if SIMDUTF_CPLUSPLUS20 |
1786 | | requires simdutf::detail::indexes_into_byte_like<InputPtr> |
1787 | | #endif |
1788 | | simdutf_warn_unused simdutf_constexpr23 result |
1789 | | validate_with_errors(InputPtr data, size_t len) noexcept { |
1790 | | size_t pos = 0; |
1791 | | #if SIMDUTF_CPLUSPLUS23 |
1792 | | // avoid memcpy during constant evaluation |
1793 | | if !consteval |
1794 | | #endif |
1795 | | { |
1796 | | // process in blocks of 16 bytes when possible |
1797 | | for (; pos + 16 <= len; pos += 16) { |
1798 | | uint64_t v1; |
1799 | | std::memcpy(&v1, data + pos, sizeof(uint64_t)); |
1800 | | uint64_t v2; |
1801 | | std::memcpy(&v2, data + pos + sizeof(uint64_t), sizeof(uint64_t)); |
1802 | | uint64_t v{v1 | v2}; |
1803 | | if ((v & 0x8080808080808080) != 0) { |
1804 | | for (; pos < len; pos++) { |
1805 | | if (static_cast<std::uint8_t>(data[pos]) >= 0b10000000) { |
1806 | | return result(error_code::TOO_LARGE, pos); |
1807 | | } |
1808 | | } |
1809 | | } |
1810 | | } |
1811 | | } |
1812 | | |
1813 | | // process the tail byte-by-byte |
1814 | | for (; pos < len; pos++) { |
1815 | | if (static_cast<std::uint8_t>(data[pos]) >= 0b10000000) { |
1816 | | return result(error_code::TOO_LARGE, pos); |
1817 | | } |
1818 | | } |
1819 | | return result(error_code::SUCCESS, pos); |
1820 | | } |
1821 | | |
1822 | | } // namespace ascii |
1823 | | } // unnamed namespace |
1824 | | } // namespace scalar |
1825 | | } // namespace simdutf |
1826 | | |
1827 | | #endif |
1828 | | /* end file include/simdutf/scalar/ascii.h */ |
1829 | | /* begin file include/simdutf/scalar/atomic_util.h */ |
1830 | | #ifndef SIMDUTF_ATOMIC_UTIL_H |
1831 | | #define SIMDUTF_ATOMIC_UTIL_H |
1832 | | #if SIMDUTF_ATOMIC_REF |
1833 | | #include <atomic> |
1834 | | #include <cstring> |
1835 | | namespace simdutf { |
1836 | | namespace scalar { |
1837 | | |
1838 | | // This function is a memcpy that uses atomic operations to read from the |
1839 | | // source. |
1840 | 0 | inline void memcpy_atomic_read(char *dst, const char *src, size_t len) { |
1841 | 0 | static_assert(std::atomic_ref<char>::required_alignment == sizeof(char), |
1842 | 0 | "std::atomic_ref requires the same alignment as char_type"); |
1843 | | // We expect all 64-bit systems to be able to read 64-bit words from an |
1844 | | // aligned memory region atomically. You might be able to do better on |
1845 | | // specific systems, e.g., x64 systems can read 128-bit words atomically. |
1846 | 0 | constexpr size_t alignment = sizeof(uint64_t); |
1847 | | |
1848 | | // Lambda for atomic byte-by-byte copy |
1849 | 0 | auto bbb_memcpy_atomic_read = [](char *bytedst, const char *bytesrc, |
1850 | 0 | size_t bytelen) noexcept { |
1851 | 0 | char *mutable_src = const_cast<char *>(bytesrc); |
1852 | 0 | for (size_t j = 0; j < bytelen; ++j) { |
1853 | 0 | bytedst[j] = |
1854 | 0 | std::atomic_ref<char>(mutable_src[j]).load(std::memory_order_relaxed); |
1855 | 0 | } |
1856 | 0 | }; |
1857 | | |
1858 | | // Handle unaligned start |
1859 | 0 | size_t offset = reinterpret_cast<std::uintptr_t>(src) % alignment; |
1860 | 0 | if (offset) { |
1861 | 0 | size_t to_align = detail::min(len, alignment - offset); |
1862 | 0 | bbb_memcpy_atomic_read(dst, src, to_align); |
1863 | 0 | src += to_align; |
1864 | 0 | dst += to_align; |
1865 | 0 | len -= to_align; |
1866 | 0 | } |
1867 | | |
1868 | | // Process aligned 64-bit chunks |
1869 | 0 | while (len >= alignment) { |
1870 | 0 | auto *src_aligned = reinterpret_cast<uint64_t *>(const_cast<char *>(src)); |
1871 | 0 | const auto dst_value = |
1872 | 0 | std::atomic_ref<uint64_t>(*src_aligned).load(std::memory_order_relaxed); |
1873 | 0 | std::memcpy(dst, &dst_value, sizeof(uint64_t)); |
1874 | 0 | src += alignment; |
1875 | 0 | dst += alignment; |
1876 | 0 | len -= alignment; |
1877 | 0 | } |
1878 | | |
1879 | | // Handle remaining bytes |
1880 | 0 | if (len) { |
1881 | 0 | bbb_memcpy_atomic_read(dst, src, len); |
1882 | 0 | } |
1883 | 0 | } |
1884 | | |
1885 | | // This function is a memcpy that uses atomic operations to write to the |
1886 | | // destination. |
1887 | 0 | inline void memcpy_atomic_write(char *dst, const char *src, size_t len) { |
1888 | 0 | static_assert(std::atomic_ref<char>::required_alignment == sizeof(char), |
1889 | 0 | "std::atomic_ref requires the same alignment as char"); |
1890 | | // We expect all 64-bit systems to be able to write 64-bit words to an aligned |
1891 | | // memory region atomically. |
1892 | | // You might be able to do better on specific systems, e.g., x64 systems can |
1893 | | // write 128-bit words atomically. |
1894 | 0 | constexpr size_t alignment = sizeof(uint64_t); |
1895 | | |
1896 | | // Lambda for atomic byte-by-byte write |
1897 | 0 | auto bbb_memcpy_atomic_write = [](char *bytedst, const char *bytesrc, |
1898 | 0 | size_t bytelen) noexcept { |
1899 | 0 | for (size_t j = 0; j < bytelen; ++j) { |
1900 | 0 | std::atomic_ref<char>(bytedst[j]) |
1901 | 0 | .store(bytesrc[j], std::memory_order_relaxed); |
1902 | 0 | } |
1903 | 0 | }; |
1904 | | |
1905 | | // Handle unaligned start |
1906 | 0 | size_t offset = reinterpret_cast<std::uintptr_t>(dst) % alignment; |
1907 | 0 | if (offset) { |
1908 | 0 | size_t to_align = detail::min(len, alignment - offset); |
1909 | 0 | bbb_memcpy_atomic_write(dst, src, to_align); |
1910 | 0 | dst += to_align; |
1911 | 0 | src += to_align; |
1912 | 0 | len -= to_align; |
1913 | 0 | } |
1914 | | |
1915 | | // Process aligned 64-bit chunks |
1916 | 0 | while (len >= alignment) { |
1917 | 0 | auto *dst_aligned = reinterpret_cast<uint64_t *>(dst); |
1918 | 0 | uint64_t src_val; |
1919 | 0 | std::memcpy(&src_val, src, sizeof(uint64_t)); // Non-atomic read from src |
1920 | 0 | std::atomic_ref<uint64_t>(*dst_aligned) |
1921 | 0 | .store(src_val, std::memory_order_relaxed); |
1922 | 0 | dst += alignment; |
1923 | 0 | src += alignment; |
1924 | 0 | len -= alignment; |
1925 | 0 | } |
1926 | | |
1927 | | // Handle remaining bytes |
1928 | 0 | if (len) { |
1929 | 0 | bbb_memcpy_atomic_write(dst, src, len); |
1930 | 0 | } |
1931 | 0 | } |
1932 | | } // namespace scalar |
1933 | | } // namespace simdutf |
1934 | | #endif // SIMDUTF_ATOMIC_REF |
1935 | | #endif // SIMDUTF_ATOMIC_UTIL_H |
1936 | | /* end file include/simdutf/scalar/atomic_util.h */ |
1937 | | /* begin file include/simdutf/scalar/latin1.h */ |
1938 | | #ifndef SIMDUTF_LATIN1_H |
1939 | | #define SIMDUTF_LATIN1_H |
1940 | | |
1941 | | namespace simdutf { |
1942 | | namespace scalar { |
1943 | | namespace { |
1944 | | namespace latin1 { |
1945 | | |
1946 | | simdutf_really_inline size_t utf8_length_from_latin1(const char *buf, |
1947 | 0 | size_t len) { |
1948 | 0 | const uint8_t *c = reinterpret_cast<const uint8_t *>(buf); |
1949 | 0 | size_t answer = 0; |
1950 | 0 | for (size_t i = 0; i < len; i++) { |
1951 | 0 | if ((c[i] >> 7)) { |
1952 | 0 | answer++; |
1953 | 0 | } |
1954 | 0 | } |
1955 | 0 | return answer + len; |
1956 | 0 | } Unexecuted instantiation: parser.cpp:simdutf::scalar::(anonymous namespace)::latin1::utf8_length_from_latin1(char const*, unsigned long) Unexecuted instantiation: base64.cpp:simdutf::scalar::(anonymous namespace)::latin1::utf8_length_from_latin1(char const*, unsigned long) Unexecuted instantiation: simdutf.cpp:simdutf::scalar::(anonymous namespace)::latin1::utf8_length_from_latin1(char const*, unsigned long) |
1957 | | |
1958 | | } // namespace latin1 |
1959 | | } // unnamed namespace |
1960 | | } // namespace scalar |
1961 | | } // namespace simdutf |
1962 | | |
1963 | | #endif |
1964 | | /* end file include/simdutf/scalar/latin1.h */ |
1965 | | /* begin file include/simdutf/scalar/latin1_to_utf16/latin1_to_utf16.h */ |
1966 | | #ifndef SIMDUTF_LATIN1_TO_UTF16_H |
1967 | | #define SIMDUTF_LATIN1_TO_UTF16_H |
1968 | | |
1969 | | namespace simdutf { |
1970 | | namespace scalar { |
1971 | | namespace { |
1972 | | namespace latin1_to_utf16 { |
1973 | | |
1974 | | template <endianness big_endian, typename InputPtr> |
1975 | | #if SIMDUTF_CPLUSPLUS20 |
1976 | | requires simdutf::detail::indexes_into_byte_like<InputPtr> |
1977 | | #endif |
1978 | | simdutf_constexpr23 size_t convert(InputPtr data, size_t len, |
1979 | | char16_t *utf16_output) { |
1980 | | size_t pos = 0; |
1981 | | char16_t *start{utf16_output}; |
1982 | | |
1983 | | while (pos < len) { |
1984 | | uint16_t word = |
1985 | | uint8_t(data[pos]); // extend Latin-1 char to 16-bit Unicode code point |
1986 | | *utf16_output++ = |
1987 | | char16_t(match_system(big_endian) ? word : u16_swap_bytes(word)); |
1988 | | pos++; |
1989 | | } |
1990 | | |
1991 | | return utf16_output - start; |
1992 | | } |
1993 | | |
1994 | | template <endianness big_endian> |
1995 | | inline result convert_with_errors(const char *buf, size_t len, |
1996 | | char16_t *utf16_output) { |
1997 | | const uint8_t *data = reinterpret_cast<const uint8_t *>(buf); |
1998 | | size_t pos = 0; |
1999 | | char16_t *start{utf16_output}; |
2000 | | |
2001 | | while (pos < len) { |
2002 | | uint16_t word = |
2003 | | uint16_t(data[pos]); // extend Latin-1 char to 16-bit Unicode code point |
2004 | | *utf16_output++ = |
2005 | | char16_t(match_system(big_endian) ? word : u16_swap_bytes(word)); |
2006 | | pos++; |
2007 | | } |
2008 | | |
2009 | | return result(error_code::SUCCESS, utf16_output - start); |
2010 | | } |
2011 | | |
2012 | | } // namespace latin1_to_utf16 |
2013 | | } // unnamed namespace |
2014 | | } // namespace scalar |
2015 | | } // namespace simdutf |
2016 | | |
2017 | | #endif |
2018 | | /* end file include/simdutf/scalar/latin1_to_utf16/latin1_to_utf16.h */ |
2019 | | /* begin file include/simdutf/scalar/latin1_to_utf32/latin1_to_utf32.h */ |
2020 | | #ifndef SIMDUTF_LATIN1_TO_UTF32_H |
2021 | | #define SIMDUTF_LATIN1_TO_UTF32_H |
2022 | | |
2023 | | namespace simdutf { |
2024 | | namespace scalar { |
2025 | | namespace { |
2026 | | namespace latin1_to_utf32 { |
2027 | | |
2028 | | template <typename InputPtr> |
2029 | | #if SIMDUTF_CPLUSPLUS20 |
2030 | | requires simdutf::detail::indexes_into_byte_like<InputPtr> |
2031 | | #endif |
2032 | | simdutf_constexpr23 size_t convert(InputPtr data, size_t len, |
2033 | | char32_t *utf32_output) { |
2034 | | char32_t *start{utf32_output}; |
2035 | | for (size_t i = 0; i < len; i++) { |
2036 | | *utf32_output++ = uint8_t(data[i]); |
2037 | | } |
2038 | | return utf32_output - start; |
2039 | | } |
2040 | | |
2041 | | } // namespace latin1_to_utf32 |
2042 | | } // unnamed namespace |
2043 | | } // namespace scalar |
2044 | | } // namespace simdutf |
2045 | | |
2046 | | #endif |
2047 | | /* end file include/simdutf/scalar/latin1_to_utf32/latin1_to_utf32.h */ |
2048 | | /* begin file include/simdutf/scalar/latin1_to_utf8/latin1_to_utf8.h */ |
2049 | | #ifndef SIMDUTF_LATIN1_TO_UTF8_H |
2050 | | #define SIMDUTF_LATIN1_TO_UTF8_H |
2051 | | |
2052 | | #include <cstring> |
2053 | | |
2054 | | namespace simdutf { |
2055 | | namespace scalar { |
2056 | | namespace { |
2057 | | namespace latin1_to_utf8 { |
2058 | | |
2059 | | template <typename InputPtr, typename OutputPtr> |
2060 | | #if SIMDUTF_CPLUSPLUS20 |
2061 | | requires(simdutf::detail::indexes_into_byte_like<InputPtr> && |
2062 | | simdutf::detail::index_assignable_from_char<OutputPtr>) |
2063 | | #endif |
2064 | | simdutf_constexpr23 size_t convert(InputPtr data, size_t len, |
2065 | 0 | OutputPtr utf8_output) { |
2066 | 0 | // const unsigned char *data = reinterpret_cast<const unsigned char *>(buf); |
2067 | 0 | size_t pos = 0; |
2068 | 0 | size_t utf8_pos = 0; |
2069 | 0 |
|
2070 | 0 | while (pos < len) { |
2071 | 0 | #if SIMDUTF_CPLUSPLUS23 |
2072 | 0 | if !consteval |
2073 | 0 | #endif |
2074 | 0 | { |
2075 | 0 | // try to convert the next block of 16 ASCII bytes |
2076 | 0 | if (pos + 16 <= len) { // if it is safe to read 16 more bytes, check that |
2077 | 0 | // they are ascii |
2078 | 0 | uint64_t v1; |
2079 | 0 | ::memcpy(&v1, data + pos, sizeof(uint64_t)); |
2080 | 0 | uint64_t v2; |
2081 | 0 | ::memcpy(&v2, data + pos + sizeof(uint64_t), sizeof(uint64_t)); |
2082 | 0 | uint64_t v{v1 | |
2083 | 0 | v2}; // We are only interested in these bits: 1000 1000 1000 |
2084 | 0 | // 1000, so it makes sense to concatenate everything |
2085 | 0 | if ((v & 0x8080808080808080) == |
2086 | 0 | 0) { // if NONE of these are set, e.g. all of them are zero, then |
2087 | 0 | // everything is ASCII |
2088 | 0 | size_t final_pos = pos + 16; |
2089 | 0 | while (pos < final_pos) { |
2090 | 0 | utf8_output[utf8_pos++] = char(data[pos]); |
2091 | 0 | pos++; |
2092 | 0 | } |
2093 | 0 | continue; |
2094 | 0 | } |
2095 | 0 | } // if (pos + 16 <= len) |
2096 | 0 | } // !consteval scope |
2097 | 0 |
|
2098 | 0 | unsigned char byte = data[pos]; |
2099 | 0 | if ((byte & 0x80) == 0) { // if ASCII |
2100 | 0 | // will generate one UTF-8 bytes |
2101 | 0 | utf8_output[utf8_pos++] = char(byte); |
2102 | 0 | pos++; |
2103 | 0 | } else { |
2104 | 0 | // will generate two UTF-8 bytes |
2105 | 0 | utf8_output[utf8_pos++] = char((byte >> 6) | 0b11000000); |
2106 | 0 | utf8_output[utf8_pos++] = char((byte & 0b111111) | 0b10000000); |
2107 | 0 | pos++; |
2108 | 0 | } |
2109 | 0 | } // while |
2110 | 0 | return utf8_pos; |
2111 | 0 | } Unexecuted instantiation: parser.cpp:_ZN7simdutf6scalar12_GLOBAL__N_114latin1_to_utf87convertIPKhPcQaasr7simdutf6detailE22indexes_into_byte_likeIT_Esr7simdutf6detailE26index_assignable_from_charIT0_EEEmS7_mS8_ Unexecuted instantiation: base64.cpp:_ZN7simdutf6scalar12_GLOBAL__N_114latin1_to_utf87convertIPKhPcQaasr7simdutf6detailE22indexes_into_byte_likeIT_Esr7simdutf6detailE26index_assignable_from_charIT0_EEEmS7_mS8_ Unexecuted instantiation: simdutf.cpp:_ZN7simdutf6scalar12_GLOBAL__N_114latin1_to_utf87convertIPKhPcQaasr7simdutf6detailE22indexes_into_byte_likeIT_Esr7simdutf6detailE26index_assignable_from_charIT0_EEEmS7_mS8_ |
2112 | | |
2113 | | simdutf_really_inline size_t convert(const char *buf, size_t len, |
2114 | 0 | char *utf8_output) { |
2115 | 0 | return convert(reinterpret_cast<const unsigned char *>(buf), len, |
2116 | 0 | utf8_output); |
2117 | 0 | } Unexecuted instantiation: parser.cpp:simdutf::scalar::(anonymous namespace)::latin1_to_utf8::convert(char const*, unsigned long, char*) Unexecuted instantiation: base64.cpp:simdutf::scalar::(anonymous namespace)::latin1_to_utf8::convert(char const*, unsigned long, char*) Unexecuted instantiation: simdutf.cpp:simdutf::scalar::(anonymous namespace)::latin1_to_utf8::convert(char const*, unsigned long, char*) |
2118 | | |
2119 | | inline size_t convert_safe(const char *buf, size_t len, char *utf8_output, |
2120 | 0 | size_t utf8_len) { |
2121 | 0 | const unsigned char *data = reinterpret_cast<const unsigned char *>(buf); |
2122 | 0 | size_t pos = 0; |
2123 | 0 | size_t skip_pos = 0; |
2124 | 0 | size_t utf8_pos = 0; |
2125 | 0 | while (pos < len && utf8_pos < utf8_len) { |
2126 | 0 | // try to convert the next block of 16 ASCII bytes |
2127 | 0 | if (pos >= skip_pos && pos + 16 <= len && |
2128 | 0 | utf8_pos + 16 <= utf8_len) { // if it is safe to read 16 more bytes, |
2129 | 0 | // check that they are ascii |
2130 | 0 | uint64_t v1; |
2131 | 0 | ::memcpy(&v1, data + pos, sizeof(uint64_t)); |
2132 | 0 | uint64_t v2; |
2133 | 0 | ::memcpy(&v2, data + pos + sizeof(uint64_t), sizeof(uint64_t)); |
2134 | 0 | uint64_t v{v1 | |
2135 | 0 | v2}; // We are only interested in these bits: 1000 1000 1000 |
2136 | 0 | // 1000, so it makes sense to concatenate everything |
2137 | 0 | if ((v & 0x8080808080808080) == |
2138 | 0 | 0) { // if NONE of these are set, e.g. all of them are zero, then |
2139 | 0 | // everything is ASCII |
2140 | 0 | ::memcpy(utf8_output + utf8_pos, buf + pos, 16); |
2141 | 0 | utf8_pos += 16; |
2142 | 0 | pos += 16; |
2143 | 0 | } else { |
2144 | 0 | // At least one of the next 16 bytes are not ASCII, we will process them |
2145 | 0 | // one by one |
2146 | 0 | skip_pos = pos + 16; |
2147 | 0 | } |
2148 | 0 | } else { |
2149 | 0 | const auto byte = data[pos]; |
2150 | 0 | if ((byte & 0x80) == 0) { // if ASCII |
2151 | 0 | // will generate one UTF-8 bytes |
2152 | 0 | utf8_output[utf8_pos++] = char(byte); |
2153 | 0 | pos++; |
2154 | 0 | } else if (utf8_pos + 2 <= utf8_len) { |
2155 | 0 | // will generate two UTF-8 bytes |
2156 | 0 | utf8_output[utf8_pos++] = char((byte >> 6) | 0b11000000); |
2157 | 0 | utf8_output[utf8_pos++] = char((byte & 0b111111) | 0b10000000); |
2158 | 0 | pos++; |
2159 | 0 | } else { |
2160 | 0 | break; |
2161 | 0 | } |
2162 | 0 | } |
2163 | 0 | } |
2164 | 0 | return utf8_pos; |
2165 | 0 | } Unexecuted instantiation: parser.cpp:simdutf::scalar::(anonymous namespace)::latin1_to_utf8::convert_safe(char const*, unsigned long, char*, unsigned long) Unexecuted instantiation: base64.cpp:simdutf::scalar::(anonymous namespace)::latin1_to_utf8::convert_safe(char const*, unsigned long, char*, unsigned long) Unexecuted instantiation: simdutf.cpp:simdutf::scalar::(anonymous namespace)::latin1_to_utf8::convert_safe(char const*, unsigned long, char*, unsigned long) |
2166 | | |
2167 | | inline full_result convert_safe_with_details(const char *buf, size_t len, |
2168 | | char *utf8_output, |
2169 | 0 | size_t utf8_len) { |
2170 | 0 | const size_t output_count = convert_safe(buf, len, utf8_output, utf8_len); |
2171 | 0 | // Recover the consumed input count from the completed output. The runtime |
2172 | 0 | // safe converter uses this helper only for its short scalar tail. |
2173 | 0 | size_t input_count = 0; |
2174 | 0 | size_t counted_output = 0; |
2175 | 0 | while (input_count < len) { |
2176 | 0 | const size_t width = |
2177 | 0 | uint8_t(buf[input_count]) < uint8_t(0x80) ? size_t(1) : size_t(2); |
2178 | 0 | if (counted_output + width > output_count) { |
2179 | 0 | break; |
2180 | 0 | } |
2181 | 0 | input_count++; |
2182 | 0 | counted_output += width; |
2183 | 0 | } |
2184 | 0 | return full_result(input_count == len ? error_code::SUCCESS |
2185 | 0 | : error_code::OUTPUT_BUFFER_TOO_SMALL, |
2186 | 0 | input_count, output_count); |
2187 | 0 | } Unexecuted instantiation: parser.cpp:simdutf::scalar::(anonymous namespace)::latin1_to_utf8::convert_safe_with_details(char const*, unsigned long, char*, unsigned long) Unexecuted instantiation: base64.cpp:simdutf::scalar::(anonymous namespace)::latin1_to_utf8::convert_safe_with_details(char const*, unsigned long, char*, unsigned long) Unexecuted instantiation: simdutf.cpp:simdutf::scalar::(anonymous namespace)::latin1_to_utf8::convert_safe_with_details(char const*, unsigned long, char*, unsigned long) |
2188 | | |
2189 | | template <typename InputPtr, typename OutputPtr> |
2190 | | #if SIMDUTF_CPLUSPLUS20 |
2191 | | requires(simdutf::detail::indexes_into_byte_like<InputPtr> && |
2192 | | simdutf::detail::index_assignable_from_char<OutputPtr>) |
2193 | | #endif |
2194 | | simdutf_constexpr23 size_t convert_safe_constexpr(InputPtr data, size_t len, |
2195 | | OutputPtr utf8_output, |
2196 | | size_t utf8_len) { |
2197 | | size_t pos = 0; |
2198 | | size_t utf8_pos = 0; |
2199 | | while (pos < len && utf8_pos < utf8_len) { |
2200 | | const unsigned char byte = data[pos]; |
2201 | | if ((byte & 0x80) == 0) { // if ASCII |
2202 | | // will generate one UTF-8 bytes |
2203 | | utf8_output[utf8_pos++] = char(byte); |
2204 | | pos++; |
2205 | | } else if (utf8_pos + 2 <= utf8_len) { |
2206 | | // will generate two UTF-8 bytes |
2207 | | utf8_output[utf8_pos++] = char((byte >> 6) | 0b11000000); |
2208 | | utf8_output[utf8_pos++] = char((byte & 0b111111) | 0b10000000); |
2209 | | pos++; |
2210 | | } else { |
2211 | | break; |
2212 | | } |
2213 | | } |
2214 | | return utf8_pos; |
2215 | | } |
2216 | | |
2217 | | template <typename InputPtr, typename OutputPtr> |
2218 | | #if SIMDUTF_CPLUSPLUS20 |
2219 | | requires(simdutf::detail::indexes_into_byte_like<InputPtr> && |
2220 | | simdutf::detail::index_assignable_from_char<OutputPtr>) |
2221 | | #endif |
2222 | | simdutf_constexpr23 full_result convert_safe_with_details_constexpr( |
2223 | | InputPtr data, size_t len, OutputPtr utf8_output, size_t utf8_len) { |
2224 | | const size_t output_count = |
2225 | | convert_safe_constexpr(data, len, utf8_output, utf8_len); |
2226 | | size_t input_count = 0; |
2227 | | size_t counted_output = 0; |
2228 | | while (input_count < len) { |
2229 | | const size_t width = |
2230 | | uint8_t(data[input_count]) < uint8_t(0x80) ? size_t(1) : size_t(2); |
2231 | | if (counted_output + width > output_count) { |
2232 | | break; |
2233 | | } |
2234 | | input_count++; |
2235 | | counted_output += width; |
2236 | | } |
2237 | | return full_result(input_count == len ? error_code::SUCCESS |
2238 | | : error_code::OUTPUT_BUFFER_TOO_SMALL, |
2239 | | input_count, output_count); |
2240 | | } |
2241 | | |
2242 | | template <typename InputPtr> |
2243 | | #if SIMDUTF_CPLUSPLUS20 |
2244 | | requires simdutf::detail::indexes_into_byte_like<InputPtr> |
2245 | | #endif |
2246 | | simdutf_constexpr23 simdutf_warn_unused size_t |
2247 | | utf8_length_from_latin1(InputPtr input, size_t length) noexcept { |
2248 | | size_t answer = length; |
2249 | | size_t i = 0; |
2250 | | |
2251 | | #if SIMDUTF_CPLUSPLUS23 |
2252 | | if !consteval |
2253 | | #endif |
2254 | | { |
2255 | | auto pop = [](uint64_t v) { |
2256 | | return (size_t)(((v >> 7) & UINT64_C(0x0101010101010101)) * |
2257 | | UINT64_C(0x0101010101010101) >> |
2258 | | 56); |
2259 | | }; |
2260 | | for (; i + 32 <= length; i += 32) { |
2261 | | uint64_t v; |
2262 | | memcpy(&v, input + i, 8); |
2263 | | answer += pop(v); |
2264 | | memcpy(&v, input + i + 8, sizeof(v)); |
2265 | | answer += pop(v); |
2266 | | memcpy(&v, input + i + 16, sizeof(v)); |
2267 | | answer += pop(v); |
2268 | | memcpy(&v, input + i + 24, sizeof(v)); |
2269 | | answer += pop(v); |
2270 | | } |
2271 | | for (; i + 8 <= length; i += 8) { |
2272 | | uint64_t v; |
2273 | | memcpy(&v, input + i, sizeof(v)); |
2274 | | answer += pop(v); |
2275 | | } |
2276 | | } // !consteval scope |
2277 | | for (; i + 1 <= length; i += 1) { |
2278 | | answer += static_cast<uint8_t>(input[i]) >> 7; |
2279 | | } |
2280 | | return answer; |
2281 | | } |
2282 | | |
2283 | | } // namespace latin1_to_utf8 |
2284 | | } // unnamed namespace |
2285 | | } // namespace scalar |
2286 | | } // namespace simdutf |
2287 | | |
2288 | | #endif |
2289 | | /* end file include/simdutf/scalar/latin1_to_utf8/latin1_to_utf8.h */ |
2290 | | /* begin file include/simdutf/scalar/utf16.h */ |
2291 | | #ifndef SIMDUTF_UTF16_H |
2292 | | #define SIMDUTF_UTF16_H |
2293 | | |
2294 | | namespace simdutf { |
2295 | | namespace scalar { |
2296 | | namespace utf16 { |
2297 | | |
2298 | | template <endianness big_endian> |
2299 | | simdutf_warn_unused simdutf_constexpr23 bool |
2300 | | validate_as_ascii(const char16_t *data, size_t len) noexcept { |
2301 | | for (size_t pos = 0; pos < len; pos++) { |
2302 | | char16_t word = scalar::utf16::swap_if_needed<big_endian>(data[pos]); |
2303 | | if (word >= 0x80) { |
2304 | | return false; |
2305 | | } |
2306 | | } |
2307 | | return true; |
2308 | | } |
2309 | | |
2310 | | template <endianness big_endian> |
2311 | | inline simdutf_warn_unused simdutf_constexpr23 bool |
2312 | | validate(const char16_t *data, size_t len) noexcept { |
2313 | | uint64_t pos = 0; |
2314 | | while (pos < len) { |
2315 | | char16_t word = scalar::utf16::swap_if_needed<big_endian>(data[pos]); |
2316 | | if ((word & 0xF800) == 0xD800) { |
2317 | | if (pos + 1 >= len) { |
2318 | | return false; |
2319 | | } |
2320 | | char16_t diff = char16_t(word - 0xD800); |
2321 | | if (diff > 0x3FF) { |
2322 | | return false; |
2323 | | } |
2324 | | char16_t next_word = !match_system(big_endian) |
2325 | | ? u16_swap_bytes(data[pos + 1]) |
2326 | | : data[pos + 1]; |
2327 | | char16_t diff2 = char16_t(next_word - 0xDC00); |
2328 | | if (diff2 > 0x3FF) { |
2329 | | return false; |
2330 | | } |
2331 | | pos += 2; |
2332 | | } else { |
2333 | | pos++; |
2334 | | } |
2335 | | } |
2336 | | return true; |
2337 | | } |
2338 | | |
2339 | | template <endianness big_endian> |
2340 | | inline simdutf_warn_unused simdutf_constexpr23 result |
2341 | | validate_with_errors(const char16_t *data, size_t len) noexcept { |
2342 | | size_t pos = 0; |
2343 | | while (pos < len) { |
2344 | | char16_t word = scalar::utf16::swap_if_needed<big_endian>(data[pos]); |
2345 | | if ((word & 0xF800) == 0xD800) { |
2346 | | if (pos + 1 >= len) { |
2347 | | return result(error_code::SURROGATE, pos); |
2348 | | } |
2349 | | char16_t diff = char16_t(word - 0xD800); |
2350 | | if (diff > 0x3FF) { |
2351 | | return result(error_code::SURROGATE, pos); |
2352 | | } |
2353 | | char16_t next_word = !match_system(big_endian) |
2354 | | ? u16_swap_bytes(data[pos + 1]) |
2355 | | : data[pos + 1]; |
2356 | | char16_t diff2 = uint16_t(next_word - 0xDC00); |
2357 | | if (diff2 > 0x3FF) { |
2358 | | return result(error_code::SURROGATE, pos); |
2359 | | } |
2360 | | pos += 2; |
2361 | | } else { |
2362 | | pos++; |
2363 | | } |
2364 | | } |
2365 | | return result(error_code::SUCCESS, pos); |
2366 | | } |
2367 | | |
2368 | | template <endianness big_endian> |
2369 | | simdutf_constexpr23 size_t count_code_points(const char16_t *p, size_t len) { |
2370 | | // We are not BOM aware. |
2371 | | size_t counter{0}; |
2372 | | for (size_t i = 0; i < len; i++) { |
2373 | | char16_t word = scalar::utf16::swap_if_needed<big_endian>(p[i]); |
2374 | | counter += ((word & 0xFC00) != 0xDC00); |
2375 | | } |
2376 | | return counter; |
2377 | | } |
2378 | | |
2379 | | template <endianness big_endian> |
2380 | | simdutf_constexpr23 size_t utf8_length_from_utf16(const char16_t *p, |
2381 | | size_t len) { |
2382 | | // We are not BOM aware. |
2383 | | size_t counter{0}; |
2384 | | for (size_t i = 0; i < len; i++) { |
2385 | | char16_t word = scalar::utf16::swap_if_needed<big_endian>(p[i]); |
2386 | | counter++; // ASCII |
2387 | | counter += static_cast<size_t>( |
2388 | | word > |
2389 | | 0x7F); // non-ASCII is at least 2 bytes, surrogates are 2*2 == 4 bytes |
2390 | | counter += static_cast<size_t>((word > 0x7FF && word <= 0xD7FF) || |
2391 | | (word >= 0xE000)); // three-byte |
2392 | | } |
2393 | | return counter; |
2394 | | } |
2395 | | |
2396 | | template <endianness big_endian> |
2397 | | simdutf_constexpr23 size_t utf32_length_from_utf16(const char16_t *p, |
2398 | | size_t len) { |
2399 | | // We are not BOM aware. |
2400 | | size_t counter{0}; |
2401 | | for (size_t i = 0; i < len; i++) { |
2402 | | char16_t word = scalar::utf16::swap_if_needed<big_endian>(p[i]); |
2403 | | counter += ((word & 0xFC00) != 0xDC00); |
2404 | | } |
2405 | | return counter; |
2406 | | } |
2407 | | |
2408 | | simdutf_really_inline simdutf_constexpr23 void |
2409 | 0 | change_endianness_utf16(const char16_t *input, size_t size, char16_t *output) { |
2410 | 0 | for (size_t i = 0; i < size; i++) { |
2411 | 0 | *output++ = char16_t(input[i] >> 8 | input[i] << 8); |
2412 | 0 | } |
2413 | 0 | } |
2414 | | |
2415 | | template <endianness big_endian> |
2416 | | simdutf_warn_unused simdutf_constexpr23 size_t |
2417 | | trim_partial_utf16(const char16_t *input, size_t length) { |
2418 | | if (length == 0) { |
2419 | | return 0; |
2420 | | } |
2421 | | uint16_t last_word = uint16_t(input[length - 1]); |
2422 | | last_word = scalar::utf16::swap_if_needed<big_endian>(last_word); |
2423 | | length -= ((last_word & 0xFC00) == 0xD800); |
2424 | | return length; |
2425 | | } |
2426 | | |
2427 | | template <endianness big_endian> constexpr bool is_high_surrogate(char16_t c) { |
2428 | | c = scalar::utf16::swap_if_needed<big_endian>(c); |
2429 | | return (0xd800 <= c && c <= 0xdbff); |
2430 | | } |
2431 | | |
2432 | | template <endianness big_endian> constexpr bool is_low_surrogate(char16_t c) { |
2433 | | c = scalar::utf16::swap_if_needed<big_endian>(c); |
2434 | | return (0xdc00 <= c && c <= 0xdfff); |
2435 | | } |
2436 | | |
2437 | 0 | simdutf_unused simdutf_really_inline constexpr bool high_surrogate(char16_t c) { |
2438 | 0 | return (0xd800 <= c && c <= 0xdbff); |
2439 | 0 | } |
2440 | | |
2441 | | template <endianness big_endian> |
2442 | | simdutf_constexpr23 result |
2443 | | utf8_length_from_utf16_with_replacement(const char16_t *p, size_t len) { |
2444 | | bool any_surrogates = false; |
2445 | | // We are not BOM aware. |
2446 | | size_t counter{0}; |
2447 | | for (size_t i = 0; i < len; i++) { |
2448 | | if (is_high_surrogate<big_endian>(p[i])) { |
2449 | | any_surrogates = true; |
2450 | | // surrogate pair |
2451 | | if (i + 1 < len && is_low_surrogate<big_endian>(p[i + 1])) { |
2452 | | counter += 4; |
2453 | | i++; // skip low surrogate |
2454 | | } else { |
2455 | | counter += 3; // unpaired high surrogate replaced by U+FFFD |
2456 | | } |
2457 | | continue; |
2458 | | } else if (is_low_surrogate<big_endian>(p[i])) { |
2459 | | any_surrogates = true; |
2460 | | counter += 3; // unpaired low surrogate replaced by U+FFFD |
2461 | | continue; |
2462 | | } |
2463 | | char16_t word = !match_system(big_endian) ? u16_swap_bytes(p[i]) : p[i]; |
2464 | | counter++; // at least 1 byte |
2465 | | counter += |
2466 | | static_cast<size_t>(word > 0x7F); // non-ASCII is at least 2 bytes |
2467 | | counter += static_cast<size_t>(word > 0x7FF); // three-byte |
2468 | | } |
2469 | | return {any_surrogates ? error_code::SURROGATE : error_code::SUCCESS, |
2470 | | counter}; |
2471 | | } |
2472 | | |
2473 | | // variable templates are a C++14 extension |
2474 | | template <endianness big_endian> constexpr char16_t replacement() { |
2475 | | return !match_system(big_endian) ? scalar::u16_swap_bytes(0xfffd) : 0xfffd; |
2476 | | } |
2477 | | |
2478 | | template <endianness big_endian> |
2479 | | simdutf_constexpr23 void to_well_formed_utf16(const char16_t *input, size_t len, |
2480 | | char16_t *output) { |
2481 | | const char16_t replacement = utf16::replacement<big_endian>(); |
2482 | | bool high_surrogate_prev = false, high_surrogate, low_surrogate; |
2483 | | size_t i = 0; |
2484 | | for (; i < len; i++) { |
2485 | | char16_t c = input[i]; |
2486 | | high_surrogate = is_high_surrogate<big_endian>(c); |
2487 | | low_surrogate = is_low_surrogate<big_endian>(c); |
2488 | | if (high_surrogate_prev && !low_surrogate) { |
2489 | | output[i - 1] = replacement; |
2490 | | } |
2491 | | |
2492 | | if (!high_surrogate_prev && low_surrogate) { |
2493 | | output[i] = replacement; |
2494 | | } else { |
2495 | | output[i] = input[i]; |
2496 | | } |
2497 | | high_surrogate_prev = high_surrogate; |
2498 | | } |
2499 | | |
2500 | | /* string may not end with high surrogate */ |
2501 | | if (high_surrogate_prev) { |
2502 | | output[i - 1] = replacement; |
2503 | | } |
2504 | | } |
2505 | | |
2506 | | } // namespace utf16 |
2507 | | } // namespace scalar |
2508 | | } // namespace simdutf |
2509 | | |
2510 | | #endif |
2511 | | /* end file include/simdutf/scalar/utf16.h */ |
2512 | | /* begin file include/simdutf/scalar/utf16_to_latin1/utf16_to_latin1.h */ |
2513 | | #ifndef SIMDUTF_UTF16_TO_LATIN1_H |
2514 | | #define SIMDUTF_UTF16_TO_LATIN1_H |
2515 | | |
2516 | | #include <cstring> // for std::memcpy |
2517 | | |
2518 | | namespace simdutf { |
2519 | | namespace scalar { |
2520 | | namespace { |
2521 | | namespace utf16_to_latin1 { |
2522 | | |
2523 | | template <endianness big_endian, typename InputPtr, typename OutputPtr> |
2524 | | #if SIMDUTF_CPLUSPLUS20 |
2525 | | requires(simdutf::detail::indexes_into_utf16<InputPtr> && |
2526 | | simdutf::detail::index_assignable_from_char<OutputPtr>) |
2527 | | #endif |
2528 | | simdutf_constexpr23 size_t convert(InputPtr data, size_t len, |
2529 | | OutputPtr latin_output) { |
2530 | | if (len == 0) { |
2531 | | return 0; |
2532 | | } |
2533 | | size_t pos = 0; |
2534 | | const auto latin_output_start = latin_output; |
2535 | | uint16_t word = 0; |
2536 | | uint16_t too_large = 0; |
2537 | | |
2538 | | while (pos < len) { |
2539 | | word = !match_system(big_endian) ? u16_swap_bytes(data[pos]) : data[pos]; |
2540 | | too_large |= word; |
2541 | | *latin_output++ = char(word & 0xFF); |
2542 | | pos++; |
2543 | | } |
2544 | | if ((too_large & 0xFF00) != 0) { |
2545 | | return 0; |
2546 | | } |
2547 | | |
2548 | | return latin_output - latin_output_start; |
2549 | | } |
2550 | | |
2551 | | template <endianness big_endian, typename InputPtr, typename OutputPtr> |
2552 | | #if SIMDUTF_CPLUSPLUS20 |
2553 | | requires(simdutf::detail::indexes_into_utf16<InputPtr> && |
2554 | | simdutf::detail::index_assignable_from_char<OutputPtr>) |
2555 | | #endif |
2556 | | simdutf_constexpr23 result convert_with_errors(InputPtr data, size_t len, |
2557 | | OutputPtr latin_output) { |
2558 | | if (len == 0) { |
2559 | | return result(error_code::SUCCESS, 0); |
2560 | | } |
2561 | | size_t pos = 0; |
2562 | | auto start = latin_output; |
2563 | | uint16_t word; |
2564 | | |
2565 | | while (pos < len) { |
2566 | | #if SIMDUTF_CPLUSPLUS23 |
2567 | | if !consteval |
2568 | | #endif |
2569 | | { |
2570 | | if (pos + 16 <= len) { // if it is safe to read 32 more bytes, check that |
2571 | | // they are Latin1 |
2572 | | uint64_t v1, v2, v3, v4; |
2573 | | ::memcpy(&v1, data + pos, sizeof(uint64_t)); |
2574 | | ::memcpy(&v2, data + pos + 4, sizeof(uint64_t)); |
2575 | | ::memcpy(&v3, data + pos + 8, sizeof(uint64_t)); |
2576 | | ::memcpy(&v4, data + pos + 12, sizeof(uint64_t)); |
2577 | | |
2578 | | if constexpr (!match_system(big_endian)) { |
2579 | | v1 = (v1 >> 8) | (v1 << (64 - 8)); |
2580 | | } |
2581 | | if constexpr (!match_system(big_endian)) { |
2582 | | v2 = (v2 >> 8) | (v2 << (64 - 8)); |
2583 | | } |
2584 | | if constexpr (!match_system(big_endian)) { |
2585 | | v3 = (v3 >> 8) | (v3 << (64 - 8)); |
2586 | | } |
2587 | | if constexpr (!match_system(big_endian)) { |
2588 | | v4 = (v4 >> 8) | (v4 << (64 - 8)); |
2589 | | } |
2590 | | |
2591 | | if (((v1 | v2 | v3 | v4) & 0xFF00FF00FF00FF00) == 0) { |
2592 | | size_t final_pos = pos + 16; |
2593 | | while (pos < final_pos) { |
2594 | | *latin_output++ = !match_system(big_endian) |
2595 | | ? char(u16_swap_bytes(data[pos])) |
2596 | | : char(data[pos]); |
2597 | | pos++; |
2598 | | } |
2599 | | continue; |
2600 | | } |
2601 | | } |
2602 | | } |
2603 | | |
2604 | | word = !match_system(big_endian) ? u16_swap_bytes(data[pos]) : data[pos]; |
2605 | | if ((word & 0xFF00) == 0) { |
2606 | | *latin_output++ = char(word & 0xFF); |
2607 | | pos++; |
2608 | | } else { |
2609 | | return result(error_code::TOO_LARGE, pos); |
2610 | | } |
2611 | | } |
2612 | | return result(error_code::SUCCESS, latin_output - start); |
2613 | | } |
2614 | | |
2615 | | } // namespace utf16_to_latin1 |
2616 | | } // unnamed namespace |
2617 | | } // namespace scalar |
2618 | | } // namespace simdutf |
2619 | | |
2620 | | #endif |
2621 | | /* end file include/simdutf/scalar/utf16_to_latin1/utf16_to_latin1.h */ |
2622 | | /* begin file include/simdutf/scalar/utf16_to_latin1/valid_utf16_to_latin1.h */ |
2623 | | #ifndef SIMDUTF_VALID_UTF16_TO_LATIN1_H |
2624 | | #define SIMDUTF_VALID_UTF16_TO_LATIN1_H |
2625 | | |
2626 | | namespace simdutf { |
2627 | | namespace scalar { |
2628 | | namespace { |
2629 | | namespace utf16_to_latin1 { |
2630 | | |
2631 | | template <endianness big_endian, class InputIterator, class OutputIterator> |
2632 | | simdutf_constexpr23 inline size_t |
2633 | | convert_valid_impl(InputIterator data, size_t len, |
2634 | | OutputIterator latin_output) { |
2635 | | static_assert( |
2636 | | std::is_same<typename std::decay<decltype(*data)>::type, uint16_t>::value, |
2637 | | "must decay to uint16_t"); |
2638 | | size_t pos = 0; |
2639 | | const auto start = latin_output; |
2640 | | uint16_t word = 0; |
2641 | | |
2642 | | while (pos < len) { |
2643 | | word = !match_system(big_endian) ? u16_swap_bytes(data[pos]) : data[pos]; |
2644 | | *latin_output++ = char(word); |
2645 | | pos++; |
2646 | | } |
2647 | | |
2648 | | return latin_output - start; |
2649 | | } |
2650 | | |
2651 | | template <endianness big_endian> |
2652 | | simdutf_really_inline size_t convert_valid(const char16_t *buf, size_t len, |
2653 | | char *latin_output) { |
2654 | | return convert_valid_impl<big_endian>(reinterpret_cast<const uint16_t *>(buf), |
2655 | | len, latin_output); |
2656 | | } |
2657 | | } // namespace utf16_to_latin1 |
2658 | | } // unnamed namespace |
2659 | | } // namespace scalar |
2660 | | } // namespace simdutf |
2661 | | |
2662 | | #endif |
2663 | | /* end file include/simdutf/scalar/utf16_to_latin1/valid_utf16_to_latin1.h */ |
2664 | | /* begin file include/simdutf/scalar/utf16_to_utf32/utf16_to_utf32.h */ |
2665 | | #ifndef SIMDUTF_UTF16_TO_UTF32_H |
2666 | | #define SIMDUTF_UTF16_TO_UTF32_H |
2667 | | |
2668 | | namespace simdutf { |
2669 | | namespace scalar { |
2670 | | namespace { |
2671 | | namespace utf16_to_utf32 { |
2672 | | |
2673 | | template <endianness big_endian> |
2674 | | simdutf_constexpr23 size_t convert(const char16_t *data, size_t len, |
2675 | | char32_t *utf32_output) { |
2676 | | size_t pos = 0; |
2677 | | char32_t *start{utf32_output}; |
2678 | | while (pos < len) { |
2679 | | uint16_t word = |
2680 | | !match_system(big_endian) ? u16_swap_bytes(data[pos]) : data[pos]; |
2681 | | if ((word & 0xF800) != 0xD800) { |
2682 | | // No surrogate pair, extend 16-bit word to 32-bit word |
2683 | | *utf32_output++ = char32_t(word); |
2684 | | pos++; |
2685 | | } else { |
2686 | | // must be a surrogate pair |
2687 | | uint16_t diff = uint16_t(word - 0xD800); |
2688 | | if (diff > 0x3FF) { |
2689 | | return 0; |
2690 | | } |
2691 | | if (pos + 1 >= len) { |
2692 | | return 0; |
2693 | | } // minimal bound checking |
2694 | | uint16_t next_word = !match_system(big_endian) |
2695 | | ? u16_swap_bytes(data[pos + 1]) |
2696 | | : data[pos + 1]; |
2697 | | uint16_t diff2 = uint16_t(next_word - 0xDC00); |
2698 | | if (diff2 > 0x3FF) { |
2699 | | return 0; |
2700 | | } |
2701 | | uint32_t value = (diff << 10) + diff2 + 0x10000; |
2702 | | *utf32_output++ = char32_t(value); |
2703 | | pos += 2; |
2704 | | } |
2705 | | } |
2706 | | return utf32_output - start; |
2707 | | } |
2708 | | |
2709 | | template <endianness big_endian> |
2710 | | simdutf_constexpr23 result convert_with_errors(const char16_t *data, size_t len, |
2711 | | char32_t *utf32_output) { |
2712 | | size_t pos = 0; |
2713 | | char32_t *start{utf32_output}; |
2714 | | while (pos < len) { |
2715 | | uint16_t word = |
2716 | | !match_system(big_endian) ? u16_swap_bytes(data[pos]) : data[pos]; |
2717 | | if ((word & 0xF800) != 0xD800) { |
2718 | | // No surrogate pair, extend 16-bit word to 32-bit word |
2719 | | *utf32_output++ = char32_t(word); |
2720 | | pos++; |
2721 | | } else { |
2722 | | // must be a surrogate pair |
2723 | | uint16_t diff = uint16_t(word - 0xD800); |
2724 | | if (diff > 0x3FF) { |
2725 | | return result(error_code::SURROGATE, pos); |
2726 | | } |
2727 | | if (pos + 1 >= len) { |
2728 | | return result(error_code::SURROGATE, pos); |
2729 | | } // minimal bound checking |
2730 | | uint16_t next_word = !match_system(big_endian) |
2731 | | ? u16_swap_bytes(data[pos + 1]) |
2732 | | : data[pos + 1]; |
2733 | | uint16_t diff2 = uint16_t(next_word - 0xDC00); |
2734 | | if (diff2 > 0x3FF) { |
2735 | | return result(error_code::SURROGATE, pos); |
2736 | | } |
2737 | | uint32_t value = (diff << 10) + diff2 + 0x10000; |
2738 | | *utf32_output++ = char32_t(value); |
2739 | | pos += 2; |
2740 | | } |
2741 | | } |
2742 | | return result(error_code::SUCCESS, utf32_output - start); |
2743 | | } |
2744 | | |
2745 | | } // namespace utf16_to_utf32 |
2746 | | } // unnamed namespace |
2747 | | } // namespace scalar |
2748 | | } // namespace simdutf |
2749 | | |
2750 | | #endif |
2751 | | /* end file include/simdutf/scalar/utf16_to_utf32/utf16_to_utf32.h */ |
2752 | | /* begin file include/simdutf/scalar/utf16_to_utf32/valid_utf16_to_utf32.h */ |
2753 | | #ifndef SIMDUTF_VALID_UTF16_TO_UTF32_H |
2754 | | #define SIMDUTF_VALID_UTF16_TO_UTF32_H |
2755 | | |
2756 | | namespace simdutf { |
2757 | | namespace scalar { |
2758 | | namespace { |
2759 | | namespace utf16_to_utf32 { |
2760 | | |
2761 | | template <endianness big_endian> |
2762 | | simdutf_constexpr23 size_t convert_valid(const char16_t *data, size_t len, |
2763 | | char32_t *utf32_output) { |
2764 | | size_t pos = 0; |
2765 | | char32_t *start{utf32_output}; |
2766 | | while (pos < len) { |
2767 | | uint16_t word = |
2768 | | !match_system(big_endian) ? u16_swap_bytes(data[pos]) : data[pos]; |
2769 | | if ((word & 0xF800) != 0xD800) { |
2770 | | // No surrogate pair, extend 16-bit word to 32-bit word |
2771 | | *utf32_output++ = char32_t(word); |
2772 | | pos++; |
2773 | | } else { |
2774 | | // must be a surrogate pair |
2775 | | uint16_t diff = uint16_t(word - 0xD800); |
2776 | | if (pos + 1 >= len) { |
2777 | | return 0; |
2778 | | } // minimal bound checking |
2779 | | uint16_t next_word = !match_system(big_endian) |
2780 | | ? u16_swap_bytes(data[pos + 1]) |
2781 | | : data[pos + 1]; |
2782 | | uint16_t diff2 = uint16_t(next_word - 0xDC00); |
2783 | | uint32_t value = (diff << 10) + diff2 + 0x10000; |
2784 | | *utf32_output++ = char32_t(value); |
2785 | | pos += 2; |
2786 | | } |
2787 | | } |
2788 | | return utf32_output - start; |
2789 | | } |
2790 | | |
2791 | | } // namespace utf16_to_utf32 |
2792 | | } // unnamed namespace |
2793 | | } // namespace scalar |
2794 | | } // namespace simdutf |
2795 | | |
2796 | | #endif |
2797 | | /* end file include/simdutf/scalar/utf16_to_utf32/valid_utf16_to_utf32.h */ |
2798 | | /* begin file include/simdutf/scalar/utf16_to_utf8/utf16_to_utf8.h */ |
2799 | | #ifndef SIMDUTF_UTF16_TO_UTF8_H |
2800 | | #define SIMDUTF_UTF16_TO_UTF8_H |
2801 | | |
2802 | | #include <cstring> |
2803 | | |
2804 | | namespace simdutf { |
2805 | | namespace scalar { |
2806 | | namespace { |
2807 | | namespace utf16_to_utf8 { |
2808 | | |
2809 | | template <endianness big_endian, typename InputPtr, typename OutputPtr> |
2810 | | #if SIMDUTF_CPLUSPLUS20 |
2811 | | requires simdutf::detail::indexes_into_utf16<InputPtr> |
2812 | | // FIXME constrain output as well |
2813 | | #endif |
2814 | | simdutf_constexpr23 size_t convert(InputPtr data, size_t len, |
2815 | | OutputPtr utf8_output) { |
2816 | | size_t pos = 0; |
2817 | | const auto start = utf8_output; |
2818 | | while (pos < len) { |
2819 | | #if SIMDUTF_CPLUSPLUS23 |
2820 | | if !consteval |
2821 | | #endif |
2822 | | { |
2823 | | // try to convert the next block of 8 bytes |
2824 | | if (pos + 4 <= len) { // if it is safe to read 8 more bytes, check that |
2825 | | // they are ascii |
2826 | | uint64_t v; |
2827 | | ::memcpy(&v, data + pos, sizeof(uint64_t)); |
2828 | | if constexpr (!match_system(big_endian)) { |
2829 | | v = (v >> 8) | (v << (64 - 8)); |
2830 | | } |
2831 | | if ((v & 0xFF80FF80FF80FF80) == 0) { |
2832 | | size_t final_pos = pos + 4; |
2833 | | while (pos < final_pos) { |
2834 | | *utf8_output++ = !match_system(big_endian) |
2835 | | ? char(u16_swap_bytes(data[pos])) |
2836 | | : char(data[pos]); |
2837 | | pos++; |
2838 | | } |
2839 | | continue; |
2840 | | } |
2841 | | } |
2842 | | } |
2843 | | uint16_t word = |
2844 | | !match_system(big_endian) ? u16_swap_bytes(data[pos]) : data[pos]; |
2845 | | if ((word & 0xFF80) == 0) { |
2846 | | // will generate one UTF-8 bytes |
2847 | | *utf8_output++ = char(word); |
2848 | | pos++; |
2849 | | } else if ((word & 0xF800) == 0) { |
2850 | | // will generate two UTF-8 bytes |
2851 | | // we have 0b110XXXXX 0b10XXXXXX |
2852 | | *utf8_output++ = char((word >> 6) | 0b11000000); |
2853 | | *utf8_output++ = char((word & 0b111111) | 0b10000000); |
2854 | | pos++; |
2855 | | } else if ((word & 0xF800) != 0xD800) { |
2856 | | // will generate three UTF-8 bytes |
2857 | | // we have 0b1110XXXX 0b10XXXXXX 0b10XXXXXX |
2858 | | *utf8_output++ = char((word >> 12) | 0b11100000); |
2859 | | *utf8_output++ = char(((word >> 6) & 0b111111) | 0b10000000); |
2860 | | *utf8_output++ = char((word & 0b111111) | 0b10000000); |
2861 | | pos++; |
2862 | | } else { |
2863 | | // must be a surrogate pair |
2864 | | if (pos + 1 >= len) { |
2865 | | return 0; |
2866 | | } |
2867 | | uint16_t diff = uint16_t(word - 0xD800); |
2868 | | if (diff > 0x3FF) { |
2869 | | return 0; |
2870 | | } |
2871 | | uint16_t next_word = !match_system(big_endian) |
2872 | | ? u16_swap_bytes(data[pos + 1]) |
2873 | | : data[pos + 1]; |
2874 | | uint16_t diff2 = uint16_t(next_word - 0xDC00); |
2875 | | if (diff2 > 0x3FF) { |
2876 | | return 0; |
2877 | | } |
2878 | | uint32_t value = (diff << 10) + diff2 + 0x10000; |
2879 | | // will generate four UTF-8 bytes |
2880 | | // we have 0b11110XXX 0b10XXXXXX 0b10XXXXXX 0b10XXXXXX |
2881 | | *utf8_output++ = char((value >> 18) | 0b11110000); |
2882 | | *utf8_output++ = char(((value >> 12) & 0b111111) | 0b10000000); |
2883 | | *utf8_output++ = char(((value >> 6) & 0b111111) | 0b10000000); |
2884 | | *utf8_output++ = char((value & 0b111111) | 0b10000000); |
2885 | | pos += 2; |
2886 | | } |
2887 | | } |
2888 | | return utf8_output - start; |
2889 | | } |
2890 | | |
2891 | | template <endianness big_endian, bool check_output = false, typename InputPtr, |
2892 | | typename OutputPtr> |
2893 | | #if SIMDUTF_CPLUSPLUS20 |
2894 | | requires(simdutf::detail::indexes_into_utf16<InputPtr> && |
2895 | | simdutf::detail::index_assignable_from_char<OutputPtr>) |
2896 | | #endif |
2897 | | simdutf_constexpr23 full_result convert_with_errors(InputPtr data, size_t len, |
2898 | | OutputPtr utf8_output, |
2899 | | size_t utf8_len = 0) { |
2900 | | if (check_output && utf8_len == 0) { |
2901 | | return full_result(error_code::OUTPUT_BUFFER_TOO_SMALL, 0, 0); |
2902 | | } |
2903 | | |
2904 | | size_t pos = 0; |
2905 | | auto start = utf8_output; |
2906 | | auto end = utf8_output + utf8_len; |
2907 | | |
2908 | | while (pos < len) { |
2909 | | #if SIMDUTF_CPLUSPLUS23 |
2910 | | if !consteval |
2911 | | #endif |
2912 | | { |
2913 | | // try to convert the next block of 8 bytes |
2914 | | if (pos + 4 <= len) { // if it is safe to read 8 more bytes, check that |
2915 | | // they are ascii |
2916 | | uint64_t v; |
2917 | | ::memcpy(&v, data + pos, sizeof(uint64_t)); |
2918 | | if constexpr (!match_system(big_endian)) |
2919 | | v = (v >> 8) | (v << (64 - 8)); |
2920 | | if ((v & 0xFF80FF80FF80FF80) == 0) { |
2921 | | size_t final_pos = pos + 4; |
2922 | | while (pos < final_pos) { |
2923 | | if (check_output && size_t(end - utf8_output) < 1) { |
2924 | | return full_result(error_code::OUTPUT_BUFFER_TOO_SMALL, pos, |
2925 | | utf8_output - start); |
2926 | | } |
2927 | | *utf8_output++ = !match_system(big_endian) |
2928 | | ? char(u16_swap_bytes(data[pos])) |
2929 | | : char(data[pos]); |
2930 | | pos++; |
2931 | | } |
2932 | | continue; |
2933 | | } |
2934 | | } |
2935 | | } |
2936 | | |
2937 | | uint16_t word = |
2938 | | !match_system(big_endian) ? u16_swap_bytes(data[pos]) : data[pos]; |
2939 | | if ((word & 0xFF80) == 0) { |
2940 | | // will generate one UTF-8 bytes |
2941 | | if (check_output && size_t(end - utf8_output) < 1) { |
2942 | | return full_result(error_code::OUTPUT_BUFFER_TOO_SMALL, pos, |
2943 | | utf8_output - start); |
2944 | | } |
2945 | | *utf8_output++ = char(word); |
2946 | | pos++; |
2947 | | } else if ((word & 0xF800) == 0) { |
2948 | | // will generate two UTF-8 bytes |
2949 | | // we have 0b110XXXXX 0b10XXXXXX |
2950 | | if (check_output && size_t(end - utf8_output) < 2) { |
2951 | | return full_result(error_code::OUTPUT_BUFFER_TOO_SMALL, pos, |
2952 | | utf8_output - start); |
2953 | | } |
2954 | | *utf8_output++ = char((word >> 6) | 0b11000000); |
2955 | | *utf8_output++ = char((word & 0b111111) | 0b10000000); |
2956 | | pos++; |
2957 | | |
2958 | | } else if ((word & 0xF800) != 0xD800) { |
2959 | | // will generate three UTF-8 bytes |
2960 | | // we have 0b1110XXXX 0b10XXXXXX 0b10XXXXXX |
2961 | | if (check_output && size_t(end - utf8_output) < 3) { |
2962 | | return full_result(error_code::OUTPUT_BUFFER_TOO_SMALL, pos, |
2963 | | utf8_output - start); |
2964 | | } |
2965 | | *utf8_output++ = char((word >> 12) | 0b11100000); |
2966 | | *utf8_output++ = char(((word >> 6) & 0b111111) | 0b10000000); |
2967 | | *utf8_output++ = char((word & 0b111111) | 0b10000000); |
2968 | | pos++; |
2969 | | } else { |
2970 | | |
2971 | | if (check_output && size_t(end - utf8_output) < 4) { |
2972 | | return full_result(error_code::OUTPUT_BUFFER_TOO_SMALL, pos, |
2973 | | utf8_output - start); |
2974 | | } |
2975 | | // must be a surrogate pair |
2976 | | if (pos + 1 >= len) { |
2977 | | return full_result(error_code::SURROGATE, pos, utf8_output - start); |
2978 | | } |
2979 | | uint16_t diff = uint16_t(word - 0xD800); |
2980 | | if (diff > 0x3FF) { |
2981 | | return full_result(error_code::SURROGATE, pos, utf8_output - start); |
2982 | | } |
2983 | | uint16_t next_word = !match_system(big_endian) |
2984 | | ? u16_swap_bytes(data[pos + 1]) |
2985 | | : data[pos + 1]; |
2986 | | uint16_t diff2 = uint16_t(next_word - 0xDC00); |
2987 | | if (diff2 > 0x3FF) { |
2988 | | return full_result(error_code::SURROGATE, pos, utf8_output - start); |
2989 | | } |
2990 | | uint32_t value = (diff << 10) + diff2 + 0x10000; |
2991 | | // will generate four UTF-8 bytes |
2992 | | // we have 0b11110XXX 0b10XXXXXX 0b10XXXXXX 0b10XXXXXX |
2993 | | *utf8_output++ = char((value >> 18) | 0b11110000); |
2994 | | *utf8_output++ = char(((value >> 12) & 0b111111) | 0b10000000); |
2995 | | *utf8_output++ = char(((value >> 6) & 0b111111) | 0b10000000); |
2996 | | *utf8_output++ = char((value & 0b111111) | 0b10000000); |
2997 | | pos += 2; |
2998 | | } |
2999 | | } |
3000 | | return full_result(error_code::SUCCESS, pos, utf8_output - start); |
3001 | | } |
3002 | | |
3003 | | template <endianness big_endian> |
3004 | | inline result simple_convert_with_errors(const char16_t *buf, size_t len, |
3005 | | char *utf8_output) { |
3006 | | return convert_with_errors<big_endian, false>(buf, len, utf8_output, 0); |
3007 | | } |
3008 | | |
3009 | | template <endianness big_endian> |
3010 | | simdutf_constexpr23 size_t convert_with_replacement(const char16_t *data, |
3011 | | size_t len, |
3012 | | char *utf8_output) { |
3013 | | size_t pos = 0; |
3014 | | char *start = utf8_output; |
3015 | | while (pos < len) { |
3016 | | #if SIMDUTF_CPLUSPLUS23 |
3017 | | if !consteval |
3018 | | #endif |
3019 | | { |
3020 | | // try to convert the next block of 8 bytes |
3021 | | if (pos + 4 <= len) { // if it is safe to read 8 more bytes, check that |
3022 | | // they are ascii |
3023 | | uint64_t v; |
3024 | | ::memcpy(&v, data + pos, sizeof(uint64_t)); |
3025 | | if constexpr (!match_system(big_endian)) { |
3026 | | v = (v >> 8) | (v << (64 - 8)); |
3027 | | } |
3028 | | if ((v & 0xFF80FF80FF80FF80) == 0) { |
3029 | | size_t final_pos = pos + 4; |
3030 | | while (pos < final_pos) { |
3031 | | *utf8_output++ = !match_system(big_endian) |
3032 | | ? char(u16_swap_bytes(data[pos])) |
3033 | | : char(data[pos]); |
3034 | | pos++; |
3035 | | } |
3036 | | continue; |
3037 | | } |
3038 | | } |
3039 | | } |
3040 | | uint16_t word = |
3041 | | !match_system(big_endian) ? u16_swap_bytes(data[pos]) : data[pos]; |
3042 | | if ((word & 0xFF80) == 0) { |
3043 | | // will generate one UTF-8 bytes |
3044 | | *utf8_output++ = char(word); |
3045 | | pos++; |
3046 | | } else if ((word & 0xF800) == 0) { |
3047 | | // will generate two UTF-8 bytes |
3048 | | // we have 0b110XXXXX 0b10XXXXXX |
3049 | | *utf8_output++ = char((word >> 6) | 0b11000000); |
3050 | | *utf8_output++ = char((word & 0b111111) | 0b10000000); |
3051 | | pos++; |
3052 | | } else if ((word & 0xF800) != 0xD800) { |
3053 | | // will generate three UTF-8 bytes |
3054 | | // we have 0b1110XXXX 0b10XXXXXX 0b10XXXXXX |
3055 | | *utf8_output++ = char((word >> 12) | 0b11100000); |
3056 | | *utf8_output++ = char(((word >> 6) & 0b111111) | 0b10000000); |
3057 | | *utf8_output++ = char((word & 0b111111) | 0b10000000); |
3058 | | pos++; |
3059 | | } else { |
3060 | | // surrogate range |
3061 | | uint16_t diff = uint16_t(word - 0xD800); |
3062 | | if (diff <= 0x3FF && pos + 1 < len) { |
3063 | | // high surrogate, check for valid pair |
3064 | | uint16_t next_word = !match_system(big_endian) |
3065 | | ? u16_swap_bytes(data[pos + 1]) |
3066 | | : data[pos + 1]; |
3067 | | uint16_t diff2 = uint16_t(next_word - 0xDC00); |
3068 | | if (diff2 <= 0x3FF) { |
3069 | | // valid surrogate pair |
3070 | | uint32_t value = (diff << 10) + diff2 + 0x10000; |
3071 | | // will generate four UTF-8 bytes |
3072 | | *utf8_output++ = char((value >> 18) | 0b11110000); |
3073 | | *utf8_output++ = char(((value >> 12) & 0b111111) | 0b10000000); |
3074 | | *utf8_output++ = char(((value >> 6) & 0b111111) | 0b10000000); |
3075 | | *utf8_output++ = char((value & 0b111111) | 0b10000000); |
3076 | | pos += 2; |
3077 | | continue; |
3078 | | } |
3079 | | } |
3080 | | // unpaired surrogate: replace with U+FFFD (0xEF 0xBF 0xBD) |
3081 | | *utf8_output++ = char(0xef); |
3082 | | *utf8_output++ = char(0xbf); |
3083 | | *utf8_output++ = char(0xbd); |
3084 | | pos++; |
3085 | | } |
3086 | | } |
3087 | | return utf8_output - start; |
3088 | | } |
3089 | | |
3090 | | template <endianness big_endian, typename InputPtr, typename OutputPtr> |
3091 | | #if SIMDUTF_CPLUSPLUS20 |
3092 | | requires(simdutf::detail::indexes_into_utf16<InputPtr> && |
3093 | | simdutf::detail::index_assignable_from_char<OutputPtr>) |
3094 | | #endif |
3095 | | simdutf_constexpr23 full_result convert_with_replacement_safe( |
3096 | | InputPtr data, size_t len, OutputPtr utf8_output, size_t utf8_len) { |
3097 | | if (len == 0) { |
3098 | | return full_result(error_code::SUCCESS, 0, 0); |
3099 | | } |
3100 | | if (utf8_len == 0) { |
3101 | | return full_result(error_code::OUTPUT_BUFFER_TOO_SMALL, 0, 0); |
3102 | | } |
3103 | | |
3104 | | size_t input_count = 0; |
3105 | | size_t output_count = 0; |
3106 | | while (input_count < len) { |
3107 | | full_result r = convert_with_errors<big_endian, true>( |
3108 | | data + input_count, len - input_count, utf8_output + output_count, |
3109 | | utf8_len - output_count); |
3110 | | input_count += r.input_count; |
3111 | | output_count += r.output_count; |
3112 | | |
3113 | | if (r.error == error_code::SUCCESS) { |
3114 | | return full_result(error_code::SUCCESS, input_count, output_count); |
3115 | | } |
3116 | | |
3117 | | if (r.error == error_code::OUTPUT_BUFFER_TOO_SMALL) { |
3118 | | if (utf8_len - output_count < 3) { |
3119 | | return full_result(r.error, input_count, output_count); |
3120 | | } |
3121 | | |
3122 | | uint16_t word = !match_system(big_endian) |
3123 | | ? u16_swap_bytes(data[input_count]) |
3124 | | : data[input_count]; |
3125 | | bool unpaired = (word & 0xfc00) == 0xdc00; |
3126 | | if ((word & 0xfc00) == 0xd800) { |
3127 | | if (input_count + 1 == len) { |
3128 | | unpaired = true; |
3129 | | } else { |
3130 | | const uint16_t next_word = !match_system(big_endian) |
3131 | | ? u16_swap_bytes(data[input_count + 1]) |
3132 | | : data[input_count + 1]; |
3133 | | unpaired = (next_word & 0xfc00) != 0xdc00; |
3134 | | } |
3135 | | } |
3136 | | if (!unpaired) { |
3137 | | return full_result(r.error, input_count, output_count); |
3138 | | } |
3139 | | } else if (r.error != error_code::SURROGATE) { |
3140 | | return full_result(r.error, input_count, output_count); |
3141 | | } |
3142 | | |
3143 | | if (utf8_len - output_count < 3) { |
3144 | | return full_result(error_code::OUTPUT_BUFFER_TOO_SMALL, input_count, |
3145 | | output_count); |
3146 | | } |
3147 | | utf8_output[output_count++] = char(0xef); |
3148 | | utf8_output[output_count++] = char(0xbf); |
3149 | | utf8_output[output_count++] = char(0xbd); |
3150 | | input_count++; |
3151 | | } |
3152 | | return full_result(error_code::SUCCESS, input_count, output_count); |
3153 | | } |
3154 | | |
3155 | | } // namespace utf16_to_utf8 |
3156 | | } // unnamed namespace |
3157 | | } // namespace scalar |
3158 | | } // namespace simdutf |
3159 | | |
3160 | | #endif |
3161 | | /* end file include/simdutf/scalar/utf16_to_utf8/utf16_to_utf8.h */ |
3162 | | /* begin file include/simdutf/scalar/utf16_to_utf8/valid_utf16_to_utf8.h */ |
3163 | | #ifndef SIMDUTF_VALID_UTF16_TO_UTF8_H |
3164 | | #define SIMDUTF_VALID_UTF16_TO_UTF8_H |
3165 | | |
3166 | | #include <cstring> |
3167 | | |
3168 | | namespace simdutf { |
3169 | | namespace scalar { |
3170 | | namespace { |
3171 | | namespace utf16_to_utf8 { |
3172 | | |
3173 | | template <endianness big_endian, typename InputPtr, typename OutputPtr> |
3174 | | #if SIMDUTF_CPLUSPLUS20 |
3175 | | requires(simdutf::detail::indexes_into_utf16<InputPtr> && |
3176 | | simdutf::detail::index_assignable_from_char<OutputPtr>) |
3177 | | #endif |
3178 | | simdutf_constexpr23 size_t convert_valid(InputPtr data, size_t len, |
3179 | | OutputPtr utf8_output) { |
3180 | | size_t pos = 0; |
3181 | | auto start = utf8_output; |
3182 | | while (pos < len) { |
3183 | | #if SIMDUTF_CPLUSPLUS23 |
3184 | | if !consteval |
3185 | | #endif |
3186 | | { |
3187 | | // try to convert the next block of 4 ASCII characters |
3188 | | if (pos + 4 <= len) { // if it is safe to read 8 more bytes, check that |
3189 | | // they are ascii |
3190 | | uint64_t v; |
3191 | | ::memcpy(&v, data + pos, sizeof(uint64_t)); |
3192 | | if constexpr (!match_system(big_endian)) { |
3193 | | v = (v >> 8) | (v << (64 - 8)); |
3194 | | } |
3195 | | if ((v & 0xFF80FF80FF80FF80) == 0) { |
3196 | | size_t final_pos = pos + 4; |
3197 | | while (pos < final_pos) { |
3198 | | *utf8_output++ = !match_system(big_endian) |
3199 | | ? char(u16_swap_bytes(data[pos])) |
3200 | | : char(data[pos]); |
3201 | | pos++; |
3202 | | } |
3203 | | continue; |
3204 | | } |
3205 | | } |
3206 | | } |
3207 | | |
3208 | | uint16_t word = |
3209 | | !match_system(big_endian) ? u16_swap_bytes(data[pos]) : data[pos]; |
3210 | | if ((word & 0xFF80) == 0) { |
3211 | | // will generate one UTF-8 bytes |
3212 | | *utf8_output++ = char(word); |
3213 | | pos++; |
3214 | | } else if ((word & 0xF800) == 0) { |
3215 | | // will generate two UTF-8 bytes |
3216 | | // we have 0b110XXXXX 0b10XXXXXX |
3217 | | *utf8_output++ = char((word >> 6) | 0b11000000); |
3218 | | *utf8_output++ = char((word & 0b111111) | 0b10000000); |
3219 | | pos++; |
3220 | | } else if ((word & 0xF800) != 0xD800) { |
3221 | | // will generate three UTF-8 bytes |
3222 | | // we have 0b1110XXXX 0b10XXXXXX 0b10XXXXXX |
3223 | | *utf8_output++ = char((word >> 12) | 0b11100000); |
3224 | | *utf8_output++ = char(((word >> 6) & 0b111111) | 0b10000000); |
3225 | | *utf8_output++ = char((word & 0b111111) | 0b10000000); |
3226 | | pos++; |
3227 | | } else { |
3228 | | // must be a surrogate pair |
3229 | | uint16_t diff = uint16_t(word - 0xD800); |
3230 | | if (pos + 1 >= len) { |
3231 | | return 0; |
3232 | | } // minimal bound checking |
3233 | | uint16_t next_word = !match_system(big_endian) |
3234 | | ? u16_swap_bytes(data[pos + 1]) |
3235 | | : data[pos + 1]; |
3236 | | uint16_t diff2 = uint16_t(next_word - 0xDC00); |
3237 | | uint32_t value = (diff << 10) + diff2 + 0x10000; |
3238 | | // will generate four UTF-8 bytes |
3239 | | // we have 0b11110XXX 0b10XXXXXX 0b10XXXXXX 0b10XXXXXX |
3240 | | *utf8_output++ = char((value >> 18) | 0b11110000); |
3241 | | *utf8_output++ = char(((value >> 12) & 0b111111) | 0b10000000); |
3242 | | *utf8_output++ = char(((value >> 6) & 0b111111) | 0b10000000); |
3243 | | *utf8_output++ = char((value & 0b111111) | 0b10000000); |
3244 | | pos += 2; |
3245 | | } |
3246 | | } |
3247 | | return utf8_output - start; |
3248 | | } |
3249 | | |
3250 | | } // namespace utf16_to_utf8 |
3251 | | } // unnamed namespace |
3252 | | } // namespace scalar |
3253 | | } // namespace simdutf |
3254 | | |
3255 | | #endif |
3256 | | /* end file include/simdutf/scalar/utf16_to_utf8/valid_utf16_to_utf8.h */ |
3257 | | /* begin file include/simdutf/scalar/utf32.h */ |
3258 | | #ifndef SIMDUTF_UTF32_H |
3259 | | #define SIMDUTF_UTF32_H |
3260 | | |
3261 | | namespace simdutf { |
3262 | | namespace scalar { |
3263 | | namespace utf32 { |
3264 | | |
3265 | | template <typename InputPtr> |
3266 | | #if SIMDUTF_CPLUSPLUS20 |
3267 | | requires simdutf::detail::indexes_into_uint32<InputPtr> |
3268 | | #endif |
3269 | | simdutf_warn_unused simdutf_constexpr23 bool validate(InputPtr data, |
3270 | 0 | size_t len) noexcept { |
3271 | 0 | uint64_t pos = 0; |
3272 | 0 | for (; pos < len; pos++) { |
3273 | 0 | uint32_t word = data[pos]; |
3274 | 0 | if (word > 0x10FFFF || (word >= 0xD800 && word <= 0xDFFF)) { |
3275 | 0 | return false; |
3276 | 0 | } |
3277 | 0 | } |
3278 | 0 | return true; |
3279 | 0 | } |
3280 | | |
3281 | | simdutf_warn_unused simdutf_really_inline bool validate(const char32_t *buf, |
3282 | 0 | size_t len) noexcept { |
3283 | 0 | return validate(reinterpret_cast<const uint32_t *>(buf), len); |
3284 | 0 | } |
3285 | | |
3286 | | template <typename InputPtr> |
3287 | | #if SIMDUTF_CPLUSPLUS20 |
3288 | | requires simdutf::detail::indexes_into_uint32<InputPtr> |
3289 | | #endif |
3290 | | simdutf_warn_unused simdutf_constexpr23 result |
3291 | 0 | validate_with_errors(InputPtr data, size_t len) noexcept { |
3292 | 0 | size_t pos = 0; |
3293 | 0 | for (; pos < len; pos++) { |
3294 | 0 | uint32_t word = data[pos]; |
3295 | 0 | if (word > 0x10FFFF) { |
3296 | 0 | return result(error_code::TOO_LARGE, pos); |
3297 | 0 | } |
3298 | 0 | if (word >= 0xD800 && word <= 0xDFFF) { |
3299 | 0 | return result(error_code::SURROGATE, pos); |
3300 | 0 | } |
3301 | 0 | } |
3302 | 0 | return result(error_code::SUCCESS, pos); |
3303 | 0 | } |
3304 | | |
3305 | | simdutf_warn_unused simdutf_really_inline result |
3306 | 0 | validate_with_errors(const char32_t *buf, size_t len) noexcept { |
3307 | 0 | return validate_with_errors(reinterpret_cast<const uint32_t *>(buf), len); |
3308 | 0 | } |
3309 | | |
3310 | | inline simdutf_constexpr23 size_t utf8_length_from_utf32(const char32_t *p, |
3311 | 0 | size_t len) { |
3312 | 0 | // We are not BOM aware. |
3313 | 0 | size_t counter{0}; |
3314 | 0 | for (size_t i = 0; i < len; i++) { |
3315 | 0 | // credit: @ttsugriy for the vectorizable approach |
3316 | 0 | counter++; // ASCII |
3317 | 0 | counter += static_cast<size_t>(p[i] > 0x7F); // two-byte |
3318 | 0 | counter += static_cast<size_t>(p[i] > 0x7FF); // three-byte |
3319 | 0 | counter += static_cast<size_t>(p[i] > 0xFFFF); // four-bytes |
3320 | 0 | } |
3321 | 0 | return counter; |
3322 | 0 | } |
3323 | | |
3324 | | inline simdutf_warn_unused simdutf_constexpr23 size_t |
3325 | 0 | utf16_length_from_utf32(const char32_t *p, size_t len) { |
3326 | 0 | // We are not BOM aware. |
3327 | 0 | size_t counter{0}; |
3328 | 0 | for (size_t i = 0; i < len; i++) { |
3329 | 0 | counter++; // non-surrogate word |
3330 | 0 | counter += static_cast<size_t>(p[i] > 0xFFFF); // surrogate pair |
3331 | 0 | } |
3332 | 0 | return counter; |
3333 | 0 | } |
3334 | | |
3335 | | } // namespace utf32 |
3336 | | } // namespace scalar |
3337 | | } // namespace simdutf |
3338 | | |
3339 | | #endif |
3340 | | /* end file include/simdutf/scalar/utf32.h */ |
3341 | | /* begin file include/simdutf/scalar/utf32_to_latin1/utf32_to_latin1.h */ |
3342 | | #ifndef SIMDUTF_UTF32_TO_LATIN1_H |
3343 | | #define SIMDUTF_UTF32_TO_LATIN1_H |
3344 | | |
3345 | | #include <cstring> |
3346 | | |
3347 | | namespace simdutf { |
3348 | | namespace scalar { |
3349 | | namespace { |
3350 | | namespace utf32_to_latin1 { |
3351 | | |
3352 | | inline simdutf_constexpr23 size_t convert(const char32_t *data, size_t len, |
3353 | 0 | char *latin1_output) { |
3354 | 0 | char *start = latin1_output; |
3355 | 0 | uint32_t utf32_char; |
3356 | 0 | size_t pos = 0; |
3357 | 0 | uint32_t too_large = 0; |
3358 | 0 |
|
3359 | 0 | while (pos < len) { |
3360 | 0 | utf32_char = (uint32_t)data[pos]; |
3361 | 0 | too_large |= utf32_char; |
3362 | 0 | *latin1_output++ = (char)(utf32_char & 0xFF); |
3363 | 0 | pos++; |
3364 | 0 | } |
3365 | 0 | if ((too_large & 0xFFFFFF00) != 0) { |
3366 | 0 | return 0; |
3367 | 0 | } |
3368 | 0 | return latin1_output - start; |
3369 | 0 | } Unexecuted instantiation: parser.cpp:simdutf::scalar::(anonymous namespace)::utf32_to_latin1::convert(char32_t const*, unsigned long, char*) Unexecuted instantiation: base64.cpp:simdutf::scalar::(anonymous namespace)::utf32_to_latin1::convert(char32_t const*, unsigned long, char*) Unexecuted instantiation: simdutf.cpp:simdutf::scalar::(anonymous namespace)::utf32_to_latin1::convert(char32_t const*, unsigned long, char*) |
3370 | | |
3371 | | inline simdutf_constexpr23 result convert_with_errors(const char32_t *data, |
3372 | | size_t len, |
3373 | 0 | char *latin1_output) { |
3374 | 0 | char *start{latin1_output}; |
3375 | 0 | size_t pos = 0; |
3376 | 0 | while (pos < len) { |
3377 | 0 | #if SIMDUTF_CPLUSPLUS23 |
3378 | 0 | if !consteval |
3379 | 0 | #endif |
3380 | 0 | { |
3381 | 0 | if (pos + 2 <= len) { // if it is safe to read 8 more bytes, check that |
3382 | 0 | // they are Latin1 |
3383 | 0 | uint64_t v; |
3384 | 0 | ::memcpy(&v, data + pos, sizeof(uint64_t)); |
3385 | 0 | if ((v & 0xFFFFFF00FFFFFF00) == 0) { |
3386 | 0 | *latin1_output++ = char(data[pos]); |
3387 | 0 | *latin1_output++ = char(data[pos + 1]); |
3388 | 0 | pos += 2; |
3389 | 0 | continue; |
3390 | 0 | } |
3391 | 0 | } |
3392 | 0 | } |
3393 | 0 |
|
3394 | 0 | uint32_t utf32_char = data[pos]; |
3395 | 0 | if ((utf32_char & 0xFFFFFF00) == |
3396 | 0 | 0) { // Check if the character can be represented in Latin-1 |
3397 | 0 | *latin1_output++ = (char)(utf32_char & 0xFF); |
3398 | 0 | pos++; |
3399 | 0 | } else { |
3400 | 0 | return result(error_code::TOO_LARGE, pos); |
3401 | 0 | }; |
3402 | 0 | } |
3403 | 0 | return result(error_code::SUCCESS, latin1_output - start); |
3404 | 0 | } Unexecuted instantiation: parser.cpp:simdutf::scalar::(anonymous namespace)::utf32_to_latin1::convert_with_errors(char32_t const*, unsigned long, char*) Unexecuted instantiation: base64.cpp:simdutf::scalar::(anonymous namespace)::utf32_to_latin1::convert_with_errors(char32_t const*, unsigned long, char*) Unexecuted instantiation: simdutf.cpp:simdutf::scalar::(anonymous namespace)::utf32_to_latin1::convert_with_errors(char32_t const*, unsigned long, char*) |
3405 | | |
3406 | | } // namespace utf32_to_latin1 |
3407 | | } // unnamed namespace |
3408 | | } // namespace scalar |
3409 | | } // namespace simdutf |
3410 | | |
3411 | | #endif |
3412 | | /* end file include/simdutf/scalar/utf32_to_latin1/utf32_to_latin1.h */ |
3413 | | /* begin file include/simdutf/scalar/utf32_to_latin1/valid_utf32_to_latin1.h */ |
3414 | | #ifndef SIMDUTF_VALID_UTF32_TO_LATIN1_H |
3415 | | #define SIMDUTF_VALID_UTF32_TO_LATIN1_H |
3416 | | |
3417 | | #include <cstring> |
3418 | | |
3419 | | namespace simdutf { |
3420 | | namespace scalar { |
3421 | | namespace { |
3422 | | namespace utf32_to_latin1 { |
3423 | | |
3424 | | template <typename ReadPtr, typename WritePtr> |
3425 | | simdutf_constexpr23 size_t convert_valid(ReadPtr data, size_t len, |
3426 | 0 | WritePtr latin1_output) { |
3427 | 0 | static_assert( |
3428 | 0 | std::is_same<typename std::decay<decltype(*data)>::type, uint32_t>::value, |
3429 | 0 | "dereferencing the data pointer must result in a uint32_t"); |
3430 | 0 | auto start = latin1_output; |
3431 | 0 | uint32_t utf32_char; |
3432 | 0 | size_t pos = 0; |
3433 | 0 |
|
3434 | 0 | while (pos < len) { |
3435 | 0 | utf32_char = data[pos]; |
3436 | 0 |
|
3437 | 0 | #if SIMDUTF_CPLUSPLUS23 |
3438 | 0 | // avoid using the 8 byte at a time optimization in constant evaluation |
3439 | 0 | // mode. memcpy can't be used and replacing it with bitwise or gave worse |
3440 | 0 | // codegen (when not during constant evaluation). |
3441 | 0 | if !consteval { |
3442 | 0 | #endif |
3443 | 0 | if (pos + 2 <= len) { |
3444 | 0 | // if it is safe to read 8 more bytes, check that they are Latin1 |
3445 | 0 | uint64_t v; |
3446 | 0 | std::memcpy(&v, data + pos, sizeof(uint64_t)); |
3447 | 0 | if ((v & 0xFFFFFF00FFFFFF00) == 0) { |
3448 | 0 | *latin1_output++ = char(data[pos]); |
3449 | 0 | *latin1_output++ = char(data[pos + 1]); |
3450 | 0 | pos += 2; |
3451 | 0 | continue; |
3452 | 0 | } else { |
3453 | 0 | // output can not be represented in latin1 |
3454 | 0 | return 0; |
3455 | 0 | } |
3456 | 0 | } |
3457 | 0 | #if SIMDUTF_CPLUSPLUS23 |
3458 | 0 | } // if ! consteval |
3459 | 0 | #endif |
3460 | 0 | if ((utf32_char & 0xFFFFFF00) == 0) { |
3461 | 0 | *latin1_output++ = char(utf32_char); |
3462 | 0 | } else { |
3463 | 0 | // output can not be represented in latin1 |
3464 | 0 | return 0; |
3465 | 0 | } |
3466 | 0 | pos++; |
3467 | 0 | } |
3468 | 0 | return latin1_output - start; |
3469 | 0 | } Unexecuted instantiation: parser.cpp:unsigned long simdutf::scalar::(anonymous namespace)::utf32_to_latin1::convert_valid<unsigned int const*, char*>(unsigned int const*, unsigned long, char*) Unexecuted instantiation: base64.cpp:unsigned long simdutf::scalar::(anonymous namespace)::utf32_to_latin1::convert_valid<unsigned int const*, char*>(unsigned int const*, unsigned long, char*) Unexecuted instantiation: simdutf.cpp:unsigned long simdutf::scalar::(anonymous namespace)::utf32_to_latin1::convert_valid<unsigned int const*, char*>(unsigned int const*, unsigned long, char*) |
3470 | | |
3471 | | simdutf_really_inline size_t convert_valid(const char32_t *buf, size_t len, |
3472 | 0 | char *latin1_output) { |
3473 | 0 | return convert_valid(reinterpret_cast<const uint32_t *>(buf), len, |
3474 | 0 | latin1_output); |
3475 | 0 | } Unexecuted instantiation: parser.cpp:simdutf::scalar::(anonymous namespace)::utf32_to_latin1::convert_valid(char32_t const*, unsigned long, char*) Unexecuted instantiation: base64.cpp:simdutf::scalar::(anonymous namespace)::utf32_to_latin1::convert_valid(char32_t const*, unsigned long, char*) Unexecuted instantiation: simdutf.cpp:simdutf::scalar::(anonymous namespace)::utf32_to_latin1::convert_valid(char32_t const*, unsigned long, char*) |
3476 | | |
3477 | | } // namespace utf32_to_latin1 |
3478 | | } // unnamed namespace |
3479 | | } // namespace scalar |
3480 | | } // namespace simdutf |
3481 | | |
3482 | | #endif |
3483 | | /* end file include/simdutf/scalar/utf32_to_latin1/valid_utf32_to_latin1.h */ |
3484 | | /* begin file include/simdutf/scalar/utf32_to_utf16/utf32_to_utf16.h */ |
3485 | | #ifndef SIMDUTF_UTF32_TO_UTF16_H |
3486 | | #define SIMDUTF_UTF32_TO_UTF16_H |
3487 | | |
3488 | | namespace simdutf { |
3489 | | namespace scalar { |
3490 | | namespace { |
3491 | | namespace utf32_to_utf16 { |
3492 | | |
3493 | | template <endianness big_endian> |
3494 | | simdutf_constexpr23 size_t convert(const char32_t *data, size_t len, |
3495 | | char16_t *utf16_output) { |
3496 | | size_t pos = 0; |
3497 | | char16_t *start{utf16_output}; |
3498 | | while (pos < len) { |
3499 | | uint32_t word = data[pos]; |
3500 | | if ((word & 0xFFFF0000) == 0) { |
3501 | | if (word >= 0xD800 && word <= 0xDFFF) { |
3502 | | return 0; |
3503 | | } |
3504 | | // will not generate a surrogate pair |
3505 | | *utf16_output++ = !match_system(big_endian) |
3506 | | ? char16_t(u16_swap_bytes(uint16_t(word))) |
3507 | | : char16_t(word); |
3508 | | } else { |
3509 | | // will generate a surrogate pair |
3510 | | if (word > 0x10FFFF) { |
3511 | | return 0; |
3512 | | } |
3513 | | word -= 0x10000; |
3514 | | uint16_t high_surrogate = uint16_t(0xD800 + (word >> 10)); |
3515 | | uint16_t low_surrogate = uint16_t(0xDC00 + (word & 0x3FF)); |
3516 | | if constexpr (!match_system(big_endian)) { |
3517 | | high_surrogate = u16_swap_bytes(high_surrogate); |
3518 | | low_surrogate = u16_swap_bytes(low_surrogate); |
3519 | | } |
3520 | | *utf16_output++ = char16_t(high_surrogate); |
3521 | | *utf16_output++ = char16_t(low_surrogate); |
3522 | | } |
3523 | | pos++; |
3524 | | } |
3525 | | return utf16_output - start; |
3526 | | } |
3527 | | |
3528 | | template <endianness big_endian> |
3529 | | simdutf_constexpr23 result convert_with_errors(const char32_t *data, size_t len, |
3530 | | char16_t *utf16_output) { |
3531 | | size_t pos = 0; |
3532 | | char16_t *start{utf16_output}; |
3533 | | while (pos < len) { |
3534 | | uint32_t word = data[pos]; |
3535 | | if ((word & 0xFFFF0000) == 0) { |
3536 | | if (word >= 0xD800 && word <= 0xDFFF) { |
3537 | | return result(error_code::SURROGATE, pos); |
3538 | | } |
3539 | | // will not generate a surrogate pair |
3540 | | *utf16_output++ = !match_system(big_endian) |
3541 | | ? char16_t(u16_swap_bytes(uint16_t(word))) |
3542 | | : char16_t(word); |
3543 | | } else { |
3544 | | // will generate a surrogate pair |
3545 | | if (word > 0x10FFFF) { |
3546 | | return result(error_code::TOO_LARGE, pos); |
3547 | | } |
3548 | | word -= 0x10000; |
3549 | | uint16_t high_surrogate = uint16_t(0xD800 + (word >> 10)); |
3550 | | uint16_t low_surrogate = uint16_t(0xDC00 + (word & 0x3FF)); |
3551 | | if constexpr (!match_system(big_endian)) { |
3552 | | high_surrogate = u16_swap_bytes(high_surrogate); |
3553 | | low_surrogate = u16_swap_bytes(low_surrogate); |
3554 | | } |
3555 | | *utf16_output++ = char16_t(high_surrogate); |
3556 | | *utf16_output++ = char16_t(low_surrogate); |
3557 | | } |
3558 | | pos++; |
3559 | | } |
3560 | | return result(error_code::SUCCESS, utf16_output - start); |
3561 | | } |
3562 | | |
3563 | | } // namespace utf32_to_utf16 |
3564 | | } // unnamed namespace |
3565 | | } // namespace scalar |
3566 | | } // namespace simdutf |
3567 | | |
3568 | | #endif |
3569 | | /* end file include/simdutf/scalar/utf32_to_utf16/utf32_to_utf16.h */ |
3570 | | /* begin file include/simdutf/scalar/utf32_to_utf16/valid_utf32_to_utf16.h */ |
3571 | | #ifndef SIMDUTF_VALID_UTF32_TO_UTF16_H |
3572 | | #define SIMDUTF_VALID_UTF32_TO_UTF16_H |
3573 | | |
3574 | | namespace simdutf { |
3575 | | namespace scalar { |
3576 | | namespace { |
3577 | | namespace utf32_to_utf16 { |
3578 | | |
3579 | | template <endianness big_endian> |
3580 | | simdutf_constexpr23 size_t convert_valid(const char32_t *data, size_t len, |
3581 | | char16_t *utf16_output) { |
3582 | | size_t pos = 0; |
3583 | | char16_t *start{utf16_output}; |
3584 | | while (pos < len) { |
3585 | | uint32_t word = data[pos]; |
3586 | | if ((word & 0xFFFF0000) == 0) { |
3587 | | // will not generate a surrogate pair |
3588 | | *utf16_output++ = !match_system(big_endian) |
3589 | | ? char16_t(u16_swap_bytes(uint16_t(word))) |
3590 | | : char16_t(word); |
3591 | | pos++; |
3592 | | } else { |
3593 | | // will generate a surrogate pair |
3594 | | word -= 0x10000; |
3595 | | uint16_t high_surrogate = uint16_t(0xD800 + (word >> 10)); |
3596 | | uint16_t low_surrogate = uint16_t(0xDC00 + (word & 0x3FF)); |
3597 | | if constexpr (!match_system(big_endian)) { |
3598 | | high_surrogate = u16_swap_bytes(high_surrogate); |
3599 | | low_surrogate = u16_swap_bytes(low_surrogate); |
3600 | | } |
3601 | | *utf16_output++ = char16_t(high_surrogate); |
3602 | | *utf16_output++ = char16_t(low_surrogate); |
3603 | | pos++; |
3604 | | } |
3605 | | } |
3606 | | return utf16_output - start; |
3607 | | } |
3608 | | |
3609 | | } // namespace utf32_to_utf16 |
3610 | | } // unnamed namespace |
3611 | | } // namespace scalar |
3612 | | } // namespace simdutf |
3613 | | |
3614 | | #endif |
3615 | | /* end file include/simdutf/scalar/utf32_to_utf16/valid_utf32_to_utf16.h */ |
3616 | | /* begin file include/simdutf/scalar/utf32_to_utf8/utf32_to_utf8.h */ |
3617 | | #ifndef SIMDUTF_UTF32_TO_UTF8_H |
3618 | | #define SIMDUTF_UTF32_TO_UTF8_H |
3619 | | |
3620 | | #include <cstring> |
3621 | | |
3622 | | namespace simdutf { |
3623 | | namespace scalar { |
3624 | | namespace { |
3625 | | namespace utf32_to_utf8 { |
3626 | | |
3627 | | template <typename InputPtr, typename OutputPtr> |
3628 | | #if SIMDUTF_CPLUSPLUS20 |
3629 | | requires(simdutf::detail::indexes_into_utf32<InputPtr> && |
3630 | | simdutf::detail::index_assignable_from_char<OutputPtr>) |
3631 | | #endif |
3632 | | simdutf_constexpr23 size_t convert(InputPtr data, size_t len, |
3633 | | OutputPtr utf8_output) { |
3634 | | size_t pos = 0; |
3635 | | auto start = utf8_output; |
3636 | | while (pos < len) { |
3637 | | #if SIMDUTF_CPLUSPLUS23 |
3638 | | if !consteval |
3639 | | #endif |
3640 | | { // try to convert the next block of 2 ASCII characters |
3641 | | if (pos + 2 <= len) { // if it is safe to read 8 more bytes, check that |
3642 | | // they are ascii |
3643 | | uint64_t v; |
3644 | | ::memcpy(&v, data + pos, sizeof(uint64_t)); |
3645 | | if ((v & 0xFFFFFF80FFFFFF80) == 0) { |
3646 | | *utf8_output++ = char(data[pos]); |
3647 | | *utf8_output++ = char(data[pos + 1]); |
3648 | | pos += 2; |
3649 | | continue; |
3650 | | } |
3651 | | } |
3652 | | } |
3653 | | |
3654 | | uint32_t word = data[pos]; |
3655 | | if ((word & 0xFFFFFF80) == 0) { |
3656 | | // will generate one UTF-8 bytes |
3657 | | *utf8_output++ = char(word); |
3658 | | pos++; |
3659 | | } else if ((word & 0xFFFFF800) == 0) { |
3660 | | // will generate two UTF-8 bytes |
3661 | | // we have 0b110XXXXX 0b10XXXXXX |
3662 | | *utf8_output++ = char((word >> 6) | 0b11000000); |
3663 | | *utf8_output++ = char((word & 0b111111) | 0b10000000); |
3664 | | pos++; |
3665 | | } else if ((word & 0xFFFF0000) == 0) { |
3666 | | // will generate three UTF-8 bytes |
3667 | | // we have 0b1110XXXX 0b10XXXXXX 0b10XXXXXX |
3668 | | if (word >= 0xD800 && word <= 0xDFFF) { |
3669 | | return 0; |
3670 | | } |
3671 | | *utf8_output++ = char((word >> 12) | 0b11100000); |
3672 | | *utf8_output++ = char(((word >> 6) & 0b111111) | 0b10000000); |
3673 | | *utf8_output++ = char((word & 0b111111) | 0b10000000); |
3674 | | pos++; |
3675 | | } else { |
3676 | | // will generate four UTF-8 bytes |
3677 | | // we have 0b11110XXX 0b10XXXXXX 0b10XXXXXX 0b10XXXXXX |
3678 | | if (word > 0x10FFFF) { |
3679 | | return 0; |
3680 | | } |
3681 | | *utf8_output++ = char((word >> 18) | 0b11110000); |
3682 | | *utf8_output++ = char(((word >> 12) & 0b111111) | 0b10000000); |
3683 | | *utf8_output++ = char(((word >> 6) & 0b111111) | 0b10000000); |
3684 | | *utf8_output++ = char((word & 0b111111) | 0b10000000); |
3685 | | pos++; |
3686 | | } |
3687 | | } |
3688 | | return utf8_output - start; |
3689 | | } |
3690 | | |
3691 | | template <typename InputPtr, typename OutputPtr> |
3692 | | #if SIMDUTF_CPLUSPLUS20 |
3693 | | requires(simdutf::detail::indexes_into_utf32<InputPtr> && |
3694 | | simdutf::detail::index_assignable_from_char<OutputPtr>) |
3695 | | #endif |
3696 | | simdutf_constexpr23 result convert_with_errors(InputPtr data, size_t len, |
3697 | | OutputPtr utf8_output) { |
3698 | | size_t pos = 0; |
3699 | | auto start = utf8_output; |
3700 | | while (pos < len) { |
3701 | | #if SIMDUTF_CPLUSPLUS23 |
3702 | | if !consteval |
3703 | | #endif |
3704 | | { // try to convert the next block of 2 ASCII characters |
3705 | | if (pos + 2 <= len) { // if it is safe to read 8 more bytes, check that |
3706 | | // they are ascii |
3707 | | uint64_t v; |
3708 | | ::memcpy(&v, data + pos, sizeof(uint64_t)); |
3709 | | if ((v & 0xFFFFFF80FFFFFF80) == 0) { |
3710 | | *utf8_output++ = char(data[pos]); |
3711 | | *utf8_output++ = char(data[pos + 1]); |
3712 | | pos += 2; |
3713 | | continue; |
3714 | | } |
3715 | | } |
3716 | | } |
3717 | | |
3718 | | uint32_t word = data[pos]; |
3719 | | if ((word & 0xFFFFFF80) == 0) { |
3720 | | // will generate one UTF-8 bytes |
3721 | | *utf8_output++ = char(word); |
3722 | | pos++; |
3723 | | } else if ((word & 0xFFFFF800) == 0) { |
3724 | | // will generate two UTF-8 bytes |
3725 | | // we have 0b110XXXXX 0b10XXXXXX |
3726 | | *utf8_output++ = char((word >> 6) | 0b11000000); |
3727 | | *utf8_output++ = char((word & 0b111111) | 0b10000000); |
3728 | | pos++; |
3729 | | } else if ((word & 0xFFFF0000) == 0) { |
3730 | | // will generate three UTF-8 bytes |
3731 | | // we have 0b1110XXXX 0b10XXXXXX 0b10XXXXXX |
3732 | | if (word >= 0xD800 && word <= 0xDFFF) { |
3733 | | return result(error_code::SURROGATE, pos); |
3734 | | } |
3735 | | *utf8_output++ = char((word >> 12) | 0b11100000); |
3736 | | *utf8_output++ = char(((word >> 6) & 0b111111) | 0b10000000); |
3737 | | *utf8_output++ = char((word & 0b111111) | 0b10000000); |
3738 | | pos++; |
3739 | | } else { |
3740 | | // will generate four UTF-8 bytes |
3741 | | // we have 0b11110XXX 0b10XXXXXX 0b10XXXXXX 0b10XXXXXX |
3742 | | if (word > 0x10FFFF) { |
3743 | | return result(error_code::TOO_LARGE, pos); |
3744 | | } |
3745 | | *utf8_output++ = char((word >> 18) | 0b11110000); |
3746 | | *utf8_output++ = char(((word >> 12) & 0b111111) | 0b10000000); |
3747 | | *utf8_output++ = char(((word >> 6) & 0b111111) | 0b10000000); |
3748 | | *utf8_output++ = char((word & 0b111111) | 0b10000000); |
3749 | | pos++; |
3750 | | } |
3751 | | } |
3752 | | return result(error_code::SUCCESS, utf8_output - start); |
3753 | | } |
3754 | | |
3755 | | } // namespace utf32_to_utf8 |
3756 | | } // unnamed namespace |
3757 | | } // namespace scalar |
3758 | | } // namespace simdutf |
3759 | | |
3760 | | #endif |
3761 | | /* end file include/simdutf/scalar/utf32_to_utf8/utf32_to_utf8.h */ |
3762 | | /* begin file include/simdutf/scalar/utf32_to_utf8/valid_utf32_to_utf8.h */ |
3763 | | #ifndef SIMDUTF_VALID_UTF32_TO_UTF8_H |
3764 | | #define SIMDUTF_VALID_UTF32_TO_UTF8_H |
3765 | | |
3766 | | #include <cstring> |
3767 | | |
3768 | | namespace simdutf { |
3769 | | namespace scalar { |
3770 | | namespace { |
3771 | | namespace utf32_to_utf8 { |
3772 | | |
3773 | | template <typename InputPtr, typename OutputPtr> |
3774 | | #if SIMDUTF_CPLUSPLUS20 |
3775 | | requires(simdutf::detail::indexes_into_utf32<InputPtr> && |
3776 | | simdutf::detail::index_assignable_from_char<OutputPtr>) |
3777 | | #endif |
3778 | | simdutf_constexpr23 size_t convert_valid(InputPtr data, size_t len, |
3779 | | OutputPtr utf8_output) { |
3780 | | size_t pos = 0; |
3781 | | auto start = utf8_output; |
3782 | | while (pos < len) { |
3783 | | #if SIMDUTF_CPLUSPLUS23 |
3784 | | if !consteval |
3785 | | #endif |
3786 | | { // try to convert the next block of 2 ASCII characters |
3787 | | if (pos + 2 <= len) { // if it is safe to read 8 more bytes, check that |
3788 | | // they are ascii |
3789 | | uint64_t v; |
3790 | | ::memcpy(&v, data + pos, sizeof(uint64_t)); |
3791 | | if ((v & 0xFFFFFF80FFFFFF80) == 0) { |
3792 | | *utf8_output++ = char(data[pos]); |
3793 | | *utf8_output++ = char(data[pos + 1]); |
3794 | | pos += 2; |
3795 | | continue; |
3796 | | } |
3797 | | } |
3798 | | } |
3799 | | |
3800 | | uint32_t word = data[pos]; |
3801 | | if ((word & 0xFFFFFF80) == 0) { |
3802 | | // will generate one UTF-8 bytes |
3803 | | *utf8_output++ = char(word); |
3804 | | pos++; |
3805 | | } else if ((word & 0xFFFFF800) == 0) { |
3806 | | // will generate two UTF-8 bytes |
3807 | | // we have 0b110XXXXX 0b10XXXXXX |
3808 | | *utf8_output++ = char((word >> 6) | 0b11000000); |
3809 | | *utf8_output++ = char((word & 0b111111) | 0b10000000); |
3810 | | pos++; |
3811 | | } else if ((word & 0xFFFF0000) == 0) { |
3812 | | // will generate three UTF-8 bytes |
3813 | | // we have 0b1110XXXX 0b10XXXXXX 0b10XXXXXX |
3814 | | *utf8_output++ = char((word >> 12) | 0b11100000); |
3815 | | *utf8_output++ = char(((word >> 6) & 0b111111) | 0b10000000); |
3816 | | *utf8_output++ = char((word & 0b111111) | 0b10000000); |
3817 | | pos++; |
3818 | | } else { |
3819 | | // will generate four UTF-8 bytes |
3820 | | // we have 0b11110XXX 0b10XXXXXX 0b10XXXXXX 0b10XXXXXX |
3821 | | *utf8_output++ = char((word >> 18) | 0b11110000); |
3822 | | *utf8_output++ = char(((word >> 12) & 0b111111) | 0b10000000); |
3823 | | *utf8_output++ = char(((word >> 6) & 0b111111) | 0b10000000); |
3824 | | *utf8_output++ = char((word & 0b111111) | 0b10000000); |
3825 | | pos++; |
3826 | | } |
3827 | | } |
3828 | | return utf8_output - start; |
3829 | | } |
3830 | | |
3831 | | } // namespace utf32_to_utf8 |
3832 | | } // unnamed namespace |
3833 | | } // namespace scalar |
3834 | | } // namespace simdutf |
3835 | | |
3836 | | #endif |
3837 | | /* end file include/simdutf/scalar/utf32_to_utf8/valid_utf32_to_utf8.h */ |
3838 | | /* begin file include/simdutf/scalar/utf8.h */ |
3839 | | #ifndef SIMDUTF_UTF8_H |
3840 | | #define SIMDUTF_UTF8_H |
3841 | | |
3842 | | #include <cstring> |
3843 | | |
3844 | | namespace simdutf { |
3845 | | namespace scalar { |
3846 | | namespace { |
3847 | | namespace utf8 { |
3848 | | |
3849 | | // credit: based on code from Google Fuchsia (Apache Licensed) |
3850 | | template <class BytePtr> |
3851 | | simdutf_constexpr23 simdutf_warn_unused bool validate(BytePtr data, |
3852 | 0 | size_t len) noexcept { |
3853 | 0 | static_assert( |
3854 | 0 | std::is_same<typename std::decay<decltype(*data)>::type, uint8_t>::value, |
3855 | 0 | "dereferencing the data pointer must result in a uint8_t"); |
3856 | 0 | uint64_t pos = 0; |
3857 | 0 | uint32_t code_point = 0; |
3858 | 0 | while (pos < len) { |
3859 | 0 | uint64_t next_pos; |
3860 | 0 | #if SIMDUTF_CPLUSPLUS23 |
3861 | 0 | if !consteval |
3862 | 0 | #endif |
3863 | 0 | { // check if the next 16 bytes are ascii. |
3864 | 0 | next_pos = pos + 16; |
3865 | 0 | if (next_pos <= len) { // if it is safe to read 16 more bytes, check |
3866 | 0 | // that they are ascii |
3867 | 0 | uint64_t v1{}; |
3868 | 0 | std::memcpy(&v1, data + pos, sizeof(uint64_t)); |
3869 | 0 | uint64_t v2{}; |
3870 | 0 | std::memcpy(&v2, data + pos + sizeof(uint64_t), sizeof(uint64_t)); |
3871 | 0 | uint64_t v{v1 | v2}; |
3872 | 0 | if ((v & 0x8080808080808080) == 0) { |
3873 | 0 | pos = next_pos; |
3874 | 0 | continue; |
3875 | 0 | } |
3876 | 0 | } |
3877 | 0 | } |
3878 | 0 |
|
3879 | 0 | unsigned char byte = data[pos]; |
3880 | 0 |
|
3881 | 0 | while (byte < 0b10000000) { |
3882 | 0 | if (++pos == len) { |
3883 | 0 | return true; |
3884 | 0 | } |
3885 | 0 | byte = data[pos]; |
3886 | 0 | } |
3887 | 0 |
|
3888 | 0 | if ((byte & 0b11100000) == 0b11000000) { |
3889 | 0 | next_pos = pos + 2; |
3890 | 0 | if (next_pos > len) { |
3891 | 0 | return false; |
3892 | 0 | } |
3893 | 0 | if ((data[pos + 1] & 0b11000000) != 0b10000000) { |
3894 | 0 | return false; |
3895 | 0 | } |
3896 | 0 | // range check |
3897 | 0 | code_point = (byte & 0b00011111) << 6 | (data[pos + 1] & 0b00111111); |
3898 | 0 | if (code_point < 0x80) { |
3899 | 0 | return false; |
3900 | 0 | } |
3901 | 0 | } else if ((byte & 0b11110000) == 0b11100000) { |
3902 | 0 | next_pos = pos + 3; |
3903 | 0 | if (next_pos > len) { |
3904 | 0 | return false; |
3905 | 0 | } |
3906 | 0 | if ((data[pos + 1] & 0b11000000) != 0b10000000) { |
3907 | 0 | return false; |
3908 | 0 | } |
3909 | 0 | if ((data[pos + 2] & 0b11000000) != 0b10000000) { |
3910 | 0 | return false; |
3911 | 0 | } |
3912 | 0 | // range check |
3913 | 0 | code_point = (byte & 0b00001111) << 12 | |
3914 | 0 | (data[pos + 1] & 0b00111111) << 6 | |
3915 | 0 | (data[pos + 2] & 0b00111111); |
3916 | 0 | if ((code_point < 0x800) || |
3917 | 0 | (0xd7ff < code_point && code_point < 0xe000)) { |
3918 | 0 | return false; |
3919 | 0 | } |
3920 | 0 | } else if ((byte & 0b11111000) == 0b11110000) { // 0b11110000 |
3921 | 0 | next_pos = pos + 4; |
3922 | 0 | if (next_pos > len) { |
3923 | 0 | return false; |
3924 | 0 | } |
3925 | 0 | if ((data[pos + 1] & 0b11000000) != 0b10000000) { |
3926 | 0 | return false; |
3927 | 0 | } |
3928 | 0 | if ((data[pos + 2] & 0b11000000) != 0b10000000) { |
3929 | 0 | return false; |
3930 | 0 | } |
3931 | 0 | if ((data[pos + 3] & 0b11000000) != 0b10000000) { |
3932 | 0 | return false; |
3933 | 0 | } |
3934 | 0 | // range check |
3935 | 0 | code_point = |
3936 | 0 | (byte & 0b00000111) << 18 | (data[pos + 1] & 0b00111111) << 12 | |
3937 | 0 | (data[pos + 2] & 0b00111111) << 6 | (data[pos + 3] & 0b00111111); |
3938 | 0 | if (code_point <= 0xffff || 0x10ffff < code_point) { |
3939 | 0 | return false; |
3940 | 0 | } |
3941 | 0 | } else { |
3942 | 0 | // we may have a continuation |
3943 | 0 | return false; |
3944 | 0 | } |
3945 | 0 | pos = next_pos; |
3946 | 0 | } |
3947 | 0 | return true; |
3948 | 0 | } Unexecuted instantiation: parser.cpp:bool simdutf::scalar::(anonymous namespace)::utf8::validate<unsigned char const*>(unsigned char const*, unsigned long) Unexecuted instantiation: base64.cpp:bool simdutf::scalar::(anonymous namespace)::utf8::validate<unsigned char const*>(unsigned char const*, unsigned long) Unexecuted instantiation: simdutf.cpp:bool simdutf::scalar::(anonymous namespace)::utf8::validate<unsigned char const*>(unsigned char const*, unsigned long) |
3949 | | |
3950 | | simdutf_really_inline simdutf_warn_unused bool validate(const char *buf, |
3951 | 0 | size_t len) noexcept { |
3952 | 0 | return validate(reinterpret_cast<const uint8_t *>(buf), len); |
3953 | 0 | } Unexecuted instantiation: parser.cpp:simdutf::scalar::(anonymous namespace)::utf8::validate(char const*, unsigned long) Unexecuted instantiation: base64.cpp:simdutf::scalar::(anonymous namespace)::utf8::validate(char const*, unsigned long) Unexecuted instantiation: simdutf.cpp:simdutf::scalar::(anonymous namespace)::utf8::validate(char const*, unsigned long) |
3954 | | |
3955 | | template <class BytePtr> |
3956 | | simdutf_constexpr23 simdutf_warn_unused result |
3957 | 0 | validate_with_errors(BytePtr data, size_t len) noexcept { |
3958 | 0 | static_assert( |
3959 | 0 | std::is_same<typename std::decay<decltype(*data)>::type, uint8_t>::value, |
3960 | 0 | "dereferencing the data pointer must result in a uint8_t"); |
3961 | 0 | size_t pos = 0; |
3962 | 0 | uint32_t code_point = 0; |
3963 | 0 | while (pos < len) { |
3964 | 0 | // check of the next 16 bytes are ascii. |
3965 | 0 | size_t next_pos = pos + 16; |
3966 | 0 | if (next_pos <= |
3967 | 0 | len) { // if it is safe to read 16 more bytes, check that they are ascii |
3968 | 0 | uint64_t v1; |
3969 | 0 | std::memcpy(&v1, data + pos, sizeof(uint64_t)); |
3970 | 0 | uint64_t v2; |
3971 | 0 | std::memcpy(&v2, data + pos + sizeof(uint64_t), sizeof(uint64_t)); |
3972 | 0 | uint64_t v{v1 | v2}; |
3973 | 0 | if ((v & 0x8080808080808080) == 0) { |
3974 | 0 | pos = next_pos; |
3975 | 0 | continue; |
3976 | 0 | } |
3977 | 0 | } |
3978 | 0 | unsigned char byte = data[pos]; |
3979 | 0 |
|
3980 | 0 | while (byte < 0b10000000) { |
3981 | 0 | if (++pos == len) { |
3982 | 0 | return result(error_code::SUCCESS, len); |
3983 | 0 | } |
3984 | 0 | byte = data[pos]; |
3985 | 0 | } |
3986 | 0 |
|
3987 | 0 | if ((byte & 0b11100000) == 0b11000000) { |
3988 | 0 | next_pos = pos + 2; |
3989 | 0 | if (next_pos > len) { |
3990 | 0 | return result(error_code::TOO_SHORT, pos); |
3991 | 0 | } |
3992 | 0 | if ((data[pos + 1] & 0b11000000) != 0b10000000) { |
3993 | 0 | return result(error_code::TOO_SHORT, pos); |
3994 | 0 | } |
3995 | 0 | // range check |
3996 | 0 | code_point = (byte & 0b00011111) << 6 | (data[pos + 1] & 0b00111111); |
3997 | 0 | if (code_point < 0x80) { |
3998 | 0 | return result(error_code::OVERLONG, pos); |
3999 | 0 | } |
4000 | 0 | } else if ((byte & 0b11110000) == 0b11100000) { |
4001 | 0 | next_pos = pos + 3; |
4002 | 0 | if (next_pos > len) { |
4003 | 0 | return result(error_code::TOO_SHORT, pos); |
4004 | 0 | } |
4005 | 0 | if ((data[pos + 1] & 0b11000000) != 0b10000000) { |
4006 | 0 | return result(error_code::TOO_SHORT, pos); |
4007 | 0 | } |
4008 | 0 | if ((data[pos + 2] & 0b11000000) != 0b10000000) { |
4009 | 0 | return result(error_code::TOO_SHORT, pos); |
4010 | 0 | } |
4011 | 0 | // range check |
4012 | 0 | code_point = (byte & 0b00001111) << 12 | |
4013 | 0 | (data[pos + 1] & 0b00111111) << 6 | |
4014 | 0 | (data[pos + 2] & 0b00111111); |
4015 | 0 | if (code_point < 0x800) { |
4016 | 0 | return result(error_code::OVERLONG, pos); |
4017 | 0 | } |
4018 | 0 | if (0xd7ff < code_point && code_point < 0xe000) { |
4019 | 0 | return result(error_code::SURROGATE, pos); |
4020 | 0 | } |
4021 | 0 | } else if ((byte & 0b11111000) == 0b11110000) { // 0b11110000 |
4022 | 0 | next_pos = pos + 4; |
4023 | 0 | if (next_pos > len) { |
4024 | 0 | return result(error_code::TOO_SHORT, pos); |
4025 | 0 | } |
4026 | 0 | if ((data[pos + 1] & 0b11000000) != 0b10000000) { |
4027 | 0 | return result(error_code::TOO_SHORT, pos); |
4028 | 0 | } |
4029 | 0 | if ((data[pos + 2] & 0b11000000) != 0b10000000) { |
4030 | 0 | return result(error_code::TOO_SHORT, pos); |
4031 | 0 | } |
4032 | 0 | if ((data[pos + 3] & 0b11000000) != 0b10000000) { |
4033 | 0 | return result(error_code::TOO_SHORT, pos); |
4034 | 0 | } |
4035 | 0 | // range check |
4036 | 0 | code_point = |
4037 | 0 | (byte & 0b00000111) << 18 | (data[pos + 1] & 0b00111111) << 12 | |
4038 | 0 | (data[pos + 2] & 0b00111111) << 6 | (data[pos + 3] & 0b00111111); |
4039 | 0 | if (code_point <= 0xffff) { |
4040 | 0 | return result(error_code::OVERLONG, pos); |
4041 | 0 | } |
4042 | 0 | if (0x10ffff < code_point) { |
4043 | 0 | return result(error_code::TOO_LARGE, pos); |
4044 | 0 | } |
4045 | 0 | } else { |
4046 | 0 | // we either have too many continuation bytes or an invalid leading byte |
4047 | 0 | if ((byte & 0b11000000) == 0b10000000) { |
4048 | 0 | return result(error_code::TOO_LONG, pos); |
4049 | 0 | } else { |
4050 | 0 | return result(error_code::HEADER_BITS, pos); |
4051 | 0 | } |
4052 | 0 | } |
4053 | 0 | pos = next_pos; |
4054 | 0 | } |
4055 | 0 | return result(error_code::SUCCESS, len); |
4056 | 0 | } Unexecuted instantiation: parser.cpp:simdutf::result simdutf::scalar::(anonymous namespace)::utf8::validate_with_errors<unsigned char const*>(unsigned char const*, unsigned long) Unexecuted instantiation: base64.cpp:simdutf::result simdutf::scalar::(anonymous namespace)::utf8::validate_with_errors<unsigned char const*>(unsigned char const*, unsigned long) Unexecuted instantiation: simdutf.cpp:simdutf::result simdutf::scalar::(anonymous namespace)::utf8::validate_with_errors<unsigned char const*>(unsigned char const*, unsigned long) |
4057 | | |
4058 | | simdutf_really_inline simdutf_warn_unused result |
4059 | 0 | validate_with_errors(const char *buf, size_t len) noexcept { |
4060 | 0 | return validate_with_errors(reinterpret_cast<const uint8_t *>(buf), len); |
4061 | 0 | } Unexecuted instantiation: parser.cpp:simdutf::scalar::(anonymous namespace)::utf8::validate_with_errors(char const*, unsigned long) Unexecuted instantiation: base64.cpp:simdutf::scalar::(anonymous namespace)::utf8::validate_with_errors(char const*, unsigned long) Unexecuted instantiation: simdutf.cpp:simdutf::scalar::(anonymous namespace)::utf8::validate_with_errors(char const*, unsigned long) |
4062 | | |
4063 | | // Finds the previous leading byte starting backward from buf and validates with |
4064 | | // errors from there Used to pinpoint the location of an error when an invalid |
4065 | | // chunk is detected We assume that the stream starts with a leading byte, and |
4066 | | // to check that it is the case, we ask that you pass a pointer to the start of |
4067 | | // the stream (start). Note that the resulting count is underflowed if an error |
4068 | | // is encountered in the rewinded segment. |
4069 | | inline simdutf_warn_unused result rewind_and_validate_with_errors( |
4070 | 0 | const char *start, const char *buf, size_t len) noexcept { |
4071 | 0 | // First check that we start with a leading byte |
4072 | 0 | if ((*start & 0b11000000) == 0b10000000) { |
4073 | 0 | return result(error_code::TOO_LONG, 0); |
4074 | 0 | } |
4075 | 0 | size_t extra_len{0}; |
4076 | 0 | // A leading byte cannot be further than 4 bytes away |
4077 | 0 | for (int i = 0; i < 5; i++) { |
4078 | 0 | unsigned char byte = *buf; |
4079 | 0 | if ((byte & 0b11000000) != 0b10000000) { |
4080 | 0 | break; |
4081 | 0 | } else { |
4082 | 0 | buf--; |
4083 | 0 | extra_len++; |
4084 | 0 | } |
4085 | 0 | } |
4086 | 0 |
|
4087 | 0 | result res = validate_with_errors(buf, len + extra_len); |
4088 | 0 | res.count -= extra_len; // Might underflow |
4089 | 0 | return res; |
4090 | 0 | } Unexecuted instantiation: parser.cpp:simdutf::scalar::(anonymous namespace)::utf8::rewind_and_validate_with_errors(char const*, char const*, unsigned long) Unexecuted instantiation: base64.cpp:simdutf::scalar::(anonymous namespace)::utf8::rewind_and_validate_with_errors(char const*, char const*, unsigned long) Unexecuted instantiation: simdutf.cpp:simdutf::scalar::(anonymous namespace)::utf8::rewind_and_validate_with_errors(char const*, char const*, unsigned long) |
4091 | | |
4092 | | // credit: based on code from Google Fuchsia (Apache Licensed) |
4093 | | template <class BytePtr> |
4094 | | simdutf_constexpr23 simdutf_warn_unused utf8_result |
4095 | 0 | validate_with_counts(BytePtr data, size_t len) noexcept { |
4096 | 0 | static_assert( |
4097 | 0 | std::is_same<typename std::decay<decltype(*data)>::type, uint8_t>::value, |
4098 | 0 | "dereferencing the data pointer must result in a uint8_t"); |
4099 | 0 | size_t pos = 0; |
4100 | 0 | uint32_t code_point = 0; |
4101 | 0 | size_t continuations = 0; |
4102 | 0 | size_t four_byte = 0; |
4103 | 0 | while (pos < len) { |
4104 | 0 | // std::memcpy is not usable during constant evaluation, so the block-wise |
4105 | 0 | // ASCII fast path is restricted to run time, like in validate() above. |
4106 | 0 | #if SIMDUTF_CPLUSPLUS23 |
4107 | 0 | if !consteval |
4108 | 0 | #endif |
4109 | 0 | { // check if the next 16 bytes are ascii. |
4110 | 0 | const size_t next_ascii_pos = pos + 16; |
4111 | 0 | if (next_ascii_pos <= len) { // if it is safe to read 16 more bytes, check |
4112 | 0 | // that they are ascii |
4113 | 0 | uint64_t v1{}; |
4114 | 0 | std::memcpy(&v1, data + pos, sizeof(uint64_t)); |
4115 | 0 | uint64_t v2{}; |
4116 | 0 | std::memcpy(&v2, data + pos + sizeof(uint64_t), sizeof(uint64_t)); |
4117 | 0 | uint64_t v{v1 | v2}; |
4118 | 0 | if ((v & 0x8080808080808080) == 0) { |
4119 | 0 | pos = next_ascii_pos; |
4120 | 0 | continue; |
4121 | 0 | } |
4122 | 0 | } |
4123 | 0 | } |
4124 | 0 |
|
4125 | 0 | size_t next_pos; |
4126 | 0 | unsigned char byte = data[pos]; |
4127 | 0 |
|
4128 | 0 | while (byte < 0b10000000) { |
4129 | 0 | if (++pos == len) { |
4130 | 0 | return utf8_result(error_code::SUCCESS, pos, continuations, four_byte); |
4131 | 0 | } |
4132 | 0 | byte = data[pos]; |
4133 | 0 | } |
4134 | 0 |
|
4135 | 0 | if ((byte & 0b11100000) == 0b11000000) { |
4136 | 0 | next_pos = pos + 2; |
4137 | 0 | if (next_pos > len) { |
4138 | 0 | return utf8_result(error_code::TOO_SHORT, pos, continuations, |
4139 | 0 | four_byte); |
4140 | 0 | } |
4141 | 0 | if ((data[pos + 1] & 0b11000000) != 0b10000000) { |
4142 | 0 | return utf8_result(error_code::TOO_SHORT, pos, continuations, |
4143 | 0 | four_byte); |
4144 | 0 | } |
4145 | 0 | // range check |
4146 | 0 | code_point = (byte & 0b00011111) << 6 | (data[pos + 1] & 0b00111111); |
4147 | 0 | if (code_point < 0x80) { |
4148 | 0 | return utf8_result(error_code::OVERLONG, pos, continuations, four_byte); |
4149 | 0 | } |
4150 | 0 | continuations += 1; |
4151 | 0 | } else if ((byte & 0b11110000) == 0b11100000) { |
4152 | 0 | next_pos = pos + 3; |
4153 | 0 | if (next_pos > len) { |
4154 | 0 | return utf8_result(error_code::TOO_SHORT, pos, continuations, |
4155 | 0 | four_byte); |
4156 | 0 | } |
4157 | 0 | if ((data[pos + 1] & 0b11000000) != 0b10000000) { |
4158 | 0 | return utf8_result(error_code::TOO_SHORT, pos, continuations, |
4159 | 0 | four_byte); |
4160 | 0 | } |
4161 | 0 | if ((data[pos + 2] & 0b11000000) != 0b10000000) { |
4162 | 0 | return utf8_result(error_code::TOO_SHORT, pos, continuations, |
4163 | 0 | four_byte); |
4164 | 0 | } |
4165 | 0 | // range check |
4166 | 0 | code_point = (byte & 0b00001111) << 12 | |
4167 | 0 | (data[pos + 1] & 0b00111111) << 6 | |
4168 | 0 | (data[pos + 2] & 0b00111111); |
4169 | 0 | if (code_point < 0x800) { |
4170 | 0 | return utf8_result(error_code::OVERLONG, pos, continuations, four_byte); |
4171 | 0 | } else if (0xd7ff < code_point && code_point < 0xe000) { |
4172 | 0 | return utf8_result(error_code::SURROGATE, pos, continuations, |
4173 | 0 | four_byte); |
4174 | 0 | } |
4175 | 0 | continuations += 2; |
4176 | 0 | } else if ((byte & 0b11111000) == 0b11110000) { // 0b11110000 |
4177 | 0 | next_pos = pos + 4; |
4178 | 0 | if (next_pos > len) { |
4179 | 0 | return utf8_result(error_code::TOO_SHORT, pos, continuations, |
4180 | 0 | four_byte); |
4181 | 0 | } |
4182 | 0 | if ((data[pos + 1] & 0b11000000) != 0b10000000) { |
4183 | 0 | return utf8_result(error_code::TOO_SHORT, pos, continuations, |
4184 | 0 | four_byte); |
4185 | 0 | } |
4186 | 0 | if ((data[pos + 2] & 0b11000000) != 0b10000000) { |
4187 | 0 | return utf8_result(error_code::TOO_SHORT, pos, continuations, |
4188 | 0 | four_byte); |
4189 | 0 | } |
4190 | 0 | if ((data[pos + 3] & 0b11000000) != 0b10000000) { |
4191 | 0 | return utf8_result(error_code::TOO_SHORT, pos, continuations, |
4192 | 0 | four_byte); |
4193 | 0 | } |
4194 | 0 | // range check |
4195 | 0 | code_point = |
4196 | 0 | (byte & 0b00000111) << 18 | (data[pos + 1] & 0b00111111) << 12 | |
4197 | 0 | (data[pos + 2] & 0b00111111) << 6 | (data[pos + 3] & 0b00111111); |
4198 | 0 | if (code_point <= 0xffff) { |
4199 | 0 | return utf8_result(error_code::OVERLONG, pos, continuations, four_byte); |
4200 | 0 | } else if (0x10ffff < code_point) { |
4201 | 0 | return utf8_result(error_code::TOO_LARGE, pos, continuations, |
4202 | 0 | four_byte); |
4203 | 0 | } |
4204 | 0 | continuations += 3; |
4205 | 0 | four_byte += 1; |
4206 | 0 | } else { |
4207 | 0 | // Continuation byte or invalid header byte |
4208 | 0 | if ((byte & 0b11000000) == 0b10000000) { |
4209 | 0 | return utf8_result(error_code::TOO_LONG, pos, continuations, four_byte); |
4210 | 0 | } else { |
4211 | 0 | return utf8_result(error_code::HEADER_BITS, pos, continuations, |
4212 | 0 | four_byte); |
4213 | 0 | } |
4214 | 0 | } |
4215 | 0 | pos = next_pos; |
4216 | 0 | } |
4217 | 0 | return utf8_result(error_code::SUCCESS, pos, continuations, four_byte); |
4218 | 0 | } Unexecuted instantiation: parser.cpp:simdutf::utf8_result simdutf::scalar::(anonymous namespace)::utf8::validate_with_counts<unsigned char const*>(unsigned char const*, unsigned long) Unexecuted instantiation: base64.cpp:simdutf::utf8_result simdutf::scalar::(anonymous namespace)::utf8::validate_with_counts<unsigned char const*>(unsigned char const*, unsigned long) Unexecuted instantiation: simdutf.cpp:simdutf::utf8_result simdutf::scalar::(anonymous namespace)::utf8::validate_with_counts<unsigned char const*>(unsigned char const*, unsigned long) |
4219 | | |
4220 | | simdutf_really_inline simdutf_warn_unused utf8_result |
4221 | 0 | validate_with_counts(const char *buf, size_t len) noexcept { |
4222 | 0 | return validate_with_counts(reinterpret_cast<const uint8_t *>(buf), len); |
4223 | 0 | } Unexecuted instantiation: parser.cpp:simdutf::scalar::(anonymous namespace)::utf8::validate_with_counts(char const*, unsigned long) Unexecuted instantiation: base64.cpp:simdutf::scalar::(anonymous namespace)::utf8::validate_with_counts(char const*, unsigned long) Unexecuted instantiation: simdutf.cpp:simdutf::scalar::(anonymous namespace)::utf8::validate_with_counts(char const*, unsigned long) |
4224 | | |
4225 | | // Finds the previous leading byte starting backward from buf and validates from |
4226 | | // there on out while counting continuation bytes and 4-byte leads. Used to |
4227 | | // pinpoint the location of an error when an invalid chunk is detected. We check |
4228 | | // that the stream starts with a leading byte with the passed pointer to the |
4229 | | // start of the stream (start). |
4230 | | // |
4231 | | // All three fields of the result are relative to buf. The bytes we rewind over |
4232 | | // sit in a block the caller has already counted, so their contribution is |
4233 | | // subtracted back out at the end. When the error lies inside the rewound |
4234 | | // region, those three subtractions underflow. That is intended, not an |
4235 | | // oversight: the caller adds the offset of buf and the counts of the preceding |
4236 | | // blocks, which include the rewound bytes, and the unsigned wraparound cancels |
4237 | | // exactly, leaving the correct absolute values. |
4238 | | inline simdutf_warn_unused utf8_result rewind_and_validate_with_counts( |
4239 | 0 | const char *start, const char *buf, size_t len) noexcept { |
4240 | 0 | // First check that we start with a leading byte |
4241 | 0 | if ((*start & 0b11000000) == 0b10000000) { |
4242 | 0 | return utf8_result(error_code::TOO_LONG, 0, 0, 0); |
4243 | 0 | } |
4244 | 0 | // If this is the start of the buffer, we don't need to rewind to check the |
4245 | 0 | // previous chunk. |
4246 | 0 | if (start == buf) { |
4247 | 0 | return validate_with_counts(buf, len); |
4248 | 0 | } |
4249 | 0 | // As this isn't the start of the buffer, the error might be in the previous |
4250 | 0 | // chunk. So we backtrack and also need to avoid double counting. |
4251 | 0 | size_t extra_len{0}; |
4252 | 0 | size_t extra_continuations{0}; |
4253 | 0 | size_t extra_four_bytes{0}; |
4254 | 0 | // Four steps are enough. Everything before buf has already validated, so at |
4255 | 0 | // most three continuation bytes can precede it, from a four-byte sequence |
4256 | 0 | // ending exactly on the boundary; the fourth step then lands on its leading |
4257 | 0 | // byte. Note that the sibling rewind_and_validate_with_errors needs five |
4258 | 0 | // steps only because it tests the byte before stepping back, whereas we step |
4259 | 0 | // back first. Callers pass a block boundary at least 64 bytes into the |
4260 | 0 | // stream, so stepping back four bytes stays in bounds. |
4261 | 0 | for (int i = 0; i < 4; i++) { |
4262 | 0 | // We rewind at least one byte to find the actual previous leading byte. |
4263 | 0 | // We do so to backtrack into the last chunk in case the utf8 error happened |
4264 | 0 | // there already. |
4265 | 0 | buf--; |
4266 | 0 | unsigned char byte = *buf; |
4267 | 0 | extra_len++; |
4268 | 0 |
|
4269 | 0 | if (byte >= 0b10000000) { |
4270 | 0 | if (byte >= 0b11110000) { |
4271 | 0 | extra_four_bytes += 1; |
4272 | 0 | } else if ((int8_t)byte < -65 + 1) { |
4273 | 0 | extra_continuations += 1; |
4274 | 0 | } |
4275 | 0 | } |
4276 | 0 | if ((byte & 0b11000000) != 0b10000000) { |
4277 | 0 | break; |
4278 | 0 | } |
4279 | 0 | } |
4280 | 0 |
|
4281 | 0 | utf8_result res = validate_with_counts(buf, len + extra_len); |
4282 | 0 | res.input_count -= extra_len; |
4283 | 0 | res.continuation_count -= extra_continuations; |
4284 | 0 | res.four_byte_count -= extra_four_bytes; |
4285 | 0 | return res; |
4286 | 0 | } Unexecuted instantiation: parser.cpp:simdutf::scalar::(anonymous namespace)::utf8::rewind_and_validate_with_counts(char const*, char const*, unsigned long) Unexecuted instantiation: base64.cpp:simdutf::scalar::(anonymous namespace)::utf8::rewind_and_validate_with_counts(char const*, char const*, unsigned long) Unexecuted instantiation: simdutf.cpp:simdutf::scalar::(anonymous namespace)::utf8::rewind_and_validate_with_counts(char const*, char const*, unsigned long) |
4287 | | |
4288 | | template <typename InputPtr> |
4289 | | #if SIMDUTF_CPLUSPLUS20 |
4290 | | requires simdutf::detail::indexes_into_byte_like<InputPtr> |
4291 | | #endif |
4292 | | simdutf_constexpr23 size_t count_code_points(InputPtr data, size_t len) { |
4293 | | size_t counter{0}; |
4294 | | for (size_t i = 0; i < len; i++) { |
4295 | | // -65 is 0b10111111, anything larger in two-complement's should start a new |
4296 | | // code point. |
4297 | | if (int8_t(data[i]) > -65) { |
4298 | | counter++; |
4299 | | } |
4300 | | } |
4301 | | return counter; |
4302 | | } |
4303 | | |
4304 | | template <typename InputPtr> |
4305 | | #if SIMDUTF_CPLUSPLUS20 |
4306 | | requires simdutf::detail::indexes_into_byte_like<InputPtr> |
4307 | | #endif |
4308 | | simdutf_constexpr23 size_t utf16_length_from_utf8(InputPtr data, size_t len) { |
4309 | | size_t counter{0}; |
4310 | | for (size_t i = 0; i < len; i++) { |
4311 | | if (int8_t(data[i]) > -65) { |
4312 | | counter++; |
4313 | | } |
4314 | | if (uint8_t(data[i]) >= 240) { |
4315 | | counter++; |
4316 | | } |
4317 | | } |
4318 | | return counter; |
4319 | | } |
4320 | | |
4321 | | template <typename InputPtr> |
4322 | | #if SIMDUTF_CPLUSPLUS20 |
4323 | | requires simdutf::detail::indexes_into_byte_like<InputPtr> |
4324 | | #endif |
4325 | | simdutf_warn_unused simdutf_constexpr23 size_t |
4326 | | trim_partial_utf8(InputPtr input, size_t length) { |
4327 | | if (length < 3) { |
4328 | | switch (length) { |
4329 | | case 2: |
4330 | | if (uint8_t(input[length - 1]) >= 0xc0) { |
4331 | | return length - 1; |
4332 | | } // 2-, 3- and 4-byte characters with only 1 byte left |
4333 | | if (uint8_t(input[length - 2]) >= 0xe0) { |
4334 | | return length - 2; |
4335 | | } // 3- and 4-byte characters with only 2 bytes left |
4336 | | return length; |
4337 | | case 1: |
4338 | | if (uint8_t(input[length - 1]) >= 0xc0) { |
4339 | | return length - 1; |
4340 | | } // 2-, 3- and 4-byte characters with only 1 byte left |
4341 | | return length; |
4342 | | case 0: |
4343 | | return length; |
4344 | | } |
4345 | | } |
4346 | | if (uint8_t(input[length - 1]) >= 0xc0) { |
4347 | | return length - 1; |
4348 | | } // 2-, 3- and 4-byte characters with only 1 byte left |
4349 | | if (uint8_t(input[length - 2]) >= 0xe0) { |
4350 | | return length - 2; |
4351 | | } // 3- and 4-byte characters with only 1 byte left |
4352 | | if (uint8_t(input[length - 3]) >= 0xf0) { |
4353 | | return length - 3; |
4354 | | } // 4-byte characters with only 3 bytes left |
4355 | | return length; |
4356 | | } |
4357 | | |
4358 | | } // namespace utf8 |
4359 | | } // unnamed namespace |
4360 | | } // namespace scalar |
4361 | | } // namespace simdutf |
4362 | | |
4363 | | #endif |
4364 | | /* end file include/simdutf/scalar/utf8.h */ |
4365 | | /* begin file include/simdutf/scalar/utf8_to_latin1/utf8_to_latin1.h */ |
4366 | | #ifndef SIMDUTF_UTF8_TO_LATIN1_H |
4367 | | #define SIMDUTF_UTF8_TO_LATIN1_H |
4368 | | |
4369 | | #include <cstring> |
4370 | | |
4371 | | namespace simdutf { |
4372 | | namespace scalar { |
4373 | | namespace { |
4374 | | namespace utf8_to_latin1 { |
4375 | | |
4376 | | template <typename InputPtr, typename OutputPtr> |
4377 | | #if SIMDUTF_CPLUSPLUS20 |
4378 | | requires(simdutf::detail::indexes_into_byte_like<InputPtr> && |
4379 | | simdutf::detail::indexes_into_byte_like<OutputPtr>) |
4380 | | #endif |
4381 | | simdutf_constexpr23 size_t convert(InputPtr data, size_t len, |
4382 | | OutputPtr latin_output) { |
4383 | | size_t pos = 0; |
4384 | | auto start = latin_output; |
4385 | | |
4386 | | while (pos < len) { |
4387 | | #if SIMDUTF_CPLUSPLUS23 |
4388 | | if !consteval |
4389 | | #endif |
4390 | | { |
4391 | | // try to convert the next block of 16 ASCII bytes |
4392 | | if (pos + 16 <= len) { // if it is safe to read 16 more bytes, check that |
4393 | | // they are ascii |
4394 | | uint64_t v1; |
4395 | | ::memcpy(&v1, data + pos, sizeof(uint64_t)); |
4396 | | uint64_t v2; |
4397 | | ::memcpy(&v2, data + pos + sizeof(uint64_t), sizeof(uint64_t)); |
4398 | | uint64_t v{v1 | v2}; // We are only interested in these bits: 1000 1000 |
4399 | | // 1000 1000 .... etc |
4400 | | if ((v & 0x8080808080808080) == |
4401 | | 0) { // if NONE of these are set, e.g. all of them are zero, then |
4402 | | // everything is ASCII |
4403 | | size_t final_pos = pos + 16; |
4404 | | while (pos < final_pos) { |
4405 | | *latin_output++ = char(data[pos]); |
4406 | | pos++; |
4407 | | } |
4408 | | continue; |
4409 | | } |
4410 | | } |
4411 | | } |
4412 | | |
4413 | | // suppose it is not an all ASCII byte sequence |
4414 | | uint8_t leading_byte = data[pos]; // leading byte |
4415 | | if (leading_byte < 0b10000000) { |
4416 | | // converting one ASCII byte !!! |
4417 | | *latin_output++ = char(leading_byte); |
4418 | | pos++; |
4419 | | } else if ((leading_byte & 0b11100000) == |
4420 | | 0b11000000) { // the first three bits indicate: |
4421 | | // We have a two-byte UTF-8 |
4422 | | if (pos + 1 >= len) { |
4423 | | return 0; |
4424 | | } // minimal bound checking |
4425 | | if ((data[pos + 1] & 0b11000000) != 0b10000000) { |
4426 | | return 0; |
4427 | | } // checks if the next byte is a valid continuation byte in UTF-8. A |
4428 | | // valid continuation byte starts with 10. |
4429 | | // range check - |
4430 | | uint32_t code_point = |
4431 | | (leading_byte & 0b00011111) << 6 | |
4432 | | (data[pos + 1] & |
4433 | | 0b00111111); // assembles the Unicode code point from the two bytes. |
4434 | | // It does this by discarding the leading 110 and 10 |
4435 | | // bits from the two bytes, shifting the remaining bits |
4436 | | // of the first byte, and then combining the results |
4437 | | // with a bitwise OR operation. |
4438 | | if (code_point < 0x80 || 0xFF < code_point) { |
4439 | | return 0; // We only care about the range 129-255 which is Non-ASCII |
4440 | | // latin1 characters. A code_point beneath 0x80 is invalid as |
4441 | | // it is already covered by bytes whose leading bit is zero. |
4442 | | } |
4443 | | *latin_output++ = char(code_point); |
4444 | | pos += 2; |
4445 | | } else { |
4446 | | return 0; |
4447 | | } |
4448 | | } |
4449 | | return latin_output - start; |
4450 | | } |
4451 | | |
4452 | | template <typename InputPtr> |
4453 | | #if SIMDUTF_CPLUSPLUS20 |
4454 | | requires simdutf::detail::indexes_into_byte_like<InputPtr> |
4455 | | #endif |
4456 | | simdutf_constexpr23 result convert_with_errors(InputPtr data, size_t len, |
4457 | 0 | char *latin_output) { |
4458 | 0 | size_t pos = 0; |
4459 | 0 | char *start{latin_output}; |
4460 | 0 |
|
4461 | 0 | while (pos < len) { |
4462 | 0 | #if SIMDUTF_CPLUSPLUS23 |
4463 | 0 | if !consteval |
4464 | 0 | #endif |
4465 | 0 | { |
4466 | 0 | // try to convert the next block of 16 ASCII bytes |
4467 | 0 | if (pos + 16 <= len) { // if it is safe to read 16 more bytes, check that |
4468 | 0 | // they are ascii |
4469 | 0 | uint64_t v1; |
4470 | 0 | ::memcpy(&v1, data + pos, sizeof(uint64_t)); |
4471 | 0 | uint64_t v2; |
4472 | 0 | ::memcpy(&v2, data + pos + sizeof(uint64_t), sizeof(uint64_t)); |
4473 | 0 | uint64_t v{v1 | v2}; // We are only interested in these bits: 1000 1000 |
4474 | 0 | // 1000 1000...etc |
4475 | 0 | if ((v & 0x8080808080808080) == |
4476 | 0 | 0) { // if NONE of these are set, e.g. all of them are zero, then |
4477 | 0 | // everything is ASCII |
4478 | 0 | size_t final_pos = pos + 16; |
4479 | 0 | while (pos < final_pos) { |
4480 | 0 | *latin_output++ = char(data[pos]); |
4481 | 0 | pos++; |
4482 | 0 | } |
4483 | 0 | continue; |
4484 | 0 | } |
4485 | 0 | } |
4486 | 0 | } |
4487 | 0 | // suppose it is not an all ASCII byte sequence |
4488 | 0 | uint8_t leading_byte = data[pos]; // leading byte |
4489 | 0 | if (leading_byte < 0b10000000) { |
4490 | 0 | // converting one ASCII byte !!! |
4491 | 0 | *latin_output++ = char(leading_byte); |
4492 | 0 | pos++; |
4493 | 0 | } else if ((leading_byte & 0b11100000) == |
4494 | 0 | 0b11000000) { // the first three bits indicate: |
4495 | 0 | // We have a two-byte UTF-8 |
4496 | 0 | if (pos + 1 >= len) { |
4497 | 0 | return result(error_code::TOO_SHORT, pos); |
4498 | 0 | } // minimal bound checking |
4499 | 0 | if ((data[pos + 1] & 0b11000000) != 0b10000000) { |
4500 | 0 | return result(error_code::TOO_SHORT, pos); |
4501 | 0 | } // checks if the next byte is a valid continuation byte in UTF-8. A |
4502 | 0 | // valid continuation byte starts with 10. |
4503 | 0 | // range check - |
4504 | 0 | uint32_t code_point = |
4505 | 0 | (leading_byte & 0b00011111) << 6 | |
4506 | 0 | (data[pos + 1] & |
4507 | 0 | 0b00111111); // assembles the Unicode code point from the two bytes. |
4508 | 0 | // It does this by discarding the leading 110 and 10 |
4509 | 0 | // bits from the two bytes, shifting the remaining bits |
4510 | 0 | // of the first byte, and then combining the results |
4511 | 0 | // with a bitwise OR operation. |
4512 | 0 | if (code_point < 0x80) { |
4513 | 0 | return result(error_code::OVERLONG, pos); |
4514 | 0 | } |
4515 | 0 | if (0xFF < code_point) { |
4516 | 0 | return result(error_code::TOO_LARGE, pos); |
4517 | 0 | } // We only care about the range 129-255 which is Non-ASCII latin1 |
4518 | 0 | // characters |
4519 | 0 | *latin_output++ = char(code_point); |
4520 | 0 | pos += 2; |
4521 | 0 | } else if ((leading_byte & 0b11110000) == 0b11100000) { |
4522 | 0 | // We have a three-byte UTF-8 |
4523 | 0 | return result(error_code::TOO_LARGE, pos); |
4524 | 0 | } else if ((leading_byte & 0b11111000) == 0b11110000) { // 0b11110000 |
4525 | 0 | // we have a 4-byte UTF-8 word. |
4526 | 0 | return result(error_code::TOO_LARGE, pos); |
4527 | 0 | } else { |
4528 | 0 | // we either have too many continuation bytes or an invalid leading byte |
4529 | 0 | if ((leading_byte & 0b11000000) == 0b10000000) { |
4530 | 0 | return result(error_code::TOO_LONG, pos); |
4531 | 0 | } |
4532 | 0 |
|
4533 | 0 | return result(error_code::HEADER_BITS, pos); |
4534 | 0 | } |
4535 | 0 | } |
4536 | 0 | return result(error_code::SUCCESS, latin_output - start); |
4537 | 0 | } Unexecuted instantiation: parser.cpp:_ZN7simdutf6scalar12_GLOBAL__N_114utf8_to_latin119convert_with_errorsIPKcQsr7simdutf6detailE22indexes_into_byte_likeIT_EEENS_6resultES6_mPc Unexecuted instantiation: base64.cpp:_ZN7simdutf6scalar12_GLOBAL__N_114utf8_to_latin119convert_with_errorsIPKcQsr7simdutf6detailE22indexes_into_byte_likeIT_EEENS_6resultES6_mPc Unexecuted instantiation: simdutf.cpp:_ZN7simdutf6scalar12_GLOBAL__N_114utf8_to_latin119convert_with_errorsIPKcQsr7simdutf6detailE22indexes_into_byte_likeIT_EEENS_6resultES6_mPc |
4538 | | |
4539 | | inline result rewind_and_convert_with_errors(size_t prior_bytes, |
4540 | | const char *buf, size_t len, |
4541 | 0 | char *latin1_output) { |
4542 | 0 | size_t extra_len{0}; |
4543 | 0 | // We potentially need to go back in time and find a leading byte. |
4544 | 0 | // In theory '3' would be sufficient, but sometimes the error can go back |
4545 | 0 | // quite far. |
4546 | 0 | size_t how_far_back = prior_bytes; |
4547 | 0 | // size_t how_far_back = 3; // 3 bytes in the past + current position |
4548 | 0 | // if(how_far_back >= prior_bytes) { how_far_back = prior_bytes; } |
4549 | 0 | bool found_leading_bytes{false}; |
4550 | 0 | // important: it is i <= how_far_back and not 'i < how_far_back'. |
4551 | 0 | for (size_t i = 0; i <= how_far_back; i++) { |
4552 | 0 | unsigned char byte = buf[-static_cast<std::ptrdiff_t>(i)]; |
4553 | 0 | found_leading_bytes = ((byte & 0b11000000) != 0b10000000); |
4554 | 0 | if (found_leading_bytes) { |
4555 | 0 | if (i > 0 && byte < 128) { |
4556 | 0 | // If we had to go back and the leading byte is ascii |
4557 | 0 | // then we can stop right away. |
4558 | 0 | return result(error_code::TOO_LONG, 0 - i + 1); |
4559 | 0 | } |
4560 | 0 | buf -= i; |
4561 | 0 | extra_len = i; |
4562 | 0 | break; |
4563 | 0 | } |
4564 | 0 | } |
4565 | 0 | // |
4566 | 0 | // It is possible for this function to return a negative count in its result. |
4567 | 0 | // C++ Standard Section 18.1 defines size_t is in <cstddef> which is described |
4568 | 0 | // in C Standard as <stddef.h>. C Standard Section 4.1.5 defines size_t as an |
4569 | 0 | // unsigned integral type of the result of the sizeof operator |
4570 | 0 | // |
4571 | 0 | // An unsigned type will simply wrap round arithmetically (well defined). |
4572 | 0 | // |
4573 | 0 | if (!found_leading_bytes) { |
4574 | 0 | // If how_far_back == 3, we may have four consecutive continuation bytes!!! |
4575 | 0 | // [....] [continuation] [continuation] [continuation] | [buf is |
4576 | 0 | // continuation] Or we possibly have a stream that does not start with a |
4577 | 0 | // leading byte. |
4578 | 0 | return result(error_code::TOO_LONG, 0 - how_far_back); |
4579 | 0 | } |
4580 | 0 | result res = convert_with_errors(buf, len + extra_len, latin1_output); |
4581 | 0 | if (res.error) { |
4582 | 0 | res.count -= extra_len; |
4583 | 0 | } |
4584 | 0 | return res; |
4585 | 0 | } Unexecuted instantiation: parser.cpp:simdutf::scalar::(anonymous namespace)::utf8_to_latin1::rewind_and_convert_with_errors(unsigned long, char const*, unsigned long, char*) Unexecuted instantiation: base64.cpp:simdutf::scalar::(anonymous namespace)::utf8_to_latin1::rewind_and_convert_with_errors(unsigned long, char const*, unsigned long, char*) Unexecuted instantiation: simdutf.cpp:simdutf::scalar::(anonymous namespace)::utf8_to_latin1::rewind_and_convert_with_errors(unsigned long, char const*, unsigned long, char*) |
4586 | | |
4587 | | } // namespace utf8_to_latin1 |
4588 | | } // unnamed namespace |
4589 | | } // namespace scalar |
4590 | | } // namespace simdutf |
4591 | | |
4592 | | #endif |
4593 | | /* end file include/simdutf/scalar/utf8_to_latin1/utf8_to_latin1.h */ |
4594 | | /* begin file include/simdutf/scalar/utf8_to_latin1/valid_utf8_to_latin1.h */ |
4595 | | #ifndef SIMDUTF_VALID_UTF8_TO_LATIN1_H |
4596 | | #define SIMDUTF_VALID_UTF8_TO_LATIN1_H |
4597 | | |
4598 | | #include <cstring> |
4599 | | |
4600 | | namespace simdutf { |
4601 | | namespace scalar { |
4602 | | namespace { |
4603 | | namespace utf8_to_latin1 { |
4604 | | |
4605 | | template <typename InputPtr> |
4606 | | #if SIMDUTF_CPLUSPLUS20 |
4607 | | requires simdutf::detail::indexes_into_byte_like<InputPtr> |
4608 | | #endif |
4609 | | simdutf_constexpr23 size_t convert_valid(InputPtr data, size_t len, |
4610 | | char *latin_output) { |
4611 | | |
4612 | | size_t pos = 0; |
4613 | | char *start{latin_output}; |
4614 | | |
4615 | | while (pos < len) { |
4616 | | #if SIMDUTF_CPLUSPLUS23 |
4617 | | if !consteval |
4618 | | #endif |
4619 | | { |
4620 | | // try to convert the next block of 16 ASCII bytes |
4621 | | if (pos + 16 <= len) { // if it is safe to read 16 more bytes, check that |
4622 | | // they are ascii |
4623 | | uint64_t v1; |
4624 | | ::memcpy(&v1, data + pos, sizeof(uint64_t)); |
4625 | | uint64_t v2; |
4626 | | ::memcpy(&v2, data + pos + sizeof(uint64_t), sizeof(uint64_t)); |
4627 | | uint64_t v{v1 | |
4628 | | v2}; // We are only interested in these bits: 1000 1000 1000 |
4629 | | // 1000, so it makes sense to concatenate everything |
4630 | | if ((v & 0x8080808080808080) == |
4631 | | 0) { // if NONE of these are set, e.g. all of them are zero, then |
4632 | | // everything is ASCII |
4633 | | size_t final_pos = pos + 16; |
4634 | | while (pos < final_pos) { |
4635 | | *latin_output++ = uint8_t(data[pos]); |
4636 | | pos++; |
4637 | | } |
4638 | | continue; |
4639 | | } |
4640 | | } |
4641 | | } |
4642 | | |
4643 | | // suppose it is not an all ASCII byte sequence |
4644 | | auto leading_byte = uint8_t(data[pos]); // leading byte |
4645 | | if (leading_byte < 0b10000000) { |
4646 | | // converting one ASCII byte !!! |
4647 | | *latin_output++ = char(leading_byte); |
4648 | | pos++; |
4649 | | } else if ((leading_byte & 0b11100000) == |
4650 | | 0b11000000) { // the first three bits indicate: |
4651 | | // We have a two-byte UTF-8 |
4652 | | if (pos + 1 >= len) { |
4653 | | break; |
4654 | | } // minimal bound checking |
4655 | | if ((uint8_t(data[pos + 1]) & 0b11000000) != 0b10000000) { |
4656 | | return 0; |
4657 | | } // checks if the next byte is a valid continuation byte in UTF-8. A |
4658 | | // valid continuation byte starts with 10. |
4659 | | // range check - |
4660 | | uint32_t code_point = |
4661 | | (leading_byte & 0b00011111) << 6 | |
4662 | | (uint8_t(data[pos + 1]) & |
4663 | | 0b00111111); // assembles the Unicode code point from the two bytes. |
4664 | | // It does this by discarding the leading 110 and 10 |
4665 | | // bits from the two bytes, shifting the remaining bits |
4666 | | // of the first byte, and then combining the results |
4667 | | // with a bitwise OR operation. |
4668 | | *latin_output++ = char(code_point); |
4669 | | pos += 2; |
4670 | | } else { |
4671 | | // we may have a continuation but we do not do error checking |
4672 | | return 0; |
4673 | | } |
4674 | | } |
4675 | | return latin_output - start; |
4676 | | } |
4677 | | |
4678 | | } // namespace utf8_to_latin1 |
4679 | | } // unnamed namespace |
4680 | | } // namespace scalar |
4681 | | } // namespace simdutf |
4682 | | |
4683 | | #endif |
4684 | | /* end file include/simdutf/scalar/utf8_to_latin1/valid_utf8_to_latin1.h */ |
4685 | | /* begin file include/simdutf/scalar/utf8_to_utf16/utf8_to_utf16.h */ |
4686 | | #ifndef SIMDUTF_UTF8_TO_UTF16_H |
4687 | | #define SIMDUTF_UTF8_TO_UTF16_H |
4688 | | |
4689 | | #include <cstring> |
4690 | | |
4691 | | namespace simdutf { |
4692 | | namespace scalar { |
4693 | | namespace { |
4694 | | namespace utf8_to_utf16 { |
4695 | | |
4696 | | template <endianness big_endian, typename InputPtr> |
4697 | | #if SIMDUTF_CPLUSPLUS20 |
4698 | | requires simdutf::detail::indexes_into_byte_like<InputPtr> |
4699 | | #endif |
4700 | | simdutf_constexpr23 size_t convert(InputPtr data, size_t len, |
4701 | | char16_t *utf16_output) { |
4702 | | size_t pos = 0; |
4703 | | char16_t *start{utf16_output}; |
4704 | | while (pos < len) { |
4705 | | #if SIMDUTF_CPLUSPLUS23 |
4706 | | if !consteval |
4707 | | #endif |
4708 | | // try to convert the next block of 16 ASCII bytes |
4709 | | { |
4710 | | if (pos + 16 <= len) { // if it is safe to read 16 more bytes, check that |
4711 | | // they are ascii |
4712 | | uint64_t v1; |
4713 | | ::memcpy(&v1, data + pos, sizeof(uint64_t)); |
4714 | | uint64_t v2; |
4715 | | ::memcpy(&v2, data + pos + sizeof(uint64_t), sizeof(uint64_t)); |
4716 | | uint64_t v{v1 | v2}; |
4717 | | if ((v & 0x8080808080808080) == 0) { |
4718 | | size_t final_pos = pos + 16; |
4719 | | while (pos < final_pos) { |
4720 | | *utf16_output++ = !match_system(big_endian) |
4721 | | ? char16_t(u16_swap_bytes(data[pos])) |
4722 | | : char16_t(data[pos]); |
4723 | | pos++; |
4724 | | } |
4725 | | continue; |
4726 | | } |
4727 | | } |
4728 | | } |
4729 | | |
4730 | | uint8_t leading_byte = data[pos]; // leading byte |
4731 | | if (leading_byte < 0b10000000) { |
4732 | | // converting one ASCII byte !!! |
4733 | | *utf16_output++ = !match_system(big_endian) |
4734 | | ? char16_t(u16_swap_bytes(leading_byte)) |
4735 | | : char16_t(leading_byte); |
4736 | | pos++; |
4737 | | } else if ((leading_byte & 0b11100000) == 0b11000000) { |
4738 | | // We have a two-byte UTF-8, it should become |
4739 | | // a single UTF-16 word. |
4740 | | if (pos + 1 >= len) { |
4741 | | return 0; |
4742 | | } // minimal bound checking |
4743 | | if ((data[pos + 1] & 0b11000000) != 0b10000000) { |
4744 | | return 0; |
4745 | | } |
4746 | | // range check |
4747 | | uint32_t code_point = |
4748 | | (leading_byte & 0b00011111) << 6 | (data[pos + 1] & 0b00111111); |
4749 | | if (code_point < 0x80) { |
4750 | | return 0; |
4751 | | } |
4752 | | if constexpr (!match_system(big_endian)) { |
4753 | | code_point = uint32_t(u16_swap_bytes(uint16_t(code_point))); |
4754 | | } |
4755 | | *utf16_output++ = char16_t(code_point); |
4756 | | pos += 2; |
4757 | | } else if ((leading_byte & 0b11110000) == 0b11100000) { |
4758 | | // We have a three-byte UTF-8, it should become |
4759 | | // a single UTF-16 word. |
4760 | | if (pos + 2 >= len) { |
4761 | | return 0; |
4762 | | } // minimal bound checking |
4763 | | |
4764 | | if ((data[pos + 1] & 0b11000000) != 0b10000000) { |
4765 | | return 0; |
4766 | | } |
4767 | | if ((data[pos + 2] & 0b11000000) != 0b10000000) { |
4768 | | return 0; |
4769 | | } |
4770 | | // range check |
4771 | | uint32_t code_point = (leading_byte & 0b00001111) << 12 | |
4772 | | (data[pos + 1] & 0b00111111) << 6 | |
4773 | | (data[pos + 2] & 0b00111111); |
4774 | | if (code_point < 0x800 || (0xd7ff < code_point && code_point < 0xe000)) { |
4775 | | return 0; |
4776 | | } |
4777 | | if constexpr (!match_system(big_endian)) { |
4778 | | code_point = uint32_t(u16_swap_bytes(uint16_t(code_point))); |
4779 | | } |
4780 | | *utf16_output++ = char16_t(code_point); |
4781 | | pos += 3; |
4782 | | } else if ((leading_byte & 0b11111000) == 0b11110000) { // 0b11110000 |
4783 | | // we have a 4-byte UTF-8 word. |
4784 | | if (pos + 3 >= len) { |
4785 | | return 0; |
4786 | | } // minimal bound checking |
4787 | | if ((data[pos + 1] & 0b11000000) != 0b10000000) { |
4788 | | return 0; |
4789 | | } |
4790 | | if ((data[pos + 2] & 0b11000000) != 0b10000000) { |
4791 | | return 0; |
4792 | | } |
4793 | | if ((data[pos + 3] & 0b11000000) != 0b10000000) { |
4794 | | return 0; |
4795 | | } |
4796 | | |
4797 | | // range check |
4798 | | uint32_t code_point = (leading_byte & 0b00000111) << 18 | |
4799 | | (data[pos + 1] & 0b00111111) << 12 | |
4800 | | (data[pos + 2] & 0b00111111) << 6 | |
4801 | | (data[pos + 3] & 0b00111111); |
4802 | | if (code_point <= 0xffff || 0x10ffff < code_point) { |
4803 | | return 0; |
4804 | | } |
4805 | | code_point -= 0x10000; |
4806 | | // The mask is a no-op (code_point < 0x100000). It stops clang 18's SLP |
4807 | | // vectorizer on RISC-V V from narrowing code_point to 16 bits before |
4808 | | // the shift, which drops bits 16-19 of the code point. |
4809 | | uint16_t high_surrogate = uint16_t(0xD800 + ((code_point >> 10) & 0x3FF)); |
4810 | | uint16_t low_surrogate = uint16_t(0xDC00 + (code_point & 0x3FF)); |
4811 | | if constexpr (!match_system(big_endian)) { |
4812 | | high_surrogate = u16_swap_bytes(high_surrogate); |
4813 | | low_surrogate = u16_swap_bytes(low_surrogate); |
4814 | | } |
4815 | | *utf16_output++ = char16_t(high_surrogate); |
4816 | | *utf16_output++ = char16_t(low_surrogate); |
4817 | | pos += 4; |
4818 | | } else { |
4819 | | return 0; |
4820 | | } |
4821 | | } |
4822 | | return utf16_output - start; |
4823 | | } |
4824 | | |
4825 | | template <endianness big_endian, typename InputPtr> |
4826 | | #if SIMDUTF_CPLUSPLUS20 |
4827 | | requires simdutf::detail::indexes_into_byte_like<InputPtr> |
4828 | | #endif |
4829 | | simdutf_constexpr23 result convert_with_errors(InputPtr data, size_t len, |
4830 | | char16_t *utf16_output) { |
4831 | | size_t pos = 0; |
4832 | | char16_t *start{utf16_output}; |
4833 | | while (pos < len) { |
4834 | | #if SIMDUTF_CPLUSPLUS23 |
4835 | | if !consteval |
4836 | | #endif |
4837 | | { |
4838 | | // try to convert the next block of 16 ASCII bytes |
4839 | | if (pos + 16 <= len) { // if it is safe to read 16 more bytes, check that |
4840 | | // they are ascii |
4841 | | uint64_t v1; |
4842 | | ::memcpy(&v1, data + pos, sizeof(uint64_t)); |
4843 | | uint64_t v2; |
4844 | | ::memcpy(&v2, data + pos + sizeof(uint64_t), sizeof(uint64_t)); |
4845 | | uint64_t v{v1 | v2}; |
4846 | | if ((v & 0x8080808080808080) == 0) { |
4847 | | size_t final_pos = pos + 16; |
4848 | | while (pos < final_pos) { |
4849 | | const char16_t byte = uint8_t(data[pos]); |
4850 | | *utf16_output++ = |
4851 | | !match_system(big_endian) ? u16_swap_bytes(byte) : byte; |
4852 | | pos++; |
4853 | | } |
4854 | | continue; |
4855 | | } |
4856 | | } |
4857 | | } |
4858 | | |
4859 | | auto leading_byte = uint8_t(data[pos]); // leading byte |
4860 | | if (leading_byte < 0b10000000) { |
4861 | | // converting one ASCII byte !!! |
4862 | | *utf16_output++ = !match_system(big_endian) |
4863 | | ? char16_t(u16_swap_bytes(leading_byte)) |
4864 | | : char16_t(leading_byte); |
4865 | | pos++; |
4866 | | } else if ((leading_byte & 0b11100000) == 0b11000000) { |
4867 | | // We have a two-byte UTF-8, it should become |
4868 | | // a single UTF-16 word. |
4869 | | if (pos + 1 >= len) { |
4870 | | return result(error_code::TOO_SHORT, pos); |
4871 | | } // minimal bound checking |
4872 | | if ((uint8_t(data[pos + 1]) & 0b11000000) != 0b10000000) { |
4873 | | return result(error_code::TOO_SHORT, pos); |
4874 | | } |
4875 | | // range check |
4876 | | uint32_t code_point = (leading_byte & 0b00011111) << 6 | |
4877 | | (uint8_t(data[pos + 1]) & 0b00111111); |
4878 | | if (code_point < 0x80) { |
4879 | | return result(error_code::OVERLONG, pos); |
4880 | | } |
4881 | | if constexpr (!match_system(big_endian)) { |
4882 | | code_point = uint32_t(u16_swap_bytes(uint16_t(code_point))); |
4883 | | } |
4884 | | *utf16_output++ = char16_t(code_point); |
4885 | | pos += 2; |
4886 | | } else if ((leading_byte & 0b11110000) == 0b11100000) { |
4887 | | // We have a three-byte UTF-8, it should become |
4888 | | // a single UTF-16 word. |
4889 | | if (pos + 2 >= len) { |
4890 | | return result(error_code::TOO_SHORT, pos); |
4891 | | } // minimal bound checking |
4892 | | |
4893 | | if ((uint8_t(data[pos + 1]) & 0b11000000) != 0b10000000) { |
4894 | | return result(error_code::TOO_SHORT, pos); |
4895 | | } |
4896 | | if ((uint8_t(data[pos + 2]) & 0b11000000) != 0b10000000) { |
4897 | | return result(error_code::TOO_SHORT, pos); |
4898 | | } |
4899 | | // range check |
4900 | | uint32_t code_point = (leading_byte & 0b00001111) << 12 | |
4901 | | (uint8_t(data[pos + 1]) & 0b00111111) << 6 | |
4902 | | (uint8_t(data[pos + 2]) & 0b00111111); |
4903 | | if (code_point < 0x800) { |
4904 | | return result(error_code::OVERLONG, pos); |
4905 | | } |
4906 | | if (0xd7ff < code_point && code_point < 0xe000) { |
4907 | | return result(error_code::SURROGATE, pos); |
4908 | | } |
4909 | | if constexpr (!match_system(big_endian)) { |
4910 | | code_point = uint32_t(u16_swap_bytes(uint16_t(code_point))); |
4911 | | } |
4912 | | *utf16_output++ = char16_t(code_point); |
4913 | | pos += 3; |
4914 | | } else if ((leading_byte & 0b11111000) == 0b11110000) { // 0b11110000 |
4915 | | // we have a 4-byte UTF-8 word. |
4916 | | if (pos + 3 >= len) { |
4917 | | return result(error_code::TOO_SHORT, pos); |
4918 | | } // minimal bound checking |
4919 | | if ((uint8_t(data[pos + 1]) & 0b11000000) != 0b10000000) { |
4920 | | return result(error_code::TOO_SHORT, pos); |
4921 | | } |
4922 | | if ((uint8_t(data[pos + 2]) & 0b11000000) != 0b10000000) { |
4923 | | return result(error_code::TOO_SHORT, pos); |
4924 | | } |
4925 | | if ((uint8_t(data[pos + 3]) & 0b11000000) != 0b10000000) { |
4926 | | return result(error_code::TOO_SHORT, pos); |
4927 | | } |
4928 | | |
4929 | | // range check |
4930 | | uint32_t code_point = (leading_byte & 0b00000111) << 18 | |
4931 | | (uint8_t(data[pos + 1]) & 0b00111111) << 12 | |
4932 | | (uint8_t(data[pos + 2]) & 0b00111111) << 6 | |
4933 | | (uint8_t(data[pos + 3]) & 0b00111111); |
4934 | | if (code_point <= 0xffff) { |
4935 | | return result(error_code::OVERLONG, pos); |
4936 | | } |
4937 | | if (0x10ffff < code_point) { |
4938 | | return result(error_code::TOO_LARGE, pos); |
4939 | | } |
4940 | | code_point -= 0x10000; |
4941 | | // The mask is a no-op (code_point < 0x100000). It stops clang 18's SLP |
4942 | | // vectorizer on RISC-V V from narrowing code_point to 16 bits before |
4943 | | // the shift, which drops bits 16-19 of the code point. |
4944 | | uint16_t high_surrogate = uint16_t(0xD800 + ((code_point >> 10) & 0x3FF)); |
4945 | | uint16_t low_surrogate = uint16_t(0xDC00 + (code_point & 0x3FF)); |
4946 | | if constexpr (!match_system(big_endian)) { |
4947 | | high_surrogate = u16_swap_bytes(high_surrogate); |
4948 | | low_surrogate = u16_swap_bytes(low_surrogate); |
4949 | | } |
4950 | | *utf16_output++ = char16_t(high_surrogate); |
4951 | | *utf16_output++ = char16_t(low_surrogate); |
4952 | | pos += 4; |
4953 | | } else { |
4954 | | // we either have too many continuation bytes or an invalid leading byte |
4955 | | if ((leading_byte & 0b11000000) == 0b10000000) { |
4956 | | return result(error_code::TOO_LONG, pos); |
4957 | | } else { |
4958 | | return result(error_code::HEADER_BITS, pos); |
4959 | | } |
4960 | | } |
4961 | | } |
4962 | | return result(error_code::SUCCESS, utf16_output - start); |
4963 | | } |
4964 | | |
4965 | | /** |
4966 | | * When rewind_and_convert_with_errors is called, we are pointing at 'buf' and |
4967 | | * we have up to len input bytes left, and we encountered some error. It is |
4968 | | * possible that the error is at 'buf' exactly, but it could also be in the |
4969 | | * previous bytes (up to 3 bytes back). |
4970 | | * |
4971 | | * prior_bytes indicates how many bytes, prior to 'buf' may belong to the |
4972 | | * current memory section and can be safely accessed. We prior_bytes to access |
4973 | | * safely up to three bytes before 'buf'. |
4974 | | * |
4975 | | * The caller is responsible to ensure that len > 0. |
4976 | | * |
4977 | | * If the error is believed to have occurred prior to 'buf', the count value |
4978 | | * contain in the result will be SIZE_T - 1, SIZE_T - 2, or SIZE_T - 3. |
4979 | | */ |
4980 | | template <endianness endian> |
4981 | | inline result rewind_and_convert_with_errors(size_t prior_bytes, |
4982 | | const char *buf, size_t len, |
4983 | | char16_t *utf16_output) { |
4984 | | size_t extra_len{0}; |
4985 | | // We potentially need to go back in time and find a leading byte. |
4986 | | // In theory '3' would be sufficient, but sometimes the error can go back |
4987 | | // quite far. |
4988 | | size_t how_far_back = prior_bytes; |
4989 | | // size_t how_far_back = 3; // 3 bytes in the past + current position |
4990 | | // if(how_far_back >= prior_bytes) { how_far_back = prior_bytes; } |
4991 | | bool found_leading_bytes{false}; |
4992 | | // important: it is i <= how_far_back and not 'i < how_far_back'. |
4993 | | for (size_t i = 0; i <= how_far_back; i++) { |
4994 | | unsigned char byte = buf[-static_cast<std::ptrdiff_t>(i)]; |
4995 | | found_leading_bytes = ((byte & 0b11000000) != 0b10000000); |
4996 | | if (found_leading_bytes) { |
4997 | | if (i > 0 && byte < 128) { |
4998 | | // If we had to go back and the leading byte is ascii |
4999 | | // then we can stop right away. |
5000 | | return result(error_code::TOO_LONG, 0 - i + 1); |
5001 | | } |
5002 | | buf -= i; |
5003 | | extra_len = i; |
5004 | | break; |
5005 | | } |
5006 | | } |
5007 | | // |
5008 | | // It is possible for this function to return a negative count in its result. |
5009 | | // C++ Standard Section 18.1 defines size_t is in <cstddef> which is described |
5010 | | // in C Standard as <stddef.h>. C Standard Section 4.1.5 defines size_t as an |
5011 | | // unsigned integral type of the result of the sizeof operator |
5012 | | // |
5013 | | // An unsigned type will simply wrap round arithmetically (well defined). |
5014 | | // |
5015 | | if (!found_leading_bytes) { |
5016 | | // If how_far_back == 3, we may have four consecutive continuation bytes!!! |
5017 | | // [....] [continuation] [continuation] [continuation] | [buf is |
5018 | | // continuation] Or we possibly have a stream that does not start with a |
5019 | | // leading byte. |
5020 | | return result(error_code::TOO_LONG, 0 - how_far_back); |
5021 | | } |
5022 | | result res = convert_with_errors<endian>(buf, len + extra_len, utf16_output); |
5023 | | if (res.error) { |
5024 | | res.count -= extra_len; |
5025 | | } |
5026 | | return res; |
5027 | | } |
5028 | | |
5029 | | } // namespace utf8_to_utf16 |
5030 | | } // unnamed namespace |
5031 | | } // namespace scalar |
5032 | | } // namespace simdutf |
5033 | | |
5034 | | #endif |
5035 | | /* end file include/simdutf/scalar/utf8_to_utf16/utf8_to_utf16.h */ |
5036 | | /* begin file include/simdutf/scalar/utf8_to_utf16/utf8_to_utf16_with_replacement.h */ |
5037 | | #ifndef SIMDUTF_UTF8_TO_UTF16_WITH_REPLACEMENT_H |
5038 | | #define SIMDUTF_UTF8_TO_UTF16_WITH_REPLACEMENT_H |
5039 | | |
5040 | | #include <cstring> |
5041 | | |
5042 | | namespace simdutf { |
5043 | | namespace scalar { |
5044 | | namespace { |
5045 | | namespace utf8_to_utf16 { |
5046 | | |
5047 | | // Pointer-like view so validate_with_counts can run during constant |
5048 | | // evaluation, where reinterpret_cast from char* to uint8_t* is not allowed. |
5049 | | // operator+ exists only for the runtime ASCII probe inside that function. |
5050 | | template <typename InputPtr> struct utf8_byte_pointer { |
5051 | | InputPtr p; |
5052 | | simdutf_constexpr23 uint8_t operator*() const noexcept { |
5053 | | return uint8_t(static_cast<unsigned char>(*p)); |
5054 | | } |
5055 | | simdutf_constexpr23 uint8_t operator[](size_t i) const noexcept { |
5056 | | return uint8_t(static_cast<unsigned char>(p[i])); |
5057 | | } |
5058 | | const uint8_t *operator+(size_t i) const noexcept { |
5059 | | return reinterpret_cast<const uint8_t *>(static_cast<const void *>(p + i)); |
5060 | | } |
5061 | | }; |
5062 | | |
5063 | | // Byte length of one maximal subpart starting at ptr. n must be at least 1. |
5064 | | // The validator reports the first byte of the ill-formed sequence. |
5065 | | template <typename InputPtr> |
5066 | | #if SIMDUTF_CPLUSPLUS20 |
5067 | | requires simdutf::detail::indexes_into_byte_like<InputPtr> |
5068 | | #endif |
5069 | | simdutf_constexpr23 size_t maximal_subpart(InputPtr ptr, size_t n) noexcept { |
5070 | | const uint8_t b = uint8_t(static_cast<unsigned char>(ptr[0])); |
5071 | | size_t need; |
5072 | | uint8_t lo = 0x80; |
5073 | | uint8_t hi = 0xBF; |
5074 | | if (b < 0xC2) { |
5075 | | return 1; // ASCII is handled by the caller; continuation, C0, C1 |
5076 | | } else if (b < 0xE0) { |
5077 | | need = 1; |
5078 | | } else if (b < 0xF0) { |
5079 | | need = 2; |
5080 | | if (b == 0xE0) { |
5081 | | lo = 0xA0; |
5082 | | } else if (b == 0xED) { |
5083 | | hi = 0x9F; |
5084 | | } |
5085 | | } else if (b < 0xF5) { |
5086 | | need = 3; |
5087 | | if (b == 0xF0) { |
5088 | | lo = 0x90; |
5089 | | } else if (b == 0xF4) { |
5090 | | hi = 0x8F; |
5091 | | } |
5092 | | } else { |
5093 | | return 1; // F5..FF |
5094 | | } |
5095 | | if (n < 2 || uint8_t(static_cast<unsigned char>(ptr[1])) < lo || |
5096 | | uint8_t(static_cast<unsigned char>(ptr[1])) > hi) { |
5097 | | return 1; |
5098 | | } |
5099 | | size_t i = 2; |
5100 | | while (i <= need && i < n && |
5101 | | (uint8_t(static_cast<unsigned char>(ptr[i])) & 0xC0) == 0x80) { |
5102 | | i++; |
5103 | | } |
5104 | | return i; |
5105 | | } |
5106 | | |
5107 | | // WHATWG / Unicode substitution of maximal subparts. One U+FFFD per subpart. |
5108 | | // `write == false` counts UTF-16 code units and does not store. |
5109 | | template <endianness endian, bool write, typename InputPtr> |
5110 | | #if SIMDUTF_CPLUSPLUS20 |
5111 | | requires simdutf::detail::indexes_into_byte_like<InputPtr> |
5112 | | #endif |
5113 | | simdutf_constexpr23 size_t transcode_with_replacement( |
5114 | | InputPtr data, size_t len, char16_t *utf16_output) noexcept { |
5115 | | size_t i = 0; |
5116 | | size_t written = 0; |
5117 | | uint32_t cp = 0; |
5118 | | size_t needed = 0; |
5119 | | size_t seen = 0; |
5120 | | uint8_t lo = 0x80; |
5121 | | uint8_t hi = 0xBF; |
5122 | | auto store = [&](uint32_t c) { |
5123 | | if (c >= 0x10000) { |
5124 | | c -= 0x10000; |
5125 | | // The mask is a no-op (c < 0x100000). It stops clang 18's SLP |
5126 | | // vectorizer on RISC-V V from narrowing c to 16 bits before |
5127 | | // the shift, which drops bits 16-19 of the code point. |
5128 | | const uint16_t high = uint16_t(0xD800 + ((c >> 10) & 0x3FF)); |
5129 | | const uint16_t low = uint16_t(0xDC00 + (c & 0x3FF)); |
5130 | | if constexpr (write) { |
5131 | | utf16_output[written] = |
5132 | | char16_t(scalar::utf16::swap_if_needed<endian>(high)); |
5133 | | utf16_output[written + 1] = |
5134 | | char16_t(scalar::utf16::swap_if_needed<endian>(low)); |
5135 | | } |
5136 | | written += 2; |
5137 | | } else { |
5138 | | if constexpr (write) { |
5139 | | utf16_output[written] = |
5140 | | char16_t(scalar::utf16::swap_if_needed<endian>(uint16_t(c))); |
5141 | | } |
5142 | | written += 1; |
5143 | | } |
5144 | | }; |
5145 | | while (i < len) { |
5146 | | if (needed == 0 && i + 16 <= len) { |
5147 | | #if SIMDUTF_CPLUSPLUS23 |
5148 | | if !consteval |
5149 | | #endif |
5150 | | { |
5151 | | uint64_t v1; |
5152 | | std::memcpy(&v1, data + i, sizeof(v1)); |
5153 | | uint64_t v2; |
5154 | | std::memcpy(&v2, data + i + sizeof(v1), sizeof(v2)); |
5155 | | if (((v1 | v2) & 0x8080808080808080ULL) == 0) { |
5156 | | for (size_t k = 0; k < 16; k++) { |
5157 | | store(uint8_t(static_cast<unsigned char>(data[i + k]))); |
5158 | | } |
5159 | | i += 16; |
5160 | | continue; |
5161 | | } |
5162 | | } |
5163 | | } |
5164 | | const uint8_t b = uint8_t(static_cast<unsigned char>(data[i])); |
5165 | | if (needed == 0) { |
5166 | | i++; |
5167 | | lo = 0x80; |
5168 | | hi = 0xBF; |
5169 | | if (b < 0x80) { |
5170 | | store(b); |
5171 | | } else if (b <= 0xDF) { |
5172 | | if (b < 0xC2) { |
5173 | | store(0xFFFD); |
5174 | | } else { |
5175 | | needed = 1; |
5176 | | cp = b & 0x1F; |
5177 | | } |
5178 | | } else if (b <= 0xEF) { |
5179 | | if (b == 0xE0) { |
5180 | | lo = 0xA0; |
5181 | | } else if (b == 0xED) { |
5182 | | hi = 0x9F; |
5183 | | } |
5184 | | needed = 2; |
5185 | | cp = b & 0x0F; |
5186 | | } else if (b <= 0xF4) { |
5187 | | if (b == 0xF0) { |
5188 | | lo = 0x90; |
5189 | | } else if (b == 0xF4) { |
5190 | | hi = 0x8F; |
5191 | | } |
5192 | | needed = 3; |
5193 | | cp = b & 0x07; |
5194 | | } else { |
5195 | | store(0xFFFD); |
5196 | | } |
5197 | | continue; |
5198 | | } |
5199 | | if (b < lo || b > hi) { |
5200 | | needed = 0; |
5201 | | seen = 0; |
5202 | | cp = 0; |
5203 | | lo = 0x80; |
5204 | | hi = 0xBF; |
5205 | | store(0xFFFD); |
5206 | | continue; |
5207 | | } |
5208 | | i++; |
5209 | | lo = 0x80; |
5210 | | hi = 0xBF; |
5211 | | cp = (cp << 6) | uint32_t(b & 0x3F); |
5212 | | seen++; |
5213 | | if (seen == needed) { |
5214 | | store(cp); |
5215 | | needed = 0; |
5216 | | seen = 0; |
5217 | | cp = 0; |
5218 | | } |
5219 | | } |
5220 | | if (needed != 0) { |
5221 | | store(0xFFFD); |
5222 | | } |
5223 | | return written; |
5224 | | } |
5225 | | |
5226 | | template <endianness endian, typename InputPtr> |
5227 | | #if SIMDUTF_CPLUSPLUS20 |
5228 | | requires simdutf::detail::indexes_into_byte_like<InputPtr> |
5229 | | #endif |
5230 | | simdutf_constexpr23 size_t convert_with_replacement( |
5231 | | InputPtr data, size_t len, char16_t *utf16_output) noexcept { |
5232 | | return transcode_with_replacement<endian, true>(data, len, utf16_output); |
5233 | | } |
5234 | | |
5235 | | template <typename InputPtr> |
5236 | | #if SIMDUTF_CPLUSPLUS20 |
5237 | | requires simdutf::detail::indexes_into_byte_like<InputPtr> |
5238 | | #endif |
5239 | | simdutf_constexpr23 size_t count_with_replacement(InputPtr data, |
5240 | | size_t len) noexcept { |
5241 | | return transcode_with_replacement<endianness::LITTLE, false>(data, len, |
5242 | | nullptr); |
5243 | | } |
5244 | | |
5245 | | template <typename InputPtr> |
5246 | | #if SIMDUTF_CPLUSPLUS20 |
5247 | | requires simdutf::detail::indexes_into_byte_like<InputPtr> |
5248 | | #endif |
5249 | | simdutf_constexpr23 utf8_to_utf16_result |
5250 | | utf16_length_from_utf8_with_replacement(InputPtr data, size_t len) noexcept { |
5251 | | utf8_to_utf16_result out; |
5252 | | size_t pos = 0; |
5253 | | while (pos < len) { |
5254 | | utf8_result validation; |
5255 | | #if SIMDUTF_CPLUSPLUS23 |
5256 | | if consteval { |
5257 | | validation = scalar::utf8::validate_with_counts( |
5258 | | utf8_byte_pointer<InputPtr>{data + pos}, len - pos); |
5259 | | } else |
5260 | | #endif |
5261 | | { |
5262 | | validation = scalar::utf8::validate_with_counts( |
5263 | | reinterpret_cast<const uint8_t *>(data + pos), len - pos); |
5264 | | } |
5265 | | if (validation.error == error_code::SUCCESS) { |
5266 | | out.count += validation.utf16_length(); |
5267 | | return out; |
5268 | | } |
5269 | | if (validation.input_count >= len - pos) { |
5270 | | out.count += count_with_replacement(data + pos, len - pos); |
5271 | | out.more_errors = true; |
5272 | | if (out.error == error_code::SUCCESS) { |
5273 | | out.error = validation.error; |
5274 | | } |
5275 | | return out; |
5276 | | } |
5277 | | out.count += validation.utf16_length() + 1; |
5278 | | if (out.error == error_code::SUCCESS) { |
5279 | | out.error = validation.error; |
5280 | | } |
5281 | | const size_t err = pos + validation.input_count; |
5282 | | const size_t skip = maximal_subpart(data + err, len - err); |
5283 | | if (out.error_count < utf8_to_utf16_result::max_errors) { |
5284 | | out.error_offset[out.error_count] = err; |
5285 | | out.error_count += 1; |
5286 | | } else { |
5287 | | out.more_errors = true; |
5288 | | } |
5289 | | pos = err + skip; |
5290 | | } |
5291 | | return out; |
5292 | | } |
5293 | | |
5294 | | } // namespace utf8_to_utf16 |
5295 | | } // unnamed namespace |
5296 | | } // namespace scalar |
5297 | | } // namespace simdutf |
5298 | | |
5299 | | #endif // SIMDUTF_UTF8_TO_UTF16_WITH_REPLACEMENT_H |
5300 | | /* end file include/simdutf/scalar/utf8_to_utf16/utf8_to_utf16_with_replacement.h */ |
5301 | | /* begin file include/simdutf/scalar/utf8_to_utf16/valid_utf8_to_utf16.h */ |
5302 | | #ifndef SIMDUTF_VALID_UTF8_TO_UTF16_H |
5303 | | #define SIMDUTF_VALID_UTF8_TO_UTF16_H |
5304 | | |
5305 | | #include <cstring> |
5306 | | |
5307 | | namespace simdutf { |
5308 | | namespace scalar { |
5309 | | namespace { |
5310 | | namespace utf8_to_utf16 { |
5311 | | |
5312 | | template <endianness big_endian, typename InputPtr> |
5313 | | #if SIMDUTF_CPLUSPLUS20 |
5314 | | requires simdutf::detail::indexes_into_byte_like<InputPtr> |
5315 | | #endif |
5316 | | simdutf_constexpr23 size_t convert_valid(InputPtr data, size_t len, |
5317 | | char16_t *utf16_output) { |
5318 | | size_t pos = 0; |
5319 | | char16_t *start{utf16_output}; |
5320 | | while (pos < len) { |
5321 | | #if SIMDUTF_CPLUSPLUS23 |
5322 | | if !consteval |
5323 | | #endif |
5324 | | { // try to convert the next block of 8 ASCII bytes |
5325 | | if (pos + 8 <= len) { // if it is safe to read 8 more bytes, check that |
5326 | | // they are ascii |
5327 | | uint64_t v; |
5328 | | ::memcpy(&v, data + pos, sizeof(uint64_t)); |
5329 | | if ((v & 0x8080808080808080) == 0) { |
5330 | | size_t final_pos = pos + 8; |
5331 | | while (pos < final_pos) { |
5332 | | const char16_t byte = uint8_t(data[pos]); |
5333 | | *utf16_output++ = |
5334 | | !match_system(big_endian) ? u16_swap_bytes(byte) : byte; |
5335 | | pos++; |
5336 | | } |
5337 | | continue; |
5338 | | } |
5339 | | } |
5340 | | } |
5341 | | |
5342 | | auto leading_byte = uint8_t(data[pos]); // leading byte |
5343 | | if (leading_byte < 0b10000000) { |
5344 | | // converting one ASCII byte !!! |
5345 | | *utf16_output++ = !match_system(big_endian) |
5346 | | ? char16_t(u16_swap_bytes(leading_byte)) |
5347 | | : char16_t(leading_byte); |
5348 | | pos++; |
5349 | | } else if ((leading_byte & 0b11100000) == 0b11000000) { |
5350 | | // We have a two-byte UTF-8, it should become |
5351 | | // a single UTF-16 word. |
5352 | | if (pos + 1 >= len) { |
5353 | | break; |
5354 | | } // minimal bound checking |
5355 | | uint16_t code_point = uint16_t(((leading_byte & 0b00011111) << 6) | |
5356 | | (uint8_t(data[pos + 1]) & 0b00111111)); |
5357 | | if constexpr (!match_system(big_endian)) { |
5358 | | code_point = u16_swap_bytes(uint16_t(code_point)); |
5359 | | } |
5360 | | *utf16_output++ = char16_t(code_point); |
5361 | | pos += 2; |
5362 | | } else if ((leading_byte & 0b11110000) == 0b11100000) { |
5363 | | // We have a three-byte UTF-8, it should become |
5364 | | // a single UTF-16 word. |
5365 | | if (pos + 2 >= len) { |
5366 | | break; |
5367 | | } // minimal bound checking |
5368 | | uint16_t code_point = |
5369 | | uint16_t(((leading_byte & 0b00001111) << 12) | |
5370 | | ((uint8_t(data[pos + 1]) & 0b00111111) << 6) | |
5371 | | (uint8_t(data[pos + 2]) & 0b00111111)); |
5372 | | if constexpr (!match_system(big_endian)) { |
5373 | | code_point = u16_swap_bytes(uint16_t(code_point)); |
5374 | | } |
5375 | | *utf16_output++ = char16_t(code_point); |
5376 | | pos += 3; |
5377 | | } else if ((leading_byte & 0b11111000) == 0b11110000) { // 0b11110000 |
5378 | | // we have a 4-byte UTF-8 word. |
5379 | | if (pos + 3 >= len) { |
5380 | | break; |
5381 | | } // minimal bound checking |
5382 | | uint32_t code_point = ((leading_byte & 0b00000111) << 18) | |
5383 | | ((uint8_t(data[pos + 1]) & 0b00111111) << 12) | |
5384 | | ((uint8_t(data[pos + 2]) & 0b00111111) << 6) | |
5385 | | (uint8_t(data[pos + 3]) & 0b00111111); |
5386 | | code_point -= 0x10000; |
5387 | | // The mask is a no-op (code_point < 0x100000). It stops clang 18's SLP |
5388 | | // vectorizer on RISC-V V from narrowing code_point to 16 bits before |
5389 | | // the shift, which drops bits 16-19 of the code point. |
5390 | | uint16_t high_surrogate = uint16_t(0xD800 + ((code_point >> 10) & 0x3FF)); |
5391 | | uint16_t low_surrogate = uint16_t(0xDC00 + (code_point & 0x3FF)); |
5392 | | if constexpr (!match_system(big_endian)) { |
5393 | | high_surrogate = u16_swap_bytes(high_surrogate); |
5394 | | low_surrogate = u16_swap_bytes(low_surrogate); |
5395 | | } |
5396 | | *utf16_output++ = char16_t(high_surrogate); |
5397 | | *utf16_output++ = char16_t(low_surrogate); |
5398 | | pos += 4; |
5399 | | } else { |
5400 | | // we may have a continuation but we do not do error checking |
5401 | | return 0; |
5402 | | } |
5403 | | } |
5404 | | return utf16_output - start; |
5405 | | } |
5406 | | |
5407 | | } // namespace utf8_to_utf16 |
5408 | | } // unnamed namespace |
5409 | | } // namespace scalar |
5410 | | } // namespace simdutf |
5411 | | |
5412 | | #endif |
5413 | | /* end file include/simdutf/scalar/utf8_to_utf16/valid_utf8_to_utf16.h */ |
5414 | | /* begin file include/simdutf/scalar/utf8_to_utf32/utf8_to_utf32.h */ |
5415 | | #ifndef SIMDUTF_UTF8_TO_UTF32_H |
5416 | | #define SIMDUTF_UTF8_TO_UTF32_H |
5417 | | |
5418 | | #include <cstring> |
5419 | | |
5420 | | namespace simdutf { |
5421 | | namespace scalar { |
5422 | | namespace { |
5423 | | namespace utf8_to_utf32 { |
5424 | | |
5425 | | template <typename InputPtr> |
5426 | | #if SIMDUTF_CPLUSPLUS20 |
5427 | | requires simdutf::detail::indexes_into_byte_like<InputPtr> |
5428 | | #endif |
5429 | | simdutf_constexpr23 size_t convert(InputPtr data, size_t len, |
5430 | | char32_t *utf32_output) { |
5431 | | size_t pos = 0; |
5432 | | char32_t *start{utf32_output}; |
5433 | | while (pos < len) { |
5434 | | #if SIMDUTF_CPLUSPLUS23 |
5435 | | if !consteval |
5436 | | #endif |
5437 | | { |
5438 | | // try to convert the next block of 16 ASCII bytes |
5439 | | if (pos + 16 <= len) { // if it is safe to read 16 more bytes, check that |
5440 | | // they are ascii |
5441 | | uint64_t v1; |
5442 | | ::memcpy(&v1, data + pos, sizeof(uint64_t)); |
5443 | | uint64_t v2; |
5444 | | ::memcpy(&v2, data + pos + sizeof(uint64_t), sizeof(uint64_t)); |
5445 | | uint64_t v{v1 | v2}; |
5446 | | if ((v & 0x8080808080808080) == 0) { |
5447 | | size_t final_pos = pos + 16; |
5448 | | while (pos < final_pos) { |
5449 | | *utf32_output++ = uint8_t(data[pos]); |
5450 | | pos++; |
5451 | | } |
5452 | | continue; |
5453 | | } |
5454 | | } |
5455 | | } |
5456 | | auto leading_byte = uint8_t(data[pos]); // leading byte |
5457 | | if (leading_byte < 0b10000000) { |
5458 | | // converting one ASCII byte !!! |
5459 | | *utf32_output++ = char32_t(leading_byte); |
5460 | | pos++; |
5461 | | } else if ((leading_byte & 0b11100000) == 0b11000000) { |
5462 | | // We have a two-byte UTF-8 |
5463 | | if (pos + 1 >= len) { |
5464 | | return 0; |
5465 | | } // minimal bound checking |
5466 | | if ((data[pos + 1] & 0b11000000) != 0b10000000) { |
5467 | | return 0; |
5468 | | } |
5469 | | // range check |
5470 | | uint32_t code_point = (leading_byte & 0b00011111) << 6 | |
5471 | | (uint8_t(data[pos + 1]) & 0b00111111); |
5472 | | if (code_point < 0x80) { |
5473 | | return 0; |
5474 | | } |
5475 | | *utf32_output++ = char32_t(code_point); |
5476 | | pos += 2; |
5477 | | } else if ((leading_byte & 0b11110000) == 0b11100000) { |
5478 | | // We have a three-byte UTF-8 |
5479 | | if (pos + 2 >= len) { |
5480 | | return 0; |
5481 | | } // minimal bound checking |
5482 | | |
5483 | | if ((uint8_t(data[pos + 1]) & 0b11000000) != 0b10000000) { |
5484 | | return 0; |
5485 | | } |
5486 | | if ((uint8_t(data[pos + 2]) & 0b11000000) != 0b10000000) { |
5487 | | return 0; |
5488 | | } |
5489 | | // range check |
5490 | | uint32_t code_point = (leading_byte & 0b00001111) << 12 | |
5491 | | (uint8_t(data[pos + 1]) & 0b00111111) << 6 | |
5492 | | (uint8_t(data[pos + 2]) & 0b00111111); |
5493 | | if (code_point < 0x800 || (0xd7ff < code_point && code_point < 0xe000)) { |
5494 | | return 0; |
5495 | | } |
5496 | | *utf32_output++ = char32_t(code_point); |
5497 | | pos += 3; |
5498 | | } else if ((leading_byte & 0b11111000) == 0b11110000) { // 0b11110000 |
5499 | | // we have a 4-byte UTF-8 word. |
5500 | | if (pos + 3 >= len) { |
5501 | | return 0; |
5502 | | } // minimal bound checking |
5503 | | if ((uint8_t(data[pos + 1]) & 0b11000000) != 0b10000000) { |
5504 | | return 0; |
5505 | | } |
5506 | | if ((uint8_t(data[pos + 2]) & 0b11000000) != 0b10000000) { |
5507 | | return 0; |
5508 | | } |
5509 | | if ((uint8_t(data[pos + 3]) & 0b11000000) != 0b10000000) { |
5510 | | return 0; |
5511 | | } |
5512 | | |
5513 | | // range check |
5514 | | uint32_t code_point = (leading_byte & 0b00000111) << 18 | |
5515 | | (uint8_t(data[pos + 1]) & 0b00111111) << 12 | |
5516 | | (uint8_t(data[pos + 2]) & 0b00111111) << 6 | |
5517 | | (uint8_t(data[pos + 3]) & 0b00111111); |
5518 | | if (code_point <= 0xffff || 0x10ffff < code_point) { |
5519 | | return 0; |
5520 | | } |
5521 | | *utf32_output++ = char32_t(code_point); |
5522 | | pos += 4; |
5523 | | } else { |
5524 | | return 0; |
5525 | | } |
5526 | | } |
5527 | | return utf32_output - start; |
5528 | | } |
5529 | | |
5530 | | template <typename InputPtr> |
5531 | | #if SIMDUTF_CPLUSPLUS20 |
5532 | | requires simdutf::detail::indexes_into_byte_like<InputPtr> |
5533 | | #endif |
5534 | | simdutf_constexpr23 result convert_with_errors(InputPtr data, size_t len, |
5535 | 0 | char32_t *utf32_output) { |
5536 | 0 | size_t pos = 0; |
5537 | 0 | char32_t *start{utf32_output}; |
5538 | 0 | while (pos < len) { |
5539 | 0 | #if SIMDUTF_CPLUSPLUS23 |
5540 | 0 | if !consteval |
5541 | 0 | #endif |
5542 | 0 | { |
5543 | 0 | // try to convert the next block of 16 ASCII bytes |
5544 | 0 | if (pos + 16 <= len) { // if it is safe to read 16 more bytes, check that |
5545 | 0 | // they are ascii |
5546 | 0 | uint64_t v1; |
5547 | 0 | ::memcpy(&v1, data + pos, sizeof(uint64_t)); |
5548 | 0 | uint64_t v2; |
5549 | 0 | ::memcpy(&v2, data + pos + sizeof(uint64_t), sizeof(uint64_t)); |
5550 | 0 | uint64_t v{v1 | v2}; |
5551 | 0 | if ((v & 0x8080808080808080) == 0) { |
5552 | 0 | size_t final_pos = pos + 16; |
5553 | 0 | while (pos < final_pos) { |
5554 | 0 | *utf32_output++ = uint8_t(data[pos]); |
5555 | 0 | pos++; |
5556 | 0 | } |
5557 | 0 | continue; |
5558 | 0 | } |
5559 | 0 | } |
5560 | 0 | } |
5561 | 0 | auto leading_byte = uint8_t(data[pos]); // leading byte |
5562 | 0 | if (leading_byte < 0b10000000) { |
5563 | 0 | // converting one ASCII byte !!! |
5564 | 0 | *utf32_output++ = char32_t(leading_byte); |
5565 | 0 | pos++; |
5566 | 0 | } else if ((leading_byte & 0b11100000) == 0b11000000) { |
5567 | 0 | // We have a two-byte UTF-8 |
5568 | 0 | if (pos + 1 >= len) { |
5569 | 0 | return result(error_code::TOO_SHORT, pos); |
5570 | 0 | } // minimal bound checking |
5571 | 0 | if ((uint8_t(data[pos + 1]) & 0b11000000) != 0b10000000) { |
5572 | 0 | return result(error_code::TOO_SHORT, pos); |
5573 | 0 | } |
5574 | 0 | // range check |
5575 | 0 | uint32_t code_point = (leading_byte & 0b00011111) << 6 | |
5576 | 0 | (uint8_t(data[pos + 1]) & 0b00111111); |
5577 | 0 | if (code_point < 0x80) { |
5578 | 0 | return result(error_code::OVERLONG, pos); |
5579 | 0 | } |
5580 | 0 | *utf32_output++ = char32_t(code_point); |
5581 | 0 | pos += 2; |
5582 | 0 | } else if ((leading_byte & 0b11110000) == 0b11100000) { |
5583 | 0 | // We have a three-byte UTF-8 |
5584 | 0 | if (pos + 2 >= len) { |
5585 | 0 | return result(error_code::TOO_SHORT, pos); |
5586 | 0 | } // minimal bound checking |
5587 | 0 |
|
5588 | 0 | if ((uint8_t(data[pos + 1]) & 0b11000000) != 0b10000000) { |
5589 | 0 | return result(error_code::TOO_SHORT, pos); |
5590 | 0 | } |
5591 | 0 | if ((uint8_t(data[pos + 2]) & 0b11000000) != 0b10000000) { |
5592 | 0 | return result(error_code::TOO_SHORT, pos); |
5593 | 0 | } |
5594 | 0 | // range check |
5595 | 0 | uint32_t code_point = (leading_byte & 0b00001111) << 12 | |
5596 | 0 | (uint8_t(data[pos + 1]) & 0b00111111) << 6 | |
5597 | 0 | (uint8_t(data[pos + 2]) & 0b00111111); |
5598 | 0 | if (code_point < 0x800) { |
5599 | 0 | return result(error_code::OVERLONG, pos); |
5600 | 0 | } |
5601 | 0 | if (0xd7ff < code_point && code_point < 0xe000) { |
5602 | 0 | return result(error_code::SURROGATE, pos); |
5603 | 0 | } |
5604 | 0 | *utf32_output++ = char32_t(code_point); |
5605 | 0 | pos += 3; |
5606 | 0 | } else if ((leading_byte & 0b11111000) == 0b11110000) { // 0b11110000 |
5607 | 0 | // we have a 4-byte UTF-8 word. |
5608 | 0 | if (pos + 3 >= len) { |
5609 | 0 | return result(error_code::TOO_SHORT, pos); |
5610 | 0 | } // minimal bound checking |
5611 | 0 | if ((uint8_t(data[pos + 1]) & 0b11000000) != 0b10000000) { |
5612 | 0 | return result(error_code::TOO_SHORT, pos); |
5613 | 0 | } |
5614 | 0 | if ((uint8_t(data[pos + 2]) & 0b11000000) != 0b10000000) { |
5615 | 0 | return result(error_code::TOO_SHORT, pos); |
5616 | 0 | } |
5617 | 0 | if ((uint8_t(data[pos + 3]) & 0b11000000) != 0b10000000) { |
5618 | 0 | return result(error_code::TOO_SHORT, pos); |
5619 | 0 | } |
5620 | 0 |
|
5621 | 0 | // range check |
5622 | 0 | uint32_t code_point = (leading_byte & 0b00000111) << 18 | |
5623 | 0 | (uint8_t(data[pos + 1]) & 0b00111111) << 12 | |
5624 | 0 | (uint8_t(data[pos + 2]) & 0b00111111) << 6 | |
5625 | 0 | (uint8_t(data[pos + 3]) & 0b00111111); |
5626 | 0 | if (code_point <= 0xffff) { |
5627 | 0 | return result(error_code::OVERLONG, pos); |
5628 | 0 | } |
5629 | 0 | if (0x10ffff < code_point) { |
5630 | 0 | return result(error_code::TOO_LARGE, pos); |
5631 | 0 | } |
5632 | 0 | *utf32_output++ = char32_t(code_point); |
5633 | 0 | pos += 4; |
5634 | 0 | } else { |
5635 | 0 | // we either have too many continuation bytes or an invalid leading byte |
5636 | 0 | if ((leading_byte & 0b11000000) == 0b10000000) { |
5637 | 0 | return result(error_code::TOO_LONG, pos); |
5638 | 0 | } else { |
5639 | 0 | return result(error_code::HEADER_BITS, pos); |
5640 | 0 | } |
5641 | 0 | } |
5642 | 0 | } |
5643 | 0 | return result(error_code::SUCCESS, utf32_output - start); |
5644 | 0 | } Unexecuted instantiation: parser.cpp:_ZN7simdutf6scalar12_GLOBAL__N_113utf8_to_utf3219convert_with_errorsIPKcQsr7simdutf6detailE22indexes_into_byte_likeIT_EEENS_6resultES6_mPDi Unexecuted instantiation: base64.cpp:_ZN7simdutf6scalar12_GLOBAL__N_113utf8_to_utf3219convert_with_errorsIPKcQsr7simdutf6detailE22indexes_into_byte_likeIT_EEENS_6resultES6_mPDi Unexecuted instantiation: simdutf.cpp:_ZN7simdutf6scalar12_GLOBAL__N_113utf8_to_utf3219convert_with_errorsIPKcQsr7simdutf6detailE22indexes_into_byte_likeIT_EEENS_6resultES6_mPDi |
5645 | | |
5646 | | /** |
5647 | | * When rewind_and_convert_with_errors is called, we are pointing at 'buf' and |
5648 | | * we have up to len input bytes left, and we encountered some error. It is |
5649 | | * possible that the error is at 'buf' exactly, but it could also be in the |
5650 | | * previous bytes location (up to 3 bytes back). |
5651 | | * |
5652 | | * prior_bytes indicates how many bytes, prior to 'buf' may belong to the |
5653 | | * current memory section and can be safely accessed. We prior_bytes to access |
5654 | | * safely up to three bytes before 'buf'. |
5655 | | * |
5656 | | * The caller is responsible to ensure that len > 0. |
5657 | | * |
5658 | | * If the error is believed to have occurred prior to 'buf', the count value |
5659 | | * contain in the result will be SIZE_T - 1, SIZE_T - 2, or SIZE_T - 3. |
5660 | | */ |
5661 | | inline result rewind_and_convert_with_errors(size_t prior_bytes, |
5662 | | const char *buf, size_t len, |
5663 | 0 | char32_t *utf32_output) { |
5664 | 0 | size_t extra_len{0}; |
5665 | 0 | // We potentially need to go back in time and find a leading byte. |
5666 | 0 | size_t how_far_back = 3; // 3 bytes in the past + current position |
5667 | 0 | if (how_far_back > prior_bytes) { |
5668 | 0 | how_far_back = prior_bytes; |
5669 | 0 | } |
5670 | 0 | bool found_leading_bytes{false}; |
5671 | 0 | // important: it is i <= how_far_back and not 'i < how_far_back'. |
5672 | 0 | for (size_t i = 0; i <= how_far_back; i++) { |
5673 | 0 | unsigned char byte = buf[-static_cast<std::ptrdiff_t>(i)]; |
5674 | 0 | found_leading_bytes = ((byte & 0b11000000) != 0b10000000); |
5675 | 0 | if (found_leading_bytes) { |
5676 | 0 | if (i > 0 && byte < 128) { |
5677 | 0 | // If we had to go back and the leading byte is ascii |
5678 | 0 | // then we can stop right away. |
5679 | 0 | return result(error_code::TOO_LONG, 0 - i + 1); |
5680 | 0 | } |
5681 | 0 | buf -= i; |
5682 | 0 | extra_len = i; |
5683 | 0 | break; |
5684 | 0 | } |
5685 | 0 | } |
5686 | 0 | // |
5687 | 0 | // It is possible for this function to return a negative count in its result. |
5688 | 0 | // C++ Standard Section 18.1 defines size_t is in <cstddef> which is described |
5689 | 0 | // in C Standard as <stddef.h>. C Standard Section 4.1.5 defines size_t as an |
5690 | 0 | // unsigned integral type of the result of the sizeof operator |
5691 | 0 | // |
5692 | 0 | // An unsigned type will simply wrap round arithmetically (well defined). |
5693 | 0 | // |
5694 | 0 | if (!found_leading_bytes) { |
5695 | 0 | // If how_far_back == 3, we may have four consecutive continuation bytes!!! |
5696 | 0 | // [....] [continuation] [continuation] [continuation] | [buf is |
5697 | 0 | // continuation] Or we possibly have a stream that does not start with a |
5698 | 0 | // leading byte. |
5699 | 0 | return result(error_code::TOO_LONG, 0 - how_far_back); |
5700 | 0 | } |
5701 | 0 |
|
5702 | 0 | result res = convert_with_errors(buf, len + extra_len, utf32_output); |
5703 | 0 | if (res.error) { |
5704 | 0 | res.count -= extra_len; |
5705 | 0 | } |
5706 | 0 | return res; |
5707 | 0 | } Unexecuted instantiation: parser.cpp:simdutf::scalar::(anonymous namespace)::utf8_to_utf32::rewind_and_convert_with_errors(unsigned long, char const*, unsigned long, char32_t*) Unexecuted instantiation: base64.cpp:simdutf::scalar::(anonymous namespace)::utf8_to_utf32::rewind_and_convert_with_errors(unsigned long, char const*, unsigned long, char32_t*) Unexecuted instantiation: simdutf.cpp:simdutf::scalar::(anonymous namespace)::utf8_to_utf32::rewind_and_convert_with_errors(unsigned long, char const*, unsigned long, char32_t*) |
5708 | | |
5709 | | } // namespace utf8_to_utf32 |
5710 | | } // unnamed namespace |
5711 | | } // namespace scalar |
5712 | | } // namespace simdutf |
5713 | | |
5714 | | #endif |
5715 | | /* end file include/simdutf/scalar/utf8_to_utf32/utf8_to_utf32.h */ |
5716 | | /* begin file include/simdutf/scalar/utf8_to_utf32/valid_utf8_to_utf32.h */ |
5717 | | #ifndef SIMDUTF_VALID_UTF8_TO_UTF32_H |
5718 | | #define SIMDUTF_VALID_UTF8_TO_UTF32_H |
5719 | | |
5720 | | #include <cstring> |
5721 | | |
5722 | | namespace simdutf { |
5723 | | namespace scalar { |
5724 | | namespace { |
5725 | | namespace utf8_to_utf32 { |
5726 | | |
5727 | | template <typename InputPtr> |
5728 | | #if SIMDUTF_CPLUSPLUS20 |
5729 | | requires simdutf::detail::indexes_into_byte_like<InputPtr> |
5730 | | #endif |
5731 | | simdutf_constexpr23 size_t convert_valid(InputPtr data, size_t len, |
5732 | | char32_t *utf32_output) { |
5733 | | size_t pos = 0; |
5734 | | char32_t *start{utf32_output}; |
5735 | | while (pos < len) { |
5736 | | #if SIMDUTF_CPLUSPLUS23 |
5737 | | if !consteval |
5738 | | #endif |
5739 | | { |
5740 | | // try to convert the next block of 8 ASCII bytes |
5741 | | if (pos + 8 <= len) { // if it is safe to read 8 more bytes, check that |
5742 | | // they are ascii |
5743 | | uint64_t v; |
5744 | | ::memcpy(&v, data + pos, sizeof(uint64_t)); |
5745 | | if ((v & 0x8080808080808080) == 0) { |
5746 | | size_t final_pos = pos + 8; |
5747 | | while (pos < final_pos) { |
5748 | | *utf32_output++ = uint8_t(data[pos]); |
5749 | | pos++; |
5750 | | } |
5751 | | continue; |
5752 | | } |
5753 | | } |
5754 | | } |
5755 | | auto leading_byte = uint8_t(data[pos]); // leading byte |
5756 | | if (leading_byte < 0b10000000) { |
5757 | | // converting one ASCII byte !!! |
5758 | | *utf32_output++ = char32_t(leading_byte); |
5759 | | pos++; |
5760 | | } else if ((leading_byte & 0b11100000) == 0b11000000) { |
5761 | | // We have a two-byte UTF-8 |
5762 | | if (pos + 1 >= len) { |
5763 | | break; |
5764 | | } // minimal bound checking |
5765 | | *utf32_output++ = char32_t(((leading_byte & 0b00011111) << 6) | |
5766 | | (uint8_t(data[pos + 1]) & 0b00111111)); |
5767 | | pos += 2; |
5768 | | } else if ((leading_byte & 0b11110000) == 0b11100000) { |
5769 | | // We have a three-byte UTF-8 |
5770 | | if (pos + 2 >= len) { |
5771 | | break; |
5772 | | } // minimal bound checking |
5773 | | *utf32_output++ = char32_t(((leading_byte & 0b00001111) << 12) | |
5774 | | ((uint8_t(data[pos + 1]) & 0b00111111) << 6) | |
5775 | | (uint8_t(data[pos + 2]) & 0b00111111)); |
5776 | | pos += 3; |
5777 | | } else if ((leading_byte & 0b11111000) == 0b11110000) { // 0b11110000 |
5778 | | // we have a 4-byte UTF-8 word. |
5779 | | if (pos + 3 >= len) { |
5780 | | break; |
5781 | | } // minimal bound checking |
5782 | | uint32_t code_word = ((leading_byte & 0b00000111) << 18) | |
5783 | | ((uint8_t(data[pos + 1]) & 0b00111111) << 12) | |
5784 | | ((uint8_t(data[pos + 2]) & 0b00111111) << 6) | |
5785 | | (uint8_t(data[pos + 3]) & 0b00111111); |
5786 | | *utf32_output++ = char32_t(code_word); |
5787 | | pos += 4; |
5788 | | } else { |
5789 | | // we may have a continuation but we do not do error checking |
5790 | | return 0; |
5791 | | } |
5792 | | } |
5793 | | return utf32_output - start; |
5794 | | } |
5795 | | |
5796 | | } // namespace utf8_to_utf32 |
5797 | | } // unnamed namespace |
5798 | | } // namespace scalar |
5799 | | } // namespace simdutf |
5800 | | |
5801 | | #endif |
5802 | | /* end file include/simdutf/scalar/utf8_to_utf32/valid_utf8_to_utf32.h */ |
5803 | | |
5804 | | namespace simdutf { |
5805 | | |
5806 | | constexpr size_t default_line_length = |
5807 | | 76; ///< default line length for base64 encoding with lines |
5808 | | |
5809 | | #if SIMDUTF_FEATURE_DETECT_ENCODING |
5810 | | /** |
5811 | | * Autodetect the encoding of the input, a single encoding is recommended. |
5812 | | * E.g., the function might return simdutf::encoding_type::UTF8, |
5813 | | * simdutf::encoding_type::UTF16_LE, simdutf::encoding_type::UTF16_BE, or |
5814 | | * simdutf::encoding_type::UTF32_LE. |
5815 | | * |
5816 | | * @param input the string to analyze. |
5817 | | * @param length the length of the string in bytes. |
5818 | | * @return the detected encoding type |
5819 | | */ |
5820 | | simdutf_warn_unused simdutf::encoding_type |
5821 | | autodetect_encoding(const char *input, size_t length) noexcept; |
5822 | | simdutf_really_inline simdutf_warn_unused simdutf::encoding_type |
5823 | | autodetect_encoding(const uint8_t *input, size_t length) noexcept { |
5824 | | return autodetect_encoding(reinterpret_cast<const char *>(input), length); |
5825 | | } |
5826 | | #if SIMDUTF_SPAN |
5827 | | /** |
5828 | | * Autodetect the encoding of the input, a single encoding is recommended. |
5829 | | * E.g., the function might return simdutf::encoding_type::UTF8, |
5830 | | * simdutf::encoding_type::UTF16_LE, simdutf::encoding_type::UTF16_BE, or |
5831 | | * simdutf::encoding_type::UTF32_LE. |
5832 | | * |
5833 | | * @param input the string to analyze. can be a anything span-like that has a |
5834 | | * data() and size() that points to character data: std::string, |
5835 | | * std::string_view, std::vector<char>, std::span<const std::byte> etc. |
5836 | | * @return the detected encoding type |
5837 | | */ |
5838 | | simdutf_really_inline simdutf_warn_unused simdutf::encoding_type |
5839 | | autodetect_encoding( |
5840 | | const detail::input_span_of_byte_like auto &input) noexcept { |
5841 | | return autodetect_encoding(reinterpret_cast<const char *>(input.data()), |
5842 | | input.size()); |
5843 | | } |
5844 | | #endif // SIMDUTF_SPAN |
5845 | | |
5846 | | /** |
5847 | | * Autodetect the possible encodings of the input in one pass. |
5848 | | * E.g., if the input might be UTF-16LE or UTF-8, this function returns |
5849 | | * the value (simdutf::encoding_type::UTF8 | simdutf::encoding_type::UTF16_LE). |
5850 | | * |
5851 | | * Overridden by each implementation. |
5852 | | * |
5853 | | * @param input the string to analyze. |
5854 | | * @param length the length of the string in bytes. |
5855 | | * @return the detected encoding type |
5856 | | */ |
5857 | | simdutf_warn_unused int detect_encodings(const char *input, |
5858 | | size_t length) noexcept; |
5859 | | simdutf_really_inline simdutf_warn_unused int |
5860 | | detect_encodings(const uint8_t *input, size_t length) noexcept { |
5861 | | return detect_encodings(reinterpret_cast<const char *>(input), length); |
5862 | | } |
5863 | | #if SIMDUTF_SPAN |
5864 | | simdutf_really_inline simdutf_warn_unused int |
5865 | | detect_encodings(const detail::input_span_of_byte_like auto &input) noexcept { |
5866 | | return detect_encodings(reinterpret_cast<const char *>(input.data()), |
5867 | | input.size()); |
5868 | | } |
5869 | | #endif // SIMDUTF_SPAN |
5870 | | #endif // SIMDUTF_FEATURE_DETECT_ENCODING |
5871 | | |
5872 | | #if SIMDUTF_FEATURE_UTF8 || SIMDUTF_FEATURE_DETECT_ENCODING |
5873 | | /** |
5874 | | * Validate the UTF-8 string. This function may be best when you expect |
5875 | | * the input to be almost always valid. Otherwise, consider using |
5876 | | * validate_utf8_with_errors. |
5877 | | * |
5878 | | * Overridden by each implementation. |
5879 | | * |
5880 | | * @param buf the UTF-8 string to validate. |
5881 | | * @param len the length of the string in bytes. |
5882 | | * @return true if and only if the string is valid UTF-8. |
5883 | | */ |
5884 | | simdutf_warn_unused bool validate_utf8(const char *buf, size_t len) noexcept; |
5885 | | #if SIMDUTF_SPAN |
5886 | | simdutf_constexpr23 simdutf_really_inline simdutf_warn_unused bool |
5887 | | validate_utf8(const detail::input_span_of_byte_like auto &input) noexcept { |
5888 | | #if SIMDUTF_CPLUSPLUS23 |
5889 | | if consteval { |
5890 | | return scalar::utf8::validate( |
5891 | | detail::constexpr_cast_ptr<uint8_t>(input.data()), input.size()); |
5892 | | } else |
5893 | | #endif |
5894 | | { |
5895 | | return validate_utf8(reinterpret_cast<const char *>(input.data()), |
5896 | | input.size()); |
5897 | | } |
5898 | | } |
5899 | | #endif // SIMDUTF_SPAN |
5900 | | #endif // SIMDUTF_FEATURE_UTF8 || SIMDUTF_FEATURE_DETECT_ENCODING |
5901 | | |
5902 | | #if SIMDUTF_FEATURE_UTF8 |
5903 | | /** |
5904 | | * Validate the UTF-8 string and stop on error. |
5905 | | * |
5906 | | * Overridden by each implementation. |
5907 | | * |
5908 | | * @param buf the UTF-8 string to validate. |
5909 | | * @param len the length of the string in bytes. |
5910 | | * @return a result pair struct (of type simdutf::result containing the two |
5911 | | * fields error and count) with an error code and either position of the error |
5912 | | * (in the input in code units) if any, or the number of code units validated if |
5913 | | * successful. |
5914 | | */ |
5915 | | simdutf_warn_unused result validate_utf8_with_errors(const char *buf, |
5916 | | size_t len) noexcept; |
5917 | | #if SIMDUTF_SPAN |
5918 | | simdutf_really_inline simdutf_constexpr23 simdutf_warn_unused result |
5919 | | validate_utf8_with_errors( |
5920 | | const detail::input_span_of_byte_like auto &input) noexcept { |
5921 | | #if SIMDUTF_CPLUSPLUS23 |
5922 | | if consteval { |
5923 | | return scalar::utf8::validate_with_errors( |
5924 | | detail::constexpr_cast_ptr<uint8_t>(input.data()), input.size()); |
5925 | | } else |
5926 | | #endif |
5927 | | { |
5928 | | return validate_utf8_with_errors( |
5929 | | reinterpret_cast<const char *>(input.data()), input.size()); |
5930 | | } |
5931 | | } |
5932 | | #endif // SIMDUTF_SPAN |
5933 | | #endif // SIMDUTF_FEATURE_UTF8 |
5934 | | |
5935 | | #if SIMDUTF_FEATURE_UTF8 |
5936 | | /** |
5937 | | * Validate the UTF-8 string and stop on error, while counting the number of |
5938 | | * continuation bytes and of four-byte sequences in the valid prefix. |
5939 | | * |
5940 | | * Overridden by each implementation. |
5941 | | * |
5942 | | * These two counts are enough to derive, without a second pass over the input, |
5943 | | * both the number of code points (input_count - continuation_count) and the |
5944 | | * number of UTF-16 code units (input_count - continuation_count + |
5945 | | * four_byte_count) of the valid prefix. The utf32_length() and utf16_length() |
5946 | | * helpers return them. |
5947 | | * |
5948 | | * @param buf the UTF-8 string to validate. |
5949 | | * @param len the length of the string in bytes. |
5950 | | * @return a utf8_result struct with an error code, the number of bytes in the |
5951 | | * valid prefix (input_count), and the counts of continuation bytes and of |
5952 | | * four-byte sequences within it. |
5953 | | */ |
5954 | | simdutf_warn_unused utf8_result validate_utf8_with_counts(const char *buf, |
5955 | | size_t len) noexcept; |
5956 | | #if SIMDUTF_SPAN |
5957 | | simdutf_really_inline simdutf_constexpr23 simdutf_warn_unused utf8_result |
5958 | | validate_utf8_with_counts( |
5959 | | const detail::input_span_of_byte_like auto &input) noexcept { |
5960 | | #if SIMDUTF_CPLUSPLUS23 |
5961 | | if consteval { |
5962 | | return scalar::utf8::validate_with_counts( |
5963 | | detail::constexpr_cast_ptr<uint8_t>(input.data()), input.size()); |
5964 | | } else |
5965 | | #endif |
5966 | | { |
5967 | | return validate_utf8_with_counts( |
5968 | | reinterpret_cast<const char *>(input.data()), input.size()); |
5969 | | } |
5970 | | } |
5971 | | #endif // SIMDUTF_SPAN |
5972 | | #endif // SIMDUTF_FEATURE_UTF8 |
5973 | | |
5974 | | #if SIMDUTF_FEATURE_ASCII |
5975 | | /** |
5976 | | * Validate the ASCII string. |
5977 | | * |
5978 | | * Overridden by each implementation. |
5979 | | * |
5980 | | * @param buf the ASCII string to validate. |
5981 | | * @param len the length of the string in bytes. |
5982 | | * @return true if and only if the string is valid ASCII. |
5983 | | */ |
5984 | | simdutf_warn_unused bool validate_ascii(const char *buf, size_t len) noexcept; |
5985 | | #if SIMDUTF_SPAN |
5986 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 bool |
5987 | | validate_ascii(const detail::input_span_of_byte_like auto &input) noexcept { |
5988 | | #if SIMDUTF_CPLUSPLUS23 |
5989 | | if consteval { |
5990 | | return scalar::ascii::validate( |
5991 | | detail::constexpr_cast_ptr<std::uint8_t>(input.data()), input.size()); |
5992 | | } else |
5993 | | #endif |
5994 | | { |
5995 | | return validate_ascii(reinterpret_cast<const char *>(input.data()), |
5996 | | input.size()); |
5997 | | } |
5998 | | } |
5999 | | #endif // SIMDUTF_SPAN |
6000 | | |
6001 | | /** |
6002 | | * Validate the ASCII string and stop on error. It might be faster than |
6003 | | * validate_utf8 when an error is expected to occur early. |
6004 | | * |
6005 | | * Overridden by each implementation. |
6006 | | * |
6007 | | * @param buf the ASCII string to validate. |
6008 | | * @param len the length of the string in bytes. |
6009 | | * @return a result pair struct (of type simdutf::result containing the two |
6010 | | * fields error and count) with an error code and either position of the error |
6011 | | * (in the input in code units) if any, or the number of code units validated if |
6012 | | * successful. |
6013 | | */ |
6014 | | simdutf_warn_unused result validate_ascii_with_errors(const char *buf, |
6015 | | size_t len) noexcept; |
6016 | | #if SIMDUTF_SPAN |
6017 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result |
6018 | | validate_ascii_with_errors( |
6019 | | const detail::input_span_of_byte_like auto &input) noexcept { |
6020 | | #if SIMDUTF_CPLUSPLUS23 |
6021 | | if consteval { |
6022 | | return scalar::ascii::validate_with_errors( |
6023 | | detail::constexpr_cast_ptr<std::uint8_t>(input.data()), input.size()); |
6024 | | } else |
6025 | | #endif |
6026 | | { |
6027 | | return validate_ascii_with_errors( |
6028 | | reinterpret_cast<const char *>(input.data()), input.size()); |
6029 | | } |
6030 | | } |
6031 | | #endif // SIMDUTF_SPAN |
6032 | | #endif // SIMDUTF_FEATURE_ASCII |
6033 | | |
6034 | | #if SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_ASCII |
6035 | | /** |
6036 | | * Validate the ASCII string as a UTF-16 sequence. |
6037 | | * An UTF-16 sequence is considered an ASCII sequence |
6038 | | * if it could be converted to an ASCII string losslessly. |
6039 | | * |
6040 | | * Overridden by each implementation. |
6041 | | * |
6042 | | * @param buf the UTF-16 string to validate. |
6043 | | * @param len the length of the string in bytes. |
6044 | | * @return true if and only if the string is valid ASCII. |
6045 | | */ |
6046 | | simdutf_warn_unused bool validate_utf16_as_ascii(const char16_t *buf, |
6047 | | size_t len) noexcept; |
6048 | | #if SIMDUTF_SPAN |
6049 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 bool |
6050 | | validate_utf16_as_ascii(std::span<const char16_t> input) noexcept { |
6051 | | #if SIMDUTF_CPLUSPLUS23 |
6052 | | if consteval { |
6053 | | return scalar::utf16::validate_as_ascii<endianness::NATIVE>(input.data(), |
6054 | | input.size()); |
6055 | | } else |
6056 | | #endif |
6057 | | { |
6058 | | return validate_utf16_as_ascii(input.data(), input.size()); |
6059 | | } |
6060 | | } |
6061 | | #endif // SIMDUTF_SPAN |
6062 | | |
6063 | | /** |
6064 | | * Validate the ASCII string as a UTF-16BE sequence. |
6065 | | * An UTF-16 sequence is considered an ASCII sequence |
6066 | | * if it could be converted to an ASCII string losslessly. |
6067 | | * |
6068 | | * Overridden by each implementation. |
6069 | | * |
6070 | | * @param buf the UTF-16BE string to validate. |
6071 | | * @param len the length of the string in bytes. |
6072 | | * @return true if and only if the string is valid ASCII. |
6073 | | */ |
6074 | | simdutf_warn_unused bool validate_utf16be_as_ascii(const char16_t *buf, |
6075 | | size_t len) noexcept; |
6076 | | #if SIMDUTF_SPAN |
6077 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 bool |
6078 | | validate_utf16be_as_ascii(std::span<const char16_t> input) noexcept { |
6079 | | #if SIMDUTF_CPLUSPLUS23 |
6080 | | if consteval { |
6081 | | return scalar::utf16::validate_as_ascii<endianness::BIG>(input.data(), |
6082 | | input.size()); |
6083 | | } else |
6084 | | #endif |
6085 | | { |
6086 | | return validate_utf16be_as_ascii(input.data(), input.size()); |
6087 | | } |
6088 | | } |
6089 | | #endif // SIMDUTF_SPAN |
6090 | | |
6091 | | /** |
6092 | | * Validate the ASCII string as a UTF-16LE sequence. |
6093 | | * An UTF-16 sequence is considered an ASCII sequence |
6094 | | * if it could be converted to an ASCII string losslessly. |
6095 | | * |
6096 | | * Overridden by each implementation. |
6097 | | * |
6098 | | * @param buf the UTF-16LE string to validate. |
6099 | | * @param len the length of the string in bytes. |
6100 | | * @return true if and only if the string is valid ASCII. |
6101 | | */ |
6102 | | simdutf_warn_unused bool validate_utf16le_as_ascii(const char16_t *buf, |
6103 | | size_t len) noexcept; |
6104 | | #if SIMDUTF_SPAN |
6105 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 bool |
6106 | | validate_utf16le_as_ascii(std::span<const char16_t> input) noexcept { |
6107 | | #if SIMDUTF_CPLUSPLUS23 |
6108 | | if consteval { |
6109 | | return scalar::utf16::validate_as_ascii<endianness::LITTLE>(input.data(), |
6110 | | input.size()); |
6111 | | } else |
6112 | | #endif |
6113 | | { |
6114 | | return validate_utf16le_as_ascii(input.data(), input.size()); |
6115 | | } |
6116 | | } |
6117 | | #endif // SIMDUTF_SPAN |
6118 | | #endif // SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_ASCII |
6119 | | |
6120 | | #if SIMDUTF_FEATURE_UTF16 |
6121 | | /** |
6122 | | * Using native endianness; Validate the UTF-16 string. |
6123 | | * This function may be best when you expect the input to be almost always |
6124 | | * valid. Otherwise, consider using validate_utf16_with_errors. |
6125 | | * |
6126 | | * Overridden by each implementation. |
6127 | | * |
6128 | | * This function is not BOM-aware. |
6129 | | * |
6130 | | * @param buf the UTF-16 string to validate. |
6131 | | * @param len the length of the string in number of 2-byte code units |
6132 | | * (char16_t). |
6133 | | * @return true if and only if the string is valid UTF-16. |
6134 | | */ |
6135 | | simdutf_warn_unused bool validate_utf16(const char16_t *buf, |
6136 | | size_t len) noexcept; |
6137 | | #if SIMDUTF_SPAN |
6138 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 bool |
6139 | | validate_utf16(std::span<const char16_t> input) noexcept { |
6140 | | #if SIMDUTF_CPLUSPLUS23 |
6141 | | if consteval { |
6142 | | return scalar::utf16::validate<endianness::NATIVE>(input.data(), |
6143 | | input.size()); |
6144 | | } else |
6145 | | #endif |
6146 | | { |
6147 | | return validate_utf16(input.data(), input.size()); |
6148 | | } |
6149 | | } |
6150 | | #endif // SIMDUTF_SPAN |
6151 | | #endif // SIMDUTF_FEATURE_UTF16 |
6152 | | |
6153 | | #if SIMDUTF_FEATURE_UTF16 || SIMDUTF_FEATURE_DETECT_ENCODING |
6154 | | /** |
6155 | | * Validate the UTF-16LE string. This function may be best when you expect |
6156 | | * the input to be almost always valid. Otherwise, consider using |
6157 | | * validate_utf16le_with_errors. |
6158 | | * |
6159 | | * Overridden by each implementation. |
6160 | | * |
6161 | | * This function is not BOM-aware. |
6162 | | * |
6163 | | * @param buf the UTF-16LE string to validate. |
6164 | | * @param len the length of the string in number of 2-byte code units |
6165 | | * (char16_t). |
6166 | | * @return true if and only if the string is valid UTF-16LE. |
6167 | | */ |
6168 | | simdutf_warn_unused bool validate_utf16le(const char16_t *buf, |
6169 | | size_t len) noexcept; |
6170 | | #if SIMDUTF_SPAN |
6171 | | simdutf_really_inline simdutf_constexpr23 simdutf_warn_unused bool |
6172 | | validate_utf16le(std::span<const char16_t> input) noexcept { |
6173 | | #if SIMDUTF_CPLUSPLUS23 |
6174 | | if consteval { |
6175 | | return scalar::utf16::validate<endianness::LITTLE>(input.data(), |
6176 | | input.size()); |
6177 | | } else |
6178 | | #endif |
6179 | | { |
6180 | | return validate_utf16le(input.data(), input.size()); |
6181 | | } |
6182 | | } |
6183 | | #endif // SIMDUTF_SPAN |
6184 | | #endif // SIMDUTF_FEATURE_UTF16 || SIMDUTF_FEATURE_DETECT_ENCODING |
6185 | | |
6186 | | #if SIMDUTF_FEATURE_UTF16 |
6187 | | /** |
6188 | | * Validate the UTF-16BE string. This function may be best when you expect |
6189 | | * the input to be almost always valid. Otherwise, consider using |
6190 | | * validate_utf16be_with_errors. |
6191 | | * |
6192 | | * Overridden by each implementation. |
6193 | | * |
6194 | | * This function is not BOM-aware. |
6195 | | * |
6196 | | * @param buf the UTF-16BE string to validate. |
6197 | | * @param len the length of the string in number of 2-byte code units |
6198 | | * (char16_t). |
6199 | | * @return true if and only if the string is valid UTF-16BE. |
6200 | | */ |
6201 | | simdutf_warn_unused bool validate_utf16be(const char16_t *buf, |
6202 | | size_t len) noexcept; |
6203 | | #if SIMDUTF_SPAN |
6204 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 bool |
6205 | | validate_utf16be(std::span<const char16_t> input) noexcept { |
6206 | | #if SIMDUTF_CPLUSPLUS23 |
6207 | | if consteval { |
6208 | | return scalar::utf16::validate<endianness::BIG>(input.data(), input.size()); |
6209 | | } else |
6210 | | #endif |
6211 | | { |
6212 | | return validate_utf16be(input.data(), input.size()); |
6213 | | } |
6214 | | } |
6215 | | #endif // SIMDUTF_SPAN |
6216 | | |
6217 | | /** |
6218 | | * Using native endianness; Validate the UTF-16 string and stop on error. |
6219 | | * It might be faster than validate_utf16 when an error is expected to occur |
6220 | | * early. |
6221 | | * |
6222 | | * Overridden by each implementation. |
6223 | | * |
6224 | | * This function is not BOM-aware. |
6225 | | * |
6226 | | * @param buf the UTF-16 string to validate. |
6227 | | * @param len the length of the string in number of 2-byte code units |
6228 | | * (char16_t). |
6229 | | * @return a result pair struct (of type simdutf::result containing the two |
6230 | | * fields error and count) with an error code and either position of the error |
6231 | | * (in the input in code units) if any, or the number of code units validated if |
6232 | | * successful. |
6233 | | */ |
6234 | | simdutf_warn_unused result validate_utf16_with_errors(const char16_t *buf, |
6235 | | size_t len) noexcept; |
6236 | | #if SIMDUTF_SPAN |
6237 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result |
6238 | | validate_utf16_with_errors(std::span<const char16_t> input) noexcept { |
6239 | | #if SIMDUTF_CPLUSPLUS23 |
6240 | | if consteval { |
6241 | | return scalar::utf16::validate_with_errors<endianness::NATIVE>( |
6242 | | input.data(), input.size()); |
6243 | | } else |
6244 | | #endif |
6245 | | { |
6246 | | return validate_utf16_with_errors(input.data(), input.size()); |
6247 | | } |
6248 | | } |
6249 | | #endif // SIMDUTF_SPAN |
6250 | | |
6251 | | /** |
6252 | | * Validate the UTF-16LE string and stop on error. It might be faster than |
6253 | | * validate_utf16le when an error is expected to occur early. |
6254 | | * |
6255 | | * Overridden by each implementation. |
6256 | | * |
6257 | | * This function is not BOM-aware. |
6258 | | * |
6259 | | * @param buf the UTF-16LE string to validate. |
6260 | | * @param len the length of the string in number of 2-byte code units |
6261 | | * (char16_t). |
6262 | | * @return a result pair struct (of type simdutf::result containing the two |
6263 | | * fields error and count) with an error code and either position of the error |
6264 | | * (in the input in code units) if any, or the number of code units validated if |
6265 | | * successful. |
6266 | | */ |
6267 | | simdutf_warn_unused result validate_utf16le_with_errors(const char16_t *buf, |
6268 | | size_t len) noexcept; |
6269 | | #if SIMDUTF_SPAN |
6270 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result |
6271 | | validate_utf16le_with_errors(std::span<const char16_t> input) noexcept { |
6272 | | #if SIMDUTF_CPLUSPLUS23 |
6273 | | if consteval { |
6274 | | return scalar::utf16::validate_with_errors<endianness::LITTLE>( |
6275 | | input.data(), input.size()); |
6276 | | } else |
6277 | | #endif |
6278 | | { |
6279 | | return validate_utf16le_with_errors(input.data(), input.size()); |
6280 | | } |
6281 | | } |
6282 | | #endif // SIMDUTF_SPAN |
6283 | | |
6284 | | /** |
6285 | | * Validate the UTF-16BE string and stop on error. It might be faster than |
6286 | | * validate_utf16be when an error is expected to occur early. |
6287 | | * |
6288 | | * Overridden by each implementation. |
6289 | | * |
6290 | | * This function is not BOM-aware. |
6291 | | * |
6292 | | * @param buf the UTF-16BE string to validate. |
6293 | | * @param len the length of the string in number of 2-byte code units |
6294 | | * (char16_t). |
6295 | | * @return a result pair struct (of type simdutf::result containing the two |
6296 | | * fields error and count) with an error code and either position of the error |
6297 | | * (in the input in code units) if any, or the number of code units validated if |
6298 | | * successful. |
6299 | | */ |
6300 | | simdutf_warn_unused result validate_utf16be_with_errors(const char16_t *buf, |
6301 | | size_t len) noexcept; |
6302 | | #if SIMDUTF_SPAN |
6303 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result |
6304 | | validate_utf16be_with_errors(std::span<const char16_t> input) noexcept { |
6305 | | #if SIMDUTF_CPLUSPLUS23 |
6306 | | if consteval { |
6307 | | return scalar::utf16::validate_with_errors<endianness::BIG>(input.data(), |
6308 | | input.size()); |
6309 | | } else |
6310 | | #endif |
6311 | | { |
6312 | | return validate_utf16be_with_errors(input.data(), input.size()); |
6313 | | } |
6314 | | } |
6315 | | #endif // SIMDUTF_SPAN |
6316 | | |
6317 | | /** |
6318 | | * Fixes an ill-formed UTF-16LE string by replacing mismatched surrogates with |
6319 | | * the Unicode replacement character U+FFFD. If input and output points to |
6320 | | * different memory areas, the procedure copies string, and it's expected that |
6321 | | * output memory is at least as big as the input. It's also possible to set |
6322 | | * input equal output, that makes replacements an in-place operation. |
6323 | | * |
6324 | | * @param input the UTF-16LE string to correct. |
6325 | | * @param len the length of the string in number of 2-byte code units |
6326 | | * (char16_t). |
6327 | | * @param output the output buffer. |
6328 | | */ |
6329 | | void to_well_formed_utf16le(const char16_t *input, size_t len, |
6330 | | char16_t *output) noexcept; |
6331 | | #if SIMDUTF_SPAN |
6332 | | simdutf_really_inline simdutf_constexpr23 void |
6333 | | to_well_formed_utf16le(std::span<const char16_t> input, |
6334 | | std::span<char16_t> output) noexcept { |
6335 | | #if SIMDUTF_CPLUSPLUS23 |
6336 | | if consteval { |
6337 | | scalar::utf16::to_well_formed_utf16<endianness::LITTLE>( |
6338 | | input.data(), input.size(), output.data()); |
6339 | | } else |
6340 | | #endif |
6341 | | { |
6342 | | to_well_formed_utf16le(input.data(), input.size(), output.data()); |
6343 | | } |
6344 | | } |
6345 | | #endif // SIMDUTF_SPAN |
6346 | | |
6347 | | /** |
6348 | | * Fixes an ill-formed UTF-16BE string by replacing mismatched surrogates with |
6349 | | * the Unicode replacement character U+FFFD. If input and output points to |
6350 | | * different memory areas, the procedure copies string, and it's expected that |
6351 | | * output memory is at least as big as the input. It's also possible to set |
6352 | | * input equal output, that makes replacements an in-place operation. |
6353 | | * |
6354 | | * @param input the UTF-16BE string to correct. |
6355 | | * @param len the length of the string in number of 2-byte code units |
6356 | | * (char16_t). |
6357 | | * @param output the output buffer. |
6358 | | */ |
6359 | | void to_well_formed_utf16be(const char16_t *input, size_t len, |
6360 | | char16_t *output) noexcept; |
6361 | | #if SIMDUTF_SPAN |
6362 | | simdutf_really_inline simdutf_constexpr23 void |
6363 | | to_well_formed_utf16be(std::span<const char16_t> input, |
6364 | | std::span<char16_t> output) noexcept { |
6365 | | #if SIMDUTF_CPLUSPLUS23 |
6366 | | if consteval { |
6367 | | scalar::utf16::to_well_formed_utf16<endianness::BIG>( |
6368 | | input.data(), input.size(), output.data()); |
6369 | | } else |
6370 | | #endif |
6371 | | { |
6372 | | to_well_formed_utf16be(input.data(), input.size(), output.data()); |
6373 | | } |
6374 | | } |
6375 | | #endif // SIMDUTF_SPAN |
6376 | | |
6377 | | /** |
6378 | | * Fixes an ill-formed UTF-16 string by replacing mismatched surrogates with the |
6379 | | * Unicode replacement character U+FFFD. If input and output points to different |
6380 | | * memory areas, the procedure copies string, and it's expected that output |
6381 | | * memory is at least as big as the input. It's also possible to set input equal |
6382 | | * output, that makes replacements an in-place operation. |
6383 | | * |
6384 | | * @param input the UTF-16 string to correct. |
6385 | | * @param len the length of the string in number of 2-byte code units |
6386 | | * (char16_t). |
6387 | | * @param output the output buffer. |
6388 | | */ |
6389 | | void to_well_formed_utf16(const char16_t *input, size_t len, |
6390 | | char16_t *output) noexcept; |
6391 | | #if SIMDUTF_SPAN |
6392 | | simdutf_really_inline simdutf_constexpr23 void |
6393 | | to_well_formed_utf16(std::span<const char16_t> input, |
6394 | | std::span<char16_t> output) noexcept { |
6395 | | #if SIMDUTF_CPLUSPLUS23 |
6396 | | if consteval { |
6397 | | scalar::utf16::to_well_formed_utf16<endianness::NATIVE>( |
6398 | | input.data(), input.size(), output.data()); |
6399 | | } else |
6400 | | #endif |
6401 | | { |
6402 | | to_well_formed_utf16(input.data(), input.size(), output.data()); |
6403 | | } |
6404 | | } |
6405 | | #endif // SIMDUTF_SPAN |
6406 | | |
6407 | | #endif // SIMDUTF_FEATURE_UTF16 |
6408 | | |
6409 | | #if SIMDUTF_FEATURE_UTF32 || SIMDUTF_FEATURE_DETECT_ENCODING |
6410 | | /** |
6411 | | * Validate the UTF-32 string. This function may be best when you expect |
6412 | | * the input to be almost always valid. Otherwise, consider using |
6413 | | * validate_utf32_with_errors. |
6414 | | * |
6415 | | * Overridden by each implementation. |
6416 | | * |
6417 | | * This function is not BOM-aware. |
6418 | | * |
6419 | | * @param buf the UTF-32 string to validate. |
6420 | | * @param len the length of the string in number of 4-byte code units |
6421 | | * (char32_t). |
6422 | | * @return true if and only if the string is valid UTF-32. |
6423 | | */ |
6424 | | simdutf_warn_unused bool validate_utf32(const char32_t *buf, |
6425 | | size_t len) noexcept; |
6426 | | #if SIMDUTF_SPAN |
6427 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 bool |
6428 | | validate_utf32(std::span<const char32_t> input) noexcept { |
6429 | | #if SIMDUTF_CPLUSPLUS23 |
6430 | | if consteval { |
6431 | | return scalar::utf32::validate( |
6432 | | detail::constexpr_cast_ptr<std::uint32_t>(input.data()), input.size()); |
6433 | | } else |
6434 | | #endif |
6435 | | { |
6436 | | return validate_utf32(input.data(), input.size()); |
6437 | | } |
6438 | | } |
6439 | | #endif // SIMDUTF_SPAN |
6440 | | #endif // SIMDUTF_FEATURE_UTF32 || SIMDUTF_FEATURE_DETECT_ENCODING |
6441 | | |
6442 | | #if SIMDUTF_FEATURE_UTF32 |
6443 | | /** |
6444 | | * Validate the UTF-32 string and stop on error. It might be faster than |
6445 | | * validate_utf32 when an error is expected to occur early. |
6446 | | * |
6447 | | * Overridden by each implementation. |
6448 | | * |
6449 | | * This function is not BOM-aware. |
6450 | | * |
6451 | | * @param buf the UTF-32 string to validate. |
6452 | | * @param len the length of the string in number of 4-byte code units |
6453 | | * (char32_t). |
6454 | | * @return a result pair struct (of type simdutf::result containing the two |
6455 | | * fields error and count) with an error code and either position of the error |
6456 | | * (in the input in code units) if any, or the number of code units validated if |
6457 | | * successful. |
6458 | | */ |
6459 | | simdutf_warn_unused result validate_utf32_with_errors(const char32_t *buf, |
6460 | | size_t len) noexcept; |
6461 | | #if SIMDUTF_SPAN |
6462 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result |
6463 | | validate_utf32_with_errors(std::span<const char32_t> input) noexcept { |
6464 | | #if SIMDUTF_CPLUSPLUS23 |
6465 | | if consteval { |
6466 | | return scalar::utf32::validate_with_errors( |
6467 | | detail::constexpr_cast_ptr<std::uint32_t>(input.data()), input.size()); |
6468 | | } else |
6469 | | #endif |
6470 | | { |
6471 | | return validate_utf32_with_errors(input.data(), input.size()); |
6472 | | } |
6473 | | } |
6474 | | #endif // SIMDUTF_SPAN |
6475 | | #endif // SIMDUTF_FEATURE_UTF32 |
6476 | | |
6477 | | #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_LATIN1 |
6478 | | /** |
6479 | | * Convert Latin1 string into UTF-8 string. |
6480 | | * |
6481 | | * This function is suitable to work with inputs from untrusted sources. |
6482 | | * |
6483 | | * @param input the Latin1 string to convert |
6484 | | * @param length the length of the string in bytes |
6485 | | * @param utf8_output the pointer to buffer that can hold conversion result |
6486 | | * @return the number of written char; 0 if conversion is not possible |
6487 | | */ |
6488 | | simdutf_warn_unused size_t convert_latin1_to_utf8(const char *input, |
6489 | | size_t length, |
6490 | | char *utf8_output) noexcept; |
6491 | | #if SIMDUTF_SPAN |
6492 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t |
6493 | | convert_latin1_to_utf8( |
6494 | | const detail::input_span_of_byte_like auto &latin1_input, |
6495 | | detail::output_span_of_byte_like auto &&utf8_output) noexcept { |
6496 | | #if SIMDUTF_CPLUSPLUS23 |
6497 | | if consteval { |
6498 | | return scalar::latin1_to_utf8::convert( |
6499 | | detail::constexpr_cast_ptr<char>(latin1_input.data()), |
6500 | | latin1_input.size(), |
6501 | | detail::constexpr_cast_writeptr<char>(utf8_output.data())); |
6502 | | } else |
6503 | | #endif |
6504 | | { |
6505 | | return convert_latin1_to_utf8( |
6506 | | reinterpret_cast<const char *>(latin1_input.data()), |
6507 | | latin1_input.size(), reinterpret_cast<char *>(utf8_output.data())); |
6508 | | } |
6509 | | } |
6510 | | #endif // SIMDUTF_SPAN |
6511 | | |
6512 | | /** |
6513 | | * Convert Latin1 string into UTF-8 string with output limit. |
6514 | | * |
6515 | | * This function is suitable to work with inputs from untrusted sources. |
6516 | | * |
6517 | | * We write as many characters as possible. |
6518 | | * |
6519 | | * Using convert_latin1_to_utf8_safe instead of convert_latin1_to_utf8 comes |
6520 | | * with a significant penalty in some cases, being up to four times slower, |
6521 | | * especially on short inputs. If you have allocated the output buffer so that |
6522 | | * it contains utf8_length_from_latin1(input, length) bytes, then prefer |
6523 | | * convert_latin1_to_utf8. |
6524 | | * |
6525 | | * @param input the Latin1 string to convert |
6526 | | * @param length the length of the string in bytes |
6527 | | * @param utf8_output the pointer to buffer that can hold conversion result |
6528 | | * @param utf8_len the maximum output length |
6529 | | * @return the number of written char; 0 if conversion is not possible |
6530 | | */ |
6531 | | simdutf_warn_unused size_t |
6532 | | convert_latin1_to_utf8_safe(const char *input, size_t length, char *utf8_output, |
6533 | | size_t utf8_len) noexcept; |
6534 | | #if SIMDUTF_SPAN |
6535 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t |
6536 | | convert_latin1_to_utf8_safe( |
6537 | | const detail::input_span_of_byte_like auto &input, |
6538 | | detail::output_span_of_byte_like auto &&utf8_output) noexcept { |
6539 | | // implementation note: outputspan is a forwarding ref to avoid copying |
6540 | | // and allow both lvalues and rvalues. std::span can be copied without |
6541 | | // problems, but std::vector should not, and this function should accept |
6542 | | // both. it will allow using an owning rvalue ref (example: passing a |
6543 | | // temporary std::string) as output, but the user will quickly find out |
6544 | | // that he has no way of getting the data out of the object in that case. |
6545 | | #if SIMDUTF_CPLUSPLUS23 |
6546 | | if consteval { |
6547 | | return scalar::latin1_to_utf8::convert_safe_constexpr( |
6548 | | input.data(), input.size(), utf8_output.data(), utf8_output.size()); |
6549 | | } else |
6550 | | #endif |
6551 | | { |
6552 | | return convert_latin1_to_utf8_safe( |
6553 | | reinterpret_cast<const char *>(input.data()), input.size(), |
6554 | | reinterpret_cast<char *>(utf8_output.data()), utf8_output.size()); |
6555 | | } |
6556 | | } |
6557 | | #endif // SIMDUTF_SPAN |
6558 | | |
6559 | | /** |
6560 | | * Convert a Latin1 string into a size-limited UTF-8 buffer and report how much |
6561 | | * input was consumed and output was written. |
6562 | | * |
6563 | | * We write as many complete characters as possible. The returned error is |
6564 | | * SUCCESS if all input was consumed, or OUTPUT_BUFFER_TOO_SMALL otherwise. |
6565 | | * |
6566 | | * @param input the Latin1 string to convert |
6567 | | * @param length the length of the string in bytes |
6568 | | * @param utf8_output the pointer to the output buffer |
6569 | | * @param utf8_len the maximum output length |
6570 | | * @return a full_result with error, input_count and output_count |
6571 | | */ |
6572 | | simdutf_warn_unused full_result convert_latin1_to_utf8_safe_with_details( |
6573 | | const char *input, size_t length, char *utf8_output, |
6574 | | size_t utf8_len) noexcept; |
6575 | | #if SIMDUTF_SPAN |
6576 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 full_result |
6577 | | convert_latin1_to_utf8_safe_with_details( |
6578 | | const detail::input_span_of_byte_like auto &input, |
6579 | | detail::output_span_of_byte_like auto &&utf8_output) noexcept { |
6580 | | #if SIMDUTF_CPLUSPLUS23 |
6581 | | if consteval { |
6582 | | return scalar::latin1_to_utf8::convert_safe_with_details_constexpr( |
6583 | | input.data(), input.size(), utf8_output.data(), utf8_output.size()); |
6584 | | } else |
6585 | | #endif |
6586 | | { |
6587 | | return convert_latin1_to_utf8_safe_with_details( |
6588 | | reinterpret_cast<const char *>(input.data()), input.size(), |
6589 | | reinterpret_cast<char *>(utf8_output.data()), utf8_output.size()); |
6590 | | } |
6591 | | } |
6592 | | #endif // SIMDUTF_SPAN |
6593 | | #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_LATIN1 |
6594 | | |
6595 | | #if SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_LATIN1 |
6596 | | /** |
6597 | | * Convert possibly Latin1 string into UTF-16LE string. |
6598 | | * |
6599 | | * This function is suitable to work with inputs from untrusted sources. |
6600 | | * |
6601 | | * @param input the Latin1 string to convert |
6602 | | * @param length the length of the string in bytes |
6603 | | * @param utf16_output the pointer to buffer that can hold conversion result |
6604 | | * @return the number of written char16_t; 0 if conversion is not possible |
6605 | | */ |
6606 | | simdutf_warn_unused size_t convert_latin1_to_utf16le( |
6607 | | const char *input, size_t length, char16_t *utf16_output) noexcept; |
6608 | | #if SIMDUTF_SPAN |
6609 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t |
6610 | | convert_latin1_to_utf16le( |
6611 | | const detail::input_span_of_byte_like auto &latin1_input, |
6612 | | std::span<char16_t> utf16_output) noexcept { |
6613 | | #if SIMDUTF_CPLUSPLUS23 |
6614 | | if consteval { |
6615 | | return scalar::latin1_to_utf16::convert<endianness::LITTLE>( |
6616 | | latin1_input.data(), latin1_input.size(), utf16_output.data()); |
6617 | | } else |
6618 | | #endif |
6619 | | { |
6620 | | return convert_latin1_to_utf16le( |
6621 | | reinterpret_cast<const char *>(latin1_input.data()), |
6622 | | latin1_input.size(), utf16_output.data()); |
6623 | | } |
6624 | | } |
6625 | | #endif // SIMDUTF_SPAN |
6626 | | |
6627 | | /** |
6628 | | * Convert Latin1 string into UTF-16BE string. |
6629 | | * |
6630 | | * This function is suitable to work with inputs from untrusted sources. |
6631 | | * |
6632 | | * @param input the Latin1 string to convert |
6633 | | * @param length the length of the string in bytes |
6634 | | * @param utf16_output the pointer to buffer that can hold conversion result |
6635 | | * @return the number of written char16_t; 0 if conversion is not possible |
6636 | | */ |
6637 | | simdutf_warn_unused size_t convert_latin1_to_utf16be( |
6638 | | const char *input, size_t length, char16_t *utf16_output) noexcept; |
6639 | | #if SIMDUTF_SPAN |
6640 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t |
6641 | | convert_latin1_to_utf16be(const detail::input_span_of_byte_like auto &input, |
6642 | | std::span<char16_t> output) noexcept { |
6643 | | #if SIMDUTF_CPLUSPLUS23 |
6644 | | if consteval { |
6645 | | return scalar::latin1_to_utf16::convert<endianness::BIG>( |
6646 | | input.data(), input.size(), output.data()); |
6647 | | } else |
6648 | | #endif |
6649 | | { |
6650 | | return convert_latin1_to_utf16be( |
6651 | | reinterpret_cast<const char *>(input.data()), input.size(), |
6652 | | output.data()); |
6653 | | } |
6654 | | } |
6655 | | #endif // SIMDUTF_SPAN |
6656 | | /** |
6657 | | * Compute the number of bytes that this UTF-16 string would require in Latin1 |
6658 | | * format. |
6659 | | * |
6660 | | * @param length the length of the string in Latin1 code units (char) |
6661 | | * @return the length of the string in Latin1 code units (char) required to |
6662 | | * encode the UTF-16 string as Latin1 |
6663 | | */ |
6664 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t |
6665 | | latin1_length_from_utf16(size_t length) noexcept { |
6666 | | return length; |
6667 | | } |
6668 | | |
6669 | | /** |
6670 | | * Compute the number of code units that this Latin1 string would require in |
6671 | | * UTF-16 format. |
6672 | | * |
6673 | | * @param length the length of the string in Latin1 code units (char) |
6674 | | * @return the length of the string in 2-byte code units (char16_t) required to |
6675 | | * encode the Latin1 string as UTF-16 |
6676 | | */ |
6677 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t |
6678 | | utf16_length_from_latin1(size_t length) noexcept { |
6679 | | return length; |
6680 | | } |
6681 | | #endif // SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_LATIN1 |
6682 | | |
6683 | | #if SIMDUTF_FEATURE_UTF32 && SIMDUTF_FEATURE_LATIN1 |
6684 | | /** |
6685 | | * Convert Latin1 string into UTF-32 string. |
6686 | | * |
6687 | | * This function is suitable to work with inputs from untrusted sources. |
6688 | | * |
6689 | | * @param input the Latin1 string to convert |
6690 | | * @param length the length of the string in bytes |
6691 | | * @param utf32_buffer the pointer to buffer that can hold conversion result |
6692 | | * @return the number of written char32_t; 0 if conversion is not possible |
6693 | | */ |
6694 | | simdutf_warn_unused size_t convert_latin1_to_utf32( |
6695 | | const char *input, size_t length, char32_t *utf32_buffer) noexcept; |
6696 | | #if SIMDUTF_SPAN |
6697 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t |
6698 | | convert_latin1_to_utf32( |
6699 | | const detail::input_span_of_byte_like auto &latin1_input, |
6700 | | std::span<char32_t> utf32_output) noexcept { |
6701 | | #if SIMDUTF_CPLUSPLUS23 |
6702 | | if consteval { |
6703 | | return scalar::latin1_to_utf32::convert( |
6704 | | latin1_input.data(), latin1_input.size(), utf32_output.data()); |
6705 | | } else |
6706 | | #endif |
6707 | | { |
6708 | | return convert_latin1_to_utf32( |
6709 | | reinterpret_cast<const char *>(latin1_input.data()), |
6710 | | latin1_input.size(), utf32_output.data()); |
6711 | | } |
6712 | | } |
6713 | | #endif // SIMDUTF_SPAN |
6714 | | #endif // SIMDUTF_FEATURE_UTF32 && SIMDUTF_FEATURE_LATIN1 |
6715 | | |
6716 | | #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_LATIN1 |
6717 | | /** |
6718 | | * Convert possibly broken UTF-8 string into latin1 string. |
6719 | | * |
6720 | | * During the conversion also validation of the input string is done. |
6721 | | * This function is suitable to work with inputs from untrusted sources. |
6722 | | * |
6723 | | * @param input the UTF-8 string to convert |
6724 | | * @param length the length of the string in bytes |
6725 | | * @param latin1_output the pointer to buffer that can hold conversion result |
6726 | | * @return the number of written char; 0 if the input was not valid UTF-8 string |
6727 | | * or if it cannot be represented as Latin1 |
6728 | | */ |
6729 | | simdutf_warn_unused size_t convert_utf8_to_latin1(const char *input, |
6730 | | size_t length, |
6731 | | char *latin1_output) noexcept; |
6732 | | #if SIMDUTF_SPAN |
6733 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t |
6734 | | convert_utf8_to_latin1( |
6735 | | const detail::input_span_of_byte_like auto &input, |
6736 | | detail::output_span_of_byte_like auto &&output) noexcept { |
6737 | | #if SIMDUTF_CPLUSPLUS23 |
6738 | | if consteval { |
6739 | | return scalar::utf8_to_latin1::convert(input.data(), input.size(), |
6740 | | output.data()); |
6741 | | } else |
6742 | | #endif |
6743 | | { |
6744 | | return convert_utf8_to_latin1(reinterpret_cast<const char *>(input.data()), |
6745 | | input.size(), |
6746 | | reinterpret_cast<char *>(output.data())); |
6747 | | } |
6748 | | } |
6749 | | #endif // SIMDUTF_SPAN |
6750 | | #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_LATIN1 |
6751 | | |
6752 | | #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 |
6753 | | /** |
6754 | | * Using native endianness, convert possibly broken UTF-8 string into a UTF-16 |
6755 | | * string. |
6756 | | * |
6757 | | * During the conversion also validation of the input string is done. |
6758 | | * This function is suitable to work with inputs from untrusted sources. |
6759 | | * |
6760 | | * @param input the UTF-8 string to convert |
6761 | | * @param length the length of the string in bytes |
6762 | | * @param utf16_output the pointer to buffer that can hold conversion result |
6763 | | * @return the number of written char16_t; 0 if the input was not valid UTF-8 |
6764 | | * string |
6765 | | */ |
6766 | | simdutf_warn_unused size_t convert_utf8_to_utf16( |
6767 | | const char *input, size_t length, char16_t *utf16_output) noexcept; |
6768 | | #if SIMDUTF_SPAN |
6769 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t |
6770 | | convert_utf8_to_utf16(const detail::input_span_of_byte_like auto &input, |
6771 | | std::span<char16_t> output) noexcept { |
6772 | | #if SIMDUTF_CPLUSPLUS23 |
6773 | | if consteval { |
6774 | | return scalar::utf8_to_utf16::convert<endianness::NATIVE>( |
6775 | | input.data(), input.size(), output.data()); |
6776 | | } else |
6777 | | #endif |
6778 | | { |
6779 | | return convert_utf8_to_utf16(reinterpret_cast<const char *>(input.data()), |
6780 | | input.size(), output.data()); |
6781 | | } |
6782 | | } |
6783 | | #endif // SIMDUTF_SPAN |
6784 | | |
6785 | | /** |
6786 | | * Compute the number of bytes that this UTF-16LE string would require in UTF-8 |
6787 | | * format even when the UTF-16LE content contains mismatched surrogates |
6788 | | * that have to be replaced by the replacement character (0xFFFD). |
6789 | | * |
6790 | | * @param input the UTF-16LE string to convert |
6791 | | * @param length the length of the string in 2-byte code units (char16_t) |
6792 | | * @return a result pair struct (of type simdutf::result containing the two |
6793 | | * fields error and count) where the count is the number of bytes required to |
6794 | | * encode the UTF-16LE string as UTF-8, and the error code is either SUCCESS or |
6795 | | * SURROGATE. The count is correct regardless of the error field. |
6796 | | * When SURROGATE is returned, it does not indicate an error in the case of this |
6797 | | * function: it indicates that at least one surrogate has been encountered: the |
6798 | | * surrogates may be matched or not (thus this function does not validate). If |
6799 | | * the returned error code is SUCCESS, then the input contains no surrogate, is |
6800 | | * in the Basic Multilingual Plane, and is necessarily valid. |
6801 | | */ |
6802 | | simdutf_warn_unused result utf8_length_from_utf16le_with_replacement( |
6803 | | const char16_t *input, size_t length) noexcept; |
6804 | | #if SIMDUTF_SPAN |
6805 | | simdutf_really_inline simdutf_constexpr23 simdutf_warn_unused result |
6806 | | utf8_length_from_utf16le_with_replacement( |
6807 | | std::span<const char16_t> valid_utf16_input) noexcept { |
6808 | | #if SIMDUTF_CPLUSPLUS23 |
6809 | | if consteval { |
6810 | | return scalar::utf16::utf8_length_from_utf16_with_replacement< |
6811 | | endianness::LITTLE>(valid_utf16_input.data(), valid_utf16_input.size()); |
6812 | | } else |
6813 | | #endif |
6814 | | { |
6815 | | return utf8_length_from_utf16le_with_replacement(valid_utf16_input.data(), |
6816 | | valid_utf16_input.size()); |
6817 | | } |
6818 | | } |
6819 | | #endif // SIMDUTF_SPAN |
6820 | | |
6821 | | /** |
6822 | | * Compute the number of bytes that this UTF-16BE string would require in UTF-8 |
6823 | | * format even when the UTF-16BE content contains mismatched surrogates |
6824 | | * that have to be replaced by the replacement character (0xFFFD). |
6825 | | * |
6826 | | * @param input the UTF-16BE string to convert |
6827 | | * @param length the length of the string in 2-byte code units (char16_t) |
6828 | | * @return a result pair struct (of type simdutf::result containing the two |
6829 | | * fields error and count) where the count is the number of bytes required to |
6830 | | * encode the UTF-16BE string as UTF-8, and the error code is either SUCCESS or |
6831 | | * SURROGATE. The count is correct regardless of the error field. |
6832 | | * When SURROGATE is returned, it does not indicate an error in the case of this |
6833 | | * function: it indicates that at least one surrogate has been encountered: the |
6834 | | * surrogates may be matched or not (thus this function does not validate). If |
6835 | | * the returned error code is SUCCESS, then the input contains no surrogate, is |
6836 | | * in the Basic Multilingual Plane, and is necessarily valid. |
6837 | | */ |
6838 | | simdutf_warn_unused result utf8_length_from_utf16be_with_replacement( |
6839 | | const char16_t *input, size_t length) noexcept; |
6840 | | #if SIMDUTF_SPAN |
6841 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result |
6842 | | utf8_length_from_utf16be_with_replacement( |
6843 | | std::span<const char16_t> valid_utf16_input) noexcept { |
6844 | | #if SIMDUTF_CPLUSPLUS23 |
6845 | | if consteval { |
6846 | | return scalar::utf16::utf8_length_from_utf16_with_replacement< |
6847 | | endianness::BIG>(valid_utf16_input.data(), valid_utf16_input.size()); |
6848 | | } else |
6849 | | #endif |
6850 | | { |
6851 | | return utf8_length_from_utf16be_with_replacement(valid_utf16_input.data(), |
6852 | | valid_utf16_input.size()); |
6853 | | } |
6854 | | } |
6855 | | #endif // SIMDUTF_SPAN |
6856 | | |
6857 | | #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 |
6858 | | |
6859 | | #if SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_LATIN1 |
6860 | | /** |
6861 | | * Using native endianness, convert a Latin1 string into a UTF-16 string. |
6862 | | * |
6863 | | * @param input the Latin1 string to convert |
6864 | | * @param length the length of the string in bytes |
6865 | | * @param utf16_output the pointer to buffer that can hold conversion result |
6866 | | * @return the number of written char16_t. |
6867 | | */ |
6868 | | simdutf_warn_unused size_t convert_latin1_to_utf16( |
6869 | | const char *input, size_t length, char16_t *utf16_output) noexcept; |
6870 | | #if SIMDUTF_SPAN |
6871 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t |
6872 | | convert_latin1_to_utf16(const detail::input_span_of_byte_like auto &input, |
6873 | | std::span<char16_t> output) noexcept { |
6874 | | #if SIMDUTF_CPLUSPLUS23 |
6875 | | if consteval { |
6876 | | return scalar::latin1_to_utf16::convert<endianness::NATIVE>( |
6877 | | input.data(), input.size(), output.data()); |
6878 | | } else |
6879 | | #endif |
6880 | | { |
6881 | | return convert_latin1_to_utf16(reinterpret_cast<const char *>(input.data()), |
6882 | | input.size(), output.data()); |
6883 | | } |
6884 | | } |
6885 | | #endif // SIMDUTF_SPAN |
6886 | | #endif // SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_LATIN1 |
6887 | | |
6888 | | #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 |
6889 | | /** |
6890 | | * Convert possibly broken UTF-8 string into UTF-16LE string. |
6891 | | * |
6892 | | * During the conversion also validation of the input string is done. |
6893 | | * This function is suitable to work with inputs from untrusted sources. |
6894 | | * |
6895 | | * @param input the UTF-8 string to convert |
6896 | | * @param length the length of the string in bytes |
6897 | | * @param utf16_output the pointer to buffer that can hold conversion result |
6898 | | * @return the number of written char16_t; 0 if the input was not valid UTF-8 |
6899 | | * string |
6900 | | */ |
6901 | | simdutf_warn_unused size_t convert_utf8_to_utf16le( |
6902 | | const char *input, size_t length, char16_t *utf16_output) noexcept; |
6903 | | #if SIMDUTF_SPAN |
6904 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t |
6905 | | convert_utf8_to_utf16le(const detail::input_span_of_byte_like auto &utf8_input, |
6906 | | std::span<char16_t> utf16_output) noexcept { |
6907 | | #if SIMDUTF_CPLUSPLUS23 |
6908 | | if consteval { |
6909 | | return scalar::utf8_to_utf16::convert<endianness::LITTLE>( |
6910 | | utf8_input.data(), utf8_input.size(), utf16_output.data()); |
6911 | | } else |
6912 | | #endif |
6913 | | { |
6914 | | return convert_utf8_to_utf16le( |
6915 | | reinterpret_cast<const char *>(utf8_input.data()), utf8_input.size(), |
6916 | | utf16_output.data()); |
6917 | | } |
6918 | | } |
6919 | | #endif // SIMDUTF_SPAN |
6920 | | |
6921 | | /** |
6922 | | * Convert possibly broken UTF-8 string into UTF-16BE string. |
6923 | | * |
6924 | | * During the conversion also validation of the input string is done. |
6925 | | * This function is suitable to work with inputs from untrusted sources. |
6926 | | * |
6927 | | * @param input the UTF-8 string to convert |
6928 | | * @param length the length of the string in bytes |
6929 | | * @param utf16_output the pointer to buffer that can hold conversion result |
6930 | | * @return the number of written char16_t; 0 if the input was not valid UTF-8 |
6931 | | * string |
6932 | | */ |
6933 | | simdutf_warn_unused size_t convert_utf8_to_utf16be( |
6934 | | const char *input, size_t length, char16_t *utf16_output) noexcept; |
6935 | | #if SIMDUTF_SPAN |
6936 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t |
6937 | | convert_utf8_to_utf16be(const detail::input_span_of_byte_like auto &utf8_input, |
6938 | | std::span<char16_t> utf16_output) noexcept { |
6939 | | |
6940 | | #if SIMDUTF_CPLUSPLUS23 |
6941 | | if consteval { |
6942 | | return scalar::utf8_to_utf16::convert<endianness::BIG>( |
6943 | | utf8_input.data(), utf8_input.size(), utf16_output.data()); |
6944 | | } else |
6945 | | #endif |
6946 | | { |
6947 | | return convert_utf8_to_utf16be( |
6948 | | reinterpret_cast<const char *>(utf8_input.data()), utf8_input.size(), |
6949 | | utf16_output.data()); |
6950 | | } |
6951 | | } |
6952 | | #endif // SIMDUTF_SPAN |
6953 | | #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 |
6954 | | |
6955 | | #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_LATIN1 |
6956 | | /** |
6957 | | * Convert possibly broken UTF-8 string into latin1 string with errors. |
6958 | | * If the string cannot be represented as Latin1, an error |
6959 | | * code is returned. |
6960 | | * |
6961 | | * During the conversion also validation of the input string is done. |
6962 | | * This function is suitable to work with inputs from untrusted sources. |
6963 | | * |
6964 | | * @param input the UTF-8 string to convert |
6965 | | * @param length the length of the string in bytes |
6966 | | * @param latin1_output the pointer to buffer that can hold conversion result |
6967 | | * @return a result pair struct (of type simdutf::result containing the two |
6968 | | * fields error and count) with an error code and either position of the error |
6969 | | * (in the input in code units) if any, or the number of code units validated if |
6970 | | * successful. |
6971 | | */ |
6972 | | simdutf_warn_unused result convert_utf8_to_latin1_with_errors( |
6973 | | const char *input, size_t length, char *latin1_output) noexcept; |
6974 | | #if SIMDUTF_SPAN |
6975 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result |
6976 | | convert_utf8_to_latin1_with_errors( |
6977 | | const detail::input_span_of_byte_like auto &utf8_input, |
6978 | | detail::output_span_of_byte_like auto &&latin1_output) noexcept { |
6979 | | #if SIMDUTF_CPLUSPLUS23 |
6980 | | if consteval { |
6981 | | return scalar::utf8_to_latin1::convert_with_errors( |
6982 | | utf8_input.data(), utf8_input.size(), latin1_output.data()); |
6983 | | } else |
6984 | | #endif |
6985 | | { |
6986 | | return convert_utf8_to_latin1_with_errors( |
6987 | | reinterpret_cast<const char *>(utf8_input.data()), utf8_input.size(), |
6988 | | reinterpret_cast<char *>(latin1_output.data())); |
6989 | | } |
6990 | | } |
6991 | | #endif // SIMDUTF_SPAN |
6992 | | #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_LATIN1 |
6993 | | |
6994 | | #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 |
6995 | | /** |
6996 | | * Using native endianness, convert possibly broken UTF-8 string into UTF-16 |
6997 | | * string and stop on error. |
6998 | | * |
6999 | | * During the conversion also validation of the input string is done. |
7000 | | * This function is suitable to work with inputs from untrusted sources. |
7001 | | * |
7002 | | * @param input the UTF-8 string to convert |
7003 | | * @param length the length of the string in bytes |
7004 | | * @param utf16_output the pointer to buffer that can hold conversion result |
7005 | | * @return a result pair struct (of type simdutf::result containing the two |
7006 | | * fields error and count) with an error code and either position of the error |
7007 | | * (in the input in code units) if any, or the number of char16_t written if |
7008 | | * successful. |
7009 | | */ |
7010 | | simdutf_warn_unused result convert_utf8_to_utf16_with_errors( |
7011 | | const char *input, size_t length, char16_t *utf16_output) noexcept; |
7012 | | #if SIMDUTF_SPAN |
7013 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result |
7014 | | convert_utf8_to_utf16_with_errors( |
7015 | | const detail::input_span_of_byte_like auto &utf8_input, |
7016 | | std::span<char16_t> utf16_output) noexcept { |
7017 | | #if SIMDUTF_CPLUSPLUS23 |
7018 | | if consteval { |
7019 | | return scalar::utf8_to_utf16::convert_with_errors<endianness::NATIVE>( |
7020 | | utf8_input.data(), utf8_input.size(), utf16_output.data()); |
7021 | | } else |
7022 | | #endif |
7023 | | { |
7024 | | return convert_utf8_to_utf16_with_errors( |
7025 | | reinterpret_cast<const char *>(utf8_input.data()), utf8_input.size(), |
7026 | | utf16_output.data()); |
7027 | | } |
7028 | | } |
7029 | | #endif // SIMDUTF_SPAN |
7030 | | |
7031 | | /** |
7032 | | * Convert possibly broken UTF-8 string into UTF-16LE string and stop on error. |
7033 | | * |
7034 | | * During the conversion also validation of the input string is done. |
7035 | | * This function is suitable to work with inputs from untrusted sources. |
7036 | | * |
7037 | | * @param input the UTF-8 string to convert |
7038 | | * @param length the length of the string in bytes |
7039 | | * @param utf16_output the pointer to buffer that can hold conversion result |
7040 | | * @return a result pair struct (of type simdutf::result containing the two |
7041 | | * fields error and count) with an error code and either position of the error |
7042 | | * (in the input in code units) if any, or the number of char16_t written if |
7043 | | * successful. |
7044 | | */ |
7045 | | simdutf_warn_unused result convert_utf8_to_utf16le_with_errors( |
7046 | | const char *input, size_t length, char16_t *utf16_output) noexcept; |
7047 | | #if SIMDUTF_SPAN |
7048 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result |
7049 | | convert_utf8_to_utf16le_with_errors( |
7050 | | const detail::input_span_of_byte_like auto &utf8_input, |
7051 | | std::span<char16_t> utf16_output) noexcept { |
7052 | | #if SIMDUTF_CPLUSPLUS23 |
7053 | | if consteval { |
7054 | | return scalar::utf8_to_utf16::convert_with_errors<endianness::LITTLE>( |
7055 | | utf8_input.data(), utf8_input.size(), utf16_output.data()); |
7056 | | } else |
7057 | | #endif |
7058 | | { |
7059 | | return convert_utf8_to_utf16le_with_errors( |
7060 | | reinterpret_cast<const char *>(utf8_input.data()), utf8_input.size(), |
7061 | | utf16_output.data()); |
7062 | | } |
7063 | | } |
7064 | | #endif // SIMDUTF_SPAN |
7065 | | |
7066 | | /** |
7067 | | * Convert possibly broken UTF-8 string into UTF-16BE string and stop on error. |
7068 | | * |
7069 | | * During the conversion also validation of the input string is done. |
7070 | | * This function is suitable to work with inputs from untrusted sources. |
7071 | | * |
7072 | | * @param input the UTF-8 string to convert |
7073 | | * @param length the length of the string in bytes |
7074 | | * @param utf16_output the pointer to buffer that can hold conversion result |
7075 | | * @return a result pair struct (of type simdutf::result containing the two |
7076 | | * fields error and count) with an error code and either position of the error |
7077 | | * (in the input in code units) if any, or the number of char16_t written if |
7078 | | * successful. |
7079 | | */ |
7080 | | simdutf_warn_unused result convert_utf8_to_utf16be_with_errors( |
7081 | | const char *input, size_t length, char16_t *utf16_output) noexcept; |
7082 | | #if SIMDUTF_SPAN |
7083 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result |
7084 | | convert_utf8_to_utf16be_with_errors( |
7085 | | const detail::input_span_of_byte_like auto &utf8_input, |
7086 | | std::span<char16_t> utf16_output) noexcept { |
7087 | | #if SIMDUTF_CPLUSPLUS23 |
7088 | | if consteval { |
7089 | | return scalar::utf8_to_utf16::convert_with_errors<endianness::BIG>( |
7090 | | utf8_input.data(), utf8_input.size(), utf16_output.data()); |
7091 | | } else |
7092 | | #endif |
7093 | | { |
7094 | | return convert_utf8_to_utf16be_with_errors( |
7095 | | reinterpret_cast<const char *>(utf8_input.data()), utf8_input.size(), |
7096 | | utf16_output.data()); |
7097 | | } |
7098 | | } |
7099 | | #endif // SIMDUTF_SPAN |
7100 | | |
7101 | | /** |
7102 | | * Convert a possibly ill-formed UTF-8 string into a UTF-16 string (native |
7103 | | * endianness), replacing each ill-formed subsequence with U+FFFD. |
7104 | | * |
7105 | | * Substitution follows Unicode maximal subparts (the WHATWG rule): each |
7106 | | * maximal subpart of an ill-formed sequence becomes one U+FFFD code unit. |
7107 | | * The function always succeeds. The output buffer must hold |
7108 | | * utf16_length_from_utf8_with_replacement(...).count char16_t. A buffer of |
7109 | | * `length` char16_t is always large enough. Pass that result to the overload |
7110 | | * that takes it, so the recorded error locations are not discovered again. |
7111 | | * |
7112 | | * This function is not BOM-aware. |
7113 | | * |
7114 | | * @param input the UTF-8 string to convert |
7115 | | * @param length the length of the string in bytes |
7116 | | * @param utf16_output the pointer to buffer that can hold the conversion |
7117 | | * result |
7118 | | * @return the number of written char16_t |
7119 | | */ |
7120 | | simdutf_warn_unused size_t convert_utf8_to_utf16_with_replacement( |
7121 | | const char *input, size_t length, char16_t *utf16_output) noexcept; |
7122 | | #if SIMDUTF_SPAN |
7123 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t |
7124 | | convert_utf8_to_utf16_with_replacement( |
7125 | | const detail::input_span_of_byte_like auto &utf8_input, |
7126 | | std::span<char16_t> utf16_output) noexcept { |
7127 | | #if SIMDUTF_CPLUSPLUS23 |
7128 | | if consteval { |
7129 | | return scalar::utf8_to_utf16::convert_with_replacement<endianness::NATIVE>( |
7130 | | utf8_input.data(), utf8_input.size(), utf16_output.data()); |
7131 | | } else |
7132 | | #endif |
7133 | | { |
7134 | | return convert_utf8_to_utf16_with_replacement( |
7135 | | reinterpret_cast<const char *>(utf8_input.data()), utf8_input.size(), |
7136 | | utf16_output.data()); |
7137 | | } |
7138 | | } |
7139 | | #endif // SIMDUTF_SPAN |
7140 | | |
7141 | | /** |
7142 | | * Convert a possibly ill-formed UTF-8 string into a UTF-16 string (native |
7143 | | * endianness), replacing each ill-formed subsequence with U+FFFD, using error |
7144 | | * locations already computed for this same input. |
7145 | | * |
7146 | | * locations must be the value returned by |
7147 | | * utf16_length_from_utf8_with_replacement for these bytes. When |
7148 | | * locations.more_errors is false, every ill-formed subsequence is in |
7149 | | * locations.error_offset and the gaps are valid UTF-8. When it is true, the |
7150 | | * input has further ill-formed subsequences, and the tail past the stored |
7151 | | * locations is scanned during conversion. The function always succeeds. |
7152 | | * |
7153 | | * @param input the UTF-8 string to convert |
7154 | | * @param length the length of the string in bytes |
7155 | | * @param utf16_output the pointer to buffer that can hold the conversion |
7156 | | * result |
7157 | | * @param locations result of utf16_length_from_utf8_with_replacement |
7158 | | * @return the number of written char16_t, equal to locations.count when |
7159 | | * locations describes this input |
7160 | | */ |
7161 | | simdutf_warn_unused size_t convert_utf8_to_utf16_with_replacement( |
7162 | | const char *input, size_t length, char16_t *utf16_output, |
7163 | | const utf8_to_utf16_result &locations) noexcept; |
7164 | | #if SIMDUTF_SPAN |
7165 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t |
7166 | | convert_utf8_to_utf16_with_replacement( |
7167 | | const detail::input_span_of_byte_like auto &utf8_input, |
7168 | | std::span<char16_t> utf16_output, |
7169 | | const utf8_to_utf16_result &locations) noexcept { |
7170 | | #if SIMDUTF_CPLUSPLUS23 |
7171 | | if consteval { |
7172 | | (void)locations; |
7173 | | return scalar::utf8_to_utf16::convert_with_replacement<endianness::NATIVE>( |
7174 | | utf8_input.data(), utf8_input.size(), utf16_output.data()); |
7175 | | } else |
7176 | | #endif |
7177 | | { |
7178 | | return convert_utf8_to_utf16_with_replacement( |
7179 | | reinterpret_cast<const char *>(utf8_input.data()), utf8_input.size(), |
7180 | | utf16_output.data(), locations); |
7181 | | } |
7182 | | } |
7183 | | #endif // SIMDUTF_SPAN |
7184 | | |
7185 | | /** |
7186 | | * Convert a possibly ill-formed UTF-8 string into a UTF-16LE string, replacing |
7187 | | * each ill-formed subsequence with U+FFFD. |
7188 | | * |
7189 | | * Substitution follows Unicode maximal subparts (the WHATWG rule): each |
7190 | | * maximal subpart of an ill-formed sequence becomes one U+FFFD code unit. |
7191 | | * The function always succeeds. The output buffer must hold |
7192 | | * utf16_length_from_utf8_with_replacement(...).count char16_t. A buffer of |
7193 | | * `length` char16_t is always large enough. Pass that result to the overload |
7194 | | * that takes it, so the recorded error locations are not discovered again. |
7195 | | * |
7196 | | * This function is not BOM-aware. |
7197 | | * |
7198 | | * @param input the UTF-8 string to convert |
7199 | | * @param length the length of the string in bytes |
7200 | | * @param utf16_output the pointer to buffer that can hold the conversion |
7201 | | * result |
7202 | | * @return the number of written char16_t |
7203 | | */ |
7204 | | simdutf_warn_unused size_t convert_utf8_to_utf16le_with_replacement( |
7205 | | const char *input, size_t length, char16_t *utf16_output) noexcept; |
7206 | | #if SIMDUTF_SPAN |
7207 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t |
7208 | | convert_utf8_to_utf16le_with_replacement( |
7209 | | const detail::input_span_of_byte_like auto &utf8_input, |
7210 | | std::span<char16_t> utf16_output) noexcept { |
7211 | | #if SIMDUTF_CPLUSPLUS23 |
7212 | | if consteval { |
7213 | | return scalar::utf8_to_utf16::convert_with_replacement<endianness::LITTLE>( |
7214 | | utf8_input.data(), utf8_input.size(), utf16_output.data()); |
7215 | | } else |
7216 | | #endif |
7217 | | { |
7218 | | return convert_utf8_to_utf16le_with_replacement( |
7219 | | reinterpret_cast<const char *>(utf8_input.data()), utf8_input.size(), |
7220 | | utf16_output.data()); |
7221 | | } |
7222 | | } |
7223 | | #endif // SIMDUTF_SPAN |
7224 | | |
7225 | | /** |
7226 | | * Convert a possibly ill-formed UTF-8 string into a UTF-16LE string, using |
7227 | | * error locations already computed for this same input. See |
7228 | | * convert_utf8_to_utf16_with_replacement. |
7229 | | * |
7230 | | * @param input the UTF-8 string to convert |
7231 | | * @param length the length of the string in bytes |
7232 | | * @param utf16_output the pointer to buffer that can hold the conversion |
7233 | | * result |
7234 | | * @param locations result of utf16_length_from_utf8_with_replacement |
7235 | | * @return the number of written char16_t |
7236 | | */ |
7237 | | simdutf_warn_unused size_t convert_utf8_to_utf16le_with_replacement( |
7238 | | const char *input, size_t length, char16_t *utf16_output, |
7239 | | const utf8_to_utf16_result &locations) noexcept; |
7240 | | #if SIMDUTF_SPAN |
7241 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t |
7242 | | convert_utf8_to_utf16le_with_replacement( |
7243 | | const detail::input_span_of_byte_like auto &utf8_input, |
7244 | | std::span<char16_t> utf16_output, |
7245 | | const utf8_to_utf16_result &locations) noexcept { |
7246 | | #if SIMDUTF_CPLUSPLUS23 |
7247 | | if consteval { |
7248 | | (void)locations; |
7249 | | return scalar::utf8_to_utf16::convert_with_replacement<endianness::LITTLE>( |
7250 | | utf8_input.data(), utf8_input.size(), utf16_output.data()); |
7251 | | } else |
7252 | | #endif |
7253 | | { |
7254 | | return convert_utf8_to_utf16le_with_replacement( |
7255 | | reinterpret_cast<const char *>(utf8_input.data()), utf8_input.size(), |
7256 | | utf16_output.data(), locations); |
7257 | | } |
7258 | | } |
7259 | | #endif // SIMDUTF_SPAN |
7260 | | |
7261 | | /** |
7262 | | * Convert a possibly ill-formed UTF-8 string into a UTF-16BE string, replacing |
7263 | | * each ill-formed subsequence with U+FFFD. |
7264 | | * |
7265 | | * Substitution follows Unicode maximal subparts (the WHATWG rule): each |
7266 | | * maximal subpart of an ill-formed sequence becomes one U+FFFD code unit. |
7267 | | * The function always succeeds. The output buffer must hold |
7268 | | * utf16_length_from_utf8_with_replacement(...).count char16_t. A buffer of |
7269 | | * `length` char16_t is always large enough. Pass that result to the overload |
7270 | | * that takes it, so the recorded error locations are not discovered again. |
7271 | | * |
7272 | | * This function is not BOM-aware. |
7273 | | * |
7274 | | * @param input the UTF-8 string to convert |
7275 | | * @param length the length of the string in bytes |
7276 | | * @param utf16_output the pointer to buffer that can hold the conversion |
7277 | | * result |
7278 | | * @return the number of written char16_t |
7279 | | */ |
7280 | | simdutf_warn_unused size_t convert_utf8_to_utf16be_with_replacement( |
7281 | | const char *input, size_t length, char16_t *utf16_output) noexcept; |
7282 | | #if SIMDUTF_SPAN |
7283 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t |
7284 | | convert_utf8_to_utf16be_with_replacement( |
7285 | | const detail::input_span_of_byte_like auto &utf8_input, |
7286 | | std::span<char16_t> utf16_output) noexcept { |
7287 | | #if SIMDUTF_CPLUSPLUS23 |
7288 | | if consteval { |
7289 | | return scalar::utf8_to_utf16::convert_with_replacement<endianness::BIG>( |
7290 | | utf8_input.data(), utf8_input.size(), utf16_output.data()); |
7291 | | } else |
7292 | | #endif |
7293 | | { |
7294 | | return convert_utf8_to_utf16be_with_replacement( |
7295 | | reinterpret_cast<const char *>(utf8_input.data()), utf8_input.size(), |
7296 | | utf16_output.data()); |
7297 | | } |
7298 | | } |
7299 | | #endif // SIMDUTF_SPAN |
7300 | | |
7301 | | /** |
7302 | | * Convert a possibly ill-formed UTF-8 string into a UTF-16BE string, using |
7303 | | * error locations already computed for this same input. See |
7304 | | * convert_utf8_to_utf16_with_replacement. |
7305 | | * |
7306 | | * @param input the UTF-8 string to convert |
7307 | | * @param length the length of the string in bytes |
7308 | | * @param utf16_output the pointer to buffer that can hold the conversion |
7309 | | * result |
7310 | | * @param locations result of utf16_length_from_utf8_with_replacement |
7311 | | * @return the number of written char16_t |
7312 | | */ |
7313 | | simdutf_warn_unused size_t convert_utf8_to_utf16be_with_replacement( |
7314 | | const char *input, size_t length, char16_t *utf16_output, |
7315 | | const utf8_to_utf16_result &locations) noexcept; |
7316 | | #if SIMDUTF_SPAN |
7317 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t |
7318 | | convert_utf8_to_utf16be_with_replacement( |
7319 | | const detail::input_span_of_byte_like auto &utf8_input, |
7320 | | std::span<char16_t> utf16_output, |
7321 | | const utf8_to_utf16_result &locations) noexcept { |
7322 | | #if SIMDUTF_CPLUSPLUS23 |
7323 | | if consteval { |
7324 | | (void)locations; |
7325 | | return scalar::utf8_to_utf16::convert_with_replacement<endianness::BIG>( |
7326 | | utf8_input.data(), utf8_input.size(), utf16_output.data()); |
7327 | | } else |
7328 | | #endif |
7329 | | { |
7330 | | return convert_utf8_to_utf16be_with_replacement( |
7331 | | reinterpret_cast<const char *>(utf8_input.data()), utf8_input.size(), |
7332 | | utf16_output.data(), locations); |
7333 | | } |
7334 | | } |
7335 | | #endif // SIMDUTF_SPAN |
7336 | | #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 |
7337 | | |
7338 | | #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32 |
7339 | | /** |
7340 | | * Convert possibly broken UTF-8 string into UTF-32 string. |
7341 | | * |
7342 | | * During the conversion also validation of the input string is done. |
7343 | | * This function is suitable to work with inputs from untrusted sources. |
7344 | | * |
7345 | | * @param input the UTF-8 string to convert |
7346 | | * @param length the length of the string in bytes |
7347 | | * @param utf32_output the pointer to buffer that can hold conversion result |
7348 | | * @return the number of written char32_t; 0 if the input was not valid UTF-8 |
7349 | | * string |
7350 | | */ |
7351 | | simdutf_warn_unused size_t convert_utf8_to_utf32( |
7352 | | const char *input, size_t length, char32_t *utf32_output) noexcept; |
7353 | | #if SIMDUTF_SPAN |
7354 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t |
7355 | | convert_utf8_to_utf32(const detail::input_span_of_byte_like auto &utf8_input, |
7356 | | std::span<char32_t> utf32_output) noexcept { |
7357 | | #if SIMDUTF_CPLUSPLUS23 |
7358 | | if consteval { |
7359 | | return scalar::utf8_to_utf32::convert(utf8_input.data(), utf8_input.size(), |
7360 | | utf32_output.data()); |
7361 | | } else |
7362 | | #endif |
7363 | | { |
7364 | | return convert_utf8_to_utf32( |
7365 | | reinterpret_cast<const char *>(utf8_input.data()), utf8_input.size(), |
7366 | | utf32_output.data()); |
7367 | | } |
7368 | | } |
7369 | | #endif // SIMDUTF_SPAN |
7370 | | |
7371 | | /** |
7372 | | * Convert possibly broken UTF-8 string into UTF-32 string and stop on error. |
7373 | | * |
7374 | | * During the conversion also validation of the input string is done. |
7375 | | * This function is suitable to work with inputs from untrusted sources. |
7376 | | * |
7377 | | * @param input the UTF-8 string to convert |
7378 | | * @param length the length of the string in bytes |
7379 | | * @param utf32_output the pointer to buffer that can hold conversion result |
7380 | | * @return a result pair struct (of type simdutf::result containing the two |
7381 | | * fields error and count) with an error code and either position of the error |
7382 | | * (in the input in code units) if any, or the number of char32_t written if |
7383 | | * successful. |
7384 | | */ |
7385 | | simdutf_warn_unused result convert_utf8_to_utf32_with_errors( |
7386 | | const char *input, size_t length, char32_t *utf32_output) noexcept; |
7387 | | #if SIMDUTF_SPAN |
7388 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result |
7389 | | convert_utf8_to_utf32_with_errors( |
7390 | | const detail::input_span_of_byte_like auto &utf8_input, |
7391 | | std::span<char32_t> utf32_output) noexcept { |
7392 | | #if SIMDUTF_CPLUSPLUS23 |
7393 | | if consteval { |
7394 | | return scalar::utf8_to_utf32::convert_with_errors( |
7395 | | utf8_input.data(), utf8_input.size(), utf32_output.data()); |
7396 | | } else |
7397 | | #endif |
7398 | | { |
7399 | | return convert_utf8_to_utf32_with_errors( |
7400 | | reinterpret_cast<const char *>(utf8_input.data()), utf8_input.size(), |
7401 | | utf32_output.data()); |
7402 | | } |
7403 | | } |
7404 | | #endif // SIMDUTF_SPAN |
7405 | | #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32 |
7406 | | |
7407 | | #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_LATIN1 |
7408 | | /** |
7409 | | * Convert valid UTF-8 string into latin1 string. |
7410 | | * |
7411 | | * This function assumes that the input string is valid UTF-8 and that it can be |
7412 | | * represented as Latin1. If you violate this assumption, the result is |
7413 | | * implementation defined and may include system-dependent behavior such as |
7414 | | * crashes. |
7415 | | * |
7416 | | * This function is for expert users only and not part of our public API. Use |
7417 | | * convert_utf8_to_latin1 instead. The function may be removed from the library |
7418 | | * in the future. |
7419 | | * |
7420 | | * This function is not BOM-aware. |
7421 | | * |
7422 | | * @param input the UTF-8 string to convert |
7423 | | * @param length the length of the string in bytes |
7424 | | * @param latin1_output the pointer to buffer that can hold conversion result |
7425 | | * @return the number of written char; 0 if the input was not valid UTF-8 string |
7426 | | */ |
7427 | | simdutf_warn_unused size_t convert_valid_utf8_to_latin1( |
7428 | | const char *input, size_t length, char *latin1_output) noexcept; |
7429 | | #if SIMDUTF_SPAN |
7430 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t |
7431 | | convert_valid_utf8_to_latin1( |
7432 | | const detail::input_span_of_byte_like auto &valid_utf8_input, |
7433 | | detail::output_span_of_byte_like auto &&latin1_output) noexcept { |
7434 | | #if SIMDUTF_CPLUSPLUS23 |
7435 | | if consteval { |
7436 | | return scalar::utf8_to_latin1::convert_valid( |
7437 | | valid_utf8_input.data(), valid_utf8_input.size(), latin1_output.data()); |
7438 | | } else |
7439 | | #endif |
7440 | | { |
7441 | | return convert_valid_utf8_to_latin1( |
7442 | | reinterpret_cast<const char *>(valid_utf8_input.data()), |
7443 | | valid_utf8_input.size(), latin1_output.data()); |
7444 | | } |
7445 | | } |
7446 | | #endif // SIMDUTF_SPAN |
7447 | | #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_LATIN1 |
7448 | | |
7449 | | #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 |
7450 | | /** |
7451 | | * Using native endianness, convert valid UTF-8 string into a UTF-16 string. |
7452 | | * |
7453 | | * This function assumes that the input string is valid UTF-8. |
7454 | | * |
7455 | | * @param input the UTF-8 string to convert |
7456 | | * @param length the length of the string in bytes |
7457 | | * @param utf16_buffer the pointer to buffer that can hold conversion result |
7458 | | * @return the number of written char16_t |
7459 | | */ |
7460 | | simdutf_warn_unused size_t convert_valid_utf8_to_utf16( |
7461 | | const char *input, size_t length, char16_t *utf16_buffer) noexcept; |
7462 | | #if SIMDUTF_SPAN |
7463 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t |
7464 | | convert_valid_utf8_to_utf16( |
7465 | | const detail::input_span_of_byte_like auto &valid_utf8_input, |
7466 | | std::span<char16_t> utf16_output) noexcept { |
7467 | | #if SIMDUTF_CPLUSPLUS23 |
7468 | | if consteval { |
7469 | | return scalar::utf8_to_utf16::convert_valid<endianness::NATIVE>( |
7470 | | valid_utf8_input.data(), valid_utf8_input.size(), utf16_output.data()); |
7471 | | } else |
7472 | | #endif |
7473 | | { |
7474 | | return convert_valid_utf8_to_utf16( |
7475 | | reinterpret_cast<const char *>(valid_utf8_input.data()), |
7476 | | valid_utf8_input.size(), utf16_output.data()); |
7477 | | } |
7478 | | } |
7479 | | #endif // SIMDUTF_SPAN |
7480 | | |
7481 | | /** |
7482 | | * Convert valid UTF-8 string into UTF-16LE string. |
7483 | | * |
7484 | | * This function assumes that the input string is valid UTF-8. |
7485 | | * |
7486 | | * @param input the UTF-8 string to convert |
7487 | | * @param length the length of the string in bytes |
7488 | | * @param utf16_buffer the pointer to buffer that can hold conversion result |
7489 | | * @return the number of written char16_t |
7490 | | */ |
7491 | | simdutf_warn_unused size_t convert_valid_utf8_to_utf16le( |
7492 | | const char *input, size_t length, char16_t *utf16_buffer) noexcept; |
7493 | | #if SIMDUTF_SPAN |
7494 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t |
7495 | | convert_valid_utf8_to_utf16le( |
7496 | | const detail::input_span_of_byte_like auto &valid_utf8_input, |
7497 | | std::span<char16_t> utf16_output) noexcept { |
7498 | | |
7499 | | #if SIMDUTF_CPLUSPLUS23 |
7500 | | if consteval { |
7501 | | return scalar::utf8_to_utf16::convert_valid<endianness::LITTLE>( |
7502 | | valid_utf8_input.data(), valid_utf8_input.size(), utf16_output.data()); |
7503 | | } else |
7504 | | #endif |
7505 | | { |
7506 | | return convert_valid_utf8_to_utf16le( |
7507 | | reinterpret_cast<const char *>(valid_utf8_input.data()), |
7508 | | valid_utf8_input.size(), utf16_output.data()); |
7509 | | } |
7510 | | } |
7511 | | #endif // SIMDUTF_SPAN |
7512 | | |
7513 | | /** |
7514 | | * Convert valid UTF-8 string into UTF-16BE string. |
7515 | | * |
7516 | | * This function assumes that the input string is valid UTF-8. |
7517 | | * |
7518 | | * @param input the UTF-8 string to convert |
7519 | | * @param length the length of the string in bytes |
7520 | | * @param utf16_buffer the pointer to buffer that can hold conversion result |
7521 | | * @return the number of written char16_t |
7522 | | */ |
7523 | | simdutf_warn_unused size_t convert_valid_utf8_to_utf16be( |
7524 | | const char *input, size_t length, char16_t *utf16_buffer) noexcept; |
7525 | | #if SIMDUTF_SPAN |
7526 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t |
7527 | | convert_valid_utf8_to_utf16be( |
7528 | | const detail::input_span_of_byte_like auto &valid_utf8_input, |
7529 | | std::span<char16_t> utf16_output) noexcept { |
7530 | | #if SIMDUTF_CPLUSPLUS23 |
7531 | | if consteval { |
7532 | | return scalar::utf8_to_utf16::convert_valid<endianness::BIG>( |
7533 | | valid_utf8_input.data(), valid_utf8_input.size(), utf16_output.data()); |
7534 | | } else |
7535 | | #endif |
7536 | | { |
7537 | | return convert_valid_utf8_to_utf16be( |
7538 | | reinterpret_cast<const char *>(valid_utf8_input.data()), |
7539 | | valid_utf8_input.size(), utf16_output.data()); |
7540 | | } |
7541 | | } |
7542 | | #endif // SIMDUTF_SPAN |
7543 | | #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 |
7544 | | |
7545 | | #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32 |
7546 | | /** |
7547 | | * Convert valid UTF-8 string into UTF-32 string. |
7548 | | * |
7549 | | * This function assumes that the input string is valid UTF-8. |
7550 | | * |
7551 | | * @param input the UTF-8 string to convert |
7552 | | * @param length the length of the string in bytes |
7553 | | * @param utf32_buffer the pointer to buffer that can hold conversion result |
7554 | | * @return the number of written char32_t |
7555 | | */ |
7556 | | simdutf_warn_unused size_t convert_valid_utf8_to_utf32( |
7557 | | const char *input, size_t length, char32_t *utf32_buffer) noexcept; |
7558 | | #if SIMDUTF_SPAN |
7559 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t |
7560 | | convert_valid_utf8_to_utf32( |
7561 | | const detail::input_span_of_byte_like auto &valid_utf8_input, |
7562 | | std::span<char32_t> utf32_output) noexcept { |
7563 | | #if SIMDUTF_CPLUSPLUS23 |
7564 | | if consteval { |
7565 | | return scalar::utf8_to_utf32::convert_valid( |
7566 | | valid_utf8_input.data(), valid_utf8_input.size(), utf32_output.data()); |
7567 | | } else |
7568 | | #endif |
7569 | | { |
7570 | | return convert_valid_utf8_to_utf32( |
7571 | | reinterpret_cast<const char *>(valid_utf8_input.data()), |
7572 | | valid_utf8_input.size(), utf32_output.data()); |
7573 | | } |
7574 | | } |
7575 | | #endif // SIMDUTF_SPAN |
7576 | | #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32 |
7577 | | |
7578 | | #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_LATIN1 |
7579 | | /** |
7580 | | * Return the number of bytes that this Latin1 string would require in UTF-8 |
7581 | | * format. |
7582 | | * |
7583 | | * @param input the Latin1 string to convert |
7584 | | * @param length the length of the string bytes |
7585 | | * @return the number of bytes required to encode the Latin1 string as UTF-8 |
7586 | | */ |
7587 | | simdutf_warn_unused size_t utf8_length_from_latin1(const char *input, |
7588 | | size_t length) noexcept; |
7589 | | #if SIMDUTF_SPAN |
7590 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t |
7591 | | utf8_length_from_latin1( |
7592 | | const detail::input_span_of_byte_like auto &latin1_input) noexcept { |
7593 | | #if SIMDUTF_CPLUSPLUS23 |
7594 | | if consteval { |
7595 | | return scalar::latin1_to_utf8::utf8_length_from_latin1(latin1_input.data(), |
7596 | | latin1_input.size()); |
7597 | | } else |
7598 | | #endif |
7599 | | { |
7600 | | return utf8_length_from_latin1( |
7601 | | reinterpret_cast<const char *>(latin1_input.data()), |
7602 | | latin1_input.size()); |
7603 | | } |
7604 | | } |
7605 | | #endif // SIMDUTF_SPAN |
7606 | | |
7607 | | /** |
7608 | | * Compute the number of bytes that this UTF-8 string would require in Latin1 |
7609 | | * format. |
7610 | | * |
7611 | | * This function does not validate the input. It is acceptable to pass invalid |
7612 | | * UTF-8 strings but in such cases the result is implementation defined. |
7613 | | * |
7614 | | * This function is not BOM-aware. |
7615 | | * |
7616 | | * @param input the UTF-8 string to convert |
7617 | | * @param length the length of the string in byte |
7618 | | * @return the number of bytes required to encode the UTF-8 string as Latin1 |
7619 | | */ |
7620 | | simdutf_warn_unused size_t latin1_length_from_utf8(const char *input, |
7621 | | size_t length) noexcept; |
7622 | | #if SIMDUTF_SPAN |
7623 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t |
7624 | | latin1_length_from_utf8( |
7625 | | const detail::input_span_of_byte_like auto &valid_utf8_input) noexcept { |
7626 | | #if SIMDUTF_CPLUSPLUS23 |
7627 | | if consteval { |
7628 | | return scalar::utf8::count_code_points(valid_utf8_input.data(), |
7629 | | valid_utf8_input.size()); |
7630 | | } else |
7631 | | #endif |
7632 | | { |
7633 | | return latin1_length_from_utf8( |
7634 | | reinterpret_cast<const char *>(valid_utf8_input.data()), |
7635 | | valid_utf8_input.size()); |
7636 | | } |
7637 | | } |
7638 | | #endif // SIMDUTF_SPAN |
7639 | | #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_LATIN1 |
7640 | | |
7641 | | #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 |
7642 | | /** |
7643 | | * Compute the number of 2-byte code units that this UTF-8 string would require |
7644 | | * in UTF-16LE format. |
7645 | | * |
7646 | | * This function does not validate the input. It is acceptable to pass invalid |
7647 | | * UTF-8 strings but in such cases the result is implementation defined. |
7648 | | * |
7649 | | * This function is not BOM-aware. |
7650 | | * |
7651 | | * @param input the UTF-8 string to process |
7652 | | * @param length the length of the string in bytes |
7653 | | * @return the number of char16_t code units required to encode the UTF-8 string |
7654 | | * as UTF-16LE |
7655 | | */ |
7656 | | simdutf_warn_unused size_t utf16_length_from_utf8(const char *input, |
7657 | | size_t length) noexcept; |
7658 | | #if SIMDUTF_SPAN |
7659 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t |
7660 | | utf16_length_from_utf8( |
7661 | | const detail::input_span_of_byte_like auto &valid_utf8_input) noexcept { |
7662 | | #if SIMDUTF_CPLUSPLUS23 |
7663 | | if consteval { |
7664 | | return scalar::utf8::utf16_length_from_utf8(valid_utf8_input.data(), |
7665 | | valid_utf8_input.size()); |
7666 | | } else |
7667 | | #endif |
7668 | | { |
7669 | | return utf16_length_from_utf8( |
7670 | | reinterpret_cast<const char *>(valid_utf8_input.data()), |
7671 | | valid_utf8_input.size()); |
7672 | | } |
7673 | | } |
7674 | | #endif // SIMDUTF_SPAN |
7675 | | |
7676 | | /** |
7677 | | * Compute the number of char16_t that this UTF-8 string requires in UTF-16 |
7678 | | * when ill-formed subsequences are replaced by U+FFFD, and record where those |
7679 | | * subsequences are. |
7680 | | * |
7681 | | * Substitution follows Unicode maximal subparts (the WHATWG rule): each |
7682 | | * maximal subpart becomes one U+FFFD. count is always the number of char16_t |
7683 | | * that convert_utf8_to_utf16_with_replacement writes, and it is at most |
7684 | | * `length`. The count does not depend on endianness. |
7685 | | * |
7686 | | * error is SUCCESS when the input is valid UTF-8. Otherwise it is the error |
7687 | | * code of the first ill-formed sequence (HEADER_BITS, TOO_SHORT, TOO_LONG, |
7688 | | * OVERLONG, TOO_LARGE, or SURROGATE). count stays correct either way. |
7689 | | * |
7690 | | * error_offset holds the first error_count byte indexes, at most |
7691 | | * utf8_to_utf16_result::max_errors (16), counting from the start of input. |
7692 | | * more_errors is true when the input has further ill-formed subsequences. |
7693 | | * Pass the whole result to convert_utf8_to_utf16_with_replacement on these |
7694 | | * same bytes. A complete list (more_errors false) lets that conversion skip a |
7695 | | * second scan. |
7696 | | * |
7697 | | * When the input is known to be valid, utf16_length_from_utf8 is the faster |
7698 | | * length function: it only counts, whereas this one validates. |
7699 | | * |
7700 | | * This function is not BOM-aware. |
7701 | | * |
7702 | | * @param input the UTF-8 string to process |
7703 | | * @param length the length of the string in bytes |
7704 | | * @return a utf8_to_utf16_result |
7705 | | */ |
7706 | | simdutf_warn_unused utf8_to_utf16_result |
7707 | | utf16_length_from_utf8_with_replacement(const char *input, |
7708 | | size_t length) noexcept; |
7709 | | #if SIMDUTF_SPAN |
7710 | | simdutf_really_inline |
7711 | | simdutf_warn_unused simdutf_constexpr23 utf8_to_utf16_result |
7712 | | utf16_length_from_utf8_with_replacement( |
7713 | | const detail::input_span_of_byte_like auto &utf8_input) noexcept { |
7714 | | #if SIMDUTF_CPLUSPLUS23 |
7715 | | if consteval { |
7716 | | return scalar::utf8_to_utf16::utf16_length_from_utf8_with_replacement( |
7717 | | utf8_input.data(), utf8_input.size()); |
7718 | | } else |
7719 | | #endif |
7720 | | { |
7721 | | return utf16_length_from_utf8_with_replacement( |
7722 | | reinterpret_cast<const char *>(utf8_input.data()), utf8_input.size()); |
7723 | | } |
7724 | | } |
7725 | | #endif // SIMDUTF_SPAN |
7726 | | #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 |
7727 | | |
7728 | | #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32 |
7729 | | /** |
7730 | | * Compute the number of 4-byte code units that this UTF-8 string would require |
7731 | | * in UTF-32 format. |
7732 | | * |
7733 | | * This function is equivalent to count_utf8 |
7734 | | * |
7735 | | * This function does not validate the input. It is acceptable to pass invalid |
7736 | | * UTF-8 strings but in such cases the result is implementation defined. |
7737 | | * |
7738 | | * This function is not BOM-aware. |
7739 | | * |
7740 | | * @param input the UTF-8 string to process |
7741 | | * @param length the length of the string in bytes |
7742 | | * @return the number of char32_t code units required to encode the UTF-8 string |
7743 | | * as UTF-32 |
7744 | | */ |
7745 | | simdutf_warn_unused size_t utf32_length_from_utf8(const char *input, |
7746 | | size_t length) noexcept; |
7747 | | #if SIMDUTF_SPAN |
7748 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t |
7749 | | utf32_length_from_utf8( |
7750 | | const detail::input_span_of_byte_like auto &valid_utf8_input) noexcept { |
7751 | | |
7752 | | #if SIMDUTF_CPLUSPLUS23 |
7753 | | if consteval { |
7754 | | return scalar::utf8::count_code_points(valid_utf8_input.data(), |
7755 | | valid_utf8_input.size()); |
7756 | | } else |
7757 | | #endif |
7758 | | { |
7759 | | return utf32_length_from_utf8( |
7760 | | reinterpret_cast<const char *>(valid_utf8_input.data()), |
7761 | | valid_utf8_input.size()); |
7762 | | } |
7763 | | } |
7764 | | #endif // SIMDUTF_SPAN |
7765 | | #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32 |
7766 | | |
7767 | | #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 |
7768 | | /** |
7769 | | * Using native endianness, convert possibly broken UTF-16 string into UTF-8 |
7770 | | * string. |
7771 | | * |
7772 | | * During the conversion also validation of the input string is done. |
7773 | | * This function is suitable to work with inputs from untrusted sources. |
7774 | | * |
7775 | | * This function is not BOM-aware. |
7776 | | * |
7777 | | * @param input the UTF-16 string to convert |
7778 | | * @param length the length of the string in 2-byte code units (char16_t) |
7779 | | * @param utf8_buffer the pointer to buffer that can hold conversion result |
7780 | | * @return number of written code units; 0 if input is not a valid UTF-16LE |
7781 | | * string |
7782 | | */ |
7783 | | simdutf_warn_unused size_t convert_utf16_to_utf8(const char16_t *input, |
7784 | | size_t length, |
7785 | | char *utf8_buffer) noexcept; |
7786 | | #if SIMDUTF_SPAN |
7787 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t |
7788 | | convert_utf16_to_utf8( |
7789 | | std::span<const char16_t> utf16_input, |
7790 | | detail::output_span_of_byte_like auto &&utf8_output) noexcept { |
7791 | | #if SIMDUTF_CPLUSPLUS23 |
7792 | | if consteval { |
7793 | | return scalar::utf16_to_utf8::convert<endianness::NATIVE>( |
7794 | | utf16_input.data(), utf16_input.size(), utf8_output.data()); |
7795 | | } else |
7796 | | #endif |
7797 | | { |
7798 | | return convert_utf16_to_utf8(utf16_input.data(), utf16_input.size(), |
7799 | | reinterpret_cast<char *>(utf8_output.data())); |
7800 | | } |
7801 | | } |
7802 | | #endif // SIMDUTF_SPAN |
7803 | | |
7804 | | /** |
7805 | | * Using native endianness, convert possibly broken UTF-16 string into UTF-8 |
7806 | | * string with output limit. |
7807 | | * |
7808 | | * We write as many characters as possible into the output buffer, |
7809 | | * |
7810 | | * During the conversion also validation of the input string is done. |
7811 | | * This function is suitable to work with inputs from untrusted sources. |
7812 | | * |
7813 | | * This function is not BOM-aware. |
7814 | | * |
7815 | | * Using convert_utf16_to_utf8_safe instead of convert_utf16_to_utf8 comes with |
7816 | | * a significant penalty in some cases, being up to three times slower, |
7817 | | * especially on short inputs. If you have allocated the output buffer so that |
7818 | | * it contains utf8_length_from_utf16(input, length) bytes, then prefer |
7819 | | * convert_utf16_to_utf8. |
7820 | | * |
7821 | | * @param input the UTF-16 string to convert |
7822 | | * @param length the length of the string in 16-bit code units (char16_t) |
7823 | | * @param utf8_output the pointer to buffer that can hold conversion result |
7824 | | * @param utf8_len the maximum output length |
7825 | | * @return the number of written char; 0 if conversion is not possible |
7826 | | */ |
7827 | | simdutf_warn_unused size_t convert_utf16_to_utf8_safe(const char16_t *input, |
7828 | | size_t length, |
7829 | | char *utf8_output, |
7830 | | size_t utf8_len) noexcept; |
7831 | | #if SIMDUTF_SPAN |
7832 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t |
7833 | | convert_utf16_to_utf8_safe( |
7834 | | std::span<const char16_t> utf16_input, |
7835 | | detail::output_span_of_byte_like auto &&utf8_output) noexcept { |
7836 | | // implementation note: outputspan is a forwarding ref to avoid copying |
7837 | | // and allow both lvalues and rvalues. std::span can be copied without |
7838 | | // problems, but std::vector should not, and this function should accept |
7839 | | // both. it will allow using an owning rvalue ref (example: passing a |
7840 | | // temporary std::string) as output, but the user will quickly find out |
7841 | | // that he has no way of getting the data out of the object in that case. |
7842 | | #if SIMDUTF_CPLUSPLUS23 |
7843 | | if consteval { |
7844 | | const full_result r = |
7845 | | scalar::utf16_to_utf8::convert_with_errors<endianness::NATIVE, true>( |
7846 | | utf16_input.data(), utf16_input.size(), utf8_output.data(), |
7847 | | utf8_output.size()); |
7848 | | if (r.error != error_code::SUCCESS && |
7849 | | r.error != error_code::OUTPUT_BUFFER_TOO_SMALL) { |
7850 | | return 0; |
7851 | | } |
7852 | | return r.output_count; |
7853 | | } else |
7854 | | #endif |
7855 | | { |
7856 | | return convert_utf16_to_utf8_safe( |
7857 | | utf16_input.data(), utf16_input.size(), |
7858 | | reinterpret_cast<char *>(utf8_output.data()), utf8_output.size()); |
7859 | | } |
7860 | | } |
7861 | | #endif // SIMDUTF_SPAN |
7862 | | |
7863 | | /** |
7864 | | * Convert a possibly broken UTF-16 string into a size-limited UTF-8 buffer and |
7865 | | * report how much input was consumed and output was written. |
7866 | | * |
7867 | | * We write as many complete characters as possible while validating the input. |
7868 | | * The returned error is SUCCESS if all input was consumed, |
7869 | | * OUTPUT_BUFFER_TOO_SMALL if the next character does not fit, or SURROGATE if |
7870 | | * an unpaired surrogate was found. |
7871 | | * |
7872 | | * @param input the UTF-16 string to convert |
7873 | | * @param length the length in 16-bit code units |
7874 | | * @param utf8_output the pointer to the output buffer |
7875 | | * @param utf8_len the maximum output length |
7876 | | * @return a full_result with error, input_count and output_count |
7877 | | */ |
7878 | | simdutf_warn_unused full_result convert_utf16_to_utf8_safe_with_details( |
7879 | | const char16_t *input, size_t length, char *utf8_output, |
7880 | | size_t utf8_len) noexcept; |
7881 | | #if SIMDUTF_SPAN |
7882 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 full_result |
7883 | | convert_utf16_to_utf8_safe_with_details( |
7884 | | std::span<const char16_t> utf16_input, |
7885 | | detail::output_span_of_byte_like auto &&utf8_output) noexcept { |
7886 | | #if SIMDUTF_CPLUSPLUS23 |
7887 | | if consteval { |
7888 | | if (utf16_input.empty()) { |
7889 | | return full_result(error_code::SUCCESS, 0, 0); |
7890 | | } |
7891 | | return scalar::utf16_to_utf8::convert_with_errors<endianness::NATIVE, true>( |
7892 | | utf16_input.data(), utf16_input.size(), utf8_output.data(), |
7893 | | utf8_output.size()); |
7894 | | } else |
7895 | | #endif |
7896 | | { |
7897 | | return convert_utf16_to_utf8_safe_with_details( |
7898 | | utf16_input.data(), utf16_input.size(), |
7899 | | reinterpret_cast<char *>(utf8_output.data()), utf8_output.size()); |
7900 | | } |
7901 | | } |
7902 | | #endif // SIMDUTF_SPAN |
7903 | | #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 |
7904 | | |
7905 | | #if SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_LATIN1 |
7906 | | /** |
7907 | | * Using native endianness, convert possibly broken UTF-16 string into Latin1 |
7908 | | * string. |
7909 | | * |
7910 | | * During the conversion also validation of the input string is done. |
7911 | | * This function is suitable to work with inputs from untrusted sources. |
7912 | | * |
7913 | | * This function is not BOM-aware. |
7914 | | * |
7915 | | * @param input the UTF-16 string to convert |
7916 | | * @param length the length of the string in 2-byte code units (char16_t) |
7917 | | * @param latin1_buffer the pointer to buffer that can hold conversion result |
7918 | | * @return number of written code units; 0 if input is not a valid UTF-16 string |
7919 | | * or if it cannot be represented as Latin1 |
7920 | | */ |
7921 | | simdutf_warn_unused size_t convert_utf16_to_latin1( |
7922 | | const char16_t *input, size_t length, char *latin1_buffer) noexcept; |
7923 | | #if SIMDUTF_SPAN |
7924 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t |
7925 | | convert_utf16_to_latin1( |
7926 | | std::span<const char16_t> utf16_input, |
7927 | | detail::output_span_of_byte_like auto &&latin1_output) noexcept { |
7928 | | #if SIMDUTF_CPLUSPLUS23 |
7929 | | if consteval { |
7930 | | return scalar::utf16_to_latin1::convert<endianness::NATIVE>( |
7931 | | utf16_input.data(), utf16_input.size(), latin1_output.data()); |
7932 | | } else |
7933 | | #endif |
7934 | | { |
7935 | | return convert_utf16_to_latin1( |
7936 | | utf16_input.data(), utf16_input.size(), |
7937 | | reinterpret_cast<char *>(latin1_output.data())); |
7938 | | } |
7939 | | } |
7940 | | #endif // SIMDUTF_SPAN |
7941 | | |
7942 | | /** |
7943 | | * Convert possibly broken UTF-16LE string into Latin1 string. |
7944 | | * If the string cannot be represented as Latin1, an error |
7945 | | * is returned. |
7946 | | * |
7947 | | * During the conversion also validation of the input string is done. |
7948 | | * This function is suitable to work with inputs from untrusted sources. |
7949 | | * |
7950 | | * This function is not BOM-aware. |
7951 | | * |
7952 | | * @param input the UTF-16LE string to convert |
7953 | | * @param length the length of the string in 2-byte code units (char16_t) |
7954 | | * @param latin1_buffer the pointer to buffer that can hold conversion result |
7955 | | * @return number of written code units; 0 if input is not a valid UTF-16LE |
7956 | | * string or if it cannot be represented as Latin1 |
7957 | | */ |
7958 | | simdutf_warn_unused size_t convert_utf16le_to_latin1( |
7959 | | const char16_t *input, size_t length, char *latin1_buffer) noexcept; |
7960 | | #if SIMDUTF_SPAN |
7961 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t |
7962 | | convert_utf16le_to_latin1( |
7963 | | std::span<const char16_t> utf16_input, |
7964 | | detail::output_span_of_byte_like auto &&latin1_output) noexcept { |
7965 | | #if SIMDUTF_CPLUSPLUS23 |
7966 | | if consteval { |
7967 | | return scalar::utf16_to_latin1::convert<endianness::LITTLE>( |
7968 | | utf16_input.data(), utf16_input.size(), latin1_output.data()); |
7969 | | } else |
7970 | | #endif |
7971 | | { |
7972 | | return convert_utf16le_to_latin1( |
7973 | | utf16_input.data(), utf16_input.size(), |
7974 | | reinterpret_cast<char *>(latin1_output.data())); |
7975 | | } |
7976 | | } |
7977 | | #endif // SIMDUTF_SPAN |
7978 | | |
7979 | | /** |
7980 | | * Convert possibly broken UTF-16BE string into Latin1 string. |
7981 | | * |
7982 | | * During the conversion also validation of the input string is done. |
7983 | | * This function is suitable to work with inputs from untrusted sources. |
7984 | | * |
7985 | | * This function is not BOM-aware. |
7986 | | * |
7987 | | * @param input the UTF-16BE string to convert |
7988 | | * @param length the length of the string in 2-byte code units (char16_t) |
7989 | | * @param latin1_buffer the pointer to buffer that can hold conversion result |
7990 | | * @return number of written code units; 0 if input is not a valid UTF-16BE |
7991 | | * string or if it cannot be represented as Latin1 |
7992 | | */ |
7993 | | simdutf_warn_unused size_t convert_utf16be_to_latin1( |
7994 | | const char16_t *input, size_t length, char *latin1_buffer) noexcept; |
7995 | | #if SIMDUTF_SPAN |
7996 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t |
7997 | | convert_utf16be_to_latin1( |
7998 | | std::span<const char16_t> utf16_input, |
7999 | | detail::output_span_of_byte_like auto &&latin1_output) noexcept { |
8000 | | #if SIMDUTF_CPLUSPLUS23 |
8001 | | if consteval { |
8002 | | return scalar::utf16_to_latin1::convert<endianness::BIG>( |
8003 | | utf16_input.data(), utf16_input.size(), latin1_output.data()); |
8004 | | } else |
8005 | | #endif |
8006 | | { |
8007 | | return convert_utf16be_to_latin1( |
8008 | | utf16_input.data(), utf16_input.size(), |
8009 | | reinterpret_cast<char *>(latin1_output.data())); |
8010 | | } |
8011 | | } |
8012 | | #endif // SIMDUTF_SPAN |
8013 | | #endif // SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_LATIN1 |
8014 | | |
8015 | | #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 |
8016 | | /** |
8017 | | * Convert possibly broken UTF-16LE string into UTF-8 string. |
8018 | | * |
8019 | | * During the conversion also validation of the input string is done. |
8020 | | * This function is suitable to work with inputs from untrusted sources. |
8021 | | * |
8022 | | * This function is not BOM-aware. |
8023 | | * |
8024 | | * @param input the UTF-16LE string to convert |
8025 | | * @param length the length of the string in 2-byte code units (char16_t) |
8026 | | * @param utf8_buffer the pointer to buffer that can hold conversion result |
8027 | | * @return number of written code units; 0 if input is not a valid UTF-16LE |
8028 | | * string |
8029 | | */ |
8030 | | simdutf_warn_unused size_t convert_utf16le_to_utf8(const char16_t *input, |
8031 | | size_t length, |
8032 | | char *utf8_buffer) noexcept; |
8033 | | #if SIMDUTF_SPAN |
8034 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t |
8035 | | convert_utf16le_to_utf8( |
8036 | | std::span<const char16_t> utf16_input, |
8037 | | detail::output_span_of_byte_like auto &&utf8_output) noexcept { |
8038 | | #if SIMDUTF_CPLUSPLUS23 |
8039 | | if consteval { |
8040 | | return scalar::utf16_to_utf8::convert<endianness::LITTLE>( |
8041 | | utf16_input.data(), utf16_input.size(), utf8_output.data()); |
8042 | | } else |
8043 | | #endif |
8044 | | { |
8045 | | return convert_utf16le_to_utf8( |
8046 | | utf16_input.data(), utf16_input.size(), |
8047 | | reinterpret_cast<char *>(utf8_output.data())); |
8048 | | } |
8049 | | } |
8050 | | #endif // SIMDUTF_SPAN |
8051 | | |
8052 | | /** |
8053 | | * Convert possibly broken UTF-16BE string into UTF-8 string. |
8054 | | * |
8055 | | * During the conversion also validation of the input string is done. |
8056 | | * This function is suitable to work with inputs from untrusted sources. |
8057 | | * |
8058 | | * This function is not BOM-aware. |
8059 | | * |
8060 | | * @param input the UTF-16BE string to convert |
8061 | | * @param length the length of the string in 2-byte code units (char16_t) |
8062 | | * @param utf8_buffer the pointer to buffer that can hold conversion result |
8063 | | * @return number of written code units; 0 if input is not a valid UTF-16LE |
8064 | | * string |
8065 | | */ |
8066 | | simdutf_warn_unused size_t convert_utf16be_to_utf8(const char16_t *input, |
8067 | | size_t length, |
8068 | | char *utf8_buffer) noexcept; |
8069 | | #if SIMDUTF_SPAN |
8070 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t |
8071 | | convert_utf16be_to_utf8( |
8072 | | std::span<const char16_t> utf16_input, |
8073 | | detail::output_span_of_byte_like auto &&utf8_output) noexcept { |
8074 | | #if SIMDUTF_CPLUSPLUS23 |
8075 | | if consteval { |
8076 | | return scalar::utf16_to_utf8::convert<endianness::BIG>( |
8077 | | utf16_input.data(), utf16_input.size(), utf8_output.data()); |
8078 | | } else |
8079 | | #endif |
8080 | | { |
8081 | | return convert_utf16be_to_utf8( |
8082 | | utf16_input.data(), utf16_input.size(), |
8083 | | reinterpret_cast<char *>(utf8_output.data())); |
8084 | | } |
8085 | | } |
8086 | | #endif // SIMDUTF_SPAN |
8087 | | #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 |
8088 | | |
8089 | | #if SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_LATIN1 |
8090 | | /** |
8091 | | * Using native endianness, convert possibly broken UTF-16 string into Latin1 |
8092 | | * string. |
8093 | | * |
8094 | | * During the conversion also validation of the input string is done. |
8095 | | * This function is suitable to work with inputs from untrusted sources. |
8096 | | * This function is not BOM-aware. |
8097 | | * |
8098 | | * @param input the UTF-16 string to convert |
8099 | | * @param length the length of the string in 2-byte code units (char16_t) |
8100 | | * @param latin1_buffer the pointer to buffer that can hold conversion result |
8101 | | * @return a result pair struct (of type simdutf::result containing the two |
8102 | | * fields error and count) with an error code and either position of the error |
8103 | | * (in the input in code units) if any, or the number of char written if |
8104 | | * successful. |
8105 | | */ |
8106 | | simdutf_warn_unused result convert_utf16_to_latin1_with_errors( |
8107 | | const char16_t *input, size_t length, char *latin1_buffer) noexcept; |
8108 | | #if SIMDUTF_SPAN |
8109 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result |
8110 | | convert_utf16_to_latin1_with_errors( |
8111 | | std::span<const char16_t> utf16_input, |
8112 | | detail::output_span_of_byte_like auto &&latin1_output) noexcept { |
8113 | | #if SIMDUTF_CPLUSPLUS23 |
8114 | | if consteval { |
8115 | | return scalar::utf16_to_latin1::convert_with_errors<endianness::NATIVE>( |
8116 | | utf16_input.data(), utf16_input.size(), latin1_output.data()); |
8117 | | } else |
8118 | | #endif |
8119 | | { |
8120 | | return convert_utf16_to_latin1_with_errors( |
8121 | | utf16_input.data(), utf16_input.size(), |
8122 | | reinterpret_cast<char *>(latin1_output.data())); |
8123 | | } |
8124 | | } |
8125 | | #endif // SIMDUTF_SPAN |
8126 | | |
8127 | | /** |
8128 | | * Convert possibly broken UTF-16LE string into Latin1 string. |
8129 | | * |
8130 | | * During the conversion also validation of the input string is done. |
8131 | | * This function is suitable to work with inputs from untrusted sources. |
8132 | | * This function is not BOM-aware. |
8133 | | * |
8134 | | * @param input the UTF-16LE string to convert |
8135 | | * @param length the length of the string in 2-byte code units (char16_t) |
8136 | | * @param latin1_buffer the pointer to buffer that can hold conversion result |
8137 | | * @return a result pair struct (of type simdutf::result containing the two |
8138 | | * fields error and count) with an error code and either position of the error |
8139 | | * (in the input in code units) if any, or the number of char written if |
8140 | | * successful. |
8141 | | */ |
8142 | | simdutf_warn_unused result convert_utf16le_to_latin1_with_errors( |
8143 | | const char16_t *input, size_t length, char *latin1_buffer) noexcept; |
8144 | | #if SIMDUTF_SPAN |
8145 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result |
8146 | | convert_utf16le_to_latin1_with_errors( |
8147 | | std::span<const char16_t> utf16_input, |
8148 | | detail::output_span_of_byte_like auto &&latin1_output) noexcept { |
8149 | | #if SIMDUTF_CPLUSPLUS23 |
8150 | | if consteval { |
8151 | | return scalar::utf16_to_latin1::convert_with_errors<endianness::LITTLE>( |
8152 | | utf16_input.data(), utf16_input.size(), latin1_output.data()); |
8153 | | } else |
8154 | | #endif |
8155 | | { |
8156 | | return convert_utf16le_to_latin1_with_errors( |
8157 | | utf16_input.data(), utf16_input.size(), |
8158 | | reinterpret_cast<char *>(latin1_output.data())); |
8159 | | } |
8160 | | } |
8161 | | #endif // SIMDUTF_SPAN |
8162 | | |
8163 | | /** |
8164 | | * Convert possibly broken UTF-16BE string into Latin1 string. |
8165 | | * If the string cannot be represented as Latin1, an error |
8166 | | * is returned. |
8167 | | * |
8168 | | * During the conversion also validation of the input string is done. |
8169 | | * This function is suitable to work with inputs from untrusted sources. |
8170 | | * This function is not BOM-aware. |
8171 | | * |
8172 | | * @param input the UTF-16BE string to convert |
8173 | | * @param length the length of the string in 2-byte code units (char16_t) |
8174 | | * @param latin1_buffer the pointer to buffer that can hold conversion result |
8175 | | * @return a result pair struct (of type simdutf::result containing the two |
8176 | | * fields error and count) with an error code and either position of the error |
8177 | | * (in the input in code units) if any, or the number of char written if |
8178 | | * successful. |
8179 | | */ |
8180 | | simdutf_warn_unused result convert_utf16be_to_latin1_with_errors( |
8181 | | const char16_t *input, size_t length, char *latin1_buffer) noexcept; |
8182 | | #if SIMDUTF_SPAN |
8183 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result |
8184 | | convert_utf16be_to_latin1_with_errors( |
8185 | | std::span<const char16_t> utf16_input, |
8186 | | detail::output_span_of_byte_like auto &&latin1_output) noexcept { |
8187 | | #if SIMDUTF_CPLUSPLUS23 |
8188 | | if consteval { |
8189 | | return scalar::utf16_to_latin1::convert_with_errors<endianness::BIG>( |
8190 | | utf16_input.data(), utf16_input.size(), latin1_output.data()); |
8191 | | } else |
8192 | | #endif |
8193 | | { |
8194 | | return convert_utf16be_to_latin1_with_errors( |
8195 | | utf16_input.data(), utf16_input.size(), |
8196 | | reinterpret_cast<char *>(latin1_output.data())); |
8197 | | } |
8198 | | } |
8199 | | #endif // SIMDUTF_SPAN |
8200 | | #endif // SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_LATIN1 |
8201 | | |
8202 | | #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 |
8203 | | /** |
8204 | | * Using native endianness, convert possibly broken UTF-16 string into UTF-8 |
8205 | | * string and stop on error. |
8206 | | * |
8207 | | * During the conversion also validation of the input string is done. |
8208 | | * This function is suitable to work with inputs from untrusted sources. |
8209 | | * |
8210 | | * This function is not BOM-aware. |
8211 | | * |
8212 | | * @param input the UTF-16 string to convert |
8213 | | * @param length the length of the string in 2-byte code units (char16_t) |
8214 | | * @param utf8_buffer the pointer to buffer that can hold conversion result |
8215 | | * @return a result pair struct (of type simdutf::result containing the two |
8216 | | * fields error and count) with an error code and either position of the error |
8217 | | * (in the input in code units) if any, or the number of char written if |
8218 | | * successful. |
8219 | | */ |
8220 | | simdutf_warn_unused result convert_utf16_to_utf8_with_errors( |
8221 | | const char16_t *input, size_t length, char *utf8_buffer) noexcept; |
8222 | | #if SIMDUTF_SPAN |
8223 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result |
8224 | | convert_utf16_to_utf8_with_errors( |
8225 | | std::span<const char16_t> utf16_input, |
8226 | | detail::output_span_of_byte_like auto &&utf8_output) noexcept { |
8227 | | #if SIMDUTF_CPLUSPLUS23 |
8228 | | if consteval { |
8229 | | return scalar::utf16_to_utf8::convert_with_errors<endianness::NATIVE>( |
8230 | | utf16_input.data(), utf16_input.size(), utf8_output.data()); |
8231 | | } else |
8232 | | #endif |
8233 | | { |
8234 | | return convert_utf16_to_utf8_with_errors( |
8235 | | utf16_input.data(), utf16_input.size(), |
8236 | | reinterpret_cast<char *>(utf8_output.data())); |
8237 | | } |
8238 | | } |
8239 | | #endif // SIMDUTF_SPAN |
8240 | | |
8241 | | /** |
8242 | | * Convert possibly broken UTF-16LE string into UTF-8 string and stop on error. |
8243 | | * |
8244 | | * During the conversion also validation of the input string is done. |
8245 | | * This function is suitable to work with inputs from untrusted sources. |
8246 | | * |
8247 | | * This function is not BOM-aware. |
8248 | | * |
8249 | | * @param input the UTF-16LE string to convert |
8250 | | * @param length the length of the string in 2-byte code units (char16_t) |
8251 | | * @param utf8_buffer the pointer to buffer that can hold conversion result |
8252 | | * @return a result pair struct (of type simdutf::result containing the two |
8253 | | * fields error and count) with an error code and either position of the error |
8254 | | * (in the input in code units) if any, or the number of char written if |
8255 | | * successful. |
8256 | | */ |
8257 | | simdutf_warn_unused result convert_utf16le_to_utf8_with_errors( |
8258 | | const char16_t *input, size_t length, char *utf8_buffer) noexcept; |
8259 | | #if SIMDUTF_SPAN |
8260 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result |
8261 | | convert_utf16le_to_utf8_with_errors( |
8262 | | std::span<const char16_t> utf16_input, |
8263 | | detail::output_span_of_byte_like auto &&utf8_output) noexcept { |
8264 | | #if SIMDUTF_CPLUSPLUS23 |
8265 | | if consteval { |
8266 | | return scalar::utf16_to_utf8::convert_with_errors<endianness::LITTLE>( |
8267 | | utf16_input.data(), utf16_input.size(), utf8_output.data()); |
8268 | | } else |
8269 | | #endif |
8270 | | { |
8271 | | return convert_utf16le_to_utf8_with_errors( |
8272 | | utf16_input.data(), utf16_input.size(), |
8273 | | reinterpret_cast<char *>(utf8_output.data())); |
8274 | | } |
8275 | | } |
8276 | | #endif // SIMDUTF_SPAN |
8277 | | |
8278 | | /** |
8279 | | * Convert possibly broken UTF-16BE string into UTF-8 string and stop on error. |
8280 | | * |
8281 | | * During the conversion also validation of the input string is done. |
8282 | | * This function is suitable to work with inputs from untrusted sources. |
8283 | | * |
8284 | | * This function is not BOM-aware. |
8285 | | * |
8286 | | * @param input the UTF-16BE string to convert |
8287 | | * @param length the length of the string in 2-byte code units (char16_t) |
8288 | | * @param utf8_buffer the pointer to buffer that can hold conversion result |
8289 | | * @return a result pair struct (of type simdutf::result containing the two |
8290 | | * fields error and count) with an error code and either position of the error |
8291 | | * (in the input in code units) if any, or the number of char written if |
8292 | | * successful. |
8293 | | */ |
8294 | | simdutf_warn_unused result convert_utf16be_to_utf8_with_errors( |
8295 | | const char16_t *input, size_t length, char *utf8_buffer) noexcept; |
8296 | | #if SIMDUTF_SPAN |
8297 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result |
8298 | | convert_utf16be_to_utf8_with_errors( |
8299 | | std::span<const char16_t> utf16_input, |
8300 | | detail::output_span_of_byte_like auto &&utf8_output) noexcept { |
8301 | | #if SIMDUTF_CPLUSPLUS23 |
8302 | | if consteval { |
8303 | | return scalar::utf16_to_utf8::convert_with_errors<endianness::BIG>( |
8304 | | utf16_input.data(), utf16_input.size(), utf8_output.data()); |
8305 | | } else |
8306 | | #endif |
8307 | | { |
8308 | | return convert_utf16be_to_utf8_with_errors( |
8309 | | utf16_input.data(), utf16_input.size(), |
8310 | | reinterpret_cast<char *>(utf8_output.data())); |
8311 | | } |
8312 | | } |
8313 | | #endif // SIMDUTF_SPAN |
8314 | | |
8315 | | /** |
8316 | | * Convert possibly broken UTF-16LE string into UTF-8 string, replacing |
8317 | | * unpaired surrogates with the Unicode replacement character U+FFFD. |
8318 | | * |
8319 | | * This function always succeeds: unpaired surrogates are replaced with |
8320 | | * U+FFFD (3 bytes in UTF-8: 0xEF 0xBF 0xBD). |
8321 | | * |
8322 | | * This function is not BOM-aware. |
8323 | | * |
8324 | | * @param input the UTF-16LE string to convert |
8325 | | * @param length the length of the string in 2-byte code units (char16_t) |
8326 | | * @param utf8_buffer the pointer to buffer that can hold conversion result |
8327 | | * @return number of written code units |
8328 | | */ |
8329 | | simdutf_warn_unused size_t convert_utf16le_to_utf8_with_replacement( |
8330 | | const char16_t *input, size_t length, char *utf8_buffer) noexcept; |
8331 | | #if SIMDUTF_SPAN |
8332 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t |
8333 | | convert_utf16le_to_utf8_with_replacement( |
8334 | | std::span<const char16_t> utf16_input, |
8335 | | detail::output_span_of_byte_like auto &&utf8_output) noexcept { |
8336 | | #if SIMDUTF_CPLUSPLUS23 |
8337 | | if consteval { |
8338 | | return scalar::utf16_to_utf8::convert_with_replacement<endianness::LITTLE>( |
8339 | | utf16_input.data(), utf16_input.size(), utf8_output.data()); |
8340 | | } else |
8341 | | #endif |
8342 | | { |
8343 | | return convert_utf16le_to_utf8_with_replacement( |
8344 | | utf16_input.data(), utf16_input.size(), |
8345 | | reinterpret_cast<char *>(utf8_output.data())); |
8346 | | } |
8347 | | } |
8348 | | #endif // SIMDUTF_SPAN |
8349 | | |
8350 | | /** |
8351 | | * Convert possibly broken UTF-16BE string into UTF-8 string, replacing |
8352 | | * unpaired surrogates with the Unicode replacement character U+FFFD. |
8353 | | * |
8354 | | * This function always succeeds: unpaired surrogates are replaced with |
8355 | | * U+FFFD (3 bytes in UTF-8: 0xEF 0xBF 0xBD). |
8356 | | * |
8357 | | * This function is not BOM-aware. |
8358 | | * |
8359 | | * @param input the UTF-16BE string to convert |
8360 | | * @param length the length of the string in 2-byte code units (char16_t) |
8361 | | * @param utf8_buffer the pointer to buffer that can hold conversion result |
8362 | | * @return number of written code units |
8363 | | */ |
8364 | | simdutf_warn_unused size_t convert_utf16be_to_utf8_with_replacement( |
8365 | | const char16_t *input, size_t length, char *utf8_buffer) noexcept; |
8366 | | #if SIMDUTF_SPAN |
8367 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t |
8368 | | convert_utf16be_to_utf8_with_replacement( |
8369 | | std::span<const char16_t> utf16_input, |
8370 | | detail::output_span_of_byte_like auto &&utf8_output) noexcept { |
8371 | | #if SIMDUTF_CPLUSPLUS23 |
8372 | | if consteval { |
8373 | | return scalar::utf16_to_utf8::convert_with_replacement<endianness::BIG>( |
8374 | | utf16_input.data(), utf16_input.size(), utf8_output.data()); |
8375 | | } else |
8376 | | #endif |
8377 | | { |
8378 | | return convert_utf16be_to_utf8_with_replacement( |
8379 | | utf16_input.data(), utf16_input.size(), |
8380 | | reinterpret_cast<char *>(utf8_output.data())); |
8381 | | } |
8382 | | } |
8383 | | #endif // SIMDUTF_SPAN |
8384 | | |
8385 | | /** |
8386 | | * Convert possibly broken UTF-16 string (native endianness) into UTF-8 string, |
8387 | | * replacing unpaired surrogates with the Unicode replacement character U+FFFD. |
8388 | | * |
8389 | | * This function always succeeds: unpaired surrogates are replaced with |
8390 | | * U+FFFD (3 bytes in UTF-8: 0xEF 0xBF 0xBD). |
8391 | | * |
8392 | | * This function is not BOM-aware. |
8393 | | * |
8394 | | * @param input the UTF-16 string to convert |
8395 | | * @param length the length of the string in 2-byte code units (char16_t) |
8396 | | * @param utf8_buffer the pointer to buffer that can hold conversion result |
8397 | | * @return number of written code units |
8398 | | */ |
8399 | | simdutf_warn_unused size_t convert_utf16_to_utf8_with_replacement( |
8400 | | const char16_t *input, size_t length, char *utf8_buffer) noexcept; |
8401 | | #if SIMDUTF_SPAN |
8402 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t |
8403 | | convert_utf16_to_utf8_with_replacement( |
8404 | | std::span<const char16_t> utf16_input, |
8405 | | detail::output_span_of_byte_like auto &&utf8_output) noexcept { |
8406 | | #if SIMDUTF_CPLUSPLUS23 |
8407 | | if consteval { |
8408 | | return scalar::utf16_to_utf8::convert_with_replacement<endianness::NATIVE>( |
8409 | | utf16_input.data(), utf16_input.size(), utf8_output.data()); |
8410 | | } else |
8411 | | #endif |
8412 | | { |
8413 | | return convert_utf16_to_utf8_with_replacement( |
8414 | | utf16_input.data(), utf16_input.size(), |
8415 | | reinterpret_cast<char *>(utf8_output.data())); |
8416 | | } |
8417 | | } |
8418 | | #endif // SIMDUTF_SPAN |
8419 | | |
8420 | | /** |
8421 | | * Convert a possibly broken UTF-16 string into a size-limited UTF-8 buffer, |
8422 | | * replacing unpaired surrogates with U+FFFD and reporting how much input was |
8423 | | * consumed and output was written. |
8424 | | * |
8425 | | * We write as many complete characters as possible. The returned error is |
8426 | | * SUCCESS if all input was consumed, or OUTPUT_BUFFER_TOO_SMALL if the next |
8427 | | * character or replacement does not fit. |
8428 | | * |
8429 | | * @param input the UTF-16 string to convert |
8430 | | * @param length the length in 16-bit code units |
8431 | | * @param utf8_output the pointer to the output buffer |
8432 | | * @param utf8_len the maximum output length |
8433 | | * @return a full_result with error, input_count and output_count |
8434 | | */ |
8435 | | simdutf_warn_unused full_result convert_utf16_to_utf8_with_replacement_safe( |
8436 | | const char16_t *input, size_t length, char *utf8_output, |
8437 | | size_t utf8_len) noexcept; |
8438 | | #if SIMDUTF_SPAN |
8439 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 full_result |
8440 | | convert_utf16_to_utf8_with_replacement_safe( |
8441 | | std::span<const char16_t> utf16_input, |
8442 | | detail::output_span_of_byte_like auto &&utf8_output) noexcept { |
8443 | | #if SIMDUTF_CPLUSPLUS23 |
8444 | | if consteval { |
8445 | | return scalar::utf16_to_utf8::convert_with_replacement_safe< |
8446 | | endianness::NATIVE>(utf16_input.data(), utf16_input.size(), |
8447 | | utf8_output.data(), utf8_output.size()); |
8448 | | } else |
8449 | | #endif |
8450 | | { |
8451 | | return convert_utf16_to_utf8_with_replacement_safe( |
8452 | | utf16_input.data(), utf16_input.size(), |
8453 | | reinterpret_cast<char *>(utf8_output.data()), utf8_output.size()); |
8454 | | } |
8455 | | } |
8456 | | #endif // SIMDUTF_SPAN |
8457 | | #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 |
8458 | | |
8459 | | #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 |
8460 | | /** |
8461 | | * Using native endianness, convert valid UTF-16 string into UTF-8 string. |
8462 | | * |
8463 | | * This function assumes that the input string is valid UTF-16. |
8464 | | * |
8465 | | * This function is not BOM-aware. |
8466 | | * |
8467 | | * @param input the UTF-16 string to convert |
8468 | | * @param length the length of the string in 2-byte code units (char16_t) |
8469 | | * @param utf8_buffer the pointer to a buffer that can hold the conversion |
8470 | | * result |
8471 | | * @return number of written code units; 0 if conversion is not possible |
8472 | | */ |
8473 | | simdutf_warn_unused size_t convert_valid_utf16_to_utf8( |
8474 | | const char16_t *input, size_t length, char *utf8_buffer) noexcept; |
8475 | | #if SIMDUTF_SPAN |
8476 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t |
8477 | | convert_valid_utf16_to_utf8( |
8478 | | std::span<const char16_t> valid_utf16_input, |
8479 | | detail::output_span_of_byte_like auto &&utf8_output) noexcept { |
8480 | | #if SIMDUTF_CPLUSPLUS23 |
8481 | | if consteval { |
8482 | | return scalar::utf16_to_utf8::convert_valid<endianness::NATIVE>( |
8483 | | valid_utf16_input.data(), valid_utf16_input.size(), utf8_output.data()); |
8484 | | } else |
8485 | | #endif |
8486 | | { |
8487 | | return convert_valid_utf16_to_utf8( |
8488 | | valid_utf16_input.data(), valid_utf16_input.size(), |
8489 | | reinterpret_cast<char *>(utf8_output.data())); |
8490 | | } |
8491 | | } |
8492 | | #endif // SIMDUTF_SPAN |
8493 | | #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 |
8494 | | |
8495 | | #if SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_LATIN1 |
8496 | | /** |
8497 | | * Using native endianness, convert UTF-16 string into Latin1 string. |
8498 | | * |
8499 | | * This function assumes that the input string is valid UTF-16 and that it can |
8500 | | * be represented as Latin1. If you violate this assumption, the result is |
8501 | | * implementation defined and may include system-dependent behavior such as |
8502 | | * crashes. |
8503 | | * |
8504 | | * This function is for expert users only and not part of our public API. Use |
8505 | | * convert_utf16_to_latin1 instead. The function may be removed from the library |
8506 | | * in the future. |
8507 | | * |
8508 | | * This function is not BOM-aware. |
8509 | | * |
8510 | | * @param input the UTF-16 string to convert |
8511 | | * @param length the length of the string in 2-byte code units (char16_t) |
8512 | | * @param latin1_buffer the pointer to buffer that can hold conversion result |
8513 | | * @return number of written code units; 0 if conversion is not possible |
8514 | | */ |
8515 | | simdutf_warn_unused size_t convert_valid_utf16_to_latin1( |
8516 | | const char16_t *input, size_t length, char *latin1_buffer) noexcept; |
8517 | | #if SIMDUTF_SPAN |
8518 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t |
8519 | | convert_valid_utf16_to_latin1( |
8520 | | std::span<const char16_t> valid_utf16_input, |
8521 | | detail::output_span_of_byte_like auto &&latin1_output) noexcept { |
8522 | | #if SIMDUTF_CPLUSPLUS23 |
8523 | | if consteval { |
8524 | | return scalar::utf16_to_latin1::convert_valid_impl<endianness::NATIVE>( |
8525 | | detail::constexpr_cast_ptr<uint16_t>(valid_utf16_input.data()), |
8526 | | valid_utf16_input.size(), |
8527 | | detail::constexpr_cast_writeptr<char>(latin1_output.data())); |
8528 | | } else |
8529 | | #endif |
8530 | | { |
8531 | | return convert_valid_utf16_to_latin1( |
8532 | | valid_utf16_input.data(), valid_utf16_input.size(), |
8533 | | reinterpret_cast<char *>(latin1_output.data())); |
8534 | | } |
8535 | | } |
8536 | | #endif // SIMDUTF_SPAN |
8537 | | |
8538 | | /** |
8539 | | * Convert valid UTF-16LE string into Latin1 string. |
8540 | | * |
8541 | | * This function assumes that the input string is valid UTF-16LE and that it can |
8542 | | * be represented as Latin1. If you violate this assumption, the result is |
8543 | | * implementation defined and may include system-dependent behavior such as |
8544 | | * crashes. |
8545 | | * |
8546 | | * This function is for expert users only and not part of our public API. Use |
8547 | | * convert_utf16le_to_latin1 instead. The function may be removed from the |
8548 | | * library in the future. |
8549 | | * |
8550 | | * This function is not BOM-aware. |
8551 | | * |
8552 | | * @param input the UTF-16LE string to convert |
8553 | | * @param length the length of the string in 2-byte code units (char16_t) |
8554 | | * @param latin1_buffer the pointer to buffer that can hold conversion result |
8555 | | * @return number of written code units; 0 if conversion is not possible |
8556 | | */ |
8557 | | simdutf_warn_unused size_t convert_valid_utf16le_to_latin1( |
8558 | | const char16_t *input, size_t length, char *latin1_buffer) noexcept; |
8559 | | #if SIMDUTF_SPAN |
8560 | | simdutf_really_inline simdutf_constexpr23 simdutf_warn_unused size_t |
8561 | | convert_valid_utf16le_to_latin1( |
8562 | | std::span<const char16_t> valid_utf16_input, |
8563 | | detail::output_span_of_byte_like auto &&latin1_output) noexcept { |
8564 | | #if SIMDUTF_CPLUSPLUS23 |
8565 | | if consteval { |
8566 | | return scalar::utf16_to_latin1::convert_valid_impl<endianness::LITTLE>( |
8567 | | detail::constexpr_cast_ptr<uint16_t>(valid_utf16_input.data()), |
8568 | | valid_utf16_input.size(), |
8569 | | detail::constexpr_cast_writeptr<char>(latin1_output.data())); |
8570 | | } else |
8571 | | #endif |
8572 | | { |
8573 | | return convert_valid_utf16le_to_latin1( |
8574 | | valid_utf16_input.data(), valid_utf16_input.size(), |
8575 | | reinterpret_cast<char *>(latin1_output.data())); |
8576 | | } |
8577 | | } |
8578 | | #endif // SIMDUTF_SPAN |
8579 | | |
8580 | | /** |
8581 | | * Convert valid UTF-16BE string into Latin1 string. |
8582 | | * |
8583 | | * This function assumes that the input string is valid UTF-16BE and that it can |
8584 | | * be represented as Latin1. If you violate this assumption, the result is |
8585 | | * implementation defined and may include system-dependent behavior such as |
8586 | | * crashes. |
8587 | | * |
8588 | | * This function is for expert users only and not part of our public API. Use |
8589 | | * convert_utf16be_to_latin1 instead. The function may be removed from the |
8590 | | * library in the future. |
8591 | | * |
8592 | | * This function is not BOM-aware. |
8593 | | * |
8594 | | * @param input the UTF-16BE string to convert |
8595 | | * @param length the length of the string in 2-byte code units (char16_t) |
8596 | | * @param latin1_buffer the pointer to buffer that can hold conversion result |
8597 | | * @return number of written code units; 0 if conversion is not possible |
8598 | | */ |
8599 | | simdutf_warn_unused size_t convert_valid_utf16be_to_latin1( |
8600 | | const char16_t *input, size_t length, char *latin1_buffer) noexcept; |
8601 | | #if SIMDUTF_SPAN |
8602 | | simdutf_really_inline simdutf_constexpr23 simdutf_warn_unused size_t |
8603 | | convert_valid_utf16be_to_latin1( |
8604 | | std::span<const char16_t> valid_utf16_input, |
8605 | | detail::output_span_of_byte_like auto &&latin1_output) noexcept { |
8606 | | #if SIMDUTF_CPLUSPLUS23 |
8607 | | if consteval { |
8608 | | return scalar::utf16_to_latin1::convert_valid_impl<endianness::BIG>( |
8609 | | detail::constexpr_cast_ptr<uint16_t>(valid_utf16_input.data()), |
8610 | | valid_utf16_input.size(), |
8611 | | detail::constexpr_cast_writeptr<char>(latin1_output.data())); |
8612 | | } else |
8613 | | #endif |
8614 | | { |
8615 | | return convert_valid_utf16be_to_latin1( |
8616 | | valid_utf16_input.data(), valid_utf16_input.size(), |
8617 | | reinterpret_cast<char *>(latin1_output.data())); |
8618 | | } |
8619 | | } |
8620 | | #endif // SIMDUTF_SPAN |
8621 | | #endif // SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_LATIN1 |
8622 | | |
8623 | | #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 |
8624 | | /** |
8625 | | * Convert valid UTF-16LE string into UTF-8 string. |
8626 | | * |
8627 | | * This function assumes that the input string is valid UTF-16LE |
8628 | | * |
8629 | | * This function is not BOM-aware. |
8630 | | * |
8631 | | * @param input the UTF-16LE string to convert |
8632 | | * @param length the length of the string in 2-byte code units (char16_t) |
8633 | | * @param utf8_buffer the pointer to a buffer that can hold the conversion |
8634 | | * result |
8635 | | * @return number of written code units; 0 if conversion is not possible |
8636 | | */ |
8637 | | simdutf_warn_unused size_t convert_valid_utf16le_to_utf8( |
8638 | | const char16_t *input, size_t length, char *utf8_buffer) noexcept; |
8639 | | #if SIMDUTF_SPAN |
8640 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t |
8641 | | convert_valid_utf16le_to_utf8( |
8642 | | std::span<const char16_t> valid_utf16_input, |
8643 | | detail::output_span_of_byte_like auto &&utf8_output) noexcept { |
8644 | | #if SIMDUTF_CPLUSPLUS23 |
8645 | | if consteval { |
8646 | | return scalar::utf16_to_utf8::convert_valid<endianness::NATIVE>( |
8647 | | valid_utf16_input.data(), valid_utf16_input.size(), utf8_output.data()); |
8648 | | } else |
8649 | | #endif |
8650 | | { |
8651 | | return convert_valid_utf16le_to_utf8( |
8652 | | valid_utf16_input.data(), valid_utf16_input.size(), |
8653 | | reinterpret_cast<char *>(utf8_output.data())); |
8654 | | } |
8655 | | } |
8656 | | #endif // SIMDUTF_SPAN |
8657 | | |
8658 | | /** |
8659 | | * Convert valid UTF-16BE string into UTF-8 string. |
8660 | | * |
8661 | | * This function assumes that the input string is valid UTF-16BE. |
8662 | | * |
8663 | | * This function is not BOM-aware. |
8664 | | * |
8665 | | * @param input the UTF-16BE string to convert |
8666 | | * @param length the length of the string in 2-byte code units (char16_t) |
8667 | | * @param utf8_buffer the pointer to a buffer that can hold the conversion |
8668 | | * result |
8669 | | * @return number of written code units; 0 if conversion is not possible |
8670 | | */ |
8671 | | simdutf_warn_unused size_t convert_valid_utf16be_to_utf8( |
8672 | | const char16_t *input, size_t length, char *utf8_buffer) noexcept; |
8673 | | #if SIMDUTF_SPAN |
8674 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t |
8675 | | convert_valid_utf16be_to_utf8( |
8676 | | std::span<const char16_t> valid_utf16_input, |
8677 | | detail::output_span_of_byte_like auto &&utf8_output) noexcept { |
8678 | | #if SIMDUTF_CPLUSPLUS23 |
8679 | | if consteval { |
8680 | | return scalar::utf16_to_utf8::convert_valid<endianness::BIG>( |
8681 | | valid_utf16_input.data(), valid_utf16_input.size(), utf8_output.data()); |
8682 | | } else |
8683 | | #endif |
8684 | | { |
8685 | | return convert_valid_utf16be_to_utf8( |
8686 | | valid_utf16_input.data(), valid_utf16_input.size(), |
8687 | | reinterpret_cast<char *>(utf8_output.data())); |
8688 | | } |
8689 | | } |
8690 | | #endif // SIMDUTF_SPAN |
8691 | | #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 |
8692 | | |
8693 | | #if SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_UTF32 |
8694 | | /** |
8695 | | * Using native endianness, convert possibly broken UTF-16 string into UTF-32 |
8696 | | * string. |
8697 | | * |
8698 | | * During the conversion also validation of the input string is done. |
8699 | | * This function is suitable to work with inputs from untrusted sources. |
8700 | | * |
8701 | | * This function is not BOM-aware. |
8702 | | * |
8703 | | * @param input the UTF-16 string to convert |
8704 | | * @param length the length of the string in 2-byte code units (char16_t) |
8705 | | * @param utf32_buffer the pointer to buffer that can hold conversion result |
8706 | | * @return number of written code units; 0 if input is not a valid UTF-16LE |
8707 | | * string |
8708 | | */ |
8709 | | simdutf_warn_unused size_t convert_utf16_to_utf32( |
8710 | | const char16_t *input, size_t length, char32_t *utf32_buffer) noexcept; |
8711 | | #if SIMDUTF_SPAN |
8712 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t |
8713 | | convert_utf16_to_utf32(std::span<const char16_t> utf16_input, |
8714 | | std::span<char32_t> utf32_output) noexcept { |
8715 | | |
8716 | | #if SIMDUTF_CPLUSPLUS23 |
8717 | | if consteval { |
8718 | | return scalar::utf16_to_utf32::convert<endianness::NATIVE>( |
8719 | | utf16_input.data(), utf16_input.size(), utf32_output.data()); |
8720 | | } else |
8721 | | #endif |
8722 | | { |
8723 | | return convert_utf16_to_utf32(utf16_input.data(), utf16_input.size(), |
8724 | | utf32_output.data()); |
8725 | | } |
8726 | | } |
8727 | | #endif // SIMDUTF_SPAN |
8728 | | |
8729 | | /** |
8730 | | * Convert possibly broken UTF-16LE string into UTF-32 string. |
8731 | | * |
8732 | | * During the conversion also validation of the input string is done. |
8733 | | * This function is suitable to work with inputs from untrusted sources. |
8734 | | * |
8735 | | * This function is not BOM-aware. |
8736 | | * |
8737 | | * @param input the UTF-16LE string to convert |
8738 | | * @param length the length of the string in 2-byte code units (char16_t) |
8739 | | * @param utf32_buffer the pointer to buffer that can hold conversion result |
8740 | | * @return number of written code units; 0 if input is not a valid UTF-16LE |
8741 | | * string |
8742 | | */ |
8743 | | simdutf_warn_unused size_t convert_utf16le_to_utf32( |
8744 | | const char16_t *input, size_t length, char32_t *utf32_buffer) noexcept; |
8745 | | #if SIMDUTF_SPAN |
8746 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t |
8747 | | convert_utf16le_to_utf32(std::span<const char16_t> utf16_input, |
8748 | | std::span<char32_t> utf32_output) noexcept { |
8749 | | #if SIMDUTF_CPLUSPLUS23 |
8750 | | if consteval { |
8751 | | return scalar::utf16_to_utf32::convert<endianness::LITTLE>( |
8752 | | utf16_input.data(), utf16_input.size(), utf32_output.data()); |
8753 | | } else |
8754 | | #endif |
8755 | | { |
8756 | | return convert_utf16le_to_utf32(utf16_input.data(), utf16_input.size(), |
8757 | | utf32_output.data()); |
8758 | | } |
8759 | | } |
8760 | | #endif // SIMDUTF_SPAN |
8761 | | |
8762 | | /** |
8763 | | * Convert possibly broken UTF-16BE string into UTF-32 string. |
8764 | | * |
8765 | | * During the conversion also validation of the input string is done. |
8766 | | * This function is suitable to work with inputs from untrusted sources. |
8767 | | * |
8768 | | * This function is not BOM-aware. |
8769 | | * |
8770 | | * @param input the UTF-16BE string to convert |
8771 | | * @param length the length of the string in 2-byte code units (char16_t) |
8772 | | * @param utf32_buffer the pointer to buffer that can hold conversion result |
8773 | | * @return number of written code units; 0 if input is not a valid UTF-16LE |
8774 | | * string |
8775 | | */ |
8776 | | simdutf_warn_unused size_t convert_utf16be_to_utf32( |
8777 | | const char16_t *input, size_t length, char32_t *utf32_buffer) noexcept; |
8778 | | #if SIMDUTF_SPAN |
8779 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t |
8780 | | convert_utf16be_to_utf32(std::span<const char16_t> utf16_input, |
8781 | | std::span<char32_t> utf32_output) noexcept { |
8782 | | #if SIMDUTF_CPLUSPLUS23 |
8783 | | if consteval { |
8784 | | return scalar::utf16_to_utf32::convert<endianness::BIG>( |
8785 | | utf16_input.data(), utf16_input.size(), utf32_output.data()); |
8786 | | } else |
8787 | | #endif |
8788 | | { |
8789 | | return convert_utf16be_to_utf32(utf16_input.data(), utf16_input.size(), |
8790 | | utf32_output.data()); |
8791 | | } |
8792 | | } |
8793 | | #endif // SIMDUTF_SPAN |
8794 | | |
8795 | | /** |
8796 | | * Using native endianness, convert possibly broken UTF-16 string into |
8797 | | * UTF-32 string and stop on error. |
8798 | | * |
8799 | | * During the conversion also validation of the input string is done. |
8800 | | * This function is suitable to work with inputs from untrusted sources. |
8801 | | * |
8802 | | * This function is not BOM-aware. |
8803 | | * |
8804 | | * @param input the UTF-16 string to convert |
8805 | | * @param length the length of the string in 2-byte code units (char16_t) |
8806 | | * @param utf32_buffer the pointer to buffer that can hold conversion result |
8807 | | * @return a result pair struct (of type simdutf::result containing the two |
8808 | | * fields error and count) with an error code and either position of the error |
8809 | | * (in the input in code units) if any, or the number of char32_t written if |
8810 | | * successful. |
8811 | | */ |
8812 | | simdutf_warn_unused result convert_utf16_to_utf32_with_errors( |
8813 | | const char16_t *input, size_t length, char32_t *utf32_buffer) noexcept; |
8814 | | #if SIMDUTF_SPAN |
8815 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result |
8816 | | convert_utf16_to_utf32_with_errors(std::span<const char16_t> utf16_input, |
8817 | | std::span<char32_t> utf32_output) noexcept { |
8818 | | #if SIMDUTF_CPLUSPLUS23 |
8819 | | if consteval { |
8820 | | return scalar::utf16_to_utf32::convert_with_errors<endianness::NATIVE>( |
8821 | | utf16_input.data(), utf16_input.size(), utf32_output.data()); |
8822 | | } else |
8823 | | #endif |
8824 | | { |
8825 | | return convert_utf16_to_utf32_with_errors( |
8826 | | utf16_input.data(), utf16_input.size(), utf32_output.data()); |
8827 | | } |
8828 | | } |
8829 | | #endif // SIMDUTF_SPAN |
8830 | | |
8831 | | /** |
8832 | | * Convert possibly broken UTF-16LE string into UTF-32 string and stop on error. |
8833 | | * |
8834 | | * During the conversion also validation of the input string is done. |
8835 | | * This function is suitable to work with inputs from untrusted sources. |
8836 | | * |
8837 | | * This function is not BOM-aware. |
8838 | | * |
8839 | | * @param input the UTF-16LE string to convert |
8840 | | * @param length the length of the string in 2-byte code units (char16_t) |
8841 | | * @param utf32_buffer the pointer to buffer that can hold conversion result |
8842 | | * @return a result pair struct (of type simdutf::result containing the two |
8843 | | * fields error and count) with an error code and either position of the error |
8844 | | * (in the input in code units) if any, or the number of char32_t written if |
8845 | | * successful. |
8846 | | */ |
8847 | | simdutf_warn_unused result convert_utf16le_to_utf32_with_errors( |
8848 | | const char16_t *input, size_t length, char32_t *utf32_buffer) noexcept; |
8849 | | #if SIMDUTF_SPAN |
8850 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result |
8851 | | convert_utf16le_to_utf32_with_errors( |
8852 | | std::span<const char16_t> utf16_input, |
8853 | | std::span<char32_t> utf32_output) noexcept { |
8854 | | #if SIMDUTF_CPLUSPLUS23 |
8855 | | if consteval { |
8856 | | return scalar::utf16_to_utf32::convert_with_errors<endianness::LITTLE>( |
8857 | | utf16_input.data(), utf16_input.size(), utf32_output.data()); |
8858 | | } else |
8859 | | #endif |
8860 | | { |
8861 | | return convert_utf16le_to_utf32_with_errors( |
8862 | | utf16_input.data(), utf16_input.size(), utf32_output.data()); |
8863 | | } |
8864 | | } |
8865 | | #endif // SIMDUTF_SPAN |
8866 | | |
8867 | | /** |
8868 | | * Convert possibly broken UTF-16BE string into UTF-32 string and stop on error. |
8869 | | * |
8870 | | * During the conversion also validation of the input string is done. |
8871 | | * This function is suitable to work with inputs from untrusted sources. |
8872 | | * |
8873 | | * This function is not BOM-aware. |
8874 | | * |
8875 | | * @param input the UTF-16BE string to convert |
8876 | | * @param length the length of the string in 2-byte code units (char16_t) |
8877 | | * @param utf32_buffer the pointer to buffer that can hold conversion result |
8878 | | * @return a result pair struct (of type simdutf::result containing the two |
8879 | | * fields error and count) with an error code and either position of the error |
8880 | | * (in the input in code units) if any, or the number of char32_t written if |
8881 | | * successful. |
8882 | | */ |
8883 | | simdutf_warn_unused result convert_utf16be_to_utf32_with_errors( |
8884 | | const char16_t *input, size_t length, char32_t *utf32_buffer) noexcept; |
8885 | | #if SIMDUTF_SPAN |
8886 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result |
8887 | | convert_utf16be_to_utf32_with_errors( |
8888 | | std::span<const char16_t> utf16_input, |
8889 | | std::span<char32_t> utf32_output) noexcept { |
8890 | | #if SIMDUTF_CPLUSPLUS23 |
8891 | | if consteval { |
8892 | | return scalar::utf16_to_utf32::convert_with_errors<endianness::BIG>( |
8893 | | utf16_input.data(), utf16_input.size(), utf32_output.data()); |
8894 | | } else |
8895 | | #endif |
8896 | | { |
8897 | | return convert_utf16be_to_utf32_with_errors( |
8898 | | utf16_input.data(), utf16_input.size(), utf32_output.data()); |
8899 | | } |
8900 | | } |
8901 | | #endif // SIMDUTF_SPAN |
8902 | | |
8903 | | /** |
8904 | | * Using native endianness, convert valid UTF-16 string into UTF-32 string. |
8905 | | * |
8906 | | * This function assumes that the input string is valid UTF-16 (native |
8907 | | * endianness). |
8908 | | * |
8909 | | * This function is not BOM-aware. |
8910 | | * |
8911 | | * @param input the UTF-16 string to convert |
8912 | | * @param length the length of the string in 2-byte code units (char16_t) |
8913 | | * @param utf32_buffer the pointer to a buffer that can hold the conversion |
8914 | | * result |
8915 | | * @return number of written code units; 0 if conversion is not possible |
8916 | | */ |
8917 | | simdutf_warn_unused size_t convert_valid_utf16_to_utf32( |
8918 | | const char16_t *input, size_t length, char32_t *utf32_buffer) noexcept; |
8919 | | #if SIMDUTF_SPAN |
8920 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t |
8921 | | convert_valid_utf16_to_utf32(std::span<const char16_t> valid_utf16_input, |
8922 | | std::span<char32_t> utf32_output) noexcept { |
8923 | | #if SIMDUTF_CPLUSPLUS23 |
8924 | | if consteval { |
8925 | | return scalar::utf16_to_utf32::convert_valid<endianness::NATIVE>( |
8926 | | valid_utf16_input.data(), valid_utf16_input.size(), |
8927 | | utf32_output.data()); |
8928 | | } else |
8929 | | #endif |
8930 | | { |
8931 | | return convert_valid_utf16_to_utf32(valid_utf16_input.data(), |
8932 | | valid_utf16_input.size(), |
8933 | | utf32_output.data()); |
8934 | | } |
8935 | | } |
8936 | | #endif // SIMDUTF_SPAN |
8937 | | |
8938 | | /** |
8939 | | * Convert valid UTF-16LE string into UTF-32 string. |
8940 | | * |
8941 | | * This function assumes that the input string is valid UTF-16LE. |
8942 | | * |
8943 | | * This function is not BOM-aware. |
8944 | | * |
8945 | | * @param input the UTF-16LE string to convert |
8946 | | * @param length the length of the string in 2-byte code units (char16_t) |
8947 | | * @param utf32_buffer the pointer to a buffer that can hold the conversion |
8948 | | * result |
8949 | | * @return number of written code units; 0 if conversion is not possible |
8950 | | */ |
8951 | | simdutf_warn_unused size_t convert_valid_utf16le_to_utf32( |
8952 | | const char16_t *input, size_t length, char32_t *utf32_buffer) noexcept; |
8953 | | #if SIMDUTF_SPAN |
8954 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t |
8955 | | convert_valid_utf16le_to_utf32(std::span<const char16_t> valid_utf16_input, |
8956 | | std::span<char32_t> utf32_output) noexcept { |
8957 | | #if SIMDUTF_CPLUSPLUS23 |
8958 | | if consteval { |
8959 | | return scalar::utf16_to_utf32::convert_valid<endianness::LITTLE>( |
8960 | | valid_utf16_input.data(), valid_utf16_input.size(), |
8961 | | utf32_output.data()); |
8962 | | } else |
8963 | | #endif |
8964 | | { |
8965 | | return convert_valid_utf16le_to_utf32(valid_utf16_input.data(), |
8966 | | valid_utf16_input.size(), |
8967 | | utf32_output.data()); |
8968 | | } |
8969 | | } |
8970 | | #endif // SIMDUTF_SPAN |
8971 | | |
8972 | | /** |
8973 | | * Convert valid UTF-16BE string into UTF-32 string. |
8974 | | * |
8975 | | * This function assumes that the input string is valid UTF-16LE. |
8976 | | * |
8977 | | * This function is not BOM-aware. |
8978 | | * |
8979 | | * @param input the UTF-16BE string to convert |
8980 | | * @param length the length of the string in 2-byte code units (char16_t) |
8981 | | * @param utf32_buffer the pointer to a buffer that can hold the conversion |
8982 | | * result |
8983 | | * @return number of written code units; 0 if conversion is not possible |
8984 | | */ |
8985 | | simdutf_warn_unused size_t convert_valid_utf16be_to_utf32( |
8986 | | const char16_t *input, size_t length, char32_t *utf32_buffer) noexcept; |
8987 | | #if SIMDUTF_SPAN |
8988 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t |
8989 | | convert_valid_utf16be_to_utf32(std::span<const char16_t> valid_utf16_input, |
8990 | | std::span<char32_t> utf32_output) noexcept { |
8991 | | #if SIMDUTF_CPLUSPLUS23 |
8992 | | if consteval { |
8993 | | return scalar::utf16_to_utf32::convert_valid<endianness::BIG>( |
8994 | | valid_utf16_input.data(), valid_utf16_input.size(), |
8995 | | utf32_output.data()); |
8996 | | } else |
8997 | | #endif |
8998 | | { |
8999 | | return convert_valid_utf16be_to_utf32(valid_utf16_input.data(), |
9000 | | valid_utf16_input.size(), |
9001 | | utf32_output.data()); |
9002 | | } |
9003 | | } |
9004 | | #endif // SIMDUTF_SPAN |
9005 | | #endif // SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_UTF32 |
9006 | | |
9007 | | #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 |
9008 | | /** |
9009 | | * Using native endianness; Compute the number of bytes that this UTF-16 |
9010 | | * string would require in UTF-8 format. |
9011 | | * |
9012 | | * This function does not validate the input. It is acceptable to pass invalid |
9013 | | * UTF-16 strings but in such cases the result is implementation defined. |
9014 | | * |
9015 | | * @param input the UTF-16 string to convert |
9016 | | * @param length the length of the string in 2-byte code units (char16_t) |
9017 | | * @return the number of bytes required to encode the UTF-16LE string as UTF-8 |
9018 | | */ |
9019 | | simdutf_warn_unused size_t utf8_length_from_utf16(const char16_t *input, |
9020 | | size_t length) noexcept; |
9021 | | #if SIMDUTF_SPAN |
9022 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t |
9023 | | utf8_length_from_utf16(std::span<const char16_t> valid_utf16_input) noexcept { |
9024 | | #if SIMDUTF_CPLUSPLUS23 |
9025 | | if consteval { |
9026 | | return scalar::utf16::utf8_length_from_utf16<endianness::NATIVE>( |
9027 | | valid_utf16_input.data(), valid_utf16_input.size()); |
9028 | | } else |
9029 | | #endif |
9030 | | { |
9031 | | return utf8_length_from_utf16(valid_utf16_input.data(), |
9032 | | valid_utf16_input.size()); |
9033 | | } |
9034 | | } |
9035 | | #endif // SIMDUTF_SPAN |
9036 | | |
9037 | | /** |
9038 | | * Using native endianness; compute the number of bytes that this UTF-16 |
9039 | | * string would require in UTF-8 format even when the UTF-16LE content contains |
9040 | | * mismatched surrogates that have to be replaced by the replacement character |
9041 | | * (0xFFFD). |
9042 | | * |
9043 | | * @param input the UTF-16 string to convert |
9044 | | * @param length the length of the string in 2-byte code units (char16_t) |
9045 | | * @return a result pair struct (of type simdutf::result containing the two |
9046 | | * fields error and count) where the count is the number of bytes required to |
9047 | | * encode the UTF-16 string as UTF-8, and the error code is either SUCCESS or |
9048 | | * SURROGATE. The count is correct regardless of the error field. |
9049 | | * When SURROGATE is returned, it does not indicate an error in the case of this |
9050 | | * function: it indicates that at least one surrogate has been encountered: the |
9051 | | * surrogates may be matched or not (thus this function does not validate). If |
9052 | | * the returned error code is SUCCESS, then the input contains no surrogate, is |
9053 | | * in the Basic Multilingual Plane, and is necessarily valid. |
9054 | | */ |
9055 | | simdutf_warn_unused result utf8_length_from_utf16_with_replacement( |
9056 | | const char16_t *input, size_t length) noexcept; |
9057 | | #if SIMDUTF_SPAN |
9058 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result |
9059 | | utf8_length_from_utf16_with_replacement( |
9060 | | std::span<const char16_t> valid_utf16_input) noexcept { |
9061 | | #if SIMDUTF_CPLUSPLUS23 |
9062 | | if consteval { |
9063 | | return scalar::utf16::utf8_length_from_utf16_with_replacement< |
9064 | | endianness::NATIVE>(valid_utf16_input.data(), valid_utf16_input.size()); |
9065 | | } else |
9066 | | #endif |
9067 | | { |
9068 | | return utf8_length_from_utf16_with_replacement(valid_utf16_input.data(), |
9069 | | valid_utf16_input.size()); |
9070 | | } |
9071 | | } |
9072 | | #endif // SIMDUTF_SPAN |
9073 | | |
9074 | | /** |
9075 | | * Compute the number of bytes that this UTF-16LE string would require in UTF-8 |
9076 | | * format. |
9077 | | * |
9078 | | * This function does not validate the input. It is acceptable to pass invalid |
9079 | | * UTF-16 strings but in such cases the result is implementation defined. |
9080 | | * |
9081 | | * @param input the UTF-16LE string to convert |
9082 | | * @param length the length of the string in 2-byte code units (char16_t) |
9083 | | * @return the number of bytes required to encode the UTF-16LE string as UTF-8 |
9084 | | */ |
9085 | | simdutf_warn_unused size_t utf8_length_from_utf16le(const char16_t *input, |
9086 | | size_t length) noexcept; |
9087 | | #if SIMDUTF_SPAN |
9088 | | simdutf_really_inline simdutf_constexpr23 simdutf_warn_unused size_t |
9089 | | utf8_length_from_utf16le(std::span<const char16_t> valid_utf16_input) noexcept { |
9090 | | #if SIMDUTF_CPLUSPLUS23 |
9091 | | if consteval { |
9092 | | return scalar::utf16::utf8_length_from_utf16<endianness::LITTLE>( |
9093 | | valid_utf16_input.data(), valid_utf16_input.size()); |
9094 | | } else |
9095 | | #endif |
9096 | | { |
9097 | | return utf8_length_from_utf16le(valid_utf16_input.data(), |
9098 | | valid_utf16_input.size()); |
9099 | | } |
9100 | | } |
9101 | | #endif // SIMDUTF_SPAN |
9102 | | |
9103 | | /** |
9104 | | * Compute the number of bytes that this UTF-16BE string would require in UTF-8 |
9105 | | * format. |
9106 | | * |
9107 | | * This function does not validate the input. It is acceptable to pass invalid |
9108 | | * UTF-16 strings but in such cases the result is implementation defined. |
9109 | | * |
9110 | | * @param input the UTF-16BE string to convert |
9111 | | * @param length the length of the string in 2-byte code units (char16_t) |
9112 | | * @return the number of bytes required to encode the UTF-16BE string as UTF-8 |
9113 | | */ |
9114 | | simdutf_warn_unused size_t utf8_length_from_utf16be(const char16_t *input, |
9115 | | size_t length) noexcept; |
9116 | | #if SIMDUTF_SPAN |
9117 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t |
9118 | | utf8_length_from_utf16be(std::span<const char16_t> valid_utf16_input) noexcept { |
9119 | | #if SIMDUTF_CPLUSPLUS23 |
9120 | | if consteval { |
9121 | | return scalar::utf16::utf8_length_from_utf16<endianness::BIG>( |
9122 | | valid_utf16_input.data(), valid_utf16_input.size()); |
9123 | | } else |
9124 | | #endif |
9125 | | { |
9126 | | return utf8_length_from_utf16be(valid_utf16_input.data(), |
9127 | | valid_utf16_input.size()); |
9128 | | } |
9129 | | } |
9130 | | #endif // SIMDUTF_SPAN |
9131 | | #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 |
9132 | | |
9133 | | #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32 |
9134 | | /** |
9135 | | * Convert possibly broken UTF-32 string into UTF-8 string. |
9136 | | * |
9137 | | * During the conversion also validation of the input string is done. |
9138 | | * This function is suitable to work with inputs from untrusted sources. |
9139 | | * |
9140 | | * This function is not BOM-aware. |
9141 | | * |
9142 | | * @param input the UTF-32 string to convert |
9143 | | * @param length the length of the string in 4-byte code units (char32_t) |
9144 | | * @param utf8_buffer the pointer to buffer that can hold conversion result |
9145 | | * @return number of written code units; 0 if input is not a valid UTF-32 string |
9146 | | */ |
9147 | | simdutf_warn_unused size_t convert_utf32_to_utf8(const char32_t *input, |
9148 | | size_t length, |
9149 | | char *utf8_buffer) noexcept; |
9150 | | #if SIMDUTF_SPAN |
9151 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t |
9152 | | convert_utf32_to_utf8( |
9153 | | std::span<const char32_t> utf32_input, |
9154 | | detail::output_span_of_byte_like auto &&utf8_output) noexcept { |
9155 | | #if SIMDUTF_CPLUSPLUS23 |
9156 | | if consteval { |
9157 | | return scalar::utf32_to_utf8::convert( |
9158 | | utf32_input.data(), utf32_input.size(), utf8_output.data()); |
9159 | | } else |
9160 | | #endif |
9161 | | { |
9162 | | return convert_utf32_to_utf8(utf32_input.data(), utf32_input.size(), |
9163 | | reinterpret_cast<char *>(utf8_output.data())); |
9164 | | } |
9165 | | } |
9166 | | #endif // SIMDUTF_SPAN |
9167 | | |
9168 | | /** |
9169 | | * Convert possibly broken UTF-32 string into UTF-8 string and stop on error. |
9170 | | * |
9171 | | * During the conversion also validation of the input string is done. |
9172 | | * This function is suitable to work with inputs from untrusted sources. |
9173 | | * |
9174 | | * This function is not BOM-aware. |
9175 | | * |
9176 | | * @param input the UTF-32 string to convert |
9177 | | * @param length the length of the string in 4-byte code units (char32_t) |
9178 | | * @param utf8_buffer the pointer to buffer that can hold conversion result |
9179 | | * @return a result pair struct (of type simdutf::result containing the two |
9180 | | * fields error and count) with an error code and either position of the error |
9181 | | * (in the input in code units) if any, or the number of char written if |
9182 | | * successful. |
9183 | | */ |
9184 | | simdutf_warn_unused result convert_utf32_to_utf8_with_errors( |
9185 | | const char32_t *input, size_t length, char *utf8_buffer) noexcept; |
9186 | | #if SIMDUTF_SPAN |
9187 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result |
9188 | | convert_utf32_to_utf8_with_errors( |
9189 | | std::span<const char32_t> utf32_input, |
9190 | | detail::output_span_of_byte_like auto &&utf8_output) noexcept { |
9191 | | #if SIMDUTF_CPLUSPLUS23 |
9192 | | if consteval { |
9193 | | return scalar::utf32_to_utf8::convert_with_errors( |
9194 | | utf32_input.data(), utf32_input.size(), utf8_output.data()); |
9195 | | } else |
9196 | | #endif |
9197 | | { |
9198 | | return convert_utf32_to_utf8_with_errors( |
9199 | | utf32_input.data(), utf32_input.size(), |
9200 | | reinterpret_cast<char *>(utf8_output.data())); |
9201 | | } |
9202 | | } |
9203 | | #endif // SIMDUTF_SPAN |
9204 | | |
9205 | | /** |
9206 | | * Convert valid UTF-32 string into UTF-8 string. |
9207 | | * |
9208 | | * This function assumes that the input string is valid UTF-32. |
9209 | | * |
9210 | | * This function is not BOM-aware. |
9211 | | * |
9212 | | * @param input the UTF-32 string to convert |
9213 | | * @param length the length of the string in 4-byte code units (char32_t) |
9214 | | * @param utf8_buffer the pointer to a buffer that can hold the conversion |
9215 | | * result |
9216 | | * @return number of written code units; 0 if conversion is not possible |
9217 | | */ |
9218 | | simdutf_warn_unused size_t convert_valid_utf32_to_utf8( |
9219 | | const char32_t *input, size_t length, char *utf8_buffer) noexcept; |
9220 | | #if SIMDUTF_SPAN |
9221 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t |
9222 | | convert_valid_utf32_to_utf8( |
9223 | | std::span<const char32_t> valid_utf32_input, |
9224 | | detail::output_span_of_byte_like auto &&utf8_output) noexcept { |
9225 | | #if SIMDUTF_CPLUSPLUS23 |
9226 | | if consteval { |
9227 | | return scalar::utf32_to_utf8::convert_valid( |
9228 | | valid_utf32_input.data(), valid_utf32_input.size(), utf8_output.data()); |
9229 | | } else |
9230 | | #endif |
9231 | | { |
9232 | | return convert_valid_utf32_to_utf8( |
9233 | | valid_utf32_input.data(), valid_utf32_input.size(), |
9234 | | reinterpret_cast<char *>(utf8_output.data())); |
9235 | | } |
9236 | | } |
9237 | | #endif // SIMDUTF_SPAN |
9238 | | #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32 |
9239 | | |
9240 | | #if SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_UTF32 |
9241 | | /** |
9242 | | * Using native endianness, convert possibly broken UTF-32 string into a UTF-16 |
9243 | | * string. |
9244 | | * |
9245 | | * During the conversion also validation of the input string is done. |
9246 | | * This function is suitable to work with inputs from untrusted sources. |
9247 | | * |
9248 | | * This function is not BOM-aware. |
9249 | | * |
9250 | | * @param input the UTF-32 string to convert |
9251 | | * @param length the length of the string in 4-byte code units (char32_t) |
9252 | | * @param utf16_buffer the pointer to buffer that can hold conversion result |
9253 | | * @return number of written code units; 0 if input is not a valid UTF-32 string |
9254 | | */ |
9255 | | simdutf_warn_unused size_t convert_utf32_to_utf16( |
9256 | | const char32_t *input, size_t length, char16_t *utf16_buffer) noexcept; |
9257 | | #if SIMDUTF_SPAN |
9258 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t |
9259 | | convert_utf32_to_utf16(std::span<const char32_t> utf32_input, |
9260 | | std::span<char16_t> utf16_output) noexcept { |
9261 | | #if SIMDUTF_CPLUSPLUS23 |
9262 | | if consteval { |
9263 | | return scalar::utf32_to_utf16::convert<endianness::NATIVE>( |
9264 | | utf32_input.data(), utf32_input.size(), utf16_output.data()); |
9265 | | } else |
9266 | | #endif |
9267 | | { |
9268 | | return convert_utf32_to_utf16(utf32_input.data(), utf32_input.size(), |
9269 | | utf16_output.data()); |
9270 | | } |
9271 | | } |
9272 | | #endif // SIMDUTF_SPAN |
9273 | | |
9274 | | /** |
9275 | | * Convert possibly broken UTF-32 string into UTF-16LE string. |
9276 | | * |
9277 | | * During the conversion also validation of the input string is done. |
9278 | | * This function is suitable to work with inputs from untrusted sources. |
9279 | | * |
9280 | | * This function is not BOM-aware. |
9281 | | * |
9282 | | * @param input the UTF-32 string to convert |
9283 | | * @param length the length of the string in 4-byte code units (char32_t) |
9284 | | * @param utf16_buffer the pointer to buffer that can hold conversion result |
9285 | | * @return number of written code units; 0 if input is not a valid UTF-32 string |
9286 | | */ |
9287 | | simdutf_warn_unused size_t convert_utf32_to_utf16le( |
9288 | | const char32_t *input, size_t length, char16_t *utf16_buffer) noexcept; |
9289 | | #if SIMDUTF_SPAN |
9290 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t |
9291 | | convert_utf32_to_utf16le(std::span<const char32_t> utf32_input, |
9292 | | std::span<char16_t> utf16_output) noexcept { |
9293 | | #if SIMDUTF_CPLUSPLUS23 |
9294 | | if consteval { |
9295 | | return scalar::utf32_to_utf16::convert<endianness::LITTLE>( |
9296 | | utf32_input.data(), utf32_input.size(), utf16_output.data()); |
9297 | | } else |
9298 | | #endif |
9299 | | { |
9300 | | return convert_utf32_to_utf16le(utf32_input.data(), utf32_input.size(), |
9301 | | utf16_output.data()); |
9302 | | } |
9303 | | } |
9304 | | #endif // SIMDUTF_SPAN |
9305 | | #endif // SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_UTF32 |
9306 | | |
9307 | | #if SIMDUTF_FEATURE_UTF32 && SIMDUTF_FEATURE_LATIN1 |
9308 | | /** |
9309 | | * Convert possibly broken UTF-32 string into Latin1 string. |
9310 | | * |
9311 | | * During the conversion also validation of the input string is done. |
9312 | | * This function is suitable to work with inputs from untrusted sources. |
9313 | | * |
9314 | | * This function is not BOM-aware. |
9315 | | * |
9316 | | * @param input the UTF-32 string to convert |
9317 | | * @param length the length of the string in 4-byte code units (char32_t) |
9318 | | * @param latin1_buffer the pointer to buffer that can hold conversion result |
9319 | | * @return number of written code units; 0 if input is not a valid UTF-32 string |
9320 | | * or if it cannot be represented as Latin1 |
9321 | | */ |
9322 | | simdutf_warn_unused size_t convert_utf32_to_latin1( |
9323 | | const char32_t *input, size_t length, char *latin1_buffer) noexcept; |
9324 | | #if SIMDUTF_SPAN |
9325 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t |
9326 | | convert_utf32_to_latin1( |
9327 | | std::span<const char32_t> utf32_input, |
9328 | | detail::output_span_of_byte_like auto &&latin1_output) noexcept { |
9329 | | #if SIMDUTF_CPLUSPLUS23 |
9330 | | if consteval { |
9331 | | return scalar::utf32_to_latin1::convert( |
9332 | | utf32_input.data(), utf32_input.size(), latin1_output.data()); |
9333 | | } else |
9334 | | #endif |
9335 | | { |
9336 | | return convert_utf32_to_latin1( |
9337 | | utf32_input.data(), utf32_input.size(), |
9338 | | reinterpret_cast<char *>(latin1_output.data())); |
9339 | | } |
9340 | | } |
9341 | | #endif // SIMDUTF_SPAN |
9342 | | |
9343 | | /** |
9344 | | * Convert possibly broken UTF-32 string into Latin1 string and stop on error. |
9345 | | * If the string cannot be represented as Latin1, an error is returned. |
9346 | | * |
9347 | | * During the conversion also validation of the input string is done. |
9348 | | * This function is suitable to work with inputs from untrusted sources. |
9349 | | * |
9350 | | * This function is not BOM-aware. |
9351 | | * |
9352 | | * @param input the UTF-32 string to convert |
9353 | | * @param length the length of the string in 4-byte code units (char32_t) |
9354 | | * @param latin1_buffer the pointer to buffer that can hold conversion result |
9355 | | * @return a result pair struct (of type simdutf::result containing the two |
9356 | | * fields error and count) with an error code and either position of the error |
9357 | | * (in the input in code units) if any, or the number of char written if |
9358 | | * successful. |
9359 | | */ |
9360 | | simdutf_warn_unused result convert_utf32_to_latin1_with_errors( |
9361 | | const char32_t *input, size_t length, char *latin1_buffer) noexcept; |
9362 | | #if SIMDUTF_SPAN |
9363 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result |
9364 | | convert_utf32_to_latin1_with_errors( |
9365 | | std::span<const char32_t> utf32_input, |
9366 | | detail::output_span_of_byte_like auto &&latin1_output) noexcept { |
9367 | | #if SIMDUTF_CPLUSPLUS23 |
9368 | | if consteval { |
9369 | | return scalar::utf32_to_latin1::convert_with_errors( |
9370 | | utf32_input.data(), utf32_input.size(), latin1_output.data()); |
9371 | | } else |
9372 | | #endif |
9373 | | { |
9374 | | return convert_utf32_to_latin1_with_errors( |
9375 | | utf32_input.data(), utf32_input.size(), |
9376 | | reinterpret_cast<char *>(latin1_output.data())); |
9377 | | } |
9378 | | } |
9379 | | #endif // SIMDUTF_SPAN |
9380 | | |
9381 | | /** |
9382 | | * Convert valid UTF-32 string into Latin1 string. |
9383 | | * |
9384 | | * This function assumes that the input string is valid UTF-32 and that it can |
9385 | | * be represented as Latin1. If you violate this assumption, the result is |
9386 | | * implementation defined and may include system-dependent behavior such as |
9387 | | * crashes. |
9388 | | * |
9389 | | * This function is for expert users only and not part of our public API. Use |
9390 | | * convert_utf32_to_latin1 instead. The function may be removed from the library |
9391 | | * in the future. |
9392 | | * |
9393 | | * This function is not BOM-aware. |
9394 | | * |
9395 | | * @param input the UTF-32 string to convert |
9396 | | * @param length the length of the string in 4-byte code units (char32_t) |
9397 | | * @param latin1_buffer the pointer to a buffer that can hold the conversion |
9398 | | * result |
9399 | | * @return number of written code units; 0 if conversion is not possible |
9400 | | */ |
9401 | | simdutf_warn_unused size_t convert_valid_utf32_to_latin1( |
9402 | | const char32_t *input, size_t length, char *latin1_buffer) noexcept; |
9403 | | #if SIMDUTF_SPAN |
9404 | | simdutf_really_inline simdutf_constexpr23 simdutf_warn_unused size_t |
9405 | | convert_valid_utf32_to_latin1( |
9406 | | std::span<const char32_t> valid_utf32_input, |
9407 | | detail::output_span_of_byte_like auto &&latin1_output) noexcept { |
9408 | | #if SIMDUTF_CPLUSPLUS23 |
9409 | | if consteval { |
9410 | | return scalar::utf32_to_latin1::convert_valid( |
9411 | | detail::constexpr_cast_ptr<uint32_t>(valid_utf32_input.data()), |
9412 | | valid_utf32_input.size(), |
9413 | | detail::constexpr_cast_writeptr<char>(latin1_output.data())); |
9414 | | } |
9415 | | #endif |
9416 | | { |
9417 | | return convert_valid_utf32_to_latin1( |
9418 | | valid_utf32_input.data(), valid_utf32_input.size(), |
9419 | | reinterpret_cast<char *>(latin1_output.data())); |
9420 | | } |
9421 | | } |
9422 | | #endif // SIMDUTF_SPAN |
9423 | | |
9424 | | /** |
9425 | | * Compute the number of bytes that this UTF-32 string would require in Latin1 |
9426 | | * format. |
9427 | | * |
9428 | | * This function does not validate the input. It is acceptable to pass invalid |
9429 | | * UTF-32 strings but in such cases the result is implementation defined. |
9430 | | * |
9431 | | * This function is not BOM-aware. |
9432 | | * |
9433 | | * @param length the length of the string in 4-byte code units (char32_t) |
9434 | | * @return the number of bytes required to encode the UTF-32 string as Latin1 |
9435 | | */ |
9436 | | simdutf_warn_unused simdutf_really_inline simdutf_constexpr23 size_t |
9437 | | latin1_length_from_utf32(size_t length) noexcept { |
9438 | | return length; |
9439 | | } |
9440 | | |
9441 | | /** |
9442 | | * Compute the number of bytes that this Latin1 string would require in UTF-32 |
9443 | | * format. |
9444 | | * |
9445 | | * @param length the length of the string in Latin1 code units (char) |
9446 | | * @return the length of the string in 4-byte code units (char32_t) required to |
9447 | | * encode the Latin1 string as UTF-32 |
9448 | | */ |
9449 | | simdutf_warn_unused simdutf_really_inline simdutf_constexpr23 size_t |
9450 | | utf32_length_from_latin1(size_t length) noexcept { |
9451 | | return length; |
9452 | | } |
9453 | | #endif // SIMDUTF_FEATURE_UTF32 && SIMDUTF_FEATURE_LATIN1 |
9454 | | |
9455 | | #if SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_UTF32 |
9456 | | /** |
9457 | | * Convert possibly broken UTF-32 string into UTF-16BE string. |
9458 | | * |
9459 | | * During the conversion also validation of the input string is done. |
9460 | | * This function is suitable to work with inputs from untrusted sources. |
9461 | | * |
9462 | | * This function is not BOM-aware. |
9463 | | * |
9464 | | * @param input the UTF-32 string to convert |
9465 | | * @param length the length of the string in 4-byte code units (char32_t) |
9466 | | * @param utf16_buffer the pointer to buffer that can hold conversion result |
9467 | | * @return number of written code units; 0 if input is not a valid UTF-32 string |
9468 | | */ |
9469 | | simdutf_warn_unused size_t convert_utf32_to_utf16be( |
9470 | | const char32_t *input, size_t length, char16_t *utf16_buffer) noexcept; |
9471 | | #if SIMDUTF_SPAN |
9472 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t |
9473 | | convert_utf32_to_utf16be(std::span<const char32_t> utf32_input, |
9474 | | std::span<char16_t> utf16_output) noexcept { |
9475 | | #if SIMDUTF_CPLUSPLUS23 |
9476 | | if consteval { |
9477 | | return scalar::utf32_to_utf16::convert<endianness::BIG>( |
9478 | | utf32_input.data(), utf32_input.size(), utf16_output.data()); |
9479 | | } else |
9480 | | #endif |
9481 | | { |
9482 | | return convert_utf32_to_utf16be(utf32_input.data(), utf32_input.size(), |
9483 | | utf16_output.data()); |
9484 | | } |
9485 | | } |
9486 | | #endif // SIMDUTF_SPAN |
9487 | | |
9488 | | /** |
9489 | | * Using native endianness, convert possibly broken UTF-32 string into UTF-16 |
9490 | | * string and stop on error. |
9491 | | * |
9492 | | * During the conversion also validation of the input string is done. |
9493 | | * This function is suitable to work with inputs from untrusted sources. |
9494 | | * |
9495 | | * This function is not BOM-aware. |
9496 | | * |
9497 | | * @param input the UTF-32 string to convert |
9498 | | * @param length the length of the string in 4-byte code units (char32_t) |
9499 | | * @param utf16_buffer the pointer to buffer that can hold conversion result |
9500 | | * @return a result pair struct (of type simdutf::result containing the two |
9501 | | * fields error and count) with an error code and either position of the error |
9502 | | * (in the input in code units) if any, or the number of char16_t written if |
9503 | | * successful. |
9504 | | */ |
9505 | | simdutf_warn_unused result convert_utf32_to_utf16_with_errors( |
9506 | | const char32_t *input, size_t length, char16_t *utf16_buffer) noexcept; |
9507 | | #if SIMDUTF_SPAN |
9508 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result |
9509 | | convert_utf32_to_utf16_with_errors(std::span<const char32_t> utf32_input, |
9510 | | std::span<char16_t> utf16_output) noexcept { |
9511 | | #if SIMDUTF_CPLUSPLUS23 |
9512 | | if consteval { |
9513 | | return scalar::utf32_to_utf16::convert_with_errors<endianness::NATIVE>( |
9514 | | utf32_input.data(), utf32_input.size(), utf16_output.data()); |
9515 | | } else |
9516 | | #endif |
9517 | | { |
9518 | | return convert_utf32_to_utf16_with_errors( |
9519 | | utf32_input.data(), utf32_input.size(), utf16_output.data()); |
9520 | | } |
9521 | | } |
9522 | | #endif // SIMDUTF_SPAN |
9523 | | |
9524 | | /** |
9525 | | * Convert possibly broken UTF-32 string into UTF-16LE string and stop on error. |
9526 | | * |
9527 | | * During the conversion also validation of the input string is done. |
9528 | | * This function is suitable to work with inputs from untrusted sources. |
9529 | | * |
9530 | | * This function is not BOM-aware. |
9531 | | * |
9532 | | * @param input the UTF-32 string to convert |
9533 | | * @param length the length of the string in 4-byte code units (char32_t) |
9534 | | * @param utf16_buffer the pointer to buffer that can hold conversion result |
9535 | | * @return a result pair struct (of type simdutf::result containing the two |
9536 | | * fields error and count) with an error code and either position of the error |
9537 | | * (in the input in code units) if any, or the number of char16_t written if |
9538 | | * successful. |
9539 | | */ |
9540 | | simdutf_warn_unused result convert_utf32_to_utf16le_with_errors( |
9541 | | const char32_t *input, size_t length, char16_t *utf16_buffer) noexcept; |
9542 | | #if SIMDUTF_SPAN |
9543 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result |
9544 | | convert_utf32_to_utf16le_with_errors( |
9545 | | std::span<const char32_t> utf32_input, |
9546 | | std::span<char16_t> utf16_output) noexcept { |
9547 | | #if SIMDUTF_CPLUSPLUS23 |
9548 | | if consteval { |
9549 | | return scalar::utf32_to_utf16::convert_with_errors<endianness::LITTLE>( |
9550 | | utf32_input.data(), utf32_input.size(), utf16_output.data()); |
9551 | | } else |
9552 | | #endif |
9553 | | { |
9554 | | return convert_utf32_to_utf16le_with_errors( |
9555 | | utf32_input.data(), utf32_input.size(), utf16_output.data()); |
9556 | | } |
9557 | | } |
9558 | | #endif // SIMDUTF_SPAN |
9559 | | |
9560 | | /** |
9561 | | * Convert possibly broken UTF-32 string into UTF-16BE string and stop on error. |
9562 | | * |
9563 | | * During the conversion also validation of the input string is done. |
9564 | | * This function is suitable to work with inputs from untrusted sources. |
9565 | | * |
9566 | | * This function is not BOM-aware. |
9567 | | * |
9568 | | * @param input the UTF-32 string to convert |
9569 | | * @param length the length of the string in 4-byte code units (char32_t) |
9570 | | * @param utf16_buffer the pointer to buffer that can hold conversion result |
9571 | | * @return a result pair struct (of type simdutf::result containing the two |
9572 | | * fields error and count) with an error code and either position of the error |
9573 | | * (in the input in code units) if any, or the number of char16_t written if |
9574 | | * successful. |
9575 | | */ |
9576 | | simdutf_warn_unused result convert_utf32_to_utf16be_with_errors( |
9577 | | const char32_t *input, size_t length, char16_t *utf16_buffer) noexcept; |
9578 | | #if SIMDUTF_SPAN |
9579 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result |
9580 | | convert_utf32_to_utf16be_with_errors( |
9581 | | std::span<const char32_t> utf32_input, |
9582 | | std::span<char16_t> utf16_output) noexcept { |
9583 | | #if SIMDUTF_CPLUSPLUS23 |
9584 | | if consteval { |
9585 | | return scalar::utf32_to_utf16::convert_with_errors<endianness::BIG>( |
9586 | | utf32_input.data(), utf32_input.size(), utf16_output.data()); |
9587 | | } else |
9588 | | #endif |
9589 | | { |
9590 | | return convert_utf32_to_utf16be_with_errors( |
9591 | | utf32_input.data(), utf32_input.size(), utf16_output.data()); |
9592 | | } |
9593 | | } |
9594 | | #endif // SIMDUTF_SPAN |
9595 | | |
9596 | | /** |
9597 | | * Using native endianness, convert valid UTF-32 string into a UTF-16 string. |
9598 | | * |
9599 | | * This function assumes that the input string is valid UTF-32. |
9600 | | * |
9601 | | * This function is not BOM-aware. |
9602 | | * |
9603 | | * @param input the UTF-32 string to convert |
9604 | | * @param length the length of the string in 4-byte code units (char32_t) |
9605 | | * @param utf16_buffer the pointer to a buffer that can hold the conversion |
9606 | | * result |
9607 | | * @return number of written code units; 0 if conversion is not possible |
9608 | | */ |
9609 | | simdutf_warn_unused size_t convert_valid_utf32_to_utf16( |
9610 | | const char32_t *input, size_t length, char16_t *utf16_buffer) noexcept; |
9611 | | #if SIMDUTF_SPAN |
9612 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t |
9613 | | convert_valid_utf32_to_utf16(std::span<const char32_t> valid_utf32_input, |
9614 | | std::span<char16_t> utf16_output) noexcept { |
9615 | | |
9616 | | #if SIMDUTF_CPLUSPLUS23 |
9617 | | if consteval { |
9618 | | return scalar::utf32_to_utf16::convert_valid<endianness::NATIVE>( |
9619 | | valid_utf32_input.data(), valid_utf32_input.size(), |
9620 | | utf16_output.data()); |
9621 | | } else |
9622 | | #endif |
9623 | | { |
9624 | | return convert_valid_utf32_to_utf16(valid_utf32_input.data(), |
9625 | | valid_utf32_input.size(), |
9626 | | utf16_output.data()); |
9627 | | } |
9628 | | } |
9629 | | #endif // SIMDUTF_SPAN |
9630 | | |
9631 | | /** |
9632 | | * Convert valid UTF-32 string into UTF-16LE string. |
9633 | | * |
9634 | | * This function assumes that the input string is valid UTF-32. |
9635 | | * |
9636 | | * This function is not BOM-aware. |
9637 | | * |
9638 | | * @param input the UTF-32 string to convert |
9639 | | * @param length the length of the string in 4-byte code units (char32_t) |
9640 | | * @param utf16_buffer the pointer to a buffer that can hold the conversion |
9641 | | * result |
9642 | | * @return number of written code units; 0 if conversion is not possible |
9643 | | */ |
9644 | | simdutf_warn_unused size_t convert_valid_utf32_to_utf16le( |
9645 | | const char32_t *input, size_t length, char16_t *utf16_buffer) noexcept; |
9646 | | #if SIMDUTF_SPAN |
9647 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t |
9648 | | convert_valid_utf32_to_utf16le(std::span<const char32_t> valid_utf32_input, |
9649 | | std::span<char16_t> utf16_output) noexcept { |
9650 | | #if SIMDUTF_CPLUSPLUS23 |
9651 | | if consteval { |
9652 | | return scalar::utf32_to_utf16::convert_valid<endianness::LITTLE>( |
9653 | | valid_utf32_input.data(), valid_utf32_input.size(), |
9654 | | utf16_output.data()); |
9655 | | } else |
9656 | | #endif |
9657 | | { |
9658 | | return convert_valid_utf32_to_utf16le(valid_utf32_input.data(), |
9659 | | valid_utf32_input.size(), |
9660 | | utf16_output.data()); |
9661 | | } |
9662 | | } |
9663 | | #endif // SIMDUTF_SPAN |
9664 | | |
9665 | | /** |
9666 | | * Convert valid UTF-32 string into UTF-16BE string. |
9667 | | * |
9668 | | * This function assumes that the input string is valid UTF-32. |
9669 | | * |
9670 | | * This function is not BOM-aware. |
9671 | | * |
9672 | | * @param input the UTF-32 string to convert |
9673 | | * @param length the length of the string in 4-byte code units (char32_t) |
9674 | | * @param utf16_buffer the pointer to a buffer that can hold the conversion |
9675 | | * result |
9676 | | * @return number of written code units; 0 if conversion is not possible |
9677 | | */ |
9678 | | simdutf_warn_unused size_t convert_valid_utf32_to_utf16be( |
9679 | | const char32_t *input, size_t length, char16_t *utf16_buffer) noexcept; |
9680 | | #if SIMDUTF_SPAN |
9681 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t |
9682 | | convert_valid_utf32_to_utf16be(std::span<const char32_t> valid_utf32_input, |
9683 | | std::span<char16_t> utf16_output) noexcept { |
9684 | | #if SIMDUTF_CPLUSPLUS23 |
9685 | | if consteval { |
9686 | | return scalar::utf32_to_utf16::convert_valid<endianness::BIG>( |
9687 | | valid_utf32_input.data(), valid_utf32_input.size(), |
9688 | | utf16_output.data()); |
9689 | | } else |
9690 | | #endif |
9691 | | { |
9692 | | return convert_valid_utf32_to_utf16be(valid_utf32_input.data(), |
9693 | | valid_utf32_input.size(), |
9694 | | utf16_output.data()); |
9695 | | } |
9696 | | } |
9697 | | #endif // SIMDUTF_SPAN |
9698 | | #endif // SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_UTF32 |
9699 | | |
9700 | | #if SIMDUTF_FEATURE_UTF16 |
9701 | | /** |
9702 | | * Change the endianness of the input. Can be used to go from UTF-16LE to |
9703 | | * UTF-16BE or from UTF-16BE to UTF-16LE. |
9704 | | * |
9705 | | * This function does not validate the input. |
9706 | | * |
9707 | | * This function is not BOM-aware. |
9708 | | * |
9709 | | * @param input the UTF-16 string to process |
9710 | | * @param length the length of the string in 2-byte code units (char16_t) |
9711 | | * @param output the pointer to a buffer that can hold the conversion |
9712 | | * result |
9713 | | */ |
9714 | | void change_endianness_utf16(const char16_t *input, size_t length, |
9715 | | char16_t *output) noexcept; |
9716 | | #if SIMDUTF_SPAN |
9717 | | simdutf_really_inline simdutf_constexpr23 void |
9718 | | change_endianness_utf16(std::span<const char16_t> utf16_input, |
9719 | | std::span<char16_t> utf16_output) noexcept { |
9720 | | #if SIMDUTF_CPLUSPLUS23 |
9721 | | if consteval { |
9722 | | return scalar::utf16::change_endianness_utf16( |
9723 | | utf16_input.data(), utf16_input.size(), utf16_output.data()); |
9724 | | } else |
9725 | | #endif |
9726 | | { |
9727 | | return change_endianness_utf16(utf16_input.data(), utf16_input.size(), |
9728 | | utf16_output.data()); |
9729 | | } |
9730 | | } |
9731 | | #endif // SIMDUTF_SPAN |
9732 | | #endif // SIMDUTF_FEATURE_UTF16 |
9733 | | |
9734 | | #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32 |
9735 | | /** |
9736 | | * Compute the number of bytes that this UTF-32 string would require in UTF-8 |
9737 | | * format. |
9738 | | * |
9739 | | * This function does not validate the input. It is acceptable to pass invalid |
9740 | | * UTF-32 strings but in such cases the result is implementation defined. |
9741 | | * |
9742 | | * @param input the UTF-32 string to convert |
9743 | | * @param length the length of the string in 4-byte code units (char32_t) |
9744 | | * @return the number of bytes required to encode the UTF-32 string as UTF-8 |
9745 | | */ |
9746 | | simdutf_warn_unused size_t utf8_length_from_utf32(const char32_t *input, |
9747 | | size_t length) noexcept; |
9748 | | #if SIMDUTF_SPAN |
9749 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t |
9750 | | utf8_length_from_utf32(std::span<const char32_t> valid_utf32_input) noexcept { |
9751 | | #if SIMDUTF_CPLUSPLUS23 |
9752 | | if consteval { |
9753 | | return scalar::utf32::utf8_length_from_utf32(valid_utf32_input.data(), |
9754 | | valid_utf32_input.size()); |
9755 | | } else |
9756 | | #endif |
9757 | | { |
9758 | | return utf8_length_from_utf32(valid_utf32_input.data(), |
9759 | | valid_utf32_input.size()); |
9760 | | } |
9761 | | } |
9762 | | #endif // SIMDUTF_SPAN |
9763 | | #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32 |
9764 | | |
9765 | | #if SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_UTF32 |
9766 | | /** |
9767 | | * Compute the number of two-byte code units that this UTF-32 string would |
9768 | | * require in UTF-16 format. |
9769 | | * |
9770 | | * This function does not validate the input. It is acceptable to pass invalid |
9771 | | * UTF-32 strings but in such cases the result is implementation defined. |
9772 | | * |
9773 | | * @param input the UTF-32 string to convert |
9774 | | * @param length the length of the string in 4-byte code units (char32_t) |
9775 | | * @return the number of bytes required to encode the UTF-32 string as UTF-16 |
9776 | | */ |
9777 | | simdutf_warn_unused size_t utf16_length_from_utf32(const char32_t *input, |
9778 | | size_t length) noexcept; |
9779 | | #if SIMDUTF_SPAN |
9780 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t |
9781 | | utf16_length_from_utf32(std::span<const char32_t> valid_utf32_input) noexcept { |
9782 | | #if SIMDUTF_CPLUSPLUS23 |
9783 | | if consteval { |
9784 | | return scalar::utf32::utf16_length_from_utf32(valid_utf32_input.data(), |
9785 | | valid_utf32_input.size()); |
9786 | | } else |
9787 | | #endif |
9788 | | { |
9789 | | return utf16_length_from_utf32(valid_utf32_input.data(), |
9790 | | valid_utf32_input.size()); |
9791 | | } |
9792 | | } |
9793 | | #endif // SIMDUTF_SPAN |
9794 | | |
9795 | | /** |
9796 | | * Using native endianness; Compute the number of bytes that this UTF-16 |
9797 | | * string would require in UTF-32 format. |
9798 | | * |
9799 | | * This function is equivalent to count_utf16. |
9800 | | * |
9801 | | * This function does not validate the input. It is acceptable to pass invalid |
9802 | | * UTF-16 strings but in such cases the result is implementation defined. |
9803 | | * |
9804 | | * This function is not BOM-aware. |
9805 | | * |
9806 | | * @param input the UTF-16 string to convert |
9807 | | * @param length the length of the string in 2-byte code units (char16_t) |
9808 | | * @return the number of bytes required to encode the UTF-16LE string as UTF-32 |
9809 | | */ |
9810 | | simdutf_warn_unused size_t utf32_length_from_utf16(const char16_t *input, |
9811 | | size_t length) noexcept; |
9812 | | #if SIMDUTF_SPAN |
9813 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t |
9814 | | utf32_length_from_utf16(std::span<const char16_t> valid_utf16_input) noexcept { |
9815 | | #if SIMDUTF_CPLUSPLUS23 |
9816 | | if consteval { |
9817 | | return scalar::utf16::utf32_length_from_utf16<endianness::NATIVE>( |
9818 | | valid_utf16_input.data(), valid_utf16_input.size()); |
9819 | | } else |
9820 | | #endif |
9821 | | { |
9822 | | return utf32_length_from_utf16(valid_utf16_input.data(), |
9823 | | valid_utf16_input.size()); |
9824 | | } |
9825 | | } |
9826 | | #endif // SIMDUTF_SPAN |
9827 | | |
9828 | | /** |
9829 | | * Compute the number of bytes that this UTF-16LE string would require in UTF-32 |
9830 | | * format. |
9831 | | * |
9832 | | * This function is equivalent to count_utf16le. |
9833 | | * |
9834 | | * This function does not validate the input. It is acceptable to pass invalid |
9835 | | * UTF-16 strings but in such cases the result is implementation defined. |
9836 | | * |
9837 | | * This function is not BOM-aware. |
9838 | | * |
9839 | | * @param input the UTF-16LE string to convert |
9840 | | * @param length the length of the string in 2-byte code units (char16_t) |
9841 | | * @return the number of bytes required to encode the UTF-16LE string as UTF-32 |
9842 | | */ |
9843 | | simdutf_warn_unused size_t utf32_length_from_utf16le(const char16_t *input, |
9844 | | size_t length) noexcept; |
9845 | | #if SIMDUTF_SPAN |
9846 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t |
9847 | | utf32_length_from_utf16le( |
9848 | | std::span<const char16_t> valid_utf16_input) noexcept { |
9849 | | #if SIMDUTF_CPLUSPLUS23 |
9850 | | if consteval { |
9851 | | return scalar::utf16::utf32_length_from_utf16<endianness::LITTLE>( |
9852 | | valid_utf16_input.data(), valid_utf16_input.size()); |
9853 | | } else |
9854 | | #endif |
9855 | | { |
9856 | | return utf32_length_from_utf16le(valid_utf16_input.data(), |
9857 | | valid_utf16_input.size()); |
9858 | | } |
9859 | | } |
9860 | | #endif // SIMDUTF_SPAN |
9861 | | |
9862 | | /** |
9863 | | * Compute the number of bytes that this UTF-16BE string would require in UTF-32 |
9864 | | * format. |
9865 | | * |
9866 | | * This function is equivalent to count_utf16be. |
9867 | | * |
9868 | | * This function does not validate the input. It is acceptable to pass invalid |
9869 | | * UTF-16 strings but in such cases the result is implementation defined. |
9870 | | * |
9871 | | * This function is not BOM-aware. |
9872 | | * |
9873 | | * @param input the UTF-16BE string to convert |
9874 | | * @param length the length of the string in 2-byte code units (char16_t) |
9875 | | * @return the number of bytes required to encode the UTF-16BE string as UTF-32 |
9876 | | */ |
9877 | | simdutf_warn_unused size_t utf32_length_from_utf16be(const char16_t *input, |
9878 | | size_t length) noexcept; |
9879 | | #if SIMDUTF_SPAN |
9880 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t |
9881 | | utf32_length_from_utf16be( |
9882 | | std::span<const char16_t> valid_utf16_input) noexcept { |
9883 | | #if SIMDUTF_CPLUSPLUS23 |
9884 | | if consteval { |
9885 | | return scalar::utf16::utf32_length_from_utf16<endianness::BIG>( |
9886 | | valid_utf16_input.data(), valid_utf16_input.size()); |
9887 | | } else |
9888 | | #endif |
9889 | | { |
9890 | | return utf32_length_from_utf16be(valid_utf16_input.data(), |
9891 | | valid_utf16_input.size()); |
9892 | | } |
9893 | | } |
9894 | | #endif // SIMDUTF_SPAN |
9895 | | #endif // SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_UTF32 |
9896 | | |
9897 | | #if SIMDUTF_FEATURE_UTF16 |
9898 | | /** |
9899 | | * Count the number of code points (characters) in the string assuming that |
9900 | | * it is valid. |
9901 | | * |
9902 | | * This function assumes that the input string is valid UTF-16 (native |
9903 | | * endianness). It is acceptable to pass invalid UTF-16 strings but in such |
9904 | | * cases the result is implementation defined. |
9905 | | * |
9906 | | * This function is not BOM-aware. |
9907 | | * |
9908 | | * @param input the UTF-16 string to process |
9909 | | * @param length the length of the string in 2-byte code units (char16_t) |
9910 | | * @return number of code points |
9911 | | */ |
9912 | | simdutf_warn_unused size_t count_utf16(const char16_t *input, |
9913 | | size_t length) noexcept; |
9914 | | #if SIMDUTF_SPAN |
9915 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t |
9916 | | count_utf16(std::span<const char16_t> valid_utf16_input) noexcept { |
9917 | | #if SIMDUTF_CPLUSPLUS23 |
9918 | | if consteval { |
9919 | | return scalar::utf16::count_code_points<endianness::NATIVE>( |
9920 | | valid_utf16_input.data(), valid_utf16_input.size()); |
9921 | | } else |
9922 | | #endif |
9923 | | { |
9924 | | return count_utf16(valid_utf16_input.data(), valid_utf16_input.size()); |
9925 | | } |
9926 | | } |
9927 | | #endif // SIMDUTF_SPAN |
9928 | | |
9929 | | /** |
9930 | | * Count the number of code points (characters) in the string assuming that |
9931 | | * it is valid. |
9932 | | * |
9933 | | * This function assumes that the input string is valid UTF-16LE. |
9934 | | * It is acceptable to pass invalid UTF-16 strings but in such cases |
9935 | | * the result is implementation defined. |
9936 | | * |
9937 | | * This function is not BOM-aware. |
9938 | | * |
9939 | | * @param input the UTF-16LE string to process |
9940 | | * @param length the length of the string in 2-byte code units (char16_t) |
9941 | | * @return number of code points |
9942 | | */ |
9943 | | simdutf_warn_unused size_t count_utf16le(const char16_t *input, |
9944 | | size_t length) noexcept; |
9945 | | #if SIMDUTF_SPAN |
9946 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t |
9947 | | count_utf16le(std::span<const char16_t> valid_utf16_input) noexcept { |
9948 | | #if SIMDUTF_CPLUSPLUS23 |
9949 | | if consteval { |
9950 | | return scalar::utf16::count_code_points<endianness::LITTLE>( |
9951 | | valid_utf16_input.data(), valid_utf16_input.size()); |
9952 | | } else |
9953 | | #endif |
9954 | | { |
9955 | | return count_utf16le(valid_utf16_input.data(), valid_utf16_input.size()); |
9956 | | } |
9957 | | } |
9958 | | #endif // SIMDUTF_SPAN |
9959 | | |
9960 | | /** |
9961 | | * Count the number of code points (characters) in the string assuming that |
9962 | | * it is valid. |
9963 | | * |
9964 | | * This function assumes that the input string is valid UTF-16BE. |
9965 | | * It is acceptable to pass invalid UTF-16 strings but in such cases |
9966 | | * the result is implementation defined. |
9967 | | * |
9968 | | * This function is not BOM-aware. |
9969 | | * |
9970 | | * @param input the UTF-16BE string to process |
9971 | | * @param length the length of the string in 2-byte code units (char16_t) |
9972 | | * @return number of code points |
9973 | | */ |
9974 | | simdutf_warn_unused size_t count_utf16be(const char16_t *input, |
9975 | | size_t length) noexcept; |
9976 | | #if SIMDUTF_SPAN |
9977 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t |
9978 | | count_utf16be(std::span<const char16_t> valid_utf16_input) noexcept { |
9979 | | #if SIMDUTF_CPLUSPLUS23 |
9980 | | if consteval { |
9981 | | return scalar::utf16::count_code_points<endianness::BIG>( |
9982 | | valid_utf16_input.data(), valid_utf16_input.size()); |
9983 | | } else |
9984 | | #endif |
9985 | | { |
9986 | | return count_utf16be(valid_utf16_input.data(), valid_utf16_input.size()); |
9987 | | } |
9988 | | } |
9989 | | #endif // SIMDUTF_SPAN |
9990 | | #endif // SIMDUTF_FEATURE_UTF16 |
9991 | | |
9992 | | #if SIMDUTF_FEATURE_UTF8 |
9993 | | /** |
9994 | | * Count the number of code points (characters) in the string assuming that |
9995 | | * it is valid. |
9996 | | * |
9997 | | * This function assumes that the input string is valid UTF-8. |
9998 | | * It is acceptable to pass invalid UTF-8 strings but in such cases |
9999 | | * the result is implementation defined. |
10000 | | * |
10001 | | * @param input the UTF-8 string to process |
10002 | | * @param length the length of the string in bytes |
10003 | | * @return number of code points |
10004 | | */ |
10005 | | simdutf_warn_unused size_t count_utf8(const char *input, |
10006 | | size_t length) noexcept; |
10007 | | #if SIMDUTF_SPAN |
10008 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t count_utf8( |
10009 | | const detail::input_span_of_byte_like auto &valid_utf8_input) noexcept { |
10010 | | #if SIMDUTF_CPLUSPLUS23 |
10011 | | if consteval { |
10012 | | return scalar::utf8::count_code_points(valid_utf8_input.data(), |
10013 | | valid_utf8_input.size()); |
10014 | | } else |
10015 | | #endif |
10016 | | { |
10017 | | return count_utf8(reinterpret_cast<const char *>(valid_utf8_input.data()), |
10018 | | valid_utf8_input.size()); |
10019 | | } |
10020 | | } |
10021 | | #endif // SIMDUTF_SPAN |
10022 | | |
10023 | | /** |
10024 | | * Given a valid UTF-8 string having a possibly truncated last character, |
10025 | | * this function checks the end of string. If the last character is truncated |
10026 | | * (or partial), then it returns a shorter length (shorter by 1 to 3 bytes) so |
10027 | | * that the short UTF-8 strings only contain complete characters. If there is no |
10028 | | * truncated character, the original length is returned. |
10029 | | * |
10030 | | * This function assumes that the input string is valid UTF-8, but possibly |
10031 | | * truncated. |
10032 | | * |
10033 | | * @param input the UTF-8 string to process |
10034 | | * @param length the length of the string in bytes |
10035 | | * @return the length of the string in bytes, possibly shorter by 1 to 3 bytes |
10036 | | */ |
10037 | | simdutf_warn_unused size_t trim_partial_utf8(const char *input, size_t length); |
10038 | | #if SIMDUTF_SPAN |
10039 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t |
10040 | | trim_partial_utf8( |
10041 | | const detail::input_span_of_byte_like auto &valid_utf8_input) noexcept { |
10042 | | #if SIMDUTF_CPLUSPLUS23 |
10043 | | if consteval { |
10044 | | return scalar::utf8::trim_partial_utf8(valid_utf8_input.data(), |
10045 | | valid_utf8_input.size()); |
10046 | | } else |
10047 | | #endif |
10048 | | { |
10049 | | return trim_partial_utf8( |
10050 | | reinterpret_cast<const char *>(valid_utf8_input.data()), |
10051 | | valid_utf8_input.size()); |
10052 | | } |
10053 | | } |
10054 | | #endif // SIMDUTF_SPAN |
10055 | | #endif // SIMDUTF_FEATURE_UTF8 |
10056 | | |
10057 | | #if SIMDUTF_FEATURE_UTF16 |
10058 | | /** |
10059 | | * Given a valid UTF-16BE string having a possibly truncated last character, |
10060 | | * this function checks the end of string. If the last character is truncated |
10061 | | * (or partial), then it returns a shorter length (shorter by 1 unit) so that |
10062 | | * the short UTF-16BE strings only contain complete characters. If there is no |
10063 | | * truncated character, the original length is returned. |
10064 | | * |
10065 | | * This function assumes that the input string is valid UTF-16BE, but possibly |
10066 | | * truncated. |
10067 | | * |
10068 | | * @param input the UTF-16BE string to process |
10069 | | * @param length the length of the string in bytes |
10070 | | * @return the length of the string in bytes, possibly shorter by 1 unit |
10071 | | */ |
10072 | | simdutf_warn_unused size_t trim_partial_utf16be(const char16_t *input, |
10073 | | size_t length); |
10074 | | #if SIMDUTF_SPAN |
10075 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t |
10076 | | trim_partial_utf16be(std::span<const char16_t> valid_utf16_input) noexcept { |
10077 | | #if SIMDUTF_CPLUSPLUS23 |
10078 | | if consteval { |
10079 | | return scalar::utf16::trim_partial_utf16<endianness::BIG>( |
10080 | | valid_utf16_input.data(), valid_utf16_input.size()); |
10081 | | } else |
10082 | | #endif |
10083 | | { |
10084 | | return trim_partial_utf16be(valid_utf16_input.data(), |
10085 | | valid_utf16_input.size()); |
10086 | | } |
10087 | | } |
10088 | | #endif // SIMDUTF_SPAN |
10089 | | |
10090 | | /** |
10091 | | * Given a valid UTF-16LE string having a possibly truncated last character, |
10092 | | * this function checks the end of string. If the last character is truncated |
10093 | | * (or partial), then it returns a shorter length (shorter by 1 unit) so that |
10094 | | * the short UTF-16LE strings only contain complete characters. If there is no |
10095 | | * truncated character, the original length is returned. |
10096 | | * |
10097 | | * This function assumes that the input string is valid UTF-16LE, but possibly |
10098 | | * truncated. |
10099 | | * |
10100 | | * @param input the UTF-16LE string to process |
10101 | | * @param length the length of the string in bytes |
10102 | | * @return the length of the string in unit, possibly shorter by 1 unit |
10103 | | */ |
10104 | | simdutf_warn_unused size_t trim_partial_utf16le(const char16_t *input, |
10105 | | size_t length); |
10106 | | #if SIMDUTF_SPAN |
10107 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t |
10108 | | trim_partial_utf16le(std::span<const char16_t> valid_utf16_input) noexcept { |
10109 | | #if SIMDUTF_CPLUSPLUS23 |
10110 | | if consteval { |
10111 | | return scalar::utf16::trim_partial_utf16<endianness::LITTLE>( |
10112 | | valid_utf16_input.data(), valid_utf16_input.size()); |
10113 | | } else |
10114 | | #endif |
10115 | | { |
10116 | | return trim_partial_utf16le(valid_utf16_input.data(), |
10117 | | valid_utf16_input.size()); |
10118 | | } |
10119 | | } |
10120 | | #endif // SIMDUTF_SPAN |
10121 | | |
10122 | | /** |
10123 | | * Given a valid UTF-16 string having a possibly truncated last character, |
10124 | | * this function checks the end of string. If the last character is truncated |
10125 | | * (or partial), then it returns a shorter length (shorter by 1 unit) so that |
10126 | | * the short UTF-16 strings only contain complete characters. If there is no |
10127 | | * truncated character, the original length is returned. |
10128 | | * |
10129 | | * This function assumes that the input string is valid UTF-16, but possibly |
10130 | | * truncated. We use the native endianness. |
10131 | | * |
10132 | | * @param input the UTF-16 string to process |
10133 | | * @param length the length of the string in bytes |
10134 | | * @return the length of the string in unit, possibly shorter by 1 unit |
10135 | | */ |
10136 | | simdutf_warn_unused size_t trim_partial_utf16(const char16_t *input, |
10137 | | size_t length); |
10138 | | #if SIMDUTF_SPAN |
10139 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t |
10140 | | trim_partial_utf16(std::span<const char16_t> valid_utf16_input) noexcept { |
10141 | | #if SIMDUTF_CPLUSPLUS23 |
10142 | | if consteval { |
10143 | | return scalar::utf16::trim_partial_utf16<endianness::NATIVE>( |
10144 | | valid_utf16_input.data(), valid_utf16_input.size()); |
10145 | | } else |
10146 | | #endif |
10147 | | { |
10148 | | return trim_partial_utf16(valid_utf16_input.data(), |
10149 | | valid_utf16_input.size()); |
10150 | | } |
10151 | | } |
10152 | | #endif // SIMDUTF_SPAN |
10153 | | #endif // SIMDUTF_FEATURE_UTF16 |
10154 | | |
10155 | | #if SIMDUTF_FEATURE_BASE64 || SIMDUTF_FEATURE_UTF16 || \ |
10156 | | SIMDUTF_FEATURE_DETECT_ENCODING |
10157 | | #ifndef SIMDUTF_NEED_TRAILING_ZEROES |
10158 | | #define SIMDUTF_NEED_TRAILING_ZEROES 1 |
10159 | | #endif |
10160 | | #endif // SIMDUTF_FEATURE_BASE64 || SIMDUTF_FEATURE_UTF16 || |
10161 | | // SIMDUTF_FEATURE_DETECT_ENCODING |
10162 | | |
10163 | | #if SIMDUTF_FEATURE_BASE64 |
10164 | | // base64_options are used to specify the base64 encoding options. |
10165 | | // ASCII spaces are ' ', '\t', '\n', '\r', '\f' |
10166 | | // garbage characters are characters that are not part of the base64 alphabet |
10167 | | // nor ASCII spaces. |
10168 | | constexpr uint64_t base64_reverse_padding = |
10169 | | 2; /* modifier for base64_default and base64_url */ |
10170 | | enum base64_options : uint64_t { |
10171 | | base64_default = 0, /* standard base64 format (with padding) */ |
10172 | | base64_url = 1, /* base64url format (no padding) */ |
10173 | | base64_default_no_padding = |
10174 | | base64_default | |
10175 | | base64_reverse_padding, /* standard base64 format without padding */ |
10176 | | base64_url_with_padding = |
10177 | | base64_url | base64_reverse_padding, /* base64url with padding */ |
10178 | | base64_default_accept_garbage = |
10179 | | 4, /* standard base64 format accepting garbage characters, the input stops |
10180 | | with the first '=' if any */ |
10181 | | base64_url_accept_garbage = |
10182 | | 5, /* base64url format accepting garbage characters, the input stops with |
10183 | | the first '=' if any */ |
10184 | | base64_default_or_url = |
10185 | | 8, /* standard/base64url hybrid format (only meaningful for decoding!) */ |
10186 | | base64_default_or_url_accept_garbage = |
10187 | | 12, /* standard/base64url hybrid format accepting garbage characters |
10188 | | (only meaningful for decoding!), the input stops with the first '=' |
10189 | | if any */ |
10190 | | }; |
10191 | | |
10192 | | // last_chunk_handling_options are used to specify the handling of the last |
10193 | | // chunk in base64 decoding. |
10194 | | // https://tc39.es/proposal-arraybuffer-base64/spec/#sec-frombase64 |
10195 | | enum last_chunk_handling_options : uint64_t { |
10196 | | loose = 0, /* standard base64 format, decode partial final chunk */ |
10197 | | strict = 1, /* error when the last chunk is partial, 2 or 3 chars, and |
10198 | | unpadded, or non-zero bit padding */ |
10199 | | stop_before_partial = |
10200 | | 2, /* if the last chunk is partial, ignore it (no error) */ |
10201 | | only_full_chunks = |
10202 | | 3 /* only decode full blocks (4 base64 characters, no padding) */ |
10203 | | }; |
10204 | | |
10205 | | inline simdutf_constexpr23 bool |
10206 | 43.5k | is_partial(last_chunk_handling_options options) { |
10207 | 43.5k | return (options == stop_before_partial) || (options == only_full_chunks); |
10208 | 43.5k | } |
10209 | | |
10210 | | namespace detail { |
10211 | | simdutf_warn_unused const char *find(const char *start, const char *end, |
10212 | | char character) noexcept; |
10213 | | simdutf_warn_unused const char16_t * |
10214 | | find(const char16_t *start, const char16_t *end, char16_t character) noexcept; |
10215 | | } // namespace detail |
10216 | | |
10217 | | /** |
10218 | | * Find the first occurrence of a character in a string. If the character is |
10219 | | * not found, return a pointer to the end of the string. |
10220 | | * @param start the start of the string |
10221 | | * @param end the end of the string |
10222 | | * @param character the character to find |
10223 | | * @return a pointer to the first occurrence of the character in the string, |
10224 | | * or a pointer to the end of the string if the character is not found. |
10225 | | * |
10226 | | */ |
10227 | | simdutf_warn_unused simdutf_really_inline simdutf_constexpr23 const char * |
10228 | 0 | find(const char *start, const char *end, char character) noexcept { |
10229 | | #if SIMDUTF_CPLUSPLUS23 |
10230 | | if consteval { |
10231 | | for (; start != end; ++start) |
10232 | | if (*start == character) |
10233 | | return start; |
10234 | | return end; |
10235 | | } else |
10236 | | #endif |
10237 | 0 | { |
10238 | 0 | return detail::find(start, end, character); |
10239 | 0 | } |
10240 | 0 | } |
10241 | | simdutf_warn_unused simdutf_really_inline simdutf_constexpr23 const char16_t * |
10242 | 0 | find(const char16_t *start, const char16_t *end, char16_t character) noexcept { |
10243 | | // implementation note: this is repeated instead of a template, to ensure |
10244 | | // the api is still a function and compiles without concepts |
10245 | | #if SIMDUTF_CPLUSPLUS23 |
10246 | | if consteval { |
10247 | | for (; start != end; ++start) |
10248 | | if (*start == character) |
10249 | | return start; |
10250 | | return end; |
10251 | | } else |
10252 | | #endif |
10253 | 0 | { |
10254 | 0 | return detail::find(start, end, character); |
10255 | 0 | } |
10256 | 0 | } |
10257 | | } |
10258 | | // We include base64_tables once. |
10259 | | /* begin file include/simdutf/base64_tables.h */ |
10260 | | #ifndef SIMDUTF_BASE64_TABLES_H |
10261 | | #define SIMDUTF_BASE64_TABLES_H |
10262 | | #include <cstdint> |
10263 | | |
10264 | | namespace simdutf { |
10265 | | namespace { |
10266 | | namespace tables { |
10267 | | namespace base64 { |
10268 | | namespace base64_default { |
10269 | | |
10270 | | constexpr char e0[256] = { |
10271 | | 'A', 'A', 'A', 'A', 'B', 'B', 'B', 'B', 'C', 'C', 'C', 'C', 'D', 'D', 'D', |
10272 | | 'D', 'E', 'E', 'E', 'E', 'F', 'F', 'F', 'F', 'G', 'G', 'G', 'G', 'H', 'H', |
10273 | | 'H', 'H', 'I', 'I', 'I', 'I', 'J', 'J', 'J', 'J', 'K', 'K', 'K', 'K', 'L', |
10274 | | 'L', 'L', 'L', 'M', 'M', 'M', 'M', 'N', 'N', 'N', 'N', 'O', 'O', 'O', 'O', |
10275 | | 'P', 'P', 'P', 'P', 'Q', 'Q', 'Q', 'Q', 'R', 'R', 'R', 'R', 'S', 'S', 'S', |
10276 | | 'S', 'T', 'T', 'T', 'T', 'U', 'U', 'U', 'U', 'V', 'V', 'V', 'V', 'W', 'W', |
10277 | | 'W', 'W', 'X', 'X', 'X', 'X', 'Y', 'Y', 'Y', 'Y', 'Z', 'Z', 'Z', 'Z', 'a', |
10278 | | 'a', 'a', 'a', 'b', 'b', 'b', 'b', 'c', 'c', 'c', 'c', 'd', 'd', 'd', 'd', |
10279 | | 'e', 'e', 'e', 'e', 'f', 'f', 'f', 'f', 'g', 'g', 'g', 'g', 'h', 'h', 'h', |
10280 | | 'h', 'i', 'i', 'i', 'i', 'j', 'j', 'j', 'j', 'k', 'k', 'k', 'k', 'l', 'l', |
10281 | | 'l', 'l', 'm', 'm', 'm', 'm', 'n', 'n', 'n', 'n', 'o', 'o', 'o', 'o', 'p', |
10282 | | 'p', 'p', 'p', 'q', 'q', 'q', 'q', 'r', 'r', 'r', 'r', 's', 's', 's', 's', |
10283 | | 't', 't', 't', 't', 'u', 'u', 'u', 'u', 'v', 'v', 'v', 'v', 'w', 'w', 'w', |
10284 | | 'w', 'x', 'x', 'x', 'x', 'y', 'y', 'y', 'y', 'z', 'z', 'z', 'z', '0', '0', |
10285 | | '0', '0', '1', '1', '1', '1', '2', '2', '2', '2', '3', '3', '3', '3', '4', |
10286 | | '4', '4', '4', '5', '5', '5', '5', '6', '6', '6', '6', '7', '7', '7', '7', |
10287 | | '8', '8', '8', '8', '9', '9', '9', '9', '+', '+', '+', '+', '/', '/', '/', |
10288 | | '/'}; |
10289 | | |
10290 | | constexpr char e1[256] = { |
10291 | | 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', |
10292 | | 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', |
10293 | | 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', |
10294 | | 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', |
10295 | | '8', '9', '+', '/', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', |
10296 | | 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', |
10297 | | 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', |
10298 | | 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', |
10299 | | '4', '5', '6', '7', '8', '9', '+', '/', 'A', 'B', 'C', 'D', 'E', 'F', 'G', |
10300 | | 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', |
10301 | | 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', |
10302 | | 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', |
10303 | | '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/', 'A', 'B', 'C', |
10304 | | 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', |
10305 | | 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', |
10306 | | 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', |
10307 | | 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', |
10308 | | '/'}; |
10309 | | |
10310 | | constexpr char e2[256] = { |
10311 | | 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', |
10312 | | 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', |
10313 | | 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', |
10314 | | 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', |
10315 | | '8', '9', '+', '/', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', |
10316 | | 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', |
10317 | | 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', |
10318 | | 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', |
10319 | | '4', '5', '6', '7', '8', '9', '+', '/', 'A', 'B', 'C', 'D', 'E', 'F', 'G', |
10320 | | 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', |
10321 | | 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', |
10322 | | 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', |
10323 | | '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/', 'A', 'B', 'C', |
10324 | | 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', |
10325 | | 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', |
10326 | | 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', |
10327 | | 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', |
10328 | | '/'}; |
10329 | | |
10330 | | constexpr uint32_t d0[256] = { |
10331 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10332 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10333 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10334 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10335 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10336 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10337 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10338 | | 0x01ffffff, 0x000000f8, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x000000fc, |
10339 | | 0x000000d0, 0x000000d4, 0x000000d8, 0x000000dc, 0x000000e0, 0x000000e4, |
10340 | | 0x000000e8, 0x000000ec, 0x000000f0, 0x000000f4, 0x01ffffff, 0x01ffffff, |
10341 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x00000000, |
10342 | | 0x00000004, 0x00000008, 0x0000000c, 0x00000010, 0x00000014, 0x00000018, |
10343 | | 0x0000001c, 0x00000020, 0x00000024, 0x00000028, 0x0000002c, 0x00000030, |
10344 | | 0x00000034, 0x00000038, 0x0000003c, 0x00000040, 0x00000044, 0x00000048, |
10345 | | 0x0000004c, 0x00000050, 0x00000054, 0x00000058, 0x0000005c, 0x00000060, |
10346 | | 0x00000064, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10347 | | 0x01ffffff, 0x00000068, 0x0000006c, 0x00000070, 0x00000074, 0x00000078, |
10348 | | 0x0000007c, 0x00000080, 0x00000084, 0x00000088, 0x0000008c, 0x00000090, |
10349 | | 0x00000094, 0x00000098, 0x0000009c, 0x000000a0, 0x000000a4, 0x000000a8, |
10350 | | 0x000000ac, 0x000000b0, 0x000000b4, 0x000000b8, 0x000000bc, 0x000000c0, |
10351 | | 0x000000c4, 0x000000c8, 0x000000cc, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10352 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10353 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10354 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10355 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10356 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10357 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10358 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10359 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10360 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10361 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10362 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10363 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10364 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10365 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10366 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10367 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10368 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10369 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10370 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10371 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10372 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10373 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff}; |
10374 | | |
10375 | | constexpr uint32_t d1[256] = { |
10376 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10377 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10378 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10379 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10380 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10381 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10382 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10383 | | 0x01ffffff, 0x0000e003, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x0000f003, |
10384 | | 0x00004003, 0x00005003, 0x00006003, 0x00007003, 0x00008003, 0x00009003, |
10385 | | 0x0000a003, 0x0000b003, 0x0000c003, 0x0000d003, 0x01ffffff, 0x01ffffff, |
10386 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x00000000, |
10387 | | 0x00001000, 0x00002000, 0x00003000, 0x00004000, 0x00005000, 0x00006000, |
10388 | | 0x00007000, 0x00008000, 0x00009000, 0x0000a000, 0x0000b000, 0x0000c000, |
10389 | | 0x0000d000, 0x0000e000, 0x0000f000, 0x00000001, 0x00001001, 0x00002001, |
10390 | | 0x00003001, 0x00004001, 0x00005001, 0x00006001, 0x00007001, 0x00008001, |
10391 | | 0x00009001, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10392 | | 0x01ffffff, 0x0000a001, 0x0000b001, 0x0000c001, 0x0000d001, 0x0000e001, |
10393 | | 0x0000f001, 0x00000002, 0x00001002, 0x00002002, 0x00003002, 0x00004002, |
10394 | | 0x00005002, 0x00006002, 0x00007002, 0x00008002, 0x00009002, 0x0000a002, |
10395 | | 0x0000b002, 0x0000c002, 0x0000d002, 0x0000e002, 0x0000f002, 0x00000003, |
10396 | | 0x00001003, 0x00002003, 0x00003003, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10397 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10398 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10399 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10400 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10401 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10402 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10403 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10404 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10405 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10406 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10407 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10408 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10409 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10410 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10411 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10412 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10413 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10414 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10415 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10416 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10417 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10418 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff}; |
10419 | | |
10420 | | constexpr uint32_t d2[256] = { |
10421 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10422 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10423 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10424 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10425 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10426 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10427 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10428 | | 0x01ffffff, 0x00800f00, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x00c00f00, |
10429 | | 0x00000d00, 0x00400d00, 0x00800d00, 0x00c00d00, 0x00000e00, 0x00400e00, |
10430 | | 0x00800e00, 0x00c00e00, 0x00000f00, 0x00400f00, 0x01ffffff, 0x01ffffff, |
10431 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x00000000, |
10432 | | 0x00400000, 0x00800000, 0x00c00000, 0x00000100, 0x00400100, 0x00800100, |
10433 | | 0x00c00100, 0x00000200, 0x00400200, 0x00800200, 0x00c00200, 0x00000300, |
10434 | | 0x00400300, 0x00800300, 0x00c00300, 0x00000400, 0x00400400, 0x00800400, |
10435 | | 0x00c00400, 0x00000500, 0x00400500, 0x00800500, 0x00c00500, 0x00000600, |
10436 | | 0x00400600, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10437 | | 0x01ffffff, 0x00800600, 0x00c00600, 0x00000700, 0x00400700, 0x00800700, |
10438 | | 0x00c00700, 0x00000800, 0x00400800, 0x00800800, 0x00c00800, 0x00000900, |
10439 | | 0x00400900, 0x00800900, 0x00c00900, 0x00000a00, 0x00400a00, 0x00800a00, |
10440 | | 0x00c00a00, 0x00000b00, 0x00400b00, 0x00800b00, 0x00c00b00, 0x00000c00, |
10441 | | 0x00400c00, 0x00800c00, 0x00c00c00, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10442 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10443 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10444 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10445 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10446 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10447 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10448 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10449 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10450 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10451 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10452 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10453 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10454 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10455 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10456 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10457 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10458 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10459 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10460 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10461 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10462 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10463 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff}; |
10464 | | |
10465 | | constexpr uint32_t d3[256] = { |
10466 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10467 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10468 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10469 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10470 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10471 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10472 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10473 | | 0x01ffffff, 0x003e0000, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x003f0000, |
10474 | | 0x00340000, 0x00350000, 0x00360000, 0x00370000, 0x00380000, 0x00390000, |
10475 | | 0x003a0000, 0x003b0000, 0x003c0000, 0x003d0000, 0x01ffffff, 0x01ffffff, |
10476 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x00000000, |
10477 | | 0x00010000, 0x00020000, 0x00030000, 0x00040000, 0x00050000, 0x00060000, |
10478 | | 0x00070000, 0x00080000, 0x00090000, 0x000a0000, 0x000b0000, 0x000c0000, |
10479 | | 0x000d0000, 0x000e0000, 0x000f0000, 0x00100000, 0x00110000, 0x00120000, |
10480 | | 0x00130000, 0x00140000, 0x00150000, 0x00160000, 0x00170000, 0x00180000, |
10481 | | 0x00190000, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10482 | | 0x01ffffff, 0x001a0000, 0x001b0000, 0x001c0000, 0x001d0000, 0x001e0000, |
10483 | | 0x001f0000, 0x00200000, 0x00210000, 0x00220000, 0x00230000, 0x00240000, |
10484 | | 0x00250000, 0x00260000, 0x00270000, 0x00280000, 0x00290000, 0x002a0000, |
10485 | | 0x002b0000, 0x002c0000, 0x002d0000, 0x002e0000, 0x002f0000, 0x00300000, |
10486 | | 0x00310000, 0x00320000, 0x00330000, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10487 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10488 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10489 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10490 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10491 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10492 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10493 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10494 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10495 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10496 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10497 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10498 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10499 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10500 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10501 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10502 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10503 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10504 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10505 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10506 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10507 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10508 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff}; |
10509 | | } // namespace base64_default |
10510 | | |
10511 | | namespace base64_url { |
10512 | | |
10513 | | constexpr char e0[256] = { |
10514 | | 'A', 'A', 'A', 'A', 'B', 'B', 'B', 'B', 'C', 'C', 'C', 'C', 'D', 'D', 'D', |
10515 | | 'D', 'E', 'E', 'E', 'E', 'F', 'F', 'F', 'F', 'G', 'G', 'G', 'G', 'H', 'H', |
10516 | | 'H', 'H', 'I', 'I', 'I', 'I', 'J', 'J', 'J', 'J', 'K', 'K', 'K', 'K', 'L', |
10517 | | 'L', 'L', 'L', 'M', 'M', 'M', 'M', 'N', 'N', 'N', 'N', 'O', 'O', 'O', 'O', |
10518 | | 'P', 'P', 'P', 'P', 'Q', 'Q', 'Q', 'Q', 'R', 'R', 'R', 'R', 'S', 'S', 'S', |
10519 | | 'S', 'T', 'T', 'T', 'T', 'U', 'U', 'U', 'U', 'V', 'V', 'V', 'V', 'W', 'W', |
10520 | | 'W', 'W', 'X', 'X', 'X', 'X', 'Y', 'Y', 'Y', 'Y', 'Z', 'Z', 'Z', 'Z', 'a', |
10521 | | 'a', 'a', 'a', 'b', 'b', 'b', 'b', 'c', 'c', 'c', 'c', 'd', 'd', 'd', 'd', |
10522 | | 'e', 'e', 'e', 'e', 'f', 'f', 'f', 'f', 'g', 'g', 'g', 'g', 'h', 'h', 'h', |
10523 | | 'h', 'i', 'i', 'i', 'i', 'j', 'j', 'j', 'j', 'k', 'k', 'k', 'k', 'l', 'l', |
10524 | | 'l', 'l', 'm', 'm', 'm', 'm', 'n', 'n', 'n', 'n', 'o', 'o', 'o', 'o', 'p', |
10525 | | 'p', 'p', 'p', 'q', 'q', 'q', 'q', 'r', 'r', 'r', 'r', 's', 's', 's', 's', |
10526 | | 't', 't', 't', 't', 'u', 'u', 'u', 'u', 'v', 'v', 'v', 'v', 'w', 'w', 'w', |
10527 | | 'w', 'x', 'x', 'x', 'x', 'y', 'y', 'y', 'y', 'z', 'z', 'z', 'z', '0', '0', |
10528 | | '0', '0', '1', '1', '1', '1', '2', '2', '2', '2', '3', '3', '3', '3', '4', |
10529 | | '4', '4', '4', '5', '5', '5', '5', '6', '6', '6', '6', '7', '7', '7', '7', |
10530 | | '8', '8', '8', '8', '9', '9', '9', '9', '-', '-', '-', '-', '_', '_', '_', |
10531 | | '_'}; |
10532 | | |
10533 | | constexpr char e1[256] = { |
10534 | | 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', |
10535 | | 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', |
10536 | | 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', |
10537 | | 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', |
10538 | | '8', '9', '-', '_', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', |
10539 | | 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', |
10540 | | 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', |
10541 | | 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', |
10542 | | '4', '5', '6', '7', '8', '9', '-', '_', 'A', 'B', 'C', 'D', 'E', 'F', 'G', |
10543 | | 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', |
10544 | | 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', |
10545 | | 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', |
10546 | | '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_', 'A', 'B', 'C', |
10547 | | 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', |
10548 | | 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', |
10549 | | 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', |
10550 | | 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', |
10551 | | '_'}; |
10552 | | |
10553 | | constexpr char e2[256] = { |
10554 | | 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', |
10555 | | 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', |
10556 | | 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', |
10557 | | 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', |
10558 | | '8', '9', '-', '_', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', |
10559 | | 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', |
10560 | | 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', |
10561 | | 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', |
10562 | | '4', '5', '6', '7', '8', '9', '-', '_', 'A', 'B', 'C', 'D', 'E', 'F', 'G', |
10563 | | 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', |
10564 | | 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', |
10565 | | 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', |
10566 | | '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_', 'A', 'B', 'C', |
10567 | | 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', |
10568 | | 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', |
10569 | | 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', |
10570 | | 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', |
10571 | | '_'}; |
10572 | | |
10573 | | constexpr uint32_t d0[256] = { |
10574 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10575 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10576 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10577 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10578 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10579 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10580 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10581 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x000000f8, 0x01ffffff, 0x01ffffff, |
10582 | | 0x000000d0, 0x000000d4, 0x000000d8, 0x000000dc, 0x000000e0, 0x000000e4, |
10583 | | 0x000000e8, 0x000000ec, 0x000000f0, 0x000000f4, 0x01ffffff, 0x01ffffff, |
10584 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x00000000, |
10585 | | 0x00000004, 0x00000008, 0x0000000c, 0x00000010, 0x00000014, 0x00000018, |
10586 | | 0x0000001c, 0x00000020, 0x00000024, 0x00000028, 0x0000002c, 0x00000030, |
10587 | | 0x00000034, 0x00000038, 0x0000003c, 0x00000040, 0x00000044, 0x00000048, |
10588 | | 0x0000004c, 0x00000050, 0x00000054, 0x00000058, 0x0000005c, 0x00000060, |
10589 | | 0x00000064, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x000000fc, |
10590 | | 0x01ffffff, 0x00000068, 0x0000006c, 0x00000070, 0x00000074, 0x00000078, |
10591 | | 0x0000007c, 0x00000080, 0x00000084, 0x00000088, 0x0000008c, 0x00000090, |
10592 | | 0x00000094, 0x00000098, 0x0000009c, 0x000000a0, 0x000000a4, 0x000000a8, |
10593 | | 0x000000ac, 0x000000b0, 0x000000b4, 0x000000b8, 0x000000bc, 0x000000c0, |
10594 | | 0x000000c4, 0x000000c8, 0x000000cc, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10595 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10596 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10597 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10598 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10599 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10600 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10601 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10602 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10603 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10604 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10605 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10606 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10607 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10608 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10609 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10610 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10611 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10612 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10613 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10614 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10615 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10616 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff}; |
10617 | | constexpr uint32_t d1[256] = { |
10618 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10619 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10620 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10621 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10622 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10623 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10624 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10625 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x0000e003, 0x01ffffff, 0x01ffffff, |
10626 | | 0x00004003, 0x00005003, 0x00006003, 0x00007003, 0x00008003, 0x00009003, |
10627 | | 0x0000a003, 0x0000b003, 0x0000c003, 0x0000d003, 0x01ffffff, 0x01ffffff, |
10628 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x00000000, |
10629 | | 0x00001000, 0x00002000, 0x00003000, 0x00004000, 0x00005000, 0x00006000, |
10630 | | 0x00007000, 0x00008000, 0x00009000, 0x0000a000, 0x0000b000, 0x0000c000, |
10631 | | 0x0000d000, 0x0000e000, 0x0000f000, 0x00000001, 0x00001001, 0x00002001, |
10632 | | 0x00003001, 0x00004001, 0x00005001, 0x00006001, 0x00007001, 0x00008001, |
10633 | | 0x00009001, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x0000f003, |
10634 | | 0x01ffffff, 0x0000a001, 0x0000b001, 0x0000c001, 0x0000d001, 0x0000e001, |
10635 | | 0x0000f001, 0x00000002, 0x00001002, 0x00002002, 0x00003002, 0x00004002, |
10636 | | 0x00005002, 0x00006002, 0x00007002, 0x00008002, 0x00009002, 0x0000a002, |
10637 | | 0x0000b002, 0x0000c002, 0x0000d002, 0x0000e002, 0x0000f002, 0x00000003, |
10638 | | 0x00001003, 0x00002003, 0x00003003, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10639 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10640 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10641 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10642 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10643 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10644 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10645 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10646 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10647 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10648 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10649 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10650 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10651 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10652 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10653 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10654 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10655 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10656 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10657 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10658 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10659 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10660 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff}; |
10661 | | constexpr uint32_t d2[256] = { |
10662 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10663 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10664 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10665 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10666 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10667 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10668 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10669 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x00800f00, 0x01ffffff, 0x01ffffff, |
10670 | | 0x00000d00, 0x00400d00, 0x00800d00, 0x00c00d00, 0x00000e00, 0x00400e00, |
10671 | | 0x00800e00, 0x00c00e00, 0x00000f00, 0x00400f00, 0x01ffffff, 0x01ffffff, |
10672 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x00000000, |
10673 | | 0x00400000, 0x00800000, 0x00c00000, 0x00000100, 0x00400100, 0x00800100, |
10674 | | 0x00c00100, 0x00000200, 0x00400200, 0x00800200, 0x00c00200, 0x00000300, |
10675 | | 0x00400300, 0x00800300, 0x00c00300, 0x00000400, 0x00400400, 0x00800400, |
10676 | | 0x00c00400, 0x00000500, 0x00400500, 0x00800500, 0x00c00500, 0x00000600, |
10677 | | 0x00400600, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x00c00f00, |
10678 | | 0x01ffffff, 0x00800600, 0x00c00600, 0x00000700, 0x00400700, 0x00800700, |
10679 | | 0x00c00700, 0x00000800, 0x00400800, 0x00800800, 0x00c00800, 0x00000900, |
10680 | | 0x00400900, 0x00800900, 0x00c00900, 0x00000a00, 0x00400a00, 0x00800a00, |
10681 | | 0x00c00a00, 0x00000b00, 0x00400b00, 0x00800b00, 0x00c00b00, 0x00000c00, |
10682 | | 0x00400c00, 0x00800c00, 0x00c00c00, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10683 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10684 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10685 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10686 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10687 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10688 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10689 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10690 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10691 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10692 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10693 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10694 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10695 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10696 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10697 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10698 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10699 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10700 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10701 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10702 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10703 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10704 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff}; |
10705 | | constexpr uint32_t d3[256] = { |
10706 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10707 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10708 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10709 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10710 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10711 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10712 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10713 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x003e0000, 0x01ffffff, 0x01ffffff, |
10714 | | 0x00340000, 0x00350000, 0x00360000, 0x00370000, 0x00380000, 0x00390000, |
10715 | | 0x003a0000, 0x003b0000, 0x003c0000, 0x003d0000, 0x01ffffff, 0x01ffffff, |
10716 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x00000000, |
10717 | | 0x00010000, 0x00020000, 0x00030000, 0x00040000, 0x00050000, 0x00060000, |
10718 | | 0x00070000, 0x00080000, 0x00090000, 0x000a0000, 0x000b0000, 0x000c0000, |
10719 | | 0x000d0000, 0x000e0000, 0x000f0000, 0x00100000, 0x00110000, 0x00120000, |
10720 | | 0x00130000, 0x00140000, 0x00150000, 0x00160000, 0x00170000, 0x00180000, |
10721 | | 0x00190000, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x003f0000, |
10722 | | 0x01ffffff, 0x001a0000, 0x001b0000, 0x001c0000, 0x001d0000, 0x001e0000, |
10723 | | 0x001f0000, 0x00200000, 0x00210000, 0x00220000, 0x00230000, 0x00240000, |
10724 | | 0x00250000, 0x00260000, 0x00270000, 0x00280000, 0x00290000, 0x002a0000, |
10725 | | 0x002b0000, 0x002c0000, 0x002d0000, 0x002e0000, 0x002f0000, 0x00300000, |
10726 | | 0x00310000, 0x00320000, 0x00330000, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10727 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10728 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10729 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10730 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10731 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10732 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10733 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10734 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10735 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10736 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10737 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10738 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10739 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10740 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10741 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10742 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10743 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10744 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10745 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10746 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10747 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10748 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff}; |
10749 | | } // namespace base64_url |
10750 | | |
10751 | | namespace base64_default_or_url { |
10752 | | constexpr uint32_t d0[256] = { |
10753 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10754 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10755 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10756 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10757 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10758 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10759 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10760 | | 0x01ffffff, 0x000000f8, 0x01ffffff, 0x000000f8, 0x01ffffff, 0x000000fc, |
10761 | | 0x000000d0, 0x000000d4, 0x000000d8, 0x000000dc, 0x000000e0, 0x000000e4, |
10762 | | 0x000000e8, 0x000000ec, 0x000000f0, 0x000000f4, 0x01ffffff, 0x01ffffff, |
10763 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x00000000, |
10764 | | 0x00000004, 0x00000008, 0x0000000c, 0x00000010, 0x00000014, 0x00000018, |
10765 | | 0x0000001c, 0x00000020, 0x00000024, 0x00000028, 0x0000002c, 0x00000030, |
10766 | | 0x00000034, 0x00000038, 0x0000003c, 0x00000040, 0x00000044, 0x00000048, |
10767 | | 0x0000004c, 0x00000050, 0x00000054, 0x00000058, 0x0000005c, 0x00000060, |
10768 | | 0x00000064, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x000000fc, |
10769 | | 0x01ffffff, 0x00000068, 0x0000006c, 0x00000070, 0x00000074, 0x00000078, |
10770 | | 0x0000007c, 0x00000080, 0x00000084, 0x00000088, 0x0000008c, 0x00000090, |
10771 | | 0x00000094, 0x00000098, 0x0000009c, 0x000000a0, 0x000000a4, 0x000000a8, |
10772 | | 0x000000ac, 0x000000b0, 0x000000b4, 0x000000b8, 0x000000bc, 0x000000c0, |
10773 | | 0x000000c4, 0x000000c8, 0x000000cc, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10774 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10775 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10776 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10777 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10778 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10779 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10780 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10781 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10782 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10783 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10784 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10785 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10786 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10787 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10788 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10789 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10790 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10791 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10792 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10793 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10794 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10795 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff}; |
10796 | | constexpr uint32_t d1[256] = { |
10797 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10798 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10799 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10800 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10801 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10802 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10803 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10804 | | 0x01ffffff, 0x0000e003, 0x01ffffff, 0x0000e003, 0x01ffffff, 0x0000f003, |
10805 | | 0x00004003, 0x00005003, 0x00006003, 0x00007003, 0x00008003, 0x00009003, |
10806 | | 0x0000a003, 0x0000b003, 0x0000c003, 0x0000d003, 0x01ffffff, 0x01ffffff, |
10807 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x00000000, |
10808 | | 0x00001000, 0x00002000, 0x00003000, 0x00004000, 0x00005000, 0x00006000, |
10809 | | 0x00007000, 0x00008000, 0x00009000, 0x0000a000, 0x0000b000, 0x0000c000, |
10810 | | 0x0000d000, 0x0000e000, 0x0000f000, 0x00000001, 0x00001001, 0x00002001, |
10811 | | 0x00003001, 0x00004001, 0x00005001, 0x00006001, 0x00007001, 0x00008001, |
10812 | | 0x00009001, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x0000f003, |
10813 | | 0x01ffffff, 0x0000a001, 0x0000b001, 0x0000c001, 0x0000d001, 0x0000e001, |
10814 | | 0x0000f001, 0x00000002, 0x00001002, 0x00002002, 0x00003002, 0x00004002, |
10815 | | 0x00005002, 0x00006002, 0x00007002, 0x00008002, 0x00009002, 0x0000a002, |
10816 | | 0x0000b002, 0x0000c002, 0x0000d002, 0x0000e002, 0x0000f002, 0x00000003, |
10817 | | 0x00001003, 0x00002003, 0x00003003, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10818 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10819 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10820 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10821 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10822 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10823 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10824 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10825 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10826 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10827 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10828 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10829 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10830 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10831 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10832 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10833 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10834 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10835 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10836 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10837 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10838 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10839 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff}; |
10840 | | constexpr uint32_t d2[256] = { |
10841 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10842 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10843 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10844 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10845 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10846 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10847 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10848 | | 0x01ffffff, 0x00800f00, 0x01ffffff, 0x00800f00, 0x01ffffff, 0x00c00f00, |
10849 | | 0x00000d00, 0x00400d00, 0x00800d00, 0x00c00d00, 0x00000e00, 0x00400e00, |
10850 | | 0x00800e00, 0x00c00e00, 0x00000f00, 0x00400f00, 0x01ffffff, 0x01ffffff, |
10851 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x00000000, |
10852 | | 0x00400000, 0x00800000, 0x00c00000, 0x00000100, 0x00400100, 0x00800100, |
10853 | | 0x00c00100, 0x00000200, 0x00400200, 0x00800200, 0x00c00200, 0x00000300, |
10854 | | 0x00400300, 0x00800300, 0x00c00300, 0x00000400, 0x00400400, 0x00800400, |
10855 | | 0x00c00400, 0x00000500, 0x00400500, 0x00800500, 0x00c00500, 0x00000600, |
10856 | | 0x00400600, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x00c00f00, |
10857 | | 0x01ffffff, 0x00800600, 0x00c00600, 0x00000700, 0x00400700, 0x00800700, |
10858 | | 0x00c00700, 0x00000800, 0x00400800, 0x00800800, 0x00c00800, 0x00000900, |
10859 | | 0x00400900, 0x00800900, 0x00c00900, 0x00000a00, 0x00400a00, 0x00800a00, |
10860 | | 0x00c00a00, 0x00000b00, 0x00400b00, 0x00800b00, 0x00c00b00, 0x00000c00, |
10861 | | 0x00400c00, 0x00800c00, 0x00c00c00, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10862 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10863 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10864 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10865 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10866 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10867 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10868 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10869 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10870 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10871 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10872 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10873 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10874 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10875 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10876 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10877 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10878 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10879 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10880 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10881 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10882 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10883 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff}; |
10884 | | constexpr uint32_t d3[256] = { |
10885 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10886 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10887 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10888 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10889 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10890 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10891 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10892 | | 0x01ffffff, 0x003e0000, 0x01ffffff, 0x003e0000, 0x01ffffff, 0x003f0000, |
10893 | | 0x00340000, 0x00350000, 0x00360000, 0x00370000, 0x00380000, 0x00390000, |
10894 | | 0x003a0000, 0x003b0000, 0x003c0000, 0x003d0000, 0x01ffffff, 0x01ffffff, |
10895 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x00000000, |
10896 | | 0x00010000, 0x00020000, 0x00030000, 0x00040000, 0x00050000, 0x00060000, |
10897 | | 0x00070000, 0x00080000, 0x00090000, 0x000a0000, 0x000b0000, 0x000c0000, |
10898 | | 0x000d0000, 0x000e0000, 0x000f0000, 0x00100000, 0x00110000, 0x00120000, |
10899 | | 0x00130000, 0x00140000, 0x00150000, 0x00160000, 0x00170000, 0x00180000, |
10900 | | 0x00190000, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x003f0000, |
10901 | | 0x01ffffff, 0x001a0000, 0x001b0000, 0x001c0000, 0x001d0000, 0x001e0000, |
10902 | | 0x001f0000, 0x00200000, 0x00210000, 0x00220000, 0x00230000, 0x00240000, |
10903 | | 0x00250000, 0x00260000, 0x00270000, 0x00280000, 0x00290000, 0x002a0000, |
10904 | | 0x002b0000, 0x002c0000, 0x002d0000, 0x002e0000, 0x002f0000, 0x00300000, |
10905 | | 0x00310000, 0x00320000, 0x00330000, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10906 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10907 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10908 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10909 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10910 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10911 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10912 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10913 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10914 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10915 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10916 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10917 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10918 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10919 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10920 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10921 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10922 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10923 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10924 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10925 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10926 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, |
10927 | | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff}; |
10928 | | } // namespace base64_default_or_url |
10929 | | constexpr uint64_t thintable_epi8[256] = { |
10930 | | 0x0706050403020100, 0x0007060504030201, 0x0007060504030200, |
10931 | | 0x0000070605040302, 0x0007060504030100, 0x0000070605040301, |
10932 | | 0x0000070605040300, 0x0000000706050403, 0x0007060504020100, |
10933 | | 0x0000070605040201, 0x0000070605040200, 0x0000000706050402, |
10934 | | 0x0000070605040100, 0x0000000706050401, 0x0000000706050400, |
10935 | | 0x0000000007060504, 0x0007060503020100, 0x0000070605030201, |
10936 | | 0x0000070605030200, 0x0000000706050302, 0x0000070605030100, |
10937 | | 0x0000000706050301, 0x0000000706050300, 0x0000000007060503, |
10938 | | 0x0000070605020100, 0x0000000706050201, 0x0000000706050200, |
10939 | | 0x0000000007060502, 0x0000000706050100, 0x0000000007060501, |
10940 | | 0x0000000007060500, 0x0000000000070605, 0x0007060403020100, |
10941 | | 0x0000070604030201, 0x0000070604030200, 0x0000000706040302, |
10942 | | 0x0000070604030100, 0x0000000706040301, 0x0000000706040300, |
10943 | | 0x0000000007060403, 0x0000070604020100, 0x0000000706040201, |
10944 | | 0x0000000706040200, 0x0000000007060402, 0x0000000706040100, |
10945 | | 0x0000000007060401, 0x0000000007060400, 0x0000000000070604, |
10946 | | 0x0000070603020100, 0x0000000706030201, 0x0000000706030200, |
10947 | | 0x0000000007060302, 0x0000000706030100, 0x0000000007060301, |
10948 | | 0x0000000007060300, 0x0000000000070603, 0x0000000706020100, |
10949 | | 0x0000000007060201, 0x0000000007060200, 0x0000000000070602, |
10950 | | 0x0000000007060100, 0x0000000000070601, 0x0000000000070600, |
10951 | | 0x0000000000000706, 0x0007050403020100, 0x0000070504030201, |
10952 | | 0x0000070504030200, 0x0000000705040302, 0x0000070504030100, |
10953 | | 0x0000000705040301, 0x0000000705040300, 0x0000000007050403, |
10954 | | 0x0000070504020100, 0x0000000705040201, 0x0000000705040200, |
10955 | | 0x0000000007050402, 0x0000000705040100, 0x0000000007050401, |
10956 | | 0x0000000007050400, 0x0000000000070504, 0x0000070503020100, |
10957 | | 0x0000000705030201, 0x0000000705030200, 0x0000000007050302, |
10958 | | 0x0000000705030100, 0x0000000007050301, 0x0000000007050300, |
10959 | | 0x0000000000070503, 0x0000000705020100, 0x0000000007050201, |
10960 | | 0x0000000007050200, 0x0000000000070502, 0x0000000007050100, |
10961 | | 0x0000000000070501, 0x0000000000070500, 0x0000000000000705, |
10962 | | 0x0000070403020100, 0x0000000704030201, 0x0000000704030200, |
10963 | | 0x0000000007040302, 0x0000000704030100, 0x0000000007040301, |
10964 | | 0x0000000007040300, 0x0000000000070403, 0x0000000704020100, |
10965 | | 0x0000000007040201, 0x0000000007040200, 0x0000000000070402, |
10966 | | 0x0000000007040100, 0x0000000000070401, 0x0000000000070400, |
10967 | | 0x0000000000000704, 0x0000000703020100, 0x0000000007030201, |
10968 | | 0x0000000007030200, 0x0000000000070302, 0x0000000007030100, |
10969 | | 0x0000000000070301, 0x0000000000070300, 0x0000000000000703, |
10970 | | 0x0000000007020100, 0x0000000000070201, 0x0000000000070200, |
10971 | | 0x0000000000000702, 0x0000000000070100, 0x0000000000000701, |
10972 | | 0x0000000000000700, 0x0000000000000007, 0x0006050403020100, |
10973 | | 0x0000060504030201, 0x0000060504030200, 0x0000000605040302, |
10974 | | 0x0000060504030100, 0x0000000605040301, 0x0000000605040300, |
10975 | | 0x0000000006050403, 0x0000060504020100, 0x0000000605040201, |
10976 | | 0x0000000605040200, 0x0000000006050402, 0x0000000605040100, |
10977 | | 0x0000000006050401, 0x0000000006050400, 0x0000000000060504, |
10978 | | 0x0000060503020100, 0x0000000605030201, 0x0000000605030200, |
10979 | | 0x0000000006050302, 0x0000000605030100, 0x0000000006050301, |
10980 | | 0x0000000006050300, 0x0000000000060503, 0x0000000605020100, |
10981 | | 0x0000000006050201, 0x0000000006050200, 0x0000000000060502, |
10982 | | 0x0000000006050100, 0x0000000000060501, 0x0000000000060500, |
10983 | | 0x0000000000000605, 0x0000060403020100, 0x0000000604030201, |
10984 | | 0x0000000604030200, 0x0000000006040302, 0x0000000604030100, |
10985 | | 0x0000000006040301, 0x0000000006040300, 0x0000000000060403, |
10986 | | 0x0000000604020100, 0x0000000006040201, 0x0000000006040200, |
10987 | | 0x0000000000060402, 0x0000000006040100, 0x0000000000060401, |
10988 | | 0x0000000000060400, 0x0000000000000604, 0x0000000603020100, |
10989 | | 0x0000000006030201, 0x0000000006030200, 0x0000000000060302, |
10990 | | 0x0000000006030100, 0x0000000000060301, 0x0000000000060300, |
10991 | | 0x0000000000000603, 0x0000000006020100, 0x0000000000060201, |
10992 | | 0x0000000000060200, 0x0000000000000602, 0x0000000000060100, |
10993 | | 0x0000000000000601, 0x0000000000000600, 0x0000000000000006, |
10994 | | 0x0000050403020100, 0x0000000504030201, 0x0000000504030200, |
10995 | | 0x0000000005040302, 0x0000000504030100, 0x0000000005040301, |
10996 | | 0x0000000005040300, 0x0000000000050403, 0x0000000504020100, |
10997 | | 0x0000000005040201, 0x0000000005040200, 0x0000000000050402, |
10998 | | 0x0000000005040100, 0x0000000000050401, 0x0000000000050400, |
10999 | | 0x0000000000000504, 0x0000000503020100, 0x0000000005030201, |
11000 | | 0x0000000005030200, 0x0000000000050302, 0x0000000005030100, |
11001 | | 0x0000000000050301, 0x0000000000050300, 0x0000000000000503, |
11002 | | 0x0000000005020100, 0x0000000000050201, 0x0000000000050200, |
11003 | | 0x0000000000000502, 0x0000000000050100, 0x0000000000000501, |
11004 | | 0x0000000000000500, 0x0000000000000005, 0x0000000403020100, |
11005 | | 0x0000000004030201, 0x0000000004030200, 0x0000000000040302, |
11006 | | 0x0000000004030100, 0x0000000000040301, 0x0000000000040300, |
11007 | | 0x0000000000000403, 0x0000000004020100, 0x0000000000040201, |
11008 | | 0x0000000000040200, 0x0000000000000402, 0x0000000000040100, |
11009 | | 0x0000000000000401, 0x0000000000000400, 0x0000000000000004, |
11010 | | 0x0000000003020100, 0x0000000000030201, 0x0000000000030200, |
11011 | | 0x0000000000000302, 0x0000000000030100, 0x0000000000000301, |
11012 | | 0x0000000000000300, 0x0000000000000003, 0x0000000000020100, |
11013 | | 0x0000000000000201, 0x0000000000000200, 0x0000000000000002, |
11014 | | 0x0000000000000100, 0x0000000000000001, 0x0000000000000000, |
11015 | | 0x0000000000000000, |
11016 | | }; |
11017 | | |
11018 | | constexpr uint8_t pshufb_combine_table[272] = { |
11019 | | 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, |
11020 | | 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x08, |
11021 | | 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0xff, 0x00, 0x01, 0x02, 0x03, |
11022 | | 0x04, 0x05, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0xff, 0xff, |
11023 | | 0x00, 0x01, 0x02, 0x03, 0x04, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, |
11024 | | 0x0f, 0xff, 0xff, 0xff, 0x00, 0x01, 0x02, 0x03, 0x08, 0x09, 0x0a, 0x0b, |
11025 | | 0x0c, 0x0d, 0x0e, 0x0f, 0xff, 0xff, 0xff, 0xff, 0x00, 0x01, 0x02, 0x08, |
11026 | | 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, |
11027 | | 0x00, 0x01, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0xff, 0xff, |
11028 | | 0xff, 0xff, 0xff, 0xff, 0x00, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, |
11029 | | 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x08, 0x09, 0x0a, 0x0b, |
11030 | | 0x0c, 0x0d, 0x0e, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, |
11031 | | }; |
11032 | | |
11033 | | constexpr unsigned char BitsSetTable256mul2[256] = { |
11034 | | 0, 2, 2, 4, 2, 4, 4, 6, 2, 4, 4, 6, 4, 6, 6, 8, 2, 4, 4, |
11035 | | 6, 4, 6, 6, 8, 4, 6, 6, 8, 6, 8, 8, 10, 2, 4, 4, 6, 4, 6, |
11036 | | 6, 8, 4, 6, 6, 8, 6, 8, 8, 10, 4, 6, 6, 8, 6, 8, 8, 10, 6, |
11037 | | 8, 8, 10, 8, 10, 10, 12, 2, 4, 4, 6, 4, 6, 6, 8, 4, 6, 6, 8, |
11038 | | 6, 8, 8, 10, 4, 6, 6, 8, 6, 8, 8, 10, 6, 8, 8, 10, 8, 10, 10, |
11039 | | 12, 4, 6, 6, 8, 6, 8, 8, 10, 6, 8, 8, 10, 8, 10, 10, 12, 6, 8, |
11040 | | 8, 10, 8, 10, 10, 12, 8, 10, 10, 12, 10, 12, 12, 14, 2, 4, 4, 6, 4, |
11041 | | 6, 6, 8, 4, 6, 6, 8, 6, 8, 8, 10, 4, 6, 6, 8, 6, 8, 8, 10, |
11042 | | 6, 8, 8, 10, 8, 10, 10, 12, 4, 6, 6, 8, 6, 8, 8, 10, 6, 8, 8, |
11043 | | 10, 8, 10, 10, 12, 6, 8, 8, 10, 8, 10, 10, 12, 8, 10, 10, 12, 10, 12, |
11044 | | 12, 14, 4, 6, 6, 8, 6, 8, 8, 10, 6, 8, 8, 10, 8, 10, 10, 12, 6, |
11045 | | 8, 8, 10, 8, 10, 10, 12, 8, 10, 10, 12, 10, 12, 12, 14, 6, 8, 8, 10, |
11046 | | 8, 10, 10, 12, 8, 10, 10, 12, 10, 12, 12, 14, 8, 10, 10, 12, 10, 12, 12, |
11047 | | 14, 10, 12, 12, 14, 12, 14, 14, 16}; |
11048 | | |
11049 | | constexpr uint8_t to_base64_value[] = { |
11050 | | 255, 255, 255, 255, 255, 255, 255, 255, 255, 64, 64, 255, 64, 64, 255, |
11051 | | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, |
11052 | | 255, 255, 64, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 62, 255, |
11053 | | 255, 255, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, |
11054 | | 255, 255, 255, 255, 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, |
11055 | | 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, |
11056 | | 25, 255, 255, 255, 255, 255, 255, 26, 27, 28, 29, 30, 31, 32, 33, |
11057 | | 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, |
11058 | | 49, 50, 51, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, |
11059 | | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, |
11060 | | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, |
11061 | | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, |
11062 | | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, |
11063 | | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, |
11064 | | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, |
11065 | | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, |
11066 | | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, |
11067 | | 255}; |
11068 | | |
11069 | | constexpr uint8_t to_base64_url_value[] = { |
11070 | | 255, 255, 255, 255, 255, 255, 255, 255, 255, 64, 64, 255, 64, 64, 255, |
11071 | | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, |
11072 | | 255, 255, 64, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, |
11073 | | 62, 255, 255, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, |
11074 | | 255, 255, 255, 255, 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, |
11075 | | 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, |
11076 | | 25, 255, 255, 255, 255, 63, 255, 26, 27, 28, 29, 30, 31, 32, 33, |
11077 | | 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, |
11078 | | 49, 50, 51, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, |
11079 | | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, |
11080 | | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, |
11081 | | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, |
11082 | | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, |
11083 | | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, |
11084 | | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, |
11085 | | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, |
11086 | | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, |
11087 | | 255}; |
11088 | | |
11089 | | constexpr uint8_t to_base64_default_or_url_value[] = { |
11090 | | 255, 255, 255, 255, 255, 255, 255, 255, 255, 64, 64, 255, 64, 64, 255, |
11091 | | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, |
11092 | | 255, 255, 64, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 62, 255, |
11093 | | 62, 255, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, |
11094 | | 255, 255, 255, 255, 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, |
11095 | | 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, |
11096 | | 25, 255, 255, 255, 255, 63, 255, 26, 27, 28, 29, 30, 31, 32, 33, |
11097 | | 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, |
11098 | | 49, 50, 51, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, |
11099 | | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, |
11100 | | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, |
11101 | | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, |
11102 | | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, |
11103 | | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, |
11104 | | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, |
11105 | | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, |
11106 | | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, |
11107 | | 255}; |
11108 | | |
11109 | | static_assert(sizeof(to_base64_value) == 256, |
11110 | | "to_base64_value must have 256 elements"); |
11111 | | static_assert(sizeof(to_base64_url_value) == 256, |
11112 | | "to_base64_url_value must have 256 elements"); |
11113 | | static_assert(to_base64_value[uint8_t(' ')] == 64, |
11114 | | "space must be == 64 in to_base64_value"); |
11115 | | static_assert(to_base64_url_value[uint8_t(' ')] == 64, |
11116 | | "space must be == 64 in to_base64_url_value"); |
11117 | | static_assert(to_base64_value[uint8_t('\t')] == 64, |
11118 | | "tab must be == 64 in to_base64_value"); |
11119 | | static_assert(to_base64_url_value[uint8_t('\t')] == 64, |
11120 | | "tab must be == 64 in to_base64_url_value"); |
11121 | | static_assert(to_base64_value[uint8_t('\r')] == 64, |
11122 | | "cr must be == 64 in to_base64_value"); |
11123 | | static_assert(to_base64_url_value[uint8_t('\r')] == 64, |
11124 | | "cr must be == 64 in to_base64_url_value"); |
11125 | | static_assert(to_base64_value[uint8_t('\n')] == 64, |
11126 | | "lf must be == 64 in to_base64_value"); |
11127 | | static_assert(to_base64_url_value[uint8_t('\n')] == 64, |
11128 | | "lf must be == 64 in to_base64_url_value"); |
11129 | | static_assert(to_base64_value[uint8_t('\f')] == 64, |
11130 | | "ff must be == 64 in to_base64_value"); |
11131 | | static_assert(to_base64_url_value[uint8_t('\f')] == 64, |
11132 | | "ff must be == 64 in to_base64_url_value"); |
11133 | | static_assert(to_base64_value[uint8_t('+')] == 62, |
11134 | | "+ must be == 62 in to_base64_value"); |
11135 | | static_assert(to_base64_url_value[uint8_t('-')] == 62, |
11136 | | "- must be == 62 in to_base64_url_value"); |
11137 | | static_assert(to_base64_value[uint8_t('/')] == 63, |
11138 | | "/ must be == 63 in to_base64_value"); |
11139 | | static_assert(to_base64_url_value[uint8_t('_')] == 63, |
11140 | | "_ must be == 63 in to_base64_url_value"); |
11141 | | } // namespace base64 |
11142 | | } // namespace tables |
11143 | | } // unnamed namespace |
11144 | | } // namespace simdutf |
11145 | | |
11146 | | #endif // SIMDUTF_BASE64_TABLES_H |
11147 | | /* end file include/simdutf/base64_tables.h */ |
11148 | | /* begin file include/simdutf/scalar/base64.h */ |
11149 | | #ifndef SIMDUTF_BASE64_H |
11150 | | #define SIMDUTF_BASE64_H |
11151 | | |
11152 | | #include <cstddef> |
11153 | | #include <cstdint> |
11154 | | #include <cstring> |
11155 | | |
11156 | | namespace simdutf { |
11157 | | namespace scalar { |
11158 | | namespace { |
11159 | | namespace base64 { |
11160 | | |
11161 | | // This function is not expected to be fast. Do not use in long loops. |
11162 | | // In most instances you should be using is_ignorable. |
11163 | | template <class char_type> bool is_ascii_white_space(char_type c) { |
11164 | | return c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\f'; |
11165 | | } |
11166 | | |
11167 | 344k | template <class char_type> simdutf_constexpr23 bool is_eight_byte(char_type c) { |
11168 | 344k | if constexpr (sizeof(char_type) == 1) { |
11169 | 344k | return true; |
11170 | 344k | } |
11171 | 0 | return uint8_t(c) == c; |
11172 | 344k | } Unexecuted instantiation: parser.cpp:bool simdutf::scalar::(anonymous namespace)::base64::is_eight_byte<char>(char) Unexecuted instantiation: parser.cpp:bool simdutf::scalar::(anonymous namespace)::base64::is_eight_byte<char16_t>(char16_t) Unexecuted instantiation: base64.cpp:bool simdutf::scalar::(anonymous namespace)::base64::is_eight_byte<char>(char) Unexecuted instantiation: base64.cpp:bool simdutf::scalar::(anonymous namespace)::base64::is_eight_byte<char16_t>(char16_t) simdutf.cpp:bool simdutf::scalar::(anonymous namespace)::base64::is_eight_byte<char>(char) Line | Count | Source | 11167 | 344k | template <class char_type> simdutf_constexpr23 bool is_eight_byte(char_type c) { | 11168 | 344k | if constexpr (sizeof(char_type) == 1) { | 11169 | 344k | return true; | 11170 | 344k | } | 11171 | 0 | return uint8_t(c) == c; | 11172 | 344k | } |
Unexecuted instantiation: simdutf.cpp:bool simdutf::scalar::(anonymous namespace)::base64::is_eight_byte<char16_t>(char16_t) |
11173 | | |
11174 | | template <class char_type> |
11175 | | simdutf_constexpr23 bool is_ignorable(char_type c, |
11176 | 0 | simdutf::base64_options options) { |
11177 | 0 | const uint8_t *to_base64 = |
11178 | 0 | (options & base64_default_or_url) |
11179 | 0 | ? tables::base64::to_base64_default_or_url_value |
11180 | 0 | : ((options & base64_url) ? tables::base64::to_base64_url_value |
11181 | 0 | : tables::base64::to_base64_value); |
11182 | 0 | const bool ignore_garbage = |
11183 | 0 | (options == base64_options::base64_url_accept_garbage) || |
11184 | 0 | (options == base64_options::base64_default_accept_garbage) || |
11185 | 0 | (options == base64_options::base64_default_or_url_accept_garbage); |
11186 | 0 | uint8_t code = to_base64[uint8_t(c)]; |
11187 | 0 | if (is_eight_byte(c) && code <= 63) { |
11188 | 0 | return false; |
11189 | 0 | } |
11190 | 0 | if (is_eight_byte(c) && code == 64) { |
11191 | 0 | return true; |
11192 | 0 | } |
11193 | 0 | return ignore_garbage; |
11194 | 0 | } Unexecuted instantiation: parser.cpp:bool simdutf::scalar::(anonymous namespace)::base64::is_ignorable<char>(char, simdutf::base64_options) Unexecuted instantiation: parser.cpp:bool simdutf::scalar::(anonymous namespace)::base64::is_ignorable<char16_t>(char16_t, simdutf::base64_options) Unexecuted instantiation: base64.cpp:bool simdutf::scalar::(anonymous namespace)::base64::is_ignorable<char>(char, simdutf::base64_options) Unexecuted instantiation: base64.cpp:bool simdutf::scalar::(anonymous namespace)::base64::is_ignorable<char16_t>(char16_t, simdutf::base64_options) Unexecuted instantiation: simdutf.cpp:bool simdutf::scalar::(anonymous namespace)::base64::is_ignorable<char>(char, simdutf::base64_options) Unexecuted instantiation: simdutf.cpp:bool simdutf::scalar::(anonymous namespace)::base64::is_ignorable<char16_t>(char16_t, simdutf::base64_options) |
11195 | | template <class char_type> |
11196 | | simdutf_constexpr23 bool is_base64(char_type c, |
11197 | 0 | simdutf::base64_options options) { |
11198 | 0 | const uint8_t *to_base64 = |
11199 | 0 | (options & base64_default_or_url) |
11200 | 0 | ? tables::base64::to_base64_default_or_url_value |
11201 | 0 | : ((options & base64_url) ? tables::base64::to_base64_url_value |
11202 | 0 | : tables::base64::to_base64_value); |
11203 | 0 | uint8_t code = to_base64[uint8_t(c)]; |
11204 | 0 | if (is_eight_byte(c) && code <= 63) { |
11205 | 0 | return true; |
11206 | 0 | } |
11207 | 0 | return false; |
11208 | 0 | } Unexecuted instantiation: parser.cpp:bool simdutf::scalar::(anonymous namespace)::base64::is_base64<char>(char, simdutf::base64_options) Unexecuted instantiation: parser.cpp:bool simdutf::scalar::(anonymous namespace)::base64::is_base64<char16_t>(char16_t, simdutf::base64_options) Unexecuted instantiation: base64.cpp:bool simdutf::scalar::(anonymous namespace)::base64::is_base64<char>(char, simdutf::base64_options) Unexecuted instantiation: base64.cpp:bool simdutf::scalar::(anonymous namespace)::base64::is_base64<char16_t>(char16_t, simdutf::base64_options) Unexecuted instantiation: simdutf.cpp:bool simdutf::scalar::(anonymous namespace)::base64::is_base64<char>(char, simdutf::base64_options) Unexecuted instantiation: simdutf.cpp:bool simdutf::scalar::(anonymous namespace)::base64::is_base64<char16_t>(char16_t, simdutf::base64_options) |
11209 | | |
11210 | | template <class char_type> |
11211 | | simdutf_constexpr23 bool is_base64_or_padding(char_type c, |
11212 | 0 | simdutf::base64_options options) { |
11213 | 0 | const uint8_t *to_base64 = |
11214 | 0 | (options & base64_default_or_url) |
11215 | 0 | ? tables::base64::to_base64_default_or_url_value |
11216 | 0 | : ((options & base64_url) ? tables::base64::to_base64_url_value |
11217 | 0 | : tables::base64::to_base64_value); |
11218 | 0 | if (c == '=') { |
11219 | 0 | return true; |
11220 | 0 | } |
11221 | 0 | uint8_t code = to_base64[uint8_t(c)]; |
11222 | 0 | if (is_eight_byte(c) && code <= 63) { |
11223 | 0 | return true; |
11224 | 0 | } |
11225 | 0 | return false; |
11226 | 0 | } Unexecuted instantiation: parser.cpp:bool simdutf::scalar::(anonymous namespace)::base64::is_base64_or_padding<char>(char, simdutf::base64_options) Unexecuted instantiation: parser.cpp:bool simdutf::scalar::(anonymous namespace)::base64::is_base64_or_padding<char16_t>(char16_t, simdutf::base64_options) Unexecuted instantiation: base64.cpp:bool simdutf::scalar::(anonymous namespace)::base64::is_base64_or_padding<char>(char, simdutf::base64_options) Unexecuted instantiation: base64.cpp:bool simdutf::scalar::(anonymous namespace)::base64::is_base64_or_padding<char16_t>(char16_t, simdutf::base64_options) Unexecuted instantiation: simdutf.cpp:bool simdutf::scalar::(anonymous namespace)::base64::is_base64_or_padding<char>(char, simdutf::base64_options) Unexecuted instantiation: simdutf.cpp:bool simdutf::scalar::(anonymous namespace)::base64::is_base64_or_padding<char16_t>(char16_t, simdutf::base64_options) |
11227 | | |
11228 | | template <class char_type> |
11229 | | bool is_ignorable_or_padding(char_type c, simdutf::base64_options options) { |
11230 | | return is_ignorable(c, options) || c == '='; |
11231 | | } |
11232 | | |
11233 | | struct reduced_input { |
11234 | | size_t equalsigns; // number of padding characters '=', typically 0, 1, 2. |
11235 | | size_t equallocation; // location of the first padding character if any |
11236 | | size_t srclen; // length of the input buffer before padding |
11237 | | size_t full_input_length; // length of the input buffer with padding but |
11238 | | // without ignorable characters |
11239 | | }; |
11240 | | |
11241 | | // find the end of the base64 input buffer |
11242 | | // It returns the number of padding characters, the location of the first |
11243 | | // padding character if any, the length of the input buffer before padding |
11244 | | // and the length of the input buffer with padding. The input buffer is not |
11245 | | // modified. The function assumes that there are at most two padding characters. |
11246 | | template <class char_type> |
11247 | | simdutf_constexpr23 reduced_input find_end(const char_type *src, size_t srclen, |
11248 | 22.7k | simdutf::base64_options options) { |
11249 | 22.7k | const uint8_t *to_base64 = |
11250 | 22.7k | (options & base64_default_or_url) |
11251 | 22.7k | ? tables::base64::to_base64_default_or_url_value |
11252 | 22.7k | : ((options & base64_url) ? tables::base64::to_base64_url_value |
11253 | 22.7k | : tables::base64::to_base64_value); |
11254 | 22.7k | const bool ignore_garbage = |
11255 | 22.7k | (options == base64_options::base64_url_accept_garbage) || |
11256 | 22.7k | (options == base64_options::base64_default_accept_garbage) || |
11257 | 22.7k | (options == base64_options::base64_default_or_url_accept_garbage); |
11258 | | |
11259 | 22.7k | size_t equalsigns = 0; |
11260 | | // We intentionally include trailing spaces in the full input length. |
11261 | | // See https://github.com/simdutf/simdutf/issues/824 |
11262 | 22.7k | size_t full_input_length = srclen; |
11263 | | // skip trailing spaces |
11264 | 25.0k | while (!ignore_garbage && srclen > 0 && |
11265 | 25.0k | scalar::base64::is_eight_byte(src[srclen - 1]) && |
11266 | 25.0k | to_base64[uint8_t(src[srclen - 1])] == 64) { |
11267 | 2.31k | srclen--; |
11268 | 2.31k | } |
11269 | 22.7k | size_t equallocation = |
11270 | 22.7k | srclen; // location of the first padding character if any |
11271 | 22.7k | if (ignore_garbage) { |
11272 | | // Technically, we don't need to find the first padding character, we can |
11273 | | // just change our algorithms, but it adds substantial complexity. |
11274 | 0 | auto it = simdutf::find(src, src + srclen, '='); |
11275 | 0 | if (it != src + srclen) { |
11276 | 0 | equallocation = it - src; |
11277 | 0 | equalsigns = 1; |
11278 | 0 | srclen = equallocation; |
11279 | 0 | full_input_length = equallocation + 1; |
11280 | 0 | } |
11281 | 0 | return {equalsigns, equallocation, srclen, full_input_length}; |
11282 | 0 | } |
11283 | 22.7k | if (!ignore_garbage && srclen > 0 && src[srclen - 1] == '=') { |
11284 | | // This is the last '=' sign. |
11285 | 2.56k | equallocation = srclen - 1; |
11286 | 2.56k | srclen--; |
11287 | 2.56k | equalsigns = 1; |
11288 | | // skip trailing spaces |
11289 | 3.00k | while (srclen > 0 && scalar::base64::is_eight_byte(src[srclen - 1]) && |
11290 | 3.00k | to_base64[uint8_t(src[srclen - 1])] == 64) { |
11291 | 440 | srclen--; |
11292 | 440 | } |
11293 | 2.56k | if (srclen > 0 && src[srclen - 1] == '=') { |
11294 | | // This is the second '=' sign. |
11295 | 283 | equallocation = srclen - 1; |
11296 | 283 | srclen--; |
11297 | 283 | equalsigns = 2; |
11298 | 283 | } |
11299 | 2.56k | } |
11300 | 22.7k | return {equalsigns, equallocation, srclen, full_input_length}; |
11301 | 22.7k | } simdutf.cpp:simdutf::scalar::(anonymous namespace)::base64::reduced_input simdutf::scalar::(anonymous namespace)::base64::find_end<char>(char const*, unsigned long, simdutf::base64_options) Line | Count | Source | 11248 | 22.7k | simdutf::base64_options options) { | 11249 | 22.7k | const uint8_t *to_base64 = | 11250 | 22.7k | (options & base64_default_or_url) | 11251 | 22.7k | ? tables::base64::to_base64_default_or_url_value | 11252 | 22.7k | : ((options & base64_url) ? tables::base64::to_base64_url_value | 11253 | 22.7k | : tables::base64::to_base64_value); | 11254 | 22.7k | const bool ignore_garbage = | 11255 | 22.7k | (options == base64_options::base64_url_accept_garbage) || | 11256 | 22.7k | (options == base64_options::base64_default_accept_garbage) || | 11257 | 22.7k | (options == base64_options::base64_default_or_url_accept_garbage); | 11258 | | | 11259 | 22.7k | size_t equalsigns = 0; | 11260 | | // We intentionally include trailing spaces in the full input length. | 11261 | | // See https://github.com/simdutf/simdutf/issues/824 | 11262 | 22.7k | size_t full_input_length = srclen; | 11263 | | // skip trailing spaces | 11264 | 25.0k | while (!ignore_garbage && srclen > 0 && | 11265 | 25.0k | scalar::base64::is_eight_byte(src[srclen - 1]) && | 11266 | 25.0k | to_base64[uint8_t(src[srclen - 1])] == 64) { | 11267 | 2.31k | srclen--; | 11268 | 2.31k | } | 11269 | 22.7k | size_t equallocation = | 11270 | 22.7k | srclen; // location of the first padding character if any | 11271 | 22.7k | if (ignore_garbage) { | 11272 | | // Technically, we don't need to find the first padding character, we can | 11273 | | // just change our algorithms, but it adds substantial complexity. | 11274 | 0 | auto it = simdutf::find(src, src + srclen, '='); | 11275 | 0 | if (it != src + srclen) { | 11276 | 0 | equallocation = it - src; | 11277 | 0 | equalsigns = 1; | 11278 | 0 | srclen = equallocation; | 11279 | 0 | full_input_length = equallocation + 1; | 11280 | 0 | } | 11281 | 0 | return {equalsigns, equallocation, srclen, full_input_length}; | 11282 | 0 | } | 11283 | 22.7k | if (!ignore_garbage && srclen > 0 && src[srclen - 1] == '=') { | 11284 | | // This is the last '=' sign. | 11285 | 2.56k | equallocation = srclen - 1; | 11286 | 2.56k | srclen--; | 11287 | 2.56k | equalsigns = 1; | 11288 | | // skip trailing spaces | 11289 | 3.00k | while (srclen > 0 && scalar::base64::is_eight_byte(src[srclen - 1]) && | 11290 | 3.00k | to_base64[uint8_t(src[srclen - 1])] == 64) { | 11291 | 440 | srclen--; | 11292 | 440 | } | 11293 | 2.56k | if (srclen > 0 && src[srclen - 1] == '=') { | 11294 | | // This is the second '=' sign. | 11295 | 283 | equallocation = srclen - 1; | 11296 | 283 | srclen--; | 11297 | 283 | equalsigns = 2; | 11298 | 283 | } | 11299 | 2.56k | } | 11300 | 22.7k | return {equalsigns, equallocation, srclen, full_input_length}; | 11301 | 22.7k | } |
Unexecuted instantiation: simdutf.cpp:simdutf::scalar::(anonymous namespace)::base64::reduced_input simdutf::scalar::(anonymous namespace)::base64::find_end<char16_t>(char16_t const*, unsigned long, simdutf::base64_options) |
11302 | | |
11303 | | // Returns true upon success. The destination buffer must be large enough. |
11304 | | // This functions assumes that the padding (=) has been removed. |
11305 | | // if check_capacity is true, it will check that the destination buffer is |
11306 | | // large enough. If it is not, it will return OUTPUT_BUFFER_TOO_SMALL. |
11307 | | template <bool check_capacity, class char_type> |
11308 | | simdutf_constexpr23 full_result base64_tail_decode_impl( |
11309 | | char *dst, size_t outlen, const char_type *src, size_t length, |
11310 | | size_t padding_characters, // number of padding characters |
11311 | | // '=', typically 0, 1, 2. |
11312 | 21.8k | base64_options options, last_chunk_handling_options last_chunk_options) { |
11313 | 21.8k | char *dstend = dst + outlen; |
11314 | 21.8k | (void)dstend; |
11315 | | // This looks like 10 branches, but we expect the compiler to resolve this to |
11316 | | // two branches (easily predicted): |
11317 | 21.8k | const uint8_t *to_base64 = |
11318 | 21.8k | (options & base64_default_or_url) |
11319 | 21.8k | ? tables::base64::to_base64_default_or_url_value |
11320 | 21.8k | : ((options & base64_url) ? tables::base64::to_base64_url_value |
11321 | 21.8k | : tables::base64::to_base64_value); |
11322 | 21.8k | const uint32_t *d0 = |
11323 | 21.8k | (options & base64_default_or_url) |
11324 | 21.8k | ? tables::base64::base64_default_or_url::d0 |
11325 | 21.8k | : ((options & base64_url) ? tables::base64::base64_url::d0 |
11326 | 21.8k | : tables::base64::base64_default::d0); |
11327 | 21.8k | const uint32_t *d1 = |
11328 | 21.8k | (options & base64_default_or_url) |
11329 | 21.8k | ? tables::base64::base64_default_or_url::d1 |
11330 | 21.8k | : ((options & base64_url) ? tables::base64::base64_url::d1 |
11331 | 21.8k | : tables::base64::base64_default::d1); |
11332 | 21.8k | const uint32_t *d2 = |
11333 | 21.8k | (options & base64_default_or_url) |
11334 | 21.8k | ? tables::base64::base64_default_or_url::d2 |
11335 | 21.8k | : ((options & base64_url) ? tables::base64::base64_url::d2 |
11336 | 21.8k | : tables::base64::base64_default::d2); |
11337 | 21.8k | const uint32_t *d3 = |
11338 | 21.8k | (options & base64_default_or_url) |
11339 | 21.8k | ? tables::base64::base64_default_or_url::d3 |
11340 | 21.8k | : ((options & base64_url) ? tables::base64::base64_url::d3 |
11341 | 21.8k | : tables::base64::base64_default::d3); |
11342 | 21.8k | const bool ignore_garbage = |
11343 | 21.8k | (options == base64_options::base64_url_accept_garbage) || |
11344 | 21.8k | (options == base64_options::base64_default_accept_garbage) || |
11345 | 21.8k | (options == base64_options::base64_default_or_url_accept_garbage); |
11346 | | |
11347 | 21.8k | const char_type *srcend = src + length; |
11348 | 21.8k | const char_type *srcinit = src; |
11349 | 21.8k | const char *dstinit = dst; |
11350 | | |
11351 | 21.8k | uint32_t x; |
11352 | 21.8k | size_t idx; |
11353 | 21.8k | uint8_t buffer[4]; |
11354 | 21.9k | while (true) { |
11355 | 97.2k | while (srcend - src >= 4 && is_eight_byte(src[0]) && |
11356 | 75.5k | is_eight_byte(src[1]) && is_eight_byte(src[2]) && |
11357 | 75.5k | is_eight_byte(src[3]) && |
11358 | 75.5k | (x = d0[uint8_t(src[0])] | d1[uint8_t(src[1])] | |
11359 | 75.5k | d2[uint8_t(src[2])] | d3[uint8_t(src[3])]) < 0x01FFFFFF) { |
11360 | 75.3k | if (check_capacity && dstend - dst < 3) { |
11361 | 0 | return {OUTPUT_BUFFER_TOO_SMALL, size_t(src - srcinit), |
11362 | 0 | size_t(dst - dstinit)}; |
11363 | 0 | } |
11364 | 75.3k | *dst++ = static_cast<char>(x & 0xFF); |
11365 | 75.3k | *dst++ = static_cast<char>((x >> 8) & 0xFF); |
11366 | 75.3k | *dst++ = static_cast<char>((x >> 16) & 0xFF); |
11367 | 75.3k | src += 4; |
11368 | 75.3k | } |
11369 | 21.9k | const char_type *srccur = src; |
11370 | 21.9k | idx = 0; |
11371 | | // we need at least four characters. |
11372 | 21.9k | #ifdef __clang__ |
11373 | | // If possible, we read four characters at a time. (It is an optimization.) |
11374 | 21.9k | if (ignore_garbage && src + 4 <= srcend) { |
11375 | 0 | char_type c0 = src[0]; |
11376 | 0 | char_type c1 = src[1]; |
11377 | 0 | char_type c2 = src[2]; |
11378 | 0 | char_type c3 = src[3]; |
11379 | |
|
11380 | 0 | uint8_t code0 = to_base64[uint8_t(c0)]; |
11381 | 0 | uint8_t code1 = to_base64[uint8_t(c1)]; |
11382 | 0 | uint8_t code2 = to_base64[uint8_t(c2)]; |
11383 | 0 | uint8_t code3 = to_base64[uint8_t(c3)]; |
11384 | |
|
11385 | 0 | buffer[idx] = code0; |
11386 | 0 | idx += (is_eight_byte(c0) && code0 <= 63); |
11387 | 0 | buffer[idx] = code1; |
11388 | 0 | idx += (is_eight_byte(c1) && code1 <= 63); |
11389 | 0 | buffer[idx] = code2; |
11390 | 0 | idx += (is_eight_byte(c2) && code2 <= 63); |
11391 | 0 | buffer[idx] = code3; |
11392 | 0 | idx += (is_eight_byte(c3) && code3 <= 63); |
11393 | 0 | src += 4; |
11394 | 0 | } |
11395 | 21.9k | #endif |
11396 | 32.5k | while ((idx < 4) && (src < srcend)) { |
11397 | 10.6k | char_type c = *src; |
11398 | | |
11399 | 10.6k | uint8_t code = to_base64[uint8_t(c)]; |
11400 | 10.6k | buffer[idx] = uint8_t(code); |
11401 | 10.6k | if (is_eight_byte(c) && code <= 63) { |
11402 | 7.85k | idx++; |
11403 | 7.85k | } else if (!ignore_garbage && |
11404 | 2.83k | (code > 64 || !scalar::base64::is_eight_byte(c))) { |
11405 | 101 | return {INVALID_BASE64_CHARACTER, size_t(src - srcinit), |
11406 | 101 | size_t(dst - dstinit)}; |
11407 | 2.73k | } else { |
11408 | | // We have a space or a newline or garbage. We ignore it. |
11409 | 2.73k | } |
11410 | 10.5k | src++; |
11411 | 10.5k | } |
11412 | 21.8k | if (idx != 4) { |
11413 | 21.7k | simdutf_log_assert(idx < 4, "idx should be less than 4"); |
11414 | | // We never should have that the number of base64 characters + the |
11415 | | // number of padding characters is more than 4. |
11416 | 21.7k | if (!ignore_garbage && (idx + padding_characters > 4)) { |
11417 | 1 | return {INVALID_BASE64_CHARACTER, size_t(src - srcinit), |
11418 | 1 | size_t(dst - dstinit), true}; |
11419 | 1 | } |
11420 | | |
11421 | | // The idea here is that in loose mode, |
11422 | | // if there is padding at all, it must be used |
11423 | | // to form 4-wise chunk. However, in loose mode, |
11424 | | // we do accept no padding at all. |
11425 | 21.7k | if (!ignore_garbage && |
11426 | 21.7k | last_chunk_options == last_chunk_handling_options::loose && |
11427 | 21.7k | (idx >= 2) && padding_characters > 0 && |
11428 | 2.46k | ((idx + padding_characters) & 3) != 0) { |
11429 | 12 | return {INVALID_BASE64_CHARACTER, size_t(src - srcinit), |
11430 | 12 | size_t(dst - dstinit), true}; |
11431 | 12 | } else |
11432 | | |
11433 | | // The idea here is that in strict mode, we do not want to accept |
11434 | | // incomplete base64 chunks. So if the chunk was otherwise valid, we |
11435 | | // return BASE64_INPUT_REMAINDER. |
11436 | 21.7k | if (!ignore_garbage && |
11437 | 21.7k | last_chunk_options == last_chunk_handling_options::strict && |
11438 | 0 | (idx >= 2) && ((idx + padding_characters) & 3) != 0) { |
11439 | | // The partial chunk was at src - idx |
11440 | 0 | return {BASE64_INPUT_REMAINDER, size_t(src - srcinit), |
11441 | 0 | size_t(dst - dstinit), true}; |
11442 | 0 | } else |
11443 | | // If there is a partial chunk with insufficient padding, with |
11444 | | // stop_before_partial, we need to just ignore it. In "only full" |
11445 | | // mode, skip the minute there are padding characters. |
11446 | 21.7k | if ((last_chunk_options == |
11447 | 21.7k | last_chunk_handling_options::stop_before_partial && |
11448 | 0 | (padding_characters + idx < 4) && (idx != 0) && |
11449 | 0 | (idx >= 2 || padding_characters == 0)) || |
11450 | 21.7k | (last_chunk_options == |
11451 | 21.7k | last_chunk_handling_options::only_full_chunks && |
11452 | 0 | (idx >= 2 || padding_characters == 0))) { |
11453 | | // partial means that we are *not* going to consume the read |
11454 | | // characters. We need to rewind the src pointer. |
11455 | 0 | src = srccur; |
11456 | 0 | return {SUCCESS, size_t(src - srcinit), size_t(dst - dstinit)}; |
11457 | 21.7k | } else { |
11458 | 21.7k | if (idx == 2) { |
11459 | 308 | uint32_t triple = (uint32_t(buffer[0]) << 3 * 6) + |
11460 | 308 | (uint32_t(buffer[1]) << 2 * 6); |
11461 | 308 | if (!ignore_garbage && |
11462 | 308 | (last_chunk_options == last_chunk_handling_options::strict) && |
11463 | 0 | (triple & 0xffff)) { |
11464 | 0 | return {BASE64_EXTRA_BITS, size_t(src - srcinit), |
11465 | 0 | size_t(dst - dstinit)}; |
11466 | 0 | } |
11467 | 308 | if (check_capacity && dstend - dst < 1) { |
11468 | 0 | return {OUTPUT_BUFFER_TOO_SMALL, size_t(srccur - srcinit), |
11469 | 0 | size_t(dst - dstinit)}; |
11470 | 0 | } |
11471 | 308 | *dst++ = static_cast<char>((triple >> 16) & 0xFF); |
11472 | 21.4k | } else if (idx == 3) { |
11473 | 2.20k | uint32_t triple = (uint32_t(buffer[0]) << 3 * 6) + |
11474 | 2.20k | (uint32_t(buffer[1]) << 2 * 6) + |
11475 | 2.20k | (uint32_t(buffer[2]) << 1 * 6); |
11476 | 2.20k | if (!ignore_garbage && |
11477 | 2.20k | (last_chunk_options == last_chunk_handling_options::strict) && |
11478 | 0 | (triple & 0xff)) { |
11479 | 0 | return {BASE64_EXTRA_BITS, size_t(src - srcinit), |
11480 | 0 | size_t(dst - dstinit)}; |
11481 | 0 | } |
11482 | 2.20k | if (check_capacity && dstend - dst < 2) { |
11483 | 0 | return {OUTPUT_BUFFER_TOO_SMALL, size_t(srccur - srcinit), |
11484 | 0 | size_t(dst - dstinit)}; |
11485 | 0 | } |
11486 | 2.20k | *dst++ = static_cast<char>((triple >> 16) & 0xFF); |
11487 | 2.20k | *dst++ = static_cast<char>((triple >> 8) & 0xFF); |
11488 | 19.2k | } else if (!ignore_garbage && idx == 1 && |
11489 | 38 | (!is_partial(last_chunk_options) || |
11490 | 0 | (is_partial(last_chunk_options) && |
11491 | 38 | padding_characters > 0))) { |
11492 | 38 | return {BASE64_INPUT_REMAINDER, size_t(src - srcinit), |
11493 | 38 | size_t(dst - dstinit)}; |
11494 | 19.1k | } else if (!ignore_garbage && idx == 0 && padding_characters > 0) { |
11495 | 21 | return {INVALID_BASE64_CHARACTER, size_t(src - srcinit), |
11496 | 21 | size_t(dst - dstinit), true}; |
11497 | 21 | } |
11498 | 21.6k | return {SUCCESS, size_t(src - srcinit), size_t(dst - dstinit)}; |
11499 | 21.7k | } |
11500 | 21.7k | } |
11501 | 109 | if (check_capacity && dstend - dst < 3) { |
11502 | 0 | return {OUTPUT_BUFFER_TOO_SMALL, size_t(srccur - srcinit), |
11503 | 0 | size_t(dst - dstinit)}; |
11504 | 0 | } |
11505 | 109 | uint32_t triple = |
11506 | 109 | (uint32_t(buffer[0]) << 3 * 6) + (uint32_t(buffer[1]) << 2 * 6) + |
11507 | 109 | (uint32_t(buffer[2]) << 1 * 6) + (uint32_t(buffer[3]) << 0 * 6); |
11508 | 109 | *dst++ = static_cast<char>((triple >> 16) & 0xFF); |
11509 | 109 | *dst++ = static_cast<char>((triple >> 8) & 0xFF); |
11510 | 109 | *dst++ = static_cast<char>(triple & 0xFF); |
11511 | 109 | } |
11512 | 21.8k | } Unexecuted instantiation: simdutf.cpp:simdutf::full_result simdutf::scalar::(anonymous namespace)::base64::base64_tail_decode_impl<true, char>(char*, unsigned long, char const*, unsigned long, unsigned long, simdutf::base64_options, simdutf::last_chunk_handling_options) Unexecuted instantiation: simdutf.cpp:simdutf::full_result simdutf::scalar::(anonymous namespace)::base64::base64_tail_decode_impl<true, char16_t>(char*, unsigned long, char16_t const*, unsigned long, unsigned long, simdutf::base64_options, simdutf::last_chunk_handling_options) simdutf.cpp:simdutf::full_result simdutf::scalar::(anonymous namespace)::base64::base64_tail_decode_impl<false, char>(char*, unsigned long, char const*, unsigned long, unsigned long, simdutf::base64_options, simdutf::last_chunk_handling_options) Line | Count | Source | 11312 | 21.8k | base64_options options, last_chunk_handling_options last_chunk_options) { | 11313 | 21.8k | char *dstend = dst + outlen; | 11314 | 21.8k | (void)dstend; | 11315 | | // This looks like 10 branches, but we expect the compiler to resolve this to | 11316 | | // two branches (easily predicted): | 11317 | 21.8k | const uint8_t *to_base64 = | 11318 | 21.8k | (options & base64_default_or_url) | 11319 | 21.8k | ? tables::base64::to_base64_default_or_url_value | 11320 | 21.8k | : ((options & base64_url) ? tables::base64::to_base64_url_value | 11321 | 21.8k | : tables::base64::to_base64_value); | 11322 | 21.8k | const uint32_t *d0 = | 11323 | 21.8k | (options & base64_default_or_url) | 11324 | 21.8k | ? tables::base64::base64_default_or_url::d0 | 11325 | 21.8k | : ((options & base64_url) ? tables::base64::base64_url::d0 | 11326 | 21.8k | : tables::base64::base64_default::d0); | 11327 | 21.8k | const uint32_t *d1 = | 11328 | 21.8k | (options & base64_default_or_url) | 11329 | 21.8k | ? tables::base64::base64_default_or_url::d1 | 11330 | 21.8k | : ((options & base64_url) ? tables::base64::base64_url::d1 | 11331 | 21.8k | : tables::base64::base64_default::d1); | 11332 | 21.8k | const uint32_t *d2 = | 11333 | 21.8k | (options & base64_default_or_url) | 11334 | 21.8k | ? tables::base64::base64_default_or_url::d2 | 11335 | 21.8k | : ((options & base64_url) ? tables::base64::base64_url::d2 | 11336 | 21.8k | : tables::base64::base64_default::d2); | 11337 | 21.8k | const uint32_t *d3 = | 11338 | 21.8k | (options & base64_default_or_url) | 11339 | 21.8k | ? tables::base64::base64_default_or_url::d3 | 11340 | 21.8k | : ((options & base64_url) ? tables::base64::base64_url::d3 | 11341 | 21.8k | : tables::base64::base64_default::d3); | 11342 | 21.8k | const bool ignore_garbage = | 11343 | 21.8k | (options == base64_options::base64_url_accept_garbage) || | 11344 | 21.8k | (options == base64_options::base64_default_accept_garbage) || | 11345 | 21.8k | (options == base64_options::base64_default_or_url_accept_garbage); | 11346 | | | 11347 | 21.8k | const char_type *srcend = src + length; | 11348 | 21.8k | const char_type *srcinit = src; | 11349 | 21.8k | const char *dstinit = dst; | 11350 | | | 11351 | 21.8k | uint32_t x; | 11352 | 21.8k | size_t idx; | 11353 | 21.8k | uint8_t buffer[4]; | 11354 | 21.9k | while (true) { | 11355 | 97.2k | while (srcend - src >= 4 && is_eight_byte(src[0]) && | 11356 | 75.5k | is_eight_byte(src[1]) && is_eight_byte(src[2]) && | 11357 | 75.5k | is_eight_byte(src[3]) && | 11358 | 75.5k | (x = d0[uint8_t(src[0])] | d1[uint8_t(src[1])] | | 11359 | 75.5k | d2[uint8_t(src[2])] | d3[uint8_t(src[3])]) < 0x01FFFFFF) { | 11360 | 75.3k | if (check_capacity && dstend - dst < 3) { | 11361 | 0 | return {OUTPUT_BUFFER_TOO_SMALL, size_t(src - srcinit), | 11362 | 0 | size_t(dst - dstinit)}; | 11363 | 0 | } | 11364 | 75.3k | *dst++ = static_cast<char>(x & 0xFF); | 11365 | 75.3k | *dst++ = static_cast<char>((x >> 8) & 0xFF); | 11366 | 75.3k | *dst++ = static_cast<char>((x >> 16) & 0xFF); | 11367 | 75.3k | src += 4; | 11368 | 75.3k | } | 11369 | 21.9k | const char_type *srccur = src; | 11370 | 21.9k | idx = 0; | 11371 | | // we need at least four characters. | 11372 | 21.9k | #ifdef __clang__ | 11373 | | // If possible, we read four characters at a time. (It is an optimization.) | 11374 | 21.9k | if (ignore_garbage && src + 4 <= srcend) { | 11375 | 0 | char_type c0 = src[0]; | 11376 | 0 | char_type c1 = src[1]; | 11377 | 0 | char_type c2 = src[2]; | 11378 | 0 | char_type c3 = src[3]; | 11379 | |
| 11380 | 0 | uint8_t code0 = to_base64[uint8_t(c0)]; | 11381 | 0 | uint8_t code1 = to_base64[uint8_t(c1)]; | 11382 | 0 | uint8_t code2 = to_base64[uint8_t(c2)]; | 11383 | 0 | uint8_t code3 = to_base64[uint8_t(c3)]; | 11384 | |
| 11385 | 0 | buffer[idx] = code0; | 11386 | 0 | idx += (is_eight_byte(c0) && code0 <= 63); | 11387 | 0 | buffer[idx] = code1; | 11388 | 0 | idx += (is_eight_byte(c1) && code1 <= 63); | 11389 | 0 | buffer[idx] = code2; | 11390 | 0 | idx += (is_eight_byte(c2) && code2 <= 63); | 11391 | 0 | buffer[idx] = code3; | 11392 | 0 | idx += (is_eight_byte(c3) && code3 <= 63); | 11393 | 0 | src += 4; | 11394 | 0 | } | 11395 | 21.9k | #endif | 11396 | 32.5k | while ((idx < 4) && (src < srcend)) { | 11397 | 10.6k | char_type c = *src; | 11398 | | | 11399 | 10.6k | uint8_t code = to_base64[uint8_t(c)]; | 11400 | 10.6k | buffer[idx] = uint8_t(code); | 11401 | 10.6k | if (is_eight_byte(c) && code <= 63) { | 11402 | 7.85k | idx++; | 11403 | 7.85k | } else if (!ignore_garbage && | 11404 | 2.83k | (code > 64 || !scalar::base64::is_eight_byte(c))) { | 11405 | 101 | return {INVALID_BASE64_CHARACTER, size_t(src - srcinit), | 11406 | 101 | size_t(dst - dstinit)}; | 11407 | 2.73k | } else { | 11408 | | // We have a space or a newline or garbage. We ignore it. | 11409 | 2.73k | } | 11410 | 10.5k | src++; | 11411 | 10.5k | } | 11412 | 21.8k | if (idx != 4) { | 11413 | 21.7k | simdutf_log_assert(idx < 4, "idx should be less than 4"); | 11414 | | // We never should have that the number of base64 characters + the | 11415 | | // number of padding characters is more than 4. | 11416 | 21.7k | if (!ignore_garbage && (idx + padding_characters > 4)) { | 11417 | 1 | return {INVALID_BASE64_CHARACTER, size_t(src - srcinit), | 11418 | 1 | size_t(dst - dstinit), true}; | 11419 | 1 | } | 11420 | | | 11421 | | // The idea here is that in loose mode, | 11422 | | // if there is padding at all, it must be used | 11423 | | // to form 4-wise chunk. However, in loose mode, | 11424 | | // we do accept no padding at all. | 11425 | 21.7k | if (!ignore_garbage && | 11426 | 21.7k | last_chunk_options == last_chunk_handling_options::loose && | 11427 | 21.7k | (idx >= 2) && padding_characters > 0 && | 11428 | 2.46k | ((idx + padding_characters) & 3) != 0) { | 11429 | 12 | return {INVALID_BASE64_CHARACTER, size_t(src - srcinit), | 11430 | 12 | size_t(dst - dstinit), true}; | 11431 | 12 | } else | 11432 | | | 11433 | | // The idea here is that in strict mode, we do not want to accept | 11434 | | // incomplete base64 chunks. So if the chunk was otherwise valid, we | 11435 | | // return BASE64_INPUT_REMAINDER. | 11436 | 21.7k | if (!ignore_garbage && | 11437 | 21.7k | last_chunk_options == last_chunk_handling_options::strict && | 11438 | 0 | (idx >= 2) && ((idx + padding_characters) & 3) != 0) { | 11439 | | // The partial chunk was at src - idx | 11440 | 0 | return {BASE64_INPUT_REMAINDER, size_t(src - srcinit), | 11441 | 0 | size_t(dst - dstinit), true}; | 11442 | 0 | } else | 11443 | | // If there is a partial chunk with insufficient padding, with | 11444 | | // stop_before_partial, we need to just ignore it. In "only full" | 11445 | | // mode, skip the minute there are padding characters. | 11446 | 21.7k | if ((last_chunk_options == | 11447 | 21.7k | last_chunk_handling_options::stop_before_partial && | 11448 | 0 | (padding_characters + idx < 4) && (idx != 0) && | 11449 | 0 | (idx >= 2 || padding_characters == 0)) || | 11450 | 21.7k | (last_chunk_options == | 11451 | 21.7k | last_chunk_handling_options::only_full_chunks && | 11452 | 0 | (idx >= 2 || padding_characters == 0))) { | 11453 | | // partial means that we are *not* going to consume the read | 11454 | | // characters. We need to rewind the src pointer. | 11455 | 0 | src = srccur; | 11456 | 0 | return {SUCCESS, size_t(src - srcinit), size_t(dst - dstinit)}; | 11457 | 21.7k | } else { | 11458 | 21.7k | if (idx == 2) { | 11459 | 308 | uint32_t triple = (uint32_t(buffer[0]) << 3 * 6) + | 11460 | 308 | (uint32_t(buffer[1]) << 2 * 6); | 11461 | 308 | if (!ignore_garbage && | 11462 | 308 | (last_chunk_options == last_chunk_handling_options::strict) && | 11463 | 0 | (triple & 0xffff)) { | 11464 | 0 | return {BASE64_EXTRA_BITS, size_t(src - srcinit), | 11465 | 0 | size_t(dst - dstinit)}; | 11466 | 0 | } | 11467 | 308 | if (check_capacity && dstend - dst < 1) { | 11468 | 0 | return {OUTPUT_BUFFER_TOO_SMALL, size_t(srccur - srcinit), | 11469 | 0 | size_t(dst - dstinit)}; | 11470 | 0 | } | 11471 | 308 | *dst++ = static_cast<char>((triple >> 16) & 0xFF); | 11472 | 21.4k | } else if (idx == 3) { | 11473 | 2.20k | uint32_t triple = (uint32_t(buffer[0]) << 3 * 6) + | 11474 | 2.20k | (uint32_t(buffer[1]) << 2 * 6) + | 11475 | 2.20k | (uint32_t(buffer[2]) << 1 * 6); | 11476 | 2.20k | if (!ignore_garbage && | 11477 | 2.20k | (last_chunk_options == last_chunk_handling_options::strict) && | 11478 | 0 | (triple & 0xff)) { | 11479 | 0 | return {BASE64_EXTRA_BITS, size_t(src - srcinit), | 11480 | 0 | size_t(dst - dstinit)}; | 11481 | 0 | } | 11482 | 2.20k | if (check_capacity && dstend - dst < 2) { | 11483 | 0 | return {OUTPUT_BUFFER_TOO_SMALL, size_t(srccur - srcinit), | 11484 | 0 | size_t(dst - dstinit)}; | 11485 | 0 | } | 11486 | 2.20k | *dst++ = static_cast<char>((triple >> 16) & 0xFF); | 11487 | 2.20k | *dst++ = static_cast<char>((triple >> 8) & 0xFF); | 11488 | 19.2k | } else if (!ignore_garbage && idx == 1 && | 11489 | 38 | (!is_partial(last_chunk_options) || | 11490 | 0 | (is_partial(last_chunk_options) && | 11491 | 38 | padding_characters > 0))) { | 11492 | 38 | return {BASE64_INPUT_REMAINDER, size_t(src - srcinit), | 11493 | 38 | size_t(dst - dstinit)}; | 11494 | 19.1k | } else if (!ignore_garbage && idx == 0 && padding_characters > 0) { | 11495 | 21 | return {INVALID_BASE64_CHARACTER, size_t(src - srcinit), | 11496 | 21 | size_t(dst - dstinit), true}; | 11497 | 21 | } | 11498 | 21.6k | return {SUCCESS, size_t(src - srcinit), size_t(dst - dstinit)}; | 11499 | 21.7k | } | 11500 | 21.7k | } | 11501 | 109 | if (check_capacity && dstend - dst < 3) { | 11502 | 0 | return {OUTPUT_BUFFER_TOO_SMALL, size_t(srccur - srcinit), | 11503 | 0 | size_t(dst - dstinit)}; | 11504 | 0 | } | 11505 | 109 | uint32_t triple = | 11506 | 109 | (uint32_t(buffer[0]) << 3 * 6) + (uint32_t(buffer[1]) << 2 * 6) + | 11507 | 109 | (uint32_t(buffer[2]) << 1 * 6) + (uint32_t(buffer[3]) << 0 * 6); | 11508 | 109 | *dst++ = static_cast<char>((triple >> 16) & 0xFF); | 11509 | 109 | *dst++ = static_cast<char>((triple >> 8) & 0xFF); | 11510 | 109 | *dst++ = static_cast<char>(triple & 0xFF); | 11511 | 109 | } | 11512 | 21.8k | } |
Unexecuted instantiation: simdutf.cpp:simdutf::full_result simdutf::scalar::(anonymous namespace)::base64::base64_tail_decode_impl<false, char16_t>(char*, unsigned long, char16_t const*, unsigned long, unsigned long, simdutf::base64_options, simdutf::last_chunk_handling_options) |
11513 | | |
11514 | | template <class char_type> |
11515 | | simdutf_constexpr23 full_result base64_tail_decode( |
11516 | | char *dst, const char_type *src, size_t length, |
11517 | | size_t padding_characters, // number of padding characters |
11518 | | // '=', typically 0, 1, 2. |
11519 | 21.8k | base64_options options, last_chunk_handling_options last_chunk_options) { |
11520 | 21.8k | return base64_tail_decode_impl<false>(dst, 0, src, length, padding_characters, |
11521 | 21.8k | options, last_chunk_options); |
11522 | 21.8k | } simdutf.cpp:simdutf::full_result simdutf::scalar::(anonymous namespace)::base64::base64_tail_decode<char>(char*, char const*, unsigned long, unsigned long, simdutf::base64_options, simdutf::last_chunk_handling_options) Line | Count | Source | 11519 | 21.8k | base64_options options, last_chunk_handling_options last_chunk_options) { | 11520 | 21.8k | return base64_tail_decode_impl<false>(dst, 0, src, length, padding_characters, | 11521 | 21.8k | options, last_chunk_options); | 11522 | 21.8k | } |
Unexecuted instantiation: simdutf.cpp:simdutf::full_result simdutf::scalar::(anonymous namespace)::base64::base64_tail_decode<char16_t>(char*, char16_t const*, unsigned long, unsigned long, simdutf::base64_options, simdutf::last_chunk_handling_options) |
11523 | | |
11524 | | // like base64_tail_decode, but it will not write past the end of the output |
11525 | | // buffer. The outlen parameter is modified to reflect the number of bytes |
11526 | | // written. This functions assumes that the padding (=) has been removed. |
11527 | | // |
11528 | | template <class char_type> |
11529 | | simdutf_constexpr23 full_result base64_tail_decode_safe( |
11530 | | char *dst, size_t outlen, const char_type *src, size_t length, |
11531 | | size_t padding_characters, // number of padding characters |
11532 | | // '=', typically 0, 1, 2. |
11533 | 0 | base64_options options, last_chunk_handling_options last_chunk_options) { |
11534 | 0 | return base64_tail_decode_impl<true>(dst, outlen, src, length, |
11535 | 0 | padding_characters, options, |
11536 | 0 | last_chunk_options); |
11537 | 0 | } Unexecuted instantiation: simdutf.cpp:simdutf::full_result simdutf::scalar::(anonymous namespace)::base64::base64_tail_decode_safe<char>(char*, unsigned long, char const*, unsigned long, unsigned long, simdutf::base64_options, simdutf::last_chunk_handling_options) Unexecuted instantiation: simdutf.cpp:simdutf::full_result simdutf::scalar::(anonymous namespace)::base64::base64_tail_decode_safe<char16_t>(char*, unsigned long, char16_t const*, unsigned long, unsigned long, simdutf::base64_options, simdutf::last_chunk_handling_options) |
11538 | | |
11539 | | inline simdutf_constexpr23 full_result |
11540 | | patch_tail_result(full_result r, size_t previous_input, size_t previous_output, |
11541 | | size_t equallocation, size_t full_input_length, |
11542 | 21.8k | last_chunk_handling_options last_chunk_options) { |
11543 | 21.8k | r.input_count += previous_input; |
11544 | 21.8k | r.output_count += previous_output; |
11545 | 21.8k | if (r.padding_error) { |
11546 | 34 | r.input_count = equallocation; |
11547 | 34 | } |
11548 | | |
11549 | 21.8k | if (r.error == error_code::SUCCESS) { |
11550 | 21.6k | if (!is_partial(last_chunk_options)) { |
11551 | | // A success when we are not in stop_before_partial mode. |
11552 | | // means that we have consumed the whole input buffer. |
11553 | 21.6k | r.input_count = full_input_length; |
11554 | 21.6k | } else if (r.output_count % 3 != 0) { |
11555 | 0 | r.input_count = full_input_length; |
11556 | 0 | } |
11557 | 21.6k | } |
11558 | 21.8k | return r; |
11559 | 21.8k | } Unexecuted instantiation: parser.cpp:simdutf::scalar::(anonymous namespace)::base64::patch_tail_result(simdutf::full_result, unsigned long, unsigned long, unsigned long, unsigned long, simdutf::last_chunk_handling_options) Unexecuted instantiation: base64.cpp:simdutf::scalar::(anonymous namespace)::base64::patch_tail_result(simdutf::full_result, unsigned long, unsigned long, unsigned long, unsigned long, simdutf::last_chunk_handling_options) simdutf.cpp:simdutf::scalar::(anonymous namespace)::base64::patch_tail_result(simdutf::full_result, unsigned long, unsigned long, unsigned long, unsigned long, simdutf::last_chunk_handling_options) Line | Count | Source | 11542 | 21.8k | last_chunk_handling_options last_chunk_options) { | 11543 | 21.8k | r.input_count += previous_input; | 11544 | 21.8k | r.output_count += previous_output; | 11545 | 21.8k | if (r.padding_error) { | 11546 | 34 | r.input_count = equallocation; | 11547 | 34 | } | 11548 | | | 11549 | 21.8k | if (r.error == error_code::SUCCESS) { | 11550 | 21.6k | if (!is_partial(last_chunk_options)) { | 11551 | | // A success when we are not in stop_before_partial mode. | 11552 | | // means that we have consumed the whole input buffer. | 11553 | 21.6k | r.input_count = full_input_length; | 11554 | 21.6k | } else if (r.output_count % 3 != 0) { | 11555 | 0 | r.input_count = full_input_length; | 11556 | 0 | } | 11557 | 21.6k | } | 11558 | 21.8k | return r; | 11559 | 21.8k | } |
|
11560 | | |
11561 | | // Returns the number of bytes written. The destination buffer must be large |
11562 | | // enough. It will add padding (=) if needed. |
11563 | | template <bool use_lines = false> |
11564 | | simdutf_constexpr23 size_t tail_encode_base64_impl( |
11565 | | char *dst, const char *src, size_t srclen, base64_options options, |
11566 | 0 | size_t line_length = simdutf::default_line_length, size_t line_offset = 0) { |
11567 | 0 | if constexpr (use_lines) { |
11568 | | // sanitize line_length and starting_line_offset. |
11569 | | // line_length must be greater than 3. |
11570 | 0 | if (line_length < 4) { |
11571 | 0 | line_length = 4; |
11572 | 0 | } |
11573 | 0 | simdutf_log_assert(line_offset <= line_length, |
11574 | 0 | "line_offset should be less than line_length"); |
11575 | 0 | } |
11576 | | // By default, we use padding if we are not using the URL variant. |
11577 | | // This is check with ((options & base64_url) == 0) which returns true if we |
11578 | | // are not using the URL variant. However, we also allow 'inversion' of the |
11579 | | // convention with the base64_reverse_padding option. If the |
11580 | | // base64_reverse_padding option is set, we use padding if we are using the |
11581 | | // URL variant, and we omit it if we are not using the URL variant. This is |
11582 | | // checked with |
11583 | | // ((options & base64_reverse_padding) == base64_reverse_padding). |
11584 | 0 | bool use_padding = |
11585 | 0 | ((options & base64_url) == 0) ^ |
11586 | 0 | ((options & base64_reverse_padding) == base64_reverse_padding); |
11587 | | // This looks like 3 branches, but we expect the compiler to resolve this to |
11588 | | // a single branch: |
11589 | 0 | const char *e0 = (options & base64_url) ? tables::base64::base64_url::e0 |
11590 | 0 | : tables::base64::base64_default::e0; |
11591 | 0 | const char *e1 = (options & base64_url) ? tables::base64::base64_url::e1 |
11592 | 0 | : tables::base64::base64_default::e1; |
11593 | 0 | const char *e2 = (options & base64_url) ? tables::base64::base64_url::e2 |
11594 | 0 | : tables::base64::base64_default::e2; |
11595 | 0 | char *out = dst; |
11596 | 0 | size_t i = 0; |
11597 | 0 | uint8_t t1, t2, t3; |
11598 | 0 | for (; i + 2 < srclen; i += 3) { |
11599 | 0 | t1 = uint8_t(src[i]); |
11600 | 0 | t2 = uint8_t(src[i + 1]); |
11601 | 0 | t3 = uint8_t(src[i + 2]); |
11602 | 0 | if constexpr (use_lines) { |
11603 | 0 | if (line_offset + 3 >= line_length) { |
11604 | 0 | if (line_offset == line_length) { |
11605 | 0 | *out++ = '\n'; |
11606 | 0 | *out++ = e0[t1]; |
11607 | 0 | *out++ = e1[((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)]; |
11608 | 0 | *out++ = e1[((t2 & 0x0F) << 2) | ((t3 >> 6) & 0x03)]; |
11609 | 0 | *out++ = e2[t3]; |
11610 | 0 | line_offset = 4; |
11611 | 0 | } else if (line_offset + 1 == line_length) { |
11612 | 0 | *out++ = e0[t1]; |
11613 | 0 | *out++ = '\n'; |
11614 | 0 | *out++ = e1[((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)]; |
11615 | 0 | *out++ = e1[((t2 & 0x0F) << 2) | ((t3 >> 6) & 0x03)]; |
11616 | 0 | *out++ = e2[t3]; |
11617 | 0 | line_offset = 3; |
11618 | 0 | } else if (line_offset + 2 == line_length) { |
11619 | 0 | *out++ = e0[t1]; |
11620 | 0 | *out++ = e1[((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)]; |
11621 | 0 | *out++ = '\n'; |
11622 | 0 | *out++ = e1[((t2 & 0x0F) << 2) | ((t3 >> 6) & 0x03)]; |
11623 | 0 | *out++ = e2[t3]; |
11624 | 0 | line_offset = 2; |
11625 | 0 | } else if (line_offset + 3 == line_length) { |
11626 | 0 | *out++ = e0[t1]; |
11627 | 0 | *out++ = e1[((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)]; |
11628 | 0 | *out++ = e1[((t2 & 0x0F) << 2) | ((t3 >> 6) & 0x03)]; |
11629 | 0 | *out++ = '\n'; |
11630 | 0 | *out++ = e2[t3]; |
11631 | 0 | line_offset = 1; |
11632 | 0 | } |
11633 | 0 | } else { |
11634 | 0 | *out++ = e0[t1]; |
11635 | 0 | *out++ = e1[((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)]; |
11636 | 0 | *out++ = e1[((t2 & 0x0F) << 2) | ((t3 >> 6) & 0x03)]; |
11637 | 0 | *out++ = e2[t3]; |
11638 | 0 | line_offset += 4; |
11639 | 0 | } |
11640 | 0 | } else { |
11641 | 0 | *out++ = e0[t1]; |
11642 | 0 | *out++ = e1[((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)]; |
11643 | 0 | *out++ = e1[((t2 & 0x0F) << 2) | ((t3 >> 6) & 0x03)]; |
11644 | 0 | *out++ = e2[t3]; |
11645 | 0 | } |
11646 | 0 | } |
11647 | 0 | switch (srclen - i) { |
11648 | 0 | case 0: |
11649 | 0 | break; |
11650 | 0 | case 1: |
11651 | 0 | t1 = uint8_t(src[i]); |
11652 | 0 | if constexpr (use_lines) { |
11653 | 0 | if (use_padding) { |
11654 | 0 | if (line_offset + 3 >= line_length) { |
11655 | 0 | if (line_offset == line_length) { |
11656 | 0 | *out++ = '\n'; |
11657 | 0 | *out++ = e0[t1]; |
11658 | 0 | *out++ = e1[(t1 & 0x03) << 4]; |
11659 | 0 | *out++ = '='; |
11660 | 0 | *out++ = '='; |
11661 | 0 | } else if (line_offset + 1 == line_length) { |
11662 | 0 | *out++ = e0[t1]; |
11663 | 0 | *out++ = '\n'; |
11664 | 0 | *out++ = e1[(t1 & 0x03) << 4]; |
11665 | 0 | *out++ = '='; |
11666 | 0 | *out++ = '='; |
11667 | 0 | } else if (line_offset + 2 == line_length) { |
11668 | 0 | *out++ = e0[t1]; |
11669 | 0 | *out++ = e1[(t1 & 0x03) << 4]; |
11670 | 0 | *out++ = '\n'; |
11671 | 0 | *out++ = '='; |
11672 | 0 | *out++ = '='; |
11673 | 0 | } else if (line_offset + 3 == line_length) { |
11674 | 0 | *out++ = e0[t1]; |
11675 | 0 | *out++ = e1[(t1 & 0x03) << 4]; |
11676 | 0 | *out++ = '='; |
11677 | 0 | *out++ = '\n'; |
11678 | 0 | *out++ = '='; |
11679 | 0 | } |
11680 | 0 | } else { |
11681 | 0 | *out++ = e0[t1]; |
11682 | 0 | *out++ = e1[(t1 & 0x03) << 4]; |
11683 | 0 | *out++ = '='; |
11684 | 0 | *out++ = '='; |
11685 | 0 | } |
11686 | 0 | } else { |
11687 | 0 | if (line_offset + 2 >= line_length) { |
11688 | 0 | if (line_offset == line_length) { |
11689 | 0 | *out++ = '\n'; |
11690 | 0 | *out++ = e0[uint8_t(src[i])]; |
11691 | 0 | *out++ = e1[(uint8_t(src[i]) & 0x03) << 4]; |
11692 | 0 | } else if (line_offset + 1 == line_length) { |
11693 | 0 | *out++ = e0[uint8_t(src[i])]; |
11694 | 0 | *out++ = '\n'; |
11695 | 0 | *out++ = e1[(uint8_t(src[i]) & 0x03) << 4]; |
11696 | 0 | } else { |
11697 | 0 | *out++ = e0[uint8_t(src[i])]; |
11698 | 0 | *out++ = e1[(uint8_t(src[i]) & 0x03) << 4]; |
11699 | | // *out++ = '\n'; ==> no newline at the end of the output |
11700 | 0 | } |
11701 | 0 | } else { |
11702 | 0 | *out++ = e0[uint8_t(src[i])]; |
11703 | 0 | *out++ = e1[(uint8_t(src[i]) & 0x03) << 4]; |
11704 | 0 | } |
11705 | 0 | } |
11706 | 0 | } else { |
11707 | 0 | *out++ = e0[t1]; |
11708 | 0 | *out++ = e1[(t1 & 0x03) << 4]; |
11709 | 0 | if (use_padding) { |
11710 | 0 | *out++ = '='; |
11711 | 0 | *out++ = '='; |
11712 | 0 | } |
11713 | 0 | } |
11714 | 0 | break; |
11715 | 0 | default: /* case 2 */ |
11716 | 0 | t1 = uint8_t(src[i]); |
11717 | 0 | t2 = uint8_t(src[i + 1]); |
11718 | 0 | if constexpr (use_lines) { |
11719 | 0 | if (use_padding) { |
11720 | 0 | if (line_offset + 3 >= line_length) { |
11721 | 0 | if (line_offset == line_length) { |
11722 | 0 | *out++ = '\n'; |
11723 | 0 | *out++ = e0[t1]; |
11724 | 0 | *out++ = e1[((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)]; |
11725 | 0 | *out++ = e2[(t2 & 0x0F) << 2]; |
11726 | 0 | *out++ = '='; |
11727 | 0 | } else if (line_offset + 1 == line_length) { |
11728 | 0 | *out++ = e0[t1]; |
11729 | 0 | *out++ = '\n'; |
11730 | 0 | *out++ = e1[((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)]; |
11731 | 0 | *out++ = e2[(t2 & 0x0F) << 2]; |
11732 | 0 | *out++ = '='; |
11733 | 0 | } else if (line_offset + 2 == line_length) { |
11734 | 0 | *out++ = e0[t1]; |
11735 | 0 | *out++ = e1[((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)]; |
11736 | 0 | *out++ = '\n'; |
11737 | 0 | *out++ = e2[(t2 & 0x0F) << 2]; |
11738 | 0 | *out++ = '='; |
11739 | 0 | } else if (line_offset + 3 == line_length) { |
11740 | 0 | *out++ = e0[t1]; |
11741 | 0 | *out++ = e1[((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)]; |
11742 | 0 | *out++ = e2[(t2 & 0x0F) << 2]; |
11743 | 0 | *out++ = '\n'; |
11744 | 0 | *out++ = '='; |
11745 | 0 | } |
11746 | 0 | } else { |
11747 | 0 | *out++ = e0[t1]; |
11748 | 0 | *out++ = e1[((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)]; |
11749 | 0 | *out++ = e2[(t2 & 0x0F) << 2]; |
11750 | 0 | *out++ = '='; |
11751 | 0 | } |
11752 | 0 | } else { |
11753 | 0 | if (line_offset + 3 >= line_length) { |
11754 | 0 | if (line_offset == line_length) { |
11755 | 0 | *out++ = '\n'; |
11756 | 0 | *out++ = e0[t1]; |
11757 | 0 | *out++ = e1[((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)]; |
11758 | 0 | *out++ = e2[(t2 & 0x0F) << 2]; |
11759 | 0 | } else if (line_offset + 1 == line_length) { |
11760 | 0 | *out++ = e0[t1]; |
11761 | 0 | *out++ = '\n'; |
11762 | 0 | *out++ = e1[((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)]; |
11763 | 0 | *out++ = e2[(t2 & 0x0F) << 2]; |
11764 | 0 | } else if (line_offset + 2 == line_length) { |
11765 | 0 | *out++ = e0[t1]; |
11766 | 0 | *out++ = e1[((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)]; |
11767 | 0 | *out++ = '\n'; |
11768 | 0 | *out++ = e2[(t2 & 0x0F) << 2]; |
11769 | 0 | } else { |
11770 | 0 | *out++ = e0[t1]; |
11771 | 0 | *out++ = e1[((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)]; |
11772 | 0 | *out++ = e2[(t2 & 0x0F) << 2]; |
11773 | | // *out++ = '\n'; ==> no newline at the end of the output |
11774 | 0 | } |
11775 | 0 | } else { |
11776 | 0 | *out++ = e0[t1]; |
11777 | 0 | *out++ = e1[((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)]; |
11778 | 0 | *out++ = e2[(t2 & 0x0F) << 2]; |
11779 | 0 | } |
11780 | 0 | } |
11781 | 0 | } else { |
11782 | 0 | *out++ = e0[t1]; |
11783 | 0 | *out++ = e1[((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)]; |
11784 | 0 | *out++ = e2[(t2 & 0x0F) << 2]; |
11785 | 0 | if (use_padding) { |
11786 | 0 | *out++ = '='; |
11787 | 0 | } |
11788 | 0 | } |
11789 | 0 | } |
11790 | 0 | return (size_t)(out - dst); |
11791 | 0 | } Unexecuted instantiation: parser.cpp:unsigned long simdutf::scalar::(anonymous namespace)::base64::tail_encode_base64_impl<false>(char*, char const*, unsigned long, simdutf::base64_options, unsigned long, unsigned long) Unexecuted instantiation: base64.cpp:unsigned long simdutf::scalar::(anonymous namespace)::base64::tail_encode_base64_impl<false>(char*, char const*, unsigned long, simdutf::base64_options, unsigned long, unsigned long) Unexecuted instantiation: simdutf.cpp:unsigned long simdutf::scalar::(anonymous namespace)::base64::tail_encode_base64_impl<false>(char*, char const*, unsigned long, simdutf::base64_options, unsigned long, unsigned long) Unexecuted instantiation: simdutf.cpp:unsigned long simdutf::scalar::(anonymous namespace)::base64::tail_encode_base64_impl<true>(char*, char const*, unsigned long, simdutf::base64_options, unsigned long, unsigned long) |
11792 | | |
11793 | | // Returns the number of bytes written. The destination buffer must be large |
11794 | | // enough. It will add padding (=) if needed. |
11795 | | simdutf_unused inline simdutf_constexpr23 size_t tail_encode_base64( |
11796 | 0 | char *dst, const char *src, size_t srclen, base64_options options) { |
11797 | 0 | return tail_encode_base64_impl(dst, src, srclen, options); |
11798 | 0 | } Unexecuted instantiation: parser.cpp:simdutf::scalar::(anonymous namespace)::base64::tail_encode_base64(char*, char const*, unsigned long, simdutf::base64_options) Unexecuted instantiation: base64.cpp:simdutf::scalar::(anonymous namespace)::base64::tail_encode_base64(char*, char const*, unsigned long, simdutf::base64_options) Unexecuted instantiation: simdutf.cpp:simdutf::scalar::(anonymous namespace)::base64::tail_encode_base64(char*, char const*, unsigned long, simdutf::base64_options) |
11799 | | |
11800 | | template <class InputPtr> |
11801 | | simdutf_warn_unused simdutf_constexpr23 size_t |
11802 | 0 | maximal_binary_length_from_base64(InputPtr input, size_t length) noexcept { |
11803 | | // We process the padding characters ('=') at the end to make sure |
11804 | | // that we return an exact result when the input has no ignorable characters |
11805 | | // (e.g., spaces). |
11806 | 0 | size_t padding = 0; |
11807 | 0 | if (length > 0) { |
11808 | 0 | if (input[length - 1] == '=') { |
11809 | 0 | padding++; |
11810 | 0 | if (length > 1 && input[length - 2] == '=') { |
11811 | 0 | padding++; |
11812 | 0 | } |
11813 | 0 | } |
11814 | 0 | } |
11815 | | // The input is not otherwise processed for ignorable characters or |
11816 | | // validation, so that the function runs in constant time (very fast). In |
11817 | | // practice, base64 inputs without ignorable characters are common and the |
11818 | | // common case are line separated inputs with relatively long lines (e.g., 76 |
11819 | | // characters) which leads this function to a slight (1%) overestimation of |
11820 | | // the output size. |
11821 | | // |
11822 | | // Of course, some inputs might contain an arbitrary number of spaces or |
11823 | | // newlines, which would make this function return a very pessimistic output |
11824 | | // size but systems that produce base64 outputs typically do not do that and |
11825 | | // if they do, they do not care much about minimizing memory usage. |
11826 | | // |
11827 | | // In specialized applications, users may know that their input is line |
11828 | | // separated, which can be checked very quickly by by iterating (e.g., over 76 |
11829 | | // character chunks, looking for the linefeed characters only). We could |
11830 | | // provide a specialized function for that, but it is not clear that the added |
11831 | | // complexity is worth it for us. |
11832 | | // |
11833 | 0 | size_t actual_length = length - padding; |
11834 | 0 | if (actual_length % 4 <= 1) { |
11835 | 0 | return actual_length / 4 * 3; |
11836 | 0 | } |
11837 | | // if we have a valid input, then the remainder must be 2 or 3 adding one or |
11838 | | // two extra bytes. |
11839 | 0 | return actual_length / 4 * 3 + (actual_length % 4) - 1; |
11840 | 0 | } Unexecuted instantiation: simdutf.cpp:unsigned long simdutf::scalar::(anonymous namespace)::base64::maximal_binary_length_from_base64<char const*>(char const*, unsigned long) Unexecuted instantiation: simdutf.cpp:unsigned long simdutf::scalar::(anonymous namespace)::base64::maximal_binary_length_from_base64<char16_t const*>(char16_t const*, unsigned long) |
11841 | | |
11842 | | // This function computes the binary length by iterating through the input |
11843 | | // and counting non-whitespace characters (excluding padding characters). |
11844 | | // We use a simple check (c > ' ') which is easy to parallelize and matches |
11845 | | // SIMD behavior. Only the last few characters are checked for padding '='. |
11846 | | template <class char_type> |
11847 | | simdutf_warn_unused simdutf_constexpr23 size_t |
11848 | 0 | binary_length_from_base64(const char_type *input, size_t length) noexcept { |
11849 | | // Count non-whitespace characters (c > ' ') with loop unrolling |
11850 | 0 | size_t count = 0; |
11851 | 0 | for (size_t i = 0; i < length; i++) { |
11852 | 0 | count += (input[i] > ' '); |
11853 | 0 | } |
11854 | | |
11855 | | // Check for padding '=' at the end (at most 2 padding characters) |
11856 | | // Scan backwards, skipping whitespace, to find padding |
11857 | 0 | size_t padding = 0; |
11858 | 0 | size_t pos = length; |
11859 | | // Skip trailing whitespace |
11860 | 0 | while (pos > 0 && padding < 2) { |
11861 | 0 | char_type c = input[--pos]; |
11862 | 0 | if (c == '=') { |
11863 | 0 | padding++; |
11864 | 0 | } else if (c > ' ') { |
11865 | 0 | break; |
11866 | 0 | } |
11867 | 0 | } |
11868 | 0 | return ((count - padding) * 3) / 4; |
11869 | 0 | } Unexecuted instantiation: simdutf.cpp:unsigned long simdutf::scalar::(anonymous namespace)::base64::binary_length_from_base64<char>(char const*, unsigned long) Unexecuted instantiation: simdutf.cpp:unsigned long simdutf::scalar::(anonymous namespace)::base64::binary_length_from_base64<char16_t>(char16_t const*, unsigned long) |
11870 | | |
11871 | | template <typename char_type> |
11872 | | simdutf_warn_unused simdutf_constexpr23 full_result |
11873 | | base64_to_binary_details_impl( |
11874 | | const char_type *input, size_t length, char *output, base64_options options, |
11875 | 0 | last_chunk_handling_options last_chunk_options) noexcept { |
11876 | 0 | const bool ignore_garbage = |
11877 | 0 | (options == base64_options::base64_url_accept_garbage) || |
11878 | 0 | (options == base64_options::base64_default_accept_garbage) || |
11879 | 0 | (options == base64_options::base64_default_or_url_accept_garbage); |
11880 | 0 | auto ri = simdutf::scalar::base64::find_end(input, length, options); |
11881 | 0 | size_t equallocation = ri.equallocation; |
11882 | 0 | size_t equalsigns = ri.equalsigns; |
11883 | 0 | length = ri.srclen; |
11884 | 0 | size_t full_input_length = ri.full_input_length; |
11885 | 0 | if (length == 0) { |
11886 | 0 | if (!ignore_garbage && equalsigns > 0) { |
11887 | 0 | return {INVALID_BASE64_CHARACTER, equallocation, 0, true}; |
11888 | 0 | } |
11889 | 0 | return {SUCCESS, full_input_length, 0}; |
11890 | 0 | } |
11891 | 0 | full_result r = scalar::base64::base64_tail_decode( |
11892 | 0 | output, input, length, equalsigns, options, last_chunk_options); |
11893 | 0 | r = scalar::base64::patch_tail_result(r, 0, 0, equallocation, |
11894 | 0 | full_input_length, last_chunk_options); |
11895 | 0 | if (!is_partial(last_chunk_options) && r.error == error_code::SUCCESS && |
11896 | 0 | equalsigns > 0 && !ignore_garbage) { |
11897 | | // additional checks |
11898 | 0 | if ((r.output_count % 3 == 0) || |
11899 | 0 | ((r.output_count % 3) + 1 + equalsigns != 4)) { |
11900 | 0 | return {INVALID_BASE64_CHARACTER, equallocation, r.output_count, true}; |
11901 | 0 | } |
11902 | 0 | } |
11903 | | // When is_partial(last_chunk_options) is true, we must either end with |
11904 | | // the end of the stream (beyond whitespace) or right after a non-ignorable |
11905 | | // character or at the very beginning of the stream. |
11906 | | // See https://tc39.es/proposal-arraybuffer-base64/spec/#sec-frombase64 |
11907 | 0 | if (is_partial(last_chunk_options) && r.error == error_code::SUCCESS && |
11908 | 0 | r.input_count < full_input_length) { |
11909 | | // First check if we can extend the input to the end of the stream |
11910 | 0 | while (r.input_count < full_input_length && |
11911 | 0 | base64_ignorable(*(input + r.input_count), options)) { |
11912 | 0 | r.input_count++; |
11913 | 0 | } |
11914 | | // If we are still not at the end of the stream, then we must backtrack |
11915 | | // to the last non-ignorable character. |
11916 | 0 | if (r.input_count < full_input_length) { |
11917 | 0 | while (r.input_count > 0 && |
11918 | 0 | base64_ignorable(*(input + r.input_count - 1), options)) { |
11919 | 0 | r.input_count--; |
11920 | 0 | } |
11921 | 0 | } |
11922 | 0 | } |
11923 | 0 | return r; |
11924 | 0 | } Unexecuted instantiation: simdutf.cpp:simdutf::full_result simdutf::scalar::(anonymous namespace)::base64::base64_to_binary_details_impl<char>(char const*, unsigned long, char*, simdutf::base64_options, simdutf::last_chunk_handling_options) Unexecuted instantiation: simdutf.cpp:simdutf::full_result simdutf::scalar::(anonymous namespace)::base64::base64_to_binary_details_impl<char16_t>(char16_t const*, unsigned long, char*, simdutf::base64_options, simdutf::last_chunk_handling_options) |
11925 | | |
11926 | | template <typename char_type> |
11927 | | simdutf_constexpr23 simdutf_warn_unused full_result |
11928 | | base64_to_binary_details_safe_impl( |
11929 | | const char_type *input, size_t length, char *output, size_t outlen, |
11930 | | base64_options options, |
11931 | 0 | last_chunk_handling_options last_chunk_options) noexcept { |
11932 | 0 | const bool ignore_garbage = |
11933 | 0 | (options == base64_options::base64_url_accept_garbage) || |
11934 | 0 | (options == base64_options::base64_default_accept_garbage) || |
11935 | 0 | (options == base64_options::base64_default_or_url_accept_garbage); |
11936 | 0 | auto ri = simdutf::scalar::base64::find_end(input, length, options); |
11937 | 0 | size_t equallocation = ri.equallocation; |
11938 | 0 | size_t equalsigns = ri.equalsigns; |
11939 | 0 | length = ri.srclen; |
11940 | 0 | size_t full_input_length = ri.full_input_length; |
11941 | 0 | if (length == 0) { |
11942 | 0 | if (!ignore_garbage && equalsigns > 0) { |
11943 | 0 | return {INVALID_BASE64_CHARACTER, equallocation, 0}; |
11944 | 0 | } |
11945 | 0 | return {SUCCESS, full_input_length, 0}; |
11946 | 0 | } |
11947 | 0 | full_result r = scalar::base64::base64_tail_decode_safe( |
11948 | 0 | output, outlen, input, length, equalsigns, options, last_chunk_options); |
11949 | 0 | r = scalar::base64::patch_tail_result(r, 0, 0, equallocation, |
11950 | 0 | full_input_length, last_chunk_options); |
11951 | 0 | if (!is_partial(last_chunk_options) && r.error == error_code::SUCCESS && |
11952 | 0 | equalsigns > 0 && !ignore_garbage) { |
11953 | | // additional checks |
11954 | 0 | if ((r.output_count % 3 == 0) || |
11955 | 0 | ((r.output_count % 3) + 1 + equalsigns != 4)) { |
11956 | 0 | return {INVALID_BASE64_CHARACTER, equallocation, r.output_count}; |
11957 | 0 | } |
11958 | 0 | } |
11959 | | |
11960 | | // When is_partial(last_chunk_options) is true, we must either end with |
11961 | | // the end of the stream (beyond whitespace) or right after a non-ignorable |
11962 | | // character or at the very beginning of the stream. |
11963 | | // See https://tc39.es/proposal-arraybuffer-base64/spec/#sec-frombase64 |
11964 | 0 | if (is_partial(last_chunk_options) && r.error == error_code::SUCCESS && |
11965 | 0 | r.input_count < full_input_length) { |
11966 | | // First check if we can extend the input to the end of the stream |
11967 | 0 | while (r.input_count < full_input_length && |
11968 | 0 | base64_ignorable(*(input + r.input_count), options)) { |
11969 | 0 | r.input_count++; |
11970 | 0 | } |
11971 | | // If we are still not at the end of the stream, then we must backtrack |
11972 | | // to the last non-ignorable character. |
11973 | 0 | if (r.input_count < full_input_length) { |
11974 | 0 | while (r.input_count > 0 && |
11975 | 0 | base64_ignorable(*(input + r.input_count - 1), options)) { |
11976 | 0 | r.input_count--; |
11977 | 0 | } |
11978 | 0 | } |
11979 | 0 | } |
11980 | 0 | return r; |
11981 | 0 | } Unexecuted instantiation: simdutf.cpp:simdutf::full_result simdutf::scalar::(anonymous namespace)::base64::base64_to_binary_details_safe_impl<char>(char const*, unsigned long, char*, unsigned long, simdutf::base64_options, simdutf::last_chunk_handling_options) Unexecuted instantiation: simdutf.cpp:simdutf::full_result simdutf::scalar::(anonymous namespace)::base64::base64_to_binary_details_safe_impl<char16_t>(char16_t const*, unsigned long, char*, unsigned long, simdutf::base64_options, simdutf::last_chunk_handling_options) |
11982 | | |
11983 | | simdutf_warn_unused simdutf_constexpr23 size_t |
11984 | 0 | base64_length_from_binary(size_t length, base64_options options) noexcept { |
11985 | | // By default, we use padding if we are not using the URL variant. |
11986 | | // This is check with ((options & base64_url) == 0) which returns true if we |
11987 | | // are not using the URL variant. However, we also allow 'inversion' of the |
11988 | | // convention with the base64_reverse_padding option. If the |
11989 | | // base64_reverse_padding option is set, we use padding if we are using the |
11990 | | // URL variant, and we omit it if we are not using the URL variant. This is |
11991 | | // checked with |
11992 | | // ((options & base64_reverse_padding) == base64_reverse_padding). |
11993 | 0 | bool use_padding = |
11994 | 0 | ((options & base64_url) == 0) ^ |
11995 | 0 | ((options & base64_reverse_padding) == base64_reverse_padding); |
11996 | 0 | if (!use_padding) { |
11997 | 0 | return length / 3 * 4 + ((length % 3) ? (length % 3) + 1 : 0); |
11998 | 0 | } |
11999 | 0 | return (length + 2) / 3 * |
12000 | 0 | 4; // We use padding to make the length a multiple of 4. |
12001 | 0 | } Unexecuted instantiation: parser.cpp:simdutf::scalar::(anonymous namespace)::base64::base64_length_from_binary(unsigned long, simdutf::base64_options) Unexecuted instantiation: base64.cpp:simdutf::scalar::(anonymous namespace)::base64::base64_length_from_binary(unsigned long, simdutf::base64_options) Unexecuted instantiation: simdutf.cpp:simdutf::scalar::(anonymous namespace)::base64::base64_length_from_binary(unsigned long, simdutf::base64_options) |
12002 | | |
12003 | | simdutf_warn_unused simdutf_constexpr23 size_t |
12004 | | base64_length_from_binary_with_lines(size_t length, base64_options options, |
12005 | 0 | size_t line_length) noexcept { |
12006 | 0 | if (length == 0) { |
12007 | 0 | return 0; |
12008 | 0 | } |
12009 | 0 | size_t base64_length = |
12010 | 0 | scalar::base64::base64_length_from_binary(length, options); |
12011 | 0 | if (line_length < 4) { |
12012 | 0 | line_length = 4; |
12013 | 0 | } |
12014 | 0 | // number of lines, rounded up without computing base64_length + line_length, |
12015 | 0 | // which wraps around when line_length is close to SIZE_MAX |
12016 | 0 | size_t lines = base64_length / line_length; |
12017 | 0 | if (base64_length % line_length != 0) { |
12018 | 0 | lines++; |
12019 | 0 | } |
12020 | 0 | return base64_length + lines - 1; |
12021 | 0 | } Unexecuted instantiation: parser.cpp:simdutf::scalar::(anonymous namespace)::base64::base64_length_from_binary_with_lines(unsigned long, simdutf::base64_options, unsigned long) Unexecuted instantiation: base64.cpp:simdutf::scalar::(anonymous namespace)::base64::base64_length_from_binary_with_lines(unsigned long, simdutf::base64_options, unsigned long) Unexecuted instantiation: simdutf.cpp:simdutf::scalar::(anonymous namespace)::base64::base64_length_from_binary_with_lines(unsigned long, simdutf::base64_options, unsigned long) |
12022 | | |
12023 | | // Return the length of the prefix that contains count base64 characters. |
12024 | | // Thus, if count is 3, the function returns the length of the prefix |
12025 | | // that contains 3 base64 characters. |
12026 | | // The function returns (size_t)-1 if there is not enough base64 characters in |
12027 | | // the input. |
12028 | | template <typename char_type> |
12029 | | simdutf_warn_unused size_t prefix_length(size_t count, |
12030 | | simdutf::base64_options options, |
12031 | | const char_type *input, |
12032 | | size_t length) noexcept { |
12033 | | size_t i = 0; |
12034 | | while (i < length && is_ignorable(input[i], options)) { |
12035 | | i++; |
12036 | | } |
12037 | | if (count == 0) { |
12038 | | return i; // duh! |
12039 | | } |
12040 | | for (; i < length; i++) { |
12041 | | if (is_ignorable(input[i], options)) { |
12042 | | continue; |
12043 | | } |
12044 | | // We have a base64 character or a padding character. |
12045 | | count--; |
12046 | | if (count == 0) { |
12047 | | return i + 1; |
12048 | | } |
12049 | | } |
12050 | | simdutf_log_assert(false, "You never get here"); |
12051 | | |
12052 | | return -1; // should never happen |
12053 | | } |
12054 | | |
12055 | | } // namespace base64 |
12056 | | } // unnamed namespace |
12057 | | } // namespace scalar |
12058 | | } // namespace simdutf |
12059 | | |
12060 | | #endif |
12061 | | /* end file include/simdutf/scalar/base64.h */ |
12062 | | |
12063 | | namespace simdutf { |
12064 | | |
12065 | 0 | inline std::string_view to_string(base64_options options) { |
12066 | 0 | switch (options) { |
12067 | 0 | case base64_default: |
12068 | 0 | return "base64_default"; |
12069 | 0 | case base64_url: |
12070 | 0 | return "base64_url"; |
12071 | 0 | case base64_reverse_padding: |
12072 | 0 | return "base64_reverse_padding"; |
12073 | 0 | case base64_url_with_padding: |
12074 | 0 | return "base64_url_with_padding"; |
12075 | 0 | case base64_default_accept_garbage: |
12076 | 0 | return "base64_default_accept_garbage"; |
12077 | 0 | case base64_url_accept_garbage: |
12078 | 0 | return "base64_url_accept_garbage"; |
12079 | 0 | case base64_default_or_url: |
12080 | 0 | return "base64_default_or_url"; |
12081 | 0 | case base64_default_or_url_accept_garbage: |
12082 | 0 | return "base64_default_or_url_accept_garbage"; |
12083 | 0 | } |
12084 | 0 | return "<unknown>"; |
12085 | 0 | } |
12086 | | |
12087 | 0 | inline std::string_view to_string(last_chunk_handling_options options) { |
12088 | 0 | switch (options) { |
12089 | 0 | case loose: |
12090 | 0 | return "loose"; |
12091 | 0 | case strict: |
12092 | 0 | return "strict"; |
12093 | 0 | case stop_before_partial: |
12094 | 0 | return "stop_before_partial"; |
12095 | 0 | case only_full_chunks: |
12096 | 0 | return "only_full_chunks"; |
12097 | 0 | } |
12098 | 0 | return "<unknown>"; |
12099 | 0 | } |
12100 | | |
12101 | | /** |
12102 | | * Provide the maximal binary length in bytes given the base64 input. |
12103 | | * As long as the input does not contain ignorable characters (e.g., ASCII |
12104 | | * spaces or linefeed characters), the result is exact. In particular, the |
12105 | | * function checks for padding characters. |
12106 | | * |
12107 | | * The function is fast (constant time). It checks up to two characters at |
12108 | | * the end of the string. The input is not otherwise validated or read. |
12109 | | * |
12110 | | * @param input the base64 input to process |
12111 | | * @param length the length of the base64 input in bytes |
12112 | | * @return maximum number of binary bytes |
12113 | | */ |
12114 | | simdutf_warn_unused size_t |
12115 | | maximal_binary_length_from_base64(const char *input, size_t length) noexcept; |
12116 | | #if SIMDUTF_SPAN |
12117 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t |
12118 | | maximal_binary_length_from_base64( |
12119 | | const detail::input_span_of_byte_like auto &input) noexcept { |
12120 | | #if SIMDUTF_CPLUSPLUS23 |
12121 | | if consteval { |
12122 | | return scalar::base64::maximal_binary_length_from_base64( |
12123 | | detail::constexpr_cast_ptr<uint8_t>(input.data()), input.size()); |
12124 | | } else |
12125 | | #endif |
12126 | | { |
12127 | | return maximal_binary_length_from_base64( |
12128 | | reinterpret_cast<const char *>(input.data()), input.size()); |
12129 | | } |
12130 | | } |
12131 | | #endif // SIMDUTF_SPAN |
12132 | | |
12133 | | /** |
12134 | | * Provide the maximal binary length in bytes given the base64 input. |
12135 | | * As long as the input does not contain ignorable characters (e.g., ASCII |
12136 | | * spaces or linefeed characters), the result is exact. In particular, the |
12137 | | * function checks for padding characters. |
12138 | | * |
12139 | | * The function is fast (constant time). It checks up to two characters at |
12140 | | * the end of the string. The input is not otherwise validated or read. |
12141 | | * |
12142 | | * @param input the base64 input to process, in ASCII stored as 16-bit |
12143 | | * units |
12144 | | * @param length the length of the base64 input in 16-bit units |
12145 | | * @return maximal number of binary bytes |
12146 | | */ |
12147 | | simdutf_warn_unused size_t maximal_binary_length_from_base64( |
12148 | | const char16_t *input, size_t length) noexcept; |
12149 | | #if SIMDUTF_SPAN |
12150 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t |
12151 | 0 | maximal_binary_length_from_base64(std::span<const char16_t> input) noexcept { |
12152 | 0 | #if SIMDUTF_CPLUSPLUS23 |
12153 | 0 | if consteval { |
12154 | 0 | return scalar::base64::maximal_binary_length_from_base64(input.data(), |
12155 | 0 | input.size()); |
12156 | 0 | } else |
12157 | 0 | #endif |
12158 | 0 | { |
12159 | 0 | return maximal_binary_length_from_base64(input.data(), input.size()); |
12160 | 0 | } |
12161 | 0 | } |
12162 | | #endif // SIMDUTF_SPAN |
12163 | | |
12164 | | /** |
12165 | | * Compute the binary length from a base64 input. |
12166 | | * This function is useful for base64 inputs that may contain ASCII whitespaces |
12167 | | * (such as line breaks). For such inputs, the result is exact, and for any |
12168 | | * inputs the result can be used to size the output buffer passed to |
12169 | | * `base64_to_binary`. |
12170 | | * |
12171 | | * The function ignores whitespace and does not require padding characters |
12172 | | * ('='). |
12173 | | * |
12174 | | * @param input the base64 input to process |
12175 | | * @param length the length of the base64 input in bytes |
12176 | | * @return number of binary bytes |
12177 | | */ |
12178 | | simdutf_warn_unused size_t binary_length_from_base64(const char *input, |
12179 | | size_t length) noexcept; |
12180 | | #if SIMDUTF_SPAN |
12181 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t |
12182 | | binary_length_from_base64( |
12183 | | const detail::input_span_of_byte_like auto &input) noexcept { |
12184 | | #if SIMDUTF_CPLUSPLUS23 |
12185 | | if consteval { |
12186 | | return scalar::base64::binary_length_from_base64(input.data(), |
12187 | | input.size()); |
12188 | | } else |
12189 | | #endif |
12190 | | { |
12191 | | return binary_length_from_base64( |
12192 | | reinterpret_cast<const char *>(input.data()), input.size()); |
12193 | | } |
12194 | | } |
12195 | | #endif // SIMDUTF_SPAN |
12196 | | |
12197 | | /** |
12198 | | * Compute the binary length from a base64 input. |
12199 | | * This function is useful for base64 inputs that may contain ASCII whitespaces |
12200 | | * (such as line breaks). For such inputs, the result is exact, and for any |
12201 | | * inputs the result can be used to size the output buffer passed to |
12202 | | * `base64_to_binary`. |
12203 | | * |
12204 | | * The function ignores whitespace and does not require padding characters |
12205 | | * ('='). |
12206 | | * |
12207 | | * @param input the base64 input to process, in ASCII stored as 16-bit |
12208 | | * units |
12209 | | * @param length the length of the base64 input in 16-bit units |
12210 | | * @return number of binary bytes |
12211 | | */ |
12212 | | simdutf_warn_unused size_t binary_length_from_base64(const char16_t *input, |
12213 | | size_t length) noexcept; |
12214 | | #if SIMDUTF_SPAN |
12215 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t |
12216 | 0 | binary_length_from_base64(std::span<const char16_t> input) noexcept { |
12217 | 0 | #if SIMDUTF_CPLUSPLUS23 |
12218 | 0 | if consteval { |
12219 | 0 | return scalar::base64::binary_length_from_base64(input.data(), |
12220 | 0 | input.size()); |
12221 | 0 | } else |
12222 | 0 | #endif |
12223 | 0 | { |
12224 | 0 | return binary_length_from_base64(input.data(), input.size()); |
12225 | 0 | } |
12226 | 0 | } |
12227 | | #endif // SIMDUTF_SPAN |
12228 | | |
12229 | | /** |
12230 | | * Convert a base64 input to a binary output. |
12231 | | * |
12232 | | * This function follows the WHATWG forgiving-base64 format, which means that it |
12233 | | * will ignore any ASCII spaces in the input. You may provide a padded input |
12234 | | * (with one or two equal signs at the end) or an unpadded input (without any |
12235 | | * equal signs at the end). |
12236 | | * |
12237 | | * See https://infra.spec.whatwg.org/#forgiving-base64-decode |
12238 | | * |
12239 | | * This function will fail in case of invalid input. When last_chunk_options = |
12240 | | * loose, there are two possible reasons for failure: the input contains a |
12241 | | * number of base64 characters that when divided by 4, leaves a single remainder |
12242 | | * character (BASE64_INPUT_REMAINDER), or the input contains a character that is |
12243 | | * not a valid base64 character (INVALID_BASE64_CHARACTER). |
12244 | | * |
12245 | | * When the error is INVALID_BASE64_CHARACTER, r.count contains the index in the |
12246 | | * input where the invalid character was found. When the error is |
12247 | | * BASE64_INPUT_REMAINDER, then r.count contains the number of bytes decoded. |
12248 | | * |
12249 | | * The default option (simdutf::base64_default) expects the characters `+` and |
12250 | | * `/` as part of its alphabet. The URL option (simdutf::base64_url) expects the |
12251 | | * characters `-` and `_` as part of its alphabet. |
12252 | | * |
12253 | | * The padding (`=`) is validated if present. There may be at most two padding |
12254 | | * characters at the end of the input. If there are any padding characters, the |
12255 | | * total number of characters (excluding spaces but including padding |
12256 | | * characters) must be divisible by four. |
12257 | | * |
12258 | | * You should call this function with a buffer that is at least |
12259 | | * maximal_binary_length_from_base64(input, length) bytes long. If you fail to |
12260 | | * provide that much space, the function may cause a buffer overflow. |
12261 | | * |
12262 | | * Advanced users may want to tailor how the last chunk is handled. By default, |
12263 | | * we use a loose (forgiving) approach but we also support a strict approach |
12264 | | * as well as a stop_before_partial approach, as per the following proposal: |
12265 | | * |
12266 | | * https://tc39.es/proposal-arraybuffer-base64/spec/#sec-frombase64 |
12267 | | * |
12268 | | * @param input the base64 string to process |
12269 | | * @param length the length of the string in bytes |
12270 | | * @param output the pointer to a buffer that can hold the conversion |
12271 | | * result (should be at least maximal_binary_length_from_base64(input, length) |
12272 | | * bytes long). |
12273 | | * @param options the base64 options to use, usually base64_default or |
12274 | | * base64_url, and base64_default by default. |
12275 | | * @param last_chunk_options the last chunk handling options, |
12276 | | * last_chunk_handling_options::loose by default |
12277 | | * but can also be last_chunk_handling_options::strict or |
12278 | | * last_chunk_handling_options::stop_before_partial. |
12279 | | * @return a result pair struct (of type simdutf::result containing the two |
12280 | | * fields error and count) with an error code and either position of the error |
12281 | | * (in the input in bytes) if any, or the number of bytes written if successful. |
12282 | | */ |
12283 | | simdutf_warn_unused result base64_to_binary( |
12284 | | const char *input, size_t length, char *output, |
12285 | | base64_options options = base64_default, |
12286 | | last_chunk_handling_options last_chunk_options = loose) noexcept; |
12287 | | #if SIMDUTF_SPAN |
12288 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result |
12289 | | base64_to_binary( |
12290 | | const detail::input_span_of_byte_like auto &input, |
12291 | | detail::output_span_of_byte_like auto &&binary_output, |
12292 | | base64_options options = base64_default, |
12293 | | last_chunk_handling_options last_chunk_options = loose) noexcept { |
12294 | | #if SIMDUTF_CPLUSPLUS23 |
12295 | | if consteval { |
12296 | | return scalar::base64::base64_to_binary_details_impl( |
12297 | | input.data(), input.size(), binary_output.data(), options, |
12298 | | last_chunk_options); |
12299 | | } else |
12300 | | #endif |
12301 | | { |
12302 | | return base64_to_binary(reinterpret_cast<const char *>(input.data()), |
12303 | | input.size(), |
12304 | | reinterpret_cast<char *>(binary_output.data()), |
12305 | | options, last_chunk_options); |
12306 | | } |
12307 | | } |
12308 | | #endif // SIMDUTF_SPAN |
12309 | | |
12310 | | /** |
12311 | | * Provide the base64 length in bytes given the length of a binary input. |
12312 | | * |
12313 | | * @param length the length of the input in bytes |
12314 | | * @param options the base64 options to use (default: base64_default) |
12315 | | * @return number of base64 bytes |
12316 | | */ |
12317 | | inline simdutf_warn_unused simdutf_constexpr23 size_t base64_length_from_binary( |
12318 | 0 | size_t length, base64_options options = base64_default) noexcept { |
12319 | 0 | return scalar::base64::base64_length_from_binary(length, options); |
12320 | 0 | } |
12321 | | |
12322 | | /** |
12323 | | * Provide the base64 length in bytes given the length of a binary input, |
12324 | | * taking into account line breaks. |
12325 | | * |
12326 | | * @param length the length of the input in bytes |
12327 | | * @param options the base64 options to use (default: base64_default) |
12328 | | * @param line_length the length of lines, must be at least 4 (otherwise it is |
12329 | | * interpreted as 4), |
12330 | | * @return number of base64 bytes |
12331 | | */ |
12332 | | inline simdutf_warn_unused simdutf_constexpr23 size_t |
12333 | | base64_length_from_binary_with_lines( |
12334 | | size_t length, base64_options options = base64_default, |
12335 | 0 | size_t line_length = default_line_length) noexcept { |
12336 | 0 | return scalar::base64::base64_length_from_binary_with_lines(length, options, |
12337 | 0 | line_length); |
12338 | 0 | } |
12339 | | |
12340 | | /** |
12341 | | * Convert a binary input to a base64 output. |
12342 | | * |
12343 | | * The default option (simdutf::base64_default) uses the characters `+` and `/` |
12344 | | * as part of its alphabet. Further, it adds padding (`=`) at the end of the |
12345 | | * output to ensure that the output length is a multiple of four. |
12346 | | * |
12347 | | * The URL option (simdutf::base64_url) uses the characters `-` and `_` as part |
12348 | | * of its alphabet. No padding is added at the end of the output. |
12349 | | * |
12350 | | * This function always succeeds. |
12351 | | * |
12352 | | * @param input the binary to process |
12353 | | * @param length the length of the input in bytes |
12354 | | * @param output the pointer to a buffer that can hold the conversion |
12355 | | * result (should be at least base64_length_from_binary(length) bytes long) |
12356 | | * @param options the base64 options to use, can be base64_default or |
12357 | | * base64_url, is base64_default by default. |
12358 | | * @return number of written bytes, will be equal to |
12359 | | * base64_length_from_binary(length, options) |
12360 | | */ |
12361 | | size_t binary_to_base64(const char *input, size_t length, char *output, |
12362 | | base64_options options = base64_default) noexcept; |
12363 | | #if SIMDUTF_SPAN |
12364 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t |
12365 | | binary_to_base64(const detail::input_span_of_byte_like auto &input, |
12366 | | detail::output_span_of_byte_like auto &&binary_output, |
12367 | | base64_options options = base64_default) noexcept { |
12368 | | #if SIMDUTF_CPLUSPLUS23 |
12369 | | if consteval { |
12370 | | return scalar::base64::tail_encode_base64( |
12371 | | binary_output.data(), input.data(), input.size(), options); |
12372 | | } else |
12373 | | #endif |
12374 | | { |
12375 | | return binary_to_base64( |
12376 | | reinterpret_cast<const char *>(input.data()), input.size(), |
12377 | | reinterpret_cast<char *>(binary_output.data()), options); |
12378 | | } |
12379 | | } |
12380 | | #endif // SIMDUTF_SPAN |
12381 | | |
12382 | | /** |
12383 | | * Convert a binary input to a base64 output with line breaks. |
12384 | | * |
12385 | | * The default option (simdutf::base64_default) uses the characters `+` and `/` |
12386 | | * as part of its alphabet. Further, it adds padding (`=`) at the end of the |
12387 | | * output to ensure that the output length is a multiple of four. |
12388 | | * |
12389 | | * The URL option (simdutf::base64_url) uses the characters `-` and `_` as part |
12390 | | * of its alphabet. No padding is added at the end of the output. |
12391 | | * |
12392 | | * This function always succeeds. |
12393 | | * |
12394 | | * @param input the binary to process |
12395 | | * @param length the length of the input in bytes |
12396 | | * @param output the pointer to a buffer that can hold the conversion |
12397 | | * result (should be at least base64_length_from_binary_with_lines(length, |
12398 | | * options, line_length) bytes long) |
12399 | | * @param line_length the length of lines, must be at least 4 (otherwise it is |
12400 | | * interpreted as 4), |
12401 | | * @param options the base64 options to use, can be base64_default or |
12402 | | * base64_url, is base64_default by default. |
12403 | | * @return number of written bytes, will be equal to |
12404 | | * base64_length_from_binary_with_lines(length, options) |
12405 | | */ |
12406 | | size_t |
12407 | | binary_to_base64_with_lines(const char *input, size_t length, char *output, |
12408 | | size_t line_length = simdutf::default_line_length, |
12409 | | base64_options options = base64_default) noexcept; |
12410 | | #if SIMDUTF_SPAN |
12411 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t |
12412 | | binary_to_base64_with_lines( |
12413 | | const detail::input_span_of_byte_like auto &input, |
12414 | | detail::output_span_of_byte_like auto &&binary_output, |
12415 | | size_t line_length = simdutf::default_line_length, |
12416 | | base64_options options = base64_default) noexcept { |
12417 | | #if SIMDUTF_CPLUSPLUS23 |
12418 | | if consteval { |
12419 | | return scalar::base64::tail_encode_base64_impl<true>( |
12420 | | binary_output.data(), input.data(), input.size(), options, line_length); |
12421 | | } else |
12422 | | #endif |
12423 | | { |
12424 | | return binary_to_base64_with_lines( |
12425 | | reinterpret_cast<const char *>(input.data()), input.size(), |
12426 | | reinterpret_cast<char *>(binary_output.data()), line_length, options); |
12427 | | } |
12428 | | } |
12429 | | #endif // SIMDUTF_SPAN |
12430 | | |
12431 | | #if SIMDUTF_ATOMIC_REF |
12432 | | /** |
12433 | | * Convert a binary input to a base64 output, using atomic accesses. |
12434 | | * This function comes with a potentially significant performance |
12435 | | * penalty, but it may be useful in some cases where the input |
12436 | | * buffers are shared between threads, to avoid undefined |
12437 | | * behavior in case of data races. |
12438 | | * |
12439 | | * The function is for advanced users. Its main use case is when |
12440 | | * to silence sanitizer warnings. We have no documented use case |
12441 | | * where this function is actually necessary in terms of practical correctness. |
12442 | | * |
12443 | | * This function is only available when simdutf is compiled with |
12444 | | * C++20 support and __cpp_lib_atomic_ref >= 201806L. You may check |
12445 | | * the availability of this function by checking the macro |
12446 | | * SIMDUTF_ATOMIC_REF. |
12447 | | * |
12448 | | * The default option (simdutf::base64_default) uses the characters `+` and `/` |
12449 | | * as part of its alphabet. Further, it adds padding (`=`) at the end of the |
12450 | | * output to ensure that the output length is a multiple of four. |
12451 | | * |
12452 | | * The URL option (simdutf::base64_url) uses the characters `-` and `_` as part |
12453 | | * of its alphabet. No padding is added at the end of the output. |
12454 | | * |
12455 | | * This function always succeeds. |
12456 | | * |
12457 | | * This function is considered experimental. It is not tested by default |
12458 | | * (see the CMake option SIMDUTF_ATOMIC_BASE64_TESTS) nor is it fuzz tested. |
12459 | | * It is not documented in the public API documentation (README). It is |
12460 | | * offered on a best effort basis. We rely on the community for further |
12461 | | * testing and feedback. |
12462 | | * |
12463 | | * @brief atomic_binary_to_base64 |
12464 | | * @param input the binary to process |
12465 | | * @param length the length of the input in bytes |
12466 | | * @param output the pointer to a buffer that can hold the conversion |
12467 | | * result (should be at least base64_length_from_binary(length) bytes long) |
12468 | | * @param options the base64 options to use, can be base64_default or |
12469 | | * base64_url, is base64_default by default. |
12470 | | * @return number of written bytes, will be equal to |
12471 | | * base64_length_from_binary(length, options) |
12472 | | */ |
12473 | | size_t |
12474 | | atomic_binary_to_base64(const char *input, size_t length, char *output, |
12475 | | base64_options options = base64_default) noexcept; |
12476 | | #if SIMDUTF_SPAN |
12477 | | simdutf_really_inline simdutf_warn_unused size_t |
12478 | | atomic_binary_to_base64(const detail::input_span_of_byte_like auto &input, |
12479 | | detail::output_span_of_byte_like auto &&binary_output, |
12480 | | base64_options options = base64_default) noexcept { |
12481 | | return atomic_binary_to_base64( |
12482 | | reinterpret_cast<const char *>(input.data()), input.size(), |
12483 | | reinterpret_cast<char *>(binary_output.data()), options); |
12484 | | } |
12485 | | #endif // SIMDUTF_SPAN |
12486 | | #endif // SIMDUTF_ATOMIC_REF |
12487 | | |
12488 | | /** |
12489 | | * Convert a base64 input to a binary output. |
12490 | | * |
12491 | | * This function follows the WHATWG forgiving-base64 format, which means that it |
12492 | | * will ignore any ASCII spaces in the input. You may provide a padded input |
12493 | | * (with one or two equal signs at the end) or an unpadded input (without any |
12494 | | * equal signs at the end). |
12495 | | * |
12496 | | * See https://infra.spec.whatwg.org/#forgiving-base64-decode |
12497 | | * |
12498 | | * This function will fail in case of invalid input. When last_chunk_options = |
12499 | | * loose, there are two possible reasons for failure: the input contains a |
12500 | | * number of base64 characters that when divided by 4, leaves a single remainder |
12501 | | * character (BASE64_INPUT_REMAINDER), or the input contains a character that is |
12502 | | * not a valid base64 character (INVALID_BASE64_CHARACTER). |
12503 | | * |
12504 | | * When the error is INVALID_BASE64_CHARACTER, r.count contains the index in the |
12505 | | * input where the invalid character was found. When the error is |
12506 | | * BASE64_INPUT_REMAINDER, then r.count contains the number of bytes decoded. |
12507 | | * |
12508 | | * The default option (simdutf::base64_default) expects the characters `+` and |
12509 | | * `/` as part of its alphabet. The URL option (simdutf::base64_url) expects the |
12510 | | * characters `-` and `_` as part of its alphabet. |
12511 | | * |
12512 | | * The padding (`=`) is validated if present. There may be at most two padding |
12513 | | * characters at the end of the input. If there are any padding characters, the |
12514 | | * total number of characters (excluding spaces but including padding |
12515 | | * characters) must be divisible by four. |
12516 | | * |
12517 | | * You should call this function with a buffer that is at least |
12518 | | * maximal_binary_length_from_base64(input, length) bytes long. If you fail |
12519 | | * to provide that much space, the function may cause a buffer overflow. |
12520 | | * |
12521 | | * Advanced users may want to tailor how the last chunk is handled. By default, |
12522 | | * we use a loose (forgiving) approach but we also support a strict approach |
12523 | | * as well as a stop_before_partial approach, as per the following proposal: |
12524 | | * |
12525 | | * https://tc39.es/proposal-arraybuffer-base64/spec/#sec-frombase64 |
12526 | | * |
12527 | | * @param input the base64 string to process, in ASCII stored as 16-bit |
12528 | | * units |
12529 | | * @param length the length of the string in 16-bit units |
12530 | | * @param output the pointer to a buffer that can hold the conversion |
12531 | | * result (should be at least maximal_binary_length_from_base64(input, length) |
12532 | | * bytes long). |
12533 | | * @param options the base64 options to use, can be base64_default or |
12534 | | * base64_url, is base64_default by default. |
12535 | | * @param last_chunk_options the last chunk handling options, |
12536 | | * last_chunk_handling_options::loose by default |
12537 | | * but can also be last_chunk_handling_options::strict or |
12538 | | * last_chunk_handling_options::stop_before_partial. |
12539 | | * @return a result pair struct (of type simdutf::result containing the two |
12540 | | * fields error and count) with an error code and position of the |
12541 | | * INVALID_BASE64_CHARACTER error (in the input in units) if any, or the number |
12542 | | * of bytes written if successful. |
12543 | | */ |
12544 | | simdutf_warn_unused result |
12545 | | base64_to_binary(const char16_t *input, size_t length, char *output, |
12546 | | base64_options options = base64_default, |
12547 | | last_chunk_handling_options last_chunk_options = |
12548 | | last_chunk_handling_options::loose) noexcept; |
12549 | | #if SIMDUTF_SPAN |
12550 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result |
12551 | | base64_to_binary( |
12552 | | std::span<const char16_t> input, |
12553 | | detail::output_span_of_byte_like auto &&binary_output, |
12554 | | base64_options options = base64_default, |
12555 | | last_chunk_handling_options last_chunk_options = loose) noexcept { |
12556 | | #if SIMDUTF_CPLUSPLUS23 |
12557 | | if consteval { |
12558 | | return scalar::base64::base64_to_binary_details_impl( |
12559 | | input.data(), input.size(), binary_output.data(), options, |
12560 | | last_chunk_options); |
12561 | | } else |
12562 | | #endif |
12563 | | { |
12564 | | return base64_to_binary(input.data(), input.size(), |
12565 | | reinterpret_cast<char *>(binary_output.data()), |
12566 | | options, last_chunk_options); |
12567 | | } |
12568 | | } |
12569 | | #endif // SIMDUTF_SPAN |
12570 | | |
12571 | | /** |
12572 | | * Convert a base64 input to a binary output while returning more details |
12573 | | * than base64_to_binary. |
12574 | | * |
12575 | | * This function follows the WHATWG forgiving-base64 format, which means that it |
12576 | | * will ignore any ASCII spaces in the input. You may provide a padded input |
12577 | | * (with one or two equal signs at the end) or an unpadded input (without any |
12578 | | * equal signs at the end). |
12579 | | * |
12580 | | * See https://infra.spec.whatwg.org/#forgiving-base64-decode |
12581 | | * |
12582 | | * Unlike base64_to_binary, this function returns a full_result with both |
12583 | | * input_count and output_count, so you always know how much input was consumed |
12584 | | * and how much output was written. There are three cases where the input may |
12585 | | * not be fully consumed: |
12586 | | * |
12587 | | * 1. stop_before_partial: When last_chunk_options is set to |
12588 | | * stop_before_partial, any incomplete 4-character group at the end of the |
12589 | | * input is left unconsumed. This is useful for streaming/chunked decoding |
12590 | | * where you can carry over the unconsumed input to the next chunk. |
12591 | | * |
12592 | | * 2. INVALID_BASE64_CHARACTER: The input contains a character that is not a |
12593 | | * valid base64 character. In this case, input_count indicates where the |
12594 | | * invalid character was found. |
12595 | | * |
12596 | | * 3. BASE64_INPUT_REMAINDER: When last_chunk_options is loose, the input |
12597 | | * contains a number of base64 characters that, when divided by 4, leaves |
12598 | | * a single remainder character (which cannot encode any bytes). |
12599 | | * |
12600 | | * You should call this function with a buffer that is at least |
12601 | | * maximal_binary_length_from_base64(input, length) bytes long. If you fail to |
12602 | | * provide that much space, the function may cause a buffer overflow. |
12603 | | * |
12604 | | * @param input the base64 string to process |
12605 | | * @param length the length of the string in bytes |
12606 | | * @param output the pointer to a buffer that can hold the conversion |
12607 | | * result (should be at least maximal_binary_length_from_base64(input, length) |
12608 | | * bytes long). |
12609 | | * @param options the base64 options to use, can be base64_default or |
12610 | | * base64_url, is base64_default by default. |
12611 | | * @param last_chunk_options the last chunk handling options, |
12612 | | * last_chunk_handling_options::loose by default |
12613 | | * but can also be last_chunk_handling_options::strict or |
12614 | | * last_chunk_handling_options::stop_before_partial. |
12615 | | * @return a full_result struct (of type simdutf::full_result containing the |
12616 | | * three fields error, input_count and output_count). |
12617 | | */ |
12618 | | simdutf_warn_unused full_result |
12619 | | base64_to_binary_details(const char *input, size_t length, char *output, |
12620 | | base64_options options = base64_default, |
12621 | | last_chunk_handling_options last_chunk_options = |
12622 | | last_chunk_handling_options::loose) noexcept; |
12623 | | #if SIMDUTF_SPAN |
12624 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 full_result |
12625 | | base64_to_binary_details( |
12626 | | const detail::input_span_of_byte_like auto &input, |
12627 | | detail::output_span_of_byte_like auto &&binary_output, |
12628 | | base64_options options = base64_default, |
12629 | | last_chunk_handling_options last_chunk_options = loose) noexcept { |
12630 | | #if SIMDUTF_CPLUSPLUS23 |
12631 | | if consteval { |
12632 | | return scalar::base64::base64_to_binary_details_impl( |
12633 | | input.data(), input.size(), binary_output.data(), options, |
12634 | | last_chunk_options); |
12635 | | } else |
12636 | | #endif |
12637 | | { |
12638 | | return base64_to_binary_details( |
12639 | | reinterpret_cast<const char *>(input.data()), input.size(), |
12640 | | reinterpret_cast<char *>(binary_output.data()), options, |
12641 | | last_chunk_options); |
12642 | | } |
12643 | | } |
12644 | | #endif // SIMDUTF_SPAN |
12645 | | |
12646 | | /** |
12647 | | * Convert a base64 input to a binary output while returning more details |
12648 | | * than base64_to_binary. |
12649 | | * |
12650 | | * This function follows the WHATWG forgiving-base64 format, which means that it |
12651 | | * will ignore any ASCII spaces in the input. You may provide a padded input |
12652 | | * (with one or two equal signs at the end) or an unpadded input (without any |
12653 | | * equal signs at the end). |
12654 | | * |
12655 | | * See https://infra.spec.whatwg.org/#forgiving-base64-decode |
12656 | | * |
12657 | | * Unlike base64_to_binary, this function returns a full_result with both |
12658 | | * input_count and output_count, so you always know how much input was consumed |
12659 | | * and how much output was written. There are three cases where the input may |
12660 | | * not be fully consumed: |
12661 | | * |
12662 | | * 1. stop_before_partial: When last_chunk_options is set to |
12663 | | * stop_before_partial, any incomplete 4-character group at the end of the |
12664 | | * input is left unconsumed. This is useful for streaming/chunked decoding |
12665 | | * where you can carry over the unconsumed input to the next chunk. |
12666 | | * |
12667 | | * 2. INVALID_BASE64_CHARACTER: The input contains a character that is not a |
12668 | | * valid base64 character. In this case, input_count indicates where the |
12669 | | * invalid character was found. |
12670 | | * |
12671 | | * 3. BASE64_INPUT_REMAINDER: When last_chunk_options is loose, the input |
12672 | | * contains a number of base64 characters that, when divided by 4, leaves |
12673 | | * a single remainder character (which cannot encode any bytes). |
12674 | | * |
12675 | | * You should call this function with a buffer that is at least |
12676 | | * maximal_binary_length_from_base64(input, length) bytes long. If you fail to |
12677 | | * provide that much space, the function may cause a buffer overflow. |
12678 | | * |
12679 | | * @param input the base64 string to process, in ASCII stored as 16-bit |
12680 | | * units |
12681 | | * @param length the length of the string in 16-bit units |
12682 | | * @param output the pointer to a buffer that can hold the conversion |
12683 | | * result (should be at least maximal_binary_length_from_base64(input, length) |
12684 | | * bytes long). |
12685 | | * @param options the base64 options to use, can be base64_default or |
12686 | | * base64_url, is base64_default by default. |
12687 | | * @param last_chunk_options the last chunk handling options, |
12688 | | * last_chunk_handling_options::loose by default |
12689 | | * but can also be last_chunk_handling_options::strict or |
12690 | | * last_chunk_handling_options::stop_before_partial. |
12691 | | * @return a full_result struct (of type simdutf::full_result containing the |
12692 | | * three fields error, input_count and output_count). |
12693 | | */ |
12694 | | simdutf_warn_unused full_result |
12695 | | base64_to_binary_details(const char16_t *input, size_t length, char *output, |
12696 | | base64_options options = base64_default, |
12697 | | last_chunk_handling_options last_chunk_options = |
12698 | | last_chunk_handling_options::loose) noexcept; |
12699 | | #if SIMDUTF_SPAN |
12700 | | simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 full_result |
12701 | | base64_to_binary_details( |
12702 | | std::span<const char16_t> input, |
12703 | | detail::output_span_of_byte_like auto &&binary_output, |
12704 | | base64_options options = base64_default, |
12705 | | last_chunk_handling_options last_chunk_options = loose) noexcept { |
12706 | | #if SIMDUTF_CPLUSPLUS23 |
12707 | | if consteval { |
12708 | | return scalar::base64::base64_to_binary_details_impl( |
12709 | | input.data(), input.size(), binary_output.data(), options, |
12710 | | last_chunk_options); |
12711 | | } else |
12712 | | #endif |
12713 | | { |
12714 | | return base64_to_binary_details( |
12715 | | input.data(), input.size(), |
12716 | | reinterpret_cast<char *>(binary_output.data()), options, |
12717 | | last_chunk_options); |
12718 | | } |
12719 | | } |
12720 | | #endif // SIMDUTF_SPAN |
12721 | | |
12722 | | /** |
12723 | | * Check if a character is an ignorable base64 character. |
12724 | | * Checking a large input, character by character, is not computationally |
12725 | | * efficient. |
12726 | | * |
12727 | | * @param input the character to check |
12728 | | * @param options the base64 options to use, is base64_default by default. |
12729 | | * @return true if the character is an ignorable base64 character, false |
12730 | | * otherwise. |
12731 | | */ |
12732 | | simdutf_warn_unused simdutf_really_inline simdutf_constexpr23 bool |
12733 | 0 | base64_ignorable(char input, base64_options options = base64_default) noexcept { |
12734 | 0 | return scalar::base64::is_ignorable(input, options); |
12735 | 0 | } |
12736 | | simdutf_warn_unused simdutf_really_inline simdutf_constexpr23 bool |
12737 | | base64_ignorable(char16_t input, |
12738 | 0 | base64_options options = base64_default) noexcept { |
12739 | 0 | return scalar::base64::is_ignorable(input, options); |
12740 | 0 | } |
12741 | | |
12742 | | /** |
12743 | | * Check if a character is a valid base64 character. |
12744 | | * Checking a large input, character by character, is not computationally |
12745 | | * efficient. |
12746 | | * Note that padding characters are not considered valid base64 characters in |
12747 | | * this context, nor are spaces. |
12748 | | * |
12749 | | * @param input the character to check |
12750 | | * @param options the base64 options to use, is base64_default by default. |
12751 | | * @return true if the character is a base64 character, false otherwise. |
12752 | | */ |
12753 | | simdutf_warn_unused simdutf_really_inline simdutf_constexpr23 bool |
12754 | 0 | base64_valid(char input, base64_options options = base64_default) noexcept { |
12755 | 0 | return scalar::base64::is_base64(input, options); |
12756 | 0 | } |
12757 | | simdutf_warn_unused simdutf_really_inline simdutf_constexpr23 bool |
12758 | 0 | base64_valid(char16_t input, base64_options options = base64_default) noexcept { |
12759 | 0 | return scalar::base64::is_base64(input, options); |
12760 | 0 | } |
12761 | | |
12762 | | /** |
12763 | | * Check if a character is a valid base64 character or the padding character |
12764 | | * ('='). Checking a large input, character by character, is not computationally |
12765 | | * efficient. |
12766 | | * |
12767 | | * @param input the character to check |
12768 | | * @param options the base64 options to use, is base64_default by default. |
12769 | | * @return true if the character is a base64 character, false otherwise. |
12770 | | */ |
12771 | | simdutf_warn_unused simdutf_really_inline simdutf_constexpr23 bool |
12772 | | base64_valid_or_padding(char input, |
12773 | 0 | base64_options options = base64_default) noexcept { |
12774 | 0 | return scalar::base64::is_base64_or_padding(input, options); |
12775 | 0 | } |
12776 | | simdutf_warn_unused simdutf_really_inline simdutf_constexpr23 bool |
12777 | | base64_valid_or_padding(char16_t input, |
12778 | 0 | base64_options options = base64_default) noexcept { |
12779 | 0 | return scalar::base64::is_base64_or_padding(input, options); |
12780 | 0 | } |
12781 | | |
12782 | | /** |
12783 | | * Convert a base64 input to a binary output. |
12784 | | * |
12785 | | * This function follows the WHATWG forgiving-base64 format, which means that it |
12786 | | * will ignore any ASCII spaces in the input. You may provide a padded input |
12787 | | * (with one or two equal signs at the end) or an unpadded input (without any |
12788 | | * equal signs at the end). |
12789 | | * |
12790 | | * See https://infra.spec.whatwg.org/#forgiving-base64-decode |
12791 | | * |
12792 | | * This function will fail in case of invalid input. When last_chunk_options = |
12793 | | * loose, there are three possible reasons for failure: the input contains a |
12794 | | * number of base64 characters that when divided by 4, leaves a single remainder |
12795 | | * character (BASE64_INPUT_REMAINDER), the input contains a character that is |
12796 | | * not a valid base64 character (INVALID_BASE64_CHARACTER), or the output buffer |
12797 | | * is too small (OUTPUT_BUFFER_TOO_SMALL). |
12798 | | * |
12799 | | * When OUTPUT_BUFFER_TOO_SMALL, we return both the number of bytes written |
12800 | | * and the number of units processed, see description of the parameters and |
12801 | | * returned value. |
12802 | | * |
12803 | | * When the error is INVALID_BASE64_CHARACTER, r.count contains the index in the |
12804 | | * input where the invalid character was found. When the error is |
12805 | | * BASE64_INPUT_REMAINDER, then r.count contains the number of bytes decoded. |
12806 | | * |
12807 | | * The default option (simdutf::base64_default) expects the characters `+` and |
12808 | | * `/` as part of its alphabet. The URL option (simdutf::base64_url) expects the |
12809 | | * characters `-` and `_` as part of its alphabet. |
12810 | | * |
12811 | | * The padding (`=`) is validated if present. There may be at most two padding |
12812 | | * characters at the end of the input. If there are any padding characters, the |
12813 | | * total number of characters (excluding spaces but including padding |
12814 | | * characters) must be divisible by four. |
12815 | | * |
12816 | | * The INVALID_BASE64_CHARACTER cases are considered fatal and you are expected |
12817 | | * to discard the output unless the parameter decode_up_to_bad_char is set to |
12818 | | * true. In that case, the function will decode up to the first invalid |
12819 | | * character. Extra padding characters ('=') are considered invalid characters. |
12820 | | * |
12821 | | * Advanced users may want to tailor how the last chunk is handled. By default, |
12822 | | * we use a loose (forgiving) approach but we also support a strict approach |
12823 | | * as well as a stop_before_partial approach, as per the following proposal: |
12824 | | * |
12825 | | * https://tc39.es/proposal-arraybuffer-base64/spec/#sec-frombase64 |
12826 | | * |
12827 | | * The base64_to_binary_safe function has negligible overhead compared with |
12828 | | * base64_to_binary in the absence of ignorable characters; however, on short |
12829 | | * inputs containing ignorable characters, it can be up to three times slower. |
12830 | | * |
12831 | | * @param input the base64 string to process, in ASCII stored as 8-bit |
12832 | | * or 16-bit units |
12833 | | * @param length the length of the string in 8-bit or 16-bit units. |
12834 | | * @param output the pointer to a buffer that can hold the conversion |
12835 | | * result. |
12836 | | * @param outlen the number of bytes that can be written in the output |
12837 | | * buffer. Upon return, it is modified to reflect how many bytes were written. |
12838 | | * @param options the base64 options to use, can be base64_default or |
12839 | | * base64_url, is base64_default by default. |
12840 | | * @param last_chunk_options the last chunk handling options, |
12841 | | * last_chunk_handling_options::loose by default |
12842 | | * but can also be last_chunk_handling_options::strict or |
12843 | | * last_chunk_handling_options::stop_before_partial. |
12844 | | * @param decode_up_to_bad_char if true, the function will decode up to the |
12845 | | * first invalid character. By default (false), it is assumed that the output |
12846 | | * buffer is to be discarded. When there are multiple errors in the input, |
12847 | | * using decode_up_to_bad_char might trigger a different error. |
12848 | | * @return a result pair struct (of type simdutf::result containing the two |
12849 | | * fields error and count) with an error code and position of the |
12850 | | * INVALID_BASE64_CHARACTER error (in the input in units) if any, or the number |
12851 | | * of units processed if successful. |
12852 | | */ |
12853 | | simdutf_warn_unused result |
12854 | | base64_to_binary_safe(const char *input, size_t length, char *output, |
12855 | | size_t &outlen, base64_options options = base64_default, |
12856 | | last_chunk_handling_options last_chunk_options = |
12857 | | last_chunk_handling_options::loose, |
12858 | | bool decode_up_to_bad_char = false) noexcept; |
12859 | | // the span overload has moved to the bottom of the file |
12860 | | |
12861 | | simdutf_warn_unused result |
12862 | | base64_to_binary_safe(const char16_t *input, size_t length, char *output, |
12863 | | size_t &outlen, base64_options options = base64_default, |
12864 | | last_chunk_handling_options last_chunk_options = |
12865 | | last_chunk_handling_options::loose, |
12866 | | bool decode_up_to_bad_char = false) noexcept; |
12867 | | // span overload moved to bottom of file |
12868 | | |
12869 | | #if SIMDUTF_ATOMIC_REF |
12870 | | /** |
12871 | | * Convert a base64 input to a binary output with a size limit and using atomic |
12872 | | * operations. |
12873 | | * |
12874 | | * Like `base64_to_binary_safe` but using atomic operations, this function is |
12875 | | * thread-safe for concurrent memory access, allowing the output |
12876 | | * buffers to be shared between threads without undefined behavior in case of |
12877 | | * data races. |
12878 | | * |
12879 | | * This function comes with a potentially significant performance penalty, but |
12880 | | * is useful when thread safety is needed during base64 decoding. |
12881 | | * |
12882 | | * This function is only available when simdutf is compiled with |
12883 | | * C++20 support and __cpp_lib_atomic_ref >= 201806L. You may check |
12884 | | * the availability of this function by checking the macro |
12885 | | * SIMDUTF_ATOMIC_REF. |
12886 | | * |
12887 | | * This function is considered experimental. It is not tested by default |
12888 | | * (see the CMake option SIMDUTF_ATOMIC_BASE64_TESTS) nor is it fuzz tested. |
12889 | | * It is not documented in the public API documentation (README). It is |
12890 | | * offered on a best effort basis. We rely on the community for further |
12891 | | * testing and feedback. |
12892 | | * |
12893 | | * @param input the base64 input to decode |
12894 | | * @param length the length of the input in bytes |
12895 | | * @param output the pointer to buffer that can hold the conversion |
12896 | | * result |
12897 | | * @param outlen the number of bytes that can be written in the output |
12898 | | * buffer. Upon return, it is modified to reflect how many bytes were written. |
12899 | | * @param options the base64 options to use (default, url, etc.) |
12900 | | * @param last_chunk_options the last chunk handling options (loose, strict, |
12901 | | * stop_before_partial) |
12902 | | * @param decode_up_to_bad_char if true, the function will decode up to the |
12903 | | * first invalid character. By default (false), it is assumed that the output |
12904 | | * buffer is to be discarded. When there are multiple errors in the input, |
12905 | | * using decode_up_to_bad_char might trigger a different error. |
12906 | | * @return a result struct with an error code and count indicating error |
12907 | | * position or success |
12908 | | */ |
12909 | | simdutf_warn_unused result atomic_base64_to_binary_safe( |
12910 | | const char *input, size_t length, char *output, size_t &outlen, |
12911 | | base64_options options = base64_default, |
12912 | | last_chunk_handling_options last_chunk_options = |
12913 | | last_chunk_handling_options::loose, |
12914 | | bool decode_up_to_bad_char = false) noexcept; |
12915 | | simdutf_warn_unused result atomic_base64_to_binary_safe( |
12916 | | const char16_t *input, size_t length, char *output, size_t &outlen, |
12917 | | base64_options options = base64_default, |
12918 | | last_chunk_handling_options last_chunk_options = loose, |
12919 | | bool decode_up_to_bad_char = false) noexcept; |
12920 | | #if SIMDUTF_SPAN |
12921 | | /** |
12922 | | * @brief span overload |
12923 | | * @return a tuple of result and outlen |
12924 | | */ |
12925 | | simdutf_really_inline simdutf_warn_unused std::tuple<result, std::size_t> |
12926 | | atomic_base64_to_binary_safe( |
12927 | | const detail::input_span_of_byte_like auto &binary_input, |
12928 | | detail::output_span_of_byte_like auto &&output, |
12929 | | base64_options options = base64_default, |
12930 | | last_chunk_handling_options last_chunk_options = |
12931 | | last_chunk_handling_options::loose, |
12932 | | bool decode_up_to_bad_char = false) noexcept { |
12933 | | size_t outlen = output.size(); |
12934 | | auto ret = atomic_base64_to_binary_safe( |
12935 | | reinterpret_cast<const char *>(binary_input.data()), binary_input.size(), |
12936 | | reinterpret_cast<char *>(output.data()), outlen, options, |
12937 | | last_chunk_options, decode_up_to_bad_char); |
12938 | | return {ret, outlen}; |
12939 | | } |
12940 | | /** |
12941 | | * @brief span overload |
12942 | | * @return a tuple of result and outlen |
12943 | | */ |
12944 | | simdutf_warn_unused std::tuple<result, std::size_t> |
12945 | | atomic_base64_to_binary_safe( |
12946 | | std::span<const char16_t> base64_input, |
12947 | | detail::output_span_of_byte_like auto &&binary_output, |
12948 | | base64_options options = base64_default, |
12949 | | last_chunk_handling_options last_chunk_options = loose, |
12950 | | bool decode_up_to_bad_char = false) noexcept { |
12951 | | size_t outlen = binary_output.size(); |
12952 | | auto ret = atomic_base64_to_binary_safe( |
12953 | | base64_input.data(), base64_input.size(), |
12954 | | reinterpret_cast<char *>(binary_output.data()), outlen, options, |
12955 | | last_chunk_options, decode_up_to_bad_char); |
12956 | | return {ret, outlen}; |
12957 | | } |
12958 | | #endif // SIMDUTF_SPAN |
12959 | | #endif // SIMDUTF_ATOMIC_REF |
12960 | | |
12961 | | #endif // SIMDUTF_FEATURE_BASE64 |
12962 | | |
12963 | | /** |
12964 | | * An implementation of simdutf for a particular CPU architecture. |
12965 | | * |
12966 | | * Also used to maintain the currently active implementation. The active |
12967 | | * implementation is automatically initialized on first use to the most advanced |
12968 | | * implementation supported by the host. |
12969 | | */ |
12970 | | class implementation { |
12971 | | public: |
12972 | | /** |
12973 | | * The name of this implementation. |
12974 | | * |
12975 | | * const implementation *impl = simdutf::active_implementation; |
12976 | | * cout << "simdutf is optimized for " << impl->name() << "(" << |
12977 | | * impl->description() << ")" << endl; |
12978 | | * |
12979 | | * @return the name of the implementation, e.g. "haswell", "westmere", "arm64" |
12980 | | */ |
12981 | 0 | virtual std::string_view name() const noexcept { return _name; } |
12982 | | |
12983 | | /** |
12984 | | * The description of this implementation. |
12985 | | * |
12986 | | * const implementation *impl = simdutf::active_implementation; |
12987 | | * cout << "simdutf is optimized for " << impl->name() << "(" << |
12988 | | * impl->description() << ")" << endl; |
12989 | | * |
12990 | | * @return the name of the implementation, e.g. "haswell", "westmere", "arm64" |
12991 | | */ |
12992 | 0 | virtual std::string_view description() const noexcept { return _description; } |
12993 | | |
12994 | | /** |
12995 | | * The instruction sets this implementation is compiled against |
12996 | | * and the current CPU match. This function may poll the current CPU/system |
12997 | | * and should therefore not be called too often if performance is a concern. |
12998 | | * |
12999 | | * |
13000 | | * @return true if the implementation can be safely used on the current system |
13001 | | * (determined at runtime) |
13002 | | */ |
13003 | | bool supported_by_runtime_system() const; |
13004 | | |
13005 | | #if SIMDUTF_FEATURE_DETECT_ENCODING |
13006 | | /** |
13007 | | * This function will try to detect the encoding |
13008 | | * @param input the string to identify |
13009 | | * @param length the length of the string in bytes. |
13010 | | * @return the encoding type detected |
13011 | | */ |
13012 | | virtual encoding_type autodetect_encoding(const char *input, |
13013 | | size_t length) const noexcept; |
13014 | | |
13015 | | /** |
13016 | | * This function will try to detect the possible encodings in one pass |
13017 | | * @param input the string to identify |
13018 | | * @param length the length of the string in bytes. |
13019 | | * @return the encoding type detected |
13020 | | */ |
13021 | | virtual int detect_encodings(const char *input, |
13022 | | size_t length) const noexcept = 0; |
13023 | | #endif // SIMDUTF_FEATURE_DETECT_ENCODING |
13024 | | |
13025 | | /** |
13026 | | * @private For internal implementation use |
13027 | | * |
13028 | | * The instruction sets this implementation is compiled against. |
13029 | | * |
13030 | | * @return a mask of all required `internal::instruction_set::` values |
13031 | | */ |
13032 | 2 | virtual uint32_t required_instruction_sets() const { |
13033 | 2 | return _required_instruction_sets; |
13034 | 2 | } |
13035 | | |
13036 | | #if SIMDUTF_FEATURE_UTF8 || SIMDUTF_FEATURE_DETECT_ENCODING |
13037 | | /** |
13038 | | * Validate the UTF-8 string. |
13039 | | * |
13040 | | * Overridden by each implementation. |
13041 | | * |
13042 | | * @param buf the UTF-8 string to validate. |
13043 | | * @param len the length of the string in bytes. |
13044 | | * @return true if and only if the string is valid UTF-8. |
13045 | | */ |
13046 | | simdutf_warn_unused virtual bool validate_utf8(const char *buf, |
13047 | | size_t len) const noexcept = 0; |
13048 | | #endif // SIMDUTF_FEATURE_UTF8 || SIMDUTF_FEATURE_DETECT_ENCODING |
13049 | | |
13050 | | #if SIMDUTF_FEATURE_UTF8 |
13051 | | /** |
13052 | | * Validate the UTF-8 string and stop on errors. |
13053 | | * |
13054 | | * Overridden by each implementation. |
13055 | | * |
13056 | | * @param buf the UTF-8 string to validate. |
13057 | | * @param len the length of the string in bytes. |
13058 | | * @return a result pair struct (of type simdutf::result containing the two |
13059 | | * fields error and count) with an error code and either position of the error |
13060 | | * (in the input in code units) if any, or the number of code units validated |
13061 | | * if successful. |
13062 | | */ |
13063 | | simdutf_warn_unused virtual result |
13064 | | validate_utf8_with_errors(const char *buf, size_t len) const noexcept = 0; |
13065 | | /** |
13066 | | * Finds the pointer to the first byte of invalid utf8 while counting |
13067 | | continuation bytes and four-byte sequences. |
13068 | | |
13069 | | * @param buf the UTF-8 string to validate. |
13070 | | * @param len the length of the string in bytes. |
13071 | | * @return a utf8_result struct. It contains the length of the valid utf8 |
13072 | | segment, the error code and the count of continuation bytes and four-byte |
13073 | | sequences. |
13074 | | * |
13075 | | * Returns a utf8_result |
13076 | | */ |
13077 | | virtual simdutf_warn_unused utf8_result |
13078 | | validate_utf8_with_counts(const char *buf, size_t len) const noexcept = 0; |
13079 | | |
13080 | | #endif // SIMDUTF_FEATURE_UTF8 |
13081 | | |
13082 | | #if SIMDUTF_FEATURE_ASCII |
13083 | | /** |
13084 | | * Validate the ASCII string. |
13085 | | * |
13086 | | * Overridden by each implementation. |
13087 | | * |
13088 | | * @param buf the ASCII string to validate. |
13089 | | * @param len the length of the string in bytes. |
13090 | | * @return true if and only if the string is valid ASCII. |
13091 | | */ |
13092 | | simdutf_warn_unused virtual bool |
13093 | | validate_ascii(const char *buf, size_t len) const noexcept = 0; |
13094 | | |
13095 | | /** |
13096 | | * Validate the ASCII string and stop on error. |
13097 | | * |
13098 | | * Overridden by each implementation. |
13099 | | * |
13100 | | * @param buf the ASCII string to validate. |
13101 | | * @param len the length of the string in bytes. |
13102 | | * @return a result pair struct (of type simdutf::result containing the two |
13103 | | * fields error and count) with an error code and either position of the error |
13104 | | * (in the input in code units) if any, or the number of code units validated |
13105 | | * if successful. |
13106 | | */ |
13107 | | simdutf_warn_unused virtual result |
13108 | | validate_ascii_with_errors(const char *buf, size_t len) const noexcept = 0; |
13109 | | |
13110 | | #endif // SIMDUTF_FEATURE_ASCII |
13111 | | |
13112 | | #if SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_ASCII |
13113 | | /** |
13114 | | * Validate the ASCII string as a UTF-16BE sequence. |
13115 | | * An UTF-16 sequence is considered an ASCII sequence |
13116 | | * if it could be converted to an ASCII string losslessly. |
13117 | | * |
13118 | | * Overridden by each implementation. |
13119 | | * |
13120 | | * @param buf the UTF-16BE string to validate. |
13121 | | * @param len the length of the string in bytes. |
13122 | | * @return true if and only if the string is valid ASCII. |
13123 | | */ |
13124 | | simdutf_warn_unused virtual bool |
13125 | | validate_utf16be_as_ascii(const char16_t *buf, size_t len) const noexcept = 0; |
13126 | | |
13127 | | /** |
13128 | | * Validate the ASCII string as a UTF-16LE sequence. |
13129 | | * An UTF-16 sequence is considered an ASCII sequence |
13130 | | * if it could be converted to an ASCII string losslessly. |
13131 | | * |
13132 | | * Overridden by each implementation. |
13133 | | * |
13134 | | * @param buf the UTF-16LE string to validate. |
13135 | | * @param len the length of the string in bytes. |
13136 | | * @return true if and only if the string is valid ASCII. |
13137 | | */ |
13138 | | simdutf_warn_unused virtual bool |
13139 | | validate_utf16le_as_ascii(const char16_t *buf, size_t len) const noexcept = 0; |
13140 | | #endif // SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_ASCII |
13141 | | |
13142 | | #if SIMDUTF_FEATURE_UTF16 || SIMDUTF_FEATURE_DETECT_ENCODING |
13143 | | /** |
13144 | | * Validate the UTF-16LE string.This function may be best when you expect |
13145 | | * the input to be almost always valid. Otherwise, consider using |
13146 | | * validate_utf16le_with_errors. |
13147 | | * |
13148 | | * Overridden by each implementation. |
13149 | | * |
13150 | | * This function is not BOM-aware. |
13151 | | * |
13152 | | * @param buf the UTF-16LE string to validate. |
13153 | | * @param len the length of the string in number of 2-byte code units |
13154 | | * (char16_t). |
13155 | | * @return true if and only if the string is valid UTF-16LE. |
13156 | | */ |
13157 | | simdutf_warn_unused virtual bool |
13158 | | validate_utf16le(const char16_t *buf, size_t len) const noexcept = 0; |
13159 | | #endif // SIMDUTF_FEATURE_UTF16 || SIMDUTF_FEATURE_DETECT_ENCODING |
13160 | | |
13161 | | #if SIMDUTF_FEATURE_UTF16 |
13162 | | /** |
13163 | | * Validate the UTF-16BE string. This function may be best when you expect |
13164 | | * the input to be almost always valid. Otherwise, consider using |
13165 | | * validate_utf16be_with_errors. |
13166 | | * |
13167 | | * Overridden by each implementation. |
13168 | | * |
13169 | | * This function is not BOM-aware. |
13170 | | * |
13171 | | * @param buf the UTF-16BE string to validate. |
13172 | | * @param len the length of the string in number of 2-byte code units |
13173 | | * (char16_t). |
13174 | | * @return true if and only if the string is valid UTF-16BE. |
13175 | | */ |
13176 | | simdutf_warn_unused virtual bool |
13177 | | validate_utf16be(const char16_t *buf, size_t len) const noexcept = 0; |
13178 | | |
13179 | | /** |
13180 | | * Validate the UTF-16LE string and stop on error. It might be faster than |
13181 | | * validate_utf16le when an error is expected to occur early. |
13182 | | * |
13183 | | * Overridden by each implementation. |
13184 | | * |
13185 | | * This function is not BOM-aware. |
13186 | | * |
13187 | | * @param buf the UTF-16LE string to validate. |
13188 | | * @param len the length of the string in number of 2-byte code units |
13189 | | * (char16_t). |
13190 | | * @return a result pair struct (of type simdutf::result containing the two |
13191 | | * fields error and count) with an error code and either position of the error |
13192 | | * (in the input in code units) if any, or the number of code units validated |
13193 | | * if successful. |
13194 | | */ |
13195 | | simdutf_warn_unused virtual result |
13196 | | validate_utf16le_with_errors(const char16_t *buf, |
13197 | | size_t len) const noexcept = 0; |
13198 | | |
13199 | | /** |
13200 | | * Validate the UTF-16BE string and stop on error. It might be faster than |
13201 | | * validate_utf16be when an error is expected to occur early. |
13202 | | * |
13203 | | * Overridden by each implementation. |
13204 | | * |
13205 | | * This function is not BOM-aware. |
13206 | | * |
13207 | | * @param buf the UTF-16BE string to validate. |
13208 | | * @param len the length of the string in number of 2-byte code units |
13209 | | * (char16_t). |
13210 | | * @return a result pair struct (of type simdutf::result containing the two |
13211 | | * fields error and count) with an error code and either position of the error |
13212 | | * (in the input in code units) if any, or the number of code units validated |
13213 | | * if successful. |
13214 | | */ |
13215 | | simdutf_warn_unused virtual result |
13216 | | validate_utf16be_with_errors(const char16_t *buf, |
13217 | | size_t len) const noexcept = 0; |
13218 | | /** |
13219 | | * Copies the UTF-16LE string while replacing mismatched surrogates with the |
13220 | | * Unicode replacement character U+FFFD. We allow the input and output to be |
13221 | | * the same buffer so that the correction is done in-place. |
13222 | | * |
13223 | | * Overridden by each implementation. |
13224 | | * |
13225 | | * @param input the UTF-16LE string to correct. |
13226 | | * @param len the length of the string in number of 2-byte code units |
13227 | | * (char16_t). |
13228 | | * @param output the output buffer. |
13229 | | */ |
13230 | | virtual void to_well_formed_utf16le(const char16_t *input, size_t len, |
13231 | | char16_t *output) const noexcept = 0; |
13232 | | /** |
13233 | | * Copies the UTF-16BE string while replacing mismatched surrogates with the |
13234 | | * Unicode replacement character U+FFFD. We allow the input and output to be |
13235 | | * the same buffer so that the correction is done in-place. |
13236 | | * |
13237 | | * Overridden by each implementation. |
13238 | | * |
13239 | | * @param input the UTF-16BE string to correct. |
13240 | | * @param len the length of the string in number of 2-byte code units |
13241 | | * (char16_t). |
13242 | | * @param output the output buffer. |
13243 | | */ |
13244 | | virtual void to_well_formed_utf16be(const char16_t *input, size_t len, |
13245 | | char16_t *output) const noexcept = 0; |
13246 | | #endif // SIMDUTF_FEATURE_UTF16 |
13247 | | |
13248 | | #if SIMDUTF_FEATURE_UTF32 || SIMDUTF_FEATURE_DETECT_ENCODING |
13249 | | /** |
13250 | | * Validate the UTF-32 string. |
13251 | | * |
13252 | | * Overridden by each implementation. |
13253 | | * |
13254 | | * This function is not BOM-aware. |
13255 | | * |
13256 | | * @param buf the UTF-32 string to validate. |
13257 | | * @param len the length of the string in number of 4-byte code units |
13258 | | * (char32_t). |
13259 | | * @return true if and only if the string is valid UTF-32. |
13260 | | */ |
13261 | | simdutf_warn_unused virtual bool |
13262 | | validate_utf32(const char32_t *buf, size_t len) const noexcept = 0; |
13263 | | #endif // SIMDUTF_FEATURE_UTF32 || SIMDUTF_FEATURE_DETECT_ENCODING |
13264 | | |
13265 | | #if SIMDUTF_FEATURE_UTF32 |
13266 | | /** |
13267 | | * Validate the UTF-32 string and stop on error. |
13268 | | * |
13269 | | * Overridden by each implementation. |
13270 | | * |
13271 | | * This function is not BOM-aware. |
13272 | | * |
13273 | | * @param buf the UTF-32 string to validate. |
13274 | | * @param len the length of the string in number of 4-byte code units |
13275 | | * (char32_t). |
13276 | | * @return a result pair struct (of type simdutf::result containing the two |
13277 | | * fields error and count) with an error code and either position of the error |
13278 | | * (in the input in code units) if any, or the number of code units validated |
13279 | | * if successful. |
13280 | | */ |
13281 | | simdutf_warn_unused virtual result |
13282 | | validate_utf32_with_errors(const char32_t *buf, |
13283 | | size_t len) const noexcept = 0; |
13284 | | #endif // SIMDUTF_FEATURE_UTF32 |
13285 | | |
13286 | | #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_LATIN1 |
13287 | | /** |
13288 | | * Convert Latin1 string into UTF-8 string. |
13289 | | * |
13290 | | * This function is suitable to work with inputs from untrusted sources. |
13291 | | * |
13292 | | * @param input the Latin1 string to convert |
13293 | | * @param length the length of the string in bytes |
13294 | | * @param utf8_output the pointer to buffer that can hold conversion result |
13295 | | * @return the number of written char; 0 if conversion is not possible |
13296 | | */ |
13297 | | simdutf_warn_unused virtual size_t |
13298 | | convert_latin1_to_utf8(const char *input, size_t length, |
13299 | | char *utf8_output) const noexcept = 0; |
13300 | | #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_LATIN1 |
13301 | | |
13302 | | #if SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_LATIN1 |
13303 | | /** |
13304 | | * Convert possibly Latin1 string into UTF-16LE string. |
13305 | | * |
13306 | | * This function is suitable to work with inputs from untrusted sources. |
13307 | | * |
13308 | | * @param input the Latin1 string to convert |
13309 | | * @param length the length of the string in bytes |
13310 | | * @param utf16_output the pointer to buffer that can hold conversion result |
13311 | | * @return the number of written char16_t; 0 if conversion is not possible |
13312 | | */ |
13313 | | simdutf_warn_unused virtual size_t |
13314 | | convert_latin1_to_utf16le(const char *input, size_t length, |
13315 | | char16_t *utf16_output) const noexcept = 0; |
13316 | | |
13317 | | /** |
13318 | | * Convert Latin1 string into UTF-16BE string. |
13319 | | * |
13320 | | * This function is suitable to work with inputs from untrusted sources. |
13321 | | * |
13322 | | * @param input the Latin1 string to convert |
13323 | | * @param length the length of the string in bytes |
13324 | | * @param utf16_output the pointer to buffer that can hold conversion result |
13325 | | * @return the number of written char16_t; 0 if conversion is not possible |
13326 | | */ |
13327 | | simdutf_warn_unused virtual size_t |
13328 | | convert_latin1_to_utf16be(const char *input, size_t length, |
13329 | | char16_t *utf16_output) const noexcept = 0; |
13330 | | #endif // SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_LATIN1 |
13331 | | |
13332 | | #if SIMDUTF_FEATURE_UTF32 && SIMDUTF_FEATURE_LATIN1 |
13333 | | /** |
13334 | | * Convert Latin1 string into UTF-32 string. |
13335 | | * |
13336 | | * This function is suitable to work with inputs from untrusted sources. |
13337 | | * |
13338 | | * @param input the Latin1 string to convert |
13339 | | * @param length the length of the string in bytes |
13340 | | * @param utf32_buffer the pointer to buffer that can hold conversion result |
13341 | | * @return the number of written char32_t; 0 if conversion is not possible |
13342 | | */ |
13343 | | simdutf_warn_unused virtual size_t |
13344 | | convert_latin1_to_utf32(const char *input, size_t length, |
13345 | | char32_t *utf32_buffer) const noexcept = 0; |
13346 | | #endif // SIMDUTF_FEATURE_UTF32 && SIMDUTF_FEATURE_LATIN1 |
13347 | | |
13348 | | #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_LATIN1 |
13349 | | /** |
13350 | | * Convert possibly broken UTF-8 string into latin1 string. |
13351 | | * |
13352 | | * During the conversion also validation of the input string is done. |
13353 | | * This function is suitable to work with inputs from untrusted sources. |
13354 | | * |
13355 | | * @param input the UTF-8 string to convert |
13356 | | * @param length the length of the string in bytes |
13357 | | * @param latin1_output the pointer to buffer that can hold conversion result |
13358 | | * @return the number of written char; 0 if the input was not valid UTF-8 |
13359 | | * string or if it cannot be represented as Latin1 |
13360 | | */ |
13361 | | simdutf_warn_unused virtual size_t |
13362 | | convert_utf8_to_latin1(const char *input, size_t length, |
13363 | | char *latin1_output) const noexcept = 0; |
13364 | | |
13365 | | /** |
13366 | | * Convert possibly broken UTF-8 string into latin1 string with errors. |
13367 | | * If the string cannot be represented as Latin1, an error |
13368 | | * code is returned. |
13369 | | * |
13370 | | * During the conversion also validation of the input string is done. |
13371 | | * This function is suitable to work with inputs from untrusted sources. |
13372 | | * |
13373 | | * @param input the UTF-8 string to convert |
13374 | | * @param length the length of the string in bytes |
13375 | | * @param latin1_output the pointer to buffer that can hold conversion result |
13376 | | * @return a result pair struct (of type simdutf::result containing the two |
13377 | | * fields error and count) with an error code and either position of the error |
13378 | | * (in the input in code units) if any, or the number of code units validated |
13379 | | * if successful. |
13380 | | */ |
13381 | | simdutf_warn_unused virtual result |
13382 | | convert_utf8_to_latin1_with_errors(const char *input, size_t length, |
13383 | | char *latin1_output) const noexcept = 0; |
13384 | | |
13385 | | /** |
13386 | | * Convert valid UTF-8 string into latin1 string. |
13387 | | * |
13388 | | * This function assumes that the input string is valid UTF-8 and that it can |
13389 | | * be represented as Latin1. If you violate this assumption, the result is |
13390 | | * implementation defined and may include system-dependent behavior such as |
13391 | | * crashes. |
13392 | | * |
13393 | | * This function is for expert users only and not part of our public API. Use |
13394 | | * convert_utf8_to_latin1 instead. |
13395 | | * |
13396 | | * This function is not BOM-aware. |
13397 | | * |
13398 | | * @param input the UTF-8 string to convert |
13399 | | * @param length the length of the string in bytes |
13400 | | * @param latin1_output the pointer to buffer that can hold conversion result |
13401 | | * @return the number of written char; 0 if the input was not valid UTF-8 |
13402 | | * string |
13403 | | */ |
13404 | | simdutf_warn_unused virtual size_t |
13405 | | convert_valid_utf8_to_latin1(const char *input, size_t length, |
13406 | | char *latin1_output) const noexcept = 0; |
13407 | | #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_LATIN1 |
13408 | | |
13409 | | #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 |
13410 | | /** |
13411 | | * Convert possibly broken UTF-8 string into UTF-16LE string. |
13412 | | * |
13413 | | * During the conversion also validation of the input string is done. |
13414 | | * This function is suitable to work with inputs from untrusted sources. |
13415 | | * |
13416 | | * @param input the UTF-8 string to convert |
13417 | | * @param length the length of the string in bytes |
13418 | | * @param utf16_output the pointer to buffer that can hold conversion result |
13419 | | * @return the number of written char16_t; 0 if the input was not valid UTF-8 |
13420 | | * string |
13421 | | */ |
13422 | | simdutf_warn_unused virtual size_t |
13423 | | convert_utf8_to_utf16le(const char *input, size_t length, |
13424 | | char16_t *utf16_output) const noexcept = 0; |
13425 | | |
13426 | | /** |
13427 | | * Convert possibly broken UTF-8 string into UTF-16BE string. |
13428 | | * |
13429 | | * During the conversion also validation of the input string is done. |
13430 | | * This function is suitable to work with inputs from untrusted sources. |
13431 | | * |
13432 | | * @param input the UTF-8 string to convert |
13433 | | * @param length the length of the string in bytes |
13434 | | * @param utf16_output the pointer to buffer that can hold conversion result |
13435 | | * @return the number of written char16_t; 0 if the input was not valid UTF-8 |
13436 | | * string |
13437 | | */ |
13438 | | simdutf_warn_unused virtual size_t |
13439 | | convert_utf8_to_utf16be(const char *input, size_t length, |
13440 | | char16_t *utf16_output) const noexcept = 0; |
13441 | | |
13442 | | /** |
13443 | | * Convert possibly broken UTF-8 string into UTF-16LE string and stop on |
13444 | | * error. |
13445 | | * |
13446 | | * During the conversion also validation of the input string is done. |
13447 | | * This function is suitable to work with inputs from untrusted sources. |
13448 | | * |
13449 | | * @param input the UTF-8 string to convert |
13450 | | * @param length the length of the string in bytes |
13451 | | * @param utf16_output the pointer to buffer that can hold conversion result |
13452 | | * @return a result pair struct (of type simdutf::result containing the two |
13453 | | * fields error and count) with an error code and either position of the error |
13454 | | * (in the input in code units) if any, or the number of code units validated |
13455 | | * if successful. |
13456 | | */ |
13457 | | simdutf_warn_unused virtual result convert_utf8_to_utf16le_with_errors( |
13458 | | const char *input, size_t length, |
13459 | | char16_t *utf16_output) const noexcept = 0; |
13460 | | |
13461 | | /** |
13462 | | * Convert possibly broken UTF-8 string into UTF-16BE string and stop on |
13463 | | * error. |
13464 | | * |
13465 | | * During the conversion also validation of the input string is done. |
13466 | | * This function is suitable to work with inputs from untrusted sources. |
13467 | | * |
13468 | | * @param input the UTF-8 string to convert |
13469 | | * @param length the length of the string in bytes |
13470 | | * @param utf16_output the pointer to buffer that can hold conversion result |
13471 | | * @return a result pair struct (of type simdutf::result containing the two |
13472 | | * fields error and count) with an error code and either position of the error |
13473 | | * (in the input in code units) if any, or the number of code units validated |
13474 | | * if successful. |
13475 | | */ |
13476 | | simdutf_warn_unused virtual result convert_utf8_to_utf16be_with_errors( |
13477 | | const char *input, size_t length, |
13478 | | char16_t *utf16_output) const noexcept = 0; |
13479 | | /** |
13480 | | * Compute the number of bytes that this UTF-16LE string would require in |
13481 | | * UTF-8 format even when the UTF-16LE content contains mismatched |
13482 | | * surrogates that have to be replaced by the replacement character (0xFFFD). |
13483 | | * |
13484 | | * @param input the UTF-16LE string to convert |
13485 | | * @param length the length of the string in 2-byte code units |
13486 | | * (char16_t) |
13487 | | * @return a result pair struct (of type simdutf::result containing the two |
13488 | | * fields error and count) where the count is the number of bytes required to |
13489 | | * encode the UTF-16LE string as UTF-8, and the error code is either SUCCESS |
13490 | | * or SURROGATE. The count is correct regardless of the error field. |
13491 | | * When SURROGATE is returned, it does not indicate an error in the case of |
13492 | | * this function: it indicates that at least one surrogate has been |
13493 | | * encountered: the surrogates may be matched or not (thus this function does |
13494 | | * not validate). If the returned error code is SUCCESS, then the input |
13495 | | * contains no surrogate, is in the Basic Multilingual Plane, and is |
13496 | | * necessarily valid. |
13497 | | */ |
13498 | | virtual simdutf_warn_unused result utf8_length_from_utf16le_with_replacement( |
13499 | | const char16_t *input, size_t length) const noexcept = 0; |
13500 | | |
13501 | | /** |
13502 | | * Compute the number of bytes that this UTF-16BE string would require in |
13503 | | * UTF-8 format even when the UTF-16BE content contains mismatched |
13504 | | * surrogates that have to be replaced by the replacement character (0xFFFD). |
13505 | | * |
13506 | | * @param input the UTF-16BE string to convert |
13507 | | * @param length the length of the string in 2-byte code units |
13508 | | * (char16_t) |
13509 | | * @return a result pair struct (of type simdutf::result containing the two |
13510 | | * fields error and count) where the count is the number of bytes required to |
13511 | | * encode the UTF-16BE string as UTF-8, and the error code is either SUCCESS |
13512 | | * or SURROGATE. The count is correct regardless of the error field. |
13513 | | * When SURROGATE is returned, it does not indicate an error in the case of |
13514 | | * this function: it indicates that at least one surrogate has been |
13515 | | * encountered: the surrogates may be matched or not (thus this function does |
13516 | | * not validate). If the returned error code is SUCCESS, then the input |
13517 | | * contains no surrogate, is in the Basic Multilingual Plane, and is |
13518 | | * necessarily valid. |
13519 | | */ |
13520 | | virtual simdutf_warn_unused result utf8_length_from_utf16be_with_replacement( |
13521 | | const char16_t *input, size_t length) const noexcept = 0; |
13522 | | |
13523 | | #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 |
13524 | | |
13525 | | #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32 |
13526 | | /** |
13527 | | * Convert possibly broken UTF-8 string into UTF-32 string. |
13528 | | * |
13529 | | * During the conversion also validation of the input string is done. |
13530 | | * This function is suitable to work with inputs from untrusted sources. |
13531 | | * |
13532 | | * @param input the UTF-8 string to convert |
13533 | | * @param length the length of the string in bytes |
13534 | | * @param utf32_output the pointer to buffer that can hold conversion result |
13535 | | * @return the number of written char16_t; 0 if the input was not valid UTF-8 |
13536 | | * string |
13537 | | */ |
13538 | | simdutf_warn_unused virtual size_t |
13539 | | convert_utf8_to_utf32(const char *input, size_t length, |
13540 | | char32_t *utf32_output) const noexcept = 0; |
13541 | | |
13542 | | /** |
13543 | | * Convert possibly broken UTF-8 string into UTF-32 string and stop on error. |
13544 | | * |
13545 | | * During the conversion also validation of the input string is done. |
13546 | | * This function is suitable to work with inputs from untrusted sources. |
13547 | | * |
13548 | | * @param input the UTF-8 string to convert |
13549 | | * @param length the length of the string in bytes |
13550 | | * @param utf32_output the pointer to buffer that can hold conversion result |
13551 | | * @return a result pair struct (of type simdutf::result containing the two |
13552 | | * fields error and count) with an error code and either position of the error |
13553 | | * (in the input in code units) if any, or the number of char32_t written if |
13554 | | * successful. |
13555 | | */ |
13556 | | simdutf_warn_unused virtual result |
13557 | | convert_utf8_to_utf32_with_errors(const char *input, size_t length, |
13558 | | char32_t *utf32_output) const noexcept = 0; |
13559 | | #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32 |
13560 | | |
13561 | | #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 |
13562 | | /** |
13563 | | * Convert valid UTF-8 string into UTF-16LE string. |
13564 | | * |
13565 | | * This function assumes that the input string is valid UTF-8. |
13566 | | * |
13567 | | * @param input the UTF-8 string to convert |
13568 | | * @param length the length of the string in bytes |
13569 | | * @param utf16_buffer the pointer to buffer that can hold conversion result |
13570 | | * @return the number of written char16_t |
13571 | | */ |
13572 | | simdutf_warn_unused virtual size_t |
13573 | | convert_valid_utf8_to_utf16le(const char *input, size_t length, |
13574 | | char16_t *utf16_buffer) const noexcept = 0; |
13575 | | |
13576 | | /** |
13577 | | * Convert valid UTF-8 string into UTF-16BE string. |
13578 | | * |
13579 | | * This function assumes that the input string is valid UTF-8. |
13580 | | * |
13581 | | * @param input the UTF-8 string to convert |
13582 | | * @param length the length of the string in bytes |
13583 | | * @param utf16_buffer the pointer to buffer that can hold conversion result |
13584 | | * @return the number of written char16_t |
13585 | | */ |
13586 | | simdutf_warn_unused virtual size_t |
13587 | | convert_valid_utf8_to_utf16be(const char *input, size_t length, |
13588 | | char16_t *utf16_buffer) const noexcept = 0; |
13589 | | #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 |
13590 | | |
13591 | | #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32 |
13592 | | /** |
13593 | | * Convert valid UTF-8 string into UTF-32 string. |
13594 | | * |
13595 | | * This function assumes that the input string is valid UTF-8. |
13596 | | * |
13597 | | * @param input the UTF-8 string to convert |
13598 | | * @param length the length of the string in bytes |
13599 | | * @param utf32_buffer the pointer to buffer that can hold conversion result |
13600 | | * @return the number of written char32_t |
13601 | | */ |
13602 | | simdutf_warn_unused virtual size_t |
13603 | | convert_valid_utf8_to_utf32(const char *input, size_t length, |
13604 | | char32_t *utf32_buffer) const noexcept = 0; |
13605 | | #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32 |
13606 | | |
13607 | | #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 |
13608 | | /** |
13609 | | * Compute the number of 2-byte code units that this UTF-8 string would |
13610 | | * require in UTF-16LE format. |
13611 | | * |
13612 | | * This function does not validate the input. It is acceptable to pass invalid |
13613 | | * UTF-8 strings but in such cases the result is implementation defined. |
13614 | | * |
13615 | | * @param input the UTF-8 string to process |
13616 | | * @param length the length of the string in bytes |
13617 | | * @return the number of char16_t code units required to encode the UTF-8 |
13618 | | * string as UTF-16LE |
13619 | | */ |
13620 | | simdutf_warn_unused virtual size_t |
13621 | | utf16_length_from_utf8(const char *input, size_t length) const noexcept = 0; |
13622 | | #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 |
13623 | | |
13624 | | #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32 |
13625 | | /** |
13626 | | * Compute the number of 4-byte code units that this UTF-8 string would |
13627 | | * require in UTF-32 format. |
13628 | | * |
13629 | | * This function is equivalent to count_utf8. It is acceptable to pass invalid |
13630 | | * UTF-8 strings but in such cases the result is implementation defined. |
13631 | | * |
13632 | | * This function does not validate the input. |
13633 | | * |
13634 | | * @param input the UTF-8 string to process |
13635 | | * @param length the length of the string in bytes |
13636 | | * @return the number of char32_t code units required to encode the UTF-8 |
13637 | | * string as UTF-32 |
13638 | | */ |
13639 | | simdutf_warn_unused virtual size_t |
13640 | | utf32_length_from_utf8(const char *input, size_t length) const noexcept = 0; |
13641 | | #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32 |
13642 | | |
13643 | | #if SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_LATIN1 |
13644 | | /** |
13645 | | * Convert possibly broken UTF-16LE string into Latin1 string. |
13646 | | * |
13647 | | * During the conversion also validation of the input string is done. |
13648 | | * This function is suitable to work with inputs from untrusted sources. |
13649 | | * |
13650 | | * This function is not BOM-aware. |
13651 | | * |
13652 | | * @param input the UTF-16LE string to convert |
13653 | | * @param length the length of the string in 2-byte code units |
13654 | | * (char16_t) |
13655 | | * @param latin1_buffer the pointer to buffer that can hold conversion |
13656 | | * result |
13657 | | * @return number of written code units; 0 if input is not a valid UTF-16LE |
13658 | | * string or if it cannot be represented as Latin1 |
13659 | | */ |
13660 | | simdutf_warn_unused virtual size_t |
13661 | | convert_utf16le_to_latin1(const char16_t *input, size_t length, |
13662 | | char *latin1_buffer) const noexcept = 0; |
13663 | | |
13664 | | /** |
13665 | | * Convert possibly broken UTF-16BE string into Latin1 string. |
13666 | | * |
13667 | | * During the conversion also validation of the input string is done. |
13668 | | * This function is suitable to work with inputs from untrusted sources. |
13669 | | * |
13670 | | * This function is not BOM-aware. |
13671 | | * |
13672 | | * @param input the UTF-16BE string to convert |
13673 | | * @param length the length of the string in 2-byte code units |
13674 | | * (char16_t) |
13675 | | * @param latin1_buffer the pointer to buffer that can hold conversion |
13676 | | * result |
13677 | | * @return number of written code units; 0 if input is not a valid UTF-16BE |
13678 | | * string or if it cannot be represented as Latin1 |
13679 | | */ |
13680 | | simdutf_warn_unused virtual size_t |
13681 | | convert_utf16be_to_latin1(const char16_t *input, size_t length, |
13682 | | char *latin1_buffer) const noexcept = 0; |
13683 | | |
13684 | | /** |
13685 | | * Convert possibly broken UTF-16LE string into Latin1 string. |
13686 | | * If the string cannot be represented as Latin1, an error |
13687 | | * is returned. |
13688 | | * |
13689 | | * During the conversion also validation of the input string is done. |
13690 | | * This function is suitable to work with inputs from untrusted sources. |
13691 | | * This function is not BOM-aware. |
13692 | | * |
13693 | | * @param input the UTF-16LE string to convert |
13694 | | * @param length the length of the string in 2-byte code units |
13695 | | * (char16_t) |
13696 | | * @param latin1_buffer the pointer to buffer that can hold conversion |
13697 | | * result |
13698 | | * @return a result pair struct (of type simdutf::result containing the two |
13699 | | * fields error and count) with an error code and either position of the error |
13700 | | * (in the input in code units) if any, or the number of char written if |
13701 | | * successful. |
13702 | | */ |
13703 | | simdutf_warn_unused virtual result |
13704 | | convert_utf16le_to_latin1_with_errors(const char16_t *input, size_t length, |
13705 | | char *latin1_buffer) const noexcept = 0; |
13706 | | |
13707 | | /** |
13708 | | * Convert possibly broken UTF-16BE string into Latin1 string. |
13709 | | * If the string cannot be represented as Latin1, an error |
13710 | | * is returned. |
13711 | | * |
13712 | | * During the conversion also validation of the input string is done. |
13713 | | * This function is suitable to work with inputs from untrusted sources. |
13714 | | * This function is not BOM-aware. |
13715 | | * |
13716 | | * @param input the UTF-16BE string to convert |
13717 | | * @param length the length of the string in 2-byte code units |
13718 | | * (char16_t) |
13719 | | * @param latin1_buffer the pointer to buffer that can hold conversion |
13720 | | * result |
13721 | | * @return a result pair struct (of type simdutf::result containing the two |
13722 | | * fields error and count) with an error code and either position of the error |
13723 | | * (in the input in code units) if any, or the number of char written if |
13724 | | * successful. |
13725 | | */ |
13726 | | simdutf_warn_unused virtual result |
13727 | | convert_utf16be_to_latin1_with_errors(const char16_t *input, size_t length, |
13728 | | char *latin1_buffer) const noexcept = 0; |
13729 | | |
13730 | | /** |
13731 | | * Convert valid UTF-16LE string into Latin1 string. |
13732 | | * |
13733 | | * This function assumes that the input string is valid UTF-L16LE and that it |
13734 | | * can be represented as Latin1. If you violate this assumption, the result is |
13735 | | * implementation defined and may include system-dependent behavior such as |
13736 | | * crashes. |
13737 | | * |
13738 | | * This function is for expert users only and not part of our public API. Use |
13739 | | * convert_utf16le_to_latin1 instead. |
13740 | | * |
13741 | | * This function is not BOM-aware. |
13742 | | * |
13743 | | * @param input the UTF-16LE string to convert |
13744 | | * @param length the length of the string in 2-byte code units |
13745 | | * (char16_t) |
13746 | | * @param latin1_buffer the pointer to buffer that can hold conversion |
13747 | | * result |
13748 | | * @return number of written code units; 0 if conversion is not possible |
13749 | | */ |
13750 | | simdutf_warn_unused virtual size_t |
13751 | | convert_valid_utf16le_to_latin1(const char16_t *input, size_t length, |
13752 | | char *latin1_buffer) const noexcept = 0; |
13753 | | |
13754 | | /** |
13755 | | * Convert valid UTF-16BE string into Latin1 string. |
13756 | | * |
13757 | | * This function assumes that the input string is valid UTF16-BE and that it |
13758 | | * can be represented as Latin1. If you violate this assumption, the result is |
13759 | | * implementation defined and may include system-dependent behavior such as |
13760 | | * crashes. |
13761 | | * |
13762 | | * This function is for expert users only and not part of our public API. Use |
13763 | | * convert_utf16be_to_latin1 instead. |
13764 | | * |
13765 | | * This function is not BOM-aware. |
13766 | | * |
13767 | | * @param input the UTF-16BE string to convert |
13768 | | * @param length the length of the string in 2-byte code units |
13769 | | * (char16_t) |
13770 | | * @param latin1_buffer the pointer to buffer that can hold conversion |
13771 | | * result |
13772 | | * @return number of written code units; 0 if conversion is not possible |
13773 | | */ |
13774 | | simdutf_warn_unused virtual size_t |
13775 | | convert_valid_utf16be_to_latin1(const char16_t *input, size_t length, |
13776 | | char *latin1_buffer) const noexcept = 0; |
13777 | | #endif // SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_LATIN1 |
13778 | | |
13779 | | #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 |
13780 | | /** |
13781 | | * Convert possibly broken UTF-16LE string into UTF-8 string. |
13782 | | * |
13783 | | * During the conversion also validation of the input string is done. |
13784 | | * This function is suitable to work with inputs from untrusted sources. |
13785 | | * |
13786 | | * This function is not BOM-aware. |
13787 | | * |
13788 | | * @param input the UTF-16LE string to convert |
13789 | | * @param length the length of the string in 2-byte code units |
13790 | | * (char16_t) |
13791 | | * @param utf8_buffer the pointer to buffer that can hold conversion result |
13792 | | * @return number of written code units; 0 if input is not a valid UTF-16LE |
13793 | | * string |
13794 | | */ |
13795 | | simdutf_warn_unused virtual size_t |
13796 | | convert_utf16le_to_utf8(const char16_t *input, size_t length, |
13797 | | char *utf8_buffer) const noexcept = 0; |
13798 | | |
13799 | | /** |
13800 | | * Convert possibly broken UTF-16BE string into UTF-8 string. |
13801 | | * |
13802 | | * During the conversion also validation of the input string is done. |
13803 | | * This function is suitable to work with inputs from untrusted sources. |
13804 | | * |
13805 | | * This function is not BOM-aware. |
13806 | | * |
13807 | | * @param input the UTF-16BE string to convert |
13808 | | * @param length the length of the string in 2-byte code units |
13809 | | * (char16_t) |
13810 | | * @param utf8_buffer the pointer to buffer that can hold conversion result |
13811 | | * @return number of written code units; 0 if input is not a valid UTF-16BE |
13812 | | * string |
13813 | | */ |
13814 | | simdutf_warn_unused virtual size_t |
13815 | | convert_utf16be_to_utf8(const char16_t *input, size_t length, |
13816 | | char *utf8_buffer) const noexcept = 0; |
13817 | | |
13818 | | /** |
13819 | | * Convert possibly broken UTF-16LE string into UTF-8 string and stop on |
13820 | | * error. |
13821 | | * |
13822 | | * During the conversion also validation of the input string is done. |
13823 | | * This function is suitable to work with inputs from untrusted sources. |
13824 | | * |
13825 | | * This function is not BOM-aware. |
13826 | | * |
13827 | | * @param input the UTF-16LE string to convert |
13828 | | * @param length the length of the string in 2-byte code units |
13829 | | * (char16_t) |
13830 | | * @param utf8_buffer the pointer to buffer that can hold conversion result |
13831 | | * @return a result pair struct (of type simdutf::result containing the two |
13832 | | * fields error and count) with an error code and either position of the error |
13833 | | * (in the input in code units) if any, or the number of char written if |
13834 | | * successful. |
13835 | | */ |
13836 | | simdutf_warn_unused virtual result |
13837 | | convert_utf16le_to_utf8_with_errors(const char16_t *input, size_t length, |
13838 | | char *utf8_buffer) const noexcept = 0; |
13839 | | |
13840 | | /** |
13841 | | * Convert possibly broken UTF-16BE string into UTF-8 string and stop on |
13842 | | * error. |
13843 | | * |
13844 | | * During the conversion also validation of the input string is done. |
13845 | | * This function is suitable to work with inputs from untrusted sources. |
13846 | | * |
13847 | | * This function is not BOM-aware. |
13848 | | * |
13849 | | * @param input the UTF-16BE string to convert |
13850 | | * @param length the length of the string in 2-byte code units |
13851 | | * (char16_t) |
13852 | | * @param utf8_buffer the pointer to buffer that can hold conversion result |
13853 | | * @return a result pair struct (of type simdutf::result containing the two |
13854 | | * fields error and count) with an error code and either position of the error |
13855 | | * (in the input in code units) if any, or the number of char written if |
13856 | | * successful. |
13857 | | */ |
13858 | | simdutf_warn_unused virtual result |
13859 | | convert_utf16be_to_utf8_with_errors(const char16_t *input, size_t length, |
13860 | | char *utf8_buffer) const noexcept = 0; |
13861 | | |
13862 | | /** |
13863 | | * Convert possibly broken UTF-16LE string into UTF-8 string, replacing |
13864 | | * unpaired surrogates with the Unicode replacement character U+FFFD. |
13865 | | * |
13866 | | * This function always succeeds: unpaired surrogates are replaced with |
13867 | | * U+FFFD (3 bytes in UTF-8: 0xEF 0xBF 0xBD). |
13868 | | * |
13869 | | * This function is not BOM-aware. |
13870 | | * |
13871 | | * @param input the UTF-16LE string to convert |
13872 | | * @param length the length of the string in 2-byte code units |
13873 | | * (char16_t) |
13874 | | * @param utf8_buffer the pointer to buffer that can hold conversion result |
13875 | | * @return number of written code units |
13876 | | */ |
13877 | | simdutf_warn_unused virtual size_t convert_utf16le_to_utf8_with_replacement( |
13878 | | const char16_t *input, size_t length, |
13879 | | char *utf8_buffer) const noexcept = 0; |
13880 | | |
13881 | | /** |
13882 | | * Convert possibly broken UTF-16BE string into UTF-8 string, replacing |
13883 | | * unpaired surrogates with the Unicode replacement character U+FFFD. |
13884 | | * |
13885 | | * This function always succeeds: unpaired surrogates are replaced with |
13886 | | * U+FFFD (3 bytes in UTF-8: 0xEF 0xBF 0xBD). |
13887 | | * |
13888 | | * This function is not BOM-aware. |
13889 | | * |
13890 | | * @param input the UTF-16BE string to convert |
13891 | | * @param length the length of the string in 2-byte code units |
13892 | | * (char16_t) |
13893 | | * @param utf8_buffer the pointer to buffer that can hold conversion result |
13894 | | * @return number of written code units |
13895 | | */ |
13896 | | simdutf_warn_unused virtual size_t convert_utf16be_to_utf8_with_replacement( |
13897 | | const char16_t *input, size_t length, |
13898 | | char *utf8_buffer) const noexcept = 0; |
13899 | | |
13900 | | /** |
13901 | | * Convert valid UTF-16LE string into UTF-8 string. |
13902 | | * |
13903 | | * This function assumes that the input string is valid UTF-16LE. |
13904 | | * |
13905 | | * This function is not BOM-aware. |
13906 | | * |
13907 | | * @param input the UTF-16LE string to convert |
13908 | | * @param length the length of the string in 2-byte code units |
13909 | | * (char16_t) |
13910 | | * @param utf8_buffer the pointer to a buffer that can hold the conversion |
13911 | | * result |
13912 | | * @return number of written code units; 0 if conversion is not possible |
13913 | | */ |
13914 | | simdutf_warn_unused virtual size_t |
13915 | | convert_valid_utf16le_to_utf8(const char16_t *input, size_t length, |
13916 | | char *utf8_buffer) const noexcept = 0; |
13917 | | |
13918 | | /** |
13919 | | * Convert valid UTF-16BE string into UTF-8 string. |
13920 | | * |
13921 | | * This function assumes that the input string is valid UTF-16BE. |
13922 | | * |
13923 | | * This function is not BOM-aware. |
13924 | | * |
13925 | | * @param input the UTF-16BE string to convert |
13926 | | * @param length the length of the string in 2-byte code units |
13927 | | * (char16_t) |
13928 | | * @param utf8_buffer the pointer to a buffer that can hold the conversion |
13929 | | * result |
13930 | | * @return number of written code units; 0 if conversion is not possible |
13931 | | */ |
13932 | | simdutf_warn_unused virtual size_t |
13933 | | convert_valid_utf16be_to_utf8(const char16_t *input, size_t length, |
13934 | | char *utf8_buffer) const noexcept = 0; |
13935 | | #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 |
13936 | | |
13937 | | #if SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_UTF32 |
13938 | | /** |
13939 | | * Convert possibly broken UTF-16LE string into UTF-32 string. |
13940 | | * |
13941 | | * During the conversion also validation of the input string is done. |
13942 | | * This function is suitable to work with inputs from untrusted sources. |
13943 | | * |
13944 | | * This function is not BOM-aware. |
13945 | | * |
13946 | | * @param input the UTF-16LE string to convert |
13947 | | * @param length the length of the string in 2-byte code units |
13948 | | * (char16_t) |
13949 | | * @param utf32_buffer the pointer to buffer that can hold conversion result |
13950 | | * @return number of written code units; 0 if input is not a valid UTF-16LE |
13951 | | * string |
13952 | | */ |
13953 | | simdutf_warn_unused virtual size_t |
13954 | | convert_utf16le_to_utf32(const char16_t *input, size_t length, |
13955 | | char32_t *utf32_buffer) const noexcept = 0; |
13956 | | |
13957 | | /** |
13958 | | * Convert possibly broken UTF-16BE string into UTF-32 string. |
13959 | | * |
13960 | | * During the conversion also validation of the input string is done. |
13961 | | * This function is suitable to work with inputs from untrusted sources. |
13962 | | * |
13963 | | * This function is not BOM-aware. |
13964 | | * |
13965 | | * @param input the UTF-16BE string to convert |
13966 | | * @param length the length of the string in 2-byte code units |
13967 | | * (char16_t) |
13968 | | * @param utf32_buffer the pointer to buffer that can hold conversion result |
13969 | | * @return number of written code units; 0 if input is not a valid UTF-16BE |
13970 | | * string |
13971 | | */ |
13972 | | simdutf_warn_unused virtual size_t |
13973 | | convert_utf16be_to_utf32(const char16_t *input, size_t length, |
13974 | | char32_t *utf32_buffer) const noexcept = 0; |
13975 | | |
13976 | | /** |
13977 | | * Convert possibly broken UTF-16LE string into UTF-32 string and stop on |
13978 | | * error. |
13979 | | * |
13980 | | * During the conversion also validation of the input string is done. |
13981 | | * This function is suitable to work with inputs from untrusted sources. |
13982 | | * |
13983 | | * This function is not BOM-aware. |
13984 | | * |
13985 | | * @param input the UTF-16LE string to convert |
13986 | | * @param length the length of the string in 2-byte code units |
13987 | | * (char16_t) |
13988 | | * @param utf32_buffer the pointer to buffer that can hold conversion result |
13989 | | * @return a result pair struct (of type simdutf::result containing the two |
13990 | | * fields error and count) with an error code and either position of the error |
13991 | | * (in the input in code units) if any, or the number of char32_t written if |
13992 | | * successful. |
13993 | | */ |
13994 | | simdutf_warn_unused virtual result convert_utf16le_to_utf32_with_errors( |
13995 | | const char16_t *input, size_t length, |
13996 | | char32_t *utf32_buffer) const noexcept = 0; |
13997 | | |
13998 | | /** |
13999 | | * Convert possibly broken UTF-16BE string into UTF-32 string and stop on |
14000 | | * error. |
14001 | | * |
14002 | | * During the conversion also validation of the input string is done. |
14003 | | * This function is suitable to work with inputs from untrusted sources. |
14004 | | * |
14005 | | * This function is not BOM-aware. |
14006 | | * |
14007 | | * @param input the UTF-16BE string to convert |
14008 | | * @param length the length of the string in 2-byte code units |
14009 | | * (char16_t) |
14010 | | * @param utf32_buffer the pointer to buffer that can hold conversion result |
14011 | | * @return a result pair struct (of type simdutf::result containing the two |
14012 | | * fields error and count) with an error code and either position of the error |
14013 | | * (in the input in code units) if any, or the number of char32_t written if |
14014 | | * successful. |
14015 | | */ |
14016 | | simdutf_warn_unused virtual result convert_utf16be_to_utf32_with_errors( |
14017 | | const char16_t *input, size_t length, |
14018 | | char32_t *utf32_buffer) const noexcept = 0; |
14019 | | |
14020 | | /** |
14021 | | * Convert valid UTF-16LE string into UTF-32 string. |
14022 | | * |
14023 | | * This function assumes that the input string is valid UTF-16LE. |
14024 | | * |
14025 | | * This function is not BOM-aware. |
14026 | | * |
14027 | | * @param input the UTF-16LE string to convert |
14028 | | * @param length the length of the string in 2-byte code units |
14029 | | * (char16_t) |
14030 | | * @param utf32_buffer the pointer to a buffer that can hold the conversion |
14031 | | * result |
14032 | | * @return number of written code units; 0 if conversion is not possible |
14033 | | */ |
14034 | | simdutf_warn_unused virtual size_t |
14035 | | convert_valid_utf16le_to_utf32(const char16_t *input, size_t length, |
14036 | | char32_t *utf32_buffer) const noexcept = 0; |
14037 | | |
14038 | | /** |
14039 | | * Convert valid UTF-16LE string into UTF-32BE string. |
14040 | | * |
14041 | | * This function assumes that the input string is valid UTF-16BE. |
14042 | | * |
14043 | | * This function is not BOM-aware. |
14044 | | * |
14045 | | * @param input the UTF-16BE string to convert |
14046 | | * @param length the length of the string in 2-byte code units |
14047 | | * (char16_t) |
14048 | | * @param utf32_buffer the pointer to a buffer that can hold the conversion |
14049 | | * result |
14050 | | * @return number of written code units; 0 if conversion is not possible |
14051 | | */ |
14052 | | simdutf_warn_unused virtual size_t |
14053 | | convert_valid_utf16be_to_utf32(const char16_t *input, size_t length, |
14054 | | char32_t *utf32_buffer) const noexcept = 0; |
14055 | | #endif // SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_UTF32 |
14056 | | |
14057 | | #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 |
14058 | | /** |
14059 | | * Compute the number of bytes that this UTF-16LE string would require in |
14060 | | * UTF-8 format. |
14061 | | * |
14062 | | * This function does not validate the input. It is acceptable to pass invalid |
14063 | | * UTF-16 strings but in such cases the result is implementation defined. |
14064 | | * |
14065 | | * This function is not BOM-aware. |
14066 | | * |
14067 | | * @param input the UTF-16LE string to convert |
14068 | | * @param length the length of the string in 2-byte code units |
14069 | | * (char16_t) |
14070 | | * @return the number of bytes required to encode the UTF-16LE string as UTF-8 |
14071 | | */ |
14072 | | simdutf_warn_unused virtual size_t |
14073 | | utf8_length_from_utf16le(const char16_t *input, |
14074 | | size_t length) const noexcept = 0; |
14075 | | |
14076 | | /** |
14077 | | * Compute the number of bytes that this UTF-16BE string would require in |
14078 | | * UTF-8 format. |
14079 | | * |
14080 | | * This function does not validate the input. It is acceptable to pass invalid |
14081 | | * UTF-16 strings but in such cases the result is implementation defined. |
14082 | | * |
14083 | | * This function is not BOM-aware. |
14084 | | * |
14085 | | * @param input the UTF-16BE string to convert |
14086 | | * @param length the length of the string in 2-byte code units |
14087 | | * (char16_t) |
14088 | | * @return the number of bytes required to encode the UTF-16BE string as UTF-8 |
14089 | | */ |
14090 | | simdutf_warn_unused virtual size_t |
14091 | | utf8_length_from_utf16be(const char16_t *input, |
14092 | | size_t length) const noexcept = 0; |
14093 | | #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 |
14094 | | |
14095 | | #if SIMDUTF_FEATURE_UTF32 && SIMDUTF_FEATURE_LATIN1 |
14096 | | /** |
14097 | | * Convert possibly broken UTF-32 string into Latin1 string. |
14098 | | * |
14099 | | * During the conversion also validation of the input string is done. |
14100 | | * This function is suitable to work with inputs from untrusted sources. |
14101 | | * |
14102 | | * This function is not BOM-aware. |
14103 | | * |
14104 | | * @param input the UTF-32 string to convert |
14105 | | * @param length the length of the string in 4-byte code units |
14106 | | * (char32_t) |
14107 | | * @param latin1_buffer the pointer to buffer that can hold conversion |
14108 | | * result |
14109 | | * @return number of written code units; 0 if input is not a valid UTF-32 |
14110 | | * string |
14111 | | */ |
14112 | | simdutf_warn_unused virtual size_t |
14113 | | convert_utf32_to_latin1(const char32_t *input, size_t length, |
14114 | | char *latin1_buffer) const noexcept = 0; |
14115 | | #endif // SIMDUTF_FEATURE_UTF32 && SIMDUTF_FEATURE_LATIN1 |
14116 | | |
14117 | | #if SIMDUTF_FEATURE_UTF32 && SIMDUTF_FEATURE_LATIN1 |
14118 | | /** |
14119 | | * Convert possibly broken UTF-32 string into Latin1 string and stop on error. |
14120 | | * If the string cannot be represented as Latin1, an error is returned. |
14121 | | * |
14122 | | * During the conversion also validation of the input string is done. |
14123 | | * This function is suitable to work with inputs from untrusted sources. |
14124 | | * |
14125 | | * This function is not BOM-aware. |
14126 | | * |
14127 | | * @param input the UTF-32 string to convert |
14128 | | * @param length the length of the string in 4-byte code units |
14129 | | * (char32_t) |
14130 | | * @param latin1_buffer the pointer to buffer that can hold conversion |
14131 | | * result |
14132 | | * @return a result pair struct (of type simdutf::result containing the two |
14133 | | * fields error and count) with an error code and either position of the error |
14134 | | * (in the input in code units) if any, or the number of char written if |
14135 | | * successful. |
14136 | | */ |
14137 | | simdutf_warn_unused virtual result |
14138 | | convert_utf32_to_latin1_with_errors(const char32_t *input, size_t length, |
14139 | | char *latin1_buffer) const noexcept = 0; |
14140 | | |
14141 | | /** |
14142 | | * Convert valid UTF-32 string into Latin1 string. |
14143 | | * |
14144 | | * This function assumes that the input string is valid UTF-32 and can be |
14145 | | * represented as Latin1. If you violate this assumption, the result is |
14146 | | * implementation defined and may include system-dependent behavior such as |
14147 | | * crashes. |
14148 | | * |
14149 | | * This function is for expert users only and not part of our public API. Use |
14150 | | * convert_utf32_to_latin1 instead. |
14151 | | * |
14152 | | * This function is not BOM-aware. |
14153 | | * |
14154 | | * @param input the UTF-32 string to convert |
14155 | | * @param length the length of the string in 4-byte code units |
14156 | | * (char32_t) |
14157 | | * @param latin1_buffer the pointer to a buffer that can hold the conversion |
14158 | | * result |
14159 | | * @return number of written code units; 0 if conversion is not possible |
14160 | | */ |
14161 | | simdutf_warn_unused virtual size_t |
14162 | | convert_valid_utf32_to_latin1(const char32_t *input, size_t length, |
14163 | | char *latin1_buffer) const noexcept = 0; |
14164 | | #endif // SIMDUTF_FEATURE_UTF32 && SIMDUTF_FEATURE_LATIN1 |
14165 | | |
14166 | | #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32 |
14167 | | /** |
14168 | | * Convert possibly broken UTF-32 string into UTF-8 string. |
14169 | | * |
14170 | | * During the conversion also validation of the input string is done. |
14171 | | * This function is suitable to work with inputs from untrusted sources. |
14172 | | * |
14173 | | * This function is not BOM-aware. |
14174 | | * |
14175 | | * @param input the UTF-32 string to convert |
14176 | | * @param length the length of the string in 4-byte code units |
14177 | | * (char32_t) |
14178 | | * @param utf8_buffer the pointer to buffer that can hold conversion result |
14179 | | * @return number of written code units; 0 if input is not a valid UTF-32 |
14180 | | * string |
14181 | | */ |
14182 | | simdutf_warn_unused virtual size_t |
14183 | | convert_utf32_to_utf8(const char32_t *input, size_t length, |
14184 | | char *utf8_buffer) const noexcept = 0; |
14185 | | |
14186 | | /** |
14187 | | * Convert possibly broken UTF-32 string into UTF-8 string and stop on error. |
14188 | | * |
14189 | | * During the conversion also validation of the input string is done. |
14190 | | * This function is suitable to work with inputs from untrusted sources. |
14191 | | * |
14192 | | * This function is not BOM-aware. |
14193 | | * |
14194 | | * @param input the UTF-32 string to convert |
14195 | | * @param length the length of the string in 4-byte code units |
14196 | | * (char32_t) |
14197 | | * @param utf8_buffer the pointer to buffer that can hold conversion result |
14198 | | * @return a result pair struct (of type simdutf::result containing the two |
14199 | | * fields error and count) with an error code and either position of the error |
14200 | | * (in the input in code units) if any, or the number of char written if |
14201 | | * successful. |
14202 | | */ |
14203 | | simdutf_warn_unused virtual result |
14204 | | convert_utf32_to_utf8_with_errors(const char32_t *input, size_t length, |
14205 | | char *utf8_buffer) const noexcept = 0; |
14206 | | |
14207 | | /** |
14208 | | * Convert valid UTF-32 string into UTF-8 string. |
14209 | | * |
14210 | | * This function assumes that the input string is valid UTF-32. |
14211 | | * |
14212 | | * This function is not BOM-aware. |
14213 | | * |
14214 | | * @param input the UTF-32 string to convert |
14215 | | * @param length the length of the string in 4-byte code units |
14216 | | * (char32_t) |
14217 | | * @param utf8_buffer the pointer to a buffer that can hold the conversion |
14218 | | * result |
14219 | | * @return number of written code units; 0 if conversion is not possible |
14220 | | */ |
14221 | | simdutf_warn_unused virtual size_t |
14222 | | convert_valid_utf32_to_utf8(const char32_t *input, size_t length, |
14223 | | char *utf8_buffer) const noexcept = 0; |
14224 | | #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32 |
14225 | | |
14226 | | #if SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_LATIN1 |
14227 | | /** |
14228 | | * Return the number of bytes that this UTF-16 string would require in Latin1 |
14229 | | * format. |
14230 | | * |
14231 | | * |
14232 | | * @param length the length of the string in 2-byte code units |
14233 | | * (char16_t) |
14234 | | * @return the number of bytes required to encode the UTF-16 string as Latin1 |
14235 | | */ |
14236 | | simdutf_warn_unused virtual size_t |
14237 | | utf16_length_from_latin1(size_t length) const noexcept { |
14238 | | return length; |
14239 | | } |
14240 | | #endif // SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_LATIN1 |
14241 | | |
14242 | | #if SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_UTF32 |
14243 | | /** |
14244 | | * Convert possibly broken UTF-32 string into UTF-16LE string. |
14245 | | * |
14246 | | * During the conversion also validation of the input string is done. |
14247 | | * This function is suitable to work with inputs from untrusted sources. |
14248 | | * |
14249 | | * This function is not BOM-aware. |
14250 | | * |
14251 | | * @param input the UTF-32 string to convert |
14252 | | * @param length the length of the string in 4-byte code units |
14253 | | * (char32_t) |
14254 | | * @param utf16_buffer the pointer to buffer that can hold conversion result |
14255 | | * @return number of written code units; 0 if input is not a valid UTF-32 |
14256 | | * string |
14257 | | */ |
14258 | | simdutf_warn_unused virtual size_t |
14259 | | convert_utf32_to_utf16le(const char32_t *input, size_t length, |
14260 | | char16_t *utf16_buffer) const noexcept = 0; |
14261 | | |
14262 | | /** |
14263 | | * Convert possibly broken UTF-32 string into UTF-16BE string. |
14264 | | * |
14265 | | * During the conversion also validation of the input string is done. |
14266 | | * This function is suitable to work with inputs from untrusted sources. |
14267 | | * |
14268 | | * This function is not BOM-aware. |
14269 | | * |
14270 | | * @param input the UTF-32 string to convert |
14271 | | * @param length the length of the string in 4-byte code units |
14272 | | * (char32_t) |
14273 | | * @param utf16_buffer the pointer to buffer that can hold conversion result |
14274 | | * @return number of written code units; 0 if input is not a valid UTF-32 |
14275 | | * string |
14276 | | */ |
14277 | | simdutf_warn_unused virtual size_t |
14278 | | convert_utf32_to_utf16be(const char32_t *input, size_t length, |
14279 | | char16_t *utf16_buffer) const noexcept = 0; |
14280 | | |
14281 | | /** |
14282 | | * Convert possibly broken UTF-32 string into UTF-16LE string and stop on |
14283 | | * error. |
14284 | | * |
14285 | | * During the conversion also validation of the input string is done. |
14286 | | * This function is suitable to work with inputs from untrusted sources. |
14287 | | * |
14288 | | * This function is not BOM-aware. |
14289 | | * |
14290 | | * @param input the UTF-32 string to convert |
14291 | | * @param length the length of the string in 4-byte code units |
14292 | | * (char32_t) |
14293 | | * @param utf16_buffer the pointer to buffer that can hold conversion result |
14294 | | * @return a result pair struct (of type simdutf::result containing the two |
14295 | | * fields error and count) with an error code and either position of the error |
14296 | | * (in the input in code units) if any, or the number of char16_t written if |
14297 | | * successful. |
14298 | | */ |
14299 | | simdutf_warn_unused virtual result convert_utf32_to_utf16le_with_errors( |
14300 | | const char32_t *input, size_t length, |
14301 | | char16_t *utf16_buffer) const noexcept = 0; |
14302 | | |
14303 | | /** |
14304 | | * Convert possibly broken UTF-32 string into UTF-16BE string and stop on |
14305 | | * error. |
14306 | | * |
14307 | | * During the conversion also validation of the input string is done. |
14308 | | * This function is suitable to work with inputs from untrusted sources. |
14309 | | * |
14310 | | * This function is not BOM-aware. |
14311 | | * |
14312 | | * @param input the UTF-32 string to convert |
14313 | | * @param length the length of the string in 4-byte code units |
14314 | | * (char32_t) |
14315 | | * @param utf16_buffer the pointer to buffer that can hold conversion result |
14316 | | * @return a result pair struct (of type simdutf::result containing the two |
14317 | | * fields error and count) with an error code and either position of the error |
14318 | | * (in the input in code units) if any, or the number of char16_t written if |
14319 | | * successful. |
14320 | | */ |
14321 | | simdutf_warn_unused virtual result convert_utf32_to_utf16be_with_errors( |
14322 | | const char32_t *input, size_t length, |
14323 | | char16_t *utf16_buffer) const noexcept = 0; |
14324 | | |
14325 | | /** |
14326 | | * Convert valid UTF-32 string into UTF-16LE string. |
14327 | | * |
14328 | | * This function assumes that the input string is valid UTF-32. |
14329 | | * |
14330 | | * This function is not BOM-aware. |
14331 | | * |
14332 | | * @param input the UTF-32 string to convert |
14333 | | * @param length the length of the string in 4-byte code units |
14334 | | * (char32_t) |
14335 | | * @param utf16_buffer the pointer to a buffer that can hold the conversion |
14336 | | * result |
14337 | | * @return number of written code units; 0 if conversion is not possible |
14338 | | */ |
14339 | | simdutf_warn_unused virtual size_t |
14340 | | convert_valid_utf32_to_utf16le(const char32_t *input, size_t length, |
14341 | | char16_t *utf16_buffer) const noexcept = 0; |
14342 | | |
14343 | | /** |
14344 | | * Convert valid UTF-32 string into UTF-16BE string. |
14345 | | * |
14346 | | * This function assumes that the input string is valid UTF-32. |
14347 | | * |
14348 | | * This function is not BOM-aware. |
14349 | | * |
14350 | | * @param input the UTF-32 string to convert |
14351 | | * @param length the length of the string in 4-byte code units |
14352 | | * (char32_t) |
14353 | | * @param utf16_buffer the pointer to a buffer that can hold the conversion |
14354 | | * result |
14355 | | * @return number of written code units; 0 if conversion is not possible |
14356 | | */ |
14357 | | simdutf_warn_unused virtual size_t |
14358 | | convert_valid_utf32_to_utf16be(const char32_t *input, size_t length, |
14359 | | char16_t *utf16_buffer) const noexcept = 0; |
14360 | | #endif // SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_UTF32 |
14361 | | |
14362 | | #if SIMDUTF_FEATURE_UTF16 |
14363 | | /** |
14364 | | * Change the endianness of the input. Can be used to go from UTF-16LE to |
14365 | | * UTF-16BE or from UTF-16BE to UTF-16LE. |
14366 | | * |
14367 | | * This function does not validate the input. |
14368 | | * |
14369 | | * This function is not BOM-aware. |
14370 | | * |
14371 | | * @param input the UTF-16 string to process |
14372 | | * @param length the length of the string in 2-byte code units |
14373 | | * (char16_t) |
14374 | | * @param output the pointer to a buffer that can hold the conversion |
14375 | | * result |
14376 | | */ |
14377 | | virtual void change_endianness_utf16(const char16_t *input, size_t length, |
14378 | | char16_t *output) const noexcept = 0; |
14379 | | #endif // SIMDUTF_FEATURE_UTF16 |
14380 | | |
14381 | | #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_LATIN1 |
14382 | | /** |
14383 | | * Return the number of bytes that this Latin1 string would require in UTF-8 |
14384 | | * format. |
14385 | | * |
14386 | | * @param input the Latin1 string to convert |
14387 | | * @param length the length of the string bytes |
14388 | | * @return the number of bytes required to encode the Latin1 string as UTF-8 |
14389 | | */ |
14390 | | simdutf_warn_unused virtual size_t |
14391 | | utf8_length_from_latin1(const char *input, size_t length) const noexcept = 0; |
14392 | | #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_LATIN1 |
14393 | | |
14394 | | #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32 |
14395 | | /** |
14396 | | * Compute the number of bytes that this UTF-32 string would require in UTF-8 |
14397 | | * format. |
14398 | | * |
14399 | | * This function does not validate the input. It is acceptable to pass invalid |
14400 | | * UTF-32 strings but in such cases the result is implementation defined. |
14401 | | * |
14402 | | * @param input the UTF-32 string to convert |
14403 | | * @param length the length of the string in 4-byte code units |
14404 | | * (char32_t) |
14405 | | * @return the number of bytes required to encode the UTF-32 string as UTF-8 |
14406 | | */ |
14407 | | simdutf_warn_unused virtual size_t |
14408 | | utf8_length_from_utf32(const char32_t *input, |
14409 | | size_t length) const noexcept = 0; |
14410 | | #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32 |
14411 | | |
14412 | | #if SIMDUTF_FEATURE_UTF32 && SIMDUTF_FEATURE_LATIN1 |
14413 | | /** |
14414 | | * Compute the number of bytes that this UTF-32 string would require in Latin1 |
14415 | | * format. |
14416 | | * |
14417 | | * This function does not validate the input. It is acceptable to pass invalid |
14418 | | * UTF-32 strings but in such cases the result is implementation defined. |
14419 | | * |
14420 | | * @param length the length of the string in 4-byte code units |
14421 | | * (char32_t) |
14422 | | * @return the number of bytes required to encode the UTF-32 string as Latin1 |
14423 | | */ |
14424 | | simdutf_warn_unused virtual size_t |
14425 | | latin1_length_from_utf32(size_t length) const noexcept { |
14426 | | return length; |
14427 | | } |
14428 | | #endif // SIMDUTF_FEATURE_UTF32 && SIMDUTF_FEATURE_LATIN1 |
14429 | | |
14430 | | #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_LATIN1 |
14431 | | /** |
14432 | | * Compute the number of bytes that this UTF-8 string would require in Latin1 |
14433 | | * format. |
14434 | | * |
14435 | | * This function does not validate the input. It is acceptable to pass invalid |
14436 | | * UTF-8 strings but in such cases the result is implementation defined. |
14437 | | * |
14438 | | * @param input the UTF-8 string to convert |
14439 | | * @param length the length of the string in byte |
14440 | | * @return the number of bytes required to encode the UTF-8 string as Latin1 |
14441 | | */ |
14442 | | simdutf_warn_unused virtual size_t |
14443 | | latin1_length_from_utf8(const char *input, size_t length) const noexcept = 0; |
14444 | | #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_LATIN1 |
14445 | | |
14446 | | #if SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_LATIN1 |
14447 | | /** |
14448 | | * Compute the number of bytes that this UTF-16LE/BE string would require in |
14449 | | * Latin1 format. |
14450 | | * |
14451 | | * This function does not validate the input. It is acceptable to pass invalid |
14452 | | * UTF-16 strings but in such cases the result is implementation defined. |
14453 | | * |
14454 | | * This function is not BOM-aware. |
14455 | | * |
14456 | | * @param length the length of the string in 2-byte code units |
14457 | | * (char16_t) |
14458 | | * @return the number of bytes required to encode the UTF-16LE string as |
14459 | | * Latin1 |
14460 | | */ |
14461 | | simdutf_warn_unused virtual size_t |
14462 | | latin1_length_from_utf16(size_t length) const noexcept { |
14463 | | return length; |
14464 | | } |
14465 | | #endif // SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_LATIN1 |
14466 | | |
14467 | | #if SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_UTF32 |
14468 | | /** |
14469 | | * Compute the number of two-byte code units that this UTF-32 string would |
14470 | | * require in UTF-16 format. |
14471 | | * |
14472 | | * This function does not validate the input. It is acceptable to pass invalid |
14473 | | * UTF-32 strings but in such cases the result is implementation defined. |
14474 | | * |
14475 | | * @param input the UTF-32 string to convert |
14476 | | * @param length the length of the string in 4-byte code units |
14477 | | * (char32_t) |
14478 | | * @return the number of bytes required to encode the UTF-32 string as UTF-16 |
14479 | | */ |
14480 | | simdutf_warn_unused virtual size_t |
14481 | | utf16_length_from_utf32(const char32_t *input, |
14482 | | size_t length) const noexcept = 0; |
14483 | | #endif // SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_UTF32 |
14484 | | |
14485 | | #if SIMDUTF_FEATURE_UTF32 && SIMDUTF_FEATURE_LATIN1 |
14486 | | /** |
14487 | | * Return the number of bytes that this UTF-32 string would require in Latin1 |
14488 | | * format. |
14489 | | * |
14490 | | * @param length the length of the string in 4-byte code units |
14491 | | * (char32_t) |
14492 | | * @return the number of bytes required to encode the UTF-32 string as Latin1 |
14493 | | */ |
14494 | | simdutf_warn_unused virtual size_t |
14495 | | utf32_length_from_latin1(size_t length) const noexcept { |
14496 | | return length; |
14497 | | } |
14498 | | #endif // SIMDUTF_FEATURE_UTF32 && SIMDUTF_FEATURE_LATIN1 |
14499 | | |
14500 | | #if SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_UTF32 |
14501 | | /** |
14502 | | * Compute the number of bytes that this UTF-16LE string would require in |
14503 | | * UTF-32 format. |
14504 | | * |
14505 | | * This function is equivalent to count_utf16le. |
14506 | | * |
14507 | | * This function does not validate the input. It is acceptable to pass invalid |
14508 | | * UTF-16 strings but in such cases the result is implementation defined. |
14509 | | * |
14510 | | * This function is not BOM-aware. |
14511 | | * |
14512 | | * @param input the UTF-16LE string to convert |
14513 | | * @param length the length of the string in 2-byte code units |
14514 | | * (char16_t) |
14515 | | * @return the number of bytes required to encode the UTF-16LE string as |
14516 | | * UTF-32 |
14517 | | */ |
14518 | | simdutf_warn_unused virtual size_t |
14519 | | utf32_length_from_utf16le(const char16_t *input, |
14520 | | size_t length) const noexcept = 0; |
14521 | | |
14522 | | /** |
14523 | | * Compute the number of bytes that this UTF-16BE string would require in |
14524 | | * UTF-32 format. |
14525 | | * |
14526 | | * This function is equivalent to count_utf16be. |
14527 | | * |
14528 | | * This function does not validate the input. It is acceptable to pass invalid |
14529 | | * UTF-16 strings but in such cases the result is implementation defined. |
14530 | | * |
14531 | | * This function is not BOM-aware. |
14532 | | * |
14533 | | * @param input the UTF-16BE string to convert |
14534 | | * @param length the length of the string in 2-byte code units |
14535 | | * (char16_t) |
14536 | | * @return the number of bytes required to encode the UTF-16BE string as |
14537 | | * UTF-32 |
14538 | | */ |
14539 | | simdutf_warn_unused virtual size_t |
14540 | | utf32_length_from_utf16be(const char16_t *input, |
14541 | | size_t length) const noexcept = 0; |
14542 | | #endif // SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_UTF32 |
14543 | | |
14544 | | #if SIMDUTF_FEATURE_UTF16 |
14545 | | /** |
14546 | | * Count the number of code points (characters) in the string assuming that |
14547 | | * it is valid. |
14548 | | * |
14549 | | * This function assumes that the input string is valid UTF-16LE. |
14550 | | * It is acceptable to pass invalid UTF-16 strings but in such cases |
14551 | | * the result is implementation defined. |
14552 | | * |
14553 | | * This function is not BOM-aware. |
14554 | | * |
14555 | | * @param input the UTF-16LE string to process |
14556 | | * @param length the length of the string in 2-byte code units |
14557 | | * (char16_t) |
14558 | | * @return number of code points |
14559 | | */ |
14560 | | simdutf_warn_unused virtual size_t |
14561 | | count_utf16le(const char16_t *input, size_t length) const noexcept = 0; |
14562 | | |
14563 | | /** |
14564 | | * Count the number of code points (characters) in the string assuming that |
14565 | | * it is valid. |
14566 | | * |
14567 | | * This function assumes that the input string is valid UTF-16BE. |
14568 | | * It is acceptable to pass invalid UTF-16 strings but in such cases |
14569 | | * the result is implementation defined. |
14570 | | * |
14571 | | * This function is not BOM-aware. |
14572 | | * |
14573 | | * @param input the UTF-16BE string to process |
14574 | | * @param length the length of the string in 2-byte code units |
14575 | | * (char16_t) |
14576 | | * @return number of code points |
14577 | | */ |
14578 | | simdutf_warn_unused virtual size_t |
14579 | | count_utf16be(const char16_t *input, size_t length) const noexcept = 0; |
14580 | | #endif // SIMDUTF_FEATURE_UTF16 |
14581 | | |
14582 | | #if SIMDUTF_FEATURE_UTF8 |
14583 | | /** |
14584 | | * Count the number of code points (characters) in the string assuming that |
14585 | | * it is valid. |
14586 | | * |
14587 | | * This function assumes that the input string is valid UTF-8. |
14588 | | * It is acceptable to pass invalid UTF-8 strings but in such cases |
14589 | | * the result is implementation defined. |
14590 | | * |
14591 | | * @param input the UTF-8 string to process |
14592 | | * @param length the length of the string in bytes |
14593 | | * @return number of code points |
14594 | | */ |
14595 | | simdutf_warn_unused virtual size_t |
14596 | | count_utf8(const char *input, size_t length) const noexcept = 0; |
14597 | | #endif // SIMDUTF_FEATURE_UTF8 |
14598 | | |
14599 | | #if SIMDUTF_FEATURE_BASE64 |
14600 | | /** |
14601 | | * Provide the maximal binary length in bytes given the base64 input. |
14602 | | * As long as the input does not contain ignorable characters (e.g., ASCII |
14603 | | * spaces or linefeed characters), the result is exact. In particular, the |
14604 | | * function checks for padding characters. |
14605 | | * |
14606 | | * The function is fast (constant time). It checks up to two characters at |
14607 | | * the end of the string. The input is not otherwise validated or read.. |
14608 | | * |
14609 | | * @param input the base64 input to process |
14610 | | * @param length the length of the base64 input in bytes |
14611 | | * @return maximal number of binary bytes |
14612 | | */ |
14613 | | simdutf_warn_unused size_t maximal_binary_length_from_base64( |
14614 | | const char *input, size_t length) const noexcept; |
14615 | | |
14616 | | /** |
14617 | | * Provide the maximal binary length in bytes given the base64 input. |
14618 | | * As long as the input does not contain ignorable characters (e.g., ASCII |
14619 | | * spaces or linefeed characters), the result is exact. In particular, the |
14620 | | * function checks for padding characters. |
14621 | | * |
14622 | | * The function is fast (constant time). It checks up to two characters at |
14623 | | * the end of the string. The input is not otherwise validated or read. |
14624 | | * |
14625 | | * @param input the base64 input to process, in ASCII stored as 16-bit |
14626 | | * units |
14627 | | * @param length the length of the base64 input in 16-bit units |
14628 | | * @return maximal number of binary bytes |
14629 | | */ |
14630 | | simdutf_warn_unused size_t maximal_binary_length_from_base64( |
14631 | | const char16_t *input, size_t length) const noexcept; |
14632 | | |
14633 | | /** |
14634 | | * Compute the binary length from a base64 input with ASCII spaces. |
14635 | | * This function is useful for well-formed base64 inputs that may contain |
14636 | | * ASCII spaces (such as line breaks). For such inputs, the result is exact. |
14637 | | * |
14638 | | * The function counts non-whitespace characters (ASCII value > 0x20) and |
14639 | | * subtracts padding characters ('=') found at the end. |
14640 | | * |
14641 | | * @param input the base64 input to process |
14642 | | * @param length the length of the base64 input in bytes |
14643 | | * @return number of binary bytes |
14644 | | */ |
14645 | | simdutf_warn_unused virtual size_t |
14646 | | binary_length_from_base64(const char *input, size_t length) const noexcept; |
14647 | | |
14648 | | /** |
14649 | | * Compute the binary length from a base64 input with ASCII spaces. |
14650 | | * This function is useful for well-formed base64 inputs that may contain |
14651 | | * ASCII spaces (such as line breaks). For such inputs, the result is exact. |
14652 | | * |
14653 | | * The function counts non-whitespace characters (ASCII value > 0x20) and |
14654 | | * subtracts padding characters ('=') found at the end. |
14655 | | * |
14656 | | * @param input the base64 input to process, in ASCII stored as 16-bit |
14657 | | * units |
14658 | | * @param length the length of the base64 input in 16-bit units |
14659 | | * @return number of binary bytes |
14660 | | */ |
14661 | | simdutf_warn_unused virtual size_t |
14662 | | binary_length_from_base64(const char16_t *input, |
14663 | | size_t length) const noexcept; |
14664 | | |
14665 | | /** |
14666 | | * Convert a base64 input to a binary output. |
14667 | | * |
14668 | | * This function follows the WHATWG forgiving-base64 format, which means that |
14669 | | * it will ignore any ASCII spaces in the input. You may provide a padded |
14670 | | * input (with one or two equal signs at the end) or an unpadded input |
14671 | | * (without any equal signs at the end). |
14672 | | * |
14673 | | * See https://infra.spec.whatwg.org/#forgiving-base64-decode |
14674 | | * |
14675 | | * This function will fail in case of invalid input. When last_chunk_options = |
14676 | | * loose, there are two possible reasons for failure: the input contains a |
14677 | | * number of base64 characters that when divided by 4, leaves a single |
14678 | | * remainder character (BASE64_INPUT_REMAINDER), or the input contains a |
14679 | | * character that is not a valid base64 character (INVALID_BASE64_CHARACTER). |
14680 | | * |
14681 | | * You should call this function with a buffer that is at least |
14682 | | * maximal_binary_length_from_base64(input, length) bytes long. If you fail to |
14683 | | * provide that much space, the function may cause a buffer overflow. |
14684 | | * |
14685 | | * @param input the base64 string to process |
14686 | | * @param length the length of the string in bytes |
14687 | | * @param output the pointer to a buffer that can hold the conversion |
14688 | | * result (should be at least maximal_binary_length_from_base64(input, length) |
14689 | | * bytes long). |
14690 | | * @param options the base64 options to use, can be base64_default or |
14691 | | * base64_url, is base64_default by default. |
14692 | | * @param last_chunk_options the handling of the last chunk (default: loose) |
14693 | | * @return a result pair struct (of type simdutf::result containing the two |
14694 | | * fields error and count) with an error code and either position of the error |
14695 | | * (in the input in bytes) if any, or the number of bytes written if |
14696 | | * successful. |
14697 | | */ |
14698 | | simdutf_warn_unused virtual result |
14699 | | base64_to_binary(const char *input, size_t length, char *output, |
14700 | | base64_options options = base64_default, |
14701 | | last_chunk_handling_options last_chunk_options = |
14702 | | last_chunk_handling_options::loose) const noexcept = 0; |
14703 | | |
14704 | | /** |
14705 | | * Convert a base64 input to a binary output while returning more details |
14706 | | * than base64_to_binary. |
14707 | | * |
14708 | | * This function follows the WHATWG forgiving-base64 format, which means that |
14709 | | * it will ignore any ASCII spaces in the input. You may provide a padded |
14710 | | * input (with one or two equal signs at the end) or an unpadded input |
14711 | | * (without any equal signs at the end). |
14712 | | * |
14713 | | * See https://infra.spec.whatwg.org/#forgiving-base64-decode |
14714 | | * |
14715 | | * This function will fail in case of invalid input. When last_chunk_options = |
14716 | | * loose, there are two possible reasons for failure: the input contains a |
14717 | | * number of base64 characters that when divided by 4, leaves a single |
14718 | | * remainder character (BASE64_INPUT_REMAINDER), or the input contains a |
14719 | | * character that is not a valid base64 character (INVALID_BASE64_CHARACTER). |
14720 | | * |
14721 | | * You should call this function with a buffer that is at least |
14722 | | * maximal_binary_length_from_base64(input, length) bytes long. If you fail to |
14723 | | * provide that much space, the function may cause a buffer overflow. |
14724 | | * |
14725 | | * @param input the base64 string to process |
14726 | | * @param length the length of the string in bytes |
14727 | | * @param output the pointer to a buffer that can hold the conversion |
14728 | | * result (should be at least maximal_binary_length_from_base64(input, length) |
14729 | | * bytes long). |
14730 | | * @param options the base64 options to use, can be base64_default or |
14731 | | * base64_url, is base64_default by default. |
14732 | | * @param last_chunk_options the handling of the last chunk (default: loose) |
14733 | | * @return a full_result pair struct (of type simdutf::result containing the |
14734 | | * three fields error, input_count and output_count). |
14735 | | */ |
14736 | | simdutf_warn_unused virtual full_result base64_to_binary_details( |
14737 | | const char *input, size_t length, char *output, |
14738 | | base64_options options = base64_default, |
14739 | | last_chunk_handling_options last_chunk_options = |
14740 | | last_chunk_handling_options::loose) const noexcept = 0; |
14741 | | |
14742 | | /** |
14743 | | * Convert a base64 input to a binary output. |
14744 | | * |
14745 | | * This function follows the WHATWG forgiving-base64 format, which means that |
14746 | | * it will ignore any ASCII spaces in the input. You may provide a padded |
14747 | | * input (with one or two equal signs at the end) or an unpadded input |
14748 | | * (without any equal signs at the end). |
14749 | | * |
14750 | | * See https://infra.spec.whatwg.org/#forgiving-base64-decode |
14751 | | * |
14752 | | * This function will fail in case of invalid input. When last_chunk_options = |
14753 | | * loose, there are two possible reasons for failure: the input contains a |
14754 | | * number of base64 characters that when divided by 4, leaves a single |
14755 | | * remainder character (BASE64_INPUT_REMAINDER), or the input contains a |
14756 | | * character that is not a valid base64 character (INVALID_BASE64_CHARACTER). |
14757 | | * |
14758 | | * You should call this function with a buffer that is at least |
14759 | | * maximal_binary_length_from_base64(input, length) bytes long. If you |
14760 | | * fail to provide that much space, the function may cause a buffer overflow. |
14761 | | * |
14762 | | * @param input the base64 string to process, in ASCII stored as |
14763 | | * 16-bit units |
14764 | | * @param length the length of the string in 16-bit units |
14765 | | * @param output the pointer to a buffer that can hold the conversion |
14766 | | * result (should be at least maximal_binary_length_from_base64(input, length) |
14767 | | * bytes long). |
14768 | | * @param options the base64 options to use, can be base64_default or |
14769 | | * base64_url, is base64_default by default. |
14770 | | * @param last_chunk_options the handling of the last chunk (default: loose) |
14771 | | * @return a result pair struct (of type simdutf::result containing the two |
14772 | | * fields error and count) with an error code and position of the |
14773 | | * INVALID_BASE64_CHARACTER error (in the input in units) if any, or the |
14774 | | * number of bytes written if successful. |
14775 | | */ |
14776 | | simdutf_warn_unused virtual result |
14777 | | base64_to_binary(const char16_t *input, size_t length, char *output, |
14778 | | base64_options options = base64_default, |
14779 | | last_chunk_handling_options last_chunk_options = |
14780 | | last_chunk_handling_options::loose) const noexcept = 0; |
14781 | | |
14782 | | /** |
14783 | | * Convert a base64 input to a binary output while returning more details |
14784 | | * than base64_to_binary. |
14785 | | * |
14786 | | * This function follows the WHATWG forgiving-base64 format, which means that |
14787 | | * it will ignore any ASCII spaces in the input. You may provide a padded |
14788 | | * input (with one or two equal signs at the end) or an unpadded input |
14789 | | * (without any equal signs at the end). |
14790 | | * |
14791 | | * See https://infra.spec.whatwg.org/#forgiving-base64-decode |
14792 | | * |
14793 | | * This function will fail in case of invalid input. When last_chunk_options = |
14794 | | * loose, there are two possible reasons for failure: the input contains a |
14795 | | * number of base64 characters that when divided by 4, leaves a single |
14796 | | * remainder character (BASE64_INPUT_REMAINDER), or the input contains a |
14797 | | * character that is not a valid base64 character (INVALID_BASE64_CHARACTER). |
14798 | | * |
14799 | | * You should call this function with a buffer that is at least |
14800 | | * maximal_binary_length_from_base64(input, length) bytes long. If you fail to |
14801 | | * provide that much space, the function may cause a buffer overflow. |
14802 | | * |
14803 | | * @param input the base64 string to process |
14804 | | * @param length the length of the string in bytes |
14805 | | * @param output the pointer to a buffer that can hold the conversion |
14806 | | * result (should be at least maximal_binary_length_from_base64(input, length) |
14807 | | * bytes long). |
14808 | | * @param options the base64 options to use, can be base64_default or |
14809 | | * base64_url, is base64_default by default. |
14810 | | * @param last_chunk_options the handling of the last chunk (default: loose) |
14811 | | * @return a full_result pair struct (of type simdutf::result containing the |
14812 | | * three fields error, input_count and output_count). |
14813 | | */ |
14814 | | simdutf_warn_unused virtual full_result base64_to_binary_details( |
14815 | | const char16_t *input, size_t length, char *output, |
14816 | | base64_options options = base64_default, |
14817 | | last_chunk_handling_options last_chunk_options = |
14818 | | last_chunk_handling_options::loose) const noexcept = 0; |
14819 | | |
14820 | | /** |
14821 | | * Provide the base64 length in bytes given the length of a binary input. |
14822 | | * |
14823 | | * @param length the length of the input in bytes |
14824 | | * @param options the base64 options to use, can be base64_default or |
14825 | | * base64_url, is base64_default by default. |
14826 | | * @return number of base64 bytes |
14827 | | */ |
14828 | | simdutf_warn_unused size_t base64_length_from_binary( |
14829 | | size_t length, base64_options options = base64_default) const noexcept; |
14830 | | |
14831 | | /** |
14832 | | * Convert a binary input to a base64 output. |
14833 | | * |
14834 | | * The default option (simdutf::base64_default) uses the characters `+` and |
14835 | | * `/` as part of its alphabet. Further, it adds padding (`=`) at the end of |
14836 | | * the output to ensure that the output length is a multiple of four. |
14837 | | * |
14838 | | * The URL option (simdutf::base64_url) uses the characters `-` and `_` as |
14839 | | * part of its alphabet. No padding is added at the end of the output. |
14840 | | * |
14841 | | * This function always succeeds. |
14842 | | * |
14843 | | * @param input the binary to process |
14844 | | * @param length the length of the input in bytes |
14845 | | * @param output the pointer to a buffer that can hold the conversion |
14846 | | * result (should be at least base64_length_from_binary(length) bytes long) |
14847 | | * @param options the base64 options to use, can be base64_default or |
14848 | | * base64_url, is base64_default by default. |
14849 | | * @return number of written bytes, will be equal to |
14850 | | * base64_length_from_binary(length, options) |
14851 | | */ |
14852 | | virtual size_t |
14853 | | binary_to_base64(const char *input, size_t length, char *output, |
14854 | | base64_options options = base64_default) const noexcept = 0; |
14855 | | |
14856 | | /** |
14857 | | * Convert a binary input to a base64 output with lines of given length. |
14858 | | * Lines are separated by a single linefeed character. |
14859 | | * |
14860 | | * The default option (simdutf::base64_default) uses the characters `+` and |
14861 | | * `/` as part of its alphabet. Further, it adds padding (`=`) at the end of |
14862 | | * the output to ensure that the output length is a multiple of four. |
14863 | | * |
14864 | | * The URL option (simdutf::base64_url) uses the characters `-` and `_` as |
14865 | | * part of its alphabet. No padding is added at the end of the output. |
14866 | | * |
14867 | | * This function always succeeds. |
14868 | | * |
14869 | | * @param input the binary to process |
14870 | | * @param length the length of the input in bytes |
14871 | | * @param output the pointer to a buffer that can hold the conversion |
14872 | | * result (should be at least base64_length_from_binary_with_lines(length, |
14873 | | * options, line_length) bytes long) |
14874 | | * @param line_length the length of each line, values smaller than 4 are |
14875 | | * interpreted as 4 |
14876 | | * @param options the base64 options to use, can be base64_default or |
14877 | | * base64_url, is base64_default by default. |
14878 | | * @return number of written bytes, will be equal to |
14879 | | * base64_length_from_binary_with_lines(length, options, line_length) |
14880 | | */ |
14881 | | virtual size_t binary_to_base64_with_lines( |
14882 | | const char *input, size_t length, char *output, |
14883 | | size_t line_length = simdutf::default_line_length, |
14884 | | base64_options options = base64_default) const noexcept = 0; |
14885 | | |
14886 | | /** |
14887 | | * Find the first occurrence of a character in a string. If the character is |
14888 | | * not found, return a pointer to the end of the string. |
14889 | | * @param start the start of the string |
14890 | | * @param end the end of the string |
14891 | | * @param character the character to find |
14892 | | * @return a pointer to the first occurrence of the character in the string, |
14893 | | * or a pointer to the end of the string if the character is not found. |
14894 | | * |
14895 | | */ |
14896 | | virtual const char *find(const char *start, const char *end, |
14897 | | char character) const noexcept = 0; |
14898 | | virtual const char16_t *find(const char16_t *start, const char16_t *end, |
14899 | | char16_t character) const noexcept = 0; |
14900 | | #endif // SIMDUTF_FEATURE_BASE64 |
14901 | | |
14902 | | #ifdef SIMDUTF_INTERNAL_TESTS |
14903 | | // This method is exported only in developer mode, its purpose |
14904 | | // is to expose some internal test procedures from the given |
14905 | | // implementation and then use them through our standard test |
14906 | | // framework. |
14907 | | // |
14908 | | // Regular users should not use it, the tests of the public |
14909 | | // API are enough. |
14910 | | |
14911 | | struct TestProcedure { |
14912 | | // display name |
14913 | | std::string_view name; |
14914 | | |
14915 | | // procedure should return whether given test pass or not |
14916 | | void (*procedure)(const implementation &); |
14917 | | }; |
14918 | | |
14919 | | virtual std::vector<TestProcedure> internal_tests() const; |
14920 | | #endif |
14921 | | |
14922 | | protected: |
14923 | | /** @private Construct an implementation with the given name and description. |
14924 | | * For subclasses. |
14925 | | * @param name the name of this implementation |
14926 | | * @param description a description of this implementation |
14927 | | * @param required_instruction_sets the instruction sets this implementation |
14928 | | * requires |
14929 | | */ |
14930 | | simdutf_really_inline implementation(const char *name, |
14931 | | const char *description, |
14932 | | uint32_t required_instruction_sets) |
14933 | 5 | : _name(name), _description(description), |
14934 | 5 | _required_instruction_sets(required_instruction_sets) {} |
14935 | | |
14936 | | protected: |
14937 | | ~implementation() = default; |
14938 | | |
14939 | | private: |
14940 | | /** |
14941 | | * The name of this implementation. |
14942 | | */ |
14943 | | const char *_name; |
14944 | | |
14945 | | /** |
14946 | | * The description of this implementation. |
14947 | | */ |
14948 | | const char *_description; |
14949 | | |
14950 | | /** |
14951 | | * Instruction sets required for this implementation. |
14952 | | */ |
14953 | | const uint32_t _required_instruction_sets; |
14954 | | }; |
14955 | | |
14956 | | /** @private */ |
14957 | | namespace internal { |
14958 | | |
14959 | | /** |
14960 | | * The list of available implementations compiled into simdutf. |
14961 | | */ |
14962 | | class available_implementation_list { |
14963 | | public: |
14964 | | /** Get the list of available implementations compiled into simdutf */ |
14965 | 1 | simdutf_really_inline available_implementation_list() {} |
14966 | | /** Number of implementations */ |
14967 | | size_t size() const noexcept; |
14968 | | /** STL const begin() iterator */ |
14969 | | const implementation *const *begin() const noexcept; |
14970 | | /** STL const end() iterator */ |
14971 | | const implementation *const *end() const noexcept; |
14972 | | |
14973 | | /** |
14974 | | * Get the implementation with the given name. |
14975 | | * |
14976 | | * Case sensitive. |
14977 | | * |
14978 | | * const implementation *impl = |
14979 | | * simdutf::available_implementations["westmere"]; if (!impl) { exit(1); } if |
14980 | | * (!imp->supported_by_runtime_system()) { exit(1); } |
14981 | | * simdutf::active_implementation = impl; |
14982 | | * |
14983 | | * @param name the implementation to find, e.g. "westmere", "haswell", "arm64" |
14984 | | * @return the implementation, or nullptr if the parse failed. |
14985 | | */ |
14986 | 0 | const implementation *operator[](std::string_view name) const noexcept { |
14987 | 0 | for (const implementation *impl : *this) { |
14988 | 0 | if (impl->name() == name) { |
14989 | 0 | return impl; |
14990 | 0 | } |
14991 | 0 | } |
14992 | 0 | return nullptr; |
14993 | 0 | } |
14994 | | |
14995 | | /** |
14996 | | * Detect the most advanced implementation supported by the current host. |
14997 | | * |
14998 | | * This is used to initialize the implementation on startup. |
14999 | | * |
15000 | | * const implementation *impl = |
15001 | | * simdutf::available_implementation::detect_best_supported(); |
15002 | | * simdutf::active_implementation = impl; |
15003 | | * |
15004 | | * @return the most advanced supported implementation for the current host, or |
15005 | | * an implementation that returns UNSUPPORTED_ARCHITECTURE if there is no |
15006 | | * supported implementation. Will never return nullptr. |
15007 | | */ |
15008 | | const implementation *detect_best_supported() const noexcept; |
15009 | | }; |
15010 | | |
15011 | | template <typename T> class atomic_ptr { |
15012 | | public: |
15013 | 1 | atomic_ptr(T *_ptr) : ptr{_ptr} {} |
15014 | | |
15015 | | #if defined(SIMDUTF_NO_THREADS) |
15016 | | operator const T *() const { return ptr; } |
15017 | | const T &operator*() const { return *ptr; } |
15018 | | const T *operator->() const { return ptr; } |
15019 | | |
15020 | | operator T *() { return ptr; } |
15021 | | T &operator*() { return *ptr; } |
15022 | | T *operator->() { return ptr; } |
15023 | | atomic_ptr &operator=(T *_ptr) { |
15024 | | ptr = _ptr; |
15025 | | return *this; |
15026 | | } |
15027 | | |
15028 | | #else |
15029 | | operator const T *() const { return ptr.load(); } |
15030 | | const T &operator*() const { return *ptr; } |
15031 | | const T *operator->() const { return ptr.load(); } |
15032 | | |
15033 | 1 | operator T *() { return ptr.load(); } |
15034 | | T &operator*() { return *ptr; } |
15035 | 22.7k | T *operator->() { return ptr.load(); } |
15036 | 1 | atomic_ptr &operator=(T *_ptr) { |
15037 | 1 | ptr = _ptr; |
15038 | 1 | return *this; |
15039 | 1 | } |
15040 | | |
15041 | | #endif |
15042 | | |
15043 | | private: |
15044 | | #if defined(SIMDUTF_NO_THREADS) |
15045 | | T *ptr; |
15046 | | #else |
15047 | | std::atomic<T *> ptr; |
15048 | | #endif |
15049 | | }; |
15050 | | |
15051 | | class detect_best_supported_implementation_on_first_use; |
15052 | | |
15053 | | } // namespace internal |
15054 | | |
15055 | | /** |
15056 | | * The list of available implementations compiled into simdutf. |
15057 | | */ |
15058 | | extern SIMDUTF_DLLIMPORTEXPORT const internal::available_implementation_list & |
15059 | | get_available_implementations(); |
15060 | | |
15061 | | /** |
15062 | | * The active implementation. |
15063 | | * |
15064 | | * Automatically initialized on first use to the most advanced implementation |
15065 | | * supported by this hardware. |
15066 | | */ |
15067 | | extern SIMDUTF_DLLIMPORTEXPORT internal::atomic_ptr<const implementation> & |
15068 | | get_active_implementation(); |
15069 | | |
15070 | | } // namespace simdutf |
15071 | | |
15072 | | #if SIMDUTF_FEATURE_BASE64 |
15073 | | // this header is not part of the public api |
15074 | | /* begin file include/simdutf/base64_implementation.h */ |
15075 | | #ifndef SIMDUTF_BASE64_IMPLEMENTATION_H |
15076 | | #define SIMDUTF_BASE64_IMPLEMENTATION_H |
15077 | | |
15078 | | // this is not part of the public api |
15079 | | |
15080 | | #include <type_traits> // for is_same |
15081 | | |
15082 | | namespace simdutf { |
15083 | | |
15084 | | template <typename chartype> |
15085 | | simdutf_warn_unused simdutf_constexpr23 result slow_base64_to_binary_safe_impl( |
15086 | | const chartype *input, size_t length, char *output, size_t &outlen, |
15087 | | base64_options options, |
15088 | 0 | last_chunk_handling_options last_chunk_options) noexcept { |
15089 | 0 | const bool ignore_garbage = (options & base64_default_accept_garbage) != 0; |
15090 | 0 | auto ri = simdutf::scalar::base64::find_end(input, length, options); |
15091 | 0 | size_t equallocation = ri.equallocation; |
15092 | 0 | size_t equalsigns = ri.equalsigns; |
15093 | 0 | length = ri.srclen; |
15094 | 0 | size_t full_input_length = ri.full_input_length; |
15095 | 0 | (void)full_input_length; |
15096 | 0 | if (length == 0) { |
15097 | 0 | outlen = 0; |
15098 | 0 | if (!ignore_garbage && equalsigns > 0) { |
15099 | 0 | return {INVALID_BASE64_CHARACTER, equallocation}; |
15100 | 0 | } |
15101 | 0 | return {SUCCESS, 0}; |
15102 | 0 | } |
15103 | | |
15104 | | // The parameters of base64_tail_decode_safe are: |
15105 | | // - dst: the output buffer |
15106 | | // - outlen: the size of the output buffer |
15107 | | // - srcr: the input buffer |
15108 | | // - length: the size of the input buffer |
15109 | | // - padded_characters: the number of padding characters |
15110 | | // - options: the options for the base64 decoder |
15111 | | // - last_chunk_options: the options for the last chunk |
15112 | | // The function will return the number of bytes written to the output buffer |
15113 | | // and the number of bytes read from the input buffer. |
15114 | | // The function will also return an error code if the input buffer is not |
15115 | | // valid base64. |
15116 | 0 | full_result r = scalar::base64::base64_tail_decode_safe( |
15117 | 0 | output, outlen, input, length, equalsigns, options, last_chunk_options); |
15118 | 0 | r = scalar::base64::patch_tail_result(r, 0, 0, equallocation, |
15119 | 0 | full_input_length, last_chunk_options); |
15120 | 0 | outlen = r.output_count; |
15121 | 0 | if (!is_partial(last_chunk_options) && r.error == error_code::SUCCESS && |
15122 | 0 | equalsigns > 0) { |
15123 | | // additional checks |
15124 | 0 | if ((outlen % 3 == 0) || ((outlen % 3) + 1 + equalsigns != 4)) { |
15125 | 0 | r.error = error_code::INVALID_BASE64_CHARACTER; |
15126 | 0 | } |
15127 | 0 | } |
15128 | 0 | return {r.error, r.input_count}; // we cannot return r itself because it gets |
15129 | | // converted to error/output_count |
15130 | 0 | } Unexecuted instantiation: simdutf::result simdutf::slow_base64_to_binary_safe_impl<char>(char const*, unsigned long, char*, unsigned long&, simdutf::base64_options, simdutf::last_chunk_handling_options) Unexecuted instantiation: simdutf::result simdutf::slow_base64_to_binary_safe_impl<char16_t>(char16_t const*, unsigned long, char*, unsigned long&, simdutf::base64_options, simdutf::last_chunk_handling_options) |
15131 | | |
15132 | | template <typename chartype> |
15133 | | simdutf_warn_unused simdutf_constexpr23 result base64_to_binary_safe_impl( |
15134 | | const chartype *input, size_t length, char *output, size_t &outlen, |
15135 | | base64_options options, |
15136 | | last_chunk_handling_options last_chunk_handling_options, |
15137 | 0 | bool decode_up_to_bad_char) noexcept { |
15138 | 0 | static_assert(std::is_same<chartype, char>::value || |
15139 | 0 | std::is_same<chartype, char16_t>::value, |
15140 | 0 | "Only char and char16_t are supported."); |
15141 | 0 | size_t remaining_input_length = length; |
15142 | 0 | size_t remaining_output_length = outlen; |
15143 | 0 | size_t input_position = 0; |
15144 | 0 | size_t output_position = 0; |
15145 | | |
15146 | | // We also do a first pass using the fast path to decode as much as possible |
15147 | 0 | size_t safe_input = detail::min( |
15148 | 0 | remaining_input_length, |
15149 | 0 | base64_length_from_binary(remaining_output_length / 3 * 3, options)); |
15150 | 0 | bool done_with_partial = (safe_input == remaining_input_length); |
15151 | 0 | simdutf::full_result r; |
15152 | |
|
15153 | | #if SIMDUTF_CPLUSPLUS23 |
15154 | | if consteval { |
15155 | | r = scalar::base64::base64_to_binary_details_impl( |
15156 | | input + input_position, safe_input, output + output_position, options, |
15157 | | done_with_partial |
15158 | | ? last_chunk_handling_options |
15159 | | : simdutf::last_chunk_handling_options::only_full_chunks); |
15160 | | } else |
15161 | | #endif |
15162 | 0 | { |
15163 | 0 | r = get_active_implementation()->base64_to_binary_details( |
15164 | 0 | input + input_position, safe_input, output + output_position, options, |
15165 | 0 | done_with_partial |
15166 | 0 | ? last_chunk_handling_options |
15167 | 0 | : simdutf::last_chunk_handling_options::only_full_chunks); |
15168 | 0 | } |
15169 | 0 | simdutf_log_assert(r.input_count <= safe_input, |
15170 | 0 | "You should not read more than safe_input"); |
15171 | 0 | simdutf_log_assert(r.output_count <= remaining_output_length, |
15172 | 0 | "You should not write more than remaining_output_length"); |
15173 | | // Technically redundant, but we want to be explicit about it. |
15174 | 0 | input_position += r.input_count; |
15175 | 0 | output_position += r.output_count; |
15176 | 0 | remaining_input_length -= r.input_count; |
15177 | 0 | remaining_output_length -= r.output_count; |
15178 | 0 | if (r.error != simdutf::error_code::SUCCESS) { |
15179 | | // There is an error. We return. |
15180 | 0 | if (decode_up_to_bad_char && |
15181 | 0 | r.error == error_code::INVALID_BASE64_CHARACTER) { |
15182 | 0 | return slow_base64_to_binary_safe_impl( |
15183 | 0 | input, length, output, outlen, options, last_chunk_handling_options); |
15184 | 0 | } |
15185 | 0 | outlen = output_position; |
15186 | 0 | return {r.error, input_position}; |
15187 | 0 | } |
15188 | | |
15189 | 0 | if (done_with_partial) { |
15190 | | // We are done. We have decoded everything. |
15191 | 0 | outlen = output_position; |
15192 | 0 | return {simdutf::error_code::SUCCESS, input_position}; |
15193 | 0 | } |
15194 | | // We have decoded some data, but we still have some data to decode. |
15195 | | // We need to decode the rest of the input buffer. |
15196 | 0 | r = simdutf::scalar::base64::base64_to_binary_details_safe_impl( |
15197 | 0 | input + input_position, remaining_input_length, output + output_position, |
15198 | 0 | remaining_output_length, options, last_chunk_handling_options); |
15199 | 0 | input_position += r.input_count; |
15200 | 0 | output_position += r.output_count; |
15201 | 0 | remaining_input_length -= r.input_count; |
15202 | 0 | remaining_output_length -= r.output_count; |
15203 | |
|
15204 | 0 | if (r.error != simdutf::error_code::SUCCESS) { |
15205 | | // There is an error. We return. |
15206 | 0 | if (decode_up_to_bad_char && |
15207 | 0 | r.error == error_code::INVALID_BASE64_CHARACTER) { |
15208 | 0 | return slow_base64_to_binary_safe_impl( |
15209 | 0 | input, length, output, outlen, options, last_chunk_handling_options); |
15210 | 0 | } |
15211 | 0 | outlen = output_position; |
15212 | 0 | return {r.error, input_position}; |
15213 | 0 | } |
15214 | 0 | if (input_position < length) { |
15215 | | // We cannot process the entire input in one go, so we need to |
15216 | | // process it in two steps: first the fast path, then the slow path. |
15217 | | // In some cases, the processing might 'eat up' trailing ignorable |
15218 | | // characters in the fast path, but that can be a problem. |
15219 | | // suppose we have just white space followed by a single base64 character. |
15220 | | // If we first process the white space with the fast path, it will |
15221 | | // eat all of it. But, by the JavaScript standard, we should consume |
15222 | | // no character. See |
15223 | | // https://tc39.es/proposal-arraybuffer-base64/spec/#sec-frombase64 |
15224 | 0 | while (input_position > 0 && |
15225 | 0 | base64_ignorable(input[input_position - 1], options)) { |
15226 | 0 | input_position--; |
15227 | 0 | } |
15228 | 0 | } |
15229 | 0 | outlen = output_position; |
15230 | 0 | return {simdutf::error_code::SUCCESS, input_position}; |
15231 | 0 | } Unexecuted instantiation: simdutf::result simdutf::base64_to_binary_safe_impl<char>(char const*, unsigned long, char*, unsigned long&, simdutf::base64_options, simdutf::last_chunk_handling_options, bool) Unexecuted instantiation: simdutf::result simdutf::base64_to_binary_safe_impl<char16_t>(char16_t const*, unsigned long, char*, unsigned long&, simdutf::base64_options, simdutf::last_chunk_handling_options, bool) |
15232 | | |
15233 | | } // namespace simdutf |
15234 | | #endif // SIMDUTF_BASE64_IMPLEMENTATION_H |
15235 | | /* end file include/simdutf/base64_implementation.h */ |
15236 | | |
15237 | | namespace simdutf { |
15238 | | #if SIMDUTF_SPAN |
15239 | | /** |
15240 | | * @brief span overload |
15241 | | * @return a tuple of result and outlen |
15242 | | */ |
15243 | | simdutf_really_inline |
15244 | | simdutf_constexpr23 simdutf_warn_unused std::tuple<result, std::size_t> |
15245 | | base64_to_binary_safe( |
15246 | | const detail::input_span_of_byte_like auto &input, |
15247 | | detail::output_span_of_byte_like auto &&binary_output, |
15248 | | base64_options options = base64_default, |
15249 | | last_chunk_handling_options last_chunk_options = loose, |
15250 | | bool decode_up_to_bad_char = false) noexcept { |
15251 | | size_t outlen = binary_output.size(); |
15252 | | #if SIMDUTF_CPLUSPLUS23 |
15253 | | if consteval { |
15254 | | using CInput = std::decay_t<decltype(*input.data())>; |
15255 | | static_assert(std::is_same_v<CInput, char>, |
15256 | | "sorry, the constexpr implementation is for now limited to " |
15257 | | "input of type char"); |
15258 | | using COutput = std::decay_t<decltype(*binary_output.data())>; |
15259 | | static_assert(std::is_same_v<COutput, char>, |
15260 | | "sorry, the constexpr implementation is for now limited to " |
15261 | | "output of type char"); |
15262 | | auto r = base64_to_binary_safe_impl( |
15263 | | input.data(), input.size(), binary_output.data(), outlen, options, |
15264 | | last_chunk_options, decode_up_to_bad_char); |
15265 | | return {r, outlen}; |
15266 | | } else |
15267 | | #endif |
15268 | | { |
15269 | | auto r = base64_to_binary_safe_impl<char>( |
15270 | | reinterpret_cast<const char *>(input.data()), input.size(), |
15271 | | reinterpret_cast<char *>(binary_output.data()), outlen, options, |
15272 | | last_chunk_options, decode_up_to_bad_char); |
15273 | | return {r, outlen}; |
15274 | | } |
15275 | | } |
15276 | | |
15277 | | #if SIMDUTF_SPAN |
15278 | | /** |
15279 | | * @brief span overload |
15280 | | * @return a tuple of result and outlen |
15281 | | */ |
15282 | | simdutf_really_inline |
15283 | | simdutf_warn_unused simdutf_constexpr23 std::tuple<result, std::size_t> |
15284 | | base64_to_binary_safe( |
15285 | | std::span<const char16_t> input, |
15286 | | detail::output_span_of_byte_like auto &&binary_output, |
15287 | | base64_options options = base64_default, |
15288 | | last_chunk_handling_options last_chunk_options = loose, |
15289 | | bool decode_up_to_bad_char = false) noexcept { |
15290 | | size_t outlen = binary_output.size(); |
15291 | | #if SIMDUTF_CPLUSPLUS23 |
15292 | | if consteval { |
15293 | | auto r = base64_to_binary_safe_impl( |
15294 | | input.data(), input.size(), binary_output.data(), outlen, options, |
15295 | | last_chunk_options, decode_up_to_bad_char); |
15296 | | return {r, outlen}; |
15297 | | } else |
15298 | | #endif |
15299 | | { |
15300 | | auto r = base64_to_binary_safe( |
15301 | | input.data(), input.size(), |
15302 | | reinterpret_cast<char *>(binary_output.data()), outlen, options, |
15303 | | last_chunk_options, decode_up_to_bad_char); |
15304 | | return {r, outlen}; |
15305 | | } |
15306 | | } |
15307 | | #endif // SIMDUTF_SPAN |
15308 | | |
15309 | | #endif // SIMDUTF_SPAN |
15310 | | } // namespace simdutf |
15311 | | |
15312 | | #endif // SIMDUTF_FEATURE_BASE64 |
15313 | | |
15314 | | #if SIMDUTF_CPLUSPLUS23 && SIMDUTF_FEATURE_BASE64 |
15315 | | |
15316 | | namespace simdutf { |
15317 | | namespace literals { |
15318 | | |
15319 | | namespace detail { |
15320 | | |
15321 | | // the detail namespace is not part of the public api |
15322 | | |
15323 | | template <std::size_t N> struct base64_literal_helper { |
15324 | | std::array<char, N - 1> storage{}; |
15325 | | static constexpr std::size_t size() noexcept { return N - 1; } |
15326 | | consteval base64_literal_helper(const char (&str)[N]) { |
15327 | | for (std::size_t i = 0; i < size(); i++) { |
15328 | | storage[i] = str[i]; |
15329 | | } |
15330 | | } |
15331 | | }; |
15332 | | |
15333 | | template <std::size_t InputLen> struct base64_decode_result { |
15334 | | static constexpr std::size_t max_out = (InputLen + 3) / 4 * 3; |
15335 | | std::array<char, max_out> buffer{}; |
15336 | | std::size_t output_count{}; |
15337 | | }; |
15338 | | |
15339 | | template <std::size_t InputLen> |
15340 | | consteval auto base64_decode_literal(const char *str) { |
15341 | | base64_decode_result<InputLen> result{}; |
15342 | | auto r = scalar::base64::base64_to_binary_details_impl( |
15343 | | str, InputLen, result.buffer.data(), base64_default, loose); |
15344 | | if (r.error != error_code::SUCCESS) { |
15345 | | #if __cpp_lib_unreachable >= 202202L |
15346 | | std::unreachable(); // invalid base64 input in _base64 literal |
15347 | | #else |
15348 | | // workaround for older stdlib |
15349 | | throw "invalid base64 input in _base64 literal"; |
15350 | | #endif |
15351 | | } |
15352 | | result.output_count = r.output_count; |
15353 | | return result; |
15354 | | } |
15355 | | |
15356 | | template <base64_literal_helper a> consteval auto base64_make_array() { |
15357 | | constexpr auto decoded = base64_decode_literal<a.size()>(a.storage.data()); |
15358 | | std::array<char, decoded.output_count> ret{}; |
15359 | | for (std::size_t i = 0; i < decoded.output_count; i++) { |
15360 | | ret[i] = decoded.buffer[i]; |
15361 | | } |
15362 | | return ret; |
15363 | | } |
15364 | | |
15365 | | } // namespace detail |
15366 | | |
15367 | | /** |
15368 | | * User-defined literal for compile-time base64 decoding. |
15369 | | * |
15370 | | * Usage: |
15371 | | * using namespace simdutf::literals; |
15372 | | * constexpr auto decoded = "SGVsbG8gV29ybGQh"_base64; |
15373 | | * // decoded is a std::array<char, 12> containing "Hello World!" |
15374 | | * |
15375 | | * The input must be valid base64. Whitepace is allowed and ignored. |
15376 | | * A compilation error occurs if the input is invalid. |
15377 | | */ |
15378 | | template <detail::base64_literal_helper a> consteval auto operator""_base64() { |
15379 | | return detail::base64_make_array<a>(); |
15380 | | } |
15381 | | |
15382 | | } // namespace literals |
15383 | | } // namespace simdutf |
15384 | | |
15385 | | #endif // SIMDUTF_CPLUSPLUS23 && SIMDUTF_FEATURE_BASE64 |
15386 | | |
15387 | | #endif // SIMDUTF_IMPLEMENTATION_H |
15388 | | /* end file include/simdutf/implementation.h */ |
15389 | | |
15390 | | // Implementation-internal files (must be included before the implementations |
15391 | | // themselves, to keep amalgamation working--otherwise, the first time a file is |
15392 | | // included, it might be put inside the #ifdef |
15393 | | // SIMDUTF_IMPLEMENTATION_ARM64/FALLBACK/etc., which means the other |
15394 | | // implementations can't compile unless that implementation is turned on). |
15395 | | |
15396 | | SIMDUTF_POP_DISABLE_WARNINGS |
15397 | | |
15398 | | #endif // SIMDUTF_H |
15399 | | /* end file include/simdutf.h */ |