Coverage Report

Created: 2025-10-28 06:49

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-13 10:52:31 -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
21.4k
ada_really_inline constexpr bool bit_at(const uint8_t a[], const uint8_t i) {
998
21.4k
  return !!(a[i >> 3] & (1 << (i & 7)));
999
21.4k
}
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
1.46k
constexpr bool has_hex_prefix_unsafe(std::string_view input) {
1019
  // This is actually efficient code, see has_hex_prefix for the assembly.
1020
1.46k
  constexpr bool is_little_endian = std::endian::native == std::endian::little;
1021
1.46k
  constexpr uint16_t word0x = 0x7830;
1022
1.46k
  uint16_t two_first_bytes =
1023
1.46k
      static_cast<uint16_t>(input[0]) |
1024
1.46k
      static_cast<uint16_t>((static_cast<uint16_t>(input[1]) << 8));
1025
1.46k
  if constexpr (is_little_endian) {
1026
1.46k
    two_first_bytes |= 0x2000;
1027
  } else {
1028
    two_first_bytes |= 0x020;
1029
  }
1030
1.46k
  return two_first_bytes == word0x;
1031
1.46k
}
1032
1033
1.76k
constexpr bool has_hex_prefix(std::string_view input) {
1034
1.76k
  return input.size() >= 2 && has_hex_prefix_unsafe(input);
1035
1.76k
}
1036
1037
9.56k
constexpr bool is_digit(char x) noexcept { return (x >= '0') & (x <= '9'); }
1038
1039
21.7k
constexpr char to_lower(char x) noexcept { return (x | 0x20); }
1040
1041
11.3k
constexpr bool is_alpha(char x) noexcept {
1042
11.3k
  return (to_lower(x) >= 'a') && (to_lower(x) <= 'z');
1043
11.3k
}
1044
1045
717
constexpr bool is_windows_drive_letter(std::string_view input) noexcept {
1046
717
  return input.size() >= 2 &&
1047
605
         (is_alpha(input[0]) && ((input[1] == ':') || (input[1] == '|'))) &&
1048
70
         ((input.size() == 2) || (input[2] == '/' || input[2] == '\\' ||
1049
46
                                  input[2] == '?' || input[2] == '#'));
1050
717
}
1051
1052
constexpr bool is_normalized_windows_drive_letter(
1053
0
    std::string_view input) noexcept {
1054
0
  return input.size() >= 2 && (is_alpha(input[0]) && (input[1] == ':'));
1055
0
}
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
28.3k
  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
18.9k
                                                       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
18.9k
  return input.substr(pos1, pos2 - pos1);
1476
18.9k
}
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
6.24k
inline void inner_concat(std::string& buffer, T t) {
1528
6.24k
  buffer.append(t);
1529
6.24k
}
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
166
inline void inner_concat(std::string& buffer, T t) {
1528
166
  buffer.append(t);
1529
166
}
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
6.07k
inline void inner_concat(std::string& buffer, T t) {
1528
6.07k
  buffer.append(t);
1529
6.07k
}
Unexecuted instantiation: 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> >)
1530
1531
/**
1532
 * @private
1533
 */
1534
template <typename T, typename... Args>
1535
6.24k
inline void inner_concat(std::string& buffer, T t, Args... args) {
1536
6.24k
  buffer.append(t);
1537
6.24k
  return inner_concat(buffer, args...);
1538
6.24k
}
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
166
inline void inner_concat(std::string& buffer, T t, Args... args) {
1536
166
  buffer.append(t);
1537
166
  return inner_concat(buffer, args...);
1538
166
}
Unexecuted instantiation: 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> >)
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
6.07k
inline void inner_concat(std::string& buffer, T t, Args... args) {
1536
6.07k
  buffer.append(t);
1537
6.07k
  return inner_concat(buffer, args...);
1538
6.07k
}
Unexecuted instantiation: 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*)
Unexecuted instantiation: 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> >)
Unexecuted instantiation: 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> >)
1539
1540
/**
1541
 * @private
1542
 * Concatenate the arguments and return a string.
1543
 * @returns a string
1544
 */
1545
template <typename... Args>
1546
6.24k
std::string concat(Args... args) {
1547
6.24k
  std::string answer;
1548
6.24k
  inner_concat(answer, args...);
1549
6.24k
  return answer;
1550
6.24k
}
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
166
std::string concat(Args... args) {
1547
166
  std::string answer;
1548
166
  inner_concat(answer, args...);
1549
166
  return answer;
1550
166
}
Unexecuted instantiation: 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> >)
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
6.07k
std::string concat(Args... args) {
1547
6.07k
  std::string answer;
1548
6.07k
  inner_concat(answer, args...);
1549
6.07k
  return answer;
1550
6.07k
}
Unexecuted instantiation: 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*)
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> >)
Unexecuted instantiation: 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> >)
1551
1552
/**
1553
 * @private
1554
 * @return Number of leading zeroes.
1555
 */
1556
0
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
0
  return __builtin_clz(input_num);
1563
0
#endif  // ADA_REGULAR_VISUAL_STUDIO
1564
0
}
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
0
inline int fast_digit_count(uint32_t x) noexcept {
1573
0
  auto int_log2 = [](uint32_t z) -> int {
1574
0
    return 31 - ada::helpers::leading_zeroes(z | 1);
1575
0
  };
1576
0
  // Compiles to very few instructions. Note that the
1577
0
  // table is static and thus effectively a constant.
1578
0
  // We leave it inside the function because it is meaningless
1579
0
  // outside of it (this comes at no performance cost).
1580
0
  const static uint64_t table[] = {
1581
0
      4294967296,  8589934582,  8589934582,  8589934582,  12884901788,
1582
0
      12884901788, 12884901788, 17179868184, 17179868184, 17179868184,
1583
0
      21474826480, 21474826480, 21474826480, 21474826480, 25769703776,
1584
0
      25769703776, 25769703776, 30063771072, 30063771072, 30063771072,
1585
0
      34349738368, 34349738368, 34349738368, 34349738368, 38554705664,
1586
0
      38554705664, 38554705664, 41949672960, 41949672960, 41949672960,
1587
0
      42949672960, 42949672960};
1588
0
  return int((x + table[int_log2(x)]) >> 32);
1589
0
}
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
0
#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
0
  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
0
  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
0
      : m_val(std::forward<Args>(args)...), m_has_val(true) {}
Unexecuted instantiation: _ZN2tl6detail21expected_storage_baseIN3ada3urlENS2_6errorsELb0ELb1EEC2IJS3_ETnPNSt3__19enable_ifIXsr3std16is_constructibleIS3_DpOT_EE5valueEvE4typeELPv0EEENS_10in_place_tESB_
Unexecuted instantiation: _ZN2tl6detail21expected_storage_baseIN3ada14url_aggregatorENS2_6errorsELb0ELb1EEC2IJS3_ETnPNSt3__19enable_ifIXsr3std16is_constructibleIS3_DpOT_EE5valueEvE4typeELPv0EEENS_10in_place_tESB_
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
0
      : m_unexpect(std::forward<Args>(args)...), m_has_val(false) {}
