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