Ada 2.9.2
Fast spec-compliant URL parser
Loading...
Searching...
No Matches
ada.h
Go to the documentation of this file.
1/* auto-generated on 2024-12-07 02:04:48.426670. 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#ifndef __has_cpp_attribute
483#define ada_lifetime_bound
484#elif __has_cpp_attribute(msvc::lifetimebound)
485#define ada_lifetime_bound [[msvc::lifetimebound]]
486#elif __has_cpp_attribute(clang::lifetimebound)
487#define ada_lifetime_bound [[clang::lifetimebound]]
488#elif __has_cpp_attribute(lifetimebound)
489#define ada_lifetime_bound [[lifetimebound]]
490#else
491#define ada_lifetime_bound
492#endif
493
494#endif // ADA_COMMON_DEFS_H
495/* end file include/ada/common_defs.h */
496#include <cstdint>
497
505namespace ada::character_sets {
506ada_really_inline bool bit_at(const uint8_t a[], uint8_t i);
507} // namespace ada::character_sets
508
509#endif // ADA_CHARACTER_SETS_H
510/* end file include/ada/character_sets.h */
511
517namespace ada::character_sets {
518
519constexpr char hex[1024] =
520 "%00\0%01\0%02\0%03\0%04\0%05\0%06\0%07\0"
521 "%08\0%09\0%0A\0%0B\0%0C\0%0D\0%0E\0%0F\0"
522 "%10\0%11\0%12\0%13\0%14\0%15\0%16\0%17\0"
523 "%18\0%19\0%1A\0%1B\0%1C\0%1D\0%1E\0%1F\0"
524 "%20\0%21\0%22\0%23\0%24\0%25\0%26\0%27\0"
525 "%28\0%29\0%2A\0%2B\0%2C\0%2D\0%2E\0%2F\0"
526 "%30\0%31\0%32\0%33\0%34\0%35\0%36\0%37\0"
527 "%38\0%39\0%3A\0%3B\0%3C\0%3D\0%3E\0%3F\0"
528 "%40\0%41\0%42\0%43\0%44\0%45\0%46\0%47\0"
529 "%48\0%49\0%4A\0%4B\0%4C\0%4D\0%4E\0%4F\0"
530 "%50\0%51\0%52\0%53\0%54\0%55\0%56\0%57\0"
531 "%58\0%59\0%5A\0%5B\0%5C\0%5D\0%5E\0%5F\0"
532 "%60\0%61\0%62\0%63\0%64\0%65\0%66\0%67\0"
533 "%68\0%69\0%6A\0%6B\0%6C\0%6D\0%6E\0%6F\0"
534 "%70\0%71\0%72\0%73\0%74\0%75\0%76\0%77\0"
535 "%78\0%79\0%7A\0%7B\0%7C\0%7D\0%7E\0%7F\0"
536 "%80\0%81\0%82\0%83\0%84\0%85\0%86\0%87\0"
537 "%88\0%89\0%8A\0%8B\0%8C\0%8D\0%8E\0%8F\0"
538 "%90\0%91\0%92\0%93\0%94\0%95\0%96\0%97\0"
539 "%98\0%99\0%9A\0%9B\0%9C\0%9D\0%9E\0%9F\0"
540 "%A0\0%A1\0%A2\0%A3\0%A4\0%A5\0%A6\0%A7\0"
541 "%A8\0%A9\0%AA\0%AB\0%AC\0%AD\0%AE\0%AF\0"
542 "%B0\0%B1\0%B2\0%B3\0%B4\0%B5\0%B6\0%B7\0"
543 "%B8\0%B9\0%BA\0%BB\0%BC\0%BD\0%BE\0%BF\0"
544 "%C0\0%C1\0%C2\0%C3\0%C4\0%C5\0%C6\0%C7\0"
545 "%C8\0%C9\0%CA\0%CB\0%CC\0%CD\0%CE\0%CF\0"
546 "%D0\0%D1\0%D2\0%D3\0%D4\0%D5\0%D6\0%D7\0"
547 "%D8\0%D9\0%DA\0%DB\0%DC\0%DD\0%DE\0%DF\0"
548 "%E0\0%E1\0%E2\0%E3\0%E4\0%E5\0%E6\0%E7\0"
549 "%E8\0%E9\0%EA\0%EB\0%EC\0%ED\0%EE\0%EF\0"
550 "%F0\0%F1\0%F2\0%F3\0%F4\0%F5\0%F6\0%F7\0"
551 "%F8\0%F9\0%FA\0%FB\0%FC\0%FD\0%FE\0%FF";
552
553constexpr uint8_t C0_CONTROL_PERCENT_ENCODE[32] = {
554 // 00 01 02 03 04 05 06 07
555 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
556 // 08 09 0A 0B 0C 0D 0E 0F
557 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
558 // 10 11 12 13 14 15 16 17
559 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
560 // 18 19 1A 1B 1C 1D 1E 1F
561 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
562 // 20 21 22 23 24 25 26 27
563 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
564 // 28 29 2A 2B 2C 2D 2E 2F
565 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
566 // 30 31 32 33 34 35 36 37
567 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
568 // 38 39 3A 3B 3C 3D 3E 3F
569 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
570 // 40 41 42 43 44 45 46 47
571 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
572 // 48 49 4A 4B 4C 4D 4E 4F
573 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
574 // 50 51 52 53 54 55 56 57
575 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
576 // 58 59 5A 5B 5C 5D 5E 5F
577 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
578 // 60 61 62 63 64 65 66 67
579 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
580 // 68 69 6A 6B 6C 6D 6E 6F
581 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
582 // 70 71 72 73 74 75 76 77
583 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
584 // 78 79 7A 7B 7C 7D 7E 7F
585 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x80,
586 // 80 81 82 83 84 85 86 87
587 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
588 // 88 89 8A 8B 8C 8D 8E 8F
589 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
590 // 90 91 92 93 94 95 96 97
591 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
592 // 98 99 9A 9B 9C 9D 9E 9F
593 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
594 // A0 A1 A2 A3 A4 A5 A6 A7
595 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
596 // A8 A9 AA AB AC AD AE AF
597 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
598 // B0 B1 B2 B3 B4 B5 B6 B7
599 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
600 // B8 B9 BA BB BC BD BE BF
601 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
602 // C0 C1 C2 C3 C4 C5 C6 C7
603 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
604 // C8 C9 CA CB CC CD CE CF
605 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
606 // D0 D1 D2 D3 D4 D5 D6 D7
607 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
608 // D8 D9 DA DB DC DD DE DF
609 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
610 // E0 E1 E2 E3 E4 E5 E6 E7
611 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
612 // E8 E9 EA EB EC ED EE EF
613 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
614 // F0 F1 F2 F3 F4 F5 F6 F7
615 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
616 // F8 F9 FA FB FC FD FE FF
617 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80};
618
619constexpr uint8_t SPECIAL_QUERY_PERCENT_ENCODE[32] = {
620 // 00 01 02 03 04 05 06 07
621 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
622 // 08 09 0A 0B 0C 0D 0E 0F
623 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
624 // 10 11 12 13 14 15 16 17
625 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
626 // 18 19 1A 1B 1C 1D 1E 1F
627 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
628 // 20 21 22 23 24 25 26 27
629 0x01 | 0x00 | 0x04 | 0x08 | 0x00 | 0x00 | 0x00 | 0x80,
630 // 28 29 2A 2B 2C 2D 2E 2F
631 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
632 // 30 31 32 33 34 35 36 37
633 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
634 // 38 39 3A 3B 3C 3D 3E 3F
635 0x00 | 0x00 | 0x00 | 0x00 | 0x10 | 0x00 | 0x40 | 0x00,
636 // 40 41 42 43 44 45 46 47
637 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
638 // 48 49 4A 4B 4C 4D 4E 4F
639 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
640 // 50 51 52 53 54 55 56 57
641 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
642 // 58 59 5A 5B 5C 5D 5E 5F
643 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
644 // 60 61 62 63 64 65 66 67
645 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
646 // 68 69 6A 6B 6C 6D 6E 6F
647 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
648 // 70 71 72 73 74 75 76 77
649 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
650 // 78 79 7A 7B 7C 7D 7E 7F
651 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x80,
652 // 80 81 82 83 84 85 86 87
653 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
654 // 88 89 8A 8B 8C 8D 8E 8F
655 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
656 // 90 91 92 93 94 95 96 97
657 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
658 // 98 99 9A 9B 9C 9D 9E 9F
659 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
660 // A0 A1 A2 A3 A4 A5 A6 A7
661 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
662 // A8 A9 AA AB AC AD AE AF
663 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
664 // B0 B1 B2 B3 B4 B5 B6 B7
665 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
666 // B8 B9 BA BB BC BD BE BF
667 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
668 // C0 C1 C2 C3 C4 C5 C6 C7
669 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
670 // C8 C9 CA CB CC CD CE CF
671 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
672 // D0 D1 D2 D3 D4 D5 D6 D7
673 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
674 // D8 D9 DA DB DC DD DE DF
675 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
676 // E0 E1 E2 E3 E4 E5 E6 E7
677 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
678 // E8 E9 EA EB EC ED EE EF
679 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
680 // F0 F1 F2 F3 F4 F5 F6 F7
681 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
682 // F8 F9 FA FB FC FD FE FF
683 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80};
684
685constexpr uint8_t QUERY_PERCENT_ENCODE[32] = {
686 // 00 01 02 03 04 05 06 07
687 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
688 // 08 09 0A 0B 0C 0D 0E 0F
689 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
690 // 10 11 12 13 14 15 16 17
691 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
692 // 18 19 1A 1B 1C 1D 1E 1F
693 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
694 // 20 21 22 23 24 25 26 27
695 0x01 | 0x00 | 0x04 | 0x08 | 0x00 | 0x00 | 0x00 | 0x00,
696 // 28 29 2A 2B 2C 2D 2E 2F
697 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
698 // 30 31 32 33 34 35 36 37
699 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
700 // 38 39 3A 3B 3C 3D 3E 3F
701 0x00 | 0x00 | 0x00 | 0x00 | 0x10 | 0x00 | 0x40 | 0x00,
702 // 40 41 42 43 44 45 46 47
703 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
704 // 48 49 4A 4B 4C 4D 4E 4F
705 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
706 // 50 51 52 53 54 55 56 57
707 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
708 // 58 59 5A 5B 5C 5D 5E 5F
709 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
710 // 60 61 62 63 64 65 66 67
711 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
712 // 68 69 6A 6B 6C 6D 6E 6F
713 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
714 // 70 71 72 73 74 75 76 77
715 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
716 // 78 79 7A 7B 7C 7D 7E 7F
717 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x80,
718 // 80 81 82 83 84 85 86 87
719 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
720 // 88 89 8A 8B 8C 8D 8E 8F
721 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
722 // 90 91 92 93 94 95 96 97
723 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
724 // 98 99 9A 9B 9C 9D 9E 9F
725 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
726 // A0 A1 A2 A3 A4 A5 A6 A7
727 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
728 // A8 A9 AA AB AC AD AE AF
729 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
730 // B0 B1 B2 B3 B4 B5 B6 B7
731 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
732 // B8 B9 BA BB BC BD BE BF
733 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
734 // C0 C1 C2 C3 C4 C5 C6 C7
735 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
736 // C8 C9 CA CB CC CD CE CF
737 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
738 // D0 D1 D2 D3 D4 D5 D6 D7
739 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
740 // D8 D9 DA DB DC DD DE DF
741 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
742 // E0 E1 E2 E3 E4 E5 E6 E7
743 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
744 // E8 E9 EA EB EC ED EE EF
745 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
746 // F0 F1 F2 F3 F4 F5 F6 F7
747 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
748 // F8 F9 FA FB FC FD FE FF
749 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80};
750
751constexpr uint8_t FRAGMENT_PERCENT_ENCODE[32] = {
752 // 00 01 02 03 04 05 06 07
753 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
754 // 08 09 0A 0B 0C 0D 0E 0F
755 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
756 // 10 11 12 13 14 15 16 17
757 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
758 // 18 19 1A 1B 1C 1D 1E 1F
759 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
760 // 20 21 22 23 24 25 26 27
761 0x01 | 0x00 | 0x04 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
762 // 28 29 2A 2B 2C 2D 2E 2F
763 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
764 // 30 31 32 33 34 35 36 37
765 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
766 // 38 39 3A 3B 3C 3D 3E 3F
767 0x00 | 0x00 | 0x00 | 0x00 | 0x10 | 0x00 | 0x40 | 0x00,
768 // 40 41 42 43 44 45 46 47
769 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
770 // 48 49 4A 4B 4C 4D 4E 4F
771 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
772 // 50 51 52 53 54 55 56 57
773 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
774 // 58 59 5A 5B 5C 5D 5E 5F
775 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
776 // 60 61 62 63 64 65 66 67
777 0x01 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
778 // 68 69 6A 6B 6C 6D 6E 6F
779 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
780 // 70 71 72 73 74 75 76 77
781 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
782 // 78 79 7A 7B 7C 7D 7E 7F
783 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x80,
784 // 80 81 82 83 84 85 86 87
785 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
786 // 88 89 8A 8B 8C 8D 8E 8F
787 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
788 // 90 91 92 93 94 95 96 97
789 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
790 // 98 99 9A 9B 9C 9D 9E 9F
791 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
792 // A0 A1 A2 A3 A4 A5 A6 A7
793 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
794 // A8 A9 AA AB AC AD AE AF
795 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
796 // B0 B1 B2 B3 B4 B5 B6 B7
797 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
798 // B8 B9 BA BB BC BD BE BF
799 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
800 // C0 C1 C2 C3 C4 C5 C6 C7
801 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
802 // C8 C9 CA CB CC CD CE CF
803 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
804 // D0 D1 D2 D3 D4 D5 D6 D7
805 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
806 // D8 D9 DA DB DC DD DE DF
807 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
808 // E0 E1 E2 E3 E4 E5 E6 E7
809 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
810 // E8 E9 EA EB EC ED EE EF
811 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
812 // F0 F1 F2 F3 F4 F5 F6 F7
813 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
814 // F8 F9 FA FB FC FD FE FF
815 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80};
816
817constexpr uint8_t USERINFO_PERCENT_ENCODE[32] = {
818 // 00 01 02 03 04 05 06 07
819 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
820 // 08 09 0A 0B 0C 0D 0E 0F
821 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
822 // 10 11 12 13 14 15 16 17
823 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
824 // 18 19 1A 1B 1C 1D 1E 1F
825 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
826 // 20 21 22 23 24 25 26 27
827 0x01 | 0x00 | 0x04 | 0x08 | 0x00 | 0x00 | 0x00 | 0x00,
828 // 28 29 2A 2B 2C 2D 2E 2F
829 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x80,
830 // 30 31 32 33 34 35 36 37
831 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
832 // 38 39 3A 3B 3C 3D 3E 3F
833 0x00 | 0x00 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
834 // 40 41 42 43 44 45 46 47
835 0x01 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
836 // 48 49 4A 4B 4C 4D 4E 4F
837 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
838 // 50 51 52 53 54 55 56 57
839 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
840 // 58 59 5A 5B 5C 5D 5E 5F
841 0x00 | 0x00 | 0x00 | 0x08 | 0x10 | 0x20 | 0x40 | 0x00,
842 // 60 61 62 63 64 65 66 67
843 0x01 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
844 // 68 69 6A 6B 6C 6D 6E 6F
845 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
846 // 70 71 72 73 74 75 76 77
847 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
848 // 78 79 7A 7B 7C 7D 7E 7F
849 0x00 | 0x00 | 0x00 | 0x08 | 0x10 | 0x20 | 0x00 | 0x80,
850 // 80 81 82 83 84 85 86 87
851 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
852 // 88 89 8A 8B 8C 8D 8E 8F
853 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
854 // 90 91 92 93 94 95 96 97
855 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
856 // 98 99 9A 9B 9C 9D 9E 9F
857 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
858 // A0 A1 A2 A3 A4 A5 A6 A7
859 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
860 // A8 A9 AA AB AC AD AE AF
861 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
862 // B0 B1 B2 B3 B4 B5 B6 B7
863 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
864 // B8 B9 BA BB BC BD BE BF
865 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
866 // C0 C1 C2 C3 C4 C5 C6 C7
867 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
868 // C8 C9 CA CB CC CD CE CF
869 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
870 // D0 D1 D2 D3 D4 D5 D6 D7
871 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
872 // D8 D9 DA DB DC DD DE DF
873 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
874 // E0 E1 E2 E3 E4 E5 E6 E7
875 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
876 // E8 E9 EA EB EC ED EE EF
877 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
878 // F0 F1 F2 F3 F4 F5 F6 F7
879 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
880 // F8 F9 FA FB FC FD FE FF
881 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80};
882
883constexpr uint8_t PATH_PERCENT_ENCODE[32] = {
884 // 00 01 02 03 04 05 06 07
885 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
886 // 08 09 0A 0B 0C 0D 0E 0F
887 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
888 // 10 11 12 13 14 15 16 17
889 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
890 // 18 19 1A 1B 1C 1D 1E 1F
891 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
892 // 20 21 22 23 24 25 26 27
893 0x01 | 0x00 | 0x04 | 0x08 | 0x00 | 0x00 | 0x00 | 0x00,
894 // 28 29 2A 2B 2C 2D 2E 2F
895 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
896 // 30 31 32 33 34 35 36 37
897 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
898 // 38 39 3A 3B 3C 3D 3E 3F
899 0x00 | 0x00 | 0x00 | 0x00 | 0x10 | 0x00 | 0x40 | 0x80,
900 // 40 41 42 43 44 45 46 47
901 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
902 // 48 49 4A 4B 4C 4D 4E 4F
903 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
904 // 50 51 52 53 54 55 56 57
905 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
906 // 58 59 5A 5B 5C 5D 5E 5F
907 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
908 // 60 61 62 63 64 65 66 67
909 0x01 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
910 // 68 69 6A 6B 6C 6D 6E 6F
911 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
912 // 70 71 72 73 74 75 76 77
913 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
914 // 78 79 7A 7B 7C 7D 7E 7F
915 0x00 | 0x00 | 0x00 | 0x08 | 0x00 | 0x20 | 0x00 | 0x80,
916 // 80 81 82 83 84 85 86 87
917 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
918 // 88 89 8A 8B 8C 8D 8E 8F
919 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
920 // 90 91 92 93 94 95 96 97
921 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
922 // 98 99 9A 9B 9C 9D 9E 9F
923 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
924 // A0 A1 A2 A3 A4 A5 A6 A7
925 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
926 // A8 A9 AA AB AC AD AE AF
927 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
928 // B0 B1 B2 B3 B4 B5 B6 B7
929 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
930 // B8 B9 BA BB BC BD BE BF
931 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
932 // C0 C1 C2 C3 C4 C5 C6 C7
933 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
934 // C8 C9 CA CB CC CD CE CF
935 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
936 // D0 D1 D2 D3 D4 D5 D6 D7
937 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
938 // D8 D9 DA DB DC DD DE DF
939 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
940 // E0 E1 E2 E3 E4 E5 E6 E7
941 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
942 // E8 E9 EA EB EC ED EE EF
943 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
944 // F0 F1 F2 F3 F4 F5 F6 F7
945 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
946 // F8 F9 FA FB FC FD FE FF
947 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80};
948
949constexpr uint8_t WWW_FORM_URLENCODED_PERCENT_ENCODE[32] = {
950 // 00 01 02 03 04 05 06 07
951 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
952 // 08 09 0A 0B 0C 0D 0E 0F
953 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
954 // 10 11 12 13 14 15 16 17
955 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
956 // 18 19 1A 1B 1C 1D 1E 1F
957 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
958 // 20 21 22 23 24 25 26 27
959 0x00 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
960 // 28 29 2A 2B 2C 2D 2E 2F
961 0x01 | 0x02 | 0x00 | 0x08 | 0x10 | 0x00 | 0x00 | 0x80,
962 // 30 31 32 33 34 35 36 37
963 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
964 // 38 39 3A 3B 3C 3D 3E 3F
965 0x00 | 0x00 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
966 // 40 41 42 43 44 45 46 47
967 0x01 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
968 // 48 49 4A 4B 4C 4D 4E 4F
969 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
970 // 50 51 52 53 54 55 56 57
971 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
972 // 58 59 5A 5B 5C 5D 5E 5F
973 0x00 | 0x00 | 0x00 | 0x08 | 0x00 | 0x20 | 0x40 | 0x00,
974 // 60 61 62 63 64 65 66 67
975 0x01 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
976 // 68 69 6A 6B 6C 6D 6E 6F
977 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
978 // 70 71 72 73 74 75 76 77
979 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
980 // 78 79 7A 7B 7C 7D 7E 7F
981 0x00 | 0x00 | 0x00 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
982 // 80 81 82 83 84 85 86 87
983 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
984 // 88 89 8A 8B 8C 8D 8E 8F
985 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
986 // 90 91 92 93 94 95 96 97
987 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
988 // 98 99 9A 9B 9C 9D 9E 9F
989 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
990 // A0 A1 A2 A3 A4 A5 A6 A7
991 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
992 // A8 A9 AA AB AC AD AE AF
993 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
994 // B0 B1 B2 B3 B4 B5 B6 B7
995 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
996 // B8 B9 BA BB BC BD BE BF
997 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
998 // C0 C1 C2 C3 C4 C5 C6 C7
999 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
1000 // C8 C9 CA CB CC CD CE CF
1001 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
1002 // D0 D1 D2 D3 D4 D5 D6 D7
1003 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
1004 // D8 D9 DA DB DC DD DE DF
1005 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
1006 // E0 E1 E2 E3 E4 E5 E6 E7
1007 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
1008 // E8 E9 EA EB EC ED EE EF
1009 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
1010 // F0 F1 F2 F3 F4 F5 F6 F7
1011 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
1012 // F8 F9 FA FB FC FD FE FF
1013 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80};
1014
1015ada_really_inline bool bit_at(const uint8_t a[], const uint8_t i) {
1016 return !!(a[i >> 3] & (1 << (i & 7)));
1017}
1018
1019} // namespace ada::character_sets
1020
1021#endif // ADA_CHARACTER_SETS_INL_H
1022/* end file include/ada/character_sets-inl.h */
1023/* begin file include/ada/checkers-inl.h */
1028#ifndef ADA_CHECKERS_INL_H
1029#define ADA_CHECKERS_INL_H
1030
1031
1032#include <algorithm>
1033#include <string_view>
1034#include <cstring>
1035
1036namespace ada::checkers {
1037
1038inline bool has_hex_prefix_unsafe(std::string_view input) {
1039 // This is actually efficient code, see has_hex_prefix for the assembly.
1040 uint32_t value_one = 1;
1041 bool is_little_endian = (reinterpret_cast<char*>(&value_one)[0] == 1);
1042 uint16_t word0x{};
1043 std::memcpy(&word0x, "0x", 2); // we would use bit_cast in C++20 and the
1044 // function could be constexpr.
1045 uint16_t two_first_bytes{};
1046 std::memcpy(&two_first_bytes, input.data(), 2);
1047 if (is_little_endian) {
1048 two_first_bytes |= 0x2000;
1049 } else {
1050 two_first_bytes |= 0x020;
1051 }
1052 return two_first_bytes == word0x;
1053}
1054
1055inline bool has_hex_prefix(std::string_view input) {
1056 return input.size() >= 2 && has_hex_prefix_unsafe(input);
1057}
1058
1059constexpr bool is_digit(char x) noexcept { return (x >= '0') & (x <= '9'); }
1060
1061constexpr char to_lower(char x) noexcept { return (x | 0x20); }
1062
1063constexpr bool is_alpha(char x) noexcept {
1064 return (to_lower(x) >= 'a') && (to_lower(x) <= 'z');
1065}
1066
1067inline constexpr bool is_windows_drive_letter(std::string_view input) noexcept {
1068 return input.size() >= 2 &&
1069 (is_alpha(input[0]) && ((input[1] == ':') || (input[1] == '|'))) &&
1070 ((input.size() == 2) || (input[2] == '/' || input[2] == '\\' ||
1071 input[2] == '?' || input[2] == '#'));
1072}
1073
1074inline constexpr bool is_normalized_windows_drive_letter(
1075 std::string_view input) noexcept {
1076 return input.size() >= 2 && (is_alpha(input[0]) && (input[1] == ':'));
1077}
1078
1079ada_really_inline bool begins_with(std::string_view view,
1080 std::string_view prefix) {
1081 // in C++20, you have view.begins_with(prefix)
1082 // std::equal is constexpr in C++20
1083 return view.size() >= prefix.size() &&
1084 std::equal(prefix.begin(), prefix.end(), view.begin());
1085}
1086
1087} // namespace ada::checkers
1088
1089#endif // ADA_CHECKERS_INL_H
1090/* end file include/ada/checkers-inl.h */
1091/* begin file include/ada/log.h */
1097#ifndef ADA_LOG_H
1098#define ADA_LOG_H
1099
1100#include <iostream>
1101// To enable logging, set ADA_LOGGING to 1:
1102#ifndef ADA_LOGGING
1103#define ADA_LOGGING 0
1104#endif
1105
1106namespace ada {
1107
1112template <typename T>
1113ada_really_inline void inner_log([[maybe_unused]] T t) {
1114#if ADA_LOGGING
1115 std::cout << t << std::endl;
1116#endif
1117}
1118
1123template <typename T, typename... Args>
1124ada_really_inline void inner_log([[maybe_unused]] T t,
1125 [[maybe_unused]] Args... args) {
1126#if ADA_LOGGING
1127 std::cout << t;
1128 inner_log(args...);
1129#endif
1130}
1131
1136template <typename T, typename... Args>
1137ada_really_inline void log([[maybe_unused]] T t,
1138 [[maybe_unused]] Args... args) {
1139#if ADA_LOGGING
1140 std::cout << "ADA_LOG: " << t;
1141 inner_log(args...);
1142#endif
1143}
1144
1149template <typename T>
1150ada_really_inline void log([[maybe_unused]] T t) {
1151#if ADA_LOGGING
1152 std::cout << "ADA_LOG: " << t << std::endl;
1153#endif
1154}
1155} // namespace ada
1156
1157#if ADA_LOGGING
1158
1159#ifndef ada_log
1160#define ada_log(...) \
1161 do { \
1162 ada::log(__VA_ARGS__); \
1163 } while (0)
1164#endif // ada_log
1165#else
1166#define ada_log(...)
1167#endif // ADA_LOGGING
1168
1169#endif // ADA_LOG_H
1170/* end file include/ada/log.h */
1171/* begin file include/ada/encoding_type.h */
1176#ifndef ADA_ENCODING_TYPE_H
1177#define ADA_ENCODING_TYPE_H
1178
1179#include <string>
1180
1181namespace ada {
1182
1189enum class encoding_type {
1190 UTF8,
1191 UTF_16LE,
1192 UTF_16BE,
1193};
1194
1198ada_warn_unused std::string to_string(encoding_type type);
1199
1200} // namespace ada
1201
1202#endif // ADA_ENCODING_TYPE_H
1203/* end file include/ada/encoding_type.h */
1204/* begin file include/ada/helpers.h */
1209#ifndef ADA_HELPERS_H
1210#define ADA_HELPERS_H
1211
1212/* begin file include/ada/state.h */
1217#ifndef ADA_STATE_H
1218#define ADA_STATE_H
1219
1220
1221#include <string>
1222
1223namespace ada {
1224
1228enum class state {
1232 AUTHORITY,
1233
1238
1242 SCHEME,
1243
1247 HOST,
1248
1252 NO_SCHEME,
1253
1257 FRAGMENT,
1258
1263
1268
1272 FILE,
1273
1277 FILE_HOST,
1278
1282 FILE_SLASH,
1283
1288
1293
1298
1303
1307 QUERY,
1308
1312 PATH,
1313
1317 PATH_START,
1318
1323
1327 PORT,
1328};
1329
1333ada_warn_unused std::string to_string(ada::state s);
1334
1335} // namespace ada
1336
1337#endif // ADA_STATE_H
1338/* end file include/ada/state.h */
1339/* begin file include/ada/url_base.h */
1344#ifndef ADA_URL_BASE_H
1345#define ADA_URL_BASE_H
1346
1347/* begin file include/ada/url_components.h */
1352#ifndef ADA_URL_COMPONENTS_H
1353#define ADA_URL_COMPONENTS_H
1354
1355
1356#include <optional>
1357#include <string_view>
1358
1359namespace ada {
1360
1370 constexpr static uint32_t omitted = uint32_t(-1);
1371
1372 url_components() = default;
1373 url_components(const url_components &u) = default;
1374 url_components(url_components &&u) noexcept = default;
1375 url_components &operator=(url_components &&u) noexcept = default;
1377 ~url_components() = default;
1378
1379 /*
1380 * By using 32-bit integers, we implicitly assume that the URL string
1381 * cannot exceed 4 GB.
1382 *
1383 * https://user:pass@example.com:1234/foo/bar?baz#quux
1384 * | | | | ^^^^| | |
1385 * | | | | | | | `----- hash_start
1386 * | | | | | | `--------- search_start
1387 * | | | | | `----------------- pathname_start
1388 * | | | | `--------------------- port
1389 * | | | `----------------------- host_end
1390 * | | `---------------------------------- host_start
1391 * | `--------------------------------------- username_end
1392 * `--------------------------------------------- protocol_end
1393 */
1394 uint32_t protocol_end{0};
1399 uint32_t username_end{0};
1400 uint32_t host_start{0};
1401 uint32_t host_end{0};
1402 uint32_t port{omitted};
1403 uint32_t pathname_start{0};
1404 uint32_t search_start{omitted};
1405 uint32_t hash_start{omitted};
1406
1416 [[nodiscard]] bool check_offset_consistency() const noexcept;
1417
1421 [[nodiscard]] std::string to_string() const;
1422
1423}; // struct url_components
1424
1425} // namespace ada
1426#endif
1427/* end file include/ada/url_components.h */
1428/* begin file include/ada/scheme.h */
1433#ifndef ADA_SCHEME_H
1434#define ADA_SCHEME_H
1435
1436
1437#include <array>
1438#include <optional>
1439#include <string>
1440
1445namespace ada::scheme {
1446
1457enum type : uint8_t {
1458 HTTP = 0,
1459 NOT_SPECIAL = 1,
1460 HTTPS = 2,
1461 WS = 3,
1462 FTP = 4,
1463 WSS = 5,
1464 FILE = 6
1465};
1466
1477ada_really_inline constexpr bool is_special(std::string_view scheme);
1478
1489constexpr uint16_t get_special_port(std::string_view scheme) noexcept;
1490
1495constexpr uint16_t get_special_port(ada::scheme::type type) noexcept;
1500constexpr ada::scheme::type get_scheme_type(std::string_view scheme) noexcept;
1501
1502} // namespace ada::scheme
1503
1504#endif // ADA_SCHEME_H
1505/* end file include/ada/scheme.h */
1506
1507#include <string_view>
1508
1509namespace ada {
1510
1514enum url_host_type : uint8_t {
1518 DEFAULT = 0,
1522 IPV4 = 1,
1527 IPV6 = 2,
1528};
1529
1539struct url_base {
1540 virtual ~url_base() = default;
1541
1545 bool is_valid{true};
1546
1550 bool has_opaque_path{false};
1551
1555 url_host_type host_type = url_host_type::DEFAULT;
1556
1560 ada::scheme::type type{ada::scheme::type::NOT_SPECIAL};
1561
1566 [[nodiscard]] ada_really_inline bool is_special() const noexcept;
1567
1574 [[nodiscard]] virtual std::string get_origin() const noexcept = 0;
1575
1581 [[nodiscard]] virtual bool has_valid_domain() const noexcept = 0;
1582
1589 [[nodiscard]] inline uint16_t get_special_port() const noexcept;
1590
1596 [[nodiscard]] ada_really_inline uint16_t scheme_default_port() const noexcept;
1597
1609 virtual size_t parse_port(std::string_view view,
1610 bool check_trailing_content) noexcept = 0;
1611
1612 virtual ada_really_inline size_t parse_port(std::string_view view) noexcept {
1613 return this->parse_port(view, false);
1614 }
1615
1619 [[nodiscard]] virtual std::string to_string() const = 0;
1620
1622 virtual inline void clear_pathname() = 0;
1623
1625 virtual inline void clear_search() = 0;
1626
1628 [[nodiscard]] virtual inline bool has_hash() const noexcept = 0;
1629
1631 [[nodiscard]] virtual inline bool has_search() const noexcept = 0;
1632
1633}; // url_base
1634
1635} // namespace ada
1636
1637#endif
1638/* end file include/ada/url_base.h */
1639
1640#include <string_view>
1641#include <optional>
1642
1651namespace ada::helpers {
1652
1656template <typename out_iter>
1657void encode_json(std::string_view view, out_iter out);
1658
1672ada_really_inline std::optional<std::string_view> prune_hash(
1673 std::string_view& input) noexcept;
1674
1681ada_really_inline bool shorten_path(std::string& path,
1682 ada::scheme::type type) noexcept;
1683
1690ada_really_inline bool shorten_path(std::string_view& path,
1691 ada::scheme::type type) noexcept;
1692
1704ada_really_inline void parse_prepared_path(std::string_view input,
1705 ada::scheme::type type,
1706 std::string& path);
1707
1712ada_really_inline void remove_ascii_tab_or_newline(std::string& input) noexcept;
1713
1719ada_really_inline std::string_view substring(std::string_view input,
1720 size_t pos) noexcept;
1721
1726bool overlaps(std::string_view input1, const std::string& input2) noexcept;
1727
1733ada_really_inline std::string_view substring(const std::string& input,
1734 size_t pos1,
1735 size_t pos2) noexcept {
1736#if ADA_DEVELOPMENT_CHECKS
1737 if (pos2 < pos1) {
1738 std::cerr << "Negative-length substring: [" << pos1 << " to " << pos2 << ")"
1739 << std::endl;
1740 abort();
1741 }
1742#endif
1743 return std::string_view(input.data() + pos1, pos2 - pos1);
1744}
1745
1751ada_really_inline void resize(std::string_view& input, size_t pos) noexcept;
1752
1758ada_really_inline std::pair<size_t, bool> get_host_delimiter_location(
1759 const bool is_special, std::string_view& view) noexcept;
1760
1766ada_really_inline void trim_c0_whitespace(std::string_view& input) noexcept;
1767
1773template <class url_type>
1774ada_really_inline void strip_trailing_spaces_from_opaque_path(
1775 url_type& url) noexcept;
1776
1781ada_really_inline size_t
1782find_authority_delimiter_special(std::string_view view) noexcept;
1783
1788ada_really_inline size_t
1789find_authority_delimiter(std::string_view view) noexcept;
1790
1794template <typename T, typename... Args>
1795inline void inner_concat(std::string& buffer, T t) {
1796 buffer.append(t);
1797}
1798
1802template <typename T, typename... Args>
1803inline void inner_concat(std::string& buffer, T t, Args... args) {
1804 buffer.append(t);
1805 return inner_concat(buffer, args...);
1806}
1807
1813template <typename... Args>
1814std::string concat(Args... args) {
1815 std::string answer;
1816 inner_concat(answer, args...);
1817 return answer;
1818}
1819
1824inline int leading_zeroes(uint32_t input_num) noexcept {
1825#if ADA_REGULAR_VISUAL_STUDIO
1826 unsigned long leading_zero(0);
1827 unsigned long in(input_num);
1828 return _BitScanReverse(&leading_zero, in) ? int(31 - leading_zero) : 32;
1829#else
1830 return __builtin_clz(input_num);
1831#endif // ADA_REGULAR_VISUAL_STUDIO
1832}
1833
1840inline int fast_digit_count(uint32_t x) noexcept {
1841 auto int_log2 = [](uint32_t z) -> int {
1842 return 31 - ada::helpers::leading_zeroes(z | 1);
1843 };
1844 // Compiles to very few instructions. Note that the
1845 // table is static and thus effectively a constant.
1846 // We leave it inside the function because it is meaningless
1847 // outside of it (this comes at no performance cost).
1848 const static uint64_t table[] = {
1849 4294967296, 8589934582, 8589934582, 8589934582, 12884901788,
1850 12884901788, 12884901788, 17179868184, 17179868184, 17179868184,
1851 21474826480, 21474826480, 21474826480, 21474826480, 25769703776,
1852 25769703776, 25769703776, 30063771072, 30063771072, 30063771072,
1853 34349738368, 34349738368, 34349738368, 34349738368, 38554705664,
1854 38554705664, 38554705664, 41949672960, 41949672960, 41949672960,
1855 42949672960, 42949672960};
1856 return int((x + table[int_log2(x)]) >> 32);
1857}
1858} // namespace ada::helpers
1859
1860#endif // ADA_HELPERS_H
1861/* end file include/ada/helpers.h */
1862/* begin file include/ada/parser.h */
1867#ifndef ADA_PARSER_H
1868#define ADA_PARSER_H
1869
1870#include <optional>
1871#include <string_view>
1872
1873/* begin file include/ada/expected.h */
1880// expected - An implementation of std::expected with extensions
1881// Written in 2017 by Sy Brand (tartanllama@gmail.com, @TartanLlama)
1882//
1883// Documentation available at http://tl.tartanllama.xyz/
1884//
1885// To the extent possible under law, the author(s) have dedicated all
1886// copyright and related and neighboring rights to this software to the
1887// public domain worldwide. This software is distributed without any warranty.
1888//
1889// You should have received a copy of the CC0 Public Domain Dedication
1890// along with this software. If not, see
1891// <http://creativecommons.org/publicdomain/zero/1.0/>.
1893
1894#ifndef TL_EXPECTED_HPP
1895#define TL_EXPECTED_HPP
1896
1897#define TL_EXPECTED_VERSION_MAJOR 1
1898#define TL_EXPECTED_VERSION_MINOR 1
1899#define TL_EXPECTED_VERSION_PATCH 0
1900
1901#include <exception>
1902#include <functional>
1903#include <type_traits>
1904#include <utility>
1905
1906#if defined(__EXCEPTIONS) || defined(_CPPUNWIND)
1907#define TL_EXPECTED_EXCEPTIONS_ENABLED
1908#endif
1909
1910#if (defined(_MSC_VER) && _MSC_VER == 1900)
1911#define TL_EXPECTED_MSVC2015
1912#define TL_EXPECTED_MSVC2015_CONSTEXPR
1913#else
1914#define TL_EXPECTED_MSVC2015_CONSTEXPR constexpr
1915#endif
1916
1917#if (defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ <= 9 && \
1918 !defined(__clang__))
1919#define TL_EXPECTED_GCC49
1920#endif
1921
1922#if (defined(__GNUC__) && __GNUC__ == 5 && __GNUC_MINOR__ <= 4 && \
1923 !defined(__clang__))
1924#define TL_EXPECTED_GCC54
1925#endif
1926
1927#if (defined(__GNUC__) && __GNUC__ == 5 && __GNUC_MINOR__ <= 5 && \
1928 !defined(__clang__))
1929#define TL_EXPECTED_GCC55
1930#endif
1931
1932#if !defined(TL_ASSERT)
1933// can't have assert in constexpr in C++11 and GCC 4.9 has a compiler bug
1934#if (__cplusplus > 201103L) && !defined(TL_EXPECTED_GCC49)
1935#include <cassert>
1936#define TL_ASSERT(x) assert(x)
1937#else
1938#define TL_ASSERT(x)
1939#endif
1940#endif
1941
1942#if (defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ <= 9 && \
1943 !defined(__clang__))
1944// GCC < 5 doesn't support overloading on const&& for member functions
1945
1946#define TL_EXPECTED_NO_CONSTRR
1947// GCC < 5 doesn't support some standard C++11 type traits
1948#define TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) \
1949 std::has_trivial_copy_constructor<T>
1950#define TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(T) \
1951 std::has_trivial_copy_assign<T>
1952
1953// This one will be different for GCC 5.7 if it's ever supported
1954#define TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(T) \
1955 std::is_trivially_destructible<T>
1956
1957// GCC 5 < v < 8 has a bug in is_trivially_copy_constructible which breaks
1958// std::vector for non-copyable types
1959#elif (defined(__GNUC__) && __GNUC__ < 8 && !defined(__clang__))
1960#ifndef TL_GCC_LESS_8_TRIVIALLY_COPY_CONSTRUCTIBLE_MUTEX
1961#define TL_GCC_LESS_8_TRIVIALLY_COPY_CONSTRUCTIBLE_MUTEX
1962namespace tl {
1963namespace detail {
1964template <class T>
1965struct is_trivially_copy_constructible
1966 : std::is_trivially_copy_constructible<T> {};
1967#ifdef _GLIBCXX_VECTOR
1968template <class T, class A>
1969struct is_trivially_copy_constructible<std::vector<T, A>> : std::false_type {};
1970#endif
1971} // namespace detail
1972} // namespace tl
1973#endif
1974
1975#define TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) \
1976 tl::detail::is_trivially_copy_constructible<T>
1977#define TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(T) \
1978 std::is_trivially_copy_assignable<T>
1979#define TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(T) \
1980 std::is_trivially_destructible<T>
1981#else
1982#define TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) \
1983 std::is_trivially_copy_constructible<T>
1984#define TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(T) \
1985 std::is_trivially_copy_assignable<T>
1986#define TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(T) \
1987 std::is_trivially_destructible<T>
1988#endif
1989
1990#if __cplusplus > 201103L
1991#define TL_EXPECTED_CXX14
1992#endif
1993
1994#ifdef TL_EXPECTED_GCC49
1995#define TL_EXPECTED_GCC49_CONSTEXPR
1996#else
1997#define TL_EXPECTED_GCC49_CONSTEXPR constexpr
1998#endif
1999
2000#if (__cplusplus == 201103L || defined(TL_EXPECTED_MSVC2015) || \
2001 defined(TL_EXPECTED_GCC49))
2002#define TL_EXPECTED_11_CONSTEXPR
2003#else
2004#define TL_EXPECTED_11_CONSTEXPR constexpr
2005#endif
2006
2007namespace tl {
2008template <class T, class E>
2009class expected;
2010
2011#ifndef TL_MONOSTATE_INPLACE_MUTEX
2012#define TL_MONOSTATE_INPLACE_MUTEX
2013class monostate {};
2014
2016 explicit in_place_t() = default;
2017};
2018static constexpr in_place_t in_place{};
2019#endif
2020
2021template <class E>
2023 public:
2024 static_assert(!std::is_same<E, void>::value, "E must not be void");
2025
2026 unexpected() = delete;
2027 constexpr explicit unexpected(const E &e) : m_val(e) {}
2028
2029 constexpr explicit unexpected(E &&e) : m_val(std::move(e)) {}
2030
2031 template <class... Args, typename std::enable_if<std::is_constructible<
2032 E, Args &&...>::value>::type * = nullptr>
2033 constexpr explicit unexpected(Args &&...args)
2034 : m_val(std::forward<Args>(args)...) {}
2035 template <
2036 class U, class... Args,
2037 typename std::enable_if<std::is_constructible<
2038 E, std::initializer_list<U> &, Args &&...>::value>::type * = nullptr>
2039 constexpr explicit unexpected(std::initializer_list<U> l, Args &&...args)
2040 : m_val(l, std::forward<Args>(args)...) {}
2041
2042 constexpr const E &value() const & { return m_val; }
2043 TL_EXPECTED_11_CONSTEXPR E &value() & { return m_val; }
2044 TL_EXPECTED_11_CONSTEXPR E &&value() && { return std::move(m_val); }
2045 constexpr const E &&value() const && { return std::move(m_val); }
2046
2047 private:
2048 E m_val;
2049};
2050
2051#ifdef __cpp_deduction_guides
2052template <class E>
2053unexpected(E) -> unexpected<E>;
2054#endif
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}
2068template <class E>
2069constexpr bool operator<=(const unexpected<E> &lhs, const unexpected<E> &rhs) {
2070 return lhs.value() <= rhs.value();
2071}
2072template <class E>
2073constexpr bool operator>(const unexpected<E> &lhs, const unexpected<E> &rhs) {
2074 return lhs.value() > rhs.value();
2075}
2076template <class E>
2077constexpr bool operator>=(const unexpected<E> &lhs, const unexpected<E> &rhs) {
2078 return lhs.value() >= rhs.value();
2079}
2080
2081template <class E>
2085
2087 unexpect_t() = default;
2088};
2089static constexpr unexpect_t unexpect{};
2090
2091namespace detail {
2092template <typename E>
2094#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
2095 throw std::forward<E>(e);
2096#else
2097 (void)e;
2098#ifdef _MSC_VER
2099 __assume(0);
2100#else
2101 __builtin_unreachable();
2102#endif
2103#endif
2104}
2105
2106#ifndef TL_TRAITS_MUTEX
2107#define TL_TRAITS_MUTEX
2108// C++14-style aliases for brevity
2109template <class T>
2110using remove_const_t = typename std::remove_const<T>::type;
2111template <class T>
2112using remove_reference_t = typename std::remove_reference<T>::type;
2113template <class T>
2114using decay_t = typename std::decay<T>::type;
2115template <bool E, class T = void>
2116using enable_if_t = typename std::enable_if<E, T>::type;
2117template <bool B, class T, class F>
2118using conditional_t = typename std::conditional<B, T, F>::type;
2119
2120// std::conjunction from C++17
2121template <class...>
2122struct conjunction : std::true_type {};
2123template <class B>
2124struct conjunction<B> : B {};
2125template <class B, class... Bs>
2126struct conjunction<B, Bs...>
2127 : std::conditional<bool(B::value), conjunction<Bs...>, B>::type {};
2128
2129#if defined(_LIBCPP_VERSION) && __cplusplus == 201103L
2130#define TL_TRAITS_LIBCXX_MEM_FN_WORKAROUND
2131#endif
2132
2133// In C++11 mode, there's an issue in libc++'s std::mem_fn
2134// which results in a hard-error when using it in a noexcept expression
2135// in some cases. This is a check to workaround the common failing case.
2136#ifdef TL_TRAITS_LIBCXX_MEM_FN_WORKAROUND
2137template <class T>
2138struct is_pointer_to_non_const_member_func : std::false_type {};
2139template <class T, class Ret, class... Args>
2140struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...)>
2141 : std::true_type {};
2142template <class T, class Ret, class... Args>
2143struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...) &>
2144 : std::true_type {};
2145template <class T, class Ret, class... Args>
2146struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...) &&>
2147 : std::true_type {};
2148template <class T, class Ret, class... Args>
2149struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...) volatile>
2150 : std::true_type {};
2151template <class T, class Ret, class... Args>
2152struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...) volatile &>
2153 : std::true_type {};
2154template <class T, class Ret, class... Args>
2155struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...) volatile &&>
2156 : std::true_type {};
2157
2158template <class T>
2159struct is_const_or_const_ref : std::false_type {};
2160template <class T>
2161struct is_const_or_const_ref<T const &> : std::true_type {};
2162template <class T>
2163struct is_const_or_const_ref<T const> : std::true_type {};
2164#endif
2165
2166// std::invoke from C++17
2167// https://stackoverflow.com/questions/38288042/c11-14-invoke-workaround
2168template <
2169 typename Fn, typename... Args,
2170#ifdef TL_TRAITS_LIBCXX_MEM_FN_WORKAROUND
2171 typename = enable_if_t<!(is_pointer_to_non_const_member_func<Fn>::value &&
2172 is_const_or_const_ref<Args...>::value)>,
2173#endif
2174 typename = enable_if_t<std::is_member_pointer<decay_t<Fn>>::value>, int = 0>
2175constexpr auto invoke(Fn &&f, Args &&...args) noexcept(
2176 noexcept(std::mem_fn(f)(std::forward<Args>(args)...)))
2177 -> decltype(std::mem_fn(f)(std::forward<Args>(args)...)) {
2178 return std::mem_fn(f)(std::forward<Args>(args)...);
2179}
2180
2181template <typename Fn, typename... Args,
2182 typename = enable_if_t<!std::is_member_pointer<decay_t<Fn>>::value>>
2183constexpr auto invoke(Fn &&f, Args &&...args) noexcept(
2184 noexcept(std::forward<Fn>(f)(std::forward<Args>(args)...)))
2185 -> decltype(std::forward<Fn>(f)(std::forward<Args>(args)...)) {
2186 return std::forward<Fn>(f)(std::forward<Args>(args)...);
2187}
2188
2189// std::invoke_result from C++17
2190template <class F, class, class... Us>
2192
2193template <class F, class... Us>
2195 F,
2196 decltype(detail::invoke(std::declval<F>(), std::declval<Us>()...), void()),
2197 Us...> {
2198 using type =
2199 decltype(detail::invoke(std::declval<F>(), std::declval<Us>()...));
2200};
2201
2202template <class F, class... Us>
2203using invoke_result = invoke_result_impl<F, void, Us...>;
2204
2205template <class F, class... Us>
2206using invoke_result_t = typename invoke_result<F, Us...>::type;
2207
2208#if defined(_MSC_VER) && _MSC_VER <= 1900
2209// TODO make a version which works with MSVC 2015
2210template <class T, class U = T>
2211struct is_swappable : std::true_type {};
2212
2213template <class T, class U = T>
2214struct is_nothrow_swappable : std::true_type {};
2215#else
2216// https://stackoverflow.com/questions/26744589/what-is-a-proper-way-to-implement-is-swappable-to-test-for-the-swappable-concept
2217namespace swap_adl_tests {
2218// if swap ADL finds this then it would call std::swap otherwise (same
2219// signature)
2220struct tag {};
2221
2222template <class T>
2223tag swap(T &, T &);
2224template <class T, std::size_t N>
2225tag swap(T (&a)[N], T (&b)[N]);
2226
2227// helper functions to test if an unqualified swap is possible, and if it
2228// becomes std::swap
2229template <class, class>
2230std::false_type can_swap(...) noexcept(false);
2231template <class T, class U,
2232 class = decltype(swap(std::declval<T &>(), std::declval<U &>()))>
2233std::true_type can_swap(int) noexcept(noexcept(swap(std::declval<T &>(),
2234 std::declval<U &>())));
2235
2236template <class, class>
2237std::false_type uses_std(...);
2238template <class T, class U>
2239std::is_same<decltype(swap(std::declval<T &>(), std::declval<U &>())), tag>
2240uses_std(int);
2241
2242template <class T>
2244 : std::integral_constant<bool,
2245 std::is_nothrow_move_constructible<T>::value &&
2246 std::is_nothrow_move_assignable<T>::value> {};
2247
2248template <class T, std::size_t N>
2250
2251template <class T, class U>
2253 : std::integral_constant<bool, noexcept(can_swap<T, U>(0))> {};
2254} // namespace swap_adl_tests
2255
2256template <class T, class U = T>
2258 : std::integral_constant<
2259 bool,
2260 decltype(detail::swap_adl_tests::can_swap<T, U>(0))::value &&
2261 (!decltype(detail::swap_adl_tests::uses_std<T, U>(0))::value ||
2262 (std::is_move_assignable<T>::value &&
2263 std::is_move_constructible<T>::value))> {};
2264
2265template <class T, std::size_t N>
2266struct is_swappable<T[N], T[N]>
2267 : std::integral_constant<
2268 bool,
2269 decltype(detail::swap_adl_tests::can_swap<T[N], T[N]>(0))::value &&
2270 (!decltype(detail::swap_adl_tests::uses_std<T[N], T[N]>(
2271 0))::value ||
2272 is_swappable<T, T>::value)> {};
2273
2274template <class T, class U = T>
2276 : std::integral_constant<
2277 bool,
2278 is_swappable<T, U>::value &&
2279 ((decltype(detail::swap_adl_tests::uses_std<T, U>(0))::value &&
2280 detail::swap_adl_tests::is_std_swap_noexcept<T>::value) ||
2281 (!decltype(detail::swap_adl_tests::uses_std<T, U>(0))::value &&
2282 detail::swap_adl_tests::is_adl_swap_noexcept<T, U>::value))> {};
2283#endif
2284#endif
2285
2286// Trait for checking if a type is a tl::expected
2287template <class T>
2288struct is_expected_impl : std::false_type {};
2289template <class T, class E>
2290struct is_expected_impl<expected<T, E>> : std::true_type {};
2291template <class T>
2293
2294template <class T, class E, class U>
2296 std::is_constructible<T, U &&>::value &&
2297 !std::is_same<detail::decay_t<U>, in_place_t>::value &&
2298 !std::is_same<expected<T, E>, detail::decay_t<U>>::value &&
2299 !std::is_same<unexpected<E>, detail::decay_t<U>>::value>;
2300
2301template <class T, class E, class U, class G, class UR, class GR>
2303 std::is_constructible<T, UR>::value &&
2304 std::is_constructible<E, GR>::value &&
2305 !std::is_constructible<T, expected<U, G> &>::value &&
2306 !std::is_constructible<T, expected<U, G> &&>::value &&
2307 !std::is_constructible<T, const expected<U, G> &>::value &&
2308 !std::is_constructible<T, const expected<U, G> &&>::value &&
2309 !std::is_convertible<expected<U, G> &, T>::value &&
2310 !std::is_convertible<expected<U, G> &&, T>::value &&
2311 !std::is_convertible<const expected<U, G> &, T>::value &&
2312 !std::is_convertible<const expected<U, G> &&, T>::value>;
2313
2314template <class T, class U>
2316
2317template <class T>
2320
2321template <class T>
2324
2325template <class T>
2327
2328template <class T>
2330
2331} // namespace detail
2332
2333namespace detail {
2334struct no_init_t {};
2335static constexpr no_init_t no_init{};
2336
2337// Implements the storage of the values, and ensures that the destructor is
2338// trivial if it can be.
2339//
2340// This specialization is for where neither `T` or `E` is trivially
2341// destructible, so the destructors must be called on destruction of the
2342// `expected`
2343template <class T, class E, bool = std::is_trivially_destructible<T>::value,
2344 bool = std::is_trivially_destructible<E>::value>
2346 constexpr expected_storage_base() : m_val(T{}), m_has_val(true) {}
2347 constexpr expected_storage_base(no_init_t) : m_no_init(), m_has_val(false) {}
2348
2349 template <class... Args,
2350 detail::enable_if_t<std::is_constructible<T, Args &&...>::value> * =
2351 nullptr>
2352 constexpr expected_storage_base(in_place_t, Args &&...args)
2353 : m_val(std::forward<Args>(args)...), m_has_val(true) {}
2354
2355 template <class U, class... Args,
2356 detail::enable_if_t<std::is_constructible<
2357 T, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
2358 constexpr expected_storage_base(in_place_t, std::initializer_list<U> il,
2359 Args &&...args)
2360 : m_val(il, std::forward<Args>(args)...), m_has_val(true) {}
2361 template <class... Args,
2362 detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * =
2363 nullptr>
2364 constexpr explicit expected_storage_base(unexpect_t, Args &&...args)
2365 : m_unexpect(std::forward<Args>(args)...), m_has_val(false) {}
2366
2367 template <class U, class... Args,
2368 detail::enable_if_t<std::is_constructible<
2369 E, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
2371 std::initializer_list<U> il,
2372 Args &&...args)
2373 : m_unexpect(il, std::forward<Args>(args)...), m_has_val(false) {}
2374
2376 if (m_has_val) {
2377 m_val.~T();
2378 } else {
2379 m_unexpect.~unexpected<E>();
2380 }
2381 }
2382 union {
2386 };
2388};
2389
2390// This specialization is for when both `T` and `E` are trivially-destructible,
2391// so the destructor of the `expected` can be trivial.
2392template <class T, class E>
2394 constexpr expected_storage_base() : m_val(T{}), m_has_val(true) {}
2395 constexpr expected_storage_base(no_init_t) : m_no_init(), m_has_val(false) {}
2396
2397 template <class... Args,
2398 detail::enable_if_t<std::is_constructible<T, Args &&...>::value> * =
2399 nullptr>
2400 constexpr expected_storage_base(in_place_t, Args &&...args)
2401 : m_val(std::forward<Args>(args)...), m_has_val(true) {}
2402
2403 template <class U, class... Args,
2404 detail::enable_if_t<std::is_constructible<
2405 T, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
2406 constexpr expected_storage_base(in_place_t, std::initializer_list<U> il,
2407 Args &&...args)
2408 : m_val(il, std::forward<Args>(args)...), m_has_val(true) {}
2409 template <class... Args,
2410 detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * =
2411 nullptr>
2412 constexpr explicit expected_storage_base(unexpect_t, Args &&...args)
2413 : m_unexpect(std::forward<Args>(args)...), m_has_val(false) {}
2414
2415 template <class U, class... Args,
2416 detail::enable_if_t<std::is_constructible<
2417 E, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
2419 std::initializer_list<U> il,
2420 Args &&...args)
2421 : m_unexpect(il, std::forward<Args>(args)...), m_has_val(false) {}
2422
2424 union {
2428 };
2430};
2431
2432// T is trivial, E is not.
2433template <class T, class E>
2435 constexpr expected_storage_base() : m_val(T{}), m_has_val(true) {}
2437 : m_no_init(), m_has_val(false) {}
2438
2439 template <class... Args,
2440 detail::enable_if_t<std::is_constructible<T, Args &&...>::value> * =
2441 nullptr>
2442 constexpr expected_storage_base(in_place_t, Args &&...args)
2443 : m_val(std::forward<Args>(args)...), m_has_val(true) {}
2444
2445 template <class U, class... Args,
2446 detail::enable_if_t<std::is_constructible<
2447 T, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
2448 constexpr expected_storage_base(in_place_t, std::initializer_list<U> il,
2449 Args &&...args)
2450 : m_val(il, std::forward<Args>(args)...), m_has_val(true) {}
2451 template <class... Args,
2452 detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * =
2453 nullptr>
2454 constexpr explicit expected_storage_base(unexpect_t, Args &&...args)
2455 : m_unexpect(std::forward<Args>(args)...), m_has_val(false) {}
2456
2457 template <class U, class... Args,
2458 detail::enable_if_t<std::is_constructible<
2459 E, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
2461 std::initializer_list<U> il,
2462 Args &&...args)
2463 : m_unexpect(il, std::forward<Args>(args)...), m_has_val(false) {}
2464
2466 if (!m_has_val) {
2467 m_unexpect.~unexpected<E>();
2468 }
2469 }
2470
2471 union {
2475 };
2477};
2478
2479// E is trivial, T is not.
2480template <class T, class E>
2482 constexpr expected_storage_base() : m_val(T{}), m_has_val(true) {}
2483 constexpr expected_storage_base(no_init_t) : m_no_init(), m_has_val(false) {}
2484
2485 template <class... Args,
2486 detail::enable_if_t<std::is_constructible<T, Args &&...>::value> * =
2487 nullptr>
2488 constexpr expected_storage_base(in_place_t, Args &&...args)
2489 : m_val(std::forward<Args>(args)...), m_has_val(true) {}
2490
2491 template <class U, class... Args,
2492 detail::enable_if_t<std::is_constructible<
2493 T, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
2494 constexpr expected_storage_base(in_place_t, std::initializer_list<U> il,
2495 Args &&...args)
2496 : m_val(il, std::forward<Args>(args)...), m_has_val(true) {}
2497 template <class... Args,
2498 detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * =
2499 nullptr>
2500 constexpr explicit expected_storage_base(unexpect_t, Args &&...args)
2501 : m_unexpect(std::forward<Args>(args)...), m_has_val(false) {}
2502
2503 template <class U, class... Args,
2504 detail::enable_if_t<std::is_constructible<
2505 E, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
2507 std::initializer_list<U> il,
2508 Args &&...args)
2509 : m_unexpect(il, std::forward<Args>(args)...), m_has_val(false) {}
2510
2512 if (m_has_val) {
2513 m_val.~T();
2514 }
2515 }
2516 union {
2520 };
2522};
2523
2524// `T` is `void`, `E` is trivially-destructible
2525template <class E>
2527#if __GNUC__ <= 5
2528// no constexpr for GCC 4/5 bug
2529#else
2531#endif
2532 expected_storage_base() : m_has_val(true) {}
2533
2534 constexpr expected_storage_base(no_init_t) : m_val(), m_has_val(false) {}
2535
2536 constexpr expected_storage_base(in_place_t) : m_has_val(true) {}
2537
2538 template <class... Args,
2539 detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * =
2540 nullptr>
2541 constexpr explicit expected_storage_base(unexpect_t, Args &&...args)
2542 : m_unexpect(std::forward<Args>(args)...), m_has_val(false) {}
2543
2544 template <class U, class... Args,
2545 detail::enable_if_t<std::is_constructible<
2546 E, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
2548 std::initializer_list<U> il,
2549 Args &&...args)
2550 : m_unexpect(il, std::forward<Args>(args)...), m_has_val(false) {}
2551
2553 struct dummy {};
2554 union {
2557 };
2559};
2560
2561// `T` is `void`, `E` is not trivially-destructible
2562template <class E>
2564 constexpr expected_storage_base() : m_dummy(), m_has_val(true) {}
2565 constexpr expected_storage_base(no_init_t) : m_dummy(), m_has_val(false) {}
2566
2567 constexpr expected_storage_base(in_place_t) : m_dummy(), m_has_val(true) {}
2568
2569 template <class... Args,
2570 detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * =
2571 nullptr>
2572 constexpr explicit expected_storage_base(unexpect_t, Args &&...args)
2573 : m_unexpect(std::forward<Args>(args)...), m_has_val(false) {}
2574
2575 template <class U, class... Args,
2576 detail::enable_if_t<std::is_constructible<
2577 E, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
2579 std::initializer_list<U> il,
2580 Args &&...args)
2581 : m_unexpect(il, std::forward<Args>(args)...), m_has_val(false) {}
2582
2584 if (!m_has_val) {
2585 m_unexpect.~unexpected<E>();
2586 }
2587 }
2588
2589 union {
2592 };
2594};
2595
2596// This base class provides some handy member functions which can be used in
2597// further derived classes
2598template <class T, class E>
2600 using expected_storage_base<T, E>::expected_storage_base;
2601
2602 template <class... Args>
2603 void construct(Args &&...args) noexcept {
2604 new (std::addressof(this->m_val)) T(std::forward<Args>(args)...);
2605 this->m_has_val = true;
2606 }
2607
2608 template <class Rhs>
2609 void construct_with(Rhs &&rhs) noexcept {
2610 new (std::addressof(this->m_val)) T(std::forward<Rhs>(rhs).get());
2611 this->m_has_val = true;
2612 }
2613
2614 template <class... Args>
2615 void construct_error(Args &&...args) noexcept {
2616 new (std::addressof(this->m_unexpect))
2617 unexpected<E>(std::forward<Args>(args)...);
2618 this->m_has_val = false;
2619 }
2620
2621#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
2622
2623 // These assign overloads ensure that the most efficient assignment
2624 // implementation is used while maintaining the strong exception guarantee.
2625 // The problematic case is where rhs has a value, but *this does not.
2626 //
2627 // This overload handles the case where we can just copy-construct `T`
2628 // directly into place without throwing.
2629 template <class U = T,
2631 * = nullptr>
2632 void assign(const expected_operations_base &rhs) noexcept {
2633 if (!this->m_has_val && rhs.m_has_val) {
2634 geterr().~unexpected<E>();
2635 construct(rhs.get());
2636 } else {
2637 assign_common(rhs);
2638 }
2639 }
2640
2641 // This overload handles the case where we can attempt to create a copy of
2642 // `T`, then no-throw move it into place if the copy was successful.
2643 template <class U = T,
2644 detail::enable_if_t<!std::is_nothrow_copy_constructible<U>::value &&
2645 std::is_nothrow_move_constructible<U>::value>
2646 * = nullptr>
2647 void assign(const expected_operations_base &rhs) noexcept {
2648 if (!this->m_has_val && rhs.m_has_val) {
2649 T tmp = rhs.get();
2650 geterr().~unexpected<E>();
2651 construct(std::move(tmp));
2652 } else {
2653 assign_common(rhs);
2654 }
2655 }
2656
2657 // This overload is the worst-case, where we have to move-construct the
2658 // unexpected value into temporary storage, then try to copy the T into place.
2659 // If the construction succeeds, then everything is fine, but if it throws,
2660 // then we move the old unexpected value back into place before rethrowing the
2661 // exception.
2662 template <class U = T,
2663 detail::enable_if_t<!std::is_nothrow_copy_constructible<U>::value &&
2664 !std::is_nothrow_move_constructible<U>::value>
2665 * = nullptr>
2666 void assign(const expected_operations_base &rhs) {
2667 if (!this->m_has_val && rhs.m_has_val) {
2668 auto tmp = std::move(geterr());
2669 geterr().~unexpected<E>();
2670
2671#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
2672 try {
2673 construct(rhs.get());
2674 } catch (...) {
2675 geterr() = std::move(tmp);
2676 throw;
2677 }
2678#else
2679 construct(rhs.get());
2680#endif
2681 } else {
2682 assign_common(rhs);
2683 }
2684 }
2685
2686 // These overloads do the same as above, but for rvalues
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) noexcept {
2691 if (!this->m_has_val && rhs.m_has_val) {
2692 geterr().~unexpected<E>();
2693 construct(std::move(rhs).get());
2694 } else {
2695 assign_common(std::move(rhs));
2696 }
2697 }
2698
2699 template <class U = T,
2700 detail::enable_if_t<!std::is_nothrow_move_constructible<U>::value>
2701 * = nullptr>
2702 void assign(expected_operations_base &&rhs) {
2703 if (!this->m_has_val && rhs.m_has_val) {
2704 auto tmp = std::move(geterr());
2705 geterr().~unexpected<E>();
2706#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
2707 try {
2708 construct(std::move(rhs).get());
2709 } catch (...) {
2710 geterr() = std::move(tmp);
2711 throw;
2712 }
2713#else
2714 construct(std::move(rhs).get());
2715#endif
2716 } else {
2717 assign_common(std::move(rhs));
2718 }
2719 }
2720
2721#else
2722
2723 // If exceptions are disabled then we can just copy-construct
2724 void assign(const expected_operations_base &rhs) noexcept {
2725 if (!this->m_has_val && rhs.m_has_val) {
2726 geterr().~unexpected<E>();
2727 construct(rhs.get());
2728 } else {
2729 assign_common(rhs);
2730 }
2731 }
2732
2733 void assign(expected_operations_base &&rhs) noexcept {
2734 if (!this->m_has_val && rhs.m_has_val) {
2735 geterr().~unexpected<E>();
2736 construct(std::move(rhs).get());
2737 } else {
2738 assign_common(std::move(rhs));
2739 }
2740 }
2741
2742#endif
2743
2744 // The common part of move/copy assigning
2745 template <class Rhs>
2746 void assign_common(Rhs &&rhs) {
2747 if (this->m_has_val) {
2748 if (rhs.m_has_val) {
2749 get() = std::forward<Rhs>(rhs).get();
2750 } else {
2751 destroy_val();
2752 construct_error(std::forward<Rhs>(rhs).geterr());
2753 }
2754 } else {
2755 if (!rhs.m_has_val) {
2756 geterr() = std::forward<Rhs>(rhs).geterr();
2757 }
2758 }
2759 }
2760
2761 bool has_value() const { return this->m_has_val; }
2762
2763 TL_EXPECTED_11_CONSTEXPR T &get() & { return this->m_val; }
2764 constexpr const T &get() const & { return this->m_val; }
2765 TL_EXPECTED_11_CONSTEXPR T &&get() && { return std::move(this->m_val); }
2766#ifndef TL_EXPECTED_NO_CONSTRR
2767 constexpr const T &&get() const && { return std::move(this->m_val); }
2768#endif
2769
2771 return this->m_unexpect;
2772 }
2773 constexpr const unexpected<E> &geterr() const & { return this->m_unexpect; }
2775 return std::move(this->m_unexpect);
2776 }
2777#ifndef TL_EXPECTED_NO_CONSTRR
2778 constexpr const unexpected<E> &&geterr() const && {
2779 return std::move(this->m_unexpect);
2780 }
2781#endif
2782
2784};
2785
2786// This base class provides some handy member functions which can be used in
2787// further derived classes
2788template <class E>
2790 using expected_storage_base<void, E>::expected_storage_base;
2791
2792 template <class... Args>
2793 void construct() noexcept {
2794 this->m_has_val = true;
2795 }
2796
2797 // This function doesn't use its argument, but needs it so that code in
2798 // levels above this can work independently of whether T is void
2799 template <class Rhs>
2800 void construct_with(Rhs &&) noexcept {
2801 this->m_has_val = true;
2802 }
2803
2804 template <class... Args>
2805 void construct_error(Args &&...args) noexcept {
2806 new (std::addressof(this->m_unexpect))
2807 unexpected<E>(std::forward<Args>(args)...);
2808 this->m_has_val = false;
2809 }
2810
2811 template <class Rhs>
2812 void assign(Rhs &&rhs) noexcept {
2813 if (!this->m_has_val) {
2814 if (rhs.m_has_val) {
2815 geterr().~unexpected<E>();
2816 construct();
2817 } else {
2818 geterr() = std::forward<Rhs>(rhs).geterr();
2819 }
2820 } else {
2821 if (!rhs.m_has_val) {
2822 construct_error(std::forward<Rhs>(rhs).geterr());
2823 }
2824 }
2825 }
2826
2827 bool has_value() const { return this->m_has_val; }
2828
2830 return this->m_unexpect;
2831 }
2832 constexpr const unexpected<E> &geterr() const & { return this->m_unexpect; }
2834 return std::move(this->m_unexpect);
2835 }
2836#ifndef TL_EXPECTED_NO_CONSTRR
2837 constexpr const unexpected<E> &&geterr() const && {
2838 return std::move(this->m_unexpect);
2839 }
2840#endif
2841
2843 // no-op
2844 }
2845};
2846
2847// This class manages conditionally having a trivial copy constructor
2848// This specialization is for when T and E are trivially copy constructible
2849template <class T, class E,
2851 T)>::value &&
2854 using expected_operations_base<T, E>::expected_operations_base;
2855};
2856
2857// This specialization is for when T or E are not trivially copy constructible
2858template <class T, class E>
2860 using expected_operations_base<T, E>::expected_operations_base;
2861
2865 if (rhs.has_value()) {
2866 this->construct_with(rhs);
2867 } else {
2868 this->construct_error(rhs.geterr());
2869 }
2870 }
2871
2875};
2876
2877// This class manages conditionally having a trivial move constructor
2878// Unfortunately there's no way to achieve this in GCC < 5 AFAIK, since it
2879// doesn't implement an analogue to std::is_trivially_move_constructible. We
2880// have to make do with a non-trivial move constructor even if T is trivially
2881// move constructible
2882#ifndef TL_EXPECTED_GCC49
2883template <class T, class E,
2884 bool =
2886 std::is_trivially_move_constructible<E>::value>
2888 using expected_copy_base<T, E>::expected_copy_base;
2889};
2890#else
2891template <class T, class E, bool = false>
2892struct expected_move_base;
2893#endif
2894template <class T, class E>
2895struct expected_move_base<T, E, false> : expected_copy_base<T, E> {
2896 using expected_copy_base<T, E>::expected_copy_base;
2897
2900
2902 std::is_nothrow_move_constructible<T>::value)
2903 : expected_copy_base<T, E>(no_init) {
2904 if (rhs.has_value()) {
2905 this->construct_with(std::move(rhs));
2906 } else {
2907 this->construct_error(std::move(rhs.geterr()));
2908 }
2909 }
2912};
2913
2914// This class manages conditionally having a trivial copy assignment operator
2915template <
2916 class T, class E,
2917 bool =
2918 is_void_or<
2926 using expected_move_base<T, E>::expected_move_base;
2927};
2928
2929template <class T, class E>
2944
2945// This class manages conditionally having a trivial move assignment operator
2946// Unfortunately there's no way to achieve this in GCC < 5 AFAIK, since it
2947// doesn't implement an analogue to std::is_trivially_move_assignable. We have
2948// to make do with a non-trivial move assignment operator even if T is trivially
2949// move assignable
2950#ifndef TL_EXPECTED_GCC49
2951template <
2952 class T, class E,
2953 bool = is_void_or<
2955 std::is_trivially_move_constructible<T>,
2956 std::is_trivially_move_assignable<T>>>::value &&
2957 std::is_trivially_destructible<E>::value &&
2958 std::is_trivially_move_constructible<E>::value &&
2959 std::is_trivially_move_assignable<E>::value>
2961 using expected_copy_assign_base<T, E>::expected_copy_assign_base;
2962};
2963#else
2964template <class T, class E, bool = false>
2966#endif
2967
2968template <class T, class E>
2969struct expected_move_assign_base<T, E, false>
2971 using expected_copy_assign_base<T, E>::expected_copy_assign_base;
2972
2975
2977
2979 default;
2980
2983 &&rhs) noexcept(std::is_nothrow_move_constructible<T>::value &&
2984 std::is_nothrow_move_assignable<T>::value) {
2985 this->assign(std::move(rhs));
2986 return *this;
2987 }
2988};
2989
2990// expected_delete_ctor_base will conditionally delete copy and move
2991// constructors depending on whether T is copy/move constructible
2992template <class T, class E,
2993 bool EnableCopy = (is_copy_constructible_or_void<T>::value &&
2994 std::is_copy_constructible<E>::value),
2995 bool EnableMove = (is_move_constructible_or_void<T>::value &&
2996 std::is_move_constructible<E>::value)>
3006
3007template <class T, class E>
3017
3018template <class T, class E>
3028
3029template <class T, class E>
3039
3040// expected_delete_assign_base will conditionally delete copy and move
3041// constructors depending on whether T and E are copy/move constructible +
3042// assignable
3043template <class T, class E,
3044 bool EnableCopy = (is_copy_constructible_or_void<T>::value &&
3045 std::is_copy_constructible<E>::value &&
3046 is_copy_assignable_or_void<T>::value &&
3047 std::is_copy_assignable<E>::value),
3048 bool EnableMove = (is_move_constructible_or_void<T>::value &&
3049 std::is_move_constructible<E>::value &&
3050 is_move_assignable_or_void<T>::value &&
3051 std::is_move_assignable<E>::value)>
3062
3063template <class T, class E>
3074
3075template <class T, class E>
3086
3087template <class T, class E>
3098
3099// This is needed to be able to construct the expected_default_ctor_base which
3100// follows, while still conditionally deleting the default constructor.
3102 explicit constexpr default_constructor_tag() = default;
3103};
3104
3105// expected_default_ctor_base will ensure that expected has a deleted default
3106// consturctor if T is not default constructible.
3107// This specialization is for when T is default constructible
3108template <class T, class E,
3109 bool Enable =
3110 std::is_default_constructible<T>::value || std::is_void<T>::value>
3112 constexpr expected_default_ctor_base() noexcept = default;
3114 expected_default_ctor_base const &) noexcept = default;
3116 default;
3118 expected_default_ctor_base const &) noexcept = default;
3120 expected_default_ctor_base &&) noexcept = default;
3121
3123};
3124
3125// This specialization is for when T is not default constructible
3126template <class T, class E>
3127struct expected_default_ctor_base<T, E, false> {
3128 constexpr expected_default_ctor_base() noexcept = delete;
3130 expected_default_ctor_base const &) noexcept = default;
3132 default;
3134 expected_default_ctor_base const &) noexcept = default;
3136 expected_default_ctor_base &&) noexcept = default;
3137
3139};
3140} // namespace detail
3141
3142template <class E>
3143class bad_expected_access : public std::exception {
3144 public:
3145 explicit bad_expected_access(E e) : m_val(std::move(e)) {}
3146
3147 virtual const char *what() const noexcept override {
3148 return "Bad expected access";
3149 }
3150
3151 const E &error() const & { return m_val; }
3152 E &error() & { return m_val; }
3153 const E &&error() const && { return std::move(m_val); }
3154 E &&error() && { return std::move(m_val); }
3155
3156 private:
3157 E m_val;
3158};
3159
3167template <class T, class E>
3172 static_assert(!std::is_reference<T>::value, "T must not be a reference");
3173 static_assert(!std::is_same<T, std::remove_cv<in_place_t>::type>::value,
3174 "T must not be in_place_t");
3175 static_assert(!std::is_same<T, std::remove_cv<unexpect_t>::type>::value,
3176 "T must not be unexpect_t");
3177 static_assert(
3178 !std::is_same<T, typename std::remove_cv<unexpected<E>>::type>::value,
3179 "T must not be unexpected<E>");
3180 static_assert(!std::is_reference<E>::value, "E must not be a reference");
3181
3182 T *valptr() { return std::addressof(this->m_val); }
3183 const T *valptr() const { return std::addressof(this->m_val); }
3184 unexpected<E> *errptr() { return std::addressof(this->m_unexpect); }
3185 const unexpected<E> *errptr() const {
3186 return std::addressof(this->m_unexpect);
3187 }
3188
3189 template <class U = T,
3191 TL_EXPECTED_11_CONSTEXPR U &val() {
3192 return this->m_val;
3193 }
3194 TL_EXPECTED_11_CONSTEXPR unexpected<E> &err() { return this->m_unexpect; }
3195
3196 template <class U = T,
3198 constexpr const U &val() const {
3199 return this->m_val;
3200 }
3201 constexpr const unexpected<E> &err() const { return this->m_unexpect; }
3202
3205
3206 public:
3207 typedef T value_type;
3208 typedef E error_type;
3210
3211#if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \
3212 !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55)
3213 template <class F>
3214 TL_EXPECTED_11_CONSTEXPR auto and_then(F &&f) & {
3215 return and_then_impl(*this, std::forward<F>(f));
3216 }
3217 template <class F>
3218 TL_EXPECTED_11_CONSTEXPR auto and_then(F &&f) && {
3219 return and_then_impl(std::move(*this), std::forward<F>(f));
3220 }
3221 template <class F>
3222 constexpr auto and_then(F &&f) const & {
3223 return and_then_impl(*this, std::forward<F>(f));
3224 }
3225
3226#ifndef TL_EXPECTED_NO_CONSTRR
3227 template <class F>
3228 constexpr auto and_then(F &&f) const && {
3229 return and_then_impl(std::move(*this), std::forward<F>(f));
3230 }
3231#endif
3232
3233#else
3234 template <class F>
3235 TL_EXPECTED_11_CONSTEXPR auto and_then(F &&f) & -> decltype(and_then_impl(
3236 std::declval<expected &>(), std::forward<F>(f))) {
3237 return and_then_impl(*this, std::forward<F>(f));
3238 }
3239 template <class F>
3240 TL_EXPECTED_11_CONSTEXPR auto and_then(F &&f) && -> decltype(and_then_impl(
3241 std::declval<expected &&>(), std::forward<F>(f))) {
3242 return and_then_impl(std::move(*this), std::forward<F>(f));
3243 }
3244 template <class F>
3245 constexpr auto and_then(F &&f) const & -> decltype(and_then_impl(
3246 std::declval<expected const &>(), std::forward<F>(f))) {
3247 return and_then_impl(*this, std::forward<F>(f));
3248 }
3249
3250#ifndef TL_EXPECTED_NO_CONSTRR
3251 template <class F>
3252 constexpr auto and_then(F &&f) const && -> decltype(and_then_impl(
3253 std::declval<expected const &&>(), std::forward<F>(f))) {
3254 return and_then_impl(std::move(*this), std::forward<F>(f));
3255 }
3256#endif
3257#endif
3258
3259#if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \
3260 !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55)
3261 template <class F>
3262 TL_EXPECTED_11_CONSTEXPR auto map(F &&f) & {
3263 return expected_map_impl(*this, std::forward<F>(f));
3264 }
3265 template <class F>
3266 TL_EXPECTED_11_CONSTEXPR auto map(F &&f) && {
3267 return expected_map_impl(std::move(*this), std::forward<F>(f));
3268 }
3269 template <class F>
3270 constexpr auto map(F &&f) const & {
3271 return expected_map_impl(*this, std::forward<F>(f));
3272 }
3273 template <class F>
3274 constexpr auto map(F &&f) const && {
3275 return expected_map_impl(std::move(*this), std::forward<F>(f));
3276 }
3277#else
3278 template <class F>
3280 std::declval<expected &>(), std::declval<F &&>()))
3281 map(F &&f) & {
3282 return expected_map_impl(*this, std::forward<F>(f));
3283 }
3284 template <class F>
3285 TL_EXPECTED_11_CONSTEXPR decltype(expected_map_impl(std::declval<expected>(),
3286 std::declval<F &&>()))
3287 map(F &&f) && {
3288 return expected_map_impl(std::move(*this), std::forward<F>(f));
3289 }
3290 template <class F>
3291 constexpr decltype(expected_map_impl(std::declval<const expected &>(),
3292 std::declval<F &&>()))
3293 map(F &&f) const & {
3294 return expected_map_impl(*this, std::forward<F>(f));
3295 }
3296
3297#ifndef TL_EXPECTED_NO_CONSTRR
3298 template <class F>
3299 constexpr decltype(expected_map_impl(std::declval<const expected &&>(),
3300 std::declval<F &&>()))
3301 map(F &&f) const && {
3302 return expected_map_impl(std::move(*this), std::forward<F>(f));
3303 }
3304#endif
3305#endif
3306
3307#if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \
3308 !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55)
3309 template <class F>
3310 TL_EXPECTED_11_CONSTEXPR auto transform(F &&f) & {
3311 return expected_map_impl(*this, std::forward<F>(f));
3312 }
3313 template <class F>
3314 TL_EXPECTED_11_CONSTEXPR auto transform(F &&f) && {
3315 return expected_map_impl(std::move(*this), std::forward<F>(f));
3316 }
3317 template <class F>
3318 constexpr auto transform(F &&f) const & {
3319 return expected_map_impl(*this, std::forward<F>(f));
3320 }
3321 template <class F>
3322 constexpr auto transform(F &&f) const && {
3323 return expected_map_impl(std::move(*this), std::forward<F>(f));
3324 }
3325#else
3326 template <class F>
3328 std::declval<expected &>(), std::declval<F &&>()))
3329 transform(F &&f) & {
3330 return expected_map_impl(*this, std::forward<F>(f));
3331 }
3332 template <class F>
3333 TL_EXPECTED_11_CONSTEXPR decltype(expected_map_impl(std::declval<expected>(),
3334 std::declval<F &&>()))
3335 transform(F &&f) && {
3336 return expected_map_impl(std::move(*this), std::forward<F>(f));
3337 }
3338 template <class F>
3339 constexpr decltype(expected_map_impl(std::declval<const expected &>(),
3340 std::declval<F &&>()))
3341 transform(F &&f) const & {
3342 return expected_map_impl(*this, std::forward<F>(f));
3343 }
3344
3345#ifndef TL_EXPECTED_NO_CONSTRR
3346 template <class F>
3347 constexpr decltype(expected_map_impl(std::declval<const expected &&>(),
3348 std::declval<F &&>()))
3349 transform(F &&f) const && {
3350 return expected_map_impl(std::move(*this), std::forward<F>(f));
3351 }
3352#endif
3353#endif
3354
3355#if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \
3356 !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55)
3357 template <class F>
3358 TL_EXPECTED_11_CONSTEXPR auto map_error(F &&f) & {
3359 return map_error_impl(*this, std::forward<F>(f));
3360 }
3361 template <class F>
3362 TL_EXPECTED_11_CONSTEXPR auto map_error(F &&f) && {
3363 return map_error_impl(std::move(*this), std::forward<F>(f));
3364 }
3365 template <class F>
3366 constexpr auto map_error(F &&f) const & {
3367 return map_error_impl(*this, std::forward<F>(f));
3368 }
3369 template <class F>
3370 constexpr auto map_error(F &&f) const && {
3371 return map_error_impl(std::move(*this), std::forward<F>(f));
3372 }
3373#else
3374 template <class F>
3375 TL_EXPECTED_11_CONSTEXPR decltype(map_error_impl(std::declval<expected &>(),
3376 std::declval<F &&>()))
3377 map_error(F &&f) & {
3378 return map_error_impl(*this, std::forward<F>(f));
3379 }
3380 template <class F>
3381 TL_EXPECTED_11_CONSTEXPR decltype(map_error_impl(std::declval<expected &&>(),
3382 std::declval<F &&>()))
3383 map_error(F &&f) && {
3384 return map_error_impl(std::move(*this), std::forward<F>(f));
3385 }
3386 template <class F>
3387 constexpr decltype(map_error_impl(std::declval<const expected &>(),
3388 std::declval<F &&>()))
3389 map_error(F &&f) const & {
3390 return map_error_impl(*this, std::forward<F>(f));
3391 }
3392
3393#ifndef TL_EXPECTED_NO_CONSTRR
3394 template <class F>
3395 constexpr decltype(map_error_impl(std::declval<const expected &&>(),
3396 std::declval<F &&>()))
3397 map_error(F &&f) const && {
3398 return map_error_impl(std::move(*this), std::forward<F>(f));
3399 }
3400#endif
3401#endif
3402#if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \
3403 !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55)
3404 template <class F>
3405 TL_EXPECTED_11_CONSTEXPR auto transform_error(F &&f) & {
3406 return map_error_impl(*this, std::forward<F>(f));
3407 }
3408 template <class F>
3409 TL_EXPECTED_11_CONSTEXPR auto transform_error(F &&f) && {
3410 return map_error_impl(std::move(*this), std::forward<F>(f));
3411 }
3412 template <class F>
3413 constexpr auto transform_error(F &&f) const & {
3414 return map_error_impl(*this, std::forward<F>(f));
3415 }
3416 template <class F>
3417 constexpr auto transform_error(F &&f) const && {
3418 return map_error_impl(std::move(*this), std::forward<F>(f));
3419 }
3420#else
3421 template <class F>
3422 TL_EXPECTED_11_CONSTEXPR decltype(map_error_impl(std::declval<expected &>(),
3423 std::declval<F &&>()))
3425 return map_error_impl(*this, std::forward<F>(f));
3426 }
3427 template <class F>
3428 TL_EXPECTED_11_CONSTEXPR decltype(map_error_impl(std::declval<expected &&>(),
3429 std::declval<F &&>()))
3431 return map_error_impl(std::move(*this), std::forward<F>(f));
3432 }
3433 template <class F>
3434 constexpr decltype(map_error_impl(std::declval<const expected &>(),
3435 std::declval<F &&>()))
3436 transform_error(F &&f) const & {
3437 return map_error_impl(*this, std::forward<F>(f));
3438 }
3439
3440#ifndef TL_EXPECTED_NO_CONSTRR
3441 template <class F>
3442 constexpr decltype(map_error_impl(std::declval<const expected &&>(),
3443 std::declval<F &&>()))
3444 transform_error(F &&f) const && {
3445 return map_error_impl(std::move(*this), std::forward<F>(f));
3446 }
3447#endif
3448#endif
3449 template <class F>
3451 return or_else_impl(*this, std::forward<F>(f));
3452 }
3453
3454 template <class F>
3456 return or_else_impl(std::move(*this), std::forward<F>(f));
3457 }
3458
3459 template <class F>
3460 expected constexpr or_else(F &&f) const & {
3461 return or_else_impl(*this, std::forward<F>(f));
3462 }
3463
3464#ifndef TL_EXPECTED_NO_CONSTRR
3465 template <class F>
3466 expected constexpr or_else(F &&f) const && {
3467 return or_else_impl(std::move(*this), std::forward<F>(f));
3468 }
3469#endif
3470 constexpr expected() = default;
3471 constexpr expected(const expected &rhs) = default;
3472 constexpr expected(expected &&rhs) = default;
3473 expected &operator=(const expected &rhs) = default;
3474 expected &operator=(expected &&rhs) = default;
3475
3476 template <class... Args,
3477 detail::enable_if_t<std::is_constructible<T, Args &&...>::value> * =
3478 nullptr>
3479 constexpr expected(in_place_t, Args &&...args)
3480 : impl_base(in_place, std::forward<Args>(args)...),
3481 ctor_base(detail::default_constructor_tag{}) {}
3482
3483 template <class U, class... Args,
3484 detail::enable_if_t<std::is_constructible<
3485 T, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
3486 constexpr expected(in_place_t, std::initializer_list<U> il, Args &&...args)
3487 : impl_base(in_place, il, std::forward<Args>(args)...),
3488 ctor_base(detail::default_constructor_tag{}) {}
3489
3490 template <class G = E,
3492 nullptr,
3494 nullptr>
3495 explicit constexpr expected(const unexpected<G> &e)
3496 : impl_base(unexpect, e.value()),
3497 ctor_base(detail::default_constructor_tag{}) {}
3498
3499 template <
3500 class G = E,
3502 nullptr,
3504 constexpr expected(unexpected<G> const &e)
3505 : impl_base(unexpect, e.value()),
3506 ctor_base(detail::default_constructor_tag{}) {}
3507
3508 template <
3509 class G = E,
3512 explicit constexpr expected(unexpected<G> &&e) noexcept(
3513 std::is_nothrow_constructible<E, G &&>::value)
3514 : impl_base(unexpect, std::move(e.value())),
3515 ctor_base(detail::default_constructor_tag{}) {}
3516
3517 template <
3518 class G = E,
3521 constexpr expected(unexpected<G> &&e) noexcept(
3522 std::is_nothrow_constructible<E, G &&>::value)
3523 : impl_base(unexpect, std::move(e.value())),
3524 ctor_base(detail::default_constructor_tag{}) {}
3525
3526 template <class... Args,
3527 detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * =
3528 nullptr>
3529 constexpr explicit expected(unexpect_t, Args &&...args)
3530 : impl_base(unexpect, std::forward<Args>(args)...),
3531 ctor_base(detail::default_constructor_tag{}) {}
3532
3533 template <class U, class... Args,
3534 detail::enable_if_t<std::is_constructible<
3535 E, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
3536 constexpr explicit expected(unexpect_t, std::initializer_list<U> il,
3537 Args &&...args)
3538 : impl_base(unexpect, il, std::forward<Args>(args)...),
3539 ctor_base(detail::default_constructor_tag{}) {}
3540
3541 template <class U, class G,
3542 detail::enable_if_t<!(std::is_convertible<U const &, T>::value &&
3543 std::is_convertible<G const &, E>::value)> * =
3544 nullptr,
3546 * = nullptr>
3548 : ctor_base(detail::default_constructor_tag{}) {
3549 if (rhs.has_value()) {
3550 this->construct(*rhs);
3551 } else {
3552 this->construct_error(rhs.error());
3553 }
3554 }
3555
3556 template <class U, class G,
3557 detail::enable_if_t<(std::is_convertible<U const &, T>::value &&
3558 std::is_convertible<G const &, E>::value)> * =
3559 nullptr,
3561 * = nullptr>
3563 : ctor_base(detail::default_constructor_tag{}) {
3564 if (rhs.has_value()) {
3565 this->construct(*rhs);
3566 } else {
3567 this->construct_error(rhs.error());
3568 }
3569 }
3570
3571 template <
3572 class U, class G,
3573 detail::enable_if_t<!(std::is_convertible<U &&, T>::value &&
3574 std::is_convertible<G &&, E>::value)> * = nullptr,
3577 : ctor_base(detail::default_constructor_tag{}) {
3578 if (rhs.has_value()) {
3579 this->construct(std::move(*rhs));
3580 } else {
3581 this->construct_error(std::move(rhs.error()));
3582 }
3583 }
3584
3585 template <
3586 class U, class G,
3587 detail::enable_if_t<(std::is_convertible<U &&, T>::value &&
3588 std::is_convertible<G &&, E>::value)> * = nullptr,
3591 : ctor_base(detail::default_constructor_tag{}) {
3592 if (rhs.has_value()) {
3593 this->construct(std::move(*rhs));
3594 } else {
3595 this->construct_error(std::move(rhs.error()));
3596 }
3597 }
3598
3599 template <
3600 class U = T,
3604 : expected(in_place, std::forward<U>(v)) {}
3605
3606 template <
3607 class U = T,
3611 : expected(in_place, std::forward<U>(v)) {}
3612
3613 template <
3614 class U = T, class G = T,
3616 nullptr,
3619 (!std::is_same<expected<T, E>, detail::decay_t<U>>::value &&
3621 std::is_same<T, detail::decay_t<U>>>::value &&
3622 std::is_constructible<T, U>::value &&
3623 std::is_assignable<G &, U>::value &&
3624 std::is_nothrow_move_constructible<E>::value)> * = nullptr>
3626 if (has_value()) {
3627 val() = std::forward<U>(v);
3628 } else {
3629 err().~unexpected<E>();
3630 ::new (valptr()) T(std::forward<U>(v));
3631 this->m_has_val = true;
3632 }
3633
3634 return *this;
3635 }
3636
3637 template <
3638 class U = T, class G = T,
3640 nullptr,
3643 (!std::is_same<expected<T, E>, detail::decay_t<U>>::value &&
3645 std::is_same<T, detail::decay_t<U>>>::value &&
3646 std::is_constructible<T, U>::value &&
3647 std::is_assignable<G &, U>::value &&
3648 std::is_nothrow_move_constructible<E>::value)> * = nullptr>
3649 expected &operator=(U &&v) {
3650 if (has_value()) {
3651 val() = std::forward<U>(v);
3652 } else {
3653 auto tmp = std::move(err());
3654 err().~unexpected<E>();
3655
3656#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
3657 try {
3658 ::new (valptr()) T(std::forward<U>(v));
3659 this->m_has_val = true;
3660 } catch (...) {
3661 err() = std::move(tmp);
3662 throw;
3663 }
3664#else
3665 ::new (valptr()) T(std::forward<U>(v));
3666 this->m_has_val = true;
3667#endif
3668 }
3669
3670 return *this;
3671 }
3672
3673 template <class G = E,
3675 std::is_assignable<G &, G>::value> * = nullptr>
3677 if (!has_value()) {
3678 err() = rhs;
3679 } else {
3680 this->destroy_val();
3681 ::new (errptr()) unexpected<E>(rhs);
3682 this->m_has_val = false;
3683 }
3684
3685 return *this;
3686 }
3687
3688 template <class G = E,
3690 std::is_move_assignable<G>::value> * = nullptr>
3692 if (!has_value()) {
3693 err() = std::move(rhs);
3694 } else {
3695 this->destroy_val();
3696 ::new (errptr()) unexpected<E>(std::move(rhs));
3697 this->m_has_val = false;
3698 }
3699
3700 return *this;
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 } else {
3709 err().~unexpected<E>();
3710 this->m_has_val = true;
3711 }
3712 ::new (valptr()) T(std::forward<Args>(args)...);
3713 }
3714
3715 template <class... Args, detail::enable_if_t<!std::is_nothrow_constructible<
3716 T, Args &&...>::value> * = nullptr>
3717 void emplace(Args &&...args) {
3718 if (has_value()) {
3719 val().~T();
3720 ::new (valptr()) T(std::forward<Args>(args)...);
3721 } else {
3722 auto tmp = std::move(err());
3723 err().~unexpected<E>();
3724
3725#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
3726 try {
3727 ::new (valptr()) T(std::forward<Args>(args)...);
3728 this->m_has_val = true;
3729 } catch (...) {
3730 err() = std::move(tmp);
3731 throw;
3732 }
3733#else
3734 ::new (valptr()) T(std::forward<Args>(args)...);
3735 this->m_has_val = true;
3736#endif
3737 }
3738 }
3739
3740 template <class U, class... Args,
3741 detail::enable_if_t<std::is_nothrow_constructible<
3742 T, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
3743 void emplace(std::initializer_list<U> il, Args &&...args) {
3744 if (has_value()) {
3745 T t(il, std::forward<Args>(args)...);
3746 val() = std::move(t);
3747 } else {
3748 err().~unexpected<E>();
3749 ::new (valptr()) T(il, std::forward<Args>(args)...);
3750 this->m_has_val = true;
3751 }
3752 }
3753
3754 template <class U, class... Args,
3755 detail::enable_if_t<!std::is_nothrow_constructible<
3756 T, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
3757 void emplace(std::initializer_list<U> il, Args &&...args) {
3758 if (has_value()) {
3759 T t(il, std::forward<Args>(args)...);
3760 val() = std::move(t);
3761 } else {
3762 auto tmp = std::move(err());
3763 err().~unexpected<E>();
3764
3765#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
3766 try {
3767 ::new (valptr()) T(il, std::forward<Args>(args)...);
3768 this->m_has_val = true;
3769 } catch (...) {
3770 err() = std::move(tmp);
3771 throw;
3772 }
3773#else
3774 ::new (valptr()) T(il, std::forward<Args>(args)...);
3775 this->m_has_val = true;
3776#endif
3777 }
3778 }
3779
3780 private:
3781 using t_is_void = std::true_type;
3782 using t_is_not_void = std::false_type;
3783 using t_is_nothrow_move_constructible = std::true_type;
3784 using move_constructing_t_can_throw = std::false_type;
3785 using e_is_nothrow_move_constructible = std::true_type;
3786 using move_constructing_e_can_throw = std::false_type;
3787
3788 void swap_where_both_have_value(expected & /*rhs*/, t_is_void) noexcept {
3789 // swapping void is a no-op
3790 }
3791
3792 void swap_where_both_have_value(expected &rhs, t_is_not_void) {
3793 using std::swap;
3794 swap(val(), rhs.val());
3795 }
3796
3797 void swap_where_only_one_has_value(expected &rhs, t_is_void) noexcept(
3798 std::is_nothrow_move_constructible<E>::value) {
3799 ::new (errptr()) unexpected_type(std::move(rhs.err()));
3800 rhs.err().~unexpected_type();
3801 std::swap(this->m_has_val, rhs.m_has_val);
3802 }
3803
3804 void swap_where_only_one_has_value(expected &rhs, t_is_not_void) {
3805 swap_where_only_one_has_value_and_t_is_not_void(
3806 rhs, typename std::is_nothrow_move_constructible<T>::type{},
3807 typename std::is_nothrow_move_constructible<E>::type{});
3808 }
3809
3810 void swap_where_only_one_has_value_and_t_is_not_void(
3811 expected &rhs, t_is_nothrow_move_constructible,
3812 e_is_nothrow_move_constructible) noexcept {
3813 auto temp = std::move(val());
3814 val().~T();
3815 ::new (errptr()) unexpected_type(std::move(rhs.err()));
3816 rhs.err().~unexpected_type();
3817 ::new (rhs.valptr()) T(std::move(temp));
3818 std::swap(this->m_has_val, rhs.m_has_val);
3819 }
3820
3821 void swap_where_only_one_has_value_and_t_is_not_void(
3822 expected &rhs, t_is_nothrow_move_constructible,
3823 move_constructing_e_can_throw) {
3824 auto temp = std::move(val());
3825 val().~T();
3826#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
3827 try {
3828 ::new (errptr()) unexpected_type(std::move(rhs.err()));
3829 rhs.err().~unexpected_type();
3830 ::new (rhs.valptr()) T(std::move(temp));
3831 std::swap(this->m_has_val, rhs.m_has_val);
3832 } catch (...) {
3833 val() = std::move(temp);
3834 throw;
3835 }
3836#else
3837 ::new (errptr()) unexpected_type(std::move(rhs.err()));
3838 rhs.err().~unexpected_type();
3839 ::new (rhs.valptr()) T(std::move(temp));
3840 std::swap(this->m_has_val, rhs.m_has_val);
3841#endif
3842 }
3843
3844 void swap_where_only_one_has_value_and_t_is_not_void(
3845 expected &rhs, move_constructing_t_can_throw,
3846 e_is_nothrow_move_constructible) {
3847 auto temp = std::move(rhs.err());
3848 rhs.err().~unexpected_type();
3849#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
3850 try {
3851 ::new (rhs.valptr()) T(std::move(val()));
3852 val().~T();
3853 ::new (errptr()) unexpected_type(std::move(temp));
3854 std::swap(this->m_has_val, rhs.m_has_val);
3855 } catch (...) {
3856 rhs.err() = std::move(temp);
3857 throw;
3858 }
3859#else
3860 ::new (rhs.valptr()) T(std::move(val()));
3861 val().~T();
3862 ::new (errptr()) unexpected_type(std::move(temp));
3863 std::swap(this->m_has_val, rhs.m_has_val);
3864#endif
3865 }
3866
3867 public:
3868 template <class OT = T, class OE = E>
3869 detail::enable_if_t<detail::is_swappable<OT>::value &&
3870 detail::is_swappable<OE>::value &&
3871 (std::is_nothrow_move_constructible<OT>::value ||
3872 std::is_nothrow_move_constructible<OE>::value)>
3873 swap(expected &rhs) noexcept(std::is_nothrow_move_constructible<T>::value &&
3875 std::is_nothrow_move_constructible<E>::value &&
3877 if (has_value() && rhs.has_value()) {
3878 swap_where_both_have_value(rhs, typename std::is_void<T>::type{});
3879 } else if (!has_value() && rhs.has_value()) {
3880 rhs.swap(*this);
3881 } else if (has_value()) {
3882 swap_where_only_one_has_value(rhs, typename std::is_void<T>::type{});
3883 } else {
3884 using std::swap;
3885 swap(err(), rhs.err());
3886 }
3887 }
3888
3889 constexpr const T *operator->() const {
3890 TL_ASSERT(has_value());
3891 return valptr();
3892 }
3894 TL_ASSERT(has_value());
3895 return valptr();
3896 }
3897
3898 template <class U = T,
3900 constexpr const U &operator*() const & {
3901 TL_ASSERT(has_value());
3902 return val();
3903 }
3904 template <class U = T,
3907 TL_ASSERT(has_value());
3908 return val();
3909 }
3910 template <class U = T,
3912 constexpr const U &&operator*() const && {
3913 TL_ASSERT(has_value());
3914 return std::move(val());
3915 }
3916 template <class U = T,
3919 TL_ASSERT(has_value());
3920 return std::move(val());
3921 }
3922
3923 constexpr bool has_value() const noexcept { return this->m_has_val; }
3924 constexpr explicit operator bool() const noexcept { return this->m_has_val; }
3925
3926 template <class U = T,
3928 TL_EXPECTED_11_CONSTEXPR const U &value() const & {
3929 if (!has_value())
3930 detail::throw_exception(bad_expected_access<E>(err().value()));
3931 return val();
3932 }
3933 template <class U = T,
3936 if (!has_value())
3937 detail::throw_exception(bad_expected_access<E>(err().value()));
3938 return val();
3939 }
3940 template <class U = T,
3942 TL_EXPECTED_11_CONSTEXPR const U &&value() const && {
3943 if (!has_value())
3944 detail::throw_exception(bad_expected_access<E>(std::move(err()).value()));
3945 return std::move(val());
3946 }
3947 template <class U = T,
3950 if (!has_value())
3951 detail::throw_exception(bad_expected_access<E>(std::move(err()).value()));
3952 return std::move(val());
3953 }
3954
3955 constexpr const E &error() const & {
3956 TL_ASSERT(!has_value());
3957 return err().value();
3958 }
3960 TL_ASSERT(!has_value());
3961 return err().value();
3962 }
3963 constexpr const E &&error() const && {
3964 TL_ASSERT(!has_value());
3965 return std::move(err().value());
3966 }
3968 TL_ASSERT(!has_value());
3969 return std::move(err().value());
3970 }
3971
3972 template <class U>
3973 constexpr T value_or(U &&v) const & {
3974 static_assert(std::is_copy_constructible<T>::value &&
3975 std::is_convertible<U &&, T>::value,
3976 "T must be copy-constructible and convertible to from U&&");
3977 return bool(*this) ? **this : static_cast<T>(std::forward<U>(v));
3978 }
3979 template <class U>
3981 static_assert(std::is_move_constructible<T>::value &&
3982 std::is_convertible<U &&, T>::value,
3983 "T must be move-constructible and convertible to from U&&");
3984 return bool(*this) ? std::move(**this) : static_cast<T>(std::forward<U>(v));
3985 }
3986};
3987
3988namespace detail {
3989template <class Exp>
3991template <class Exp>
3993template <class Exp, class Ret>
3995
3996#ifdef TL_EXPECTED_CXX14
3997template <class Exp, class F,
3999 class Ret = decltype(detail::invoke(std::declval<F>(),
4000 *std::declval<Exp>()))>
4001constexpr auto and_then_impl(Exp &&exp, F &&f) {
4002 static_assert(detail::is_expected<Ret>::value, "F must return an expected");
4003
4004 return exp.has_value()
4005 ? detail::invoke(std::forward<F>(f), *std::forward<Exp>(exp))
4006 : Ret(unexpect, std::forward<Exp>(exp).error());
4007}
4008
4009template <class Exp, class F,
4011 class Ret = decltype(detail::invoke(std::declval<F>()))>
4012constexpr auto and_then_impl(Exp &&exp, F &&f) {
4013 static_assert(detail::is_expected<Ret>::value, "F must return an expected");
4014
4015 return exp.has_value() ? detail::invoke(std::forward<F>(f))
4016 : Ret(unexpect, std::forward<Exp>(exp).error());
4017}
4018#else
4019template <class>
4020struct TC;
4021template <class Exp, class F,
4022 class Ret = decltype(detail::invoke(std::declval<F>(),
4023 *std::declval<Exp>())),
4024 detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr>
4025auto and_then_impl(Exp &&exp, F &&f) -> Ret {
4026 static_assert(detail::is_expected<Ret>::value, "F must return an expected");
4027
4028 return exp.has_value()
4029 ? detail::invoke(std::forward<F>(f), *std::forward<Exp>(exp))
4030 : Ret(unexpect, std::forward<Exp>(exp).error());
4031}
4032
4033template <class Exp, class F,
4034 class Ret = decltype(detail::invoke(std::declval<F>())),
4035 detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr>
4036constexpr auto and_then_impl(Exp &&exp, F &&f) -> Ret {
4037 static_assert(detail::is_expected<Ret>::value, "F must return an expected");
4038
4039 return exp.has_value() ? detail::invoke(std::forward<F>(f))
4040 : Ret(unexpect, std::forward<Exp>(exp).error());
4041}
4042#endif
4043
4044#ifdef TL_EXPECTED_CXX14
4045template <class Exp, class F,
4047 class Ret = decltype(detail::invoke(std::declval<F>(),
4048 *std::declval<Exp>())),
4049 detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
4050constexpr auto expected_map_impl(Exp &&exp, F &&f) {
4051 using result = ret_t<Exp, detail::decay_t<Ret>>;
4052 return exp.has_value() ? result(detail::invoke(std::forward<F>(f),
4053 *std::forward<Exp>(exp)))
4054 : result(unexpect, std::forward<Exp>(exp).error());
4055}
4056
4057template <class Exp, class F,
4058 detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
4059 class Ret = decltype(detail::invoke(std::declval<F>(),
4060 *std::declval<Exp>())),
4061 detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
4062auto expected_map_impl(Exp &&exp, F &&f) {
4063 using result = expected<void, err_t<Exp>>;
4064 if (exp.has_value()) {
4065 detail::invoke(std::forward<F>(f), *std::forward<Exp>(exp));
4066 return result();
4067 }
4068
4069 return result(unexpect, std::forward<Exp>(exp).error());
4070}
4071
4072template <class Exp, class F,
4073 detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
4074 class Ret = decltype(detail::invoke(std::declval<F>())),
4075 detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
4076constexpr auto expected_map_impl(Exp &&exp, F &&f) {
4077 using result = ret_t<Exp, detail::decay_t<Ret>>;
4078 return exp.has_value() ? result(detail::invoke(std::forward<F>(f)))
4079 : result(unexpect, std::forward<Exp>(exp).error());
4080}
4081
4082template <class Exp, class F,
4083 detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
4084 class Ret = decltype(detail::invoke(std::declval<F>())),
4085 detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
4086auto expected_map_impl(Exp &&exp, F &&f) {
4087 using result = expected<void, err_t<Exp>>;
4088 if (exp.has_value()) {
4089 detail::invoke(std::forward<F>(f));
4090 return result();
4091 }
4092
4093 return result(unexpect, std::forward<Exp>(exp).error());
4094}
4095#else
4096template <class Exp, class F,
4097 detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
4098 class Ret = decltype(detail::invoke(std::declval<F>(),
4099 *std::declval<Exp>())),
4100 detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
4101
4102constexpr auto expected_map_impl(Exp &&exp, F &&f)
4104 using result = ret_t<Exp, detail::decay_t<Ret>>;
4105
4106 return exp.has_value() ? result(detail::invoke(std::forward<F>(f),
4107 *std::forward<Exp>(exp)))
4108 : result(unexpect, std::forward<Exp>(exp).error());
4109}
4110
4111template <class Exp, class F,
4113 class Ret = decltype(detail::invoke(std::declval<F>(),
4114 *std::declval<Exp>())),
4115 detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
4116
4118 if (exp.has_value()) {
4119 detail::invoke(std::forward<F>(f), *std::forward<Exp>(exp));
4120 return {};
4121 }
4122
4123 return unexpected<err_t<Exp>>(std::forward<Exp>(exp).error());
4124}
4125
4126template <class Exp, class F,
4128 class Ret = decltype(detail::invoke(std::declval<F>())),
4129 detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
4130
4131constexpr auto expected_map_impl(Exp &&exp, F &&f)
4132 -> ret_t<Exp, detail::decay_t<Ret>> {
4133 using result = ret_t<Exp, detail::decay_t<Ret>>;
4134
4135 return exp.has_value() ? result(detail::invoke(std::forward<F>(f)))
4136 : result(unexpect, std::forward<Exp>(exp).error());
4137}
4138
4139template <class Exp, class F,
4140 detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
4141 class Ret = decltype(detail::invoke(std::declval<F>())),
4142 detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
4143
4144auto expected_map_impl(Exp &&exp, F &&f) -> expected<void, err_t<Exp>> {
4145 if (exp.has_value()) {
4146 detail::invoke(std::forward<F>(f));
4147 return {};
4148 }
4149
4150 return unexpected<err_t<Exp>>(std::forward<Exp>(exp).error());
4151}
4152#endif
4153
4154#if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \
4155 !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55)
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>
4161constexpr auto map_error_impl(Exp &&exp, F &&f) {
4162 using result = expected<exp_t<Exp>, detail::decay_t<Ret>>;
4163 return exp.has_value()
4164 ? result(*std::forward<Exp>(exp))
4165 : result(unexpect, detail::invoke(std::forward<F>(f),
4166 std::forward<Exp>(exp).error()));
4167}
4168template <class Exp, class F,
4169 detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
4170 class Ret = decltype(detail::invoke(std::declval<F>(),
4171 std::declval<Exp>().error())),
4172 detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
4173auto map_error_impl(Exp &&exp, F &&f) {
4174 using result = expected<exp_t<Exp>, monostate>;
4175 if (exp.has_value()) {
4176 return result(*std::forward<Exp>(exp));
4177 }
4178
4179 detail::invoke(std::forward<F>(f), std::forward<Exp>(exp).error());
4180 return result(unexpect, monostate{});
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>
4187constexpr auto map_error_impl(Exp &&exp, F &&f) {
4188 using result = expected<exp_t<Exp>, detail::decay_t<Ret>>;
4189 return exp.has_value()
4190 ? result()
4191 : result(unexpect, detail::invoke(std::forward<F>(f),
4192 std::forward<Exp>(exp).error()));
4193}
4194template <class Exp, class F,
4195 detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
4196 class Ret = decltype(detail::invoke(std::declval<F>(),
4197 std::declval<Exp>().error())),
4198 detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
4199auto map_error_impl(Exp &&exp, F &&f) {
4200 using result = expected<exp_t<Exp>, monostate>;
4201 if (exp.has_value()) {
4202 return result();
4203 }
4204
4205 detail::invoke(std::forward<F>(f), std::forward<Exp>(exp).error());
4206 return result(unexpect, monostate{});
4207}
4208#else
4209template <class Exp, class F,
4210 detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
4211 class Ret = decltype(detail::invoke(std::declval<F>(),
4212 std::declval<Exp>().error())),
4213 detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
4214constexpr auto map_error_impl(Exp &&exp, F &&f)
4217
4218 return exp.has_value()
4219 ? result(*std::forward<Exp>(exp))
4220 : result(unexpect, detail::invoke(std::forward<F>(f),
4221 std::forward<Exp>(exp).error()));
4222}
4223
4224template <class Exp, class F,
4226 class Ret = decltype(detail::invoke(std::declval<F>(),
4227 std::declval<Exp>().error())),
4228 detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
4229auto map_error_impl(Exp &&exp, F &&f) -> expected<exp_t<Exp>, monostate> {
4230 using result = expected<exp_t<Exp>, monostate>;
4231 if (exp.has_value()) {
4232 return result(*std::forward<Exp>(exp));
4233 }
4234
4235 detail::invoke(std::forward<F>(f), std::forward<Exp>(exp).error());
4236 return result(unexpect, monostate{});
4237}
4238
4239template <class Exp, class F,
4241 class Ret = decltype(detail::invoke(std::declval<F>(),
4242 std::declval<Exp>().error())),
4243 detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
4244constexpr auto map_error_impl(Exp &&exp, F &&f)
4247
4248 return exp.has_value()
4249 ? result()
4250 : result(unexpect, detail::invoke(std::forward<F>(f),
4251 std::forward<Exp>(exp).error()));
4252}
4253
4254template <class Exp, class F,
4255 detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
4256 class Ret = decltype(detail::invoke(std::declval<F>(),
4257 std::declval<Exp>().error())),
4258 detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
4259auto map_error_impl(Exp &&exp, F &&f) -> expected<exp_t<Exp>, monostate> {
4260 using result = expected<exp_t<Exp>, monostate>;
4261 if (exp.has_value()) {
4262 return result();
4263 }
4264
4265 detail::invoke(std::forward<F>(f), std::forward<Exp>(exp).error());
4266 return result(unexpect, monostate{});
4267}
4268#endif
4269
4270#ifdef TL_EXPECTED_CXX14
4271template <class Exp, class F,
4272 class Ret = decltype(detail::invoke(std::declval<F>(),
4273 std::declval<Exp>().error())),
4274 detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
4275constexpr auto or_else_impl(Exp &&exp, F &&f) {
4276 static_assert(detail::is_expected<Ret>::value, "F must return an expected");
4277 return exp.has_value() ? std::forward<Exp>(exp)
4278 : detail::invoke(std::forward<F>(f),
4279 std::forward<Exp>(exp).error());
4280}
4281
4282template <class Exp, class F,
4283 class Ret = decltype(detail::invoke(std::declval<F>(),
4284 std::declval<Exp>().error())),
4285 detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
4286detail::decay_t<Exp> or_else_impl(Exp &&exp, F &&f) {
4287 return exp.has_value() ? std::forward<Exp>(exp)
4288 : (detail::invoke(std::forward<F>(f),
4289 std::forward<Exp>(exp).error()),
4290 std::forward<Exp>(exp));
4291}
4292#else
4293template <class Exp, class F,
4294 class Ret = decltype(detail::invoke(std::declval<F>(),
4295 std::declval<Exp>().error())),
4296 detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
4297auto or_else_impl(Exp &&exp, F &&f) -> Ret {
4298 static_assert(detail::is_expected<Ret>::value, "F must return an expected");
4299 return exp.has_value() ? std::forward<Exp>(exp)
4300 : detail::invoke(std::forward<F>(f),
4301 std::forward<Exp>(exp).error());
4302}
4303
4304template <class Exp, class F,
4305 class Ret = decltype(detail::invoke(std::declval<F>(),
4306 std::declval<Exp>().error())),
4307 detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
4309 return exp.has_value() ? std::forward<Exp>(exp)
4310 : (detail::invoke(std::forward<F>(f),
4311 std::forward<Exp>(exp).error()),
4312 std::forward<Exp>(exp));
4313}
4314#endif
4315} // namespace detail
4316
4317template <class T, class E, class U, class F>
4318constexpr bool operator==(const expected<T, E> &lhs,
4319 const expected<U, F> &rhs) {
4320 return (lhs.has_value() != rhs.has_value())
4321 ? false
4322 : (!lhs.has_value() ? lhs.error() == rhs.error() : *lhs == *rhs);
4323}
4324template <class T, class E, class U, class F>
4325constexpr bool operator!=(const expected<T, E> &lhs,
4326 const expected<U, F> &rhs) {
4327 return (lhs.has_value() != rhs.has_value())
4328 ? true
4329 : (!lhs.has_value() ? lhs.error() != rhs.error() : *lhs != *rhs);
4330}
4331template <class E, class F>
4332constexpr bool operator==(const expected<void, E> &lhs,
4333 const expected<void, F> &rhs) {
4334 return (lhs.has_value() != rhs.has_value())
4335 ? false
4336 : (!lhs.has_value() ? lhs.error() == rhs.error() : true);
4337}
4338template <class E, class F>
4339constexpr bool operator!=(const expected<void, E> &lhs,
4340 const expected<void, F> &rhs) {
4341 return (lhs.has_value() != rhs.has_value())
4342 ? true
4343 : (!lhs.has_value() ? lhs.error() == rhs.error() : false);
4344}
4345
4346template <class T, class E, class U>
4347constexpr bool operator==(const expected<T, E> &x, const U &v) {
4348 return x.has_value() ? *x == v : false;
4349}
4350template <class T, class E, class U>
4351constexpr bool operator==(const U &v, const expected<T, E> &x) {
4352 return x.has_value() ? *x == v : false;
4353}
4354template <class T, class E, class U>
4355constexpr bool operator!=(const expected<T, E> &x, const U &v) {
4356 return x.has_value() ? *x != v : true;
4357}
4358template <class T, class E, class U>
4359constexpr bool operator!=(const U &v, const expected<T, E> &x) {
4360 return x.has_value() ? *x != v : true;
4361}
4362
4363template <class T, class E>
4364constexpr bool operator==(const expected<T, E> &x, const unexpected<E> &e) {
4365 return x.has_value() ? false : x.error() == e.value();
4366}
4367template <class T, class E>
4368constexpr bool operator==(const unexpected<E> &e, const expected<T, E> &x) {
4369 return x.has_value() ? false : x.error() == e.value();
4370}
4371template <class T, class E>
4372constexpr bool operator!=(const expected<T, E> &x, const unexpected<E> &e) {
4373 return x.has_value() ? true : x.error() != e.value();
4374}
4375template <class T, class E>
4376constexpr bool operator!=(const unexpected<E> &e, const expected<T, E> &x) {
4377 return x.has_value() ? true : x.error() != e.value();
4378}
4379
4380template <class T, class E,
4381 detail::enable_if_t<(std::is_void<T>::value ||
4382 std::is_move_constructible<T>::value) &&
4383 detail::is_swappable<T>::value &&
4384 std::is_move_constructible<E>::value &&
4385 detail::is_swappable<E>::value> * = nullptr>
4386void swap(expected<T, E> &lhs,
4387 expected<T, E> &rhs) noexcept(noexcept(lhs.swap(rhs))) {
4388 lhs.swap(rhs);
4389}
4390} // namespace tl
4391
4392#endif
4393/* end file include/ada/expected.h */
4394
4398namespace ada {
4399struct url_aggregator;
4400struct url;
4401} // namespace ada
4402
4407namespace ada::parser {
4414template <typename result_type = ada::url_aggregator>
4415result_type parse_url(std::string_view user_input,
4416 const result_type* base_url = nullptr);
4417
4418extern template url_aggregator parse_url<url_aggregator>(
4419 std::string_view user_input, const url_aggregator* base_url);
4420extern template url parse_url<url>(std::string_view user_input,
4421 const url* base_url);
4422
4423template <typename result_type = ada::url_aggregator, bool store_values = true>
4424result_type parse_url_impl(std::string_view user_input,
4425 const result_type* base_url = nullptr);
4426
4427extern template url_aggregator parse_url_impl<url_aggregator>(
4428 std::string_view user_input, const url_aggregator* base_url);
4429extern template url parse_url_impl<url>(std::string_view user_input,
4430 const url* base_url);
4431} // namespace ada::parser
4432
4433#endif // ADA_PARSER_H
4434/* end file include/ada/parser.h */
4435/* begin file include/ada/scheme-inl.h */
4440#ifndef ADA_SCHEME_INL_H
4441#define ADA_SCHEME_INL_H
4442
4443
4444namespace ada::scheme {
4445
4450namespace details {
4451// for use with is_special and get_special_port
4452// Spaces, if present, are removed from URL.
4453constexpr std::string_view is_special_list[] = {"http", " ", "https", "ws",
4454 "ftp", "wss", "file", " "};
4455// for use with get_special_port
4456constexpr uint16_t special_ports[] = {80, 0, 443, 80, 21, 443, 0, 0};
4457} // namespace details
4458
4459
4483ada_really_inline constexpr bool is_special(std::string_view scheme) {
4484 if (scheme.empty()) {
4485 return false;
4486 }
4487 int hash_value = (2 * scheme.size() + (unsigned)(scheme[0])) & 7;
4488 const std::string_view target = details::is_special_list[hash_value];
4489 return (target[0] == scheme[0]) && (target.substr(1) == scheme.substr(1));
4490}
4491constexpr uint16_t get_special_port(std::string_view scheme) noexcept {
4492 if (scheme.empty()) {
4493 return 0;
4494 }
4495 int hash_value = (2 * scheme.size() + (unsigned)(scheme[0])) & 7;
4496 const std::string_view target = details::is_special_list[hash_value];
4497 if ((target[0] == scheme[0]) && (target.substr(1) == scheme.substr(1))) {
4498 return details::special_ports[hash_value];
4499 } else {
4500 return 0;
4501 }
4502}
4503constexpr uint16_t get_special_port(ada::scheme::type type) noexcept {
4504 return details::special_ports[int(type)];
4505}
4506constexpr ada::scheme::type get_scheme_type(std::string_view scheme) noexcept {
4507 if (scheme.empty()) {
4509 }
4510 int hash_value = (2 * scheme.size() + (unsigned)(scheme[0])) & 7;
4511 const std::string_view target = details::is_special_list[hash_value];
4512 if ((target[0] == scheme[0]) && (target.substr(1) == scheme.substr(1))) {
4513 return ada::scheme::type(hash_value);
4514 } else {
4516 }
4517}
4518
4519} // namespace ada::scheme
4520
4521#endif // ADA_SCHEME_INL_H
4522/* end file include/ada/scheme-inl.h */
4523/* begin file include/ada/serializers.h */
4528#ifndef ADA_SERIALIZERS_H
4529#define ADA_SERIALIZERS_H
4530
4531
4532#include <array>
4533#include <optional>
4534#include <string>
4535
4540namespace ada::serializers {
4541
4545void find_longest_sequence_of_ipv6_pieces(
4546 const std::array<uint16_t, 8>& address, size_t& compress,
4547 size_t& compress_length) noexcept;
4548
4555std::string ipv6(const std::array<uint16_t, 8>& address) noexcept;
4556
4563std::string ipv4(uint64_t address) noexcept;
4564
4565} // namespace ada::serializers
4566
4567#endif // ADA_SERIALIZERS_H
4568/* end file include/ada/serializers.h */
4569/* begin file include/ada/unicode.h */
4574#ifndef ADA_UNICODE_H
4575#define ADA_UNICODE_H
4576
4577
4578#include <string>
4579#include <optional>
4580
4589namespace ada::unicode {
4590
4632bool to_ascii(std::optional<std::string>& out, std::string_view plain,
4633 size_t first_percent);
4634
4642ada_really_inline bool has_tabs_or_newline(
4643 std::string_view user_input) noexcept;
4644
4650ada_really_inline constexpr bool is_forbidden_host_code_point(char c) noexcept;
4651
4657ada_really_inline constexpr bool contains_forbidden_domain_code_point(
4658 const char* input, size_t length) noexcept;
4659
4667ada_really_inline constexpr uint8_t
4668contains_forbidden_domain_code_point_or_upper(const char* input,
4669 size_t length) noexcept;
4670
4676ada_really_inline constexpr bool is_forbidden_domain_code_point(
4677 char c) noexcept;
4678
4683ada_really_inline constexpr bool is_alnum_plus(char c) noexcept;
4684
4692ada_really_inline constexpr bool is_ascii_hex_digit(char c) noexcept;
4693
4702ada_really_inline constexpr bool is_c0_control_or_space(char c) noexcept;
4703
4710ada_really_inline constexpr bool is_ascii_tab_or_newline(char c) noexcept;
4711
4717ada_really_inline ada_constexpr bool is_double_dot_path_segment(
4718 std::string_view input) noexcept;
4719
4725ada_really_inline constexpr bool is_single_dot_path_segment(
4726 std::string_view input) noexcept;
4727
4732ada_really_inline constexpr bool is_lowercase_hex(char c) noexcept;
4733
4739ada_really_inline unsigned constexpr convert_hex_to_binary(char c) noexcept;
4740
4750std::string percent_decode(std::string_view input, size_t first_percent);
4751
4757std::string percent_encode(std::string_view input,
4758 const uint8_t character_set[]);
4765std::string percent_encode(std::string_view input,
4766 const uint8_t character_set[], size_t index);
4775template <bool append>
4776bool percent_encode(std::string_view input, const uint8_t character_set[],
4777 std::string& out);
4783ada_really_inline size_t percent_encode_index(std::string_view input,
4784 const uint8_t character_set[]);
4790constexpr bool to_lower_ascii(char* input, size_t length) noexcept;
4791} // namespace ada::unicode
4792
4793#endif // ADA_UNICODE_H
4794/* end file include/ada/unicode.h */
4795/* begin file include/ada/url_base-inl.h */
4800#ifndef ADA_URL_BASE_INL_H
4801#define ADA_URL_BASE_INL_H
4802
4803/* begin file include/ada/url_aggregator.h */
4808#ifndef ADA_URL_AGGREGATOR_H
4809#define ADA_URL_AGGREGATOR_H
4810
4811#include <string>
4812#include <string_view>
4813
4814
4815namespace ada {
4816
4826 url_aggregator() = default;
4827 url_aggregator(const url_aggregator &u) = default;
4828 url_aggregator(url_aggregator &&u) noexcept = default;
4829 url_aggregator &operator=(url_aggregator &&u) noexcept = default;
4831 ~url_aggregator() override = default;
4832
4833 bool set_href(std::string_view input);
4834 bool set_host(std::string_view input);
4835 bool set_hostname(std::string_view input);
4836 bool set_protocol(std::string_view input);
4837 bool set_username(std::string_view input);
4838 bool set_password(std::string_view input);
4839 bool set_port(std::string_view input);
4840 bool set_pathname(std::string_view input);
4841 void set_search(std::string_view input);
4842 void set_hash(std::string_view input);
4843
4844 [[nodiscard]] bool has_valid_domain() const noexcept override;
4851 [[nodiscard]] std::string get_origin() const noexcept override;
4860 [[nodiscard]] inline std::string_view get_href() const noexcept
4868 [[nodiscard]] std::string_view get_username() const noexcept
4876 [[nodiscard]] std::string_view get_password() const noexcept
4884 [[nodiscard]] std::string_view get_port() const noexcept ada_lifetime_bound;
4891 [[nodiscard]] std::string_view get_hash() const noexcept ada_lifetime_bound;
4900 [[nodiscard]] std::string_view get_host() const noexcept ada_lifetime_bound;
4908 [[nodiscard]] std::string_view get_hostname() const noexcept
4917 [[nodiscard]] std::string_view get_pathname() const noexcept
4925 [[nodiscard]] ada_really_inline uint32_t get_pathname_length() const noexcept;
4932 [[nodiscard]] std::string_view get_search() const noexcept ada_lifetime_bound;
4940 [[nodiscard]] std::string_view get_protocol() const noexcept
4942
4947 [[nodiscard]] ada_really_inline bool has_credentials() const noexcept;
4948
4970 [[nodiscard]] ada_really_inline const ada::url_components &get_components()
4971 const noexcept;
4975 [[nodiscard]] std::string to_string() const override;
4979 [[nodiscard]] std::string to_diagram() const;
4980
4986 [[nodiscard]] bool validate() const noexcept;
4987
4989 [[nodiscard]] inline bool has_empty_hostname() const noexcept;
4991 [[nodiscard]] inline bool has_hostname() const noexcept;
4993 [[nodiscard]] inline bool has_non_empty_username() const noexcept;
4995 [[nodiscard]] inline bool has_non_empty_password() const noexcept;
4997 [[nodiscard]] inline bool has_port() const noexcept;
4999 [[nodiscard]] inline bool has_password() const noexcept;
5001 [[nodiscard]] inline bool has_hash() const noexcept override;
5003 [[nodiscard]] inline bool has_search() const noexcept override;
5004
5005 inline void clear_port();
5006 inline void clear_hash();
5007 inline void clear_search() override;
5008
5009 private:
5010 friend ada::url_aggregator ada::parser::parse_url<ada::url_aggregator>(
5011 std::string_view, const ada::url_aggregator *);
5012 friend void ada::helpers::strip_trailing_spaces_from_opaque_path<
5013 ada::url_aggregator>(ada::url_aggregator &url) noexcept;
5014 friend ada::url_aggregator ada::parser::parse_url_impl<
5015 ada::url_aggregator, true>(std::string_view, const ada::url_aggregator *);
5017 ada::parser::parse_url_impl<ada::url_aggregator, false>(
5018 std::string_view, const ada::url_aggregator *);
5019
5020 std::string buffer{};
5021 url_components components{};
5022
5028 [[nodiscard]] ada_really_inline bool is_at_path() const noexcept;
5029
5030 inline void add_authority_slashes_if_needed() noexcept;
5031
5036 inline void reserve(uint32_t capacity);
5037
5038 ada_really_inline size_t parse_port(
5039 std::string_view view, bool check_trailing_content) noexcept override;
5040
5041 ada_really_inline size_t parse_port(std::string_view view) noexcept override {
5042 return this->parse_port(view, false);
5043 }
5044
5051 [[nodiscard]] bool parse_ipv4(std::string_view input, bool in_place);
5052
5057 [[nodiscard]] bool parse_ipv6(std::string_view input);
5058
5063 [[nodiscard]] bool parse_opaque_host(std::string_view input);
5064
5065 ada_really_inline void parse_path(std::string_view input);
5066
5071 [[nodiscard]] inline bool cannot_have_credentials_or_port() const;
5072
5073 template <bool override_hostname = false>
5074 bool set_host_or_hostname(std::string_view input);
5075
5076 ada_really_inline bool parse_host(std::string_view input);
5077
5078 inline void update_base_authority(std::string_view base_buffer,
5079 const ada::url_components &base);
5080 inline void update_unencoded_base_hash(std::string_view input);
5081 inline void update_base_hostname(std::string_view input);
5082 inline void update_base_search(std::string_view input);
5083 inline void update_base_search(std::string_view input,
5084 const uint8_t *query_percent_encode_set);
5085 inline void update_base_pathname(std::string_view input);
5086 inline void update_base_username(std::string_view input);
5087 inline void append_base_username(std::string_view input);
5088 inline void update_base_password(std::string_view input);
5089 inline void append_base_password(std::string_view input);
5090 inline void update_base_port(uint32_t input);
5091 inline void append_base_pathname(std::string_view input);
5092 [[nodiscard]] inline uint32_t retrieve_base_port() const;
5093 inline void clear_hostname();
5094 inline void clear_password();
5095 inline void clear_pathname() override;
5096 [[nodiscard]] inline bool has_dash_dot() const noexcept;
5097 void delete_dash_dot();
5098 inline void consume_prepared_path(std::string_view input);
5099 template <bool has_state_override = false>
5100 [[nodiscard]] ada_really_inline bool parse_scheme_with_colon(
5101 std::string_view input);
5102 ada_really_inline uint32_t replace_and_resize(uint32_t start, uint32_t end,
5103 std::string_view input);
5104 [[nodiscard]] inline bool has_authority() const noexcept;
5105 inline void set_protocol_as_file();
5106 inline void set_scheme(std::string_view new_scheme) noexcept;
5111 inline void set_scheme_from_view_with_colon(
5112 std::string_view new_scheme_with_colon) noexcept;
5113 inline void copy_scheme(const url_aggregator &u) noexcept;
5114
5115}; // url_aggregator
5116
5117inline std::ostream &operator<<(std::ostream &out, const ada::url &u);
5118} // namespace ada
5119
5120#endif
5121/* end file include/ada/url_aggregator.h */
5122/* begin file include/ada/checkers.h */
5127#ifndef ADA_CHECKERS_H
5128#define ADA_CHECKERS_H
5129
5130
5131#include <string_view>
5132#include <cstring>
5133
5141namespace ada::checkers {
5142
5149constexpr char to_lower(char x) noexcept;
5150
5158constexpr bool is_alpha(char x) noexcept;
5159
5167inline bool has_hex_prefix_unsafe(std::string_view input);
5172inline bool has_hex_prefix(std::string_view input);
5173
5179constexpr bool is_digit(char x) noexcept;
5180
5193inline constexpr bool is_windows_drive_letter(std::string_view input) noexcept;
5194
5200inline constexpr bool is_normalized_windows_drive_letter(
5201 std::string_view input) noexcept;
5202
5207ada_really_inline bool begins_with(std::string_view view,
5208 std::string_view prefix);
5209
5216ada_really_inline ada_constexpr bool is_ipv4(std::string_view view) noexcept;
5217
5225ada_really_inline constexpr uint8_t path_signature(
5226 std::string_view input) noexcept;
5227
5239ada_really_inline constexpr bool verify_dns_length(
5240 std::string_view input) noexcept;
5241
5242} // namespace ada::checkers
5243
5244#endif // ADA_CHECKERS_H
5245/* end file include/ada/checkers.h */
5246/* begin file include/ada/url.h */
5251#ifndef ADA_URL_H
5252#define ADA_URL_H
5253
5254#include <algorithm>
5255#include <charconv>
5256#include <iostream>
5257#include <optional>
5258#include <string>
5259#include <string_view>
5260
5261
5262namespace ada {
5263
5276struct url : url_base {
5277 url() = default;
5278 url(const url &u) = default;
5279 url(url &&u) noexcept = default;
5280 url &operator=(url &&u) noexcept = default;
5281 url &operator=(const url &u) = default;
5282 ~url() override = default;
5283
5289 std::string username{};
5290
5296 std::string password{};
5297
5302 std::optional<std::string> host{};
5303
5309 std::optional<uint16_t> port{};
5310
5316 std::string path{};
5317
5322 std::optional<std::string> query{};
5323
5330 std::optional<std::string> hash{};
5331
5333 [[nodiscard]] inline bool has_empty_hostname() const noexcept;
5335 [[nodiscard]] inline bool has_port() const noexcept;
5337 [[nodiscard]] inline bool has_hostname() const noexcept;
5338 [[nodiscard]] bool has_valid_domain() const noexcept override;
5339
5343 [[nodiscard]] std::string to_string() const override;
5344
5349 [[nodiscard]] ada_really_inline std::string get_href() const noexcept;
5350
5357 [[nodiscard]] std::string get_origin() const noexcept override;
5358
5365 [[nodiscard]] std::string get_protocol() const noexcept;
5366
5374 [[nodiscard]] std::string get_host() const noexcept;
5375
5382 [[nodiscard]] std::string get_hostname() const noexcept;
5383
5390 [[nodiscard]] std::string_view get_pathname() const noexcept;
5391
5398 [[nodiscard]] ada_really_inline size_t get_pathname_length() const noexcept;
5399
5405 [[nodiscard]] std::string get_search() const noexcept;
5406
5412 [[nodiscard]] const std::string &get_username() const noexcept;
5413
5418 bool set_username(std::string_view input);
5419
5424 bool set_password(std::string_view input);
5425
5430 bool set_port(std::string_view input);
5431
5436 void set_hash(std::string_view input);
5437
5442 void set_search(std::string_view input);
5443
5448 bool set_pathname(std::string_view input);
5449
5454 bool set_host(std::string_view input);
5455
5460 bool set_hostname(std::string_view input);
5461
5466 bool set_protocol(std::string_view input);
5467
5471 bool set_href(std::string_view input);
5472
5478 [[nodiscard]] const std::string &get_password() const noexcept;
5479
5485 [[nodiscard]] std::string get_port() const noexcept;
5486
5492 [[nodiscard]] std::string get_hash() const noexcept;
5493
5498 [[nodiscard]] ada_really_inline bool has_credentials() const noexcept;
5499
5521 [[nodiscard]] ada_really_inline ada::url_components get_components()
5522 const noexcept;
5524 [[nodiscard]] inline bool has_hash() const noexcept override;
5526 [[nodiscard]] inline bool has_search() const noexcept override;
5527
5528 private:
5529 friend ada::url ada::parser::parse_url<ada::url>(std::string_view,
5530 const ada::url *);
5531 friend ada::url_aggregator ada::parser::parse_url<ada::url_aggregator>(
5532 std::string_view, const ada::url_aggregator *);
5533 friend void ada::helpers::strip_trailing_spaces_from_opaque_path<ada::url>(
5534 ada::url &url) noexcept;
5535
5536 friend ada::url ada::parser::parse_url_impl<ada::url, true>(std::string_view,
5537 const ada::url *);
5538 friend ada::url_aggregator ada::parser::parse_url_impl<
5539 ada::url_aggregator, true>(std::string_view, const ada::url_aggregator *);
5540
5541 inline void update_unencoded_base_hash(std::string_view input);
5542 inline void update_base_hostname(std::string_view input);
5543 inline void update_base_search(std::string_view input);
5544 inline void update_base_search(std::string_view input,
5545 const uint8_t query_percent_encode_set[]);
5546 inline void update_base_search(std::optional<std::string> input);
5547 inline void update_base_pathname(std::string_view input);
5548 inline void update_base_username(std::string_view input);
5549 inline void update_base_password(std::string_view input);
5550 inline void update_base_port(std::optional<uint16_t> input);
5551
5557 template <bool override_hostname = false>
5558 bool set_host_or_hostname(std::string_view input);
5559
5564 [[nodiscard]] bool parse_ipv4(std::string_view input);
5565
5570 [[nodiscard]] bool parse_ipv6(std::string_view input);
5571
5576 [[nodiscard]] bool parse_opaque_host(std::string_view input);
5577
5587 std::string non_special_scheme{};
5588
5593 [[nodiscard]] inline bool cannot_have_credentials_or_port() const;
5594
5595 ada_really_inline size_t parse_port(
5596 std::string_view view, bool check_trailing_content) noexcept override;
5597
5598 ada_really_inline size_t parse_port(std::string_view view) noexcept override {
5599 return this->parse_port(view, false);
5600 }
5601
5606 inline void copy_scheme(const ada::url &u);
5607
5616 [[nodiscard]] ada_really_inline bool parse_host(std::string_view input);
5617
5618 template <bool has_state_override = false>
5619 [[nodiscard]] ada_really_inline bool parse_scheme(std::string_view input);
5620
5621 inline void clear_pathname() override;
5622 inline void clear_search() override;
5623 inline void set_protocol_as_file();
5624
5635 ada_really_inline void parse_path(std::string_view input);
5636
5642 inline void set_scheme(std::string &&new_scheme) noexcept;
5643
5648 inline void copy_scheme(ada::url &&u) noexcept;
5649
5650}; // struct url
5651
5652inline std::ostream &operator<<(std::ostream &out, const ada::url &u);
5653} // namespace ada
5654
5655#endif // ADA_URL_H
5656/* end file include/ada/url.h */
5657
5658#include <optional>
5659#include <string>
5660#if ADA_REGULAR_VISUAL_STUDIO
5661#include <intrin.h>
5662#endif // ADA_REGULAR_VISUAL_STUDIO
5663
5664namespace ada {
5665
5666[[nodiscard]] ada_really_inline bool url_base::is_special() const noexcept {
5668}
5669
5670[[nodiscard]] inline uint16_t url_base::get_special_port() const noexcept {
5671 return ada::scheme::get_special_port(type);
5672}
5673
5674[[nodiscard]] ada_really_inline uint16_t
5675url_base::scheme_default_port() const noexcept {
5676 return scheme::get_special_port(type);
5677}
5678
5679} // namespace ada
5680
5681#endif // ADA_URL_BASE_INL_H
5682/* end file include/ada/url_base-inl.h */
5683/* begin file include/ada/url-inl.h */
5688#ifndef ADA_URL_INL_H
5689#define ADA_URL_INL_H
5690
5691
5692#include <optional>
5693#include <string>
5694#if ADA_REGULAR_VISUAL_STUDIO
5695#include <intrin.h>
5696#endif // ADA_REGULAR_VISUAL_STUDIO
5697
5698namespace ada {
5699[[nodiscard]] ada_really_inline bool url::has_credentials() const noexcept {
5700 return !username.empty() || !password.empty();
5701}
5702[[nodiscard]] ada_really_inline bool url::has_port() const noexcept {
5703 return port.has_value();
5704}
5705[[nodiscard]] inline bool url::cannot_have_credentials_or_port() const {
5706 return !host.has_value() || host.value().empty() ||
5707 type == ada::scheme::type::FILE;
5708}
5709[[nodiscard]] inline bool url::has_empty_hostname() const noexcept {
5710 if (!host.has_value()) {
5711 return false;
5712 }
5713 return host.value().empty();
5714}
5715[[nodiscard]] inline bool url::has_hostname() const noexcept {
5716 return host.has_value();
5717}
5718inline std::ostream &operator<<(std::ostream &out, const ada::url &u) {
5719 return out << u.to_string();
5720}
5721
5722[[nodiscard]] size_t url::get_pathname_length() const noexcept {
5723 return path.size();
5724}
5725
5726[[nodiscard]] ada_really_inline ada::url_components url::get_components()
5727 const noexcept {
5728 url_components out{};
5729
5730 // protocol ends with ':'. for example: "https:"
5731 out.protocol_end = uint32_t(get_protocol().size());
5732
5733 // Trailing index is always the next character of the current one.
5734 size_t running_index = out.protocol_end;
5735
5736 if (host.has_value()) {
5737 // 2 characters for "//" and 1 character for starting index
5738 out.host_start = out.protocol_end + 2;
5739
5740 if (has_credentials()) {
5741 out.username_end = uint32_t(out.host_start + username.size());
5742
5743 out.host_start += uint32_t(username.size());
5744
5745 if (!password.empty()) {
5746 out.host_start += uint32_t(password.size() + 1);
5747 }
5748
5749 out.host_end = uint32_t(out.host_start + host.value().size());
5750 } else {
5751 out.username_end = out.host_start;
5752
5753 // Host does not start with "@" if it does not include credentials.
5754 out.host_end = uint32_t(out.host_start + host.value().size()) - 1;
5755 }
5756
5757 running_index = out.host_end + 1;
5758 } else {
5759 // Update host start and end date to the same index, since it does not
5760 // exist.
5761 out.host_start = out.protocol_end;
5762 out.host_end = out.host_start;
5763
5764 if (!has_opaque_path && checkers::begins_with(path, "//")) {
5765 // If url's host is null, url does not have an opaque path, url's path's
5766 // size is greater than 1, and url's path[0] is the empty string, then
5767 // append U+002F (/) followed by U+002E (.) to output.
5768 running_index = out.protocol_end + 2;
5769 } else {
5770 running_index = out.protocol_end;
5771 }
5772 }
5773
5774 if (port.has_value()) {
5775 out.port = *port;
5776 running_index += helpers::fast_digit_count(*port) + 1; // Port omits ':'
5777 }
5778
5779 out.pathname_start = uint32_t(running_index);
5780
5781 running_index += path.size();
5782
5783 if (query.has_value()) {
5784 out.search_start = uint32_t(running_index);
5785 running_index += get_search().size();
5786 if (get_search().empty()) {
5787 running_index++;
5788 }
5789 }
5790
5791 if (hash.has_value()) {
5792 out.hash_start = uint32_t(running_index);
5793 }
5794
5795 return out;
5796}
5797
5798inline void url::update_base_hostname(std::string_view input) { host = input; }
5799
5800inline void url::update_unencoded_base_hash(std::string_view input) {
5801 // We do the percent encoding
5802 hash = unicode::percent_encode(input,
5804}
5805
5806inline void url::update_base_search(std::string_view input,
5807 const uint8_t query_percent_encode_set[]) {
5808 query = ada::unicode::percent_encode(input, query_percent_encode_set);
5809}
5810
5811inline void url::update_base_search(std::optional<std::string> input) {
5812 query = input;
5813}
5814
5815inline void url::update_base_pathname(const std::string_view input) {
5816 path = input;
5817}
5818
5819inline void url::update_base_username(const std::string_view input) {
5820 username = input;
5821}
5822
5823inline void url::update_base_password(const std::string_view input) {
5824 password = input;
5825}
5826
5827inline void url::update_base_port(std::optional<uint16_t> input) {
5828 port = input;
5829}
5830
5831inline void url::clear_pathname() { path.clear(); }
5832
5833inline void url::clear_search() { query = std::nullopt; }
5834
5835[[nodiscard]] inline bool url::has_hash() const noexcept {
5836 return hash.has_value();
5837}
5838
5839[[nodiscard]] inline bool url::has_search() const noexcept {
5840 return query.has_value();
5841}
5842
5843inline void url::set_protocol_as_file() { type = ada::scheme::type::FILE; }
5844
5845inline void url::set_scheme(std::string &&new_scheme) noexcept {
5846 type = ada::scheme::get_scheme_type(new_scheme);
5847 // We only move the 'scheme' if it is non-special.
5848 if (!is_special()) {
5849 non_special_scheme = std::move(new_scheme);
5850 }
5851}
5852
5853inline void url::copy_scheme(ada::url &&u) noexcept {
5854 non_special_scheme = u.non_special_scheme;
5855 type = u.type;
5856}
5857
5858inline void url::copy_scheme(const ada::url &u) {
5859 non_special_scheme = u.non_special_scheme;
5860 type = u.type;
5861}
5862
5863[[nodiscard]] ada_really_inline std::string url::get_href() const noexcept {
5864 std::string output = get_protocol();
5865
5866 if (host.has_value()) {
5867 output += "//";
5868 if (has_credentials()) {
5869 output += username;
5870 if (!password.empty()) {
5871 output += ":" + get_password();
5872 }
5873 output += "@";
5874 }
5875 output += host.value();
5876 if (port.has_value()) {
5877 output += ":" + get_port();
5878 }
5879 } else if (!has_opaque_path && checkers::begins_with(path, "//")) {
5880 // If url's host is null, url does not have an opaque path, url's path's
5881 // size is greater than 1, and url's path[0] is the empty string, then
5882 // append U+002F (/) followed by U+002E (.) to output.
5883 output += "/.";
5884 }
5885 output += path;
5886 if (query.has_value()) {
5887 output += "?" + query.value();
5888 }
5889 if (hash.has_value()) {
5890 output += "#" + hash.value();
5891 }
5892 return output;
5893}
5894
5895ada_really_inline size_t url::parse_port(std::string_view view,
5896 bool check_trailing_content) noexcept {
5897 ada_log("parse_port('", view, "') ", view.size());
5898 if (!view.empty() && view[0] == '-') {
5899 ada_log("parse_port: view[0] == '0' && view.size() > 1");
5900 is_valid = false;
5901 return 0;
5902 }
5903 uint16_t parsed_port{};
5904 auto r = std::from_chars(view.data(), view.data() + view.size(), parsed_port);
5905 if (r.ec == std::errc::result_out_of_range) {
5906 ada_log("parse_port: r.ec == std::errc::result_out_of_range");
5907 is_valid = false;
5908 return 0;
5909 }
5910 ada_log("parse_port: ", parsed_port);
5911 const size_t consumed = size_t(r.ptr - view.data());
5912 ada_log("parse_port: consumed ", consumed);
5913 if (check_trailing_content) {
5914 is_valid &=
5915 (consumed == view.size() || view[consumed] == '/' ||
5916 view[consumed] == '?' || (is_special() && view[consumed] == '\\'));
5917 }
5918 ada_log("parse_port: is_valid = ", is_valid);
5919 if (is_valid) {
5920 // scheme_default_port can return 0, and we should allow 0 as a base port.
5921 auto default_port = scheme_default_port();
5922 bool is_port_valid = (default_port == 0 && parsed_port == 0) ||
5923 (default_port != parsed_port);
5924 port = (r.ec == std::errc() && is_port_valid)
5925 ? std::optional<uint16_t>(parsed_port)
5926 : std::nullopt;
5927 }
5928 return consumed;
5929}
5930
5931} // namespace ada
5932
5933#endif // ADA_URL_H
5934/* end file include/ada/url-inl.h */
5935/* begin file include/ada/url_aggregator-inl.h */
5940#ifndef ADA_URL_AGGREGATOR_INL_H
5941#define ADA_URL_AGGREGATOR_INL_H
5942
5943/* begin file include/ada/unicode-inl.h */
5948#ifndef ADA_UNICODE_INL_H
5949#define ADA_UNICODE_INL_H
5950#include <algorithm>
5951
5960namespace ada::unicode {
5961ada_really_inline size_t percent_encode_index(const std::string_view input,
5962 const uint8_t character_set[]) {
5963 return std::distance(
5964 input.begin(),
5965 std::find_if(input.begin(), input.end(), [character_set](const char c) {
5966 return character_sets::bit_at(character_set, c);
5967 }));
5968}
5969} // namespace ada::unicode
5970
5971#endif // ADA_UNICODE_INL_H
5972/* end file include/ada/unicode-inl.h */
5973
5974#include <optional>
5975#include <string_view>
5976
5977namespace ada {
5978
5979inline void url_aggregator::update_base_authority(
5980 std::string_view base_buffer, const ada::url_components &base) {
5981 std::string_view input = base_buffer.substr(
5982 base.protocol_end, base.host_start - base.protocol_end);
5983 ada_log("url_aggregator::update_base_authority ", input);
5984
5985 bool input_starts_with_dash = checkers::begins_with(input, "//");
5986 uint32_t diff = components.host_start - components.protocol_end;
5987
5988 buffer.erase(components.protocol_end,
5989 components.host_start - components.protocol_end);
5990 components.username_end = components.protocol_end;
5991
5992 if (input_starts_with_dash) {
5993 input.remove_prefix(2);
5994 diff += 2; // add "//"
5995 buffer.insert(components.protocol_end, "//");
5996 components.username_end += 2;
5997 }
5998
5999 size_t password_delimiter = input.find(':');
6000
6001 // Check if input contains both username and password by checking the
6002 // delimiter: ":" A typical input that contains authority would be "user:pass"
6003 if (password_delimiter != std::string_view::npos) {
6004 // Insert both username and password
6005 std::string_view username = input.substr(0, password_delimiter);
6006 std::string_view password = input.substr(password_delimiter + 1);
6007
6008 buffer.insert(components.protocol_end + diff, username);
6009 diff += uint32_t(username.size());
6010 buffer.insert(components.protocol_end + diff, ":");
6011 components.username_end = components.protocol_end + diff;
6012 buffer.insert(components.protocol_end + diff + 1, password);
6013 diff += uint32_t(password.size()) + 1;
6014 } else if (!input.empty()) {
6015 // Insert only username
6016 buffer.insert(components.protocol_end + diff, input);
6017 components.username_end =
6018 components.protocol_end + diff + uint32_t(input.size());
6019 diff += uint32_t(input.size());
6020 }
6021
6022 components.host_start += diff;
6023
6024 if (buffer.size() > base.host_start && buffer[base.host_start] != '@') {
6025 buffer.insert(components.host_start, "@");
6026 diff++;
6027 }
6028 components.host_end += diff;
6029 components.pathname_start += diff;
6030 if (components.search_start != url_components::omitted) {
6031 components.search_start += diff;
6032 }
6033 if (components.hash_start != url_components::omitted) {
6034 components.hash_start += diff;
6035 }
6036}
6037
6038inline void url_aggregator::update_unencoded_base_hash(std::string_view input) {
6039 ada_log("url_aggregator::update_unencoded_base_hash ", input, " [",
6040 input.size(), " bytes], buffer is '", buffer, "' [", buffer.size(),
6041 " bytes] components.hash_start = ", components.hash_start);
6042 ADA_ASSERT_TRUE(validate());
6043 ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
6044 if (components.hash_start != url_components::omitted) {
6045 buffer.resize(components.hash_start);
6046 }
6047 components.hash_start = uint32_t(buffer.size());
6048 buffer += "#";
6049 bool encoding_required = unicode::percent_encode<true>(
6051 // When encoding_required is false, then buffer is left unchanged, and percent
6052 // encoding was not deemed required.
6053 if (!encoding_required) {
6054 buffer.append(input);
6055 }
6056 ada_log("url_aggregator::update_unencoded_base_hash final buffer is '",
6057 buffer, "' [", buffer.size(), " bytes]");
6058 ADA_ASSERT_TRUE(validate());
6059}
6060
6061ada_really_inline uint32_t url_aggregator::replace_and_resize(
6062 uint32_t start, uint32_t end, std::string_view input) {
6063 uint32_t current_length = end - start;
6064 uint32_t input_size = uint32_t(input.size());
6065 uint32_t new_difference = input_size - current_length;
6066
6067 if (current_length == 0) {
6068 buffer.insert(start, input);
6069 } else if (input_size == current_length) {
6070 buffer.replace(start, input_size, input);
6071 } else if (input_size < current_length) {
6072 buffer.erase(start, current_length - input_size);
6073 buffer.replace(start, input_size, input);
6074 } else {
6075 buffer.replace(start, current_length, input.substr(0, current_length));
6076 buffer.insert(start + current_length, input.substr(current_length));
6077 }
6078
6079 return new_difference;
6080}
6081
6082inline void url_aggregator::update_base_hostname(const std::string_view input) {
6083 ada_log("url_aggregator::update_base_hostname ", input, " [", input.size(),
6084 " bytes], buffer is '", buffer, "' [", buffer.size(), " bytes]");
6085 ADA_ASSERT_TRUE(validate());
6086 ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
6087
6088 // This next line is required for when parsing a URL like `foo://`
6089 add_authority_slashes_if_needed();
6090
6091 bool has_credentials = components.protocol_end + 2 < components.host_start;
6092 uint32_t new_difference =
6093 replace_and_resize(components.host_start, components.host_end, input);
6094
6095 if (has_credentials) {
6096 buffer.insert(components.host_start, "@");
6097 new_difference++;
6098 }
6099 components.host_end += new_difference;
6100 components.pathname_start += new_difference;
6101 if (components.search_start != url_components::omitted) {
6102 components.search_start += new_difference;
6103 }
6104 if (components.hash_start != url_components::omitted) {
6105 components.hash_start += new_difference;
6106 }
6107 ADA_ASSERT_TRUE(validate());
6108}
6109
6110[[nodiscard]] ada_really_inline uint32_t
6111url_aggregator::get_pathname_length() const noexcept {
6112 ada_log("url_aggregator::get_pathname_length");
6113 uint32_t ending_index = uint32_t(buffer.size());
6114 if (components.search_start != url_components::omitted) {
6115 ending_index = components.search_start;
6116 } else if (components.hash_start != url_components::omitted) {
6117 ending_index = components.hash_start;
6118 }
6119 return ending_index - components.pathname_start;
6120}
6121
6122[[nodiscard]] ada_really_inline bool url_aggregator::is_at_path()
6123 const noexcept {
6124 return buffer.size() == components.pathname_start;
6125}
6126
6127inline void url_aggregator::update_base_search(std::string_view input) {
6128 ada_log("url_aggregator::update_base_search ", input);
6129 ADA_ASSERT_TRUE(validate());
6130 ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
6131 if (input.empty()) {
6132 clear_search();
6133 return;
6134 }
6135
6136 if (input[0] == '?') {
6137 input.remove_prefix(1);
6138 }
6139
6140 if (components.hash_start == url_components::omitted) {
6141 if (components.search_start == url_components::omitted) {
6142 components.search_start = uint32_t(buffer.size());
6143 buffer += "?";
6144 } else {
6145 buffer.resize(components.search_start + 1);
6146 }
6147
6148 buffer.append(input);
6149 } else {
6150 if (components.search_start == url_components::omitted) {
6151 components.search_start = components.hash_start;
6152 } else {
6153 buffer.erase(components.search_start,
6154 components.hash_start - components.search_start);
6155 components.hash_start = components.search_start;
6156 }
6157
6158 buffer.insert(components.search_start, "?");
6159 buffer.insert(components.search_start + 1, input);
6160 components.hash_start += uint32_t(input.size() + 1); // Do not forget `?`
6161 }
6162
6163 ADA_ASSERT_TRUE(validate());
6164}
6165
6166inline void url_aggregator::update_base_search(
6167 std::string_view input, const uint8_t query_percent_encode_set[]) {
6168 ada_log("url_aggregator::update_base_search ", input,
6169 " with encoding parameter ", to_string(), "\n", to_diagram());
6170 ADA_ASSERT_TRUE(validate());
6171 ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
6172
6173 if (components.hash_start == url_components::omitted) {
6174 if (components.search_start == url_components::omitted) {
6175 components.search_start = uint32_t(buffer.size());
6176 buffer += "?";
6177 } else {
6178 buffer.resize(components.search_start + 1);
6179 }
6180
6181 bool encoding_required =
6182 unicode::percent_encode<true>(input, query_percent_encode_set, buffer);
6183 // When encoding_required is false, then buffer is left unchanged, and
6184 // percent encoding was not deemed required.
6185 if (!encoding_required) {
6186 buffer.append(input);
6187 }
6188 } else {
6189 if (components.search_start == url_components::omitted) {
6190 components.search_start = components.hash_start;
6191 } else {
6192 buffer.erase(components.search_start,
6193 components.hash_start - components.search_start);
6194 components.hash_start = components.search_start;
6195 }
6196
6197 buffer.insert(components.search_start, "?");
6198 size_t idx =
6199 ada::unicode::percent_encode_index(input, query_percent_encode_set);
6200 if (idx == input.size()) {
6201 buffer.insert(components.search_start + 1, input);
6202 components.hash_start += uint32_t(input.size() + 1); // Do not forget `?`
6203 } else {
6204 buffer.insert(components.search_start + 1, input, 0, idx);
6205 input.remove_prefix(idx);
6206 // We only create a temporary string if we need percent encoding and
6207 // we attempt to create as small a temporary string as we can.
6208 std::string encoded =
6209 ada::unicode::percent_encode(input, query_percent_encode_set);
6210 buffer.insert(components.search_start + idx + 1, encoded);
6211 components.hash_start +=
6212 uint32_t(encoded.size() + idx + 1); // Do not forget `?`
6213 }
6214 }
6215
6216 ADA_ASSERT_TRUE(validate());
6217}
6218
6219inline void url_aggregator::update_base_pathname(const std::string_view input) {
6220 ada_log("url_aggregator::update_base_pathname '", input, "' [", input.size(),
6221 " bytes] \n", to_diagram());
6222 ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
6223 ADA_ASSERT_TRUE(validate());
6224
6225 const bool begins_with_dashdash = checkers::begins_with(input, "//");
6226 if (!begins_with_dashdash && has_dash_dot()) {
6227 ada_log("url_aggregator::update_base_pathname has /.: \n", to_diagram());
6228 // We must delete the ./
6229 delete_dash_dot();
6230 }
6231
6232 if (begins_with_dashdash && !has_opaque_path && !has_authority() &&
6233 !has_dash_dot()) {
6234 // If url's host is null, url does not have an opaque path, url's path's
6235 // size is greater than 1, then append U+002F (/) followed by U+002E (.) to
6236 // output.
6237 buffer.insert(components.pathname_start, "/.");
6238 components.pathname_start += 2;
6239 }
6240
6241 uint32_t difference = replace_and_resize(
6242 components.pathname_start,
6243 components.pathname_start + get_pathname_length(), input);
6244 if (components.search_start != url_components::omitted) {
6245 components.search_start += difference;
6246 }
6247 if (components.hash_start != url_components::omitted) {
6248 components.hash_start += difference;
6249 }
6250 ada_log("url_aggregator::update_base_pathname end '", input, "' [",
6251 input.size(), " bytes] \n", to_diagram());
6252 ADA_ASSERT_TRUE(validate());
6253}
6254
6255inline void url_aggregator::append_base_pathname(const std::string_view input) {
6256 ada_log("url_aggregator::append_base_pathname ", input, " ", to_string(),
6257 "\n", to_diagram());
6258 ADA_ASSERT_TRUE(validate());
6259 ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
6260#if ADA_DEVELOPMENT_CHECKS
6261 // computing the expected password.
6262 std::string path_expected(get_pathname());
6263 path_expected.append(input);
6264#endif // ADA_DEVELOPMENT_CHECKS
6265 uint32_t ending_index = uint32_t(buffer.size());
6266 if (components.search_start != url_components::omitted) {
6267 ending_index = components.search_start;
6268 } else if (components.hash_start != url_components::omitted) {
6269 ending_index = components.hash_start;
6270 }
6271 buffer.insert(ending_index, input);
6272
6273 if (components.search_start != url_components::omitted) {
6274 components.search_start += uint32_t(input.size());
6275 }
6276 if (components.hash_start != url_components::omitted) {
6277 components.hash_start += uint32_t(input.size());
6278 }
6279#if ADA_DEVELOPMENT_CHECKS
6280 std::string path_after = std::string(get_pathname());
6282 path_expected, path_after,
6283 "append_base_pathname problem after inserting " + std::string(input));
6284#endif // ADA_DEVELOPMENT_CHECKS
6285 ADA_ASSERT_TRUE(validate());
6286}
6287
6288inline void url_aggregator::update_base_username(const std::string_view input) {
6289 ada_log("url_aggregator::update_base_username '", input, "' ", to_string(),
6290 "\n", to_diagram());
6291 ADA_ASSERT_TRUE(validate());
6292 ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
6293
6294 add_authority_slashes_if_needed();
6295
6296 bool has_password = has_non_empty_password();
6297 bool host_starts_with_at = buffer.size() > components.host_start &&
6298 buffer[components.host_start] == '@';
6299 uint32_t diff = replace_and_resize(components.protocol_end + 2,
6300 components.username_end, input);
6301
6302 components.username_end += diff;
6303 components.host_start += diff;
6304
6305 if (!input.empty() && !host_starts_with_at) {
6306 buffer.insert(components.host_start, "@");
6307 diff++;
6308 } else if (input.empty() && host_starts_with_at && !has_password) {
6309 // Input is empty, there is no password, and we need to remove "@" from
6310 // hostname
6311 buffer.erase(components.host_start, 1);
6312 diff--;
6313 }
6314
6315 components.host_end += diff;
6316 components.pathname_start += diff;
6317 if (components.search_start != url_components::omitted) {
6318 components.search_start += diff;
6319 }
6320 if (components.hash_start != url_components::omitted) {
6321 components.hash_start += diff;
6322 }
6323 ADA_ASSERT_TRUE(validate());
6324}
6325
6326inline void url_aggregator::append_base_username(const std::string_view input) {
6327 ada_log("url_aggregator::append_base_username ", input);
6328 ADA_ASSERT_TRUE(validate());
6329 ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
6330#if ADA_DEVELOPMENT_CHECKS
6331 // computing the expected password.
6332 std::string username_expected(get_username());
6333 username_expected.append(input);
6334#endif // ADA_DEVELOPMENT_CHECKS
6335 add_authority_slashes_if_needed();
6336
6337 // If input is empty, do nothing.
6338 if (input.empty()) {
6339 return;
6340 }
6341
6342 uint32_t difference = uint32_t(input.size());
6343 buffer.insert(components.username_end, input);
6344 components.username_end += difference;
6345 components.host_start += difference;
6346
6347 if (buffer[components.host_start] != '@' &&
6348 components.host_start != components.host_end) {
6349 buffer.insert(components.host_start, "@");
6350 difference++;
6351 }
6352
6353 components.host_end += difference;
6354 components.pathname_start += difference;
6355 if (components.search_start != url_components::omitted) {
6356 components.search_start += difference;
6357 }
6358 if (components.hash_start != url_components::omitted) {
6359 components.hash_start += difference;
6360 }
6361#if ADA_DEVELOPMENT_CHECKS
6362 std::string username_after(get_username());
6364 username_expected, username_after,
6365 "append_base_username problem after inserting " + std::string(input));
6366#endif // ADA_DEVELOPMENT_CHECKS
6367 ADA_ASSERT_TRUE(validate());
6368}
6369
6370inline void url_aggregator::clear_password() {
6371 ada_log("url_aggregator::clear_password ", to_string(), "\n", to_diagram());
6372 ADA_ASSERT_TRUE(validate());
6373 if (!has_password()) {
6374 return;
6375 }
6376
6377 uint32_t diff = components.host_start - components.username_end;
6378 buffer.erase(components.username_end, diff);
6379 components.host_start -= diff;
6380 components.host_end -= diff;
6381 components.pathname_start -= diff;
6382 if (components.search_start != url_components::omitted) {
6383 components.search_start -= diff;
6384 }
6385 if (components.hash_start != url_components::omitted) {
6386 components.hash_start -= diff;
6387 }
6388}
6389
6390inline void url_aggregator::update_base_password(const std::string_view input) {
6391 ada_log("url_aggregator::update_base_password ", input);
6392 ADA_ASSERT_TRUE(validate());
6393 ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
6394
6395 add_authority_slashes_if_needed();
6396
6397 // TODO: Optimization opportunity. Merge the following removal functions.
6398 if (input.empty()) {
6399 clear_password();
6400
6401 // Remove username too, if it is empty.
6402 if (!has_non_empty_username()) {
6403 update_base_username("");
6404 }
6405
6406 return;
6407 }
6408
6409 bool password_exists = has_password();
6410 uint32_t difference = uint32_t(input.size());
6411
6412 if (password_exists) {
6413 uint32_t current_length =
6414 components.host_start - components.username_end - 1;
6415 buffer.erase(components.username_end + 1, current_length);
6416 difference -= current_length;
6417 } else {
6418 buffer.insert(components.username_end, ":");
6419 difference++;
6420 }
6421
6422 buffer.insert(components.username_end + 1, input);
6423 components.host_start += difference;
6424
6425 // The following line is required to add "@" to hostname. When updating
6426 // password if hostname does not start with "@", it is "update_base_password"s
6427 // responsibility to set it.
6428 if (buffer[components.host_start] != '@') {
6429 buffer.insert(components.host_start, "@");
6430 difference++;
6431 }
6432
6433 components.host_end += difference;
6434 components.pathname_start += difference;
6435 if (components.search_start != url_components::omitted) {
6436 components.search_start += difference;
6437 }
6438 if (components.hash_start != url_components::omitted) {
6439 components.hash_start += difference;
6440 }
6441 ADA_ASSERT_TRUE(validate());
6442}
6443
6444inline void url_aggregator::append_base_password(const std::string_view input) {
6445 ada_log("url_aggregator::append_base_password ", input, " ", to_string(),
6446 "\n", to_diagram());
6447 ADA_ASSERT_TRUE(validate());
6448 ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
6449#if ADA_DEVELOPMENT_CHECKS
6450 // computing the expected password.
6451 std::string password_expected = std::string(get_password());
6452 password_expected.append(input);
6453#endif // ADA_DEVELOPMENT_CHECKS
6454 add_authority_slashes_if_needed();
6455
6456 // If input is empty, do nothing.
6457 if (input.empty()) {
6458 return;
6459 }
6460
6461 uint32_t difference = uint32_t(input.size());
6462 if (has_password()) {
6463 buffer.insert(components.host_start, input);
6464 } else {
6465 difference++; // Increment for ":"
6466 buffer.insert(components.username_end, ":");
6467 buffer.insert(components.username_end + 1, input);
6468 }
6469 components.host_start += difference;
6470
6471 // The following line is required to add "@" to hostname. When updating
6472 // password if hostname does not start with "@", it is "append_base_password"s
6473 // responsibility to set it.
6474 if (buffer[components.host_start] != '@') {
6475 buffer.insert(components.host_start, "@");
6476 difference++;
6477 }
6478
6479 components.host_end += difference;
6480 components.pathname_start += difference;
6481 if (components.search_start != url_components::omitted) {
6482 components.search_start += difference;
6483 }
6484 if (components.hash_start != url_components::omitted) {
6485 components.hash_start += difference;
6486 }
6487#if ADA_DEVELOPMENT_CHECKS
6488 std::string password_after(get_password());
6490 password_expected, password_after,
6491 "append_base_password problem after inserting " + std::string(input));
6492#endif // ADA_DEVELOPMENT_CHECKS
6493 ADA_ASSERT_TRUE(validate());
6494}
6495
6496inline void url_aggregator::update_base_port(uint32_t input) {
6497 ada_log("url_aggregator::update_base_port");
6498 ADA_ASSERT_TRUE(validate());
6499 if (input == url_components::omitted) {
6500 clear_port();
6501 return;
6502 }
6503 // calling std::to_string(input.value()) is unfortunate given that the port
6504 // value is probably already available as a string.
6505 std::string value = helpers::concat(":", std::to_string(input));
6506 uint32_t difference = uint32_t(value.size());
6507
6508 if (components.port != url_components::omitted) {
6509 difference -= components.pathname_start - components.host_end;
6510 buffer.erase(components.host_end,
6511 components.pathname_start - components.host_end);
6512 }
6513
6514 buffer.insert(components.host_end, value);
6515 components.pathname_start += difference;
6516 if (components.search_start != url_components::omitted) {
6517 components.search_start += difference;
6518 }
6519 if (components.hash_start != url_components::omitted) {
6520 components.hash_start += difference;
6521 }
6522 components.port = input;
6523 ADA_ASSERT_TRUE(validate());
6524}
6525
6526inline void url_aggregator::clear_port() {
6527 ada_log("url_aggregator::clear_port");
6528 ADA_ASSERT_TRUE(validate());
6529 if (components.port == url_components::omitted) {
6530 return;
6531 }
6532 uint32_t length = components.pathname_start - components.host_end;
6533 buffer.erase(components.host_end, length);
6534 components.pathname_start -= length;
6535 if (components.search_start != url_components::omitted) {
6536 components.search_start -= length;
6537 }
6538 if (components.hash_start != url_components::omitted) {
6539 components.hash_start -= length;
6540 }
6541 components.port = url_components::omitted;
6542 ADA_ASSERT_TRUE(validate());
6543}
6544
6545[[nodiscard]] inline uint32_t url_aggregator::retrieve_base_port() const {
6546 ada_log("url_aggregator::retrieve_base_port");
6547 return components.port;
6548}
6549
6550inline void url_aggregator::clear_search() {
6551 ada_log("url_aggregator::clear_search");
6552 ADA_ASSERT_TRUE(validate());
6553 if (components.search_start == url_components::omitted) {
6554 return;
6555 }
6556
6557 if (components.hash_start == url_components::omitted) {
6558 buffer.resize(components.search_start);
6559 } else {
6560 buffer.erase(components.search_start,
6561 components.hash_start - components.search_start);
6562 components.hash_start = components.search_start;
6563 }
6564
6565 components.search_start = url_components::omitted;
6566
6567#if ADA_DEVELOPMENT_CHECKS
6568 ADA_ASSERT_EQUAL(get_search(), "",
6569 "search should have been cleared on buffer=" + buffer +
6570 " with " + components.to_string() + "\n" + to_diagram());
6571#endif
6572 ADA_ASSERT_TRUE(validate());
6573}
6574
6575inline void url_aggregator::clear_hash() {
6576 ada_log("url_aggregator::clear_hash");
6577 ADA_ASSERT_TRUE(validate());
6578 if (components.hash_start == url_components::omitted) {
6579 return;
6580 }
6581 buffer.resize(components.hash_start);
6582 components.hash_start = url_components::omitted;
6583
6584#if ADA_DEVELOPMENT_CHECKS
6585 ADA_ASSERT_EQUAL(get_hash(), "",
6586 "hash should have been cleared on buffer=" + buffer +
6587 " with " + components.to_string() + "\n" + to_diagram());
6588#endif
6589 ADA_ASSERT_TRUE(validate());
6590}
6591
6592inline void url_aggregator::clear_pathname() {
6593 ada_log("url_aggregator::clear_pathname");
6594 ADA_ASSERT_TRUE(validate());
6595 uint32_t ending_index = uint32_t(buffer.size());
6596 if (components.search_start != url_components::omitted) {
6597 ending_index = components.search_start;
6598 } else if (components.hash_start != url_components::omitted) {
6599 ending_index = components.hash_start;
6600 }
6601 uint32_t pathname_length = ending_index - components.pathname_start;
6602 buffer.erase(components.pathname_start, pathname_length);
6603 uint32_t difference = pathname_length;
6604 if (components.pathname_start == components.host_end + 2 &&
6605 buffer[components.host_end] == '/' &&
6606 buffer[components.host_end + 1] == '.') {
6607 components.pathname_start -= 2;
6608 buffer.erase(components.host_end, 2);
6609 difference += 2;
6610 }
6611 if (components.search_start != url_components::omitted) {
6612 components.search_start -= difference;
6613 }
6614 if (components.hash_start != url_components::omitted) {
6615 components.hash_start -= difference;
6616 }
6617 ada_log("url_aggregator::clear_pathname completed, running checks...");
6618#if ADA_DEVELOPMENT_CHECKS
6619 ADA_ASSERT_EQUAL(get_pathname(), "",
6620 "pathname should have been cleared on buffer=" + buffer +
6621 " with " + components.to_string() + "\n" + to_diagram());
6622#endif
6623 ADA_ASSERT_TRUE(validate());
6624 ada_log("url_aggregator::clear_pathname completed, running checks... ok");
6625}
6626
6627inline void url_aggregator::clear_hostname() {
6628 ada_log("url_aggregator::clear_hostname");
6629 ADA_ASSERT_TRUE(validate());
6630 if (!has_authority()) {
6631 return;
6632 }
6633 ADA_ASSERT_TRUE(has_authority());
6634
6635 uint32_t hostname_length = components.host_end - components.host_start;
6636 uint32_t start = components.host_start;
6637
6638 // If hostname starts with "@", we should not remove that character.
6639 if (hostname_length > 0 && buffer[start] == '@') {
6640 start++;
6641 hostname_length--;
6642 }
6643 buffer.erase(start, hostname_length);
6644 components.host_end = start;
6645 components.pathname_start -= hostname_length;
6646 if (components.search_start != url_components::omitted) {
6647 components.search_start -= hostname_length;
6648 }
6649 if (components.hash_start != url_components::omitted) {
6650 components.hash_start -= hostname_length;
6651 }
6652#if ADA_DEVELOPMENT_CHECKS
6653 ADA_ASSERT_EQUAL(get_hostname(), "",
6654 "hostname should have been cleared on buffer=" + buffer +
6655 " with " + components.to_string() + "\n" + to_diagram());
6656#endif
6657 ADA_ASSERT_TRUE(has_authority());
6658 ADA_ASSERT_EQUAL(has_empty_hostname(), true,
6659 "hostname should have been cleared on buffer=" + buffer +
6660 " with " + components.to_string() + "\n" + to_diagram());
6661 ADA_ASSERT_TRUE(validate());
6662}
6663
6664[[nodiscard]] inline bool url_aggregator::has_hash() const noexcept {
6665 ada_log("url_aggregator::has_hash");
6666 return components.hash_start != url_components::omitted;
6667}
6668
6669[[nodiscard]] inline bool url_aggregator::has_search() const noexcept {
6670 ada_log("url_aggregator::has_search");
6671 return components.search_start != url_components::omitted;
6672}
6673
6674ada_really_inline bool url_aggregator::has_credentials() const noexcept {
6675 ada_log("url_aggregator::has_credentials");
6676 return has_non_empty_username() || has_non_empty_password();
6677}
6678
6679inline bool url_aggregator::cannot_have_credentials_or_port() const {
6680 ada_log("url_aggregator::cannot_have_credentials_or_port");
6681 return type == ada::scheme::type::FILE ||
6682 components.host_start == components.host_end;
6683}
6684
6685[[nodiscard]] ada_really_inline const ada::url_components &
6686url_aggregator::get_components() const noexcept {
6687 return components;
6688}
6689
6690[[nodiscard]] inline bool ada::url_aggregator::has_authority() const noexcept {
6691 ada_log("url_aggregator::has_authority");
6692 // Performance: instead of doing this potentially expensive check, we could
6693 // have a boolean in the struct.
6694 return components.protocol_end + 2 <= components.host_start &&
6695 helpers::substring(buffer, components.protocol_end,
6696 components.protocol_end + 2) == "//";
6697}
6698
6699inline void ada::url_aggregator::add_authority_slashes_if_needed() noexcept {
6700 ada_log("url_aggregator::add_authority_slashes_if_needed");
6701 ADA_ASSERT_TRUE(validate());
6702 // Protocol setter will insert `http:` to the URL. It is up to hostname setter
6703 // to insert
6704 // `//` initially to the buffer, since it depends on the hostname existence.
6705 if (has_authority()) {
6706 return;
6707 }
6708 // Performance: the common case is components.protocol_end == buffer.size()
6709 // Optimization opportunity: in many cases, the "//" is part of the input and
6710 // the insert could be fused with another insert.
6711 buffer.insert(components.protocol_end, "//");
6712 components.username_end += 2;
6713 components.host_start += 2;
6714 components.host_end += 2;
6715 components.pathname_start += 2;
6716 if (components.search_start != url_components::omitted) {
6717 components.search_start += 2;
6718 }
6719 if (components.hash_start != url_components::omitted) {
6720 components.hash_start += 2;
6721 }
6722 ADA_ASSERT_TRUE(validate());
6723}
6724
6725inline void ada::url_aggregator::reserve(uint32_t capacity) {
6726 buffer.reserve(capacity);
6727}
6728
6729inline bool url_aggregator::has_non_empty_username() const noexcept {
6730 ada_log("url_aggregator::has_non_empty_username");
6731 return components.protocol_end + 2 < components.username_end;
6732}
6733
6734inline bool url_aggregator::has_non_empty_password() const noexcept {
6735 ada_log("url_aggregator::has_non_empty_password");
6736 return components.host_start - components.username_end > 0;
6737}
6738
6739inline bool url_aggregator::has_password() const noexcept {
6740 ada_log("url_aggregator::has_password");
6741 // This function does not care about the length of the password
6742 return components.host_start > components.username_end &&
6743 buffer[components.username_end] == ':';
6744}
6745
6746inline bool url_aggregator::has_empty_hostname() const noexcept {
6747 if (!has_hostname()) {
6748 return false;
6749 }
6750 if (components.host_start == components.host_end) {
6751 return true;
6752 }
6753 if (components.host_end > components.host_start + 1) {
6754 return false;
6755 }
6756 return components.username_end != components.host_start;
6757}
6758
6759inline bool url_aggregator::has_hostname() const noexcept {
6760 return has_authority();
6761}
6762
6763inline bool url_aggregator::has_port() const noexcept {
6764 ada_log("url_aggregator::has_port");
6765 // A URL cannot have a username/password/port if its host is null or the empty
6766 // string, or its scheme is "file".
6767 return has_hostname() && components.pathname_start != components.host_end;
6768}
6769
6770[[nodiscard]] inline bool url_aggregator::has_dash_dot() const noexcept {
6771 // If url's host is null, url does not have an opaque path, url's path's size
6772 // is greater than 1, and url's path[0] is the empty string, then append
6773 // U+002F (/) followed by U+002E (.) to output.
6774 ada_log("url_aggregator::has_dash_dot");
6775#if ADA_DEVELOPMENT_CHECKS
6776 // If pathname_start and host_end are exactly two characters apart, then we
6777 // either have a one-digit port such as http://test.com:5?param=1 or else we
6778 // have a /.: sequence such as "non-spec:/.//". We test that this is the case.
6779 if (components.pathname_start == components.host_end + 2) {
6780 ADA_ASSERT_TRUE((buffer[components.host_end] == '/' &&
6781 buffer[components.host_end + 1] == '.') ||
6782 (buffer[components.host_end] == ':' &&
6783 checkers::is_digit(buffer[components.host_end + 1])));
6784 }
6785 if (components.pathname_start == components.host_end + 2 &&
6786 buffer[components.host_end] == '/' &&
6787 buffer[components.host_end + 1] == '.') {
6788 ADA_ASSERT_TRUE(components.pathname_start + 1 < buffer.size());
6789 ADA_ASSERT_TRUE(buffer[components.pathname_start] == '/');
6790 ADA_ASSERT_TRUE(buffer[components.pathname_start + 1] == '/');
6791 }
6792#endif
6793 // Performance: it should be uncommon for components.pathname_start ==
6794 // components.host_end + 2 to be true. So we put this check first in the
6795 // sequence. Most times, we do not have an opaque path. Checking for '/.' is
6796 // more expensive, but should be uncommon.
6797 return components.pathname_start == components.host_end + 2 &&
6798 !has_opaque_path && buffer[components.host_end] == '/' &&
6799 buffer[components.host_end + 1] == '.';
6800}
6801
6802[[nodiscard]] inline std::string_view url_aggregator::get_href() const noexcept
6804 ada_log("url_aggregator::get_href");
6805 return buffer;
6806}
6807
6808ada_really_inline size_t url_aggregator::parse_port(
6809 std::string_view view, bool check_trailing_content) noexcept {
6810 ada_log("url_aggregator::parse_port('", view, "') ", view.size());
6811 if (!view.empty() && view[0] == '-') {
6812 ada_log("parse_port: view[0] == '0' && view.size() > 1");
6813 is_valid = false;
6814 return 0;
6815 }
6816 uint16_t parsed_port{};
6817 auto r = std::from_chars(view.data(), view.data() + view.size(), parsed_port);
6818 if (r.ec == std::errc::result_out_of_range) {
6819 ada_log("parse_port: r.ec == std::errc::result_out_of_range");
6820 is_valid = false;
6821 return 0;
6822 }
6823 ada_log("parse_port: ", parsed_port);
6824 const size_t consumed = size_t(r.ptr - view.data());
6825 ada_log("parse_port: consumed ", consumed);
6826 if (check_trailing_content) {
6827 is_valid &=
6828 (consumed == view.size() || view[consumed] == '/' ||
6829 view[consumed] == '?' || (is_special() && view[consumed] == '\\'));
6830 }
6831 ada_log("parse_port: is_valid = ", is_valid);
6832 if (is_valid) {
6833 ada_log("parse_port", r.ec == std::errc());
6834 // scheme_default_port can return 0, and we should allow 0 as a base port.
6835 auto default_port = scheme_default_port();
6836 bool is_port_valid = (default_port == 0 && parsed_port == 0) ||
6837 (default_port != parsed_port);
6838 if (r.ec == std::errc() && is_port_valid) {
6839 update_base_port(parsed_port);
6840 } else {
6841 clear_port();
6842 }
6843 }
6844 return consumed;
6845}
6846
6847inline void url_aggregator::set_protocol_as_file() {
6848 ada_log("url_aggregator::set_protocol_as_file ");
6849 ADA_ASSERT_TRUE(validate());
6850 type = ada::scheme::type::FILE;
6851 // next line could overflow but unsigned arithmetic has well-defined
6852 // overflows.
6853 uint32_t new_difference = 5 - components.protocol_end;
6854
6855 if (buffer.empty()) {
6856 buffer.append("file:");
6857 } else {
6858 buffer.erase(0, components.protocol_end);
6859 buffer.insert(0, "file:");
6860 }
6861 components.protocol_end = 5;
6862
6863 // Update the rest of the components.
6864 components.username_end += new_difference;
6865 components.host_start += new_difference;
6866 components.host_end += new_difference;
6867 components.pathname_start += new_difference;
6868 if (components.search_start != url_components::omitted) {
6869 components.search_start += new_difference;
6870 }
6871 if (components.hash_start != url_components::omitted) {
6872 components.hash_start += new_difference;
6873 }
6874 ADA_ASSERT_TRUE(validate());
6875}
6876
6877inline std::ostream &operator<<(std::ostream &out,
6878 const ada::url_aggregator &u) {
6879 return out << u.to_string();
6880}
6881} // namespace ada
6882
6883#endif // ADA_URL_AGGREGATOR_INL_H
6884/* end file include/ada/url_aggregator-inl.h */
6885/* begin file include/ada/url_search_params.h */
6890#ifndef ADA_URL_SEARCH_PARAMS_H
6891#define ADA_URL_SEARCH_PARAMS_H
6892
6893#include <optional>
6894#include <string>
6895#include <string_view>
6896#include <vector>
6897
6898namespace ada {
6899
6901 KEYS,
6902 VALUES,
6903 ENTRIES,
6904};
6905
6906template <typename T, url_search_params_iter_type Type>
6907struct url_search_params_iter;
6908
6909typedef std::pair<std::string_view, std::string_view> key_value_view_pair;
6910
6911using url_search_params_keys_iter =
6912 url_search_params_iter<std::string_view, url_search_params_iter_type::KEYS>;
6913using url_search_params_values_iter =
6914 url_search_params_iter<std::string_view,
6915 url_search_params_iter_type::VALUES>;
6916using url_search_params_entries_iter =
6917 url_search_params_iter<key_value_view_pair,
6918 url_search_params_iter_type::ENTRIES>;
6919
6925
6930 url_search_params(const std::string_view input) { initialize(input); }
6931
6933 url_search_params(url_search_params &&u) noexcept = default;
6937
6938 [[nodiscard]] inline size_t size() const noexcept;
6939
6943 inline void append(std::string_view key, std::string_view value);
6944
6948 inline void remove(std::string_view key);
6949 inline void remove(std::string_view key, std::string_view value);
6950
6954 inline std::optional<std::string_view> get(std::string_view key);
6955
6959 inline std::vector<std::string> get_all(std::string_view key);
6960
6964 inline bool has(std::string_view key) noexcept;
6965 inline bool has(std::string_view key, std::string_view value) noexcept;
6966
6970 inline void set(std::string_view key, std::string_view value);
6971
6975 inline void sort();
6976
6980 inline std::string to_string() const;
6981
6990
6998
7007
7012 inline auto begin() const { return params.begin(); }
7013 inline auto end() const { return params.end(); }
7014 inline auto front() const { return params.front(); }
7015 inline auto back() const { return params.back(); }
7016 inline auto operator[](size_t index) const { return params[index]; }
7017
7024 void reset(std::string_view input);
7025
7026 private:
7027 typedef std::pair<std::string, std::string> key_value_pair;
7028 std::vector<key_value_pair> params{};
7029
7033 void initialize(std::string_view init);
7034
7035 template <typename T, url_search_params_iter_type Type>
7037}; // url_search_params
7038
7045template <typename T, url_search_params_iter_type Type>
7047 inline url_search_params_iter() : params(EMPTY) {}
7051 default;
7054
7058 inline std::optional<T> next();
7059
7060 inline bool has_next();
7061
7062 private:
7063 static url_search_params EMPTY;
7064 inline url_search_params_iter(url_search_params &params_) : params(params_) {}
7065
7066 url_search_params &params;
7067 size_t pos = 0;
7068
7069 friend struct url_search_params;
7070};
7071
7072} // namespace ada
7073#endif
7074/* end file include/ada/url_search_params.h */
7075/* begin file include/ada/url_search_params-inl.h */
7080#ifndef ADA_URL_SEARCH_PARAMS_INL_H
7081#define ADA_URL_SEARCH_PARAMS_INL_H
7082
7083
7084#include <algorithm>
7085#include <optional>
7086#include <string>
7087#include <string_view>
7088#include <vector>
7089
7090namespace ada {
7091
7092// A default, empty url_search_params for use with empty iterators.
7093template <typename T, ada::url_search_params_iter_type Type>
7094url_search_params url_search_params_iter<T, Type>::EMPTY;
7095
7096inline void url_search_params::reset(std::string_view input) {
7097 params.clear();
7098 initialize(input);
7099}
7100
7101inline void url_search_params::initialize(std::string_view input) {
7102 if (!input.empty() && input.front() == '?') {
7103 input.remove_prefix(1);
7104 }
7105
7106 auto process_key_value = [&](const std::string_view current) {
7107 auto equal = current.find('=');
7108
7109 if (equal == std::string_view::npos) {
7110 std::string name(current);
7111 std::replace(name.begin(), name.end(), '+', ' ');
7112 params.emplace_back(unicode::percent_decode(name, name.find('%')), "");
7113 } else {
7114 std::string name(current.substr(0, equal));
7115 std::string value(current.substr(equal + 1));
7116
7117 std::replace(name.begin(), name.end(), '+', ' ');
7118 std::replace(value.begin(), value.end(), '+', ' ');
7119
7120 params.emplace_back(unicode::percent_decode(name, name.find('%')),
7121 unicode::percent_decode(value, value.find('%')));
7122 }
7123 };
7124
7125 while (!input.empty()) {
7126 auto ampersand_index = input.find('&');
7127
7128 if (ampersand_index == std::string_view::npos) {
7129 if (!input.empty()) {
7130 process_key_value(input);
7131 }
7132 break;
7133 } else if (ampersand_index != 0) {
7134 process_key_value(input.substr(0, ampersand_index));
7135 }
7136
7137 input.remove_prefix(ampersand_index + 1);
7138 }
7139}
7140
7141inline void url_search_params::append(const std::string_view key,
7142 const std::string_view value) {
7143 params.emplace_back(key, value);
7144}
7145
7146inline size_t url_search_params::size() const noexcept { return params.size(); }
7147
7148inline std::optional<std::string_view> url_search_params::get(
7149 const std::string_view key) {
7150 auto entry = std::find_if(params.begin(), params.end(),
7151 [&key](auto &param) { return param.first == key; });
7152
7153 if (entry == params.end()) {
7154 return std::nullopt;
7155 }
7156
7157 return entry->second;
7158}
7159
7160inline std::vector<std::string> url_search_params::get_all(
7161 const std::string_view key) {
7162 std::vector<std::string> out{};
7163
7164 for (auto &param : params) {
7165 if (param.first == key) {
7166 out.emplace_back(param.second);
7167 }
7168 }
7169
7170 return out;
7171}
7172
7173inline bool url_search_params::has(const std::string_view key) noexcept {
7174 auto entry = std::find_if(params.begin(), params.end(),
7175 [&key](auto &param) { return param.first == key; });
7176 return entry != params.end();
7177}
7178
7179inline bool url_search_params::has(std::string_view key,
7180 std::string_view value) noexcept {
7181 auto entry =
7182 std::find_if(params.begin(), params.end(), [&key, &value](auto &param) {
7183 return param.first == key && param.second == value;
7184 });
7185 return entry != params.end();
7186}
7187
7188inline std::string url_search_params::to_string() const {
7190 std::string out{};
7191 for (size_t i = 0; i < params.size(); i++) {
7192 auto key = ada::unicode::percent_encode(params[i].first, character_set);
7193 auto value = ada::unicode::percent_encode(params[i].second, character_set);
7194
7195 // Performance optimization: Move this inside percent_encode.
7196 std::replace(key.begin(), key.end(), ' ', '+');
7197 std::replace(value.begin(), value.end(), ' ', '+');
7198
7199 if (i != 0) {
7200 out += "&";
7201 }
7202 out.append(key);
7203 out += "=";
7204 out.append(value);
7205 }
7206 return out;
7207}
7208
7209inline void url_search_params::set(const std::string_view key,
7210 const std::string_view value) {
7211 const auto find = [&key](auto &param) { return param.first == key; };
7212
7213 auto it = std::find_if(params.begin(), params.end(), find);
7214
7215 if (it == params.end()) {
7216 params.emplace_back(key, value);
7217 } else {
7218 it->second = value;
7219 params.erase(std::remove_if(std::next(it), params.end(), find),
7220 params.end());
7221 }
7222}
7223
7224inline void url_search_params::remove(const std::string_view key) {
7225 params.erase(
7226 std::remove_if(params.begin(), params.end(),
7227 [&key](auto &param) { return param.first == key; }),
7228 params.end());
7229}
7230
7231inline void url_search_params::remove(const std::string_view key,
7232 const std::string_view value) {
7233 params.erase(std::remove_if(params.begin(), params.end(),
7234 [&key, &value](auto &param) {
7235 return param.first == key &&
7236 param.second == value;
7237 }),
7238 params.end());
7239}
7240
7241inline void url_search_params::sort() {
7242 std::stable_sort(params.begin(), params.end(),
7243 [](const key_value_pair &lhs, const key_value_pair &rhs) {
7244 return lhs.first < rhs.first;
7245 });
7246}
7247
7249 return url_search_params_keys_iter(*this);
7250}
7251
7256 return url_search_params_values_iter(*this);
7257}
7258
7263 return url_search_params_entries_iter(*this);
7264}
7265
7266template <typename T, url_search_params_iter_type Type>
7268 return pos < params.params.size();
7269}
7270
7271template <>
7272inline std::optional<std::string_view> url_search_params_keys_iter::next() {
7273 if (!has_next()) {
7274 return std::nullopt;
7275 }
7276 return params.params[pos++].first;
7277}
7278
7279template <>
7280inline std::optional<std::string_view> url_search_params_values_iter::next() {
7281 if (!has_next()) {
7282 return std::nullopt;
7283 }
7284 return params.params[pos++].second;
7285}
7286
7287template <>
7288inline std::optional<key_value_view_pair>
7290 if (!has_next()) {
7291 return std::nullopt;
7292 }
7293 return params.params[pos++];
7294}
7295
7296} // namespace ada
7297
7298#endif // ADA_URL_SEARCH_PARAMS_INL_H
7299/* end file include/ada/url_search_params-inl.h */
7300
7301// Public API
7302/* begin file include/ada/ada_version.h */
7307#ifndef ADA_ADA_VERSION_H
7308#define ADA_ADA_VERSION_H
7309
7310#define ADA_VERSION "2.9.2"
7311
7312namespace ada {
7313
7314enum {
7318};
7319
7320} // namespace ada
7321
7322#endif // ADA_ADA_VERSION_H
7323/* end file include/ada/ada_version.h */
7324/* begin file include/ada/implementation.h */
7330#ifndef ADA_IMPLEMENTATION_H
7331#define ADA_IMPLEMENTATION_H
7332
7333#include <string>
7334#include <optional>
7335
7336
7337namespace ada {
7338enum class errors { generic_error };
7339
7340template <class result_type = ada::url_aggregator>
7342
7352template <class result_type = ada::url_aggregator>
7354 std::string_view input, const result_type* base_url = nullptr);
7355
7356extern template ada::result<url> parse<url>(std::string_view input,
7357 const url* base_url);
7359 std::string_view input, const url_aggregator* base_url);
7360
7367bool can_parse(std::string_view input,
7368 const std::string_view* base_input = nullptr);
7369
7375std::string href_from_file(std::string_view path);
7376} // namespace ada
7377
7378#endif // ADA_IMPLEMENTATION_H
7379/* end file include/ada/implementation.h */
7380
7381#endif // ADA_H
7382/* end file include/ada.h */
virtual const char * what() const noexcept override
Definition ada.h:3147
const E & error() const &
Definition ada.h:3151
const E && error() const &&
Definition ada.h:3153
constexpr expected(const unexpected< G > &e)
Definition ada.h:3495
expected & operator=(const expected &rhs)=default
constexpr T value_or(U &&v) const &
Definition ada.h:3973
TL_EXPECTED_11_CONSTEXPR decltype(expected_map_impl(std::declval< expected >(), std::declval< F && >())) transform(F &&f) &&
Definition ada.h:3335
constexpr decltype(map_error_impl(std::declval< const expected && >(), std::declval< F && >())) transform_error(F &&f) const &&
Definition ada.h:3444
TL_EXPECTED_11_CONSTEXPR T * operator->()
Definition ada.h:3893
TL_EXPECTED_11_CONSTEXPR expected(const expected< U, G > &rhs)
Definition ada.h:3547
TL_EXPECTED_11_CONSTEXPR decltype(map_error_impl(std::declval< expected && >(), std::declval< F && >())) transform_error(F &&f) &&
Definition ada.h:3430
unexpected< E > unexpected_type
Definition ada.h:3209
constexpr auto and_then(F &&f) const &&-> decltype(and_then_impl(std::declval< expected const && >(), std::forward< F >(f)))
Definition ada.h:3252
constexpr const E && error() const &&
Definition ada.h:3963
TL_EXPECTED_11_CONSTEXPR const U & value() const &
Definition ada.h:3928
constexpr decltype(expected_map_impl(std::declval< const expected && >(), std::declval< F && >())) transform(F &&f) const &&
Definition ada.h:3349
TL_EXPECTED_11_CONSTEXPR auto and_then(F &&f) &&-> decltype(and_then_impl(std::declval< expected && >(), std::forward< F >(f)))
Definition ada.h:3240
TL_EXPECTED_11_CONSTEXPR decltype(expected_map_impl(std::declval< expected >(), std::declval< F && >())) map(F &&f) &&
Definition ada.h:3287
void emplace(std::initializer_list< U > il, Args &&...args)
Definition ada.h:3743
constexpr expected(const expected &rhs)=default
TL_EXPECTED_11_CONSTEXPR U & operator*() &
Definition ada.h:3906
constexpr const E & error() const &
Definition ada.h:3955
constexpr bool has_value() const noexcept
Definition ada.h:3923
T value_type
Definition ada.h:3207
TL_EXPECTED_11_CONSTEXPR T value_or(U &&v) &&
Definition ada.h:3980
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:3873
TL_EXPECTED_11_CONSTEXPR decltype(map_error_impl(std::declval< expected & >(), std::declval< F && >())) map_error(F &&f) &
Definition ada.h:3377
constexpr expected()=default
TL_EXPECTED_11_CONSTEXPR decltype(expected_map_impl(std::declval< expected & >(), std::declval< F && >())) map(F &&f) &
Definition ada.h:3281
constexpr auto and_then(F &&f) const &-> decltype(and_then_impl(std::declval< expected const & >(), std::forward< F >(f)))
Definition ada.h:3245
TL_EXPECTED_11_CONSTEXPR expected(expected< U, G > &&rhs)
Definition ada.h:3576
constexpr expected(unexpected< G > &&e) noexcept(std::is_nothrow_constructible< E, G && >::value)
Definition ada.h:3512
TL_EXPECTED_MSVC2015_CONSTEXPR expected(U &&v)
Definition ada.h:3603
constexpr expected(unexpect_t, Args &&...args)
Definition ada.h:3529
expected TL_EXPECTED_11_CONSTEXPR or_else(F &&f) &
Definition ada.h:3450
constexpr const T * operator->() const
Definition ada.h:3889
constexpr decltype(expected_map_impl(std::declval< const expected & >(), std::declval< F && >())) transform(F &&f) const &
Definition ada.h:3341
constexpr expected(unexpected< G > const &e)
Definition ada.h:3504
expected & operator=(const unexpected< G > &rhs)
Definition ada.h:3676
void emplace(Args &&...args)
Definition ada.h:3705
E error_type
Definition ada.h:3208
expected & operator=(U &&v)
Definition ada.h:3625
constexpr expected(unexpect_t, std::initializer_list< U > il, Args &&...args)
Definition ada.h:3536
constexpr decltype(map_error_impl(std::declval< const expected & >(), std::declval< F && >())) map_error(F &&f) const &
Definition ada.h:3389
expected constexpr or_else(F &&f) const &
Definition ada.h:3460
TL_EXPECTED_11_CONSTEXPR E && error() &&
Definition ada.h:3967
constexpr expected(in_place_t, std::initializer_list< U > il, Args &&...args)
Definition ada.h:3486
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:3329
constexpr decltype(map_error_impl(std::declval< const expected && >(), std::declval< F && >())) map_error(F &&f) const &&
Definition ada.h:3397
constexpr const U & operator*() const &
Definition ada.h:3900
TL_EXPECTED_11_CONSTEXPR const U && value() const &&
Definition ada.h:3942
constexpr expected(in_place_t, Args &&...args)
Definition ada.h:3479
TL_EXPECTED_11_CONSTEXPR decltype(map_error_impl(std::declval< expected & >(), std::declval< F && >())) transform_error(F &&f) &
Definition ada.h:3424
TL_EXPECTED_11_CONSTEXPR auto and_then(F &&f) &-> decltype(and_then_impl(std::declval< expected & >(), std::forward< F >(f)))
Definition ada.h:3235
expected TL_EXPECTED_11_CONSTEXPR or_else(F &&f) &&
Definition ada.h:3455
expected & operator=(expected &&rhs)=default
expected constexpr or_else(F &&f) const &&
Definition ada.h:3466
expected & operator=(unexpected< G > &&rhs) noexcept
Definition ada.h:3691
TL_EXPECTED_11_CONSTEXPR U && operator*() &&
Definition ada.h:3918
constexpr const U && operator*() const &&
Definition ada.h:3912
constexpr decltype(map_error_impl(std::declval< const expected & >(), std::declval< F && >())) transform_error(F &&f) const &
Definition ada.h:3436
TL_EXPECTED_11_CONSTEXPR E & error() &
Definition ada.h:3959
TL_EXPECTED_11_CONSTEXPR decltype(map_error_impl(std::declval< expected && >(), std::declval< F && >())) map_error(F &&f) &&
Definition ada.h:3383
TL_EXPECTED_11_CONSTEXPR U & value() &
Definition ada.h:3935
constexpr decltype(expected_map_impl(std::declval< const expected & >(), std::declval< F && >())) map(F &&f) const &
Definition ada.h:3293
TL_EXPECTED_11_CONSTEXPR U && value() &&
Definition ada.h:3949
constexpr decltype(expected_map_impl(std::declval< const expected && >(), std::declval< F && >())) map(F &&f) const &&
Definition ada.h:3301
TL_EXPECTED_11_CONSTEXPR E & value() &
Definition ada.h:2043
constexpr unexpected(const E &e)
Definition ada.h:2027
constexpr unexpected(Args &&...args)
Definition ada.h:2033
constexpr const E & value() const &
Definition ada.h:2042
TL_EXPECTED_11_CONSTEXPR E && value() &&
Definition ada.h:2044
constexpr unexpected(std::initializer_list< U > l, Args &&...args)
Definition ada.h:2039
constexpr const E && value() const &&
Definition ada.h:2045
constexpr unexpected(E &&e)
Definition ada.h:2029
unexpected()=delete
#define ADA_ASSERT_TRUE(COND)
#define ada_constexpr
#define ada_lifetime_bound
#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
@ ADA_VERSION_MINOR
Definition ada_version.h:14
@ ADA_VERSION_REVISION
Definition ada_version.h:15
@ ADA_VERSION_MAJOR
Definition ada_version.h:13
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()
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:2335
typename std::remove_reference< T >::type remove_reference_t
Definition ada.h:2112
is_void_or< T, std::is_move_assignable< T > > is_move_assignable_or_void
Definition ada.h:2329
typename std::enable_if< E, T >::type enable_if_t
Definition ada.h:2116
is_void_or< T, std::is_copy_assignable< T > > is_copy_assignable_or_void
Definition ada.h:2326
typename std::decay< T >::type decay_t
Definition ada.h:2114
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:2175
typename detail::decay_t< Exp >::error_type err_t
Definition ada.h:3992
conditional_t< std::is_void< T >::value, std::true_type, U > is_void_or
Definition ada.h:2315
typename std::remove_const< T >::type remove_const_t
Definition ada.h:2110
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:2295
constexpr auto map_error_impl(Exp &&exp, F &&f) -> expected< exp_t< Exp >, detail::decay_t< Ret > >
Definition ada.h:4214
auto and_then_impl(Exp &&exp, F &&f) -> Ret
Definition ada.h:4025
typename std::conditional< B, T, F >::type conditional_t
Definition ada.h:2118
is_void_or< T, std::is_move_constructible< T > > is_move_constructible_or_void
Definition ada.h:2322
TL_EXPECTED_11_CONSTEXPR void throw_exception(E &&e)
Definition ada.h:2093
typename invoke_result< F, Us... >::type invoke_result_t
Definition ada.h:2206
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:2302
auto or_else_impl(Exp &&exp, F &&f) -> Ret
Definition ada.h:4297
constexpr auto expected_map_impl(Exp &&exp, F &&f) -> ret_t< Exp, detail::decay_t< Ret > >
Definition ada.h:4102
typename detail::decay_t< Exp >::value_type exp_t
Definition ada.h:3990
is_void_or< T, std::is_copy_constructible< T > > is_copy_constructible_or_void
Definition ada.h:2318
Definition ada.h:2007
constexpr bool operator>=(const unexpected< E > &lhs, const unexpected< E > &rhs)
Definition ada.h:2077
constexpr bool operator>(const unexpected< E > &lhs, const unexpected< E > &rhs)
Definition ada.h:2073
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:2057
constexpr bool operator<=(const unexpected< E > &lhs, const unexpected< E > &rhs)
Definition ada.h:2069
static constexpr in_place_t in_place
Definition ada.h:2018
static constexpr unexpect_t unexpect
Definition ada.h:2089
constexpr bool operator<(const unexpected< E > &lhs, const unexpected< E > &rhs)
Definition ada.h:2065
unexpected< typename std::decay< E >::type > make_unexpected(E &&e)
Definition ada.h:2082
#define TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(T)
Definition ada.h:1986
#define TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T)
Definition ada.h:1982
#define TL_EXPECTED_MSVC2015_CONSTEXPR
Definition ada.h:1914
#define TL_ASSERT(x)
Definition ada.h:1938
#define TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(T)
Definition ada.h:1984
#define ada_log(...)
Definition ada.h:1166
#define TL_EXPECTED_11_CONSTEXPR
Definition ada.h:2004
Lightweight URL struct.
Definition ada.h:4825
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:13950
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:1539
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:1369
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:7013
std::vector< std::string > get_all(std::string_view key)
auto front() const
Definition ada.h:7014
auto back() const
Definition ada.h:7015
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:7016
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:6930
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:5276
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:2937
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:2863
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:2981
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:2901
constexpr const unexpected< E > && geterr() const &&
Definition ada.h:2837
constexpr const unexpected< E > & geterr() const &
Definition ada.h:2832
void construct_error(Args &&...args) noexcept
Definition ada.h:2805
TL_EXPECTED_11_CONSTEXPR void destroy_val()
Definition ada.h:2842
TL_EXPECTED_11_CONSTEXPR unexpected< E > & geterr() &
Definition ada.h:2829
TL_EXPECTED_11_CONSTEXPR unexpected< E > && geterr() &&
Definition ada.h:2833
constexpr const T && get() const &&
Definition ada.h:2767
TL_EXPECTED_11_CONSTEXPR unexpected< E > && geterr() &&
Definition ada.h:2774
constexpr const unexpected< E > & geterr() const &
Definition ada.h:2773
constexpr const T & get() const &
Definition ada.h:2764
TL_EXPECTED_11_CONSTEXPR void destroy_val()
Definition ada.h:2783
constexpr const unexpected< E > && geterr() const &&
Definition ada.h:2778
void construct(Args &&...args) noexcept
Definition ada.h:2603
void assign(const expected_operations_base &rhs) noexcept
Definition ada.h:2724
TL_EXPECTED_11_CONSTEXPR unexpected< E > & geterr() &
Definition ada.h:2770
void construct_with(Rhs &&rhs) noexcept
Definition ada.h:2609
void construct_error(Args &&...args) noexcept
Definition ada.h:2615
TL_EXPECTED_11_CONSTEXPR T && get() &&
Definition ada.h:2765
void assign(expected_operations_base &&rhs) noexcept
Definition ada.h:2733
TL_EXPECTED_11_CONSTEXPR T & get() &
Definition ada.h:2763
constexpr expected_storage_base(in_place_t, std::initializer_list< U > il, Args &&...args)
Definition ada.h:2494
constexpr expected_storage_base(in_place_t, Args &&...args)
Definition ada.h:2488
constexpr expected_storage_base(unexpect_t, Args &&...args)
Definition ada.h:2500
constexpr expected_storage_base(unexpect_t, std::initializer_list< U > il, Args &&...args)
Definition ada.h:2506
TL_EXPECTED_MSVC2015_CONSTEXPR expected_storage_base(no_init_t)
Definition ada.h:2436
constexpr expected_storage_base(unexpect_t, std::initializer_list< U > il, Args &&...args)
Definition ada.h:2460
constexpr expected_storage_base(unexpect_t, Args &&...args)
Definition ada.h:2454
constexpr expected_storage_base(in_place_t, Args &&...args)
Definition ada.h:2442
constexpr expected_storage_base(in_place_t, std::initializer_list< U > il, Args &&...args)
Definition ada.h:2448
constexpr expected_storage_base(in_place_t, Args &&...args)
Definition ada.h:2400
constexpr expected_storage_base(in_place_t, std::initializer_list< U > il, Args &&...args)
Definition ada.h:2406
constexpr expected_storage_base(unexpect_t, Args &&...args)
Definition ada.h:2412
constexpr expected_storage_base(unexpect_t, std::initializer_list< U > il, Args &&...args)
Definition ada.h:2418
constexpr expected_storage_base(unexpect_t, std::initializer_list< U > il, Args &&...args)
Definition ada.h:2578
constexpr expected_storage_base(unexpect_t, Args &&...args)
Definition ada.h:2572
constexpr expected_storage_base(unexpect_t, Args &&...args)
Definition ada.h:2541
constexpr expected_storage_base(unexpect_t, std::initializer_list< U > il, Args &&...args)
Definition ada.h:2547
constexpr expected_storage_base(unexpect_t, Args &&...args)
Definition ada.h:2364
constexpr expected_storage_base(no_init_t)
Definition ada.h:2347
constexpr expected_storage_base()
Definition ada.h:2346
constexpr expected_storage_base(in_place_t, std::initializer_list< U > il, Args &&...args)
Definition ada.h:2358
constexpr expected_storage_base(in_place_t, Args &&...args)
Definition ada.h:2352
unexpected< E > m_unexpect
Definition ada.h:2384
constexpr expected_storage_base(unexpect_t, std::initializer_list< U > il, Args &&...args)
Definition ada.h:2370
in_place_t()=default
unexpect_t()=default