• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* auto-generated on 2024-01-29 13:13:24 -0500. Do not edit! */
2 /* begin file include/ada.h */
3 /**
4  * @file ada.h
5  * @brief Includes all definitions for Ada.
6  */
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 
23 namespace ada::idna {
24 
25 size_t utf8_to_utf32(const char* buf, size_t len, char32_t* utf32_output);
26 
27 size_t utf8_length_from_utf32(const char32_t* buf, size_t len);
28 
29 size_t utf32_length_from_utf8(const char* buf, size_t len);
30 
31 size_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 
44 namespace ada::idna {
45 
46 // If the input is ascii, then the mapping is just -> lower case.
47 void ascii_map(char* input, size_t length);
48 // check whether an ascii string needs mapping
49 bool ascii_has_upper_case(char* input, size_t length);
50 // Map the characters according to IDNA, returning the empty string on error.
51 std::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 
64 namespace ada::idna {
65 
66 // Normalize the characters according to IDNA (Unicode Normalization Form C).
67 void 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 
79 namespace ada::idna {
80 
81 bool punycode_to_utf32(std::string_view input, std::u32string& out);
82 bool verify_punycode(std::string_view input);
83 bool 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 
96 namespace ada::idna {
97 
98 /**
99  * @see https://www.unicode.org/reports/tr46/#Validity_Criteria
100  */
101 bool 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 
114 namespace 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.
125 std::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
130 bool contains_forbidden_domain_code_point(std::string_view ascii_string);
131 
132 bool begins_with(std::u32string_view view, std::u32string_view prefix);
133 bool begins_with(std::string_view view, std::string_view prefix);
134 
135 bool constexpr is_ascii(std::u32string_view view);
136 bool 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 
149 namespace ada::idna {
150 
151 std::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 */
162 /**
163  * @file character_sets-inl.h
164  * @brief Definitions of the character sets used by unicode functions.
165  * @author Node.js
166  * @see https://github.com/nodejs/node/blob/main/src/node_url_tables.cc
167  */
168 #ifndef ADA_CHARACTER_SETS_INL_H
169 #define ADA_CHARACTER_SETS_INL_H
170 
171 /* begin file include/ada/character_sets.h */
172 /**
173  * @file character_sets.h
174  * @brief Declaration of the character sets used by unicode functions.
175  * @author Node.js
176  * @see https://github.com/nodejs/node/blob/main/src/node_url_tables.cc
177  */
178 #ifndef ADA_CHARACTER_SETS_H
179 #define ADA_CHARACTER_SETS_H
180 
181 /* begin file include/ada/common_defs.h */
182 /**
183  * @file common_defs.h
184  * @brief Common definitions for cross-platform compiler support.
185  */
186 #ifndef ADA_COMMON_DEFS_H
187 #define ADA_COMMON_DEFS_H
188 
189 #ifdef _MSC_VER
190 #define ADA_VISUAL_STUDIO 1
191 /**
192  * We want to differentiate carefully between
193  * clang under visual studio and regular visual
194  * studio.
195  */
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)
312 /**
313  * It does not matter here whether you are using
314  * the regular visual studio or clang under visual
315  * studio.
316  */
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 
326 /// If EXPR is an error, returns it.
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 
346 namespace ada {
unreachable()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)) __builtin_unreachable(); \
467   } while (0)
468 #endif
469 
470 #if defined(__SSE2__) || defined(__x86_64__) || defined(__x86_64) || \
471     (defined(_M_AMD64) || defined(_M_X64) ||                         \
472      (defined(_M_IX86_FP) && _M_IX86_FP == 2))
473 #define ADA_SSE2 1
474 #endif
475 
476 #if defined(__aarch64__) || defined(_M_ARM64)
477 #define ADA_NEON 1
478 #endif
479 
480 #endif  // ADA_COMMON_DEFS_H
481 /* end file include/ada/common_defs.h */
482 #include <cstdint>
483 
484 /**
485  * @namespace ada::character_sets
486  * @brief Includes the definitions for unicode character sets.
487  */
488 namespace ada::character_sets {
489 ada_really_inline bool bit_at(const uint8_t a[], uint8_t i);
490 }  // namespace ada::character_sets
491 
492 #endif  // ADA_CHARACTER_SETS_H
493 /* end file include/ada/character_sets.h */
494 
495 namespace ada::character_sets {
496 
497 constexpr char hex[1024] =
498     "%00\0%01\0%02\0%03\0%04\0%05\0%06\0%07\0"
499     "%08\0%09\0%0A\0%0B\0%0C\0%0D\0%0E\0%0F\0"
500     "%10\0%11\0%12\0%13\0%14\0%15\0%16\0%17\0"
501     "%18\0%19\0%1A\0%1B\0%1C\0%1D\0%1E\0%1F\0"
502     "%20\0%21\0%22\0%23\0%24\0%25\0%26\0%27\0"
503     "%28\0%29\0%2A\0%2B\0%2C\0%2D\0%2E\0%2F\0"
504     "%30\0%31\0%32\0%33\0%34\0%35\0%36\0%37\0"
505     "%38\0%39\0%3A\0%3B\0%3C\0%3D\0%3E\0%3F\0"
506     "%40\0%41\0%42\0%43\0%44\0%45\0%46\0%47\0"
507     "%48\0%49\0%4A\0%4B\0%4C\0%4D\0%4E\0%4F\0"
508     "%50\0%51\0%52\0%53\0%54\0%55\0%56\0%57\0"
509     "%58\0%59\0%5A\0%5B\0%5C\0%5D\0%5E\0%5F\0"
510     "%60\0%61\0%62\0%63\0%64\0%65\0%66\0%67\0"
511     "%68\0%69\0%6A\0%6B\0%6C\0%6D\0%6E\0%6F\0"
512     "%70\0%71\0%72\0%73\0%74\0%75\0%76\0%77\0"
513     "%78\0%79\0%7A\0%7B\0%7C\0%7D\0%7E\0%7F\0"
514     "%80\0%81\0%82\0%83\0%84\0%85\0%86\0%87\0"
515     "%88\0%89\0%8A\0%8B\0%8C\0%8D\0%8E\0%8F\0"
516     "%90\0%91\0%92\0%93\0%94\0%95\0%96\0%97\0"
517     "%98\0%99\0%9A\0%9B\0%9C\0%9D\0%9E\0%9F\0"
518     "%A0\0%A1\0%A2\0%A3\0%A4\0%A5\0%A6\0%A7\0"
519     "%A8\0%A9\0%AA\0%AB\0%AC\0%AD\0%AE\0%AF\0"
520     "%B0\0%B1\0%B2\0%B3\0%B4\0%B5\0%B6\0%B7\0"
521     "%B8\0%B9\0%BA\0%BB\0%BC\0%BD\0%BE\0%BF\0"
522     "%C0\0%C1\0%C2\0%C3\0%C4\0%C5\0%C6\0%C7\0"
523     "%C8\0%C9\0%CA\0%CB\0%CC\0%CD\0%CE\0%CF\0"
524     "%D0\0%D1\0%D2\0%D3\0%D4\0%D5\0%D6\0%D7\0"
525     "%D8\0%D9\0%DA\0%DB\0%DC\0%DD\0%DE\0%DF\0"
526     "%E0\0%E1\0%E2\0%E3\0%E4\0%E5\0%E6\0%E7\0"
527     "%E8\0%E9\0%EA\0%EB\0%EC\0%ED\0%EE\0%EF\0"
528     "%F0\0%F1\0%F2\0%F3\0%F4\0%F5\0%F6\0%F7\0"
529     "%F8\0%F9\0%FA\0%FB\0%FC\0%FD\0%FE\0%FF";
530 
531 constexpr uint8_t C0_CONTROL_PERCENT_ENCODE[32] = {
532     // 00     01     02     03     04     05     06     07
533     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
534     // 08     09     0A     0B     0C     0D     0E     0F
535     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
536     // 10     11     12     13     14     15     16     17
537     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
538     // 18     19     1A     1B     1C     1D     1E     1F
539     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
540     // 20     21     22     23     24     25     26     27
541     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
542     // 28     29     2A     2B     2C     2D     2E     2F
543     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
544     // 30     31     32     33     34     35     36     37
545     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
546     // 38     39     3A     3B     3C     3D     3E     3F
547     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
548     // 40     41     42     43     44     45     46     47
549     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
550     // 48     49     4A     4B     4C     4D     4E     4F
551     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
552     // 50     51     52     53     54     55     56     57
553     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
554     // 58     59     5A     5B     5C     5D     5E     5F
555     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
556     // 60     61     62     63     64     65     66     67
557     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
558     // 68     69     6A     6B     6C     6D     6E     6F
559     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
560     // 70     71     72     73     74     75     76     77
561     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
562     // 78     79     7A     7B     7C     7D     7E     7F
563     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x80,
564     // 80     81     82     83     84     85     86     87
565     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
566     // 88     89     8A     8B     8C     8D     8E     8F
567     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
568     // 90     91     92     93     94     95     96     97
569     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
570     // 98     99     9A     9B     9C     9D     9E     9F
571     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
572     // A0     A1     A2     A3     A4     A5     A6     A7
573     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
574     // A8     A9     AA     AB     AC     AD     AE     AF
575     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
576     // B0     B1     B2     B3     B4     B5     B6     B7
577     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
578     // B8     B9     BA     BB     BC     BD     BE     BF
579     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
580     // C0     C1     C2     C3     C4     C5     C6     C7
581     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
582     // C8     C9     CA     CB     CC     CD     CE     CF
583     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
584     // D0     D1     D2     D3     D4     D5     D6     D7
585     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
586     // D8     D9     DA     DB     DC     DD     DE     DF
587     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
588     // E0     E1     E2     E3     E4     E5     E6     E7
589     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
590     // E8     E9     EA     EB     EC     ED     EE     EF
591     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
592     // F0     F1     F2     F3     F4     F5     F6     F7
593     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
594     // F8     F9     FA     FB     FC     FD     FE     FF
595     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80};
596 
597 constexpr uint8_t SPECIAL_QUERY_PERCENT_ENCODE[32] = {
598     // 00     01     02     03     04     05     06     07
599     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
600     // 08     09     0A     0B     0C     0D     0E     0F
601     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
602     // 10     11     12     13     14     15     16     17
603     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
604     // 18     19     1A     1B     1C     1D     1E     1F
605     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
606     // 20     21     22     23     24     25     26     27
607     0x01 | 0x00 | 0x04 | 0x08 | 0x00 | 0x00 | 0x00 | 0x80,
608     // 28     29     2A     2B     2C     2D     2E     2F
609     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
610     // 30     31     32     33     34     35     36     37
611     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
612     // 38     39     3A     3B     3C     3D     3E     3F
613     0x00 | 0x00 | 0x00 | 0x00 | 0x10 | 0x00 | 0x40 | 0x00,
614     // 40     41     42     43     44     45     46     47
615     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
616     // 48     49     4A     4B     4C     4D     4E     4F
617     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
618     // 50     51     52     53     54     55     56     57
619     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
620     // 58     59     5A     5B     5C     5D     5E     5F
621     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
622     // 60     61     62     63     64     65     66     67
623     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
624     // 68     69     6A     6B     6C     6D     6E     6F
625     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
626     // 70     71     72     73     74     75     76     77
627     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
628     // 78     79     7A     7B     7C     7D     7E     7F
629     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x80,
630     // 80     81     82     83     84     85     86     87
631     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
632     // 88     89     8A     8B     8C     8D     8E     8F
633     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
634     // 90     91     92     93     94     95     96     97
635     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
636     // 98     99     9A     9B     9C     9D     9E     9F
637     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
638     // A0     A1     A2     A3     A4     A5     A6     A7
639     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
640     // A8     A9     AA     AB     AC     AD     AE     AF
641     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
642     // B0     B1     B2     B3     B4     B5     B6     B7
643     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
644     // B8     B9     BA     BB     BC     BD     BE     BF
645     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
646     // C0     C1     C2     C3     C4     C5     C6     C7
647     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
648     // C8     C9     CA     CB     CC     CD     CE     CF
649     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
650     // D0     D1     D2     D3     D4     D5     D6     D7
651     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
652     // D8     D9     DA     DB     DC     DD     DE     DF
653     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
654     // E0     E1     E2     E3     E4     E5     E6     E7
655     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
656     // E8     E9     EA     EB     EC     ED     EE     EF
657     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
658     // F0     F1     F2     F3     F4     F5     F6     F7
659     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
660     // F8     F9     FA     FB     FC     FD     FE     FF
661     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80};
662 
663 constexpr uint8_t QUERY_PERCENT_ENCODE[32] = {
664     // 00     01     02     03     04     05     06     07
665     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
666     // 08     09     0A     0B     0C     0D     0E     0F
667     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
668     // 10     11     12     13     14     15     16     17
669     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
670     // 18     19     1A     1B     1C     1D     1E     1F
671     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
672     // 20     21     22     23     24     25     26     27
673     0x01 | 0x00 | 0x04 | 0x08 | 0x00 | 0x00 | 0x00 | 0x00,
674     // 28     29     2A     2B     2C     2D     2E     2F
675     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
676     // 30     31     32     33     34     35     36     37
677     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
678     // 38     39     3A     3B     3C     3D     3E     3F
679     0x00 | 0x00 | 0x00 | 0x00 | 0x10 | 0x00 | 0x40 | 0x00,
680     // 40     41     42     43     44     45     46     47
681     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
682     // 48     49     4A     4B     4C     4D     4E     4F
683     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
684     // 50     51     52     53     54     55     56     57
685     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
686     // 58     59     5A     5B     5C     5D     5E     5F
687     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
688     // 60     61     62     63     64     65     66     67
689     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
690     // 68     69     6A     6B     6C     6D     6E     6F
691     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
692     // 70     71     72     73     74     75     76     77
693     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
694     // 78     79     7A     7B     7C     7D     7E     7F
695     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x80,
696     // 80     81     82     83     84     85     86     87
697     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
698     // 88     89     8A     8B     8C     8D     8E     8F
699     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
700     // 90     91     92     93     94     95     96     97
701     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
702     // 98     99     9A     9B     9C     9D     9E     9F
703     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
704     // A0     A1     A2     A3     A4     A5     A6     A7
705     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
706     // A8     A9     AA     AB     AC     AD     AE     AF
707     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
708     // B0     B1     B2     B3     B4     B5     B6     B7
709     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
710     // B8     B9     BA     BB     BC     BD     BE     BF
711     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
712     // C0     C1     C2     C3     C4     C5     C6     C7
713     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
714     // C8     C9     CA     CB     CC     CD     CE     CF
715     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
716     // D0     D1     D2     D3     D4     D5     D6     D7
717     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
718     // D8     D9     DA     DB     DC     DD     DE     DF
719     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
720     // E0     E1     E2     E3     E4     E5     E6     E7
721     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
722     // E8     E9     EA     EB     EC     ED     EE     EF
723     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
724     // F0     F1     F2     F3     F4     F5     F6     F7
725     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
726     // F8     F9     FA     FB     FC     FD     FE     FF
727     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80};
728 
729 constexpr uint8_t FRAGMENT_PERCENT_ENCODE[32] = {
730     // 00     01     02     03     04     05     06     07
731     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
732     // 08     09     0A     0B     0C     0D     0E     0F
733     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
734     // 10     11     12     13     14     15     16     17
735     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
736     // 18     19     1A     1B     1C     1D     1E     1F
737     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
738     // 20     21     22     23     24     25     26     27
739     0x01 | 0x00 | 0x04 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
740     // 28     29     2A     2B     2C     2D     2E     2F
741     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
742     // 30     31     32     33     34     35     36     37
743     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
744     // 38     39     3A     3B     3C     3D     3E     3F
745     0x00 | 0x00 | 0x00 | 0x00 | 0x10 | 0x00 | 0x40 | 0x00,
746     // 40     41     42     43     44     45     46     47
747     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
748     // 48     49     4A     4B     4C     4D     4E     4F
749     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
750     // 50     51     52     53     54     55     56     57
751     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
752     // 58     59     5A     5B     5C     5D     5E     5F
753     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
754     // 60     61     62     63     64     65     66     67
755     0x01 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
756     // 68     69     6A     6B     6C     6D     6E     6F
757     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
758     // 70     71     72     73     74     75     76     77
759     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
760     // 78     79     7A     7B     7C     7D     7E     7F
761     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x80,
762     // 80     81     82     83     84     85     86     87
763     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
764     // 88     89     8A     8B     8C     8D     8E     8F
765     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
766     // 90     91     92     93     94     95     96     97
767     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
768     // 98     99     9A     9B     9C     9D     9E     9F
769     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
770     // A0     A1     A2     A3     A4     A5     A6     A7
771     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
772     // A8     A9     AA     AB     AC     AD     AE     AF
773     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
774     // B0     B1     B2     B3     B4     B5     B6     B7
775     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
776     // B8     B9     BA     BB     BC     BD     BE     BF
777     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
778     // C0     C1     C2     C3     C4     C5     C6     C7
779     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
780     // C8     C9     CA     CB     CC     CD     CE     CF
781     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
782     // D0     D1     D2     D3     D4     D5     D6     D7
783     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
784     // D8     D9     DA     DB     DC     DD     DE     DF
785     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
786     // E0     E1     E2     E3     E4     E5     E6     E7
787     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
788     // E8     E9     EA     EB     EC     ED     EE     EF
789     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
790     // F0     F1     F2     F3     F4     F5     F6     F7
791     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
792     // F8     F9     FA     FB     FC     FD     FE     FF
793     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80};
794 
795 constexpr uint8_t USERINFO_PERCENT_ENCODE[32] = {
796     // 00     01     02     03     04     05     06     07
797     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
798     // 08     09     0A     0B     0C     0D     0E     0F
799     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
800     // 10     11     12     13     14     15     16     17
801     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
802     // 18     19     1A     1B     1C     1D     1E     1F
803     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
804     // 20     21     22     23     24     25     26     27
805     0x01 | 0x00 | 0x04 | 0x08 | 0x00 | 0x00 | 0x00 | 0x00,
806     // 28     29     2A     2B     2C     2D     2E     2F
807     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x80,
808     // 30     31     32     33     34     35     36     37
809     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
810     // 38     39     3A     3B     3C     3D     3E     3F
811     0x00 | 0x00 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
812     // 40     41     42     43     44     45     46     47
813     0x01 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
814     // 48     49     4A     4B     4C     4D     4E     4F
815     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
816     // 50     51     52     53     54     55     56     57
817     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
818     // 58     59     5A     5B     5C     5D     5E     5F
819     0x00 | 0x00 | 0x00 | 0x08 | 0x10 | 0x20 | 0x40 | 0x00,
820     // 60     61     62     63     64     65     66     67
821     0x01 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
822     // 68     69     6A     6B     6C     6D     6E     6F
823     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
824     // 70     71     72     73     74     75     76     77
825     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
826     // 78     79     7A     7B     7C     7D     7E     7F
827     0x00 | 0x00 | 0x00 | 0x08 | 0x10 | 0x20 | 0x00 | 0x80,
828     // 80     81     82     83     84     85     86     87
829     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
830     // 88     89     8A     8B     8C     8D     8E     8F
831     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
832     // 90     91     92     93     94     95     96     97
833     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
834     // 98     99     9A     9B     9C     9D     9E     9F
835     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
836     // A0     A1     A2     A3     A4     A5     A6     A7
837     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
838     // A8     A9     AA     AB     AC     AD     AE     AF
839     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
840     // B0     B1     B2     B3     B4     B5     B6     B7
841     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
842     // B8     B9     BA     BB     BC     BD     BE     BF
843     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
844     // C0     C1     C2     C3     C4     C5     C6     C7
845     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
846     // C8     C9     CA     CB     CC     CD     CE     CF
847     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
848     // D0     D1     D2     D3     D4     D5     D6     D7
849     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
850     // D8     D9     DA     DB     DC     DD     DE     DF
851     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
852     // E0     E1     E2     E3     E4     E5     E6     E7
853     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
854     // E8     E9     EA     EB     EC     ED     EE     EF
855     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
856     // F0     F1     F2     F3     F4     F5     F6     F7
857     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
858     // F8     F9     FA     FB     FC     FD     FE     FF
859     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80};
860 
861 constexpr uint8_t PATH_PERCENT_ENCODE[32] = {
862     // 00     01     02     03     04     05     06     07
863     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
864     // 08     09     0A     0B     0C     0D     0E     0F
865     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
866     // 10     11     12     13     14     15     16     17
867     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
868     // 18     19     1A     1B     1C     1D     1E     1F
869     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
870     // 20     21     22     23     24     25     26     27
871     0x01 | 0x00 | 0x04 | 0x08 | 0x00 | 0x00 | 0x00 | 0x00,
872     // 28     29     2A     2B     2C     2D     2E     2F
873     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
874     // 30     31     32     33     34     35     36     37
875     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
876     // 38     39     3A     3B     3C     3D     3E     3F
877     0x00 | 0x00 | 0x00 | 0x00 | 0x10 | 0x00 | 0x40 | 0x80,
878     // 40     41     42     43     44     45     46     47
879     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
880     // 48     49     4A     4B     4C     4D     4E     4F
881     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
882     // 50     51     52     53     54     55     56     57
883     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
884     // 58     59     5A     5B     5C     5D     5E     5F
885     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
886     // 60     61     62     63     64     65     66     67
887     0x01 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
888     // 68     69     6A     6B     6C     6D     6E     6F
889     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
890     // 70     71     72     73     74     75     76     77
891     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
892     // 78     79     7A     7B     7C     7D     7E     7F
893     0x00 | 0x00 | 0x00 | 0x08 | 0x00 | 0x20 | 0x00 | 0x80,
894     // 80     81     82     83     84     85     86     87
895     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
896     // 88     89     8A     8B     8C     8D     8E     8F
897     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
898     // 90     91     92     93     94     95     96     97
899     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
900     // 98     99     9A     9B     9C     9D     9E     9F
901     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
902     // A0     A1     A2     A3     A4     A5     A6     A7
903     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
904     // A8     A9     AA     AB     AC     AD     AE     AF
905     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
906     // B0     B1     B2     B3     B4     B5     B6     B7
907     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
908     // B8     B9     BA     BB     BC     BD     BE     BF
909     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
910     // C0     C1     C2     C3     C4     C5     C6     C7
911     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
912     // C8     C9     CA     CB     CC     CD     CE     CF
913     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
914     // D0     D1     D2     D3     D4     D5     D6     D7
915     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
916     // D8     D9     DA     DB     DC     DD     DE     DF
917     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
918     // E0     E1     E2     E3     E4     E5     E6     E7
919     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
920     // E8     E9     EA     EB     EC     ED     EE     EF
921     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
922     // F0     F1     F2     F3     F4     F5     F6     F7
923     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
924     // F8     F9     FA     FB     FC     FD     FE     FF
925     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80};
926 
927 constexpr uint8_t WWW_FORM_URLENCODED_PERCENT_ENCODE[32] = {
928     // 00     01     02     03     04     05     06     07
929     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
930     // 08     09     0A     0B     0C     0D     0E     0F
931     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
932     // 10     11     12     13     14     15     16     17
933     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
934     // 18     19     1A     1B     1C     1D     1E     1F
935     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
936     // 20     21     22     23     24     25     26     27
937     0x00 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
938     // 28     29     2A     2B     2C     2D     2E     2F
939     0x01 | 0x02 | 0x00 | 0x08 | 0x10 | 0x00 | 0x00 | 0x00,
940     // 30     31     32     33     34     35     36     37
941     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
942     // 38     39     3A     3B     3C     3D     3E     3F
943     0x00 | 0x00 | 0x00 | 0x00 | 0x10 | 0x00 | 0x40 | 0x80,
944     // 40     41     42     43     44     45     46     47
945     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
946     // 48     49     4A     4B     4C     4D     4E     4F
947     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
948     // 50     51     52     53     54     55     56     57
949     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
950     // 58     59     5A     5B     5C     5D     5E     5F
951     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
952     // 60     61     62     63     64     65     66     67
953     0x01 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
954     // 68     69     6A     6B     6C     6D     6E     6F
955     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
956     // 70     71     72     73     74     75     76     77
957     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
958     // 78     79     7A     7B     7C     7D     7E     7F
959     0x00 | 0x00 | 0x00 | 0x08 | 0x00 | 0x20 | 0x40 | 0x80,
960     // 80     81     82     83     84     85     86     87
961     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
962     // 88     89     8A     8B     8C     8D     8E     8F
963     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
964     // 90     91     92     93     94     95     96     97
965     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
966     // 98     99     9A     9B     9C     9D     9E     9F
967     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
968     // A0     A1     A2     A3     A4     A5     A6     A7
969     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
970     // A8     A9     AA     AB     AC     AD     AE     AF
971     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
972     // B0     B1     B2     B3     B4     B5     B6     B7
973     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
974     // B8     B9     BA     BB     BC     BD     BE     BF
975     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
976     // C0     C1     C2     C3     C4     C5     C6     C7
977     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
978     // C8     C9     CA     CB     CC     CD     CE     CF
979     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
980     // D0     D1     D2     D3     D4     D5     D6     D7
981     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
982     // D8     D9     DA     DB     DC     DD     DE     DF
983     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
984     // E0     E1     E2     E3     E4     E5     E6     E7
985     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
986     // E8     E9     EA     EB     EC     ED     EE     EF
987     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
988     // F0     F1     F2     F3     F4     F5     F6     F7
989     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
990     // F8     F9     FA     FB     FC     FD     FE     FF
991     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80};
992 
bit_at(const uint8_t a[],const uint8_t i)993 ada_really_inline bool bit_at(const uint8_t a[], const uint8_t i) {
994   return !!(a[i >> 3] & (1 << (i & 7)));
995 }
996 
997 }  // namespace ada::character_sets
998 
999 #endif  // ADA_CHARACTER_SETS_INL_H
1000 /* end file include/ada/character_sets-inl.h */
1001 /* begin file include/ada/checkers-inl.h */
1002 /**
1003  * @file checkers-inl.h
1004  * @brief Definitions for URL specific checkers used within Ada.
1005  */
1006 #ifndef ADA_CHECKERS_INL_H
1007 #define ADA_CHECKERS_INL_H
1008 
1009 
1010 #include <algorithm>
1011 #include <string_view>
1012 #include <cstring>
1013 
1014 namespace ada::checkers {
1015 
has_hex_prefix_unsafe(std::string_view input)1016 inline bool has_hex_prefix_unsafe(std::string_view input) {
1017   // This is actually efficient code, see has_hex_prefix for the assembly.
1018   uint32_t value_one = 1;
1019   bool is_little_endian = (reinterpret_cast<char*>(&value_one)[0] == 1);
1020   uint16_t word0x{};
1021   std::memcpy(&word0x, "0x", 2);  // we would use bit_cast in C++20 and the
1022                                   // function could be constexpr.
1023   uint16_t two_first_bytes{};
1024   std::memcpy(&two_first_bytes, input.data(), 2);
1025   if (is_little_endian) {
1026     two_first_bytes |= 0x2000;
1027   } else {
1028     two_first_bytes |= 0x020;
1029   }
1030   return two_first_bytes == word0x;
1031 }
1032 
has_hex_prefix(std::string_view input)1033 inline bool has_hex_prefix(std::string_view input) {
1034   return input.size() >= 2 && has_hex_prefix_unsafe(input);
1035 }
1036 
is_digit(char x)1037 constexpr bool is_digit(char x) noexcept { return (x >= '0') & (x <= '9'); }
1038 
to_lower(char x)1039 constexpr char to_lower(char x) noexcept { return (x | 0x20); }
1040 
is_alpha(char x)1041 constexpr bool is_alpha(char x) noexcept {
1042   return (to_lower(x) >= 'a') && (to_lower(x) <= 'z');
1043 }
1044 
is_windows_drive_letter(std::string_view input)1045 inline constexpr bool is_windows_drive_letter(std::string_view input) noexcept {
1046   return input.size() >= 2 &&
1047          (is_alpha(input[0]) && ((input[1] == ':') || (input[1] == '|'))) &&
1048          ((input.size() == 2) || (input[2] == '/' || input[2] == '\\' ||
1049                                   input[2] == '?' || input[2] == '#'));
1050 }
1051 
is_normalized_windows_drive_letter(std::string_view input)1052 inline constexpr bool is_normalized_windows_drive_letter(
1053     std::string_view input) noexcept {
1054   return input.size() >= 2 && (is_alpha(input[0]) && (input[1] == ':'));
1055 }
1056 
begins_with(std::string_view view,std::string_view prefix)1057 ada_really_inline bool begins_with(std::string_view view,
1058                                    std::string_view prefix) {
1059   // in C++20, you have view.begins_with(prefix)
1060   // std::equal is constexpr in C++20
1061   return view.size() >= prefix.size() &&
1062          std::equal(prefix.begin(), prefix.end(), view.begin());
1063 }
1064 
1065 }  // namespace ada::checkers
1066 
1067 #endif  // ADA_CHECKERS_H
1068 /* end file include/ada/checkers-inl.h */
1069 /* begin file include/ada/log.h */
1070 /**
1071  * @file log.h
1072  * @brief Includes the definitions for logging.
1073  * @private Excluded from docs through the doxygen file.
1074  */
1075 #ifndef ADA_LOG_H
1076 #define ADA_LOG_H
1077 
1078 #include <iostream>
1079 // To enable logging, set ADA_LOGGING to 1:
1080 #ifndef ADA_LOGGING
1081 #define ADA_LOGGING 0
1082 #endif
1083 
1084 namespace ada {
1085 
1086 /**
1087  * Private function used for logging messages.
1088  * @private
1089  */
1090 template <typename T>
inner_log(T t)1091 ada_really_inline void inner_log([[maybe_unused]] T t) {
1092 #if ADA_LOGGING
1093   std::cout << t << std::endl;
1094 #endif
1095 }
1096 
1097 /**
1098  * Private function used for logging messages.
1099  * @private
1100  */
1101 template <typename T, typename... Args>
inner_log(T t,Args...args)1102 ada_really_inline void inner_log([[maybe_unused]] T t,
1103                                  [[maybe_unused]] Args... args) {
1104 #if ADA_LOGGING
1105   std::cout << t;
1106   inner_log(args...);
1107 #endif
1108 }
1109 
1110 /**
1111  * Log a message.
1112  * @private
1113  */
1114 template <typename T, typename... Args>
log(T t,Args...args)1115 ada_really_inline void log([[maybe_unused]] T t,
1116                            [[maybe_unused]] Args... args) {
1117 #if ADA_LOGGING
1118   std::cout << "ADA_LOG: " << t;
1119   inner_log(args...);
1120 #endif
1121 }
1122 
1123 /**
1124  * Log a message.
1125  * @private
1126  */
1127 template <typename T>
log(T t)1128 ada_really_inline void log([[maybe_unused]] T t) {
1129 #if ADA_LOGGING
1130   std::cout << "ADA_LOG: " << t << std::endl;
1131 #endif
1132 }
1133 }  // namespace ada
1134 
1135 #if ADA_LOGGING
1136 
1137 #ifndef ada_log
1138 #define ada_log(...)       \
1139   do {                     \
1140     ada::log(__VA_ARGS__); \
1141   } while (0)
1142 #endif  // ada_log
1143 #else
1144 #define ada_log(...)
1145 #endif  // ADA_LOGGING
1146 
1147 #endif  // ADA_LOG_H
1148 /* end file include/ada/log.h */
1149 /* begin file include/ada/encoding_type.h */
1150 /**
1151  * @file encoding_type.h
1152  * @brief Definition for supported encoding types.
1153  */
1154 #ifndef ADA_ENCODING_TYPE_H
1155 #define ADA_ENCODING_TYPE_H
1156 
1157 #include <string>
1158 
1159 namespace ada {
1160 
1161 /**
1162  * This specification defines three encodings with the same names as encoding
1163  * schemes defined in the Unicode standard: UTF-8, UTF-16LE, and UTF-16BE.
1164  *
1165  * @see https://encoding.spec.whatwg.org/#encodings
1166  */
1167 enum class encoding_type {
1168   UTF8,
1169   UTF_16LE,
1170   UTF_16BE,
1171 };
1172 
1173 /**
1174  * Convert a encoding_type to string.
1175  */
1176 ada_warn_unused std::string to_string(encoding_type type);
1177 
1178 }  // namespace ada
1179 
1180 #endif  // ADA_ENCODING_TYPE_H
1181 /* end file include/ada/encoding_type.h */
1182 /* begin file include/ada/helpers.h */
1183 /**
1184  * @file helpers.h
1185  * @brief Definitions for helper functions used within Ada.
1186  */
1187 #ifndef ADA_HELPERS_H
1188 #define ADA_HELPERS_H
1189 
1190 /* begin file include/ada/state.h */
1191 /**
1192  * @file state.h
1193  * @brief Definitions for the states of the URL state machine.
1194  */
1195 #ifndef ADA_STATE_H
1196 #define ADA_STATE_H
1197 
1198 
1199 #include <string>
1200 
1201 namespace ada {
1202 
1203 /**
1204  * @see https://url.spec.whatwg.org/#url-parsing
1205  */
1206 enum class state {
1207   AUTHORITY,
1208   SCHEME_START,
1209   SCHEME,
1210   HOST,
1211   NO_SCHEME,
1212   FRAGMENT,
1213   RELATIVE_SCHEME,
1214   RELATIVE_SLASH,
1215   FILE,
1216   FILE_HOST,
1217   FILE_SLASH,
1218   PATH_OR_AUTHORITY,
1219   SPECIAL_AUTHORITY_IGNORE_SLASHES,
1220   SPECIAL_AUTHORITY_SLASHES,
1221   SPECIAL_RELATIVE_OR_AUTHORITY,
1222   QUERY,
1223   PATH,
1224   PATH_START,
1225   OPAQUE_PATH,
1226   PORT,
1227 };
1228 
1229 /**
1230  * Stringify a URL state machine state.
1231  */
1232 ada_warn_unused std::string to_string(ada::state s);
1233 
1234 }  // namespace ada
1235 
1236 #endif  // ADA_STATE_H
1237 /* end file include/ada/state.h */
1238 /* begin file include/ada/url_base.h */
1239 /**
1240  * @file url_base.h
1241  * @brief Declaration for the basic URL definitions
1242  */
1243 #ifndef ADA_URL_BASE_H
1244 #define ADA_URL_BASE_H
1245 
1246 /* begin file include/ada/url_components.h */
1247 /**
1248  * @file url_components.h
1249  * @brief Declaration for the URL Components
1250  */
1251 #ifndef ADA_URL_COMPONENTS_H
1252 #define ADA_URL_COMPONENTS_H
1253 
1254 
1255 #include <optional>
1256 #include <string_view>
1257 
1258 namespace ada {
1259 
1260 /**
1261  * @brief URL Component representations using offsets.
1262  *
1263  * @details We design the url_components struct so that it is as small
1264  * and simple as possible. This version uses 32 bytes.
1265  *
1266  * This struct is used to extract components from a single 'href'.
1267  */
1268 struct url_components {
1269   constexpr static uint32_t omitted = uint32_t(-1);
1270 
1271   url_components() = default;
1272   url_components(const url_components &u) = default;
1273   url_components(url_components &&u) noexcept = default;
1274   url_components &operator=(url_components &&u) noexcept = default;
1275   url_components &operator=(const url_components &u) = default;
1276   ~url_components() = default;
1277 
1278   /*
1279    * By using 32-bit integers, we implicitly assume that the URL string
1280    * cannot exceed 4 GB.
1281    *
1282    * https://user:pass@example.com:1234/foo/bar?baz#quux
1283    *       |     |    |          | ^^^^|       |   |
1284    *       |     |    |          | |   |       |   `----- hash_start
1285    *       |     |    |          | |   |       `--------- search_start
1286    *       |     |    |          | |   `----------------- pathname_start
1287    *       |     |    |          | `--------------------- port
1288    *       |     |    |          `----------------------- host_end
1289    *       |     |    `---------------------------------- host_start
1290    *       |     `--------------------------------------- username_end
1291    *       `--------------------------------------------- protocol_end
1292    */
1293   uint32_t protocol_end{0};
1294   /**
1295    * Username end is not `omitted` by default to make username and password
1296    * getters less costly to implement.
1297    */
1298   uint32_t username_end{0};
1299   uint32_t host_start{0};
1300   uint32_t host_end{0};
1301   uint32_t port{omitted};
1302   uint32_t pathname_start{0};
1303   uint32_t search_start{omitted};
1304   uint32_t hash_start{omitted};
1305 
1306   /**
1307    * Check the following conditions:
1308    * protocol_end < username_end < ... < hash_start,
1309    * expect when a value is omitted. It also computes
1310    * a lower bound on  the possible string length that may match these
1311    * offsets.
1312    * @return true if the offset values are
1313    *  consistent with a possible URL string
1314    */
1315   [[nodiscard]] bool check_offset_consistency() const noexcept;
1316 
1317   /**
1318    * Converts a url_components to JSON stringified version.
1319    */
1320   [[nodiscard]] std::string to_string() const;
1321 
1322 };  // struct url_components
1323 
1324 }  // namespace ada
1325 #endif
1326 /* end file include/ada/url_components.h */
1327 /* begin file include/ada/scheme.h */
1328 /**
1329  * @file scheme.h
1330  * @brief Declarations for the URL scheme.
1331  */
1332 #ifndef ADA_SCHEME_H
1333 #define ADA_SCHEME_H
1334 
1335 
1336 #include <array>
1337 #include <optional>
1338 #include <string>
1339 
1340 /**
1341  * @namespace ada::scheme
1342  * @brief Includes the scheme declarations
1343  */
1344 namespace ada::scheme {
1345 
1346 /**
1347  * Type of the scheme as an enum.
1348  * Using strings to represent a scheme type is not ideal because
1349  * checking for types involves string comparisons. It is faster to use
1350  * a simple integer.
1351  * In C++11, we are allowed to specify the underlying type of the enum.
1352  * We pick an 8-bit integer (which allows up to 256 types). Specifying the
1353  * type of the enum may help integration with other systems if the type
1354  * variable is exposed (since its value will not depend on the compiler).
1355  */
1356 enum type : uint8_t {
1357   HTTP = 0,
1358   NOT_SPECIAL = 1,
1359   HTTPS = 2,
1360   WS = 3,
1361   FTP = 4,
1362   WSS = 5,
1363   FILE = 6
1364 };
1365 
1366 /**
1367  * A special scheme is an ASCII string that is listed in the first column of the
1368  * following table. The default port for a special scheme is listed in the
1369  * second column on the same row. The default port for any other ASCII string is
1370  * null.
1371  *
1372  * @see https://url.spec.whatwg.org/#url-miscellaneous
1373  * @param scheme
1374  * @return If scheme is a special scheme
1375  */
1376 ada_really_inline constexpr bool is_special(std::string_view scheme);
1377 
1378 /**
1379  * A special scheme is an ASCII string that is listed in the first column of the
1380  * following table. The default port for a special scheme is listed in the
1381  * second column on the same row. The default port for any other ASCII string is
1382  * null.
1383  *
1384  * @see https://url.spec.whatwg.org/#url-miscellaneous
1385  * @param scheme
1386  * @return The special port
1387  */
1388 constexpr uint16_t get_special_port(std::string_view scheme) noexcept;
1389 
1390 /**
1391  * Returns the port number of a special scheme.
1392  * @see https://url.spec.whatwg.org/#special-scheme
1393  */
1394 constexpr uint16_t get_special_port(ada::scheme::type type) noexcept;
1395 /**
1396  * Returns the scheme of an input, or NOT_SPECIAL if it's not a special scheme
1397  * defined by the spec.
1398  */
1399 constexpr ada::scheme::type get_scheme_type(std::string_view scheme) noexcept;
1400 
1401 }  // namespace ada::scheme
1402 
1403 #endif  // ADA_SCHEME_H
1404 /* end file include/ada/scheme.h */
1405 
1406 #include <string_view>
1407 
1408 namespace ada {
1409 
1410 /**
1411  * Type of URL host as an enum.
1412  */
1413 enum url_host_type : uint8_t {
1414   /**
1415    * Represents common URLs such as "https://www.google.com"
1416    */
1417   DEFAULT = 0,
1418   /**
1419    * Represents ipv4 addresses such as "http://127.0.0.1"
1420    */
1421   IPV4 = 1,
1422   /**
1423    * Represents ipv6 addresses such as
1424    * "http://[2001:db8:3333:4444:5555:6666:7777:8888]"
1425    */
1426   IPV6 = 2,
1427 };
1428 
1429 /**
1430  * @brief Base class of URL implementations
1431  *
1432  * @details A url_base contains a few attributes: is_valid, has_opaque_path and
1433  * type. All non-trivial implementation details are in derived classes such as
1434  * ada::url and ada::url_aggregator.
1435  *
1436  * It is an abstract class that cannot be instantiated directly.
1437  */
1438 struct url_base {
1439   virtual ~url_base() = default;
1440 
1441   /**
1442    * Used for returning the validity from the result of the URL parser.
1443    */
1444   bool is_valid{true};
1445 
1446   /**
1447    * A URL has an opaque path if its path is a string.
1448    */
1449   bool has_opaque_path{false};
1450 
1451   /**
1452    * URL hosts type
1453    */
1454   url_host_type host_type = url_host_type::DEFAULT;
1455 
1456   /**
1457    * @private
1458    */
1459   ada::scheme::type type{ada::scheme::type::NOT_SPECIAL};
1460 
1461   /**
1462    * A URL is special if its scheme is a special scheme. A URL is not special if
1463    * its scheme is not a special scheme.
1464    */
1465   [[nodiscard]] ada_really_inline bool is_special() const noexcept;
1466 
1467   /**
1468    * The origin getter steps are to return the serialization of this's URL's
1469    * origin. [HTML]
1470    * @return a newly allocated string.
1471    * @see https://url.spec.whatwg.org/#concept-url-origin
1472    */
1473   [[nodiscard]] virtual std::string get_origin() const noexcept = 0;
1474 
1475   /**
1476    * Returns true if this URL has a valid domain as per RFC 1034 and
1477    * corresponding specifications. Among other things, it requires
1478    * that the domain string has fewer than 255 octets.
1479    */
1480   [[nodiscard]] virtual bool has_valid_domain() const noexcept = 0;
1481 
1482   /**
1483    * @private
1484    *
1485    * Return the 'special port' if the URL is special and not 'file'.
1486    * Returns 0 otherwise.
1487    */
1488   [[nodiscard]] inline uint16_t get_special_port() const noexcept;
1489 
1490   /**
1491    * @private
1492    *
1493    * Get the default port if the url's scheme has one, returns 0 otherwise.
1494    */
1495   [[nodiscard]] ada_really_inline uint16_t scheme_default_port() const noexcept;
1496 
1497   /**
1498    * @private
1499    *
1500    * Parse a port (16-bit decimal digit) from the provided input.
1501    * We assume that the input does not contain spaces or tabs
1502    * within the ASCII digits.
1503    * It returns how many bytes were consumed when a number is successfully
1504    * parsed.
1505    * @return On failure, it returns zero.
1506    * @see https://url.spec.whatwg.org/#host-parsing
1507    */
1508   virtual size_t parse_port(std::string_view view,
1509                             bool check_trailing_content) noexcept = 0;
1510 
parse_porturl_base1511   virtual ada_really_inline size_t parse_port(std::string_view view) noexcept {
1512     return this->parse_port(view, false);
1513   }
1514 
1515   /**
1516    * Returns a JSON string representation of this URL.
1517    */
1518   [[nodiscard]] virtual std::string to_string() const = 0;
1519 
1520   /** @private */
1521   virtual inline void clear_pathname() = 0;
1522 
1523   /** @private */
1524   virtual inline void clear_search() = 0;
1525 
1526   /** @private */
1527   [[nodiscard]] virtual inline bool has_hash() const noexcept = 0;
1528 
1529   /** @private */
1530   [[nodiscard]] virtual inline bool has_search() const noexcept = 0;
1531 
1532 };  // url_base
1533 
1534 }  // namespace ada
1535 
1536 #endif
1537 /* end file include/ada/url_base.h */
1538 
1539 #include <string_view>
1540 #include <optional>
1541 
1542 /**
1543  * @private
1544  * @namespace ada::helpers
1545  * @brief Includes the definitions for helper functions
1546  */
1547 namespace ada::helpers {
1548 
1549 /**
1550  * @private
1551  */
1552 template <typename out_iter>
1553 void encode_json(std::string_view view, out_iter out);
1554 
1555 /**
1556  * @private
1557  * This function is used to prune a fragment from a url, and returning the
1558  * removed string if input has fragment.
1559  *
1560  * @details prune_hash seeks the first '#' and returns everything after it
1561  * as a string_view, and modifies (in place) the input so that it points at
1562  * everything before the '#'. If no '#' is found, the input is left unchanged
1563  * and std::nullopt is returned.
1564  *
1565  * @attention The function is non-allocating and it does not throw.
1566  * @returns Note that the returned string_view might be empty!
1567  */
1568 ada_really_inline std::optional<std::string_view> prune_hash(
1569     std::string_view& input) noexcept;
1570 
1571 /**
1572  * @private
1573  * Defined by the URL specification, shorten a URLs paths.
1574  * @see https://url.spec.whatwg.org/#shorten-a-urls-path
1575  * @returns Returns true if path is shortened.
1576  */
1577 ada_really_inline bool shorten_path(std::string& path,
1578                                     ada::scheme::type type) noexcept;
1579 
1580 /**
1581  * @private
1582  * Defined by the URL specification, shorten a URLs paths.
1583  * @see https://url.spec.whatwg.org/#shorten-a-urls-path
1584  * @returns Returns true if path is shortened.
1585  */
1586 ada_really_inline bool shorten_path(std::string_view& path,
1587                                     ada::scheme::type type) noexcept;
1588 
1589 /**
1590  * @private
1591  *
1592  * Parse the path from the provided input and append to the existing
1593  * (possibly empty) path. The input cannot contain tabs and spaces: it
1594  * is the user's responsibility to check.
1595  *
1596  * The input is expected to be UTF-8.
1597  *
1598  * @see https://url.spec.whatwg.org/
1599  */
1600 ada_really_inline void parse_prepared_path(std::string_view input,
1601                                            ada::scheme::type type,
1602                                            std::string& path);
1603 
1604 /**
1605  * @private
1606  * Remove and mutate all ASCII tab or newline characters from an input.
1607  */
1608 ada_really_inline void remove_ascii_tab_or_newline(std::string& input) noexcept;
1609 
1610 /**
1611  * @private
1612  * Return the substring from input going from index pos to the end.
1613  * This function cannot throw.
1614  */
1615 ada_really_inline std::string_view substring(std::string_view input,
1616                                              size_t pos) noexcept;
1617 
1618 /**
1619  * @private
1620  * Returns true if the string_view points within the string.
1621  */
1622 bool overlaps(std::string_view input1, const std::string& input2) noexcept;
1623 
1624 /**
1625  * @private
1626  * Return the substring from input going from index pos1 to the pos2 (non
1627  * included). The length of the substring is pos2 - pos1.
1628  */
substring(const std::string & input,size_t pos1,size_t pos2)1629 ada_really_inline std::string_view substring(const std::string& input,
1630                                              size_t pos1,
1631                                              size_t pos2) noexcept {
1632 #if ADA_DEVELOPMENT_CHECKS
1633   if (pos2 < pos1) {
1634     std::cerr << "Negative-length substring: [" << pos1 << " to " << pos2 << ")"
1635               << std::endl;
1636     abort();
1637   }
1638 #endif
1639   return std::string_view(input.data() + pos1, pos2 - pos1);
1640 }
1641 
1642 /**
1643  * @private
1644  * Modify the string_view so that it has the new size pos, assuming that pos <=
1645  * input.size(). This function cannot throw.
1646  */
1647 ada_really_inline void resize(std::string_view& input, size_t pos) noexcept;
1648 
1649 /**
1650  * @private
1651  * Returns a host's delimiter location depending on the state of the instance,
1652  * and whether a colon was found outside brackets. Used by the host parser.
1653  */
1654 ada_really_inline std::pair<size_t, bool> get_host_delimiter_location(
1655     const bool is_special, std::string_view& view) noexcept;
1656 
1657 /**
1658  * @private
1659  * Removes leading and trailing C0 control and whitespace characters from
1660  * string.
1661  */
1662 ada_really_inline void trim_c0_whitespace(std::string_view& input) noexcept;
1663 
1664 /**
1665  * @private
1666  * @see
1667  * https://url.spec.whatwg.org/#potentially-strip-trailing-spaces-from-an-opaque-path
1668  */
1669 template <class url_type>
1670 ada_really_inline void strip_trailing_spaces_from_opaque_path(
1671     url_type& url) noexcept;
1672 
1673 /**
1674  * @private
1675  * Finds the delimiter of a view in authority state.
1676  */
1677 ada_really_inline size_t
1678 find_authority_delimiter_special(std::string_view view) noexcept;
1679 
1680 /**
1681  * @private
1682  * Finds the delimiter of a view in authority state.
1683  */
1684 ada_really_inline size_t
1685 find_authority_delimiter(std::string_view view) noexcept;
1686 
1687 /**
1688  * @private
1689  */
1690 template <typename T, typename... Args>
inner_concat(std::string & buffer,T t)1691 inline void inner_concat(std::string& buffer, T t) {
1692   buffer.append(t);
1693 }
1694 
1695 /**
1696  * @private
1697  */
1698 template <typename T, typename... Args>
inner_concat(std::string & buffer,T t,Args...args)1699 inline void inner_concat(std::string& buffer, T t, Args... args) {
1700   buffer.append(t);
1701   return inner_concat(buffer, args...);
1702 }
1703 
1704 /**
1705  * Concatenate the arguments and return a string.
1706  * @returns a string
1707  */
1708 template <typename... Args>
concat(Args...args)1709 std::string concat(Args... args) {
1710   std::string answer;
1711   inner_concat(answer, args...);
1712   return answer;
1713 }
1714 
1715 /**
1716  * @return Number of leading zeroes.
1717  */
leading_zeroes(uint32_t input_num)1718 inline int leading_zeroes(uint32_t input_num) noexcept {
1719 #if ADA_REGULAR_VISUAL_STUDIO
1720   unsigned long leading_zero(0);
1721   unsigned long in(input_num);
1722   return _BitScanReverse(&leading_zero, in) ? int(31 - leading_zero) : 32;
1723 #else
1724   return __builtin_clz(input_num);
1725 #endif  // ADA_REGULAR_VISUAL_STUDIO
1726 }
1727 
1728 /**
1729  * Counts the number of decimal digits necessary to represent x.
1730  * faster than std::to_string(x).size().
1731  * @return digit count
1732  */
fast_digit_count(uint32_t x)1733 inline int fast_digit_count(uint32_t x) noexcept {
1734   auto int_log2 = [](uint32_t z) -> int {
1735     return 31 - ada::helpers::leading_zeroes(z | 1);
1736   };
1737   // Compiles to very few instructions. Note that the
1738   // table is static and thus effectively a constant.
1739   // We leave it inside the function because it is meaningless
1740   // outside of it (this comes at no performance cost).
1741   const static uint64_t table[] = {
1742       4294967296,  8589934582,  8589934582,  8589934582,  12884901788,
1743       12884901788, 12884901788, 17179868184, 17179868184, 17179868184,
1744       21474826480, 21474826480, 21474826480, 21474826480, 25769703776,
1745       25769703776, 25769703776, 30063771072, 30063771072, 30063771072,
1746       34349738368, 34349738368, 34349738368, 34349738368, 38554705664,
1747       38554705664, 38554705664, 41949672960, 41949672960, 41949672960,
1748       42949672960, 42949672960};
1749   return int((x + table[int_log2(x)]) >> 32);
1750 }
1751 }  // namespace ada::helpers
1752 
1753 #endif  // ADA_HELPERS_H
1754 /* end file include/ada/helpers.h */
1755 /* begin file include/ada/parser.h */
1756 /**
1757  * @file parser.h
1758  * @brief Definitions for the parser.
1759  */
1760 #ifndef ADA_PARSER_H
1761 #define ADA_PARSER_H
1762 
1763 /* begin file include/ada/expected.h */
1764 /**
1765  * @file expected.h
1766  * @brief Definitions for std::expected
1767  * @private Excluded from docs through the doxygen file.
1768  */
1769 ///
1770 // expected - An implementation of std::expected with extensions
1771 // Written in 2017 by Sy Brand (tartanllama@gmail.com, @TartanLlama)
1772 //
1773 // Documentation available at http://tl.tartanllama.xyz/
1774 //
1775 // To the extent possible under law, the author(s) have dedicated all
1776 // copyright and related and neighboring rights to this software to the
1777 // public domain worldwide. This software is distributed without any warranty.
1778 //
1779 // You should have received a copy of the CC0 Public Domain Dedication
1780 // along with this software. If not, see
1781 // <http://creativecommons.org/publicdomain/zero/1.0/>.
1782 ///
1783 
1784 #ifndef TL_EXPECTED_HPP
1785 #define TL_EXPECTED_HPP
1786 
1787 #define TL_EXPECTED_VERSION_MAJOR 1
1788 #define TL_EXPECTED_VERSION_MINOR 1
1789 #define TL_EXPECTED_VERSION_PATCH 0
1790 
1791 #include <exception>
1792 #include <functional>
1793 #include <type_traits>
1794 #include <utility>
1795 
1796 #if defined(__EXCEPTIONS) || defined(_CPPUNWIND)
1797 #define TL_EXPECTED_EXCEPTIONS_ENABLED
1798 #endif
1799 
1800 #if (defined(_MSC_VER) && _MSC_VER == 1900)
1801 #define TL_EXPECTED_MSVC2015
1802 #define TL_EXPECTED_MSVC2015_CONSTEXPR
1803 #else
1804 #define TL_EXPECTED_MSVC2015_CONSTEXPR constexpr
1805 #endif
1806 
1807 #if (defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ <= 9 && \
1808      !defined(__clang__))
1809 #define TL_EXPECTED_GCC49
1810 #endif
1811 
1812 #if (defined(__GNUC__) && __GNUC__ == 5 && __GNUC_MINOR__ <= 4 && \
1813      !defined(__clang__))
1814 #define TL_EXPECTED_GCC54
1815 #endif
1816 
1817 #if (defined(__GNUC__) && __GNUC__ == 5 && __GNUC_MINOR__ <= 5 && \
1818      !defined(__clang__))
1819 #define TL_EXPECTED_GCC55
1820 #endif
1821 
1822 #if !defined(TL_ASSERT)
1823 // can't have assert in constexpr in C++11 and GCC 4.9 has a compiler bug
1824 #if (__cplusplus > 201103L) && !defined(TL_EXPECTED_GCC49)
1825 #include <cassert>
1826 #define TL_ASSERT(x) assert(x)
1827 #else
1828 #define TL_ASSERT(x)
1829 #endif
1830 #endif
1831 
1832 #if (defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ <= 9 && \
1833      !defined(__clang__))
1834 // GCC < 5 doesn't support overloading on const&& for member functions
1835 
1836 #define TL_EXPECTED_NO_CONSTRR
1837 // GCC < 5 doesn't support some standard C++11 type traits
1838 #define TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) \
1839   std::has_trivial_copy_constructor<T>
1840 #define TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(T) \
1841   std::has_trivial_copy_assign<T>
1842 
1843 // This one will be different for GCC 5.7 if it's ever supported
1844 #define TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(T) \
1845   std::is_trivially_destructible<T>
1846 
1847 // GCC 5 < v < 8 has a bug in is_trivially_copy_constructible which breaks
1848 // std::vector for non-copyable types
1849 #elif (defined(__GNUC__) && __GNUC__ < 8 && !defined(__clang__))
1850 #ifndef TL_GCC_LESS_8_TRIVIALLY_COPY_CONSTRUCTIBLE_MUTEX
1851 #define TL_GCC_LESS_8_TRIVIALLY_COPY_CONSTRUCTIBLE_MUTEX
1852 namespace tl {
1853 namespace detail {
1854 template <class T>
1855 struct is_trivially_copy_constructible
1856     : std::is_trivially_copy_constructible<T> {};
1857 #ifdef _GLIBCXX_VECTOR
1858 template <class T, class A>
1859 struct is_trivially_copy_constructible<std::vector<T, A>> : std::false_type {};
1860 #endif
1861 }  // namespace detail
1862 }  // namespace tl
1863 #endif
1864 
1865 #define TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) \
1866   tl::detail::is_trivially_copy_constructible<T>
1867 #define TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(T) \
1868   std::is_trivially_copy_assignable<T>
1869 #define TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(T) \
1870   std::is_trivially_destructible<T>
1871 #else
1872 #define TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) \
1873   std::is_trivially_copy_constructible<T>
1874 #define TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(T) \
1875   std::is_trivially_copy_assignable<T>
1876 #define TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(T) \
1877   std::is_trivially_destructible<T>
1878 #endif
1879 
1880 #if __cplusplus > 201103L
1881 #define TL_EXPECTED_CXX14
1882 #endif
1883 
1884 #ifdef TL_EXPECTED_GCC49
1885 #define TL_EXPECTED_GCC49_CONSTEXPR
1886 #else
1887 #define TL_EXPECTED_GCC49_CONSTEXPR constexpr
1888 #endif
1889 
1890 #if (__cplusplus == 201103L || defined(TL_EXPECTED_MSVC2015) || \
1891      defined(TL_EXPECTED_GCC49))
1892 #define TL_EXPECTED_11_CONSTEXPR
1893 #else
1894 #define TL_EXPECTED_11_CONSTEXPR constexpr
1895 #endif
1896 
1897 namespace tl {
1898 template <class T, class E>
1899 class expected;
1900 
1901 #ifndef TL_MONOSTATE_INPLACE_MUTEX
1902 #define TL_MONOSTATE_INPLACE_MUTEX
1903 class monostate {};
1904 
1905 struct in_place_t {
1906   explicit in_place_t() = default;
1907 };
1908 static constexpr in_place_t in_place{};
1909 #endif
1910 
1911 template <class E>
1912 class unexpected {
1913  public:
1914   static_assert(!std::is_same<E, void>::value, "E must not be void");
1915 
1916   unexpected() = delete;
1917   constexpr explicit unexpected(const E &e) : m_val(e) {}
1918 
1919   constexpr explicit unexpected(E &&e) : m_val(std::move(e)) {}
1920 
1921   template <class... Args, typename std::enable_if<std::is_constructible<
1922                                E, Args &&...>::value>::type * = nullptr>
1923   constexpr explicit unexpected(Args &&...args)
1924       : m_val(std::forward<Args>(args)...) {}
1925   template <
1926       class U, class... Args,
1927       typename std::enable_if<std::is_constructible<
1928           E, std::initializer_list<U> &, Args &&...>::value>::type * = nullptr>
1929   constexpr explicit unexpected(std::initializer_list<U> l, Args &&...args)
1930       : m_val(l, std::forward<Args>(args)...) {}
1931 
1932   constexpr const E &value() const & { return m_val; }
1933   TL_EXPECTED_11_CONSTEXPR E &value() & { return m_val; }
1934   TL_EXPECTED_11_CONSTEXPR E &&value() && { return std::move(m_val); }
1935   constexpr const E &&value() const && { return std::move(m_val); }
1936 
1937  private:
1938   E m_val;
1939 };
1940 
1941 #ifdef __cpp_deduction_guides
1942 template <class E>
1943 unexpected(E) -> unexpected<E>;
1944 #endif
1945 
1946 template <class E>
1947 constexpr bool operator==(const unexpected<E> &lhs, const unexpected<E> &rhs) {
1948   return lhs.value() == rhs.value();
1949 }
1950 template <class E>
1951 constexpr bool operator!=(const unexpected<E> &lhs, const unexpected<E> &rhs) {
1952   return lhs.value() != rhs.value();
1953 }
1954 template <class E>
1955 constexpr bool operator<(const unexpected<E> &lhs, const unexpected<E> &rhs) {
1956   return lhs.value() < rhs.value();
1957 }
1958 template <class E>
1959 constexpr bool operator<=(const unexpected<E> &lhs, const unexpected<E> &rhs) {
1960   return lhs.value() <= rhs.value();
1961 }
1962 template <class E>
1963 constexpr bool operator>(const unexpected<E> &lhs, const unexpected<E> &rhs) {
1964   return lhs.value() > rhs.value();
1965 }
1966 template <class E>
1967 constexpr bool operator>=(const unexpected<E> &lhs, const unexpected<E> &rhs) {
1968   return lhs.value() >= rhs.value();
1969 }
1970 
1971 template <class E>
1972 unexpected<typename std::decay<E>::type> make_unexpected(E &&e) {
1973   return unexpected<typename std::decay<E>::type>(std::forward<E>(e));
1974 }
1975 
1976 struct unexpect_t {
1977   unexpect_t() = default;
1978 };
1979 static constexpr unexpect_t unexpect{};
1980 
1981 namespace detail {
1982 template <typename E>
1983 [[noreturn]] TL_EXPECTED_11_CONSTEXPR void throw_exception(E &&e) {
1984 #ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
1985   throw std::forward<E>(e);
1986 #else
1987   (void)e;
1988 #ifdef _MSC_VER
1989   __assume(0);
1990 #else
1991   __builtin_unreachable();
1992 #endif
1993 #endif
1994 }
1995 
1996 #ifndef TL_TRAITS_MUTEX
1997 #define TL_TRAITS_MUTEX
1998 // C++14-style aliases for brevity
1999 template <class T>
2000 using remove_const_t = typename std::remove_const<T>::type;
2001 template <class T>
2002 using remove_reference_t = typename std::remove_reference<T>::type;
2003 template <class T>
2004 using decay_t = typename std::decay<T>::type;
2005 template <bool E, class T = void>
2006 using enable_if_t = typename std::enable_if<E, T>::type;
2007 template <bool B, class T, class F>
2008 using conditional_t = typename std::conditional<B, T, F>::type;
2009 
2010 // std::conjunction from C++17
2011 template <class...>
2012 struct conjunction : std::true_type {};
2013 template <class B>
2014 struct conjunction<B> : B {};
2015 template <class B, class... Bs>
2016 struct conjunction<B, Bs...>
2017     : std::conditional<bool(B::value), conjunction<Bs...>, B>::type {};
2018 
2019 #if defined(_LIBCPP_VERSION) && __cplusplus == 201103L
2020 #define TL_TRAITS_LIBCXX_MEM_FN_WORKAROUND
2021 #endif
2022 
2023 // In C++11 mode, there's an issue in libc++'s std::mem_fn
2024 // which results in a hard-error when using it in a noexcept expression
2025 // in some cases. This is a check to workaround the common failing case.
2026 #ifdef TL_TRAITS_LIBCXX_MEM_FN_WORKAROUND
2027 template <class T>
2028 struct is_pointer_to_non_const_member_func : std::false_type {};
2029 template <class T, class Ret, class... Args>
2030 struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...)>
2031     : std::true_type {};
2032 template <class T, class Ret, class... Args>
2033 struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...) &>
2034     : std::true_type {};
2035 template <class T, class Ret, class... Args>
2036 struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...) &&>
2037     : std::true_type {};
2038 template <class T, class Ret, class... Args>
2039 struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...) volatile>
2040     : std::true_type {};
2041 template <class T, class Ret, class... Args>
2042 struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...) volatile &>
2043     : std::true_type {};
2044 template <class T, class Ret, class... Args>
2045 struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...) volatile &&>
2046     : std::true_type {};
2047 
2048 template <class T>
2049 struct is_const_or_const_ref : std::false_type {};
2050 template <class T>
2051 struct is_const_or_const_ref<T const &> : std::true_type {};
2052 template <class T>
2053 struct is_const_or_const_ref<T const> : std::true_type {};
2054 #endif
2055 
2056 // std::invoke from C++17
2057 // https://stackoverflow.com/questions/38288042/c11-14-invoke-workaround
2058 template <
2059     typename Fn, typename... Args,
2060 #ifdef TL_TRAITS_LIBCXX_MEM_FN_WORKAROUND
2061     typename = enable_if_t<!(is_pointer_to_non_const_member_func<Fn>::value &&
2062                              is_const_or_const_ref<Args...>::value)>,
2063 #endif
2064     typename = enable_if_t<std::is_member_pointer<decay_t<Fn>>::value>, int = 0>
2065 constexpr auto invoke(Fn &&f, Args &&...args) noexcept(
2066     noexcept(std::mem_fn(f)(std::forward<Args>(args)...)))
2067     -> decltype(std::mem_fn(f)(std::forward<Args>(args)...)) {
2068   return std::mem_fn(f)(std::forward<Args>(args)...);
2069 }
2070 
2071 template <typename Fn, typename... Args,
2072           typename = enable_if_t<!std::is_member_pointer<decay_t<Fn>>::value>>
2073 constexpr auto invoke(Fn &&f, Args &&...args) noexcept(
2074     noexcept(std::forward<Fn>(f)(std::forward<Args>(args)...)))
2075     -> decltype(std::forward<Fn>(f)(std::forward<Args>(args)...)) {
2076   return std::forward<Fn>(f)(std::forward<Args>(args)...);
2077 }
2078 
2079 // std::invoke_result from C++17
2080 template <class F, class, class... Us>
2081 struct invoke_result_impl;
2082 
2083 template <class F, class... Us>
2084 struct invoke_result_impl<
2085     F,
2086     decltype(detail::invoke(std::declval<F>(), std::declval<Us>()...), void()),
2087     Us...> {
2088   using type =
2089       decltype(detail::invoke(std::declval<F>(), std::declval<Us>()...));
2090 };
2091 
2092 template <class F, class... Us>
2093 using invoke_result = invoke_result_impl<F, void, Us...>;
2094 
2095 template <class F, class... Us>
2096 using invoke_result_t = typename invoke_result<F, Us...>::type;
2097 
2098 #if defined(_MSC_VER) && _MSC_VER <= 1900
2099 // TODO make a version which works with MSVC 2015
2100 template <class T, class U = T>
2101 struct is_swappable : std::true_type {};
2102 
2103 template <class T, class U = T>
2104 struct is_nothrow_swappable : std::true_type {};
2105 #else
2106 // https://stackoverflow.com/questions/26744589/what-is-a-proper-way-to-implement-is-swappable-to-test-for-the-swappable-concept
2107 namespace swap_adl_tests {
2108 // if swap ADL finds this then it would call std::swap otherwise (same
2109 // signature)
2110 struct tag {};
2111 
2112 template <class T>
2113 tag swap(T &, T &);
2114 template <class T, std::size_t N>
2115 tag swap(T (&a)[N], T (&b)[N]);
2116 
2117 // helper functions to test if an unqualified swap is possible, and if it
2118 // becomes std::swap
2119 template <class, class>
2120 std::false_type can_swap(...) noexcept(false);
2121 template <class T, class U,
2122           class = decltype(swap(std::declval<T &>(), std::declval<U &>()))>
2123 std::true_type can_swap(int) noexcept(noexcept(swap(std::declval<T &>(),
2124                                                     std::declval<U &>())));
2125 
2126 template <class, class>
2127 std::false_type uses_std(...);
2128 template <class T, class U>
2129 std::is_same<decltype(swap(std::declval<T &>(), std::declval<U &>())), tag>
2130 uses_std(int);
2131 
2132 template <class T>
2133 struct is_std_swap_noexcept
2134     : std::integral_constant<bool,
2135                              std::is_nothrow_move_constructible<T>::value &&
2136                                  std::is_nothrow_move_assignable<T>::value> {};
2137 
2138 template <class T, std::size_t N>
2139 struct is_std_swap_noexcept<T[N]> : is_std_swap_noexcept<T> {};
2140 
2141 template <class T, class U>
2142 struct is_adl_swap_noexcept
2143     : std::integral_constant<bool, noexcept(can_swap<T, U>(0))> {};
2144 }  // namespace swap_adl_tests
2145 
2146 template <class T, class U = T>
2147 struct is_swappable
2148     : std::integral_constant<
2149           bool,
2150           decltype(detail::swap_adl_tests::can_swap<T, U>(0))::value &&
2151               (!decltype(detail::swap_adl_tests::uses_std<T, U>(0))::value ||
2152                (std::is_move_assignable<T>::value &&
2153                 std::is_move_constructible<T>::value))> {};
2154 
2155 template <class T, std::size_t N>
2156 struct is_swappable<T[N], T[N]>
2157     : std::integral_constant<
2158           bool,
2159           decltype(detail::swap_adl_tests::can_swap<T[N], T[N]>(0))::value &&
2160               (!decltype(detail::swap_adl_tests::uses_std<T[N], T[N]>(
2161                    0))::value ||
2162                is_swappable<T, T>::value)> {};
2163 
2164 template <class T, class U = T>
2165 struct is_nothrow_swappable
2166     : std::integral_constant<
2167           bool,
2168           is_swappable<T, U>::value &&
2169               ((decltype(detail::swap_adl_tests::uses_std<T, U>(0))::value &&
2170                 detail::swap_adl_tests::is_std_swap_noexcept<T>::value) ||
2171                (!decltype(detail::swap_adl_tests::uses_std<T, U>(0))::value &&
2172                 detail::swap_adl_tests::is_adl_swap_noexcept<T, U>::value))> {};
2173 #endif
2174 #endif
2175 
2176 // Trait for checking if a type is a tl::expected
2177 template <class T>
2178 struct is_expected_impl : std::false_type {};
2179 template <class T, class E>
2180 struct is_expected_impl<expected<T, E>> : std::true_type {};
2181 template <class T>
2182 using is_expected = is_expected_impl<decay_t<T>>;
2183 
2184 template <class T, class E, class U>
2185 using expected_enable_forward_value = detail::enable_if_t<
2186     std::is_constructible<T, U &&>::value &&
2187     !std::is_same<detail::decay_t<U>, in_place_t>::value &&
2188     !std::is_same<expected<T, E>, detail::decay_t<U>>::value &&
2189     !std::is_same<unexpected<E>, detail::decay_t<U>>::value>;
2190 
2191 template <class T, class E, class U, class G, class UR, class GR>
2192 using expected_enable_from_other = detail::enable_if_t<
2193     std::is_constructible<T, UR>::value &&
2194     std::is_constructible<E, GR>::value &&
2195     !std::is_constructible<T, expected<U, G> &>::value &&
2196     !std::is_constructible<T, expected<U, G> &&>::value &&
2197     !std::is_constructible<T, const expected<U, G> &>::value &&
2198     !std::is_constructible<T, const expected<U, G> &&>::value &&
2199     !std::is_convertible<expected<U, G> &, T>::value &&
2200     !std::is_convertible<expected<U, G> &&, T>::value &&
2201     !std::is_convertible<const expected<U, G> &, T>::value &&
2202     !std::is_convertible<const expected<U, G> &&, T>::value>;
2203 
2204 template <class T, class U>
2205 using is_void_or = conditional_t<std::is_void<T>::value, std::true_type, U>;
2206 
2207 template <class T>
2208 using is_copy_constructible_or_void =
2209     is_void_or<T, std::is_copy_constructible<T>>;
2210 
2211 template <class T>
2212 using is_move_constructible_or_void =
2213     is_void_or<T, std::is_move_constructible<T>>;
2214 
2215 template <class T>
2216 using is_copy_assignable_or_void = is_void_or<T, std::is_copy_assignable<T>>;
2217 
2218 template <class T>
2219 using is_move_assignable_or_void = is_void_or<T, std::is_move_assignable<T>>;
2220 
2221 }  // namespace detail
2222 
2223 namespace detail {
2224 struct no_init_t {};
2225 static constexpr no_init_t no_init{};
2226 
2227 // Implements the storage of the values, and ensures that the destructor is
2228 // trivial if it can be.
2229 //
2230 // This specialization is for where neither `T` or `E` is trivially
2231 // destructible, so the destructors must be called on destruction of the
2232 // `expected`
2233 template <class T, class E, bool = std::is_trivially_destructible<T>::value,
2234           bool = std::is_trivially_destructible<E>::value>
2235 struct expected_storage_base {
2236   constexpr expected_storage_base() : m_val(T{}), m_has_val(true) {}
2237   constexpr expected_storage_base(no_init_t) : m_no_init(), m_has_val(false) {}
2238 
2239   template <class... Args,
2240             detail::enable_if_t<std::is_constructible<T, Args &&...>::value> * =
2241                 nullptr>
2242   constexpr expected_storage_base(in_place_t, Args &&...args)
2243       : m_val(std::forward<Args>(args)...), m_has_val(true) {}
2244 
2245   template <class U, class... Args,
2246             detail::enable_if_t<std::is_constructible<
2247                 T, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
2248   constexpr expected_storage_base(in_place_t, std::initializer_list<U> il,
2249                                   Args &&...args)
2250       : m_val(il, std::forward<Args>(args)...), m_has_val(true) {}
2251   template <class... Args,
2252             detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * =
2253                 nullptr>
2254   constexpr explicit expected_storage_base(unexpect_t, Args &&...args)
2255       : m_unexpect(std::forward<Args>(args)...), m_has_val(false) {}
2256 
2257   template <class U, class... Args,
2258             detail::enable_if_t<std::is_constructible<
2259                 E, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
2260   constexpr explicit expected_storage_base(unexpect_t,
2261                                            std::initializer_list<U> il,
2262                                            Args &&...args)
2263       : m_unexpect(il, std::forward<Args>(args)...), m_has_val(false) {}
2264 
2265   ~expected_storage_base() {
2266     if (m_has_val) {
2267       m_val.~T();
2268     } else {
2269       m_unexpect.~unexpected<E>();
2270     }
2271   }
2272   union {
2273     T m_val;
2274     unexpected<E> m_unexpect;
2275     char m_no_init;
2276   };
2277   bool m_has_val;
2278 };
2279 
2280 // This specialization is for when both `T` and `E` are trivially-destructible,
2281 // so the destructor of the `expected` can be trivial.
2282 template <class T, class E>
2283 struct expected_storage_base<T, E, true, true> {
2284   constexpr expected_storage_base() : m_val(T{}), m_has_val(true) {}
2285   constexpr expected_storage_base(no_init_t) : m_no_init(), m_has_val(false) {}
2286 
2287   template <class... Args,
2288             detail::enable_if_t<std::is_constructible<T, Args &&...>::value> * =
2289                 nullptr>
2290   constexpr expected_storage_base(in_place_t, Args &&...args)
2291       : m_val(std::forward<Args>(args)...), m_has_val(true) {}
2292 
2293   template <class U, class... Args,
2294             detail::enable_if_t<std::is_constructible<
2295                 T, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
2296   constexpr expected_storage_base(in_place_t, std::initializer_list<U> il,
2297                                   Args &&...args)
2298       : m_val(il, std::forward<Args>(args)...), m_has_val(true) {}
2299   template <class... Args,
2300             detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * =
2301                 nullptr>
2302   constexpr explicit expected_storage_base(unexpect_t, Args &&...args)
2303       : m_unexpect(std::forward<Args>(args)...), m_has_val(false) {}
2304 
2305   template <class U, class... Args,
2306             detail::enable_if_t<std::is_constructible<
2307                 E, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
2308   constexpr explicit expected_storage_base(unexpect_t,
2309                                            std::initializer_list<U> il,
2310                                            Args &&...args)
2311       : m_unexpect(il, std::forward<Args>(args)...), m_has_val(false) {}
2312 
2313   ~expected_storage_base() = default;
2314   union {
2315     T m_val;
2316     unexpected<E> m_unexpect;
2317     char m_no_init;
2318   };
2319   bool m_has_val;
2320 };
2321 
2322 // T is trivial, E is not.
2323 template <class T, class E>
2324 struct expected_storage_base<T, E, true, false> {
2325   constexpr expected_storage_base() : m_val(T{}), m_has_val(true) {}
2326   TL_EXPECTED_MSVC2015_CONSTEXPR expected_storage_base(no_init_t)
2327       : m_no_init(), m_has_val(false) {}
2328 
2329   template <class... Args,
2330             detail::enable_if_t<std::is_constructible<T, Args &&...>::value> * =
2331                 nullptr>
2332   constexpr expected_storage_base(in_place_t, Args &&...args)
2333       : m_val(std::forward<Args>(args)...), m_has_val(true) {}
2334 
2335   template <class U, class... Args,
2336             detail::enable_if_t<std::is_constructible<
2337                 T, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
2338   constexpr expected_storage_base(in_place_t, std::initializer_list<U> il,
2339                                   Args &&...args)
2340       : m_val(il, std::forward<Args>(args)...), m_has_val(true) {}
2341   template <class... Args,
2342             detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * =
2343                 nullptr>
2344   constexpr explicit expected_storage_base(unexpect_t, Args &&...args)
2345       : m_unexpect(std::forward<Args>(args)...), m_has_val(false) {}
2346 
2347   template <class U, class... Args,
2348             detail::enable_if_t<std::is_constructible<
2349                 E, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
2350   constexpr explicit expected_storage_base(unexpect_t,
2351                                            std::initializer_list<U> il,
2352                                            Args &&...args)
2353       : m_unexpect(il, std::forward<Args>(args)...), m_has_val(false) {}
2354 
2355   ~expected_storage_base() {
2356     if (!m_has_val) {
2357       m_unexpect.~unexpected<E>();
2358     }
2359   }
2360 
2361   union {
2362     T m_val;
2363     unexpected<E> m_unexpect;
2364     char m_no_init;
2365   };
2366   bool m_has_val;
2367 };
2368 
2369 // E is trivial, T is not.
2370 template <class T, class E>
2371 struct expected_storage_base<T, E, false, true> {
2372   constexpr expected_storage_base() : m_val(T{}), m_has_val(true) {}
2373   constexpr expected_storage_base(no_init_t) : m_no_init(), m_has_val(false) {}
2374 
2375   template <class... Args,
2376             detail::enable_if_t<std::is_constructible<T, Args &&...>::value> * =
2377                 nullptr>
2378   constexpr expected_storage_base(in_place_t, Args &&...args)
2379       : m_val(std::forward<Args>(args)...), m_has_val(true) {}
2380 
2381   template <class U, class... Args,
2382             detail::enable_if_t<std::is_constructible<
2383                 T, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
2384   constexpr expected_storage_base(in_place_t, std::initializer_list<U> il,
2385                                   Args &&...args)
2386       : m_val(il, std::forward<Args>(args)...), m_has_val(true) {}
2387   template <class... Args,
2388             detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * =
2389                 nullptr>
2390   constexpr explicit expected_storage_base(unexpect_t, Args &&...args)
2391       : m_unexpect(std::forward<Args>(args)...), m_has_val(false) {}
2392 
2393   template <class U, class... Args,
2394             detail::enable_if_t<std::is_constructible<
2395                 E, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
2396   constexpr explicit expected_storage_base(unexpect_t,
2397                                            std::initializer_list<U> il,
2398                                            Args &&...args)
2399       : m_unexpect(il, std::forward<Args>(args)...), m_has_val(false) {}
2400 
2401   ~expected_storage_base() {
2402     if (m_has_val) {
2403       m_val.~T();
2404     }
2405   }
2406   union {
2407     T m_val;
2408     unexpected<E> m_unexpect;
2409     char m_no_init;
2410   };
2411   bool m_has_val;
2412 };
2413 
2414 // `T` is `void`, `E` is trivially-destructible
2415 template <class E>
2416 struct expected_storage_base<void, E, false, true> {
2417 #if __GNUC__ <= 5
2418 // no constexpr for GCC 4/5 bug
2419 #else
2420   TL_EXPECTED_MSVC2015_CONSTEXPR
2421 #endif
2422   expected_storage_base() : m_has_val(true) {}
2423 
2424   constexpr expected_storage_base(no_init_t) : m_val(), m_has_val(false) {}
2425 
2426   constexpr expected_storage_base(in_place_t) : m_has_val(true) {}
2427 
2428   template <class... Args,
2429             detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * =
2430                 nullptr>
2431   constexpr explicit expected_storage_base(unexpect_t, Args &&...args)
2432       : m_unexpect(std::forward<Args>(args)...), m_has_val(false) {}
2433 
2434   template <class U, class... Args,
2435             detail::enable_if_t<std::is_constructible<
2436                 E, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
2437   constexpr explicit expected_storage_base(unexpect_t,
2438                                            std::initializer_list<U> il,
2439                                            Args &&...args)
2440       : m_unexpect(il, std::forward<Args>(args)...), m_has_val(false) {}
2441 
2442   ~expected_storage_base() = default;
2443   struct dummy {};
2444   union {
2445     unexpected<E> m_unexpect;
2446     dummy m_val;
2447   };
2448   bool m_has_val;
2449 };
2450 
2451 // `T` is `void`, `E` is not trivially-destructible
2452 template <class E>
2453 struct expected_storage_base<void, E, false, false> {
2454   constexpr expected_storage_base() : m_dummy(), m_has_val(true) {}
2455   constexpr expected_storage_base(no_init_t) : m_dummy(), m_has_val(false) {}
2456 
2457   constexpr expected_storage_base(in_place_t) : m_dummy(), m_has_val(true) {}
2458 
2459   template <class... Args,
2460             detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * =
2461                 nullptr>
2462   constexpr explicit expected_storage_base(unexpect_t, Args &&...args)
2463       : m_unexpect(std::forward<Args>(args)...), m_has_val(false) {}
2464 
2465   template <class U, class... Args,
2466             detail::enable_if_t<std::is_constructible<
2467                 E, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
2468   constexpr explicit expected_storage_base(unexpect_t,
2469                                            std::initializer_list<U> il,
2470                                            Args &&...args)
2471       : m_unexpect(il, std::forward<Args>(args)...), m_has_val(false) {}
2472 
2473   ~expected_storage_base() {
2474     if (!m_has_val) {
2475       m_unexpect.~unexpected<E>();
2476     }
2477   }
2478 
2479   union {
2480     unexpected<E> m_unexpect;
2481     char m_dummy;
2482   };
2483   bool m_has_val;
2484 };
2485 
2486 // This base class provides some handy member functions which can be used in
2487 // further derived classes
2488 template <class T, class E>
2489 struct expected_operations_base : expected_storage_base<T, E> {
2490   using expected_storage_base<T, E>::expected_storage_base;
2491 
2492   template <class... Args>
2493   void construct(Args &&...args) noexcept {
2494     new (std::addressof(this->m_val)) T(std::forward<Args>(args)...);
2495     this->m_has_val = true;
2496   }
2497 
2498   template <class Rhs>
2499   void construct_with(Rhs &&rhs) noexcept {
2500     new (std::addressof(this->m_val)) T(std::forward<Rhs>(rhs).get());
2501     this->m_has_val = true;
2502   }
2503 
2504   template <class... Args>
2505   void construct_error(Args &&...args) noexcept {
2506     new (std::addressof(this->m_unexpect))
2507         unexpected<E>(std::forward<Args>(args)...);
2508     this->m_has_val = false;
2509   }
2510 
2511 #ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
2512 
2513   // These assign overloads ensure that the most efficient assignment
2514   // implementation is used while maintaining the strong exception guarantee.
2515   // The problematic case is where rhs has a value, but *this does not.
2516   //
2517   // This overload handles the case where we can just copy-construct `T`
2518   // directly into place without throwing.
2519   template <class U = T,
2520             detail::enable_if_t<std::is_nothrow_copy_constructible<U>::value>
2521                 * = nullptr>
2522   void assign(const expected_operations_base &rhs) noexcept {
2523     if (!this->m_has_val && rhs.m_has_val) {
2524       geterr().~unexpected<E>();
2525       construct(rhs.get());
2526     } else {
2527       assign_common(rhs);
2528     }
2529   }
2530 
2531   // This overload handles the case where we can attempt to create a copy of
2532   // `T`, then no-throw move it into place if the copy was successful.
2533   template <class U = T,
2534             detail::enable_if_t<!std::is_nothrow_copy_constructible<U>::value &&
2535                                 std::is_nothrow_move_constructible<U>::value>
2536                 * = nullptr>
2537   void assign(const expected_operations_base &rhs) noexcept {
2538     if (!this->m_has_val && rhs.m_has_val) {
2539       T tmp = rhs.get();
2540       geterr().~unexpected<E>();
2541       construct(std::move(tmp));
2542     } else {
2543       assign_common(rhs);
2544     }
2545   }
2546 
2547   // This overload is the worst-case, where we have to move-construct the
2548   // unexpected value into temporary storage, then try to copy the T into place.
2549   // If the construction succeeds, then everything is fine, but if it throws,
2550   // then we move the old unexpected value back into place before rethrowing the
2551   // exception.
2552   template <class U = T,
2553             detail::enable_if_t<!std::is_nothrow_copy_constructible<U>::value &&
2554                                 !std::is_nothrow_move_constructible<U>::value>
2555                 * = nullptr>
2556   void assign(const expected_operations_base &rhs) {
2557     if (!this->m_has_val && rhs.m_has_val) {
2558       auto tmp = std::move(geterr());
2559       geterr().~unexpected<E>();
2560 
2561 #ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
2562       try {
2563         construct(rhs.get());
2564       } catch (...) {
2565         geterr() = std::move(tmp);
2566         throw;
2567       }
2568 #else
2569       construct(rhs.get());
2570 #endif
2571     } else {
2572       assign_common(rhs);
2573     }
2574   }
2575 
2576   // These overloads do the same as above, but for rvalues
2577   template <class U = T,
2578             detail::enable_if_t<std::is_nothrow_move_constructible<U>::value>
2579                 * = nullptr>
2580   void assign(expected_operations_base &&rhs) noexcept {
2581     if (!this->m_has_val && rhs.m_has_val) {
2582       geterr().~unexpected<E>();
2583       construct(std::move(rhs).get());
2584     } else {
2585       assign_common(std::move(rhs));
2586     }
2587   }
2588 
2589   template <class U = T,
2590             detail::enable_if_t<!std::is_nothrow_move_constructible<U>::value>
2591                 * = nullptr>
2592   void assign(expected_operations_base &&rhs) {
2593     if (!this->m_has_val && rhs.m_has_val) {
2594       auto tmp = std::move(geterr());
2595       geterr().~unexpected<E>();
2596 #ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
2597       try {
2598         construct(std::move(rhs).get());
2599       } catch (...) {
2600         geterr() = std::move(tmp);
2601         throw;
2602       }
2603 #else
2604       construct(std::move(rhs).get());
2605 #endif
2606     } else {
2607       assign_common(std::move(rhs));
2608     }
2609   }
2610 
2611 #else
2612 
2613   // If exceptions are disabled then we can just copy-construct
2614   void assign(const expected_operations_base &rhs) noexcept {
2615     if (!this->m_has_val && rhs.m_has_val) {
2616       geterr().~unexpected<E>();
2617       construct(rhs.get());
2618     } else {
2619       assign_common(rhs);
2620     }
2621   }
2622 
2623   void assign(expected_operations_base &&rhs) noexcept {
2624     if (!this->m_has_val && rhs.m_has_val) {
2625       geterr().~unexpected<E>();
2626       construct(std::move(rhs).get());
2627     } else {
2628       assign_common(std::move(rhs));
2629     }
2630   }
2631 
2632 #endif
2633 
2634   // The common part of move/copy assigning
2635   template <class Rhs>
2636   void assign_common(Rhs &&rhs) {
2637     if (this->m_has_val) {
2638       if (rhs.m_has_val) {
2639         get() = std::forward<Rhs>(rhs).get();
2640       } else {
2641         destroy_val();
2642         construct_error(std::forward<Rhs>(rhs).geterr());
2643       }
2644     } else {
2645       if (!rhs.m_has_val) {
2646         geterr() = std::forward<Rhs>(rhs).geterr();
2647       }
2648     }
2649   }
2650 
2651   bool has_value() const { return this->m_has_val; }
2652 
2653   TL_EXPECTED_11_CONSTEXPR T &get() & { return this->m_val; }
2654   constexpr const T &get() const & { return this->m_val; }
2655   TL_EXPECTED_11_CONSTEXPR T &&get() && { return std::move(this->m_val); }
2656 #ifndef TL_EXPECTED_NO_CONSTRR
2657   constexpr const T &&get() const && { return std::move(this->m_val); }
2658 #endif
2659 
2660   TL_EXPECTED_11_CONSTEXPR unexpected<E> &geterr() & {
2661     return this->m_unexpect;
2662   }
2663   constexpr const unexpected<E> &geterr() const & { return this->m_unexpect; }
2664   TL_EXPECTED_11_CONSTEXPR unexpected<E> &&geterr() && {
2665     return std::move(this->m_unexpect);
2666   }
2667 #ifndef TL_EXPECTED_NO_CONSTRR
2668   constexpr const unexpected<E> &&geterr() const && {
2669     return std::move(this->m_unexpect);
2670   }
2671 #endif
2672 
2673   TL_EXPECTED_11_CONSTEXPR void destroy_val() { get().~T(); }
2674 };
2675 
2676 // This base class provides some handy member functions which can be used in
2677 // further derived classes
2678 template <class E>
2679 struct expected_operations_base<void, E> : expected_storage_base<void, E> {
2680   using expected_storage_base<void, E>::expected_storage_base;
2681 
2682   template <class... Args>
2683   void construct() noexcept {
2684     this->m_has_val = true;
2685   }
2686 
2687   // This function doesn't use its argument, but needs it so that code in
2688   // levels above this can work independently of whether T is void
2689   template <class Rhs>
2690   void construct_with(Rhs &&) noexcept {
2691     this->m_has_val = true;
2692   }
2693 
2694   template <class... Args>
2695   void construct_error(Args &&...args) noexcept {
2696     new (std::addressof(this->m_unexpect))
2697         unexpected<E>(std::forward<Args>(args)...);
2698     this->m_has_val = false;
2699   }
2700 
2701   template <class Rhs>
2702   void assign(Rhs &&rhs) noexcept {
2703     if (!this->m_has_val) {
2704       if (rhs.m_has_val) {
2705         geterr().~unexpected<E>();
2706         construct();
2707       } else {
2708         geterr() = std::forward<Rhs>(rhs).geterr();
2709       }
2710     } else {
2711       if (!rhs.m_has_val) {
2712         construct_error(std::forward<Rhs>(rhs).geterr());
2713       }
2714     }
2715   }
2716 
2717   bool has_value() const { return this->m_has_val; }
2718 
2719   TL_EXPECTED_11_CONSTEXPR unexpected<E> &geterr() & {
2720     return this->m_unexpect;
2721   }
2722   constexpr const unexpected<E> &geterr() const & { return this->m_unexpect; }
2723   TL_EXPECTED_11_CONSTEXPR unexpected<E> &&geterr() && {
2724     return std::move(this->m_unexpect);
2725   }
2726 #ifndef TL_EXPECTED_NO_CONSTRR
2727   constexpr const unexpected<E> &&geterr() const && {
2728     return std::move(this->m_unexpect);
2729   }
2730 #endif
2731 
2732   TL_EXPECTED_11_CONSTEXPR void destroy_val() {
2733     // no-op
2734   }
2735 };
2736 
2737 // This class manages conditionally having a trivial copy constructor
2738 // This specialization is for when T and E are trivially copy constructible
2739 template <class T, class E,
2740           bool = is_void_or<T, TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T)>::
2741               value &&TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(E)::value>
2742 struct expected_copy_base : expected_operations_base<T, E> {
2743   using expected_operations_base<T, E>::expected_operations_base;
2744 };
2745 
2746 // This specialization is for when T or E are not trivially copy constructible
2747 template <class T, class E>
2748 struct expected_copy_base<T, E, false> : expected_operations_base<T, E> {
2749   using expected_operations_base<T, E>::expected_operations_base;
2750 
2751   expected_copy_base() = default;
2752   expected_copy_base(const expected_copy_base &rhs)
2753       : expected_operations_base<T, E>(no_init) {
2754     if (rhs.has_value()) {
2755       this->construct_with(rhs);
2756     } else {
2757       this->construct_error(rhs.geterr());
2758     }
2759   }
2760 
2761   expected_copy_base(expected_copy_base &&rhs) = default;
2762   expected_copy_base &operator=(const expected_copy_base &rhs) = default;
2763   expected_copy_base &operator=(expected_copy_base &&rhs) = default;
2764 };
2765 
2766 // This class manages conditionally having a trivial move constructor
2767 // Unfortunately there's no way to achieve this in GCC < 5 AFAIK, since it
2768 // doesn't implement an analogue to std::is_trivially_move_constructible. We
2769 // have to make do with a non-trivial move constructor even if T is trivially
2770 // move constructible
2771 #ifndef TL_EXPECTED_GCC49
2772 template <class T, class E,
2773           bool = is_void_or<T, std::is_trivially_move_constructible<T>>::value
2774               &&std::is_trivially_move_constructible<E>::value>
2775 struct expected_move_base : expected_copy_base<T, E> {
2776   using expected_copy_base<T, E>::expected_copy_base;
2777 };
2778 #else
2779 template <class T, class E, bool = false>
2780 struct expected_move_base;
2781 #endif
2782 template <class T, class E>
2783 struct expected_move_base<T, E, false> : expected_copy_base<T, E> {
2784   using expected_copy_base<T, E>::expected_copy_base;
2785 
2786   expected_move_base() = default;
2787   expected_move_base(const expected_move_base &rhs) = default;
2788 
2789   expected_move_base(expected_move_base &&rhs) noexcept(
2790       std::is_nothrow_move_constructible<T>::value)
2791       : expected_copy_base<T, E>(no_init) {
2792     if (rhs.has_value()) {
2793       this->construct_with(std::move(rhs));
2794     } else {
2795       this->construct_error(std::move(rhs.geterr()));
2796     }
2797   }
2798   expected_move_base &operator=(const expected_move_base &rhs) = default;
2799   expected_move_base &operator=(expected_move_base &&rhs) = default;
2800 };
2801 
2802 // This class manages conditionally having a trivial copy assignment operator
2803 template <class T, class E,
2804           bool = is_void_or<
2805               T, conjunction<TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(T),
2806                              TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T),
2807                              TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(T)>>::value
2808               &&TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(E)::value
2809                   &&TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(E)::value
2810                       &&TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(E)::value>
2811 struct expected_copy_assign_base : expected_move_base<T, E> {
2812   using expected_move_base<T, E>::expected_move_base;
2813 };
2814 
2815 template <class T, class E>
2816 struct expected_copy_assign_base<T, E, false> : expected_move_base<T, E> {
2817   using expected_move_base<T, E>::expected_move_base;
2818 
2819   expected_copy_assign_base() = default;
2820   expected_copy_assign_base(const expected_copy_assign_base &rhs) = default;
2821 
2822   expected_copy_assign_base(expected_copy_assign_base &&rhs) = default;
2823   expected_copy_assign_base &operator=(const expected_copy_assign_base &rhs) {
2824     this->assign(rhs);
2825     return *this;
2826   }
2827   expected_copy_assign_base &operator=(expected_copy_assign_base &&rhs) =
2828       default;
2829 };
2830 
2831 // This class manages conditionally having a trivial move assignment operator
2832 // Unfortunately there's no way to achieve this in GCC < 5 AFAIK, since it
2833 // doesn't implement an analogue to std::is_trivially_move_assignable. We have
2834 // to make do with a non-trivial move assignment operator even if T is trivially
2835 // move assignable
2836 #ifndef TL_EXPECTED_GCC49
2837 template <class T, class E,
2838           bool =
2839               is_void_or<T, conjunction<std::is_trivially_destructible<T>,
2840                                         std::is_trivially_move_constructible<T>,
2841                                         std::is_trivially_move_assignable<T>>>::
2842                   value &&std::is_trivially_destructible<E>::value
2843                       &&std::is_trivially_move_constructible<E>::value
2844                           &&std::is_trivially_move_assignable<E>::value>
2845 struct expected_move_assign_base : expected_copy_assign_base<T, E> {
2846   using expected_copy_assign_base<T, E>::expected_copy_assign_base;
2847 };
2848 #else
2849 template <class T, class E, bool = false>
2850 struct expected_move_assign_base;
2851 #endif
2852 
2853 template <class T, class E>
2854 struct expected_move_assign_base<T, E, false>
2855     : expected_copy_assign_base<T, E> {
2856   using expected_copy_assign_base<T, E>::expected_copy_assign_base;
2857 
2858   expected_move_assign_base() = default;
2859   expected_move_assign_base(const expected_move_assign_base &rhs) = default;
2860 
2861   expected_move_assign_base(expected_move_assign_base &&rhs) = default;
2862 
2863   expected_move_assign_base &operator=(const expected_move_assign_base &rhs) =
2864       default;
2865 
2866   expected_move_assign_base &
2867   operator=(expected_move_assign_base &&rhs) noexcept(
2868       std::is_nothrow_move_constructible<T>::value
2869           &&std::is_nothrow_move_assignable<T>::value) {
2870     this->assign(std::move(rhs));
2871     return *this;
2872   }
2873 };
2874 
2875 // expected_delete_ctor_base will conditionally delete copy and move
2876 // constructors depending on whether T is copy/move constructible
2877 template <class T, class E,
2878           bool EnableCopy = (is_copy_constructible_or_void<T>::value &&
2879                              std::is_copy_constructible<E>::value),
2880           bool EnableMove = (is_move_constructible_or_void<T>::value &&
2881                              std::is_move_constructible<E>::value)>
2882 struct expected_delete_ctor_base {
2883   expected_delete_ctor_base() = default;
2884   expected_delete_ctor_base(const expected_delete_ctor_base &) = default;
2885   expected_delete_ctor_base(expected_delete_ctor_base &&) noexcept = default;
2886   expected_delete_ctor_base &operator=(const expected_delete_ctor_base &) =
2887       default;
2888   expected_delete_ctor_base &operator=(expected_delete_ctor_base &&) noexcept =
2889       default;
2890 };
2891 
2892 template <class T, class E>
2893 struct expected_delete_ctor_base<T, E, true, false> {
2894   expected_delete_ctor_base() = default;
2895   expected_delete_ctor_base(const expected_delete_ctor_base &) = default;
2896   expected_delete_ctor_base(expected_delete_ctor_base &&) noexcept = delete;
2897   expected_delete_ctor_base &operator=(const expected_delete_ctor_base &) =
2898       default;
2899   expected_delete_ctor_base &operator=(expected_delete_ctor_base &&) noexcept =
2900       default;
2901 };
2902 
2903 template <class T, class E>
2904 struct expected_delete_ctor_base<T, E, false, true> {
2905   expected_delete_ctor_base() = default;
2906   expected_delete_ctor_base(const expected_delete_ctor_base &) = delete;
2907   expected_delete_ctor_base(expected_delete_ctor_base &&) noexcept = default;
2908   expected_delete_ctor_base &operator=(const expected_delete_ctor_base &) =
2909       default;
2910   expected_delete_ctor_base &operator=(expected_delete_ctor_base &&) noexcept =
2911       default;
2912 };
2913 
2914 template <class T, class E>
2915 struct expected_delete_ctor_base<T, E, false, false> {
2916   expected_delete_ctor_base() = default;
2917   expected_delete_ctor_base(const expected_delete_ctor_base &) = delete;
2918   expected_delete_ctor_base(expected_delete_ctor_base &&) noexcept = delete;
2919   expected_delete_ctor_base &operator=(const expected_delete_ctor_base &) =
2920       default;
2921   expected_delete_ctor_base &operator=(expected_delete_ctor_base &&) noexcept =
2922       default;
2923 };
2924 
2925 // expected_delete_assign_base will conditionally delete copy and move
2926 // constructors depending on whether T and E are copy/move constructible +
2927 // assignable
2928 template <class T, class E,
2929           bool EnableCopy = (is_copy_constructible_or_void<T>::value &&
2930                              std::is_copy_constructible<E>::value &&
2931                              is_copy_assignable_or_void<T>::value &&
2932                              std::is_copy_assignable<E>::value),
2933           bool EnableMove = (is_move_constructible_or_void<T>::value &&
2934                              std::is_move_constructible<E>::value &&
2935                              is_move_assignable_or_void<T>::value &&
2936                              std::is_move_assignable<E>::value)>
2937 struct expected_delete_assign_base {
2938   expected_delete_assign_base() = default;
2939   expected_delete_assign_base(const expected_delete_assign_base &) = default;
2940   expected_delete_assign_base(expected_delete_assign_base &&) noexcept =
2941       default;
2942   expected_delete_assign_base &operator=(const expected_delete_assign_base &) =
2943       default;
2944   expected_delete_assign_base &operator=(
2945       expected_delete_assign_base &&) noexcept = default;
2946 };
2947 
2948 template <class T, class E>
2949 struct expected_delete_assign_base<T, E, true, false> {
2950   expected_delete_assign_base() = default;
2951   expected_delete_assign_base(const expected_delete_assign_base &) = default;
2952   expected_delete_assign_base(expected_delete_assign_base &&) noexcept =
2953       default;
2954   expected_delete_assign_base &operator=(const expected_delete_assign_base &) =
2955       default;
2956   expected_delete_assign_base &operator=(
2957       expected_delete_assign_base &&) noexcept = delete;
2958 };
2959 
2960 template <class T, class E>
2961 struct expected_delete_assign_base<T, E, false, true> {
2962   expected_delete_assign_base() = default;
2963   expected_delete_assign_base(const expected_delete_assign_base &) = default;
2964   expected_delete_assign_base(expected_delete_assign_base &&) noexcept =
2965       default;
2966   expected_delete_assign_base &operator=(const expected_delete_assign_base &) =
2967       delete;
2968   expected_delete_assign_base &operator=(
2969       expected_delete_assign_base &&) noexcept = default;
2970 };
2971 
2972 template <class T, class E>
2973 struct expected_delete_assign_base<T, E, false, false> {
2974   expected_delete_assign_base() = default;
2975   expected_delete_assign_base(const expected_delete_assign_base &) = default;
2976   expected_delete_assign_base(expected_delete_assign_base &&) noexcept =
2977       default;
2978   expected_delete_assign_base &operator=(const expected_delete_assign_base &) =
2979       delete;
2980   expected_delete_assign_base &operator=(
2981       expected_delete_assign_base &&) noexcept = delete;
2982 };
2983 
2984 // This is needed to be able to construct the expected_default_ctor_base which
2985 // follows, while still conditionally deleting the default constructor.
2986 struct default_constructor_tag {
2987   explicit constexpr default_constructor_tag() = default;
2988 };
2989 
2990 // expected_default_ctor_base will ensure that expected has a deleted default
2991 // consturctor if T is not default constructible.
2992 // This specialization is for when T is default constructible
2993 template <class T, class E,
2994           bool Enable =
2995               std::is_default_constructible<T>::value || std::is_void<T>::value>
2996 struct expected_default_ctor_base {
2997   constexpr expected_default_ctor_base() noexcept = default;
2998   constexpr expected_default_ctor_base(
2999       expected_default_ctor_base const &) noexcept = default;
3000   constexpr expected_default_ctor_base(expected_default_ctor_base &&) noexcept =
3001       default;
3002   expected_default_ctor_base &operator=(
3003       expected_default_ctor_base const &) noexcept = default;
3004   expected_default_ctor_base &operator=(
3005       expected_default_ctor_base &&) noexcept = default;
3006 
3007   constexpr explicit expected_default_ctor_base(default_constructor_tag) {}
3008 };
3009 
3010 // This specialization is for when T is not default constructible
3011 template <class T, class E>
3012 struct expected_default_ctor_base<T, E, false> {
3013   constexpr expected_default_ctor_base() noexcept = delete;
3014   constexpr expected_default_ctor_base(
3015       expected_default_ctor_base const &) noexcept = default;
3016   constexpr expected_default_ctor_base(expected_default_ctor_base &&) noexcept =
3017       default;
3018   expected_default_ctor_base &operator=(
3019       expected_default_ctor_base const &) noexcept = default;
3020   expected_default_ctor_base &operator=(
3021       expected_default_ctor_base &&) noexcept = default;
3022 
3023   constexpr explicit expected_default_ctor_base(default_constructor_tag) {}
3024 };
3025 }  // namespace detail
3026 
3027 template <class E>
3028 class bad_expected_access : public std::exception {
3029  public:
3030   explicit bad_expected_access(E e) : m_val(std::move(e)) {}
3031 
3032   virtual const char *what() const noexcept override {
3033     return "Bad expected access";
3034   }
3035 
3036   const E &error() const & { return m_val; }
3037   E &error() & { return m_val; }
3038   const E &&error() const && { return std::move(m_val); }
3039   E &&error() && { return std::move(m_val); }
3040 
3041  private:
3042   E m_val;
3043 };
3044 
3045 /// An `expected<T, E>` object is an object that contains the storage for
3046 /// another object and manages the lifetime of this contained object `T`.
3047 /// Alternatively it could contain the storage for another unexpected object
3048 /// `E`. The contained object may not be initialized after the expected object
3049 /// has been initialized, and may not be destroyed before the expected object
3050 /// has been destroyed. The initialization state of the contained object is
3051 /// tracked by the expected object.
3052 template <class T, class E>
3053 class expected : private detail::expected_move_assign_base<T, E>,
3054                  private detail::expected_delete_ctor_base<T, E>,
3055                  private detail::expected_delete_assign_base<T, E>,
3056                  private detail::expected_default_ctor_base<T, E> {
3057   static_assert(!std::is_reference<T>::value, "T must not be a reference");
3058   static_assert(!std::is_same<T, std::remove_cv<in_place_t>::type>::value,
3059                 "T must not be in_place_t");
3060   static_assert(!std::is_same<T, std::remove_cv<unexpect_t>::type>::value,
3061                 "T must not be unexpect_t");
3062   static_assert(
3063       !std::is_same<T, typename std::remove_cv<unexpected<E>>::type>::value,
3064       "T must not be unexpected<E>");
3065   static_assert(!std::is_reference<E>::value, "E must not be a reference");
3066 
3067   T *valptr() { return std::addressof(this->m_val); }
3068   const T *valptr() const { return std::addressof(this->m_val); }
3069   unexpected<E> *errptr() { return std::addressof(this->m_unexpect); }
3070   const unexpected<E> *errptr() const {
3071     return std::addressof(this->m_unexpect);
3072   }
3073 
3074   template <class U = T,
3075             detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
3076   TL_EXPECTED_11_CONSTEXPR U &val() {
3077     return this->m_val;
3078   }
3079   TL_EXPECTED_11_CONSTEXPR unexpected<E> &err() { return this->m_unexpect; }
3080 
3081   template <class U = T,
3082             detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
3083   constexpr const U &val() const {
3084     return this->m_val;
3085   }
3086   constexpr const unexpected<E> &err() const { return this->m_unexpect; }
3087 
3088   using impl_base = detail::expected_move_assign_base<T, E>;
3089   using ctor_base = detail::expected_default_ctor_base<T, E>;
3090 
3091  public:
3092   typedef T value_type;
3093   typedef E error_type;
3094   typedef unexpected<E> unexpected_type;
3095 
3096 #if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \
3097     !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55)
3098   template <class F>
3099   TL_EXPECTED_11_CONSTEXPR auto and_then(F &&f) & {
3100     return and_then_impl(*this, std::forward<F>(f));
3101   }
3102   template <class F>
3103   TL_EXPECTED_11_CONSTEXPR auto and_then(F &&f) && {
3104     return and_then_impl(std::move(*this), std::forward<F>(f));
3105   }
3106   template <class F>
3107   constexpr auto and_then(F &&f) const & {
3108     return and_then_impl(*this, std::forward<F>(f));
3109   }
3110 
3111 #ifndef TL_EXPECTED_NO_CONSTRR
3112   template <class F>
3113   constexpr auto and_then(F &&f) const && {
3114     return and_then_impl(std::move(*this), std::forward<F>(f));
3115   }
3116 #endif
3117 
3118 #else
3119   template <class F>
3120   TL_EXPECTED_11_CONSTEXPR auto and_then(F &&f) & -> decltype(and_then_impl(
3121       std::declval<expected &>(), std::forward<F>(f))) {
3122     return and_then_impl(*this, std::forward<F>(f));
3123   }
3124   template <class F>
3125   TL_EXPECTED_11_CONSTEXPR auto and_then(F &&f) && -> decltype(and_then_impl(
3126       std::declval<expected &&>(), std::forward<F>(f))) {
3127     return and_then_impl(std::move(*this), std::forward<F>(f));
3128   }
3129   template <class F>
3130   constexpr auto and_then(F &&f) const & -> decltype(and_then_impl(
3131       std::declval<expected const &>(), std::forward<F>(f))) {
3132     return and_then_impl(*this, std::forward<F>(f));
3133   }
3134 
3135 #ifndef TL_EXPECTED_NO_CONSTRR
3136   template <class F>
3137   constexpr auto and_then(F &&f) const && -> decltype(and_then_impl(
3138       std::declval<expected const &&>(), std::forward<F>(f))) {
3139     return and_then_impl(std::move(*this), std::forward<F>(f));
3140   }
3141 #endif
3142 #endif
3143 
3144 #if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \
3145     !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55)
3146   template <class F>
3147   TL_EXPECTED_11_CONSTEXPR auto map(F &&f) & {
3148     return expected_map_impl(*this, std::forward<F>(f));
3149   }
3150   template <class F>
3151   TL_EXPECTED_11_CONSTEXPR auto map(F &&f) && {
3152     return expected_map_impl(std::move(*this), std::forward<F>(f));
3153   }
3154   template <class F>
3155   constexpr auto map(F &&f) const & {
3156     return expected_map_impl(*this, std::forward<F>(f));
3157   }
3158   template <class F>
3159   constexpr auto map(F &&f) const && {
3160     return expected_map_impl(std::move(*this), std::forward<F>(f));
3161   }
3162 #else
3163   template <class F>
3164   TL_EXPECTED_11_CONSTEXPR decltype(expected_map_impl(
3165       std::declval<expected &>(), std::declval<F &&>()))
3166   map(F &&f) & {
3167     return expected_map_impl(*this, std::forward<F>(f));
3168   }
3169   template <class F>
3170   TL_EXPECTED_11_CONSTEXPR decltype(expected_map_impl(std::declval<expected>(),
3171                                                       std::declval<F &&>()))
3172   map(F &&f) && {
3173     return expected_map_impl(std::move(*this), std::forward<F>(f));
3174   }
3175   template <class F>
3176   constexpr decltype(expected_map_impl(std::declval<const expected &>(),
3177                                        std::declval<F &&>()))
3178   map(F &&f) const & {
3179     return expected_map_impl(*this, std::forward<F>(f));
3180   }
3181 
3182 #ifndef TL_EXPECTED_NO_CONSTRR
3183   template <class F>
3184   constexpr decltype(expected_map_impl(std::declval<const expected &&>(),
3185                                        std::declval<F &&>()))
3186   map(F &&f) const && {
3187     return expected_map_impl(std::move(*this), std::forward<F>(f));
3188   }
3189 #endif
3190 #endif
3191 
3192 #if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \
3193     !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55)
3194   template <class F>
3195   TL_EXPECTED_11_CONSTEXPR auto transform(F &&f) & {
3196     return expected_map_impl(*this, std::forward<F>(f));
3197   }
3198   template <class F>
3199   TL_EXPECTED_11_CONSTEXPR auto transform(F &&f) && {
3200     return expected_map_impl(std::move(*this), std::forward<F>(f));
3201   }
3202   template <class F>
3203   constexpr auto transform(F &&f) const & {
3204     return expected_map_impl(*this, std::forward<F>(f));
3205   }
3206   template <class F>
3207   constexpr auto transform(F &&f) const && {
3208     return expected_map_impl(std::move(*this), std::forward<F>(f));
3209   }
3210 #else
3211   template <class F>
3212   TL_EXPECTED_11_CONSTEXPR decltype(expected_map_impl(
3213       std::declval<expected &>(), std::declval<F &&>()))
3214   transform(F &&f) & {
3215     return expected_map_impl(*this, std::forward<F>(f));
3216   }
3217   template <class F>
3218   TL_EXPECTED_11_CONSTEXPR decltype(expected_map_impl(std::declval<expected>(),
3219                                                       std::declval<F &&>()))
3220   transform(F &&f) && {
3221     return expected_map_impl(std::move(*this), std::forward<F>(f));
3222   }
3223   template <class F>
3224   constexpr decltype(expected_map_impl(std::declval<const expected &>(),
3225                                        std::declval<F &&>()))
3226   transform(F &&f) const & {
3227     return expected_map_impl(*this, std::forward<F>(f));
3228   }
3229 
3230 #ifndef TL_EXPECTED_NO_CONSTRR
3231   template <class F>
3232   constexpr decltype(expected_map_impl(std::declval<const expected &&>(),
3233                                        std::declval<F &&>()))
3234   transform(F &&f) const && {
3235     return expected_map_impl(std::move(*this), std::forward<F>(f));
3236   }
3237 #endif
3238 #endif
3239 
3240 #if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \
3241     !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55)
3242   template <class F>
3243   TL_EXPECTED_11_CONSTEXPR auto map_error(F &&f) & {
3244     return map_error_impl(*this, std::forward<F>(f));
3245   }
3246   template <class F>
3247   TL_EXPECTED_11_CONSTEXPR auto map_error(F &&f) && {
3248     return map_error_impl(std::move(*this), std::forward<F>(f));
3249   }
3250   template <class F>
3251   constexpr auto map_error(F &&f) const & {
3252     return map_error_impl(*this, std::forward<F>(f));
3253   }
3254   template <class F>
3255   constexpr auto map_error(F &&f) const && {
3256     return map_error_impl(std::move(*this), std::forward<F>(f));
3257   }
3258 #else
3259   template <class F>
3260   TL_EXPECTED_11_CONSTEXPR decltype(map_error_impl(std::declval<expected &>(),
3261                                                    std::declval<F &&>()))
3262   map_error(F &&f) & {
3263     return map_error_impl(*this, std::forward<F>(f));
3264   }
3265   template <class F>
3266   TL_EXPECTED_11_CONSTEXPR decltype(map_error_impl(std::declval<expected &&>(),
3267                                                    std::declval<F &&>()))
3268   map_error(F &&f) && {
3269     return map_error_impl(std::move(*this), std::forward<F>(f));
3270   }
3271   template <class F>
3272   constexpr decltype(map_error_impl(std::declval<const expected &>(),
3273                                     std::declval<F &&>()))
3274   map_error(F &&f) const & {
3275     return map_error_impl(*this, std::forward<F>(f));
3276   }
3277 
3278 #ifndef TL_EXPECTED_NO_CONSTRR
3279   template <class F>
3280   constexpr decltype(map_error_impl(std::declval<const expected &&>(),
3281                                     std::declval<F &&>()))
3282   map_error(F &&f) const && {
3283     return map_error_impl(std::move(*this), std::forward<F>(f));
3284   }
3285 #endif
3286 #endif
3287 #if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \
3288     !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55)
3289   template <class F>
3290   TL_EXPECTED_11_CONSTEXPR auto transform_error(F &&f) & {
3291     return map_error_impl(*this, std::forward<F>(f));
3292   }
3293   template <class F>
3294   TL_EXPECTED_11_CONSTEXPR auto transform_error(F &&f) && {
3295     return map_error_impl(std::move(*this), std::forward<F>(f));
3296   }
3297   template <class F>
3298   constexpr auto transform_error(F &&f) const & {
3299     return map_error_impl(*this, std::forward<F>(f));
3300   }
3301   template <class F>
3302   constexpr auto transform_error(F &&f) const && {
3303     return map_error_impl(std::move(*this), std::forward<F>(f));
3304   }
3305 #else
3306   template <class F>
3307   TL_EXPECTED_11_CONSTEXPR decltype(map_error_impl(std::declval<expected &>(),
3308                                                    std::declval<F &&>()))
3309   transform_error(F &&f) & {
3310     return map_error_impl(*this, std::forward<F>(f));
3311   }
3312   template <class F>
3313   TL_EXPECTED_11_CONSTEXPR decltype(map_error_impl(std::declval<expected &&>(),
3314                                                    std::declval<F &&>()))
3315   transform_error(F &&f) && {
3316     return map_error_impl(std::move(*this), std::forward<F>(f));
3317   }
3318   template <class F>
3319   constexpr decltype(map_error_impl(std::declval<const expected &>(),
3320                                     std::declval<F &&>()))
3321   transform_error(F &&f) const & {
3322     return map_error_impl(*this, std::forward<F>(f));
3323   }
3324 
3325 #ifndef TL_EXPECTED_NO_CONSTRR
3326   template <class F>
3327   constexpr decltype(map_error_impl(std::declval<const expected &&>(),
3328                                     std::declval<F &&>()))
3329   transform_error(F &&f) const && {
3330     return map_error_impl(std::move(*this), std::forward<F>(f));
3331   }
3332 #endif
3333 #endif
3334   template <class F>
3335   expected TL_EXPECTED_11_CONSTEXPR or_else(F &&f) & {
3336     return or_else_impl(*this, std::forward<F>(f));
3337   }
3338 
3339   template <class F>
3340   expected TL_EXPECTED_11_CONSTEXPR or_else(F &&f) && {
3341     return or_else_impl(std::move(*this), std::forward<F>(f));
3342   }
3343 
3344   template <class F>
3345   expected constexpr or_else(F &&f) const & {
3346     return or_else_impl(*this, std::forward<F>(f));
3347   }
3348 
3349 #ifndef TL_EXPECTED_NO_CONSTRR
3350   template <class F>
3351   expected constexpr or_else(F &&f) const && {
3352     return or_else_impl(std::move(*this), std::forward<F>(f));
3353   }
3354 #endif
3355   constexpr expected() = default;
3356   constexpr expected(const expected &rhs) = default;
3357   constexpr expected(expected &&rhs) = default;
3358   expected &operator=(const expected &rhs) = default;
3359   expected &operator=(expected &&rhs) = default;
3360 
3361   template <class... Args,
3362             detail::enable_if_t<std::is_constructible<T, Args &&...>::value> * =
3363                 nullptr>
3364   constexpr expected(in_place_t, Args &&...args)
3365       : impl_base(in_place, std::forward<Args>(args)...),
3366         ctor_base(detail::default_constructor_tag{}) {}
3367 
3368   template <class U, class... Args,
3369             detail::enable_if_t<std::is_constructible<
3370                 T, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
3371   constexpr expected(in_place_t, std::initializer_list<U> il, Args &&...args)
3372       : impl_base(in_place, il, std::forward<Args>(args)...),
3373         ctor_base(detail::default_constructor_tag{}) {}
3374 
3375   template <class G = E,
3376             detail::enable_if_t<std::is_constructible<E, const G &>::value> * =
3377                 nullptr,
3378             detail::enable_if_t<!std::is_convertible<const G &, E>::value> * =
3379                 nullptr>
3380   explicit constexpr expected(const unexpected<G> &e)
3381       : impl_base(unexpect, e.value()),
3382         ctor_base(detail::default_constructor_tag{}) {}
3383 
3384   template <
3385       class G = E,
3386       detail::enable_if_t<std::is_constructible<E, const G &>::value> * =
3387           nullptr,
3388       detail::enable_if_t<std::is_convertible<const G &, E>::value> * = nullptr>
3389   constexpr expected(unexpected<G> const &e)
3390       : impl_base(unexpect, e.value()),
3391         ctor_base(detail::default_constructor_tag{}) {}
3392 
3393   template <
3394       class G = E,
3395       detail::enable_if_t<std::is_constructible<E, G &&>::value> * = nullptr,
3396       detail::enable_if_t<!std::is_convertible<G &&, E>::value> * = nullptr>
3397   explicit constexpr expected(unexpected<G> &&e) noexcept(
3398       std::is_nothrow_constructible<E, G &&>::value)
3399       : impl_base(unexpect, std::move(e.value())),
3400         ctor_base(detail::default_constructor_tag{}) {}
3401 
3402   template <
3403       class G = E,
3404       detail::enable_if_t<std::is_constructible<E, G &&>::value> * = nullptr,
3405       detail::enable_if_t<std::is_convertible<G &&, E>::value> * = nullptr>
3406   constexpr expected(unexpected<G> &&e) noexcept(
3407       std::is_nothrow_constructible<E, G &&>::value)
3408       : impl_base(unexpect, std::move(e.value())),
3409         ctor_base(detail::default_constructor_tag{}) {}
3410 
3411   template <class... Args,
3412             detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * =
3413                 nullptr>
3414   constexpr explicit expected(unexpect_t, Args &&...args)
3415       : impl_base(unexpect, std::forward<Args>(args)...),
3416         ctor_base(detail::default_constructor_tag{}) {}
3417 
3418   template <class U, class... Args,
3419             detail::enable_if_t<std::is_constructible<
3420                 E, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
3421   constexpr explicit expected(unexpect_t, std::initializer_list<U> il,
3422                               Args &&...args)
3423       : impl_base(unexpect, il, std::forward<Args>(args)...),
3424         ctor_base(detail::default_constructor_tag{}) {}
3425 
3426   template <class U, class G,
3427             detail::enable_if_t<!(std::is_convertible<U const &, T>::value &&
3428                                   std::is_convertible<G const &, E>::value)> * =
3429                 nullptr,
3430             detail::expected_enable_from_other<T, E, U, G, const U &, const G &>
3431                 * = nullptr>
3432   explicit TL_EXPECTED_11_CONSTEXPR expected(const expected<U, G> &rhs)
3433       : ctor_base(detail::default_constructor_tag{}) {
3434     if (rhs.has_value()) {
3435       this->construct(*rhs);
3436     } else {
3437       this->construct_error(rhs.error());
3438     }
3439   }
3440 
3441   template <class U, class G,
3442             detail::enable_if_t<(std::is_convertible<U const &, T>::value &&
3443                                  std::is_convertible<G const &, E>::value)> * =
3444                 nullptr,
3445             detail::expected_enable_from_other<T, E, U, G, const U &, const G &>
3446                 * = nullptr>
3447   TL_EXPECTED_11_CONSTEXPR expected(const expected<U, G> &rhs)
3448       : ctor_base(detail::default_constructor_tag{}) {
3449     if (rhs.has_value()) {
3450       this->construct(*rhs);
3451     } else {
3452       this->construct_error(rhs.error());
3453     }
3454   }
3455 
3456   template <
3457       class U, class G,
3458       detail::enable_if_t<!(std::is_convertible<U &&, T>::value &&
3459                             std::is_convertible<G &&, E>::value)> * = nullptr,
3460       detail::expected_enable_from_other<T, E, U, G, U &&, G &&> * = nullptr>
3461   explicit TL_EXPECTED_11_CONSTEXPR expected(expected<U, G> &&rhs)
3462       : ctor_base(detail::default_constructor_tag{}) {
3463     if (rhs.has_value()) {
3464       this->construct(std::move(*rhs));
3465     } else {
3466       this->construct_error(std::move(rhs.error()));
3467     }
3468   }
3469 
3470   template <
3471       class U, class G,
3472       detail::enable_if_t<(std::is_convertible<U &&, T>::value &&
3473                            std::is_convertible<G &&, E>::value)> * = nullptr,
3474       detail::expected_enable_from_other<T, E, U, G, U &&, G &&> * = nullptr>
3475   TL_EXPECTED_11_CONSTEXPR expected(expected<U, G> &&rhs)
3476       : ctor_base(detail::default_constructor_tag{}) {
3477     if (rhs.has_value()) {
3478       this->construct(std::move(*rhs));
3479     } else {
3480       this->construct_error(std::move(rhs.error()));
3481     }
3482   }
3483 
3484   template <
3485       class U = T,
3486       detail::enable_if_t<!std::is_convertible<U &&, T>::value> * = nullptr,
3487       detail::expected_enable_forward_value<T, E, U> * = nullptr>
3488   explicit TL_EXPECTED_MSVC2015_CONSTEXPR expected(U &&v)
3489       : expected(in_place, std::forward<U>(v)) {}
3490 
3491   template <
3492       class U = T,
3493       detail::enable_if_t<std::is_convertible<U &&, T>::value> * = nullptr,
3494       detail::expected_enable_forward_value<T, E, U> * = nullptr>
3495   TL_EXPECTED_MSVC2015_CONSTEXPR expected(U &&v)
3496       : expected(in_place, std::forward<U>(v)) {}
3497 
3498   template <
3499       class U = T, class G = T,
3500       detail::enable_if_t<std::is_nothrow_constructible<T, U &&>::value> * =
3501           nullptr,
3502       detail::enable_if_t<!std::is_void<G>::value> * = nullptr,
3503       detail::enable_if_t<
3504           (!std::is_same<expected<T, E>, detail::decay_t<U>>::value &&
3505            !detail::conjunction<std::is_scalar<T>,
3506                                 std::is_same<T, detail::decay_t<U>>>::value &&
3507            std::is_constructible<T, U>::value &&
3508            std::is_assignable<G &, U>::value &&
3509            std::is_nothrow_move_constructible<E>::value)> * = nullptr>
3510   expected &operator=(U &&v) {
3511     if (has_value()) {
3512       val() = std::forward<U>(v);
3513     } else {
3514       err().~unexpected<E>();
3515       ::new (valptr()) T(std::forward<U>(v));
3516       this->m_has_val = true;
3517     }
3518 
3519     return *this;
3520   }
3521 
3522   template <
3523       class U = T, class G = T,
3524       detail::enable_if_t<!std::is_nothrow_constructible<T, U &&>::value> * =
3525           nullptr,
3526       detail::enable_if_t<!std::is_void<U>::value> * = nullptr,
3527       detail::enable_if_t<
3528           (!std::is_same<expected<T, E>, detail::decay_t<U>>::value &&
3529            !detail::conjunction<std::is_scalar<T>,
3530                                 std::is_same<T, detail::decay_t<U>>>::value &&
3531            std::is_constructible<T, U>::value &&
3532            std::is_assignable<G &, U>::value &&
3533            std::is_nothrow_move_constructible<E>::value)> * = nullptr>
3534   expected &operator=(U &&v) {
3535     if (has_value()) {
3536       val() = std::forward<U>(v);
3537     } else {
3538       auto tmp = std::move(err());
3539       err().~unexpected<E>();
3540 
3541 #ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
3542       try {
3543         ::new (valptr()) T(std::forward<U>(v));
3544         this->m_has_val = true;
3545       } catch (...) {
3546         err() = std::move(tmp);
3547         throw;
3548       }
3549 #else
3550       ::new (valptr()) T(std::forward<U>(v));
3551       this->m_has_val = true;
3552 #endif
3553     }
3554 
3555     return *this;
3556   }
3557 
3558   template <class G = E,
3559             detail::enable_if_t<std::is_nothrow_copy_constructible<G>::value &&
3560                                 std::is_assignable<G &, G>::value> * = nullptr>
3561   expected &operator=(const unexpected<G> &rhs) {
3562     if (!has_value()) {
3563       err() = rhs;
3564     } else {
3565       this->destroy_val();
3566       ::new (errptr()) unexpected<E>(rhs);
3567       this->m_has_val = false;
3568     }
3569 
3570     return *this;
3571   }
3572 
3573   template <class G = E,
3574             detail::enable_if_t<std::is_nothrow_move_constructible<G>::value &&
3575                                 std::is_move_assignable<G>::value> * = nullptr>
3576   expected &operator=(unexpected<G> &&rhs) noexcept {
3577     if (!has_value()) {
3578       err() = std::move(rhs);
3579     } else {
3580       this->destroy_val();
3581       ::new (errptr()) unexpected<E>(std::move(rhs));
3582       this->m_has_val = false;
3583     }
3584 
3585     return *this;
3586   }
3587 
3588   template <class... Args, detail::enable_if_t<std::is_nothrow_constructible<
3589                                T, Args &&...>::value> * = nullptr>
3590   void emplace(Args &&...args) {
3591     if (has_value()) {
3592       val().~T();
3593     } else {
3594       err().~unexpected<E>();
3595       this->m_has_val = true;
3596     }
3597     ::new (valptr()) T(std::forward<Args>(args)...);
3598   }
3599 
3600   template <class... Args, detail::enable_if_t<!std::is_nothrow_constructible<
3601                                T, Args &&...>::value> * = nullptr>
3602   void emplace(Args &&...args) {
3603     if (has_value()) {
3604       val().~T();
3605       ::new (valptr()) T(std::forward<Args>(args)...);
3606     } else {
3607       auto tmp = std::move(err());
3608       err().~unexpected<E>();
3609 
3610 #ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
3611       try {
3612         ::new (valptr()) T(std::forward<Args>(args)...);
3613         this->m_has_val = true;
3614       } catch (...) {
3615         err() = std::move(tmp);
3616         throw;
3617       }
3618 #else
3619       ::new (valptr()) T(std::forward<Args>(args)...);
3620       this->m_has_val = true;
3621 #endif
3622     }
3623   }
3624 
3625   template <class U, class... Args,
3626             detail::enable_if_t<std::is_nothrow_constructible<
3627                 T, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
3628   void emplace(std::initializer_list<U> il, Args &&...args) {
3629     if (has_value()) {
3630       T t(il, std::forward<Args>(args)...);
3631       val() = std::move(t);
3632     } else {
3633       err().~unexpected<E>();
3634       ::new (valptr()) T(il, std::forward<Args>(args)...);
3635       this->m_has_val = true;
3636     }
3637   }
3638 
3639   template <class U, class... Args,
3640             detail::enable_if_t<!std::is_nothrow_constructible<
3641                 T, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
3642   void emplace(std::initializer_list<U> il, Args &&...args) {
3643     if (has_value()) {
3644       T t(il, std::forward<Args>(args)...);
3645       val() = std::move(t);
3646     } else {
3647       auto tmp = std::move(err());
3648       err().~unexpected<E>();
3649 
3650 #ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
3651       try {
3652         ::new (valptr()) T(il, std::forward<Args>(args)...);
3653         this->m_has_val = true;
3654       } catch (...) {
3655         err() = std::move(tmp);
3656         throw;
3657       }
3658 #else
3659       ::new (valptr()) T(il, std::forward<Args>(args)...);
3660       this->m_has_val = true;
3661 #endif
3662     }
3663   }
3664 
3665  private:
3666   using t_is_void = std::true_type;
3667   using t_is_not_void = std::false_type;
3668   using t_is_nothrow_move_constructible = std::true_type;
3669   using move_constructing_t_can_throw = std::false_type;
3670   using e_is_nothrow_move_constructible = std::true_type;
3671   using move_constructing_e_can_throw = std::false_type;
3672 
3673   void swap_where_both_have_value(expected & /*rhs*/, t_is_void) noexcept {
3674     // swapping void is a no-op
3675   }
3676 
3677   void swap_where_both_have_value(expected &rhs, t_is_not_void) {
3678     using std::swap;
3679     swap(val(), rhs.val());
3680   }
3681 
3682   void swap_where_only_one_has_value(expected &rhs, t_is_void) noexcept(
3683       std::is_nothrow_move_constructible<E>::value) {
3684     ::new (errptr()) unexpected_type(std::move(rhs.err()));
3685     rhs.err().~unexpected_type();
3686     std::swap(this->m_has_val, rhs.m_has_val);
3687   }
3688 
3689   void swap_where_only_one_has_value(expected &rhs, t_is_not_void) {
3690     swap_where_only_one_has_value_and_t_is_not_void(
3691         rhs, typename std::is_nothrow_move_constructible<T>::type{},
3692         typename std::is_nothrow_move_constructible<E>::type{});
3693   }
3694 
3695   void swap_where_only_one_has_value_and_t_is_not_void(
3696       expected &rhs, t_is_nothrow_move_constructible,
3697       e_is_nothrow_move_constructible) noexcept {
3698     auto temp = std::move(val());
3699     val().~T();
3700     ::new (errptr()) unexpected_type(std::move(rhs.err()));
3701     rhs.err().~unexpected_type();
3702     ::new (rhs.valptr()) T(std::move(temp));
3703     std::swap(this->m_has_val, rhs.m_has_val);
3704   }
3705 
3706   void swap_where_only_one_has_value_and_t_is_not_void(
3707       expected &rhs, t_is_nothrow_move_constructible,
3708       move_constructing_e_can_throw) {
3709     auto temp = std::move(val());
3710     val().~T();
3711 #ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
3712     try {
3713       ::new (errptr()) unexpected_type(std::move(rhs.err()));
3714       rhs.err().~unexpected_type();
3715       ::new (rhs.valptr()) T(std::move(temp));
3716       std::swap(this->m_has_val, rhs.m_has_val);
3717     } catch (...) {
3718       val() = std::move(temp);
3719       throw;
3720     }
3721 #else
3722     ::new (errptr()) unexpected_type(std::move(rhs.err()));
3723     rhs.err().~unexpected_type();
3724     ::new (rhs.valptr()) T(std::move(temp));
3725     std::swap(this->m_has_val, rhs.m_has_val);
3726 #endif
3727   }
3728 
3729   void swap_where_only_one_has_value_and_t_is_not_void(
3730       expected &rhs, move_constructing_t_can_throw,
3731       e_is_nothrow_move_constructible) {
3732     auto temp = std::move(rhs.err());
3733     rhs.err().~unexpected_type();
3734 #ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
3735     try {
3736       ::new (rhs.valptr()) T(std::move(val()));
3737       val().~T();
3738       ::new (errptr()) unexpected_type(std::move(temp));
3739       std::swap(this->m_has_val, rhs.m_has_val);
3740     } catch (...) {
3741       rhs.err() = std::move(temp);
3742       throw;
3743     }
3744 #else
3745     ::new (rhs.valptr()) T(std::move(val()));
3746     val().~T();
3747     ::new (errptr()) unexpected_type(std::move(temp));
3748     std::swap(this->m_has_val, rhs.m_has_val);
3749 #endif
3750   }
3751 
3752  public:
3753   template <class OT = T, class OE = E>
3754   detail::enable_if_t<detail::is_swappable<OT>::value &&
3755                       detail::is_swappable<OE>::value &&
3756                       (std::is_nothrow_move_constructible<OT>::value ||
3757                        std::is_nothrow_move_constructible<OE>::value)>
3758   swap(expected &rhs) noexcept(
3759       std::is_nothrow_move_constructible<T>::value
3760           &&detail::is_nothrow_swappable<T>::value
3761               &&std::is_nothrow_move_constructible<E>::value
3762                   &&detail::is_nothrow_swappable<E>::value) {
3763     if (has_value() && rhs.has_value()) {
3764       swap_where_both_have_value(rhs, typename std::is_void<T>::type{});
3765     } else if (!has_value() && rhs.has_value()) {
3766       rhs.swap(*this);
3767     } else if (has_value()) {
3768       swap_where_only_one_has_value(rhs, typename std::is_void<T>::type{});
3769     } else {
3770       using std::swap;
3771       swap(err(), rhs.err());
3772     }
3773   }
3774 
3775   constexpr const T *operator->() const {
3776     TL_ASSERT(has_value());
3777     return valptr();
3778   }
3779   TL_EXPECTED_11_CONSTEXPR T *operator->() {
3780     TL_ASSERT(has_value());
3781     return valptr();
3782   }
3783 
3784   template <class U = T,
3785             detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
3786   constexpr const U &operator*() const & {
3787     TL_ASSERT(has_value());
3788     return val();
3789   }
3790   template <class U = T,
3791             detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
3792   TL_EXPECTED_11_CONSTEXPR U &operator*() & {
3793     TL_ASSERT(has_value());
3794     return val();
3795   }
3796   template <class U = T,
3797             detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
3798   constexpr const U &&operator*() const && {
3799     TL_ASSERT(has_value());
3800     return std::move(val());
3801   }
3802   template <class U = T,
3803             detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
3804   TL_EXPECTED_11_CONSTEXPR U &&operator*() && {
3805     TL_ASSERT(has_value());
3806     return std::move(val());
3807   }
3808 
3809   constexpr bool has_value() const noexcept { return this->m_has_val; }
3810   constexpr explicit operator bool() const noexcept { return this->m_has_val; }
3811 
3812   template <class U = T,
3813             detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
3814   TL_EXPECTED_11_CONSTEXPR const U &value() const & {
3815     if (!has_value())
3816       detail::throw_exception(bad_expected_access<E>(err().value()));
3817     return val();
3818   }
3819   template <class U = T,
3820             detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
3821   TL_EXPECTED_11_CONSTEXPR U &value() & {
3822     if (!has_value())
3823       detail::throw_exception(bad_expected_access<E>(err().value()));
3824     return val();
3825   }
3826   template <class U = T,
3827             detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
3828   TL_EXPECTED_11_CONSTEXPR const U &&value() const && {
3829     if (!has_value())
3830       detail::throw_exception(bad_expected_access<E>(std::move(err()).value()));
3831     return std::move(val());
3832   }
3833   template <class U = T,
3834             detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
3835   TL_EXPECTED_11_CONSTEXPR U &&value() && {
3836     if (!has_value())
3837       detail::throw_exception(bad_expected_access<E>(std::move(err()).value()));
3838     return std::move(val());
3839   }
3840 
3841   constexpr const E &error() const & {
3842     TL_ASSERT(!has_value());
3843     return err().value();
3844   }
3845   TL_EXPECTED_11_CONSTEXPR E &error() & {
3846     TL_ASSERT(!has_value());
3847     return err().value();
3848   }
3849   constexpr const E &&error() const && {
3850     TL_ASSERT(!has_value());
3851     return std::move(err().value());
3852   }
3853   TL_EXPECTED_11_CONSTEXPR E &&error() && {
3854     TL_ASSERT(!has_value());
3855     return std::move(err().value());
3856   }
3857 
3858   template <class U>
3859   constexpr T value_or(U &&v) const & {
3860     static_assert(std::is_copy_constructible<T>::value &&
3861                       std::is_convertible<U &&, T>::value,
3862                   "T must be copy-constructible and convertible to from U&&");
3863     return bool(*this) ? **this : static_cast<T>(std::forward<U>(v));
3864   }
3865   template <class U>
3866   TL_EXPECTED_11_CONSTEXPR T value_or(U &&v) && {
3867     static_assert(std::is_move_constructible<T>::value &&
3868                       std::is_convertible<U &&, T>::value,
3869                   "T must be move-constructible and convertible to from U&&");
3870     return bool(*this) ? std::move(**this) : static_cast<T>(std::forward<U>(v));
3871   }
3872 };
3873 
3874 namespace detail {
3875 template <class Exp>
3876 using exp_t = typename detail::decay_t<Exp>::value_type;
3877 template <class Exp>
3878 using err_t = typename detail::decay_t<Exp>::error_type;
3879 template <class Exp, class Ret>
3880 using ret_t = expected<Ret, err_t<Exp>>;
3881 
3882 #ifdef TL_EXPECTED_CXX14
3883 template <class Exp, class F,
3884           detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
3885           class Ret = decltype(detail::invoke(std::declval<F>(),
3886                                               *std::declval<Exp>()))>
3887 constexpr auto and_then_impl(Exp &&exp, F &&f) {
3888   static_assert(detail::is_expected<Ret>::value, "F must return an expected");
3889 
3890   return exp.has_value()
3891              ? detail::invoke(std::forward<F>(f), *std::forward<Exp>(exp))
3892              : Ret(unexpect, std::forward<Exp>(exp).error());
3893 }
3894 
3895 template <class Exp, class F,
3896           detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
3897           class Ret = decltype(detail::invoke(std::declval<F>()))>
3898 constexpr auto and_then_impl(Exp &&exp, F &&f) {
3899   static_assert(detail::is_expected<Ret>::value, "F must return an expected");
3900 
3901   return exp.has_value() ? detail::invoke(std::forward<F>(f))
3902                          : Ret(unexpect, std::forward<Exp>(exp).error());
3903 }
3904 #else
3905 template <class>
3906 struct TC;
3907 template <class Exp, class F,
3908           class Ret = decltype(detail::invoke(std::declval<F>(),
3909                                               *std::declval<Exp>())),
3910           detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr>
3911 auto and_then_impl(Exp &&exp, F &&f) -> Ret {
3912   static_assert(detail::is_expected<Ret>::value, "F must return an expected");
3913 
3914   return exp.has_value()
3915              ? detail::invoke(std::forward<F>(f), *std::forward<Exp>(exp))
3916              : Ret(unexpect, std::forward<Exp>(exp).error());
3917 }
3918 
3919 template <class Exp, class F,
3920           class Ret = decltype(detail::invoke(std::declval<F>())),
3921           detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr>
3922 constexpr auto and_then_impl(Exp &&exp, F &&f) -> Ret {
3923   static_assert(detail::is_expected<Ret>::value, "F must return an expected");
3924 
3925   return exp.has_value() ? detail::invoke(std::forward<F>(f))
3926                          : Ret(unexpect, std::forward<Exp>(exp).error());
3927 }
3928 #endif
3929 
3930 #ifdef TL_EXPECTED_CXX14
3931 template <class Exp, class F,
3932           detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
3933           class Ret = decltype(detail::invoke(std::declval<F>(),
3934                                               *std::declval<Exp>())),
3935           detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
3936 constexpr auto expected_map_impl(Exp &&exp, F &&f) {
3937   using result = ret_t<Exp, detail::decay_t<Ret>>;
3938   return exp.has_value() ? result(detail::invoke(std::forward<F>(f),
3939                                                  *std::forward<Exp>(exp)))
3940                          : result(unexpect, std::forward<Exp>(exp).error());
3941 }
3942 
3943 template <class Exp, class F,
3944           detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
3945           class Ret = decltype(detail::invoke(std::declval<F>(),
3946                                               *std::declval<Exp>())),
3947           detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
3948 auto expected_map_impl(Exp &&exp, F &&f) {
3949   using result = expected<void, err_t<Exp>>;
3950   if (exp.has_value()) {
3951     detail::invoke(std::forward<F>(f), *std::forward<Exp>(exp));
3952     return result();
3953   }
3954 
3955   return result(unexpect, std::forward<Exp>(exp).error());
3956 }
3957 
3958 template <class Exp, class F,
3959           detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
3960           class Ret = decltype(detail::invoke(std::declval<F>())),
3961           detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
3962 constexpr auto expected_map_impl(Exp &&exp, F &&f) {
3963   using result = ret_t<Exp, detail::decay_t<Ret>>;
3964   return exp.has_value() ? result(detail::invoke(std::forward<F>(f)))
3965                          : result(unexpect, std::forward<Exp>(exp).error());
3966 }
3967 
3968 template <class Exp, class F,
3969           detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
3970           class Ret = decltype(detail::invoke(std::declval<F>())),
3971           detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
3972 auto expected_map_impl(Exp &&exp, F &&f) {
3973   using result = expected<void, err_t<Exp>>;
3974   if (exp.has_value()) {
3975     detail::invoke(std::forward<F>(f));
3976     return result();
3977   }
3978 
3979   return result(unexpect, std::forward<Exp>(exp).error());
3980 }
3981 #else
3982 template <class Exp, class F,
3983           detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
3984           class Ret = decltype(detail::invoke(std::declval<F>(),
3985                                               *std::declval<Exp>())),
3986           detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
3987 
3988 constexpr auto expected_map_impl(Exp &&exp, F &&f)
3989     -> ret_t<Exp, detail::decay_t<Ret>> {
3990   using result = ret_t<Exp, detail::decay_t<Ret>>;
3991 
3992   return exp.has_value() ? result(detail::invoke(std::forward<F>(f),
3993                                                  *std::forward<Exp>(exp)))
3994                          : result(unexpect, std::forward<Exp>(exp).error());
3995 }
3996 
3997 template <class Exp, class F,
3998           detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
3999           class Ret = decltype(detail::invoke(std::declval<F>(),
4000                                               *std::declval<Exp>())),
4001           detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
4002 
4003 auto expected_map_impl(Exp &&exp, F &&f) -> expected<void, err_t<Exp>> {
4004   if (exp.has_value()) {
4005     detail::invoke(std::forward<F>(f), *std::forward<Exp>(exp));
4006     return {};
4007   }
4008 
4009   return unexpected<err_t<Exp>>(std::forward<Exp>(exp).error());
4010 }
4011 
4012 template <class Exp, class F,
4013           detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
4014           class Ret = decltype(detail::invoke(std::declval<F>())),
4015           detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
4016 
4017 constexpr auto expected_map_impl(Exp &&exp, F &&f)
4018     -> ret_t<Exp, detail::decay_t<Ret>> {
4019   using result = ret_t<Exp, detail::decay_t<Ret>>;
4020 
4021   return exp.has_value() ? result(detail::invoke(std::forward<F>(f)))
4022                          : result(unexpect, std::forward<Exp>(exp).error());
4023 }
4024 
4025 template <class Exp, class F,
4026           detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
4027           class Ret = decltype(detail::invoke(std::declval<F>())),
4028           detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
4029 
4030 auto expected_map_impl(Exp &&exp, F &&f) -> expected<void, err_t<Exp>> {
4031   if (exp.has_value()) {
4032     detail::invoke(std::forward<F>(f));
4033     return {};
4034   }
4035 
4036   return unexpected<err_t<Exp>>(std::forward<Exp>(exp).error());
4037 }
4038 #endif
4039 
4040 #if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \
4041     !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55)
4042 template <class Exp, class F,
4043           detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
4044           class Ret = decltype(detail::invoke(std::declval<F>(),
4045                                               std::declval<Exp>().error())),
4046           detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
4047 constexpr auto map_error_impl(Exp &&exp, F &&f) {
4048   using result = expected<exp_t<Exp>, detail::decay_t<Ret>>;
4049   return exp.has_value()
4050              ? result(*std::forward<Exp>(exp))
4051              : result(unexpect, detail::invoke(std::forward<F>(f),
4052                                                std::forward<Exp>(exp).error()));
4053 }
4054 template <class Exp, class F,
4055           detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
4056           class Ret = decltype(detail::invoke(std::declval<F>(),
4057                                               std::declval<Exp>().error())),
4058           detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
4059 auto map_error_impl(Exp &&exp, F &&f) {
4060   using result = expected<exp_t<Exp>, monostate>;
4061   if (exp.has_value()) {
4062     return result(*std::forward<Exp>(exp));
4063   }
4064 
4065   detail::invoke(std::forward<F>(f), std::forward<Exp>(exp).error());
4066   return result(unexpect, monostate{});
4067 }
4068 template <class Exp, class F,
4069           detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
4070           class Ret = decltype(detail::invoke(std::declval<F>(),
4071                                               std::declval<Exp>().error())),
4072           detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
4073 constexpr auto map_error_impl(Exp &&exp, F &&f) {
4074   using result = expected<exp_t<Exp>, detail::decay_t<Ret>>;
4075   return exp.has_value()
4076              ? result()
4077              : result(unexpect, detail::invoke(std::forward<F>(f),
4078                                                std::forward<Exp>(exp).error()));
4079 }
4080 template <class Exp, class F,
4081           detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
4082           class Ret = decltype(detail::invoke(std::declval<F>(),
4083                                               std::declval<Exp>().error())),
4084           detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
4085 auto map_error_impl(Exp &&exp, F &&f) {
4086   using result = expected<exp_t<Exp>, monostate>;
4087   if (exp.has_value()) {
4088     return result();
4089   }
4090 
4091   detail::invoke(std::forward<F>(f), std::forward<Exp>(exp).error());
4092   return result(unexpect, monostate{});
4093 }
4094 #else
4095 template <class Exp, class F,
4096           detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
4097           class Ret = decltype(detail::invoke(std::declval<F>(),
4098                                               std::declval<Exp>().error())),
4099           detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
4100 constexpr auto map_error_impl(Exp &&exp, F &&f)
4101     -> expected<exp_t<Exp>, detail::decay_t<Ret>> {
4102   using result = expected<exp_t<Exp>, detail::decay_t<Ret>>;
4103 
4104   return exp.has_value()
4105              ? result(*std::forward<Exp>(exp))
4106              : result(unexpect, detail::invoke(std::forward<F>(f),
4107                                                std::forward<Exp>(exp).error()));
4108 }
4109 
4110 template <class Exp, class F,
4111           detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
4112           class Ret = decltype(detail::invoke(std::declval<F>(),
4113                                               std::declval<Exp>().error())),
4114           detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
4115 auto map_error_impl(Exp &&exp, F &&f) -> expected<exp_t<Exp>, monostate> {
4116   using result = expected<exp_t<Exp>, monostate>;
4117   if (exp.has_value()) {
4118     return result(*std::forward<Exp>(exp));
4119   }
4120 
4121   detail::invoke(std::forward<F>(f), std::forward<Exp>(exp).error());
4122   return result(unexpect, monostate{});
4123 }
4124 
4125 template <class Exp, class F,
4126           detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
4127           class Ret = decltype(detail::invoke(std::declval<F>(),
4128                                               std::declval<Exp>().error())),
4129           detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
4130 constexpr auto map_error_impl(Exp &&exp, F &&f)
4131     -> expected<exp_t<Exp>, detail::decay_t<Ret>> {
4132   using result = expected<exp_t<Exp>, detail::decay_t<Ret>>;
4133 
4134   return exp.has_value()
4135              ? result()
4136              : result(unexpect, detail::invoke(std::forward<F>(f),
4137                                                std::forward<Exp>(exp).error()));
4138 }
4139 
4140 template <class Exp, class F,
4141           detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
4142           class Ret = decltype(detail::invoke(std::declval<F>(),
4143                                               std::declval<Exp>().error())),
4144           detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
4145 auto map_error_impl(Exp &&exp, F &&f) -> expected<exp_t<Exp>, monostate> {
4146   using result = expected<exp_t<Exp>, monostate>;
4147   if (exp.has_value()) {
4148     return result();
4149   }
4150 
4151   detail::invoke(std::forward<F>(f), std::forward<Exp>(exp).error());
4152   return result(unexpect, monostate{});
4153 }
4154 #endif
4155 
4156 #ifdef TL_EXPECTED_CXX14
4157 template <class Exp, class F,
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>
4161 constexpr auto or_else_impl(Exp &&exp, F &&f) {
4162   static_assert(detail::is_expected<Ret>::value, "F must return an expected");
4163   return exp.has_value() ? std::forward<Exp>(exp)
4164                          : detail::invoke(std::forward<F>(f),
4165                                           std::forward<Exp>(exp).error());
4166 }
4167 
4168 template <class Exp, class F,
4169           class Ret = decltype(detail::invoke(std::declval<F>(),
4170                                               std::declval<Exp>().error())),
4171           detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
4172 detail::decay_t<Exp> or_else_impl(Exp &&exp, F &&f) {
4173   return exp.has_value() ? std::forward<Exp>(exp)
4174                          : (detail::invoke(std::forward<F>(f),
4175                                            std::forward<Exp>(exp).error()),
4176                             std::forward<Exp>(exp));
4177 }
4178 #else
4179 template <class Exp, class F,
4180           class Ret = decltype(detail::invoke(std::declval<F>(),
4181                                               std::declval<Exp>().error())),
4182           detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
4183 auto or_else_impl(Exp &&exp, F &&f) -> Ret {
4184   static_assert(detail::is_expected<Ret>::value, "F must return an expected");
4185   return exp.has_value() ? std::forward<Exp>(exp)
4186                          : detail::invoke(std::forward<F>(f),
4187                                           std::forward<Exp>(exp).error());
4188 }
4189 
4190 template <class Exp, class F,
4191           class Ret = decltype(detail::invoke(std::declval<F>(),
4192                                               std::declval<Exp>().error())),
4193           detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
4194 detail::decay_t<Exp> or_else_impl(Exp &&exp, F &&f) {
4195   return exp.has_value() ? std::forward<Exp>(exp)
4196                          : (detail::invoke(std::forward<F>(f),
4197                                            std::forward<Exp>(exp).error()),
4198                             std::forward<Exp>(exp));
4199 }
4200 #endif
4201 }  // namespace detail
4202 
4203 template <class T, class E, class U, class F>
4204 constexpr bool operator==(const expected<T, E> &lhs,
4205                           const expected<U, F> &rhs) {
4206   return (lhs.has_value() != rhs.has_value())
4207              ? false
4208              : (!lhs.has_value() ? lhs.error() == rhs.error() : *lhs == *rhs);
4209 }
4210 template <class T, class E, class U, class F>
4211 constexpr bool operator!=(const expected<T, E> &lhs,
4212                           const expected<U, F> &rhs) {
4213   return (lhs.has_value() != rhs.has_value())
4214              ? true
4215              : (!lhs.has_value() ? lhs.error() != rhs.error() : *lhs != *rhs);
4216 }
4217 template <class E, class F>
4218 constexpr bool operator==(const expected<void, E> &lhs,
4219                           const expected<void, F> &rhs) {
4220   return (lhs.has_value() != rhs.has_value())
4221              ? false
4222              : (!lhs.has_value() ? lhs.error() == rhs.error() : true);
4223 }
4224 template <class E, class F>
4225 constexpr bool operator!=(const expected<void, E> &lhs,
4226                           const expected<void, F> &rhs) {
4227   return (lhs.has_value() != rhs.has_value())
4228              ? true
4229              : (!lhs.has_value() ? lhs.error() == rhs.error() : false);
4230 }
4231 
4232 template <class T, class E, class U>
4233 constexpr bool operator==(const expected<T, E> &x, const U &v) {
4234   return x.has_value() ? *x == v : false;
4235 }
4236 template <class T, class E, class U>
4237 constexpr bool operator==(const U &v, const expected<T, E> &x) {
4238   return x.has_value() ? *x == v : false;
4239 }
4240 template <class T, class E, class U>
4241 constexpr bool operator!=(const expected<T, E> &x, const U &v) {
4242   return x.has_value() ? *x != v : true;
4243 }
4244 template <class T, class E, class U>
4245 constexpr bool operator!=(const U &v, const expected<T, E> &x) {
4246   return x.has_value() ? *x != v : true;
4247 }
4248 
4249 template <class T, class E>
4250 constexpr bool operator==(const expected<T, E> &x, const unexpected<E> &e) {
4251   return x.has_value() ? false : x.error() == e.value();
4252 }
4253 template <class T, class E>
4254 constexpr bool operator==(const unexpected<E> &e, const expected<T, E> &x) {
4255   return x.has_value() ? false : x.error() == e.value();
4256 }
4257 template <class T, class E>
4258 constexpr bool operator!=(const expected<T, E> &x, const unexpected<E> &e) {
4259   return x.has_value() ? true : x.error() != e.value();
4260 }
4261 template <class T, class E>
4262 constexpr bool operator!=(const unexpected<E> &e, const expected<T, E> &x) {
4263   return x.has_value() ? true : x.error() != e.value();
4264 }
4265 
4266 template <class T, class E,
4267           detail::enable_if_t<(std::is_void<T>::value ||
4268                                std::is_move_constructible<T>::value) &&
4269                               detail::is_swappable<T>::value &&
4270                               std::is_move_constructible<E>::value &&
4271                               detail::is_swappable<E>::value> * = nullptr>
4272 void swap(expected<T, E> &lhs,
4273           expected<T, E> &rhs) noexcept(noexcept(lhs.swap(rhs))) {
4274   lhs.swap(rhs);
4275 }
4276 }  // namespace tl
4277 
4278 #endif
4279 /* end file include/ada/expected.h */
4280 
4281 #include <optional>
4282 #include <string_view>
4283 
4284 /**
4285  * @private
4286  */
4287 namespace ada {
4288 struct url_aggregator;
4289 struct url;
4290 }  // namespace ada
4291 
4292 /**
4293  * @namespace ada::parser
4294  * @brief Includes the definitions for supported parsers
4295  */
4296 namespace ada::parser {
4297 
4298 /**
4299  * Parses a url.
4300  */
4301 template <typename result_type = ada::url_aggregator>
4302 result_type parse_url(std::string_view user_input,
4303                       const result_type* base_url = nullptr);
4304 
4305 extern template url_aggregator parse_url<url_aggregator>(
4306     std::string_view user_input, const url_aggregator* base_url);
4307 extern template url parse_url<url>(std::string_view user_input,
4308                                    const url* base_url);
4309 
4310 }  // namespace ada::parser
4311 
4312 #endif  // ADA_PARSER_H
4313 /* end file include/ada/parser.h */
4314 /* begin file include/ada/scheme-inl.h */
4315 /**
4316  * @file scheme-inl.h
4317  * @brief Definitions for the URL scheme.
4318  */
4319 #ifndef ADA_SCHEME_INL_H
4320 #define ADA_SCHEME_INL_H
4321 
4322 
4323 namespace ada::scheme {
4324 
4325 /**
4326  * @namespace ada::scheme::details
4327  * @brief Includes the definitions for scheme specific entities
4328  */
4329 namespace details {
4330 // for use with is_special and get_special_port
4331 // Spaces, if present, are removed from URL.
4332 constexpr std::string_view is_special_list[] = {"http", " ",   "https", "ws",
4333                                                 "ftp",  "wss", "file",  " "};
4334 // for use with get_special_port
4335 constexpr uint16_t special_ports[] = {80, 0, 443, 80, 21, 443, 0, 0};
4336 }  // namespace details
4337 
4338 ada_really_inline constexpr bool is_special(std::string_view scheme) {
4339   if (scheme.empty()) {
4340     return false;
4341   }
4342   int hash_value = (2 * scheme.size() + (unsigned)(scheme[0])) & 7;
4343   const std::string_view target = details::is_special_list[hash_value];
4344   return (target[0] == scheme[0]) && (target.substr(1) == scheme.substr(1));
4345 }
4346 constexpr uint16_t get_special_port(std::string_view scheme) noexcept {
4347   if (scheme.empty()) {
4348     return 0;
4349   }
4350   int hash_value = (2 * scheme.size() + (unsigned)(scheme[0])) & 7;
4351   const std::string_view target = details::is_special_list[hash_value];
4352   if ((target[0] == scheme[0]) && (target.substr(1) == scheme.substr(1))) {
4353     return details::special_ports[hash_value];
4354   } else {
4355     return 0;
4356   }
4357 }
4358 constexpr uint16_t get_special_port(ada::scheme::type type) noexcept {
4359   return details::special_ports[int(type)];
4360 }
4361 constexpr ada::scheme::type get_scheme_type(std::string_view scheme) noexcept {
4362   if (scheme.empty()) {
4363     return ada::scheme::NOT_SPECIAL;
4364   }
4365   int hash_value = (2 * scheme.size() + (unsigned)(scheme[0])) & 7;
4366   const std::string_view target = details::is_special_list[hash_value];
4367   if ((target[0] == scheme[0]) && (target.substr(1) == scheme.substr(1))) {
4368     return ada::scheme::type(hash_value);
4369   } else {
4370     return ada::scheme::NOT_SPECIAL;
4371   }
4372 }
4373 
4374 }  // namespace ada::scheme
4375 
4376 #endif  // ADA_SCHEME_INL_H
4377 /* end file include/ada/scheme-inl.h */
4378 /* begin file include/ada/serializers.h */
4379 /**
4380  * @file serializers.h
4381  * @brief Definitions for the URL serializers.
4382  */
4383 #ifndef ADA_SERIALIZERS_H
4384 #define ADA_SERIALIZERS_H
4385 
4386 
4387 #include <array>
4388 #include <optional>
4389 #include <string>
4390 
4391 /**
4392  * @namespace ada::serializers
4393  * @brief Includes the definitions for URL serializers
4394  */
4395 namespace ada::serializers {
4396 
4397 /**
4398  * Finds and returns the longest sequence of 0 values in a ipv6 input.
4399  */
4400 void find_longest_sequence_of_ipv6_pieces(
4401     const std::array<uint16_t, 8>& address, size_t& compress,
4402     size_t& compress_length) noexcept;
4403 
4404 /**
4405  * Serializes an ipv6 address.
4406  * @details An IPv6 address is a 128-bit unsigned integer that identifies a
4407  * network address.
4408  * @see https://url.spec.whatwg.org/#concept-ipv6-serializer
4409  */
4410 std::string ipv6(const std::array<uint16_t, 8>& address) noexcept;
4411 
4412 /**
4413  * Serializes an ipv4 address.
4414  * @details An IPv4 address is a 32-bit unsigned integer that identifies a
4415  * network address.
4416  * @see https://url.spec.whatwg.org/#concept-ipv4-serializer
4417  */
4418 std::string ipv4(uint64_t address) noexcept;
4419 
4420 }  // namespace ada::serializers
4421 
4422 #endif  // ADA_SERIALIZERS_H
4423 /* end file include/ada/serializers.h */
4424 /* begin file include/ada/unicode.h */
4425 /**
4426  * @file unicode.h
4427  * @brief Definitions for all unicode specific functions.
4428  */
4429 #ifndef ADA_UNICODE_H
4430 #define ADA_UNICODE_H
4431 
4432 
4433 #include <string>
4434 #include <optional>
4435 
4436 /**
4437  * @namespace ada::unicode
4438  * @brief Includes the definitions for unicode operations
4439  */
4440 namespace ada::unicode {
4441 
4442 /**
4443  * We receive a UTF-8 string representing a domain name.
4444  * If the string is percent encoded, we apply percent decoding.
4445  *
4446  * Given a domain, we need to identify its labels.
4447  * They are separated by label-separators:
4448  *
4449  * U+002E (.) FULL STOP
4450  * U+FF0E FULLWIDTH FULL STOP
4451  * U+3002 IDEOGRAPHIC FULL STOP
4452  * U+FF61 HALFWIDTH IDEOGRAPHIC FULL STOP
4453  *
4454  * They are all mapped to U+002E.
4455  *
4456  * We process each label into a string that should not exceed 63 octets.
4457  * If the string is already punycode (starts with "xn--"), then we must
4458  * scan it to look for unallowed code points.
4459  * Otherwise, if the string is not pure ASCII, we need to transcode it
4460  * to punycode by following RFC 3454 which requires us to
4461  * - Map characters  (see section 3),
4462  * - Normalize (see section 4),
4463  * - Reject forbidden characters,
4464  * - Check for right-to-left characters and if so, check all requirements (see
4465  * section 6),
4466  * - Optionally reject based on unassigned code points (section 7).
4467  *
4468  * The Unicode standard provides a table of code points with a mapping, a list
4469  * of forbidden code points and so forth. This table is subject to change and
4470  * will vary based on the implementation. For Unicode 15, the table is at
4471  * https://www.unicode.org/Public/idna/15.0.0/IdnaMappingTable.txt
4472  * If you use ICU, they parse this table and map it to code using a Python
4473  * script.
4474  *
4475  * The resulting strings should not exceed 255 octets according to RFC 1035
4476  * section 2.3.4. ICU checks for label size and domain size, but these errors
4477  * are ignored.
4478  *
4479  * @see https://url.spec.whatwg.org/#concept-domain-to-ascii
4480  *
4481  */
4482 bool to_ascii(std::optional<std::string>& out, std::string_view plain,
4483               size_t first_percent);
4484 
4485 /**
4486  * @see https://www.unicode.org/reports/tr46/#ToUnicode
4487  */
4488 std::string to_unicode(std::string_view input);
4489 
4490 /**
4491  * Checks if the input has tab or newline characters.
4492  *
4493  * @attention The has_tabs_or_newline function is a bottleneck and it is simple
4494  * enough that compilers like GCC can 'autovectorize it'.
4495  */
4496 ada_really_inline bool has_tabs_or_newline(
4497     std::string_view user_input) noexcept;
4498 
4499 /**
4500  * Checks if the input is a forbidden host code point.
4501  * @see https://url.spec.whatwg.org/#forbidden-host-code-point
4502  */
4503 ada_really_inline constexpr bool is_forbidden_host_code_point(char c) noexcept;
4504 
4505 /**
4506  * Checks if the input contains a forbidden domain code point.
4507  * @see https://url.spec.whatwg.org/#forbidden-domain-code-point
4508  */
4509 ada_really_inline constexpr bool contains_forbidden_domain_code_point(
4510     const char* input, size_t length) noexcept;
4511 
4512 /**
4513  * Checks if the input contains a forbidden domain code point in which case
4514  * the first bit is set to 1. If the input contains an upper case ASCII letter,
4515  * then the second bit is set to 1.
4516  * @see https://url.spec.whatwg.org/#forbidden-domain-code-point
4517  */
4518 ada_really_inline constexpr uint8_t
4519 contains_forbidden_domain_code_point_or_upper(const char* input,
4520                                               size_t length) noexcept;
4521 
4522 /**
4523  * Checks if the input is a forbidden domain code point.
4524  * @see https://url.spec.whatwg.org/#forbidden-domain-code-point
4525  */
4526 ada_really_inline constexpr bool is_forbidden_domain_code_point(
4527     char c) noexcept;
4528 
4529 /**
4530  * Checks if the input is alphanumeric, '+', '-' or '.'
4531  */
4532 ada_really_inline constexpr bool is_alnum_plus(char c) noexcept;
4533 
4534 /**
4535  * @details An ASCII hex digit is an ASCII upper hex digit or ASCII lower hex
4536  * digit. An ASCII upper hex digit is an ASCII digit or a code point in the
4537  * range U+0041 (A) to U+0046 (F), inclusive. An ASCII lower hex digit is an
4538  * ASCII digit or a code point in the range U+0061 (a) to U+0066 (f), inclusive.
4539  */
4540 ada_really_inline constexpr bool is_ascii_hex_digit(char c) noexcept;
4541 
4542 /**
4543  * Checks if the input is a C0 control or space character.
4544  *
4545  * @details A C0 control or space is a C0 control or U+0020 SPACE.
4546  * A C0 control is a code point in the range U+0000 NULL to U+001F INFORMATION
4547  * SEPARATOR ONE, inclusive.
4548  */
4549 ada_really_inline constexpr bool is_c0_control_or_space(char c) noexcept;
4550 
4551 /**
4552  * Checks if the input is a ASCII tab or newline character.
4553  *
4554  * @details An ASCII tab or newline is U+0009 TAB, U+000A LF, or U+000D CR.
4555  */
4556 ada_really_inline constexpr bool is_ascii_tab_or_newline(char c) noexcept;
4557 
4558 /**
4559  * @details A double-dot path segment must be ".." or an ASCII case-insensitive
4560  * match for ".%2e", "%2e.", or "%2e%2e".
4561  */
4562 ada_really_inline ada_constexpr bool is_double_dot_path_segment(
4563     std::string_view input) noexcept;
4564 
4565 /**
4566  * @details A single-dot path segment must be "." or an ASCII case-insensitive
4567  * match for "%2e".
4568  */
4569 ada_really_inline constexpr bool is_single_dot_path_segment(
4570     std::string_view input) noexcept;
4571 
4572 /**
4573  * @details ipv4 character might contain 0-9 or a-f character ranges.
4574  */
4575 ada_really_inline constexpr bool is_lowercase_hex(char c) noexcept;
4576 
4577 /**
4578  * @details Convert hex to binary. Caller is responsible to ensure that
4579  * the parameter is an hexadecimal digit (0-9, A-F, a-f).
4580  */
4581 ada_really_inline unsigned constexpr convert_hex_to_binary(char c) noexcept;
4582 
4583 /**
4584  * first_percent should be  = input.find('%')
4585  *
4586  * @todo It would be faster as noexcept maybe, but it could be unsafe since.
4587  * @author Node.js
4588  * @see https://github.com/nodejs/node/blob/main/src/node_url.cc#L245
4589  * @see https://encoding.spec.whatwg.org/#utf-8-decode-without-bom
4590  */
4591 std::string percent_decode(std::string_view input, size_t first_percent);
4592 
4593 /**
4594  * Returns a percent-encoding string whether percent encoding was needed or not.
4595  * @see https://github.com/nodejs/node/blob/main/src/node_url.cc#L226
4596  */
4597 std::string percent_encode(std::string_view input,
4598                            const uint8_t character_set[]);
4599 /**
4600  * Returns a percent-encoded string version of input, while starting the percent
4601  * encoding at the provided index.
4602  * @see https://github.com/nodejs/node/blob/main/src/node_url.cc#L226
4603  */
4604 std::string percent_encode(std::string_view input,
4605                            const uint8_t character_set[], size_t index);
4606 /**
4607  * Returns true if percent encoding was needed, in which case, we store
4608  * the percent-encoded content in 'out'. If the boolean 'append' is set to
4609  * true, the content is appended to 'out'.
4610  * If percent encoding is not needed, out is left unchanged.
4611  * @see https://github.com/nodejs/node/blob/main/src/node_url.cc#L226
4612  */
4613 template <bool append>
4614 bool percent_encode(std::string_view input, const uint8_t character_set[],
4615                     std::string& out);
4616 /**
4617  * Returns the index at which percent encoding should start, or (equivalently),
4618  * the length of the prefix that does not require percent encoding.
4619  */
4620 ada_really_inline size_t percent_encode_index(std::string_view input,
4621                                               const uint8_t character_set[]);
4622 /**
4623  * Lowers the string in-place, assuming that the content is ASCII.
4624  * Return true if the content was ASCII.
4625  */
4626 constexpr bool to_lower_ascii(char* input, size_t length) noexcept;
4627 }  // namespace ada::unicode
4628 
4629 #endif  // ADA_UNICODE_H
4630 /* end file include/ada/unicode.h */
4631 /* begin file include/ada/url_base-inl.h */
4632 /**
4633  * @file url_base-inl.h
4634  * @brief Inline functions for url base
4635  */
4636 #ifndef ADA_URL_BASE_INL_H
4637 #define ADA_URL_BASE_INL_H
4638 
4639 /* begin file include/ada/url_aggregator.h */
4640 /**
4641  * @file url_aggregator.h
4642  * @brief Declaration for the basic URL definitions
4643  */
4644 #ifndef ADA_URL_AGGREGATOR_H
4645 #define ADA_URL_AGGREGATOR_H
4646 
4647 
4648 #include <string>
4649 #include <string_view>
4650 
4651 namespace ada {
4652 
4653 /**
4654  * @brief Lightweight URL struct.
4655  *
4656  * @details The url_aggregator class aims to minimize temporary memory
4657  * allocation while representing a parsed URL. Internally, it contains a single
4658  * normalized URL (the href), and it makes available the components, mostly
4659  * using std::string_view.
4660  */
4661 struct url_aggregator : url_base {
4662   url_aggregator() = default;
4663   url_aggregator(const url_aggregator &u) = default;
4664   url_aggregator(url_aggregator &&u) noexcept = default;
4665   url_aggregator &operator=(url_aggregator &&u) noexcept = default;
4666   url_aggregator &operator=(const url_aggregator &u) = default;
4667   ~url_aggregator() override = default;
4668 
4669   bool set_href(std::string_view input);
4670   bool set_host(std::string_view input);
4671   bool set_hostname(std::string_view input);
4672   bool set_protocol(std::string_view input);
4673   bool set_username(std::string_view input);
4674   bool set_password(std::string_view input);
4675   bool set_port(std::string_view input);
4676   bool set_pathname(std::string_view input);
4677   void set_search(std::string_view input);
4678   void set_hash(std::string_view input);
4679 
4680   [[nodiscard]] bool has_valid_domain() const noexcept override;
4681   /**
4682    * The origin getter steps are to return the serialization of this's URL's
4683    * origin. [HTML]
4684    * @return a newly allocated string.
4685    * @see https://url.spec.whatwg.org/#concept-url-origin
4686    */
4687   [[nodiscard]] std::string get_origin() const noexcept override;
4688   /**
4689    * Return the normalized string.
4690    * This function does not allocate memory.
4691    * It is highly efficient.
4692    * @return a constant reference to the underlying normalized URL.
4693    * @see https://url.spec.whatwg.org/#dom-url-href
4694    * @see https://url.spec.whatwg.org/#concept-url-serializer
4695    */
4696   [[nodiscard]] inline std::string_view get_href() const noexcept;
4697   /**
4698    * The username getter steps are to return this's URL's username.
4699    * This function does not allocate memory.
4700    * @return a lightweight std::string_view.
4701    * @see https://url.spec.whatwg.org/#dom-url-username
4702    */
4703   [[nodiscard]] std::string_view get_username() const noexcept;
4704   /**
4705    * The password getter steps are to return this's URL's password.
4706    * This function does not allocate memory.
4707    * @return a lightweight std::string_view.
4708    * @see https://url.spec.whatwg.org/#dom-url-password
4709    */
4710   [[nodiscard]] std::string_view get_password() const noexcept;
4711   /**
4712    * Return this's URL's port, serialized.
4713    * This function does not allocate memory.
4714    * @return a lightweight std::string_view.
4715    * @see https://url.spec.whatwg.org/#dom-url-port
4716    */
4717   [[nodiscard]] std::string_view get_port() const noexcept;
4718   /**
4719    * Return U+0023 (#), followed by this's URL's fragment.
4720    * This function does not allocate memory.
4721    * @return a lightweight std::string_view..
4722    * @see https://url.spec.whatwg.org/#dom-url-hash
4723    */
4724   [[nodiscard]] std::string_view get_hash() const noexcept;
4725   /**
4726    * Return url's host, serialized, followed by U+003A (:) and url's port,
4727    * serialized.
4728    * This function does not allocate memory.
4729    * When there is no host, this function returns the empty view.
4730    * @return a lightweight std::string_view.
4731    * @see https://url.spec.whatwg.org/#dom-url-host
4732    */
4733   [[nodiscard]] std::string_view get_host() const noexcept;
4734   /**
4735    * Return this's URL's host, serialized.
4736    * This function does not allocate memory.
4737    * When there is no host, this function returns the empty view.
4738    * @return a lightweight std::string_view.
4739    * @see https://url.spec.whatwg.org/#dom-url-hostname
4740    */
4741   [[nodiscard]] std::string_view get_hostname() const noexcept;
4742   /**
4743    * The pathname getter steps are to return the result of URL path serializing
4744    * this's URL.
4745    * This function does not allocate memory.
4746    * @return a lightweight std::string_view.
4747    * @see https://url.spec.whatwg.org/#dom-url-pathname
4748    */
4749   [[nodiscard]] std::string_view get_pathname() const noexcept;
4750   /**
4751    * Compute the pathname length in bytes without instantiating a view or a
4752    * string.
4753    * @return size of the pathname in bytes
4754    * @see https://url.spec.whatwg.org/#dom-url-pathname
4755    */
4756   [[nodiscard]] ada_really_inline uint32_t get_pathname_length() const noexcept;
4757   /**
4758    * Return U+003F (?), followed by this's URL's query.
4759    * This function does not allocate memory.
4760    * @return a lightweight std::string_view.
4761    * @see https://url.spec.whatwg.org/#dom-url-search
4762    */
4763   [[nodiscard]] std::string_view get_search() const noexcept;
4764   /**
4765    * The protocol getter steps are to return this's URL's scheme, followed by
4766    * U+003A (:).
4767    * This function does not allocate memory.
4768    * @return a lightweight std::string_view.
4769    * @see https://url.spec.whatwg.org/#dom-url-protocol
4770    */
4771   [[nodiscard]] std::string_view get_protocol() const noexcept;
4772 
4773   /**
4774    * A URL includes credentials if its username or password is not the empty
4775    * string.
4776    */
4777   [[nodiscard]] ada_really_inline bool has_credentials() const noexcept;
4778 
4779   /**
4780    * Useful for implementing efficient serialization for the URL.
4781    *
4782    * https://user:pass@example.com:1234/foo/bar?baz#quux
4783    *       |     |    |          | ^^^^|       |   |
4784    *       |     |    |          | |   |       |   `----- hash_start
4785    *       |     |    |          | |   |       `--------- search_start
4786    *       |     |    |          | |   `----------------- pathname_start
4787    *       |     |    |          | `--------------------- port
4788    *       |     |    |          `----------------------- host_end
4789    *       |     |    `---------------------------------- host_start
4790    *       |     `--------------------------------------- username_end
4791    *       `--------------------------------------------- protocol_end
4792    *
4793    * Inspired after servo/url
4794    *
4795    * @return a constant reference to the underlying component attribute.
4796    *
4797    * @see
4798    * https://github.com/servo/rust-url/blob/b65a45515c10713f6d212e6726719a020203cc98/url/src/quirks.rs#L31
4799    */
4800   [[nodiscard]] ada_really_inline const ada::url_components &get_components()
4801       const noexcept;
4802   /**
4803    * Returns a string representation of this URL.
4804    */
4805   [[nodiscard]] std::string to_string() const override;
4806   /**
4807    * Returns a string diagram of this URL.
4808    */
4809   [[nodiscard]] std::string to_diagram() const;
4810 
4811   /**
4812    * Verifies that the parsed URL could be valid. Useful for debugging purposes.
4813    * @return true if the URL is valid, otherwise return true of the offsets are
4814    * possible.
4815    */
4816   [[nodiscard]] bool validate() const noexcept;
4817 
4818   /** @return true if it has an host but it is the empty string */
4819   [[nodiscard]] inline bool has_empty_hostname() const noexcept;
4820   /** @return true if it has a host (included an empty host) */
4821   [[nodiscard]] inline bool has_hostname() const noexcept;
4822   /** @return true if the URL has a non-empty username */
4823   [[nodiscard]] inline bool has_non_empty_username() const noexcept;
4824   /** @return true if the URL has a non-empty password */
4825   [[nodiscard]] inline bool has_non_empty_password() const noexcept;
4826   /** @return true if the URL has a (non default) port */
4827   [[nodiscard]] inline bool has_port() const noexcept;
4828   /** @return true if the URL has a password */
4829   [[nodiscard]] inline bool has_password() const noexcept;
4830   /** @return true if the URL has a hash component */
4831   [[nodiscard]] inline bool has_hash() const noexcept override;
4832   /** @return true if the URL has a search component */
4833   [[nodiscard]] inline bool has_search() const noexcept override;
4834 
4835   inline void clear_port();
4836   inline void clear_hash();
4837   inline void clear_search() override;
4838 
4839  private:
4840   friend ada::url_aggregator ada::parser::parse_url<ada::url_aggregator>(
4841       std::string_view, const ada::url_aggregator *);
4842   friend void ada::helpers::strip_trailing_spaces_from_opaque_path<
4843       ada::url_aggregator>(ada::url_aggregator &url) noexcept;
4844 
4845   std::string buffer{};
4846   url_components components{};
4847 
4848   /**
4849    * Returns true if neither the search, nor the hash nor the pathname
4850    * have been set.
4851    * @return true if the buffer is ready to receive the path.
4852    */
4853   [[nodiscard]] ada_really_inline bool is_at_path() const noexcept;
4854 
4855   inline void add_authority_slashes_if_needed() noexcept;
4856 
4857   /**
4858    * To optimize performance, you may indicate how much memory to allocate
4859    * within this instance.
4860    */
4861   inline void reserve(uint32_t capacity);
4862 
4863   ada_really_inline size_t parse_port(
4864       std::string_view view, bool check_trailing_content) noexcept override;
4865 
4866   ada_really_inline size_t parse_port(std::string_view view) noexcept override {
4867     return this->parse_port(view, false);
4868   }
4869 
4870   /**
4871    * Return true on success. The 'in_place' parameter indicates whether the
4872    * the string_view input is pointing in the buffer. When in_place is false,
4873    * we must nearly always update the buffer.
4874    * @see https://url.spec.whatwg.org/#concept-ipv4-parser
4875    */
4876   [[nodiscard]] bool parse_ipv4(std::string_view input, bool in_place);
4877 
4878   /**
4879    * Return true on success.
4880    * @see https://url.spec.whatwg.org/#concept-ipv6-parser
4881    */
4882   [[nodiscard]] bool parse_ipv6(std::string_view input);
4883 
4884   /**
4885    * Return true on success.
4886    * @see https://url.spec.whatwg.org/#concept-opaque-host-parser
4887    */
4888   [[nodiscard]] bool parse_opaque_host(std::string_view input);
4889 
4890   ada_really_inline void parse_path(std::string_view input);
4891 
4892   /**
4893    * A URL cannot have a username/password/port if its host is null or the empty
4894    * string, or its scheme is "file".
4895    */
4896   [[nodiscard]] inline bool cannot_have_credentials_or_port() const;
4897 
4898   template <bool override_hostname = false>
4899   bool set_host_or_hostname(std::string_view input);
4900 
4901   ada_really_inline bool parse_host(std::string_view input);
4902 
4903   inline void update_base_authority(std::string_view base_buffer,
4904                                     const ada::url_components &base);
4905   inline void update_unencoded_base_hash(std::string_view input);
4906   inline void update_base_hostname(std::string_view input);
4907   inline void update_base_search(std::string_view input);
4908   inline void update_base_search(std::string_view input,
4909                                  const uint8_t *query_percent_encode_set);
4910   inline void update_base_pathname(std::string_view input);
4911   inline void update_base_username(std::string_view input);
4912   inline void append_base_username(std::string_view input);
4913   inline void update_base_password(std::string_view input);
4914   inline void append_base_password(std::string_view input);
4915   inline void update_base_port(uint32_t input);
4916   inline void append_base_pathname(std::string_view input);
4917   [[nodiscard]] inline uint32_t retrieve_base_port() const;
4918   inline void clear_hostname();
4919   inline void clear_password();
4920   inline void clear_pathname() override;
4921   [[nodiscard]] inline bool has_dash_dot() const noexcept;
4922   void delete_dash_dot();
4923   inline void consume_prepared_path(std::string_view input);
4924   template <bool has_state_override = false>
4925   [[nodiscard]] ada_really_inline bool parse_scheme_with_colon(
4926       std::string_view input);
4927   ada_really_inline uint32_t replace_and_resize(uint32_t start, uint32_t end,
4928                                                 std::string_view input);
4929   [[nodiscard]] inline bool has_authority() const noexcept;
4930   inline void set_protocol_as_file();
4931   inline void set_scheme(std::string_view new_scheme) noexcept;
4932   /**
4933    * Fast function to set the scheme from a view with a colon in the
4934    * buffer, does not change type.
4935    */
4936   inline void set_scheme_from_view_with_colon(
4937       std::string_view new_scheme_with_colon) noexcept;
4938   inline void copy_scheme(const url_aggregator &u) noexcept;
4939 
4940 };  // url_aggregator
4941 
4942 inline std::ostream &operator<<(std::ostream &out, const ada::url &u);
4943 }  // namespace ada
4944 
4945 #endif
4946 /* end file include/ada/url_aggregator.h */
4947 /* begin file include/ada/checkers.h */
4948 /**
4949  * @file checkers.h
4950  * @brief Declarations for URL specific checkers used within Ada.
4951  */
4952 #ifndef ADA_CHECKERS_H
4953 #define ADA_CHECKERS_H
4954 
4955 
4956 #include <string_view>
4957 #include <cstring>
4958 
4959 /**
4960  * @namespace ada::checkers
4961  * @brief Includes the definitions for validation functions
4962  */
4963 namespace ada::checkers {
4964 
4965 /**
4966  * Assuming that x is an ASCII letter, this function returns the lower case
4967  * equivalent.
4968  * @details More likely to be inlined by the compiler and constexpr.
4969  */
4970 constexpr char to_lower(char x) noexcept;
4971 
4972 /**
4973  * Returns true if the character is an ASCII letter. Equivalent to std::isalpha
4974  * but more likely to be inlined by the compiler.
4975  *
4976  * @attention std::isalpha is not constexpr generally.
4977  */
4978 constexpr bool is_alpha(char x) noexcept;
4979 
4980 /**
4981  * Check whether a string starts with 0x or 0X. The function is only
4982  * safe if input.size() >=2.
4983  *
4984  * @see has_hex_prefix
4985  */
4986 inline bool has_hex_prefix_unsafe(std::string_view input);
4987 /**
4988  * Check whether a string starts with 0x or 0X.
4989  */
4990 inline bool has_hex_prefix(std::string_view input);
4991 
4992 /**
4993  * Check whether x is an ASCII digit. More likely to be inlined than
4994  * std::isdigit.
4995  */
4996 constexpr bool is_digit(char x) noexcept;
4997 
4998 /**
4999  * @details A string starts with a Windows drive letter if all of the following
5000  * are true:
5001  *
5002  *   - its length is greater than or equal to 2
5003  *   - its first two code points are a Windows drive letter
5004  *   - its length is 2 or its third code point is U+002F (/), U+005C (\), U+003F
5005  * (?), or U+0023 (#).
5006  *
5007  * https://url.spec.whatwg.org/#start-with-a-windows-drive-letter
5008  */
5009 inline constexpr bool is_windows_drive_letter(std::string_view input) noexcept;
5010 
5011 /**
5012  * @details A normalized Windows drive letter is a Windows drive letter of which
5013  * the second code point is U+003A (:).
5014  */
5015 inline constexpr bool is_normalized_windows_drive_letter(
5016     std::string_view input) noexcept;
5017 
5018 /**
5019  * @warning Will be removed when Ada requires C++20.
5020  */
5021 ada_really_inline bool begins_with(std::string_view view,
5022                                    std::string_view prefix);
5023 
5024 /**
5025  * Returns true if an input is an ipv4 address. It is assumed that the string
5026  * does not contain uppercase ASCII characters (the input should have been
5027  * lowered cased before calling this function) and is not empty.
5028  */
5029 ada_really_inline ada_constexpr bool is_ipv4(std::string_view view) noexcept;
5030 
5031 /**
5032  * Returns a bitset. If the first bit is set, then at least one character needs
5033  * percent encoding. If the second bit is set, a \\ is found. If the third bit
5034  * is set then we have a dot. If the fourth bit is set, then we have a percent
5035  * character.
5036  */
5037 ada_really_inline constexpr uint8_t path_signature(
5038     std::string_view input) noexcept;
5039 
5040 /**
5041  * Returns true if the length of the domain name and its labels are according to
5042  * the specifications. The length of the domain must be 255 octets (253
5043  * characters not including the last 2 which are the empty label reserved at the
5044  * end). When the empty label is included (a dot at the end), the domain name
5045  * can have 254 characters. The length of a label must be at least 1 and at most
5046  * 63 characters.
5047  * @see section 3.1. of https://www.rfc-editor.org/rfc/rfc1034
5048  * @see https://www.unicode.org/reports/tr46/#ToASCII
5049  */
5050 ada_really_inline constexpr bool verify_dns_length(
5051     std::string_view input) noexcept;
5052 
5053 }  // namespace ada::checkers
5054 
5055 #endif  // ADA_CHECKERS_H
5056 /* end file include/ada/checkers.h */
5057 /* begin file include/ada/url.h */
5058 /**
5059  * @file url.h
5060  * @brief Declaration for the URL
5061  */
5062 #ifndef ADA_URL_H
5063 #define ADA_URL_H
5064 
5065 
5066 #include <algorithm>
5067 #include <charconv>
5068 #include <iostream>
5069 #include <optional>
5070 #include <string>
5071 #include <string_view>
5072 
5073 namespace ada {
5074 
5075 /**
5076  * @brief Generic URL struct reliant on std::string instantiation.
5077  *
5078  * @details To disambiguate from a valid URL string it can also be referred to
5079  * as a URL record. A URL is a struct that represents a universal identifier.
5080  * Unlike the url_aggregator, the ada::url represents the different components
5081  * of a parsed URL as independent std::string instances. This makes the
5082  * structure heavier and more reliant on memory allocations. When getting
5083  * components from the parsed URL, a new std::string is typically constructed.
5084  *
5085  * @see https://url.spec.whatwg.org/#url-representation
5086  */
5087 struct url : url_base {
5088   url() = default;
5089   url(const url &u) = default;
5090   url(url &&u) noexcept = default;
5091   url &operator=(url &&u) noexcept = default;
5092   url &operator=(const url &u) = default;
5093   ~url() override = default;
5094 
5095   /**
5096    * @private
5097    * A URL's username is an ASCII string identifying a username. It is initially
5098    * the empty string.
5099    */
5100   std::string username{};
5101 
5102   /**
5103    * @private
5104    * A URL's password is an ASCII string identifying a password. It is initially
5105    * the empty string.
5106    */
5107   std::string password{};
5108 
5109   /**
5110    * @private
5111    * A URL's host is null or a host. It is initially null.
5112    */
5113   std::optional<std::string> host{};
5114 
5115   /**
5116    * @private
5117    * A URL's port is either null or a 16-bit unsigned integer that identifies a
5118    * networking port. It is initially null.
5119    */
5120   std::optional<uint16_t> port{};
5121 
5122   /**
5123    * @private
5124    * A URL's path is either an ASCII string or a list of zero or more ASCII
5125    * strings, usually identifying a location.
5126    */
5127   std::string path{};
5128 
5129   /**
5130    * @private
5131    * A URL's query is either null or an ASCII string. It is initially null.
5132    */
5133   std::optional<std::string> query{};
5134 
5135   /**
5136    * @private
5137    * A URL's fragment is either null or an ASCII string that can be used for
5138    * further processing on the resource the URL's other components identify. It
5139    * is initially null.
5140    */
5141   std::optional<std::string> hash{};
5142 
5143   /** @return true if it has an host but it is the empty string */
5144   [[nodiscard]] inline bool has_empty_hostname() const noexcept;
5145   /** @return true if the URL has a (non default) port */
5146   [[nodiscard]] inline bool has_port() const noexcept;
5147   /** @return true if it has a host (included an empty host) */
5148   [[nodiscard]] inline bool has_hostname() const noexcept;
5149   [[nodiscard]] bool has_valid_domain() const noexcept override;
5150 
5151   /**
5152    * Returns a JSON string representation of this URL.
5153    */
5154   [[nodiscard]] std::string to_string() const override;
5155 
5156   /**
5157    * @see https://url.spec.whatwg.org/#dom-url-href
5158    * @see https://url.spec.whatwg.org/#concept-url-serializer
5159    */
5160   [[nodiscard]] ada_really_inline std::string get_href() const noexcept;
5161 
5162   /**
5163    * The origin getter steps are to return the serialization of this's URL's
5164    * origin. [HTML]
5165    * @return a newly allocated string.
5166    * @see https://url.spec.whatwg.org/#concept-url-origin
5167    */
5168   [[nodiscard]] std::string get_origin() const noexcept override;
5169 
5170   /**
5171    * The protocol getter steps are to return this's URL's scheme, followed by
5172    * U+003A (:).
5173    * @return a newly allocated string.
5174    * @see https://url.spec.whatwg.org/#dom-url-protocol
5175    */
5176   [[nodiscard]] std::string get_protocol() const noexcept;
5177 
5178   /**
5179    * Return url's host, serialized, followed by U+003A (:) and url's port,
5180    * serialized.
5181    * When there is no host, this function returns the empty string.
5182    * @return a newly allocated string.
5183    * @see https://url.spec.whatwg.org/#dom-url-host
5184    */
5185   [[nodiscard]] std::string get_host() const noexcept;
5186 
5187   /**
5188    * Return this's URL's host, serialized.
5189    * When there is no host, this function returns the empty string.
5190    * @return a newly allocated string.
5191    * @see https://url.spec.whatwg.org/#dom-url-hostname
5192    */
5193   [[nodiscard]] std::string get_hostname() const noexcept;
5194 
5195   /**
5196    * The pathname getter steps are to return the result of URL path serializing
5197    * this's URL.
5198    * @return a newly allocated string.
5199    * @see https://url.spec.whatwg.org/#dom-url-pathname
5200    */
5201   [[nodiscard]] std::string_view get_pathname() const noexcept;
5202 
5203   /**
5204    * Compute the pathname length in bytes without instantiating a view or a
5205    * string.
5206    * @return size of the pathname in bytes
5207    * @see https://url.spec.whatwg.org/#dom-url-pathname
5208    */
5209   [[nodiscard]] ada_really_inline size_t get_pathname_length() const noexcept;
5210 
5211   /**
5212    * Return U+003F (?), followed by this's URL's query.
5213    * @return a newly allocated string.
5214    * @see https://url.spec.whatwg.org/#dom-url-search
5215    */
5216   [[nodiscard]] std::string get_search() const noexcept;
5217 
5218   /**
5219    * The username getter steps are to return this's URL's username.
5220    * @return a constant reference to the underlying string.
5221    * @see https://url.spec.whatwg.org/#dom-url-username
5222    */
5223   [[nodiscard]] const std::string &get_username() const noexcept;
5224 
5225   /**
5226    * @return Returns true on successful operation.
5227    * @see https://url.spec.whatwg.org/#dom-url-username
5228    */
5229   bool set_username(std::string_view input);
5230 
5231   /**
5232    * @return Returns true on success.
5233    * @see https://url.spec.whatwg.org/#dom-url-password
5234    */
5235   bool set_password(std::string_view input);
5236 
5237   /**
5238    * @return Returns true on success.
5239    * @see https://url.spec.whatwg.org/#dom-url-port
5240    */
5241   bool set_port(std::string_view input);
5242 
5243   /**
5244    * This function always succeeds.
5245    * @see https://url.spec.whatwg.org/#dom-url-hash
5246    */
5247   void set_hash(std::string_view input);
5248 
5249   /**
5250    * This function always succeeds.
5251    * @see https://url.spec.whatwg.org/#dom-url-search
5252    */
5253   void set_search(std::string_view input);
5254 
5255   /**
5256    * @return Returns true on success.
5257    * @see https://url.spec.whatwg.org/#dom-url-search
5258    */
5259   bool set_pathname(std::string_view input);
5260 
5261   /**
5262    * @return Returns true on success.
5263    * @see https://url.spec.whatwg.org/#dom-url-host
5264    */
5265   bool set_host(std::string_view input);
5266 
5267   /**
5268    * @return Returns true on success.
5269    * @see https://url.spec.whatwg.org/#dom-url-hostname
5270    */
5271   bool set_hostname(std::string_view input);
5272 
5273   /**
5274    * @return Returns true on success.
5275    * @see https://url.spec.whatwg.org/#dom-url-protocol
5276    */
5277   bool set_protocol(std::string_view input);
5278 
5279   /**
5280    * @see https://url.spec.whatwg.org/#dom-url-href
5281    */
5282   bool set_href(std::string_view input);
5283 
5284   /**
5285    * The password getter steps are to return this's URL's password.
5286    * @return a constant reference to the underlying string.
5287    * @see https://url.spec.whatwg.org/#dom-url-password
5288    */
5289   [[nodiscard]] const std::string &get_password() const noexcept;
5290 
5291   /**
5292    * Return this's URL's port, serialized.
5293    * @return a newly constructed string representing the port.
5294    * @see https://url.spec.whatwg.org/#dom-url-port
5295    */
5296   [[nodiscard]] std::string get_port() const noexcept;
5297 
5298   /**
5299    * Return U+0023 (#), followed by this's URL's fragment.
5300    * @return a newly constructed string representing the hash.
5301    * @see https://url.spec.whatwg.org/#dom-url-hash
5302    */
5303   [[nodiscard]] std::string get_hash() const noexcept;
5304 
5305   /**
5306    * A URL includes credentials if its username or password is not the empty
5307    * string.
5308    */
5309   [[nodiscard]] ada_really_inline bool has_credentials() const noexcept;
5310 
5311   /**
5312    * Useful for implementing efficient serialization for the URL.
5313    *
5314    * https://user:pass@example.com:1234/foo/bar?baz#quux
5315    *       |     |    |          | ^^^^|       |   |
5316    *       |     |    |          | |   |       |   `----- hash_start
5317    *       |     |    |          | |   |       `--------- search_start
5318    *       |     |    |          | |   `----------------- pathname_start
5319    *       |     |    |          | `--------------------- port
5320    *       |     |    |          `----------------------- host_end
5321    *       |     |    `---------------------------------- host_start
5322    *       |     `--------------------------------------- username_end
5323    *       `--------------------------------------------- protocol_end
5324    *
5325    * Inspired after servo/url
5326    *
5327    * @return a newly constructed component.
5328    *
5329    * @see
5330    * https://github.com/servo/rust-url/blob/b65a45515c10713f6d212e6726719a020203cc98/url/src/quirks.rs#L31
5331    */
5332   [[nodiscard]] ada_really_inline ada::url_components get_components()
5333       const noexcept;
5334   /** @return true if the URL has a hash component */
5335   [[nodiscard]] inline bool has_hash() const noexcept override;
5336   /** @return true if the URL has a search component */
5337   [[nodiscard]] inline bool has_search() const noexcept override;
5338 
5339  private:
5340   friend ada::url ada::parser::parse_url<ada::url>(std::string_view,
5341                                                    const ada::url *);
5342   friend ada::url_aggregator ada::parser::parse_url<ada::url_aggregator>(
5343       std::string_view, const ada::url_aggregator *);
5344   friend void ada::helpers::strip_trailing_spaces_from_opaque_path<ada::url>(
5345       ada::url &url) noexcept;
5346 
5347   inline void update_unencoded_base_hash(std::string_view input);
5348   inline void update_base_hostname(std::string_view input);
5349   inline void update_base_search(std::string_view input);
5350   inline void update_base_search(std::string_view input,
5351                                  const uint8_t query_percent_encode_set[]);
5352   inline void update_base_search(std::optional<std::string> input);
5353   inline void update_base_pathname(std::string_view input);
5354   inline void update_base_username(std::string_view input);
5355   inline void update_base_password(std::string_view input);
5356   inline void update_base_port(std::optional<uint16_t> input);
5357 
5358   /**
5359    * Sets the host or hostname according to override condition.
5360    * Return true on success.
5361    * @see https://url.spec.whatwg.org/#hostname-state
5362    */
5363   template <bool override_hostname = false>
5364   bool set_host_or_hostname(std::string_view input);
5365 
5366   /**
5367    * Return true on success.
5368    * @see https://url.spec.whatwg.org/#concept-ipv4-parser
5369    */
5370   [[nodiscard]] bool parse_ipv4(std::string_view input);
5371 
5372   /**
5373    * Return true on success.
5374    * @see https://url.spec.whatwg.org/#concept-ipv6-parser
5375    */
5376   [[nodiscard]] bool parse_ipv6(std::string_view input);
5377 
5378   /**
5379    * Return true on success.
5380    * @see https://url.spec.whatwg.org/#concept-opaque-host-parser
5381    */
5382   [[nodiscard]] bool parse_opaque_host(std::string_view input);
5383 
5384   /**
5385    * A URL's scheme is an ASCII string that identifies the type of URL and can
5386    * be used to dispatch a URL for further processing after parsing. It is
5387    * initially the empty string. We only set non_special_scheme when the scheme
5388    * is non-special, otherwise we avoid constructing string.
5389    *
5390    * Special schemes are stored in ada::scheme::details::is_special_list so we
5391    * typically do not need to store them in each url instance.
5392    */
5393   std::string non_special_scheme{};
5394 
5395   /**
5396    * A URL cannot have a username/password/port if its host is null or the empty
5397    * string, or its scheme is "file".
5398    */
5399   [[nodiscard]] inline bool cannot_have_credentials_or_port() const;
5400 
5401   ada_really_inline size_t parse_port(
5402       std::string_view view, bool check_trailing_content) noexcept override;
5403 
5404   ada_really_inline size_t parse_port(std::string_view view) noexcept override {
5405     return this->parse_port(view, false);
5406   }
5407 
5408   /**
5409    * Take the scheme from another URL. The scheme string is copied from the
5410    * provided url.
5411    */
5412   inline void copy_scheme(const ada::url &u);
5413 
5414   /**
5415    * Parse the host from the provided input. We assume that
5416    * the input does not contain spaces or tabs. Control
5417    * characters and spaces are not trimmed (they should have
5418    * been removed if needed).
5419    * Return true on success.
5420    * @see https://url.spec.whatwg.org/#host-parsing
5421    */
5422   [[nodiscard]] ada_really_inline bool parse_host(std::string_view input);
5423 
5424   template <bool has_state_override = false>
5425   [[nodiscard]] ada_really_inline bool parse_scheme(std::string_view input);
5426 
5427   inline void clear_pathname() override;
5428   inline void clear_search() override;
5429   inline void set_protocol_as_file();
5430 
5431   /**
5432    * Parse the path from the provided input.
5433    * Return true on success. Control characters not
5434    * trimmed from the ends (they should have
5435    * been removed if needed).
5436    *
5437    * The input is expected to be UTF-8.
5438    *
5439    * @see https://url.spec.whatwg.org/
5440    */
5441   ada_really_inline void parse_path(std::string_view input);
5442 
5443   /**
5444    * Set the scheme for this URL. The provided scheme should be a valid
5445    * scheme string, be lower-cased, not contain spaces or tabs. It should
5446    * have no spurious trailing or leading content.
5447    */
5448   inline void set_scheme(std::string &&new_scheme) noexcept;
5449 
5450   /**
5451    * Take the scheme from another URL. The scheme string is moved from the
5452    * provided url.
5453    */
5454   inline void copy_scheme(ada::url &&u) noexcept;
5455 
5456 };  // struct url
5457 
5458 inline std::ostream &operator<<(std::ostream &out, const ada::url &u);
5459 }  // namespace ada
5460 
5461 #endif  // ADA_URL_H
5462 /* end file include/ada/url.h */
5463 
5464 #include <optional>
5465 #include <string>
5466 #if ADA_REGULAR_VISUAL_STUDIO
5467 #include <intrin.h>
5468 #endif  // ADA_REGULAR_VISUAL_STUDIO
5469 
5470 namespace ada {
5471 
5472 [[nodiscard]] ada_really_inline bool url_base::is_special() const noexcept {
5473   return type != ada::scheme::NOT_SPECIAL;
5474 }
5475 
5476 [[nodiscard]] inline uint16_t url_base::get_special_port() const noexcept {
5477   return ada::scheme::get_special_port(type);
5478 }
5479 
5480 [[nodiscard]] ada_really_inline uint16_t
5481 url_base::scheme_default_port() const noexcept {
5482   return scheme::get_special_port(type);
5483 }
5484 
5485 }  // namespace ada
5486 
5487 #endif  // ADA_URL_BASE_INL_H
5488 /* end file include/ada/url_base-inl.h */
5489 /* begin file include/ada/url-inl.h */
5490 /**
5491  * @file url-inl.h
5492  * @brief Definitions for the URL
5493  */
5494 #ifndef ADA_URL_INL_H
5495 #define ADA_URL_INL_H
5496 
5497 
5498 #include <optional>
5499 #include <string>
5500 #if ADA_REGULAR_VISUAL_STUDIO
5501 #include <intrin.h>
5502 #endif  // ADA_REGULAR_VISUAL_STUDIO
5503 
5504 namespace ada {
5505 [[nodiscard]] ada_really_inline bool url::has_credentials() const noexcept {
5506   return !username.empty() || !password.empty();
5507 }
5508 [[nodiscard]] ada_really_inline bool url::has_port() const noexcept {
5509   return port.has_value();
5510 }
5511 [[nodiscard]] inline bool url::cannot_have_credentials_or_port() const {
5512   return !host.has_value() || host.value().empty() ||
5513          type == ada::scheme::type::FILE;
5514 }
5515 [[nodiscard]] inline bool url::has_empty_hostname() const noexcept {
5516   if (!host.has_value()) {
5517     return false;
5518   }
5519   return host.value().empty();
5520 }
5521 [[nodiscard]] inline bool url::has_hostname() const noexcept {
5522   return host.has_value();
5523 }
5524 inline std::ostream &operator<<(std::ostream &out, const ada::url &u) {
5525   return out << u.to_string();
5526 }
5527 
5528 [[nodiscard]] size_t url::get_pathname_length() const noexcept {
5529   return path.size();
5530 }
5531 
5532 [[nodiscard]] ada_really_inline ada::url_components url::get_components()
5533     const noexcept {
5534   url_components out{};
5535 
5536   // protocol ends with ':'. for example: "https:"
5537   out.protocol_end = uint32_t(get_protocol().size());
5538 
5539   // Trailing index is always the next character of the current one.
5540   size_t running_index = out.protocol_end;
5541 
5542   if (host.has_value()) {
5543     // 2 characters for "//" and 1 character for starting index
5544     out.host_start = out.protocol_end + 2;
5545 
5546     if (has_credentials()) {
5547       out.username_end = uint32_t(out.host_start + username.size());
5548 
5549       out.host_start += uint32_t(username.size());
5550 
5551       if (!password.empty()) {
5552         out.host_start += uint32_t(password.size() + 1);
5553       }
5554 
5555       out.host_end = uint32_t(out.host_start + host.value().size());
5556     } else {
5557       out.username_end = out.host_start;
5558 
5559       // Host does not start with "@" if it does not include credentials.
5560       out.host_end = uint32_t(out.host_start + host.value().size()) - 1;
5561     }
5562 
5563     running_index = out.host_end + 1;
5564   } else {
5565     // Update host start and end date to the same index, since it does not
5566     // exist.
5567     out.host_start = out.protocol_end;
5568     out.host_end = out.host_start;
5569 
5570     if (!has_opaque_path && checkers::begins_with(path, "//")) {
5571       // If url's host is null, url does not have an opaque path, url's path's
5572       // size is greater than 1, and url's path[0] is the empty string, then
5573       // append U+002F (/) followed by U+002E (.) to output.
5574       running_index = out.protocol_end + 2;
5575     } else {
5576       running_index = out.protocol_end;
5577     }
5578   }
5579 
5580   if (port.has_value()) {
5581     out.port = *port;
5582     running_index += helpers::fast_digit_count(*port) + 1;  // Port omits ':'
5583   }
5584 
5585   out.pathname_start = uint32_t(running_index);
5586 
5587   running_index += path.size();
5588 
5589   if (query.has_value()) {
5590     out.search_start = uint32_t(running_index);
5591     running_index += get_search().size();
5592     if (get_search().size() == 0) {
5593       running_index++;
5594     }
5595   }
5596 
5597   if (hash.has_value()) {
5598     out.hash_start = uint32_t(running_index);
5599   }
5600 
5601   return out;
5602 }
5603 
5604 inline void url::update_base_hostname(std::string_view input) { host = input; }
5605 
5606 inline void url::update_unencoded_base_hash(std::string_view input) {
5607   // We do the percent encoding
5608   hash = unicode::percent_encode(input,
5609                                  ada::character_sets::FRAGMENT_PERCENT_ENCODE);
5610 }
5611 
5612 inline void url::update_base_search(std::string_view input,
5613                                     const uint8_t query_percent_encode_set[]) {
5614   query = ada::unicode::percent_encode(input, query_percent_encode_set);
5615 }
5616 
5617 inline void url::update_base_search(std::optional<std::string> input) {
5618   query = input;
5619 }
5620 
5621 inline void url::update_base_pathname(const std::string_view input) {
5622   path = input;
5623 }
5624 
5625 inline void url::update_base_username(const std::string_view input) {
5626   username = input;
5627 }
5628 
5629 inline void url::update_base_password(const std::string_view input) {
5630   password = input;
5631 }
5632 
5633 inline void url::update_base_port(std::optional<uint16_t> input) {
5634   port = input;
5635 }
5636 
5637 inline void url::clear_pathname() { path.clear(); }
5638 
5639 inline void url::clear_search() { query = std::nullopt; }
5640 
5641 [[nodiscard]] inline bool url::has_hash() const noexcept {
5642   return hash.has_value();
5643 }
5644 
5645 [[nodiscard]] inline bool url::has_search() const noexcept {
5646   return query.has_value();
5647 }
5648 
5649 inline void url::set_protocol_as_file() { type = ada::scheme::type::FILE; }
5650 
5651 inline void url::set_scheme(std::string &&new_scheme) noexcept {
5652   type = ada::scheme::get_scheme_type(new_scheme);
5653   // We only move the 'scheme' if it is non-special.
5654   if (!is_special()) {
5655     non_special_scheme = new_scheme;
5656   }
5657 }
5658 
5659 inline void url::copy_scheme(ada::url &&u) noexcept {
5660   non_special_scheme = u.non_special_scheme;
5661   type = u.type;
5662 }
5663 
5664 inline void url::copy_scheme(const ada::url &u) {
5665   non_special_scheme = u.non_special_scheme;
5666   type = u.type;
5667 }
5668 
5669 [[nodiscard]] ada_really_inline std::string url::get_href() const noexcept {
5670   std::string output = get_protocol();
5671 
5672   if (host.has_value()) {
5673     output += "//";
5674     if (has_credentials()) {
5675       output += username;
5676       if (!password.empty()) {
5677         output += ":" + get_password();
5678       }
5679       output += "@";
5680     }
5681     output += host.value();
5682     if (port.has_value()) {
5683       output += ":" + get_port();
5684     }
5685   } else if (!has_opaque_path && checkers::begins_with(path, "//")) {
5686     // If url's host is null, url does not have an opaque path, url's path's
5687     // size is greater than 1, and url's path[0] is the empty string, then
5688     // append U+002F (/) followed by U+002E (.) to output.
5689     output += "/.";
5690   }
5691   output += path;
5692   if (query.has_value()) {
5693     output += "?" + query.value();
5694   }
5695   if (hash.has_value()) {
5696     output += "#" + hash.value();
5697   }
5698   return output;
5699 }
5700 
5701 ada_really_inline size_t url::parse_port(std::string_view view,
5702                                          bool check_trailing_content) noexcept {
5703   ada_log("parse_port('", view, "') ", view.size());
5704   uint16_t parsed_port{};
5705   auto r = std::from_chars(view.data(), view.data() + view.size(), parsed_port);
5706   if (r.ec == std::errc::result_out_of_range) {
5707     ada_log("parse_port: std::errc::result_out_of_range");
5708     is_valid = false;
5709     return 0;
5710   }
5711   ada_log("parse_port: ", parsed_port);
5712   const size_t consumed = size_t(r.ptr - view.data());
5713   ada_log("parse_port: consumed ", consumed);
5714   if (check_trailing_content) {
5715     is_valid &=
5716         (consumed == view.size() || view[consumed] == '/' ||
5717          view[consumed] == '?' || (is_special() && view[consumed] == '\\'));
5718   }
5719   ada_log("parse_port: is_valid = ", is_valid);
5720   if (is_valid) {
5721     // scheme_default_port can return 0, and we should allow 0 as a base port.
5722     auto default_port = scheme_default_port();
5723     bool is_port_valid = (default_port == 0 && parsed_port == 0) ||
5724                          (default_port != parsed_port);
5725     port = (r.ec == std::errc() && is_port_valid)
5726                ? std::optional<uint16_t>(parsed_port)
5727                : std::nullopt;
5728   }
5729   return consumed;
5730 }
5731 
5732 }  // namespace ada
5733 
5734 #endif  // ADA_URL_H
5735 /* end file include/ada/url-inl.h */
5736 /* begin file include/ada/url_aggregator-inl.h */
5737 /**
5738  * @file url_aggregator-inl.h
5739  * @brief Inline functions for url aggregator
5740  */
5741 #ifndef ADA_URL_AGGREGATOR_INL_H
5742 #define ADA_URL_AGGREGATOR_INL_H
5743 
5744 /* begin file include/ada/unicode-inl.h */
5745 /**
5746  * @file unicode-inl.h
5747  * @brief Definitions for unicode operations.
5748  */
5749 #ifndef ADA_UNICODE_INL_H
5750 #define ADA_UNICODE_INL_H
5751 #include <algorithm>
5752 
5753 /**
5754  * @namespace ada::unicode
5755  * @brief Includes the declarations for unicode operations
5756  */
5757 namespace ada::unicode {
5758 ada_really_inline size_t percent_encode_index(const std::string_view input,
5759                                               const uint8_t character_set[]) {
5760   return std::distance(
5761       input.begin(),
5762       std::find_if(input.begin(), input.end(), [character_set](const char c) {
5763         return character_sets::bit_at(character_set, c);
5764       }));
5765 }
5766 }  // namespace ada::unicode
5767 
5768 #endif  // ADA_UNICODE_INL_H
5769 /* end file include/ada/unicode-inl.h */
5770 
5771 #include <optional>
5772 #include <string_view>
5773 
5774 namespace ada {
5775 
5776 inline void url_aggregator::update_base_authority(
5777     std::string_view base_buffer, const ada::url_components &base) {
5778   std::string_view input = base_buffer.substr(
5779       base.protocol_end, base.host_start - base.protocol_end);
5780   ada_log("url_aggregator::update_base_authority ", input);
5781 
5782   bool input_starts_with_dash = checkers::begins_with(input, "//");
5783   uint32_t diff = components.host_start - components.protocol_end;
5784 
5785   buffer.erase(components.protocol_end,
5786                components.host_start - components.protocol_end);
5787   components.username_end = components.protocol_end;
5788 
5789   if (input_starts_with_dash) {
5790     input.remove_prefix(2);
5791     diff += 2;  // add "//"
5792     buffer.insert(components.protocol_end, "//");
5793     components.username_end += 2;
5794   }
5795 
5796   size_t password_delimiter = input.find(':');
5797 
5798   // Check if input contains both username and password by checking the
5799   // delimiter: ":" A typical input that contains authority would be "user:pass"
5800   if (password_delimiter != std::string_view::npos) {
5801     // Insert both username and password
5802     std::string_view username = input.substr(0, password_delimiter);
5803     std::string_view password = input.substr(password_delimiter + 1);
5804 
5805     buffer.insert(components.protocol_end + diff, username);
5806     diff += uint32_t(username.size());
5807     buffer.insert(components.protocol_end + diff, ":");
5808     components.username_end = components.protocol_end + diff;
5809     buffer.insert(components.protocol_end + diff + 1, password);
5810     diff += uint32_t(password.size()) + 1;
5811   } else if (!input.empty()) {
5812     // Insert only username
5813     buffer.insert(components.protocol_end + diff, input);
5814     components.username_end =
5815         components.protocol_end + diff + uint32_t(input.size());
5816     diff += uint32_t(input.size());
5817   }
5818 
5819   components.host_start += diff;
5820 
5821   if (buffer.size() > base.host_start && buffer[base.host_start] != '@') {
5822     buffer.insert(components.host_start, "@");
5823     diff++;
5824   }
5825   components.host_end += diff;
5826   components.pathname_start += diff;
5827   if (components.search_start != url_components::omitted) {
5828     components.search_start += diff;
5829   }
5830   if (components.hash_start != url_components::omitted) {
5831     components.hash_start += diff;
5832   }
5833 }
5834 
5835 inline void url_aggregator::update_unencoded_base_hash(std::string_view input) {
5836   ada_log("url_aggregator::update_unencoded_base_hash ", input, " [",
5837           input.size(), " bytes], buffer is '", buffer, "' [", buffer.size(),
5838           " bytes] components.hash_start = ", components.hash_start);
5839   ADA_ASSERT_TRUE(validate());
5840   ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
5841   if (components.hash_start != url_components::omitted) {
5842     buffer.resize(components.hash_start);
5843   }
5844   components.hash_start = uint32_t(buffer.size());
5845   buffer += "#";
5846   bool encoding_required = unicode::percent_encode<true>(
5847       input, ada::character_sets::FRAGMENT_PERCENT_ENCODE, buffer);
5848   // When encoding_required is false, then buffer is left unchanged, and percent
5849   // encoding was not deemed required.
5850   if (!encoding_required) {
5851     buffer.append(input);
5852   }
5853   ada_log("url_aggregator::update_unencoded_base_hash final buffer is '",
5854           buffer, "' [", buffer.size(), " bytes]");
5855   ADA_ASSERT_TRUE(validate());
5856 }
5857 
5858 ada_really_inline uint32_t url_aggregator::replace_and_resize(
5859     uint32_t start, uint32_t end, std::string_view input) {
5860   uint32_t current_length = end - start;
5861   uint32_t input_size = uint32_t(input.size());
5862   uint32_t new_difference = input_size - current_length;
5863 
5864   if (current_length == 0) {
5865     buffer.insert(start, input);
5866   } else if (input_size == current_length) {
5867     buffer.replace(start, input_size, input);
5868   } else if (input_size < current_length) {
5869     buffer.erase(start, current_length - input_size);
5870     buffer.replace(start, input_size, input);
5871   } else {
5872     buffer.replace(start, current_length, input.substr(0, current_length));
5873     buffer.insert(start + current_length, input.substr(current_length));
5874   }
5875 
5876   return new_difference;
5877 }
5878 
5879 inline void url_aggregator::update_base_hostname(const std::string_view input) {
5880   ada_log("url_aggregator::update_base_hostname ", input, " [", input.size(),
5881           " bytes], buffer is '", buffer, "' [", buffer.size(), " bytes]");
5882   ADA_ASSERT_TRUE(validate());
5883   ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
5884 
5885   // This next line is required for when parsing a URL like `foo://`
5886   add_authority_slashes_if_needed();
5887 
5888   bool has_credentials = components.protocol_end + 2 < components.host_start;
5889   uint32_t new_difference =
5890       replace_and_resize(components.host_start, components.host_end, input);
5891 
5892   if (has_credentials) {
5893     buffer.insert(components.host_start, "@");
5894     new_difference++;
5895   }
5896   components.host_end += new_difference;
5897   components.pathname_start += new_difference;
5898   if (components.search_start != url_components::omitted) {
5899     components.search_start += new_difference;
5900   }
5901   if (components.hash_start != url_components::omitted) {
5902     components.hash_start += new_difference;
5903   }
5904   ADA_ASSERT_TRUE(validate());
5905 }
5906 
5907 [[nodiscard]] ada_really_inline uint32_t
5908 url_aggregator::get_pathname_length() const noexcept {
5909   ada_log("url_aggregator::get_pathname_length");
5910   uint32_t ending_index = uint32_t(buffer.size());
5911   if (components.search_start != url_components::omitted) {
5912     ending_index = components.search_start;
5913   } else if (components.hash_start != url_components::omitted) {
5914     ending_index = components.hash_start;
5915   }
5916   return ending_index - components.pathname_start;
5917 }
5918 
5919 [[nodiscard]] ada_really_inline bool url_aggregator::is_at_path()
5920     const noexcept {
5921   return buffer.size() == components.pathname_start;
5922 }
5923 
5924 inline void url_aggregator::update_base_search(std::string_view input) {
5925   ada_log("url_aggregator::update_base_search ", input);
5926   ADA_ASSERT_TRUE(validate());
5927   ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
5928   if (input.empty()) {
5929     clear_search();
5930     return;
5931   }
5932 
5933   if (input[0] == '?') {
5934     input.remove_prefix(1);
5935   }
5936 
5937   if (components.hash_start == url_components::omitted) {
5938     if (components.search_start == url_components::omitted) {
5939       components.search_start = uint32_t(buffer.size());
5940       buffer += "?";
5941     } else {
5942       buffer.resize(components.search_start + 1);
5943     }
5944 
5945     buffer.append(input);
5946   } else {
5947     if (components.search_start == url_components::omitted) {
5948       components.search_start = components.hash_start;
5949     } else {
5950       buffer.erase(components.search_start,
5951                    components.hash_start - components.search_start);
5952       components.hash_start = components.search_start;
5953     }
5954 
5955     buffer.insert(components.search_start, "?");
5956     buffer.insert(components.search_start + 1, input);
5957     components.hash_start += uint32_t(input.size() + 1);  // Do not forget `?`
5958   }
5959 
5960   ADA_ASSERT_TRUE(validate());
5961 }
5962 
5963 inline void url_aggregator::update_base_search(
5964     std::string_view input, const uint8_t query_percent_encode_set[]) {
5965   ada_log("url_aggregator::update_base_search ", input,
5966           " with encoding parameter ", to_string(), "\n", to_diagram());
5967   ADA_ASSERT_TRUE(validate());
5968   ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
5969 
5970   if (components.hash_start == url_components::omitted) {
5971     if (components.search_start == url_components::omitted) {
5972       components.search_start = uint32_t(buffer.size());
5973       buffer += "?";
5974     } else {
5975       buffer.resize(components.search_start + 1);
5976     }
5977 
5978     bool encoding_required =
5979         unicode::percent_encode<true>(input, query_percent_encode_set, buffer);
5980     // When encoding_required is false, then buffer is left unchanged, and
5981     // percent encoding was not deemed required.
5982     if (!encoding_required) {
5983       buffer.append(input);
5984     }
5985   } else {
5986     if (components.search_start == url_components::omitted) {
5987       components.search_start = components.hash_start;
5988     } else {
5989       buffer.erase(components.search_start,
5990                    components.hash_start - components.search_start);
5991       components.hash_start = components.search_start;
5992     }
5993 
5994     buffer.insert(components.search_start, "?");
5995     size_t idx =
5996         ada::unicode::percent_encode_index(input, query_percent_encode_set);
5997     if (idx == input.size()) {
5998       buffer.insert(components.search_start + 1, input);
5999       components.hash_start += uint32_t(input.size() + 1);  // Do not forget `?`
6000     } else {
6001       buffer.insert(components.search_start + 1, input, 0, idx);
6002       input.remove_prefix(idx);
6003       // We only create a temporary string if we need percent encoding and
6004       // we attempt to create as small a temporary string as we can.
6005       std::string encoded =
6006           ada::unicode::percent_encode(input, query_percent_encode_set);
6007       buffer.insert(components.search_start + idx + 1, encoded);
6008       components.hash_start +=
6009           uint32_t(encoded.size() + idx + 1);  // Do not forget `?`
6010     }
6011   }
6012 
6013   ADA_ASSERT_TRUE(validate());
6014 }
6015 
6016 inline void url_aggregator::update_base_pathname(const std::string_view input) {
6017   ada_log("url_aggregator::update_base_pathname '", input, "' [", input.size(),
6018           " bytes] \n", to_diagram());
6019   ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
6020   ADA_ASSERT_TRUE(validate());
6021 
6022   const bool begins_with_dashdash = checkers::begins_with(input, "//");
6023   if (!begins_with_dashdash && has_dash_dot()) {
6024     ada_log("url_aggregator::update_base_pathname has /.: \n", to_diagram());
6025     // We must delete the ./
6026     delete_dash_dot();
6027   }
6028 
6029   if (begins_with_dashdash && !has_opaque_path && !has_authority() &&
6030       !has_dash_dot()) {
6031     // If url's host is null, url does not have an opaque path, url's path's
6032     // size is greater than 1, then append U+002F (/) followed by U+002E (.) to
6033     // output.
6034     buffer.insert(components.pathname_start, "/.");
6035     components.pathname_start += 2;
6036   }
6037 
6038   uint32_t difference = replace_and_resize(
6039       components.pathname_start,
6040       components.pathname_start + get_pathname_length(), input);
6041   if (components.search_start != url_components::omitted) {
6042     components.search_start += difference;
6043   }
6044   if (components.hash_start != url_components::omitted) {
6045     components.hash_start += difference;
6046   }
6047   ada_log("url_aggregator::update_base_pathname end '", input, "' [",
6048           input.size(), " bytes] \n", to_diagram());
6049   ADA_ASSERT_TRUE(validate());
6050 }
6051 
6052 inline void url_aggregator::append_base_pathname(const std::string_view input) {
6053   ada_log("url_aggregator::append_base_pathname ", input, " ", to_string(),
6054           "\n", to_diagram());
6055   ADA_ASSERT_TRUE(validate());
6056   ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
6057 #if ADA_DEVELOPMENT_CHECKS
6058   // computing the expected password.
6059   std::string path_expected = std::string(get_pathname());
6060   path_expected.append(input);
6061 #endif  // ADA_DEVELOPMENT_CHECKS
6062   uint32_t ending_index = uint32_t(buffer.size());
6063   if (components.search_start != url_components::omitted) {
6064     ending_index = components.search_start;
6065   } else if (components.hash_start != url_components::omitted) {
6066     ending_index = components.hash_start;
6067   }
6068   buffer.insert(ending_index, input);
6069 
6070   if (components.search_start != url_components::omitted) {
6071     components.search_start += uint32_t(input.size());
6072   }
6073   if (components.hash_start != url_components::omitted) {
6074     components.hash_start += uint32_t(input.size());
6075   }
6076 #if ADA_DEVELOPMENT_CHECKS
6077   std::string path_after = std::string(get_pathname());
6078   ADA_ASSERT_EQUAL(
6079       path_expected, path_after,
6080       "append_base_pathname problem after inserting " + std::string(input));
6081 #endif  // ADA_DEVELOPMENT_CHECKS
6082   ADA_ASSERT_TRUE(validate());
6083 }
6084 
6085 inline void url_aggregator::update_base_username(const std::string_view input) {
6086   ada_log("url_aggregator::update_base_username '", input, "' ", to_string(),
6087           "\n", to_diagram());
6088   ADA_ASSERT_TRUE(validate());
6089   ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
6090 
6091   add_authority_slashes_if_needed();
6092 
6093   bool has_password = has_non_empty_password();
6094   bool host_starts_with_at = buffer.size() > components.host_start &&
6095                              buffer[components.host_start] == '@';
6096   uint32_t diff = replace_and_resize(components.protocol_end + 2,
6097                                      components.username_end, input);
6098 
6099   components.username_end += diff;
6100   components.host_start += diff;
6101 
6102   if (!input.empty() && !host_starts_with_at) {
6103     buffer.insert(components.host_start, "@");
6104     diff++;
6105   } else if (input.empty() && host_starts_with_at && !has_password) {
6106     // Input is empty, there is no password, and we need to remove "@" from
6107     // hostname
6108     buffer.erase(components.host_start, 1);
6109     diff--;
6110   }
6111 
6112   components.host_end += diff;
6113   components.pathname_start += diff;
6114   if (components.search_start != url_components::omitted) {
6115     components.search_start += diff;
6116   }
6117   if (components.hash_start != url_components::omitted) {
6118     components.hash_start += diff;
6119   }
6120   ADA_ASSERT_TRUE(validate());
6121 }
6122 
6123 inline void url_aggregator::append_base_username(const std::string_view input) {
6124   ada_log("url_aggregator::append_base_username ", input);
6125   ADA_ASSERT_TRUE(validate());
6126   ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
6127 #if ADA_DEVELOPMENT_CHECKS
6128   // computing the expected password.
6129   std::string username_expected = std::string(get_username());
6130   username_expected.append(input);
6131 #endif  // ADA_DEVELOPMENT_CHECKS
6132   add_authority_slashes_if_needed();
6133 
6134   // If input is empty, do nothing.
6135   if (input.empty()) {
6136     return;
6137   }
6138 
6139   uint32_t difference = uint32_t(input.size());
6140   buffer.insert(components.username_end, input);
6141   components.username_end += difference;
6142   components.host_start += difference;
6143 
6144   if (buffer[components.host_start] != '@' &&
6145       components.host_start != components.host_end) {
6146     buffer.insert(components.host_start, "@");
6147     difference++;
6148   }
6149 
6150   components.host_end += difference;
6151   components.pathname_start += difference;
6152   if (components.search_start != url_components::omitted) {
6153     components.search_start += difference;
6154   }
6155   if (components.hash_start != url_components::omitted) {
6156     components.hash_start += difference;
6157   }
6158 #if ADA_DEVELOPMENT_CHECKS
6159   std::string username_after = std::string(get_username());
6160   ADA_ASSERT_EQUAL(
6161       username_expected, username_after,
6162       "append_base_username problem after inserting " + std::string(input));
6163 #endif  // ADA_DEVELOPMENT_CHECKS
6164   ADA_ASSERT_TRUE(validate());
6165 }
6166 
6167 inline void url_aggregator::clear_password() {
6168   ada_log("url_aggregator::clear_password ", to_string(), "\n", to_diagram());
6169   ADA_ASSERT_TRUE(validate());
6170   if (!has_password()) {
6171     return;
6172   }
6173 
6174   uint32_t diff = components.host_start - components.username_end;
6175   buffer.erase(components.username_end, diff);
6176   components.host_start -= diff;
6177   components.host_end -= diff;
6178   components.pathname_start -= diff;
6179   if (components.search_start != url_components::omitted) {
6180     components.search_start -= diff;
6181   }
6182   if (components.hash_start != url_components::omitted) {
6183     components.hash_start -= diff;
6184   }
6185 }
6186 
6187 inline void url_aggregator::update_base_password(const std::string_view input) {
6188   ada_log("url_aggregator::update_base_password ", input);
6189   ADA_ASSERT_TRUE(validate());
6190   ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
6191 
6192   add_authority_slashes_if_needed();
6193 
6194   // TODO: Optimization opportunity. Merge the following removal functions.
6195   if (input.empty()) {
6196     clear_password();
6197 
6198     // Remove username too, if it is empty.
6199     if (!has_non_empty_username()) {
6200       update_base_username("");
6201     }
6202 
6203     return;
6204   }
6205 
6206   bool password_exists = has_password();
6207   uint32_t difference = uint32_t(input.size());
6208 
6209   if (password_exists) {
6210     uint32_t current_length =
6211         components.host_start - components.username_end - 1;
6212     buffer.erase(components.username_end + 1, current_length);
6213     difference -= current_length;
6214   } else {
6215     buffer.insert(components.username_end, ":");
6216     difference++;
6217   }
6218 
6219   buffer.insert(components.username_end + 1, input);
6220   components.host_start += difference;
6221 
6222   // The following line is required to add "@" to hostname. When updating
6223   // password if hostname does not start with "@", it is "update_base_password"s
6224   // responsibility to set it.
6225   if (buffer[components.host_start] != '@') {
6226     buffer.insert(components.host_start, "@");
6227     difference++;
6228   }
6229 
6230   components.host_end += difference;
6231   components.pathname_start += difference;
6232   if (components.search_start != url_components::omitted) {
6233     components.search_start += difference;
6234   }
6235   if (components.hash_start != url_components::omitted) {
6236     components.hash_start += difference;
6237   }
6238   ADA_ASSERT_TRUE(validate());
6239 }
6240 
6241 inline void url_aggregator::append_base_password(const std::string_view input) {
6242   ada_log("url_aggregator::append_base_password ", input, " ", to_string(),
6243           "\n", to_diagram());
6244   ADA_ASSERT_TRUE(validate());
6245   ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
6246 #if ADA_DEVELOPMENT_CHECKS
6247   // computing the expected password.
6248   std::string password_expected = std::string(get_password());
6249   password_expected.append(input);
6250 #endif  // ADA_DEVELOPMENT_CHECKS
6251   add_authority_slashes_if_needed();
6252 
6253   // If input is empty, do nothing.
6254   if (input.empty()) {
6255     return;
6256   }
6257 
6258   uint32_t difference = uint32_t(input.size());
6259   if (has_password()) {
6260     buffer.insert(components.host_start, input);
6261   } else {
6262     difference++;  // Increment for ":"
6263     buffer.insert(components.username_end, ":");
6264     buffer.insert(components.username_end + 1, input);
6265   }
6266   components.host_start += difference;
6267 
6268   // The following line is required to add "@" to hostname. When updating
6269   // password if hostname does not start with "@", it is "append_base_password"s
6270   // responsibility to set it.
6271   if (buffer[components.host_start] != '@') {
6272     buffer.insert(components.host_start, "@");
6273     difference++;
6274   }
6275 
6276   components.host_end += difference;
6277   components.pathname_start += difference;
6278   if (components.search_start != url_components::omitted) {
6279     components.search_start += difference;
6280   }
6281   if (components.hash_start != url_components::omitted) {
6282     components.hash_start += difference;
6283   }
6284 #if ADA_DEVELOPMENT_CHECKS
6285   std::string password_after = std::string(get_password());
6286   ADA_ASSERT_EQUAL(
6287       password_expected, password_after,
6288       "append_base_password problem after inserting " + std::string(input));
6289 #endif  // ADA_DEVELOPMENT_CHECKS
6290   ADA_ASSERT_TRUE(validate());
6291 }
6292 
6293 inline void url_aggregator::update_base_port(uint32_t input) {
6294   ada_log("url_aggregator::update_base_port");
6295   ADA_ASSERT_TRUE(validate());
6296   if (input == url_components::omitted) {
6297     clear_port();
6298     return;
6299   }
6300   // calling std::to_string(input.value()) is unfortunate given that the port
6301   // value is probably already available as a string.
6302   std::string value = helpers::concat(":", std::to_string(input));
6303   uint32_t difference = uint32_t(value.size());
6304 
6305   if (components.port != url_components::omitted) {
6306     difference -= components.pathname_start - components.host_end;
6307     buffer.erase(components.host_end,
6308                  components.pathname_start - components.host_end);
6309   }
6310 
6311   buffer.insert(components.host_end, value);
6312   components.pathname_start += difference;
6313   if (components.search_start != url_components::omitted) {
6314     components.search_start += difference;
6315   }
6316   if (components.hash_start != url_components::omitted) {
6317     components.hash_start += difference;
6318   }
6319   components.port = input;
6320   ADA_ASSERT_TRUE(validate());
6321 }
6322 
6323 inline void url_aggregator::clear_port() {
6324   ada_log("url_aggregator::clear_port");
6325   ADA_ASSERT_TRUE(validate());
6326   if (components.port == url_components::omitted) {
6327     return;
6328   }
6329   uint32_t length = components.pathname_start - components.host_end;
6330   buffer.erase(components.host_end, length);
6331   components.pathname_start -= length;
6332   if (components.search_start != url_components::omitted) {
6333     components.search_start -= length;
6334   }
6335   if (components.hash_start != url_components::omitted) {
6336     components.hash_start -= length;
6337   }
6338   components.port = url_components::omitted;
6339   ADA_ASSERT_TRUE(validate());
6340 }
6341 
6342 [[nodiscard]] inline uint32_t url_aggregator::retrieve_base_port() const {
6343   ada_log("url_aggregator::retrieve_base_port");
6344   return components.port;
6345 }
6346 
6347 inline void url_aggregator::clear_search() {
6348   ada_log("url_aggregator::clear_search");
6349   ADA_ASSERT_TRUE(validate());
6350   if (components.search_start == url_components::omitted) {
6351     return;
6352   }
6353 
6354   if (components.hash_start == url_components::omitted) {
6355     buffer.resize(components.search_start);
6356   } else {
6357     buffer.erase(components.search_start,
6358                  components.hash_start - components.search_start);
6359     components.hash_start = components.search_start;
6360   }
6361 
6362   components.search_start = url_components::omitted;
6363 
6364 #if ADA_DEVELOPMENT_CHECKS
6365   ADA_ASSERT_EQUAL(get_search(), "",
6366                    "search should have been cleared on buffer=" + buffer +
6367                        " with " + components.to_string() + "\n" + to_diagram());
6368 #endif
6369   ADA_ASSERT_TRUE(validate());
6370 }
6371 
6372 inline void url_aggregator::clear_hash() {
6373   ada_log("url_aggregator::clear_hash");
6374   ADA_ASSERT_TRUE(validate());
6375   if (components.hash_start == url_components::omitted) {
6376     return;
6377   }
6378   buffer.resize(components.hash_start);
6379   components.hash_start = url_components::omitted;
6380 
6381 #if ADA_DEVELOPMENT_CHECKS
6382   ADA_ASSERT_EQUAL(get_hash(), "",
6383                    "hash should have been cleared on buffer=" + buffer +
6384                        " with " + components.to_string() + "\n" + to_diagram());
6385 #endif
6386   ADA_ASSERT_TRUE(validate());
6387 }
6388 
6389 inline void url_aggregator::clear_pathname() {
6390   ada_log("url_aggregator::clear_pathname");
6391   ADA_ASSERT_TRUE(validate());
6392   uint32_t ending_index = uint32_t(buffer.size());
6393   if (components.search_start != url_components::omitted) {
6394     ending_index = components.search_start;
6395   } else if (components.hash_start != url_components::omitted) {
6396     ending_index = components.hash_start;
6397   }
6398   uint32_t pathname_length = ending_index - components.pathname_start;
6399   buffer.erase(components.pathname_start, pathname_length);
6400   uint32_t difference = pathname_length;
6401   if (components.pathname_start == components.host_end + 2 &&
6402       buffer[components.host_end] == '/' &&
6403       buffer[components.host_end + 1] == '.') {
6404     components.pathname_start -= 2;
6405     buffer.erase(components.host_end, 2);
6406     difference += 2;
6407   }
6408   if (components.search_start != url_components::omitted) {
6409     components.search_start -= difference;
6410   }
6411   if (components.hash_start != url_components::omitted) {
6412     components.hash_start -= difference;
6413   }
6414   ada_log("url_aggregator::clear_pathname completed, running checks...");
6415 #if ADA_DEVELOPMENT_CHECKS
6416   ADA_ASSERT_EQUAL(get_pathname(), "",
6417                    "pathname should have been cleared on buffer=" + buffer +
6418                        " with " + components.to_string() + "\n" + to_diagram());
6419 #endif
6420   ADA_ASSERT_TRUE(validate());
6421   ada_log("url_aggregator::clear_pathname completed, running checks... ok");
6422 }
6423 
6424 inline void url_aggregator::clear_hostname() {
6425   ada_log("url_aggregator::clear_hostname");
6426   ADA_ASSERT_TRUE(validate());
6427   if (!has_authority()) {
6428     return;
6429   }
6430   ADA_ASSERT_TRUE(has_authority());
6431 
6432   uint32_t hostname_length = components.host_end - components.host_start;
6433   uint32_t start = components.host_start;
6434 
6435   // If hostname starts with "@", we should not remove that character.
6436   if (hostname_length > 0 && buffer[start] == '@') {
6437     start++;
6438     hostname_length--;
6439   }
6440   buffer.erase(start, hostname_length);
6441   components.host_end = start;
6442   components.pathname_start -= hostname_length;
6443   if (components.search_start != url_components::omitted) {
6444     components.search_start -= hostname_length;
6445   }
6446   if (components.hash_start != url_components::omitted) {
6447     components.hash_start -= hostname_length;
6448   }
6449 #if ADA_DEVELOPMENT_CHECKS
6450   ADA_ASSERT_EQUAL(get_hostname(), "",
6451                    "hostname should have been cleared on buffer=" + buffer +
6452                        " with " + components.to_string() + "\n" + to_diagram());
6453 #endif
6454   ADA_ASSERT_TRUE(has_authority());
6455   ADA_ASSERT_EQUAL(has_empty_hostname(), true,
6456                    "hostname should have been cleared on buffer=" + buffer +
6457                        " with " + components.to_string() + "\n" + to_diagram());
6458   ADA_ASSERT_TRUE(validate());
6459 }
6460 
6461 [[nodiscard]] inline bool url_aggregator::has_hash() const noexcept {
6462   ada_log("url_aggregator::has_hash");
6463   return components.hash_start != url_components::omitted;
6464 }
6465 
6466 [[nodiscard]] inline bool url_aggregator::has_search() const noexcept {
6467   ada_log("url_aggregator::has_search");
6468   return components.search_start != url_components::omitted;
6469 }
6470 
6471 ada_really_inline bool url_aggregator::has_credentials() const noexcept {
6472   ada_log("url_aggregator::has_credentials");
6473   return has_non_empty_username() || has_non_empty_password();
6474 }
6475 
6476 inline bool url_aggregator::cannot_have_credentials_or_port() const {
6477   ada_log("url_aggregator::cannot_have_credentials_or_port");
6478   return type == ada::scheme::type::FILE ||
6479          components.host_start == components.host_end;
6480 }
6481 
6482 [[nodiscard]] ada_really_inline const ada::url_components &
6483 url_aggregator::get_components() const noexcept {
6484   return components;
6485 }
6486 
6487 [[nodiscard]] inline bool ada::url_aggregator::has_authority() const noexcept {
6488   ada_log("url_aggregator::has_authority");
6489   // Performance: instead of doing this potentially expensive check, we could
6490   // have a boolean in the struct.
6491   return components.protocol_end + 2 <= components.host_start &&
6492          helpers::substring(buffer, components.protocol_end,
6493                             components.protocol_end + 2) == "//";
6494 }
6495 
6496 inline void ada::url_aggregator::add_authority_slashes_if_needed() noexcept {
6497   ada_log("url_aggregator::add_authority_slashes_if_needed");
6498   ADA_ASSERT_TRUE(validate());
6499   // Protocol setter will insert `http:` to the URL. It is up to hostname setter
6500   // to insert
6501   // `//` initially to the buffer, since it depends on the hostname existence.
6502   if (has_authority()) {
6503     return;
6504   }
6505   // Performance: the common case is components.protocol_end == buffer.size()
6506   // Optimization opportunity: in many cases, the "//" is part of the input and
6507   // the insert could be fused with another insert.
6508   buffer.insert(components.protocol_end, "//");
6509   components.username_end += 2;
6510   components.host_start += 2;
6511   components.host_end += 2;
6512   components.pathname_start += 2;
6513   if (components.search_start != url_components::omitted) {
6514     components.search_start += 2;
6515   }
6516   if (components.hash_start != url_components::omitted) {
6517     components.hash_start += 2;
6518   }
6519   ADA_ASSERT_TRUE(validate());
6520 }
6521 
6522 inline void ada::url_aggregator::reserve(uint32_t capacity) {
6523   buffer.reserve(capacity);
6524 }
6525 
6526 inline bool url_aggregator::has_non_empty_username() const noexcept {
6527   ada_log("url_aggregator::has_non_empty_username");
6528   return components.protocol_end + 2 < components.username_end;
6529 }
6530 
6531 inline bool url_aggregator::has_non_empty_password() const noexcept {
6532   ada_log("url_aggregator::has_non_empty_password");
6533   return components.host_start - components.username_end > 0;
6534 }
6535 
6536 inline bool url_aggregator::has_password() const noexcept {
6537   ada_log("url_aggregator::has_password");
6538   // This function does not care about the length of the password
6539   return components.host_start > components.username_end &&
6540          buffer[components.username_end] == ':';
6541 }
6542 
6543 inline bool url_aggregator::has_empty_hostname() const noexcept {
6544   if (!has_hostname()) {
6545     return false;
6546   }
6547   if (components.host_start == components.host_end) {
6548     return true;
6549   }
6550   if (components.host_end > components.host_start + 1) {
6551     return false;
6552   }
6553   return components.username_end != components.host_start;
6554 }
6555 
6556 inline bool url_aggregator::has_hostname() const noexcept {
6557   return has_authority();
6558 }
6559 
6560 inline bool url_aggregator::has_port() const noexcept {
6561   ada_log("url_aggregator::has_port");
6562   // A URL cannot have a username/password/port if its host is null or the empty
6563   // string, or its scheme is "file".
6564   return has_hostname() && components.pathname_start != components.host_end;
6565 }
6566 
6567 [[nodiscard]] inline bool url_aggregator::has_dash_dot() const noexcept {
6568   // If url's host is null, url does not have an opaque path, url's path's size
6569   // is greater than 1, and url's path[0] is the empty string, then append
6570   // U+002F (/) followed by U+002E (.) to output.
6571   ada_log("url_aggregator::has_dash_dot");
6572 #if ADA_DEVELOPMENT_CHECKS
6573   // If pathname_start and host_end are exactly two characters apart, then we
6574   // either have a one-digit port such as http://test.com:5?param=1 or else we
6575   // have a /.: sequence such as "non-spec:/.//". We test that this is the case.
6576   if (components.pathname_start == components.host_end + 2) {
6577     ADA_ASSERT_TRUE((buffer[components.host_end] == '/' &&
6578                      buffer[components.host_end + 1] == '.') ||
6579                     (buffer[components.host_end] == ':' &&
6580                      checkers::is_digit(buffer[components.host_end + 1])));
6581   }
6582   if (components.pathname_start == components.host_end + 2 &&
6583       buffer[components.host_end] == '/' &&
6584       buffer[components.host_end + 1] == '.') {
6585     ADA_ASSERT_TRUE(components.pathname_start + 1 < buffer.size());
6586     ADA_ASSERT_TRUE(buffer[components.pathname_start] == '/');
6587     ADA_ASSERT_TRUE(buffer[components.pathname_start + 1] == '/');
6588   }
6589 #endif
6590   // Performance: it should be uncommon for components.pathname_start ==
6591   // components.host_end + 2 to be true. So we put this check first in the
6592   // sequence. Most times, we do not have an opaque path. Checking for '/.' is
6593   // more expensive, but should be uncommon.
6594   return components.pathname_start == components.host_end + 2 &&
6595          !has_opaque_path && buffer[components.host_end] == '/' &&
6596          buffer[components.host_end + 1] == '.';
6597 }
6598 
6599 [[nodiscard]] inline std::string_view url_aggregator::get_href()
6600     const noexcept {
6601   ada_log("url_aggregator::get_href");
6602   return buffer;
6603 }
6604 
6605 ada_really_inline size_t url_aggregator::parse_port(
6606     std::string_view view, bool check_trailing_content) noexcept {
6607   ada_log("url_aggregator::parse_port('", view, "') ", view.size());
6608   uint16_t parsed_port{};
6609   auto r = std::from_chars(view.data(), view.data() + view.size(), parsed_port);
6610   if (r.ec == std::errc::result_out_of_range) {
6611     ada_log("parse_port: std::errc::result_out_of_range");
6612     is_valid = false;
6613     return 0;
6614   }
6615   ada_log("parse_port: ", parsed_port);
6616   const size_t consumed = size_t(r.ptr - view.data());
6617   ada_log("parse_port: consumed ", consumed);
6618   if (check_trailing_content) {
6619     is_valid &=
6620         (consumed == view.size() || view[consumed] == '/' ||
6621          view[consumed] == '?' || (is_special() && view[consumed] == '\\'));
6622   }
6623   ada_log("parse_port: is_valid = ", is_valid);
6624   if (is_valid) {
6625     ada_log("parse_port", r.ec == std::errc());
6626     // scheme_default_port can return 0, and we should allow 0 as a base port.
6627     auto default_port = scheme_default_port();
6628     bool is_port_valid = (default_port == 0 && parsed_port == 0) ||
6629                          (default_port != parsed_port);
6630     if (r.ec == std::errc() && is_port_valid) {
6631       update_base_port(parsed_port);
6632     } else {
6633       clear_port();
6634     }
6635   }
6636   return consumed;
6637 }
6638 
6639 inline void url_aggregator::set_protocol_as_file() {
6640   ada_log("url_aggregator::set_protocol_as_file ");
6641   ADA_ASSERT_TRUE(validate());
6642   type = ada::scheme::type::FILE;
6643   // next line could overflow but unsigned arithmetic has well-defined
6644   // overflows.
6645   uint32_t new_difference = 5 - components.protocol_end;
6646 
6647   if (buffer.empty()) {
6648     buffer.append("file:");
6649   } else {
6650     buffer.erase(0, components.protocol_end);
6651     buffer.insert(0, "file:");
6652   }
6653   components.protocol_end = 5;
6654 
6655   // Update the rest of the components.
6656   components.username_end += new_difference;
6657   components.host_start += new_difference;
6658   components.host_end += new_difference;
6659   components.pathname_start += new_difference;
6660   if (components.search_start != url_components::omitted) {
6661     components.search_start += new_difference;
6662   }
6663   if (components.hash_start != url_components::omitted) {
6664     components.hash_start += new_difference;
6665   }
6666   ADA_ASSERT_TRUE(validate());
6667 }
6668 
6669 inline std::ostream &operator<<(std::ostream &out,
6670                                 const ada::url_aggregator &u) {
6671   return out << u.to_string();
6672 }
6673 }  // namespace ada
6674 
6675 #endif  // ADA_URL_AGGREGATOR_INL_H
6676 /* end file include/ada/url_aggregator-inl.h */
6677 /* begin file include/ada/url_search_params.h */
6678 /**
6679  * @file url_search_params.h
6680  * @brief Declaration for the URL Search Params
6681  */
6682 #ifndef ADA_URL_SEARCH_PARAMS_H
6683 #define ADA_URL_SEARCH_PARAMS_H
6684 
6685 #include <optional>
6686 #include <string>
6687 #include <string_view>
6688 #include <vector>
6689 
6690 namespace ada {
6691 
6692 enum class url_search_params_iter_type {
6693   KEYS,
6694   VALUES,
6695   ENTRIES,
6696 };
6697 
6698 template <typename T, url_search_params_iter_type Type>
6699 struct url_search_params_iter;
6700 
6701 typedef std::pair<std::string_view, std::string_view> key_value_view_pair;
6702 
6703 using url_search_params_keys_iter =
6704     url_search_params_iter<std::string_view, url_search_params_iter_type::KEYS>;
6705 using url_search_params_values_iter =
6706     url_search_params_iter<std::string_view,
6707                            url_search_params_iter_type::VALUES>;
6708 using url_search_params_entries_iter =
6709     url_search_params_iter<key_value_view_pair,
6710                            url_search_params_iter_type::ENTRIES>;
6711 
6712 /**
6713  * @see https://url.spec.whatwg.org/#interface-urlsearchparams
6714  */
6715 struct url_search_params {
6716   url_search_params() = default;
6717 
6718   /**
6719    * @see
6720    * https://github.com/web-platform-tests/wpt/blob/master/url/urlsearchparams-constructor.any.js
6721    */
6722   url_search_params(const std::string_view input) { initialize(input); }
6723 
6724   url_search_params(const url_search_params &u) = default;
6725   url_search_params(url_search_params &&u) noexcept = default;
6726   url_search_params &operator=(url_search_params &&u) noexcept = default;
6727   url_search_params &operator=(const url_search_params &u) = default;
6728   ~url_search_params() = default;
6729 
6730   [[nodiscard]] inline size_t size() const noexcept;
6731 
6732   /**
6733    * @see https://url.spec.whatwg.org/#dom-urlsearchparams-append
6734    */
6735   inline void append(std::string_view key, std::string_view value);
6736 
6737   /**
6738    * @see https://url.spec.whatwg.org/#dom-urlsearchparams-delete
6739    */
6740   inline void remove(std::string_view key);
6741   inline void remove(std::string_view key, std::string_view value);
6742 
6743   /**
6744    * @see https://url.spec.whatwg.org/#dom-urlsearchparams-get
6745    */
6746   inline std::optional<std::string_view> get(std::string_view key);
6747 
6748   /**
6749    * @see https://url.spec.whatwg.org/#dom-urlsearchparams-getall
6750    */
6751   inline std::vector<std::string> get_all(std::string_view key);
6752 
6753   /**
6754    * @see https://url.spec.whatwg.org/#dom-urlsearchparams-has
6755    */
6756   inline bool has(std::string_view key) noexcept;
6757   inline bool has(std::string_view key, std::string_view value) noexcept;
6758 
6759   /**
6760    * @see https://url.spec.whatwg.org/#dom-urlsearchparams-set
6761    */
6762   inline void set(std::string_view key, std::string_view value);
6763 
6764   /**
6765    * @see https://url.spec.whatwg.org/#dom-urlsearchparams-sort
6766    */
6767   inline void sort();
6768 
6769   /**
6770    * @see https://url.spec.whatwg.org/#urlsearchparams-stringification-behavior
6771    */
6772   inline std::string to_string();
6773 
6774   /**
6775    * Returns a simple JS-style iterator over all of the keys in this
6776    * url_search_params. The keys in the iterator are not unique. The valid
6777    * lifespan of the iterator is tied to the url_search_params. The iterator
6778    * must be freed when you're done with it.
6779    * @see https://url.spec.whatwg.org/#interface-urlsearchparams
6780    */
6781   inline url_search_params_keys_iter get_keys();
6782 
6783   /**
6784    * Returns a simple JS-style iterator over all of the values in this
6785    * url_search_params. The valid lifespan of the iterator is tied to the
6786    * url_search_params. The iterator must be freed when you're done with it.
6787    * @see https://url.spec.whatwg.org/#interface-urlsearchparams
6788    */
6789   inline url_search_params_values_iter get_values();
6790 
6791   /**
6792    * Returns a simple JS-style iterator over all of the entries in this
6793    * url_search_params. The entries are pairs of keys and corresponding values.
6794    * The valid lifespan of the iterator is tied to the url_search_params. The
6795    * iterator must be freed when you're done with it.
6796    * @see https://url.spec.whatwg.org/#interface-urlsearchparams
6797    */
6798   inline url_search_params_entries_iter get_entries();
6799 
6800   /**
6801    * C++ style conventional iterator support. const only because we
6802    * do not really want the params to be modified via the iterator.
6803    */
6804   inline auto begin() const { return params.begin(); }
6805   inline auto end() const { return params.end(); }
6806   inline auto front() const { return params.front(); }
6807   inline auto back() const { return params.back(); }
6808   inline auto operator[](size_t index) const { return params[index]; }
6809 
6810  private:
6811   typedef std::pair<std::string, std::string> key_value_pair;
6812   std::vector<key_value_pair> params{};
6813 
6814   /**
6815    * @see https://url.spec.whatwg.org/#concept-urlencoded-parser
6816    */
6817   void initialize(std::string_view init);
6818 
6819   template <typename T, url_search_params_iter_type Type>
6820   friend struct url_search_params_iter;
6821 };  // url_search_params
6822 
6823 /**
6824  * Implements a non-conventional iterator pattern that is closer in style to
6825  * JavaScript's definition of an iterator.
6826  *
6827  * @see https://webidl.spec.whatwg.org/#idl-iterable
6828  */
6829 template <typename T, url_search_params_iter_type Type>
6830 struct url_search_params_iter {
6831   inline url_search_params_iter() : params(EMPTY) {}
6832   url_search_params_iter(const url_search_params_iter &u) = default;
6833   url_search_params_iter(url_search_params_iter &&u) noexcept = default;
6834   url_search_params_iter &operator=(url_search_params_iter &&u) noexcept =
6835       default;
6836   url_search_params_iter &operator=(const url_search_params_iter &u) = default;
6837   ~url_search_params_iter() = default;
6838 
6839   /**
6840    * Return the next item in the iterator or std::nullopt if done.
6841    */
6842   inline std::optional<T> next();
6843 
6844   inline bool has_next();
6845 
6846  private:
6847   static url_search_params EMPTY;
6848   inline url_search_params_iter(url_search_params &params_) : params(params_) {}
6849 
6850   url_search_params &params;
6851   size_t pos = 0;
6852 
6853   friend struct url_search_params;
6854 };
6855 
6856 }  // namespace ada
6857 #endif
6858 /* end file include/ada/url_search_params.h */
6859 /* begin file include/ada/url_search_params-inl.h */
6860 /**
6861  * @file url_search_params-inl.h
6862  * @brief Inline declarations for the URL Search Params
6863  */
6864 #ifndef ADA_URL_SEARCH_PARAMS_INL_H
6865 #define ADA_URL_SEARCH_PARAMS_INL_H
6866 
6867 
6868 #include <algorithm>
6869 #include <optional>
6870 #include <string>
6871 #include <string_view>
6872 #include <vector>
6873 
6874 namespace ada {
6875 
6876 // A default, empty url_search_params for use with empty iterators.
6877 template <typename T, ada::url_search_params_iter_type Type>
6878 url_search_params url_search_params_iter<T, Type>::EMPTY;
6879 
6880 inline void url_search_params::initialize(std::string_view input) {
6881   if (!input.empty() && input.front() == '?') {
6882     input.remove_prefix(1);
6883   }
6884 
6885   auto process_key_value = [&](const std::string_view current) {
6886     auto equal = current.find('=');
6887 
6888     if (equal == std::string_view::npos) {
6889       auto name = std::string(current);
6890       std::replace(name.begin(), name.end(), '+', ' ');
6891       params.emplace_back(unicode::percent_decode(name, name.find('%')), "");
6892     } else {
6893       auto name = std::string(current.substr(0, equal));
6894       auto value = std::string(current.substr(equal + 1));
6895 
6896       std::replace(name.begin(), name.end(), '+', ' ');
6897       std::replace(value.begin(), value.end(), '+', ' ');
6898 
6899       params.emplace_back(unicode::percent_decode(name, name.find('%')),
6900                           unicode::percent_decode(value, value.find('%')));
6901     }
6902   };
6903 
6904   while (!input.empty()) {
6905     auto ampersand_index = input.find('&');
6906 
6907     if (ampersand_index == std::string_view::npos) {
6908       if (!input.empty()) {
6909         process_key_value(input);
6910       }
6911       break;
6912     } else if (ampersand_index != 0) {
6913       process_key_value(input.substr(0, ampersand_index));
6914     }
6915 
6916     input.remove_prefix(ampersand_index + 1);
6917   }
6918 }
6919 
6920 inline void url_search_params::append(const std::string_view key,
6921                                       const std::string_view value) {
6922   params.emplace_back(key, value);
6923 }
6924 
6925 inline size_t url_search_params::size() const noexcept { return params.size(); }
6926 
6927 inline std::optional<std::string_view> url_search_params::get(
6928     const std::string_view key) {
6929   auto entry = std::find_if(params.begin(), params.end(),
6930                             [&key](auto &param) { return param.first == key; });
6931 
6932   if (entry == params.end()) {
6933     return std::nullopt;
6934   }
6935 
6936   return entry->second;
6937 }
6938 
6939 inline std::vector<std::string> url_search_params::get_all(
6940     const std::string_view key) {
6941   std::vector<std::string> out{};
6942 
6943   for (auto &param : params) {
6944     if (param.first == key) {
6945       out.emplace_back(param.second);
6946     }
6947   }
6948 
6949   return out;
6950 }
6951 
6952 inline bool url_search_params::has(const std::string_view key) noexcept {
6953   auto entry = std::find_if(params.begin(), params.end(),
6954                             [&key](auto &param) { return param.first == key; });
6955   return entry != params.end();
6956 }
6957 
6958 inline bool url_search_params::has(std::string_view key,
6959                                    std::string_view value) noexcept {
6960   auto entry =
6961       std::find_if(params.begin(), params.end(), [&key, &value](auto &param) {
6962         return param.first == key && param.second == value;
6963       });
6964   return entry != params.end();
6965 }
6966 
6967 inline std::string url_search_params::to_string() {
6968   auto character_set = ada::character_sets::WWW_FORM_URLENCODED_PERCENT_ENCODE;
6969   std::string out{};
6970   for (size_t i = 0; i < params.size(); i++) {
6971     auto key = ada::unicode::percent_encode(params[i].first, character_set);
6972     auto value = ada::unicode::percent_encode(params[i].second, character_set);
6973 
6974     // Performance optimization: Move this inside percent_encode.
6975     std::replace(key.begin(), key.end(), ' ', '+');
6976     std::replace(value.begin(), value.end(), ' ', '+');
6977 
6978     if (i != 0) {
6979       out += "&";
6980     }
6981     out.append(key);
6982     out += "=";
6983     out.append(value);
6984   }
6985   return out;
6986 }
6987 
6988 inline void url_search_params::set(const std::string_view key,
6989                                    const std::string_view value) {
6990   const auto find = [&key](auto &param) { return param.first == key; };
6991 
6992   auto it = std::find_if(params.begin(), params.end(), find);
6993 
6994   if (it == params.end()) {
6995     params.emplace_back(key, value);
6996   } else {
6997     it->second = value;
6998     params.erase(std::remove_if(std::next(it), params.end(), find),
6999                  params.end());
7000   }
7001 }
7002 
7003 inline void url_search_params::remove(const std::string_view key) {
7004   params.erase(
7005       std::remove_if(params.begin(), params.end(),
7006                      [&key](auto &param) { return param.first == key; }),
7007       params.end());
7008 }
7009 
7010 inline void url_search_params::remove(const std::string_view key,
7011                                       const std::string_view value) {
7012   params.erase(std::remove_if(params.begin(), params.end(),
7013                               [&key, &value](auto &param) {
7014                                 return param.first == key &&
7015                                        param.second == value;
7016                               }),
7017                params.end());
7018 }
7019 
7020 inline void url_search_params::sort() {
7021   std::stable_sort(params.begin(), params.end(),
7022                    [](const key_value_pair &lhs, const key_value_pair &rhs) {
7023                      return lhs.first < rhs.first;
7024                    });
7025 }
7026 
7027 inline url_search_params_keys_iter url_search_params::get_keys() {
7028   return url_search_params_keys_iter(*this);
7029 }
7030 
7031 /**
7032  * @see https://url.spec.whatwg.org/#interface-urlsearchparams
7033  */
7034 inline url_search_params_values_iter url_search_params::get_values() {
7035   return url_search_params_values_iter(*this);
7036 }
7037 
7038 /**
7039  * @see https://url.spec.whatwg.org/#interface-urlsearchparams
7040  */
7041 inline url_search_params_entries_iter url_search_params::get_entries() {
7042   return url_search_params_entries_iter(*this);
7043 }
7044 
7045 template <typename T, url_search_params_iter_type Type>
7046 inline bool url_search_params_iter<T, Type>::has_next() {
7047   return pos < params.params.size();
7048 }
7049 
7050 template <>
7051 inline std::optional<std::string_view> url_search_params_keys_iter::next() {
7052   if (!has_next()) return std::nullopt;
7053   return params.params[pos++].first;
7054 }
7055 
7056 template <>
7057 inline std::optional<std::string_view> url_search_params_values_iter::next() {
7058   if (!has_next()) return std::nullopt;
7059   return params.params[pos++].second;
7060 }
7061 
7062 template <>
7063 inline std::optional<key_value_view_pair>
7064 url_search_params_entries_iter::next() {
7065   if (!has_next()) return std::nullopt;
7066   return params.params[pos++];
7067 }
7068 
7069 }  // namespace ada
7070 
7071 #endif  // ADA_URL_SEARCH_PARAMS_INL_H
7072 /* end file include/ada/url_search_params-inl.h */
7073 
7074 // Public API
7075 /* begin file include/ada/ada_version.h */
7076 /**
7077  * @file ada_version.h
7078  * @brief Definitions for Ada's version number.
7079  */
7080 #ifndef ADA_ADA_VERSION_H
7081 #define ADA_ADA_VERSION_H
7082 
7083 #define ADA_VERSION "2.7.6"
7084 
7085 namespace ada {
7086 
7087 enum {
7088   ADA_VERSION_MAJOR = 2,
7089   ADA_VERSION_MINOR = 7,
7090   ADA_VERSION_REVISION = 6,
7091 };
7092 
7093 }  // namespace ada
7094 
7095 #endif  // ADA_ADA_VERSION_H
7096 /* end file include/ada/ada_version.h */
7097 /* begin file include/ada/implementation.h */
7098 /**
7099  * @file implementation.h
7100  * @brief Definitions for user facing functions for parsing URL and it's
7101  * components.
7102  */
7103 #ifndef ADA_IMPLEMENTATION_H
7104 #define ADA_IMPLEMENTATION_H
7105 
7106 #include <string>
7107 #include <optional>
7108 
7109 
7110 namespace ada {
7111 enum class errors { generic_error };
7112 
7113 template <class result_type = ada::url_aggregator>
7114 using result = tl::expected<result_type, ada::errors>;
7115 
7116 /**
7117  * The URL parser takes a scalar value string input, with an optional null or
7118  * base URL base (default null). The parser assumes the input is a valid ASCII
7119  * or UTF-8 string.
7120  *
7121  * @param input the string input to analyze (must be valid ASCII or UTF-8)
7122  * @param base_url the optional URL input to use as a base url.
7123  * @return a parsed URL.
7124  */
7125 template <class result_type = ada::url_aggregator>
7126 ada_warn_unused ada::result<result_type> parse(
7127     std::string_view input, const result_type* base_url = nullptr);
7128 
7129 extern template ada::result<url> parse<url>(std::string_view input,
7130                                             const url* base_url);
7131 extern template ada::result<url_aggregator> parse<url_aggregator>(
7132     std::string_view input, const url_aggregator* base_url);
7133 
7134 /**
7135  * Verifies whether the URL strings can be parsed. The function assumes
7136  * that the inputs are valid ASCII or UTF-8 strings.
7137  * @see https://url.spec.whatwg.org/#dom-url-canparse
7138  * @return If URL can be parsed or not.
7139  */
7140 bool can_parse(std::string_view input,
7141                const std::string_view* base_input = nullptr);
7142 
7143 /**
7144  * Computes a href string from a file path. The function assumes
7145  * that the input is a valid ASCII or UTF-8 string.
7146  * @return a href string (starts with file:://)
7147  */
7148 std::string href_from_file(std::string_view path);
7149 }  // namespace ada
7150 
7151 #endif  // ADA_IMPLEMENTATION_H
7152 /* end file include/ada/implementation.h */
7153 
7154 #endif  // ADA_H
7155 /* end file include/ada.h */
7156