Coverage Report

Created: 2025-08-26 06:35

/src/ada-url/build/singleheader/ada.h
Line
Count
Source (jump to first uncovered line)
1
/* auto-generated on 2025-08-01 09:04:57 -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 2025-03-08 13:17:11 -0500. 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
// Map the characters according to IDNA, returning the empty string on error.
49
std::u32string map(std::u32string_view input);
50
51
}  // namespace ada::idna
52
53
#endif
54
/* end file include/ada/idna/mapping.h */
55
/* begin file include/ada/idna/normalization.h */
56
#ifndef ADA_IDNA_NORMALIZATION_H
57
#define ADA_IDNA_NORMALIZATION_H
58
59
#include <string>
60
#include <string_view>
61
62
namespace ada::idna {
63
64
// Normalize the characters according to IDNA (Unicode Normalization Form C).
65
void normalize(std::u32string& input);
66
67
}  // namespace ada::idna
68
#endif
69
/* end file include/ada/idna/normalization.h */
70
/* begin file include/ada/idna/punycode.h */
71
#ifndef ADA_IDNA_PUNYCODE_H
72
#define ADA_IDNA_PUNYCODE_H
73
74
#include <string>
75
#include <string_view>
76
77
namespace ada::idna {
78
79
bool punycode_to_utf32(std::string_view input, std::u32string& out);
80
bool verify_punycode(std::string_view input);
81
bool utf32_to_punycode(std::u32string_view input, std::string& out);
82
83
}  // namespace ada::idna
84
85
#endif  // ADA_IDNA_PUNYCODE_H
86
/* end file include/ada/idna/punycode.h */
87
/* begin file include/ada/idna/validity.h */
88
#ifndef ADA_IDNA_VALIDITY_H
89
#define ADA_IDNA_VALIDITY_H
90
91
#include <string>
92
#include <string_view>
93
94
namespace ada::idna {
95
96
/**
97
 * @see https://www.unicode.org/reports/tr46/#Validity_Criteria
98
 */
99
bool is_label_valid(std::u32string_view label);
100
101
}  // namespace ada::idna
102
103
#endif  // ADA_IDNA_VALIDITY_H
104
/* end file include/ada/idna/validity.h */
105
/* begin file include/ada/idna/to_ascii.h */
106
#ifndef ADA_IDNA_TO_ASCII_H
107
#define ADA_IDNA_TO_ASCII_H
108
109
#include <string>
110
#include <string_view>
111
112
namespace ada::idna {
113
114
// Converts a domain (e.g., www.google.com) possibly containing international
115
// characters to an ascii domain (with punycode). It will not do percent
116
// decoding: percent decoding should be done prior to calling this function. We
117
// do not remove tabs and spaces, they should have been removed prior to calling
118
// this function. We also do not trim control characters. We also assume that
119
// the input is not empty. We return "" on error.
120
//
121
//
122
// This function may accept or even produce invalid domains.
123
std::string to_ascii(std::string_view ut8_string);
124
125
// Returns true if the string contains a forbidden code point according to the
126
// WHATGL URL specification:
127
// https://url.spec.whatwg.org/#forbidden-domain-code-point
128
bool contains_forbidden_domain_code_point(std::string_view ascii_string);
129
130
bool constexpr is_ascii(std::u32string_view view);
131
bool constexpr is_ascii(std::string_view view);
132
133
}  // namespace ada::idna
134
135
#endif  // ADA_IDNA_TO_ASCII_H
136
/* end file include/ada/idna/to_ascii.h */
137
/* begin file include/ada/idna/to_unicode.h */
138
139
#ifndef ADA_IDNA_TO_UNICODE_H
140
#define ADA_IDNA_TO_UNICODE_H
141
142
#include <string_view>
143
144
namespace ada::idna {
145
146
std::string to_unicode(std::string_view input);
147
148
}  // namespace ada::idna
149
150
#endif  // ADA_IDNA_TO_UNICODE_H
151
/* end file include/ada/idna/to_unicode.h */
152
/* begin file include/ada/idna/identifier.h */
153
#ifndef ADA_IDNA_IDENTIFIER_H
154
#define ADA_IDNA_IDENTIFIER_H
155
156
#include <string>
157
#include <string_view>
158
159
namespace ada::idna {
160
161
// Verify if it is valid name code point given a Unicode code point and a
162
// boolean first: If first is true return the result of checking if code point
163
// is contained in the IdentifierStart set of code points. Otherwise return the
164
// result of checking if code point is contained in the IdentifierPart set of
165
// code points. Returns false if the input is empty or the code point is not
166
// valid. There is minimal Unicode error handling: the input should be valid
167
// UTF-8. https://urlpattern.spec.whatwg.org/#is-a-valid-name-code-point
168
bool valid_name_code_point(char32_t code_point, bool first);
169
170
}  // namespace ada::idna
171
172
#endif
173
/* end file include/ada/idna/identifier.h */
174
175
#endif
176
/* end file include/idna.h */
177
/* end file include/ada/ada_idna.h */
178
/* begin file include/ada/character_sets.h */
179
/**
180
 * @file character_sets.h
181
 * @brief Declaration of the character sets used by unicode functions.
182
 * @author Node.js
183
 * @see https://github.com/nodejs/node/blob/main/src/node_url_tables.cc
184
 */
185
#ifndef ADA_CHARACTER_SETS_H
186
#define ADA_CHARACTER_SETS_H
187
188
/* begin file include/ada/common_defs.h */
189
/**
190
 * @file common_defs.h
191
 * @brief Common definitions for cross-platform compiler support.
192
 */
193
#ifndef ADA_COMMON_DEFS_H
194
#define ADA_COMMON_DEFS_H
195
196
// https://en.cppreference.com/w/cpp/feature_test#Library_features
197
// detect C++20 features
198
#include <version>
199
200
#ifdef _MSC_VER
201
#define ADA_VISUAL_STUDIO 1
202
/**
203
 * We want to differentiate carefully between
204
 * clang under visual studio and regular visual
205
 * studio.
206
 */
207
#ifdef __clang__
208
// clang under visual studio
209
#define ADA_CLANG_VISUAL_STUDIO 1
210
#else
211
// just regular visual studio (best guess)
212
#define ADA_REGULAR_VISUAL_STUDIO 1
213
#endif  // __clang__
214
#endif  // _MSC_VER
215
216
#if defined(__GNUC__)
217
// Marks a block with a name so that MCA analysis can see it.
218
#define ADA_BEGIN_DEBUG_BLOCK(name) __asm volatile("# LLVM-MCA-BEGIN " #name);
219
#define ADA_END_DEBUG_BLOCK(name) __asm volatile("# LLVM-MCA-END " #name);
220
#define ADA_DEBUG_BLOCK(name, block) \
221
  BEGIN_DEBUG_BLOCK(name);           \
222
  block;                             \
223
  END_DEBUG_BLOCK(name);
224
#else
225
#define ADA_BEGIN_DEBUG_BLOCK(name)
226
#define ADA_END_DEBUG_BLOCK(name)
227
#define ADA_DEBUG_BLOCK(name, block)
228
#endif
229
230
// Align to N-byte boundary
231
#define ADA_ROUNDUP_N(a, n) (((a) + ((n)-1)) & ~((n)-1))
232
#define ADA_ROUNDDOWN_N(a, n) ((a) & ~((n)-1))
233
234
#define ADA_ISALIGNED_N(ptr, n) (((uintptr_t)(ptr) & ((n)-1)) == 0)
235
236
#if defined(ADA_REGULAR_VISUAL_STUDIO)
237
238
#define ada_really_inline __forceinline
239
#define ada_never_inline __declspec(noinline)
240
241
#define ada_unused
242
#define ada_warn_unused
243
244
#define ADA_PUSH_DISABLE_WARNINGS __pragma(warning(push))
245
#define ADA_PUSH_DISABLE_ALL_WARNINGS __pragma(warning(push, 0))
246
#define ADA_DISABLE_VS_WARNING(WARNING_NUMBER) \
247
  __pragma(warning(disable : WARNING_NUMBER))
248
// Get rid of Intellisense-only warnings (Code Analysis)
249
// Though __has_include is C++17, it is supported in Visual Studio 2017 or
250
// better (_MSC_VER>=1910).
251
#ifdef __has_include
252
#if __has_include(<CppCoreCheck\Warnings.h>)
253
#include <CppCoreCheck\Warnings.h>
254
#define ADA_DISABLE_UNDESIRED_WARNINGS \
255
  ADA_DISABLE_VS_WARNING(ALL_CPPCORECHECK_WARNINGS)
256
#endif
257
#endif
258
259
#ifndef ADA_DISABLE_UNDESIRED_WARNINGS
260
#define ADA_DISABLE_UNDESIRED_WARNINGS
261
#endif
262
263
#define ADA_DISABLE_DEPRECATED_WARNING ADA_DISABLE_VS_WARNING(4996)
264
#define ADA_DISABLE_STRICT_OVERFLOW_WARNING
265
#define ADA_POP_DISABLE_WARNINGS __pragma(warning(pop))
266
267
#else  // ADA_REGULAR_VISUAL_STUDIO
268
269
#define ada_really_inline inline __attribute__((always_inline))
270
#define ada_never_inline inline __attribute__((noinline))
271
272
#define ada_unused __attribute__((unused))
273
#define ada_warn_unused __attribute__((warn_unused_result))
274
275
#define ADA_PUSH_DISABLE_WARNINGS _Pragma("GCC diagnostic push")
276
// gcc doesn't seem to disable all warnings with all and extra, add warnings
277
// here as necessary
278
#define ADA_PUSH_DISABLE_ALL_WARNINGS               \
279
  ADA_PUSH_DISABLE_WARNINGS                         \
280
  ADA_DISABLE_GCC_WARNING("-Weffc++")               \
281
  ADA_DISABLE_GCC_WARNING("-Wall")                  \
282
  ADA_DISABLE_GCC_WARNING("-Wconversion")           \
283
  ADA_DISABLE_GCC_WARNING("-Wextra")                \
284
  ADA_DISABLE_GCC_WARNING("-Wattributes")           \
285
  ADA_DISABLE_GCC_WARNING("-Wimplicit-fallthrough") \
286
  ADA_DISABLE_GCC_WARNING("-Wnon-virtual-dtor")     \
287
  ADA_DISABLE_GCC_WARNING("-Wreturn-type")          \
288
  ADA_DISABLE_GCC_WARNING("-Wshadow")               \
289
  ADA_DISABLE_GCC_WARNING("-Wunused-parameter")     \
290
  ADA_DISABLE_GCC_WARNING("-Wunused-variable")      \
291
  ADA_DISABLE_GCC_WARNING("-Wsign-compare")
292
#define ADA_PRAGMA(P) _Pragma(#P)
293
#define ADA_DISABLE_GCC_WARNING(WARNING) \
294
  ADA_PRAGMA(GCC diagnostic ignored WARNING)
295
#if defined(ADA_CLANG_VISUAL_STUDIO)
296
#define ADA_DISABLE_UNDESIRED_WARNINGS \
297
  ADA_DISABLE_GCC_WARNING("-Wmicrosoft-include")
298
#else
299
#define ADA_DISABLE_UNDESIRED_WARNINGS
300
#endif
301
#define ADA_DISABLE_DEPRECATED_WARNING \
302
  ADA_DISABLE_GCC_WARNING("-Wdeprecated-declarations")
303
#define ADA_DISABLE_STRICT_OVERFLOW_WARNING \
304
  ADA_DISABLE_GCC_WARNING("-Wstrict-overflow")
305
#define ADA_POP_DISABLE_WARNINGS _Pragma("GCC diagnostic pop")
306
307
#endif  // MSC_VER
308
309
#if defined(ADA_VISUAL_STUDIO)
310
/**
311
 * It does not matter here whether you are using
312
 * the regular visual studio or clang under visual
313
 * studio.
314
 */
315
#if ADA_USING_LIBRARY
316
#define ADA_DLLIMPORTEXPORT __declspec(dllimport)
317
#else
318
#define ADA_DLLIMPORTEXPORT __declspec(dllexport)
319
#endif
320
#else
321
#define ADA_DLLIMPORTEXPORT
322
#endif
323
324
/// If EXPR is an error, returns it.
325
#define ADA_TRY(EXPR)   \
326
  {                     \
327
    auto _err = (EXPR); \
328
    if (_err) {         \
329
      return _err;      \
330
    }                   \
331
  }
332
333
// __has_cpp_attribute is part of C++20
334
#if !defined(__has_cpp_attribute)
335
#define __has_cpp_attribute(x) 0
336
#endif
337
338
#if __has_cpp_attribute(gnu::noinline)
339
#define ADA_ATTRIBUTE_NOINLINE [[gnu::noinline]]
340
#else
341
#define ADA_ATTRIBUTE_NOINLINE
342
#endif
343
344
namespace ada {
345
0
[[noreturn]] inline void unreachable() {
346
0
#ifdef __GNUC__
347
0
  __builtin_unreachable();
348
#elif defined(_MSC_VER)
349
  __assume(false);
350
#else
351
#endif
352
0
}
353
}  // namespace ada
354
355
// Unless the programmer has already set ADA_DEVELOPMENT_CHECKS,
356
// we want to set it under debug builds. We detect a debug build
357
// under Visual Studio when the _DEBUG macro is set. Under the other
358
// compilers, we use the fact that they define __OPTIMIZE__ whenever
359
// they allow optimizations.
360
// It is possible that this could miss some cases where ADA_DEVELOPMENT_CHECKS
361
// is helpful, but the programmer can set the macro ADA_DEVELOPMENT_CHECKS.
362
// It could also wrongly set ADA_DEVELOPMENT_CHECKS (e.g., if the programmer
363
// sets _DEBUG in a release build under Visual Studio, or if some compiler fails
364
// to set the __OPTIMIZE__ macro).
365
#if !defined(ADA_DEVELOPMENT_CHECKS) && !defined(NDEBUG)
366
#ifdef _MSC_VER
367
// Visual Studio seems to set _DEBUG for debug builds.
368
#ifdef _DEBUG
369
#define ADA_DEVELOPMENT_CHECKS 1
370
#endif  // _DEBUG
371
#else   // _MSC_VER
372
// All other compilers appear to set __OPTIMIZE__ to a positive integer
373
// when the compiler is optimizing.
374
#ifndef __OPTIMIZE__
375
#define ADA_DEVELOPMENT_CHECKS 1
376
#endif  // __OPTIMIZE__
377
#endif  // _MSC_VER
378
#endif  // ADA_DEVELOPMENT_CHECKS
379
380
#define ADA_STR(x) #x
381
382
#if ADA_DEVELOPMENT_CHECKS
383
#define ADA_REQUIRE(EXPR) \
384
  {                       \
385
    if (!(EXPR) { abort(); }) }
386
387
#define ADA_FAIL(MESSAGE)                            \
388
  do {                                               \
389
    std::cerr << "FAIL: " << (MESSAGE) << std::endl; \
390
    abort();                                         \
391
  } while (0);
392
#define ADA_ASSERT_EQUAL(LHS, RHS, MESSAGE)                                    \
393
  do {                                                                         \
394
    if (LHS != RHS) {                                                          \
395
      std::cerr << "Mismatch: '" << LHS << "' - '" << RHS << "'" << std::endl; \
396
      ADA_FAIL(MESSAGE);                                                       \
397
    }                                                                          \
398
  } while (0);
399
#define ADA_ASSERT_TRUE(COND)                                               \
400
  do {                                                                      \
401
    if (!(COND)) {                                                          \
402
      std::cerr << "Assert at line " << __LINE__ << " of file " << __FILE__ \
403
                << std::endl;                                               \
404
      ADA_FAIL(ADA_STR(COND));                                              \
405
    }                                                                       \
406
  } while (0);
407
#else
408
#define ADA_FAIL(MESSAGE)
409
#define ADA_ASSERT_EQUAL(LHS, RHS, MESSAGE)
410
#define ADA_ASSERT_TRUE(COND)
411
#endif
412
413
#ifdef ADA_VISUAL_STUDIO
414
#define ADA_ASSUME(COND) __assume(COND)
415
#else
416
#define ADA_ASSUME(COND)       \
417
  do {                         \
418
    if (!(COND)) {             \
419
      __builtin_unreachable(); \
420
    }                          \
421
  } while (0)
422
#endif
423
424
#if defined(__SSE2__) || defined(__x86_64__) || defined(__x86_64) || \
425
    (defined(_M_AMD64) || defined(_M_X64) ||                         \
426
     (defined(_M_IX86_FP) && _M_IX86_FP == 2))
427
#define ADA_SSE2 1
428
#endif
429
430
#if defined(__aarch64__) || defined(_M_ARM64)
431
#define ADA_NEON 1
432
#endif
433
434
#if defined(__loongarch_sx)
435
#define ADA_LSX 1
436
#endif
437
438
#ifndef __has_cpp_attribute
439
#define ada_lifetime_bound
440
#elif __has_cpp_attribute(msvc::lifetimebound)
441
#define ada_lifetime_bound [[msvc::lifetimebound]]
442
#elif __has_cpp_attribute(clang::lifetimebound)
443
#define ada_lifetime_bound [[clang::lifetimebound]]
444
#elif __has_cpp_attribute(lifetimebound)
445
#define ada_lifetime_bound [[lifetimebound]]
446
#else
447
#define ada_lifetime_bound
448
#endif
449
450
#ifdef __cpp_lib_format
451
#if __cpp_lib_format >= 202110L
452
#include <format>
453
#define ADA_HAS_FORMAT 1
454
#endif
455
#endif
456
457
#ifndef ADA_INCLUDE_URL_PATTERN
458
#define ADA_INCLUDE_URL_PATTERN 1
459
#endif  // ADA_INCLUDE_URL_PATTERN
460
461
#endif  // ADA_COMMON_DEFS_H
462
/* end file include/ada/common_defs.h */
463
#include <cstdint>
464
465
/**
466
 * These functions are not part of our public API and may
467
 * change at any time.
468
 * @private
469
 * @namespace ada::character_sets
470
 * @brief Includes the definitions for unicode character sets.
471
 */
472
namespace ada::character_sets {
473
ada_really_inline constexpr bool bit_at(const uint8_t a[], uint8_t i);
474
}  // namespace ada::character_sets
475
476
#endif  // ADA_CHARACTER_SETS_H
477
/* end file include/ada/character_sets.h */
478
/* begin file include/ada/character_sets-inl.h */
479
/**
480
 * @file character_sets-inl.h
481
 * @brief Definitions of the character sets used by unicode functions.
482
 * @author Node.js
483
 * @see https://github.com/nodejs/node/blob/main/src/node_url_tables.cc
484
 */
485
#ifndef ADA_CHARACTER_SETS_INL_H
486
#define ADA_CHARACTER_SETS_INL_H
487
488
489
/**
490
 * These functions are not part of our public API and may
491
 * change at any time.
492
 * @private
493
 */
494
namespace ada::character_sets {
495
496
constexpr char hex[1024] =
497
    "%00\0%01\0%02\0%03\0%04\0%05\0%06\0%07\0"
498
    "%08\0%09\0%0A\0%0B\0%0C\0%0D\0%0E\0%0F\0"
499
    "%10\0%11\0%12\0%13\0%14\0%15\0%16\0%17\0"
500
    "%18\0%19\0%1A\0%1B\0%1C\0%1D\0%1E\0%1F\0"
501
    "%20\0%21\0%22\0%23\0%24\0%25\0%26\0%27\0"
502
    "%28\0%29\0%2A\0%2B\0%2C\0%2D\0%2E\0%2F\0"
503
    "%30\0%31\0%32\0%33\0%34\0%35\0%36\0%37\0"
504
    "%38\0%39\0%3A\0%3B\0%3C\0%3D\0%3E\0%3F\0"
505
    "%40\0%41\0%42\0%43\0%44\0%45\0%46\0%47\0"
506
    "%48\0%49\0%4A\0%4B\0%4C\0%4D\0%4E\0%4F\0"
507
    "%50\0%51\0%52\0%53\0%54\0%55\0%56\0%57\0"
508
    "%58\0%59\0%5A\0%5B\0%5C\0%5D\0%5E\0%5F\0"
509
    "%60\0%61\0%62\0%63\0%64\0%65\0%66\0%67\0"
510
    "%68\0%69\0%6A\0%6B\0%6C\0%6D\0%6E\0%6F\0"
511
    "%70\0%71\0%72\0%73\0%74\0%75\0%76\0%77\0"
512
    "%78\0%79\0%7A\0%7B\0%7C\0%7D\0%7E\0%7F\0"
513
    "%80\0%81\0%82\0%83\0%84\0%85\0%86\0%87\0"
514
    "%88\0%89\0%8A\0%8B\0%8C\0%8D\0%8E\0%8F\0"
515
    "%90\0%91\0%92\0%93\0%94\0%95\0%96\0%97\0"
516
    "%98\0%99\0%9A\0%9B\0%9C\0%9D\0%9E\0%9F\0"
517
    "%A0\0%A1\0%A2\0%A3\0%A4\0%A5\0%A6\0%A7\0"
518
    "%A8\0%A9\0%AA\0%AB\0%AC\0%AD\0%AE\0%AF\0"
519
    "%B0\0%B1\0%B2\0%B3\0%B4\0%B5\0%B6\0%B7\0"
520
    "%B8\0%B9\0%BA\0%BB\0%BC\0%BD\0%BE\0%BF\0"
521
    "%C0\0%C1\0%C2\0%C3\0%C4\0%C5\0%C6\0%C7\0"
522
    "%C8\0%C9\0%CA\0%CB\0%CC\0%CD\0%CE\0%CF\0"
523
    "%D0\0%D1\0%D2\0%D3\0%D4\0%D5\0%D6\0%D7\0"
524
    "%D8\0%D9\0%DA\0%DB\0%DC\0%DD\0%DE\0%DF\0"
525
    "%E0\0%E1\0%E2\0%E3\0%E4\0%E5\0%E6\0%E7\0"
526
    "%E8\0%E9\0%EA\0%EB\0%EC\0%ED\0%EE\0%EF\0"
527
    "%F0\0%F1\0%F2\0%F3\0%F4\0%F5\0%F6\0%F7\0"
528
    "%F8\0%F9\0%FA\0%FB\0%FC\0%FD\0%FE\0%FF";
529
530
constexpr uint8_t C0_CONTROL_PERCENT_ENCODE[32] = {
531
    // 00     01     02     03     04     05     06     07
532
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
533
    // 08     09     0A     0B     0C     0D     0E     0F
534
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
535
    // 10     11     12     13     14     15     16     17
536
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
537
    // 18     19     1A     1B     1C     1D     1E     1F
538
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
539
    // 20     21     22     23     24     25     26     27
540
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
541
    // 28     29     2A     2B     2C     2D     2E     2F
542
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
543
    // 30     31     32     33     34     35     36     37
544
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
545
    // 38     39     3A     3B     3C     3D     3E     3F
546
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
547
    // 40     41     42     43     44     45     46     47
548
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
549
    // 48     49     4A     4B     4C     4D     4E     4F
550
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
551
    // 50     51     52     53     54     55     56     57
552
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
553
    // 58     59     5A     5B     5C     5D     5E     5F
554
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
555
    // 60     61     62     63     64     65     66     67
556
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
557
    // 68     69     6A     6B     6C     6D     6E     6F
558
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
559
    // 70     71     72     73     74     75     76     77
560
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
561
    // 78     79     7A     7B     7C     7D     7E     7F
562
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x80,
563
    // 80     81     82     83     84     85     86     87
564
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
565
    // 88     89     8A     8B     8C     8D     8E     8F
566
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
567
    // 90     91     92     93     94     95     96     97
568
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
569
    // 98     99     9A     9B     9C     9D     9E     9F
570
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
571
    // A0     A1     A2     A3     A4     A5     A6     A7
572
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
573
    // A8     A9     AA     AB     AC     AD     AE     AF
574
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
575
    // B0     B1     B2     B3     B4     B5     B6     B7
576
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
577
    // B8     B9     BA     BB     BC     BD     BE     BF
578
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
579
    // C0     C1     C2     C3     C4     C5     C6     C7
580
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
581
    // C8     C9     CA     CB     CC     CD     CE     CF
582
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
583
    // D0     D1     D2     D3     D4     D5     D6     D7
584
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
585
    // D8     D9     DA     DB     DC     DD     DE     DF
586
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
587
    // E0     E1     E2     E3     E4     E5     E6     E7
588
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
589
    // E8     E9     EA     EB     EC     ED     EE     EF
590
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
591
    // F0     F1     F2     F3     F4     F5     F6     F7
592
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
593
    // F8     F9     FA     FB     FC     FD     FE     FF
594
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80};
595
596
constexpr uint8_t SPECIAL_QUERY_PERCENT_ENCODE[32] = {
597
    // 00     01     02     03     04     05     06     07
598
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
599
    // 08     09     0A     0B     0C     0D     0E     0F
600
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
601
    // 10     11     12     13     14     15     16     17
602
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
603
    // 18     19     1A     1B     1C     1D     1E     1F
604
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
605
    // 20     21     22     23     24     25     26     27
606
    0x01 | 0x00 | 0x04 | 0x08 | 0x00 | 0x00 | 0x00 | 0x80,
607
    // 28     29     2A     2B     2C     2D     2E     2F
608
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
609
    // 30     31     32     33     34     35     36     37
610
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
611
    // 38     39     3A     3B     3C     3D     3E     3F
612
    0x00 | 0x00 | 0x00 | 0x00 | 0x10 | 0x00 | 0x40 | 0x00,
613
    // 40     41     42     43     44     45     46     47
614
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
615
    // 48     49     4A     4B     4C     4D     4E     4F
616
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
617
    // 50     51     52     53     54     55     56     57
618
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
619
    // 58     59     5A     5B     5C     5D     5E     5F
620
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
621
    // 60     61     62     63     64     65     66     67
622
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
623
    // 68     69     6A     6B     6C     6D     6E     6F
624
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
625
    // 70     71     72     73     74     75     76     77
626
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
627
    // 78     79     7A     7B     7C     7D     7E     7F
628
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x80,
629
    // 80     81     82     83     84     85     86     87
630
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
631
    // 88     89     8A     8B     8C     8D     8E     8F
632
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
633
    // 90     91     92     93     94     95     96     97
634
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
635
    // 98     99     9A     9B     9C     9D     9E     9F
636
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
637
    // A0     A1     A2     A3     A4     A5     A6     A7
638
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
639
    // A8     A9     AA     AB     AC     AD     AE     AF
640
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
641
    // B0     B1     B2     B3     B4     B5     B6     B7
642
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
643
    // B8     B9     BA     BB     BC     BD     BE     BF
644
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
645
    // C0     C1     C2     C3     C4     C5     C6     C7
646
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
647
    // C8     C9     CA     CB     CC     CD     CE     CF
648
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
649
    // D0     D1     D2     D3     D4     D5     D6     D7
650
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
651
    // D8     D9     DA     DB     DC     DD     DE     DF
652
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
653
    // E0     E1     E2     E3     E4     E5     E6     E7
654
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
655
    // E8     E9     EA     EB     EC     ED     EE     EF
656
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
657
    // F0     F1     F2     F3     F4     F5     F6     F7
658
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
659
    // F8     F9     FA     FB     FC     FD     FE     FF
660
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80};
661
662
constexpr uint8_t QUERY_PERCENT_ENCODE[32] = {
663
    // 00     01     02     03     04     05     06     07
664
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
665
    // 08     09     0A     0B     0C     0D     0E     0F
666
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
667
    // 10     11     12     13     14     15     16     17
668
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
669
    // 18     19     1A     1B     1C     1D     1E     1F
670
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
671
    // 20     21     22     23     24     25     26     27
672
    0x01 | 0x00 | 0x04 | 0x08 | 0x00 | 0x00 | 0x00 | 0x00,
673
    // 28     29     2A     2B     2C     2D     2E     2F
674
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
675
    // 30     31     32     33     34     35     36     37
676
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
677
    // 38     39     3A     3B     3C     3D     3E     3F
678
    0x00 | 0x00 | 0x00 | 0x00 | 0x10 | 0x00 | 0x40 | 0x00,
679
    // 40     41     42     43     44     45     46     47
680
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
681
    // 48     49     4A     4B     4C     4D     4E     4F
682
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
683
    // 50     51     52     53     54     55     56     57
684
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
685
    // 58     59     5A     5B     5C     5D     5E     5F
686
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
687
    // 60     61     62     63     64     65     66     67
688
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
689
    // 68     69     6A     6B     6C     6D     6E     6F
690
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
691
    // 70     71     72     73     74     75     76     77
692
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
693
    // 78     79     7A     7B     7C     7D     7E     7F
694
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x80,
695
    // 80     81     82     83     84     85     86     87
696
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
697
    // 88     89     8A     8B     8C     8D     8E     8F
698
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
699
    // 90     91     92     93     94     95     96     97
700
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
701
    // 98     99     9A     9B     9C     9D     9E     9F
702
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
703
    // A0     A1     A2     A3     A4     A5     A6     A7
704
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
705
    // A8     A9     AA     AB     AC     AD     AE     AF
706
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
707
    // B0     B1     B2     B3     B4     B5     B6     B7
708
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
709
    // B8     B9     BA     BB     BC     BD     BE     BF
710
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
711
    // C0     C1     C2     C3     C4     C5     C6     C7
712
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
713
    // C8     C9     CA     CB     CC     CD     CE     CF
714
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
715
    // D0     D1     D2     D3     D4     D5     D6     D7
716
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
717
    // D8     D9     DA     DB     DC     DD     DE     DF
718
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
719
    // E0     E1     E2     E3     E4     E5     E6     E7
720
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
721
    // E8     E9     EA     EB     EC     ED     EE     EF
722
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
723
    // F0     F1     F2     F3     F4     F5     F6     F7
724
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
725
    // F8     F9     FA     FB     FC     FD     FE     FF
726
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80};
727
728
constexpr uint8_t FRAGMENT_PERCENT_ENCODE[32] = {
729
    // 00     01     02     03     04     05     06     07
730
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
731
    // 08     09     0A     0B     0C     0D     0E     0F
732
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
733
    // 10     11     12     13     14     15     16     17
734
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
735
    // 18     19     1A     1B     1C     1D     1E     1F
736
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
737
    // 20     21     22     23     24     25     26     27
738
    0x01 | 0x00 | 0x04 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
739
    // 28     29     2A     2B     2C     2D     2E     2F
740
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
741
    // 30     31     32     33     34     35     36     37
742
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
743
    // 38     39     3A     3B     3C     3D     3E     3F
744
    0x00 | 0x00 | 0x00 | 0x00 | 0x10 | 0x00 | 0x40 | 0x00,
745
    // 40     41     42     43     44     45     46     47
746
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
747
    // 48     49     4A     4B     4C     4D     4E     4F
748
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
749
    // 50     51     52     53     54     55     56     57
750
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
751
    // 58     59     5A     5B     5C     5D     5E     5F
752
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
753
    // 60     61     62     63     64     65     66     67
754
    0x01 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
755
    // 68     69     6A     6B     6C     6D     6E     6F
756
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
757
    // 70     71     72     73     74     75     76     77
758
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
759
    // 78     79     7A     7B     7C     7D     7E     7F
760
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x80,
761
    // 80     81     82     83     84     85     86     87
762
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
763
    // 88     89     8A     8B     8C     8D     8E     8F
764
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
765
    // 90     91     92     93     94     95     96     97
766
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
767
    // 98     99     9A     9B     9C     9D     9E     9F
768
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
769
    // A0     A1     A2     A3     A4     A5     A6     A7
770
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
771
    // A8     A9     AA     AB     AC     AD     AE     AF
772
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
773
    // B0     B1     B2     B3     B4     B5     B6     B7
774
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
775
    // B8     B9     BA     BB     BC     BD     BE     BF
776
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
777
    // C0     C1     C2     C3     C4     C5     C6     C7
778
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
779
    // C8     C9     CA     CB     CC     CD     CE     CF
780
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
781
    // D0     D1     D2     D3     D4     D5     D6     D7
782
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
783
    // D8     D9     DA     DB     DC     DD     DE     DF
784
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
785
    // E0     E1     E2     E3     E4     E5     E6     E7
786
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
787
    // E8     E9     EA     EB     EC     ED     EE     EF
788
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
789
    // F0     F1     F2     F3     F4     F5     F6     F7
790
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
791
    // F8     F9     FA     FB     FC     FD     FE     FF
792
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80};
793
794
constexpr uint8_t USERINFO_PERCENT_ENCODE[32] = {
795
    // 00     01     02     03     04     05     06     07
796
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
797
    // 08     09     0A     0B     0C     0D     0E     0F
798
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
799
    // 10     11     12     13     14     15     16     17
800
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
801
    // 18     19     1A     1B     1C     1D     1E     1F
802
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
803
    // 20     21     22     23     24     25     26     27
804
    0x01 | 0x00 | 0x04 | 0x08 | 0x00 | 0x00 | 0x00 | 0x00,
805
    // 28     29     2A     2B     2C     2D     2E     2F
806
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x80,
807
    // 30     31     32     33     34     35     36     37
808
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
809
    // 38     39     3A     3B     3C     3D     3E     3F
810
    0x00 | 0x00 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
811
    // 40     41     42     43     44     45     46     47
812
    0x01 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
813
    // 48     49     4A     4B     4C     4D     4E     4F
814
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
815
    // 50     51     52     53     54     55     56     57
816
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
817
    // 58     59     5A     5B     5C     5D     5E     5F
818
    0x00 | 0x00 | 0x00 | 0x08 | 0x10 | 0x20 | 0x40 | 0x00,
819
    // 60     61     62     63     64     65     66     67
820
    0x01 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
821
    // 68     69     6A     6B     6C     6D     6E     6F
822
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
823
    // 70     71     72     73     74     75     76     77
824
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
825
    // 78     79     7A     7B     7C     7D     7E     7F
826
    0x00 | 0x00 | 0x00 | 0x08 | 0x10 | 0x20 | 0x00 | 0x80,
827
    // 80     81     82     83     84     85     86     87
828
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
829
    // 88     89     8A     8B     8C     8D     8E     8F
830
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
831
    // 90     91     92     93     94     95     96     97
832
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
833
    // 98     99     9A     9B     9C     9D     9E     9F
834
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
835
    // A0     A1     A2     A3     A4     A5     A6     A7
836
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
837
    // A8     A9     AA     AB     AC     AD     AE     AF
838
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
839
    // B0     B1     B2     B3     B4     B5     B6     B7
840
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
841
    // B8     B9     BA     BB     BC     BD     BE     BF
842
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
843
    // C0     C1     C2     C3     C4     C5     C6     C7
844
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
845
    // C8     C9     CA     CB     CC     CD     CE     CF
846
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
847
    // D0     D1     D2     D3     D4     D5     D6     D7
848
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
849
    // D8     D9     DA     DB     DC     DD     DE     DF
850
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
851
    // E0     E1     E2     E3     E4     E5     E6     E7
852
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
853
    // E8     E9     EA     EB     EC     ED     EE     EF
854
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
855
    // F0     F1     F2     F3     F4     F5     F6     F7
856
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
857
    // F8     F9     FA     FB     FC     FD     FE     FF
858
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80};
859
860
constexpr uint8_t PATH_PERCENT_ENCODE[32] = {
861
    // 00     01     02     03     04     05     06     07
862
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
863
    // 08     09     0A     0B     0C     0D     0E     0F
864
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
865
    // 10     11     12     13     14     15     16     17
866
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
867
    // 18     19     1A     1B     1C     1D     1E     1F
868
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
869
    // 20     21     22     23     24     25     26     27
870
    0x01 | 0x00 | 0x04 | 0x08 | 0x00 | 0x00 | 0x00 | 0x00,
871
    // 28     29     2A     2B     2C     2D     2E     2F
872
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
873
    // 30     31     32     33     34     35     36     37
874
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
875
    // 38     39     3A     3B     3C     3D     3E     3F
876
    0x00 | 0x00 | 0x00 | 0x00 | 0x10 | 0x00 | 0x40 | 0x80,
877
    // 40     41     42     43     44     45     46     47
878
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
879
    // 48     49     4A     4B     4C     4D     4E     4F
880
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
881
    // 50     51     52     53     54     55     56     57
882
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
883
    // 58     59     5A     5B     5C     5D     5E     5F
884
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x40 | 0x00,
885
    // 60     61     62     63     64     65     66     67
886
    0x01 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
887
    // 68     69     6A     6B     6C     6D     6E     6F
888
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
889
    // 70     71     72     73     74     75     76     77
890
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
891
    // 78     79     7A     7B     7C     7D     7E     7F
892
    0x00 | 0x00 | 0x00 | 0x08 | 0x00 | 0x20 | 0x00 | 0x80,
893
    // 80     81     82     83     84     85     86     87
894
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
895
    // 88     89     8A     8B     8C     8D     8E     8F
896
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
897
    // 90     91     92     93     94     95     96     97
898
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
899
    // 98     99     9A     9B     9C     9D     9E     9F
900
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
901
    // A0     A1     A2     A3     A4     A5     A6     A7
902
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
903
    // A8     A9     AA     AB     AC     AD     AE     AF
904
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
905
    // B0     B1     B2     B3     B4     B5     B6     B7
906
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
907
    // B8     B9     BA     BB     BC     BD     BE     BF
908
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
909
    // C0     C1     C2     C3     C4     C5     C6     C7
910
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
911
    // C8     C9     CA     CB     CC     CD     CE     CF
912
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
913
    // D0     D1     D2     D3     D4     D5     D6     D7
914
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
915
    // D8     D9     DA     DB     DC     DD     DE     DF
916
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
917
    // E0     E1     E2     E3     E4     E5     E6     E7
918
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
919
    // E8     E9     EA     EB     EC     ED     EE     EF
920
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
921
    // F0     F1     F2     F3     F4     F5     F6     F7
922
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
923
    // F8     F9     FA     FB     FC     FD     FE     FF
924
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80};
925
926
constexpr uint8_t WWW_FORM_URLENCODED_PERCENT_ENCODE[32] = {
927
    // 00     01     02     03     04     05     06     07
928
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
929
    // 08     09     0A     0B     0C     0D     0E     0F
930
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
931
    // 10     11     12     13     14     15     16     17
932
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
933
    // 18     19     1A     1B     1C     1D     1E     1F
934
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
935
    // 20     21     22     23     24     25     26     27
936
    0x00 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
937
    // 28     29     2A     2B     2C     2D     2E     2F
938
    0x01 | 0x02 | 0x00 | 0x08 | 0x10 | 0x00 | 0x00 | 0x80,
939
    // 30     31     32     33     34     35     36     37
940
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
941
    // 38     39     3A     3B     3C     3D     3E     3F
942
    0x00 | 0x00 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
943
    // 40     41     42     43     44     45     46     47
944
    0x01 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
945
    // 48     49     4A     4B     4C     4D     4E     4F
946
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
947
    // 50     51     52     53     54     55     56     57
948
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
949
    // 58     59     5A     5B     5C     5D     5E     5F
950
    0x00 | 0x00 | 0x00 | 0x08 | 0x10 | 0x20 | 0x40 | 0x00,
951
    // 60     61     62     63     64     65     66     67
952
    0x01 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
953
    // 68     69     6A     6B     6C     6D     6E     6F
954
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
955
    // 70     71     72     73     74     75     76     77
956
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
957
    // 78     79     7A     7B     7C     7D     7E     7F
958
    0x00 | 0x00 | 0x00 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
959
    // 80     81     82     83     84     85     86     87
960
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
961
    // 88     89     8A     8B     8C     8D     8E     8F
962
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
963
    // 90     91     92     93     94     95     96     97
964
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
965
    // 98     99     9A     9B     9C     9D     9E     9F
966
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
967
    // A0     A1     A2     A3     A4     A5     A6     A7
968
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
969
    // A8     A9     AA     AB     AC     AD     AE     AF
970
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
971
    // B0     B1     B2     B3     B4     B5     B6     B7
972
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
973
    // B8     B9     BA     BB     BC     BD     BE     BF
974
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
975
    // C0     C1     C2     C3     C4     C5     C6     C7
976
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
977
    // C8     C9     CA     CB     CC     CD     CE     CF
978
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
979
    // D0     D1     D2     D3     D4     D5     D6     D7
980
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
981
    // D8     D9     DA     DB     DC     DD     DE     DF
982
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
983
    // E0     E1     E2     E3     E4     E5     E6     E7
984
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
985
    // E8     E9     EA     EB     EC     ED     EE     EF
986
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
987
    // F0     F1     F2     F3     F4     F5     F6     F7
988
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
989
    // F8     F9     FA     FB     FC     FD     FE     FF
990
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80};
991
992
6.27M
ada_really_inline constexpr bool bit_at(const uint8_t a[], const uint8_t i) {
993
6.27M
  return !!(a[i >> 3] & (1 << (i & 7)));
994
6.27M
}
995
996
}  // namespace ada::character_sets
997
998
#endif  // ADA_CHARACTER_SETS_INL_H
999
/* end file include/ada/character_sets-inl.h */
1000
/* begin file include/ada/checkers-inl.h */
1001
/**
1002
 * @file checkers-inl.h
1003
 * @brief Definitions for URL specific checkers used within Ada.
1004
 */
1005
#ifndef ADA_CHECKERS_INL_H
1006
#define ADA_CHECKERS_INL_H
1007
1008
#include <bit>
1009
#include <string_view>
1010
1011
namespace ada::checkers {
1012
1013
8.72k
constexpr bool has_hex_prefix_unsafe(std::string_view input) {
1014
  // This is actually efficient code, see has_hex_prefix for the assembly.
1015
8.72k
  constexpr bool is_little_endian = std::endian::native == std::endian::little;
1016
8.72k
  constexpr uint16_t word0x = 0x7830;
1017
8.72k
  uint16_t two_first_bytes =
1018
8.72k
      static_cast<uint16_t>(input[0]) |
1019
8.72k
      static_cast<uint16_t>((static_cast<uint16_t>(input[1]) << 8));
1020
8.72k
  if constexpr (is_little_endian) {
1021
8.72k
    two_first_bytes |= 0x2000;
1022
  } else {
1023
    two_first_bytes |= 0x020;
1024
  }
1025
8.72k
  return two_first_bytes == word0x;
1026
8.72k
}
1027
1028
10.6k
constexpr bool has_hex_prefix(std::string_view input) {
1029
10.6k
  return input.size() >= 2 && has_hex_prefix_unsafe(input);
1030
10.6k
}
1031
1032
67.7k
constexpr bool is_digit(char x) noexcept { return (x >= '0') & (x <= '9'); }
1033
1034
258k
constexpr char to_lower(char x) noexcept { return (x | 0x20); }
1035
1036
145k
constexpr bool is_alpha(char x) noexcept {
1037
145k
  return (to_lower(x) >= 'a') && (to_lower(x) <= 'z');
1038
145k
}
1039
1040
36.5k
constexpr bool is_windows_drive_letter(std::string_view input) noexcept {
1041
36.5k
  return input.size() >= 2 &&
1042
36.5k
         (is_alpha(input[0]) && ((input[1] == ':') || (input[1] == '|'))) &&
1043
36.5k
         ((input.size() == 2) || (input[2] == '/' || input[2] == '\\' ||
1044
2.81k
                                  input[2] == '?' || input[2] == '#'));
1045
36.5k
}
1046
1047
constexpr bool is_normalized_windows_drive_letter(
1048
13.6k
    std::string_view input) noexcept {
1049
13.6k
  return input.size() >= 2 && (is_alpha(input[0]) && (input[1] == ':'));
1050
13.6k
}
1051
1052
}  // namespace ada::checkers
1053
1054
#endif  // ADA_CHECKERS_INL_H
1055
/* end file include/ada/checkers-inl.h */
1056
/* begin file include/ada/log.h */
1057
/**
1058
 * @file log.h
1059
 * @brief Includes the definitions for logging.
1060
 * @private Excluded from docs through the doxygen file.
1061
 */
1062
#ifndef ADA_LOG_H
1063
#define ADA_LOG_H
1064
1065
// To enable logging, set ADA_LOGGING to 1:
1066
#ifndef ADA_LOGGING
1067
#define ADA_LOGGING 0
1068
#endif
1069
1070
#if ADA_LOGGING
1071
#include <iostream>
1072
#endif  // ADA_LOGGING
1073
1074
namespace ada {
1075
1076
/**
1077
 * Log a message. If you want to have no overhead when logging is disabled, use
1078
 * the ada_log macro.
1079
 * @private
1080
 */
1081
template <typename... Args>
1082
constexpr ada_really_inline void log([[maybe_unused]] Args... args) {
1083
#if ADA_LOGGING
1084
  ((std::cout << "ADA_LOG: ") << ... << args) << std::endl;
1085
#endif  // ADA_LOGGING
1086
}
1087
}  // namespace ada
1088
1089
#if ADA_LOGGING
1090
#ifndef ada_log
1091
#define ada_log(...)       \
1092
  do {                     \
1093
    ada::log(__VA_ARGS__); \
1094
  } while (0)
1095
#endif  // ada_log
1096
#else
1097
#define ada_log(...)
1098
#endif  // ADA_LOGGING
1099
1100
#endif  // ADA_LOG_H
1101
/* end file include/ada/log.h */
1102
/* begin file include/ada/encoding_type.h */
1103
/**
1104
 * @file encoding_type.h
1105
 * @brief Definition for supported encoding types.
1106
 */
1107
#ifndef ADA_ENCODING_TYPE_H
1108
#define ADA_ENCODING_TYPE_H
1109
1110
#include <string>
1111
1112
namespace ada {
1113
1114
/**
1115
 * This specification defines three encodings with the same names as encoding
1116
 * schemes defined in the Unicode standard: UTF-8, UTF-16LE, and UTF-16BE.
1117
 *
1118
 * @see https://encoding.spec.whatwg.org/#encodings
1119
 */
1120
enum class encoding_type {
1121
  UTF8,
1122
  UTF_16LE,
1123
  UTF_16BE,
1124
};
1125
1126
/**
1127
 * Convert a encoding_type to string.
1128
 */
1129
ada_warn_unused std::string_view to_string(encoding_type type);
1130
1131
}  // namespace ada
1132
1133
#endif  // ADA_ENCODING_TYPE_H
1134
/* end file include/ada/encoding_type.h */
1135
/* begin file include/ada/helpers.h */
1136
/**
1137
 * @file helpers.h
1138
 * @brief Definitions for helper functions used within Ada.
1139
 */
1140
#ifndef ADA_HELPERS_H
1141
#define ADA_HELPERS_H
1142
1143
/* begin file include/ada/url_base.h */
1144
/**
1145
 * @file url_base.h
1146
 * @brief Declaration for the basic URL definitions
1147
 */
1148
#ifndef ADA_URL_BASE_H
1149
#define ADA_URL_BASE_H
1150
1151
/* begin file include/ada/scheme.h */
1152
/**
1153
 * @file scheme.h
1154
 * @brief Declarations for the URL scheme.
1155
 */
1156
#ifndef ADA_SCHEME_H
1157
#define ADA_SCHEME_H
1158
1159
1160
#include <string>
1161
1162
/**
1163
 * @namespace ada::scheme
1164
 * @brief Includes the scheme declarations
1165
 */
1166
namespace ada::scheme {
1167
1168
/**
1169
 * Type of the scheme as an enum.
1170
 * Using strings to represent a scheme type is not ideal because
1171
 * checking for types involves string comparisons. It is faster to use
1172
 * a simple integer.
1173
 * In C++11, we are allowed to specify the underlying type of the enum.
1174
 * We pick an 8-bit integer (which allows up to 256 types). Specifying the
1175
 * type of the enum may help integration with other systems if the type
1176
 * variable is exposed (since its value will not depend on the compiler).
1177
 */
1178
enum type : uint8_t {
1179
  HTTP = 0,
1180
  NOT_SPECIAL = 1,
1181
  HTTPS = 2,
1182
  WS = 3,
1183
  FTP = 4,
1184
  WSS = 5,
1185
  FILE = 6
1186
};
1187
1188
/**
1189
 * A special scheme is an ASCII string that is listed in the first column of the
1190
 * following table. The default port for a special scheme is listed in the
1191
 * second column on the same row. The default port for any other ASCII string is
1192
 * null.
1193
 *
1194
 * @see https://url.spec.whatwg.org/#url-miscellaneous
1195
 * @param scheme
1196
 * @return If scheme is a special scheme
1197
 */
1198
ada_really_inline constexpr bool is_special(std::string_view scheme);
1199
1200
/**
1201
 * A special scheme is an ASCII string that is listed in the first column of the
1202
 * following table. The default port for a special scheme is listed in the
1203
 * second column on the same row. The default port for any other ASCII string is
1204
 * null.
1205
 *
1206
 * @see https://url.spec.whatwg.org/#url-miscellaneous
1207
 * @param scheme
1208
 * @return The special port
1209
 */
1210
constexpr uint16_t get_special_port(std::string_view scheme) noexcept;
1211
1212
/**
1213
 * Returns the port number of a special scheme.
1214
 * @see https://url.spec.whatwg.org/#special-scheme
1215
 */
1216
constexpr uint16_t get_special_port(ada::scheme::type type) noexcept;
1217
/**
1218
 * Returns the scheme of an input, or NOT_SPECIAL if it's not a special scheme
1219
 * defined by the spec.
1220
 */
1221
constexpr ada::scheme::type get_scheme_type(std::string_view scheme) noexcept;
1222
1223
}  // namespace ada::scheme
1224
1225
#endif  // ADA_SCHEME_H
1226
/* end file include/ada/scheme.h */
1227
1228
#include <string>
1229
#include <string_view>
1230
1231
namespace ada {
1232
1233
/**
1234
 * Type of URL host as an enum.
1235
 */
1236
enum url_host_type : uint8_t {
1237
  /**
1238
   * Represents common URLs such as "https://www.google.com"
1239
   */
1240
  DEFAULT = 0,
1241
  /**
1242
   * Represents ipv4 addresses such as "http://127.0.0.1"
1243
   */
1244
  IPV4 = 1,
1245
  /**
1246
   * Represents ipv6 addresses such as
1247
   * "http://[2001:db8:3333:4444:5555:6666:7777:8888]"
1248
   */
1249
  IPV6 = 2,
1250
};
1251
1252
/**
1253
 * @brief Base class of URL implementations
1254
 *
1255
 * @details A url_base contains a few attributes: is_valid, has_opaque_path and
1256
 * type. All non-trivial implementation details are in derived classes such as
1257
 * ada::url and ada::url_aggregator.
1258
 *
1259
 * It is an abstract class that cannot be instantiated directly.
1260
 */
1261
struct url_base {
1262
155k
  virtual ~url_base() = default;
1263
1264
  /**
1265
   * Used for returning the validity from the result of the URL parser.
1266
   */
1267
  bool is_valid{true};
1268
1269
  /**
1270
   * A URL has an opaque path if its path is a string.
1271
   */
1272
  bool has_opaque_path{false};
1273
1274
  /**
1275
   * URL hosts type
1276
   */
1277
  url_host_type host_type = url_host_type::DEFAULT;
1278
1279
  /**
1280
   * @private
1281
   */
1282
  ada::scheme::type type{ada::scheme::type::NOT_SPECIAL};
1283
1284
  /**
1285
   * A URL is special if its scheme is a special scheme. A URL is not special if
1286
   * its scheme is not a special scheme.
1287
   */
1288
  [[nodiscard]] ada_really_inline constexpr bool is_special() const noexcept;
1289
1290
  /**
1291
   * The origin getter steps are to return the serialization of this's URL's
1292
   * origin. [HTML]
1293
   * @return a newly allocated string.
1294
   * @see https://url.spec.whatwg.org/#concept-url-origin
1295
   */
1296
  [[nodiscard]] virtual std::string get_origin() const noexcept = 0;
1297
1298
  /**
1299
   * Returns true if this URL has a valid domain as per RFC 1034 and
1300
   * corresponding specifications. Among other things, it requires
1301
   * that the domain string has fewer than 255 octets.
1302
   */
1303
  [[nodiscard]] virtual bool has_valid_domain() const noexcept = 0;
1304
1305
  /**
1306
   * @private
1307
   *
1308
   * Return the 'special port' if the URL is special and not 'file'.
1309
   * Returns 0 otherwise.
1310
   */
1311
  [[nodiscard]] inline uint16_t get_special_port() const noexcept;
1312
1313
  /**
1314
   * @private
1315
   *
1316
   * Get the default port if the url's scheme has one, returns 0 otherwise.
1317
   */
1318
  [[nodiscard]] ada_really_inline uint16_t scheme_default_port() const noexcept;
1319
1320
  /**
1321
   * @private
1322
   *
1323
   * Parse a port (16-bit decimal digit) from the provided input.
1324
   * We assume that the input does not contain spaces or tabs
1325
   * within the ASCII digits.
1326
   * It returns how many bytes were consumed when a number is successfully
1327
   * parsed.
1328
   * @return On failure, it returns zero.
1329
   * @see https://url.spec.whatwg.org/#host-parsing
1330
   */
1331
  virtual size_t parse_port(std::string_view view,
1332
                            bool check_trailing_content) noexcept = 0;
1333
1334
0
  virtual ada_really_inline size_t parse_port(std::string_view view) noexcept {
1335
0
    return this->parse_port(view, false);
1336
0
  }
1337
1338
  /**
1339
   * Returns a JSON string representation of this URL.
1340
   */
1341
  [[nodiscard]] virtual std::string to_string() const = 0;
1342
1343
  /** @private */
1344
  virtual inline void clear_pathname() = 0;
1345
1346
  /** @private */
1347
  virtual inline void clear_search() = 0;
1348
1349
  /** @private */
1350
  [[nodiscard]] virtual inline bool has_hash() const noexcept = 0;
1351
1352
  /** @private */
1353
  [[nodiscard]] virtual inline bool has_search() const noexcept = 0;
1354
1355
};  // url_base
1356
1357
}  // namespace ada
1358
1359
#endif
1360
/* end file include/ada/url_base.h */
1361
1362
#include <string>
1363
#include <string_view>
1364
#include <optional>
1365
1366
#if ADA_DEVELOPMENT_CHECKS
1367
#include <iostream>
1368
#endif  // ADA_DEVELOPMENT_CHECKS
1369
1370
/**
1371
 * These functions are not part of our public API and may
1372
 * change at any time.
1373
 *
1374
 * @private
1375
 * @namespace ada::helpers
1376
 * @brief Includes the definitions for helper functions
1377
 */
1378
namespace ada::helpers {
1379
1380
/**
1381
 * @private
1382
 */
1383
template <typename out_iter>
1384
void encode_json(std::string_view view, out_iter out);
1385
1386
/**
1387
 * @private
1388
 * This function is used to prune a fragment from a url, and returning the
1389
 * removed string if input has fragment.
1390
 *
1391
 * @details prune_hash seeks the first '#' and returns everything after it
1392
 * as a string_view, and modifies (in place) the input so that it points at
1393
 * everything before the '#'. If no '#' is found, the input is left unchanged
1394
 * and std::nullopt is returned.
1395
 *
1396
 * @attention The function is non-allocating and it does not throw.
1397
 * @returns Note that the returned string_view might be empty!
1398
 */
1399
ada_really_inline std::optional<std::string_view> prune_hash(
1400
    std::string_view& input) noexcept;
1401
1402
/**
1403
 * @private
1404
 * Defined by the URL specification, shorten a URLs paths.
1405
 * @see https://url.spec.whatwg.org/#shorten-a-urls-path
1406
 * @returns Returns true if path is shortened.
1407
 */
1408
ada_really_inline bool shorten_path(std::string& path,
1409
                                    ada::scheme::type type) noexcept;
1410
1411
/**
1412
 * @private
1413
 * Defined by the URL specification, shorten a URLs paths.
1414
 * @see https://url.spec.whatwg.org/#shorten-a-urls-path
1415
 * @returns Returns true if path is shortened.
1416
 */
1417
ada_really_inline bool shorten_path(std::string_view& path,
1418
                                    ada::scheme::type type) noexcept;
1419
1420
/**
1421
 * @private
1422
 *
1423
 * Parse the path from the provided input and append to the existing
1424
 * (possibly empty) path. The input cannot contain tabs and spaces: it
1425
 * is the user's responsibility to check.
1426
 *
1427
 * The input is expected to be UTF-8.
1428
 *
1429
 * @see https://url.spec.whatwg.org/
1430
 */
1431
ada_really_inline void parse_prepared_path(std::string_view input,
1432
                                           ada::scheme::type type,
1433
                                           std::string& path);
1434
1435
/**
1436
 * @private
1437
 * Remove and mutate all ASCII tab or newline characters from an input.
1438
 */
1439
ada_really_inline void remove_ascii_tab_or_newline(std::string& input) noexcept;
1440
1441
/**
1442
 * @private
1443
 * Return the substring from input going from index pos to the end.
1444
 * This function cannot throw.
1445
 */
1446
ada_really_inline constexpr std::string_view substring(std::string_view input,
1447
                                                       size_t pos) noexcept;
1448
1449
/**
1450
 * @private
1451
 * Returns true if the string_view points within the string.
1452
 */
1453
bool overlaps(std::string_view input1, const std::string& input2) noexcept;
1454
1455
/**
1456
 * @private
1457
 * Return the substring from input going from index pos1 to the pos2 (non
1458
 * included). The length of the substring is pos2 - pos1.
1459
 */
1460
ada_really_inline constexpr std::string_view substring(std::string_view input,
1461
                                                       size_t pos1,
1462
417k
                                                       size_t pos2) noexcept {
1463
#if ADA_DEVELOPMENT_CHECKS
1464
  if (pos2 < pos1) {
1465
    std::cerr << "Negative-length substring: [" << pos1 << " to " << pos2 << ")"
1466
              << std::endl;
1467
    abort();
1468
  }
1469
#endif
1470
417k
  return input.substr(pos1, pos2 - pos1);
1471
417k
}
1472
1473
/**
1474
 * @private
1475
 * Modify the string_view so that it has the new size pos, assuming that pos <=
1476
 * input.size(). This function cannot throw.
1477
 */
1478
ada_really_inline void resize(std::string_view& input, size_t pos) noexcept;
1479
1480
/**
1481
 * @private
1482
 * Returns a host's delimiter location depending on the state of the instance,
1483
 * and whether a colon was found outside brackets. Used by the host parser.
1484
 */
1485
ada_really_inline std::pair<size_t, bool> get_host_delimiter_location(
1486
    bool is_special, std::string_view& view) noexcept;
1487
1488
/**
1489
 * @private
1490
 * Removes leading and trailing C0 control and whitespace characters from
1491
 * string.
1492
 */
1493
void trim_c0_whitespace(std::string_view& input) noexcept;
1494
1495
/**
1496
 * @private
1497
 * @see
1498
 * https://url.spec.whatwg.org/#potentially-strip-trailing-spaces-from-an-opaque-path
1499
 */
1500
template <class url_type>
1501
ada_really_inline void strip_trailing_spaces_from_opaque_path(
1502
    url_type& url) noexcept;
1503
1504
/**
1505
 * @private
1506
 * Finds the delimiter of a view in authority state.
1507
 */
1508
ada_really_inline size_t
1509
find_authority_delimiter_special(std::string_view view) noexcept;
1510
1511
/**
1512
 * @private
1513
 * Finds the delimiter of a view in authority state.
1514
 */
1515
ada_really_inline size_t
1516
find_authority_delimiter(std::string_view view) noexcept;
1517
1518
/**
1519
 * @private
1520
 */
1521
template <typename T, typename... Args>
1522
89.9k
inline void inner_concat(std::string& buffer, T t) {
1523
89.9k
  buffer.append(t);
1524
89.9k
}
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
1522
11.7k
inline void inner_concat(std::string& buffer, T t) {
1523
11.7k
  buffer.append(t);
1524
11.7k
}
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
1522
65.9k
inline void inner_concat(std::string& buffer, T t) {
1523
65.9k
  buffer.append(t);
1524
65.9k
}
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
1522
12.3k
inline void inner_concat(std::string& buffer, T t) {
1523
12.3k
  buffer.append(t);
1524
12.3k
}
1525
1526
/**
1527
 * @private
1528
 */
1529
template <typename T, typename... Args>
1530
111k
inline void inner_concat(std::string& buffer, T t, Args... args) {
1531
111k
  buffer.append(t);
1532
111k
  return inner_concat(buffer, args...);
1533
111k
}
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
1530
11.7k
inline void inner_concat(std::string& buffer, T t, Args... args) {
1531
11.7k
  buffer.append(t);
1532
11.7k
  return inner_concat(buffer, args...);
1533
11.7k
}
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
1530
9.26k
inline void inner_concat(std::string& buffer, T t, Args... args) {
1531
9.26k
  buffer.append(t);
1532
9.26k
  return inner_concat(buffer, args...);
1533
9.26k
}
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
1530
60.5k
inline void inner_concat(std::string& buffer, T t, Args... args) {
1531
60.5k
  buffer.append(t);
1532
60.5k
  return inner_concat(buffer, args...);
1533
60.5k
}
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
1530
5.38k
inline void inner_concat(std::string& buffer, T t, Args... args) {
1531
5.38k
  buffer.append(t);
1532
5.38k
  return inner_concat(buffer, args...);
1533
5.38k
}
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
1530
12.3k
inline void inner_concat(std::string& buffer, T t, Args... args) {
1531
12.3k
  buffer.append(t);
1532
12.3k
  return inner_concat(buffer, args...);
1533
12.3k
}
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
1530
12.3k
inline void inner_concat(std::string& buffer, T t, Args... args) {
1531
12.3k
  buffer.append(t);
1532
12.3k
  return inner_concat(buffer, args...);
1533
12.3k
}
1534
1535
/**
1536
 * @private
1537
 * Concatenate the arguments and return a string.
1538
 * @returns a string
1539
 */
1540
template <typename... Args>
1541
89.9k
std::string concat(Args... args) {
1542
89.9k
  std::string answer;
1543
89.9k
  inner_concat(answer, args...);
1544
89.9k
  return answer;
1545
89.9k
}
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
1541
2.44k
std::string concat(Args... args) {
1542
2.44k
  std::string answer;
1543
2.44k
  inner_concat(answer, args...);
1544
2.44k
  return answer;
1545
2.44k
}
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
1541
9.26k
std::string concat(Args... args) {
1542
9.26k
  std::string answer;
1543
9.26k
  inner_concat(answer, args...);
1544
9.26k
  return answer;
1545
9.26k
}
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
1541
60.5k
std::string concat(Args... args) {
1542
60.5k
  std::string answer;
1543
60.5k
  inner_concat(answer, args...);
1544
60.5k
  return answer;
1545
60.5k
}
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
1541
5.38k
std::string concat(Args... args) {
1542
5.38k
  std::string answer;
1543
5.38k
  inner_concat(answer, args...);
1544
5.38k
  return answer;
1545
5.38k
}
Unexecuted instantiation: 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> >)
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
1541
12.3k
std::string concat(Args... args) {
1542
12.3k
  std::string answer;
1543
12.3k
  inner_concat(answer, args...);
1544
12.3k
  return answer;
1545
12.3k
}
1546
1547
/**
1548
 * @private
1549
 * @return Number of leading zeroes.
1550
 */
1551
41.2k
inline int leading_zeroes(uint32_t input_num) noexcept {
1552
#if ADA_REGULAR_VISUAL_STUDIO
1553
  unsigned long leading_zero(0);
1554
  unsigned long in(input_num);
1555
  return _BitScanReverse(&leading_zero, in) ? int(31 - leading_zero) : 32;
1556
#else
1557
41.2k
  return __builtin_clz(input_num);
1558
41.2k
#endif  // ADA_REGULAR_VISUAL_STUDIO
1559
41.2k
}
1560
1561
/**
1562
 * @private
1563
 * Counts the number of decimal digits necessary to represent x.
1564
 * faster than std::to_string(x).size().
1565
 * @return digit count
1566
 */
1567
938
inline int fast_digit_count(uint32_t x) noexcept {
1568
938
  auto int_log2 = [](uint32_t z) -> int {
1569
938
    return 31 - ada::helpers::leading_zeroes(z | 1);
1570
938
  };
1571
  // Compiles to very few instructions. Note that the
1572
  // table is static and thus effectively a constant.
1573
  // We leave it inside the function because it is meaningless
1574
  // outside of it (this comes at no performance cost).
1575
938
  const static uint64_t table[] = {
1576
938
      4294967296,  8589934582,  8589934582,  8589934582,  12884901788,
1577
938
      12884901788, 12884901788, 17179868184, 17179868184, 17179868184,
1578
938
      21474826480, 21474826480, 21474826480, 21474826480, 25769703776,
1579
938
      25769703776, 25769703776, 30063771072, 30063771072, 30063771072,
1580
938
      34349738368, 34349738368, 34349738368, 34349738368, 38554705664,
1581
938
      38554705664, 38554705664, 41949672960, 41949672960, 41949672960,
1582
938
      42949672960, 42949672960};
1583
938
  return int((x + table[int_log2(x)]) >> 32);
1584
938
}
1585
}  // namespace ada::helpers
1586
1587
#endif  // ADA_HELPERS_H
1588
/* end file include/ada/helpers.h */
1589
/* begin file include/ada/parser.h */
1590
/**
1591
 * @file parser.h
1592
 * @brief Definitions for the parser.
1593
 */
1594
#ifndef ADA_PARSER_H
1595
#define ADA_PARSER_H
1596
1597
#include <string_view>
1598
#include <variant>
1599
1600
/* begin file include/ada/expected.h */
1601
/**
1602
 * @file expected.h
1603
 * @brief Definitions for std::expected
1604
 * @private Excluded from docs through the doxygen file.
1605
 */
1606
///
1607
// expected - An implementation of std::expected with extensions
1608
// Written in 2017 by Sy Brand (tartanllama@gmail.com, @TartanLlama)
1609
//
1610
// Documentation available at http://tl.tartanllama.xyz/
1611
//
1612
// To the extent possible under law, the author(s) have dedicated all
1613
// copyright and related and neighboring rights to this software to the
1614
// public domain worldwide. This software is distributed without any warranty.
1615
//
1616
// You should have received a copy of the CC0 Public Domain Dedication
1617
// along with this software. If not, see
1618
// <http://creativecommons.org/publicdomain/zero/1.0/>.
1619
///
1620
1621
#ifndef TL_EXPECTED_HPP
1622
#define TL_EXPECTED_HPP
1623
1624
#define TL_EXPECTED_VERSION_MAJOR 1
1625
#define TL_EXPECTED_VERSION_MINOR 1
1626
#define TL_EXPECTED_VERSION_PATCH 0
1627
1628
#include <exception>
1629
#include <functional>
1630
#include <type_traits>
1631
#include <utility>
1632
1633
#if defined(__EXCEPTIONS) || defined(_CPPUNWIND)
1634
#define TL_EXPECTED_EXCEPTIONS_ENABLED
1635
#endif
1636
1637
#if (defined(_MSC_VER) && _MSC_VER == 1900)
1638
#define TL_EXPECTED_MSVC2015
1639
#define TL_EXPECTED_MSVC2015_CONSTEXPR
1640
#else
1641
#define TL_EXPECTED_MSVC2015_CONSTEXPR constexpr
1642
#endif
1643
1644
#if (defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ <= 9 && \
1645
     !defined(__clang__))
1646
#define TL_EXPECTED_GCC49
1647
#endif
1648
1649
#if (defined(__GNUC__) && __GNUC__ == 5 && __GNUC_MINOR__ <= 4 && \
1650
     !defined(__clang__))
1651
#define TL_EXPECTED_GCC54
1652
#endif
1653
1654
#if (defined(__GNUC__) && __GNUC__ == 5 && __GNUC_MINOR__ <= 5 && \
1655
     !defined(__clang__))
1656
#define TL_EXPECTED_GCC55
1657
#endif
1658
1659
#if !defined(TL_ASSERT)
1660
// can't have assert in constexpr in C++11 and GCC 4.9 has a compiler bug
1661
#if (__cplusplus > 201103L) && !defined(TL_EXPECTED_GCC49)
1662
#include <cassert>
1663
740k
#define TL_ASSERT(x) assert(x)
1664
#else
1665
#define TL_ASSERT(x)
1666
#endif
1667
#endif
1668
1669
#if (defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ <= 9 && \
1670
     !defined(__clang__))
1671
// GCC < 5 doesn't support overloading on const&& for member functions
1672
1673
#define TL_EXPECTED_NO_CONSTRR
1674
// GCC < 5 doesn't support some standard C++11 type traits
1675
#define TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) \
1676
  std::has_trivial_copy_constructor<T>
1677
#define TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(T) \
1678
  std::has_trivial_copy_assign<T>
1679
1680
// This one will be different for GCC 5.7 if it's ever supported
1681
#define TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(T) \
1682
  std::is_trivially_destructible<T>
1683
1684
// GCC 5 < v < 8 has a bug in is_trivially_copy_constructible which breaks
1685
// std::vector for non-copyable types
1686
#elif (defined(__GNUC__) && __GNUC__ < 8 && !defined(__clang__))
1687
#ifndef TL_GCC_LESS_8_TRIVIALLY_COPY_CONSTRUCTIBLE_MUTEX
1688
#define TL_GCC_LESS_8_TRIVIALLY_COPY_CONSTRUCTIBLE_MUTEX
1689
namespace tl {
1690
namespace detail {
1691
template <class T>
1692
struct is_trivially_copy_constructible
1693
    : std::is_trivially_copy_constructible<T> {};
1694
#ifdef _GLIBCXX_VECTOR
1695
template <class T, class A>
1696
struct is_trivially_copy_constructible<std::vector<T, A>> : std::false_type {};
1697
#endif
1698
}  // namespace detail
1699
}  // namespace tl
1700
#endif
1701
1702
#define TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) \
1703
  tl::detail::is_trivially_copy_constructible<T>
1704
#define TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(T) \
1705
  std::is_trivially_copy_assignable<T>
1706
#define TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(T) \
1707
  std::is_trivially_destructible<T>
1708
#else
1709
#define TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) \
1710
  std::is_trivially_copy_constructible<T>
1711
#define TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(T) \
1712
  std::is_trivially_copy_assignable<T>
1713
#define TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(T) \
1714
  std::is_trivially_destructible<T>
1715
#endif
1716
1717
#if __cplusplus > 201103L
1718
#define TL_EXPECTED_CXX14
1719
#endif
1720
1721
#ifdef TL_EXPECTED_GCC49
1722
#define TL_EXPECTED_GCC49_CONSTEXPR
1723
#else
1724
#define TL_EXPECTED_GCC49_CONSTEXPR constexpr
1725
#endif
1726
1727
#if (__cplusplus == 201103L || defined(TL_EXPECTED_MSVC2015) || \
1728
     defined(TL_EXPECTED_GCC49))
1729
#define TL_EXPECTED_11_CONSTEXPR
1730
#else
1731
#define TL_EXPECTED_11_CONSTEXPR constexpr
1732
#endif
1733
1734
namespace tl {
1735
template <class T, class E>
1736
class expected;
1737
1738
#ifndef TL_MONOSTATE_INPLACE_MUTEX
1739
#define TL_MONOSTATE_INPLACE_MUTEX
1740
class monostate {};
1741
1742
struct in_place_t {
1743
  explicit in_place_t() = default;
1744
};
1745
static constexpr in_place_t in_place{};
1746
#endif
1747
1748
template <class E>
1749
class unexpected {
1750
 public:
1751
  static_assert(!std::is_same<E, void>::value, "E must not be void");
1752
1753
  unexpected() = delete;
1754
0
  constexpr explicit unexpected(const E &e) : m_val(e) {}
1755
1756
33.2k
  constexpr explicit unexpected(E &&e) : m_val(std::move(e)) {}
1757
1758
  template <class... Args, typename std::enable_if<std::is_constructible<
1759
                               E, Args &&...>::value>::type * = nullptr>
1760
  constexpr explicit unexpected(Args &&...args)
1761
394
      : m_val(std::forward<Args>(args)...) {}
1762
  template <
1763
      class U, class... Args,
1764
      typename std::enable_if<std::is_constructible<
1765
          E, std::initializer_list<U> &, Args &&...>::value>::type * = nullptr>
1766
  constexpr explicit unexpected(std::initializer_list<U> l, Args &&...args)
1767
      : m_val(l, std::forward<Args>(args)...) {}
1768
1769
  constexpr const E &value() const & { return m_val; }
1770
17.2k
  TL_EXPECTED_11_CONSTEXPR E &value() & { return m_val; }
1771
  TL_EXPECTED_11_CONSTEXPR E &&value() && { return std::move(m_val); }
1772
  constexpr const E &&value() const && { return std::move(m_val); }
1773
1774
 private:
1775
  E m_val;
1776
};
1777
1778
#ifdef __cpp_deduction_guides
1779
template <class E>
1780
unexpected(E) -> unexpected<E>;
1781
#endif
1782
1783
template <class E>
1784
constexpr bool operator==(const unexpected<E> &lhs, const unexpected<E> &rhs) {
1785
  return lhs.value() == rhs.value();
1786
}
1787
template <class E>
1788
constexpr bool operator!=(const unexpected<E> &lhs, const unexpected<E> &rhs) {
1789
  return lhs.value() != rhs.value();
1790
}
1791
template <class E>
1792
constexpr bool operator<(const unexpected<E> &lhs, const unexpected<E> &rhs) {
1793
  return lhs.value() < rhs.value();
1794
}
1795
template <class E>
1796
constexpr bool operator<=(const unexpected<E> &lhs, const unexpected<E> &rhs) {
1797
  return lhs.value() <= rhs.value();
1798
}
1799
template <class E>
1800
constexpr bool operator>(const unexpected<E> &lhs, const unexpected<E> &rhs) {
1801
  return lhs.value() > rhs.value();
1802
}
1803
template <class E>
1804
constexpr bool operator>=(const unexpected<E> &lhs, const unexpected<E> &rhs) {
1805
  return lhs.value() >= rhs.value();
1806
}
1807
1808
template <class E>
1809
unexpected<typename std::decay<E>::type> make_unexpected(E &&e) {
1810
  return unexpected<typename std::decay<E>::type>(std::forward<E>(e));
1811
}
1812
1813
struct unexpect_t {
1814
  unexpect_t() = default;
1815
};
1816
static constexpr unexpect_t unexpect{};
1817
1818
namespace detail {
1819
template <typename E>
1820
0
[[noreturn]] TL_EXPECTED_11_CONSTEXPR void throw_exception(E &&e) {
1821
0
#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
1822
0
  throw std::forward<E>(e);
1823
#else
1824
  (void)e;
1825
#ifdef _MSC_VER
1826
  __assume(0);
1827
#else
1828
  __builtin_unreachable();
1829
#endif
1830
#endif
1831
0
}
1832
1833
#ifndef TL_TRAITS_MUTEX
1834
#define TL_TRAITS_MUTEX
1835
// C++14-style aliases for brevity
1836
template <class T>
1837
using remove_const_t = typename std::remove_const<T>::type;
1838
template <class T>
1839
using remove_reference_t = typename std::remove_reference<T>::type;
1840
template <class T>
1841
using decay_t = typename std::decay<T>::type;
1842
template <bool E, class T = void>
1843
using enable_if_t = typename std::enable_if<E, T>::type;
1844
template <bool B, class T, class F>
1845
using conditional_t = typename std::conditional<B, T, F>::type;
1846
1847
// std::conjunction from C++17
1848
template <class...>
1849
struct conjunction : std::true_type {};
1850
template <class B>
1851
struct conjunction<B> : B {};
1852
template <class B, class... Bs>
1853
struct conjunction<B, Bs...>
1854
    : std::conditional<bool(B::value), conjunction<Bs...>, B>::type {};
1855
1856
#if defined(_LIBCPP_VERSION) && __cplusplus == 201103L
1857
#define TL_TRAITS_LIBCXX_MEM_FN_WORKAROUND
1858
#endif
1859
1860
// In C++11 mode, there's an issue in libc++'s std::mem_fn
1861
// which results in a hard-error when using it in a noexcept expression
1862
// in some cases. This is a check to workaround the common failing case.
1863
#ifdef TL_TRAITS_LIBCXX_MEM_FN_WORKAROUND
1864
template <class T>
1865
struct is_pointer_to_non_const_member_func : std::false_type {};
1866
template <class T, class Ret, class... Args>
1867
struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...)>
1868
    : std::true_type {};
1869
template <class T, class Ret, class... Args>
1870
struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...) &>
1871
    : std::true_type {};
1872
template <class T, class Ret, class... Args>
1873
struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...) &&>
1874
    : std::true_type {};
1875
template <class T, class Ret, class... Args>
1876
struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...) volatile>
1877
    : std::true_type {};
1878
template <class T, class Ret, class... Args>
1879
struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...) volatile &>
1880
    : std::true_type {};
1881
template <class T, class Ret, class... Args>
1882
struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...) volatile &&>
1883
    : std::true_type {};
1884
1885
template <class T>
1886
struct is_const_or_const_ref : std::false_type {};
1887
template <class T>
1888
struct is_const_or_const_ref<T const &> : std::true_type {};
1889
template <class T>
1890
struct is_const_or_const_ref<T const> : std::true_type {};
1891
#endif
1892
1893
// std::invoke from C++17
1894
// https://stackoverflow.com/questions/38288042/c11-14-invoke-workaround
1895
template <
1896
    typename Fn, typename... Args,
1897
#ifdef TL_TRAITS_LIBCXX_MEM_FN_WORKAROUND
1898
    typename = enable_if_t<!(is_pointer_to_non_const_member_func<Fn>::value &&
1899
                             is_const_or_const_ref<Args...>::value)>,
1900
#endif
1901
    typename = enable_if_t<std::is_member_pointer<decay_t<Fn>>::value>, int = 0>
1902
constexpr auto invoke(Fn &&f, Args &&...args) noexcept(
1903
    noexcept(std::mem_fn(f)(std::forward<Args>(args)...)))
1904
    -> decltype(std::mem_fn(f)(std::forward<Args>(args)...)) {
1905
  return std::mem_fn(f)(std::forward<Args>(args)...);
1906
}
1907
1908
template <typename Fn, typename... Args,
1909
          typename = enable_if_t<!std::is_member_pointer<decay_t<Fn>>::value>>
1910
constexpr auto invoke(Fn &&f, Args &&...args) noexcept(
1911
    noexcept(std::forward<Fn>(f)(std::forward<Args>(args)...)))
1912
    -> decltype(std::forward<Fn>(f)(std::forward<Args>(args)...)) {
1913
  return std::forward<Fn>(f)(std::forward<Args>(args)...);
1914
}
1915
1916
// std::invoke_result from C++17
1917
template <class F, class, class... Us>
1918
struct invoke_result_impl;
1919
1920
template <class F, class... Us>
1921
struct invoke_result_impl<
1922
    F,
1923
    decltype(detail::invoke(std::declval<F>(), std::declval<Us>()...), void()),
1924
    Us...> {
1925
  using type =
1926
      decltype(detail::invoke(std::declval<F>(), std::declval<Us>()...));
1927
};
1928
1929
template <class F, class... Us>
1930
using invoke_result = invoke_result_impl<F, void, Us...>;
1931
1932
template <class F, class... Us>
1933
using invoke_result_t = typename invoke_result<F, Us...>::type;
1934
1935
#if defined(_MSC_VER) && _MSC_VER <= 1900
1936
// TODO make a version which works with MSVC 2015
1937
template <class T, class U = T>
1938
struct is_swappable : std::true_type {};
1939
1940
template <class T, class U = T>
1941
struct is_nothrow_swappable : std::true_type {};
1942
#else
1943
// https://stackoverflow.com/questions/26744589/what-is-a-proper-way-to-implement-is-swappable-to-test-for-the-swappable-concept
1944
namespace swap_adl_tests {
1945
// if swap ADL finds this then it would call std::swap otherwise (same
1946
// signature)
1947
struct tag {};
1948
1949
template <class T>
1950
tag swap(T &, T &);
1951
template <class T, std::size_t N>
1952
tag swap(T (&a)[N], T (&b)[N]);
1953
1954
// helper functions to test if an unqualified swap is possible, and if it
1955
// becomes std::swap
1956
template <class, class>
1957
std::false_type can_swap(...) noexcept(false);
1958
template <class T, class U,
1959
          class = decltype(swap(std::declval<T &>(), std::declval<U &>()))>
1960
std::true_type can_swap(int) noexcept(noexcept(swap(std::declval<T &>(),
1961
                                                    std::declval<U &>())));
1962
1963
template <class, class>
1964
std::false_type uses_std(...);
1965
template <class T, class U>
1966
std::is_same<decltype(swap(std::declval<T &>(), std::declval<U &>())), tag>
1967
uses_std(int);
1968
1969
template <class T>
1970
struct is_std_swap_noexcept
1971
    : std::integral_constant<bool,
1972
                             std::is_nothrow_move_constructible<T>::value &&
1973
                                 std::is_nothrow_move_assignable<T>::value> {};
1974
1975
template <class T, std::size_t N>
1976
struct is_std_swap_noexcept<T[N]> : is_std_swap_noexcept<T> {};
1977
1978
template <class T, class U>
1979
struct is_adl_swap_noexcept
1980
    : std::integral_constant<bool, noexcept(can_swap<T, U>(0))> {};
1981
}  // namespace swap_adl_tests
1982
1983
template <class T, class U = T>
1984
struct is_swappable
1985
    : std::integral_constant<
1986
          bool,
1987
          decltype(detail::swap_adl_tests::can_swap<T, U>(0))::value &&
1988
              (!decltype(detail::swap_adl_tests::uses_std<T, U>(0))::value ||
1989
               (std::is_move_assignable<T>::value &&
1990
                std::is_move_constructible<T>::value))> {};
1991
1992
template <class T, std::size_t N>
1993
struct is_swappable<T[N], T[N]>
1994
    : std::integral_constant<
1995
          bool,
1996
          decltype(detail::swap_adl_tests::can_swap<T[N], T[N]>(0))::value &&
1997
              (!decltype(detail::swap_adl_tests::uses_std<T[N], T[N]>(
1998
                   0))::value ||
1999
               is_swappable<T, T>::value)> {};
2000
2001
template <class T, class U = T>
2002
struct is_nothrow_swappable
2003
    : std::integral_constant<
2004
          bool,
2005
          is_swappable<T, U>::value &&
2006
              ((decltype(detail::swap_adl_tests::uses_std<T, U>(0))::value &&
2007
                detail::swap_adl_tests::is_std_swap_noexcept<T>::value) ||
2008
               (!decltype(detail::swap_adl_tests::uses_std<T, U>(0))::value &&
2009
                detail::swap_adl_tests::is_adl_swap_noexcept<T, U>::value))> {};
2010
#endif
2011
#endif
2012
2013
// Trait for checking if a type is a tl::expected
2014
template <class T>
2015
struct is_expected_impl : std::false_type {};
2016
template <class T, class E>
2017
struct is_expected_impl<expected<T, E>> : std::true_type {};
2018
template <class T>
2019
using is_expected = is_expected_impl<decay_t<T>>;
2020
2021
template <class T, class E, class U>
2022
using expected_enable_forward_value = detail::enable_if_t<
2023
    std::is_constructible<T, U &&>::value &&
2024
    !std::is_same<detail::decay_t<U>, in_place_t>::value &&
2025
    !std::is_same<expected<T, E>, detail::decay_t<U>>::value &&
2026
    !std::is_same<unexpected<E>, detail::decay_t<U>>::value>;
2027
2028
template <class T, class E, class U, class G, class UR, class GR>
2029
using expected_enable_from_other = detail::enable_if_t<
2030
    std::is_constructible<T, UR>::value &&
2031
    std::is_constructible<E, GR>::value &&
2032
    !std::is_constructible<T, expected<U, G> &>::value &&
2033
    !std::is_constructible<T, expected<U, G> &&>::value &&
2034
    !std::is_constructible<T, const expected<U, G> &>::value &&
2035
    !std::is_constructible<T, const expected<U, G> &&>::value &&
2036
    !std::is_convertible<expected<U, G> &, T>::value &&
2037
    !std::is_convertible<expected<U, G> &&, T>::value &&
2038
    !std::is_convertible<const expected<U, G> &, T>::value &&
2039
    !std::is_convertible<const expected<U, G> &&, T>::value>;
2040
2041
template <class T, class U>
2042
using is_void_or = conditional_t<std::is_void<T>::value, std::true_type, U>;
2043
2044
template <class T>
2045
using is_copy_constructible_or_void =
2046
    is_void_or<T, std::is_copy_constructible<T>>;
2047
2048
template <class T>
2049
using is_move_constructible_or_void =
2050
    is_void_or<T, std::is_move_constructible<T>>;
2051
2052
template <class T>
2053
using is_copy_assignable_or_void = is_void_or<T, std::is_copy_assignable<T>>;
2054
2055
template <class T>
2056
using is_move_assignable_or_void = is_void_or<T, std::is_move_assignable<T>>;
2057
2058
}  // namespace detail
2059
2060
namespace detail {
2061
struct no_init_t {};
2062
static constexpr no_init_t no_init{};
2063
2064
// Implements the storage of the values, and ensures that the destructor is
2065
// trivial if it can be.
2066
//
2067
// This specialization is for where neither `T` or `E` is trivially
2068
// destructible, so the destructors must be called on destruction of the
2069
// `expected`
2070
template <class T, class E, bool = std::is_trivially_destructible<T>::value,
2071
          bool = std::is_trivially_destructible<E>::value>
2072
struct expected_storage_base {
2073
  constexpr expected_storage_base() : m_val(T{}), m_has_val(true) {}
2074
  constexpr expected_storage_base(no_init_t) : m_no_init(), m_has_val(false) {}
2075
2076
  template <class... Args,
2077
            detail::enable_if_t<std::is_constructible<T, Args &&...>::value> * =
2078
                nullptr>
2079
  constexpr expected_storage_base(in_place_t, Args &&...args)
2080
      : m_val(std::forward<Args>(args)...), m_has_val(true) {}
2081
2082
  template <class U, class... Args,
2083
            detail::enable_if_t<std::is_constructible<
2084
                T, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
2085
  constexpr expected_storage_base(in_place_t, std::initializer_list<U> il,
2086
                                  Args &&...args)
2087
      : m_val(il, std::forward<Args>(args)...), m_has_val(true) {}
2088
  template <class... Args,
2089
            detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * =
2090
                nullptr>
2091
  constexpr explicit expected_storage_base(unexpect_t, Args &&...args)
2092
      : m_unexpect(std::forward<Args>(args)...), m_has_val(false) {}
2093
2094
  template <class U, class... Args,
2095
            detail::enable_if_t<std::is_constructible<
2096
                E, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
2097
  constexpr explicit expected_storage_base(unexpect_t,
2098
                                           std::initializer_list<U> il,
2099
                                           Args &&...args)
2100
      : m_unexpect(il, std::forward<Args>(args)...), m_has_val(false) {}
2101
2102
  ~expected_storage_base() {
2103
    if (m_has_val) {
2104
      m_val.~T();
2105
    } else {
2106
      m_unexpect.~unexpected<E>();
2107
    }
2108
  }
2109
  union {
2110
    T m_val;
2111
    unexpected<E> m_unexpect;
2112
    char m_no_init;
2113
  };
2114
  bool m_has_val;
2115
};
2116
2117
// This specialization is for when both `T` and `E` are trivially-destructible,
2118
// so the destructor of the `expected` can be trivial.
2119
template <class T, class E>
2120
struct expected_storage_base<T, E, true, true> {
2121
  constexpr expected_storage_base() : m_val(T{}), m_has_val(true) {}
2122
  constexpr expected_storage_base(no_init_t) : m_no_init(), m_has_val(false) {}
2123
2124
  template <class... Args,
2125
            detail::enable_if_t<std::is_constructible<T, Args &&...>::value> * =
2126
                nullptr>
2127
  constexpr expected_storage_base(in_place_t, Args &&...args)
2128
0
      : m_val(std::forward<Args>(args)...), m_has_val(true) {}
Unexecuted instantiation: _ZN2tl6detail21expected_storage_baseIN3ada22url_search_params_iterINSt3__117basic_string_viewIcNS4_11char_traitsIcEEEELNS2_27url_search_params_iter_typeE0EEENS2_6errorsELb1ELb1EEC2IJSA_ETnPNS4_9enable_ifIXsr3std16is_constructibleISA_DpOT_EE5valueEvE4typeELPv0EEENS_10in_place_tESH_
Unexecuted instantiation: _ZN2tl6detail21expected_storage_baseIN3ada22url_search_params_iterINSt3__117basic_string_viewIcNS4_11char_traitsIcEEEELNS2_27url_search_params_iter_typeE1EEENS2_6errorsELb1ELb1EEC2IJSA_ETnPNS4_9enable_ifIXsr3std16is_constructibleISA_DpOT_EE5valueEvE4typeELPv0EEENS_10in_place_tESH_
Unexecuted instantiation: _ZN2tl6detail21expected_storage_baseIN3ada22url_search_params_iterINSt3__14pairINS4_17basic_string_viewIcNS4_11char_traitsIcEEEES9_EELNS2_27url_search_params_iter_typeE2EEENS2_6errorsELb1ELb1EEC2IJSC_ETnPNS4_9enable_ifIXsr3std16is_constructibleISC_DpOT_EE5valueEvE4typeELPv0EEENS_10in_place_tESJ_
2129
2130
  template <class U, class... Args,
2131
            detail::enable_if_t<std::is_constructible<
2132
                T, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
2133
  constexpr expected_storage_base(in_place_t, std::initializer_list<U> il,
2134
                                  Args &&...args)
2135
      : m_val(il, std::forward<Args>(args)...), m_has_val(true) {}
2136
  template <class... Args,
2137
            detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * =
2138
                nullptr>
2139
  constexpr explicit expected_storage_base(unexpect_t, Args &&...args)
2140
      : m_unexpect(std::forward<Args>(args)...), m_has_val(false) {}
2141
2142
  template <class U, class... Args,
2143
            detail::enable_if_t<std::is_constructible<
2144
                E, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
2145
  constexpr explicit expected_storage_base(unexpect_t,
2146
                                           std::initializer_list<U> il,
2147
                                           Args &&...args)
2148
      : m_unexpect(il, std::forward<Args>(args)...), m_has_val(false) {}
2149
2150
  ~expected_storage_base() = default;
2151
  union {
2152
    T m_val;
2153
    unexpected<E> m_unexpect;
2154
    char m_no_init;
2155
  };
2156
  bool m_has_val;
2157
};
2158
2159
// T is trivial, E is not.
2160
template <class T, class E>
2161
struct expected_storage_base<T, E, true, false> {
2162
  constexpr expected_storage_base() : m_val(T{}), m_has_val(true) {}
2163
  TL_EXPECTED_MSVC2015_CONSTEXPR expected_storage_base(no_init_t)
2164
      : m_no_init(), m_has_val(false) {}
2165
2166
  template <class... Args,
2167
            detail::enable_if_t<std::is_constructible<T, Args &&...>::value> * =
2168
                nullptr>
2169
  constexpr expected_storage_base(in_place_t, Args &&...args)
2170
      : m_val(std::forward<Args>(args)...), m_has_val(true) {}
2171
2172
  template <class U, class... Args,
2173
            detail::enable_if_t<std::is_constructible<
2174
                T, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
2175
  constexpr expected_storage_base(in_place_t, std::initializer_list<U> il,
2176
                                  Args &&...args)
2177
      : m_val(il, std::forward<Args>(args)...), m_has_val(true) {}
2178
  template <class... Args,
2179
            detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * =
2180
                nullptr>
2181
  constexpr explicit expected_storage_base(unexpect_t, Args &&...args)
2182
      : m_unexpect(std::forward<Args>(args)...), m_has_val(false) {}
2183
2184
  template <class U, class... Args,
2185
            detail::enable_if_t<std::is_constructible<
2186
                E, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
2187
  constexpr explicit expected_storage_base(unexpect_t,
2188
                                           std::initializer_list<U> il,
2189
                                           Args &&...args)
2190
      : m_unexpect(il, std::forward<Args>(args)...), m_has_val(false) {}
2191
2192
  ~expected_storage_base() {
2193
    if (!m_has_val) {
2194
      m_unexpect.~unexpected<E>();
2195
    }
2196
  }
2197
2198
  union {
2199
    T m_val;
2200
    unexpected<E> m_unexpect;
2201
    char m_no_init;
2202
  };
2203
  bool m_has_val;
2204
};
2205
2206
// E is trivial, T is not.
2207
template <class T, class E>
2208
struct expected_storage_base<T, E, false, true> {
2209
  constexpr expected_storage_base() : m_val(T{}), m_has_val(true) {}
2210
0
  constexpr expected_storage_base(no_init_t) : m_no_init(), m_has_val(false) {}
2211
2212
  template <class... Args,
2213
            detail::enable_if_t<std::is_constructible<T, Args &&...>::value> * =
2214
                nullptr>
2215
  constexpr expected_storage_base(in_place_t, Args &&...args)
2216
75.6k
      : m_val(std::forward<Args>(args)...), m_has_val(true) {}
_ZN2tl6detail21expected_storage_baseIN3ada3urlENS2_6errorsELb0ELb1EEC2IJS3_ETnPNSt3__19enable_ifIXsr3std16is_constructibleIS3_DpOT_EE5valueEvE4typeELPv0EEENS_10in_place_tESB_
Line
Count
Source
2216
15.1k
      : m_val(std::forward<Args>(args)...), m_has_val(true) {}
_ZN2tl6detail21expected_storage_baseIN3ada14url_aggregatorENS2_6errorsELb0ELb1EEC2IJS3_ETnPNSt3__19enable_ifIXsr3std16is_constructibleIS3_DpOT_EE5valueEvE4typeELPv0EEENS_10in_place_tESB_
Line
Count
Source
2216
30.9k
      : m_val(std::forward<Args>(args)...), m_has_val(true) {}
_ZN2tl6detail21expected_storage_baseIN3ada16url_pattern_initENS2_6errorsELb0ELb1EEC2IJS3_ETnPNSt3__19enable_ifIXsr3std16is_constructibleIS3_DpOT_EE5valueEvE4typeELPv0EEENS_10in_place_tESB_
Line
Count
Source
2216
591
      : m_val(std::forward<Args>(args)...), m_has_val(true) {}
_ZN2tl6detail21expected_storage_baseINSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEN3ada6errorsELb0ELb1EEC2IJS8_ETnPNS2_9enable_ifIXsr3std16is_constructibleIS8_DpOT_EE5valueEvE4typeELPv0EEENS_10in_place_tESG_
Line
Count
Source
2216
4.72k
      : m_val(std::forward<Args>(args)...), m_has_val(true) {}
_ZN2tl6detail21expected_storage_baseINSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEN3ada6errorsELb0ELb1EEC2IJRA1_KcETnPNS2_9enable_ifIXsr3std16is_constructibleIS8_DpOT_EE5valueEvE4typeELPv0EEENS_10in_place_tESJ_
Line
Count
Source
2216
5.31k
      : m_val(std::forward<Args>(args)...), m_has_val(true) {}
_ZN2tl6detail21expected_storage_baseINSt3__16vectorIN3ada19url_pattern_helpers5tokenENS2_9allocatorIS6_EEEENS4_6errorsELb0ELb1EEC2IJRS9_ETnPNS2_9enable_ifIXsr3std16is_constructibleIS9_DpOT_EE5valueEvE4typeELPv0EEENS_10in_place_tESH_
Line
Count
Source
2216
6.50k
      : m_val(std::forward<Args>(args)...), m_has_val(true) {}
Unexecuted instantiation: _ZN2tl6detail21expected_storage_baseIN3ada17url_search_paramsENS2_6errorsELb0ELb1EEC2IJS3_ETnPNSt3__19enable_ifIXsr3std16is_constructibleIS3_DpOT_EE5valueEvE4typeELPv0EEENS_10in_place_tESB_
Unexecuted instantiation: _ZN2tl6detail21expected_storage_baseINSt3__16vectorINS2_12basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEENS7_IS9_EEEEN3ada6errorsELb0ELb1EEC2IJSB_ETnPNS2_9enable_ifIXsr3std16is_constructibleISB_DpOT_EE5valueEvE4typeELPv0EEENS_10in_place_tESJ_
_ZN2tl6detail21expected_storage_baseIN3ada16url_pattern_initENS2_6errorsELb0ELb1EEC2IJRS3_ETnPNSt3__19enable_ifIXsr3std16is_constructibleIS3_DpOT_EE5valueEvE4typeELPv0EEENS_10in_place_tESC_
Line
Count
Source
2216
1.18k
      : m_val(std::forward<Args>(args)...), m_has_val(true) {}
_ZN2tl6detail21expected_storage_baseINSt3__16vectorIN3ada16url_pattern_partENS2_9allocatorIS5_EEEENS4_6errorsELb0ELb1EEC2IJRS8_ETnPNS2_9enable_ifIXsr3std16is_constructibleIS8_DpOT_EE5valueEvE4typeELPv0EEENS_10in_place_tESG_
Line
Count
Source
2216
5.31k
      : m_val(std::forward<Args>(args)...), m_has_val(true) {}
_ZN2tl6detail21expected_storage_baseIN3ada21url_pattern_componentINS2_17url_pattern_regex18std_regex_providerEEENS2_6errorsELb0ELb1EEC2IJS6_ETnPNSt3__19enable_ifIXsr3std16is_constructibleIS6_DpOT_EE5valueEvE4typeELPv0EEENS_10in_place_tESE_
Line
Count
Source
2216
5.31k
      : m_val(std::forward<Args>(args)...), m_has_val(true) {}
_ZN2tl6detail21expected_storage_baseIN3ada11url_patternINS2_17url_pattern_regex18std_regex_providerEEENS2_6errorsELb0ELb1EEC2IJS6_ETnPNSt3__19enable_ifIXsr3std16is_constructibleIS6_DpOT_EE5valueEvE4typeELPv0EEENS_10in_place_tESE_
Line
Count
Source
2216
591
      : m_val(std::forward<Args>(args)...), m_has_val(true) {}
2217
2218
  template <class U, class... Args,
2219
            detail::enable_if_t<std::is_constructible<
2220
                T, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
2221
  constexpr expected_storage_base(in_place_t, std::initializer_list<U> il,
2222
                                  Args &&...args)
2223
      : m_val(il, std::forward<Args>(args)...), m_has_val(true) {}
2224
  template <class... Args,
2225
            detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * =
2226
                nullptr>
2227
  constexpr explicit expected_storage_base(unexpect_t, Args &&...args)
2228
16.8k
      : m_unexpect(std::forward<Args>(args)...), m_has_val(false) {}
_ZN2tl6detail21expected_storage_baseIN3ada3urlENS2_6errorsELb0ELb1EEC2IJS4_ETnPNSt3__19enable_ifIXsr3std16is_constructibleIS4_DpOT_EE5valueEvE4typeELPv0EEENS_10unexpect_tESB_
Line
Count
Source
2228
6.10k
      : m_unexpect(std::forward<Args>(args)...), m_has_val(false) {}
_ZN2tl6detail21expected_storage_baseIN3ada14url_aggregatorENS2_6errorsELb0ELb1EEC2IJS4_ETnPNSt3__19enable_ifIXsr3std16is_constructibleIS4_DpOT_EE5valueEvE4typeELPv0EEENS_10unexpect_tESB_
Line
Count
Source
2228
9.33k
      : m_unexpect(std::forward<Args>(args)...), m_has_val(false) {}
_ZN2tl6detail21expected_storage_baseIN3ada16url_pattern_initENS2_6errorsELb0ELb1EEC2IJS4_ETnPNSt3__19enable_ifIXsr3std16is_constructibleIS4_DpOT_EE5valueEvE4typeELPv0EEENS_10unexpect_tESB_
Line
Count
Source
2228
394
      : m_unexpect(std::forward<Args>(args)...), m_has_val(false) {}
Unexecuted instantiation: _ZN2tl6detail21expected_storage_baseINSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEN3ada6errorsELb0ELb1EEC2IJSA_ETnPNS2_9enable_ifIXsr3std16is_constructibleISA_DpOT_EE5valueEvE4typeELPv0EEENS_10unexpect_tESG_
Unexecuted instantiation: _ZN2tl6detail21expected_storage_baseINSt3__16vectorIN3ada19url_pattern_helpers5tokenENS2_9allocatorIS6_EEEENS4_6errorsELb0ELb1EEC2IJSA_ETnPNS2_9enable_ifIXsr3std16is_constructibleISA_DpOT_EE5valueEvE4typeELPv0EEENS_10unexpect_tESG_
_ZN2tl6detail21expected_storage_baseIN3ada11url_patternINS2_17url_pattern_regex18std_regex_providerEEENS2_6errorsELb0ELb1EEC2IJS7_ETnPNSt3__19enable_ifIXsr3std16is_constructibleIS7_DpOT_EE5valueEvE4typeELPv0EEENS_10unexpect_tESE_
Line
Count
Source
2228
985
      : m_unexpect(std::forward<Args>(args)...), m_has_val(false) {}
Unexecuted instantiation: _ZN2tl6detail21expected_storage_baseINSt3__16vectorIN3ada16url_pattern_partENS2_9allocatorIS5_EEEENS4_6errorsELb0ELb1EEC2IJS9_ETnPNS2_9enable_ifIXsr3std16is_constructibleIS9_DpOT_EE5valueEvE4typeELPv0EEENS_10unexpect_tESF_
Unexecuted instantiation: _ZN2tl6detail21expected_storage_baseIN3ada21url_pattern_componentINS2_17url_pattern_regex18std_regex_providerEEENS2_6errorsELb0ELb1EEC2IJS7_ETnPNSt3__19enable_ifIXsr3std16is_constructibleIS7_DpOT_EE5valueEvE4typeELPv0EEENS_10unexpect_tESE_
2229
2230
  template <class U, class... Args,
2231
            detail::enable_if_t<std::is_constructible<
2232
                E, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
2233
  constexpr explicit expected_storage_base(unexpect_t,
2234
                                           std::initializer_list<U> il,
2235
                                           Args &&...args)
2236
      : m_unexpect(il, std::forward<Args>(args)...), m_has_val(false) {}
2237
2238
92.4k
  ~expected_storage_base() {
2239
92.4k
    if (m_has_val) {
2240
75.6k
      m_val.~T();
2241
75.6k
    }
2242
92.4k
  }
tl::detail::expected_storage_base<ada::url, ada::errors, false, true>::~expected_storage_base()
Line
Count
Source
2238
21.2k
  ~expected_storage_base() {
2239
21.2k
    if (m_has_val) {
2240
15.1k
      m_val.~T();
2241
15.1k
    }
2242
21.2k
  }
tl::detail::expected_storage_base<ada::url_aggregator, ada::errors, false, true>::~expected_storage_base()
Line
Count
Source
2238
40.2k
  ~expected_storage_base() {
2239
40.2k
    if (m_has_val) {
2240
30.9k
      m_val.~T();
2241
30.9k
    }
2242
40.2k
  }
tl::detail::expected_storage_base<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, ada::errors, false, true>::~expected_storage_base()
Line
Count
Source
2238
10.0k
  ~expected_storage_base() {
2239
10.0k
    if (m_has_val) {
2240
10.0k
      m_val.~T();
2241
10.0k
    }
2242
10.0k
  }
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()
tl::detail::expected_storage_base<ada::url_pattern<ada::url_pattern_regex::std_regex_provider>, ada::errors, false, true>::~expected_storage_base()
Line
Count
Source
2238
1.57k
  ~expected_storage_base() {
2239
1.57k
    if (m_has_val) {
2240
591
      m_val.~T();
2241
591
    }
2242
1.57k
  }
tl::detail::expected_storage_base<std::__1::vector<ada::url_pattern_helpers::token, std::__1::allocator<ada::url_pattern_helpers::token> >, ada::errors, false, true>::~expected_storage_base()
Line
Count
Source
2238
6.50k
  ~expected_storage_base() {
2239
6.50k
    if (m_has_val) {
2240
6.50k
      m_val.~T();
2241
6.50k
    }
2242
6.50k
  }
tl::detail::expected_storage_base<ada::url_pattern_init, ada::errors, false, true>::~expected_storage_base()
Line
Count
Source
2238
2.16k
  ~expected_storage_base() {
2239
2.16k
    if (m_has_val) {
2240
1.77k
      m_val.~T();
2241
1.77k
    }
2242
2.16k
  }
tl::detail::expected_storage_base<std::__1::vector<ada::url_pattern_part, std::__1::allocator<ada::url_pattern_part> >, ada::errors, false, true>::~expected_storage_base()
Line
Count
Source
2238
5.31k
  ~expected_storage_base() {
2239
5.31k
    if (m_has_val) {
2240
5.31k
      m_val.~T();
2241
5.31k
    }
2242
5.31k
  }
tl::detail::expected_storage_base<ada::url_pattern_component<ada::url_pattern_regex::std_regex_provider>, ada::errors, false, true>::~expected_storage_base()
Line
Count
Source
2238
5.31k
  ~expected_storage_base() {
2239
5.31k
    if (m_has_val) {
2240
5.31k
      m_val.~T();
2241
5.31k
    }
2242
5.31k
  }
2243
  union {
2244
    T m_val;
2245
    unexpected<E> m_unexpect;
2246
    char m_no_init;
2247
  };
2248
  bool m_has_val;
2249
};
2250
2251
// `T` is `void`, `E` is trivially-destructible
2252
template <class E>
2253
struct expected_storage_base<void, E, false, true> {
2254
#if __GNUC__ <= 5
2255
// no constexpr for GCC 4/5 bug
2256
#else
2257
  TL_EXPECTED_MSVC2015_CONSTEXPR
2258
#endif
2259
  expected_storage_base() : m_has_val(true) {}
2260
2261
  constexpr expected_storage_base(no_init_t) : m_val(), m_has_val(false) {}
2262
2263
  constexpr expected_storage_base(in_place_t) : m_has_val(true) {}
2264
2265
  template <class... Args,
2266
            detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * =
2267
                nullptr>
2268
  constexpr explicit expected_storage_base(unexpect_t, Args &&...args)
2269
      : m_unexpect(std::forward<Args>(args)...), m_has_val(false) {}
2270
2271
  template <class U, class... Args,
2272
            detail::enable_if_t<std::is_constructible<
2273
                E, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
2274
  constexpr explicit expected_storage_base(unexpect_t,
2275
                                           std::initializer_list<U> il,
2276
                                           Args &&...args)
2277
      : m_unexpect(il, std::forward<Args>(args)...), m_has_val(false) {}
2278
2279
  ~expected_storage_base() = default;
2280
  struct dummy {};
2281
  union {
2282
    unexpected<E> m_unexpect;
2283
    dummy m_val;
2284
  };
2285
  bool m_has_val;
2286
};
2287
2288
// `T` is `void`, `E` is not trivially-destructible
2289
template <class E>
2290
struct expected_storage_base<void, E, false, false> {
2291
  constexpr expected_storage_base() : m_dummy(), m_has_val(true) {}
2292
  constexpr expected_storage_base(no_init_t) : m_dummy(), m_has_val(false) {}
2293
2294
  constexpr expected_storage_base(in_place_t) : m_dummy(), m_has_val(true) {}
2295
2296
  template <class... Args,
2297
            detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * =
2298
                nullptr>
2299
  constexpr explicit expected_storage_base(unexpect_t, Args &&...args)
2300
      : m_unexpect(std::forward<Args>(args)...), m_has_val(false) {}
2301
2302
  template <class U, class... Args,
2303
            detail::enable_if_t<std::is_constructible<
2304
                E, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
2305
  constexpr explicit expected_storage_base(unexpect_t,
2306
                                           std::initializer_list<U> il,
2307
                                           Args &&...args)
2308
      : m_unexpect(il, std::forward<Args>(args)...), m_has_val(false) {}
2309
2310
  ~expected_storage_base() {
2311
    if (!m_has_val) {
2312
      m_unexpect.~unexpected<E>();
2313
    }
2314
  }
2315
2316
  union {
2317
    unexpected<E> m_unexpect;
2318
    char m_dummy;
2319
  };
2320
  bool m_has_val;
2321
};
2322
2323
// This base class provides some handy member functions which can be used in
2324
// further derived classes
2325
template <class T, class E>
2326
struct expected_operations_base : expected_storage_base<T, E> {
2327
  using expected_storage_base<T, E>::expected_storage_base;
2328
2329
  template <class... Args>
2330
  void construct(Args &&...args) noexcept {
2331
    new (std::addressof(this->m_val)) T(std::forward<Args>(args)...);
2332
    this->m_has_val = true;
2333
  }
2334
2335
  template <class Rhs>
2336
0
  void construct_with(Rhs &&rhs) noexcept {
2337
0
    new (std::addressof(this->m_val)) T(std::forward<Rhs>(rhs).get());
2338
0
    this->m_has_val = true;
2339
0
  }
2340
2341
  template <class... Args>
2342
0
  void construct_error(Args &&...args) noexcept {
2343
0
    new (std::addressof(this->m_unexpect))
2344
0
        unexpected<E>(std::forward<Args>(args)...);
2345
0
    this->m_has_val = false;
2346
0
  }
2347
2348
#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
2349
2350
  // These assign overloads ensure that the most efficient assignment
2351
  // implementation is used while maintaining the strong exception guarantee.
2352
  // The problematic case is where rhs has a value, but *this does not.
2353
  //
2354
  // This overload handles the case where we can just copy-construct `T`
2355
  // directly into place without throwing.
2356
  template <class U = T,
2357
            detail::enable_if_t<std::is_nothrow_copy_constructible<U>::value>
2358
                * = nullptr>
2359
  void assign(const expected_operations_base &rhs) noexcept {
2360
    if (!this->m_has_val && rhs.m_has_val) {
2361
      geterr().~unexpected<E>();
2362
      construct(rhs.get());
2363
    } else {
2364
      assign_common(rhs);
2365
    }
2366
  }
2367
2368
  // This overload handles the case where we can attempt to create a copy of
2369
  // `T`, then no-throw move it into place if the copy was successful.
2370
  template <class U = T,
2371
            detail::enable_if_t<!std::is_nothrow_copy_constructible<U>::value &&
2372
                                std::is_nothrow_move_constructible<U>::value>
2373
                * = nullptr>
2374
  void assign(const expected_operations_base &rhs) noexcept {
2375
    if (!this->m_has_val && rhs.m_has_val) {
2376
      T tmp = rhs.get();
2377
      geterr().~unexpected<E>();
2378
      construct(std::move(tmp));
2379
    } else {
2380
      assign_common(rhs);
2381
    }
2382
  }
2383
2384
  // This overload is the worst-case, where we have to move-construct the
2385
  // unexpected value into temporary storage, then try to copy the T into place.
2386
  // If the construction succeeds, then everything is fine, but if it throws,
2387
  // then we move the old unexpected value back into place before rethrowing the
2388
  // exception.
2389
  template <class U = T,
2390
            detail::enable_if_t<!std::is_nothrow_copy_constructible<U>::value &&
2391
                                !std::is_nothrow_move_constructible<U>::value>
2392
                * = nullptr>
2393
  void assign(const expected_operations_base &rhs) {
2394
    if (!this->m_has_val && rhs.m_has_val) {
2395
      auto tmp = std::move(geterr());
2396
      geterr().~unexpected<E>();
2397
2398
#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
2399
      try {
2400
        construct(rhs.get());
2401
      } catch (...) {
2402
        geterr() = std::move(tmp);
2403
        throw;
2404
      }
2405
#else
2406
      construct(rhs.get());
2407
#endif
2408
    } else {
2409
      assign_common(rhs);
2410
    }
2411
  }
2412
2413
  // These overloads do the same as above, but for rvalues
2414
  template <class U = T,
2415
            detail::enable_if_t<std::is_nothrow_move_constructible<U>::value>
2416
                * = nullptr>
2417
  void assign(expected_operations_base &&rhs) noexcept {
2418
    if (!this->m_has_val && rhs.m_has_val) {
2419
      geterr().~unexpected<E>();
2420
      construct(std::move(rhs).get());
2421
    } else {
2422
      assign_common(std::move(rhs));
2423
    }
2424
  }
2425
2426
  template <class U = T,
2427
            detail::enable_if_t<!std::is_nothrow_move_constructible<U>::value>
2428
                * = nullptr>
2429
  void assign(expected_operations_base &&rhs) {
2430
    if (!this->m_has_val && rhs.m_has_val) {
2431
      auto tmp = std::move(geterr());
2432
      geterr().~unexpected<E>();
2433
#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
2434
      try {
2435
        construct(std::move(rhs).get());
2436
      } catch (...) {
2437
        geterr() = std::move(tmp);
2438
        throw;
2439
      }
2440
#else
2441
      construct(std::move(rhs).get());
2442
#endif
2443
    } else {
2444
      assign_common(std::move(rhs));
2445
    }
2446
  }
2447
2448
#else
2449
2450
  // If exceptions are disabled then we can just copy-construct
2451
  void assign(const expected_operations_base &rhs) noexcept {
2452
    if (!this->m_has_val && rhs.m_has_val) {
2453
      geterr().~unexpected<E>();
2454
      construct(rhs.get());
2455
    } else {
2456
      assign_common(rhs);
2457
    }
2458
  }
2459
2460
  void assign(expected_operations_base &&rhs) noexcept {
2461
    if (!this->m_has_val && rhs.m_has_val) {
2462
      geterr().~unexpected<E>();
2463
      construct(std::move(rhs).get());
2464
    } else {
2465
      assign_common(std::move(rhs));
2466
    }
2467
  }
2468
2469
#endif
2470
2471
  // The common part of move/copy assigning
2472
  template <class Rhs>
2473
  void assign_common(Rhs &&rhs) {
2474
    if (this->m_has_val) {
2475
      if (rhs.m_has_val) {
2476
        get() = std::forward<Rhs>(rhs).get();
2477
      } else {
2478
        destroy_val();
2479
        construct_error(std::forward<Rhs>(rhs).geterr());
2480
      }
2481
    } else {
2482
      if (!rhs.m_has_val) {
2483
        geterr() = std::forward<Rhs>(rhs).geterr();
2484
      }
2485
    }
2486
  }
2487
2488
0
  bool has_value() const { return this->m_has_val; }
2489
2490
  TL_EXPECTED_11_CONSTEXPR T &get() & { return this->m_val; }
2491
0
  constexpr const T &get() const & { return this->m_val; }
2492
  TL_EXPECTED_11_CONSTEXPR T &&get() && { return std::move(this->m_val); }
2493
#ifndef TL_EXPECTED_NO_CONSTRR
2494
  constexpr const T &&get() const && { return std::move(this->m_val); }
2495
#endif
2496
2497
  TL_EXPECTED_11_CONSTEXPR unexpected<E> &geterr() & {
2498
    return this->m_unexpect;
2499
  }
2500
0
  constexpr const unexpected<E> &geterr() const & { return this->m_unexpect; }
2501
  TL_EXPECTED_11_CONSTEXPR unexpected<E> &&geterr() && {
2502
    return std::move(this->m_unexpect);
2503
  }
2504
#ifndef TL_EXPECTED_NO_CONSTRR
2505
  constexpr const unexpected<E> &&geterr() const && {
2506
    return std::move(this->m_unexpect);
2507
  }
2508
#endif
2509
2510
  TL_EXPECTED_11_CONSTEXPR void destroy_val() { get().~T(); }
2511
};
2512
2513
// This base class provides some handy member functions which can be used in
2514
// further derived classes
2515
template <class E>
2516
struct expected_operations_base<void, E> : expected_storage_base<void, E> {
2517
  using expected_storage_base<void, E>::expected_storage_base;
2518
2519
  template <class... Args>
2520
  void construct() noexcept {
2521
    this->m_has_val = true;
2522
  }
2523
2524
  // This function doesn't use its argument, but needs it so that code in
2525
  // levels above this can work independently of whether T is void
2526
  template <class Rhs>
2527
  void construct_with(Rhs &&) noexcept {
2528
    this->m_has_val = true;
2529
  }
2530
2531
  template <class... Args>
2532
  void construct_error(Args &&...args) noexcept {
2533
    new (std::addressof(this->m_unexpect))
2534
        unexpected<E>(std::forward<Args>(args)...);
2535
    this->m_has_val = false;
2536
  }
2537
2538
  template <class Rhs>
2539
  void assign(Rhs &&rhs) noexcept {
2540
    if (!this->m_has_val) {
2541
      if (rhs.m_has_val) {
2542
        geterr().~unexpected<E>();
2543
        construct();
2544
      } else {
2545
        geterr() = std::forward<Rhs>(rhs).geterr();
2546
      }
2547
    } else {
2548
      if (!rhs.m_has_val) {
2549
        construct_error(std::forward<Rhs>(rhs).geterr());
2550
      }
2551
    }
2552
  }
2553
2554
  bool has_value() const { return this->m_has_val; }
2555
2556
  TL_EXPECTED_11_CONSTEXPR unexpected<E> &geterr() & {
2557
    return this->m_unexpect;
2558
  }
2559
  constexpr const unexpected<E> &geterr() const & { return this->m_unexpect; }
2560
  TL_EXPECTED_11_CONSTEXPR unexpected<E> &&geterr() && {
2561
    return std::move(this->m_unexpect);
2562
  }
2563
#ifndef TL_EXPECTED_NO_CONSTRR
2564
  constexpr const unexpected<E> &&geterr() const && {
2565
    return std::move(this->m_unexpect);
2566
  }
2567
#endif
2568
2569
  TL_EXPECTED_11_CONSTEXPR void destroy_val() {
2570
    // no-op
2571
  }
2572
};
2573
2574
// This class manages conditionally having a trivial copy constructor
2575
// This specialization is for when T and E are trivially copy constructible
2576
template <class T, class E,
2577
          bool = is_void_or<T, TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(
2578
                                   T)>::value &&
2579
                 TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(E)::value>
2580
struct expected_copy_base : expected_operations_base<T, E> {
2581
  using expected_operations_base<T, E>::expected_operations_base;
2582
};
2583
2584
// This specialization is for when T or E are not trivially copy constructible
2585
template <class T, class E>
2586
struct expected_copy_base<T, E, false> : expected_operations_base<T, E> {
2587
  using expected_operations_base<T, E>::expected_operations_base;
2588
2589
  expected_copy_base() = default;
2590
  expected_copy_base(const expected_copy_base &rhs)
2591
0
      : expected_operations_base<T, E>(no_init) {
2592
0
    if (rhs.has_value()) {
2593
0
      this->construct_with(rhs);
2594
0
    } else {
2595
0
      this->construct_error(rhs.geterr());
2596
0
    }
2597
0
  }
2598
2599
  expected_copy_base(expected_copy_base &&rhs) = default;
2600
  expected_copy_base &operator=(const expected_copy_base &rhs) = default;
2601
  expected_copy_base &operator=(expected_copy_base &&rhs) = default;
2602
};
2603
2604
// This class manages conditionally having a trivial move constructor
2605
// Unfortunately there's no way to achieve this in GCC < 5 AFAIK, since it
2606
// doesn't implement an analogue to std::is_trivially_move_constructible. We
2607
// have to make do with a non-trivial move constructor even if T is trivially
2608
// move constructible
2609
#ifndef TL_EXPECTED_GCC49
2610
template <class T, class E,
2611
          bool =
2612
              is_void_or<T, std::is_trivially_move_constructible<T>>::value &&
2613
              std::is_trivially_move_constructible<E>::value>
2614
struct expected_move_base : expected_copy_base<T, E> {
2615
  using expected_copy_base<T, E>::expected_copy_base;
2616
};
2617
#else
2618
template <class T, class E, bool = false>
2619
struct expected_move_base;
2620
#endif
2621
template <class T, class E>
2622
struct expected_move_base<T, E, false> : expected_copy_base<T, E> {
2623
  using expected_copy_base<T, E>::expected_copy_base;
2624
2625
  expected_move_base() = default;
2626
0
  expected_move_base(const expected_move_base &rhs) = default;
2627
2628
  expected_move_base(expected_move_base &&rhs) noexcept(
2629
      std::is_nothrow_move_constructible<T>::value)
2630
      : expected_copy_base<T, E>(no_init) {
2631
    if (rhs.has_value()) {
2632
      this->construct_with(std::move(rhs));
2633
    } else {
2634
      this->construct_error(std::move(rhs.geterr()));
2635
    }
2636
  }
2637
  expected_move_base &operator=(const expected_move_base &rhs) = default;
2638
  expected_move_base &operator=(expected_move_base &&rhs) = default;
2639
};
2640
2641
// This class manages conditionally having a trivial copy assignment operator
2642
template <
2643
    class T, class E,
2644
    bool =
2645
        is_void_or<
2646
            T, conjunction<TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(T),
2647
                           TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T),
2648
                           TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(T)>>::value &&
2649
        TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(E)::value &&
2650
        TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(E)::value &&
2651
        TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(E)::value>
2652
struct expected_copy_assign_base : expected_move_base<T, E> {
2653
  using expected_move_base<T, E>::expected_move_base;
2654
};
2655
2656
template <class T, class E>
2657
struct expected_copy_assign_base<T, E, false> : expected_move_base<T, E> {
2658
  using expected_move_base<T, E>::expected_move_base;
2659
2660
  expected_copy_assign_base() = default;
2661
0
  expected_copy_assign_base(const expected_copy_assign_base &rhs) = default;
2662
2663
  expected_copy_assign_base(expected_copy_assign_base &&rhs) = default;
2664
  expected_copy_assign_base &operator=(const expected_copy_assign_base &rhs) {
2665
    this->assign(rhs);
2666
    return *this;
2667
  }
2668
  expected_copy_assign_base &operator=(expected_copy_assign_base &&rhs) =
2669
      default;
2670
};
2671
2672
// This class manages conditionally having a trivial move assignment operator
2673
// Unfortunately there's no way to achieve this in GCC < 5 AFAIK, since it
2674
// doesn't implement an analogue to std::is_trivially_move_assignable. We have
2675
// to make do with a non-trivial move assignment operator even if T is trivially
2676
// move assignable
2677
#ifndef TL_EXPECTED_GCC49
2678
template <
2679
    class T, class E,
2680
    bool = is_void_or<
2681
               T, conjunction<std::is_trivially_destructible<T>,
2682
                              std::is_trivially_move_constructible<T>,
2683
                              std::is_trivially_move_assignable<T>>>::value &&
2684
           std::is_trivially_destructible<E>::value &&
2685
           std::is_trivially_move_constructible<E>::value &&
2686
           std::is_trivially_move_assignable<E>::value>
2687
struct expected_move_assign_base : expected_copy_assign_base<T, E> {
2688
  using expected_copy_assign_base<T, E>::expected_copy_assign_base;
2689
};
2690
#else
2691
template <class T, class E, bool = false>
2692
struct expected_move_assign_base;
2693
#endif
2694
2695
template <class T, class E>
2696
struct expected_move_assign_base<T, E, false>
2697
    : expected_copy_assign_base<T, E> {
2698
  using expected_copy_assign_base<T, E>::expected_copy_assign_base;
2699
2700
  expected_move_assign_base() = default;
2701
0
  expected_move_assign_base(const expected_move_assign_base &rhs) = default;
2702
2703
  expected_move_assign_base(expected_move_assign_base &&rhs) = default;
2704
2705
  expected_move_assign_base &operator=(const expected_move_assign_base &rhs) =
2706
      default;
2707
2708
  expected_move_assign_base &operator=(
2709
      expected_move_assign_base
2710
          &&rhs) noexcept(std::is_nothrow_move_constructible<T>::value &&
2711
                          std::is_nothrow_move_assignable<T>::value) {
2712
    this->assign(std::move(rhs));
2713
    return *this;
2714
  }
2715
};
2716
2717
// expected_delete_ctor_base will conditionally delete copy and move
2718
// constructors depending on whether T is copy/move constructible
2719
template <class T, class E,
2720
          bool EnableCopy = (is_copy_constructible_or_void<T>::value &&
2721
                             std::is_copy_constructible<E>::value),
2722
          bool EnableMove = (is_move_constructible_or_void<T>::value &&
2723
                             std::is_move_constructible<E>::value)>
2724
struct expected_delete_ctor_base {
2725
  expected_delete_ctor_base() = default;
2726
  expected_delete_ctor_base(const expected_delete_ctor_base &) = default;
2727
  expected_delete_ctor_base(expected_delete_ctor_base &&) noexcept = default;
2728
  expected_delete_ctor_base &operator=(const expected_delete_ctor_base &) =
2729
      default;
2730
  expected_delete_ctor_base &operator=(expected_delete_ctor_base &&) noexcept =
2731
      default;
2732
};
2733
2734
template <class T, class E>
2735
struct expected_delete_ctor_base<T, E, true, false> {
2736
  expected_delete_ctor_base() = default;
2737
  expected_delete_ctor_base(const expected_delete_ctor_base &) = default;
2738
  expected_delete_ctor_base(expected_delete_ctor_base &&) noexcept = delete;
2739
  expected_delete_ctor_base &operator=(const expected_delete_ctor_base &) =
2740
      default;
2741
  expected_delete_ctor_base &operator=(expected_delete_ctor_base &&) noexcept =
2742
      default;
2743
};
2744
2745
template <class T, class E>
2746
struct expected_delete_ctor_base<T, E, false, true> {
2747
  expected_delete_ctor_base() = default;
2748
  expected_delete_ctor_base(const expected_delete_ctor_base &) = delete;
2749
  expected_delete_ctor_base(expected_delete_ctor_base &&) noexcept = default;
2750
  expected_delete_ctor_base &operator=(const expected_delete_ctor_base &) =
2751
      default;
2752
  expected_delete_ctor_base &operator=(expected_delete_ctor_base &&) noexcept =
2753
      default;
2754
};
2755
2756
template <class T, class E>
2757
struct expected_delete_ctor_base<T, E, false, false> {
2758
  expected_delete_ctor_base() = default;
2759
  expected_delete_ctor_base(const expected_delete_ctor_base &) = delete;
2760
  expected_delete_ctor_base(expected_delete_ctor_base &&) noexcept = delete;
2761
  expected_delete_ctor_base &operator=(const expected_delete_ctor_base &) =
2762
      default;
2763
  expected_delete_ctor_base &operator=(expected_delete_ctor_base &&) noexcept =
2764
      default;
2765
};
2766
2767
// expected_delete_assign_base will conditionally delete copy and move
2768
// constructors depending on whether T and E are copy/move constructible +
2769
// assignable
2770
template <class T, class E,
2771
          bool EnableCopy = (is_copy_constructible_or_void<T>::value &&
2772
                             std::is_copy_constructible<E>::value &&
2773
                             is_copy_assignable_or_void<T>::value &&
2774
                             std::is_copy_assignable<E>::value),
2775
          bool EnableMove = (is_move_constructible_or_void<T>::value &&
2776
                             std::is_move_constructible<E>::value &&
2777
                             is_move_assignable_or_void<T>::value &&
2778
                             std::is_move_assignable<E>::value)>
2779
struct expected_delete_assign_base {
2780
  expected_delete_assign_base() = default;
2781
  expected_delete_assign_base(const expected_delete_assign_base &) = default;
2782
  expected_delete_assign_base(expected_delete_assign_base &&) noexcept =
2783
      default;
2784
  expected_delete_assign_base &operator=(const expected_delete_assign_base &) =
2785
      default;
2786
  expected_delete_assign_base &operator=(
2787
      expected_delete_assign_base &&) noexcept = default;
2788
};
2789
2790
template <class T, class E>
2791
struct expected_delete_assign_base<T, E, true, false> {
2792
  expected_delete_assign_base() = default;
2793
  expected_delete_assign_base(const expected_delete_assign_base &) = default;
2794
  expected_delete_assign_base(expected_delete_assign_base &&) noexcept =
2795
      default;
2796
  expected_delete_assign_base &operator=(const expected_delete_assign_base &) =
2797
      default;
2798
  expected_delete_assign_base &operator=(
2799
      expected_delete_assign_base &&) noexcept = delete;
2800
};
2801
2802
template <class T, class E>
2803
struct expected_delete_assign_base<T, E, false, true> {
2804
  expected_delete_assign_base() = default;
2805
  expected_delete_assign_base(const expected_delete_assign_base &) = default;
2806
  expected_delete_assign_base(expected_delete_assign_base &&) noexcept =
2807
      default;
2808
  expected_delete_assign_base &operator=(const expected_delete_assign_base &) =
2809
      delete;
2810
  expected_delete_assign_base &operator=(
2811
      expected_delete_assign_base &&) noexcept = default;
2812
};
2813
2814
template <class T, class E>
2815
struct expected_delete_assign_base<T, E, false, false> {
2816
  expected_delete_assign_base() = default;
2817
  expected_delete_assign_base(const expected_delete_assign_base &) = default;
2818
  expected_delete_assign_base(expected_delete_assign_base &&) noexcept =
2819
      default;
2820
  expected_delete_assign_base &operator=(const expected_delete_assign_base &) =
2821
      delete;
2822
  expected_delete_assign_base &operator=(
2823
      expected_delete_assign_base &&) noexcept = delete;
2824
};
2825
2826
// This is needed to be able to construct the expected_default_ctor_base which
2827
// follows, while still conditionally deleting the default constructor.
2828
struct default_constructor_tag {
2829
  explicit constexpr default_constructor_tag() = default;
2830
};
2831
2832
// expected_default_ctor_base will ensure that expected has a deleted default
2833
// consturctor if T is not default constructible.
2834
// This specialization is for when T is default constructible
2835
template <class T, class E,
2836
          bool Enable =
2837
              std::is_default_constructible<T>::value || std::is_void<T>::value>
2838
struct expected_default_ctor_base {
2839
  constexpr expected_default_ctor_base() noexcept = default;
2840
  constexpr expected_default_ctor_base(
2841
      expected_default_ctor_base const &) noexcept = default;
2842
  constexpr expected_default_ctor_base(expected_default_ctor_base &&) noexcept =
2843
      default;
2844
  expected_default_ctor_base &operator=(
2845
      expected_default_ctor_base const &) noexcept = default;
2846
  expected_default_ctor_base &operator=(
2847
      expected_default_ctor_base &&) noexcept = default;
2848
2849
92.4k
  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
2849
21.2k
  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
2849
40.2k
  constexpr explicit expected_default_ctor_base(default_constructor_tag) {}
tl::detail::expected_default_ctor_base<ada::url_pattern_init, ada::errors, true>::expected_default_ctor_base(tl::detail::default_constructor_tag)
Line
Count
Source
2849
2.16k
  constexpr explicit expected_default_ctor_base(default_constructor_tag) {}
tl::detail::expected_default_ctor_base<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)
Line
Count
Source
2849
10.0k
  constexpr explicit expected_default_ctor_base(default_constructor_tag) {}
tl::detail::expected_default_ctor_base<std::__1::vector<ada::url_pattern_helpers::token, std::__1::allocator<ada::url_pattern_helpers::token> >, ada::errors, true>::expected_default_ctor_base(tl::detail::default_constructor_tag)
Line
Count
Source
2849
6.50k
  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)
tl::detail::expected_default_ctor_base<ada::url_pattern<ada::url_pattern_regex::std_regex_provider>, ada::errors, true>::expected_default_ctor_base(tl::detail::default_constructor_tag)
Line
Count
Source
2849
1.57k
  constexpr explicit expected_default_ctor_base(default_constructor_tag) {}
tl::detail::expected_default_ctor_base<std::__1::vector<ada::url_pattern_part, std::__1::allocator<ada::url_pattern_part> >, ada::errors, true>::expected_default_ctor_base(tl::detail::default_constructor_tag)
Line
Count
Source
2849
5.31k
  constexpr explicit expected_default_ctor_base(default_constructor_tag) {}
tl::detail::expected_default_ctor_base<ada::url_pattern_component<ada::url_pattern_regex::std_regex_provider>, ada::errors, true>::expected_default_ctor_base(tl::detail::default_constructor_tag)
Line
Count
Source
2849
5.31k
  constexpr explicit expected_default_ctor_base(default_constructor_tag) {}
2850
};
2851
2852
// This specialization is for when T is not default constructible
2853
template <class T, class E>
2854
struct expected_default_ctor_base<T, E, false> {
2855
  constexpr expected_default_ctor_base() noexcept = delete;
2856
  constexpr expected_default_ctor_base(
2857
      expected_default_ctor_base const &) noexcept = default;
2858
  constexpr expected_default_ctor_base(expected_default_ctor_base &&) noexcept =
2859
      default;
2860
  expected_default_ctor_base &operator=(
2861
      expected_default_ctor_base const &) noexcept = default;
2862
  expected_default_ctor_base &operator=(
2863
      expected_default_ctor_base &&) noexcept = default;
2864
2865
  constexpr explicit expected_default_ctor_base(default_constructor_tag) {}
2866
};
2867
}  // namespace detail
2868
2869
template <class E>
2870
class bad_expected_access : public std::exception {
2871
 public:
2872
0
  explicit bad_expected_access(E e) : m_val(std::move(e)) {}
2873
2874
0
  virtual const char *what() const noexcept override {
2875
0
    return "Bad expected access";
2876
0
  }
2877
2878
  const E &error() const & { return m_val; }
2879
  E &error() & { return m_val; }
2880
  const E &&error() const && { return std::move(m_val); }
2881
  E &&error() && { return std::move(m_val); }
2882
2883
 private:
2884
  E m_val;
2885
};
2886
2887
/// An `expected<T, E>` object is an object that contains the storage for
2888
/// another object and manages the lifetime of this contained object `T`.
2889
/// Alternatively it could contain the storage for another unexpected object
2890
/// `E`. The contained object may not be initialized after the expected object
2891
/// has been initialized, and may not be destroyed before the expected object
2892
/// has been destroyed. The initialization state of the contained object is
2893
/// tracked by the expected object.
2894
template <class T, class E>
2895
class expected : private detail::expected_move_assign_base<T, E>,
2896
                 private detail::expected_delete_ctor_base<T, E>,
2897
                 private detail::expected_delete_assign_base<T, E>,
2898
                 private detail::expected_default_ctor_base<T, E> {
2899
  static_assert(!std::is_reference<T>::value, "T must not be a reference");
2900
  static_assert(!std::is_same<T, std::remove_cv<in_place_t>::type>::value,
2901
                "T must not be in_place_t");
2902
  static_assert(!std::is_same<T, std::remove_cv<unexpect_t>::type>::value,
2903
                "T must not be unexpect_t");
2904
  static_assert(
2905
      !std::is_same<T, typename std::remove_cv<unexpected<E>>::type>::value,
2906
      "T must not be unexpected<E>");
2907
  static_assert(!std::is_reference<E>::value, "E must not be a reference");
2908
2909
688k
  T *valptr() { return std::addressof(this->m_val); }
tl::expected<ada::url, ada::errors>::valptr()
Line
Count
Source
2909
196k
  T *valptr() { return std::addressof(this->m_val); }
tl::expected<ada::url_aggregator, ada::errors>::valptr()
Line
Count
Source
2909
477k
  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()
tl::expected<ada::url_pattern_init, ada::errors>::valptr()
Line
Count
Source
2909
14.1k
  T *valptr() { return std::addressof(this->m_val); }
2910
  const T *valptr() const { return std::addressof(this->m_val); }
2911
  unexpected<E> *errptr() { return std::addressof(this->m_unexpect); }
2912
  const unexpected<E> *errptr() const {
2913
    return std::addressof(this->m_unexpect);
2914
  }
2915
2916
  template <class U = T,
2917
            detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
2918
52.2k
  TL_EXPECTED_11_CONSTEXPR U &val() {
2919
52.2k
    return this->m_val;
2920
52.2k
  }
_ZN2tl8expectedIN3ada3urlENS1_6errorsEE3valIS2_TnPNSt3__19enable_ifIXntsr3std7is_voidIT_EE5valueEvE4typeELPv0EEERS8_v
Line
Count
Source
2918
2.92k
  TL_EXPECTED_11_CONSTEXPR U &val() {
2919
2.92k
    return this->m_val;
2920
2.92k
  }
_ZN2tl8expectedIN3ada14url_aggregatorENS1_6errorsEE3valIS2_TnPNSt3__19enable_ifIXntsr3std7is_voidIT_EE5valueEvE4typeELPv0EEERS8_v
Line
Count
Source
2918
9.73k
  TL_EXPECTED_11_CONSTEXPR U &val() {
2919
9.73k
    return this->m_val;
2920
9.73k
  }
_ZN2tl8expectedINSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEN3ada6errorsEE3valIS7_TnPNS1_9enable_ifIXntsr3std7is_voidIT_EE5valueEvE4typeELPv0EEERSD_v
Line
Count
Source
2918
10.0k
  TL_EXPECTED_11_CONSTEXPR U &val() {
2919
10.0k
    return this->m_val;
2920
10.0k
  }
_ZN2tl8expectedIN3ada11url_patternINS1_17url_pattern_regex18std_regex_providerEEENS1_6errorsEE3valIS5_TnPNSt3__19enable_ifIXntsr3std7is_voidIT_EE5valueEvE4typeELPv0EEERSB_v
Line
Count
Source
2918
591
  TL_EXPECTED_11_CONSTEXPR U &val() {
2919
591
    return this->m_val;
2920
591
  }
_ZN2tl8expectedINSt3__16vectorIN3ada19url_pattern_helpers5tokenENS1_9allocatorIS5_EEEENS3_6errorsEE3valIS8_TnPNS1_9enable_ifIXntsr3std7is_voidIT_EE5valueEvE4typeELPv0EEERSD_v
Line
Count
Source
2918
6.50k
  TL_EXPECTED_11_CONSTEXPR U &val() {
2919
6.50k
    return this->m_val;
2920
6.50k
  }
_ZN2tl8expectedIN3ada16url_pattern_initENS1_6errorsEE3valIS2_TnPNSt3__19enable_ifIXntsr3std7is_voidIT_EE5valueEvE4typeELPv0EEERS8_v
Line
Count
Source
2918
1.18k
  TL_EXPECTED_11_CONSTEXPR U &val() {
2919
1.18k
    return this->m_val;
2920
1.18k
  }
_ZN2tl8expectedINSt3__16vectorIN3ada16url_pattern_partENS1_9allocatorIS4_EEEENS3_6errorsEE3valIS7_TnPNS1_9enable_ifIXntsr3std7is_voidIT_EE5valueEvE4typeELPv0EEERSC_v
Line
Count
Source
2918
15.9k
  TL_EXPECTED_11_CONSTEXPR U &val() {
2919
15.9k
    return this->m_val;
2920
15.9k
  }
_ZN2tl8expectedIN3ada21url_pattern_componentINS1_17url_pattern_regex18std_regex_providerEEENS1_6errorsEE3valIS5_TnPNSt3__19enable_ifIXntsr3std7is_voidIT_EE5valueEvE4typeELPv0EEERSB_v
Line
Count
Source
2918
5.31k
  TL_EXPECTED_11_CONSTEXPR U &val() {
2919
5.31k
    return this->m_val;
2920
5.31k
  }
2921
394
  TL_EXPECTED_11_CONSTEXPR unexpected<E> &err() { return this->m_unexpect; }
Unexecuted instantiation: tl::expected<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, ada::errors>::err()
Unexecuted instantiation: tl::expected<ada::url_aggregator, ada::errors>::err()
Unexecuted instantiation: tl::expected<std::__1::vector<ada::url_pattern_helpers::token, std::__1::allocator<ada::url_pattern_helpers::token> >, ada::errors>::err()
tl::expected<ada::url_pattern_init, ada::errors>::err()
Line
Count
Source
2921
394
  TL_EXPECTED_11_CONSTEXPR unexpected<E> &err() { return this->m_unexpect; }
Unexecuted instantiation: tl::expected<std::__1::vector<ada::url_pattern_part, std::__1::allocator<ada::url_pattern_part> >, ada::errors>::err()
Unexecuted instantiation: tl::expected<ada::url_pattern_component<ada::url_pattern_regex::std_regex_provider>, ada::errors>::err()
2922
2923
  template <class U = T,
2924
            detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
2925
  constexpr const U &val() const {
2926
    return this->m_val;
2927
  }
2928
  constexpr const unexpected<E> &err() const { return this->m_unexpect; }
2929
2930
  using impl_base = detail::expected_move_assign_base<T, E>;
2931
  using ctor_base = detail::expected_default_ctor_base<T, E>;
2932
2933
 public:
2934
  typedef T value_type;
2935
  typedef E error_type;
2936
  typedef unexpected<E> unexpected_type;
2937
2938
#if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \
2939
    !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55)
2940
  template <class F>
2941
  TL_EXPECTED_11_CONSTEXPR auto and_then(F &&f) & {
2942
    return and_then_impl(*this, std::forward<F>(f));
2943
  }
2944
  template <class F>
2945
  TL_EXPECTED_11_CONSTEXPR auto and_then(F &&f) && {
2946
    return and_then_impl(std::move(*this), std::forward<F>(f));
2947
  }
2948
  template <class F>
2949
  constexpr auto and_then(F &&f) const & {
2950
    return and_then_impl(*this, std::forward<F>(f));
2951
  }
2952
2953
#ifndef TL_EXPECTED_NO_CONSTRR
2954
  template <class F>
2955
  constexpr auto and_then(F &&f) const && {
2956
    return and_then_impl(std::move(*this), std::forward<F>(f));
2957
  }
2958
#endif
2959
2960
#else
2961
  template <class F>
2962
  TL_EXPECTED_11_CONSTEXPR auto and_then(F &&f) & -> decltype(and_then_impl(
2963
      std::declval<expected &>(), std::forward<F>(f))) {
2964
    return and_then_impl(*this, std::forward<F>(f));
2965
  }
2966
  template <class F>
2967
  TL_EXPECTED_11_CONSTEXPR auto and_then(F &&f) && -> decltype(and_then_impl(
2968
      std::declval<expected &&>(), std::forward<F>(f))) {
2969
    return and_then_impl(std::move(*this), std::forward<F>(f));
2970
  }
2971
  template <class F>
2972
  constexpr auto and_then(F &&f) const & -> decltype(and_then_impl(
2973
      std::declval<expected const &>(), std::forward<F>(f))) {
2974
    return and_then_impl(*this, std::forward<F>(f));
2975
  }
2976
2977
#ifndef TL_EXPECTED_NO_CONSTRR
2978
  template <class F>
2979
  constexpr auto and_then(F &&f) const && -> decltype(and_then_impl(
2980
      std::declval<expected const &&>(), std::forward<F>(f))) {
2981
    return and_then_impl(std::move(*this), std::forward<F>(f));
2982
  }
2983
#endif
2984
#endif
2985
2986
#if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \
2987
    !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55)
2988
  template <class F>
2989
  TL_EXPECTED_11_CONSTEXPR auto map(F &&f) & {
2990
    return expected_map_impl(*this, std::forward<F>(f));
2991
  }
2992
  template <class F>
2993
  TL_EXPECTED_11_CONSTEXPR auto map(F &&f) && {
2994
    return expected_map_impl(std::move(*this), std::forward<F>(f));
2995
  }
2996
  template <class F>
2997
  constexpr auto map(F &&f) const & {
2998
    return expected_map_impl(*this, std::forward<F>(f));
2999
  }
3000
  template <class F>
3001
  constexpr auto map(F &&f) const && {
3002
    return expected_map_impl(std::move(*this), std::forward<F>(f));
3003
  }
3004
#else
3005
  template <class F>
3006
  TL_EXPECTED_11_CONSTEXPR decltype(expected_map_impl(
3007
      std::declval<expected &>(), std::declval<F &&>()))
3008
  map(F &&f) & {
3009
    return expected_map_impl(*this, std::forward<F>(f));
3010
  }
3011
  template <class F>
3012
  TL_EXPECTED_11_CONSTEXPR decltype(expected_map_impl(std::declval<expected>(),
3013
                                                      std::declval<F &&>()))
3014
  map(F &&f) && {
3015
    return expected_map_impl(std::move(*this), std::forward<F>(f));
3016
  }
3017
  template <class F>
3018
  constexpr decltype(expected_map_impl(std::declval<const expected &>(),
3019
                                       std::declval<F &&>()))
3020
  map(F &&f) const & {
3021
    return expected_map_impl(*this, std::forward<F>(f));
3022
  }
3023
3024
#ifndef TL_EXPECTED_NO_CONSTRR
3025
  template <class F>
3026
  constexpr decltype(expected_map_impl(std::declval<const expected &&>(),
3027
                                       std::declval<F &&>()))
3028
  map(F &&f) const && {
3029
    return expected_map_impl(std::move(*this), std::forward<F>(f));
3030
  }
3031
#endif
3032
#endif
3033
3034
#if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \
3035
    !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55)
3036
  template <class F>
3037
  TL_EXPECTED_11_CONSTEXPR auto transform(F &&f) & {
3038
    return expected_map_impl(*this, std::forward<F>(f));
3039
  }
3040
  template <class F>
3041
  TL_EXPECTED_11_CONSTEXPR auto transform(F &&f) && {
3042
    return expected_map_impl(std::move(*this), std::forward<F>(f));
3043
  }
3044
  template <class F>
3045
  constexpr auto transform(F &&f) const & {
3046
    return expected_map_impl(*this, std::forward<F>(f));
3047
  }
3048
  template <class F>
3049
  constexpr auto transform(F &&f) const && {
3050
    return expected_map_impl(std::move(*this), std::forward<F>(f));
3051
  }
3052
#else
3053
  template <class F>
3054
  TL_EXPECTED_11_CONSTEXPR decltype(expected_map_impl(
3055
      std::declval<expected &>(), std::declval<F &&>()))
3056
  transform(F &&f) & {
3057
    return expected_map_impl(*this, std::forward<F>(f));
3058
  }
3059
  template <class F>
3060
  TL_EXPECTED_11_CONSTEXPR decltype(expected_map_impl(std::declval<expected>(),
3061
                                                      std::declval<F &&>()))
3062
  transform(F &&f) && {
3063
    return expected_map_impl(std::move(*this), std::forward<F>(f));
3064
  }
3065
  template <class F>
3066
  constexpr decltype(expected_map_impl(std::declval<const expected &>(),
3067
                                       std::declval<F &&>()))
3068
  transform(F &&f) const & {
3069
    return expected_map_impl(*this, std::forward<F>(f));
3070
  }
3071
3072
#ifndef TL_EXPECTED_NO_CONSTRR
3073
  template <class F>
3074
  constexpr decltype(expected_map_impl(std::declval<const expected &&>(),
3075
                                       std::declval<F &&>()))
3076
  transform(F &&f) const && {
3077
    return expected_map_impl(std::move(*this), std::forward<F>(f));
3078
  }
3079
#endif
3080
#endif
3081
3082
#if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \
3083
    !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55)
3084
  template <class F>
3085
  TL_EXPECTED_11_CONSTEXPR auto map_error(F &&f) & {
3086
    return map_error_impl(*this, std::forward<F>(f));
3087
  }
3088
  template <class F>
3089
  TL_EXPECTED_11_CONSTEXPR auto map_error(F &&f) && {
3090
    return map_error_impl(std::move(*this), std::forward<F>(f));
3091
  }
3092
  template <class F>
3093
  constexpr auto map_error(F &&f) const & {
3094
    return map_error_impl(*this, std::forward<F>(f));
3095
  }
3096
  template <class F>
3097
  constexpr auto map_error(F &&f) const && {
3098
    return map_error_impl(std::move(*this), std::forward<F>(f));
3099
  }
3100
#else
3101
  template <class F>
3102
  TL_EXPECTED_11_CONSTEXPR decltype(map_error_impl(std::declval<expected &>(),
3103
                                                   std::declval<F &&>()))
3104
  map_error(F &&f) & {
3105
    return map_error_impl(*this, std::forward<F>(f));
3106
  }
3107
  template <class F>
3108
  TL_EXPECTED_11_CONSTEXPR decltype(map_error_impl(std::declval<expected &&>(),
3109
                                                   std::declval<F &&>()))
3110
  map_error(F &&f) && {
3111
    return map_error_impl(std::move(*this), std::forward<F>(f));
3112
  }
3113
  template <class F>
3114
  constexpr decltype(map_error_impl(std::declval<const expected &>(),
3115
                                    std::declval<F &&>()))
3116
  map_error(F &&f) const & {
3117
    return map_error_impl(*this, std::forward<F>(f));
3118
  }
3119
3120
#ifndef TL_EXPECTED_NO_CONSTRR
3121
  template <class F>
3122
  constexpr decltype(map_error_impl(std::declval<const expected &&>(),
3123
                                    std::declval<F &&>()))
3124
  map_error(F &&f) const && {
3125
    return map_error_impl(std::move(*this), std::forward<F>(f));
3126
  }
3127
#endif
3128
#endif
3129
#if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \
3130
    !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55)
3131
  template <class F>
3132
  TL_EXPECTED_11_CONSTEXPR auto transform_error(F &&f) & {
3133
    return map_error_impl(*this, std::forward<F>(f));
3134
  }
3135
  template <class F>
3136
  TL_EXPECTED_11_CONSTEXPR auto transform_error(F &&f) && {
3137
    return map_error_impl(std::move(*this), std::forward<F>(f));
3138
  }
3139
  template <class F>
3140
  constexpr auto transform_error(F &&f) const & {
3141
    return map_error_impl(*this, std::forward<F>(f));
3142
  }
3143
  template <class F>
3144
  constexpr auto transform_error(F &&f) const && {
3145
    return map_error_impl(std::move(*this), std::forward<F>(f));
3146
  }
3147
#else
3148
  template <class F>
3149
  TL_EXPECTED_11_CONSTEXPR decltype(map_error_impl(std::declval<expected &>(),
3150
                                                   std::declval<F &&>()))
3151
  transform_error(F &&f) & {
3152
    return map_error_impl(*this, std::forward<F>(f));
3153
  }
3154
  template <class F>
3155
  TL_EXPECTED_11_CONSTEXPR decltype(map_error_impl(std::declval<expected &&>(),
3156
                                                   std::declval<F &&>()))
3157
  transform_error(F &&f) && {
3158
    return map_error_impl(std::move(*this), std::forward<F>(f));
3159
  }
3160
  template <class F>
3161
  constexpr decltype(map_error_impl(std::declval<const expected &>(),
3162
                                    std::declval<F &&>()))
3163
  transform_error(F &&f) const & {
3164
    return map_error_impl(*this, std::forward<F>(f));
3165
  }
3166
3167
#ifndef TL_EXPECTED_NO_CONSTRR
3168
  template <class F>
3169
  constexpr decltype(map_error_impl(std::declval<const expected &&>(),
3170
                                    std::declval<F &&>()))
3171
  transform_error(F &&f) const && {
3172
    return map_error_impl(std::move(*this), std::forward<F>(f));
3173
  }
3174
#endif
3175
#endif
3176
  template <class F>
3177
  expected TL_EXPECTED_11_CONSTEXPR or_else(F &&f) & {
3178
    return or_else_impl(*this, std::forward<F>(f));
3179
  }
3180
3181
  template <class F>
3182
  expected TL_EXPECTED_11_CONSTEXPR or_else(F &&f) && {
3183
    return or_else_impl(std::move(*this), std::forward<F>(f));
3184
  }
3185
3186
  template <class F>
3187
  expected constexpr or_else(F &&f) const & {
3188
    return or_else_impl(*this, std::forward<F>(f));
3189
  }
3190
3191
#ifndef TL_EXPECTED_NO_CONSTRR
3192
  template <class F>
3193
  expected constexpr or_else(F &&f) const && {
3194
    return or_else_impl(std::move(*this), std::forward<F>(f));
3195
  }
3196
#endif
3197
  constexpr expected() = default;
3198
0
  constexpr expected(const expected &rhs) = default;
3199
  constexpr expected(expected &&rhs) = default;
3200
  expected &operator=(const expected &rhs) = default;
3201
  expected &operator=(expected &&rhs) = default;
3202
3203
  template <class... Args,
3204
            detail::enable_if_t<std::is_constructible<T, Args &&...>::value> * =
3205
                nullptr>
3206
  constexpr expected(in_place_t, Args &&...args)
3207
75.6k
      : impl_base(in_place, std::forward<Args>(args)...),
3208
75.6k
        ctor_base(detail::default_constructor_tag{}) {}
_ZN2tl8expectedIN3ada3urlENS1_6errorsEEC2IJS2_ETnPNSt3__19enable_ifIXsr3std16is_constructibleIS2_DpOT_EE5valueEvE4typeELPv0EEENS_10in_place_tESA_
Line
Count
Source
3207
15.1k
      : impl_base(in_place, std::forward<Args>(args)...),
3208
15.1k
        ctor_base(detail::default_constructor_tag{}) {}
_ZN2tl8expectedIN3ada14url_aggregatorENS1_6errorsEEC2IJS2_ETnPNSt3__19enable_ifIXsr3std16is_constructibleIS2_DpOT_EE5valueEvE4typeELPv0EEENS_10in_place_tESA_
Line
Count
Source
3207
30.9k
      : impl_base(in_place, std::forward<Args>(args)...),
3208
30.9k
        ctor_base(detail::default_constructor_tag{}) {}
_ZN2tl8expectedIN3ada16url_pattern_initENS1_6errorsEEC2IJS2_ETnPNSt3__19enable_ifIXsr3std16is_constructibleIS2_DpOT_EE5valueEvE4typeELPv0EEENS_10in_place_tESA_
Line
Count
Source
3207
591
      : impl_base(in_place, std::forward<Args>(args)...),
3208
591
        ctor_base(detail::default_constructor_tag{}) {}
_ZN2tl8expectedINSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEN3ada6errorsEEC2IJS7_ETnPNS1_9enable_ifIXsr3std16is_constructibleIS7_DpOT_EE5valueEvE4typeELPv0EEENS_10in_place_tESF_
Line
Count
Source
3207
4.72k
      : impl_base(in_place, std::forward<Args>(args)...),
3208
4.72k
        ctor_base(detail::default_constructor_tag{}) {}
_ZN2tl8expectedINSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEN3ada6errorsEEC2IJRA1_KcETnPNS1_9enable_ifIXsr3std16is_constructibleIS7_DpOT_EE5valueEvE4typeELPv0EEENS_10in_place_tESI_
Line
Count
Source
3207
5.31k
      : impl_base(in_place, std::forward<Args>(args)...),
3208
5.31k
        ctor_base(detail::default_constructor_tag{}) {}
_ZN2tl8expectedINSt3__16vectorIN3ada19url_pattern_helpers5tokenENS1_9allocatorIS5_EEEENS3_6errorsEEC2IJRS8_ETnPNS1_9enable_ifIXsr3std16is_constructibleIS8_DpOT_EE5valueEvE4typeELPv0EEENS_10in_place_tESG_
Line
Count
Source
3207
6.50k
      : impl_base(in_place, std::forward<Args>(args)...),
3208
6.50k
        ctor_base(detail::default_constructor_tag{}) {}
Unexecuted instantiation: _ZN2tl8expectedIN3ada17url_search_paramsENS1_6errorsEEC2IJS2_ETnPNSt3__19enable_ifIXsr3std16is_constructibleIS2_DpOT_EE5valueEvE4typeELPv0EEENS_10in_place_tESA_
Unexecuted instantiation: _ZN2tl8expectedINSt3__16vectorINS1_12basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEENS6_IS8_EEEEN3ada6errorsEEC2IJSA_ETnPNS1_9enable_ifIXsr3std16is_constructibleISA_DpOT_EE5valueEvE4typeELPv0EEENS_10in_place_tESI_
Unexecuted instantiation: _ZN2tl8expectedIN3ada22url_search_params_iterINSt3__117basic_string_viewIcNS3_11char_traitsIcEEEELNS1_27url_search_params_iter_typeE0EEENS1_6errorsEEC2IJS9_ETnPNS3_9enable_ifIXsr3std16is_constructibleIS9_DpOT_EE5valueEvE4typeELPv0EEENS_10in_place_tESG_
Unexecuted instantiation: _ZN2tl8expectedIN3ada22url_search_params_iterINSt3__117basic_string_viewIcNS3_11char_traitsIcEEEELNS1_27url_search_params_iter_typeE1EEENS1_6errorsEEC2IJS9_ETnPNS3_9enable_ifIXsr3std16is_constructibleIS9_DpOT_EE5valueEvE4typeELPv0EEENS_10in_place_tESG_
Unexecuted instantiation: _ZN2tl8expectedIN3ada22url_search_params_iterINSt3__14pairINS3_17basic_string_viewIcNS3_11char_traitsIcEEEES8_EELNS1_27url_search_params_iter_typeE2EEENS1_6errorsEEC2IJSB_ETnPNS3_9enable_ifIXsr3std16is_constructibleISB_DpOT_EE5valueEvE4typeELPv0EEENS_10in_place_tESI_
_ZN2tl8expectedIN3ada16url_pattern_initENS1_6errorsEEC2IJRS2_ETnPNSt3__19enable_ifIXsr3std16is_constructibleIS2_DpOT_EE5valueEvE4typeELPv0EEENS_10in_place_tESB_
Line
Count
Source
3207
1.18k
      : impl_base(in_place, std::forward<Args>(args)...),
3208
1.18k
        ctor_base(detail::default_constructor_tag{}) {}
_ZN2tl8expectedINSt3__16vectorIN3ada16url_pattern_partENS1_9allocatorIS4_EEEENS3_6errorsEEC2IJRS7_ETnPNS1_9enable_ifIXsr3std16is_constructibleIS7_DpOT_EE5valueEvE4typeELPv0EEENS_10in_place_tESF_
Line
Count
Source
3207
5.31k
      : impl_base(in_place, std::forward<Args>(args)...),
3208
5.31k
        ctor_base(detail::default_constructor_tag{}) {}
_ZN2tl8expectedIN3ada21url_pattern_componentINS1_17url_pattern_regex18std_regex_providerEEENS1_6errorsEEC2IJS5_ETnPNSt3__19enable_ifIXsr3std16is_constructibleIS5_DpOT_EE5valueEvE4typeELPv0EEENS_10in_place_tESD_
Line
Count
Source
3207
5.31k
      : impl_base(in_place, std::forward<Args>(args)...),
3208
5.31k
        ctor_base(detail::default_constructor_tag{}) {}
_ZN2tl8expectedIN3ada11url_patternINS1_17url_pattern_regex18std_regex_providerEEENS1_6errorsEEC2IJS5_ETnPNSt3__19enable_ifIXsr3std16is_constructibleIS5_DpOT_EE5valueEvE4typeELPv0EEENS_10in_place_tESD_
Line
Count
Source
3207
591
      : impl_base(in_place, std::forward<Args>(args)...),
3208
591
        ctor_base(detail::default_constructor_tag{}) {}
3209
3210
  template <class U, class... Args,
3211
            detail::enable_if_t<std::is_constructible<
3212
                T, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
3213
  constexpr expected(in_place_t, std::initializer_list<U> il, Args &&...args)
3214
      : impl_base(in_place, il, std::forward<Args>(args)...),
3215
        ctor_base(detail::default_constructor_tag{}) {}
3216
3217
  template <class G = E,
3218
            detail::enable_if_t<std::is_constructible<E, const G &>::value> * =
3219
                nullptr,
3220
            detail::enable_if_t<!std::is_convertible<const G &, E>::value> * =
3221
                nullptr>
3222
  explicit constexpr expected(const unexpected<G> &e)
3223
      : impl_base(unexpect, e.value()),
3224
        ctor_base(detail::default_constructor_tag{}) {}
3225
3226
  template <
3227
      class G = E,
3228
      detail::enable_if_t<std::is_constructible<E, const G &>::value> * =
3229
          nullptr,
3230
      detail::enable_if_t<std::is_convertible<const G &, E>::value> * = nullptr>
3231
  constexpr expected(unexpected<G> const &e)
3232
      : impl_base(unexpect, e.value()),
3233
        ctor_base(detail::default_constructor_tag{}) {}
3234
3235
  template <
3236
      class G = E,
3237
      detail::enable_if_t<std::is_constructible<E, G &&>::value> * = nullptr,
3238
      detail::enable_if_t<!std::is_convertible<G &&, E>::value> * = nullptr>
3239
  explicit constexpr expected(unexpected<G> &&e) noexcept(
3240
      std::is_nothrow_constructible<E, G &&>::value)
3241
      : impl_base(unexpect, std::move(e.value())),
3242
        ctor_base(detail::default_constructor_tag{}) {}
3243
3244
  template <
3245
      class G = E,
3246
      detail::enable_if_t<std::is_constructible<E, G &&>::value> * = nullptr,
3247
      detail::enable_if_t<std::is_convertible<G &&, E>::value> * = nullptr>
3248
  constexpr expected(unexpected<G> &&e) noexcept(
3249
      std::is_nothrow_constructible<E, G &&>::value)
3250
16.8k
      : impl_base(unexpect, std::move(e.value())),
3251
16.8k
        ctor_base(detail::default_constructor_tag{}) {}
_ZN2tl8expectedIN3ada3urlENS1_6errorsEEC2IS3_TnPNSt3__19enable_ifIXsr3std16is_constructibleIS3_OT_EE5valueEvE4typeELPv0ETnPNS7_IXsr3std14is_convertibleIS9_S3_EE5valueEvE4typeELSD_0EEEONS_10unexpectedIS8_EE
Line
Count
Source
3250
6.10k
      : impl_base(unexpect, std::move(e.value())),
3251
6.10k
        ctor_base(detail::default_constructor_tag{}) {}
_ZN2tl8expectedIN3ada14url_aggregatorENS1_6errorsEEC2IS3_TnPNSt3__19enable_ifIXsr3std16is_constructibleIS3_OT_EE5valueEvE4typeELPv0ETnPNS7_IXsr3std14is_convertibleIS9_S3_EE5valueEvE4typeELSD_0EEEONS_10unexpectedIS8_EE
Line
Count
Source
3250
9.33k
      : impl_base(unexpect, std::move(e.value())),
3251
9.33k
        ctor_base(detail::default_constructor_tag{}) {}
_ZN2tl8expectedIN3ada16url_pattern_initENS1_6errorsEEC2IS3_TnPNSt3__19enable_ifIXsr3std16is_constructibleIS3_OT_EE5valueEvE4typeELPv0ETnPNS7_IXsr3std14is_convertibleIS9_S3_EE5valueEvE4typeELSD_0EEEONS_10unexpectedIS8_EE
Line
Count
Source
3250
394
      : impl_base(unexpect, std::move(e.value())),
3251
394
        ctor_base(detail::default_constructor_tag{}) {}
Unexecuted instantiation: _ZN2tl8expectedINSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEN3ada6errorsEEC2IS9_TnPNS1_9enable_ifIXsr3std16is_constructibleIS9_OT_EE5valueEvE4typeELPv0ETnPNSC_IXsr3std14is_convertibleISE_S9_EE5valueEvE4typeELSI_0EEEONS_10unexpectedISD_EE
Unexecuted instantiation: _ZN2tl8expectedINSt3__16vectorIN3ada19url_pattern_helpers5tokenENS1_9allocatorIS5_EEEENS3_6errorsEEC2IS9_TnPNS1_9enable_ifIXsr3std16is_constructibleIS9_OT_EE5valueEvE4typeELPv0ETnPNSC_IXsr3std14is_convertibleISE_S9_EE5valueEvE4typeELSI_0EEEONS_10unexpectedISD_EE
_ZN2tl8expectedIN3ada11url_patternINS1_17url_pattern_regex18std_regex_providerEEENS1_6errorsEEC2IS6_TnPNSt3__19enable_ifIXsr3std16is_constructibleIS6_OT_EE5valueEvE4typeELPv0ETnPNSA_IXsr3std14is_convertibleISC_S6_EE5valueEvE4typeELSG_0EEEONS_10unexpectedISB_EE
Line
Count
Source
3250
985
      : impl_base(unexpect, std::move(e.value())),
3251
985
        ctor_base(detail::default_constructor_tag{}) {}
Unexecuted instantiation: _ZN2tl8expectedINSt3__16vectorIN3ada16url_pattern_partENS1_9allocatorIS4_EEEENS3_6errorsEEC2IS8_TnPNS1_9enable_ifIXsr3std16is_constructibleIS8_OT_EE5valueEvE4typeELPv0ETnPNSB_IXsr3std14is_convertibleISD_S8_EE5valueEvE4typeELSH_0EEEONS_10unexpectedISC_EE
Unexecuted instantiation: _ZN2tl8expectedIN3ada21url_pattern_componentINS1_17url_pattern_regex18std_regex_providerEEENS1_6errorsEEC2IS6_TnPNSt3__19enable_ifIXsr3std16is_constructibleIS6_OT_EE5valueEvE4typeELPv0ETnPNSA_IXsr3std14is_convertibleISC_S6_EE5valueEvE4typeELSG_0EEEONS_10unexpectedISB_EE
3252
3253
  template <class... Args,
3254
            detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * =
3255
                nullptr>
3256
  constexpr explicit expected(unexpect_t, Args &&...args)
3257
      : impl_base(unexpect, std::forward<Args>(args)...),
3258
        ctor_base(detail::default_constructor_tag{}) {}
3259
3260
  template <class U, class... Args,
3261
            detail::enable_if_t<std::is_constructible<
3262
                E, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
3263
  constexpr explicit expected(unexpect_t, std::initializer_list<U> il,
3264
                              Args &&...args)
3265
      : impl_base(unexpect, il, std::forward<Args>(args)...),
3266
        ctor_base(detail::default_constructor_tag{}) {}
3267
3268
  template <class U, class G,
3269
            detail::enable_if_t<!(std::is_convertible<U const &, T>::value &&
3270
                                  std::is_convertible<G const &, E>::value)> * =
3271
                nullptr,
3272
            detail::expected_enable_from_other<T, E, U, G, const U &, const G &>
3273
                * = nullptr>
3274
  explicit TL_EXPECTED_11_CONSTEXPR expected(const expected<U, G> &rhs)
3275
      : ctor_base(detail::default_constructor_tag{}) {
3276
    if (rhs.has_value()) {
3277
      this->construct(*rhs);
3278
    } else {
3279
      this->construct_error(rhs.error());
3280
    }
3281
  }
3282
3283
  template <class U, class G,
3284
            detail::enable_if_t<(std::is_convertible<U const &, T>::value &&
3285
                                 std::is_convertible<G const &, E>::value)> * =
3286
                nullptr,
3287
            detail::expected_enable_from_other<T, E, U, G, const U &, const G &>
3288
                * = nullptr>
3289
  TL_EXPECTED_11_CONSTEXPR expected(const expected<U, G> &rhs)
3290
      : ctor_base(detail::default_constructor_tag{}) {
3291
    if (rhs.has_value()) {
3292
      this->construct(*rhs);
3293
    } else {
3294
      this->construct_error(rhs.error());
3295
    }
3296
  }
3297
3298
  template <
3299
      class U, class G,
3300
      detail::enable_if_t<!(std::is_convertible<U &&, T>::value &&
3301
                            std::is_convertible<G &&, E>::value)> * = nullptr,
3302
      detail::expected_enable_from_other<T, E, U, G, U &&, G &&> * = nullptr>
3303
  explicit TL_EXPECTED_11_CONSTEXPR expected(expected<U, G> &&rhs)
3304
      : ctor_base(detail::default_constructor_tag{}) {
3305
    if (rhs.has_value()) {
3306
      this->construct(std::move(*rhs));
3307
    } else {
3308
      this->construct_error(std::move(rhs.error()));
3309
    }
3310
  }
3311
3312
  template <
3313
      class U, class G,
3314
      detail::enable_if_t<(std::is_convertible<U &&, T>::value &&
3315
                           std::is_convertible<G &&, E>::value)> * = nullptr,
3316
      detail::expected_enable_from_other<T, E, U, G, U &&, G &&> * = nullptr>
3317
  TL_EXPECTED_11_CONSTEXPR expected(expected<U, G> &&rhs)
3318
      : ctor_base(detail::default_constructor_tag{}) {
3319
    if (rhs.has_value()) {
3320
      this->construct(std::move(*rhs));
3321
    } else {
3322
      this->construct_error(std::move(rhs.error()));
3323
    }
3324
  }
3325
3326
  template <
3327
      class U = T,
3328
      detail::enable_if_t<!std::is_convertible<U &&, T>::value> * = nullptr,
3329
      detail::expected_enable_forward_value<T, E, U> * = nullptr>
3330
  explicit TL_EXPECTED_MSVC2015_CONSTEXPR expected(U &&v)
3331
      : expected(in_place, std::forward<U>(v)) {}
3332
3333
  template <
3334
      class U = T,
3335
      detail::enable_if_t<std::is_convertible<U &&, T>::value> * = nullptr,
3336
      detail::expected_enable_forward_value<T, E, U> * = nullptr>
3337
  TL_EXPECTED_MSVC2015_CONSTEXPR expected(U &&v)
3338
75.6k
      : expected(in_place, std::forward<U>(v)) {}
_ZN2tl8expectedIN3ada3urlENS1_6errorsEEC2IS2_TnPNSt3__19enable_ifIXsr3std14is_convertibleIOT_S2_EE5valueEvE4typeELPv0ETnPNS7_IXaaaaaasr3std16is_constructibleIS2_S9_EE5valuentsr3std7is_sameINS6_5decayIS8_E4typeENS_10in_place_tEEE5valuentsr3std7is_sameIS4_SG_EE5valuentsr3std7is_sameINS_10unexpectedIS3_EESG_EE5valueEvE4typeELSD_0EEES9_
Line
Count
Source
3338
15.1k
      : expected(in_place, std::forward<U>(v)) {}
_ZN2tl8expectedIN3ada14url_aggregatorENS1_6errorsEEC2IS2_TnPNSt3__19enable_ifIXsr3std14is_convertibleIOT_S2_EE5valueEvE4typeELPv0ETnPNS7_IXaaaaaasr3std16is_constructibleIS2_S9_EE5valuentsr3std7is_sameINS6_5decayIS8_E4typeENS_10in_place_tEEE5valuentsr3std7is_sameIS4_SG_EE5valuentsr3std7is_sameINS_10unexpectedIS3_EESG_EE5valueEvE4typeELSD_0EEES9_
Line
Count
Source
3338
30.9k
      : expected(in_place, std::forward<U>(v)) {}
_ZN2tl8expectedIN3ada16url_pattern_initENS1_6errorsEEC2IS2_TnPNSt3__19enable_ifIXsr3std14is_convertibleIOT_S2_EE5valueEvE4typeELPv0ETnPNS7_IXaaaaaasr3std16is_constructibleIS2_S9_EE5valuentsr3std7is_sameINS6_5decayIS8_E4typeENS_10in_place_tEEE5valuentsr3std7is_sameIS4_SG_EE5valuentsr3std7is_sameINS_10unexpectedIS3_EESG_EE5valueEvE4typeELSD_0EEES9_
Line
Count
Source
3338
591
      : expected(in_place, std::forward<U>(v)) {}
_ZN2tl8expectedINSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEN3ada6errorsEEC2IS7_TnPNS1_9enable_ifIXsr3std14is_convertibleIOT_S7_EE5valueEvE4typeELPv0ETnPNSC_IXaaaaaasr3std16is_constructibleIS7_SE_EE5valuentsr3std7is_sameINS1_5decayISD_E4typeENS_10in_place_tEEE5valuentsr3std7is_sameISA_SL_EE5valuentsr3std7is_sameINS_10unexpectedIS9_EESL_EE5valueEvE4typeELSI_0EEESE_
Line
Count
Source
3338
4.72k
      : expected(in_place, std::forward<U>(v)) {}
_ZN2tl8expectedINSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEN3ada6errorsEEC2IRA1_KcTnPNS1_9enable_ifIXsr3std14is_convertibleIOT_S7_EE5valueEvE4typeELPv0ETnPNSF_IXaaaaaasr3std16is_constructibleIS7_SH_EE5valuentsr3std7is_sameINS1_5decayISG_E4typeENS_10in_place_tEEE5valuentsr3std7is_sameISA_SO_EE5valuentsr3std7is_sameINS_10unexpectedIS9_EESO_EE5valueEvE4typeELSL_0EEESH_
Line
Count
Source
3338
5.31k
      : expected(in_place, std::forward<U>(v)) {}
_ZN2tl8expectedINSt3__16vectorIN3ada19url_pattern_helpers5tokenENS1_9allocatorIS5_EEEENS3_6errorsEEC2IRS8_TnPNS1_9enable_ifIXsr3std14is_convertibleIOT_S8_EE5valueEvE4typeELPv0ETnPNSD_IXaaaaaasr3std16is_constructibleIS8_SF_EE5valuentsr3std7is_sameINS1_5decayISE_E4typeENS_10in_place_tEEE5valuentsr3std7is_sameISA_SM_EE5valuentsr3std7is_sameINS_10unexpectedIS9_EESM_EE5valueEvE4typeELSJ_0EEESF_
Line
Count
Source
3338
6.50k
      : expected(in_place, std::forward<U>(v)) {}
Unexecuted instantiation: _ZN2tl8expectedIN3ada17url_search_paramsENS1_6errorsEEC2IS2_TnPNSt3__19enable_ifIXsr3std14is_convertibleIOT_S2_EE5valueEvE4typeELPv0ETnPNS7_IXaaaaaasr3std16is_constructibleIS2_S9_EE5valuentsr3std7is_sameINS6_5decayIS8_E4typeENS_10in_place_tEEE5valuentsr3std7is_sameIS4_SG_EE5valuentsr3std7is_sameINS_10unexpectedIS3_EESG_EE5valueEvE4typeELSD_0EEES9_
Unexecuted instantiation: _ZN2tl8expectedINSt3__16vectorINS1_12basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEENS6_IS8_EEEEN3ada6errorsEEC2ISA_TnPNS1_9enable_ifIXsr3std14is_convertibleIOT_SA_EE5valueEvE4typeELPv0ETnPNSF_IXaaaaaasr3std16is_constructibleISA_SH_EE5valuentsr3std7is_sameINS1_5decayISG_E4typeENS_10in_place_tEEE5valuentsr3std7is_sameISD_SO_EE5valuentsr3std7is_sameINS_10unexpectedISC_EESO_EE5valueEvE4typeELSL_0EEESH_
Unexecuted instantiation: _ZN2tl8expectedIN3ada22url_search_params_iterINSt3__117basic_string_viewIcNS3_11char_traitsIcEEEELNS1_27url_search_params_iter_typeE0EEENS1_6errorsEEC2IS9_TnPNS3_9enable_ifIXsr3std14is_convertibleIOT_S9_EE5valueEvE4typeELPv0ETnPNSD_IXaaaaaasr3std16is_constructibleIS9_SF_EE5valuentsr3std7is_sameINS3_5decayISE_E4typeENS_10in_place_tEEE5valuentsr3std7is_sameISB_SM_EE5valuentsr3std7is_sameINS_10unexpectedISA_EESM_EE5valueEvE4typeELSJ_0EEESF_
Unexecuted instantiation: _ZN2tl8expectedIN3ada22url_search_params_iterINSt3__117basic_string_viewIcNS3_11char_traitsIcEEEELNS1_27url_search_params_iter_typeE1EEENS1_6errorsEEC2IS9_TnPNS3_9enable_ifIXsr3std14is_convertibleIOT_S9_EE5valueEvE4typeELPv0ETnPNSD_IXaaaaaasr3std16is_constructibleIS9_SF_EE5valuentsr3std7is_sameINS3_5decayISE_E4typeENS_10in_place_tEEE5valuentsr3std7is_sameISB_SM_EE5valuentsr3std7is_sameINS_10unexpectedISA_EESM_EE5valueEvE4typeELSJ_0EEESF_
Unexecuted instantiation: _ZN2tl8expectedIN3ada22url_search_params_iterINSt3__14pairINS3_17basic_string_viewIcNS3_11char_traitsIcEEEES8_EELNS1_27url_search_params_iter_typeE2EEENS1_6errorsEEC2ISB_TnPNS3_9enable_ifIXsr3std14is_convertibleIOT_SB_EE5valueEvE4typeELPv0ETnPNSF_IXaaaaaasr3std16is_constructibleISB_SH_EE5valuentsr3std7is_sameINS3_5decayISG_E4typeENS_10in_place_tEEE5valuentsr3std7is_sameISD_SO_EE5valuentsr3std7is_sameINS_10unexpectedISC_EESO_EE5valueEvE4typeELSL_0EEESH_
_ZN2tl8expectedIN3ada16url_pattern_initENS1_6errorsEEC2IRS2_TnPNSt3__19enable_ifIXsr3std14is_convertibleIOT_S2_EE5valueEvE4typeELPv0ETnPNS8_IXaaaaaasr3std16is_constructibleIS2_SA_EE5valuentsr3std7is_sameINS7_5decayIS9_E4typeENS_10in_place_tEEE5valuentsr3std7is_sameIS4_SH_EE5valuentsr3std7is_sameINS_10unexpectedIS3_EESH_EE5valueEvE4typeELSE_0EEESA_
Line
Count
Source
3338
1.18k
      : expected(in_place, std::forward<U>(v)) {}
_ZN2tl8expectedINSt3__16vectorIN3ada16url_pattern_partENS1_9allocatorIS4_EEEENS3_6errorsEEC2IRS7_TnPNS1_9enable_ifIXsr3std14is_convertibleIOT_S7_EE5valueEvE4typeELPv0ETnPNSC_IXaaaaaasr3std16is_constructibleIS7_SE_EE5valuentsr3std7is_sameINS1_5decayISD_E4typeENS_10in_place_tEEE5valuentsr3std7is_sameIS9_SL_EE5valuentsr3std7is_sameINS_10unexpectedIS8_EESL_EE5valueEvE4typeELSI_0EEESE_
Line
Count
Source
3338
5.31k
      : expected(in_place, std::forward<U>(v)) {}
_ZN2tl8expectedIN3ada21url_pattern_componentINS1_17url_pattern_regex18std_regex_providerEEENS1_6errorsEEC2IS5_TnPNSt3__19enable_ifIXsr3std14is_convertibleIOT_S5_EE5valueEvE4typeELPv0ETnPNSA_IXaaaaaasr3std16is_constructibleIS5_SC_EE5valuentsr3std7is_sameINS9_5decayISB_E4typeENS_10in_place_tEEE5valuentsr3std7is_sameIS7_SJ_EE5valuentsr3std7is_sameINS_10unexpectedIS6_EESJ_EE5valueEvE4typeELSG_0EEESC_
Line
Count
Source
3338
5.31k
      : expected(in_place, std::forward<U>(v)) {}
_ZN2tl8expectedIN3ada11url_patternINS1_17url_pattern_regex18std_regex_providerEEENS1_6errorsEEC2IS5_TnPNSt3__19enable_ifIXsr3std14is_convertibleIOT_S5_EE5valueEvE4typeELPv0ETnPNSA_IXaaaaaasr3std16is_constructibleIS5_SC_EE5valuentsr3std7is_sameINS9_5decayISB_E4typeENS_10in_place_tEEE5valuentsr3std7is_sameIS7_SJ_EE5valuentsr3std7is_sameINS_10unexpectedIS6_EESJ_EE5valueEvE4typeELSG_0EEESC_
Line
Count
Source
3338
591
      : expected(in_place, std::forward<U>(v)) {}
3339
3340
  template <
3341
      class U = T, class G = T,
3342
      detail::enable_if_t<std::is_nothrow_constructible<T, U &&>::value> * =
3343
          nullptr,
3344
      detail::enable_if_t<!std::is_void<G>::value> * = nullptr,
3345
      detail::enable_if_t<
3346
          (!std::is_same<expected<T, E>, detail::decay_t<U>>::value &&
3347
           !detail::conjunction<std::is_scalar<T>,
3348
                                std::is_same<T, detail::decay_t<U>>>::value &&
3349
           std::is_constructible<T, U>::value &&
3350
           std::is_assignable<G &, U>::value &&
3351
           std::is_nothrow_move_constructible<E>::value)> * = nullptr>
3352
  expected &operator=(U &&v) {
3353
    if (has_value()) {
3354
      val() = std::forward<U>(v);
3355
    } else {
3356
      err().~unexpected<E>();
3357
      ::new (valptr()) T(std::forward<U>(v));
3358
      this->m_has_val = true;
3359
    }
3360
3361
    return *this;
3362
  }
3363
3364
  template <
3365
      class U = T, class G = T,
3366
      detail::enable_if_t<!std::is_nothrow_constructible<T, U &&>::value> * =
3367
          nullptr,
3368
      detail::enable_if_t<!std::is_void<U>::value> * = nullptr,
3369
      detail::enable_if_t<
3370
          (!std::is_same<expected<T, E>, detail::decay_t<U>>::value &&
3371
           !detail::conjunction<std::is_scalar<T>,
3372
                                std::is_same<T, detail::decay_t<U>>>::value &&
3373
           std::is_constructible<T, U>::value &&
3374
           std::is_assignable<G &, U>::value &&
3375
           std::is_nothrow_move_constructible<E>::value)> * = nullptr>
3376
  expected &operator=(U &&v) {
3377
    if (has_value()) {
3378
      val() = std::forward<U>(v);
3379
    } else {
3380
      auto tmp = std::move(err());
3381
      err().~unexpected<E>();
3382
3383
#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
3384
      try {
3385
        ::new (valptr()) T(std::forward<U>(v));
3386
        this->m_has_val = true;
3387
      } catch (...) {
3388
        err() = std::move(tmp);
3389
        throw;
3390
      }
3391
#else
3392
      ::new (valptr()) T(std::forward<U>(v));
3393
      this->m_has_val = true;
3394
#endif
3395
    }
3396
3397
    return *this;
3398
  }
3399
3400
  template <class G = E,
3401
            detail::enable_if_t<std::is_nothrow_copy_constructible<G>::value &&
3402
                                std::is_assignable<G &, G>::value> * = nullptr>
3403
  expected &operator=(const unexpected<G> &rhs) {
3404
    if (!has_value()) {
3405
      err() = rhs;
3406
    } else {
3407
      this->destroy_val();
3408
      ::new (errptr()) unexpected<E>(rhs);
3409
      this->m_has_val = false;
3410
    }
3411
3412
    return *this;
3413
  }
3414
3415
  template <class G = E,
3416
            detail::enable_if_t<std::is_nothrow_move_constructible<G>::value &&
3417
                                std::is_move_assignable<G>::value> * = nullptr>
3418
  expected &operator=(unexpected<G> &&rhs) noexcept {
3419
    if (!has_value()) {
3420
      err() = std::move(rhs);
3421
    } else {
3422
      this->destroy_val();
3423
      ::new (errptr()) unexpected<E>(std::move(rhs));
3424
      this->m_has_val = false;
3425
    }
3426
3427
    return *this;
3428
  }
3429
3430
  template <class... Args, detail::enable_if_t<std::is_nothrow_constructible<
3431
                               T, Args &&...>::value> * = nullptr>
3432
  void emplace(Args &&...args) {
3433
    if (has_value()) {
3434
      val().~T();
3435
    } else {
3436
      err().~unexpected<E>();
3437
      this->m_has_val = true;
3438
    }
3439
    ::new (valptr()) T(std::forward<Args>(args)...);
3440
  }
3441
3442
  template <class... Args, detail::enable_if_t<!std::is_nothrow_constructible<
3443
                               T, Args &&...>::value> * = nullptr>
3444
  void emplace(Args &&...args) {
3445
    if (has_value()) {
3446
      val().~T();
3447
      ::new (valptr()) T(std::forward<Args>(args)...);
3448
    } else {
3449
      auto tmp = std::move(err());
3450
      err().~unexpected<E>();
3451
3452
#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
3453
      try {
3454
        ::new (valptr()) T(std::forward<Args>(args)...);
3455
        this->m_has_val = true;
3456
      } catch (...) {
3457
        err() = std::move(tmp);
3458
        throw;
3459
      }
3460
#else
3461
      ::new (valptr()) T(std::forward<Args>(args)...);
3462
      this->m_has_val = true;
3463
#endif
3464
    }
3465
  }
3466
3467
  template <class U, class... Args,
3468
            detail::enable_if_t<std::is_nothrow_constructible<
3469
                T, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
3470
  void emplace(std::initializer_list<U> il, Args &&...args) {
3471
    if (has_value()) {
3472
      T t(il, std::forward<Args>(args)...);
3473
      val() = std::move(t);
3474
    } else {
3475
      err().~unexpected<E>();
3476
      ::new (valptr()) T(il, std::forward<Args>(args)...);
3477
      this->m_has_val = true;
3478
    }
3479
  }
3480
3481
  template <class U, class... Args,
3482
            detail::enable_if_t<!std::is_nothrow_constructible<
3483
                T, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
3484
  void emplace(std::initializer_list<U> il, Args &&...args) {
3485
    if (has_value()) {
3486
      T t(il, std::forward<Args>(args)...);
3487
      val() = std::move(t);
3488
    } else {
3489
      auto tmp = std::move(err());
3490
      err().~unexpected<E>();
3491
3492
#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
3493
      try {
3494
        ::new (valptr()) T(il, std::forward<Args>(args)...);
3495
        this->m_has_val = true;
3496
      } catch (...) {
3497
        err() = std::move(tmp);
3498
        throw;
3499
      }
3500
#else
3501
      ::new (valptr()) T(il, std::forward<Args>(args)...);
3502
      this->m_has_val = true;
3503
#endif
3504
    }
3505
  }
3506
3507
 private:
3508
  using t_is_void = std::true_type;
3509
  using t_is_not_void = std::false_type;
3510
  using t_is_nothrow_move_constructible = std::true_type;
3511
  using move_constructing_t_can_throw = std::false_type;
3512
  using e_is_nothrow_move_constructible = std::true_type;
3513
  using move_constructing_e_can_throw = std::false_type;
3514
3515
  void swap_where_both_have_value(expected & /*rhs*/, t_is_void) noexcept {
3516
    // swapping void is a no-op
3517
  }
3518
3519
  void swap_where_both_have_value(expected &rhs, t_is_not_void) {
3520
    using std::swap;
3521
    swap(val(), rhs.val());
3522
  }
3523
3524
  void swap_where_only_one_has_value(expected &rhs, t_is_void) noexcept(
3525
      std::is_nothrow_move_constructible<E>::value) {
3526
    ::new (errptr()) unexpected_type(std::move(rhs.err()));
3527
    rhs.err().~unexpected_type();
3528
    std::swap(this->m_has_val, rhs.m_has_val);
3529
  }
3530
3531
  void swap_where_only_one_has_value(expected &rhs, t_is_not_void) {
3532
    swap_where_only_one_has_value_and_t_is_not_void(
3533
        rhs, typename std::is_nothrow_move_constructible<T>::type{},
3534
        typename std::is_nothrow_move_constructible<E>::type{});
3535
  }
3536
3537
  void swap_where_only_one_has_value_and_t_is_not_void(
3538
      expected &rhs, t_is_nothrow_move_constructible,
3539
      e_is_nothrow_move_constructible) noexcept {
3540
    auto temp = std::move(val());
3541
    val().~T();
3542
    ::new (errptr()) unexpected_type(std::move(rhs.err()));
3543
    rhs.err().~unexpected_type();
3544
    ::new (rhs.valptr()) T(std::move(temp));
3545
    std::swap(this->m_has_val, rhs.m_has_val);
3546
  }
3547
3548
  void swap_where_only_one_has_value_and_t_is_not_void(
3549
      expected &rhs, t_is_nothrow_move_constructible,
3550
      move_constructing_e_can_throw) {
3551
    auto temp = std::move(val());
3552
    val().~T();
3553
#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
3554
    try {
3555
      ::new (errptr()) unexpected_type(std::move(rhs.err()));
3556
      rhs.err().~unexpected_type();
3557
      ::new (rhs.valptr()) T(std::move(temp));
3558
      std::swap(this->m_has_val, rhs.m_has_val);
3559
    } catch (...) {
3560
      val() = std::move(temp);
3561
      throw;
3562
    }
3563
#else
3564
    ::new (errptr()) unexpected_type(std::move(rhs.err()));
3565
    rhs.err().~unexpected_type();
3566
    ::new (rhs.valptr()) T(std::move(temp));
3567
    std::swap(this->m_has_val, rhs.m_has_val);
3568
#endif
3569
  }
3570
3571
  void swap_where_only_one_has_value_and_t_is_not_void(
3572
      expected &rhs, move_constructing_t_can_throw,
3573
      e_is_nothrow_move_constructible) {
3574
    auto temp = std::move(rhs.err());
3575
    rhs.err().~unexpected_type();
3576
#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
3577
    try {
3578
      ::new (rhs.valptr()) T(std::move(val()));
3579
      val().~T();
3580
      ::new (errptr()) unexpected_type(std::move(temp));
3581
      std::swap(this->m_has_val, rhs.m_has_val);
3582
    } catch (...) {
3583
      rhs.err() = std::move(temp);
3584
      throw;
3585
    }
3586
#else
3587
    ::new (rhs.valptr()) T(std::move(val()));
3588
    val().~T();
3589
    ::new (errptr()) unexpected_type(std::move(temp));
3590
    std::swap(this->m_has_val, rhs.m_has_val);
3591
#endif
3592
  }
3593
3594
 public:
3595
  template <class OT = T, class OE = E>
3596
  detail::enable_if_t<detail::is_swappable<OT>::value &&
3597
                      detail::is_swappable<OE>::value &&
3598
                      (std::is_nothrow_move_constructible<OT>::value ||
3599
                       std::is_nothrow_move_constructible<OE>::value)>
3600
  swap(expected &rhs) noexcept(std::is_nothrow_move_constructible<T>::value &&
3601
                               detail::is_nothrow_swappable<T>::value &&
3602
                               std::is_nothrow_move_constructible<E>::value &&
3603
                               detail::is_nothrow_swappable<E>::value) {
3604
    if (has_value() && rhs.has_value()) {
3605
      swap_where_both_have_value(rhs, typename std::is_void<T>::type{});
3606
    } else if (!has_value() && rhs.has_value()) {
3607
      rhs.swap(*this);
3608
    } else if (has_value()) {
3609
      swap_where_only_one_has_value(rhs, typename std::is_void<T>::type{});
3610
    } else {
3611
      using std::swap;
3612
      swap(err(), rhs.err());
3613
    }
3614
  }
3615
3616
  constexpr const T *operator->() const {
3617
    TL_ASSERT(has_value());
3618
    return valptr();
3619
  }
3620
688k
  TL_EXPECTED_11_CONSTEXPR T *operator->() {
3621
688k
    TL_ASSERT(has_value());
3622
688k
    return valptr();
3623
688k
  }
tl::expected<ada::url, ada::errors>::operator->()
Line
Count
Source
3620
196k
  TL_EXPECTED_11_CONSTEXPR T *operator->() {
3621
196k
    TL_ASSERT(has_value());
3622
196k
    return valptr();
3623
196k
  }
tl::expected<ada::url_aggregator, ada::errors>::operator->()
Line
Count
Source
3620
477k
  TL_EXPECTED_11_CONSTEXPR T *operator->() {
3621
477k
    TL_ASSERT(has_value());
3622
477k
    return valptr();
3623
477k
  }
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->()
tl::expected<ada::url_pattern_init, ada::errors>::operator->()
Line
Count
Source
3620
14.1k
  TL_EXPECTED_11_CONSTEXPR T *operator->() {
3621
14.1k
    TL_ASSERT(has_value());
3622
14.1k
    return valptr();
3623
14.1k
  }
3624
3625
  template <class U = T,
3626
            detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
3627
  constexpr const U &operator*() const & {
3628
    TL_ASSERT(has_value());
3629
    return val();
3630
  }
3631
  template <class U = T,
3632
            detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
3633
52.2k
  TL_EXPECTED_11_CONSTEXPR U &operator*() & {
3634
52.2k
    TL_ASSERT(has_value());
3635
52.2k
    return val();
3636
52.2k
  }
_ZNR2tl8expectedIN3ada3urlENS1_6errorsEEdeIS2_TnPNSt3__19enable_ifIXntsr3std7is_voidIT_EE5valueEvE4typeELPv0EEERS8_v
Line
Count
Source
3633
2.92k
  TL_EXPECTED_11_CONSTEXPR U &operator*() & {
3634
2.92k
    TL_ASSERT(has_value());
3635
2.92k
    return val();
3636
2.92k
  }
_ZNR2tl8expectedIN3ada14url_aggregatorENS1_6errorsEEdeIS2_TnPNSt3__19enable_ifIXntsr3std7is_voidIT_EE5valueEvE4typeELPv0EEERS8_v
Line
Count
Source
3633
9.73k
  TL_EXPECTED_11_CONSTEXPR U &operator*() & {
3634
9.73k
    TL_ASSERT(has_value());
3635
9.73k
    return val();
3636
9.73k
  }
_ZNR2tl8expectedINSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEN3ada6errorsEEdeIS7_TnPNS1_9enable_ifIXntsr3std7is_voidIT_EE5valueEvE4typeELPv0EEERSD_v
Line
Count
Source
3633
10.0k
  TL_EXPECTED_11_CONSTEXPR U &operator*() & {
3634
10.0k
    TL_ASSERT(has_value());
3635
10.0k
    return val();
3636
10.0k
  }
_ZNR2tl8expectedIN3ada11url_patternINS1_17url_pattern_regex18std_regex_providerEEENS1_6errorsEEdeIS5_TnPNSt3__19enable_ifIXntsr3std7is_voidIT_EE5valueEvE4typeELPv0EEERSB_v
Line
Count
Source
3633
591
  TL_EXPECTED_11_CONSTEXPR U &operator*() & {
3634
591
    TL_ASSERT(has_value());
3635
591
    return val();
3636
591
  }
_ZNR2tl8expectedINSt3__16vectorIN3ada19url_pattern_helpers5tokenENS1_9allocatorIS5_EEEENS3_6errorsEEdeIS8_TnPNS1_9enable_ifIXntsr3std7is_voidIT_EE5valueEvE4typeELPv0EEERSD_v
Line
Count
Source
3633
6.50k
  TL_EXPECTED_11_CONSTEXPR U &operator*() & {
3634
6.50k
    TL_ASSERT(has_value());
3635
6.50k
    return val();
3636
6.50k
  }
_ZNR2tl8expectedIN3ada16url_pattern_initENS1_6errorsEEdeIS2_TnPNSt3__19enable_ifIXntsr3std7is_voidIT_EE5valueEvE4typeELPv0EEERS8_v
Line
Count
Source
3633
1.18k
  TL_EXPECTED_11_CONSTEXPR U &operator*() & {
3634
1.18k
    TL_ASSERT(has_value());
3635
1.18k
    return val();
3636
1.18k
  }
_ZNR2tl8expectedINSt3__16vectorIN3ada16url_pattern_partENS1_9allocatorIS4_EEEENS3_6errorsEEdeIS7_TnPNS1_9enable_ifIXntsr3std7is_voidIT_EE5valueEvE4typeELPv0EEERSC_v
Line
Count
Source
3633
15.9k
  TL_EXPECTED_11_CONSTEXPR U &operator*() & {
3634
15.9k
    TL_ASSERT(has_value());
3635
15.9k
    return val();
3636
15.9k
  }
_ZNR2tl8expectedIN3ada21url_pattern_componentINS1_17url_pattern_regex18std_regex_providerEEENS1_6errorsEEdeIS5_TnPNSt3__19enable_ifIXntsr3std7is_voidIT_EE5valueEvE4typeELPv0EEERSB_v
Line
Count
Source
3633
5.31k
  TL_EXPECTED_11_CONSTEXPR U &operator*() & {
3634
5.31k
    TL_ASSERT(has_value());
3635
5.31k
    return val();
3636
5.31k
  }
3637
  template <class U = T,
3638
            detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
3639
  constexpr const U &&operator*() const && {
3640
    TL_ASSERT(has_value());
3641
    return std::move(val());
3642
  }
3643
  template <class U = T,
3644
            detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
3645
  TL_EXPECTED_11_CONSTEXPR U &&operator*() && {
3646
    TL_ASSERT(has_value());
3647
    return std::move(val());
3648
  }
3649
3650
774k
  constexpr bool has_value() const noexcept { return this->m_has_val; }
tl::expected<ada::url, ada::errors>::has_value() const
Line
Count
Source
3650
208k
  constexpr bool has_value() const noexcept { return this->m_has_val; }
tl::expected<ada::url_aggregator, ada::errors>::has_value() const
Line
Count
Source
3650
512k
  constexpr bool has_value() const noexcept { return this->m_has_val; }
tl::expected<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, ada::errors>::has_value() const
Line
Count
Source
3650
10.0k
  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
tl::expected<ada::url_pattern<ada::url_pattern_regex::std_regex_provider>, ada::errors>::has_value() const
Line
Count
Source
3650
591
  constexpr bool has_value() const noexcept { return this->m_has_val; }
tl::expected<std::__1::vector<ada::url_pattern_helpers::token, std::__1::allocator<ada::url_pattern_helpers::token> >, ada::errors>::has_value() const
Line
Count
Source
3650
6.50k
  constexpr bool has_value() const noexcept { return this->m_has_val; }
tl::expected<ada::url_pattern_init, ada::errors>::has_value() const
Line
Count
Source
3650
15.7k
  constexpr bool has_value() const noexcept { return this->m_has_val; }
tl::expected<std::__1::vector<ada::url_pattern_part, std::__1::allocator<ada::url_pattern_part> >, ada::errors>::has_value() const
Line
Count
Source
3650
15.9k
  constexpr bool has_value() const noexcept { return this->m_has_val; }
tl::expected<ada::url_pattern_component<ada::url_pattern_regex::std_regex_provider>, ada::errors>::has_value() const
Line
Count
Source
3650
5.31k
  constexpr bool has_value() const noexcept { return this->m_has_val; }
3651
314k
  constexpr explicit operator bool() const noexcept { return this->m_has_val; }
tl::expected<ada::url, ada::errors>::operator bool() const
Line
Count
Source
3651
21.2k
  constexpr explicit operator bool() const noexcept { return this->m_has_val; }
tl::expected<ada::url_aggregator, ada::errors>::operator bool() const
Line
Count
Source
3651
262k
  constexpr explicit operator bool() const noexcept { return this->m_has_val; }
tl::expected<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, ada::errors>::operator bool() const
Line
Count
Source
3651
10.0k
  constexpr explicit operator bool() const noexcept { return this->m_has_val; }
Unexecuted instantiation: tl::expected<ada::url_search_params, ada::errors>::operator bool() const
tl::expected<ada::url_pattern<ada::url_pattern_regex::std_regex_provider>, ada::errors>::operator bool() const
Line
Count
Source
3651
1.57k
  constexpr explicit operator bool() const noexcept { return this->m_has_val; }
tl::expected<std::__1::vector<ada::url_pattern_helpers::token, std::__1::allocator<ada::url_pattern_helpers::token> >, ada::errors>::operator bool() const
Line
Count
Source
3651
6.50k
  constexpr explicit operator bool() const noexcept { return this->m_has_val; }
tl::expected<ada::url_pattern_init, ada::errors>::operator bool() const
Line
Count
Source
3651
2.16k
  constexpr explicit operator bool() const noexcept { return this->m_has_val; }
tl::expected<std::__1::vector<ada::url_pattern_part, std::__1::allocator<ada::url_pattern_part> >, ada::errors>::operator bool() const
Line
Count
Source
3651
5.31k
  constexpr explicit operator bool() const noexcept { return this->m_has_val; }
tl::expected<ada::url_pattern_component<ada::url_pattern_regex::std_regex_provider>, ada::errors>::operator bool() const
Line
Count
Source
3651
5.31k
  constexpr explicit operator bool() const noexcept { return this->m_has_val; }
3652
3653
  template <class U = T,
3654
            detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
3655
  TL_EXPECTED_11_CONSTEXPR const U &value() const & {
3656
    if (!has_value())
3657
      detail::throw_exception(bad_expected_access<E>(err().value()));
3658
    return val();
3659
  }
3660
  template <class U = T,
3661
            detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
3662
0
  TL_EXPECTED_11_CONSTEXPR U &value() & {
3663
0
    if (!has_value())
3664
0
      detail::throw_exception(bad_expected_access<E>(err().value()));
3665
0
    return val();
3666
0
  }
3667
  template <class U = T,
3668
            detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
3669
  TL_EXPECTED_11_CONSTEXPR const U &&value() const && {
3670
    if (!has_value())
3671
      detail::throw_exception(bad_expected_access<E>(std::move(err()).value()));
3672
    return std::move(val());
3673
  }
3674
  template <class U = T,
3675
            detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
3676
  TL_EXPECTED_11_CONSTEXPR U &&value() && {
3677
    if (!has_value())
3678
      detail::throw_exception(bad_expected_access<E>(std::move(err()).value()));
3679
    return std::move(val());
3680
  }
3681
3682
  constexpr const E &error() const & {
3683
    TL_ASSERT(!has_value());
3684
    return err().value();
3685
  }
3686
394
  TL_EXPECTED_11_CONSTEXPR E &error() & {
3687
394
    TL_ASSERT(!has_value());
3688
394
    return err().value();
3689
394
  }
Unexecuted instantiation: tl::expected<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, ada::errors>::error() &
Unexecuted instantiation: tl::expected<std::__1::vector<ada::url_pattern_helpers::token, std::__1::allocator<ada::url_pattern_helpers::token> >, ada::errors>::error() &
Unexecuted instantiation: tl::expected<std::__1::vector<ada::url_pattern_helpers::token, std::__1::allocator<ada::url_pattern_helpers::token> >, ada::errors>::error() &
tl::expected<ada::url_pattern_init, ada::errors>::error() &
Line
Count
Source
3686
394
  TL_EXPECTED_11_CONSTEXPR E &error() & {
3687
394
    TL_ASSERT(!has_value());
3688
394
    return err().value();
3689
394
  }
Unexecuted instantiation: tl::expected<std::__1::vector<ada::url_pattern_part, std::__1::allocator<ada::url_pattern_part> >, ada::errors>::error() &
Unexecuted instantiation: tl::expected<ada::url_pattern_component<ada::url_pattern_regex::std_regex_provider>, ada::errors>::error() &
3690
  constexpr const E &&error() const && {
3691
    TL_ASSERT(!has_value());
3692
    return std::move(err().value());
3693
  }
3694
  TL_EXPECTED_11_CONSTEXPR E &&error() && {
3695
    TL_ASSERT(!has_value());
3696
    return std::move(err().value());
3697
  }
3698
3699
  template <class U>
3700
  constexpr T value_or(U &&v) const & {
3701
    static_assert(std::is_copy_constructible<T>::value &&
3702
                      std::is_convertible<U &&, T>::value,
3703
                  "T must be copy-constructible and convertible to from U&&");
3704
    return bool(*this) ? **this : static_cast<T>(std::forward<U>(v));
3705
  }
3706
  template <class U>
3707
  TL_EXPECTED_11_CONSTEXPR T value_or(U &&v) && {
3708
    static_assert(std::is_move_constructible<T>::value &&
3709
                      std::is_convertible<U &&, T>::value,
3710
                  "T must be move-constructible and convertible to from U&&");
3711
    return bool(*this) ? std::move(**this) : static_cast<T>(std::forward<U>(v));
3712
  }
3713
};
3714
3715
namespace detail {
3716
template <class Exp>
3717
using exp_t = typename detail::decay_t<Exp>::value_type;
3718
template <class Exp>
3719
using err_t = typename detail::decay_t<Exp>::error_type;
3720
template <class Exp, class Ret>
3721
using ret_t = expected<Ret, err_t<Exp>>;
3722
3723
#ifdef TL_EXPECTED_CXX14
3724
template <class Exp, class F,
3725
          detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
3726
          class Ret = decltype(detail::invoke(std::declval<F>(),
3727
                                              *std::declval<Exp>()))>
3728
constexpr auto and_then_impl(Exp &&exp, F &&f) {
3729
  static_assert(detail::is_expected<Ret>::value, "F must return an expected");
3730
3731
  return exp.has_value()
3732
             ? detail::invoke(std::forward<F>(f), *std::forward<Exp>(exp))
3733
             : Ret(unexpect, std::forward<Exp>(exp).error());
3734
}
3735
3736
template <class Exp, class F,
3737
          detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
3738
          class Ret = decltype(detail::invoke(std::declval<F>()))>
3739
constexpr auto and_then_impl(Exp &&exp, F &&f) {
3740
  static_assert(detail::is_expected<Ret>::value, "F must return an expected");
3741
3742
  return exp.has_value() ? detail::invoke(std::forward<F>(f))
3743
                         : Ret(unexpect, std::forward<Exp>(exp).error());
3744
}
3745
#else
3746
template <class>
3747
struct TC;
3748
template <class Exp, class F,
3749
          class Ret = decltype(detail::invoke(std::declval<F>(),
3750
                                              *std::declval<Exp>())),
3751
          detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr>
3752
auto and_then_impl(Exp &&exp, F &&f) -> Ret {
3753
  static_assert(detail::is_expected<Ret>::value, "F must return an expected");
3754
3755
  return exp.has_value()
3756
             ? detail::invoke(std::forward<F>(f), *std::forward<Exp>(exp))
3757
             : Ret(unexpect, std::forward<Exp>(exp).error());
3758
}
3759
3760
template <class Exp, class F,
3761
          class Ret = decltype(detail::invoke(std::declval<F>())),
3762
          detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr>
3763
constexpr auto and_then_impl(Exp &&exp, F &&f) -> Ret {
3764
  static_assert(detail::is_expected<Ret>::value, "F must return an expected");
3765
3766
  return exp.has_value() ? detail::invoke(std::forward<F>(f))
3767
                         : Ret(unexpect, std::forward<Exp>(exp).error());
3768
}
3769
#endif
3770
3771
#ifdef TL_EXPECTED_CXX14
3772
template <class Exp, class F,
3773
          detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
3774
          class Ret = decltype(detail::invoke(std::declval<F>(),
3775
                                              *std::declval<Exp>())),
3776
          detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
3777
constexpr auto expected_map_impl(Exp &&exp, F &&f) {
3778
  using result = ret_t<Exp, detail::decay_t<Ret>>;
3779
  return exp.has_value() ? result(detail::invoke(std::forward<F>(f),
3780
                                                 *std::forward<Exp>(exp)))
3781
                         : result(unexpect, std::forward<Exp>(exp).error());
3782
}
3783
3784
template <class Exp, class F,
3785
          detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
3786
          class Ret = decltype(detail::invoke(std::declval<F>(),
3787
                                              *std::declval<Exp>())),
3788
          detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
3789
auto expected_map_impl(Exp &&exp, F &&f) {
3790
  using result = expected<void, err_t<Exp>>;
3791
  if (exp.has_value()) {
3792
    detail::invoke(std::forward<F>(f), *std::forward<Exp>(exp));
3793
    return result();
3794
  }
3795
3796
  return result(unexpect, std::forward<Exp>(exp).error());
3797
}
3798
3799
template <class Exp, class F,
3800
          detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
3801
          class Ret = decltype(detail::invoke(std::declval<F>())),
3802
          detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
3803
constexpr auto expected_map_impl(Exp &&exp, F &&f) {
3804
  using result = ret_t<Exp, detail::decay_t<Ret>>;
3805
  return exp.has_value() ? result(detail::invoke(std::forward<F>(f)))
3806
                         : result(unexpect, std::forward<Exp>(exp).error());
3807
}
3808
3809
template <class Exp, class F,
3810
          detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
3811
          class Ret = decltype(detail::invoke(std::declval<F>())),
3812
          detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
3813
auto expected_map_impl(Exp &&exp, F &&f) {
3814
  using result = expected<void, err_t<Exp>>;
3815
  if (exp.has_value()) {
3816
    detail::invoke(std::forward<F>(f));
3817
    return result();
3818
  }
3819
3820
  return result(unexpect, std::forward<Exp>(exp).error());
3821
}
3822
#else
3823
template <class Exp, class F,
3824
          detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
3825
          class Ret = decltype(detail::invoke(std::declval<F>(),
3826
                                              *std::declval<Exp>())),
3827
          detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
3828
3829
constexpr auto expected_map_impl(Exp &&exp, F &&f)
3830
    -> ret_t<Exp, detail::decay_t<Ret>> {
3831
  using result = ret_t<Exp, detail::decay_t<Ret>>;
3832
3833
  return exp.has_value() ? result(detail::invoke(std::forward<F>(f),
3834
                                                 *std::forward<Exp>(exp)))
3835
                         : result(unexpect, std::forward<Exp>(exp).error());
3836
}
3837
3838
template <class Exp, class F,
3839
          detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
3840
          class Ret = decltype(detail::invoke(std::declval<F>(),
3841
                                              *std::declval<Exp>())),
3842
          detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
3843
3844
auto expected_map_impl(Exp &&exp, F &&f) -> expected<void, err_t<Exp>> {
3845
  if (exp.has_value()) {
3846
    detail::invoke(std::forward<F>(f), *std::forward<Exp>(exp));
3847
    return {};
3848
  }
3849
3850
  return unexpected<err_t<Exp>>(std::forward<Exp>(exp).error());
3851
}
3852
3853
template <class Exp, class F,
3854
          detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
3855
          class Ret = decltype(detail::invoke(std::declval<F>())),
3856
          detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
3857
3858
constexpr auto expected_map_impl(Exp &&exp, F &&f)
3859
    -> ret_t<Exp, detail::decay_t<Ret>> {
3860
  using result = ret_t<Exp, detail::decay_t<Ret>>;
3861
3862
  return exp.has_value() ? result(detail::invoke(std::forward<F>(f)))
3863
                         : result(unexpect, std::forward<Exp>(exp).error());
3864
}
3865
3866
template <class Exp, class F,
3867
          detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
3868
          class Ret = decltype(detail::invoke(std::declval<F>())),
3869
          detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
3870
3871
auto expected_map_impl(Exp &&exp, F &&f) -> expected<void, err_t<Exp>> {
3872
  if (exp.has_value()) {
3873
    detail::invoke(std::forward<F>(f));
3874
    return {};
3875
  }
3876
3877
  return unexpected<err_t<Exp>>(std::forward<Exp>(exp).error());
3878
}
3879
#endif
3880
3881
#if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \
3882
    !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55)
3883
template <class Exp, class F,
3884
          detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
3885
          class Ret = decltype(detail::invoke(std::declval<F>(),
3886
                                              std::declval<Exp>().error())),
3887
          detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
3888
constexpr auto map_error_impl(Exp &&exp, F &&f) {
3889
  using result = expected<exp_t<Exp>, detail::decay_t<Ret>>;
3890
  return exp.has_value()
3891
             ? result(*std::forward<Exp>(exp))
3892
             : result(unexpect, detail::invoke(std::forward<F>(f),
3893
                                               std::forward<Exp>(exp).error()));
3894
}
3895
template <class Exp, class F,
3896
          detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
3897
          class Ret = decltype(detail::invoke(std::declval<F>(),
3898
                                              std::declval<Exp>().error())),
3899
          detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
3900
auto map_error_impl(Exp &&exp, F &&f) {
3901
  using result = expected<exp_t<Exp>, monostate>;
3902
  if (exp.has_value()) {
3903
    return result(*std::forward<Exp>(exp));
3904
  }
3905
3906
  detail::invoke(std::forward<F>(f), std::forward<Exp>(exp).error());
3907
  return result(unexpect, monostate{});
3908
}
3909
template <class Exp, class F,
3910
          detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
3911
          class Ret = decltype(detail::invoke(std::declval<F>(),
3912
                                              std::declval<Exp>().error())),
3913
          detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
3914
constexpr auto map_error_impl(Exp &&exp, F &&f) {
3915
  using result = expected<exp_t<Exp>, detail::decay_t<Ret>>;
3916
  return exp.has_value()
3917
             ? result()
3918
             : result(unexpect, detail::invoke(std::forward<F>(f),
3919
                                               std::forward<Exp>(exp).error()));
3920
}
3921
template <class Exp, class F,
3922
          detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
3923
          class Ret = decltype(detail::invoke(std::declval<F>(),
3924
                                              std::declval<Exp>().error())),
3925
          detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
3926
auto map_error_impl(Exp &&exp, F &&f) {
3927
  using result = expected<exp_t<Exp>, monostate>;
3928
  if (exp.has_value()) {
3929
    return result();
3930
  }
3931
3932
  detail::invoke(std::forward<F>(f), std::forward<Exp>(exp).error());
3933
  return result(unexpect, monostate{});
3934
}
3935
#else
3936
template <class Exp, class F,
3937
          detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
3938
          class Ret = decltype(detail::invoke(std::declval<F>(),
3939
                                              std::declval<Exp>().error())),
3940
          detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
3941
constexpr auto map_error_impl(Exp &&exp, F &&f)
3942
    -> expected<exp_t<Exp>, detail::decay_t<Ret>> {
3943
  using result = expected<exp_t<Exp>, detail::decay_t<Ret>>;
3944
3945
  return exp.has_value()
3946
             ? result(*std::forward<Exp>(exp))
3947
             : result(unexpect, detail::invoke(std::forward<F>(f),
3948
                                               std::forward<Exp>(exp).error()));
3949
}
3950
3951
template <class Exp, class F,
3952
          detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
3953
          class Ret = decltype(detail::invoke(std::declval<F>(),
3954
                                              std::declval<Exp>().error())),
3955
          detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
3956
auto map_error_impl(Exp &&exp, F &&f) -> expected<exp_t<Exp>, monostate> {
3957
  using result = expected<exp_t<Exp>, monostate>;
3958
  if (exp.has_value()) {
3959
    return result(*std::forward<Exp>(exp));
3960
  }
3961
3962
  detail::invoke(std::forward<F>(f), std::forward<Exp>(exp).error());
3963
  return result(unexpect, monostate{});
3964
}
3965
3966
template <class Exp, class F,
3967
          detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
3968
          class Ret = decltype(detail::invoke(std::declval<F>(),
3969
                                              std::declval<Exp>().error())),
3970
          detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
3971
constexpr auto map_error_impl(Exp &&exp, F &&f)
3972
    -> expected<exp_t<Exp>, detail::decay_t<Ret>> {
3973
  using result = expected<exp_t<Exp>, detail::decay_t<Ret>>;
3974
3975
  return exp.has_value()
3976
             ? result()
3977
             : result(unexpect, detail::invoke(std::forward<F>(f),
3978
                                               std::forward<Exp>(exp).error()));
3979
}
3980
3981
template <class Exp, class F,
3982
          detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
3983
          class Ret = decltype(detail::invoke(std::declval<F>(),
3984
                                              std::declval<Exp>().error())),
3985
          detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
3986
auto map_error_impl(Exp &&exp, F &&f) -> expected<exp_t<Exp>, monostate> {
3987
  using result = expected<exp_t<Exp>, monostate>;
3988
  if (exp.has_value()) {
3989
    return result();
3990
  }
3991
3992
  detail::invoke(std::forward<F>(f), std::forward<Exp>(exp).error());
3993
  return result(unexpect, monostate{});
3994
}
3995
#endif
3996
3997
#ifdef TL_EXPECTED_CXX14
3998
template <class Exp, class F,
3999
          class Ret = decltype(detail::invoke(std::declval<F>(),
4000
                                              std::declval<Exp>().error())),
4001
          detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
4002
constexpr auto or_else_impl(Exp &&exp, F &&f) {
4003
  static_assert(detail::is_expected<Ret>::value, "F must return an expected");
4004
  return exp.has_value() ? std::forward<Exp>(exp)
4005
                         : detail::invoke(std::forward<F>(f),
4006
                                          std::forward<Exp>(exp).error());
4007
}
4008
4009
template <class Exp, class F,
4010
          class Ret = decltype(detail::invoke(std::declval<F>(),
4011
                                              std::declval<Exp>().error())),
4012
          detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
4013
detail::decay_t<Exp> or_else_impl(Exp &&exp, F &&f) {
4014
  return exp.has_value() ? std::forward<Exp>(exp)
4015
                         : (detail::invoke(std::forward<F>(f),
4016
                                           std::forward<Exp>(exp).error()),
4017
                            std::forward<Exp>(exp));
4018
}
4019
#else
4020
template <class Exp, class F,
4021
          class Ret = decltype(detail::invoke(std::declval<F>(),
4022
                                              std::declval<Exp>().error())),
4023
          detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
4024
auto or_else_impl(Exp &&exp, F &&f) -> Ret {
4025
  static_assert(detail::is_expected<Ret>::value, "F must return an expected");
4026
  return exp.has_value() ? std::forward<Exp>(exp)
4027
                         : detail::invoke(std::forward<F>(f),
4028
                                          std::forward<Exp>(exp).error());
4029
}
4030
4031
template <class Exp, class F,
4032
          class Ret = decltype(detail::invoke(std::declval<F>(),
4033
                                              std::declval<Exp>().error())),
4034
          detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
4035
detail::decay_t<Exp> or_else_impl(Exp &&exp, F &&f) {
4036
  return exp.has_value() ? std::forward<Exp>(exp)
4037
                         : (detail::invoke(std::forward<F>(f),
4038
                                           std::forward<Exp>(exp).error()),
4039
                            std::forward<Exp>(exp));
4040
}
4041
#endif
4042
}  // namespace detail
4043
4044
template <class T, class E, class U, class F>
4045
constexpr bool operator==(const expected<T, E> &lhs,
4046
                          const expected<U, F> &rhs) {
4047
  return (lhs.has_value() != rhs.has_value())
4048
             ? false
4049
             : (!lhs.has_value() ? lhs.error() == rhs.error() : *lhs == *rhs);
4050
}
4051
template <class T, class E, class U, class F>
4052
constexpr bool operator!=(const expected<T, E> &lhs,
4053
                          const expected<U, F> &rhs) {
4054
  return (lhs.has_value() != rhs.has_value())
4055
             ? true
4056
             : (!lhs.has_value() ? lhs.error() != rhs.error() : *lhs != *rhs);
4057
}
4058
template <class E, class F>
4059
constexpr bool operator==(const expected<void, E> &lhs,
4060
                          const expected<void, F> &rhs) {
4061
  return (lhs.has_value() != rhs.has_value())
4062
             ? false
4063
             : (!lhs.has_value() ? lhs.error() == rhs.error() : true);
4064
}
4065
template <class E, class F>
4066
constexpr bool operator!=(const expected<void, E> &lhs,
4067
                          const expected<void, F> &rhs) {
4068
  return (lhs.has_value() != rhs.has_value())
4069
             ? true
4070
             : (!lhs.has_value() ? lhs.error() == rhs.error() : false);
4071
}
4072
4073
template <class T, class E, class U>
4074
constexpr bool operator==(const expected<T, E> &x, const U &v) {
4075
  return x.has_value() ? *x == v : false;
4076
}
4077
template <class T, class E, class U>
4078
constexpr bool operator==(const U &v, const expected<T, E> &x) {
4079
  return x.has_value() ? *x == v : false;
4080
}
4081
template <class T, class E, class U>
4082
constexpr bool operator!=(const expected<T, E> &x, const U &v) {
4083
  return x.has_value() ? *x != v : true;
4084
}
4085
template <class T, class E, class U>
4086
constexpr bool operator!=(const U &v, const expected<T, E> &x) {
4087
  return x.has_value() ? *x != v : true;
4088
}
4089
4090
template <class T, class E>
4091
constexpr bool operator==(const expected<T, E> &x, const unexpected<E> &e) {
4092
  return x.has_value() ? false : x.error() == e.value();
4093
}
4094
template <class T, class E>
4095
constexpr bool operator==(const unexpected<E> &e, const expected<T, E> &x) {
4096
  return x.has_value() ? false : x.error() == e.value();
4097
}
4098
template <class T, class E>
4099
constexpr bool operator!=(const expected<T, E> &x, const unexpected<E> &e) {
4100
  return x.has_value() ? true : x.error() != e.value();
4101
}
4102
template <class T, class E>
4103
constexpr bool operator!=(const unexpected<E> &e, const expected<T, E> &x) {
4104
  return x.has_value() ? true : x.error() != e.value();
4105
}
4106
4107
template <class T, class E,
4108
          detail::enable_if_t<(std::is_void<T>::value ||
4109
                               std::is_move_constructible<T>::value) &&
4110
                              detail::is_swappable<T>::value &&
4111
                              std::is_move_constructible<E>::value &&
4112
                              detail::is_swappable<E>::value> * = nullptr>
4113
void swap(expected<T, E> &lhs,
4114
          expected<T, E> &rhs) noexcept(noexcept(lhs.swap(rhs))) {
4115
  lhs.swap(rhs);
4116
}
4117
}  // namespace tl
4118
4119
#endif
4120
/* end file include/ada/expected.h */
4121
4122
/* begin file include/ada/url_pattern_regex.h */
4123
/**
4124
 * @file url_search_params.h
4125
 * @brief Declaration for the URL Search Params
4126
 */
4127
#ifndef ADA_URL_PATTERN_REGEX_H
4128
#define ADA_URL_PATTERN_REGEX_H
4129
4130
#include <string>
4131
#include <string_view>
4132
4133
#ifdef ADA_USE_UNSAFE_STD_REGEX_PROVIDER
4134
#include <regex>
4135
#endif  // ADA_USE_UNSAFE_STD_REGEX_PROVIDER
4136
4137
#if ADA_INCLUDE_URL_PATTERN
4138
namespace ada::url_pattern_regex {
4139
4140
template <typename T>
4141
concept regex_concept = requires(T t, std::string_view pattern,
4142
                                 bool ignore_case, std::string_view input) {
4143
  // Ensure the class has a type alias 'regex_type'
4144
  typename T::regex_type;
4145
4146
  // Function to create a regex instance
4147
  {
4148
    T::create_instance(pattern, ignore_case)
4149
  } -> std::same_as<std::optional<typename T::regex_type>>;
4150
4151
  // Function to perform regex search
4152
  {
4153
    T::regex_search(input, std::declval<typename T::regex_type&>())
4154
  } -> std::same_as<std::optional<std::vector<std::optional<std::string>>>>;
4155
4156
  // Function to match regex pattern
4157
  {
4158
    T::regex_match(input, std::declval<typename T::regex_type&>())
4159
  } -> std::same_as<bool>;
4160
4161
  // Copy constructor
4162
  { T(std::declval<const T&>()) } -> std::same_as<T>;
4163
4164
  // Move constructor
4165
  { T(std::declval<T&&>()) } -> std::same_as<T>;
4166
};
4167
4168
#ifdef ADA_USE_UNSAFE_STD_REGEX_PROVIDER
4169
class std_regex_provider final {
4170
 public:
4171
  std_regex_provider() = default;
4172
  using regex_type = std::regex;
4173
  static std::optional<regex_type> create_instance(std::string_view pattern,
4174
                                                   bool ignore_case);
4175
  static std::optional<std::vector<std::optional<std::string>>> regex_search(
4176
      std::string_view input, const regex_type& pattern);
4177
  static bool regex_match(std::string_view input, const regex_type& pattern);
4178
};
4179
#endif  // ADA_USE_UNSAFE_STD_REGEX_PROVIDER
4180
4181
}  // namespace ada::url_pattern_regex
4182
#endif  // ADA_INCLUDE_URL_PATTERN
4183
#endif  // ADA_URL_PATTERN_REGEX_H
4184
/* end file include/ada/url_pattern_regex.h */
4185
/* begin file include/ada/url_pattern_init.h */
4186
/**
4187
 * @file url_pattern_init.h
4188
 * @brief Declaration for the url_pattern_init implementation.
4189
 */
4190
#ifndef ADA_URL_PATTERN_INIT_H
4191
#define ADA_URL_PATTERN_INIT_H
4192
4193
/* begin file include/ada/errors.h */
4194
/**
4195
 * @file errors.h
4196
 * @brief Definitions for the errors.
4197
 */
4198
#ifndef ADA_ERRORS_H
4199
#define ADA_ERRORS_H
4200
4201
#include <cstdint>
4202
namespace ada {
4203
enum class errors : uint8_t { type_error };
4204
}  // namespace ada
4205
#endif  // ADA_ERRORS_H
4206
/* end file include/ada/errors.h */
4207
4208
#include <string_view>
4209
#include <string>
4210
#include <optional>
4211
#include <iostream>
4212
4213
#if ADA_TESTING
4214
#include <iostream>
4215
#endif  // ADA_TESTING
4216
4217
#if ADA_INCLUDE_URL_PATTERN
4218
namespace ada {
4219
4220
// Important: C++20 allows us to use concept rather than `using` or `typedef
4221
// and allows functions with second argument, which is optional (using either
4222
// std::nullopt or a parameter with default value)
4223
template <typename F>
4224
concept url_pattern_encoding_callback = requires(F f, std::string_view sv) {
4225
  { f(sv) } -> std::same_as<tl::expected<std::string, errors>>;
4226
};
4227
4228
// A structure providing matching patterns for individual components
4229
// of a URL. When a URLPattern is created, or when a URLPattern is
4230
// used to match or test against a URL, the input can be given as
4231
// either a string or a URLPatternInit struct. If a string is given,
4232
// it will be parsed to create a URLPatternInit. The URLPatternInit
4233
// API is defined as part of the URLPattern specification.
4234
// All provided strings must be valid UTF-8.
4235
struct url_pattern_init {
4236
  enum class process_type : uint8_t {
4237
    url,
4238
    pattern,
4239
  };
4240
4241
0
  friend std::ostream& operator<<(std::ostream& os, process_type type) {
4242
0
    switch (type) {
4243
0
      case process_type::url:
4244
0
        return os << "url";
4245
0
      case process_type::pattern:
4246
0
        return os << "pattern";
4247
0
      default:
4248
0
        return os << "unknown";
4249
0
    }
4250
0
  }
4251
4252
  // All strings must be valid UTF-8.
4253
  // @see https://urlpattern.spec.whatwg.org/#process-a-urlpatterninit
4254
  static tl::expected<url_pattern_init, errors> process(
4255
      const url_pattern_init& init, process_type type,
4256
      std::optional<std::string_view> protocol = std::nullopt,
4257
      std::optional<std::string_view> username = std::nullopt,
4258
      std::optional<std::string_view> password = std::nullopt,
4259
      std::optional<std::string_view> hostname = std::nullopt,
4260
      std::optional<std::string_view> port = std::nullopt,
4261
      std::optional<std::string_view> pathname = std::nullopt,
4262
      std::optional<std::string_view> search = std::nullopt,
4263
      std::optional<std::string_view> hash = std::nullopt);
4264
4265
  // @see https://urlpattern.spec.whatwg.org/#process-protocol-for-init
4266
  static tl::expected<std::string, errors> process_protocol(
4267
      std::string_view value, process_type type);
4268
4269
  // @see https://urlpattern.spec.whatwg.org/#process-username-for-init
4270
  static tl::expected<std::string, errors> process_username(
4271
      std::string_view value, process_type type);
4272
4273
  // @see https://urlpattern.spec.whatwg.org/#process-password-for-init
4274
  static tl::expected<std::string, errors> process_password(
4275
      std::string_view value, process_type type);
4276
4277
  // @see https://urlpattern.spec.whatwg.org/#process-hostname-for-init
4278
  static tl::expected<std::string, errors> process_hostname(
4279
      std::string_view value, process_type type);
4280
4281
  // @see https://urlpattern.spec.whatwg.org/#process-port-for-init
4282
  static tl::expected<std::string, errors> process_port(
4283
      std::string_view port, std::string_view protocol, process_type type);
4284
4285
  // @see https://urlpattern.spec.whatwg.org/#process-pathname-for-init
4286
  static tl::expected<std::string, errors> process_pathname(
4287
      std::string_view value, std::string_view protocol, process_type type);
4288
4289
  // @see https://urlpattern.spec.whatwg.org/#process-search-for-init
4290
  static tl::expected<std::string, errors> process_search(
4291
      std::string_view value, process_type type);
4292
4293
  // @see https://urlpattern.spec.whatwg.org/#process-hash-for-init
4294
  static tl::expected<std::string, errors> process_hash(std::string_view value,
4295
                                                        process_type type);
4296
4297
#if ADA_TESTING
4298
  friend void PrintTo(const url_pattern_init& init, std::ostream* os) {
4299
    *os << "protocol: '" << init.protocol.value_or("undefined") << "', ";
4300
    *os << "username: '" << init.username.value_or("undefined") << "', ";
4301
    *os << "password: '" << init.password.value_or("undefined") << "', ";
4302
    *os << "hostname: '" << init.hostname.value_or("undefined") << "', ";
4303
    *os << "port: '" << init.port.value_or("undefined") << "', ";
4304
    *os << "pathname: '" << init.pathname.value_or("undefined") << "', ";
4305
    *os << "search: '" << init.search.value_or("undefined") << "', ";
4306
    *os << "hash: '" << init.hash.value_or("undefined") << "', ";
4307
    *os << "base_url: '" << init.base_url.value_or("undefined") << "', ";
4308
  }
4309
#endif  // ADA_TESTING
4310
4311
  bool operator==(const url_pattern_init&) const;
4312
  // If present, must be valid UTF-8.
4313
  std::optional<std::string> protocol{};
4314
  // If present, must be valid UTF-8.
4315
  std::optional<std::string> username{};
4316
  // If present, must be valid UTF-8.
4317
  std::optional<std::string> password{};
4318
  // If present, must be valid UTF-8.
4319
  std::optional<std::string> hostname{};
4320
  // If present, must be valid UTF-8.
4321
  std::optional<std::string> port{};
4322
  // If present, must be valid UTF-8.
4323
  std::optional<std::string> pathname{};
4324
  // If present, must be valid UTF-8.
4325
  std::optional<std::string> search{};
4326
  // If present, must be valid UTF-8.
4327
  std::optional<std::string> hash{};
4328
  // If present, must be valid UTF-8.
4329
  std::optional<std::string> base_url{};
4330
};
4331
}  // namespace ada
4332
#endif  // ADA_INCLUDE_URL_PATTERN
4333
#endif  // ADA_URL_PATTERN_INIT_H
4334
/* end file include/ada/url_pattern_init.h */
4335
4336
/**
4337
 * @private
4338
 */
4339
namespace ada {
4340
struct url_aggregator;
4341
struct url;
4342
#if ADA_INCLUDE_URL_PATTERN
4343
template <url_pattern_regex::regex_concept regex_provider>
4344
class url_pattern;
4345
struct url_pattern_options;
4346
#endif  // ADA_INCLUDE_URL_PATTERN
4347
enum class errors : uint8_t;
4348
}  // namespace ada
4349
4350
/**
4351
 * @namespace ada::parser
4352
 * @brief Includes the definitions for supported parsers
4353
 */
4354
namespace ada::parser {
4355
/**
4356
 * Parses a url. The parameter user_input is the input to be parsed:
4357
 * it should be a valid UTF-8 string. The parameter base_url is an optional
4358
 * parameter that can be used to resolve relative URLs. If the base_url is
4359
 * provided, the user_input is resolved against the base_url.
4360
 */
4361
template <typename result_type = url_aggregator>
4362
result_type parse_url(std::string_view user_input,
4363
                      const result_type* base_url = nullptr);
4364
4365
extern template url_aggregator parse_url<url_aggregator>(
4366
    std::string_view user_input, const url_aggregator* base_url);
4367
extern template url parse_url<url>(std::string_view user_input,
4368
                                   const url* base_url);
4369
4370
template <typename result_type = url_aggregator, bool store_values = true>
4371
result_type parse_url_impl(std::string_view user_input,
4372
                           const result_type* base_url = nullptr);
4373
4374
extern template url_aggregator parse_url_impl<url_aggregator>(
4375
    std::string_view user_input, const url_aggregator* base_url);
4376
extern template url parse_url_impl<url>(std::string_view user_input,
4377
                                        const url* base_url);
4378
4379
#if ADA_INCLUDE_URL_PATTERN
4380
template <url_pattern_regex::regex_concept regex_provider>
4381
tl::expected<url_pattern<regex_provider>, errors> parse_url_pattern_impl(
4382
    std::variant<std::string_view, url_pattern_init>&& input,
4383
    const std::string_view* base_url, const url_pattern_options* options);
4384
#endif  // ADA_INCLUDE_URL_PATTERN
4385
4386
}  // namespace ada::parser
4387
4388
#endif  // ADA_PARSER_H
4389
/* end file include/ada/parser.h */
4390
/* begin file include/ada/parser-inl.h */
4391
/**
4392
 * @file parser-inl.h
4393
 */
4394
#ifndef ADA_PARSER_INL_H
4395
#define ADA_PARSER_INL_H
4396
4397
/* begin file include/ada/url_pattern.h */
4398
/**
4399
 * @file url_pattern.h
4400
 * @brief Declaration for the URLPattern implementation.
4401
 */
4402
#ifndef ADA_URL_PATTERN_H
4403
#define ADA_URL_PATTERN_H
4404
4405
/* begin file include/ada/implementation.h */
4406
/**
4407
 * @file implementation.h
4408
 * @brief Definitions for user facing functions for parsing URL and it's
4409
 * components.
4410
 */
4411
#ifndef ADA_IMPLEMENTATION_H
4412
#define ADA_IMPLEMENTATION_H
4413
4414
#include <string>
4415
#include <string_view>
4416
#include <optional>
4417
4418
/* begin file include/ada/url.h */
4419
/**
4420
 * @file url.h
4421
 * @brief Declaration for the URL
4422
 */
4423
#ifndef ADA_URL_H
4424
#define ADA_URL_H
4425
4426
#include <algorithm>
4427
#include <optional>
4428
#include <ostream>
4429
#include <string>
4430
#include <string_view>
4431
4432
/* begin file include/ada/checkers.h */
4433
/**
4434
 * @file checkers.h
4435
 * @brief Declarations for URL specific checkers used within Ada.
4436
 */
4437
#ifndef ADA_CHECKERS_H
4438
#define ADA_CHECKERS_H
4439
4440
4441
#include <cstring>
4442
#include <string_view>
4443
4444
/**
4445
 * These functions are not part of our public API and may
4446
 * change at any time.
4447
 * @private
4448
 * @namespace ada::checkers
4449
 * @brief Includes the definitions for validation functions
4450
 */
4451
namespace ada::checkers {
4452
4453
/**
4454
 * @private
4455
 * Assuming that x is an ASCII letter, this function returns the lower case
4456
 * equivalent.
4457
 * @details More likely to be inlined by the compiler and constexpr.
4458
 */
4459
constexpr char to_lower(char x) noexcept;
4460
4461
/**
4462
 * @private
4463
 * Returns true if the character is an ASCII letter. Equivalent to std::isalpha
4464
 * but more likely to be inlined by the compiler.
4465
 *
4466
 * @attention std::isalpha is not constexpr generally.
4467
 */
4468
constexpr bool is_alpha(char x) noexcept;
4469
4470
/**
4471
 * @private
4472
 * Check whether a string starts with 0x or 0X. The function is only
4473
 * safe if input.size() >=2.
4474
 *
4475
 * @see has_hex_prefix
4476
 */
4477
constexpr bool has_hex_prefix_unsafe(std::string_view input);
4478
/**
4479
 * @private
4480
 * Check whether a string starts with 0x or 0X.
4481
 */
4482
constexpr bool has_hex_prefix(std::string_view input);
4483
4484
/**
4485
 * @private
4486
 * Check whether x is an ASCII digit. More likely to be inlined than
4487
 * std::isdigit.
4488
 */
4489
constexpr bool is_digit(char x) noexcept;
4490
4491
/**
4492
 * @private
4493
 * @details A string starts with a Windows drive letter if all of the following
4494
 * are true:
4495
 *
4496
 *   - its length is greater than or equal to 2
4497
 *   - its first two code points are a Windows drive letter
4498
 *   - its length is 2 or its third code point is U+002F (/), U+005C (\), U+003F
4499
 * (?), or U+0023 (#).
4500
 *
4501
 * https://url.spec.whatwg.org/#start-with-a-windows-drive-letter
4502
 */
4503
inline constexpr bool is_windows_drive_letter(std::string_view input) noexcept;
4504
4505
/**
4506
 * @private
4507
 * @details A normalized Windows drive letter is a Windows drive letter of which
4508
 * the second code point is U+003A (:).
4509
 */
4510
inline constexpr bool is_normalized_windows_drive_letter(
4511
    std::string_view input) noexcept;
4512
4513
/**
4514
 * @private
4515
 * Returns true if an input is an ipv4 address. It is assumed that the string
4516
 * does not contain uppercase ASCII characters (the input should have been
4517
 * lowered cased before calling this function) and is not empty.
4518
 */
4519
ada_really_inline constexpr bool is_ipv4(std::string_view view) noexcept;
4520
4521
/**
4522
 * @private
4523
 * Returns a bitset. If the first bit is set, then at least one character needs
4524
 * percent encoding. If the second bit is set, a \\ is found. If the third bit
4525
 * is set then we have a dot. If the fourth bit is set, then we have a percent
4526
 * character.
4527
 */
4528
ada_really_inline constexpr uint8_t path_signature(
4529
    std::string_view input) noexcept;
4530
4531
/**
4532
 * @private
4533
 * Returns true if the length of the domain name and its labels are according to
4534
 * the specifications. The length of the domain must be 255 octets (253
4535
 * characters not including the last 2 which are the empty label reserved at the
4536
 * end). When the empty label is included (a dot at the end), the domain name
4537
 * can have 254 characters. The length of a label must be at least 1 and at most
4538
 * 63 characters.
4539
 * @see section 3.1. of https://www.rfc-editor.org/rfc/rfc1034
4540
 * @see https://www.unicode.org/reports/tr46/#ToASCII
4541
 */
4542
ada_really_inline constexpr bool verify_dns_length(
4543
    std::string_view input) noexcept;
4544
4545
}  // namespace ada::checkers
4546
4547
#endif  // ADA_CHECKERS_H
4548
/* end file include/ada/checkers.h */
4549
/* begin file include/ada/url_components.h */
4550
/**
4551
 * @file url_components.h
4552
 * @brief Declaration for the URL Components
4553
 */
4554
#ifndef ADA_URL_COMPONENTS_H
4555
#define ADA_URL_COMPONENTS_H
4556
4557
namespace ada {
4558
4559
/**
4560
 * @brief URL Component representations using offsets.
4561
 *
4562
 * @details We design the url_components struct so that it is as small
4563
 * and simple as possible. This version uses 32 bytes.
4564
 *
4565
 * This struct is used to extract components from a single 'href'.
4566
 */
4567
struct url_components {
4568
  constexpr static uint32_t omitted = uint32_t(-1);
4569
4570
88.1k
  url_components() = default;
4571
  url_components(const url_components &u) = default;
4572
  url_components(url_components &&u) noexcept = default;
4573
  url_components &operator=(url_components &&u) noexcept = default;
4574
  url_components &operator=(const url_components &u) = default;
4575
  ~url_components() = default;
4576
4577
  /*
4578
   * By using 32-bit integers, we implicitly assume that the URL string
4579
   * cannot exceed 4 GB.
4580
   *
4581
   * https://user:pass@example.com:1234/foo/bar?baz#quux
4582
   *       |     |    |          | ^^^^|       |   |
4583
   *       |     |    |          | |   |       |   `----- hash_start
4584
   *       |     |    |          | |   |       `--------- search_start
4585
   *       |     |    |          | |   `----------------- pathname_start
4586
   *       |     |    |          | `--------------------- port
4587
   *       |     |    |          `----------------------- host_end
4588
   *       |     |    `---------------------------------- host_start
4589
   *       |     `--------------------------------------- username_end
4590
   *       `--------------------------------------------- protocol_end
4591
   */
4592
  uint32_t protocol_end{0};
4593
  /**
4594
   * Username end is not `omitted` by default to make username and password
4595
   * getters less costly to implement.
4596
   */
4597
  uint32_t username_end{0};
4598
  uint32_t host_start{0};
4599
  uint32_t host_end{0};
4600
  uint32_t port{omitted};
4601
  uint32_t pathname_start{0};
4602
  uint32_t search_start{omitted};
4603
  uint32_t hash_start{omitted};
4604
4605
  /**
4606
   * Check the following conditions:
4607
   * protocol_end < username_end < ... < hash_start,
4608
   * expect when a value is omitted. It also computes
4609
   * a lower bound on  the possible string length that may match these
4610
   * offsets.
4611
   * @return true if the offset values are
4612
   *  consistent with a possible URL string
4613
   */
4614
  [[nodiscard]] constexpr bool check_offset_consistency() const noexcept;
4615
4616
  /**
4617
   * Converts a url_components to JSON stringified version.
4618
   */
4619
  [[nodiscard]] std::string to_string() const;
4620
4621
};  // struct url_components
4622
}  // namespace ada
4623
#endif
4624
/* end file include/ada/url_components.h */
4625
4626
namespace ada {
4627
4628
struct url_aggregator;
4629
4630
// namespace parser {
4631
// template <typename result_type>
4632
// result_type parse_url(std::string_view user_input,
4633
//                       const result_type* base_url = nullptr);
4634
// template <typename result_type, bool store_values>
4635
// result_type parse_url_impl(std::string_view user_input,
4636
//                            const result_type* base_url = nullptr);
4637
// }
4638
4639
/**
4640
 * @brief Generic URL struct reliant on std::string instantiation.
4641
 *
4642
 * @details To disambiguate from a valid URL string it can also be referred to
4643
 * as a URL record. A URL is a struct that represents a universal identifier.
4644
 * Unlike the url_aggregator, the ada::url represents the different components
4645
 * of a parsed URL as independent std::string instances. This makes the
4646
 * structure heavier and more reliant on memory allocations. When getting
4647
 * components from the parsed URL, a new std::string is typically constructed.
4648
 *
4649
 * @see https://url.spec.whatwg.org/#url-representation
4650
 */
4651
struct url : url_base {
4652
21.2k
  url() = default;
4653
  url(const url &u) = default;
4654
15.1k
  url(url &&u) noexcept = default;
4655
  url &operator=(url &&u) noexcept = default;
4656
2.92k
  url &operator=(const url &u) = default;
4657
36.3k
  ~url() override = default;
4658
4659
  /**
4660
   * @private
4661
   * A URL's username is an ASCII string identifying a username. It is initially
4662
   * the empty string.
4663
   */
4664
  std::string username{};
4665
4666
  /**
4667
   * @private
4668
   * A URL's password is an ASCII string identifying a password. It is initially
4669
   * the empty string.
4670
   */
4671
  std::string password{};
4672
4673
  /**
4674
   * @private
4675
   * A URL's host is null or a host. It is initially null.
4676
   */
4677
  std::optional<std::string> host{};
4678
4679
  /**
4680
   * @private
4681
   * A URL's port is either null or a 16-bit unsigned integer that identifies a
4682
   * networking port. It is initially null.
4683
   */
4684
  std::optional<uint16_t> port{};
4685
4686
  /**
4687
   * @private
4688
   * A URL's path is either an ASCII string or a list of zero or more ASCII
4689
   * strings, usually identifying a location.
4690
   */
4691
  std::string path{};
4692
4693
  /**
4694
   * @private
4695
   * A URL's query is either null or an ASCII string. It is initially null.
4696
   */
4697
  std::optional<std::string> query{};
4698
4699
  /**
4700
   * @private
4701
   * A URL's fragment is either null or an ASCII string that can be used for
4702
   * further processing on the resource the URL's other components identify. It
4703
   * is initially null.
4704
   */
4705
  std::optional<std::string> hash{};
4706
4707
  /** @return true if it has an host but it is the empty string */
4708
  [[nodiscard]] inline bool has_empty_hostname() const noexcept;
4709
  /** @return true if the URL has a (non default) port */
4710
  [[nodiscard]] inline bool has_port() const noexcept;
4711
  /** @return true if it has a host (included an empty host) */
4712
  [[nodiscard]] inline bool has_hostname() const noexcept;
4713
  [[nodiscard]] bool has_valid_domain() const noexcept override;
4714
4715
  /**
4716
   * Returns a JSON string representation of this URL.
4717
   */
4718
  [[nodiscard]] std::string to_string() const override;
4719
4720
  /**
4721
   * @see https://url.spec.whatwg.org/#dom-url-href
4722
   * @see https://url.spec.whatwg.org/#concept-url-serializer
4723
   */
4724
  [[nodiscard]] ada_really_inline std::string get_href() const noexcept;
4725
4726
  /**
4727
   * The origin getter steps are to return the serialization of this's URL's
4728
   * origin. [HTML]
4729
   * @return a newly allocated string.
4730
   * @see https://url.spec.whatwg.org/#concept-url-origin
4731
   */
4732
  [[nodiscard]] std::string get_origin() const noexcept override;
4733
4734
  /**
4735
   * The protocol getter steps are to return this's URL's scheme, followed by
4736
   * U+003A (:).
4737
   * @return a newly allocated string.
4738
   * @see https://url.spec.whatwg.org/#dom-url-protocol
4739
   */
4740
  [[nodiscard]] std::string get_protocol() const noexcept;
4741
4742
  /**
4743
   * Return url's host, serialized, followed by U+003A (:) and url's port,
4744
   * serialized.
4745
   * When there is no host, this function returns the empty string.
4746
   * @return a newly allocated string.
4747
   * @see https://url.spec.whatwg.org/#dom-url-host
4748
   */
4749
  [[nodiscard]] std::string get_host() const noexcept;
4750
4751
  /**
4752
   * Return this's URL's host, serialized.
4753
   * When there is no host, this function returns the empty string.
4754
   * @return a newly allocated string.
4755
   * @see https://url.spec.whatwg.org/#dom-url-hostname
4756
   */
4757
  [[nodiscard]] std::string get_hostname() const noexcept;
4758
4759
  /**
4760
   * The pathname getter steps are to return the result of URL path serializing
4761
   * this's URL.
4762
   * @return a newly allocated string.
4763
   * @see https://url.spec.whatwg.org/#dom-url-pathname
4764
   */
4765
  [[nodiscard]] constexpr std::string_view get_pathname() const noexcept;
4766
4767
  /**
4768
   * Compute the pathname length in bytes without instantiating a view or a
4769
   * string.
4770
   * @return size of the pathname in bytes
4771
   * @see https://url.spec.whatwg.org/#dom-url-pathname
4772
   */
4773
  [[nodiscard]] ada_really_inline size_t get_pathname_length() const noexcept;
4774
4775
  /**
4776
   * Return U+003F (?), followed by this's URL's query.
4777
   * @return a newly allocated string.
4778
   * @see https://url.spec.whatwg.org/#dom-url-search
4779
   */
4780
  [[nodiscard]] std::string get_search() const noexcept;
4781
4782
  /**
4783
   * The username getter steps are to return this's URL's username.
4784
   * @return a constant reference to the underlying string.
4785
   * @see https://url.spec.whatwg.org/#dom-url-username
4786
   */
4787
  [[nodiscard]] const std::string &get_username() const noexcept;
4788
4789
  /**
4790
   * @return Returns true on successful operation.
4791
   * @see https://url.spec.whatwg.org/#dom-url-username
4792
   */
4793
  bool set_username(std::string_view input);
4794
4795
  /**
4796
   * @return Returns true on success.
4797
   * @see https://url.spec.whatwg.org/#dom-url-password
4798
   */
4799
  bool set_password(std::string_view input);
4800
4801
  /**
4802
   * @return Returns true on success.
4803
   * @see https://url.spec.whatwg.org/#dom-url-port
4804
   */
4805
  bool set_port(std::string_view input);
4806
4807
  /**
4808
   * This function always succeeds.
4809
   * @see https://url.spec.whatwg.org/#dom-url-hash
4810
   */
4811
  void set_hash(std::string_view input);
4812
4813
  /**
4814
   * This function always succeeds.
4815
   * @see https://url.spec.whatwg.org/#dom-url-search
4816
   */
4817
  void set_search(std::string_view input);
4818
4819
  /**
4820
   * @return Returns true on success.
4821
   * @see https://url.spec.whatwg.org/#dom-url-search
4822
   */
4823
  bool set_pathname(std::string_view input);
4824
4825
  /**
4826
   * @return Returns true on success.
4827
   * @see https://url.spec.whatwg.org/#dom-url-host
4828
   */
4829
  bool set_host(std::string_view input);
4830
4831
  /**
4832
   * @return Returns true on success.
4833
   * @see https://url.spec.whatwg.org/#dom-url-hostname
4834
   */
4835
  bool set_hostname(std::string_view input);
4836
4837
  /**
4838
   * @return Returns true on success.
4839
   * @see https://url.spec.whatwg.org/#dom-url-protocol
4840
   */
4841
  bool set_protocol(std::string_view input);
4842
4843
  /**
4844
   * @see https://url.spec.whatwg.org/#dom-url-href
4845
   */
4846
  bool set_href(std::string_view input);
4847
4848
  /**
4849
   * The password getter steps are to return this's URL's password.
4850
   * @return a constant reference to the underlying string.
4851
   * @see https://url.spec.whatwg.org/#dom-url-password
4852
   */
4853
  [[nodiscard]] const std::string &get_password() const noexcept;
4854
4855
  /**
4856
   * Return this's URL's port, serialized.
4857
   * @return a newly constructed string representing the port.
4858
   * @see https://url.spec.whatwg.org/#dom-url-port
4859
   */
4860
  [[nodiscard]] std::string get_port() const noexcept;
4861
4862
  /**
4863
   * Return U+0023 (#), followed by this's URL's fragment.
4864
   * @return a newly constructed string representing the hash.
4865
   * @see https://url.spec.whatwg.org/#dom-url-hash
4866
   */
4867
  [[nodiscard]] std::string get_hash() const noexcept;
4868
4869
  /**
4870
   * A URL includes credentials if its username or password is not the empty
4871
   * string.
4872
   */
4873
  [[nodiscard]] ada_really_inline bool has_credentials() const noexcept;
4874
4875
  /**
4876
   * Useful for implementing efficient serialization for the URL.
4877
   *
4878
   * https://user:pass@example.com:1234/foo/bar?baz#quux
4879
   *       |     |    |          | ^^^^|       |   |
4880
   *       |     |    |          | |   |       |   `----- hash_start
4881
   *       |     |    |          | |   |       `--------- search_start
4882
   *       |     |    |          | |   `----------------- pathname_start
4883
   *       |     |    |          | `--------------------- port
4884
   *       |     |    |          `----------------------- host_end
4885
   *       |     |    `---------------------------------- host_start
4886
   *       |     `--------------------------------------- username_end
4887
   *       `--------------------------------------------- protocol_end
4888
   *
4889
   * Inspired after servo/url
4890
   *
4891
   * @return a newly constructed component.
4892
   *
4893
   * @see
4894
   * https://github.com/servo/rust-url/blob/b65a45515c10713f6d212e6726719a020203cc98/url/src/quirks.rs#L31
4895
   */
4896
  [[nodiscard]] ada_really_inline ada::url_components get_components()
4897
      const noexcept;
4898
  /** @return true if the URL has a hash component */
4899
  [[nodiscard]] constexpr bool has_hash() const noexcept override;
4900
  /** @return true if the URL has a search component */
4901
  [[nodiscard]] constexpr bool has_search() const noexcept override;
4902
4903
 private:
4904
  friend ada::url ada::parser::parse_url<ada::url>(std::string_view,
4905
                                                   const ada::url *);
4906
  friend ada::url_aggregator ada::parser::parse_url<ada::url_aggregator>(
4907
      std::string_view, const ada::url_aggregator *);
4908
  friend void ada::helpers::strip_trailing_spaces_from_opaque_path<ada::url>(
4909
      ada::url &url) noexcept;
4910
4911
  friend ada::url ada::parser::parse_url_impl<ada::url, true>(std::string_view,
4912
                                                              const ada::url *);
4913
  friend ada::url_aggregator ada::parser::parse_url_impl<
4914
      ada::url_aggregator, true>(std::string_view, const ada::url_aggregator *);
4915
4916
  inline void update_unencoded_base_hash(std::string_view input);
4917
  inline void update_base_hostname(std::string_view input);
4918
  inline void update_base_search(std::string_view input,
4919
                                 const uint8_t query_percent_encode_set[]);
4920
  inline void update_base_search(std::optional<std::string> &&input);
4921
  inline void update_base_pathname(std::string_view input);
4922
  inline void update_base_username(std::string_view input);
4923
  inline void update_base_password(std::string_view input);
4924
  inline void update_base_port(std::optional<uint16_t> input);
4925
4926
  /**
4927
   * Sets the host or hostname according to override condition.
4928
   * Return true on success.
4929
   * @see https://url.spec.whatwg.org/#hostname-state
4930
   */
4931
  template <bool override_hostname = false>
4932
  bool set_host_or_hostname(std::string_view input);
4933
4934
  /**
4935
   * Return true on success.
4936
   * @see https://url.spec.whatwg.org/#concept-ipv4-parser
4937
   */
4938
  [[nodiscard]] bool parse_ipv4(std::string_view input);
4939
4940
  /**
4941
   * Return true on success.
4942
   * @see https://url.spec.whatwg.org/#concept-ipv6-parser
4943
   */
4944
  [[nodiscard]] bool parse_ipv6(std::string_view input);
4945
4946
  /**
4947
   * Return true on success.
4948
   * @see https://url.spec.whatwg.org/#concept-opaque-host-parser
4949
   */
4950
  [[nodiscard]] bool parse_opaque_host(std::string_view input);
4951
4952
  /**
4953
   * A URL's scheme is an ASCII string that identifies the type of URL and can
4954
   * be used to dispatch a URL for further processing after parsing. It is
4955
   * initially the empty string. We only set non_special_scheme when the scheme
4956
   * is non-special, otherwise we avoid constructing string.
4957
   *
4958
   * Special schemes are stored in ada::scheme::details::is_special_list so we
4959
   * typically do not need to store them in each url instance.
4960
   */
4961
  std::string non_special_scheme{};
4962
4963
  /**
4964
   * A URL cannot have a username/password/port if its host is null or the empty
4965
   * string, or its scheme is "file".
4966
   */
4967
  [[nodiscard]] inline bool cannot_have_credentials_or_port() const;
4968
4969
  ada_really_inline size_t parse_port(
4970
      std::string_view view, bool check_trailing_content) noexcept override;
4971
4972
1.50k
  ada_really_inline size_t parse_port(std::string_view view) noexcept override {
4973
1.50k
    return this->parse_port(view, false);
4974
1.50k
  }
4975
4976
  /**
4977
   * Parse the host from the provided input. We assume that
4978
   * the input does not contain spaces or tabs. Control
4979
   * characters and spaces are not trimmed (they should have
4980
   * been removed if needed).
4981
   * Return true on success.
4982
   * @see https://url.spec.whatwg.org/#host-parsing
4983
   */
4984
  [[nodiscard]] ada_really_inline bool parse_host(std::string_view input);
4985
4986
  template <bool has_state_override = false>
4987
  [[nodiscard]] ada_really_inline bool parse_scheme(std::string_view input);
4988
4989
  constexpr void clear_pathname() override;
4990
  constexpr void clear_search() override;
4991
  constexpr void set_protocol_as_file();
4992
4993
  /**
4994
   * Parse the path from the provided input.
4995
   * Return true on success. Control characters not
4996
   * trimmed from the ends (they should have
4997
   * been removed if needed).
4998
   *
4999
   * The input is expected to be UTF-8.
5000
   *
5001
   * @see https://url.spec.whatwg.org/
5002
   */
5003
  ada_really_inline void parse_path(std::string_view input);
5004
5005
  /**
5006
   * Set the scheme for this URL. The provided scheme should be a valid
5007
   * scheme string, be lower-cased, not contain spaces or tabs. It should
5008
   * have no spurious trailing or leading content.
5009
   */
5010
  inline void set_scheme(std::string &&new_scheme) noexcept;
5011
5012
  /**
5013
   * Take the scheme from another URL. The scheme string is moved from the
5014
   * provided url.
5015
   */
5016
  constexpr void copy_scheme(ada::url &&u) noexcept;
5017
5018
  /**
5019
   * Take the scheme from another URL. The scheme string is copied from the
5020
   * provided url.
5021
   */
5022
  constexpr void copy_scheme(const ada::url &u);
5023
5024
};  // struct url
5025
5026
inline std::ostream &operator<<(std::ostream &out, const ada::url &u);
5027
}  // namespace ada
5028
5029
#endif  // ADA_URL_H
5030
/* end file include/ada/url.h */
5031
5032
namespace ada {
5033
5034
template <class result_type = ada::url_aggregator>
5035
using result = tl::expected<result_type, ada::errors>;
5036
5037
/**
5038
 * The URL parser takes a scalar value string input, with an optional null or
5039
 * base URL base (default null). The parser assumes the input is a valid ASCII
5040
 * or UTF-8 string.
5041
 *
5042
 * @param input the string input to analyze (must be valid ASCII or UTF-8)
5043
 * @param base_url the optional URL input to use as a base url.
5044
 * @return a parsed URL.
5045
 */
5046
template <class result_type = ada::url_aggregator>
5047
ada_warn_unused ada::result<result_type> parse(
5048
    std::string_view input, const result_type* base_url = nullptr);
5049
5050
extern template ada::result<url> parse<url>(std::string_view input,
5051
                                            const url* base_url);
5052
extern template ada::result<url_aggregator> parse<url_aggregator>(
5053
    std::string_view input, const url_aggregator* base_url);
5054
5055
/**
5056
 * Verifies whether the URL strings can be parsed. The function assumes
5057
 * that the inputs are valid ASCII or UTF-8 strings.
5058
 * @see https://url.spec.whatwg.org/#dom-url-canparse
5059
 * @return If URL can be parsed or not.
5060
 */
5061
bool can_parse(std::string_view input,
5062
               const std::string_view* base_input = nullptr);
5063
5064
#if ADA_INCLUDE_URL_PATTERN
5065
/**
5066
 * Implementation of the URL pattern parsing algorithm.
5067
 * @see https://urlpattern.spec.whatwg.org
5068
 *
5069
 * @param input valid UTF-8 string or URLPatternInit struct
5070
 * @param base_url an optional valid UTF-8 string
5071
 * @param options an optional url_pattern_options struct
5072
 * @return url_pattern instance
5073
 */
5074
template <url_pattern_regex::regex_concept regex_provider>
5075
ada_warn_unused tl::expected<url_pattern<regex_provider>, errors>
5076
parse_url_pattern(std::variant<std::string_view, url_pattern_init>&& input,
5077
                  const std::string_view* base_url = nullptr,
5078
                  const url_pattern_options* options = nullptr);
5079
#endif  // ADA_INCLUDE_URL_PATTERN
5080
5081
/**
5082
 * Computes a href string from a file path. The function assumes
5083
 * that the input is a valid ASCII or UTF-8 string.
5084
 * @return a href string (starts with file:://)
5085
 */
5086
std::string href_from_file(std::string_view path);
5087
}  // namespace ada
5088
5089
#endif  // ADA_IMPLEMENTATION_H
5090
/* end file include/ada/implementation.h */
5091
5092
#include <ostream>
5093
#include <string>
5094
#include <string_view>
5095
#include <unordered_map>
5096
#include <variant>
5097
#include <vector>
5098
5099
#if ADA_TESTING
5100
#include <iostream>
5101
#endif  // ADA_TESTING
5102
5103
#if ADA_INCLUDE_URL_PATTERN
5104
namespace ada {
5105
5106
enum class url_pattern_part_type : uint8_t {
5107
  // The part represents a simple fixed text string.
5108
  FIXED_TEXT,
5109
  // The part represents a matching group with a custom regular expression.
5110
  REGEXP,
5111
  // The part represents a matching group that matches code points up to the
5112
  // next separator code point. This is typically used for a named group like
5113
  // ":foo" that does not have a custom regular expression.
5114
  SEGMENT_WILDCARD,
5115
  // The part represents a matching group that greedily matches all code points.
5116
  // This is typically used for the "*" wildcard matching group.
5117
  FULL_WILDCARD,
5118
};
5119
5120
enum class url_pattern_part_modifier : uint8_t {
5121
  // The part does not have a modifier.
5122
  none,
5123
  // The part has an optional modifier indicated by the U+003F (?) code point.
5124
  optional,
5125
  // The part has a "zero or more" modifier indicated by the U+002A (*) code
5126
  // point.
5127
  zero_or_more,
5128
  // The part has a "one or more" modifier indicated by the U+002B (+) code
5129
  // point.
5130
  one_or_more,
5131
};
5132
5133
// @see https://urlpattern.spec.whatwg.org/#part
5134
class url_pattern_part {
5135
 public:
5136
  url_pattern_part(url_pattern_part_type _type, std::string&& _value,
5137
                   url_pattern_part_modifier _modifier)
5138
1.77k
      : type(_type), value(std::move(_value)), modifier(_modifier) {}
5139
5140
  url_pattern_part(url_pattern_part_type _type, std::string&& _value,
5141
                   url_pattern_part_modifier _modifier, std::string&& _name,
5142
                   std::string&& _prefix, std::string&& _suffix)
5143
2.95k
      : type(_type),
5144
2.95k
        value(std::move(_value)),
5145
2.95k
        modifier(_modifier),
5146
2.95k
        name(std::move(_name)),
5147
2.95k
        prefix(std::move(_prefix)),
5148
2.95k
        suffix(std::move(_suffix)) {}
5149
  // A part has an associated type, a string, which must be set upon creation.
5150
  url_pattern_part_type type;
5151
  // A part has an associated value, a string, which must be set upon creation.
5152
  std::string value;
5153
  // A part has an associated modifier a string, which must be set upon
5154
  // creation.
5155
  url_pattern_part_modifier modifier;
5156
  // A part has an associated name, a string, initially the empty string.
5157
  std::string name{};
5158
  // A part has an associated prefix, a string, initially the empty string.
5159
  std::string prefix{};
5160
  // A part has an associated suffix, a string, initially the empty string.
5161
  std::string suffix{};
5162
5163
  inline bool is_regexp() const noexcept;
5164
};
5165
5166
// @see https://urlpattern.spec.whatwg.org/#options-header
5167
struct url_pattern_compile_component_options {
5168
  url_pattern_compile_component_options() = default;
5169
  explicit url_pattern_compile_component_options(
5170
      std::optional<char> new_delimiter = std::nullopt,
5171
      std::optional<char> new_prefix = std::nullopt)
5172
36
      : delimiter(new_delimiter), prefix(new_prefix) {}
5173
5174
  inline std::string_view get_delimiter() const ada_warn_unused;
5175
  inline std::string_view get_prefix() const ada_warn_unused;
5176
5177
  // @see https://urlpattern.spec.whatwg.org/#options-ignore-case
5178
  bool ignore_case = false;
5179
5180
  static url_pattern_compile_component_options DEFAULT;
5181
  static url_pattern_compile_component_options HOSTNAME;
5182
  static url_pattern_compile_component_options PATHNAME;
5183
5184
 private:
5185
  // @see https://urlpattern.spec.whatwg.org/#options-delimiter-code-point
5186
  std::optional<char> delimiter{};
5187
  // @see https://urlpattern.spec.whatwg.org/#options-prefix-code-point
5188
  std::optional<char> prefix{};
5189
};
5190
5191
// The default options is an options struct with delimiter code point set to
5192
// the empty string and prefix code point set to the empty string.
5193
inline url_pattern_compile_component_options
5194
    url_pattern_compile_component_options::DEFAULT(std::nullopt, std::nullopt);
5195
5196
// The hostname options is an options struct with delimiter code point set
5197
// "." and prefix code point set to the empty string.
5198
inline url_pattern_compile_component_options
5199
    url_pattern_compile_component_options::HOSTNAME('.', std::nullopt);
5200
5201
// The pathname options is an options struct with delimiter code point set
5202
// "/" and prefix code point set to "/".
5203
inline url_pattern_compile_component_options
5204
    url_pattern_compile_component_options::PATHNAME('/', '/');
5205
5206
// A struct providing the URLPattern matching results for a single
5207
// URL component. The URLPatternComponentResult is only ever used
5208
// as a member attribute of a URLPatternResult struct. The
5209
// URLPatternComponentResult API is defined as part of the URLPattern
5210
// specification.
5211
struct url_pattern_component_result {
5212
  std::string input;
5213
  std::unordered_map<std::string, std::optional<std::string>> groups;
5214
5215
  bool operator==(const url_pattern_component_result&) const;
5216
5217
#if ADA_TESTING
5218
  friend void PrintTo(const url_pattern_component_result& result,
5219
                      std::ostream* os) {
5220
    *os << "input: '" << result.input << "', group: ";
5221
    for (const auto& group : result.groups) {
5222
      *os << "(" << group.first << ", " << group.second.value_or("undefined")
5223
          << ") ";
5224
    }
5225
  }
5226
#endif  // ADA_TESTING
5227
};
5228
5229
template <url_pattern_regex::regex_concept regex_provider>
5230
class url_pattern_component {
5231
 public:
5232
4.72k
  url_pattern_component() = default;
5233
5234
  // This function explicitly takes a std::string because it is moved.
5235
  // To avoid unnecessary copy, move each value while calling the constructor.
5236
  url_pattern_component(std::string&& new_pattern,
5237
                        typename regex_provider::regex_type&& new_regexp,
5238
                        std::vector<std::string>&& new_group_name_list,
5239
                        bool new_has_regexp_groups)
5240
5.31k
      : regexp(std::move(new_regexp)),
5241
5.31k
        pattern(std::move(new_pattern)),
5242
5.31k
        group_name_list(std::move(new_group_name_list)),
5243
5.31k
        has_regexp_groups(new_has_regexp_groups) {}
5244
5245
  // @see https://urlpattern.spec.whatwg.org/#compile-a-component
5246
  template <url_pattern_encoding_callback F>
5247
  static tl::expected<url_pattern_component, errors> compile(
5248
      std::string_view input, F& encoding_callback,
5249
      url_pattern_compile_component_options& options);
5250
5251
  // @see https://urlpattern.spec.whatwg.org/#create-a-component-match-result
5252
  url_pattern_component_result create_component_match_result(
5253
      std::string&& input,
5254
      std::vector<std::optional<std::string>>&& exec_result);
5255
5256
#if ADA_TESTING
5257
  friend void PrintTo(const url_pattern_component& component,
5258
                      std::ostream* os) {
5259
    *os << "pattern: '" << component.pattern
5260
        << "', has_regexp_groups: " << component.has_regexp_groups
5261
        << "group_name_list: ";
5262
    for (const auto& name : component.group_name_list) {
5263
      *os << name << ", ";
5264
    }
5265
  }
5266
#endif  // ADA_TESTING
5267
5268
  typename regex_provider::regex_type regexp{};
5269
  std::string pattern{};
5270
  std::vector<std::string> group_name_list{};
5271
  bool has_regexp_groups = false;
5272
};
5273
5274
// A URLPattern input can be either a string or a URLPatternInit object.
5275
// If it is a string, it must be a valid UTF-8 string.
5276
using url_pattern_input = std::variant<std::string_view, url_pattern_init>;
5277
5278
// A struct providing the URLPattern matching results for all
5279
// components of a URL. The URLPatternResult API is defined as
5280
// part of the URLPattern specification.
5281
struct url_pattern_result {
5282
  std::vector<url_pattern_input> inputs;
5283
  url_pattern_component_result protocol;
5284
  url_pattern_component_result username;
5285
  url_pattern_component_result password;
5286
  url_pattern_component_result hostname;
5287
  url_pattern_component_result port;
5288
  url_pattern_component_result pathname;
5289
  url_pattern_component_result search;
5290
  url_pattern_component_result hash;
5291
};
5292
5293
struct url_pattern_options {
5294
  bool ignore_case = false;
5295
5296
#if ADA_TESTING
5297
  friend void PrintTo(const url_pattern_options& options, std::ostream* os) {
5298
    *os << "ignore_case: '" << options.ignore_case;
5299
  }
5300
#endif  // ADA_TESTING
5301
};
5302
5303
// URLPattern is a Web Platform standard API for matching URLs against a
5304
// pattern syntax (think of it as a regular expression for URLs). It is
5305
// defined in https://wicg.github.io/urlpattern.
5306
// More information about the URL Pattern syntax can be found at
5307
// https://developer.mozilla.org/en-US/docs/Web/API/URL_Pattern_API
5308
//
5309
// We require all strings to be valid UTF-8: it is the user's responsibility
5310
// to ensure that the provided strings are valid UTF-8.
5311
template <url_pattern_regex::regex_concept regex_provider>
5312
class url_pattern {
5313
 public:
5314
591
  url_pattern() = default;
5315
5316
  /**
5317
   * If non-null, base_url must pointer at a valid UTF-8 string.
5318
   * @see https://urlpattern.spec.whatwg.org/#dom-urlpattern-exec
5319
   */
5320
  result<std::optional<url_pattern_result>> exec(
5321
      const url_pattern_input& input,
5322
      const std::string_view* base_url = nullptr);
5323
5324
  /**
5325
   * If non-null, base_url must pointer at a valid UTF-8 string.
5326
   * @see https://urlpattern.spec.whatwg.org/#dom-urlpattern-test
5327
   */
5328
  result<bool> test(const url_pattern_input& input,
5329
                    const std::string_view* base_url = nullptr);
5330
5331
  /**
5332
   * @see https://urlpattern.spec.whatwg.org/#url-pattern-match
5333
   * This function expects a valid UTF-8 string if input is a string.
5334
   */
5335
  result<std::optional<url_pattern_result>> match(
5336
      const url_pattern_input& input,
5337
      const std::string_view* base_url_string = nullptr);
5338
5339
  // @see https://urlpattern.spec.whatwg.org/#dom-urlpattern-protocol
5340
  [[nodiscard]] std::string_view get_protocol() const ada_lifetime_bound;
5341
  // @see https://urlpattern.spec.whatwg.org/#dom-urlpattern-username
5342
  [[nodiscard]] std::string_view get_username() const ada_lifetime_bound;
5343
  // @see https://urlpattern.spec.whatwg.org/#dom-urlpattern-password
5344
  [[nodiscard]] std::string_view get_password() const ada_lifetime_bound;
5345
  // @see https://urlpattern.spec.whatwg.org/#dom-urlpattern-hostname
5346
  [[nodiscard]] std::string_view get_hostname() const ada_lifetime_bound;
5347
  // @see https://urlpattern.spec.whatwg.org/#dom-urlpattern-port
5348
  [[nodiscard]] std::string_view get_port() const ada_lifetime_bound;
5349
  // @see https://urlpattern.spec.whatwg.org/#dom-urlpattern-pathname
5350
  [[nodiscard]] std::string_view get_pathname() const ada_lifetime_bound;
5351
  // @see https://urlpattern.spec.whatwg.org/#dom-urlpattern-search
5352
  [[nodiscard]] std::string_view get_search() const ada_lifetime_bound;
5353
  // @see https://urlpattern.spec.whatwg.org/#dom-urlpattern-hash
5354
  [[nodiscard]] std::string_view get_hash() const ada_lifetime_bound;
5355
5356
  // If ignoreCase is true, the JavaScript regular expression created for each
5357
  // pattern must use the `vi` flag. Otherwise, they must use the `v` flag.
5358
  [[nodiscard]] bool ignore_case() const;
5359
5360
  // @see https://urlpattern.spec.whatwg.org/#url-pattern-has-regexp-groups
5361
  [[nodiscard]] bool has_regexp_groups() const;
5362
5363
#if ADA_TESTING
5364
  friend void PrintTo(const url_pattern& c, std::ostream* os) {
5365
    *os << "protocol_component: '" << c.get_protocol() << ", ";
5366
    *os << "username_component: '" << c.get_username() << ", ";
5367
    *os << "password_component: '" << c.get_password() << ", ";
5368
    *os << "hostname_component: '" << c.get_hostname() << ", ";
5369
    *os << "port_component: '" << c.get_port() << ", ";
5370
    *os << "pathname_component: '" << c.get_pathname() << ", ";
5371
    *os << "search_component: '" << c.get_search() << ", ";
5372
    *os << "hash_component: '" << c.get_hash();
5373
  }
5374
#endif  // ADA_TESTING
5375
5376
  template <url_pattern_regex::regex_concept P>
5377
  friend tl::expected<url_pattern<P>, errors> parser::parse_url_pattern_impl(
5378
      std::variant<std::string_view, url_pattern_init>&& input,
5379
      const std::string_view* base_url, const url_pattern_options* options);
5380
5381
  /**
5382
   * @private
5383
   * We can not make this private due to a LLVM bug.
5384
   * Ref: https://github.com/ada-url/ada/pull/859
5385
   */
5386
  url_pattern_component<regex_provider> protocol_component{};
5387
  /**
5388
   * @private
5389
   * We can not make this private due to a LLVM bug.
5390
   * Ref: https://github.com/ada-url/ada/pull/859
5391
   */
5392
  url_pattern_component<regex_provider> username_component{};
5393
  /**
5394
   * @private
5395
   * We can not make this private due to a LLVM bug.
5396
   * Ref: https://github.com/ada-url/ada/pull/859
5397
   */
5398
  url_pattern_component<regex_provider> password_component{};
5399
  /**
5400
   * @private
5401
   * We can not make this private due to a LLVM bug.
5402
   * Ref: https://github.com/ada-url/ada/pull/859
5403
   */
5404
  url_pattern_component<regex_provider> hostname_component{};
5405
  /**
5406
   * @private
5407
   * We can not make this private due to a LLVM bug.
5408
   * Ref: https://github.com/ada-url/ada/pull/859
5409
   */
5410
  url_pattern_component<regex_provider> port_component{};
5411
  /**
5412
   * @private
5413
   * We can not make this private due to a LLVM bug.
5414
   * Ref: https://github.com/ada-url/ada/pull/859
5415
   */
5416
  url_pattern_component<regex_provider> pathname_component{};
5417
  /**
5418
   * @private
5419
   * We can not make this private due to a LLVM bug.
5420
   * Ref: https://github.com/ada-url/ada/pull/859
5421
   */
5422
  url_pattern_component<regex_provider> search_component{};
5423
  /**
5424
   * @private
5425
   * We can not make this private due to a LLVM bug.
5426
   * Ref: https://github.com/ada-url/ada/pull/859
5427
   */
5428
  url_pattern_component<regex_provider> hash_component{};
5429
  /**
5430
   * @private
5431
   * We can not make this private due to a LLVM bug.
5432
   * Ref: https://github.com/ada-url/ada/pull/859
5433
   */
5434
  bool ignore_case_ = false;
5435
};
5436
}  // namespace ada
5437
#endif  // ADA_INCLUDE_URL_PATTERN
5438
#endif
5439
/* end file include/ada/url_pattern.h */
5440
/* begin file include/ada/url_pattern_helpers.h */
5441
/**
5442
 * @file url_pattern_helpers.h
5443
 * @brief Declaration for the URLPattern helpers.
5444
 */
5445
#ifndef ADA_URL_PATTERN_HELPERS_H
5446
#define ADA_URL_PATTERN_HELPERS_H
5447
5448
5449
#include <string>
5450
#include <tuple>
5451
#include <vector>
5452
5453
#if ADA_INCLUDE_URL_PATTERN
5454
namespace ada {
5455
enum class errors : uint8_t;
5456
}
5457
5458
namespace ada::url_pattern_helpers {
5459
5460
// @see https://urlpattern.spec.whatwg.org/#token
5461
enum class token_type : uint8_t {
5462
  INVALID_CHAR,    // 0
5463
  OPEN,            // 1
5464
  CLOSE,           // 2
5465
  REGEXP,          // 3
5466
  NAME,            // 4
5467
  CHAR,            // 5
5468
  ESCAPED_CHAR,    // 6
5469
  OTHER_MODIFIER,  // 7
5470
  ASTERISK,        // 8
5471
  END,             // 9
5472
};
5473
5474
#ifdef ADA_TESTING
5475
std::string to_string(token_type type);
5476
#endif  // ADA_TESTING
5477
5478
// @see https://urlpattern.spec.whatwg.org/#tokenize-policy
5479
enum class token_policy {
5480
  strict,
5481
  lenient,
5482
};
5483
5484
// @see https://urlpattern.spec.whatwg.org/#tokens
5485
class token {
5486
 public:
5487
  token(token_type _type, size_t _index, std::string&& _value)
5488
48.1k
      : type(_type), index(_index), value(std::move(_value)) {}
5489
5490
  // A token has an associated type, a string, initially "invalid-char".
5491
  token_type type = token_type::INVALID_CHAR;
5492
5493
  // A token has an associated index, a number, initially 0. It is the position
5494
  // of the first code point in the pattern string represented by the token.
5495
  size_t index = 0;
5496
5497
  // A token has an associated value, a string, initially the empty string. It
5498
  // contains the code points from the pattern string represented by the token.
5499
  std::string value{};
5500
};
5501
5502
// @see https://urlpattern.spec.whatwg.org/#pattern-parser
5503
template <url_pattern_encoding_callback F>
5504
class url_pattern_parser {
5505
 public:
5506
  url_pattern_parser(F& encoding_callback_,
5507
                     std::string_view segment_wildcard_regexp_)
5508
5.31k
      : encoding_callback(encoding_callback_),
5509
5.31k
        segment_wildcard_regexp(segment_wildcard_regexp_) {}
5510
5511
26.0k
  bool can_continue() const { return index < tokens.size(); }
5512
5513
  // @see https://urlpattern.spec.whatwg.org/#try-to-consume-a-token
5514
  token* try_consume_token(token_type type);
5515
  // @see https://urlpattern.spec.whatwg.org/#try-to-consume-a-modifier-token
5516
  token* try_consume_modifier_token();
5517
  // @see
5518
  // https://urlpattern.spec.whatwg.org/#try-to-consume-a-regexp-or-wildcard-token
5519
  token* try_consume_regexp_or_wildcard_token(const token* name_token);
5520
  // @see https://urlpattern.spec.whatwg.org/#consume-text
5521
  std::string consume_text();
5522
  // @see https://urlpattern.spec.whatwg.org/#consume-a-required-token
5523
  bool consume_required_token(token_type type);
5524
  // @see
5525
  // https://urlpattern.spec.whatwg.org/#maybe-add-a-part-from-the-pending-fixed-value
5526
  std::optional<errors> maybe_add_part_from_the_pending_fixed_value()
5527
      ada_warn_unused;
5528
  // @see https://urlpattern.spec.whatwg.org/#add-a-part
5529
  std::optional<errors> add_part(std::string_view prefix, token* name_token,
5530
                                 token* regexp_or_wildcard_token,
5531
                                 std::string_view suyffix,
5532
                                 token* modifier_token) ada_warn_unused;
5533
5534
  std::vector<token> tokens{};
5535
  F& encoding_callback;
5536
  std::string segment_wildcard_regexp;
5537
  std::vector<url_pattern_part> parts{};
5538
  std::string pending_fixed_value{};
5539
  size_t index = 0;
5540
  size_t next_numeric_name = 0;
5541
};
5542
5543
// @see https://urlpattern.spec.whatwg.org/#tokenizer
5544
class Tokenizer {
5545
 public:
5546
  explicit Tokenizer(std::string_view new_input, token_policy new_policy)
5547
6.50k
      : input(new_input), policy(new_policy) {}
5548
5549
  // @see https://urlpattern.spec.whatwg.org/#get-the-next-code-point
5550
  constexpr void get_next_code_point();
5551
5552
  // @see https://urlpattern.spec.whatwg.org/#seek-and-get-the-next-code-point
5553
  constexpr void seek_and_get_next_code_point(size_t index);
5554
5555
  // @see https://urlpattern.spec.whatwg.org/#add-a-token
5556
5557
  void add_token(token_type type, size_t next_position, size_t value_position,
5558
                 size_t value_length);
5559
5560
  // @see https://urlpattern.spec.whatwg.org/#add-a-token-with-default-length
5561
  void add_token_with_default_length(token_type type, size_t next_position,
5562
                                     size_t value_position);
5563
5564
  // @see
5565
  // https://urlpattern.spec.whatwg.org/#add-a-token-with-default-position-and-length
5566
  void add_token_with_defaults(token_type type);
5567
5568
  // @see https://urlpattern.spec.whatwg.org/#process-a-tokenizing-error
5569
  std::optional<errors> process_tokenizing_error(
5570
      size_t next_position, size_t value_position) ada_warn_unused;
5571
5572
  friend tl::expected<std::vector<token>, errors> tokenize(
5573
      std::string_view input, token_policy policy);
5574
5575
 private:
5576
  // has an associated input, a pattern string, initially the empty string.
5577
  std::string input;
5578
  // has an associated policy, a tokenize policy, initially "strict".
5579
  token_policy policy;
5580
  // has an associated token list, a token list, initially an empty list.
5581
  std::vector<token> token_list{};
5582
  // has an associated index, a number, initially 0.
5583
  size_t index = 0;
5584
  // has an associated next index, a number, initially 0.
5585
  size_t next_index = 0;
5586
  // has an associated code point, a Unicode code point, initially null.
5587
  char32_t code_point{};
5588
};
5589
5590
// @see https://urlpattern.spec.whatwg.org/#constructor-string-parser
5591
template <url_pattern_regex::regex_concept regex_provider>
5592
struct constructor_string_parser {
5593
  explicit constructor_string_parser(std::string_view new_input,
5594
                                     std::vector<token>&& new_token_list)
5595
1.18k
      : input(new_input), token_list(std::move(new_token_list)) {}
5596
  // @see https://urlpattern.spec.whatwg.org/#parse-a-constructor-string
5597
  static tl::expected<url_pattern_init, errors> parse(std::string_view input);
5598
5599
  // @see https://urlpattern.spec.whatwg.org/#constructor-string-parser-state
5600
  enum class State {
5601
    INIT,
5602
    PROTOCOL,
5603
    AUTHORITY,
5604
    USERNAME,
5605
    PASSWORD,
5606
    HOSTNAME,
5607
    PORT,
5608
    PATHNAME,
5609
    SEARCH,
5610
    HASH,
5611
    DONE,
5612
  };
5613
5614
  // @see
5615
  // https://urlpattern.spec.whatwg.org/#compute-protocol-matches-a-special-scheme-flag
5616
  std::optional<errors> compute_protocol_matches_special_scheme_flag();
5617
5618
 private:
5619
  // @see https://urlpattern.spec.whatwg.org/#rewind
5620
  constexpr void rewind();
5621
5622
  // @see https://urlpattern.spec.whatwg.org/#is-a-hash-prefix
5623
  constexpr bool is_hash_prefix();
5624
5625
  // @see https://urlpattern.spec.whatwg.org/#is-a-search-prefix
5626
  constexpr bool is_search_prefix();
5627
5628
  // @see https://urlpattern.spec.whatwg.org/#change-state
5629
  void change_state(State state, size_t skip);
5630
5631
  // @see https://urlpattern.spec.whatwg.org/#is-a-group-open
5632
  constexpr bool is_group_open() const;
5633
5634
  // @see https://urlpattern.spec.whatwg.org/#is-a-group-close
5635
  constexpr bool is_group_close() const;
5636
5637
  // @see https://urlpattern.spec.whatwg.org/#is-a-protocol-suffix
5638
  constexpr bool is_protocol_suffix() const;
5639
5640
  // @see https://urlpattern.spec.whatwg.org/#next-is-authority-slashes
5641
  constexpr bool next_is_authority_slashes() const;
5642
5643
  // @see https://urlpattern.spec.whatwg.org/#is-an-identity-terminator
5644
  constexpr bool is_an_identity_terminator() const;
5645
5646
  // @see https://urlpattern.spec.whatwg.org/#is-a-pathname-start
5647
  constexpr bool is_pathname_start() const;
5648
5649
  // @see https://urlpattern.spec.whatwg.org/#is-a-password-prefix
5650
  constexpr bool is_password_prefix() const;
5651
5652
  // @see https://urlpattern.spec.whatwg.org/#is-an-ipv6-open
5653
  constexpr bool is_an_ipv6_open() const;
5654
5655
  // @see https://urlpattern.spec.whatwg.org/#is-an-ipv6-close
5656
  constexpr bool is_an_ipv6_close() const;
5657
5658
  // @see https://urlpattern.spec.whatwg.org/#is-a-port-prefix
5659
  constexpr bool is_port_prefix() const;
5660
5661
  // @see https://urlpattern.spec.whatwg.org/#is-a-non-special-pattern-char
5662
  constexpr bool is_non_special_pattern_char(size_t index,
5663
                                             uint32_t value) const;
5664
5665
  // @see https://urlpattern.spec.whatwg.org/#get-a-safe-token
5666
  constexpr const token* get_safe_token(size_t index) const;
5667
5668
  // @see https://urlpattern.spec.whatwg.org/#make-a-component-string
5669
  std::string make_component_string();
5670
  // has an associated input, a string, which must be set upon creation.
5671
  std::string input;
5672
  // has an associated token list, a token list, which must be set upon
5673
  // creation.
5674
  std::vector<token> token_list;
5675
  // has an associated result, a URLPatternInit, initially set to a new
5676
  // URLPatternInit.
5677
  url_pattern_init result{};
5678
  // has an associated component start, a number, initially set to 0.
5679
  size_t component_start = 0;
5680
  // has an associated token index, a number, initially set to 0.
5681
  size_t token_index = 0;
5682
  // has an associated token increment, a number, initially set to 1.
5683
  size_t token_increment = 1;
5684
  // has an associated group depth, a number, initially set to 0.
5685
  size_t group_depth = 0;
5686
  // has an associated hostname IPv6 bracket depth, a number, initially set to
5687
  // 0.
5688
  size_t hostname_ipv6_bracket_depth = 0;
5689
  // has an associated protocol matches a special scheme flag, a boolean,
5690
  // initially set to false.
5691
  bool protocol_matches_a_special_scheme_flag = false;
5692
  // has an associated state, a string, initially set to "init".
5693
  State state = State::INIT;
5694
};
5695
5696
// @see https://urlpattern.spec.whatwg.org/#canonicalize-a-protocol
5697
tl::expected<std::string, errors> canonicalize_protocol(std::string_view input);
5698
5699
// @see https://wicg.github.io/urlpattern/#canonicalize-a-username
5700
tl::expected<std::string, errors> canonicalize_username(std::string_view input);
5701
5702
// @see https://wicg.github.io/urlpattern/#canonicalize-a-password
5703
tl::expected<std::string, errors> canonicalize_password(std::string_view input);
5704
5705
// @see https://wicg.github.io/urlpattern/#canonicalize-a-password
5706
tl::expected<std::string, errors> canonicalize_hostname(std::string_view input);
5707
5708
// @see https://wicg.github.io/urlpattern/#canonicalize-an-ipv6-hostname
5709
tl::expected<std::string, errors> canonicalize_ipv6_hostname(
5710
    std::string_view input);
5711
5712
// @see https://wicg.github.io/urlpattern/#canonicalize-a-port
5713
tl::expected<std::string, errors> canonicalize_port(std::string_view input);
5714
5715
// @see https://wicg.github.io/urlpattern/#canonicalize-a-port
5716
tl::expected<std::string, errors> canonicalize_port_with_protocol(
5717
    std::string_view input, std::string_view protocol);
5718
5719
// @see https://wicg.github.io/urlpattern/#canonicalize-a-pathname
5720
tl::expected<std::string, errors> canonicalize_pathname(std::string_view input);
5721
5722
// @see https://wicg.github.io/urlpattern/#canonicalize-an-opaque-pathname
5723
tl::expected<std::string, errors> canonicalize_opaque_pathname(
5724
    std::string_view input);
5725
5726
// @see https://wicg.github.io/urlpattern/#canonicalize-a-search
5727
tl::expected<std::string, errors> canonicalize_search(std::string_view input);
5728
5729
// @see https://wicg.github.io/urlpattern/#canonicalize-a-hash
5730
tl::expected<std::string, errors> canonicalize_hash(std::string_view input);
5731
5732
// @see https://urlpattern.spec.whatwg.org/#tokenize
5733
tl::expected<std::vector<token>, errors> tokenize(std::string_view input,
5734
                                                  token_policy policy);
5735
5736
// @see https://urlpattern.spec.whatwg.org/#process-a-base-url-string
5737
std::string process_base_url_string(std::string_view input,
5738
                                    url_pattern_init::process_type type);
5739
5740
// @see https://urlpattern.spec.whatwg.org/#escape-a-pattern-string
5741
std::string escape_pattern_string(std::string_view input);
5742
5743
// @see https://urlpattern.spec.whatwg.org/#escape-a-regexp-string
5744
std::string escape_regexp_string(std::string_view input);
5745
5746
// @see https://urlpattern.spec.whatwg.org/#is-an-absolute-pathname
5747
constexpr bool is_absolute_pathname(
5748
    std::string_view input, url_pattern_init::process_type type) noexcept;
5749
5750
// @see https://urlpattern.spec.whatwg.org/#parse-a-pattern-string
5751
template <url_pattern_encoding_callback F>
5752
tl::expected<std::vector<url_pattern_part>, errors> parse_pattern_string(
5753
    std::string_view input, url_pattern_compile_component_options& options,
5754
    F& encoding_callback);
5755
5756
// @see https://urlpattern.spec.whatwg.org/#generate-a-pattern-string
5757
std::string generate_pattern_string(
5758
    std::vector<url_pattern_part>& part_list,
5759
    url_pattern_compile_component_options& options);
5760
5761
// @see
5762
// https://urlpattern.spec.whatwg.org/#generate-a-regular-expression-and-name-list
5763
std::tuple<std::string, std::vector<std::string>>
5764
generate_regular_expression_and_name_list(
5765
    const std::vector<url_pattern_part>& part_list,
5766
    url_pattern_compile_component_options options);
5767
5768
// @see https://urlpattern.spec.whatwg.org/#hostname-pattern-is-an-ipv6-address
5769
bool is_ipv6_address(std::string_view input) noexcept;
5770
5771
// @see
5772
// https://urlpattern.spec.whatwg.org/#protocol-component-matches-a-special-scheme
5773
template <url_pattern_regex::regex_concept regex_provider>
5774
bool protocol_component_matches_special_scheme(
5775
    ada::url_pattern_component<regex_provider>& input);
5776
5777
// @see https://urlpattern.spec.whatwg.org/#convert-a-modifier-to-a-string
5778
std::string convert_modifier_to_string(url_pattern_part_modifier modifier);
5779
5780
// @see https://urlpattern.spec.whatwg.org/#generate-a-segment-wildcard-regexp
5781
std::string generate_segment_wildcard_regexp(
5782
    url_pattern_compile_component_options options);
5783
5784
}  // namespace ada::url_pattern_helpers
5785
#endif  // ADA_INCLUDE_URL_PATTERN
5786
#endif
5787
/* end file include/ada/url_pattern_helpers.h */
5788
5789
#include <string>
5790
#include <string_view>
5791
#include <variant>
5792
5793
namespace ada::parser {
5794
#if ADA_INCLUDE_URL_PATTERN
5795
template <url_pattern_regex::regex_concept regex_provider>
5796
tl::expected<url_pattern<regex_provider>, errors> parse_url_pattern_impl(
5797
    std::variant<std::string_view, url_pattern_init>&& input,
5798
1.57k
    const std::string_view* base_url, const url_pattern_options* options) {
5799
  // Let init be null.
5800
1.57k
  url_pattern_init init;
5801
5802
  // If input is a scalar value string then:
5803
1.57k
  if (std::holds_alternative<std::string_view>(input)) {
5804
    // Set init to the result of running parse a constructor string given input.
5805
1.18k
    auto parse_result =
5806
1.18k
        url_pattern_helpers::constructor_string_parser<regex_provider>::parse(
5807
1.18k
            std::get<std::string_view>(input));
5808
1.18k
    if (!parse_result) {
5809
0
      ada_log("constructor_string_parser::parse failed");
5810
0
      return tl::unexpected(parse_result.error());
5811
0
    }
5812
1.18k
    init = std::move(*parse_result);
5813
    // If baseURL is null and init["protocol"] does not exist, then throw a
5814
    // TypeError.
5815
1.18k
    if (!base_url && !init.protocol) {
5816
197
      ada_log("base url is null and protocol is not set");
5817
197
      return tl::unexpected(errors::type_error);
5818
197
    }
5819
5820
    // If baseURL is not null, set init["baseURL"] to baseURL.
5821
985
    if (base_url) {
5822
788
      init.base_url = std::string(*base_url);
5823
788
    }
5824
985
  } else {
5825
    // Assert: input is a URLPatternInit.
5826
394
    ADA_ASSERT_TRUE(std::holds_alternative<url_pattern_init>(input));
5827
    // If baseURL is not null, then throw a TypeError.
5828
394
    if (base_url) {
5829
394
      ada_log("base url is not null");
5830
394
      return tl::unexpected(errors::type_error);
5831
394
    }
5832
    // Optimization: Avoid copy by moving the input value.
5833
    // Set init to input.
5834
0
    init = std::move(std::get<url_pattern_init>(input));
5835
0
  }
5836
5837
  // Let processedInit be the result of process a URLPatternInit given init,
5838
  // "pattern", null, null, null, null, null, null, null, and null.
5839
985
  auto processed_init =
5840
985
      url_pattern_init::process(init, url_pattern_init::process_type::pattern);
5841
985
  if (!processed_init) {
5842
394
    ada_log("url_pattern_init::process failed for init and 'pattern'");
5843
394
    return tl::unexpected(processed_init.error());
5844
394
  }
5845
5846
  // For each componentName of  "protocol", "username", "password", "hostname",
5847
  // "port", "pathname", "search", "hash" If processedInit[componentName] does
5848
  // not exist, then set processedInit[componentName] to "*".
5849
591
  ADA_ASSERT_TRUE(processed_init.has_value());
5850
591
  if (!processed_init->protocol) processed_init->protocol = "*";
5851
591
  if (!processed_init->username) processed_init->username = "*";
5852
591
  if (!processed_init->password) processed_init->password = "*";
5853
591
  if (!processed_init->hostname) processed_init->hostname = "*";
5854
591
  if (!processed_init->port) processed_init->port = "*";
5855
591
  if (!processed_init->pathname) processed_init->pathname = "*";
5856
591
  if (!processed_init->search) processed_init->search = "*";
5857
591
  if (!processed_init->hash) processed_init->hash = "*";
5858
5859
591
  ada_log("-- processed_init->protocol: ", processed_init->protocol.value());
5860
591
  ada_log("-- processed_init->username: ", processed_init->username.value());
5861
591
  ada_log("-- processed_init->password: ", processed_init->password.value());
5862
591
  ada_log("-- processed_init->hostname: ", processed_init->hostname.value());
5863
591
  ada_log("-- processed_init->port: ", processed_init->port.value());
5864
591
  ada_log("-- processed_init->pathname: ", processed_init->pathname.value());
5865
591
  ada_log("-- processed_init->search: ", processed_init->search.value());
5866
591
  ada_log("-- processed_init->hash: ", processed_init->hash.value());
5867
5868
  // If processedInit["protocol"] is a special scheme and processedInit["port"]
5869
  // is a string which represents its corresponding default port in radix-10
5870
  // using ASCII digits then set processedInit["port"] to the empty string.
5871
  // TODO: Optimization opportunity.
5872
591
  if (scheme::is_special(*processed_init->protocol)) {
5873
591
    std::string_view port = processed_init->port.value();
5874
591
    if (std::to_string(scheme::get_special_port(*processed_init->protocol)) ==
5875
591
        port) {
5876
0
      processed_init->port->clear();
5877
0
    }
5878
591
  }
5879
5880
  // Let urlPattern be a new URL pattern.
5881
591
  url_pattern<regex_provider> url_pattern_{};
5882
5883
  // Set urlPattern's protocol component to the result of compiling a component
5884
  // given processedInit["protocol"], canonicalize a protocol, and default
5885
  // options.
5886
591
  auto protocol_component = url_pattern_component<regex_provider>::compile(
5887
591
      processed_init->protocol.value(),
5888
591
      url_pattern_helpers::canonicalize_protocol,
5889
591
      url_pattern_compile_component_options::DEFAULT);
5890
591
  if (!protocol_component) {
5891
0
    ada_log("url_pattern_component::compile failed for protocol ",
5892
0
            processed_init->protocol.value());
5893
0
    return tl::unexpected(protocol_component.error());
5894
0
  }
5895
591
  url_pattern_.protocol_component = std::move(*protocol_component);
5896
5897
  // Set urlPattern's username component to the result of compiling a component
5898
  // given processedInit["username"], canonicalize a username, and default
5899
  // options.
5900
591
  auto username_component = url_pattern_component<regex_provider>::compile(
5901
591
      processed_init->username.value(),
5902
591
      url_pattern_helpers::canonicalize_username,
5903
591
      url_pattern_compile_component_options::DEFAULT);
5904
591
  if (!username_component) {
5905
0
    ada_log("url_pattern_component::compile failed for username ",
5906
0
            processed_init->username.value());
5907
0
    return tl::unexpected(username_component.error());
5908
0
  }
5909
591
  url_pattern_.username_component = std::move(*username_component);
5910
5911
  // Set urlPattern's password component to the result of compiling a component
5912
  // given processedInit["password"], canonicalize a password, and default
5913
  // options.
5914
591
  auto password_component = url_pattern_component<regex_provider>::compile(
5915
591
      processed_init->password.value(),
5916
591
      url_pattern_helpers::canonicalize_password,
5917
591
      url_pattern_compile_component_options::DEFAULT);
5918
591
  if (!password_component) {
5919
0
    ada_log("url_pattern_component::compile failed for password ",
5920
0
            processed_init->password.value());
5921
0
    return tl::unexpected(password_component.error());
5922
0
  }
5923
591
  url_pattern_.password_component = std::move(*password_component);
5924
5925
  // TODO: Optimization opportunity. The following if statement can be
5926
  // simplified.
5927
  // If the result running hostname pattern is an IPv6 address given
5928
  // processedInit["hostname"] is true, then set urlPattern's hostname component
5929
  // to the result of compiling a component given processedInit["hostname"],
5930
  // canonicalize an IPv6 hostname, and hostname options.
5931
591
  if (url_pattern_helpers::is_ipv6_address(processed_init->hostname.value())) {
5932
0
    ada_log("processed_init->hostname is ipv6 address");
5933
    // then set urlPattern's hostname component to the result of compiling a
5934
    // component given processedInit["hostname"], canonicalize an IPv6 hostname,
5935
    // and hostname options.
5936
0
    auto hostname_component = url_pattern_component<regex_provider>::compile(
5937
0
        processed_init->hostname.value(),
5938
0
        url_pattern_helpers::canonicalize_ipv6_hostname,
5939
0
        url_pattern_compile_component_options::DEFAULT);
5940
0
    if (!hostname_component) {
5941
0
      ada_log("url_pattern_component::compile failed for ipv6 hostname ",
5942
0
              processed_init->hostname.value());
5943
0
      return tl::unexpected(hostname_component.error());
5944
0
    }
5945
0
    url_pattern_.hostname_component = std::move(*hostname_component);
5946
591
  } else {
5947
    // Otherwise, set urlPattern's hostname component to the result of compiling
5948
    // a component given processedInit["hostname"], canonicalize a hostname, and
5949
    // hostname options.
5950
591
    auto hostname_component = url_pattern_component<regex_provider>::compile(
5951
591
        processed_init->hostname.value(),
5952
591
        url_pattern_helpers::canonicalize_hostname,
5953
591
        url_pattern_compile_component_options::HOSTNAME);
5954
591
    if (!hostname_component) {
5955
0
      ada_log("url_pattern_component::compile failed for hostname ",
5956
0
              processed_init->hostname.value());
5957
0
      return tl::unexpected(hostname_component.error());
5958
0
    }
5959
591
    url_pattern_.hostname_component = std::move(*hostname_component);
5960
591
  }
5961
5962
  // Set urlPattern's port component to the result of compiling a component
5963
  // given processedInit["port"], canonicalize a port, and default options.
5964
591
  auto port_component = url_pattern_component<regex_provider>::compile(
5965
591
      processed_init->port.value(), url_pattern_helpers::canonicalize_port,
5966
591
      url_pattern_compile_component_options::DEFAULT);
5967
591
  if (!port_component) {
5968
0
    ada_log("url_pattern_component::compile failed for port ",
5969
0
            processed_init->port.value());
5970
0
    return tl::unexpected(port_component.error());
5971
0
  }
5972
591
  url_pattern_.port_component = std::move(*port_component);
5973
5974
  // Let compileOptions be a copy of the default options with the ignore case
5975
  // property set to options["ignoreCase"].
5976
591
  auto compile_options = url_pattern_compile_component_options::DEFAULT;
5977
591
  if (options) {
5978
197
    compile_options.ignore_case = options->ignore_case;
5979
197
  }
5980
5981
  // TODO: Optimization opportunity: Simplify this if statement.
5982
  // If the result of running protocol component matches a special scheme given
5983
  // urlPattern's protocol component is true, then:
5984
591
  if (url_pattern_helpers::protocol_component_matches_special_scheme<
5985
591
          regex_provider>(url_pattern_.protocol_component)) {
5986
    // Let pathCompileOptions be copy of the pathname options with the ignore
5987
    // case property set to options["ignoreCase"].
5988
591
    auto path_compile_options = url_pattern_compile_component_options::PATHNAME;
5989
591
    if (options) {
5990
197
      path_compile_options.ignore_case = options->ignore_case;
5991
197
    }
5992
5993
    // Set urlPattern's pathname component to the result of compiling a
5994
    // component given processedInit["pathname"], canonicalize a pathname, and
5995
    // pathCompileOptions.
5996
591
    auto pathname_component = url_pattern_component<regex_provider>::compile(
5997
591
        processed_init->pathname.value(),
5998
591
        url_pattern_helpers::canonicalize_pathname, path_compile_options);
5999
591
    if (!pathname_component) {
6000
0
      ada_log("url_pattern_component::compile failed for pathname ",
6001
0
              processed_init->pathname.value());
6002
0
      return tl::unexpected(pathname_component.error());
6003
0
    }
6004
591
    url_pattern_.pathname_component = std::move(*pathname_component);
6005
591
  } else {
6006
    // Otherwise set urlPattern's pathname component to the result of compiling
6007
    // a component given processedInit["pathname"], canonicalize an opaque
6008
    // pathname, and compileOptions.
6009
0
    auto pathname_component = url_pattern_component<regex_provider>::compile(
6010
0
        processed_init->pathname.value(),
6011
0
        url_pattern_helpers::canonicalize_opaque_pathname, compile_options);
6012
0
    if (!pathname_component) {
6013
0
      ada_log("url_pattern_component::compile failed for opaque pathname ",
6014
0
              processed_init->pathname.value());
6015
0
      return tl::unexpected(pathname_component.error());
6016
0
    }
6017
0
    url_pattern_.pathname_component = std::move(*pathname_component);
6018
0
  }
6019
6020
  // Set urlPattern's search component to the result of compiling a component
6021
  // given processedInit["search"], canonicalize a search, and compileOptions.
6022
591
  auto search_component = url_pattern_component<regex_provider>::compile(
6023
591
      processed_init->search.value(), url_pattern_helpers::canonicalize_search,
6024
591
      compile_options);
6025
591
  if (!search_component) {
6026
0
    ada_log("url_pattern_component::compile failed for search ",
6027
0
            processed_init->search.value());
6028
0
    return tl::unexpected(search_component.error());
6029
0
  }
6030
591
  url_pattern_.search_component = std::move(*search_component);
6031
6032
  // Set urlPattern's hash component to the result of compiling a component
6033
  // given processedInit["hash"], canonicalize a hash, and compileOptions.
6034
591
  auto hash_component = url_pattern_component<regex_provider>::compile(
6035
591
      processed_init->hash.value(), url_pattern_helpers::canonicalize_hash,
6036
591
      compile_options);
6037
591
  if (!hash_component) {
6038
0
    ada_log("url_pattern_component::compile failed for hash ",
6039
0
            processed_init->hash.value());
6040
0
    return tl::unexpected(hash_component.error());
6041
0
  }
6042
591
  url_pattern_.hash_component = std::move(*hash_component);
6043
6044
  // Return urlPattern.
6045
591
  return url_pattern_;
6046
591
}
6047
#endif  // ADA_INCLUDE_URL_PATTERN
6048
6049
}  // namespace ada::parser
6050
6051
#endif  // ADA_PARSER_INL_H
6052
/* end file include/ada/parser-inl.h */
6053
/* begin file include/ada/scheme-inl.h */
6054
/**
6055
 * @file scheme-inl.h
6056
 * @brief Definitions for the URL scheme.
6057
 */
6058
#ifndef ADA_SCHEME_INL_H
6059
#define ADA_SCHEME_INL_H
6060
6061
6062
namespace ada::scheme {
6063
6064
/**
6065
 * @namespace ada::scheme::details
6066
 * @brief Includes the definitions for scheme specific entities
6067
 */
6068
namespace details {
6069
// for use with is_special and get_special_port
6070
// Spaces, if present, are removed from URL.
6071
constexpr std::string_view is_special_list[] = {"http", " ",   "https", "ws",
6072
                                                "ftp",  "wss", "file",  " "};
6073
// for use with get_special_port
6074
constexpr uint16_t special_ports[] = {80, 0, 443, 80, 21, 443, 0, 0};
6075
}  // namespace details
6076
6077
/****
6078
 * @private
6079
 * In is_special, get_scheme_type, and get_special_port, we
6080
 * use a standard hashing technique to find the index of the scheme in
6081
 * the is_special_list. The hashing technique is based on the size of
6082
 * the scheme and the first character of the scheme. It ensures that we
6083
 * do at most one string comparison per call. If the protocol is
6084
 * predictible (e.g., it is always "http"), we can get a better average
6085
 * performance by using a simpler approach where we loop and compare
6086
 * scheme with all possible protocols starting with the most likely
6087
 * protocol. Doing multiple comparisons may have a poor worst case
6088
 * performance, however. In this instance, we choose a potentially
6089
 * slightly lower best-case performance for a better worst-case
6090
 * performance. We can revisit this choice at any time.
6091
 *
6092
 * Reference:
6093
 * Schmidt, Douglas C. "Gperf: A perfect hash function generator."
6094
 * More C++ gems 17 (2000).
6095
 *
6096
 * Reference: https://en.wikipedia.org/wiki/Perfect_hash_function
6097
 *
6098
 * Reference: https://github.com/ada-url/ada/issues/617
6099
 ****/
6100
6101
9.21k
ada_really_inline constexpr bool is_special(std::string_view scheme) {
6102
9.21k
  if (scheme.empty()) {
6103
0
    return false;
6104
0
  }
6105
9.21k
  int hash_value = (2 * scheme.size() + (unsigned)(scheme[0])) & 7;
6106
9.21k
  const std::string_view target = details::is_special_list[hash_value];
6107
9.21k
  return (target[0] == scheme[0]) && (target.substr(1) == scheme.substr(1));
6108
9.21k
}
6109
591
constexpr uint16_t get_special_port(std::string_view scheme) noexcept {
6110
591
  if (scheme.empty()) {
6111
0
    return 0;
6112
0
  }
6113
591
  int hash_value = (2 * scheme.size() + (unsigned)(scheme[0])) & 7;
6114
591
  const std::string_view target = details::is_special_list[hash_value];
6115
591
  if ((target[0] == scheme[0]) && (target.substr(1) == scheme.substr(1))) {
6116
591
    return details::special_ports[hash_value];
6117
591
  } else {
6118
0
    return 0;
6119
0
  }
6120
591
}
6121
15.6k
constexpr uint16_t get_special_port(ada::scheme::type type) noexcept {
6122
15.6k
  return details::special_ports[int(type)];
6123
15.6k
}
6124
117k
constexpr ada::scheme::type get_scheme_type(std::string_view scheme) noexcept {
6125
117k
  if (scheme.empty()) {
6126
0
    return ada::scheme::NOT_SPECIAL;
6127
0
  }
6128
117k
  int hash_value = (2 * scheme.size() + (unsigned)(scheme[0])) & 7;
6129
117k
  const std::string_view target = details::is_special_list[hash_value];
6130
117k
  if ((target[0] == scheme[0]) && (target.substr(1) == scheme.substr(1))) {
6131
60.1k
    return ada::scheme::type(hash_value);
6132
60.1k
  } else {
6133
57.4k
    return ada::scheme::NOT_SPECIAL;
6134
57.4k
  }
6135
117k
}
6136
6137
}  // namespace ada::scheme
6138
6139
#endif  // ADA_SCHEME_INL_H
6140
/* end file include/ada/scheme-inl.h */
6141
/* begin file include/ada/serializers.h */
6142
/**
6143
 * @file serializers.h
6144
 * @brief Definitions for the URL serializers.
6145
 */
6146
#ifndef ADA_SERIALIZERS_H
6147
#define ADA_SERIALIZERS_H
6148
6149
6150
#include <array>
6151
#include <string>
6152
6153
/**
6154
 * @namespace ada::serializers
6155
 * @brief Includes the definitions for URL serializers
6156
 */
6157
namespace ada::serializers {
6158
6159
/**
6160
 * Finds and returns the longest sequence of 0 values in a ipv6 input.
6161
 */
6162
void find_longest_sequence_of_ipv6_pieces(
6163
    const std::array<uint16_t, 8>& address, size_t& compress,
6164
    size_t& compress_length) noexcept;
6165
6166
/**
6167
 * Serializes an ipv6 address.
6168
 * @details An IPv6 address is a 128-bit unsigned integer that identifies a
6169
 * network address.
6170
 * @see https://url.spec.whatwg.org/#concept-ipv6-serializer
6171
 */
6172
std::string ipv6(const std::array<uint16_t, 8>& address) noexcept;
6173
6174
/**
6175
 * Serializes an ipv4 address.
6176
 * @details An IPv4 address is a 32-bit unsigned integer that identifies a
6177
 * network address.
6178
 * @see https://url.spec.whatwg.org/#concept-ipv4-serializer
6179
 */
6180
std::string ipv4(uint64_t address) noexcept;
6181
6182
}  // namespace ada::serializers
6183
6184
#endif  // ADA_SERIALIZERS_H
6185
/* end file include/ada/serializers.h */
6186
/* begin file include/ada/state.h */
6187
/**
6188
 * @file state.h
6189
 * @brief Definitions for the states of the URL state machine.
6190
 */
6191
#ifndef ADA_STATE_H
6192
#define ADA_STATE_H
6193
6194
6195
#include <string>
6196
6197
namespace ada {
6198
6199
/**
6200
 * @see https://url.spec.whatwg.org/#url-parsing
6201
 */
6202
enum class state {
6203
  /**
6204
   * @see https://url.spec.whatwg.org/#authority-state
6205
   */
6206
  AUTHORITY,
6207
6208
  /**
6209
   * @see https://url.spec.whatwg.org/#scheme-start-state
6210
   */
6211
  SCHEME_START,
6212
6213
  /**
6214
   * @see https://url.spec.whatwg.org/#scheme-state
6215
   */
6216
  SCHEME,
6217
6218
  /**
6219
   * @see https://url.spec.whatwg.org/#host-state
6220
   */
6221
  HOST,
6222
6223
  /**
6224
   * @see https://url.spec.whatwg.org/#no-scheme-state
6225
   */
6226
  NO_SCHEME,
6227
6228
  /**
6229
   * @see https://url.spec.whatwg.org/#fragment-state
6230
   */
6231
  FRAGMENT,
6232
6233
  /**
6234
   * @see https://url.spec.whatwg.org/#relative-state
6235
   */
6236
  RELATIVE_SCHEME,
6237
6238
  /**
6239
   * @see https://url.spec.whatwg.org/#relative-slash-state
6240
   */
6241
  RELATIVE_SLASH,
6242
6243
  /**
6244
   * @see https://url.spec.whatwg.org/#file-state
6245
   */
6246
  FILE,
6247
6248
  /**
6249
   * @see https://url.spec.whatwg.org/#file-host-state
6250
   */
6251
  FILE_HOST,
6252
6253
  /**
6254
   * @see https://url.spec.whatwg.org/#file-slash-state
6255
   */
6256
  FILE_SLASH,
6257
6258
  /**
6259
   * @see https://url.spec.whatwg.org/#path-or-authority-state
6260
   */
6261
  PATH_OR_AUTHORITY,
6262
6263
  /**
6264
   * @see https://url.spec.whatwg.org/#special-authority-ignore-slashes-state
6265
   */
6266
  SPECIAL_AUTHORITY_IGNORE_SLASHES,
6267
6268
  /**
6269
   * @see https://url.spec.whatwg.org/#special-authority-slashes-state
6270
   */
6271
  SPECIAL_AUTHORITY_SLASHES,
6272
6273
  /**
6274
   * @see https://url.spec.whatwg.org/#special-relative-or-authority-state
6275
   */
6276
  SPECIAL_RELATIVE_OR_AUTHORITY,
6277
6278
  /**
6279
   * @see https://url.spec.whatwg.org/#query-state
6280
   */
6281
  QUERY,
6282
6283
  /**
6284
   * @see https://url.spec.whatwg.org/#path-state
6285
   */
6286
  PATH,
6287
6288
  /**
6289
   * @see https://url.spec.whatwg.org/#path-start-state
6290
   */
6291
  PATH_START,
6292
6293
  /**
6294
   * @see https://url.spec.whatwg.org/#cannot-be-a-base-url-path-state
6295
   */
6296
  OPAQUE_PATH,
6297
6298
  /**
6299
   * @see https://url.spec.whatwg.org/#port-state
6300
   */
6301
  PORT,
6302
};
6303
6304
/**
6305
 * Stringify a URL state machine state.
6306
 */
6307
ada_warn_unused std::string to_string(ada::state s);
6308
6309
}  // namespace ada
6310
6311
#endif  // ADA_STATE_H
6312
/* end file include/ada/state.h */
6313
/* begin file include/ada/unicode.h */
6314
/**
6315
 * @file unicode.h
6316
 * @brief Definitions for all unicode specific functions.
6317
 */
6318
#ifndef ADA_UNICODE_H
6319
#define ADA_UNICODE_H
6320
6321
6322
#include <string>
6323
#include <string_view>
6324
#include <optional>
6325
6326
/**
6327
 * Unicode operations. These functions are not part of our public API and may
6328
 * change at any time.
6329
 *
6330
 * @private
6331
 * @namespace ada::unicode
6332
 * @brief Includes the definitions for unicode operations
6333
 */
6334
namespace ada::unicode {
6335
6336
/**
6337
 * @private
6338
 * We receive a UTF-8 string representing a domain name.
6339
 * If the string is percent encoded, we apply percent decoding.
6340
 *
6341
 * Given a domain, we need to identify its labels.
6342
 * They are separated by label-separators:
6343
 *
6344
 * U+002E (.) FULL STOP
6345
 * U+FF0E FULLWIDTH FULL STOP
6346
 * U+3002 IDEOGRAPHIC FULL STOP
6347
 * U+FF61 HALFWIDTH IDEOGRAPHIC FULL STOP
6348
 *
6349
 * They are all mapped to U+002E.
6350
 *
6351
 * We process each label into a string that should not exceed 63 octets.
6352
 * If the string is already punycode (starts with "xn--"), then we must
6353
 * scan it to look for unallowed code points.
6354
 * Otherwise, if the string is not pure ASCII, we need to transcode it
6355
 * to punycode by following RFC 3454 which requires us to
6356
 * - Map characters  (see section 3),
6357
 * - Normalize (see section 4),
6358
 * - Reject forbidden characters,
6359
 * - Check for right-to-left characters and if so, check all requirements (see
6360
 * section 6),
6361
 * - Optionally reject based on unassigned code points (section 7).
6362
 *
6363
 * The Unicode standard provides a table of code points with a mapping, a list
6364
 * of forbidden code points and so forth. This table is subject to change and
6365
 * will vary based on the implementation. For Unicode 15, the table is at
6366
 * https://www.unicode.org/Public/idna/15.0.0/IdnaMappingTable.txt
6367
 * If you use ICU, they parse this table and map it to code using a Python
6368
 * script.
6369
 *
6370
 * The resulting strings should not exceed 255 octets according to RFC 1035
6371
 * section 2.3.4. ICU checks for label size and domain size, but these errors
6372
 * are ignored.
6373
 *
6374
 * @see https://url.spec.whatwg.org/#concept-domain-to-ascii
6375
 *
6376
 */
6377
bool to_ascii(std::optional<std::string>& out, std::string_view plain,
6378
              size_t first_percent);
6379
6380
/**
6381
 * @private
6382
 * Checks if the input has tab or newline characters.
6383
 *
6384
 * @attention The has_tabs_or_newline function is a bottleneck and it is simple
6385
 * enough that compilers like GCC can 'autovectorize it'.
6386
 */
6387
ada_really_inline bool has_tabs_or_newline(
6388
    std::string_view user_input) noexcept;
6389
6390
/**
6391
 * @private
6392
 * Checks if the input is a forbidden host code point.
6393
 * @see https://url.spec.whatwg.org/#forbidden-host-code-point
6394
 */
6395
ada_really_inline constexpr bool is_forbidden_host_code_point(char c) noexcept;
6396
6397
/**
6398
 * @private
6399
 * Checks if the input contains a forbidden domain code point.
6400
 * @see https://url.spec.whatwg.org/#forbidden-domain-code-point
6401
 */
6402
ada_really_inline constexpr bool contains_forbidden_domain_code_point(
6403
    const char* input, size_t length) noexcept;
6404
6405
/**
6406
 * @private
6407
 * Checks if the input contains a forbidden domain code point in which case
6408
 * the first bit is set to 1. If the input contains an upper case ASCII letter,
6409
 * then the second bit is set to 1.
6410
 * @see https://url.spec.whatwg.org/#forbidden-domain-code-point
6411
 */
6412
ada_really_inline constexpr uint8_t
6413
contains_forbidden_domain_code_point_or_upper(const char* input,
6414
                                              size_t length) noexcept;
6415
6416
/**
6417
 * @private
6418
 * Checks if the input is a forbidden domain code point.
6419
 * @see https://url.spec.whatwg.org/#forbidden-domain-code-point
6420
 */
6421
ada_really_inline constexpr bool is_forbidden_domain_code_point(
6422
    char c) noexcept;
6423
6424
/**
6425
 * @private
6426
 * Checks if the input is alphanumeric, '+', '-' or '.'
6427
 */
6428
ada_really_inline constexpr bool is_alnum_plus(char c) noexcept;
6429
6430
/**
6431
 * @private
6432
 * @details An ASCII hex digit is an ASCII upper hex digit or ASCII lower hex
6433
 * digit. An ASCII upper hex digit is an ASCII digit or a code point in the
6434
 * range U+0041 (A) to U+0046 (F), inclusive. An ASCII lower hex digit is an
6435
 * ASCII digit or a code point in the range U+0061 (a) to U+0066 (f), inclusive.
6436
 */
6437
ada_really_inline constexpr bool is_ascii_hex_digit(char c) noexcept;
6438
6439
/**
6440
 * @private
6441
 * An ASCII digit is a code point in the range U+0030 (0) to U+0039 (9),
6442
 * inclusive.
6443
 */
6444
ada_really_inline constexpr bool is_ascii_digit(char c) noexcept;
6445
6446
/**
6447
 * @private
6448
 * @details If a char is between U+0000 and U+007F inclusive, then it's an ASCII
6449
 * character.
6450
 */
6451
ada_really_inline constexpr bool is_ascii(char32_t c) noexcept;
6452
6453
/**
6454
 * @private
6455
 * Checks if the input is a C0 control or space character.
6456
 *
6457
 * @details A C0 control or space is a C0 control or U+0020 SPACE.
6458
 * A C0 control is a code point in the range U+0000 NULL to U+001F INFORMATION
6459
 * SEPARATOR ONE, inclusive.
6460
 */
6461
ada_really_inline constexpr bool is_c0_control_or_space(char c) noexcept;
6462
6463
/**
6464
 * @private
6465
 * Checks if the input is a ASCII tab or newline character.
6466
 *
6467
 * @details An ASCII tab or newline is U+0009 TAB, U+000A LF, or U+000D CR.
6468
 */
6469
ada_really_inline constexpr bool is_ascii_tab_or_newline(char c) noexcept;
6470
6471
/**
6472
 * @private
6473
 * @details A double-dot path segment must be ".." or an ASCII case-insensitive
6474
 * match for ".%2e", "%2e.", or "%2e%2e".
6475
 */
6476
ada_really_inline constexpr bool is_double_dot_path_segment(
6477
    std::string_view input) noexcept;
6478
6479
/**
6480
 * @private
6481
 * @details A single-dot path segment must be "." or an ASCII case-insensitive
6482
 * match for "%2e".
6483
 */
6484
ada_really_inline constexpr bool is_single_dot_path_segment(
6485
    std::string_view input) noexcept;
6486
6487
/**
6488
 * @private
6489
 * @details ipv4 character might contain 0-9 or a-f character ranges.
6490
 */
6491
ada_really_inline constexpr bool is_lowercase_hex(char c) noexcept;
6492
6493
/**
6494
 * @private
6495
 * @details Convert hex to binary. Caller is responsible to ensure that
6496
 * the parameter is an hexadecimal digit (0-9, A-F, a-f).
6497
 */
6498
ada_really_inline unsigned constexpr convert_hex_to_binary(char c) noexcept;
6499
6500
/**
6501
 * @private
6502
 * first_percent should be  = input.find('%')
6503
 *
6504
 * @todo It would be faster as noexcept maybe, but it could be unsafe since.
6505
 * @author Node.js
6506
 * @see https://github.com/nodejs/node/blob/main/src/node_url.cc#L245
6507
 * @see https://encoding.spec.whatwg.org/#utf-8-decode-without-bom
6508
 */
6509
std::string percent_decode(std::string_view input, size_t first_percent);
6510
6511
/**
6512
 * @private
6513
 * Returns a percent-encoding string whether percent encoding was needed or not.
6514
 * @see https://github.com/nodejs/node/blob/main/src/node_url.cc#L226
6515
 */
6516
std::string percent_encode(std::string_view input,
6517
                           const uint8_t character_set[]);
6518
/**
6519
 * @private
6520
 * Returns a percent-encoded string version of input, while starting the percent
6521
 * encoding at the provided index.
6522
 * @see https://github.com/nodejs/node/blob/main/src/node_url.cc#L226
6523
 */
6524
std::string percent_encode(std::string_view input,
6525
                           const uint8_t character_set[], size_t index);
6526
/**
6527
 * @private
6528
 * Returns true if percent encoding was needed, in which case, we store
6529
 * the percent-encoded content in 'out'. If the boolean 'append' is set to
6530
 * true, the content is appended to 'out'.
6531
 * If percent encoding is not needed, out is left unchanged.
6532
 * @see https://github.com/nodejs/node/blob/main/src/node_url.cc#L226
6533
 */
6534
template <bool append>
6535
bool percent_encode(std::string_view input, const uint8_t character_set[],
6536
                    std::string& out);
6537
/**
6538
 * @private
6539
 * Returns the index at which percent encoding should start, or (equivalently),
6540
 * the length of the prefix that does not require percent encoding.
6541
 */
6542
ada_really_inline size_t percent_encode_index(std::string_view input,
6543
                                              const uint8_t character_set[]);
6544
/**
6545
 * @private
6546
 * Lowers the string in-place, assuming that the content is ASCII.
6547
 * Return true if the content was ASCII.
6548
 */
6549
constexpr bool to_lower_ascii(char* input, size_t length) noexcept;
6550
}  // namespace ada::unicode
6551
6552
#endif  // ADA_UNICODE_H
6553
/* end file include/ada/unicode.h */
6554
/* begin file include/ada/url_base-inl.h */
6555
/**
6556
 * @file url_base-inl.h
6557
 * @brief Inline functions for url base
6558
 */
6559
#ifndef ADA_URL_BASE_INL_H
6560
#define ADA_URL_BASE_INL_H
6561
6562
6563
#include <string>
6564
#if ADA_REGULAR_VISUAL_STUDIO
6565
#include <intrin.h>
6566
#endif  // ADA_REGULAR_VISUAL_STUDIO
6567
6568
namespace ada {
6569
6570
[[nodiscard]] ada_really_inline constexpr bool url_base::is_special()
6571
526k
    const noexcept {
6572
526k
  return type != ada::scheme::NOT_SPECIAL;
6573
526k
}
6574
6575
9.64k
[[nodiscard]] inline uint16_t url_base::get_special_port() const noexcept {
6576
9.64k
  return ada::scheme::get_special_port(type);
6577
9.64k
}
6578
6579
[[nodiscard]] ada_really_inline uint16_t
6580
6.05k
url_base::scheme_default_port() const noexcept {
6581
6.05k
  return scheme::get_special_port(type);
6582
6.05k
}
6583
6584
}  // namespace ada
6585
6586
#endif  // ADA_URL_BASE_INL_H
6587
/* end file include/ada/url_base-inl.h */
6588
/* begin file include/ada/url-inl.h */
6589
/**
6590
 * @file url-inl.h
6591
 * @brief Definitions for the URL
6592
 */
6593
#ifndef ADA_URL_INL_H
6594
#define ADA_URL_INL_H
6595
6596
6597
#include <charconv>
6598
#include <optional>
6599
#include <string>
6600
#if ADA_REGULAR_VISUAL_STUDIO
6601
#include <intrin.h>
6602
#endif  // ADA_REGULAR_VISUAL_STUDIO
6603
6604
namespace ada {
6605
13.7k
[[nodiscard]] ada_really_inline bool url::has_credentials() const noexcept {
6606
13.7k
  return !username.empty() || !password.empty();
6607
13.7k
}
6608
0
[[nodiscard]] ada_really_inline bool url::has_port() const noexcept {
6609
0
  return port.has_value();
6610
0
}
6611
29.4k
[[nodiscard]] inline bool url::cannot_have_credentials_or_port() const {
6612
29.4k
  return !host.has_value() || host.value().empty() ||
6613
29.4k
         type == ada::scheme::type::FILE;
6614
29.4k
}
6615
0
[[nodiscard]] inline bool url::has_empty_hostname() const noexcept {
6616
0
  if (!host.has_value()) {
6617
0
    return false;
6618
0
  }
6619
0
  return host.value().empty();
6620
0
}
6621
0
[[nodiscard]] inline bool url::has_hostname() const noexcept {
6622
0
  return host.has_value();
6623
0
}
6624
0
inline std::ostream &operator<<(std::ostream &out, const ada::url &u) {
6625
0
  return out << u.to_string();
6626
0
}
6627
6628
0
[[nodiscard]] size_t url::get_pathname_length() const noexcept {
6629
0
  return path.size();
6630
0
}
6631
6632
8.88k
[[nodiscard]] constexpr std::string_view url::get_pathname() const noexcept {
6633
8.88k
  return path;
6634
8.88k
}
6635
6636
[[nodiscard]] ada_really_inline ada::url_components url::get_components()
6637
0
    const noexcept {
6638
0
  url_components out{};
6639
0
6640
0
  // protocol ends with ':'. for example: "https:"
6641
0
  out.protocol_end = uint32_t(get_protocol().size());
6642
0
6643
0
  // Trailing index is always the next character of the current one.
6644
0
  // NOLINTNEXTLINE(clang-analyzer-deadcode.DeadStores)
6645
0
  size_t running_index = out.protocol_end;
6646
0
6647
0
  if (host.has_value()) {
6648
0
    // 2 characters for "//" and 1 character for starting index
6649
0
    out.host_start = out.protocol_end + 2;
6650
0
6651
0
    if (has_credentials()) {
6652
0
      out.username_end = uint32_t(out.host_start + username.size());
6653
0
6654
0
      out.host_start += uint32_t(username.size());
6655
0
6656
0
      if (!password.empty()) {
6657
0
        out.host_start += uint32_t(password.size() + 1);
6658
0
      }
6659
0
6660
0
      out.host_end = uint32_t(out.host_start + host.value().size());
6661
0
    } else {
6662
0
      out.username_end = out.host_start;
6663
0
6664
0
      // Host does not start with "@" if it does not include credentials.
6665
0
      out.host_end = uint32_t(out.host_start + host.value().size()) - 1;
6666
0
    }
6667
0
6668
0
    running_index = out.host_end + 1;
6669
0
  } else {
6670
0
    // Update host start and end date to the same index, since it does not
6671
0
    // exist.
6672
0
    out.host_start = out.protocol_end;
6673
0
    out.host_end = out.host_start;
6674
0
6675
0
    if (!has_opaque_path && path.starts_with("//")) {
6676
0
      // If url's host is null, url does not have an opaque path, url's path's
6677
0
      // size is greater than 1, and url's path[0] is the empty string, then
6678
0
      // append U+002F (/) followed by U+002E (.) to output.
6679
0
      running_index = out.protocol_end + 2;
6680
0
    } else {
6681
0
      running_index = out.protocol_end;
6682
0
    }
6683
0
  }
6684
0
6685
0
  if (port.has_value()) {
6686
0
    out.port = *port;
6687
0
    running_index += helpers::fast_digit_count(*port) + 1;  // Port omits ':'
6688
0
  }
6689
0
6690
0
  out.pathname_start = uint32_t(running_index);
6691
0
6692
0
  running_index += path.size();
6693
0
6694
0
  if (query.has_value()) {
6695
0
    out.search_start = uint32_t(running_index);
6696
0
    running_index += get_search().size();
6697
0
    if (get_search().empty()) {
6698
0
      running_index++;
6699
0
    }
6700
0
  }
6701
0
6702
0
  if (hash.has_value()) {
6703
0
    out.hash_start = uint32_t(running_index);
6704
0
  }
6705
0
6706
0
  return out;
6707
0
}
6708
6709
42
inline void url::update_base_hostname(std::string_view input) { host = input; }
6710
6711
144
inline void url::update_unencoded_base_hash(std::string_view input) {
6712
  // We do the percent encoding
6713
144
  hash = unicode::percent_encode(input,
6714
144
                                 ada::character_sets::FRAGMENT_PERCENT_ENCODE);
6715
144
}
6716
6717
inline void url::update_base_search(std::string_view input,
6718
248
                                    const uint8_t query_percent_encode_set[]) {
6719
248
  query = ada::unicode::percent_encode(input, query_percent_encode_set);
6720
248
}
6721
6722
0
inline void url::update_base_search(std::optional<std::string> &&input) {
6723
0
  query = std::move(input);
6724
0
}
6725
6726
12.3k
inline void url::update_base_pathname(const std::string_view input) {
6727
12.3k
  path = input;
6728
12.3k
}
6729
6730
0
inline void url::update_base_username(const std::string_view input) {
6731
0
  username = input;
6732
0
}
6733
6734
0
inline void url::update_base_password(const std::string_view input) {
6735
0
  password = input;
6736
0
}
6737
6738
5.22k
inline void url::update_base_port(std::optional<uint16_t> input) {
6739
5.22k
  port = input;
6740
5.22k
}
6741
6742
0
constexpr void url::clear_pathname() { path.clear(); }
6743
6744
0
constexpr void url::clear_search() { query = std::nullopt; }
6745
6746
0
[[nodiscard]] constexpr bool url::has_hash() const noexcept {
6747
0
  return hash.has_value();
6748
0
}
6749
6750
6.43k
[[nodiscard]] constexpr bool url::has_search() const noexcept {
6751
6.43k
  return query.has_value();
6752
6.43k
}
6753
6754
1.45k
constexpr void url::set_protocol_as_file() { type = ada::scheme::type::FILE; }
6755
6756
4.99k
inline void url::set_scheme(std::string &&new_scheme) noexcept {
6757
4.99k
  type = ada::scheme::get_scheme_type(new_scheme);
6758
  // We only move the 'scheme' if it is non-special.
6759
4.99k
  if (!is_special()) {
6760
2.93k
    non_special_scheme = std::move(new_scheme);
6761
2.93k
  }
6762
4.99k
}
6763
6764
0
constexpr void url::copy_scheme(ada::url &&u) noexcept {
6765
0
  non_special_scheme = u.non_special_scheme;
6766
0
  type = u.type;
6767
0
}
6768
6769
0
constexpr void url::copy_scheme(const ada::url &u) {
6770
0
  non_special_scheme = u.non_special_scheme;
6771
0
  type = u.type;
6772
0
}
6773
6774
8.91k
[[nodiscard]] ada_really_inline std::string url::get_href() const noexcept {
6775
8.91k
  std::string output = get_protocol();
6776
6777
8.91k
  if (host.has_value()) {
6778
5.18k
    output += "//";
6779
5.18k
    if (has_credentials()) {
6780
609
      output += username;
6781
609
      if (!password.empty()) {
6782
210
        output += ":" + get_password();
6783
210
      }
6784
609
      output += "@";
6785
609
    }
6786
5.18k
    output += host.value();
6787
5.18k
    if (port.has_value()) {
6788
143
      output += ":" + get_port();
6789
143
    }
6790
5.18k
  } else if (!has_opaque_path && path.starts_with("//")) {
6791
    // If url's host is null, url does not have an opaque path, url's path's
6792
    // size is greater than 1, and url's path[0] is the empty string, then
6793
    // append U+002F (/) followed by U+002E (.) to output.
6794
33
    output += "/.";
6795
33
  }
6796
8.91k
  output += path;
6797
8.91k
  if (query.has_value()) {
6798
369
    output += "?" + query.value();
6799
369
  }
6800
8.91k
  if (hash.has_value()) {
6801
213
    output += "#" + hash.value();
6802
213
  }
6803
8.91k
  return output;
6804
8.91k
}
6805
6806
ada_really_inline size_t url::parse_port(std::string_view view,
6807
2.15k
                                         bool check_trailing_content) noexcept {
6808
2.15k
  ada_log("parse_port('", view, "') ", view.size());
6809
2.15k
  if (!view.empty() && view[0] == '-') {
6810
6
    ada_log("parse_port: view[0] == '0' && view.size() > 1");
6811
6
    is_valid = false;
6812
6
    return 0;
6813
6
  }
6814
2.15k
  uint16_t parsed_port{};
6815
2.15k
  auto r = std::from_chars(view.data(), view.data() + view.size(), parsed_port);
6816
2.15k
  if (r.ec == std::errc::result_out_of_range) {
6817
213
    ada_log("parse_port: r.ec == std::errc::result_out_of_range");
6818
213
    is_valid = false;
6819
213
    return 0;
6820
213
  }
6821
1.93k
  ada_log("parse_port: ", parsed_port);
6822
1.93k
  const auto consumed = size_t(r.ptr - view.data());
6823
1.93k
  ada_log("parse_port: consumed ", consumed);
6824
1.93k
  if (check_trailing_content) {
6825
644
    is_valid &=
6826
644
        (consumed == view.size() || view[consumed] == '/' ||
6827
644
         view[consumed] == '?' || (is_special() && view[consumed] == '\\'));
6828
644
  }
6829
1.93k
  ada_log("parse_port: is_valid = ", is_valid);
6830
1.93k
  if (is_valid) {
6831
    // scheme_default_port can return 0, and we should allow 0 as a base port.
6832
1.58k
    auto default_port = scheme_default_port();
6833
1.58k
    bool is_port_valid = (default_port == 0 && parsed_port == 0) ||
6834
1.58k
                         (default_port != parsed_port);
6835
1.58k
    port = (r.ec == std::errc() && is_port_valid) ? std::optional(parsed_port)
6836
1.58k
                                                  : std::nullopt;
6837
1.58k
  }
6838
1.93k
  return consumed;
6839
2.15k
}
6840
6841
}  // namespace ada
6842
6843
#endif  // ADA_URL_H
6844
/* end file include/ada/url-inl.h */
6845
/* begin file include/ada/url_components-inl.h */
6846
/**
6847
 * @file url_components.h
6848
 * @brief Declaration for the URL Components
6849
 */
6850
#ifndef ADA_URL_COMPONENTS_INL_H
6851
#define ADA_URL_COMPONENTS_INL_H
6852
6853
6854
namespace ada {
6855
6856
[[nodiscard]] constexpr bool url_components::check_offset_consistency()
6857
0
    const noexcept {
6858
0
  /**
6859
0
   * https://user:pass@example.com:1234/foo/bar?baz#quux
6860
0
   *       |     |    |          | ^^^^|       |   |
6861
0
   *       |     |    |          | |   |       |   `----- hash_start
6862
0
   *       |     |    |          | |   |       `--------- search_start
6863
0
   *       |     |    |          | |   `----------------- pathname_start
6864
0
   *       |     |    |          | `--------------------- port
6865
0
   *       |     |    |          `----------------------- host_end
6866
0
   *       |     |    `---------------------------------- host_start
6867
0
   *       |     `--------------------------------------- username_end
6868
0
   *       `--------------------------------------------- protocol_end
6869
0
   */
6870
0
  // These conditions can be made more strict.
6871
0
  if (protocol_end == url_components::omitted) {
6872
0
    return false;
6873
0
  }
6874
0
  uint32_t index = protocol_end;
6875
0
6876
0
  if (username_end == url_components::omitted) {
6877
0
    return false;
6878
0
  }
6879
0
  if (username_end < index) {
6880
0
    return false;
6881
0
  }
6882
0
  index = username_end;
6883
0
6884
0
  if (host_start == url_components::omitted) {
6885
0
    return false;
6886
0
  }
6887
0
  if (host_start < index) {
6888
0
    return false;
6889
0
  }
6890
0
  index = host_start;
6891
0
6892
0
  if (port != url_components::omitted) {
6893
0
    if (port > 0xffff) {
6894
0
      return false;
6895
0
    }
6896
0
    uint32_t port_length = helpers::fast_digit_count(port) + 1;
6897
0
    if (index + port_length < index) {
6898
0
      return false;
6899
0
    }
6900
0
    index += port_length;
6901
0
  }
6902
0
6903
0
  if (pathname_start == url_components::omitted) {
6904
0
    return false;
6905
0
  }
6906
0
  if (pathname_start < index) {
6907
0
    return false;
6908
0
  }
6909
0
  index = pathname_start;
6910
0
6911
0
  if (search_start != url_components::omitted) {
6912
0
    if (search_start < index) {
6913
0
      return false;
6914
0
    }
6915
0
    index = search_start;
6916
0
  }
6917
0
6918
0
  if (hash_start != url_components::omitted) {
6919
0
    if (hash_start < index) {
6920
0
      return false;
6921
0
    }
6922
0
  }
6923
0
6924
0
  return true;
6925
0
}
6926
6927
}  // namespace ada
6928
#endif
6929
/* end file include/ada/url_components-inl.h */
6930
/* begin file include/ada/url_aggregator.h */
6931
/**
6932
 * @file url_aggregator.h
6933
 * @brief Declaration for the basic URL definitions
6934
 */
6935
#ifndef ADA_URL_AGGREGATOR_H
6936
#define ADA_URL_AGGREGATOR_H
6937
6938
#include <ostream>
6939
#include <string>
6940
#include <string_view>
6941
#include <variant>
6942
6943
6944
namespace ada {
6945
6946
namespace parser {}
6947
6948
/**
6949
 * @brief Lightweight URL struct.
6950
 *
6951
 * @details The url_aggregator class aims to minimize temporary memory
6952
 * allocation while representing a parsed URL. Internally, it contains a single
6953
 * normalized URL (the href), and it makes available the components, mostly
6954
 * using std::string_view.
6955
 */
6956
struct url_aggregator : url_base {
6957
88.1k
  url_aggregator() = default;
6958
0
  url_aggregator(const url_aggregator &u) = default;
6959
31.3k
  url_aggregator(url_aggregator &&u) noexcept = default;
6960
7.08k
  url_aggregator &operator=(url_aggregator &&u) noexcept = default;
6961
9.33k
  url_aggregator &operator=(const url_aggregator &u) = default;
6962
119k
  ~url_aggregator() override = default;
6963
6964
  bool set_href(std::string_view input);
6965
  bool set_host(std::string_view input);
6966
  bool set_hostname(std::string_view input);
6967
  bool set_protocol(std::string_view input);
6968
  bool set_username(std::string_view input);
6969
  bool set_password(std::string_view input);
6970
  bool set_port(std::string_view input);
6971
  bool set_pathname(std::string_view input);
6972
  void set_search(std::string_view input);
6973
  void set_hash(std::string_view input);
6974
6975
  [[nodiscard]] bool has_valid_domain() const noexcept override;
6976
  /**
6977
   * The origin getter steps are to return the serialization of this's URL's
6978
   * origin. [HTML]
6979
   * @return a newly allocated string.
6980
   * @see https://url.spec.whatwg.org/#concept-url-origin
6981
   */
6982
  [[nodiscard]] std::string get_origin() const noexcept override;
6983
  /**
6984
   * Return the normalized string.
6985
   * This function does not allocate memory.
6986
   * It is highly efficient.
6987
   * @return a constant reference to the underlying normalized URL.
6988
   * @see https://url.spec.whatwg.org/#dom-url-href
6989
   * @see https://url.spec.whatwg.org/#concept-url-serializer
6990
   */
6991
  [[nodiscard]] constexpr std::string_view get_href() const noexcept
6992
      ada_lifetime_bound;
6993
  /**
6994
   * The username getter steps are to return this's URL's username.
6995
   * This function does not allocate memory.
6996
   * @return a lightweight std::string_view.
6997
   * @see https://url.spec.whatwg.org/#dom-url-username
6998
   */
6999
  [[nodiscard]] std::string_view get_username() const noexcept
7000
      ada_lifetime_bound;
7001
  /**
7002
   * The password getter steps are to return this's URL's password.
7003
   * This function does not allocate memory.
7004
   * @return a lightweight std::string_view.
7005
   * @see https://url.spec.whatwg.org/#dom-url-password
7006
   */
7007
  [[nodiscard]] std::string_view get_password() const noexcept
7008
      ada_lifetime_bound;
7009
  /**
7010
   * Return this's URL's port, serialized.
7011
   * This function does not allocate memory.
7012
   * @return a lightweight std::string_view.
7013
   * @see https://url.spec.whatwg.org/#dom-url-port
7014
   */
7015
  [[nodiscard]] std::string_view get_port() const noexcept ada_lifetime_bound;
7016
  /**
7017
   * Return U+0023 (#), followed by this's URL's fragment.
7018
   * This function does not allocate memory.
7019
   * @return a lightweight std::string_view..
7020
   * @see https://url.spec.whatwg.org/#dom-url-hash
7021
   */
7022
  [[nodiscard]] std::string_view get_hash() const noexcept ada_lifetime_bound;
7023
  /**
7024
   * Return url's host, serialized, followed by U+003A (:) and url's port,
7025
   * serialized.
7026
   * This function does not allocate memory.
7027
   * When there is no host, this function returns the empty view.
7028
   * @return a lightweight std::string_view.
7029
   * @see https://url.spec.whatwg.org/#dom-url-host
7030
   */
7031
  [[nodiscard]] std::string_view get_host() const noexcept ada_lifetime_bound;
7032
  /**
7033
   * Return this's URL's host, serialized.
7034
   * This function does not allocate memory.
7035
   * When there is no host, this function returns the empty view.
7036
   * @return a lightweight std::string_view.
7037
   * @see https://url.spec.whatwg.org/#dom-url-hostname
7038
   */
7039
  [[nodiscard]] std::string_view get_hostname() const noexcept
7040
      ada_lifetime_bound;
7041
  /**
7042
   * The pathname getter steps are to return the result of URL path serializing
7043
   * this's URL.
7044
   * This function does not allocate memory.
7045
   * @return a lightweight std::string_view.
7046
   * @see https://url.spec.whatwg.org/#dom-url-pathname
7047
   */
7048
  [[nodiscard]] constexpr std::string_view get_pathname() const noexcept
7049
      ada_lifetime_bound;
7050
  /**
7051
   * Compute the pathname length in bytes without instantiating a view or a
7052
   * string.
7053
   * @return size of the pathname in bytes
7054
   * @see https://url.spec.whatwg.org/#dom-url-pathname
7055
   */
7056
  [[nodiscard]] ada_really_inline uint32_t get_pathname_length() const noexcept;
7057
  /**
7058
   * Return U+003F (?), followed by this's URL's query.
7059
   * This function does not allocate memory.
7060
   * @return a lightweight std::string_view.
7061
   * @see https://url.spec.whatwg.org/#dom-url-search
7062
   */
7063
  [[nodiscard]] std::string_view get_search() const noexcept ada_lifetime_bound;
7064
  /**
7065
   * The protocol getter steps are to return this's URL's scheme, followed by
7066
   * U+003A (:).
7067
   * This function does not allocate memory.
7068
   * @return a lightweight std::string_view.
7069
   * @see https://url.spec.whatwg.org/#dom-url-protocol
7070
   */
7071
  [[nodiscard]] std::string_view get_protocol() const noexcept
7072
      ada_lifetime_bound;
7073
7074
  /**
7075
   * A URL includes credentials if its username or password is not the empty
7076
   * string.
7077
   */
7078
  [[nodiscard]] ada_really_inline constexpr bool has_credentials()
7079
      const noexcept;
7080
7081
  /**
7082
   * Useful for implementing efficient serialization for the URL.
7083
   *
7084
   * https://user:pass@example.com:1234/foo/bar?baz#quux
7085
   *       |     |    |          | ^^^^|       |   |
7086
   *       |     |    |          | |   |       |   `----- hash_start
7087
   *       |     |    |          | |   |       `--------- search_start
7088
   *       |     |    |          | |   `----------------- pathname_start
7089
   *       |     |    |          | `--------------------- port
7090
   *       |     |    |          `----------------------- host_end
7091
   *       |     |    `---------------------------------- host_start
7092
   *       |     `--------------------------------------- username_end
7093
   *       `--------------------------------------------- protocol_end
7094
   *
7095
   * Inspired after servo/url
7096
   *
7097
   * @return a constant reference to the underlying component attribute.
7098
   *
7099
   * @see
7100
   * https://github.com/servo/rust-url/blob/b65a45515c10713f6d212e6726719a020203cc98/url/src/quirks.rs#L31
7101
   */
7102
  [[nodiscard]] ada_really_inline const url_components &get_components()
7103
      const noexcept;
7104
  /**
7105
   * Returns a string representation of this URL.
7106
   */
7107
  [[nodiscard]] std::string to_string() const override;
7108
  /**
7109
   * Returns a string diagram of this URL.
7110
   */
7111
  [[nodiscard]] std::string to_diagram() const;
7112
7113
  /**
7114
   * Verifies that the parsed URL could be valid. Useful for debugging purposes.
7115
   * @return true if the URL is valid, otherwise return true of the offsets are
7116
   * possible.
7117
   */
7118
  [[nodiscard]] constexpr bool validate() const noexcept;
7119
7120
  /** @return true if it has an host but it is the empty string */
7121
  [[nodiscard]] constexpr bool has_empty_hostname() const noexcept;
7122
  /** @return true if it has a host (included an empty host) */
7123
  [[nodiscard]] constexpr bool has_hostname() const noexcept;
7124
  /** @return true if the URL has a non-empty username */
7125
  [[nodiscard]] constexpr bool has_non_empty_username() const noexcept;
7126
  /** @return true if the URL has a non-empty password */
7127
  [[nodiscard]] constexpr bool has_non_empty_password() const noexcept;
7128
  /** @return true if the URL has a (non default) port */
7129
  [[nodiscard]] constexpr bool has_port() const noexcept;
7130
  /** @return true if the URL has a password */
7131
  [[nodiscard]] constexpr bool has_password() const noexcept;
7132
  /** @return true if the URL has a hash component */
7133
  [[nodiscard]] constexpr bool has_hash() const noexcept override;
7134
  /** @return true if the URL has a search component */
7135
  [[nodiscard]] constexpr bool has_search() const noexcept override;
7136
7137
  inline void clear_port();
7138
  inline void clear_hash();
7139
  inline void clear_search() override;
7140
7141
 private:
7142
  // helper methods
7143
  friend void helpers::strip_trailing_spaces_from_opaque_path<url_aggregator>(
7144
      url_aggregator &url) noexcept;
7145
  // parse_url methods
7146
  friend url_aggregator parser::parse_url<url_aggregator>(
7147
      std::string_view, const url_aggregator *);
7148
7149
  friend url_aggregator parser::parse_url_impl<url_aggregator, true>(
7150
      std::string_view, const url_aggregator *);
7151
  friend url_aggregator parser::parse_url_impl<url_aggregator, false>(
7152
      std::string_view, const url_aggregator *);
7153
7154
#if ADA_INCLUDE_URL_PATTERN
7155
  // url_pattern methods
7156
  template <url_pattern_regex::regex_concept regex_provider>
7157
  friend tl::expected<url_pattern<regex_provider>, errors>
7158
  parse_url_pattern_impl(
7159
      std::variant<std::string_view, url_pattern_init> &&input,
7160
      const std::string_view *base_url, const url_pattern_options *options);
7161
#endif  // ADA_INCLUDE_URL_PATTERN
7162
7163
  std::string buffer{};
7164
  url_components components{};
7165
7166
  /**
7167
   * Returns true if neither the search, nor the hash nor the pathname
7168
   * have been set.
7169
   * @return true if the buffer is ready to receive the path.
7170
   */
7171
  [[nodiscard]] ada_really_inline bool is_at_path() const noexcept;
7172
7173
  inline void add_authority_slashes_if_needed() noexcept;
7174
7175
  /**
7176
   * To optimize performance, you may indicate how much memory to allocate
7177
   * within this instance.
7178
   */
7179
  constexpr void reserve(uint32_t capacity);
7180
7181
  ada_really_inline size_t parse_port(
7182
      std::string_view view, bool check_trailing_content) noexcept override;
7183
7184
2.30k
  ada_really_inline size_t parse_port(std::string_view view) noexcept override {
7185
2.30k
    return this->parse_port(view, false);
7186
2.30k
  }
7187
7188
  /**
7189
   * Return true on success. The 'in_place' parameter indicates whether the
7190
   * the string_view input is pointing in the buffer. When in_place is false,
7191
   * we must nearly always update the buffer.
7192
   * @see https://url.spec.whatwg.org/#concept-ipv4-parser
7193
   */
7194
  [[nodiscard]] bool parse_ipv4(std::string_view input, bool in_place);
7195
7196
  /**
7197
   * Return true on success.
7198
   * @see https://url.spec.whatwg.org/#concept-ipv6-parser
7199
   */
7200
  [[nodiscard]] bool parse_ipv6(std::string_view input);
7201
7202
  /**
7203
   * Return true on success.
7204
   * @see https://url.spec.whatwg.org/#concept-opaque-host-parser
7205
   */
7206
  [[nodiscard]] bool parse_opaque_host(std::string_view input);
7207
7208
  ada_really_inline void parse_path(std::string_view input);
7209
7210
  /**
7211
   * A URL cannot have a username/password/port if its host is null or the empty
7212
   * string, or its scheme is "file".
7213
   */
7214
  [[nodiscard]] constexpr bool cannot_have_credentials_or_port() const;
7215
7216
  template <bool override_hostname = false>
7217
  bool set_host_or_hostname(std::string_view input);
7218
7219
  ada_really_inline bool parse_host(std::string_view input);
7220
7221
  inline void update_base_authority(std::string_view base_buffer,
7222
                                    const url_components &base);
7223
  inline void update_unencoded_base_hash(std::string_view input);
7224
  inline void update_base_hostname(std::string_view input);
7225
  inline void update_base_search(std::string_view input);
7226
  inline void update_base_search(std::string_view input,
7227
                                 const uint8_t *query_percent_encode_set);
7228
  inline void update_base_pathname(std::string_view input);
7229
  inline void update_base_username(std::string_view input);
7230
  inline void append_base_username(std::string_view input);
7231
  inline void update_base_password(std::string_view input);
7232
  inline void append_base_password(std::string_view input);
7233
  inline void update_base_port(uint32_t input);
7234
  inline void append_base_pathname(std::string_view input);
7235
  [[nodiscard]] inline uint32_t retrieve_base_port() const;
7236
  constexpr void clear_hostname();
7237
  constexpr void clear_password();
7238
  constexpr void clear_pathname() override;
7239
  [[nodiscard]] constexpr bool has_dash_dot() const noexcept;
7240
  void delete_dash_dot();
7241
  inline void consume_prepared_path(std::string_view input);
7242
  template <bool has_state_override = false>
7243
  [[nodiscard]] ada_really_inline bool parse_scheme_with_colon(
7244
      std::string_view input);
7245
  ada_really_inline uint32_t replace_and_resize(uint32_t start, uint32_t end,
7246
                                                std::string_view input);
7247
  [[nodiscard]] constexpr bool has_authority() const noexcept;
7248
  constexpr void set_protocol_as_file();
7249
  inline void set_scheme(std::string_view new_scheme) noexcept;
7250
  /**
7251
   * Fast function to set the scheme from a view with a colon in the
7252
   * buffer, does not change type.
7253
   */
7254
  inline void set_scheme_from_view_with_colon(
7255
      std::string_view new_scheme_with_colon) noexcept;
7256
  inline void copy_scheme(const url_aggregator &u) noexcept;
7257
7258
  inline void update_host_to_base_host(const std::string_view input) noexcept;
7259
7260
};  // url_aggregator
7261
7262
inline std::ostream &operator<<(std::ostream &out, const url &u);
7263
}  // namespace ada
7264
7265
#endif
7266
/* end file include/ada/url_aggregator.h */
7267
/* begin file include/ada/url_aggregator-inl.h */
7268
/**
7269
 * @file url_aggregator-inl.h
7270
 * @brief Inline functions for url aggregator
7271
 */
7272
#ifndef ADA_URL_AGGREGATOR_INL_H
7273
#define ADA_URL_AGGREGATOR_INL_H
7274
7275
/* begin file include/ada/unicode-inl.h */
7276
/**
7277
 * @file unicode-inl.h
7278
 * @brief Definitions for unicode operations.
7279
 */
7280
#ifndef ADA_UNICODE_INL_H
7281
#define ADA_UNICODE_INL_H
7282
7283
/**
7284
 * Unicode operations. These functions are not part of our public API and may
7285
 * change at any time.
7286
 *
7287
 * private
7288
 * @namespace ada::unicode
7289
 * @brief Includes the declarations for unicode operations
7290
 */
7291
namespace ada::unicode {
7292
ada_really_inline size_t percent_encode_index(const std::string_view input,
7293
28.2k
                                              const uint8_t character_set[]) {
7294
28.2k
  const char* data = input.data();
7295
28.2k
  const size_t size = input.size();
7296
7297
  // Process 8 bytes at a time using unrolled loop
7298
28.2k
  size_t i = 0;
7299
42.1k
  for (; i + 8 <= size; i += 8) {
7300
29.6k
    unsigned char chunk[8];
7301
29.6k
    std::memcpy(&chunk, data + i,
7302
29.6k
                8);  // entices compiler to unconditionally process 8 characters
7303
7304
    // Check 8 characters at once
7305
166k
    for (size_t j = 0; j < 8; j++) {
7306
152k
      if (character_sets::bit_at(character_set, chunk[j])) {
7307
15.7k
        return i + j;
7308
15.7k
      }
7309
152k
    }
7310
29.6k
  }
7311
7312
  // Handle remaining bytes
7313
31.4k
  for (; i < size; i++) {
7314
27.2k
    if (character_sets::bit_at(character_set, data[i])) {
7315
8.27k
      return i;
7316
8.27k
    }
7317
27.2k
  }
7318
7319
4.20k
  return size;
7320
12.4k
}
7321
}  // namespace ada::unicode
7322
7323
#endif  // ADA_UNICODE_INL_H
7324
/* end file include/ada/unicode-inl.h */
7325
7326
#include <charconv>
7327
#include <ostream>
7328
#include <string_view>
7329
7330
namespace ada {
7331
7332
inline void url_aggregator::update_base_authority(
7333
293
    std::string_view base_buffer, const ada::url_components &base) {
7334
293
  std::string_view input = base_buffer.substr(
7335
293
      base.protocol_end, base.host_start - base.protocol_end);
7336
293
  ada_log("url_aggregator::update_base_authority ", input);
7337
7338
293
  bool input_starts_with_dash = input.starts_with("//");
7339
293
  uint32_t diff = components.host_start - components.protocol_end;
7340
7341
293
  buffer.erase(components.protocol_end,
7342
293
               components.host_start - components.protocol_end);
7343
293
  components.username_end = components.protocol_end;
7344
7345
293
  if (input_starts_with_dash) {
7346
199
    input.remove_prefix(2);
7347
199
    diff += 2;  // add "//"
7348
199
    buffer.insert(components.protocol_end, "//");
7349
199
    components.username_end += 2;
7350
199
  }
7351
7352
293
  size_t password_delimiter = input.find(':');
7353
7354
  // Check if input contains both username and password by checking the
7355
  // delimiter: ":" A typical input that contains authority would be "user:pass"
7356
293
  if (password_delimiter != std::string_view::npos) {
7357
    // Insert both username and password
7358
38
    std::string_view username = input.substr(0, password_delimiter);
7359
38
    std::string_view password = input.substr(password_delimiter + 1);
7360
7361
38
    buffer.insert(components.protocol_end + diff, username);
7362
38
    diff += uint32_t(username.size());
7363
38
    buffer.insert(components.protocol_end + diff, ":");
7364
38
    components.username_end = components.protocol_end + diff;
7365
38
    buffer.insert(components.protocol_end + diff + 1, password);
7366
38
    diff += uint32_t(password.size()) + 1;
7367
255
  } else if (!input.empty()) {
7368
    // Insert only username
7369
22
    buffer.insert(components.protocol_end + diff, input);
7370
22
    components.username_end =
7371
22
        components.protocol_end + diff + uint32_t(input.size());
7372
22
    diff += uint32_t(input.size());
7373
22
  }
7374
7375
293
  components.host_start += diff;
7376
7377
293
  if (buffer.size() > base.host_start && buffer[base.host_start] != '@') {
7378
0
    buffer.insert(components.host_start, "@");
7379
0
    diff++;
7380
0
  }
7381
293
  components.host_end += diff;
7382
293
  components.pathname_start += diff;
7383
293
  if (components.search_start != url_components::omitted) {
7384
0
    components.search_start += diff;
7385
0
  }
7386
293
  if (components.hash_start != url_components::omitted) {
7387
0
    components.hash_start += diff;
7388
0
  }
7389
293
}
7390
7391
16.2k
inline void url_aggregator::update_unencoded_base_hash(std::string_view input) {
7392
16.2k
  ada_log("url_aggregator::update_unencoded_base_hash ", input, " [",
7393
16.2k
          input.size(), " bytes], buffer is '", buffer, "' [", buffer.size(),
7394
16.2k
          " bytes] components.hash_start = ", components.hash_start);
7395
16.2k
  ADA_ASSERT_TRUE(validate());
7396
16.2k
  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
7397
16.2k
  if (components.hash_start != url_components::omitted) {
7398
329
    buffer.resize(components.hash_start);
7399
329
  }
7400
16.2k
  components.hash_start = uint32_t(buffer.size());
7401
16.2k
  buffer += "#";
7402
16.2k
  bool encoding_required = unicode::percent_encode<true>(
7403
16.2k
      input, ada::character_sets::FRAGMENT_PERCENT_ENCODE, buffer);
7404
  // When encoding_required is false, then buffer is left unchanged, and percent
7405
  // encoding was not deemed required.
7406
16.2k
  if (!encoding_required) {
7407
7.22k
    buffer.append(input);
7408
7.22k
  }
7409
16.2k
  ada_log("url_aggregator::update_unencoded_base_hash final buffer is '",
7410
16.2k
          buffer, "' [", buffer.size(), " bytes]");
7411
16.2k
  ADA_ASSERT_TRUE(validate());
7412
16.2k
}
7413
7414
ada_really_inline uint32_t url_aggregator::replace_and_resize(
7415
115k
    uint32_t start, uint32_t end, std::string_view input) {
7416
115k
  uint32_t current_length = end - start;
7417
115k
  uint32_t input_size = uint32_t(input.size());
7418
115k
  uint32_t new_difference = input_size - current_length;
7419
7420
115k
  if (current_length == 0) {
7421
92.1k
    buffer.insert(start, input);
7422
92.1k
  } else if (input_size == current_length) {
7423
3.96k
    buffer.replace(start, input_size, input);
7424
19.3k
  } else if (input_size < current_length) {
7425
13.2k
    buffer.erase(start, current_length - input_size);
7426
13.2k
    buffer.replace(start, input_size, input);
7427
13.2k
  } else {
7428
6.06k
    buffer.replace(start, current_length, input.substr(0, current_length));
7429
6.06k
    buffer.insert(start + current_length, input.substr(current_length));
7430
6.06k
  }
7431
7432
115k
  return new_difference;
7433
115k
}
7434
7435
60.9k
inline void url_aggregator::update_base_hostname(const std::string_view input) {
7436
60.9k
  ada_log("url_aggregator::update_base_hostname ", input, " [", input.size(),
7437
60.9k
          " bytes], buffer is '", buffer, "' [", buffer.size(), " bytes]");
7438
60.9k
  ADA_ASSERT_TRUE(validate());
7439
60.9k
  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
7440
7441
  // This next line is required for when parsing a URL like `foo://`
7442
60.9k
  add_authority_slashes_if_needed();
7443
7444
60.9k
  bool has_credentials = components.protocol_end + 2 < components.host_start;
7445
60.9k
  uint32_t new_difference =
7446
60.9k
      replace_and_resize(components.host_start, components.host_end, input);
7447
7448
60.9k
  if (has_credentials) {
7449
14.5k
    buffer.insert(components.host_start, "@");
7450
14.5k
    new_difference++;
7451
14.5k
  }
7452
60.9k
  components.host_end += new_difference;
7453
60.9k
  components.pathname_start += new_difference;
7454
60.9k
  if (components.search_start != url_components::omitted) {
7455
389
    components.search_start += new_difference;
7456
389
  }
7457
60.9k
  if (components.hash_start != url_components::omitted) {
7458
278
    components.hash_start += new_difference;
7459
278
  }
7460
60.9k
  ADA_ASSERT_TRUE(validate());
7461
60.9k
}
7462
7463
[[nodiscard]] ada_really_inline uint32_t
7464
42.1k
url_aggregator::get_pathname_length() const noexcept {
7465
42.1k
  ada_log("url_aggregator::get_pathname_length");
7466
42.1k
  uint32_t ending_index = uint32_t(buffer.size());
7467
42.1k
  if (components.search_start != url_components::omitted) {
7468
366
    ending_index = components.search_start;
7469
41.7k
  } else if (components.hash_start != url_components::omitted) {
7470
201
    ending_index = components.hash_start;
7471
201
  }
7472
42.1k
  return ending_index - components.pathname_start;
7473
42.1k
}
7474
7475
[[nodiscard]] ada_really_inline bool url_aggregator::is_at_path()
7476
5.94k
    const noexcept {
7477
5.94k
  return buffer.size() == components.pathname_start;
7478
5.94k
}
7479
7480
420
inline void url_aggregator::update_base_search(std::string_view input) {
7481
420
  ada_log("url_aggregator::update_base_search ", input);
7482
420
  ADA_ASSERT_TRUE(validate());
7483
420
  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
7484
420
  if (input.empty()) {
7485
420
    clear_search();
7486
420
    return;
7487
420
  }
7488
7489
0
  if (input[0] == '?') {
7490
0
    input.remove_prefix(1);
7491
0
  }
7492
7493
0
  if (components.hash_start == url_components::omitted) {
7494
0
    if (components.search_start == url_components::omitted) {
7495
0
      components.search_start = uint32_t(buffer.size());
7496
0
      buffer += "?";
7497
0
    } else {
7498
0
      buffer.resize(components.search_start + 1);
7499
0
    }
7500
7501
0
    buffer.append(input);
7502
0
  } else {
7503
0
    if (components.search_start == url_components::omitted) {
7504
0
      components.search_start = components.hash_start;
7505
0
    } else {
7506
0
      buffer.erase(components.search_start,
7507
0
                   components.hash_start - components.search_start);
7508
0
      components.hash_start = components.search_start;
7509
0
    }
7510
7511
0
    buffer.insert(components.search_start, "?");
7512
0
    buffer.insert(components.search_start + 1, input);
7513
0
    components.hash_start += uint32_t(input.size() + 1);  // Do not forget `?`
7514
0
  }
7515
7516
0
  ADA_ASSERT_TRUE(validate());
7517
0
}
7518
7519
inline void url_aggregator::update_base_search(
7520
16.3k
    std::string_view input, const uint8_t query_percent_encode_set[]) {
7521
16.3k
  ada_log("url_aggregator::update_base_search ", input,
7522
16.3k
          " with encoding parameter ", to_string(), "\n", to_diagram());
7523
16.3k
  ADA_ASSERT_TRUE(validate());
7524
16.3k
  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
7525
7526
16.3k
  if (components.hash_start == url_components::omitted) {
7527
16.0k
    if (components.search_start == url_components::omitted) {
7528
15.7k
      components.search_start = uint32_t(buffer.size());
7529
15.7k
      buffer += "?";
7530
15.7k
    } else {
7531
357
      buffer.resize(components.search_start + 1);
7532
357
    }
7533
7534
16.0k
    bool encoding_required =
7535
16.0k
        unicode::percent_encode<true>(input, query_percent_encode_set, buffer);
7536
    // When encoding_required is false, then buffer is left unchanged, and
7537
    // percent encoding was not deemed required.
7538
16.0k
    if (!encoding_required) {
7539
7.08k
      buffer.append(input);
7540
7.08k
    }
7541
16.0k
  } else {
7542
329
    if (components.search_start == url_components::omitted) {
7543
257
      components.search_start = components.hash_start;
7544
257
    } else {
7545
72
      buffer.erase(components.search_start,
7546
72
                   components.hash_start - components.search_start);
7547
72
      components.hash_start = components.search_start;
7548
72
    }
7549
7550
329
    buffer.insert(components.search_start, "?");
7551
329
    size_t idx =
7552
329
        ada::unicode::percent_encode_index(input, query_percent_encode_set);
7553
329
    if (idx == input.size()) {
7554
0
      buffer.insert(components.search_start + 1, input);
7555
0
      components.hash_start += uint32_t(input.size() + 1);  // Do not forget `?`
7556
329
    } else {
7557
329
      buffer.insert(components.search_start + 1, input, 0, idx);
7558
329
      input.remove_prefix(idx);
7559
      // We only create a temporary string if we need percent encoding and
7560
      // we attempt to create as small a temporary string as we can.
7561
329
      std::string encoded =
7562
329
          ada::unicode::percent_encode(input, query_percent_encode_set);
7563
329
      buffer.insert(components.search_start + idx + 1, encoded);
7564
329
      components.hash_start +=
7565
329
          uint32_t(encoded.size() + idx + 1);  // Do not forget `?`
7566
329
    }
7567
329
  }
7568
7569
16.3k
  ADA_ASSERT_TRUE(validate());
7570
16.3k
}
7571
7572
42.1k
inline void url_aggregator::update_base_pathname(const std::string_view input) {
7573
42.1k
  ada_log("url_aggregator::update_base_pathname '", input, "' [", input.size(),
7574
42.1k
          " bytes] \n", to_diagram());
7575
42.1k
  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
7576
42.1k
  ADA_ASSERT_TRUE(validate());
7577
7578
42.1k
  const bool begins_with_dashdash = input.starts_with("//");
7579
42.1k
  if (!begins_with_dashdash && has_dash_dot()) {
7580
    // We must delete the ./
7581
0
    delete_dash_dot();
7582
0
  }
7583
7584
42.1k
  if (begins_with_dashdash && !has_opaque_path && !has_authority() &&
7585
42.1k
      !has_dash_dot()) {
7586
    // If url's host is null, url does not have an opaque path, url's path's
7587
    // size is greater than 1, then append U+002F (/) followed by U+002E (.) to
7588
    // output.
7589
112
    buffer.insert(components.pathname_start, "/.");
7590
112
    components.pathname_start += 2;
7591
112
  }
7592
7593
42.1k
  uint32_t difference = replace_and_resize(
7594
42.1k
      components.pathname_start,
7595
42.1k
      components.pathname_start + get_pathname_length(), input);
7596
42.1k
  if (components.search_start != url_components::omitted) {
7597
366
    components.search_start += difference;
7598
366
  }
7599
42.1k
  if (components.hash_start != url_components::omitted) {
7600
266
    components.hash_start += difference;
7601
266
  }
7602
42.1k
  ADA_ASSERT_TRUE(validate());
7603
42.1k
}
7604
7605
0
inline void url_aggregator::append_base_pathname(const std::string_view input) {
7606
0
  ada_log("url_aggregator::append_base_pathname ", input, " ", to_string(),
7607
0
          "\n", to_diagram());
7608
0
  ADA_ASSERT_TRUE(validate());
7609
0
  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
7610
#if ADA_DEVELOPMENT_CHECKS
7611
  // computing the expected password.
7612
  std::string path_expected(get_pathname());
7613
  path_expected.append(input);
7614
#endif  // ADA_DEVELOPMENT_CHECKS
7615
0
  uint32_t ending_index = uint32_t(buffer.size());
7616
0
  if (components.search_start != url_components::omitted) {
7617
0
    ending_index = components.search_start;
7618
0
  } else if (components.hash_start != url_components::omitted) {
7619
0
    ending_index = components.hash_start;
7620
0
  }
7621
0
  buffer.insert(ending_index, input);
7622
7623
0
  if (components.search_start != url_components::omitted) {
7624
0
    components.search_start += uint32_t(input.size());
7625
0
  }
7626
0
  if (components.hash_start != url_components::omitted) {
7627
0
    components.hash_start += uint32_t(input.size());
7628
0
  }
7629
#if ADA_DEVELOPMENT_CHECKS
7630
  std::string path_after = std::string(get_pathname());
7631
  ADA_ASSERT_EQUAL(
7632
      path_expected, path_after,
7633
      "append_base_pathname problem after inserting " + std::string(input));
7634
#endif  // ADA_DEVELOPMENT_CHECKS
7635
0
  ADA_ASSERT_TRUE(validate());
7636
0
}
7637
7638
12.4k
inline void url_aggregator::update_base_username(const std::string_view input) {
7639
12.4k
  ada_log("url_aggregator::update_base_username '", input, "' ", to_string(),
7640
12.4k
          "\n", to_diagram());
7641
12.4k
  ADA_ASSERT_TRUE(validate());
7642
12.4k
  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
7643
7644
12.4k
  add_authority_slashes_if_needed();
7645
7646
12.4k
  bool has_password = has_non_empty_password();
7647
12.4k
  bool host_starts_with_at = buffer.size() > components.host_start &&
7648
12.4k
                             buffer[components.host_start] == '@';
7649
12.4k
  uint32_t diff = replace_and_resize(components.protocol_end + 2,
7650
12.4k
                                     components.username_end, input);
7651
7652
12.4k
  components.username_end += diff;
7653
12.4k
  components.host_start += diff;
7654
7655
12.4k
  if (!input.empty() && !host_starts_with_at) {
7656
12.0k
    buffer.insert(components.host_start, "@");
7657
12.0k
    diff++;
7658
12.0k
  } else if (input.empty() && host_starts_with_at && !has_password) {
7659
    // Input is empty, there is no password, and we need to remove "@" from
7660
    // hostname
7661
0
    buffer.erase(components.host_start, 1);
7662
0
    diff--;
7663
0
  }
7664
7665
12.4k
  components.host_end += diff;
7666
12.4k
  components.pathname_start += diff;
7667
12.4k
  if (components.search_start != url_components::omitted) {
7668
339
    components.search_start += diff;
7669
339
  }
7670
12.4k
  if (components.hash_start != url_components::omitted) {
7671
250
    components.hash_start += diff;
7672
250
  }
7673
12.4k
  ADA_ASSERT_TRUE(validate());
7674
12.4k
}
7675
7676
37.0k
inline void url_aggregator::append_base_username(const std::string_view input) {
7677
37.0k
  ada_log("url_aggregator::append_base_username ", input);
7678
37.0k
  ADA_ASSERT_TRUE(validate());
7679
37.0k
  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
7680
#if ADA_DEVELOPMENT_CHECKS
7681
  // computing the expected password.
7682
  std::string username_expected(get_username());
7683
  username_expected.append(input);
7684
#endif  // ADA_DEVELOPMENT_CHECKS
7685
37.0k
  add_authority_slashes_if_needed();
7686
7687
  // If input is empty, do nothing.
7688
37.0k
  if (input.empty()) {
7689
9.71k
    return;
7690
9.71k
  }
7691
7692
27.3k
  uint32_t difference = uint32_t(input.size());
7693
27.3k
  buffer.insert(components.username_end, input);
7694
27.3k
  components.username_end += difference;
7695
27.3k
  components.host_start += difference;
7696
7697
27.3k
  if (buffer[components.host_start] != '@' &&
7698
27.3k
      components.host_start != components.host_end) {
7699
1.55k
    buffer.insert(components.host_start, "@");
7700
1.55k
    difference++;
7701
1.55k
  }
7702
7703
27.3k
  components.host_end += difference;
7704
27.3k
  components.pathname_start += difference;
7705
27.3k
  if (components.search_start != url_components::omitted) {
7706
0
    components.search_start += difference;
7707
0
  }
7708
27.3k
  if (components.hash_start != url_components::omitted) {
7709
0
    components.hash_start += difference;
7710
0
  }
7711
#if ADA_DEVELOPMENT_CHECKS
7712
  std::string username_after(get_username());
7713
  ADA_ASSERT_EQUAL(
7714
      username_expected, username_after,
7715
      "append_base_username problem after inserting " + std::string(input));
7716
#endif  // ADA_DEVELOPMENT_CHECKS
7717
27.3k
  ADA_ASSERT_TRUE(validate());
7718
27.3k
}
7719
7720
6
constexpr void url_aggregator::clear_password() {
7721
6
  ada_log("url_aggregator::clear_password ", to_string());
7722
6
  ADA_ASSERT_TRUE(validate());
7723
6
  if (!has_password()) {
7724
6
    return;
7725
6
  }
7726
7727
0
  uint32_t diff = components.host_start - components.username_end;
7728
0
  buffer.erase(components.username_end, diff);
7729
0
  components.host_start -= diff;
7730
0
  components.host_end -= diff;
7731
0
  components.pathname_start -= diff;
7732
0
  if (components.search_start != url_components::omitted) {
7733
0
    components.search_start -= diff;
7734
0
  }
7735
0
  if (components.hash_start != url_components::omitted) {
7736
0
    components.hash_start -= diff;
7737
0
  }
7738
0
}
7739
7740
12.4k
inline void url_aggregator::update_base_password(const std::string_view input) {
7741
12.4k
  ada_log("url_aggregator::update_base_password ", input);
7742
12.4k
  ADA_ASSERT_TRUE(validate());
7743
12.4k
  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
7744
7745
12.4k
  add_authority_slashes_if_needed();
7746
7747
  // TODO: Optimization opportunity. Merge the following removal functions.
7748
12.4k
  if (input.empty()) {
7749
6
    clear_password();
7750
7751
    // Remove username too, if it is empty.
7752
6
    if (!has_non_empty_username()) {
7753
6
      update_base_username("");
7754
6
    }
7755
7756
6
    return;
7757
6
  }
7758
7759
12.4k
  bool password_exists = has_password();
7760
12.4k
  uint32_t difference = uint32_t(input.size());
7761
7762
12.4k
  if (password_exists) {
7763
141
    uint32_t current_length =
7764
141
        components.host_start - components.username_end - 1;
7765
141
    buffer.erase(components.username_end + 1, current_length);
7766
141
    difference -= current_length;
7767
12.2k
  } else {
7768
12.2k
    buffer.insert(components.username_end, ":");
7769
12.2k
    difference++;
7770
12.2k
  }
7771
7772
12.4k
  buffer.insert(components.username_end + 1, input);
7773
12.4k
  components.host_start += difference;
7774
7775
  // The following line is required to add "@" to hostname. When updating
7776
  // password if hostname does not start with "@", it is "update_base_password"s
7777
  // responsibility to set it.
7778
12.4k
  if (buffer[components.host_start] != '@') {
7779
0
    buffer.insert(components.host_start, "@");
7780
0
    difference++;
7781
0
  }
7782
7783
12.4k
  components.host_end += difference;
7784
12.4k
  components.pathname_start += difference;
7785
12.4k
  if (components.search_start != url_components::omitted) {
7786
339
    components.search_start += difference;
7787
339
  }
7788
12.4k
  if (components.hash_start != url_components::omitted) {
7789
250
    components.hash_start += difference;
7790
250
  }
7791
12.4k
  ADA_ASSERT_TRUE(validate());
7792
12.4k
}
7793
7794
22.3k
inline void url_aggregator::append_base_password(const std::string_view input) {
7795
22.3k
  ada_log("url_aggregator::append_base_password ", input, " ", to_string(),
7796
22.3k
          "\n", to_diagram());
7797
22.3k
  ADA_ASSERT_TRUE(validate());
7798
22.3k
  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
7799
#if ADA_DEVELOPMENT_CHECKS
7800
  // computing the expected password.
7801
  std::string password_expected = std::string(get_password());
7802
  password_expected.append(input);
7803
#endif  // ADA_DEVELOPMENT_CHECKS
7804
22.3k
  add_authority_slashes_if_needed();
7805
7806
  // If input is empty, do nothing.
7807
22.3k
  if (input.empty()) {
7808
6.23k
    return;
7809
6.23k
  }
7810
7811
16.1k
  uint32_t difference = uint32_t(input.size());
7812
16.1k
  if (has_password()) {
7813
15.3k
    buffer.insert(components.host_start, input);
7814
15.3k
  } else {
7815
792
    difference++;  // Increment for ":"
7816
792
    buffer.insert(components.username_end, ":");
7817
792
    buffer.insert(components.username_end + 1, input);
7818
792
  }
7819
16.1k
  components.host_start += difference;
7820
7821
  // The following line is required to add "@" to hostname. When updating
7822
  // password if hostname does not start with "@", it is "append_base_password"s
7823
  // responsibility to set it.
7824
16.1k
  if (buffer[components.host_start] != '@') {
7825
563
    buffer.insert(components.host_start, "@");
7826
563
    difference++;
7827
563
  }
7828
7829
16.1k
  components.host_end += difference;
7830
16.1k
  components.pathname_start += difference;
7831
16.1k
  if (components.search_start != url_components::omitted) {
7832
0
    components.search_start += difference;
7833
0
  }
7834
16.1k
  if (components.hash_start != url_components::omitted) {
7835
0
    components.hash_start += difference;
7836
0
  }
7837
#if ADA_DEVELOPMENT_CHECKS
7838
  std::string password_after(get_password());
7839
  ADA_ASSERT_EQUAL(
7840
      password_expected, password_after,
7841
      "append_base_password problem after inserting " + std::string(input));
7842
#endif  // ADA_DEVELOPMENT_CHECKS
7843
16.1k
  ADA_ASSERT_TRUE(validate());
7844
16.1k
}
7845
7846
10.5k
inline void url_aggregator::update_base_port(uint32_t input) {
7847
10.5k
  ada_log("url_aggregator::update_base_port");
7848
10.5k
  ADA_ASSERT_TRUE(validate());
7849
10.5k
  if (input == url_components::omitted) {
7850
8.15k
    clear_port();
7851
8.15k
    return;
7852
8.15k
  }
7853
  // calling std::to_string(input.value()) is unfortunate given that the port
7854
  // value is probably already available as a string.
7855
2.44k
  std::string value = helpers::concat(":", std::to_string(input));
7856
2.44k
  uint32_t difference = uint32_t(value.size());
7857
7858
2.44k
  if (components.port != url_components::omitted) {
7859
94
    difference -= components.pathname_start - components.host_end;
7860
94
    buffer.erase(components.host_end,
7861
94
                 components.pathname_start - components.host_end);
7862
94
  }
7863
7864
2.44k
  buffer.insert(components.host_end, value);
7865
2.44k
  components.pathname_start += difference;
7866
2.44k
  if (components.search_start != url_components::omitted) {
7867
636
    components.search_start += difference;
7868
636
  }
7869
2.44k
  if (components.hash_start != url_components::omitted) {
7870
617
    components.hash_start += difference;
7871
617
  }
7872
2.44k
  components.port = input;
7873
2.44k
  ADA_ASSERT_TRUE(validate());
7874
2.44k
}
7875
7876
25.5k
inline void url_aggregator::clear_port() {
7877
25.5k
  ada_log("url_aggregator::clear_port");
7878
25.5k
  ADA_ASSERT_TRUE(validate());
7879
25.5k
  if (components.port == url_components::omitted) {
7880
23.8k
    return;
7881
23.8k
  }
7882
1.74k
  uint32_t length = components.pathname_start - components.host_end;
7883
1.74k
  buffer.erase(components.host_end, length);
7884
1.74k
  components.pathname_start -= length;
7885
1.74k
  if (components.search_start != url_components::omitted) {
7886
1.70k
    components.search_start -= length;
7887
1.70k
  }
7888
1.74k
  if (components.hash_start != url_components::omitted) {
7889
1.69k
    components.hash_start -= length;
7890
1.69k
  }
7891
1.74k
  components.port = url_components::omitted;
7892
1.74k
  ADA_ASSERT_TRUE(validate());
7893
1.74k
}
7894
7895
293
[[nodiscard]] inline uint32_t url_aggregator::retrieve_base_port() const {
7896
293
  ada_log("url_aggregator::retrieve_base_port");
7897
293
  return components.port;
7898
293
}
7899
7900
15.9k
inline void url_aggregator::clear_search() {
7901
15.9k
  ada_log("url_aggregator::clear_search");
7902
15.9k
  ADA_ASSERT_TRUE(validate());
7903
15.9k
  if (components.search_start == url_components::omitted) {
7904
607
    return;
7905
607
  }
7906
7907
15.2k
  if (components.hash_start == url_components::omitted) {
7908
6.41k
    buffer.resize(components.search_start);
7909
8.88k
  } else {
7910
8.88k
    buffer.erase(components.search_start,
7911
8.88k
                 components.hash_start - components.search_start);
7912
8.88k
    components.hash_start = components.search_start;
7913
8.88k
  }
7914
7915
15.2k
  components.search_start = url_components::omitted;
7916
7917
#if ADA_DEVELOPMENT_CHECKS
7918
  ADA_ASSERT_EQUAL(get_search(), "",
7919
                   "search should have been cleared on buffer=" + buffer +
7920
                       " with " + components.to_string() + "\n" + to_diagram());
7921
#endif
7922
15.2k
  ADA_ASSERT_TRUE(validate());
7923
15.2k
}
7924
7925
15.3k
inline void url_aggregator::clear_hash() {
7926
15.3k
  ada_log("url_aggregator::clear_hash");
7927
15.3k
  ADA_ASSERT_TRUE(validate());
7928
15.3k
  if (components.hash_start == url_components::omitted) {
7929
6
    return;
7930
6
  }
7931
15.2k
  buffer.resize(components.hash_start);
7932
15.2k
  components.hash_start = url_components::omitted;
7933
7934
#if ADA_DEVELOPMENT_CHECKS
7935
  ADA_ASSERT_EQUAL(get_hash(), "",
7936
                   "hash should have been cleared on buffer=" + buffer +
7937
                       " with " + components.to_string() + "\n" + to_diagram());
7938
#endif
7939
15.2k
  ADA_ASSERT_TRUE(validate());
7940
15.2k
}
7941
7942
14.0k
constexpr void url_aggregator::clear_pathname() {
7943
14.0k
  ada_log("url_aggregator::clear_pathname");
7944
14.0k
  ADA_ASSERT_TRUE(validate());
7945
14.0k
  uint32_t ending_index = uint32_t(buffer.size());
7946
14.0k
  if (components.search_start != url_components::omitted) {
7947
366
    ending_index = components.search_start;
7948
13.6k
  } else if (components.hash_start != url_components::omitted) {
7949
201
    ending_index = components.hash_start;
7950
201
  }
7951
14.0k
  uint32_t pathname_length = ending_index - components.pathname_start;
7952
14.0k
  buffer.erase(components.pathname_start, pathname_length);
7953
14.0k
  uint32_t difference = pathname_length;
7954
14.0k
  if (components.pathname_start == components.host_end + 2 &&
7955
14.0k
      buffer[components.host_end] == '/' &&
7956
14.0k
      buffer[components.host_end + 1] == '.') {
7957
44
    components.pathname_start -= 2;
7958
44
    buffer.erase(components.host_end, 2);
7959
44
    difference += 2;
7960
44
  }
7961
14.0k
  if (components.search_start != url_components::omitted) {
7962
366
    components.search_start -= difference;
7963
366
  }
7964
14.0k
  if (components.hash_start != url_components::omitted) {
7965
266
    components.hash_start -= difference;
7966
266
  }
7967
14.0k
  ada_log("url_aggregator::clear_pathname completed, running checks...");
7968
#if ADA_DEVELOPMENT_CHECKS
7969
  ADA_ASSERT_EQUAL(get_pathname(), "",
7970
                   "pathname should have been cleared on buffer=" + buffer +
7971
                       " with " + components.to_string() + "\n" + to_diagram());
7972
#endif
7973
14.0k
  ADA_ASSERT_TRUE(validate());
7974
14.0k
  ada_log("url_aggregator::clear_pathname completed, running checks... ok");
7975
14.0k
}
7976
7977
2
constexpr void url_aggregator::clear_hostname() {
7978
2
  ada_log("url_aggregator::clear_hostname");
7979
2
  ADA_ASSERT_TRUE(validate());
7980
2
  if (!has_authority()) {
7981
0
    return;
7982
0
  }
7983
2
  ADA_ASSERT_TRUE(has_authority());
7984
7985
2
  uint32_t hostname_length = components.host_end - components.host_start;
7986
2
  uint32_t start = components.host_start;
7987
7988
  // If hostname starts with "@", we should not remove that character.
7989
2
  if (hostname_length > 0 && buffer[start] == '@') {
7990
0
    start++;
7991
0
    hostname_length--;
7992
0
  }
7993
2
  buffer.erase(start, hostname_length);
7994
2
  components.host_end = start;
7995
2
  components.pathname_start -= hostname_length;
7996
2
  if (components.search_start != url_components::omitted) {
7997
0
    components.search_start -= hostname_length;
7998
0
  }
7999
2
  if (components.hash_start != url_components::omitted) {
8000
0
    components.hash_start -= hostname_length;
8001
0
  }
8002
#if ADA_DEVELOPMENT_CHECKS
8003
  ADA_ASSERT_EQUAL(get_hostname(), "",
8004
                   "hostname should have been cleared on buffer=" + buffer +
8005
                       " with " + components.to_string() + "\n" + to_diagram());
8006
#endif
8007
2
  ADA_ASSERT_TRUE(has_authority());
8008
2
  ADA_ASSERT_EQUAL(has_empty_hostname(), true,
8009
2
                   "hostname should have been cleared on buffer=" + buffer +
8010
2
                       " with " + components.to_string() + "\n" + to_diagram());
8011
2
  ADA_ASSERT_TRUE(validate());
8012
2
}
8013
8014
6.41k
[[nodiscard]] constexpr bool url_aggregator::has_hash() const noexcept {
8015
6.41k
  ada_log("url_aggregator::has_hash");
8016
6.41k
  return components.hash_start != url_components::omitted;
8017
6.41k
}
8018
8019
6.41k
[[nodiscard]] constexpr bool url_aggregator::has_search() const noexcept {
8020
6.41k
  ada_log("url_aggregator::has_search");
8021
6.41k
  return components.search_start != url_components::omitted;
8022
6.41k
}
8023
8024
20.8k
constexpr bool url_aggregator::has_credentials() const noexcept {
8025
20.8k
  ada_log("url_aggregator::has_credentials");
8026
20.8k
  return has_non_empty_username() || has_non_empty_password();
8027
20.8k
}
8028
8029
52.5k
constexpr bool url_aggregator::cannot_have_credentials_or_port() const {
8030
52.5k
  ada_log("url_aggregator::cannot_have_credentials_or_port");
8031
52.5k
  return type == ada::scheme::type::FILE ||
8032
52.5k
         components.host_start == components.host_end;
8033
52.5k
}
8034
8035
[[nodiscard]] ada_really_inline const ada::url_components &
8036
6.70k
url_aggregator::get_components() const noexcept {
8037
6.70k
  return components;
8038
6.70k
}
8039
8040
[[nodiscard]] constexpr bool ada::url_aggregator::has_authority()
8041
165k
    const noexcept {
8042
165k
  ada_log("url_aggregator::has_authority");
8043
  // Performance: instead of doing this potentially expensive check, we could
8044
  // have a boolean in the struct.
8045
165k
  return components.protocol_end + 2 <= components.host_start &&
8046
165k
         helpers::substring(buffer, components.protocol_end,
8047
124k
                            components.protocol_end + 2) == "//";
8048
165k
}
8049
8050
145k
inline void ada::url_aggregator::add_authority_slashes_if_needed() noexcept {
8051
145k
  ada_log("url_aggregator::add_authority_slashes_if_needed");
8052
145k
  ADA_ASSERT_TRUE(validate());
8053
  // Protocol setter will insert `http:` to the URL. It is up to hostname setter
8054
  // to insert
8055
  // `//` initially to the buffer, since it depends on the hostname existence.
8056
145k
  if (has_authority()) {
8057
108k
    return;
8058
108k
  }
8059
  // Performance: the common case is components.protocol_end == buffer.size()
8060
  // Optimization opportunity: in many cases, the "//" is part of the input and
8061
  // the insert could be fused with another insert.
8062
36.5k
  buffer.insert(components.protocol_end, "//");
8063
36.5k
  components.username_end += 2;
8064
36.5k
  components.host_start += 2;
8065
36.5k
  components.host_end += 2;
8066
36.5k
  components.pathname_start += 2;
8067
36.5k
  if (components.search_start != url_components::omitted) {
8068
134
    components.search_start += 2;
8069
134
  }
8070
36.5k
  if (components.hash_start != url_components::omitted) {
8071
96
    components.hash_start += 2;
8072
96
  }
8073
36.5k
  ADA_ASSERT_TRUE(validate());
8074
36.5k
}
8075
8076
40.2k
constexpr void ada::url_aggregator::reserve(uint32_t capacity) {
8077
40.2k
  buffer.reserve(capacity);
8078
40.2k
}
8079
8080
48.9k
constexpr bool url_aggregator::has_non_empty_username() const noexcept {
8081
48.9k
  ada_log("url_aggregator::has_non_empty_username");
8082
48.9k
  return components.protocol_end + 2 < components.username_end;
8083
48.9k
}
8084
8085
50.5k
constexpr bool url_aggregator::has_non_empty_password() const noexcept {
8086
50.5k
  ada_log("url_aggregator::has_non_empty_password");
8087
50.5k
  return components.host_start - components.username_end > 0;
8088
50.5k
}
8089
8090
34.9k
constexpr bool url_aggregator::has_password() const noexcept {
8091
34.9k
  ada_log("url_aggregator::has_password");
8092
  // This function does not care about the length of the password
8093
34.9k
  return components.host_start > components.username_end &&
8094
34.9k
         buffer[components.username_end] == ':';
8095
34.9k
}
8096
8097
6.41k
constexpr bool url_aggregator::has_empty_hostname() const noexcept {
8098
6.41k
  if (!has_hostname()) {
8099
1.29k
    return false;
8100
1.29k
  }
8101
5.11k
  if (components.host_start == components.host_end) {
8102
562
    return true;
8103
562
  }
8104
4.55k
  if (components.host_end > components.host_start + 1) {
8105
4.52k
    return false;
8106
4.52k
  }
8107
31
  return components.username_end != components.host_start;
8108
4.55k
}
8109
8110
19.3k
constexpr bool url_aggregator::has_hostname() const noexcept {
8111
19.3k
  return has_authority();
8112
19.3k
}
8113
8114
6.41k
constexpr bool url_aggregator::has_port() const noexcept {
8115
6.41k
  ada_log("url_aggregator::has_port");
8116
  // A URL cannot have a username/password/port if its host is null or the empty
8117
  // string, or its scheme is "file".
8118
6.41k
  return has_hostname() && components.pathname_start != components.host_end;
8119
6.41k
}
8120
8121
46.3k
[[nodiscard]] constexpr bool url_aggregator::has_dash_dot() const noexcept {
8122
  // If url's host is null, url does not have an opaque path, url's path's size
8123
  // is greater than 1, and url's path[0] is the empty string, then append
8124
  // U+002F (/) followed by U+002E (.) to output.
8125
46.3k
  ada_log("url_aggregator::has_dash_dot");
8126
#if ADA_DEVELOPMENT_CHECKS
8127
  // If pathname_start and host_end are exactly two characters apart, then we
8128
  // either have a one-digit port such as http://test.com:5?param=1 or else we
8129
  // have a /.: sequence such as "non-spec:/.//". We test that this is the case.
8130
  if (components.pathname_start == components.host_end + 2) {
8131
    ADA_ASSERT_TRUE((buffer[components.host_end] == '/' &&
8132
                     buffer[components.host_end + 1] == '.') ||
8133
                    (buffer[components.host_end] == ':' &&
8134
                     checkers::is_digit(buffer[components.host_end + 1])));
8135
  }
8136
  if (components.pathname_start == components.host_end + 2 &&
8137
      buffer[components.host_end] == '/' &&
8138
      buffer[components.host_end + 1] == '.') {
8139
    ADA_ASSERT_TRUE(components.pathname_start + 1 < buffer.size());
8140
    ADA_ASSERT_TRUE(buffer[components.pathname_start] == '/');
8141
    ADA_ASSERT_TRUE(buffer[components.pathname_start + 1] == '/');
8142
  }
8143
#endif
8144
  // Performance: it should be uncommon for components.pathname_start ==
8145
  // components.host_end + 2 to be true. So we put this check first in the
8146
  // sequence. Most times, we do not have an opaque path. Checking for '/.' is
8147
  // more expensive, but should be uncommon.
8148
46.3k
  return components.pathname_start == components.host_end + 2 &&
8149
46.3k
         !has_opaque_path && buffer[components.host_end] == '/' &&
8150
46.3k
         buffer[components.host_end + 1] == '.';
8151
46.3k
}
8152
8153
[[nodiscard]] constexpr std::string_view url_aggregator::get_href()
8154
15.4k
    const noexcept ada_lifetime_bound {
8155
15.4k
  ada_log("url_aggregator::get_href");
8156
15.4k
  return buffer;
8157
15.4k
}
8158
8159
ada_really_inline size_t url_aggregator::parse_port(
8160
5.55k
    std::string_view view, bool check_trailing_content) noexcept {
8161
5.55k
  ada_log("url_aggregator::parse_port('", view, "') ", view.size());
8162
5.55k
  if (!view.empty() && view[0] == '-') {
8163
13
    ada_log("parse_port: view[0] == '0' && view.size() > 1");
8164
13
    is_valid = false;
8165
13
    return 0;
8166
13
  }
8167
5.54k
  uint16_t parsed_port{};
8168
5.54k
  auto r = std::from_chars(view.data(), view.data() + view.size(), parsed_port);
8169
5.54k
  if (r.ec == std::errc::result_out_of_range) {
8170
381
    ada_log("parse_port: r.ec == std::errc::result_out_of_range");
8171
381
    is_valid = false;
8172
381
    return 0;
8173
381
  }
8174
5.16k
  ada_log("parse_port: ", parsed_port);
8175
5.16k
  const size_t consumed = size_t(r.ptr - view.data());
8176
5.16k
  ada_log("parse_port: consumed ", consumed);
8177
5.16k
  if (check_trailing_content) {
8178
3.16k
    is_valid &=
8179
3.16k
        (consumed == view.size() || view[consumed] == '/' ||
8180
3.16k
         view[consumed] == '?' || (is_special() && view[consumed] == '\\'));
8181
3.16k
  }
8182
5.16k
  ada_log("parse_port: is_valid = ", is_valid);
8183
5.16k
  if (is_valid) {
8184
4.46k
    ada_log("parse_port", r.ec == std::errc());
8185
    // scheme_default_port can return 0, and we should allow 0 as a base port.
8186
4.46k
    auto default_port = scheme_default_port();
8187
4.46k
    bool is_port_valid = (default_port == 0 && parsed_port == 0) ||
8188
4.46k
                         (default_port != parsed_port);
8189
4.46k
    if (r.ec == std::errc() && is_port_valid) {
8190
2.39k
      update_base_port(parsed_port);
8191
2.39k
    } else {
8192
2.06k
      clear_port();
8193
2.06k
    }
8194
4.46k
  }
8195
5.16k
  return consumed;
8196
5.54k
}
8197
8198
5.24k
constexpr void url_aggregator::set_protocol_as_file() {
8199
5.24k
  ada_log("url_aggregator::set_protocol_as_file ");
8200
5.24k
  ADA_ASSERT_TRUE(validate());
8201
5.24k
  type = ada::scheme::type::FILE;
8202
  // next line could overflow but unsigned arithmetic has well-defined
8203
  // overflows.
8204
5.24k
  uint32_t new_difference = 5 - components.protocol_end;
8205
8206
5.24k
  if (buffer.empty()) {
8207
103
    buffer.append("file:");
8208
5.13k
  } else {
8209
5.13k
    buffer.erase(0, components.protocol_end);
8210
5.13k
    buffer.insert(0, "file:");
8211
5.13k
  }
8212
5.24k
  components.protocol_end = 5;
8213
8214
  // Update the rest of the components.
8215
5.24k
  components.username_end += new_difference;
8216
5.24k
  components.host_start += new_difference;
8217
5.24k
  components.host_end += new_difference;
8218
5.24k
  components.pathname_start += new_difference;
8219
5.24k
  if (components.search_start != url_components::omitted) {
8220
0
    components.search_start += new_difference;
8221
0
  }
8222
5.24k
  if (components.hash_start != url_components::omitted) {
8223
0
    components.hash_start += new_difference;
8224
0
  }
8225
5.24k
  ADA_ASSERT_TRUE(validate());
8226
5.24k
}
8227
8228
11.8k
[[nodiscard]] constexpr bool url_aggregator::validate() const noexcept {
8229
11.8k
  if (!is_valid) {
8230
2.47k
    return true;
8231
2.47k
  }
8232
9.33k
  if (!components.check_offset_consistency()) {
8233
0
    ada_log("url_aggregator::validate inconsistent components \n",
8234
0
            to_diagram());
8235
0
    return false;
8236
0
  }
8237
  // We have a credible components struct, but let us investivate more
8238
  // carefully:
8239
  /**
8240
   * https://user:pass@example.com:1234/foo/bar?baz#quux
8241
   *       |     |    |          | ^^^^|       |   |
8242
   *       |     |    |          | |   |       |   `----- hash_start
8243
   *       |     |    |          | |   |       `--------- search_start
8244
   *       |     |    |          | |   `----------------- pathname_start
8245
   *       |     |    |          | `--------------------- port
8246
   *       |     |    |          `----------------------- host_end
8247
   *       |     |    `---------------------------------- host_start
8248
   *       |     `--------------------------------------- username_end
8249
   *       `--------------------------------------------- protocol_end
8250
   */
8251
9.33k
  if (components.protocol_end == url_components::omitted) {
8252
0
    ada_log("url_aggregator::validate omitted protocol_end \n", to_diagram());
8253
0
    return false;
8254
0
  }
8255
9.33k
  if (components.username_end == url_components::omitted) {
8256
0
    ada_log("url_aggregator::validate omitted username_end \n", to_diagram());
8257
0
    return false;
8258
0
  }
8259
9.33k
  if (components.host_start == url_components::omitted) {
8260
0
    ada_log("url_aggregator::validate omitted host_start \n", to_diagram());
8261
0
    return false;
8262
0
  }
8263
9.33k
  if (components.host_end == url_components::omitted) {
8264
0
    ada_log("url_aggregator::validate omitted host_end \n", to_diagram());
8265
0
    return false;
8266
0
  }
8267
9.33k
  if (components.pathname_start == url_components::omitted) {
8268
0
    ada_log("url_aggregator::validate omitted pathname_start \n", to_diagram());
8269
0
    return false;
8270
0
  }
8271
8272
9.33k
  if (components.protocol_end > buffer.size()) {
8273
0
    ada_log("url_aggregator::validate protocol_end overflow \n", to_diagram());
8274
0
    return false;
8275
0
  }
8276
9.33k
  if (components.username_end > buffer.size()) {
8277
0
    ada_log("url_aggregator::validate username_end overflow \n", to_diagram());
8278
0
    return false;
8279
0
  }
8280
9.33k
  if (components.host_start > buffer.size()) {
8281
0
    ada_log("url_aggregator::validate host_start overflow \n", to_diagram());
8282
0
    return false;
8283
0
  }
8284
9.33k
  if (components.host_end > buffer.size()) {
8285
0
    ada_log("url_aggregator::validate host_end overflow \n", to_diagram());
8286
0
    return false;
8287
0
  }
8288
9.33k
  if (components.pathname_start > buffer.size()) {
8289
0
    ada_log("url_aggregator::validate pathname_start overflow \n",
8290
0
            to_diagram());
8291
0
    return false;
8292
0
  }
8293
8294
9.33k
  if (components.protocol_end > 0) {
8295
9.33k
    if (buffer[components.protocol_end - 1] != ':') {
8296
0
      ada_log(
8297
0
          "url_aggregator::validate missing : at the end of the protocol \n",
8298
0
          to_diagram());
8299
0
      return false;
8300
0
    }
8301
9.33k
  }
8302
8303
9.33k
  if (components.username_end != buffer.size() &&
8304
9.33k
      components.username_end > components.protocol_end + 2) {
8305
6.54k
    if (buffer[components.username_end] != ':' &&
8306
6.54k
        buffer[components.username_end] != '@') {
8307
0
      ada_log(
8308
0
          "url_aggregator::validate missing : or @ at the end of the username "
8309
0
          "\n",
8310
0
          to_diagram());
8311
0
      return false;
8312
0
    }
8313
6.54k
  }
8314
8315
9.33k
  if (components.host_start != buffer.size()) {
8316
9.17k
    if (components.host_start > components.username_end) {
8317
6.46k
      if (buffer[components.host_start] != '@') {
8318
0
        ada_log(
8319
0
            "url_aggregator::validate missing @ at the end of the password \n",
8320
0
            to_diagram());
8321
0
        return false;
8322
0
      }
8323
6.46k
    } else if (components.host_start == components.username_end &&
8324
2.70k
               components.host_end > components.host_start) {
8325
1.18k
      if (components.host_start == components.protocol_end + 2) {
8326
1.05k
        if (buffer[components.protocol_end] != '/' ||
8327
1.05k
            buffer[components.protocol_end + 1] != '/') {
8328
0
          ada_log(
8329
0
              "url_aggregator::validate missing // between protocol and host "
8330
0
              "\n",
8331
0
              to_diagram());
8332
0
          return false;
8333
0
        }
8334
1.05k
      } else {
8335
132
        if (components.host_start > components.protocol_end &&
8336
132
            buffer[components.host_start] != '@') {
8337
0
          ada_log(
8338
0
              "url_aggregator::validate missing @ at the end of the username "
8339
0
              "\n",
8340
0
              to_diagram());
8341
0
          return false;
8342
0
        }
8343
132
      }
8344
1.52k
    } else {
8345
1.52k
      if (components.host_end != components.host_start) {
8346
0
        ada_log("url_aggregator::validate expected omitted host \n",
8347
0
                to_diagram());
8348
0
        return false;
8349
0
      }
8350
1.52k
    }
8351
9.17k
  }
8352
9.33k
  if (components.host_end != buffer.size() &&
8353
9.33k
      components.pathname_start > components.host_end) {
8354
949
    if (components.pathname_start == components.host_end + 2 &&
8355
949
        buffer[components.host_end] == '/' &&
8356
949
        buffer[components.host_end + 1] == '.') {
8357
11
      if (components.pathname_start + 1 >= buffer.size() ||
8358
11
          buffer[components.pathname_start] != '/' ||
8359
11
          buffer[components.pathname_start + 1] != '/') {
8360
0
        ada_log(
8361
0
            "url_aggregator::validate expected the path to begin with // \n",
8362
0
            to_diagram());
8363
0
        return false;
8364
0
      }
8365
938
    } else if (buffer[components.host_end] != ':') {
8366
0
      ada_log("url_aggregator::validate missing : at the port \n",
8367
0
              to_diagram());
8368
0
      return false;
8369
0
    }
8370
949
  }
8371
9.33k
  if (components.pathname_start != buffer.size() &&
8372
9.33k
      components.pathname_start < components.search_start &&
8373
9.33k
      components.pathname_start < components.hash_start && !has_opaque_path) {
8374
8.42k
    if (buffer[components.pathname_start] != '/') {
8375
0
      ada_log("url_aggregator::validate missing / at the path \n",
8376
0
              to_diagram());
8377
0
      return false;
8378
0
    }
8379
8.42k
  }
8380
9.33k
  if (components.search_start != url_components::omitted) {
8381
6.52k
    if (buffer[components.search_start] != '?') {
8382
0
      ada_log("url_aggregator::validate missing ? at the search \n",
8383
0
              to_diagram());
8384
0
      return false;
8385
0
    }
8386
6.52k
  }
8387
9.33k
  if (components.hash_start != url_components::omitted) {
8388
6.47k
    if (buffer[components.hash_start] != '#') {
8389
0
      ada_log("url_aggregator::validate missing # at the hash \n",
8390
0
              to_diagram());
8391
0
      return false;
8392
0
    }
8393
6.47k
  }
8394
8395
9.33k
  return true;
8396
9.33k
}
8397
8398
[[nodiscard]] constexpr std::string_view url_aggregator::get_pathname()
8399
53.4k
    const noexcept ada_lifetime_bound {
8400
53.4k
  ada_log("url_aggregator::get_pathname pathname_start = ",
8401
53.4k
          components.pathname_start, " buffer.size() = ", buffer.size(),
8402
53.4k
          " components.search_start = ", components.search_start,
8403
53.4k
          " components.hash_start = ", components.hash_start);
8404
53.4k
  auto ending_index = uint32_t(buffer.size());
8405
53.4k
  if (components.search_start != url_components::omitted) {
8406
23.4k
    ending_index = components.search_start;
8407
29.9k
  } else if (components.hash_start != url_components::omitted) {
8408
412
    ending_index = components.hash_start;
8409
412
  }
8410
53.4k
  return helpers::substring(buffer, components.pathname_start, ending_index);
8411
53.4k
}
8412
8413
inline std::ostream &operator<<(std::ostream &out,
8414
0
                                const ada::url_aggregator &u) {
8415
0
  return out << u.to_string();
8416
0
}
8417
8418
void url_aggregator::update_host_to_base_host(
8419
400
    const std::string_view input) noexcept {
8420
400
  ada_log("url_aggregator::update_host_to_base_host ", input);
8421
400
  ADA_ASSERT_TRUE(validate());
8422
400
  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
8423
400
  if (type != ada::scheme::type::FILE) {
8424
    // Let host be the result of host parsing host_view with url is not special.
8425
293
    if (input.empty() && !is_special()) {
8426
96
      if (has_hostname()) {
8427
2
        clear_hostname();
8428
94
      } else if (has_dash_dot()) {
8429
0
        add_authority_slashes_if_needed();
8430
0
        delete_dash_dot();
8431
0
      }
8432
96
      return;
8433
96
    }
8434
293
  }
8435
304
  update_base_hostname(input);
8436
304
  ADA_ASSERT_TRUE(validate());
8437
304
  return;
8438
400
}
8439
}  // namespace ada
8440
8441
#endif  // ADA_URL_AGGREGATOR_INL_H
8442
/* end file include/ada/url_aggregator-inl.h */
8443
/* begin file include/ada/url_search_params.h */
8444
/**
8445
 * @file url_search_params.h
8446
 * @brief Declaration for the URL Search Params
8447
 */
8448
#ifndef ADA_URL_SEARCH_PARAMS_H
8449
#define ADA_URL_SEARCH_PARAMS_H
8450
8451
#include <optional>
8452
#include <string>
8453
#include <string_view>
8454
#include <vector>
8455
8456
namespace ada {
8457
8458
enum class url_search_params_iter_type {
8459
  KEYS,
8460
  VALUES,
8461
  ENTRIES,
8462
};
8463
8464
template <typename T, url_search_params_iter_type Type>
8465
struct url_search_params_iter;
8466
8467
typedef std::pair<std::string_view, std::string_view> key_value_view_pair;
8468
8469
using url_search_params_keys_iter =
8470
    url_search_params_iter<std::string_view, url_search_params_iter_type::KEYS>;
8471
using url_search_params_values_iter =
8472
    url_search_params_iter<std::string_view,
8473
                           url_search_params_iter_type::VALUES>;
8474
using url_search_params_entries_iter =
8475
    url_search_params_iter<key_value_view_pair,
8476
                           url_search_params_iter_type::ENTRIES>;
8477
8478
/**
8479
 * We require all strings to be valid UTF-8. It is the user's responsibility to
8480
 * ensure that the provided strings are valid UTF-8.
8481
 * @see https://url.spec.whatwg.org/#interface-urlsearchparams
8482
 */
8483
struct url_search_params {
8484
1.02k
  url_search_params() = default;
8485
8486
  /**
8487
   * @see
8488
   * https://github.com/web-platform-tests/wpt/blob/master/url/urlsearchparams-constructor.any.js
8489
   */
8490
1.02k
  explicit url_search_params(const std::string_view input) {
8491
1.02k
    initialize(input);
8492
1.02k
  }
8493
8494
  url_search_params(const url_search_params &u) = default;
8495
0
  url_search_params(url_search_params &&u) noexcept = default;
8496
  url_search_params &operator=(url_search_params &&u) noexcept = default;
8497
  url_search_params &operator=(const url_search_params &u) = default;
8498
2.05k
  ~url_search_params() = default;
8499
8500
  [[nodiscard]] inline size_t size() const noexcept;
8501
8502
  /**
8503
   * Both key and value must be valid UTF-8.
8504
   * @see https://url.spec.whatwg.org/#dom-urlsearchparams-append
8505
   */
8506
  inline void append(std::string_view key, std::string_view value);
8507
8508
  /**
8509
   * @see https://url.spec.whatwg.org/#dom-urlsearchparams-delete
8510
   */
8511
  inline void remove(std::string_view key);
8512
  inline void remove(std::string_view key, std::string_view value);
8513
8514
  /**
8515
   * @see https://url.spec.whatwg.org/#dom-urlsearchparams-get
8516
   */
8517
  inline std::optional<std::string_view> get(std::string_view key);
8518
8519
  /**
8520
   * @see https://url.spec.whatwg.org/#dom-urlsearchparams-getall
8521
   */
8522
  inline std::vector<std::string> get_all(std::string_view key);
8523
8524
  /**
8525
   * @see https://url.spec.whatwg.org/#dom-urlsearchparams-has
8526
   */
8527
  inline bool has(std::string_view key) noexcept;
8528
  inline bool has(std::string_view key, std::string_view value) noexcept;
8529
8530
  /**
8531
   * Both key and value must be valid UTF-8.
8532
   * @see https://url.spec.whatwg.org/#dom-urlsearchparams-set
8533
   */
8534
  inline void set(std::string_view key, std::string_view value);
8535
8536
  /**
8537
   * @see https://url.spec.whatwg.org/#dom-urlsearchparams-sort
8538
   */
8539
  inline void sort();
8540
8541
  /**
8542
   * @see https://url.spec.whatwg.org/#urlsearchparams-stringification-behavior
8543
   */
8544
  inline std::string to_string() const;
8545
8546
  /**
8547
   * Returns a simple JS-style iterator over all of the keys in this
8548
   * url_search_params. The keys in the iterator are not unique. The valid
8549
   * lifespan of the iterator is tied to the url_search_params. The iterator
8550
   * must be freed when you're done with it.
8551
   * @see https://url.spec.whatwg.org/#interface-urlsearchparams
8552
   */
8553
  inline url_search_params_keys_iter get_keys();
8554
8555
  /**
8556
   * Returns a simple JS-style iterator over all of the values in this
8557
   * url_search_params. The valid lifespan of the iterator is tied to the
8558
   * url_search_params. The iterator must be freed when you're done with it.
8559
   * @see https://url.spec.whatwg.org/#interface-urlsearchparams
8560
   */
8561
  inline url_search_params_values_iter get_values();
8562
8563
  /**
8564
   * Returns a simple JS-style iterator over all of the entries in this
8565
   * url_search_params. The entries are pairs of keys and corresponding values.
8566
   * The valid lifespan of the iterator is tied to the url_search_params. The
8567
   * iterator must be freed when you're done with it.
8568
   * @see https://url.spec.whatwg.org/#interface-urlsearchparams
8569
   */
8570
  inline url_search_params_entries_iter get_entries();
8571
8572
  /**
8573
   * C++ style conventional iterator support. const only because we
8574
   * do not really want the params to be modified via the iterator.
8575
   */
8576
0
  inline auto begin() const { return params.begin(); }
8577
0
  inline auto end() const { return params.end(); }
8578
0
  inline auto front() const { return params.front(); }
8579
0
  inline auto back() const { return params.back(); }
8580
0
  inline auto operator[](size_t index) const { return params[index]; }
8581
8582
  /**
8583
   * @private
8584
   * Used to reset the search params to a new input.
8585
   * Used primarily for C API.
8586
   * @param input
8587
   */
8588
  void reset(std::string_view input);
8589
8590
 private:
8591
  typedef std::pair<std::string, std::string> key_value_pair;
8592
  std::vector<key_value_pair> params{};
8593
8594
  /**
8595
   * The init parameter must be valid UTF-8.
8596
   * @see https://url.spec.whatwg.org/#concept-urlencoded-parser
8597
   */
8598
  void initialize(std::string_view init);
8599
8600
  template <typename T, url_search_params_iter_type Type>
8601
  friend struct url_search_params_iter;
8602
};  // url_search_params
8603
8604
/**
8605
 * Implements a non-conventional iterator pattern that is closer in style to
8606
 * JavaScript's definition of an iterator.
8607
 *
8608
 * @see https://webidl.spec.whatwg.org/#idl-iterable
8609
 */
8610
template <typename T, url_search_params_iter_type Type>
8611
struct url_search_params_iter {
8612
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()
8613
  url_search_params_iter(const url_search_params_iter &u) = default;
8614
  url_search_params_iter(url_search_params_iter &&u) noexcept = default;
8615
  url_search_params_iter &operator=(url_search_params_iter &&u) noexcept =
8616
      default;
8617
  url_search_params_iter &operator=(const url_search_params_iter &u) = default;
8618
  ~url_search_params_iter() = default;
8619
8620
  /**
8621
   * Return the next item in the iterator or std::nullopt if done.
8622
   */
8623
  inline std::optional<T> next();
8624
8625
  inline bool has_next() const;
8626
8627
 private:
8628
  static url_search_params EMPTY;
8629
3.08k
  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
8629
1.02k
  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
8629
1.02k
  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
8629
1.02k
  inline url_search_params_iter(url_search_params &params_) : params(params_) {}
8630
8631
  url_search_params &params;
8632
  size_t pos = 0;
8633
8634
  friend struct url_search_params;
8635
};
8636
8637
}  // namespace ada
8638
#endif
8639
/* end file include/ada/url_search_params.h */
8640
/* begin file include/ada/url_search_params-inl.h */
8641
/**
8642
 * @file url_search_params-inl.h
8643
 * @brief Inline declarations for the URL Search Params
8644
 */
8645
#ifndef ADA_URL_SEARCH_PARAMS_INL_H
8646
#define ADA_URL_SEARCH_PARAMS_INL_H
8647
8648
8649
#include <algorithm>
8650
#include <optional>
8651
#include <ranges>
8652
#include <string>
8653
#include <string_view>
8654
#include <vector>
8655
8656
namespace ada {
8657
8658
// A default, empty url_search_params for use with empty iterators.
8659
template <typename T, ada::url_search_params_iter_type Type>
8660
url_search_params url_search_params_iter<T, Type>::EMPTY;
8661
8662
1.02k
inline void url_search_params::reset(std::string_view input) {
8663
1.02k
  params.clear();
8664
1.02k
  initialize(input);
8665
1.02k
}
8666
8667
2.05k
inline void url_search_params::initialize(std::string_view input) {
8668
2.05k
  if (!input.empty() && input.front() == '?') {
8669
3
    input.remove_prefix(1);
8670
3
  }
8671
8672
5.62k
  auto process_key_value = [&](const std::string_view current) {
8673
5.62k
    auto equal = current.find('=');
8674
8675
5.62k
    if (equal == std::string_view::npos) {
8676
2.93k
      std::string name(current);
8677
2.93k
      std::ranges::replace(name, '+', ' ');
8678
2.93k
      params.emplace_back(unicode::percent_decode(name, name.find('%')), "");
8679
2.93k
    } else {
8680
2.69k
      std::string name(current.substr(0, equal));
8681
2.69k
      std::string value(current.substr(equal + 1));
8682
8683
2.69k
      std::ranges::replace(name, '+', ' ');
8684
2.69k
      std::ranges::replace(value, '+', ' ');
8685
8686
2.69k
      params.emplace_back(unicode::percent_decode(name, name.find('%')),
8687
2.69k
                          unicode::percent_decode(value, value.find('%')));
8688
2.69k
    }
8689
5.62k
  };
8690
8691
7.77k
  while (!input.empty()) {
8692
6.61k
    auto ampersand_index = input.find('&');
8693
8694
6.61k
    if (ampersand_index == std::string_view::npos) {
8695
899
      if (!input.empty()) {
8696
899
        process_key_value(input);
8697
899
      }
8698
899
      break;
8699
5.71k
    } else if (ampersand_index != 0) {
8700
4.72k
      process_key_value(input.substr(0, ampersand_index));
8701
4.72k
    }
8702
8703
5.71k
    input.remove_prefix(ampersand_index + 1);
8704
5.71k
  }
8705
2.05k
}
8706
8707
inline void url_search_params::append(const std::string_view key,
8708
1.99k
                                      const std::string_view value) {
8709
1.99k
  params.emplace_back(key, value);
8710
1.99k
}
8711
8712
0
inline size_t url_search_params::size() const noexcept { return params.size(); }
8713
8714
inline std::optional<std::string_view> url_search_params::get(
8715
0
    const std::string_view key) {
8716
0
  auto entry = std::ranges::find_if(
8717
0
      params, [&key](const auto &param) { return param.first == key; });
8718
8719
0
  if (entry == params.end()) {
8720
0
    return std::nullopt;
8721
0
  }
8722
8723
0
  return entry->second;
8724
0
}
8725
8726
inline std::vector<std::string> url_search_params::get_all(
8727
0
    const std::string_view key) {
8728
0
  std::vector<std::string> out{};
8729
8730
0
  for (auto &param : params) {
8731
0
    if (param.first == key) {
8732
0
      out.emplace_back(param.second);
8733
0
    }
8734
0
  }
8735
8736
0
  return out;
8737
0
}
8738
8739
1.02k
inline bool url_search_params::has(const std::string_view key) noexcept {
8740
1.02k
  auto entry = std::ranges::find_if(
8741
1.02k
      params, [&key](const auto &param) { return param.first == key; });
8742
1.02k
  return entry != params.end();
8743
1.02k
}
8744
8745
inline bool url_search_params::has(std::string_view key,
8746
1.02k
                                   std::string_view value) noexcept {
8747
1.02k
  auto entry = std::ranges::find_if(params, [&key, &value](const auto &param) {
8748
962
    return param.first == key && param.second == value;
8749
962
  });
8750
1.02k
  return entry != params.end();
8751
1.02k
}
8752
8753
1.02k
inline std::string url_search_params::to_string() const {
8754
1.02k
  auto character_set = ada::character_sets::WWW_FORM_URLENCODED_PERCENT_ENCODE;
8755
1.02k
  std::string out{};
8756
2.05k
  for (size_t i = 0; i < params.size(); i++) {
8757
1.02k
    auto key = ada::unicode::percent_encode(params[i].first, character_set);
8758
1.02k
    auto value = ada::unicode::percent_encode(params[i].second, character_set);
8759
8760
    // Performance optimization: Move this inside percent_encode.
8761
1.02k
    std::ranges::replace(key, ' ', '+');
8762
1.02k
    std::ranges::replace(value, ' ', '+');
8763
8764
1.02k
    if (i != 0) {
8765
0
      out += "&";
8766
0
    }
8767
1.02k
    out.append(key);
8768
1.02k
    out += "=";
8769
1.02k
    out.append(value);
8770
1.02k
  }
8771
1.02k
  return out;
8772
1.02k
}
8773
8774
inline void url_search_params::set(const std::string_view key,
8775
1.02k
                                   const std::string_view value) {
8776
1.02k
  const auto find = [&key](const auto &param) { return param.first == key; };
8777
8778
1.02k
  auto it = std::ranges::find_if(params, find);
8779
8780
1.02k
  if (it == params.end()) {
8781
0
    params.emplace_back(key, value);
8782
1.02k
  } else {
8783
1.02k
    it->second = value;
8784
1.02k
    params.erase(std::remove_if(std::next(it), params.end(), find),
8785
1.02k
                 params.end());
8786
1.02k
  }
8787
1.02k
}
8788
8789
1.99k
inline void url_search_params::remove(const std::string_view key) {
8790
1.99k
  std::erase_if(params,
8791
2.95k
                [&key](const auto &param) { return param.first == key; });
8792
1.99k
}
8793
8794
inline void url_search_params::remove(const std::string_view key,
8795
1.99k
                                      const std::string_view value) {
8796
1.99k
  std::erase_if(params, [&key, &value](const auto &param) {
8797
962
    return param.first == key && param.second == value;
8798
962
  });
8799
1.99k
}
8800
8801
0
inline void url_search_params::sort() {
8802
  // We rely on the fact that the content is valid UTF-8.
8803
0
  std::ranges::stable_sort(params, [](const key_value_pair &lhs,
8804
0
                                      const key_value_pair &rhs) {
8805
0
    size_t i = 0, j = 0;
8806
0
    uint32_t low_surrogate1 = 0, low_surrogate2 = 0;
8807
0
    while ((i < lhs.first.size() || low_surrogate1 != 0) &&
8808
0
           (j < rhs.first.size() || low_surrogate2 != 0)) {
8809
0
      uint32_t codePoint1 = 0, codePoint2 = 0;
8810
8811
0
      if (low_surrogate1 != 0) {
8812
0
        codePoint1 = low_surrogate1;
8813
0
        low_surrogate1 = 0;
8814
0
      } else {
8815
0
        uint8_t c1 = uint8_t(lhs.first[i]);
8816
0
        if (c1 <= 0x7F) {
8817
0
          codePoint1 = c1;
8818
0
          i++;
8819
0
        } else if (c1 <= 0xDF) {
8820
0
          codePoint1 = ((c1 & 0x1F) << 6) | (uint8_t(lhs.first[i + 1]) & 0x3F);
8821
0
          i += 2;
8822
0
        } else if (c1 <= 0xEF) {
8823
0
          codePoint1 = ((c1 & 0x0F) << 12) |
8824
0
                       ((uint8_t(lhs.first[i + 1]) & 0x3F) << 6) |
8825
0
                       (uint8_t(lhs.first[i + 2]) & 0x3F);
8826
0
          i += 3;
8827
0
        } else {
8828
0
          codePoint1 = ((c1 & 0x07) << 18) |
8829
0
                       ((uint8_t(lhs.first[i + 1]) & 0x3F) << 12) |
8830
0
                       ((uint8_t(lhs.first[i + 2]) & 0x3F) << 6) |
8831
0
                       (uint8_t(lhs.first[i + 3]) & 0x3F);
8832
0
          i += 4;
8833
8834
0
          codePoint1 -= 0x10000;
8835
0
          uint16_t high_surrogate = uint16_t(0xD800 + (codePoint1 >> 10));
8836
0
          low_surrogate1 = uint16_t(0xDC00 + (codePoint1 & 0x3FF));
8837
0
          codePoint1 = high_surrogate;
8838
0
        }
8839
0
      }
8840
8841
0
      if (low_surrogate2 != 0) {
8842
0
        codePoint2 = low_surrogate2;
8843
0
        low_surrogate2 = 0;
8844
0
      } else {
8845
0
        uint8_t c2 = uint8_t(rhs.first[j]);
8846
0
        if (c2 <= 0x7F) {
8847
0
          codePoint2 = c2;
8848
0
          j++;
8849
0
        } else if (c2 <= 0xDF) {
8850
0
          codePoint2 = ((c2 & 0x1F) << 6) | (uint8_t(rhs.first[j + 1]) & 0x3F);
8851
0
          j += 2;
8852
0
        } else if (c2 <= 0xEF) {
8853
0
          codePoint2 = ((c2 & 0x0F) << 12) |
8854
0
                       ((uint8_t(rhs.first[j + 1]) & 0x3F) << 6) |
8855
0
                       (uint8_t(rhs.first[j + 2]) & 0x3F);
8856
0
          j += 3;
8857
0
        } else {
8858
0
          codePoint2 = ((c2 & 0x07) << 18) |
8859
0
                       ((uint8_t(rhs.first[j + 1]) & 0x3F) << 12) |
8860
0
                       ((uint8_t(rhs.first[j + 2]) & 0x3F) << 6) |
8861
0
                       (uint8_t(rhs.first[j + 3]) & 0x3F);
8862
0
          j += 4;
8863
0
          codePoint2 -= 0x10000;
8864
0
          uint16_t high_surrogate = uint16_t(0xD800 + (codePoint2 >> 10));
8865
0
          low_surrogate2 = uint16_t(0xDC00 + (codePoint2 & 0x3FF));
8866
0
          codePoint2 = high_surrogate;
8867
0
        }
8868
0
      }
8869
8870
0
      if (codePoint1 != codePoint2) {
8871
0
        return (codePoint1 < codePoint2);
8872
0
      }
8873
0
    }
8874
0
    return (j < rhs.first.size() || low_surrogate2 != 0);
8875
0
  });
8876
0
}
8877
8878
1.02k
inline url_search_params_keys_iter url_search_params::get_keys() {
8879
1.02k
  return url_search_params_keys_iter(*this);
8880
1.02k
}
8881
8882
/**
8883
 * @see https://url.spec.whatwg.org/#interface-urlsearchparams
8884
 */
8885
1.02k
inline url_search_params_values_iter url_search_params::get_values() {
8886
1.02k
  return url_search_params_values_iter(*this);
8887
1.02k
}
8888
8889
/**
8890
 * @see https://url.spec.whatwg.org/#interface-urlsearchparams
8891
 */
8892
1.02k
inline url_search_params_entries_iter url_search_params::get_entries() {
8893
1.02k
  return url_search_params_entries_iter(*this);
8894
1.02k
}
8895
8896
template <typename T, url_search_params_iter_type Type>
8897
3.08k
inline bool url_search_params_iter<T, Type>::has_next() const {
8898
3.08k
  return pos < params.params.size();
8899
3.08k
}
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() const
Line
Count
Source
8897
1.02k
inline bool url_search_params_iter<T, Type>::has_next() const {
8898
1.02k
  return pos < params.params.size();
8899
1.02k
}
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() const
Line
Count
Source
8897
1.02k
inline bool url_search_params_iter<T, Type>::has_next() const {
8898
1.02k
  return pos < params.params.size();
8899
1.02k
}
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() const
Line
Count
Source
8897
1.02k
inline bool url_search_params_iter<T, Type>::has_next() const {
8898
1.02k
  return pos < params.params.size();
8899
1.02k
}
8900
8901
template <>
8902
0
inline std::optional<std::string_view> url_search_params_keys_iter::next() {
8903
0
  if (!has_next()) {
8904
0
    return std::nullopt;
8905
0
  }
8906
0
  return params.params[pos++].first;
8907
0
}
8908
8909
template <>
8910
0
inline std::optional<std::string_view> url_search_params_values_iter::next() {
8911
0
  if (!has_next()) {
8912
0
    return std::nullopt;
8913
0
  }
8914
0
  return params.params[pos++].second;
8915
0
}
8916
8917
template <>
8918
inline std::optional<key_value_view_pair>
8919
0
url_search_params_entries_iter::next() {
8920
0
  if (!has_next()) {
8921
0
    return std::nullopt;
8922
0
  }
8923
0
  return params.params[pos++];
8924
0
}
8925
8926
}  // namespace ada
8927
8928
#endif  // ADA_URL_SEARCH_PARAMS_INL_H
8929
/* end file include/ada/url_search_params-inl.h */
8930
8931
/* begin file include/ada/url_pattern-inl.h */
8932
/**
8933
 * @file url_pattern-inl.h
8934
 * @brief Declaration for the URLPattern inline functions.
8935
 */
8936
#ifndef ADA_URL_PATTERN_INL_H
8937
#define ADA_URL_PATTERN_INL_H
8938
8939
8940
#include <algorithm>
8941
#include <string_view>
8942
#include <utility>
8943
8944
#if ADA_INCLUDE_URL_PATTERN
8945
namespace ada {
8946
8947
0
inline bool url_pattern_init::operator==(const url_pattern_init& other) const {
8948
0
  return protocol == other.protocol && username == other.username &&
8949
0
         password == other.password && hostname == other.hostname &&
8950
0
         port == other.port && search == other.search && hash == other.hash &&
8951
0
         pathname == other.pathname;
8952
0
}
8953
8954
inline bool url_pattern_component_result::operator==(
8955
0
    const url_pattern_component_result& other) const {
8956
0
  return input == other.input && groups == other.groups;
8957
0
}
8958
8959
template <url_pattern_regex::regex_concept regex_provider>
8960
url_pattern_component_result
8961
url_pattern_component<regex_provider>::create_component_match_result(
8962
    std::string&& input,
8963
    std::vector<std::optional<std::string>>&& exec_result) {
8964
  // Let result be a new URLPatternComponentResult.
8965
  // Set result["input"] to input.
8966
  // Let groups be a record<USVString, (USVString or undefined)>.
8967
  auto result =
8968
      url_pattern_component_result{.input = std::move(input), .groups = {}};
8969
8970
  // Optimization: Let's reserve the size.
8971
  result.groups.reserve(exec_result.size());
8972
8973
  // We explicitly start iterating from 0 even though the spec
8974
  // says we should start from 1. This case is handled by the
8975
  // std_regex_provider.
8976
  for (size_t index = 0; index < exec_result.size(); index++) {
8977
    result.groups.insert({
8978
        group_name_list[index],
8979
        std::move(exec_result[index]),
8980
    });
8981
  }
8982
  return result;
8983
}
8984
8985
template <url_pattern_regex::regex_concept regex_provider>
8986
std::string_view url_pattern<regex_provider>::get_protocol() const
8987
591
    ada_lifetime_bound {
8988
  // Return this's associated URL pattern's protocol component's pattern string.
8989
591
  return protocol_component.pattern;
8990
591
}
8991
template <url_pattern_regex::regex_concept regex_provider>
8992
std::string_view url_pattern<regex_provider>::get_username() const
8993
591
    ada_lifetime_bound {
8994
  // Return this's associated URL pattern's username component's pattern string.
8995
591
  return username_component.pattern;
8996
591
}
8997
template <url_pattern_regex::regex_concept regex_provider>
8998
std::string_view url_pattern<regex_provider>::get_password() const
8999
591
    ada_lifetime_bound {
9000
  // Return this's associated URL pattern's password component's pattern string.
9001
591
  return password_component.pattern;
9002
591
}
9003
template <url_pattern_regex::regex_concept regex_provider>
9004
std::string_view url_pattern<regex_provider>::get_hostname() const
9005
591
    ada_lifetime_bound {
9006
  // Return this's associated URL pattern's hostname component's pattern string.
9007
591
  return hostname_component.pattern;
9008
591
}
9009
template <url_pattern_regex::regex_concept regex_provider>
9010
std::string_view url_pattern<regex_provider>::get_port() const
9011
591
    ada_lifetime_bound {
9012
  // Return this's associated URL pattern's port component's pattern string.
9013
591
  return port_component.pattern;
9014
591
}
9015
template <url_pattern_regex::regex_concept regex_provider>
9016
std::string_view url_pattern<regex_provider>::get_pathname() const
9017
591
    ada_lifetime_bound {
9018
  // Return this's associated URL pattern's pathname component's pattern string.
9019
591
  return pathname_component.pattern;
9020
591
}
9021
template <url_pattern_regex::regex_concept regex_provider>
9022
std::string_view url_pattern<regex_provider>::get_search() const
9023
591
    ada_lifetime_bound {
9024
  // Return this's associated URL pattern's search component's pattern string.
9025
591
  return search_component.pattern;
9026
591
}
9027
template <url_pattern_regex::regex_concept regex_provider>
9028
std::string_view url_pattern<regex_provider>::get_hash() const
9029
591
    ada_lifetime_bound {
9030
  // Return this's associated URL pattern's hash component's pattern string.
9031
591
  return hash_component.pattern;
9032
591
}
9033
template <url_pattern_regex::regex_concept regex_provider>
9034
591
bool url_pattern<regex_provider>::ignore_case() const {
9035
591
  return ignore_case_;
9036
591
}
9037
template <url_pattern_regex::regex_concept regex_provider>
9038
591
bool url_pattern<regex_provider>::has_regexp_groups() const {
9039
  // If this's associated URL pattern's has regexp groups, then return true.
9040
591
  return protocol_component.has_regexp_groups ||
9041
591
         username_component.has_regexp_groups ||
9042
591
         password_component.has_regexp_groups ||
9043
591
         hostname_component.has_regexp_groups ||
9044
591
         port_component.has_regexp_groups ||
9045
591
         pathname_component.has_regexp_groups ||
9046
591
         search_component.has_regexp_groups || hash_component.has_regexp_groups;
9047
591
}
9048
9049
4.72k
inline bool url_pattern_part::is_regexp() const noexcept {
9050
4.72k
  return type == url_pattern_part_type::REGEXP;
9051
4.72k
}
9052
9053
inline std::string_view url_pattern_compile_component_options::get_delimiter()
9054
5.31k
    const {
9055
5.31k
  if (delimiter) {
9056
1.18k
    return {&delimiter.value(), 1};
9057
1.18k
  }
9058
4.13k
  return {};
9059
5.31k
}
9060
9061
inline std::string_view url_pattern_compile_component_options::get_prefix()
9062
1.18k
    const {
9063
1.18k
  if (prefix) {
9064
1.18k
    return {&prefix.value(), 1};
9065
1.18k
  }
9066
0
  return {};
9067
1.18k
}
9068
9069
template <url_pattern_regex::regex_concept regex_provider>
9070
template <url_pattern_encoding_callback F>
9071
tl::expected<url_pattern_component<regex_provider>, errors>
9072
url_pattern_component<regex_provider>::compile(
9073
    std::string_view input, F& encoding_callback,
9074
5.31k
    url_pattern_compile_component_options& options) {
9075
5.31k
  ada_log("url_pattern_component::compile input: ", input);
9076
  // Let part list be the result of running parse a pattern string given input,
9077
  // options, and encoding callback.
9078
5.31k
  auto part_list = url_pattern_helpers::parse_pattern_string(input, options,
9079
5.31k
                                                             encoding_callback);
9080
9081
5.31k
  if (!part_list) {
9082
0
    ada_log("parse_pattern_string failed");
9083
0
    return tl::unexpected(part_list.error());
9084
0
  }
9085
9086
  // Let (regular expression string, name list) be the result of running
9087
  // generate a regular expression and name list given part list and options.
9088
5.31k
  auto [regular_expression_string, name_list] =
9089
5.31k
      url_pattern_helpers::generate_regular_expression_and_name_list(*part_list,
9090
5.31k
                                                                     options);
9091
9092
5.31k
  ada_log("regular expression string: ", regular_expression_string);
9093
9094
  // Let pattern string be the result of running generate a pattern
9095
  // string given part list and options.
9096
5.31k
  auto pattern_string =
9097
5.31k
      url_pattern_helpers::generate_pattern_string(*part_list, options);
9098
9099
  // Let regular expression be RegExpCreate(regular expression string,
9100
  // flags). If this throws an exception, catch it, and throw a
9101
  // TypeError.
9102
5.31k
  std::optional<typename regex_provider::regex_type> regular_expression =
9103
5.31k
      regex_provider::create_instance(regular_expression_string,
9104
5.31k
                                      options.ignore_case);
9105
9106
5.31k
  if (!regular_expression) {
9107
0
    return tl::unexpected(errors::type_error);
9108
0
  }
9109
9110
  // For each part of part list:
9111
  // - If part's type is "regexp", then set has regexp groups to true.
9112
5.31k
  const auto has_regexp = [](const auto& part) { return part.is_regexp(); };
9113
5.31k
  const bool has_regexp_groups = std::ranges::any_of(*part_list, has_regexp);
9114
9115
5.31k
  ada_log("has regexp groups: ", has_regexp_groups);
9116
9117
  // Return a new component whose pattern string is pattern string, regular
9118
  // expression is regular expression, group name list is name list, and has
9119
  // regexp groups is has regexp groups.
9120
5.31k
  return url_pattern_component<regex_provider>(
9121
5.31k
      std::move(pattern_string), std::move(*regular_expression),
9122
5.31k
      std::move(name_list), has_regexp_groups);
9123
5.31k
}
9124
9125
template <url_pattern_regex::regex_concept regex_provider>
9126
result<std::optional<url_pattern_result>> url_pattern<regex_provider>::exec(
9127
    const url_pattern_input& input, const std::string_view* base_url) {
9128
  // Return the result of match given this's associated URL pattern, input, and
9129
  // baseURL if given.
9130
  return match(input, base_url);
9131
}
9132
9133
template <url_pattern_regex::regex_concept regex_provider>
9134
result<bool> url_pattern<regex_provider>::test(
9135
    const url_pattern_input& input, const std::string_view* base_url) {
9136
  // TODO: Optimization opportunity. Rather than returning `url_pattern_result`
9137
  // Implement a fast path just like `can_parse()` in ada_url.
9138
  // Let result be the result of match given this's associated URL pattern,
9139
  // input, and baseURL if given.
9140
  // If result is null, return false.
9141
  if (auto result = match(input, base_url); result.has_value()) {
9142
    return result->has_value();
9143
  }
9144
  return tl::unexpected(errors::type_error);
9145
}
9146
9147
template <url_pattern_regex::regex_concept regex_provider>
9148
result<std::optional<url_pattern_result>> url_pattern<regex_provider>::match(
9149
    const url_pattern_input& input, const std::string_view* base_url_string) {
9150
  std::string protocol{};
9151
  std::string username{};
9152
  std::string password{};
9153
  std::string hostname{};
9154
  std::string port{};
9155
  std::string pathname{};
9156
  std::string search{};
9157
  std::string hash{};
9158
9159
  // Let inputs be an empty list.
9160
  // Append input to inputs.
9161
  std::vector inputs{input};
9162
9163
  // If input is a URLPatternInit then:
9164
  if (std::holds_alternative<url_pattern_init>(input)) {
9165
    ada_log(
9166
        "url_pattern::match called with url_pattern_init and base_url_string=",
9167
        base_url_string);
9168
    // If baseURLString was given, throw a TypeError.
9169
    if (base_url_string) {
9170
      ada_log("failed to match because base_url_string was given");
9171
      return tl::unexpected(errors::type_error);
9172
    }
9173
9174
    // Let applyResult be the result of process a URLPatternInit given input,
9175
    // "url", protocol, username, password, hostname, port, pathname, search,
9176
    // and hash.
9177
    auto apply_result = url_pattern_init::process(
9178
        std::get<url_pattern_init>(input), url_pattern_init::process_type::url,
9179
        protocol, username, password, hostname, port, pathname, search, hash);
9180
9181
    // If this throws an exception, catch it, and return null.
9182
    if (!apply_result.has_value()) {
9183
      ada_log("match returned std::nullopt because process threw");
9184
      return std::nullopt;
9185
    }
9186
9187
    // Set protocol to applyResult["protocol"].
9188
    ADA_ASSERT_TRUE(apply_result->protocol.has_value());
9189
    protocol = std::move(apply_result->protocol.value());
9190
9191
    // Set username to applyResult["username"].
9192
    ADA_ASSERT_TRUE(apply_result->username.has_value());
9193
    username = std::move(apply_result->username.value());
9194
9195
    // Set password to applyResult["password"].
9196
    ADA_ASSERT_TRUE(apply_result->password.has_value());
9197
    password = std::move(apply_result->password.value());
9198
9199
    // Set hostname to applyResult["hostname"].
9200
    ADA_ASSERT_TRUE(apply_result->hostname.has_value());
9201
    hostname = std::move(apply_result->hostname.value());
9202
9203
    // Set port to applyResult["port"].
9204
    ADA_ASSERT_TRUE(apply_result->port.has_value());
9205
    port = std::move(apply_result->port.value());
9206
9207
    // Set pathname to applyResult["pathname"].
9208
    ADA_ASSERT_TRUE(apply_result->pathname.has_value());
9209
    pathname = std::move(apply_result->pathname.value());
9210
9211
    // Set search to applyResult["search"].
9212
    ADA_ASSERT_TRUE(apply_result->search.has_value());
9213
    if (apply_result->search->starts_with("?")) {
9214
      search = apply_result->search->substr(1);
9215
    } else {
9216
      search = std::move(apply_result->search.value());
9217
    }
9218
9219
    // Set hash to applyResult["hash"].
9220
    ADA_ASSERT_TRUE(apply_result->hash.has_value());
9221
    ADA_ASSERT_TRUE(!apply_result->hash->starts_with("#"));
9222
    hash = std::move(apply_result->hash.value());
9223
  } else {
9224
    ADA_ASSERT_TRUE(std::holds_alternative<std::string_view>(input));
9225
9226
    // Let baseURL be null.
9227
    result<url_aggregator> base_url;
9228
9229
    // If baseURLString was given, then:
9230
    if (base_url_string) {
9231
      // Let baseURL be the result of parsing baseURLString.
9232
      base_url = ada::parse<url_aggregator>(*base_url_string, nullptr);
9233
9234
      // If baseURL is failure, return null.
9235
      if (!base_url) {
9236
        ada_log("match returned std::nullopt because failed to parse base_url=",
9237
                *base_url_string);
9238
        return std::nullopt;
9239
      }
9240
9241
      // Append baseURLString to inputs.
9242
      inputs.emplace_back(*base_url_string);
9243
    }
9244
9245
    url_aggregator* base_url_value =
9246
        base_url.has_value() ? &*base_url : nullptr;
9247
9248
    // Set url to the result of parsing input given baseURL.
9249
    auto url = ada::parse<url_aggregator>(std::get<std::string_view>(input),
9250
                                          base_url_value);
9251
9252
    // If url is failure, return null.
9253
    if (!url) {
9254
      ada_log("match returned std::nullopt because url failed");
9255
      return std::nullopt;
9256
    }
9257
9258
    // Set protocol to url's scheme.
9259
    // IMPORTANT: Not documented on the URLPattern spec, but protocol suffix ':'
9260
    // is removed. Similar work was done on workerd:
9261
    // https://github.com/cloudflare/workerd/blob/8620d14012513a6ce04d079e401d3becac3c67bd/src/workerd/jsg/url.c%2B%2B#L2038
9262
    protocol = url->get_protocol().substr(0, url->get_protocol().size() - 1);
9263
    // Set username to url's username.
9264
    username = url->get_username();
9265
    // Set password to url's password.
9266
    password = url->get_password();
9267
    // Set hostname to url's host, serialized, or the empty string if the value
9268
    // is null.
9269
    hostname = url->get_hostname();
9270
    // Set port to url's port, serialized, or the empty string if the value is
9271
    // null.
9272
    port = url->get_port();
9273
    // Set pathname to the result of URL path serializing url.
9274
    pathname = url->get_pathname();
9275
    // Set search to url's query or the empty string if the value is null.
9276
    // IMPORTANT: Not documented on the URLPattern spec, but search prefix '?'
9277
    // is removed. Similar work was done on workerd:
9278
    // https://github.com/cloudflare/workerd/blob/8620d14012513a6ce04d079e401d3becac3c67bd/src/workerd/jsg/url.c%2B%2B#L2232
9279
    if (url->has_search()) {
9280
      auto view = url->get_search();
9281
      search = view.starts_with("?") ? url->get_search().substr(1) : view;
9282
    }
9283
    // Set hash to url's fragment or the empty string if the value is null.
9284
    // IMPORTANT: Not documented on the URLPattern spec, but hash prefix '#' is
9285
    // removed. Similar work was done on workerd:
9286
    // https://github.com/cloudflare/workerd/blob/8620d14012513a6ce04d079e401d3becac3c67bd/src/workerd/jsg/url.c%2B%2B#L2242
9287
    if (url->has_hash()) {
9288
      auto view = url->get_hash();
9289
      hash = view.starts_with("#") ? url->get_hash().substr(1) : view;
9290
    }
9291
  }
9292
9293
  // Let protocolExecResult be RegExpBuiltinExec(urlPattern's protocol
9294
  // component's regular expression, protocol).
9295
  auto protocol_exec_result =
9296
      regex_provider::regex_search(protocol, protocol_component.regexp);
9297
9298
  if (!protocol_exec_result) {
9299
    return std::nullopt;
9300
  }
9301
9302
  // Let usernameExecResult be RegExpBuiltinExec(urlPattern's username
9303
  // component's regular expression, username).
9304
  auto username_exec_result =
9305
      regex_provider::regex_search(username, username_component.regexp);
9306
9307
  if (!username_exec_result) {
9308
    return std::nullopt;
9309
  }
9310
9311
  // Let passwordExecResult be RegExpBuiltinExec(urlPattern's password
9312
  // component's regular expression, password).
9313
  auto password_exec_result =
9314
      regex_provider::regex_search(password, password_component.regexp);
9315
9316
  if (!password_exec_result) {
9317
    return std::nullopt;
9318
  }
9319
9320
  // Let hostnameExecResult be RegExpBuiltinExec(urlPattern's hostname
9321
  // component's regular expression, hostname).
9322
  auto hostname_exec_result =
9323
      regex_provider::regex_search(hostname, hostname_component.regexp);
9324
9325
  if (!hostname_exec_result) {
9326
    return std::nullopt;
9327
  }
9328
9329
  // Let portExecResult be RegExpBuiltinExec(urlPattern's port component's
9330
  // regular expression, port).
9331
  auto port_exec_result =
9332
      regex_provider::regex_search(port, port_component.regexp);
9333
9334
  if (!port_exec_result) {
9335
    return std::nullopt;
9336
  }
9337
9338
  // Let pathnameExecResult be RegExpBuiltinExec(urlPattern's pathname
9339
  // component's regular expression, pathname).
9340
  auto pathname_exec_result =
9341
      regex_provider::regex_search(pathname, pathname_component.regexp);
9342
9343
  if (!pathname_exec_result) {
9344
    return std::nullopt;
9345
  }
9346
9347
  // Let searchExecResult be RegExpBuiltinExec(urlPattern's search component's
9348
  // regular expression, search).
9349
  auto search_exec_result =
9350
      regex_provider::regex_search(search, search_component.regexp);
9351
9352
  if (!search_exec_result) {
9353
    return std::nullopt;
9354
  }
9355
9356
  // Let hashExecResult be RegExpBuiltinExec(urlPattern's hash component's
9357
  // regular expression, hash).
9358
  auto hash_exec_result =
9359
      regex_provider::regex_search(hash, hash_component.regexp);
9360
9361
  if (!hash_exec_result) {
9362
    return std::nullopt;
9363
  }
9364
9365
  // Let result be a new URLPatternResult.
9366
  auto result = url_pattern_result{};
9367
  // Set result["inputs"] to inputs.
9368
  result.inputs = std::move(inputs);
9369
  // Set result["protocol"] to the result of creating a component match result
9370
  // given urlPattern's protocol component, protocol, and protocolExecResult.
9371
  result.protocol = protocol_component.create_component_match_result(
9372
      std::move(protocol), std::move(*protocol_exec_result));
9373
9374
  // Set result["username"] to the result of creating a component match result
9375
  // given urlPattern's username component, username, and usernameExecResult.
9376
  result.username = username_component.create_component_match_result(
9377
      std::move(username), std::move(*username_exec_result));
9378
9379
  // Set result["password"] to the result of creating a component match result
9380
  // given urlPattern's password component, password, and passwordExecResult.
9381
  result.password = password_component.create_component_match_result(
9382
      std::move(password), std::move(*password_exec_result));
9383
9384
  // Set result["hostname"] to the result of creating a component match result
9385
  // given urlPattern's hostname component, hostname, and hostnameExecResult.
9386
  result.hostname = hostname_component.create_component_match_result(
9387
      std::move(hostname), std::move(*hostname_exec_result));
9388
9389
  // Set result["port"] to the result of creating a component match result given
9390
  // urlPattern's port component, port, and portExecResult.
9391
  result.port = port_component.create_component_match_result(
9392
      std::move(port), std::move(*port_exec_result));
9393
9394
  // Set result["pathname"] to the result of creating a component match result
9395
  // given urlPattern's pathname component, pathname, and pathnameExecResult.
9396
  result.pathname = pathname_component.create_component_match_result(
9397
      std::move(pathname), std::move(*pathname_exec_result));
9398
9399
  // Set result["search"] to the result of creating a component match result
9400
  // given urlPattern's search component, search, and searchExecResult.
9401
  result.search = search_component.create_component_match_result(
9402
      std::move(search), std::move(*search_exec_result));
9403
9404
  // Set result["hash"] to the result of creating a component match result given
9405
  // urlPattern's hash component, hash, and hashExecResult.
9406
  result.hash = hash_component.create_component_match_result(
9407
      std::move(hash), std::move(*hash_exec_result));
9408
9409
  return result;
9410
}
9411
9412
}  // namespace ada
9413
#endif  // ADA_INCLUDE_URL_PATTERN
9414
#endif
9415
/* end file include/ada/url_pattern-inl.h */
9416
/* begin file include/ada/url_pattern_helpers-inl.h */
9417
/**
9418
 * @file url_pattern_helpers-inl.h
9419
 * @brief Declaration for the URLPattern helpers.
9420
 */
9421
#ifndef ADA_URL_PATTERN_HELPERS_INL_H
9422
#define ADA_URL_PATTERN_HELPERS_INL_H
9423
9424
#include <optional>
9425
#include <string_view>
9426
9427
9428
#if ADA_INCLUDE_URL_PATTERN
9429
namespace ada::url_pattern_helpers {
9430
#if defined(ADA_TESTING) || defined(ADA_LOGGING)
9431
0
inline std::string to_string(token_type type) {
9432
0
  switch (type) {
9433
0
    case token_type::INVALID_CHAR:
9434
0
      return "INVALID_CHAR";
9435
0
    case token_type::OPEN:
9436
0
      return "OPEN";
9437
0
    case token_type::CLOSE:
9438
0
      return "CLOSE";
9439
0
    case token_type::REGEXP:
9440
0
      return "REGEXP";
9441
0
    case token_type::NAME:
9442
0
      return "NAME";
9443
0
    case token_type::CHAR:
9444
0
      return "CHAR";
9445
0
    case token_type::ESCAPED_CHAR:
9446
0
      return "ESCAPED_CHAR";
9447
0
    case token_type::OTHER_MODIFIER:
9448
0
      return "OTHER_MODIFIER";
9449
0
    case token_type::ASTERISK:
9450
0
      return "ASTERISK";
9451
0
    case token_type::END:
9452
0
      return "END";
9453
0
    default:
9454
0
      ada::unreachable();
9455
0
  }
9456
0
}
9457
#endif  // defined(ADA_TESTING) || defined(ADA_LOGGING)
9458
9459
template <url_pattern_regex::regex_concept regex_provider>
9460
1.77k
constexpr void constructor_string_parser<regex_provider>::rewind() {
9461
  // Set parser's token index to parser's component start.
9462
1.77k
  token_index = component_start;
9463
  // Set parser's token increment to 0.
9464
1.77k
  token_increment = 0;
9465
1.77k
}
9466
9467
template <url_pattern_regex::regex_concept regex_provider>
9468
28.0k
constexpr bool constructor_string_parser<regex_provider>::is_hash_prefix() {
9469
  // Return the result of running is a non-special pattern char given parser,
9470
  // parser's token index and "#".
9471
28.0k
  return is_non_special_pattern_char(token_index, '#');
9472
28.0k
}
9473
9474
template <url_pattern_regex::regex_concept regex_provider>
9475
28.0k
constexpr bool constructor_string_parser<regex_provider>::is_search_prefix() {
9476
  // If result of running is a non-special pattern char given parser, parser's
9477
  // token index and "?" is true, then return true.
9478
28.0k
  if (is_non_special_pattern_char(token_index, '?')) {
9479
0
    return true;
9480
0
  }
9481
9482
  // If parser's token list[parser's token index]'s value is not "?", then
9483
  // return false.
9484
28.0k
  if (token_list[token_index].value != "?") {
9485
28.0k
    return false;
9486
28.0k
  }
9487
9488
  // If previous index is less than 0, then return true.
9489
0
  if (token_index == 0) return true;
9490
  // Let previous index be parser's token index - 1.
9491
0
  auto previous_index = token_index - 1;
9492
  // Let previous token be the result of running get a safe token given parser
9493
  // and previous index.
9494
0
  auto previous_token = get_safe_token(previous_index);
9495
0
  ADA_ASSERT_TRUE(previous_token);
9496
  // If any of the following are true, then return false:
9497
  // - previous token's type is "name".
9498
  // - previous token's type is "regexp".
9499
  // - previous token's type is "close".
9500
  // - previous token's type is "asterisk".
9501
0
  return !(previous_token->type == token_type::NAME ||
9502
0
           previous_token->type == token_type::REGEXP ||
9503
0
           previous_token->type == token_type::CLOSE ||
9504
0
           previous_token->type == token_type::ASTERISK);
9505
0
}
9506
9507
template <url_pattern_regex::regex_concept regex_provider>
9508
constexpr bool
9509
constructor_string_parser<regex_provider>::is_non_special_pattern_char(
9510
120k
    size_t index, uint32_t value) const {
9511
  // Let token be the result of running get a safe token given parser and index.
9512
120k
  auto token = get_safe_token(index);
9513
120k
  ADA_ASSERT_TRUE(token);
9514
9515
  // If token's value is not value, then return false.
9516
  // TODO: Remove this once we make sure get_safe_token returns a non-empty
9517
  // string.
9518
120k
  if (!token->value.empty() &&
9519
120k
      static_cast<uint32_t>(token->value[0]) != value) {
9520
116k
    return false;
9521
116k
  }
9522
9523
  // If any of the following are true:
9524
  // - token's type is "char";
9525
  // - token's type is "escaped-char"; or
9526
  // - token's type is "invalid-char",
9527
  // - then return true.
9528
3.54k
  return token->type == token_type::CHAR ||
9529
3.54k
         token->type == token_type::ESCAPED_CHAR ||
9530
3.54k
         token->type == token_type::INVALID_CHAR;
9531
120k
}
9532
9533
template <url_pattern_regex::regex_concept regex_provider>
9534
constexpr const token*
9535
123k
constructor_string_parser<regex_provider>::get_safe_token(size_t index) const {
9536
  // If index is less than parser's token list's size, then return parser's
9537
  // token list[index].
9538
123k
  if (index < token_list.size()) [[likely]] {
9539
123k
    return &token_list[index];
9540
123k
  }
9541
9542
  // Assert: parser's token list's size is greater than or equal to 1.
9543
0
  ADA_ASSERT_TRUE(!token_list.empty());
9544
9545
  // Let token be parser's token list[last index].
9546
  // Assert: token's type is "end".
9547
0
  ADA_ASSERT_TRUE(token_list.back().type == token_type::END);
9548
9549
  // Return token.
9550
0
  return &token_list.back();
9551
123k
}
9552
9553
template <url_pattern_regex::regex_concept regex_provider>
9554
constexpr bool constructor_string_parser<regex_provider>::is_group_open()
9555
48.9k
    const {
9556
  // If parser's token list[parser's token index]'s type is "open", then return
9557
  // true.
9558
48.9k
  return token_list[token_index].type == token_type::OPEN;
9559
48.9k
}
9560
9561
template <url_pattern_regex::regex_concept regex_provider>
9562
constexpr bool constructor_string_parser<regex_provider>::is_group_close()
9563
0
    const {
9564
  // If parser's token list[parser's token index]'s type is "close", then return
9565
  // true.
9566
0
  return token_list[token_index].type == token_type::CLOSE;
9567
0
}
9568
9569
template <url_pattern_regex::regex_concept regex_provider>
9570
constexpr bool
9571
591
constructor_string_parser<regex_provider>::next_is_authority_slashes() const {
9572
  // If the result of running is a non-special pattern char given parser,
9573
  // parser's token index + 1, and "/" is false, then return false.
9574
591
  if (!is_non_special_pattern_char(token_index + 1, '/')) {
9575
0
    return false;
9576
0
  }
9577
  // If the result of running is a non-special pattern char given parser,
9578
  // parser's token index + 2, and "/" is false, then return false.
9579
591
  if (!is_non_special_pattern_char(token_index + 2, '/')) {
9580
0
    return false;
9581
0
  }
9582
591
  return true;
9583
591
}
9584
9585
template <url_pattern_regex::regex_concept regex_provider>
9586
constexpr bool constructor_string_parser<regex_provider>::is_protocol_suffix()
9587
20.3k
    const {
9588
  // Return the result of running is a non-special pattern char given parser,
9589
  // parser's token index, and ":".
9590
20.3k
  return is_non_special_pattern_char(token_index, ':');
9591
20.3k
}
9592
9593
template <url_pattern_regex::regex_concept regex_provider>
9594
void constructor_string_parser<regex_provider>::change_state(State new_state,
9595
4.13k
                                                             size_t skip) {
9596
  // If parser's state is not "init", not "authority", and not "done", then set
9597
  // parser's result[parser's state] to the result of running make a component
9598
  // string given parser.
9599
4.13k
  if (state != State::INIT && state != State::AUTHORITY &&
9600
4.13k
      state != State::DONE) {
9601
2.36k
    auto value = make_component_string();
9602
    // TODO: Simplify this.
9603
2.36k
    switch (state) {
9604
591
      case State::PROTOCOL: {
9605
591
        result.protocol = value;
9606
591
        break;
9607
0
      }
9608
0
      case State::USERNAME: {
9609
0
        result.username = value;
9610
0
        break;
9611
0
      }
9612
0
      case State::PASSWORD: {
9613
0
        result.password = value;
9614
0
        break;
9615
0
      }
9616
591
      case State::HOSTNAME: {
9617
591
        result.hostname = value;
9618
591
        break;
9619
0
      }
9620
0
      case State::PORT: {
9621
0
        result.port = value;
9622
0
        break;
9623
0
      }
9624
1.18k
      case State::PATHNAME: {
9625
1.18k
        result.pathname = value;
9626
1.18k
        break;
9627
0
      }
9628
0
      case State::SEARCH: {
9629
0
        result.search = value;
9630
0
        break;
9631
0
      }
9632
0
      case State::HASH: {
9633
0
        result.hash = value;
9634
0
        break;
9635
0
      }
9636
0
      default:
9637
0
        ada::unreachable();
9638
2.36k
    }
9639
2.36k
  }
9640
9641
  // If parser's state is not "init" and new state is not "done", then:
9642
4.13k
  if (state != State::INIT && new_state != State::DONE) {
9643
    // If parser's state is "protocol", "authority", "username", or "password";
9644
    // new state is "port", "pathname", "search", or "hash"; and parser's
9645
    // result["hostname"] does not exist, then set parser's result["hostname"]
9646
    // to the empty string.
9647
1.77k
    if ((state == State::PROTOCOL || state == State::AUTHORITY ||
9648
1.77k
         state == State::USERNAME || state == State::PASSWORD) &&
9649
1.77k
        (new_state == State::PORT || new_state == State::PATHNAME ||
9650
1.18k
         new_state == State::SEARCH || new_state == State::HASH) &&
9651
1.77k
        !result.hostname)
9652
0
      result.hostname = "";
9653
1.77k
  }
9654
9655
  // If parser's state is "protocol", "authority", "username", "password",
9656
  // "hostname", or "port"; new state is "search" or "hash"; and parser's
9657
  // result["pathname"] does not exist, then:
9658
4.13k
  if ((state == State::PROTOCOL || state == State::AUTHORITY ||
9659
4.13k
       state == State::USERNAME || state == State::PASSWORD ||
9660
4.13k
       state == State::HOSTNAME || state == State::PORT) &&
9661
4.13k
      (new_state == State::SEARCH || new_state == State::HASH) &&
9662
4.13k
      !result.pathname) {
9663
0
    if (protocol_matches_a_special_scheme_flag) {
9664
0
      result.pathname = "/";
9665
0
    } else {
9666
      // Otherwise, set parser's result["pathname"] to the empty string.
9667
0
      result.pathname = "";
9668
0
    }
9669
0
  }
9670
9671
  // If parser's state is "protocol", "authority", "username", "password",
9672
  // "hostname", "port", or "pathname"; new state is "hash"; and parser's
9673
  // result["search"] does not exist, then set parser's result["search"] to
9674
  // the empty string.
9675
4.13k
  if ((state == State::PROTOCOL || state == State::AUTHORITY ||
9676
4.13k
       state == State::USERNAME || state == State::PASSWORD ||
9677
4.13k
       state == State::HOSTNAME || state == State::PORT ||
9678
4.13k
       state == State::PATHNAME) &&
9679
4.13k
      new_state == State::HASH && !result.search) {
9680
0
    result.search = "";
9681
0
  }
9682
9683
  // Set parser's state to new state.
9684
4.13k
  state = new_state;
9685
  // Increment parser's token index by skip.
9686
4.13k
  token_index += skip;
9687
  // Set parser's component start to parser's token index.
9688
4.13k
  component_start = token_index;
9689
  // Set parser's token increment to 0.
9690
4.13k
  token_increment = 0;
9691
4.13k
}
9692
9693
template <url_pattern_regex::regex_concept regex_provider>
9694
2.95k
std::string constructor_string_parser<regex_provider>::make_component_string() {
9695
  // Assert: parser's token index is less than parser's token list's size.
9696
2.95k
  ADA_ASSERT_TRUE(token_index < token_list.size());
9697
9698
  // Let token be parser's token list[parser's token index].
9699
  // Let end index be token's index.
9700
2.95k
  const auto end_index = token_list[token_index].index;
9701
  // Let component start token be the result of running get a safe token given
9702
  // parser and parser's component start.
9703
2.95k
  const auto component_start_token = get_safe_token(component_start);
9704
2.95k
  ADA_ASSERT_TRUE(component_start_token);
9705
  // Let component start input index be component start token's index.
9706
2.95k
  const auto component_start_input_index = component_start_token->index;
9707
  // Return the code point substring from component start input index to end
9708
  // index within parser's input.
9709
2.95k
  return input.substr(component_start_input_index,
9710
2.95k
                      end_index - component_start_input_index);
9711
2.95k
}
9712
9713
template <url_pattern_regex::regex_concept regex_provider>
9714
constexpr bool
9715
7.09k
constructor_string_parser<regex_provider>::is_an_identity_terminator() const {
9716
  // Return the result of running is a non-special pattern char given parser,
9717
  // parser's token index, and "@".
9718
7.09k
  return is_non_special_pattern_char(token_index, '@');
9719
7.09k
}
9720
9721
template <url_pattern_regex::regex_concept regex_provider>
9722
constexpr bool constructor_string_parser<regex_provider>::is_pathname_start()
9723
14.1k
    const {
9724
  // Return the result of running is a non-special pattern char given parser,
9725
  // parser's token index, and "/".
9726
14.1k
  return is_non_special_pattern_char(token_index, '/');
9727
14.1k
}
9728
9729
template <url_pattern_regex::regex_concept regex_provider>
9730
constexpr bool constructor_string_parser<regex_provider>::is_password_prefix()
9731
0
    const {
9732
  // Return the result of running is a non-special pattern char given parser,
9733
  // parser's token index, and ":".
9734
0
  return is_non_special_pattern_char(token_index, ':');
9735
0
}
9736
9737
template <url_pattern_regex::regex_concept regex_provider>
9738
constexpr bool constructor_string_parser<regex_provider>::is_an_ipv6_open()
9739
7.09k
    const {
9740
  // Return the result of running is a non-special pattern char given parser,
9741
  // parser's token index, and "[".
9742
7.09k
  return is_non_special_pattern_char(token_index, '[');
9743
7.09k
}
9744
9745
template <url_pattern_regex::regex_concept regex_provider>
9746
constexpr bool constructor_string_parser<regex_provider>::is_an_ipv6_close()
9747
7.09k
    const {
9748
  // Return the result of running is a non-special pattern char given parser,
9749
  // parser's token index, and "]".
9750
7.09k
  return is_non_special_pattern_char(token_index, ']');
9751
7.09k
}
9752
9753
template <url_pattern_regex::regex_concept regex_provider>
9754
constexpr bool constructor_string_parser<regex_provider>::is_port_prefix()
9755
7.09k
    const {
9756
  // Return the result of running is a non-special pattern char given parser,
9757
  // parser's token index, and ":".
9758
7.09k
  return is_non_special_pattern_char(token_index, ':');
9759
7.09k
}
9760
9761
42.1k
constexpr void Tokenizer::get_next_code_point() {
9762
42.1k
  ada_log("Tokenizer::get_next_code_point called with index=", next_index);
9763
42.1k
  ADA_ASSERT_TRUE(next_index < input.size());
9764
  // this assumes that we have a valid, non-truncated UTF-8 stream.
9765
42.1k
  code_point = 0;
9766
42.1k
  size_t number_bytes = 0;
9767
42.1k
  unsigned char first_byte = input[next_index];
9768
9769
42.1k
  if ((first_byte & 0x80) == 0) {
9770
    // 1-byte character (ASCII)
9771
42.1k
    next_index++;
9772
42.1k
    code_point = first_byte;
9773
42.1k
    ada_log("Tokenizer::get_next_code_point returning ASCII code point=",
9774
42.1k
            uint32_t(code_point));
9775
42.1k
    ada_log("Tokenizer::get_next_code_point next_index =", next_index,
9776
42.1k
            " input.size()=", input.size());
9777
42.1k
    return;
9778
42.1k
  }
9779
0
  ada_log("Tokenizer::get_next_code_point read first byte=",
9780
0
          uint32_t(first_byte));
9781
0
  if ((first_byte & 0xE0) == 0xC0) {
9782
0
    code_point = first_byte & 0x1F;
9783
0
    number_bytes = 2;
9784
0
    ada_log("Tokenizer::get_next_code_point two bytes");
9785
0
  } else if ((first_byte & 0xF0) == 0xE0) {
9786
0
    code_point = first_byte & 0x0F;
9787
0
    number_bytes = 3;
9788
0
    ada_log("Tokenizer::get_next_code_point three bytes");
9789
0
  } else if ((first_byte & 0xF8) == 0xF0) {
9790
0
    code_point = first_byte & 0x07;
9791
0
    number_bytes = 4;
9792
0
    ada_log("Tokenizer::get_next_code_point four bytes");
9793
0
  }
9794
0
  ADA_ASSERT_TRUE(number_bytes + next_index <= input.size());
9795
9796
0
  for (size_t i = 1 + next_index; i < number_bytes + next_index; ++i) {
9797
0
    unsigned char byte = input[i];
9798
0
    ada_log("Tokenizer::get_next_code_point read byte=", uint32_t(byte));
9799
0
    code_point = (code_point << 6) | (byte & 0x3F);
9800
0
  }
9801
0
  ada_log("Tokenizer::get_next_code_point returning non-ASCII code point=",
9802
0
          uint32_t(code_point));
9803
0
  ada_log("Tokenizer::get_next_code_point next_index =", next_index,
9804
0
          " input.size()=", input.size());
9805
0
  next_index += number_bytes;
9806
0
}
9807
9808
42.1k
constexpr void Tokenizer::seek_and_get_next_code_point(size_t new_index) {
9809
42.1k
  ada_log("Tokenizer::seek_and_get_next_code_point called with new_index=",
9810
42.1k
          new_index);
9811
  // Set tokenizer's next index to index.
9812
42.1k
  next_index = new_index;
9813
  // Run get the next code point given tokenizer.
9814
42.1k
  get_next_code_point();
9815
42.1k
}
9816
9817
inline void Tokenizer::add_token(token_type type, size_t next_position,
9818
48.1k
                                 size_t value_position, size_t value_length) {
9819
48.1k
  ada_log("Tokenizer::add_token called with type=", to_string(type),
9820
48.1k
          " next_position=", next_position, " value_position=", value_position);
9821
48.1k
  ADA_ASSERT_TRUE(next_position >= value_position);
9822
9823
  // Let token be a new token.
9824
  // Set token's type to type.
9825
  // Set token's index to tokenizer's index.
9826
  // Set token's value to the code point substring from value position with
9827
  // length value length within tokenizer's input.
9828
  // Append token to the back of tokenizer's token list.
9829
48.1k
  token_list.emplace_back(type, index,
9830
48.1k
                          input.substr(value_position, value_length));
9831
  // Set tokenizer's index to next position.
9832
48.1k
  index = next_position;
9833
48.1k
}
9834
9835
inline void Tokenizer::add_token_with_default_length(token_type type,
9836
                                                     size_t next_position,
9837
48.1k
                                                     size_t value_position) {
9838
  // Let computed length be next position - value position.
9839
48.1k
  auto computed_length = next_position - value_position;
9840
  // Run add a token given tokenizer, type, next position, value position, and
9841
  // computed length.
9842
48.1k
  add_token(type, next_position, value_position, computed_length);
9843
48.1k
}
9844
9845
41.0k
inline void Tokenizer::add_token_with_defaults(token_type type) {
9846
41.0k
  ada_log("Tokenizer::add_token_with_defaults called with type=",
9847
41.0k
          to_string(type));
9848
  // Run add a token with default length given tokenizer, type, tokenizer's next
9849
  // index, and tokenizer's index.
9850
41.0k
  add_token_with_default_length(type, next_index, index);
9851
41.0k
}
9852
9853
inline ada_warn_unused std::optional<errors>
9854
Tokenizer::process_tokenizing_error(size_t next_position,
9855
591
                                    size_t value_position) {
9856
  // If tokenizer's policy is "strict", then throw a TypeError.
9857
591
  if (policy == token_policy::strict) {
9858
0
    ada_log("process_tokenizing_error failed with next_position=",
9859
0
            next_position, " value_position=", value_position);
9860
0
    return errors::type_error;
9861
0
  }
9862
  // Assert: tokenizer's policy is "lenient".
9863
591
  ADA_ASSERT_TRUE(policy == token_policy::lenient);
9864
  // Run add a token with default length given tokenizer, "invalid-char", next
9865
  // position, and value position.
9866
591
  add_token_with_default_length(token_type::INVALID_CHAR, next_position,
9867
591
                                value_position);
9868
591
  return std::nullopt;
9869
591
}
9870
9871
template <url_pattern_encoding_callback F>
9872
2.95k
token* url_pattern_parser<F>::try_consume_modifier_token() {
9873
  // Let token be the result of running try to consume a token given parser and
9874
  // "other-modifier".
9875
2.95k
  auto token = try_consume_token(token_type::OTHER_MODIFIER);
9876
  // If token is not null, then return token.
9877
2.95k
  if (token) return token;
9878
  // Set token to the result of running try to consume a token given parser and
9879
  // "asterisk".
9880
  // Return token.
9881
2.95k
  return try_consume_token(token_type::ASTERISK);
9882
2.95k
}
9883
9884
template <url_pattern_encoding_callback F>
9885
token* url_pattern_parser<F>::try_consume_regexp_or_wildcard_token(
9886
20.6k
    const token* name_token) {
9887
  // Let token be the result of running try to consume a token given parser and
9888
  // "regexp".
9889
20.6k
  auto token = try_consume_token(token_type::REGEXP);
9890
  // If name token is null and token is null, then set token to the result of
9891
  // running try to consume a token given parser and "asterisk".
9892
20.6k
  if (!name_token && !token) {
9893
20.6k
    token = try_consume_token(token_type::ASTERISK);
9894
20.6k
  }
9895
  // Return token.
9896
20.6k
  return token;
9897
20.6k
}
9898
9899
template <url_pattern_encoding_callback F>
9900
104k
token* url_pattern_parser<F>::try_consume_token(token_type type) {
9901
104k
  ada_log("url_pattern_parser::try_consume_token called with type=",
9902
104k
          to_string(type));
9903
  // Assert: parser's index is less than parser's token list size.
9904
104k
  ADA_ASSERT_TRUE(index < tokens.size());
9905
  // Let next token be parser's token list[parser's index].
9906
104k
  auto& next_token = tokens[index];
9907
  // If next token's type is not type return null.
9908
104k
  if (next_token.type != type) return nullptr;
9909
  // Increase parser's index by 1.
9910
21.2k
  index++;
9911
  // Return next token.
9912
21.2k
  return &next_token;
9913
104k
}
9914
9915
template <url_pattern_encoding_callback F>
9916
0
std::string url_pattern_parser<F>::consume_text() {
9917
  // Let result be the empty string.
9918
0
  std::string result{};
9919
  // While true:
9920
0
  while (true) {
9921
    // Let token be the result of running try to consume a token given parser
9922
    // and "char".
9923
0
    auto token = try_consume_token(token_type::CHAR);
9924
    // If token is null, then set token to the result of running try to consume
9925
    // a token given parser and "escaped-char".
9926
0
    if (!token) token = try_consume_token(token_type::ESCAPED_CHAR);
9927
    // If token is null, then break.
9928
0
    if (!token) break;
9929
    // Append token's value to the end of result.
9930
0
    result.append(token->value);
9931
0
  }
9932
  // Return result.
9933
0
  return result;
9934
0
}
9935
9936
template <url_pattern_encoding_callback F>
9937
5.31k
bool url_pattern_parser<F>::consume_required_token(token_type type) {
9938
5.31k
  ada_log("url_pattern_parser::consume_required_token called with type=",
9939
5.31k
          to_string(type));
9940
  // Let result be the result of running try to consume a token given parser and
9941
  // type.
9942
5.31k
  return try_consume_token(type) != nullptr;
9943
5.31k
}
9944
9945
template <url_pattern_encoding_callback F>
9946
std::optional<errors>
9947
11.2k
url_pattern_parser<F>::maybe_add_part_from_the_pending_fixed_value() {
9948
  // If parser's pending fixed value is the empty string, then return.
9949
11.2k
  if (pending_fixed_value.empty()) {
9950
9.45k
    ada_log("pending_fixed_value is empty");
9951
9.45k
    return std::nullopt;
9952
9.45k
  }
9953
  // Let encoded value be the result of running parser's encoding callback given
9954
  // parser's pending fixed value.
9955
1.77k
  auto encoded_value = encoding_callback(pending_fixed_value);
9956
1.77k
  if (!encoded_value) {
9957
0
    ada_log("failed to encode pending_fixed_value: ", pending_fixed_value);
9958
0
    return encoded_value.error();
9959
0
  }
9960
  // Set parser's pending fixed value to the empty string.
9961
1.77k
  pending_fixed_value.clear();
9962
  // Let part be a new part whose type is "fixed-text", value is encoded value,
9963
  // and modifier is "none".
9964
  // Append part to parser's part list.
9965
1.77k
  parts.emplace_back(url_pattern_part_type::FIXED_TEXT,
9966
1.77k
                     std::move(*encoded_value),
9967
1.77k
                     url_pattern_part_modifier::none);
9968
1.77k
  return std::nullopt;
9969
1.77k
}
9970
9971
template <url_pattern_encoding_callback F>
9972
std::optional<errors> url_pattern_parser<F>::add_part(
9973
    std::string_view prefix, token* name_token, token* regexp_or_wildcard_token,
9974
2.95k
    std::string_view suffix, token* modifier_token) {
9975
  // Let modifier be "none".
9976
2.95k
  auto modifier = url_pattern_part_modifier::none;
9977
  // If modifier token is not null:
9978
2.95k
  if (modifier_token) {
9979
    // If modifier token's value is "?" then set modifier to "optional".
9980
0
    if (modifier_token->value == "?") {
9981
0
      modifier = url_pattern_part_modifier::optional;
9982
0
    } else if (modifier_token->value == "*") {
9983
      // Otherwise if modifier token's value is "*" then set modifier to
9984
      // "zero-or-more".
9985
0
      modifier = url_pattern_part_modifier::zero_or_more;
9986
0
    } else if (modifier_token->value == "+") {
9987
      // Otherwise if modifier token's value is "+" then set modifier to
9988
      // "one-or-more".
9989
0
      modifier = url_pattern_part_modifier::one_or_more;
9990
0
    }
9991
0
  }
9992
  // If name token is null and regexp or wildcard token is null and modifier
9993
  // is "none":
9994
2.95k
  if (!name_token && !regexp_or_wildcard_token &&
9995
2.95k
      modifier == url_pattern_part_modifier::none) {
9996
    // Append prefix to the end of parser's pending fixed value.
9997
0
    pending_fixed_value.append(prefix);
9998
0
    return std::nullopt;
9999
0
  }
10000
  // Run maybe add a part from the pending fixed value given parser.
10001
2.95k
  if (auto error = maybe_add_part_from_the_pending_fixed_value()) {
10002
0
    return *error;
10003
0
  }
10004
  // If name token is null and regexp or wildcard token is null:
10005
2.95k
  if (!name_token && !regexp_or_wildcard_token) {
10006
    // Assert: suffix is the empty string.
10007
0
    ADA_ASSERT_TRUE(suffix.empty());
10008
    // If prefix is the empty string, then return.
10009
0
    if (prefix.empty()) return std::nullopt;
10010
    // Let encoded value be the result of running parser's encoding callback
10011
    // given prefix.
10012
0
    auto encoded_value = encoding_callback(prefix);
10013
0
    if (!encoded_value) {
10014
0
      return encoded_value.error();
10015
0
    }
10016
    // Let part be a new part whose type is "fixed-text", value is encoded
10017
    // value, and modifier is modifier.
10018
    // Append part to parser's part list.
10019
0
    parts.emplace_back(url_pattern_part_type::FIXED_TEXT,
10020
0
                       std::move(*encoded_value), modifier);
10021
0
    return std::nullopt;
10022
0
  }
10023
  // Let regexp value be the empty string.
10024
2.95k
  std::string regexp_value{};
10025
  // If regexp or wildcard token is null, then set regexp value to parser's
10026
  // segment wildcard regexp.
10027
2.95k
  if (!regexp_or_wildcard_token) {
10028
0
    regexp_value = segment_wildcard_regexp;
10029
2.95k
  } else if (regexp_or_wildcard_token->type == token_type::ASTERISK) {
10030
    // Otherwise if regexp or wildcard token's type is "asterisk", then set
10031
    // regexp value to the full wildcard regexp value.
10032
2.95k
    regexp_value = ".*";
10033
2.95k
  } else {
10034
    // Otherwise set regexp value to regexp or wildcard token's value.
10035
0
    regexp_value = regexp_or_wildcard_token->value;
10036
0
  }
10037
  // Let type be "regexp".
10038
2.95k
  auto type = url_pattern_part_type::REGEXP;
10039
  // If regexp value is parser's segment wildcard regexp:
10040
2.95k
  if (regexp_value == segment_wildcard_regexp) {
10041
    // Set type to "segment-wildcard".
10042
0
    type = url_pattern_part_type::SEGMENT_WILDCARD;
10043
    // Set regexp value to the empty string.
10044
0
    regexp_value.clear();
10045
2.95k
  } else if (regexp_value == ".*") {
10046
    // Otherwise if regexp value is the full wildcard regexp value:
10047
    // Set type to "full-wildcard".
10048
2.95k
    type = url_pattern_part_type::FULL_WILDCARD;
10049
    // Set regexp value to the empty string.
10050
2.95k
    regexp_value.clear();
10051
2.95k
  }
10052
  // Let name be the empty string.
10053
2.95k
  std::string name{};
10054
  // If name token is not null, then set name to name token's value.
10055
2.95k
  if (name_token) {
10056
0
    name = name_token->value;
10057
2.95k
  } else if (regexp_or_wildcard_token != nullptr) {
10058
    // Otherwise if regexp or wildcard token is not null:
10059
    // Set name to parser's next numeric name, serialized.
10060
2.95k
    name = std::to_string(next_numeric_name);
10061
    // Increment parser's next numeric name by 1.
10062
2.95k
    next_numeric_name++;
10063
2.95k
  }
10064
  // If the result of running is a duplicate name given parser and name is
10065
  // true, then throw a TypeError.
10066
2.95k
  if (std::ranges::any_of(
10067
2.95k
          parts, [&name](const auto& part) { return part.name == name; })) {
10068
0
    return errors::type_error;
10069
0
  }
10070
  // Let encoded prefix be the result of running parser's encoding callback
10071
  // given prefix.
10072
2.95k
  auto encoded_prefix = encoding_callback(prefix);
10073
2.95k
  if (!encoded_prefix) return encoded_prefix.error();
10074
  // Let encoded suffix be the result of running parser's encoding callback
10075
  // given suffix.
10076
2.95k
  auto encoded_suffix = encoding_callback(suffix);
10077
2.95k
  if (!encoded_suffix) return encoded_suffix.error();
10078
  // Let part be a new part whose type is type, value is regexp value,
10079
  // modifier is modifier, name is name, prefix is encoded prefix, and suffix
10080
  // is encoded suffix.
10081
  // Append part to parser's part list.
10082
2.95k
  parts.emplace_back(type, std::move(regexp_value), modifier, std::move(name),
10083
2.95k
                     std::move(*encoded_prefix), std::move(*encoded_suffix));
10084
2.95k
  return std::nullopt;
10085
2.95k
}
10086
10087
template <url_pattern_encoding_callback F>
10088
tl::expected<std::vector<url_pattern_part>, errors> parse_pattern_string(
10089
    std::string_view input, url_pattern_compile_component_options& options,
10090
5.31k
    F& encoding_callback) {
10091
5.31k
  ada_log("parse_pattern_string input=", input);
10092
  // Let parser be a new pattern parser whose encoding callback is encoding
10093
  // callback and segment wildcard regexp is the result of running generate a
10094
  // segment wildcard regexp given options.
10095
5.31k
  auto parser = url_pattern_parser<F>(
10096
5.31k
      encoding_callback, generate_segment_wildcard_regexp(options));
10097
  // Set parser's token list to the result of running tokenize given input and
10098
  // "strict".
10099
5.31k
  auto tokenize_result = tokenize(input, token_policy::strict);
10100
5.31k
  if (!tokenize_result) {
10101
0
    ada_log("parse_pattern_string tokenize failed");
10102
0
    return tl::unexpected(tokenize_result.error());
10103
0
  }
10104
5.31k
  parser.tokens = std::move(*tokenize_result);
10105
10106
  // While parser's index is less than parser's token list's size:
10107
26.0k
  while (parser.can_continue()) {
10108
    // Let char token be the result of running try to consume a token given
10109
    // parser and "char".
10110
20.6k
    auto char_token = parser.try_consume_token(token_type::CHAR);
10111
    // Let name token be the result of running try to consume a token given
10112
    // parser and "name".
10113
20.6k
    auto name_token = parser.try_consume_token(token_type::NAME);
10114
    // Let regexp or wildcard token be the result of running try to consume a
10115
    // regexp or wildcard token given parser and name token.
10116
20.6k
    auto regexp_or_wildcard_token =
10117
20.6k
        parser.try_consume_regexp_or_wildcard_token(name_token);
10118
    // If name token is not null or regexp or wildcard token is not null:
10119
20.6k
    if (name_token || regexp_or_wildcard_token) {
10120
      // Let prefix be the empty string.
10121
2.95k
      std::string prefix{};
10122
      // If char token is not null then set prefix to char token's value.
10123
2.95k
      if (char_token) prefix = char_token->value;
10124
      // If prefix is not the empty string and not options's prefix code point:
10125
2.95k
      if (!prefix.empty() && prefix != options.get_prefix()) {
10126
        // Append prefix to the end of parser's pending fixed value.
10127
0
        parser.pending_fixed_value.append(prefix);
10128
        // Set prefix to the empty string.
10129
0
        prefix.clear();
10130
0
      }
10131
      // Run maybe add a part from the pending fixed value given parser.
10132
2.95k
      if (auto error = parser.maybe_add_part_from_the_pending_fixed_value()) {
10133
0
        ada_log("maybe_add_part_from_the_pending_fixed_value failed");
10134
0
        return tl::unexpected(*error);
10135
0
      }
10136
      // Let modifier token be the result of running try to consume a modifier
10137
      // token given parser.
10138
2.95k
      auto modifier_token = parser.try_consume_modifier_token();
10139
      // Run add a part given parser, prefix, name token, regexp or wildcard
10140
      // token, the empty string, and modifier token.
10141
2.95k
      if (auto error =
10142
2.95k
              parser.add_part(prefix, name_token, regexp_or_wildcard_token, "",
10143
2.95k
                              modifier_token)) {
10144
0
        ada_log("parser.add_part failed");
10145
0
        return tl::unexpected(*error);
10146
0
      }
10147
      // Continue.
10148
2.95k
      continue;
10149
2.95k
    }
10150
10151
    // Let fixed token be char token.
10152
17.7k
    auto fixed_token = char_token;
10153
    // If fixed token is null, then set fixed token to the result of running try
10154
    // to consume a token given parser and "escaped-char".
10155
17.7k
    if (!fixed_token)
10156
5.31k
      fixed_token = parser.try_consume_token(token_type::ESCAPED_CHAR);
10157
    // If fixed token is not null:
10158
17.7k
    if (fixed_token) {
10159
      // Append fixed token's value to parser's pending fixed value.
10160
12.4k
      parser.pending_fixed_value.append(fixed_token->value);
10161
      // Continue.
10162
12.4k
      continue;
10163
12.4k
    }
10164
    // Let open token be the result of running try to consume a token given
10165
    // parser and "open".
10166
5.31k
    auto open_token = parser.try_consume_token(token_type::OPEN);
10167
    // If open token is not null:
10168
5.31k
    if (open_token) {
10169
      // Set prefix be the result of running consume text given parser.
10170
0
      auto prefix_ = parser.consume_text();
10171
      // Set name token to the result of running try to consume a token given
10172
      // parser and "name".
10173
0
      name_token = parser.try_consume_token(token_type::NAME);
10174
      // Set regexp or wildcard token to the result of running try to consume a
10175
      // regexp or wildcard token given parser and name token.
10176
0
      regexp_or_wildcard_token =
10177
0
          parser.try_consume_regexp_or_wildcard_token(name_token);
10178
      // Let suffix be the result of running consume text given parser.
10179
0
      auto suffix_ = parser.consume_text();
10180
      // Run consume a required token given parser and "close".
10181
0
      if (!parser.consume_required_token(token_type::CLOSE)) {
10182
0
        ada_log("parser.consume_required_token failed");
10183
0
        return tl::unexpected(errors::type_error);
10184
0
      }
10185
      // Set modifier token to the result of running try to consume a modifier
10186
      // token given parser.
10187
0
      auto modifier_token = parser.try_consume_modifier_token();
10188
      // Run add a part given parser, prefix, name token, regexp or wildcard
10189
      // token, suffix, and modifier token.
10190
0
      if (auto error =
10191
0
              parser.add_part(prefix_, name_token, regexp_or_wildcard_token,
10192
0
                              suffix_, modifier_token)) {
10193
0
        return tl::unexpected(*error);
10194
0
      }
10195
      // Continue.
10196
0
      continue;
10197
0
    }
10198
    // Run maybe add a part from the pending fixed value given parser.
10199
5.31k
    if (auto error = parser.maybe_add_part_from_the_pending_fixed_value()) {
10200
0
      ada_log("maybe_add_part_from_the_pending_fixed_value failed on line 992");
10201
0
      return tl::unexpected(*error);
10202
0
    }
10203
    // Run consume a required token given parser and "end".
10204
5.31k
    if (!parser.consume_required_token(token_type::END)) {
10205
0
      return tl::unexpected(errors::type_error);
10206
0
    }
10207
5.31k
  }
10208
5.31k
  ada_log("parser.parts size is: ", parser.parts.size());
10209
  // Return parser's part list.
10210
5.31k
  return parser.parts;
10211
5.31k
}
10212
10213
template <url_pattern_regex::regex_concept regex_provider>
10214
bool protocol_component_matches_special_scheme(
10215
1.18k
    url_pattern_component<regex_provider>& component) {
10216
  // let's avoid unnecessary copy here.
10217
1.18k
  auto& regex = component.regexp;
10218
1.18k
  return regex_provider::regex_match("http", regex) ||
10219
1.18k
         regex_provider::regex_match("https", regex) ||
10220
1.18k
         regex_provider::regex_match("ws", regex) ||
10221
1.18k
         regex_provider::regex_match("wss", regex) ||
10222
1.18k
         regex_provider::regex_match("ftp", regex);
10223
1.18k
}
10224
10225
template <url_pattern_regex::regex_concept regex_provider>
10226
inline std::optional<errors> constructor_string_parser<
10227
591
    regex_provider>::compute_protocol_matches_special_scheme_flag() {
10228
591
  ada_log(
10229
591
      "constructor_string_parser::compute_protocol_matches_special_scheme_"
10230
591
      "flag");
10231
  // Let protocol string be the result of running make a component string given
10232
  // parser.
10233
591
  auto protocol_string = make_component_string();
10234
  // Let protocol component be the result of compiling a component given
10235
  // protocol string, canonicalize a protocol, and default options.
10236
591
  auto protocol_component = url_pattern_component<regex_provider>::compile(
10237
591
      protocol_string, canonicalize_protocol,
10238
591
      url_pattern_compile_component_options::DEFAULT);
10239
591
  if (!protocol_component) {
10240
0
    ada_log("url_pattern_component::compile failed for protocol_string ",
10241
0
            protocol_string);
10242
0
    return protocol_component.error();
10243
0
  }
10244
  // If the result of running protocol component matches a special scheme given
10245
  // protocol component is true, then set parser's protocol matches a special
10246
  // scheme flag to true.
10247
591
  if (protocol_component_matches_special_scheme(*protocol_component)) {
10248
591
    protocol_matches_a_special_scheme_flag = true;
10249
591
  }
10250
591
  return std::nullopt;
10251
591
}
10252
10253
template <url_pattern_regex::regex_concept regex_provider>
10254
tl::expected<url_pattern_init, errors>
10255
1.18k
constructor_string_parser<regex_provider>::parse(std::string_view input) {
10256
1.18k
  ada_log("constructor_string_parser::parse input=", input);
10257
  // Let parser be a new constructor string parser whose input is input and
10258
  // token list is the result of running tokenize given input and "lenient".
10259
1.18k
  auto token_list = tokenize(input, token_policy::lenient);
10260
1.18k
  if (!token_list) {
10261
0
    return tl::unexpected(token_list.error());
10262
0
  }
10263
1.18k
  auto parser = constructor_string_parser(input, std::move(*token_list));
10264
10265
  // While parser's token index is less than parser's token list size:
10266
50.7k
  while (parser.token_index < parser.token_list.size()) {
10267
    // Set parser's token increment to 1.
10268
50.7k
    parser.token_increment = 1;
10269
10270
    // If parser's token list[parser's token index]'s type is "end" then:
10271
50.7k
    if (parser.token_list[parser.token_index].type == token_type::END) {
10272
      // If parser's state is "init":
10273
1.77k
      if (parser.state == State::INIT) {
10274
        // Run rewind given parser.
10275
591
        parser.rewind();
10276
        // If the result of running is a hash prefix given parser is true, then
10277
        // run change state given parser, "hash" and 1.
10278
591
        if (parser.is_hash_prefix()) {
10279
0
          parser.change_state(State::HASH, 1);
10280
591
        } else if (parser.is_search_prefix()) {
10281
          // Otherwise if the result of running is a search prefix given parser
10282
          // is true: Run change state given parser, "search" and 1.
10283
0
          parser.change_state(State::SEARCH, 1);
10284
591
        } else {
10285
          // Run change state given parser, "pathname" and 0.
10286
591
          parser.change_state(State::PATHNAME, 0);
10287
591
        }
10288
        // Increment parser's token index by parser's token increment.
10289
591
        parser.token_index += parser.token_increment;
10290
        // Continue.
10291
591
        continue;
10292
591
      }
10293
10294
1.18k
      if (parser.state == State::AUTHORITY) {
10295
        // If parser's state is "authority":
10296
        // Run rewind and set state given parser, and "hostname".
10297
0
        parser.rewind();
10298
0
        parser.change_state(State::HOSTNAME, 0);
10299
        // Increment parser's token index by parser's token increment.
10300
0
        parser.token_index += parser.token_increment;
10301
        // Continue.
10302
0
        continue;
10303
0
      }
10304
10305
      // Run change state given parser, "done" and 0.
10306
1.18k
      parser.change_state(State::DONE, 0);
10307
      // Break.
10308
1.18k
      break;
10309
1.18k
    }
10310
10311
    // If the result of running is a group open given parser is true:
10312
48.9k
    if (parser.is_group_open()) {
10313
      // Increment parser's group depth by 1.
10314
0
      parser.group_depth += 1;
10315
      // Increment parser's token index by parser's token increment.
10316
0
      parser.token_index += parser.token_increment;
10317
0
    }
10318
10319
    // If parser's group depth is greater than 0:
10320
48.9k
    if (parser.group_depth > 0) {
10321
      // If the result of running is a group close given parser is true, then
10322
      // decrement parser's group depth by 1.
10323
0
      if (parser.is_group_close()) {
10324
0
        parser.group_depth -= 1;
10325
0
      } else {
10326
        // Increment parser's token index by parser's token increment.
10327
0
        parser.token_index += parser.token_increment;
10328
0
        continue;
10329
0
      }
10330
0
    }
10331
10332
    // Switch on parser's state and run the associated steps:
10333
48.9k
    switch (parser.state) {
10334
16.7k
      case State::INIT: {
10335
        // If the result of running is a protocol suffix given parser is true:
10336
16.7k
        if (parser.is_protocol_suffix()) {
10337
          // Run rewind and set state given parser and "protocol".
10338
591
          parser.rewind();
10339
591
          parser.change_state(State::PROTOCOL, 0);
10340
591
        }
10341
16.7k
        break;
10342
0
      }
10343
3.54k
      case State::PROTOCOL: {
10344
        // If the result of running is a protocol suffix given parser is true:
10345
3.54k
        if (parser.is_protocol_suffix()) {
10346
          // Run compute protocol matches a special scheme flag given parser.
10347
591
          if (const auto error =
10348
591
                  parser.compute_protocol_matches_special_scheme_flag()) {
10349
0
            ada_log("compute_protocol_matches_special_scheme_flag failed");
10350
0
            return tl::unexpected(*error);
10351
0
          }
10352
          // Let next state be "pathname".
10353
591
          auto next_state = State::PATHNAME;
10354
          // Let skip be 1.
10355
591
          auto skip = 1;
10356
          // If the result of running next is authority slashes given parser is
10357
          // true:
10358
591
          if (parser.next_is_authority_slashes()) {
10359
            // Set next state to "authority".
10360
591
            next_state = State::AUTHORITY;
10361
            // Set skip to 3.
10362
591
            skip = 3;
10363
591
          } else if (parser.protocol_matches_a_special_scheme_flag) {
10364
            // Otherwise if parser's protocol matches a special scheme flag is
10365
            // true, then set next state to "authority".
10366
0
            next_state = State::AUTHORITY;
10367
0
          }
10368
10369
          // Run change state given parser, next state, and skip.
10370
591
          parser.change_state(next_state, skip);
10371
591
        }
10372
3.54k
        break;
10373
3.54k
      }
10374
7.09k
      case State::AUTHORITY: {
10375
        // If the result of running is an identity terminator given parser is
10376
        // true, then run rewind and set state given parser and "username".
10377
7.09k
        if (parser.is_an_identity_terminator()) {
10378
0
          parser.rewind();
10379
0
          parser.change_state(State::USERNAME, 0);
10380
7.09k
        } else if (parser.is_pathname_start() || parser.is_search_prefix() ||
10381
7.09k
                   parser.is_hash_prefix()) {
10382
          // Otherwise if any of the following are true:
10383
          // - the result of running is a pathname start given parser;
10384
          // - the result of running is a search prefix given parser; or
10385
          // - the result of running is a hash prefix given parser,
10386
          // then run rewind and set state given parser and "hostname".
10387
591
          parser.rewind();
10388
591
          parser.change_state(State::HOSTNAME, 0);
10389
591
        }
10390
7.09k
        break;
10391
3.54k
      }
10392
0
      case State::USERNAME: {
10393
        // If the result of running is a password prefix given parser is true,
10394
        // then run change state given parser, "password", and 1.
10395
0
        if (parser.is_password_prefix()) {
10396
0
          parser.change_state(State::PASSWORD, 1);
10397
0
        } else if (parser.is_an_identity_terminator()) {
10398
          // Otherwise if the result of running is an identity terminator given
10399
          // parser is true, then run change state given parser, "hostname",
10400
          // and 1.
10401
0
          parser.change_state(State::HOSTNAME, 1);
10402
0
        }
10403
0
        break;
10404
3.54k
      }
10405
0
      case State::PASSWORD: {
10406
        // If the result of running is an identity terminator given parser is
10407
        // true, then run change state given parser, "hostname", and 1.
10408
0
        if (parser.is_an_identity_terminator()) {
10409
0
          parser.change_state(State::HOSTNAME, 1);
10410
0
        }
10411
0
        break;
10412
3.54k
      }
10413
7.09k
      case State::HOSTNAME: {
10414
        // If the result of running is an IPv6 open given parser is true, then
10415
        // increment parser's hostname IPv6 bracket depth by 1.
10416
7.09k
        if (parser.is_an_ipv6_open()) {
10417
0
          parser.hostname_ipv6_bracket_depth += 1;
10418
7.09k
        } else if (parser.is_an_ipv6_close()) {
10419
          // Otherwise if the result of running is an IPv6 close given parser is
10420
          // true, then decrement parser's hostname IPv6 bracket depth by 1.
10421
0
          parser.hostname_ipv6_bracket_depth -= 1;
10422
7.09k
        } else if (parser.is_port_prefix() &&
10423
7.09k
                   parser.hostname_ipv6_bracket_depth == 0) {
10424
          // Otherwise if the result of running is a port prefix given parser is
10425
          // true and parser's hostname IPv6 bracket depth is zero, then run
10426
          // change state given parser, "port", and 1.
10427
0
          parser.change_state(State::PORT, 1);
10428
7.09k
        } else if (parser.is_pathname_start()) {
10429
          // Otherwise if the result of running is a pathname start given parser
10430
          // is true, then run change state given parser, "pathname", and 0.
10431
591
          parser.change_state(State::PATHNAME, 0);
10432
6.50k
        } else if (parser.is_search_prefix()) {
10433
          // Otherwise if the result of running is a search prefix given parser
10434
          // is true, then run change state given parser, "search", and 1.
10435
0
          parser.change_state(State::SEARCH, 1);
10436
6.50k
        } else if (parser.is_hash_prefix()) {
10437
          // Otherwise if the result of running is a hash prefix given parser is
10438
          // true, then run change state given parser, "hash", and 1.
10439
0
          parser.change_state(State::HASH, 1);
10440
0
        }
10441
10442
7.09k
        break;
10443
3.54k
      }
10444
0
      case State::PORT: {
10445
        // If the result of running is a pathname start given parser is true,
10446
        // then run change state given parser, "pathname", and 0.
10447
0
        if (parser.is_pathname_start()) {
10448
0
          parser.change_state(State::PATHNAME, 0);
10449
0
        } else if (parser.is_search_prefix()) {
10450
          // Otherwise if the result of running is a search prefix given parser
10451
          // is true, then run change state given parser, "search", and 1.
10452
0
          parser.change_state(State::SEARCH, 1);
10453
0
        } else if (parser.is_hash_prefix()) {
10454
          // Otherwise if the result of running is a hash prefix given parser is
10455
          // true, then run change state given parser, "hash", and 1.
10456
0
          parser.change_state(State::HASH, 1);
10457
0
        }
10458
0
        break;
10459
3.54k
      }
10460
14.4k
      case State::PATHNAME: {
10461
        // If the result of running is a search prefix given parser is true,
10462
        // then run change state given parser, "search", and 1.
10463
14.4k
        if (parser.is_search_prefix()) {
10464
0
          parser.change_state(State::SEARCH, 1);
10465
14.4k
        } else if (parser.is_hash_prefix()) {
10466
          // Otherwise if the result of running is a hash prefix given parser is
10467
          // true, then run change state given parser, "hash", and 1.
10468
0
          parser.change_state(State::HASH, 1);
10469
0
        }
10470
14.4k
        break;
10471
3.54k
      }
10472
0
      case State::SEARCH: {
10473
        // If the result of running is a hash prefix given parser is true, then
10474
        // run change state given parser, "hash", and 1.
10475
0
        if (parser.is_hash_prefix()) {
10476
0
          parser.change_state(State::HASH, 1);
10477
0
        }
10478
0
        break;
10479
3.54k
      }
10480
0
      case State::HASH: {
10481
        // Do nothing
10482
0
        break;
10483
3.54k
      }
10484
0
      default: {
10485
        // Assert: This step is never reached.
10486
0
        unreachable();
10487
0
      }
10488
48.9k
    }
10489
10490
    // Increment parser's token index by parser's token increment.
10491
48.9k
    parser.token_index += parser.token_increment;
10492
48.9k
  }
10493
10494
  // If parser's result contains "hostname" and not "port", then set parser's
10495
  // result["port"] to the empty string.
10496
1.18k
  if (parser.result.hostname && !parser.result.port) {
10497
591
    parser.result.port = "";
10498
591
  }
10499
10500
  // Return parser's result.
10501
1.18k
  return parser.result;
10502
1.18k
}
10503
10504
}  // namespace ada::url_pattern_helpers
10505
#endif  // ADA_INCLUDE_URL_PATTERN
10506
#endif
10507
/* end file include/ada/url_pattern_helpers-inl.h */
10508
10509
// Public API
10510
/* begin file include/ada/ada_version.h */
10511
/**
10512
 * @file ada_version.h
10513
 * @brief Definitions for Ada's version number.
10514
 */
10515
#ifndef ADA_ADA_VERSION_H
10516
#define ADA_ADA_VERSION_H
10517
10518
#define ADA_VERSION "3.2.7"
10519
10520
namespace ada {
10521
10522
enum {
10523
  ADA_VERSION_MAJOR = 3,
10524
  ADA_VERSION_MINOR = 2,
10525
  ADA_VERSION_REVISION = 7,
10526
};
10527
10528
}  // namespace ada
10529
10530
#endif  // ADA_ADA_VERSION_H
10531
/* end file include/ada/ada_version.h */
10532
/* begin file include/ada/implementation-inl.h */
10533
/**
10534
 * @file implementation-inl.h
10535
 */
10536
#ifndef ADA_IMPLEMENTATION_INL_H
10537
#define ADA_IMPLEMENTATION_INL_H
10538
10539
10540
10541
#include <variant>
10542
#include <string_view>
10543
10544
namespace ada {
10545
10546
#if ADA_INCLUDE_URL_PATTERN
10547
template <url_pattern_regex::regex_concept regex_provider>
10548
ada_warn_unused tl::expected<url_pattern<regex_provider>, errors>
10549
parse_url_pattern(std::variant<std::string_view, url_pattern_init>&& input,
10550
                  const std::string_view* base_url,
10551
1.57k
                  const url_pattern_options* options) {
10552
1.57k
  return parser::parse_url_pattern_impl<regex_provider>(std::move(input),
10553
1.57k
                                                        base_url, options);
10554
1.57k
}
10555
#endif  // ADA_INCLUDE_URL_PATTERN
10556
10557
}  // namespace ada
10558
10559
#endif  // ADA_IMPLEMENTATION_INL_H
10560
/* end file include/ada/implementation-inl.h */
10561
10562
#endif  // ADA_H
10563
/* end file include/ada.h */