Unexecuted instantiation: _ZN2tl6detail21expected_storage_baseIN3ada3urlENS2_6errorsELb0ELb1EEC2IJS4_ETnPNSt3__19enable_ifIXsr3std16is_constructibleIS4_DpOT_EE5valueEvE4typeELPv0EEENS_10unexpect_tESB_
Unexecuted instantiation: _ZN2tl6detail21expected_storage_baseIN3ada14url_aggregatorENS2_6errorsELb0ELb1EEC2IJS4_ETnPNSt3__19enable_ifIXsr3std16is_constructibleIS4_DpOT_EE5valueEvE4typeELPv0EEENS_10unexpect_tESB_
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
0
  ~expected_storage_base() {
2244
0
    if (m_has_val) {
2245
0
      m_val.~T();
2246
0
    }
2247
0
  }
Unexecuted instantiation: tl::detail::expected_storage_base<ada::url, ada::errors, false, true>::~expected_storage_base()
Unexecuted instantiation: tl::detail::expected_storage_base<ada::url_aggregator, ada::errors, false, true>::~expected_storage_base()
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
0
  constexpr explicit expected_default_ctor_base(default_constructor_tag) {}
Unexecuted instantiation: tl::detail::expected_default_ctor_base<ada::url, ada::errors, true>::expected_default_ctor_base(tl::detail::default_constructor_tag)
Unexecuted instantiation: tl::detail::expected_default_ctor_base<ada::url_aggregator, ada::errors, true>::expected_default_ctor_base(tl::detail::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
0
  T *valptr() { return std::addressof(this->m_val); }
Unexecuted instantiation: tl::expected<ada::url, ada::errors>::valptr()
Unexecuted instantiation: tl::expected<ada::url_aggregator, ada::errors>::valptr()
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
0
  TL_EXPECTED_11_CONSTEXPR U &val() {
2924
0
    return this->m_val;
2925
0
  }
Unexecuted instantiation: _ZN2tl8expectedIN3ada3urlENS1_6errorsEE3valIS2_TnPNSt3__19enable_ifIXntsr3std7is_voidIT_EE5valueEvE4typeELPv0EEERS8_v
Unexecuted instantiation: _ZN2tl8expectedIN3ada14url_aggregatorENS1_6errorsEE3valIS2_TnPNSt3__19enable_ifIXntsr3std7is_voidIT_EE5valueEvE4typeELPv0EEERS8_v
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
0
      : impl_base(in_place, std::forward<Args>(args)...),
3213
0
        ctor_base(detail::default_constructor_tag{}) {}
Unexecuted instantiation: _ZN2tl8expectedIN3ada3urlENS1_6errorsEEC2IJS2_ETnPNSt3__19enable_ifIXsr3std16is_constructibleIS2_DpOT_EE5valueEvE4typeELPv0EEENS_10in_place_tESA_
Unexecuted instantiation: _ZN2tl8expectedIN3ada14url_aggregatorENS1_6errorsEEC2IJS2_ETnPNSt3__19enable_ifIXsr3std16is_constructibleIS2_DpOT_EE5valueEvE4typeELPv0EEENS_10in_place_tESA_
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
0
      : impl_base(unexpect, std::move(e.value())),
3256
0
        ctor_base(detail::default_constructor_tag{}) {}
Unexecuted instantiation: _ZN2tl8expectedIN3ada3urlENS1_6errorsEEC2IS3_TnPNSt3__19enable_ifIXsr3std16is_constructibleIS3_OT_EE5valueEvE4typeELPv0ETnPNS7_IXsr3std14is_convertibleIS9_S3_EE5valueEvE4typeELSD_0EEEONS_10unexpectedIS8_EE
Unexecuted instantiation: _ZN2tl8expectedIN3ada14url_aggregatorENS1_6errorsEEC2IS3_TnPNSt3__19enable_ifIXsr3std16is_constructibleIS3_OT_EE5valueEvE4typeELPv0ETnPNS7_IXsr3std14is_convertibleIS9_S3_EE5valueEvE4typeELSD_0EEEONS_10unexpectedIS8_EE
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
0
      : expected(in_place, std::forward<U>(v)) {}
Unexecuted instantiation: _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_
Unexecuted instantiation: _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_
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
0
  TL_EXPECTED_11_CONSTEXPR T *operator->() {
3626
0
    TL_ASSERT(has_value());
3627
0
    return valptr();
3628
0
  }
Unexecuted instantiation: tl::expected<ada::url, ada::errors>::operator->()
Unexecuted instantiation: tl::expected<ada::url_aggregator, ada::errors>::operator->()
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
0
  TL_EXPECTED_11_CONSTEXPR U &operator*() & {
3639
0
    TL_ASSERT(has_value());
3640
0
    return val();
3641
0
  }
Unexecuted instantiation: _ZNR2tl8expectedIN3ada3urlENS1_6errorsEEdeIS2_TnPNSt3__19enable_ifIXntsr3std7is_voidIT_EE5valueEvE4typeELPv0EEERS8_v
Unexecuted instantiation: _ZNR2tl8expectedIN3ada14url_aggregatorENS1_6errorsEEdeIS2_TnPNSt3__19enable_ifIXntsr3std7is_voidIT_EE5valueEvE4typeELPv0EEERS8_v
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
0
  constexpr bool has_value() const noexcept { return this->m_has_val; }
Unexecuted instantiation: tl::expected<ada::url, ada::errors>::has_value() const
Unexecuted instantiation: tl::expected<ada::url_aggregator, ada::errors>::has_value() const
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
0
  constexpr explicit operator bool() const noexcept { return this->m_has_val; }
Unexecuted instantiation: tl::expected<ada::url, ada::errors>::operator bool() const
Unexecuted instantiation: tl::expected<ada::url_aggregator, ada::errors>::operator bool() const
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
28.3k
  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
0
  url() = default;
4658
  url(const url &u) = default;
4659
0
  url(url &&u) noexcept = default;
4660
  url &operator=(url &&u) noexcept = default;
4661
0
  url &operator=(const url &u) = default;
4662
0
  ~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
0
  ada_really_inline size_t parse_port(std::string_view view) noexcept override {
4978
0
    return this->parse_port(view, false);
4979
0
  }
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
0
ada_really_inline constexpr bool is_special(std::string_view scheme) {
6107
0
  if (scheme.empty()) {
6108
0
    return false;
6109
0
  }
6110
0
  int hash_value = (2 * scheme.size() + (unsigned)(scheme[0])) & 7;
6111
0
  const std::string_view target = details::is_special_list[hash_value];
6112
0
  return (target[0] == scheme[0]) && (target.substr(1) == scheme.substr(1));
6113
0
}
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
516
constexpr uint16_t get_special_port(ada::scheme::type type) noexcept {
6127
516
  return details::special_ports[int(type)];
6128
516
}
6129
16.0k
constexpr ada::scheme::type get_scheme_type(std::string_view scheme) noexcept {
6130
16.0k
  if (scheme.empty()) {
6131
0
    return ada::scheme::NOT_SPECIAL;
6132
0
  }
6133
16.0k
  int hash_value = (2 * scheme.size() + (unsigned)(scheme[0])) & 7;
6134
16.0k
  const std::string_view target = details::is_special_list[hash_value];
6135
16.0k
  if ((target[0] == scheme[0]) && (target.substr(1) == scheme.substr(1))) {
6136
7.39k
    return ada::scheme::type(hash_value);
6137
8.64k
  } else {
6138
8.64k
    return ada::scheme::NOT_SPECIAL;
6139
8.64k
  }
6140
16.0k
}
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
45.5k
    const noexcept {
6577
45.5k
  return type != ada::scheme::NOT_SPECIAL;
6578
45.5k
}
6579
6580
0
[[nodiscard]] inline uint16_t url_base::get_special_port() const noexcept {
6581
0
  return ada::scheme::get_special_port(type);
6582
0
}
6583
6584
[[nodiscard]] ada_really_inline uint16_t
6585
516
url_base::scheme_default_port() const noexcept {
6586
516
  return scheme::get_special_port(type);
6587
516
}
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
0
[[nodiscard]] ada_really_inline bool url::has_credentials() const noexcept {
6611
0
  return !username.empty() || !password.empty();
6612
0
}
6613
0
[[nodiscard]] ada_really_inline bool url::has_port() const noexcept {
6614
0
  return port.has_value();
6615
0
}
6616
0
[[nodiscard]] inline bool url::cannot_have_credentials_or_port() const {
6617
0
  return !host.has_value() || host.value().empty() ||
6618
0
         type == ada::scheme::type::FILE;
6619
0
}
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
0
[[nodiscard]] constexpr std::string_view url::get_pathname() const noexcept {
6638
0
  return path;
6639
0
}
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
0
inline void url::update_base_hostname(std::string_view input) { host = input; }
6715
6716
0
inline void url::update_unencoded_base_hash(std::string_view input) {
6717
  // We do the percent encoding
6718
0
  hash = unicode::percent_encode(input,
6719
0
                                 ada::character_sets::FRAGMENT_PERCENT_ENCODE);
6720
0
}
6721
6722
inline void url::update_base_search(std::string_view input,
6723
0
                                    const uint8_t query_percent_encode_set[]) {
6724
0
  query = ada::unicode::percent_encode(input, query_percent_encode_set);
6725
0
}
6726
6727
0
inline void url::update_base_search(std::optional<std::string> &&input) {
6728
0
  query = std::move(input);
6729
0
}
6730
6731
0
inline void url::update_base_pathname(const std::string_view input) {
6732
0
  path = input;
6733
0
}
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
0
inline void url::update_base_port(std::optional<uint16_t> input) {
6744
0
  port = input;
6745
0
}
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
0
[[nodiscard]] constexpr bool url::has_search() const noexcept {
6756
0
  return query.has_value();
6757
0
}
6758
6759
0
constexpr void url::set_protocol_as_file() { type = ada::scheme::type::FILE; }
6760
6761
0
inline void url::set_scheme(std::string &&new_scheme) noexcept {
6762
0
  type = ada::scheme::get_scheme_type(new_scheme);
6763
  // We only move the 'scheme' if it is non-special.
6764
0
  if (!is_special()) {
6765
0
    non_special_scheme = std::move(new_scheme);
6766
0
  }
6767
0
}
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
0
[[nodiscard]] ada_really_inline std::string url::get_href() const noexcept {
6780
0
  std::string output = get_protocol();
6781
0
6782
0
  if (host.has_value()) {
6783
0
    output += "//";
6784
0
    if (has_credentials()) {
6785
0
      output += username;
6786
0
      if (!password.empty()) {
6787
0
        output += ":" + get_password();
6788
0
      }
6789
0
      output += "@";
6790
0
    }
6791
0
    output += host.value();
6792
0
    if (port.has_value()) {
6793
0
      output += ":" + get_port();
6794
0
    }
6795
0
  } else if (!has_opaque_path && path.starts_with("//")) {
6796
0
    // If url's host is null, url does not have an opaque path, url's path's
6797
0
    // size is greater than 1, and url's path[0] is the empty string, then
6798
0
    // append U+002F (/) followed by U+002E (.) to output.
6799
0
    output += "/.";
6800
0
  }
6801
0
  output += path;
6802
0
  if (query.has_value()) {
6803
0
    output += "?" + query.value();
6804
0
  }
6805
0
  if (hash.has_value()) {
6806
0
    output += "#" + hash.value();
6807
0
  }
6808
0
  return output;
6809
0
}
6810
6811
ada_really_inline size_t url::parse_port(std::string_view view,
6812
0
                                         bool check_trailing_content) noexcept {
6813
0
  ada_log("parse_port('", view, "') ", view.size());
6814
0
  if (!view.empty() && view[0] == '-') {
6815
0
    ada_log("parse_port: view[0] == '0' && view.size() > 1");
6816
0
    is_valid = false;
6817
0
    return 0;
6818
0
  }
6819
0
  uint16_t parsed_port{};
6820
0
  auto r = std::from_chars(view.data(), view.data() + view.size(), parsed_port);
6821
0
  if (r.ec == std::errc::result_out_of_range) {
6822
0
    ada_log("parse_port: r.ec == std::errc::result_out_of_range");
6823
0
    is_valid = false;
6824
0
    return 0;
6825
0
  }
6826
0
  ada_log("parse_port: ", parsed_port);
6827
0
  const auto consumed = size_t(r.ptr - view.data());
6828
0
  ada_log("parse_port: consumed ", consumed);
6829
0
  if (check_trailing_content) {
6830
0
    is_valid &=
6831
0
        (consumed == view.size() || view[consumed] == '/' ||
6832
0
         view[consumed] == '?' || (is_special() && view[consumed] == '\\'));
6833
0
  }
6834
0
  ada_log("parse_port: is_valid = ", is_valid);
6835
0
  if (is_valid) {
6836
    // scheme_default_port can return 0, and we should allow 0 as a base port.
6837
0
    auto default_port = scheme_default_port();
6838
0
    bool is_port_valid = (default_port == 0 && parsed_port == 0) ||
6839
0
                         (default_port != parsed_port);
6840
0
    port = (r.ec == std::errc() && is_port_valid) ? std::optional(parsed_port)
6841
0
                                                  : std::nullopt;
6842
0
  }
6843
0
  return consumed;
6844
0
}
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
0
    const noexcept {
6863
0
  /**
6864
0
   * https://user:pass@example.com:1234/foo/bar?baz#quux
6865
0
   *       |     |    |          | ^^^^|       |   |
6866
0
   *       |     |    |          | |   |       |   `----- hash_start
6867
0
   *       |     |    |          | |   |       `--------- search_start
6868
0
   *       |     |    |          | |   `----------------- pathname_start
6869
0
   *       |     |    |          | `--------------------- port
6870
0
   *       |     |    |          `----------------------- host_end
6871
0
   *       |     |    `---------------------------------- host_start
6872
0
   *       |     `--------------------------------------- username_end
6873
0
   *       `--------------------------------------------- protocol_end
6874
0
   */
6875
0
  // These conditions can be made more strict.
6876
0
  if (protocol_end == url_components::omitted) {
6877
0
    return false;
6878
0
  }
6879
0
  uint32_t index = protocol_end;
6880
0
6881
0
  if (username_end == url_components::omitted) {
6882
0
    return false;
6883
0
  }
6884
0
  if (username_end < index) {
6885
0
    return false;
6886
0
  }
6887
0
  index = username_end;
6888
0
6889
0
  if (host_start == url_components::omitted) {
6890
0
    return false;
6891
0
  }
6892
0
  if (host_start < index) {
6893
0
    return false;
6894
0
  }
6895
0
  index = host_start;
6896
0
6897
0
  if (port != url_components::omitted) {
6898
0
    if (port > 0xffff) {
6899
0
      return false;
6900
0
    }
6901
0
    uint32_t port_length = helpers::fast_digit_count(port) + 1;
6902
0
    if (index + port_length < index) {
6903
0
      return false;
6904
0
    }
6905
0
    index += port_length;
6906
0
  }
6907
0
6908
0
  if (pathname_start == url_components::omitted) {
6909
0
    return false;
6910
0
  }
6911
0
  if (pathname_start < index) {
6912
0
    return false;
6913
0
  }
6914
0
  index = pathname_start;
6915
0
6916
0
  if (search_start != url_components::omitted) {
6917
0
    if (search_start < index) {
6918
0
      return false;
6919
0
    }
6920
0
    index = search_start;
6921
0
  }
6922
0
6923
0
  if (hash_start != url_components::omitted) {
6924
0
    if (hash_start < index) {
6925
0
      return false;
6926
0
    }
6927
0
  }
6928
0
6929
0
  return true;
6930
0
}
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
28.3k
  url_aggregator() = default;
6963
0
  url_aggregator(const url_aggregator &u) = default;
6964
0
  url_aggregator(url_aggregator &&u) noexcept = default;
6965
6.50k
  url_aggregator &operator=(url_aggregator &&u) noexcept = default;
6966
0
  url_aggregator &operator=(const url_aggregator &u) = default;
6967
28.3k
  ~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
0
  ada_really_inline size_t parse_port(std::string_view view) noexcept override {
7190
0
    return this->parse_port(view, false);
7191
0
  }
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
221
                                              const uint8_t character_set[]) {
7299
221
  const char* data = input.data();
7300
221
  const size_t size = input.size();
7301
7302
  // Process 8 bytes at a time using unrolled loop
7303
221
  size_t i = 0;
7304
430
  for (; i + 8 <= size; i += 8) {
7305
296
    unsigned char chunk[8];
7306
296
    std::memcpy(&chunk, data + i,
7307
296
                8);  // entices compiler to unconditionally process 8 characters
7308
7309
    // Check 8 characters at once
7310
2.08k
    for (size_t j = 0; j < 8; j++) {
7311
1.87k
      if (character_sets::bit_at(character_set, chunk[j])) {
7312
87
        return i + j;
7313
87
      }
7314
1.87k
    }
7315
296
  }
7316
7317
  // Handle remaining bytes
7318
260
  for (; i < size; i++) {
7319
182
    if (character_sets::bit_at(character_set, data[i])) {
7320
56
      return i;
7321
56
    }
7322
182
  }
7323
7324
78
  return size;
7325
134
}
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
320
    std::string_view base_buffer, const ada::url_components &base) {
7339
320
  std::string_view input = base_buffer.substr(
7340
320
      base.protocol_end, base.host_start - base.protocol_end);
7341
320
  ada_log("url_aggregator::update_base_authority ", input);
7342
7343
320
  bool input_starts_with_dash = input.starts_with("//");
7344
320
  uint32_t diff = components.host_start - components.protocol_end;
7345
7346
320
  buffer.erase(components.protocol_end,
7347
320
               components.host_start - components.protocol_end);
7348
320
  components.username_end = components.protocol_end;
7349
7350
320
  if (input_starts_with_dash) {
7351
198
    input.remove_prefix(2);
7352
198
    diff += 2;  // add "//"
7353
198
    buffer.insert(components.protocol_end, "//");
7354
198
    components.username_end += 2;
7355
198
  }
7356
7357
320
  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
320
  if (password_delimiter != std::string_view::npos) {
7362
    // Insert both username and password
7363
38
    std::string_view username = input.substr(0, password_delimiter);
7364
38
    std::string_view password = input.substr(password_delimiter + 1);
7365
7366
38
    buffer.insert(components.protocol_end + diff, username);
7367
38
    diff += uint32_t(username.size());
7368
38
    buffer.insert(components.protocol_end + diff, ":");
7369
38
    components.username_end = components.protocol_end + diff;
7370
38
    buffer.insert(components.protocol_end + diff + 1, password);
7371
38
    diff += uint32_t(password.size()) + 1;
7372
282
  } else if (!input.empty()) {
7373
    // Insert only username
7374
26
    buffer.insert(components.protocol_end + diff, input);
7375
26
    components.username_end =
7376
26
        components.protocol_end + diff + uint32_t(input.size());
7377
26
    diff += uint32_t(input.size());
7378
26
  }
7379
7380
320
  components.host_start += diff;
7381
7382
320
  if (buffer.size() > base.host_start && buffer[base.host_start] != '@') {
7383
0
    buffer.insert(components.host_start, "@");
7384
0
    diff++;
7385
0
  }
7386
320
  components.host_end += diff;
7387
320
  components.pathname_start += diff;
7388
320
  if (components.search_start != url_components::omitted) {
7389
0
    components.search_start += diff;
7390
0
  }
7391
320
  if (components.hash_start != url_components::omitted) {
7392
0
    components.hash_start += diff;
7393
0
  }
7394
320
}
7395
7396
107
inline void url_aggregator::update_unencoded_base_hash(std::string_view input) {
7397
107
  ada_log("url_aggregator::update_unencoded_base_hash ", input, " [",
7398
107
          input.size(), " bytes], buffer is '", buffer, "' [", buffer.size(),
7399
107
          " bytes] components.hash_start = ", components.hash_start);
7400
107
  ADA_ASSERT_TRUE(validate());
7401
107
  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
7402
107
  if (components.hash_start != url_components::omitted) {
7403
0
    buffer.resize(components.hash_start);
7404
0
  }
7405
107
  components.hash_start = uint32_t(buffer.size());
7406
107
  buffer += "#";
7407
107
  bool encoding_required = unicode::percent_encode<true>(
7408
107
      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
107
  if (!encoding_required) {
7412
51
    buffer.append(input);
7413
51
  }
7414
107
  ada_log("url_aggregator::update_unencoded_base_hash final buffer is '",
7415
107
          buffer, "' [", buffer.size(), " bytes]");
7416
107
  ADA_ASSERT_TRUE(validate());
7417
107
}
7418
7419
ada_really_inline uint32_t url_aggregator::replace_and_resize(
7420
8.94k
    uint32_t start, uint32_t end, std::string_view input) {
7421
8.94k
  uint32_t current_length = end - start;
7422
8.94k
  uint32_t input_size = uint32_t(input.size());
7423
8.94k
  uint32_t new_difference = input_size - current_length;
7424
7425
8.94k
  if (current_length == 0) {
7426
8.06k
    buffer.insert(start, input);
7427
8.06k
  } else if (input_size == current_length) {
7428
126
    buffer.replace(start, input_size, input);
7429
758
  } else if (input_size < current_length) {
7430
138
    buffer.erase(start, current_length - input_size);
7431
138
    buffer.replace(start, input_size, input);
7432
620
  } else {
7433
620
    buffer.replace(start, current_length, input.substr(0, current_length));
7434
620
    buffer.insert(start + current_length, input.substr(current_length));
7435
620
  }
7436
7437
8.94k
  return new_difference;
7438
8.94k
}
7439
7440
6.40k
inline void url_aggregator::update_base_hostname(const std::string_view input) {
7441
6.40k
  ada_log("url_aggregator::update_base_hostname ", input, " [", input.size(),
7442
6.40k
          " bytes], buffer is '", buffer, "' [", buffer.size(), " bytes]");
7443
6.40k
  ADA_ASSERT_TRUE(validate());
7444
6.40k
  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
7445
7446
  // This next line is required for when parsing a URL like `foo://`
7447
6.40k
  add_authority_slashes_if_needed();
7448
7449
6.40k
  bool has_credentials = components.protocol_end + 2 < components.host_start;
7450
6.40k
  uint32_t new_difference =
7451
6.40k
      replace_and_resize(components.host_start, components.host_end, input);
7452
7453
6.40k
  if (has_credentials) {
7454
317
    buffer.insert(components.host_start, "@");
7455
317
    new_difference++;
7456
317
  }
7457
6.40k
  components.host_end += new_difference;
7458
6.40k
  components.pathname_start += new_difference;
7459
6.40k
  if (components.search_start != url_components::omitted) {
7460
0
    components.search_start += new_difference;
7461
0
  }
7462
6.40k
  if (components.hash_start != url_components::omitted) {
7463
0
    components.hash_start += new_difference;
7464
0
  }
7465
6.40k
  ADA_ASSERT_TRUE(validate());
7466
6.40k
}
7467
7468
[[nodiscard]] ada_really_inline uint32_t
7469
2.54k
url_aggregator::get_pathname_length() const noexcept {
7470
2.54k
  ada_log("url_aggregator::get_pathname_length");
7471
2.54k
  uint32_t ending_index = uint32_t(buffer.size());
7472
2.54k
  if (components.search_start != url_components::omitted) {
7473
0
    ending_index = components.search_start;
7474
2.54k
  } else if (components.hash_start != url_components::omitted) {
7475
0
    ending_index = components.hash_start;
7476
0
  }
7477
2.54k
  return ending_index - components.pathname_start;
7478
2.54k
}
7479
7480
[[nodiscard]] ada_really_inline bool url_aggregator::is_at_path()
7481
0
    const noexcept {
7482
0
  return buffer.size() == components.pathname_start;
7483
0
}
7484
7485
432
inline void url_aggregator::update_base_search(std::string_view input) {
7486
432
  ada_log("url_aggregator::update_base_search ", input);
7487
432
  ADA_ASSERT_TRUE(validate());
7488
432
  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
7489
432
  if (input.empty()) {
7490
432
    clear_search();
7491
432
    return;
7492
432
  }
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
0
    std::string_view input, const uint8_t query_percent_encode_set[]) {
7526
0
  ada_log("url_aggregator::update_base_search ", input,
7527
0
          " with encoding parameter ", to_string(), "\n", to_diagram());
7528
0
  ADA_ASSERT_TRUE(validate());
7529
0
  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
7530
7531
0
  if (components.hash_start == url_components::omitted) {
7532
0
    if (components.search_start == url_components::omitted) {
7533
0
      components.search_start = uint32_t(buffer.size());
7534
0
      buffer += "?";
7535
0
    } else {
7536
0
      buffer.resize(components.search_start + 1);
7537
0
    }
7538
7539
0
    bool encoding_required =
7540
0
        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
0
    if (!encoding_required) {
7544
0
      buffer.append(input);
7545
0
    }
7546
0
  } 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
0
  ADA_ASSERT_TRUE(validate());
7575
0
}
7576
7577
2.54k
inline void url_aggregator::update_base_pathname(const std::string_view input) {
7578
2.54k
  ada_log("url_aggregator::update_base_pathname '", input, "' [", input.size(),
7579
2.54k
          " bytes] \n", to_diagram());
7580
2.54k
  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
7581
2.54k
  ADA_ASSERT_TRUE(validate());
7582
7583
2.54k
  const bool begins_with_dashdash = input.starts_with("//");
7584
2.54k
  if (!begins_with_dashdash && has_dash_dot()) {
7585
    // We must delete the ./
7586
0
    delete_dash_dot();
7587
0
  }
7588
7589
2.54k
  if (begins_with_dashdash && !has_opaque_path && !has_authority() &&
7590
0
      !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
0
    buffer.insert(components.pathname_start, "/.");
7595
0
    components.pathname_start += 2;
7596
0
  }
7597
7598
2.54k
  uint32_t difference = replace_and_resize(
7599
2.54k
      components.pathname_start,
7600
2.54k
      components.pathname_start + get_pathname_length(), input);
7601
2.54k
  if (components.search_start != url_components::omitted) {
7602
0
    components.search_start += difference;
7603
0
  }
7604
2.54k
  if (components.hash_start != url_components::omitted) {
7605
0
    components.hash_start += difference;
7606
0
  }
7607
2.54k
  ADA_ASSERT_TRUE(validate());
7608
2.54k
}
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
0
inline void url_aggregator::update_base_username(const std::string_view input) {
7644
0
  ada_log("url_aggregator::update_base_username '", input, "' ", to_string(),
7645
0
          "\n", to_diagram());
7646
0
  ADA_ASSERT_TRUE(validate());
7647
0
  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
7648
7649
0
  add_authority_slashes_if_needed();
7650
7651
0
  bool has_password = has_non_empty_password();
7652
0
  bool host_starts_with_at = buffer.size() > components.host_start &&
7653
0
                             buffer[components.host_start] == '@';
7654
0
  uint32_t diff = replace_and_resize(components.protocol_end + 2,
7655
0
                                     components.username_end, input);
7656
7657
0
  components.username_end += diff;
7658
0
  components.host_start += diff;
7659
7660
0
  if (!input.empty() && !host_starts_with_at) {
7661
0
    buffer.insert(components.host_start, "@");
7662
0
    diff++;
7663
0
  } 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
0
  components.host_end += diff;
7671
0
  components.pathname_start += diff;
7672
0
  if (components.search_start != url_components::omitted) {
7673
0
    components.search_start += diff;
7674
0
  }
7675
0
  if (components.hash_start != url_components::omitted) {
7676
0
    components.hash_start += diff;
7677
0
  }
7678
0
  ADA_ASSERT_TRUE(validate());
7679
0
}
7680
7681
4.86k
inline void url_aggregator::append_base_username(const std::string_view input) {
7682
4.86k
  ada_log("url_aggregator::append_base_username ", input);
7683
4.86k
  ADA_ASSERT_TRUE(validate());
7684
4.86k
  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
4.86k
  add_authority_slashes_if_needed();
7691
7692
  // If input is empty, do nothing.
7693
4.86k
  if (input.empty()) {
7694
0
    return;
7695
0
  }
7696
7697
4.86k
  uint32_t difference = uint32_t(input.size());
7698
4.86k
  buffer.insert(components.username_end, input);
7699
4.86k
  components.username_end += difference;
7700
4.86k
  components.host_start += difference;
7701
7702
4.86k
  if (buffer[components.host_start] != '@' &&
7703
227
      components.host_start != components.host_end) {
7704
227
    buffer.insert(components.host_start, "@");
7705
227
    difference++;
7706
227
  }
7707
7708
4.86k
  components.host_end += difference;
7709
4.86k
  components.pathname_start += difference;
7710
4.86k
  if (components.search_start != url_components::omitted) {
7711
0
    components.search_start += difference;
7712
0
  }
7713
4.86k
  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
4.86k
  ADA_ASSERT_TRUE(validate());
7723
4.86k
}
7724
7725
0
constexpr void url_aggregator::clear_password() {
7726
0
  ada_log("url_aggregator::clear_password ", to_string());
7727
0
  ADA_ASSERT_TRUE(validate());
7728
0
  if (!has_password()) {
7729
0
    return;
7730
0
  }
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
0
inline void url_aggregator::update_base_password(const std::string_view input) {
7746
0
  ada_log("url_aggregator::update_base_password ", input);
7747
0
  ADA_ASSERT_TRUE(validate());
7748
0
  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
7749
7750
0
  add_authority_slashes_if_needed();
7751
7752
  // TODO: Optimization opportunity. Merge the following removal functions.
7753
0
  if (input.empty()) {
7754
0
    clear_password();
7755
7756
    // Remove username too, if it is empty.
7757
0
    if (!has_non_empty_username()) {
7758
0
      update_base_username("");
7759
0
    }
7760
7761
0
    return;
7762
0
  }
7763
7764
0
  bool password_exists = has_password();
7765
0
  uint32_t difference = uint32_t(input.size());
7766
7767
0
  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
0
  } else {
7773
0
    buffer.insert(components.username_end, ":");
7774
0
    difference++;
7775
0
  }
7776
7777
0
  buffer.insert(components.username_end + 1, input);
7778
0
  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
0
  if (buffer[components.host_start] != '@') {
7784
0
    buffer.insert(components.host_start, "@");
7785
0
    difference++;
7786
0
  }
7787
7788
0
  components.host_end += difference;
7789
0
  components.pathname_start += difference;
7790
0
  if (components.search_start != url_components::omitted) {
7791
0
    components.search_start += difference;
7792
0
  }
7793
0
  if (components.hash_start != url_components::omitted) {
7794
0
    components.hash_start += difference;
7795
0
  }
7796
0
  ADA_ASSERT_TRUE(validate());
7797
0
}
7798
7799
3.13k
inline void url_aggregator::append_base_password(const std::string_view input) {
7800
3.13k
  ada_log("url_aggregator::append_base_password ", input, " ", to_string(),
7801
3.13k
          "\n", to_diagram());
7802
3.13k
  ADA_ASSERT_TRUE(validate());
7803
3.13k
  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
3.13k
  add_authority_slashes_if_needed();
7810
7811
  // If input is empty, do nothing.
7812
3.13k
  if (input.empty()) {
7813
0
    return;
7814
0
  }
7815
7816
3.13k
  uint32_t difference = uint32_t(input.size());
7817
3.13k
  if (has_password()) {
7818
3.03k
    buffer.insert(components.host_start, input);
7819
3.03k
  } else {
7820
104
    difference++;  // Increment for ":"
7821
104
    buffer.insert(components.username_end, ":");
7822
104
    buffer.insert(components.username_end + 1, input);
7823
104
  }
7824
3.13k
  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
3.13k
  if (buffer[components.host_start] != '@') {
7830
56
    buffer.insert(components.host_start, "@");
7831
56
    difference++;
7832
56
  }
7833
7834
3.13k
  components.host_end += difference;
7835
3.13k
  components.pathname_start += difference;
7836
3.13k
  if (components.search_start != url_components::omitted) {
7837
0
    components.search_start += difference;
7838
0
  }
7839
3.13k
  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
3.13k
  ADA_ASSERT_TRUE(validate());
7849
3.13k
}
7850
7851
465
inline void url_aggregator::update_base_port(uint32_t input) {
7852
465
  ada_log("url_aggregator::update_base_port");
7853
465
  ADA_ASSERT_TRUE(validate());
7854
465
  if (input == url_components::omitted) {
7855
299
    clear_port();
7856
299
    return;
7857
299
  }
7858
  // calling std::to_string(input.value()) is unfortunate given that the port
7859
  // value is probably already available as a string.
7860
166
  std::string value = helpers::concat(":", std::to_string(input));
7861
166
  uint32_t difference = uint32_t(value.size());
7862
7863
166
  if (components.port != url_components::omitted) {
7864
0
    difference -= components.pathname_start - components.host_end;
7865
0
    buffer.erase(components.host_end,
7866
0
                 components.pathname_start - components.host_end);
7867
0
  }
7868
7869
166
  buffer.insert(components.host_end, value);
7870
166
  components.pathname_start += difference;
7871
166
  if (components.search_start != url_components::omitted) {
7872
0
    components.search_start += difference;
7873
0
  }
7874
166
  if (components.hash_start != url_components::omitted) {
7875
0
    components.hash_start += difference;
7876
0
  }
7877
166
  components.port = input;
7878
166
  ADA_ASSERT_TRUE(validate());
7879
166
}
7880
7881
670
inline void url_aggregator::clear_port() {
7882
670
  ada_log("url_aggregator::clear_port");
7883
670
  ADA_ASSERT_TRUE(validate());
7884
670
  if (components.port == url_components::omitted) {
7885
670
    return;
7886
670
  }
7887
0
  uint32_t length = components.pathname_start - components.host_end;
7888
0
  buffer.erase(components.host_end, length);
7889
0
  components.pathname_start -= length;
7890
0
  if (components.search_start != url_components::omitted) {
7891
0
    components.search_start -= length;
7892
0
  }
7893
0
  if (components.hash_start != url_components::omitted) {
7894
0
    components.hash_start -= length;
7895
0
  }
7896
0
  components.port = url_components::omitted;
7897
0
  ADA_ASSERT_TRUE(validate());
7898
0
}
7899
7900
320
[[nodiscard]] inline uint32_t url_aggregator::retrieve_base_port() const {
7901
320
  ada_log("url_aggregator::retrieve_base_port");
7902
320
  return components.port;
7903
320
}
7904
7905
620
inline void url_aggregator::clear_search() {
7906
620
  ada_log("url_aggregator::clear_search");
7907
620
  ADA_ASSERT_TRUE(validate());
7908
620
  if (components.search_start == url_components::omitted) {
7909
620
    return;
7910
620
  }
7911
7912
0
  if (components.hash_start == url_components::omitted) {
7913
0
    buffer.resize(components.search_start);
7914
0
  } else {
7915
0
    buffer.erase(components.search_start,
7916
0
                 components.hash_start - components.search_start);
7917
0
    components.hash_start = components.search_start;
7918
0
  }
7919
7920
0
  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
0
  ADA_ASSERT_TRUE(validate());
7928
0
}
7929
7930
0
inline void url_aggregator::clear_hash() {
7931
0
  ada_log("url_aggregator::clear_hash");
7932
0
  ADA_ASSERT_TRUE(validate());
7933
0
  if (components.hash_start == url_components::omitted) {
7934
0
    return;
7935
0
  }
7936
0
  buffer.resize(components.hash_start);
7937
0
  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
0
  ADA_ASSERT_TRUE(validate());
7945
0
}
7946
7947
13
constexpr void url_aggregator::clear_pathname() {
7948
13
  ada_log("url_aggregator::clear_pathname");
7949
13
  ADA_ASSERT_TRUE(validate());
7950
13
  uint32_t ending_index = uint32_t(buffer.size());
7951
13
  if (components.search_start != url_components::omitted) {
7952
0
    ending_index = components.search_start;
7953
13
  } else if (components.hash_start != url_components::omitted) {
7954
0
    ending_index = components.hash_start;
7955
0
  }
7956
13
  uint32_t pathname_length = ending_index - components.pathname_start;
7957
13
  buffer.erase(components.pathname_start, pathname_length);
7958
13
  uint32_t difference = pathname_length;
7959
13
  if (components.pathname_start == components.host_end + 2 &&
7960
0
      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
13
  if (components.search_start != url_components::omitted) {
7967
0
    components.search_start -= difference;
7968
0
  }
7969
13
  if (components.hash_start != url_components::omitted) {
7970
0
    components.hash_start -= difference;
7971
0
  }
7972
13
  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
13
  ADA_ASSERT_TRUE(validate());
7979
13
  ada_log("url_aggregator::clear_pathname completed, running checks... ok");
7980
13
}
7981
7982
2
constexpr void url_aggregator::clear_hostname() {
7983
2
  ada_log("url_aggregator::clear_hostname");
7984
2
  ADA_ASSERT_TRUE(validate());
7985
2
  if (!has_authority()) {
7986
0
    return;
7987
0
  }
7988
2
  ADA_ASSERT_TRUE(has_authority());
7989
7990
2
  uint32_t hostname_length = components.host_end - components.host_start;
7991
2
  uint32_t start = components.host_start;
7992
7993
  // If hostname starts with "@", we should not remove that character.
7994
2
  if (hostname_length > 0 && buffer[start] == '@') {
7995
0
    start++;
7996
0
    hostname_length--;
7997
0
  }
7998
2
  buffer.erase(start, hostname_length);
7999
2
  components.host_end = start;
8000
2
  components.pathname_start -= hostname_length;
8001
2
  if (components.search_start != url_components::omitted) {
8002
0
    components.search_start -= hostname_length;
8003
0
  }
8004
2
  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
2
  ADA_ASSERT_TRUE(has_authority());
8013
2
  ADA_ASSERT_EQUAL(has_empty_hostname(), true,
8014
2
                   "hostname should have been cleared on buffer=" + buffer +
8015
2
                       " with " + components.to_string() + "\n" + to_diagram());
8016
2
  ADA_ASSERT_TRUE(validate());
8017
2
}
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
0
constexpr bool url_aggregator::has_credentials() const noexcept {
8030
0
  ada_log("url_aggregator::has_credentials");
8031
0
  return has_non_empty_username() || has_non_empty_password();
8032
0
}
8033
8034
0
constexpr bool url_aggregator::cannot_have_credentials_or_port() const {
8035
0
  ada_log("url_aggregator::cannot_have_credentials_or_port");
8036
0
  return type == ada::scheme::type::FILE ||
8037
0
         components.host_start == components.host_end;
8038
0
}
8039
8040
[[nodiscard]] ada_really_inline const ada::url_components &
8041
320
url_aggregator::get_components() const noexcept {
8042
320
  return components;
8043
320
}
8044
8045
[[nodiscard]] constexpr bool ada::url_aggregator::has_authority()
8046
14.5k
    const noexcept {
8047
14.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
14.5k
  return components.protocol_end + 2 <= components.host_start &&
8051
9.37k
         helpers::substring(buffer, components.protocol_end,
8052
9.37k
                            components.protocol_end + 2) == "//";
8053
14.5k
}
8054
8055
14.4k
inline void ada::url_aggregator::add_authority_slashes_if_needed() noexcept {
8056
14.4k
  ada_log("url_aggregator::add_authority_slashes_if_needed");
8057
14.4k
  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
14.4k
  if (has_authority()) {
8062
9.37k
    return;
8063
9.37k
  }
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
5.03k
  buffer.insert(components.protocol_end, "//");
8068
5.03k
  components.username_end += 2;
8069
5.03k
  components.host_start += 2;
8070
5.03k
  components.host_end += 2;
8071
5.03k
  components.pathname_start += 2;
8072
5.03k
  if (components.search_start != url_components::omitted) {
8073
0
    components.search_start += 2;
8074
0
  }
8075
5.03k
  if (components.hash_start != url_components::omitted) {
8076
0
    components.hash_start += 2;
8077
0
  }
8078
5.03k
  ADA_ASSERT_TRUE(validate());
8079
5.03k
}
8080
8081
0
constexpr void ada::url_aggregator::reserve(uint32_t capacity) {
8082
0
  buffer.reserve(capacity);
8083
0
}
8084
8085
0
constexpr bool url_aggregator::has_non_empty_username() const noexcept {
8086
0
  ada_log("url_aggregator::has_non_empty_username");
8087
0
  return components.protocol_end + 2 < components.username_end;
8088
0
}
8089
8090
0
constexpr bool url_aggregator::has_non_empty_password() const noexcept {
8091
0
  ada_log("url_aggregator::has_non_empty_password");
8092
0
  return components.host_start - components.username_end > 0;
8093
0
}
8094
8095
3.13k
constexpr bool url_aggregator::has_password() const noexcept {
8096
3.13k
  ada_log("url_aggregator::has_password");
8097
  // This function does not care about the length of the password
8098
3.13k
  return components.host_start > components.username_end &&
8099
3.03k
         buffer[components.username_end] == ':';
8100
3.13k
}
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
124
constexpr bool url_aggregator::has_hostname() const noexcept {
8116
124
  return has_authority();
8117
124
}
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
2.66k
[[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
2.66k
  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
2.66k
  return components.pathname_start == components.host_end + 2 &&
8154
4
         !has_opaque_path && buffer[components.host_end] == '/' &&
8155
0
         buffer[components.host_end + 1] == '.';
8156
2.66k
}
8157
8158
[[nodiscard]] constexpr std::string_view url_aggregator::get_href()
8159
320
    const noexcept ada_lifetime_bound {
8160
320
  ada_log("url_aggregator::get_href");
8161
320
  return buffer;
8162
320
}
8163
8164
ada_really_inline size_t url_aggregator::parse_port(
8165
633
    std::string_view view, bool check_trailing_content) noexcept {
8166
633
  ada_log("url_aggregator::parse_port('", view, "') ", view.size());
8167
633
  if (!view.empty() && view[0] == '-') {
8168
3
    ada_log("parse_port: view[0] == '0' && view.size() > 1");
8169
3
    is_valid = false;
8170
3
    return 0;
8171
3
  }
8172
630
  uint16_t parsed_port{};
8173
630
  auto r = std::from_chars(view.data(), view.data() + view.size(), parsed_port);
8174
630
  if (r.ec == std::errc::result_out_of_range) {
8175
34
    ada_log("parse_port: r.ec == std::errc::result_out_of_range");
8176
34
    is_valid = false;
8177
34
    return 0;
8178
34
  }
8179
596
  ada_log("parse_port: ", parsed_port);
8180
596
  const size_t consumed = size_t(r.ptr - view.data());
8181
596
  ada_log("parse_port: consumed ", consumed);
8182
596
  if (check_trailing_content) {
8183
596
    is_valid &=
8184
596
        (consumed == view.size() || view[consumed] == '/' ||
8185
90
         view[consumed] == '?' || (is_special() && view[consumed] == '\\'));
8186
596
  }
8187
596
  ada_log("parse_port: is_valid = ", is_valid);
8188
596
  if (is_valid) {
8189
516
    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
516
    auto default_port = scheme_default_port();
8192
516
    bool is_port_valid = (default_port == 0 && parsed_port == 0) ||
8193
500
                         (default_port != parsed_port);
8194
516
    if (r.ec == std::errc() && is_port_valid) {
8195
145
      update_base_port(parsed_port);
8196
371
    } else {
8197
371
      clear_port();
8198
371
    }
8199
516
  }
8200
596
  return consumed;
8201
630
}
8202
8203
871
constexpr void url_aggregator::set_protocol_as_file() {
8204
871
  ada_log("url_aggregator::set_protocol_as_file ");
8205
871
  ADA_ASSERT_TRUE(validate());
8206
871
  type = ada::scheme::type::FILE;
8207
  // next line could overflow but unsigned arithmetic has well-defined
8208
  // overflows.
8209
871
  uint32_t new_difference = 5 - components.protocol_end;
8210
8211
871
  if (buffer.empty()) {
8212
102
    buffer.append("file:");
8213
769
  } else {
8214
769
    buffer.erase(0, components.protocol_end);
8215
769
    buffer.insert(0, "file:");
8216
769
  }
8217
871
  components.protocol_end = 5;
8218
8219
  // Update the rest of the components.
8220
871
  components.username_end += new_difference;
8221
871
  components.host_start += new_difference;
8222
871
  components.host_end += new_difference;
8223
871
  components.pathname_start += new_difference;
8224
871
  if (components.search_start != url_components::omitted) {
8225
0
    components.search_start += new_difference;
8226
0
  }
8227
871
  if (components.hash_start != url_components::omitted) {
8228
0
    components.hash_start += new_difference;
8229
0
  }
8230
871
  ADA_ASSERT_TRUE(validate());
8231
871
}
8232
8233
0
[[nodiscard]] constexpr bool url_aggregator::validate() const noexcept {
8234
0
  if (!is_valid) {
8235
0
    return true;
8236
0
  }
8237
0
  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
0
  // We have a credible components struct, but let us investivate more
8243
0
  // carefully:
8244
0
  /**
8245
0
   * https://user:pass@example.com:1234/foo/bar?baz#quux
8246
0
   *       |     |    |          | ^^^^|       |   |
8247
0
   *       |     |    |          | |   |       |   `----- hash_start
8248
0
   *       |     |    |          | |   |       `--------- search_start
8249
0
   *       |     |    |          | |   `----------------- pathname_start
8250
0
   *       |     |    |          | `--------------------- port
8251
0
   *       |     |    |          `----------------------- host_end
8252
0
   *       |     |    `---------------------------------- host_start
8253
0
   *       |     `--------------------------------------- username_end
8254
0
   *       `--------------------------------------------- protocol_end
8255
0
   */
8256
0
  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
0
  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
0
  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
0
  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
0
  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
0
8277
0
  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
0
  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
0
  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
0
  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
0
  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
0
8299
0
  if (components.protocol_end > 0) {
8300
0
    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
0
  }
8307
0
8308
0
  if (components.username_end != buffer.size() &&
8309
0
      components.username_end > components.protocol_end + 2) {
8310
0
    if (buffer[components.username_end] != ':' &&
8311
0
        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
0
  }
8319
0
8320
0
  if (components.host_start != buffer.size()) {
8321
0
    if (components.host_start > components.username_end) {
8322
0
      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
0
    } else if (components.host_start == components.username_end &&
8329
0
               components.host_end > components.host_start) {
8330
0
      if (components.host_start == components.protocol_end + 2) {
8331
0
        if (buffer[components.protocol_end] != '/' ||
8332
0
            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
0
      } else {
8340
0
        if (components.host_start > components.protocol_end &&
8341
0
            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
0
      }
8349
0
    } else {
8350
0
      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
0
    }
8356
0
  }
8357
0
  if (components.host_end != buffer.size() &&
8358
0
      components.pathname_start > components.host_end) {
8359
0
    if (components.pathname_start == components.host_end + 2 &&
8360
0
        buffer[components.host_end] == '/' &&
8361
0
        buffer[components.host_end + 1] == '.') {
8362
0
      if (components.pathname_start + 1 >= buffer.size() ||
8363
0
          buffer[components.pathname_start] != '/' ||
8364
0
          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
0
    } 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
0
  }
8376
0
  if (components.pathname_start != buffer.size() &&
8377
0
      components.pathname_start < components.search_start &&
8378
0
      components.pathname_start < components.hash_start && !has_opaque_path) {
8379
0
    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
0
  }
8385
0
  if (components.search_start != url_components::omitted) {
8386
0
    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
0
  }
8392
0
  if (components.hash_start != url_components::omitted) {
8393
0
    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
0
  }
8399
0
8400
0
  return true;
8401
0
}
8402
8403
[[nodiscard]] constexpr std::string_view url_aggregator::get_pathname()
8404
633
    const noexcept ada_lifetime_bound {
8405
633
  ada_log("url_aggregator::get_pathname pathname_start = ",
8406
633
          components.pathname_start, " buffer.size() = ", buffer.size(),
8407
633
          " components.search_start = ", components.search_start,
8408
633
          " components.hash_start = ", components.hash_start);
8409
633
  auto ending_index = uint32_t(buffer.size());
8410
633
  if (components.search_start != url_components::omitted) {
8411
0
    ending_index = components.search_start;
8412
633
  } else if (components.hash_start != url_components::omitted) {
8413
0
    ending_index = components.hash_start;
8414
0
  }
8415
633
  return helpers::substring(buffer, components.pathname_start, ending_index);
8416
633
}
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
427
    const std::string_view input) noexcept {
8425
427
  ada_log("url_aggregator::update_host_to_base_host ", input);
8426
427
  ADA_ASSERT_TRUE(validate());
8427
427
  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
8428
427
  if (type != ada::scheme::type::FILE) {
8429
    // Let host be the result of host parsing host_view with url is not special.
8430
320
    if (input.empty() && !is_special()) {
8431
124
      if (has_hostname()) {
8432
2
        clear_hostname();
8433
122
      } else if (has_dash_dot()) {
8434
0
        add_authority_slashes_if_needed();
8435
0
        delete_dash_dot();
8436
0
      }
8437
124
      return;
8438
124
    }
8439
320
  }
8440
303
  update_base_hostname(input);
8441
303
  ADA_ASSERT_TRUE(validate());
8442
303
  return;
8443
427
}
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 */