Coverage Report

Created: 2025-08-28 09:57

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