Ada 2.9.0
Fast spec-compliant URL parser
Loading...
Searching...
No Matches
ada.h
Go to the documentation of this file.
1/* auto-generated on 2024-08-06 10:21:46.081562. Do not edit! */
2/* begin file include/ada.h */
7#ifndef ADA_H
8#define ADA_H
9
10/* begin file include/ada/ada_idna.h */
11/* auto-generated on 2023-09-19 15:58:51 -0400. Do not edit! */
12/* begin file include/idna.h */
13#ifndef ADA_IDNA_H
14#define ADA_IDNA_H
15
16/* begin file include/ada/idna/unicode_transcoding.h */
17#ifndef ADA_IDNA_UNICODE_TRANSCODING_H
18#define ADA_IDNA_UNICODE_TRANSCODING_H
19
20#include <string>
21#include <string_view>
22
23namespace ada::idna {
24
25size_t utf8_to_utf32(const char* buf, size_t len, char32_t* utf32_output);
26
27size_t utf8_length_from_utf32(const char32_t* buf, size_t len);
28
29size_t utf32_length_from_utf8(const char* buf, size_t len);
30
31size_t utf32_to_utf8(const char32_t* buf, size_t len, char* utf8_output);
32
33} // namespace ada::idna
34
35#endif // ADA_IDNA_UNICODE_TRANSCODING_H
36/* end file include/ada/idna/unicode_transcoding.h */
37/* begin file include/ada/idna/mapping.h */
38#ifndef ADA_IDNA_MAPPING_H
39#define ADA_IDNA_MAPPING_H
40
41#include <string>
42#include <string_view>
43
44namespace ada::idna {
45
46// If the input is ascii, then the mapping is just -> lower case.
47void ascii_map(char* input, size_t length);
48// check whether an ascii string needs mapping
49bool ascii_has_upper_case(char* input, size_t length);
50// Map the characters according to IDNA, returning the empty string on error.
51std::u32string map(std::u32string_view input);
52
53} // namespace ada::idna
54
55#endif
56/* end file include/ada/idna/mapping.h */
57/* begin file include/ada/idna/normalization.h */
58#ifndef ADA_IDNA_NORMALIZATION_H
59#define ADA_IDNA_NORMALIZATION_H
60
61#include <string>
62#include <string_view>
63
64namespace ada::idna {
65
66// Normalize the characters according to IDNA (Unicode Normalization Form C).
67void normalize(std::u32string& input);
68
69} // namespace ada::idna
70#endif
71/* end file include/ada/idna/normalization.h */
72/* begin file include/ada/idna/punycode.h */
73#ifndef ADA_IDNA_PUNYCODE_H
74#define ADA_IDNA_PUNYCODE_H
75
76#include <string>
77#include <string_view>
78
79namespace ada::idna {
80
81bool punycode_to_utf32(std::string_view input, std::u32string& out);
82bool verify_punycode(std::string_view input);
83bool utf32_to_punycode(std::u32string_view input, std::string& out);
84
85} // namespace ada::idna
86
87#endif // ADA_IDNA_PUNYCODE_H
88/* end file include/ada/idna/punycode.h */
89/* begin file include/ada/idna/validity.h */
90#ifndef ADA_IDNA_VALIDITY_H
91#define ADA_IDNA_VALIDITY_H
92
93#include <string>
94#include <string_view>
95
96namespace ada::idna {
97
101bool is_label_valid(std::u32string_view label);
102
103} // namespace ada::idna
104
105#endif // ADA_IDNA_VALIDITY_H
106/* end file include/ada/idna/validity.h */
107/* begin file include/ada/idna/to_ascii.h */
108#ifndef ADA_IDNA_TO_ASCII_H
109#define ADA_IDNA_TO_ASCII_H
110
111#include <string>
112#include <string_view>
113
114namespace ada::idna {
115
116// Converts a domain (e.g., www.google.com) possibly containing international
117// characters to an ascii domain (with punycode). It will not do percent
118// decoding: percent decoding should be done prior to calling this function. We
119// do not remove tabs and spaces, they should have been removed prior to calling
120// this function. We also do not trim control characters. We also assume that
121// the input is not empty. We return "" on error.
122//
123//
124// This function may accept or even produce invalid domains.
125std::string to_ascii(std::string_view ut8_string);
126
127// Returns true if the string contains a forbidden code point according to the
128// WHATGL URL specification:
129// https://url.spec.whatwg.org/#forbidden-domain-code-point
130bool contains_forbidden_domain_code_point(std::string_view ascii_string);
131
132bool begins_with(std::u32string_view view, std::u32string_view prefix);
133bool begins_with(std::string_view view, std::string_view prefix);
134
135bool constexpr is_ascii(std::u32string_view view);
136bool constexpr is_ascii(std::string_view view);
137
138} // namespace ada::idna
139
140#endif // ADA_IDNA_TO_ASCII_H
141/* end file include/ada/idna/to_ascii.h */
142/* begin file include/ada/idna/to_unicode.h */
143
144#ifndef ADA_IDNA_TO_UNICODE_H
145#define ADA_IDNA_TO_UNICODE_H
146
147#include <string_view>
148
149namespace ada::idna {
150
151std::string to_unicode(std::string_view input);
152
153} // namespace ada::idna
154
155#endif // ADA_IDNA_TO_UNICODE_H
156/* end file include/ada/idna/to_unicode.h */
157
158#endif
159/* end file include/idna.h */
160/* end file include/ada/ada_idna.h */
161/* begin file include/ada/character_sets-inl.h */
168#ifndef ADA_CHARACTER_SETS_INL_H
169#define ADA_CHARACTER_SETS_INL_H
170
171/* begin file include/ada/character_sets.h */
178#ifndef ADA_CHARACTER_SETS_H
179#define ADA_CHARACTER_SETS_H
180
181/* begin file include/ada/common_defs.h */
186#ifndef ADA_COMMON_DEFS_H
187#define ADA_COMMON_DEFS_H
188
189#ifdef _MSC_VER
190#define ADA_VISUAL_STUDIO 1
196#ifdef __clang__
197// clang under visual studio
198#define ADA_CLANG_VISUAL_STUDIO 1
199#else
200// just regular visual studio (best guess)
201#define ADA_REGULAR_VISUAL_STUDIO 1
202#endif // __clang__
203#endif // _MSC_VER
204
205#if defined(__GNUC__)
206// Marks a block with a name so that MCA analysis can see it.
207#define ADA_BEGIN_DEBUG_BLOCK(name) __asm volatile("# LLVM-MCA-BEGIN " #name);
208#define ADA_END_DEBUG_BLOCK(name) __asm volatile("# LLVM-MCA-END " #name);
209#define ADA_DEBUG_BLOCK(name, block) \
210 BEGIN_DEBUG_BLOCK(name); \
211 block; \
212 END_DEBUG_BLOCK(name);
213#else
214#define ADA_BEGIN_DEBUG_BLOCK(name)
215#define ADA_END_DEBUG_BLOCK(name)
216#define ADA_DEBUG_BLOCK(name, block)
217#endif
218
219// Align to N-byte boundary
220#define ADA_ROUNDUP_N(a, n) (((a) + ((n)-1)) & ~((n)-1))
221#define ADA_ROUNDDOWN_N(a, n) ((a) & ~((n)-1))
222
223#define ADA_ISALIGNED_N(ptr, n) (((uintptr_t)(ptr) & ((n)-1)) == 0)
224
225#if defined(ADA_REGULAR_VISUAL_STUDIO)
226
227#define ada_really_inline __forceinline
228#define ada_never_inline __declspec(noinline)
229
230#define ada_unused
231#define ada_warn_unused
232
233#ifndef ada_likely
234#define ada_likely(x) x
235#endif
236#ifndef ada_unlikely
237#define ada_unlikely(x) x
238#endif
239
240#define ADA_PUSH_DISABLE_WARNINGS __pragma(warning(push))
241#define ADA_PUSH_DISABLE_ALL_WARNINGS __pragma(warning(push, 0))
242#define ADA_DISABLE_VS_WARNING(WARNING_NUMBER) \
243 __pragma(warning(disable : WARNING_NUMBER))
244// Get rid of Intellisense-only warnings (Code Analysis)
245// Though __has_include is C++17, it is supported in Visual Studio 2017 or
246// better (_MSC_VER>=1910).
247#ifdef __has_include
248#if __has_include(<CppCoreCheck\Warnings.h>)
249#include <CppCoreCheck\Warnings.h>
250#define ADA_DISABLE_UNDESIRED_WARNINGS \
251 ADA_DISABLE_VS_WARNING(ALL_CPPCORECHECK_WARNINGS)
252#endif
253#endif
254
255#ifndef ADA_DISABLE_UNDESIRED_WARNINGS
256#define ADA_DISABLE_UNDESIRED_WARNINGS
257#endif
258
259#define ADA_DISABLE_DEPRECATED_WARNING ADA_DISABLE_VS_WARNING(4996)
260#define ADA_DISABLE_STRICT_OVERFLOW_WARNING
261#define ADA_POP_DISABLE_WARNINGS __pragma(warning(pop))
262
263#else // ADA_REGULAR_VISUAL_STUDIO
264
265#define ada_really_inline inline __attribute__((always_inline))
266#define ada_never_inline inline __attribute__((noinline))
267
268#define ada_unused __attribute__((unused))
269#define ada_warn_unused __attribute__((warn_unused_result))
270
271#ifndef ada_likely
272#define ada_likely(x) __builtin_expect(!!(x), 1)
273#endif
274#ifndef ada_unlikely
275#define ada_unlikely(x) __builtin_expect(!!(x), 0)
276#endif
277
278#define ADA_PUSH_DISABLE_WARNINGS _Pragma("GCC diagnostic push")
279// gcc doesn't seem to disable all warnings with all and extra, add warnings
280// here as necessary
281#define ADA_PUSH_DISABLE_ALL_WARNINGS \
282 ADA_PUSH_DISABLE_WARNINGS \
283 ADA_DISABLE_GCC_WARNING("-Weffc++") \
284 ADA_DISABLE_GCC_WARNING("-Wall") \
285 ADA_DISABLE_GCC_WARNING("-Wconversion") \
286 ADA_DISABLE_GCC_WARNING("-Wextra") \
287 ADA_DISABLE_GCC_WARNING("-Wattributes") \
288 ADA_DISABLE_GCC_WARNING("-Wimplicit-fallthrough") \
289 ADA_DISABLE_GCC_WARNING("-Wnon-virtual-dtor") \
290 ADA_DISABLE_GCC_WARNING("-Wreturn-type") \
291 ADA_DISABLE_GCC_WARNING("-Wshadow") \
292 ADA_DISABLE_GCC_WARNING("-Wunused-parameter") \
293 ADA_DISABLE_GCC_WARNING("-Wunused-variable")
294#define ADA_PRAGMA(P) _Pragma(#P)
295#define ADA_DISABLE_GCC_WARNING(WARNING) \
296 ADA_PRAGMA(GCC diagnostic ignored WARNING)
297#if defined(ADA_CLANG_VISUAL_STUDIO)
298#define ADA_DISABLE_UNDESIRED_WARNINGS \
299 ADA_DISABLE_GCC_WARNING("-Wmicrosoft-include")
300#else
301#define ADA_DISABLE_UNDESIRED_WARNINGS
302#endif
303#define ADA_DISABLE_DEPRECATED_WARNING \
304 ADA_DISABLE_GCC_WARNING("-Wdeprecated-declarations")
305#define ADA_DISABLE_STRICT_OVERFLOW_WARNING \
306 ADA_DISABLE_GCC_WARNING("-Wstrict-overflow")
307#define ADA_POP_DISABLE_WARNINGS _Pragma("GCC diagnostic pop")
308
309#endif // MSC_VER
310
311#if defined(ADA_VISUAL_STUDIO)
317#if ADA_USING_LIBRARY
318#define ADA_DLLIMPORTEXPORT __declspec(dllimport)
319#else
320#define ADA_DLLIMPORTEXPORT __declspec(dllexport)
321#endif
322#else
323#define ADA_DLLIMPORTEXPORT
324#endif
325
327#define ADA_TRY(EXPR) \
328 { \
329 auto _err = (EXPR); \
330 if (_err) { \
331 return _err; \
332 } \
333 }
334
335// __has_cpp_attribute is part of C++20
336#if !defined(__has_cpp_attribute)
337#define __has_cpp_attribute(x) 0
338#endif
339
340#if __has_cpp_attribute(gnu::noinline)
341#define ADA_ATTRIBUTE_NOINLINE [[gnu::noinline]]
342#else
343#define ADA_ATTRIBUTE_NOINLINE
344#endif
345
346namespace ada {
347[[noreturn]] inline void unreachable() {
348#ifdef __GNUC__
349 __builtin_unreachable();
350#elif defined(_MSC_VER)
351 __assume(false);
352#else
353#endif
354}
355} // namespace ada
356
357#if defined(__GNUC__) && !defined(__clang__)
358#if __GNUC__ <= 8
359#define ADA_OLD_GCC 1
360#endif // __GNUC__ <= 8
361#endif // defined(__GNUC__) && !defined(__clang__)
362
363#if ADA_OLD_GCC
364#define ada_constexpr
365#else
366#define ada_constexpr constexpr
367#endif
368
369#if defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__)
370#define ADA_IS_BIG_ENDIAN (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
371#elif defined(_WIN32)
372#define ADA_IS_BIG_ENDIAN 0
373#else
374#if defined(__APPLE__) || \
375 defined(__FreeBSD__) // defined __BYTE_ORDER__ && defined
376 // __ORDER_BIG_ENDIAN__
377#include <machine/endian.h>
378#elif defined(sun) || \
379 defined(__sun) // defined(__APPLE__) || defined(__FreeBSD__)
380#include <sys/byteorder.h>
381#else // defined(__APPLE__) || defined(__FreeBSD__)
382
383#ifdef __has_include
384#if __has_include(<endian.h>)
385#include <endian.h>
386#endif //__has_include(<endian.h>)
387#endif //__has_include
388
389#endif // defined(__APPLE__) || defined(__FreeBSD__)
390
391#ifndef !defined(__BYTE_ORDER__) || !defined(__ORDER_LITTLE_ENDIAN__)
392#define ADA_IS_BIG_ENDIAN 0
393#endif
394
395#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
396#define ADA_IS_BIG_ENDIAN 0
397#else // __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
398#define ADA_IS_BIG_ENDIAN 1
399#endif // __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
400
401#endif // defined __BYTE_ORDER__ && defined __ORDER_BIG_ENDIAN__
402
403// Unless the programmer has already set ADA_DEVELOPMENT_CHECKS,
404// we want to set it under debug builds. We detect a debug build
405// under Visual Studio when the _DEBUG macro is set. Under the other
406// compilers, we use the fact that they define __OPTIMIZE__ whenever
407// they allow optimizations.
408// It is possible that this could miss some cases where ADA_DEVELOPMENT_CHECKS
409// is helpful, but the programmer can set the macro ADA_DEVELOPMENT_CHECKS.
410// It could also wrongly set ADA_DEVELOPMENT_CHECKS (e.g., if the programmer
411// sets _DEBUG in a release build under Visual Studio, or if some compiler fails
412// to set the __OPTIMIZE__ macro).
413#if !defined(ADA_DEVELOPMENT_CHECKS) && !defined(NDEBUG)
414#ifdef _MSC_VER
415// Visual Studio seems to set _DEBUG for debug builds.
416#ifdef _DEBUG
417#define ADA_DEVELOPMENT_CHECKS 1
418#endif // _DEBUG
419#else // _MSC_VER
420// All other compilers appear to set __OPTIMIZE__ to a positive integer
421// when the compiler is optimizing.
422#ifndef __OPTIMIZE__
423#define ADA_DEVELOPMENT_CHECKS 1
424#endif // __OPTIMIZE__
425#endif // _MSC_VER
426#endif // ADA_DEVELOPMENT_CHECKS
427
428#define ADA_STR(x) #x
429
430#if ADA_DEVELOPMENT_CHECKS
431#define ADA_REQUIRE(EXPR) \
432 { \
433 if (!(EXPR) { abort(); }) }
434
435#define ADA_FAIL(MESSAGE) \
436 do { \
437 std::cerr << "FAIL: " << (MESSAGE) << std::endl; \
438 abort(); \
439 } while (0);
440#define ADA_ASSERT_EQUAL(LHS, RHS, MESSAGE) \
441 do { \
442 if (LHS != RHS) { \
443 std::cerr << "Mismatch: '" << LHS << "' - '" << RHS << "'" << std::endl; \
444 ADA_FAIL(MESSAGE); \
445 } \
446 } while (0);
447#define ADA_ASSERT_TRUE(COND) \
448 do { \
449 if (!(COND)) { \
450 std::cerr << "Assert at line " << __LINE__ << " of file " << __FILE__ \
451 << std::endl; \
452 ADA_FAIL(ADA_STR(COND)); \
453 } \
454 } while (0);
455#else
456#define ADA_FAIL(MESSAGE)
457#define ADA_ASSERT_EQUAL(LHS, RHS, MESSAGE)
458#define ADA_ASSERT_TRUE(COND)
459#endif
460
461#ifdef ADA_VISUAL_STUDIO
462#define ADA_ASSUME(COND) __assume(COND)
463#else
464#define ADA_ASSUME(COND) \
465 do { \
466 if (!(COND)) { \
467 __builtin_unreachable(); \
468 } \
469 } while (0)
470#endif
471
472#if defined(__SSE2__) || defined(__x86_64__) || defined(__x86_64) || \
473 (defined(_M_AMD64) || defined(_M_X64) || \
474 (defined(_M_IX86_FP) && _M_IX86_FP == 2))
475#define ADA_SSE2 1
476#endif
477
478#if defined(__aarch64__) || defined(_M_ARM64)
479#define ADA_NEON 1
480#endif
481
482#endif // ADA_COMMON_DEFS_H
483/* end file include/ada/common_defs.h */
484#include <cstdint>
485
493namespace ada::character_sets {
494ada_really_inline bool bit_at(const uint8_t a[], uint8_t i);
495} // namespace ada::character_sets
496
497#endif // ADA_CHARACTER_SETS_H
498/* end file include/ada/character_sets.h */
499
505namespace ada::character_sets {
506
507constexpr char hex[1024] =
508 "%00\0%01\0%02\0%03\0%04\0%05\0%06\0%07\0"
509 "%08\0%09\0%0A\0%0B\0%0C\0%0D\0%0E\0%0F\0"
510 "%10\0%11\0%12\0%13\0%14\0%15\0%16\0%17\0"
511 "%18\0%19\0%1A\0%1B\0%1C\0%1D\0%1E\0%1F\0"
512 "%20\0%21\0%22\0%23\0%24\0%25\0%26\0%27\0"
513 "%28\0%29\0%2A\0%2B\0%2C\0%2D\0%2E\0%2F\0"
514 "%30\0%31\0%32\0%33\0%34\0%35\0%36\0%37\0"
515 "%38\0%39\0%3A\0%3B\0%3C\0%3D\0%3E\0%3F\0"
516 "%40\0%41\0%42\0%43\0%44\0%45\0%46\0%47\0"
517 "%48\0%49\0%4A\0%4B\0%4C\0%4D\0%4E\0%4F\0"
518 "%50\0%51\0%52\0%53\0%54\0%55\0%56\0%57\0"
519 "%58\0%59\0%5A\0%5B\0%5C\0%5D\0%5E\0%5F\0"
520 "%60\0%61\0%62\0%63\0%64\0%65\0%66\0%67\0"
521 "%68\0%69\0%6A\0%6B\0%6C\0%6D\0%6E\0%6F\0"
522 "%70\0%71\0%72\0%73\0%74\0%75\0%76\0%77\0"
523 "%78\0%79\0%7A\0%7B\0%7C\0%7D\0%7E\0%7F\0"
524 "%80\0%81\0%82\0%83\0%84\0%85\0%86\0%87\0"
525 "%88\0%89\0%8A\0%8B\0%8C\0%8D\0%8E\0%8F\0"
526 "%90\0%91\0%92\0%93\0%94\0%95\0%96\0%97\0"
527 "%98\0%99\0%9A\0%9B\0%9C\0%9D\0%9E\0%9F\0"
528 "%A0\0%A1\0%A2\0%A3\0%A4\0%A5\0%A6\0%A7\0"
529 "%A8\0%A9\0%AA\0%AB\0%AC\0%AD\0%AE\0%AF\0"
530 "%B0\0%B1\0%B2\0%B3\0%B4\0%B5\0%B6\0%B7\0"
531 "%B8\0%B9\0%BA\0%BB\0%BC\0%BD\0%BE\0%BF\0"
532 "%C0\0%C1\0%C2\0%C3\0%C4\0%C5\0%C6\0%C7\0"
533 "%C8\0%C9\0%CA\0%CB\0%CC\0%CD\0%CE\0%CF\0"
534 "%D0\0%D1\0%D2\0%D3\0%D4\0%D5\0%D6\0%D7\0"
535 "%D8\0%D9\0%DA\0%DB\0%DC\0%DD\0%DE\0%DF\0"
536 "%E0\0%E1\0%E2\0%E3\0%E4\0%E5\0%E6\0%E7\0"
537 "%E8\0%E9\0%EA\0%EB\0%EC\0%ED\0%EE\0%EF\0"
538 "%F0\0%F1\0%F2\0%F3\0%F4\0%F5\0%F6\0%F7\0"
539 "%F8\0%F9\0%FA\0%FB\0%FC\0%FD\0%FE\0%FF";
540
541constexpr uint8_t C0_CONTROL_PERCENT_ENCODE[32] = {
542 // 00 01 02 03 04 05 06 07
543 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
544 // 08 09 0A 0B 0C 0D 0E 0F
545 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
546 // 10 11 12 13 14 15 16 17
547 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
548 // 18 19 1A 1B 1C 1D 1E 1F
549 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
550 // 20 21 22 23 24 25 26 27
551 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
552 // 28 29 2A 2B 2C 2D 2E 2F
553 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
554 // 30 31 32 33 34 35 36 37
555 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
556 // 38 39 3A 3B 3C 3D 3E 3F
557 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
558 // 40 41 42 43 44 45 46 47
559 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
560 // 48 49 4A 4B 4C 4D 4E 4F
561 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
562 // 50 51 52 53 54 55 56 57
563 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
564 // 58 59 5A 5B 5C 5D 5E 5F
565 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
566 // 60 61 62 63 64 65 66 67
567 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
568 // 68 69 6A 6B 6C 6D 6E 6F
569 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
570 // 70 71 72 73 74 75 76 77
571 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
572 // 78 79 7A 7B 7C 7D 7E 7F
573 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x80,
574 // 80 81 82 83 84 85 86 87
575 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
576 // 88 89 8A 8B 8C 8D 8E 8F
577 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
578 // 90 91 92 93 94 95 96 97
579 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
580 // 98 99 9A 9B 9C 9D 9E 9F
581 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
582 // A0 A1 A2 A3 A4 A5 A6 A7
583 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
584 // A8 A9 AA AB AC AD AE AF
585 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
586 // B0 B1 B2 B3 B4 B5 B6 B7
587 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
588 // B8 B9 BA BB BC BD BE BF
589 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
590 // C0 C1 C2 C3 C4 C5 C6 C7
591 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
592 // C8 C9 CA CB CC CD CE CF
593 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
594 // D0 D1 D2 D3 D4 D5 D6 D7
595 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
596 // D8 D9 DA DB DC DD DE DF
597 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
598 // E0 E1 E2 E3 E4 E5 E6 E7
599 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
600 // E8 E9 EA EB EC ED EE EF
601 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
602 // F0 F1 F2 F3 F4 F5 F6 F7
603 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
604 // F8 F9 FA FB FC FD FE FF
605 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80};
606
607constexpr uint8_t SPECIAL_QUERY_PERCENT_ENCODE[32] = {
608 // 00 01 02 03 04 05 06 07
609 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
610 // 08 09 0A 0B 0C 0D 0E 0F
611 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
612 // 10 11 12 13 14 15 16 17
613 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
614 // 18 19 1A 1B 1C 1D 1E 1F
615 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
616 // 20 21 22 23 24 25 26 27
617 0x01 | 0x00 | 0x04 | 0x08 | 0x00 | 0x00 | 0x00 | 0x80,
618 // 28 29 2A 2B 2C 2D 2E 2F
619 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
620 // 30 31 32 33 34 35 36 37
621 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
622 // 38 39 3A 3B 3C 3D 3E 3F
623 0x00 | 0x00 | 0x00 | 0x00 | 0x10 | 0x00 | 0x40 | 0x00,
624 // 40 41 42 43 44 45 46 47
625 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
626 // 48 49 4A 4B 4C 4D 4E 4F
627 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
628 // 50 51 52 53 54 55 56 57
629 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
630 // 58 59 5A 5B 5C 5D 5E 5F
631 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
632 // 60 61 62 63 64 65 66 67
633 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
634 // 68 69 6A 6B 6C 6D 6E 6F
635 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
636 // 70 71 72 73 74 75 76 77
637 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
638 // 78 79 7A 7B 7C 7D 7E 7F
639 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x80,
640 // 80 81 82 83 84 85 86 87
641 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
642 // 88 89 8A 8B 8C 8D 8E 8F
643 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
644 // 90 91 92 93 94 95 96 97
645 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
646 // 98 99 9A 9B 9C 9D 9E 9F
647 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
648 // A0 A1 A2 A3 A4 A5 A6 A7
649 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
650 // A8 A9 AA AB AC AD AE AF
651 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
652 // B0 B1 B2 B3 B4 B5 B6 B7
653 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
654 // B8 B9 BA BB BC BD BE BF
655 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
656 // C0 C1 C2 C3 C4 C5 C6 C7
657 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
658 // C8 C9 CA CB CC CD CE CF
659 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
660 // D0 D1 D2 D3 D4 D5 D6 D7
661 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
662 // D8 D9 DA DB DC DD DE DF
663 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
664 // E0 E1 E2 E3 E4 E5 E6 E7
665 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
666 // E8 E9 EA EB EC ED EE EF
667 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
668 // F0 F1 F2 F3 F4 F5 F6 F7
669 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
670 // F8 F9 FA FB FC FD FE FF
671 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80};
672
673constexpr uint8_t QUERY_PERCENT_ENCODE[32] = {
674 // 00 01 02 03 04 05 06 07
675 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
676 // 08 09 0A 0B 0C 0D 0E 0F
677 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
678 // 10 11 12 13 14 15 16 17
679 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
680 // 18 19 1A 1B 1C 1D 1E 1F
681 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
682 // 20 21 22 23 24 25 26 27
683 0x01 | 0x00 | 0x04 | 0x08 | 0x00 | 0x00 | 0x00 | 0x00,
684 // 28 29 2A 2B 2C 2D 2E 2F
685 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
686 // 30 31 32 33 34 35 36 37
687 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
688 // 38 39 3A 3B 3C 3D 3E 3F
689 0x00 | 0x00 | 0x00 | 0x00 | 0x10 | 0x00 | 0x40 | 0x00,
690 // 40 41 42 43 44 45 46 47
691 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
692 // 48 49 4A 4B 4C 4D 4E 4F
693 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
694 // 50 51 52 53 54 55 56 57
695 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
696 // 58 59 5A 5B 5C 5D 5E 5F
697 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
698 // 60 61 62 63 64 65 66 67
699 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
700 // 68 69 6A 6B 6C 6D 6E 6F
701 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
702 // 70 71 72 73 74 75 76 77
703 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
704 // 78 79 7A 7B 7C 7D 7E 7F
705 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x80,
706 // 80 81 82 83 84 85 86 87
707 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
708 // 88 89 8A 8B 8C 8D 8E 8F
709 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
710 // 90 91 92 93 94 95 96 97
711 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
712 // 98 99 9A 9B 9C 9D 9E 9F
713 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
714 // A0 A1 A2 A3 A4 A5 A6 A7
715 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
716 // A8 A9 AA AB AC AD AE AF
717 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
718 // B0 B1 B2 B3 B4 B5 B6 B7
719 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
720 // B8 B9 BA BB BC BD BE BF
721 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
722 // C0 C1 C2 C3 C4 C5 C6 C7
723 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
724 // C8 C9 CA CB CC CD CE CF
725 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
726 // D0 D1 D2 D3 D4 D5 D6 D7
727 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
728 // D8 D9 DA DB DC DD DE DF
729 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
730 // E0 E1 E2 E3 E4 E5 E6 E7
731 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
732 // E8 E9 EA EB EC ED EE EF
733 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
734 // F0 F1 F2 F3 F4 F5 F6 F7
735 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
736 // F8 F9 FA FB FC FD FE FF
737 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80};
738
739constexpr uint8_t FRAGMENT_PERCENT_ENCODE[32] = {
740 // 00 01 02 03 04 05 06 07
741 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
742 // 08 09 0A 0B 0C 0D 0E 0F
743 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
744 // 10 11 12 13 14 15 16 17
745 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
746 // 18 19 1A 1B 1C 1D 1E 1F
747 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
748 // 20 21 22 23 24 25 26 27
749 0x01 | 0x00 | 0x04 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
750 // 28 29 2A 2B 2C 2D 2E 2F
751 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
752 // 30 31 32 33 34 35 36 37
753 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
754 // 38 39 3A 3B 3C 3D 3E 3F
755 0x00 | 0x00 | 0x00 | 0x00 | 0x10 | 0x00 | 0x40 | 0x00,
756 // 40 41 42 43 44 45 46 47
757 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
758 // 48 49 4A 4B 4C 4D 4E 4F
759 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
760 // 50 51 52 53 54 55 56 57
761 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
762 // 58 59 5A 5B 5C 5D 5E 5F
763 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
764 // 60 61 62 63 64 65 66 67
765 0x01 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
766 // 68 69 6A 6B 6C 6D 6E 6F
767 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
768 // 70 71 72 73 74 75 76 77
769 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
770 // 78 79 7A 7B 7C 7D 7E 7F
771 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x80,
772 // 80 81 82 83 84 85 86 87
773 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
774 // 88 89 8A 8B 8C 8D 8E 8F
775 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
776 // 90 91 92 93 94 95 96 97
777 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
778 // 98 99 9A 9B 9C 9D 9E 9F
779 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
780 // A0 A1 A2 A3 A4 A5 A6 A7
781 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
782 // A8 A9 AA AB AC AD AE AF
783 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
784 // B0 B1 B2 B3 B4 B5 B6 B7
785 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
786 // B8 B9 BA BB BC BD BE BF
787 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
788 // C0 C1 C2 C3 C4 C5 C6 C7
789 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
790 // C8 C9 CA CB CC CD CE CF
791 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
792 // D0 D1 D2 D3 D4 D5 D6 D7
793 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
794 // D8 D9 DA DB DC DD DE DF
795 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
796 // E0 E1 E2 E3 E4 E5 E6 E7
797 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
798 // E8 E9 EA EB EC ED EE EF
799 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
800 // F0 F1 F2 F3 F4 F5 F6 F7
801 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
802 // F8 F9 FA FB FC FD FE FF
803 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80};
804
805constexpr uint8_t USERINFO_PERCENT_ENCODE[32] = {
806 // 00 01 02 03 04 05 06 07
807 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
808 // 08 09 0A 0B 0C 0D 0E 0F
809 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
810 // 10 11 12 13 14 15 16 17
811 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
812 // 18 19 1A 1B 1C 1D 1E 1F
813 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
814 // 20 21 22 23 24 25 26 27
815 0x01 | 0x00 | 0x04 | 0x08 | 0x00 | 0x00 | 0x00 | 0x00,
816 // 28 29 2A 2B 2C 2D 2E 2F
817 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x80,
818 // 30 31 32 33 34 35 36 37
819 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
820 // 38 39 3A 3B 3C 3D 3E 3F
821 0x00 | 0x00 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
822 // 40 41 42 43 44 45 46 47
823 0x01 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
824 // 48 49 4A 4B 4C 4D 4E 4F
825 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
826 // 50 51 52 53 54 55 56 57
827 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
828 // 58 59 5A 5B 5C 5D 5E 5F
829 0x00 | 0x00 | 0x00 | 0x08 | 0x10 | 0x20 | 0x40 | 0x00,
830 // 60 61 62 63 64 65 66 67
831 0x01 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
832 // 68 69 6A 6B 6C 6D 6E 6F
833 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
834 // 70 71 72 73 74 75 76 77
835 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
836 // 78 79 7A 7B 7C 7D 7E 7F
837 0x00 | 0x00 | 0x00 | 0x08 | 0x10 | 0x20 | 0x00 | 0x80,
838 // 80 81 82 83 84 85 86 87
839 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
840 // 88 89 8A 8B 8C 8D 8E 8F
841 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
842 // 90 91 92 93 94 95 96 97
843 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
844 // 98 99 9A 9B 9C 9D 9E 9F
845 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
846 // A0 A1 A2 A3 A4 A5 A6 A7
847 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
848 // A8 A9 AA AB AC AD AE AF
849 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
850 // B0 B1 B2 B3 B4 B5 B6 B7
851 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
852 // B8 B9 BA BB BC BD BE BF
853 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
854 // C0 C1 C2 C3 C4 C5 C6 C7
855 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
856 // C8 C9 CA CB CC CD CE CF
857 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
858 // D0 D1 D2 D3 D4 D5 D6 D7
859 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
860 // D8 D9 DA DB DC DD DE DF
861 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
862 // E0 E1 E2 E3 E4 E5 E6 E7
863 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
864 // E8 E9 EA EB EC ED EE EF
865 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
866 // F0 F1 F2 F3 F4 F5 F6 F7
867 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
868 // F8 F9 FA FB FC FD FE FF
869 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80};
870
871constexpr uint8_t PATH_PERCENT_ENCODE[32] = {
872 // 00 01 02 03 04 05 06 07
873 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
874 // 08 09 0A 0B 0C 0D 0E 0F
875 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
876 // 10 11 12 13 14 15 16 17
877 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
878 // 18 19 1A 1B 1C 1D 1E 1F
879 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
880 // 20 21 22 23 24 25 26 27
881 0x01 | 0x00 | 0x04 | 0x08 | 0x00 | 0x00 | 0x00 | 0x00,
882 // 28 29 2A 2B 2C 2D 2E 2F
883 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
884 // 30 31 32 33 34 35 36 37
885 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
886 // 38 39 3A 3B 3C 3D 3E 3F
887 0x00 | 0x00 | 0x00 | 0x00 | 0x10 | 0x00 | 0x40 | 0x80,
888 // 40 41 42 43 44 45 46 47
889 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
890 // 48 49 4A 4B 4C 4D 4E 4F
891 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
892 // 50 51 52 53 54 55 56 57
893 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
894 // 58 59 5A 5B 5C 5D 5E 5F
895 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
896 // 60 61 62 63 64 65 66 67
897 0x01 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
898 // 68 69 6A 6B 6C 6D 6E 6F
899 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
900 // 70 71 72 73 74 75 76 77
901 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
902 // 78 79 7A 7B 7C 7D 7E 7F
903 0x00 | 0x00 | 0x00 | 0x08 | 0x00 | 0x20 | 0x00 | 0x80,
904 // 80 81 82 83 84 85 86 87
905 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
906 // 88 89 8A 8B 8C 8D 8E 8F
907 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
908 // 90 91 92 93 94 95 96 97
909 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
910 // 98 99 9A 9B 9C 9D 9E 9F
911 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
912 // A0 A1 A2 A3 A4 A5 A6 A7
913 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
914 // A8 A9 AA AB AC AD AE AF
915 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
916 // B0 B1 B2 B3 B4 B5 B6 B7
917 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
918 // B8 B9 BA BB BC BD BE BF
919 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
920 // C0 C1 C2 C3 C4 C5 C6 C7
921 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
922 // C8 C9 CA CB CC CD CE CF
923 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
924 // D0 D1 D2 D3 D4 D5 D6 D7
925 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
926 // D8 D9 DA DB DC DD DE DF
927 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
928 // E0 E1 E2 E3 E4 E5 E6 E7
929 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
930 // E8 E9 EA EB EC ED EE EF
931 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
932 // F0 F1 F2 F3 F4 F5 F6 F7
933 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
934 // F8 F9 FA FB FC FD FE FF
935 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80};
936
937constexpr uint8_t WWW_FORM_URLENCODED_PERCENT_ENCODE[32] = {
938 // 00 01 02 03 04 05 06 07
939 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
940 // 08 09 0A 0B 0C 0D 0E 0F
941 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
942 // 10 11 12 13 14 15 16 17
943 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
944 // 18 19 1A 1B 1C 1D 1E 1F
945 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
946 // 20 21 22 23 24 25 26 27
947 0x00 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
948 // 28 29 2A 2B 2C 2D 2E 2F
949 0x01 | 0x02 | 0x00 | 0x08 | 0x10 | 0x00 | 0x00 | 0x80,
950 // 30 31 32 33 34 35 36 37
951 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
952 // 38 39 3A 3B 3C 3D 3E 3F
953 0x00 | 0x00 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
954 // 40 41 42 43 44 45 46 47
955 0x01 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
956 // 48 49 4A 4B 4C 4D 4E 4F
957 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
958 // 50 51 52 53 54 55 56 57
959 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
960 // 58 59 5A 5B 5C 5D 5E 5F
961 0x00 | 0x00 | 0x00 | 0x08 | 0x00 | 0x20 | 0x40 | 0x00,
962 // 60 61 62 63 64 65 66 67
963 0x01 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
964 // 68 69 6A 6B 6C 6D 6E 6F
965 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
966 // 70 71 72 73 74 75 76 77
967 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
968 // 78 79 7A 7B 7C 7D 7E 7F
969 0x00 | 0x00 | 0x00 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
970 // 80 81 82 83 84 85 86 87
971 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
972 // 88 89 8A 8B 8C 8D 8E 8F
973 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
974 // 90 91 92 93 94 95 96 97
975 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
976 // 98 99 9A 9B 9C 9D 9E 9F
977 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
978 // A0 A1 A2 A3 A4 A5 A6 A7
979 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
980 // A8 A9 AA AB AC AD AE AF
981 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
982 // B0 B1 B2 B3 B4 B5 B6 B7
983 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
984 // B8 B9 BA BB BC BD BE BF
985 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
986 // C0 C1 C2 C3 C4 C5 C6 C7
987 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
988 // C8 C9 CA CB CC CD CE CF
989 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
990 // D0 D1 D2 D3 D4 D5 D6 D7
991 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
992 // D8 D9 DA DB DC DD DE DF
993 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
994 // E0 E1 E2 E3 E4 E5 E6 E7
995 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
996 // E8 E9 EA EB EC ED EE EF
997 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
998 // F0 F1 F2 F3 F4 F5 F6 F7
999 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
1000 // F8 F9 FA FB FC FD FE FF
1001 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80};
1002
1003ada_really_inline bool bit_at(const uint8_t a[], const uint8_t i) {
1004 return !!(a[i >> 3] & (1 << (i & 7)));
1005}
1006
1007} // namespace ada::character_sets
1008
1009#endif // ADA_CHARACTER_SETS_INL_H
1010/* end file include/ada/character_sets-inl.h */
1011/* begin file include/ada/checkers-inl.h */
1016#ifndef ADA_CHECKERS_INL_H
1017#define ADA_CHECKERS_INL_H
1018
1019
1020#include <algorithm>
1021#include <string_view>
1022#include <cstring>
1023
1024namespace ada::checkers {
1025
1026inline bool has_hex_prefix_unsafe(std::string_view input) {
1027 // This is actually efficient code, see has_hex_prefix for the assembly.
1028 uint32_t value_one = 1;
1029 bool is_little_endian = (reinterpret_cast<char*>(&value_one)[0] == 1);
1030 uint16_t word0x{};
1031 std::memcpy(&word0x, "0x", 2); // we would use bit_cast in C++20 and the
1032 // function could be constexpr.
1033 uint16_t two_first_bytes{};
1034 std::memcpy(&two_first_bytes, input.data(), 2);
1035 if (is_little_endian) {
1036 two_first_bytes |= 0x2000;
1037 } else {
1038 two_first_bytes |= 0x020;
1039 }
1040 return two_first_bytes == word0x;
1041}
1042
1043inline bool has_hex_prefix(std::string_view input) {
1044 return input.size() >= 2 && has_hex_prefix_unsafe(input);
1045}
1046
1047constexpr bool is_digit(char x) noexcept { return (x >= '0') & (x <= '9'); }
1048
1049constexpr char to_lower(char x) noexcept { return (x | 0x20); }
1050
1051constexpr bool is_alpha(char x) noexcept {
1052 return (to_lower(x) >= 'a') && (to_lower(x) <= 'z');
1053}
1054
1055inline constexpr bool is_windows_drive_letter(std::string_view input) noexcept {
1056 return input.size() >= 2 &&
1057 (is_alpha(input[0]) && ((input[1] == ':') || (input[1] == '|'))) &&
1058 ((input.size() == 2) || (input[2] == '/' || input[2] == '\\' ||
1059 input[2] == '?' || input[2] == '#'));
1060}
1061
1062inline constexpr bool is_normalized_windows_drive_letter(
1063 std::string_view input) noexcept {
1064 return input.size() >= 2 && (is_alpha(input[0]) && (input[1] == ':'));
1065}
1066
1067ada_really_inline bool begins_with(std::string_view view,
1068 std::string_view prefix) {
1069 // in C++20, you have view.begins_with(prefix)
1070 // std::equal is constexpr in C++20
1071 return view.size() >= prefix.size() &&
1072 std::equal(prefix.begin(), prefix.end(), view.begin());
1073}
1074
1075} // namespace ada::checkers
1076
1077#endif // ADA_CHECKERS_INL_H
1078/* end file include/ada/checkers-inl.h */
1079/* begin file include/ada/log.h */
1085#ifndef ADA_LOG_H
1086#define ADA_LOG_H
1087
1088#include <iostream>
1089// To enable logging, set ADA_LOGGING to 1:
1090#ifndef ADA_LOGGING
1091#define ADA_LOGGING 0
1092#endif
1093
1094namespace ada {
1095
1100template <typename T>
1101ada_really_inline void inner_log([[maybe_unused]] T t) {
1102#if ADA_LOGGING
1103 std::cout << t << std::endl;
1104#endif
1105}
1106
1111template <typename T, typename... Args>
1112ada_really_inline void inner_log([[maybe_unused]] T t,
1113 [[maybe_unused]] Args... args) {
1114#if ADA_LOGGING
1115 std::cout << t;
1116 inner_log(args...);
1117#endif
1118}
1119
1124template <typename T, typename... Args>
1125ada_really_inline void log([[maybe_unused]] T t,
1126 [[maybe_unused]] Args... args) {
1127#if ADA_LOGGING
1128 std::cout << "ADA_LOG: " << t;
1129 inner_log(args...);
1130#endif
1131}
1132
1137template <typename T>
1138ada_really_inline void log([[maybe_unused]] T t) {
1139#if ADA_LOGGING
1140 std::cout << "ADA_LOG: " << t << std::endl;
1141#endif
1142}
1143} // namespace ada
1144
1145#if ADA_LOGGING
1146
1147#ifndef ada_log
1148#define ada_log(...) \
1149 do { \
1150 ada::log(__VA_ARGS__); \
1151 } while (0)
1152#endif // ada_log
1153#else
1154#define ada_log(...)
1155#endif // ADA_LOGGING
1156
1157#endif // ADA_LOG_H
1158/* end file include/ada/log.h */
1159/* begin file include/ada/encoding_type.h */
1164#ifndef ADA_ENCODING_TYPE_H
1165#define ADA_ENCODING_TYPE_H
1166
1167#include <string>
1168
1169namespace ada {
1170
1177enum class encoding_type {
1178 UTF8,
1179 UTF_16LE,
1180 UTF_16BE,
1181};
1182
1186ada_warn_unused std::string to_string(encoding_type type);
1187
1188} // namespace ada
1189
1190#endif // ADA_ENCODING_TYPE_H
1191/* end file include/ada/encoding_type.h */
1192/* begin file include/ada/helpers.h */
1197#ifndef ADA_HELPERS_H
1198#define ADA_HELPERS_H
1199
1200/* begin file include/ada/state.h */
1205#ifndef ADA_STATE_H
1206#define ADA_STATE_H
1207
1208
1209#include <string>
1210
1211namespace ada {
1212
1216enum class state {
1220 AUTHORITY,
1221
1226
1230 SCHEME,
1231
1235 HOST,
1236
1240 NO_SCHEME,
1241
1245 FRAGMENT,
1246
1251
1256
1260 FILE,
1261
1265 FILE_HOST,
1266
1270 FILE_SLASH,
1271
1276
1281
1286
1291
1295 QUERY,
1296
1300 PATH,
1301
1305 PATH_START,
1306
1311
1315 PORT,
1316};
1317
1321ada_warn_unused std::string to_string(ada::state s);
1322
1323} // namespace ada
1324
1325#endif // ADA_STATE_H
1326/* end file include/ada/state.h */
1327/* begin file include/ada/url_base.h */
1332#ifndef ADA_URL_BASE_H
1333#define ADA_URL_BASE_H
1334
1335/* begin file include/ada/url_components.h */
1340#ifndef ADA_URL_COMPONENTS_H
1341#define ADA_URL_COMPONENTS_H
1342
1343
1344#include <optional>
1345#include <string_view>
1346
1347namespace ada {
1348
1358 constexpr static uint32_t omitted = uint32_t(-1);
1359
1360 url_components() = default;
1361 url_components(const url_components &u) = default;
1362 url_components(url_components &&u) noexcept = default;
1363 url_components &operator=(url_components &&u) noexcept = default;
1365 ~url_components() = default;
1366
1367 /*
1368 * By using 32-bit integers, we implicitly assume that the URL string
1369 * cannot exceed 4 GB.
1370 *
1371 * https://user:pass@example.com:1234/foo/bar?baz#quux
1372 * | | | | ^^^^| | |
1373 * | | | | | | | `----- hash_start
1374 * | | | | | | `--------- search_start
1375 * | | | | | `----------------- pathname_start
1376 * | | | | `--------------------- port
1377 * | | | `----------------------- host_end
1378 * | | `---------------------------------- host_start
1379 * | `--------------------------------------- username_end
1380 * `--------------------------------------------- protocol_end
1381 */
1382 uint32_t protocol_end{0};
1387 uint32_t username_end{0};
1388 uint32_t host_start{0};
1389 uint32_t host_end{0};
1390 uint32_t port{omitted};
1391 uint32_t pathname_start{0};
1392 uint32_t search_start{omitted};
1393 uint32_t hash_start{omitted};
1394
1404 [[nodiscard]] bool check_offset_consistency() const noexcept;
1405
1409 [[nodiscard]] std::string to_string() const;
1410
1411}; // struct url_components
1412
1413} // namespace ada
1414#endif
1415/* end file include/ada/url_components.h */
1416/* begin file include/ada/scheme.h */
1421#ifndef ADA_SCHEME_H
1422#define ADA_SCHEME_H
1423
1424
1425#include <array>
1426#include <optional>
1427#include <string>
1428
1433namespace ada::scheme {
1434
1445enum type : uint8_t {
1446 HTTP = 0,
1447 NOT_SPECIAL = 1,
1448 HTTPS = 2,
1449 WS = 3,
1450 FTP = 4,
1451 WSS = 5,
1452 FILE = 6
1453};
1454
1465ada_really_inline constexpr bool is_special(std::string_view scheme);
1466
1477constexpr uint16_t get_special_port(std::string_view scheme) noexcept;
1478
1483constexpr uint16_t get_special_port(ada::scheme::type type) noexcept;
1488constexpr ada::scheme::type get_scheme_type(std::string_view scheme) noexcept;
1489
1490} // namespace ada::scheme
1491
1492#endif // ADA_SCHEME_H
1493/* end file include/ada/scheme.h */
1494
1495#include <string_view>
1496
1497namespace ada {
1498
1502enum url_host_type : uint8_t {
1506 DEFAULT = 0,
1510 IPV4 = 1,
1515 IPV6 = 2,
1516};
1517
1527struct url_base {
1528 virtual ~url_base() = default;
1529
1533 bool is_valid{true};
1534
1538 bool has_opaque_path{false};
1539
1543 url_host_type host_type = url_host_type::DEFAULT;
1544
1548 ada::scheme::type type{ada::scheme::type::NOT_SPECIAL};
1549
1554 [[nodiscard]] ada_really_inline bool is_special() const noexcept;
1555
1562 [[nodiscard]] virtual std::string get_origin() const noexcept = 0;
1563
1569 [[nodiscard]] virtual bool has_valid_domain() const noexcept = 0;
1570
1577 [[nodiscard]] inline uint16_t get_special_port() const noexcept;
1578
1584 [[nodiscard]] ada_really_inline uint16_t scheme_default_port() const noexcept;
1585
1597 virtual size_t parse_port(std::string_view view,
1598 bool check_trailing_content) noexcept = 0;
1599
1600 virtual ada_really_inline size_t parse_port(std::string_view view) noexcept {
1601 return this->parse_port(view, false);
1602 }
1603
1607 [[nodiscard]] virtual std::string to_string() const = 0;
1608
1610 virtual inline void clear_pathname() = 0;
1611
1613 virtual inline void clear_search() = 0;
1614
1616 [[nodiscard]] virtual inline bool has_hash() const noexcept = 0;
1617
1619 [[nodiscard]] virtual inline bool has_search() const noexcept = 0;
1620
1621}; // url_base
1622
1623} // namespace ada
1624
1625#endif
1626/* end file include/ada/url_base.h */
1627
1628#include <string_view>
1629#include <optional>
1630
1639namespace ada::helpers {
1640
1644template <typename out_iter>
1645void encode_json(std::string_view view, out_iter out);
1646
1660ada_really_inline std::optional<std::string_view> prune_hash(
1661 std::string_view& input) noexcept;
1662
1669ada_really_inline bool shorten_path(std::string& path,
1670 ada::scheme::type type) noexcept;
1671
1678ada_really_inline bool shorten_path(std::string_view& path,
1679 ada::scheme::type type) noexcept;
1680
1692ada_really_inline void parse_prepared_path(std::string_view input,
1693 ada::scheme::type type,
1694 std::string& path);
1695
1700ada_really_inline void remove_ascii_tab_or_newline(std::string& input) noexcept;
1701
1707ada_really_inline std::string_view substring(std::string_view input,
1708 size_t pos) noexcept;
1709
1714bool overlaps(std::string_view input1, const std::string& input2) noexcept;
1715
1721ada_really_inline std::string_view substring(const std::string& input,
1722 size_t pos1,
1723 size_t pos2) noexcept {
1724#if ADA_DEVELOPMENT_CHECKS
1725 if (pos2 < pos1) {
1726 std::cerr << "Negative-length substring: [" << pos1 << " to " << pos2 << ")"
1727 << std::endl;
1728 abort();
1729 }
1730#endif
1731 return std::string_view(input.data() + pos1, pos2 - pos1);
1732}
1733
1739ada_really_inline void resize(std::string_view& input, size_t pos) noexcept;
1740
1746ada_really_inline std::pair<size_t, bool> get_host_delimiter_location(
1747 const bool is_special, std::string_view& view) noexcept;
1748
1754ada_really_inline void trim_c0_whitespace(std::string_view& input) noexcept;
1755
1761template <class url_type>
1762ada_really_inline void strip_trailing_spaces_from_opaque_path(
1763 url_type& url) noexcept;
1764
1769ada_really_inline size_t
1770find_authority_delimiter_special(std::string_view view) noexcept;
1771
1776ada_really_inline size_t
1777find_authority_delimiter(std::string_view view) noexcept;
1778
1782template <typename T, typename... Args>
1783inline void inner_concat(std::string& buffer, T t) {
1784 buffer.append(t);
1785}
1786
1790template <typename T, typename... Args>
1791inline void inner_concat(std::string& buffer, T t, Args... args) {
1792 buffer.append(t);
1793 return inner_concat(buffer, args...);
1794}
1795
1801template <typename... Args>
1802std::string concat(Args... args) {
1803 std::string answer;
1804 inner_concat(answer, args...);
1805 return answer;
1806}
1807
1812inline int leading_zeroes(uint32_t input_num) noexcept {
1813#if ADA_REGULAR_VISUAL_STUDIO
1814 unsigned long leading_zero(0);
1815 unsigned long in(input_num);
1816 return _BitScanReverse(&leading_zero, in) ? int(31 - leading_zero) : 32;
1817#else
1818 return __builtin_clz(input_num);
1819#endif // ADA_REGULAR_VISUAL_STUDIO
1820}
1821
1828inline int fast_digit_count(uint32_t x) noexcept {
1829 auto int_log2 = [](uint32_t z) -> int {
1830 return 31 - ada::helpers::leading_zeroes(z | 1);
1831 };
1832 // Compiles to very few instructions. Note that the
1833 // table is static and thus effectively a constant.
1834 // We leave it inside the function because it is meaningless
1835 // outside of it (this comes at no performance cost).
1836 const static uint64_t table[] = {
1837 4294967296, 8589934582, 8589934582, 8589934582, 12884901788,
1838 12884901788, 12884901788, 17179868184, 17179868184, 17179868184,
1839 21474826480, 21474826480, 21474826480, 21474826480, 25769703776,
1840 25769703776, 25769703776, 30063771072, 30063771072, 30063771072,
1841 34349738368, 34349738368, 34349738368, 34349738368, 38554705664,
1842 38554705664, 38554705664, 41949672960, 41949672960, 41949672960,
1843 42949672960, 42949672960};
1844 return int((x + table[int_log2(x)]) >> 32);
1845}
1846} // namespace ada::helpers
1847
1848#endif // ADA_HELPERS_H
1849/* end file include/ada/helpers.h */
1850/* begin file include/ada/parser.h */
1855#ifndef ADA_PARSER_H
1856#define ADA_PARSER_H
1857
1858#include <optional>
1859#include <string_view>
1860
1861/* begin file include/ada/expected.h */
1868// expected - An implementation of std::expected with extensions
1869// Written in 2017 by Sy Brand (tartanllama@gmail.com, @TartanLlama)
1870//
1871// Documentation available at http://tl.tartanllama.xyz/
1872//
1873// To the extent possible under law, the author(s) have dedicated all
1874// copyright and related and neighboring rights to this software to the
1875// public domain worldwide. This software is distributed without any warranty.
1876//
1877// You should have received a copy of the CC0 Public Domain Dedication
1878// along with this software. If not, see
1879// <http://creativecommons.org/publicdomain/zero/1.0/>.
1881
1882#ifndef TL_EXPECTED_HPP
1883#define TL_EXPECTED_HPP
1884
1885#define TL_EXPECTED_VERSION_MAJOR 1
1886#define TL_EXPECTED_VERSION_MINOR 1
1887#define TL_EXPECTED_VERSION_PATCH 0
1888
1889#include <exception>
1890#include <functional>
1891#include <type_traits>
1892#include <utility>
1893
1894#if defined(__EXCEPTIONS) || defined(_CPPUNWIND)
1895#define TL_EXPECTED_EXCEPTIONS_ENABLED
1896#endif
1897
1898#if (defined(_MSC_VER) && _MSC_VER == 1900)
1899#define TL_EXPECTED_MSVC2015
1900#define TL_EXPECTED_MSVC2015_CONSTEXPR
1901#else
1902#define TL_EXPECTED_MSVC2015_CONSTEXPR constexpr
1903#endif
1904
1905#if (defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ <= 9 && \
1906 !defined(__clang__))
1907#define TL_EXPECTED_GCC49
1908#endif
1909
1910#if (defined(__GNUC__) && __GNUC__ == 5 && __GNUC_MINOR__ <= 4 && \
1911 !defined(__clang__))
1912#define TL_EXPECTED_GCC54
1913#endif
1914
1915#if (defined(__GNUC__) && __GNUC__ == 5 && __GNUC_MINOR__ <= 5 && \
1916 !defined(__clang__))
1917#define TL_EXPECTED_GCC55
1918#endif
1919
1920#if !defined(TL_ASSERT)
1921// can't have assert in constexpr in C++11 and GCC 4.9 has a compiler bug
1922#if (__cplusplus > 201103L) && !defined(TL_EXPECTED_GCC49)
1923#include <cassert>
1924#define TL_ASSERT(x) assert(x)
1925#else
1926#define TL_ASSERT(x)
1927#endif
1928#endif
1929
1930#if (defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ <= 9 && \
1931 !defined(__clang__))
1932// GCC < 5 doesn't support overloading on const&& for member functions
1933
1934#define TL_EXPECTED_NO_CONSTRR
1935// GCC < 5 doesn't support some standard C++11 type traits
1936#define TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) \
1937 std::has_trivial_copy_constructor<T>
1938#define TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(T) \
1939 std::has_trivial_copy_assign<T>
1940
1941// This one will be different for GCC 5.7 if it's ever supported
1942#define TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(T) \
1943 std::is_trivially_destructible<T>
1944
1945// GCC 5 < v < 8 has a bug in is_trivially_copy_constructible which breaks
1946// std::vector for non-copyable types
1947#elif (defined(__GNUC__) && __GNUC__ < 8 && !defined(__clang__))
1948#ifndef TL_GCC_LESS_8_TRIVIALLY_COPY_CONSTRUCTIBLE_MUTEX
1949#define TL_GCC_LESS_8_TRIVIALLY_COPY_CONSTRUCTIBLE_MUTEX
1950namespace tl {
1951namespace detail {
1952template <class T>
1953struct is_trivially_copy_constructible
1954 : std::is_trivially_copy_constructible<T> {};
1955#ifdef _GLIBCXX_VECTOR
1956template <class T, class A>
1957struct is_trivially_copy_constructible<std::vector<T, A>> : std::false_type {};
1958#endif
1959} // namespace detail
1960} // namespace tl
1961#endif
1962
1963#define TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) \
1964 tl::detail::is_trivially_copy_constructible<T>
1965#define TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(T) \
1966 std::is_trivially_copy_assignable<T>
1967#define TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(T) \
1968 std::is_trivially_destructible<T>
1969#else
1970#define TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) \
1971 std::is_trivially_copy_constructible<T>
1972#define TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(T) \
1973 std::is_trivially_copy_assignable<T>
1974#define TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(T) \
1975 std::is_trivially_destructible<T>
1976#endif
1977
1978#if __cplusplus > 201103L
1979#define TL_EXPECTED_CXX14
1980#endif
1981
1982#ifdef TL_EXPECTED_GCC49
1983#define TL_EXPECTED_GCC49_CONSTEXPR
1984#else
1985#define TL_EXPECTED_GCC49_CONSTEXPR constexpr
1986#endif
1987
1988#if (__cplusplus == 201103L || defined(TL_EXPECTED_MSVC2015) || \
1989 defined(TL_EXPECTED_GCC49))
1990#define TL_EXPECTED_11_CONSTEXPR
1991#else
1992#define TL_EXPECTED_11_CONSTEXPR constexpr
1993#endif
1994
1995namespace tl {
1996template <class T, class E>
1997class expected;
1998
1999#ifndef TL_MONOSTATE_INPLACE_MUTEX
2000#define TL_MONOSTATE_INPLACE_MUTEX
2001class monostate {};
2002
2004 explicit in_place_t() = default;
2005};
2006static constexpr in_place_t in_place{};
2007#endif
2008
2009template <class E>
2011 public:
2012 static_assert(!std::is_same<E, void>::value, "E must not be void");
2013
2014 unexpected() = delete;
2015 constexpr explicit unexpected(const E &e) : m_val(e) {}
2016
2017 constexpr explicit unexpected(E &&e) : m_val(std::move(e)) {}
2018
2019 template <class... Args, typename std::enable_if<std::is_constructible<
2020 E, Args &&...>::value>::type * = nullptr>
2021 constexpr explicit unexpected(Args &&...args)
2022 : m_val(std::forward<Args>(args)...) {}
2023 template <
2024 class U, class... Args,
2025 typename std::enable_if<std::is_constructible<
2026 E, std::initializer_list<U> &, Args &&...>::value>::type * = nullptr>
2027 constexpr explicit unexpected(std::initializer_list<U> l, Args &&...args)
2028 : m_val(l, std::forward<Args>(args)...) {}
2029
2030 constexpr const E &value() const & { return m_val; }
2031 TL_EXPECTED_11_CONSTEXPR E &value() & { return m_val; }
2032 TL_EXPECTED_11_CONSTEXPR E &&value() && { return std::move(m_val); }
2033 constexpr const E &&value() const && { return std::move(m_val); }
2034
2035 private:
2036 E m_val;
2037};
2038
2039#ifdef __cpp_deduction_guides
2040template <class E>
2041unexpected(E) -> unexpected<E>;
2042#endif
2043
2044template <class E>
2045constexpr bool operator==(const unexpected<E> &lhs, const unexpected<E> &rhs) {
2046 return lhs.value() == rhs.value();
2047}
2048template <class E>
2049constexpr bool operator!=(const unexpected<E> &lhs, const unexpected<E> &rhs) {
2050 return lhs.value() != rhs.value();
2051}
2052template <class E>
2053constexpr bool operator<(const unexpected<E> &lhs, const unexpected<E> &rhs) {
2054 return lhs.value() < rhs.value();
2055}
2056template <class E>
2057constexpr bool operator<=(const unexpected<E> &lhs, const unexpected<E> &rhs) {
2058 return lhs.value() <= rhs.value();
2059}
2060template <class E>
2061constexpr bool operator>(const unexpected<E> &lhs, const unexpected<E> &rhs) {
2062 return lhs.value() > rhs.value();
2063}
2064template <class E>
2065constexpr bool operator>=(const unexpected<E> &lhs, const unexpected<E> &rhs) {
2066 return lhs.value() >= rhs.value();
2067}
2068
2069template <class E>
2073
2075 unexpect_t() = default;
2076};
2077static constexpr unexpect_t unexpect{};
2078
2079namespace detail {
2080template <typename E>
2082#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
2083 throw std::forward<E>(e);
2084#else
2085 (void)e;
2086#ifdef _MSC_VER
2087 __assume(0);
2088#else
2089 __builtin_unreachable();
2090#endif
2091#endif
2092}
2093
2094#ifndef TL_TRAITS_MUTEX
2095#define TL_TRAITS_MUTEX
2096// C++14-style aliases for brevity
2097template <class T>
2098using remove_const_t = typename std::remove_const<T>::type;
2099template <class T>
2100using remove_reference_t = typename std::remove_reference<T>::type;
2101template <class T>
2102using decay_t = typename std::decay<T>::type;
2103template <bool E, class T = void>
2104using enable_if_t = typename std::enable_if<E, T>::type;
2105template <bool B, class T, class F>
2106using conditional_t = typename std::conditional<B, T, F>::type;
2107
2108// std::conjunction from C++17
2109template <class...>
2110struct conjunction : std::true_type {};
2111template <class B>
2112struct conjunction<B> : B {};
2113template <class B, class... Bs>
2114struct conjunction<B, Bs...>
2115 : std::conditional<bool(B::value), conjunction<Bs...>, B>::type {};
2116
2117#if defined(_LIBCPP_VERSION) && __cplusplus == 201103L
2118#define TL_TRAITS_LIBCXX_MEM_FN_WORKAROUND
2119#endif
2120
2121// In C++11 mode, there's an issue in libc++'s std::mem_fn
2122// which results in a hard-error when using it in a noexcept expression
2123// in some cases. This is a check to workaround the common failing case.
2124#ifdef TL_TRAITS_LIBCXX_MEM_FN_WORKAROUND
2125template <class T>
2126struct is_pointer_to_non_const_member_func : std::false_type {};
2127template <class T, class Ret, class... Args>
2128struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...)>
2129 : std::true_type {};
2130template <class T, class Ret, class... Args>
2131struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...) &>
2132 : std::true_type {};
2133template <class T, class Ret, class... Args>
2134struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...) &&>
2135 : std::true_type {};
2136template <class T, class Ret, class... Args>
2137struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...) volatile>
2138 : std::true_type {};
2139template <class T, class Ret, class... Args>
2140struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...) volatile &>
2141 : std::true_type {};
2142template <class T, class Ret, class... Args>
2143struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...) volatile &&>
2144 : std::true_type {};
2145
2146template <class T>
2147struct is_const_or_const_ref : std::false_type {};
2148template <class T>
2149struct is_const_or_const_ref<T const &> : std::true_type {};
2150template <class T>
2151struct is_const_or_const_ref<T const> : std::true_type {};
2152#endif
2153
2154// std::invoke from C++17
2155// https://stackoverflow.com/questions/38288042/c11-14-invoke-workaround
2156template <
2157 typename Fn, typename... Args,
2158#ifdef TL_TRAITS_LIBCXX_MEM_FN_WORKAROUND
2159 typename = enable_if_t<!(is_pointer_to_non_const_member_func<Fn>::value &&
2160 is_const_or_const_ref<Args...>::value)>,
2161#endif
2162 typename = enable_if_t<std::is_member_pointer<decay_t<Fn>>::value>, int = 0>
2163constexpr auto invoke(Fn &&f, Args &&...args) noexcept(
2164 noexcept(std::mem_fn(f)(std::forward<Args>(args)...)))
2165 -> decltype(std::mem_fn(f)(std::forward<Args>(args)...)) {
2166 return std::mem_fn(f)(std::forward<Args>(args)...);
2167}
2168
2169template <typename Fn, typename... Args,
2170 typename = enable_if_t<!std::is_member_pointer<decay_t<Fn>>::value>>
2171constexpr auto invoke(Fn &&f, Args &&...args) noexcept(
2172 noexcept(std::forward<Fn>(f)(std::forward<Args>(args)...)))
2173 -> decltype(std::forward<Fn>(f)(std::forward<Args>(args)...)) {
2174 return std::forward<Fn>(f)(std::forward<Args>(args)...);
2175}
2176
2177// std::invoke_result from C++17
2178template <class F, class, class... Us>
2180
2181template <class F, class... Us>
2183 F,
2184 decltype(detail::invoke(std::declval<F>(), std::declval<Us>()...), void()),
2185 Us...> {
2186 using type =
2187 decltype(detail::invoke(std::declval<F>(), std::declval<Us>()...));
2188};
2189
2190template <class F, class... Us>
2191using invoke_result = invoke_result_impl<F, void, Us...>;
2192
2193template <class F, class... Us>
2194using invoke_result_t = typename invoke_result<F, Us...>::type;
2195
2196#if defined(_MSC_VER) && _MSC_VER <= 1900
2197// TODO make a version which works with MSVC 2015
2198template <class T, class U = T>
2199struct is_swappable : std::true_type {};
2200
2201template <class T, class U = T>
2202struct is_nothrow_swappable : std::true_type {};
2203#else
2204// https://stackoverflow.com/questions/26744589/what-is-a-proper-way-to-implement-is-swappable-to-test-for-the-swappable-concept
2205namespace swap_adl_tests {
2206// if swap ADL finds this then it would call std::swap otherwise (same
2207// signature)
2208struct tag {};
2209
2210template <class T>
2211tag swap(T &, T &);
2212template <class T, std::size_t N>
2213tag swap(T (&a)[N], T (&b)[N]);
2214
2215// helper functions to test if an unqualified swap is possible, and if it
2216// becomes std::swap
2217template <class, class>
2218std::false_type can_swap(...) noexcept(false);
2219template <class T, class U,
2220 class = decltype(swap(std::declval<T &>(), std::declval<U &>()))>
2221std::true_type can_swap(int) noexcept(noexcept(swap(std::declval<T &>(),
2222 std::declval<U &>())));
2223
2224template <class, class>
2225std::false_type uses_std(...);
2226template <class T, class U>
2227std::is_same<decltype(swap(std::declval<T &>(), std::declval<U &>())), tag>
2228uses_std(int);
2229
2230template <class T>
2232 : std::integral_constant<bool,
2233 std::is_nothrow_move_constructible<T>::value &&
2234 std::is_nothrow_move_assignable<T>::value> {};
2235
2236template <class T, std::size_t N>
2238
2239template <class T, class U>
2241 : std::integral_constant<bool, noexcept(can_swap<T, U>(0))> {};
2242} // namespace swap_adl_tests
2243
2244template <class T, class U = T>
2246 : std::integral_constant<
2247 bool,
2248 decltype(detail::swap_adl_tests::can_swap<T, U>(0))::value &&
2249 (!decltype(detail::swap_adl_tests::uses_std<T, U>(0))::value ||
2250 (std::is_move_assignable<T>::value &&
2251 std::is_move_constructible<T>::value))> {};
2252
2253template <class T, std::size_t N>
2254struct is_swappable<T[N], T[N]>
2255 : std::integral_constant<
2256 bool,
2257 decltype(detail::swap_adl_tests::can_swap<T[N], T[N]>(0))::value &&
2258 (!decltype(detail::swap_adl_tests::uses_std<T[N], T[N]>(
2259 0))::value ||
2260 is_swappable<T, T>::value)> {};
2261
2262template <class T, class U = T>
2264 : std::integral_constant<
2265 bool,
2266 is_swappable<T, U>::value &&
2267 ((decltype(detail::swap_adl_tests::uses_std<T, U>(0))::value &&
2268 detail::swap_adl_tests::is_std_swap_noexcept<T>::value) ||
2269 (!decltype(detail::swap_adl_tests::uses_std<T, U>(0))::value &&
2270 detail::swap_adl_tests::is_adl_swap_noexcept<T, U>::value))> {};
2271#endif
2272#endif
2273
2274// Trait for checking if a type is a tl::expected
2275template <class T>
2276struct is_expected_impl : std::false_type {};
2277template <class T, class E>
2278struct is_expected_impl<expected<T, E>> : std::true_type {};
2279template <class T>
2281
2282template <class T, class E, class U>
2284 std::is_constructible<T, U &&>::value &&
2285 !std::is_same<detail::decay_t<U>, in_place_t>::value &&
2286 !std::is_same<expected<T, E>, detail::decay_t<U>>::value &&
2287 !std::is_same<unexpected<E>, detail::decay_t<U>>::value>;
2288
2289template <class T, class E, class U, class G, class UR, class GR>
2291 std::is_constructible<T, UR>::value &&
2292 std::is_constructible<E, GR>::value &&
2293 !std::is_constructible<T, expected<U, G> &>::value &&
2294 !std::is_constructible<T, expected<U, G> &&>::value &&
2295 !std::is_constructible<T, const expected<U, G> &>::value &&
2296 !std::is_constructible<T, const expected<U, G> &&>::value &&
2297 !std::is_convertible<expected<U, G> &, T>::value &&
2298 !std::is_convertible<expected<U, G> &&, T>::value &&
2299 !std::is_convertible<const expected<U, G> &, T>::value &&
2300 !std::is_convertible<const expected<U, G> &&, T>::value>;
2301
2302template <class T, class U>
2304
2305template <class T>
2308
2309template <class T>
2312
2313template <class T>
2315
2316template <class T>
2318
2319} // namespace detail
2320
2321namespace detail {
2322struct no_init_t {};
2323static constexpr no_init_t no_init{};
2324
2325// Implements the storage of the values, and ensures that the destructor is
2326// trivial if it can be.
2327//
2328// This specialization is for where neither `T` or `E` is trivially
2329// destructible, so the destructors must be called on destruction of the
2330// `expected`
2331template <class T, class E, bool = std::is_trivially_destructible<T>::value,
2332 bool = std::is_trivially_destructible<E>::value>
2334 constexpr expected_storage_base() : m_val(T{}), m_has_val(true) {}
2335 constexpr expected_storage_base(no_init_t) : m_no_init(), m_has_val(false) {}
2336
2337 template <class... Args,
2338 detail::enable_if_t<std::is_constructible<T, Args &&...>::value> * =
2339 nullptr>
2340 constexpr expected_storage_base(in_place_t, Args &&...args)
2341 : m_val(std::forward<Args>(args)...), m_has_val(true) {}
2342
2343 template <class U, class... Args,
2344 detail::enable_if_t<std::is_constructible<
2345 T, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
2346 constexpr expected_storage_base(in_place_t, std::initializer_list<U> il,
2347 Args &&...args)
2348 : m_val(il, std::forward<Args>(args)...), m_has_val(true) {}
2349 template <class... Args,
2350 detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * =
2351 nullptr>
2352 constexpr explicit expected_storage_base(unexpect_t, Args &&...args)
2353 : m_unexpect(std::forward<Args>(args)...), m_has_val(false) {}
2354
2355 template <class U, class... Args,
2356 detail::enable_if_t<std::is_constructible<
2357 E, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
2359 std::initializer_list<U> il,
2360 Args &&...args)
2361 : m_unexpect(il, std::forward<Args>(args)...), m_has_val(false) {}
2362
2364 if (m_has_val) {
2365 m_val.~T();
2366 } else {
2367 m_unexpect.~unexpected<E>();
2368 }
2369 }
2370 union {
2374 };
2376};
2377
2378// This specialization is for when both `T` and `E` are trivially-destructible,
2379// so the destructor of the `expected` can be trivial.
2380template <class T, class E>
2382 constexpr expected_storage_base() : m_val(T{}), m_has_val(true) {}
2383 constexpr expected_storage_base(no_init_t) : m_no_init(), m_has_val(false) {}
2384
2385 template <class... Args,
2386 detail::enable_if_t<std::is_constructible<T, Args &&...>::value> * =
2387 nullptr>
2388 constexpr expected_storage_base(in_place_t, Args &&...args)
2389 : m_val(std::forward<Args>(args)...), m_has_val(true) {}
2390
2391 template <class U, class... Args,
2392 detail::enable_if_t<std::is_constructible<
2393 T, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
2394 constexpr expected_storage_base(in_place_t, std::initializer_list<U> il,
2395 Args &&...args)
2396 : m_val(il, std::forward<Args>(args)...), m_has_val(true) {}
2397 template <class... Args,
2398 detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * =
2399 nullptr>
2400 constexpr explicit expected_storage_base(unexpect_t, Args &&...args)
2401 : m_unexpect(std::forward<Args>(args)...), m_has_val(false) {}
2402
2403 template <class U, class... Args,
2404 detail::enable_if_t<std::is_constructible<
2405 E, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
2407 std::initializer_list<U> il,
2408 Args &&...args)
2409 : m_unexpect(il, std::forward<Args>(args)...), m_has_val(false) {}
2410
2412 union {
2416 };
2418};
2419
2420// T is trivial, E is not.
2421template <class T, class E>
2423 constexpr expected_storage_base() : m_val(T{}), m_has_val(true) {}
2425 : m_no_init(), m_has_val(false) {}
2426
2427 template <class... Args,
2428 detail::enable_if_t<std::is_constructible<T, Args &&...>::value> * =
2429 nullptr>
2430 constexpr expected_storage_base(in_place_t, Args &&...args)
2431 : m_val(std::forward<Args>(args)...), m_has_val(true) {}
2432
2433 template <class U, class... Args,
2434 detail::enable_if_t<std::is_constructible<
2435 T, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
2436 constexpr expected_storage_base(in_place_t, std::initializer_list<U> il,
2437 Args &&...args)
2438 : m_val(il, std::forward<Args>(args)...), m_has_val(true) {}
2439 template <class... Args,
2440 detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * =
2441 nullptr>
2442 constexpr explicit expected_storage_base(unexpect_t, Args &&...args)
2443 : m_unexpect(std::forward<Args>(args)...), m_has_val(false) {}
2444
2445 template <class U, class... Args,
2446 detail::enable_if_t<std::is_constructible<
2447 E, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
2449 std::initializer_list<U> il,
2450 Args &&...args)
2451 : m_unexpect(il, std::forward<Args>(args)...), m_has_val(false) {}
2452
2454 if (!m_has_val) {
2455 m_unexpect.~unexpected<E>();
2456 }
2457 }
2458
2459 union {
2463 };
2465};
2466
2467// E is trivial, T is not.
2468template <class T, class E>
2470 constexpr expected_storage_base() : m_val(T{}), m_has_val(true) {}
2471 constexpr expected_storage_base(no_init_t) : m_no_init(), m_has_val(false) {}
2472
2473 template <class... Args,
2474 detail::enable_if_t<std::is_constructible<T, Args &&...>::value> * =
2475 nullptr>
2476 constexpr expected_storage_base(in_place_t, Args &&...args)
2477 : m_val(std::forward<Args>(args)...), m_has_val(true) {}
2478
2479 template <class U, class... Args,
2480 detail::enable_if_t<std::is_constructible<
2481 T, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
2482 constexpr expected_storage_base(in_place_t, std::initializer_list<U> il,
2483 Args &&...args)
2484 : m_val(il, std::forward<Args>(args)...), m_has_val(true) {}
2485 template <class... Args,
2486 detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * =
2487 nullptr>
2488 constexpr explicit expected_storage_base(unexpect_t, Args &&...args)
2489 : m_unexpect(std::forward<Args>(args)...), m_has_val(false) {}
2490
2491 template <class U, class... Args,
2492 detail::enable_if_t<std::is_constructible<
2493 E, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
2495 std::initializer_list<U> il,
2496 Args &&...args)
2497 : m_unexpect(il, std::forward<Args>(args)...), m_has_val(false) {}
2498
2500 if (m_has_val) {
2501 m_val.~T();
2502 }
2503 }
2504 union {
2508 };
2510};
2511
2512// `T` is `void`, `E` is trivially-destructible
2513template <class E>
2515#if __GNUC__ <= 5
2516// no constexpr for GCC 4/5 bug
2517#else
2519#endif
2520 expected_storage_base() : m_has_val(true) {}
2521
2522 constexpr expected_storage_base(no_init_t) : m_val(), m_has_val(false) {}
2523
2524 constexpr expected_storage_base(in_place_t) : m_has_val(true) {}
2525
2526 template <class... Args,
2527 detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * =
2528 nullptr>
2529 constexpr explicit expected_storage_base(unexpect_t, Args &&...args)
2530 : m_unexpect(std::forward<Args>(args)...), m_has_val(false) {}
2531
2532 template <class U, class... Args,
2533 detail::enable_if_t<std::is_constructible<
2534 E, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
2536 std::initializer_list<U> il,
2537 Args &&...args)
2538 : m_unexpect(il, std::forward<Args>(args)...), m_has_val(false) {}
2539
2541 struct dummy {};
2542 union {
2545 };
2547};
2548
2549// `T` is `void`, `E` is not trivially-destructible
2550template <class E>
2552 constexpr expected_storage_base() : m_dummy(), m_has_val(true) {}
2553 constexpr expected_storage_base(no_init_t) : m_dummy(), m_has_val(false) {}
2554
2555 constexpr expected_storage_base(in_place_t) : m_dummy(), m_has_val(true) {}
2556
2557 template <class... Args,
2558 detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * =
2559 nullptr>
2560 constexpr explicit expected_storage_base(unexpect_t, Args &&...args)
2561 : m_unexpect(std::forward<Args>(args)...), m_has_val(false) {}
2562
2563 template <class U, class... Args,
2564 detail::enable_if_t<std::is_constructible<
2565 E, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
2567 std::initializer_list<U> il,
2568 Args &&...args)
2569 : m_unexpect(il, std::forward<Args>(args)...), m_has_val(false) {}
2570
2572 if (!m_has_val) {
2573 m_unexpect.~unexpected<E>();
2574 }
2575 }
2576
2577 union {
2580 };
2582};
2583
2584// This base class provides some handy member functions which can be used in
2585// further derived classes
2586template <class T, class E>
2588 using expected_storage_base<T, E>::expected_storage_base;
2589
2590 template <class... Args>
2591 void construct(Args &&...args) noexcept {
2592 new (std::addressof(this->m_val)) T(std::forward<Args>(args)...);
2593 this->m_has_val = true;
2594 }
2595
2596 template <class Rhs>
2597 void construct_with(Rhs &&rhs) noexcept {
2598 new (std::addressof(this->m_val)) T(std::forward<Rhs>(rhs).get());
2599 this->m_has_val = true;
2600 }
2601
2602 template <class... Args>
2603 void construct_error(Args &&...args) noexcept {
2604 new (std::addressof(this->m_unexpect))
2605 unexpected<E>(std::forward<Args>(args)...);
2606 this->m_has_val = false;
2607 }
2608
2609#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
2610
2611 // These assign overloads ensure that the most efficient assignment
2612 // implementation is used while maintaining the strong exception guarantee.
2613 // The problematic case is where rhs has a value, but *this does not.
2614 //
2615 // This overload handles the case where we can just copy-construct `T`
2616 // directly into place without throwing.
2617 template <class U = T,
2619 * = nullptr>
2620 void assign(const expected_operations_base &rhs) noexcept {
2621 if (!this->m_has_val && rhs.m_has_val) {
2622 geterr().~unexpected<E>();
2623 construct(rhs.get());
2624 } else {
2625 assign_common(rhs);
2626 }
2627 }
2628
2629 // This overload handles the case where we can attempt to create a copy of
2630 // `T`, then no-throw move it into place if the copy was successful.
2631 template <class U = T,
2632 detail::enable_if_t<!std::is_nothrow_copy_constructible<U>::value &&
2633 std::is_nothrow_move_constructible<U>::value>
2634 * = nullptr>
2635 void assign(const expected_operations_base &rhs) noexcept {
2636 if (!this->m_has_val && rhs.m_has_val) {
2637 T tmp = rhs.get();
2638 geterr().~unexpected<E>();
2639 construct(std::move(tmp));
2640 } else {
2641 assign_common(rhs);
2642 }
2643 }
2644
2645 // This overload is the worst-case, where we have to move-construct the
2646 // unexpected value into temporary storage, then try to copy the T into place.
2647 // If the construction succeeds, then everything is fine, but if it throws,
2648 // then we move the old unexpected value back into place before rethrowing the
2649 // exception.
2650 template <class U = T,
2651 detail::enable_if_t<!std::is_nothrow_copy_constructible<U>::value &&
2652 !std::is_nothrow_move_constructible<U>::value>
2653 * = nullptr>
2654 void assign(const expected_operations_base &rhs) {
2655 if (!this->m_has_val && rhs.m_has_val) {
2656 auto tmp = std::move(geterr());
2657 geterr().~unexpected<E>();
2658
2659#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
2660 try {
2661 construct(rhs.get());
2662 } catch (...) {
2663 geterr() = std::move(tmp);
2664 throw;
2665 }
2666#else
2667 construct(rhs.get());
2668#endif
2669 } else {
2670 assign_common(rhs);
2671 }
2672 }
2673
2674 // These overloads do the same as above, but for rvalues
2675 template <class U = T,
2676 detail::enable_if_t<std::is_nothrow_move_constructible<U>::value>
2677 * = nullptr>
2678 void assign(expected_operations_base &&rhs) noexcept {
2679 if (!this->m_has_val && rhs.m_has_val) {
2680 geterr().~unexpected<E>();
2681 construct(std::move(rhs).get());
2682 } else {
2683 assign_common(std::move(rhs));
2684 }
2685 }
2686
2687 template <class U = T,
2688 detail::enable_if_t<!std::is_nothrow_move_constructible<U>::value>
2689 * = nullptr>
2690 void assign(expected_operations_base &&rhs) {
2691 if (!this->m_has_val && rhs.m_has_val) {
2692 auto tmp = std::move(geterr());
2693 geterr().~unexpected<E>();
2694#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
2695 try {
2696 construct(std::move(rhs).get());
2697 } catch (...) {
2698 geterr() = std::move(tmp);
2699 throw;
2700 }
2701#else
2702 construct(std::move(rhs).get());
2703#endif
2704 } else {
2705 assign_common(std::move(rhs));
2706 }
2707 }
2708
2709#else
2710
2711 // If exceptions are disabled then we can just copy-construct
2712 void assign(const expected_operations_base &rhs) noexcept {
2713 if (!this->m_has_val && rhs.m_has_val) {
2714 geterr().~unexpected<E>();
2715 construct(rhs.get());
2716 } else {
2717 assign_common(rhs);
2718 }
2719 }
2720
2721 void assign(expected_operations_base &&rhs) noexcept {
2722 if (!this->m_has_val && rhs.m_has_val) {
2723 geterr().~unexpected<E>();
2724 construct(std::move(rhs).get());
2725 } else {
2726 assign_common(std::move(rhs));
2727 }
2728 }
2729
2730#endif
2731
2732 // The common part of move/copy assigning
2733 template <class Rhs>
2734 void assign_common(Rhs &&rhs) {
2735 if (this->m_has_val) {
2736 if (rhs.m_has_val) {
2737 get() = std::forward<Rhs>(rhs).get();
2738 } else {
2739 destroy_val();
2740 construct_error(std::forward<Rhs>(rhs).geterr());
2741 }
2742 } else {
2743 if (!rhs.m_has_val) {
2744 geterr() = std::forward<Rhs>(rhs).geterr();
2745 }
2746 }
2747 }
2748
2749 bool has_value() const { return this->m_has_val; }
2750
2751 TL_EXPECTED_11_CONSTEXPR T &get() & { return this->m_val; }
2752 constexpr const T &get() const & { return this->m_val; }
2753 TL_EXPECTED_11_CONSTEXPR T &&get() && { return std::move(this->m_val); }
2754#ifndef TL_EXPECTED_NO_CONSTRR
2755 constexpr const T &&get() const && { return std::move(this->m_val); }
2756#endif
2757
2759 return this->m_unexpect;
2760 }
2761 constexpr const unexpected<E> &geterr() const & { return this->m_unexpect; }
2763 return std::move(this->m_unexpect);
2764 }
2765#ifndef TL_EXPECTED_NO_CONSTRR
2766 constexpr const unexpected<E> &&geterr() const && {
2767 return std::move(this->m_unexpect);
2768 }
2769#endif
2770
2772};
2773
2774// This base class provides some handy member functions which can be used in
2775// further derived classes
2776template <class E>
2778 using expected_storage_base<void, E>::expected_storage_base;
2779
2780 template <class... Args>
2781 void construct() noexcept {
2782 this->m_has_val = true;
2783 }
2784
2785 // This function doesn't use its argument, but needs it so that code in
2786 // levels above this can work independently of whether T is void
2787 template <class Rhs>
2788 void construct_with(Rhs &&) noexcept {
2789 this->m_has_val = true;
2790 }
2791
2792 template <class... Args>
2793 void construct_error(Args &&...args) noexcept {
2794 new (std::addressof(this->m_unexpect))
2795 unexpected<E>(std::forward<Args>(args)...);
2796 this->m_has_val = false;
2797 }
2798
2799 template <class Rhs>
2800 void assign(Rhs &&rhs) noexcept {
2801 if (!this->m_has_val) {
2802 if (rhs.m_has_val) {
2803 geterr().~unexpected<E>();
2804 construct();
2805 } else {
2806 geterr() = std::forward<Rhs>(rhs).geterr();
2807 }
2808 } else {
2809 if (!rhs.m_has_val) {
2810 construct_error(std::forward<Rhs>(rhs).geterr());
2811 }
2812 }
2813 }
2814
2815 bool has_value() const { return this->m_has_val; }
2816
2818 return this->m_unexpect;
2819 }
2820 constexpr const unexpected<E> &geterr() const & { return this->m_unexpect; }
2822 return std::move(this->m_unexpect);
2823 }
2824#ifndef TL_EXPECTED_NO_CONSTRR
2825 constexpr const unexpected<E> &&geterr() const && {
2826 return std::move(this->m_unexpect);
2827 }
2828#endif
2829
2831 // no-op
2832 }
2833};
2834
2835// This class manages conditionally having a trivial copy constructor
2836// This specialization is for when T and E are trivially copy constructible
2837template <class T, class E,
2839 T)>::value &&
2842 using expected_operations_base<T, E>::expected_operations_base;
2843};
2844
2845// This specialization is for when T or E are not trivially copy constructible
2846template <class T, class E>
2848 using expected_operations_base<T, E>::expected_operations_base;
2849
2853 if (rhs.has_value()) {
2854 this->construct_with(rhs);
2855 } else {
2856 this->construct_error(rhs.geterr());
2857 }
2858 }
2859
2863};
2864
2865// This class manages conditionally having a trivial move constructor
2866// Unfortunately there's no way to achieve this in GCC < 5 AFAIK, since it
2867// doesn't implement an analogue to std::is_trivially_move_constructible. We
2868// have to make do with a non-trivial move constructor even if T is trivially
2869// move constructible
2870#ifndef TL_EXPECTED_GCC49
2871template <class T, class E,
2872 bool =
2874 std::is_trivially_move_constructible<E>::value>
2876 using expected_copy_base<T, E>::expected_copy_base;
2877};
2878#else
2879template <class T, class E, bool = false>
2880struct expected_move_base;
2881#endif
2882template <class T, class E>
2883struct expected_move_base<T, E, false> : expected_copy_base<T, E> {
2884 using expected_copy_base<T, E>::expected_copy_base;
2885
2888
2890 std::is_nothrow_move_constructible<T>::value)
2891 : expected_copy_base<T, E>(no_init) {
2892 if (rhs.has_value()) {
2893 this->construct_with(std::move(rhs));
2894 } else {
2895 this->construct_error(std::move(rhs.geterr()));
2896 }
2897 }
2900};
2901
2902// This class manages conditionally having a trivial copy assignment operator
2903template <
2904 class T, class E,
2905 bool =
2906 is_void_or<
2914 using expected_move_base<T, E>::expected_move_base;
2915};
2916
2917template <class T, class E>
2932
2933// This class manages conditionally having a trivial move assignment operator
2934// Unfortunately there's no way to achieve this in GCC < 5 AFAIK, since it
2935// doesn't implement an analogue to std::is_trivially_move_assignable. We have
2936// to make do with a non-trivial move assignment operator even if T is trivially
2937// move assignable
2938#ifndef TL_EXPECTED_GCC49
2939template <
2940 class T, class E,
2941 bool = is_void_or<
2943 std::is_trivially_move_constructible<T>,
2944 std::is_trivially_move_assignable<T>>>::value &&
2945 std::is_trivially_destructible<E>::value &&
2946 std::is_trivially_move_constructible<E>::value &&
2947 std::is_trivially_move_assignable<E>::value>
2949 using expected_copy_assign_base<T, E>::expected_copy_assign_base;
2950};
2951#else
2952template <class T, class E, bool = false>
2954#endif
2955
2956template <class T, class E>
2957struct expected_move_assign_base<T, E, false>
2959 using expected_copy_assign_base<T, E>::expected_copy_assign_base;
2960
2963
2965
2967 default;
2968
2971 &&rhs) noexcept(std::is_nothrow_move_constructible<T>::value &&
2972 std::is_nothrow_move_assignable<T>::value) {
2973 this->assign(std::move(rhs));
2974 return *this;
2975 }
2976};
2977
2978// expected_delete_ctor_base will conditionally delete copy and move
2979// constructors depending on whether T is copy/move constructible
2980template <class T, class E,
2981 bool EnableCopy = (is_copy_constructible_or_void<T>::value &&
2982 std::is_copy_constructible<E>::value),
2983 bool EnableMove = (is_move_constructible_or_void<T>::value &&
2984 std::is_move_constructible<E>::value)>
2994
2995template <class T, class E>
3005
3006template <class T, class E>
3016
3017template <class T, class E>
3027
3028// expected_delete_assign_base will conditionally delete copy and move
3029// constructors depending on whether T and E are copy/move constructible +
3030// assignable
3031template <class T, class E,
3032 bool EnableCopy = (is_copy_constructible_or_void<T>::value &&
3033 std::is_copy_constructible<E>::value &&
3034 is_copy_assignable_or_void<T>::value &&
3035 std::is_copy_assignable<E>::value),
3036 bool EnableMove = (is_move_constructible_or_void<T>::value &&
3037 std::is_move_constructible<E>::value &&
3038 is_move_assignable_or_void<T>::value &&
3039 std::is_move_assignable<E>::value)>
3050
3051template <class T, class E>
3062
3063template <class T, class E>
3074
3075template <class T, class E>
3086
3087// This is needed to be able to construct the expected_default_ctor_base which
3088// follows, while still conditionally deleting the default constructor.
3090 explicit constexpr default_constructor_tag() = default;
3091};
3092
3093// expected_default_ctor_base will ensure that expected has a deleted default
3094// consturctor if T is not default constructible.
3095// This specialization is for when T is default constructible
3096template <class T, class E,
3097 bool Enable =
3098 std::is_default_constructible<T>::value || std::is_void<T>::value>
3100 constexpr expected_default_ctor_base() noexcept = default;
3102 expected_default_ctor_base const &) noexcept = default;
3104 default;
3106 expected_default_ctor_base const &) noexcept = default;
3108 expected_default_ctor_base &&) noexcept = default;
3109
3111};
3112
3113// This specialization is for when T is not default constructible
3114template <class T, class E>
3115struct expected_default_ctor_base<T, E, false> {
3116 constexpr expected_default_ctor_base() noexcept = delete;
3118 expected_default_ctor_base const &) noexcept = default;
3120 default;
3122 expected_default_ctor_base const &) noexcept = default;
3124 expected_default_ctor_base &&) noexcept = default;
3125
3127};
3128} // namespace detail
3129
3130template <class E>
3131class bad_expected_access : public std::exception {
3132 public:
3133 explicit bad_expected_access(E e) : m_val(std::move(e)) {}
3134
3135 virtual const char *what() const noexcept override {
3136 return "Bad expected access";
3137 }
3138
3139 const E &error() const & { return m_val; }
3140 E &error() & { return m_val; }
3141 const E &&error() const && { return std::move(m_val); }
3142 E &&error() && { return std::move(m_val); }
3143
3144 private:
3145 E m_val;
3146};
3147
3155template <class T, class E>
3160 static_assert(!std::is_reference<T>::value, "T must not be a reference");
3161 static_assert(!std::is_same<T, std::remove_cv<in_place_t>::type>::value,
3162 "T must not be in_place_t");
3163 static_assert(!std::is_same<T, std::remove_cv<unexpect_t>::type>::value,
3164 "T must not be unexpect_t");
3165 static_assert(
3166 !std::is_same<T, typename std::remove_cv<unexpected<E>>::type>::value,
3167 "T must not be unexpected<E>");
3168 static_assert(!std::is_reference<E>::value, "E must not be a reference");
3169
3170 T *valptr() { return std::addressof(this->m_val); }
3171 const T *valptr() const { return std::addressof(this->m_val); }
3172 unexpected<E> *errptr() { return std::addressof(this->m_unexpect); }
3173 const unexpected<E> *errptr() const {
3174 return std::addressof(this->m_unexpect);
3175 }
3176
3177 template <class U = T,
3179 TL_EXPECTED_11_CONSTEXPR U &val() {
3180 return this->m_val;
3181 }
3182 TL_EXPECTED_11_CONSTEXPR unexpected<E> &err() { return this->m_unexpect; }
3183
3184 template <class U = T,
3186 constexpr const U &val() const {
3187 return this->m_val;
3188 }
3189 constexpr const unexpected<E> &err() const { return this->m_unexpect; }
3190
3193
3194 public:
3195 typedef T value_type;
3196 typedef E error_type;
3198
3199#if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \
3200 !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55)
3201 template <class F>
3202 TL_EXPECTED_11_CONSTEXPR auto and_then(F &&f) & {
3203 return and_then_impl(*this, std::forward<F>(f));
3204 }
3205 template <class F>
3206 TL_EXPECTED_11_CONSTEXPR auto and_then(F &&f) && {
3207 return and_then_impl(std::move(*this), std::forward<F>(f));
3208 }
3209 template <class F>
3210 constexpr auto and_then(F &&f) const & {
3211 return and_then_impl(*this, std::forward<F>(f));
3212 }
3213
3214#ifndef TL_EXPECTED_NO_CONSTRR
3215 template <class F>
3216 constexpr auto and_then(F &&f) const && {
3217 return and_then_impl(std::move(*this), std::forward<F>(f));
3218 }
3219#endif
3220
3221#else
3222 template <class F>
3223 TL_EXPECTED_11_CONSTEXPR auto and_then(F &&f) & -> decltype(and_then_impl(
3224 std::declval<expected &>(), std::forward<F>(f))) {
3225 return and_then_impl(*this, std::forward<F>(f));
3226 }
3227 template <class F>
3228 TL_EXPECTED_11_CONSTEXPR auto and_then(F &&f) && -> decltype(and_then_impl(
3229 std::declval<expected &&>(), std::forward<F>(f))) {
3230 return and_then_impl(std::move(*this), std::forward<F>(f));
3231 }
3232 template <class F>
3233 constexpr auto and_then(F &&f) const & -> decltype(and_then_impl(
3234 std::declval<expected const &>(), std::forward<F>(f))) {
3235 return and_then_impl(*this, std::forward<F>(f));
3236 }
3237
3238#ifndef TL_EXPECTED_NO_CONSTRR
3239 template <class F>
3240 constexpr auto and_then(F &&f) const && -> decltype(and_then_impl(
3241 std::declval<expected const &&>(), std::forward<F>(f))) {
3242 return and_then_impl(std::move(*this), std::forward<F>(f));
3243 }
3244#endif
3245#endif
3246
3247#if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \
3248 !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55)
3249 template <class F>
3250 TL_EXPECTED_11_CONSTEXPR auto map(F &&f) & {
3251 return expected_map_impl(*this, std::forward<F>(f));
3252 }
3253 template <class F>
3254 TL_EXPECTED_11_CONSTEXPR auto map(F &&f) && {
3255 return expected_map_impl(std::move(*this), std::forward<F>(f));
3256 }
3257 template <class F>
3258 constexpr auto map(F &&f) const & {
3259 return expected_map_impl(*this, std::forward<F>(f));
3260 }
3261 template <class F>
3262 constexpr auto map(F &&f) const && {
3263 return expected_map_impl(std::move(*this), std::forward<F>(f));
3264 }
3265#else
3266 template <class F>
3268 std::declval<expected &>(), std::declval<F &&>()))
3269 map(F &&f) & {
3270 return expected_map_impl(*this, std::forward<F>(f));
3271 }
3272 template <class F>
3273 TL_EXPECTED_11_CONSTEXPR decltype(expected_map_impl(std::declval<expected>(),
3274 std::declval<F &&>()))
3275 map(F &&f) && {
3276 return expected_map_impl(std::move(*this), std::forward<F>(f));
3277 }
3278 template <class F>
3279 constexpr decltype(expected_map_impl(std::declval<const expected &>(),
3280 std::declval<F &&>()))
3281 map(F &&f) const & {
3282 return expected_map_impl(*this, std::forward<F>(f));
3283 }
3284
3285#ifndef TL_EXPECTED_NO_CONSTRR
3286 template <class F>
3287 constexpr decltype(expected_map_impl(std::declval<const expected &&>(),
3288 std::declval<F &&>()))
3289 map(F &&f) const && {
3290 return expected_map_impl(std::move(*this), std::forward<F>(f));
3291 }
3292#endif
3293#endif
3294
3295#if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \
3296 !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55)
3297 template <class F>
3298 TL_EXPECTED_11_CONSTEXPR auto transform(F &&f) & {
3299 return expected_map_impl(*this, std::forward<F>(f));
3300 }
3301 template <class F>
3302 TL_EXPECTED_11_CONSTEXPR auto transform(F &&f) && {
3303 return expected_map_impl(std::move(*this), std::forward<F>(f));
3304 }
3305 template <class F>
3306 constexpr auto transform(F &&f) const & {
3307 return expected_map_impl(*this, std::forward<F>(f));
3308 }
3309 template <class F>
3310 constexpr auto transform(F &&f) const && {
3311 return expected_map_impl(std::move(*this), std::forward<F>(f));
3312 }
3313#else
3314 template <class F>
3316 std::declval<expected &>(), std::declval<F &&>()))
3317 transform(F &&f) & {
3318 return expected_map_impl(*this, std::forward<F>(f));
3319 }
3320 template <class F>
3321 TL_EXPECTED_11_CONSTEXPR decltype(expected_map_impl(std::declval<expected>(),
3322 std::declval<F &&>()))
3323 transform(F &&f) && {
3324 return expected_map_impl(std::move(*this), std::forward<F>(f));
3325 }
3326 template <class F>
3327 constexpr decltype(expected_map_impl(std::declval<const expected &>(),
3328 std::declval<F &&>()))
3329 transform(F &&f) const & {
3330 return expected_map_impl(*this, std::forward<F>(f));
3331 }
3332
3333#ifndef TL_EXPECTED_NO_CONSTRR
3334 template <class F>
3335 constexpr decltype(expected_map_impl(std::declval<const expected &&>(),
3336 std::declval<F &&>()))
3337 transform(F &&f) const && {
3338 return expected_map_impl(std::move(*this), std::forward<F>(f));
3339 }
3340#endif
3341#endif
3342
3343#if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \
3344 !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55)
3345 template <class F>
3346 TL_EXPECTED_11_CONSTEXPR auto map_error(F &&f) & {
3347 return map_error_impl(*this, std::forward<F>(f));
3348 }
3349 template <class F>
3350 TL_EXPECTED_11_CONSTEXPR auto map_error(F &&f) && {
3351 return map_error_impl(std::move(*this), std::forward<F>(f));
3352 }
3353 template <class F>
3354 constexpr auto map_error(F &&f) const & {
3355 return map_error_impl(*this, std::forward<F>(f));
3356 }
3357 template <class F>
3358 constexpr auto map_error(F &&f) const && {
3359 return map_error_impl(std::move(*this), std::forward<F>(f));
3360 }
3361#else
3362 template <class F>
3363 TL_EXPECTED_11_CONSTEXPR decltype(map_error_impl(std::declval<expected &>(),
3364 std::declval<F &&>()))
3365 map_error(F &&f) & {
3366 return map_error_impl(*this, std::forward<F>(f));
3367 }
3368 template <class F>
3369 TL_EXPECTED_11_CONSTEXPR decltype(map_error_impl(std::declval<expected &&>(),
3370 std::declval<F &&>()))
3371 map_error(F &&f) && {
3372 return map_error_impl(std::move(*this), std::forward<F>(f));
3373 }
3374 template <class F>
3375 constexpr decltype(map_error_impl(std::declval<const expected &>(),
3376 std::declval<F &&>()))
3377 map_error(F &&f) const & {
3378 return map_error_impl(*this, std::forward<F>(f));
3379 }
3380
3381#ifndef TL_EXPECTED_NO_CONSTRR
3382 template <class F>
3383 constexpr decltype(map_error_impl(std::declval<const expected &&>(),
3384 std::declval<F &&>()))
3385 map_error(F &&f) const && {
3386 return map_error_impl(std::move(*this), std::forward<F>(f));
3387 }
3388#endif
3389#endif
3390#if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \
3391 !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55)
3392 template <class F>
3393 TL_EXPECTED_11_CONSTEXPR auto transform_error(F &&f) & {
3394 return map_error_impl(*this, std::forward<F>(f));
3395 }
3396 template <class F>
3397 TL_EXPECTED_11_CONSTEXPR auto transform_error(F &&f) && {
3398 return map_error_impl(std::move(*this), std::forward<F>(f));
3399 }
3400 template <class F>
3401 constexpr auto transform_error(F &&f) const & {
3402 return map_error_impl(*this, std::forward<F>(f));
3403 }
3404 template <class F>
3405 constexpr auto transform_error(F &&f) const && {
3406 return map_error_impl(std::move(*this), std::forward<F>(f));
3407 }
3408#else
3409 template <class F>
3410 TL_EXPECTED_11_CONSTEXPR decltype(map_error_impl(std::declval<expected &>(),
3411 std::declval<F &&>()))
3413 return map_error_impl(*this, std::forward<F>(f));
3414 }
3415 template <class F>
3416 TL_EXPECTED_11_CONSTEXPR decltype(map_error_impl(std::declval<expected &&>(),
3417 std::declval<F &&>()))
3419 return map_error_impl(std::move(*this), std::forward<F>(f));
3420 }
3421 template <class F>
3422 constexpr decltype(map_error_impl(std::declval<const expected &>(),
3423 std::declval<F &&>()))
3424 transform_error(F &&f) const & {
3425 return map_error_impl(*this, std::forward<F>(f));
3426 }
3427
3428#ifndef TL_EXPECTED_NO_CONSTRR
3429 template <class F>
3430 constexpr decltype(map_error_impl(std::declval<const expected &&>(),
3431 std::declval<F &&>()))
3432 transform_error(F &&f) const && {
3433 return map_error_impl(std::move(*this), std::forward<F>(f));
3434 }
3435#endif
3436#endif
3437 template <class F>
3439 return or_else_impl(*this, std::forward<F>(f));
3440 }
3441
3442 template <class F>
3444 return or_else_impl(std::move(*this), std::forward<F>(f));
3445 }
3446
3447 template <class F>
3448 expected constexpr or_else(F &&f) const & {
3449 return or_else_impl(*this, std::forward<F>(f));
3450 }
3451
3452#ifndef TL_EXPECTED_NO_CONSTRR
3453 template <class F>
3454 expected constexpr or_else(F &&f) const && {
3455 return or_else_impl(std::move(*this), std::forward<F>(f));
3456 }
3457#endif
3458 constexpr expected() = default;
3459 constexpr expected(const expected &rhs) = default;
3460 constexpr expected(expected &&rhs) = default;
3461 expected &operator=(const expected &rhs) = default;
3462 expected &operator=(expected &&rhs) = default;
3463
3464 template <class... Args,
3465 detail::enable_if_t<std::is_constructible<T, Args &&...>::value> * =
3466 nullptr>
3467 constexpr expected(in_place_t, Args &&...args)
3468 : impl_base(in_place, std::forward<Args>(args)...),
3469 ctor_base(detail::default_constructor_tag{}) {}
3470
3471 template <class U, class... Args,
3472 detail::enable_if_t<std::is_constructible<
3473 T, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
3474 constexpr expected(in_place_t, std::initializer_list<U> il, Args &&...args)
3475 : impl_base(in_place, il, std::forward<Args>(args)...),
3476 ctor_base(detail::default_constructor_tag{}) {}
3477
3478 template <class G = E,
3480 nullptr,
3482 nullptr>
3483 explicit constexpr expected(const unexpected<G> &e)
3484 : impl_base(unexpect, e.value()),
3485 ctor_base(detail::default_constructor_tag{}) {}
3486
3487 template <
3488 class G = E,
3490 nullptr,
3492 constexpr expected(unexpected<G> const &e)
3493 : impl_base(unexpect, e.value()),
3494 ctor_base(detail::default_constructor_tag{}) {}
3495
3496 template <
3497 class G = E,
3500 explicit constexpr expected(unexpected<G> &&e) noexcept(
3501 std::is_nothrow_constructible<E, G &&>::value)
3502 : impl_base(unexpect, std::move(e.value())),
3503 ctor_base(detail::default_constructor_tag{}) {}
3504
3505 template <
3506 class G = E,
3509 constexpr expected(unexpected<G> &&e) noexcept(
3510 std::is_nothrow_constructible<E, G &&>::value)
3511 : impl_base(unexpect, std::move(e.value())),
3512 ctor_base(detail::default_constructor_tag{}) {}
3513
3514 template <class... Args,
3515 detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * =
3516 nullptr>
3517 constexpr explicit expected(unexpect_t, Args &&...args)
3518 : impl_base(unexpect, std::forward<Args>(args)...),
3519 ctor_base(detail::default_constructor_tag{}) {}
3520
3521 template <class U, class... Args,
3522 detail::enable_if_t<std::is_constructible<
3523 E, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
3524 constexpr explicit expected(unexpect_t, std::initializer_list<U> il,
3525 Args &&...args)
3526 : impl_base(unexpect, il, std::forward<Args>(args)...),
3527 ctor_base(detail::default_constructor_tag{}) {}
3528
3529 template <class U, class G,
3530 detail::enable_if_t<!(std::is_convertible<U const &, T>::value &&
3531 std::is_convertible<G const &, E>::value)> * =
3532 nullptr,
3534 * = nullptr>
3537 if (rhs.has_value()) {
3538 this->construct(*rhs);
3539 } else {
3540 this->construct_error(rhs.error());
3541 }
3542 }
3543
3544 template <class U, class G,
3545 detail::enable_if_t<(std::is_convertible<U const &, T>::value &&
3546 std::is_convertible<G const &, E>::value)> * =
3547 nullptr,
3548 detail::expected_enable_from_other<T, E, U, G, const U &, const G &>
3549 * = nullptr>
3552 if (rhs.has_value()) {
3553 this->construct(*rhs);
3554 } else {
3555 this->construct_error(rhs.error());
3556 }
3557 }
3558
3559 template <
3560 class U, class G,
3561 detail::enable_if_t<!(std::is_convertible<U &&, T>::value &&
3562 std::is_convertible<G &&, E>::value)> * = nullptr,
3563 detail::expected_enable_from_other<T, E, U, G, U &&, G &&> * = nullptr>
3566 if (rhs.has_value()) {
3567 this->construct(std::move(*rhs));
3568 } else {
3569 this->construct_error(std::move(rhs.error()));
3570 }
3571 }
3572
3573 template <
3574 class U, class G,
3575 detail::enable_if_t<(std::is_convertible<U &&, T>::value &&
3576 std::is_convertible<G &&, E>::value)> * = nullptr,
3577 detail::expected_enable_from_other<T, E, U, G, U &&, G &&> * = nullptr>
3580 if (rhs.has_value()) {
3581 this->construct(std::move(*rhs));
3582 } else {
3583 this->construct_error(std::move(rhs.error()));
3584 }
3585 }
3586
3587 template <
3588 class U = T,
3589 detail::enable_if_t<!std::is_convertible<U &&, T>::value> * = nullptr,
3590 detail::expected_enable_forward_value<T, E, U> * = nullptr>
3592 : expected(in_place, std::forward<U>(v)) {}
3593
3594 template <
3595 class U = T,
3599 : expected(in_place, std::forward<U>(v)) {}
3600
3601 template <
3602 class U = T, class G = T,
3604 nullptr,
3607 (!std::is_same<expected<T, E>, detail::decay_t<U>>::value &&
3609 std::is_same<T, detail::decay_t<U>>>::value &&
3610 std::is_constructible<T, U>::value &&
3611 std::is_assignable<G &, U>::value &&
3612 std::is_nothrow_move_constructible<E>::value)> * = nullptr>
3613 expected &operator=(U &&v) {
3614 if (has_value()) {
3615 val() = std::forward<U>(v);
3616 } else {
3617 err().~unexpected<E>();
3618 ::new (valptr()) T(std::forward<U>(v));
3619 this->m_has_val = true;
3620 }
3621
3622 return *this;
3623 }
3624
3625 template <
3626 class U = T, class G = T,
3628 nullptr,
3631 (!std::is_same<expected<T, E>, detail::decay_t<U>>::value &&
3633 std::is_same<T, detail::decay_t<U>>>::value &&
3634 std::is_constructible<T, U>::value &&
3635 std::is_assignable<G &, U>::value &&
3636 std::is_nothrow_move_constructible<E>::value)> * = nullptr>
3637 expected &operator=(U &&v) {
3638 if (has_value()) {
3639 val() = std::forward<U>(v);
3640 } else {
3641 auto tmp = std::move(err());
3642 err().~unexpected<E>();
3643
3644#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
3645 try {
3646 ::new (valptr()) T(std::forward<U>(v));
3647 this->m_has_val = true;
3648 } catch (...) {
3649 err() = std::move(tmp);
3650 throw;
3651 }
3652#else
3653 ::new (valptr()) T(std::forward<U>(v));
3654 this->m_has_val = true;
3655#endif
3656 }
3657
3658 return *this;
3659 }
3660
3661 template <class G = E,
3663 std::is_assignable<G &, G>::value> * = nullptr>
3665 if (!has_value()) {
3666 err() = rhs;
3667 } else {
3668 this->destroy_val();
3669 ::new (errptr()) unexpected<E>(rhs);
3670 this->m_has_val = false;
3671 }
3672
3673 return *this;
3674 }
3675
3676 template <class G = E,
3678 std::is_move_assignable<G>::value> * = nullptr>
3680 if (!has_value()) {
3681 err() = std::move(rhs);
3682 } else {
3683 this->destroy_val();
3684 ::new (errptr()) unexpected<E>(std::move(rhs));
3685 this->m_has_val = false;
3686 }
3687
3688 return *this;
3689 }
3690
3691 template <class... Args, detail::enable_if_t<std::is_nothrow_constructible<
3692 T, Args &&...>::value> * = nullptr>
3693 void emplace(Args &&...args) {
3694 if (has_value()) {
3695 val().~T();
3696 } else {
3697 err().~unexpected<E>();
3698 this->m_has_val = true;
3699 }
3700 ::new (valptr()) T(std::forward<Args>(args)...);
3701 }
3702
3703 template <class... Args, detail::enable_if_t<!std::is_nothrow_constructible<
3704 T, Args &&...>::value> * = nullptr>
3705 void emplace(Args &&...args) {
3706 if (has_value()) {
3707 val().~T();
3708 ::new (valptr()) T(std::forward<Args>(args)...);
3709 } else {
3710 auto tmp = std::move(err());
3711 err().~unexpected<E>();
3712
3713#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
3714 try {
3715 ::new (valptr()) T(std::forward<Args>(args)...);
3716 this->m_has_val = true;
3717 } catch (...) {
3718 err() = std::move(tmp);
3719 throw;
3720 }
3721#else
3722 ::new (valptr()) T(std::forward<Args>(args)...);
3723 this->m_has_val = true;
3724#endif
3725 }
3726 }
3727
3728 template <class U, class... Args,
3729 detail::enable_if_t<std::is_nothrow_constructible<
3730 T, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
3731 void emplace(std::initializer_list<U> il, Args &&...args) {
3732 if (has_value()) {
3733 T t(il, std::forward<Args>(args)...);
3734 val() = std::move(t);
3735 } else {
3736 err().~unexpected<E>();
3737 ::new (valptr()) T(il, std::forward<Args>(args)...);
3738 this->m_has_val = true;
3739 }
3740 }
3741
3742 template <class U, class... Args,
3743 detail::enable_if_t<!std::is_nothrow_constructible<
3744 T, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
3745 void emplace(std::initializer_list<U> il, Args &&...args) {
3746 if (has_value()) {
3747 T t(il, std::forward<Args>(args)...);
3748 val() = std::move(t);
3749 } else {
3750 auto tmp = std::move(err());
3751 err().~unexpected<E>();
3752
3753#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
3754 try {
3755 ::new (valptr()) T(il, std::forward<Args>(args)...);
3756 this->m_has_val = true;
3757 } catch (...) {
3758 err() = std::move(tmp);
3759 throw;
3760 }
3761#else
3762 ::new (valptr()) T(il, std::forward<Args>(args)...);
3763 this->m_has_val = true;
3764#endif
3765 }
3766 }
3767
3768 private:
3769 using t_is_void = std::true_type;
3770 using t_is_not_void = std::false_type;
3771 using t_is_nothrow_move_constructible = std::true_type;
3772 using move_constructing_t_can_throw = std::false_type;
3773 using e_is_nothrow_move_constructible = std::true_type;
3774 using move_constructing_e_can_throw = std::false_type;
3775
3776 void swap_where_both_have_value(expected & /*rhs*/, t_is_void) noexcept {
3777 // swapping void is a no-op
3778 }
3779
3780 void swap_where_both_have_value(expected &rhs, t_is_not_void) {
3781 using std::swap;
3782 swap(val(), rhs.val());
3783 }
3784
3785 void swap_where_only_one_has_value(expected &rhs, t_is_void) noexcept(
3786 std::is_nothrow_move_constructible<E>::value) {
3787 ::new (errptr()) unexpected_type(std::move(rhs.err()));
3788 rhs.err().~unexpected_type();
3789 std::swap(this->m_has_val, rhs.m_has_val);
3790 }
3791
3792 void swap_where_only_one_has_value(expected &rhs, t_is_not_void) {
3793 swap_where_only_one_has_value_and_t_is_not_void(
3794 rhs, typename std::is_nothrow_move_constructible<T>::type{},
3795 typename std::is_nothrow_move_constructible<E>::type{});
3796 }
3797
3798 void swap_where_only_one_has_value_and_t_is_not_void(
3799 expected &rhs, t_is_nothrow_move_constructible,
3800 e_is_nothrow_move_constructible) noexcept {
3801 auto temp = std::move(val());
3802 val().~T();
3803 ::new (errptr()) unexpected_type(std::move(rhs.err()));
3804 rhs.err().~unexpected_type();
3805 ::new (rhs.valptr()) T(std::move(temp));
3806 std::swap(this->m_has_val, rhs.m_has_val);
3807 }
3808
3809 void swap_where_only_one_has_value_and_t_is_not_void(
3810 expected &rhs, t_is_nothrow_move_constructible,
3811 move_constructing_e_can_throw) {
3812 auto temp = std::move(val());
3813 val().~T();
3814#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
3815 try {
3816 ::new (errptr()) unexpected_type(std::move(rhs.err()));
3817 rhs.err().~unexpected_type();
3818 ::new (rhs.valptr()) T(std::move(temp));
3819 std::swap(this->m_has_val, rhs.m_has_val);
3820 } catch (...) {
3821 val() = std::move(temp);
3822 throw;
3823 }
3824#else
3825 ::new (errptr()) unexpected_type(std::move(rhs.err()));
3826 rhs.err().~unexpected_type();
3827 ::new (rhs.valptr()) T(std::move(temp));
3828 std::swap(this->m_has_val, rhs.m_has_val);
3829#endif
3830 }
3831
3832 void swap_where_only_one_has_value_and_t_is_not_void(
3833 expected &rhs, move_constructing_t_can_throw,
3834 e_is_nothrow_move_constructible) {
3835 auto temp = std::move(rhs.err());
3836 rhs.err().~unexpected_type();
3837#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
3838 try {
3839 ::new (rhs.valptr()) T(std::move(val()));
3840 val().~T();
3841 ::new (errptr()) unexpected_type(std::move(temp));
3842 std::swap(this->m_has_val, rhs.m_has_val);
3843 } catch (...) {
3844 rhs.err() = std::move(temp);
3845 throw;
3846 }
3847#else
3848 ::new (rhs.valptr()) T(std::move(val()));
3849 val().~T();
3850 ::new (errptr()) unexpected_type(std::move(temp));
3851 std::swap(this->m_has_val, rhs.m_has_val);
3852#endif
3853 }
3854
3855 public:
3856 template <class OT = T, class OE = E>
3857 detail::enable_if_t<detail::is_swappable<OT>::value &&
3858 detail::is_swappable<OE>::value &&
3859 (std::is_nothrow_move_constructible<OT>::value ||
3860 std::is_nothrow_move_constructible<OE>::value)>
3861 swap(expected &rhs) noexcept(std::is_nothrow_move_constructible<T>::value &&
3863 std::is_nothrow_move_constructible<E>::value &&
3865 if (has_value() && rhs.has_value()) {
3866 swap_where_both_have_value(rhs, typename std::is_void<T>::type{});
3867 } else if (!has_value() && rhs.has_value()) {
3868 rhs.swap(*this);
3869 } else if (has_value()) {
3870 swap_where_only_one_has_value(rhs, typename std::is_void<T>::type{});
3871 } else {
3872 using std::swap;
3873 swap(err(), rhs.err());
3874 }
3875 }
3876
3877 constexpr const T *operator->() const {
3878 TL_ASSERT(has_value());
3879 return valptr();
3880 }
3882 TL_ASSERT(has_value());
3883 return valptr();
3884 }
3885
3886 template <class U = T,
3888 constexpr const U &operator*() const & {
3889 TL_ASSERT(has_value());
3890 return val();
3891 }
3892 template <class U = T,
3895 TL_ASSERT(has_value());
3896 return val();
3897 }
3898 template <class U = T,
3900 constexpr const U &&operator*() const && {
3901 TL_ASSERT(has_value());
3902 return std::move(val());
3903 }
3904 template <class U = T,
3907 TL_ASSERT(has_value());
3908 return std::move(val());
3909 }
3910
3911 constexpr bool has_value() const noexcept { return this->m_has_val; }
3912 constexpr explicit operator bool() const noexcept { return this->m_has_val; }
3913
3914 template <class U = T,
3916 TL_EXPECTED_11_CONSTEXPR const U &value() const & {
3917 if (!has_value())
3918 detail::throw_exception(bad_expected_access<E>(err().value()));
3919 return val();
3920 }
3921 template <class U = T,
3924 if (!has_value())
3925 detail::throw_exception(bad_expected_access<E>(err().value()));
3926 return val();
3927 }
3928 template <class U = T,
3930 TL_EXPECTED_11_CONSTEXPR const U &&value() const && {
3931 if (!has_value())
3932 detail::throw_exception(bad_expected_access<E>(std::move(err()).value()));
3933 return std::move(val());
3934 }
3935 template <class U = T,
3938 if (!has_value())
3939 detail::throw_exception(bad_expected_access<E>(std::move(err()).value()));
3940 return std::move(val());
3941 }
3942
3943 constexpr const E &error() const & {
3944 TL_ASSERT(!has_value());
3945 return err().value();
3946 }
3948 TL_ASSERT(!has_value());
3949 return err().value();
3950 }
3951 constexpr const E &&error() const && {
3952 TL_ASSERT(!has_value());
3953 return std::move(err().value());
3954 }
3956 TL_ASSERT(!has_value());
3957 return std::move(err().value());
3958 }
3959
3960 template <class U>
3961 constexpr T value_or(U &&v) const & {
3962 static_assert(std::is_copy_constructible<T>::value &&
3963 std::is_convertible<U &&, T>::value,
3964 "T must be copy-constructible and convertible to from U&&");
3965 return bool(*this) ? **this : static_cast<T>(std::forward<U>(v));
3966 }
3967 template <class U>
3969 static_assert(std::is_move_constructible<T>::value &&
3970 std::is_convertible<U &&, T>::value,
3971 "T must be move-constructible and convertible to from U&&");
3972 return bool(*this) ? std::move(**this) : static_cast<T>(std::forward<U>(v));
3973 }
3974};
3975
3976namespace detail {
3977template <class Exp>
3979template <class Exp>
3981template <class Exp, class Ret>
3983
3984#ifdef TL_EXPECTED_CXX14
3985template <class Exp, class F,
3987 class Ret = decltype(detail::invoke(std::declval<F>(),
3988 *std::declval<Exp>()))>
3989constexpr auto and_then_impl(Exp &&exp, F &&f) {
3990 static_assert(detail::is_expected<Ret>::value, "F must return an expected");
3991
3992 return exp.has_value()
3993 ? detail::invoke(std::forward<F>(f), *std::forward<Exp>(exp))
3994 : Ret(unexpect, std::forward<Exp>(exp).error());
3995}
3996
3997template <class Exp, class F,
3999 class Ret = decltype(detail::invoke(std::declval<F>()))>
4000constexpr auto and_then_impl(Exp &&exp, F &&f) {
4001 static_assert(detail::is_expected<Ret>::value, "F must return an expected");
4002
4003 return exp.has_value() ? detail::invoke(std::forward<F>(f))
4004 : Ret(unexpect, std::forward<Exp>(exp).error());
4005}
4006#else
4007template <class>
4008struct TC;
4009template <class Exp, class F,
4010 class Ret = decltype(detail::invoke(std::declval<F>(),
4011 *std::declval<Exp>())),
4012 detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr>
4013auto and_then_impl(Exp &&exp, F &&f) -> Ret {
4014 static_assert(detail::is_expected<Ret>::value, "F must return an expected");
4015
4016 return exp.has_value()
4017 ? detail::invoke(std::forward<F>(f), *std::forward<Exp>(exp))
4018 : Ret(unexpect, std::forward<Exp>(exp).error());
4019}
4020
4021template <class Exp, class F,
4022 class Ret = decltype(detail::invoke(std::declval<F>())),
4023 detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr>
4024constexpr auto and_then_impl(Exp &&exp, F &&f) -> Ret {
4025 static_assert(detail::is_expected<Ret>::value, "F must return an expected");
4026
4027 return exp.has_value() ? detail::invoke(std::forward<F>(f))
4028 : Ret(unexpect, std::forward<Exp>(exp).error());
4029}
4030#endif
4031
4032#ifdef TL_EXPECTED_CXX14
4033template <class Exp, class F,
4035 class Ret = decltype(detail::invoke(std::declval<F>(),
4036 *std::declval<Exp>())),
4037 detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
4038constexpr auto expected_map_impl(Exp &&exp, F &&f) {
4039 using result = ret_t<Exp, detail::decay_t<Ret>>;
4040 return exp.has_value() ? result(detail::invoke(std::forward<F>(f),
4041 *std::forward<Exp>(exp)))
4042 : result(unexpect, std::forward<Exp>(exp).error());
4043}
4044
4045template <class Exp, class F,
4046 detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
4047 class Ret = decltype(detail::invoke(std::declval<F>(),
4048 *std::declval<Exp>())),
4049 detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
4050auto expected_map_impl(Exp &&exp, F &&f) {
4051 using result = expected<void, err_t<Exp>>;
4052 if (exp.has_value()) {
4053 detail::invoke(std::forward<F>(f), *std::forward<Exp>(exp));
4054 return result();
4055 }
4056
4057 return result(unexpect, std::forward<Exp>(exp).error());
4058}
4059
4060template <class Exp, class F,
4061 detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
4062 class Ret = decltype(detail::invoke(std::declval<F>())),
4063 detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
4064constexpr auto expected_map_impl(Exp &&exp, F &&f) {
4065 using result = ret_t<Exp, detail::decay_t<Ret>>;
4066 return exp.has_value() ? result(detail::invoke(std::forward<F>(f)))
4067 : result(unexpect, std::forward<Exp>(exp).error());
4068}
4069
4070template <class Exp, class F,
4071 detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
4072 class Ret = decltype(detail::invoke(std::declval<F>())),
4073 detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
4074auto expected_map_impl(Exp &&exp, F &&f) {
4075 using result = expected<void, err_t<Exp>>;
4076 if (exp.has_value()) {
4077 detail::invoke(std::forward<F>(f));
4078 return result();
4079 }
4080
4081 return result(unexpect, std::forward<Exp>(exp).error());
4082}
4083#else
4084template <class Exp, class F,
4085 detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
4086 class Ret = decltype(detail::invoke(std::declval<F>(),
4087 *std::declval<Exp>())),
4088 detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
4089
4090constexpr auto expected_map_impl(Exp &&exp, F &&f)
4092 using result = ret_t<Exp, detail::decay_t<Ret>>;
4093
4094 return exp.has_value() ? result(detail::invoke(std::forward<F>(f),
4095 *std::forward<Exp>(exp)))
4096 : result(unexpect, std::forward<Exp>(exp).error());
4097}
4098
4099template <class Exp, class F,
4101 class Ret = decltype(detail::invoke(std::declval<F>(),
4102 *std::declval<Exp>())),
4103 detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
4104
4106 if (exp.has_value()) {
4107 detail::invoke(std::forward<F>(f), *std::forward<Exp>(exp));
4108 return {};
4109 }
4110
4111 return unexpected<err_t<Exp>>(std::forward<Exp>(exp).error());
4112}
4113
4114template <class Exp, class F,
4116 class Ret = decltype(detail::invoke(std::declval<F>())),
4117 detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
4118
4119constexpr auto expected_map_impl(Exp &&exp, F &&f)
4120 -> ret_t<Exp, detail::decay_t<Ret>> {
4121 using result = ret_t<Exp, detail::decay_t<Ret>>;
4122
4123 return exp.has_value() ? result(detail::invoke(std::forward<F>(f)))
4124 : result(unexpect, std::forward<Exp>(exp).error());
4125}
4126
4127template <class Exp, class F,
4128 detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
4129 class Ret = decltype(detail::invoke(std::declval<F>())),
4130 detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
4131
4132auto expected_map_impl(Exp &&exp, F &&f) -> expected<void, err_t<Exp>> {
4133 if (exp.has_value()) {
4134 detail::invoke(std::forward<F>(f));
4135 return {};
4136 }
4137
4138 return unexpected<err_t<Exp>>(std::forward<Exp>(exp).error());
4139}
4140#endif
4141
4142#if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \
4143 !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55)
4144template <class Exp, class F,
4145 detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
4146 class Ret = decltype(detail::invoke(std::declval<F>(),
4147 std::declval<Exp>().error())),
4148 detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
4149constexpr auto map_error_impl(Exp &&exp, F &&f) {
4150 using result = expected<exp_t<Exp>, detail::decay_t<Ret>>;
4151 return exp.has_value()
4152 ? result(*std::forward<Exp>(exp))
4153 : result(unexpect, detail::invoke(std::forward<F>(f),
4154 std::forward<Exp>(exp).error()));
4155}
4156template <class Exp, class F,
4157 detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
4158 class Ret = decltype(detail::invoke(std::declval<F>(),
4159 std::declval<Exp>().error())),
4160 detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
4161auto map_error_impl(Exp &&exp, F &&f) {
4162 using result = expected<exp_t<Exp>, monostate>;
4163 if (exp.has_value()) {
4164 return result(*std::forward<Exp>(exp));
4165 }
4166
4167 detail::invoke(std::forward<F>(f), std::forward<Exp>(exp).error());
4168 return result(unexpect, monostate{});
4169}
4170template <class Exp, class F,
4171 detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
4172 class Ret = decltype(detail::invoke(std::declval<F>(),
4173 std::declval<Exp>().error())),
4174 detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
4175constexpr auto map_error_impl(Exp &&exp, F &&f) {
4176 using result = expected<exp_t<Exp>, detail::decay_t<Ret>>;
4177 return exp.has_value()
4178 ? result()
4179 : result(unexpect, detail::invoke(std::forward<F>(f),
4180 std::forward<Exp>(exp).error()));
4181}
4182template <class Exp, class F,
4183 detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
4184 class Ret = decltype(detail::invoke(std::declval<F>(),
4185 std::declval<Exp>().error())),
4186 detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
4187auto map_error_impl(Exp &&exp, F &&f) {
4188 using result = expected<exp_t<Exp>, monostate>;
4189 if (exp.has_value()) {
4190 return result();
4191 }
4192
4193 detail::invoke(std::forward<F>(f), std::forward<Exp>(exp).error());
4194 return result(unexpect, monostate{});
4195}
4196#else
4197template <class Exp, class F,
4198 detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
4199 class Ret = decltype(detail::invoke(std::declval<F>(),
4200 std::declval<Exp>().error())),
4201 detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
4202constexpr auto map_error_impl(Exp &&exp, F &&f)
4205
4206 return exp.has_value()
4207 ? result(*std::forward<Exp>(exp))
4208 : result(unexpect, detail::invoke(std::forward<F>(f),
4209 std::forward<Exp>(exp).error()));
4210}
4211
4212template <class Exp, class F,
4214 class Ret = decltype(detail::invoke(std::declval<F>(),
4215 std::declval<Exp>().error())),
4216 detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
4217auto map_error_impl(Exp &&exp, F &&f) -> expected<exp_t<Exp>, monostate> {
4218 using result = expected<exp_t<Exp>, monostate>;
4219 if (exp.has_value()) {
4220 return result(*std::forward<Exp>(exp));
4221 }
4222
4223 detail::invoke(std::forward<F>(f), std::forward<Exp>(exp).error());
4224 return result(unexpect, monostate{});
4225}
4226
4227template <class Exp, class F,
4229 class Ret = decltype(detail::invoke(std::declval<F>(),
4230 std::declval<Exp>().error())),
4231 detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
4232constexpr auto map_error_impl(Exp &&exp, F &&f)
4235
4236 return exp.has_value()
4237 ? result()
4238 : result(unexpect, detail::invoke(std::forward<F>(f),
4239 std::forward<Exp>(exp).error()));
4240}
4241
4242template <class Exp, class F,
4243 detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
4244 class Ret = decltype(detail::invoke(std::declval<F>(),
4245 std::declval<Exp>().error())),
4246 detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
4247auto map_error_impl(Exp &&exp, F &&f) -> expected<exp_t<Exp>, monostate> {
4248 using result = expected<exp_t<Exp>, monostate>;
4249 if (exp.has_value()) {
4250 return result();
4251 }
4252
4253 detail::invoke(std::forward<F>(f), std::forward<Exp>(exp).error());
4254 return result(unexpect, monostate{});
4255}
4256#endif
4257
4258#ifdef TL_EXPECTED_CXX14
4259template <class Exp, class F,
4260 class Ret = decltype(detail::invoke(std::declval<F>(),
4261 std::declval<Exp>().error())),
4262 detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
4263constexpr auto or_else_impl(Exp &&exp, F &&f) {
4264 static_assert(detail::is_expected<Ret>::value, "F must return an expected");
4265 return exp.has_value() ? std::forward<Exp>(exp)
4266 : detail::invoke(std::forward<F>(f),
4267 std::forward<Exp>(exp).error());
4268}
4269
4270template <class Exp, class F,
4271 class Ret = decltype(detail::invoke(std::declval<F>(),
4272 std::declval<Exp>().error())),
4273 detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
4274detail::decay_t<Exp> or_else_impl(Exp &&exp, F &&f) {
4275 return exp.has_value() ? std::forward<Exp>(exp)
4276 : (detail::invoke(std::forward<F>(f),
4277 std::forward<Exp>(exp).error()),
4278 std::forward<Exp>(exp));
4279}
4280#else
4281template <class Exp, class F,
4282 class Ret = decltype(detail::invoke(std::declval<F>(),
4283 std::declval<Exp>().error())),
4284 detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
4285auto or_else_impl(Exp &&exp, F &&f) -> Ret {
4286 static_assert(detail::is_expected<Ret>::value, "F must return an expected");
4287 return exp.has_value() ? std::forward<Exp>(exp)
4288 : detail::invoke(std::forward<F>(f),
4289 std::forward<Exp>(exp).error());
4290}
4291
4292template <class Exp, class F,
4293 class Ret = decltype(detail::invoke(std::declval<F>(),
4294 std::declval<Exp>().error())),
4295 detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
4297 return exp.has_value() ? std::forward<Exp>(exp)
4298 : (detail::invoke(std::forward<F>(f),
4299 std::forward<Exp>(exp).error()),
4300 std::forward<Exp>(exp));
4301}
4302#endif
4303} // namespace detail
4304
4305template <class T, class E, class U, class F>
4306constexpr bool operator==(const expected<T, E> &lhs,
4307 const expected<U, F> &rhs) {
4308 return (lhs.has_value() != rhs.has_value())
4309 ? false
4310 : (!lhs.has_value() ? lhs.error() == rhs.error() : *lhs == *rhs);
4311}
4312template <class T, class E, class U, class F>
4313constexpr bool operator!=(const expected<T, E> &lhs,
4314 const expected<U, F> &rhs) {
4315 return (lhs.has_value() != rhs.has_value())
4316 ? true
4317 : (!lhs.has_value() ? lhs.error() != rhs.error() : *lhs != *rhs);
4318}
4319template <class E, class F>
4320constexpr bool operator==(const expected<void, E> &lhs,
4321 const expected<void, F> &rhs) {
4322 return (lhs.has_value() != rhs.has_value())
4323 ? false
4324 : (!lhs.has_value() ? lhs.error() == rhs.error() : true);
4325}
4326template <class E, class F>
4327constexpr bool operator!=(const expected<void, E> &lhs,
4328 const expected<void, F> &rhs) {
4329 return (lhs.has_value() != rhs.has_value())
4330 ? true
4331 : (!lhs.has_value() ? lhs.error() == rhs.error() : false);
4332}
4333
4334template <class T, class E, class U>
4335constexpr bool operator==(const expected<T, E> &x, const U &v) {
4336 return x.has_value() ? *x == v : false;
4337}
4338template <class T, class E, class U>
4339constexpr bool operator==(const U &v, const expected<T, E> &x) {
4340 return x.has_value() ? *x == v : false;
4341}
4342template <class T, class E, class U>
4343constexpr bool operator!=(const expected<T, E> &x, const U &v) {
4344 return x.has_value() ? *x != v : true;
4345}
4346template <class T, class E, class U>
4347constexpr bool operator!=(const U &v, const expected<T, E> &x) {
4348 return x.has_value() ? *x != v : true;
4349}
4350
4351template <class T, class E>
4352constexpr bool operator==(const expected<T, E> &x, const unexpected<E> &e) {
4353 return x.has_value() ? false : x.error() == e.value();
4354}
4355template <class T, class E>
4356constexpr bool operator==(const unexpected<E> &e, const expected<T, E> &x) {
4357 return x.has_value() ? false : x.error() == e.value();
4358}
4359template <class T, class E>
4360constexpr bool operator!=(const expected<T, E> &x, const unexpected<E> &e) {
4361 return x.has_value() ? true : x.error() != e.value();
4362}
4363template <class T, class E>
4364constexpr bool operator!=(const unexpected<E> &e, const expected<T, E> &x) {
4365 return x.has_value() ? true : x.error() != e.value();
4366}
4367
4368template <class T, class E,
4369 detail::enable_if_t<(std::is_void<T>::value ||
4370 std::is_move_constructible<T>::value) &&
4371 detail::is_swappable<T>::value &&
4372 std::is_move_constructible<E>::value &&
4373 detail::is_swappable<E>::value> * = nullptr>
4374void swap(expected<T, E> &lhs,
4375 expected<T, E> &rhs) noexcept(noexcept(lhs.swap(rhs))) {
4376 lhs.swap(rhs);
4377}
4378} // namespace tl
4379
4380#endif
4381/* end file include/ada/expected.h */
4382
4386namespace ada {
4387struct url_aggregator;
4388struct url;
4389} // namespace ada
4390
4395namespace ada::parser {
4402template <typename result_type = ada::url_aggregator>
4403result_type parse_url(std::string_view user_input,
4404 const result_type* base_url = nullptr);
4405
4406extern template url_aggregator parse_url<url_aggregator>(
4407 std::string_view user_input, const url_aggregator* base_url);
4408extern template url parse_url<url>(std::string_view user_input,
4409 const url* base_url);
4410
4411template <typename result_type = ada::url_aggregator, bool store_values = true>
4412result_type parse_url_impl(std::string_view user_input,
4413 const result_type* base_url = nullptr);
4414
4415extern template url_aggregator parse_url_impl<url_aggregator>(
4416 std::string_view user_input, const url_aggregator* base_url);
4417extern template url parse_url_impl<url>(std::string_view user_input,
4418 const url* base_url);
4419} // namespace ada::parser
4420
4421#endif // ADA_PARSER_H
4422/* end file include/ada/parser.h */
4423/* begin file include/ada/scheme-inl.h */
4428#ifndef ADA_SCHEME_INL_H
4429#define ADA_SCHEME_INL_H
4430
4431
4432namespace ada::scheme {
4433
4438namespace details {
4439// for use with is_special and get_special_port
4440// Spaces, if present, are removed from URL.
4441constexpr std::string_view is_special_list[] = {"http", " ", "https", "ws",
4442 "ftp", "wss", "file", " "};
4443// for use with get_special_port
4444constexpr uint16_t special_ports[] = {80, 0, 443, 80, 21, 443, 0, 0};
4445} // namespace details
4446
4447
4471ada_really_inline constexpr bool is_special(std::string_view scheme) {
4472 if (scheme.empty()) {
4473 return false;
4474 }
4475 int hash_value = (2 * scheme.size() + (unsigned)(scheme[0])) & 7;
4476 const std::string_view target = details::is_special_list[hash_value];
4477 return (target[0] == scheme[0]) && (target.substr(1) == scheme.substr(1));
4478}
4479constexpr uint16_t get_special_port(std::string_view scheme) noexcept {
4480 if (scheme.empty()) {
4481 return 0;
4482 }
4483 int hash_value = (2 * scheme.size() + (unsigned)(scheme[0])) & 7;
4484 const std::string_view target = details::is_special_list[hash_value];
4485 if ((target[0] == scheme[0]) && (target.substr(1) == scheme.substr(1))) {
4486 return details::special_ports[hash_value];
4487 } else {
4488 return 0;
4489 }
4490}
4491constexpr uint16_t get_special_port(ada::scheme::type type) noexcept {
4492 return details::special_ports[int(type)];
4493}
4494constexpr ada::scheme::type get_scheme_type(std::string_view scheme) noexcept {
4495 if (scheme.empty()) {
4497 }
4498 int hash_value = (2 * scheme.size() + (unsigned)(scheme[0])) & 7;
4499 const std::string_view target = details::is_special_list[hash_value];
4500 if ((target[0] == scheme[0]) && (target.substr(1) == scheme.substr(1))) {
4501 return ada::scheme::type(hash_value);
4502 } else {
4504 }
4505}
4506
4507} // namespace ada::scheme
4508
4509#endif // ADA_SCHEME_INL_H
4510/* end file include/ada/scheme-inl.h */
4511/* begin file include/ada/serializers.h */
4516#ifndef ADA_SERIALIZERS_H
4517#define ADA_SERIALIZERS_H
4518
4519
4520#include <array>
4521#include <optional>
4522#include <string>
4523
4528namespace ada::serializers {
4529
4533void find_longest_sequence_of_ipv6_pieces(
4534 const std::array<uint16_t, 8>& address, size_t& compress,
4535 size_t& compress_length) noexcept;
4536
4543std::string ipv6(const std::array<uint16_t, 8>& address) noexcept;
4544
4551std::string ipv4(uint64_t address) noexcept;
4552
4553} // namespace ada::serializers
4554
4555#endif // ADA_SERIALIZERS_H
4556/* end file include/ada/serializers.h */
4557/* begin file include/ada/unicode.h */
4562#ifndef ADA_UNICODE_H
4563#define ADA_UNICODE_H
4564
4565
4566#include <string>
4567#include <optional>
4568
4577namespace ada::unicode {
4578
4620bool to_ascii(std::optional<std::string>& out, std::string_view plain,
4621 size_t first_percent);
4622
4630ada_really_inline bool has_tabs_or_newline(
4631 std::string_view user_input) noexcept;
4632
4638ada_really_inline constexpr bool is_forbidden_host_code_point(char c) noexcept;
4639
4645ada_really_inline constexpr bool contains_forbidden_domain_code_point(
4646 const char* input, size_t length) noexcept;
4647
4655ada_really_inline constexpr uint8_t
4656contains_forbidden_domain_code_point_or_upper(const char* input,
4657 size_t length) noexcept;
4658
4664ada_really_inline constexpr bool is_forbidden_domain_code_point(
4665 char c) noexcept;
4666
4671ada_really_inline constexpr bool is_alnum_plus(char c) noexcept;
4672
4680ada_really_inline constexpr bool is_ascii_hex_digit(char c) noexcept;
4681
4690ada_really_inline constexpr bool is_c0_control_or_space(char c) noexcept;
4691
4698ada_really_inline constexpr bool is_ascii_tab_or_newline(char c) noexcept;
4699
4705ada_really_inline ada_constexpr bool is_double_dot_path_segment(
4706 std::string_view input) noexcept;
4707
4713ada_really_inline constexpr bool is_single_dot_path_segment(
4714 std::string_view input) noexcept;
4715
4720ada_really_inline constexpr bool is_lowercase_hex(char c) noexcept;
4721
4727ada_really_inline unsigned constexpr convert_hex_to_binary(char c) noexcept;
4728
4738std::string percent_decode(std::string_view input, size_t first_percent);
4739
4745std::string percent_encode(std::string_view input,
4746 const uint8_t character_set[]);
4753std::string percent_encode(std::string_view input,
4754 const uint8_t character_set[], size_t index);
4763template <bool append>
4764bool percent_encode(std::string_view input, const uint8_t character_set[],
4765 std::string& out);
4771ada_really_inline size_t percent_encode_index(std::string_view input,
4772 const uint8_t character_set[]);
4778constexpr bool to_lower_ascii(char* input, size_t length) noexcept;
4779} // namespace ada::unicode
4780
4781#endif // ADA_UNICODE_H
4782/* end file include/ada/unicode.h */
4783/* begin file include/ada/url_base-inl.h */
4788#ifndef ADA_URL_BASE_INL_H
4789#define ADA_URL_BASE_INL_H
4790
4791/* begin file include/ada/url_aggregator.h */
4796#ifndef ADA_URL_AGGREGATOR_H
4797#define ADA_URL_AGGREGATOR_H
4798
4799#include <string>
4800#include <string_view>
4801
4802
4803namespace ada {
4804
4814 url_aggregator() = default;
4815 url_aggregator(const url_aggregator &u) = default;
4816 url_aggregator(url_aggregator &&u) noexcept = default;
4817 url_aggregator &operator=(url_aggregator &&u) noexcept = default;
4819 ~url_aggregator() override = default;
4820
4821 bool set_href(std::string_view input);
4822 bool set_host(std::string_view input);
4823 bool set_hostname(std::string_view input);
4824 bool set_protocol(std::string_view input);
4825 bool set_username(std::string_view input);
4826 bool set_password(std::string_view input);
4827 bool set_port(std::string_view input);
4828 bool set_pathname(std::string_view input);
4829 void set_search(std::string_view input);
4830 void set_hash(std::string_view input);
4831
4832 [[nodiscard]] bool has_valid_domain() const noexcept override;
4839 [[nodiscard]] std::string get_origin() const noexcept override;
4848 [[nodiscard]] inline std::string_view get_href() const noexcept;
4855 [[nodiscard]] std::string_view get_username() const noexcept;
4862 [[nodiscard]] std::string_view get_password() const noexcept;
4869 [[nodiscard]] std::string_view get_port() const noexcept;
4876 [[nodiscard]] std::string_view get_hash() const noexcept;
4885 [[nodiscard]] std::string_view get_host() const noexcept;
4893 [[nodiscard]] std::string_view get_hostname() const noexcept;
4901 [[nodiscard]] std::string_view get_pathname() const noexcept;
4908 [[nodiscard]] ada_really_inline uint32_t get_pathname_length() const noexcept;
4915 [[nodiscard]] std::string_view get_search() const noexcept;
4923 [[nodiscard]] std::string_view get_protocol() const noexcept;
4924
4929 [[nodiscard]] ada_really_inline bool has_credentials() const noexcept;
4930
4952 [[nodiscard]] ada_really_inline const ada::url_components &get_components()
4953 const noexcept;
4957 [[nodiscard]] std::string to_string() const override;
4961 [[nodiscard]] std::string to_diagram() const;
4962
4968 [[nodiscard]] bool validate() const noexcept;
4969
4971 [[nodiscard]] inline bool has_empty_hostname() const noexcept;
4973 [[nodiscard]] inline bool has_hostname() const noexcept;
4975 [[nodiscard]] inline bool has_non_empty_username() const noexcept;
4977 [[nodiscard]] inline bool has_non_empty_password() const noexcept;
4979 [[nodiscard]] inline bool has_port() const noexcept;
4981 [[nodiscard]] inline bool has_password() const noexcept;
4983 [[nodiscard]] inline bool has_hash() const noexcept override;
4985 [[nodiscard]] inline bool has_search() const noexcept override;
4986
4987 inline void clear_port();
4988 inline void clear_hash();
4989 inline void clear_search() override;
4990
4991 private:
4992 friend ada::url_aggregator ada::parser::parse_url<ada::url_aggregator>(
4993 std::string_view, const ada::url_aggregator *);
4994 friend void ada::helpers::strip_trailing_spaces_from_opaque_path<
4995 ada::url_aggregator>(ada::url_aggregator &url) noexcept;
4996 friend ada::url_aggregator ada::parser::parse_url_impl<
4997 ada::url_aggregator, true>(std::string_view, const ada::url_aggregator *);
4999 ada::parser::parse_url_impl<ada::url_aggregator, false>(
5000 std::string_view, const ada::url_aggregator *);
5001
5002 std::string buffer{};
5003 url_components components{};
5004
5010 [[nodiscard]] ada_really_inline bool is_at_path() const noexcept;
5011
5012 inline void add_authority_slashes_if_needed() noexcept;
5013
5018 inline void reserve(uint32_t capacity);
5019
5020 ada_really_inline size_t parse_port(
5021 std::string_view view, bool check_trailing_content) noexcept override;
5022
5023 ada_really_inline size_t parse_port(std::string_view view) noexcept override {
5024 return this->parse_port(view, false);
5025 }
5026
5033 [[nodiscard]] bool parse_ipv4(std::string_view input, bool in_place);
5034
5039 [[nodiscard]] bool parse_ipv6(std::string_view input);
5040
5045 [[nodiscard]] bool parse_opaque_host(std::string_view input);
5046
5047 ada_really_inline void parse_path(std::string_view input);
5048
5053 [[nodiscard]] inline bool cannot_have_credentials_or_port() const;
5054
5055 template <bool override_hostname = false>
5056 bool set_host_or_hostname(std::string_view input);
5057
5058 ada_really_inline bool parse_host(std::string_view input);
5059
5060 inline void update_base_authority(std::string_view base_buffer,
5061 const ada::url_components &base);
5062 inline void update_unencoded_base_hash(std::string_view input);
5063 inline void update_base_hostname(std::string_view input);
5064 inline void update_base_search(std::string_view input);
5065 inline void update_base_search(std::string_view input,
5066 const uint8_t *query_percent_encode_set);
5067 inline void update_base_pathname(std::string_view input);
5068 inline void update_base_username(std::string_view input);
5069 inline void append_base_username(std::string_view input);
5070 inline void update_base_password(std::string_view input);
5071 inline void append_base_password(std::string_view input);
5072 inline void update_base_port(uint32_t input);
5073 inline void append_base_pathname(std::string_view input);
5074 [[nodiscard]] inline uint32_t retrieve_base_port() const;
5075 inline void clear_hostname();
5076 inline void clear_password();
5077 inline void clear_pathname() override;
5078 [[nodiscard]] inline bool has_dash_dot() const noexcept;
5079 void delete_dash_dot();
5080 inline void consume_prepared_path(std::string_view input);
5081 template <bool has_state_override = false>
5082 [[nodiscard]] ada_really_inline bool parse_scheme_with_colon(
5083 std::string_view input);
5084 ada_really_inline uint32_t replace_and_resize(uint32_t start, uint32_t end,
5085 std::string_view input);
5086 [[nodiscard]] inline bool has_authority() const noexcept;
5087 inline void set_protocol_as_file();
5088 inline void set_scheme(std::string_view new_scheme) noexcept;
5093 inline void set_scheme_from_view_with_colon(
5094 std::string_view new_scheme_with_colon) noexcept;
5095 inline void copy_scheme(const url_aggregator &u) noexcept;
5096
5097}; // url_aggregator
5098
5099inline std::ostream &operator<<(std::ostream &out, const ada::url &u);
5100} // namespace ada
5101
5102#endif
5103/* end file include/ada/url_aggregator.h */
5104/* begin file include/ada/checkers.h */
5109#ifndef ADA_CHECKERS_H
5110#define ADA_CHECKERS_H
5111
5112
5113#include <string_view>
5114#include <cstring>
5115
5123namespace ada::checkers {
5124
5131constexpr char to_lower(char x) noexcept;
5132
5140constexpr bool is_alpha(char x) noexcept;
5141
5149inline bool has_hex_prefix_unsafe(std::string_view input);
5154inline bool has_hex_prefix(std::string_view input);
5155
5161constexpr bool is_digit(char x) noexcept;
5162
5175inline constexpr bool is_windows_drive_letter(std::string_view input) noexcept;
5176
5182inline constexpr bool is_normalized_windows_drive_letter(
5183 std::string_view input) noexcept;
5184
5189ada_really_inline bool begins_with(std::string_view view,
5190 std::string_view prefix);
5191
5198ada_really_inline ada_constexpr bool is_ipv4(std::string_view view) noexcept;
5199
5207ada_really_inline constexpr uint8_t path_signature(
5208 std::string_view input) noexcept;
5209
5221ada_really_inline constexpr bool verify_dns_length(
5222 std::string_view input) noexcept;
5223
5224} // namespace ada::checkers
5225
5226#endif // ADA_CHECKERS_H
5227/* end file include/ada/checkers.h */
5228/* begin file include/ada/url.h */
5233#ifndef ADA_URL_H
5234#define ADA_URL_H
5235
5236#include <algorithm>
5237#include <charconv>
5238#include <iostream>
5239#include <optional>
5240#include <string>
5241#include <string_view>
5242
5243
5244namespace ada {
5245
5258struct url : url_base {
5259 url() = default;
5260 url(const url &u) = default;
5261 url(url &&u) noexcept = default;
5262 url &operator=(url &&u) noexcept = default;
5263 url &operator=(const url &u) = default;
5264 ~url() override = default;
5265
5271 std::string username{};
5272
5278 std::string password{};
5279
5284 std::optional<std::string> host{};
5285
5291 std::optional<uint16_t> port{};
5292
5298 std::string path{};
5299
5304 std::optional<std::string> query{};
5305
5312 std::optional<std::string> hash{};
5313
5315 [[nodiscard]] inline bool has_empty_hostname() const noexcept;
5317 [[nodiscard]] inline bool has_port() const noexcept;
5319 [[nodiscard]] inline bool has_hostname() const noexcept;
5320 [[nodiscard]] bool has_valid_domain() const noexcept override;
5321
5325 [[nodiscard]] std::string to_string() const override;
5326
5331 [[nodiscard]] ada_really_inline std::string get_href() const noexcept;
5332
5339 [[nodiscard]] std::string get_origin() const noexcept override;
5340
5347 [[nodiscard]] std::string get_protocol() const noexcept;
5348
5356 [[nodiscard]] std::string get_host() const noexcept;
5357
5364 [[nodiscard]] std::string get_hostname() const noexcept;
5365
5372 [[nodiscard]] std::string_view get_pathname() const noexcept;
5373
5380 [[nodiscard]] ada_really_inline size_t get_pathname_length() const noexcept;
5381
5387 [[nodiscard]] std::string get_search() const noexcept;
5388
5394 [[nodiscard]] const std::string &get_username() const noexcept;
5395
5400 bool set_username(std::string_view input);
5401
5406 bool set_password(std::string_view input);
5407
5412 bool set_port(std::string_view input);
5413
5418 void set_hash(std::string_view input);
5419
5424 void set_search(std::string_view input);
5425
5430 bool set_pathname(std::string_view input);
5431
5436 bool set_host(std::string_view input);
5437
5442 bool set_hostname(std::string_view input);
5443
5448 bool set_protocol(std::string_view input);
5449
5453 bool set_href(std::string_view input);
5454
5460 [[nodiscard]] const std::string &get_password() const noexcept;
5461
5467 [[nodiscard]] std::string get_port() const noexcept;
5468
5474 [[nodiscard]] std::string get_hash() const noexcept;
5475
5480 [[nodiscard]] ada_really_inline bool has_credentials() const noexcept;
5481
5503 [[nodiscard]] ada_really_inline ada::url_components get_components()
5504 const noexcept;
5506 [[nodiscard]] inline bool has_hash() const noexcept override;
5508 [[nodiscard]] inline bool has_search() const noexcept override;
5509
5510 private:
5511 friend ada::url ada::parser::parse_url<ada::url>(std::string_view,
5512 const ada::url *);
5513 friend ada::url_aggregator ada::parser::parse_url<ada::url_aggregator>(
5514 std::string_view, const ada::url_aggregator *);
5515 friend void ada::helpers::strip_trailing_spaces_from_opaque_path<ada::url>(
5516 ada::url &url) noexcept;
5517
5518 friend ada::url ada::parser::parse_url_impl<ada::url, true>(std::string_view,
5519 const ada::url *);
5520 friend ada::url_aggregator ada::parser::parse_url_impl<
5521 ada::url_aggregator, true>(std::string_view, const ada::url_aggregator *);
5522
5523 inline void update_unencoded_base_hash(std::string_view input);
5524 inline void update_base_hostname(std::string_view input);
5525 inline void update_base_search(std::string_view input);
5526 inline void update_base_search(std::string_view input,
5527 const uint8_t query_percent_encode_set[]);
5528 inline void update_base_search(std::optional<std::string> input);
5529 inline void update_base_pathname(std::string_view input);
5530 inline void update_base_username(std::string_view input);
5531 inline void update_base_password(std::string_view input);
5532 inline void update_base_port(std::optional<uint16_t> input);
5533
5539 template <bool override_hostname = false>
5540 bool set_host_or_hostname(std::string_view input);
5541
5546 [[nodiscard]] bool parse_ipv4(std::string_view input);
5547
5552 [[nodiscard]] bool parse_ipv6(std::string_view input);
5553
5558 [[nodiscard]] bool parse_opaque_host(std::string_view input);
5559
5569 std::string non_special_scheme{};
5570
5575 [[nodiscard]] inline bool cannot_have_credentials_or_port() const;
5576
5577 ada_really_inline size_t parse_port(
5578 std::string_view view, bool check_trailing_content) noexcept override;
5579
5580 ada_really_inline size_t parse_port(std::string_view view) noexcept override {
5581 return this->parse_port(view, false);
5582 }
5583
5588 inline void copy_scheme(const ada::url &u);
5589
5598 [[nodiscard]] ada_really_inline bool parse_host(std::string_view input);
5599
5600 template <bool has_state_override = false>
5601 [[nodiscard]] ada_really_inline bool parse_scheme(std::string_view input);
5602
5603 inline void clear_pathname() override;
5604 inline void clear_search() override;
5605 inline void set_protocol_as_file();
5606
5617 ada_really_inline void parse_path(std::string_view input);
5618
5624 inline void set_scheme(std::string &&new_scheme) noexcept;
5625
5630 inline void copy_scheme(ada::url &&u) noexcept;
5631
5632}; // struct url
5633
5634inline std::ostream &operator<<(std::ostream &out, const ada::url &u);
5635} // namespace ada
5636
5637#endif // ADA_URL_H
5638/* end file include/ada/url.h */
5639
5640#include <optional>
5641#include <string>
5642#if ADA_REGULAR_VISUAL_STUDIO
5643#include <intrin.h>
5644#endif // ADA_REGULAR_VISUAL_STUDIO
5645
5646namespace ada {
5647
5648[[nodiscard]] ada_really_inline bool url_base::is_special() const noexcept {
5650}
5651
5652[[nodiscard]] inline uint16_t url_base::get_special_port() const noexcept {
5653 return ada::scheme::get_special_port(type);
5654}
5655
5656[[nodiscard]] ada_really_inline uint16_t
5657url_base::scheme_default_port() const noexcept {
5658 return scheme::get_special_port(type);
5659}
5660
5661} // namespace ada
5662
5663#endif // ADA_URL_BASE_INL_H
5664/* end file include/ada/url_base-inl.h */
5665/* begin file include/ada/url-inl.h */
5670#ifndef ADA_URL_INL_H
5671#define ADA_URL_INL_H
5672
5673
5674#include <optional>
5675#include <string>
5676#if ADA_REGULAR_VISUAL_STUDIO
5677#include <intrin.h>
5678#endif // ADA_REGULAR_VISUAL_STUDIO
5679
5680namespace ada {
5681[[nodiscard]] ada_really_inline bool url::has_credentials() const noexcept {
5682 return !username.empty() || !password.empty();
5683}
5684[[nodiscard]] ada_really_inline bool url::has_port() const noexcept {
5685 return port.has_value();
5686}
5687[[nodiscard]] inline bool url::cannot_have_credentials_or_port() const {
5688 return !host.has_value() || host.value().empty() ||
5689 type == ada::scheme::type::FILE;
5690}
5691[[nodiscard]] inline bool url::has_empty_hostname() const noexcept {
5692 if (!host.has_value()) {
5693 return false;
5694 }
5695 return host.value().empty();
5696}
5697[[nodiscard]] inline bool url::has_hostname() const noexcept {
5698 return host.has_value();
5699}
5700inline std::ostream &operator<<(std::ostream &out, const ada::url &u) {
5701 return out << u.to_string();
5702}
5703
5704[[nodiscard]] size_t url::get_pathname_length() const noexcept {
5705 return path.size();
5706}
5707
5708[[nodiscard]] ada_really_inline ada::url_components url::get_components()
5709 const noexcept {
5710 url_components out{};
5711
5712 // protocol ends with ':'. for example: "https:"
5713 out.protocol_end = uint32_t(get_protocol().size());
5714
5715 // Trailing index is always the next character of the current one.
5716 size_t running_index = out.protocol_end;
5717
5718 if (host.has_value()) {
5719 // 2 characters for "//" and 1 character for starting index
5720 out.host_start = out.protocol_end + 2;
5721
5722 if (has_credentials()) {
5723 out.username_end = uint32_t(out.host_start + username.size());
5724
5725 out.host_start += uint32_t(username.size());
5726
5727 if (!password.empty()) {
5728 out.host_start += uint32_t(password.size() + 1);
5729 }
5730
5731 out.host_end = uint32_t(out.host_start + host.value().size());
5732 } else {
5733 out.username_end = out.host_start;
5734
5735 // Host does not start with "@" if it does not include credentials.
5736 out.host_end = uint32_t(out.host_start + host.value().size()) - 1;
5737 }
5738
5739 running_index = out.host_end + 1;
5740 } else {
5741 // Update host start and end date to the same index, since it does not
5742 // exist.
5743 out.host_start = out.protocol_end;
5744 out.host_end = out.host_start;
5745
5746 if (!has_opaque_path && checkers::begins_with(path, "//")) {
5747 // If url's host is null, url does not have an opaque path, url's path's
5748 // size is greater than 1, and url's path[0] is the empty string, then
5749 // append U+002F (/) followed by U+002E (.) to output.
5750 running_index = out.protocol_end + 2;
5751 } else {
5752 running_index = out.protocol_end;
5753 }
5754 }
5755
5756 if (port.has_value()) {
5757 out.port = *port;
5758 running_index += helpers::fast_digit_count(*port) + 1; // Port omits ':'
5759 }
5760
5761 out.pathname_start = uint32_t(running_index);
5762
5763 running_index += path.size();
5764
5765 if (query.has_value()) {
5766 out.search_start = uint32_t(running_index);
5767 running_index += get_search().size();
5768 if (get_search().empty()) {
5769 running_index++;
5770 }
5771 }
5772
5773 if (hash.has_value()) {
5774 out.hash_start = uint32_t(running_index);
5775 }
5776
5777 return out;
5778}
5779
5780inline void url::update_base_hostname(std::string_view input) { host = input; }
5781
5782inline void url::update_unencoded_base_hash(std::string_view input) {
5783 // We do the percent encoding
5784 hash = unicode::percent_encode(input,
5786}
5787
5788inline void url::update_base_search(std::string_view input,
5789 const uint8_t query_percent_encode_set[]) {
5790 query = ada::unicode::percent_encode(input, query_percent_encode_set);
5791}
5792
5793inline void url::update_base_search(std::optional<std::string> input) {
5794 query = input;
5795}
5796
5797inline void url::update_base_pathname(const std::string_view input) {
5798 path = input;
5799}
5800
5801inline void url::update_base_username(const std::string_view input) {
5802 username = input;
5803}
5804
5805inline void url::update_base_password(const std::string_view input) {
5806 password = input;
5807}
5808
5809inline void url::update_base_port(std::optional<uint16_t> input) {
5810 port = input;
5811}
5812
5813inline void url::clear_pathname() { path.clear(); }
5814
5815inline void url::clear_search() { query = std::nullopt; }
5816
5817[[nodiscard]] inline bool url::has_hash() const noexcept {
5818 return hash.has_value();
5819}
5820
5821[[nodiscard]] inline bool url::has_search() const noexcept {
5822 return query.has_value();
5823}
5824
5825inline void url::set_protocol_as_file() { type = ada::scheme::type::FILE; }
5826
5827inline void url::set_scheme(std::string &&new_scheme) noexcept {
5828 type = ada::scheme::get_scheme_type(new_scheme);
5829 // We only move the 'scheme' if it is non-special.
5830 if (!is_special()) {
5831 non_special_scheme = new_scheme;
5832 }
5833}
5834
5835inline void url::copy_scheme(ada::url &&u) noexcept {
5836 non_special_scheme = u.non_special_scheme;
5837 type = u.type;
5838}
5839
5840inline void url::copy_scheme(const ada::url &u) {
5841 non_special_scheme = u.non_special_scheme;
5842 type = u.type;
5843}
5844
5845[[nodiscard]] ada_really_inline std::string url::get_href() const noexcept {
5846 std::string output = get_protocol();
5847
5848 if (host.has_value()) {
5849 output += "//";
5850 if (has_credentials()) {
5851 output += username;
5852 if (!password.empty()) {
5853 output += ":" + get_password();
5854 }
5855 output += "@";
5856 }
5857 output += host.value();
5858 if (port.has_value()) {
5859 output += ":" + get_port();
5860 }
5861 } else if (!has_opaque_path && checkers::begins_with(path, "//")) {
5862 // If url's host is null, url does not have an opaque path, url's path's
5863 // size is greater than 1, and url's path[0] is the empty string, then
5864 // append U+002F (/) followed by U+002E (.) to output.
5865 output += "/.";
5866 }
5867 output += path;
5868 if (query.has_value()) {
5869 output += "?" + query.value();
5870 }
5871 if (hash.has_value()) {
5872 output += "#" + hash.value();
5873 }
5874 return output;
5875}
5876
5877ada_really_inline size_t url::parse_port(std::string_view view,
5878 bool check_trailing_content) noexcept {
5879 ada_log("parse_port('", view, "') ", view.size());
5880 uint16_t parsed_port{};
5881 auto r = std::from_chars(view.data(), view.data() + view.size(), parsed_port);
5882 if (r.ec == std::errc::result_out_of_range) {
5883 ada_log("parse_port: std::errc::result_out_of_range");
5884 is_valid = false;
5885 return 0;
5886 }
5887 ada_log("parse_port: ", parsed_port);
5888 const size_t consumed = size_t(r.ptr - view.data());
5889 ada_log("parse_port: consumed ", consumed);
5890 if (check_trailing_content) {
5891 is_valid &=
5892 (consumed == view.size() || view[consumed] == '/' ||
5893 view[consumed] == '?' || (is_special() && view[consumed] == '\\'));
5894 }
5895 ada_log("parse_port: is_valid = ", is_valid);
5896 if (is_valid) {
5897 // scheme_default_port can return 0, and we should allow 0 as a base port.
5898 auto default_port = scheme_default_port();
5899 bool is_port_valid = (default_port == 0 && parsed_port == 0) ||
5900 (default_port != parsed_port);
5901 port = (r.ec == std::errc() && is_port_valid)
5902 ? std::optional<uint16_t>(parsed_port)
5903 : std::nullopt;
5904 }
5905 return consumed;
5906}
5907
5908} // namespace ada
5909
5910#endif // ADA_URL_H
5911/* end file include/ada/url-inl.h */
5912/* begin file include/ada/url_aggregator-inl.h */
5917#ifndef ADA_URL_AGGREGATOR_INL_H
5918#define ADA_URL_AGGREGATOR_INL_H
5919
5920/* begin file include/ada/unicode-inl.h */
5925#ifndef ADA_UNICODE_INL_H
5926#define ADA_UNICODE_INL_H
5927#include <algorithm>
5928
5937namespace ada::unicode {
5938ada_really_inline size_t percent_encode_index(const std::string_view input,
5939 const uint8_t character_set[]) {
5940 return std::distance(
5941 input.begin(),
5942 std::find_if(input.begin(), input.end(), [character_set](const char c) {
5943 return character_sets::bit_at(character_set, c);
5944 }));
5945}
5946} // namespace ada::unicode
5947
5948#endif // ADA_UNICODE_INL_H
5949/* end file include/ada/unicode-inl.h */
5950
5951#include <optional>
5952#include <string_view>
5953
5954namespace ada {
5955
5956inline void url_aggregator::update_base_authority(
5957 std::string_view base_buffer, const ada::url_components &base) {
5958 std::string_view input = base_buffer.substr(
5959 base.protocol_end, base.host_start - base.protocol_end);
5960 ada_log("url_aggregator::update_base_authority ", input);
5961
5962 bool input_starts_with_dash = checkers::begins_with(input, "//");
5963 uint32_t diff = components.host_start - components.protocol_end;
5964
5965 buffer.erase(components.protocol_end,
5966 components.host_start - components.protocol_end);
5967 components.username_end = components.protocol_end;
5968
5969 if (input_starts_with_dash) {
5970 input.remove_prefix(2);
5971 diff += 2; // add "//"
5972 buffer.insert(components.protocol_end, "//");
5973 components.username_end += 2;
5974 }
5975
5976 size_t password_delimiter = input.find(':');
5977
5978 // Check if input contains both username and password by checking the
5979 // delimiter: ":" A typical input that contains authority would be "user:pass"
5980 if (password_delimiter != std::string_view::npos) {
5981 // Insert both username and password
5982 std::string_view username = input.substr(0, password_delimiter);
5983 std::string_view password = input.substr(password_delimiter + 1);
5984
5985 buffer.insert(components.protocol_end + diff, username);
5986 diff += uint32_t(username.size());
5987 buffer.insert(components.protocol_end + diff, ":");
5988 components.username_end = components.protocol_end + diff;
5989 buffer.insert(components.protocol_end + diff + 1, password);
5990 diff += uint32_t(password.size()) + 1;
5991 } else if (!input.empty()) {
5992 // Insert only username
5993 buffer.insert(components.protocol_end + diff, input);
5994 components.username_end =
5995 components.protocol_end + diff + uint32_t(input.size());
5996 diff += uint32_t(input.size());
5997 }
5998
5999 components.host_start += diff;
6000
6001 if (buffer.size() > base.host_start && buffer[base.host_start] != '@') {
6002 buffer.insert(components.host_start, "@");
6003 diff++;
6004 }
6005 components.host_end += diff;
6006 components.pathname_start += diff;
6007 if (components.search_start != url_components::omitted) {
6008 components.search_start += diff;
6009 }
6010 if (components.hash_start != url_components::omitted) {
6011 components.hash_start += diff;
6012 }
6013}
6014
6015inline void url_aggregator::update_unencoded_base_hash(std::string_view input) {
6016 ada_log("url_aggregator::update_unencoded_base_hash ", input, " [",
6017 input.size(), " bytes], buffer is '", buffer, "' [", buffer.size(),
6018 " bytes] components.hash_start = ", components.hash_start);
6019 ADA_ASSERT_TRUE(validate());
6020 ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
6021 if (components.hash_start != url_components::omitted) {
6022 buffer.resize(components.hash_start);
6023 }
6024 components.hash_start = uint32_t(buffer.size());
6025 buffer += "#";
6026 bool encoding_required = unicode::percent_encode<true>(
6028 // When encoding_required is false, then buffer is left unchanged, and percent
6029 // encoding was not deemed required.
6030 if (!encoding_required) {
6031 buffer.append(input);
6032 }
6033 ada_log("url_aggregator::update_unencoded_base_hash final buffer is '",
6034 buffer, "' [", buffer.size(), " bytes]");
6035 ADA_ASSERT_TRUE(validate());
6036}
6037
6038ada_really_inline uint32_t url_aggregator::replace_and_resize(
6039 uint32_t start, uint32_t end, std::string_view input) {
6040 uint32_t current_length = end - start;
6041 uint32_t input_size = uint32_t(input.size());
6042 uint32_t new_difference = input_size - current_length;
6043
6044 if (current_length == 0) {
6045 buffer.insert(start, input);
6046 } else if (input_size == current_length) {
6047 buffer.replace(start, input_size, input);
6048 } else if (input_size < current_length) {
6049 buffer.erase(start, current_length - input_size);
6050 buffer.replace(start, input_size, input);
6051 } else {
6052 buffer.replace(start, current_length, input.substr(0, current_length));
6053 buffer.insert(start + current_length, input.substr(current_length));
6054 }
6055
6056 return new_difference;
6057}
6058
6059inline void url_aggregator::update_base_hostname(const std::string_view input) {
6060 ada_log("url_aggregator::update_base_hostname ", input, " [", input.size(),
6061 " bytes], buffer is '", buffer, "' [", buffer.size(), " bytes]");
6062 ADA_ASSERT_TRUE(validate());
6063 ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
6064
6065 // This next line is required for when parsing a URL like `foo://`
6066 add_authority_slashes_if_needed();
6067
6068 bool has_credentials = components.protocol_end + 2 < components.host_start;
6069 uint32_t new_difference =
6070 replace_and_resize(components.host_start, components.host_end, input);
6071
6072 if (has_credentials) {
6073 buffer.insert(components.host_start, "@");
6074 new_difference++;
6075 }
6076 components.host_end += new_difference;
6077 components.pathname_start += new_difference;
6078 if (components.search_start != url_components::omitted) {
6079 components.search_start += new_difference;
6080 }
6081 if (components.hash_start != url_components::omitted) {
6082 components.hash_start += new_difference;
6083 }
6084 ADA_ASSERT_TRUE(validate());
6085}
6086
6087[[nodiscard]] ada_really_inline uint32_t
6088url_aggregator::get_pathname_length() const noexcept {
6089 ada_log("url_aggregator::get_pathname_length");
6090 uint32_t ending_index = uint32_t(buffer.size());
6091 if (components.search_start != url_components::omitted) {
6092 ending_index = components.search_start;
6093 } else if (components.hash_start != url_components::omitted) {
6094 ending_index = components.hash_start;
6095 }
6096 return ending_index - components.pathname_start;
6097}
6098
6099[[nodiscard]] ada_really_inline bool url_aggregator::is_at_path()
6100 const noexcept {
6101 return buffer.size() == components.pathname_start;
6102}
6103
6104inline void url_aggregator::update_base_search(std::string_view input) {
6105 ada_log("url_aggregator::update_base_search ", input);
6106 ADA_ASSERT_TRUE(validate());
6107 ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
6108 if (input.empty()) {
6109 clear_search();
6110 return;
6111 }
6112
6113 if (input[0] == '?') {
6114 input.remove_prefix(1);
6115 }
6116
6117 if (components.hash_start == url_components::omitted) {
6118 if (components.search_start == url_components::omitted) {
6119 components.search_start = uint32_t(buffer.size());
6120 buffer += "?";
6121 } else {
6122 buffer.resize(components.search_start + 1);
6123 }
6124
6125 buffer.append(input);
6126 } else {
6127 if (components.search_start == url_components::omitted) {
6128 components.search_start = components.hash_start;
6129 } else {
6130 buffer.erase(components.search_start,
6131 components.hash_start - components.search_start);
6132 components.hash_start = components.search_start;
6133 }
6134
6135 buffer.insert(components.search_start, "?");
6136 buffer.insert(components.search_start + 1, input);
6137 components.hash_start += uint32_t(input.size() + 1); // Do not forget `?`
6138 }
6139
6140 ADA_ASSERT_TRUE(validate());
6141}
6142
6143inline void url_aggregator::update_base_search(
6144 std::string_view input, const uint8_t query_percent_encode_set[]) {
6145 ada_log("url_aggregator::update_base_search ", input,
6146 " with encoding parameter ", to_string(), "\n", to_diagram());
6147 ADA_ASSERT_TRUE(validate());
6148 ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
6149
6150 if (components.hash_start == url_components::omitted) {
6151 if (components.search_start == url_components::omitted) {
6152 components.search_start = uint32_t(buffer.size());
6153 buffer += "?";
6154 } else {
6155 buffer.resize(components.search_start + 1);
6156 }
6157
6158 bool encoding_required =
6159 unicode::percent_encode<true>(input, query_percent_encode_set, buffer);
6160 // When encoding_required is false, then buffer is left unchanged, and
6161 // percent encoding was not deemed required.
6162 if (!encoding_required) {
6163 buffer.append(input);
6164 }
6165 } else {
6166 if (components.search_start == url_components::omitted) {
6167 components.search_start = components.hash_start;
6168 } else {
6169 buffer.erase(components.search_start,
6170 components.hash_start - components.search_start);
6171 components.hash_start = components.search_start;
6172 }
6173
6174 buffer.insert(components.search_start, "?");
6175 size_t idx =
6176 ada::unicode::percent_encode_index(input, query_percent_encode_set);
6177 if (idx == input.size()) {
6178 buffer.insert(components.search_start + 1, input);
6179 components.hash_start += uint32_t(input.size() + 1); // Do not forget `?`
6180 } else {
6181 buffer.insert(components.search_start + 1, input, 0, idx);
6182 input.remove_prefix(idx);
6183 // We only create a temporary string if we need percent encoding and
6184 // we attempt to create as small a temporary string as we can.
6185 std::string encoded =
6186 ada::unicode::percent_encode(input, query_percent_encode_set);
6187 buffer.insert(components.search_start + idx + 1, encoded);
6188 components.hash_start +=
6189 uint32_t(encoded.size() + idx + 1); // Do not forget `?`
6190 }
6191 }
6192
6193 ADA_ASSERT_TRUE(validate());
6194}
6195
6196inline void url_aggregator::update_base_pathname(const std::string_view input) {
6197 ada_log("url_aggregator::update_base_pathname '", input, "' [", input.size(),
6198 " bytes] \n", to_diagram());
6199 ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
6200 ADA_ASSERT_TRUE(validate());
6201
6202 const bool begins_with_dashdash = checkers::begins_with(input, "//");
6203 if (!begins_with_dashdash && has_dash_dot()) {
6204 ada_log("url_aggregator::update_base_pathname has /.: \n", to_diagram());
6205 // We must delete the ./
6206 delete_dash_dot();
6207 }
6208
6209 if (begins_with_dashdash && !has_opaque_path && !has_authority() &&
6210 !has_dash_dot()) {
6211 // If url's host is null, url does not have an opaque path, url's path's
6212 // size is greater than 1, then append U+002F (/) followed by U+002E (.) to
6213 // output.
6214 buffer.insert(components.pathname_start, "/.");
6215 components.pathname_start += 2;
6216 }
6217
6218 uint32_t difference = replace_and_resize(
6219 components.pathname_start,
6220 components.pathname_start + get_pathname_length(), input);
6221 if (components.search_start != url_components::omitted) {
6222 components.search_start += difference;
6223 }
6224 if (components.hash_start != url_components::omitted) {
6225 components.hash_start += difference;
6226 }
6227 ada_log("url_aggregator::update_base_pathname end '", input, "' [",
6228 input.size(), " bytes] \n", to_diagram());
6229 ADA_ASSERT_TRUE(validate());
6230}
6231
6232inline void url_aggregator::append_base_pathname(const std::string_view input) {
6233 ada_log("url_aggregator::append_base_pathname ", input, " ", to_string(),
6234 "\n", to_diagram());
6235 ADA_ASSERT_TRUE(validate());
6236 ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
6237#if ADA_DEVELOPMENT_CHECKS
6238 // computing the expected password.
6239 std::string path_expected(get_pathname());
6240 path_expected.append(input);
6241#endif // ADA_DEVELOPMENT_CHECKS
6242 uint32_t ending_index = uint32_t(buffer.size());
6243 if (components.search_start != url_components::omitted) {
6244 ending_index = components.search_start;
6245 } else if (components.hash_start != url_components::omitted) {
6246 ending_index = components.hash_start;
6247 }
6248 buffer.insert(ending_index, input);
6249
6250 if (components.search_start != url_components::omitted) {
6251 components.search_start += uint32_t(input.size());
6252 }
6253 if (components.hash_start != url_components::omitted) {
6254 components.hash_start += uint32_t(input.size());
6255 }
6256#if ADA_DEVELOPMENT_CHECKS
6257 std::string path_after = std::string(get_pathname());
6259 path_expected, path_after,
6260 "append_base_pathname problem after inserting " + std::string(input));
6261#endif // ADA_DEVELOPMENT_CHECKS
6262 ADA_ASSERT_TRUE(validate());
6263}
6264
6265inline void url_aggregator::update_base_username(const std::string_view input) {
6266 ada_log("url_aggregator::update_base_username '", input, "' ", to_string(),
6267 "\n", to_diagram());
6268 ADA_ASSERT_TRUE(validate());
6269 ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
6270
6271 add_authority_slashes_if_needed();
6272
6273 bool has_password = has_non_empty_password();
6274 bool host_starts_with_at = buffer.size() > components.host_start &&
6275 buffer[components.host_start] == '@';
6276 uint32_t diff = replace_and_resize(components.protocol_end + 2,
6277 components.username_end, input);
6278
6279 components.username_end += diff;
6280 components.host_start += diff;
6281
6282 if (!input.empty() && !host_starts_with_at) {
6283 buffer.insert(components.host_start, "@");
6284 diff++;
6285 } else if (input.empty() && host_starts_with_at && !has_password) {
6286 // Input is empty, there is no password, and we need to remove "@" from
6287 // hostname
6288 buffer.erase(components.host_start, 1);
6289 diff--;
6290 }
6291
6292 components.host_end += diff;
6293 components.pathname_start += diff;
6294 if (components.search_start != url_components::omitted) {
6295 components.search_start += diff;
6296 }
6297 if (components.hash_start != url_components::omitted) {
6298 components.hash_start += diff;
6299 }
6300 ADA_ASSERT_TRUE(validate());
6301}
6302
6303inline void url_aggregator::append_base_username(const std::string_view input) {
6304 ada_log("url_aggregator::append_base_username ", input);
6305 ADA_ASSERT_TRUE(validate());
6306 ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
6307#if ADA_DEVELOPMENT_CHECKS
6308 // computing the expected password.
6309 std::string username_expected(get_username());
6310 username_expected.append(input);
6311#endif // ADA_DEVELOPMENT_CHECKS
6312 add_authority_slashes_if_needed();
6313
6314 // If input is empty, do nothing.
6315 if (input.empty()) {
6316 return;
6317 }
6318
6319 uint32_t difference = uint32_t(input.size());
6320 buffer.insert(components.username_end, input);
6321 components.username_end += difference;
6322 components.host_start += difference;
6323
6324 if (buffer[components.host_start] != '@' &&
6325 components.host_start != components.host_end) {
6326 buffer.insert(components.host_start, "@");
6327 difference++;
6328 }
6329
6330 components.host_end += difference;
6331 components.pathname_start += difference;
6332 if (components.search_start != url_components::omitted) {
6333 components.search_start += difference;
6334 }
6335 if (components.hash_start != url_components::omitted) {
6336 components.hash_start += difference;
6337 }
6338#if ADA_DEVELOPMENT_CHECKS
6339 std::string username_after(get_username());
6341 username_expected, username_after,
6342 "append_base_username problem after inserting " + std::string(input));
6343#endif // ADA_DEVELOPMENT_CHECKS
6344 ADA_ASSERT_TRUE(validate());
6345}
6346
6347inline void url_aggregator::clear_password() {
6348 ada_log("url_aggregator::clear_password ", to_string(), "\n", to_diagram());
6349 ADA_ASSERT_TRUE(validate());
6350 if (!has_password()) {
6351 return;
6352 }
6353
6354 uint32_t diff = components.host_start - components.username_end;
6355 buffer.erase(components.username_end, diff);
6356 components.host_start -= diff;
6357 components.host_end -= diff;
6358 components.pathname_start -= diff;
6359 if (components.search_start != url_components::omitted) {
6360 components.search_start -= diff;
6361 }
6362 if (components.hash_start != url_components::omitted) {
6363 components.hash_start -= diff;
6364 }
6365}
6366
6367inline void url_aggregator::update_base_password(const std::string_view input) {
6368 ada_log("url_aggregator::update_base_password ", input);
6369 ADA_ASSERT_TRUE(validate());
6370 ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
6371
6372 add_authority_slashes_if_needed();
6373
6374 // TODO: Optimization opportunity. Merge the following removal functions.
6375 if (input.empty()) {
6376 clear_password();
6377
6378 // Remove username too, if it is empty.
6379 if (!has_non_empty_username()) {
6380 update_base_username("");
6381 }
6382
6383 return;
6384 }
6385
6386 bool password_exists = has_password();
6387 uint32_t difference = uint32_t(input.size());
6388
6389 if (password_exists) {
6390 uint32_t current_length =
6391 components.host_start - components.username_end - 1;
6392 buffer.erase(components.username_end + 1, current_length);
6393 difference -= current_length;
6394 } else {
6395 buffer.insert(components.username_end, ":");
6396 difference++;
6397 }
6398
6399 buffer.insert(components.username_end + 1, input);
6400 components.host_start += difference;
6401
6402 // The following line is required to add "@" to hostname. When updating
6403 // password if hostname does not start with "@", it is "update_base_password"s
6404 // responsibility to set it.
6405 if (buffer[components.host_start] != '@') {
6406 buffer.insert(components.host_start, "@");
6407 difference++;
6408 }
6409
6410 components.host_end += difference;
6411 components.pathname_start += difference;
6412 if (components.search_start != url_components::omitted) {
6413 components.search_start += difference;
6414 }
6415 if (components.hash_start != url_components::omitted) {
6416 components.hash_start += difference;
6417 }
6418 ADA_ASSERT_TRUE(validate());
6419}
6420
6421inline void url_aggregator::append_base_password(const std::string_view input) {
6422 ada_log("url_aggregator::append_base_password ", input, " ", to_string(),
6423 "\n", to_diagram());
6424 ADA_ASSERT_TRUE(validate());
6425 ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
6426#if ADA_DEVELOPMENT_CHECKS
6427 // computing the expected password.
6428 std::string password_expected = std::string(get_password());
6429 password_expected.append(input);
6430#endif // ADA_DEVELOPMENT_CHECKS
6431 add_authority_slashes_if_needed();
6432
6433 // If input is empty, do nothing.
6434 if (input.empty()) {
6435 return;
6436 }
6437
6438 uint32_t difference = uint32_t(input.size());
6439 if (has_password()) {
6440 buffer.insert(components.host_start, input);
6441 } else {
6442 difference++; // Increment for ":"
6443 buffer.insert(components.username_end, ":");
6444 buffer.insert(components.username_end + 1, input);
6445 }
6446 components.host_start += difference;
6447
6448 // The following line is required to add "@" to hostname. When updating
6449 // password if hostname does not start with "@", it is "append_base_password"s
6450 // responsibility to set it.
6451 if (buffer[components.host_start] != '@') {
6452 buffer.insert(components.host_start, "@");
6453 difference++;
6454 }
6455
6456 components.host_end += difference;
6457 components.pathname_start += difference;
6458 if (components.search_start != url_components::omitted) {
6459 components.search_start += difference;
6460 }
6461 if (components.hash_start != url_components::omitted) {
6462 components.hash_start += difference;
6463 }
6464#if ADA_DEVELOPMENT_CHECKS
6465 std::string password_after(get_password());
6467 password_expected, password_after,
6468 "append_base_password problem after inserting " + std::string(input));
6469#endif // ADA_DEVELOPMENT_CHECKS
6470 ADA_ASSERT_TRUE(validate());
6471}
6472
6473inline void url_aggregator::update_base_port(uint32_t input) {
6474 ada_log("url_aggregator::update_base_port");
6475 ADA_ASSERT_TRUE(validate());
6476 if (input == url_components::omitted) {
6477 clear_port();
6478 return;
6479 }
6480 // calling std::to_string(input.value()) is unfortunate given that the port
6481 // value is probably already available as a string.
6482 std::string value = helpers::concat(":", std::to_string(input));
6483 uint32_t difference = uint32_t(value.size());
6484
6485 if (components.port != url_components::omitted) {
6486 difference -= components.pathname_start - components.host_end;
6487 buffer.erase(components.host_end,
6488 components.pathname_start - components.host_end);
6489 }
6490
6491 buffer.insert(components.host_end, value);
6492 components.pathname_start += difference;
6493 if (components.search_start != url_components::omitted) {
6494 components.search_start += difference;
6495 }
6496 if (components.hash_start != url_components::omitted) {
6497 components.hash_start += difference;
6498 }
6499 components.port = input;
6500 ADA_ASSERT_TRUE(validate());
6501}
6502
6503inline void url_aggregator::clear_port() {
6504 ada_log("url_aggregator::clear_port");
6505 ADA_ASSERT_TRUE(validate());
6506 if (components.port == url_components::omitted) {
6507 return;
6508 }
6509 uint32_t length = components.pathname_start - components.host_end;
6510 buffer.erase(components.host_end, length);
6511 components.pathname_start -= length;
6512 if (components.search_start != url_components::omitted) {
6513 components.search_start -= length;
6514 }
6515 if (components.hash_start != url_components::omitted) {
6516 components.hash_start -= length;
6517 }
6518 components.port = url_components::omitted;
6519 ADA_ASSERT_TRUE(validate());
6520}
6521
6522[[nodiscard]] inline uint32_t url_aggregator::retrieve_base_port() const {
6523 ada_log("url_aggregator::retrieve_base_port");
6524 return components.port;
6525}
6526
6527inline void url_aggregator::clear_search() {
6528 ada_log("url_aggregator::clear_search");
6529 ADA_ASSERT_TRUE(validate());
6530 if (components.search_start == url_components::omitted) {
6531 return;
6532 }
6533
6534 if (components.hash_start == url_components::omitted) {
6535 buffer.resize(components.search_start);
6536 } else {
6537 buffer.erase(components.search_start,
6538 components.hash_start - components.search_start);
6539 components.hash_start = components.search_start;
6540 }
6541
6542 components.search_start = url_components::omitted;
6543
6544#if ADA_DEVELOPMENT_CHECKS
6545 ADA_ASSERT_EQUAL(get_search(), "",
6546 "search should have been cleared on buffer=" + buffer +
6547 " with " + components.to_string() + "\n" + to_diagram());
6548#endif
6549 ADA_ASSERT_TRUE(validate());
6550}
6551
6552inline void url_aggregator::clear_hash() {
6553 ada_log("url_aggregator::clear_hash");
6554 ADA_ASSERT_TRUE(validate());
6555 if (components.hash_start == url_components::omitted) {
6556 return;
6557 }
6558 buffer.resize(components.hash_start);
6559 components.hash_start = url_components::omitted;
6560
6561#if ADA_DEVELOPMENT_CHECKS
6562 ADA_ASSERT_EQUAL(get_hash(), "",
6563 "hash should have been cleared on buffer=" + buffer +
6564 " with " + components.to_string() + "\n" + to_diagram());
6565#endif
6566 ADA_ASSERT_TRUE(validate());
6567}
6568
6569inline void url_aggregator::clear_pathname() {
6570 ada_log("url_aggregator::clear_pathname");
6571 ADA_ASSERT_TRUE(validate());
6572 uint32_t ending_index = uint32_t(buffer.size());
6573 if (components.search_start != url_components::omitted) {
6574 ending_index = components.search_start;
6575 } else if (components.hash_start != url_components::omitted) {
6576 ending_index = components.hash_start;
6577 }
6578 uint32_t pathname_length = ending_index - components.pathname_start;
6579 buffer.erase(components.pathname_start, pathname_length);
6580 uint32_t difference = pathname_length;
6581 if (components.pathname_start == components.host_end + 2 &&
6582 buffer[components.host_end] == '/' &&
6583 buffer[components.host_end + 1] == '.') {
6584 components.pathname_start -= 2;
6585 buffer.erase(components.host_end, 2);
6586 difference += 2;
6587 }
6588 if (components.search_start != url_components::omitted) {
6589 components.search_start -= difference;
6590 }
6591 if (components.hash_start != url_components::omitted) {
6592 components.hash_start -= difference;
6593 }
6594 ada_log("url_aggregator::clear_pathname completed, running checks...");
6595#if ADA_DEVELOPMENT_CHECKS
6596 ADA_ASSERT_EQUAL(get_pathname(), "",
6597 "pathname should have been cleared on buffer=" + buffer +
6598 " with " + components.to_string() + "\n" + to_diagram());
6599#endif
6600 ADA_ASSERT_TRUE(validate());
6601 ada_log("url_aggregator::clear_pathname completed, running checks... ok");
6602}
6603
6604inline void url_aggregator::clear_hostname() {
6605 ada_log("url_aggregator::clear_hostname");
6606 ADA_ASSERT_TRUE(validate());
6607 if (!has_authority()) {
6608 return;
6609 }
6610 ADA_ASSERT_TRUE(has_authority());
6611
6612 uint32_t hostname_length = components.host_end - components.host_start;
6613 uint32_t start = components.host_start;
6614
6615 // If hostname starts with "@", we should not remove that character.
6616 if (hostname_length > 0 && buffer[start] == '@') {
6617 start++;
6618 hostname_length--;
6619 }
6620 buffer.erase(start, hostname_length);
6621 components.host_end = start;
6622 components.pathname_start -= hostname_length;
6623 if (components.search_start != url_components::omitted) {
6624 components.search_start -= hostname_length;
6625 }
6626 if (components.hash_start != url_components::omitted) {
6627 components.hash_start -= hostname_length;
6628 }
6629#if ADA_DEVELOPMENT_CHECKS
6630 ADA_ASSERT_EQUAL(get_hostname(), "",
6631 "hostname should have been cleared on buffer=" + buffer +
6632 " with " + components.to_string() + "\n" + to_diagram());
6633#endif
6634 ADA_ASSERT_TRUE(has_authority());
6635 ADA_ASSERT_EQUAL(has_empty_hostname(), true,
6636 "hostname should have been cleared on buffer=" + buffer +
6637 " with " + components.to_string() + "\n" + to_diagram());
6638 ADA_ASSERT_TRUE(validate());
6639}
6640
6641[[nodiscard]] inline bool url_aggregator::has_hash() const noexcept {
6642 ada_log("url_aggregator::has_hash");
6643 return components.hash_start != url_components::omitted;
6644}
6645
6646[[nodiscard]] inline bool url_aggregator::has_search() const noexcept {
6647 ada_log("url_aggregator::has_search");
6648 return components.search_start != url_components::omitted;
6649}
6650
6651ada_really_inline bool url_aggregator::has_credentials() const noexcept {
6652 ada_log("url_aggregator::has_credentials");
6653 return has_non_empty_username() || has_non_empty_password();
6654}
6655
6656inline bool url_aggregator::cannot_have_credentials_or_port() const {
6657 ada_log("url_aggregator::cannot_have_credentials_or_port");
6658 return type == ada::scheme::type::FILE ||
6659 components.host_start == components.host_end;
6660}
6661
6662[[nodiscard]] ada_really_inline const ada::url_components &
6663url_aggregator::get_components() const noexcept {
6664 return components;
6665}
6666
6667[[nodiscard]] inline bool ada::url_aggregator::has_authority() const noexcept {
6668 ada_log("url_aggregator::has_authority");
6669 // Performance: instead of doing this potentially expensive check, we could
6670 // have a boolean in the struct.
6671 return components.protocol_end + 2 <= components.host_start &&
6672 helpers::substring(buffer, components.protocol_end,
6673 components.protocol_end + 2) == "//";
6674}
6675
6676inline void ada::url_aggregator::add_authority_slashes_if_needed() noexcept {
6677 ada_log("url_aggregator::add_authority_slashes_if_needed");
6678 ADA_ASSERT_TRUE(validate());
6679 // Protocol setter will insert `http:` to the URL. It is up to hostname setter
6680 // to insert
6681 // `//` initially to the buffer, since it depends on the hostname existence.
6682 if (has_authority()) {
6683 return;
6684 }
6685 // Performance: the common case is components.protocol_end == buffer.size()
6686 // Optimization opportunity: in many cases, the "//" is part of the input and
6687 // the insert could be fused with another insert.
6688 buffer.insert(components.protocol_end, "//");
6689 components.username_end += 2;
6690 components.host_start += 2;
6691 components.host_end += 2;
6692 components.pathname_start += 2;
6693 if (components.search_start != url_components::omitted) {
6694 components.search_start += 2;
6695 }
6696 if (components.hash_start != url_components::omitted) {
6697 components.hash_start += 2;
6698 }
6699 ADA_ASSERT_TRUE(validate());
6700}
6701
6702inline void ada::url_aggregator::reserve(uint32_t capacity) {
6703 buffer.reserve(capacity);
6704}
6705
6706inline bool url_aggregator::has_non_empty_username() const noexcept {
6707 ada_log("url_aggregator::has_non_empty_username");
6708 return components.protocol_end + 2 < components.username_end;
6709}
6710
6711inline bool url_aggregator::has_non_empty_password() const noexcept {
6712 ada_log("url_aggregator::has_non_empty_password");
6713 return components.host_start - components.username_end > 0;
6714}
6715
6716inline bool url_aggregator::has_password() const noexcept {
6717 ada_log("url_aggregator::has_password");
6718 // This function does not care about the length of the password
6719 return components.host_start > components.username_end &&
6720 buffer[components.username_end] == ':';
6721}
6722
6723inline bool url_aggregator::has_empty_hostname() const noexcept {
6724 if (!has_hostname()) {
6725 return false;
6726 }
6727 if (components.host_start == components.host_end) {
6728 return true;
6729 }
6730 if (components.host_end > components.host_start + 1) {
6731 return false;
6732 }
6733 return components.username_end != components.host_start;
6734}
6735
6736inline bool url_aggregator::has_hostname() const noexcept {
6737 return has_authority();
6738}
6739
6740inline bool url_aggregator::has_port() const noexcept {
6741 ada_log("url_aggregator::has_port");
6742 // A URL cannot have a username/password/port if its host is null or the empty
6743 // string, or its scheme is "file".
6744 return has_hostname() && components.pathname_start != components.host_end;
6745}
6746
6747[[nodiscard]] inline bool url_aggregator::has_dash_dot() const noexcept {
6748 // If url's host is null, url does not have an opaque path, url's path's size
6749 // is greater than 1, and url's path[0] is the empty string, then append
6750 // U+002F (/) followed by U+002E (.) to output.
6751 ada_log("url_aggregator::has_dash_dot");
6752#if ADA_DEVELOPMENT_CHECKS
6753 // If pathname_start and host_end are exactly two characters apart, then we
6754 // either have a one-digit port such as http://test.com:5?param=1 or else we
6755 // have a /.: sequence such as "non-spec:/.//". We test that this is the case.
6756 if (components.pathname_start == components.host_end + 2) {
6757 ADA_ASSERT_TRUE((buffer[components.host_end] == '/' &&
6758 buffer[components.host_end + 1] == '.') ||
6759 (buffer[components.host_end] == ':' &&
6760 checkers::is_digit(buffer[components.host_end + 1])));
6761 }
6762 if (components.pathname_start == components.host_end + 2 &&
6763 buffer[components.host_end] == '/' &&
6764 buffer[components.host_end + 1] == '.') {
6765 ADA_ASSERT_TRUE(components.pathname_start + 1 < buffer.size());
6766 ADA_ASSERT_TRUE(buffer[components.pathname_start] == '/');
6767 ADA_ASSERT_TRUE(buffer[components.pathname_start + 1] == '/');
6768 }
6769#endif
6770 // Performance: it should be uncommon for components.pathname_start ==
6771 // components.host_end + 2 to be true. So we put this check first in the
6772 // sequence. Most times, we do not have an opaque path. Checking for '/.' is
6773 // more expensive, but should be uncommon.
6774 return components.pathname_start == components.host_end + 2 &&
6775 !has_opaque_path && buffer[components.host_end] == '/' &&
6776 buffer[components.host_end + 1] == '.';
6777}
6778
6779[[nodiscard]] inline std::string_view url_aggregator::get_href()
6780 const noexcept {
6781 ada_log("url_aggregator::get_href");
6782 return buffer;
6783}
6784
6785ada_really_inline size_t url_aggregator::parse_port(
6786 std::string_view view, bool check_trailing_content) noexcept {
6787 ada_log("url_aggregator::parse_port('", view, "') ", view.size());
6788 uint16_t parsed_port{};
6789 auto r = std::from_chars(view.data(), view.data() + view.size(), parsed_port);
6790 if (r.ec == std::errc::result_out_of_range) {
6791 ada_log("parse_port: std::errc::result_out_of_range");
6792 is_valid = false;
6793 return 0;
6794 }
6795 ada_log("parse_port: ", parsed_port);
6796 const size_t consumed = size_t(r.ptr - view.data());
6797 ada_log("parse_port: consumed ", consumed);
6798 if (check_trailing_content) {
6799 is_valid &=
6800 (consumed == view.size() || view[consumed] == '/' ||
6801 view[consumed] == '?' || (is_special() && view[consumed] == '\\'));
6802 }
6803 ada_log("parse_port: is_valid = ", is_valid);
6804 if (is_valid) {
6805 ada_log("parse_port", r.ec == std::errc());
6806 // scheme_default_port can return 0, and we should allow 0 as a base port.
6807 auto default_port = scheme_default_port();
6808 bool is_port_valid = (default_port == 0 && parsed_port == 0) ||
6809 (default_port != parsed_port);
6810 if (r.ec == std::errc() && is_port_valid) {
6811 update_base_port(parsed_port);
6812 } else {
6813 clear_port();
6814 }
6815 }
6816 return consumed;
6817}
6818
6819inline void url_aggregator::set_protocol_as_file() {
6820 ada_log("url_aggregator::set_protocol_as_file ");
6821 ADA_ASSERT_TRUE(validate());
6822 type = ada::scheme::type::FILE;
6823 // next line could overflow but unsigned arithmetic has well-defined
6824 // overflows.
6825 uint32_t new_difference = 5 - components.protocol_end;
6826
6827 if (buffer.empty()) {
6828 buffer.append("file:");
6829 } else {
6830 buffer.erase(0, components.protocol_end);
6831 buffer.insert(0, "file:");
6832 }
6833 components.protocol_end = 5;
6834
6835 // Update the rest of the components.
6836 components.username_end += new_difference;
6837 components.host_start += new_difference;
6838 components.host_end += new_difference;
6839 components.pathname_start += new_difference;
6840 if (components.search_start != url_components::omitted) {
6841 components.search_start += new_difference;
6842 }
6843 if (components.hash_start != url_components::omitted) {
6844 components.hash_start += new_difference;
6845 }
6846 ADA_ASSERT_TRUE(validate());
6847}
6848
6849inline std::ostream &operator<<(std::ostream &out,
6850 const ada::url_aggregator &u) {
6851 return out << u.to_string();
6852}
6853} // namespace ada
6854
6855#endif // ADA_URL_AGGREGATOR_INL_H
6856/* end file include/ada/url_aggregator-inl.h */
6857/* begin file include/ada/url_search_params.h */
6862#ifndef ADA_URL_SEARCH_PARAMS_H
6863#define ADA_URL_SEARCH_PARAMS_H
6864
6865#include <optional>
6866#include <string>
6867#include <string_view>
6868#include <vector>
6869
6870namespace ada {
6871
6873 KEYS,
6874 VALUES,
6875 ENTRIES,
6876};
6877
6878template <typename T, url_search_params_iter_type Type>
6879struct url_search_params_iter;
6880
6881typedef std::pair<std::string_view, std::string_view> key_value_view_pair;
6882
6883using url_search_params_keys_iter =
6884 url_search_params_iter<std::string_view, url_search_params_iter_type::KEYS>;
6885using url_search_params_values_iter =
6886 url_search_params_iter<std::string_view,
6887 url_search_params_iter_type::VALUES>;
6888using url_search_params_entries_iter =
6889 url_search_params_iter<key_value_view_pair,
6890 url_search_params_iter_type::ENTRIES>;
6891
6897
6902 url_search_params(const std::string_view input) { initialize(input); }
6903
6905 url_search_params(url_search_params &&u) noexcept = default;
6909
6910 [[nodiscard]] inline size_t size() const noexcept;
6911
6915 inline void append(std::string_view key, std::string_view value);
6916
6920 inline void remove(std::string_view key);
6921 inline void remove(std::string_view key, std::string_view value);
6922
6926 inline std::optional<std::string_view> get(std::string_view key);
6927
6931 inline std::vector<std::string> get_all(std::string_view key);
6932
6936 inline bool has(std::string_view key) noexcept;
6937 inline bool has(std::string_view key, std::string_view value) noexcept;
6938
6942 inline void set(std::string_view key, std::string_view value);
6943
6947 inline void sort();
6948
6952 inline std::string to_string() const;
6953
6962
6970
6979
6984 inline auto begin() const { return params.begin(); }
6985 inline auto end() const { return params.end(); }
6986 inline auto front() const { return params.front(); }
6987 inline auto back() const { return params.back(); }
6988 inline auto operator[](size_t index) const { return params[index]; }
6989
6996 void reset(std::string_view input);
6997
6998 private:
6999 typedef std::pair<std::string, std::string> key_value_pair;
7000 std::vector<key_value_pair> params{};
7001
7005 void initialize(std::string_view init);
7006
7007 template <typename T, url_search_params_iter_type Type>
7009}; // url_search_params
7010
7017template <typename T, url_search_params_iter_type Type>
7019 inline url_search_params_iter() : params(EMPTY) {}
7023 default;
7026
7030 inline std::optional<T> next();
7031
7032 inline bool has_next();
7033
7034 private:
7035 static url_search_params EMPTY;
7036 inline url_search_params_iter(url_search_params &params_) : params(params_) {}
7037
7038 url_search_params &params;
7039 size_t pos = 0;
7040
7041 friend struct url_search_params;
7042};
7043
7044} // namespace ada
7045#endif
7046/* end file include/ada/url_search_params.h */
7047/* begin file include/ada/url_search_params-inl.h */
7052#ifndef ADA_URL_SEARCH_PARAMS_INL_H
7053#define ADA_URL_SEARCH_PARAMS_INL_H
7054
7055
7056#include <algorithm>
7057#include <optional>
7058#include <string>
7059#include <string_view>
7060#include <vector>
7061
7062namespace ada {
7063
7064// A default, empty url_search_params for use with empty iterators.
7065template <typename T, ada::url_search_params_iter_type Type>
7066url_search_params url_search_params_iter<T, Type>::EMPTY;
7067
7068inline void url_search_params::reset(std::string_view input) {
7069 params.clear();
7070 initialize(input);
7071}
7072
7073inline void url_search_params::initialize(std::string_view input) {
7074 if (!input.empty() && input.front() == '?') {
7075 input.remove_prefix(1);
7076 }
7077
7078 auto process_key_value = [&](const std::string_view current) {
7079 auto equal = current.find('=');
7080
7081 if (equal == std::string_view::npos) {
7082 std::string name(current);
7083 std::replace(name.begin(), name.end(), '+', ' ');
7084 params.emplace_back(unicode::percent_decode(name, name.find('%')), "");
7085 } else {
7086 std::string name(current.substr(0, equal));
7087 std::string value(current.substr(equal + 1));
7088
7089 std::replace(name.begin(), name.end(), '+', ' ');
7090 std::replace(value.begin(), value.end(), '+', ' ');
7091
7092 params.emplace_back(unicode::percent_decode(name, name.find('%')),
7093 unicode::percent_decode(value, value.find('%')));
7094 }
7095 };
7096
7097 while (!input.empty()) {
7098 auto ampersand_index = input.find('&');
7099
7100 if (ampersand_index == std::string_view::npos) {
7101 if (!input.empty()) {
7102 process_key_value(input);
7103 }
7104 break;
7105 } else if (ampersand_index != 0) {
7106 process_key_value(input.substr(0, ampersand_index));
7107 }
7108
7109 input.remove_prefix(ampersand_index + 1);
7110 }
7111}
7112
7113inline void url_search_params::append(const std::string_view key,
7114 const std::string_view value) {
7115 params.emplace_back(key, value);
7116}
7117
7118inline size_t url_search_params::size() const noexcept { return params.size(); }
7119
7120inline std::optional<std::string_view> url_search_params::get(
7121 const std::string_view key) {
7122 auto entry = std::find_if(params.begin(), params.end(),
7123 [&key](auto &param) { return param.first == key; });
7124
7125 if (entry == params.end()) {
7126 return std::nullopt;
7127 }
7128
7129 return entry->second;
7130}
7131
7132inline std::vector<std::string> url_search_params::get_all(
7133 const std::string_view key) {
7134 std::vector<std::string> out{};
7135
7136 for (auto &param : params) {
7137 if (param.first == key) {
7138 out.emplace_back(param.second);
7139 }
7140 }
7141
7142 return out;
7143}
7144
7145inline bool url_search_params::has(const std::string_view key) noexcept {
7146 auto entry = std::find_if(params.begin(), params.end(),
7147 [&key](auto &param) { return param.first == key; });
7148 return entry != params.end();
7149}
7150
7151inline bool url_search_params::has(std::string_view key,
7152 std::string_view value) noexcept {
7153 auto entry =
7154 std::find_if(params.begin(), params.end(), [&key, &value](auto &param) {
7155 return param.first == key && param.second == value;
7156 });
7157 return entry != params.end();
7158}
7159
7160inline std::string url_search_params::to_string() const {
7162 std::string out{};
7163 for (size_t i = 0; i < params.size(); i++) {
7164 auto key = ada::unicode::percent_encode(params[i].first, character_set);
7165 auto value = ada::unicode::percent_encode(params[i].second, character_set);
7166
7167 // Performance optimization: Move this inside percent_encode.
7168 std::replace(key.begin(), key.end(), ' ', '+');
7169 std::replace(value.begin(), value.end(), ' ', '+');
7170
7171 if (i != 0) {
7172 out += "&";
7173 }
7174 out.append(key);
7175 out += "=";
7176 out.append(value);
7177 }
7178 return out;
7179}
7180
7181inline void url_search_params::set(const std::string_view key,
7182 const std::string_view value) {
7183 const auto find = [&key](auto &param) { return param.first == key; };
7184
7185 auto it = std::find_if(params.begin(), params.end(), find);
7186
7187 if (it == params.end()) {
7188 params.emplace_back(key, value);
7189 } else {
7190 it->second = value;
7191 params.erase(std::remove_if(std::next(it), params.end(), find),
7192 params.end());
7193 }
7194}
7195
7196inline void url_search_params::remove(const std::string_view key) {
7197 params.erase(
7198 std::remove_if(params.begin(), params.end(),
7199 [&key](auto &param) { return param.first == key; }),
7200 params.end());
7201}
7202
7203inline void url_search_params::remove(const std::string_view key,
7204 const std::string_view value) {
7205 params.erase(std::remove_if(params.begin(), params.end(),
7206 [&key, &value](auto &param) {
7207 return param.first == key &&
7208 param.second == value;
7209 }),
7210 params.end());
7211}
7212
7213inline void url_search_params::sort() {
7214 std::stable_sort(params.begin(), params.end(),
7215 [](const key_value_pair &lhs, const key_value_pair &rhs) {
7216 return lhs.first < rhs.first;
7217 });
7218}
7219
7221 return url_search_params_keys_iter(*this);
7222}
7223
7228 return url_search_params_values_iter(*this);
7229}
7230
7235 return url_search_params_entries_iter(*this);
7236}
7237
7238template <typename T, url_search_params_iter_type Type>
7240 return pos < params.params.size();
7241}
7242
7243template <>
7244inline std::optional<std::string_view> url_search_params_keys_iter::next() {
7245 if (!has_next()) {
7246 return std::nullopt;
7247 }
7248 return params.params[pos++].first;
7249}
7250
7251template <>
7252inline std::optional<std::string_view> url_search_params_values_iter::next() {
7253 if (!has_next()) {
7254 return std::nullopt;
7255 }
7256 return params.params[pos++].second;
7257}
7258
7259template <>
7260inline std::optional<key_value_view_pair>
7262 if (!has_next()) {
7263 return std::nullopt;
7264 }
7265 return params.params[pos++];
7266}
7267
7268} // namespace ada
7269
7270#endif // ADA_URL_SEARCH_PARAMS_INL_H
7271/* end file include/ada/url_search_params-inl.h */
7272
7273// Public API
7274/* begin file include/ada/ada_version.h */
7279#ifndef ADA_ADA_VERSION_H
7280#define ADA_ADA_VERSION_H
7281
7282#define ADA_VERSION "2.9.0"
7283
7284namespace ada {
7285
7286enum {
7290};
7291
7292} // namespace ada
7293
7294#endif // ADA_ADA_VERSION_H
7295/* end file include/ada/ada_version.h */
7296/* begin file include/ada/implementation.h */
7302#ifndef ADA_IMPLEMENTATION_H
7303#define ADA_IMPLEMENTATION_H
7304
7305#include <string>
7306#include <optional>
7307
7308
7309namespace ada {
7310enum class errors { generic_error };
7311
7312template <class result_type = ada::url_aggregator>
7314
7324template <class result_type = ada::url_aggregator>
7326 std::string_view input, const result_type* base_url = nullptr);
7327
7328extern template ada::result<url> parse<url>(std::string_view input,
7329 const url* base_url);
7331 std::string_view input, const url_aggregator* base_url);
7332
7339bool can_parse(std::string_view input,
7340 const std::string_view* base_input = nullptr);
7341
7347std::string href_from_file(std::string_view path);
7348} // namespace ada
7349
7350#endif // ADA_IMPLEMENTATION_H
7351/* end file include/ada/implementation.h */
7352
7353#endif // ADA_H
7354/* end file include/ada.h */
virtual const char * what() const noexcept override
Definition ada.h:3135
const E & error() const &
Definition ada.h:3139
const E && error() const &&
Definition ada.h:3141
constexpr expected(const unexpected< G > &e)
Definition ada.h:3483
expected & operator=(const expected &rhs)=default
constexpr T value_or(U &&v) const &
Definition ada.h:3961
TL_EXPECTED_11_CONSTEXPR decltype(expected_map_impl(std::declval< expected >(), std::declval< F && >())) transform(F &&f) &&
Definition ada.h:3323
constexpr decltype(map_error_impl(std::declval< const expected && >(), std::declval< F && >())) transform_error(F &&f) const &&
Definition ada.h:3432
TL_EXPECTED_11_CONSTEXPR T * operator->()
Definition ada.h:3881
TL_EXPECTED_11_CONSTEXPR expected(const expected< U, G > &rhs)
Definition ada.h:3535
TL_EXPECTED_11_CONSTEXPR decltype(map_error_impl(std::declval< expected && >(), std::declval< F && >())) transform_error(F &&f) &&
Definition ada.h:3418
constexpr auto and_then(F &&f) const &&-> decltype(and_then_impl(std::declval< expected const && >(), std::forward< F >(f)))
Definition ada.h:3240
constexpr const E && error() const &&
Definition ada.h:3951
TL_EXPECTED_11_CONSTEXPR const U & value() const &
Definition ada.h:3916
constexpr decltype(expected_map_impl(std::declval< const expected && >(), std::declval< F && >())) transform(F &&f) const &&
Definition ada.h:3337
TL_EXPECTED_11_CONSTEXPR auto and_then(F &&f) &&-> decltype(and_then_impl(std::declval< expected && >(), std::forward< F >(f)))
Definition ada.h:3228
TL_EXPECTED_11_CONSTEXPR decltype(expected_map_impl(std::declval< expected >(), std::declval< F && >())) map(F &&f) &&
Definition ada.h:3275
void emplace(std::initializer_list< U > il, Args &&...args)
Definition ada.h:3731
constexpr expected(const expected &rhs)=default
TL_EXPECTED_11_CONSTEXPR U & operator*() &
Definition ada.h:3894
constexpr const E & error() const &
Definition ada.h:3943
constexpr bool has_value() const noexcept
Definition ada.h:3911
TL_EXPECTED_11_CONSTEXPR T value_or(U &&v) &&
Definition ada.h:3968
detail::enable_if_t< detail::is_swappable< OT >::value &&detail::is_swappable< OE >::value &&(std::is_nothrow_move_constructible< OT >::value||std::is_nothrow_move_constructible< OE >::value)> swap(expected &rhs) noexcept(std::is_nothrow_move_constructible< T >::value &&detail::is_nothrow_swappable< T >::value &&std::is_nothrow_move_constructible< E >::value &&detail::is_nothrow_swappable< E >::value)
Definition ada.h:3861
TL_EXPECTED_11_CONSTEXPR decltype(map_error_impl(std::declval< expected & >(), std::declval< F && >())) map_error(F &&f) &
Definition ada.h:3365
constexpr expected()=default
TL_EXPECTED_11_CONSTEXPR decltype(expected_map_impl(std::declval< expected & >(), std::declval< F && >())) map(F &&f) &
Definition ada.h:3269
constexpr auto and_then(F &&f) const &-> decltype(and_then_impl(std::declval< expected const & >(), std::forward< F >(f)))
Definition ada.h:3233
TL_EXPECTED_11_CONSTEXPR expected(expected< U, G > &&rhs)
Definition ada.h:3564
constexpr expected(unexpected< G > &&e) noexcept(std::is_nothrow_constructible< E, G && >::value)
Definition ada.h:3500
TL_EXPECTED_MSVC2015_CONSTEXPR expected(U &&v)
Definition ada.h:3591
constexpr expected(unexpect_t, Args &&...args)
Definition ada.h:3517
expected TL_EXPECTED_11_CONSTEXPR or_else(F &&f) &
Definition ada.h:3438
constexpr const T * operator->() const
Definition ada.h:3877
constexpr decltype(expected_map_impl(std::declval< const expected & >(), std::declval< F && >())) transform(F &&f) const &
Definition ada.h:3329
constexpr expected(unexpected< G > const &e)
Definition ada.h:3492
expected & operator=(const unexpected< G > &rhs)
Definition ada.h:3664
void emplace(Args &&...args)
Definition ada.h:3693
constexpr expected(unexpect_t, std::initializer_list< U > il, Args &&...args)
Definition ada.h:3524
constexpr decltype(map_error_impl(std::declval< const expected & >(), std::declval< F && >())) map_error(F &&f) const &
Definition ada.h:3377
expected constexpr or_else(F &&f) const &
Definition ada.h:3448
TL_EXPECTED_11_CONSTEXPR E && error() &&
Definition ada.h:3955
T value_type
Definition ada.h:3195
constexpr expected(in_place_t, std::initializer_list< U > il, Args &&...args)
Definition ada.h:3474
constexpr expected(expected &&rhs)=default
TL_EXPECTED_11_CONSTEXPR decltype(expected_map_impl(std::declval< expected & >(), std::declval< F && >())) transform(F &&f) &
Definition ada.h:3317
constexpr decltype(map_error_impl(std::declval< const expected && >(), std::declval< F && >())) map_error(F &&f) const &&
Definition ada.h:3385
E error_type
Definition ada.h:3196
constexpr const U & operator*() const &
Definition ada.h:3888
TL_EXPECTED_11_CONSTEXPR const U && value() const &&
Definition ada.h:3930
constexpr expected(in_place_t, Args &&...args)
Definition ada.h:3467
TL_EXPECTED_11_CONSTEXPR decltype(map_error_impl(std::declval< expected & >(), std::declval< F && >())) transform_error(F &&f) &
Definition ada.h:3412
TL_EXPECTED_11_CONSTEXPR auto and_then(F &&f) &-> decltype(and_then_impl(std::declval< expected & >(), std::forward< F >(f)))
Definition ada.h:3223
expected TL_EXPECTED_11_CONSTEXPR or_else(F &&f) &&
Definition ada.h:3443
unexpected< E > unexpected_type
Definition ada.h:3197
expected & operator=(expected &&rhs)=default
expected constexpr or_else(F &&f) const &&
Definition ada.h:3454
expected & operator=(unexpected< G > &&rhs) noexcept
Definition ada.h:3679
TL_EXPECTED_11_CONSTEXPR U && operator*() &&
Definition ada.h:3906
constexpr const U && operator*() const &&
Definition ada.h:3900
constexpr decltype(map_error_impl(std::declval< const expected & >(), std::declval< F && >())) transform_error(F &&f) const &
Definition ada.h:3424
TL_EXPECTED_11_CONSTEXPR E & error() &
Definition ada.h:3947
TL_EXPECTED_11_CONSTEXPR decltype(map_error_impl(std::declval< expected && >(), std::declval< F && >())) map_error(F &&f) &&
Definition ada.h:3371
TL_EXPECTED_11_CONSTEXPR U & value() &
Definition ada.h:3923
constexpr decltype(expected_map_impl(std::declval< const expected & >(), std::declval< F && >())) map(F &&f) const &
Definition ada.h:3281
TL_EXPECTED_11_CONSTEXPR U && value() &&
Definition ada.h:3937
constexpr decltype(expected_map_impl(std::declval< const expected && >(), std::declval< F && >())) map(F &&f) const &&
Definition ada.h:3289
TL_EXPECTED_11_CONSTEXPR E & value() &
Definition ada.h:2031
constexpr unexpected(const E &e)
Definition ada.h:2015
constexpr unexpected(Args &&...args)
Definition ada.h:2021
constexpr const E & value() const &
Definition ada.h:2030
TL_EXPECTED_11_CONSTEXPR E && value() &&
Definition ada.h:2032
constexpr unexpected(std::initializer_list< U > l, Args &&...args)
Definition ada.h:2027
constexpr const E && value() const &&
Definition ada.h:2033
constexpr unexpected(E &&e)
Definition ada.h:2017
unexpected()=delete
#define ADA_ASSERT_TRUE(COND)
#define ada_constexpr
#define ada_warn_unused
Definition common_defs.h:88
#define ADA_ASSERT_EQUAL(LHS, RHS, MESSAGE)
#define ada_really_inline
Definition common_defs.h:84
Includes the definitions for unicode character sets.
constexpr uint8_t C0_CONTROL_PERCENT_ENCODE[32]
constexpr uint8_t FRAGMENT_PERCENT_ENCODE[32]
constexpr uint8_t PATH_PERCENT_ENCODE[32]
constexpr uint8_t USERINFO_PERCENT_ENCODE[32]
constexpr uint8_t WWW_FORM_URLENCODED_PERCENT_ENCODE[32]
constexpr uint8_t SPECIAL_QUERY_PERCENT_ENCODE[32]
constexpr char hex[1024]
constexpr uint8_t QUERY_PERCENT_ENCODE[32]
ada_really_inline bool bit_at(const uint8_t a[], const uint8_t i)
Includes the definitions for validation functions.
bool has_hex_prefix_unsafe(std::string_view input)
constexpr bool is_normalized_windows_drive_letter(std::string_view input) noexcept
constexpr bool is_windows_drive_letter(std::string_view input) noexcept
constexpr char to_lower(char x) noexcept
bool has_hex_prefix(std::string_view input)
constexpr bool is_alpha(char x) noexcept
constexpr bool is_digit(char x) noexcept
ada_really_inline bool begins_with(std::string_view view, std::string_view prefix)
Includes the definitions for helper functions.
constexpr int32_t base
Definition ada.cpp:7970
void ascii_map(char *input, size_t length)
Definition ada.cpp:2779
bool punycode_to_utf32(std::string_view input, std::u32string &out)
Definition ada.cpp:8003
size_t utf32_length_from_utf8(const char *buf, size_t len)
Definition ada.cpp:256
size_t utf32_to_utf8(const char32_t *buf, size_t len, char *utf8_output)
Definition ada.cpp:265
bool constexpr is_ascii(std::u32string_view view)
Definition ada.cpp:9541
void normalize(std::u32string &input)
Definition ada.cpp:7953
bool utf32_to_punycode(std::u32string_view input, std::string &out)
Definition ada.cpp:8122
std::string to_ascii(std::string_view ut8_string)
Definition ada.cpp:9640
std::string to_unicode(std::string_view input)
Definition ada.cpp:9737
bool begins_with(std::u32string_view view, std::u32string_view prefix)
Definition ada.cpp:9525
size_t utf8_length_from_utf32(const char32_t *buf, size_t len)
Definition ada.cpp:243
bool is_label_valid(std::u32string_view label)
Definition ada.cpp:8990
bool ascii_has_upper_case(char *input, size_t length)
Definition ada.cpp:2755
bool contains_forbidden_domain_code_point(std::string_view ascii_string)
Definition ada.cpp:9578
std::u32string map(std::u32string_view input)
Definition ada.cpp:2805
size_t utf8_to_utf32(const char *buf, size_t len, char32_t *utf32_output)
Definition ada.cpp:146
bool verify_punycode(std::string_view input)
Definition ada.cpp:8064
Includes the definitions for supported parsers.
result_type parse_url(std::string_view user_input, const result_type *base_url=nullptr)
Definition ada.cpp:13057
result_type parse_url_impl(std::string_view user_input, const result_type *base_url=nullptr)
Definition ada.cpp:12144
Includes the scheme declarations.
Definition scheme-inl.h:10
constexpr ada::scheme::type get_scheme_type(std::string_view scheme) noexcept
Definition scheme-inl.h:72
@ NOT_SPECIAL
Definition scheme.h:32
constexpr uint16_t get_special_port(std::string_view scheme) noexcept
Definition scheme-inl.h:57
Includes the definitions for URL serializers.
Includes the declarations for unicode operations.
ada_really_inline size_t percent_encode_index(const std::string_view input, const uint8_t character_set[])
Definition unicode-inl.h:19
Definition ada_idna.h:13
bool can_parse(std::string_view input, const std::string_view *base_input=nullptr)
Definition ada.cpp:10389
template ada::result< url > parse< url >(std::string_view input, const url *base_url)
url_search_params_iter< key_value_view_pair, url_search_params_iter_type::ENTRIES > url_search_params_entries_iter
std::string href_from_file(std::string_view path)
Definition ada.cpp:10366
std::ostream & operator<<(std::ostream &out, const ada::url &u)
Definition url-inl.h:38
ada_warn_unused std::string to_string(encoding_type type)
Definition ada.cpp:10408
url_search_params_iter< std::string_view, url_search_params_iter_type::KEYS > url_search_params_keys_iter
url_host_type
Definition url_base.h:19
@ IPV4
Definition url_base.h:27
@ DEFAULT
Definition url_base.h:23
@ IPV6
Definition url_base.h:32
state
Definition state.h:17
@ SPECIAL_RELATIVE_OR_AUTHORITY
@ SPECIAL_AUTHORITY_SLASHES
@ SPECIAL_AUTHORITY_IGNORE_SLASHES
template ada::result< url_aggregator > parse< url_aggregator >(std::string_view input, const url_aggregator *base_url)
encoding_type
url_search_params_iter_type
url_search_params_iter< std::string_view, url_search_params_iter_type::VALUES > url_search_params_values_iter
void unreachable()
@ ADA_VERSION_MINOR
Definition ada_version.h:14
@ ADA_VERSION_REVISION
Definition ada_version.h:15
@ ADA_VERSION_MAJOR
Definition ada_version.h:13
tl::expected< result_type, ada::errors > result
ada_warn_unused ada::result< result_type > parse(std::string_view input, const result_type *base_url=nullptr)
Definition ada.cpp:10351
std::false_type can_swap(...) noexcept(false)
static constexpr no_init_t no_init
Definition ada.h:2323
typename std::remove_reference< T >::type remove_reference_t
Definition ada.h:2100
is_void_or< T, std::is_move_assignable< T > > is_move_assignable_or_void
Definition ada.h:2317
typename std::enable_if< E, T >::type enable_if_t
Definition ada.h:2104
is_void_or< T, std::is_copy_assignable< T > > is_copy_assignable_or_void
Definition ada.h:2314
typename std::decay< T >::type decay_t
Definition ada.h:2102
constexpr auto invoke(Fn &&f, Args &&...args) noexcept(noexcept(std::mem_fn(f)(std::forward< Args >(args)...))) -> decltype(std::mem_fn(f)(std::forward< Args >(args)...))
Definition ada.h:2163
typename detail::decay_t< Exp >::error_type err_t
Definition ada.h:3980
conditional_t< std::is_void< T >::value, std::true_type, U > is_void_or
Definition ada.h:2303
typename std::remove_const< T >::type remove_const_t
Definition ada.h:2098
detail::enable_if_t< std::is_constructible< T, U && >::value && !std::is_same< detail::decay_t< U >, in_place_t >::value && !std::is_same< expected< T, E >, detail::decay_t< U > >::value && !std::is_same< unexpected< E >, detail::decay_t< U > >::value > expected_enable_forward_value
Definition ada.h:2283
constexpr auto map_error_impl(Exp &&exp, F &&f) -> expected< exp_t< Exp >, detail::decay_t< Ret > >
Definition ada.h:4202
auto and_then_impl(Exp &&exp, F &&f) -> Ret
Definition ada.h:4013
typename std::conditional< B, T, F >::type conditional_t
Definition ada.h:2106
is_void_or< T, std::is_move_constructible< T > > is_move_constructible_or_void
Definition ada.h:2310
TL_EXPECTED_11_CONSTEXPR void throw_exception(E &&e)
Definition ada.h:2081
typename invoke_result< F, Us... >::type invoke_result_t
Definition ada.h:2194
detail::enable_if_t< std::is_constructible< T, UR >::value && std::is_constructible< E, GR >::value && !std::is_constructible< T, expected< U, G > & >::value && !std::is_constructible< T, expected< U, G > && >::value && !std::is_constructible< T, const expected< U, G > & >::value && !std::is_constructible< T, const expected< U, G > && >::value && !std::is_convertible< expected< U, G > &, T >::value && !std::is_convertible< expected< U, G > &&, T >::value && !std::is_convertible< const expected< U, G > &, T >::value && !std::is_convertible< const expected< U, G > &&, T >::value > expected_enable_from_other
Definition ada.h:2290
auto or_else_impl(Exp &&exp, F &&f) -> Ret
Definition ada.h:4285
constexpr auto expected_map_impl(Exp &&exp, F &&f) -> ret_t< Exp, detail::decay_t< Ret > >
Definition ada.h:4090
typename detail::decay_t< Exp >::value_type exp_t
Definition ada.h:3978
is_void_or< T, std::is_copy_constructible< T > > is_copy_constructible_or_void
Definition ada.h:2306
Definition ada.h:1995
constexpr bool operator>=(const unexpected< E > &lhs, const unexpected< E > &rhs)
Definition ada.h:2065
constexpr bool operator>(const unexpected< E > &lhs, const unexpected< E > &rhs)
Definition ada.h:2061
constexpr bool operator!=(const unexpected< E > &lhs, const unexpected< E > &rhs)
Definition ada.h:2049
constexpr bool operator==(const unexpected< E > &lhs, const unexpected< E > &rhs)
Definition ada.h:2045
constexpr bool operator<=(const unexpected< E > &lhs, const unexpected< E > &rhs)
Definition ada.h:2057
static constexpr in_place_t in_place
Definition ada.h:2006
static constexpr unexpect_t unexpect
Definition ada.h:2077
constexpr bool operator<(const unexpected< E > &lhs, const unexpected< E > &rhs)
Definition ada.h:2053
unexpected< typename std::decay< E >::type > make_unexpected(E &&e)
Definition ada.h:2070
#define TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(T)
Definition ada.h:1974
#define TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T)
Definition ada.h:1970
#define TL_EXPECTED_MSVC2015_CONSTEXPR
Definition ada.h:1902
#define TL_ASSERT(x)
Definition ada.h:1926
#define TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(T)
Definition ada.h:1972
#define ada_log(...)
Definition ada.h:1154
#define TL_EXPECTED_11_CONSTEXPR
Definition ada.h:1992
Lightweight URL struct.
Definition ada.h:4813
url_aggregator & operator=(const url_aggregator &u)=default
url_aggregator & operator=(url_aggregator &&u) noexcept=default
void set_hash(std::string_view input)
url_aggregator()=default
std::string to_string() const override
Definition ada.cpp:13941
bool set_protocol(std::string_view input)
bool has_valid_domain() const noexcept override
bool set_hostname(std::string_view input)
bool set_password(std::string_view input)
~url_aggregator() override=default
bool set_pathname(std::string_view input)
bool set_href(std::string_view input)
void set_search(std::string_view input)
url_aggregator(url_aggregator &&u) noexcept=default
bool set_host(std::string_view input)
bool set_port(std::string_view input)
url_aggregator(const url_aggregator &u)=default
bool set_username(std::string_view input)
Base class of URL implementations.
Definition ada.h:1527
virtual ~url_base()=default
ada_really_inline bool is_special() const noexcept
url_host_type host_type
Definition url_base.h:60
virtual bool has_valid_domain() const noexcept=0
bool is_valid
Definition url_base.h:50
virtual std::string get_origin() const noexcept=0
bool has_opaque_path
Definition url_base.h:55
virtual std::string to_string() const =0
URL Component representations using offsets.
Definition ada.h:1357
bool check_offset_consistency() const noexcept
std::string to_string() const
Definition ada.cpp:13150
url_components & operator=(url_components &&u) noexcept=default
~url_components()=default
url_components()=default
url_components(url_components &&u) noexcept=default
url_components(const url_components &u)=default
url_components & operator=(const url_components &u)=default
static constexpr uint32_t omitted
url_search_params_iter(const url_search_params_iter &u)=default
url_search_params_iter & operator=(url_search_params_iter &&u) noexcept=default
std::optional< T > next()
url_search_params_iter(url_search_params_iter &&u) noexcept=default
url_search_params_iter & operator=(const url_search_params_iter &u)=default
void set(std::string_view key, std::string_view value)
auto end() const
Definition ada.h:6985
std::vector< std::string > get_all(std::string_view key)
auto front() const
Definition ada.h:6986
auto back() const
Definition ada.h:6987
void remove(std::string_view key)
url_search_params(const url_search_params &u)=default
url_search_params(url_search_params &&u) noexcept=default
auto operator[](size_t index) const
Definition ada.h:6988
url_search_params_entries_iter get_entries()
std::string to_string() const
url_search_params & operator=(url_search_params &&u) noexcept=default
url_search_params_keys_iter get_keys()
size_t size() const noexcept
url_search_params & operator=(const url_search_params &u)=default
void append(std::string_view key, std::string_view value)
url_search_params(const std::string_view input)
Definition ada.h:6902
url_search_params_values_iter get_values()
~url_search_params()=default
std::optional< std::string_view > get(std::string_view key)
bool has(std::string_view key) noexcept
Generic URL struct reliant on std::string instantiation.
Definition ada.h:5258
url(url &&u) noexcept=default
bool has_empty_hostname() const noexcept
url & operator=(url &&u) noexcept=default
url & operator=(const url &u)=default
url(const url &u)=default
~url() override=default
url()=default
std::string to_string() const override
Definition ada.cpp:11749
constexpr default_constructor_tag()=default
expected_copy_assign_base(const expected_copy_assign_base &rhs)=default
expected_copy_assign_base(expected_copy_assign_base &&rhs)=default
expected_copy_assign_base & operator=(expected_copy_assign_base &&rhs)=default
expected_copy_assign_base & operator=(const expected_copy_assign_base &rhs)
Definition ada.h:2925
expected_copy_base(expected_copy_base &&rhs)=default
expected_copy_base & operator=(expected_copy_base &&rhs)=default
expected_copy_base(const expected_copy_base &rhs)
Definition ada.h:2851
expected_copy_base & operator=(const expected_copy_base &rhs)=default
constexpr expected_default_ctor_base() noexcept=delete
constexpr expected_default_ctor_base() noexcept=default
expected_delete_assign_base(expected_delete_assign_base &&) noexcept=default
expected_delete_assign_base(const expected_delete_assign_base &)=default
expected_delete_assign_base(expected_delete_assign_base &&) noexcept=default
expected_delete_assign_base(const expected_delete_assign_base &)=default
expected_delete_assign_base(const expected_delete_assign_base &)=default
expected_delete_assign_base(expected_delete_assign_base &&) noexcept=default
expected_delete_assign_base(const expected_delete_assign_base &)=default
expected_delete_assign_base(expected_delete_assign_base &&) noexcept=default
expected_delete_ctor_base(expected_delete_ctor_base &&) noexcept=delete
expected_delete_ctor_base(const expected_delete_ctor_base &)=delete
expected_delete_ctor_base(expected_delete_ctor_base &&) noexcept=default
expected_delete_ctor_base(const expected_delete_ctor_base &)=delete
expected_delete_ctor_base(expected_delete_ctor_base &&) noexcept=delete
expected_delete_ctor_base(const expected_delete_ctor_base &)=default
expected_delete_ctor_base(const expected_delete_ctor_base &)=default
expected_delete_ctor_base(expected_delete_ctor_base &&) noexcept=default
expected_move_assign_base & operator=(expected_move_assign_base &&rhs) noexcept(std::is_nothrow_move_constructible< T >::value &&std::is_nothrow_move_assignable< T >::value)
Definition ada.h:2969
expected_move_assign_base(expected_move_assign_base &&rhs)=default
expected_move_assign_base(const expected_move_assign_base &rhs)=default
expected_move_assign_base & operator=(const expected_move_assign_base &rhs)=default
expected_move_base & operator=(expected_move_base &&rhs)=default
expected_move_base & operator=(const expected_move_base &rhs)=default
expected_move_base(const expected_move_base &rhs)=default
expected_move_base(expected_move_base &&rhs) noexcept(std::is_nothrow_move_constructible< T >::value)
Definition ada.h:2889
constexpr const unexpected< E > && geterr() const &&
Definition ada.h:2825
constexpr const unexpected< E > & geterr() const &
Definition ada.h:2820
void construct_error(Args &&...args) noexcept
Definition ada.h:2793
TL_EXPECTED_11_CONSTEXPR void destroy_val()
Definition ada.h:2830
TL_EXPECTED_11_CONSTEXPR unexpected< E > & geterr() &
Definition ada.h:2817
TL_EXPECTED_11_CONSTEXPR unexpected< E > && geterr() &&
Definition ada.h:2821
constexpr const T && get() const &&
Definition ada.h:2755
TL_EXPECTED_11_CONSTEXPR unexpected< E > && geterr() &&
Definition ada.h:2762
constexpr const unexpected< E > & geterr() const &
Definition ada.h:2761
constexpr const T & get() const &
Definition ada.h:2752
TL_EXPECTED_11_CONSTEXPR void destroy_val()
Definition ada.h:2771
constexpr const unexpected< E > && geterr() const &&
Definition ada.h:2766
void construct(Args &&...args) noexcept
Definition ada.h:2591
void assign(const expected_operations_base &rhs) noexcept
Definition ada.h:2712
TL_EXPECTED_11_CONSTEXPR unexpected< E > & geterr() &
Definition ada.h:2758
void construct_with(Rhs &&rhs) noexcept
Definition ada.h:2597
void construct_error(Args &&...args) noexcept
Definition ada.h:2603
TL_EXPECTED_11_CONSTEXPR T && get() &&
Definition ada.h:2753
void assign(expected_operations_base &&rhs) noexcept
Definition ada.h:2721
TL_EXPECTED_11_CONSTEXPR T & get() &
Definition ada.h:2751
constexpr expected_storage_base(in_place_t, std::initializer_list< U > il, Args &&...args)
Definition ada.h:2482
constexpr expected_storage_base(in_place_t, Args &&...args)
Definition ada.h:2476
constexpr expected_storage_base(unexpect_t, Args &&...args)
Definition ada.h:2488
constexpr expected_storage_base(unexpect_t, std::initializer_list< U > il, Args &&...args)
Definition ada.h:2494
TL_EXPECTED_MSVC2015_CONSTEXPR expected_storage_base(no_init_t)
Definition ada.h:2424
constexpr expected_storage_base(unexpect_t, std::initializer_list< U > il, Args &&...args)
Definition ada.h:2448
constexpr expected_storage_base(unexpect_t, Args &&...args)
Definition ada.h:2442
constexpr expected_storage_base(in_place_t, Args &&...args)
Definition ada.h:2430
constexpr expected_storage_base(in_place_t, std::initializer_list< U > il, Args &&...args)
Definition ada.h:2436
constexpr expected_storage_base(in_place_t, Args &&...args)
Definition ada.h:2388
constexpr expected_storage_base(in_place_t, std::initializer_list< U > il, Args &&...args)
Definition ada.h:2394
constexpr expected_storage_base(unexpect_t, Args &&...args)
Definition ada.h:2400
constexpr expected_storage_base(unexpect_t, std::initializer_list< U > il, Args &&...args)
Definition ada.h:2406
constexpr expected_storage_base(unexpect_t, std::initializer_list< U > il, Args &&...args)
Definition ada.h:2566
constexpr expected_storage_base(unexpect_t, Args &&...args)
Definition ada.h:2560
constexpr expected_storage_base(unexpect_t, Args &&...args)
Definition ada.h:2529
constexpr expected_storage_base(unexpect_t, std::initializer_list< U > il, Args &&...args)
Definition ada.h:2535
constexpr expected_storage_base(unexpect_t, Args &&...args)
Definition ada.h:2352
constexpr expected_storage_base(no_init_t)
Definition ada.h:2335
constexpr expected_storage_base()
Definition ada.h:2334
constexpr expected_storage_base(in_place_t, std::initializer_list< U > il, Args &&...args)
Definition ada.h:2346
constexpr expected_storage_base(in_place_t, Args &&...args)
Definition ada.h:2340
unexpected< E > m_unexpect
Definition ada.h:2372
constexpr expected_storage_base(unexpect_t, std::initializer_list< U > il, Args &&...args)
Definition ada.h:2358
in_place_t()=default
unexpect_t()=default