Coverage Report

Created: 2024-05-13 06:25

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