Coverage Report

Created: 2025-10-10 06:28

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ada-url/build/singleheader/ada.h
Line
Count
Source
1
/* auto-generated on 2025-10-03 19:59:52 -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
#if defined(__riscv_v) && __riscv_v_intrinsic >= 11000
439
// Support RVV intrinsics v0.11 and above
440
#define ADA_RVV 1
441
#endif
442
443
#ifndef __has_cpp_attribute
444
#define ada_lifetime_bound
445
#elif __has_cpp_attribute(msvc::lifetimebound)
446
#define ada_lifetime_bound [[msvc::lifetimebound]]
447
#elif __has_cpp_attribute(clang::lifetimebound)
448
#define ada_lifetime_bound [[clang::lifetimebound]]
449
#elif __has_cpp_attribute(lifetimebound)
450
#define ada_lifetime_bound [[lifetimebound]]
451
#else
452
#define ada_lifetime_bound
453
#endif
454
455
#ifdef __cpp_lib_format
456
#if __cpp_lib_format >= 202110L
457
#include <format>
458
#define ADA_HAS_FORMAT 1
459
#endif
460
#endif
461
462
#ifndef ADA_INCLUDE_URL_PATTERN
463
#define ADA_INCLUDE_URL_PATTERN 1
464
#endif  // ADA_INCLUDE_URL_PATTERN
465
466
#endif  // ADA_COMMON_DEFS_H
467
/* end file include/ada/common_defs.h */
468
#include <cstdint>
469
470
/**
471
 * These functions are not part of our public API and may
472
 * change at any time.
473
 * @private
474
 * @namespace ada::character_sets
475
 * @brief Includes the definitions for unicode character sets.
476
 */
477
namespace ada::character_sets {
478
ada_really_inline constexpr bool bit_at(const uint8_t a[], uint8_t i);
479
}  // namespace ada::character_sets
480
481
#endif  // ADA_CHARACTER_SETS_H
482
/* end file include/ada/character_sets.h */
483
/* begin file include/ada/character_sets-inl.h */
484
/**
485
 * @file character_sets-inl.h
486
 * @brief Definitions of the character sets used by unicode functions.
487
 * @author Node.js
488
 * @see https://github.com/nodejs/node/blob/main/src/node_url_tables.cc
489
 */
490
#ifndef ADA_CHARACTER_SETS_INL_H
491
#define ADA_CHARACTER_SETS_INL_H
492
493
494
/**
495
 * These functions are not part of our public API and may
496
 * change at any time.
497
 * @private
498
 */
499
namespace ada::character_sets {
500
501
constexpr char hex[1024] =
502
    "%00\0%01\0%02\0%03\0%04\0%05\0%06\0%07\0"
503
    "%08\0%09\0%0A\0%0B\0%0C\0%0D\0%0E\0%0F\0"
504
    "%10\0%11\0%12\0%13\0%14\0%15\0%16\0%17\0"
505
    "%18\0%19\0%1A\0%1B\0%1C\0%1D\0%1E\0%1F\0"
506
    "%20\0%21\0%22\0%23\0%24\0%25\0%26\0%27\0"
507
    "%28\0%29\0%2A\0%2B\0%2C\0%2D\0%2E\0%2F\0"
508
    "%30\0%31\0%32\0%33\0%34\0%35\0%36\0%37\0"
509
    "%38\0%39\0%3A\0%3B\0%3C\0%3D\0%3E\0%3F\0"
510
    "%40\0%41\0%42\0%43\0%44\0%45\0%46\0%47\0"
511
    "%48\0%49\0%4A\0%4B\0%4C\0%4D\0%4E\0%4F\0"
512
    "%50\0%51\0%52\0%53\0%54\0%55\0%56\0%57\0"
513
    "%58\0%59\0%5A\0%5B\0%5C\0%5D\0%5E\0%5F\0"
514
    "%60\0%61\0%62\0%63\0%64\0%65\0%66\0%67\0"
515
    "%68\0%69\0%6A\0%6B\0%6C\0%6D\0%6E\0%6F\0"
516
    "%70\0%71\0%72\0%73\0%74\0%75\0%76\0%77\0"
517
    "%78\0%79\0%7A\0%7B\0%7C\0%7D\0%7E\0%7F\0"
518
    "%80\0%81\0%82\0%83\0%84\0%85\0%86\0%87\0"
519
    "%88\0%89\0%8A\0%8B\0%8C\0%8D\0%8E\0%8F\0"
520
    "%90\0%91\0%92\0%93\0%94\0%95\0%96\0%97\0"
521
    "%98\0%99\0%9A\0%9B\0%9C\0%9D\0%9E\0%9F\0"
522
    "%A0\0%A1\0%A2\0%A3\0%A4\0%A5\0%A6\0%A7\0"
523
    "%A8\0%A9\0%AA\0%AB\0%AC\0%AD\0%AE\0%AF\0"
524
    "%B0\0%B1\0%B2\0%B3\0%B4\0%B5\0%B6\0%B7\0"
525
    "%B8\0%B9\0%BA\0%BB\0%BC\0%BD\0%BE\0%BF\0"
526
    "%C0\0%C1\0%C2\0%C3\0%C4\0%C5\0%C6\0%C7\0"
527
    "%C8\0%C9\0%CA\0%CB\0%CC\0%CD\0%CE\0%CF\0"
528
    "%D0\0%D1\0%D2\0%D3\0%D4\0%D5\0%D6\0%D7\0"
529
    "%D8\0%D9\0%DA\0%DB\0%DC\0%DD\0%DE\0%DF\0"
530
    "%E0\0%E1\0%E2\0%E3\0%E4\0%E5\0%E6\0%E7\0"
531
    "%E8\0%E9\0%EA\0%EB\0%EC\0%ED\0%EE\0%EF\0"
532
    "%F0\0%F1\0%F2\0%F3\0%F4\0%F5\0%F6\0%F7\0"
533
    "%F8\0%F9\0%FA\0%FB\0%FC\0%FD\0%FE\0%FF";
534
535
constexpr uint8_t C0_CONTROL_PERCENT_ENCODE[32] = {
536
    // 00     01     02     03     04     05     06     07
537
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
538
    // 08     09     0A     0B     0C     0D     0E     0F
539
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
540
    // 10     11     12     13     14     15     16     17
541
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
542
    // 18     19     1A     1B     1C     1D     1E     1F
543
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
544
    // 20     21     22     23     24     25     26     27
545
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
546
    // 28     29     2A     2B     2C     2D     2E     2F
547
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
548
    // 30     31     32     33     34     35     36     37
549
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
550
    // 38     39     3A     3B     3C     3D     3E     3F
551
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
552
    // 40     41     42     43     44     45     46     47
553
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
554
    // 48     49     4A     4B     4C     4D     4E     4F
555
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
556
    // 50     51     52     53     54     55     56     57
557
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
558
    // 58     59     5A     5B     5C     5D     5E     5F
559
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
560
    // 60     61     62     63     64     65     66     67
561
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
562
    // 68     69     6A     6B     6C     6D     6E     6F
563
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
564
    // 70     71     72     73     74     75     76     77
565
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
566
    // 78     79     7A     7B     7C     7D     7E     7F
567
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x80,
568
    // 80     81     82     83     84     85     86     87
569
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
570
    // 88     89     8A     8B     8C     8D     8E     8F
571
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
572
    // 90     91     92     93     94     95     96     97
573
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
574
    // 98     99     9A     9B     9C     9D     9E     9F
575
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
576
    // A0     A1     A2     A3     A4     A5     A6     A7
577
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
578
    // A8     A9     AA     AB     AC     AD     AE     AF
579
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
580
    // B0     B1     B2     B3     B4     B5     B6     B7
581
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
582
    // B8     B9     BA     BB     BC     BD     BE     BF
583
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
584
    // C0     C1     C2     C3     C4     C5     C6     C7
585
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
586
    // C8     C9     CA     CB     CC     CD     CE     CF
587
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
588
    // D0     D1     D2     D3     D4     D5     D6     D7
589
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
590
    // D8     D9     DA     DB     DC     DD     DE     DF
591
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
592
    // E0     E1     E2     E3     E4     E5     E6     E7
593
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
594
    // E8     E9     EA     EB     EC     ED     EE     EF
595
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
596
    // F0     F1     F2     F3     F4     F5     F6     F7
597
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
598
    // F8     F9     FA     FB     FC     FD     FE     FF
599
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80};
600
601
constexpr uint8_t SPECIAL_QUERY_PERCENT_ENCODE[32] = {
602
    // 00     01     02     03     04     05     06     07
603
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
604
    // 08     09     0A     0B     0C     0D     0E     0F
605
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
606
    // 10     11     12     13     14     15     16     17
607
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
608
    // 18     19     1A     1B     1C     1D     1E     1F
609
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
610
    // 20     21     22     23     24     25     26     27
611
    0x01 | 0x00 | 0x04 | 0x08 | 0x00 | 0x00 | 0x00 | 0x80,
612
    // 28     29     2A     2B     2C     2D     2E     2F
613
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
614
    // 30     31     32     33     34     35     36     37
615
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
616
    // 38     39     3A     3B     3C     3D     3E     3F
617
    0x00 | 0x00 | 0x00 | 0x00 | 0x10 | 0x00 | 0x40 | 0x00,
618
    // 40     41     42     43     44     45     46     47
619
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
620
    // 48     49     4A     4B     4C     4D     4E     4F
621
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
622
    // 50     51     52     53     54     55     56     57
623
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
624
    // 58     59     5A     5B     5C     5D     5E     5F
625
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
626
    // 60     61     62     63     64     65     66     67
627
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
628
    // 68     69     6A     6B     6C     6D     6E     6F
629
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
630
    // 70     71     72     73     74     75     76     77
631
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
632
    // 78     79     7A     7B     7C     7D     7E     7F
633
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x80,
634
    // 80     81     82     83     84     85     86     87
635
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
636
    // 88     89     8A     8B     8C     8D     8E     8F
637
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
638
    // 90     91     92     93     94     95     96     97
639
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
640
    // 98     99     9A     9B     9C     9D     9E     9F
641
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
642
    // A0     A1     A2     A3     A4     A5     A6     A7
643
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
644
    // A8     A9     AA     AB     AC     AD     AE     AF
645
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
646
    // B0     B1     B2     B3     B4     B5     B6     B7
647
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
648
    // B8     B9     BA     BB     BC     BD     BE     BF
649
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
650
    // C0     C1     C2     C3     C4     C5     C6     C7
651
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
652
    // C8     C9     CA     CB     CC     CD     CE     CF
653
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
654
    // D0     D1     D2     D3     D4     D5     D6     D7
655
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
656
    // D8     D9     DA     DB     DC     DD     DE     DF
657
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
658
    // E0     E1     E2     E3     E4     E5     E6     E7
659
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
660
    // E8     E9     EA     EB     EC     ED     EE     EF
661
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
662
    // F0     F1     F2     F3     F4     F5     F6     F7
663
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
664
    // F8     F9     FA     FB     FC     FD     FE     FF
665
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80};
666
667
constexpr uint8_t QUERY_PERCENT_ENCODE[32] = {
668
    // 00     01     02     03     04     05     06     07
669
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
670
    // 08     09     0A     0B     0C     0D     0E     0F
671
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
672
    // 10     11     12     13     14     15     16     17
673
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
674
    // 18     19     1A     1B     1C     1D     1E     1F
675
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
676
    // 20     21     22     23     24     25     26     27
677
    0x01 | 0x00 | 0x04 | 0x08 | 0x00 | 0x00 | 0x00 | 0x00,
678
    // 28     29     2A     2B     2C     2D     2E     2F
679
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
680
    // 30     31     32     33     34     35     36     37
681
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
682
    // 38     39     3A     3B     3C     3D     3E     3F
683
    0x00 | 0x00 | 0x00 | 0x00 | 0x10 | 0x00 | 0x40 | 0x00,
684
    // 40     41     42     43     44     45     46     47
685
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
686
    // 48     49     4A     4B     4C     4D     4E     4F
687
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
688
    // 50     51     52     53     54     55     56     57
689
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
690
    // 58     59     5A     5B     5C     5D     5E     5F
691
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
692
    // 60     61     62     63     64     65     66     67
693
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
694
    // 68     69     6A     6B     6C     6D     6E     6F
695
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
696
    // 70     71     72     73     74     75     76     77
697
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
698
    // 78     79     7A     7B     7C     7D     7E     7F
699
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x80,
700
    // 80     81     82     83     84     85     86     87
701
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
702
    // 88     89     8A     8B     8C     8D     8E     8F
703
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
704
    // 90     91     92     93     94     95     96     97
705
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
706
    // 98     99     9A     9B     9C     9D     9E     9F
707
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
708
    // A0     A1     A2     A3     A4     A5     A6     A7
709
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
710
    // A8     A9     AA     AB     AC     AD     AE     AF
711
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
712
    // B0     B1     B2     B3     B4     B5     B6     B7
713
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
714
    // B8     B9     BA     BB     BC     BD     BE     BF
715
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
716
    // C0     C1     C2     C3     C4     C5     C6     C7
717
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
718
    // C8     C9     CA     CB     CC     CD     CE     CF
719
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
720
    // D0     D1     D2     D3     D4     D5     D6     D7
721
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
722
    // D8     D9     DA     DB     DC     DD     DE     DF
723
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
724
    // E0     E1     E2     E3     E4     E5     E6     E7
725
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
726
    // E8     E9     EA     EB     EC     ED     EE     EF
727
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
728
    // F0     F1     F2     F3     F4     F5     F6     F7
729
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
730
    // F8     F9     FA     FB     FC     FD     FE     FF
731
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80};
732
733
constexpr uint8_t FRAGMENT_PERCENT_ENCODE[32] = {
734
    // 00     01     02     03     04     05     06     07
735
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
736
    // 08     09     0A     0B     0C     0D     0E     0F
737
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
738
    // 10     11     12     13     14     15     16     17
739
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
740
    // 18     19     1A     1B     1C     1D     1E     1F
741
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
742
    // 20     21     22     23     24     25     26     27
743
    0x01 | 0x00 | 0x04 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
744
    // 28     29     2A     2B     2C     2D     2E     2F
745
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
746
    // 30     31     32     33     34     35     36     37
747
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
748
    // 38     39     3A     3B     3C     3D     3E     3F
749
    0x00 | 0x00 | 0x00 | 0x00 | 0x10 | 0x00 | 0x40 | 0x00,
750
    // 40     41     42     43     44     45     46     47
751
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
752
    // 48     49     4A     4B     4C     4D     4E     4F
753
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
754
    // 50     51     52     53     54     55     56     57
755
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
756
    // 58     59     5A     5B     5C     5D     5E     5F
757
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
758
    // 60     61     62     63     64     65     66     67
759
    0x01 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
760
    // 68     69     6A     6B     6C     6D     6E     6F
761
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
762
    // 70     71     72     73     74     75     76     77
763
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
764
    // 78     79     7A     7B     7C     7D     7E     7F
765
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x80,
766
    // 80     81     82     83     84     85     86     87
767
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
768
    // 88     89     8A     8B     8C     8D     8E     8F
769
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
770
    // 90     91     92     93     94     95     96     97
771
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
772
    // 98     99     9A     9B     9C     9D     9E     9F
773
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
774
    // A0     A1     A2     A3     A4     A5     A6     A7
775
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
776
    // A8     A9     AA     AB     AC     AD     AE     AF
777
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
778
    // B0     B1     B2     B3     B4     B5     B6     B7
779
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
780
    // B8     B9     BA     BB     BC     BD     BE     BF
781
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
782
    // C0     C1     C2     C3     C4     C5     C6     C7
783
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
784
    // C8     C9     CA     CB     CC     CD     CE     CF
785
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
786
    // D0     D1     D2     D3     D4     D5     D6     D7
787
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
788
    // D8     D9     DA     DB     DC     DD     DE     DF
789
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
790
    // E0     E1     E2     E3     E4     E5     E6     E7
791
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
792
    // E8     E9     EA     EB     EC     ED     EE     EF
793
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
794
    // F0     F1     F2     F3     F4     F5     F6     F7
795
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
796
    // F8     F9     FA     FB     FC     FD     FE     FF
797
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80};
798
799
constexpr uint8_t USERINFO_PERCENT_ENCODE[32] = {
800
    // 00     01     02     03     04     05     06     07
801
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
802
    // 08     09     0A     0B     0C     0D     0E     0F
803
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
804
    // 10     11     12     13     14     15     16     17
805
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
806
    // 18     19     1A     1B     1C     1D     1E     1F
807
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
808
    // 20     21     22     23     24     25     26     27
809
    0x01 | 0x00 | 0x04 | 0x08 | 0x00 | 0x00 | 0x00 | 0x00,
810
    // 28     29     2A     2B     2C     2D     2E     2F
811
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x80,
812
    // 30     31     32     33     34     35     36     37
813
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
814
    // 38     39     3A     3B     3C     3D     3E     3F
815
    0x00 | 0x00 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
816
    // 40     41     42     43     44     45     46     47
817
    0x01 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
818
    // 48     49     4A     4B     4C     4D     4E     4F
819
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
820
    // 50     51     52     53     54     55     56     57
821
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
822
    // 58     59     5A     5B     5C     5D     5E     5F
823
    0x00 | 0x00 | 0x00 | 0x08 | 0x10 | 0x20 | 0x40 | 0x00,
824
    // 60     61     62     63     64     65     66     67
825
    0x01 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
826
    // 68     69     6A     6B     6C     6D     6E     6F
827
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
828
    // 70     71     72     73     74     75     76     77
829
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
830
    // 78     79     7A     7B     7C     7D     7E     7F
831
    0x00 | 0x00 | 0x00 | 0x08 | 0x10 | 0x20 | 0x00 | 0x80,
832
    // 80     81     82     83     84     85     86     87
833
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
834
    // 88     89     8A     8B     8C     8D     8E     8F
835
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
836
    // 90     91     92     93     94     95     96     97
837
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
838
    // 98     99     9A     9B     9C     9D     9E     9F
839
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
840
    // A0     A1     A2     A3     A4     A5     A6     A7
841
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
842
    // A8     A9     AA     AB     AC     AD     AE     AF
843
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
844
    // B0     B1     B2     B3     B4     B5     B6     B7
845
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
846
    // B8     B9     BA     BB     BC     BD     BE     BF
847
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
848
    // C0     C1     C2     C3     C4     C5     C6     C7
849
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
850
    // C8     C9     CA     CB     CC     CD     CE     CF
851
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
852
    // D0     D1     D2     D3     D4     D5     D6     D7
853
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
854
    // D8     D9     DA     DB     DC     DD     DE     DF
855
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
856
    // E0     E1     E2     E3     E4     E5     E6     E7
857
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
858
    // E8     E9     EA     EB     EC     ED     EE     EF
859
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
860
    // F0     F1     F2     F3     F4     F5     F6     F7
861
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
862
    // F8     F9     FA     FB     FC     FD     FE     FF
863
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80};
864
865
constexpr uint8_t PATH_PERCENT_ENCODE[32] = {
866
    // 00     01     02     03     04     05     06     07
867
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
868
    // 08     09     0A     0B     0C     0D     0E     0F
869
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
870
    // 10     11     12     13     14     15     16     17
871
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
872
    // 18     19     1A     1B     1C     1D     1E     1F
873
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
874
    // 20     21     22     23     24     25     26     27
875
    0x01 | 0x00 | 0x04 | 0x08 | 0x00 | 0x00 | 0x00 | 0x00,
876
    // 28     29     2A     2B     2C     2D     2E     2F
877
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
878
    // 30     31     32     33     34     35     36     37
879
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
880
    // 38     39     3A     3B     3C     3D     3E     3F
881
    0x00 | 0x00 | 0x00 | 0x00 | 0x10 | 0x00 | 0x40 | 0x80,
882
    // 40     41     42     43     44     45     46     47
883
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
884
    // 48     49     4A     4B     4C     4D     4E     4F
885
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
886
    // 50     51     52     53     54     55     56     57
887
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
888
    // 58     59     5A     5B     5C     5D     5E     5F
889
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x40 | 0x00,
890
    // 60     61     62     63     64     65     66     67
891
    0x01 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
892
    // 68     69     6A     6B     6C     6D     6E     6F
893
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
894
    // 70     71     72     73     74     75     76     77
895
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
896
    // 78     79     7A     7B     7C     7D     7E     7F
897
    0x00 | 0x00 | 0x00 | 0x08 | 0x00 | 0x20 | 0x00 | 0x80,
898
    // 80     81     82     83     84     85     86     87
899
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
900
    // 88     89     8A     8B     8C     8D     8E     8F
901
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
902
    // 90     91     92     93     94     95     96     97
903
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
904
    // 98     99     9A     9B     9C     9D     9E     9F
905
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
906
    // A0     A1     A2     A3     A4     A5     A6     A7
907
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
908
    // A8     A9     AA     AB     AC     AD     AE     AF
909
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
910
    // B0     B1     B2     B3     B4     B5     B6     B7
911
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
912
    // B8     B9     BA     BB     BC     BD     BE     BF
913
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
914
    // C0     C1     C2     C3     C4     C5     C6     C7
915
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
916
    // C8     C9     CA     CB     CC     CD     CE     CF
917
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
918
    // D0     D1     D2     D3     D4     D5     D6     D7
919
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
920
    // D8     D9     DA     DB     DC     DD     DE     DF
921
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
922
    // E0     E1     E2     E3     E4     E5     E6     E7
923
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
924
    // E8     E9     EA     EB     EC     ED     EE     EF
925
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
926
    // F0     F1     F2     F3     F4     F5     F6     F7
927
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
928
    // F8     F9     FA     FB     FC     FD     FE     FF
929
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80};
930
931
constexpr uint8_t WWW_FORM_URLENCODED_PERCENT_ENCODE[32] = {
932
    // 00     01     02     03     04     05     06     07
933
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
934
    // 08     09     0A     0B     0C     0D     0E     0F
935
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
936
    // 10     11     12     13     14     15     16     17
937
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
938
    // 18     19     1A     1B     1C     1D     1E     1F
939
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
940
    // 20     21     22     23     24     25     26     27
941
    0x00 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
942
    // 28     29     2A     2B     2C     2D     2E     2F
943
    0x01 | 0x02 | 0x00 | 0x08 | 0x10 | 0x00 | 0x00 | 0x80,
944
    // 30     31     32     33     34     35     36     37
945
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
946
    // 38     39     3A     3B     3C     3D     3E     3F
947
    0x00 | 0x00 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
948
    // 40     41     42     43     44     45     46     47
949
    0x01 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
950
    // 48     49     4A     4B     4C     4D     4E     4F
951
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
952
    // 50     51     52     53     54     55     56     57
953
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
954
    // 58     59     5A     5B     5C     5D     5E     5F
955
    0x00 | 0x00 | 0x00 | 0x08 | 0x10 | 0x20 | 0x40 | 0x00,
956
    // 60     61     62     63     64     65     66     67
957
    0x01 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
958
    // 68     69     6A     6B     6C     6D     6E     6F
959
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
960
    // 70     71     72     73     74     75     76     77
961
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
962
    // 78     79     7A     7B     7C     7D     7E     7F
963
    0x00 | 0x00 | 0x00 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
964
    // 80     81     82     83     84     85     86     87
965
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
966
    // 88     89     8A     8B     8C     8D     8E     8F
967
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
968
    // 90     91     92     93     94     95     96     97
969
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
970
    // 98     99     9A     9B     9C     9D     9E     9F
971
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
972
    // A0     A1     A2     A3     A4     A5     A6     A7
973
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
974
    // A8     A9     AA     AB     AC     AD     AE     AF
975
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
976
    // B0     B1     B2     B3     B4     B5     B6     B7
977
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
978
    // B8     B9     BA     BB     BC     BD     BE     BF
979
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
980
    // C0     C1     C2     C3     C4     C5     C6     C7
981
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
982
    // C8     C9     CA     CB     CC     CD     CE     CF
983
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
984
    // D0     D1     D2     D3     D4     D5     D6     D7
985
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
986
    // D8     D9     DA     DB     DC     DD     DE     DF
987
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
988
    // E0     E1     E2     E3     E4     E5     E6     E7
989
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
990
    // E8     E9     EA     EB     EC     ED     EE     EF
991
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
992
    // F0     F1     F2     F3     F4     F5     F6     F7
993
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
994
    // F8     F9     FA     FB     FC     FD     FE     FF
995
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80};
996
997
3.29M
ada_really_inline constexpr bool bit_at(const uint8_t a[], const uint8_t i) {
998
3.29M
  return !!(a[i >> 3] & (1 << (i & 7)));
999
3.29M
}
1000
1001
}  // namespace ada::character_sets
1002
1003
#endif  // ADA_CHARACTER_SETS_INL_H
1004
/* end file include/ada/character_sets-inl.h */
1005
/* begin file include/ada/checkers-inl.h */
1006
/**
1007
 * @file checkers-inl.h
1008
 * @brief Definitions for URL specific checkers used within Ada.
1009
 */
1010
#ifndef ADA_CHECKERS_INL_H
1011
#define ADA_CHECKERS_INL_H
1012
1013
#include <bit>
1014
#include <string_view>
1015
1016
namespace ada::checkers {
1017
1018
4.39k
constexpr bool has_hex_prefix_unsafe(std::string_view input) {
1019
  // This is actually efficient code, see has_hex_prefix for the assembly.
1020
4.39k
  constexpr bool is_little_endian = std::endian::native == std::endian::little;
1021
4.39k
  constexpr uint16_t word0x = 0x7830;
1022
4.39k
  uint16_t two_first_bytes =
1023
4.39k
      static_cast<uint16_t>(input[0]) |
1024
4.39k
      static_cast<uint16_t>((static_cast<uint16_t>(input[1]) << 8));
1025
4.39k
  if constexpr (is_little_endian) {
1026
4.39k
    two_first_bytes |= 0x2000;
1027
  } else {
1028
    two_first_bytes |= 0x020;
1029
  }
1030
4.39k
  return two_first_bytes == word0x;
1031
4.39k
}
1032
1033
5.32k
constexpr bool has_hex_prefix(std::string_view input) {
1034
5.32k
  return input.size() >= 2 && has_hex_prefix_unsafe(input);
1035
5.32k
}
1036
1037
32.8k
constexpr bool is_digit(char x) noexcept { return (x >= '0') & (x <= '9'); }
1038
1039
160k
constexpr char to_lower(char x) noexcept { return (x | 0x20); }
1040
1041
94.4k
constexpr bool is_alpha(char x) noexcept {
1042
94.4k
  return (to_lower(x) >= 'a') && (to_lower(x) <= 'z');
1043
94.4k
}
1044
1045
30.2k
constexpr bool is_windows_drive_letter(std::string_view input) noexcept {
1046
30.2k
  return input.size() >= 2 &&
1047
25.5k
         (is_alpha(input[0]) && ((input[1] == ':') || (input[1] == '|'))) &&
1048
3.68k
         ((input.size() == 2) || (input[2] == '/' || input[2] == '\\' ||
1049
1.99k
                                  input[2] == '?' || input[2] == '#'));
1050
30.2k
}
1051
1052
constexpr bool is_normalized_windows_drive_letter(
1053
11.8k
    std::string_view input) noexcept {
1054
11.8k
  return input.size() >= 2 && (is_alpha(input[0]) && (input[1] == ':'));
1055
11.8k
}
1056
1057
}  // namespace ada::checkers
1058
1059
#endif  // ADA_CHECKERS_INL_H
1060
/* end file include/ada/checkers-inl.h */
1061
/* begin file include/ada/log.h */
1062
/**
1063
 * @file log.h
1064
 * @brief Includes the definitions for logging.
1065
 * @private Excluded from docs through the doxygen file.
1066
 */
1067
#ifndef ADA_LOG_H
1068
#define ADA_LOG_H
1069
1070
// To enable logging, set ADA_LOGGING to 1:
1071
#ifndef ADA_LOGGING
1072
#define ADA_LOGGING 0
1073
#endif
1074
1075
#if ADA_LOGGING
1076
#include <iostream>
1077
#endif  // ADA_LOGGING
1078
1079
namespace ada {
1080
1081
/**
1082
 * Log a message. If you want to have no overhead when logging is disabled, use
1083
 * the ada_log macro.
1084
 * @private
1085
 */
1086
template <typename... Args>
1087
constexpr ada_really_inline void log([[maybe_unused]] Args... args) {
1088
#if ADA_LOGGING
1089
  ((std::cout << "ADA_LOG: ") << ... << args) << std::endl;
1090
#endif  // ADA_LOGGING
1091
}
1092
}  // namespace ada
1093
1094
#if ADA_LOGGING
1095
#ifndef ada_log
1096
#define ada_log(...)       \
1097
  do {                     \
1098
    ada::log(__VA_ARGS__); \
1099
  } while (0)
1100
#endif  // ada_log
1101
#else
1102
#define ada_log(...)
1103
#endif  // ADA_LOGGING
1104
1105
#endif  // ADA_LOG_H
1106
/* end file include/ada/log.h */
1107
/* begin file include/ada/encoding_type.h */
1108
/**
1109
 * @file encoding_type.h
1110
 * @brief Definition for supported encoding types.
1111
 */
1112
#ifndef ADA_ENCODING_TYPE_H
1113
#define ADA_ENCODING_TYPE_H
1114
1115
#include <string>
1116
1117
namespace ada {
1118
1119
/**
1120
 * This specification defines three encodings with the same names as encoding
1121
 * schemes defined in the Unicode standard: UTF-8, UTF-16LE, and UTF-16BE.
1122
 *
1123
 * @see https://encoding.spec.whatwg.org/#encodings
1124
 */
1125
enum class encoding_type {
1126
  UTF8,
1127
  UTF_16LE,
1128
  UTF_16BE,
1129
};
1130
1131
/**
1132
 * Convert a encoding_type to string.
1133
 */
1134
ada_warn_unused std::string_view to_string(encoding_type type);
1135
1136
}  // namespace ada
1137
1138
#endif  // ADA_ENCODING_TYPE_H
1139
/* end file include/ada/encoding_type.h */
1140
/* begin file include/ada/helpers.h */
1141
/**
1142
 * @file helpers.h
1143
 * @brief Definitions for helper functions used within Ada.
1144
 */
1145
#ifndef ADA_HELPERS_H
1146
#define ADA_HELPERS_H
1147
1148
/* begin file include/ada/url_base.h */
1149
/**
1150
 * @file url_base.h
1151
 * @brief Declaration for the basic URL definitions
1152
 */
1153
#ifndef ADA_URL_BASE_H
1154
#define ADA_URL_BASE_H
1155
1156
/* begin file include/ada/scheme.h */
1157
/**
1158
 * @file scheme.h
1159
 * @brief Declarations for the URL scheme.
1160
 */
1161
#ifndef ADA_SCHEME_H
1162
#define ADA_SCHEME_H
1163
1164
1165
#include <string>
1166
1167
/**
1168
 * @namespace ada::scheme
1169
 * @brief Includes the scheme declarations
1170
 */
1171
namespace ada::scheme {
1172
1173
/**
1174
 * Type of the scheme as an enum.
1175
 * Using strings to represent a scheme type is not ideal because
1176
 * checking for types involves string comparisons. It is faster to use
1177
 * a simple integer.
1178
 * In C++11, we are allowed to specify the underlying type of the enum.
1179
 * We pick an 8-bit integer (which allows up to 256 types). Specifying the
1180
 * type of the enum may help integration with other systems if the type
1181
 * variable is exposed (since its value will not depend on the compiler).
1182
 */
1183
enum type : uint8_t {
1184
  HTTP = 0,
1185
  NOT_SPECIAL = 1,
1186
  HTTPS = 2,
1187
  WS = 3,
1188
  FTP = 4,
1189
  WSS = 5,
1190
  FILE = 6
1191
};
1192
1193
/**
1194
 * A special scheme is an ASCII string that is listed in the first column of the
1195
 * following table. The default port for a special scheme is listed in the
1196
 * second column on the same row. The default port for any other ASCII string is
1197
 * null.
1198
 *
1199
 * @see https://url.spec.whatwg.org/#url-miscellaneous
1200
 * @param scheme
1201
 * @return If scheme is a special scheme
1202
 */
1203
ada_really_inline constexpr bool is_special(std::string_view scheme);
1204
1205
/**
1206
 * A special scheme is an ASCII string that is listed in the first column of the
1207
 * following table. The default port for a special scheme is listed in the
1208
 * second column on the same row. The default port for any other ASCII string is
1209
 * null.
1210
 *
1211
 * @see https://url.spec.whatwg.org/#url-miscellaneous
1212
 * @param scheme
1213
 * @return The special port
1214
 */
1215
constexpr uint16_t get_special_port(std::string_view scheme) noexcept;
1216
1217
/**
1218
 * Returns the port number of a special scheme.
1219
 * @see https://url.spec.whatwg.org/#special-scheme
1220
 */
1221
constexpr uint16_t get_special_port(ada::scheme::type type) noexcept;
1222
/**
1223
 * Returns the scheme of an input, or NOT_SPECIAL if it's not a special scheme
1224
 * defined by the spec.
1225
 */
1226
constexpr ada::scheme::type get_scheme_type(std::string_view scheme) noexcept;
1227
1228
}  // namespace ada::scheme
1229
1230
#endif  // ADA_SCHEME_H
1231
/* end file include/ada/scheme.h */
1232
1233
#include <string>
1234
#include <string_view>
1235
1236
namespace ada {
1237
1238
/**
1239
 * Type of URL host as an enum.
1240
 */
1241
enum url_host_type : uint8_t {
1242
  /**
1243
   * Represents common URLs such as "https://www.google.com"
1244
   */
1245
  DEFAULT = 0,
1246
  /**
1247
   * Represents ipv4 addresses such as "http://127.0.0.1"
1248
   */
1249
  IPV4 = 1,
1250
  /**
1251
   * Represents ipv6 addresses such as
1252
   * "http://[2001:db8:3333:4444:5555:6666:7777:8888]"
1253
   */
1254
  IPV6 = 2,
1255
};
1256
1257
/**
1258
 * @brief Base class of URL implementations
1259
 *
1260
 * @details A url_base contains a few attributes: is_valid, has_opaque_path and
1261
 * type. All non-trivial implementation details are in derived classes such as
1262
 * ada::url and ada::url_aggregator.
1263
 *
1264
 * It is an abstract class that cannot be instantiated directly.
1265
 */
1266
struct url_base {
1267
73.7k
  virtual ~url_base() = default;
1268
1269
  /**
1270
   * Used for returning the validity from the result of the URL parser.
1271
   */
1272
  bool is_valid{true};
1273
1274
  /**
1275
   * A URL has an opaque path if its path is a string.
1276
   */
1277
  bool has_opaque_path{false};
1278
1279
  /**
1280
   * URL hosts type
1281
   */
1282
  url_host_type host_type = url_host_type::DEFAULT;
1283
1284
  /**
1285
   * @private
1286
   */
1287
  ada::scheme::type type{ada::scheme::type::NOT_SPECIAL};
1288
1289
  /**
1290
   * A URL is special if its scheme is a special scheme. A URL is not special if
1291
   * its scheme is not a special scheme.
1292
   */
1293
  [[nodiscard]] ada_really_inline constexpr bool is_special() const noexcept;
1294
1295
  /**
1296
   * The origin getter steps are to return the serialization of this's URL's
1297
   * origin. [HTML]
1298
   * @return a newly allocated string.
1299
   * @see https://url.spec.whatwg.org/#concept-url-origin
1300
   */
1301
  [[nodiscard]] virtual std::string get_origin() const noexcept = 0;
1302
1303
  /**
1304
   * Returns true if this URL has a valid domain as per RFC 1034 and
1305
   * corresponding specifications. Among other things, it requires
1306
   * that the domain string has fewer than 255 octets.
1307
   */
1308
  [[nodiscard]] virtual bool has_valid_domain() const noexcept = 0;
1309
1310
  /**
1311
   * @private
1312
   *
1313
   * Return the 'special port' if the URL is special and not 'file'.
1314
   * Returns 0 otherwise.
1315
   */
1316
  [[nodiscard]] inline uint16_t get_special_port() const noexcept;
1317
1318
  /**
1319
   * @private
1320
   *
1321
   * Get the default port if the url's scheme has one, returns 0 otherwise.
1322
   */
1323
  [[nodiscard]] ada_really_inline uint16_t scheme_default_port() const noexcept;
1324
1325
  /**
1326
   * @private
1327
   *
1328
   * Parse a port (16-bit decimal digit) from the provided input.
1329
   * We assume that the input does not contain spaces or tabs
1330
   * within the ASCII digits.
1331
   * It returns how many bytes were consumed when a number is successfully
1332
   * parsed.
1333
   * @return On failure, it returns zero.
1334
   * @see https://url.spec.whatwg.org/#host-parsing
1335
   */
1336
  virtual size_t parse_port(std::string_view view,
1337
                            bool check_trailing_content) noexcept = 0;
1338
1339
0
  virtual ada_really_inline size_t parse_port(std::string_view view) noexcept {
1340
0
    return this->parse_port(view, false);
1341
0
  }
1342
1343
  /**
1344
   * Returns a JSON string representation of this URL.
1345
   */
1346
  [[nodiscard]] virtual std::string to_string() const = 0;
1347
1348
  /** @private */
1349
  virtual inline void clear_pathname() = 0;
1350
1351
  /** @private */
1352
  virtual inline void clear_search() = 0;
1353
1354
  /** @private */
1355
  [[nodiscard]] virtual inline bool has_hash() const noexcept = 0;
1356
1357
  /** @private */
1358
  [[nodiscard]] virtual inline bool has_search() const noexcept = 0;
1359
1360
};  // url_base
1361
1362
}  // namespace ada
1363
1364
#endif
1365
/* end file include/ada/url_base.h */
1366
1367
#include <string>
1368
#include <string_view>
1369
#include <optional>
1370
1371
#if ADA_DEVELOPMENT_CHECKS
1372
#include <iostream>
1373
#endif  // ADA_DEVELOPMENT_CHECKS
1374
1375
/**
1376
 * These functions are not part of our public API and may
1377
 * change at any time.
1378
 *
1379
 * @private
1380
 * @namespace ada::helpers
1381
 * @brief Includes the definitions for helper functions
1382
 */
1383
namespace ada::helpers {
1384
1385
/**
1386
 * @private
1387
 */
1388
template <typename out_iter>
1389
void encode_json(std::string_view view, out_iter out);
1390
1391
/**
1392
 * @private
1393
 * This function is used to prune a fragment from a url, and returning the
1394
 * removed string if input has fragment.
1395
 *
1396
 * @details prune_hash seeks the first '#' and returns everything after it
1397
 * as a string_view, and modifies (in place) the input so that it points at
1398
 * everything before the '#'. If no '#' is found, the input is left unchanged
1399
 * and std::nullopt is returned.
1400
 *
1401
 * @attention The function is non-allocating and it does not throw.
1402
 * @returns Note that the returned string_view might be empty!
1403
 */
1404
ada_really_inline std::optional<std::string_view> prune_hash(
1405
    std::string_view& input) noexcept;
1406
1407
/**
1408
 * @private
1409
 * Defined by the URL specification, shorten a URLs paths.
1410
 * @see https://url.spec.whatwg.org/#shorten-a-urls-path
1411
 * @returns Returns true if path is shortened.
1412
 */
1413
ada_really_inline bool shorten_path(std::string& path,
1414
                                    ada::scheme::type type) noexcept;
1415
1416
/**
1417
 * @private
1418
 * Defined by the URL specification, shorten a URLs paths.
1419
 * @see https://url.spec.whatwg.org/#shorten-a-urls-path
1420
 * @returns Returns true if path is shortened.
1421
 */
1422
ada_really_inline bool shorten_path(std::string_view& path,
1423
                                    ada::scheme::type type) noexcept;
1424
1425
/**
1426
 * @private
1427
 *
1428
 * Parse the path from the provided input and append to the existing
1429
 * (possibly empty) path. The input cannot contain tabs and spaces: it
1430
 * is the user's responsibility to check.
1431
 *
1432
 * The input is expected to be UTF-8.
1433
 *
1434
 * @see https://url.spec.whatwg.org/
1435
 */
1436
ada_really_inline void parse_prepared_path(std::string_view input,
1437
                                           ada::scheme::type type,
1438
                                           std::string& path);
1439
1440
/**
1441
 * @private
1442
 * Remove and mutate all ASCII tab or newline characters from an input.
1443
 */
1444
ada_really_inline void remove_ascii_tab_or_newline(std::string& input) noexcept;
1445
1446
/**
1447
 * @private
1448
 * Return the substring from input going from index pos to the end.
1449
 * This function cannot throw.
1450
 */
1451
ada_really_inline constexpr std::string_view substring(std::string_view input,
1452
                                                       size_t pos) noexcept;
1453
1454
/**
1455
 * @private
1456
 * Returns true if the string_view points within the string.
1457
 */
1458
bool overlaps(std::string_view input1, const std::string& input2) noexcept;
1459
1460
/**
1461
 * @private
1462
 * Return the substring from input going from index pos1 to the pos2 (non
1463
 * included). The length of the substring is pos2 - pos1.
1464
 */
1465
ada_really_inline constexpr std::string_view substring(std::string_view input,
1466
                                                       size_t pos1,
1467
234k
                                                       size_t pos2) noexcept {
1468
#if ADA_DEVELOPMENT_CHECKS
1469
  if (pos2 < pos1) {
1470
    std::cerr << "Negative-length substring: [" << pos1 << " to " << pos2 << ")"
1471
              << std::endl;
1472
    abort();
1473
  }
1474
#endif
1475
234k
  return input.substr(pos1, pos2 - pos1);
1476
234k
}
1477
1478
/**
1479
 * @private
1480
 * Modify the string_view so that it has the new size pos, assuming that pos <=
1481
 * input.size(). This function cannot throw.
1482
 */
1483
ada_really_inline void resize(std::string_view& input, size_t pos) noexcept;
1484
1485
/**
1486
 * @private
1487
 * Returns a host's delimiter location depending on the state of the instance,
1488
 * and whether a colon was found outside brackets. Used by the host parser.
1489
 */
1490
ada_really_inline std::pair<size_t, bool> get_host_delimiter_location(
1491
    bool is_special, std::string_view& view) noexcept;
1492
1493
/**
1494
 * @private
1495
 * Removes leading and trailing C0 control and whitespace characters from
1496
 * string.
1497
 */
1498
void trim_c0_whitespace(std::string_view& input) noexcept;
1499
1500
/**
1501
 * @private
1502
 * @see
1503
 * https://url.spec.whatwg.org/#potentially-strip-trailing-spaces-from-an-opaque-path
1504
 */
1505
template <class url_type>
1506
ada_really_inline void strip_trailing_spaces_from_opaque_path(
1507
    url_type& url) noexcept;
1508
1509
/**
1510
 * @private
1511
 * Finds the delimiter of a view in authority state.
1512
 */
1513
ada_really_inline size_t
1514
find_authority_delimiter_special(std::string_view view) noexcept;
1515
1516
/**
1517
 * @private
1518
 * Finds the delimiter of a view in authority state.
1519
 */
1520
ada_really_inline size_t
1521
find_authority_delimiter(std::string_view view) noexcept;
1522
1523
/**
1524
 * @private
1525
 */
1526
template <typename T, typename... Args>
1527
61.9k
inline void inner_concat(std::string& buffer, T t) {
1528
61.9k
  buffer.append(t);
1529
61.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
1527
10.4k
inline void inner_concat(std::string& buffer, T t) {
1528
10.4k
  buffer.append(t);
1529
10.4k
}
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
1527
42.2k
inline void inner_concat(std::string& buffer, T t) {
1528
42.2k
  buffer.append(t);
1529
42.2k
}
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
1527
9.28k
inline void inner_concat(std::string& buffer, T t) {
1528
9.28k
  buffer.append(t);
1529
9.28k
}
1530
1531
/**
1532
 * @private
1533
 */
1534
template <typename T, typename... Args>
1535
80.6k
inline void inner_concat(std::string& buffer, T t, Args... args) {
1536
80.6k
  buffer.append(t);
1537
80.6k
  return inner_concat(buffer, args...);
1538
80.6k
}
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
1535
10.4k
inline void inner_concat(std::string& buffer, T t, Args... args) {
1536
10.4k
  buffer.append(t);
1537
10.4k
  return inner_concat(buffer, args...);
1538
10.4k
}
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
1535
9.40k
inline void inner_concat(std::string& buffer, T t, Args... args) {
1536
9.40k
  buffer.append(t);
1537
9.40k
  return inner_concat(buffer, args...);
1538
9.40k
}
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
1535
36.6k
inline void inner_concat(std::string& buffer, T t, Args... args) {
1536
36.6k
  buffer.append(t);
1537
36.6k
  return inner_concat(buffer, args...);
1538
36.6k
}
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
1535
5.59k
inline void inner_concat(std::string& buffer, T t, Args... args) {
1536
5.59k
  buffer.append(t);
1537
5.59k
  return inner_concat(buffer, args...);
1538
5.59k
}
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
1535
9.28k
inline void inner_concat(std::string& buffer, T t, Args... args) {
1536
9.28k
  buffer.append(t);
1537
9.28k
  return inner_concat(buffer, args...);
1538
9.28k
}
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
1535
9.28k
inline void inner_concat(std::string& buffer, T t, Args... args) {
1536
9.28k
  buffer.append(t);
1537
9.28k
  return inner_concat(buffer, args...);
1538
9.28k
}
1539
1540
/**
1541
 * @private
1542
 * Concatenate the arguments and return a string.
1543
 * @returns a string
1544
 */
1545
template <typename... Args>
1546
61.9k
std::string concat(Args... args) {
1547
61.9k
  std::string answer;
1548
61.9k
  inner_concat(answer, args...);
1549
61.9k
  return answer;
1550
61.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
1546
1.08k
std::string concat(Args... args) {
1547
1.08k
  std::string answer;
1548
1.08k
  inner_concat(answer, args...);
1549
1.08k
  return answer;
1550
1.08k
}
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
1546
9.40k
std::string concat(Args... args) {
1547
9.40k
  std::string answer;
1548
9.40k
  inner_concat(answer, args...);
1549
9.40k
  return answer;
1550
9.40k
}
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
1546
36.6k
std::string concat(Args... args) {
1547
36.6k
  std::string answer;
1548
36.6k
  inner_concat(answer, args...);
1549
36.6k
  return answer;
1550
36.6k
}
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
1546
5.59k
std::string concat(Args... args) {
1547
5.59k
  std::string answer;
1548
5.59k
  inner_concat(answer, args...);
1549
5.59k
  return answer;
1550
5.59k
}
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
1546
9.28k
std::string concat(Args... args) {
1547
9.28k
  std::string answer;
1548
9.28k
  inner_concat(answer, args...);
1549
9.28k
  return answer;
1550
9.28k
}
1551
1552
/**
1553
 * @private
1554
 * @return Number of leading zeroes.
1555
 */
1556
22.4k
inline int leading_zeroes(uint32_t input_num) noexcept {
1557
#if ADA_REGULAR_VISUAL_STUDIO
1558
  unsigned long leading_zero(0);
1559
  unsigned long in(input_num);
1560
  return _BitScanReverse(&leading_zero, in) ? int(31 - leading_zero) : 32;
1561
#else
1562
22.4k
  return __builtin_clz(input_num);
1563
22.4k
#endif  // ADA_REGULAR_VISUAL_STUDIO
1564
22.4k
}
1565
1566
/**
1567
 * @private
1568
 * Counts the number of decimal digits necessary to represent x.
1569
 * faster than std::to_string(x).size().
1570
 * @return digit count
1571
 */
1572
950
inline int fast_digit_count(uint32_t x) noexcept {
1573
950
  auto int_log2 = [](uint32_t z) -> int {
1574
950
    return 31 - ada::helpers::leading_zeroes(z | 1);
1575
950
  };
1576
  // Compiles to very few instructions. Note that the
1577
  // table is static and thus effectively a constant.
1578
  // We leave it inside the function because it is meaningless
1579
  // outside of it (this comes at no performance cost).
1580
950
  const static uint64_t table[] = {
1581
950
      4294967296,  8589934582,  8589934582,  8589934582,  12884901788,
1582
950
      12884901788, 12884901788, 17179868184, 17179868184, 17179868184,
1583
950
      21474826480, 21474826480, 21474826480, 21474826480, 25769703776,
1584
950
      25769703776, 25769703776, 30063771072, 30063771072, 30063771072,
1585
950
      34349738368, 34349738368, 34349738368, 34349738368, 38554705664,
1586
950
      38554705664, 38554705664, 41949672960, 41949672960, 41949672960,
1587
950
      42949672960, 42949672960};
1588
950
  return int((x + table[int_log2(x)]) >> 32);
1589
950
}
1590
}  // namespace ada::helpers
1591
1592
#endif  // ADA_HELPERS_H
1593
/* end file include/ada/helpers.h */
1594
/* begin file include/ada/parser.h */
1595
/**
1596
 * @file parser.h
1597
 * @brief Definitions for the parser.
1598
 */
1599
#ifndef ADA_PARSER_H
1600
#define ADA_PARSER_H
1601
1602
#include <string_view>
1603
#include <variant>
1604
1605
/* begin file include/ada/expected.h */
1606
/**
1607
 * @file expected.h
1608
 * @brief Definitions for std::expected
1609
 * @private Excluded from docs through the doxygen file.
1610
 */
1611
///
1612
// expected - An implementation of std::expected with extensions
1613
// Written in 2017 by Sy Brand (tartanllama@gmail.com, @TartanLlama)
1614
//
1615
// Documentation available at http://tl.tartanllama.xyz/
1616
//
1617
// To the extent possible under law, the author(s) have dedicated all
1618
// copyright and related and neighboring rights to this software to the
1619
// public domain worldwide. This software is distributed without any warranty.
1620
//
1621
// You should have received a copy of the CC0 Public Domain Dedication
1622
// along with this software. If not, see
1623
// <http://creativecommons.org/publicdomain/zero/1.0/>.
1624
///
1625
1626
#ifndef TL_EXPECTED_HPP
1627
#define TL_EXPECTED_HPP
1628
1629
#define TL_EXPECTED_VERSION_MAJOR 1
1630
#define TL_EXPECTED_VERSION_MINOR 1
1631
#define TL_EXPECTED_VERSION_PATCH 0
1632
1633
#include <exception>
1634
#include <functional>
1635
#include <type_traits>
1636
#include <utility>
1637
1638
#if defined(__EXCEPTIONS) || defined(_CPPUNWIND)
1639
#define TL_EXPECTED_EXCEPTIONS_ENABLED
1640
#endif
1641
1642
#if (defined(_MSC_VER) && _MSC_VER == 1900)
1643
#define TL_EXPECTED_MSVC2015
1644
#define TL_EXPECTED_MSVC2015_CONSTEXPR
1645
#else
1646
#define TL_EXPECTED_MSVC2015_CONSTEXPR constexpr
1647
#endif
1648
1649
#if (defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ <= 9 && \
1650
     !defined(__clang__))
1651
#define TL_EXPECTED_GCC49
1652
#endif
1653
1654
#if (defined(__GNUC__) && __GNUC__ == 5 && __GNUC_MINOR__ <= 4 && \
1655
     !defined(__clang__))
1656
#define TL_EXPECTED_GCC54
1657
#endif
1658
1659
#if (defined(__GNUC__) && __GNUC__ == 5 && __GNUC_MINOR__ <= 5 && \
1660
     !defined(__clang__))
1661
#define TL_EXPECTED_GCC55
1662
#endif
1663
1664
#if !defined(TL_ASSERT)
1665
// can't have assert in constexpr in C++11 and GCC 4.9 has a compiler bug
1666
#if (__cplusplus > 201103L) && !defined(TL_EXPECTED_GCC49)
1667
#include <cassert>
1668
450k
#define TL_ASSERT(x) assert(x)
1669
#else
1670
#define TL_ASSERT(x)
1671
#endif
1672
#endif
1673
1674
#if (defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ <= 9 && \
1675
     !defined(__clang__))
1676
// GCC < 5 doesn't support overloading on const&& for member functions
1677
1678
#define TL_EXPECTED_NO_CONSTRR
1679
// GCC < 5 doesn't support some standard C++11 type traits
1680
#define TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) \
1681
  std::has_trivial_copy_constructor<T>
1682
#define TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(T) \
1683
  std::has_trivial_copy_assign<T>
1684
1685
// This one will be different for GCC 5.7 if it's ever supported
1686
#define TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(T) \
1687
  std::is_trivially_destructible<T>
1688
1689
// GCC 5 < v < 8 has a bug in is_trivially_copy_constructible which breaks
1690
// std::vector for non-copyable types
1691
#elif (defined(__GNUC__) && __GNUC__ < 8 && !defined(__clang__))
1692
#ifndef TL_GCC_LESS_8_TRIVIALLY_COPY_CONSTRUCTIBLE_MUTEX
1693
#define TL_GCC_LESS_8_TRIVIALLY_COPY_CONSTRUCTIBLE_MUTEX
1694
namespace tl {
1695
namespace detail {
1696
template <class T>
1697
struct is_trivially_copy_constructible
1698
    : std::is_trivially_copy_constructible<T> {};
1699
#ifdef _GLIBCXX_VECTOR
1700
template <class T, class A>
1701
struct is_trivially_copy_constructible<std::vector<T, A>> : std::false_type {};
1702
#endif
1703
}  // namespace detail
1704
}  // namespace tl
1705
#endif
1706
1707
#define TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) \
1708
  tl::detail::is_trivially_copy_constructible<T>
1709
#define TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(T) \
1710
  std::is_trivially_copy_assignable<T>
1711
#define TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(T) \
1712
  std::is_trivially_destructible<T>
1713
#else
1714
#define TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) \
1715
  std::is_trivially_copy_constructible<T>
1716
#define TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(T) \
1717
  std::is_trivially_copy_assignable<T>
1718
#define TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(T) \
1719
  std::is_trivially_destructible<T>
1720
#endif
1721
1722
#if __cplusplus > 201103L
1723
#define TL_EXPECTED_CXX14
1724
#endif
1725
1726
#ifdef TL_EXPECTED_GCC49
1727
#define TL_EXPECTED_GCC49_CONSTEXPR
1728
#else
1729
#define TL_EXPECTED_GCC49_CONSTEXPR constexpr
1730
#endif
1731
1732
#if (__cplusplus == 201103L || defined(TL_EXPECTED_MSVC2015) || \
1733
     defined(TL_EXPECTED_GCC49))
1734
#define TL_EXPECTED_11_CONSTEXPR
1735
#else
1736
#define TL_EXPECTED_11_CONSTEXPR constexpr
1737
#endif
1738
1739
namespace tl {
1740
template <class T, class E>
1741
class expected;
1742
1743
#ifndef TL_MONOSTATE_INPLACE_MUTEX
1744
#define TL_MONOSTATE_INPLACE_MUTEX
1745
class monostate {};
1746
1747
struct in_place_t {
1748
  explicit in_place_t() = default;
1749
};
1750
static constexpr in_place_t in_place{};
1751
#endif
1752
1753
template <class E>
1754
class unexpected {
1755
 public:
1756
  static_assert(!std::is_same<E, void>::value, "E must not be void");
1757
1758
  unexpected() = delete;
1759
  constexpr explicit unexpected(const E &e) : m_val(e) {}
1760
1761
24.3k
  constexpr explicit unexpected(E &&e) : m_val(std::move(e)) {}
1762
1763
  template <class... Args, typename std::enable_if<std::is_constructible<
1764
                               E, Args &&...>::value>::type * = nullptr>
1765
  constexpr explicit unexpected(Args &&...args)
1766
0
      : m_val(std::forward<Args>(args)...) {}
1767
  template <
1768
      class U, class... Args,
1769
      typename std::enable_if<std::is_constructible<
1770
          E, std::initializer_list<U> &, Args &&...>::value>::type * = nullptr>
1771
  constexpr explicit unexpected(std::initializer_list<U> l, Args &&...args)
1772
      : m_val(l, std::forward<Args>(args)...) {}
1773
1774
  constexpr const E &value() const & { return m_val; }
1775
12.1k
  TL_EXPECTED_11_CONSTEXPR E &value() & { return m_val; }
1776
  TL_EXPECTED_11_CONSTEXPR E &&value() && { return std::move(m_val); }
1777
  constexpr const E &&value() const && { return std::move(m_val); }
1778
1779
 private:
1780
  E m_val;
1781
};
1782
1783
#ifdef __cpp_deduction_guides
1784
template <class E>
1785
unexpected(E) -> unexpected<E>;
1786
#endif
1787
1788
template <class E>
1789
constexpr bool operator==(const unexpected<E> &lhs, const unexpected<E> &rhs) {
1790
  return lhs.value() == rhs.value();
1791
}
1792
template <class E>
1793
constexpr bool operator!=(const unexpected<E> &lhs, const unexpected<E> &rhs) {
1794
  return lhs.value() != rhs.value();
1795
}
1796
template <class E>
1797
constexpr bool operator<(const unexpected<E> &lhs, const unexpected<E> &rhs) {
1798
  return lhs.value() < rhs.value();
1799
}
1800
template <class E>
1801
constexpr bool operator<=(const unexpected<E> &lhs, const unexpected<E> &rhs) {
1802
  return lhs.value() <= rhs.value();
1803
}
1804
template <class E>
1805
constexpr bool operator>(const unexpected<E> &lhs, const unexpected<E> &rhs) {
1806
  return lhs.value() > rhs.value();
1807
}
1808
template <class E>
1809
constexpr bool operator>=(const unexpected<E> &lhs, const unexpected<E> &rhs) {
1810
  return lhs.value() >= rhs.value();
1811
}
1812
1813
template <class E>
1814
unexpected<typename std::decay<E>::type> make_unexpected(E &&e) {
1815
  return unexpected<typename std::decay<E>::type>(std::forward<E>(e));
1816
}
1817
1818
struct unexpect_t {
1819
  unexpect_t() = default;
1820
};
1821
static constexpr unexpect_t unexpect{};
1822
1823
namespace detail {
1824
template <typename E>
1825
0
[[noreturn]] TL_EXPECTED_11_CONSTEXPR void throw_exception(E &&e) {
1826
0
#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
1827
0
  throw std::forward<E>(e);
1828
#else
1829
  (void)e;
1830
#ifdef _MSC_VER
1831
  __assume(0);
1832
#else
1833
  __builtin_unreachable();
1834
#endif
1835
#endif
1836
0
}
1837
1838
#ifndef TL_TRAITS_MUTEX
1839
#define TL_TRAITS_MUTEX
1840
// C++14-style aliases for brevity
1841
template <class T>
1842
using remove_const_t = typename std::remove_const<T>::type;
1843
template <class T>
1844
using remove_reference_t = typename std::remove_reference<T>::type;
1845
template <class T>
1846
using decay_t = typename std::decay<T>::type;
1847
template <bool E, class T = void>
1848
using enable_if_t = typename std::enable_if<E, T>::type;
1849
template <bool B, class T, class F>
1850
using conditional_t = typename std::conditional<B, T, F>::type;
1851
1852
// std::conjunction from C++17
1853
template <class...>
1854
struct conjunction : std::true_type {};
1855
template <class B>
1856
struct conjunction<B> : B {};
1857
template <class B, class... Bs>
1858
struct conjunction<B, Bs...>
1859
    : std::conditional<bool(B::value), conjunction<Bs...>, B>::type {};
1860
1861
#if defined(_LIBCPP_VERSION) && __cplusplus == 201103L
1862
#define TL_TRAITS_LIBCXX_MEM_FN_WORKAROUND
1863
#endif
1864
1865
// In C++11 mode, there's an issue in libc++'s std::mem_fn
1866
// which results in a hard-error when using it in a noexcept expression
1867
// in some cases. This is a check to workaround the common failing case.
1868
#ifdef TL_TRAITS_LIBCXX_MEM_FN_WORKAROUND
1869
template <class T>
1870
struct is_pointer_to_non_const_member_func : std::false_type {};
1871
template <class T, class Ret, class... Args>
1872
struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...)>
1873
    : std::true_type {};
1874
template <class T, class Ret, class... Args>
1875
struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...) &>
1876
    : std::true_type {};
1877
template <class T, class Ret, class... Args>
1878
struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...) &&>
1879
    : std::true_type {};
1880
template <class T, class Ret, class... Args>
1881
struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...) volatile>
1882
    : std::true_type {};
1883
template <class T, class Ret, class... Args>
1884
struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...) volatile &>
1885
    : std::true_type {};
1886
template <class T, class Ret, class... Args>
1887
struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...) volatile &&>
1888
    : std::true_type {};
1889
1890
template <class T>
1891
struct is_const_or_const_ref : std::false_type {};
1892
template <class T>
1893
struct is_const_or_const_ref<T const &> : std::true_type {};
1894
template <class T>
1895
struct is_const_or_const_ref<T const> : std::true_type {};
1896
#endif
1897
1898
// std::invoke from C++17
1899
// https://stackoverflow.com/questions/38288042/c11-14-invoke-workaround
1900
template <
1901
    typename Fn, typename... Args,
1902
#ifdef TL_TRAITS_LIBCXX_MEM_FN_WORKAROUND
1903
    typename = enable_if_t<!(is_pointer_to_non_const_member_func<Fn>::value &&
1904
                             is_const_or_const_ref<Args...>::value)>,
1905
#endif
1906
    typename = enable_if_t<std::is_member_pointer<decay_t<Fn>>::value>, int = 0>
1907
constexpr auto invoke(Fn &&f, Args &&...args) noexcept(
1908
    noexcept(std::mem_fn(f)(std::forward<Args>(args)...)))
1909
    -> decltype(std::mem_fn(f)(std::forward<Args>(args)...)) {
1910
  return std::mem_fn(f)(std::forward<Args>(args)...);
1911
}
1912
1913
template <typename Fn, typename... Args,
1914
          typename = enable_if_t<!std::is_member_pointer<decay_t<Fn>>::value>>
1915
constexpr auto invoke(Fn &&f, Args &&...args) noexcept(
1916
    noexcept(std::forward<Fn>(f)(std::forward<Args>(args)...)))
1917
    -> decltype(std::forward<Fn>(f)(std::forward<Args>(args)...)) {
1918
  return std::forward<Fn>(f)(std::forward<Args>(args)...);
1919
}
1920
1921
// std::invoke_result from C++17
1922
template <class F, class, class... Us>
1923
struct invoke_result_impl;
1924
1925
template <class F, class... Us>
1926
struct invoke_result_impl<
1927
    F,
1928
    decltype(detail::invoke(std::declval<F>(), std::declval<Us>()...), void()),
1929
    Us...> {
1930
  using type =
1931
      decltype(detail::invoke(std::declval<F>(), std::declval<Us>()...));
1932
};
1933
1934
template <class F, class... Us>
1935
using invoke_result = invoke_result_impl<F, void, Us...>;
1936
1937
template <class F, class... Us>
1938
using invoke_result_t = typename invoke_result<F, Us...>::type;
1939
1940
#if defined(_MSC_VER) && _MSC_VER <= 1900
1941
// TODO make a version which works with MSVC 2015
1942
template <class T, class U = T>
1943
struct is_swappable : std::true_type {};
1944
1945
template <class T, class U = T>
1946
struct is_nothrow_swappable : std::true_type {};
1947
#else
1948
// https://stackoverflow.com/questions/26744589/what-is-a-proper-way-to-implement-is-swappable-to-test-for-the-swappable-concept
1949
namespace swap_adl_tests {
1950
// if swap ADL finds this then it would call std::swap otherwise (same
1951
// signature)
1952
struct tag {};
1953
1954
template <class T>
1955
tag swap(T &, T &);
1956
template <class T, std::size_t N>
1957
tag swap(T (&a)[N], T (&b)[N]);
1958
1959
// helper functions to test if an unqualified swap is possible, and if it
1960
// becomes std::swap
1961
template <class, class>
1962
std::false_type can_swap(...) noexcept(false);
1963
template <class T, class U,
1964
          class = decltype(swap(std::declval<T &>(), std::declval<U &>()))>
1965
std::true_type can_swap(int) noexcept(noexcept(swap(std::declval<T &>(),
1966
                                                    std::declval<U &>())));
1967
1968
template <class, class>
1969
std::false_type uses_std(...);
1970
template <class T, class U>
1971
std::is_same<decltype(swap(std::declval<T &>(), std::declval<U &>())), tag>
1972
uses_std(int);
1973
1974
template <class T>
1975
struct is_std_swap_noexcept
1976
    : std::integral_constant<bool,
1977
                             std::is_nothrow_move_constructible<T>::value &&
1978
                                 std::is_nothrow_move_assignable<T>::value> {};
1979
1980
template <class T, std::size_t N>
1981
struct is_std_swap_noexcept<T[N]> : is_std_swap_noexcept<T> {};
1982
1983
template <class T, class U>
1984
struct is_adl_swap_noexcept
1985
    : std::integral_constant<bool, noexcept(can_swap<T, U>(0))> {};
1986
}  // namespace swap_adl_tests
1987
1988
template <class T, class U = T>
1989
struct is_swappable
1990
    : std::integral_constant<
1991
          bool,
1992
          decltype(detail::swap_adl_tests::can_swap<T, U>(0))::value &&
1993
              (!decltype(detail::swap_adl_tests::uses_std<T, U>(0))::value ||
1994
               (std::is_move_assignable<T>::value &&
1995
                std::is_move_constructible<T>::value))> {};
1996
1997
template <class T, std::size_t N>
1998
struct is_swappable<T[N], T[N]>
1999
    : std::integral_constant<
2000
          bool,
2001
          decltype(detail::swap_adl_tests::can_swap<T[N], T[N]>(0))::value &&
2002
              (!decltype(detail::swap_adl_tests::uses_std<T[N], T[N]>(
2003
                   0))::value ||
2004
               is_swappable<T, T>::value)> {};
2005
2006
template <class T, class U = T>
2007
struct is_nothrow_swappable
2008
    : std::integral_constant<
2009
          bool,
2010
          is_swappable<T, U>::value &&
2011
              ((decltype(detail::swap_adl_tests::uses_std<T, U>(0))::value &&
2012
                detail::swap_adl_tests::is_std_swap_noexcept<T>::value) ||
2013
               (!decltype(detail::swap_adl_tests::uses_std<T, U>(0))::value &&
2014
                detail::swap_adl_tests::is_adl_swap_noexcept<T, U>::value))> {};
2015
#endif
2016
#endif
2017
2018
// Trait for checking if a type is a tl::expected
2019
template <class T>
2020
struct is_expected_impl : std::false_type {};
2021
template <class T, class E>
2022
struct is_expected_impl<expected<T, E>> : std::true_type {};
2023
template <class T>
2024
using is_expected = is_expected_impl<decay_t<T>>;
2025
2026
template <class T, class E, class U>
2027
using expected_enable_forward_value = detail::enable_if_t<
2028
    std::is_constructible<T, U &&>::value &&
2029
    !std::is_same<detail::decay_t<U>, in_place_t>::value &&
2030
    !std::is_same<expected<T, E>, detail::decay_t<U>>::value &&
2031
    !std::is_same<unexpected<E>, detail::decay_t<U>>::value>;
2032
2033
template <class T, class E, class U, class G, class UR, class GR>
2034
using expected_enable_from_other = detail::enable_if_t<
2035
    std::is_constructible<T, UR>::value &&
2036
    std::is_constructible<E, GR>::value &&
2037
    !std::is_constructible<T, expected<U, G> &>::value &&
2038
    !std::is_constructible<T, expected<U, G> &&>::value &&
2039
    !std::is_constructible<T, const expected<U, G> &>::value &&
2040
    !std::is_constructible<T, const expected<U, G> &&>::value &&
2041
    !std::is_convertible<expected<U, G> &, T>::value &&
2042
    !std::is_convertible<expected<U, G> &&, T>::value &&
2043
    !std::is_convertible<const expected<U, G> &, T>::value &&
2044
    !std::is_convertible<const expected<U, G> &&, T>::value>;
2045
2046
template <class T, class U>
2047
using is_void_or = conditional_t<std::is_void<T>::value, std::true_type, U>;
2048
2049
template <class T>
2050
using is_copy_constructible_or_void =
2051
    is_void_or<T, std::is_copy_constructible<T>>;
2052
2053
template <class T>
2054
using is_move_constructible_or_void =
2055
    is_void_or<T, std::is_move_constructible<T>>;
2056
2057
template <class T>
2058
using is_copy_assignable_or_void = is_void_or<T, std::is_copy_assignable<T>>;
2059
2060
template <class T>
2061
using is_move_assignable_or_void = is_void_or<T, std::is_move_assignable<T>>;
2062
2063
}  // namespace detail
2064
2065
namespace detail {
2066
struct no_init_t {};
2067
static constexpr no_init_t no_init{};
2068
2069
// Implements the storage of the values, and ensures that the destructor is
2070
// trivial if it can be.
2071
//
2072
// This specialization is for where neither `T` or `E` is trivially
2073
// destructible, so the destructors must be called on destruction of the
2074
// `expected`
2075
template <class T, class E, bool = std::is_trivially_destructible<T>::value,
2076
          bool = std::is_trivially_destructible<E>::value>
2077
struct expected_storage_base {
2078
  constexpr expected_storage_base() : m_val(T{}), m_has_val(true) {}
2079
  constexpr expected_storage_base(no_init_t) : m_no_init(), m_has_val(false) {}
2080
2081
  template <class... Args,
2082
            detail::enable_if_t<std::is_constructible<T, Args &&...>::value> * =
2083
                nullptr>
2084
  constexpr expected_storage_base(in_place_t, Args &&...args)
2085
      : m_val(std::forward<Args>(args)...), m_has_val(true) {}
2086
2087
  template <class U, class... Args,
2088
            detail::enable_if_t<std::is_constructible<
2089
                T, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
2090
  constexpr expected_storage_base(in_place_t, std::initializer_list<U> il,
2091
                                  Args &&...args)
2092
      : m_val(il, std::forward<Args>(args)...), m_has_val(true) {}
2093
  template <class... Args,
2094
            detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * =
2095
                nullptr>
2096
  constexpr explicit expected_storage_base(unexpect_t, Args &&...args)
2097
      : m_unexpect(std::forward<Args>(args)...), m_has_val(false) {}
2098
2099
  template <class U, class... Args,
2100
            detail::enable_if_t<std::is_constructible<
2101
                E, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
2102
  constexpr explicit expected_storage_base(unexpect_t,
2103
                                           std::initializer_list<U> il,
2104
                                           Args &&...args)
2105
      : m_unexpect(il, std::forward<Args>(args)...), m_has_val(false) {}
2106
2107
  ~expected_storage_base() {
2108
    if (m_has_val) {
2109
      m_val.~T();
2110
    } else {
2111
      m_unexpect.~unexpected<E>();
2112
    }
2113
  }
2114
  union {
2115
    T m_val;
2116
    unexpected<E> m_unexpect;
2117
    char m_no_init;
2118
  };
2119
  bool m_has_val;
2120
};
2121
2122
// This specialization is for when both `T` and `E` are trivially-destructible,
2123
// so the destructor of the `expected` can be trivial.
2124
template <class T, class E>
2125
struct expected_storage_base<T, E, true, true> {
2126
  constexpr expected_storage_base() : m_val(T{}), m_has_val(true) {}
2127
  constexpr expected_storage_base(no_init_t) : m_no_init(), m_has_val(false) {}
2128
2129
  template <class... Args,
2130
            detail::enable_if_t<std::is_constructible<T, Args &&...>::value> * =
2131
                nullptr>
2132
  constexpr expected_storage_base(in_place_t, Args &&...args)
2133
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_
2134
2135
  template <class U, class... Args,
2136
            detail::enable_if_t<std::is_constructible<
2137
                T, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
2138
  constexpr expected_storage_base(in_place_t, std::initializer_list<U> il,
2139
                                  Args &&...args)
2140
      : m_val(il, std::forward<Args>(args)...), m_has_val(true) {}
2141
  template <class... Args,
2142
            detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * =
2143
                nullptr>
2144
  constexpr explicit expected_storage_base(unexpect_t, Args &&...args)
2145
      : m_unexpect(std::forward<Args>(args)...), m_has_val(false) {}
2146
2147
  template <class U, class... Args,
2148
            detail::enable_if_t<std::is_constructible<
2149
                E, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
2150
  constexpr explicit expected_storage_base(unexpect_t,
2151
                                           std::initializer_list<U> il,
2152
                                           Args &&...args)
2153
      : m_unexpect(il, std::forward<Args>(args)...), m_has_val(false) {}
2154
2155
  ~expected_storage_base() = default;
2156
  union {
2157
    T m_val;
2158
    unexpected<E> m_unexpect;
2159
    char m_no_init;
2160
  };
2161
  bool m_has_val;
2162
};
2163
2164
// T is trivial, E is not.
2165
template <class T, class E>
2166
struct expected_storage_base<T, E, true, false> {
2167
  constexpr expected_storage_base() : m_val(T{}), m_has_val(true) {}
2168
  TL_EXPECTED_MSVC2015_CONSTEXPR expected_storage_base(no_init_t)
2169
      : m_no_init(), m_has_val(false) {}
2170
2171
  template <class... Args,
2172
            detail::enable_if_t<std::is_constructible<T, Args &&...>::value> * =
2173
                nullptr>
2174
  constexpr expected_storage_base(in_place_t, Args &&...args)
2175
      : m_val(std::forward<Args>(args)...), m_has_val(true) {}
2176
2177
  template <class U, class... Args,
2178
            detail::enable_if_t<std::is_constructible<
2179
                T, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
2180
  constexpr expected_storage_base(in_place_t, std::initializer_list<U> il,
2181
                                  Args &&...args)
2182
      : m_val(il, std::forward<Args>(args)...), m_has_val(true) {}
2183
  template <class... Args,
2184
            detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * =
2185
                nullptr>
2186
  constexpr explicit expected_storage_base(unexpect_t, Args &&...args)
2187
      : m_unexpect(std::forward<Args>(args)...), m_has_val(false) {}
2188
2189
  template <class U, class... Args,
2190
            detail::enable_if_t<std::is_constructible<
2191
                E, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
2192
  constexpr explicit expected_storage_base(unexpect_t,
2193
                                           std::initializer_list<U> il,
2194
                                           Args &&...args)
2195
      : m_unexpect(il, std::forward<Args>(args)...), m_has_val(false) {}
2196
2197
  ~expected_storage_base() {
2198
    if (!m_has_val) {
2199
      m_unexpect.~unexpected<E>();
2200
    }
2201
  }
2202
2203
  union {
2204
    T m_val;
2205
    unexpected<E> m_unexpect;
2206
    char m_no_init;
2207
  };
2208
  bool m_has_val;
2209
};
2210
2211
// E is trivial, T is not.
2212
template <class T, class E>
2213
struct expected_storage_base<T, E, false, true> {
2214
  constexpr expected_storage_base() : m_val(T{}), m_has_val(true) {}
2215
0
  constexpr expected_storage_base(no_init_t) : m_no_init(), m_has_val(false) {}
2216
2217
  template <class... Args,
2218
            detail::enable_if_t<std::is_constructible<T, Args &&...>::value> * =
2219
                nullptr>
2220
  constexpr expected_storage_base(in_place_t, Args &&...args)
2221
30.7k
      : 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
2221
15.4k
      : 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
2221
15.3k
      : m_val(std::forward<Args>(args)...), m_has_val(true) {}
Unexecuted instantiation: _ZN2tl6detail21expected_storage_baseIN3ada16url_pattern_initENS2_6errorsELb0ELb1EEC2IJS3_ETnPNSt3__19enable_ifIXsr3std16is_constructibleIS3_DpOT_EE5valueEvE4typeELPv0EEENS_10in_place_tESB_
Unexecuted instantiation: _ZN2tl6detail21expected_storage_baseINSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEN3ada6errorsELb0ELb1EEC2IJS8_ETnPNS2_9enable_ifIXsr3std16is_constructibleIS8_DpOT_EE5valueEvE4typeELPv0EEENS_10in_place_tESG_
Unexecuted instantiation: _ZN2tl6detail21expected_storage_baseINSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEN3ada6errorsELb0ELb1EEC2IJRA1_KcETnPNS2_9enable_ifIXsr3std16is_constructibleIS8_DpOT_EE5valueEvE4typeELPv0EEENS_10in_place_tESJ_
Unexecuted instantiation: _ZN2tl6detail21expected_storage_baseINSt3__16vectorIN3ada19url_pattern_helpers5tokenENS2_9allocatorIS6_EEEENS4_6errorsELb0ELb1EEC2IJRS9_ETnPNS2_9enable_ifIXsr3std16is_constructibleIS9_DpOT_EE5valueEvE4typeELPv0EEENS_10in_place_tESH_
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_
2222
2223
  template <class U, class... Args,
2224
            detail::enable_if_t<std::is_constructible<
2225
                T, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
2226
  constexpr expected_storage_base(in_place_t, std::initializer_list<U> il,
2227
                                  Args &&...args)
2228
      : m_val(il, std::forward<Args>(args)...), m_has_val(true) {}
2229
  template <class... Args,
2230
            detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * =
2231
                nullptr>
2232
  constexpr explicit expected_storage_base(unexpect_t, Args &&...args)
2233
12.1k
      : 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
2233
6.02k
      : 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
2233
6.16k
      : m_unexpect(std::forward<Args>(args)...), m_has_val(false) {}
Unexecuted instantiation: _ZN2tl6detail21expected_storage_baseIN3ada16url_pattern_initENS2_6errorsELb0ELb1EEC2IJS4_ETnPNSt3__19enable_ifIXsr3std16is_constructibleIS4_DpOT_EE5valueEvE4typeELPv0EEENS_10unexpect_tESB_
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_
2234
2235
  template <class U, class... Args,
2236
            detail::enable_if_t<std::is_constructible<
2237
                E, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
2238
  constexpr explicit expected_storage_base(unexpect_t,
2239
                                           std::initializer_list<U> il,
2240
                                           Args &&...args)
2241
      : m_unexpect(il, std::forward<Args>(args)...), m_has_val(false) {}
2242
2243
42.9k
  ~expected_storage_base() {
2244
42.9k
    if (m_has_val) {
2245
30.7k
      m_val.~T();
2246
30.7k
    }
2247
42.9k
  }
tl::detail::expected_storage_base<ada::url, ada::errors, false, true>::~expected_storage_base()
Line
Count
Source
2243
21.4k
  ~expected_storage_base() {
2244
21.4k
    if (m_has_val) {
2245
15.4k
      m_val.~T();
2246
15.4k
    }
2247
21.4k
  }
tl::detail::expected_storage_base<ada::url_aggregator, ada::errors, false, true>::~expected_storage_base()
Line
Count
Source
2243
21.4k
  ~expected_storage_base() {
2244
21.4k
    if (m_has_val) {
2245
15.3k
      m_val.~T();
2246
15.3k
    }
2247
21.4k
  }
Unexecuted instantiation: 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()
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()
2248
  union {
2249
    T m_val;
2250
    unexpected<E> m_unexpect;
2251
    char m_no_init;
2252
  };
2253
  bool m_has_val;
2254
};
2255
2256
// `T` is `void`, `E` is trivially-destructible
2257
template <class E>
2258
struct expected_storage_base<void, E, false, true> {
2259
#if __GNUC__ <= 5
2260
// no constexpr for GCC 4/5 bug
2261
#else
2262
  TL_EXPECTED_MSVC2015_CONSTEXPR
2263
#endif
2264
  expected_storage_base() : m_has_val(true) {}
2265
2266
  constexpr expected_storage_base(no_init_t) : m_val(), m_has_val(false) {}
2267
2268
  constexpr expected_storage_base(in_place_t) : m_has_val(true) {}
2269
2270
  template <class... Args,
2271
            detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * =
2272
                nullptr>
2273
  constexpr explicit expected_storage_base(unexpect_t, Args &&...args)
2274
      : m_unexpect(std::forward<Args>(args)...), m_has_val(false) {}
2275
2276
  template <class U, class... Args,
2277
            detail::enable_if_t<std::is_constructible<
2278
                E, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
2279
  constexpr explicit expected_storage_base(unexpect_t,
2280
                                           std::initializer_list<U> il,
2281
                                           Args &&...args)
2282
      : m_unexpect(il, std::forward<Args>(args)...), m_has_val(false) {}
2283
2284
  ~expected_storage_base() = default;
2285
  struct dummy {};
2286
  union {
2287
    unexpected<E> m_unexpect;
2288
    dummy m_val;
2289
  };
2290
  bool m_has_val;
2291
};
2292
2293
// `T` is `void`, `E` is not trivially-destructible
2294
template <class E>
2295
struct expected_storage_base<void, E, false, false> {
2296
  constexpr expected_storage_base() : m_dummy(), m_has_val(true) {}
2297
  constexpr expected_storage_base(no_init_t) : m_dummy(), m_has_val(false) {}
2298
2299
  constexpr expected_storage_base(in_place_t) : m_dummy(), m_has_val(true) {}
2300
2301
  template <class... Args,
2302
            detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * =
2303
                nullptr>
2304
  constexpr explicit expected_storage_base(unexpect_t, Args &&...args)
2305
      : m_unexpect(std::forward<Args>(args)...), m_has_val(false) {}
2306
2307
  template <class U, class... Args,
2308
            detail::enable_if_t<std::is_constructible<
2309
                E, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
2310
  constexpr explicit expected_storage_base(unexpect_t,
2311
                                           std::initializer_list<U> il,
2312
                                           Args &&...args)
2313
      : m_unexpect(il, std::forward<Args>(args)...), m_has_val(false) {}
2314
2315
  ~expected_storage_base() {
2316
    if (!m_has_val) {
2317
      m_unexpect.~unexpected<E>();
2318
    }
2319
  }
2320
2321
  union {
2322
    unexpected<E> m_unexpect;
2323
    char m_dummy;
2324
  };
2325
  bool m_has_val;
2326
};
2327
2328
// This base class provides some handy member functions which can be used in
2329
// further derived classes
2330
template <class T, class E>
2331
struct expected_operations_base : expected_storage_base<T, E> {
2332
  using expected_storage_base<T, E>::expected_storage_base;
2333
2334
  template <class... Args>
2335
  void construct(Args &&...args) noexcept {
2336
    new (std::addressof(this->m_val)) T(std::forward<Args>(args)...);
2337
    this->m_has_val = true;
2338
  }
2339
2340
  template <class Rhs>
2341
0
  void construct_with(Rhs &&rhs) noexcept {
2342
0
    new (std::addressof(this->m_val)) T(std::forward<Rhs>(rhs).get());
2343
0
    this->m_has_val = true;
2344
0
  }
2345
2346
  template <class... Args>
2347
0
  void construct_error(Args &&...args) noexcept {
2348
0
    new (std::addressof(this->m_unexpect))
2349
0
        unexpected<E>(std::forward<Args>(args)...);
2350
0
    this->m_has_val = false;
2351
0
  }
2352
2353
#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
2354
2355
  // These assign overloads ensure that the most efficient assignment
2356
  // implementation is used while maintaining the strong exception guarantee.
2357
  // The problematic case is where rhs has a value, but *this does not.
2358
  //
2359
  // This overload handles the case where we can just copy-construct `T`
2360
  // directly into place without throwing.
2361
  template <class U = T,
2362
            detail::enable_if_t<std::is_nothrow_copy_constructible<U>::value>
2363
                * = nullptr>
2364
  void assign(const expected_operations_base &rhs) noexcept {
2365
    if (!this->m_has_val && rhs.m_has_val) {
2366
      geterr().~unexpected<E>();
2367
      construct(rhs.get());
2368
    } else {
2369
      assign_common(rhs);
2370
    }
2371
  }
2372
2373
  // This overload handles the case where we can attempt to create a copy of
2374
  // `T`, then no-throw move it into place if the copy was successful.
2375
  template <class U = T,
2376
            detail::enable_if_t<!std::is_nothrow_copy_constructible<U>::value &&
2377
                                std::is_nothrow_move_constructible<U>::value>
2378
                * = nullptr>
2379
  void assign(const expected_operations_base &rhs) noexcept {
2380
    if (!this->m_has_val && rhs.m_has_val) {
2381
      T tmp = rhs.get();
2382
      geterr().~unexpected<E>();
2383
      construct(std::move(tmp));
2384
    } else {
2385
      assign_common(rhs);
2386
    }
2387
  }
2388
2389
  // This overload is the worst-case, where we have to move-construct the
2390
  // unexpected value into temporary storage, then try to copy the T into place.
2391
  // If the construction succeeds, then everything is fine, but if it throws,
2392
  // then we move the old unexpected value back into place before rethrowing the
2393
  // exception.
2394
  template <class U = T,
2395
            detail::enable_if_t<!std::is_nothrow_copy_constructible<U>::value &&
2396
                                !std::is_nothrow_move_constructible<U>::value>
2397
                * = nullptr>
2398
  void assign(const expected_operations_base &rhs) {
2399
    if (!this->m_has_val && rhs.m_has_val) {
2400
      auto tmp = std::move(geterr());
2401
      geterr().~unexpected<E>();
2402
2403
#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
2404
      try {
2405
        construct(rhs.get());
2406
      } catch (...) {
2407
        geterr() = std::move(tmp);
2408
        throw;
2409
      }
2410
#else
2411
      construct(rhs.get());
2412
#endif
2413
    } else {
2414
      assign_common(rhs);
2415
    }
2416
  }
2417
2418
  // These overloads do the same as above, but for rvalues
2419
  template <class U = T,
2420
            detail::enable_if_t<std::is_nothrow_move_constructible<U>::value>
2421
                * = nullptr>
2422
  void assign(expected_operations_base &&rhs) noexcept {
2423
    if (!this->m_has_val && rhs.m_has_val) {
2424
      geterr().~unexpected<E>();
2425
      construct(std::move(rhs).get());
2426
    } else {
2427
      assign_common(std::move(rhs));
2428
    }
2429
  }
2430
2431
  template <class U = T,
2432
            detail::enable_if_t<!std::is_nothrow_move_constructible<U>::value>
2433
                * = nullptr>
2434
  void assign(expected_operations_base &&rhs) {
2435
    if (!this->m_has_val && rhs.m_has_val) {
2436
      auto tmp = std::move(geterr());
2437
      geterr().~unexpected<E>();
2438
#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
2439
      try {
2440
        construct(std::move(rhs).get());
2441
      } catch (...) {
2442
        geterr() = std::move(tmp);
2443
        throw;
2444
      }
2445
#else
2446
      construct(std::move(rhs).get());
2447
#endif
2448
    } else {
2449
      assign_common(std::move(rhs));
2450
    }
2451
  }
2452
2453
#else
2454
2455
  // If exceptions are disabled then we can just copy-construct
2456
  void assign(const expected_operations_base &rhs) noexcept {
2457
    if (!this->m_has_val && rhs.m_has_val) {
2458
      geterr().~unexpected<E>();
2459
      construct(rhs.get());
2460
    } else {
2461
      assign_common(rhs);
2462
    }
2463
  }
2464
2465
  void assign(expected_operations_base &&rhs) noexcept {
2466
    if (!this->m_has_val && rhs.m_has_val) {
2467
      geterr().~unexpected<E>();
2468
      construct(std::move(rhs).get());
2469
    } else {
2470
      assign_common(std::move(rhs));
2471
    }
2472
  }
2473
2474
#endif
2475
2476
  // The common part of move/copy assigning
2477
  template <class Rhs>
2478
  void assign_common(Rhs &&rhs) {
2479
    if (this->m_has_val) {
2480
      if (rhs.m_has_val) {
2481
        get() = std::forward<Rhs>(rhs).get();
2482
      } else {
2483
        destroy_val();
2484
        construct_error(std::forward<Rhs>(rhs).geterr());
2485
      }
2486
    } else {
2487
      if (!rhs.m_has_val) {
2488
        geterr() = std::forward<Rhs>(rhs).geterr();
2489
      }
2490
    }
2491
  }
2492
2493
0
  bool has_value() const { return this->m_has_val; }
2494
2495
  TL_EXPECTED_11_CONSTEXPR T &get() & { return this->m_val; }
2496
0
  constexpr const T &get() const & { return this->m_val; }
2497
  TL_EXPECTED_11_CONSTEXPR T &&get() && { return std::move(this->m_val); }
2498
#ifndef TL_EXPECTED_NO_CONSTRR
2499
  constexpr const T &&get() const && { return std::move(this->m_val); }
2500
#endif
2501
2502
  TL_EXPECTED_11_CONSTEXPR unexpected<E> &geterr() & {
2503
    return this->m_unexpect;
2504
  }
2505
0
  constexpr const unexpected<E> &geterr() const & { return this->m_unexpect; }
2506
  TL_EXPECTED_11_CONSTEXPR unexpected<E> &&geterr() && {
2507
    return std::move(this->m_unexpect);
2508
  }
2509
#ifndef TL_EXPECTED_NO_CONSTRR
2510
  constexpr const unexpected<E> &&geterr() const && {
2511
    return std::move(this->m_unexpect);
2512
  }
2513
#endif
2514
2515
  TL_EXPECTED_11_CONSTEXPR void destroy_val() { get().~T(); }
2516
};
2517
2518
// This base class provides some handy member functions which can be used in
2519
// further derived classes
2520
template <class E>
2521
struct expected_operations_base<void, E> : expected_storage_base<void, E> {
2522
  using expected_storage_base<void, E>::expected_storage_base;
2523
2524
  template <class... Args>
2525
  void construct() noexcept {
2526
    this->m_has_val = true;
2527
  }
2528
2529
  // This function doesn't use its argument, but needs it so that code in
2530
  // levels above this can work independently of whether T is void
2531
  template <class Rhs>
2532
  void construct_with(Rhs &&) noexcept {
2533
    this->m_has_val = true;
2534
  }
2535
2536
  template <class... Args>
2537
  void construct_error(Args &&...args) noexcept {
2538
    new (std::addressof(this->m_unexpect))
2539
        unexpected<E>(std::forward<Args>(args)...);
2540
    this->m_has_val = false;
2541
  }
2542
2543
  template <class Rhs>
2544
  void assign(Rhs &&rhs) noexcept {
2545
    if (!this->m_has_val) {
2546
      if (rhs.m_has_val) {
2547
        geterr().~unexpected<E>();
2548
        construct();
2549
      } else {
2550
        geterr() = std::forward<Rhs>(rhs).geterr();
2551
      }
2552
    } else {
2553
      if (!rhs.m_has_val) {
2554
        construct_error(std::forward<Rhs>(rhs).geterr());
2555
      }
2556
    }
2557
  }
2558
2559
  bool has_value() const { return this->m_has_val; }
2560
2561
  TL_EXPECTED_11_CONSTEXPR unexpected<E> &geterr() & {
2562
    return this->m_unexpect;
2563
  }
2564
  constexpr const unexpected<E> &geterr() const & { return this->m_unexpect; }
2565
  TL_EXPECTED_11_CONSTEXPR unexpected<E> &&geterr() && {
2566
    return std::move(this->m_unexpect);
2567
  }
2568
#ifndef TL_EXPECTED_NO_CONSTRR
2569
  constexpr const unexpected<E> &&geterr() const && {
2570
    return std::move(this->m_unexpect);
2571
  }
2572
#endif
2573
2574
  TL_EXPECTED_11_CONSTEXPR void destroy_val() {
2575
    // no-op
2576
  }
2577
};
2578
2579
// This class manages conditionally having a trivial copy constructor
2580
// This specialization is for when T and E are trivially copy constructible
2581
template <class T, class E,
2582
          bool = is_void_or<T, TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(
2583
                                   T)>::value &&
2584
                 TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(E)::value>
2585
struct expected_copy_base : expected_operations_base<T, E> {
2586
  using expected_operations_base<T, E>::expected_operations_base;
2587
};
2588
2589
// This specialization is for when T or E are not trivially copy constructible
2590
template <class T, class E>
2591
struct expected_copy_base<T, E, false> : expected_operations_base<T, E> {
2592
  using expected_operations_base<T, E>::expected_operations_base;
2593
2594
  expected_copy_base() = default;
2595
  expected_copy_base(const expected_copy_base &rhs)
2596
0
      : expected_operations_base<T, E>(no_init) {
2597
0
    if (rhs.has_value()) {
2598
0
      this->construct_with(rhs);
2599
0
    } else {
2600
0
      this->construct_error(rhs.geterr());
2601
0
    }
2602
0
  }
2603
2604
  expected_copy_base(expected_copy_base &&rhs) = default;
2605
  expected_copy_base &operator=(const expected_copy_base &rhs) = default;
2606
  expected_copy_base &operator=(expected_copy_base &&rhs) = default;
2607
};
2608
2609
// This class manages conditionally having a trivial move constructor
2610
// Unfortunately there's no way to achieve this in GCC < 5 AFAIK, since it
2611
// doesn't implement an analogue to std::is_trivially_move_constructible. We
2612
// have to make do with a non-trivial move constructor even if T is trivially
2613
// move constructible
2614
#ifndef TL_EXPECTED_GCC49
2615
template <class T, class E,
2616
          bool =
2617
              is_void_or<T, std::is_trivially_move_constructible<T>>::value &&
2618
              std::is_trivially_move_constructible<E>::value>
2619
struct expected_move_base : expected_copy_base<T, E> {
2620
  using expected_copy_base<T, E>::expected_copy_base;
2621
};
2622
#else
2623
template <class T, class E, bool = false>
2624
struct expected_move_base;
2625
#endif
2626
template <class T, class E>
2627
struct expected_move_base<T, E, false> : expected_copy_base<T, E> {
2628
  using expected_copy_base<T, E>::expected_copy_base;
2629
2630
  expected_move_base() = default;
2631
0
  expected_move_base(const expected_move_base &rhs) = default;
2632
2633
  expected_move_base(expected_move_base &&rhs) noexcept(
2634
      std::is_nothrow_move_constructible<T>::value)
2635
      : expected_copy_base<T, E>(no_init) {
2636
    if (rhs.has_value()) {
2637
      this->construct_with(std::move(rhs));
2638
    } else {
2639
      this->construct_error(std::move(rhs.geterr()));
2640
    }
2641
  }
2642
  expected_move_base &operator=(const expected_move_base &rhs) = default;
2643
  expected_move_base &operator=(expected_move_base &&rhs) = default;
2644
};
2645
2646
// This class manages conditionally having a trivial copy assignment operator
2647
template <
2648
    class T, class E,
2649
    bool =
2650
        is_void_or<
2651
            T, conjunction<TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(T),
2652
                           TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T),
2653
                           TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(T)>>::value &&
2654
        TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(E)::value &&
2655
        TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(E)::value &&
2656
        TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(E)::value>
2657
struct expected_copy_assign_base : expected_move_base<T, E> {
2658
  using expected_move_base<T, E>::expected_move_base;
2659
};
2660
2661
template <class T, class E>
2662
struct expected_copy_assign_base<T, E, false> : expected_move_base<T, E> {
2663
  using expected_move_base<T, E>::expected_move_base;
2664
2665
  expected_copy_assign_base() = default;
2666
0
  expected_copy_assign_base(const expected_copy_assign_base &rhs) = default;
2667
2668
  expected_copy_assign_base(expected_copy_assign_base &&rhs) = default;
2669
  expected_copy_assign_base &operator=(const expected_copy_assign_base &rhs) {
2670
    this->assign(rhs);
2671
    return *this;
2672
  }
2673
  expected_copy_assign_base &operator=(expected_copy_assign_base &&rhs) =
2674
      default;
2675
};
2676
2677
// This class manages conditionally having a trivial move assignment operator
2678
// Unfortunately there's no way to achieve this in GCC < 5 AFAIK, since it
2679
// doesn't implement an analogue to std::is_trivially_move_assignable. We have
2680
// to make do with a non-trivial move assignment operator even if T is trivially
2681
// move assignable
2682
#ifndef TL_EXPECTED_GCC49
2683
template <
2684
    class T, class E,
2685
    bool = is_void_or<
2686
               T, conjunction<std::is_trivially_destructible<T>,
2687
                              std::is_trivially_move_constructible<T>,
2688
                              std::is_trivially_move_assignable<T>>>::value &&
2689
           std::is_trivially_destructible<E>::value &&
2690
           std::is_trivially_move_constructible<E>::value &&
2691
           std::is_trivially_move_assignable<E>::value>
2692
struct expected_move_assign_base : expected_copy_assign_base<T, E> {
2693
  using expected_copy_assign_base<T, E>::expected_copy_assign_base;
2694
};
2695
#else
2696
template <class T, class E, bool = false>
2697
struct expected_move_assign_base;
2698
#endif
2699
2700
template <class T, class E>
2701
struct expected_move_assign_base<T, E, false>
2702
    : expected_copy_assign_base<T, E> {
2703
  using expected_copy_assign_base<T, E>::expected_copy_assign_base;
2704
2705
  expected_move_assign_base() = default;
2706
0
  expected_move_assign_base(const expected_move_assign_base &rhs) = default;
2707
2708
  expected_move_assign_base(expected_move_assign_base &&rhs) = default;
2709
2710
  expected_move_assign_base &operator=(const expected_move_assign_base &rhs) =
2711
      default;
2712
2713
  expected_move_assign_base &operator=(
2714
      expected_move_assign_base
2715
          &&rhs) noexcept(std::is_nothrow_move_constructible<T>::value &&
2716
                          std::is_nothrow_move_assignable<T>::value) {
2717
    this->assign(std::move(rhs));
2718
    return *this;
2719
  }
2720
};
2721
2722
// expected_delete_ctor_base will conditionally delete copy and move
2723
// constructors depending on whether T is copy/move constructible
2724
template <class T, class E,
2725
          bool EnableCopy = (is_copy_constructible_or_void<T>::value &&
2726
                             std::is_copy_constructible<E>::value),
2727
          bool EnableMove = (is_move_constructible_or_void<T>::value &&
2728
                             std::is_move_constructible<E>::value)>
2729
struct expected_delete_ctor_base {
2730
  expected_delete_ctor_base() = default;
2731
  expected_delete_ctor_base(const expected_delete_ctor_base &) = default;
2732
  expected_delete_ctor_base(expected_delete_ctor_base &&) noexcept = default;
2733
  expected_delete_ctor_base &operator=(const expected_delete_ctor_base &) =
2734
      default;
2735
  expected_delete_ctor_base &operator=(expected_delete_ctor_base &&) noexcept =
2736
      default;
2737
};
2738
2739
template <class T, class E>
2740
struct expected_delete_ctor_base<T, E, true, false> {
2741
  expected_delete_ctor_base() = default;
2742
  expected_delete_ctor_base(const expected_delete_ctor_base &) = default;
2743
  expected_delete_ctor_base(expected_delete_ctor_base &&) noexcept = delete;
2744
  expected_delete_ctor_base &operator=(const expected_delete_ctor_base &) =
2745
      default;
2746
  expected_delete_ctor_base &operator=(expected_delete_ctor_base &&) noexcept =
2747
      default;
2748
};
2749
2750
template <class T, class E>
2751
struct expected_delete_ctor_base<T, E, false, true> {
2752
  expected_delete_ctor_base() = default;
2753
  expected_delete_ctor_base(const expected_delete_ctor_base &) = delete;
2754
  expected_delete_ctor_base(expected_delete_ctor_base &&) noexcept = default;
2755
  expected_delete_ctor_base &operator=(const expected_delete_ctor_base &) =
2756
      default;
2757
  expected_delete_ctor_base &operator=(expected_delete_ctor_base &&) noexcept =
2758
      default;
2759
};
2760
2761
template <class T, class E>
2762
struct expected_delete_ctor_base<T, E, false, false> {
2763
  expected_delete_ctor_base() = default;
2764
  expected_delete_ctor_base(const expected_delete_ctor_base &) = delete;
2765
  expected_delete_ctor_base(expected_delete_ctor_base &&) noexcept = delete;
2766
  expected_delete_ctor_base &operator=(const expected_delete_ctor_base &) =
2767
      default;
2768
  expected_delete_ctor_base &operator=(expected_delete_ctor_base &&) noexcept =
2769
      default;
2770
};
2771
2772
// expected_delete_assign_base will conditionally delete copy and move
2773
// constructors depending on whether T and E are copy/move constructible +
2774
// assignable
2775
template <class T, class E,
2776
          bool EnableCopy = (is_copy_constructible_or_void<T>::value &&
2777
                             std::is_copy_constructible<E>::value &&
2778
                             is_copy_assignable_or_void<T>::value &&
2779
                             std::is_copy_assignable<E>::value),
2780
          bool EnableMove = (is_move_constructible_or_void<T>::value &&
2781
                             std::is_move_constructible<E>::value &&
2782
                             is_move_assignable_or_void<T>::value &&
2783
                             std::is_move_assignable<E>::value)>
2784
struct expected_delete_assign_base {
2785
  expected_delete_assign_base() = default;
2786
  expected_delete_assign_base(const expected_delete_assign_base &) = default;
2787
  expected_delete_assign_base(expected_delete_assign_base &&) noexcept =
2788
      default;
2789
  expected_delete_assign_base &operator=(const expected_delete_assign_base &) =
2790
      default;
2791
  expected_delete_assign_base &operator=(
2792
      expected_delete_assign_base &&) noexcept = default;
2793
};
2794
2795
template <class T, class E>
2796
struct expected_delete_assign_base<T, E, true, false> {
2797
  expected_delete_assign_base() = default;
2798
  expected_delete_assign_base(const expected_delete_assign_base &) = default;
2799
  expected_delete_assign_base(expected_delete_assign_base &&) noexcept =
2800
      default;
2801
  expected_delete_assign_base &operator=(const expected_delete_assign_base &) =
2802
      default;
2803
  expected_delete_assign_base &operator=(
2804
      expected_delete_assign_base &&) noexcept = delete;
2805
};
2806
2807
template <class T, class E>
2808
struct expected_delete_assign_base<T, E, false, true> {
2809
  expected_delete_assign_base() = default;
2810
  expected_delete_assign_base(const expected_delete_assign_base &) = default;
2811
  expected_delete_assign_base(expected_delete_assign_base &&) noexcept =
2812
      default;
2813
  expected_delete_assign_base &operator=(const expected_delete_assign_base &) =
2814
      delete;
2815
  expected_delete_assign_base &operator=(
2816
      expected_delete_assign_base &&) noexcept = default;
2817
};
2818
2819
template <class T, class E>
2820
struct expected_delete_assign_base<T, E, false, false> {
2821
  expected_delete_assign_base() = default;
2822
  expected_delete_assign_base(const expected_delete_assign_base &) = default;
2823
  expected_delete_assign_base(expected_delete_assign_base &&) noexcept =
2824
      default;
2825
  expected_delete_assign_base &operator=(const expected_delete_assign_base &) =
2826
      delete;
2827
  expected_delete_assign_base &operator=(
2828
      expected_delete_assign_base &&) noexcept = delete;
2829
};
2830
2831
// This is needed to be able to construct the expected_default_ctor_base which
2832
// follows, while still conditionally deleting the default constructor.
2833
struct default_constructor_tag {
2834
  explicit constexpr default_constructor_tag() = default;
2835
};
2836
2837
// expected_default_ctor_base will ensure that expected has a deleted default
2838
// consturctor if T is not default constructible.
2839
// This specialization is for when T is default constructible
2840
template <class T, class E,
2841
          bool Enable =
2842
              std::is_default_constructible<T>::value || std::is_void<T>::value>
2843
struct expected_default_ctor_base {
2844
  constexpr expected_default_ctor_base() noexcept = default;
2845
  constexpr expected_default_ctor_base(
2846
      expected_default_ctor_base const &) noexcept = default;
2847
  constexpr expected_default_ctor_base(expected_default_ctor_base &&) noexcept =
2848
      default;
2849
  expected_default_ctor_base &operator=(
2850
      expected_default_ctor_base const &) noexcept = default;
2851
  expected_default_ctor_base &operator=(
2852
      expected_default_ctor_base &&) noexcept = default;
2853
2854
42.9k
  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
2854
21.4k
  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
2854
21.4k
  constexpr explicit expected_default_ctor_base(default_constructor_tag) {}
Unexecuted instantiation: tl::detail::expected_default_ctor_base<ada::url_pattern_init, ada::errors, true>::expected_default_ctor_base(tl::detail::default_constructor_tag)
Unexecuted instantiation: 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)
Unexecuted instantiation: 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)
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)
2855
};
2856
2857
// This specialization is for when T is not default constructible
2858
template <class T, class E>
2859
struct expected_default_ctor_base<T, E, false> {
2860
  constexpr expected_default_ctor_base() noexcept = delete;
2861
  constexpr expected_default_ctor_base(
2862
      expected_default_ctor_base const &) noexcept = default;
2863
  constexpr expected_default_ctor_base(expected_default_ctor_base &&) noexcept =
2864
      default;
2865
  expected_default_ctor_base &operator=(
2866
      expected_default_ctor_base const &) noexcept = default;
2867
  expected_default_ctor_base &operator=(
2868
      expected_default_ctor_base &&) noexcept = default;
2869
2870
  constexpr explicit expected_default_ctor_base(default_constructor_tag) {}
2871
};
2872
}  // namespace detail
2873
2874
template <class E>
2875
class bad_expected_access : public std::exception {
2876
 public:
2877
0
  explicit bad_expected_access(E e) : m_val(std::move(e)) {}
2878
2879
0
  virtual const char *what() const noexcept override {
2880
0
    return "Bad expected access";
2881
0
  }
2882
2883
  const E &error() const & { return m_val; }
2884
  E &error() & { return m_val; }
2885
  const E &&error() const && { return std::move(m_val); }
2886
  E &&error() && { return std::move(m_val); }
2887
2888
 private:
2889
  E m_val;
2890
};
2891
2892
/// An `expected<T, E>` object is an object that contains the storage for
2893
/// another object and manages the lifetime of this contained object `T`.
2894
/// Alternatively it could contain the storage for another unexpected object
2895
/// `E`. The contained object may not be initialized after the expected object
2896
/// has been initialized, and may not be destroyed before the expected object
2897
/// has been destroyed. The initialization state of the contained object is
2898
/// tracked by the expected object.
2899
template <class T, class E>
2900
class expected : private detail::expected_move_assign_base<T, E>,
2901
                 private detail::expected_delete_ctor_base<T, E>,
2902
                 private detail::expected_delete_assign_base<T, E>,
2903
                 private detail::expected_default_ctor_base<T, E> {
2904
  static_assert(!std::is_reference<T>::value, "T must not be a reference");
2905
  static_assert(!std::is_same<T, std::remove_cv<in_place_t>::type>::value,
2906
                "T must not be in_place_t");
2907
  static_assert(!std::is_same<T, std::remove_cv<unexpect_t>::type>::value,
2908
                "T must not be unexpect_t");
2909
  static_assert(
2910
      !std::is_same<T, typename std::remove_cv<unexpected<E>>::type>::value,
2911
      "T must not be unexpected<E>");
2912
  static_assert(!std::is_reference<E>::value, "E must not be a reference");
2913
2914
444k
  T *valptr() { return std::addressof(this->m_val); }
tl::expected<ada::url, ada::errors>::valptr()
Line
Count
Source
2914
198k
  T *valptr() { return std::addressof(this->m_val); }
tl::expected<ada::url_aggregator, ada::errors>::valptr()
Line
Count
Source
2914
246k
  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()
Unexecuted instantiation: tl::expected<ada::url_pattern_init, ada::errors>::valptr()
2915
  const T *valptr() const { return std::addressof(this->m_val); }
2916
  unexpected<E> *errptr() { return std::addressof(this->m_unexpect); }
2917
  const unexpected<E> *errptr() const {
2918
    return std::addressof(this->m_unexpect);
2919
  }
2920
2921
  template <class U = T,
2922
            detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
2923
6.11k
  TL_EXPECTED_11_CONSTEXPR U &val() {
2924
6.11k
    return this->m_val;
2925
6.11k
  }
_ZN2tl8expectedIN3ada3urlENS1_6errorsEE3valIS2_TnPNSt3__19enable_ifIXntsr3std7is_voidIT_EE5valueEvE4typeELPv0EEERS8_v
Line
Count
Source
2923
3.05k
  TL_EXPECTED_11_CONSTEXPR U &val() {
2924
3.05k
    return this->m_val;
2925
3.05k
  }
_ZN2tl8expectedIN3ada14url_aggregatorENS1_6errorsEE3valIS2_TnPNSt3__19enable_ifIXntsr3std7is_voidIT_EE5valueEvE4typeELPv0EEERS8_v
Line
Count
Source
2923
3.05k
  TL_EXPECTED_11_CONSTEXPR U &val() {
2924
3.05k
    return this->m_val;
2925
3.05k
  }
Unexecuted instantiation: _ZN2tl8expectedINSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEN3ada6errorsEE3valIS7_TnPNS1_9enable_ifIXntsr3std7is_voidIT_EE5valueEvE4typeELPv0EEERSD_v
Unexecuted instantiation: _ZN2tl8expectedINSt3__16vectorIN3ada19url_pattern_helpers5tokenENS1_9allocatorIS5_EEEENS3_6errorsEE3valIS8_TnPNS1_9enable_ifIXntsr3std7is_voidIT_EE5valueEvE4typeELPv0EEERSD_v
2926
0
  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<ada::url_pattern_init, 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()
2927
2928
  template <class U = T,
2929
            detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
2930
  constexpr const U &val() const {
2931
    return this->m_val;
2932
  }
2933
  constexpr const unexpected<E> &err() const { return this->m_unexpect; }
2934
2935
  using impl_base = detail::expected_move_assign_base<T, E>;
2936
  using ctor_base = detail::expected_default_ctor_base<T, E>;
2937
2938
 public:
2939
  typedef T value_type;
2940
  typedef E error_type;
2941
  typedef unexpected<E> unexpected_type;
2942
2943
#if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \
2944
    !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55)
2945
  template <class F>
2946
  TL_EXPECTED_11_CONSTEXPR auto and_then(F &&f) & {
2947
    return and_then_impl(*this, std::forward<F>(f));
2948
  }
2949
  template <class F>
2950
  TL_EXPECTED_11_CONSTEXPR auto and_then(F &&f) && {
2951
    return and_then_impl(std::move(*this), std::forward<F>(f));
2952
  }
2953
  template <class F>
2954
  constexpr auto and_then(F &&f) const & {
2955
    return and_then_impl(*this, std::forward<F>(f));
2956
  }
2957
2958
#ifndef TL_EXPECTED_NO_CONSTRR
2959
  template <class F>
2960
  constexpr auto and_then(F &&f) const && {
2961
    return and_then_impl(std::move(*this), std::forward<F>(f));
2962
  }
2963
#endif
2964
2965
#else
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(*this, std::forward<F>(f));
2970
  }
2971
  template <class F>
2972
  TL_EXPECTED_11_CONSTEXPR auto and_then(F &&f) && -> decltype(and_then_impl(
2973
      std::declval<expected &&>(), std::forward<F>(f))) {
2974
    return and_then_impl(std::move(*this), std::forward<F>(f));
2975
  }
2976
  template <class F>
2977
  constexpr auto and_then(F &&f) const & -> decltype(and_then_impl(
2978
      std::declval<expected const &>(), std::forward<F>(f))) {
2979
    return and_then_impl(*this, std::forward<F>(f));
2980
  }
2981
2982
#ifndef TL_EXPECTED_NO_CONSTRR
2983
  template <class F>
2984
  constexpr auto and_then(F &&f) const && -> decltype(and_then_impl(
2985
      std::declval<expected const &&>(), std::forward<F>(f))) {
2986
    return and_then_impl(std::move(*this), std::forward<F>(f));
2987
  }
2988
#endif
2989
#endif
2990
2991
#if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \
2992
    !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55)
2993
  template <class F>
2994
  TL_EXPECTED_11_CONSTEXPR auto map(F &&f) & {
2995
    return expected_map_impl(*this, std::forward<F>(f));
2996
  }
2997
  template <class F>
2998
  TL_EXPECTED_11_CONSTEXPR auto map(F &&f) && {
2999
    return expected_map_impl(std::move(*this), std::forward<F>(f));
3000
  }
3001
  template <class F>
3002
  constexpr auto map(F &&f) const & {
3003
    return expected_map_impl(*this, std::forward<F>(f));
3004
  }
3005
  template <class F>
3006
  constexpr auto map(F &&f) const && {
3007
    return expected_map_impl(std::move(*this), std::forward<F>(f));
3008
  }
3009
#else
3010
  template <class F>
3011
  TL_EXPECTED_11_CONSTEXPR decltype(expected_map_impl(
3012
      std::declval<expected &>(), std::declval<F &&>()))
3013
  map(F &&f) & {
3014
    return expected_map_impl(*this, std::forward<F>(f));
3015
  }
3016
  template <class F>
3017
  TL_EXPECTED_11_CONSTEXPR decltype(expected_map_impl(std::declval<expected>(),
3018
                                                      std::declval<F &&>()))
3019
  map(F &&f) && {
3020
    return expected_map_impl(std::move(*this), std::forward<F>(f));
3021
  }
3022
  template <class F>
3023
  constexpr decltype(expected_map_impl(std::declval<const expected &>(),
3024
                                       std::declval<F &&>()))
3025
  map(F &&f) const & {
3026
    return expected_map_impl(*this, std::forward<F>(f));
3027
  }
3028
3029
#ifndef TL_EXPECTED_NO_CONSTRR
3030
  template <class F>
3031
  constexpr decltype(expected_map_impl(std::declval<const expected &&>(),
3032
                                       std::declval<F &&>()))
3033
  map(F &&f) const && {
3034
    return expected_map_impl(std::move(*this), std::forward<F>(f));
3035
  }
3036
#endif
3037
#endif
3038
3039
#if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \
3040
    !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55)
3041
  template <class F>
3042
  TL_EXPECTED_11_CONSTEXPR auto transform(F &&f) & {
3043
    return expected_map_impl(*this, std::forward<F>(f));
3044
  }
3045
  template <class F>
3046
  TL_EXPECTED_11_CONSTEXPR auto transform(F &&f) && {
3047
    return expected_map_impl(std::move(*this), std::forward<F>(f));
3048
  }
3049
  template <class F>
3050
  constexpr auto transform(F &&f) const & {
3051
    return expected_map_impl(*this, std::forward<F>(f));
3052
  }
3053
  template <class F>
3054
  constexpr auto transform(F &&f) const && {
3055
    return expected_map_impl(std::move(*this), std::forward<F>(f));
3056
  }
3057
#else
3058
  template <class F>
3059
  TL_EXPECTED_11_CONSTEXPR decltype(expected_map_impl(
3060
      std::declval<expected &>(), std::declval<F &&>()))
3061
  transform(F &&f) & {
3062
    return expected_map_impl(*this, std::forward<F>(f));
3063
  }
3064
  template <class F>
3065
  TL_EXPECTED_11_CONSTEXPR decltype(expected_map_impl(std::declval<expected>(),
3066
                                                      std::declval<F &&>()))
3067
  transform(F &&f) && {
3068
    return expected_map_impl(std::move(*this), std::forward<F>(f));
3069
  }
3070
  template <class F>
3071
  constexpr decltype(expected_map_impl(std::declval<const expected &>(),
3072
                                       std::declval<F &&>()))
3073
  transform(F &&f) const & {
3074
    return expected_map_impl(*this, std::forward<F>(f));
3075
  }
3076
3077
#ifndef TL_EXPECTED_NO_CONSTRR
3078
  template <class F>
3079
  constexpr decltype(expected_map_impl(std::declval<const expected &&>(),
3080
                                       std::declval<F &&>()))
3081
  transform(F &&f) const && {
3082
    return expected_map_impl(std::move(*this), std::forward<F>(f));
3083
  }
3084
#endif
3085
#endif
3086
3087
#if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \
3088
    !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55)
3089
  template <class F>
3090
  TL_EXPECTED_11_CONSTEXPR auto map_error(F &&f) & {
3091
    return map_error_impl(*this, std::forward<F>(f));
3092
  }
3093
  template <class F>
3094
  TL_EXPECTED_11_CONSTEXPR auto map_error(F &&f) && {
3095
    return map_error_impl(std::move(*this), std::forward<F>(f));
3096
  }
3097
  template <class F>
3098
  constexpr auto map_error(F &&f) const & {
3099
    return map_error_impl(*this, std::forward<F>(f));
3100
  }
3101
  template <class F>
3102
  constexpr auto map_error(F &&f) const && {
3103
    return map_error_impl(std::move(*this), std::forward<F>(f));
3104
  }
3105
#else
3106
  template <class F>
3107
  TL_EXPECTED_11_CONSTEXPR decltype(map_error_impl(std::declval<expected &>(),
3108
                                                   std::declval<F &&>()))
3109
  map_error(F &&f) & {
3110
    return map_error_impl(*this, std::forward<F>(f));
3111
  }
3112
  template <class F>
3113
  TL_EXPECTED_11_CONSTEXPR decltype(map_error_impl(std::declval<expected &&>(),
3114
                                                   std::declval<F &&>()))
3115
  map_error(F &&f) && {
3116
    return map_error_impl(std::move(*this), std::forward<F>(f));
3117
  }
3118
  template <class F>
3119
  constexpr decltype(map_error_impl(std::declval<const expected &>(),
3120
                                    std::declval<F &&>()))
3121
  map_error(F &&f) const & {
3122
    return map_error_impl(*this, std::forward<F>(f));
3123
  }
3124
3125
#ifndef TL_EXPECTED_NO_CONSTRR
3126
  template <class F>
3127
  constexpr decltype(map_error_impl(std::declval<const expected &&>(),
3128
                                    std::declval<F &&>()))
3129
  map_error(F &&f) const && {
3130
    return map_error_impl(std::move(*this), std::forward<F>(f));
3131
  }
3132
#endif
3133
#endif
3134
#if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \
3135
    !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55)
3136
  template <class F>
3137
  TL_EXPECTED_11_CONSTEXPR auto transform_error(F &&f) & {
3138
    return map_error_impl(*this, std::forward<F>(f));
3139
  }
3140
  template <class F>
3141
  TL_EXPECTED_11_CONSTEXPR auto transform_error(F &&f) && {
3142
    return map_error_impl(std::move(*this), std::forward<F>(f));
3143
  }
3144
  template <class F>
3145
  constexpr auto transform_error(F &&f) const & {
3146
    return map_error_impl(*this, std::forward<F>(f));
3147
  }
3148
  template <class F>
3149
  constexpr auto transform_error(F &&f) const && {
3150
    return map_error_impl(std::move(*this), std::forward<F>(f));
3151
  }
3152
#else
3153
  template <class F>
3154
  TL_EXPECTED_11_CONSTEXPR decltype(map_error_impl(std::declval<expected &>(),
3155
                                                   std::declval<F &&>()))
3156
  transform_error(F &&f) & {
3157
    return map_error_impl(*this, std::forward<F>(f));
3158
  }
3159
  template <class F>
3160
  TL_EXPECTED_11_CONSTEXPR decltype(map_error_impl(std::declval<expected &&>(),
3161
                                                   std::declval<F &&>()))
3162
  transform_error(F &&f) && {
3163
    return map_error_impl(std::move(*this), std::forward<F>(f));
3164
  }
3165
  template <class F>
3166
  constexpr decltype(map_error_impl(std::declval<const expected &>(),
3167
                                    std::declval<F &&>()))
3168
  transform_error(F &&f) const & {
3169
    return map_error_impl(*this, std::forward<F>(f));
3170
  }
3171
3172
#ifndef TL_EXPECTED_NO_CONSTRR
3173
  template <class F>
3174
  constexpr decltype(map_error_impl(std::declval<const expected &&>(),
3175
                                    std::declval<F &&>()))
3176
  transform_error(F &&f) const && {
3177
    return map_error_impl(std::move(*this), std::forward<F>(f));
3178
  }
3179
#endif
3180
#endif
3181
  template <class F>
3182
  expected TL_EXPECTED_11_CONSTEXPR or_else(F &&f) & {
3183
    return or_else_impl(*this, std::forward<F>(f));
3184
  }
3185
3186
  template <class F>
3187
  expected TL_EXPECTED_11_CONSTEXPR or_else(F &&f) && {
3188
    return or_else_impl(std::move(*this), std::forward<F>(f));
3189
  }
3190
3191
  template <class F>
3192
  expected constexpr or_else(F &&f) const & {
3193
    return or_else_impl(*this, std::forward<F>(f));
3194
  }
3195
3196
#ifndef TL_EXPECTED_NO_CONSTRR
3197
  template <class F>
3198
  expected constexpr or_else(F &&f) const && {
3199
    return or_else_impl(std::move(*this), std::forward<F>(f));
3200
  }
3201
#endif
3202
  constexpr expected() = default;
3203
0
  constexpr expected(const expected &rhs) = default;
3204
  constexpr expected(expected &&rhs) = default;
3205
  expected &operator=(const expected &rhs) = default;
3206
  expected &operator=(expected &&rhs) = default;
3207
3208
  template <class... Args,
3209
            detail::enable_if_t<std::is_constructible<T, Args &&...>::value> * =
3210
                nullptr>
3211
  constexpr expected(in_place_t, Args &&...args)
3212
30.7k
      : impl_base(in_place, std::forward<Args>(args)...),
3213
30.7k
        ctor_base(detail::default_constructor_tag{}) {}
_ZN2tl8expectedIN3ada3urlENS1_6errorsEEC2IJS2_ETnPNSt3__19enable_ifIXsr3std16is_constructibleIS2_DpOT_EE5valueEvE4typeELPv0EEENS_10in_place_tESA_
Line
Count
Source
3212
15.4k
      : impl_base(in_place, std::forward<Args>(args)...),
3213
15.4k
        ctor_base(detail::default_constructor_tag{}) {}
_ZN2tl8expectedIN3ada14url_aggregatorENS1_6errorsEEC2IJS2_ETnPNSt3__19enable_ifIXsr3std16is_constructibleIS2_DpOT_EE5valueEvE4typeELPv0EEENS_10in_place_tESA_
Line
Count
Source
3212
15.3k
      : impl_base(in_place, std::forward<Args>(args)...),
3213
15.3k
        ctor_base(detail::default_constructor_tag{}) {}
Unexecuted instantiation: _ZN2tl8expectedIN3ada16url_pattern_initENS1_6errorsEEC2IJS2_ETnPNSt3__19enable_ifIXsr3std16is_constructibleIS2_DpOT_EE5valueEvE4typeELPv0EEENS_10in_place_tESA_
Unexecuted instantiation: _ZN2tl8expectedINSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEN3ada6errorsEEC2IJS7_ETnPNS1_9enable_ifIXsr3std16is_constructibleIS7_DpOT_EE5valueEvE4typeELPv0EEENS_10in_place_tESF_
Unexecuted instantiation: _ZN2tl8expectedINSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEN3ada6errorsEEC2IJRA1_KcETnPNS1_9enable_ifIXsr3std16is_constructibleIS7_DpOT_EE5valueEvE4typeELPv0EEENS_10in_place_tESI_
Unexecuted instantiation: _ZN2tl8expectedINSt3__16vectorIN3ada19url_pattern_helpers5tokenENS1_9allocatorIS5_EEEENS3_6errorsEEC2IJRS8_ETnPNS1_9enable_ifIXsr3std16is_constructibleIS8_DpOT_EE5valueEvE4typeELPv0EEENS_10in_place_tESG_
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_
3214
3215
  template <class U, class... Args,
3216
            detail::enable_if_t<std::is_constructible<
3217
                T, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
3218
  constexpr expected(in_place_t, std::initializer_list<U> il, Args &&...args)
3219
      : impl_base(in_place, il, std::forward<Args>(args)...),
3220
        ctor_base(detail::default_constructor_tag{}) {}
3221
3222
  template <class G = E,
3223
            detail::enable_if_t<std::is_constructible<E, const G &>::value> * =
3224
                nullptr,
3225
            detail::enable_if_t<!std::is_convertible<const G &, E>::value> * =
3226
                nullptr>
3227
  explicit constexpr expected(const unexpected<G> &e)
3228
      : impl_base(unexpect, e.value()),
3229
        ctor_base(detail::default_constructor_tag{}) {}
3230
3231
  template <
3232
      class G = E,
3233
      detail::enable_if_t<std::is_constructible<E, const G &>::value> * =
3234
          nullptr,
3235
      detail::enable_if_t<std::is_convertible<const G &, E>::value> * = nullptr>
3236
  constexpr expected(unexpected<G> const &e)
3237
      : impl_base(unexpect, e.value()),
3238
        ctor_base(detail::default_constructor_tag{}) {}
3239
3240
  template <
3241
      class G = E,
3242
      detail::enable_if_t<std::is_constructible<E, G &&>::value> * = nullptr,
3243
      detail::enable_if_t<!std::is_convertible<G &&, E>::value> * = nullptr>
3244
  explicit constexpr expected(unexpected<G> &&e) noexcept(
3245
      std::is_nothrow_constructible<E, G &&>::value)
3246
      : impl_base(unexpect, std::move(e.value())),
3247
        ctor_base(detail::default_constructor_tag{}) {}
3248
3249
  template <
3250
      class G = E,
3251
      detail::enable_if_t<std::is_constructible<E, G &&>::value> * = nullptr,
3252
      detail::enable_if_t<std::is_convertible<G &&, E>::value> * = nullptr>
3253
  constexpr expected(unexpected<G> &&e) noexcept(
3254
      std::is_nothrow_constructible<E, G &&>::value)
3255
12.1k
      : impl_base(unexpect, std::move(e.value())),
3256
12.1k
        ctor_base(detail::default_constructor_tag{}) {}
_ZN2tl8expectedIN3ada3urlENS1_6errorsEEC2IS3_TnPNSt3__19enable_ifIXsr3std16is_constructibleIS3_OT_EE5valueEvE4typeELPv0ETnPNS7_IXsr3std14is_convertibleIS9_S3_EE5valueEvE4typeELSD_0EEEONS_10unexpectedIS8_EE
Line
Count
Source
3255
6.02k
      : impl_base(unexpect, std::move(e.value())),
3256
6.02k
        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
3255
6.16k
      : impl_base(unexpect, std::move(e.value())),
3256
6.16k
        ctor_base(detail::default_constructor_tag{}) {}
Unexecuted instantiation: _ZN2tl8expectedIN3ada16url_pattern_initENS1_6errorsEEC2IS3_TnPNSt3__19enable_ifIXsr3std16is_constructibleIS3_OT_EE5valueEvE4typeELPv0ETnPNS7_IXsr3std14is_convertibleIS9_S3_EE5valueEvE4typeELSD_0EEEONS_10unexpectedIS8_EE
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
3257
3258
  template <class... Args,
3259
            detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * =
3260
                nullptr>
3261
  constexpr explicit expected(unexpect_t, Args &&...args)
3262
      : impl_base(unexpect, std::forward<Args>(args)...),
3263
        ctor_base(detail::default_constructor_tag{}) {}
3264
3265
  template <class U, class... Args,
3266
            detail::enable_if_t<std::is_constructible<
3267
                E, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
3268
  constexpr explicit expected(unexpect_t, std::initializer_list<U> il,
3269
                              Args &&...args)
3270
      : impl_base(unexpect, il, std::forward<Args>(args)...),
3271
        ctor_base(detail::default_constructor_tag{}) {}
3272
3273
  template <class U, class G,
3274
            detail::enable_if_t<!(std::is_convertible<U const &, T>::value &&
3275
                                  std::is_convertible<G const &, E>::value)> * =
3276
                nullptr,
3277
            detail::expected_enable_from_other<T, E, U, G, const U &, const G &>
3278
                * = nullptr>
3279
  explicit TL_EXPECTED_11_CONSTEXPR expected(const expected<U, G> &rhs)
3280
      : ctor_base(detail::default_constructor_tag{}) {
3281
    if (rhs.has_value()) {
3282
      this->construct(*rhs);
3283
    } else {
3284
      this->construct_error(rhs.error());
3285
    }
3286
  }
3287
3288
  template <class U, class G,
3289
            detail::enable_if_t<(std::is_convertible<U const &, T>::value &&
3290
                                 std::is_convertible<G const &, E>::value)> * =
3291
                nullptr,
3292
            detail::expected_enable_from_other<T, E, U, G, const U &, const G &>
3293
                * = nullptr>
3294
  TL_EXPECTED_11_CONSTEXPR expected(const expected<U, G> &rhs)
3295
      : ctor_base(detail::default_constructor_tag{}) {
3296
    if (rhs.has_value()) {
3297
      this->construct(*rhs);
3298
    } else {
3299
      this->construct_error(rhs.error());
3300
    }
3301
  }
3302
3303
  template <
3304
      class U, class G,
3305
      detail::enable_if_t<!(std::is_convertible<U &&, T>::value &&
3306
                            std::is_convertible<G &&, E>::value)> * = nullptr,
3307
      detail::expected_enable_from_other<T, E, U, G, U &&, G &&> * = nullptr>
3308
  explicit TL_EXPECTED_11_CONSTEXPR expected(expected<U, G> &&rhs)
3309
      : ctor_base(detail::default_constructor_tag{}) {
3310
    if (rhs.has_value()) {
3311
      this->construct(std::move(*rhs));
3312
    } else {
3313
      this->construct_error(std::move(rhs.error()));
3314
    }
3315
  }
3316
3317
  template <
3318
      class U, class G,
3319
      detail::enable_if_t<(std::is_convertible<U &&, T>::value &&
3320
                           std::is_convertible<G &&, E>::value)> * = nullptr,
3321
      detail::expected_enable_from_other<T, E, U, G, U &&, G &&> * = nullptr>
3322
  TL_EXPECTED_11_CONSTEXPR expected(expected<U, G> &&rhs)
3323
      : ctor_base(detail::default_constructor_tag{}) {
3324
    if (rhs.has_value()) {
3325
      this->construct(std::move(*rhs));
3326
    } else {
3327
      this->construct_error(std::move(rhs.error()));
3328
    }
3329
  }
3330
3331
  template <
3332
      class U = T,
3333
      detail::enable_if_t<!std::is_convertible<U &&, T>::value> * = nullptr,
3334
      detail::expected_enable_forward_value<T, E, U> * = nullptr>
3335
  explicit TL_EXPECTED_MSVC2015_CONSTEXPR expected(U &&v)
3336
      : expected(in_place, std::forward<U>(v)) {}
3337
3338
  template <
3339
      class U = T,
3340
      detail::enable_if_t<std::is_convertible<U &&, T>::value> * = nullptr,
3341
      detail::expected_enable_forward_value<T, E, U> * = nullptr>
3342
  TL_EXPECTED_MSVC2015_CONSTEXPR expected(U &&v)
3343
30.7k
      : 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
3343
15.4k
      : 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
3343
15.3k
      : expected(in_place, std::forward<U>(v)) {}
Unexecuted instantiation: _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_
Unexecuted instantiation: _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_
Unexecuted instantiation: _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_
Unexecuted instantiation: _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_
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_
3344
3345
  template <
3346
      class U = T, class G = T,
3347
      detail::enable_if_t<std::is_nothrow_constructible<T, U &&>::value> * =
3348
          nullptr,
3349
      detail::enable_if_t<!std::is_void<G>::value> * = nullptr,
3350
      detail::enable_if_t<
3351
          (!std::is_same<expected<T, E>, detail::decay_t<U>>::value &&
3352
           !detail::conjunction<std::is_scalar<T>,
3353
                                std::is_same<T, detail::decay_t<U>>>::value &&
3354
           std::is_constructible<T, U>::value &&
3355
           std::is_assignable<G &, U>::value &&
3356
           std::is_nothrow_move_constructible<E>::value)> * = nullptr>
3357
  expected &operator=(U &&v) {
3358
    if (has_value()) {
3359
      val() = std::forward<U>(v);
3360
    } else {
3361
      err().~unexpected<E>();
3362
      ::new (valptr()) T(std::forward<U>(v));
3363
      this->m_has_val = true;
3364
    }
3365
3366
    return *this;
3367
  }
3368
3369
  template <
3370
      class U = T, class G = T,
3371
      detail::enable_if_t<!std::is_nothrow_constructible<T, U &&>::value> * =
3372
          nullptr,
3373
      detail::enable_if_t<!std::is_void<U>::value> * = nullptr,
3374
      detail::enable_if_t<
3375
          (!std::is_same<expected<T, E>, detail::decay_t<U>>::value &&
3376
           !detail::conjunction<std::is_scalar<T>,
3377
                                std::is_same<T, detail::decay_t<U>>>::value &&
3378
           std::is_constructible<T, U>::value &&
3379
           std::is_assignable<G &, U>::value &&
3380
           std::is_nothrow_move_constructible<E>::value)> * = nullptr>
3381
  expected &operator=(U &&v) {
3382
    if (has_value()) {
3383
      val() = std::forward<U>(v);
3384
    } else {
3385
      auto tmp = std::move(err());
3386
      err().~unexpected<E>();
3387
3388
#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
3389
      try {
3390
        ::new (valptr()) T(std::forward<U>(v));
3391
        this->m_has_val = true;
3392
      } catch (...) {
3393
        err() = std::move(tmp);
3394
        throw;
3395
      }
3396
#else
3397
      ::new (valptr()) T(std::forward<U>(v));
3398
      this->m_has_val = true;
3399
#endif
3400
    }
3401
3402
    return *this;
3403
  }
3404
3405
  template <class G = E,
3406
            detail::enable_if_t<std::is_nothrow_copy_constructible<G>::value &&
3407
                                std::is_assignable<G &, G>::value> * = nullptr>
3408
  expected &operator=(const unexpected<G> &rhs) {
3409
    if (!has_value()) {
3410
      err() = rhs;
3411
    } else {
3412
      this->destroy_val();
3413
      ::new (errptr()) unexpected<E>(rhs);
3414
      this->m_has_val = false;
3415
    }
3416
3417
    return *this;
3418
  }
3419
3420
  template <class G = E,
3421
            detail::enable_if_t<std::is_nothrow_move_constructible<G>::value &&
3422
                                std::is_move_assignable<G>::value> * = nullptr>
3423
  expected &operator=(unexpected<G> &&rhs) noexcept {
3424
    if (!has_value()) {
3425
      err() = std::move(rhs);
3426
    } else {
3427
      this->destroy_val();
3428
      ::new (errptr()) unexpected<E>(std::move(rhs));
3429
      this->m_has_val = false;
3430
    }
3431
3432
    return *this;
3433
  }
3434
3435
  template <class... Args, detail::enable_if_t<std::is_nothrow_constructible<
3436
                               T, Args &&...>::value> * = nullptr>
3437
  void emplace(Args &&...args) {
3438
    if (has_value()) {
3439
      val().~T();
3440
    } else {
3441
      err().~unexpected<E>();
3442
      this->m_has_val = true;
3443
    }
3444
    ::new (valptr()) T(std::forward<Args>(args)...);
3445
  }
3446
3447
  template <class... Args, detail::enable_if_t<!std::is_nothrow_constructible<
3448
                               T, Args &&...>::value> * = nullptr>
3449
  void emplace(Args &&...args) {
3450
    if (has_value()) {
3451
      val().~T();
3452
      ::new (valptr()) T(std::forward<Args>(args)...);
3453
    } else {
3454
      auto tmp = std::move(err());
3455
      err().~unexpected<E>();
3456
3457
#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
3458
      try {
3459
        ::new (valptr()) T(std::forward<Args>(args)...);
3460
        this->m_has_val = true;
3461
      } catch (...) {
3462
        err() = std::move(tmp);
3463
        throw;
3464
      }
3465
#else
3466
      ::new (valptr()) T(std::forward<Args>(args)...);
3467
      this->m_has_val = true;
3468
#endif
3469
    }
3470
  }
3471
3472
  template <class U, class... Args,
3473
            detail::enable_if_t<std::is_nothrow_constructible<
3474
                T, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
3475
  void emplace(std::initializer_list<U> il, Args &&...args) {
3476
    if (has_value()) {
3477
      T t(il, std::forward<Args>(args)...);
3478
      val() = std::move(t);
3479
    } else {
3480
      err().~unexpected<E>();
3481
      ::new (valptr()) T(il, std::forward<Args>(args)...);
3482
      this->m_has_val = true;
3483
    }
3484
  }
3485
3486
  template <class U, class... Args,
3487
            detail::enable_if_t<!std::is_nothrow_constructible<
3488
                T, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
3489
  void emplace(std::initializer_list<U> il, Args &&...args) {
3490
    if (has_value()) {
3491
      T t(il, std::forward<Args>(args)...);
3492
      val() = std::move(t);
3493
    } else {
3494
      auto tmp = std::move(err());
3495
      err().~unexpected<E>();
3496
3497
#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
3498
      try {
3499
        ::new (valptr()) T(il, std::forward<Args>(args)...);
3500
        this->m_has_val = true;
3501
      } catch (...) {
3502
        err() = std::move(tmp);
3503
        throw;
3504
      }
3505
#else
3506
      ::new (valptr()) T(il, std::forward<Args>(args)...);
3507
      this->m_has_val = true;
3508
#endif
3509
    }
3510
  }
3511
3512
 private:
3513
  using t_is_void = std::true_type;
3514
  using t_is_not_void = std::false_type;
3515
  using t_is_nothrow_move_constructible = std::true_type;
3516
  using move_constructing_t_can_throw = std::false_type;
3517
  using e_is_nothrow_move_constructible = std::true_type;
3518
  using move_constructing_e_can_throw = std::false_type;
3519
3520
  void swap_where_both_have_value(expected & /*rhs*/, t_is_void) noexcept {
3521
    // swapping void is a no-op
3522
  }
3523
3524
  void swap_where_both_have_value(expected &rhs, t_is_not_void) {
3525
    using std::swap;
3526
    swap(val(), rhs.val());
3527
  }
3528
3529
  void swap_where_only_one_has_value(expected &rhs, t_is_void) noexcept(
3530
      std::is_nothrow_move_constructible<E>::value) {
3531
    ::new (errptr()) unexpected_type(std::move(rhs.err()));
3532
    rhs.err().~unexpected_type();
3533
    std::swap(this->m_has_val, rhs.m_has_val);
3534
  }
3535
3536
  void swap_where_only_one_has_value(expected &rhs, t_is_not_void) {
3537
    swap_where_only_one_has_value_and_t_is_not_void(
3538
        rhs, typename std::is_nothrow_move_constructible<T>::type{},
3539
        typename std::is_nothrow_move_constructible<E>::type{});
3540
  }
3541
3542
  void swap_where_only_one_has_value_and_t_is_not_void(
3543
      expected &rhs, t_is_nothrow_move_constructible,
3544
      e_is_nothrow_move_constructible) noexcept {
3545
    auto temp = std::move(val());
3546
    val().~T();
3547
    ::new (errptr()) unexpected_type(std::move(rhs.err()));
3548
    rhs.err().~unexpected_type();
3549
    ::new (rhs.valptr()) T(std::move(temp));
3550
    std::swap(this->m_has_val, rhs.m_has_val);
3551
  }
3552
3553
  void swap_where_only_one_has_value_and_t_is_not_void(
3554
      expected &rhs, t_is_nothrow_move_constructible,
3555
      move_constructing_e_can_throw) {
3556
    auto temp = std::move(val());
3557
    val().~T();
3558
#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
3559
    try {
3560
      ::new (errptr()) unexpected_type(std::move(rhs.err()));
3561
      rhs.err().~unexpected_type();
3562
      ::new (rhs.valptr()) T(std::move(temp));
3563
      std::swap(this->m_has_val, rhs.m_has_val);
3564
    } catch (...) {
3565
      val() = std::move(temp);
3566
      throw;
3567
    }
3568
#else
3569
    ::new (errptr()) unexpected_type(std::move(rhs.err()));
3570
    rhs.err().~unexpected_type();
3571
    ::new (rhs.valptr()) T(std::move(temp));
3572
    std::swap(this->m_has_val, rhs.m_has_val);
3573
#endif
3574
  }
3575
3576
  void swap_where_only_one_has_value_and_t_is_not_void(
3577
      expected &rhs, move_constructing_t_can_throw,
3578
      e_is_nothrow_move_constructible) {
3579
    auto temp = std::move(rhs.err());
3580
    rhs.err().~unexpected_type();
3581
#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
3582
    try {
3583
      ::new (rhs.valptr()) T(std::move(val()));
3584
      val().~T();
3585
      ::new (errptr()) unexpected_type(std::move(temp));
3586
      std::swap(this->m_has_val, rhs.m_has_val);
3587
    } catch (...) {
3588
      rhs.err() = std::move(temp);
3589
      throw;
3590
    }
3591
#else
3592
    ::new (rhs.valptr()) T(std::move(val()));
3593
    val().~T();
3594
    ::new (errptr()) unexpected_type(std::move(temp));
3595
    std::swap(this->m_has_val, rhs.m_has_val);
3596
#endif
3597
  }
3598
3599
 public:
3600
  template <class OT = T, class OE = E>
3601
  detail::enable_if_t<detail::is_swappable<OT>::value &&
3602
                      detail::is_swappable<OE>::value &&
3603
                      (std::is_nothrow_move_constructible<OT>::value ||
3604
                       std::is_nothrow_move_constructible<OE>::value)>
3605
  swap(expected &rhs) noexcept(std::is_nothrow_move_constructible<T>::value &&
3606
                               detail::is_nothrow_swappable<T>::value &&
3607
                               std::is_nothrow_move_constructible<E>::value &&
3608
                               detail::is_nothrow_swappable<E>::value) {
3609
    if (has_value() && rhs.has_value()) {
3610
      swap_where_both_have_value(rhs, typename std::is_void<T>::type{});
3611
    } else if (!has_value() && rhs.has_value()) {
3612
      rhs.swap(*this);
3613
    } else if (has_value()) {
3614
      swap_where_only_one_has_value(rhs, typename std::is_void<T>::type{});
3615
    } else {
3616
      using std::swap;
3617
      swap(err(), rhs.err());
3618
    }
3619
  }
3620
3621
  constexpr const T *operator->() const {
3622
    TL_ASSERT(has_value());
3623
    return valptr();
3624
  }
3625
444k
  TL_EXPECTED_11_CONSTEXPR T *operator->() {
3626
444k
    TL_ASSERT(has_value());
3627
444k
    return valptr();
3628
444k
  }
tl::expected<ada::url, ada::errors>::operator->()
Line
Count
Source
3625
198k
  TL_EXPECTED_11_CONSTEXPR T *operator->() {
3626
198k
    TL_ASSERT(has_value());
3627
198k
    return valptr();
3628
198k
  }
tl::expected<ada::url_aggregator, ada::errors>::operator->()
Line
Count
Source
3625
246k
  TL_EXPECTED_11_CONSTEXPR T *operator->() {
3626
246k
    TL_ASSERT(has_value());
3627
246k
    return valptr();
3628
246k
  }
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->()
Unexecuted instantiation: tl::expected<ada::url_pattern_init, ada::errors>::operator->()
3629
3630
  template <class U = T,
3631
            detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
3632
  constexpr const U &operator*() const & {
3633
    TL_ASSERT(has_value());
3634
    return val();
3635
  }
3636
  template <class U = T,
3637
            detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
3638
6.11k
  TL_EXPECTED_11_CONSTEXPR U &operator*() & {
3639
6.11k
    TL_ASSERT(has_value());
3640
6.11k
    return val();
3641
6.11k
  }
_ZNR2tl8expectedIN3ada3urlENS1_6errorsEEdeIS2_TnPNSt3__19enable_ifIXntsr3std7is_voidIT_EE5valueEvE4typeELPv0EEERS8_v
Line
Count
Source
3638
3.05k
  TL_EXPECTED_11_CONSTEXPR U &operator*() & {
3639
3.05k
    TL_ASSERT(has_value());
3640
3.05k
    return val();
3641
3.05k
  }
_ZNR2tl8expectedIN3ada14url_aggregatorENS1_6errorsEEdeIS2_TnPNSt3__19enable_ifIXntsr3std7is_voidIT_EE5valueEvE4typeELPv0EEERS8_v
Line
Count
Source
3638
3.05k
  TL_EXPECTED_11_CONSTEXPR U &operator*() & {
3639
3.05k
    TL_ASSERT(has_value());
3640
3.05k
    return val();
3641
3.05k
  }
Unexecuted instantiation: _ZNR2tl8expectedINSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEN3ada6errorsEEdeIS7_TnPNS1_9enable_ifIXntsr3std7is_voidIT_EE5valueEvE4typeELPv0EEERSD_v
Unexecuted instantiation: _ZNR2tl8expectedINSt3__16vectorIN3ada19url_pattern_helpers5tokenENS1_9allocatorIS5_EEEENS3_6errorsEEdeIS8_TnPNS1_9enable_ifIXntsr3std7is_voidIT_EE5valueEvE4typeELPv0EEERSD_v
3642
  template <class U = T,
3643
            detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
3644
  constexpr const U &&operator*() const && {
3645
    TL_ASSERT(has_value());
3646
    return std::move(val());
3647
  }
3648
  template <class U = T,
3649
            detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
3650
  TL_EXPECTED_11_CONSTEXPR U &&operator*() && {
3651
    TL_ASSERT(has_value());
3652
    return std::move(val());
3653
  }
3654
3655
469k
  constexpr bool has_value() const noexcept { return this->m_has_val; }
tl::expected<ada::url, ada::errors>::has_value() const
Line
Count
Source
3655
211k
  constexpr bool has_value() const noexcept { return this->m_has_val; }
tl::expected<ada::url_aggregator, ada::errors>::has_value() const
Line
Count
Source
3655
258k
  constexpr bool has_value() const noexcept { return this->m_has_val; }
Unexecuted instantiation: tl::expected<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, 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
Unexecuted instantiation: tl::expected<ada::url_pattern_init, ada::errors>::has_value() const
Unexecuted instantiation: tl::expected<std::__1::vector<ada::url_pattern_helpers::token, std::__1::allocator<ada::url_pattern_helpers::token> >, ada::errors>::has_value() const
3656
42.9k
  constexpr explicit operator bool() const noexcept { return this->m_has_val; }
tl::expected<ada::url, ada::errors>::operator bool() const
Line
Count
Source
3656
21.4k
  constexpr explicit operator bool() const noexcept { return this->m_has_val; }
tl::expected<ada::url_aggregator, ada::errors>::operator bool() const
Line
Count
Source
3656
21.4k
  constexpr explicit operator bool() const noexcept { return this->m_has_val; }
Unexecuted instantiation: tl::expected<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, ada::errors>::operator bool() const
Unexecuted instantiation: tl::expected<ada::url_search_params, ada::errors>::operator bool() const
Unexecuted instantiation: tl::expected<ada::url_pattern_init, ada::errors>::operator bool() const
Unexecuted instantiation: tl::expected<std::__1::vector<ada::url_pattern_helpers::token, std::__1::allocator<ada::url_pattern_helpers::token> >, ada::errors>::operator bool() const
3657
3658
  template <class U = T,
3659
            detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
3660
  TL_EXPECTED_11_CONSTEXPR const U &value() const & {
3661
    if (!has_value())
3662
      detail::throw_exception(bad_expected_access<E>(err().value()));
3663
    return val();
3664
  }
3665
  template <class U = T,
3666
            detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
3667
0
  TL_EXPECTED_11_CONSTEXPR U &value() & {
3668
0
    if (!has_value())
3669
0
      detail::throw_exception(bad_expected_access<E>(err().value()));
3670
0
    return val();
3671
0
  }
3672
  template <class U = T,
3673
            detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
3674
  TL_EXPECTED_11_CONSTEXPR const U &&value() const && {
3675
    if (!has_value())
3676
      detail::throw_exception(bad_expected_access<E>(std::move(err()).value()));
3677
    return std::move(val());
3678
  }
3679
  template <class U = T,
3680
            detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
3681
  TL_EXPECTED_11_CONSTEXPR U &&value() && {
3682
    if (!has_value())
3683
      detail::throw_exception(bad_expected_access<E>(std::move(err()).value()));
3684
    return std::move(val());
3685
  }
3686
3687
  constexpr const E &error() const & {
3688
    TL_ASSERT(!has_value());
3689
    return err().value();
3690
  }
3691
0
  TL_EXPECTED_11_CONSTEXPR E &error() & {
3692
0
    TL_ASSERT(!has_value());
3693
0
    return err().value();
3694
0
  }
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<ada::url_pattern_init, 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() &
3695
  constexpr const E &&error() const && {
3696
    TL_ASSERT(!has_value());
3697
    return std::move(err().value());
3698
  }
3699
  TL_EXPECTED_11_CONSTEXPR E &&error() && {
3700
    TL_ASSERT(!has_value());
3701
    return std::move(err().value());
3702
  }
3703
3704
  template <class U>
3705
  constexpr T value_or(U &&v) const & {
3706
    static_assert(std::is_copy_constructible<T>::value &&
3707
                      std::is_convertible<U &&, T>::value,
3708
                  "T must be copy-constructible and convertible to from U&&");
3709
    return bool(*this) ? **this : static_cast<T>(std::forward<U>(v));
3710
  }
3711
  template <class U>
3712
  TL_EXPECTED_11_CONSTEXPR T value_or(U &&v) && {
3713
    static_assert(std::is_move_constructible<T>::value &&
3714
                      std::is_convertible<U &&, T>::value,
3715
                  "T must be move-constructible and convertible to from U&&");
3716
    return bool(*this) ? std::move(**this) : static_cast<T>(std::forward<U>(v));
3717
  }
3718
};
3719
3720
namespace detail {
3721
template <class Exp>
3722
using exp_t = typename detail::decay_t<Exp>::value_type;
3723
template <class Exp>
3724
using err_t = typename detail::decay_t<Exp>::error_type;
3725
template <class Exp, class Ret>
3726
using ret_t = expected<Ret, err_t<Exp>>;
3727
3728
#ifdef TL_EXPECTED_CXX14
3729
template <class Exp, class F,
3730
          detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
3731
          class Ret = decltype(detail::invoke(std::declval<F>(),
3732
                                              *std::declval<Exp>()))>
3733
constexpr auto and_then_impl(Exp &&exp, F &&f) {
3734
  static_assert(detail::is_expected<Ret>::value, "F must return an expected");
3735
3736
  return exp.has_value()
3737
             ? detail::invoke(std::forward<F>(f), *std::forward<Exp>(exp))
3738
             : Ret(unexpect, std::forward<Exp>(exp).error());
3739
}
3740
3741
template <class Exp, class F,
3742
          detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
3743
          class Ret = decltype(detail::invoke(std::declval<F>()))>
3744
constexpr auto and_then_impl(Exp &&exp, F &&f) {
3745
  static_assert(detail::is_expected<Ret>::value, "F must return an expected");
3746
3747
  return exp.has_value() ? detail::invoke(std::forward<F>(f))
3748
                         : Ret(unexpect, std::forward<Exp>(exp).error());
3749
}
3750
#else
3751
template <class>
3752
struct TC;
3753
template <class Exp, class F,
3754
          class Ret = decltype(detail::invoke(std::declval<F>(),
3755
                                              *std::declval<Exp>())),
3756
          detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr>
3757
auto and_then_impl(Exp &&exp, F &&f) -> Ret {
3758
  static_assert(detail::is_expected<Ret>::value, "F must return an expected");
3759
3760
  return exp.has_value()
3761
             ? detail::invoke(std::forward<F>(f), *std::forward<Exp>(exp))
3762
             : Ret(unexpect, std::forward<Exp>(exp).error());
3763
}
3764
3765
template <class Exp, class F,
3766
          class Ret = decltype(detail::invoke(std::declval<F>())),
3767
          detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr>
3768
constexpr auto and_then_impl(Exp &&exp, F &&f) -> Ret {
3769
  static_assert(detail::is_expected<Ret>::value, "F must return an expected");
3770
3771
  return exp.has_value() ? detail::invoke(std::forward<F>(f))
3772
                         : Ret(unexpect, std::forward<Exp>(exp).error());
3773
}
3774
#endif
3775
3776
#ifdef TL_EXPECTED_CXX14
3777
template <class Exp, class F,
3778
          detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
3779
          class Ret = decltype(detail::invoke(std::declval<F>(),
3780
                                              *std::declval<Exp>())),
3781
          detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
3782
constexpr auto expected_map_impl(Exp &&exp, F &&f) {
3783
  using result = ret_t<Exp, detail::decay_t<Ret>>;
3784
  return exp.has_value() ? result(detail::invoke(std::forward<F>(f),
3785
                                                 *std::forward<Exp>(exp)))
3786
                         : result(unexpect, std::forward<Exp>(exp).error());
3787
}
3788
3789
template <class Exp, class F,
3790
          detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
3791
          class Ret = decltype(detail::invoke(std::declval<F>(),
3792
                                              *std::declval<Exp>())),
3793
          detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
3794
auto expected_map_impl(Exp &&exp, F &&f) {
3795
  using result = expected<void, err_t<Exp>>;
3796
  if (exp.has_value()) {
3797
    detail::invoke(std::forward<F>(f), *std::forward<Exp>(exp));
3798
    return result();
3799
  }
3800
3801
  return result(unexpect, std::forward<Exp>(exp).error());
3802
}
3803
3804
template <class Exp, class F,
3805
          detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
3806
          class Ret = decltype(detail::invoke(std::declval<F>())),
3807
          detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
3808
constexpr auto expected_map_impl(Exp &&exp, F &&f) {
3809
  using result = ret_t<Exp, detail::decay_t<Ret>>;
3810
  return exp.has_value() ? result(detail::invoke(std::forward<F>(f)))
3811
                         : result(unexpect, std::forward<Exp>(exp).error());
3812
}
3813
3814
template <class Exp, class F,
3815
          detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
3816
          class Ret = decltype(detail::invoke(std::declval<F>())),
3817
          detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
3818
auto expected_map_impl(Exp &&exp, F &&f) {
3819
  using result = expected<void, err_t<Exp>>;
3820
  if (exp.has_value()) {
3821
    detail::invoke(std::forward<F>(f));
3822
    return result();
3823
  }
3824
3825
  return result(unexpect, std::forward<Exp>(exp).error());
3826
}
3827
#else
3828
template <class Exp, class F,
3829
          detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
3830
          class Ret = decltype(detail::invoke(std::declval<F>(),
3831
                                              *std::declval<Exp>())),
3832
          detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
3833
3834
constexpr auto expected_map_impl(Exp &&exp, F &&f)
3835
    -> ret_t<Exp, detail::decay_t<Ret>> {
3836
  using result = ret_t<Exp, detail::decay_t<Ret>>;
3837
3838
  return exp.has_value() ? result(detail::invoke(std::forward<F>(f),
3839
                                                 *std::forward<Exp>(exp)))
3840
                         : result(unexpect, std::forward<Exp>(exp).error());
3841
}
3842
3843
template <class Exp, class F,
3844
          detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
3845
          class Ret = decltype(detail::invoke(std::declval<F>(),
3846
                                              *std::declval<Exp>())),
3847
          detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
3848
3849
auto expected_map_impl(Exp &&exp, F &&f) -> expected<void, err_t<Exp>> {
3850
  if (exp.has_value()) {
3851
    detail::invoke(std::forward<F>(f), *std::forward<Exp>(exp));
3852
    return {};
3853
  }
3854
3855
  return unexpected<err_t<Exp>>(std::forward<Exp>(exp).error());
3856
}
3857
3858
template <class Exp, class F,
3859
          detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
3860
          class Ret = decltype(detail::invoke(std::declval<F>())),
3861
          detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
3862
3863
constexpr auto expected_map_impl(Exp &&exp, F &&f)
3864
    -> ret_t<Exp, detail::decay_t<Ret>> {
3865
  using result = ret_t<Exp, detail::decay_t<Ret>>;
3866
3867
  return exp.has_value() ? result(detail::invoke(std::forward<F>(f)))
3868
                         : result(unexpect, std::forward<Exp>(exp).error());
3869
}
3870
3871
template <class Exp, class F,
3872
          detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
3873
          class Ret = decltype(detail::invoke(std::declval<F>())),
3874
          detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
3875
3876
auto expected_map_impl(Exp &&exp, F &&f) -> expected<void, err_t<Exp>> {
3877
  if (exp.has_value()) {
3878
    detail::invoke(std::forward<F>(f));
3879
    return {};
3880
  }
3881
3882
  return unexpected<err_t<Exp>>(std::forward<Exp>(exp).error());
3883
}
3884
#endif
3885
3886
#if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \
3887
    !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55)
3888
template <class Exp, class F,
3889
          detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
3890
          class Ret = decltype(detail::invoke(std::declval<F>(),
3891
                                              std::declval<Exp>().error())),
3892
          detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
3893
constexpr auto map_error_impl(Exp &&exp, F &&f) {
3894
  using result = expected<exp_t<Exp>, detail::decay_t<Ret>>;
3895
  return exp.has_value()
3896
             ? result(*std::forward<Exp>(exp))
3897
             : result(unexpect, detail::invoke(std::forward<F>(f),
3898
                                               std::forward<Exp>(exp).error()));
3899
}
3900
template <class Exp, class F,
3901
          detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
3902
          class Ret = decltype(detail::invoke(std::declval<F>(),
3903
                                              std::declval<Exp>().error())),
3904
          detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
3905
auto map_error_impl(Exp &&exp, F &&f) {
3906
  using result = expected<exp_t<Exp>, monostate>;
3907
  if (exp.has_value()) {
3908
    return result(*std::forward<Exp>(exp));
3909
  }
3910
3911
  detail::invoke(std::forward<F>(f), std::forward<Exp>(exp).error());
3912
  return result(unexpect, monostate{});
3913
}
3914
template <class Exp, class F,
3915
          detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
3916
          class Ret = decltype(detail::invoke(std::declval<F>(),
3917
                                              std::declval<Exp>().error())),
3918
          detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
3919
constexpr auto map_error_impl(Exp &&exp, F &&f) {
3920
  using result = expected<exp_t<Exp>, detail::decay_t<Ret>>;
3921
  return exp.has_value()
3922
             ? result()
3923
             : result(unexpect, detail::invoke(std::forward<F>(f),
3924
                                               std::forward<Exp>(exp).error()));
3925
}
3926
template <class Exp, class F,
3927
          detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
3928
          class Ret = decltype(detail::invoke(std::declval<F>(),
3929
                                              std::declval<Exp>().error())),
3930
          detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
3931
auto map_error_impl(Exp &&exp, F &&f) {
3932
  using result = expected<exp_t<Exp>, monostate>;
3933
  if (exp.has_value()) {
3934
    return result();
3935
  }
3936
3937
  detail::invoke(std::forward<F>(f), std::forward<Exp>(exp).error());
3938
  return result(unexpect, monostate{});
3939
}
3940
#else
3941
template <class Exp, class F,
3942
          detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
3943
          class Ret = decltype(detail::invoke(std::declval<F>(),
3944
                                              std::declval<Exp>().error())),
3945
          detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
3946
constexpr auto map_error_impl(Exp &&exp, F &&f)
3947
    -> expected<exp_t<Exp>, detail::decay_t<Ret>> {
3948
  using result = expected<exp_t<Exp>, detail::decay_t<Ret>>;
3949
3950
  return exp.has_value()
3951
             ? result(*std::forward<Exp>(exp))
3952
             : result(unexpect, detail::invoke(std::forward<F>(f),
3953
                                               std::forward<Exp>(exp).error()));
3954
}
3955
3956
template <class Exp, class F,
3957
          detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
3958
          class Ret = decltype(detail::invoke(std::declval<F>(),
3959
                                              std::declval<Exp>().error())),
3960
          detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
3961
auto map_error_impl(Exp &&exp, F &&f) -> expected<exp_t<Exp>, monostate> {
3962
  using result = expected<exp_t<Exp>, monostate>;
3963
  if (exp.has_value()) {
3964
    return result(*std::forward<Exp>(exp));
3965
  }
3966
3967
  detail::invoke(std::forward<F>(f), std::forward<Exp>(exp).error());
3968
  return result(unexpect, monostate{});
3969
}
3970
3971
template <class Exp, class F,
3972
          detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
3973
          class Ret = decltype(detail::invoke(std::declval<F>(),
3974
                                              std::declval<Exp>().error())),
3975
          detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
3976
constexpr auto map_error_impl(Exp &&exp, F &&f)
3977
    -> expected<exp_t<Exp>, detail::decay_t<Ret>> {
3978
  using result = expected<exp_t<Exp>, detail::decay_t<Ret>>;
3979
3980
  return exp.has_value()
3981
             ? result()
3982
             : result(unexpect, detail::invoke(std::forward<F>(f),
3983
                                               std::forward<Exp>(exp).error()));
3984
}
3985
3986
template <class Exp, class F,
3987
          detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
3988
          class Ret = decltype(detail::invoke(std::declval<F>(),
3989
                                              std::declval<Exp>().error())),
3990
          detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
3991
auto map_error_impl(Exp &&exp, F &&f) -> expected<exp_t<Exp>, monostate> {
3992
  using result = expected<exp_t<Exp>, monostate>;
3993
  if (exp.has_value()) {
3994
    return result();
3995
  }
3996
3997
  detail::invoke(std::forward<F>(f), std::forward<Exp>(exp).error());
3998
  return result(unexpect, monostate{});
3999
}
4000
#endif
4001
4002
#ifdef TL_EXPECTED_CXX14
4003
template <class Exp, class F,
4004
          class Ret = decltype(detail::invoke(std::declval<F>(),
4005
                                              std::declval<Exp>().error())),
4006
          detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
4007
constexpr auto or_else_impl(Exp &&exp, F &&f) {
4008
  static_assert(detail::is_expected<Ret>::value, "F must return an expected");
4009
  return exp.has_value() ? std::forward<Exp>(exp)
4010
                         : detail::invoke(std::forward<F>(f),
4011
                                          std::forward<Exp>(exp).error());
4012
}
4013
4014
template <class Exp, class F,
4015
          class Ret = decltype(detail::invoke(std::declval<F>(),
4016
                                              std::declval<Exp>().error())),
4017
          detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
4018
detail::decay_t<Exp> or_else_impl(Exp &&exp, F &&f) {
4019
  return exp.has_value() ? std::forward<Exp>(exp)
4020
                         : (detail::invoke(std::forward<F>(f),
4021
                                           std::forward<Exp>(exp).error()),
4022
                            std::forward<Exp>(exp));
4023
}
4024
#else
4025
template <class Exp, class F,
4026
          class Ret = decltype(detail::invoke(std::declval<F>(),
4027
                                              std::declval<Exp>().error())),
4028
          detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
4029
auto or_else_impl(Exp &&exp, F &&f) -> Ret {
4030
  static_assert(detail::is_expected<Ret>::value, "F must return an expected");
4031
  return exp.has_value() ? std::forward<Exp>(exp)
4032
                         : detail::invoke(std::forward<F>(f),
4033
                                          std::forward<Exp>(exp).error());
4034
}
4035
4036
template <class Exp, class F,
4037
          class Ret = decltype(detail::invoke(std::declval<F>(),
4038
                                              std::declval<Exp>().error())),
4039
          detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
4040
detail::decay_t<Exp> or_else_impl(Exp &&exp, F &&f) {
4041
  return exp.has_value() ? std::forward<Exp>(exp)
4042
                         : (detail::invoke(std::forward<F>(f),
4043
                                           std::forward<Exp>(exp).error()),
4044
                            std::forward<Exp>(exp));
4045
}
4046
#endif
4047
}  // namespace detail
4048
4049
template <class T, class E, class U, class F>
4050
constexpr bool operator==(const expected<T, E> &lhs,
4051
                          const expected<U, F> &rhs) {
4052
  return (lhs.has_value() != rhs.has_value())
4053
             ? false
4054
             : (!lhs.has_value() ? lhs.error() == rhs.error() : *lhs == *rhs);
4055
}
4056
template <class T, class E, class U, class F>
4057
constexpr bool operator!=(const expected<T, E> &lhs,
4058
                          const expected<U, F> &rhs) {
4059
  return (lhs.has_value() != rhs.has_value())
4060
             ? true
4061
             : (!lhs.has_value() ? lhs.error() != rhs.error() : *lhs != *rhs);
4062
}
4063
template <class E, class F>
4064
constexpr bool operator==(const expected<void, E> &lhs,
4065
                          const expected<void, F> &rhs) {
4066
  return (lhs.has_value() != rhs.has_value())
4067
             ? false
4068
             : (!lhs.has_value() ? lhs.error() == rhs.error() : true);
4069
}
4070
template <class E, class F>
4071
constexpr bool operator!=(const expected<void, E> &lhs,
4072
                          const expected<void, F> &rhs) {
4073
  return (lhs.has_value() != rhs.has_value())
4074
             ? true
4075
             : (!lhs.has_value() ? lhs.error() == rhs.error() : false);
4076
}
4077
4078
template <class T, class E, class U>
4079
constexpr bool operator==(const expected<T, E> &x, const U &v) {
4080
  return x.has_value() ? *x == v : false;
4081
}
4082
template <class T, class E, class U>
4083
constexpr bool operator==(const U &v, const expected<T, E> &x) {
4084
  return x.has_value() ? *x == v : false;
4085
}
4086
template <class T, class E, class U>
4087
constexpr bool operator!=(const expected<T, E> &x, const U &v) {
4088
  return x.has_value() ? *x != v : true;
4089
}
4090
template <class T, class E, class U>
4091
constexpr bool operator!=(const U &v, const expected<T, E> &x) {
4092
  return x.has_value() ? *x != v : true;
4093
}
4094
4095
template <class T, class E>
4096
constexpr bool operator==(const expected<T, E> &x, const unexpected<E> &e) {
4097
  return x.has_value() ? false : x.error() == e.value();
4098
}
4099
template <class T, class E>
4100
constexpr bool operator==(const unexpected<E> &e, const expected<T, E> &x) {
4101
  return x.has_value() ? false : x.error() == e.value();
4102
}
4103
template <class T, class E>
4104
constexpr bool operator!=(const expected<T, E> &x, const unexpected<E> &e) {
4105
  return x.has_value() ? true : x.error() != e.value();
4106
}
4107
template <class T, class E>
4108
constexpr bool operator!=(const unexpected<E> &e, const expected<T, E> &x) {
4109
  return x.has_value() ? true : x.error() != e.value();
4110
}
4111
4112
template <class T, class E,
4113
          detail::enable_if_t<(std::is_void<T>::value ||
4114
                               std::is_move_constructible<T>::value) &&
4115
                              detail::is_swappable<T>::value &&
4116
                              std::is_move_constructible<E>::value &&
4117
                              detail::is_swappable<E>::value> * = nullptr>
4118
void swap(expected<T, E> &lhs,
4119
          expected<T, E> &rhs) noexcept(noexcept(lhs.swap(rhs))) {
4120
  lhs.swap(rhs);
4121
}
4122
}  // namespace tl
4123
4124
#endif
4125
/* end file include/ada/expected.h */
4126
4127
/* begin file include/ada/url_pattern_regex.h */
4128
/**
4129
 * @file url_search_params.h
4130
 * @brief Declaration for the URL Search Params
4131
 */
4132
#ifndef ADA_URL_PATTERN_REGEX_H
4133
#define ADA_URL_PATTERN_REGEX_H
4134
4135
#include <string>
4136
#include <string_view>
4137
4138
#ifdef ADA_USE_UNSAFE_STD_REGEX_PROVIDER
4139
#include <regex>
4140
#endif  // ADA_USE_UNSAFE_STD_REGEX_PROVIDER
4141
4142
#if ADA_INCLUDE_URL_PATTERN
4143
namespace ada::url_pattern_regex {
4144
4145
template <typename T>
4146
concept regex_concept = requires(T t, std::string_view pattern,
4147
                                 bool ignore_case, std::string_view input) {
4148
  // Ensure the class has a type alias 'regex_type'
4149
  typename T::regex_type;
4150
4151
  // Function to create a regex instance
4152
  {
4153
    T::create_instance(pattern, ignore_case)
4154
  } -> std::same_as<std::optional<typename T::regex_type>>;
4155
4156
  // Function to perform regex search
4157
  {
4158
    T::regex_search(input, std::declval<typename T::regex_type&>())
4159
  } -> std::same_as<std::optional<std::vector<std::optional<std::string>>>>;
4160
4161
  // Function to match regex pattern
4162
  {
4163
    T::regex_match(input, std::declval<typename T::regex_type&>())
4164
  } -> std::same_as<bool>;
4165
4166
  // Copy constructor
4167
  { T(std::declval<const T&>()) } -> std::same_as<T>;
4168
4169
  // Move constructor
4170
  { T(std::declval<T&&>()) } -> std::same_as<T>;
4171
};
4172
4173
#ifdef ADA_USE_UNSAFE_STD_REGEX_PROVIDER
4174
class std_regex_provider final {
4175
 public:
4176
  std_regex_provider() = default;
4177
  using regex_type = std::regex;
4178
  static std::optional<regex_type> create_instance(std::string_view pattern,
4179
                                                   bool ignore_case);
4180
  static std::optional<std::vector<std::optional<std::string>>> regex_search(
4181
      std::string_view input, const regex_type& pattern);
4182
  static bool regex_match(std::string_view input, const regex_type& pattern);
4183
};
4184
#endif  // ADA_USE_UNSAFE_STD_REGEX_PROVIDER
4185
4186
}  // namespace ada::url_pattern_regex
4187
#endif  // ADA_INCLUDE_URL_PATTERN
4188
#endif  // ADA_URL_PATTERN_REGEX_H
4189
/* end file include/ada/url_pattern_regex.h */
4190
/* begin file include/ada/url_pattern_init.h */
4191
/**
4192
 * @file url_pattern_init.h
4193
 * @brief Declaration for the url_pattern_init implementation.
4194
 */
4195
#ifndef ADA_URL_PATTERN_INIT_H
4196
#define ADA_URL_PATTERN_INIT_H
4197
4198
/* begin file include/ada/errors.h */
4199
/**
4200
 * @file errors.h
4201
 * @brief Definitions for the errors.
4202
 */
4203
#ifndef ADA_ERRORS_H
4204
#define ADA_ERRORS_H
4205
4206
#include <cstdint>
4207
namespace ada {
4208
enum class errors : uint8_t { type_error };
4209
}  // namespace ada
4210
#endif  // ADA_ERRORS_H
4211
/* end file include/ada/errors.h */
4212
4213
#include <string_view>
4214
#include <string>
4215
#include <optional>
4216
#include <iostream>
4217
4218
#if ADA_TESTING
4219
#include <iostream>
4220
#endif  // ADA_TESTING
4221
4222
#if ADA_INCLUDE_URL_PATTERN
4223
namespace ada {
4224
4225
// Important: C++20 allows us to use concept rather than `using` or `typedef
4226
// and allows functions with second argument, which is optional (using either
4227
// std::nullopt or a parameter with default value)
4228
template <typename F>
4229
concept url_pattern_encoding_callback = requires(F f, std::string_view sv) {
4230
  { f(sv) } -> std::same_as<tl::expected<std::string, errors>>;
4231
};
4232
4233
// A structure providing matching patterns for individual components
4234
// of a URL. When a URLPattern is created, or when a URLPattern is
4235
// used to match or test against a URL, the input can be given as
4236
// either a string or a URLPatternInit struct. If a string is given,
4237
// it will be parsed to create a URLPatternInit. The URLPatternInit
4238
// API is defined as part of the URLPattern specification.
4239
// All provided strings must be valid UTF-8.
4240
struct url_pattern_init {
4241
  enum class process_type : uint8_t {
4242
    url,
4243
    pattern,
4244
  };
4245
4246
0
  friend std::ostream& operator<<(std::ostream& os, process_type type) {
4247
0
    switch (type) {
4248
0
      case process_type::url:
4249
0
        return os << "url";
4250
0
      case process_type::pattern:
4251
0
        return os << "pattern";
4252
0
      default:
4253
0
        return os << "unknown";
4254
0
    }
4255
0
  }
4256
4257
  // All strings must be valid UTF-8.
4258
  // @see https://urlpattern.spec.whatwg.org/#process-a-urlpatterninit
4259
  static tl::expected<url_pattern_init, errors> process(
4260
      const url_pattern_init& init, process_type type,
4261
      std::optional<std::string_view> protocol = std::nullopt,
4262
      std::optional<std::string_view> username = std::nullopt,
4263
      std::optional<std::string_view> password = std::nullopt,
4264
      std::optional<std::string_view> hostname = std::nullopt,
4265
      std::optional<std::string_view> port = std::nullopt,
4266
      std::optional<std::string_view> pathname = std::nullopt,
4267
      std::optional<std::string_view> search = std::nullopt,
4268
      std::optional<std::string_view> hash = std::nullopt);
4269
4270
  // @see https://urlpattern.spec.whatwg.org/#process-protocol-for-init
4271
  static tl::expected<std::string, errors> process_protocol(
4272
      std::string_view value, process_type type);
4273
4274
  // @see https://urlpattern.spec.whatwg.org/#process-username-for-init
4275
  static tl::expected<std::string, errors> process_username(
4276
      std::string_view value, process_type type);
4277
4278
  // @see https://urlpattern.spec.whatwg.org/#process-password-for-init
4279
  static tl::expected<std::string, errors> process_password(
4280
      std::string_view value, process_type type);
4281
4282
  // @see https://urlpattern.spec.whatwg.org/#process-hostname-for-init
4283
  static tl::expected<std::string, errors> process_hostname(
4284
      std::string_view value, process_type type);
4285
4286
  // @see https://urlpattern.spec.whatwg.org/#process-port-for-init
4287
  static tl::expected<std::string, errors> process_port(
4288
      std::string_view port, std::string_view protocol, process_type type);
4289
4290
  // @see https://urlpattern.spec.whatwg.org/#process-pathname-for-init
4291
  static tl::expected<std::string, errors> process_pathname(
4292
      std::string_view value, std::string_view protocol, process_type type);
4293
4294
  // @see https://urlpattern.spec.whatwg.org/#process-search-for-init
4295
  static tl::expected<std::string, errors> process_search(
4296
      std::string_view value, process_type type);
4297
4298
  // @see https://urlpattern.spec.whatwg.org/#process-hash-for-init
4299
  static tl::expected<std::string, errors> process_hash(std::string_view value,
4300
                                                        process_type type);
4301
4302
#if ADA_TESTING
4303
  friend void PrintTo(const url_pattern_init& init, std::ostream* os) {
4304
    *os << "protocol: '" << init.protocol.value_or("undefined") << "', ";
4305
    *os << "username: '" << init.username.value_or("undefined") << "', ";
4306
    *os << "password: '" << init.password.value_or("undefined") << "', ";
4307
    *os << "hostname: '" << init.hostname.value_or("undefined") << "', ";
4308
    *os << "port: '" << init.port.value_or("undefined") << "', ";
4309
    *os << "pathname: '" << init.pathname.value_or("undefined") << "', ";
4310
    *os << "search: '" << init.search.value_or("undefined") << "', ";
4311
    *os << "hash: '" << init.hash.value_or("undefined") << "', ";
4312
    *os << "base_url: '" << init.base_url.value_or("undefined") << "', ";
4313
  }
4314
#endif  // ADA_TESTING
4315
4316
  bool operator==(const url_pattern_init&) const;
4317
  // If present, must be valid UTF-8.
4318
  std::optional<std::string> protocol{};
4319
  // If present, must be valid UTF-8.
4320
  std::optional<std::string> username{};
4321
  // If present, must be valid UTF-8.
4322
  std::optional<std::string> password{};
4323
  // If present, must be valid UTF-8.
4324
  std::optional<std::string> hostname{};
4325
  // If present, must be valid UTF-8.
4326
  std::optional<std::string> port{};
4327
  // If present, must be valid UTF-8.
4328
  std::optional<std::string> pathname{};
4329
  // If present, must be valid UTF-8.
4330
  std::optional<std::string> search{};
4331
  // If present, must be valid UTF-8.
4332
  std::optional<std::string> hash{};
4333
  // If present, must be valid UTF-8.
4334
  std::optional<std::string> base_url{};
4335
};
4336
}  // namespace ada
4337
#endif  // ADA_INCLUDE_URL_PATTERN
4338
#endif  // ADA_URL_PATTERN_INIT_H
4339
/* end file include/ada/url_pattern_init.h */
4340
4341
/**
4342
 * @private
4343
 */
4344
namespace ada {
4345
struct url_aggregator;
4346
struct url;
4347
#if ADA_INCLUDE_URL_PATTERN
4348
template <url_pattern_regex::regex_concept regex_provider>
4349
class url_pattern;
4350
struct url_pattern_options;
4351
#endif  // ADA_INCLUDE_URL_PATTERN
4352
enum class errors : uint8_t;
4353
}  // namespace ada
4354
4355
/**
4356
 * @namespace ada::parser
4357
 * @brief Includes the definitions for supported parsers
4358
 */
4359
namespace ada::parser {
4360
/**
4361
 * Parses a url. The parameter user_input is the input to be parsed:
4362
 * it should be a valid UTF-8 string. The parameter base_url is an optional
4363
 * parameter that can be used to resolve relative URLs. If the base_url is
4364
 * provided, the user_input is resolved against the base_url.
4365
 */
4366
template <typename result_type = url_aggregator>
4367
result_type parse_url(std::string_view user_input,
4368
                      const result_type* base_url = nullptr);
4369
4370
extern template url_aggregator parse_url<url_aggregator>(
4371
    std::string_view user_input, const url_aggregator* base_url);
4372
extern template url parse_url<url>(std::string_view user_input,
4373
                                   const url* base_url);
4374
4375
template <typename result_type = url_aggregator, bool store_values = true>
4376
result_type parse_url_impl(std::string_view user_input,
4377
                           const result_type* base_url = nullptr);
4378
4379
extern template url_aggregator parse_url_impl<url_aggregator>(
4380
    std::string_view user_input, const url_aggregator* base_url);
4381
extern template url parse_url_impl<url>(std::string_view user_input,
4382
                                        const url* base_url);
4383
4384
#if ADA_INCLUDE_URL_PATTERN
4385
template <url_pattern_regex::regex_concept regex_provider>
4386
tl::expected<url_pattern<regex_provider>, errors> parse_url_pattern_impl(
4387
    std::variant<std::string_view, url_pattern_init>&& input,
4388
    const std::string_view* base_url, const url_pattern_options* options);
4389
#endif  // ADA_INCLUDE_URL_PATTERN
4390
4391
}  // namespace ada::parser
4392
4393
#endif  // ADA_PARSER_H
4394
/* end file include/ada/parser.h */
4395
/* begin file include/ada/parser-inl.h */
4396
/**
4397
 * @file parser-inl.h
4398
 */
4399
#ifndef ADA_PARSER_INL_H
4400
#define ADA_PARSER_INL_H
4401
4402
/* begin file include/ada/url_pattern.h */
4403
/**
4404
 * @file url_pattern.h
4405
 * @brief Declaration for the URLPattern implementation.
4406
 */
4407
#ifndef ADA_URL_PATTERN_H
4408
#define ADA_URL_PATTERN_H
4409
4410
/* begin file include/ada/implementation.h */
4411
/**
4412
 * @file implementation.h
4413
 * @brief Definitions for user facing functions for parsing URL and it's
4414
 * components.
4415
 */
4416
#ifndef ADA_IMPLEMENTATION_H
4417
#define ADA_IMPLEMENTATION_H
4418
4419
#include <string>
4420
#include <string_view>
4421
#include <optional>
4422
4423
/* begin file include/ada/url.h */
4424
/**
4425
 * @file url.h
4426
 * @brief Declaration for the URL
4427
 */
4428
#ifndef ADA_URL_H
4429
#define ADA_URL_H
4430
4431
#include <algorithm>
4432
#include <optional>
4433
#include <ostream>
4434
#include <string>
4435
#include <string_view>
4436
4437
/* begin file include/ada/checkers.h */
4438
/**
4439
 * @file checkers.h
4440
 * @brief Declarations for URL specific checkers used within Ada.
4441
 */
4442
#ifndef ADA_CHECKERS_H
4443
#define ADA_CHECKERS_H
4444
4445
4446
#include <cstring>
4447
#include <string_view>
4448
4449
/**
4450
 * These functions are not part of our public API and may
4451
 * change at any time.
4452
 * @private
4453
 * @namespace ada::checkers
4454
 * @brief Includes the definitions for validation functions
4455
 */
4456
namespace ada::checkers {
4457
4458
/**
4459
 * @private
4460
 * Assuming that x is an ASCII letter, this function returns the lower case
4461
 * equivalent.
4462
 * @details More likely to be inlined by the compiler and constexpr.
4463
 */
4464
constexpr char to_lower(char x) noexcept;
4465
4466
/**
4467
 * @private
4468
 * Returns true if the character is an ASCII letter. Equivalent to std::isalpha
4469
 * but more likely to be inlined by the compiler.
4470
 *
4471
 * @attention std::isalpha is not constexpr generally.
4472
 */
4473
constexpr bool is_alpha(char x) noexcept;
4474
4475
/**
4476
 * @private
4477
 * Check whether a string starts with 0x or 0X. The function is only
4478
 * safe if input.size() >=2.
4479
 *
4480
 * @see has_hex_prefix
4481
 */
4482
constexpr bool has_hex_prefix_unsafe(std::string_view input);
4483
/**
4484
 * @private
4485
 * Check whether a string starts with 0x or 0X.
4486
 */
4487
constexpr bool has_hex_prefix(std::string_view input);
4488
4489
/**
4490
 * @private
4491
 * Check whether x is an ASCII digit. More likely to be inlined than
4492
 * std::isdigit.
4493
 */
4494
constexpr bool is_digit(char x) noexcept;
4495
4496
/**
4497
 * @private
4498
 * @details A string starts with a Windows drive letter if all of the following
4499
 * are true:
4500
 *
4501
 *   - its length is greater than or equal to 2
4502
 *   - its first two code points are a Windows drive letter
4503
 *   - its length is 2 or its third code point is U+002F (/), U+005C (\), U+003F
4504
 * (?), or U+0023 (#).
4505
 *
4506
 * https://url.spec.whatwg.org/#start-with-a-windows-drive-letter
4507
 */
4508
inline constexpr bool is_windows_drive_letter(std::string_view input) noexcept;
4509
4510
/**
4511
 * @private
4512
 * @details A normalized Windows drive letter is a Windows drive letter of which
4513
 * the second code point is U+003A (:).
4514
 */
4515
inline constexpr bool is_normalized_windows_drive_letter(
4516
    std::string_view input) noexcept;
4517
4518
/**
4519
 * @private
4520
 * Returns true if an input is an ipv4 address. It is assumed that the string
4521
 * does not contain uppercase ASCII characters (the input should have been
4522
 * lowered cased before calling this function) and is not empty.
4523
 */
4524
ada_really_inline constexpr bool is_ipv4(std::string_view view) noexcept;
4525
4526
/**
4527
 * @private
4528
 * Returns a bitset. If the first bit is set, then at least one character needs
4529
 * percent encoding. If the second bit is set, a \\ is found. If the third bit
4530
 * is set then we have a dot. If the fourth bit is set, then we have a percent
4531
 * character.
4532
 */
4533
ada_really_inline constexpr uint8_t path_signature(
4534
    std::string_view input) noexcept;
4535
4536
/**
4537
 * @private
4538
 * Returns true if the length of the domain name and its labels are according to
4539
 * the specifications. The length of the domain must be 255 octets (253
4540
 * characters not including the last 2 which are the empty label reserved at the
4541
 * end). When the empty label is included (a dot at the end), the domain name
4542
 * can have 254 characters. The length of a label must be at least 1 and at most
4543
 * 63 characters.
4544
 * @see section 3.1. of https://www.rfc-editor.org/rfc/rfc1034
4545
 * @see https://www.unicode.org/reports/tr46/#ToASCII
4546
 */
4547
ada_really_inline constexpr bool verify_dns_length(
4548
    std::string_view input) noexcept;
4549
4550
}  // namespace ada::checkers
4551
4552
#endif  // ADA_CHECKERS_H
4553
/* end file include/ada/checkers.h */
4554
/* begin file include/ada/url_components.h */
4555
/**
4556
 * @file url_components.h
4557
 * @brief Declaration for the URL Components
4558
 */
4559
#ifndef ADA_URL_COMPONENTS_H
4560
#define ADA_URL_COMPONENTS_H
4561
4562
namespace ada {
4563
4564
/**
4565
 * @brief URL Component representations using offsets.
4566
 *
4567
 * @details We design the url_components struct so that it is as small
4568
 * and simple as possible. This version uses 32 bytes.
4569
 *
4570
 * This struct is used to extract components from a single 'href'.
4571
 */
4572
struct url_components {
4573
  constexpr static uint32_t omitted = uint32_t(-1);
4574
4575
21.4k
  url_components() = default;
4576
  url_components(const url_components &u) = default;
4577
  url_components(url_components &&u) noexcept = default;
4578
  url_components &operator=(url_components &&u) noexcept = default;
4579
  url_components &operator=(const url_components &u) = default;
4580
  ~url_components() = default;
4581
4582
  /*
4583
   * By using 32-bit integers, we implicitly assume that the URL string
4584
   * cannot exceed 4 GB.
4585
   *
4586
   * https://user:pass@example.com:1234/foo/bar?baz#quux
4587
   *       |     |    |          | ^^^^|       |   |
4588
   *       |     |    |          | |   |       |   `----- hash_start
4589
   *       |     |    |          | |   |       `--------- search_start
4590
   *       |     |    |          | |   `----------------- pathname_start
4591
   *       |     |    |          | `--------------------- port
4592
   *       |     |    |          `----------------------- host_end
4593
   *       |     |    `---------------------------------- host_start
4594
   *       |     `--------------------------------------- username_end
4595
   *       `--------------------------------------------- protocol_end
4596
   */
4597
  uint32_t protocol_end{0};
4598
  /**
4599
   * Username end is not `omitted` by default to make username and password
4600
   * getters less costly to implement.
4601
   */
4602
  uint32_t username_end{0};
4603
  uint32_t host_start{0};
4604
  uint32_t host_end{0};
4605
  uint32_t port{omitted};
4606
  uint32_t pathname_start{0};
4607
  uint32_t search_start{omitted};
4608
  uint32_t hash_start{omitted};
4609
4610
  /**
4611
   * Check the following conditions:
4612
   * protocol_end < username_end < ... < hash_start,
4613
   * expect when a value is omitted. It also computes
4614
   * a lower bound on  the possible string length that may match these
4615
   * offsets.
4616
   * @return true if the offset values are
4617
   *  consistent with a possible URL string
4618
   */
4619
  [[nodiscard]] constexpr bool check_offset_consistency() const noexcept;
4620
4621
  /**
4622
   * Converts a url_components to JSON stringified version.
4623
   */
4624
  [[nodiscard]] std::string to_string() const;
4625
4626
};  // struct url_components
4627
}  // namespace ada
4628
#endif
4629
/* end file include/ada/url_components.h */
4630
4631
namespace ada {
4632
4633
struct url_aggregator;
4634
4635
// namespace parser {
4636
// template <typename result_type>
4637
// result_type parse_url(std::string_view user_input,
4638
//                       const result_type* base_url = nullptr);
4639
// template <typename result_type, bool store_values>
4640
// result_type parse_url_impl(std::string_view user_input,
4641
//                            const result_type* base_url = nullptr);
4642
// }
4643
4644
/**
4645
 * @brief Generic URL struct reliant on std::string instantiation.
4646
 *
4647
 * @details To disambiguate from a valid URL string it can also be referred to
4648
 * as a URL record. A URL is a struct that represents a universal identifier.
4649
 * Unlike the url_aggregator, the ada::url represents the different components
4650
 * of a parsed URL as independent std::string instances. This makes the
4651
 * structure heavier and more reliant on memory allocations. When getting
4652
 * components from the parsed URL, a new std::string is typically constructed.
4653
 *
4654
 * @see https://url.spec.whatwg.org/#url-representation
4655
 */
4656
struct url : url_base {
4657
21.4k
  url() = default;
4658
  url(const url &u) = default;
4659
15.4k
  url(url &&u) noexcept = default;
4660
  url &operator=(url &&u) noexcept = default;
4661
3.05k
  url &operator=(const url &u) = default;
4662
36.9k
  ~url() override = default;
4663
4664
  /**
4665
   * @private
4666
   * A URL's username is an ASCII string identifying a username. It is initially
4667
   * the empty string.
4668
   */
4669
  std::string username{};
4670
4671
  /**
4672
   * @private
4673
   * A URL's password is an ASCII string identifying a password. It is initially
4674
   * the empty string.
4675
   */
4676
  std::string password{};
4677
4678
  /**
4679
   * @private
4680
   * A URL's host is null or a host. It is initially null.
4681
   */
4682
  std::optional<std::string> host{};
4683
4684
  /**
4685
   * @private
4686
   * A URL's port is either null or a 16-bit unsigned integer that identifies a
4687
   * networking port. It is initially null.
4688
   */
4689
  std::optional<uint16_t> port{};
4690
4691
  /**
4692
   * @private
4693
   * A URL's path is either an ASCII string or a list of zero or more ASCII
4694
   * strings, usually identifying a location.
4695
   */
4696
  std::string path{};
4697
4698
  /**
4699
   * @private
4700
   * A URL's query is either null or an ASCII string. It is initially null.
4701
   */
4702
  std::optional<std::string> query{};
4703
4704
  /**
4705
   * @private
4706
   * A URL's fragment is either null or an ASCII string that can be used for
4707
   * further processing on the resource the URL's other components identify. It
4708
   * is initially null.
4709
   */
4710
  std::optional<std::string> hash{};
4711
4712
  /** @return true if it has an host but it is the empty string */
4713
  [[nodiscard]] inline bool has_empty_hostname() const noexcept;
4714
  /** @return true if the URL has a (non default) port */
4715
  [[nodiscard]] inline bool has_port() const noexcept;
4716
  /** @return true if it has a host (included an empty host) */
4717
  [[nodiscard]] inline bool has_hostname() const noexcept;
4718
  [[nodiscard]] bool has_valid_domain() const noexcept override;
4719
4720
  /**
4721
   * Returns a JSON string representation of this URL.
4722
   */
4723
  [[nodiscard]] std::string to_string() const override;
4724
4725
  /**
4726
   * @see https://url.spec.whatwg.org/#dom-url-href
4727
   * @see https://url.spec.whatwg.org/#concept-url-serializer
4728
   */
4729
  [[nodiscard]] ada_really_inline std::string get_href() const noexcept;
4730
4731
  /**
4732
   * The origin getter steps are to return the serialization of this's URL's
4733
   * origin. [HTML]
4734
   * @return a newly allocated string.
4735
   * @see https://url.spec.whatwg.org/#concept-url-origin
4736
   */
4737
  [[nodiscard]] std::string get_origin() const noexcept override;
4738
4739
  /**
4740
   * The protocol getter steps are to return this's URL's scheme, followed by
4741
   * U+003A (:).
4742
   * @return a newly allocated string.
4743
   * @see https://url.spec.whatwg.org/#dom-url-protocol
4744
   */
4745
  [[nodiscard]] std::string get_protocol() const noexcept;
4746
4747
  /**
4748
   * Return url's host, serialized, followed by U+003A (:) and url's port,
4749
   * serialized.
4750
   * When there is no host, this function returns the empty string.
4751
   * @return a newly allocated string.
4752
   * @see https://url.spec.whatwg.org/#dom-url-host
4753
   */
4754
  [[nodiscard]] std::string get_host() const noexcept;
4755
4756
  /**
4757
   * Return this's URL's host, serialized.
4758
   * When there is no host, this function returns the empty string.
4759
   * @return a newly allocated string.
4760
   * @see https://url.spec.whatwg.org/#dom-url-hostname
4761
   */
4762
  [[nodiscard]] std::string get_hostname() const noexcept;
4763
4764
  /**
4765
   * The pathname getter steps are to return the result of URL path serializing
4766
   * this's URL.
4767
   * @return a newly allocated string.
4768
   * @see https://url.spec.whatwg.org/#dom-url-pathname
4769
   */
4770
  [[nodiscard]] constexpr std::string_view get_pathname() const noexcept;
4771
4772
  /**
4773
   * Compute the pathname length in bytes without instantiating a view or a
4774
   * string.
4775
   * @return size of the pathname in bytes
4776
   * @see https://url.spec.whatwg.org/#dom-url-pathname
4777
   */
4778
  [[nodiscard]] ada_really_inline size_t get_pathname_length() const noexcept;
4779
4780
  /**
4781
   * Return U+003F (?), followed by this's URL's query.
4782
   * @return a newly allocated string.
4783
   * @see https://url.spec.whatwg.org/#dom-url-search
4784
   */
4785
  [[nodiscard]] std::string get_search() const noexcept;
4786
4787
  /**
4788
   * The username getter steps are to return this's URL's username.
4789
   * @return a constant reference to the underlying string.
4790
   * @see https://url.spec.whatwg.org/#dom-url-username
4791
   */
4792
  [[nodiscard]] const std::string &get_username() const noexcept;
4793
4794
  /**
4795
   * @return Returns true on successful operation.
4796
   * @see https://url.spec.whatwg.org/#dom-url-username
4797
   */
4798
  bool set_username(std::string_view input);
4799
4800
  /**
4801
   * @return Returns true on success.
4802
   * @see https://url.spec.whatwg.org/#dom-url-password
4803
   */
4804
  bool set_password(std::string_view input);
4805
4806
  /**
4807
   * @return Returns true on success.
4808
   * @see https://url.spec.whatwg.org/#dom-url-port
4809
   */
4810
  bool set_port(std::string_view input);
4811
4812
  /**
4813
   * This function always succeeds.
4814
   * @see https://url.spec.whatwg.org/#dom-url-hash
4815
   */
4816
  void set_hash(std::string_view input);
4817
4818
  /**
4819
   * This function always succeeds.
4820
   * @see https://url.spec.whatwg.org/#dom-url-search
4821
   */
4822
  void set_search(std::string_view input);
4823
4824
  /**
4825
   * @return Returns true on success.
4826
   * @see https://url.spec.whatwg.org/#dom-url-search
4827
   */
4828
  bool set_pathname(std::string_view input);
4829
4830
  /**
4831
   * @return Returns true on success.
4832
   * @see https://url.spec.whatwg.org/#dom-url-host
4833
   */
4834
  bool set_host(std::string_view input);
4835
4836
  /**
4837
   * @return Returns true on success.
4838
   * @see https://url.spec.whatwg.org/#dom-url-hostname
4839
   */
4840
  bool set_hostname(std::string_view input);
4841
4842
  /**
4843
   * @return Returns true on success.
4844
   * @see https://url.spec.whatwg.org/#dom-url-protocol
4845
   */
4846
  bool set_protocol(std::string_view input);
4847
4848
  /**
4849
   * @see https://url.spec.whatwg.org/#dom-url-href
4850
   */
4851
  bool set_href(std::string_view input);
4852
4853
  /**
4854
   * The password getter steps are to return this's URL's password.
4855
   * @return a constant reference to the underlying string.
4856
   * @see https://url.spec.whatwg.org/#dom-url-password
4857
   */
4858
  [[nodiscard]] const std::string &get_password() const noexcept;
4859
4860
  /**
4861
   * Return this's URL's port, serialized.
4862
   * @return a newly constructed string representing the port.
4863
   * @see https://url.spec.whatwg.org/#dom-url-port
4864
   */
4865
  [[nodiscard]] std::string get_port() const noexcept;
4866
4867
  /**
4868
   * Return U+0023 (#), followed by this's URL's fragment.
4869
   * @return a newly constructed string representing the hash.
4870
   * @see https://url.spec.whatwg.org/#dom-url-hash
4871
   */
4872
  [[nodiscard]] std::string get_hash() const noexcept;
4873
4874
  /**
4875
   * A URL includes credentials if its username or password is not the empty
4876
   * string.
4877
   */
4878
  [[nodiscard]] ada_really_inline bool has_credentials() const noexcept;
4879
4880
  /**
4881
   * Useful for implementing efficient serialization for the URL.
4882
   *
4883
   * https://user:pass@example.com:1234/foo/bar?baz#quux
4884
   *       |     |    |          | ^^^^|       |   |
4885
   *       |     |    |          | |   |       |   `----- hash_start
4886
   *       |     |    |          | |   |       `--------- search_start
4887
   *       |     |    |          | |   `----------------- pathname_start
4888
   *       |     |    |          | `--------------------- port
4889
   *       |     |    |          `----------------------- host_end
4890
   *       |     |    `---------------------------------- host_start
4891
   *       |     `--------------------------------------- username_end
4892
   *       `--------------------------------------------- protocol_end
4893
   *
4894
   * Inspired after servo/url
4895
   *
4896
   * @return a newly constructed component.
4897
   *
4898
   * @see
4899
   * https://github.com/servo/rust-url/blob/b65a45515c10713f6d212e6726719a020203cc98/url/src/quirks.rs#L31
4900
   */
4901
  [[nodiscard]] ada_really_inline ada::url_components get_components()
4902
      const noexcept;
4903
  /** @return true if the URL has a hash component */
4904
  [[nodiscard]] constexpr bool has_hash() const noexcept override;
4905
  /** @return true if the URL has a search component */
4906
  [[nodiscard]] constexpr bool has_search() const noexcept override;
4907
4908
 private:
4909
  friend ada::url ada::parser::parse_url<ada::url>(std::string_view,
4910
                                                   const ada::url *);
4911
  friend ada::url_aggregator ada::parser::parse_url<ada::url_aggregator>(
4912
      std::string_view, const ada::url_aggregator *);
4913
  friend void ada::helpers::strip_trailing_spaces_from_opaque_path<ada::url>(
4914
      ada::url &url) noexcept;
4915
4916
  friend ada::url ada::parser::parse_url_impl<ada::url, true>(std::string_view,
4917
                                                              const ada::url *);
4918
  friend ada::url_aggregator ada::parser::parse_url_impl<
4919
      ada::url_aggregator, true>(std::string_view, const ada::url_aggregator *);
4920
4921
  inline void update_unencoded_base_hash(std::string_view input);
4922
  inline void update_base_hostname(std::string_view input);
4923
  inline void update_base_search(std::string_view input,
4924
                                 const uint8_t query_percent_encode_set[]);
4925
  inline void update_base_search(std::optional<std::string> &&input);
4926
  inline void update_base_pathname(std::string_view input);
4927
  inline void update_base_username(std::string_view input);
4928
  inline void update_base_password(std::string_view input);
4929
  inline void update_base_port(std::optional<uint16_t> input);
4930
4931
  /**
4932
   * Sets the host or hostname according to override condition.
4933
   * Return true on success.
4934
   * @see https://url.spec.whatwg.org/#hostname-state
4935
   */
4936
  template <bool override_hostname = false>
4937
  bool set_host_or_hostname(std::string_view input);
4938
4939
  /**
4940
   * Return true on success.
4941
   * @see https://url.spec.whatwg.org/#concept-ipv4-parser
4942
   */
4943
  [[nodiscard]] bool parse_ipv4(std::string_view input);
4944
4945
  /**
4946
   * Return true on success.
4947
   * @see https://url.spec.whatwg.org/#concept-ipv6-parser
4948
   */
4949
  [[nodiscard]] bool parse_ipv6(std::string_view input);
4950
4951
  /**
4952
   * Return true on success.
4953
   * @see https://url.spec.whatwg.org/#concept-opaque-host-parser
4954
   */
4955
  [[nodiscard]] bool parse_opaque_host(std::string_view input);
4956
4957
  /**
4958
   * A URL's scheme is an ASCII string that identifies the type of URL and can
4959
   * be used to dispatch a URL for further processing after parsing. It is
4960
   * initially the empty string. We only set non_special_scheme when the scheme
4961
   * is non-special, otherwise we avoid constructing string.
4962
   *
4963
   * Special schemes are stored in ada::scheme::details::is_special_list so we
4964
   * typically do not need to store them in each url instance.
4965
   */
4966
  std::string non_special_scheme{};
4967
4968
  /**
4969
   * A URL cannot have a username/password/port if its host is null or the empty
4970
   * string, or its scheme is "file".
4971
   */
4972
  [[nodiscard]] inline bool cannot_have_credentials_or_port() const;
4973
4974
  ada_really_inline size_t parse_port(
4975
      std::string_view view, bool check_trailing_content) noexcept override;
4976
4977
1.47k
  ada_really_inline size_t parse_port(std::string_view view) noexcept override {
4978
1.47k
    return this->parse_port(view, false);
4979
1.47k
  }
4980
4981
  /**
4982
   * Parse the host from the provided input. We assume that
4983
   * the input does not contain spaces or tabs. Control
4984
   * characters and spaces are not trimmed (they should have
4985
   * been removed if needed).
4986
   * Return true on success.
4987
   * @see https://url.spec.whatwg.org/#host-parsing
4988
   */
4989
  [[nodiscard]] ada_really_inline bool parse_host(std::string_view input);
4990
4991
  template <bool has_state_override = false>
4992
  [[nodiscard]] ada_really_inline bool parse_scheme(std::string_view input);
4993
4994
  constexpr void clear_pathname() override;
4995
  constexpr void clear_search() override;
4996
  constexpr void set_protocol_as_file();
4997
4998
  /**
4999
   * Parse the path from the provided input.
5000
   * Return true on success. Control characters not
5001
   * trimmed from the ends (they should have
5002
   * been removed if needed).
5003
   *
5004
   * The input is expected to be UTF-8.
5005
   *
5006
   * @see https://url.spec.whatwg.org/
5007
   */
5008
  ada_really_inline void parse_path(std::string_view input);
5009
5010
  /**
5011
   * Set the scheme for this URL. The provided scheme should be a valid
5012
   * scheme string, be lower-cased, not contain spaces or tabs. It should
5013
   * have no spurious trailing or leading content.
5014
   */
5015
  inline void set_scheme(std::string &&new_scheme) noexcept;
5016
5017
  /**
5018
   * Take the scheme from another URL. The scheme string is moved from the
5019
   * provided url.
5020
   */
5021
  constexpr void copy_scheme(ada::url &&u) noexcept;
5022
5023
  /**
5024
   * Take the scheme from another URL. The scheme string is copied from the
5025
   * provided url.
5026
   */
5027
  constexpr void copy_scheme(const ada::url &u);
5028
5029
};  // struct url
5030
5031
inline std::ostream &operator<<(std::ostream &out, const ada::url &u);
5032
}  // namespace ada
5033
5034
#endif  // ADA_URL_H
5035
/* end file include/ada/url.h */
5036
5037
namespace ada {
5038
5039
template <class result_type = ada::url_aggregator>
5040
using result = tl::expected<result_type, ada::errors>;
5041
5042
/**
5043
 * The URL parser takes a scalar value string input, with an optional null or
5044
 * base URL base (default null). The parser assumes the input is a valid ASCII
5045
 * or UTF-8 string.
5046
 *
5047
 * @param input the string input to analyze (must be valid ASCII or UTF-8)
5048
 * @param base_url the optional URL input to use as a base url.
5049
 * @return a parsed URL.
5050
 */
5051
template <class result_type = ada::url_aggregator>
5052
ada_warn_unused ada::result<result_type> parse(
5053
    std::string_view input, const result_type* base_url = nullptr);
5054
5055
extern template ada::result<url> parse<url>(std::string_view input,
5056
                                            const url* base_url);
5057
extern template ada::result<url_aggregator> parse<url_aggregator>(
5058
    std::string_view input, const url_aggregator* base_url);
5059
5060
/**
5061
 * Verifies whether the URL strings can be parsed. The function assumes
5062
 * that the inputs are valid ASCII or UTF-8 strings.
5063
 * @see https://url.spec.whatwg.org/#dom-url-canparse
5064
 * @return If URL can be parsed or not.
5065
 */
5066
bool can_parse(std::string_view input,
5067
               const std::string_view* base_input = nullptr);
5068
5069
#if ADA_INCLUDE_URL_PATTERN
5070
/**
5071
 * Implementation of the URL pattern parsing algorithm.
5072
 * @see https://urlpattern.spec.whatwg.org
5073
 *
5074
 * @param input valid UTF-8 string or URLPatternInit struct
5075
 * @param base_url an optional valid UTF-8 string
5076
 * @param options an optional url_pattern_options struct
5077
 * @return url_pattern instance
5078
 */
5079
template <url_pattern_regex::regex_concept regex_provider>
5080
ada_warn_unused tl::expected<url_pattern<regex_provider>, errors>
5081
parse_url_pattern(std::variant<std::string_view, url_pattern_init>&& input,
5082
                  const std::string_view* base_url = nullptr,
5083
                  const url_pattern_options* options = nullptr);
5084
#endif  // ADA_INCLUDE_URL_PATTERN
5085
5086
/**
5087
 * Computes a href string from a file path. The function assumes
5088
 * that the input is a valid ASCII or UTF-8 string.
5089
 * @return a href string (starts with file:://)
5090
 */
5091
std::string href_from_file(std::string_view path);
5092
}  // namespace ada
5093
5094
#endif  // ADA_IMPLEMENTATION_H
5095
/* end file include/ada/implementation.h */
5096
5097
#include <ostream>
5098
#include <string>
5099
#include <string_view>
5100
#include <unordered_map>
5101
#include <variant>
5102
#include <vector>
5103
5104
#if ADA_TESTING
5105
#include <iostream>
5106
#endif  // ADA_TESTING
5107
5108
#if ADA_INCLUDE_URL_PATTERN
5109
namespace ada {
5110
5111
enum class url_pattern_part_type : uint8_t {
5112
  // The part represents a simple fixed text string.
5113
  FIXED_TEXT,
5114
  // The part represents a matching group with a custom regular expression.
5115
  REGEXP,
5116
  // The part represents a matching group that matches code points up to the
5117
  // next separator code point. This is typically used for a named group like
5118
  // ":foo" that does not have a custom regular expression.
5119
  SEGMENT_WILDCARD,
5120
  // The part represents a matching group that greedily matches all code points.
5121
  // This is typically used for the "*" wildcard matching group.
5122
  FULL_WILDCARD,
5123
};
5124
5125
enum class url_pattern_part_modifier : uint8_t {
5126
  // The part does not have a modifier.
5127
  none,
5128
  // The part has an optional modifier indicated by the U+003F (?) code point.
5129
  optional,
5130
  // The part has a "zero or more" modifier indicated by the U+002A (*) code
5131
  // point.
5132
  zero_or_more,
5133
  // The part has a "one or more" modifier indicated by the U+002B (+) code
5134
  // point.
5135
  one_or_more,
5136
};
5137
5138
// @see https://urlpattern.spec.whatwg.org/#part
5139
class url_pattern_part {
5140
 public:
5141
  url_pattern_part(url_pattern_part_type _type, std::string&& _value,
5142
                   url_pattern_part_modifier _modifier)
5143
0
      : type(_type), value(std::move(_value)), modifier(_modifier) {}
5144
5145
  url_pattern_part(url_pattern_part_type _type, std::string&& _value,
5146
                   url_pattern_part_modifier _modifier, std::string&& _name,
5147
                   std::string&& _prefix, std::string&& _suffix)
5148
      : type(_type),
5149
        value(std::move(_value)),
5150
        modifier(_modifier),
5151
        name(std::move(_name)),
5152
        prefix(std::move(_prefix)),
5153
0
        suffix(std::move(_suffix)) {}
5154
  // A part has an associated type, a string, which must be set upon creation.
5155
  url_pattern_part_type type;
5156
  // A part has an associated value, a string, which must be set upon creation.
5157
  std::string value;
5158
  // A part has an associated modifier a string, which must be set upon
5159
  // creation.
5160
  url_pattern_part_modifier modifier;
5161
  // A part has an associated name, a string, initially the empty string.
5162
  std::string name{};
5163
  // A part has an associated prefix, a string, initially the empty string.
5164
  std::string prefix{};
5165
  // A part has an associated suffix, a string, initially the empty string.
5166
  std::string suffix{};
5167
5168
  inline bool is_regexp() const noexcept;
5169
};
5170
5171
// @see https://urlpattern.spec.whatwg.org/#options-header
5172
struct url_pattern_compile_component_options {
5173
  url_pattern_compile_component_options() = default;
5174
  explicit url_pattern_compile_component_options(
5175
      std::optional<char> new_delimiter = std::nullopt,
5176
      std::optional<char> new_prefix = std::nullopt)
5177
6
      : delimiter(new_delimiter), prefix(new_prefix) {}
5178
5179
  inline std::string_view get_delimiter() const ada_warn_unused;
5180
  inline std::string_view get_prefix() const ada_warn_unused;
5181
5182
  // @see https://urlpattern.spec.whatwg.org/#options-ignore-case
5183
  bool ignore_case = false;
5184
5185
  static url_pattern_compile_component_options DEFAULT;
5186
  static url_pattern_compile_component_options HOSTNAME;
5187
  static url_pattern_compile_component_options PATHNAME;
5188
5189
 private:
5190
  // @see https://urlpattern.spec.whatwg.org/#options-delimiter-code-point
5191
  std::optional<char> delimiter{};
5192
  // @see https://urlpattern.spec.whatwg.org/#options-prefix-code-point
5193
  std::optional<char> prefix{};
5194
};
5195
5196
// The default options is an options struct with delimiter code point set to
5197
// the empty string and prefix code point set to the empty string.
5198
inline url_pattern_compile_component_options
5199
    url_pattern_compile_component_options::DEFAULT(std::nullopt, std::nullopt);
5200
5201
// The hostname options is an options struct with delimiter code point set
5202
// "." and prefix code point set to the empty string.
5203
inline url_pattern_compile_component_options
5204
    url_pattern_compile_component_options::HOSTNAME('.', std::nullopt);
5205
5206
// The pathname options is an options struct with delimiter code point set
5207
// "/" and prefix code point set to "/".
5208
inline url_pattern_compile_component_options
5209
    url_pattern_compile_component_options::PATHNAME('/', '/');
5210
5211
// A struct providing the URLPattern matching results for a single
5212
// URL component. The URLPatternComponentResult is only ever used
5213
// as a member attribute of a URLPatternResult struct. The
5214
// URLPatternComponentResult API is defined as part of the URLPattern
5215
// specification.
5216
struct url_pattern_component_result {
5217
  std::string input;
5218
  std::unordered_map<std::string, std::optional<std::string>> groups;
5219
5220
  bool operator==(const url_pattern_component_result&) const;
5221
5222
#if ADA_TESTING
5223
  friend void PrintTo(const url_pattern_component_result& result,
5224
                      std::ostream* os) {
5225
    *os << "input: '" << result.input << "', group: ";
5226
    for (const auto& group : result.groups) {
5227
      *os << "(" << group.first << ", " << group.second.value_or("undefined")
5228
          << ") ";
5229
    }
5230
  }
5231
#endif  // ADA_TESTING
5232
};
5233
5234
template <url_pattern_regex::regex_concept regex_provider>
5235
class url_pattern_component {
5236
 public:
5237
  url_pattern_component() = default;
5238
5239
  // This function explicitly takes a std::string because it is moved.
5240
  // To avoid unnecessary copy, move each value while calling the constructor.
5241
  url_pattern_component(std::string&& new_pattern,
5242
                        typename regex_provider::regex_type&& new_regexp,
5243
                        std::vector<std::string>&& new_group_name_list,
5244
                        bool new_has_regexp_groups)
5245
      : regexp(std::move(new_regexp)),
5246
        pattern(std::move(new_pattern)),
5247
        group_name_list(std::move(new_group_name_list)),
5248
        has_regexp_groups(new_has_regexp_groups) {}
5249
5250
  // @see https://urlpattern.spec.whatwg.org/#compile-a-component
5251
  template <url_pattern_encoding_callback F>
5252
  static tl::expected<url_pattern_component, errors> compile(
5253
      std::string_view input, F& encoding_callback,
5254
      url_pattern_compile_component_options& options);
5255
5256
  // @see https://urlpattern.spec.whatwg.org/#create-a-component-match-result
5257
  url_pattern_component_result create_component_match_result(
5258
      std::string&& input,
5259
      std::vector<std::optional<std::string>>&& exec_result);
5260
5261
#if ADA_TESTING
5262
  friend void PrintTo(const url_pattern_component& component,
5263
                      std::ostream* os) {
5264
    *os << "pattern: '" << component.pattern
5265
        << "', has_regexp_groups: " << component.has_regexp_groups
5266
        << "group_name_list: ";
5267
    for (const auto& name : component.group_name_list) {
5268
      *os << name << ", ";
5269
    }
5270
  }
5271
#endif  // ADA_TESTING
5272
5273
  typename regex_provider::regex_type regexp{};
5274
  std::string pattern{};
5275
  std::vector<std::string> group_name_list{};
5276
  bool has_regexp_groups = false;
5277
};
5278
5279
// A URLPattern input can be either a string or a URLPatternInit object.
5280
// If it is a string, it must be a valid UTF-8 string.
5281
using url_pattern_input = std::variant<std::string_view, url_pattern_init>;
5282
5283
// A struct providing the URLPattern matching results for all
5284
// components of a URL. The URLPatternResult API is defined as
5285
// part of the URLPattern specification.
5286
struct url_pattern_result {
5287
  std::vector<url_pattern_input> inputs;
5288
  url_pattern_component_result protocol;
5289
  url_pattern_component_result username;
5290
  url_pattern_component_result password;
5291
  url_pattern_component_result hostname;
5292
  url_pattern_component_result port;
5293
  url_pattern_component_result pathname;
5294
  url_pattern_component_result search;
5295
  url_pattern_component_result hash;
5296
};
5297
5298
struct url_pattern_options {
5299
  bool ignore_case = false;
5300
5301
#if ADA_TESTING
5302
  friend void PrintTo(const url_pattern_options& options, std::ostream* os) {
5303
    *os << "ignore_case: '" << options.ignore_case;
5304
  }
5305
#endif  // ADA_TESTING
5306
};
5307
5308
// URLPattern is a Web Platform standard API for matching URLs against a
5309
// pattern syntax (think of it as a regular expression for URLs). It is
5310
// defined in https://wicg.github.io/urlpattern.
5311
// More information about the URL Pattern syntax can be found at
5312
// https://developer.mozilla.org/en-US/docs/Web/API/URL_Pattern_API
5313
//
5314
// We require all strings to be valid UTF-8: it is the user's responsibility
5315
// to ensure that the provided strings are valid UTF-8.
5316
template <url_pattern_regex::regex_concept regex_provider>
5317
class url_pattern {
5318
 public:
5319
  url_pattern() = default;
5320
5321
  /**
5322
   * If non-null, base_url must pointer at a valid UTF-8 string.
5323
   * @see https://urlpattern.spec.whatwg.org/#dom-urlpattern-exec
5324
   */
5325
  result<std::optional<url_pattern_result>> exec(
5326
      const url_pattern_input& input,
5327
      const std::string_view* base_url = nullptr);
5328
5329
  /**
5330
   * If non-null, base_url must pointer at a valid UTF-8 string.
5331
   * @see https://urlpattern.spec.whatwg.org/#dom-urlpattern-test
5332
   */
5333
  result<bool> test(const url_pattern_input& input,
5334
                    const std::string_view* base_url = nullptr);
5335
5336
  /**
5337
   * @see https://urlpattern.spec.whatwg.org/#url-pattern-match
5338
   * This function expects a valid UTF-8 string if input is a string.
5339
   */
5340
  result<std::optional<url_pattern_result>> match(
5341
      const url_pattern_input& input,
5342
      const std::string_view* base_url_string = nullptr);
5343
5344
  // @see https://urlpattern.spec.whatwg.org/#dom-urlpattern-protocol
5345
  [[nodiscard]] std::string_view get_protocol() const ada_lifetime_bound;
5346
  // @see https://urlpattern.spec.whatwg.org/#dom-urlpattern-username
5347
  [[nodiscard]] std::string_view get_username() const ada_lifetime_bound;
5348
  // @see https://urlpattern.spec.whatwg.org/#dom-urlpattern-password
5349
  [[nodiscard]] std::string_view get_password() const ada_lifetime_bound;
5350
  // @see https://urlpattern.spec.whatwg.org/#dom-urlpattern-hostname
5351
  [[nodiscard]] std::string_view get_hostname() const ada_lifetime_bound;
5352
  // @see https://urlpattern.spec.whatwg.org/#dom-urlpattern-port
5353
  [[nodiscard]] std::string_view get_port() const ada_lifetime_bound;
5354
  // @see https://urlpattern.spec.whatwg.org/#dom-urlpattern-pathname
5355
  [[nodiscard]] std::string_view get_pathname() const ada_lifetime_bound;
5356
  // @see https://urlpattern.spec.whatwg.org/#dom-urlpattern-search
5357
  [[nodiscard]] std::string_view get_search() const ada_lifetime_bound;
5358
  // @see https://urlpattern.spec.whatwg.org/#dom-urlpattern-hash
5359
  [[nodiscard]] std::string_view get_hash() const ada_lifetime_bound;
5360
5361
  // If ignoreCase is true, the JavaScript regular expression created for each
5362
  // pattern must use the `vi` flag. Otherwise, they must use the `v` flag.
5363
  [[nodiscard]] bool ignore_case() const;
5364
5365
  // @see https://urlpattern.spec.whatwg.org/#url-pattern-has-regexp-groups
5366
  [[nodiscard]] bool has_regexp_groups() const;
5367
5368
#if ADA_TESTING
5369
  friend void PrintTo(const url_pattern& c, std::ostream* os) {
5370
    *os << "protocol_component: '" << c.get_protocol() << ", ";
5371
    *os << "username_component: '" << c.get_username() << ", ";
5372
    *os << "password_component: '" << c.get_password() << ", ";
5373
    *os << "hostname_component: '" << c.get_hostname() << ", ";
5374
    *os << "port_component: '" << c.get_port() << ", ";
5375
    *os << "pathname_component: '" << c.get_pathname() << ", ";
5376
    *os << "search_component: '" << c.get_search() << ", ";
5377
    *os << "hash_component: '" << c.get_hash();
5378
  }
5379
#endif  // ADA_TESTING
5380
5381
  template <url_pattern_regex::regex_concept P>
5382
  friend tl::expected<url_pattern<P>, errors> parser::parse_url_pattern_impl(
5383
      std::variant<std::string_view, url_pattern_init>&& input,
5384
      const std::string_view* base_url, const url_pattern_options* options);
5385
5386
  /**
5387
   * @private
5388
   * We can not make this private due to a LLVM bug.
5389
   * Ref: https://github.com/ada-url/ada/pull/859
5390
   */
5391
  url_pattern_component<regex_provider> protocol_component{};
5392
  /**
5393
   * @private
5394
   * We can not make this private due to a LLVM bug.
5395
   * Ref: https://github.com/ada-url/ada/pull/859
5396
   */
5397
  url_pattern_component<regex_provider> username_component{};
5398
  /**
5399
   * @private
5400
   * We can not make this private due to a LLVM bug.
5401
   * Ref: https://github.com/ada-url/ada/pull/859
5402
   */
5403
  url_pattern_component<regex_provider> password_component{};
5404
  /**
5405
   * @private
5406
   * We can not make this private due to a LLVM bug.
5407
   * Ref: https://github.com/ada-url/ada/pull/859
5408
   */
5409
  url_pattern_component<regex_provider> hostname_component{};
5410
  /**
5411
   * @private
5412
   * We can not make this private due to a LLVM bug.
5413
   * Ref: https://github.com/ada-url/ada/pull/859
5414
   */
5415
  url_pattern_component<regex_provider> port_component{};
5416
  /**
5417
   * @private
5418
   * We can not make this private due to a LLVM bug.
5419
   * Ref: https://github.com/ada-url/ada/pull/859
5420
   */
5421
  url_pattern_component<regex_provider> pathname_component{};
5422
  /**
5423
   * @private
5424
   * We can not make this private due to a LLVM bug.
5425
   * Ref: https://github.com/ada-url/ada/pull/859
5426
   */
5427
  url_pattern_component<regex_provider> search_component{};
5428
  /**
5429
   * @private
5430
   * We can not make this private due to a LLVM bug.
5431
   * Ref: https://github.com/ada-url/ada/pull/859
5432
   */
5433
  url_pattern_component<regex_provider> hash_component{};
5434
  /**
5435
   * @private
5436
   * We can not make this private due to a LLVM bug.
5437
   * Ref: https://github.com/ada-url/ada/pull/859
5438
   */
5439
  bool ignore_case_ = false;
5440
};
5441
}  // namespace ada
5442
#endif  // ADA_INCLUDE_URL_PATTERN
5443
#endif
5444
/* end file include/ada/url_pattern.h */
5445
/* begin file include/ada/url_pattern_helpers.h */
5446
/**
5447
 * @file url_pattern_helpers.h
5448
 * @brief Declaration for the URLPattern helpers.
5449
 */
5450
#ifndef ADA_URL_PATTERN_HELPERS_H
5451
#define ADA_URL_PATTERN_HELPERS_H
5452
5453
5454
#include <string>
5455
#include <tuple>
5456
#include <vector>
5457
5458
#if ADA_INCLUDE_URL_PATTERN
5459
namespace ada {
5460
enum class errors : uint8_t;
5461
}
5462
5463
namespace ada::url_pattern_helpers {
5464
5465
// @see https://urlpattern.spec.whatwg.org/#token
5466
enum class token_type : uint8_t {
5467
  INVALID_CHAR,    // 0
5468
  OPEN,            // 1
5469
  CLOSE,           // 2
5470
  REGEXP,          // 3
5471
  NAME,            // 4
5472
  CHAR,            // 5
5473
  ESCAPED_CHAR,    // 6
5474
  OTHER_MODIFIER,  // 7
5475
  ASTERISK,        // 8
5476
  END,             // 9
5477
};
5478
5479
#ifdef ADA_TESTING
5480
std::string to_string(token_type type);
5481
#endif  // ADA_TESTING
5482
5483
// @see https://urlpattern.spec.whatwg.org/#tokenize-policy
5484
enum class token_policy {
5485
  strict,
5486
  lenient,
5487
};
5488
5489
// @see https://urlpattern.spec.whatwg.org/#tokens
5490
class token {
5491
 public:
5492
  token(token_type _type, size_t _index, std::string&& _value)
5493
0
      : type(_type), index(_index), value(std::move(_value)) {}
5494
5495
  // A token has an associated type, a string, initially "invalid-char".
5496
  token_type type = token_type::INVALID_CHAR;
5497
5498
  // A token has an associated index, a number, initially 0. It is the position
5499
  // of the first code point in the pattern string represented by the token.
5500
  size_t index = 0;
5501
5502
  // A token has an associated value, a string, initially the empty string. It
5503
  // contains the code points from the pattern string represented by the token.
5504
  std::string value{};
5505
};
5506
5507
// @see https://urlpattern.spec.whatwg.org/#pattern-parser
5508
template <url_pattern_encoding_callback F>
5509
class url_pattern_parser {
5510
 public:
5511
  url_pattern_parser(F& encoding_callback_,
5512
                     std::string_view segment_wildcard_regexp_)
5513
      : encoding_callback(encoding_callback_),
5514
        segment_wildcard_regexp(segment_wildcard_regexp_) {}
5515
5516
  bool can_continue() const { return index < tokens.size(); }
5517
5518
  // @see https://urlpattern.spec.whatwg.org/#try-to-consume-a-token
5519
  token* try_consume_token(token_type type);
5520
  // @see https://urlpattern.spec.whatwg.org/#try-to-consume-a-modifier-token
5521
  token* try_consume_modifier_token();
5522
  // @see
5523
  // https://urlpattern.spec.whatwg.org/#try-to-consume-a-regexp-or-wildcard-token
5524
  token* try_consume_regexp_or_wildcard_token(const token* name_token);
5525
  // @see https://urlpattern.spec.whatwg.org/#consume-text
5526
  std::string consume_text();
5527
  // @see https://urlpattern.spec.whatwg.org/#consume-a-required-token
5528
  bool consume_required_token(token_type type);
5529
  // @see
5530
  // https://urlpattern.spec.whatwg.org/#maybe-add-a-part-from-the-pending-fixed-value
5531
  std::optional<errors> maybe_add_part_from_the_pending_fixed_value()
5532
      ada_warn_unused;
5533
  // @see https://urlpattern.spec.whatwg.org/#add-a-part
5534
  std::optional<errors> add_part(std::string_view prefix, token* name_token,
5535
                                 token* regexp_or_wildcard_token,
5536
                                 std::string_view suyffix,
5537
                                 token* modifier_token) ada_warn_unused;
5538
5539
  std::vector<token> tokens{};
5540
  F& encoding_callback;
5541
  std::string segment_wildcard_regexp;
5542
  std::vector<url_pattern_part> parts{};
5543
  std::string pending_fixed_value{};
5544
  size_t index = 0;
5545
  size_t next_numeric_name = 0;
5546
};
5547
5548
// @see https://urlpattern.spec.whatwg.org/#tokenizer
5549
class Tokenizer {
5550
 public:
5551
  explicit Tokenizer(std::string_view new_input, token_policy new_policy)
5552
0
      : input(new_input), policy(new_policy) {}
5553
5554
  // @see https://urlpattern.spec.whatwg.org/#get-the-next-code-point
5555
  constexpr void get_next_code_point();
5556
5557
  // @see https://urlpattern.spec.whatwg.org/#seek-and-get-the-next-code-point
5558
  constexpr void seek_and_get_next_code_point(size_t index);
5559
5560
  // @see https://urlpattern.spec.whatwg.org/#add-a-token
5561
5562
  void add_token(token_type type, size_t next_position, size_t value_position,
5563
                 size_t value_length);
5564
5565
  // @see https://urlpattern.spec.whatwg.org/#add-a-token-with-default-length
5566
  void add_token_with_default_length(token_type type, size_t next_position,
5567
                                     size_t value_position);
5568
5569
  // @see
5570
  // https://urlpattern.spec.whatwg.org/#add-a-token-with-default-position-and-length
5571
  void add_token_with_defaults(token_type type);
5572
5573
  // @see https://urlpattern.spec.whatwg.org/#process-a-tokenizing-error
5574
  std::optional<errors> process_tokenizing_error(
5575
      size_t next_position, size_t value_position) ada_warn_unused;
5576
5577
  friend tl::expected<std::vector<token>, errors> tokenize(
5578
      std::string_view input, token_policy policy);
5579
5580
 private:
5581
  // has an associated input, a pattern string, initially the empty string.
5582
  std::string input;
5583
  // has an associated policy, a tokenize policy, initially "strict".
5584
  token_policy policy;
5585
  // has an associated token list, a token list, initially an empty list.
5586
  std::vector<token> token_list{};
5587
  // has an associated index, a number, initially 0.
5588
  size_t index = 0;
5589
  // has an associated next index, a number, initially 0.
5590
  size_t next_index = 0;
5591
  // has an associated code point, a Unicode code point, initially null.
5592
  char32_t code_point{};
5593
};
5594
5595
// @see https://urlpattern.spec.whatwg.org/#constructor-string-parser
5596
template <url_pattern_regex::regex_concept regex_provider>
5597
struct constructor_string_parser {
5598
  explicit constructor_string_parser(std::string_view new_input,
5599
                                     std::vector<token>&& new_token_list)
5600
      : input(new_input), token_list(std::move(new_token_list)) {}
5601
  // @see https://urlpattern.spec.whatwg.org/#parse-a-constructor-string
5602
  static tl::expected<url_pattern_init, errors> parse(std::string_view input);
5603
5604
  // @see https://urlpattern.spec.whatwg.org/#constructor-string-parser-state
5605
  enum class State {
5606
    INIT,
5607
    PROTOCOL,
5608
    AUTHORITY,
5609
    USERNAME,
5610
    PASSWORD,
5611
    HOSTNAME,
5612
    PORT,
5613
    PATHNAME,
5614
    SEARCH,
5615
    HASH,
5616
    DONE,
5617
  };
5618
5619
  // @see
5620
  // https://urlpattern.spec.whatwg.org/#compute-protocol-matches-a-special-scheme-flag
5621
  std::optional<errors> compute_protocol_matches_special_scheme_flag();
5622
5623
 private:
5624
  // @see https://urlpattern.spec.whatwg.org/#rewind
5625
  constexpr void rewind();
5626
5627
  // @see https://urlpattern.spec.whatwg.org/#is-a-hash-prefix
5628
  constexpr bool is_hash_prefix();
5629
5630
  // @see https://urlpattern.spec.whatwg.org/#is-a-search-prefix
5631
  constexpr bool is_search_prefix();
5632
5633
  // @see https://urlpattern.spec.whatwg.org/#change-state
5634
  void change_state(State state, size_t skip);
5635
5636
  // @see https://urlpattern.spec.whatwg.org/#is-a-group-open
5637
  constexpr bool is_group_open() const;
5638
5639
  // @see https://urlpattern.spec.whatwg.org/#is-a-group-close
5640
  constexpr bool is_group_close() const;
5641
5642
  // @see https://urlpattern.spec.whatwg.org/#is-a-protocol-suffix
5643
  constexpr bool is_protocol_suffix() const;
5644
5645
  // @see https://urlpattern.spec.whatwg.org/#next-is-authority-slashes
5646
  constexpr bool next_is_authority_slashes() const;
5647
5648
  // @see https://urlpattern.spec.whatwg.org/#is-an-identity-terminator
5649
  constexpr bool is_an_identity_terminator() const;
5650
5651
  // @see https://urlpattern.spec.whatwg.org/#is-a-pathname-start
5652
  constexpr bool is_pathname_start() const;
5653
5654
  // @see https://urlpattern.spec.whatwg.org/#is-a-password-prefix
5655
  constexpr bool is_password_prefix() const;
5656
5657
  // @see https://urlpattern.spec.whatwg.org/#is-an-ipv6-open
5658
  constexpr bool is_an_ipv6_open() const;
5659
5660
  // @see https://urlpattern.spec.whatwg.org/#is-an-ipv6-close
5661
  constexpr bool is_an_ipv6_close() const;
5662
5663
  // @see https://urlpattern.spec.whatwg.org/#is-a-port-prefix
5664
  constexpr bool is_port_prefix() const;
5665
5666
  // @see https://urlpattern.spec.whatwg.org/#is-a-non-special-pattern-char
5667
  constexpr bool is_non_special_pattern_char(size_t index,
5668
                                             uint32_t value) const;
5669
5670
  // @see https://urlpattern.spec.whatwg.org/#get-a-safe-token
5671
  constexpr const token* get_safe_token(size_t index) const;
5672
5673
  // @see https://urlpattern.spec.whatwg.org/#make-a-component-string
5674
  std::string make_component_string();
5675
  // has an associated input, a string, which must be set upon creation.
5676
  std::string input;
5677
  // has an associated token list, a token list, which must be set upon
5678
  // creation.
5679
  std::vector<token> token_list;
5680
  // has an associated result, a URLPatternInit, initially set to a new
5681
  // URLPatternInit.
5682
  url_pattern_init result{};
5683
  // has an associated component start, a number, initially set to 0.
5684
  size_t component_start = 0;
5685
  // has an associated token index, a number, initially set to 0.
5686
  size_t token_index = 0;
5687
  // has an associated token increment, a number, initially set to 1.
5688
  size_t token_increment = 1;
5689
  // has an associated group depth, a number, initially set to 0.
5690
  size_t group_depth = 0;
5691
  // has an associated hostname IPv6 bracket depth, a number, initially set to
5692
  // 0.
5693
  size_t hostname_ipv6_bracket_depth = 0;
5694
  // has an associated protocol matches a special scheme flag, a boolean,
5695
  // initially set to false.
5696
  bool protocol_matches_a_special_scheme_flag = false;
5697
  // has an associated state, a string, initially set to "init".
5698
  State state = State::INIT;
5699
};
5700
5701
// @see https://urlpattern.spec.whatwg.org/#canonicalize-a-protocol
5702
tl::expected<std::string, errors> canonicalize_protocol(std::string_view input);
5703
5704
// @see https://wicg.github.io/urlpattern/#canonicalize-a-username
5705
tl::expected<std::string, errors> canonicalize_username(std::string_view input);
5706
5707
// @see https://wicg.github.io/urlpattern/#canonicalize-a-password
5708
tl::expected<std::string, errors> canonicalize_password(std::string_view input);
5709
5710
// @see https://wicg.github.io/urlpattern/#canonicalize-a-password
5711
tl::expected<std::string, errors> canonicalize_hostname(std::string_view input);
5712
5713
// @see https://wicg.github.io/urlpattern/#canonicalize-an-ipv6-hostname
5714
tl::expected<std::string, errors> canonicalize_ipv6_hostname(
5715
    std::string_view input);
5716
5717
// @see https://wicg.github.io/urlpattern/#canonicalize-a-port
5718
tl::expected<std::string, errors> canonicalize_port(std::string_view input);
5719
5720
// @see https://wicg.github.io/urlpattern/#canonicalize-a-port
5721
tl::expected<std::string, errors> canonicalize_port_with_protocol(
5722
    std::string_view input, std::string_view protocol);
5723
5724
// @see https://wicg.github.io/urlpattern/#canonicalize-a-pathname
5725
tl::expected<std::string, errors> canonicalize_pathname(std::string_view input);
5726
5727
// @see https://wicg.github.io/urlpattern/#canonicalize-an-opaque-pathname
5728
tl::expected<std::string, errors> canonicalize_opaque_pathname(
5729
    std::string_view input);
5730
5731
// @see https://wicg.github.io/urlpattern/#canonicalize-a-search
5732
tl::expected<std::string, errors> canonicalize_search(std::string_view input);
5733
5734
// @see https://wicg.github.io/urlpattern/#canonicalize-a-hash
5735
tl::expected<std::string, errors> canonicalize_hash(std::string_view input);
5736
5737
// @see https://urlpattern.spec.whatwg.org/#tokenize
5738
tl::expected<std::vector<token>, errors> tokenize(std::string_view input,
5739
                                                  token_policy policy);
5740
5741
// @see https://urlpattern.spec.whatwg.org/#process-a-base-url-string
5742
std::string process_base_url_string(std::string_view input,
5743
                                    url_pattern_init::process_type type);
5744
5745
// @see https://urlpattern.spec.whatwg.org/#escape-a-pattern-string
5746
std::string escape_pattern_string(std::string_view input);
5747
5748
// @see https://urlpattern.spec.whatwg.org/#escape-a-regexp-string
5749
std::string escape_regexp_string(std::string_view input);
5750
5751
// @see https://urlpattern.spec.whatwg.org/#is-an-absolute-pathname
5752
constexpr bool is_absolute_pathname(
5753
    std::string_view input, url_pattern_init::process_type type) noexcept;
5754
5755
// @see https://urlpattern.spec.whatwg.org/#parse-a-pattern-string
5756
template <url_pattern_encoding_callback F>
5757
tl::expected<std::vector<url_pattern_part>, errors> parse_pattern_string(
5758
    std::string_view input, url_pattern_compile_component_options& options,
5759
    F& encoding_callback);
5760
5761
// @see https://urlpattern.spec.whatwg.org/#generate-a-pattern-string
5762
std::string generate_pattern_string(
5763
    std::vector<url_pattern_part>& part_list,
5764
    url_pattern_compile_component_options& options);
5765
5766
// @see
5767
// https://urlpattern.spec.whatwg.org/#generate-a-regular-expression-and-name-list
5768
std::tuple<std::string, std::vector<std::string>>
5769
generate_regular_expression_and_name_list(
5770
    const std::vector<url_pattern_part>& part_list,
5771
    url_pattern_compile_component_options options);
5772
5773
// @see https://urlpattern.spec.whatwg.org/#hostname-pattern-is-an-ipv6-address
5774
bool is_ipv6_address(std::string_view input) noexcept;
5775
5776
// @see
5777
// https://urlpattern.spec.whatwg.org/#protocol-component-matches-a-special-scheme
5778
template <url_pattern_regex::regex_concept regex_provider>
5779
bool protocol_component_matches_special_scheme(
5780
    ada::url_pattern_component<regex_provider>& input);
5781
5782
// @see https://urlpattern.spec.whatwg.org/#convert-a-modifier-to-a-string
5783
std::string convert_modifier_to_string(url_pattern_part_modifier modifier);
5784
5785
// @see https://urlpattern.spec.whatwg.org/#generate-a-segment-wildcard-regexp
5786
std::string generate_segment_wildcard_regexp(
5787
    url_pattern_compile_component_options options);
5788
5789
}  // namespace ada::url_pattern_helpers
5790
#endif  // ADA_INCLUDE_URL_PATTERN
5791
#endif
5792
/* end file include/ada/url_pattern_helpers.h */
5793
5794
#include <string>
5795
#include <string_view>
5796
#include <variant>
5797
5798
namespace ada::parser {
5799
#if ADA_INCLUDE_URL_PATTERN
5800
template <url_pattern_regex::regex_concept regex_provider>
5801
tl::expected<url_pattern<regex_provider>, errors> parse_url_pattern_impl(
5802
    std::variant<std::string_view, url_pattern_init>&& input,
5803
    const std::string_view* base_url, const url_pattern_options* options) {
5804
  // Let init be null.
5805
  url_pattern_init init;
5806
5807
  // If input is a scalar value string then:
5808
  if (std::holds_alternative<std::string_view>(input)) {
5809
    // Set init to the result of running parse a constructor string given input.
5810
    auto parse_result =
5811
        url_pattern_helpers::constructor_string_parser<regex_provider>::parse(
5812
            std::get<std::string_view>(input));
5813
    if (!parse_result) {
5814
      ada_log("constructor_string_parser::parse failed");
5815
      return tl::unexpected(parse_result.error());
5816
    }
5817
    init = std::move(*parse_result);
5818
    // If baseURL is null and init["protocol"] does not exist, then throw a
5819
    // TypeError.
5820
    if (!base_url && !init.protocol) {
5821
      ada_log("base url is null and protocol is not set");
5822
      return tl::unexpected(errors::type_error);
5823
    }
5824
5825
    // If baseURL is not null, set init["baseURL"] to baseURL.
5826
    if (base_url) {
5827
      init.base_url = std::string(*base_url);
5828
    }
5829
  } else {
5830
    // Assert: input is a URLPatternInit.
5831
    ADA_ASSERT_TRUE(std::holds_alternative<url_pattern_init>(input));
5832
    // If baseURL is not null, then throw a TypeError.
5833
    if (base_url) {
5834
      ada_log("base url is not null");
5835
      return tl::unexpected(errors::type_error);
5836
    }
5837
    // Optimization: Avoid copy by moving the input value.
5838
    // Set init to input.
5839
    init = std::move(std::get<url_pattern_init>(input));
5840
  }
5841
5842
  // Let processedInit be the result of process a URLPatternInit given init,
5843
  // "pattern", null, null, null, null, null, null, null, and null.
5844
  auto processed_init =
5845
      url_pattern_init::process(init, url_pattern_init::process_type::pattern);
5846
  if (!processed_init) {
5847
    ada_log("url_pattern_init::process failed for init and 'pattern'");
5848
    return tl::unexpected(processed_init.error());
5849
  }
5850
5851
  // For each componentName of  "protocol", "username", "password", "hostname",
5852
  // "port", "pathname", "search", "hash" If processedInit[componentName] does
5853
  // not exist, then set processedInit[componentName] to "*".
5854
  ADA_ASSERT_TRUE(processed_init.has_value());
5855
  if (!processed_init->protocol) processed_init->protocol = "*";
5856
  if (!processed_init->username) processed_init->username = "*";
5857
  if (!processed_init->password) processed_init->password = "*";
5858
  if (!processed_init->hostname) processed_init->hostname = "*";
5859
  if (!processed_init->port) processed_init->port = "*";
5860
  if (!processed_init->pathname) processed_init->pathname = "*";
5861
  if (!processed_init->search) processed_init->search = "*";
5862
  if (!processed_init->hash) processed_init->hash = "*";
5863
5864
  ada_log("-- processed_init->protocol: ", processed_init->protocol.value());
5865
  ada_log("-- processed_init->username: ", processed_init->username.value());
5866
  ada_log("-- processed_init->password: ", processed_init->password.value());
5867
  ada_log("-- processed_init->hostname: ", processed_init->hostname.value());
5868
  ada_log("-- processed_init->port: ", processed_init->port.value());
5869
  ada_log("-- processed_init->pathname: ", processed_init->pathname.value());
5870
  ada_log("-- processed_init->search: ", processed_init->search.value());
5871
  ada_log("-- processed_init->hash: ", processed_init->hash.value());
5872
5873
  // If processedInit["protocol"] is a special scheme and processedInit["port"]
5874
  // is a string which represents its corresponding default port in radix-10
5875
  // using ASCII digits then set processedInit["port"] to the empty string.
5876
  // TODO: Optimization opportunity.
5877
  if (scheme::is_special(*processed_init->protocol)) {
5878
    std::string_view port = processed_init->port.value();
5879
    if (std::to_string(scheme::get_special_port(*processed_init->protocol)) ==
5880
        port) {
5881
      processed_init->port->clear();
5882
    }
5883
  }
5884
5885
  // Let urlPattern be a new URL pattern.
5886
  url_pattern<regex_provider> url_pattern_{};
5887
5888
  // Set urlPattern's protocol component to the result of compiling a component
5889
  // given processedInit["protocol"], canonicalize a protocol, and default
5890
  // options.
5891
  auto protocol_component = url_pattern_component<regex_provider>::compile(
5892
      processed_init->protocol.value(),
5893
      url_pattern_helpers::canonicalize_protocol,
5894
      url_pattern_compile_component_options::DEFAULT);
5895
  if (!protocol_component) {
5896
    ada_log("url_pattern_component::compile failed for protocol ",
5897
            processed_init->protocol.value());
5898
    return tl::unexpected(protocol_component.error());
5899
  }
5900
  url_pattern_.protocol_component = std::move(*protocol_component);
5901
5902
  // Set urlPattern's username component to the result of compiling a component
5903
  // given processedInit["username"], canonicalize a username, and default
5904
  // options.
5905
  auto username_component = url_pattern_component<regex_provider>::compile(
5906
      processed_init->username.value(),
5907
      url_pattern_helpers::canonicalize_username,
5908
      url_pattern_compile_component_options::DEFAULT);
5909
  if (!username_component) {
5910
    ada_log("url_pattern_component::compile failed for username ",
5911
            processed_init->username.value());
5912
    return tl::unexpected(username_component.error());
5913
  }
5914
  url_pattern_.username_component = std::move(*username_component);
5915
5916
  // Set urlPattern's password component to the result of compiling a component
5917
  // given processedInit["password"], canonicalize a password, and default
5918
  // options.
5919
  auto password_component = url_pattern_component<regex_provider>::compile(
5920
      processed_init->password.value(),
5921
      url_pattern_helpers::canonicalize_password,
5922
      url_pattern_compile_component_options::DEFAULT);
5923
  if (!password_component) {
5924
    ada_log("url_pattern_component::compile failed for password ",
5925
            processed_init->password.value());
5926
    return tl::unexpected(password_component.error());
5927
  }
5928
  url_pattern_.password_component = std::move(*password_component);
5929
5930
  // TODO: Optimization opportunity. The following if statement can be
5931
  // simplified.
5932
  // If the result running hostname pattern is an IPv6 address given
5933
  // processedInit["hostname"] is true, then set urlPattern's hostname component
5934
  // to the result of compiling a component given processedInit["hostname"],
5935
  // canonicalize an IPv6 hostname, and hostname options.
5936
  if (url_pattern_helpers::is_ipv6_address(processed_init->hostname.value())) {
5937
    ada_log("processed_init->hostname is ipv6 address");
5938
    // then set urlPattern's hostname component to the result of compiling a
5939
    // component given processedInit["hostname"], canonicalize an IPv6 hostname,
5940
    // and hostname options.
5941
    auto hostname_component = url_pattern_component<regex_provider>::compile(
5942
        processed_init->hostname.value(),
5943
        url_pattern_helpers::canonicalize_ipv6_hostname,
5944
        url_pattern_compile_component_options::DEFAULT);
5945
    if (!hostname_component) {
5946
      ada_log("url_pattern_component::compile failed for ipv6 hostname ",
5947
              processed_init->hostname.value());
5948
      return tl::unexpected(hostname_component.error());
5949
    }
5950
    url_pattern_.hostname_component = std::move(*hostname_component);
5951
  } else {
5952
    // Otherwise, set urlPattern's hostname component to the result of compiling
5953
    // a component given processedInit["hostname"], canonicalize a hostname, and
5954
    // hostname options.
5955
    auto hostname_component = url_pattern_component<regex_provider>::compile(
5956
        processed_init->hostname.value(),
5957
        url_pattern_helpers::canonicalize_hostname,
5958
        url_pattern_compile_component_options::HOSTNAME);
5959
    if (!hostname_component) {
5960
      ada_log("url_pattern_component::compile failed for hostname ",
5961
              processed_init->hostname.value());
5962
      return tl::unexpected(hostname_component.error());
5963
    }
5964
    url_pattern_.hostname_component = std::move(*hostname_component);
5965
  }
5966
5967
  // Set urlPattern's port component to the result of compiling a component
5968
  // given processedInit["port"], canonicalize a port, and default options.
5969
  auto port_component = url_pattern_component<regex_provider>::compile(
5970
      processed_init->port.value(), url_pattern_helpers::canonicalize_port,
5971
      url_pattern_compile_component_options::DEFAULT);
5972
  if (!port_component) {
5973
    ada_log("url_pattern_component::compile failed for port ",
5974
            processed_init->port.value());
5975
    return tl::unexpected(port_component.error());
5976
  }
5977
  url_pattern_.port_component = std::move(*port_component);
5978
5979
  // Let compileOptions be a copy of the default options with the ignore case
5980
  // property set to options["ignoreCase"].
5981
  auto compile_options = url_pattern_compile_component_options::DEFAULT;
5982
  if (options) {
5983
    compile_options.ignore_case = options->ignore_case;
5984
  }
5985
5986
  // TODO: Optimization opportunity: Simplify this if statement.
5987
  // If the result of running protocol component matches a special scheme given
5988
  // urlPattern's protocol component is true, then:
5989
  if (url_pattern_helpers::protocol_component_matches_special_scheme<
5990
          regex_provider>(url_pattern_.protocol_component)) {
5991
    // Let pathCompileOptions be copy of the pathname options with the ignore
5992
    // case property set to options["ignoreCase"].
5993
    auto path_compile_options = url_pattern_compile_component_options::PATHNAME;
5994
    if (options) {
5995
      path_compile_options.ignore_case = options->ignore_case;
5996
    }
5997
5998
    // Set urlPattern's pathname component to the result of compiling a
5999
    // component given processedInit["pathname"], canonicalize a pathname, and
6000
    // pathCompileOptions.
6001
    auto pathname_component = url_pattern_component<regex_provider>::compile(
6002
        processed_init->pathname.value(),
6003
        url_pattern_helpers::canonicalize_pathname, path_compile_options);
6004
    if (!pathname_component) {
6005
      ada_log("url_pattern_component::compile failed for pathname ",
6006
              processed_init->pathname.value());
6007
      return tl::unexpected(pathname_component.error());
6008
    }
6009
    url_pattern_.pathname_component = std::move(*pathname_component);
6010
  } else {
6011
    // Otherwise set urlPattern's pathname component to the result of compiling
6012
    // a component given processedInit["pathname"], canonicalize an opaque
6013
    // pathname, and compileOptions.
6014
    auto pathname_component = url_pattern_component<regex_provider>::compile(
6015
        processed_init->pathname.value(),
6016
        url_pattern_helpers::canonicalize_opaque_pathname, compile_options);
6017
    if (!pathname_component) {
6018
      ada_log("url_pattern_component::compile failed for opaque pathname ",
6019
              processed_init->pathname.value());
6020
      return tl::unexpected(pathname_component.error());
6021
    }
6022
    url_pattern_.pathname_component = std::move(*pathname_component);
6023
  }
6024
6025
  // Set urlPattern's search component to the result of compiling a component
6026
  // given processedInit["search"], canonicalize a search, and compileOptions.
6027
  auto search_component = url_pattern_component<regex_provider>::compile(
6028
      processed_init->search.value(), url_pattern_helpers::canonicalize_search,
6029
      compile_options);
6030
  if (!search_component) {
6031
    ada_log("url_pattern_component::compile failed for search ",
6032
            processed_init->search.value());
6033
    return tl::unexpected(search_component.error());
6034
  }
6035
  url_pattern_.search_component = std::move(*search_component);
6036
6037
  // Set urlPattern's hash component to the result of compiling a component
6038
  // given processedInit["hash"], canonicalize a hash, and compileOptions.
6039
  auto hash_component = url_pattern_component<regex_provider>::compile(
6040
      processed_init->hash.value(), url_pattern_helpers::canonicalize_hash,
6041
      compile_options);
6042
  if (!hash_component) {
6043
    ada_log("url_pattern_component::compile failed for hash ",
6044
            processed_init->hash.value());
6045
    return tl::unexpected(hash_component.error());
6046
  }
6047
  url_pattern_.hash_component = std::move(*hash_component);
6048
6049
  // Return urlPattern.
6050
  return url_pattern_;
6051
}
6052
#endif  // ADA_INCLUDE_URL_PATTERN
6053
6054
}  // namespace ada::parser
6055
6056
#endif  // ADA_PARSER_INL_H
6057
/* end file include/ada/parser-inl.h */
6058
/* begin file include/ada/scheme-inl.h */
6059
/**
6060
 * @file scheme-inl.h
6061
 * @brief Definitions for the URL scheme.
6062
 */
6063
#ifndef ADA_SCHEME_INL_H
6064
#define ADA_SCHEME_INL_H
6065
6066
6067
namespace ada::scheme {
6068
6069
/**
6070
 * @namespace ada::scheme::details
6071
 * @brief Includes the definitions for scheme specific entities
6072
 */
6073
namespace details {
6074
// for use with is_special and get_special_port
6075
// Spaces, if present, are removed from URL.
6076
constexpr std::string_view is_special_list[] = {"http", " ",   "https", "ws",
6077
                                                "ftp",  "wss", "file",  " "};
6078
// for use with get_special_port
6079
constexpr uint16_t special_ports[] = {80, 0, 443, 80, 21, 443, 0, 0};
6080
}  // namespace details
6081
6082
/****
6083
 * @private
6084
 * In is_special, get_scheme_type, and get_special_port, we
6085
 * use a standard hashing technique to find the index of the scheme in
6086
 * the is_special_list. The hashing technique is based on the size of
6087
 * the scheme and the first character of the scheme. It ensures that we
6088
 * do at most one string comparison per call. If the protocol is
6089
 * predictible (e.g., it is always "http"), we can get a better average
6090
 * performance by using a simpler approach where we loop and compare
6091
 * scheme with all possible protocols starting with the most likely
6092
 * protocol. Doing multiple comparisons may have a poor worst case
6093
 * performance, however. In this instance, we choose a potentially
6094
 * slightly lower best-case performance for a better worst-case
6095
 * performance. We can revisit this choice at any time.
6096
 *
6097
 * Reference:
6098
 * Schmidt, Douglas C. "Gperf: A perfect hash function generator."
6099
 * More C++ gems 17 (2000).
6100
 *
6101
 * Reference: https://en.wikipedia.org/wiki/Perfect_hash_function
6102
 *
6103
 * Reference: https://github.com/ada-url/ada/issues/617
6104
 ****/
6105
6106
4.99k
ada_really_inline constexpr bool is_special(std::string_view scheme) {
6107
4.99k
  if (scheme.empty()) {
6108
0
    return false;
6109
0
  }
6110
4.99k
  int hash_value = (2 * scheme.size() + (unsigned)(scheme[0])) & 7;
6111
4.99k
  const std::string_view target = details::is_special_list[hash_value];
6112
4.99k
  return (target[0] == scheme[0]) && (target.substr(1) == scheme.substr(1));
6113
4.99k
}
6114
0
constexpr uint16_t get_special_port(std::string_view scheme) noexcept {
6115
0
  if (scheme.empty()) {
6116
0
    return 0;
6117
0
  }
6118
0
  int hash_value = (2 * scheme.size() + (unsigned)(scheme[0])) & 7;
6119
0
  const std::string_view target = details::is_special_list[hash_value];
6120
0
  if ((target[0] == scheme[0]) && (target.substr(1) == scheme.substr(1))) {
6121
0
    return details::special_ports[hash_value];
6122
0
  } else {
6123
0
    return 0;
6124
0
  }
6125
0
}
6126
7.30k
constexpr uint16_t get_special_port(ada::scheme::type type) noexcept {
6127
7.30k
  return details::special_ports[int(type)];
6128
7.30k
}
6129
50.1k
constexpr ada::scheme::type get_scheme_type(std::string_view scheme) noexcept {
6130
50.1k
  if (scheme.empty()) {
6131
0
    return ada::scheme::NOT_SPECIAL;
6132
0
  }
6133
50.1k
  int hash_value = (2 * scheme.size() + (unsigned)(scheme[0])) & 7;
6134
50.1k
  const std::string_view target = details::is_special_list[hash_value];
6135
50.1k
  if ((target[0] == scheme[0]) && (target.substr(1) == scheme.substr(1))) {
6136
30.6k
    return ada::scheme::type(hash_value);
6137
30.6k
  } else {
6138
19.5k
    return ada::scheme::NOT_SPECIAL;
6139
19.5k
  }
6140
50.1k
}
6141
6142
}  // namespace ada::scheme
6143
6144
#endif  // ADA_SCHEME_INL_H
6145
/* end file include/ada/scheme-inl.h */
6146
/* begin file include/ada/serializers.h */
6147
/**
6148
 * @file serializers.h
6149
 * @brief Definitions for the URL serializers.
6150
 */
6151
#ifndef ADA_SERIALIZERS_H
6152
#define ADA_SERIALIZERS_H
6153
6154
6155
#include <array>
6156
#include <string>
6157
6158
/**
6159
 * @namespace ada::serializers
6160
 * @brief Includes the definitions for URL serializers
6161
 */
6162
namespace ada::serializers {
6163
6164
/**
6165
 * Finds and returns the longest sequence of 0 values in a ipv6 input.
6166
 */
6167
void find_longest_sequence_of_ipv6_pieces(
6168
    const std::array<uint16_t, 8>& address, size_t& compress,
6169
    size_t& compress_length) noexcept;
6170
6171
/**
6172
 * Serializes an ipv6 address.
6173
 * @details An IPv6 address is a 128-bit unsigned integer that identifies a
6174
 * network address.
6175
 * @see https://url.spec.whatwg.org/#concept-ipv6-serializer
6176
 */
6177
std::string ipv6(const std::array<uint16_t, 8>& address) noexcept;
6178
6179
/**
6180
 * Serializes an ipv4 address.
6181
 * @details An IPv4 address is a 32-bit unsigned integer that identifies a
6182
 * network address.
6183
 * @see https://url.spec.whatwg.org/#concept-ipv4-serializer
6184
 */
6185
std::string ipv4(uint64_t address) noexcept;
6186
6187
}  // namespace ada::serializers
6188
6189
#endif  // ADA_SERIALIZERS_H
6190
/* end file include/ada/serializers.h */
6191
/* begin file include/ada/state.h */
6192
/**
6193
 * @file state.h
6194
 * @brief Definitions for the states of the URL state machine.
6195
 */
6196
#ifndef ADA_STATE_H
6197
#define ADA_STATE_H
6198
6199
6200
#include <string>
6201
6202
namespace ada {
6203
6204
/**
6205
 * @see https://url.spec.whatwg.org/#url-parsing
6206
 */
6207
enum class state {
6208
  /**
6209
   * @see https://url.spec.whatwg.org/#authority-state
6210
   */
6211
  AUTHORITY,
6212
6213
  /**
6214
   * @see https://url.spec.whatwg.org/#scheme-start-state
6215
   */
6216
  SCHEME_START,
6217
6218
  /**
6219
   * @see https://url.spec.whatwg.org/#scheme-state
6220
   */
6221
  SCHEME,
6222
6223
  /**
6224
   * @see https://url.spec.whatwg.org/#host-state
6225
   */
6226
  HOST,
6227
6228
  /**
6229
   * @see https://url.spec.whatwg.org/#no-scheme-state
6230
   */
6231
  NO_SCHEME,
6232
6233
  /**
6234
   * @see https://url.spec.whatwg.org/#fragment-state
6235
   */
6236
  FRAGMENT,
6237
6238
  /**
6239
   * @see https://url.spec.whatwg.org/#relative-state
6240
   */
6241
  RELATIVE_SCHEME,
6242
6243
  /**
6244
   * @see https://url.spec.whatwg.org/#relative-slash-state
6245
   */
6246
  RELATIVE_SLASH,
6247
6248
  /**
6249
   * @see https://url.spec.whatwg.org/#file-state
6250
   */
6251
  FILE,
6252
6253
  /**
6254
   * @see https://url.spec.whatwg.org/#file-host-state
6255
   */
6256
  FILE_HOST,
6257
6258
  /**
6259
   * @see https://url.spec.whatwg.org/#file-slash-state
6260
   */
6261
  FILE_SLASH,
6262
6263
  /**
6264
   * @see https://url.spec.whatwg.org/#path-or-authority-state
6265
   */
6266
  PATH_OR_AUTHORITY,
6267
6268
  /**
6269
   * @see https://url.spec.whatwg.org/#special-authority-ignore-slashes-state
6270
   */
6271
  SPECIAL_AUTHORITY_IGNORE_SLASHES,
6272
6273
  /**
6274
   * @see https://url.spec.whatwg.org/#special-authority-slashes-state
6275
   */
6276
  SPECIAL_AUTHORITY_SLASHES,
6277
6278
  /**
6279
   * @see https://url.spec.whatwg.org/#special-relative-or-authority-state
6280
   */
6281
  SPECIAL_RELATIVE_OR_AUTHORITY,
6282
6283
  /**
6284
   * @see https://url.spec.whatwg.org/#query-state
6285
   */
6286
  QUERY,
6287
6288
  /**
6289
   * @see https://url.spec.whatwg.org/#path-state
6290
   */
6291
  PATH,
6292
6293
  /**
6294
   * @see https://url.spec.whatwg.org/#path-start-state
6295
   */
6296
  PATH_START,
6297
6298
  /**
6299
   * @see https://url.spec.whatwg.org/#cannot-be-a-base-url-path-state
6300
   */
6301
  OPAQUE_PATH,
6302
6303
  /**
6304
   * @see https://url.spec.whatwg.org/#port-state
6305
   */
6306
  PORT,
6307
};
6308
6309
/**
6310
 * Stringify a URL state machine state.
6311
 */
6312
ada_warn_unused std::string to_string(ada::state s);
6313
6314
}  // namespace ada
6315
6316
#endif  // ADA_STATE_H
6317
/* end file include/ada/state.h */
6318
/* begin file include/ada/unicode.h */
6319
/**
6320
 * @file unicode.h
6321
 * @brief Definitions for all unicode specific functions.
6322
 */
6323
#ifndef ADA_UNICODE_H
6324
#define ADA_UNICODE_H
6325
6326
6327
#include <string>
6328
#include <string_view>
6329
#include <optional>
6330
6331
/**
6332
 * Unicode operations. These functions are not part of our public API and may
6333
 * change at any time.
6334
 *
6335
 * @private
6336
 * @namespace ada::unicode
6337
 * @brief Includes the definitions for unicode operations
6338
 */
6339
namespace ada::unicode {
6340
6341
/**
6342
 * @private
6343
 * We receive a UTF-8 string representing a domain name.
6344
 * If the string is percent encoded, we apply percent decoding.
6345
 *
6346
 * Given a domain, we need to identify its labels.
6347
 * They are separated by label-separators:
6348
 *
6349
 * U+002E (.) FULL STOP
6350
 * U+FF0E FULLWIDTH FULL STOP
6351
 * U+3002 IDEOGRAPHIC FULL STOP
6352
 * U+FF61 HALFWIDTH IDEOGRAPHIC FULL STOP
6353
 *
6354
 * They are all mapped to U+002E.
6355
 *
6356
 * We process each label into a string that should not exceed 63 octets.
6357
 * If the string is already punycode (starts with "xn--"), then we must
6358
 * scan it to look for unallowed code points.
6359
 * Otherwise, if the string is not pure ASCII, we need to transcode it
6360
 * to punycode by following RFC 3454 which requires us to
6361
 * - Map characters  (see section 3),
6362
 * - Normalize (see section 4),
6363
 * - Reject forbidden characters,
6364
 * - Check for right-to-left characters and if so, check all requirements (see
6365
 * section 6),
6366
 * - Optionally reject based on unassigned code points (section 7).
6367
 *
6368
 * The Unicode standard provides a table of code points with a mapping, a list
6369
 * of forbidden code points and so forth. This table is subject to change and
6370
 * will vary based on the implementation. For Unicode 15, the table is at
6371
 * https://www.unicode.org/Public/idna/15.0.0/IdnaMappingTable.txt
6372
 * If you use ICU, they parse this table and map it to code using a Python
6373
 * script.
6374
 *
6375
 * The resulting strings should not exceed 255 octets according to RFC 1035
6376
 * section 2.3.4. ICU checks for label size and domain size, but these errors
6377
 * are ignored.
6378
 *
6379
 * @see https://url.spec.whatwg.org/#concept-domain-to-ascii
6380
 *
6381
 */
6382
bool to_ascii(std::optional<std::string>& out, std::string_view plain,
6383
              size_t first_percent);
6384
6385
/**
6386
 * @private
6387
 * Checks if the input has tab or newline characters.
6388
 *
6389
 * @attention The has_tabs_or_newline function is a bottleneck and it is simple
6390
 * enough that compilers like GCC can 'autovectorize it'.
6391
 */
6392
ada_really_inline bool has_tabs_or_newline(
6393
    std::string_view user_input) noexcept;
6394
6395
/**
6396
 * @private
6397
 * Checks if the input is a forbidden host code point.
6398
 * @see https://url.spec.whatwg.org/#forbidden-host-code-point
6399
 */
6400
ada_really_inline constexpr bool is_forbidden_host_code_point(char c) noexcept;
6401
6402
/**
6403
 * @private
6404
 * Checks if the input contains a forbidden domain code point.
6405
 * @see https://url.spec.whatwg.org/#forbidden-domain-code-point
6406
 */
6407
ada_really_inline constexpr bool contains_forbidden_domain_code_point(
6408
    const char* input, size_t length) noexcept;
6409
6410
/**
6411
 * @private
6412
 * Checks if the input contains a forbidden domain code point in which case
6413
 * the first bit is set to 1. If the input contains an upper case ASCII letter,
6414
 * then the second bit is set to 1.
6415
 * @see https://url.spec.whatwg.org/#forbidden-domain-code-point
6416
 */
6417
ada_really_inline constexpr uint8_t
6418
contains_forbidden_domain_code_point_or_upper(const char* input,
6419
                                              size_t length) noexcept;
6420
6421
/**
6422
 * @private
6423
 * Checks if the input is a forbidden domain code point.
6424
 * @see https://url.spec.whatwg.org/#forbidden-domain-code-point
6425
 */
6426
ada_really_inline constexpr bool is_forbidden_domain_code_point(
6427
    char c) noexcept;
6428
6429
/**
6430
 * @private
6431
 * Checks if the input is alphanumeric, '+', '-' or '.'
6432
 */
6433
ada_really_inline constexpr bool is_alnum_plus(char c) noexcept;
6434
6435
/**
6436
 * @private
6437
 * @details An ASCII hex digit is an ASCII upper hex digit or ASCII lower hex
6438
 * digit. An ASCII upper hex digit is an ASCII digit or a code point in the
6439
 * range U+0041 (A) to U+0046 (F), inclusive. An ASCII lower hex digit is an
6440
 * ASCII digit or a code point in the range U+0061 (a) to U+0066 (f), inclusive.
6441
 */
6442
ada_really_inline constexpr bool is_ascii_hex_digit(char c) noexcept;
6443
6444
/**
6445
 * @private
6446
 * An ASCII digit is a code point in the range U+0030 (0) to U+0039 (9),
6447
 * inclusive.
6448
 */
6449
ada_really_inline constexpr bool is_ascii_digit(char c) noexcept;
6450
6451
/**
6452
 * @private
6453
 * @details If a char is between U+0000 and U+007F inclusive, then it's an ASCII
6454
 * character.
6455
 */
6456
ada_really_inline constexpr bool is_ascii(char32_t c) noexcept;
6457
6458
/**
6459
 * @private
6460
 * Checks if the input is a C0 control or space character.
6461
 *
6462
 * @details A C0 control or space is a C0 control or U+0020 SPACE.
6463
 * A C0 control is a code point in the range U+0000 NULL to U+001F INFORMATION
6464
 * SEPARATOR ONE, inclusive.
6465
 */
6466
ada_really_inline constexpr bool is_c0_control_or_space(char c) noexcept;
6467
6468
/**
6469
 * @private
6470
 * Checks if the input is a ASCII tab or newline character.
6471
 *
6472
 * @details An ASCII tab or newline is U+0009 TAB, U+000A LF, or U+000D CR.
6473
 */
6474
ada_really_inline constexpr bool is_ascii_tab_or_newline(char c) noexcept;
6475
6476
/**
6477
 * @private
6478
 * @details A double-dot path segment must be ".." or an ASCII case-insensitive
6479
 * match for ".%2e", "%2e.", or "%2e%2e".
6480
 */
6481
ada_really_inline constexpr bool is_double_dot_path_segment(
6482
    std::string_view input) noexcept;
6483
6484
/**
6485
 * @private
6486
 * @details A single-dot path segment must be "." or an ASCII case-insensitive
6487
 * match for "%2e".
6488
 */
6489
ada_really_inline constexpr bool is_single_dot_path_segment(
6490
    std::string_view input) noexcept;
6491
6492
/**
6493
 * @private
6494
 * @details ipv4 character might contain 0-9 or a-f character ranges.
6495
 */
6496
ada_really_inline constexpr bool is_lowercase_hex(char c) noexcept;
6497
6498
/**
6499
 * @private
6500
 * @details Convert hex to binary. Caller is responsible to ensure that
6501
 * the parameter is an hexadecimal digit (0-9, A-F, a-f).
6502
 */
6503
ada_really_inline unsigned constexpr convert_hex_to_binary(char c) noexcept;
6504
6505
/**
6506
 * @private
6507
 * first_percent should be  = input.find('%')
6508
 *
6509
 * @todo It would be faster as noexcept maybe, but it could be unsafe since.
6510
 * @author Node.js
6511
 * @see https://github.com/nodejs/node/blob/main/src/node_url.cc#L245
6512
 * @see https://encoding.spec.whatwg.org/#utf-8-decode-without-bom
6513
 */
6514
std::string percent_decode(std::string_view input, size_t first_percent);
6515
6516
/**
6517
 * @private
6518
 * Returns a percent-encoding string whether percent encoding was needed or not.
6519
 * @see https://github.com/nodejs/node/blob/main/src/node_url.cc#L226
6520
 */
6521
std::string percent_encode(std::string_view input,
6522
                           const uint8_t character_set[]);
6523
/**
6524
 * @private
6525
 * Returns a percent-encoded string version of input, while starting the percent
6526
 * encoding at the provided index.
6527
 * @see https://github.com/nodejs/node/blob/main/src/node_url.cc#L226
6528
 */
6529
std::string percent_encode(std::string_view input,
6530
                           const uint8_t character_set[], size_t index);
6531
/**
6532
 * @private
6533
 * Returns true if percent encoding was needed, in which case, we store
6534
 * the percent-encoded content in 'out'. If the boolean 'append' is set to
6535
 * true, the content is appended to 'out'.
6536
 * If percent encoding is not needed, out is left unchanged.
6537
 * @see https://github.com/nodejs/node/blob/main/src/node_url.cc#L226
6538
 */
6539
template <bool append>
6540
bool percent_encode(std::string_view input, const uint8_t character_set[],
6541
                    std::string& out);
6542
/**
6543
 * @private
6544
 * Returns the index at which percent encoding should start, or (equivalently),
6545
 * the length of the prefix that does not require percent encoding.
6546
 */
6547
ada_really_inline size_t percent_encode_index(std::string_view input,
6548
                                              const uint8_t character_set[]);
6549
/**
6550
 * @private
6551
 * Lowers the string in-place, assuming that the content is ASCII.
6552
 * Return true if the content was ASCII.
6553
 */
6554
constexpr bool to_lower_ascii(char* input, size_t length) noexcept;
6555
}  // namespace ada::unicode
6556
6557
#endif  // ADA_UNICODE_H
6558
/* end file include/ada/unicode.h */
6559
/* begin file include/ada/url_base-inl.h */
6560
/**
6561
 * @file url_base-inl.h
6562
 * @brief Inline functions for url base
6563
 */
6564
#ifndef ADA_URL_BASE_INL_H
6565
#define ADA_URL_BASE_INL_H
6566
6567
6568
#include <string>
6569
#if ADA_REGULAR_VISUAL_STUDIO
6570
#include <intrin.h>
6571
#endif  // ADA_REGULAR_VISUAL_STUDIO
6572
6573
namespace ada {
6574
6575
[[nodiscard]] ada_really_inline constexpr bool url_base::is_special()
6576
320k
    const noexcept {
6577
320k
  return type != ada::scheme::NOT_SPECIAL;
6578
320k
}
6579
6580
4.38k
[[nodiscard]] inline uint16_t url_base::get_special_port() const noexcept {
6581
4.38k
  return ada::scheme::get_special_port(type);
6582
4.38k
}
6583
6584
[[nodiscard]] ada_really_inline uint16_t
6585
2.92k
url_base::scheme_default_port() const noexcept {
6586
2.92k
  return scheme::get_special_port(type);
6587
2.92k
}
6588
6589
}  // namespace ada
6590
6591
#endif  // ADA_URL_BASE_INL_H
6592
/* end file include/ada/url_base-inl.h */
6593
/* begin file include/ada/url-inl.h */
6594
/**
6595
 * @file url-inl.h
6596
 * @brief Definitions for the URL
6597
 */
6598
#ifndef ADA_URL_INL_H
6599
#define ADA_URL_INL_H
6600
6601
6602
#include <charconv>
6603
#include <optional>
6604
#include <string>
6605
#if ADA_REGULAR_VISUAL_STUDIO
6606
#include <intrin.h>
6607
#endif  // ADA_REGULAR_VISUAL_STUDIO
6608
6609
namespace ada {
6610
14.2k
[[nodiscard]] ada_really_inline bool url::has_credentials() const noexcept {
6611
14.2k
  return !username.empty() || !password.empty();
6612
14.2k
}
6613
0
[[nodiscard]] ada_really_inline bool url::has_port() const noexcept {
6614
0
  return port.has_value();
6615
0
}
6616
29.7k
[[nodiscard]] inline bool url::cannot_have_credentials_or_port() const {
6617
29.7k
  return !host.has_value() || host.value().empty() ||
6618
29.7k
         type == ada::scheme::type::FILE;
6619
29.7k
}
6620
0
[[nodiscard]] inline bool url::has_empty_hostname() const noexcept {
6621
0
  if (!host.has_value()) {
6622
0
    return false;
6623
0
  }
6624
0
  return host.value().empty();
6625
0
}
6626
0
[[nodiscard]] inline bool url::has_hostname() const noexcept {
6627
0
  return host.has_value();
6628
0
}
6629
0
inline std::ostream &operator<<(std::ostream &out, const ada::url &u) {
6630
0
  return out << u.to_string();
6631
0
}
6632
6633
0
[[nodiscard]] size_t url::get_pathname_length() const noexcept {
6634
0
  return path.size();
6635
0
}
6636
6637
8.96k
[[nodiscard]] constexpr std::string_view url::get_pathname() const noexcept {
6638
8.96k
  return path;
6639
8.96k
}
6640
6641
[[nodiscard]] ada_really_inline ada::url_components url::get_components()
6642
0
    const noexcept {
6643
0
  url_components out{};
6644
0
6645
0
  // protocol ends with ':'. for example: "https:"
6646
0
  out.protocol_end = uint32_t(get_protocol().size());
6647
0
6648
0
  // Trailing index is always the next character of the current one.
6649
0
  // NOLINTNEXTLINE(clang-analyzer-deadcode.DeadStores)
6650
0
  size_t running_index = out.protocol_end;
6651
0
6652
0
  if (host.has_value()) {
6653
0
    // 2 characters for "//" and 1 character for starting index
6654
0
    out.host_start = out.protocol_end + 2;
6655
0
6656
0
    if (has_credentials()) {
6657
0
      out.username_end = uint32_t(out.host_start + username.size());
6658
0
6659
0
      out.host_start += uint32_t(username.size());
6660
0
6661
0
      if (!password.empty()) {
6662
0
        out.host_start += uint32_t(password.size() + 1);
6663
0
      }
6664
0
6665
0
      out.host_end = uint32_t(out.host_start + host.value().size());
6666
0
    } else {
6667
0
      out.username_end = out.host_start;
6668
0
6669
0
      // Host does not start with "@" if it does not include credentials.
6670
0
      out.host_end = uint32_t(out.host_start + host.value().size()) - 1;
6671
0
    }
6672
0
6673
0
    running_index = out.host_end + 1;
6674
0
  } else {
6675
0
    // Update host start and end date to the same index, since it does not
6676
0
    // exist.
6677
0
    out.host_start = out.protocol_end;
6678
0
    out.host_end = out.host_start;
6679
0
6680
0
    if (!has_opaque_path && path.starts_with("//")) {
6681
0
      // If url's host is null, url does not have an opaque path, url's path's
6682
0
      // size is greater than 1, and url's path[0] is the empty string, then
6683
0
      // append U+002F (/) followed by U+002E (.) to output.
6684
0
      running_index = out.protocol_end + 2;
6685
0
    } else {
6686
0
      running_index = out.protocol_end;
6687
0
    }
6688
0
  }
6689
0
6690
0
  if (port.has_value()) {
6691
0
    out.port = *port;
6692
0
    running_index += helpers::fast_digit_count(*port) + 1;  // Port omits ':'
6693
0
  }
6694
0
6695
0
  out.pathname_start = uint32_t(running_index);
6696
0
6697
0
  running_index += path.size();
6698
0
6699
0
  if (query.has_value()) {
6700
0
    out.search_start = uint32_t(running_index);
6701
0
    running_index += get_search().size();
6702
0
    if (get_search().empty()) {
6703
0
      running_index++;
6704
0
    }
6705
0
  }
6706
0
6707
0
  if (hash.has_value()) {
6708
0
    out.hash_start = uint32_t(running_index);
6709
0
  }
6710
0
6711
0
  return out;
6712
0
}
6713
6714
52
inline void url::update_base_hostname(std::string_view input) { host = input; }
6715
6716
236
inline void url::update_unencoded_base_hash(std::string_view input) {
6717
  // We do the percent encoding
6718
236
  hash = unicode::percent_encode(input,
6719
236
                                 ada::character_sets::FRAGMENT_PERCENT_ENCODE);
6720
236
}
6721
6722
inline void url::update_base_search(std::string_view input,
6723
342
                                    const uint8_t query_percent_encode_set[]) {
6724
342
  query = ada::unicode::percent_encode(input, query_percent_encode_set);
6725
342
}
6726
6727
0
inline void url::update_base_search(std::optional<std::string> &&input) {
6728
0
  query = std::move(input);
6729
0
}
6730
6731
12.4k
inline void url::update_base_pathname(const std::string_view input) {
6732
12.4k
  path = input;
6733
12.4k
}
6734
6735
0
inline void url::update_base_username(const std::string_view input) {
6736
0
  username = input;
6737
0
}
6738
6739
0
inline void url::update_base_password(const std::string_view input) {
6740
0
  password = input;
6741
0
}
6742
6743
5.20k
inline void url::update_base_port(std::optional<uint16_t> input) {
6744
5.20k
  port = input;
6745
5.20k
}
6746
6747
0
constexpr void url::clear_pathname() { path.clear(); }
6748
6749
0
constexpr void url::clear_search() { query = std::nullopt; }
6750
6751
0
[[nodiscard]] constexpr bool url::has_hash() const noexcept {
6752
0
  return hash.has_value();
6753
0
}
6754
6755
6.53k
[[nodiscard]] constexpr bool url::has_search() const noexcept {
6756
6.53k
  return query.has_value();
6757
6.53k
}
6758
6759
1.45k
constexpr void url::set_protocol_as_file() { type = ada::scheme::type::FILE; }
6760
6761
4.92k
inline void url::set_scheme(std::string &&new_scheme) noexcept {
6762
4.92k
  type = ada::scheme::get_scheme_type(new_scheme);
6763
  // We only move the 'scheme' if it is non-special.
6764
4.92k
  if (!is_special()) {
6765
3.03k
    non_special_scheme = std::move(new_scheme);
6766
3.03k
  }
6767
4.92k
}
6768
6769
0
constexpr void url::copy_scheme(ada::url &&u) noexcept {
6770
0
  non_special_scheme = u.non_special_scheme;
6771
0
  type = u.type;
6772
0
}
6773
6774
0
constexpr void url::copy_scheme(const ada::url &u) {
6775
0
  non_special_scheme = u.non_special_scheme;
6776
0
  type = u.type;
6777
0
}
6778
6779
9.31k
[[nodiscard]] ada_really_inline std::string url::get_href() const noexcept {
6780
9.31k
  std::string output = get_protocol();
6781
6782
9.31k
  if (host.has_value()) {
6783
5.48k
    output += "//";
6784
5.48k
    if (has_credentials()) {
6785
869
      output += username;
6786
869
      if (!password.empty()) {
6787
384
        output += ":" + get_password();
6788
384
      }
6789
869
      output += "@";
6790
869
    }
6791
5.48k
    output += host.value();
6792
5.48k
    if (port.has_value()) {
6793
215
      output += ":" + get_port();
6794
215
    }
6795
5.48k
  } else if (!has_opaque_path && path.starts_with("//")) {
6796
    // If url's host is null, url does not have an opaque path, url's path's
6797
    // size is greater than 1, and url's path[0] is the empty string, then
6798
    // append U+002F (/) followed by U+002E (.) to output.
6799
63
    output += "/.";
6800
63
  }
6801
9.31k
  output += path;
6802
9.31k
  if (query.has_value()) {
6803
509
    output += "?" + query.value();
6804
509
  }
6805
9.31k
  if (hash.has_value()) {
6806
352
    output += "#" + hash.value();
6807
352
  }
6808
9.31k
  return output;
6809
9.31k
}
6810
6811
ada_really_inline size_t url::parse_port(std::string_view view,
6812
2.05k
                                         bool check_trailing_content) noexcept {
6813
2.05k
  ada_log("parse_port('", view, "') ", view.size());
6814
2.05k
  if (!view.empty() && view[0] == '-') {
6815
2
    ada_log("parse_port: view[0] == '0' && view.size() > 1");
6816
2
    is_valid = false;
6817
2
    return 0;
6818
2
  }
6819
2.05k
  uint16_t parsed_port{};
6820
2.05k
  auto r = std::from_chars(view.data(), view.data() + view.size(), parsed_port);
6821
2.05k
  if (r.ec == std::errc::result_out_of_range) {
6822
216
    ada_log("parse_port: r.ec == std::errc::result_out_of_range");
6823
216
    is_valid = false;
6824
216
    return 0;
6825
216
  }
6826
1.83k
  ada_log("parse_port: ", parsed_port);
6827
1.83k
  const auto consumed = size_t(r.ptr - view.data());
6828
1.83k
  ada_log("parse_port: consumed ", consumed);
6829
1.83k
  if (check_trailing_content) {
6830
577
    is_valid &=
6831
577
        (consumed == view.size() || view[consumed] == '/' ||
6832
100
         view[consumed] == '?' || (is_special() && view[consumed] == '\\'));
6833
577
  }
6834
1.83k
  ada_log("parse_port: is_valid = ", is_valid);
6835
1.83k
  if (is_valid) {
6836
    // scheme_default_port can return 0, and we should allow 0 as a base port.
6837
1.48k
    auto default_port = scheme_default_port();
6838
1.48k
    bool is_port_valid = (default_port == 0 && parsed_port == 0) ||
6839
1.47k
                         (default_port != parsed_port);
6840
1.48k
    port = (r.ec == std::errc() && is_port_valid) ? std::optional(parsed_port)
6841
1.48k
                                                  : std::nullopt;
6842
1.48k
  }
6843
1.83k
  return consumed;
6844
2.05k
}
6845
6846
}  // namespace ada
6847
6848
#endif  // ADA_URL_H
6849
/* end file include/ada/url-inl.h */
6850
/* begin file include/ada/url_components-inl.h */
6851
/**
6852
 * @file url_components.h
6853
 * @brief Declaration for the URL Components
6854
 */
6855
#ifndef ADA_URL_COMPONENTS_INL_H
6856
#define ADA_URL_COMPONENTS_INL_H
6857
6858
6859
namespace ada {
6860
6861
[[nodiscard]] constexpr bool url_components::check_offset_consistency()
6862
9.56k
    const noexcept {
6863
  /**
6864
   * https://user:pass@example.com:1234/foo/bar?baz#quux
6865
   *       |     |    |          | ^^^^|       |   |
6866
   *       |     |    |          | |   |       |   `----- hash_start
6867
   *       |     |    |          | |   |       `--------- search_start
6868
   *       |     |    |          | |   `----------------- pathname_start
6869
   *       |     |    |          | `--------------------- port
6870
   *       |     |    |          `----------------------- host_end
6871
   *       |     |    `---------------------------------- host_start
6872
   *       |     `--------------------------------------- username_end
6873
   *       `--------------------------------------------- protocol_end
6874
   */
6875
  // These conditions can be made more strict.
6876
9.56k
  if (protocol_end == url_components::omitted) {
6877
0
    return false;
6878
0
  }
6879
9.56k
  uint32_t index = protocol_end;
6880
6881
9.56k
  if (username_end == url_components::omitted) {
6882
0
    return false;
6883
0
  }
6884
9.56k
  if (username_end < index) {
6885
0
    return false;
6886
0
  }
6887
9.56k
  index = username_end;
6888
6889
9.56k
  if (host_start == url_components::omitted) {
6890
0
    return false;
6891
0
  }
6892
9.56k
  if (host_start < index) {
6893
0
    return false;
6894
0
  }
6895
9.56k
  index = host_start;
6896
6897
9.56k
  if (port != url_components::omitted) {
6898
950
    if (port > 0xffff) {
6899
0
      return false;
6900
0
    }
6901
950
    uint32_t port_length = helpers::fast_digit_count(port) + 1;
6902
950
    if (index + port_length < index) {
6903
0
      return false;
6904
0
    }
6905
950
    index += port_length;
6906
950
  }
6907
6908
9.56k
  if (pathname_start == url_components::omitted) {
6909
0
    return false;
6910
0
  }
6911
9.56k
  if (pathname_start < index) {
6912
0
    return false;
6913
0
  }
6914
9.56k
  index = pathname_start;
6915
6916
9.56k
  if (search_start != url_components::omitted) {
6917
6.66k
    if (search_start < index) {
6918
0
      return false;
6919
0
    }
6920
6.66k
    index = search_start;
6921
6.66k
  }
6922
6923
9.56k
  if (hash_start != url_components::omitted) {
6924
6.61k
    if (hash_start < index) {
6925
0
      return false;
6926
0
    }
6927
6.61k
  }
6928
6929
9.56k
  return true;
6930
9.56k
}
6931
6932
}  // namespace ada
6933
#endif
6934
/* end file include/ada/url_components-inl.h */
6935
/* begin file include/ada/url_aggregator.h */
6936
/**
6937
 * @file url_aggregator.h
6938
 * @brief Declaration for the basic URL definitions
6939
 */
6940
#ifndef ADA_URL_AGGREGATOR_H
6941
#define ADA_URL_AGGREGATOR_H
6942
6943
#include <ostream>
6944
#include <string>
6945
#include <string_view>
6946
#include <variant>
6947
6948
6949
namespace ada {
6950
6951
namespace parser {}
6952
6953
/**
6954
 * @brief Lightweight URL struct.
6955
 *
6956
 * @details The url_aggregator class aims to minimize temporary memory
6957
 * allocation while representing a parsed URL. Internally, it contains a single
6958
 * normalized URL (the href), and it makes available the components, mostly
6959
 * using std::string_view.
6960
 */
6961
struct url_aggregator : url_base {
6962
21.4k
  url_aggregator() = default;
6963
0
  url_aggregator(const url_aggregator &u) = default;
6964
15.3k
  url_aggregator(url_aggregator &&u) noexcept = default;
6965
0
  url_aggregator &operator=(url_aggregator &&u) noexcept = default;
6966
3.05k
  url_aggregator &operator=(const url_aggregator &u) = default;
6967
36.7k
  ~url_aggregator() override = default;
6968
6969
  bool set_href(std::string_view input);
6970
  bool set_host(std::string_view input);
6971
  bool set_hostname(std::string_view input);
6972
  bool set_protocol(std::string_view input);
6973
  bool set_username(std::string_view input);
6974
  bool set_password(std::string_view input);
6975
  bool set_port(std::string_view input);
6976
  bool set_pathname(std::string_view input);
6977
  void set_search(std::string_view input);
6978
  void set_hash(std::string_view input);
6979
6980
  [[nodiscard]] bool has_valid_domain() const noexcept override;
6981
  /**
6982
   * The origin getter steps are to return the serialization of this's URL's
6983
   * origin. [HTML]
6984
   * @return a newly allocated string.
6985
   * @see https://url.spec.whatwg.org/#concept-url-origin
6986
   */
6987
  [[nodiscard]] std::string get_origin() const noexcept override;
6988
  /**
6989
   * Return the normalized string.
6990
   * This function does not allocate memory.
6991
   * It is highly efficient.
6992
   * @return a constant reference to the underlying normalized URL.
6993
   * @see https://url.spec.whatwg.org/#dom-url-href
6994
   * @see https://url.spec.whatwg.org/#concept-url-serializer
6995
   */
6996
  [[nodiscard]] constexpr std::string_view get_href() const noexcept
6997
      ada_lifetime_bound;
6998
  /**
6999
   * The username getter steps are to return this's URL's username.
7000
   * This function does not allocate memory.
7001
   * @return a lightweight std::string_view.
7002
   * @see https://url.spec.whatwg.org/#dom-url-username
7003
   */
7004
  [[nodiscard]] std::string_view get_username() const noexcept
7005
      ada_lifetime_bound;
7006
  /**
7007
   * The password getter steps are to return this's URL's password.
7008
   * This function does not allocate memory.
7009
   * @return a lightweight std::string_view.
7010
   * @see https://url.spec.whatwg.org/#dom-url-password
7011
   */
7012
  [[nodiscard]] std::string_view get_password() const noexcept
7013
      ada_lifetime_bound;
7014
  /**
7015
   * Return this's URL's port, serialized.
7016
   * This function does not allocate memory.
7017
   * @return a lightweight std::string_view.
7018
   * @see https://url.spec.whatwg.org/#dom-url-port
7019
   */
7020
  [[nodiscard]] std::string_view get_port() const noexcept ada_lifetime_bound;
7021
  /**
7022
   * Return U+0023 (#), followed by this's URL's fragment.
7023
   * This function does not allocate memory.
7024
   * @return a lightweight std::string_view..
7025
   * @see https://url.spec.whatwg.org/#dom-url-hash
7026
   */
7027
  [[nodiscard]] std::string_view get_hash() const noexcept ada_lifetime_bound;
7028
  /**
7029
   * Return url's host, serialized, followed by U+003A (:) and url's port,
7030
   * serialized.
7031
   * This function does not allocate memory.
7032
   * When there is no host, this function returns the empty view.
7033
   * @return a lightweight std::string_view.
7034
   * @see https://url.spec.whatwg.org/#dom-url-host
7035
   */
7036
  [[nodiscard]] std::string_view get_host() const noexcept ada_lifetime_bound;
7037
  /**
7038
   * Return this's URL's host, serialized.
7039
   * This function does not allocate memory.
7040
   * When there is no host, this function returns the empty view.
7041
   * @return a lightweight std::string_view.
7042
   * @see https://url.spec.whatwg.org/#dom-url-hostname
7043
   */
7044
  [[nodiscard]] std::string_view get_hostname() const noexcept
7045
      ada_lifetime_bound;
7046
  /**
7047
   * The pathname getter steps are to return the result of URL path serializing
7048
   * this's URL.
7049
   * This function does not allocate memory.
7050
   * @return a lightweight std::string_view.
7051
   * @see https://url.spec.whatwg.org/#dom-url-pathname
7052
   */
7053
  [[nodiscard]] constexpr std::string_view get_pathname() const noexcept
7054
      ada_lifetime_bound;
7055
  /**
7056
   * Compute the pathname length in bytes without instantiating a view or a
7057
   * string.
7058
   * @return size of the pathname in bytes
7059
   * @see https://url.spec.whatwg.org/#dom-url-pathname
7060
   */
7061
  [[nodiscard]] ada_really_inline uint32_t get_pathname_length() const noexcept;
7062
  /**
7063
   * Return U+003F (?), followed by this's URL's query.
7064
   * This function does not allocate memory.
7065
   * @return a lightweight std::string_view.
7066
   * @see https://url.spec.whatwg.org/#dom-url-search
7067
   */
7068
  [[nodiscard]] std::string_view get_search() const noexcept ada_lifetime_bound;
7069
  /**
7070
   * The protocol getter steps are to return this's URL's scheme, followed by
7071
   * U+003A (:).
7072
   * This function does not allocate memory.
7073
   * @return a lightweight std::string_view.
7074
   * @see https://url.spec.whatwg.org/#dom-url-protocol
7075
   */
7076
  [[nodiscard]] std::string_view get_protocol() const noexcept
7077
      ada_lifetime_bound;
7078
7079
  /**
7080
   * A URL includes credentials if its username or password is not the empty
7081
   * string.
7082
   */
7083
  [[nodiscard]] ada_really_inline constexpr bool has_credentials()
7084
      const noexcept;
7085
7086
  /**
7087
   * Useful for implementing efficient serialization for the URL.
7088
   *
7089
   * https://user:pass@example.com:1234/foo/bar?baz#quux
7090
   *       |     |    |          | ^^^^|       |   |
7091
   *       |     |    |          | |   |       |   `----- hash_start
7092
   *       |     |    |          | |   |       `--------- search_start
7093
   *       |     |    |          | |   `----------------- pathname_start
7094
   *       |     |    |          | `--------------------- port
7095
   *       |     |    |          `----------------------- host_end
7096
   *       |     |    `---------------------------------- host_start
7097
   *       |     `--------------------------------------- username_end
7098
   *       `--------------------------------------------- protocol_end
7099
   *
7100
   * Inspired after servo/url
7101
   *
7102
   * @return a constant reference to the underlying component attribute.
7103
   *
7104
   * @see
7105
   * https://github.com/servo/rust-url/blob/b65a45515c10713f6d212e6726719a020203cc98/url/src/quirks.rs#L31
7106
   */
7107
  [[nodiscard]] ada_really_inline const url_components &get_components()
7108
      const noexcept;
7109
  /**
7110
   * Returns a string representation of this URL.
7111
   */
7112
  [[nodiscard]] std::string to_string() const override;
7113
  /**
7114
   * Returns a string diagram of this URL.
7115
   */
7116
  [[nodiscard]] std::string to_diagram() const;
7117
7118
  /**
7119
   * Verifies that the parsed URL could be valid. Useful for debugging purposes.
7120
   * @return true if the URL is valid, otherwise return true of the offsets are
7121
   * possible.
7122
   */
7123
  [[nodiscard]] constexpr bool validate() const noexcept;
7124
7125
  /** @return true if it has an host but it is the empty string */
7126
  [[nodiscard]] constexpr bool has_empty_hostname() const noexcept;
7127
  /** @return true if it has a host (included an empty host) */
7128
  [[nodiscard]] constexpr bool has_hostname() const noexcept;
7129
  /** @return true if the URL has a non-empty username */
7130
  [[nodiscard]] constexpr bool has_non_empty_username() const noexcept;
7131
  /** @return true if the URL has a non-empty password */
7132
  [[nodiscard]] constexpr bool has_non_empty_password() const noexcept;
7133
  /** @return true if the URL has a (non default) port */
7134
  [[nodiscard]] constexpr bool has_port() const noexcept;
7135
  /** @return true if the URL has a password */
7136
  [[nodiscard]] constexpr bool has_password() const noexcept;
7137
  /** @return true if the URL has a hash component */
7138
  [[nodiscard]] constexpr bool has_hash() const noexcept override;
7139
  /** @return true if the URL has a search component */
7140
  [[nodiscard]] constexpr bool has_search() const noexcept override;
7141
7142
  inline void clear_port();
7143
  inline void clear_hash();
7144
  inline void clear_search() override;
7145
7146
 private:
7147
  // helper methods
7148
  friend void helpers::strip_trailing_spaces_from_opaque_path<url_aggregator>(
7149
      url_aggregator &url) noexcept;
7150
  // parse_url methods
7151
  friend url_aggregator parser::parse_url<url_aggregator>(
7152
      std::string_view, const url_aggregator *);
7153
7154
  friend url_aggregator parser::parse_url_impl<url_aggregator, true>(
7155
      std::string_view, const url_aggregator *);
7156
  friend url_aggregator parser::parse_url_impl<url_aggregator, false>(
7157
      std::string_view, const url_aggregator *);
7158
7159
#if ADA_INCLUDE_URL_PATTERN
7160
  // url_pattern methods
7161
  template <url_pattern_regex::regex_concept regex_provider>
7162
  friend tl::expected<url_pattern<regex_provider>, errors>
7163
  parse_url_pattern_impl(
7164
      std::variant<std::string_view, url_pattern_init> &&input,
7165
      const std::string_view *base_url, const url_pattern_options *options);
7166
#endif  // ADA_INCLUDE_URL_PATTERN
7167
7168
  std::string buffer{};
7169
  url_components components{};
7170
7171
  /**
7172
   * Returns true if neither the search, nor the hash nor the pathname
7173
   * have been set.
7174
   * @return true if the buffer is ready to receive the path.
7175
   */
7176
  [[nodiscard]] ada_really_inline bool is_at_path() const noexcept;
7177
7178
  inline void add_authority_slashes_if_needed() noexcept;
7179
7180
  /**
7181
   * To optimize performance, you may indicate how much memory to allocate
7182
   * within this instance.
7183
   */
7184
  constexpr void reserve(uint32_t capacity);
7185
7186
  ada_really_inline size_t parse_port(
7187
      std::string_view view, bool check_trailing_content) noexcept override;
7188
7189
1.45k
  ada_really_inline size_t parse_port(std::string_view view) noexcept override {
7190
1.45k
    return this->parse_port(view, false);
7191
1.45k
  }
7192
7193
  /**
7194
   * Return true on success. The 'in_place' parameter indicates whether the
7195
   * the string_view input is pointing in the buffer. When in_place is false,
7196
   * we must nearly always update the buffer.
7197
   * @see https://url.spec.whatwg.org/#concept-ipv4-parser
7198
   */
7199
  [[nodiscard]] bool parse_ipv4(std::string_view input, bool in_place);
7200
7201
  /**
7202
   * Return true on success.
7203
   * @see https://url.spec.whatwg.org/#concept-ipv6-parser
7204
   */
7205
  [[nodiscard]] bool parse_ipv6(std::string_view input);
7206
7207
  /**
7208
   * Return true on success.
7209
   * @see https://url.spec.whatwg.org/#concept-opaque-host-parser
7210
   */
7211
  [[nodiscard]] bool parse_opaque_host(std::string_view input);
7212
7213
  ada_really_inline void parse_path(std::string_view input);
7214
7215
  /**
7216
   * A URL cannot have a username/password/port if its host is null or the empty
7217
   * string, or its scheme is "file".
7218
   */
7219
  [[nodiscard]] constexpr bool cannot_have_credentials_or_port() const;
7220
7221
  template <bool override_hostname = false>
7222
  bool set_host_or_hostname(std::string_view input);
7223
7224
  ada_really_inline bool parse_host(std::string_view input);
7225
7226
  inline void update_base_authority(std::string_view base_buffer,
7227
                                    const url_components &base);
7228
  inline void update_unencoded_base_hash(std::string_view input);
7229
  inline void update_base_hostname(std::string_view input);
7230
  inline void update_base_search(std::string_view input);
7231
  inline void update_base_search(std::string_view input,
7232
                                 const uint8_t *query_percent_encode_set);
7233
  inline void update_base_pathname(std::string_view input);
7234
  inline void update_base_username(std::string_view input);
7235
  inline void append_base_username(std::string_view input);
7236
  inline void update_base_password(std::string_view input);
7237
  inline void append_base_password(std::string_view input);
7238
  inline void update_base_port(uint32_t input);
7239
  inline void append_base_pathname(std::string_view input);
7240
  [[nodiscard]] inline uint32_t retrieve_base_port() const;
7241
  constexpr void clear_hostname();
7242
  constexpr void clear_password();
7243
  constexpr void clear_pathname() override;
7244
  [[nodiscard]] constexpr bool has_dash_dot() const noexcept;
7245
  void delete_dash_dot();
7246
  inline void consume_prepared_path(std::string_view input);
7247
  template <bool has_state_override = false>
7248
  [[nodiscard]] ada_really_inline bool parse_scheme_with_colon(
7249
      std::string_view input);
7250
  ada_really_inline uint32_t replace_and_resize(uint32_t start, uint32_t end,
7251
                                                std::string_view input);
7252
  [[nodiscard]] constexpr bool has_authority() const noexcept;
7253
  constexpr void set_protocol_as_file();
7254
  inline void set_scheme(std::string_view new_scheme) noexcept;
7255
  /**
7256
   * Fast function to set the scheme from a view with a colon in the
7257
   * buffer, does not change type.
7258
   */
7259
  inline void set_scheme_from_view_with_colon(
7260
      std::string_view new_scheme_with_colon) noexcept;
7261
  inline void copy_scheme(const url_aggregator &u) noexcept;
7262
7263
  inline void update_host_to_base_host(const std::string_view input) noexcept;
7264
7265
};  // url_aggregator
7266
7267
inline std::ostream &operator<<(std::ostream &out, const url &u);
7268
}  // namespace ada
7269
7270
#endif
7271
/* end file include/ada/url_aggregator.h */
7272
/* begin file include/ada/url_aggregator-inl.h */
7273
/**
7274
 * @file url_aggregator-inl.h
7275
 * @brief Inline functions for url aggregator
7276
 */
7277
#ifndef ADA_URL_AGGREGATOR_INL_H
7278
#define ADA_URL_AGGREGATOR_INL_H
7279
7280
/* begin file include/ada/unicode-inl.h */
7281
/**
7282
 * @file unicode-inl.h
7283
 * @brief Definitions for unicode operations.
7284
 */
7285
#ifndef ADA_UNICODE_INL_H
7286
#define ADA_UNICODE_INL_H
7287
7288
/**
7289
 * Unicode operations. These functions are not part of our public API and may
7290
 * change at any time.
7291
 *
7292
 * private
7293
 * @namespace ada::unicode
7294
 * @brief Includes the declarations for unicode operations
7295
 */
7296
namespace ada::unicode {
7297
ada_really_inline size_t percent_encode_index(const std::string_view input,
7298
16.7k
                                              const uint8_t character_set[]) {
7299
16.7k
  const char* data = input.data();
7300
16.7k
  const size_t size = input.size();
7301
7302
  // Process 8 bytes at a time using unrolled loop
7303
16.7k
  size_t i = 0;
7304
24.5k
  for (; i + 8 <= size; i += 8) {
7305
16.8k
    unsigned char chunk[8];
7306
16.8k
    std::memcpy(&chunk, data + i,
7307
16.8k
                8);  // entices compiler to unconditionally process 8 characters
7308
7309
    // Check 8 characters at once
7310
93.5k
    for (size_t j = 0; j < 8; j++) {
7311
85.7k
      if (character_sets::bit_at(character_set, chunk[j])) {
7312
9.01k
        return i + j;
7313
9.01k
      }
7314
85.7k
    }
7315
16.8k
  }
7316
7317
  // Handle remaining bytes
7318
20.1k
  for (; i < size; i++) {
7319
17.9k
    if (character_sets::bit_at(character_set, data[i])) {
7320
5.44k
      return i;
7321
5.44k
    }
7322
17.9k
  }
7323
7324
2.26k
  return size;
7325
7.71k
}
7326
}  // namespace ada::unicode
7327
7328
#endif  // ADA_UNICODE_INL_H
7329
/* end file include/ada/unicode-inl.h */
7330
7331
#include <charconv>
7332
#include <ostream>
7333
#include <string_view>
7334
7335
namespace ada {
7336
7337
inline void url_aggregator::update_base_authority(
7338
0
    std::string_view base_buffer, const ada::url_components &base) {
7339
0
  std::string_view input = base_buffer.substr(
7340
0
      base.protocol_end, base.host_start - base.protocol_end);
7341
0
  ada_log("url_aggregator::update_base_authority ", input);
7342
7343
0
  bool input_starts_with_dash = input.starts_with("//");
7344
0
  uint32_t diff = components.host_start - components.protocol_end;
7345
7346
0
  buffer.erase(components.protocol_end,
7347
0
               components.host_start - components.protocol_end);
7348
0
  components.username_end = components.protocol_end;
7349
7350
0
  if (input_starts_with_dash) {
7351
0
    input.remove_prefix(2);
7352
0
    diff += 2;  // add "//"
7353
0
    buffer.insert(components.protocol_end, "//");
7354
0
    components.username_end += 2;
7355
0
  }
7356
7357
0
  size_t password_delimiter = input.find(':');
7358
7359
  // Check if input contains both username and password by checking the
7360
  // delimiter: ":" A typical input that contains authority would be "user:pass"
7361
0
  if (password_delimiter != std::string_view::npos) {
7362
    // Insert both username and password
7363
0
    std::string_view username = input.substr(0, password_delimiter);
7364
0
    std::string_view password = input.substr(password_delimiter + 1);
7365
7366
0
    buffer.insert(components.protocol_end + diff, username);
7367
0
    diff += uint32_t(username.size());
7368
0
    buffer.insert(components.protocol_end + diff, ":");
7369
0
    components.username_end = components.protocol_end + diff;
7370
0
    buffer.insert(components.protocol_end + diff + 1, password);
7371
0
    diff += uint32_t(password.size()) + 1;
7372
0
  } else if (!input.empty()) {
7373
    // Insert only username
7374
0
    buffer.insert(components.protocol_end + diff, input);
7375
0
    components.username_end =
7376
0
        components.protocol_end + diff + uint32_t(input.size());
7377
0
    diff += uint32_t(input.size());
7378
0
  }
7379
7380
0
  components.host_start += diff;
7381
7382
0
  if (buffer.size() > base.host_start && buffer[base.host_start] != '@') {
7383
0
    buffer.insert(components.host_start, "@");
7384
0
    diff++;
7385
0
  }
7386
0
  components.host_end += diff;
7387
0
  components.pathname_start += diff;
7388
0
  if (components.search_start != url_components::omitted) {
7389
0
    components.search_start += diff;
7390
0
  }
7391
0
  if (components.hash_start != url_components::omitted) {
7392
0
    components.hash_start += diff;
7393
0
  }
7394
0
}
7395
7396
9.19k
inline void url_aggregator::update_unencoded_base_hash(std::string_view input) {
7397
9.19k
  ada_log("url_aggregator::update_unencoded_base_hash ", input, " [",
7398
9.19k
          input.size(), " bytes], buffer is '", buffer, "' [", buffer.size(),
7399
9.19k
          " bytes] components.hash_start = ", components.hash_start);
7400
9.19k
  ADA_ASSERT_TRUE(validate());
7401
9.19k
  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
7402
9.19k
  if (components.hash_start != url_components::omitted) {
7403
0
    buffer.resize(components.hash_start);
7404
0
  }
7405
9.19k
  components.hash_start = uint32_t(buffer.size());
7406
9.19k
  buffer += "#";
7407
9.19k
  bool encoding_required = unicode::percent_encode<true>(
7408
9.19k
      input, ada::character_sets::FRAGMENT_PERCENT_ENCODE, buffer);
7409
  // When encoding_required is false, then buffer is left unchanged, and percent
7410
  // encoding was not deemed required.
7411
9.19k
  if (!encoding_required) {
7412
3.97k
    buffer.append(input);
7413
3.97k
  }
7414
9.19k
  ada_log("url_aggregator::update_unencoded_base_hash final buffer is '",
7415
9.19k
          buffer, "' [", buffer.size(), " bytes]");
7416
9.19k
  ADA_ASSERT_TRUE(validate());
7417
9.19k
}
7418
7419
ada_really_inline uint32_t url_aggregator::replace_and_resize(
7420
57.1k
    uint32_t start, uint32_t end, std::string_view input) {
7421
57.1k
  uint32_t current_length = end - start;
7422
57.1k
  uint32_t input_size = uint32_t(input.size());
7423
57.1k
  uint32_t new_difference = input_size - current_length;
7424
7425
57.1k
  if (current_length == 0) {
7426
42.4k
    buffer.insert(start, input);
7427
42.4k
  } else if (input_size == current_length) {
7428
2.05k
    buffer.replace(start, input_size, input);
7429
12.6k
  } else if (input_size < current_length) {
7430
10.3k
    buffer.erase(start, current_length - input_size);
7431
10.3k
    buffer.replace(start, input_size, input);
7432
10.3k
  } else {
7433
2.29k
    buffer.replace(start, current_length, input.substr(0, current_length));
7434
2.29k
    buffer.insert(start + current_length, input.substr(current_length));
7435
2.29k
  }
7436
7437
57.1k
  return new_difference;
7438
57.1k
}
7439
7440
27.5k
inline void url_aggregator::update_base_hostname(const std::string_view input) {
7441
27.5k
  ada_log("url_aggregator::update_base_hostname ", input, " [", input.size(),
7442
27.5k
          " bytes], buffer is '", buffer, "' [", buffer.size(), " bytes]");
7443
27.5k
  ADA_ASSERT_TRUE(validate());
7444
27.5k
  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
7445
7446
  // This next line is required for when parsing a URL like `foo://`
7447
27.5k
  add_authority_slashes_if_needed();
7448
7449
27.5k
  bool has_credentials = components.protocol_end + 2 < components.host_start;
7450
27.5k
  uint32_t new_difference =
7451
27.5k
      replace_and_resize(components.host_start, components.host_end, input);
7452
7453
27.5k
  if (has_credentials) {
7454
12.9k
    buffer.insert(components.host_start, "@");
7455
12.9k
    new_difference++;
7456
12.9k
  }
7457
27.5k
  components.host_end += new_difference;
7458
27.5k
  components.pathname_start += new_difference;
7459
27.5k
  if (components.search_start != url_components::omitted) {
7460
0
    components.search_start += new_difference;
7461
0
  }
7462
27.5k
  if (components.hash_start != url_components::omitted) {
7463
0
    components.hash_start += new_difference;
7464
0
  }
7465
27.5k
  ADA_ASSERT_TRUE(validate());
7466
27.5k
}
7467
7468
[[nodiscard]] ada_really_inline uint32_t
7469
21.4k
url_aggregator::get_pathname_length() const noexcept {
7470
21.4k
  ada_log("url_aggregator::get_pathname_length");
7471
21.4k
  uint32_t ending_index = uint32_t(buffer.size());
7472
21.4k
  if (components.search_start != url_components::omitted) {
7473
0
    ending_index = components.search_start;
7474
21.4k
  } else if (components.hash_start != url_components::omitted) {
7475
0
    ending_index = components.hash_start;
7476
0
  }
7477
21.4k
  return ending_index - components.pathname_start;
7478
21.4k
}
7479
7480
[[nodiscard]] ada_really_inline bool url_aggregator::is_at_path()
7481
2.63k
    const noexcept {
7482
2.63k
  return buffer.size() == components.pathname_start;
7483
2.63k
}
7484
7485
0
inline void url_aggregator::update_base_search(std::string_view input) {
7486
0
  ada_log("url_aggregator::update_base_search ", input);
7487
0
  ADA_ASSERT_TRUE(validate());
7488
0
  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
7489
0
  if (input.empty()) {
7490
0
    clear_search();
7491
0
    return;
7492
0
  }
7493
7494
0
  if (input[0] == '?') {
7495
0
    input.remove_prefix(1);
7496
0
  }
7497
7498
0
  if (components.hash_start == url_components::omitted) {
7499
0
    if (components.search_start == url_components::omitted) {
7500
0
      components.search_start = uint32_t(buffer.size());
7501
0
      buffer += "?";
7502
0
    } else {
7503
0
      buffer.resize(components.search_start + 1);
7504
0
    }
7505
7506
0
    buffer.append(input);
7507
0
  } else {
7508
0
    if (components.search_start == url_components::omitted) {
7509
0
      components.search_start = components.hash_start;
7510
0
    } else {
7511
0
      buffer.erase(components.search_start,
7512
0
                   components.hash_start - components.search_start);
7513
0
      components.hash_start = components.search_start;
7514
0
    }
7515
7516
0
    buffer.insert(components.search_start, "?");
7517
0
    buffer.insert(components.search_start + 1, input);
7518
0
    components.hash_start += uint32_t(input.size() + 1);  // Do not forget `?`
7519
0
  }
7520
7521
0
  ADA_ASSERT_TRUE(validate());
7522
0
}
7523
7524
inline void url_aggregator::update_base_search(
7525
9.29k
    std::string_view input, const uint8_t query_percent_encode_set[]) {
7526
9.29k
  ada_log("url_aggregator::update_base_search ", input,
7527
9.29k
          " with encoding parameter ", to_string(), "\n", to_diagram());
7528
9.29k
  ADA_ASSERT_TRUE(validate());
7529
9.29k
  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
7530
7531
9.29k
  if (components.hash_start == url_components::omitted) {
7532
9.29k
    if (components.search_start == url_components::omitted) {
7533
9.29k
      components.search_start = uint32_t(buffer.size());
7534
9.29k
      buffer += "?";
7535
9.29k
    } else {
7536
0
      buffer.resize(components.search_start + 1);
7537
0
    }
7538
7539
9.29k
    bool encoding_required =
7540
9.29k
        unicode::percent_encode<true>(input, query_percent_encode_set, buffer);
7541
    // When encoding_required is false, then buffer is left unchanged, and
7542
    // percent encoding was not deemed required.
7543
9.29k
    if (!encoding_required) {
7544
3.92k
      buffer.append(input);
7545
3.92k
    }
7546
9.29k
  } else {
7547
0
    if (components.search_start == url_components::omitted) {
7548
0
      components.search_start = components.hash_start;
7549
0
    } else {
7550
0
      buffer.erase(components.search_start,
7551
0
                   components.hash_start - components.search_start);
7552
0
      components.hash_start = components.search_start;
7553
0
    }
7554
7555
0
    buffer.insert(components.search_start, "?");
7556
0
    size_t idx =
7557
0
        ada::unicode::percent_encode_index(input, query_percent_encode_set);
7558
0
    if (idx == input.size()) {
7559
0
      buffer.insert(components.search_start + 1, input);
7560
0
      components.hash_start += uint32_t(input.size() + 1);  // Do not forget `?`
7561
0
    } else {
7562
0
      buffer.insert(components.search_start + 1, input, 0, idx);
7563
0
      input.remove_prefix(idx);
7564
      // We only create a temporary string if we need percent encoding and
7565
      // we attempt to create as small a temporary string as we can.
7566
0
      std::string encoded =
7567
0
          ada::unicode::percent_encode(input, query_percent_encode_set);
7568
0
      buffer.insert(components.search_start + idx + 1, encoded);
7569
0
      components.hash_start +=
7570
0
          uint32_t(encoded.size() + idx + 1);  // Do not forget `?`
7571
0
    }
7572
0
  }
7573
7574
9.29k
  ADA_ASSERT_TRUE(validate());
7575
9.29k
}
7576
7577
21.4k
inline void url_aggregator::update_base_pathname(const std::string_view input) {
7578
21.4k
  ada_log("url_aggregator::update_base_pathname '", input, "' [", input.size(),
7579
21.4k
          " bytes] \n", to_diagram());
7580
21.4k
  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
7581
21.4k
  ADA_ASSERT_TRUE(validate());
7582
7583
21.4k
  const bool begins_with_dashdash = input.starts_with("//");
7584
21.4k
  if (!begins_with_dashdash && has_dash_dot()) {
7585
    // We must delete the ./
7586
0
    delete_dash_dot();
7587
0
  }
7588
7589
21.4k
  if (begins_with_dashdash && !has_opaque_path && !has_authority() &&
7590
43
      !has_dash_dot()) {
7591
    // If url's host is null, url does not have an opaque path, url's path's
7592
    // size is greater than 1, then append U+002F (/) followed by U+002E (.) to
7593
    // output.
7594
43
    buffer.insert(components.pathname_start, "/.");
7595
43
    components.pathname_start += 2;
7596
43
  }
7597
7598
21.4k
  uint32_t difference = replace_and_resize(
7599
21.4k
      components.pathname_start,
7600
21.4k
      components.pathname_start + get_pathname_length(), input);
7601
21.4k
  if (components.search_start != url_components::omitted) {
7602
0
    components.search_start += difference;
7603
0
  }
7604
21.4k
  if (components.hash_start != url_components::omitted) {
7605
0
    components.hash_start += difference;
7606
0
  }
7607
21.4k
  ADA_ASSERT_TRUE(validate());
7608
21.4k
}
7609
7610
0
inline void url_aggregator::append_base_pathname(const std::string_view input) {
7611
0
  ada_log("url_aggregator::append_base_pathname ", input, " ", to_string(),
7612
0
          "\n", to_diagram());
7613
0
  ADA_ASSERT_TRUE(validate());
7614
0
  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
7615
#if ADA_DEVELOPMENT_CHECKS
7616
  // computing the expected password.
7617
  std::string path_expected(get_pathname());
7618
  path_expected.append(input);
7619
#endif  // ADA_DEVELOPMENT_CHECKS
7620
0
  uint32_t ending_index = uint32_t(buffer.size());
7621
0
  if (components.search_start != url_components::omitted) {
7622
0
    ending_index = components.search_start;
7623
0
  } else if (components.hash_start != url_components::omitted) {
7624
0
    ending_index = components.hash_start;
7625
0
  }
7626
0
  buffer.insert(ending_index, input);
7627
7628
0
  if (components.search_start != url_components::omitted) {
7629
0
    components.search_start += uint32_t(input.size());
7630
0
  }
7631
0
  if (components.hash_start != url_components::omitted) {
7632
0
    components.hash_start += uint32_t(input.size());
7633
0
  }
7634
#if ADA_DEVELOPMENT_CHECKS
7635
  std::string path_after = std::string(get_pathname());
7636
  ADA_ASSERT_EQUAL(
7637
      path_expected, path_after,
7638
      "append_base_pathname problem after inserting " + std::string(input));
7639
#endif  // ADA_DEVELOPMENT_CHECKS
7640
0
  ADA_ASSERT_TRUE(validate());
7641
0
}
7642
7643
8.24k
inline void url_aggregator::update_base_username(const std::string_view input) {
7644
8.24k
  ada_log("url_aggregator::update_base_username '", input, "' ", to_string(),
7645
8.24k
          "\n", to_diagram());
7646
8.24k
  ADA_ASSERT_TRUE(validate());
7647
8.24k
  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
7648
7649
8.24k
  add_authority_slashes_if_needed();
7650
7651
8.24k
  bool has_password = has_non_empty_password();
7652
8.24k
  bool host_starts_with_at = buffer.size() > components.host_start &&
7653
8.24k
                             buffer[components.host_start] == '@';
7654
8.24k
  uint32_t diff = replace_and_resize(components.protocol_end + 2,
7655
8.24k
                                     components.username_end, input);
7656
7657
8.24k
  components.username_end += diff;
7658
8.24k
  components.host_start += diff;
7659
7660
8.24k
  if (!input.empty() && !host_starts_with_at) {
7661
8.23k
    buffer.insert(components.host_start, "@");
7662
8.23k
    diff++;
7663
8.23k
  } else if (input.empty() && host_starts_with_at && !has_password) {
7664
    // Input is empty, there is no password, and we need to remove "@" from
7665
    // hostname
7666
0
    buffer.erase(components.host_start, 1);
7667
0
    diff--;
7668
0
  }
7669
7670
8.24k
  components.host_end += diff;
7671
8.24k
  components.pathname_start += diff;
7672
8.24k
  if (components.search_start != url_components::omitted) {
7673
0
    components.search_start += diff;
7674
0
  }
7675
8.24k
  if (components.hash_start != url_components::omitted) {
7676
0
    components.hash_start += diff;
7677
0
  }
7678
8.24k
  ADA_ASSERT_TRUE(validate());
7679
8.24k
}
7680
7681
8.99k
inline void url_aggregator::append_base_username(const std::string_view input) {
7682
8.99k
  ada_log("url_aggregator::append_base_username ", input);
7683
8.99k
  ADA_ASSERT_TRUE(validate());
7684
8.99k
  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
7685
#if ADA_DEVELOPMENT_CHECKS
7686
  // computing the expected password.
7687
  std::string username_expected(get_username());
7688
  username_expected.append(input);
7689
#endif  // ADA_DEVELOPMENT_CHECKS
7690
8.99k
  add_authority_slashes_if_needed();
7691
7692
  // If input is empty, do nothing.
7693
8.99k
  if (input.empty()) {
7694
3.24k
    return;
7695
3.24k
  }
7696
7697
5.75k
  uint32_t difference = uint32_t(input.size());
7698
5.75k
  buffer.insert(components.username_end, input);
7699
5.75k
  components.username_end += difference;
7700
5.75k
  components.host_start += difference;
7701
7702
5.75k
  if (buffer[components.host_start] != '@' &&
7703
509
      components.host_start != components.host_end) {
7704
509
    buffer.insert(components.host_start, "@");
7705
509
    difference++;
7706
509
  }
7707
7708
5.75k
  components.host_end += difference;
7709
5.75k
  components.pathname_start += difference;
7710
5.75k
  if (components.search_start != url_components::omitted) {
7711
0
    components.search_start += difference;
7712
0
  }
7713
5.75k
  if (components.hash_start != url_components::omitted) {
7714
0
    components.hash_start += difference;
7715
0
  }
7716
#if ADA_DEVELOPMENT_CHECKS
7717
  std::string username_after(get_username());
7718
  ADA_ASSERT_EQUAL(
7719
      username_expected, username_after,
7720
      "append_base_username problem after inserting " + std::string(input));
7721
#endif  // ADA_DEVELOPMENT_CHECKS
7722
5.75k
  ADA_ASSERT_TRUE(validate());
7723
5.75k
}
7724
7725
3
constexpr void url_aggregator::clear_password() {
7726
3
  ada_log("url_aggregator::clear_password ", to_string());
7727
3
  ADA_ASSERT_TRUE(validate());
7728
3
  if (!has_password()) {
7729
3
    return;
7730
3
  }
7731
7732
0
  uint32_t diff = components.host_start - components.username_end;
7733
0
  buffer.erase(components.username_end, diff);
7734
0
  components.host_start -= diff;
7735
0
  components.host_end -= diff;
7736
0
  components.pathname_start -= diff;
7737
0
  if (components.search_start != url_components::omitted) {
7738
0
    components.search_start -= diff;
7739
0
  }
7740
0
  if (components.hash_start != url_components::omitted) {
7741
0
    components.hash_start -= diff;
7742
0
  }
7743
0
}
7744
7745
8.23k
inline void url_aggregator::update_base_password(const std::string_view input) {
7746
8.23k
  ada_log("url_aggregator::update_base_password ", input);
7747
8.23k
  ADA_ASSERT_TRUE(validate());
7748
8.23k
  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
7749
7750
8.23k
  add_authority_slashes_if_needed();
7751
7752
  // TODO: Optimization opportunity. Merge the following removal functions.
7753
8.23k
  if (input.empty()) {
7754
3
    clear_password();
7755
7756
    // Remove username too, if it is empty.
7757
3
    if (!has_non_empty_username()) {
7758
3
      update_base_username("");
7759
3
    }
7760
7761
3
    return;
7762
3
  }
7763
7764
8.23k
  bool password_exists = has_password();
7765
8.23k
  uint32_t difference = uint32_t(input.size());
7766
7767
8.23k
  if (password_exists) {
7768
0
    uint32_t current_length =
7769
0
        components.host_start - components.username_end - 1;
7770
0
    buffer.erase(components.username_end + 1, current_length);
7771
0
    difference -= current_length;
7772
8.23k
  } else {
7773
8.23k
    buffer.insert(components.username_end, ":");
7774
8.23k
    difference++;
7775
8.23k
  }
7776
7777
8.23k
  buffer.insert(components.username_end + 1, input);
7778
8.23k
  components.host_start += difference;
7779
7780
  // The following line is required to add "@" to hostname. When updating
7781
  // password if hostname does not start with "@", it is "update_base_password"s
7782
  // responsibility to set it.
7783
8.23k
  if (buffer[components.host_start] != '@') {
7784
0
    buffer.insert(components.host_start, "@");
7785
0
    difference++;
7786
0
  }
7787
7788
8.23k
  components.host_end += difference;
7789
8.23k
  components.pathname_start += difference;
7790
8.23k
  if (components.search_start != url_components::omitted) {
7791
0
    components.search_start += difference;
7792
0
  }
7793
8.23k
  if (components.hash_start != url_components::omitted) {
7794
0
    components.hash_start += difference;
7795
0
  }
7796
8.23k
  ADA_ASSERT_TRUE(validate());
7797
8.23k
}
7798
7799
7.02k
inline void url_aggregator::append_base_password(const std::string_view input) {
7800
7.02k
  ada_log("url_aggregator::append_base_password ", input, " ", to_string(),
7801
7.02k
          "\n", to_diagram());
7802
7.02k
  ADA_ASSERT_TRUE(validate());
7803
7.02k
  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
7804
#if ADA_DEVELOPMENT_CHECKS
7805
  // computing the expected password.
7806
  std::string password_expected = std::string(get_password());
7807
  password_expected.append(input);
7808
#endif  // ADA_DEVELOPMENT_CHECKS
7809
7.02k
  add_authority_slashes_if_needed();
7810
7811
  // If input is empty, do nothing.
7812
7.02k
  if (input.empty()) {
7813
2.41k
    return;
7814
2.41k
  }
7815
7816
4.61k
  uint32_t difference = uint32_t(input.size());
7817
4.61k
  if (has_password()) {
7818
4.30k
    buffer.insert(components.host_start, input);
7819
4.30k
  } else {
7820
308
    difference++;  // Increment for ":"
7821
308
    buffer.insert(components.username_end, ":");
7822
308
    buffer.insert(components.username_end + 1, input);
7823
308
  }
7824
4.61k
  components.host_start += difference;
7825
7826
  // The following line is required to add "@" to hostname. When updating
7827
  // password if hostname does not start with "@", it is "append_base_password"s
7828
  // responsibility to set it.
7829
4.61k
  if (buffer[components.host_start] != '@') {
7830
197
    buffer.insert(components.host_start, "@");
7831
197
    difference++;
7832
197
  }
7833
7834
4.61k
  components.host_end += difference;
7835
4.61k
  components.pathname_start += difference;
7836
4.61k
  if (components.search_start != url_components::omitted) {
7837
0
    components.search_start += difference;
7838
0
  }
7839
4.61k
  if (components.hash_start != url_components::omitted) {
7840
0
    components.hash_start += difference;
7841
0
  }
7842
#if ADA_DEVELOPMENT_CHECKS
7843
  std::string password_after(get_password());
7844
  ADA_ASSERT_EQUAL(
7845
      password_expected, password_after,
7846
      "append_base_password problem after inserting " + std::string(input));
7847
#endif  // ADA_DEVELOPMENT_CHECKS
7848
4.61k
  ADA_ASSERT_TRUE(validate());
7849
4.61k
}
7850
7851
6.83k
inline void url_aggregator::update_base_port(uint32_t input) {
7852
6.83k
  ada_log("url_aggregator::update_base_port");
7853
6.83k
  ADA_ASSERT_TRUE(validate());
7854
6.83k
  if (input == url_components::omitted) {
7855
5.75k
    clear_port();
7856
5.75k
    return;
7857
5.75k
  }
7858
  // calling std::to_string(input.value()) is unfortunate given that the port
7859
  // value is probably already available as a string.
7860
1.08k
  std::string value = helpers::concat(":", std::to_string(input));
7861
1.08k
  uint32_t difference = uint32_t(value.size());
7862
7863
1.08k
  if (components.port != url_components::omitted) {
7864
34
    difference -= components.pathname_start - components.host_end;
7865
34
    buffer.erase(components.host_end,
7866
34
                 components.pathname_start - components.host_end);
7867
34
  }
7868
7869
1.08k
  buffer.insert(components.host_end, value);
7870
1.08k
  components.pathname_start += difference;
7871
1.08k
  if (components.search_start != url_components::omitted) {
7872
562
    components.search_start += difference;
7873
562
  }
7874
1.08k
  if (components.hash_start != url_components::omitted) {
7875
562
    components.hash_start += difference;
7876
562
  }
7877
1.08k
  components.port = input;
7878
1.08k
  ADA_ASSERT_TRUE(validate());
7879
1.08k
}
7880
7881
15.0k
inline void url_aggregator::clear_port() {
7882
15.0k
  ada_log("url_aggregator::clear_port");
7883
15.0k
  ADA_ASSERT_TRUE(validate());
7884
15.0k
  if (components.port == url_components::omitted) {
7885
14.1k
    return;
7886
14.1k
  }
7887
902
  uint32_t length = components.pathname_start - components.host_end;
7888
902
  buffer.erase(components.host_end, length);
7889
902
  components.pathname_start -= length;
7890
902
  if (components.search_start != url_components::omitted) {
7891
902
    components.search_start -= length;
7892
902
  }
7893
902
  if (components.hash_start != url_components::omitted) {
7894
902
    components.hash_start -= length;
7895
902
  }
7896
902
  components.port = url_components::omitted;
7897
902
  ADA_ASSERT_TRUE(validate());
7898
902
}
7899
7900
0
[[nodiscard]] inline uint32_t url_aggregator::retrieve_base_port() const {
7901
0
  ada_log("url_aggregator::retrieve_base_port");
7902
0
  return components.port;
7903
0
}
7904
7905
8.97k
inline void url_aggregator::clear_search() {
7906
8.97k
  ada_log("url_aggregator::clear_search");
7907
8.97k
  ADA_ASSERT_TRUE(validate());
7908
8.97k
  if (components.search_start == url_components::omitted) {
7909
6
    return;
7910
6
  }
7911
7912
8.96k
  if (components.hash_start == url_components::omitted) {
7913
0
    buffer.resize(components.search_start);
7914
8.96k
  } else {
7915
8.96k
    buffer.erase(components.search_start,
7916
8.96k
                 components.hash_start - components.search_start);
7917
8.96k
    components.hash_start = components.search_start;
7918
8.96k
  }
7919
7920
8.96k
  components.search_start = url_components::omitted;
7921
7922
#if ADA_DEVELOPMENT_CHECKS
7923
  ADA_ASSERT_EQUAL(get_search(), "",
7924
                   "search should have been cleared on buffer=" + buffer +
7925
                       " with " + components.to_string() + "\n" + to_diagram());
7926
#endif
7927
8.96k
  ADA_ASSERT_TRUE(validate());
7928
8.96k
}
7929
7930
8.96k
inline void url_aggregator::clear_hash() {
7931
8.96k
  ada_log("url_aggregator::clear_hash");
7932
8.96k
  ADA_ASSERT_TRUE(validate());
7933
8.96k
  if (components.hash_start == url_components::omitted) {
7934
3
    return;
7935
3
  }
7936
8.96k
  buffer.resize(components.hash_start);
7937
8.96k
  components.hash_start = url_components::omitted;
7938
7939
#if ADA_DEVELOPMENT_CHECKS
7940
  ADA_ASSERT_EQUAL(get_hash(), "",
7941
                   "hash should have been cleared on buffer=" + buffer +
7942
                       " with " + components.to_string() + "\n" + to_diagram());
7943
#endif
7944
8.96k
  ADA_ASSERT_TRUE(validate());
7945
8.96k
}
7946
7947
8.96k
constexpr void url_aggregator::clear_pathname() {
7948
8.96k
  ada_log("url_aggregator::clear_pathname");
7949
8.96k
  ADA_ASSERT_TRUE(validate());
7950
8.96k
  uint32_t ending_index = uint32_t(buffer.size());
7951
8.96k
  if (components.search_start != url_components::omitted) {
7952
0
    ending_index = components.search_start;
7953
8.96k
  } else if (components.hash_start != url_components::omitted) {
7954
0
    ending_index = components.hash_start;
7955
0
  }
7956
8.96k
  uint32_t pathname_length = ending_index - components.pathname_start;
7957
8.96k
  buffer.erase(components.pathname_start, pathname_length);
7958
8.96k
  uint32_t difference = pathname_length;
7959
8.96k
  if (components.pathname_start == components.host_end + 2 &&
7960
320
      buffer[components.host_end] == '/' &&
7961
0
      buffer[components.host_end + 1] == '.') {
7962
0
    components.pathname_start -= 2;
7963
0
    buffer.erase(components.host_end, 2);
7964
0
    difference += 2;
7965
0
  }
7966
8.96k
  if (components.search_start != url_components::omitted) {
7967
0
    components.search_start -= difference;
7968
0
  }
7969
8.96k
  if (components.hash_start != url_components::omitted) {
7970
0
    components.hash_start -= difference;
7971
0
  }
7972
8.96k
  ada_log("url_aggregator::clear_pathname completed, running checks...");
7973
#if ADA_DEVELOPMENT_CHECKS
7974
  ADA_ASSERT_EQUAL(get_pathname(), "",
7975
                   "pathname should have been cleared on buffer=" + buffer +
7976
                       " with " + components.to_string() + "\n" + to_diagram());
7977
#endif
7978
8.96k
  ADA_ASSERT_TRUE(validate());
7979
8.96k
  ada_log("url_aggregator::clear_pathname completed, running checks... ok");
7980
8.96k
}
7981
7982
0
constexpr void url_aggregator::clear_hostname() {
7983
0
  ada_log("url_aggregator::clear_hostname");
7984
0
  ADA_ASSERT_TRUE(validate());
7985
0
  if (!has_authority()) {
7986
0
    return;
7987
0
  }
7988
0
  ADA_ASSERT_TRUE(has_authority());
7989
7990
0
  uint32_t hostname_length = components.host_end - components.host_start;
7991
0
  uint32_t start = components.host_start;
7992
7993
  // If hostname starts with "@", we should not remove that character.
7994
0
  if (hostname_length > 0 && buffer[start] == '@') {
7995
0
    start++;
7996
0
    hostname_length--;
7997
0
  }
7998
0
  buffer.erase(start, hostname_length);
7999
0
  components.host_end = start;
8000
0
  components.pathname_start -= hostname_length;
8001
0
  if (components.search_start != url_components::omitted) {
8002
0
    components.search_start -= hostname_length;
8003
0
  }
8004
0
  if (components.hash_start != url_components::omitted) {
8005
0
    components.hash_start -= hostname_length;
8006
0
  }
8007
#if ADA_DEVELOPMENT_CHECKS
8008
  ADA_ASSERT_EQUAL(get_hostname(), "",
8009
                   "hostname should have been cleared on buffer=" + buffer +
8010
                       " with " + components.to_string() + "\n" + to_diagram());
8011
#endif
8012
0
  ADA_ASSERT_TRUE(has_authority());
8013
0
  ADA_ASSERT_EQUAL(has_empty_hostname(), true,
8014
0
                   "hostname should have been cleared on buffer=" + buffer +
8015
0
                       " with " + components.to_string() + "\n" + to_diagram());
8016
0
  ADA_ASSERT_TRUE(validate());
8017
0
}
8018
8019
0
[[nodiscard]] constexpr bool url_aggregator::has_hash() const noexcept {
8020
0
  ada_log("url_aggregator::has_hash");
8021
0
  return components.hash_start != url_components::omitted;
8022
0
}
8023
8024
0
[[nodiscard]] constexpr bool url_aggregator::has_search() const noexcept {
8025
0
  ada_log("url_aggregator::has_search");
8026
0
  return components.search_start != url_components::omitted;
8027
0
}
8028
8029
8.69k
constexpr bool url_aggregator::has_credentials() const noexcept {
8030
8.69k
  ada_log("url_aggregator::has_credentials");
8031
8.69k
  return has_non_empty_username() || has_non_empty_password();
8032
8.69k
}
8033
8034
29.7k
constexpr bool url_aggregator::cannot_have_credentials_or_port() const {
8035
29.7k
  ada_log("url_aggregator::cannot_have_credentials_or_port");
8036
29.7k
  return type == ada::scheme::type::FILE ||
8037
27.5k
         components.host_start == components.host_end;
8038
29.7k
}
8039
8040
[[nodiscard]] ada_really_inline const ada::url_components &
8041
0
url_aggregator::get_components() const noexcept {
8042
0
  return components;
8043
0
}
8044
8045
[[nodiscard]] constexpr bool ada::url_aggregator::has_authority()
8046
60.5k
    const noexcept {
8047
60.5k
  ada_log("url_aggregator::has_authority");
8048
  // Performance: instead of doing this potentially expensive check, we could
8049
  // have a boolean in the struct.
8050
60.5k
  return components.protocol_end + 2 <= components.host_start &&
8051
47.4k
         helpers::substring(buffer, components.protocol_end,
8052
47.4k
                            components.protocol_end + 2) == "//";
8053
60.5k
}
8054
8055
60.0k
inline void ada::url_aggregator::add_authority_slashes_if_needed() noexcept {
8056
60.0k
  ada_log("url_aggregator::add_authority_slashes_if_needed");
8057
60.0k
  ADA_ASSERT_TRUE(validate());
8058
  // Protocol setter will insert `http:` to the URL. It is up to hostname setter
8059
  // to insert
8060
  // `//` initially to the buffer, since it depends on the hostname existence.
8061
60.0k
  if (has_authority()) {
8062
46.9k
    return;
8063
46.9k
  }
8064
  // Performance: the common case is components.protocol_end == buffer.size()
8065
  // Optimization opportunity: in many cases, the "//" is part of the input and
8066
  // the insert could be fused with another insert.
8067
13.0k
  buffer.insert(components.protocol_end, "//");
8068
13.0k
  components.username_end += 2;
8069
13.0k
  components.host_start += 2;
8070
13.0k
  components.host_end += 2;
8071
13.0k
  components.pathname_start += 2;
8072
13.0k
  if (components.search_start != url_components::omitted) {
8073
0
    components.search_start += 2;
8074
0
  }
8075
13.0k
  if (components.hash_start != url_components::omitted) {
8076
0
    components.hash_start += 2;
8077
0
  }
8078
13.0k
  ADA_ASSERT_TRUE(validate());
8079
13.0k
}
8080
8081
21.4k
constexpr void ada::url_aggregator::reserve(uint32_t capacity) {
8082
21.4k
  buffer.reserve(capacity);
8083
21.4k
}
8084
8085
24.1k
constexpr bool url_aggregator::has_non_empty_username() const noexcept {
8086
24.1k
  ada_log("url_aggregator::has_non_empty_username");
8087
24.1k
  return components.protocol_end + 2 < components.username_end;
8088
24.1k
}
8089
8090
25.9k
constexpr bool url_aggregator::has_non_empty_password() const noexcept {
8091
25.9k
  ada_log("url_aggregator::has_non_empty_password");
8092
25.9k
  return components.host_start - components.username_end > 0;
8093
25.9k
}
8094
8095
12.8k
constexpr bool url_aggregator::has_password() const noexcept {
8096
12.8k
  ada_log("url_aggregator::has_password");
8097
  // This function does not care about the length of the password
8098
12.8k
  return components.host_start > components.username_end &&
8099
4.30k
         buffer[components.username_end] == ':';
8100
12.8k
}
8101
8102
0
constexpr bool url_aggregator::has_empty_hostname() const noexcept {
8103
0
  if (!has_hostname()) {
8104
0
    return false;
8105
0
  }
8106
0
  if (components.host_start == components.host_end) {
8107
0
    return true;
8108
0
  }
8109
0
  if (components.host_end > components.host_start + 1) {
8110
0
    return false;
8111
0
  }
8112
0
  return components.username_end != components.host_start;
8113
0
}
8114
8115
0
constexpr bool url_aggregator::has_hostname() const noexcept {
8116
0
  return has_authority();
8117
0
}
8118
8119
0
constexpr bool url_aggregator::has_port() const noexcept {
8120
0
  ada_log("url_aggregator::has_port");
8121
  // A URL cannot have a username/password/port if its host is null or the empty
8122
  // string, or its scheme is "file".
8123
0
  return has_hostname() && components.pathname_start != components.host_end;
8124
0
}
8125
8126
25.2k
[[nodiscard]] constexpr bool url_aggregator::has_dash_dot() const noexcept {
8127
  // If url's host is null, url does not have an opaque path, url's path's size
8128
  // is greater than 1, and url's path[0] is the empty string, then append
8129
  // U+002F (/) followed by U+002E (.) to output.
8130
25.2k
  ada_log("url_aggregator::has_dash_dot");
8131
#if ADA_DEVELOPMENT_CHECKS
8132
  // If pathname_start and host_end are exactly two characters apart, then we
8133
  // either have a one-digit port such as http://test.com:5?param=1 or else we
8134
  // have a /.: sequence such as "non-spec:/.//". We test that this is the case.
8135
  if (components.pathname_start == components.host_end + 2) {
8136
    ADA_ASSERT_TRUE((buffer[components.host_end] == '/' &&
8137
                     buffer[components.host_end + 1] == '.') ||
8138
                    (buffer[components.host_end] == ':' &&
8139
                     checkers::is_digit(buffer[components.host_end + 1])));
8140
  }
8141
  if (components.pathname_start == components.host_end + 2 &&
8142
      buffer[components.host_end] == '/' &&
8143
      buffer[components.host_end + 1] == '.') {
8144
    ADA_ASSERT_TRUE(components.pathname_start + 1 < buffer.size());
8145
    ADA_ASSERT_TRUE(buffer[components.pathname_start] == '/');
8146
    ADA_ASSERT_TRUE(buffer[components.pathname_start + 1] == '/');
8147
  }
8148
#endif
8149
  // Performance: it should be uncommon for components.pathname_start ==
8150
  // components.host_end + 2 to be true. So we put this check first in the
8151
  // sequence. Most times, we do not have an opaque path. Checking for '/.' is
8152
  // more expensive, but should be uncommon.
8153
25.2k
  return components.pathname_start == components.host_end + 2 &&
8154
221
         !has_opaque_path && buffer[components.host_end] == '/' &&
8155
0
         buffer[components.host_end + 1] == '.';
8156
25.2k
}
8157
8158
[[nodiscard]] constexpr std::string_view url_aggregator::get_href()
8159
9.17k
    const noexcept ada_lifetime_bound {
8160
9.17k
  ada_log("url_aggregator::get_href");
8161
9.17k
  return buffer;
8162
9.17k
}
8163
8164
ada_really_inline size_t url_aggregator::parse_port(
8165
2.02k
    std::string_view view, bool check_trailing_content) noexcept {
8166
2.02k
  ada_log("url_aggregator::parse_port('", view, "') ", view.size());
8167
2.02k
  if (!view.empty() && view[0] == '-') {
8168
2
    ada_log("parse_port: view[0] == '0' && view.size() > 1");
8169
2
    is_valid = false;
8170
2
    return 0;
8171
2
  }
8172
2.01k
  uint16_t parsed_port{};
8173
2.01k
  auto r = std::from_chars(view.data(), view.data() + view.size(), parsed_port);
8174
2.01k
  if (r.ec == std::errc::result_out_of_range) {
8175
208
    ada_log("parse_port: r.ec == std::errc::result_out_of_range");
8176
208
    is_valid = false;
8177
208
    return 0;
8178
208
  }
8179
1.81k
  ada_log("parse_port: ", parsed_port);
8180
1.81k
  const size_t consumed = size_t(r.ptr - view.data());
8181
1.81k
  ada_log("parse_port: consumed ", consumed);
8182
1.81k
  if (check_trailing_content) {
8183
561
    is_valid &=
8184
561
        (consumed == view.size() || view[consumed] == '/' ||
8185
95
         view[consumed] == '?' || (is_special() && view[consumed] == '\\'));
8186
561
  }
8187
1.81k
  ada_log("parse_port: is_valid = ", is_valid);
8188
1.81k
  if (is_valid) {
8189
1.44k
    ada_log("parse_port", r.ec == std::errc());
8190
    // scheme_default_port can return 0, and we should allow 0 as a base port.
8191
1.44k
    auto default_port = scheme_default_port();
8192
1.44k
    bool is_port_valid = (default_port == 0 && parsed_port == 0) ||
8193
1.43k
                         (default_port != parsed_port);
8194
1.44k
    if (r.ec == std::errc() && is_port_valid) {
8195
1.08k
      update_base_port(parsed_port);
8196
1.08k
    } else {
8197
364
      clear_port();
8198
364
    }
8199
1.44k
  }
8200
1.81k
  return consumed;
8201
2.01k
}
8202
8203
1.45k
constexpr void url_aggregator::set_protocol_as_file() {
8204
1.45k
  ada_log("url_aggregator::set_protocol_as_file ");
8205
1.45k
  ADA_ASSERT_TRUE(validate());
8206
1.45k
  type = ada::scheme::type::FILE;
8207
  // next line could overflow but unsigned arithmetic has well-defined
8208
  // overflows.
8209
1.45k
  uint32_t new_difference = 5 - components.protocol_end;
8210
8211
1.45k
  if (buffer.empty()) {
8212
0
    buffer.append("file:");
8213
1.45k
  } else {
8214
1.45k
    buffer.erase(0, components.protocol_end);
8215
1.45k
    buffer.insert(0, "file:");
8216
1.45k
  }
8217
1.45k
  components.protocol_end = 5;
8218
8219
  // Update the rest of the components.
8220
1.45k
  components.username_end += new_difference;
8221
1.45k
  components.host_start += new_difference;
8222
1.45k
  components.host_end += new_difference;
8223
1.45k
  components.pathname_start += new_difference;
8224
1.45k
  if (components.search_start != url_components::omitted) {
8225
0
    components.search_start += new_difference;
8226
0
  }
8227
1.45k
  if (components.hash_start != url_components::omitted) {
8228
0
    components.hash_start += new_difference;
8229
0
  }
8230
1.45k
  ADA_ASSERT_TRUE(validate());
8231
1.45k
}
8232
8233
12.0k
[[nodiscard]] constexpr bool url_aggregator::validate() const noexcept {
8234
12.0k
  if (!is_valid) {
8235
2.46k
    return true;
8236
2.46k
  }
8237
9.56k
  if (!components.check_offset_consistency()) {
8238
0
    ada_log("url_aggregator::validate inconsistent components \n",
8239
0
            to_diagram());
8240
0
    return false;
8241
0
  }
8242
  // We have a credible components struct, but let us investivate more
8243
  // carefully:
8244
  /**
8245
   * https://user:pass@example.com:1234/foo/bar?baz#quux
8246
   *       |     |    |          | ^^^^|       |   |
8247
   *       |     |    |          | |   |       |   `----- hash_start
8248
   *       |     |    |          | |   |       `--------- search_start
8249
   *       |     |    |          | |   `----------------- pathname_start
8250
   *       |     |    |          | `--------------------- port
8251
   *       |     |    |          `----------------------- host_end
8252
   *       |     |    `---------------------------------- host_start
8253
   *       |     `--------------------------------------- username_end
8254
   *       `--------------------------------------------- protocol_end
8255
   */
8256
9.56k
  if (components.protocol_end == url_components::omitted) {
8257
0
    ada_log("url_aggregator::validate omitted protocol_end \n", to_diagram());
8258
0
    return false;
8259
0
  }
8260
9.56k
  if (components.username_end == url_components::omitted) {
8261
0
    ada_log("url_aggregator::validate omitted username_end \n", to_diagram());
8262
0
    return false;
8263
0
  }
8264
9.56k
  if (components.host_start == url_components::omitted) {
8265
0
    ada_log("url_aggregator::validate omitted host_start \n", to_diagram());
8266
0
    return false;
8267
0
  }
8268
9.56k
  if (components.host_end == url_components::omitted) {
8269
0
    ada_log("url_aggregator::validate omitted host_end \n", to_diagram());
8270
0
    return false;
8271
0
  }
8272
9.56k
  if (components.pathname_start == url_components::omitted) {
8273
0
    ada_log("url_aggregator::validate omitted pathname_start \n", to_diagram());
8274
0
    return false;
8275
0
  }
8276
8277
9.56k
  if (components.protocol_end > buffer.size()) {
8278
0
    ada_log("url_aggregator::validate protocol_end overflow \n", to_diagram());
8279
0
    return false;
8280
0
  }
8281
9.56k
  if (components.username_end > buffer.size()) {
8282
0
    ada_log("url_aggregator::validate username_end overflow \n", to_diagram());
8283
0
    return false;
8284
0
  }
8285
9.56k
  if (components.host_start > buffer.size()) {
8286
0
    ada_log("url_aggregator::validate host_start overflow \n", to_diagram());
8287
0
    return false;
8288
0
  }
8289
9.56k
  if (components.host_end > buffer.size()) {
8290
0
    ada_log("url_aggregator::validate host_end overflow \n", to_diagram());
8291
0
    return false;
8292
0
  }
8293
9.56k
  if (components.pathname_start > buffer.size()) {
8294
0
    ada_log("url_aggregator::validate pathname_start overflow \n",
8295
0
            to_diagram());
8296
0
    return false;
8297
0
  }
8298
8299
9.56k
  if (components.protocol_end > 0) {
8300
9.56k
    if (buffer[components.protocol_end - 1] != ':') {
8301
0
      ada_log(
8302
0
          "url_aggregator::validate missing : at the end of the protocol \n",
8303
0
          to_diagram());
8304
0
      return false;
8305
0
    }
8306
9.56k
  }
8307
8308
9.56k
  if (components.username_end != buffer.size() &&
8309
9.40k
      components.username_end > components.protocol_end + 2) {
8310
6.70k
    if (buffer[components.username_end] != ':' &&
8311
161
        buffer[components.username_end] != '@') {
8312
0
      ada_log(
8313
0
          "url_aggregator::validate missing : or @ at the end of the username "
8314
0
          "\n",
8315
0
          to_diagram());
8316
0
      return false;
8317
0
    }
8318
6.70k
  }
8319
8320
9.56k
  if (components.host_start != buffer.size()) {
8321
9.40k
    if (components.host_start > components.username_end) {
8322
6.62k
      if (buffer[components.host_start] != '@') {
8323
0
        ada_log(
8324
0
            "url_aggregator::validate missing @ at the end of the password \n",
8325
0
            to_diagram());
8326
0
        return false;
8327
0
      }
8328
6.62k
    } else if (components.host_start == components.username_end &&
8329
2.78k
               components.host_end > components.host_start) {
8330
1.20k
      if (components.host_start == components.protocol_end + 2) {
8331
1.04k
        if (buffer[components.protocol_end] != '/' ||
8332
1.04k
            buffer[components.protocol_end + 1] != '/') {
8333
0
          ada_log(
8334
0
              "url_aggregator::validate missing // between protocol and host "
8335
0
              "\n",
8336
0
              to_diagram());
8337
0
          return false;
8338
0
        }
8339
1.04k
      } else {
8340
161
        if (components.host_start > components.protocol_end &&
8341
161
            buffer[components.host_start] != '@') {
8342
0
          ada_log(
8343
0
              "url_aggregator::validate missing @ at the end of the username "
8344
0
              "\n",
8345
0
              to_diagram());
8346
0
          return false;
8347
0
        }
8348
161
      }
8349
1.57k
    } else {
8350
1.57k
      if (components.host_end != components.host_start) {
8351
0
        ada_log("url_aggregator::validate expected omitted host \n",
8352
0
                to_diagram());
8353
0
        return false;
8354
0
      }
8355
1.57k
    }
8356
9.40k
  }
8357
9.56k
  if (components.host_end != buffer.size() &&
8358
9.32k
      components.pathname_start > components.host_end) {
8359
971
    if (components.pathname_start == components.host_end + 2 &&
8360
755
        buffer[components.host_end] == '/' &&
8361
21
        buffer[components.host_end + 1] == '.') {
8362
21
      if (components.pathname_start + 1 >= buffer.size() ||
8363
21
          buffer[components.pathname_start] != '/' ||
8364
21
          buffer[components.pathname_start + 1] != '/') {
8365
0
        ada_log(
8366
0
            "url_aggregator::validate expected the path to begin with // \n",
8367
0
            to_diagram());
8368
0
        return false;
8369
0
      }
8370
950
    } else if (buffer[components.host_end] != ':') {
8371
0
      ada_log("url_aggregator::validate missing : at the port \n",
8372
0
              to_diagram());
8373
0
      return false;
8374
0
    }
8375
971
  }
8376
9.56k
  if (components.pathname_start != buffer.size() &&
8377
9.31k
      components.pathname_start < components.search_start &&
8378
9.27k
      components.pathname_start < components.hash_start && !has_opaque_path) {
8379
8.61k
    if (buffer[components.pathname_start] != '/') {
8380
0
      ada_log("url_aggregator::validate missing / at the path \n",
8381
0
              to_diagram());
8382
0
      return false;
8383
0
    }
8384
8.61k
  }
8385
9.56k
  if (components.search_start != url_components::omitted) {
8386
6.66k
    if (buffer[components.search_start] != '?') {
8387
0
      ada_log("url_aggregator::validate missing ? at the search \n",
8388
0
              to_diagram());
8389
0
      return false;
8390
0
    }
8391
6.66k
  }
8392
9.56k
  if (components.hash_start != url_components::omitted) {
8393
6.61k
    if (buffer[components.hash_start] != '#') {
8394
0
      ada_log("url_aggregator::validate missing # at the hash \n",
8395
0
              to_diagram());
8396
0
      return false;
8397
0
    }
8398
6.61k
  }
8399
8400
9.56k
  return true;
8401
9.56k
}
8402
8403
[[nodiscard]] constexpr std::string_view url_aggregator::get_pathname()
8404
33.8k
    const noexcept ada_lifetime_bound {
8405
33.8k
  ada_log("url_aggregator::get_pathname pathname_start = ",
8406
33.8k
          components.pathname_start, " buffer.size() = ", buffer.size(),
8407
33.8k
          " components.search_start = ", components.search_start,
8408
33.8k
          " components.hash_start = ", components.hash_start);
8409
33.8k
  auto ending_index = uint32_t(buffer.size());
8410
33.8k
  if (components.search_start != url_components::omitted) {
8411
15.4k
    ending_index = components.search_start;
8412
18.3k
  } else if (components.hash_start != url_components::omitted) {
8413
13
    ending_index = components.hash_start;
8414
13
  }
8415
33.8k
  return helpers::substring(buffer, components.pathname_start, ending_index);
8416
33.8k
}
8417
8418
inline std::ostream &operator<<(std::ostream &out,
8419
0
                                const ada::url_aggregator &u) {
8420
0
  return out << u.to_string();
8421
0
}
8422
8423
void url_aggregator::update_host_to_base_host(
8424
0
    const std::string_view input) noexcept {
8425
0
  ada_log("url_aggregator::update_host_to_base_host ", input);
8426
0
  ADA_ASSERT_TRUE(validate());
8427
0
  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
8428
0
  if (type != ada::scheme::type::FILE) {
8429
    // Let host be the result of host parsing host_view with url is not special.
8430
0
    if (input.empty() && !is_special()) {
8431
0
      if (has_hostname()) {
8432
0
        clear_hostname();
8433
0
      } else if (has_dash_dot()) {
8434
0
        add_authority_slashes_if_needed();
8435
0
        delete_dash_dot();
8436
0
      }
8437
0
      return;
8438
0
    }
8439
0
  }
8440
0
  update_base_hostname(input);
8441
0
  ADA_ASSERT_TRUE(validate());
8442
0
  return;
8443
0
}
8444
}  // namespace ada
8445
8446
#endif  // ADA_URL_AGGREGATOR_INL_H
8447
/* end file include/ada/url_aggregator-inl.h */
8448
/* begin file include/ada/url_search_params.h */
8449
/**
8450
 * @file url_search_params.h
8451
 * @brief Declaration for the URL Search Params
8452
 */
8453
#ifndef ADA_URL_SEARCH_PARAMS_H
8454
#define ADA_URL_SEARCH_PARAMS_H
8455
8456
#include <optional>
8457
#include <string>
8458
#include <string_view>
8459
#include <vector>
8460
8461
namespace ada {
8462
8463
enum class url_search_params_iter_type {
8464
  KEYS,
8465
  VALUES,
8466
  ENTRIES,
8467
};
8468
8469
template <typename T, url_search_params_iter_type Type>
8470
struct url_search_params_iter;
8471
8472
typedef std::pair<std::string_view, std::string_view> key_value_view_pair;
8473
8474
using url_search_params_keys_iter =
8475
    url_search_params_iter<std::string_view, url_search_params_iter_type::KEYS>;
8476
using url_search_params_values_iter =
8477
    url_search_params_iter<std::string_view,
8478
                           url_search_params_iter_type::VALUES>;
8479
using url_search_params_entries_iter =
8480
    url_search_params_iter<key_value_view_pair,
8481
                           url_search_params_iter_type::ENTRIES>;
8482
8483
/**
8484
 * We require all strings to be valid UTF-8. It is the user's responsibility to
8485
 * ensure that the provided strings are valid UTF-8.
8486
 * @see https://url.spec.whatwg.org/#interface-urlsearchparams
8487
 */
8488
struct url_search_params {
8489
  url_search_params() = default;
8490
8491
  /**
8492
   * @see
8493
   * https://github.com/web-platform-tests/wpt/blob/master/url/urlsearchparams-constructor.any.js
8494
   */
8495
0
  explicit url_search_params(const std::string_view input) {
8496
0
    initialize(input);
8497
0
  }
8498
8499
  url_search_params(const url_search_params &u) = default;
8500
0
  url_search_params(url_search_params &&u) noexcept = default;
8501
  url_search_params &operator=(url_search_params &&u) noexcept = default;
8502
  url_search_params &operator=(const url_search_params &u) = default;
8503
0
  ~url_search_params() = default;
8504
8505
  [[nodiscard]] inline size_t size() const noexcept;
8506
8507
  /**
8508
   * Both key and value must be valid UTF-8.
8509
   * @see https://url.spec.whatwg.org/#dom-urlsearchparams-append
8510
   */
8511
  inline void append(std::string_view key, std::string_view value);
8512
8513
  /**
8514
   * @see https://url.spec.whatwg.org/#dom-urlsearchparams-delete
8515
   */
8516
  inline void remove(std::string_view key);
8517
  inline void remove(std::string_view key, std::string_view value);
8518
8519
  /**
8520
   * @see https://url.spec.whatwg.org/#dom-urlsearchparams-get
8521
   */
8522
  inline std::optional<std::string_view> get(std::string_view key);
8523
8524
  /**
8525
   * @see https://url.spec.whatwg.org/#dom-urlsearchparams-getall
8526
   */
8527
  inline std::vector<std::string> get_all(std::string_view key);
8528
8529
  /**
8530
   * @see https://url.spec.whatwg.org/#dom-urlsearchparams-has
8531
   */
8532
  inline bool has(std::string_view key) noexcept;
8533
  inline bool has(std::string_view key, std::string_view value) noexcept;
8534
8535
  /**
8536
   * Both key and value must be valid UTF-8.
8537
   * @see https://url.spec.whatwg.org/#dom-urlsearchparams-set
8538
   */
8539
  inline void set(std::string_view key, std::string_view value);
8540
8541
  /**
8542
   * @see https://url.spec.whatwg.org/#dom-urlsearchparams-sort
8543
   */
8544
  inline void sort();
8545
8546
  /**
8547
   * @see https://url.spec.whatwg.org/#urlsearchparams-stringification-behavior
8548
   */
8549
  inline std::string to_string() const;
8550
8551
  /**
8552
   * Returns a simple JS-style iterator over all of the keys in this
8553
   * url_search_params. The keys in the iterator are not unique. The valid
8554
   * lifespan of the iterator is tied to the url_search_params. The iterator
8555
   * must be freed when you're done with it.
8556
   * @see https://url.spec.whatwg.org/#interface-urlsearchparams
8557
   */
8558
  inline url_search_params_keys_iter get_keys();
8559
8560
  /**
8561
   * Returns a simple JS-style iterator over all of the values in this
8562
   * url_search_params. The valid lifespan of the iterator is tied to the
8563
   * url_search_params. The iterator must be freed when you're done with it.
8564
   * @see https://url.spec.whatwg.org/#interface-urlsearchparams
8565
   */
8566
  inline url_search_params_values_iter get_values();
8567
8568
  /**
8569
   * Returns a simple JS-style iterator over all of the entries in this
8570
   * url_search_params. The entries are pairs of keys and corresponding values.
8571
   * The valid lifespan of the iterator is tied to the url_search_params. The
8572
   * iterator must be freed when you're done with it.
8573
   * @see https://url.spec.whatwg.org/#interface-urlsearchparams
8574
   */
8575
  inline url_search_params_entries_iter get_entries();
8576
8577
  /**
8578
   * C++ style conventional iterator support. const only because we
8579
   * do not really want the params to be modified via the iterator.
8580
   */
8581
0
  inline auto begin() const { return params.begin(); }
8582
0
  inline auto end() const { return params.end(); }
8583
0
  inline auto front() const { return params.front(); }
8584
0
  inline auto back() const { return params.back(); }
8585
0
  inline auto operator[](size_t index) const { return params[index]; }
8586
8587
  /**
8588
   * @private
8589
   * Used to reset the search params to a new input.
8590
   * Used primarily for C API.
8591
   * @param input
8592
   */
8593
  void reset(std::string_view input);
8594
8595
 private:
8596
  typedef std::pair<std::string, std::string> key_value_pair;
8597
  std::vector<key_value_pair> params{};
8598
8599
  /**
8600
   * The init parameter must be valid UTF-8.
8601
   * @see https://url.spec.whatwg.org/#concept-urlencoded-parser
8602
   */
8603
  void initialize(std::string_view init);
8604
8605
  template <typename T, url_search_params_iter_type Type>
8606
  friend struct url_search_params_iter;
8607
};  // url_search_params
8608
8609
/**
8610
 * Implements a non-conventional iterator pattern that is closer in style to
8611
 * JavaScript's definition of an iterator.
8612
 *
8613
 * @see https://webidl.spec.whatwg.org/#idl-iterable
8614
 */
8615
template <typename T, url_search_params_iter_type Type>
8616
struct url_search_params_iter {
8617
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()
8618
  url_search_params_iter(const url_search_params_iter &u) = default;
8619
  url_search_params_iter(url_search_params_iter &&u) noexcept = default;
8620
  url_search_params_iter &operator=(url_search_params_iter &&u) noexcept =
8621
      default;
8622
  url_search_params_iter &operator=(const url_search_params_iter &u) = default;
8623
  ~url_search_params_iter() = default;
8624
8625
  /**
8626
   * Return the next item in the iterator or std::nullopt if done.
8627
   */
8628
  inline std::optional<T> next();
8629
8630
  inline bool has_next() const;
8631
8632
 private:
8633
  static url_search_params EMPTY;
8634
0
  inline url_search_params_iter(url_search_params &params_) : params(params_) {}
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(ada::url_search_params&)
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(ada::url_search_params&)
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(ada::url_search_params&)
8635
8636
  url_search_params &params;
8637
  size_t pos = 0;
8638
8639
  friend struct url_search_params;
8640
};
8641
8642
}  // namespace ada
8643
#endif
8644
/* end file include/ada/url_search_params.h */
8645
/* begin file include/ada/url_search_params-inl.h */
8646
/**
8647
 * @file url_search_params-inl.h
8648
 * @brief Inline declarations for the URL Search Params
8649
 */
8650
#ifndef ADA_URL_SEARCH_PARAMS_INL_H
8651
#define ADA_URL_SEARCH_PARAMS_INL_H
8652
8653
8654
#include <algorithm>
8655
#include <optional>
8656
#include <ranges>
8657
#include <string>
8658
#include <string_view>
8659
#include <vector>
8660
8661
namespace ada {
8662
8663
// A default, empty url_search_params for use with empty iterators.
8664
template <typename T, ada::url_search_params_iter_type Type>
8665
url_search_params url_search_params_iter<T, Type>::EMPTY;
8666
8667
0
inline void url_search_params::reset(std::string_view input) {
8668
0
  params.clear();
8669
0
  initialize(input);
8670
0
}
8671
8672
0
inline void url_search_params::initialize(std::string_view input) {
8673
0
  if (!input.empty() && input.front() == '?') {
8674
0
    input.remove_prefix(1);
8675
0
  }
8676
8677
0
  auto process_key_value = [&](const std::string_view current) {
8678
0
    auto equal = current.find('=');
8679
8680
0
    if (equal == std::string_view::npos) {
8681
0
      std::string name(current);
8682
0
      std::ranges::replace(name, '+', ' ');
8683
0
      params.emplace_back(unicode::percent_decode(name, name.find('%')), "");
8684
0
    } else {
8685
0
      std::string name(current.substr(0, equal));
8686
0
      std::string value(current.substr(equal + 1));
8687
8688
0
      std::ranges::replace(name, '+', ' ');
8689
0
      std::ranges::replace(value, '+', ' ');
8690
8691
0
      params.emplace_back(unicode::percent_decode(name, name.find('%')),
8692
0
                          unicode::percent_decode(value, value.find('%')));
8693
0
    }
8694
0
  };
8695
8696
0
  while (!input.empty()) {
8697
0
    auto ampersand_index = input.find('&');
8698
8699
0
    if (ampersand_index == std::string_view::npos) {
8700
0
      if (!input.empty()) {
8701
0
        process_key_value(input);
8702
0
      }
8703
0
      break;
8704
0
    } else if (ampersand_index != 0) {
8705
0
      process_key_value(input.substr(0, ampersand_index));
8706
0
    }
8707
8708
0
    input.remove_prefix(ampersand_index + 1);
8709
0
  }
8710
0
}
8711
8712
inline void url_search_params::append(const std::string_view key,
8713
0
                                      const std::string_view value) {
8714
0
  params.emplace_back(key, value);
8715
0
}
8716
8717
0
inline size_t url_search_params::size() const noexcept { return params.size(); }
8718
8719
inline std::optional<std::string_view> url_search_params::get(
8720
0
    const std::string_view key) {
8721
0
  auto entry = std::ranges::find_if(
8722
0
      params, [&key](const auto &param) { return param.first == key; });
8723
8724
0
  if (entry == params.end()) {
8725
0
    return std::nullopt;
8726
0
  }
8727
8728
0
  return entry->second;
8729
0
}
8730
8731
inline std::vector<std::string> url_search_params::get_all(
8732
0
    const std::string_view key) {
8733
0
  std::vector<std::string> out{};
8734
8735
0
  for (auto &param : params) {
8736
0
    if (param.first == key) {
8737
0
      out.emplace_back(param.second);
8738
0
    }
8739
0
  }
8740
8741
0
  return out;
8742
0
}
8743
8744
0
inline bool url_search_params::has(const std::string_view key) noexcept {
8745
0
  auto entry = std::ranges::find_if(
8746
0
      params, [&key](const auto &param) { return param.first == key; });
8747
0
  return entry != params.end();
8748
0
}
8749
8750
inline bool url_search_params::has(std::string_view key,
8751
0
                                   std::string_view value) noexcept {
8752
0
  auto entry = std::ranges::find_if(params, [&key, &value](const auto &param) {
8753
0
    return param.first == key && param.second == value;
8754
0
  });
8755
0
  return entry != params.end();
8756
0
}
8757
8758
0
inline std::string url_search_params::to_string() const {
8759
0
  auto character_set = ada::character_sets::WWW_FORM_URLENCODED_PERCENT_ENCODE;
8760
0
  std::string out{};
8761
0
  for (size_t i = 0; i < params.size(); i++) {
8762
0
    auto key = ada::unicode::percent_encode(params[i].first, character_set);
8763
0
    auto value = ada::unicode::percent_encode(params[i].second, character_set);
8764
8765
    // Performance optimization: Move this inside percent_encode.
8766
0
    std::ranges::replace(key, ' ', '+');
8767
0
    std::ranges::replace(value, ' ', '+');
8768
8769
0
    if (i != 0) {
8770
0
      out += "&";
8771
0
    }
8772
0
    out.append(key);
8773
0
    out += "=";
8774
0
    out.append(value);
8775
0
  }
8776
0
  return out;
8777
0
}
8778
8779
inline void url_search_params::set(const std::string_view key,
8780
0
                                   const std::string_view value) {
8781
0
  const auto find = [&key](const auto &param) { return param.first == key; };
8782
8783
0
  auto it = std::ranges::find_if(params, find);
8784
8785
0
  if (it == params.end()) {
8786
0
    params.emplace_back(key, value);
8787
0
  } else {
8788
0
    it->second = value;
8789
0
    params.erase(std::remove_if(std::next(it), params.end(), find),
8790
0
                 params.end());
8791
0
  }
8792
0
}
8793
8794
0
inline void url_search_params::remove(const std::string_view key) {
8795
0
  std::erase_if(params,
8796
0
                [&key](const auto &param) { return param.first == key; });
8797
0
}
8798
8799
inline void url_search_params::remove(const std::string_view key,
8800
0
                                      const std::string_view value) {
8801
0
  std::erase_if(params, [&key, &value](const auto &param) {
8802
0
    return param.first == key && param.second == value;
8803
0
  });
8804
0
}
8805
8806
0
inline void url_search_params::sort() {
8807
  // We rely on the fact that the content is valid UTF-8.
8808
0
  std::ranges::stable_sort(params, [](const key_value_pair &lhs,
8809
0
                                      const key_value_pair &rhs) {
8810
0
    size_t i = 0, j = 0;
8811
0
    uint32_t low_surrogate1 = 0, low_surrogate2 = 0;
8812
0
    while ((i < lhs.first.size() || low_surrogate1 != 0) &&
8813
0
           (j < rhs.first.size() || low_surrogate2 != 0)) {
8814
0
      uint32_t codePoint1 = 0, codePoint2 = 0;
8815
8816
0
      if (low_surrogate1 != 0) {
8817
0
        codePoint1 = low_surrogate1;
8818
0
        low_surrogate1 = 0;
8819
0
      } else {
8820
0
        uint8_t c1 = uint8_t(lhs.first[i]);
8821
0
        if (c1 <= 0x7F) {
8822
0
          codePoint1 = c1;
8823
0
          i++;
8824
0
        } else if (c1 <= 0xDF) {
8825
0
          codePoint1 = ((c1 & 0x1F) << 6) | (uint8_t(lhs.first[i + 1]) & 0x3F);
8826
0
          i += 2;
8827
0
        } else if (c1 <= 0xEF) {
8828
0
          codePoint1 = ((c1 & 0x0F) << 12) |
8829
0
                       ((uint8_t(lhs.first[i + 1]) & 0x3F) << 6) |
8830
0
                       (uint8_t(lhs.first[i + 2]) & 0x3F);
8831
0
          i += 3;
8832
0
        } else {
8833
0
          codePoint1 = ((c1 & 0x07) << 18) |
8834
0
                       ((uint8_t(lhs.first[i + 1]) & 0x3F) << 12) |
8835
0
                       ((uint8_t(lhs.first[i + 2]) & 0x3F) << 6) |
8836
0
                       (uint8_t(lhs.first[i + 3]) & 0x3F);
8837
0
          i += 4;
8838
8839
0
          codePoint1 -= 0x10000;
8840
0
          uint16_t high_surrogate = uint16_t(0xD800 + (codePoint1 >> 10));
8841
0
          low_surrogate1 = uint16_t(0xDC00 + (codePoint1 & 0x3FF));
8842
0
          codePoint1 = high_surrogate;
8843
0
        }
8844
0
      }
8845
8846
0
      if (low_surrogate2 != 0) {
8847
0
        codePoint2 = low_surrogate2;
8848
0
        low_surrogate2 = 0;
8849
0
      } else {
8850
0
        uint8_t c2 = uint8_t(rhs.first[j]);
8851
0
        if (c2 <= 0x7F) {
8852
0
          codePoint2 = c2;
8853
0
          j++;
8854
0
        } else if (c2 <= 0xDF) {
8855
0
          codePoint2 = ((c2 & 0x1F) << 6) | (uint8_t(rhs.first[j + 1]) & 0x3F);
8856
0
          j += 2;
8857
0
        } else if (c2 <= 0xEF) {
8858
0
          codePoint2 = ((c2 & 0x0F) << 12) |
8859
0
                       ((uint8_t(rhs.first[j + 1]) & 0x3F) << 6) |
8860
0
                       (uint8_t(rhs.first[j + 2]) & 0x3F);
8861
0
          j += 3;
8862
0
        } else {
8863
0
          codePoint2 = ((c2 & 0x07) << 18) |
8864
0
                       ((uint8_t(rhs.first[j + 1]) & 0x3F) << 12) |
8865
0
                       ((uint8_t(rhs.first[j + 2]) & 0x3F) << 6) |
8866
0
                       (uint8_t(rhs.first[j + 3]) & 0x3F);
8867
0
          j += 4;
8868
0
          codePoint2 -= 0x10000;
8869
0
          uint16_t high_surrogate = uint16_t(0xD800 + (codePoint2 >> 10));
8870
0
          low_surrogate2 = uint16_t(0xDC00 + (codePoint2 & 0x3FF));
8871
0
          codePoint2 = high_surrogate;
8872
0
        }
8873
0
      }
8874
8875
0
      if (codePoint1 != codePoint2) {
8876
0
        return (codePoint1 < codePoint2);
8877
0
      }
8878
0
    }
8879
0
    return (j < rhs.first.size() || low_surrogate2 != 0);
8880
0
  });
8881
0
}
8882
8883
0
inline url_search_params_keys_iter url_search_params::get_keys() {
8884
0
  return url_search_params_keys_iter(*this);
8885
0
}
8886
8887
/**
8888
 * @see https://url.spec.whatwg.org/#interface-urlsearchparams
8889
 */
8890
0
inline url_search_params_values_iter url_search_params::get_values() {
8891
0
  return url_search_params_values_iter(*this);
8892
0
}
8893
8894
/**
8895
 * @see https://url.spec.whatwg.org/#interface-urlsearchparams
8896
 */
8897
0
inline url_search_params_entries_iter url_search_params::get_entries() {
8898
0
  return url_search_params_entries_iter(*this);
8899
0
}
8900
8901
template <typename T, url_search_params_iter_type Type>
8902
0
inline bool url_search_params_iter<T, Type>::has_next() const {
8903
0
  return pos < params.params.size();
8904
0
}
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>::has_next() const
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>::has_next() const
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>::has_next() const
8905
8906
template <>
8907
0
inline std::optional<std::string_view> url_search_params_keys_iter::next() {
8908
0
  if (!has_next()) {
8909
0
    return std::nullopt;
8910
0
  }
8911
0
  return params.params[pos++].first;
8912
0
}
8913
8914
template <>
8915
0
inline std::optional<std::string_view> url_search_params_values_iter::next() {
8916
0
  if (!has_next()) {
8917
0
    return std::nullopt;
8918
0
  }
8919
0
  return params.params[pos++].second;
8920
0
}
8921
8922
template <>
8923
inline std::optional<key_value_view_pair>
8924
0
url_search_params_entries_iter::next() {
8925
0
  if (!has_next()) {
8926
0
    return std::nullopt;
8927
0
  }
8928
0
  return params.params[pos++];
8929
0
}
8930
8931
}  // namespace ada
8932
8933
#endif  // ADA_URL_SEARCH_PARAMS_INL_H
8934
/* end file include/ada/url_search_params-inl.h */
8935
8936
/* begin file include/ada/url_pattern-inl.h */
8937
/**
8938
 * @file url_pattern-inl.h
8939
 * @brief Declaration for the URLPattern inline functions.
8940
 */
8941
#ifndef ADA_URL_PATTERN_INL_H
8942
#define ADA_URL_PATTERN_INL_H
8943
8944
8945
#include <algorithm>
8946
#include <string_view>
8947
#include <utility>
8948
8949
#if ADA_INCLUDE_URL_PATTERN
8950
namespace ada {
8951
8952
0
inline bool url_pattern_init::operator==(const url_pattern_init& other) const {
8953
0
  return protocol == other.protocol && username == other.username &&
8954
0
         password == other.password && hostname == other.hostname &&
8955
0
         port == other.port && search == other.search && hash == other.hash &&
8956
0
         pathname == other.pathname;
8957
0
}
8958
8959
inline bool url_pattern_component_result::operator==(
8960
0
    const url_pattern_component_result& other) const {
8961
0
  return input == other.input && groups == other.groups;
8962
0
}
8963
8964
template <url_pattern_regex::regex_concept regex_provider>
8965
url_pattern_component_result
8966
url_pattern_component<regex_provider>::create_component_match_result(
8967
    std::string&& input,
8968
    std::vector<std::optional<std::string>>&& exec_result) {
8969
  // Let result be a new URLPatternComponentResult.
8970
  // Set result["input"] to input.
8971
  // Let groups be a record<USVString, (USVString or undefined)>.
8972
  auto result =
8973
      url_pattern_component_result{.input = std::move(input), .groups = {}};
8974
8975
  // Optimization: Let's reserve the size.
8976
  result.groups.reserve(exec_result.size());
8977
8978
  // We explicitly start iterating from 0 even though the spec
8979
  // says we should start from 1. This case is handled by the
8980
  // std_regex_provider.
8981
  for (size_t index = 0; index < exec_result.size(); index++) {
8982
    result.groups.insert({
8983
        group_name_list[index],
8984
        std::move(exec_result[index]),
8985
    });
8986
  }
8987
  return result;
8988
}
8989
8990
template <url_pattern_regex::regex_concept regex_provider>
8991
std::string_view url_pattern<regex_provider>::get_protocol() const
8992
    ada_lifetime_bound {
8993
  // Return this's associated URL pattern's protocol component's pattern string.
8994
  return protocol_component.pattern;
8995
}
8996
template <url_pattern_regex::regex_concept regex_provider>
8997
std::string_view url_pattern<regex_provider>::get_username() const
8998
    ada_lifetime_bound {
8999
  // Return this's associated URL pattern's username component's pattern string.
9000
  return username_component.pattern;
9001
}
9002
template <url_pattern_regex::regex_concept regex_provider>
9003
std::string_view url_pattern<regex_provider>::get_password() const
9004
    ada_lifetime_bound {
9005
  // Return this's associated URL pattern's password component's pattern string.
9006
  return password_component.pattern;
9007
}
9008
template <url_pattern_regex::regex_concept regex_provider>
9009
std::string_view url_pattern<regex_provider>::get_hostname() const
9010
    ada_lifetime_bound {
9011
  // Return this's associated URL pattern's hostname component's pattern string.
9012
  return hostname_component.pattern;
9013
}
9014
template <url_pattern_regex::regex_concept regex_provider>
9015
std::string_view url_pattern<regex_provider>::get_port() const
9016
    ada_lifetime_bound {
9017
  // Return this's associated URL pattern's port component's pattern string.
9018
  return port_component.pattern;
9019
}
9020
template <url_pattern_regex::regex_concept regex_provider>
9021
std::string_view url_pattern<regex_provider>::get_pathname() const
9022
    ada_lifetime_bound {
9023
  // Return this's associated URL pattern's pathname component's pattern string.
9024
  return pathname_component.pattern;
9025
}
9026
template <url_pattern_regex::regex_concept regex_provider>
9027
std::string_view url_pattern<regex_provider>::get_search() const
9028
    ada_lifetime_bound {
9029
  // Return this's associated URL pattern's search component's pattern string.
9030
  return search_component.pattern;
9031
}
9032
template <url_pattern_regex::regex_concept regex_provider>
9033
std::string_view url_pattern<regex_provider>::get_hash() const
9034
    ada_lifetime_bound {
9035
  // Return this's associated URL pattern's hash component's pattern string.
9036
  return hash_component.pattern;
9037
}
9038
template <url_pattern_regex::regex_concept regex_provider>
9039
bool url_pattern<regex_provider>::ignore_case() const {
9040
  return ignore_case_;
9041
}
9042
template <url_pattern_regex::regex_concept regex_provider>
9043
bool url_pattern<regex_provider>::has_regexp_groups() const {
9044
  // If this's associated URL pattern's has regexp groups, then return true.
9045
  return protocol_component.has_regexp_groups ||
9046
         username_component.has_regexp_groups ||
9047
         password_component.has_regexp_groups ||
9048
         hostname_component.has_regexp_groups ||
9049
         port_component.has_regexp_groups ||
9050
         pathname_component.has_regexp_groups ||
9051
         search_component.has_regexp_groups || hash_component.has_regexp_groups;
9052
}
9053
9054
0
inline bool url_pattern_part::is_regexp() const noexcept {
9055
0
  return type == url_pattern_part_type::REGEXP;
9056
0
}
9057
9058
inline std::string_view url_pattern_compile_component_options::get_delimiter()
9059
0
    const {
9060
0
  if (delimiter) {
9061
0
    return {&delimiter.value(), 1};
9062
0
  }
9063
0
  return {};
9064
0
}
9065
9066
inline std::string_view url_pattern_compile_component_options::get_prefix()
9067
0
    const {
9068
0
  if (prefix) {
9069
0
    return {&prefix.value(), 1};
9070
0
  }
9071
0
  return {};
9072
0
}
9073
9074
template <url_pattern_regex::regex_concept regex_provider>
9075
template <url_pattern_encoding_callback F>
9076
tl::expected<url_pattern_component<regex_provider>, errors>
9077
url_pattern_component<regex_provider>::compile(
9078
    std::string_view input, F& encoding_callback,
9079
    url_pattern_compile_component_options& options) {
9080
  ada_log("url_pattern_component::compile input: ", input);
9081
  // Let part list be the result of running parse a pattern string given input,
9082
  // options, and encoding callback.
9083
  auto part_list = url_pattern_helpers::parse_pattern_string(input, options,
9084
                                                             encoding_callback);
9085
9086
  if (!part_list) {
9087
    ada_log("parse_pattern_string failed");
9088
    return tl::unexpected(part_list.error());
9089
  }
9090
9091
  // Let (regular expression string, name list) be the result of running
9092
  // generate a regular expression and name list given part list and options.
9093
  auto [regular_expression_string, name_list] =
9094
      url_pattern_helpers::generate_regular_expression_and_name_list(*part_list,
9095
                                                                     options);
9096
9097
  ada_log("regular expression string: ", regular_expression_string);
9098
9099
  // Let pattern string be the result of running generate a pattern
9100
  // string given part list and options.
9101
  auto pattern_string =
9102
      url_pattern_helpers::generate_pattern_string(*part_list, options);
9103
9104
  // Let regular expression be RegExpCreate(regular expression string,
9105
  // flags). If this throws an exception, catch it, and throw a
9106
  // TypeError.
9107
  std::optional<typename regex_provider::regex_type> regular_expression =
9108
      regex_provider::create_instance(regular_expression_string,
9109
                                      options.ignore_case);
9110
9111
  if (!regular_expression) {
9112
    return tl::unexpected(errors::type_error);
9113
  }
9114
9115
  // For each part of part list:
9116
  // - If part's type is "regexp", then set has regexp groups to true.
9117
  const auto has_regexp = [](const auto& part) { return part.is_regexp(); };
9118
  const bool has_regexp_groups = std::ranges::any_of(*part_list, has_regexp);
9119
9120
  ada_log("has regexp groups: ", has_regexp_groups);
9121
9122
  // Return a new component whose pattern string is pattern string, regular
9123
  // expression is regular expression, group name list is name list, and has
9124
  // regexp groups is has regexp groups.
9125
  return url_pattern_component<regex_provider>(
9126
      std::move(pattern_string), std::move(*regular_expression),
9127
      std::move(name_list), has_regexp_groups);
9128
}
9129
9130
template <url_pattern_regex::regex_concept regex_provider>
9131
result<std::optional<url_pattern_result>> url_pattern<regex_provider>::exec(
9132
    const url_pattern_input& input, const std::string_view* base_url) {
9133
  // Return the result of match given this's associated URL pattern, input, and
9134
  // baseURL if given.
9135
  return match(input, base_url);
9136
}
9137
9138
template <url_pattern_regex::regex_concept regex_provider>
9139
result<bool> url_pattern<regex_provider>::test(
9140
    const url_pattern_input& input, const std::string_view* base_url) {
9141
  // TODO: Optimization opportunity. Rather than returning `url_pattern_result`
9142
  // Implement a fast path just like `can_parse()` in ada_url.
9143
  // Let result be the result of match given this's associated URL pattern,
9144
  // input, and baseURL if given.
9145
  // If result is null, return false.
9146
  if (auto result = match(input, base_url); result.has_value()) {
9147
    return result->has_value();
9148
  }
9149
  return tl::unexpected(errors::type_error);
9150
}
9151
9152
template <url_pattern_regex::regex_concept regex_provider>
9153
result<std::optional<url_pattern_result>> url_pattern<regex_provider>::match(
9154
    const url_pattern_input& input, const std::string_view* base_url_string) {
9155
  std::string protocol{};
9156
  std::string username{};
9157
  std::string password{};
9158
  std::string hostname{};
9159
  std::string port{};
9160
  std::string pathname{};
9161
  std::string search{};
9162
  std::string hash{};
9163
9164
  // Let inputs be an empty list.
9165
  // Append input to inputs.
9166
  std::vector inputs{input};
9167
9168
  // If input is a URLPatternInit then:
9169
  if (std::holds_alternative<url_pattern_init>(input)) {
9170
    ada_log(
9171
        "url_pattern::match called with url_pattern_init and base_url_string=",
9172
        base_url_string);
9173
    // If baseURLString was given, throw a TypeError.
9174
    if (base_url_string) {
9175
      ada_log("failed to match because base_url_string was given");
9176
      return tl::unexpected(errors::type_error);
9177
    }
9178
9179
    // Let applyResult be the result of process a URLPatternInit given input,
9180
    // "url", protocol, username, password, hostname, port, pathname, search,
9181
    // and hash.
9182
    auto apply_result = url_pattern_init::process(
9183
        std::get<url_pattern_init>(input), url_pattern_init::process_type::url,
9184
        protocol, username, password, hostname, port, pathname, search, hash);
9185
9186
    // If this throws an exception, catch it, and return null.
9187
    if (!apply_result.has_value()) {
9188
      ada_log("match returned std::nullopt because process threw");
9189
      return std::nullopt;
9190
    }
9191
9192
    // Set protocol to applyResult["protocol"].
9193
    ADA_ASSERT_TRUE(apply_result->protocol.has_value());
9194
    protocol = std::move(apply_result->protocol.value());
9195
9196
    // Set username to applyResult["username"].
9197
    ADA_ASSERT_TRUE(apply_result->username.has_value());
9198
    username = std::move(apply_result->username.value());
9199
9200
    // Set password to applyResult["password"].
9201
    ADA_ASSERT_TRUE(apply_result->password.has_value());
9202
    password = std::move(apply_result->password.value());
9203
9204
    // Set hostname to applyResult["hostname"].
9205
    ADA_ASSERT_TRUE(apply_result->hostname.has_value());
9206
    hostname = std::move(apply_result->hostname.value());
9207
9208
    // Set port to applyResult["port"].
9209
    ADA_ASSERT_TRUE(apply_result->port.has_value());
9210
    port = std::move(apply_result->port.value());
9211
9212
    // Set pathname to applyResult["pathname"].
9213
    ADA_ASSERT_TRUE(apply_result->pathname.has_value());
9214
    pathname = std::move(apply_result->pathname.value());
9215
9216
    // Set search to applyResult["search"].
9217
    ADA_ASSERT_TRUE(apply_result->search.has_value());
9218
    if (apply_result->search->starts_with("?")) {
9219
      search = apply_result->search->substr(1);
9220
    } else {
9221
      search = std::move(apply_result->search.value());
9222
    }
9223
9224
    // Set hash to applyResult["hash"].
9225
    ADA_ASSERT_TRUE(apply_result->hash.has_value());
9226
    ADA_ASSERT_TRUE(!apply_result->hash->starts_with("#"));
9227
    hash = std::move(apply_result->hash.value());
9228
  } else {
9229
    ADA_ASSERT_TRUE(std::holds_alternative<std::string_view>(input));
9230
9231
    // Let baseURL be null.
9232
    result<url_aggregator> base_url;
9233
9234
    // If baseURLString was given, then:
9235
    if (base_url_string) {
9236
      // Let baseURL be the result of parsing baseURLString.
9237
      base_url = ada::parse<url_aggregator>(*base_url_string, nullptr);
9238
9239
      // If baseURL is failure, return null.
9240
      if (!base_url) {
9241
        ada_log("match returned std::nullopt because failed to parse base_url=",
9242
                *base_url_string);
9243
        return std::nullopt;
9244
      }
9245
9246
      // Append baseURLString to inputs.
9247
      inputs.emplace_back(*base_url_string);
9248
    }
9249
9250
    url_aggregator* base_url_value =
9251
        base_url.has_value() ? &*base_url : nullptr;
9252
9253
    // Set url to the result of parsing input given baseURL.
9254
    auto url = ada::parse<url_aggregator>(std::get<std::string_view>(input),
9255
                                          base_url_value);
9256
9257
    // If url is failure, return null.
9258
    if (!url) {
9259
      ada_log("match returned std::nullopt because url failed");
9260
      return std::nullopt;
9261
    }
9262
9263
    // Set protocol to url's scheme.
9264
    // IMPORTANT: Not documented on the URLPattern spec, but protocol suffix ':'
9265
    // is removed. Similar work was done on workerd:
9266
    // https://github.com/cloudflare/workerd/blob/8620d14012513a6ce04d079e401d3becac3c67bd/src/workerd/jsg/url.c%2B%2B#L2038
9267
    protocol = url->get_protocol().substr(0, url->get_protocol().size() - 1);
9268
    // Set username to url's username.
9269
    username = url->get_username();
9270
    // Set password to url's password.
9271
    password = url->get_password();
9272
    // Set hostname to url's host, serialized, or the empty string if the value
9273
    // is null.
9274
    hostname = url->get_hostname();
9275
    // Set port to url's port, serialized, or the empty string if the value is
9276
    // null.
9277
    port = url->get_port();
9278
    // Set pathname to the result of URL path serializing url.
9279
    pathname = url->get_pathname();
9280
    // Set search to url's query or the empty string if the value is null.
9281
    // IMPORTANT: Not documented on the URLPattern spec, but search prefix '?'
9282
    // is removed. Similar work was done on workerd:
9283
    // https://github.com/cloudflare/workerd/blob/8620d14012513a6ce04d079e401d3becac3c67bd/src/workerd/jsg/url.c%2B%2B#L2232
9284
    if (url->has_search()) {
9285
      auto view = url->get_search();
9286
      search = view.starts_with("?") ? url->get_search().substr(1) : view;
9287
    }
9288
    // Set hash to url's fragment or the empty string if the value is null.
9289
    // IMPORTANT: Not documented on the URLPattern spec, but hash prefix '#' is
9290
    // removed. Similar work was done on workerd:
9291
    // https://github.com/cloudflare/workerd/blob/8620d14012513a6ce04d079e401d3becac3c67bd/src/workerd/jsg/url.c%2B%2B#L2242
9292
    if (url->has_hash()) {
9293
      auto view = url->get_hash();
9294
      hash = view.starts_with("#") ? url->get_hash().substr(1) : view;
9295
    }
9296
  }
9297
9298
  // Let protocolExecResult be RegExpBuiltinExec(urlPattern's protocol
9299
  // component's regular expression, protocol).
9300
  auto protocol_exec_result =
9301
      regex_provider::regex_search(protocol, protocol_component.regexp);
9302
9303
  if (!protocol_exec_result) {
9304
    return std::nullopt;
9305
  }
9306
9307
  // Let usernameExecResult be RegExpBuiltinExec(urlPattern's username
9308
  // component's regular expression, username).
9309
  auto username_exec_result =
9310
      regex_provider::regex_search(username, username_component.regexp);
9311
9312
  if (!username_exec_result) {
9313
    return std::nullopt;
9314
  }
9315
9316
  // Let passwordExecResult be RegExpBuiltinExec(urlPattern's password
9317
  // component's regular expression, password).
9318
  auto password_exec_result =
9319
      regex_provider::regex_search(password, password_component.regexp);
9320
9321
  if (!password_exec_result) {
9322
    return std::nullopt;
9323
  }
9324
9325
  // Let hostnameExecResult be RegExpBuiltinExec(urlPattern's hostname
9326
  // component's regular expression, hostname).
9327
  auto hostname_exec_result =
9328
      regex_provider::regex_search(hostname, hostname_component.regexp);
9329
9330
  if (!hostname_exec_result) {
9331
    return std::nullopt;
9332
  }
9333
9334
  // Let portExecResult be RegExpBuiltinExec(urlPattern's port component's
9335
  // regular expression, port).
9336
  auto port_exec_result =
9337
      regex_provider::regex_search(port, port_component.regexp);
9338
9339
  if (!port_exec_result) {
9340
    return std::nullopt;
9341
  }
9342
9343
  // Let pathnameExecResult be RegExpBuiltinExec(urlPattern's pathname
9344
  // component's regular expression, pathname).
9345
  auto pathname_exec_result =
9346
      regex_provider::regex_search(pathname, pathname_component.regexp);
9347
9348
  if (!pathname_exec_result) {
9349
    return std::nullopt;
9350
  }
9351
9352
  // Let searchExecResult be RegExpBuiltinExec(urlPattern's search component's
9353
  // regular expression, search).
9354
  auto search_exec_result =
9355
      regex_provider::regex_search(search, search_component.regexp);
9356
9357
  if (!search_exec_result) {
9358
    return std::nullopt;
9359
  }
9360
9361
  // Let hashExecResult be RegExpBuiltinExec(urlPattern's hash component's
9362
  // regular expression, hash).
9363
  auto hash_exec_result =
9364
      regex_provider::regex_search(hash, hash_component.regexp);
9365
9366
  if (!hash_exec_result) {
9367
    return std::nullopt;
9368
  }
9369
9370
  // Let result be a new URLPatternResult.
9371
  auto result = url_pattern_result{};
9372
  // Set result["inputs"] to inputs.
9373
  result.inputs = std::move(inputs);
9374
  // Set result["protocol"] to the result of creating a component match result
9375
  // given urlPattern's protocol component, protocol, and protocolExecResult.
9376
  result.protocol = protocol_component.create_component_match_result(
9377
      std::move(protocol), std::move(*protocol_exec_result));
9378
9379
  // Set result["username"] to the result of creating a component match result
9380
  // given urlPattern's username component, username, and usernameExecResult.
9381
  result.username = username_component.create_component_match_result(
9382
      std::move(username), std::move(*username_exec_result));
9383
9384
  // Set result["password"] to the result of creating a component match result
9385
  // given urlPattern's password component, password, and passwordExecResult.
9386
  result.password = password_component.create_component_match_result(
9387
      std::move(password), std::move(*password_exec_result));
9388
9389
  // Set result["hostname"] to the result of creating a component match result
9390
  // given urlPattern's hostname component, hostname, and hostnameExecResult.
9391
  result.hostname = hostname_component.create_component_match_result(
9392
      std::move(hostname), std::move(*hostname_exec_result));
9393
9394
  // Set result["port"] to the result of creating a component match result given
9395
  // urlPattern's port component, port, and portExecResult.
9396
  result.port = port_component.create_component_match_result(
9397
      std::move(port), std::move(*port_exec_result));
9398
9399
  // Set result["pathname"] to the result of creating a component match result
9400
  // given urlPattern's pathname component, pathname, and pathnameExecResult.
9401
  result.pathname = pathname_component.create_component_match_result(
9402
      std::move(pathname), std::move(*pathname_exec_result));
9403
9404
  // Set result["search"] to the result of creating a component match result
9405
  // given urlPattern's search component, search, and searchExecResult.
9406
  result.search = search_component.create_component_match_result(
9407
      std::move(search), std::move(*search_exec_result));
9408
9409
  // Set result["hash"] to the result of creating a component match result given
9410
  // urlPattern's hash component, hash, and hashExecResult.
9411
  result.hash = hash_component.create_component_match_result(
9412
      std::move(hash), std::move(*hash_exec_result));
9413
9414
  return result;
9415
}
9416
9417
}  // namespace ada
9418
#endif  // ADA_INCLUDE_URL_PATTERN
9419
#endif
9420
/* end file include/ada/url_pattern-inl.h */
9421
/* begin file include/ada/url_pattern_helpers-inl.h */
9422
/**
9423
 * @file url_pattern_helpers-inl.h
9424
 * @brief Declaration for the URLPattern helpers.
9425
 */
9426
#ifndef ADA_URL_PATTERN_HELPERS_INL_H
9427
#define ADA_URL_PATTERN_HELPERS_INL_H
9428
9429
#include <optional>
9430
#include <string_view>
9431
9432
9433
#if ADA_INCLUDE_URL_PATTERN
9434
namespace ada::url_pattern_helpers {
9435
#if defined(ADA_TESTING) || defined(ADA_LOGGING)
9436
0
inline std::string to_string(token_type type) {
9437
0
  switch (type) {
9438
0
    case token_type::INVALID_CHAR:
9439
0
      return "INVALID_CHAR";
9440
0
    case token_type::OPEN:
9441
0
      return "OPEN";
9442
0
    case token_type::CLOSE:
9443
0
      return "CLOSE";
9444
0
    case token_type::REGEXP:
9445
0
      return "REGEXP";
9446
0
    case token_type::NAME:
9447
0
      return "NAME";
9448
0
    case token_type::CHAR:
9449
0
      return "CHAR";
9450
0
    case token_type::ESCAPED_CHAR:
9451
0
      return "ESCAPED_CHAR";
9452
0
    case token_type::OTHER_MODIFIER:
9453
0
      return "OTHER_MODIFIER";
9454
0
    case token_type::ASTERISK:
9455
0
      return "ASTERISK";
9456
0
    case token_type::END:
9457
0
      return "END";
9458
0
    default:
9459
0
      ada::unreachable();
9460
0
  }
9461
0
}
9462
#endif  // defined(ADA_TESTING) || defined(ADA_LOGGING)
9463
9464
template <url_pattern_regex::regex_concept regex_provider>
9465
constexpr void constructor_string_parser<regex_provider>::rewind() {
9466
  // Set parser's token index to parser's component start.
9467
  token_index = component_start;
9468
  // Set parser's token increment to 0.
9469
  token_increment = 0;
9470
}
9471
9472
template <url_pattern_regex::regex_concept regex_provider>
9473
constexpr bool constructor_string_parser<regex_provider>::is_hash_prefix() {
9474
  // Return the result of running is a non-special pattern char given parser,
9475
  // parser's token index and "#".
9476
  return is_non_special_pattern_char(token_index, '#');
9477
}
9478
9479
template <url_pattern_regex::regex_concept regex_provider>
9480
constexpr bool constructor_string_parser<regex_provider>::is_search_prefix() {
9481
  // If result of running is a non-special pattern char given parser, parser's
9482
  // token index and "?" is true, then return true.
9483
  if (is_non_special_pattern_char(token_index, '?')) {
9484
    return true;
9485
  }
9486
9487
  // If parser's token list[parser's token index]'s value is not "?", then
9488
  // return false.
9489
  if (token_list[token_index].value != "?") {
9490
    return false;
9491
  }
9492
9493
  // If previous index is less than 0, then return true.
9494
  if (token_index == 0) return true;
9495
  // Let previous index be parser's token index - 1.
9496
  auto previous_index = token_index - 1;
9497
  // Let previous token be the result of running get a safe token given parser
9498
  // and previous index.
9499
  auto previous_token = get_safe_token(previous_index);
9500
  ADA_ASSERT_TRUE(previous_token);
9501
  // If any of the following are true, then return false:
9502
  // - previous token's type is "name".
9503
  // - previous token's type is "regexp".
9504
  // - previous token's type is "close".
9505
  // - previous token's type is "asterisk".
9506
  return !(previous_token->type == token_type::NAME ||
9507
           previous_token->type == token_type::REGEXP ||
9508
           previous_token->type == token_type::CLOSE ||
9509
           previous_token->type == token_type::ASTERISK);
9510
}
9511
9512
template <url_pattern_regex::regex_concept regex_provider>
9513
constexpr bool
9514
constructor_string_parser<regex_provider>::is_non_special_pattern_char(
9515
    size_t index, uint32_t value) const {
9516
  // Let token be the result of running get a safe token given parser and index.
9517
  auto token = get_safe_token(index);
9518
  ADA_ASSERT_TRUE(token);
9519
9520
  // If token's value is not value, then return false.
9521
  // TODO: Remove this once we make sure get_safe_token returns a non-empty
9522
  // string.
9523
  if (!token->value.empty() &&
9524
      static_cast<uint32_t>(token->value[0]) != value) {
9525
    return false;
9526
  }
9527
9528
  // If any of the following are true:
9529
  // - token's type is "char";
9530
  // - token's type is "escaped-char"; or
9531
  // - token's type is "invalid-char",
9532
  // - then return true.
9533
  return token->type == token_type::CHAR ||
9534
         token->type == token_type::ESCAPED_CHAR ||
9535
         token->type == token_type::INVALID_CHAR;
9536
}
9537
9538
template <url_pattern_regex::regex_concept regex_provider>
9539
constexpr const token*
9540
constructor_string_parser<regex_provider>::get_safe_token(size_t index) const {
9541
  // If index is less than parser's token list's size, then return parser's
9542
  // token list[index].
9543
  if (index < token_list.size()) [[likely]] {
9544
    return &token_list[index];
9545
  }
9546
9547
  // Assert: parser's token list's size is greater than or equal to 1.
9548
  ADA_ASSERT_TRUE(!token_list.empty());
9549
9550
  // Let token be parser's token list[last index].
9551
  // Assert: token's type is "end".
9552
  ADA_ASSERT_TRUE(token_list.back().type == token_type::END);
9553
9554
  // Return token.
9555
  return &token_list.back();
9556
}
9557
9558
template <url_pattern_regex::regex_concept regex_provider>
9559
constexpr bool constructor_string_parser<regex_provider>::is_group_open()
9560
    const {
9561
  // If parser's token list[parser's token index]'s type is "open", then return
9562
  // true.
9563
  return token_list[token_index].type == token_type::OPEN;
9564
}
9565
9566
template <url_pattern_regex::regex_concept regex_provider>
9567
constexpr bool constructor_string_parser<regex_provider>::is_group_close()
9568
    const {
9569
  // If parser's token list[parser's token index]'s type is "close", then return
9570
  // true.
9571
  return token_list[token_index].type == token_type::CLOSE;
9572
}
9573
9574
template <url_pattern_regex::regex_concept regex_provider>
9575
constexpr bool
9576
constructor_string_parser<regex_provider>::next_is_authority_slashes() const {
9577
  // If the result of running is a non-special pattern char given parser,
9578
  // parser's token index + 1, and "/" is false, then return false.
9579
  if (!is_non_special_pattern_char(token_index + 1, '/')) {
9580
    return false;
9581
  }
9582
  // If the result of running is a non-special pattern char given parser,
9583
  // parser's token index + 2, and "/" is false, then return false.
9584
  if (!is_non_special_pattern_char(token_index + 2, '/')) {
9585
    return false;
9586
  }
9587
  return true;
9588
}
9589
9590
template <url_pattern_regex::regex_concept regex_provider>
9591
constexpr bool constructor_string_parser<regex_provider>::is_protocol_suffix()
9592
    const {
9593
  // Return the result of running is a non-special pattern char given parser,
9594
  // parser's token index, and ":".
9595
  return is_non_special_pattern_char(token_index, ':');
9596
}
9597
9598
template <url_pattern_regex::regex_concept regex_provider>
9599
void constructor_string_parser<regex_provider>::change_state(State new_state,
9600
                                                             size_t skip) {
9601
  // If parser's state is not "init", not "authority", and not "done", then set
9602
  // parser's result[parser's state] to the result of running make a component
9603
  // string given parser.
9604
  if (state != State::INIT && state != State::AUTHORITY &&
9605
      state != State::DONE) {
9606
    auto value = make_component_string();
9607
    // TODO: Simplify this.
9608
    switch (state) {
9609
      case State::PROTOCOL: {
9610
        result.protocol = value;
9611
        break;
9612
      }
9613
      case State::USERNAME: {
9614
        result.username = value;
9615
        break;
9616
      }
9617
      case State::PASSWORD: {
9618
        result.password = value;
9619
        break;
9620
      }
9621
      case State::HOSTNAME: {
9622
        result.hostname = value;
9623
        break;
9624
      }
9625
      case State::PORT: {
9626
        result.port = value;
9627
        break;
9628
      }
9629
      case State::PATHNAME: {
9630
        result.pathname = value;
9631
        break;
9632
      }
9633
      case State::SEARCH: {
9634
        result.search = value;
9635
        break;
9636
      }
9637
      case State::HASH: {
9638
        result.hash = value;
9639
        break;
9640
      }
9641
      default:
9642
        ada::unreachable();
9643
    }
9644
  }
9645
9646
  // If parser's state is not "init" and new state is not "done", then:
9647
  if (state != State::INIT && new_state != State::DONE) {
9648
    // If parser's state is "protocol", "authority", "username", or "password";
9649
    // new state is "port", "pathname", "search", or "hash"; and parser's
9650
    // result["hostname"] does not exist, then set parser's result["hostname"]
9651
    // to the empty string.
9652
    if ((state == State::PROTOCOL || state == State::AUTHORITY ||
9653
         state == State::USERNAME || state == State::PASSWORD) &&
9654
        (new_state == State::PORT || new_state == State::PATHNAME ||
9655
         new_state == State::SEARCH || new_state == State::HASH) &&
9656
        !result.hostname)
9657
      result.hostname = "";
9658
  }
9659
9660
  // If parser's state is "protocol", "authority", "username", "password",
9661
  // "hostname", or "port"; new state is "search" or "hash"; and parser's
9662
  // result["pathname"] does not exist, then:
9663
  if ((state == State::PROTOCOL || state == State::AUTHORITY ||
9664
       state == State::USERNAME || state == State::PASSWORD ||
9665
       state == State::HOSTNAME || state == State::PORT) &&
9666
      (new_state == State::SEARCH || new_state == State::HASH) &&
9667
      !result.pathname) {
9668
    if (protocol_matches_a_special_scheme_flag) {
9669
      result.pathname = "/";
9670
    } else {
9671
      // Otherwise, set parser's result["pathname"] to the empty string.
9672
      result.pathname = "";
9673
    }
9674
  }
9675
9676
  // If parser's state is "protocol", "authority", "username", "password",
9677
  // "hostname", "port", or "pathname"; new state is "hash"; and parser's
9678
  // result["search"] does not exist, then set parser's result["search"] to
9679
  // the empty string.
9680
  if ((state == State::PROTOCOL || state == State::AUTHORITY ||
9681
       state == State::USERNAME || state == State::PASSWORD ||
9682
       state == State::HOSTNAME || state == State::PORT ||
9683
       state == State::PATHNAME) &&
9684
      new_state == State::HASH && !result.search) {
9685
    result.search = "";
9686
  }
9687
9688
  // Set parser's state to new state.
9689
  state = new_state;
9690
  // Increment parser's token index by skip.
9691
  token_index += skip;
9692
  // Set parser's component start to parser's token index.
9693
  component_start = token_index;
9694
  // Set parser's token increment to 0.
9695
  token_increment = 0;
9696
}
9697
9698
template <url_pattern_regex::regex_concept regex_provider>
9699
std::string constructor_string_parser<regex_provider>::make_component_string() {
9700
  // Assert: parser's token index is less than parser's token list's size.
9701
  ADA_ASSERT_TRUE(token_index < token_list.size());
9702
9703
  // Let token be parser's token list[parser's token index].
9704
  // Let end index be token's index.
9705
  const auto end_index = token_list[token_index].index;
9706
  // Let component start token be the result of running get a safe token given
9707
  // parser and parser's component start.
9708
  const auto component_start_token = get_safe_token(component_start);
9709
  ADA_ASSERT_TRUE(component_start_token);
9710
  // Let component start input index be component start token's index.
9711
  const auto component_start_input_index = component_start_token->index;
9712
  // Return the code point substring from component start input index to end
9713
  // index within parser's input.
9714
  return input.substr(component_start_input_index,
9715
                      end_index - component_start_input_index);
9716
}
9717
9718
template <url_pattern_regex::regex_concept regex_provider>
9719
constexpr bool
9720
constructor_string_parser<regex_provider>::is_an_identity_terminator() const {
9721
  // Return the result of running is a non-special pattern char given parser,
9722
  // parser's token index, and "@".
9723
  return is_non_special_pattern_char(token_index, '@');
9724
}
9725
9726
template <url_pattern_regex::regex_concept regex_provider>
9727
constexpr bool constructor_string_parser<regex_provider>::is_pathname_start()
9728
    const {
9729
  // Return the result of running is a non-special pattern char given parser,
9730
  // parser's token index, and "/".
9731
  return is_non_special_pattern_char(token_index, '/');
9732
}
9733
9734
template <url_pattern_regex::regex_concept regex_provider>
9735
constexpr bool constructor_string_parser<regex_provider>::is_password_prefix()
9736
    const {
9737
  // Return the result of running is a non-special pattern char given parser,
9738
  // parser's token index, and ":".
9739
  return is_non_special_pattern_char(token_index, ':');
9740
}
9741
9742
template <url_pattern_regex::regex_concept regex_provider>
9743
constexpr bool constructor_string_parser<regex_provider>::is_an_ipv6_open()
9744
    const {
9745
  // Return the result of running is a non-special pattern char given parser,
9746
  // parser's token index, and "[".
9747
  return is_non_special_pattern_char(token_index, '[');
9748
}
9749
9750
template <url_pattern_regex::regex_concept regex_provider>
9751
constexpr bool constructor_string_parser<regex_provider>::is_an_ipv6_close()
9752
    const {
9753
  // Return the result of running is a non-special pattern char given parser,
9754
  // parser's token index, and "]".
9755
  return is_non_special_pattern_char(token_index, ']');
9756
}
9757
9758
template <url_pattern_regex::regex_concept regex_provider>
9759
constexpr bool constructor_string_parser<regex_provider>::is_port_prefix()
9760
    const {
9761
  // Return the result of running is a non-special pattern char given parser,
9762
  // parser's token index, and ":".
9763
  return is_non_special_pattern_char(token_index, ':');
9764
}
9765
9766
0
constexpr void Tokenizer::get_next_code_point() {
9767
0
  ada_log("Tokenizer::get_next_code_point called with index=", next_index);
9768
0
  ADA_ASSERT_TRUE(next_index < input.size());
9769
  // this assumes that we have a valid, non-truncated UTF-8 stream.
9770
0
  code_point = 0;
9771
0
  size_t number_bytes = 0;
9772
0
  unsigned char first_byte = input[next_index];
9773
9774
0
  if ((first_byte & 0x80) == 0) {
9775
    // 1-byte character (ASCII)
9776
0
    next_index++;
9777
0
    code_point = first_byte;
9778
0
    ada_log("Tokenizer::get_next_code_point returning ASCII code point=",
9779
0
            uint32_t(code_point));
9780
0
    ada_log("Tokenizer::get_next_code_point next_index =", next_index,
9781
0
            " input.size()=", input.size());
9782
0
    return;
9783
0
  }
9784
0
  ada_log("Tokenizer::get_next_code_point read first byte=",
9785
0
          uint32_t(first_byte));
9786
0
  if ((first_byte & 0xE0) == 0xC0) {
9787
0
    code_point = first_byte & 0x1F;
9788
0
    number_bytes = 2;
9789
0
    ada_log("Tokenizer::get_next_code_point two bytes");
9790
0
  } else if ((first_byte & 0xF0) == 0xE0) {
9791
0
    code_point = first_byte & 0x0F;
9792
0
    number_bytes = 3;
9793
0
    ada_log("Tokenizer::get_next_code_point three bytes");
9794
0
  } else if ((first_byte & 0xF8) == 0xF0) {
9795
0
    code_point = first_byte & 0x07;
9796
0
    number_bytes = 4;
9797
0
    ada_log("Tokenizer::get_next_code_point four bytes");
9798
0
  }
9799
0
  ADA_ASSERT_TRUE(number_bytes + next_index <= input.size());
9800
9801
0
  for (size_t i = 1 + next_index; i < number_bytes + next_index; ++i) {
9802
0
    unsigned char byte = input[i];
9803
0
    ada_log("Tokenizer::get_next_code_point read byte=", uint32_t(byte));
9804
0
    code_point = (code_point << 6) | (byte & 0x3F);
9805
0
  }
9806
0
  ada_log("Tokenizer::get_next_code_point returning non-ASCII code point=",
9807
0
          uint32_t(code_point));
9808
0
  ada_log("Tokenizer::get_next_code_point next_index =", next_index,
9809
0
          " input.size()=", input.size());
9810
0
  next_index += number_bytes;
9811
0
}
9812
9813
0
constexpr void Tokenizer::seek_and_get_next_code_point(size_t new_index) {
9814
0
  ada_log("Tokenizer::seek_and_get_next_code_point called with new_index=",
9815
0
          new_index);
9816
  // Set tokenizer's next index to index.
9817
0
  next_index = new_index;
9818
  // Run get the next code point given tokenizer.
9819
0
  get_next_code_point();
9820
0
}
9821
9822
inline void Tokenizer::add_token(token_type type, size_t next_position,
9823
0
                                 size_t value_position, size_t value_length) {
9824
0
  ada_log("Tokenizer::add_token called with type=", to_string(type),
9825
0
          " next_position=", next_position, " value_position=", value_position);
9826
0
  ADA_ASSERT_TRUE(next_position >= value_position);
9827
9828
  // Let token be a new token.
9829
  // Set token's type to type.
9830
  // Set token's index to tokenizer's index.
9831
  // Set token's value to the code point substring from value position with
9832
  // length value length within tokenizer's input.
9833
  // Append token to the back of tokenizer's token list.
9834
0
  token_list.emplace_back(type, index,
9835
0
                          input.substr(value_position, value_length));
9836
  // Set tokenizer's index to next position.
9837
0
  index = next_position;
9838
0
}
9839
9840
inline void Tokenizer::add_token_with_default_length(token_type type,
9841
                                                     size_t next_position,
9842
0
                                                     size_t value_position) {
9843
  // Let computed length be next position - value position.
9844
0
  auto computed_length = next_position - value_position;
9845
  // Run add a token given tokenizer, type, next position, value position, and
9846
  // computed length.
9847
0
  add_token(type, next_position, value_position, computed_length);
9848
0
}
9849
9850
0
inline void Tokenizer::add_token_with_defaults(token_type type) {
9851
0
  ada_log("Tokenizer::add_token_with_defaults called with type=",
9852
0
          to_string(type));
9853
  // Run add a token with default length given tokenizer, type, tokenizer's next
9854
  // index, and tokenizer's index.
9855
0
  add_token_with_default_length(type, next_index, index);
9856
0
}
9857
9858
inline ada_warn_unused std::optional<errors>
9859
Tokenizer::process_tokenizing_error(size_t next_position,
9860
0
                                    size_t value_position) {
9861
  // If tokenizer's policy is "strict", then throw a TypeError.
9862
0
  if (policy == token_policy::strict) {
9863
0
    ada_log("process_tokenizing_error failed with next_position=",
9864
0
            next_position, " value_position=", value_position);
9865
0
    return errors::type_error;
9866
0
  }
9867
  // Assert: tokenizer's policy is "lenient".
9868
0
  ADA_ASSERT_TRUE(policy == token_policy::lenient);
9869
  // Run add a token with default length given tokenizer, "invalid-char", next
9870
  // position, and value position.
9871
0
  add_token_with_default_length(token_type::INVALID_CHAR, next_position,
9872
0
                                value_position);
9873
0
  return std::nullopt;
9874
0
}
9875
9876
template <url_pattern_encoding_callback F>
9877
token* url_pattern_parser<F>::try_consume_modifier_token() {
9878
  // Let token be the result of running try to consume a token given parser and
9879
  // "other-modifier".
9880
  auto token = try_consume_token(token_type::OTHER_MODIFIER);
9881
  // If token is not null, then return token.
9882
  if (token) return token;
9883
  // Set token to the result of running try to consume a token given parser and
9884
  // "asterisk".
9885
  // Return token.
9886
  return try_consume_token(token_type::ASTERISK);
9887
}
9888
9889
template <url_pattern_encoding_callback F>
9890
token* url_pattern_parser<F>::try_consume_regexp_or_wildcard_token(
9891
    const token* name_token) {
9892
  // Let token be the result of running try to consume a token given parser and
9893
  // "regexp".
9894
  auto token = try_consume_token(token_type::REGEXP);
9895
  // If name token is null and token is null, then set token to the result of
9896
  // running try to consume a token given parser and "asterisk".
9897
  if (!name_token && !token) {
9898
    token = try_consume_token(token_type::ASTERISK);
9899
  }
9900
  // Return token.
9901
  return token;
9902
}
9903
9904
template <url_pattern_encoding_callback F>
9905
token* url_pattern_parser<F>::try_consume_token(token_type type) {
9906
  ada_log("url_pattern_parser::try_consume_token called with type=",
9907
          to_string(type));
9908
  // Assert: parser's index is less than parser's token list size.
9909
  ADA_ASSERT_TRUE(index < tokens.size());
9910
  // Let next token be parser's token list[parser's index].
9911
  auto& next_token = tokens[index];
9912
  // If next token's type is not type return null.
9913
  if (next_token.type != type) return nullptr;
9914
  // Increase parser's index by 1.
9915
  index++;
9916
  // Return next token.
9917
  return &next_token;
9918
}
9919
9920
template <url_pattern_encoding_callback F>
9921
std::string url_pattern_parser<F>::consume_text() {
9922
  // Let result be the empty string.
9923
  std::string result{};
9924
  // While true:
9925
  while (true) {
9926
    // Let token be the result of running try to consume a token given parser
9927
    // and "char".
9928
    auto token = try_consume_token(token_type::CHAR);
9929
    // If token is null, then set token to the result of running try to consume
9930
    // a token given parser and "escaped-char".
9931
    if (!token) token = try_consume_token(token_type::ESCAPED_CHAR);
9932
    // If token is null, then break.
9933
    if (!token) break;
9934
    // Append token's value to the end of result.
9935
    result.append(token->value);
9936
  }
9937
  // Return result.
9938
  return result;
9939
}
9940
9941
template <url_pattern_encoding_callback F>
9942
bool url_pattern_parser<F>::consume_required_token(token_type type) {
9943
  ada_log("url_pattern_parser::consume_required_token called with type=",
9944
          to_string(type));
9945
  // Let result be the result of running try to consume a token given parser and
9946
  // type.
9947
  return try_consume_token(type) != nullptr;
9948
}
9949
9950
template <url_pattern_encoding_callback F>
9951
std::optional<errors>
9952
url_pattern_parser<F>::maybe_add_part_from_the_pending_fixed_value() {
9953
  // If parser's pending fixed value is the empty string, then return.
9954
  if (pending_fixed_value.empty()) {
9955
    ada_log("pending_fixed_value is empty");
9956
    return std::nullopt;
9957
  }
9958
  // Let encoded value be the result of running parser's encoding callback given
9959
  // parser's pending fixed value.
9960
  auto encoded_value = encoding_callback(pending_fixed_value);
9961
  if (!encoded_value) {
9962
    ada_log("failed to encode pending_fixed_value: ", pending_fixed_value);
9963
    return encoded_value.error();
9964
  }
9965
  // Set parser's pending fixed value to the empty string.
9966
  pending_fixed_value.clear();
9967
  // Let part be a new part whose type is "fixed-text", value is encoded value,
9968
  // and modifier is "none".
9969
  // Append part to parser's part list.
9970
  parts.emplace_back(url_pattern_part_type::FIXED_TEXT,
9971
                     std::move(*encoded_value),
9972
                     url_pattern_part_modifier::none);
9973
  return std::nullopt;
9974
}
9975
9976
template <url_pattern_encoding_callback F>
9977
std::optional<errors> url_pattern_parser<F>::add_part(
9978
    std::string_view prefix, token* name_token, token* regexp_or_wildcard_token,
9979
    std::string_view suffix, token* modifier_token) {
9980
  // Let modifier be "none".
9981
  auto modifier = url_pattern_part_modifier::none;
9982
  // If modifier token is not null:
9983
  if (modifier_token) {
9984
    // If modifier token's value is "?" then set modifier to "optional".
9985
    if (modifier_token->value == "?") {
9986
      modifier = url_pattern_part_modifier::optional;
9987
    } else if (modifier_token->value == "*") {
9988
      // Otherwise if modifier token's value is "*" then set modifier to
9989
      // "zero-or-more".
9990
      modifier = url_pattern_part_modifier::zero_or_more;
9991
    } else if (modifier_token->value == "+") {
9992
      // Otherwise if modifier token's value is "+" then set modifier to
9993
      // "one-or-more".
9994
      modifier = url_pattern_part_modifier::one_or_more;
9995
    }
9996
  }
9997
  // If name token is null and regexp or wildcard token is null and modifier
9998
  // is "none":
9999
  if (!name_token && !regexp_or_wildcard_token &&
10000
      modifier == url_pattern_part_modifier::none) {
10001
    // Append prefix to the end of parser's pending fixed value.
10002
    pending_fixed_value.append(prefix);
10003
    return std::nullopt;
10004
  }
10005
  // Run maybe add a part from the pending fixed value given parser.
10006
  if (auto error = maybe_add_part_from_the_pending_fixed_value()) {
10007
    return *error;
10008
  }
10009
  // If name token is null and regexp or wildcard token is null:
10010
  if (!name_token && !regexp_or_wildcard_token) {
10011
    // Assert: suffix is the empty string.
10012
    ADA_ASSERT_TRUE(suffix.empty());
10013
    // If prefix is the empty string, then return.
10014
    if (prefix.empty()) return std::nullopt;
10015
    // Let encoded value be the result of running parser's encoding callback
10016
    // given prefix.
10017
    auto encoded_value = encoding_callback(prefix);
10018
    if (!encoded_value) {
10019
      return encoded_value.error();
10020
    }
10021
    // Let part be a new part whose type is "fixed-text", value is encoded
10022
    // value, and modifier is modifier.
10023
    // Append part to parser's part list.
10024
    parts.emplace_back(url_pattern_part_type::FIXED_TEXT,
10025
                       std::move(*encoded_value), modifier);
10026
    return std::nullopt;
10027
  }
10028
  // Let regexp value be the empty string.
10029
  std::string regexp_value{};
10030
  // If regexp or wildcard token is null, then set regexp value to parser's
10031
  // segment wildcard regexp.
10032
  if (!regexp_or_wildcard_token) {
10033
    regexp_value = segment_wildcard_regexp;
10034
  } else if (regexp_or_wildcard_token->type == token_type::ASTERISK) {
10035
    // Otherwise if regexp or wildcard token's type is "asterisk", then set
10036
    // regexp value to the full wildcard regexp value.
10037
    regexp_value = ".*";
10038
  } else {
10039
    // Otherwise set regexp value to regexp or wildcard token's value.
10040
    regexp_value = regexp_or_wildcard_token->value;
10041
  }
10042
  // Let type be "regexp".
10043
  auto type = url_pattern_part_type::REGEXP;
10044
  // If regexp value is parser's segment wildcard regexp:
10045
  if (regexp_value == segment_wildcard_regexp) {
10046
    // Set type to "segment-wildcard".
10047
    type = url_pattern_part_type::SEGMENT_WILDCARD;
10048
    // Set regexp value to the empty string.
10049
    regexp_value.clear();
10050
  } else if (regexp_value == ".*") {
10051
    // Otherwise if regexp value is the full wildcard regexp value:
10052
    // Set type to "full-wildcard".
10053
    type = url_pattern_part_type::FULL_WILDCARD;
10054
    // Set regexp value to the empty string.
10055
    regexp_value.clear();
10056
  }
10057
  // Let name be the empty string.
10058
  std::string name{};
10059
  // If name token is not null, then set name to name token's value.
10060
  if (name_token) {
10061
    name = name_token->value;
10062
  } else if (regexp_or_wildcard_token != nullptr) {
10063
    // Otherwise if regexp or wildcard token is not null:
10064
    // Set name to parser's next numeric name, serialized.
10065
    name = std::to_string(next_numeric_name);
10066
    // Increment parser's next numeric name by 1.
10067
    next_numeric_name++;
10068
  }
10069
  // If the result of running is a duplicate name given parser and name is
10070
  // true, then throw a TypeError.
10071
  if (std::ranges::any_of(
10072
          parts, [&name](const auto& part) { return part.name == name; })) {
10073
    return errors::type_error;
10074
  }
10075
  // Let encoded prefix be the result of running parser's encoding callback
10076
  // given prefix.
10077
  auto encoded_prefix = encoding_callback(prefix);
10078
  if (!encoded_prefix) return encoded_prefix.error();
10079
  // Let encoded suffix be the result of running parser's encoding callback
10080
  // given suffix.
10081
  auto encoded_suffix = encoding_callback(suffix);
10082
  if (!encoded_suffix) return encoded_suffix.error();
10083
  // Let part be a new part whose type is type, value is regexp value,
10084
  // modifier is modifier, name is name, prefix is encoded prefix, and suffix
10085
  // is encoded suffix.
10086
  // Append part to parser's part list.
10087
  parts.emplace_back(type, std::move(regexp_value), modifier, std::move(name),
10088
                     std::move(*encoded_prefix), std::move(*encoded_suffix));
10089
  return std::nullopt;
10090
}
10091
10092
template <url_pattern_encoding_callback F>
10093
tl::expected<std::vector<url_pattern_part>, errors> parse_pattern_string(
10094
    std::string_view input, url_pattern_compile_component_options& options,
10095
    F& encoding_callback) {
10096
  ada_log("parse_pattern_string input=", input);
10097
  // Let parser be a new pattern parser whose encoding callback is encoding
10098
  // callback and segment wildcard regexp is the result of running generate a
10099
  // segment wildcard regexp given options.
10100
  auto parser = url_pattern_parser<F>(
10101
      encoding_callback, generate_segment_wildcard_regexp(options));
10102
  // Set parser's token list to the result of running tokenize given input and
10103
  // "strict".
10104
  auto tokenize_result = tokenize(input, token_policy::strict);
10105
  if (!tokenize_result) {
10106
    ada_log("parse_pattern_string tokenize failed");
10107
    return tl::unexpected(tokenize_result.error());
10108
  }
10109
  parser.tokens = std::move(*tokenize_result);
10110
10111
  // While parser's index is less than parser's token list's size:
10112
  while (parser.can_continue()) {
10113
    // Let char token be the result of running try to consume a token given
10114
    // parser and "char".
10115
    auto char_token = parser.try_consume_token(token_type::CHAR);
10116
    // Let name token be the result of running try to consume a token given
10117
    // parser and "name".
10118
    auto name_token = parser.try_consume_token(token_type::NAME);
10119
    // Let regexp or wildcard token be the result of running try to consume a
10120
    // regexp or wildcard token given parser and name token.
10121
    auto regexp_or_wildcard_token =
10122
        parser.try_consume_regexp_or_wildcard_token(name_token);
10123
    // If name token is not null or regexp or wildcard token is not null:
10124
    if (name_token || regexp_or_wildcard_token) {
10125
      // Let prefix be the empty string.
10126
      std::string prefix{};
10127
      // If char token is not null then set prefix to char token's value.
10128
      if (char_token) prefix = char_token->value;
10129
      // If prefix is not the empty string and not options's prefix code point:
10130
      if (!prefix.empty() && prefix != options.get_prefix()) {
10131
        // Append prefix to the end of parser's pending fixed value.
10132
        parser.pending_fixed_value.append(prefix);
10133
        // Set prefix to the empty string.
10134
        prefix.clear();
10135
      }
10136
      // Run maybe add a part from the pending fixed value given parser.
10137
      if (auto error = parser.maybe_add_part_from_the_pending_fixed_value()) {
10138
        ada_log("maybe_add_part_from_the_pending_fixed_value failed");
10139
        return tl::unexpected(*error);
10140
      }
10141
      // Let modifier token be the result of running try to consume a modifier
10142
      // token given parser.
10143
      auto modifier_token = parser.try_consume_modifier_token();
10144
      // Run add a part given parser, prefix, name token, regexp or wildcard
10145
      // token, the empty string, and modifier token.
10146
      if (auto error =
10147
              parser.add_part(prefix, name_token, regexp_or_wildcard_token, "",
10148
                              modifier_token)) {
10149
        ada_log("parser.add_part failed");
10150
        return tl::unexpected(*error);
10151
      }
10152
      // Continue.
10153
      continue;
10154
    }
10155
10156
    // Let fixed token be char token.
10157
    auto fixed_token = char_token;
10158
    // If fixed token is null, then set fixed token to the result of running try
10159
    // to consume a token given parser and "escaped-char".
10160
    if (!fixed_token)
10161
      fixed_token = parser.try_consume_token(token_type::ESCAPED_CHAR);
10162
    // If fixed token is not null:
10163
    if (fixed_token) {
10164
      // Append fixed token's value to parser's pending fixed value.
10165
      parser.pending_fixed_value.append(fixed_token->value);
10166
      // Continue.
10167
      continue;
10168
    }
10169
    // Let open token be the result of running try to consume a token given
10170
    // parser and "open".
10171
    auto open_token = parser.try_consume_token(token_type::OPEN);
10172
    // If open token is not null:
10173
    if (open_token) {
10174
      // Set prefix be the result of running consume text given parser.
10175
      auto prefix_ = parser.consume_text();
10176
      // Set name token to the result of running try to consume a token given
10177
      // parser and "name".
10178
      name_token = parser.try_consume_token(token_type::NAME);
10179
      // Set regexp or wildcard token to the result of running try to consume a
10180
      // regexp or wildcard token given parser and name token.
10181
      regexp_or_wildcard_token =
10182
          parser.try_consume_regexp_or_wildcard_token(name_token);
10183
      // Let suffix be the result of running consume text given parser.
10184
      auto suffix_ = parser.consume_text();
10185
      // Run consume a required token given parser and "close".
10186
      if (!parser.consume_required_token(token_type::CLOSE)) {
10187
        ada_log("parser.consume_required_token failed");
10188
        return tl::unexpected(errors::type_error);
10189
      }
10190
      // Set modifier token to the result of running try to consume a modifier
10191
      // token given parser.
10192
      auto modifier_token = parser.try_consume_modifier_token();
10193
      // Run add a part given parser, prefix, name token, regexp or wildcard
10194
      // token, suffix, and modifier token.
10195
      if (auto error =
10196
              parser.add_part(prefix_, name_token, regexp_or_wildcard_token,
10197
                              suffix_, modifier_token)) {
10198
        return tl::unexpected(*error);
10199
      }
10200
      // Continue.
10201
      continue;
10202
    }
10203
    // Run maybe add a part from the pending fixed value given parser.
10204
    if (auto error = parser.maybe_add_part_from_the_pending_fixed_value()) {
10205
      ada_log("maybe_add_part_from_the_pending_fixed_value failed on line 992");
10206
      return tl::unexpected(*error);
10207
    }
10208
    // Run consume a required token given parser and "end".
10209
    if (!parser.consume_required_token(token_type::END)) {
10210
      return tl::unexpected(errors::type_error);
10211
    }
10212
  }
10213
  ada_log("parser.parts size is: ", parser.parts.size());
10214
  // Return parser's part list.
10215
  return parser.parts;
10216
}
10217
10218
template <url_pattern_regex::regex_concept regex_provider>
10219
bool protocol_component_matches_special_scheme(
10220
    url_pattern_component<regex_provider>& component) {
10221
  // let's avoid unnecessary copy here.
10222
  auto& regex = component.regexp;
10223
  return regex_provider::regex_match("http", regex) ||
10224
         regex_provider::regex_match("https", regex) ||
10225
         regex_provider::regex_match("ws", regex) ||
10226
         regex_provider::regex_match("wss", regex) ||
10227
         regex_provider::regex_match("ftp", regex);
10228
}
10229
10230
template <url_pattern_regex::regex_concept regex_provider>
10231
inline std::optional<errors> constructor_string_parser<
10232
    regex_provider>::compute_protocol_matches_special_scheme_flag() {
10233
  ada_log(
10234
      "constructor_string_parser::compute_protocol_matches_special_scheme_"
10235
      "flag");
10236
  // Let protocol string be the result of running make a component string given
10237
  // parser.
10238
  auto protocol_string = make_component_string();
10239
  // Let protocol component be the result of compiling a component given
10240
  // protocol string, canonicalize a protocol, and default options.
10241
  auto protocol_component = url_pattern_component<regex_provider>::compile(
10242
      protocol_string, canonicalize_protocol,
10243
      url_pattern_compile_component_options::DEFAULT);
10244
  if (!protocol_component) {
10245
    ada_log("url_pattern_component::compile failed for protocol_string ",
10246
            protocol_string);
10247
    return protocol_component.error();
10248
  }
10249
  // If the result of running protocol component matches a special scheme given
10250
  // protocol component is true, then set parser's protocol matches a special
10251
  // scheme flag to true.
10252
  if (protocol_component_matches_special_scheme(*protocol_component)) {
10253
    protocol_matches_a_special_scheme_flag = true;
10254
  }
10255
  return std::nullopt;
10256
}
10257
10258
template <url_pattern_regex::regex_concept regex_provider>
10259
tl::expected<url_pattern_init, errors>
10260
constructor_string_parser<regex_provider>::parse(std::string_view input) {
10261
  ada_log("constructor_string_parser::parse input=", input);
10262
  // Let parser be a new constructor string parser whose input is input and
10263
  // token list is the result of running tokenize given input and "lenient".
10264
  auto token_list = tokenize(input, token_policy::lenient);
10265
  if (!token_list) {
10266
    return tl::unexpected(token_list.error());
10267
  }
10268
  auto parser = constructor_string_parser(input, std::move(*token_list));
10269
10270
  // While parser's token index is less than parser's token list size:
10271
  while (parser.token_index < parser.token_list.size()) {
10272
    // Set parser's token increment to 1.
10273
    parser.token_increment = 1;
10274
10275
    // If parser's token list[parser's token index]'s type is "end" then:
10276
    if (parser.token_list[parser.token_index].type == token_type::END) {
10277
      // If parser's state is "init":
10278
      if (parser.state == State::INIT) {
10279
        // Run rewind given parser.
10280
        parser.rewind();
10281
        // If the result of running is a hash prefix given parser is true, then
10282
        // run change state given parser, "hash" and 1.
10283
        if (parser.is_hash_prefix()) {
10284
          parser.change_state(State::HASH, 1);
10285
        } else if (parser.is_search_prefix()) {
10286
          // Otherwise if the result of running is a search prefix given parser
10287
          // is true: Run change state given parser, "search" and 1.
10288
          parser.change_state(State::SEARCH, 1);
10289
        } else {
10290
          // Run change state given parser, "pathname" and 0.
10291
          parser.change_state(State::PATHNAME, 0);
10292
        }
10293
        // Increment parser's token index by parser's token increment.
10294
        parser.token_index += parser.token_increment;
10295
        // Continue.
10296
        continue;
10297
      }
10298
10299
      if (parser.state == State::AUTHORITY) {
10300
        // If parser's state is "authority":
10301
        // Run rewind and set state given parser, and "hostname".
10302
        parser.rewind();
10303
        parser.change_state(State::HOSTNAME, 0);
10304
        // Increment parser's token index by parser's token increment.
10305
        parser.token_index += parser.token_increment;
10306
        // Continue.
10307
        continue;
10308
      }
10309
10310
      // Run change state given parser, "done" and 0.
10311
      parser.change_state(State::DONE, 0);
10312
      // Break.
10313
      break;
10314
    }
10315
10316
    // If the result of running is a group open given parser is true:
10317
    if (parser.is_group_open()) {
10318
      // Increment parser's group depth by 1.
10319
      parser.group_depth += 1;
10320
      // Increment parser's token index by parser's token increment.
10321
      parser.token_index += parser.token_increment;
10322
    }
10323
10324
    // If parser's group depth is greater than 0:
10325
    if (parser.group_depth > 0) {
10326
      // If the result of running is a group close given parser is true, then
10327
      // decrement parser's group depth by 1.
10328
      if (parser.is_group_close()) {
10329
        parser.group_depth -= 1;
10330
      } else {
10331
        // Increment parser's token index by parser's token increment.
10332
        parser.token_index += parser.token_increment;
10333
        continue;
10334
      }
10335
    }
10336
10337
    // Switch on parser's state and run the associated steps:
10338
    switch (parser.state) {
10339
      case State::INIT: {
10340
        // If the result of running is a protocol suffix given parser is true:
10341
        if (parser.is_protocol_suffix()) {
10342
          // Run rewind and set state given parser and "protocol".
10343
          parser.rewind();
10344
          parser.change_state(State::PROTOCOL, 0);
10345
        }
10346
        break;
10347
      }
10348
      case State::PROTOCOL: {
10349
        // If the result of running is a protocol suffix given parser is true:
10350
        if (parser.is_protocol_suffix()) {
10351
          // Run compute protocol matches a special scheme flag given parser.
10352
          if (const auto error =
10353
                  parser.compute_protocol_matches_special_scheme_flag()) {
10354
            ada_log("compute_protocol_matches_special_scheme_flag failed");
10355
            return tl::unexpected(*error);
10356
          }
10357
          // Let next state be "pathname".
10358
          auto next_state = State::PATHNAME;
10359
          // Let skip be 1.
10360
          auto skip = 1;
10361
          // If the result of running next is authority slashes given parser is
10362
          // true:
10363
          if (parser.next_is_authority_slashes()) {
10364
            // Set next state to "authority".
10365
            next_state = State::AUTHORITY;
10366
            // Set skip to 3.
10367
            skip = 3;
10368
          } else if (parser.protocol_matches_a_special_scheme_flag) {
10369
            // Otherwise if parser's protocol matches a special scheme flag is
10370
            // true, then set next state to "authority".
10371
            next_state = State::AUTHORITY;
10372
          }
10373
10374
          // Run change state given parser, next state, and skip.
10375
          parser.change_state(next_state, skip);
10376
        }
10377
        break;
10378
      }
10379
      case State::AUTHORITY: {
10380
        // If the result of running is an identity terminator given parser is
10381
        // true, then run rewind and set state given parser and "username".
10382
        if (parser.is_an_identity_terminator()) {
10383
          parser.rewind();
10384
          parser.change_state(State::USERNAME, 0);
10385
        } else if (parser.is_pathname_start() || parser.is_search_prefix() ||
10386
                   parser.is_hash_prefix()) {
10387
          // Otherwise if any of the following are true:
10388
          // - the result of running is a pathname start given parser;
10389
          // - the result of running is a search prefix given parser; or
10390
          // - the result of running is a hash prefix given parser,
10391
          // then run rewind and set state given parser and "hostname".
10392
          parser.rewind();
10393
          parser.change_state(State::HOSTNAME, 0);
10394
        }
10395
        break;
10396
      }
10397
      case State::USERNAME: {
10398
        // If the result of running is a password prefix given parser is true,
10399
        // then run change state given parser, "password", and 1.
10400
        if (parser.is_password_prefix()) {
10401
          parser.change_state(State::PASSWORD, 1);
10402
        } else if (parser.is_an_identity_terminator()) {
10403
          // Otherwise if the result of running is an identity terminator given
10404
          // parser is true, then run change state given parser, "hostname",
10405
          // and 1.
10406
          parser.change_state(State::HOSTNAME, 1);
10407
        }
10408
        break;
10409
      }
10410
      case State::PASSWORD: {
10411
        // If the result of running is an identity terminator given parser is
10412
        // true, then run change state given parser, "hostname", and 1.
10413
        if (parser.is_an_identity_terminator()) {
10414
          parser.change_state(State::HOSTNAME, 1);
10415
        }
10416
        break;
10417
      }
10418
      case State::HOSTNAME: {
10419
        // If the result of running is an IPv6 open given parser is true, then
10420
        // increment parser's hostname IPv6 bracket depth by 1.
10421
        if (parser.is_an_ipv6_open()) {
10422
          parser.hostname_ipv6_bracket_depth += 1;
10423
        } else if (parser.is_an_ipv6_close()) {
10424
          // Otherwise if the result of running is an IPv6 close given parser is
10425
          // true, then decrement parser's hostname IPv6 bracket depth by 1.
10426
          parser.hostname_ipv6_bracket_depth -= 1;
10427
        } else if (parser.is_port_prefix() &&
10428
                   parser.hostname_ipv6_bracket_depth == 0) {
10429
          // Otherwise if the result of running is a port prefix given parser is
10430
          // true and parser's hostname IPv6 bracket depth is zero, then run
10431
          // change state given parser, "port", and 1.
10432
          parser.change_state(State::PORT, 1);
10433
        } else if (parser.is_pathname_start()) {
10434
          // Otherwise if the result of running is a pathname start given parser
10435
          // is true, then run change state given parser, "pathname", and 0.
10436
          parser.change_state(State::PATHNAME, 0);
10437
        } else if (parser.is_search_prefix()) {
10438
          // Otherwise if the result of running is a search prefix given parser
10439
          // is true, then run change state given parser, "search", and 1.
10440
          parser.change_state(State::SEARCH, 1);
10441
        } else if (parser.is_hash_prefix()) {
10442
          // Otherwise if the result of running is a hash prefix given parser is
10443
          // true, then run change state given parser, "hash", and 1.
10444
          parser.change_state(State::HASH, 1);
10445
        }
10446
10447
        break;
10448
      }
10449
      case State::PORT: {
10450
        // If the result of running is a pathname start given parser is true,
10451
        // then run change state given parser, "pathname", and 0.
10452
        if (parser.is_pathname_start()) {
10453
          parser.change_state(State::PATHNAME, 0);
10454
        } else if (parser.is_search_prefix()) {
10455
          // Otherwise if the result of running is a search prefix given parser
10456
          // is true, then run change state given parser, "search", and 1.
10457
          parser.change_state(State::SEARCH, 1);
10458
        } else if (parser.is_hash_prefix()) {
10459
          // Otherwise if the result of running is a hash prefix given parser is
10460
          // true, then run change state given parser, "hash", and 1.
10461
          parser.change_state(State::HASH, 1);
10462
        }
10463
        break;
10464
      }
10465
      case State::PATHNAME: {
10466
        // If the result of running is a search prefix given parser is true,
10467
        // then run change state given parser, "search", and 1.
10468
        if (parser.is_search_prefix()) {
10469
          parser.change_state(State::SEARCH, 1);
10470
        } else if (parser.is_hash_prefix()) {
10471
          // Otherwise if the result of running is a hash prefix given parser is
10472
          // true, then run change state given parser, "hash", and 1.
10473
          parser.change_state(State::HASH, 1);
10474
        }
10475
        break;
10476
      }
10477
      case State::SEARCH: {
10478
        // If the result of running is a hash prefix given parser is true, then
10479
        // run change state given parser, "hash", and 1.
10480
        if (parser.is_hash_prefix()) {
10481
          parser.change_state(State::HASH, 1);
10482
        }
10483
        break;
10484
      }
10485
      case State::HASH: {
10486
        // Do nothing
10487
        break;
10488
      }
10489
      default: {
10490
        // Assert: This step is never reached.
10491
        unreachable();
10492
      }
10493
    }
10494
10495
    // Increment parser's token index by parser's token increment.
10496
    parser.token_index += parser.token_increment;
10497
  }
10498
10499
  // If parser's result contains "hostname" and not "port", then set parser's
10500
  // result["port"] to the empty string.
10501
  if (parser.result.hostname && !parser.result.port) {
10502
    parser.result.port = "";
10503
  }
10504
10505
  // Return parser's result.
10506
  return parser.result;
10507
}
10508
10509
}  // namespace ada::url_pattern_helpers
10510
#endif  // ADA_INCLUDE_URL_PATTERN
10511
#endif
10512
/* end file include/ada/url_pattern_helpers-inl.h */
10513
10514
// Public API
10515
/* begin file include/ada/ada_version.h */
10516
/**
10517
 * @file ada_version.h
10518
 * @brief Definitions for Ada's version number.
10519
 */
10520
#ifndef ADA_ADA_VERSION_H
10521
#define ADA_ADA_VERSION_H
10522
10523
#define ADA_VERSION "3.3.0"
10524
10525
namespace ada {
10526
10527
enum {
10528
  ADA_VERSION_MAJOR = 3,
10529
  ADA_VERSION_MINOR = 3,
10530
  ADA_VERSION_REVISION = 0,
10531
};
10532
10533
}  // namespace ada
10534
10535
#endif  // ADA_ADA_VERSION_H
10536
/* end file include/ada/ada_version.h */
10537
/* begin file include/ada/implementation-inl.h */
10538
/**
10539
 * @file implementation-inl.h
10540
 */
10541
#ifndef ADA_IMPLEMENTATION_INL_H
10542
#define ADA_IMPLEMENTATION_INL_H
10543
10544
10545
10546
#include <variant>
10547
#include <string_view>
10548
10549
namespace ada {
10550
10551
#if ADA_INCLUDE_URL_PATTERN
10552
template <url_pattern_regex::regex_concept regex_provider>
10553
ada_warn_unused tl::expected<url_pattern<regex_provider>, errors>
10554
parse_url_pattern(std::variant<std::string_view, url_pattern_init>&& input,
10555
                  const std::string_view* base_url,
10556
                  const url_pattern_options* options) {
10557
  return parser::parse_url_pattern_impl<regex_provider>(std::move(input),
10558
                                                        base_url, options);
10559
}
10560
#endif  // ADA_INCLUDE_URL_PATTERN
10561
10562
}  // namespace ada
10563
10564
#endif  // ADA_IMPLEMENTATION_INL_H
10565
/* end file include/ada/implementation-inl.h */
10566
10567
#endif  // ADA_H
10568
/* end file include/ada.h */