Coverage Report

Created: 2025-07-12 07:04

/src/ada-url/build/singleheader/ada.h
Line
Count
Source (jump to first uncovered line)
1
/* auto-generated on 2025-07-10 09:56:15 -0400. Do not edit! */
2
/* begin file include/ada.h */
3
/**
4
 * @file ada.h
5
 * @brief Includes all definitions for Ada.
6
 */
7
#ifndef ADA_H
8
#define ADA_H
9
10
/* begin file include/ada/ada_idna.h */
11
/* auto-generated on 2025-03-08 13:17:11 -0500. Do not edit! */
12
/* begin file include/idna.h */
13
#ifndef ADA_IDNA_H
14
#define ADA_IDNA_H
15
16
/* begin file include/ada/idna/unicode_transcoding.h */
17
#ifndef ADA_IDNA_UNICODE_TRANSCODING_H
18
#define ADA_IDNA_UNICODE_TRANSCODING_H
19
20
#include <string>
21
#include <string_view>
22
23
namespace ada::idna {
24
25
size_t utf8_to_utf32(const char* buf, size_t len, char32_t* utf32_output);
26
27
size_t utf8_length_from_utf32(const char32_t* buf, size_t len);
28
29
size_t utf32_length_from_utf8(const char* buf, size_t len);
30
31
size_t utf32_to_utf8(const char32_t* buf, size_t len, char* utf8_output);
32
33
}  // namespace ada::idna
34
35
#endif  // ADA_IDNA_UNICODE_TRANSCODING_H
36
/* end file include/ada/idna/unicode_transcoding.h */
37
/* begin file include/ada/idna/mapping.h */
38
#ifndef ADA_IDNA_MAPPING_H
39
#define ADA_IDNA_MAPPING_H
40
41
#include <string>
42
#include <string_view>
43
44
namespace ada::idna {
45
46
// If the input is ascii, then the mapping is just -> lower case.
47
void ascii_map(char* input, size_t length);
48
// Map the characters according to IDNA, returning the empty string on error.
49
std::u32string map(std::u32string_view input);
50
51
}  // namespace ada::idna
52
53
#endif
54
/* end file include/ada/idna/mapping.h */
55
/* begin file include/ada/idna/normalization.h */
56
#ifndef ADA_IDNA_NORMALIZATION_H
57
#define ADA_IDNA_NORMALIZATION_H
58
59
#include <string>
60
#include <string_view>
61
62
namespace ada::idna {
63
64
// Normalize the characters according to IDNA (Unicode Normalization Form C).
65
void normalize(std::u32string& input);
66
67
}  // namespace ada::idna
68
#endif
69
/* end file include/ada/idna/normalization.h */
70
/* begin file include/ada/idna/punycode.h */
71
#ifndef ADA_IDNA_PUNYCODE_H
72
#define ADA_IDNA_PUNYCODE_H
73
74
#include <string>
75
#include <string_view>
76
77
namespace ada::idna {
78
79
bool punycode_to_utf32(std::string_view input, std::u32string& out);
80
bool verify_punycode(std::string_view input);
81
bool utf32_to_punycode(std::u32string_view input, std::string& out);
82
83
}  // namespace ada::idna
84
85
#endif  // ADA_IDNA_PUNYCODE_H
86
/* end file include/ada/idna/punycode.h */
87
/* begin file include/ada/idna/validity.h */
88
#ifndef ADA_IDNA_VALIDITY_H
89
#define ADA_IDNA_VALIDITY_H
90
91
#include <string>
92
#include <string_view>
93
94
namespace ada::idna {
95
96
/**
97
 * @see https://www.unicode.org/reports/tr46/#Validity_Criteria
98
 */
99
bool is_label_valid(std::u32string_view label);
100
101
}  // namespace ada::idna
102
103
#endif  // ADA_IDNA_VALIDITY_H
104
/* end file include/ada/idna/validity.h */
105
/* begin file include/ada/idna/to_ascii.h */
106
#ifndef ADA_IDNA_TO_ASCII_H
107
#define ADA_IDNA_TO_ASCII_H
108
109
#include <string>
110
#include <string_view>
111
112
namespace ada::idna {
113
114
// Converts a domain (e.g., www.google.com) possibly containing international
115
// characters to an ascii domain (with punycode). It will not do percent
116
// decoding: percent decoding should be done prior to calling this function. We
117
// do not remove tabs and spaces, they should have been removed prior to calling
118
// this function. We also do not trim control characters. We also assume that
119
// the input is not empty. We return "" on error.
120
//
121
//
122
// This function may accept or even produce invalid domains.
123
std::string to_ascii(std::string_view ut8_string);
124
125
// Returns true if the string contains a forbidden code point according to the
126
// WHATGL URL specification:
127
// https://url.spec.whatwg.org/#forbidden-domain-code-point
128
bool contains_forbidden_domain_code_point(std::string_view ascii_string);
129
130
bool constexpr is_ascii(std::u32string_view view);
131
bool constexpr is_ascii(std::string_view view);
132
133
}  // namespace ada::idna
134
135
#endif  // ADA_IDNA_TO_ASCII_H
136
/* end file include/ada/idna/to_ascii.h */
137
/* begin file include/ada/idna/to_unicode.h */
138
139
#ifndef ADA_IDNA_TO_UNICODE_H
140
#define ADA_IDNA_TO_UNICODE_H
141
142
#include <string_view>
143
144
namespace ada::idna {
145
146
std::string to_unicode(std::string_view input);
147
148
}  // namespace ada::idna
149
150
#endif  // ADA_IDNA_TO_UNICODE_H
151
/* end file include/ada/idna/to_unicode.h */
152
/* begin file include/ada/idna/identifier.h */
153
#ifndef ADA_IDNA_IDENTIFIER_H
154
#define ADA_IDNA_IDENTIFIER_H
155
156
#include <string>
157
#include <string_view>
158
159
namespace ada::idna {
160
161
// Verify if it is valid name code point given a Unicode code point and a
162
// boolean first: If first is true return the result of checking if code point
163
// is contained in the IdentifierStart set of code points. Otherwise return the
164
// result of checking if code point is contained in the IdentifierPart set of
165
// code points. Returns false if the input is empty or the code point is not
166
// valid. There is minimal Unicode error handling: the input should be valid
167
// UTF-8. https://urlpattern.spec.whatwg.org/#is-a-valid-name-code-point
168
bool valid_name_code_point(char32_t code_point, bool first);
169
170
}  // namespace ada::idna
171
172
#endif
173
/* end file include/ada/idna/identifier.h */
174
175
#endif
176
/* end file include/idna.h */
177
/* end file include/ada/ada_idna.h */
178
/* begin file include/ada/character_sets.h */
179
/**
180
 * @file character_sets.h
181
 * @brief Declaration of the character sets used by unicode functions.
182
 * @author Node.js
183
 * @see https://github.com/nodejs/node/blob/main/src/node_url_tables.cc
184
 */
185
#ifndef ADA_CHARACTER_SETS_H
186
#define ADA_CHARACTER_SETS_H
187
188
/* begin file include/ada/common_defs.h */
189
/**
190
 * @file common_defs.h
191
 * @brief Common definitions for cross-platform compiler support.
192
 */
193
#ifndef ADA_COMMON_DEFS_H
194
#define ADA_COMMON_DEFS_H
195
196
// https://en.cppreference.com/w/cpp/feature_test#Library_features
197
// detect C++20 features
198
#include <version>
199
200
#ifdef _MSC_VER
201
#define ADA_VISUAL_STUDIO 1
202
/**
203
 * We want to differentiate carefully between
204
 * clang under visual studio and regular visual
205
 * studio.
206
 */
207
#ifdef __clang__
208
// clang under visual studio
209
#define ADA_CLANG_VISUAL_STUDIO 1
210
#else
211
// just regular visual studio (best guess)
212
#define ADA_REGULAR_VISUAL_STUDIO 1
213
#endif  // __clang__
214
#endif  // _MSC_VER
215
216
#if defined(__GNUC__)
217
// Marks a block with a name so that MCA analysis can see it.
218
#define ADA_BEGIN_DEBUG_BLOCK(name) __asm volatile("# LLVM-MCA-BEGIN " #name);
219
#define ADA_END_DEBUG_BLOCK(name) __asm volatile("# LLVM-MCA-END " #name);
220
#define ADA_DEBUG_BLOCK(name, block) \
221
  BEGIN_DEBUG_BLOCK(name);           \
222
  block;                             \
223
  END_DEBUG_BLOCK(name);
224
#else
225
#define ADA_BEGIN_DEBUG_BLOCK(name)
226
#define ADA_END_DEBUG_BLOCK(name)
227
#define ADA_DEBUG_BLOCK(name, block)
228
#endif
229
230
// Align to N-byte boundary
231
#define ADA_ROUNDUP_N(a, n) (((a) + ((n)-1)) & ~((n)-1))
232
#define ADA_ROUNDDOWN_N(a, n) ((a) & ~((n)-1))
233
234
#define ADA_ISALIGNED_N(ptr, n) (((uintptr_t)(ptr) & ((n)-1)) == 0)
235
236
#if defined(ADA_REGULAR_VISUAL_STUDIO)
237
238
#define ada_really_inline __forceinline
239
#define ada_never_inline __declspec(noinline)
240
241
#define ada_unused
242
#define ada_warn_unused
243
244
#define ADA_PUSH_DISABLE_WARNINGS __pragma(warning(push))
245
#define ADA_PUSH_DISABLE_ALL_WARNINGS __pragma(warning(push, 0))
246
#define ADA_DISABLE_VS_WARNING(WARNING_NUMBER) \
247
  __pragma(warning(disable : WARNING_NUMBER))
248
// Get rid of Intellisense-only warnings (Code Analysis)
249
// Though __has_include is C++17, it is supported in Visual Studio 2017 or
250
// better (_MSC_VER>=1910).
251
#ifdef __has_include
252
#if __has_include(<CppCoreCheck\Warnings.h>)
253
#include <CppCoreCheck\Warnings.h>
254
#define ADA_DISABLE_UNDESIRED_WARNINGS \
255
  ADA_DISABLE_VS_WARNING(ALL_CPPCORECHECK_WARNINGS)
256
#endif
257
#endif
258
259
#ifndef ADA_DISABLE_UNDESIRED_WARNINGS
260
#define ADA_DISABLE_UNDESIRED_WARNINGS
261
#endif
262
263
#define ADA_DISABLE_DEPRECATED_WARNING ADA_DISABLE_VS_WARNING(4996)
264
#define ADA_DISABLE_STRICT_OVERFLOW_WARNING
265
#define ADA_POP_DISABLE_WARNINGS __pragma(warning(pop))
266
267
#else  // ADA_REGULAR_VISUAL_STUDIO
268
269
#define ada_really_inline inline __attribute__((always_inline))
270
#define ada_never_inline inline __attribute__((noinline))
271
272
#define ada_unused __attribute__((unused))
273
#define ada_warn_unused __attribute__((warn_unused_result))
274
275
#define ADA_PUSH_DISABLE_WARNINGS _Pragma("GCC diagnostic push")
276
// gcc doesn't seem to disable all warnings with all and extra, add warnings
277
// here as necessary
278
#define ADA_PUSH_DISABLE_ALL_WARNINGS               \
279
  ADA_PUSH_DISABLE_WARNINGS                         \
280
  ADA_DISABLE_GCC_WARNING("-Weffc++")               \
281
  ADA_DISABLE_GCC_WARNING("-Wall")                  \
282
  ADA_DISABLE_GCC_WARNING("-Wconversion")           \
283
  ADA_DISABLE_GCC_WARNING("-Wextra")                \
284
  ADA_DISABLE_GCC_WARNING("-Wattributes")           \
285
  ADA_DISABLE_GCC_WARNING("-Wimplicit-fallthrough") \
286
  ADA_DISABLE_GCC_WARNING("-Wnon-virtual-dtor")     \
287
  ADA_DISABLE_GCC_WARNING("-Wreturn-type")          \
288
  ADA_DISABLE_GCC_WARNING("-Wshadow")               \
289
  ADA_DISABLE_GCC_WARNING("-Wunused-parameter")     \
290
  ADA_DISABLE_GCC_WARNING("-Wunused-variable")      \
291
  ADA_DISABLE_GCC_WARNING("-Wsign-compare")
292
#define ADA_PRAGMA(P) _Pragma(#P)
293
#define ADA_DISABLE_GCC_WARNING(WARNING) \
294
  ADA_PRAGMA(GCC diagnostic ignored WARNING)
295
#if defined(ADA_CLANG_VISUAL_STUDIO)
296
#define ADA_DISABLE_UNDESIRED_WARNINGS \
297
  ADA_DISABLE_GCC_WARNING("-Wmicrosoft-include")
298
#else
299
#define ADA_DISABLE_UNDESIRED_WARNINGS
300
#endif
301
#define ADA_DISABLE_DEPRECATED_WARNING \
302
  ADA_DISABLE_GCC_WARNING("-Wdeprecated-declarations")
303
#define ADA_DISABLE_STRICT_OVERFLOW_WARNING \
304
  ADA_DISABLE_GCC_WARNING("-Wstrict-overflow")
305
#define ADA_POP_DISABLE_WARNINGS _Pragma("GCC diagnostic pop")
306
307
#endif  // MSC_VER
308
309
#if defined(ADA_VISUAL_STUDIO)
310
/**
311
 * It does not matter here whether you are using
312
 * the regular visual studio or clang under visual
313
 * studio.
314
 */
315
#if ADA_USING_LIBRARY
316
#define ADA_DLLIMPORTEXPORT __declspec(dllimport)
317
#else
318
#define ADA_DLLIMPORTEXPORT __declspec(dllexport)
319
#endif
320
#else
321
#define ADA_DLLIMPORTEXPORT
322
#endif
323
324
/// If EXPR is an error, returns it.
325
#define ADA_TRY(EXPR)   \
326
  {                     \
327
    auto _err = (EXPR); \
328
    if (_err) {         \
329
      return _err;      \
330
    }                   \
331
  }
332
333
// __has_cpp_attribute is part of C++20
334
#if !defined(__has_cpp_attribute)
335
#define __has_cpp_attribute(x) 0
336
#endif
337
338
#if __has_cpp_attribute(gnu::noinline)
339
#define ADA_ATTRIBUTE_NOINLINE [[gnu::noinline]]
340
#else
341
#define ADA_ATTRIBUTE_NOINLINE
342
#endif
343
344
namespace ada {
345
0
[[noreturn]] inline void unreachable() {
346
0
#ifdef __GNUC__
347
0
  __builtin_unreachable();
348
#elif defined(_MSC_VER)
349
  __assume(false);
350
#else
351
#endif
352
0
}
353
}  // namespace ada
354
355
// Unless the programmer has already set ADA_DEVELOPMENT_CHECKS,
356
// we want to set it under debug builds. We detect a debug build
357
// under Visual Studio when the _DEBUG macro is set. Under the other
358
// compilers, we use the fact that they define __OPTIMIZE__ whenever
359
// they allow optimizations.
360
// It is possible that this could miss some cases where ADA_DEVELOPMENT_CHECKS
361
// is helpful, but the programmer can set the macro ADA_DEVELOPMENT_CHECKS.
362
// It could also wrongly set ADA_DEVELOPMENT_CHECKS (e.g., if the programmer
363
// sets _DEBUG in a release build under Visual Studio, or if some compiler fails
364
// to set the __OPTIMIZE__ macro).
365
#if !defined(ADA_DEVELOPMENT_CHECKS) && !defined(NDEBUG)
366
#ifdef _MSC_VER
367
// Visual Studio seems to set _DEBUG for debug builds.
368
#ifdef _DEBUG
369
#define ADA_DEVELOPMENT_CHECKS 1
370
#endif  // _DEBUG
371
#else   // _MSC_VER
372
// All other compilers appear to set __OPTIMIZE__ to a positive integer
373
// when the compiler is optimizing.
374
#ifndef __OPTIMIZE__
375
#define ADA_DEVELOPMENT_CHECKS 1
376
#endif  // __OPTIMIZE__
377
#endif  // _MSC_VER
378
#endif  // ADA_DEVELOPMENT_CHECKS
379
380
#define ADA_STR(x) #x
381
382
#if ADA_DEVELOPMENT_CHECKS
383
#define ADA_REQUIRE(EXPR) \
384
  {                       \
385
    if (!(EXPR) { abort(); }) }
386
387
#define ADA_FAIL(MESSAGE)                            \
388
  do {                                               \
389
    std::cerr << "FAIL: " << (MESSAGE) << std::endl; \
390
    abort();                                         \
391
  } while (0);
392
#define ADA_ASSERT_EQUAL(LHS, RHS, MESSAGE)                                    \
393
  do {                                                                         \
394
    if (LHS != RHS) {                                                          \
395
      std::cerr << "Mismatch: '" << LHS << "' - '" << RHS << "'" << std::endl; \
396
      ADA_FAIL(MESSAGE);                                                       \
397
    }                                                                          \
398
  } while (0);
399
#define ADA_ASSERT_TRUE(COND)                                               \
400
  do {                                                                      \
401
    if (!(COND)) {                                                          \
402
      std::cerr << "Assert at line " << __LINE__ << " of file " << __FILE__ \
403
                << std::endl;                                               \
404
      ADA_FAIL(ADA_STR(COND));                                              \
405
    }                                                                       \
406
  } while (0);
407
#else
408
#define ADA_FAIL(MESSAGE)
409
#define ADA_ASSERT_EQUAL(LHS, RHS, MESSAGE)
410
#define ADA_ASSERT_TRUE(COND)
411
#endif
412
413
#ifdef ADA_VISUAL_STUDIO
414
#define ADA_ASSUME(COND) __assume(COND)
415
#else
416
#define ADA_ASSUME(COND)       \
417
  do {                         \
418
    if (!(COND)) {             \
419
      __builtin_unreachable(); \
420
    }                          \
421
  } while (0)
422
#endif
423
424
#if defined(__SSE2__) || defined(__x86_64__) || defined(__x86_64) || \
425
    (defined(_M_AMD64) || defined(_M_X64) ||                         \
426
     (defined(_M_IX86_FP) && _M_IX86_FP == 2))
427
#define ADA_SSE2 1
428
#endif
429
430
#if defined(__aarch64__) || defined(_M_ARM64)
431
#define ADA_NEON 1
432
#endif
433
434
#if defined(__loongarch_sx)
435
#define ADA_LSX 1
436
#endif
437
438
#ifndef __has_cpp_attribute
439
#define ada_lifetime_bound
440
#elif __has_cpp_attribute(msvc::lifetimebound)
441
#define ada_lifetime_bound [[msvc::lifetimebound]]
442
#elif __has_cpp_attribute(clang::lifetimebound)
443
#define ada_lifetime_bound [[clang::lifetimebound]]
444
#elif __has_cpp_attribute(lifetimebound)
445
#define ada_lifetime_bound [[lifetimebound]]
446
#else
447
#define ada_lifetime_bound
448
#endif
449
450
#ifdef __cpp_lib_format
451
#if __cpp_lib_format >= 202110L
452
#include <format>
453
#define ADA_HAS_FORMAT 1
454
#endif
455
#endif
456
457
#ifndef ADA_INCLUDE_URL_PATTERN
458
#define ADA_INCLUDE_URL_PATTERN 1
459
#endif  // ADA_INCLUDE_URL_PATTERN
460
461
#endif  // ADA_COMMON_DEFS_H
462
/* end file include/ada/common_defs.h */
463
#include <cstdint>
464
465
/**
466
 * These functions are not part of our public API and may
467
 * change at any time.
468
 * @private
469
 * @namespace ada::character_sets
470
 * @brief Includes the definitions for unicode character sets.
471
 */
472
namespace ada::character_sets {
473
ada_really_inline constexpr bool bit_at(const uint8_t a[], uint8_t i);
474
}  // namespace ada::character_sets
475
476
#endif  // ADA_CHARACTER_SETS_H
477
/* end file include/ada/character_sets.h */
478
/* begin file include/ada/character_sets-inl.h */
479
/**
480
 * @file character_sets-inl.h
481
 * @brief Definitions of the character sets used by unicode functions.
482
 * @author Node.js
483
 * @see https://github.com/nodejs/node/blob/main/src/node_url_tables.cc
484
 */
485
#ifndef ADA_CHARACTER_SETS_INL_H
486
#define ADA_CHARACTER_SETS_INL_H
487
488
489
/**
490
 * These functions are not part of our public API and may
491
 * change at any time.
492
 * @private
493
 */
494
namespace ada::character_sets {
495
496
constexpr char hex[1024] =
497
    "%00\0%01\0%02\0%03\0%04\0%05\0%06\0%07\0"
498
    "%08\0%09\0%0A\0%0B\0%0C\0%0D\0%0E\0%0F\0"
499
    "%10\0%11\0%12\0%13\0%14\0%15\0%16\0%17\0"
500
    "%18\0%19\0%1A\0%1B\0%1C\0%1D\0%1E\0%1F\0"
501
    "%20\0%21\0%22\0%23\0%24\0%25\0%26\0%27\0"
502
    "%28\0%29\0%2A\0%2B\0%2C\0%2D\0%2E\0%2F\0"
503
    "%30\0%31\0%32\0%33\0%34\0%35\0%36\0%37\0"
504
    "%38\0%39\0%3A\0%3B\0%3C\0%3D\0%3E\0%3F\0"
505
    "%40\0%41\0%42\0%43\0%44\0%45\0%46\0%47\0"
506
    "%48\0%49\0%4A\0%4B\0%4C\0%4D\0%4E\0%4F\0"
507
    "%50\0%51\0%52\0%53\0%54\0%55\0%56\0%57\0"
508
    "%58\0%59\0%5A\0%5B\0%5C\0%5D\0%5E\0%5F\0"
509
    "%60\0%61\0%62\0%63\0%64\0%65\0%66\0%67\0"
510
    "%68\0%69\0%6A\0%6B\0%6C\0%6D\0%6E\0%6F\0"
511
    "%70\0%71\0%72\0%73\0%74\0%75\0%76\0%77\0"
512
    "%78\0%79\0%7A\0%7B\0%7C\0%7D\0%7E\0%7F\0"
513
    "%80\0%81\0%82\0%83\0%84\0%85\0%86\0%87\0"
514
    "%88\0%89\0%8A\0%8B\0%8C\0%8D\0%8E\0%8F\0"
515
    "%90\0%91\0%92\0%93\0%94\0%95\0%96\0%97\0"
516
    "%98\0%99\0%9A\0%9B\0%9C\0%9D\0%9E\0%9F\0"
517
    "%A0\0%A1\0%A2\0%A3\0%A4\0%A5\0%A6\0%A7\0"
518
    "%A8\0%A9\0%AA\0%AB\0%AC\0%AD\0%AE\0%AF\0"
519
    "%B0\0%B1\0%B2\0%B3\0%B4\0%B5\0%B6\0%B7\0"
520
    "%B8\0%B9\0%BA\0%BB\0%BC\0%BD\0%BE\0%BF\0"
521
    "%C0\0%C1\0%C2\0%C3\0%C4\0%C5\0%C6\0%C7\0"
522
    "%C8\0%C9\0%CA\0%CB\0%CC\0%CD\0%CE\0%CF\0"
523
    "%D0\0%D1\0%D2\0%D3\0%D4\0%D5\0%D6\0%D7\0"
524
    "%D8\0%D9\0%DA\0%DB\0%DC\0%DD\0%DE\0%DF\0"
525
    "%E0\0%E1\0%E2\0%E3\0%E4\0%E5\0%E6\0%E7\0"
526
    "%E8\0%E9\0%EA\0%EB\0%EC\0%ED\0%EE\0%EF\0"
527
    "%F0\0%F1\0%F2\0%F3\0%F4\0%F5\0%F6\0%F7\0"
528
    "%F8\0%F9\0%FA\0%FB\0%FC\0%FD\0%FE\0%FF";
529
530
constexpr uint8_t C0_CONTROL_PERCENT_ENCODE[32] = {
531
    // 00     01     02     03     04     05     06     07
532
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
533
    // 08     09     0A     0B     0C     0D     0E     0F
534
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
535
    // 10     11     12     13     14     15     16     17
536
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
537
    // 18     19     1A     1B     1C     1D     1E     1F
538
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
539
    // 20     21     22     23     24     25     26     27
540
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
541
    // 28     29     2A     2B     2C     2D     2E     2F
542
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
543
    // 30     31     32     33     34     35     36     37
544
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
545
    // 38     39     3A     3B     3C     3D     3E     3F
546
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
547
    // 40     41     42     43     44     45     46     47
548
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
549
    // 48     49     4A     4B     4C     4D     4E     4F
550
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
551
    // 50     51     52     53     54     55     56     57
552
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
553
    // 58     59     5A     5B     5C     5D     5E     5F
554
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
555
    // 60     61     62     63     64     65     66     67
556
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
557
    // 68     69     6A     6B     6C     6D     6E     6F
558
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
559
    // 70     71     72     73     74     75     76     77
560
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
561
    // 78     79     7A     7B     7C     7D     7E     7F
562
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x80,
563
    // 80     81     82     83     84     85     86     87
564
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
565
    // 88     89     8A     8B     8C     8D     8E     8F
566
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
567
    // 90     91     92     93     94     95     96     97
568
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
569
    // 98     99     9A     9B     9C     9D     9E     9F
570
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
571
    // A0     A1     A2     A3     A4     A5     A6     A7
572
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
573
    // A8     A9     AA     AB     AC     AD     AE     AF
574
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
575
    // B0     B1     B2     B3     B4     B5     B6     B7
576
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
577
    // B8     B9     BA     BB     BC     BD     BE     BF
578
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
579
    // C0     C1     C2     C3     C4     C5     C6     C7
580
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
581
    // C8     C9     CA     CB     CC     CD     CE     CF
582
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
583
    // D0     D1     D2     D3     D4     D5     D6     D7
584
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
585
    // D8     D9     DA     DB     DC     DD     DE     DF
586
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
587
    // E0     E1     E2     E3     E4     E5     E6     E7
588
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
589
    // E8     E9     EA     EB     EC     ED     EE     EF
590
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
591
    // F0     F1     F2     F3     F4     F5     F6     F7
592
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
593
    // F8     F9     FA     FB     FC     FD     FE     FF
594
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80};
595
596
constexpr uint8_t SPECIAL_QUERY_PERCENT_ENCODE[32] = {
597
    // 00     01     02     03     04     05     06     07
598
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
599
    // 08     09     0A     0B     0C     0D     0E     0F
600
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
601
    // 10     11     12     13     14     15     16     17
602
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
603
    // 18     19     1A     1B     1C     1D     1E     1F
604
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
605
    // 20     21     22     23     24     25     26     27
606
    0x01 | 0x00 | 0x04 | 0x08 | 0x00 | 0x00 | 0x00 | 0x80,
607
    // 28     29     2A     2B     2C     2D     2E     2F
608
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
609
    // 30     31     32     33     34     35     36     37
610
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
611
    // 38     39     3A     3B     3C     3D     3E     3F
612
    0x00 | 0x00 | 0x00 | 0x00 | 0x10 | 0x00 | 0x40 | 0x00,
613
    // 40     41     42     43     44     45     46     47
614
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
615
    // 48     49     4A     4B     4C     4D     4E     4F
616
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
617
    // 50     51     52     53     54     55     56     57
618
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
619
    // 58     59     5A     5B     5C     5D     5E     5F
620
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
621
    // 60     61     62     63     64     65     66     67
622
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
623
    // 68     69     6A     6B     6C     6D     6E     6F
624
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
625
    // 70     71     72     73     74     75     76     77
626
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
627
    // 78     79     7A     7B     7C     7D     7E     7F
628
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x80,
629
    // 80     81     82     83     84     85     86     87
630
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
631
    // 88     89     8A     8B     8C     8D     8E     8F
632
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
633
    // 90     91     92     93     94     95     96     97
634
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
635
    // 98     99     9A     9B     9C     9D     9E     9F
636
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
637
    // A0     A1     A2     A3     A4     A5     A6     A7
638
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
639
    // A8     A9     AA     AB     AC     AD     AE     AF
640
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
641
    // B0     B1     B2     B3     B4     B5     B6     B7
642
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
643
    // B8     B9     BA     BB     BC     BD     BE     BF
644
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
645
    // C0     C1     C2     C3     C4     C5     C6     C7
646
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
647
    // C8     C9     CA     CB     CC     CD     CE     CF
648
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
649
    // D0     D1     D2     D3     D4     D5     D6     D7
650
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
651
    // D8     D9     DA     DB     DC     DD     DE     DF
652
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
653
    // E0     E1     E2     E3     E4     E5     E6     E7
654
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
655
    // E8     E9     EA     EB     EC     ED     EE     EF
656
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
657
    // F0     F1     F2     F3     F4     F5     F6     F7
658
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
659
    // F8     F9     FA     FB     FC     FD     FE     FF
660
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80};
661
662
constexpr uint8_t QUERY_PERCENT_ENCODE[32] = {
663
    // 00     01     02     03     04     05     06     07
664
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
665
    // 08     09     0A     0B     0C     0D     0E     0F
666
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
667
    // 10     11     12     13     14     15     16     17
668
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
669
    // 18     19     1A     1B     1C     1D     1E     1F
670
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
671
    // 20     21     22     23     24     25     26     27
672
    0x01 | 0x00 | 0x04 | 0x08 | 0x00 | 0x00 | 0x00 | 0x00,
673
    // 28     29     2A     2B     2C     2D     2E     2F
674
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
675
    // 30     31     32     33     34     35     36     37
676
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
677
    // 38     39     3A     3B     3C     3D     3E     3F
678
    0x00 | 0x00 | 0x00 | 0x00 | 0x10 | 0x00 | 0x40 | 0x00,
679
    // 40     41     42     43     44     45     46     47
680
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
681
    // 48     49     4A     4B     4C     4D     4E     4F
682
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
683
    // 50     51     52     53     54     55     56     57
684
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
685
    // 58     59     5A     5B     5C     5D     5E     5F
686
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
687
    // 60     61     62     63     64     65     66     67
688
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
689
    // 68     69     6A     6B     6C     6D     6E     6F
690
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
691
    // 70     71     72     73     74     75     76     77
692
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
693
    // 78     79     7A     7B     7C     7D     7E     7F
694
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x80,
695
    // 80     81     82     83     84     85     86     87
696
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
697
    // 88     89     8A     8B     8C     8D     8E     8F
698
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
699
    // 90     91     92     93     94     95     96     97
700
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
701
    // 98     99     9A     9B     9C     9D     9E     9F
702
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
703
    // A0     A1     A2     A3     A4     A5     A6     A7
704
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
705
    // A8     A9     AA     AB     AC     AD     AE     AF
706
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
707
    // B0     B1     B2     B3     B4     B5     B6     B7
708
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
709
    // B8     B9     BA     BB     BC     BD     BE     BF
710
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
711
    // C0     C1     C2     C3     C4     C5     C6     C7
712
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
713
    // C8     C9     CA     CB     CC     CD     CE     CF
714
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
715
    // D0     D1     D2     D3     D4     D5     D6     D7
716
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
717
    // D8     D9     DA     DB     DC     DD     DE     DF
718
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
719
    // E0     E1     E2     E3     E4     E5     E6     E7
720
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
721
    // E8     E9     EA     EB     EC     ED     EE     EF
722
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
723
    // F0     F1     F2     F3     F4     F5     F6     F7
724
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
725
    // F8     F9     FA     FB     FC     FD     FE     FF
726
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80};
727
728
constexpr uint8_t FRAGMENT_PERCENT_ENCODE[32] = {
729
    // 00     01     02     03     04     05     06     07
730
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
731
    // 08     09     0A     0B     0C     0D     0E     0F
732
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
733
    // 10     11     12     13     14     15     16     17
734
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
735
    // 18     19     1A     1B     1C     1D     1E     1F
736
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
737
    // 20     21     22     23     24     25     26     27
738
    0x01 | 0x00 | 0x04 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
739
    // 28     29     2A     2B     2C     2D     2E     2F
740
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
741
    // 30     31     32     33     34     35     36     37
742
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
743
    // 38     39     3A     3B     3C     3D     3E     3F
744
    0x00 | 0x00 | 0x00 | 0x00 | 0x10 | 0x00 | 0x40 | 0x00,
745
    // 40     41     42     43     44     45     46     47
746
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
747
    // 48     49     4A     4B     4C     4D     4E     4F
748
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
749
    // 50     51     52     53     54     55     56     57
750
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
751
    // 58     59     5A     5B     5C     5D     5E     5F
752
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
753
    // 60     61     62     63     64     65     66     67
754
    0x01 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
755
    // 68     69     6A     6B     6C     6D     6E     6F
756
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
757
    // 70     71     72     73     74     75     76     77
758
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
759
    // 78     79     7A     7B     7C     7D     7E     7F
760
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x80,
761
    // 80     81     82     83     84     85     86     87
762
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
763
    // 88     89     8A     8B     8C     8D     8E     8F
764
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
765
    // 90     91     92     93     94     95     96     97
766
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
767
    // 98     99     9A     9B     9C     9D     9E     9F
768
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
769
    // A0     A1     A2     A3     A4     A5     A6     A7
770
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
771
    // A8     A9     AA     AB     AC     AD     AE     AF
772
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
773
    // B0     B1     B2     B3     B4     B5     B6     B7
774
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
775
    // B8     B9     BA     BB     BC     BD     BE     BF
776
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
777
    // C0     C1     C2     C3     C4     C5     C6     C7
778
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
779
    // C8     C9     CA     CB     CC     CD     CE     CF
780
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
781
    // D0     D1     D2     D3     D4     D5     D6     D7
782
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
783
    // D8     D9     DA     DB     DC     DD     DE     DF
784
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
785
    // E0     E1     E2     E3     E4     E5     E6     E7
786
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
787
    // E8     E9     EA     EB     EC     ED     EE     EF
788
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
789
    // F0     F1     F2     F3     F4     F5     F6     F7
790
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
791
    // F8     F9     FA     FB     FC     FD     FE     FF
792
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80};
793
794
constexpr uint8_t USERINFO_PERCENT_ENCODE[32] = {
795
    // 00     01     02     03     04     05     06     07
796
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
797
    // 08     09     0A     0B     0C     0D     0E     0F
798
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
799
    // 10     11     12     13     14     15     16     17
800
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
801
    // 18     19     1A     1B     1C     1D     1E     1F
802
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
803
    // 20     21     22     23     24     25     26     27
804
    0x01 | 0x00 | 0x04 | 0x08 | 0x00 | 0x00 | 0x00 | 0x00,
805
    // 28     29     2A     2B     2C     2D     2E     2F
806
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x80,
807
    // 30     31     32     33     34     35     36     37
808
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
809
    // 38     39     3A     3B     3C     3D     3E     3F
810
    0x00 | 0x00 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
811
    // 40     41     42     43     44     45     46     47
812
    0x01 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
813
    // 48     49     4A     4B     4C     4D     4E     4F
814
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
815
    // 50     51     52     53     54     55     56     57
816
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
817
    // 58     59     5A     5B     5C     5D     5E     5F
818
    0x00 | 0x00 | 0x00 | 0x08 | 0x10 | 0x20 | 0x40 | 0x00,
819
    // 60     61     62     63     64     65     66     67
820
    0x01 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
821
    // 68     69     6A     6B     6C     6D     6E     6F
822
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
823
    // 70     71     72     73     74     75     76     77
824
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
825
    // 78     79     7A     7B     7C     7D     7E     7F
826
    0x00 | 0x00 | 0x00 | 0x08 | 0x10 | 0x20 | 0x00 | 0x80,
827
    // 80     81     82     83     84     85     86     87
828
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
829
    // 88     89     8A     8B     8C     8D     8E     8F
830
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
831
    // 90     91     92     93     94     95     96     97
832
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
833
    // 98     99     9A     9B     9C     9D     9E     9F
834
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
835
    // A0     A1     A2     A3     A4     A5     A6     A7
836
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
837
    // A8     A9     AA     AB     AC     AD     AE     AF
838
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
839
    // B0     B1     B2     B3     B4     B5     B6     B7
840
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
841
    // B8     B9     BA     BB     BC     BD     BE     BF
842
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
843
    // C0     C1     C2     C3     C4     C5     C6     C7
844
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
845
    // C8     C9     CA     CB     CC     CD     CE     CF
846
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
847
    // D0     D1     D2     D3     D4     D5     D6     D7
848
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
849
    // D8     D9     DA     DB     DC     DD     DE     DF
850
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
851
    // E0     E1     E2     E3     E4     E5     E6     E7
852
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
853
    // E8     E9     EA     EB     EC     ED     EE     EF
854
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
855
    // F0     F1     F2     F3     F4     F5     F6     F7
856
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
857
    // F8     F9     FA     FB     FC     FD     FE     FF
858
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80};
859
860
constexpr uint8_t PATH_PERCENT_ENCODE[32] = {
861
    // 00     01     02     03     04     05     06     07
862
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
863
    // 08     09     0A     0B     0C     0D     0E     0F
864
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
865
    // 10     11     12     13     14     15     16     17
866
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
867
    // 18     19     1A     1B     1C     1D     1E     1F
868
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
869
    // 20     21     22     23     24     25     26     27
870
    0x01 | 0x00 | 0x04 | 0x08 | 0x00 | 0x00 | 0x00 | 0x00,
871
    // 28     29     2A     2B     2C     2D     2E     2F
872
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
873
    // 30     31     32     33     34     35     36     37
874
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
875
    // 38     39     3A     3B     3C     3D     3E     3F
876
    0x00 | 0x00 | 0x00 | 0x00 | 0x10 | 0x00 | 0x40 | 0x80,
877
    // 40     41     42     43     44     45     46     47
878
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
879
    // 48     49     4A     4B     4C     4D     4E     4F
880
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
881
    // 50     51     52     53     54     55     56     57
882
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
883
    // 58     59     5A     5B     5C     5D     5E     5F
884
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x40 | 0x00,
885
    // 60     61     62     63     64     65     66     67
886
    0x01 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
887
    // 68     69     6A     6B     6C     6D     6E     6F
888
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
889
    // 70     71     72     73     74     75     76     77
890
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
891
    // 78     79     7A     7B     7C     7D     7E     7F
892
    0x00 | 0x00 | 0x00 | 0x08 | 0x00 | 0x20 | 0x00 | 0x80,
893
    // 80     81     82     83     84     85     86     87
894
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
895
    // 88     89     8A     8B     8C     8D     8E     8F
896
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
897
    // 90     91     92     93     94     95     96     97
898
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
899
    // 98     99     9A     9B     9C     9D     9E     9F
900
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
901
    // A0     A1     A2     A3     A4     A5     A6     A7
902
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
903
    // A8     A9     AA     AB     AC     AD     AE     AF
904
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
905
    // B0     B1     B2     B3     B4     B5     B6     B7
906
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
907
    // B8     B9     BA     BB     BC     BD     BE     BF
908
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
909
    // C0     C1     C2     C3     C4     C5     C6     C7
910
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
911
    // C8     C9     CA     CB     CC     CD     CE     CF
912
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
913
    // D0     D1     D2     D3     D4     D5     D6     D7
914
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
915
    // D8     D9     DA     DB     DC     DD     DE     DF
916
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
917
    // E0     E1     E2     E3     E4     E5     E6     E7
918
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
919
    // E8     E9     EA     EB     EC     ED     EE     EF
920
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
921
    // F0     F1     F2     F3     F4     F5     F6     F7
922
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
923
    // F8     F9     FA     FB     FC     FD     FE     FF
924
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80};
925
926
constexpr uint8_t WWW_FORM_URLENCODED_PERCENT_ENCODE[32] = {
927
    // 00     01     02     03     04     05     06     07
928
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
929
    // 08     09     0A     0B     0C     0D     0E     0F
930
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
931
    // 10     11     12     13     14     15     16     17
932
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
933
    // 18     19     1A     1B     1C     1D     1E     1F
934
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
935
    // 20     21     22     23     24     25     26     27
936
    0x00 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
937
    // 28     29     2A     2B     2C     2D     2E     2F
938
    0x01 | 0x02 | 0x00 | 0x08 | 0x10 | 0x00 | 0x00 | 0x80,
939
    // 30     31     32     33     34     35     36     37
940
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
941
    // 38     39     3A     3B     3C     3D     3E     3F
942
    0x00 | 0x00 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
943
    // 40     41     42     43     44     45     46     47
944
    0x01 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
945
    // 48     49     4A     4B     4C     4D     4E     4F
946
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
947
    // 50     51     52     53     54     55     56     57
948
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
949
    // 58     59     5A     5B     5C     5D     5E     5F
950
    0x00 | 0x00 | 0x00 | 0x08 | 0x00 | 0x20 | 0x40 | 0x00,
951
    // 60     61     62     63     64     65     66     67
952
    0x01 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
953
    // 68     69     6A     6B     6C     6D     6E     6F
954
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
955
    // 70     71     72     73     74     75     76     77
956
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
957
    // 78     79     7A     7B     7C     7D     7E     7F
958
    0x00 | 0x00 | 0x00 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
959
    // 80     81     82     83     84     85     86     87
960
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
961
    // 88     89     8A     8B     8C     8D     8E     8F
962
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
963
    // 90     91     92     93     94     95     96     97
964
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
965
    // 98     99     9A     9B     9C     9D     9E     9F
966
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
967
    // A0     A1     A2     A3     A4     A5     A6     A7
968
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
969
    // A8     A9     AA     AB     AC     AD     AE     AF
970
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
971
    // B0     B1     B2     B3     B4     B5     B6     B7
972
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
973
    // B8     B9     BA     BB     BC     BD     BE     BF
974
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
975
    // C0     C1     C2     C3     C4     C5     C6     C7
976
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
977
    // C8     C9     CA     CB     CC     CD     CE     CF
978
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
979
    // D0     D1     D2     D3     D4     D5     D6     D7
980
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
981
    // D8     D9     DA     DB     DC     DD     DE     DF
982
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
983
    // E0     E1     E2     E3     E4     E5     E6     E7
984
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
985
    // E8     E9     EA     EB     EC     ED     EE     EF
986
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
987
    // F0     F1     F2     F3     F4     F5     F6     F7
988
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
989
    // F8     F9     FA     FB     FC     FD     FE     FF
990
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80};
991
992
0
ada_really_inline constexpr bool bit_at(const uint8_t a[], const uint8_t i) {
993
0
  return !!(a[i >> 3] & (1 << (i & 7)));
994
0
}
995
996
}  // namespace ada::character_sets
997
998
#endif  // ADA_CHARACTER_SETS_INL_H
999
/* end file include/ada/character_sets-inl.h */
1000
/* begin file include/ada/checkers-inl.h */
1001
/**
1002
 * @file checkers-inl.h
1003
 * @brief Definitions for URL specific checkers used within Ada.
1004
 */
1005
#ifndef ADA_CHECKERS_INL_H
1006
#define ADA_CHECKERS_INL_H
1007
1008
#include <bit>
1009
#include <string_view>
1010
1011
namespace ada::checkers {
1012
1013
0
constexpr bool has_hex_prefix_unsafe(std::string_view input) {
1014
  // This is actually efficient code, see has_hex_prefix for the assembly.
1015
0
  constexpr bool is_little_endian = std::endian::native == std::endian::little;
1016
0
  constexpr uint16_t word0x = 0x7830;
1017
0
  uint16_t two_first_bytes =
1018
0
      static_cast<uint16_t>(input[0]) |
1019
0
      static_cast<uint16_t>((static_cast<uint16_t>(input[1]) << 8));
1020
0
  if constexpr (is_little_endian) {
1021
0
    two_first_bytes |= 0x2000;
1022
  } else {
1023
    two_first_bytes |= 0x020;
1024
  }
1025
0
  return two_first_bytes == word0x;
1026
0
}
1027
1028
0
constexpr bool has_hex_prefix(std::string_view input) {
1029
0
  return input.size() >= 2 && has_hex_prefix_unsafe(input);
1030
0
}
1031
1032
0
constexpr bool is_digit(char x) noexcept { return (x >= '0') & (x <= '9'); }
1033
1034
0
constexpr char to_lower(char x) noexcept { return (x | 0x20); }
1035
1036
0
constexpr bool is_alpha(char x) noexcept {
1037
0
  return (to_lower(x) >= 'a') && (to_lower(x) <= 'z');
1038
0
}
1039
1040
0
constexpr bool is_windows_drive_letter(std::string_view input) noexcept {
1041
0
  return input.size() >= 2 &&
1042
0
         (is_alpha(input[0]) && ((input[1] == ':') || (input[1] == '|'))) &&
1043
0
         ((input.size() == 2) || (input[2] == '/' || input[2] == '\\' ||
1044
0
                                  input[2] == '?' || input[2] == '#'));
1045
0
}
1046
1047
constexpr bool is_normalized_windows_drive_letter(
1048
0
    std::string_view input) noexcept {
1049
0
  return input.size() >= 2 && (is_alpha(input[0]) && (input[1] == ':'));
1050
0
}
1051
1052
}  // namespace ada::checkers
1053
1054
#endif  // ADA_CHECKERS_INL_H
1055
/* end file include/ada/checkers-inl.h */
1056
/* begin file include/ada/log.h */
1057
/**
1058
 * @file log.h
1059
 * @brief Includes the definitions for logging.
1060
 * @private Excluded from docs through the doxygen file.
1061
 */
1062
#ifndef ADA_LOG_H
1063
#define ADA_LOG_H
1064
1065
// To enable logging, set ADA_LOGGING to 1:
1066
#ifndef ADA_LOGGING
1067
#define ADA_LOGGING 0
1068
#endif
1069
1070
#if ADA_LOGGING
1071
#include <iostream>
1072
#endif  // ADA_LOGGING
1073
1074
namespace ada {
1075
1076
/**
1077
 * Log a message. If you want to have no overhead when logging is disabled, use
1078
 * the ada_log macro.
1079
 * @private
1080
 */
1081
template <typename... Args>
1082
constexpr ada_really_inline void log([[maybe_unused]] Args... args) {
1083
#if ADA_LOGGING
1084
  ((std::cout << "ADA_LOG: ") << ... << args) << std::endl;
1085
#endif  // ADA_LOGGING
1086
}
1087
}  // namespace ada
1088
1089
#if ADA_LOGGING
1090
#ifndef ada_log
1091
#define ada_log(...)       \
1092
  do {                     \
1093
    ada::log(__VA_ARGS__); \
1094
  } while (0)
1095
#endif  // ada_log
1096
#else
1097
#define ada_log(...)
1098
#endif  // ADA_LOGGING
1099
1100
#endif  // ADA_LOG_H
1101
/* end file include/ada/log.h */
1102
/* begin file include/ada/encoding_type.h */
1103
/**
1104
 * @file encoding_type.h
1105
 * @brief Definition for supported encoding types.
1106
 */
1107
#ifndef ADA_ENCODING_TYPE_H
1108
#define ADA_ENCODING_TYPE_H
1109
1110
#include <string>
1111
1112
namespace ada {
1113
1114
/**
1115
 * This specification defines three encodings with the same names as encoding
1116
 * schemes defined in the Unicode standard: UTF-8, UTF-16LE, and UTF-16BE.
1117
 *
1118
 * @see https://encoding.spec.whatwg.org/#encodings
1119
 */
1120
enum class encoding_type {
1121
  UTF8,
1122
  UTF_16LE,
1123
  UTF_16BE,
1124
};
1125
1126
/**
1127
 * Convert a encoding_type to string.
1128
 */
1129
ada_warn_unused std::string_view to_string(encoding_type type);
1130
1131
}  // namespace ada
1132
1133
#endif  // ADA_ENCODING_TYPE_H
1134
/* end file include/ada/encoding_type.h */
1135
/* begin file include/ada/helpers.h */
1136
/**
1137
 * @file helpers.h
1138
 * @brief Definitions for helper functions used within Ada.
1139
 */
1140
#ifndef ADA_HELPERS_H
1141
#define ADA_HELPERS_H
1142
1143
/* begin file include/ada/url_base.h */
1144
/**
1145
 * @file url_base.h
1146
 * @brief Declaration for the basic URL definitions
1147
 */
1148
#ifndef ADA_URL_BASE_H
1149
#define ADA_URL_BASE_H
1150
1151
/* begin file include/ada/scheme.h */
1152
/**
1153
 * @file scheme.h
1154
 * @brief Declarations for the URL scheme.
1155
 */
1156
#ifndef ADA_SCHEME_H
1157
#define ADA_SCHEME_H
1158
1159
1160
#include <string>
1161
1162
/**
1163
 * @namespace ada::scheme
1164
 * @brief Includes the scheme declarations
1165
 */
1166
namespace ada::scheme {
1167
1168
/**
1169
 * Type of the scheme as an enum.
1170
 * Using strings to represent a scheme type is not ideal because
1171
 * checking for types involves string comparisons. It is faster to use
1172
 * a simple integer.
1173
 * In C++11, we are allowed to specify the underlying type of the enum.
1174
 * We pick an 8-bit integer (which allows up to 256 types). Specifying the
1175
 * type of the enum may help integration with other systems if the type
1176
 * variable is exposed (since its value will not depend on the compiler).
1177
 */
1178
enum type : uint8_t {
1179
  HTTP = 0,
1180
  NOT_SPECIAL = 1,
1181
  HTTPS = 2,
1182
  WS = 3,
1183
  FTP = 4,
1184
  WSS = 5,
1185
  FILE = 6
1186
};
1187
1188
/**
1189
 * A special scheme is an ASCII string that is listed in the first column of the
1190
 * following table. The default port for a special scheme is listed in the
1191
 * second column on the same row. The default port for any other ASCII string is
1192
 * null.
1193
 *
1194
 * @see https://url.spec.whatwg.org/#url-miscellaneous
1195
 * @param scheme
1196
 * @return If scheme is a special scheme
1197
 */
1198
ada_really_inline constexpr bool is_special(std::string_view scheme);
1199
1200
/**
1201
 * A special scheme is an ASCII string that is listed in the first column of the
1202
 * following table. The default port for a special scheme is listed in the
1203
 * second column on the same row. The default port for any other ASCII string is
1204
 * null.
1205
 *
1206
 * @see https://url.spec.whatwg.org/#url-miscellaneous
1207
 * @param scheme
1208
 * @return The special port
1209
 */
1210
constexpr uint16_t get_special_port(std::string_view scheme) noexcept;
1211
1212
/**
1213
 * Returns the port number of a special scheme.
1214
 * @see https://url.spec.whatwg.org/#special-scheme
1215
 */
1216
constexpr uint16_t get_special_port(ada::scheme::type type) noexcept;
1217
/**
1218
 * Returns the scheme of an input, or NOT_SPECIAL if it's not a special scheme
1219
 * defined by the spec.
1220
 */
1221
constexpr ada::scheme::type get_scheme_type(std::string_view scheme) noexcept;
1222
1223
}  // namespace ada::scheme
1224
1225
#endif  // ADA_SCHEME_H
1226
/* end file include/ada/scheme.h */
1227
1228
#include <string>
1229
#include <string_view>
1230
1231
namespace ada {
1232
1233
/**
1234
 * Type of URL host as an enum.
1235
 */
1236
enum url_host_type : uint8_t {
1237
  /**
1238
   * Represents common URLs such as "https://www.google.com"
1239
   */
1240
  DEFAULT = 0,
1241
  /**
1242
   * Represents ipv4 addresses such as "http://127.0.0.1"
1243
   */
1244
  IPV4 = 1,
1245
  /**
1246
   * Represents ipv6 addresses such as
1247
   * "http://[2001:db8:3333:4444:5555:6666:7777:8888]"
1248
   */
1249
  IPV6 = 2,
1250
};
1251
1252
/**
1253
 * @brief Base class of URL implementations
1254
 *
1255
 * @details A url_base contains a few attributes: is_valid, has_opaque_path and
1256
 * type. All non-trivial implementation details are in derived classes such as
1257
 * ada::url and ada::url_aggregator.
1258
 *
1259
 * It is an abstract class that cannot be instantiated directly.
1260
 */
1261
struct url_base {
1262
0
  virtual ~url_base() = default;
1263
1264
  /**
1265
   * Used for returning the validity from the result of the URL parser.
1266
   */
1267
  bool is_valid{true};
1268
1269
  /**
1270
   * A URL has an opaque path if its path is a string.
1271
   */
1272
  bool has_opaque_path{false};
1273
1274
  /**
1275
   * URL hosts type
1276
   */
1277
  url_host_type host_type = url_host_type::DEFAULT;
1278
1279
  /**
1280
   * @private
1281
   */
1282
  ada::scheme::type type{ada::scheme::type::NOT_SPECIAL};
1283
1284
  /**
1285
   * A URL is special if its scheme is a special scheme. A URL is not special if
1286
   * its scheme is not a special scheme.
1287
   */
1288
  [[nodiscard]] ada_really_inline constexpr bool is_special() const noexcept;
1289
1290
  /**
1291
   * The origin getter steps are to return the serialization of this's URL's
1292
   * origin. [HTML]
1293
   * @return a newly allocated string.
1294
   * @see https://url.spec.whatwg.org/#concept-url-origin
1295
   */
1296
  [[nodiscard]] virtual std::string get_origin() const noexcept = 0;
1297
1298
  /**
1299
   * Returns true if this URL has a valid domain as per RFC 1034 and
1300
   * corresponding specifications. Among other things, it requires
1301
   * that the domain string has fewer than 255 octets.
1302
   */
1303
  [[nodiscard]] virtual bool has_valid_domain() const noexcept = 0;
1304
1305
  /**
1306
   * @private
1307
   *
1308
   * Return the 'special port' if the URL is special and not 'file'.
1309
   * Returns 0 otherwise.
1310
   */
1311
  [[nodiscard]] inline uint16_t get_special_port() const noexcept;
1312
1313
  /**
1314
   * @private
1315
   *
1316
   * Get the default port if the url's scheme has one, returns 0 otherwise.
1317
   */
1318
  [[nodiscard]] ada_really_inline uint16_t scheme_default_port() const noexcept;
1319
1320
  /**
1321
   * @private
1322
   *
1323
   * Parse a port (16-bit decimal digit) from the provided input.
1324
   * We assume that the input does not contain spaces or tabs
1325
   * within the ASCII digits.
1326
   * It returns how many bytes were consumed when a number is successfully
1327
   * parsed.
1328
   * @return On failure, it returns zero.
1329
   * @see https://url.spec.whatwg.org/#host-parsing
1330
   */
1331
  virtual size_t parse_port(std::string_view view,
1332
                            bool check_trailing_content) noexcept = 0;
1333
1334
0
  virtual ada_really_inline size_t parse_port(std::string_view view) noexcept {
1335
0
    return this->parse_port(view, false);
1336
0
  }
1337
1338
  /**
1339
   * Returns a JSON string representation of this URL.
1340
   */
1341
  [[nodiscard]] virtual std::string to_string() const = 0;
1342
1343
  /** @private */
1344
  virtual inline void clear_pathname() = 0;
1345
1346
  /** @private */
1347
  virtual inline void clear_search() = 0;
1348
1349
  /** @private */
1350
  [[nodiscard]] virtual inline bool has_hash() const noexcept = 0;
1351
1352
  /** @private */
1353
  [[nodiscard]] virtual inline bool has_search() const noexcept = 0;
1354
1355
};  // url_base
1356
1357
}  // namespace ada
1358
1359
#endif
1360
/* end file include/ada/url_base.h */
1361
1362
#include <string>
1363
#include <string_view>
1364
#include <optional>
1365
1366
#if ADA_DEVELOPMENT_CHECKS
1367
#include <iostream>
1368
#endif  // ADA_DEVELOPMENT_CHECKS
1369
1370
/**
1371
 * These functions are not part of our public API and may
1372
 * change at any time.
1373
 *
1374
 * @private
1375
 * @namespace ada::helpers
1376
 * @brief Includes the definitions for helper functions
1377
 */
1378
namespace ada::helpers {
1379
1380
/**
1381
 * @private
1382
 */
1383
template <typename out_iter>
1384
void encode_json(std::string_view view, out_iter out);
1385
1386
/**
1387
 * @private
1388
 * This function is used to prune a fragment from a url, and returning the
1389
 * removed string if input has fragment.
1390
 *
1391
 * @details prune_hash seeks the first '#' and returns everything after it
1392
 * as a string_view, and modifies (in place) the input so that it points at
1393
 * everything before the '#'. If no '#' is found, the input is left unchanged
1394
 * and std::nullopt is returned.
1395
 *
1396
 * @attention The function is non-allocating and it does not throw.
1397
 * @returns Note that the returned string_view might be empty!
1398
 */
1399
ada_really_inline std::optional<std::string_view> prune_hash(
1400
    std::string_view& input) noexcept;
1401
1402
/**
1403
 * @private
1404
 * Defined by the URL specification, shorten a URLs paths.
1405
 * @see https://url.spec.whatwg.org/#shorten-a-urls-path
1406
 * @returns Returns true if path is shortened.
1407
 */
1408
ada_really_inline bool shorten_path(std::string& path,
1409
                                    ada::scheme::type type) noexcept;
1410
1411
/**
1412
 * @private
1413
 * Defined by the URL specification, shorten a URLs paths.
1414
 * @see https://url.spec.whatwg.org/#shorten-a-urls-path
1415
 * @returns Returns true if path is shortened.
1416
 */
1417
ada_really_inline bool shorten_path(std::string_view& path,
1418
                                    ada::scheme::type type) noexcept;
1419
1420
/**
1421
 * @private
1422
 *
1423
 * Parse the path from the provided input and append to the existing
1424
 * (possibly empty) path. The input cannot contain tabs and spaces: it
1425
 * is the user's responsibility to check.
1426
 *
1427
 * The input is expected to be UTF-8.
1428
 *
1429
 * @see https://url.spec.whatwg.org/
1430
 */
1431
ada_really_inline void parse_prepared_path(std::string_view input,
1432
                                           ada::scheme::type type,
1433
                                           std::string& path);
1434
1435
/**
1436
 * @private
1437
 * Remove and mutate all ASCII tab or newline characters from an input.
1438
 */
1439
ada_really_inline void remove_ascii_tab_or_newline(std::string& input) noexcept;
1440
1441
/**
1442
 * @private
1443
 * Return the substring from input going from index pos to the end.
1444
 * This function cannot throw.
1445
 */
1446
ada_really_inline constexpr std::string_view substring(std::string_view input,
1447
                                                       size_t pos) noexcept;
1448
1449
/**
1450
 * @private
1451
 * Returns true if the string_view points within the string.
1452
 */
1453
bool overlaps(std::string_view input1, const std::string& input2) noexcept;
1454
1455
/**
1456
 * @private
1457
 * Return the substring from input going from index pos1 to the pos2 (non
1458
 * included). The length of the substring is pos2 - pos1.
1459
 */
1460
ada_really_inline constexpr std::string_view substring(std::string_view input,
1461
                                                       size_t pos1,
1462
0
                                                       size_t pos2) noexcept {
1463
#if ADA_DEVELOPMENT_CHECKS
1464
  if (pos2 < pos1) {
1465
    std::cerr << "Negative-length substring: [" << pos1 << " to " << pos2 << ")"
1466
              << std::endl;
1467
    abort();
1468
  }
1469
#endif
1470
0
  return input.substr(pos1, pos2 - pos1);
1471
0
}
1472
1473
/**
1474
 * @private
1475
 * Modify the string_view so that it has the new size pos, assuming that pos <=
1476
 * input.size(). This function cannot throw.
1477
 */
1478
ada_really_inline void resize(std::string_view& input, size_t pos) noexcept;
1479
1480
/**
1481
 * @private
1482
 * Returns a host's delimiter location depending on the state of the instance,
1483
 * and whether a colon was found outside brackets. Used by the host parser.
1484
 */
1485
ada_really_inline std::pair<size_t, bool> get_host_delimiter_location(
1486
    bool is_special, std::string_view& view) noexcept;
1487
1488
/**
1489
 * @private
1490
 * Removes leading and trailing C0 control and whitespace characters from
1491
 * string.
1492
 */
1493
void trim_c0_whitespace(std::string_view& input) noexcept;
1494
1495
/**
1496
 * @private
1497
 * @see
1498
 * https://url.spec.whatwg.org/#potentially-strip-trailing-spaces-from-an-opaque-path
1499
 */
1500
template <class url_type>
1501
ada_really_inline void strip_trailing_spaces_from_opaque_path(
1502
    url_type& url) noexcept;
1503
1504
/**
1505
 * @private
1506
 * Finds the delimiter of a view in authority state.
1507
 */
1508
ada_really_inline size_t
1509
find_authority_delimiter_special(std::string_view view) noexcept;
1510
1511
/**
1512
 * @private
1513
 * Finds the delimiter of a view in authority state.
1514
 */
1515
ada_really_inline size_t
1516
find_authority_delimiter(std::string_view view) noexcept;
1517
1518
/**
1519
 * @private
1520
 */
1521
template <typename T, typename... Args>
1522
0
inline void inner_concat(std::string& buffer, T t) {
1523
0
  buffer.append(t);
1524
0
}
Unexecuted instantiation: 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> >)
Unexecuted instantiation: void ada::helpers::inner_concat<char const*>(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&, char const*)
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> >)
1525
1526
/**
1527
 * @private
1528
 */
1529
template <typename T, typename... Args>
1530
0
inline void inner_concat(std::string& buffer, T t, Args... args) {
1531
0
  buffer.append(t);
1532
0
  return inner_concat(buffer, args...);
1533
0
}
Unexecuted instantiation: 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> >)
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> >)
Unexecuted instantiation: 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*)
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> >)
1534
1535
/**
1536
 * @private
1537
 * Concatenate the arguments and return a string.
1538
 * @returns a string
1539
 */
1540
template <typename... Args>
1541
0
std::string concat(Args... args) {
1542
0
  std::string answer;
1543
0
  inner_concat(answer, args...);
1544
0
  return answer;
1545
0
}
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<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> >)
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> >)
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> >, char const*)
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> >)
1546
1547
/**
1548
 * @private
1549
 * @return Number of leading zeroes.
1550
 */
1551
0
inline int leading_zeroes(uint32_t input_num) noexcept {
1552
#if ADA_REGULAR_VISUAL_STUDIO
1553
  unsigned long leading_zero(0);
1554
  unsigned long in(input_num);
1555
  return _BitScanReverse(&leading_zero, in) ? int(31 - leading_zero) : 32;
1556
#else
1557
0
  return __builtin_clz(input_num);
1558
0
#endif  // ADA_REGULAR_VISUAL_STUDIO
1559
0
}
1560
1561
/**
1562
 * @private
1563
 * Counts the number of decimal digits necessary to represent x.
1564
 * faster than std::to_string(x).size().
1565
 * @return digit count
1566
 */
1567
0
inline int fast_digit_count(uint32_t x) noexcept {
1568
0
  auto int_log2 = [](uint32_t z) -> int {
1569
0
    return 31 - ada::helpers::leading_zeroes(z | 1);
1570
0
  };
1571
0
  // Compiles to very few instructions. Note that the
1572
0
  // table is static and thus effectively a constant.
1573
0
  // We leave it inside the function because it is meaningless
1574
0
  // outside of it (this comes at no performance cost).
1575
0
  const static uint64_t table[] = {
1576
0
      4294967296,  8589934582,  8589934582,  8589934582,  12884901788,
1577
0
      12884901788, 12884901788, 17179868184, 17179868184, 17179868184,
1578
0
      21474826480, 21474826480, 21474826480, 21474826480, 25769703776,
1579
0
      25769703776, 25769703776, 30063771072, 30063771072, 30063771072,
1580
0
      34349738368, 34349738368, 34349738368, 34349738368, 38554705664,
1581
0
      38554705664, 38554705664, 41949672960, 41949672960, 41949672960,
1582
0
      42949672960, 42949672960};
1583
0
  return int((x + table[int_log2(x)]) >> 32);
1584
0
}
1585
}  // namespace ada::helpers
1586
1587
#endif  // ADA_HELPERS_H
1588
/* end file include/ada/helpers.h */
1589
/* begin file include/ada/parser.h */
1590
/**
1591
 * @file parser.h
1592
 * @brief Definitions for the parser.
1593
 */
1594
#ifndef ADA_PARSER_H
1595
#define ADA_PARSER_H
1596
1597
#include <string_view>
1598
#include <variant>
1599
1600
/* begin file include/ada/expected.h */
1601
/**
1602
 * @file expected.h
1603
 * @brief Definitions for std::expected
1604
 * @private Excluded from docs through the doxygen file.
1605
 */
1606
///
1607
// expected - An implementation of std::expected with extensions
1608
// Written in 2017 by Sy Brand (tartanllama@gmail.com, @TartanLlama)
1609
//
1610
// Documentation available at http://tl.tartanllama.xyz/
1611
//
1612
// To the extent possible under law, the author(s) have dedicated all
1613
// copyright and related and neighboring rights to this software to the
1614
// public domain worldwide. This software is distributed without any warranty.
1615
//
1616
// You should have received a copy of the CC0 Public Domain Dedication
1617
// along with this software. If not, see
1618
// <http://creativecommons.org/publicdomain/zero/1.0/>.
1619
///
1620
1621
#ifndef TL_EXPECTED_HPP
1622
#define TL_EXPECTED_HPP
1623
1624
#define TL_EXPECTED_VERSION_MAJOR 1
1625
#define TL_EXPECTED_VERSION_MINOR 1
1626
#define TL_EXPECTED_VERSION_PATCH 0
1627
1628
#include <exception>
1629
#include <functional>
1630
#include <type_traits>
1631
#include <utility>
1632
1633
#if defined(__EXCEPTIONS) || defined(_CPPUNWIND)
1634
#define TL_EXPECTED_EXCEPTIONS_ENABLED
1635
#endif
1636
1637
#if (defined(_MSC_VER) && _MSC_VER == 1900)
1638
#define TL_EXPECTED_MSVC2015
1639
#define TL_EXPECTED_MSVC2015_CONSTEXPR
1640
#else
1641
#define TL_EXPECTED_MSVC2015_CONSTEXPR constexpr
1642
#endif
1643
1644
#if (defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ <= 9 && \
1645
     !defined(__clang__))
1646
#define TL_EXPECTED_GCC49
1647
#endif
1648
1649
#if (defined(__GNUC__) && __GNUC__ == 5 && __GNUC_MINOR__ <= 4 && \
1650
     !defined(__clang__))
1651
#define TL_EXPECTED_GCC54
1652
#endif
1653
1654
#if (defined(__GNUC__) && __GNUC__ == 5 && __GNUC_MINOR__ <= 5 && \
1655
     !defined(__clang__))
1656
#define TL_EXPECTED_GCC55
1657
#endif
1658
1659
#if !defined(TL_ASSERT)
1660
// can't have assert in constexpr in C++11 and GCC 4.9 has a compiler bug
1661
#if (__cplusplus > 201103L) && !defined(TL_EXPECTED_GCC49)
1662
#include <cassert>
1663
0
#define TL_ASSERT(x) assert(x)
1664
#else
1665
#define TL_ASSERT(x)
1666
#endif
1667
#endif
1668
1669
#if (defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ <= 9 && \
1670
     !defined(__clang__))
1671
// GCC < 5 doesn't support overloading on const&& for member functions
1672
1673
#define TL_EXPECTED_NO_CONSTRR
1674
// GCC < 5 doesn't support some standard C++11 type traits
1675
#define TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) \
1676
  std::has_trivial_copy_constructor<T>
1677
#define TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(T) \
1678
  std::has_trivial_copy_assign<T>
1679
1680
// This one will be different for GCC 5.7 if it's ever supported
1681
#define TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(T) \
1682
  std::is_trivially_destructible<T>
1683
1684
// GCC 5 < v < 8 has a bug in is_trivially_copy_constructible which breaks
1685
// std::vector for non-copyable types
1686
#elif (defined(__GNUC__) && __GNUC__ < 8 && !defined(__clang__))
1687
#ifndef TL_GCC_LESS_8_TRIVIALLY_COPY_CONSTRUCTIBLE_MUTEX
1688
#define TL_GCC_LESS_8_TRIVIALLY_COPY_CONSTRUCTIBLE_MUTEX
1689
namespace tl {
1690
namespace detail {
1691
template <class T>
1692
struct is_trivially_copy_constructible
1693
    : std::is_trivially_copy_constructible<T> {};
1694
#ifdef _GLIBCXX_VECTOR
1695
template <class T, class A>
1696
struct is_trivially_copy_constructible<std::vector<T, A>> : std::false_type {};
1697
#endif
1698
}  // namespace detail
1699
}  // namespace tl
1700
#endif
1701
1702
#define TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) \
1703
  tl::detail::is_trivially_copy_constructible<T>
1704
#define TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(T) \
1705
  std::is_trivially_copy_assignable<T>
1706
#define TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(T) \
1707
  std::is_trivially_destructible<T>
1708
#else
1709
#define TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) \
1710
  std::is_trivially_copy_constructible<T>
1711
#define TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(T) \
1712
  std::is_trivially_copy_assignable<T>
1713
#define TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(T) \
1714
  std::is_trivially_destructible<T>
1715
#endif
1716
1717
#if __cplusplus > 201103L
1718
#define TL_EXPECTED_CXX14
1719
#endif
1720
1721
#ifdef TL_EXPECTED_GCC49
1722
#define TL_EXPECTED_GCC49_CONSTEXPR
1723
#else
1724
#define TL_EXPECTED_GCC49_CONSTEXPR constexpr
1725
#endif
1726
1727
#if (__cplusplus == 201103L || defined(TL_EXPECTED_MSVC2015) || \
1728
     defined(TL_EXPECTED_GCC49))
1729
#define TL_EXPECTED_11_CONSTEXPR
1730
#else
1731
#define TL_EXPECTED_11_CONSTEXPR constexpr
1732
#endif
1733
1734
namespace tl {
1735
template <class T, class E>
1736
class expected;
1737
1738
#ifndef TL_MONOSTATE_INPLACE_MUTEX
1739
#define TL_MONOSTATE_INPLACE_MUTEX
1740
class monostate {};
1741
1742
struct in_place_t {
1743
  explicit in_place_t() = default;
1744
};
1745
static constexpr in_place_t in_place{};
1746
#endif
1747
1748
template <class E>
1749
class unexpected {
1750
 public:
1751
  static_assert(!std::is_same<E, void>::value, "E must not be void");
1752
1753
  unexpected() = delete;
1754
  constexpr explicit unexpected(const E &e) : m_val(e) {}
1755
1756
0
  constexpr explicit unexpected(E &&e) : m_val(std::move(e)) {}
1757
1758
  template <class... Args, typename std::enable_if<std::is_constructible<
1759
                               E, Args &&...>::value>::type * = nullptr>
1760
  constexpr explicit unexpected(Args &&...args)
1761
0
      : m_val(std::forward<Args>(args)...) {}
1762
  template <
1763
      class U, class... Args,
1764
      typename std::enable_if<std::is_constructible<
1765
          E, std::initializer_list<U> &, Args &&...>::value>::type * = nullptr>
1766
  constexpr explicit unexpected(std::initializer_list<U> l, Args &&...args)
1767
      : m_val(l, std::forward<Args>(args)...) {}
1768
1769
  constexpr const E &value() const & { return m_val; }
1770
0
  TL_EXPECTED_11_CONSTEXPR E &value() & { return m_val; }
1771
  TL_EXPECTED_11_CONSTEXPR E &&value() && { return std::move(m_val); }
1772
  constexpr const E &&value() const && { return std::move(m_val); }
1773
1774
 private:
1775
  E m_val;
1776
};
1777
1778
#ifdef __cpp_deduction_guides
1779
template <class E>
1780
unexpected(E) -> unexpected<E>;
1781
#endif
1782
1783
template <class E>
1784
constexpr bool operator==(const unexpected<E> &lhs, const unexpected<E> &rhs) {
1785
  return lhs.value() == rhs.value();
1786
}
1787
template <class E>
1788
constexpr bool operator!=(const unexpected<E> &lhs, const unexpected<E> &rhs) {
1789
  return lhs.value() != rhs.value();
1790
}
1791
template <class E>
1792
constexpr bool operator<(const unexpected<E> &lhs, const unexpected<E> &rhs) {
1793
  return lhs.value() < rhs.value();
1794
}
1795
template <class E>
1796
constexpr bool operator<=(const unexpected<E> &lhs, const unexpected<E> &rhs) {
1797
  return lhs.value() <= rhs.value();
1798
}
1799
template <class E>
1800
constexpr bool operator>(const unexpected<E> &lhs, const unexpected<E> &rhs) {
1801
  return lhs.value() > rhs.value();
1802
}
1803
template <class E>
1804
constexpr bool operator>=(const unexpected<E> &lhs, const unexpected<E> &rhs) {
1805
  return lhs.value() >= rhs.value();
1806
}
1807
1808
template <class E>
1809
unexpected<typename std::decay<E>::type> make_unexpected(E &&e) {
1810
  return unexpected<typename std::decay<E>::type>(std::forward<E>(e));
1811
}
1812
1813
struct unexpect_t {
1814
  unexpect_t() = default;
1815
};
1816
static constexpr unexpect_t unexpect{};
1817
1818
namespace detail {
1819
template <typename E>
1820
0
[[noreturn]] TL_EXPECTED_11_CONSTEXPR void throw_exception(E &&e) {
1821
0
#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
1822
0
  throw std::forward<E>(e);
1823
#else
1824
  (void)e;
1825
#ifdef _MSC_VER
1826
  __assume(0);
1827
#else
1828
  __builtin_unreachable();
1829
#endif
1830
#endif
1831
0
}
1832
1833
#ifndef TL_TRAITS_MUTEX
1834
#define TL_TRAITS_MUTEX
1835
// C++14-style aliases for brevity
1836
template <class T>
1837
using remove_const_t = typename std::remove_const<T>::type;
1838
template <class T>
1839
using remove_reference_t = typename std::remove_reference<T>::type;
1840
template <class T>
1841
using decay_t = typename std::decay<T>::type;
1842
template <bool E, class T = void>
1843
using enable_if_t = typename std::enable_if<E, T>::type;
1844
template <bool B, class T, class F>
1845
using conditional_t = typename std::conditional<B, T, F>::type;
1846
1847
// std::conjunction from C++17
1848
template <class...>
1849
struct conjunction : std::true_type {};
1850
template <class B>
1851
struct conjunction<B> : B {};
1852
template <class B, class... Bs>
1853
struct conjunction<B, Bs...>
1854
    : std::conditional<bool(B::value), conjunction<Bs...>, B>::type {};
1855
1856
#if defined(_LIBCPP_VERSION) && __cplusplus == 201103L
1857
#define TL_TRAITS_LIBCXX_MEM_FN_WORKAROUND
1858
#endif
1859
1860
// In C++11 mode, there's an issue in libc++'s std::mem_fn
1861
// which results in a hard-error when using it in a noexcept expression
1862
// in some cases. This is a check to workaround the common failing case.
1863
#ifdef TL_TRAITS_LIBCXX_MEM_FN_WORKAROUND
1864
template <class T>
1865
struct is_pointer_to_non_const_member_func : std::false_type {};
1866
template <class T, class Ret, class... Args>
1867
struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...)>
1868
    : std::true_type {};
1869
template <class T, class Ret, class... Args>
1870
struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...) &>
1871
    : std::true_type {};
1872
template <class T, class Ret, class... Args>
1873
struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...) &&>
1874
    : std::true_type {};
1875
template <class T, class Ret, class... Args>
1876
struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...) volatile>
1877
    : std::true_type {};
1878
template <class T, class Ret, class... Args>
1879
struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...) volatile &>
1880
    : std::true_type {};
1881
template <class T, class Ret, class... Args>
1882
struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...) volatile &&>
1883
    : std::true_type {};
1884
1885
template <class T>
1886
struct is_const_or_const_ref : std::false_type {};
1887
template <class T>
1888
struct is_const_or_const_ref<T const &> : std::true_type {};
1889
template <class T>
1890
struct is_const_or_const_ref<T const> : std::true_type {};
1891
#endif
1892
1893
// std::invoke from C++17
1894
// https://stackoverflow.com/questions/38288042/c11-14-invoke-workaround
1895
template <
1896
    typename Fn, typename... Args,
1897
#ifdef TL_TRAITS_LIBCXX_MEM_FN_WORKAROUND
1898
    typename = enable_if_t<!(is_pointer_to_non_const_member_func<Fn>::value &&
1899
                             is_const_or_const_ref<Args...>::value)>,
1900
#endif
1901
    typename = enable_if_t<std::is_member_pointer<decay_t<Fn>>::value>, int = 0>
1902
constexpr auto invoke(Fn &&f, Args &&...args) noexcept(
1903
    noexcept(std::mem_fn(f)(std::forward<Args>(args)...)))
1904
    -> decltype(std::mem_fn(f)(std::forward<Args>(args)...)) {
1905
  return std::mem_fn(f)(std::forward<Args>(args)...);
1906
}
1907
1908
template <typename Fn, typename... Args,
1909
          typename = enable_if_t<!std::is_member_pointer<decay_t<Fn>>::value>>
1910
constexpr auto invoke(Fn &&f, Args &&...args) noexcept(
1911
    noexcept(std::forward<Fn>(f)(std::forward<Args>(args)...)))
1912
    -> decltype(std::forward<Fn>(f)(std::forward<Args>(args)...)) {
1913
  return std::forward<Fn>(f)(std::forward<Args>(args)...);
1914
}
1915
1916
// std::invoke_result from C++17
1917
template <class F, class, class... Us>
1918
struct invoke_result_impl;
1919
1920
template <class F, class... Us>
1921
struct invoke_result_impl<
1922
    F,
1923
    decltype(detail::invoke(std::declval<F>(), std::declval<Us>()...), void()),
1924
    Us...> {
1925
  using type =
1926
      decltype(detail::invoke(std::declval<F>(), std::declval<Us>()...));
1927
};
1928
1929
template <class F, class... Us>
1930
using invoke_result = invoke_result_impl<F, void, Us...>;
1931
1932
template <class F, class... Us>
1933
using invoke_result_t = typename invoke_result<F, Us...>::type;
1934
1935
#if defined(_MSC_VER) && _MSC_VER <= 1900
1936
// TODO make a version which works with MSVC 2015
1937
template <class T, class U = T>
1938
struct is_swappable : std::true_type {};
1939
1940
template <class T, class U = T>
1941
struct is_nothrow_swappable : std::true_type {};
1942
#else
1943
// https://stackoverflow.com/questions/26744589/what-is-a-proper-way-to-implement-is-swappable-to-test-for-the-swappable-concept
1944
namespace swap_adl_tests {
1945
// if swap ADL finds this then it would call std::swap otherwise (same
1946
// signature)
1947
struct tag {};
1948
1949
template <class T>
1950
tag swap(T &, T &);
1951
template <class T, std::size_t N>
1952
tag swap(T (&a)[N], T (&b)[N]);
1953
1954
// helper functions to test if an unqualified swap is possible, and if it
1955
// becomes std::swap
1956
template <class, class>
1957
std::false_type can_swap(...) noexcept(false);
1958
template <class T, class U,
1959
          class = decltype(swap(std::declval<T &>(), std::declval<U &>()))>
1960
std::true_type can_swap(int) noexcept(noexcept(swap(std::declval<T &>(),
1961
                                                    std::declval<U &>())));
1962
1963
template <class, class>
1964
std::false_type uses_std(...);
1965
template <class T, class U>
1966
std::is_same<decltype(swap(std::declval<T &>(), std::declval<U &>())), tag>
1967
uses_std(int);
1968
1969
template <class T>
1970
struct is_std_swap_noexcept
1971
    : std::integral_constant<bool,
1972
                             std::is_nothrow_move_constructible<T>::value &&
1973
                                 std::is_nothrow_move_assignable<T>::value> {};
1974
1975
template <class T, std::size_t N>
1976
struct is_std_swap_noexcept<T[N]> : is_std_swap_noexcept<T> {};
1977
1978
template <class T, class U>
1979
struct is_adl_swap_noexcept
1980
    : std::integral_constant<bool, noexcept(can_swap<T, U>(0))> {};
1981
}  // namespace swap_adl_tests
1982
1983
template <class T, class U = T>
1984
struct is_swappable
1985
    : std::integral_constant<
1986
          bool,
1987
          decltype(detail::swap_adl_tests::can_swap<T, U>(0))::value &&
1988
              (!decltype(detail::swap_adl_tests::uses_std<T, U>(0))::value ||
1989
               (std::is_move_assignable<T>::value &&
1990
                std::is_move_constructible<T>::value))> {};
1991
1992
template <class T, std::size_t N>
1993
struct is_swappable<T[N], T[N]>
1994
    : std::integral_constant<
1995
          bool,
1996
          decltype(detail::swap_adl_tests::can_swap<T[N], T[N]>(0))::value &&
1997
              (!decltype(detail::swap_adl_tests::uses_std<T[N], T[N]>(
1998
                   0))::value ||
1999
               is_swappable<T, T>::value)> {};
2000
2001
template <class T, class U = T>
2002
struct is_nothrow_swappable
2003
    : std::integral_constant<
2004
          bool,
2005
          is_swappable<T, U>::value &&
2006
              ((decltype(detail::swap_adl_tests::uses_std<T, U>(0))::value &&
2007
                detail::swap_adl_tests::is_std_swap_noexcept<T>::value) ||
2008
               (!decltype(detail::swap_adl_tests::uses_std<T, U>(0))::value &&
2009
                detail::swap_adl_tests::is_adl_swap_noexcept<T, U>::value))> {};
2010
#endif
2011
#endif
2012
2013
// Trait for checking if a type is a tl::expected
2014
template <class T>
2015
struct is_expected_impl : std::false_type {};
2016
template <class T, class E>
2017
struct is_expected_impl<expected<T, E>> : std::true_type {};
2018
template <class T>
2019
using is_expected = is_expected_impl<decay_t<T>>;
2020
2021
template <class T, class E, class U>
2022
using expected_enable_forward_value = detail::enable_if_t<
2023
    std::is_constructible<T, U &&>::value &&
2024
    !std::is_same<detail::decay_t<U>, in_place_t>::value &&
2025
    !std::is_same<expected<T, E>, detail::decay_t<U>>::value &&
2026
    !std::is_same<unexpected<E>, detail::decay_t<U>>::value>;
2027
2028
template <class T, class E, class U, class G, class UR, class GR>
2029
using expected_enable_from_other = detail::enable_if_t<
2030
    std::is_constructible<T, UR>::value &&
2031
    std::is_constructible<E, GR>::value &&
2032
    !std::is_constructible<T, expected<U, G> &>::value &&
2033
    !std::is_constructible<T, expected<U, G> &&>::value &&
2034
    !std::is_constructible<T, const expected<U, G> &>::value &&
2035
    !std::is_constructible<T, const expected<U, G> &&>::value &&
2036
    !std::is_convertible<expected<U, G> &, T>::value &&
2037
    !std::is_convertible<expected<U, G> &&, T>::value &&
2038
    !std::is_convertible<const expected<U, G> &, T>::value &&
2039
    !std::is_convertible<const expected<U, G> &&, T>::value>;
2040
2041
template <class T, class U>
2042
using is_void_or = conditional_t<std::is_void<T>::value, std::true_type, U>;
2043
2044
template <class T>
2045
using is_copy_constructible_or_void =
2046
    is_void_or<T, std::is_copy_constructible<T>>;
2047
2048
template <class T>
2049
using is_move_constructible_or_void =
2050
    is_void_or<T, std::is_move_constructible<T>>;
2051
2052
template <class T>
2053
using is_copy_assignable_or_void = is_void_or<T, std::is_copy_assignable<T>>;
2054
2055
template <class T>
2056
using is_move_assignable_or_void = is_void_or<T, std::is_move_assignable<T>>;
2057
2058
}  // namespace detail
2059
2060
namespace detail {
2061
struct no_init_t {};
2062
static constexpr no_init_t no_init{};
2063
2064
// Implements the storage of the values, and ensures that the destructor is
2065
// trivial if it can be.
2066
//
2067
// This specialization is for where neither `T` or `E` is trivially
2068
// destructible, so the destructors must be called on destruction of the
2069
// `expected`
2070
template <class T, class E, bool = std::is_trivially_destructible<T>::value,
2071
          bool = std::is_trivially_destructible<E>::value>
2072
struct expected_storage_base {
2073
  constexpr expected_storage_base() : m_val(T{}), m_has_val(true) {}
2074
  constexpr expected_storage_base(no_init_t) : m_no_init(), m_has_val(false) {}
2075
2076
  template <class... Args,
2077
            detail::enable_if_t<std::is_constructible<T, Args &&...>::value> * =
2078
                nullptr>
2079
  constexpr expected_storage_base(in_place_t, Args &&...args)
2080
      : m_val(std::forward<Args>(args)...), m_has_val(true) {}
2081
2082
  template <class U, class... Args,
2083
            detail::enable_if_t<std::is_constructible<
2084
                T, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
2085
  constexpr expected_storage_base(in_place_t, std::initializer_list<U> il,
2086
                                  Args &&...args)
2087
      : m_val(il, std::forward<Args>(args)...), m_has_val(true) {}
2088
  template <class... Args,
2089
            detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * =
2090
                nullptr>
2091
  constexpr explicit expected_storage_base(unexpect_t, Args &&...args)
2092
      : m_unexpect(std::forward<Args>(args)...), m_has_val(false) {}
2093
2094
  template <class U, class... Args,
2095
            detail::enable_if_t<std::is_constructible<
2096
                E, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
2097
  constexpr explicit expected_storage_base(unexpect_t,
2098
                                           std::initializer_list<U> il,
2099
                                           Args &&...args)
2100
      : m_unexpect(il, std::forward<Args>(args)...), m_has_val(false) {}
2101
2102
  ~expected_storage_base() {
2103
    if (m_has_val) {
2104
      m_val.~T();
2105
    } else {
2106
      m_unexpect.~unexpected<E>();
2107
    }
2108
  }
2109
  union {
2110
    T m_val;
2111
    unexpected<E> m_unexpect;
2112
    char m_no_init;
2113
  };
2114
  bool m_has_val;
2115
};
2116
2117
// This specialization is for when both `T` and `E` are trivially-destructible,
2118
// so the destructor of the `expected` can be trivial.
2119
template <class T, class E>
2120
struct expected_storage_base<T, E, true, true> {
2121
  constexpr expected_storage_base() : m_val(T{}), m_has_val(true) {}
2122
  constexpr expected_storage_base(no_init_t) : m_no_init(), m_has_val(false) {}
2123
2124
  template <class... Args,
2125
            detail::enable_if_t<std::is_constructible<T, Args &&...>::value> * =
2126
                nullptr>
2127
  constexpr expected_storage_base(in_place_t, Args &&...args)
2128
0
      : m_val(std::forward<Args>(args)...), m_has_val(true) {}
Unexecuted instantiation: _ZN2tl6detail21expected_storage_baseIN3ada22url_search_params_iterINSt3__117basic_string_viewIcNS4_11char_traitsIcEEEELNS2_27url_search_params_iter_typeE0EEENS2_6errorsELb1ELb1EEC2IJSA_ETnPNS4_9enable_ifIXsr3std16is_constructibleISA_DpOT_EE5valueEvE4typeELPv0EEENS_10in_place_tESH_
Unexecuted instantiation: _ZN2tl6detail21expected_storage_baseIN3ada22url_search_params_iterINSt3__117basic_string_viewIcNS4_11char_traitsIcEEEELNS2_27url_search_params_iter_typeE1EEENS2_6errorsELb1ELb1EEC2IJSA_ETnPNS4_9enable_ifIXsr3std16is_constructibleISA_DpOT_EE5valueEvE4typeELPv0EEENS_10in_place_tESH_
Unexecuted instantiation: _ZN2tl6detail21expected_storage_baseIN3ada22url_search_params_iterINSt3__14pairINS4_17basic_string_viewIcNS4_11char_traitsIcEEEES9_EELNS2_27url_search_params_iter_typeE2EEENS2_6errorsELb1ELb1EEC2IJSC_ETnPNS4_9enable_ifIXsr3std16is_constructibleISC_DpOT_EE5valueEvE4typeELPv0EEENS_10in_place_tESJ_
2129
2130
  template <class U, class... Args,
2131
            detail::enable_if_t<std::is_constructible<
2132
                T, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
2133
  constexpr expected_storage_base(in_place_t, std::initializer_list<U> il,
2134
                                  Args &&...args)
2135
      : m_val(il, std::forward<Args>(args)...), m_has_val(true) {}
2136
  template <class... Args,
2137
            detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * =
2138
                nullptr>
2139
  constexpr explicit expected_storage_base(unexpect_t, Args &&...args)
2140
      : m_unexpect(std::forward<Args>(args)...), m_has_val(false) {}
2141
2142
  template <class U, class... Args,
2143
            detail::enable_if_t<std::is_constructible<
2144
                E, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
2145
  constexpr explicit expected_storage_base(unexpect_t,
2146
                                           std::initializer_list<U> il,
2147
                                           Args &&...args)
2148
      : m_unexpect(il, std::forward<Args>(args)...), m_has_val(false) {}
2149
2150
  ~expected_storage_base() = default;
2151
  union {
2152
    T m_val;
2153
    unexpected<E> m_unexpect;
2154
    char m_no_init;
2155
  };
2156
  bool m_has_val;
2157
};
2158
2159
// T is trivial, E is not.
2160
template <class T, class E>
2161
struct expected_storage_base<T, E, true, false> {
2162
  constexpr expected_storage_base() : m_val(T{}), m_has_val(true) {}
2163
  TL_EXPECTED_MSVC2015_CONSTEXPR expected_storage_base(no_init_t)
2164
      : m_no_init(), m_has_val(false) {}
2165
2166
  template <class... Args,
2167
            detail::enable_if_t<std::is_constructible<T, Args &&...>::value> * =
2168
                nullptr>
2169
  constexpr expected_storage_base(in_place_t, Args &&...args)
2170
      : m_val(std::forward<Args>(args)...), m_has_val(true) {}
2171
2172
  template <class U, class... Args,
2173
            detail::enable_if_t<std::is_constructible<
2174
                T, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
2175
  constexpr expected_storage_base(in_place_t, std::initializer_list<U> il,
2176
                                  Args &&...args)
2177
      : m_val(il, std::forward<Args>(args)...), m_has_val(true) {}
2178
  template <class... Args,
2179
            detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * =
2180
                nullptr>
2181
  constexpr explicit expected_storage_base(unexpect_t, Args &&...args)
2182
      : m_unexpect(std::forward<Args>(args)...), m_has_val(false) {}
2183
2184
  template <class U, class... Args,
2185
            detail::enable_if_t<std::is_constructible<
2186
                E, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
2187
  constexpr explicit expected_storage_base(unexpect_t,
2188
                                           std::initializer_list<U> il,
2189
                                           Args &&...args)
2190
      : m_unexpect(il, std::forward<Args>(args)...), m_has_val(false) {}
2191
2192
  ~expected_storage_base() {
2193
    if (!m_has_val) {
2194
      m_unexpect.~unexpected<E>();
2195
    }
2196
  }
2197
2198
  union {
2199
    T m_val;
2200
    unexpected<E> m_unexpect;
2201
    char m_no_init;
2202
  };
2203
  bool m_has_val;
2204
};
2205
2206
// E is trivial, T is not.
2207
template <class T, class E>
2208
struct expected_storage_base<T, E, false, true> {
2209
  constexpr expected_storage_base() : m_val(T{}), m_has_val(true) {}
2210
0
  constexpr expected_storage_base(no_init_t) : m_no_init(), m_has_val(false) {}
2211
2212
  template <class... Args,
2213
            detail::enable_if_t<std::is_constructible<T, Args &&...>::value> * =
2214
                nullptr>
2215
  constexpr expected_storage_base(in_place_t, Args &&...args)
2216
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_
2217
2218
  template <class U, class... Args,
2219
            detail::enable_if_t<std::is_constructible<
2220
                T, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
2221
  constexpr expected_storage_base(in_place_t, std::initializer_list<U> il,
2222
                                  Args &&...args)
2223
      : m_val(il, std::forward<Args>(args)...), m_has_val(true) {}
2224
  template <class... Args,
2225
            detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * =
2226
                nullptr>
2227
  constexpr explicit expected_storage_base(unexpect_t, Args &&...args)
2228
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_
2229
2230
  template <class U, class... Args,
2231
            detail::enable_if_t<std::is_constructible<
2232
                E, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
2233
  constexpr explicit expected_storage_base(unexpect_t,
2234
                                           std::initializer_list<U> il,
2235
                                           Args &&...args)
2236
      : m_unexpect(il, std::forward<Args>(args)...), m_has_val(false) {}
2237
2238
0
  ~expected_storage_base() {
2239
0
    if (m_has_val) {
2240
0
      m_val.~T();
2241
0
    }
2242
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()
2243
  union {
2244
    T m_val;
2245
    unexpected<E> m_unexpect;
2246
    char m_no_init;
2247
  };
2248
  bool m_has_val;
2249
};
2250
2251
// `T` is `void`, `E` is trivially-destructible
2252
template <class E>
2253
struct expected_storage_base<void, E, false, true> {
2254
#if __GNUC__ <= 5
2255
// no constexpr for GCC 4/5 bug
2256
#else
2257
  TL_EXPECTED_MSVC2015_CONSTEXPR
2258
#endif
2259
  expected_storage_base() : m_has_val(true) {}
2260
2261
  constexpr expected_storage_base(no_init_t) : m_val(), m_has_val(false) {}
2262
2263
  constexpr expected_storage_base(in_place_t) : m_has_val(true) {}
2264
2265
  template <class... Args,
2266
            detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * =
2267
                nullptr>
2268
  constexpr explicit expected_storage_base(unexpect_t, Args &&...args)
2269
      : m_unexpect(std::forward<Args>(args)...), m_has_val(false) {}
2270
2271
  template <class U, class... Args,
2272
            detail::enable_if_t<std::is_constructible<
2273
                E, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
2274
  constexpr explicit expected_storage_base(unexpect_t,
2275
                                           std::initializer_list<U> il,
2276
                                           Args &&...args)
2277
      : m_unexpect(il, std::forward<Args>(args)...), m_has_val(false) {}
2278
2279
  ~expected_storage_base() = default;
2280
  struct dummy {};
2281
  union {
2282
    unexpected<E> m_unexpect;
2283
    dummy m_val;
2284
  };
2285
  bool m_has_val;
2286
};
2287
2288
// `T` is `void`, `E` is not trivially-destructible
2289
template <class E>
2290
struct expected_storage_base<void, E, false, false> {
2291
  constexpr expected_storage_base() : m_dummy(), m_has_val(true) {}
2292
  constexpr expected_storage_base(no_init_t) : m_dummy(), m_has_val(false) {}
2293
2294
  constexpr expected_storage_base(in_place_t) : m_dummy(), m_has_val(true) {}
2295
2296
  template <class... Args,
2297
            detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * =
2298
                nullptr>
2299
  constexpr explicit expected_storage_base(unexpect_t, Args &&...args)
2300
      : m_unexpect(std::forward<Args>(args)...), m_has_val(false) {}
2301
2302
  template <class U, class... Args,
2303
            detail::enable_if_t<std::is_constructible<
2304
                E, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
2305
  constexpr explicit expected_storage_base(unexpect_t,
2306
                                           std::initializer_list<U> il,
2307
                                           Args &&...args)
2308
      : m_unexpect(il, std::forward<Args>(args)...), m_has_val(false) {}
2309
2310
  ~expected_storage_base() {
2311
    if (!m_has_val) {
2312
      m_unexpect.~unexpected<E>();
2313
    }
2314
  }
2315
2316
  union {
2317
    unexpected<E> m_unexpect;
2318
    char m_dummy;
2319
  };
2320
  bool m_has_val;
2321
};
2322
2323
// This base class provides some handy member functions which can be used in
2324
// further derived classes
2325
template <class T, class E>
2326
struct expected_operations_base : expected_storage_base<T, E> {
2327
  using expected_storage_base<T, E>::expected_storage_base;
2328
2329
  template <class... Args>
2330
  void construct(Args &&...args) noexcept {
2331
    new (std::addressof(this->m_val)) T(std::forward<Args>(args)...);
2332
    this->m_has_val = true;
2333
  }
2334
2335
  template <class Rhs>
2336
0
  void construct_with(Rhs &&rhs) noexcept {
2337
0
    new (std::addressof(this->m_val)) T(std::forward<Rhs>(rhs).get());
2338
0
    this->m_has_val = true;
2339
0
  }
2340
2341
  template <class... Args>
2342
0
  void construct_error(Args &&...args) noexcept {
2343
0
    new (std::addressof(this->m_unexpect))
2344
0
        unexpected<E>(std::forward<Args>(args)...);
2345
0
    this->m_has_val = false;
2346
0
  }
2347
2348
#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
2349
2350
  // These assign overloads ensure that the most efficient assignment
2351
  // implementation is used while maintaining the strong exception guarantee.
2352
  // The problematic case is where rhs has a value, but *this does not.
2353
  //
2354
  // This overload handles the case where we can just copy-construct `T`
2355
  // directly into place without throwing.
2356
  template <class U = T,
2357
            detail::enable_if_t<std::is_nothrow_copy_constructible<U>::value>
2358
                * = nullptr>
2359
  void assign(const expected_operations_base &rhs) noexcept {
2360
    if (!this->m_has_val && rhs.m_has_val) {
2361
      geterr().~unexpected<E>();
2362
      construct(rhs.get());
2363
    } else {
2364
      assign_common(rhs);
2365
    }
2366
  }
2367
2368
  // This overload handles the case where we can attempt to create a copy of
2369
  // `T`, then no-throw move it into place if the copy was successful.
2370
  template <class U = T,
2371
            detail::enable_if_t<!std::is_nothrow_copy_constructible<U>::value &&
2372
                                std::is_nothrow_move_constructible<U>::value>
2373
                * = nullptr>
2374
  void assign(const expected_operations_base &rhs) noexcept {
2375
    if (!this->m_has_val && rhs.m_has_val) {
2376
      T tmp = rhs.get();
2377
      geterr().~unexpected<E>();
2378
      construct(std::move(tmp));
2379
    } else {
2380
      assign_common(rhs);
2381
    }
2382
  }
2383
2384
  // This overload is the worst-case, where we have to move-construct the
2385
  // unexpected value into temporary storage, then try to copy the T into place.
2386
  // If the construction succeeds, then everything is fine, but if it throws,
2387
  // then we move the old unexpected value back into place before rethrowing the
2388
  // exception.
2389
  template <class U = T,
2390
            detail::enable_if_t<!std::is_nothrow_copy_constructible<U>::value &&
2391
                                !std::is_nothrow_move_constructible<U>::value>
2392
                * = nullptr>
2393
  void assign(const expected_operations_base &rhs) {
2394
    if (!this->m_has_val && rhs.m_has_val) {
2395
      auto tmp = std::move(geterr());
2396
      geterr().~unexpected<E>();
2397
2398
#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
2399
      try {
2400
        construct(rhs.get());
2401
      } catch (...) {
2402
        geterr() = std::move(tmp);
2403
        throw;
2404
      }
2405
#else
2406
      construct(rhs.get());
2407
#endif
2408
    } else {
2409
      assign_common(rhs);
2410
    }
2411
  }
2412
2413
  // These overloads do the same as above, but for rvalues
2414
  template <class U = T,
2415
            detail::enable_if_t<std::is_nothrow_move_constructible<U>::value>
2416
                * = nullptr>
2417
  void assign(expected_operations_base &&rhs) noexcept {
2418
    if (!this->m_has_val && rhs.m_has_val) {
2419
      geterr().~unexpected<E>();
2420
      construct(std::move(rhs).get());
2421
    } else {
2422
      assign_common(std::move(rhs));
2423
    }
2424
  }
2425
2426
  template <class U = T,
2427
            detail::enable_if_t<!std::is_nothrow_move_constructible<U>::value>
2428
                * = nullptr>
2429
  void assign(expected_operations_base &&rhs) {
2430
    if (!this->m_has_val && rhs.m_has_val) {
2431
      auto tmp = std::move(geterr());
2432
      geterr().~unexpected<E>();
2433
#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
2434
      try {
2435
        construct(std::move(rhs).get());
2436
      } catch (...) {
2437
        geterr() = std::move(tmp);
2438
        throw;
2439
      }
2440
#else
2441
      construct(std::move(rhs).get());
2442
#endif
2443
    } else {
2444
      assign_common(std::move(rhs));
2445
    }
2446
  }
2447
2448
#else
2449
2450
  // If exceptions are disabled then we can just copy-construct
2451
  void assign(const expected_operations_base &rhs) noexcept {
2452
    if (!this->m_has_val && rhs.m_has_val) {
2453
      geterr().~unexpected<E>();
2454
      construct(rhs.get());
2455
    } else {
2456
      assign_common(rhs);
2457
    }
2458
  }
2459
2460
  void assign(expected_operations_base &&rhs) noexcept {
2461
    if (!this->m_has_val && rhs.m_has_val) {
2462
      geterr().~unexpected<E>();
2463
      construct(std::move(rhs).get());
2464
    } else {
2465
      assign_common(std::move(rhs));
2466
    }
2467
  }
2468
2469
#endif
2470
2471
  // The common part of move/copy assigning
2472
  template <class Rhs>
2473
  void assign_common(Rhs &&rhs) {
2474
    if (this->m_has_val) {
2475
      if (rhs.m_has_val) {
2476
        get() = std::forward<Rhs>(rhs).get();
2477
      } else {
2478
        destroy_val();
2479
        construct_error(std::forward<Rhs>(rhs).geterr());
2480
      }
2481
    } else {
2482
      if (!rhs.m_has_val) {
2483
        geterr() = std::forward<Rhs>(rhs).geterr();
2484
      }
2485
    }
2486
  }
2487
2488
0
  bool has_value() const { return this->m_has_val; }
2489
2490
  TL_EXPECTED_11_CONSTEXPR T &get() & { return this->m_val; }
2491
0
  constexpr const T &get() const & { return this->m_val; }
2492
  TL_EXPECTED_11_CONSTEXPR T &&get() && { return std::move(this->m_val); }
2493
#ifndef TL_EXPECTED_NO_CONSTRR
2494
  constexpr const T &&get() const && { return std::move(this->m_val); }
2495
#endif
2496
2497
  TL_EXPECTED_11_CONSTEXPR unexpected<E> &geterr() & {
2498
    return this->m_unexpect;
2499
  }
2500
0
  constexpr const unexpected<E> &geterr() const & { return this->m_unexpect; }
2501
  TL_EXPECTED_11_CONSTEXPR unexpected<E> &&geterr() && {
2502
    return std::move(this->m_unexpect);
2503
  }
2504
#ifndef TL_EXPECTED_NO_CONSTRR
2505
  constexpr const unexpected<E> &&geterr() const && {
2506
    return std::move(this->m_unexpect);
2507
  }
2508
#endif
2509
2510
  TL_EXPECTED_11_CONSTEXPR void destroy_val() { get().~T(); }
2511
};
2512
2513
// This base class provides some handy member functions which can be used in
2514
// further derived classes
2515
template <class E>
2516
struct expected_operations_base<void, E> : expected_storage_base<void, E> {
2517
  using expected_storage_base<void, E>::expected_storage_base;
2518
2519
  template <class... Args>
2520
  void construct() noexcept {
2521
    this->m_has_val = true;
2522
  }
2523
2524
  // This function doesn't use its argument, but needs it so that code in
2525
  // levels above this can work independently of whether T is void
2526
  template <class Rhs>
2527
  void construct_with(Rhs &&) noexcept {
2528
    this->m_has_val = true;
2529
  }
2530
2531
  template <class... Args>
2532
  void construct_error(Args &&...args) noexcept {
2533
    new (std::addressof(this->m_unexpect))
2534
        unexpected<E>(std::forward<Args>(args)...);
2535
    this->m_has_val = false;
2536
  }
2537
2538
  template <class Rhs>
2539
  void assign(Rhs &&rhs) noexcept {
2540
    if (!this->m_has_val) {
2541
      if (rhs.m_has_val) {
2542
        geterr().~unexpected<E>();
2543
        construct();
2544
      } else {
2545
        geterr() = std::forward<Rhs>(rhs).geterr();
2546
      }
2547
    } else {
2548
      if (!rhs.m_has_val) {
2549
        construct_error(std::forward<Rhs>(rhs).geterr());
2550
      }
2551
    }
2552
  }
2553
2554
  bool has_value() const { return this->m_has_val; }
2555
2556
  TL_EXPECTED_11_CONSTEXPR unexpected<E> &geterr() & {
2557
    return this->m_unexpect;
2558
  }
2559
  constexpr const unexpected<E> &geterr() const & { return this->m_unexpect; }
2560
  TL_EXPECTED_11_CONSTEXPR unexpected<E> &&geterr() && {
2561
    return std::move(this->m_unexpect);
2562
  }
2563
#ifndef TL_EXPECTED_NO_CONSTRR
2564
  constexpr const unexpected<E> &&geterr() const && {
2565
    return std::move(this->m_unexpect);
2566
  }
2567
#endif
2568
2569
  TL_EXPECTED_11_CONSTEXPR void destroy_val() {
2570
    // no-op
2571
  }
2572
};
2573
2574
// This class manages conditionally having a trivial copy constructor
2575
// This specialization is for when T and E are trivially copy constructible
2576
template <class T, class E,
2577
          bool = is_void_or<T, TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(
2578
                                   T)>::value &&
2579
                 TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(E)::value>
2580
struct expected_copy_base : expected_operations_base<T, E> {
2581
  using expected_operations_base<T, E>::expected_operations_base;
2582
};
2583
2584
// This specialization is for when T or E are not trivially copy constructible
2585
template <class T, class E>
2586
struct expected_copy_base<T, E, false> : expected_operations_base<T, E> {
2587
  using expected_operations_base<T, E>::expected_operations_base;
2588
2589
  expected_copy_base() = default;
2590
  expected_copy_base(const expected_copy_base &rhs)
2591
0
      : expected_operations_base<T, E>(no_init) {
2592
0
    if (rhs.has_value()) {
2593
0
      this->construct_with(rhs);
2594
0
    } else {
2595
0
      this->construct_error(rhs.geterr());
2596
0
    }
2597
0
  }
2598
2599
  expected_copy_base(expected_copy_base &&rhs) = default;
2600
  expected_copy_base &operator=(const expected_copy_base &rhs) = default;
2601
  expected_copy_base &operator=(expected_copy_base &&rhs) = default;
2602
};
2603
2604
// This class manages conditionally having a trivial move constructor
2605
// Unfortunately there's no way to achieve this in GCC < 5 AFAIK, since it
2606
// doesn't implement an analogue to std::is_trivially_move_constructible. We
2607
// have to make do with a non-trivial move constructor even if T is trivially
2608
// move constructible
2609
#ifndef TL_EXPECTED_GCC49
2610
template <class T, class E,
2611
          bool =
2612
              is_void_or<T, std::is_trivially_move_constructible<T>>::value &&
2613
              std::is_trivially_move_constructible<E>::value>
2614
struct expected_move_base : expected_copy_base<T, E> {
2615
  using expected_copy_base<T, E>::expected_copy_base;
2616
};
2617
#else
2618
template <class T, class E, bool = false>
2619
struct expected_move_base;
2620
#endif
2621
template <class T, class E>
2622
struct expected_move_base<T, E, false> : expected_copy_base<T, E> {
2623
  using expected_copy_base<T, E>::expected_copy_base;
2624
2625
  expected_move_base() = default;
2626
0
  expected_move_base(const expected_move_base &rhs) = default;
2627
2628
  expected_move_base(expected_move_base &&rhs) noexcept(
2629
      std::is_nothrow_move_constructible<T>::value)
2630
      : expected_copy_base<T, E>(no_init) {
2631
    if (rhs.has_value()) {
2632
      this->construct_with(std::move(rhs));
2633
    } else {
2634
      this->construct_error(std::move(rhs.geterr()));
2635
    }
2636
  }
2637
  expected_move_base &operator=(const expected_move_base &rhs) = default;
2638
  expected_move_base &operator=(expected_move_base &&rhs) = default;
2639
};
2640
2641
// This class manages conditionally having a trivial copy assignment operator
2642
template <
2643
    class T, class E,
2644
    bool =
2645
        is_void_or<
2646
            T, conjunction<TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(T),
2647
                           TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T),
2648
                           TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(T)>>::value &&
2649
        TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(E)::value &&
2650
        TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(E)::value &&
2651
        TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(E)::value>
2652
struct expected_copy_assign_base : expected_move_base<T, E> {
2653
  using expected_move_base<T, E>::expected_move_base;
2654
};
2655
2656
template <class T, class E>
2657
struct expected_copy_assign_base<T, E, false> : expected_move_base<T, E> {
2658
  using expected_move_base<T, E>::expected_move_base;
2659
2660
  expected_copy_assign_base() = default;
2661
0
  expected_copy_assign_base(const expected_copy_assign_base &rhs) = default;
2662
2663
  expected_copy_assign_base(expected_copy_assign_base &&rhs) = default;
2664
  expected_copy_assign_base &operator=(const expected_copy_assign_base &rhs) {
2665
    this->assign(rhs);
2666
    return *this;
2667
  }
2668
  expected_copy_assign_base &operator=(expected_copy_assign_base &&rhs) =
2669
      default;
2670
};
2671
2672
// This class manages conditionally having a trivial move assignment operator
2673
// Unfortunately there's no way to achieve this in GCC < 5 AFAIK, since it
2674
// doesn't implement an analogue to std::is_trivially_move_assignable. We have
2675
// to make do with a non-trivial move assignment operator even if T is trivially
2676
// move assignable
2677
#ifndef TL_EXPECTED_GCC49
2678
template <
2679
    class T, class E,
2680
    bool = is_void_or<
2681
               T, conjunction<std::is_trivially_destructible<T>,
2682
                              std::is_trivially_move_constructible<T>,
2683
                              std::is_trivially_move_assignable<T>>>::value &&
2684
           std::is_trivially_destructible<E>::value &&
2685
           std::is_trivially_move_constructible<E>::value &&
2686
           std::is_trivially_move_assignable<E>::value>
2687
struct expected_move_assign_base : expected_copy_assign_base<T, E> {
2688
  using expected_copy_assign_base<T, E>::expected_copy_assign_base;
2689
};
2690
#else
2691
template <class T, class E, bool = false>
2692
struct expected_move_assign_base;
2693
#endif
2694
2695
template <class T, class E>
2696
struct expected_move_assign_base<T, E, false>
2697
    : expected_copy_assign_base<T, E> {
2698
  using expected_copy_assign_base<T, E>::expected_copy_assign_base;
2699
2700
  expected_move_assign_base() = default;
2701
0
  expected_move_assign_base(const expected_move_assign_base &rhs) = default;
2702
2703
  expected_move_assign_base(expected_move_assign_base &&rhs) = default;
2704
2705
  expected_move_assign_base &operator=(const expected_move_assign_base &rhs) =
2706
      default;
2707
2708
  expected_move_assign_base &operator=(
2709
      expected_move_assign_base
2710
          &&rhs) noexcept(std::is_nothrow_move_constructible<T>::value &&
2711
                          std::is_nothrow_move_assignable<T>::value) {
2712
    this->assign(std::move(rhs));
2713
    return *this;
2714
  }
2715
};
2716
2717
// expected_delete_ctor_base will conditionally delete copy and move
2718
// constructors depending on whether T is copy/move constructible
2719
template <class T, class E,
2720
          bool EnableCopy = (is_copy_constructible_or_void<T>::value &&
2721
                             std::is_copy_constructible<E>::value),
2722
          bool EnableMove = (is_move_constructible_or_void<T>::value &&
2723
                             std::is_move_constructible<E>::value)>
2724
struct expected_delete_ctor_base {
2725
  expected_delete_ctor_base() = default;
2726
  expected_delete_ctor_base(const expected_delete_ctor_base &) = default;
2727
  expected_delete_ctor_base(expected_delete_ctor_base &&) noexcept = default;
2728
  expected_delete_ctor_base &operator=(const expected_delete_ctor_base &) =
2729
      default;
2730
  expected_delete_ctor_base &operator=(expected_delete_ctor_base &&) noexcept =
2731
      default;
2732
};
2733
2734
template <class T, class E>
2735
struct expected_delete_ctor_base<T, E, true, false> {
2736
  expected_delete_ctor_base() = default;
2737
  expected_delete_ctor_base(const expected_delete_ctor_base &) = default;
2738
  expected_delete_ctor_base(expected_delete_ctor_base &&) noexcept = delete;
2739
  expected_delete_ctor_base &operator=(const expected_delete_ctor_base &) =
2740
      default;
2741
  expected_delete_ctor_base &operator=(expected_delete_ctor_base &&) noexcept =
2742
      default;
2743
};
2744
2745
template <class T, class E>
2746
struct expected_delete_ctor_base<T, E, false, true> {
2747
  expected_delete_ctor_base() = default;
2748
  expected_delete_ctor_base(const expected_delete_ctor_base &) = delete;
2749
  expected_delete_ctor_base(expected_delete_ctor_base &&) noexcept = default;
2750
  expected_delete_ctor_base &operator=(const expected_delete_ctor_base &) =
2751
      default;
2752
  expected_delete_ctor_base &operator=(expected_delete_ctor_base &&) noexcept =
2753
      default;
2754
};
2755
2756
template <class T, class E>
2757
struct expected_delete_ctor_base<T, E, false, false> {
2758
  expected_delete_ctor_base() = default;
2759
  expected_delete_ctor_base(const expected_delete_ctor_base &) = delete;
2760
  expected_delete_ctor_base(expected_delete_ctor_base &&) noexcept = delete;
2761
  expected_delete_ctor_base &operator=(const expected_delete_ctor_base &) =
2762
      default;
2763
  expected_delete_ctor_base &operator=(expected_delete_ctor_base &&) noexcept =
2764
      default;
2765
};
2766
2767
// expected_delete_assign_base will conditionally delete copy and move
2768
// constructors depending on whether T and E are copy/move constructible +
2769
// assignable
2770
template <class T, class E,
2771
          bool EnableCopy = (is_copy_constructible_or_void<T>::value &&
2772
                             std::is_copy_constructible<E>::value &&
2773
                             is_copy_assignable_or_void<T>::value &&
2774
                             std::is_copy_assignable<E>::value),
2775
          bool EnableMove = (is_move_constructible_or_void<T>::value &&
2776
                             std::is_move_constructible<E>::value &&
2777
                             is_move_assignable_or_void<T>::value &&
2778
                             std::is_move_assignable<E>::value)>
2779
struct expected_delete_assign_base {
2780
  expected_delete_assign_base() = default;
2781
  expected_delete_assign_base(const expected_delete_assign_base &) = default;
2782
  expected_delete_assign_base(expected_delete_assign_base &&) noexcept =
2783
      default;
2784
  expected_delete_assign_base &operator=(const expected_delete_assign_base &) =
2785
      default;
2786
  expected_delete_assign_base &operator=(
2787
      expected_delete_assign_base &&) noexcept = default;
2788
};
2789
2790
template <class T, class E>
2791
struct expected_delete_assign_base<T, E, true, false> {
2792
  expected_delete_assign_base() = default;
2793
  expected_delete_assign_base(const expected_delete_assign_base &) = default;
2794
  expected_delete_assign_base(expected_delete_assign_base &&) noexcept =
2795
      default;
2796
  expected_delete_assign_base &operator=(const expected_delete_assign_base &) =
2797
      default;
2798
  expected_delete_assign_base &operator=(
2799
      expected_delete_assign_base &&) noexcept = delete;
2800
};
2801
2802
template <class T, class E>
2803
struct expected_delete_assign_base<T, E, false, true> {
2804
  expected_delete_assign_base() = default;
2805
  expected_delete_assign_base(const expected_delete_assign_base &) = default;
2806
  expected_delete_assign_base(expected_delete_assign_base &&) noexcept =
2807
      default;
2808
  expected_delete_assign_base &operator=(const expected_delete_assign_base &) =
2809
      delete;
2810
  expected_delete_assign_base &operator=(
2811
      expected_delete_assign_base &&) noexcept = default;
2812
};
2813
2814
template <class T, class E>
2815
struct expected_delete_assign_base<T, E, false, false> {
2816
  expected_delete_assign_base() = default;
2817
  expected_delete_assign_base(const expected_delete_assign_base &) = default;
2818
  expected_delete_assign_base(expected_delete_assign_base &&) noexcept =
2819
      default;
2820
  expected_delete_assign_base &operator=(const expected_delete_assign_base &) =
2821
      delete;
2822
  expected_delete_assign_base &operator=(
2823
      expected_delete_assign_base &&) noexcept = delete;
2824
};
2825
2826
// This is needed to be able to construct the expected_default_ctor_base which
2827
// follows, while still conditionally deleting the default constructor.
2828
struct default_constructor_tag {
2829
  explicit constexpr default_constructor_tag() = default;
2830
};
2831
2832
// expected_default_ctor_base will ensure that expected has a deleted default
2833
// consturctor if T is not default constructible.
2834
// This specialization is for when T is default constructible
2835
template <class T, class E,
2836
          bool Enable =
2837
              std::is_default_constructible<T>::value || std::is_void<T>::value>
2838
struct expected_default_ctor_base {
2839
  constexpr expected_default_ctor_base() noexcept = default;
2840
  constexpr expected_default_ctor_base(
2841
      expected_default_ctor_base const &) noexcept = default;
2842
  constexpr expected_default_ctor_base(expected_default_ctor_base &&) noexcept =
2843
      default;
2844
  expected_default_ctor_base &operator=(
2845
      expected_default_ctor_base const &) noexcept = default;
2846
  expected_default_ctor_base &operator=(
2847
      expected_default_ctor_base &&) noexcept = default;
2848
2849
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)
2850
};
2851
2852
// This specialization is for when T is not default constructible
2853
template <class T, class E>
2854
struct expected_default_ctor_base<T, E, false> {
2855
  constexpr expected_default_ctor_base() noexcept = delete;
2856
  constexpr expected_default_ctor_base(
2857
      expected_default_ctor_base const &) noexcept = default;
2858
  constexpr expected_default_ctor_base(expected_default_ctor_base &&) noexcept =
2859
      default;
2860
  expected_default_ctor_base &operator=(
2861
      expected_default_ctor_base const &) noexcept = default;
2862
  expected_default_ctor_base &operator=(
2863
      expected_default_ctor_base &&) noexcept = default;
2864
2865
  constexpr explicit expected_default_ctor_base(default_constructor_tag) {}
2866
};
2867
}  // namespace detail
2868
2869
template <class E>
2870
class bad_expected_access : public std::exception {
2871
 public:
2872
0
  explicit bad_expected_access(E e) : m_val(std::move(e)) {}
2873
2874
0
  virtual const char *what() const noexcept override {
2875
0
    return "Bad expected access";
2876
0
  }
2877
2878
  const E &error() const & { return m_val; }
2879
  E &error() & { return m_val; }
2880
  const E &&error() const && { return std::move(m_val); }
2881
  E &&error() && { return std::move(m_val); }
2882
2883
 private:
2884
  E m_val;
2885
};
2886
2887
/// An `expected<T, E>` object is an object that contains the storage for
2888
/// another object and manages the lifetime of this contained object `T`.
2889
/// Alternatively it could contain the storage for another unexpected object
2890
/// `E`. The contained object may not be initialized after the expected object
2891
/// has been initialized, and may not be destroyed before the expected object
2892
/// has been destroyed. The initialization state of the contained object is
2893
/// tracked by the expected object.
2894
template <class T, class E>
2895
class expected : private detail::expected_move_assign_base<T, E>,
2896
                 private detail::expected_delete_ctor_base<T, E>,
2897
                 private detail::expected_delete_assign_base<T, E>,
2898
                 private detail::expected_default_ctor_base<T, E> {
2899
  static_assert(!std::is_reference<T>::value, "T must not be a reference");
2900
  static_assert(!std::is_same<T, std::remove_cv<in_place_t>::type>::value,
2901
                "T must not be in_place_t");
2902
  static_assert(!std::is_same<T, std::remove_cv<unexpect_t>::type>::value,
2903
                "T must not be unexpect_t");
2904
  static_assert(
2905
      !std::is_same<T, typename std::remove_cv<unexpected<E>>::type>::value,
2906
      "T must not be unexpected<E>");
2907
  static_assert(!std::is_reference<E>::value, "E must not be a reference");
2908
2909
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()
2910
  const T *valptr() const { return std::addressof(this->m_val); }
2911
  unexpected<E> *errptr() { return std::addressof(this->m_unexpect); }
2912
  const unexpected<E> *errptr() const {
2913
    return std::addressof(this->m_unexpect);
2914
  }
2915
2916
  template <class U = T,
2917
            detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
2918
0
  TL_EXPECTED_11_CONSTEXPR U &val() {
2919
0
    return this->m_val;
2920
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
2921
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()
2922
2923
  template <class U = T,
2924
            detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
2925
  constexpr const U &val() const {
2926
    return this->m_val;
2927
  }
2928
  constexpr const unexpected<E> &err() const { return this->m_unexpect; }
2929
2930
  using impl_base = detail::expected_move_assign_base<T, E>;
2931
  using ctor_base = detail::expected_default_ctor_base<T, E>;
2932
2933
 public:
2934
  typedef T value_type;
2935
  typedef E error_type;
2936
  typedef unexpected<E> unexpected_type;
2937
2938
#if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \
2939
    !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55)
2940
  template <class F>
2941
  TL_EXPECTED_11_CONSTEXPR auto and_then(F &&f) & {
2942
    return and_then_impl(*this, std::forward<F>(f));
2943
  }
2944
  template <class F>
2945
  TL_EXPECTED_11_CONSTEXPR auto and_then(F &&f) && {
2946
    return and_then_impl(std::move(*this), std::forward<F>(f));
2947
  }
2948
  template <class F>
2949
  constexpr auto and_then(F &&f) const & {
2950
    return and_then_impl(*this, std::forward<F>(f));
2951
  }
2952
2953
#ifndef TL_EXPECTED_NO_CONSTRR
2954
  template <class F>
2955
  constexpr auto and_then(F &&f) const && {
2956
    return and_then_impl(std::move(*this), std::forward<F>(f));
2957
  }
2958
#endif
2959
2960
#else
2961
  template <class F>
2962
  TL_EXPECTED_11_CONSTEXPR auto and_then(F &&f) & -> decltype(and_then_impl(
2963
      std::declval<expected &>(), std::forward<F>(f))) {
2964
    return and_then_impl(*this, std::forward<F>(f));
2965
  }
2966
  template <class F>
2967
  TL_EXPECTED_11_CONSTEXPR auto and_then(F &&f) && -> decltype(and_then_impl(
2968
      std::declval<expected &&>(), std::forward<F>(f))) {
2969
    return and_then_impl(std::move(*this), std::forward<F>(f));
2970
  }
2971
  template <class F>
2972
  constexpr auto and_then(F &&f) const & -> decltype(and_then_impl(
2973
      std::declval<expected const &>(), std::forward<F>(f))) {
2974
    return and_then_impl(*this, std::forward<F>(f));
2975
  }
2976
2977
#ifndef TL_EXPECTED_NO_CONSTRR
2978
  template <class F>
2979
  constexpr auto and_then(F &&f) const && -> decltype(and_then_impl(
2980
      std::declval<expected const &&>(), std::forward<F>(f))) {
2981
    return and_then_impl(std::move(*this), std::forward<F>(f));
2982
  }
2983
#endif
2984
#endif
2985
2986
#if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \
2987
    !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55)
2988
  template <class F>
2989
  TL_EXPECTED_11_CONSTEXPR auto map(F &&f) & {
2990
    return expected_map_impl(*this, std::forward<F>(f));
2991
  }
2992
  template <class F>
2993
  TL_EXPECTED_11_CONSTEXPR auto map(F &&f) && {
2994
    return expected_map_impl(std::move(*this), std::forward<F>(f));
2995
  }
2996
  template <class F>
2997
  constexpr auto map(F &&f) const & {
2998
    return expected_map_impl(*this, std::forward<F>(f));
2999
  }
3000
  template <class F>
3001
  constexpr auto map(F &&f) const && {
3002
    return expected_map_impl(std::move(*this), std::forward<F>(f));
3003
  }
3004
#else
3005
  template <class F>
3006
  TL_EXPECTED_11_CONSTEXPR decltype(expected_map_impl(
3007
      std::declval<expected &>(), std::declval<F &&>()))
3008
  map(F &&f) & {
3009
    return expected_map_impl(*this, std::forward<F>(f));
3010
  }
3011
  template <class F>
3012
  TL_EXPECTED_11_CONSTEXPR decltype(expected_map_impl(std::declval<expected>(),
3013
                                                      std::declval<F &&>()))
3014
  map(F &&f) && {
3015
    return expected_map_impl(std::move(*this), std::forward<F>(f));
3016
  }
3017
  template <class F>
3018
  constexpr decltype(expected_map_impl(std::declval<const expected &>(),
3019
                                       std::declval<F &&>()))
3020
  map(F &&f) const & {
3021
    return expected_map_impl(*this, std::forward<F>(f));
3022
  }
3023
3024
#ifndef TL_EXPECTED_NO_CONSTRR
3025
  template <class F>
3026
  constexpr decltype(expected_map_impl(std::declval<const expected &&>(),
3027
                                       std::declval<F &&>()))
3028
  map(F &&f) const && {
3029
    return expected_map_impl(std::move(*this), std::forward<F>(f));
3030
  }
3031
#endif
3032
#endif
3033
3034
#if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \
3035
    !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55)
3036
  template <class F>
3037
  TL_EXPECTED_11_CONSTEXPR auto transform(F &&f) & {
3038
    return expected_map_impl(*this, std::forward<F>(f));
3039
  }
3040
  template <class F>
3041
  TL_EXPECTED_11_CONSTEXPR auto transform(F &&f) && {
3042
    return expected_map_impl(std::move(*this), std::forward<F>(f));
3043
  }
3044
  template <class F>
3045
  constexpr auto transform(F &&f) const & {
3046
    return expected_map_impl(*this, std::forward<F>(f));
3047
  }
3048
  template <class F>
3049
  constexpr auto transform(F &&f) const && {
3050
    return expected_map_impl(std::move(*this), std::forward<F>(f));
3051
  }
3052
#else
3053
  template <class F>
3054
  TL_EXPECTED_11_CONSTEXPR decltype(expected_map_impl(
3055
      std::declval<expected &>(), std::declval<F &&>()))
3056
  transform(F &&f) & {
3057
    return expected_map_impl(*this, std::forward<F>(f));
3058
  }
3059
  template <class F>
3060
  TL_EXPECTED_11_CONSTEXPR decltype(expected_map_impl(std::declval<expected>(),
3061
                                                      std::declval<F &&>()))
3062
  transform(F &&f) && {
3063
    return expected_map_impl(std::move(*this), std::forward<F>(f));
3064
  }
3065
  template <class F>
3066
  constexpr decltype(expected_map_impl(std::declval<const expected &>(),
3067
                                       std::declval<F &&>()))
3068
  transform(F &&f) const & {
3069
    return expected_map_impl(*this, std::forward<F>(f));
3070
  }
3071
3072
#ifndef TL_EXPECTED_NO_CONSTRR
3073
  template <class F>
3074
  constexpr decltype(expected_map_impl(std::declval<const expected &&>(),
3075
                                       std::declval<F &&>()))
3076
  transform(F &&f) const && {
3077
    return expected_map_impl(std::move(*this), std::forward<F>(f));
3078
  }
3079
#endif
3080
#endif
3081
3082
#if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \
3083
    !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55)
3084
  template <class F>
3085
  TL_EXPECTED_11_CONSTEXPR auto map_error(F &&f) & {
3086
    return map_error_impl(*this, std::forward<F>(f));
3087
  }
3088
  template <class F>
3089
  TL_EXPECTED_11_CONSTEXPR auto map_error(F &&f) && {
3090
    return map_error_impl(std::move(*this), std::forward<F>(f));
3091
  }
3092
  template <class F>
3093
  constexpr auto map_error(F &&f) const & {
3094
    return map_error_impl(*this, std::forward<F>(f));
3095
  }
3096
  template <class F>
3097
  constexpr auto map_error(F &&f) const && {
3098
    return map_error_impl(std::move(*this), std::forward<F>(f));
3099
  }
3100
#else
3101
  template <class F>
3102
  TL_EXPECTED_11_CONSTEXPR decltype(map_error_impl(std::declval<expected &>(),
3103
                                                   std::declval<F &&>()))
3104
  map_error(F &&f) & {
3105
    return map_error_impl(*this, std::forward<F>(f));
3106
  }
3107
  template <class F>
3108
  TL_EXPECTED_11_CONSTEXPR decltype(map_error_impl(std::declval<expected &&>(),
3109
                                                   std::declval<F &&>()))
3110
  map_error(F &&f) && {
3111
    return map_error_impl(std::move(*this), std::forward<F>(f));
3112
  }
3113
  template <class F>
3114
  constexpr decltype(map_error_impl(std::declval<const expected &>(),
3115
                                    std::declval<F &&>()))
3116
  map_error(F &&f) const & {
3117
    return map_error_impl(*this, std::forward<F>(f));
3118
  }
3119
3120
#ifndef TL_EXPECTED_NO_CONSTRR
3121
  template <class F>
3122
  constexpr decltype(map_error_impl(std::declval<const expected &&>(),
3123
                                    std::declval<F &&>()))
3124
  map_error(F &&f) const && {
3125
    return map_error_impl(std::move(*this), std::forward<F>(f));
3126
  }
3127
#endif
3128
#endif
3129
#if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \
3130
    !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55)
3131
  template <class F>
3132
  TL_EXPECTED_11_CONSTEXPR auto transform_error(F &&f) & {
3133
    return map_error_impl(*this, std::forward<F>(f));
3134
  }
3135
  template <class F>
3136
  TL_EXPECTED_11_CONSTEXPR auto transform_error(F &&f) && {
3137
    return map_error_impl(std::move(*this), std::forward<F>(f));
3138
  }
3139
  template <class F>
3140
  constexpr auto transform_error(F &&f) const & {
3141
    return map_error_impl(*this, std::forward<F>(f));
3142
  }
3143
  template <class F>
3144
  constexpr auto transform_error(F &&f) const && {
3145
    return map_error_impl(std::move(*this), std::forward<F>(f));
3146
  }
3147
#else
3148
  template <class F>
3149
  TL_EXPECTED_11_CONSTEXPR decltype(map_error_impl(std::declval<expected &>(),
3150
                                                   std::declval<F &&>()))
3151
  transform_error(F &&f) & {
3152
    return map_error_impl(*this, std::forward<F>(f));
3153
  }
3154
  template <class F>
3155
  TL_EXPECTED_11_CONSTEXPR decltype(map_error_impl(std::declval<expected &&>(),
3156
                                                   std::declval<F &&>()))
3157
  transform_error(F &&f) && {
3158
    return map_error_impl(std::move(*this), std::forward<F>(f));
3159
  }
3160
  template <class F>
3161
  constexpr decltype(map_error_impl(std::declval<const expected &>(),
3162
                                    std::declval<F &&>()))
3163
  transform_error(F &&f) const & {
3164
    return map_error_impl(*this, std::forward<F>(f));
3165
  }
3166
3167
#ifndef TL_EXPECTED_NO_CONSTRR
3168
  template <class F>
3169
  constexpr decltype(map_error_impl(std::declval<const expected &&>(),
3170
                                    std::declval<F &&>()))
3171
  transform_error(F &&f) const && {
3172
    return map_error_impl(std::move(*this), std::forward<F>(f));
3173
  }
3174
#endif
3175
#endif
3176
  template <class F>
3177
  expected TL_EXPECTED_11_CONSTEXPR or_else(F &&f) & {
3178
    return or_else_impl(*this, std::forward<F>(f));
3179
  }
3180
3181
  template <class F>
3182
  expected TL_EXPECTED_11_CONSTEXPR or_else(F &&f) && {
3183
    return or_else_impl(std::move(*this), std::forward<F>(f));
3184
  }
3185
3186
  template <class F>
3187
  expected constexpr or_else(F &&f) const & {
3188
    return or_else_impl(*this, std::forward<F>(f));
3189
  }
3190
3191
#ifndef TL_EXPECTED_NO_CONSTRR
3192
  template <class F>
3193
  expected constexpr or_else(F &&f) const && {
3194
    return or_else_impl(std::move(*this), std::forward<F>(f));
3195
  }
3196
#endif
3197
  constexpr expected() = default;
3198
0
  constexpr expected(const expected &rhs) = default;
3199
  constexpr expected(expected &&rhs) = default;
3200
  expected &operator=(const expected &rhs) = default;
3201
  expected &operator=(expected &&rhs) = default;
3202
3203
  template <class... Args,
3204
            detail::enable_if_t<std::is_constructible<T, Args &&...>::value> * =
3205
                nullptr>
3206
  constexpr expected(in_place_t, Args &&...args)
3207
0
      : impl_base(in_place, std::forward<Args>(args)...),
3208
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_
3209
3210
  template <class U, class... Args,
3211
            detail::enable_if_t<std::is_constructible<
3212
                T, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
3213
  constexpr expected(in_place_t, std::initializer_list<U> il, Args &&...args)
3214
      : impl_base(in_place, il, std::forward<Args>(args)...),
3215
        ctor_base(detail::default_constructor_tag{}) {}
3216
3217
  template <class G = E,
3218
            detail::enable_if_t<std::is_constructible<E, const G &>::value> * =
3219
                nullptr,
3220
            detail::enable_if_t<!std::is_convertible<const G &, E>::value> * =
3221
                nullptr>
3222
  explicit constexpr expected(const unexpected<G> &e)
3223
      : impl_base(unexpect, e.value()),
3224
        ctor_base(detail::default_constructor_tag{}) {}
3225
3226
  template <
3227
      class G = E,
3228
      detail::enable_if_t<std::is_constructible<E, const G &>::value> * =
3229
          nullptr,
3230
      detail::enable_if_t<std::is_convertible<const G &, E>::value> * = nullptr>
3231
  constexpr expected(unexpected<G> const &e)
3232
      : impl_base(unexpect, e.value()),
3233
        ctor_base(detail::default_constructor_tag{}) {}
3234
3235
  template <
3236
      class G = E,
3237
      detail::enable_if_t<std::is_constructible<E, G &&>::value> * = nullptr,
3238
      detail::enable_if_t<!std::is_convertible<G &&, E>::value> * = nullptr>
3239
  explicit constexpr expected(unexpected<G> &&e) noexcept(
3240
      std::is_nothrow_constructible<E, G &&>::value)
3241
      : impl_base(unexpect, std::move(e.value())),
3242
        ctor_base(detail::default_constructor_tag{}) {}
3243
3244
  template <
3245
      class G = E,
3246
      detail::enable_if_t<std::is_constructible<E, G &&>::value> * = nullptr,
3247
      detail::enable_if_t<std::is_convertible<G &&, E>::value> * = nullptr>
3248
  constexpr expected(unexpected<G> &&e) noexcept(
3249
      std::is_nothrow_constructible<E, G &&>::value)
3250
0
      : impl_base(unexpect, std::move(e.value())),
3251
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
3252
3253
  template <class... Args,
3254
            detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * =
3255
                nullptr>
3256
  constexpr explicit expected(unexpect_t, Args &&...args)
3257
      : impl_base(unexpect, std::forward<Args>(args)...),
3258
        ctor_base(detail::default_constructor_tag{}) {}
3259
3260
  template <class U, class... Args,
3261
            detail::enable_if_t<std::is_constructible<
3262
                E, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
3263
  constexpr explicit expected(unexpect_t, std::initializer_list<U> il,
3264
                              Args &&...args)
3265
      : impl_base(unexpect, il, std::forward<Args>(args)...),
3266
        ctor_base(detail::default_constructor_tag{}) {}
3267
3268
  template <class U, class G,
3269
            detail::enable_if_t<!(std::is_convertible<U const &, T>::value &&
3270
                                  std::is_convertible<G const &, E>::value)> * =
3271
                nullptr,
3272
            detail::expected_enable_from_other<T, E, U, G, const U &, const G &>
3273
                * = nullptr>
3274
  explicit TL_EXPECTED_11_CONSTEXPR expected(const expected<U, G> &rhs)
3275
      : ctor_base(detail::default_constructor_tag{}) {
3276
    if (rhs.has_value()) {
3277
      this->construct(*rhs);
3278
    } else {
3279
      this->construct_error(rhs.error());
3280
    }
3281
  }
3282
3283
  template <class U, class G,
3284
            detail::enable_if_t<(std::is_convertible<U const &, T>::value &&
3285
                                 std::is_convertible<G const &, E>::value)> * =
3286
                nullptr,
3287
            detail::expected_enable_from_other<T, E, U, G, const U &, const G &>
3288
                * = nullptr>
3289
  TL_EXPECTED_11_CONSTEXPR expected(const expected<U, G> &rhs)
3290
      : ctor_base(detail::default_constructor_tag{}) {
3291
    if (rhs.has_value()) {
3292
      this->construct(*rhs);
3293
    } else {
3294
      this->construct_error(rhs.error());
3295
    }
3296
  }
3297
3298
  template <
3299
      class U, class G,
3300
      detail::enable_if_t<!(std::is_convertible<U &&, T>::value &&
3301
                            std::is_convertible<G &&, E>::value)> * = nullptr,
3302
      detail::expected_enable_from_other<T, E, U, G, U &&, G &&> * = nullptr>
3303
  explicit TL_EXPECTED_11_CONSTEXPR expected(expected<U, G> &&rhs)
3304
      : ctor_base(detail::default_constructor_tag{}) {
3305
    if (rhs.has_value()) {
3306
      this->construct(std::move(*rhs));
3307
    } else {
3308
      this->construct_error(std::move(rhs.error()));
3309
    }
3310
  }
3311
3312
  template <
3313
      class U, class G,
3314
      detail::enable_if_t<(std::is_convertible<U &&, T>::value &&
3315
                           std::is_convertible<G &&, E>::value)> * = nullptr,
3316
      detail::expected_enable_from_other<T, E, U, G, U &&, G &&> * = nullptr>
3317
  TL_EXPECTED_11_CONSTEXPR expected(expected<U, G> &&rhs)
3318
      : ctor_base(detail::default_constructor_tag{}) {
3319
    if (rhs.has_value()) {
3320
      this->construct(std::move(*rhs));
3321
    } else {
3322
      this->construct_error(std::move(rhs.error()));
3323
    }
3324
  }
3325
3326
  template <
3327
      class U = T,
3328
      detail::enable_if_t<!std::is_convertible<U &&, T>::value> * = nullptr,
3329
      detail::expected_enable_forward_value<T, E, U> * = nullptr>
3330
  explicit TL_EXPECTED_MSVC2015_CONSTEXPR expected(U &&v)
3331
      : expected(in_place, std::forward<U>(v)) {}
3332
3333
  template <
3334
      class U = T,
3335
      detail::enable_if_t<std::is_convertible<U &&, T>::value> * = nullptr,
3336
      detail::expected_enable_forward_value<T, E, U> * = nullptr>
3337
  TL_EXPECTED_MSVC2015_CONSTEXPR expected(U &&v)
3338
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_
3339
3340
  template <
3341
      class U = T, class G = T,
3342
      detail::enable_if_t<std::is_nothrow_constructible<T, U &&>::value> * =
3343
          nullptr,
3344
      detail::enable_if_t<!std::is_void<G>::value> * = nullptr,
3345
      detail::enable_if_t<
3346
          (!std::is_same<expected<T, E>, detail::decay_t<U>>::value &&
3347
           !detail::conjunction<std::is_scalar<T>,
3348
                                std::is_same<T, detail::decay_t<U>>>::value &&
3349
           std::is_constructible<T, U>::value &&
3350
           std::is_assignable<G &, U>::value &&
3351
           std::is_nothrow_move_constructible<E>::value)> * = nullptr>
3352
  expected &operator=(U &&v) {
3353
    if (has_value()) {
3354
      val() = std::forward<U>(v);
3355
    } else {
3356
      err().~unexpected<E>();
3357
      ::new (valptr()) T(std::forward<U>(v));
3358
      this->m_has_val = true;
3359
    }
3360
3361
    return *this;
3362
  }
3363
3364
  template <
3365
      class U = T, class G = T,
3366
      detail::enable_if_t<!std::is_nothrow_constructible<T, U &&>::value> * =
3367
          nullptr,
3368
      detail::enable_if_t<!std::is_void<U>::value> * = nullptr,
3369
      detail::enable_if_t<
3370
          (!std::is_same<expected<T, E>, detail::decay_t<U>>::value &&
3371
           !detail::conjunction<std::is_scalar<T>,
3372
                                std::is_same<T, detail::decay_t<U>>>::value &&
3373
           std::is_constructible<T, U>::value &&
3374
           std::is_assignable<G &, U>::value &&
3375
           std::is_nothrow_move_constructible<E>::value)> * = nullptr>
3376
  expected &operator=(U &&v) {
3377
    if (has_value()) {
3378
      val() = std::forward<U>(v);
3379
    } else {
3380
      auto tmp = std::move(err());
3381
      err().~unexpected<E>();
3382
3383
#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
3384
      try {
3385
        ::new (valptr()) T(std::forward<U>(v));
3386
        this->m_has_val = true;
3387
      } catch (...) {
3388
        err() = std::move(tmp);
3389
        throw;
3390
      }
3391
#else
3392
      ::new (valptr()) T(std::forward<U>(v));
3393
      this->m_has_val = true;
3394
#endif
3395
    }
3396
3397
    return *this;
3398
  }
3399
3400
  template <class G = E,
3401
            detail::enable_if_t<std::is_nothrow_copy_constructible<G>::value &&
3402
                                std::is_assignable<G &, G>::value> * = nullptr>
3403
  expected &operator=(const unexpected<G> &rhs) {
3404
    if (!has_value()) {
3405
      err() = rhs;
3406
    } else {
3407
      this->destroy_val();
3408
      ::new (errptr()) unexpected<E>(rhs);
3409
      this->m_has_val = false;
3410
    }
3411
3412
    return *this;
3413
  }
3414
3415
  template <class G = E,
3416
            detail::enable_if_t<std::is_nothrow_move_constructible<G>::value &&
3417
                                std::is_move_assignable<G>::value> * = nullptr>
3418
  expected &operator=(unexpected<G> &&rhs) noexcept {
3419
    if (!has_value()) {
3420
      err() = std::move(rhs);
3421
    } else {
3422
      this->destroy_val();
3423
      ::new (errptr()) unexpected<E>(std::move(rhs));
3424
      this->m_has_val = false;
3425
    }
3426
3427
    return *this;
3428
  }
3429
3430
  template <class... Args, detail::enable_if_t<std::is_nothrow_constructible<
3431
                               T, Args &&...>::value> * = nullptr>
3432
  void emplace(Args &&...args) {
3433
    if (has_value()) {
3434
      val().~T();
3435
    } else {
3436
      err().~unexpected<E>();
3437
      this->m_has_val = true;
3438
    }
3439
    ::new (valptr()) T(std::forward<Args>(args)...);
3440
  }
3441
3442
  template <class... Args, detail::enable_if_t<!std::is_nothrow_constructible<
3443
                               T, Args &&...>::value> * = nullptr>
3444
  void emplace(Args &&...args) {
3445
    if (has_value()) {
3446
      val().~T();
3447
      ::new (valptr()) T(std::forward<Args>(args)...);
3448
    } else {
3449
      auto tmp = std::move(err());
3450
      err().~unexpected<E>();
3451
3452
#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
3453
      try {
3454
        ::new (valptr()) T(std::forward<Args>(args)...);
3455
        this->m_has_val = true;
3456
      } catch (...) {
3457
        err() = std::move(tmp);
3458
        throw;
3459
      }
3460
#else
3461
      ::new (valptr()) T(std::forward<Args>(args)...);
3462
      this->m_has_val = true;
3463
#endif
3464
    }
3465
  }
3466
3467
  template <class U, class... Args,
3468
            detail::enable_if_t<std::is_nothrow_constructible<
3469
                T, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
3470
  void emplace(std::initializer_list<U> il, Args &&...args) {
3471
    if (has_value()) {
3472
      T t(il, std::forward<Args>(args)...);
3473
      val() = std::move(t);
3474
    } else {
3475
      err().~unexpected<E>();
3476
      ::new (valptr()) T(il, std::forward<Args>(args)...);
3477
      this->m_has_val = true;
3478
    }
3479
  }
3480
3481
  template <class U, class... Args,
3482
            detail::enable_if_t<!std::is_nothrow_constructible<
3483
                T, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
3484
  void emplace(std::initializer_list<U> il, Args &&...args) {
3485
    if (has_value()) {
3486
      T t(il, std::forward<Args>(args)...);
3487
      val() = std::move(t);
3488
    } else {
3489
      auto tmp = std::move(err());
3490
      err().~unexpected<E>();
3491
3492
#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
3493
      try {
3494
        ::new (valptr()) T(il, std::forward<Args>(args)...);
3495
        this->m_has_val = true;
3496
      } catch (...) {
3497
        err() = std::move(tmp);
3498
        throw;
3499
      }
3500
#else
3501
      ::new (valptr()) T(il, std::forward<Args>(args)...);
3502
      this->m_has_val = true;
3503
#endif
3504
    }
3505
  }
3506
3507
 private:
3508
  using t_is_void = std::true_type;
3509
  using t_is_not_void = std::false_type;
3510
  using t_is_nothrow_move_constructible = std::true_type;
3511
  using move_constructing_t_can_throw = std::false_type;
3512
  using e_is_nothrow_move_constructible = std::true_type;
3513
  using move_constructing_e_can_throw = std::false_type;
3514
3515
  void swap_where_both_have_value(expected & /*rhs*/, t_is_void) noexcept {
3516
    // swapping void is a no-op
3517
  }
3518
3519
  void swap_where_both_have_value(expected &rhs, t_is_not_void) {
3520
    using std::swap;
3521
    swap(val(), rhs.val());
3522
  }
3523
3524
  void swap_where_only_one_has_value(expected &rhs, t_is_void) noexcept(
3525
      std::is_nothrow_move_constructible<E>::value) {
3526
    ::new (errptr()) unexpected_type(std::move(rhs.err()));
3527
    rhs.err().~unexpected_type();
3528
    std::swap(this->m_has_val, rhs.m_has_val);
3529
  }
3530
3531
  void swap_where_only_one_has_value(expected &rhs, t_is_not_void) {
3532
    swap_where_only_one_has_value_and_t_is_not_void(
3533
        rhs, typename std::is_nothrow_move_constructible<T>::type{},
3534
        typename std::is_nothrow_move_constructible<E>::type{});
3535
  }
3536
3537
  void swap_where_only_one_has_value_and_t_is_not_void(
3538
      expected &rhs, t_is_nothrow_move_constructible,
3539
      e_is_nothrow_move_constructible) noexcept {
3540
    auto temp = std::move(val());
3541
    val().~T();
3542
    ::new (errptr()) unexpected_type(std::move(rhs.err()));
3543
    rhs.err().~unexpected_type();
3544
    ::new (rhs.valptr()) T(std::move(temp));
3545
    std::swap(this->m_has_val, rhs.m_has_val);
3546
  }
3547
3548
  void swap_where_only_one_has_value_and_t_is_not_void(
3549
      expected &rhs, t_is_nothrow_move_constructible,
3550
      move_constructing_e_can_throw) {
3551
    auto temp = std::move(val());
3552
    val().~T();
3553
#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
3554
    try {
3555
      ::new (errptr()) unexpected_type(std::move(rhs.err()));
3556
      rhs.err().~unexpected_type();
3557
      ::new (rhs.valptr()) T(std::move(temp));
3558
      std::swap(this->m_has_val, rhs.m_has_val);
3559
    } catch (...) {
3560
      val() = std::move(temp);
3561
      throw;
3562
    }
3563
#else
3564
    ::new (errptr()) unexpected_type(std::move(rhs.err()));
3565
    rhs.err().~unexpected_type();
3566
    ::new (rhs.valptr()) T(std::move(temp));
3567
    std::swap(this->m_has_val, rhs.m_has_val);
3568
#endif
3569
  }
3570
3571
  void swap_where_only_one_has_value_and_t_is_not_void(
3572
      expected &rhs, move_constructing_t_can_throw,
3573
      e_is_nothrow_move_constructible) {
3574
    auto temp = std::move(rhs.err());
3575
    rhs.err().~unexpected_type();
3576
#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
3577
    try {
3578
      ::new (rhs.valptr()) T(std::move(val()));
3579
      val().~T();
3580
      ::new (errptr()) unexpected_type(std::move(temp));
3581
      std::swap(this->m_has_val, rhs.m_has_val);
3582
    } catch (...) {
3583
      rhs.err() = std::move(temp);
3584
      throw;
3585
    }
3586
#else
3587
    ::new (rhs.valptr()) T(std::move(val()));
3588
    val().~T();
3589
    ::new (errptr()) unexpected_type(std::move(temp));
3590
    std::swap(this->m_has_val, rhs.m_has_val);
3591
#endif
3592
  }
3593
3594
 public:
3595
  template <class OT = T, class OE = E>
3596
  detail::enable_if_t<detail::is_swappable<OT>::value &&
3597
                      detail::is_swappable<OE>::value &&
3598
                      (std::is_nothrow_move_constructible<OT>::value ||
3599
                       std::is_nothrow_move_constructible<OE>::value)>
3600
  swap(expected &rhs) noexcept(std::is_nothrow_move_constructible<T>::value &&
3601
                               detail::is_nothrow_swappable<T>::value &&
3602
                               std::is_nothrow_move_constructible<E>::value &&
3603
                               detail::is_nothrow_swappable<E>::value) {
3604
    if (has_value() && rhs.has_value()) {
3605
      swap_where_both_have_value(rhs, typename std::is_void<T>::type{});
3606
    } else if (!has_value() && rhs.has_value()) {
3607
      rhs.swap(*this);
3608
    } else if (has_value()) {
3609
      swap_where_only_one_has_value(rhs, typename std::is_void<T>::type{});
3610
    } else {
3611
      using std::swap;
3612
      swap(err(), rhs.err());
3613
    }
3614
  }
3615
3616
  constexpr const T *operator->() const {
3617
    TL_ASSERT(has_value());
3618
    return valptr();
3619
  }
3620
0
  TL_EXPECTED_11_CONSTEXPR T *operator->() {
3621
0
    TL_ASSERT(has_value());
3622
0
    return valptr();
3623
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->()
3624
3625
  template <class U = T,
3626
            detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
3627
  constexpr const U &operator*() const & {
3628
    TL_ASSERT(has_value());
3629
    return val();
3630
  }
3631
  template <class U = T,
3632
            detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
3633
0
  TL_EXPECTED_11_CONSTEXPR U &operator*() & {
3634
0
    TL_ASSERT(has_value());
3635
0
    return val();
3636
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
3637
  template <class U = T,
3638
            detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
3639
  constexpr const U &&operator*() const && {
3640
    TL_ASSERT(has_value());
3641
    return std::move(val());
3642
  }
3643
  template <class U = T,
3644
            detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
3645
  TL_EXPECTED_11_CONSTEXPR U &&operator*() && {
3646
    TL_ASSERT(has_value());
3647
    return std::move(val());
3648
  }
3649
3650
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
3651
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
3652
3653
  template <class U = T,
3654
            detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
3655
  TL_EXPECTED_11_CONSTEXPR const U &value() const & {
3656
    if (!has_value())
3657
      detail::throw_exception(bad_expected_access<E>(err().value()));
3658
    return val();
3659
  }
3660
  template <class U = T,
3661
            detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
3662
0
  TL_EXPECTED_11_CONSTEXPR U &value() & {
3663
0
    if (!has_value())
3664
0
      detail::throw_exception(bad_expected_access<E>(err().value()));
3665
0
    return val();
3666
0
  }
3667
  template <class U = T,
3668
            detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
3669
  TL_EXPECTED_11_CONSTEXPR const U &&value() const && {
3670
    if (!has_value())
3671
      detail::throw_exception(bad_expected_access<E>(std::move(err()).value()));
3672
    return std::move(val());
3673
  }
3674
  template <class U = T,
3675
            detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
3676
  TL_EXPECTED_11_CONSTEXPR U &&value() && {
3677
    if (!has_value())
3678
      detail::throw_exception(bad_expected_access<E>(std::move(err()).value()));
3679
    return std::move(val());
3680
  }
3681
3682
  constexpr const E &error() const & {
3683
    TL_ASSERT(!has_value());
3684
    return err().value();
3685
  }
3686
0
  TL_EXPECTED_11_CONSTEXPR E &error() & {
3687
0
    TL_ASSERT(!has_value());
3688
0
    return err().value();
3689
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() &
3690
  constexpr const E &&error() const && {
3691
    TL_ASSERT(!has_value());
3692
    return std::move(err().value());
3693
  }
3694
  TL_EXPECTED_11_CONSTEXPR E &&error() && {
3695
    TL_ASSERT(!has_value());
3696
    return std::move(err().value());
3697
  }
3698
3699
  template <class U>
3700
  constexpr T value_or(U &&v) const & {
3701
    static_assert(std::is_copy_constructible<T>::value &&
3702
                      std::is_convertible<U &&, T>::value,
3703
                  "T must be copy-constructible and convertible to from U&&");
3704
    return bool(*this) ? **this : static_cast<T>(std::forward<U>(v));
3705
  }
3706
  template <class U>
3707
  TL_EXPECTED_11_CONSTEXPR T value_or(U &&v) && {
3708
    static_assert(std::is_move_constructible<T>::value &&
3709
                      std::is_convertible<U &&, T>::value,
3710
                  "T must be move-constructible and convertible to from U&&");
3711
    return bool(*this) ? std::move(**this) : static_cast<T>(std::forward<U>(v));
3712
  }
3713
};
3714
3715
namespace detail {
3716
template <class Exp>
3717
using exp_t = typename detail::decay_t<Exp>::value_type;
3718
template <class Exp>
3719
using err_t = typename detail::decay_t<Exp>::error_type;
3720
template <class Exp, class Ret>
3721
using ret_t = expected<Ret, err_t<Exp>>;
3722
3723
#ifdef TL_EXPECTED_CXX14
3724
template <class Exp, class F,
3725
          detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
3726
          class Ret = decltype(detail::invoke(std::declval<F>(),
3727
                                              *std::declval<Exp>()))>
3728
constexpr auto and_then_impl(Exp &&exp, F &&f) {
3729
  static_assert(detail::is_expected<Ret>::value, "F must return an expected");
3730
3731
  return exp.has_value()
3732
             ? detail::invoke(std::forward<F>(f), *std::forward<Exp>(exp))
3733
             : Ret(unexpect, std::forward<Exp>(exp).error());
3734
}
3735
3736
template <class Exp, class F,
3737
          detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
3738
          class Ret = decltype(detail::invoke(std::declval<F>()))>
3739
constexpr auto and_then_impl(Exp &&exp, F &&f) {
3740
  static_assert(detail::is_expected<Ret>::value, "F must return an expected");
3741
3742
  return exp.has_value() ? detail::invoke(std::forward<F>(f))
3743
                         : Ret(unexpect, std::forward<Exp>(exp).error());
3744
}
3745
#else
3746
template <class>
3747
struct TC;
3748
template <class Exp, class F,
3749
          class Ret = decltype(detail::invoke(std::declval<F>(),
3750
                                              *std::declval<Exp>())),
3751
          detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr>
3752
auto and_then_impl(Exp &&exp, F &&f) -> Ret {
3753
  static_assert(detail::is_expected<Ret>::value, "F must return an expected");
3754
3755
  return exp.has_value()
3756
             ? detail::invoke(std::forward<F>(f), *std::forward<Exp>(exp))
3757
             : Ret(unexpect, std::forward<Exp>(exp).error());
3758
}
3759
3760
template <class Exp, class F,
3761
          class Ret = decltype(detail::invoke(std::declval<F>())),
3762
          detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr>
3763
constexpr auto and_then_impl(Exp &&exp, F &&f) -> Ret {
3764
  static_assert(detail::is_expected<Ret>::value, "F must return an expected");
3765
3766
  return exp.has_value() ? detail::invoke(std::forward<F>(f))
3767
                         : Ret(unexpect, std::forward<Exp>(exp).error());
3768
}
3769
#endif
3770
3771
#ifdef TL_EXPECTED_CXX14
3772
template <class Exp, class F,
3773
          detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
3774
          class Ret = decltype(detail::invoke(std::declval<F>(),
3775
                                              *std::declval<Exp>())),
3776
          detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
3777
constexpr auto expected_map_impl(Exp &&exp, F &&f) {
3778
  using result = ret_t<Exp, detail::decay_t<Ret>>;
3779
  return exp.has_value() ? result(detail::invoke(std::forward<F>(f),
3780
                                                 *std::forward<Exp>(exp)))
3781
                         : result(unexpect, std::forward<Exp>(exp).error());
3782
}
3783
3784
template <class Exp, class F,
3785
          detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
3786
          class Ret = decltype(detail::invoke(std::declval<F>(),
3787
                                              *std::declval<Exp>())),
3788
          detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
3789
auto expected_map_impl(Exp &&exp, F &&f) {
3790
  using result = expected<void, err_t<Exp>>;
3791
  if (exp.has_value()) {
3792
    detail::invoke(std::forward<F>(f), *std::forward<Exp>(exp));
3793
    return result();
3794
  }
3795
3796
  return result(unexpect, std::forward<Exp>(exp).error());
3797
}
3798
3799
template <class Exp, class F,
3800
          detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
3801
          class Ret = decltype(detail::invoke(std::declval<F>())),
3802
          detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
3803
constexpr auto expected_map_impl(Exp &&exp, F &&f) {
3804
  using result = ret_t<Exp, detail::decay_t<Ret>>;
3805
  return exp.has_value() ? result(detail::invoke(std::forward<F>(f)))
3806
                         : result(unexpect, std::forward<Exp>(exp).error());
3807
}
3808
3809
template <class Exp, class F,
3810
          detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
3811
          class Ret = decltype(detail::invoke(std::declval<F>())),
3812
          detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
3813
auto expected_map_impl(Exp &&exp, F &&f) {
3814
  using result = expected<void, err_t<Exp>>;
3815
  if (exp.has_value()) {
3816
    detail::invoke(std::forward<F>(f));
3817
    return result();
3818
  }
3819
3820
  return result(unexpect, std::forward<Exp>(exp).error());
3821
}
3822
#else
3823
template <class Exp, class F,
3824
          detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
3825
          class Ret = decltype(detail::invoke(std::declval<F>(),
3826
                                              *std::declval<Exp>())),
3827
          detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
3828
3829
constexpr auto expected_map_impl(Exp &&exp, F &&f)
3830
    -> ret_t<Exp, detail::decay_t<Ret>> {
3831
  using result = ret_t<Exp, detail::decay_t<Ret>>;
3832
3833
  return exp.has_value() ? result(detail::invoke(std::forward<F>(f),
3834
                                                 *std::forward<Exp>(exp)))
3835
                         : result(unexpect, std::forward<Exp>(exp).error());
3836
}
3837
3838
template <class Exp, class F,
3839
          detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
3840
          class Ret = decltype(detail::invoke(std::declval<F>(),
3841
                                              *std::declval<Exp>())),
3842
          detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
3843
3844
auto expected_map_impl(Exp &&exp, F &&f) -> expected<void, err_t<Exp>> {
3845
  if (exp.has_value()) {
3846
    detail::invoke(std::forward<F>(f), *std::forward<Exp>(exp));
3847
    return {};
3848
  }
3849
3850
  return unexpected<err_t<Exp>>(std::forward<Exp>(exp).error());
3851
}
3852
3853
template <class Exp, class F,
3854
          detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
3855
          class Ret = decltype(detail::invoke(std::declval<F>())),
3856
          detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
3857
3858
constexpr auto expected_map_impl(Exp &&exp, F &&f)
3859
    -> ret_t<Exp, detail::decay_t<Ret>> {
3860
  using result = ret_t<Exp, detail::decay_t<Ret>>;
3861
3862
  return exp.has_value() ? result(detail::invoke(std::forward<F>(f)))
3863
                         : result(unexpect, std::forward<Exp>(exp).error());
3864
}
3865
3866
template <class Exp, class F,
3867
          detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
3868
          class Ret = decltype(detail::invoke(std::declval<F>())),
3869
          detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
3870
3871
auto expected_map_impl(Exp &&exp, F &&f) -> expected<void, err_t<Exp>> {
3872
  if (exp.has_value()) {
3873
    detail::invoke(std::forward<F>(f));
3874
    return {};
3875
  }
3876
3877
  return unexpected<err_t<Exp>>(std::forward<Exp>(exp).error());
3878
}
3879
#endif
3880
3881
#if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \
3882
    !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55)
3883
template <class Exp, class F,
3884
          detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
3885
          class Ret = decltype(detail::invoke(std::declval<F>(),
3886
                                              std::declval<Exp>().error())),
3887
          detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
3888
constexpr auto map_error_impl(Exp &&exp, F &&f) {
3889
  using result = expected<exp_t<Exp>, detail::decay_t<Ret>>;
3890
  return exp.has_value()
3891
             ? result(*std::forward<Exp>(exp))
3892
             : result(unexpect, detail::invoke(std::forward<F>(f),
3893
                                               std::forward<Exp>(exp).error()));
3894
}
3895
template <class Exp, class F,
3896
          detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
3897
          class Ret = decltype(detail::invoke(std::declval<F>(),
3898
                                              std::declval<Exp>().error())),
3899
          detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
3900
auto map_error_impl(Exp &&exp, F &&f) {
3901
  using result = expected<exp_t<Exp>, monostate>;
3902
  if (exp.has_value()) {
3903
    return result(*std::forward<Exp>(exp));
3904
  }
3905
3906
  detail::invoke(std::forward<F>(f), std::forward<Exp>(exp).error());
3907
  return result(unexpect, monostate{});
3908
}
3909
template <class Exp, class F,
3910
          detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
3911
          class Ret = decltype(detail::invoke(std::declval<F>(),
3912
                                              std::declval<Exp>().error())),
3913
          detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
3914
constexpr auto map_error_impl(Exp &&exp, F &&f) {
3915
  using result = expected<exp_t<Exp>, detail::decay_t<Ret>>;
3916
  return exp.has_value()
3917
             ? result()
3918
             : result(unexpect, detail::invoke(std::forward<F>(f),
3919
                                               std::forward<Exp>(exp).error()));
3920
}
3921
template <class Exp, class F,
3922
          detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
3923
          class Ret = decltype(detail::invoke(std::declval<F>(),
3924
                                              std::declval<Exp>().error())),
3925
          detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
3926
auto map_error_impl(Exp &&exp, F &&f) {
3927
  using result = expected<exp_t<Exp>, monostate>;
3928
  if (exp.has_value()) {
3929
    return result();
3930
  }
3931
3932
  detail::invoke(std::forward<F>(f), std::forward<Exp>(exp).error());
3933
  return result(unexpect, monostate{});
3934
}
3935
#else
3936
template <class Exp, class F,
3937
          detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
3938
          class Ret = decltype(detail::invoke(std::declval<F>(),
3939
                                              std::declval<Exp>().error())),
3940
          detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
3941
constexpr auto map_error_impl(Exp &&exp, F &&f)
3942
    -> expected<exp_t<Exp>, detail::decay_t<Ret>> {
3943
  using result = expected<exp_t<Exp>, detail::decay_t<Ret>>;
3944
3945
  return exp.has_value()
3946
             ? result(*std::forward<Exp>(exp))
3947
             : result(unexpect, detail::invoke(std::forward<F>(f),
3948
                                               std::forward<Exp>(exp).error()));
3949
}
3950
3951
template <class Exp, class F,
3952
          detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
3953
          class Ret = decltype(detail::invoke(std::declval<F>(),
3954
                                              std::declval<Exp>().error())),
3955
          detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
3956
auto map_error_impl(Exp &&exp, F &&f) -> expected<exp_t<Exp>, monostate> {
3957
  using result = expected<exp_t<Exp>, monostate>;
3958
  if (exp.has_value()) {
3959
    return result(*std::forward<Exp>(exp));
3960
  }
3961
3962
  detail::invoke(std::forward<F>(f), std::forward<Exp>(exp).error());
3963
  return result(unexpect, monostate{});
3964
}
3965
3966
template <class Exp, class F,
3967
          detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
3968
          class Ret = decltype(detail::invoke(std::declval<F>(),
3969
                                              std::declval<Exp>().error())),
3970
          detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
3971
constexpr auto map_error_impl(Exp &&exp, F &&f)
3972
    -> expected<exp_t<Exp>, detail::decay_t<Ret>> {
3973
  using result = expected<exp_t<Exp>, detail::decay_t<Ret>>;
3974
3975
  return exp.has_value()
3976
             ? result()
3977
             : result(unexpect, detail::invoke(std::forward<F>(f),
3978
                                               std::forward<Exp>(exp).error()));
3979
}
3980
3981
template <class Exp, class F,
3982
          detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
3983
          class Ret = decltype(detail::invoke(std::declval<F>(),
3984
                                              std::declval<Exp>().error())),
3985
          detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
3986
auto map_error_impl(Exp &&exp, F &&f) -> expected<exp_t<Exp>, monostate> {
3987
  using result = expected<exp_t<Exp>, monostate>;
3988
  if (exp.has_value()) {
3989
    return result();
3990
  }
3991
3992
  detail::invoke(std::forward<F>(f), std::forward<Exp>(exp).error());
3993
  return result(unexpect, monostate{});
3994
}
3995
#endif
3996
3997
#ifdef TL_EXPECTED_CXX14
3998
template <class Exp, class F,
3999
          class Ret = decltype(detail::invoke(std::declval<F>(),
4000
                                              std::declval<Exp>().error())),
4001
          detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
4002
constexpr auto or_else_impl(Exp &&exp, F &&f) {
4003
  static_assert(detail::is_expected<Ret>::value, "F must return an expected");
4004
  return exp.has_value() ? std::forward<Exp>(exp)
4005
                         : detail::invoke(std::forward<F>(f),
4006
                                          std::forward<Exp>(exp).error());
4007
}
4008
4009
template <class Exp, class F,
4010
          class Ret = decltype(detail::invoke(std::declval<F>(),
4011
                                              std::declval<Exp>().error())),
4012
          detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
4013
detail::decay_t<Exp> or_else_impl(Exp &&exp, F &&f) {
4014
  return exp.has_value() ? std::forward<Exp>(exp)
4015
                         : (detail::invoke(std::forward<F>(f),
4016
                                           std::forward<Exp>(exp).error()),
4017
                            std::forward<Exp>(exp));
4018
}
4019
#else
4020
template <class Exp, class F,
4021
          class Ret = decltype(detail::invoke(std::declval<F>(),
4022
                                              std::declval<Exp>().error())),
4023
          detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
4024
auto or_else_impl(Exp &&exp, F &&f) -> Ret {
4025
  static_assert(detail::is_expected<Ret>::value, "F must return an expected");
4026
  return exp.has_value() ? std::forward<Exp>(exp)
4027
                         : detail::invoke(std::forward<F>(f),
4028
                                          std::forward<Exp>(exp).error());
4029
}
4030
4031
template <class Exp, class F,
4032
          class Ret = decltype(detail::invoke(std::declval<F>(),
4033
                                              std::declval<Exp>().error())),
4034
          detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
4035
detail::decay_t<Exp> or_else_impl(Exp &&exp, F &&f) {
4036
  return exp.has_value() ? std::forward<Exp>(exp)
4037
                         : (detail::invoke(std::forward<F>(f),
4038
                                           std::forward<Exp>(exp).error()),
4039
                            std::forward<Exp>(exp));
4040
}
4041
#endif
4042
}  // namespace detail
4043
4044
template <class T, class E, class U, class F>
4045
constexpr bool operator==(const expected<T, E> &lhs,
4046
                          const expected<U, F> &rhs) {
4047
  return (lhs.has_value() != rhs.has_value())
4048
             ? false
4049
             : (!lhs.has_value() ? lhs.error() == rhs.error() : *lhs == *rhs);
4050
}
4051
template <class T, class E, class U, class F>
4052
constexpr bool operator!=(const expected<T, E> &lhs,
4053
                          const expected<U, F> &rhs) {
4054
  return (lhs.has_value() != rhs.has_value())
4055
             ? true
4056
             : (!lhs.has_value() ? lhs.error() != rhs.error() : *lhs != *rhs);
4057
}
4058
template <class E, class F>
4059
constexpr bool operator==(const expected<void, E> &lhs,
4060
                          const expected<void, F> &rhs) {
4061
  return (lhs.has_value() != rhs.has_value())
4062
             ? false
4063
             : (!lhs.has_value() ? lhs.error() == rhs.error() : true);
4064
}
4065
template <class E, class F>
4066
constexpr bool operator!=(const expected<void, E> &lhs,
4067
                          const expected<void, F> &rhs) {
4068
  return (lhs.has_value() != rhs.has_value())
4069
             ? true
4070
             : (!lhs.has_value() ? lhs.error() == rhs.error() : false);
4071
}
4072
4073
template <class T, class E, class U>
4074
constexpr bool operator==(const expected<T, E> &x, const U &v) {
4075
  return x.has_value() ? *x == v : false;
4076
}
4077
template <class T, class E, class U>
4078
constexpr bool operator==(const U &v, const expected<T, E> &x) {
4079
  return x.has_value() ? *x == v : false;
4080
}
4081
template <class T, class E, class U>
4082
constexpr bool operator!=(const expected<T, E> &x, const U &v) {
4083
  return x.has_value() ? *x != v : true;
4084
}
4085
template <class T, class E, class U>
4086
constexpr bool operator!=(const U &v, const expected<T, E> &x) {
4087
  return x.has_value() ? *x != v : true;
4088
}
4089
4090
template <class T, class E>
4091
constexpr bool operator==(const expected<T, E> &x, const unexpected<E> &e) {
4092
  return x.has_value() ? false : x.error() == e.value();
4093
}
4094
template <class T, class E>
4095
constexpr bool operator==(const unexpected<E> &e, const expected<T, E> &x) {
4096
  return x.has_value() ? false : x.error() == e.value();
4097
}
4098
template <class T, class E>
4099
constexpr bool operator!=(const expected<T, E> &x, const unexpected<E> &e) {
4100
  return x.has_value() ? true : x.error() != e.value();
4101
}
4102
template <class T, class E>
4103
constexpr bool operator!=(const unexpected<E> &e, const expected<T, E> &x) {
4104
  return x.has_value() ? true : x.error() != e.value();
4105
}
4106
4107
template <class T, class E,
4108
          detail::enable_if_t<(std::is_void<T>::value ||
4109
                               std::is_move_constructible<T>::value) &&
4110
                              detail::is_swappable<T>::value &&
4111
                              std::is_move_constructible<E>::value &&
4112
                              detail::is_swappable<E>::value> * = nullptr>
4113
void swap(expected<T, E> &lhs,
4114
          expected<T, E> &rhs) noexcept(noexcept(lhs.swap(rhs))) {
4115
  lhs.swap(rhs);
4116
}
4117
}  // namespace tl
4118
4119
#endif
4120
/* end file include/ada/expected.h */
4121
4122
/* begin file include/ada/url_pattern_regex.h */
4123
/**
4124
 * @file url_search_params.h
4125
 * @brief Declaration for the URL Search Params
4126
 */
4127
#ifndef ADA_URL_PATTERN_REGEX_H
4128
#define ADA_URL_PATTERN_REGEX_H
4129
4130
#include <string>
4131
#include <string_view>
4132
4133
#ifdef ADA_USE_UNSAFE_STD_REGEX_PROVIDER
4134
#include <regex>
4135
#endif  // ADA_USE_UNSAFE_STD_REGEX_PROVIDER
4136
4137
#if ADA_INCLUDE_URL_PATTERN
4138
namespace ada::url_pattern_regex {
4139
4140
template <typename T>
4141
concept regex_concept = requires(T t, std::string_view pattern,
4142
                                 bool ignore_case, std::string_view input) {
4143
  // Ensure the class has a type alias 'regex_type'
4144
  typename T::regex_type;
4145
4146
  // Function to create a regex instance
4147
  {
4148
    T::create_instance(pattern, ignore_case)
4149
  } -> std::same_as<std::optional<typename T::regex_type>>;
4150
4151
  // Function to perform regex search
4152
  {
4153
    T::regex_search(input, std::declval<typename T::regex_type&>())
4154
  } -> std::same_as<std::optional<std::vector<std::optional<std::string>>>>;
4155
4156
  // Function to match regex pattern
4157
  {
4158
    T::regex_match(input, std::declval<typename T::regex_type&>())
4159
  } -> std::same_as<bool>;
4160
4161
  // Copy constructor
4162
  { T(std::declval<const T&>()) } -> std::same_as<T>;
4163
4164
  // Move constructor
4165
  { T(std::declval<T&&>()) } -> std::same_as<T>;
4166
};
4167
4168
#ifdef ADA_USE_UNSAFE_STD_REGEX_PROVIDER
4169
class std_regex_provider final {
4170
 public:
4171
  std_regex_provider() = default;
4172
  using regex_type = std::regex;
4173
  static std::optional<regex_type> create_instance(std::string_view pattern,
4174
                                                   bool ignore_case);
4175
  static std::optional<std::vector<std::optional<std::string>>> regex_search(
4176
      std::string_view input, const regex_type& pattern);
4177
  static bool regex_match(std::string_view input, const regex_type& pattern);
4178
};
4179
#endif  // ADA_USE_UNSAFE_STD_REGEX_PROVIDER
4180
4181
}  // namespace ada::url_pattern_regex
4182
#endif  // ADA_INCLUDE_URL_PATTERN
4183
#endif  // ADA_URL_PATTERN_REGEX_H
4184
/* end file include/ada/url_pattern_regex.h */
4185
/* begin file include/ada/url_pattern_init.h */
4186
/**
4187
 * @file url_pattern_init.h
4188
 * @brief Declaration for the url_pattern_init implementation.
4189
 */
4190
#ifndef ADA_URL_PATTERN_INIT_H
4191
#define ADA_URL_PATTERN_INIT_H
4192
4193
/* begin file include/ada/errors.h */
4194
/**
4195
 * @file errors.h
4196
 * @brief Definitions for the errors.
4197
 */
4198
#ifndef ADA_ERRORS_H
4199
#define ADA_ERRORS_H
4200
4201
#include <cstdint>
4202
namespace ada {
4203
enum class errors : uint8_t { type_error };
4204
}  // namespace ada
4205
#endif  // ADA_ERRORS_H
4206
/* end file include/ada/errors.h */
4207
4208
#include <string_view>
4209
#include <string>
4210
#include <optional>
4211
#include <iostream>
4212
4213
#if ADA_TESTING
4214
#include <iostream>
4215
#endif  // ADA_TESTING
4216
4217
#if ADA_INCLUDE_URL_PATTERN
4218
namespace ada {
4219
4220
// Important: C++20 allows us to use concept rather than `using` or `typedef
4221
// and allows functions with second argument, which is optional (using either
4222
// std::nullopt or a parameter with default value)
4223
template <typename F>
4224
concept url_pattern_encoding_callback = requires(F f, std::string_view sv) {
4225
  { f(sv) } -> std::same_as<tl::expected<std::string, errors>>;
4226
};
4227
4228
// A structure providing matching patterns for individual components
4229
// of a URL. When a URLPattern is created, or when a URLPattern is
4230
// used to match or test against a URL, the input can be given as
4231
// either a string or a URLPatternInit struct. If a string is given,
4232
// it will be parsed to create a URLPatternInit. The URLPatternInit
4233
// API is defined as part of the URLPattern specification.
4234
// All provided strings must be valid UTF-8.
4235
struct url_pattern_init {
4236
  enum class process_type : uint8_t {
4237
    url,
4238
    pattern,
4239
  };
4240
4241
0
  friend std::ostream& operator<<(std::ostream& os, process_type type) {
4242
0
    switch (type) {
4243
0
      case process_type::url:
4244
0
        return os << "url";
4245
0
      case process_type::pattern:
4246
0
        return os << "pattern";
4247
0
      default:
4248
0
        return os << "unknown";
4249
0
    }
4250
0
  }
4251
4252
  // All strings must be valid UTF-8.
4253
  // @see https://urlpattern.spec.whatwg.org/#process-a-urlpatterninit
4254
  static tl::expected<url_pattern_init, errors> process(
4255
      const url_pattern_init& init, process_type type,
4256
      std::optional<std::string_view> protocol = std::nullopt,
4257
      std::optional<std::string_view> username = std::nullopt,
4258
      std::optional<std::string_view> password = std::nullopt,
4259
      std::optional<std::string_view> hostname = std::nullopt,
4260
      std::optional<std::string_view> port = std::nullopt,
4261
      std::optional<std::string_view> pathname = std::nullopt,
4262
      std::optional<std::string_view> search = std::nullopt,
4263
      std::optional<std::string_view> hash = std::nullopt);
4264
4265
  // @see https://urlpattern.spec.whatwg.org/#process-protocol-for-init
4266
  static tl::expected<std::string, errors> process_protocol(
4267
      std::string_view value, process_type type);
4268
4269
  // @see https://urlpattern.spec.whatwg.org/#process-username-for-init
4270
  static tl::expected<std::string, errors> process_username(
4271
      std::string_view value, process_type type);
4272
4273
  // @see https://urlpattern.spec.whatwg.org/#process-password-for-init
4274
  static tl::expected<std::string, errors> process_password(
4275
      std::string_view value, process_type type);
4276
4277
  // @see https://urlpattern.spec.whatwg.org/#process-hostname-for-init
4278
  static tl::expected<std::string, errors> process_hostname(
4279
      std::string_view value, process_type type);
4280
4281
  // @see https://urlpattern.spec.whatwg.org/#process-port-for-init
4282
  static tl::expected<std::string, errors> process_port(
4283
      std::string_view port, std::string_view protocol, process_type type);
4284
4285
  // @see https://urlpattern.spec.whatwg.org/#process-pathname-for-init
4286
  static tl::expected<std::string, errors> process_pathname(
4287
      std::string_view value, std::string_view protocol, process_type type);
4288
4289
  // @see https://urlpattern.spec.whatwg.org/#process-search-for-init
4290
  static tl::expected<std::string, errors> process_search(
4291
      std::string_view value, process_type type);
4292
4293
  // @see https://urlpattern.spec.whatwg.org/#process-hash-for-init
4294
  static tl::expected<std::string, errors> process_hash(std::string_view value,
4295
                                                        process_type type);
4296
4297
#if ADA_TESTING
4298
  friend void PrintTo(const url_pattern_init& init, std::ostream* os) {
4299
    *os << "protocol: '" << init.protocol.value_or("undefined") << "', ";
4300
    *os << "username: '" << init.username.value_or("undefined") << "', ";
4301
    *os << "password: '" << init.password.value_or("undefined") << "', ";
4302
    *os << "hostname: '" << init.hostname.value_or("undefined") << "', ";
4303
    *os << "port: '" << init.port.value_or("undefined") << "', ";
4304
    *os << "pathname: '" << init.pathname.value_or("undefined") << "', ";
4305
    *os << "search: '" << init.search.value_or("undefined") << "', ";
4306
    *os << "hash: '" << init.hash.value_or("undefined") << "', ";
4307
    *os << "base_url: '" << init.base_url.value_or("undefined") << "', ";
4308
  }
4309
#endif  // ADA_TESTING
4310
4311
  bool operator==(const url_pattern_init&) const;
4312
  // If present, must be valid UTF-8.
4313
  std::optional<std::string> protocol{};
4314
  // If present, must be valid UTF-8.
4315
  std::optional<std::string> username{};
4316
  // If present, must be valid UTF-8.
4317
  std::optional<std::string> password{};
4318
  // If present, must be valid UTF-8.
4319
  std::optional<std::string> hostname{};
4320
  // If present, must be valid UTF-8.
4321
  std::optional<std::string> port{};
4322
  // If present, must be valid UTF-8.
4323
  std::optional<std::string> pathname{};
4324
  // If present, must be valid UTF-8.
4325
  std::optional<std::string> search{};
4326
  // If present, must be valid UTF-8.
4327
  std::optional<std::string> hash{};
4328
  // If present, must be valid UTF-8.
4329
  std::optional<std::string> base_url{};
4330
};
4331
}  // namespace ada
4332
#endif  // ADA_INCLUDE_URL_PATTERN
4333
#endif  // ADA_URL_PATTERN_INIT_H
4334
/* end file include/ada/url_pattern_init.h */
4335
4336
/**
4337
 * @private
4338
 */
4339
namespace ada {
4340
struct url_aggregator;
4341
struct url;
4342
#if ADA_INCLUDE_URL_PATTERN
4343
template <url_pattern_regex::regex_concept regex_provider>
4344
class url_pattern;
4345
struct url_pattern_options;
4346
#endif  // ADA_INCLUDE_URL_PATTERN
4347
enum class errors : uint8_t;
4348
}  // namespace ada
4349
4350
/**
4351
 * @namespace ada::parser
4352
 * @brief Includes the definitions for supported parsers
4353
 */
4354
namespace ada::parser {
4355
/**
4356
 * Parses a url. The parameter user_input is the input to be parsed:
4357
 * it should be a valid UTF-8 string. The parameter base_url is an optional
4358
 * parameter that can be used to resolve relative URLs. If the base_url is
4359
 * provided, the user_input is resolved against the base_url.
4360
 */
4361
template <typename result_type = url_aggregator>
4362
result_type parse_url(std::string_view user_input,
4363
                      const result_type* base_url = nullptr);
4364
4365
extern template url_aggregator parse_url<url_aggregator>(
4366
    std::string_view user_input, const url_aggregator* base_url);
4367
extern template url parse_url<url>(std::string_view user_input,
4368
                                   const url* base_url);
4369
4370
template <typename result_type = url_aggregator, bool store_values = true>
4371
result_type parse_url_impl(std::string_view user_input,
4372
                           const result_type* base_url = nullptr);
4373
4374
extern template url_aggregator parse_url_impl<url_aggregator>(
4375
    std::string_view user_input, const url_aggregator* base_url);
4376
extern template url parse_url_impl<url>(std::string_view user_input,
4377
                                        const url* base_url);
4378
4379
#if ADA_INCLUDE_URL_PATTERN
4380
template <url_pattern_regex::regex_concept regex_provider>
4381
tl::expected<url_pattern<regex_provider>, errors> parse_url_pattern_impl(
4382
    std::variant<std::string_view, url_pattern_init>&& input,
4383
    const std::string_view* base_url, const url_pattern_options* options);
4384
#endif  // ADA_INCLUDE_URL_PATTERN
4385
4386
}  // namespace ada::parser
4387
4388
#endif  // ADA_PARSER_H
4389
/* end file include/ada/parser.h */
4390
/* begin file include/ada/parser-inl.h */
4391
/**
4392
 * @file parser-inl.h
4393
 */
4394
#ifndef ADA_PARSER_INL_H
4395
#define ADA_PARSER_INL_H
4396
4397
/* begin file include/ada/url_pattern.h */
4398
/**
4399
 * @file url_pattern.h
4400
 * @brief Declaration for the URLPattern implementation.
4401
 */
4402
#ifndef ADA_URL_PATTERN_H
4403
#define ADA_URL_PATTERN_H
4404
4405
/* begin file include/ada/implementation.h */
4406
/**
4407
 * @file implementation.h
4408
 * @brief Definitions for user facing functions for parsing URL and it's
4409
 * components.
4410
 */
4411
#ifndef ADA_IMPLEMENTATION_H
4412
#define ADA_IMPLEMENTATION_H
4413
4414
#include <string>
4415
#include <string_view>
4416
#include <optional>
4417
4418
/* begin file include/ada/url.h */
4419
/**
4420
 * @file url.h
4421
 * @brief Declaration for the URL
4422
 */
4423
#ifndef ADA_URL_H
4424
#define ADA_URL_H
4425
4426
#include <algorithm>
4427
#include <optional>
4428
#include <ostream>
4429
#include <string>
4430
#include <string_view>
4431
4432
/* begin file include/ada/checkers.h */
4433
/**
4434
 * @file checkers.h
4435
 * @brief Declarations for URL specific checkers used within Ada.
4436
 */
4437
#ifndef ADA_CHECKERS_H
4438
#define ADA_CHECKERS_H
4439
4440
4441
#include <cstring>
4442
#include <string_view>
4443
4444
/**
4445
 * These functions are not part of our public API and may
4446
 * change at any time.
4447
 * @private
4448
 * @namespace ada::checkers
4449
 * @brief Includes the definitions for validation functions
4450
 */
4451
namespace ada::checkers {
4452
4453
/**
4454
 * @private
4455
 * Assuming that x is an ASCII letter, this function returns the lower case
4456
 * equivalent.
4457
 * @details More likely to be inlined by the compiler and constexpr.
4458
 */
4459
constexpr char to_lower(char x) noexcept;
4460
4461
/**
4462
 * @private
4463
 * Returns true if the character is an ASCII letter. Equivalent to std::isalpha
4464
 * but more likely to be inlined by the compiler.
4465
 *
4466
 * @attention std::isalpha is not constexpr generally.
4467
 */
4468
constexpr bool is_alpha(char x) noexcept;
4469
4470
/**
4471
 * @private
4472
 * Check whether a string starts with 0x or 0X. The function is only
4473
 * safe if input.size() >=2.
4474
 *
4475
 * @see has_hex_prefix
4476
 */
4477
constexpr bool has_hex_prefix_unsafe(std::string_view input);
4478
/**
4479
 * @private
4480
 * Check whether a string starts with 0x or 0X.
4481
 */
4482
constexpr bool has_hex_prefix(std::string_view input);
4483
4484
/**
4485
 * @private
4486
 * Check whether x is an ASCII digit. More likely to be inlined than
4487
 * std::isdigit.
4488
 */
4489
constexpr bool is_digit(char x) noexcept;
4490
4491
/**
4492
 * @private
4493
 * @details A string starts with a Windows drive letter if all of the following
4494
 * are true:
4495
 *
4496
 *   - its length is greater than or equal to 2
4497
 *   - its first two code points are a Windows drive letter
4498
 *   - its length is 2 or its third code point is U+002F (/), U+005C (\), U+003F
4499
 * (?), or U+0023 (#).
4500
 *
4501
 * https://url.spec.whatwg.org/#start-with-a-windows-drive-letter
4502
 */
4503
inline constexpr bool is_windows_drive_letter(std::string_view input) noexcept;
4504
4505
/**
4506
 * @private
4507
 * @details A normalized Windows drive letter is a Windows drive letter of which
4508
 * the second code point is U+003A (:).
4509
 */
4510
inline constexpr bool is_normalized_windows_drive_letter(
4511
    std::string_view input) noexcept;
4512
4513
/**
4514
 * @private
4515
 * Returns true if an input is an ipv4 address. It is assumed that the string
4516
 * does not contain uppercase ASCII characters (the input should have been
4517
 * lowered cased before calling this function) and is not empty.
4518
 */
4519
ada_really_inline constexpr bool is_ipv4(std::string_view view) noexcept;
4520
4521
/**
4522
 * @private
4523
 * Returns a bitset. If the first bit is set, then at least one character needs
4524
 * percent encoding. If the second bit is set, a \\ is found. If the third bit
4525
 * is set then we have a dot. If the fourth bit is set, then we have a percent
4526
 * character.
4527
 */
4528
ada_really_inline constexpr uint8_t path_signature(
4529
    std::string_view input) noexcept;
4530
4531
/**
4532
 * @private
4533
 * Returns true if the length of the domain name and its labels are according to
4534
 * the specifications. The length of the domain must be 255 octets (253
4535
 * characters not including the last 2 which are the empty label reserved at the
4536
 * end). When the empty label is included (a dot at the end), the domain name
4537
 * can have 254 characters. The length of a label must be at least 1 and at most
4538
 * 63 characters.
4539
 * @see section 3.1. of https://www.rfc-editor.org/rfc/rfc1034
4540
 * @see https://www.unicode.org/reports/tr46/#ToASCII
4541
 */
4542
ada_really_inline constexpr bool verify_dns_length(
4543
    std::string_view input) noexcept;
4544
4545
}  // namespace ada::checkers
4546
4547
#endif  // ADA_CHECKERS_H
4548
/* end file include/ada/checkers.h */
4549
/* begin file include/ada/url_components.h */
4550
/**
4551
 * @file url_components.h
4552
 * @brief Declaration for the URL Components
4553
 */
4554
#ifndef ADA_URL_COMPONENTS_H
4555
#define ADA_URL_COMPONENTS_H
4556
4557
namespace ada {
4558
4559
/**
4560
 * @brief URL Component representations using offsets.
4561
 *
4562
 * @details We design the url_components struct so that it is as small
4563
 * and simple as possible. This version uses 32 bytes.
4564
 *
4565
 * This struct is used to extract components from a single 'href'.
4566
 */
4567
struct url_components {
4568
  constexpr static uint32_t omitted = uint32_t(-1);
4569
4570
0
  url_components() = default;
4571
  url_components(const url_components &u) = default;
4572
  url_components(url_components &&u) noexcept = default;
4573
  url_components &operator=(url_components &&u) noexcept = default;
4574
  url_components &operator=(const url_components &u) = default;
4575
  ~url_components() = default;
4576
4577
  /*
4578
   * By using 32-bit integers, we implicitly assume that the URL string
4579
   * cannot exceed 4 GB.
4580
   *
4581
   * https://user:pass@example.com:1234/foo/bar?baz#quux
4582
   *       |     |    |          | ^^^^|       |   |
4583
   *       |     |    |          | |   |       |   `----- hash_start
4584
   *       |     |    |          | |   |       `--------- search_start
4585
   *       |     |    |          | |   `----------------- pathname_start
4586
   *       |     |    |          | `--------------------- port
4587
   *       |     |    |          `----------------------- host_end
4588
   *       |     |    `---------------------------------- host_start
4589
   *       |     `--------------------------------------- username_end
4590
   *       `--------------------------------------------- protocol_end
4591
   */
4592
  uint32_t protocol_end{0};
4593
  /**
4594
   * Username end is not `omitted` by default to make username and password
4595
   * getters less costly to implement.
4596
   */
4597
  uint32_t username_end{0};
4598
  uint32_t host_start{0};
4599
  uint32_t host_end{0};
4600
  uint32_t port{omitted};
4601
  uint32_t pathname_start{0};
4602
  uint32_t search_start{omitted};
4603
  uint32_t hash_start{omitted};
4604
4605
  /**
4606
   * Check the following conditions:
4607
   * protocol_end < username_end < ... < hash_start,
4608
   * expect when a value is omitted. It also computes
4609
   * a lower bound on  the possible string length that may match these
4610
   * offsets.
4611
   * @return true if the offset values are
4612
   *  consistent with a possible URL string
4613
   */
4614
  [[nodiscard]] constexpr bool check_offset_consistency() const noexcept;
4615
4616
  /**
4617
   * Converts a url_components to JSON stringified version.
4618
   */
4619
  [[nodiscard]] std::string to_string() const;
4620
4621
};  // struct url_components
4622
}  // namespace ada
4623
#endif
4624
/* end file include/ada/url_components.h */
4625
4626
namespace ada {
4627
4628
struct url_aggregator;
4629
4630
// namespace parser {
4631
// template <typename result_type>
4632
// result_type parse_url(std::string_view user_input,
4633
//                       const result_type* base_url = nullptr);
4634
// template <typename result_type, bool store_values>
4635
// result_type parse_url_impl(std::string_view user_input,
4636
//                            const result_type* base_url = nullptr);
4637
// }
4638
4639
/**
4640
 * @brief Generic URL struct reliant on std::string instantiation.
4641
 *
4642
 * @details To disambiguate from a valid URL string it can also be referred to
4643
 * as a URL record. A URL is a struct that represents a universal identifier.
4644
 * Unlike the url_aggregator, the ada::url represents the different components
4645
 * of a parsed URL as independent std::string instances. This makes the
4646
 * structure heavier and more reliant on memory allocations. When getting
4647
 * components from the parsed URL, a new std::string is typically constructed.
4648
 *
4649
 * @see https://url.spec.whatwg.org/#url-representation
4650
 */
4651
struct url : url_base {
4652
0
  url() = default;
4653
  url(const url &u) = default;
4654
0
  url(url &&u) noexcept = default;
4655
  url &operator=(url &&u) noexcept = default;
4656
0
  url &operator=(const url &u) = default;
4657
0
  ~url() override = default;
4658
4659
  /**
4660
   * @private
4661
   * A URL's username is an ASCII string identifying a username. It is initially
4662
   * the empty string.
4663
   */
4664
  std::string username{};
4665
4666
  /**
4667
   * @private
4668
   * A URL's password is an ASCII string identifying a password. It is initially
4669
   * the empty string.
4670
   */
4671
  std::string password{};
4672
4673
  /**
4674
   * @private
4675
   * A URL's host is null or a host. It is initially null.
4676
   */
4677
  std::optional<std::string> host{};
4678
4679
  /**
4680
   * @private
4681
   * A URL's port is either null or a 16-bit unsigned integer that identifies a
4682
   * networking port. It is initially null.
4683
   */
4684
  std::optional<uint16_t> port{};
4685
4686
  /**
4687
   * @private
4688
   * A URL's path is either an ASCII string or a list of zero or more ASCII
4689
   * strings, usually identifying a location.
4690
   */
4691
  std::string path{};
4692
4693
  /**
4694
   * @private
4695
   * A URL's query is either null or an ASCII string. It is initially null.
4696
   */
4697
  std::optional<std::string> query{};
4698
4699
  /**
4700
   * @private
4701
   * A URL's fragment is either null or an ASCII string that can be used for
4702
   * further processing on the resource the URL's other components identify. It
4703
   * is initially null.
4704
   */
4705
  std::optional<std::string> hash{};
4706
4707
  /** @return true if it has an host but it is the empty string */
4708
  [[nodiscard]] inline bool has_empty_hostname() const noexcept;
4709
  /** @return true if the URL has a (non default) port */
4710
  [[nodiscard]] inline bool has_port() const noexcept;
4711
  /** @return true if it has a host (included an empty host) */
4712
  [[nodiscard]] inline bool has_hostname() const noexcept;
4713
  [[nodiscard]] bool has_valid_domain() const noexcept override;
4714
4715
  /**
4716
   * Returns a JSON string representation of this URL.
4717
   */
4718
  [[nodiscard]] std::string to_string() const override;
4719
4720
  /**
4721
   * @see https://url.spec.whatwg.org/#dom-url-href
4722
   * @see https://url.spec.whatwg.org/#concept-url-serializer
4723
   */
4724
  [[nodiscard]] ada_really_inline std::string get_href() const noexcept;
4725
4726
  /**
4727
   * The origin getter steps are to return the serialization of this's URL's
4728
   * origin. [HTML]
4729
   * @return a newly allocated string.
4730
   * @see https://url.spec.whatwg.org/#concept-url-origin
4731
   */
4732
  [[nodiscard]] std::string get_origin() const noexcept override;
4733
4734
  /**
4735
   * The protocol getter steps are to return this's URL's scheme, followed by
4736
   * U+003A (:).
4737
   * @return a newly allocated string.
4738
   * @see https://url.spec.whatwg.org/#dom-url-protocol
4739
   */
4740
  [[nodiscard]] std::string get_protocol() const noexcept;
4741
4742
  /**
4743
   * Return url's host, serialized, followed by U+003A (:) and url's port,
4744
   * serialized.
4745
   * When there is no host, this function returns the empty string.
4746
   * @return a newly allocated string.
4747
   * @see https://url.spec.whatwg.org/#dom-url-host
4748
   */
4749
  [[nodiscard]] std::string get_host() const noexcept;
4750
4751
  /**
4752
   * Return this's URL's host, serialized.
4753
   * When there is no host, this function returns the empty string.
4754
   * @return a newly allocated string.
4755
   * @see https://url.spec.whatwg.org/#dom-url-hostname
4756
   */
4757
  [[nodiscard]] std::string get_hostname() const noexcept;
4758
4759
  /**
4760
   * The pathname getter steps are to return the result of URL path serializing
4761
   * this's URL.
4762
   * @return a newly allocated string.
4763
   * @see https://url.spec.whatwg.org/#dom-url-pathname
4764
   */
4765
  [[nodiscard]] constexpr std::string_view get_pathname() const noexcept;
4766
4767
  /**
4768
   * Compute the pathname length in bytes without instantiating a view or a
4769
   * string.
4770
   * @return size of the pathname in bytes
4771
   * @see https://url.spec.whatwg.org/#dom-url-pathname
4772
   */
4773
  [[nodiscard]] ada_really_inline size_t get_pathname_length() const noexcept;
4774
4775
  /**
4776
   * Return U+003F (?), followed by this's URL's query.
4777
   * @return a newly allocated string.
4778
   * @see https://url.spec.whatwg.org/#dom-url-search
4779
   */
4780
  [[nodiscard]] std::string get_search() const noexcept;
4781
4782
  /**
4783
   * The username getter steps are to return this's URL's username.
4784
   * @return a constant reference to the underlying string.
4785
   * @see https://url.spec.whatwg.org/#dom-url-username
4786
   */
4787
  [[nodiscard]] const std::string &get_username() const noexcept;
4788
4789
  /**
4790
   * @return Returns true on successful operation.
4791
   * @see https://url.spec.whatwg.org/#dom-url-username
4792
   */
4793
  bool set_username(std::string_view input);
4794
4795
  /**
4796
   * @return Returns true on success.
4797
   * @see https://url.spec.whatwg.org/#dom-url-password
4798
   */
4799
  bool set_password(std::string_view input);
4800
4801
  /**
4802
   * @return Returns true on success.
4803
   * @see https://url.spec.whatwg.org/#dom-url-port
4804
   */
4805
  bool set_port(std::string_view input);
4806
4807
  /**
4808
   * This function always succeeds.
4809
   * @see https://url.spec.whatwg.org/#dom-url-hash
4810
   */
4811
  void set_hash(std::string_view input);
4812
4813
  /**
4814
   * This function always succeeds.
4815
   * @see https://url.spec.whatwg.org/#dom-url-search
4816
   */
4817
  void set_search(std::string_view input);
4818
4819
  /**
4820
   * @return Returns true on success.
4821
   * @see https://url.spec.whatwg.org/#dom-url-search
4822
   */
4823
  bool set_pathname(std::string_view input);
4824
4825
  /**
4826
   * @return Returns true on success.
4827
   * @see https://url.spec.whatwg.org/#dom-url-host
4828
   */
4829
  bool set_host(std::string_view input);
4830
4831
  /**
4832
   * @return Returns true on success.
4833
   * @see https://url.spec.whatwg.org/#dom-url-hostname
4834
   */
4835
  bool set_hostname(std::string_view input);
4836
4837
  /**
4838
   * @return Returns true on success.
4839
   * @see https://url.spec.whatwg.org/#dom-url-protocol
4840
   */
4841
  bool set_protocol(std::string_view input);
4842
4843
  /**
4844
   * @see https://url.spec.whatwg.org/#dom-url-href
4845
   */
4846
  bool set_href(std::string_view input);
4847
4848
  /**
4849
   * The password getter steps are to return this's URL's password.
4850
   * @return a constant reference to the underlying string.
4851
   * @see https://url.spec.whatwg.org/#dom-url-password
4852
   */
4853
  [[nodiscard]] const std::string &get_password() const noexcept;
4854
4855
  /**
4856
   * Return this's URL's port, serialized.
4857
   * @return a newly constructed string representing the port.
4858
   * @see https://url.spec.whatwg.org/#dom-url-port
4859
   */
4860
  [[nodiscard]] std::string get_port() const noexcept;
4861
4862
  /**
4863
   * Return U+0023 (#), followed by this's URL's fragment.
4864
   * @return a newly constructed string representing the hash.
4865
   * @see https://url.spec.whatwg.org/#dom-url-hash
4866
   */
4867
  [[nodiscard]] std::string get_hash() const noexcept;
4868
4869
  /**
4870
   * A URL includes credentials if its username or password is not the empty
4871
   * string.
4872
   */
4873
  [[nodiscard]] ada_really_inline bool has_credentials() const noexcept;
4874
4875
  /**
4876
   * Useful for implementing efficient serialization for the URL.
4877
   *
4878
   * https://user:pass@example.com:1234/foo/bar?baz#quux
4879
   *       |     |    |          | ^^^^|       |   |
4880
   *       |     |    |          | |   |       |   `----- hash_start
4881
   *       |     |    |          | |   |       `--------- search_start
4882
   *       |     |    |          | |   `----------------- pathname_start
4883
   *       |     |    |          | `--------------------- port
4884
   *       |     |    |          `----------------------- host_end
4885
   *       |     |    `---------------------------------- host_start
4886
   *       |     `--------------------------------------- username_end
4887
   *       `--------------------------------------------- protocol_end
4888
   *
4889
   * Inspired after servo/url
4890
   *
4891
   * @return a newly constructed component.
4892
   *
4893
   * @see
4894
   * https://github.com/servo/rust-url/blob/b65a45515c10713f6d212e6726719a020203cc98/url/src/quirks.rs#L31
4895
   */
4896
  [[nodiscard]] ada_really_inline ada::url_components get_components()
4897
      const noexcept;
4898
  /** @return true if the URL has a hash component */
4899
  [[nodiscard]] constexpr bool has_hash() const noexcept override;
4900
  /** @return true if the URL has a search component */
4901
  [[nodiscard]] constexpr bool has_search() const noexcept override;
4902
4903
 private:
4904
  friend ada::url ada::parser::parse_url<ada::url>(std::string_view,
4905
                                                   const ada::url *);
4906
  friend ada::url_aggregator ada::parser::parse_url<ada::url_aggregator>(
4907
      std::string_view, const ada::url_aggregator *);
4908
  friend void ada::helpers::strip_trailing_spaces_from_opaque_path<ada::url>(
4909
      ada::url &url) noexcept;
4910
4911
  friend ada::url ada::parser::parse_url_impl<ada::url, true>(std::string_view,
4912
                                                              const ada::url *);
4913
  friend ada::url_aggregator ada::parser::parse_url_impl<
4914
      ada::url_aggregator, true>(std::string_view, const ada::url_aggregator *);
4915
4916
  inline void update_unencoded_base_hash(std::string_view input);
4917
  inline void update_base_hostname(std::string_view input);
4918
  inline void update_base_search(std::string_view input,
4919
                                 const uint8_t query_percent_encode_set[]);
4920
  inline void update_base_search(std::optional<std::string> &&input);
4921
  inline void update_base_pathname(std::string_view input);
4922
  inline void update_base_username(std::string_view input);
4923
  inline void update_base_password(std::string_view input);
4924
  inline void update_base_port(std::optional<uint16_t> input);
4925
4926
  /**
4927
   * Sets the host or hostname according to override condition.
4928
   * Return true on success.
4929
   * @see https://url.spec.whatwg.org/#hostname-state
4930
   */
4931
  template <bool override_hostname = false>
4932
  bool set_host_or_hostname(std::string_view input);
4933
4934
  /**
4935
   * Return true on success.
4936
   * @see https://url.spec.whatwg.org/#concept-ipv4-parser
4937
   */
4938
  [[nodiscard]] bool parse_ipv4(std::string_view input);
4939
4940
  /**
4941
   * Return true on success.
4942
   * @see https://url.spec.whatwg.org/#concept-ipv6-parser
4943
   */
4944
  [[nodiscard]] bool parse_ipv6(std::string_view input);
4945
4946
  /**
4947
   * Return true on success.
4948
   * @see https://url.spec.whatwg.org/#concept-opaque-host-parser
4949
   */
4950
  [[nodiscard]] bool parse_opaque_host(std::string_view input);
4951
4952
  /**
4953
   * A URL's scheme is an ASCII string that identifies the type of URL and can
4954
   * be used to dispatch a URL for further processing after parsing. It is
4955
   * initially the empty string. We only set non_special_scheme when the scheme
4956
   * is non-special, otherwise we avoid constructing string.
4957
   *
4958
   * Special schemes are stored in ada::scheme::details::is_special_list so we
4959
   * typically do not need to store them in each url instance.
4960
   */
4961
  std::string non_special_scheme{};
4962
4963
  /**
4964
   * A URL cannot have a username/password/port if its host is null or the empty
4965
   * string, or its scheme is "file".
4966
   */
4967
  [[nodiscard]] inline bool cannot_have_credentials_or_port() const;
4968
4969
  ada_really_inline size_t parse_port(
4970
      std::string_view view, bool check_trailing_content) noexcept override;
4971
4972
0
  ada_really_inline size_t parse_port(std::string_view view) noexcept override {
4973
0
    return this->parse_port(view, false);
4974
0
  }
4975
4976
  /**
4977
   * Parse the host from the provided input. We assume that
4978
   * the input does not contain spaces or tabs. Control
4979
   * characters and spaces are not trimmed (they should have
4980
   * been removed if needed).
4981
   * Return true on success.
4982
   * @see https://url.spec.whatwg.org/#host-parsing
4983
   */
4984
  [[nodiscard]] ada_really_inline bool parse_host(std::string_view input);
4985
4986
  template <bool has_state_override = false>
4987
  [[nodiscard]] ada_really_inline bool parse_scheme(std::string_view input);
4988
4989
  constexpr void clear_pathname() override;
4990
  constexpr void clear_search() override;
4991
  constexpr void set_protocol_as_file();
4992
4993
  /**
4994
   * Parse the path from the provided input.
4995
   * Return true on success. Control characters not
4996
   * trimmed from the ends (they should have
4997
   * been removed if needed).
4998
   *
4999
   * The input is expected to be UTF-8.
5000
   *
5001
   * @see https://url.spec.whatwg.org/
5002
   */
5003
  ada_really_inline void parse_path(std::string_view input);
5004
5005
  /**
5006
   * Set the scheme for this URL. The provided scheme should be a valid
5007
   * scheme string, be lower-cased, not contain spaces or tabs. It should
5008
   * have no spurious trailing or leading content.
5009
   */
5010
  inline void set_scheme(std::string &&new_scheme) noexcept;
5011
5012
  /**
5013
   * Take the scheme from another URL. The scheme string is moved from the
5014
   * provided url.
5015
   */
5016
  constexpr void copy_scheme(ada::url &&u) noexcept;
5017
5018
  /**
5019
   * Take the scheme from another URL. The scheme string is copied from the
5020
   * provided url.
5021
   */
5022
  constexpr void copy_scheme(const ada::url &u);
5023
5024
};  // struct url
5025
5026
inline std::ostream &operator<<(std::ostream &out, const ada::url &u);
5027
}  // namespace ada
5028
5029
#endif  // ADA_URL_H
5030
/* end file include/ada/url.h */
5031
5032
namespace ada {
5033
5034
template <class result_type = ada::url_aggregator>
5035
using result = tl::expected<result_type, ada::errors>;
5036
5037
/**
5038
 * The URL parser takes a scalar value string input, with an optional null or
5039
 * base URL base (default null). The parser assumes the input is a valid ASCII
5040
 * or UTF-8 string.
5041
 *
5042
 * @param input the string input to analyze (must be valid ASCII or UTF-8)
5043
 * @param base_url the optional URL input to use as a base url.
5044
 * @return a parsed URL.
5045
 */
5046
template <class result_type = ada::url_aggregator>
5047
ada_warn_unused ada::result<result_type> parse(
5048
    std::string_view input, const result_type* base_url = nullptr);
5049
5050
extern template ada::result<url> parse<url>(std::string_view input,
5051
                                            const url* base_url);
5052
extern template ada::result<url_aggregator> parse<url_aggregator>(
5053
    std::string_view input, const url_aggregator* base_url);
5054
5055
/**
5056
 * Verifies whether the URL strings can be parsed. The function assumes
5057
 * that the inputs are valid ASCII or UTF-8 strings.
5058
 * @see https://url.spec.whatwg.org/#dom-url-canparse
5059
 * @return If URL can be parsed or not.
5060
 */
5061
bool can_parse(std::string_view input,
5062
               const std::string_view* base_input = nullptr);
5063
5064
#if ADA_INCLUDE_URL_PATTERN
5065
/**
5066
 * Implementation of the URL pattern parsing algorithm.
5067
 * @see https://urlpattern.spec.whatwg.org
5068
 *
5069
 * @param input valid UTF-8 string or URLPatternInit struct
5070
 * @param base_url an optional valid UTF-8 string
5071
 * @param options an optional url_pattern_options struct
5072
 * @return url_pattern instance
5073
 */
5074
template <url_pattern_regex::regex_concept regex_provider>
5075
ada_warn_unused tl::expected<url_pattern<regex_provider>, errors>
5076
parse_url_pattern(std::variant<std::string_view, url_pattern_init>&& input,
5077
                  const std::string_view* base_url = nullptr,
5078
                  const url_pattern_options* options = nullptr);
5079
#endif  // ADA_INCLUDE_URL_PATTERN
5080
5081
/**
5082
 * Computes a href string from a file path. The function assumes
5083
 * that the input is a valid ASCII or UTF-8 string.
5084
 * @return a href string (starts with file:://)
5085
 */
5086
std::string href_from_file(std::string_view path);
5087
}  // namespace ada
5088
5089
#endif  // ADA_IMPLEMENTATION_H
5090
/* end file include/ada/implementation.h */
5091
5092
#include <ostream>
5093
#include <string>
5094
#include <string_view>
5095
#include <unordered_map>
5096
#include <variant>
5097
#include <vector>
5098
5099
#if ADA_TESTING
5100
#include <iostream>
5101
#endif  // ADA_TESTING
5102
5103
#if ADA_INCLUDE_URL_PATTERN
5104
namespace ada {
5105
5106
enum class url_pattern_part_type : uint8_t {
5107
  // The part represents a simple fixed text string.
5108
  FIXED_TEXT,
5109
  // The part represents a matching group with a custom regular expression.
5110
  REGEXP,
5111
  // The part represents a matching group that matches code points up to the
5112
  // next separator code point. This is typically used for a named group like
5113
  // ":foo" that does not have a custom regular expression.
5114
  SEGMENT_WILDCARD,
5115
  // The part represents a matching group that greedily matches all code points.
5116
  // This is typically used for the "*" wildcard matching group.
5117
  FULL_WILDCARD,
5118
};
5119
5120
enum class url_pattern_part_modifier : uint8_t {
5121
  // The part does not have a modifier.
5122
  none,
5123
  // The part has an optional modifier indicated by the U+003F (?) code point.
5124
  optional,
5125
  // The part has a "zero or more" modifier indicated by the U+002A (*) code
5126
  // point.
5127
  zero_or_more,
5128
  // The part has a "one or more" modifier indicated by the U+002B (+) code
5129
  // point.
5130
  one_or_more,
5131
};
5132
5133
// @see https://urlpattern.spec.whatwg.org/#part
5134
class url_pattern_part {
5135
 public:
5136
  url_pattern_part(url_pattern_part_type _type, std::string&& _value,
5137
                   url_pattern_part_modifier _modifier)
5138
0
      : type(_type), value(std::move(_value)), modifier(_modifier) {}
5139
5140
  url_pattern_part(url_pattern_part_type _type, std::string&& _value,
5141
                   url_pattern_part_modifier _modifier, std::string&& _name,
5142
                   std::string&& _prefix, std::string&& _suffix)
5143
      : type(_type),
5144
        value(std::move(_value)),
5145
        modifier(_modifier),
5146
        name(std::move(_name)),
5147
        prefix(std::move(_prefix)),
5148
0
        suffix(std::move(_suffix)) {}
5149
  // A part has an associated type, a string, which must be set upon creation.
5150
  url_pattern_part_type type;
5151
  // A part has an associated value, a string, which must be set upon creation.
5152
  std::string value;
5153
  // A part has an associated modifier a string, which must be set upon
5154
  // creation.
5155
  url_pattern_part_modifier modifier;
5156
  // A part has an associated name, a string, initially the empty string.
5157
  std::string name{};
5158
  // A part has an associated prefix, a string, initially the empty string.
5159
  std::string prefix{};
5160
  // A part has an associated suffix, a string, initially the empty string.
5161
  std::string suffix{};
5162
5163
  inline bool is_regexp() const noexcept;
5164
};
5165
5166
// @see https://urlpattern.spec.whatwg.org/#options-header
5167
struct url_pattern_compile_component_options {
5168
  url_pattern_compile_component_options() = default;
5169
  explicit url_pattern_compile_component_options(
5170
      std::optional<char> new_delimiter = std::nullopt,
5171
      std::optional<char> new_prefix = std::nullopt)
5172
6
      : delimiter(new_delimiter), prefix(new_prefix) {}
5173
5174
  inline std::string_view get_delimiter() const ada_warn_unused;
5175
  inline std::string_view get_prefix() const ada_warn_unused;
5176
5177
  // @see https://urlpattern.spec.whatwg.org/#options-ignore-case
5178
  bool ignore_case = false;
5179
5180
  static url_pattern_compile_component_options DEFAULT;
5181
  static url_pattern_compile_component_options HOSTNAME;
5182
  static url_pattern_compile_component_options PATHNAME;
5183
5184
 private:
5185
  // @see https://urlpattern.spec.whatwg.org/#options-delimiter-code-point
5186
  std::optional<char> delimiter{};
5187
  // @see https://urlpattern.spec.whatwg.org/#options-prefix-code-point
5188
  std::optional<char> prefix{};
5189
};
5190
5191
// The default options is an options struct with delimiter code point set to
5192
// the empty string and prefix code point set to the empty string.
5193
inline url_pattern_compile_component_options
5194
    url_pattern_compile_component_options::DEFAULT(std::nullopt, std::nullopt);
5195
5196
// The hostname options is an options struct with delimiter code point set
5197
// "." and prefix code point set to the empty string.
5198
inline url_pattern_compile_component_options
5199
    url_pattern_compile_component_options::HOSTNAME('.', std::nullopt);
5200
5201
// The pathname options is an options struct with delimiter code point set
5202
// "/" and prefix code point set to "/".
5203
inline url_pattern_compile_component_options
5204
    url_pattern_compile_component_options::PATHNAME('/', '/');
5205
5206
// A struct providing the URLPattern matching results for a single
5207
// URL component. The URLPatternComponentResult is only ever used
5208
// as a member attribute of a URLPatternResult struct. The
5209
// URLPatternComponentResult API is defined as part of the URLPattern
5210
// specification.
5211
struct url_pattern_component_result {
5212
  std::string input;
5213
  std::unordered_map<std::string, std::optional<std::string>> groups;
5214
5215
  bool operator==(const url_pattern_component_result&) const;
5216
5217
#if ADA_TESTING
5218
  friend void PrintTo(const url_pattern_component_result& result,
5219
                      std::ostream* os) {
5220
    *os << "input: '" << result.input << "', group: ";
5221
    for (const auto& group : result.groups) {
5222
      *os << "(" << group.first << ", " << group.second.value_or("undefined")
5223
          << ") ";
5224
    }
5225
  }
5226
#endif  // ADA_TESTING
5227
};
5228
5229
template <url_pattern_regex::regex_concept regex_provider>
5230
class url_pattern_component {
5231
 public:
5232
  url_pattern_component() = default;
5233
5234
  // This function explicitly takes a std::string because it is moved.
5235
  // To avoid unnecessary copy, move each value while calling the constructor.
5236
  url_pattern_component(std::string&& new_pattern,
5237
                        typename regex_provider::regex_type&& new_regexp,
5238
                        std::vector<std::string>&& new_group_name_list,
5239
                        bool new_has_regexp_groups)
5240
      : regexp(std::move(new_regexp)),
5241
        pattern(std::move(new_pattern)),
5242
        group_name_list(std::move(new_group_name_list)),
5243
        has_regexp_groups(new_has_regexp_groups) {}
5244
5245
  // @see https://urlpattern.spec.whatwg.org/#compile-a-component
5246
  template <url_pattern_encoding_callback F>
5247
  static tl::expected<url_pattern_component, errors> compile(
5248
      std::string_view input, F& encoding_callback,
5249
      url_pattern_compile_component_options& options);
5250
5251
  // @see https://urlpattern.spec.whatwg.org/#create-a-component-match-result
5252
  url_pattern_component_result create_component_match_result(
5253
      std::string&& input,
5254
      std::vector<std::optional<std::string>>&& exec_result);
5255
5256
#if ADA_TESTING
5257
  friend void PrintTo(const url_pattern_component& component,
5258
                      std::ostream* os) {
5259
    *os << "pattern: '" << component.pattern
5260
        << "', has_regexp_groups: " << component.has_regexp_groups
5261
        << "group_name_list: ";
5262
    for (const auto& name : component.group_name_list) {
5263
      *os << name << ", ";
5264
    }
5265
  }
5266
#endif  // ADA_TESTING
5267
5268
  typename regex_provider::regex_type regexp{};
5269
  std::string pattern{};
5270
  std::vector<std::string> group_name_list{};
5271
  bool has_regexp_groups = false;
5272
};
5273
5274
// A URLPattern input can be either a string or a URLPatternInit object.
5275
// If it is a string, it must be a valid UTF-8 string.
5276
using url_pattern_input = std::variant<std::string_view, url_pattern_init>;
5277
5278
// A struct providing the URLPattern matching results for all
5279
// components of a URL. The URLPatternResult API is defined as
5280
// part of the URLPattern specification.
5281
struct url_pattern_result {
5282
  std::vector<url_pattern_input> inputs;
5283
  url_pattern_component_result protocol;
5284
  url_pattern_component_result username;
5285
  url_pattern_component_result password;
5286
  url_pattern_component_result hostname;
5287
  url_pattern_component_result port;
5288
  url_pattern_component_result pathname;
5289
  url_pattern_component_result search;
5290
  url_pattern_component_result hash;
5291
};
5292
5293
struct url_pattern_options {
5294
  bool ignore_case = false;
5295
5296
#if ADA_TESTING
5297
  friend void PrintTo(const url_pattern_options& options, std::ostream* os) {
5298
    *os << "ignore_case: '" << options.ignore_case;
5299
  }
5300
#endif  // ADA_TESTING
5301
};
5302
5303
// URLPattern is a Web Platform standard API for matching URLs against a
5304
// pattern syntax (think of it as a regular expression for URLs). It is
5305
// defined in https://wicg.github.io/urlpattern.
5306
// More information about the URL Pattern syntax can be found at
5307
// https://developer.mozilla.org/en-US/docs/Web/API/URL_Pattern_API
5308
//
5309
// We require all strings to be valid UTF-8: it is the user's responsibility
5310
// to ensure that the provided strings are valid UTF-8.
5311
template <url_pattern_regex::regex_concept regex_provider>
5312
class url_pattern {
5313
 public:
5314
  url_pattern() = default;
5315
5316
  /**
5317
   * If non-null, base_url must pointer at a valid UTF-8 string.
5318
   * @see https://urlpattern.spec.whatwg.org/#dom-urlpattern-exec
5319
   */
5320
  result<std::optional<url_pattern_result>> exec(
5321
      const url_pattern_input& input,
5322
      const std::string_view* base_url = nullptr);
5323
5324
  /**
5325
   * If non-null, base_url must pointer at a valid UTF-8 string.
5326
   * @see https://urlpattern.spec.whatwg.org/#dom-urlpattern-test
5327
   */
5328
  result<bool> test(const url_pattern_input& input,
5329
                    const std::string_view* base_url = nullptr);
5330
5331
  /**
5332
   * @see https://urlpattern.spec.whatwg.org/#url-pattern-match
5333
   * This function expects a valid UTF-8 string if input is a string.
5334
   */
5335
  result<std::optional<url_pattern_result>> match(
5336
      const url_pattern_input& input,
5337
      const std::string_view* base_url_string = nullptr);
5338
5339
  // @see https://urlpattern.spec.whatwg.org/#dom-urlpattern-protocol
5340
  [[nodiscard]] std::string_view get_protocol() const ada_lifetime_bound;
5341
  // @see https://urlpattern.spec.whatwg.org/#dom-urlpattern-username
5342
  [[nodiscard]] std::string_view get_username() const ada_lifetime_bound;
5343
  // @see https://urlpattern.spec.whatwg.org/#dom-urlpattern-password
5344
  [[nodiscard]] std::string_view get_password() const ada_lifetime_bound;
5345
  // @see https://urlpattern.spec.whatwg.org/#dom-urlpattern-hostname
5346
  [[nodiscard]] std::string_view get_hostname() const ada_lifetime_bound;
5347
  // @see https://urlpattern.spec.whatwg.org/#dom-urlpattern-port
5348
  [[nodiscard]] std::string_view get_port() const ada_lifetime_bound;
5349
  // @see https://urlpattern.spec.whatwg.org/#dom-urlpattern-pathname
5350
  [[nodiscard]] std::string_view get_pathname() const ada_lifetime_bound;
5351
  // @see https://urlpattern.spec.whatwg.org/#dom-urlpattern-search
5352
  [[nodiscard]] std::string_view get_search() const ada_lifetime_bound;
5353
  // @see https://urlpattern.spec.whatwg.org/#dom-urlpattern-hash
5354
  [[nodiscard]] std::string_view get_hash() const ada_lifetime_bound;
5355
5356
  // If ignoreCase is true, the JavaScript regular expression created for each
5357
  // pattern must use the `vi` flag. Otherwise, they must use the `v` flag.
5358
  [[nodiscard]] bool ignore_case() const;
5359
5360
  // @see https://urlpattern.spec.whatwg.org/#url-pattern-has-regexp-groups
5361
  [[nodiscard]] bool has_regexp_groups() const;
5362
5363
#if ADA_TESTING
5364
  friend void PrintTo(const url_pattern& c, std::ostream* os) {
5365
    *os << "protocol_component: '" << c.get_protocol() << ", ";
5366
    *os << "username_component: '" << c.get_username() << ", ";
5367
    *os << "password_component: '" << c.get_password() << ", ";
5368
    *os << "hostname_component: '" << c.get_hostname() << ", ";
5369
    *os << "port_component: '" << c.get_port() << ", ";
5370
    *os << "pathname_component: '" << c.get_pathname() << ", ";
5371
    *os << "search_component: '" << c.get_search() << ", ";
5372
    *os << "hash_component: '" << c.get_hash();
5373
  }
5374
#endif  // ADA_TESTING
5375
5376
  template <url_pattern_regex::regex_concept P>
5377
  friend tl::expected<url_pattern<P>, errors> parser::parse_url_pattern_impl(
5378
      std::variant<std::string_view, url_pattern_init>&& input,
5379
      const std::string_view* base_url, const url_pattern_options* options);
5380
5381
  /**
5382
   * @private
5383
   * We can not make this private due to a LLVM bug.
5384
   * Ref: https://github.com/ada-url/ada/pull/859
5385
   */
5386
  url_pattern_component<regex_provider> protocol_component{};
5387
  /**
5388
   * @private
5389
   * We can not make this private due to a LLVM bug.
5390
   * Ref: https://github.com/ada-url/ada/pull/859
5391
   */
5392
  url_pattern_component<regex_provider> username_component{};
5393
  /**
5394
   * @private
5395
   * We can not make this private due to a LLVM bug.
5396
   * Ref: https://github.com/ada-url/ada/pull/859
5397
   */
5398
  url_pattern_component<regex_provider> password_component{};
5399
  /**
5400
   * @private
5401
   * We can not make this private due to a LLVM bug.
5402
   * Ref: https://github.com/ada-url/ada/pull/859
5403
   */
5404
  url_pattern_component<regex_provider> hostname_component{};
5405
  /**
5406
   * @private
5407
   * We can not make this private due to a LLVM bug.
5408
   * Ref: https://github.com/ada-url/ada/pull/859
5409
   */
5410
  url_pattern_component<regex_provider> port_component{};
5411
  /**
5412
   * @private
5413
   * We can not make this private due to a LLVM bug.
5414
   * Ref: https://github.com/ada-url/ada/pull/859
5415
   */
5416
  url_pattern_component<regex_provider> pathname_component{};
5417
  /**
5418
   * @private
5419
   * We can not make this private due to a LLVM bug.
5420
   * Ref: https://github.com/ada-url/ada/pull/859
5421
   */
5422
  url_pattern_component<regex_provider> search_component{};
5423
  /**
5424
   * @private
5425
   * We can not make this private due to a LLVM bug.
5426
   * Ref: https://github.com/ada-url/ada/pull/859
5427
   */
5428
  url_pattern_component<regex_provider> hash_component{};
5429
  /**
5430
   * @private
5431
   * We can not make this private due to a LLVM bug.
5432
   * Ref: https://github.com/ada-url/ada/pull/859
5433
   */
5434
  bool ignore_case_ = false;
5435
};
5436
}  // namespace ada
5437
#endif  // ADA_INCLUDE_URL_PATTERN
5438
#endif
5439
/* end file include/ada/url_pattern.h */
5440
/* begin file include/ada/url_pattern_helpers.h */
5441
/**
5442
 * @file url_pattern_helpers.h
5443
 * @brief Declaration for the URLPattern helpers.
5444
 */
5445
#ifndef ADA_URL_PATTERN_HELPERS_H
5446
#define ADA_URL_PATTERN_HELPERS_H
5447
5448
5449
#include <string>
5450
#include <tuple>
5451
#include <vector>
5452
5453
#if ADA_INCLUDE_URL_PATTERN
5454
namespace ada {
5455
enum class errors : uint8_t;
5456
}
5457
5458
namespace ada::url_pattern_helpers {
5459
5460
// @see https://urlpattern.spec.whatwg.org/#token
5461
enum class token_type : uint8_t {
5462
  INVALID_CHAR,    // 0
5463
  OPEN,            // 1
5464
  CLOSE,           // 2
5465
  REGEXP,          // 3
5466
  NAME,            // 4
5467
  CHAR,            // 5
5468
  ESCAPED_CHAR,    // 6
5469
  OTHER_MODIFIER,  // 7
5470
  ASTERISK,        // 8
5471
  END,             // 9
5472
};
5473
5474
#ifdef ADA_TESTING
5475
std::string to_string(token_type type);
5476
#endif  // ADA_TESTING
5477
5478
// @see https://urlpattern.spec.whatwg.org/#tokenize-policy
5479
enum class token_policy {
5480
  strict,
5481
  lenient,
5482
};
5483
5484
// @see https://urlpattern.spec.whatwg.org/#tokens
5485
class token {
5486
 public:
5487
  token(token_type _type, size_t _index, std::string&& _value)
5488
0
      : type(_type), index(_index), value(std::move(_value)) {}
5489
5490
  // A token has an associated type, a string, initially "invalid-char".
5491
  token_type type = token_type::INVALID_CHAR;
5492
5493
  // A token has an associated index, a number, initially 0. It is the position
5494
  // of the first code point in the pattern string represented by the token.
5495
  size_t index = 0;
5496
5497
  // A token has an associated value, a string, initially the empty string. It
5498
  // contains the code points from the pattern string represented by the token.
5499
  std::string value{};
5500
};
5501
5502
// @see https://urlpattern.spec.whatwg.org/#pattern-parser
5503
template <url_pattern_encoding_callback F>
5504
class url_pattern_parser {
5505
 public:
5506
  url_pattern_parser(F& encoding_callback_,
5507
                     std::string_view segment_wildcard_regexp_)
5508
      : encoding_callback(encoding_callback_),
5509
        segment_wildcard_regexp(segment_wildcard_regexp_) {}
5510
5511
  bool can_continue() const { return index < tokens.size(); }
5512
5513
  // @see https://urlpattern.spec.whatwg.org/#try-to-consume-a-token
5514
  token* try_consume_token(token_type type);
5515
  // @see https://urlpattern.spec.whatwg.org/#try-to-consume-a-modifier-token
5516
  token* try_consume_modifier_token();
5517
  // @see
5518
  // https://urlpattern.spec.whatwg.org/#try-to-consume-a-regexp-or-wildcard-token
5519
  token* try_consume_regexp_or_wildcard_token(const token* name_token);
5520
  // @see https://urlpattern.spec.whatwg.org/#consume-text
5521
  std::string consume_text();
5522
  // @see https://urlpattern.spec.whatwg.org/#consume-a-required-token
5523
  bool consume_required_token(token_type type);
5524
  // @see
5525
  // https://urlpattern.spec.whatwg.org/#maybe-add-a-part-from-the-pending-fixed-value
5526
  std::optional<errors> maybe_add_part_from_the_pending_fixed_value()
5527
      ada_warn_unused;
5528
  // @see https://urlpattern.spec.whatwg.org/#add-a-part
5529
  std::optional<errors> add_part(std::string_view prefix, token* name_token,
5530
                                 token* regexp_or_wildcard_token,
5531
                                 std::string_view suyffix,
5532
                                 token* modifier_token) ada_warn_unused;
5533
5534
  std::vector<token> tokens{};
5535
  F& encoding_callback;
5536
  std::string segment_wildcard_regexp;
5537
  std::vector<url_pattern_part> parts{};
5538
  std::string pending_fixed_value{};
5539
  size_t index = 0;
5540
  size_t next_numeric_name = 0;
5541
};
5542
5543
// @see https://urlpattern.spec.whatwg.org/#tokenizer
5544
class Tokenizer {
5545
 public:
5546
  explicit Tokenizer(std::string_view new_input, token_policy new_policy)
5547
0
      : input(new_input), policy(new_policy) {}
5548
5549
  // @see https://urlpattern.spec.whatwg.org/#get-the-next-code-point
5550
  constexpr void get_next_code_point();
5551
5552
  // @see https://urlpattern.spec.whatwg.org/#seek-and-get-the-next-code-point
5553
  constexpr void seek_and_get_next_code_point(size_t index);
5554
5555
  // @see https://urlpattern.spec.whatwg.org/#add-a-token
5556
5557
  void add_token(token_type type, size_t next_position, size_t value_position,
5558
                 size_t value_length);
5559
5560
  // @see https://urlpattern.spec.whatwg.org/#add-a-token-with-default-length
5561
  void add_token_with_default_length(token_type type, size_t next_position,
5562
                                     size_t value_position);
5563
5564
  // @see
5565
  // https://urlpattern.spec.whatwg.org/#add-a-token-with-default-position-and-length
5566
  void add_token_with_defaults(token_type type);
5567
5568
  // @see https://urlpattern.spec.whatwg.org/#process-a-tokenizing-error
5569
  std::optional<errors> process_tokenizing_error(
5570
      size_t next_position, size_t value_position) ada_warn_unused;
5571
5572
  friend tl::expected<std::vector<token>, errors> tokenize(
5573
      std::string_view input, token_policy policy);
5574
5575
 private:
5576
  // has an associated input, a pattern string, initially the empty string.
5577
  std::string input;
5578
  // has an associated policy, a tokenize policy, initially "strict".
5579
  token_policy policy;
5580
  // has an associated token list, a token list, initially an empty list.
5581
  std::vector<token> token_list{};
5582
  // has an associated index, a number, initially 0.
5583
  size_t index = 0;
5584
  // has an associated next index, a number, initially 0.
5585
  size_t next_index = 0;
5586
  // has an associated code point, a Unicode code point, initially null.
5587
  char32_t code_point{};
5588
};
5589
5590
// @see https://urlpattern.spec.whatwg.org/#constructor-string-parser
5591
template <url_pattern_regex::regex_concept regex_provider>
5592
struct constructor_string_parser {
5593
  explicit constructor_string_parser(std::string_view new_input,
5594
                                     std::vector<token>&& new_token_list)
5595
      : input(new_input), token_list(std::move(new_token_list)) {}
5596
  // @see https://urlpattern.spec.whatwg.org/#parse-a-constructor-string
5597
  static tl::expected<url_pattern_init, errors> parse(std::string_view input);
5598
5599
  // @see https://urlpattern.spec.whatwg.org/#constructor-string-parser-state
5600
  enum class State {
5601
    INIT,
5602
    PROTOCOL,
5603
    AUTHORITY,
5604
    USERNAME,
5605
    PASSWORD,
5606
    HOSTNAME,
5607
    PORT,
5608
    PATHNAME,
5609
    SEARCH,
5610
    HASH,
5611
    DONE,
5612
  };
5613
5614
  // @see
5615
  // https://urlpattern.spec.whatwg.org/#compute-protocol-matches-a-special-scheme-flag
5616
  std::optional<errors> compute_protocol_matches_special_scheme_flag();
5617
5618
 private:
5619
  // @see https://urlpattern.spec.whatwg.org/#rewind
5620
  constexpr void rewind();
5621
5622
  // @see https://urlpattern.spec.whatwg.org/#is-a-hash-prefix
5623
  constexpr bool is_hash_prefix();
5624
5625
  // @see https://urlpattern.spec.whatwg.org/#is-a-search-prefix
5626
  constexpr bool is_search_prefix();
5627
5628
  // @see https://urlpattern.spec.whatwg.org/#change-state
5629
  void change_state(State state, size_t skip);
5630
5631
  // @see https://urlpattern.spec.whatwg.org/#is-a-group-open
5632
  constexpr bool is_group_open() const;
5633
5634
  // @see https://urlpattern.spec.whatwg.org/#is-a-group-close
5635
  constexpr bool is_group_close() const;
5636
5637
  // @see https://urlpattern.spec.whatwg.org/#is-a-protocol-suffix
5638
  constexpr bool is_protocol_suffix() const;
5639
5640
  // @see https://urlpattern.spec.whatwg.org/#next-is-authority-slashes
5641
  constexpr bool next_is_authority_slashes() const;
5642
5643
  // @see https://urlpattern.spec.whatwg.org/#is-an-identity-terminator
5644
  constexpr bool is_an_identity_terminator() const;
5645
5646
  // @see https://urlpattern.spec.whatwg.org/#is-a-pathname-start
5647
  constexpr bool is_pathname_start() const;
5648
5649
  // @see https://urlpattern.spec.whatwg.org/#is-a-password-prefix
5650
  constexpr bool is_password_prefix() const;
5651
5652
  // @see https://urlpattern.spec.whatwg.org/#is-an-ipv6-open
5653
  constexpr bool is_an_ipv6_open() const;
5654
5655
  // @see https://urlpattern.spec.whatwg.org/#is-an-ipv6-close
5656
  constexpr bool is_an_ipv6_close() const;
5657
5658
  // @see https://urlpattern.spec.whatwg.org/#is-a-port-prefix
5659
  constexpr bool is_port_prefix() const;
5660
5661
  // @see https://urlpattern.spec.whatwg.org/#is-a-non-special-pattern-char
5662
  constexpr bool is_non_special_pattern_char(size_t index,
5663
                                             uint32_t value) const;
5664
5665
  // @see https://urlpattern.spec.whatwg.org/#get-a-safe-token
5666
  constexpr const token* get_safe_token(size_t index) const;
5667
5668
  // @see https://urlpattern.spec.whatwg.org/#make-a-component-string
5669
  std::string make_component_string();
5670
  // has an associated input, a string, which must be set upon creation.
5671
  std::string input;
5672
  // has an associated token list, a token list, which must be set upon
5673
  // creation.
5674
  std::vector<token> token_list;
5675
  // has an associated result, a URLPatternInit, initially set to a new
5676
  // URLPatternInit.
5677
  url_pattern_init result{};
5678
  // has an associated component start, a number, initially set to 0.
5679
  size_t component_start = 0;
5680
  // has an associated token index, a number, initially set to 0.
5681
  size_t token_index = 0;
5682
  // has an associated token increment, a number, initially set to 1.
5683
  size_t token_increment = 1;
5684
  // has an associated group depth, a number, initially set to 0.
5685
  size_t group_depth = 0;
5686
  // has an associated hostname IPv6 bracket depth, a number, initially set to
5687
  // 0.
5688
  size_t hostname_ipv6_bracket_depth = 0;
5689
  // has an associated protocol matches a special scheme flag, a boolean,
5690
  // initially set to false.
5691
  bool protocol_matches_a_special_scheme_flag = false;
5692
  // has an associated state, a string, initially set to "init".
5693
  State state = State::INIT;
5694
};
5695
5696
// @see https://urlpattern.spec.whatwg.org/#canonicalize-a-protocol
5697
tl::expected<std::string, errors> canonicalize_protocol(std::string_view input);
5698
5699
// @see https://wicg.github.io/urlpattern/#canonicalize-a-username
5700
tl::expected<std::string, errors> canonicalize_username(std::string_view input);
5701
5702
// @see https://wicg.github.io/urlpattern/#canonicalize-a-password
5703
tl::expected<std::string, errors> canonicalize_password(std::string_view input);
5704
5705
// @see https://wicg.github.io/urlpattern/#canonicalize-a-password
5706
tl::expected<std::string, errors> canonicalize_hostname(std::string_view input);
5707
5708
// @see https://wicg.github.io/urlpattern/#canonicalize-an-ipv6-hostname
5709
tl::expected<std::string, errors> canonicalize_ipv6_hostname(
5710
    std::string_view input);
5711
5712
// @see https://wicg.github.io/urlpattern/#canonicalize-a-port
5713
tl::expected<std::string, errors> canonicalize_port(std::string_view input);
5714
5715
// @see https://wicg.github.io/urlpattern/#canonicalize-a-port
5716
tl::expected<std::string, errors> canonicalize_port_with_protocol(
5717
    std::string_view input, std::string_view protocol);
5718
5719
// @see https://wicg.github.io/urlpattern/#canonicalize-a-pathname
5720
tl::expected<std::string, errors> canonicalize_pathname(std::string_view input);
5721
5722
// @see https://wicg.github.io/urlpattern/#canonicalize-an-opaque-pathname
5723
tl::expected<std::string, errors> canonicalize_opaque_pathname(
5724
    std::string_view input);
5725
5726
// @see https://wicg.github.io/urlpattern/#canonicalize-a-search
5727
tl::expected<std::string, errors> canonicalize_search(std::string_view input);
5728
5729
// @see https://wicg.github.io/urlpattern/#canonicalize-a-hash
5730
tl::expected<std::string, errors> canonicalize_hash(std::string_view input);
5731
5732
// @see https://urlpattern.spec.whatwg.org/#tokenize
5733
tl::expected<std::vector<token>, errors> tokenize(std::string_view input,
5734
                                                  token_policy policy);
5735
5736
// @see https://urlpattern.spec.whatwg.org/#process-a-base-url-string
5737
std::string process_base_url_string(std::string_view input,
5738
                                    url_pattern_init::process_type type);
5739
5740
// @see https://urlpattern.spec.whatwg.org/#escape-a-pattern-string
5741
std::string escape_pattern_string(std::string_view input);
5742
5743
// @see https://urlpattern.spec.whatwg.org/#escape-a-regexp-string
5744
std::string escape_regexp_string(std::string_view input);
5745
5746
// @see https://urlpattern.spec.whatwg.org/#is-an-absolute-pathname
5747
constexpr bool is_absolute_pathname(
5748
    std::string_view input, url_pattern_init::process_type type) noexcept;
5749
5750
// @see https://urlpattern.spec.whatwg.org/#parse-a-pattern-string
5751
template <url_pattern_encoding_callback F>
5752
tl::expected<std::vector<url_pattern_part>, errors> parse_pattern_string(
5753
    std::string_view input, url_pattern_compile_component_options& options,
5754
    F& encoding_callback);
5755
5756
// @see https://urlpattern.spec.whatwg.org/#generate-a-pattern-string
5757
std::string generate_pattern_string(
5758
    std::vector<url_pattern_part>& part_list,
5759
    url_pattern_compile_component_options& options);
5760
5761
// @see
5762
// https://urlpattern.spec.whatwg.org/#generate-a-regular-expression-and-name-list
5763
std::tuple<std::string, std::vector<std::string>>
5764
generate_regular_expression_and_name_list(
5765
    const std::vector<url_pattern_part>& part_list,
5766
    url_pattern_compile_component_options options);
5767
5768
// @see https://urlpattern.spec.whatwg.org/#hostname-pattern-is-an-ipv6-address
5769
bool is_ipv6_address(std::string_view input) noexcept;
5770
5771
// @see
5772
// https://urlpattern.spec.whatwg.org/#protocol-component-matches-a-special-scheme
5773
template <url_pattern_regex::regex_concept regex_provider>
5774
bool protocol_component_matches_special_scheme(
5775
    ada::url_pattern_component<regex_provider>& input);
5776
5777
// @see https://urlpattern.spec.whatwg.org/#convert-a-modifier-to-a-string
5778
std::string convert_modifier_to_string(url_pattern_part_modifier modifier);
5779
5780
// @see https://urlpattern.spec.whatwg.org/#generate-a-segment-wildcard-regexp
5781
std::string generate_segment_wildcard_regexp(
5782
    url_pattern_compile_component_options options);
5783
5784
}  // namespace ada::url_pattern_helpers
5785
#endif  // ADA_INCLUDE_URL_PATTERN
5786
#endif
5787
/* end file include/ada/url_pattern_helpers.h */
5788
5789
#include <string>
5790
#include <string_view>
5791
#include <variant>
5792
5793
namespace ada::parser {
5794
#if ADA_INCLUDE_URL_PATTERN
5795
template <url_pattern_regex::regex_concept regex_provider>
5796
tl::expected<url_pattern<regex_provider>, errors> parse_url_pattern_impl(
5797
    std::variant<std::string_view, url_pattern_init>&& input,
5798
    const std::string_view* base_url, const url_pattern_options* options) {
5799
  // Let init be null.
5800
  url_pattern_init init;
5801
5802
  // If input is a scalar value string then:
5803
  if (std::holds_alternative<std::string_view>(input)) {
5804
    // Set init to the result of running parse a constructor string given input.
5805
    auto parse_result =
5806
        url_pattern_helpers::constructor_string_parser<regex_provider>::parse(
5807
            std::get<std::string_view>(input));
5808
    if (!parse_result) {
5809
      ada_log("constructor_string_parser::parse failed");
5810
      return tl::unexpected(parse_result.error());
5811
    }
5812
    init = std::move(*parse_result);
5813
    // If baseURL is null and init["protocol"] does not exist, then throw a
5814
    // TypeError.
5815
    if (!base_url && !init.protocol) {
5816
      ada_log("base url is null and protocol is not set");
5817
      return tl::unexpected(errors::type_error);
5818
    }
5819
5820
    // If baseURL is not null, set init["baseURL"] to baseURL.
5821
    if (base_url) {
5822
      init.base_url = std::string(*base_url);
5823
    }
5824
  } else {
5825
    // Assert: input is a URLPatternInit.
5826
    ADA_ASSERT_TRUE(std::holds_alternative<url_pattern_init>(input));
5827
    // If baseURL is not null, then throw a TypeError.
5828
    if (base_url) {
5829
      ada_log("base url is not null");
5830
      return tl::unexpected(errors::type_error);
5831
    }
5832
    // Optimization: Avoid copy by moving the input value.
5833
    // Set init to input.
5834
    init = std::move(std::get<url_pattern_init>(input));
5835
  }
5836
5837
  // Let processedInit be the result of process a URLPatternInit given init,
5838
  // "pattern", null, null, null, null, null, null, null, and null.
5839
  auto processed_init =
5840
      url_pattern_init::process(init, url_pattern_init::process_type::pattern);
5841
  if (!processed_init) {
5842
    ada_log("url_pattern_init::process failed for init and 'pattern'");
5843
    return tl::unexpected(processed_init.error());
5844
  }
5845
5846
  // For each componentName of  "protocol", "username", "password", "hostname",
5847
  // "port", "pathname", "search", "hash" If processedInit[componentName] does
5848
  // not exist, then set processedInit[componentName] to "*".
5849
  ADA_ASSERT_TRUE(processed_init.has_value());
5850
  if (!processed_init->protocol) processed_init->protocol = "*";
5851
  if (!processed_init->username) processed_init->username = "*";
5852
  if (!processed_init->password) processed_init->password = "*";
5853
  if (!processed_init->hostname) processed_init->hostname = "*";
5854
  if (!processed_init->port) processed_init->port = "*";
5855
  if (!processed_init->pathname) processed_init->pathname = "*";
5856
  if (!processed_init->search) processed_init->search = "*";
5857
  if (!processed_init->hash) processed_init->hash = "*";
5858
5859
  ada_log("-- processed_init->protocol: ", processed_init->protocol.value());
5860
  ada_log("-- processed_init->username: ", processed_init->username.value());
5861
  ada_log("-- processed_init->password: ", processed_init->password.value());
5862
  ada_log("-- processed_init->hostname: ", processed_init->hostname.value());
5863
  ada_log("-- processed_init->port: ", processed_init->port.value());
5864
  ada_log("-- processed_init->pathname: ", processed_init->pathname.value());
5865
  ada_log("-- processed_init->search: ", processed_init->search.value());
5866
  ada_log("-- processed_init->hash: ", processed_init->hash.value());
5867
5868
  // If processedInit["protocol"] is a special scheme and processedInit["port"]
5869
  // is a string which represents its corresponding default port in radix-10
5870
  // using ASCII digits then set processedInit["port"] to the empty string.
5871
  // TODO: Optimization opportunity.
5872
  if (scheme::is_special(*processed_init->protocol)) {
5873
    std::string_view port = processed_init->port.value();
5874
    if (std::to_string(scheme::get_special_port(*processed_init->protocol)) ==
5875
        port) {
5876
      processed_init->port->clear();
5877
    }
5878
  }
5879
5880
  // Let urlPattern be a new URL pattern.
5881
  url_pattern<regex_provider> url_pattern_{};
5882
5883
  // Set urlPattern's protocol component to the result of compiling a component
5884
  // given processedInit["protocol"], canonicalize a protocol, and default
5885
  // options.
5886
  auto protocol_component = url_pattern_component<regex_provider>::compile(
5887
      processed_init->protocol.value(),
5888
      url_pattern_helpers::canonicalize_protocol,
5889
      url_pattern_compile_component_options::DEFAULT);
5890
  if (!protocol_component) {
5891
    ada_log("url_pattern_component::compile failed for protocol ",
5892
            processed_init->protocol.value());
5893
    return tl::unexpected(protocol_component.error());
5894
  }
5895
  url_pattern_.protocol_component = std::move(*protocol_component);
5896
5897
  // Set urlPattern's username component to the result of compiling a component
5898
  // given processedInit["username"], canonicalize a username, and default
5899
  // options.
5900
  auto username_component = url_pattern_component<regex_provider>::compile(
5901
      processed_init->username.value(),
5902
      url_pattern_helpers::canonicalize_username,
5903
      url_pattern_compile_component_options::DEFAULT);
5904
  if (!username_component) {
5905
    ada_log("url_pattern_component::compile failed for username ",
5906
            processed_init->username.value());
5907
    return tl::unexpected(username_component.error());
5908
  }
5909
  url_pattern_.username_component = std::move(*username_component);
5910
5911
  // Set urlPattern's password component to the result of compiling a component
5912
  // given processedInit["password"], canonicalize a password, and default
5913
  // options.
5914
  auto password_component = url_pattern_component<regex_provider>::compile(
5915
      processed_init->password.value(),
5916
      url_pattern_helpers::canonicalize_password,
5917
      url_pattern_compile_component_options::DEFAULT);
5918
  if (!password_component) {
5919
    ada_log("url_pattern_component::compile failed for password ",
5920
            processed_init->password.value());
5921
    return tl::unexpected(password_component.error());
5922
  }
5923
  url_pattern_.password_component = std::move(*password_component);
5924
5925
  // TODO: Optimization opportunity. The following if statement can be
5926
  // simplified.
5927
  // If the result running hostname pattern is an IPv6 address given
5928
  // processedInit["hostname"] is true, then set urlPattern's hostname component
5929
  // to the result of compiling a component given processedInit["hostname"],
5930
  // canonicalize an IPv6 hostname, and hostname options.
5931
  if (url_pattern_helpers::is_ipv6_address(processed_init->hostname.value())) {
5932
    ada_log("processed_init->hostname is ipv6 address");
5933
    // then set urlPattern's hostname component to the result of compiling a
5934
    // component given processedInit["hostname"], canonicalize an IPv6 hostname,
5935
    // and hostname options.
5936
    auto hostname_component = url_pattern_component<regex_provider>::compile(
5937
        processed_init->hostname.value(),
5938
        url_pattern_helpers::canonicalize_ipv6_hostname,
5939
        url_pattern_compile_component_options::DEFAULT);
5940
    if (!hostname_component) {
5941
      ada_log("url_pattern_component::compile failed for ipv6 hostname ",
5942
              processed_init->hostname.value());
5943
      return tl::unexpected(hostname_component.error());
5944
    }
5945
    url_pattern_.hostname_component = std::move(*hostname_component);
5946
  } else {
5947
    // Otherwise, set urlPattern's hostname component to the result of compiling
5948
    // a component given processedInit["hostname"], canonicalize a hostname, and
5949
    // hostname options.
5950
    auto hostname_component = url_pattern_component<regex_provider>::compile(
5951
        processed_init->hostname.value(),
5952
        url_pattern_helpers::canonicalize_hostname,
5953
        url_pattern_compile_component_options::HOSTNAME);
5954
    if (!hostname_component) {
5955
      ada_log("url_pattern_component::compile failed for hostname ",
5956
              processed_init->hostname.value());
5957
      return tl::unexpected(hostname_component.error());
5958
    }
5959
    url_pattern_.hostname_component = std::move(*hostname_component);
5960
  }
5961
5962
  // Set urlPattern's port component to the result of compiling a component
5963
  // given processedInit["port"], canonicalize a port, and default options.
5964
  auto port_component = url_pattern_component<regex_provider>::compile(
5965
      processed_init->port.value(), url_pattern_helpers::canonicalize_port,
5966
      url_pattern_compile_component_options::DEFAULT);
5967
  if (!port_component) {
5968
    ada_log("url_pattern_component::compile failed for port ",
5969
            processed_init->port.value());
5970
    return tl::unexpected(port_component.error());
5971
  }
5972
  url_pattern_.port_component = std::move(*port_component);
5973
5974
  // Let compileOptions be a copy of the default options with the ignore case
5975
  // property set to options["ignoreCase"].
5976
  auto compile_options = url_pattern_compile_component_options::DEFAULT;
5977
  if (options) {
5978
    compile_options.ignore_case = options->ignore_case;
5979
  }
5980
5981
  // TODO: Optimization opportunity: Simplify this if statement.
5982
  // If the result of running protocol component matches a special scheme given
5983
  // urlPattern's protocol component is true, then:
5984
  if (url_pattern_helpers::protocol_component_matches_special_scheme<
5985
          regex_provider>(url_pattern_.protocol_component)) {
5986
    // Let pathCompileOptions be copy of the pathname options with the ignore
5987
    // case property set to options["ignoreCase"].
5988
    auto path_compile_options = url_pattern_compile_component_options::PATHNAME;
5989
    if (options) {
5990
      path_compile_options.ignore_case = options->ignore_case;
5991
    }
5992
5993
    // Set urlPattern's pathname component to the result of compiling a
5994
    // component given processedInit["pathname"], canonicalize a pathname, and
5995
    // pathCompileOptions.
5996
    auto pathname_component = url_pattern_component<regex_provider>::compile(
5997
        processed_init->pathname.value(),
5998
        url_pattern_helpers::canonicalize_pathname, path_compile_options);
5999
    if (!pathname_component) {
6000
      ada_log("url_pattern_component::compile failed for pathname ",
6001
              processed_init->pathname.value());
6002
      return tl::unexpected(pathname_component.error());
6003
    }
6004
    url_pattern_.pathname_component = std::move(*pathname_component);
6005
  } else {
6006
    // Otherwise set urlPattern's pathname component to the result of compiling
6007
    // a component given processedInit["pathname"], canonicalize an opaque
6008
    // pathname, and compileOptions.
6009
    auto pathname_component = url_pattern_component<regex_provider>::compile(
6010
        processed_init->pathname.value(),
6011
        url_pattern_helpers::canonicalize_opaque_pathname, compile_options);
6012
    if (!pathname_component) {
6013
      ada_log("url_pattern_component::compile failed for opaque pathname ",
6014
              processed_init->pathname.value());
6015
      return tl::unexpected(pathname_component.error());
6016
    }
6017
    url_pattern_.pathname_component = std::move(*pathname_component);
6018
  }
6019
6020
  // Set urlPattern's search component to the result of compiling a component
6021
  // given processedInit["search"], canonicalize a search, and compileOptions.
6022
  auto search_component = url_pattern_component<regex_provider>::compile(
6023
      processed_init->search.value(), url_pattern_helpers::canonicalize_search,
6024
      compile_options);
6025
  if (!search_component) {
6026
    ada_log("url_pattern_component::compile failed for search ",
6027
            processed_init->search.value());
6028
    return tl::unexpected(search_component.error());
6029
  }
6030
  url_pattern_.search_component = std::move(*search_component);
6031
6032
  // Set urlPattern's hash component to the result of compiling a component
6033
  // given processedInit["hash"], canonicalize a hash, and compileOptions.
6034
  auto hash_component = url_pattern_component<regex_provider>::compile(
6035
      processed_init->hash.value(), url_pattern_helpers::canonicalize_hash,
6036
      compile_options);
6037
  if (!hash_component) {
6038
    ada_log("url_pattern_component::compile failed for hash ",
6039
            processed_init->hash.value());
6040
    return tl::unexpected(hash_component.error());
6041
  }
6042
  url_pattern_.hash_component = std::move(*hash_component);
6043
6044
  // Return urlPattern.
6045
  return url_pattern_;
6046
}
6047
#endif  // ADA_INCLUDE_URL_PATTERN
6048
6049
}  // namespace ada::parser
6050
6051
#endif  // ADA_PARSER_INL_H
6052
/* end file include/ada/parser-inl.h */
6053
/* begin file include/ada/scheme-inl.h */
6054
/**
6055
 * @file scheme-inl.h
6056
 * @brief Definitions for the URL scheme.
6057
 */
6058
#ifndef ADA_SCHEME_INL_H
6059
#define ADA_SCHEME_INL_H
6060
6061
6062
namespace ada::scheme {
6063
6064
/**
6065
 * @namespace ada::scheme::details
6066
 * @brief Includes the definitions for scheme specific entities
6067
 */
6068
namespace details {
6069
// for use with is_special and get_special_port
6070
// Spaces, if present, are removed from URL.
6071
constexpr std::string_view is_special_list[] = {"http", " ",   "https", "ws",
6072
                                                "ftp",  "wss", "file",  " "};
6073
// for use with get_special_port
6074
constexpr uint16_t special_ports[] = {80, 0, 443, 80, 21, 443, 0, 0};
6075
}  // namespace details
6076
6077
/****
6078
 * @private
6079
 * In is_special, get_scheme_type, and get_special_port, we
6080
 * use a standard hashing technique to find the index of the scheme in
6081
 * the is_special_list. The hashing technique is based on the size of
6082
 * the scheme and the first character of the scheme. It ensures that we
6083
 * do at most one string comparison per call. If the protocol is
6084
 * predictible (e.g., it is always "http"), we can get a better average
6085
 * performance by using a simpler approach where we loop and compare
6086
 * scheme with all possible protocols starting with the most likely
6087
 * protocol. Doing multiple comparisons may have a poor worst case
6088
 * performance, however. In this instance, we choose a potentially
6089
 * slightly lower best-case performance for a better worst-case
6090
 * performance. We can revisit this choice at any time.
6091
 *
6092
 * Reference:
6093
 * Schmidt, Douglas C. "Gperf: A perfect hash function generator."
6094
 * More C++ gems 17 (2000).
6095
 *
6096
 * Reference: https://en.wikipedia.org/wiki/Perfect_hash_function
6097
 *
6098
 * Reference: https://github.com/ada-url/ada/issues/617
6099
 ****/
6100
6101
0
ada_really_inline constexpr bool is_special(std::string_view scheme) {
6102
0
  if (scheme.empty()) {
6103
0
    return false;
6104
0
  }
6105
0
  int hash_value = (2 * scheme.size() + (unsigned)(scheme[0])) & 7;
6106
0
  const std::string_view target = details::is_special_list[hash_value];
6107
0
  return (target[0] == scheme[0]) && (target.substr(1) == scheme.substr(1));
6108
0
}
6109
0
constexpr uint16_t get_special_port(std::string_view scheme) noexcept {
6110
0
  if (scheme.empty()) {
6111
0
    return 0;
6112
0
  }
6113
0
  int hash_value = (2 * scheme.size() + (unsigned)(scheme[0])) & 7;
6114
0
  const std::string_view target = details::is_special_list[hash_value];
6115
0
  if ((target[0] == scheme[0]) && (target.substr(1) == scheme.substr(1))) {
6116
0
    return details::special_ports[hash_value];
6117
0
  } else {
6118
0
    return 0;
6119
0
  }
6120
0
}
6121
0
constexpr uint16_t get_special_port(ada::scheme::type type) noexcept {
6122
0
  return details::special_ports[int(type)];
6123
0
}
6124
0
constexpr ada::scheme::type get_scheme_type(std::string_view scheme) noexcept {
6125
0
  if (scheme.empty()) {
6126
0
    return ada::scheme::NOT_SPECIAL;
6127
0
  }
6128
0
  int hash_value = (2 * scheme.size() + (unsigned)(scheme[0])) & 7;
6129
0
  const std::string_view target = details::is_special_list[hash_value];
6130
0
  if ((target[0] == scheme[0]) && (target.substr(1) == scheme.substr(1))) {
6131
0
    return ada::scheme::type(hash_value);
6132
0
  } else {
6133
0
    return ada::scheme::NOT_SPECIAL;
6134
0
  }
6135
0
}
6136
6137
}  // namespace ada::scheme
6138
6139
#endif  // ADA_SCHEME_INL_H
6140
/* end file include/ada/scheme-inl.h */
6141
/* begin file include/ada/serializers.h */
6142
/**
6143
 * @file serializers.h
6144
 * @brief Definitions for the URL serializers.
6145
 */
6146
#ifndef ADA_SERIALIZERS_H
6147
#define ADA_SERIALIZERS_H
6148
6149
6150
#include <array>
6151
#include <string>
6152
6153
/**
6154
 * @namespace ada::serializers
6155
 * @brief Includes the definitions for URL serializers
6156
 */
6157
namespace ada::serializers {
6158
6159
/**
6160
 * Finds and returns the longest sequence of 0 values in a ipv6 input.
6161
 */
6162
void find_longest_sequence_of_ipv6_pieces(
6163
    const std::array<uint16_t, 8>& address, size_t& compress,
6164
    size_t& compress_length) noexcept;
6165
6166
/**
6167
 * Serializes an ipv6 address.
6168
 * @details An IPv6 address is a 128-bit unsigned integer that identifies a
6169
 * network address.
6170
 * @see https://url.spec.whatwg.org/#concept-ipv6-serializer
6171
 */
6172
std::string ipv6(const std::array<uint16_t, 8>& address) noexcept;
6173
6174
/**
6175
 * Serializes an ipv4 address.
6176
 * @details An IPv4 address is a 32-bit unsigned integer that identifies a
6177
 * network address.
6178
 * @see https://url.spec.whatwg.org/#concept-ipv4-serializer
6179
 */
6180
std::string ipv4(uint64_t address) noexcept;
6181
6182
}  // namespace ada::serializers
6183
6184
#endif  // ADA_SERIALIZERS_H
6185
/* end file include/ada/serializers.h */
6186
/* begin file include/ada/state.h */
6187
/**
6188
 * @file state.h
6189
 * @brief Definitions for the states of the URL state machine.
6190
 */
6191
#ifndef ADA_STATE_H
6192
#define ADA_STATE_H
6193
6194
6195
#include <string>
6196
6197
namespace ada {
6198
6199
/**
6200
 * @see https://url.spec.whatwg.org/#url-parsing
6201
 */
6202
enum class state {
6203
  /**
6204
   * @see https://url.spec.whatwg.org/#authority-state
6205
   */
6206
  AUTHORITY,
6207
6208
  /**
6209
   * @see https://url.spec.whatwg.org/#scheme-start-state
6210
   */
6211
  SCHEME_START,
6212
6213
  /**
6214
   * @see https://url.spec.whatwg.org/#scheme-state
6215
   */
6216
  SCHEME,
6217
6218
  /**
6219
   * @see https://url.spec.whatwg.org/#host-state
6220
   */
6221
  HOST,
6222
6223
  /**
6224
   * @see https://url.spec.whatwg.org/#no-scheme-state
6225
   */
6226
  NO_SCHEME,
6227
6228
  /**
6229
   * @see https://url.spec.whatwg.org/#fragment-state
6230
   */
6231
  FRAGMENT,
6232
6233
  /**
6234
   * @see https://url.spec.whatwg.org/#relative-state
6235
   */
6236
  RELATIVE_SCHEME,
6237
6238
  /**
6239
   * @see https://url.spec.whatwg.org/#relative-slash-state
6240
   */
6241
  RELATIVE_SLASH,
6242
6243
  /**
6244
   * @see https://url.spec.whatwg.org/#file-state
6245
   */
6246
  FILE,
6247
6248
  /**
6249
   * @see https://url.spec.whatwg.org/#file-host-state
6250
   */
6251
  FILE_HOST,
6252
6253
  /**
6254
   * @see https://url.spec.whatwg.org/#file-slash-state
6255
   */
6256
  FILE_SLASH,
6257
6258
  /**
6259
   * @see https://url.spec.whatwg.org/#path-or-authority-state
6260
   */
6261
  PATH_OR_AUTHORITY,
6262
6263
  /**
6264
   * @see https://url.spec.whatwg.org/#special-authority-ignore-slashes-state
6265
   */
6266
  SPECIAL_AUTHORITY_IGNORE_SLASHES,
6267
6268
  /**
6269
   * @see https://url.spec.whatwg.org/#special-authority-slashes-state
6270
   */
6271
  SPECIAL_AUTHORITY_SLASHES,
6272
6273
  /**
6274
   * @see https://url.spec.whatwg.org/#special-relative-or-authority-state
6275
   */
6276
  SPECIAL_RELATIVE_OR_AUTHORITY,
6277
6278
  /**
6279
   * @see https://url.spec.whatwg.org/#query-state
6280
   */
6281
  QUERY,
6282
6283
  /**
6284
   * @see https://url.spec.whatwg.org/#path-state
6285
   */
6286
  PATH,
6287
6288
  /**
6289
   * @see https://url.spec.whatwg.org/#path-start-state
6290
   */
6291
  PATH_START,
6292
6293
  /**
6294
   * @see https://url.spec.whatwg.org/#cannot-be-a-base-url-path-state
6295
   */
6296
  OPAQUE_PATH,
6297
6298
  /**
6299
   * @see https://url.spec.whatwg.org/#port-state
6300
   */
6301
  PORT,
6302
};
6303
6304
/**
6305
 * Stringify a URL state machine state.
6306
 */
6307
ada_warn_unused std::string to_string(ada::state s);
6308
6309
}  // namespace ada
6310
6311
#endif  // ADA_STATE_H
6312
/* end file include/ada/state.h */
6313
/* begin file include/ada/unicode.h */
6314
/**
6315
 * @file unicode.h
6316
 * @brief Definitions for all unicode specific functions.
6317
 */
6318
#ifndef ADA_UNICODE_H
6319
#define ADA_UNICODE_H
6320
6321
6322
#include <string>
6323
#include <string_view>
6324
#include <optional>
6325
6326
/**
6327
 * Unicode operations. These functions are not part of our public API and may
6328
 * change at any time.
6329
 *
6330
 * @private
6331
 * @namespace ada::unicode
6332
 * @brief Includes the definitions for unicode operations
6333
 */
6334
namespace ada::unicode {
6335
6336
/**
6337
 * @private
6338
 * We receive a UTF-8 string representing a domain name.
6339
 * If the string is percent encoded, we apply percent decoding.
6340
 *
6341
 * Given a domain, we need to identify its labels.
6342
 * They are separated by label-separators:
6343
 *
6344
 * U+002E (.) FULL STOP
6345
 * U+FF0E FULLWIDTH FULL STOP
6346
 * U+3002 IDEOGRAPHIC FULL STOP
6347
 * U+FF61 HALFWIDTH IDEOGRAPHIC FULL STOP
6348
 *
6349
 * They are all mapped to U+002E.
6350
 *
6351
 * We process each label into a string that should not exceed 63 octets.
6352
 * If the string is already punycode (starts with "xn--"), then we must
6353
 * scan it to look for unallowed code points.
6354
 * Otherwise, if the string is not pure ASCII, we need to transcode it
6355
 * to punycode by following RFC 3454 which requires us to
6356
 * - Map characters  (see section 3),
6357
 * - Normalize (see section 4),
6358
 * - Reject forbidden characters,
6359
 * - Check for right-to-left characters and if so, check all requirements (see
6360
 * section 6),
6361
 * - Optionally reject based on unassigned code points (section 7).
6362
 *
6363
 * The Unicode standard provides a table of code points with a mapping, a list
6364
 * of forbidden code points and so forth. This table is subject to change and
6365
 * will vary based on the implementation. For Unicode 15, the table is at
6366
 * https://www.unicode.org/Public/idna/15.0.0/IdnaMappingTable.txt
6367
 * If you use ICU, they parse this table and map it to code using a Python
6368
 * script.
6369
 *
6370
 * The resulting strings should not exceed 255 octets according to RFC 1035
6371
 * section 2.3.4. ICU checks for label size and domain size, but these errors
6372
 * are ignored.
6373
 *
6374
 * @see https://url.spec.whatwg.org/#concept-domain-to-ascii
6375
 *
6376
 */
6377
bool to_ascii(std::optional<std::string>& out, std::string_view plain,
6378
              size_t first_percent);
6379
6380
/**
6381
 * @private
6382
 * Checks if the input has tab or newline characters.
6383
 *
6384
 * @attention The has_tabs_or_newline function is a bottleneck and it is simple
6385
 * enough that compilers like GCC can 'autovectorize it'.
6386
 */
6387
ada_really_inline bool has_tabs_or_newline(
6388
    std::string_view user_input) noexcept;
6389
6390
/**
6391
 * @private
6392
 * Checks if the input is a forbidden host code point.
6393
 * @see https://url.spec.whatwg.org/#forbidden-host-code-point
6394
 */
6395
ada_really_inline constexpr bool is_forbidden_host_code_point(char c) noexcept;
6396
6397
/**
6398
 * @private
6399
 * Checks if the input contains a forbidden domain code point.
6400
 * @see https://url.spec.whatwg.org/#forbidden-domain-code-point
6401
 */
6402
ada_really_inline constexpr bool contains_forbidden_domain_code_point(
6403
    const char* input, size_t length) noexcept;
6404
6405
/**
6406
 * @private
6407
 * Checks if the input contains a forbidden domain code point in which case
6408
 * the first bit is set to 1. If the input contains an upper case ASCII letter,
6409
 * then the second bit is set to 1.
6410
 * @see https://url.spec.whatwg.org/#forbidden-domain-code-point
6411
 */
6412
ada_really_inline constexpr uint8_t
6413
contains_forbidden_domain_code_point_or_upper(const char* input,
6414
                                              size_t length) noexcept;
6415
6416
/**
6417
 * @private
6418
 * Checks if the input is a forbidden domain code point.
6419
 * @see https://url.spec.whatwg.org/#forbidden-domain-code-point
6420
 */
6421
ada_really_inline constexpr bool is_forbidden_domain_code_point(
6422
    char c) noexcept;
6423
6424
/**
6425
 * @private
6426
 * Checks if the input is alphanumeric, '+', '-' or '.'
6427
 */
6428
ada_really_inline constexpr bool is_alnum_plus(char c) noexcept;
6429
6430
/**
6431
 * @private
6432
 * @details An ASCII hex digit is an ASCII upper hex digit or ASCII lower hex
6433
 * digit. An ASCII upper hex digit is an ASCII digit or a code point in the
6434
 * range U+0041 (A) to U+0046 (F), inclusive. An ASCII lower hex digit is an
6435
 * ASCII digit or a code point in the range U+0061 (a) to U+0066 (f), inclusive.
6436
 */
6437
ada_really_inline constexpr bool is_ascii_hex_digit(char c) noexcept;
6438
6439
/**
6440
 * @private
6441
 * An ASCII digit is a code point in the range U+0030 (0) to U+0039 (9),
6442
 * inclusive.
6443
 */
6444
ada_really_inline constexpr bool is_ascii_digit(char c) noexcept;
6445
6446
/**
6447
 * @private
6448
 * @details If a char is between U+0000 and U+007F inclusive, then it's an ASCII
6449
 * character.
6450
 */
6451
ada_really_inline constexpr bool is_ascii(char32_t c) noexcept;
6452
6453
/**
6454
 * @private
6455
 * Checks if the input is a C0 control or space character.
6456
 *
6457
 * @details A C0 control or space is a C0 control or U+0020 SPACE.
6458
 * A C0 control is a code point in the range U+0000 NULL to U+001F INFORMATION
6459
 * SEPARATOR ONE, inclusive.
6460
 */
6461
ada_really_inline constexpr bool is_c0_control_or_space(char c) noexcept;
6462
6463
/**
6464
 * @private
6465
 * Checks if the input is a ASCII tab or newline character.
6466
 *
6467
 * @details An ASCII tab or newline is U+0009 TAB, U+000A LF, or U+000D CR.
6468
 */
6469
ada_really_inline constexpr bool is_ascii_tab_or_newline(char c) noexcept;
6470
6471
/**
6472
 * @private
6473
 * @details A double-dot path segment must be ".." or an ASCII case-insensitive
6474
 * match for ".%2e", "%2e.", or "%2e%2e".
6475
 */
6476
ada_really_inline constexpr bool is_double_dot_path_segment(
6477
    std::string_view input) noexcept;
6478
6479
/**
6480
 * @private
6481
 * @details A single-dot path segment must be "." or an ASCII case-insensitive
6482
 * match for "%2e".
6483
 */
6484
ada_really_inline constexpr bool is_single_dot_path_segment(
6485
    std::string_view input) noexcept;
6486
6487
/**
6488
 * @private
6489
 * @details ipv4 character might contain 0-9 or a-f character ranges.
6490
 */
6491
ada_really_inline constexpr bool is_lowercase_hex(char c) noexcept;
6492
6493
/**
6494
 * @private
6495
 * @details Convert hex to binary. Caller is responsible to ensure that
6496
 * the parameter is an hexadecimal digit (0-9, A-F, a-f).
6497
 */
6498
ada_really_inline unsigned constexpr convert_hex_to_binary(char c) noexcept;
6499
6500
/**
6501
 * @private
6502
 * first_percent should be  = input.find('%')
6503
 *
6504
 * @todo It would be faster as noexcept maybe, but it could be unsafe since.
6505
 * @author Node.js
6506
 * @see https://github.com/nodejs/node/blob/main/src/node_url.cc#L245
6507
 * @see https://encoding.spec.whatwg.org/#utf-8-decode-without-bom
6508
 */
6509
std::string percent_decode(std::string_view input, size_t first_percent);
6510
6511
/**
6512
 * @private
6513
 * Returns a percent-encoding string whether percent encoding was needed or not.
6514
 * @see https://github.com/nodejs/node/blob/main/src/node_url.cc#L226
6515
 */
6516
std::string percent_encode(std::string_view input,
6517
                           const uint8_t character_set[]);
6518
/**
6519
 * @private
6520
 * Returns a percent-encoded string version of input, while starting the percent
6521
 * encoding at the provided index.
6522
 * @see https://github.com/nodejs/node/blob/main/src/node_url.cc#L226
6523
 */
6524
std::string percent_encode(std::string_view input,
6525
                           const uint8_t character_set[], size_t index);
6526
/**
6527
 * @private
6528
 * Returns true if percent encoding was needed, in which case, we store
6529
 * the percent-encoded content in 'out'. If the boolean 'append' is set to
6530
 * true, the content is appended to 'out'.
6531
 * If percent encoding is not needed, out is left unchanged.
6532
 * @see https://github.com/nodejs/node/blob/main/src/node_url.cc#L226
6533
 */
6534
template <bool append>
6535
bool percent_encode(std::string_view input, const uint8_t character_set[],
6536
                    std::string& out);
6537
/**
6538
 * @private
6539
 * Returns the index at which percent encoding should start, or (equivalently),
6540
 * the length of the prefix that does not require percent encoding.
6541
 */
6542
ada_really_inline size_t percent_encode_index(std::string_view input,
6543
                                              const uint8_t character_set[]);
6544
/**
6545
 * @private
6546
 * Lowers the string in-place, assuming that the content is ASCII.
6547
 * Return true if the content was ASCII.
6548
 */
6549
constexpr bool to_lower_ascii(char* input, size_t length) noexcept;
6550
}  // namespace ada::unicode
6551
6552
#endif  // ADA_UNICODE_H
6553
/* end file include/ada/unicode.h */
6554
/* begin file include/ada/url_base-inl.h */
6555
/**
6556
 * @file url_base-inl.h
6557
 * @brief Inline functions for url base
6558
 */
6559
#ifndef ADA_URL_BASE_INL_H
6560
#define ADA_URL_BASE_INL_H
6561
6562
6563
#include <string>
6564
#if ADA_REGULAR_VISUAL_STUDIO
6565
#include <intrin.h>
6566
#endif  // ADA_REGULAR_VISUAL_STUDIO
6567
6568
namespace ada {
6569
6570
[[nodiscard]] ada_really_inline constexpr bool url_base::is_special()
6571
0
    const noexcept {
6572
0
  return type != ada::scheme::NOT_SPECIAL;
6573
0
}
6574
6575
0
[[nodiscard]] inline uint16_t url_base::get_special_port() const noexcept {
6576
0
  return ada::scheme::get_special_port(type);
6577
0
}
6578
6579
[[nodiscard]] ada_really_inline uint16_t
6580
0
url_base::scheme_default_port() const noexcept {
6581
0
  return scheme::get_special_port(type);
6582
0
}
6583
6584
}  // namespace ada
6585
6586
#endif  // ADA_URL_BASE_INL_H
6587
/* end file include/ada/url_base-inl.h */
6588
/* begin file include/ada/url-inl.h */
6589
/**
6590
 * @file url-inl.h
6591
 * @brief Definitions for the URL
6592
 */
6593
#ifndef ADA_URL_INL_H
6594
#define ADA_URL_INL_H
6595
6596
6597
#include <charconv>
6598
#include <optional>
6599
#include <string>
6600
#if ADA_REGULAR_VISUAL_STUDIO
6601
#include <intrin.h>
6602
#endif  // ADA_REGULAR_VISUAL_STUDIO
6603
6604
namespace ada {
6605
0
[[nodiscard]] ada_really_inline bool url::has_credentials() const noexcept {
6606
0
  return !username.empty() || !password.empty();
6607
0
}
6608
0
[[nodiscard]] ada_really_inline bool url::has_port() const noexcept {
6609
0
  return port.has_value();
6610
0
}
6611
0
[[nodiscard]] inline bool url::cannot_have_credentials_or_port() const {
6612
0
  return !host.has_value() || host.value().empty() ||
6613
0
         type == ada::scheme::type::FILE;
6614
0
}
6615
0
[[nodiscard]] inline bool url::has_empty_hostname() const noexcept {
6616
0
  if (!host.has_value()) {
6617
0
    return false;
6618
0
  }
6619
0
  return host.value().empty();
6620
0
}
6621
0
[[nodiscard]] inline bool url::has_hostname() const noexcept {
6622
0
  return host.has_value();
6623
0
}
6624
0
inline std::ostream &operator<<(std::ostream &out, const ada::url &u) {
6625
0
  return out << u.to_string();
6626
0
}
6627
6628
0
[[nodiscard]] size_t url::get_pathname_length() const noexcept {
6629
0
  return path.size();
6630
0
}
6631
6632
0
[[nodiscard]] constexpr std::string_view url::get_pathname() const noexcept {
6633
0
  return path;
6634
0
}
6635
6636
[[nodiscard]] ada_really_inline ada::url_components url::get_components()
6637
0
    const noexcept {
6638
0
  url_components out{};
6639
0
6640
0
  // protocol ends with ':'. for example: "https:"
6641
0
  out.protocol_end = uint32_t(get_protocol().size());
6642
0
6643
0
  // Trailing index is always the next character of the current one.
6644
0
  size_t running_index = out.protocol_end;
6645
0
6646
0
  if (host.has_value()) {
6647
0
    // 2 characters for "//" and 1 character for starting index
6648
0
    out.host_start = out.protocol_end + 2;
6649
0
6650
0
    if (has_credentials()) {
6651
0
      out.username_end = uint32_t(out.host_start + username.size());
6652
0
6653
0
      out.host_start += uint32_t(username.size());
6654
0
6655
0
      if (!password.empty()) {
6656
0
        out.host_start += uint32_t(password.size() + 1);
6657
0
      }
6658
0
6659
0
      out.host_end = uint32_t(out.host_start + host.value().size());
6660
0
    } else {
6661
0
      out.username_end = out.host_start;
6662
0
6663
0
      // Host does not start with "@" if it does not include credentials.
6664
0
      out.host_end = uint32_t(out.host_start + host.value().size()) - 1;
6665
0
    }
6666
0
6667
0
    running_index = out.host_end + 1;
6668
0
  } else {
6669
0
    // Update host start and end date to the same index, since it does not
6670
0
    // exist.
6671
0
    out.host_start = out.protocol_end;
6672
0
    out.host_end = out.host_start;
6673
0
6674
0
    if (!has_opaque_path && path.starts_with("//")) {
6675
0
      // If url's host is null, url does not have an opaque path, url's path's
6676
0
      // size is greater than 1, and url's path[0] is the empty string, then
6677
0
      // append U+002F (/) followed by U+002E (.) to output.
6678
0
      running_index = out.protocol_end + 2;
6679
0
    } else {
6680
0
      running_index = out.protocol_end;
6681
0
    }
6682
0
  }
6683
0
6684
0
  if (port.has_value()) {
6685
0
    out.port = *port;
6686
0
    running_index += helpers::fast_digit_count(*port) + 1;  // Port omits ':'
6687
0
  }
6688
0
6689
0
  out.pathname_start = uint32_t(running_index);
6690
0
6691
0
  running_index += path.size();
6692
0
6693
0
  if (query.has_value()) {
6694
0
    out.search_start = uint32_t(running_index);
6695
0
    running_index += get_search().size();
6696
0
    if (get_search().empty()) {
6697
0
      running_index++;
6698
0
    }
6699
0
  }
6700
0
6701
0
  if (hash.has_value()) {
6702
0
    out.hash_start = uint32_t(running_index);
6703
0
  }
6704
0
6705
0
  return out;
6706
0
}
6707
6708
0
inline void url::update_base_hostname(std::string_view input) { host = input; }
6709
6710
0
inline void url::update_unencoded_base_hash(std::string_view input) {
6711
  // We do the percent encoding
6712
0
  hash = unicode::percent_encode(input,
6713
0
                                 ada::character_sets::FRAGMENT_PERCENT_ENCODE);
6714
0
}
6715
6716
inline void url::update_base_search(std::string_view input,
6717
0
                                    const uint8_t query_percent_encode_set[]) {
6718
0
  query = ada::unicode::percent_encode(input, query_percent_encode_set);
6719
0
}
6720
6721
0
inline void url::update_base_search(std::optional<std::string> &&input) {
6722
0
  query = std::move(input);
6723
0
}
6724
6725
0
inline void url::update_base_pathname(const std::string_view input) {
6726
0
  path = input;
6727
0
}
6728
6729
0
inline void url::update_base_username(const std::string_view input) {
6730
0
  username = input;
6731
0
}
6732
6733
0
inline void url::update_base_password(const std::string_view input) {
6734
0
  password = input;
6735
0
}
6736
6737
0
inline void url::update_base_port(std::optional<uint16_t> input) {
6738
0
  port = input;
6739
0
}
6740
6741
0
constexpr void url::clear_pathname() { path.clear(); }
6742
6743
0
constexpr void url::clear_search() { query = std::nullopt; }
6744
6745
0
[[nodiscard]] constexpr bool url::has_hash() const noexcept {
6746
0
  return hash.has_value();
6747
0
}
6748
6749
0
[[nodiscard]] constexpr bool url::has_search() const noexcept {
6750
0
  return query.has_value();
6751
0
}
6752
6753
0
constexpr void url::set_protocol_as_file() { type = ada::scheme::type::FILE; }
6754
6755
0
inline void url::set_scheme(std::string &&new_scheme) noexcept {
6756
0
  type = ada::scheme::get_scheme_type(new_scheme);
6757
  // We only move the 'scheme' if it is non-special.
6758
0
  if (!is_special()) {
6759
0
    non_special_scheme = std::move(new_scheme);
6760
0
  }
6761
0
}
6762
6763
0
constexpr void url::copy_scheme(ada::url &&u) noexcept {
6764
0
  non_special_scheme = u.non_special_scheme;
6765
0
  type = u.type;
6766
0
}
6767
6768
0
constexpr void url::copy_scheme(const ada::url &u) {
6769
0
  non_special_scheme = u.non_special_scheme;
6770
0
  type = u.type;
6771
0
}
6772
6773
0
[[nodiscard]] ada_really_inline std::string url::get_href() const noexcept {
6774
0
  std::string output = get_protocol();
6775
0
6776
0
  if (host.has_value()) {
6777
0
    output += "//";
6778
0
    if (has_credentials()) {
6779
0
      output += username;
6780
0
      if (!password.empty()) {
6781
0
        output += ":" + get_password();
6782
0
      }
6783
0
      output += "@";
6784
0
    }
6785
0
    output += host.value();
6786
0
    if (port.has_value()) {
6787
0
      output += ":" + get_port();
6788
0
    }
6789
0
  } else if (!has_opaque_path && path.starts_with("//")) {
6790
0
    // If url's host is null, url does not have an opaque path, url's path's
6791
0
    // size is greater than 1, and url's path[0] is the empty string, then
6792
0
    // append U+002F (/) followed by U+002E (.) to output.
6793
0
    output += "/.";
6794
0
  }
6795
0
  output += path;
6796
0
  if (query.has_value()) {
6797
0
    output += "?" + query.value();
6798
0
  }
6799
0
  if (hash.has_value()) {
6800
0
    output += "#" + hash.value();
6801
0
  }
6802
0
  return output;
6803
0
}
6804
6805
ada_really_inline size_t url::parse_port(std::string_view view,
6806
0
                                         bool check_trailing_content) noexcept {
6807
0
  ada_log("parse_port('", view, "') ", view.size());
6808
0
  if (!view.empty() && view[0] == '-') {
6809
0
    ada_log("parse_port: view[0] == '0' && view.size() > 1");
6810
0
    is_valid = false;
6811
0
    return 0;
6812
0
  }
6813
0
  uint16_t parsed_port{};
6814
0
  auto r = std::from_chars(view.data(), view.data() + view.size(), parsed_port);
6815
0
  if (r.ec == std::errc::result_out_of_range) {
6816
0
    ada_log("parse_port: r.ec == std::errc::result_out_of_range");
6817
0
    is_valid = false;
6818
0
    return 0;
6819
0
  }
6820
0
  ada_log("parse_port: ", parsed_port);
6821
0
  const auto consumed = size_t(r.ptr - view.data());
6822
0
  ada_log("parse_port: consumed ", consumed);
6823
0
  if (check_trailing_content) {
6824
0
    is_valid &=
6825
0
        (consumed == view.size() || view[consumed] == '/' ||
6826
0
         view[consumed] == '?' || (is_special() && view[consumed] == '\\'));
6827
0
  }
6828
0
  ada_log("parse_port: is_valid = ", is_valid);
6829
0
  if (is_valid) {
6830
    // scheme_default_port can return 0, and we should allow 0 as a base port.
6831
0
    auto default_port = scheme_default_port();
6832
0
    bool is_port_valid = (default_port == 0 && parsed_port == 0) ||
6833
0
                         (default_port != parsed_port);
6834
0
    port = (r.ec == std::errc() && is_port_valid) ? std::optional(parsed_port)
6835
0
                                                  : std::nullopt;
6836
0
  }
6837
0
  return consumed;
6838
0
}
6839
6840
}  // namespace ada
6841
6842
#endif  // ADA_URL_H
6843
/* end file include/ada/url-inl.h */
6844
/* begin file include/ada/url_components-inl.h */
6845
/**
6846
 * @file url_components.h
6847
 * @brief Declaration for the URL Components
6848
 */
6849
#ifndef ADA_URL_COMPONENTS_INL_H
6850
#define ADA_URL_COMPONENTS_INL_H
6851
6852
6853
namespace ada {
6854
6855
[[nodiscard]] constexpr bool url_components::check_offset_consistency()
6856
0
    const noexcept {
6857
0
  /**
6858
0
   * https://user:pass@example.com:1234/foo/bar?baz#quux
6859
0
   *       |     |    |          | ^^^^|       |   |
6860
0
   *       |     |    |          | |   |       |   `----- hash_start
6861
0
   *       |     |    |          | |   |       `--------- search_start
6862
0
   *       |     |    |          | |   `----------------- pathname_start
6863
0
   *       |     |    |          | `--------------------- port
6864
0
   *       |     |    |          `----------------------- host_end
6865
0
   *       |     |    `---------------------------------- host_start
6866
0
   *       |     `--------------------------------------- username_end
6867
0
   *       `--------------------------------------------- protocol_end
6868
0
   */
6869
0
  // These conditions can be made more strict.
6870
0
  if (protocol_end == url_components::omitted) {
6871
0
    return false;
6872
0
  }
6873
0
  uint32_t index = protocol_end;
6874
0
6875
0
  if (username_end == url_components::omitted) {
6876
0
    return false;
6877
0
  }
6878
0
  if (username_end < index) {
6879
0
    return false;
6880
0
  }
6881
0
  index = username_end;
6882
0
6883
0
  if (host_start == url_components::omitted) {
6884
0
    return false;
6885
0
  }
6886
0
  if (host_start < index) {
6887
0
    return false;
6888
0
  }
6889
0
  index = host_start;
6890
0
6891
0
  if (port != url_components::omitted) {
6892
0
    if (port > 0xffff) {
6893
0
      return false;
6894
0
    }
6895
0
    uint32_t port_length = helpers::fast_digit_count(port) + 1;
6896
0
    if (index + port_length < index) {
6897
0
      return false;
6898
0
    }
6899
0
    index += port_length;
6900
0
  }
6901
0
6902
0
  if (pathname_start == url_components::omitted) {
6903
0
    return false;
6904
0
  }
6905
0
  if (pathname_start < index) {
6906
0
    return false;
6907
0
  }
6908
0
  index = pathname_start;
6909
0
6910
0
  if (search_start != url_components::omitted) {
6911
0
    if (search_start < index) {
6912
0
      return false;
6913
0
    }
6914
0
    index = search_start;
6915
0
  }
6916
0
6917
0
  if (hash_start != url_components::omitted) {
6918
0
    if (hash_start < index) {
6919
0
      return false;
6920
0
    }
6921
0
  }
6922
0
6923
0
  return true;
6924
0
}
6925
6926
}  // namespace ada
6927
#endif
6928
/* end file include/ada/url_components-inl.h */
6929
/* begin file include/ada/url_aggregator.h */
6930
/**
6931
 * @file url_aggregator.h
6932
 * @brief Declaration for the basic URL definitions
6933
 */
6934
#ifndef ADA_URL_AGGREGATOR_H
6935
#define ADA_URL_AGGREGATOR_H
6936
6937
#include <ostream>
6938
#include <string>
6939
#include <string_view>
6940
#include <variant>
6941
6942
6943
namespace ada {
6944
6945
namespace parser {}
6946
6947
/**
6948
 * @brief Lightweight URL struct.
6949
 *
6950
 * @details The url_aggregator class aims to minimize temporary memory
6951
 * allocation while representing a parsed URL. Internally, it contains a single
6952
 * normalized URL (the href), and it makes available the components, mostly
6953
 * using std::string_view.
6954
 */
6955
struct url_aggregator : url_base {
6956
0
  url_aggregator() = default;
6957
0
  url_aggregator(const url_aggregator &u) = default;
6958
0
  url_aggregator(url_aggregator &&u) noexcept = default;
6959
0
  url_aggregator &operator=(url_aggregator &&u) noexcept = default;
6960
0
  url_aggregator &operator=(const url_aggregator &u) = default;
6961
0
  ~url_aggregator() override = default;
6962
6963
  bool set_href(std::string_view input);
6964
  bool set_host(std::string_view input);
6965
  bool set_hostname(std::string_view input);
6966
  bool set_protocol(std::string_view input);
6967
  bool set_username(std::string_view input);
6968
  bool set_password(std::string_view input);
6969
  bool set_port(std::string_view input);
6970
  bool set_pathname(std::string_view input);
6971
  void set_search(std::string_view input);
6972
  void set_hash(std::string_view input);
6973
6974
  [[nodiscard]] bool has_valid_domain() const noexcept override;
6975
  /**
6976
   * The origin getter steps are to return the serialization of this's URL's
6977
   * origin. [HTML]
6978
   * @return a newly allocated string.
6979
   * @see https://url.spec.whatwg.org/#concept-url-origin
6980
   */
6981
  [[nodiscard]] std::string get_origin() const noexcept override;
6982
  /**
6983
   * Return the normalized string.
6984
   * This function does not allocate memory.
6985
   * It is highly efficient.
6986
   * @return a constant reference to the underlying normalized URL.
6987
   * @see https://url.spec.whatwg.org/#dom-url-href
6988
   * @see https://url.spec.whatwg.org/#concept-url-serializer
6989
   */
6990
  [[nodiscard]] constexpr std::string_view get_href() const noexcept
6991
      ada_lifetime_bound;
6992
  /**
6993
   * The username getter steps are to return this's URL's username.
6994
   * This function does not allocate memory.
6995
   * @return a lightweight std::string_view.
6996
   * @see https://url.spec.whatwg.org/#dom-url-username
6997
   */
6998
  [[nodiscard]] std::string_view get_username() const noexcept
6999
      ada_lifetime_bound;
7000
  /**
7001
   * The password getter steps are to return this's URL's password.
7002
   * This function does not allocate memory.
7003
   * @return a lightweight std::string_view.
7004
   * @see https://url.spec.whatwg.org/#dom-url-password
7005
   */
7006
  [[nodiscard]] std::string_view get_password() const noexcept
7007
      ada_lifetime_bound;
7008
  /**
7009
   * Return this's URL's port, serialized.
7010
   * This function does not allocate memory.
7011
   * @return a lightweight std::string_view.
7012
   * @see https://url.spec.whatwg.org/#dom-url-port
7013
   */
7014
  [[nodiscard]] std::string_view get_port() const noexcept ada_lifetime_bound;
7015
  /**
7016
   * Return U+0023 (#), followed by this's URL's fragment.
7017
   * This function does not allocate memory.
7018
   * @return a lightweight std::string_view..
7019
   * @see https://url.spec.whatwg.org/#dom-url-hash
7020
   */
7021
  [[nodiscard]] std::string_view get_hash() const noexcept ada_lifetime_bound;
7022
  /**
7023
   * Return url's host, serialized, followed by U+003A (:) and url's port,
7024
   * serialized.
7025
   * This function does not allocate memory.
7026
   * When there is no host, this function returns the empty view.
7027
   * @return a lightweight std::string_view.
7028
   * @see https://url.spec.whatwg.org/#dom-url-host
7029
   */
7030
  [[nodiscard]] std::string_view get_host() const noexcept ada_lifetime_bound;
7031
  /**
7032
   * Return this's URL's host, serialized.
7033
   * This function does not allocate memory.
7034
   * When there is no host, this function returns the empty view.
7035
   * @return a lightweight std::string_view.
7036
   * @see https://url.spec.whatwg.org/#dom-url-hostname
7037
   */
7038
  [[nodiscard]] std::string_view get_hostname() const noexcept
7039
      ada_lifetime_bound;
7040
  /**
7041
   * The pathname getter steps are to return the result of URL path serializing
7042
   * this's URL.
7043
   * This function does not allocate memory.
7044
   * @return a lightweight std::string_view.
7045
   * @see https://url.spec.whatwg.org/#dom-url-pathname
7046
   */
7047
  [[nodiscard]] constexpr std::string_view get_pathname() const noexcept
7048
      ada_lifetime_bound;
7049
  /**
7050
   * Compute the pathname length in bytes without instantiating a view or a
7051
   * string.
7052
   * @return size of the pathname in bytes
7053
   * @see https://url.spec.whatwg.org/#dom-url-pathname
7054
   */
7055
  [[nodiscard]] ada_really_inline uint32_t get_pathname_length() const noexcept;
7056
  /**
7057
   * Return U+003F (?), followed by this's URL's query.
7058
   * This function does not allocate memory.
7059
   * @return a lightweight std::string_view.
7060
   * @see https://url.spec.whatwg.org/#dom-url-search
7061
   */
7062
  [[nodiscard]] std::string_view get_search() const noexcept ada_lifetime_bound;
7063
  /**
7064
   * The protocol getter steps are to return this's URL's scheme, followed by
7065
   * U+003A (:).
7066
   * This function does not allocate memory.
7067
   * @return a lightweight std::string_view.
7068
   * @see https://url.spec.whatwg.org/#dom-url-protocol
7069
   */
7070
  [[nodiscard]] std::string_view get_protocol() const noexcept
7071
      ada_lifetime_bound;
7072
7073
  /**
7074
   * A URL includes credentials if its username or password is not the empty
7075
   * string.
7076
   */
7077
  [[nodiscard]] ada_really_inline constexpr bool has_credentials()
7078
      const noexcept;
7079
7080
  /**
7081
   * Useful for implementing efficient serialization for the URL.
7082
   *
7083
   * https://user:pass@example.com:1234/foo/bar?baz#quux
7084
   *       |     |    |          | ^^^^|       |   |
7085
   *       |     |    |          | |   |       |   `----- hash_start
7086
   *       |     |    |          | |   |       `--------- search_start
7087
   *       |     |    |          | |   `----------------- pathname_start
7088
   *       |     |    |          | `--------------------- port
7089
   *       |     |    |          `----------------------- host_end
7090
   *       |     |    `---------------------------------- host_start
7091
   *       |     `--------------------------------------- username_end
7092
   *       `--------------------------------------------- protocol_end
7093
   *
7094
   * Inspired after servo/url
7095
   *
7096
   * @return a constant reference to the underlying component attribute.
7097
   *
7098
   * @see
7099
   * https://github.com/servo/rust-url/blob/b65a45515c10713f6d212e6726719a020203cc98/url/src/quirks.rs#L31
7100
   */
7101
  [[nodiscard]] ada_really_inline const url_components &get_components()
7102
      const noexcept;
7103
  /**
7104
   * Returns a string representation of this URL.
7105
   */
7106
  [[nodiscard]] std::string to_string() const override;
7107
  /**
7108
   * Returns a string diagram of this URL.
7109
   */
7110
  [[nodiscard]] std::string to_diagram() const;
7111
7112
  /**
7113
   * Verifies that the parsed URL could be valid. Useful for debugging purposes.
7114
   * @return true if the URL is valid, otherwise return true of the offsets are
7115
   * possible.
7116
   */
7117
  [[nodiscard]] constexpr bool validate() const noexcept;
7118
7119
  /** @return true if it has an host but it is the empty string */
7120
  [[nodiscard]] constexpr bool has_empty_hostname() const noexcept;
7121
  /** @return true if it has a host (included an empty host) */
7122
  [[nodiscard]] constexpr bool has_hostname() const noexcept;
7123
  /** @return true if the URL has a non-empty username */
7124
  [[nodiscard]] constexpr bool has_non_empty_username() const noexcept;
7125
  /** @return true if the URL has a non-empty password */
7126
  [[nodiscard]] constexpr bool has_non_empty_password() const noexcept;
7127
  /** @return true if the URL has a (non default) port */
7128
  [[nodiscard]] constexpr bool has_port() const noexcept;
7129
  /** @return true if the URL has a password */
7130
  [[nodiscard]] constexpr bool has_password() const noexcept;
7131
  /** @return true if the URL has a hash component */
7132
  [[nodiscard]] constexpr bool has_hash() const noexcept override;
7133
  /** @return true if the URL has a search component */
7134
  [[nodiscard]] constexpr bool has_search() const noexcept override;
7135
7136
  inline void clear_port();
7137
  inline void clear_hash();
7138
  inline void clear_search() override;
7139
7140
 private:
7141
  // helper methods
7142
  friend void helpers::strip_trailing_spaces_from_opaque_path<url_aggregator>(
7143
      url_aggregator &url) noexcept;
7144
  // parse_url methods
7145
  friend url_aggregator parser::parse_url<url_aggregator>(
7146
      std::string_view, const url_aggregator *);
7147
7148
  friend url_aggregator parser::parse_url_impl<url_aggregator, true>(
7149
      std::string_view, const url_aggregator *);
7150
  friend url_aggregator parser::parse_url_impl<url_aggregator, false>(
7151
      std::string_view, const url_aggregator *);
7152
7153
#if ADA_INCLUDE_URL_PATTERN
7154
  // url_pattern methods
7155
  template <url_pattern_regex::regex_concept regex_provider>
7156
  friend tl::expected<url_pattern<regex_provider>, errors>
7157
  parse_url_pattern_impl(
7158
      std::variant<std::string_view, url_pattern_init> &&input,
7159
      const std::string_view *base_url, const url_pattern_options *options);
7160
#endif  // ADA_INCLUDE_URL_PATTERN
7161
7162
  std::string buffer{};
7163
  url_components components{};
7164
7165
  /**
7166
   * Returns true if neither the search, nor the hash nor the pathname
7167
   * have been set.
7168
   * @return true if the buffer is ready to receive the path.
7169
   */
7170
  [[nodiscard]] ada_really_inline bool is_at_path() const noexcept;
7171
7172
  inline void add_authority_slashes_if_needed() noexcept;
7173
7174
  /**
7175
   * To optimize performance, you may indicate how much memory to allocate
7176
   * within this instance.
7177
   */
7178
  constexpr void reserve(uint32_t capacity);
7179
7180
  ada_really_inline size_t parse_port(
7181
      std::string_view view, bool check_trailing_content) noexcept override;
7182
7183
0
  ada_really_inline size_t parse_port(std::string_view view) noexcept override {
7184
0
    return this->parse_port(view, false);
7185
0
  }
7186
7187
  /**
7188
   * Return true on success. The 'in_place' parameter indicates whether the
7189
   * the string_view input is pointing in the buffer. When in_place is false,
7190
   * we must nearly always update the buffer.
7191
   * @see https://url.spec.whatwg.org/#concept-ipv4-parser
7192
   */
7193
  [[nodiscard]] bool parse_ipv4(std::string_view input, bool in_place);
7194
7195
  /**
7196
   * Return true on success.
7197
   * @see https://url.spec.whatwg.org/#concept-ipv6-parser
7198
   */
7199
  [[nodiscard]] bool parse_ipv6(std::string_view input);
7200
7201
  /**
7202
   * Return true on success.
7203
   * @see https://url.spec.whatwg.org/#concept-opaque-host-parser
7204
   */
7205
  [[nodiscard]] bool parse_opaque_host(std::string_view input);
7206
7207
  ada_really_inline void parse_path(std::string_view input);
7208
7209
  /**
7210
   * A URL cannot have a username/password/port if its host is null or the empty
7211
   * string, or its scheme is "file".
7212
   */
7213
  [[nodiscard]] constexpr bool cannot_have_credentials_or_port() const;
7214
7215
  template <bool override_hostname = false>
7216
  bool set_host_or_hostname(std::string_view input);
7217
7218
  ada_really_inline bool parse_host(std::string_view input);
7219
7220
  inline void update_base_authority(std::string_view base_buffer,
7221
                                    const url_components &base);
7222
  inline void update_unencoded_base_hash(std::string_view input);
7223
  inline void update_base_hostname(std::string_view input);
7224
  inline void update_base_search(std::string_view input);
7225
  inline void update_base_search(std::string_view input,
7226
                                 const uint8_t *query_percent_encode_set);
7227
  inline void update_base_pathname(std::string_view input);
7228
  inline void update_base_username(std::string_view input);
7229
  inline void append_base_username(std::string_view input);
7230
  inline void update_base_password(std::string_view input);
7231
  inline void append_base_password(std::string_view input);
7232
  inline void update_base_port(uint32_t input);
7233
  inline void append_base_pathname(std::string_view input);
7234
  [[nodiscard]] inline uint32_t retrieve_base_port() const;
7235
  constexpr void clear_hostname();
7236
  constexpr void clear_password();
7237
  constexpr void clear_pathname() override;
7238
  [[nodiscard]] constexpr bool has_dash_dot() const noexcept;
7239
  void delete_dash_dot();
7240
  inline void consume_prepared_path(std::string_view input);
7241
  template <bool has_state_override = false>
7242
  [[nodiscard]] ada_really_inline bool parse_scheme_with_colon(
7243
      std::string_view input);
7244
  ada_really_inline uint32_t replace_and_resize(uint32_t start, uint32_t end,
7245
                                                std::string_view input);
7246
  [[nodiscard]] constexpr bool has_authority() const noexcept;
7247
  constexpr void set_protocol_as_file();
7248
  inline void set_scheme(std::string_view new_scheme) noexcept;
7249
  /**
7250
   * Fast function to set the scheme from a view with a colon in the
7251
   * buffer, does not change type.
7252
   */
7253
  inline void set_scheme_from_view_with_colon(
7254
      std::string_view new_scheme_with_colon) noexcept;
7255
  inline void copy_scheme(const url_aggregator &u) noexcept;
7256
7257
  inline void update_host_to_base_host(const std::string_view input) noexcept;
7258
7259
};  // url_aggregator
7260
7261
inline std::ostream &operator<<(std::ostream &out, const url &u);
7262
}  // namespace ada
7263
7264
#endif
7265
/* end file include/ada/url_aggregator.h */
7266
/* begin file include/ada/url_aggregator-inl.h */
7267
/**
7268
 * @file url_aggregator-inl.h
7269
 * @brief Inline functions for url aggregator
7270
 */
7271
#ifndef ADA_URL_AGGREGATOR_INL_H
7272
#define ADA_URL_AGGREGATOR_INL_H
7273
7274
/* begin file include/ada/unicode-inl.h */
7275
/**
7276
 * @file unicode-inl.h
7277
 * @brief Definitions for unicode operations.
7278
 */
7279
#ifndef ADA_UNICODE_INL_H
7280
#define ADA_UNICODE_INL_H
7281
7282
/**
7283
 * Unicode operations. These functions are not part of our public API and may
7284
 * change at any time.
7285
 *
7286
 * private
7287
 * @namespace ada::unicode
7288
 * @brief Includes the declarations for unicode operations
7289
 */
7290
namespace ada::unicode {
7291
ada_really_inline size_t percent_encode_index(const std::string_view input,
7292
0
                                              const uint8_t character_set[]) {
7293
0
  const char* data = input.data();
7294
0
  const size_t size = input.size();
7295
7296
  // Process 8 bytes at a time using unrolled loop
7297
0
  size_t i = 0;
7298
0
  for (; i + 8 <= size; i += 8) {
7299
0
    unsigned char chunk[8];
7300
0
    std::memcpy(&chunk, data + i,
7301
0
                8);  // entices compiler to unconditionally process 8 characters
7302
7303
    // Check 8 characters at once
7304
0
    for (size_t j = 0; j < 8; j++) {
7305
0
      if (character_sets::bit_at(character_set, chunk[j])) {
7306
0
        return i + j;
7307
0
      }
7308
0
    }
7309
0
  }
7310
7311
  // Handle remaining bytes
7312
0
  for (; i < size; i++) {
7313
0
    if (character_sets::bit_at(character_set, data[i])) {
7314
0
      return i;
7315
0
    }
7316
0
  }
7317
7318
0
  return size;
7319
0
}
7320
}  // namespace ada::unicode
7321
7322
#endif  // ADA_UNICODE_INL_H
7323
/* end file include/ada/unicode-inl.h */
7324
7325
#include <charconv>
7326
#include <ostream>
7327
#include <string_view>
7328
7329
namespace ada {
7330
7331
inline void url_aggregator::update_base_authority(
7332
0
    std::string_view base_buffer, const ada::url_components &base) {
7333
0
  std::string_view input = base_buffer.substr(
7334
0
      base.protocol_end, base.host_start - base.protocol_end);
7335
0
  ada_log("url_aggregator::update_base_authority ", input);
7336
7337
0
  bool input_starts_with_dash = input.starts_with("//");
7338
0
  uint32_t diff = components.host_start - components.protocol_end;
7339
7340
0
  buffer.erase(components.protocol_end,
7341
0
               components.host_start - components.protocol_end);
7342
0
  components.username_end = components.protocol_end;
7343
7344
0
  if (input_starts_with_dash) {
7345
0
    input.remove_prefix(2);
7346
0
    diff += 2;  // add "//"
7347
0
    buffer.insert(components.protocol_end, "//");
7348
0
    components.username_end += 2;
7349
0
  }
7350
7351
0
  size_t password_delimiter = input.find(':');
7352
7353
  // Check if input contains both username and password by checking the
7354
  // delimiter: ":" A typical input that contains authority would be "user:pass"
7355
0
  if (password_delimiter != std::string_view::npos) {
7356
    // Insert both username and password
7357
0
    std::string_view username = input.substr(0, password_delimiter);
7358
0
    std::string_view password = input.substr(password_delimiter + 1);
7359
7360
0
    buffer.insert(components.protocol_end + diff, username);
7361
0
    diff += uint32_t(username.size());
7362
0
    buffer.insert(components.protocol_end + diff, ":");
7363
0
    components.username_end = components.protocol_end + diff;
7364
0
    buffer.insert(components.protocol_end + diff + 1, password);
7365
0
    diff += uint32_t(password.size()) + 1;
7366
0
  } else if (!input.empty()) {
7367
    // Insert only username
7368
0
    buffer.insert(components.protocol_end + diff, input);
7369
0
    components.username_end =
7370
0
        components.protocol_end + diff + uint32_t(input.size());
7371
0
    diff += uint32_t(input.size());
7372
0
  }
7373
7374
0
  components.host_start += diff;
7375
7376
0
  if (buffer.size() > base.host_start && buffer[base.host_start] != '@') {
7377
0
    buffer.insert(components.host_start, "@");
7378
0
    diff++;
7379
0
  }
7380
0
  components.host_end += diff;
7381
0
  components.pathname_start += diff;
7382
0
  if (components.search_start != url_components::omitted) {
7383
0
    components.search_start += diff;
7384
0
  }
7385
0
  if (components.hash_start != url_components::omitted) {
7386
0
    components.hash_start += diff;
7387
0
  }
7388
0
}
7389
7390
0
inline void url_aggregator::update_unencoded_base_hash(std::string_view input) {
7391
0
  ada_log("url_aggregator::update_unencoded_base_hash ", input, " [",
7392
0
          input.size(), " bytes], buffer is '", buffer, "' [", buffer.size(),
7393
0
          " bytes] components.hash_start = ", components.hash_start);
7394
0
  ADA_ASSERT_TRUE(validate());
7395
0
  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
7396
0
  if (components.hash_start != url_components::omitted) {
7397
0
    buffer.resize(components.hash_start);
7398
0
  }
7399
0
  components.hash_start = uint32_t(buffer.size());
7400
0
  buffer += "#";
7401
0
  bool encoding_required = unicode::percent_encode<true>(
7402
0
      input, ada::character_sets::FRAGMENT_PERCENT_ENCODE, buffer);
7403
  // When encoding_required is false, then buffer is left unchanged, and percent
7404
  // encoding was not deemed required.
7405
0
  if (!encoding_required) {
7406
0
    buffer.append(input);
7407
0
  }
7408
0
  ada_log("url_aggregator::update_unencoded_base_hash final buffer is '",
7409
0
          buffer, "' [", buffer.size(), " bytes]");
7410
0
  ADA_ASSERT_TRUE(validate());
7411
0
}
7412
7413
ada_really_inline uint32_t url_aggregator::replace_and_resize(
7414
0
    uint32_t start, uint32_t end, std::string_view input) {
7415
0
  uint32_t current_length = end - start;
7416
0
  uint32_t input_size = uint32_t(input.size());
7417
0
  uint32_t new_difference = input_size - current_length;
7418
7419
0
  if (current_length == 0) {
7420
0
    buffer.insert(start, input);
7421
0
  } else if (input_size == current_length) {
7422
0
    buffer.replace(start, input_size, input);
7423
0
  } else if (input_size < current_length) {
7424
0
    buffer.erase(start, current_length - input_size);
7425
0
    buffer.replace(start, input_size, input);
7426
0
  } else {
7427
0
    buffer.replace(start, current_length, input.substr(0, current_length));
7428
0
    buffer.insert(start + current_length, input.substr(current_length));
7429
0
  }
7430
7431
0
  return new_difference;
7432
0
}
7433
7434
0
inline void url_aggregator::update_base_hostname(const std::string_view input) {
7435
0
  ada_log("url_aggregator::update_base_hostname ", input, " [", input.size(),
7436
0
          " bytes], buffer is '", buffer, "' [", buffer.size(), " bytes]");
7437
0
  ADA_ASSERT_TRUE(validate());
7438
0
  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
7439
7440
  // This next line is required for when parsing a URL like `foo://`
7441
0
  add_authority_slashes_if_needed();
7442
7443
0
  bool has_credentials = components.protocol_end + 2 < components.host_start;
7444
0
  uint32_t new_difference =
7445
0
      replace_and_resize(components.host_start, components.host_end, input);
7446
7447
0
  if (has_credentials) {
7448
0
    buffer.insert(components.host_start, "@");
7449
0
    new_difference++;
7450
0
  }
7451
0
  components.host_end += new_difference;
7452
0
  components.pathname_start += new_difference;
7453
0
  if (components.search_start != url_components::omitted) {
7454
0
    components.search_start += new_difference;
7455
0
  }
7456
0
  if (components.hash_start != url_components::omitted) {
7457
0
    components.hash_start += new_difference;
7458
0
  }
7459
0
  ADA_ASSERT_TRUE(validate());
7460
0
}
7461
7462
[[nodiscard]] ada_really_inline uint32_t
7463
0
url_aggregator::get_pathname_length() const noexcept {
7464
0
  ada_log("url_aggregator::get_pathname_length");
7465
0
  uint32_t ending_index = uint32_t(buffer.size());
7466
0
  if (components.search_start != url_components::omitted) {
7467
0
    ending_index = components.search_start;
7468
0
  } else if (components.hash_start != url_components::omitted) {
7469
0
    ending_index = components.hash_start;
7470
0
  }
7471
0
  return ending_index - components.pathname_start;
7472
0
}
7473
7474
[[nodiscard]] ada_really_inline bool url_aggregator::is_at_path()
7475
0
    const noexcept {
7476
0
  return buffer.size() == components.pathname_start;
7477
0
}
7478
7479
0
inline void url_aggregator::update_base_search(std::string_view input) {
7480
0
  ada_log("url_aggregator::update_base_search ", input);
7481
0
  ADA_ASSERT_TRUE(validate());
7482
0
  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
7483
0
  if (input.empty()) {
7484
0
    clear_search();
7485
0
    return;
7486
0
  }
7487
7488
0
  if (input[0] == '?') {
7489
0
    input.remove_prefix(1);
7490
0
  }
7491
7492
0
  if (components.hash_start == url_components::omitted) {
7493
0
    if (components.search_start == url_components::omitted) {
7494
0
      components.search_start = uint32_t(buffer.size());
7495
0
      buffer += "?";
7496
0
    } else {
7497
0
      buffer.resize(components.search_start + 1);
7498
0
    }
7499
7500
0
    buffer.append(input);
7501
0
  } else {
7502
0
    if (components.search_start == url_components::omitted) {
7503
0
      components.search_start = components.hash_start;
7504
0
    } else {
7505
0
      buffer.erase(components.search_start,
7506
0
                   components.hash_start - components.search_start);
7507
0
      components.hash_start = components.search_start;
7508
0
    }
7509
7510
0
    buffer.insert(components.search_start, "?");
7511
0
    buffer.insert(components.search_start + 1, input);
7512
0
    components.hash_start += uint32_t(input.size() + 1);  // Do not forget `?`
7513
0
  }
7514
7515
0
  ADA_ASSERT_TRUE(validate());
7516
0
}
7517
7518
inline void url_aggregator::update_base_search(
7519
0
    std::string_view input, const uint8_t query_percent_encode_set[]) {
7520
0
  ada_log("url_aggregator::update_base_search ", input,
7521
0
          " with encoding parameter ", to_string(), "\n", to_diagram());
7522
0
  ADA_ASSERT_TRUE(validate());
7523
0
  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
7524
7525
0
  if (components.hash_start == url_components::omitted) {
7526
0
    if (components.search_start == url_components::omitted) {
7527
0
      components.search_start = uint32_t(buffer.size());
7528
0
      buffer += "?";
7529
0
    } else {
7530
0
      buffer.resize(components.search_start + 1);
7531
0
    }
7532
7533
0
    bool encoding_required =
7534
0
        unicode::percent_encode<true>(input, query_percent_encode_set, buffer);
7535
    // When encoding_required is false, then buffer is left unchanged, and
7536
    // percent encoding was not deemed required.
7537
0
    if (!encoding_required) {
7538
0
      buffer.append(input);
7539
0
    }
7540
0
  } else {
7541
0
    if (components.search_start == url_components::omitted) {
7542
0
      components.search_start = components.hash_start;
7543
0
    } else {
7544
0
      buffer.erase(components.search_start,
7545
0
                   components.hash_start - components.search_start);
7546
0
      components.hash_start = components.search_start;
7547
0
    }
7548
7549
0
    buffer.insert(components.search_start, "?");
7550
0
    size_t idx =
7551
0
        ada::unicode::percent_encode_index(input, query_percent_encode_set);
7552
0
    if (idx == input.size()) {
7553
0
      buffer.insert(components.search_start + 1, input);
7554
0
      components.hash_start += uint32_t(input.size() + 1);  // Do not forget `?`
7555
0
    } else {
7556
0
      buffer.insert(components.search_start + 1, input, 0, idx);
7557
0
      input.remove_prefix(idx);
7558
      // We only create a temporary string if we need percent encoding and
7559
      // we attempt to create as small a temporary string as we can.
7560
0
      std::string encoded =
7561
0
          ada::unicode::percent_encode(input, query_percent_encode_set);
7562
0
      buffer.insert(components.search_start + idx + 1, encoded);
7563
0
      components.hash_start +=
7564
0
          uint32_t(encoded.size() + idx + 1);  // Do not forget `?`
7565
0
    }
7566
0
  }
7567
7568
0
  ADA_ASSERT_TRUE(validate());
7569
0
}
7570
7571
0
inline void url_aggregator::update_base_pathname(const std::string_view input) {
7572
0
  ada_log("url_aggregator::update_base_pathname '", input, "' [", input.size(),
7573
0
          " bytes] \n", to_diagram());
7574
0
  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
7575
0
  ADA_ASSERT_TRUE(validate());
7576
7577
0
  const bool begins_with_dashdash = input.starts_with("//");
7578
0
  if (!begins_with_dashdash && has_dash_dot()) {
7579
    // We must delete the ./
7580
0
    delete_dash_dot();
7581
0
  }
7582
7583
0
  if (begins_with_dashdash && !has_opaque_path && !has_authority() &&
7584
0
      !has_dash_dot()) {
7585
    // If url's host is null, url does not have an opaque path, url's path's
7586
    // size is greater than 1, then append U+002F (/) followed by U+002E (.) to
7587
    // output.
7588
0
    buffer.insert(components.pathname_start, "/.");
7589
0
    components.pathname_start += 2;
7590
0
  }
7591
7592
0
  uint32_t difference = replace_and_resize(
7593
0
      components.pathname_start,
7594
0
      components.pathname_start + get_pathname_length(), input);
7595
0
  if (components.search_start != url_components::omitted) {
7596
0
    components.search_start += difference;
7597
0
  }
7598
0
  if (components.hash_start != url_components::omitted) {
7599
0
    components.hash_start += difference;
7600
0
  }
7601
0
  ADA_ASSERT_TRUE(validate());
7602
0
}
7603
7604
0
inline void url_aggregator::append_base_pathname(const std::string_view input) {
7605
0
  ada_log("url_aggregator::append_base_pathname ", input, " ", to_string(),
7606
0
          "\n", to_diagram());
7607
0
  ADA_ASSERT_TRUE(validate());
7608
0
  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
7609
#if ADA_DEVELOPMENT_CHECKS
7610
  // computing the expected password.
7611
  std::string path_expected(get_pathname());
7612
  path_expected.append(input);
7613
#endif  // ADA_DEVELOPMENT_CHECKS
7614
0
  uint32_t ending_index = uint32_t(buffer.size());
7615
0
  if (components.search_start != url_components::omitted) {
7616
0
    ending_index = components.search_start;
7617
0
  } else if (components.hash_start != url_components::omitted) {
7618
0
    ending_index = components.hash_start;
7619
0
  }
7620
0
  buffer.insert(ending_index, input);
7621
7622
0
  if (components.search_start != url_components::omitted) {
7623
0
    components.search_start += uint32_t(input.size());
7624
0
  }
7625
0
  if (components.hash_start != url_components::omitted) {
7626
0
    components.hash_start += uint32_t(input.size());
7627
0
  }
7628
#if ADA_DEVELOPMENT_CHECKS
7629
  std::string path_after = std::string(get_pathname());
7630
  ADA_ASSERT_EQUAL(
7631
      path_expected, path_after,
7632
      "append_base_pathname problem after inserting " + std::string(input));
7633
#endif  // ADA_DEVELOPMENT_CHECKS
7634
0
  ADA_ASSERT_TRUE(validate());
7635
0
}
7636
7637
0
inline void url_aggregator::update_base_username(const std::string_view input) {
7638
0
  ada_log("url_aggregator::update_base_username '", input, "' ", to_string(),
7639
0
          "\n", to_diagram());
7640
0
  ADA_ASSERT_TRUE(validate());
7641
0
  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
7642
7643
0
  add_authority_slashes_if_needed();
7644
7645
0
  bool has_password = has_non_empty_password();
7646
0
  bool host_starts_with_at = buffer.size() > components.host_start &&
7647
0
                             buffer[components.host_start] == '@';
7648
0
  uint32_t diff = replace_and_resize(components.protocol_end + 2,
7649
0
                                     components.username_end, input);
7650
7651
0
  components.username_end += diff;
7652
0
  components.host_start += diff;
7653
7654
0
  if (!input.empty() && !host_starts_with_at) {
7655
0
    buffer.insert(components.host_start, "@");
7656
0
    diff++;
7657
0
  } else if (input.empty() && host_starts_with_at && !has_password) {
7658
    // Input is empty, there is no password, and we need to remove "@" from
7659
    // hostname
7660
0
    buffer.erase(components.host_start, 1);
7661
0
    diff--;
7662
0
  }
7663
7664
0
  components.host_end += diff;
7665
0
  components.pathname_start += diff;
7666
0
  if (components.search_start != url_components::omitted) {
7667
0
    components.search_start += diff;
7668
0
  }
7669
0
  if (components.hash_start != url_components::omitted) {
7670
0
    components.hash_start += diff;
7671
0
  }
7672
0
  ADA_ASSERT_TRUE(validate());
7673
0
}
7674
7675
0
inline void url_aggregator::append_base_username(const std::string_view input) {
7676
0
  ada_log("url_aggregator::append_base_username ", input);
7677
0
  ADA_ASSERT_TRUE(validate());
7678
0
  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
7679
#if ADA_DEVELOPMENT_CHECKS
7680
  // computing the expected password.
7681
  std::string username_expected(get_username());
7682
  username_expected.append(input);
7683
#endif  // ADA_DEVELOPMENT_CHECKS
7684
0
  add_authority_slashes_if_needed();
7685
7686
  // If input is empty, do nothing.
7687
0
  if (input.empty()) {
7688
0
    return;
7689
0
  }
7690
7691
0
  uint32_t difference = uint32_t(input.size());
7692
0
  buffer.insert(components.username_end, input);
7693
0
  components.username_end += difference;
7694
0
  components.host_start += difference;
7695
7696
0
  if (buffer[components.host_start] != '@' &&
7697
0
      components.host_start != components.host_end) {
7698
0
    buffer.insert(components.host_start, "@");
7699
0
    difference++;
7700
0
  }
7701
7702
0
  components.host_end += difference;
7703
0
  components.pathname_start += difference;
7704
0
  if (components.search_start != url_components::omitted) {
7705
0
    components.search_start += difference;
7706
0
  }
7707
0
  if (components.hash_start != url_components::omitted) {
7708
0
    components.hash_start += difference;
7709
0
  }
7710
#if ADA_DEVELOPMENT_CHECKS
7711
  std::string username_after(get_username());
7712
  ADA_ASSERT_EQUAL(
7713
      username_expected, username_after,
7714
      "append_base_username problem after inserting " + std::string(input));
7715
#endif  // ADA_DEVELOPMENT_CHECKS
7716
0
  ADA_ASSERT_TRUE(validate());
7717
0
}
7718
7719
0
constexpr void url_aggregator::clear_password() {
7720
0
  ada_log("url_aggregator::clear_password ", to_string());
7721
0
  ADA_ASSERT_TRUE(validate());
7722
0
  if (!has_password()) {
7723
0
    return;
7724
0
  }
7725
7726
0
  uint32_t diff = components.host_start - components.username_end;
7727
0
  buffer.erase(components.username_end, diff);
7728
0
  components.host_start -= diff;
7729
0
  components.host_end -= diff;
7730
0
  components.pathname_start -= diff;
7731
0
  if (components.search_start != url_components::omitted) {
7732
0
    components.search_start -= diff;
7733
0
  }
7734
0
  if (components.hash_start != url_components::omitted) {
7735
0
    components.hash_start -= diff;
7736
0
  }
7737
0
}
7738
7739
0
inline void url_aggregator::update_base_password(const std::string_view input) {
7740
0
  ada_log("url_aggregator::update_base_password ", input);
7741
0
  ADA_ASSERT_TRUE(validate());
7742
0
  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
7743
7744
0
  add_authority_slashes_if_needed();
7745
7746
  // TODO: Optimization opportunity. Merge the following removal functions.
7747
0
  if (input.empty()) {
7748
0
    clear_password();
7749
7750
    // Remove username too, if it is empty.
7751
0
    if (!has_non_empty_username()) {
7752
0
      update_base_username("");
7753
0
    }
7754
7755
0
    return;
7756
0
  }
7757
7758
0
  bool password_exists = has_password();
7759
0
  uint32_t difference = uint32_t(input.size());
7760
7761
0
  if (password_exists) {
7762
0
    uint32_t current_length =
7763
0
        components.host_start - components.username_end - 1;
7764
0
    buffer.erase(components.username_end + 1, current_length);
7765
0
    difference -= current_length;
7766
0
  } else {
7767
0
    buffer.insert(components.username_end, ":");
7768
0
    difference++;
7769
0
  }
7770
7771
0
  buffer.insert(components.username_end + 1, input);
7772
0
  components.host_start += difference;
7773
7774
  // The following line is required to add "@" to hostname. When updating
7775
  // password if hostname does not start with "@", it is "update_base_password"s
7776
  // responsibility to set it.
7777
0
  if (buffer[components.host_start] != '@') {
7778
0
    buffer.insert(components.host_start, "@");
7779
0
    difference++;
7780
0
  }
7781
7782
0
  components.host_end += difference;
7783
0
  components.pathname_start += difference;
7784
0
  if (components.search_start != url_components::omitted) {
7785
0
    components.search_start += difference;
7786
0
  }
7787
0
  if (components.hash_start != url_components::omitted) {
7788
0
    components.hash_start += difference;
7789
0
  }
7790
0
  ADA_ASSERT_TRUE(validate());
7791
0
}
7792
7793
0
inline void url_aggregator::append_base_password(const std::string_view input) {
7794
0
  ada_log("url_aggregator::append_base_password ", input, " ", to_string(),
7795
0
          "\n", to_diagram());
7796
0
  ADA_ASSERT_TRUE(validate());
7797
0
  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
7798
#if ADA_DEVELOPMENT_CHECKS
7799
  // computing the expected password.
7800
  std::string password_expected = std::string(get_password());
7801
  password_expected.append(input);
7802
#endif  // ADA_DEVELOPMENT_CHECKS
7803
0
  add_authority_slashes_if_needed();
7804
7805
  // If input is empty, do nothing.
7806
0
  if (input.empty()) {
7807
0
    return;
7808
0
  }
7809
7810
0
  uint32_t difference = uint32_t(input.size());
7811
0
  if (has_password()) {
7812
0
    buffer.insert(components.host_start, input);
7813
0
  } else {
7814
0
    difference++;  // Increment for ":"
7815
0
    buffer.insert(components.username_end, ":");
7816
0
    buffer.insert(components.username_end + 1, input);
7817
0
  }
7818
0
  components.host_start += difference;
7819
7820
  // The following line is required to add "@" to hostname. When updating
7821
  // password if hostname does not start with "@", it is "append_base_password"s
7822
  // responsibility to set it.
7823
0
  if (buffer[components.host_start] != '@') {
7824
0
    buffer.insert(components.host_start, "@");
7825
0
    difference++;
7826
0
  }
7827
7828
0
  components.host_end += difference;
7829
0
  components.pathname_start += difference;
7830
0
  if (components.search_start != url_components::omitted) {
7831
0
    components.search_start += difference;
7832
0
  }
7833
0
  if (components.hash_start != url_components::omitted) {
7834
0
    components.hash_start += difference;
7835
0
  }
7836
#if ADA_DEVELOPMENT_CHECKS
7837
  std::string password_after(get_password());
7838
  ADA_ASSERT_EQUAL(
7839
      password_expected, password_after,
7840
      "append_base_password problem after inserting " + std::string(input));
7841
#endif  // ADA_DEVELOPMENT_CHECKS
7842
0
  ADA_ASSERT_TRUE(validate());
7843
0
}
7844
7845
0
inline void url_aggregator::update_base_port(uint32_t input) {
7846
0
  ada_log("url_aggregator::update_base_port");
7847
0
  ADA_ASSERT_TRUE(validate());
7848
0
  if (input == url_components::omitted) {
7849
0
    clear_port();
7850
0
    return;
7851
0
  }
7852
  // calling std::to_string(input.value()) is unfortunate given that the port
7853
  // value is probably already available as a string.
7854
0
  std::string value = helpers::concat(":", std::to_string(input));
7855
0
  uint32_t difference = uint32_t(value.size());
7856
7857
0
  if (components.port != url_components::omitted) {
7858
0
    difference -= components.pathname_start - components.host_end;
7859
0
    buffer.erase(components.host_end,
7860
0
                 components.pathname_start - components.host_end);
7861
0
  }
7862
7863
0
  buffer.insert(components.host_end, value);
7864
0
  components.pathname_start += difference;
7865
0
  if (components.search_start != url_components::omitted) {
7866
0
    components.search_start += difference;
7867
0
  }
7868
0
  if (components.hash_start != url_components::omitted) {
7869
0
    components.hash_start += difference;
7870
0
  }
7871
0
  components.port = input;
7872
0
  ADA_ASSERT_TRUE(validate());
7873
0
}
7874
7875
0
inline void url_aggregator::clear_port() {
7876
0
  ada_log("url_aggregator::clear_port");
7877
0
  ADA_ASSERT_TRUE(validate());
7878
0
  if (components.port == url_components::omitted) {
7879
0
    return;
7880
0
  }
7881
0
  uint32_t length = components.pathname_start - components.host_end;
7882
0
  buffer.erase(components.host_end, length);
7883
0
  components.pathname_start -= length;
7884
0
  if (components.search_start != url_components::omitted) {
7885
0
    components.search_start -= length;
7886
0
  }
7887
0
  if (components.hash_start != url_components::omitted) {
7888
0
    components.hash_start -= length;
7889
0
  }
7890
0
  components.port = url_components::omitted;
7891
0
  ADA_ASSERT_TRUE(validate());
7892
0
}
7893
7894
0
[[nodiscard]] inline uint32_t url_aggregator::retrieve_base_port() const {
7895
0
  ada_log("url_aggregator::retrieve_base_port");
7896
0
  return components.port;
7897
0
}
7898
7899
0
inline void url_aggregator::clear_search() {
7900
0
  ada_log("url_aggregator::clear_search");
7901
0
  ADA_ASSERT_TRUE(validate());
7902
0
  if (components.search_start == url_components::omitted) {
7903
0
    return;
7904
0
  }
7905
7906
0
  if (components.hash_start == url_components::omitted) {
7907
0
    buffer.resize(components.search_start);
7908
0
  } else {
7909
0
    buffer.erase(components.search_start,
7910
0
                 components.hash_start - components.search_start);
7911
0
    components.hash_start = components.search_start;
7912
0
  }
7913
7914
0
  components.search_start = url_components::omitted;
7915
7916
#if ADA_DEVELOPMENT_CHECKS
7917
  ADA_ASSERT_EQUAL(get_search(), "",
7918
                   "search should have been cleared on buffer=" + buffer +
7919
                       " with " + components.to_string() + "\n" + to_diagram());
7920
#endif
7921
0
  ADA_ASSERT_TRUE(validate());
7922
0
}
7923
7924
0
inline void url_aggregator::clear_hash() {
7925
0
  ada_log("url_aggregator::clear_hash");
7926
0
  ADA_ASSERT_TRUE(validate());
7927
0
  if (components.hash_start == url_components::omitted) {
7928
0
    return;
7929
0
  }
7930
0
  buffer.resize(components.hash_start);
7931
0
  components.hash_start = url_components::omitted;
7932
7933
#if ADA_DEVELOPMENT_CHECKS
7934
  ADA_ASSERT_EQUAL(get_hash(), "",
7935
                   "hash should have been cleared on buffer=" + buffer +
7936
                       " with " + components.to_string() + "\n" + to_diagram());
7937
#endif
7938
0
  ADA_ASSERT_TRUE(validate());
7939
0
}
7940
7941
0
constexpr void url_aggregator::clear_pathname() {
7942
0
  ada_log("url_aggregator::clear_pathname");
7943
0
  ADA_ASSERT_TRUE(validate());
7944
0
  uint32_t ending_index = uint32_t(buffer.size());
7945
0
  if (components.search_start != url_components::omitted) {
7946
0
    ending_index = components.search_start;
7947
0
  } else if (components.hash_start != url_components::omitted) {
7948
0
    ending_index = components.hash_start;
7949
0
  }
7950
0
  uint32_t pathname_length = ending_index - components.pathname_start;
7951
0
  buffer.erase(components.pathname_start, pathname_length);
7952
0
  uint32_t difference = pathname_length;
7953
0
  if (components.pathname_start == components.host_end + 2 &&
7954
0
      buffer[components.host_end] == '/' &&
7955
0
      buffer[components.host_end + 1] == '.') {
7956
0
    components.pathname_start -= 2;
7957
0
    buffer.erase(components.host_end, 2);
7958
0
    difference += 2;
7959
0
  }
7960
0
  if (components.search_start != url_components::omitted) {
7961
0
    components.search_start -= difference;
7962
0
  }
7963
0
  if (components.hash_start != url_components::omitted) {
7964
0
    components.hash_start -= difference;
7965
0
  }
7966
0
  ada_log("url_aggregator::clear_pathname completed, running checks...");
7967
#if ADA_DEVELOPMENT_CHECKS
7968
  ADA_ASSERT_EQUAL(get_pathname(), "",
7969
                   "pathname should have been cleared on buffer=" + buffer +
7970
                       " with " + components.to_string() + "\n" + to_diagram());
7971
#endif
7972
0
  ADA_ASSERT_TRUE(validate());
7973
0
  ada_log("url_aggregator::clear_pathname completed, running checks... ok");
7974
0
}
7975
7976
0
constexpr void url_aggregator::clear_hostname() {
7977
0
  ada_log("url_aggregator::clear_hostname");
7978
0
  ADA_ASSERT_TRUE(validate());
7979
0
  if (!has_authority()) {
7980
0
    return;
7981
0
  }
7982
0
  ADA_ASSERT_TRUE(has_authority());
7983
7984
0
  uint32_t hostname_length = components.host_end - components.host_start;
7985
0
  uint32_t start = components.host_start;
7986
7987
  // If hostname starts with "@", we should not remove that character.
7988
0
  if (hostname_length > 0 && buffer[start] == '@') {
7989
0
    start++;
7990
0
    hostname_length--;
7991
0
  }
7992
0
  buffer.erase(start, hostname_length);
7993
0
  components.host_end = start;
7994
0
  components.pathname_start -= hostname_length;
7995
0
  if (components.search_start != url_components::omitted) {
7996
0
    components.search_start -= hostname_length;
7997
0
  }
7998
0
  if (components.hash_start != url_components::omitted) {
7999
0
    components.hash_start -= hostname_length;
8000
0
  }
8001
#if ADA_DEVELOPMENT_CHECKS
8002
  ADA_ASSERT_EQUAL(get_hostname(), "",
8003
                   "hostname should have been cleared on buffer=" + buffer +
8004
                       " with " + components.to_string() + "\n" + to_diagram());
8005
#endif
8006
0
  ADA_ASSERT_TRUE(has_authority());
8007
0
  ADA_ASSERT_EQUAL(has_empty_hostname(), true,
8008
0
                   "hostname should have been cleared on buffer=" + buffer +
8009
0
                       " with " + components.to_string() + "\n" + to_diagram());
8010
0
  ADA_ASSERT_TRUE(validate());
8011
0
}
8012
8013
0
[[nodiscard]] constexpr bool url_aggregator::has_hash() const noexcept {
8014
0
  ada_log("url_aggregator::has_hash");
8015
0
  return components.hash_start != url_components::omitted;
8016
0
}
8017
8018
0
[[nodiscard]] constexpr bool url_aggregator::has_search() const noexcept {
8019
0
  ada_log("url_aggregator::has_search");
8020
0
  return components.search_start != url_components::omitted;
8021
0
}
8022
8023
0
constexpr bool url_aggregator::has_credentials() const noexcept {
8024
0
  ada_log("url_aggregator::has_credentials");
8025
0
  return has_non_empty_username() || has_non_empty_password();
8026
0
}
8027
8028
0
constexpr bool url_aggregator::cannot_have_credentials_or_port() const {
8029
0
  ada_log("url_aggregator::cannot_have_credentials_or_port");
8030
0
  return type == ada::scheme::type::FILE ||
8031
0
         components.host_start == components.host_end;
8032
0
}
8033
8034
[[nodiscard]] ada_really_inline const ada::url_components &
8035
0
url_aggregator::get_components() const noexcept {
8036
0
  return components;
8037
0
}
8038
8039
[[nodiscard]] constexpr bool ada::url_aggregator::has_authority()
8040
0
    const noexcept {
8041
0
  ada_log("url_aggregator::has_authority");
8042
  // Performance: instead of doing this potentially expensive check, we could
8043
  // have a boolean in the struct.
8044
0
  return components.protocol_end + 2 <= components.host_start &&
8045
0
         helpers::substring(buffer, components.protocol_end,
8046
0
                            components.protocol_end + 2) == "//";
8047
0
}
8048
8049
0
inline void ada::url_aggregator::add_authority_slashes_if_needed() noexcept {
8050
0
  ada_log("url_aggregator::add_authority_slashes_if_needed");
8051
0
  ADA_ASSERT_TRUE(validate());
8052
  // Protocol setter will insert `http:` to the URL. It is up to hostname setter
8053
  // to insert
8054
  // `//` initially to the buffer, since it depends on the hostname existence.
8055
0
  if (has_authority()) {
8056
0
    return;
8057
0
  }
8058
  // Performance: the common case is components.protocol_end == buffer.size()
8059
  // Optimization opportunity: in many cases, the "//" is part of the input and
8060
  // the insert could be fused with another insert.
8061
0
  buffer.insert(components.protocol_end, "//");
8062
0
  components.username_end += 2;
8063
0
  components.host_start += 2;
8064
0
  components.host_end += 2;
8065
0
  components.pathname_start += 2;
8066
0
  if (components.search_start != url_components::omitted) {
8067
0
    components.search_start += 2;
8068
0
  }
8069
0
  if (components.hash_start != url_components::omitted) {
8070
0
    components.hash_start += 2;
8071
0
  }
8072
0
  ADA_ASSERT_TRUE(validate());
8073
0
}
8074
8075
0
constexpr void ada::url_aggregator::reserve(uint32_t capacity) {
8076
0
  buffer.reserve(capacity);
8077
0
}
8078
8079
0
constexpr bool url_aggregator::has_non_empty_username() const noexcept {
8080
0
  ada_log("url_aggregator::has_non_empty_username");
8081
0
  return components.protocol_end + 2 < components.username_end;
8082
0
}
8083
8084
0
constexpr bool url_aggregator::has_non_empty_password() const noexcept {
8085
0
  ada_log("url_aggregator::has_non_empty_password");
8086
0
  return components.host_start - components.username_end > 0;
8087
0
}
8088
8089
0
constexpr bool url_aggregator::has_password() const noexcept {
8090
0
  ada_log("url_aggregator::has_password");
8091
  // This function does not care about the length of the password
8092
0
  return components.host_start > components.username_end &&
8093
0
         buffer[components.username_end] == ':';
8094
0
}
8095
8096
0
constexpr bool url_aggregator::has_empty_hostname() const noexcept {
8097
0
  if (!has_hostname()) {
8098
0
    return false;
8099
0
  }
8100
0
  if (components.host_start == components.host_end) {
8101
0
    return true;
8102
0
  }
8103
0
  if (components.host_end > components.host_start + 1) {
8104
0
    return false;
8105
0
  }
8106
0
  return components.username_end != components.host_start;
8107
0
}
8108
8109
0
constexpr bool url_aggregator::has_hostname() const noexcept {
8110
0
  return has_authority();
8111
0
}
8112
8113
0
constexpr bool url_aggregator::has_port() const noexcept {
8114
0
  ada_log("url_aggregator::has_port");
8115
  // A URL cannot have a username/password/port if its host is null or the empty
8116
  // string, or its scheme is "file".
8117
0
  return has_hostname() && components.pathname_start != components.host_end;
8118
0
}
8119
8120
0
[[nodiscard]] constexpr bool url_aggregator::has_dash_dot() const noexcept {
8121
  // If url's host is null, url does not have an opaque path, url's path's size
8122
  // is greater than 1, and url's path[0] is the empty string, then append
8123
  // U+002F (/) followed by U+002E (.) to output.
8124
0
  ada_log("url_aggregator::has_dash_dot");
8125
#if ADA_DEVELOPMENT_CHECKS
8126
  // If pathname_start and host_end are exactly two characters apart, then we
8127
  // either have a one-digit port such as http://test.com:5?param=1 or else we
8128
  // have a /.: sequence such as "non-spec:/.//". We test that this is the case.
8129
  if (components.pathname_start == components.host_end + 2) {
8130
    ADA_ASSERT_TRUE((buffer[components.host_end] == '/' &&
8131
                     buffer[components.host_end + 1] == '.') ||
8132
                    (buffer[components.host_end] == ':' &&
8133
                     checkers::is_digit(buffer[components.host_end + 1])));
8134
  }
8135
  if (components.pathname_start == components.host_end + 2 &&
8136
      buffer[components.host_end] == '/' &&
8137
      buffer[components.host_end + 1] == '.') {
8138
    ADA_ASSERT_TRUE(components.pathname_start + 1 < buffer.size());
8139
    ADA_ASSERT_TRUE(buffer[components.pathname_start] == '/');
8140
    ADA_ASSERT_TRUE(buffer[components.pathname_start + 1] == '/');
8141
  }
8142
#endif
8143
  // Performance: it should be uncommon for components.pathname_start ==
8144
  // components.host_end + 2 to be true. So we put this check first in the
8145
  // sequence. Most times, we do not have an opaque path. Checking for '/.' is
8146
  // more expensive, but should be uncommon.
8147
0
  return components.pathname_start == components.host_end + 2 &&
8148
0
         !has_opaque_path && buffer[components.host_end] == '/' &&
8149
0
         buffer[components.host_end + 1] == '.';
8150
0
}
8151
8152
[[nodiscard]] constexpr std::string_view url_aggregator::get_href()
8153
0
    const noexcept ada_lifetime_bound {
8154
0
  ada_log("url_aggregator::get_href");
8155
0
  return buffer;
8156
0
}
8157
8158
ada_really_inline size_t url_aggregator::parse_port(
8159
0
    std::string_view view, bool check_trailing_content) noexcept {
8160
0
  ada_log("url_aggregator::parse_port('", view, "') ", view.size());
8161
0
  if (!view.empty() && view[0] == '-') {
8162
0
    ada_log("parse_port: view[0] == '0' && view.size() > 1");
8163
0
    is_valid = false;
8164
0
    return 0;
8165
0
  }
8166
0
  uint16_t parsed_port{};
8167
0
  auto r = std::from_chars(view.data(), view.data() + view.size(), parsed_port);
8168
0
  if (r.ec == std::errc::result_out_of_range) {
8169
0
    ada_log("parse_port: r.ec == std::errc::result_out_of_range");
8170
0
    is_valid = false;
8171
0
    return 0;
8172
0
  }
8173
0
  ada_log("parse_port: ", parsed_port);
8174
0
  const size_t consumed = size_t(r.ptr - view.data());
8175
0
  ada_log("parse_port: consumed ", consumed);
8176
0
  if (check_trailing_content) {
8177
0
    is_valid &=
8178
0
        (consumed == view.size() || view[consumed] == '/' ||
8179
0
         view[consumed] == '?' || (is_special() && view[consumed] == '\\'));
8180
0
  }
8181
0
  ada_log("parse_port: is_valid = ", is_valid);
8182
0
  if (is_valid) {
8183
0
    ada_log("parse_port", r.ec == std::errc());
8184
    // scheme_default_port can return 0, and we should allow 0 as a base port.
8185
0
    auto default_port = scheme_default_port();
8186
0
    bool is_port_valid = (default_port == 0 && parsed_port == 0) ||
8187
0
                         (default_port != parsed_port);
8188
0
    if (r.ec == std::errc() && is_port_valid) {
8189
0
      update_base_port(parsed_port);
8190
0
    } else {
8191
0
      clear_port();
8192
0
    }
8193
0
  }
8194
0
  return consumed;
8195
0
}
8196
8197
0
constexpr void url_aggregator::set_protocol_as_file() {
8198
0
  ada_log("url_aggregator::set_protocol_as_file ");
8199
0
  ADA_ASSERT_TRUE(validate());
8200
0
  type = ada::scheme::type::FILE;
8201
  // next line could overflow but unsigned arithmetic has well-defined
8202
  // overflows.
8203
0
  uint32_t new_difference = 5 - components.protocol_end;
8204
8205
0
  if (buffer.empty()) {
8206
0
    buffer.append("file:");
8207
0
  } else {
8208
0
    buffer.erase(0, components.protocol_end);
8209
0
    buffer.insert(0, "file:");
8210
0
  }
8211
0
  components.protocol_end = 5;
8212
8213
  // Update the rest of the components.
8214
0
  components.username_end += new_difference;
8215
0
  components.host_start += new_difference;
8216
0
  components.host_end += new_difference;
8217
0
  components.pathname_start += new_difference;
8218
0
  if (components.search_start != url_components::omitted) {
8219
0
    components.search_start += new_difference;
8220
0
  }
8221
0
  if (components.hash_start != url_components::omitted) {
8222
0
    components.hash_start += new_difference;
8223
0
  }
8224
0
  ADA_ASSERT_TRUE(validate());
8225
0
}
8226
8227
0
[[nodiscard]] constexpr bool url_aggregator::validate() const noexcept {
8228
0
  if (!is_valid) {
8229
0
    return true;
8230
0
  }
8231
0
  if (!components.check_offset_consistency()) {
8232
0
    ada_log("url_aggregator::validate inconsistent components \n",
8233
0
            to_diagram());
8234
0
    return false;
8235
0
  }
8236
0
  // We have a credible components struct, but let us investivate more
8237
0
  // carefully:
8238
0
  /**
8239
0
   * https://user:pass@example.com:1234/foo/bar?baz#quux
8240
0
   *       |     |    |          | ^^^^|       |   |
8241
0
   *       |     |    |          | |   |       |   `----- hash_start
8242
0
   *       |     |    |          | |   |       `--------- search_start
8243
0
   *       |     |    |          | |   `----------------- pathname_start
8244
0
   *       |     |    |          | `--------------------- port
8245
0
   *       |     |    |          `----------------------- host_end
8246
0
   *       |     |    `---------------------------------- host_start
8247
0
   *       |     `--------------------------------------- username_end
8248
0
   *       `--------------------------------------------- protocol_end
8249
0
   */
8250
0
  if (components.protocol_end == url_components::omitted) {
8251
0
    ada_log("url_aggregator::validate omitted protocol_end \n", to_diagram());
8252
0
    return false;
8253
0
  }
8254
0
  if (components.username_end == url_components::omitted) {
8255
0
    ada_log("url_aggregator::validate omitted username_end \n", to_diagram());
8256
0
    return false;
8257
0
  }
8258
0
  if (components.host_start == url_components::omitted) {
8259
0
    ada_log("url_aggregator::validate omitted host_start \n", to_diagram());
8260
0
    return false;
8261
0
  }
8262
0
  if (components.host_end == url_components::omitted) {
8263
0
    ada_log("url_aggregator::validate omitted host_end \n", to_diagram());
8264
0
    return false;
8265
0
  }
8266
0
  if (components.pathname_start == url_components::omitted) {
8267
0
    ada_log("url_aggregator::validate omitted pathname_start \n", to_diagram());
8268
0
    return false;
8269
0
  }
8270
0
8271
0
  if (components.protocol_end > buffer.size()) {
8272
0
    ada_log("url_aggregator::validate protocol_end overflow \n", to_diagram());
8273
0
    return false;
8274
0
  }
8275
0
  if (components.username_end > buffer.size()) {
8276
0
    ada_log("url_aggregator::validate username_end overflow \n", to_diagram());
8277
0
    return false;
8278
0
  }
8279
0
  if (components.host_start > buffer.size()) {
8280
0
    ada_log("url_aggregator::validate host_start overflow \n", to_diagram());
8281
0
    return false;
8282
0
  }
8283
0
  if (components.host_end > buffer.size()) {
8284
0
    ada_log("url_aggregator::validate host_end overflow \n", to_diagram());
8285
0
    return false;
8286
0
  }
8287
0
  if (components.pathname_start > buffer.size()) {
8288
0
    ada_log("url_aggregator::validate pathname_start overflow \n",
8289
0
            to_diagram());
8290
0
    return false;
8291
0
  }
8292
0
8293
0
  if (components.protocol_end > 0) {
8294
0
    if (buffer[components.protocol_end - 1] != ':') {
8295
0
      ada_log(
8296
0
          "url_aggregator::validate missing : at the end of the protocol \n",
8297
0
          to_diagram());
8298
0
      return false;
8299
0
    }
8300
0
  }
8301
0
8302
0
  if (components.username_end != buffer.size() &&
8303
0
      components.username_end > components.protocol_end + 2) {
8304
0
    if (buffer[components.username_end] != ':' &&
8305
0
        buffer[components.username_end] != '@') {
8306
0
      ada_log(
8307
0
          "url_aggregator::validate missing : or @ at the end of the username "
8308
0
          "\n",
8309
0
          to_diagram());
8310
0
      return false;
8311
0
    }
8312
0
  }
8313
0
8314
0
  if (components.host_start != buffer.size()) {
8315
0
    if (components.host_start > components.username_end) {
8316
0
      if (buffer[components.host_start] != '@') {
8317
0
        ada_log(
8318
0
            "url_aggregator::validate missing @ at the end of the password \n",
8319
0
            to_diagram());
8320
0
        return false;
8321
0
      }
8322
0
    } else if (components.host_start == components.username_end &&
8323
0
               components.host_end > components.host_start) {
8324
0
      if (components.host_start == components.protocol_end + 2) {
8325
0
        if (buffer[components.protocol_end] != '/' ||
8326
0
            buffer[components.protocol_end + 1] != '/') {
8327
0
          ada_log(
8328
0
              "url_aggregator::validate missing // between protocol and host "
8329
0
              "\n",
8330
0
              to_diagram());
8331
0
          return false;
8332
0
        }
8333
0
      } else {
8334
0
        if (components.host_start > components.protocol_end &&
8335
0
            buffer[components.host_start] != '@') {
8336
0
          ada_log(
8337
0
              "url_aggregator::validate missing @ at the end of the username "
8338
0
              "\n",
8339
0
              to_diagram());
8340
0
          return false;
8341
0
        }
8342
0
      }
8343
0
    } else {
8344
0
      if (components.host_end != components.host_start) {
8345
0
        ada_log("url_aggregator::validate expected omitted host \n",
8346
0
                to_diagram());
8347
0
        return false;
8348
0
      }
8349
0
    }
8350
0
  }
8351
0
  if (components.host_end != buffer.size() &&
8352
0
      components.pathname_start > components.host_end) {
8353
0
    if (components.pathname_start == components.host_end + 2 &&
8354
0
        buffer[components.host_end] == '/' &&
8355
0
        buffer[components.host_end + 1] == '.') {
8356
0
      if (components.pathname_start + 1 >= buffer.size() ||
8357
0
          buffer[components.pathname_start] != '/' ||
8358
0
          buffer[components.pathname_start + 1] != '/') {
8359
0
        ada_log(
8360
0
            "url_aggregator::validate expected the path to begin with // \n",
8361
0
            to_diagram());
8362
0
        return false;
8363
0
      }
8364
0
    } else if (buffer[components.host_end] != ':') {
8365
0
      ada_log("url_aggregator::validate missing : at the port \n",
8366
0
              to_diagram());
8367
0
      return false;
8368
0
    }
8369
0
  }
8370
0
  if (components.pathname_start != buffer.size() &&
8371
0
      components.pathname_start < components.search_start &&
8372
0
      components.pathname_start < components.hash_start && !has_opaque_path) {
8373
0
    if (buffer[components.pathname_start] != '/') {
8374
0
      ada_log("url_aggregator::validate missing / at the path \n",
8375
0
              to_diagram());
8376
0
      return false;
8377
0
    }
8378
0
  }
8379
0
  if (components.search_start != url_components::omitted) {
8380
0
    if (buffer[components.search_start] != '?') {
8381
0
      ada_log("url_aggregator::validate missing ? at the search \n",
8382
0
              to_diagram());
8383
0
      return false;
8384
0
    }
8385
0
  }
8386
0
  if (components.hash_start != url_components::omitted) {
8387
0
    if (buffer[components.hash_start] != '#') {
8388
0
      ada_log("url_aggregator::validate missing # at the hash \n",
8389
0
              to_diagram());
8390
0
      return false;
8391
0
    }
8392
0
  }
8393
0
8394
0
  return true;
8395
0
}
8396
8397
[[nodiscard]] constexpr std::string_view url_aggregator::get_pathname()
8398
0
    const noexcept ada_lifetime_bound {
8399
0
  ada_log("url_aggregator::get_pathname pathname_start = ",
8400
0
          components.pathname_start, " buffer.size() = ", buffer.size(),
8401
0
          " components.search_start = ", components.search_start,
8402
0
          " components.hash_start = ", components.hash_start);
8403
0
  auto ending_index = uint32_t(buffer.size());
8404
0
  if (components.search_start != url_components::omitted) {
8405
0
    ending_index = components.search_start;
8406
0
  } else if (components.hash_start != url_components::omitted) {
8407
0
    ending_index = components.hash_start;
8408
0
  }
8409
0
  return helpers::substring(buffer, components.pathname_start, ending_index);
8410
0
}
8411
8412
inline std::ostream &operator<<(std::ostream &out,
8413
0
                                const ada::url_aggregator &u) {
8414
0
  return out << u.to_string();
8415
0
}
8416
8417
void url_aggregator::update_host_to_base_host(
8418
0
    const std::string_view input) noexcept {
8419
0
  ada_log("url_aggregator::update_host_to_base_host ", input);
8420
0
  ADA_ASSERT_TRUE(validate());
8421
0
  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
8422
0
  if (type != ada::scheme::type::FILE) {
8423
    // Let host be the result of host parsing host_view with url is not special.
8424
0
    if (input.empty() && !is_special()) {
8425
0
      if (has_hostname()) {
8426
0
        clear_hostname();
8427
0
      } else if (has_dash_dot()) {
8428
0
        add_authority_slashes_if_needed();
8429
0
        delete_dash_dot();
8430
0
      }
8431
0
      return;
8432
0
    }
8433
0
  }
8434
0
  update_base_hostname(input);
8435
0
  ADA_ASSERT_TRUE(validate());
8436
0
  return;
8437
0
}
8438
}  // namespace ada
8439
8440
#endif  // ADA_URL_AGGREGATOR_INL_H
8441
/* end file include/ada/url_aggregator-inl.h */
8442
/* begin file include/ada/url_search_params.h */
8443
/**
8444
 * @file url_search_params.h
8445
 * @brief Declaration for the URL Search Params
8446
 */
8447
#ifndef ADA_URL_SEARCH_PARAMS_H
8448
#define ADA_URL_SEARCH_PARAMS_H
8449
8450
#include <optional>
8451
#include <string>
8452
#include <string_view>
8453
#include <vector>
8454
8455
namespace ada {
8456
8457
enum class url_search_params_iter_type {
8458
  KEYS,
8459
  VALUES,
8460
  ENTRIES,
8461
};
8462
8463
template <typename T, url_search_params_iter_type Type>
8464
struct url_search_params_iter;
8465
8466
typedef std::pair<std::string_view, std::string_view> key_value_view_pair;
8467
8468
using url_search_params_keys_iter =
8469
    url_search_params_iter<std::string_view, url_search_params_iter_type::KEYS>;
8470
using url_search_params_values_iter =
8471
    url_search_params_iter<std::string_view,
8472
                           url_search_params_iter_type::VALUES>;
8473
using url_search_params_entries_iter =
8474
    url_search_params_iter<key_value_view_pair,
8475
                           url_search_params_iter_type::ENTRIES>;
8476
8477
/**
8478
 * We require all strings to be valid UTF-8. It is the user's responsibility to
8479
 * ensure that the provided strings are valid UTF-8.
8480
 * @see https://url.spec.whatwg.org/#interface-urlsearchparams
8481
 */
8482
struct url_search_params {
8483
  url_search_params() = default;
8484
8485
  /**
8486
   * @see
8487
   * https://github.com/web-platform-tests/wpt/blob/master/url/urlsearchparams-constructor.any.js
8488
   */
8489
0
  explicit url_search_params(const std::string_view input) {
8490
0
    initialize(input);
8491
0
  }
8492
8493
  url_search_params(const url_search_params &u) = default;
8494
0
  url_search_params(url_search_params &&u) noexcept = default;
8495
  url_search_params &operator=(url_search_params &&u) noexcept = default;
8496
  url_search_params &operator=(const url_search_params &u) = default;
8497
0
  ~url_search_params() = default;
8498
8499
  [[nodiscard]] inline size_t size() const noexcept;
8500
8501
  /**
8502
   * Both key and value must be valid UTF-8.
8503
   * @see https://url.spec.whatwg.org/#dom-urlsearchparams-append
8504
   */
8505
  inline void append(std::string_view key, std::string_view value);
8506
8507
  /**
8508
   * @see https://url.spec.whatwg.org/#dom-urlsearchparams-delete
8509
   */
8510
  inline void remove(std::string_view key);
8511
  inline void remove(std::string_view key, std::string_view value);
8512
8513
  /**
8514
   * @see https://url.spec.whatwg.org/#dom-urlsearchparams-get
8515
   */
8516
  inline std::optional<std::string_view> get(std::string_view key);
8517
8518
  /**
8519
   * @see https://url.spec.whatwg.org/#dom-urlsearchparams-getall
8520
   */
8521
  inline std::vector<std::string> get_all(std::string_view key);
8522
8523
  /**
8524
   * @see https://url.spec.whatwg.org/#dom-urlsearchparams-has
8525
   */
8526
  inline bool has(std::string_view key) noexcept;
8527
  inline bool has(std::string_view key, std::string_view value) noexcept;
8528
8529
  /**
8530
   * Both key and value must be valid UTF-8.
8531
   * @see https://url.spec.whatwg.org/#dom-urlsearchparams-set
8532
   */
8533
  inline void set(std::string_view key, std::string_view value);
8534
8535
  /**
8536
   * @see https://url.spec.whatwg.org/#dom-urlsearchparams-sort
8537
   */
8538
  inline void sort();
8539
8540
  /**
8541
   * @see https://url.spec.whatwg.org/#urlsearchparams-stringification-behavior
8542
   */
8543
  inline std::string to_string() const;
8544
8545
  /**
8546
   * Returns a simple JS-style iterator over all of the keys in this
8547
   * url_search_params. The keys in the iterator are not unique. The valid
8548
   * lifespan of the iterator is tied to the url_search_params. The iterator
8549
   * must be freed when you're done with it.
8550
   * @see https://url.spec.whatwg.org/#interface-urlsearchparams
8551
   */
8552
  inline url_search_params_keys_iter get_keys();
8553
8554
  /**
8555
   * Returns a simple JS-style iterator over all of the values in this
8556
   * url_search_params. The valid lifespan of the iterator is tied to the
8557
   * url_search_params. The iterator must be freed when you're done with it.
8558
   * @see https://url.spec.whatwg.org/#interface-urlsearchparams
8559
   */
8560
  inline url_search_params_values_iter get_values();
8561
8562
  /**
8563
   * Returns a simple JS-style iterator over all of the entries in this
8564
   * url_search_params. The entries are pairs of keys and corresponding values.
8565
   * The valid lifespan of the iterator is tied to the url_search_params. The
8566
   * iterator must be freed when you're done with it.
8567
   * @see https://url.spec.whatwg.org/#interface-urlsearchparams
8568
   */
8569
  inline url_search_params_entries_iter get_entries();
8570
8571
  /**
8572
   * C++ style conventional iterator support. const only because we
8573
   * do not really want the params to be modified via the iterator.
8574
   */
8575
0
  inline auto begin() const { return params.begin(); }
8576
0
  inline auto end() const { return params.end(); }
8577
0
  inline auto front() const { return params.front(); }
8578
0
  inline auto back() const { return params.back(); }
8579
0
  inline auto operator[](size_t index) const { return params[index]; }
8580
8581
  /**
8582
   * @private
8583
   * Used to reset the search params to a new input.
8584
   * Used primarily for C API.
8585
   * @param input
8586
   */
8587
  void reset(std::string_view input);
8588
8589
 private:
8590
  typedef std::pair<std::string, std::string> key_value_pair;
8591
  std::vector<key_value_pair> params{};
8592
8593
  /**
8594
   * The init parameter must be valid UTF-8.
8595
   * @see https://url.spec.whatwg.org/#concept-urlencoded-parser
8596
   */
8597
  void initialize(std::string_view init);
8598
8599
  template <typename T, url_search_params_iter_type Type>
8600
  friend struct url_search_params_iter;
8601
};  // url_search_params
8602
8603
/**
8604
 * Implements a non-conventional iterator pattern that is closer in style to
8605
 * JavaScript's definition of an iterator.
8606
 *
8607
 * @see https://webidl.spec.whatwg.org/#idl-iterable
8608
 */
8609
template <typename T, url_search_params_iter_type Type>
8610
struct url_search_params_iter {
8611
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()
8612
  url_search_params_iter(const url_search_params_iter &u) = default;
8613
  url_search_params_iter(url_search_params_iter &&u) noexcept = default;
8614
  url_search_params_iter &operator=(url_search_params_iter &&u) noexcept =
8615
      default;
8616
  url_search_params_iter &operator=(const url_search_params_iter &u) = default;
8617
  ~url_search_params_iter() = default;
8618
8619
  /**
8620
   * Return the next item in the iterator or std::nullopt if done.
8621
   */
8622
  inline std::optional<T> next();
8623
8624
  inline bool has_next() const;
8625
8626
 private:
8627
  static url_search_params EMPTY;
8628
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&)
8629
8630
  url_search_params &params;
8631
  size_t pos = 0;
8632
8633
  friend struct url_search_params;
8634
};
8635
8636
}  // namespace ada
8637
#endif
8638
/* end file include/ada/url_search_params.h */
8639
/* begin file include/ada/url_search_params-inl.h */
8640
/**
8641
 * @file url_search_params-inl.h
8642
 * @brief Inline declarations for the URL Search Params
8643
 */
8644
#ifndef ADA_URL_SEARCH_PARAMS_INL_H
8645
#define ADA_URL_SEARCH_PARAMS_INL_H
8646
8647
8648
#include <algorithm>
8649
#include <optional>
8650
#include <ranges>
8651
#include <string>
8652
#include <string_view>
8653
#include <vector>
8654
8655
namespace ada {
8656
8657
// A default, empty url_search_params for use with empty iterators.
8658
template <typename T, ada::url_search_params_iter_type Type>
8659
url_search_params url_search_params_iter<T, Type>::EMPTY;
8660
8661
0
inline void url_search_params::reset(std::string_view input) {
8662
0
  params.clear();
8663
0
  initialize(input);
8664
0
}
8665
8666
0
inline void url_search_params::initialize(std::string_view input) {
8667
0
  if (!input.empty() && input.front() == '?') {
8668
0
    input.remove_prefix(1);
8669
0
  }
8670
8671
0
  auto process_key_value = [&](const std::string_view current) {
8672
0
    auto equal = current.find('=');
8673
8674
0
    if (equal == std::string_view::npos) {
8675
0
      std::string name(current);
8676
0
      std::ranges::replace(name, '+', ' ');
8677
0
      params.emplace_back(unicode::percent_decode(name, name.find('%')), "");
8678
0
    } else {
8679
0
      std::string name(current.substr(0, equal));
8680
0
      std::string value(current.substr(equal + 1));
8681
8682
0
      std::ranges::replace(name, '+', ' ');
8683
0
      std::ranges::replace(value, '+', ' ');
8684
8685
0
      params.emplace_back(unicode::percent_decode(name, name.find('%')),
8686
0
                          unicode::percent_decode(value, value.find('%')));
8687
0
    }
8688
0
  };
8689
8690
0
  while (!input.empty()) {
8691
0
    auto ampersand_index = input.find('&');
8692
8693
0
    if (ampersand_index == std::string_view::npos) {
8694
0
      if (!input.empty()) {
8695
0
        process_key_value(input);
8696
0
      }
8697
0
      break;
8698
0
    } else if (ampersand_index != 0) {
8699
0
      process_key_value(input.substr(0, ampersand_index));
8700
0
    }
8701
8702
0
    input.remove_prefix(ampersand_index + 1);
8703
0
  }
8704
0
}
8705
8706
inline void url_search_params::append(const std::string_view key,
8707
0
                                      const std::string_view value) {
8708
0
  params.emplace_back(key, value);
8709
0
}
8710
8711
0
inline size_t url_search_params::size() const noexcept { return params.size(); }
8712
8713
inline std::optional<std::string_view> url_search_params::get(
8714
0
    const std::string_view key) {
8715
0
  auto entry = std::ranges::find_if(
8716
0
      params, [&key](const auto &param) { return param.first == key; });
8717
8718
0
  if (entry == params.end()) {
8719
0
    return std::nullopt;
8720
0
  }
8721
8722
0
  return entry->second;
8723
0
}
8724
8725
inline std::vector<std::string> url_search_params::get_all(
8726
0
    const std::string_view key) {
8727
0
  std::vector<std::string> out{};
8728
8729
0
  for (auto &param : params) {
8730
0
    if (param.first == key) {
8731
0
      out.emplace_back(param.second);
8732
0
    }
8733
0
  }
8734
8735
0
  return out;
8736
0
}
8737
8738
0
inline bool url_search_params::has(const std::string_view key) noexcept {
8739
0
  auto entry = std::ranges::find_if(
8740
0
      params, [&key](const auto &param) { return param.first == key; });
8741
0
  return entry != params.end();
8742
0
}
8743
8744
inline bool url_search_params::has(std::string_view key,
8745
0
                                   std::string_view value) noexcept {
8746
0
  auto entry = std::ranges::find_if(params, [&key, &value](const auto &param) {
8747
0
    return param.first == key && param.second == value;
8748
0
  });
8749
0
  return entry != params.end();
8750
0
}
8751
8752
0
inline std::string url_search_params::to_string() const {
8753
0
  auto character_set = ada::character_sets::WWW_FORM_URLENCODED_PERCENT_ENCODE;
8754
0
  std::string out{};
8755
0
  for (size_t i = 0; i < params.size(); i++) {
8756
0
    auto key = ada::unicode::percent_encode(params[i].first, character_set);
8757
0
    auto value = ada::unicode::percent_encode(params[i].second, character_set);
8758
8759
    // Performance optimization: Move this inside percent_encode.
8760
0
    std::ranges::replace(key, ' ', '+');
8761
0
    std::ranges::replace(value, ' ', '+');
8762
8763
0
    if (i != 0) {
8764
0
      out += "&";
8765
0
    }
8766
0
    out.append(key);
8767
0
    out += "=";
8768
0
    out.append(value);
8769
0
  }
8770
0
  return out;
8771
0
}
8772
8773
inline void url_search_params::set(const std::string_view key,
8774
0
                                   const std::string_view value) {
8775
0
  const auto find = [&key](const auto &param) { return param.first == key; };
8776
8777
0
  auto it = std::ranges::find_if(params, find);
8778
8779
0
  if (it == params.end()) {
8780
0
    params.emplace_back(key, value);
8781
0
  } else {
8782
0
    it->second = value;
8783
0
    params.erase(std::remove_if(std::next(it), params.end(), find),
8784
0
                 params.end());
8785
0
  }
8786
0
}
8787
8788
0
inline void url_search_params::remove(const std::string_view key) {
8789
0
  std::erase_if(params,
8790
0
                [&key](const auto &param) { return param.first == key; });
8791
0
}
8792
8793
inline void url_search_params::remove(const std::string_view key,
8794
0
                                      const std::string_view value) {
8795
0
  std::erase_if(params, [&key, &value](const auto &param) {
8796
0
    return param.first == key && param.second == value;
8797
0
  });
8798
0
}
8799
8800
0
inline void url_search_params::sort() {
8801
  // We rely on the fact that the content is valid UTF-8.
8802
0
  std::ranges::stable_sort(params, [](const key_value_pair &lhs,
8803
0
                                      const key_value_pair &rhs) {
8804
0
    size_t i = 0, j = 0;
8805
0
    uint32_t low_surrogate1 = 0, low_surrogate2 = 0;
8806
0
    while ((i < lhs.first.size() || low_surrogate1 != 0) &&
8807
0
           (j < rhs.first.size() || low_surrogate2 != 0)) {
8808
0
      uint32_t codePoint1 = 0, codePoint2 = 0;
8809
8810
0
      if (low_surrogate1 != 0) {
8811
0
        codePoint1 = low_surrogate1;
8812
0
        low_surrogate1 = 0;
8813
0
      } else {
8814
0
        uint8_t c1 = uint8_t(lhs.first[i]);
8815
0
        if (c1 <= 0x7F) {
8816
0
          codePoint1 = c1;
8817
0
          i++;
8818
0
        } else if (c1 <= 0xDF) {
8819
0
          codePoint1 = ((c1 & 0x1F) << 6) | (uint8_t(lhs.first[i + 1]) & 0x3F);
8820
0
          i += 2;
8821
0
        } else if (c1 <= 0xEF) {
8822
0
          codePoint1 = ((c1 & 0x0F) << 12) |
8823
0
                       ((uint8_t(lhs.first[i + 1]) & 0x3F) << 6) |
8824
0
                       (uint8_t(lhs.first[i + 2]) & 0x3F);
8825
0
          i += 3;
8826
0
        } else {
8827
0
          codePoint1 = ((c1 & 0x07) << 18) |
8828
0
                       ((uint8_t(lhs.first[i + 1]) & 0x3F) << 12) |
8829
0
                       ((uint8_t(lhs.first[i + 2]) & 0x3F) << 6) |
8830
0
                       (uint8_t(lhs.first[i + 3]) & 0x3F);
8831
0
          i += 4;
8832
8833
0
          codePoint1 -= 0x10000;
8834
0
          uint16_t high_surrogate = uint16_t(0xD800 + (codePoint1 >> 10));
8835
0
          low_surrogate1 = uint16_t(0xDC00 + (codePoint1 & 0x3FF));
8836
0
          codePoint1 = high_surrogate;
8837
0
        }
8838
0
      }
8839
8840
0
      if (low_surrogate2 != 0) {
8841
0
        codePoint2 = low_surrogate2;
8842
0
        low_surrogate2 = 0;
8843
0
      } else {
8844
0
        uint8_t c2 = uint8_t(rhs.first[j]);
8845
0
        if (c2 <= 0x7F) {
8846
0
          codePoint2 = c2;
8847
0
          j++;
8848
0
        } else if (c2 <= 0xDF) {
8849
0
          codePoint2 = ((c2 & 0x1F) << 6) | (uint8_t(rhs.first[j + 1]) & 0x3F);
8850
0
          j += 2;
8851
0
        } else if (c2 <= 0xEF) {
8852
0
          codePoint2 = ((c2 & 0x0F) << 12) |
8853
0
                       ((uint8_t(rhs.first[j + 1]) & 0x3F) << 6) |
8854
0
                       (uint8_t(rhs.first[j + 2]) & 0x3F);
8855
0
          j += 3;
8856
0
        } else {
8857
0
          codePoint2 = ((c2 & 0x07) << 18) |
8858
0
                       ((uint8_t(rhs.first[j + 1]) & 0x3F) << 12) |
8859
0
                       ((uint8_t(rhs.first[j + 2]) & 0x3F) << 6) |
8860
0
                       (uint8_t(rhs.first[j + 3]) & 0x3F);
8861
0
          j += 4;
8862
0
          codePoint2 -= 0x10000;
8863
0
          uint16_t high_surrogate = uint16_t(0xD800 + (codePoint2 >> 10));
8864
0
          low_surrogate2 = uint16_t(0xDC00 + (codePoint2 & 0x3FF));
8865
0
          codePoint2 = high_surrogate;
8866
0
        }
8867
0
      }
8868
8869
0
      if (codePoint1 != codePoint2) {
8870
0
        return (codePoint1 < codePoint2);
8871
0
      }
8872
0
    }
8873
0
    return (j < rhs.first.size() || low_surrogate2 != 0);
8874
0
  });
8875
0
}
8876
8877
0
inline url_search_params_keys_iter url_search_params::get_keys() {
8878
0
  return url_search_params_keys_iter(*this);
8879
0
}
8880
8881
/**
8882
 * @see https://url.spec.whatwg.org/#interface-urlsearchparams
8883
 */
8884
0
inline url_search_params_values_iter url_search_params::get_values() {
8885
0
  return url_search_params_values_iter(*this);
8886
0
}
8887
8888
/**
8889
 * @see https://url.spec.whatwg.org/#interface-urlsearchparams
8890
 */
8891
0
inline url_search_params_entries_iter url_search_params::get_entries() {
8892
0
  return url_search_params_entries_iter(*this);
8893
0
}
8894
8895
template <typename T, url_search_params_iter_type Type>
8896
0
inline bool url_search_params_iter<T, Type>::has_next() const {
8897
0
  return pos < params.params.size();
8898
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
8899
8900
template <>
8901
0
inline std::optional<std::string_view> url_search_params_keys_iter::next() {
8902
0
  if (!has_next()) {
8903
0
    return std::nullopt;
8904
0
  }
8905
0
  return params.params[pos++].first;
8906
0
}
8907
8908
template <>
8909
0
inline std::optional<std::string_view> url_search_params_values_iter::next() {
8910
0
  if (!has_next()) {
8911
0
    return std::nullopt;
8912
0
  }
8913
0
  return params.params[pos++].second;
8914
0
}
8915
8916
template <>
8917
inline std::optional<key_value_view_pair>
8918
0
url_search_params_entries_iter::next() {
8919
0
  if (!has_next()) {
8920
0
    return std::nullopt;
8921
0
  }
8922
0
  return params.params[pos++];
8923
0
}
8924
8925
}  // namespace ada
8926
8927
#endif  // ADA_URL_SEARCH_PARAMS_INL_H
8928
/* end file include/ada/url_search_params-inl.h */
8929
8930
/* begin file include/ada/url_pattern-inl.h */
8931
/**
8932
 * @file url_pattern-inl.h
8933
 * @brief Declaration for the URLPattern inline functions.
8934
 */
8935
#ifndef ADA_URL_PATTERN_INL_H
8936
#define ADA_URL_PATTERN_INL_H
8937
8938
8939
#include <algorithm>
8940
#include <string_view>
8941
#include <utility>
8942
8943
#if ADA_INCLUDE_URL_PATTERN
8944
namespace ada {
8945
8946
0
inline bool url_pattern_init::operator==(const url_pattern_init& other) const {
8947
0
  return protocol == other.protocol && username == other.username &&
8948
0
         password == other.password && hostname == other.hostname &&
8949
0
         port == other.port && search == other.search && hash == other.hash &&
8950
0
         pathname == other.pathname;
8951
0
}
8952
8953
inline bool url_pattern_component_result::operator==(
8954
0
    const url_pattern_component_result& other) const {
8955
0
  return input == other.input && groups == other.groups;
8956
0
}
8957
8958
template <url_pattern_regex::regex_concept regex_provider>
8959
url_pattern_component_result
8960
url_pattern_component<regex_provider>::create_component_match_result(
8961
    std::string&& input,
8962
    std::vector<std::optional<std::string>>&& exec_result) {
8963
  // Let result be a new URLPatternComponentResult.
8964
  // Set result["input"] to input.
8965
  // Let groups be a record<USVString, (USVString or undefined)>.
8966
  auto result =
8967
      url_pattern_component_result{.input = std::move(input), .groups = {}};
8968
8969
  // Optimization: Let's reserve the size.
8970
  result.groups.reserve(exec_result.size());
8971
8972
  // We explicitly start iterating from 0 even though the spec
8973
  // says we should start from 1. This case is handled by the
8974
  // std_regex_provider.
8975
  for (size_t index = 0; index < exec_result.size(); index++) {
8976
    result.groups.insert({
8977
        group_name_list[index],
8978
        std::move(exec_result[index]),
8979
    });
8980
  }
8981
  return result;
8982
}
8983
8984
template <url_pattern_regex::regex_concept regex_provider>
8985
std::string_view url_pattern<regex_provider>::get_protocol() const
8986
    ada_lifetime_bound {
8987
  // Return this's associated URL pattern's protocol component's pattern string.
8988
  return protocol_component.pattern;
8989
}
8990
template <url_pattern_regex::regex_concept regex_provider>
8991
std::string_view url_pattern<regex_provider>::get_username() const
8992
    ada_lifetime_bound {
8993
  // Return this's associated URL pattern's username component's pattern string.
8994
  return username_component.pattern;
8995
}
8996
template <url_pattern_regex::regex_concept regex_provider>
8997
std::string_view url_pattern<regex_provider>::get_password() const
8998
    ada_lifetime_bound {
8999
  // Return this's associated URL pattern's password component's pattern string.
9000
  return password_component.pattern;
9001
}
9002
template <url_pattern_regex::regex_concept regex_provider>
9003
std::string_view url_pattern<regex_provider>::get_hostname() const
9004
    ada_lifetime_bound {
9005
  // Return this's associated URL pattern's hostname component's pattern string.
9006
  return hostname_component.pattern;
9007
}
9008
template <url_pattern_regex::regex_concept regex_provider>
9009
std::string_view url_pattern<regex_provider>::get_port() const
9010
    ada_lifetime_bound {
9011
  // Return this's associated URL pattern's port component's pattern string.
9012
  return port_component.pattern;
9013
}
9014
template <url_pattern_regex::regex_concept regex_provider>
9015
std::string_view url_pattern<regex_provider>::get_pathname() const
9016
    ada_lifetime_bound {
9017
  // Return this's associated URL pattern's pathname component's pattern string.
9018
  return pathname_component.pattern;
9019
}
9020
template <url_pattern_regex::regex_concept regex_provider>
9021
std::string_view url_pattern<regex_provider>::get_search() const
9022
    ada_lifetime_bound {
9023
  // Return this's associated URL pattern's search component's pattern string.
9024
  return search_component.pattern;
9025
}
9026
template <url_pattern_regex::regex_concept regex_provider>
9027
std::string_view url_pattern<regex_provider>::get_hash() const
9028
    ada_lifetime_bound {
9029
  // Return this's associated URL pattern's hash component's pattern string.
9030
  return hash_component.pattern;
9031
}
9032
template <url_pattern_regex::regex_concept regex_provider>
9033
bool url_pattern<regex_provider>::ignore_case() const {
9034
  return ignore_case_;
9035
}
9036
template <url_pattern_regex::regex_concept regex_provider>
9037
bool url_pattern<regex_provider>::has_regexp_groups() const {
9038
  // If this's associated URL pattern's has regexp groups, then return true.
9039
  return protocol_component.has_regexp_groups ||
9040
         username_component.has_regexp_groups ||
9041
         password_component.has_regexp_groups ||
9042
         hostname_component.has_regexp_groups ||
9043
         port_component.has_regexp_groups ||
9044
         pathname_component.has_regexp_groups ||
9045
         search_component.has_regexp_groups || hash_component.has_regexp_groups;
9046
}
9047
9048
0
inline bool url_pattern_part::is_regexp() const noexcept {
9049
0
  return type == url_pattern_part_type::REGEXP;
9050
0
}
9051
9052
inline std::string_view url_pattern_compile_component_options::get_delimiter()
9053
0
    const {
9054
0
  if (delimiter) {
9055
0
    return {&delimiter.value(), 1};
9056
0
  }
9057
0
  return {};
9058
0
}
9059
9060
inline std::string_view url_pattern_compile_component_options::get_prefix()
9061
0
    const {
9062
0
  if (prefix) {
9063
0
    return {&prefix.value(), 1};
9064
0
  }
9065
0
  return {};
9066
0
}
9067
9068
template <url_pattern_regex::regex_concept regex_provider>
9069
template <url_pattern_encoding_callback F>
9070
tl::expected<url_pattern_component<regex_provider>, errors>
9071
url_pattern_component<regex_provider>::compile(
9072
    std::string_view input, F& encoding_callback,
9073
    url_pattern_compile_component_options& options) {
9074
  ada_log("url_pattern_component::compile input: ", input);
9075
  // Let part list be the result of running parse a pattern string given input,
9076
  // options, and encoding callback.
9077
  auto part_list = url_pattern_helpers::parse_pattern_string(input, options,
9078
                                                             encoding_callback);
9079
9080
  if (!part_list) {
9081
    ada_log("parse_pattern_string failed");
9082
    return tl::unexpected(part_list.error());
9083
  }
9084
9085
  // Let (regular expression string, name list) be the result of running
9086
  // generate a regular expression and name list given part list and options.
9087
  auto [regular_expression_string, name_list] =
9088
      url_pattern_helpers::generate_regular_expression_and_name_list(*part_list,
9089
                                                                     options);
9090
9091
  ada_log("regular expression string: ", regular_expression_string);
9092
9093
  // Let pattern string be the result of running generate a pattern
9094
  // string given part list and options.
9095
  auto pattern_string =
9096
      url_pattern_helpers::generate_pattern_string(*part_list, options);
9097
9098
  // Let regular expression be RegExpCreate(regular expression string,
9099
  // flags). If this throws an exception, catch it, and throw a
9100
  // TypeError.
9101
  std::optional<typename regex_provider::regex_type> regular_expression =
9102
      regex_provider::create_instance(regular_expression_string,
9103
                                      options.ignore_case);
9104
9105
  if (!regular_expression) {
9106
    return tl::unexpected(errors::type_error);
9107
  }
9108
9109
  // For each part of part list:
9110
  // - If part's type is "regexp", then set has regexp groups to true.
9111
  const auto has_regexp = [](const auto& part) { return part.is_regexp(); };
9112
  const bool has_regexp_groups = std::ranges::any_of(*part_list, has_regexp);
9113
9114
  ada_log("has regexp groups: ", has_regexp_groups);
9115
9116
  // Return a new component whose pattern string is pattern string, regular
9117
  // expression is regular expression, group name list is name list, and has
9118
  // regexp groups is has regexp groups.
9119
  return url_pattern_component<regex_provider>(
9120
      std::move(pattern_string), std::move(*regular_expression),
9121
      std::move(name_list), has_regexp_groups);
9122
}
9123
9124
template <url_pattern_regex::regex_concept regex_provider>
9125
result<std::optional<url_pattern_result>> url_pattern<regex_provider>::exec(
9126
    const url_pattern_input& input, const std::string_view* base_url) {
9127
  // Return the result of match given this's associated URL pattern, input, and
9128
  // baseURL if given.
9129
  return match(input, base_url);
9130
}
9131
9132
template <url_pattern_regex::regex_concept regex_provider>
9133
result<bool> url_pattern<regex_provider>::test(
9134
    const url_pattern_input& input, const std::string_view* base_url) {
9135
  // TODO: Optimization opportunity. Rather than returning `url_pattern_result`
9136
  // Implement a fast path just like `can_parse()` in ada_url.
9137
  // Let result be the result of match given this's associated URL pattern,
9138
  // input, and baseURL if given.
9139
  // If result is null, return false.
9140
  if (auto result = match(input, base_url); result.has_value()) {
9141
    return result->has_value();
9142
  }
9143
  return tl::unexpected(errors::type_error);
9144
}
9145
9146
template <url_pattern_regex::regex_concept regex_provider>
9147
result<std::optional<url_pattern_result>> url_pattern<regex_provider>::match(
9148
    const url_pattern_input& input, const std::string_view* base_url_string) {
9149
  std::string protocol{};
9150
  std::string username{};
9151
  std::string password{};
9152
  std::string hostname{};
9153
  std::string port{};
9154
  std::string pathname{};
9155
  std::string search{};
9156
  std::string hash{};
9157
9158
  // Let inputs be an empty list.
9159
  // Append input to inputs.
9160
  std::vector inputs{input};
9161
9162
  // If input is a URLPatternInit then:
9163
  if (std::holds_alternative<url_pattern_init>(input)) {
9164
    ada_log(
9165
        "url_pattern::match called with url_pattern_init and base_url_string=",
9166
        base_url_string);
9167
    // If baseURLString was given, throw a TypeError.
9168
    if (base_url_string) {
9169
      ada_log("failed to match because base_url_string was given");
9170
      return tl::unexpected(errors::type_error);
9171
    }
9172
9173
    // Let applyResult be the result of process a URLPatternInit given input,
9174
    // "url", protocol, username, password, hostname, port, pathname, search,
9175
    // and hash.
9176
    auto apply_result = url_pattern_init::process(
9177
        std::get<url_pattern_init>(input), url_pattern_init::process_type::url,
9178
        protocol, username, password, hostname, port, pathname, search, hash);
9179
9180
    // If this throws an exception, catch it, and return null.
9181
    if (!apply_result.has_value()) {
9182
      ada_log("match returned std::nullopt because process threw");
9183
      return std::nullopt;
9184
    }
9185
9186
    // Set protocol to applyResult["protocol"].
9187
    ADA_ASSERT_TRUE(apply_result->protocol.has_value());
9188
    protocol = std::move(apply_result->protocol.value());
9189
9190
    // Set username to applyResult["username"].
9191
    ADA_ASSERT_TRUE(apply_result->username.has_value());
9192
    username = std::move(apply_result->username.value());
9193
9194
    // Set password to applyResult["password"].
9195
    ADA_ASSERT_TRUE(apply_result->password.has_value());
9196
    password = std::move(apply_result->password.value());
9197
9198
    // Set hostname to applyResult["hostname"].
9199
    ADA_ASSERT_TRUE(apply_result->hostname.has_value());
9200
    hostname = std::move(apply_result->hostname.value());
9201
9202
    // Set port to applyResult["port"].
9203
    ADA_ASSERT_TRUE(apply_result->port.has_value());
9204
    port = std::move(apply_result->port.value());
9205
9206
    // Set pathname to applyResult["pathname"].
9207
    ADA_ASSERT_TRUE(apply_result->pathname.has_value());
9208
    pathname = std::move(apply_result->pathname.value());
9209
9210
    // Set search to applyResult["search"].
9211
    ADA_ASSERT_TRUE(apply_result->search.has_value());
9212
    if (apply_result->search->starts_with("?")) {
9213
      search = apply_result->search->substr(1);
9214
    } else {
9215
      search = std::move(apply_result->search.value());
9216
    }
9217
9218
    // Set hash to applyResult["hash"].
9219
    ADA_ASSERT_TRUE(apply_result->hash.has_value());
9220
    ADA_ASSERT_TRUE(!apply_result->hash->starts_with("#"));
9221
    hash = std::move(apply_result->hash.value());
9222
  } else {
9223
    ADA_ASSERT_TRUE(std::holds_alternative<std::string_view>(input));
9224
9225
    // Let baseURL be null.
9226
    result<url_aggregator> base_url;
9227
9228
    // If baseURLString was given, then:
9229
    if (base_url_string) {
9230
      // Let baseURL be the result of parsing baseURLString.
9231
      base_url = ada::parse<url_aggregator>(*base_url_string, nullptr);
9232
9233
      // If baseURL is failure, return null.
9234
      if (!base_url) {
9235
        ada_log("match returned std::nullopt because failed to parse base_url=",
9236
                *base_url_string);
9237
        return std::nullopt;
9238
      }
9239
9240
      // Append baseURLString to inputs.
9241
      inputs.emplace_back(*base_url_string);
9242
    }
9243
9244
    url_aggregator* base_url_value =
9245
        base_url.has_value() ? &*base_url : nullptr;
9246
9247
    // Set url to the result of parsing input given baseURL.
9248
    auto url = ada::parse<url_aggregator>(std::get<std::string_view>(input),
9249
                                          base_url_value);
9250
9251
    // If url is failure, return null.
9252
    if (!url) {
9253
      ada_log("match returned std::nullopt because url failed");
9254
      return std::nullopt;
9255
    }
9256
9257
    // Set protocol to url's scheme.
9258
    // IMPORTANT: Not documented on the URLPattern spec, but protocol suffix ':'
9259
    // is removed. Similar work was done on workerd:
9260
    // https://github.com/cloudflare/workerd/blob/8620d14012513a6ce04d079e401d3becac3c67bd/src/workerd/jsg/url.c%2B%2B#L2038
9261
    protocol = url->get_protocol().substr(0, url->get_protocol().size() - 1);
9262
    // Set username to url's username.
9263
    username = url->get_username();
9264
    // Set password to url's password.
9265
    password = url->get_password();
9266
    // Set hostname to url's host, serialized, or the empty string if the value
9267
    // is null.
9268
    hostname = url->get_hostname();
9269
    // Set port to url's port, serialized, or the empty string if the value is
9270
    // null.
9271
    port = url->get_port();
9272
    // Set pathname to the result of URL path serializing url.
9273
    pathname = url->get_pathname();
9274
    // Set search to url's query or the empty string if the value is null.
9275
    // IMPORTANT: Not documented on the URLPattern spec, but search prefix '?'
9276
    // is removed. Similar work was done on workerd:
9277
    // https://github.com/cloudflare/workerd/blob/8620d14012513a6ce04d079e401d3becac3c67bd/src/workerd/jsg/url.c%2B%2B#L2232
9278
    if (url->has_search()) {
9279
      auto view = url->get_search();
9280
      search = view.starts_with("?") ? url->get_search().substr(1) : view;
9281
    }
9282
    // Set hash to url's fragment or the empty string if the value is null.
9283
    // IMPORTANT: Not documented on the URLPattern spec, but hash prefix '#' is
9284
    // removed. Similar work was done on workerd:
9285
    // https://github.com/cloudflare/workerd/blob/8620d14012513a6ce04d079e401d3becac3c67bd/src/workerd/jsg/url.c%2B%2B#L2242
9286
    if (url->has_hash()) {
9287
      auto view = url->get_hash();
9288
      hash = view.starts_with("#") ? url->get_hash().substr(1) : view;
9289
    }
9290
  }
9291
9292
  // Let protocolExecResult be RegExpBuiltinExec(urlPattern's protocol
9293
  // component's regular expression, protocol).
9294
  auto protocol_exec_result =
9295
      regex_provider::regex_search(protocol, protocol_component.regexp);
9296
9297
  if (!protocol_exec_result) {
9298
    return std::nullopt;
9299
  }
9300
9301
  // Let usernameExecResult be RegExpBuiltinExec(urlPattern's username
9302
  // component's regular expression, username).
9303
  auto username_exec_result =
9304
      regex_provider::regex_search(username, username_component.regexp);
9305
9306
  if (!username_exec_result) {
9307
    return std::nullopt;
9308
  }
9309
9310
  // Let passwordExecResult be RegExpBuiltinExec(urlPattern's password
9311
  // component's regular expression, password).
9312
  auto password_exec_result =
9313
      regex_provider::regex_search(password, password_component.regexp);
9314
9315
  if (!password_exec_result) {
9316
    return std::nullopt;
9317
  }
9318
9319
  // Let hostnameExecResult be RegExpBuiltinExec(urlPattern's hostname
9320
  // component's regular expression, hostname).
9321
  auto hostname_exec_result =
9322
      regex_provider::regex_search(hostname, hostname_component.regexp);
9323
9324
  if (!hostname_exec_result) {
9325
    return std::nullopt;
9326
  }
9327
9328
  // Let portExecResult be RegExpBuiltinExec(urlPattern's port component's
9329
  // regular expression, port).
9330
  auto port_exec_result =
9331
      regex_provider::regex_search(port, port_component.regexp);
9332
9333
  if (!port_exec_result) {
9334
    return std::nullopt;
9335
  }
9336
9337
  // Let pathnameExecResult be RegExpBuiltinExec(urlPattern's pathname
9338
  // component's regular expression, pathname).
9339
  auto pathname_exec_result =
9340
      regex_provider::regex_search(pathname, pathname_component.regexp);
9341
9342
  if (!pathname_exec_result) {
9343
    return std::nullopt;
9344
  }
9345
9346
  // Let searchExecResult be RegExpBuiltinExec(urlPattern's search component's
9347
  // regular expression, search).
9348
  auto search_exec_result =
9349
      regex_provider::regex_search(search, search_component.regexp);
9350
9351
  if (!search_exec_result) {
9352
    return std::nullopt;
9353
  }
9354
9355
  // Let hashExecResult be RegExpBuiltinExec(urlPattern's hash component's
9356
  // regular expression, hash).
9357
  auto hash_exec_result =
9358
      regex_provider::regex_search(hash, hash_component.regexp);
9359
9360
  if (!hash_exec_result) {
9361
    return std::nullopt;
9362
  }
9363
9364
  // Let result be a new URLPatternResult.
9365
  auto result = url_pattern_result{};
9366
  // Set result["inputs"] to inputs.
9367
  result.inputs = std::move(inputs);
9368
  // Set result["protocol"] to the result of creating a component match result
9369
  // given urlPattern's protocol component, protocol, and protocolExecResult.
9370
  result.protocol = protocol_component.create_component_match_result(
9371
      std::move(protocol), std::move(*protocol_exec_result));
9372
9373
  // Set result["username"] to the result of creating a component match result
9374
  // given urlPattern's username component, username, and usernameExecResult.
9375
  result.username = username_component.create_component_match_result(
9376
      std::move(username), std::move(*username_exec_result));
9377
9378
  // Set result["password"] to the result of creating a component match result
9379
  // given urlPattern's password component, password, and passwordExecResult.
9380
  result.password = password_component.create_component_match_result(
9381
      std::move(password), std::move(*password_exec_result));
9382
9383
  // Set result["hostname"] to the result of creating a component match result
9384
  // given urlPattern's hostname component, hostname, and hostnameExecResult.
9385
  result.hostname = hostname_component.create_component_match_result(
9386
      std::move(hostname), std::move(*hostname_exec_result));
9387
9388
  // Set result["port"] to the result of creating a component match result given
9389
  // urlPattern's port component, port, and portExecResult.
9390
  result.port = port_component.create_component_match_result(
9391
      std::move(port), std::move(*port_exec_result));
9392
9393
  // Set result["pathname"] to the result of creating a component match result
9394
  // given urlPattern's pathname component, pathname, and pathnameExecResult.
9395
  result.pathname = pathname_component.create_component_match_result(
9396
      std::move(pathname), std::move(*pathname_exec_result));
9397
9398
  // Set result["search"] to the result of creating a component match result
9399
  // given urlPattern's search component, search, and searchExecResult.
9400
  result.search = search_component.create_component_match_result(
9401
      std::move(search), std::move(*search_exec_result));
9402
9403
  // Set result["hash"] to the result of creating a component match result given
9404
  // urlPattern's hash component, hash, and hashExecResult.
9405
  result.hash = hash_component.create_component_match_result(
9406
      std::move(hash), std::move(*hash_exec_result));
9407
9408
  return result;
9409
}
9410
9411
}  // namespace ada
9412
#endif  // ADA_INCLUDE_URL_PATTERN
9413
#endif
9414
/* end file include/ada/url_pattern-inl.h */
9415
/* begin file include/ada/url_pattern_helpers-inl.h */
9416
/**
9417
 * @file url_pattern_helpers-inl.h
9418
 * @brief Declaration for the URLPattern helpers.
9419
 */
9420
#ifndef ADA_URL_PATTERN_HELPERS_INL_H
9421
#define ADA_URL_PATTERN_HELPERS_INL_H
9422
9423
#include <optional>
9424
#include <string_view>
9425
9426
9427
#if ADA_INCLUDE_URL_PATTERN
9428
namespace ada::url_pattern_helpers {
9429
#if defined(ADA_TESTING) || defined(ADA_LOGGING)
9430
0
inline std::string to_string(token_type type) {
9431
0
  switch (type) {
9432
0
    case token_type::INVALID_CHAR:
9433
0
      return "INVALID_CHAR";
9434
0
    case token_type::OPEN:
9435
0
      return "OPEN";
9436
0
    case token_type::CLOSE:
9437
0
      return "CLOSE";
9438
0
    case token_type::REGEXP:
9439
0
      return "REGEXP";
9440
0
    case token_type::NAME:
9441
0
      return "NAME";
9442
0
    case token_type::CHAR:
9443
0
      return "CHAR";
9444
0
    case token_type::ESCAPED_CHAR:
9445
0
      return "ESCAPED_CHAR";
9446
0
    case token_type::OTHER_MODIFIER:
9447
0
      return "OTHER_MODIFIER";
9448
0
    case token_type::ASTERISK:
9449
0
      return "ASTERISK";
9450
0
    case token_type::END:
9451
0
      return "END";
9452
0
    default:
9453
0
      ada::unreachable();
9454
0
  }
9455
0
}
9456
#endif  // defined(ADA_TESTING) || defined(ADA_LOGGING)
9457
9458
template <url_pattern_regex::regex_concept regex_provider>
9459
constexpr void constructor_string_parser<regex_provider>::rewind() {
9460
  // Set parser's token index to parser's component start.
9461
  token_index = component_start;
9462
  // Set parser's token increment to 0.
9463
  token_increment = 0;
9464
}
9465
9466
template <url_pattern_regex::regex_concept regex_provider>
9467
constexpr bool constructor_string_parser<regex_provider>::is_hash_prefix() {
9468
  // Return the result of running is a non-special pattern char given parser,
9469
  // parser's token index and "#".
9470
  return is_non_special_pattern_char(token_index, '#');
9471
}
9472
9473
template <url_pattern_regex::regex_concept regex_provider>
9474
constexpr bool constructor_string_parser<regex_provider>::is_search_prefix() {
9475
  // If result of running is a non-special pattern char given parser, parser's
9476
  // token index and "?" is true, then return true.
9477
  if (is_non_special_pattern_char(token_index, '?')) {
9478
    return true;
9479
  }
9480
9481
  // If parser's token list[parser's token index]'s value is not "?", then
9482
  // return false.
9483
  if (token_list[token_index].value != "?") {
9484
    return false;
9485
  }
9486
9487
  // If previous index is less than 0, then return true.
9488
  if (token_index == 0) return true;
9489
  // Let previous index be parser's token index - 1.
9490
  auto previous_index = token_index - 1;
9491
  // Let previous token be the result of running get a safe token given parser
9492
  // and previous index.
9493
  auto previous_token = get_safe_token(previous_index);
9494
  ADA_ASSERT_TRUE(previous_token);
9495
  // If any of the following are true, then return false:
9496
  // - previous token's type is "name".
9497
  // - previous token's type is "regexp".
9498
  // - previous token's type is "close".
9499
  // - previous token's type is "asterisk".
9500
  return !(previous_token->type == token_type::NAME ||
9501
           previous_token->type == token_type::REGEXP ||
9502
           previous_token->type == token_type::CLOSE ||
9503
           previous_token->type == token_type::ASTERISK);
9504
}
9505
9506
template <url_pattern_regex::regex_concept regex_provider>
9507
constexpr bool
9508
constructor_string_parser<regex_provider>::is_non_special_pattern_char(
9509
    size_t index, uint32_t value) const {
9510
  // Let token be the result of running get a safe token given parser and index.
9511
  auto token = get_safe_token(index);
9512
  ADA_ASSERT_TRUE(token);
9513
9514
  // If token's value is not value, then return false.
9515
  // TODO: Remove this once we make sure get_safe_token returns a non-empty
9516
  // string.
9517
  if (!token->value.empty() &&
9518
      static_cast<uint32_t>(token->value[0]) != value) {
9519
    return false;
9520
  }
9521
9522
  // If any of the following are true:
9523
  // - token's type is "char";
9524
  // - token's type is "escaped-char"; or
9525
  // - token's type is "invalid-char",
9526
  // - then return true.
9527
  return token->type == token_type::CHAR ||
9528
         token->type == token_type::ESCAPED_CHAR ||
9529
         token->type == token_type::INVALID_CHAR;
9530
}
9531
9532
template <url_pattern_regex::regex_concept regex_provider>
9533
constexpr const token*
9534
constructor_string_parser<regex_provider>::get_safe_token(size_t index) const {
9535
  // If index is less than parser's token list's size, then return parser's
9536
  // token list[index].
9537
  if (index < token_list.size()) [[likely]] {
9538
    return &token_list[index];
9539
  }
9540
9541
  // Assert: parser's token list's size is greater than or equal to 1.
9542
  ADA_ASSERT_TRUE(!token_list.empty());
9543
9544
  // Let token be parser's token list[last index].
9545
  // Assert: token's type is "end".
9546
  ADA_ASSERT_TRUE(token_list.back().type == token_type::END);
9547
9548
  // Return token.
9549
  return &token_list.back();
9550
}
9551
9552
template <url_pattern_regex::regex_concept regex_provider>
9553
constexpr bool constructor_string_parser<regex_provider>::is_group_open()
9554
    const {
9555
  // If parser's token list[parser's token index]'s type is "open", then return
9556
  // true.
9557
  return token_list[token_index].type == token_type::OPEN;
9558
}
9559
9560
template <url_pattern_regex::regex_concept regex_provider>
9561
constexpr bool constructor_string_parser<regex_provider>::is_group_close()
9562
    const {
9563
  // If parser's token list[parser's token index]'s type is "close", then return
9564
  // true.
9565
  return token_list[token_index].type == token_type::CLOSE;
9566
}
9567
9568
template <url_pattern_regex::regex_concept regex_provider>
9569
constexpr bool
9570
constructor_string_parser<regex_provider>::next_is_authority_slashes() const {
9571
  // If the result of running is a non-special pattern char given parser,
9572
  // parser's token index + 1, and "/" is false, then return false.
9573
  if (!is_non_special_pattern_char(token_index + 1, '/')) {
9574
    return false;
9575
  }
9576
  // If the result of running is a non-special pattern char given parser,
9577
  // parser's token index + 2, and "/" is false, then return false.
9578
  if (!is_non_special_pattern_char(token_index + 2, '/')) {
9579
    return false;
9580
  }
9581
  return true;
9582
}
9583
9584
template <url_pattern_regex::regex_concept regex_provider>
9585
constexpr bool constructor_string_parser<regex_provider>::is_protocol_suffix()
9586
    const {
9587
  // Return the result of running is a non-special pattern char given parser,
9588
  // parser's token index, and ":".
9589
  return is_non_special_pattern_char(token_index, ':');
9590
}
9591
9592
template <url_pattern_regex::regex_concept regex_provider>
9593
void constructor_string_parser<regex_provider>::change_state(State new_state,
9594
                                                             size_t skip) {
9595
  // If parser's state is not "init", not "authority", and not "done", then set
9596
  // parser's result[parser's state] to the result of running make a component
9597
  // string given parser.
9598
  if (state != State::INIT && state != State::AUTHORITY &&
9599
      state != State::DONE) {
9600
    auto value = make_component_string();
9601
    // TODO: Simplify this.
9602
    switch (state) {
9603
      case State::PROTOCOL: {
9604
        result.protocol = value;
9605
        break;
9606
      }
9607
      case State::USERNAME: {
9608
        result.username = value;
9609
        break;
9610
      }
9611
      case State::PASSWORD: {
9612
        result.password = value;
9613
        break;
9614
      }
9615
      case State::HOSTNAME: {
9616
        result.hostname = value;
9617
        break;
9618
      }
9619
      case State::PORT: {
9620
        result.port = value;
9621
        break;
9622
      }
9623
      case State::PATHNAME: {
9624
        result.pathname = value;
9625
        break;
9626
      }
9627
      case State::SEARCH: {
9628
        result.search = value;
9629
        break;
9630
      }
9631
      case State::HASH: {
9632
        result.hash = value;
9633
        break;
9634
      }
9635
      default:
9636
        ada::unreachable();
9637
    }
9638
  }
9639
9640
  // If parser's state is not "init" and new state is not "done", then:
9641
  if (state != State::INIT && new_state != State::DONE) {
9642
    // If parser's state is "protocol", "authority", "username", or "password";
9643
    // new state is "port", "pathname", "search", or "hash"; and parser's
9644
    // result["hostname"] does not exist, then set parser's result["hostname"]
9645
    // to the empty string.
9646
    if ((state == State::PROTOCOL || state == State::AUTHORITY ||
9647
         state == State::USERNAME || state == State::PASSWORD) &&
9648
        (new_state == State::PORT || new_state == State::PATHNAME ||
9649
         new_state == State::SEARCH || new_state == State::HASH) &&
9650
        !result.hostname)
9651
      result.hostname = "";
9652
  }
9653
9654
  // If parser's state is "protocol", "authority", "username", "password",
9655
  // "hostname", or "port"; new state is "search" or "hash"; and parser's
9656
  // result["pathname"] does not exist, then:
9657
  if ((state == State::PROTOCOL || state == State::AUTHORITY ||
9658
       state == State::USERNAME || state == State::PASSWORD ||
9659
       state == State::HOSTNAME || state == State::PORT) &&
9660
      (new_state == State::SEARCH || new_state == State::HASH) &&
9661
      !result.pathname) {
9662
    if (protocol_matches_a_special_scheme_flag) {
9663
      result.pathname = "/";
9664
    } else {
9665
      // Otherwise, set parser's result["pathname"] to the empty string.
9666
      result.pathname = "";
9667
    }
9668
  }
9669
9670
  // If parser's state is "protocol", "authority", "username", "password",
9671
  // "hostname", "port", or "pathname"; new state is "hash"; and parser's
9672
  // result["search"] does not exist, then set parser's result["search"] to
9673
  // the empty string.
9674
  if ((state == State::PROTOCOL || state == State::AUTHORITY ||
9675
       state == State::USERNAME || state == State::PASSWORD ||
9676
       state == State::HOSTNAME || state == State::PORT ||
9677
       state == State::PATHNAME) &&
9678
      new_state == State::HASH && !result.search) {
9679
    result.search = "";
9680
  }
9681
9682
  // Set parser's state to new state.
9683
  state = new_state;
9684
  // Increment parser's token index by skip.
9685
  token_index += skip;
9686
  // Set parser's component start to parser's token index.
9687
  component_start = token_index;
9688
  // Set parser's token increment to 0.
9689
  token_increment = 0;
9690
}
9691
9692
template <url_pattern_regex::regex_concept regex_provider>
9693
std::string constructor_string_parser<regex_provider>::make_component_string() {
9694
  // Assert: parser's token index is less than parser's token list's size.
9695
  ADA_ASSERT_TRUE(token_index < token_list.size());
9696
9697
  // Let token be parser's token list[parser's token index].
9698
  // Let end index be token's index.
9699
  const auto end_index = token_list[token_index].index;
9700
  // Let component start token be the result of running get a safe token given
9701
  // parser and parser's component start.
9702
  const auto component_start_token = get_safe_token(component_start);
9703
  ADA_ASSERT_TRUE(component_start_token);
9704
  // Let component start input index be component start token's index.
9705
  const auto component_start_input_index = component_start_token->index;
9706
  // Return the code point substring from component start input index to end
9707
  // index within parser's input.
9708
  return input.substr(component_start_input_index,
9709
                      end_index - component_start_input_index);
9710
}
9711
9712
template <url_pattern_regex::regex_concept regex_provider>
9713
constexpr bool
9714
constructor_string_parser<regex_provider>::is_an_identity_terminator() const {
9715
  // Return the result of running is a non-special pattern char given parser,
9716
  // parser's token index, and "@".
9717
  return is_non_special_pattern_char(token_index, '@');
9718
}
9719
9720
template <url_pattern_regex::regex_concept regex_provider>
9721
constexpr bool constructor_string_parser<regex_provider>::is_pathname_start()
9722
    const {
9723
  // Return the result of running is a non-special pattern char given parser,
9724
  // parser's token index, and "/".
9725
  return is_non_special_pattern_char(token_index, '/');
9726
}
9727
9728
template <url_pattern_regex::regex_concept regex_provider>
9729
constexpr bool constructor_string_parser<regex_provider>::is_password_prefix()
9730
    const {
9731
  // Return the result of running is a non-special pattern char given parser,
9732
  // parser's token index, and ":".
9733
  return is_non_special_pattern_char(token_index, ':');
9734
}
9735
9736
template <url_pattern_regex::regex_concept regex_provider>
9737
constexpr bool constructor_string_parser<regex_provider>::is_an_ipv6_open()
9738
    const {
9739
  // Return the result of running is a non-special pattern char given parser,
9740
  // parser's token index, and "[".
9741
  return is_non_special_pattern_char(token_index, '[');
9742
}
9743
9744
template <url_pattern_regex::regex_concept regex_provider>
9745
constexpr bool constructor_string_parser<regex_provider>::is_an_ipv6_close()
9746
    const {
9747
  // Return the result of running is a non-special pattern char given parser,
9748
  // parser's token index, and "]".
9749
  return is_non_special_pattern_char(token_index, ']');
9750
}
9751
9752
template <url_pattern_regex::regex_concept regex_provider>
9753
constexpr bool constructor_string_parser<regex_provider>::is_port_prefix()
9754
    const {
9755
  // Return the result of running is a non-special pattern char given parser,
9756
  // parser's token index, and ":".
9757
  return is_non_special_pattern_char(token_index, ':');
9758
}
9759
9760
0
constexpr void Tokenizer::get_next_code_point() {
9761
0
  ada_log("Tokenizer::get_next_code_point called with index=", next_index);
9762
0
  ADA_ASSERT_TRUE(next_index < input.size());
9763
  // this assumes that we have a valid, non-truncated UTF-8 stream.
9764
0
  code_point = 0;
9765
0
  size_t number_bytes = 0;
9766
0
  unsigned char first_byte = input[next_index];
9767
9768
0
  if ((first_byte & 0x80) == 0) {
9769
    // 1-byte character (ASCII)
9770
0
    next_index++;
9771
0
    code_point = first_byte;
9772
0
    ada_log("Tokenizer::get_next_code_point returning ASCII code point=",
9773
0
            uint32_t(code_point));
9774
0
    ada_log("Tokenizer::get_next_code_point next_index =", next_index,
9775
0
            " input.size()=", input.size());
9776
0
    return;
9777
0
  }
9778
0
  ada_log("Tokenizer::get_next_code_point read first byte=",
9779
0
          uint32_t(first_byte));
9780
0
  if ((first_byte & 0xE0) == 0xC0) {
9781
0
    code_point = first_byte & 0x1F;
9782
0
    number_bytes = 2;
9783
0
    ada_log("Tokenizer::get_next_code_point two bytes");
9784
0
  } else if ((first_byte & 0xF0) == 0xE0) {
9785
0
    code_point = first_byte & 0x0F;
9786
0
    number_bytes = 3;
9787
0
    ada_log("Tokenizer::get_next_code_point three bytes");
9788
0
  } else if ((first_byte & 0xF8) == 0xF0) {
9789
0
    code_point = first_byte & 0x07;
9790
0
    number_bytes = 4;
9791
0
    ada_log("Tokenizer::get_next_code_point four bytes");
9792
0
  }
9793
0
  ADA_ASSERT_TRUE(number_bytes + next_index <= input.size());
9794
9795
0
  for (size_t i = 1 + next_index; i < number_bytes + next_index; ++i) {
9796
0
    unsigned char byte = input[i];
9797
0
    ada_log("Tokenizer::get_next_code_point read byte=", uint32_t(byte));
9798
0
    code_point = (code_point << 6) | (byte & 0x3F);
9799
0
  }
9800
0
  ada_log("Tokenizer::get_next_code_point returning non-ASCII code point=",
9801
0
          uint32_t(code_point));
9802
0
  ada_log("Tokenizer::get_next_code_point next_index =", next_index,
9803
0
          " input.size()=", input.size());
9804
0
  next_index += number_bytes;
9805
0
}
9806
9807
0
constexpr void Tokenizer::seek_and_get_next_code_point(size_t new_index) {
9808
0
  ada_log("Tokenizer::seek_and_get_next_code_point called with new_index=",
9809
0
          new_index);
9810
  // Set tokenizer's next index to index.
9811
0
  next_index = new_index;
9812
  // Run get the next code point given tokenizer.
9813
0
  get_next_code_point();
9814
0
}
9815
9816
inline void Tokenizer::add_token(token_type type, size_t next_position,
9817
0
                                 size_t value_position, size_t value_length) {
9818
0
  ada_log("Tokenizer::add_token called with type=", to_string(type),
9819
0
          " next_position=", next_position, " value_position=", value_position);
9820
0
  ADA_ASSERT_TRUE(next_position >= value_position);
9821
9822
  // Let token be a new token.
9823
  // Set token's type to type.
9824
  // Set token's index to tokenizer's index.
9825
  // Set token's value to the code point substring from value position with
9826
  // length value length within tokenizer's input.
9827
  // Append token to the back of tokenizer's token list.
9828
0
  token_list.emplace_back(type, index,
9829
0
                          input.substr(value_position, value_length));
9830
  // Set tokenizer's index to next position.
9831
0
  index = next_position;
9832
0
}
9833
9834
inline void Tokenizer::add_token_with_default_length(token_type type,
9835
                                                     size_t next_position,
9836
0
                                                     size_t value_position) {
9837
  // Let computed length be next position - value position.
9838
0
  auto computed_length = next_position - value_position;
9839
  // Run add a token given tokenizer, type, next position, value position, and
9840
  // computed length.
9841
0
  add_token(type, next_position, value_position, computed_length);
9842
0
}
9843
9844
0
inline void Tokenizer::add_token_with_defaults(token_type type) {
9845
0
  ada_log("Tokenizer::add_token_with_defaults called with type=",
9846
0
          to_string(type));
9847
  // Run add a token with default length given tokenizer, type, tokenizer's next
9848
  // index, and tokenizer's index.
9849
0
  add_token_with_default_length(type, next_index, index);
9850
0
}
9851
9852
inline ada_warn_unused std::optional<errors>
9853
Tokenizer::process_tokenizing_error(size_t next_position,
9854
0
                                    size_t value_position) {
9855
  // If tokenizer's policy is "strict", then throw a TypeError.
9856
0
  if (policy == token_policy::strict) {
9857
0
    ada_log("process_tokenizing_error failed with next_position=",
9858
0
            next_position, " value_position=", value_position);
9859
0
    return errors::type_error;
9860
0
  }
9861
  // Assert: tokenizer's policy is "lenient".
9862
0
  ADA_ASSERT_TRUE(policy == token_policy::lenient);
9863
  // Run add a token with default length given tokenizer, "invalid-char", next
9864
  // position, and value position.
9865
0
  add_token_with_default_length(token_type::INVALID_CHAR, next_position,
9866
0
                                value_position);
9867
0
  return std::nullopt;
9868
0
}
9869
9870
template <url_pattern_encoding_callback F>
9871
token* url_pattern_parser<F>::try_consume_modifier_token() {
9872
  // Let token be the result of running try to consume a token given parser and
9873
  // "other-modifier".
9874
  auto token = try_consume_token(token_type::OTHER_MODIFIER);
9875
  // If token is not null, then return token.
9876
  if (token) return token;
9877
  // Set token to the result of running try to consume a token given parser and
9878
  // "asterisk".
9879
  // Return token.
9880
  return try_consume_token(token_type::ASTERISK);
9881
}
9882
9883
template <url_pattern_encoding_callback F>
9884
token* url_pattern_parser<F>::try_consume_regexp_or_wildcard_token(
9885
    const token* name_token) {
9886
  // Let token be the result of running try to consume a token given parser and
9887
  // "regexp".
9888
  auto token = try_consume_token(token_type::REGEXP);
9889
  // If name token is null and token is null, then set token to the result of
9890
  // running try to consume a token given parser and "asterisk".
9891
  if (!name_token && !token) {
9892
    token = try_consume_token(token_type::ASTERISK);
9893
  }
9894
  // Return token.
9895
  return token;
9896
}
9897
9898
template <url_pattern_encoding_callback F>
9899
token* url_pattern_parser<F>::try_consume_token(token_type type) {
9900
  ada_log("url_pattern_parser::try_consume_token called with type=",
9901
          to_string(type));
9902
  // Assert: parser's index is less than parser's token list size.
9903
  ADA_ASSERT_TRUE(index < tokens.size());
9904
  // Let next token be parser's token list[parser's index].
9905
  auto& next_token = tokens[index];
9906
  // If next token's type is not type return null.
9907
  if (next_token.type != type) return nullptr;
9908
  // Increase parser's index by 1.
9909
  index++;
9910
  // Return next token.
9911
  return &next_token;
9912
}
9913
9914
template <url_pattern_encoding_callback F>
9915
std::string url_pattern_parser<F>::consume_text() {
9916
  // Let result be the empty string.
9917
  std::string result{};
9918
  // While true:
9919
  while (true) {
9920
    // Let token be the result of running try to consume a token given parser
9921
    // and "char".
9922
    auto token = try_consume_token(token_type::CHAR);
9923
    // If token is null, then set token to the result of running try to consume
9924
    // a token given parser and "escaped-char".
9925
    if (!token) token = try_consume_token(token_type::ESCAPED_CHAR);
9926
    // If token is null, then break.
9927
    if (!token) break;
9928
    // Append token's value to the end of result.
9929
    result.append(token->value);
9930
  }
9931
  // Return result.
9932
  return result;
9933
}
9934
9935
template <url_pattern_encoding_callback F>
9936
bool url_pattern_parser<F>::consume_required_token(token_type type) {
9937
  ada_log("url_pattern_parser::consume_required_token called with type=",
9938
          to_string(type));
9939
  // Let result be the result of running try to consume a token given parser and
9940
  // type.
9941
  return try_consume_token(type) != nullptr;
9942
}
9943
9944
template <url_pattern_encoding_callback F>
9945
std::optional<errors>
9946
url_pattern_parser<F>::maybe_add_part_from_the_pending_fixed_value() {
9947
  // If parser's pending fixed value is the empty string, then return.
9948
  if (pending_fixed_value.empty()) {
9949
    ada_log("pending_fixed_value is empty");
9950
    return std::nullopt;
9951
  }
9952
  // Let encoded value be the result of running parser's encoding callback given
9953
  // parser's pending fixed value.
9954
  auto encoded_value = encoding_callback(pending_fixed_value);
9955
  if (!encoded_value) {
9956
    ada_log("failed to encode pending_fixed_value: ", pending_fixed_value);
9957
    return encoded_value.error();
9958
  }
9959
  // Set parser's pending fixed value to the empty string.
9960
  pending_fixed_value.clear();
9961
  // Let part be a new part whose type is "fixed-text", value is encoded value,
9962
  // and modifier is "none".
9963
  // Append part to parser's part list.
9964
  parts.emplace_back(url_pattern_part_type::FIXED_TEXT,
9965
                     std::move(*encoded_value),
9966
                     url_pattern_part_modifier::none);
9967
  return std::nullopt;
9968
}
9969
9970
template <url_pattern_encoding_callback F>
9971
std::optional<errors> url_pattern_parser<F>::add_part(
9972
    std::string_view prefix, token* name_token, token* regexp_or_wildcard_token,
9973
    std::string_view suffix, token* modifier_token) {
9974
  // Let modifier be "none".
9975
  auto modifier = url_pattern_part_modifier::none;
9976
  // If modifier token is not null:
9977
  if (modifier_token) {
9978
    // If modifier token's value is "?" then set modifier to "optional".
9979
    if (modifier_token->value == "?") {
9980
      modifier = url_pattern_part_modifier::optional;
9981
    } else if (modifier_token->value == "*") {
9982
      // Otherwise if modifier token's value is "*" then set modifier to
9983
      // "zero-or-more".
9984
      modifier = url_pattern_part_modifier::zero_or_more;
9985
    } else if (modifier_token->value == "+") {
9986
      // Otherwise if modifier token's value is "+" then set modifier to
9987
      // "one-or-more".
9988
      modifier = url_pattern_part_modifier::one_or_more;
9989
    }
9990
  }
9991
  // If name token is null and regexp or wildcard token is null and modifier
9992
  // is "none":
9993
  if (!name_token && !regexp_or_wildcard_token &&
9994
      modifier == url_pattern_part_modifier::none) {
9995
    // Append prefix to the end of parser's pending fixed value.
9996
    pending_fixed_value.append(prefix);
9997
    return std::nullopt;
9998
  }
9999
  // Run maybe add a part from the pending fixed value given parser.
10000
  if (auto error = maybe_add_part_from_the_pending_fixed_value()) {
10001
    return *error;
10002
  }
10003
  // If name token is null and regexp or wildcard token is null:
10004
  if (!name_token && !regexp_or_wildcard_token) {
10005
    // Assert: suffix is the empty string.
10006
    ADA_ASSERT_TRUE(suffix.empty());
10007
    // If prefix is the empty string, then return.
10008
    if (prefix.empty()) return std::nullopt;
10009
    // Let encoded value be the result of running parser's encoding callback
10010
    // given prefix.
10011
    auto encoded_value = encoding_callback(prefix);
10012
    if (!encoded_value) {
10013
      return encoded_value.error();
10014
    }
10015
    // Let part be a new part whose type is "fixed-text", value is encoded
10016
    // value, and modifier is modifier.
10017
    // Append part to parser's part list.
10018
    parts.emplace_back(url_pattern_part_type::FIXED_TEXT,
10019
                       std::move(*encoded_value), modifier);
10020
    return std::nullopt;
10021
  }
10022
  // Let regexp value be the empty string.
10023
  std::string regexp_value{};
10024
  // If regexp or wildcard token is null, then set regexp value to parser's
10025
  // segment wildcard regexp.
10026
  if (!regexp_or_wildcard_token) {
10027
    regexp_value = segment_wildcard_regexp;
10028
  } else if (regexp_or_wildcard_token->type == token_type::ASTERISK) {
10029
    // Otherwise if regexp or wildcard token's type is "asterisk", then set
10030
    // regexp value to the full wildcard regexp value.
10031
    regexp_value = ".*";
10032
  } else {
10033
    // Otherwise set regexp value to regexp or wildcard token's value.
10034
    regexp_value = regexp_or_wildcard_token->value;
10035
  }
10036
  // Let type be "regexp".
10037
  auto type = url_pattern_part_type::REGEXP;
10038
  // If regexp value is parser's segment wildcard regexp:
10039
  if (regexp_value == segment_wildcard_regexp) {
10040
    // Set type to "segment-wildcard".
10041
    type = url_pattern_part_type::SEGMENT_WILDCARD;
10042
    // Set regexp value to the empty string.
10043
    regexp_value.clear();
10044
  } else if (regexp_value == ".*") {
10045
    // Otherwise if regexp value is the full wildcard regexp value:
10046
    // Set type to "full-wildcard".
10047
    type = url_pattern_part_type::FULL_WILDCARD;
10048
    // Set regexp value to the empty string.
10049
    regexp_value.clear();
10050
  }
10051
  // Let name be the empty string.
10052
  std::string name{};
10053
  // If name token is not null, then set name to name token's value.
10054
  if (name_token) {
10055
    name = name_token->value;
10056
  } else if (regexp_or_wildcard_token != nullptr) {
10057
    // Otherwise if regexp or wildcard token is not null:
10058
    // Set name to parser's next numeric name, serialized.
10059
    name = std::to_string(next_numeric_name);
10060
    // Increment parser's next numeric name by 1.
10061
    next_numeric_name++;
10062
  }
10063
  // If the result of running is a duplicate name given parser and name is
10064
  // true, then throw a TypeError.
10065
  if (std::ranges::any_of(
10066
          parts, [&name](const auto& part) { return part.name == name; })) {
10067
    return errors::type_error;
10068
  }
10069
  // Let encoded prefix be the result of running parser's encoding callback
10070
  // given prefix.
10071
  auto encoded_prefix = encoding_callback(prefix);
10072
  if (!encoded_prefix) return encoded_prefix.error();
10073
  // Let encoded suffix be the result of running parser's encoding callback
10074
  // given suffix.
10075
  auto encoded_suffix = encoding_callback(suffix);
10076
  if (!encoded_suffix) return encoded_suffix.error();
10077
  // Let part be a new part whose type is type, value is regexp value,
10078
  // modifier is modifier, name is name, prefix is encoded prefix, and suffix
10079
  // is encoded suffix.
10080
  // Append part to parser's part list.
10081
  parts.emplace_back(type, std::move(regexp_value), modifier, std::move(name),
10082
                     std::move(*encoded_prefix), std::move(*encoded_suffix));
10083
  return std::nullopt;
10084
}
10085
10086
template <url_pattern_encoding_callback F>
10087
tl::expected<std::vector<url_pattern_part>, errors> parse_pattern_string(
10088
    std::string_view input, url_pattern_compile_component_options& options,
10089
    F& encoding_callback) {
10090
  ada_log("parse_pattern_string input=", input);
10091
  // Let parser be a new pattern parser whose encoding callback is encoding
10092
  // callback and segment wildcard regexp is the result of running generate a
10093
  // segment wildcard regexp given options.
10094
  auto parser = url_pattern_parser<F>(
10095
      encoding_callback, generate_segment_wildcard_regexp(options));
10096
  // Set parser's token list to the result of running tokenize given input and
10097
  // "strict".
10098
  auto tokenize_result = tokenize(input, token_policy::strict);
10099
  if (!tokenize_result) {
10100
    ada_log("parse_pattern_string tokenize failed");
10101
    return tl::unexpected(tokenize_result.error());
10102
  }
10103
  parser.tokens = std::move(*tokenize_result);
10104
10105
  // While parser's index is less than parser's token list's size:
10106
  while (parser.can_continue()) {
10107
    // Let char token be the result of running try to consume a token given
10108
    // parser and "char".
10109
    auto char_token = parser.try_consume_token(token_type::CHAR);
10110
    // Let name token be the result of running try to consume a token given
10111
    // parser and "name".
10112
    auto name_token = parser.try_consume_token(token_type::NAME);
10113
    // Let regexp or wildcard token be the result of running try to consume a
10114
    // regexp or wildcard token given parser and name token.
10115
    auto regexp_or_wildcard_token =
10116
        parser.try_consume_regexp_or_wildcard_token(name_token);
10117
    // If name token is not null or regexp or wildcard token is not null:
10118
    if (name_token || regexp_or_wildcard_token) {
10119
      // Let prefix be the empty string.
10120
      std::string prefix{};
10121
      // If char token is not null then set prefix to char token's value.
10122
      if (char_token) prefix = char_token->value;
10123
      // If prefix is not the empty string and not options's prefix code point:
10124
      if (!prefix.empty() && prefix != options.get_prefix()) {
10125
        // Append prefix to the end of parser's pending fixed value.
10126
        parser.pending_fixed_value.append(prefix);
10127
        // Set prefix to the empty string.
10128
        prefix.clear();
10129
      }
10130
      // Run maybe add a part from the pending fixed value given parser.
10131
      if (auto error = parser.maybe_add_part_from_the_pending_fixed_value()) {
10132
        ada_log("maybe_add_part_from_the_pending_fixed_value failed");
10133
        return tl::unexpected(*error);
10134
      }
10135
      // Let modifier token be the result of running try to consume a modifier
10136
      // token given parser.
10137
      auto modifier_token = parser.try_consume_modifier_token();
10138
      // Run add a part given parser, prefix, name token, regexp or wildcard
10139
      // token, the empty string, and modifier token.
10140
      if (auto error =
10141
              parser.add_part(prefix, name_token, regexp_or_wildcard_token, "",
10142
                              modifier_token)) {
10143
        ada_log("parser.add_part failed");
10144
        return tl::unexpected(*error);
10145
      }
10146
      // Continue.
10147
      continue;
10148
    }
10149
10150
    // Let fixed token be char token.
10151
    auto fixed_token = char_token;
10152
    // If fixed token is null, then set fixed token to the result of running try
10153
    // to consume a token given parser and "escaped-char".
10154
    if (!fixed_token)
10155
      fixed_token = parser.try_consume_token(token_type::ESCAPED_CHAR);
10156
    // If fixed token is not null:
10157
    if (fixed_token) {
10158
      // Append fixed token's value to parser's pending fixed value.
10159
      parser.pending_fixed_value.append(fixed_token->value);
10160
      // Continue.
10161
      continue;
10162
    }
10163
    // Let open token be the result of running try to consume a token given
10164
    // parser and "open".
10165
    auto open_token = parser.try_consume_token(token_type::OPEN);
10166
    // If open token is not null:
10167
    if (open_token) {
10168
      // Set prefix be the result of running consume text given parser.
10169
      auto prefix_ = parser.consume_text();
10170
      // Set name token to the result of running try to consume a token given
10171
      // parser and "name".
10172
      name_token = parser.try_consume_token(token_type::NAME);
10173
      // Set regexp or wildcard token to the result of running try to consume a
10174
      // regexp or wildcard token given parser and name token.
10175
      regexp_or_wildcard_token =
10176
          parser.try_consume_regexp_or_wildcard_token(name_token);
10177
      // Let suffix be the result of running consume text given parser.
10178
      auto suffix_ = parser.consume_text();
10179
      // Run consume a required token given parser and "close".
10180
      if (!parser.consume_required_token(token_type::CLOSE)) {
10181
        ada_log("parser.consume_required_token failed");
10182
        return tl::unexpected(errors::type_error);
10183
      }
10184
      // Set modifier token to the result of running try to consume a modifier
10185
      // token given parser.
10186
      auto modifier_token = parser.try_consume_modifier_token();
10187
      // Run add a part given parser, prefix, name token, regexp or wildcard
10188
      // token, suffix, and modifier token.
10189
      if (auto error =
10190
              parser.add_part(prefix_, name_token, regexp_or_wildcard_token,
10191
                              suffix_, modifier_token)) {
10192
        return tl::unexpected(*error);
10193
      }
10194
      // Continue.
10195
      continue;
10196
    }
10197
    // Run maybe add a part from the pending fixed value given parser.
10198
    if (auto error = parser.maybe_add_part_from_the_pending_fixed_value()) {
10199
      ada_log("maybe_add_part_from_the_pending_fixed_value failed on line 992");
10200
      return tl::unexpected(*error);
10201
    }
10202
    // Run consume a required token given parser and "end".
10203
    if (!parser.consume_required_token(token_type::END)) {
10204
      return tl::unexpected(errors::type_error);
10205
    }
10206
  }
10207
  ada_log("parser.parts size is: ", parser.parts.size());
10208
  // Return parser's part list.
10209
  return parser.parts;
10210
}
10211
10212
template <url_pattern_regex::regex_concept regex_provider>
10213
bool protocol_component_matches_special_scheme(
10214
    url_pattern_component<regex_provider>& component) {
10215
  // let's avoid unnecessary copy here.
10216
  auto& regex = component.regexp;
10217
  return regex_provider::regex_match("http", regex) ||
10218
         regex_provider::regex_match("https", regex) ||
10219
         regex_provider::regex_match("ws", regex) ||
10220
         regex_provider::regex_match("wss", regex) ||
10221
         regex_provider::regex_match("ftp", regex);
10222
}
10223
10224
template <url_pattern_regex::regex_concept regex_provider>
10225
inline std::optional<errors> constructor_string_parser<
10226
    regex_provider>::compute_protocol_matches_special_scheme_flag() {
10227
  ada_log(
10228
      "constructor_string_parser::compute_protocol_matches_special_scheme_"
10229
      "flag");
10230
  // Let protocol string be the result of running make a component string given
10231
  // parser.
10232
  auto protocol_string = make_component_string();
10233
  // Let protocol component be the result of compiling a component given
10234
  // protocol string, canonicalize a protocol, and default options.
10235
  auto protocol_component = url_pattern_component<regex_provider>::compile(
10236
      protocol_string, canonicalize_protocol,
10237
      url_pattern_compile_component_options::DEFAULT);
10238
  if (!protocol_component) {
10239
    ada_log("url_pattern_component::compile failed for protocol_string ",
10240
            protocol_string);
10241
    return protocol_component.error();
10242
  }
10243
  // If the result of running protocol component matches a special scheme given
10244
  // protocol component is true, then set parser's protocol matches a special
10245
  // scheme flag to true.
10246
  if (protocol_component_matches_special_scheme(*protocol_component)) {
10247
    protocol_matches_a_special_scheme_flag = true;
10248
  }
10249
  return std::nullopt;
10250
}
10251
10252
template <url_pattern_regex::regex_concept regex_provider>
10253
tl::expected<url_pattern_init, errors>
10254
constructor_string_parser<regex_provider>::parse(std::string_view input) {
10255
  ada_log("constructor_string_parser::parse input=", input);
10256
  // Let parser be a new constructor string parser whose input is input and
10257
  // token list is the result of running tokenize given input and "lenient".
10258
  auto token_list = tokenize(input, token_policy::lenient);
10259
  if (!token_list) {
10260
    return tl::unexpected(token_list.error());
10261
  }
10262
  auto parser = constructor_string_parser(input, std::move(*token_list));
10263
10264
  // While parser's token index is less than parser's token list size:
10265
  while (parser.token_index < parser.token_list.size()) {
10266
    // Set parser's token increment to 1.
10267
    parser.token_increment = 1;
10268
10269
    // If parser's token list[parser's token index]'s type is "end" then:
10270
    if (parser.token_list[parser.token_index].type == token_type::END) {
10271
      // If parser's state is "init":
10272
      if (parser.state == State::INIT) {
10273
        // Run rewind given parser.
10274
        parser.rewind();
10275
        // If the result of running is a hash prefix given parser is true, then
10276
        // run change state given parser, "hash" and 1.
10277
        if (parser.is_hash_prefix()) {
10278
          parser.change_state(State::HASH, 1);
10279
        } else if (parser.is_search_prefix()) {
10280
          // Otherwise if the result of running is a search prefix given parser
10281
          // is true: Run change state given parser, "search" and 1.
10282
          parser.change_state(State::SEARCH, 1);
10283
        } else {
10284
          // Run change state given parser, "pathname" and 0.
10285
          parser.change_state(State::PATHNAME, 0);
10286
        }
10287
        // Increment parser's token index by parser's token increment.
10288
        parser.token_index += parser.token_increment;
10289
        // Continue.
10290
        continue;
10291
      }
10292
10293
      if (parser.state == State::AUTHORITY) {
10294
        // If parser's state is "authority":
10295
        // Run rewind and set state given parser, and "hostname".
10296
        parser.rewind();
10297
        parser.change_state(State::HOSTNAME, 0);
10298
        // Increment parser's token index by parser's token increment.
10299
        parser.token_index += parser.token_increment;
10300
        // Continue.
10301
        continue;
10302
      }
10303
10304
      // Run change state given parser, "done" and 0.
10305
      parser.change_state(State::DONE, 0);
10306
      // Break.
10307
      break;
10308
    }
10309
10310
    // If the result of running is a group open given parser is true:
10311
    if (parser.is_group_open()) {
10312
      // Increment parser's group depth by 1.
10313
      parser.group_depth += 1;
10314
      // Increment parser's token index by parser's token increment.
10315
      parser.token_index += parser.token_increment;
10316
    }
10317
10318
    // If parser's group depth is greater than 0:
10319
    if (parser.group_depth > 0) {
10320
      // If the result of running is a group close given parser is true, then
10321
      // decrement parser's group depth by 1.
10322
      if (parser.is_group_close()) {
10323
        parser.group_depth -= 1;
10324
      } else {
10325
        // Increment parser's token index by parser's token increment.
10326
        parser.token_index += parser.token_increment;
10327
        continue;
10328
      }
10329
    }
10330
10331
    // Switch on parser's state and run the associated steps:
10332
    switch (parser.state) {
10333
      case State::INIT: {
10334
        // If the result of running is a protocol suffix given parser is true:
10335
        if (parser.is_protocol_suffix()) {
10336
          // Run rewind and set state given parser and "protocol".
10337
          parser.rewind();
10338
          parser.change_state(State::PROTOCOL, 0);
10339
        }
10340
        break;
10341
      }
10342
      case State::PROTOCOL: {
10343
        // If the result of running is a protocol suffix given parser is true:
10344
        if (parser.is_protocol_suffix()) {
10345
          // Run compute protocol matches a special scheme flag given parser.
10346
          if (const auto error =
10347
                  parser.compute_protocol_matches_special_scheme_flag()) {
10348
            ada_log("compute_protocol_matches_special_scheme_flag failed");
10349
            return tl::unexpected(*error);
10350
          }
10351
          // Let next state be "pathname".
10352
          auto next_state = State::PATHNAME;
10353
          // Let skip be 1.
10354
          auto skip = 1;
10355
          // If the result of running next is authority slashes given parser is
10356
          // true:
10357
          if (parser.next_is_authority_slashes()) {
10358
            // Set next state to "authority".
10359
            next_state = State::AUTHORITY;
10360
            // Set skip to 3.
10361
            skip = 3;
10362
          } else if (parser.protocol_matches_a_special_scheme_flag) {
10363
            // Otherwise if parser's protocol matches a special scheme flag is
10364
            // true, then set next state to "authority".
10365
            next_state = State::AUTHORITY;
10366
          }
10367
10368
          // Run change state given parser, next state, and skip.
10369
          parser.change_state(next_state, skip);
10370
        }
10371
        break;
10372
      }
10373
      case State::AUTHORITY: {
10374
        // If the result of running is an identity terminator given parser is
10375
        // true, then run rewind and set state given parser and "username".
10376
        if (parser.is_an_identity_terminator()) {
10377
          parser.rewind();
10378
          parser.change_state(State::USERNAME, 0);
10379
        } else if (parser.is_pathname_start() || parser.is_search_prefix() ||
10380
                   parser.is_hash_prefix()) {
10381
          // Otherwise if any of the following are true:
10382
          // - the result of running is a pathname start given parser;
10383
          // - the result of running is a search prefix given parser; or
10384
          // - the result of running is a hash prefix given parser,
10385
          // then run rewind and set state given parser and "hostname".
10386
          parser.rewind();
10387
          parser.change_state(State::HOSTNAME, 0);
10388
        }
10389
        break;
10390
      }
10391
      case State::USERNAME: {
10392
        // If the result of running is a password prefix given parser is true,
10393
        // then run change state given parser, "password", and 1.
10394
        if (parser.is_password_prefix()) {
10395
          parser.change_state(State::PASSWORD, 1);
10396
        } else if (parser.is_an_identity_terminator()) {
10397
          // Otherwise if the result of running is an identity terminator given
10398
          // parser is true, then run change state given parser, "hostname",
10399
          // and 1.
10400
          parser.change_state(State::HOSTNAME, 1);
10401
        }
10402
        break;
10403
      }
10404
      case State::PASSWORD: {
10405
        // If the result of running is an identity terminator given parser is
10406
        // true, then run change state given parser, "hostname", and 1.
10407
        if (parser.is_an_identity_terminator()) {
10408
          parser.change_state(State::HOSTNAME, 1);
10409
        }
10410
        break;
10411
      }
10412
      case State::HOSTNAME: {
10413
        // If the result of running is an IPv6 open given parser is true, then
10414
        // increment parser's hostname IPv6 bracket depth by 1.
10415
        if (parser.is_an_ipv6_open()) {
10416
          parser.hostname_ipv6_bracket_depth += 1;
10417
        } else if (parser.is_an_ipv6_close()) {
10418
          // Otherwise if the result of running is an IPv6 close given parser is
10419
          // true, then decrement parser's hostname IPv6 bracket depth by 1.
10420
          parser.hostname_ipv6_bracket_depth -= 1;
10421
        } else if (parser.is_port_prefix() &&
10422
                   parser.hostname_ipv6_bracket_depth == 0) {
10423
          // Otherwise if the result of running is a port prefix given parser is
10424
          // true and parser's hostname IPv6 bracket depth is zero, then run
10425
          // change state given parser, "port", and 1.
10426
          parser.change_state(State::PORT, 1);
10427
        } else if (parser.is_pathname_start()) {
10428
          // Otherwise if the result of running is a pathname start given parser
10429
          // is true, then run change state given parser, "pathname", and 0.
10430
          parser.change_state(State::PATHNAME, 0);
10431
        } else if (parser.is_search_prefix()) {
10432
          // Otherwise if the result of running is a search prefix given parser
10433
          // is true, then run change state given parser, "search", and 1.
10434
          parser.change_state(State::SEARCH, 1);
10435
        } else if (parser.is_hash_prefix()) {
10436
          // Otherwise if the result of running is a hash prefix given parser is
10437
          // true, then run change state given parser, "hash", and 1.
10438
          parser.change_state(State::HASH, 1);
10439
        }
10440
10441
        break;
10442
      }
10443
      case State::PORT: {
10444
        // If the result of running is a pathname start given parser is true,
10445
        // then run change state given parser, "pathname", and 0.
10446
        if (parser.is_pathname_start()) {
10447
          parser.change_state(State::PATHNAME, 0);
10448
        } else if (parser.is_search_prefix()) {
10449
          // Otherwise if the result of running is a search prefix given parser
10450
          // is true, then run change state given parser, "search", and 1.
10451
          parser.change_state(State::SEARCH, 1);
10452
        } else if (parser.is_hash_prefix()) {
10453
          // Otherwise if the result of running is a hash prefix given parser is
10454
          // true, then run change state given parser, "hash", and 1.
10455
          parser.change_state(State::HASH, 1);
10456
        }
10457
        break;
10458
      }
10459
      case State::PATHNAME: {
10460
        // If the result of running is a search prefix given parser is true,
10461
        // then run change state given parser, "search", and 1.
10462
        if (parser.is_search_prefix()) {
10463
          parser.change_state(State::SEARCH, 1);
10464
        } else if (parser.is_hash_prefix()) {
10465
          // Otherwise if the result of running is a hash prefix given parser is
10466
          // true, then run change state given parser, "hash", and 1.
10467
          parser.change_state(State::HASH, 1);
10468
        }
10469
        break;
10470
      }
10471
      case State::SEARCH: {
10472
        // If the result of running is a hash prefix given parser is true, then
10473
        // run change state given parser, "hash", and 1.
10474
        if (parser.is_hash_prefix()) {
10475
          parser.change_state(State::HASH, 1);
10476
        }
10477
        break;
10478
      }
10479
      case State::HASH: {
10480
        // Do nothing
10481
        break;
10482
      }
10483
      default: {
10484
        // Assert: This step is never reached.
10485
        unreachable();
10486
      }
10487
    }
10488
10489
    // Increment parser's token index by parser's token increment.
10490
    parser.token_index += parser.token_increment;
10491
  }
10492
10493
  // If parser's result contains "hostname" and not "port", then set parser's
10494
  // result["port"] to the empty string.
10495
  if (parser.result.hostname && !parser.result.port) {
10496
    parser.result.port = "";
10497
  }
10498
10499
  // Return parser's result.
10500
  return parser.result;
10501
}
10502
10503
}  // namespace ada::url_pattern_helpers
10504
#endif  // ADA_INCLUDE_URL_PATTERN
10505
#endif
10506
/* end file include/ada/url_pattern_helpers-inl.h */
10507
10508
// Public API
10509
/* begin file include/ada/ada_version.h */
10510
/**
10511
 * @file ada_version.h
10512
 * @brief Definitions for Ada's version number.
10513
 */
10514
#ifndef ADA_ADA_VERSION_H
10515
#define ADA_ADA_VERSION_H
10516
10517
#define ADA_VERSION "3.2.5"
10518
10519
namespace ada {
10520
10521
enum {
10522
  ADA_VERSION_MAJOR = 3,
10523
  ADA_VERSION_MINOR = 2,
10524
  ADA_VERSION_REVISION = 5,
10525
};
10526
10527
}  // namespace ada
10528
10529
#endif  // ADA_ADA_VERSION_H
10530
/* end file include/ada/ada_version.h */
10531
/* begin file include/ada/implementation-inl.h */
10532
/**
10533
 * @file implementation-inl.h
10534
 */
10535
#ifndef ADA_IMPLEMENTATION_INL_H
10536
#define ADA_IMPLEMENTATION_INL_H
10537
10538
10539
10540
#include <variant>
10541
#include <string_view>
10542
10543
namespace ada {
10544
10545
#if ADA_INCLUDE_URL_PATTERN
10546
template <url_pattern_regex::regex_concept regex_provider>
10547
ada_warn_unused tl::expected<url_pattern<regex_provider>, errors>
10548
parse_url_pattern(std::variant<std::string_view, url_pattern_init>&& input,
10549
                  const std::string_view* base_url,
10550
                  const url_pattern_options* options) {
10551
  return parser::parse_url_pattern_impl<regex_provider>(std::move(input),
10552
                                                        base_url, options);
10553
}
10554
#endif  // ADA_INCLUDE_URL_PATTERN
10555
10556
}  // namespace ada
10557
10558
#endif  // ADA_IMPLEMENTATION_INL_H
10559
/* end file include/ada/implementation-inl.h */
10560
10561
#endif  // ADA_H
10562
/* end file include/ada.h */