Line  | Count  | Source  | 
1  |  | /* auto-generated on 2025-09-23 12:57:35 -0400. Do not edit! */  | 
2  |  | /* begin file include/ada.h */  | 
3  |  | /**  | 
4  |  |  * @file ada.h  | 
5  |  |  * @brief Includes all definitions for Ada.  | 
6  |  |  */  | 
7  |  | #ifndef ADA_H  | 
8  |  | #define ADA_H  | 
9  |  |  | 
10  |  | /* begin file include/ada/ada_idna.h */  | 
11  |  | /* auto-generated on 2025-03-08 13:17:11 -0500. Do not edit! */  | 
12  |  | /* begin file include/idna.h */  | 
13  |  | #ifndef ADA_IDNA_H  | 
14  |  | #define ADA_IDNA_H  | 
15  |  |  | 
16  |  | /* begin file include/ada/idna/unicode_transcoding.h */  | 
17  |  | #ifndef ADA_IDNA_UNICODE_TRANSCODING_H  | 
18  |  | #define ADA_IDNA_UNICODE_TRANSCODING_H  | 
19  |  |  | 
20  |  | #include <string>  | 
21  |  | #include <string_view>  | 
22  |  |  | 
23  |  | namespace ada::idna { | 
24  |  |  | 
25  |  | size_t utf8_to_utf32(const char* buf, size_t len, char32_t* utf32_output);  | 
26  |  |  | 
27  |  | size_t utf8_length_from_utf32(const char32_t* buf, size_t len);  | 
28  |  |  | 
29  |  | size_t utf32_length_from_utf8(const char* buf, size_t len);  | 
30  |  |  | 
31  |  | size_t utf32_to_utf8(const char32_t* buf, size_t len, char* utf8_output);  | 
32  |  |  | 
33  |  | }  // namespace ada::idna  | 
34  |  |  | 
35  |  | #endif  // ADA_IDNA_UNICODE_TRANSCODING_H  | 
36  |  | /* end file include/ada/idna/unicode_transcoding.h */  | 
37  |  | /* begin file include/ada/idna/mapping.h */  | 
38  |  | #ifndef ADA_IDNA_MAPPING_H  | 
39  |  | #define ADA_IDNA_MAPPING_H  | 
40  |  |  | 
41  |  | #include <string>  | 
42  |  | #include <string_view>  | 
43  |  |  | 
44  |  | namespace ada::idna { | 
45  |  |  | 
46  |  | // If the input is ascii, then the mapping is just -> lower case.  | 
47  |  | void ascii_map(char* input, size_t length);  | 
48  |  | // Map the characters according to IDNA, returning the empty string on error.  | 
49  |  | std::u32string map(std::u32string_view input);  | 
50  |  |  | 
51  |  | }  // namespace ada::idna  | 
52  |  |  | 
53  |  | #endif  | 
54  |  | /* end file include/ada/idna/mapping.h */  | 
55  |  | /* begin file include/ada/idna/normalization.h */  | 
56  |  | #ifndef ADA_IDNA_NORMALIZATION_H  | 
57  |  | #define ADA_IDNA_NORMALIZATION_H  | 
58  |  |  | 
59  |  | #include <string>  | 
60  |  | #include <string_view>  | 
61  |  |  | 
62  |  | namespace ada::idna { | 
63  |  |  | 
64  |  | // Normalize the characters according to IDNA (Unicode Normalization Form C).  | 
65  |  | void normalize(std::u32string& input);  | 
66  |  |  | 
67  |  | }  // namespace ada::idna  | 
68  |  | #endif  | 
69  |  | /* end file include/ada/idna/normalization.h */  | 
70  |  | /* begin file include/ada/idna/punycode.h */  | 
71  |  | #ifndef ADA_IDNA_PUNYCODE_H  | 
72  |  | #define ADA_IDNA_PUNYCODE_H  | 
73  |  |  | 
74  |  | #include <string>  | 
75  |  | #include <string_view>  | 
76  |  |  | 
77  |  | namespace ada::idna { | 
78  |  |  | 
79  |  | bool punycode_to_utf32(std::string_view input, std::u32string& out);  | 
80  |  | bool verify_punycode(std::string_view input);  | 
81  |  | bool utf32_to_punycode(std::u32string_view input, std::string& out);  | 
82  |  |  | 
83  |  | }  // namespace ada::idna  | 
84  |  |  | 
85  |  | #endif  // ADA_IDNA_PUNYCODE_H  | 
86  |  | /* end file include/ada/idna/punycode.h */  | 
87  |  | /* begin file include/ada/idna/validity.h */  | 
88  |  | #ifndef ADA_IDNA_VALIDITY_H  | 
89  |  | #define ADA_IDNA_VALIDITY_H  | 
90  |  |  | 
91  |  | #include <string>  | 
92  |  | #include <string_view>  | 
93  |  |  | 
94  |  | namespace ada::idna { | 
95  |  |  | 
96  |  | /**  | 
97  |  |  * @see https://www.unicode.org/reports/tr46/#Validity_Criteria  | 
98  |  |  */  | 
99  |  | bool is_label_valid(std::u32string_view label);  | 
100  |  |  | 
101  |  | }  // namespace ada::idna  | 
102  |  |  | 
103  |  | #endif  // ADA_IDNA_VALIDITY_H  | 
104  |  | /* end file include/ada/idna/validity.h */  | 
105  |  | /* begin file include/ada/idna/to_ascii.h */  | 
106  |  | #ifndef ADA_IDNA_TO_ASCII_H  | 
107  |  | #define ADA_IDNA_TO_ASCII_H  | 
108  |  |  | 
109  |  | #include <string>  | 
110  |  | #include <string_view>  | 
111  |  |  | 
112  |  | namespace ada::idna { | 
113  |  |  | 
114  |  | // Converts a domain (e.g., www.google.com) possibly containing international  | 
115  |  | // characters to an ascii domain (with punycode). It will not do percent  | 
116  |  | // decoding: percent decoding should be done prior to calling this function. We  | 
117  |  | // do not remove tabs and spaces, they should have been removed prior to calling  | 
118  |  | // this function. We also do not trim control characters. We also assume that  | 
119  |  | // the input is not empty. We return "" on error.  | 
120  |  | //  | 
121  |  | //  | 
122  |  | // This function may accept or even produce invalid domains.  | 
123  |  | std::string to_ascii(std::string_view ut8_string);  | 
124  |  |  | 
125  |  | // Returns true if the string contains a forbidden code point according to the  | 
126  |  | // WHATGL URL specification:  | 
127  |  | // https://url.spec.whatwg.org/#forbidden-domain-code-point  | 
128  |  | bool contains_forbidden_domain_code_point(std::string_view ascii_string);  | 
129  |  |  | 
130  |  | bool constexpr is_ascii(std::u32string_view view);  | 
131  |  | bool constexpr is_ascii(std::string_view view);  | 
132  |  |  | 
133  |  | }  // namespace ada::idna  | 
134  |  |  | 
135  |  | #endif  // ADA_IDNA_TO_ASCII_H  | 
136  |  | /* end file include/ada/idna/to_ascii.h */  | 
137  |  | /* begin file include/ada/idna/to_unicode.h */  | 
138  |  |  | 
139  |  | #ifndef ADA_IDNA_TO_UNICODE_H  | 
140  |  | #define ADA_IDNA_TO_UNICODE_H  | 
141  |  |  | 
142  |  | #include <string_view>  | 
143  |  |  | 
144  |  | namespace ada::idna { | 
145  |  |  | 
146  |  | std::string to_unicode(std::string_view input);  | 
147  |  |  | 
148  |  | }  // namespace ada::idna  | 
149  |  |  | 
150  |  | #endif  // ADA_IDNA_TO_UNICODE_H  | 
151  |  | /* end file include/ada/idna/to_unicode.h */  | 
152  |  | /* begin file include/ada/idna/identifier.h */  | 
153  |  | #ifndef ADA_IDNA_IDENTIFIER_H  | 
154  |  | #define ADA_IDNA_IDENTIFIER_H  | 
155  |  |  | 
156  |  | #include <string>  | 
157  |  | #include <string_view>  | 
158  |  |  | 
159  |  | namespace ada::idna { | 
160  |  |  | 
161  |  | // Verify if it is valid name code point given a Unicode code point and a  | 
162  |  | // boolean first: If first is true return the result of checking if code point  | 
163  |  | // is contained in the IdentifierStart set of code points. Otherwise return the  | 
164  |  | // result of checking if code point is contained in the IdentifierPart set of  | 
165  |  | // code points. Returns false if the input is empty or the code point is not  | 
166  |  | // valid. There is minimal Unicode error handling: the input should be valid  | 
167  |  | // UTF-8. https://urlpattern.spec.whatwg.org/#is-a-valid-name-code-point  | 
168  |  | bool valid_name_code_point(char32_t code_point, bool first);  | 
169  |  |  | 
170  |  | }  // namespace ada::idna  | 
171  |  |  | 
172  |  | #endif  | 
173  |  | /* end file include/ada/idna/identifier.h */  | 
174  |  |  | 
175  |  | #endif  | 
176  |  | /* end file include/idna.h */  | 
177  |  | /* end file include/ada/ada_idna.h */  | 
178  |  | /* begin file include/ada/character_sets.h */  | 
179  |  | /**  | 
180  |  |  * @file character_sets.h  | 
181  |  |  * @brief Declaration of the character sets used by unicode functions.  | 
182  |  |  * @author Node.js  | 
183  |  |  * @see https://github.com/nodejs/node/blob/main/src/node_url_tables.cc  | 
184  |  |  */  | 
185  |  | #ifndef ADA_CHARACTER_SETS_H  | 
186  |  | #define ADA_CHARACTER_SETS_H  | 
187  |  |  | 
188  |  | /* begin file include/ada/common_defs.h */  | 
189  |  | /**  | 
190  |  |  * @file common_defs.h  | 
191  |  |  * @brief Common definitions for cross-platform compiler support.  | 
192  |  |  */  | 
193  |  | #ifndef ADA_COMMON_DEFS_H  | 
194  |  | #define ADA_COMMON_DEFS_H  | 
195  |  |  | 
196  |  | // https://en.cppreference.com/w/cpp/feature_test#Library_features  | 
197  |  | // detect C++20 features  | 
198  |  | #include <version>  | 
199  |  |  | 
200  |  | #ifdef _MSC_VER  | 
201  |  | #define ADA_VISUAL_STUDIO 1  | 
202  |  | /**  | 
203  |  |  * We want to differentiate carefully between  | 
204  |  |  * clang under visual studio and regular visual  | 
205  |  |  * studio.  | 
206  |  |  */  | 
207  |  | #ifdef __clang__  | 
208  |  | // clang under visual studio  | 
209  |  | #define ADA_CLANG_VISUAL_STUDIO 1  | 
210  |  | #else  | 
211  |  | // just regular visual studio (best guess)  | 
212  |  | #define ADA_REGULAR_VISUAL_STUDIO 1  | 
213  |  | #endif  // __clang__  | 
214  |  | #endif  // _MSC_VER  | 
215  |  |  | 
216  |  | #if defined(__GNUC__)  | 
217  |  | // Marks a block with a name so that MCA analysis can see it.  | 
218  |  | #define ADA_BEGIN_DEBUG_BLOCK(name) __asm volatile("# LLVM-MCA-BEGIN " #name); | 
219  |  | #define ADA_END_DEBUG_BLOCK(name) __asm volatile("# LLVM-MCA-END " #name); | 
220  |  | #define ADA_DEBUG_BLOCK(name, block) \  | 
221  |  |   BEGIN_DEBUG_BLOCK(name);           \  | 
222  |  |   block;                             \  | 
223  |  |   END_DEBUG_BLOCK(name);  | 
224  |  | #else  | 
225  |  | #define ADA_BEGIN_DEBUG_BLOCK(name)  | 
226  |  | #define ADA_END_DEBUG_BLOCK(name)  | 
227  |  | #define ADA_DEBUG_BLOCK(name, block)  | 
228  |  | #endif  | 
229  |  |  | 
230  |  | // Align to N-byte boundary  | 
231  |  | #define ADA_ROUNDUP_N(a, n) (((a) + ((n)-1)) & ~((n)-1))  | 
232  |  | #define ADA_ROUNDDOWN_N(a, n) ((a) & ~((n)-1))  | 
233  |  |  | 
234  |  | #define ADA_ISALIGNED_N(ptr, n) (((uintptr_t)(ptr) & ((n)-1)) == 0)  | 
235  |  |  | 
236  |  | #if defined(ADA_REGULAR_VISUAL_STUDIO)  | 
237  |  |  | 
238  |  | #define ada_really_inline __forceinline  | 
239  |  | #define ada_never_inline __declspec(noinline)  | 
240  |  |  | 
241  |  | #define ada_unused  | 
242  |  | #define ada_warn_unused  | 
243  |  |  | 
244  |  | #define ADA_PUSH_DISABLE_WARNINGS __pragma(warning(push))  | 
245  |  | #define ADA_PUSH_DISABLE_ALL_WARNINGS __pragma(warning(push, 0))  | 
246  |  | #define ADA_DISABLE_VS_WARNING(WARNING_NUMBER) \  | 
247  |  |   __pragma(warning(disable : WARNING_NUMBER))  | 
248  |  | // Get rid of Intellisense-only warnings (Code Analysis)  | 
249  |  | // Though __has_include is C++17, it is supported in Visual Studio 2017 or  | 
250  |  | // better (_MSC_VER>=1910).  | 
251  |  | #ifdef __has_include  | 
252  |  | #if __has_include(<CppCoreCheck\Warnings.h>)  | 
253  |  | #include <CppCoreCheck\Warnings.h>  | 
254  |  | #define ADA_DISABLE_UNDESIRED_WARNINGS \  | 
255  |  |   ADA_DISABLE_VS_WARNING(ALL_CPPCORECHECK_WARNINGS)  | 
256  |  | #endif  | 
257  |  | #endif  | 
258  |  |  | 
259  |  | #ifndef ADA_DISABLE_UNDESIRED_WARNINGS  | 
260  |  | #define ADA_DISABLE_UNDESIRED_WARNINGS  | 
261  |  | #endif  | 
262  |  |  | 
263  |  | #define ADA_DISABLE_DEPRECATED_WARNING ADA_DISABLE_VS_WARNING(4996)  | 
264  |  | #define ADA_DISABLE_STRICT_OVERFLOW_WARNING  | 
265  |  | #define ADA_POP_DISABLE_WARNINGS __pragma(warning(pop))  | 
266  |  |  | 
267  |  | #else  // ADA_REGULAR_VISUAL_STUDIO  | 
268  |  |  | 
269  |  | #define ada_really_inline inline __attribute__((always_inline))  | 
270  |  | #define ada_never_inline inline __attribute__((noinline))  | 
271  |  |  | 
272  |  | #define ada_unused __attribute__((unused))  | 
273  |  | #define ada_warn_unused __attribute__((warn_unused_result))  | 
274  |  |  | 
275  |  | #define ADA_PUSH_DISABLE_WARNINGS _Pragma("GCC diagnostic push") | 
276  |  | // gcc doesn't seem to disable all warnings with all and extra, add warnings  | 
277  |  | // here as necessary  | 
278  |  | #define ADA_PUSH_DISABLE_ALL_WARNINGS               \  | 
279  |  |   ADA_PUSH_DISABLE_WARNINGS                         \  | 
280  |  |   ADA_DISABLE_GCC_WARNING("-Weffc++")               \ | 
281  |  |   ADA_DISABLE_GCC_WARNING("-Wall")                  \ | 
282  |  |   ADA_DISABLE_GCC_WARNING("-Wconversion")           \ | 
283  |  |   ADA_DISABLE_GCC_WARNING("-Wextra")                \ | 
284  |  |   ADA_DISABLE_GCC_WARNING("-Wattributes")           \ | 
285  |  |   ADA_DISABLE_GCC_WARNING("-Wimplicit-fallthrough") \ | 
286  |  |   ADA_DISABLE_GCC_WARNING("-Wnon-virtual-dtor")     \ | 
287  |  |   ADA_DISABLE_GCC_WARNING("-Wreturn-type")          \ | 
288  |  |   ADA_DISABLE_GCC_WARNING("-Wshadow")               \ | 
289  |  |   ADA_DISABLE_GCC_WARNING("-Wunused-parameter")     \ | 
290  |  |   ADA_DISABLE_GCC_WARNING("-Wunused-variable")      \ | 
291  |  |   ADA_DISABLE_GCC_WARNING("-Wsign-compare") | 
292  |  | #define ADA_PRAGMA(P) _Pragma(#P)  | 
293  |  | #define ADA_DISABLE_GCC_WARNING(WARNING) \  | 
294  |  |   ADA_PRAGMA(GCC diagnostic ignored WARNING)  | 
295  |  | #if defined(ADA_CLANG_VISUAL_STUDIO)  | 
296  |  | #define ADA_DISABLE_UNDESIRED_WARNINGS \  | 
297  |  |   ADA_DISABLE_GCC_WARNING("-Wmicrosoft-include") | 
298  |  | #else  | 
299  |  | #define ADA_DISABLE_UNDESIRED_WARNINGS  | 
300  |  | #endif  | 
301  |  | #define ADA_DISABLE_DEPRECATED_WARNING \  | 
302  |  |   ADA_DISABLE_GCC_WARNING("-Wdeprecated-declarations") | 
303  |  | #define ADA_DISABLE_STRICT_OVERFLOW_WARNING \  | 
304  |  |   ADA_DISABLE_GCC_WARNING("-Wstrict-overflow") | 
305  |  | #define ADA_POP_DISABLE_WARNINGS _Pragma("GCC diagnostic pop") | 
306  |  |  | 
307  |  | #endif  // MSC_VER  | 
308  |  |  | 
309  |  | #if defined(ADA_VISUAL_STUDIO)  | 
310  |  | /**  | 
311  |  |  * It does not matter here whether you are using  | 
312  |  |  * the regular visual studio or clang under visual  | 
313  |  |  * studio.  | 
314  |  |  */  | 
315  |  | #if ADA_USING_LIBRARY  | 
316  |  | #define ADA_DLLIMPORTEXPORT __declspec(dllimport)  | 
317  |  | #else  | 
318  |  | #define ADA_DLLIMPORTEXPORT __declspec(dllexport)  | 
319  |  | #endif  | 
320  |  | #else  | 
321  |  | #define ADA_DLLIMPORTEXPORT  | 
322  |  | #endif  | 
323  |  |  | 
324  |  | /// If EXPR is an error, returns it.  | 
325  |  | #define ADA_TRY(EXPR)   \  | 
326  |  |   {                     \ | 
327  |  |     auto _err = (EXPR); \  | 
328  |  |     if (_err) {         \ | 
329  |  |       return _err;      \  | 
330  |  |     }                   \  | 
331  |  |   }  | 
332  |  |  | 
333  |  | // __has_cpp_attribute is part of C++20  | 
334  |  | #if !defined(__has_cpp_attribute)  | 
335  |  | #define __has_cpp_attribute(x) 0  | 
336  |  | #endif  | 
337  |  |  | 
338  |  | #if __has_cpp_attribute(gnu::noinline)  | 
339  |  | #define ADA_ATTRIBUTE_NOINLINE [[gnu::noinline]]  | 
340  |  | #else  | 
341  |  | #define ADA_ATTRIBUTE_NOINLINE  | 
342  |  | #endif  | 
343  |  |  | 
344  |  | namespace ada { | 
345  | 0  | [[noreturn]] inline void unreachable() { | 
346  | 0  | #ifdef __GNUC__  | 
347  | 0  |   __builtin_unreachable();  | 
348  |  | #elif defined(_MSC_VER)  | 
349  |  |   __assume(false);  | 
350  |  | #else  | 
351  |  | #endif  | 
352  | 0  | }  | 
353  |  | }  // namespace ada  | 
354  |  |  | 
355  |  | // Unless the programmer has already set ADA_DEVELOPMENT_CHECKS,  | 
356  |  | // we want to set it under debug builds. We detect a debug build  | 
357  |  | // under Visual Studio when the _DEBUG macro is set. Under the other  | 
358  |  | // compilers, we use the fact that they define __OPTIMIZE__ whenever  | 
359  |  | // they allow optimizations.  | 
360  |  | // It is possible that this could miss some cases where ADA_DEVELOPMENT_CHECKS  | 
361  |  | // is helpful, but the programmer can set the macro ADA_DEVELOPMENT_CHECKS.  | 
362  |  | // It could also wrongly set ADA_DEVELOPMENT_CHECKS (e.g., if the programmer  | 
363  |  | // sets _DEBUG in a release build under Visual Studio, or if some compiler fails  | 
364  |  | // to set the __OPTIMIZE__ macro).  | 
365  |  | #if !defined(ADA_DEVELOPMENT_CHECKS) && !defined(NDEBUG)  | 
366  |  | #ifdef _MSC_VER  | 
367  |  | // Visual Studio seems to set _DEBUG for debug builds.  | 
368  |  | #ifdef _DEBUG  | 
369  |  | #define ADA_DEVELOPMENT_CHECKS 1  | 
370  |  | #endif  // _DEBUG  | 
371  |  | #else   // _MSC_VER  | 
372  |  | // All other compilers appear to set __OPTIMIZE__ to a positive integer  | 
373  |  | // when the compiler is optimizing.  | 
374  |  | #ifndef __OPTIMIZE__  | 
375  |  | #define ADA_DEVELOPMENT_CHECKS 1  | 
376  |  | #endif  // __OPTIMIZE__  | 
377  |  | #endif  // _MSC_VER  | 
378  |  | #endif  // ADA_DEVELOPMENT_CHECKS  | 
379  |  |  | 
380  |  | #define ADA_STR(x) #x  | 
381  |  |  | 
382  |  | #if ADA_DEVELOPMENT_CHECKS  | 
383  |  | #define ADA_REQUIRE(EXPR) \  | 
384  |  |   {                       \ | 
385  |  |     if (!(EXPR) { abort(); }) } | 
386  |  |  | 
387  |  | #define ADA_FAIL(MESSAGE)                            \  | 
388  |  |   do {                                               \ | 
389  |  |     std::cerr << "FAIL: " << (MESSAGE) << std::endl; \  | 
390  |  |     abort();                                         \  | 
391  |  |   } while (0);  | 
392  |  | #define ADA_ASSERT_EQUAL(LHS, RHS, MESSAGE)                                    \  | 
393  |  |   do {                                                                         \ | 
394  |  |     if (LHS != RHS) {                                                          \ | 
395  |  |       std::cerr << "Mismatch: '" << LHS << "' - '" << RHS << "'" << std::endl; \  | 
396  |  |       ADA_FAIL(MESSAGE);                                                       \  | 
397  |  |     }                                                                          \  | 
398  |  |   } while (0);  | 
399  |  | #define ADA_ASSERT_TRUE(COND)                                               \  | 
400  |  |   do {                                                                      \ | 
401  |  |     if (!(COND)) {                                                          \ | 
402  |  |       std::cerr << "Assert at line " << __LINE__ << " of file " << __FILE__ \  | 
403  |  |                 << std::endl;                                               \  | 
404  |  |       ADA_FAIL(ADA_STR(COND));                                              \  | 
405  |  |     }                                                                       \  | 
406  |  |   } while (0);  | 
407  |  | #else  | 
408  |  | #define ADA_FAIL(MESSAGE)  | 
409  |  | #define ADA_ASSERT_EQUAL(LHS, RHS, MESSAGE)  | 
410  |  | #define ADA_ASSERT_TRUE(COND)  | 
411  |  | #endif  | 
412  |  |  | 
413  |  | #ifdef ADA_VISUAL_STUDIO  | 
414  |  | #define ADA_ASSUME(COND) __assume(COND)  | 
415  |  | #else  | 
416  |  | #define ADA_ASSUME(COND)       \  | 
417  |  |   do {                         \ | 
418  |  |     if (!(COND)) {             \ | 
419  |  |       __builtin_unreachable(); \  | 
420  |  |     }                          \  | 
421  |  |   } while (0)  | 
422  |  | #endif  | 
423  |  |  | 
424  |  | #if defined(__SSE2__) || defined(__x86_64__) || defined(__x86_64) || \  | 
425  |  |     (defined(_M_AMD64) || defined(_M_X64) ||                         \  | 
426  |  |      (defined(_M_IX86_FP) && _M_IX86_FP == 2))  | 
427  |  | #define ADA_SSE2 1  | 
428  |  | #endif  | 
429  |  |  | 
430  |  | #if defined(__aarch64__) || defined(_M_ARM64)  | 
431  |  | #define ADA_NEON 1  | 
432  |  | #endif  | 
433  |  |  | 
434  |  | #if defined(__loongarch_sx)  | 
435  |  | #define ADA_LSX 1  | 
436  |  | #endif  | 
437  |  |  | 
438  |  | #ifndef __has_cpp_attribute  | 
439  |  | #define ada_lifetime_bound  | 
440  |  | #elif __has_cpp_attribute(msvc::lifetimebound)  | 
441  |  | #define ada_lifetime_bound [[msvc::lifetimebound]]  | 
442  |  | #elif __has_cpp_attribute(clang::lifetimebound)  | 
443  |  | #define ada_lifetime_bound [[clang::lifetimebound]]  | 
444  |  | #elif __has_cpp_attribute(lifetimebound)  | 
445  |  | #define ada_lifetime_bound [[lifetimebound]]  | 
446  |  | #else  | 
447  |  | #define ada_lifetime_bound  | 
448  |  | #endif  | 
449  |  |  | 
450  |  | #ifdef __cpp_lib_format  | 
451  |  | #if __cpp_lib_format >= 202110L  | 
452  |  | #include <format>  | 
453  |  | #define ADA_HAS_FORMAT 1  | 
454  |  | #endif  | 
455  |  | #endif  | 
456  |  |  | 
457  |  | #ifndef ADA_INCLUDE_URL_PATTERN  | 
458  |  | #define ADA_INCLUDE_URL_PATTERN 1  | 
459  |  | #endif  // ADA_INCLUDE_URL_PATTERN  | 
460  |  |  | 
461  |  | #endif  // ADA_COMMON_DEFS_H  | 
462  |  | /* end file include/ada/common_defs.h */  | 
463  |  | #include <cstdint>  | 
464  |  |  | 
465  |  | /**  | 
466  |  |  * These functions are not part of our public API and may  | 
467  |  |  * change at any time.  | 
468  |  |  * @private  | 
469  |  |  * @namespace ada::character_sets  | 
470  |  |  * @brief Includes the definitions for unicode character sets.  | 
471  |  |  */  | 
472  |  | namespace ada::character_sets { | 
473  |  | ada_really_inline constexpr bool bit_at(const uint8_t a[], uint8_t i);  | 
474  |  | }  // namespace ada::character_sets  | 
475  |  |  | 
476  |  | #endif  // ADA_CHARACTER_SETS_H  | 
477  |  | /* end file include/ada/character_sets.h */  | 
478  |  | /* begin file include/ada/character_sets-inl.h */  | 
479  |  | /**  | 
480  |  |  * @file character_sets-inl.h  | 
481  |  |  * @brief Definitions of the character sets used by unicode functions.  | 
482  |  |  * @author Node.js  | 
483  |  |  * @see https://github.com/nodejs/node/blob/main/src/node_url_tables.cc  | 
484  |  |  */  | 
485  |  | #ifndef ADA_CHARACTER_SETS_INL_H  | 
486  |  | #define ADA_CHARACTER_SETS_INL_H  | 
487  |  |  | 
488  |  |  | 
489  |  | /**  | 
490  |  |  * These functions are not part of our public API and may  | 
491  |  |  * change at any time.  | 
492  |  |  * @private  | 
493  |  |  */  | 
494  |  | namespace ada::character_sets { | 
495  |  |  | 
496  |  | constexpr char hex[1024] =  | 
497  |  |     "%00\0%01\0%02\0%03\0%04\0%05\0%06\0%07\0"  | 
498  |  |     "%08\0%09\0%0A\0%0B\0%0C\0%0D\0%0E\0%0F\0"  | 
499  |  |     "%10\0%11\0%12\0%13\0%14\0%15\0%16\0%17\0"  | 
500  |  |     "%18\0%19\0%1A\0%1B\0%1C\0%1D\0%1E\0%1F\0"  | 
501  |  |     "%20\0%21\0%22\0%23\0%24\0%25\0%26\0%27\0"  | 
502  |  |     "%28\0%29\0%2A\0%2B\0%2C\0%2D\0%2E\0%2F\0"  | 
503  |  |     "%30\0%31\0%32\0%33\0%34\0%35\0%36\0%37\0"  | 
504  |  |     "%38\0%39\0%3A\0%3B\0%3C\0%3D\0%3E\0%3F\0"  | 
505  |  |     "%40\0%41\0%42\0%43\0%44\0%45\0%46\0%47\0"  | 
506  |  |     "%48\0%49\0%4A\0%4B\0%4C\0%4D\0%4E\0%4F\0"  | 
507  |  |     "%50\0%51\0%52\0%53\0%54\0%55\0%56\0%57\0"  | 
508  |  |     "%58\0%59\0%5A\0%5B\0%5C\0%5D\0%5E\0%5F\0"  | 
509  |  |     "%60\0%61\0%62\0%63\0%64\0%65\0%66\0%67\0"  | 
510  |  |     "%68\0%69\0%6A\0%6B\0%6C\0%6D\0%6E\0%6F\0"  | 
511  |  |     "%70\0%71\0%72\0%73\0%74\0%75\0%76\0%77\0"  | 
512  |  |     "%78\0%79\0%7A\0%7B\0%7C\0%7D\0%7E\0%7F\0"  | 
513  |  |     "%80\0%81\0%82\0%83\0%84\0%85\0%86\0%87\0"  | 
514  |  |     "%88\0%89\0%8A\0%8B\0%8C\0%8D\0%8E\0%8F\0"  | 
515  |  |     "%90\0%91\0%92\0%93\0%94\0%95\0%96\0%97\0"  | 
516  |  |     "%98\0%99\0%9A\0%9B\0%9C\0%9D\0%9E\0%9F\0"  | 
517  |  |     "%A0\0%A1\0%A2\0%A3\0%A4\0%A5\0%A6\0%A7\0"  | 
518  |  |     "%A8\0%A9\0%AA\0%AB\0%AC\0%AD\0%AE\0%AF\0"  | 
519  |  |     "%B0\0%B1\0%B2\0%B3\0%B4\0%B5\0%B6\0%B7\0"  | 
520  |  |     "%B8\0%B9\0%BA\0%BB\0%BC\0%BD\0%BE\0%BF\0"  | 
521  |  |     "%C0\0%C1\0%C2\0%C3\0%C4\0%C5\0%C6\0%C7\0"  | 
522  |  |     "%C8\0%C9\0%CA\0%CB\0%CC\0%CD\0%CE\0%CF\0"  | 
523  |  |     "%D0\0%D1\0%D2\0%D3\0%D4\0%D5\0%D6\0%D7\0"  | 
524  |  |     "%D8\0%D9\0%DA\0%DB\0%DC\0%DD\0%DE\0%DF\0"  | 
525  |  |     "%E0\0%E1\0%E2\0%E3\0%E4\0%E5\0%E6\0%E7\0"  | 
526  |  |     "%E8\0%E9\0%EA\0%EB\0%EC\0%ED\0%EE\0%EF\0"  | 
527  |  |     "%F0\0%F1\0%F2\0%F3\0%F4\0%F5\0%F6\0%F7\0"  | 
528  |  |     "%F8\0%F9\0%FA\0%FB\0%FC\0%FD\0%FE\0%FF";  | 
529  |  |  | 
530  |  | constexpr uint8_t C0_CONTROL_PERCENT_ENCODE[32] = { | 
531  |  |     // 00     01     02     03     04     05     06     07  | 
532  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
533  |  |     // 08     09     0A     0B     0C     0D     0E     0F  | 
534  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
535  |  |     // 10     11     12     13     14     15     16     17  | 
536  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
537  |  |     // 18     19     1A     1B     1C     1D     1E     1F  | 
538  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
539  |  |     // 20     21     22     23     24     25     26     27  | 
540  |  |     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,  | 
541  |  |     // 28     29     2A     2B     2C     2D     2E     2F  | 
542  |  |     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,  | 
543  |  |     // 30     31     32     33     34     35     36     37  | 
544  |  |     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,  | 
545  |  |     // 38     39     3A     3B     3C     3D     3E     3F  | 
546  |  |     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,  | 
547  |  |     // 40     41     42     43     44     45     46     47  | 
548  |  |     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,  | 
549  |  |     // 48     49     4A     4B     4C     4D     4E     4F  | 
550  |  |     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,  | 
551  |  |     // 50     51     52     53     54     55     56     57  | 
552  |  |     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,  | 
553  |  |     // 58     59     5A     5B     5C     5D     5E     5F  | 
554  |  |     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,  | 
555  |  |     // 60     61     62     63     64     65     66     67  | 
556  |  |     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,  | 
557  |  |     // 68     69     6A     6B     6C     6D     6E     6F  | 
558  |  |     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,  | 
559  |  |     // 70     71     72     73     74     75     76     77  | 
560  |  |     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,  | 
561  |  |     // 78     79     7A     7B     7C     7D     7E     7F  | 
562  |  |     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x80,  | 
563  |  |     // 80     81     82     83     84     85     86     87  | 
564  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
565  |  |     // 88     89     8A     8B     8C     8D     8E     8F  | 
566  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
567  |  |     // 90     91     92     93     94     95     96     97  | 
568  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
569  |  |     // 98     99     9A     9B     9C     9D     9E     9F  | 
570  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
571  |  |     // A0     A1     A2     A3     A4     A5     A6     A7  | 
572  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
573  |  |     // A8     A9     AA     AB     AC     AD     AE     AF  | 
574  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
575  |  |     // B0     B1     B2     B3     B4     B5     B6     B7  | 
576  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
577  |  |     // B8     B9     BA     BB     BC     BD     BE     BF  | 
578  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
579  |  |     // C0     C1     C2     C3     C4     C5     C6     C7  | 
580  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
581  |  |     // C8     C9     CA     CB     CC     CD     CE     CF  | 
582  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
583  |  |     // D0     D1     D2     D3     D4     D5     D6     D7  | 
584  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
585  |  |     // D8     D9     DA     DB     DC     DD     DE     DF  | 
586  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
587  |  |     // E0     E1     E2     E3     E4     E5     E6     E7  | 
588  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
589  |  |     // E8     E9     EA     EB     EC     ED     EE     EF  | 
590  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
591  |  |     // F0     F1     F2     F3     F4     F5     F6     F7  | 
592  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
593  |  |     // F8     F9     FA     FB     FC     FD     FE     FF  | 
594  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80};  | 
595  |  |  | 
596  |  | constexpr uint8_t SPECIAL_QUERY_PERCENT_ENCODE[32] = { | 
597  |  |     // 00     01     02     03     04     05     06     07  | 
598  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
599  |  |     // 08     09     0A     0B     0C     0D     0E     0F  | 
600  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
601  |  |     // 10     11     12     13     14     15     16     17  | 
602  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
603  |  |     // 18     19     1A     1B     1C     1D     1E     1F  | 
604  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
605  |  |     // 20     21     22     23     24     25     26     27  | 
606  |  |     0x01 | 0x00 | 0x04 | 0x08 | 0x00 | 0x00 | 0x00 | 0x80,  | 
607  |  |     // 28     29     2A     2B     2C     2D     2E     2F  | 
608  |  |     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,  | 
609  |  |     // 30     31     32     33     34     35     36     37  | 
610  |  |     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,  | 
611  |  |     // 38     39     3A     3B     3C     3D     3E     3F  | 
612  |  |     0x00 | 0x00 | 0x00 | 0x00 | 0x10 | 0x00 | 0x40 | 0x00,  | 
613  |  |     // 40     41     42     43     44     45     46     47  | 
614  |  |     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,  | 
615  |  |     // 48     49     4A     4B     4C     4D     4E     4F  | 
616  |  |     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,  | 
617  |  |     // 50     51     52     53     54     55     56     57  | 
618  |  |     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,  | 
619  |  |     // 58     59     5A     5B     5C     5D     5E     5F  | 
620  |  |     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,  | 
621  |  |     // 60     61     62     63     64     65     66     67  | 
622  |  |     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,  | 
623  |  |     // 68     69     6A     6B     6C     6D     6E     6F  | 
624  |  |     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,  | 
625  |  |     // 70     71     72     73     74     75     76     77  | 
626  |  |     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,  | 
627  |  |     // 78     79     7A     7B     7C     7D     7E     7F  | 
628  |  |     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x80,  | 
629  |  |     // 80     81     82     83     84     85     86     87  | 
630  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
631  |  |     // 88     89     8A     8B     8C     8D     8E     8F  | 
632  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
633  |  |     // 90     91     92     93     94     95     96     97  | 
634  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
635  |  |     // 98     99     9A     9B     9C     9D     9E     9F  | 
636  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
637  |  |     // A0     A1     A2     A3     A4     A5     A6     A7  | 
638  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
639  |  |     // A8     A9     AA     AB     AC     AD     AE     AF  | 
640  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
641  |  |     // B0     B1     B2     B3     B4     B5     B6     B7  | 
642  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
643  |  |     // B8     B9     BA     BB     BC     BD     BE     BF  | 
644  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
645  |  |     // C0     C1     C2     C3     C4     C5     C6     C7  | 
646  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
647  |  |     // C8     C9     CA     CB     CC     CD     CE     CF  | 
648  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
649  |  |     // D0     D1     D2     D3     D4     D5     D6     D7  | 
650  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
651  |  |     // D8     D9     DA     DB     DC     DD     DE     DF  | 
652  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
653  |  |     // E0     E1     E2     E3     E4     E5     E6     E7  | 
654  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
655  |  |     // E8     E9     EA     EB     EC     ED     EE     EF  | 
656  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
657  |  |     // F0     F1     F2     F3     F4     F5     F6     F7  | 
658  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
659  |  |     // F8     F9     FA     FB     FC     FD     FE     FF  | 
660  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80};  | 
661  |  |  | 
662  |  | constexpr uint8_t QUERY_PERCENT_ENCODE[32] = { | 
663  |  |     // 00     01     02     03     04     05     06     07  | 
664  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
665  |  |     // 08     09     0A     0B     0C     0D     0E     0F  | 
666  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
667  |  |     // 10     11     12     13     14     15     16     17  | 
668  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
669  |  |     // 18     19     1A     1B     1C     1D     1E     1F  | 
670  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
671  |  |     // 20     21     22     23     24     25     26     27  | 
672  |  |     0x01 | 0x00 | 0x04 | 0x08 | 0x00 | 0x00 | 0x00 | 0x00,  | 
673  |  |     // 28     29     2A     2B     2C     2D     2E     2F  | 
674  |  |     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,  | 
675  |  |     // 30     31     32     33     34     35     36     37  | 
676  |  |     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,  | 
677  |  |     // 38     39     3A     3B     3C     3D     3E     3F  | 
678  |  |     0x00 | 0x00 | 0x00 | 0x00 | 0x10 | 0x00 | 0x40 | 0x00,  | 
679  |  |     // 40     41     42     43     44     45     46     47  | 
680  |  |     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,  | 
681  |  |     // 48     49     4A     4B     4C     4D     4E     4F  | 
682  |  |     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,  | 
683  |  |     // 50     51     52     53     54     55     56     57  | 
684  |  |     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,  | 
685  |  |     // 58     59     5A     5B     5C     5D     5E     5F  | 
686  |  |     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,  | 
687  |  |     // 60     61     62     63     64     65     66     67  | 
688  |  |     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,  | 
689  |  |     // 68     69     6A     6B     6C     6D     6E     6F  | 
690  |  |     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,  | 
691  |  |     // 70     71     72     73     74     75     76     77  | 
692  |  |     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,  | 
693  |  |     // 78     79     7A     7B     7C     7D     7E     7F  | 
694  |  |     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x80,  | 
695  |  |     // 80     81     82     83     84     85     86     87  | 
696  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
697  |  |     // 88     89     8A     8B     8C     8D     8E     8F  | 
698  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
699  |  |     // 90     91     92     93     94     95     96     97  | 
700  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
701  |  |     // 98     99     9A     9B     9C     9D     9E     9F  | 
702  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
703  |  |     // A0     A1     A2     A3     A4     A5     A6     A7  | 
704  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
705  |  |     // A8     A9     AA     AB     AC     AD     AE     AF  | 
706  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
707  |  |     // B0     B1     B2     B3     B4     B5     B6     B7  | 
708  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
709  |  |     // B8     B9     BA     BB     BC     BD     BE     BF  | 
710  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
711  |  |     // C0     C1     C2     C3     C4     C5     C6     C7  | 
712  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
713  |  |     // C8     C9     CA     CB     CC     CD     CE     CF  | 
714  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
715  |  |     // D0     D1     D2     D3     D4     D5     D6     D7  | 
716  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
717  |  |     // D8     D9     DA     DB     DC     DD     DE     DF  | 
718  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
719  |  |     // E0     E1     E2     E3     E4     E5     E6     E7  | 
720  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
721  |  |     // E8     E9     EA     EB     EC     ED     EE     EF  | 
722  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
723  |  |     // F0     F1     F2     F3     F4     F5     F6     F7  | 
724  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
725  |  |     // F8     F9     FA     FB     FC     FD     FE     FF  | 
726  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80};  | 
727  |  |  | 
728  |  | constexpr uint8_t FRAGMENT_PERCENT_ENCODE[32] = { | 
729  |  |     // 00     01     02     03     04     05     06     07  | 
730  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
731  |  |     // 08     09     0A     0B     0C     0D     0E     0F  | 
732  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
733  |  |     // 10     11     12     13     14     15     16     17  | 
734  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
735  |  |     // 18     19     1A     1B     1C     1D     1E     1F  | 
736  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
737  |  |     // 20     21     22     23     24     25     26     27  | 
738  |  |     0x01 | 0x00 | 0x04 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,  | 
739  |  |     // 28     29     2A     2B     2C     2D     2E     2F  | 
740  |  |     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,  | 
741  |  |     // 30     31     32     33     34     35     36     37  | 
742  |  |     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,  | 
743  |  |     // 38     39     3A     3B     3C     3D     3E     3F  | 
744  |  |     0x00 | 0x00 | 0x00 | 0x00 | 0x10 | 0x00 | 0x40 | 0x00,  | 
745  |  |     // 40     41     42     43     44     45     46     47  | 
746  |  |     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,  | 
747  |  |     // 48     49     4A     4B     4C     4D     4E     4F  | 
748  |  |     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,  | 
749  |  |     // 50     51     52     53     54     55     56     57  | 
750  |  |     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,  | 
751  |  |     // 58     59     5A     5B     5C     5D     5E     5F  | 
752  |  |     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,  | 
753  |  |     // 60     61     62     63     64     65     66     67  | 
754  |  |     0x01 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,  | 
755  |  |     // 68     69     6A     6B     6C     6D     6E     6F  | 
756  |  |     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,  | 
757  |  |     // 70     71     72     73     74     75     76     77  | 
758  |  |     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,  | 
759  |  |     // 78     79     7A     7B     7C     7D     7E     7F  | 
760  |  |     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x80,  | 
761  |  |     // 80     81     82     83     84     85     86     87  | 
762  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
763  |  |     // 88     89     8A     8B     8C     8D     8E     8F  | 
764  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
765  |  |     // 90     91     92     93     94     95     96     97  | 
766  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
767  |  |     // 98     99     9A     9B     9C     9D     9E     9F  | 
768  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
769  |  |     // A0     A1     A2     A3     A4     A5     A6     A7  | 
770  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
771  |  |     // A8     A9     AA     AB     AC     AD     AE     AF  | 
772  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
773  |  |     // B0     B1     B2     B3     B4     B5     B6     B7  | 
774  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
775  |  |     // B8     B9     BA     BB     BC     BD     BE     BF  | 
776  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
777  |  |     // C0     C1     C2     C3     C4     C5     C6     C7  | 
778  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
779  |  |     // C8     C9     CA     CB     CC     CD     CE     CF  | 
780  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
781  |  |     // D0     D1     D2     D3     D4     D5     D6     D7  | 
782  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
783  |  |     // D8     D9     DA     DB     DC     DD     DE     DF  | 
784  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
785  |  |     // E0     E1     E2     E3     E4     E5     E6     E7  | 
786  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
787  |  |     // E8     E9     EA     EB     EC     ED     EE     EF  | 
788  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
789  |  |     // F0     F1     F2     F3     F4     F5     F6     F7  | 
790  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
791  |  |     // F8     F9     FA     FB     FC     FD     FE     FF  | 
792  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80};  | 
793  |  |  | 
794  |  | constexpr uint8_t USERINFO_PERCENT_ENCODE[32] = { | 
795  |  |     // 00     01     02     03     04     05     06     07  | 
796  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
797  |  |     // 08     09     0A     0B     0C     0D     0E     0F  | 
798  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
799  |  |     // 10     11     12     13     14     15     16     17  | 
800  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
801  |  |     // 18     19     1A     1B     1C     1D     1E     1F  | 
802  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
803  |  |     // 20     21     22     23     24     25     26     27  | 
804  |  |     0x01 | 0x00 | 0x04 | 0x08 | 0x00 | 0x00 | 0x00 | 0x00,  | 
805  |  |     // 28     29     2A     2B     2C     2D     2E     2F  | 
806  |  |     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x80,  | 
807  |  |     // 30     31     32     33     34     35     36     37  | 
808  |  |     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,  | 
809  |  |     // 38     39     3A     3B     3C     3D     3E     3F  | 
810  |  |     0x00 | 0x00 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
811  |  |     // 40     41     42     43     44     45     46     47  | 
812  |  |     0x01 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,  | 
813  |  |     // 48     49     4A     4B     4C     4D     4E     4F  | 
814  |  |     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,  | 
815  |  |     // 50     51     52     53     54     55     56     57  | 
816  |  |     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,  | 
817  |  |     // 58     59     5A     5B     5C     5D     5E     5F  | 
818  |  |     0x00 | 0x00 | 0x00 | 0x08 | 0x10 | 0x20 | 0x40 | 0x00,  | 
819  |  |     // 60     61     62     63     64     65     66     67  | 
820  |  |     0x01 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,  | 
821  |  |     // 68     69     6A     6B     6C     6D     6E     6F  | 
822  |  |     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,  | 
823  |  |     // 70     71     72     73     74     75     76     77  | 
824  |  |     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,  | 
825  |  |     // 78     79     7A     7B     7C     7D     7E     7F  | 
826  |  |     0x00 | 0x00 | 0x00 | 0x08 | 0x10 | 0x20 | 0x00 | 0x80,  | 
827  |  |     // 80     81     82     83     84     85     86     87  | 
828  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
829  |  |     // 88     89     8A     8B     8C     8D     8E     8F  | 
830  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
831  |  |     // 90     91     92     93     94     95     96     97  | 
832  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
833  |  |     // 98     99     9A     9B     9C     9D     9E     9F  | 
834  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
835  |  |     // A0     A1     A2     A3     A4     A5     A6     A7  | 
836  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
837  |  |     // A8     A9     AA     AB     AC     AD     AE     AF  | 
838  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
839  |  |     // B0     B1     B2     B3     B4     B5     B6     B7  | 
840  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
841  |  |     // B8     B9     BA     BB     BC     BD     BE     BF  | 
842  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
843  |  |     // C0     C1     C2     C3     C4     C5     C6     C7  | 
844  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
845  |  |     // C8     C9     CA     CB     CC     CD     CE     CF  | 
846  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
847  |  |     // D0     D1     D2     D3     D4     D5     D6     D7  | 
848  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
849  |  |     // D8     D9     DA     DB     DC     DD     DE     DF  | 
850  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
851  |  |     // E0     E1     E2     E3     E4     E5     E6     E7  | 
852  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
853  |  |     // E8     E9     EA     EB     EC     ED     EE     EF  | 
854  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
855  |  |     // F0     F1     F2     F3     F4     F5     F6     F7  | 
856  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
857  |  |     // F8     F9     FA     FB     FC     FD     FE     FF  | 
858  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80};  | 
859  |  |  | 
860  |  | constexpr uint8_t PATH_PERCENT_ENCODE[32] = { | 
861  |  |     // 00     01     02     03     04     05     06     07  | 
862  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
863  |  |     // 08     09     0A     0B     0C     0D     0E     0F  | 
864  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
865  |  |     // 10     11     12     13     14     15     16     17  | 
866  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
867  |  |     // 18     19     1A     1B     1C     1D     1E     1F  | 
868  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
869  |  |     // 20     21     22     23     24     25     26     27  | 
870  |  |     0x01 | 0x00 | 0x04 | 0x08 | 0x00 | 0x00 | 0x00 | 0x00,  | 
871  |  |     // 28     29     2A     2B     2C     2D     2E     2F  | 
872  |  |     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,  | 
873  |  |     // 30     31     32     33     34     35     36     37  | 
874  |  |     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,  | 
875  |  |     // 38     39     3A     3B     3C     3D     3E     3F  | 
876  |  |     0x00 | 0x00 | 0x00 | 0x00 | 0x10 | 0x00 | 0x40 | 0x80,  | 
877  |  |     // 40     41     42     43     44     45     46     47  | 
878  |  |     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,  | 
879  |  |     // 48     49     4A     4B     4C     4D     4E     4F  | 
880  |  |     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,  | 
881  |  |     // 50     51     52     53     54     55     56     57  | 
882  |  |     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,  | 
883  |  |     // 58     59     5A     5B     5C     5D     5E     5F  | 
884  |  |     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x40 | 0x00,  | 
885  |  |     // 60     61     62     63     64     65     66     67  | 
886  |  |     0x01 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,  | 
887  |  |     // 68     69     6A     6B     6C     6D     6E     6F  | 
888  |  |     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,  | 
889  |  |     // 70     71     72     73     74     75     76     77  | 
890  |  |     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,  | 
891  |  |     // 78     79     7A     7B     7C     7D     7E     7F  | 
892  |  |     0x00 | 0x00 | 0x00 | 0x08 | 0x00 | 0x20 | 0x00 | 0x80,  | 
893  |  |     // 80     81     82     83     84     85     86     87  | 
894  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
895  |  |     // 88     89     8A     8B     8C     8D     8E     8F  | 
896  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
897  |  |     // 90     91     92     93     94     95     96     97  | 
898  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
899  |  |     // 98     99     9A     9B     9C     9D     9E     9F  | 
900  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
901  |  |     // A0     A1     A2     A3     A4     A5     A6     A7  | 
902  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
903  |  |     // A8     A9     AA     AB     AC     AD     AE     AF  | 
904  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
905  |  |     // B0     B1     B2     B3     B4     B5     B6     B7  | 
906  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
907  |  |     // B8     B9     BA     BB     BC     BD     BE     BF  | 
908  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
909  |  |     // C0     C1     C2     C3     C4     C5     C6     C7  | 
910  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
911  |  |     // C8     C9     CA     CB     CC     CD     CE     CF  | 
912  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
913  |  |     // D0     D1     D2     D3     D4     D5     D6     D7  | 
914  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
915  |  |     // D8     D9     DA     DB     DC     DD     DE     DF  | 
916  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
917  |  |     // E0     E1     E2     E3     E4     E5     E6     E7  | 
918  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
919  |  |     // E8     E9     EA     EB     EC     ED     EE     EF  | 
920  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
921  |  |     // F0     F1     F2     F3     F4     F5     F6     F7  | 
922  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
923  |  |     // F8     F9     FA     FB     FC     FD     FE     FF  | 
924  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80};  | 
925  |  |  | 
926  |  | constexpr uint8_t WWW_FORM_URLENCODED_PERCENT_ENCODE[32] = { | 
927  |  |     // 00     01     02     03     04     05     06     07  | 
928  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
929  |  |     // 08     09     0A     0B     0C     0D     0E     0F  | 
930  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
931  |  |     // 10     11     12     13     14     15     16     17  | 
932  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
933  |  |     // 18     19     1A     1B     1C     1D     1E     1F  | 
934  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
935  |  |     // 20     21     22     23     24     25     26     27  | 
936  |  |     0x00 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
937  |  |     // 28     29     2A     2B     2C     2D     2E     2F  | 
938  |  |     0x01 | 0x02 | 0x00 | 0x08 | 0x10 | 0x00 | 0x00 | 0x80,  | 
939  |  |     // 30     31     32     33     34     35     36     37  | 
940  |  |     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,  | 
941  |  |     // 38     39     3A     3B     3C     3D     3E     3F  | 
942  |  |     0x00 | 0x00 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
943  |  |     // 40     41     42     43     44     45     46     47  | 
944  |  |     0x01 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,  | 
945  |  |     // 48     49     4A     4B     4C     4D     4E     4F  | 
946  |  |     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,  | 
947  |  |     // 50     51     52     53     54     55     56     57  | 
948  |  |     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,  | 
949  |  |     // 58     59     5A     5B     5C     5D     5E     5F  | 
950  |  |     0x00 | 0x00 | 0x00 | 0x08 | 0x10 | 0x20 | 0x40 | 0x00,  | 
951  |  |     // 60     61     62     63     64     65     66     67  | 
952  |  |     0x01 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,  | 
953  |  |     // 68     69     6A     6B     6C     6D     6E     6F  | 
954  |  |     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,  | 
955  |  |     // 70     71     72     73     74     75     76     77  | 
956  |  |     0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,  | 
957  |  |     // 78     79     7A     7B     7C     7D     7E     7F  | 
958  |  |     0x00 | 0x00 | 0x00 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
959  |  |     // 80     81     82     83     84     85     86     87  | 
960  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
961  |  |     // 88     89     8A     8B     8C     8D     8E     8F  | 
962  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
963  |  |     // 90     91     92     93     94     95     96     97  | 
964  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
965  |  |     // 98     99     9A     9B     9C     9D     9E     9F  | 
966  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
967  |  |     // A0     A1     A2     A3     A4     A5     A6     A7  | 
968  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
969  |  |     // A8     A9     AA     AB     AC     AD     AE     AF  | 
970  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
971  |  |     // B0     B1     B2     B3     B4     B5     B6     B7  | 
972  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
973  |  |     // B8     B9     BA     BB     BC     BD     BE     BF  | 
974  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
975  |  |     // C0     C1     C2     C3     C4     C5     C6     C7  | 
976  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
977  |  |     // C8     C9     CA     CB     CC     CD     CE     CF  | 
978  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
979  |  |     // D0     D1     D2     D3     D4     D5     D6     D7  | 
980  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
981  |  |     // D8     D9     DA     DB     DC     DD     DE     DF  | 
982  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
983  |  |     // E0     E1     E2     E3     E4     E5     E6     E7  | 
984  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
985  |  |     // E8     E9     EA     EB     EC     ED     EE     EF  | 
986  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
987  |  |     // F0     F1     F2     F3     F4     F5     F6     F7  | 
988  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,  | 
989  |  |     // F8     F9     FA     FB     FC     FD     FE     FF  | 
990  |  |     0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80};  | 
991  |  |  | 
992  | 0  | ada_really_inline constexpr bool bit_at(const uint8_t a[], const uint8_t i) { | 
993  | 0  |   return !!(a[i >> 3] & (1 << (i & 7)));  | 
994  | 0  | }  | 
995  |  |  | 
996  |  | }  // namespace ada::character_sets  | 
997  |  |  | 
998  |  | #endif  // ADA_CHARACTER_SETS_INL_H  | 
999  |  | /* end file include/ada/character_sets-inl.h */  | 
1000  |  | /* begin file include/ada/checkers-inl.h */  | 
1001  |  | /**  | 
1002  |  |  * @file checkers-inl.h  | 
1003  |  |  * @brief Definitions for URL specific checkers used within Ada.  | 
1004  |  |  */  | 
1005  |  | #ifndef ADA_CHECKERS_INL_H  | 
1006  |  | #define ADA_CHECKERS_INL_H  | 
1007  |  |  | 
1008  |  | #include <bit>  | 
1009  |  | #include <string_view>  | 
1010  |  |  | 
1011  |  | namespace ada::checkers { | 
1012  |  |  | 
1013  | 0  | constexpr bool has_hex_prefix_unsafe(std::string_view input) { | 
1014  | 0  |   // This is actually efficient code, see has_hex_prefix for the assembly.  | 
1015  | 0  |   constexpr bool is_little_endian = std::endian::native == std::endian::little;  | 
1016  | 0  |   constexpr uint16_t word0x = 0x7830;  | 
1017  | 0  |   uint16_t two_first_bytes =  | 
1018  | 0  |       static_cast<uint16_t>(input[0]) |  | 
1019  | 0  |       static_cast<uint16_t>((static_cast<uint16_t>(input[1]) << 8));  | 
1020  | 0  |   if constexpr (is_little_endian) { | 
1021  | 0  |     two_first_bytes |= 0x2000;  | 
1022  | 0  |   } else { | 
1023  | 0  |     two_first_bytes |= 0x020;  | 
1024  | 0  |   }  | 
1025  | 0  |   return two_first_bytes == word0x;  | 
1026  | 0  | }  | 
1027  |  |  | 
1028  | 0  | constexpr bool has_hex_prefix(std::string_view input) { | 
1029  | 0  |   return input.size() >= 2 && has_hex_prefix_unsafe(input);  | 
1030  | 0  | }  | 
1031  |  |  | 
1032  | 0  | constexpr bool is_digit(char x) noexcept { return (x >= '0') & (x <= '9'); } | 
1033  |  |  | 
1034  | 0  | constexpr char to_lower(char x) noexcept { return (x | 0x20); } | 
1035  |  |  | 
1036  | 0  | constexpr bool is_alpha(char x) noexcept { | 
1037  | 0  |   return (to_lower(x) >= 'a') && (to_lower(x) <= 'z');  | 
1038  | 0  | }  | 
1039  |  |  | 
1040  | 0  | constexpr bool is_windows_drive_letter(std::string_view input) noexcept { | 
1041  | 0  |   return input.size() >= 2 &&  | 
1042  | 0  |          (is_alpha(input[0]) && ((input[1] == ':') || (input[1] == '|'))) &&  | 
1043  | 0  |          ((input.size() == 2) || (input[2] == '/' || input[2] == '\\' ||  | 
1044  | 0  |                                   input[2] == '?' || input[2] == '#'));  | 
1045  | 0  | }  | 
1046  |  |  | 
1047  |  | constexpr bool is_normalized_windows_drive_letter(  | 
1048  | 0  |     std::string_view input) noexcept { | 
1049  | 0  |   return input.size() >= 2 && (is_alpha(input[0]) && (input[1] == ':'));  | 
1050  | 0  | }  | 
1051  |  |  | 
1052  |  | }  // namespace ada::checkers  | 
1053  |  |  | 
1054  |  | #endif  // ADA_CHECKERS_INL_H  | 
1055  |  | /* end file include/ada/checkers-inl.h */  | 
1056  |  | /* begin file include/ada/log.h */  | 
1057  |  | /**  | 
1058  |  |  * @file log.h  | 
1059  |  |  * @brief Includes the definitions for logging.  | 
1060  |  |  * @private Excluded from docs through the doxygen file.  | 
1061  |  |  */  | 
1062  |  | #ifndef ADA_LOG_H  | 
1063  |  | #define ADA_LOG_H  | 
1064  |  |  | 
1065  |  | // To enable logging, set ADA_LOGGING to 1:  | 
1066  |  | #ifndef ADA_LOGGING  | 
1067  |  | #define ADA_LOGGING 0  | 
1068  |  | #endif  | 
1069  |  |  | 
1070  |  | #if ADA_LOGGING  | 
1071  |  | #include <iostream>  | 
1072  |  | #endif  // ADA_LOGGING  | 
1073  |  |  | 
1074  |  | namespace ada { | 
1075  |  |  | 
1076  |  | /**  | 
1077  |  |  * Log a message. If you want to have no overhead when logging is disabled, use  | 
1078  |  |  * the ada_log macro.  | 
1079  |  |  * @private  | 
1080  |  |  */  | 
1081  |  | template <typename... Args>  | 
1082  |  | constexpr ada_really_inline void log([[maybe_unused]] Args... args) { | 
1083  |  | #if ADA_LOGGING  | 
1084  |  |   ((std::cout << "ADA_LOG: ") << ... << args) << std::endl;  | 
1085  |  | #endif  // ADA_LOGGING  | 
1086  |  | }  | 
1087  |  | }  // namespace ada  | 
1088  |  |  | 
1089  |  | #if ADA_LOGGING  | 
1090  |  | #ifndef ada_log  | 
1091  |  | #define ada_log(...)       \  | 
1092  |  |   do {                     \ | 
1093  |  |     ada::log(__VA_ARGS__); \  | 
1094  |  |   } while (0)  | 
1095  |  | #endif  // ada_log  | 
1096  |  | #else  | 
1097  |  | #define ada_log(...)  | 
1098  |  | #endif  // ADA_LOGGING  | 
1099  |  |  | 
1100  |  | #endif  // ADA_LOG_H  | 
1101  |  | /* end file include/ada/log.h */  | 
1102  |  | /* begin file include/ada/encoding_type.h */  | 
1103  |  | /**  | 
1104  |  |  * @file encoding_type.h  | 
1105  |  |  * @brief Definition for supported encoding types.  | 
1106  |  |  */  | 
1107  |  | #ifndef ADA_ENCODING_TYPE_H  | 
1108  |  | #define ADA_ENCODING_TYPE_H  | 
1109  |  |  | 
1110  |  | #include <string>  | 
1111  |  |  | 
1112  |  | namespace ada { | 
1113  |  |  | 
1114  |  | /**  | 
1115  |  |  * This specification defines three encodings with the same names as encoding  | 
1116  |  |  * schemes defined in the Unicode standard: UTF-8, UTF-16LE, and UTF-16BE.  | 
1117  |  |  *  | 
1118  |  |  * @see https://encoding.spec.whatwg.org/#encodings  | 
1119  |  |  */  | 
1120  |  | enum class encoding_type { | 
1121  |  |   UTF8,  | 
1122  |  |   UTF_16LE,  | 
1123  |  |   UTF_16BE,  | 
1124  |  | };  | 
1125  |  |  | 
1126  |  | /**  | 
1127  |  |  * Convert a encoding_type to string.  | 
1128  |  |  */  | 
1129  |  | ada_warn_unused std::string_view to_string(encoding_type type);  | 
1130  |  |  | 
1131  |  | }  // namespace ada  | 
1132  |  |  | 
1133  |  | #endif  // ADA_ENCODING_TYPE_H  | 
1134  |  | /* end file include/ada/encoding_type.h */  | 
1135  |  | /* begin file include/ada/helpers.h */  | 
1136  |  | /**  | 
1137  |  |  * @file helpers.h  | 
1138  |  |  * @brief Definitions for helper functions used within Ada.  | 
1139  |  |  */  | 
1140  |  | #ifndef ADA_HELPERS_H  | 
1141  |  | #define ADA_HELPERS_H  | 
1142  |  |  | 
1143  |  | /* begin file include/ada/url_base.h */  | 
1144  |  | /**  | 
1145  |  |  * @file url_base.h  | 
1146  |  |  * @brief Declaration for the basic URL definitions  | 
1147  |  |  */  | 
1148  |  | #ifndef ADA_URL_BASE_H  | 
1149  |  | #define ADA_URL_BASE_H  | 
1150  |  |  | 
1151  |  | /* begin file include/ada/scheme.h */  | 
1152  |  | /**  | 
1153  |  |  * @file scheme.h  | 
1154  |  |  * @brief Declarations for the URL scheme.  | 
1155  |  |  */  | 
1156  |  | #ifndef ADA_SCHEME_H  | 
1157  |  | #define ADA_SCHEME_H  | 
1158  |  |  | 
1159  |  |  | 
1160  |  | #include <string>  | 
1161  |  |  | 
1162  |  | /**  | 
1163  |  |  * @namespace ada::scheme  | 
1164  |  |  * @brief Includes the scheme declarations  | 
1165  |  |  */  | 
1166  |  | namespace ada::scheme { | 
1167  |  |  | 
1168  |  | /**  | 
1169  |  |  * Type of the scheme as an enum.  | 
1170  |  |  * Using strings to represent a scheme type is not ideal because  | 
1171  |  |  * checking for types involves string comparisons. It is faster to use  | 
1172  |  |  * a simple integer.  | 
1173  |  |  * In C++11, we are allowed to specify the underlying type of the enum.  | 
1174  |  |  * We pick an 8-bit integer (which allows up to 256 types). Specifying the  | 
1175  |  |  * type of the enum may help integration with other systems if the type  | 
1176  |  |  * variable is exposed (since its value will not depend on the compiler).  | 
1177  |  |  */  | 
1178  |  | enum type : uint8_t { | 
1179  |  |   HTTP = 0,  | 
1180  |  |   NOT_SPECIAL = 1,  | 
1181  |  |   HTTPS = 2,  | 
1182  |  |   WS = 3,  | 
1183  |  |   FTP = 4,  | 
1184  |  |   WSS = 5,  | 
1185  |  |   FILE = 6  | 
1186  |  | };  | 
1187  |  |  | 
1188  |  | /**  | 
1189  |  |  * A special scheme is an ASCII string that is listed in the first column of the  | 
1190  |  |  * following table. The default port for a special scheme is listed in the  | 
1191  |  |  * second column on the same row. The default port for any other ASCII string is  | 
1192  |  |  * null.  | 
1193  |  |  *  | 
1194  |  |  * @see https://url.spec.whatwg.org/#url-miscellaneous  | 
1195  |  |  * @param scheme  | 
1196  |  |  * @return If scheme is a special scheme  | 
1197  |  |  */  | 
1198  |  | ada_really_inline constexpr bool is_special(std::string_view scheme);  | 
1199  |  |  | 
1200  |  | /**  | 
1201  |  |  * A special scheme is an ASCII string that is listed in the first column of the  | 
1202  |  |  * following table. The default port for a special scheme is listed in the  | 
1203  |  |  * second column on the same row. The default port for any other ASCII string is  | 
1204  |  |  * null.  | 
1205  |  |  *  | 
1206  |  |  * @see https://url.spec.whatwg.org/#url-miscellaneous  | 
1207  |  |  * @param scheme  | 
1208  |  |  * @return The special port  | 
1209  |  |  */  | 
1210  |  | constexpr uint16_t get_special_port(std::string_view scheme) noexcept;  | 
1211  |  |  | 
1212  |  | /**  | 
1213  |  |  * Returns the port number of a special scheme.  | 
1214  |  |  * @see https://url.spec.whatwg.org/#special-scheme  | 
1215  |  |  */  | 
1216  |  | constexpr uint16_t get_special_port(ada::scheme::type type) noexcept;  | 
1217  |  | /**  | 
1218  |  |  * Returns the scheme of an input, or NOT_SPECIAL if it's not a special scheme  | 
1219  |  |  * defined by the spec.  | 
1220  |  |  */  | 
1221  |  | constexpr ada::scheme::type get_scheme_type(std::string_view scheme) noexcept;  | 
1222  |  |  | 
1223  |  | }  // namespace ada::scheme  | 
1224  |  |  | 
1225  |  | #endif  // ADA_SCHEME_H  | 
1226  |  | /* end file include/ada/scheme.h */  | 
1227  |  |  | 
1228  |  | #include <string>  | 
1229  |  | #include <string_view>  | 
1230  |  |  | 
1231  |  | namespace ada { | 
1232  |  |  | 
1233  |  | /**  | 
1234  |  |  * Type of URL host as an enum.  | 
1235  |  |  */  | 
1236  |  | enum url_host_type : uint8_t { | 
1237  |  |   /**  | 
1238  |  |    * Represents common URLs such as "https://www.google.com"  | 
1239  |  |    */  | 
1240  |  |   DEFAULT = 0,  | 
1241  |  |   /**  | 
1242  |  |    * Represents ipv4 addresses such as "http://127.0.0.1"  | 
1243  |  |    */  | 
1244  |  |   IPV4 = 1,  | 
1245  |  |   /**  | 
1246  |  |    * Represents ipv6 addresses such as  | 
1247  |  |    * "http://[2001:db8:3333:4444:5555:6666:7777:8888]"  | 
1248  |  |    */  | 
1249  |  |   IPV6 = 2,  | 
1250  |  | };  | 
1251  |  |  | 
1252  |  | /**  | 
1253  |  |  * @brief Base class of URL implementations  | 
1254  |  |  *  | 
1255  |  |  * @details A url_base contains a few attributes: is_valid, has_opaque_path and  | 
1256  |  |  * type. All non-trivial implementation details are in derived classes such as  | 
1257  |  |  * ada::url and ada::url_aggregator.  | 
1258  |  |  *  | 
1259  |  |  * It is an abstract class that cannot be instantiated directly.  | 
1260  |  |  */  | 
1261  |  | struct url_base { | 
1262  | 0  |   virtual ~url_base() = default;  | 
1263  |  |  | 
1264  |  |   /**  | 
1265  |  |    * Used for returning the validity from the result of the URL parser.  | 
1266  |  |    */  | 
1267  |  |   bool is_valid{true}; | 
1268  |  |  | 
1269  |  |   /**  | 
1270  |  |    * A URL has an opaque path if its path is a string.  | 
1271  |  |    */  | 
1272  |  |   bool has_opaque_path{false}; | 
1273  |  |  | 
1274  |  |   /**  | 
1275  |  |    * URL hosts type  | 
1276  |  |    */  | 
1277  |  |   url_host_type host_type = url_host_type::DEFAULT;  | 
1278  |  |  | 
1279  |  |   /**  | 
1280  |  |    * @private  | 
1281  |  |    */  | 
1282  |  |   ada::scheme::type type{ada::scheme::type::NOT_SPECIAL}; | 
1283  |  |  | 
1284  |  |   /**  | 
1285  |  |    * A URL is special if its scheme is a special scheme. A URL is not special if  | 
1286  |  |    * its scheme is not a special scheme.  | 
1287  |  |    */  | 
1288  |  |   [[nodiscard]] ada_really_inline constexpr bool is_special() const noexcept;  | 
1289  |  |  | 
1290  |  |   /**  | 
1291  |  |    * The origin getter steps are to return the serialization of this's URL's  | 
1292  |  |    * origin. [HTML]  | 
1293  |  |    * @return a newly allocated string.  | 
1294  |  |    * @see https://url.spec.whatwg.org/#concept-url-origin  | 
1295  |  |    */  | 
1296  |  |   [[nodiscard]] virtual std::string get_origin() const noexcept = 0;  | 
1297  |  |  | 
1298  |  |   /**  | 
1299  |  |    * Returns true if this URL has a valid domain as per RFC 1034 and  | 
1300  |  |    * corresponding specifications. Among other things, it requires  | 
1301  |  |    * that the domain string has fewer than 255 octets.  | 
1302  |  |    */  | 
1303  |  |   [[nodiscard]] virtual bool has_valid_domain() const noexcept = 0;  | 
1304  |  |  | 
1305  |  |   /**  | 
1306  |  |    * @private  | 
1307  |  |    *  | 
1308  |  |    * Return the 'special port' if the URL is special and not 'file'.  | 
1309  |  |    * Returns 0 otherwise.  | 
1310  |  |    */  | 
1311  |  |   [[nodiscard]] inline uint16_t get_special_port() const noexcept;  | 
1312  |  |  | 
1313  |  |   /**  | 
1314  |  |    * @private  | 
1315  |  |    *  | 
1316  |  |    * Get the default port if the url's scheme has one, returns 0 otherwise.  | 
1317  |  |    */  | 
1318  |  |   [[nodiscard]] ada_really_inline uint16_t scheme_default_port() const noexcept;  | 
1319  |  |  | 
1320  |  |   /**  | 
1321  |  |    * @private  | 
1322  |  |    *  | 
1323  |  |    * Parse a port (16-bit decimal digit) from the provided input.  | 
1324  |  |    * We assume that the input does not contain spaces or tabs  | 
1325  |  |    * within the ASCII digits.  | 
1326  |  |    * It returns how many bytes were consumed when a number is successfully  | 
1327  |  |    * parsed.  | 
1328  |  |    * @return On failure, it returns zero.  | 
1329  |  |    * @see https://url.spec.whatwg.org/#host-parsing  | 
1330  |  |    */  | 
1331  |  |   virtual size_t parse_port(std::string_view view,  | 
1332  |  |                             bool check_trailing_content) noexcept = 0;  | 
1333  |  |  | 
1334  | 0  |   virtual ada_really_inline size_t parse_port(std::string_view view) noexcept { | 
1335  | 0  |     return this->parse_port(view, false);  | 
1336  | 0  |   }  | 
1337  |  |  | 
1338  |  |   /**  | 
1339  |  |    * Returns a JSON string representation of this URL.  | 
1340  |  |    */  | 
1341  |  |   [[nodiscard]] virtual std::string to_string() const = 0;  | 
1342  |  |  | 
1343  |  |   /** @private */  | 
1344  |  |   virtual inline void clear_pathname() = 0;  | 
1345  |  |  | 
1346  |  |   /** @private */  | 
1347  |  |   virtual inline void clear_search() = 0;  | 
1348  |  |  | 
1349  |  |   /** @private */  | 
1350  |  |   [[nodiscard]] virtual inline bool has_hash() const noexcept = 0;  | 
1351  |  |  | 
1352  |  |   /** @private */  | 
1353  |  |   [[nodiscard]] virtual inline bool has_search() const noexcept = 0;  | 
1354  |  |  | 
1355  |  | };  // url_base  | 
1356  |  |  | 
1357  |  | }  // namespace ada  | 
1358  |  |  | 
1359  |  | #endif  | 
1360  |  | /* end file include/ada/url_base.h */  | 
1361  |  |  | 
1362  |  | #include <string>  | 
1363  |  | #include <string_view>  | 
1364  |  | #include <optional>  | 
1365  |  |  | 
1366  |  | #if ADA_DEVELOPMENT_CHECKS  | 
1367  |  | #include <iostream>  | 
1368  |  | #endif  // ADA_DEVELOPMENT_CHECKS  | 
1369  |  |  | 
1370  |  | /**  | 
1371  |  |  * These functions are not part of our public API and may  | 
1372  |  |  * change at any time.  | 
1373  |  |  *  | 
1374  |  |  * @private  | 
1375  |  |  * @namespace ada::helpers  | 
1376  |  |  * @brief Includes the definitions for helper functions  | 
1377  |  |  */  | 
1378  |  | namespace ada::helpers { | 
1379  |  |  | 
1380  |  | /**  | 
1381  |  |  * @private  | 
1382  |  |  */  | 
1383  |  | template <typename out_iter>  | 
1384  |  | void encode_json(std::string_view view, out_iter out);  | 
1385  |  |  | 
1386  |  | /**  | 
1387  |  |  * @private  | 
1388  |  |  * This function is used to prune a fragment from a url, and returning the  | 
1389  |  |  * removed string if input has fragment.  | 
1390  |  |  *  | 
1391  |  |  * @details prune_hash seeks the first '#' and returns everything after it  | 
1392  |  |  * as a string_view, and modifies (in place) the input so that it points at  | 
1393  |  |  * everything before the '#'. If no '#' is found, the input is left unchanged  | 
1394  |  |  * and std::nullopt is returned.  | 
1395  |  |  *  | 
1396  |  |  * @attention The function is non-allocating and it does not throw.  | 
1397  |  |  * @returns Note that the returned string_view might be empty!  | 
1398  |  |  */  | 
1399  |  | ada_really_inline std::optional<std::string_view> prune_hash(  | 
1400  |  |     std::string_view& input) noexcept;  | 
1401  |  |  | 
1402  |  | /**  | 
1403  |  |  * @private  | 
1404  |  |  * Defined by the URL specification, shorten a URLs paths.  | 
1405  |  |  * @see https://url.spec.whatwg.org/#shorten-a-urls-path  | 
1406  |  |  * @returns Returns true if path is shortened.  | 
1407  |  |  */  | 
1408  |  | ada_really_inline bool shorten_path(std::string& path,  | 
1409  |  |                                     ada::scheme::type type) noexcept;  | 
1410  |  |  | 
1411  |  | /**  | 
1412  |  |  * @private  | 
1413  |  |  * Defined by the URL specification, shorten a URLs paths.  | 
1414  |  |  * @see https://url.spec.whatwg.org/#shorten-a-urls-path  | 
1415  |  |  * @returns Returns true if path is shortened.  | 
1416  |  |  */  | 
1417  |  | ada_really_inline bool shorten_path(std::string_view& path,  | 
1418  |  |                                     ada::scheme::type type) noexcept;  | 
1419  |  |  | 
1420  |  | /**  | 
1421  |  |  * @private  | 
1422  |  |  *  | 
1423  |  |  * Parse the path from the provided input and append to the existing  | 
1424  |  |  * (possibly empty) path. The input cannot contain tabs and spaces: it  | 
1425  |  |  * is the user's responsibility to check.  | 
1426  |  |  *  | 
1427  |  |  * The input is expected to be UTF-8.  | 
1428  |  |  *  | 
1429  |  |  * @see https://url.spec.whatwg.org/  | 
1430  |  |  */  | 
1431  |  | ada_really_inline void parse_prepared_path(std::string_view input,  | 
1432  |  |                                            ada::scheme::type type,  | 
1433  |  |                                            std::string& path);  | 
1434  |  |  | 
1435  |  | /**  | 
1436  |  |  * @private  | 
1437  |  |  * Remove and mutate all ASCII tab or newline characters from an input.  | 
1438  |  |  */  | 
1439  |  | ada_really_inline void remove_ascii_tab_or_newline(std::string& input) noexcept;  | 
1440  |  |  | 
1441  |  | /**  | 
1442  |  |  * @private  | 
1443  |  |  * Return the substring from input going from index pos to the end.  | 
1444  |  |  * This function cannot throw.  | 
1445  |  |  */  | 
1446  |  | ada_really_inline constexpr std::string_view substring(std::string_view input,  | 
1447  |  |                                                        size_t pos) noexcept;  | 
1448  |  |  | 
1449  |  | /**  | 
1450  |  |  * @private  | 
1451  |  |  * Returns true if the string_view points within the string.  | 
1452  |  |  */  | 
1453  |  | bool overlaps(std::string_view input1, const std::string& input2) noexcept;  | 
1454  |  |  | 
1455  |  | /**  | 
1456  |  |  * @private  | 
1457  |  |  * Return the substring from input going from index pos1 to the pos2 (non  | 
1458  |  |  * included). The length of the substring is pos2 - pos1.  | 
1459  |  |  */  | 
1460  |  | ada_really_inline constexpr std::string_view substring(std::string_view input,  | 
1461  |  |                                                        size_t pos1,  | 
1462  | 0  |                                                        size_t pos2) noexcept { | 
1463  |  | #if ADA_DEVELOPMENT_CHECKS  | 
1464  |  |   if (pos2 < pos1) { | 
1465  |  |     std::cerr << "Negative-length substring: [" << pos1 << " to " << pos2 << ")"  | 
1466  |  |               << std::endl;  | 
1467  |  |     abort();  | 
1468  |  |   }  | 
1469  |  | #endif  | 
1470  | 0  |   return input.substr(pos1, pos2 - pos1);  | 
1471  | 0  | }  | 
1472  |  |  | 
1473  |  | /**  | 
1474  |  |  * @private  | 
1475  |  |  * Modify the string_view so that it has the new size pos, assuming that pos <=  | 
1476  |  |  * input.size(). This function cannot throw.  | 
1477  |  |  */  | 
1478  |  | ada_really_inline void resize(std::string_view& input, size_t pos) noexcept;  | 
1479  |  |  | 
1480  |  | /**  | 
1481  |  |  * @private  | 
1482  |  |  * Returns a host's delimiter location depending on the state of the instance,  | 
1483  |  |  * and whether a colon was found outside brackets. Used by the host parser.  | 
1484  |  |  */  | 
1485  |  | ada_really_inline std::pair<size_t, bool> get_host_delimiter_location(  | 
1486  |  |     bool is_special, std::string_view& view) noexcept;  | 
1487  |  |  | 
1488  |  | /**  | 
1489  |  |  * @private  | 
1490  |  |  * Removes leading and trailing C0 control and whitespace characters from  | 
1491  |  |  * string.  | 
1492  |  |  */  | 
1493  |  | void trim_c0_whitespace(std::string_view& input) noexcept;  | 
1494  |  |  | 
1495  |  | /**  | 
1496  |  |  * @private  | 
1497  |  |  * @see  | 
1498  |  |  * https://url.spec.whatwg.org/#potentially-strip-trailing-spaces-from-an-opaque-path  | 
1499  |  |  */  | 
1500  |  | template <class url_type>  | 
1501  |  | ada_really_inline void strip_trailing_spaces_from_opaque_path(  | 
1502  |  |     url_type& url) noexcept;  | 
1503  |  |  | 
1504  |  | /**  | 
1505  |  |  * @private  | 
1506  |  |  * Finds the delimiter of a view in authority state.  | 
1507  |  |  */  | 
1508  |  | ada_really_inline size_t  | 
1509  |  | find_authority_delimiter_special(std::string_view view) noexcept;  | 
1510  |  |  | 
1511  |  | /**  | 
1512  |  |  * @private  | 
1513  |  |  * Finds the delimiter of a view in authority state.  | 
1514  |  |  */  | 
1515  |  | ada_really_inline size_t  | 
1516  |  | find_authority_delimiter(std::string_view view) noexcept;  | 
1517  |  |  | 
1518  |  | /**  | 
1519  |  |  * @private  | 
1520  |  |  */  | 
1521  |  | template <typename T, typename... Args>  | 
1522  | 0  | inline void inner_concat(std::string& buffer, T t) { | 
1523  | 0  |   buffer.append(t);  | 
1524  | 0  | }  | 
1525  |  |  | 
1526  |  | /**  | 
1527  |  |  * @private  | 
1528  |  |  */  | 
1529  |  | template <typename T, typename... Args>  | 
1530  | 0  | inline void inner_concat(std::string& buffer, T t, Args... args) { | 
1531  | 0  |   buffer.append(t);  | 
1532  | 0  |   return inner_concat(buffer, args...);  | 
1533  | 0  | }  | 
1534  |  |  | 
1535  |  | /**  | 
1536  |  |  * @private  | 
1537  |  |  * Concatenate the arguments and return a string.  | 
1538  |  |  * @returns a string  | 
1539  |  |  */  | 
1540  |  | template <typename... Args>  | 
1541  | 0  | std::string concat(Args... args) { | 
1542  | 0  |   std::string answer;  | 
1543  | 0  |   inner_concat(answer, args...);  | 
1544  | 0  |   return answer;  | 
1545  | 0  | }  | 
1546  |  |  | 
1547  |  | /**  | 
1548  |  |  * @private  | 
1549  |  |  * @return Number of leading zeroes.  | 
1550  |  |  */  | 
1551  | 0  | inline int leading_zeroes(uint32_t input_num) noexcept { | 
1552  | 0  | #if ADA_REGULAR_VISUAL_STUDIO  | 
1553  | 0  |   unsigned long leading_zero(0);  | 
1554  | 0  |   unsigned long in(input_num);  | 
1555  | 0  |   return _BitScanReverse(&leading_zero, in) ? int(31 - leading_zero) : 32;  | 
1556  | 0  | #else  | 
1557  | 0  |   return __builtin_clz(input_num);  | 
1558  | 0  | #endif  // ADA_REGULAR_VISUAL_STUDIO  | 
1559  | 0  | }  | 
1560  |  |  | 
1561  |  | /**  | 
1562  |  |  * @private  | 
1563  |  |  * Counts the number of decimal digits necessary to represent x.  | 
1564  |  |  * faster than std::to_string(x).size().  | 
1565  |  |  * @return digit count  | 
1566  |  |  */  | 
1567  | 0  | inline int fast_digit_count(uint32_t x) noexcept { | 
1568  | 0  |   auto int_log2 = [](uint32_t z) -> int { | 
1569  | 0  |     return 31 - ada::helpers::leading_zeroes(z | 1);  | 
1570  | 0  |   };  | 
1571  | 0  |   // Compiles to very few instructions. Note that the  | 
1572  | 0  |   // table is static and thus effectively a constant.  | 
1573  | 0  |   // We leave it inside the function because it is meaningless  | 
1574  | 0  |   // outside of it (this comes at no performance cost).  | 
1575  | 0  |   const static uint64_t table[] = { | 
1576  | 0  |       4294967296,  8589934582,  8589934582,  8589934582,  12884901788,  | 
1577  | 0  |       12884901788, 12884901788, 17179868184, 17179868184, 17179868184,  | 
1578  | 0  |       21474826480, 21474826480, 21474826480, 21474826480, 25769703776,  | 
1579  | 0  |       25769703776, 25769703776, 30063771072, 30063771072, 30063771072,  | 
1580  | 0  |       34349738368, 34349738368, 34349738368, 34349738368, 38554705664,  | 
1581  | 0  |       38554705664, 38554705664, 41949672960, 41949672960, 41949672960,  | 
1582  | 0  |       42949672960, 42949672960};  | 
1583  | 0  |   return int((x + table[int_log2(x)]) >> 32);  | 
1584  | 0  | }  | 
1585  |  | }  // namespace ada::helpers  | 
1586  |  |  | 
1587  |  | #endif  // ADA_HELPERS_H  | 
1588  |  | /* end file include/ada/helpers.h */  | 
1589  |  | /* begin file include/ada/parser.h */  | 
1590  |  | /**  | 
1591  |  |  * @file parser.h  | 
1592  |  |  * @brief Definitions for the parser.  | 
1593  |  |  */  | 
1594  |  | #ifndef ADA_PARSER_H  | 
1595  |  | #define ADA_PARSER_H  | 
1596  |  |  | 
1597  |  | #include <string_view>  | 
1598  |  | #include <variant>  | 
1599  |  |  | 
1600  |  | /* begin file include/ada/expected.h */  | 
1601  |  | /**  | 
1602  |  |  * @file expected.h  | 
1603  |  |  * @brief Definitions for std::expected  | 
1604  |  |  * @private Excluded from docs through the doxygen file.  | 
1605  |  |  */  | 
1606  |  | ///  | 
1607  |  | // expected - An implementation of std::expected with extensions  | 
1608  |  | // Written in 2017 by Sy Brand (tartanllama@gmail.com, @TartanLlama)  | 
1609  |  | //  | 
1610  |  | // Documentation available at http://tl.tartanllama.xyz/  | 
1611  |  | //  | 
1612  |  | // To the extent possible under law, the author(s) have dedicated all  | 
1613  |  | // copyright and related and neighboring rights to this software to the  | 
1614  |  | // public domain worldwide. This software is distributed without any warranty.  | 
1615  |  | //  | 
1616  |  | // You should have received a copy of the CC0 Public Domain Dedication  | 
1617  |  | // along with this software. If not, see  | 
1618  |  | // <http://creativecommons.org/publicdomain/zero/1.0/>.  | 
1619  |  | ///  | 
1620  |  |  | 
1621  |  | #ifndef TL_EXPECTED_HPP  | 
1622  |  | #define TL_EXPECTED_HPP  | 
1623  |  |  | 
1624  |  | #define TL_EXPECTED_VERSION_MAJOR 1  | 
1625  |  | #define TL_EXPECTED_VERSION_MINOR 1  | 
1626  |  | #define TL_EXPECTED_VERSION_PATCH 0  | 
1627  |  |  | 
1628  |  | #include <exception>  | 
1629  |  | #include <functional>  | 
1630  |  | #include <type_traits>  | 
1631  |  | #include <utility>  | 
1632  |  |  | 
1633  |  | #if defined(__EXCEPTIONS) || defined(_CPPUNWIND)  | 
1634  |  | #define TL_EXPECTED_EXCEPTIONS_ENABLED  | 
1635  |  | #endif  | 
1636  |  |  | 
1637  |  | #if (defined(_MSC_VER) && _MSC_VER == 1900)  | 
1638  |  | #define TL_EXPECTED_MSVC2015  | 
1639  |  | #define TL_EXPECTED_MSVC2015_CONSTEXPR  | 
1640  |  | #else  | 
1641  |  | #define TL_EXPECTED_MSVC2015_CONSTEXPR constexpr  | 
1642  |  | #endif  | 
1643  |  |  | 
1644  |  | #if (defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ <= 9 && \  | 
1645  |  |      !defined(__clang__))  | 
1646  |  | #define TL_EXPECTED_GCC49  | 
1647  |  | #endif  | 
1648  |  |  | 
1649  |  | #if (defined(__GNUC__) && __GNUC__ == 5 && __GNUC_MINOR__ <= 4 && \  | 
1650  |  |      !defined(__clang__))  | 
1651  |  | #define TL_EXPECTED_GCC54  | 
1652  |  | #endif  | 
1653  |  |  | 
1654  |  | #if (defined(__GNUC__) && __GNUC__ == 5 && __GNUC_MINOR__ <= 5 && \  | 
1655  |  |      !defined(__clang__))  | 
1656  |  | #define TL_EXPECTED_GCC55  | 
1657  |  | #endif  | 
1658  |  |  | 
1659  |  | #if !defined(TL_ASSERT)  | 
1660  |  | // can't have assert in constexpr in C++11 and GCC 4.9 has a compiler bug  | 
1661  |  | #if (__cplusplus > 201103L) && !defined(TL_EXPECTED_GCC49)  | 
1662  |  | #include <cassert>  | 
1663  | 0  | #define TL_ASSERT(x) assert(x)  | 
1664  |  | #else  | 
1665  |  | #define TL_ASSERT(x)  | 
1666  |  | #endif  | 
1667  |  | #endif  | 
1668  |  |  | 
1669  |  | #if (defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ <= 9 && \  | 
1670  |  |      !defined(__clang__))  | 
1671  |  | // GCC < 5 doesn't support overloading on const&& for member functions  | 
1672  |  |  | 
1673  |  | #define TL_EXPECTED_NO_CONSTRR  | 
1674  |  | // GCC < 5 doesn't support some standard C++11 type traits  | 
1675  |  | #define TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) \  | 
1676  |  |   std::has_trivial_copy_constructor<T>  | 
1677  |  | #define TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(T) \  | 
1678  |  |   std::has_trivial_copy_assign<T>  | 
1679  |  |  | 
1680  |  | // This one will be different for GCC 5.7 if it's ever supported  | 
1681  |  | #define TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(T) \  | 
1682  |  |   std::is_trivially_destructible<T>  | 
1683  |  |  | 
1684  |  | // GCC 5 < v < 8 has a bug in is_trivially_copy_constructible which breaks  | 
1685  |  | // std::vector for non-copyable types  | 
1686  |  | #elif (defined(__GNUC__) && __GNUC__ < 8 && !defined(__clang__))  | 
1687  |  | #ifndef TL_GCC_LESS_8_TRIVIALLY_COPY_CONSTRUCTIBLE_MUTEX  | 
1688  |  | #define TL_GCC_LESS_8_TRIVIALLY_COPY_CONSTRUCTIBLE_MUTEX  | 
1689  |  | namespace tl { | 
1690  |  | namespace detail { | 
1691  |  | template <class T>  | 
1692  |  | struct is_trivially_copy_constructible  | 
1693  |  |     : std::is_trivially_copy_constructible<T> {}; | 
1694  |  | #ifdef _GLIBCXX_VECTOR  | 
1695  |  | template <class T, class A>  | 
1696  |  | struct is_trivially_copy_constructible<std::vector<T, A>> : std::false_type {}; | 
1697  |  | #endif  | 
1698  |  | }  // namespace detail  | 
1699  |  | }  // namespace tl  | 
1700  |  | #endif  | 
1701  |  |  | 
1702  |  | #define TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) \  | 
1703  |  |   tl::detail::is_trivially_copy_constructible<T>  | 
1704  |  | #define TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(T) \  | 
1705  |  |   std::is_trivially_copy_assignable<T>  | 
1706  |  | #define TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(T) \  | 
1707  |  |   std::is_trivially_destructible<T>  | 
1708  |  | #else  | 
1709  |  | #define TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) \  | 
1710  |  |   std::is_trivially_copy_constructible<T>  | 
1711  |  | #define TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(T) \  | 
1712  |  |   std::is_trivially_copy_assignable<T>  | 
1713  |  | #define TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(T) \  | 
1714  |  |   std::is_trivially_destructible<T>  | 
1715  |  | #endif  | 
1716  |  |  | 
1717  |  | #if __cplusplus > 201103L  | 
1718  |  | #define TL_EXPECTED_CXX14  | 
1719  |  | #endif  | 
1720  |  |  | 
1721  |  | #ifdef TL_EXPECTED_GCC49  | 
1722  |  | #define TL_EXPECTED_GCC49_CONSTEXPR  | 
1723  |  | #else  | 
1724  |  | #define TL_EXPECTED_GCC49_CONSTEXPR constexpr  | 
1725  |  | #endif  | 
1726  |  |  | 
1727  |  | #if (__cplusplus == 201103L || defined(TL_EXPECTED_MSVC2015) || \  | 
1728  |  |      defined(TL_EXPECTED_GCC49))  | 
1729  |  | #define TL_EXPECTED_11_CONSTEXPR  | 
1730  |  | #else  | 
1731  |  | #define TL_EXPECTED_11_CONSTEXPR constexpr  | 
1732  |  | #endif  | 
1733  |  |  | 
1734  |  | namespace tl { | 
1735  |  | template <class T, class E>  | 
1736  |  | class expected;  | 
1737  |  |  | 
1738  |  | #ifndef TL_MONOSTATE_INPLACE_MUTEX  | 
1739  |  | #define TL_MONOSTATE_INPLACE_MUTEX  | 
1740  |  | class monostate {}; | 
1741  |  |  | 
1742  |  | struct in_place_t { | 
1743  |  |   explicit in_place_t() = default;  | 
1744  |  | };  | 
1745  |  | static constexpr in_place_t in_place{}; | 
1746  |  | #endif  | 
1747  |  |  | 
1748  |  | template <class E>  | 
1749  |  | class unexpected { | 
1750  |  |  public:  | 
1751  |  |   static_assert(!std::is_same<E, void>::value, "E must not be void");  | 
1752  |  |  | 
1753  |  |   unexpected() = delete;  | 
1754  | 0  |   constexpr explicit unexpected(const E &e) : m_val(e) {} | 
1755  |  |  | 
1756  | 0  |   constexpr explicit unexpected(E &&e) : m_val(std::move(e)) {} | 
1757  |  |  | 
1758  |  |   template <class... Args, typename std::enable_if<std::is_constructible<  | 
1759  |  |                                E, Args &&...>::value>::type * = nullptr>  | 
1760  |  |   constexpr explicit unexpected(Args &&...args)  | 
1761  | 0  |       : m_val(std::forward<Args>(args)...) {} | 
1762  |  |   template <  | 
1763  |  |       class U, class... Args,  | 
1764  |  |       typename std::enable_if<std::is_constructible<  | 
1765  |  |           E, std::initializer_list<U> &, Args &&...>::value>::type * = nullptr>  | 
1766  |  |   constexpr explicit unexpected(std::initializer_list<U> l, Args &&...args)  | 
1767  |  |       : m_val(l, std::forward<Args>(args)...) {} | 
1768  |  |  | 
1769  |  |   constexpr const E &value() const & { return m_val; } | 
1770  | 0  |   TL_EXPECTED_11_CONSTEXPR E &value() & { return m_val; } | 
1771  |  |   TL_EXPECTED_11_CONSTEXPR E &&value() && { return std::move(m_val); } | 
1772  |  |   constexpr const E &&value() const && { return std::move(m_val); } | 
1773  |  |  | 
1774  |  |  private:  | 
1775  |  |   E m_val;  | 
1776  |  | };  | 
1777  |  |  | 
1778  |  | #ifdef __cpp_deduction_guides  | 
1779  |  | template <class E>  | 
1780  |  | unexpected(E) -> unexpected<E>;  | 
1781  |  | #endif  | 
1782  |  |  | 
1783  |  | template <class E>  | 
1784  |  | constexpr bool operator==(const unexpected<E> &lhs, const unexpected<E> &rhs) { | 
1785  |  |   return lhs.value() == rhs.value();  | 
1786  |  | }  | 
1787  |  | template <class E>  | 
1788  |  | constexpr bool operator!=(const unexpected<E> &lhs, const unexpected<E> &rhs) { | 
1789  |  |   return lhs.value() != rhs.value();  | 
1790  |  | }  | 
1791  |  | template <class E>  | 
1792  |  | constexpr bool operator<(const unexpected<E> &lhs, const unexpected<E> &rhs) { | 
1793  |  |   return lhs.value() < rhs.value();  | 
1794  |  | }  | 
1795  |  | template <class E>  | 
1796  |  | constexpr bool operator<=(const unexpected<E> &lhs, const unexpected<E> &rhs) { | 
1797  |  |   return lhs.value() <= rhs.value();  | 
1798  |  | }  | 
1799  |  | template <class E>  | 
1800  |  | constexpr bool operator>(const unexpected<E> &lhs, const unexpected<E> &rhs) { | 
1801  |  |   return lhs.value() > rhs.value();  | 
1802  |  | }  | 
1803  |  | template <class E>  | 
1804  |  | constexpr bool operator>=(const unexpected<E> &lhs, const unexpected<E> &rhs) { | 
1805  |  |   return lhs.value() >= rhs.value();  | 
1806  |  | }  | 
1807  |  |  | 
1808  |  | template <class E>  | 
1809  |  | unexpected<typename std::decay<E>::type> make_unexpected(E &&e) { | 
1810  |  |   return unexpected<typename std::decay<E>::type>(std::forward<E>(e));  | 
1811  |  | }  | 
1812  |  |  | 
1813  |  | struct unexpect_t { | 
1814  |  |   unexpect_t() = default;  | 
1815  |  | };  | 
1816  |  | static constexpr unexpect_t unexpect{}; | 
1817  |  |  | 
1818  |  | namespace detail { | 
1819  |  | template <typename E>  | 
1820  | 0  | [[noreturn]] TL_EXPECTED_11_CONSTEXPR void throw_exception(E &&e) { | 
1821  |  | #ifdef TL_EXPECTED_EXCEPTIONS_ENABLED  | 
1822  |  |   throw std::forward<E>(e);  | 
1823  |  | #else  | 
1824  | 0  |   (void)e;  | 
1825  |  | #ifdef _MSC_VER  | 
1826  |  |   __assume(0);  | 
1827  |  | #else  | 
1828  | 0  |   __builtin_unreachable();  | 
1829  | 0  | #endif  | 
1830  | 0  | #endif  | 
1831  | 0  | }  | 
1832  |  |  | 
1833  |  | #ifndef TL_TRAITS_MUTEX  | 
1834  |  | #define TL_TRAITS_MUTEX  | 
1835  |  | // C++14-style aliases for brevity  | 
1836  |  | template <class T>  | 
1837  |  | using remove_const_t = typename std::remove_const<T>::type;  | 
1838  |  | template <class T>  | 
1839  |  | using remove_reference_t = typename std::remove_reference<T>::type;  | 
1840  |  | template <class T>  | 
1841  |  | using decay_t = typename std::decay<T>::type;  | 
1842  |  | template <bool E, class T = void>  | 
1843  |  | using enable_if_t = typename std::enable_if<E, T>::type;  | 
1844  |  | template <bool B, class T, class F>  | 
1845  |  | using conditional_t = typename std::conditional<B, T, F>::type;  | 
1846  |  |  | 
1847  |  | // std::conjunction from C++17  | 
1848  |  | template <class...>  | 
1849  |  | struct conjunction : std::true_type {}; | 
1850  |  | template <class B>  | 
1851  |  | struct conjunction<B> : B {}; | 
1852  |  | template <class B, class... Bs>  | 
1853  |  | struct conjunction<B, Bs...>  | 
1854  |  |     : std::conditional<bool(B::value), conjunction<Bs...>, B>::type {}; | 
1855  |  |  | 
1856  |  | #if defined(_LIBCPP_VERSION) && __cplusplus == 201103L  | 
1857  |  | #define TL_TRAITS_LIBCXX_MEM_FN_WORKAROUND  | 
1858  |  | #endif  | 
1859  |  |  | 
1860  |  | // In C++11 mode, there's an issue in libc++'s std::mem_fn  | 
1861  |  | // which results in a hard-error when using it in a noexcept expression  | 
1862  |  | // in some cases. This is a check to workaround the common failing case.  | 
1863  |  | #ifdef TL_TRAITS_LIBCXX_MEM_FN_WORKAROUND  | 
1864  |  | template <class T>  | 
1865  |  | struct is_pointer_to_non_const_member_func : std::false_type {}; | 
1866  |  | template <class T, class Ret, class... Args>  | 
1867  |  | struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...)>  | 
1868  |  |     : std::true_type {}; | 
1869  |  | template <class T, class Ret, class... Args>  | 
1870  |  | struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...) &>  | 
1871  |  |     : std::true_type {}; | 
1872  |  | template <class T, class Ret, class... Args>  | 
1873  |  | struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...) &&>  | 
1874  |  |     : std::true_type {}; | 
1875  |  | template <class T, class Ret, class... Args>  | 
1876  |  | struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...) volatile>  | 
1877  |  |     : std::true_type {}; | 
1878  |  | template <class T, class Ret, class... Args>  | 
1879  |  | struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...) volatile &>  | 
1880  |  |     : std::true_type {}; | 
1881  |  | template <class T, class Ret, class... Args>  | 
1882  |  | struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...) volatile &&>  | 
1883  |  |     : std::true_type {}; | 
1884  |  |  | 
1885  |  | template <class T>  | 
1886  |  | struct is_const_or_const_ref : std::false_type {}; | 
1887  |  | template <class T>  | 
1888  |  | struct is_const_or_const_ref<T const &> : std::true_type {}; | 
1889  |  | template <class T>  | 
1890  |  | struct is_const_or_const_ref<T const> : std::true_type {}; | 
1891  |  | #endif  | 
1892  |  |  | 
1893  |  | // std::invoke from C++17  | 
1894  |  | // https://stackoverflow.com/questions/38288042/c11-14-invoke-workaround  | 
1895  |  | template <  | 
1896  |  |     typename Fn, typename... Args,  | 
1897  |  | #ifdef TL_TRAITS_LIBCXX_MEM_FN_WORKAROUND  | 
1898  |  |     typename = enable_if_t<!(is_pointer_to_non_const_member_func<Fn>::value &&  | 
1899  |  |                              is_const_or_const_ref<Args...>::value)>,  | 
1900  |  | #endif  | 
1901  |  |     typename = enable_if_t<std::is_member_pointer<decay_t<Fn>>::value>, int = 0>  | 
1902  |  | constexpr auto invoke(Fn &&f, Args &&...args) noexcept(  | 
1903  |  |     noexcept(std::mem_fn(f)(std::forward<Args>(args)...)))  | 
1904  |  |     -> decltype(std::mem_fn(f)(std::forward<Args>(args)...)) { | 
1905  |  |   return std::mem_fn(f)(std::forward<Args>(args)...);  | 
1906  |  | }  | 
1907  |  |  | 
1908  |  | template <typename Fn, typename... Args,  | 
1909  |  |           typename = enable_if_t<!std::is_member_pointer<decay_t<Fn>>::value>>  | 
1910  |  | constexpr auto invoke(Fn &&f, Args &&...args) noexcept(  | 
1911  |  |     noexcept(std::forward<Fn>(f)(std::forward<Args>(args)...)))  | 
1912  |  |     -> decltype(std::forward<Fn>(f)(std::forward<Args>(args)...)) { | 
1913  |  |   return std::forward<Fn>(f)(std::forward<Args>(args)...);  | 
1914  |  | }  | 
1915  |  |  | 
1916  |  | // std::invoke_result from C++17  | 
1917  |  | template <class F, class, class... Us>  | 
1918  |  | struct invoke_result_impl;  | 
1919  |  |  | 
1920  |  | template <class F, class... Us>  | 
1921  |  | struct invoke_result_impl<  | 
1922  |  |     F,  | 
1923  |  |     decltype(detail::invoke(std::declval<F>(), std::declval<Us>()...), void()),  | 
1924  |  |     Us...> { | 
1925  |  |   using type =  | 
1926  |  |       decltype(detail::invoke(std::declval<F>(), std::declval<Us>()...));  | 
1927  |  | };  | 
1928  |  |  | 
1929  |  | template <class F, class... Us>  | 
1930  |  | using invoke_result = invoke_result_impl<F, void, Us...>;  | 
1931  |  |  | 
1932  |  | template <class F, class... Us>  | 
1933  |  | using invoke_result_t = typename invoke_result<F, Us...>::type;  | 
1934  |  |  | 
1935  |  | #if defined(_MSC_VER) && _MSC_VER <= 1900  | 
1936  |  | // TODO make a version which works with MSVC 2015  | 
1937  |  | template <class T, class U = T>  | 
1938  |  | struct is_swappable : std::true_type {}; | 
1939  |  |  | 
1940  |  | template <class T, class U = T>  | 
1941  |  | struct is_nothrow_swappable : std::true_type {}; | 
1942  |  | #else  | 
1943  |  | // https://stackoverflow.com/questions/26744589/what-is-a-proper-way-to-implement-is-swappable-to-test-for-the-swappable-concept  | 
1944  |  | namespace swap_adl_tests { | 
1945  |  | // if swap ADL finds this then it would call std::swap otherwise (same  | 
1946  |  | // signature)  | 
1947  |  | struct tag {}; | 
1948  |  |  | 
1949  |  | template <class T>  | 
1950  |  | tag swap(T &, T &);  | 
1951  |  | template <class T, std::size_t N>  | 
1952  |  | tag swap(T (&a)[N], T (&b)[N]);  | 
1953  |  |  | 
1954  |  | // helper functions to test if an unqualified swap is possible, and if it  | 
1955  |  | // becomes std::swap  | 
1956  |  | template <class, class>  | 
1957  |  | std::false_type can_swap(...) noexcept(false);  | 
1958  |  | template <class T, class U,  | 
1959  |  |           class = decltype(swap(std::declval<T &>(), std::declval<U &>()))>  | 
1960  |  | std::true_type can_swap(int) noexcept(noexcept(swap(std::declval<T &>(),  | 
1961  |  |                                                     std::declval<U &>())));  | 
1962  |  |  | 
1963  |  | template <class, class>  | 
1964  |  | std::false_type uses_std(...);  | 
1965  |  | template <class T, class U>  | 
1966  |  | std::is_same<decltype(swap(std::declval<T &>(), std::declval<U &>())), tag>  | 
1967  |  | uses_std(int);  | 
1968  |  |  | 
1969  |  | template <class T>  | 
1970  |  | struct is_std_swap_noexcept  | 
1971  |  |     : std::integral_constant<bool,  | 
1972  |  |                              std::is_nothrow_move_constructible<T>::value &&  | 
1973  |  |                                  std::is_nothrow_move_assignable<T>::value> {}; | 
1974  |  |  | 
1975  |  | template <class T, std::size_t N>  | 
1976  |  | struct is_std_swap_noexcept<T[N]> : is_std_swap_noexcept<T> {}; | 
1977  |  |  | 
1978  |  | template <class T, class U>  | 
1979  |  | struct is_adl_swap_noexcept  | 
1980  |  |     : std::integral_constant<bool, noexcept(can_swap<T, U>(0))> {}; | 
1981  |  | }  // namespace swap_adl_tests  | 
1982  |  |  | 
1983  |  | template <class T, class U = T>  | 
1984  |  | struct is_swappable  | 
1985  |  |     : std::integral_constant<  | 
1986  |  |           bool,  | 
1987  |  |           decltype(detail::swap_adl_tests::can_swap<T, U>(0))::value &&  | 
1988  |  |               (!decltype(detail::swap_adl_tests::uses_std<T, U>(0))::value ||  | 
1989  |  |                (std::is_move_assignable<T>::value &&  | 
1990  |  |                 std::is_move_constructible<T>::value))> {}; | 
1991  |  |  | 
1992  |  | template <class T, std::size_t N>  | 
1993  |  | struct is_swappable<T[N], T[N]>  | 
1994  |  |     : std::integral_constant<  | 
1995  |  |           bool,  | 
1996  |  |           decltype(detail::swap_adl_tests::can_swap<T[N], T[N]>(0))::value &&  | 
1997  |  |               (!decltype(detail::swap_adl_tests::uses_std<T[N], T[N]>(  | 
1998  |  |                    0))::value ||  | 
1999  |  |                is_swappable<T, T>::value)> {}; | 
2000  |  |  | 
2001  |  | template <class T, class U = T>  | 
2002  |  | struct is_nothrow_swappable  | 
2003  |  |     : std::integral_constant<  | 
2004  |  |           bool,  | 
2005  |  |           is_swappable<T, U>::value &&  | 
2006  |  |               ((decltype(detail::swap_adl_tests::uses_std<T, U>(0))::value &&  | 
2007  |  |                 detail::swap_adl_tests::is_std_swap_noexcept<T>::value) ||  | 
2008  |  |                (!decltype(detail::swap_adl_tests::uses_std<T, U>(0))::value &&  | 
2009  |  |                 detail::swap_adl_tests::is_adl_swap_noexcept<T, U>::value))> {}; | 
2010  |  | #endif  | 
2011  |  | #endif  | 
2012  |  |  | 
2013  |  | // Trait for checking if a type is a tl::expected  | 
2014  |  | template <class T>  | 
2015  |  | struct is_expected_impl : std::false_type {}; | 
2016  |  | template <class T, class E>  | 
2017  |  | struct is_expected_impl<expected<T, E>> : std::true_type {}; | 
2018  |  | template <class T>  | 
2019  |  | using is_expected = is_expected_impl<decay_t<T>>;  | 
2020  |  |  | 
2021  |  | template <class T, class E, class U>  | 
2022  |  | using expected_enable_forward_value = detail::enable_if_t<  | 
2023  |  |     std::is_constructible<T, U &&>::value &&  | 
2024  |  |     !std::is_same<detail::decay_t<U>, in_place_t>::value &&  | 
2025  |  |     !std::is_same<expected<T, E>, detail::decay_t<U>>::value &&  | 
2026  |  |     !std::is_same<unexpected<E>, detail::decay_t<U>>::value>;  | 
2027  |  |  | 
2028  |  | template <class T, class E, class U, class G, class UR, class GR>  | 
2029  |  | using expected_enable_from_other = detail::enable_if_t<  | 
2030  |  |     std::is_constructible<T, UR>::value &&  | 
2031  |  |     std::is_constructible<E, GR>::value &&  | 
2032  |  |     !std::is_constructible<T, expected<U, G> &>::value &&  | 
2033  |  |     !std::is_constructible<T, expected<U, G> &&>::value &&  | 
2034  |  |     !std::is_constructible<T, const expected<U, G> &>::value &&  | 
2035  |  |     !std::is_constructible<T, const expected<U, G> &&>::value &&  | 
2036  |  |     !std::is_convertible<expected<U, G> &, T>::value &&  | 
2037  |  |     !std::is_convertible<expected<U, G> &&, T>::value &&  | 
2038  |  |     !std::is_convertible<const expected<U, G> &, T>::value &&  | 
2039  |  |     !std::is_convertible<const expected<U, G> &&, T>::value>;  | 
2040  |  |  | 
2041  |  | template <class T, class U>  | 
2042  |  | using is_void_or = conditional_t<std::is_void<T>::value, std::true_type, U>;  | 
2043  |  |  | 
2044  |  | template <class T>  | 
2045  |  | using is_copy_constructible_or_void =  | 
2046  |  |     is_void_or<T, std::is_copy_constructible<T>>;  | 
2047  |  |  | 
2048  |  | template <class T>  | 
2049  |  | using is_move_constructible_or_void =  | 
2050  |  |     is_void_or<T, std::is_move_constructible<T>>;  | 
2051  |  |  | 
2052  |  | template <class T>  | 
2053  |  | using is_copy_assignable_or_void = is_void_or<T, std::is_copy_assignable<T>>;  | 
2054  |  |  | 
2055  |  | template <class T>  | 
2056  |  | using is_move_assignable_or_void = is_void_or<T, std::is_move_assignable<T>>;  | 
2057  |  |  | 
2058  |  | }  // namespace detail  | 
2059  |  |  | 
2060  |  | namespace detail { | 
2061  |  | struct no_init_t {}; | 
2062  |  | static constexpr no_init_t no_init{}; | 
2063  |  |  | 
2064  |  | // Implements the storage of the values, and ensures that the destructor is  | 
2065  |  | // trivial if it can be.  | 
2066  |  | //  | 
2067  |  | // This specialization is for where neither `T` or `E` is trivially  | 
2068  |  | // destructible, so the destructors must be called on destruction of the  | 
2069  |  | // `expected`  | 
2070  |  | template <class T, class E, bool = std::is_trivially_destructible<T>::value,  | 
2071  |  |           bool = std::is_trivially_destructible<E>::value>  | 
2072  |  | struct expected_storage_base { | 
2073  |  |   constexpr expected_storage_base() : m_val(T{}), m_has_val(true) {} | 
2074  |  |   constexpr expected_storage_base(no_init_t) : m_no_init(), m_has_val(false) {} | 
2075  |  |  | 
2076  |  |   template <class... Args,  | 
2077  |  |             detail::enable_if_t<std::is_constructible<T, Args &&...>::value> * =  | 
2078  |  |                 nullptr>  | 
2079  |  |   constexpr expected_storage_base(in_place_t, Args &&...args)  | 
2080  |  |       : m_val(std::forward<Args>(args)...), m_has_val(true) {} | 
2081  |  |  | 
2082  |  |   template <class U, class... Args,  | 
2083  |  |             detail::enable_if_t<std::is_constructible<  | 
2084  |  |                 T, std::initializer_list<U> &, Args &&...>::value> * = nullptr>  | 
2085  |  |   constexpr expected_storage_base(in_place_t, std::initializer_list<U> il,  | 
2086  |  |                                   Args &&...args)  | 
2087  |  |       : m_val(il, std::forward<Args>(args)...), m_has_val(true) {} | 
2088  |  |   template <class... Args,  | 
2089  |  |             detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * =  | 
2090  |  |                 nullptr>  | 
2091  |  |   constexpr explicit expected_storage_base(unexpect_t, Args &&...args)  | 
2092  |  |       : m_unexpect(std::forward<Args>(args)...), m_has_val(false) {} | 
2093  |  |  | 
2094  |  |   template <class U, class... Args,  | 
2095  |  |             detail::enable_if_t<std::is_constructible<  | 
2096  |  |                 E, std::initializer_list<U> &, Args &&...>::value> * = nullptr>  | 
2097  |  |   constexpr explicit expected_storage_base(unexpect_t,  | 
2098  |  |                                            std::initializer_list<U> il,  | 
2099  |  |                                            Args &&...args)  | 
2100  |  |       : m_unexpect(il, std::forward<Args>(args)...), m_has_val(false) {} | 
2101  |  |  | 
2102  |  |   ~expected_storage_base() { | 
2103  |  |     if (m_has_val) { | 
2104  |  |       m_val.~T();  | 
2105  |  |     } else { | 
2106  |  |       m_unexpect.~unexpected<E>();  | 
2107  |  |     }  | 
2108  |  |   }  | 
2109  |  |   union { | 
2110  |  |     T m_val;  | 
2111  |  |     unexpected<E> m_unexpect;  | 
2112  |  |     char m_no_init;  | 
2113  |  |   };  | 
2114  |  |   bool m_has_val;  | 
2115  |  | };  | 
2116  |  |  | 
2117  |  | // This specialization is for when both `T` and `E` are trivially-destructible,  | 
2118  |  | // so the destructor of the `expected` can be trivial.  | 
2119  |  | template <class T, class E>  | 
2120  |  | struct expected_storage_base<T, E, true, true> { | 
2121  |  |   constexpr expected_storage_base() : m_val(T{}), m_has_val(true) {} | 
2122  |  |   constexpr expected_storage_base(no_init_t) : m_no_init(), m_has_val(false) {} | 
2123  |  |  | 
2124  |  |   template <class... Args,  | 
2125  |  |             detail::enable_if_t<std::is_constructible<T, Args &&...>::value> * =  | 
2126  |  |                 nullptr>  | 
2127  |  |   constexpr expected_storage_base(in_place_t, Args &&...args)  | 
2128  | 0  |       : m_val(std::forward<Args>(args)...), m_has_val(true) {} | 
2129  |  |  | 
2130  |  |   template <class U, class... Args,  | 
2131  |  |             detail::enable_if_t<std::is_constructible<  | 
2132  |  |                 T, std::initializer_list<U> &, Args &&...>::value> * = nullptr>  | 
2133  |  |   constexpr expected_storage_base(in_place_t, std::initializer_list<U> il,  | 
2134  |  |                                   Args &&...args)  | 
2135  |  |       : m_val(il, std::forward<Args>(args)...), m_has_val(true) {} | 
2136  |  |   template <class... Args,  | 
2137  |  |             detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * =  | 
2138  |  |                 nullptr>  | 
2139  |  |   constexpr explicit expected_storage_base(unexpect_t, Args &&...args)  | 
2140  | 0  |       : m_unexpect(std::forward<Args>(args)...), m_has_val(false) {} | 
2141  |  |  | 
2142  |  |   template <class U, class... Args,  | 
2143  |  |             detail::enable_if_t<std::is_constructible<  | 
2144  |  |                 E, std::initializer_list<U> &, Args &&...>::value> * = nullptr>  | 
2145  |  |   constexpr explicit expected_storage_base(unexpect_t,  | 
2146  |  |                                            std::initializer_list<U> il,  | 
2147  |  |                                            Args &&...args)  | 
2148  |  |       : m_unexpect(il, std::forward<Args>(args)...), m_has_val(false) {} | 
2149  |  |  | 
2150  |  |   ~expected_storage_base() = default;  | 
2151  |  |   union { | 
2152  |  |     T m_val;  | 
2153  |  |     unexpected<E> m_unexpect;  | 
2154  |  |     char m_no_init;  | 
2155  |  |   };  | 
2156  |  |   bool m_has_val;  | 
2157  |  | };  | 
2158  |  |  | 
2159  |  | // T is trivial, E is not.  | 
2160  |  | template <class T, class E>  | 
2161  |  | struct expected_storage_base<T, E, true, false> { | 
2162  |  |   constexpr expected_storage_base() : m_val(T{}), m_has_val(true) {} | 
2163  |  |   TL_EXPECTED_MSVC2015_CONSTEXPR expected_storage_base(no_init_t)  | 
2164  |  |       : m_no_init(), m_has_val(false) {} | 
2165  |  |  | 
2166  |  |   template <class... Args,  | 
2167  |  |             detail::enable_if_t<std::is_constructible<T, Args &&...>::value> * =  | 
2168  |  |                 nullptr>  | 
2169  |  |   constexpr expected_storage_base(in_place_t, Args &&...args)  | 
2170  |  |       : m_val(std::forward<Args>(args)...), m_has_val(true) {} | 
2171  |  |  | 
2172  |  |   template <class U, class... Args,  | 
2173  |  |             detail::enable_if_t<std::is_constructible<  | 
2174  |  |                 T, std::initializer_list<U> &, Args &&...>::value> * = nullptr>  | 
2175  |  |   constexpr expected_storage_base(in_place_t, std::initializer_list<U> il,  | 
2176  |  |                                   Args &&...args)  | 
2177  |  |       : m_val(il, std::forward<Args>(args)...), m_has_val(true) {} | 
2178  |  |   template <class... Args,  | 
2179  |  |             detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * =  | 
2180  |  |                 nullptr>  | 
2181  |  |   constexpr explicit expected_storage_base(unexpect_t, Args &&...args)  | 
2182  |  |       : m_unexpect(std::forward<Args>(args)...), m_has_val(false) {} | 
2183  |  |  | 
2184  |  |   template <class U, class... Args,  | 
2185  |  |             detail::enable_if_t<std::is_constructible<  | 
2186  |  |                 E, std::initializer_list<U> &, Args &&...>::value> * = nullptr>  | 
2187  |  |   constexpr explicit expected_storage_base(unexpect_t,  | 
2188  |  |                                            std::initializer_list<U> il,  | 
2189  |  |                                            Args &&...args)  | 
2190  |  |       : m_unexpect(il, std::forward<Args>(args)...), m_has_val(false) {} | 
2191  |  |  | 
2192  |  |   ~expected_storage_base() { | 
2193  |  |     if (!m_has_val) { | 
2194  |  |       m_unexpect.~unexpected<E>();  | 
2195  |  |     }  | 
2196  |  |   }  | 
2197  |  |  | 
2198  |  |   union { | 
2199  |  |     T m_val;  | 
2200  |  |     unexpected<E> m_unexpect;  | 
2201  |  |     char m_no_init;  | 
2202  |  |   };  | 
2203  |  |   bool m_has_val;  | 
2204  |  | };  | 
2205  |  |  | 
2206  |  | // E is trivial, T is not.  | 
2207  |  | template <class T, class E>  | 
2208  |  | struct expected_storage_base<T, E, false, true> { | 
2209  | 0  |   constexpr expected_storage_base() : m_val(T{}), m_has_val(true) {} | 
2210  |  |   constexpr expected_storage_base(no_init_t) : m_no_init(), m_has_val(false) {} | 
2211  |  |  | 
2212  |  |   template <class... Args,  | 
2213  |  |             detail::enable_if_t<std::is_constructible<T, Args &&...>::value> * =  | 
2214  |  |                 nullptr>  | 
2215  |  |   constexpr expected_storage_base(in_place_t, Args &&...args)  | 
2216  | 0  |       : m_val(std::forward<Args>(args)...), m_has_val(true) {}Unexecuted instantiation: _ZN2tl6detail21expected_storage_baseIN3ada16url_pattern_initENS2_6errorsELb0ELb1EEC2IJRS3_ETnPNSt3__19enable_ifIXsr3std16is_constructibleIS3_DpOT_EE5valueEvE4typeELPv0EEENS_10in_place_tESC_ Unexecuted instantiation: _ZN2tl6detail21expected_storage_baseINSt3__16vectorIN3ada16url_pattern_partENS2_9allocatorIS5_EEEENS4_6errorsELb0ELb1EEC2IJRS8_ETnPNS2_9enable_ifIXsr3std16is_constructibleIS8_DpOT_EE5valueEvE4typeELPv0EEENS_10in_place_tESG_ Unexecuted instantiation: _ZN2tl6detail21expected_storage_baseIN3ada21url_pattern_componentIN4node11url_pattern23URLPatternRegexProviderEEENS2_6errorsELb0ELb1EEC2IJS7_ETnPNSt3__19enable_ifIXsr3std16is_constructibleIS7_DpOT_EE5valueEvE4typeELPv0EEENS_10in_place_tESF_ Unexecuted instantiation: _ZN2tl6detail21expected_storage_baseIN3ada11url_patternIN4node11url_pattern23URLPatternRegexProviderEEENS2_6errorsELb0ELb1EEC2IJS7_ETnPNSt3__19enable_ifIXsr3std16is_constructibleIS7_DpOT_EE5valueEvE4typeELPv0EEENS_10in_place_tESF_ Unexecuted instantiation: _ZN2tl6detail21expected_storage_baseINSt3__18optionalIN3ada18url_pattern_resultEEENS4_6errorsELb0ELb1EEC2IJRKNS2_9nullopt_tEETnPNS2_9enable_ifIXsr3std16is_constructibleIS6_DpOT_EE5valueEvE4typeELPv0EEENS_10in_place_tESG_ Unexecuted instantiation: _ZN2tl6detail21expected_storage_baseINSt3__18optionalIN3ada18url_pattern_resultEEENS4_6errorsELb0ELb1EEC2IJS5_ETnPNS2_9enable_ifIXsr3std16is_constructibleIS6_DpOT_EE5valueEvE4typeELPv0EEENS_10in_place_tESD_  | 
2217  |  |  | 
2218  |  |   template <class U, class... Args,  | 
2219  |  |             detail::enable_if_t<std::is_constructible<  | 
2220  |  |                 T, std::initializer_list<U> &, Args &&...>::value> * = nullptr>  | 
2221  |  |   constexpr expected_storage_base(in_place_t, std::initializer_list<U> il,  | 
2222  |  |                                   Args &&...args)  | 
2223  |  |       : m_val(il, std::forward<Args>(args)...), m_has_val(true) {} | 
2224  |  |   template <class... Args,  | 
2225  |  |             detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * =  | 
2226  |  |                 nullptr>  | 
2227  |  |   constexpr explicit expected_storage_base(unexpect_t, Args &&...args)  | 
2228  | 0  |       : m_unexpect(std::forward<Args>(args)...), m_has_val(false) {}Unexecuted instantiation: _ZN2tl6detail21expected_storage_baseIN3ada16url_pattern_initENS2_6errorsELb0ELb1EEC2IJS4_ETnPNSt3__19enable_ifIXsr3std16is_constructibleIS4_DpOT_EE5valueEvE4typeELPv0EEENS_10unexpect_tESB_ Unexecuted instantiation: _ZN2tl6detail21expected_storage_baseIN3ada11url_patternIN4node11url_pattern23URLPatternRegexProviderEEENS2_6errorsELb0ELb1EEC2IJS8_ETnPNSt3__19enable_ifIXsr3std16is_constructibleIS8_DpOT_EE5valueEvE4typeELPv0EEENS_10unexpect_tESF_ Unexecuted instantiation: _ZN2tl6detail21expected_storage_baseINSt3__16vectorIN3ada16url_pattern_partENS2_9allocatorIS5_EEEENS4_6errorsELb0ELb1EEC2IJS9_ETnPNS2_9enable_ifIXsr3std16is_constructibleIS9_DpOT_EE5valueEvE4typeELPv0EEENS_10unexpect_tESF_ Unexecuted instantiation: _ZN2tl6detail21expected_storage_baseIN3ada21url_pattern_componentIN4node11url_pattern23URLPatternRegexProviderEEENS2_6errorsELb0ELb1EEC2IJS8_ETnPNSt3__19enable_ifIXsr3std16is_constructibleIS8_DpOT_EE5valueEvE4typeELPv0EEENS_10unexpect_tESF_ Unexecuted instantiation: _ZN2tl6detail21expected_storage_baseINSt3__18optionalIN3ada18url_pattern_resultEEENS4_6errorsELb0ELb1EEC2IJS7_ETnPNS2_9enable_ifIXsr3std16is_constructibleIS7_DpOT_EE5valueEvE4typeELPv0EEENS_10unexpect_tESD_  | 
2229  |  |  | 
2230  |  |   template <class U, class... Args,  | 
2231  |  |             detail::enable_if_t<std::is_constructible<  | 
2232  |  |                 E, std::initializer_list<U> &, Args &&...>::value> * = nullptr>  | 
2233  |  |   constexpr explicit expected_storage_base(unexpect_t,  | 
2234  |  |                                            std::initializer_list<U> il,  | 
2235  |  |                                            Args &&...args)  | 
2236  |  |       : m_unexpect(il, std::forward<Args>(args)...), m_has_val(false) {} | 
2237  |  |  | 
2238  | 0  |   ~expected_storage_base() { | 
2239  | 0  |     if (m_has_val) { | 
2240  | 0  |       m_val.~T();  | 
2241  | 0  |     }  | 
2242  | 0  |   } Unexecuted instantiation: tl::detail::expected_storage_base<ada::url_aggregator, ada::errors, false, true>::~expected_storage_base() Unexecuted instantiation: tl::detail::expected_storage_base<ada::url, ada::errors, false, true>::~expected_storage_base() Unexecuted instantiation: tl::detail::expected_storage_base<ada::url_pattern<node::url_pattern::URLPatternRegexProvider>, ada::errors, false, true>::~expected_storage_base() Unexecuted instantiation: tl::detail::expected_storage_base<std::__1::optional<ada::url_pattern_result>, ada::errors, false, true>::~expected_storage_base() Unexecuted instantiation: tl::detail::expected_storage_base<std::__1::vector<ada::url_pattern_helpers::token, std::__1::allocator<ada::url_pattern_helpers::token> >, ada::errors, false, true>::~expected_storage_base() Unexecuted instantiation: tl::detail::expected_storage_base<ada::url_pattern_init, ada::errors, false, true>::~expected_storage_base() Unexecuted instantiation: tl::detail::expected_storage_base<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, ada::errors, false, true>::~expected_storage_base() Unexecuted instantiation: tl::detail::expected_storage_base<std::__1::vector<ada::url_pattern_part, std::__1::allocator<ada::url_pattern_part> >, ada::errors, false, true>::~expected_storage_base() Unexecuted instantiation: tl::detail::expected_storage_base<ada::url_pattern_component<node::url_pattern::URLPatternRegexProvider>, ada::errors, false, true>::~expected_storage_base()  | 
2243  |  |   union { | 
2244  |  |     T m_val;  | 
2245  |  |     unexpected<E> m_unexpect;  | 
2246  |  |     char m_no_init;  | 
2247  |  |   };  | 
2248  |  |   bool m_has_val;  | 
2249  |  | };  | 
2250  |  |  | 
2251  |  | // `T` is `void`, `E` is trivially-destructible  | 
2252  |  | template <class E>  | 
2253  |  | struct expected_storage_base<void, E, false, true> { | 
2254  |  | #if __GNUC__ <= 5  | 
2255  |  | // no constexpr for GCC 4/5 bug  | 
2256  |  | #else  | 
2257  |  |   TL_EXPECTED_MSVC2015_CONSTEXPR  | 
2258  |  | #endif  | 
2259  |  |   expected_storage_base() : m_has_val(true) {} | 
2260  |  |  | 
2261  |  |   constexpr expected_storage_base(no_init_t) : m_val(), m_has_val(false) {} | 
2262  |  |  | 
2263  |  |   constexpr expected_storage_base(in_place_t) : m_has_val(true) {} | 
2264  |  |  | 
2265  |  |   template <class... Args,  | 
2266  |  |             detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * =  | 
2267  |  |                 nullptr>  | 
2268  |  |   constexpr explicit expected_storage_base(unexpect_t, Args &&...args)  | 
2269  |  |       : m_unexpect(std::forward<Args>(args)...), m_has_val(false) {} | 
2270  |  |  | 
2271  |  |   template <class U, class... Args,  | 
2272  |  |             detail::enable_if_t<std::is_constructible<  | 
2273  |  |                 E, std::initializer_list<U> &, Args &&...>::value> * = nullptr>  | 
2274  |  |   constexpr explicit expected_storage_base(unexpect_t,  | 
2275  |  |                                            std::initializer_list<U> il,  | 
2276  |  |                                            Args &&...args)  | 
2277  |  |       : m_unexpect(il, std::forward<Args>(args)...), m_has_val(false) {} | 
2278  |  |  | 
2279  |  |   ~expected_storage_base() = default;  | 
2280  |  |   struct dummy {}; | 
2281  |  |   union { | 
2282  |  |     unexpected<E> m_unexpect;  | 
2283  |  |     dummy m_val;  | 
2284  |  |   };  | 
2285  |  |   bool m_has_val;  | 
2286  |  | };  | 
2287  |  |  | 
2288  |  | // `T` is `void`, `E` is not trivially-destructible  | 
2289  |  | template <class E>  | 
2290  |  | struct expected_storage_base<void, E, false, false> { | 
2291  |  |   constexpr expected_storage_base() : m_dummy(), m_has_val(true) {} | 
2292  |  |   constexpr expected_storage_base(no_init_t) : m_dummy(), m_has_val(false) {} | 
2293  |  |  | 
2294  |  |   constexpr expected_storage_base(in_place_t) : m_dummy(), m_has_val(true) {} | 
2295  |  |  | 
2296  |  |   template <class... Args,  | 
2297  |  |             detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * =  | 
2298  |  |                 nullptr>  | 
2299  |  |   constexpr explicit expected_storage_base(unexpect_t, Args &&...args)  | 
2300  |  |       : m_unexpect(std::forward<Args>(args)...), m_has_val(false) {} | 
2301  |  |  | 
2302  |  |   template <class U, class... Args,  | 
2303  |  |             detail::enable_if_t<std::is_constructible<  | 
2304  |  |                 E, std::initializer_list<U> &, Args &&...>::value> * = nullptr>  | 
2305  |  |   constexpr explicit expected_storage_base(unexpect_t,  | 
2306  |  |                                            std::initializer_list<U> il,  | 
2307  |  |                                            Args &&...args)  | 
2308  |  |       : m_unexpect(il, std::forward<Args>(args)...), m_has_val(false) {} | 
2309  |  |  | 
2310  |  |   ~expected_storage_base() { | 
2311  |  |     if (!m_has_val) { | 
2312  |  |       m_unexpect.~unexpected<E>();  | 
2313  |  |     }  | 
2314  |  |   }  | 
2315  |  |  | 
2316  |  |   union { | 
2317  |  |     unexpected<E> m_unexpect;  | 
2318  |  |     char m_dummy;  | 
2319  |  |   };  | 
2320  |  |   bool m_has_val;  | 
2321  |  | };  | 
2322  |  |  | 
2323  |  | // This base class provides some handy member functions which can be used in  | 
2324  |  | // further derived classes  | 
2325  |  | template <class T, class E>  | 
2326  |  | struct expected_operations_base : expected_storage_base<T, E> { | 
2327  |  |   using expected_storage_base<T, E>::expected_storage_base;  | 
2328  |  |  | 
2329  |  |   template <class... Args>  | 
2330  | 0  |   void construct(Args &&...args) noexcept { | 
2331  | 0  |     new (std::addressof(this->m_val)) T(std::forward<Args>(args)...);  | 
2332  | 0  |     this->m_has_val = true;  | 
2333  | 0  |   }  | 
2334  |  |  | 
2335  |  |   template <class Rhs>  | 
2336  |  |   void construct_with(Rhs &&rhs) noexcept { | 
2337  |  |     new (std::addressof(this->m_val)) T(std::forward<Rhs>(rhs).get());  | 
2338  |  |     this->m_has_val = true;  | 
2339  |  |   }  | 
2340  |  |  | 
2341  |  |   template <class... Args>  | 
2342  | 0  |   void construct_error(Args &&...args) noexcept { | 
2343  | 0  |     new (std::addressof(this->m_unexpect))  | 
2344  | 0  |         unexpected<E>(std::forward<Args>(args)...);  | 
2345  | 0  |     this->m_has_val = false;  | 
2346  | 0  |   }  | 
2347  |  |  | 
2348  |  | #ifdef TL_EXPECTED_EXCEPTIONS_ENABLED  | 
2349  |  |  | 
2350  |  |   // These assign overloads ensure that the most efficient assignment  | 
2351  |  |   // implementation is used while maintaining the strong exception guarantee.  | 
2352  |  |   // The problematic case is where rhs has a value, but *this does not.  | 
2353  |  |   //  | 
2354  |  |   // This overload handles the case where we can just copy-construct `T`  | 
2355  |  |   // directly into place without throwing.  | 
2356  |  |   template <class U = T,  | 
2357  |  |             detail::enable_if_t<std::is_nothrow_copy_constructible<U>::value>  | 
2358  |  |                 * = nullptr>  | 
2359  |  |   void assign(const expected_operations_base &rhs) noexcept { | 
2360  |  |     if (!this->m_has_val && rhs.m_has_val) { | 
2361  |  |       geterr().~unexpected<E>();  | 
2362  |  |       construct(rhs.get());  | 
2363  |  |     } else { | 
2364  |  |       assign_common(rhs);  | 
2365  |  |     }  | 
2366  |  |   }  | 
2367  |  |  | 
2368  |  |   // This overload handles the case where we can attempt to create a copy of  | 
2369  |  |   // `T`, then no-throw move it into place if the copy was successful.  | 
2370  |  |   template <class U = T,  | 
2371  |  |             detail::enable_if_t<!std::is_nothrow_copy_constructible<U>::value &&  | 
2372  |  |                                 std::is_nothrow_move_constructible<U>::value>  | 
2373  |  |                 * = nullptr>  | 
2374  |  |   void assign(const expected_operations_base &rhs) noexcept { | 
2375  |  |     if (!this->m_has_val && rhs.m_has_val) { | 
2376  |  |       T tmp = rhs.get();  | 
2377  |  |       geterr().~unexpected<E>();  | 
2378  |  |       construct(std::move(tmp));  | 
2379  |  |     } else { | 
2380  |  |       assign_common(rhs);  | 
2381  |  |     }  | 
2382  |  |   }  | 
2383  |  |  | 
2384  |  |   // This overload is the worst-case, where we have to move-construct the  | 
2385  |  |   // unexpected value into temporary storage, then try to copy the T into place.  | 
2386  |  |   // If the construction succeeds, then everything is fine, but if it throws,  | 
2387  |  |   // then we move the old unexpected value back into place before rethrowing the  | 
2388  |  |   // exception.  | 
2389  |  |   template <class U = T,  | 
2390  |  |             detail::enable_if_t<!std::is_nothrow_copy_constructible<U>::value &&  | 
2391  |  |                                 !std::is_nothrow_move_constructible<U>::value>  | 
2392  |  |                 * = nullptr>  | 
2393  |  |   void assign(const expected_operations_base &rhs) { | 
2394  |  |     if (!this->m_has_val && rhs.m_has_val) { | 
2395  |  |       auto tmp = std::move(geterr());  | 
2396  |  |       geterr().~unexpected<E>();  | 
2397  |  |  | 
2398  |  | #ifdef TL_EXPECTED_EXCEPTIONS_ENABLED  | 
2399  |  |       try { | 
2400  |  |         construct(rhs.get());  | 
2401  |  |       } catch (...) { | 
2402  |  |         geterr() = std::move(tmp);  | 
2403  |  |         throw;  | 
2404  |  |       }  | 
2405  |  | #else  | 
2406  |  |       construct(rhs.get());  | 
2407  |  | #endif  | 
2408  |  |     } else { | 
2409  |  |       assign_common(rhs);  | 
2410  |  |     }  | 
2411  |  |   }  | 
2412  |  |  | 
2413  |  |   // These overloads do the same as above, but for rvalues  | 
2414  |  |   template <class U = T,  | 
2415  |  |             detail::enable_if_t<std::is_nothrow_move_constructible<U>::value>  | 
2416  |  |                 * = nullptr>  | 
2417  |  |   void assign(expected_operations_base &&rhs) noexcept { | 
2418  |  |     if (!this->m_has_val && rhs.m_has_val) { | 
2419  |  |       geterr().~unexpected<E>();  | 
2420  |  |       construct(std::move(rhs).get());  | 
2421  |  |     } else { | 
2422  |  |       assign_common(std::move(rhs));  | 
2423  |  |     }  | 
2424  |  |   }  | 
2425  |  |  | 
2426  |  |   template <class U = T,  | 
2427  |  |             detail::enable_if_t<!std::is_nothrow_move_constructible<U>::value>  | 
2428  |  |                 * = nullptr>  | 
2429  |  |   void assign(expected_operations_base &&rhs) { | 
2430  |  |     if (!this->m_has_val && rhs.m_has_val) { | 
2431  |  |       auto tmp = std::move(geterr());  | 
2432  |  |       geterr().~unexpected<E>();  | 
2433  |  | #ifdef TL_EXPECTED_EXCEPTIONS_ENABLED  | 
2434  |  |       try { | 
2435  |  |         construct(std::move(rhs).get());  | 
2436  |  |       } catch (...) { | 
2437  |  |         geterr() = std::move(tmp);  | 
2438  |  |         throw;  | 
2439  |  |       }  | 
2440  |  | #else  | 
2441  |  |       construct(std::move(rhs).get());  | 
2442  |  | #endif  | 
2443  |  |     } else { | 
2444  |  |       assign_common(std::move(rhs));  | 
2445  |  |     }  | 
2446  |  |   }  | 
2447  |  |  | 
2448  |  | #else  | 
2449  |  |  | 
2450  |  |   // If exceptions are disabled then we can just copy-construct  | 
2451  |  |   void assign(const expected_operations_base &rhs) noexcept { | 
2452  |  |     if (!this->m_has_val && rhs.m_has_val) { | 
2453  |  |       geterr().~unexpected<E>();  | 
2454  |  |       construct(rhs.get());  | 
2455  |  |     } else { | 
2456  |  |       assign_common(rhs);  | 
2457  |  |     }  | 
2458  |  |   }  | 
2459  |  |  | 
2460  | 0  |   void assign(expected_operations_base &&rhs) noexcept { | 
2461  | 0  |     if (!this->m_has_val && rhs.m_has_val) { | 
2462  | 0  |       geterr().~unexpected<E>();  | 
2463  | 0  |       construct(std::move(rhs).get());  | 
2464  | 0  |     } else { | 
2465  | 0  |       assign_common(std::move(rhs));  | 
2466  | 0  |     }  | 
2467  | 0  |   }  | 
2468  |  |  | 
2469  |  | #endif  | 
2470  |  |  | 
2471  |  |   // The common part of move/copy assigning  | 
2472  |  |   template <class Rhs>  | 
2473  | 0  |   void assign_common(Rhs &&rhs) { | 
2474  | 0  |     if (this->m_has_val) { | 
2475  | 0  |       if (rhs.m_has_val) { | 
2476  | 0  |         get() = std::forward<Rhs>(rhs).get();  | 
2477  | 0  |       } else { | 
2478  | 0  |         destroy_val();  | 
2479  | 0  |         construct_error(std::forward<Rhs>(rhs).geterr());  | 
2480  | 0  |       }  | 
2481  | 0  |     } else { | 
2482  | 0  |       if (!rhs.m_has_val) { | 
2483  | 0  |         geterr() = std::forward<Rhs>(rhs).geterr();  | 
2484  | 0  |       }  | 
2485  | 0  |     }  | 
2486  | 0  |   }  | 
2487  |  |  | 
2488  |  |   bool has_value() const { return this->m_has_val; } | 
2489  |  |  | 
2490  | 0  |   TL_EXPECTED_11_CONSTEXPR T &get() & { return this->m_val; } | 
2491  |  |   constexpr const T &get() const & { return this->m_val; } | 
2492  | 0  |   TL_EXPECTED_11_CONSTEXPR T &&get() && { return std::move(this->m_val); } | 
2493  |  | #ifndef TL_EXPECTED_NO_CONSTRR  | 
2494  |  |   constexpr const T &&get() const && { return std::move(this->m_val); } | 
2495  |  | #endif  | 
2496  |  |  | 
2497  | 0  |   TL_EXPECTED_11_CONSTEXPR unexpected<E> &geterr() & { | 
2498  | 0  |     return this->m_unexpect;  | 
2499  | 0  |   }  | 
2500  |  |   constexpr const unexpected<E> &geterr() const & { return this->m_unexpect; } | 
2501  | 0  |   TL_EXPECTED_11_CONSTEXPR unexpected<E> &&geterr() && { | 
2502  | 0  |     return std::move(this->m_unexpect);  | 
2503  | 0  |   }  | 
2504  |  | #ifndef TL_EXPECTED_NO_CONSTRR  | 
2505  |  |   constexpr const unexpected<E> &&geterr() const && { | 
2506  |  |     return std::move(this->m_unexpect);  | 
2507  |  |   }  | 
2508  |  | #endif  | 
2509  |  |  | 
2510  | 0  |   TL_EXPECTED_11_CONSTEXPR void destroy_val() { get().~T(); } | 
2511  |  | };  | 
2512  |  |  | 
2513  |  | // This base class provides some handy member functions which can be used in  | 
2514  |  | // further derived classes  | 
2515  |  | template <class E>  | 
2516  |  | struct expected_operations_base<void, E> : expected_storage_base<void, E> { | 
2517  |  |   using expected_storage_base<void, E>::expected_storage_base;  | 
2518  |  |  | 
2519  |  |   template <class... Args>  | 
2520  |  |   void construct() noexcept { | 
2521  |  |     this->m_has_val = true;  | 
2522  |  |   }  | 
2523  |  |  | 
2524  |  |   // This function doesn't use its argument, but needs it so that code in  | 
2525  |  |   // levels above this can work independently of whether T is void  | 
2526  |  |   template <class Rhs>  | 
2527  |  |   void construct_with(Rhs &&) noexcept { | 
2528  |  |     this->m_has_val = true;  | 
2529  |  |   }  | 
2530  |  |  | 
2531  |  |   template <class... Args>  | 
2532  |  |   void construct_error(Args &&...args) noexcept { | 
2533  |  |     new (std::addressof(this->m_unexpect))  | 
2534  |  |         unexpected<E>(std::forward<Args>(args)...);  | 
2535  |  |     this->m_has_val = false;  | 
2536  |  |   }  | 
2537  |  |  | 
2538  |  |   template <class Rhs>  | 
2539  |  |   void assign(Rhs &&rhs) noexcept { | 
2540  |  |     if (!this->m_has_val) { | 
2541  |  |       if (rhs.m_has_val) { | 
2542  |  |         geterr().~unexpected<E>();  | 
2543  |  |         construct();  | 
2544  |  |       } else { | 
2545  |  |         geterr() = std::forward<Rhs>(rhs).geterr();  | 
2546  |  |       }  | 
2547  |  |     } else { | 
2548  |  |       if (!rhs.m_has_val) { | 
2549  |  |         construct_error(std::forward<Rhs>(rhs).geterr());  | 
2550  |  |       }  | 
2551  |  |     }  | 
2552  |  |   }  | 
2553  |  |  | 
2554  |  |   bool has_value() const { return this->m_has_val; } | 
2555  |  |  | 
2556  |  |   TL_EXPECTED_11_CONSTEXPR unexpected<E> &geterr() & { | 
2557  |  |     return this->m_unexpect;  | 
2558  |  |   }  | 
2559  |  |   constexpr const unexpected<E> &geterr() const & { return this->m_unexpect; } | 
2560  |  |   TL_EXPECTED_11_CONSTEXPR unexpected<E> &&geterr() && { | 
2561  |  |     return std::move(this->m_unexpect);  | 
2562  |  |   }  | 
2563  |  | #ifndef TL_EXPECTED_NO_CONSTRR  | 
2564  |  |   constexpr const unexpected<E> &&geterr() const && { | 
2565  |  |     return std::move(this->m_unexpect);  | 
2566  |  |   }  | 
2567  |  | #endif  | 
2568  |  |  | 
2569  |  |   TL_EXPECTED_11_CONSTEXPR void destroy_val() { | 
2570  |  |     // no-op  | 
2571  |  |   }  | 
2572  |  | };  | 
2573  |  |  | 
2574  |  | // This class manages conditionally having a trivial copy constructor  | 
2575  |  | // This specialization is for when T and E are trivially copy constructible  | 
2576  |  | template <class T, class E,  | 
2577  |  |           bool = is_void_or<T, TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(  | 
2578  |  |                                    T)>::value &&  | 
2579  |  |                  TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(E)::value>  | 
2580  |  | struct expected_copy_base : expected_operations_base<T, E> { | 
2581  |  |   using expected_operations_base<T, E>::expected_operations_base;  | 
2582  |  | };  | 
2583  |  |  | 
2584  |  | // This specialization is for when T or E are not trivially copy constructible  | 
2585  |  | template <class T, class E>  | 
2586  |  | struct expected_copy_base<T, E, false> : expected_operations_base<T, E> { | 
2587  |  |   using expected_operations_base<T, E>::expected_operations_base;  | 
2588  |  |  | 
2589  | 0  |   expected_copy_base() = default;  | 
2590  |  |   expected_copy_base(const expected_copy_base &rhs)  | 
2591  |  |       : expected_operations_base<T, E>(no_init) { | 
2592  |  |     if (rhs.has_value()) { | 
2593  |  |       this->construct_with(rhs);  | 
2594  |  |     } else { | 
2595  |  |       this->construct_error(rhs.geterr());  | 
2596  |  |     }  | 
2597  |  |   }  | 
2598  |  |  | 
2599  |  |   expected_copy_base(expected_copy_base &&rhs) = default;  | 
2600  |  |   expected_copy_base &operator=(const expected_copy_base &rhs) = default;  | 
2601  |  |   expected_copy_base &operator=(expected_copy_base &&rhs) = default;  | 
2602  |  | };  | 
2603  |  |  | 
2604  |  | // This class manages conditionally having a trivial move constructor  | 
2605  |  | // Unfortunately there's no way to achieve this in GCC < 5 AFAIK, since it  | 
2606  |  | // doesn't implement an analogue to std::is_trivially_move_constructible. We  | 
2607  |  | // have to make do with a non-trivial move constructor even if T is trivially  | 
2608  |  | // move constructible  | 
2609  |  | #ifndef TL_EXPECTED_GCC49  | 
2610  |  | template <class T, class E,  | 
2611  |  |           bool =  | 
2612  |  |               is_void_or<T, std::is_trivially_move_constructible<T>>::value &&  | 
2613  |  |               std::is_trivially_move_constructible<E>::value>  | 
2614  |  | struct expected_move_base : expected_copy_base<T, E> { | 
2615  |  |   using expected_copy_base<T, E>::expected_copy_base;  | 
2616  |  | };  | 
2617  |  | #else  | 
2618  |  | template <class T, class E, bool = false>  | 
2619  |  | struct expected_move_base;  | 
2620  |  | #endif  | 
2621  |  | template <class T, class E>  | 
2622  |  | struct expected_move_base<T, E, false> : expected_copy_base<T, E> { | 
2623  |  |   using expected_copy_base<T, E>::expected_copy_base;  | 
2624  |  |  | 
2625  | 0  |   expected_move_base() = default;  | 
2626  |  |   expected_move_base(const expected_move_base &rhs) = default;  | 
2627  |  |  | 
2628  |  |   expected_move_base(expected_move_base &&rhs) noexcept(  | 
2629  |  |       std::is_nothrow_move_constructible<T>::value)  | 
2630  |  |       : expected_copy_base<T, E>(no_init) { | 
2631  |  |     if (rhs.has_value()) { | 
2632  |  |       this->construct_with(std::move(rhs));  | 
2633  |  |     } else { | 
2634  |  |       this->construct_error(std::move(rhs.geterr()));  | 
2635  |  |     }  | 
2636  |  |   }  | 
2637  |  |   expected_move_base &operator=(const expected_move_base &rhs) = default;  | 
2638  |  |   expected_move_base &operator=(expected_move_base &&rhs) = default;  | 
2639  |  | };  | 
2640  |  |  | 
2641  |  | // This class manages conditionally having a trivial copy assignment operator  | 
2642  |  | template <  | 
2643  |  |     class T, class E,  | 
2644  |  |     bool =  | 
2645  |  |         is_void_or<  | 
2646  |  |             T, conjunction<TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(T),  | 
2647  |  |                            TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T),  | 
2648  |  |                            TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(T)>>::value &&  | 
2649  |  |         TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(E)::value &&  | 
2650  |  |         TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(E)::value &&  | 
2651  |  |         TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(E)::value>  | 
2652  |  | struct expected_copy_assign_base : expected_move_base<T, E> { | 
2653  |  |   using expected_move_base<T, E>::expected_move_base;  | 
2654  |  | };  | 
2655  |  |  | 
2656  |  | template <class T, class E>  | 
2657  |  | struct expected_copy_assign_base<T, E, false> : expected_move_base<T, E> { | 
2658  |  |   using expected_move_base<T, E>::expected_move_base;  | 
2659  |  |  | 
2660  | 0  |   expected_copy_assign_base() = default;  | 
2661  |  |   expected_copy_assign_base(const expected_copy_assign_base &rhs) = default;  | 
2662  |  |  | 
2663  |  |   expected_copy_assign_base(expected_copy_assign_base &&rhs) = default;  | 
2664  |  |   expected_copy_assign_base &operator=(const expected_copy_assign_base &rhs) { | 
2665  |  |     this->assign(rhs);  | 
2666  |  |     return *this;  | 
2667  |  |   }  | 
2668  |  |   expected_copy_assign_base &operator=(expected_copy_assign_base &&rhs) =  | 
2669  |  |       default;  | 
2670  |  | };  | 
2671  |  |  | 
2672  |  | // This class manages conditionally having a trivial move assignment operator  | 
2673  |  | // Unfortunately there's no way to achieve this in GCC < 5 AFAIK, since it  | 
2674  |  | // doesn't implement an analogue to std::is_trivially_move_assignable. We have  | 
2675  |  | // to make do with a non-trivial move assignment operator even if T is trivially  | 
2676  |  | // move assignable  | 
2677  |  | #ifndef TL_EXPECTED_GCC49  | 
2678  |  | template <  | 
2679  |  |     class T, class E,  | 
2680  |  |     bool = is_void_or<  | 
2681  |  |                T, conjunction<std::is_trivially_destructible<T>,  | 
2682  |  |                               std::is_trivially_move_constructible<T>,  | 
2683  |  |                               std::is_trivially_move_assignable<T>>>::value &&  | 
2684  |  |            std::is_trivially_destructible<E>::value &&  | 
2685  |  |            std::is_trivially_move_constructible<E>::value &&  | 
2686  |  |            std::is_trivially_move_assignable<E>::value>  | 
2687  |  | struct expected_move_assign_base : expected_copy_assign_base<T, E> { | 
2688  |  |   using expected_copy_assign_base<T, E>::expected_copy_assign_base;  | 
2689  |  | };  | 
2690  |  | #else  | 
2691  |  | template <class T, class E, bool = false>  | 
2692  |  | struct expected_move_assign_base;  | 
2693  |  | #endif  | 
2694  |  |  | 
2695  |  | template <class T, class E>  | 
2696  |  | struct expected_move_assign_base<T, E, false>  | 
2697  |  |     : expected_copy_assign_base<T, E> { | 
2698  |  |   using expected_copy_assign_base<T, E>::expected_copy_assign_base;  | 
2699  |  |  | 
2700  | 0  |   expected_move_assign_base() = default;  | 
2701  |  |   expected_move_assign_base(const expected_move_assign_base &rhs) = default;  | 
2702  |  |  | 
2703  |  |   expected_move_assign_base(expected_move_assign_base &&rhs) = default;  | 
2704  |  |  | 
2705  |  |   expected_move_assign_base &operator=(const expected_move_assign_base &rhs) =  | 
2706  |  |       default;  | 
2707  |  |  | 
2708  |  |   expected_move_assign_base &operator=(  | 
2709  |  |       expected_move_assign_base  | 
2710  |  |           &&rhs) noexcept(std::is_nothrow_move_constructible<T>::value &&  | 
2711  | 0  |                           std::is_nothrow_move_assignable<T>::value) { | 
2712  | 0  |     this->assign(std::move(rhs));  | 
2713  | 0  |     return *this;  | 
2714  | 0  |   }  | 
2715  |  | };  | 
2716  |  |  | 
2717  |  | // expected_delete_ctor_base will conditionally delete copy and move  | 
2718  |  | // constructors depending on whether T is copy/move constructible  | 
2719  |  | template <class T, class E,  | 
2720  |  |           bool EnableCopy = (is_copy_constructible_or_void<T>::value &&  | 
2721  |  |                              std::is_copy_constructible<E>::value),  | 
2722  |  |           bool EnableMove = (is_move_constructible_or_void<T>::value &&  | 
2723  |  |                              std::is_move_constructible<E>::value)>  | 
2724  |  | struct expected_delete_ctor_base { | 
2725  |  |   expected_delete_ctor_base() = default;  | 
2726  |  |   expected_delete_ctor_base(const expected_delete_ctor_base &) = default;  | 
2727  |  |   expected_delete_ctor_base(expected_delete_ctor_base &&) noexcept = default;  | 
2728  |  |   expected_delete_ctor_base &operator=(const expected_delete_ctor_base &) =  | 
2729  |  |       default;  | 
2730  |  |   expected_delete_ctor_base &operator=(expected_delete_ctor_base &&) noexcept =  | 
2731  |  |       default;  | 
2732  |  | };  | 
2733  |  |  | 
2734  |  | template <class T, class E>  | 
2735  |  | struct expected_delete_ctor_base<T, E, true, false> { | 
2736  |  |   expected_delete_ctor_base() = default;  | 
2737  |  |   expected_delete_ctor_base(const expected_delete_ctor_base &) = default;  | 
2738  |  |   expected_delete_ctor_base(expected_delete_ctor_base &&) noexcept = delete;  | 
2739  |  |   expected_delete_ctor_base &operator=(const expected_delete_ctor_base &) =  | 
2740  |  |       default;  | 
2741  |  |   expected_delete_ctor_base &operator=(expected_delete_ctor_base &&) noexcept =  | 
2742  |  |       default;  | 
2743  |  | };  | 
2744  |  |  | 
2745  |  | template <class T, class E>  | 
2746  |  | struct expected_delete_ctor_base<T, E, false, true> { | 
2747  |  |   expected_delete_ctor_base() = default;  | 
2748  |  |   expected_delete_ctor_base(const expected_delete_ctor_base &) = delete;  | 
2749  |  |   expected_delete_ctor_base(expected_delete_ctor_base &&) noexcept = default;  | 
2750  |  |   expected_delete_ctor_base &operator=(const expected_delete_ctor_base &) =  | 
2751  |  |       default;  | 
2752  |  |   expected_delete_ctor_base &operator=(expected_delete_ctor_base &&) noexcept =  | 
2753  |  |       default;  | 
2754  |  | };  | 
2755  |  |  | 
2756  |  | template <class T, class E>  | 
2757  |  | struct expected_delete_ctor_base<T, E, false, false> { | 
2758  |  |   expected_delete_ctor_base() = default;  | 
2759  |  |   expected_delete_ctor_base(const expected_delete_ctor_base &) = delete;  | 
2760  |  |   expected_delete_ctor_base(expected_delete_ctor_base &&) noexcept = delete;  | 
2761  |  |   expected_delete_ctor_base &operator=(const expected_delete_ctor_base &) =  | 
2762  |  |       default;  | 
2763  |  |   expected_delete_ctor_base &operator=(expected_delete_ctor_base &&) noexcept =  | 
2764  |  |       default;  | 
2765  |  | };  | 
2766  |  |  | 
2767  |  | // expected_delete_assign_base will conditionally delete copy and move  | 
2768  |  | // constructors depending on whether T and E are copy/move constructible +  | 
2769  |  | // assignable  | 
2770  |  | template <class T, class E,  | 
2771  |  |           bool EnableCopy = (is_copy_constructible_or_void<T>::value &&  | 
2772  |  |                              std::is_copy_constructible<E>::value &&  | 
2773  |  |                              is_copy_assignable_or_void<T>::value &&  | 
2774  |  |                              std::is_copy_assignable<E>::value),  | 
2775  |  |           bool EnableMove = (is_move_constructible_or_void<T>::value &&  | 
2776  |  |                              std::is_move_constructible<E>::value &&  | 
2777  |  |                              is_move_assignable_or_void<T>::value &&  | 
2778  |  |                              std::is_move_assignable<E>::value)>  | 
2779  |  | struct expected_delete_assign_base { | 
2780  |  |   expected_delete_assign_base() = default;  | 
2781  |  |   expected_delete_assign_base(const expected_delete_assign_base &) = default;  | 
2782  |  |   expected_delete_assign_base(expected_delete_assign_base &&) noexcept =  | 
2783  |  |       default;  | 
2784  |  |   expected_delete_assign_base &operator=(const expected_delete_assign_base &) =  | 
2785  |  |       default;  | 
2786  |  |   expected_delete_assign_base &operator=(  | 
2787  |  |       expected_delete_assign_base &&) noexcept = default;  | 
2788  |  | };  | 
2789  |  |  | 
2790  |  | template <class T, class E>  | 
2791  |  | struct expected_delete_assign_base<T, E, true, false> { | 
2792  |  |   expected_delete_assign_base() = default;  | 
2793  |  |   expected_delete_assign_base(const expected_delete_assign_base &) = default;  | 
2794  |  |   expected_delete_assign_base(expected_delete_assign_base &&) noexcept =  | 
2795  |  |       default;  | 
2796  |  |   expected_delete_assign_base &operator=(const expected_delete_assign_base &) =  | 
2797  |  |       default;  | 
2798  |  |   expected_delete_assign_base &operator=(  | 
2799  |  |       expected_delete_assign_base &&) noexcept = delete;  | 
2800  |  | };  | 
2801  |  |  | 
2802  |  | template <class T, class E>  | 
2803  |  | struct expected_delete_assign_base<T, E, false, true> { | 
2804  |  |   expected_delete_assign_base() = default;  | 
2805  |  |   expected_delete_assign_base(const expected_delete_assign_base &) = default;  | 
2806  |  |   expected_delete_assign_base(expected_delete_assign_base &&) noexcept =  | 
2807  |  |       default;  | 
2808  |  |   expected_delete_assign_base &operator=(const expected_delete_assign_base &) =  | 
2809  |  |       delete;  | 
2810  |  |   expected_delete_assign_base &operator=(  | 
2811  |  |       expected_delete_assign_base &&) noexcept = default;  | 
2812  |  | };  | 
2813  |  |  | 
2814  |  | template <class T, class E>  | 
2815  |  | struct expected_delete_assign_base<T, E, false, false> { | 
2816  |  |   expected_delete_assign_base() = default;  | 
2817  |  |   expected_delete_assign_base(const expected_delete_assign_base &) = default;  | 
2818  |  |   expected_delete_assign_base(expected_delete_assign_base &&) noexcept =  | 
2819  |  |       default;  | 
2820  |  |   expected_delete_assign_base &operator=(const expected_delete_assign_base &) =  | 
2821  |  |       delete;  | 
2822  |  |   expected_delete_assign_base &operator=(  | 
2823  |  |       expected_delete_assign_base &&) noexcept = delete;  | 
2824  |  | };  | 
2825  |  |  | 
2826  |  | // This is needed to be able to construct the expected_default_ctor_base which  | 
2827  |  | // follows, while still conditionally deleting the default constructor.  | 
2828  |  | struct default_constructor_tag { | 
2829  |  |   explicit constexpr default_constructor_tag() = default;  | 
2830  |  | };  | 
2831  |  |  | 
2832  |  | // expected_default_ctor_base will ensure that expected has a deleted default  | 
2833  |  | // consturctor if T is not default constructible.  | 
2834  |  | // This specialization is for when T is default constructible  | 
2835  |  | template <class T, class E,  | 
2836  |  |           bool Enable =  | 
2837  |  |               std::is_default_constructible<T>::value || std::is_void<T>::value>  | 
2838  |  | struct expected_default_ctor_base { | 
2839  |  |   constexpr expected_default_ctor_base() noexcept = default;  | 
2840  |  |   constexpr expected_default_ctor_base(  | 
2841  |  |       expected_default_ctor_base const &) noexcept = default;  | 
2842  |  |   constexpr expected_default_ctor_base(expected_default_ctor_base &&) noexcept =  | 
2843  |  |       default;  | 
2844  |  |   expected_default_ctor_base &operator=(  | 
2845  |  |       expected_default_ctor_base const &) noexcept = default;  | 
2846  |  |   expected_default_ctor_base &operator=(  | 
2847  |  |       expected_default_ctor_base &&) noexcept = default;  | 
2848  |  |  | 
2849  | 0  |   constexpr explicit expected_default_ctor_base(default_constructor_tag) {}Unexecuted instantiation: tl::detail::expected_default_ctor_base<ada::url_pattern_init, ada::errors, true>::expected_default_ctor_base(tl::detail::default_constructor_tag) Unexecuted instantiation: tl::detail::expected_default_ctor_base<ada::url_pattern<node::url_pattern::URLPatternRegexProvider>, ada::errors, true>::expected_default_ctor_base(tl::detail::default_constructor_tag) Unexecuted instantiation: tl::detail::expected_default_ctor_base<std::__1::vector<ada::url_pattern_part, std::__1::allocator<ada::url_pattern_part> >, ada::errors, true>::expected_default_ctor_base(tl::detail::default_constructor_tag) Unexecuted instantiation: tl::detail::expected_default_ctor_base<ada::url_pattern_component<node::url_pattern::URLPatternRegexProvider>, ada::errors, true>::expected_default_ctor_base(tl::detail::default_constructor_tag) Unexecuted instantiation: tl::detail::expected_default_ctor_base<std::__1::optional<ada::url_pattern_result>, ada::errors, true>::expected_default_ctor_base(tl::detail::default_constructor_tag) Unexecuted instantiation: tl::detail::expected_default_ctor_base<bool, ada::errors, true>::expected_default_ctor_base(tl::detail::default_constructor_tag)  | 
2850  |  | };  | 
2851  |  |  | 
2852  |  | // This specialization is for when T is not default constructible  | 
2853  |  | template <class T, class E>  | 
2854  |  | struct expected_default_ctor_base<T, E, false> { | 
2855  |  |   constexpr expected_default_ctor_base() noexcept = delete;  | 
2856  |  |   constexpr expected_default_ctor_base(  | 
2857  |  |       expected_default_ctor_base const &) noexcept = default;  | 
2858  |  |   constexpr expected_default_ctor_base(expected_default_ctor_base &&) noexcept =  | 
2859  |  |       default;  | 
2860  |  |   expected_default_ctor_base &operator=(  | 
2861  |  |       expected_default_ctor_base const &) noexcept = default;  | 
2862  |  |   expected_default_ctor_base &operator=(  | 
2863  |  |       expected_default_ctor_base &&) noexcept = default;  | 
2864  |  |  | 
2865  |  |   constexpr explicit expected_default_ctor_base(default_constructor_tag) {} | 
2866  |  | };  | 
2867  |  | }  // namespace detail  | 
2868  |  |  | 
2869  |  | template <class E>  | 
2870  |  | class bad_expected_access : public std::exception { | 
2871  |  |  public:  | 
2872  | 0  |   explicit bad_expected_access(E e) : m_val(std::move(e)) {} | 
2873  |  |  | 
2874  | 0  |   virtual const char *what() const noexcept override { | 
2875  | 0  |     return "Bad expected access";  | 
2876  | 0  |   }  | 
2877  |  |  | 
2878  |  |   const E &error() const & { return m_val; } | 
2879  |  |   E &error() & { return m_val; } | 
2880  |  |   const E &&error() const && { return std::move(m_val); } | 
2881  |  |   E &&error() && { return std::move(m_val); } | 
2882  |  |  | 
2883  |  |  private:  | 
2884  |  |   E m_val;  | 
2885  |  | };  | 
2886  |  |  | 
2887  |  | /// An `expected<T, E>` object is an object that contains the storage for  | 
2888  |  | /// another object and manages the lifetime of this contained object `T`.  | 
2889  |  | /// Alternatively it could contain the storage for another unexpected object  | 
2890  |  | /// `E`. The contained object may not be initialized after the expected object  | 
2891  |  | /// has been initialized, and may not be destroyed before the expected object  | 
2892  |  | /// has been destroyed. The initialization state of the contained object is  | 
2893  |  | /// tracked by the expected object.  | 
2894  |  | template <class T, class E>  | 
2895  |  | class expected : private detail::expected_move_assign_base<T, E>,  | 
2896  |  |                  private detail::expected_delete_ctor_base<T, E>,  | 
2897  |  |                  private detail::expected_delete_assign_base<T, E>,  | 
2898  |  |                  private detail::expected_default_ctor_base<T, E> { | 
2899  |  |   static_assert(!std::is_reference<T>::value, "T must not be a reference");  | 
2900  |  |   static_assert(!std::is_same<T, std::remove_cv<in_place_t>::type>::value,  | 
2901  |  |                 "T must not be in_place_t");  | 
2902  |  |   static_assert(!std::is_same<T, std::remove_cv<unexpect_t>::type>::value,  | 
2903  |  |                 "T must not be unexpect_t");  | 
2904  |  |   static_assert(  | 
2905  |  |       !std::is_same<T, typename std::remove_cv<unexpected<E>>::type>::value,  | 
2906  |  |       "T must not be unexpected<E>");  | 
2907  |  |   static_assert(!std::is_reference<E>::value, "E must not be a reference");  | 
2908  |  |  | 
2909  | 0  |   T *valptr() { return std::addressof(this->m_val); }Unexecuted instantiation: tl::expected<ada::url_pattern_init, ada::errors>::valptr() Unexecuted instantiation: tl::expected<ada::url_aggregator, ada::errors>::valptr() Unexecuted instantiation: tl::expected<ada::url, ada::errors>::valptr() Unexecuted instantiation: tl::expected<std::__1::optional<ada::url_pattern_result>, ada::errors>::valptr()  | 
2910  |  |   const T *valptr() const { return std::addressof(this->m_val); } | 
2911  |  |   unexpected<E> *errptr() { return std::addressof(this->m_unexpect); } | 
2912  |  |   const unexpected<E> *errptr() const { | 
2913  |  |     return std::addressof(this->m_unexpect);  | 
2914  |  |   }  | 
2915  |  |  | 
2916  |  |   template <class U = T,  | 
2917  |  |             detail::enable_if_t<!std::is_void<U>::value> * = nullptr>  | 
2918  | 0  |   TL_EXPECTED_11_CONSTEXPR U &val() { | 
2919  | 0  |     return this->m_val;  | 
2920  | 0  |   } Unexecuted instantiation: _ZN2tl8expectedIN3ada14url_aggregatorENS1_6errorsEE3valIS2_TnPNSt3__19enable_ifIXntsr3std7is_voidIT_EE5valueEvE4typeELPv0EEERS8_v Unexecuted instantiation: _ZN2tl8expectedINSt3__16vectorIN3ada19url_pattern_helpers5tokenENS1_9allocatorIS5_EEEENS3_6errorsEE3valIS8_TnPNS1_9enable_ifIXntsr3std7is_voidIT_EE5valueEvE4typeELPv0EEERSD_v Unexecuted instantiation: _ZN2tl8expectedIN3ada11url_patternIN4node11url_pattern23URLPatternRegexProviderEEENS1_6errorsEE3valIS6_TnPNSt3__19enable_ifIXntsr3std7is_voidIT_EE5valueEvE4typeELPv0EEERSC_v Unexecuted instantiation: _ZN2tl8expectedIbN3ada6errorsEE3valIbTnPNSt3__19enable_ifIXntsr3std7is_voidIT_EE5valueEvE4typeELPv0EEERS7_v Unexecuted instantiation: _ZN2tl8expectedIN3ada16url_pattern_initENS1_6errorsEE3valIS2_TnPNSt3__19enable_ifIXntsr3std7is_voidIT_EE5valueEvE4typeELPv0EEERS8_v Unexecuted instantiation: _ZN2tl8expectedINSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEN3ada6errorsEE3valIS7_TnPNS1_9enable_ifIXntsr3std7is_voidIT_EE5valueEvE4typeELPv0EEERSD_v Unexecuted instantiation: _ZN2tl8expectedINSt3__16vectorIN3ada16url_pattern_partENS1_9allocatorIS4_EEEENS3_6errorsEE3valIS7_TnPNS1_9enable_ifIXntsr3std7is_voidIT_EE5valueEvE4typeELPv0EEERSC_v Unexecuted instantiation: _ZN2tl8expectedIN3ada21url_pattern_componentIN4node11url_pattern23URLPatternRegexProviderEEENS1_6errorsEE3valIS6_TnPNSt3__19enable_ifIXntsr3std7is_voidIT_EE5valueEvE4typeELPv0EEERSC_v  | 
2921  | 0  |   TL_EXPECTED_11_CONSTEXPR unexpected<E> &err() { return this->m_unexpect; }Unexecuted instantiation: tl::expected<ada::url_pattern_init, ada::errors>::err() Unexecuted instantiation: tl::expected<std::__1::vector<ada::url_pattern_helpers::token, std::__1::allocator<ada::url_pattern_helpers::token> >, ada::errors>::err() Unexecuted instantiation: tl::expected<ada::url_aggregator, ada::errors>::err() Unexecuted instantiation: tl::expected<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, ada::errors>::err() Unexecuted instantiation: tl::expected<std::__1::vector<ada::url_pattern_part, std::__1::allocator<ada::url_pattern_part> >, ada::errors>::err() Unexecuted instantiation: tl::expected<ada::url_pattern_component<node::url_pattern::URLPatternRegexProvider>, ada::errors>::err()  | 
2922  |  |  | 
2923  |  |   template <class U = T,  | 
2924  |  |             detail::enable_if_t<!std::is_void<U>::value> * = nullptr>  | 
2925  |  |   constexpr const U &val() const { | 
2926  |  |     return this->m_val;  | 
2927  |  |   }  | 
2928  |  |   constexpr const unexpected<E> &err() const { return this->m_unexpect; } | 
2929  |  |  | 
2930  |  |   using impl_base = detail::expected_move_assign_base<T, E>;  | 
2931  |  |   using ctor_base = detail::expected_default_ctor_base<T, E>;  | 
2932  |  |  | 
2933  |  |  public:  | 
2934  |  |   typedef T value_type;  | 
2935  |  |   typedef E error_type;  | 
2936  |  |   typedef unexpected<E> unexpected_type;  | 
2937  |  |  | 
2938  |  | #if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \  | 
2939  |  |     !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55)  | 
2940  |  |   template <class F>  | 
2941  |  |   TL_EXPECTED_11_CONSTEXPR auto and_then(F &&f) & { | 
2942  |  |     return and_then_impl(*this, std::forward<F>(f));  | 
2943  |  |   }  | 
2944  |  |   template <class F>  | 
2945  |  |   TL_EXPECTED_11_CONSTEXPR auto and_then(F &&f) && { | 
2946  |  |     return and_then_impl(std::move(*this), std::forward<F>(f));  | 
2947  |  |   }  | 
2948  |  |   template <class F>  | 
2949  |  |   constexpr auto and_then(F &&f) const & { | 
2950  |  |     return and_then_impl(*this, std::forward<F>(f));  | 
2951  |  |   }  | 
2952  |  |  | 
2953  |  | #ifndef TL_EXPECTED_NO_CONSTRR  | 
2954  |  |   template <class F>  | 
2955  |  |   constexpr auto and_then(F &&f) const && { | 
2956  |  |     return and_then_impl(std::move(*this), std::forward<F>(f));  | 
2957  |  |   }  | 
2958  |  | #endif  | 
2959  |  |  | 
2960  |  | #else  | 
2961  |  |   template <class F>  | 
2962  |  |   TL_EXPECTED_11_CONSTEXPR auto and_then(F &&f) & -> decltype(and_then_impl(  | 
2963  |  |       std::declval<expected &>(), std::forward<F>(f))) { | 
2964  |  |     return and_then_impl(*this, std::forward<F>(f));  | 
2965  |  |   }  | 
2966  |  |   template <class F>  | 
2967  |  |   TL_EXPECTED_11_CONSTEXPR auto and_then(F &&f) && -> decltype(and_then_impl(  | 
2968  |  |       std::declval<expected &&>(), std::forward<F>(f))) { | 
2969  |  |     return and_then_impl(std::move(*this), std::forward<F>(f));  | 
2970  |  |   }  | 
2971  |  |   template <class F>  | 
2972  |  |   constexpr auto and_then(F &&f) const & -> decltype(and_then_impl(  | 
2973  |  |       std::declval<expected const &>(), std::forward<F>(f))) { | 
2974  |  |     return and_then_impl(*this, std::forward<F>(f));  | 
2975  |  |   }  | 
2976  |  |  | 
2977  |  | #ifndef TL_EXPECTED_NO_CONSTRR  | 
2978  |  |   template <class F>  | 
2979  |  |   constexpr auto and_then(F &&f) const && -> decltype(and_then_impl(  | 
2980  |  |       std::declval<expected const &&>(), std::forward<F>(f))) { | 
2981  |  |     return and_then_impl(std::move(*this), std::forward<F>(f));  | 
2982  |  |   }  | 
2983  |  | #endif  | 
2984  |  | #endif  | 
2985  |  |  | 
2986  |  | #if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \  | 
2987  |  |     !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55)  | 
2988  |  |   template <class F>  | 
2989  |  |   TL_EXPECTED_11_CONSTEXPR auto map(F &&f) & { | 
2990  |  |     return expected_map_impl(*this, std::forward<F>(f));  | 
2991  |  |   }  | 
2992  |  |   template <class F>  | 
2993  |  |   TL_EXPECTED_11_CONSTEXPR auto map(F &&f) && { | 
2994  |  |     return expected_map_impl(std::move(*this), std::forward<F>(f));  | 
2995  |  |   }  | 
2996  |  |   template <class F>  | 
2997  |  |   constexpr auto map(F &&f) const & { | 
2998  |  |     return expected_map_impl(*this, std::forward<F>(f));  | 
2999  |  |   }  | 
3000  |  |   template <class F>  | 
3001  |  |   constexpr auto map(F &&f) const && { | 
3002  |  |     return expected_map_impl(std::move(*this), std::forward<F>(f));  | 
3003  |  |   }  | 
3004  |  | #else  | 
3005  |  |   template <class F>  | 
3006  |  |   TL_EXPECTED_11_CONSTEXPR decltype(expected_map_impl(  | 
3007  |  |       std::declval<expected &>(), std::declval<F &&>()))  | 
3008  |  |   map(F &&f) & { | 
3009  |  |     return expected_map_impl(*this, std::forward<F>(f));  | 
3010  |  |   }  | 
3011  |  |   template <class F>  | 
3012  |  |   TL_EXPECTED_11_CONSTEXPR decltype(expected_map_impl(std::declval<expected>(),  | 
3013  |  |                                                       std::declval<F &&>()))  | 
3014  |  |   map(F &&f) && { | 
3015  |  |     return expected_map_impl(std::move(*this), std::forward<F>(f));  | 
3016  |  |   }  | 
3017  |  |   template <class F>  | 
3018  |  |   constexpr decltype(expected_map_impl(std::declval<const expected &>(),  | 
3019  |  |                                        std::declval<F &&>()))  | 
3020  |  |   map(F &&f) const & { | 
3021  |  |     return expected_map_impl(*this, std::forward<F>(f));  | 
3022  |  |   }  | 
3023  |  |  | 
3024  |  | #ifndef TL_EXPECTED_NO_CONSTRR  | 
3025  |  |   template <class F>  | 
3026  |  |   constexpr decltype(expected_map_impl(std::declval<const expected &&>(),  | 
3027  |  |                                        std::declval<F &&>()))  | 
3028  |  |   map(F &&f) const && { | 
3029  |  |     return expected_map_impl(std::move(*this), std::forward<F>(f));  | 
3030  |  |   }  | 
3031  |  | #endif  | 
3032  |  | #endif  | 
3033  |  |  | 
3034  |  | #if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \  | 
3035  |  |     !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55)  | 
3036  |  |   template <class F>  | 
3037  |  |   TL_EXPECTED_11_CONSTEXPR auto transform(F &&f) & { | 
3038  |  |     return expected_map_impl(*this, std::forward<F>(f));  | 
3039  |  |   }  | 
3040  |  |   template <class F>  | 
3041  |  |   TL_EXPECTED_11_CONSTEXPR auto transform(F &&f) && { | 
3042  |  |     return expected_map_impl(std::move(*this), std::forward<F>(f));  | 
3043  |  |   }  | 
3044  |  |   template <class F>  | 
3045  |  |   constexpr auto transform(F &&f) const & { | 
3046  |  |     return expected_map_impl(*this, std::forward<F>(f));  | 
3047  |  |   }  | 
3048  |  |   template <class F>  | 
3049  |  |   constexpr auto transform(F &&f) const && { | 
3050  |  |     return expected_map_impl(std::move(*this), std::forward<F>(f));  | 
3051  |  |   }  | 
3052  |  | #else  | 
3053  |  |   template <class F>  | 
3054  |  |   TL_EXPECTED_11_CONSTEXPR decltype(expected_map_impl(  | 
3055  |  |       std::declval<expected &>(), std::declval<F &&>()))  | 
3056  |  |   transform(F &&f) & { | 
3057  |  |     return expected_map_impl(*this, std::forward<F>(f));  | 
3058  |  |   }  | 
3059  |  |   template <class F>  | 
3060  |  |   TL_EXPECTED_11_CONSTEXPR decltype(expected_map_impl(std::declval<expected>(),  | 
3061  |  |                                                       std::declval<F &&>()))  | 
3062  |  |   transform(F &&f) && { | 
3063  |  |     return expected_map_impl(std::move(*this), std::forward<F>(f));  | 
3064  |  |   }  | 
3065  |  |   template <class F>  | 
3066  |  |   constexpr decltype(expected_map_impl(std::declval<const expected &>(),  | 
3067  |  |                                        std::declval<F &&>()))  | 
3068  |  |   transform(F &&f) const & { | 
3069  |  |     return expected_map_impl(*this, std::forward<F>(f));  | 
3070  |  |   }  | 
3071  |  |  | 
3072  |  | #ifndef TL_EXPECTED_NO_CONSTRR  | 
3073  |  |   template <class F>  | 
3074  |  |   constexpr decltype(expected_map_impl(std::declval<const expected &&>(),  | 
3075  |  |                                        std::declval<F &&>()))  | 
3076  |  |   transform(F &&f) const && { | 
3077  |  |     return expected_map_impl(std::move(*this), std::forward<F>(f));  | 
3078  |  |   }  | 
3079  |  | #endif  | 
3080  |  | #endif  | 
3081  |  |  | 
3082  |  | #if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \  | 
3083  |  |     !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55)  | 
3084  |  |   template <class F>  | 
3085  |  |   TL_EXPECTED_11_CONSTEXPR auto map_error(F &&f) & { | 
3086  |  |     return map_error_impl(*this, std::forward<F>(f));  | 
3087  |  |   }  | 
3088  |  |   template <class F>  | 
3089  |  |   TL_EXPECTED_11_CONSTEXPR auto map_error(F &&f) && { | 
3090  |  |     return map_error_impl(std::move(*this), std::forward<F>(f));  | 
3091  |  |   }  | 
3092  |  |   template <class F>  | 
3093  |  |   constexpr auto map_error(F &&f) const & { | 
3094  |  |     return map_error_impl(*this, std::forward<F>(f));  | 
3095  |  |   }  | 
3096  |  |   template <class F>  | 
3097  |  |   constexpr auto map_error(F &&f) const && { | 
3098  |  |     return map_error_impl(std::move(*this), std::forward<F>(f));  | 
3099  |  |   }  | 
3100  |  | #else  | 
3101  |  |   template <class F>  | 
3102  |  |   TL_EXPECTED_11_CONSTEXPR decltype(map_error_impl(std::declval<expected &>(),  | 
3103  |  |                                                    std::declval<F &&>()))  | 
3104  |  |   map_error(F &&f) & { | 
3105  |  |     return map_error_impl(*this, std::forward<F>(f));  | 
3106  |  |   }  | 
3107  |  |   template <class F>  | 
3108  |  |   TL_EXPECTED_11_CONSTEXPR decltype(map_error_impl(std::declval<expected &&>(),  | 
3109  |  |                                                    std::declval<F &&>()))  | 
3110  |  |   map_error(F &&f) && { | 
3111  |  |     return map_error_impl(std::move(*this), std::forward<F>(f));  | 
3112  |  |   }  | 
3113  |  |   template <class F>  | 
3114  |  |   constexpr decltype(map_error_impl(std::declval<const expected &>(),  | 
3115  |  |                                     std::declval<F &&>()))  | 
3116  |  |   map_error(F &&f) const & { | 
3117  |  |     return map_error_impl(*this, std::forward<F>(f));  | 
3118  |  |   }  | 
3119  |  |  | 
3120  |  | #ifndef TL_EXPECTED_NO_CONSTRR  | 
3121  |  |   template <class F>  | 
3122  |  |   constexpr decltype(map_error_impl(std::declval<const expected &&>(),  | 
3123  |  |                                     std::declval<F &&>()))  | 
3124  |  |   map_error(F &&f) const && { | 
3125  |  |     return map_error_impl(std::move(*this), std::forward<F>(f));  | 
3126  |  |   }  | 
3127  |  | #endif  | 
3128  |  | #endif  | 
3129  |  | #if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \  | 
3130  |  |     !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55)  | 
3131  |  |   template <class F>  | 
3132  |  |   TL_EXPECTED_11_CONSTEXPR auto transform_error(F &&f) & { | 
3133  |  |     return map_error_impl(*this, std::forward<F>(f));  | 
3134  |  |   }  | 
3135  |  |   template <class F>  | 
3136  |  |   TL_EXPECTED_11_CONSTEXPR auto transform_error(F &&f) && { | 
3137  |  |     return map_error_impl(std::move(*this), std::forward<F>(f));  | 
3138  |  |   }  | 
3139  |  |   template <class F>  | 
3140  |  |   constexpr auto transform_error(F &&f) const & { | 
3141  |  |     return map_error_impl(*this, std::forward<F>(f));  | 
3142  |  |   }  | 
3143  |  |   template <class F>  | 
3144  |  |   constexpr auto transform_error(F &&f) const && { | 
3145  |  |     return map_error_impl(std::move(*this), std::forward<F>(f));  | 
3146  |  |   }  | 
3147  |  | #else  | 
3148  |  |   template <class F>  | 
3149  |  |   TL_EXPECTED_11_CONSTEXPR decltype(map_error_impl(std::declval<expected &>(),  | 
3150  |  |                                                    std::declval<F &&>()))  | 
3151  |  |   transform_error(F &&f) & { | 
3152  |  |     return map_error_impl(*this, std::forward<F>(f));  | 
3153  |  |   }  | 
3154  |  |   template <class F>  | 
3155  |  |   TL_EXPECTED_11_CONSTEXPR decltype(map_error_impl(std::declval<expected &&>(),  | 
3156  |  |                                                    std::declval<F &&>()))  | 
3157  |  |   transform_error(F &&f) && { | 
3158  |  |     return map_error_impl(std::move(*this), std::forward<F>(f));  | 
3159  |  |   }  | 
3160  |  |   template <class F>  | 
3161  |  |   constexpr decltype(map_error_impl(std::declval<const expected &>(),  | 
3162  |  |                                     std::declval<F &&>()))  | 
3163  |  |   transform_error(F &&f) const & { | 
3164  |  |     return map_error_impl(*this, std::forward<F>(f));  | 
3165  |  |   }  | 
3166  |  |  | 
3167  |  | #ifndef TL_EXPECTED_NO_CONSTRR  | 
3168  |  |   template <class F>  | 
3169  |  |   constexpr decltype(map_error_impl(std::declval<const expected &&>(),  | 
3170  |  |                                     std::declval<F &&>()))  | 
3171  |  |   transform_error(F &&f) const && { | 
3172  |  |     return map_error_impl(std::move(*this), std::forward<F>(f));  | 
3173  |  |   }  | 
3174  |  | #endif  | 
3175  |  | #endif  | 
3176  |  |   template <class F>  | 
3177  |  |   expected TL_EXPECTED_11_CONSTEXPR or_else(F &&f) & { | 
3178  |  |     return or_else_impl(*this, std::forward<F>(f));  | 
3179  |  |   }  | 
3180  |  |  | 
3181  |  |   template <class F>  | 
3182  |  |   expected TL_EXPECTED_11_CONSTEXPR or_else(F &&f) && { | 
3183  |  |     return or_else_impl(std::move(*this), std::forward<F>(f));  | 
3184  |  |   }  | 
3185  |  |  | 
3186  |  |   template <class F>  | 
3187  |  |   expected constexpr or_else(F &&f) const & { | 
3188  |  |     return or_else_impl(*this, std::forward<F>(f));  | 
3189  |  |   }  | 
3190  |  |  | 
3191  |  | #ifndef TL_EXPECTED_NO_CONSTRR  | 
3192  |  |   template <class F>  | 
3193  |  |   expected constexpr or_else(F &&f) const && { | 
3194  |  |     return or_else_impl(std::move(*this), std::forward<F>(f));  | 
3195  |  |   }  | 
3196  |  | #endif  | 
3197  | 0  |   constexpr expected() = default;  | 
3198  |  |   constexpr expected(const expected &rhs) = default;  | 
3199  |  |   constexpr expected(expected &&rhs) = default;  | 
3200  |  |   expected &operator=(const expected &rhs) = default;  | 
3201  | 0  |   expected &operator=(expected &&rhs) = default;  | 
3202  |  |  | 
3203  |  |   template <class... Args,  | 
3204  |  |             detail::enable_if_t<std::is_constructible<T, Args &&...>::value> * =  | 
3205  |  |                 nullptr>  | 
3206  |  |   constexpr expected(in_place_t, Args &&...args)  | 
3207  | 0  |       : impl_base(in_place, std::forward<Args>(args)...),  | 
3208  | 0  |         ctor_base(detail::default_constructor_tag{}) {}Unexecuted instantiation: _ZN2tl8expectedIN3ada16url_pattern_initENS1_6errorsEEC2IJRS2_ETnPNSt3__19enable_ifIXsr3std16is_constructibleIS2_DpOT_EE5valueEvE4typeELPv0EEENS_10in_place_tESB_ Unexecuted instantiation: _ZN2tl8expectedINSt3__16vectorIN3ada16url_pattern_partENS1_9allocatorIS4_EEEENS3_6errorsEEC2IJRS7_ETnPNS1_9enable_ifIXsr3std16is_constructibleIS7_DpOT_EE5valueEvE4typeELPv0EEENS_10in_place_tESF_ Unexecuted instantiation: _ZN2tl8expectedIN3ada21url_pattern_componentIN4node11url_pattern23URLPatternRegexProviderEEENS1_6errorsEEC2IJS6_ETnPNSt3__19enable_ifIXsr3std16is_constructibleIS6_DpOT_EE5valueEvE4typeELPv0EEENS_10in_place_tESE_ Unexecuted instantiation: _ZN2tl8expectedIN3ada11url_patternIN4node11url_pattern23URLPatternRegexProviderEEENS1_6errorsEEC2IJS6_ETnPNSt3__19enable_ifIXsr3std16is_constructibleIS6_DpOT_EE5valueEvE4typeELPv0EEENS_10in_place_tESE_ Unexecuted instantiation: _ZN2tl8expectedINSt3__18optionalIN3ada18url_pattern_resultEEENS3_6errorsEEC2IJRKNS1_9nullopt_tEETnPNS1_9enable_ifIXsr3std16is_constructibleIS5_DpOT_EE5valueEvE4typeELPv0EEENS_10in_place_tESF_ Unexecuted instantiation: _ZN2tl8expectedINSt3__18optionalIN3ada18url_pattern_resultEEENS3_6errorsEEC2IJS4_ETnPNS1_9enable_ifIXsr3std16is_constructibleIS5_DpOT_EE5valueEvE4typeELPv0EEENS_10in_place_tESC_ Unexecuted instantiation: _ZN2tl8expectedIbN3ada6errorsEEC2IJbETnPNSt3__19enable_ifIXsr3std16is_constructibleIbDpOT_EE5valueEvE4typeELPv0EEENS_10in_place_tES9_  | 
3209  |  |  | 
3210  |  |   template <class U, class... Args,  | 
3211  |  |             detail::enable_if_t<std::is_constructible<  | 
3212  |  |                 T, std::initializer_list<U> &, Args &&...>::value> * = nullptr>  | 
3213  |  |   constexpr expected(in_place_t, std::initializer_list<U> il, Args &&...args)  | 
3214  |  |       : impl_base(in_place, il, std::forward<Args>(args)...),  | 
3215  |  |         ctor_base(detail::default_constructor_tag{}) {} | 
3216  |  |  | 
3217  |  |   template <class G = E,  | 
3218  |  |             detail::enable_if_t<std::is_constructible<E, const G &>::value> * =  | 
3219  |  |                 nullptr,  | 
3220  |  |             detail::enable_if_t<!std::is_convertible<const G &, E>::value> * =  | 
3221  |  |                 nullptr>  | 
3222  |  |   explicit constexpr expected(const unexpected<G> &e)  | 
3223  |  |       : impl_base(unexpect, e.value()),  | 
3224  |  |         ctor_base(detail::default_constructor_tag{}) {} | 
3225  |  |  | 
3226  |  |   template <  | 
3227  |  |       class G = E,  | 
3228  |  |       detail::enable_if_t<std::is_constructible<E, const G &>::value> * =  | 
3229  |  |           nullptr,  | 
3230  |  |       detail::enable_if_t<std::is_convertible<const G &, E>::value> * = nullptr>  | 
3231  |  |   constexpr expected(unexpected<G> const &e)  | 
3232  |  |       : impl_base(unexpect, e.value()),  | 
3233  |  |         ctor_base(detail::default_constructor_tag{}) {} | 
3234  |  |  | 
3235  |  |   template <  | 
3236  |  |       class G = E,  | 
3237  |  |       detail::enable_if_t<std::is_constructible<E, G &&>::value> * = nullptr,  | 
3238  |  |       detail::enable_if_t<!std::is_convertible<G &&, E>::value> * = nullptr>  | 
3239  |  |   explicit constexpr expected(unexpected<G> &&e) noexcept(  | 
3240  |  |       std::is_nothrow_constructible<E, G &&>::value)  | 
3241  |  |       : impl_base(unexpect, std::move(e.value())),  | 
3242  |  |         ctor_base(detail::default_constructor_tag{}) {} | 
3243  |  |  | 
3244  |  |   template <  | 
3245  |  |       class G = E,  | 
3246  |  |       detail::enable_if_t<std::is_constructible<E, G &&>::value> * = nullptr,  | 
3247  |  |       detail::enable_if_t<std::is_convertible<G &&, E>::value> * = nullptr>  | 
3248  |  |   constexpr expected(unexpected<G> &&e) noexcept(  | 
3249  |  |       std::is_nothrow_constructible<E, G &&>::value)  | 
3250  | 0  |       : impl_base(unexpect, std::move(e.value())),  | 
3251  | 0  |         ctor_base(detail::default_constructor_tag{}) {}Unexecuted instantiation: _ZN2tl8expectedIN3ada16url_pattern_initENS1_6errorsEEC2IS3_TnPNSt3__19enable_ifIXsr3std16is_constructibleIS3_OT_EE5valueEvE4typeELPv0ETnPNS7_IXsr3std14is_convertibleIS9_S3_EE5valueEvE4typeELSD_0EEEONS_10unexpectedIS8_EE Unexecuted instantiation: _ZN2tl8expectedIN3ada11url_patternIN4node11url_pattern23URLPatternRegexProviderEEENS1_6errorsEEC2IS7_TnPNSt3__19enable_ifIXsr3std16is_constructibleIS7_OT_EE5valueEvE4typeELPv0ETnPNSB_IXsr3std14is_convertibleISD_S7_EE5valueEvE4typeELSH_0EEEONS_10unexpectedISC_EE Unexecuted instantiation: _ZN2tl8expectedINSt3__16vectorIN3ada16url_pattern_partENS1_9allocatorIS4_EEEENS3_6errorsEEC2IS8_TnPNS1_9enable_ifIXsr3std16is_constructibleIS8_OT_EE5valueEvE4typeELPv0ETnPNSB_IXsr3std14is_convertibleISD_S8_EE5valueEvE4typeELSH_0EEEONS_10unexpectedISC_EE Unexecuted instantiation: _ZN2tl8expectedIN3ada21url_pattern_componentIN4node11url_pattern23URLPatternRegexProviderEEENS1_6errorsEEC2IS7_TnPNSt3__19enable_ifIXsr3std16is_constructibleIS7_OT_EE5valueEvE4typeELPv0ETnPNSB_IXsr3std14is_convertibleISD_S7_EE5valueEvE4typeELSH_0EEEONS_10unexpectedISC_EE Unexecuted instantiation: _ZN2tl8expectedINSt3__18optionalIN3ada18url_pattern_resultEEENS3_6errorsEEC2IS6_TnPNS1_9enable_ifIXsr3std16is_constructibleIS6_OT_EE5valueEvE4typeELPv0ETnPNS9_IXsr3std14is_convertibleISB_S6_EE5valueEvE4typeELSF_0EEEONS_10unexpectedISA_EE Unexecuted instantiation: _ZN2tl8expectedIbN3ada6errorsEEC2IS2_TnPNSt3__19enable_ifIXsr3std16is_constructibleIS2_OT_EE5valueEvE4typeELPv0ETnPNS6_IXsr3std14is_convertibleIS8_S2_EE5valueEvE4typeELSC_0EEEONS_10unexpectedIS7_EE  | 
3252  |  |  | 
3253  |  |   template <class... Args,  | 
3254  |  |             detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * =  | 
3255  |  |                 nullptr>  | 
3256  |  |   constexpr explicit expected(unexpect_t, Args &&...args)  | 
3257  |  |       : impl_base(unexpect, std::forward<Args>(args)...),  | 
3258  |  |         ctor_base(detail::default_constructor_tag{}) {} | 
3259  |  |  | 
3260  |  |   template <class U, class... Args,  | 
3261  |  |             detail::enable_if_t<std::is_constructible<  | 
3262  |  |                 E, std::initializer_list<U> &, Args &&...>::value> * = nullptr>  | 
3263  |  |   constexpr explicit expected(unexpect_t, std::initializer_list<U> il,  | 
3264  |  |                               Args &&...args)  | 
3265  |  |       : impl_base(unexpect, il, std::forward<Args>(args)...),  | 
3266  |  |         ctor_base(detail::default_constructor_tag{}) {} | 
3267  |  |  | 
3268  |  |   template <class U, class G,  | 
3269  |  |             detail::enable_if_t<!(std::is_convertible<U const &, T>::value &&  | 
3270  |  |                                   std::is_convertible<G const &, E>::value)> * =  | 
3271  |  |                 nullptr,  | 
3272  |  |             detail::expected_enable_from_other<T, E, U, G, const U &, const G &>  | 
3273  |  |                 * = nullptr>  | 
3274  |  |   explicit TL_EXPECTED_11_CONSTEXPR expected(const expected<U, G> &rhs)  | 
3275  |  |       : ctor_base(detail::default_constructor_tag{}) { | 
3276  |  |     if (rhs.has_value()) { | 
3277  |  |       this->construct(*rhs);  | 
3278  |  |     } else { | 
3279  |  |       this->construct_error(rhs.error());  | 
3280  |  |     }  | 
3281  |  |   }  | 
3282  |  |  | 
3283  |  |   template <class U, class G,  | 
3284  |  |             detail::enable_if_t<(std::is_convertible<U const &, T>::value &&  | 
3285  |  |                                  std::is_convertible<G const &, E>::value)> * =  | 
3286  |  |                 nullptr,  | 
3287  |  |             detail::expected_enable_from_other<T, E, U, G, const U &, const G &>  | 
3288  |  |                 * = nullptr>  | 
3289  |  |   TL_EXPECTED_11_CONSTEXPR expected(const expected<U, G> &rhs)  | 
3290  |  |       : ctor_base(detail::default_constructor_tag{}) { | 
3291  |  |     if (rhs.has_value()) { | 
3292  |  |       this->construct(*rhs);  | 
3293  |  |     } else { | 
3294  |  |       this->construct_error(rhs.error());  | 
3295  |  |     }  | 
3296  |  |   }  | 
3297  |  |  | 
3298  |  |   template <  | 
3299  |  |       class U, class G,  | 
3300  |  |       detail::enable_if_t<!(std::is_convertible<U &&, T>::value &&  | 
3301  |  |                             std::is_convertible<G &&, E>::value)> * = nullptr,  | 
3302  |  |       detail::expected_enable_from_other<T, E, U, G, U &&, G &&> * = nullptr>  | 
3303  |  |   explicit TL_EXPECTED_11_CONSTEXPR expected(expected<U, G> &&rhs)  | 
3304  |  |       : ctor_base(detail::default_constructor_tag{}) { | 
3305  |  |     if (rhs.has_value()) { | 
3306  |  |       this->construct(std::move(*rhs));  | 
3307  |  |     } else { | 
3308  |  |       this->construct_error(std::move(rhs.error()));  | 
3309  |  |     }  | 
3310  |  |   }  | 
3311  |  |  | 
3312  |  |   template <  | 
3313  |  |       class U, class G,  | 
3314  |  |       detail::enable_if_t<(std::is_convertible<U &&, T>::value &&  | 
3315  |  |                            std::is_convertible<G &&, E>::value)> * = nullptr,  | 
3316  |  |       detail::expected_enable_from_other<T, E, U, G, U &&, G &&> * = nullptr>  | 
3317  |  |   TL_EXPECTED_11_CONSTEXPR expected(expected<U, G> &&rhs)  | 
3318  |  |       : ctor_base(detail::default_constructor_tag{}) { | 
3319  |  |     if (rhs.has_value()) { | 
3320  |  |       this->construct(std::move(*rhs));  | 
3321  |  |     } else { | 
3322  |  |       this->construct_error(std::move(rhs.error()));  | 
3323  |  |     }  | 
3324  |  |   }  | 
3325  |  |  | 
3326  |  |   template <  | 
3327  |  |       class U = T,  | 
3328  |  |       detail::enable_if_t<!std::is_convertible<U &&, T>::value> * = nullptr,  | 
3329  |  |       detail::expected_enable_forward_value<T, E, U> * = nullptr>  | 
3330  |  |   explicit TL_EXPECTED_MSVC2015_CONSTEXPR expected(U &&v)  | 
3331  |  |       : expected(in_place, std::forward<U>(v)) {} | 
3332  |  |  | 
3333  |  |   template <  | 
3334  |  |       class U = T,  | 
3335  |  |       detail::enable_if_t<std::is_convertible<U &&, T>::value> * = nullptr,  | 
3336  |  |       detail::expected_enable_forward_value<T, E, U> * = nullptr>  | 
3337  |  |   TL_EXPECTED_MSVC2015_CONSTEXPR expected(U &&v)  | 
3338  | 0  |       : expected(in_place, std::forward<U>(v)) {}Unexecuted instantiation: _ZN2tl8expectedIN3ada16url_pattern_initENS1_6errorsEEC2IRS2_TnPNSt3__19enable_ifIXsr3std14is_convertibleIOT_S2_EE5valueEvE4typeELPv0ETnPNS8_IXaaaaaasr3std16is_constructibleIS2_SA_EE5valuentsr3std7is_sameINS7_5decayIS9_E4typeENS_10in_place_tEEE5valuentsr3std7is_sameIS4_SH_EE5valuentsr3std7is_sameINS_10unexpectedIS3_EESH_EE5valueEvE4typeELSE_0EEESA_ Unexecuted instantiation: _ZN2tl8expectedINSt3__16vectorIN3ada16url_pattern_partENS1_9allocatorIS4_EEEENS3_6errorsEEC2IRS7_TnPNS1_9enable_ifIXsr3std14is_convertibleIOT_S7_EE5valueEvE4typeELPv0ETnPNSC_IXaaaaaasr3std16is_constructibleIS7_SE_EE5valuentsr3std7is_sameINS1_5decayISD_E4typeENS_10in_place_tEEE5valuentsr3std7is_sameIS9_SL_EE5valuentsr3std7is_sameINS_10unexpectedIS8_EESL_EE5valueEvE4typeELSI_0EEESE_ Unexecuted instantiation: _ZN2tl8expectedIN3ada21url_pattern_componentIN4node11url_pattern23URLPatternRegexProviderEEENS1_6errorsEEC2IS6_TnPNSt3__19enable_ifIXsr3std14is_convertibleIOT_S6_EE5valueEvE4typeELPv0ETnPNSB_IXaaaaaasr3std16is_constructibleIS6_SD_EE5valuentsr3std7is_sameINSA_5decayISC_E4typeENS_10in_place_tEEE5valuentsr3std7is_sameIS8_SK_EE5valuentsr3std7is_sameINS_10unexpectedIS7_EESK_EE5valueEvE4typeELSH_0EEESD_ Unexecuted instantiation: _ZN2tl8expectedIN3ada11url_patternIN4node11url_pattern23URLPatternRegexProviderEEENS1_6errorsEEC2IS6_TnPNSt3__19enable_ifIXsr3std14is_convertibleIOT_S6_EE5valueEvE4typeELPv0ETnPNSB_IXaaaaaasr3std16is_constructibleIS6_SD_EE5valuentsr3std7is_sameINSA_5decayISC_E4typeENS_10in_place_tEEE5valuentsr3std7is_sameIS8_SK_EE5valuentsr3std7is_sameINS_10unexpectedIS7_EESK_EE5valueEvE4typeELSH_0EEESD_ Unexecuted instantiation: _ZN2tl8expectedINSt3__18optionalIN3ada18url_pattern_resultEEENS3_6errorsEEC2IRKNS1_9nullopt_tETnPNS1_9enable_ifIXsr3std14is_convertibleIOT_S5_EE5valueEvE4typeELPv0ETnPNSC_IXaaaaaasr3std16is_constructibleIS5_SE_EE5valuentsr3std7is_sameINS1_5decayISD_E4typeENS_10in_place_tEEE5valuentsr3std7is_sameIS7_SL_EE5valuentsr3std7is_sameINS_10unexpectedIS6_EESL_EE5valueEvE4typeELSI_0EEESE_ Unexecuted instantiation: _ZN2tl8expectedINSt3__18optionalIN3ada18url_pattern_resultEEENS3_6errorsEEC2IS4_TnPNS1_9enable_ifIXsr3std14is_convertibleIOT_S5_EE5valueEvE4typeELPv0ETnPNS9_IXaaaaaasr3std16is_constructibleIS5_SB_EE5valuentsr3std7is_sameINS1_5decayISA_E4typeENS_10in_place_tEEE5valuentsr3std7is_sameIS7_SI_EE5valuentsr3std7is_sameINS_10unexpectedIS6_EESI_EE5valueEvE4typeELSF_0EEESB_ Unexecuted instantiation: _ZN2tl8expectedIbN3ada6errorsEEC2IbTnPNSt3__19enable_ifIXsr3std14is_convertibleIOT_bEE5valueEvE4typeELPv0ETnPNS6_IXaaaaaasr3std16is_constructibleIbS8_EE5valuentsr3std7is_sameINS5_5decayIS7_E4typeENS_10in_place_tEEE5valuentsr3std7is_sameIS3_SF_EE5valuentsr3std7is_sameINS_10unexpectedIS2_EESF_EE5valueEvE4typeELSC_0EEES8_  | 
3339  |  |  | 
3340  |  |   template <  | 
3341  |  |       class U = T, class G = T,  | 
3342  |  |       detail::enable_if_t<std::is_nothrow_constructible<T, U &&>::value> * =  | 
3343  |  |           nullptr,  | 
3344  |  |       detail::enable_if_t<!std::is_void<G>::value> * = nullptr,  | 
3345  |  |       detail::enable_if_t<  | 
3346  |  |           (!std::is_same<expected<T, E>, detail::decay_t<U>>::value &&  | 
3347  |  |            !detail::conjunction<std::is_scalar<T>,  | 
3348  |  |                                 std::is_same<T, detail::decay_t<U>>>::value &&  | 
3349  |  |            std::is_constructible<T, U>::value &&  | 
3350  |  |            std::is_assignable<G &, U>::value &&  | 
3351  |  |            std::is_nothrow_move_constructible<E>::value)> * = nullptr>  | 
3352  |  |   expected &operator=(U &&v) { | 
3353  |  |     if (has_value()) { | 
3354  |  |       val() = std::forward<U>(v);  | 
3355  |  |     } else { | 
3356  |  |       err().~unexpected<E>();  | 
3357  |  |       ::new (valptr()) T(std::forward<U>(v));  | 
3358  |  |       this->m_has_val = true;  | 
3359  |  |     }  | 
3360  |  |  | 
3361  |  |     return *this;  | 
3362  |  |   }  | 
3363  |  |  | 
3364  |  |   template <  | 
3365  |  |       class U = T, class G = T,  | 
3366  |  |       detail::enable_if_t<!std::is_nothrow_constructible<T, U &&>::value> * =  | 
3367  |  |           nullptr,  | 
3368  |  |       detail::enable_if_t<!std::is_void<U>::value> * = nullptr,  | 
3369  |  |       detail::enable_if_t<  | 
3370  |  |           (!std::is_same<expected<T, E>, detail::decay_t<U>>::value &&  | 
3371  |  |            !detail::conjunction<std::is_scalar<T>,  | 
3372  |  |                                 std::is_same<T, detail::decay_t<U>>>::value &&  | 
3373  |  |            std::is_constructible<T, U>::value &&  | 
3374  |  |            std::is_assignable<G &, U>::value &&  | 
3375  |  |            std::is_nothrow_move_constructible<E>::value)> * = nullptr>  | 
3376  |  |   expected &operator=(U &&v) { | 
3377  |  |     if (has_value()) { | 
3378  |  |       val() = std::forward<U>(v);  | 
3379  |  |     } else { | 
3380  |  |       auto tmp = std::move(err());  | 
3381  |  |       err().~unexpected<E>();  | 
3382  |  |  | 
3383  |  | #ifdef TL_EXPECTED_EXCEPTIONS_ENABLED  | 
3384  |  |       try { | 
3385  |  |         ::new (valptr()) T(std::forward<U>(v));  | 
3386  |  |         this->m_has_val = true;  | 
3387  |  |       } catch (...) { | 
3388  |  |         err() = std::move(tmp);  | 
3389  |  |         throw;  | 
3390  |  |       }  | 
3391  |  | #else  | 
3392  |  |       ::new (valptr()) T(std::forward<U>(v));  | 
3393  |  |       this->m_has_val = true;  | 
3394  |  | #endif  | 
3395  |  |     }  | 
3396  |  |  | 
3397  |  |     return *this;  | 
3398  |  |   }  | 
3399  |  |  | 
3400  |  |   template <class G = E,  | 
3401  |  |             detail::enable_if_t<std::is_nothrow_copy_constructible<G>::value &&  | 
3402  |  |                                 std::is_assignable<G &, G>::value> * = nullptr>  | 
3403  |  |   expected &operator=(const unexpected<G> &rhs) { | 
3404  |  |     if (!has_value()) { | 
3405  |  |       err() = rhs;  | 
3406  |  |     } else { | 
3407  |  |       this->destroy_val();  | 
3408  |  |       ::new (errptr()) unexpected<E>(rhs);  | 
3409  |  |       this->m_has_val = false;  | 
3410  |  |     }  | 
3411  |  |  | 
3412  |  |     return *this;  | 
3413  |  |   }  | 
3414  |  |  | 
3415  |  |   template <class G = E,  | 
3416  |  |             detail::enable_if_t<std::is_nothrow_move_constructible<G>::value &&  | 
3417  |  |                                 std::is_move_assignable<G>::value> * = nullptr>  | 
3418  |  |   expected &operator=(unexpected<G> &&rhs) noexcept { | 
3419  |  |     if (!has_value()) { | 
3420  |  |       err() = std::move(rhs);  | 
3421  |  |     } else { | 
3422  |  |       this->destroy_val();  | 
3423  |  |       ::new (errptr()) unexpected<E>(std::move(rhs));  | 
3424  |  |       this->m_has_val = false;  | 
3425  |  |     }  | 
3426  |  |  | 
3427  |  |     return *this;  | 
3428  |  |   }  | 
3429  |  |  | 
3430  |  |   template <class... Args, detail::enable_if_t<std::is_nothrow_constructible<  | 
3431  |  |                                T, Args &&...>::value> * = nullptr>  | 
3432  |  |   void emplace(Args &&...args) { | 
3433  |  |     if (has_value()) { | 
3434  |  |       val().~T();  | 
3435  |  |     } else { | 
3436  |  |       err().~unexpected<E>();  | 
3437  |  |       this->m_has_val = true;  | 
3438  |  |     }  | 
3439  |  |     ::new (valptr()) T(std::forward<Args>(args)...);  | 
3440  |  |   }  | 
3441  |  |  | 
3442  |  |   template <class... Args, detail::enable_if_t<!std::is_nothrow_constructible<  | 
3443  |  |                                T, Args &&...>::value> * = nullptr>  | 
3444  |  |   void emplace(Args &&...args) { | 
3445  |  |     if (has_value()) { | 
3446  |  |       val().~T();  | 
3447  |  |       ::new (valptr()) T(std::forward<Args>(args)...);  | 
3448  |  |     } else { | 
3449  |  |       auto tmp = std::move(err());  | 
3450  |  |       err().~unexpected<E>();  | 
3451  |  |  | 
3452  |  | #ifdef TL_EXPECTED_EXCEPTIONS_ENABLED  | 
3453  |  |       try { | 
3454  |  |         ::new (valptr()) T(std::forward<Args>(args)...);  | 
3455  |  |         this->m_has_val = true;  | 
3456  |  |       } catch (...) { | 
3457  |  |         err() = std::move(tmp);  | 
3458  |  |         throw;  | 
3459  |  |       }  | 
3460  |  | #else  | 
3461  |  |       ::new (valptr()) T(std::forward<Args>(args)...);  | 
3462  |  |       this->m_has_val = true;  | 
3463  |  | #endif  | 
3464  |  |     }  | 
3465  |  |   }  | 
3466  |  |  | 
3467  |  |   template <class U, class... Args,  | 
3468  |  |             detail::enable_if_t<std::is_nothrow_constructible<  | 
3469  |  |                 T, std::initializer_list<U> &, Args &&...>::value> * = nullptr>  | 
3470  |  |   void emplace(std::initializer_list<U> il, Args &&...args) { | 
3471  |  |     if (has_value()) { | 
3472  |  |       T t(il, std::forward<Args>(args)...);  | 
3473  |  |       val() = std::move(t);  | 
3474  |  |     } else { | 
3475  |  |       err().~unexpected<E>();  | 
3476  |  |       ::new (valptr()) T(il, std::forward<Args>(args)...);  | 
3477  |  |       this->m_has_val = true;  | 
3478  |  |     }  | 
3479  |  |   }  | 
3480  |  |  | 
3481  |  |   template <class U, class... Args,  | 
3482  |  |             detail::enable_if_t<!std::is_nothrow_constructible<  | 
3483  |  |                 T, std::initializer_list<U> &, Args &&...>::value> * = nullptr>  | 
3484  |  |   void emplace(std::initializer_list<U> il, Args &&...args) { | 
3485  |  |     if (has_value()) { | 
3486  |  |       T t(il, std::forward<Args>(args)...);  | 
3487  |  |       val() = std::move(t);  | 
3488  |  |     } else { | 
3489  |  |       auto tmp = std::move(err());  | 
3490  |  |       err().~unexpected<E>();  | 
3491  |  |  | 
3492  |  | #ifdef TL_EXPECTED_EXCEPTIONS_ENABLED  | 
3493  |  |       try { | 
3494  |  |         ::new (valptr()) T(il, std::forward<Args>(args)...);  | 
3495  |  |         this->m_has_val = true;  | 
3496  |  |       } catch (...) { | 
3497  |  |         err() = std::move(tmp);  | 
3498  |  |         throw;  | 
3499  |  |       }  | 
3500  |  | #else  | 
3501  |  |       ::new (valptr()) T(il, std::forward<Args>(args)...);  | 
3502  |  |       this->m_has_val = true;  | 
3503  |  | #endif  | 
3504  |  |     }  | 
3505  |  |   }  | 
3506  |  |  | 
3507  |  |  private:  | 
3508  |  |   using t_is_void = std::true_type;  | 
3509  |  |   using t_is_not_void = std::false_type;  | 
3510  |  |   using t_is_nothrow_move_constructible = std::true_type;  | 
3511  |  |   using move_constructing_t_can_throw = std::false_type;  | 
3512  |  |   using e_is_nothrow_move_constructible = std::true_type;  | 
3513  |  |   using move_constructing_e_can_throw = std::false_type;  | 
3514  |  |  | 
3515  |  |   void swap_where_both_have_value(expected & /*rhs*/, t_is_void) noexcept { | 
3516  |  |     // swapping void is a no-op  | 
3517  |  |   }  | 
3518  |  |  | 
3519  |  |   void swap_where_both_have_value(expected &rhs, t_is_not_void) { | 
3520  |  |     using std::swap;  | 
3521  |  |     swap(val(), rhs.val());  | 
3522  |  |   }  | 
3523  |  |  | 
3524  |  |   void swap_where_only_one_has_value(expected &rhs, t_is_void) noexcept(  | 
3525  |  |       std::is_nothrow_move_constructible<E>::value) { | 
3526  |  |     ::new (errptr()) unexpected_type(std::move(rhs.err()));  | 
3527  |  |     rhs.err().~unexpected_type();  | 
3528  |  |     std::swap(this->m_has_val, rhs.m_has_val);  | 
3529  |  |   }  | 
3530  |  |  | 
3531  |  |   void swap_where_only_one_has_value(expected &rhs, t_is_not_void) { | 
3532  |  |     swap_where_only_one_has_value_and_t_is_not_void(  | 
3533  |  |         rhs, typename std::is_nothrow_move_constructible<T>::type{}, | 
3534  |  |         typename std::is_nothrow_move_constructible<E>::type{}); | 
3535  |  |   }  | 
3536  |  |  | 
3537  |  |   void swap_where_only_one_has_value_and_t_is_not_void(  | 
3538  |  |       expected &rhs, t_is_nothrow_move_constructible,  | 
3539  |  |       e_is_nothrow_move_constructible) noexcept { | 
3540  |  |     auto temp = std::move(val());  | 
3541  |  |     val().~T();  | 
3542  |  |     ::new (errptr()) unexpected_type(std::move(rhs.err()));  | 
3543  |  |     rhs.err().~unexpected_type();  | 
3544  |  |     ::new (rhs.valptr()) T(std::move(temp));  | 
3545  |  |     std::swap(this->m_has_val, rhs.m_has_val);  | 
3546  |  |   }  | 
3547  |  |  | 
3548  |  |   void swap_where_only_one_has_value_and_t_is_not_void(  | 
3549  |  |       expected &rhs, t_is_nothrow_move_constructible,  | 
3550  |  |       move_constructing_e_can_throw) { | 
3551  |  |     auto temp = std::move(val());  | 
3552  |  |     val().~T();  | 
3553  |  | #ifdef TL_EXPECTED_EXCEPTIONS_ENABLED  | 
3554  |  |     try { | 
3555  |  |       ::new (errptr()) unexpected_type(std::move(rhs.err()));  | 
3556  |  |       rhs.err().~unexpected_type();  | 
3557  |  |       ::new (rhs.valptr()) T(std::move(temp));  | 
3558  |  |       std::swap(this->m_has_val, rhs.m_has_val);  | 
3559  |  |     } catch (...) { | 
3560  |  |       val() = std::move(temp);  | 
3561  |  |       throw;  | 
3562  |  |     }  | 
3563  |  | #else  | 
3564  |  |     ::new (errptr()) unexpected_type(std::move(rhs.err()));  | 
3565  |  |     rhs.err().~unexpected_type();  | 
3566  |  |     ::new (rhs.valptr()) T(std::move(temp));  | 
3567  |  |     std::swap(this->m_has_val, rhs.m_has_val);  | 
3568  |  | #endif  | 
3569  |  |   }  | 
3570  |  |  | 
3571  |  |   void swap_where_only_one_has_value_and_t_is_not_void(  | 
3572  |  |       expected &rhs, move_constructing_t_can_throw,  | 
3573  |  |       e_is_nothrow_move_constructible) { | 
3574  |  |     auto temp = std::move(rhs.err());  | 
3575  |  |     rhs.err().~unexpected_type();  | 
3576  |  | #ifdef TL_EXPECTED_EXCEPTIONS_ENABLED  | 
3577  |  |     try { | 
3578  |  |       ::new (rhs.valptr()) T(std::move(val()));  | 
3579  |  |       val().~T();  | 
3580  |  |       ::new (errptr()) unexpected_type(std::move(temp));  | 
3581  |  |       std::swap(this->m_has_val, rhs.m_has_val);  | 
3582  |  |     } catch (...) { | 
3583  |  |       rhs.err() = std::move(temp);  | 
3584  |  |       throw;  | 
3585  |  |     }  | 
3586  |  | #else  | 
3587  |  |     ::new (rhs.valptr()) T(std::move(val()));  | 
3588  |  |     val().~T();  | 
3589  |  |     ::new (errptr()) unexpected_type(std::move(temp));  | 
3590  |  |     std::swap(this->m_has_val, rhs.m_has_val);  | 
3591  |  | #endif  | 
3592  |  |   }  | 
3593  |  |  | 
3594  |  |  public:  | 
3595  |  |   template <class OT = T, class OE = E>  | 
3596  |  |   detail::enable_if_t<detail::is_swappable<OT>::value &&  | 
3597  |  |                       detail::is_swappable<OE>::value &&  | 
3598  |  |                       (std::is_nothrow_move_constructible<OT>::value ||  | 
3599  |  |                        std::is_nothrow_move_constructible<OE>::value)>  | 
3600  |  |   swap(expected &rhs) noexcept(std::is_nothrow_move_constructible<T>::value &&  | 
3601  |  |                                detail::is_nothrow_swappable<T>::value &&  | 
3602  |  |                                std::is_nothrow_move_constructible<E>::value &&  | 
3603  |  |                                detail::is_nothrow_swappable<E>::value) { | 
3604  |  |     if (has_value() && rhs.has_value()) { | 
3605  |  |       swap_where_both_have_value(rhs, typename std::is_void<T>::type{}); | 
3606  |  |     } else if (!has_value() && rhs.has_value()) { | 
3607  |  |       rhs.swap(*this);  | 
3608  |  |     } else if (has_value()) { | 
3609  |  |       swap_where_only_one_has_value(rhs, typename std::is_void<T>::type{}); | 
3610  |  |     } else { | 
3611  |  |       using std::swap;  | 
3612  |  |       swap(err(), rhs.err());  | 
3613  |  |     }  | 
3614  |  |   }  | 
3615  |  |  | 
3616  |  |   constexpr const T *operator->() const { | 
3617  |  |     TL_ASSERT(has_value());  | 
3618  |  |     return valptr();  | 
3619  |  |   }  | 
3620  | 0  |   TL_EXPECTED_11_CONSTEXPR T *operator->() { | 
3621  | 0  |     TL_ASSERT(has_value());  | 
3622  | 0  |     return valptr();  | 
3623  | 0  |   } Unexecuted instantiation: tl::expected<ada::url_pattern_init, ada::errors>::operator->() Unexecuted instantiation: tl::expected<ada::url_aggregator, ada::errors>::operator->() Unexecuted instantiation: tl::expected<ada::url, ada::errors>::operator->() Unexecuted instantiation: tl::expected<std::__1::optional<ada::url_pattern_result>, ada::errors>::operator->()  | 
3624  |  |  | 
3625  |  |   template <class U = T,  | 
3626  |  |             detail::enable_if_t<!std::is_void<U>::value> * = nullptr>  | 
3627  |  |   constexpr const U &operator*() const & { | 
3628  |  |     TL_ASSERT(has_value());  | 
3629  |  |     return val();  | 
3630  |  |   }  | 
3631  |  |   template <class U = T,  | 
3632  |  |             detail::enable_if_t<!std::is_void<U>::value> * = nullptr>  | 
3633  | 0  |   TL_EXPECTED_11_CONSTEXPR U &operator*() & { | 
3634  | 0  |     TL_ASSERT(has_value());  | 
3635  | 0  |     return val();  | 
3636  | 0  |   } Unexecuted instantiation: _ZNR2tl8expectedIN3ada14url_aggregatorENS1_6errorsEEdeIS2_TnPNSt3__19enable_ifIXntsr3std7is_voidIT_EE5valueEvE4typeELPv0EEERS8_v Unexecuted instantiation: _ZNR2tl8expectedINSt3__16vectorIN3ada19url_pattern_helpers5tokenENS1_9allocatorIS5_EEEENS3_6errorsEEdeIS8_TnPNS1_9enable_ifIXntsr3std7is_voidIT_EE5valueEvE4typeELPv0EEERSD_v Unexecuted instantiation: _ZNR2tl8expectedIN3ada11url_patternIN4node11url_pattern23URLPatternRegexProviderEEENS1_6errorsEEdeIS6_TnPNSt3__19enable_ifIXntsr3std7is_voidIT_EE5valueEvE4typeELPv0EEERSC_v Unexecuted instantiation: _ZNR2tl8expectedIbN3ada6errorsEEdeIbTnPNSt3__19enable_ifIXntsr3std7is_voidIT_EE5valueEvE4typeELPv0EEERS7_v Unexecuted instantiation: _ZNR2tl8expectedIN3ada16url_pattern_initENS1_6errorsEEdeIS2_TnPNSt3__19enable_ifIXntsr3std7is_voidIT_EE5valueEvE4typeELPv0EEERS8_v Unexecuted instantiation: _ZNR2tl8expectedINSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEN3ada6errorsEEdeIS7_TnPNS1_9enable_ifIXntsr3std7is_voidIT_EE5valueEvE4typeELPv0EEERSD_v Unexecuted instantiation: _ZNR2tl8expectedINSt3__16vectorIN3ada16url_pattern_partENS1_9allocatorIS4_EEEENS3_6errorsEEdeIS7_TnPNS1_9enable_ifIXntsr3std7is_voidIT_EE5valueEvE4typeELPv0EEERSC_v Unexecuted instantiation: _ZNR2tl8expectedIN3ada21url_pattern_componentIN4node11url_pattern23URLPatternRegexProviderEEENS1_6errorsEEdeIS6_TnPNSt3__19enable_ifIXntsr3std7is_voidIT_EE5valueEvE4typeELPv0EEERSC_v  | 
3637  |  |   template <class U = T,  | 
3638  |  |             detail::enable_if_t<!std::is_void<U>::value> * = nullptr>  | 
3639  |  |   constexpr const U &&operator*() const && { | 
3640  |  |     TL_ASSERT(has_value());  | 
3641  |  |     return std::move(val());  | 
3642  |  |   }  | 
3643  |  |   template <class U = T,  | 
3644  |  |             detail::enable_if_t<!std::is_void<U>::value> * = nullptr>  | 
3645  |  |   TL_EXPECTED_11_CONSTEXPR U &&operator*() && { | 
3646  |  |     TL_ASSERT(has_value());  | 
3647  |  |     return std::move(val());  | 
3648  |  |   }  | 
3649  |  |  | 
3650  | 0  |   constexpr bool has_value() const noexcept { return this->m_has_val; }Unexecuted instantiation: tl::expected<ada::url_pattern_init, ada::errors>::has_value() const Unexecuted instantiation: tl::expected<ada::url_aggregator, ada::errors>::has_value() const Unexecuted instantiation: tl::expected<std::__1::optional<ada::url_pattern_result>, ada::errors>::has_value() const  | 
3651  | 0  |   constexpr explicit operator bool() const noexcept { return this->m_has_val; }Unexecuted instantiation: tl::expected<ada::url_pattern_init, ada::errors>::operator bool() const Unexecuted instantiation: tl::expected<ada::url_aggregator, ada::errors>::operator bool() const Unexecuted instantiation: tl::expected<std::__1::vector<ada::url_pattern_helpers::token, std::__1::allocator<ada::url_pattern_helpers::token> >, ada::errors>::operator bool() const Unexecuted instantiation: tl::expected<ada::url, ada::errors>::operator bool() const Unexecuted instantiation: tl::expected<ada::url_pattern<node::url_pattern::URLPatternRegexProvider>, ada::errors>::operator bool() const Unexecuted instantiation: tl::expected<std::__1::optional<ada::url_pattern_result>, ada::errors>::operator bool() const Unexecuted instantiation: tl::expected<bool, ada::errors>::operator bool() const Unexecuted instantiation: tl::expected<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, ada::errors>::operator bool() const Unexecuted instantiation: tl::expected<std::__1::vector<ada::url_pattern_part, std::__1::allocator<ada::url_pattern_part> >, ada::errors>::operator bool() const Unexecuted instantiation: tl::expected<ada::url_pattern_component<node::url_pattern::URLPatternRegexProvider>, ada::errors>::operator bool() const  | 
3652  |  |  | 
3653  |  |   template <class U = T,  | 
3654  |  |             detail::enable_if_t<!std::is_void<U>::value> * = nullptr>  | 
3655  |  |   TL_EXPECTED_11_CONSTEXPR const U &value() const & { | 
3656  |  |     if (!has_value())  | 
3657  |  |       detail::throw_exception(bad_expected_access<E>(err().value()));  | 
3658  |  |     return val();  | 
3659  |  |   }  | 
3660  |  |   template <class U = T,  | 
3661  |  |             detail::enable_if_t<!std::is_void<U>::value> * = nullptr>  | 
3662  | 0  |   TL_EXPECTED_11_CONSTEXPR U &value() & { | 
3663  | 0  |     if (!has_value())  | 
3664  | 0  |       detail::throw_exception(bad_expected_access<E>(err().value()));  | 
3665  | 0  |     return val();  | 
3666  | 0  |   }  | 
3667  |  |   template <class U = T,  | 
3668  |  |             detail::enable_if_t<!std::is_void<U>::value> * = nullptr>  | 
3669  |  |   TL_EXPECTED_11_CONSTEXPR const U &&value() const && { | 
3670  |  |     if (!has_value())  | 
3671  |  |       detail::throw_exception(bad_expected_access<E>(std::move(err()).value()));  | 
3672  |  |     return std::move(val());  | 
3673  |  |   }  | 
3674  |  |   template <class U = T,  | 
3675  |  |             detail::enable_if_t<!std::is_void<U>::value> * = nullptr>  | 
3676  |  |   TL_EXPECTED_11_CONSTEXPR U &&value() && { | 
3677  |  |     if (!has_value())  | 
3678  |  |       detail::throw_exception(bad_expected_access<E>(std::move(err()).value()));  | 
3679  |  |     return std::move(val());  | 
3680  |  |   }  | 
3681  |  |  | 
3682  |  |   constexpr const E &error() const & { | 
3683  |  |     TL_ASSERT(!has_value());  | 
3684  |  |     return err().value();  | 
3685  |  |   }  | 
3686  | 0  |   TL_EXPECTED_11_CONSTEXPR E &error() & { | 
3687  | 0  |     TL_ASSERT(!has_value());  | 
3688  | 0  |     return err().value();  | 
3689  | 0  |   } Unexecuted instantiation: tl::expected<ada::url_pattern_init, ada::errors>::error() & Unexecuted instantiation: tl::expected<std::__1::vector<ada::url_pattern_helpers::token, std::__1::allocator<ada::url_pattern_helpers::token> >, ada::errors>::error() & Unexecuted instantiation: tl::expected<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, ada::errors>::error() & Unexecuted instantiation: tl::expected<std::__1::vector<ada::url_pattern_part, std::__1::allocator<ada::url_pattern_part> >, ada::errors>::error() & Unexecuted instantiation: tl::expected<ada::url_pattern_component<node::url_pattern::URLPatternRegexProvider>, ada::errors>::error() &  | 
3690  |  |   constexpr const E &&error() const && { | 
3691  |  |     TL_ASSERT(!has_value());  | 
3692  |  |     return std::move(err().value());  | 
3693  |  |   }  | 
3694  |  |   TL_EXPECTED_11_CONSTEXPR E &&error() && { | 
3695  |  |     TL_ASSERT(!has_value());  | 
3696  |  |     return std::move(err().value());  | 
3697  |  |   }  | 
3698  |  |  | 
3699  |  |   template <class U>  | 
3700  |  |   constexpr T value_or(U &&v) const & { | 
3701  |  |     static_assert(std::is_copy_constructible<T>::value &&  | 
3702  |  |                       std::is_convertible<U &&, T>::value,  | 
3703  |  |                   "T must be copy-constructible and convertible to from U&&");  | 
3704  |  |     return bool(*this) ? **this : static_cast<T>(std::forward<U>(v));  | 
3705  |  |   }  | 
3706  |  |   template <class U>  | 
3707  |  |   TL_EXPECTED_11_CONSTEXPR T value_or(U &&v) && { | 
3708  |  |     static_assert(std::is_move_constructible<T>::value &&  | 
3709  |  |                       std::is_convertible<U &&, T>::value,  | 
3710  |  |                   "T must be move-constructible and convertible to from U&&");  | 
3711  |  |     return bool(*this) ? std::move(**this) : static_cast<T>(std::forward<U>(v));  | 
3712  |  |   }  | 
3713  |  | };  | 
3714  |  |  | 
3715  |  | namespace detail { | 
3716  |  | template <class Exp>  | 
3717  |  | using exp_t = typename detail::decay_t<Exp>::value_type;  | 
3718  |  | template <class Exp>  | 
3719  |  | using err_t = typename detail::decay_t<Exp>::error_type;  | 
3720  |  | template <class Exp, class Ret>  | 
3721  |  | using ret_t = expected<Ret, err_t<Exp>>;  | 
3722  |  |  | 
3723  |  | #ifdef TL_EXPECTED_CXX14  | 
3724  |  | template <class Exp, class F,  | 
3725  |  |           detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,  | 
3726  |  |           class Ret = decltype(detail::invoke(std::declval<F>(),  | 
3727  |  |                                               *std::declval<Exp>()))>  | 
3728  |  | constexpr auto and_then_impl(Exp &&exp, F &&f) { | 
3729  |  |   static_assert(detail::is_expected<Ret>::value, "F must return an expected");  | 
3730  |  |  | 
3731  |  |   return exp.has_value()  | 
3732  |  |              ? detail::invoke(std::forward<F>(f), *std::forward<Exp>(exp))  | 
3733  |  |              : Ret(unexpect, std::forward<Exp>(exp).error());  | 
3734  |  | }  | 
3735  |  |  | 
3736  |  | template <class Exp, class F,  | 
3737  |  |           detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,  | 
3738  |  |           class Ret = decltype(detail::invoke(std::declval<F>()))>  | 
3739  |  | constexpr auto and_then_impl(Exp &&exp, F &&f) { | 
3740  |  |   static_assert(detail::is_expected<Ret>::value, "F must return an expected");  | 
3741  |  |  | 
3742  |  |   return exp.has_value() ? detail::invoke(std::forward<F>(f))  | 
3743  |  |                          : Ret(unexpect, std::forward<Exp>(exp).error());  | 
3744  |  | }  | 
3745  |  | #else  | 
3746  |  | template <class>  | 
3747  |  | struct TC;  | 
3748  |  | template <class Exp, class F,  | 
3749  |  |           class Ret = decltype(detail::invoke(std::declval<F>(),  | 
3750  |  |                                               *std::declval<Exp>())),  | 
3751  |  |           detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr>  | 
3752  |  | auto and_then_impl(Exp &&exp, F &&f) -> Ret { | 
3753  |  |   static_assert(detail::is_expected<Ret>::value, "F must return an expected");  | 
3754  |  |  | 
3755  |  |   return exp.has_value()  | 
3756  |  |              ? detail::invoke(std::forward<F>(f), *std::forward<Exp>(exp))  | 
3757  |  |              : Ret(unexpect, std::forward<Exp>(exp).error());  | 
3758  |  | }  | 
3759  |  |  | 
3760  |  | template <class Exp, class F,  | 
3761  |  |           class Ret = decltype(detail::invoke(std::declval<F>())),  | 
3762  |  |           detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr>  | 
3763  |  | constexpr auto and_then_impl(Exp &&exp, F &&f) -> Ret { | 
3764  |  |   static_assert(detail::is_expected<Ret>::value, "F must return an expected");  | 
3765  |  |  | 
3766  |  |   return exp.has_value() ? detail::invoke(std::forward<F>(f))  | 
3767  |  |                          : Ret(unexpect, std::forward<Exp>(exp).error());  | 
3768  |  | }  | 
3769  |  | #endif  | 
3770  |  |  | 
3771  |  | #ifdef TL_EXPECTED_CXX14  | 
3772  |  | template <class Exp, class F,  | 
3773  |  |           detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,  | 
3774  |  |           class Ret = decltype(detail::invoke(std::declval<F>(),  | 
3775  |  |                                               *std::declval<Exp>())),  | 
3776  |  |           detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>  | 
3777  |  | constexpr auto expected_map_impl(Exp &&exp, F &&f) { | 
3778  |  |   using result = ret_t<Exp, detail::decay_t<Ret>>;  | 
3779  |  |   return exp.has_value() ? result(detail::invoke(std::forward<F>(f),  | 
3780  |  |                                                  *std::forward<Exp>(exp)))  | 
3781  |  |                          : result(unexpect, std::forward<Exp>(exp).error());  | 
3782  |  | }  | 
3783  |  |  | 
3784  |  | template <class Exp, class F,  | 
3785  |  |           detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,  | 
3786  |  |           class Ret = decltype(detail::invoke(std::declval<F>(),  | 
3787  |  |                                               *std::declval<Exp>())),  | 
3788  |  |           detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>  | 
3789  |  | auto expected_map_impl(Exp &&exp, F &&f) { | 
3790  |  |   using result = expected<void, err_t<Exp>>;  | 
3791  |  |   if (exp.has_value()) { | 
3792  |  |     detail::invoke(std::forward<F>(f), *std::forward<Exp>(exp));  | 
3793  |  |     return result();  | 
3794  |  |   }  | 
3795  |  |  | 
3796  |  |   return result(unexpect, std::forward<Exp>(exp).error());  | 
3797  |  | }  | 
3798  |  |  | 
3799  |  | template <class Exp, class F,  | 
3800  |  |           detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,  | 
3801  |  |           class Ret = decltype(detail::invoke(std::declval<F>())),  | 
3802  |  |           detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>  | 
3803  |  | constexpr auto expected_map_impl(Exp &&exp, F &&f) { | 
3804  |  |   using result = ret_t<Exp, detail::decay_t<Ret>>;  | 
3805  |  |   return exp.has_value() ? result(detail::invoke(std::forward<F>(f)))  | 
3806  |  |                          : result(unexpect, std::forward<Exp>(exp).error());  | 
3807  |  | }  | 
3808  |  |  | 
3809  |  | template <class Exp, class F,  | 
3810  |  |           detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,  | 
3811  |  |           class Ret = decltype(detail::invoke(std::declval<F>())),  | 
3812  |  |           detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>  | 
3813  |  | auto expected_map_impl(Exp &&exp, F &&f) { | 
3814  |  |   using result = expected<void, err_t<Exp>>;  | 
3815  |  |   if (exp.has_value()) { | 
3816  |  |     detail::invoke(std::forward<F>(f));  | 
3817  |  |     return result();  | 
3818  |  |   }  | 
3819  |  |  | 
3820  |  |   return result(unexpect, std::forward<Exp>(exp).error());  | 
3821  |  | }  | 
3822  |  | #else  | 
3823  |  | template <class Exp, class F,  | 
3824  |  |           detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,  | 
3825  |  |           class Ret = decltype(detail::invoke(std::declval<F>(),  | 
3826  |  |                                               *std::declval<Exp>())),  | 
3827  |  |           detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>  | 
3828  |  |  | 
3829  |  | constexpr auto expected_map_impl(Exp &&exp, F &&f)  | 
3830  |  |     -> ret_t<Exp, detail::decay_t<Ret>> { | 
3831  |  |   using result = ret_t<Exp, detail::decay_t<Ret>>;  | 
3832  |  |  | 
3833  |  |   return exp.has_value() ? result(detail::invoke(std::forward<F>(f),  | 
3834  |  |                                                  *std::forward<Exp>(exp)))  | 
3835  |  |                          : result(unexpect, std::forward<Exp>(exp).error());  | 
3836  |  | }  | 
3837  |  |  | 
3838  |  | template <class Exp, class F,  | 
3839  |  |           detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,  | 
3840  |  |           class Ret = decltype(detail::invoke(std::declval<F>(),  | 
3841  |  |                                               *std::declval<Exp>())),  | 
3842  |  |           detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>  | 
3843  |  |  | 
3844  |  | auto expected_map_impl(Exp &&exp, F &&f) -> expected<void, err_t<Exp>> { | 
3845  |  |   if (exp.has_value()) { | 
3846  |  |     detail::invoke(std::forward<F>(f), *std::forward<Exp>(exp));  | 
3847  |  |     return {}; | 
3848  |  |   }  | 
3849  |  |  | 
3850  |  |   return unexpected<err_t<Exp>>(std::forward<Exp>(exp).error());  | 
3851  |  | }  | 
3852  |  |  | 
3853  |  | template <class Exp, class F,  | 
3854  |  |           detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,  | 
3855  |  |           class Ret = decltype(detail::invoke(std::declval<F>())),  | 
3856  |  |           detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>  | 
3857  |  |  | 
3858  |  | constexpr auto expected_map_impl(Exp &&exp, F &&f)  | 
3859  |  |     -> ret_t<Exp, detail::decay_t<Ret>> { | 
3860  |  |   using result = ret_t<Exp, detail::decay_t<Ret>>;  | 
3861  |  |  | 
3862  |  |   return exp.has_value() ? result(detail::invoke(std::forward<F>(f)))  | 
3863  |  |                          : result(unexpect, std::forward<Exp>(exp).error());  | 
3864  |  | }  | 
3865  |  |  | 
3866  |  | template <class Exp, class F,  | 
3867  |  |           detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,  | 
3868  |  |           class Ret = decltype(detail::invoke(std::declval<F>())),  | 
3869  |  |           detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>  | 
3870  |  |  | 
3871  |  | auto expected_map_impl(Exp &&exp, F &&f) -> expected<void, err_t<Exp>> { | 
3872  |  |   if (exp.has_value()) { | 
3873  |  |     detail::invoke(std::forward<F>(f));  | 
3874  |  |     return {}; | 
3875  |  |   }  | 
3876  |  |  | 
3877  |  |   return unexpected<err_t<Exp>>(std::forward<Exp>(exp).error());  | 
3878  |  | }  | 
3879  |  | #endif  | 
3880  |  |  | 
3881  |  | #if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \  | 
3882  |  |     !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55)  | 
3883  |  | template <class Exp, class F,  | 
3884  |  |           detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,  | 
3885  |  |           class Ret = decltype(detail::invoke(std::declval<F>(),  | 
3886  |  |                                               std::declval<Exp>().error())),  | 
3887  |  |           detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>  | 
3888  |  | constexpr auto map_error_impl(Exp &&exp, F &&f) { | 
3889  |  |   using result = expected<exp_t<Exp>, detail::decay_t<Ret>>;  | 
3890  |  |   return exp.has_value()  | 
3891  |  |              ? result(*std::forward<Exp>(exp))  | 
3892  |  |              : result(unexpect, detail::invoke(std::forward<F>(f),  | 
3893  |  |                                                std::forward<Exp>(exp).error()));  | 
3894  |  | }  | 
3895  |  | template <class Exp, class F,  | 
3896  |  |           detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,  | 
3897  |  |           class Ret = decltype(detail::invoke(std::declval<F>(),  | 
3898  |  |                                               std::declval<Exp>().error())),  | 
3899  |  |           detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>  | 
3900  |  | auto map_error_impl(Exp &&exp, F &&f) { | 
3901  |  |   using result = expected<exp_t<Exp>, monostate>;  | 
3902  |  |   if (exp.has_value()) { | 
3903  |  |     return result(*std::forward<Exp>(exp));  | 
3904  |  |   }  | 
3905  |  |  | 
3906  |  |   detail::invoke(std::forward<F>(f), std::forward<Exp>(exp).error());  | 
3907  |  |   return result(unexpect, monostate{}); | 
3908  |  | }  | 
3909  |  | template <class Exp, class F,  | 
3910  |  |           detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,  | 
3911  |  |           class Ret = decltype(detail::invoke(std::declval<F>(),  | 
3912  |  |                                               std::declval<Exp>().error())),  | 
3913  |  |           detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>  | 
3914  |  | constexpr auto map_error_impl(Exp &&exp, F &&f) { | 
3915  |  |   using result = expected<exp_t<Exp>, detail::decay_t<Ret>>;  | 
3916  |  |   return exp.has_value()  | 
3917  |  |              ? result()  | 
3918  |  |              : result(unexpect, detail::invoke(std::forward<F>(f),  | 
3919  |  |                                                std::forward<Exp>(exp).error()));  | 
3920  |  | }  | 
3921  |  | template <class Exp, class F,  | 
3922  |  |           detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,  | 
3923  |  |           class Ret = decltype(detail::invoke(std::declval<F>(),  | 
3924  |  |                                               std::declval<Exp>().error())),  | 
3925  |  |           detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>  | 
3926  |  | auto map_error_impl(Exp &&exp, F &&f) { | 
3927  |  |   using result = expected<exp_t<Exp>, monostate>;  | 
3928  |  |   if (exp.has_value()) { | 
3929  |  |     return result();  | 
3930  |  |   }  | 
3931  |  |  | 
3932  |  |   detail::invoke(std::forward<F>(f), std::forward<Exp>(exp).error());  | 
3933  |  |   return result(unexpect, monostate{}); | 
3934  |  | }  | 
3935  |  | #else  | 
3936  |  | template <class Exp, class F,  | 
3937  |  |           detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,  | 
3938  |  |           class Ret = decltype(detail::invoke(std::declval<F>(),  | 
3939  |  |                                               std::declval<Exp>().error())),  | 
3940  |  |           detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>  | 
3941  |  | constexpr auto map_error_impl(Exp &&exp, F &&f)  | 
3942  |  |     -> expected<exp_t<Exp>, detail::decay_t<Ret>> { | 
3943  |  |   using result = expected<exp_t<Exp>, detail::decay_t<Ret>>;  | 
3944  |  |  | 
3945  |  |   return exp.has_value()  | 
3946  |  |              ? result(*std::forward<Exp>(exp))  | 
3947  |  |              : result(unexpect, detail::invoke(std::forward<F>(f),  | 
3948  |  |                                                std::forward<Exp>(exp).error()));  | 
3949  |  | }  | 
3950  |  |  | 
3951  |  | template <class Exp, class F,  | 
3952  |  |           detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,  | 
3953  |  |           class Ret = decltype(detail::invoke(std::declval<F>(),  | 
3954  |  |                                               std::declval<Exp>().error())),  | 
3955  |  |           detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>  | 
3956  |  | auto map_error_impl(Exp &&exp, F &&f) -> expected<exp_t<Exp>, monostate> { | 
3957  |  |   using result = expected<exp_t<Exp>, monostate>;  | 
3958  |  |   if (exp.has_value()) { | 
3959  |  |     return result(*std::forward<Exp>(exp));  | 
3960  |  |   }  | 
3961  |  |  | 
3962  |  |   detail::invoke(std::forward<F>(f), std::forward<Exp>(exp).error());  | 
3963  |  |   return result(unexpect, monostate{}); | 
3964  |  | }  | 
3965  |  |  | 
3966  |  | template <class Exp, class F,  | 
3967  |  |           detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,  | 
3968  |  |           class Ret = decltype(detail::invoke(std::declval<F>(),  | 
3969  |  |                                               std::declval<Exp>().error())),  | 
3970  |  |           detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>  | 
3971  |  | constexpr auto map_error_impl(Exp &&exp, F &&f)  | 
3972  |  |     -> expected<exp_t<Exp>, detail::decay_t<Ret>> { | 
3973  |  |   using result = expected<exp_t<Exp>, detail::decay_t<Ret>>;  | 
3974  |  |  | 
3975  |  |   return exp.has_value()  | 
3976  |  |              ? result()  | 
3977  |  |              : result(unexpect, detail::invoke(std::forward<F>(f),  | 
3978  |  |                                                std::forward<Exp>(exp).error()));  | 
3979  |  | }  | 
3980  |  |  | 
3981  |  | template <class Exp, class F,  | 
3982  |  |           detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,  | 
3983  |  |           class Ret = decltype(detail::invoke(std::declval<F>(),  | 
3984  |  |                                               std::declval<Exp>().error())),  | 
3985  |  |           detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>  | 
3986  |  | auto map_error_impl(Exp &&exp, F &&f) -> expected<exp_t<Exp>, monostate> { | 
3987  |  |   using result = expected<exp_t<Exp>, monostate>;  | 
3988  |  |   if (exp.has_value()) { | 
3989  |  |     return result();  | 
3990  |  |   }  | 
3991  |  |  | 
3992  |  |   detail::invoke(std::forward<F>(f), std::forward<Exp>(exp).error());  | 
3993  |  |   return result(unexpect, monostate{}); | 
3994  |  | }  | 
3995  |  | #endif  | 
3996  |  |  | 
3997  |  | #ifdef TL_EXPECTED_CXX14  | 
3998  |  | template <class Exp, class F,  | 
3999  |  |           class Ret = decltype(detail::invoke(std::declval<F>(),  | 
4000  |  |                                               std::declval<Exp>().error())),  | 
4001  |  |           detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>  | 
4002  |  | constexpr auto or_else_impl(Exp &&exp, F &&f) { | 
4003  |  |   static_assert(detail::is_expected<Ret>::value, "F must return an expected");  | 
4004  |  |   return exp.has_value() ? std::forward<Exp>(exp)  | 
4005  |  |                          : detail::invoke(std::forward<F>(f),  | 
4006  |  |                                           std::forward<Exp>(exp).error());  | 
4007  |  | }  | 
4008  |  |  | 
4009  |  | template <class Exp, class F,  | 
4010  |  |           class Ret = decltype(detail::invoke(std::declval<F>(),  | 
4011  |  |                                               std::declval<Exp>().error())),  | 
4012  |  |           detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>  | 
4013  |  | detail::decay_t<Exp> or_else_impl(Exp &&exp, F &&f) { | 
4014  |  |   return exp.has_value() ? std::forward<Exp>(exp)  | 
4015  |  |                          : (detail::invoke(std::forward<F>(f),  | 
4016  |  |                                            std::forward<Exp>(exp).error()),  | 
4017  |  |                             std::forward<Exp>(exp));  | 
4018  |  | }  | 
4019  |  | #else  | 
4020  |  | template <class Exp, class F,  | 
4021  |  |           class Ret = decltype(detail::invoke(std::declval<F>(),  | 
4022  |  |                                               std::declval<Exp>().error())),  | 
4023  |  |           detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>  | 
4024  |  | auto or_else_impl(Exp &&exp, F &&f) -> Ret { | 
4025  |  |   static_assert(detail::is_expected<Ret>::value, "F must return an expected");  | 
4026  |  |   return exp.has_value() ? std::forward<Exp>(exp)  | 
4027  |  |                          : detail::invoke(std::forward<F>(f),  | 
4028  |  |                                           std::forward<Exp>(exp).error());  | 
4029  |  | }  | 
4030  |  |  | 
4031  |  | template <class Exp, class F,  | 
4032  |  |           class Ret = decltype(detail::invoke(std::declval<F>(),  | 
4033  |  |                                               std::declval<Exp>().error())),  | 
4034  |  |           detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>  | 
4035  |  | detail::decay_t<Exp> or_else_impl(Exp &&exp, F &&f) { | 
4036  |  |   return exp.has_value() ? std::forward<Exp>(exp)  | 
4037  |  |                          : (detail::invoke(std::forward<F>(f),  | 
4038  |  |                                            std::forward<Exp>(exp).error()),  | 
4039  |  |                             std::forward<Exp>(exp));  | 
4040  |  | }  | 
4041  |  | #endif  | 
4042  |  | }  // namespace detail  | 
4043  |  |  | 
4044  |  | template <class T, class E, class U, class F>  | 
4045  |  | constexpr bool operator==(const expected<T, E> &lhs,  | 
4046  |  |                           const expected<U, F> &rhs) { | 
4047  |  |   return (lhs.has_value() != rhs.has_value())  | 
4048  |  |              ? false  | 
4049  |  |              : (!lhs.has_value() ? lhs.error() == rhs.error() : *lhs == *rhs);  | 
4050  |  | }  | 
4051  |  | template <class T, class E, class U, class F>  | 
4052  |  | constexpr bool operator!=(const expected<T, E> &lhs,  | 
4053  |  |                           const expected<U, F> &rhs) { | 
4054  |  |   return (lhs.has_value() != rhs.has_value())  | 
4055  |  |              ? true  | 
4056  |  |              : (!lhs.has_value() ? lhs.error() != rhs.error() : *lhs != *rhs);  | 
4057  |  | }  | 
4058  |  | template <class E, class F>  | 
4059  |  | constexpr bool operator==(const expected<void, E> &lhs,  | 
4060  |  |                           const expected<void, F> &rhs) { | 
4061  |  |   return (lhs.has_value() != rhs.has_value())  | 
4062  |  |              ? false  | 
4063  |  |              : (!lhs.has_value() ? lhs.error() == rhs.error() : true);  | 
4064  |  | }  | 
4065  |  | template <class E, class F>  | 
4066  |  | constexpr bool operator!=(const expected<void, E> &lhs,  | 
4067  |  |                           const expected<void, F> &rhs) { | 
4068  |  |   return (lhs.has_value() != rhs.has_value())  | 
4069  |  |              ? true  | 
4070  |  |              : (!lhs.has_value() ? lhs.error() == rhs.error() : false);  | 
4071  |  | }  | 
4072  |  |  | 
4073  |  | template <class T, class E, class U>  | 
4074  |  | constexpr bool operator==(const expected<T, E> &x, const U &v) { | 
4075  |  |   return x.has_value() ? *x == v : false;  | 
4076  |  | }  | 
4077  |  | template <class T, class E, class U>  | 
4078  |  | constexpr bool operator==(const U &v, const expected<T, E> &x) { | 
4079  |  |   return x.has_value() ? *x == v : false;  | 
4080  |  | }  | 
4081  |  | template <class T, class E, class U>  | 
4082  |  | constexpr bool operator!=(const expected<T, E> &x, const U &v) { | 
4083  |  |   return x.has_value() ? *x != v : true;  | 
4084  |  | }  | 
4085  |  | template <class T, class E, class U>  | 
4086  |  | constexpr bool operator!=(const U &v, const expected<T, E> &x) { | 
4087  |  |   return x.has_value() ? *x != v : true;  | 
4088  |  | }  | 
4089  |  |  | 
4090  |  | template <class T, class E>  | 
4091  |  | constexpr bool operator==(const expected<T, E> &x, const unexpected<E> &e) { | 
4092  |  |   return x.has_value() ? false : x.error() == e.value();  | 
4093  |  | }  | 
4094  |  | template <class T, class E>  | 
4095  |  | constexpr bool operator==(const unexpected<E> &e, const expected<T, E> &x) { | 
4096  |  |   return x.has_value() ? false : x.error() == e.value();  | 
4097  |  | }  | 
4098  |  | template <class T, class E>  | 
4099  |  | constexpr bool operator!=(const expected<T, E> &x, const unexpected<E> &e) { | 
4100  |  |   return x.has_value() ? true : x.error() != e.value();  | 
4101  |  | }  | 
4102  |  | template <class T, class E>  | 
4103  |  | constexpr bool operator!=(const unexpected<E> &e, const expected<T, E> &x) { | 
4104  |  |   return x.has_value() ? true : x.error() != e.value();  | 
4105  |  | }  | 
4106  |  |  | 
4107  |  | template <class T, class E,  | 
4108  |  |           detail::enable_if_t<(std::is_void<T>::value ||  | 
4109  |  |                                std::is_move_constructible<T>::value) &&  | 
4110  |  |                               detail::is_swappable<T>::value &&  | 
4111  |  |                               std::is_move_constructible<E>::value &&  | 
4112  |  |                               detail::is_swappable<E>::value> * = nullptr>  | 
4113  |  | void swap(expected<T, E> &lhs,  | 
4114  |  |           expected<T, E> &rhs) noexcept(noexcept(lhs.swap(rhs))) { | 
4115  |  |   lhs.swap(rhs);  | 
4116  |  | }  | 
4117  |  | }  // namespace tl  | 
4118  |  |  | 
4119  |  | #endif  | 
4120  |  | /* end file include/ada/expected.h */  | 
4121  |  |  | 
4122  |  | /* begin file include/ada/url_pattern_regex.h */  | 
4123  |  | /**  | 
4124  |  |  * @file url_search_params.h  | 
4125  |  |  * @brief Declaration for the URL Search Params  | 
4126  |  |  */  | 
4127  |  | #ifndef ADA_URL_PATTERN_REGEX_H  | 
4128  |  | #define ADA_URL_PATTERN_REGEX_H  | 
4129  |  |  | 
4130  |  | #include <string>  | 
4131  |  | #include <string_view>  | 
4132  |  |  | 
4133  |  | #ifdef ADA_USE_UNSAFE_STD_REGEX_PROVIDER  | 
4134  |  | #include <regex>  | 
4135  |  | #endif  // ADA_USE_UNSAFE_STD_REGEX_PROVIDER  | 
4136  |  |  | 
4137  |  | #if ADA_INCLUDE_URL_PATTERN  | 
4138  |  | namespace ada::url_pattern_regex { | 
4139  |  |  | 
4140  |  | template <typename T>  | 
4141  |  | concept regex_concept = requires(T t, std::string_view pattern,  | 
4142  |  |                                  bool ignore_case, std::string_view input) { | 
4143  |  |   // Ensure the class has a type alias 'regex_type'  | 
4144  |  |   typename T::regex_type;  | 
4145  |  |  | 
4146  |  |   // Function to create a regex instance  | 
4147  |  |   { | 
4148  |  |     T::create_instance(pattern, ignore_case)  | 
4149  |  |   } -> std::same_as<std::optional<typename T::regex_type>>;  | 
4150  |  |  | 
4151  |  |   // Function to perform regex search  | 
4152  |  |   { | 
4153  |  |     T::regex_search(input, std::declval<typename T::regex_type&>())  | 
4154  |  |   } -> std::same_as<std::optional<std::vector<std::optional<std::string>>>>;  | 
4155  |  |  | 
4156  |  |   // Function to match regex pattern  | 
4157  |  |   { | 
4158  |  |     T::regex_match(input, std::declval<typename T::regex_type&>())  | 
4159  |  |   } -> std::same_as<bool>;  | 
4160  |  |  | 
4161  |  |   // Copy constructor  | 
4162  |  |   { T(std::declval<const T&>()) } -> std::same_as<T>; | 
4163  |  |  | 
4164  |  |   // Move constructor  | 
4165  |  |   { T(std::declval<T&&>()) } -> std::same_as<T>; | 
4166  |  | };  | 
4167  |  |  | 
4168  |  | #ifdef ADA_USE_UNSAFE_STD_REGEX_PROVIDER  | 
4169  |  | class std_regex_provider final { | 
4170  |  |  public:  | 
4171  |  |   std_regex_provider() = default;  | 
4172  |  |   using regex_type = std::regex;  | 
4173  |  |   static std::optional<regex_type> create_instance(std::string_view pattern,  | 
4174  |  |                                                    bool ignore_case);  | 
4175  |  |   static std::optional<std::vector<std::optional<std::string>>> regex_search(  | 
4176  |  |       std::string_view input, const regex_type& pattern);  | 
4177  |  |   static bool regex_match(std::string_view input, const regex_type& pattern);  | 
4178  |  | };  | 
4179  |  | #endif  // ADA_USE_UNSAFE_STD_REGEX_PROVIDER  | 
4180  |  |  | 
4181  |  | }  // namespace ada::url_pattern_regex  | 
4182  |  | #endif  // ADA_INCLUDE_URL_PATTERN  | 
4183  |  | #endif  // ADA_URL_PATTERN_REGEX_H  | 
4184  |  | /* end file include/ada/url_pattern_regex.h */  | 
4185  |  | /* begin file include/ada/url_pattern_init.h */  | 
4186  |  | /**  | 
4187  |  |  * @file url_pattern_init.h  | 
4188  |  |  * @brief Declaration for the url_pattern_init implementation.  | 
4189  |  |  */  | 
4190  |  | #ifndef ADA_URL_PATTERN_INIT_H  | 
4191  |  | #define ADA_URL_PATTERN_INIT_H  | 
4192  |  |  | 
4193  |  | /* begin file include/ada/errors.h */  | 
4194  |  | /**  | 
4195  |  |  * @file errors.h  | 
4196  |  |  * @brief Definitions for the errors.  | 
4197  |  |  */  | 
4198  |  | #ifndef ADA_ERRORS_H  | 
4199  |  | #define ADA_ERRORS_H  | 
4200  |  |  | 
4201  |  | #include <cstdint>  | 
4202  |  | namespace ada { | 
4203  |  | enum class errors : uint8_t { type_error }; | 
4204  |  | }  // namespace ada  | 
4205  |  | #endif  // ADA_ERRORS_H  | 
4206  |  | /* end file include/ada/errors.h */  | 
4207  |  |  | 
4208  |  | #include <string_view>  | 
4209  |  | #include <string>  | 
4210  |  | #include <optional>  | 
4211  |  | #include <iostream>  | 
4212  |  |  | 
4213  |  | #if ADA_TESTING  | 
4214  |  | #include <iostream>  | 
4215  |  | #endif  // ADA_TESTING  | 
4216  |  |  | 
4217  |  | #if ADA_INCLUDE_URL_PATTERN  | 
4218  |  | namespace ada { | 
4219  |  |  | 
4220  |  | // Important: C++20 allows us to use concept rather than `using` or `typedef  | 
4221  |  | // and allows functions with second argument, which is optional (using either  | 
4222  |  | // std::nullopt or a parameter with default value)  | 
4223  |  | template <typename F>  | 
4224  |  | concept url_pattern_encoding_callback = requires(F f, std::string_view sv) { | 
4225  |  |   { f(sv) } -> std::same_as<tl::expected<std::string, errors>>; | 
4226  |  | };  | 
4227  |  |  | 
4228  |  | // A structure providing matching patterns for individual components  | 
4229  |  | // of a URL. When a URLPattern is created, or when a URLPattern is  | 
4230  |  | // used to match or test against a URL, the input can be given as  | 
4231  |  | // either a string or a URLPatternInit struct. If a string is given,  | 
4232  |  | // it will be parsed to create a URLPatternInit. The URLPatternInit  | 
4233  |  | // API is defined as part of the URLPattern specification.  | 
4234  |  | // All provided strings must be valid UTF-8.  | 
4235  |  | struct url_pattern_init { | 
4236  |  |   enum class process_type : uint8_t { | 
4237  |  |     url,  | 
4238  |  |     pattern,  | 
4239  |  |   };  | 
4240  |  |  | 
4241  | 0  |   friend std::ostream& operator<<(std::ostream& os, process_type type) { | 
4242  | 0  |     switch (type) { | 
4243  | 0  |       case process_type::url:  | 
4244  | 0  |         return os << "url";  | 
4245  | 0  |       case process_type::pattern:  | 
4246  | 0  |         return os << "pattern";  | 
4247  | 0  |       default:  | 
4248  | 0  |         return os << "unknown";  | 
4249  | 0  |     }  | 
4250  | 0  |   }  | 
4251  |  |  | 
4252  |  |   // All strings must be valid UTF-8.  | 
4253  |  |   // @see https://urlpattern.spec.whatwg.org/#process-a-urlpatterninit  | 
4254  |  |   static tl::expected<url_pattern_init, errors> process(  | 
4255  |  |       const url_pattern_init& init, process_type type,  | 
4256  |  |       std::optional<std::string_view> protocol = std::nullopt,  | 
4257  |  |       std::optional<std::string_view> username = std::nullopt,  | 
4258  |  |       std::optional<std::string_view> password = std::nullopt,  | 
4259  |  |       std::optional<std::string_view> hostname = std::nullopt,  | 
4260  |  |       std::optional<std::string_view> port = std::nullopt,  | 
4261  |  |       std::optional<std::string_view> pathname = std::nullopt,  | 
4262  |  |       std::optional<std::string_view> search = std::nullopt,  | 
4263  |  |       std::optional<std::string_view> hash = std::nullopt);  | 
4264  |  |  | 
4265  |  |   // @see https://urlpattern.spec.whatwg.org/#process-protocol-for-init  | 
4266  |  |   static tl::expected<std::string, errors> process_protocol(  | 
4267  |  |       std::string_view value, process_type type);  | 
4268  |  |  | 
4269  |  |   // @see https://urlpattern.spec.whatwg.org/#process-username-for-init  | 
4270  |  |   static tl::expected<std::string, errors> process_username(  | 
4271  |  |       std::string_view value, process_type type);  | 
4272  |  |  | 
4273  |  |   // @see https://urlpattern.spec.whatwg.org/#process-password-for-init  | 
4274  |  |   static tl::expected<std::string, errors> process_password(  | 
4275  |  |       std::string_view value, process_type type);  | 
4276  |  |  | 
4277  |  |   // @see https://urlpattern.spec.whatwg.org/#process-hostname-for-init  | 
4278  |  |   static tl::expected<std::string, errors> process_hostname(  | 
4279  |  |       std::string_view value, process_type type);  | 
4280  |  |  | 
4281  |  |   // @see https://urlpattern.spec.whatwg.org/#process-port-for-init  | 
4282  |  |   static tl::expected<std::string, errors> process_port(  | 
4283  |  |       std::string_view port, std::string_view protocol, process_type type);  | 
4284  |  |  | 
4285  |  |   // @see https://urlpattern.spec.whatwg.org/#process-pathname-for-init  | 
4286  |  |   static tl::expected<std::string, errors> process_pathname(  | 
4287  |  |       std::string_view value, std::string_view protocol, process_type type);  | 
4288  |  |  | 
4289  |  |   // @see https://urlpattern.spec.whatwg.org/#process-search-for-init  | 
4290  |  |   static tl::expected<std::string, errors> process_search(  | 
4291  |  |       std::string_view value, process_type type);  | 
4292  |  |  | 
4293  |  |   // @see https://urlpattern.spec.whatwg.org/#process-hash-for-init  | 
4294  |  |   static tl::expected<std::string, errors> process_hash(std::string_view value,  | 
4295  |  |                                                         process_type type);  | 
4296  |  |  | 
4297  |  | #if ADA_TESTING  | 
4298  |  |   friend void PrintTo(const url_pattern_init& init, std::ostream* os) { | 
4299  |  |     *os << "protocol: '" << init.protocol.value_or("undefined") << "', "; | 
4300  |  |     *os << "username: '" << init.username.value_or("undefined") << "', "; | 
4301  |  |     *os << "password: '" << init.password.value_or("undefined") << "', "; | 
4302  |  |     *os << "hostname: '" << init.hostname.value_or("undefined") << "', "; | 
4303  |  |     *os << "port: '" << init.port.value_or("undefined") << "', "; | 
4304  |  |     *os << "pathname: '" << init.pathname.value_or("undefined") << "', "; | 
4305  |  |     *os << "search: '" << init.search.value_or("undefined") << "', "; | 
4306  |  |     *os << "hash: '" << init.hash.value_or("undefined") << "', "; | 
4307  |  |     *os << "base_url: '" << init.base_url.value_or("undefined") << "', "; | 
4308  |  |   }  | 
4309  |  | #endif  // ADA_TESTING  | 
4310  |  |  | 
4311  |  |   bool operator==(const url_pattern_init&) const;  | 
4312  |  |   // If present, must be valid UTF-8.  | 
4313  |  |   std::optional<std::string> protocol{}; | 
4314  |  |   // If present, must be valid UTF-8.  | 
4315  |  |   std::optional<std::string> username{}; | 
4316  |  |   // If present, must be valid UTF-8.  | 
4317  |  |   std::optional<std::string> password{}; | 
4318  |  |   // If present, must be valid UTF-8.  | 
4319  |  |   std::optional<std::string> hostname{}; | 
4320  |  |   // If present, must be valid UTF-8.  | 
4321  |  |   std::optional<std::string> port{}; | 
4322  |  |   // If present, must be valid UTF-8.  | 
4323  |  |   std::optional<std::string> pathname{}; | 
4324  |  |   // If present, must be valid UTF-8.  | 
4325  |  |   std::optional<std::string> search{}; | 
4326  |  |   // If present, must be valid UTF-8.  | 
4327  |  |   std::optional<std::string> hash{}; | 
4328  |  |   // If present, must be valid UTF-8.  | 
4329  |  |   std::optional<std::string> base_url{}; | 
4330  |  | };  | 
4331  |  | }  // namespace ada  | 
4332  |  | #endif  // ADA_INCLUDE_URL_PATTERN  | 
4333  |  | #endif  // ADA_URL_PATTERN_INIT_H  | 
4334  |  | /* end file include/ada/url_pattern_init.h */  | 
4335  |  |  | 
4336  |  | /**  | 
4337  |  |  * @private  | 
4338  |  |  */  | 
4339  |  | namespace ada { | 
4340  |  | struct url_aggregator;  | 
4341  |  | struct url;  | 
4342  |  | #if ADA_INCLUDE_URL_PATTERN  | 
4343  |  | template <url_pattern_regex::regex_concept regex_provider>  | 
4344  |  | class url_pattern;  | 
4345  |  | struct url_pattern_options;  | 
4346  |  | #endif  // ADA_INCLUDE_URL_PATTERN  | 
4347  |  | enum class errors : uint8_t;  | 
4348  |  | }  // namespace ada  | 
4349  |  |  | 
4350  |  | /**  | 
4351  |  |  * @namespace ada::parser  | 
4352  |  |  * @brief Includes the definitions for supported parsers  | 
4353  |  |  */  | 
4354  |  | namespace ada::parser { | 
4355  |  | /**  | 
4356  |  |  * Parses a url. The parameter user_input is the input to be parsed:  | 
4357  |  |  * it should be a valid UTF-8 string. The parameter base_url is an optional  | 
4358  |  |  * parameter that can be used to resolve relative URLs. If the base_url is  | 
4359  |  |  * provided, the user_input is resolved against the base_url.  | 
4360  |  |  */  | 
4361  |  | template <typename result_type = url_aggregator>  | 
4362  |  | result_type parse_url(std::string_view user_input,  | 
4363  |  |                       const result_type* base_url = nullptr);  | 
4364  |  |  | 
4365  |  | extern template url_aggregator parse_url<url_aggregator>(  | 
4366  |  |     std::string_view user_input, const url_aggregator* base_url);  | 
4367  |  | extern template url parse_url<url>(std::string_view user_input,  | 
4368  |  |                                    const url* base_url);  | 
4369  |  |  | 
4370  |  | template <typename result_type = url_aggregator, bool store_values = true>  | 
4371  |  | result_type parse_url_impl(std::string_view user_input,  | 
4372  |  |                            const result_type* base_url = nullptr);  | 
4373  |  |  | 
4374  |  | extern template url_aggregator parse_url_impl<url_aggregator>(  | 
4375  |  |     std::string_view user_input, const url_aggregator* base_url);  | 
4376  |  | extern template url parse_url_impl<url>(std::string_view user_input,  | 
4377  |  |                                         const url* base_url);  | 
4378  |  |  | 
4379  |  | #if ADA_INCLUDE_URL_PATTERN  | 
4380  |  | template <url_pattern_regex::regex_concept regex_provider>  | 
4381  |  | tl::expected<url_pattern<regex_provider>, errors> parse_url_pattern_impl(  | 
4382  |  |     std::variant<std::string_view, url_pattern_init>&& input,  | 
4383  |  |     const std::string_view* base_url, const url_pattern_options* options);  | 
4384  |  | #endif  // ADA_INCLUDE_URL_PATTERN  | 
4385  |  |  | 
4386  |  | }  // namespace ada::parser  | 
4387  |  |  | 
4388  |  | #endif  // ADA_PARSER_H  | 
4389  |  | /* end file include/ada/parser.h */  | 
4390  |  | /* begin file include/ada/parser-inl.h */  | 
4391  |  | /**  | 
4392  |  |  * @file parser-inl.h  | 
4393  |  |  */  | 
4394  |  | #ifndef ADA_PARSER_INL_H  | 
4395  |  | #define ADA_PARSER_INL_H  | 
4396  |  |  | 
4397  |  | /* begin file include/ada/url_pattern.h */  | 
4398  |  | /**  | 
4399  |  |  * @file url_pattern.h  | 
4400  |  |  * @brief Declaration for the URLPattern implementation.  | 
4401  |  |  */  | 
4402  |  | #ifndef ADA_URL_PATTERN_H  | 
4403  |  | #define ADA_URL_PATTERN_H  | 
4404  |  |  | 
4405  |  | /* begin file include/ada/implementation.h */  | 
4406  |  | /**  | 
4407  |  |  * @file implementation.h  | 
4408  |  |  * @brief Definitions for user facing functions for parsing URL and it's  | 
4409  |  |  * components.  | 
4410  |  |  */  | 
4411  |  | #ifndef ADA_IMPLEMENTATION_H  | 
4412  |  | #define ADA_IMPLEMENTATION_H  | 
4413  |  |  | 
4414  |  | #include <string>  | 
4415  |  | #include <string_view>  | 
4416  |  | #include <optional>  | 
4417  |  |  | 
4418  |  | /* begin file include/ada/url.h */  | 
4419  |  | /**  | 
4420  |  |  * @file url.h  | 
4421  |  |  * @brief Declaration for the URL  | 
4422  |  |  */  | 
4423  |  | #ifndef ADA_URL_H  | 
4424  |  | #define ADA_URL_H  | 
4425  |  |  | 
4426  |  | #include <algorithm>  | 
4427  |  | #include <optional>  | 
4428  |  | #include <ostream>  | 
4429  |  | #include <string>  | 
4430  |  | #include <string_view>  | 
4431  |  |  | 
4432  |  | /* begin file include/ada/checkers.h */  | 
4433  |  | /**  | 
4434  |  |  * @file checkers.h  | 
4435  |  |  * @brief Declarations for URL specific checkers used within Ada.  | 
4436  |  |  */  | 
4437  |  | #ifndef ADA_CHECKERS_H  | 
4438  |  | #define ADA_CHECKERS_H  | 
4439  |  |  | 
4440  |  |  | 
4441  |  | #include <cstring>  | 
4442  |  | #include <string_view>  | 
4443  |  |  | 
4444  |  | /**  | 
4445  |  |  * These functions are not part of our public API and may  | 
4446  |  |  * change at any time.  | 
4447  |  |  * @private  | 
4448  |  |  * @namespace ada::checkers  | 
4449  |  |  * @brief Includes the definitions for validation functions  | 
4450  |  |  */  | 
4451  |  | namespace ada::checkers { | 
4452  |  |  | 
4453  |  | /**  | 
4454  |  |  * @private  | 
4455  |  |  * Assuming that x is an ASCII letter, this function returns the lower case  | 
4456  |  |  * equivalent.  | 
4457  |  |  * @details More likely to be inlined by the compiler and constexpr.  | 
4458  |  |  */  | 
4459  |  | constexpr char to_lower(char x) noexcept;  | 
4460  |  |  | 
4461  |  | /**  | 
4462  |  |  * @private  | 
4463  |  |  * Returns true if the character is an ASCII letter. Equivalent to std::isalpha  | 
4464  |  |  * but more likely to be inlined by the compiler.  | 
4465  |  |  *  | 
4466  |  |  * @attention std::isalpha is not constexpr generally.  | 
4467  |  |  */  | 
4468  |  | constexpr bool is_alpha(char x) noexcept;  | 
4469  |  |  | 
4470  |  | /**  | 
4471  |  |  * @private  | 
4472  |  |  * Check whether a string starts with 0x or 0X. The function is only  | 
4473  |  |  * safe if input.size() >=2.  | 
4474  |  |  *  | 
4475  |  |  * @see has_hex_prefix  | 
4476  |  |  */  | 
4477  |  | constexpr bool has_hex_prefix_unsafe(std::string_view input);  | 
4478  |  | /**  | 
4479  |  |  * @private  | 
4480  |  |  * Check whether a string starts with 0x or 0X.  | 
4481  |  |  */  | 
4482  |  | constexpr bool has_hex_prefix(std::string_view input);  | 
4483  |  |  | 
4484  |  | /**  | 
4485  |  |  * @private  | 
4486  |  |  * Check whether x is an ASCII digit. More likely to be inlined than  | 
4487  |  |  * std::isdigit.  | 
4488  |  |  */  | 
4489  |  | constexpr bool is_digit(char x) noexcept;  | 
4490  |  |  | 
4491  |  | /**  | 
4492  |  |  * @private  | 
4493  |  |  * @details A string starts with a Windows drive letter if all of the following  | 
4494  |  |  * are true:  | 
4495  |  |  *  | 
4496  |  |  *   - its length is greater than or equal to 2  | 
4497  |  |  *   - its first two code points are a Windows drive letter  | 
4498  |  |  *   - its length is 2 or its third code point is U+002F (/), U+005C (\), U+003F  | 
4499  |  |  * (?), or U+0023 (#).  | 
4500  |  |  *  | 
4501  |  |  * https://url.spec.whatwg.org/#start-with-a-windows-drive-letter  | 
4502  |  |  */  | 
4503  |  | inline constexpr bool is_windows_drive_letter(std::string_view input) noexcept;  | 
4504  |  |  | 
4505  |  | /**  | 
4506  |  |  * @private  | 
4507  |  |  * @details A normalized Windows drive letter is a Windows drive letter of which  | 
4508  |  |  * the second code point is U+003A (:).  | 
4509  |  |  */  | 
4510  |  | inline constexpr bool is_normalized_windows_drive_letter(  | 
4511  |  |     std::string_view input) noexcept;  | 
4512  |  |  | 
4513  |  | /**  | 
4514  |  |  * @private  | 
4515  |  |  * Returns true if an input is an ipv4 address. It is assumed that the string  | 
4516  |  |  * does not contain uppercase ASCII characters (the input should have been  | 
4517  |  |  * lowered cased before calling this function) and is not empty.  | 
4518  |  |  */  | 
4519  |  | ada_really_inline constexpr bool is_ipv4(std::string_view view) noexcept;  | 
4520  |  |  | 
4521  |  | /**  | 
4522  |  |  * @private  | 
4523  |  |  * Returns a bitset. If the first bit is set, then at least one character needs  | 
4524  |  |  * percent encoding. If the second bit is set, a \\ is found. If the third bit  | 
4525  |  |  * is set then we have a dot. If the fourth bit is set, then we have a percent  | 
4526  |  |  * character.  | 
4527  |  |  */  | 
4528  |  | ada_really_inline constexpr uint8_t path_signature(  | 
4529  |  |     std::string_view input) noexcept;  | 
4530  |  |  | 
4531  |  | /**  | 
4532  |  |  * @private  | 
4533  |  |  * Returns true if the length of the domain name and its labels are according to  | 
4534  |  |  * the specifications. The length of the domain must be 255 octets (253  | 
4535  |  |  * characters not including the last 2 which are the empty label reserved at the  | 
4536  |  |  * end). When the empty label is included (a dot at the end), the domain name  | 
4537  |  |  * can have 254 characters. The length of a label must be at least 1 and at most  | 
4538  |  |  * 63 characters.  | 
4539  |  |  * @see section 3.1. of https://www.rfc-editor.org/rfc/rfc1034  | 
4540  |  |  * @see https://www.unicode.org/reports/tr46/#ToASCII  | 
4541  |  |  */  | 
4542  |  | ada_really_inline constexpr bool verify_dns_length(  | 
4543  |  |     std::string_view input) noexcept;  | 
4544  |  |  | 
4545  |  | }  // namespace ada::checkers  | 
4546  |  |  | 
4547  |  | #endif  // ADA_CHECKERS_H  | 
4548  |  | /* end file include/ada/checkers.h */  | 
4549  |  | /* begin file include/ada/url_components.h */  | 
4550  |  | /**  | 
4551  |  |  * @file url_components.h  | 
4552  |  |  * @brief Declaration for the URL Components  | 
4553  |  |  */  | 
4554  |  | #ifndef ADA_URL_COMPONENTS_H  | 
4555  |  | #define ADA_URL_COMPONENTS_H  | 
4556  |  |  | 
4557  |  | namespace ada { | 
4558  |  |  | 
4559  |  | /**  | 
4560  |  |  * @brief URL Component representations using offsets.  | 
4561  |  |  *  | 
4562  |  |  * @details We design the url_components struct so that it is as small  | 
4563  |  |  * and simple as possible. This version uses 32 bytes.  | 
4564  |  |  *  | 
4565  |  |  * This struct is used to extract components from a single 'href'.  | 
4566  |  |  */  | 
4567  |  | struct url_components { | 
4568  |  |   constexpr static uint32_t omitted = uint32_t(-1);  | 
4569  |  |  | 
4570  | 0  |   url_components() = default;  | 
4571  |  |   url_components(const url_components &u) = default;  | 
4572  |  |   url_components(url_components &&u) noexcept = default;  | 
4573  |  |   url_components &operator=(url_components &&u) noexcept = default;  | 
4574  |  |   url_components &operator=(const url_components &u) = default;  | 
4575  |  |   ~url_components() = default;  | 
4576  |  |  | 
4577  |  |   /*  | 
4578  |  |    * By using 32-bit integers, we implicitly assume that the URL string  | 
4579  |  |    * cannot exceed 4 GB.  | 
4580  |  |    *  | 
4581  |  |    * https://user:pass@example.com:1234/foo/bar?baz#quux  | 
4582  |  |    *       |     |    |          | ^^^^|       |   |  | 
4583  |  |    *       |     |    |          | |   |       |   `----- hash_start  | 
4584  |  |    *       |     |    |          | |   |       `--------- search_start  | 
4585  |  |    *       |     |    |          | |   `----------------- pathname_start  | 
4586  |  |    *       |     |    |          | `--------------------- port  | 
4587  |  |    *       |     |    |          `----------------------- host_end  | 
4588  |  |    *       |     |    `---------------------------------- host_start  | 
4589  |  |    *       |     `--------------------------------------- username_end  | 
4590  |  |    *       `--------------------------------------------- protocol_end  | 
4591  |  |    */  | 
4592  |  |   uint32_t protocol_end{0}; | 
4593  |  |   /**  | 
4594  |  |    * Username end is not `omitted` by default to make username and password  | 
4595  |  |    * getters less costly to implement.  | 
4596  |  |    */  | 
4597  |  |   uint32_t username_end{0}; | 
4598  |  |   uint32_t host_start{0}; | 
4599  |  |   uint32_t host_end{0}; | 
4600  |  |   uint32_t port{omitted}; | 
4601  |  |   uint32_t pathname_start{0}; | 
4602  |  |   uint32_t search_start{omitted}; | 
4603  |  |   uint32_t hash_start{omitted}; | 
4604  |  |  | 
4605  |  |   /**  | 
4606  |  |    * Check the following conditions:  | 
4607  |  |    * protocol_end < username_end < ... < hash_start,  | 
4608  |  |    * expect when a value is omitted. It also computes  | 
4609  |  |    * a lower bound on  the possible string length that may match these  | 
4610  |  |    * offsets.  | 
4611  |  |    * @return true if the offset values are  | 
4612  |  |    *  consistent with a possible URL string  | 
4613  |  |    */  | 
4614  |  |   [[nodiscard]] constexpr bool check_offset_consistency() const noexcept;  | 
4615  |  |  | 
4616  |  |   /**  | 
4617  |  |    * Converts a url_components to JSON stringified version.  | 
4618  |  |    */  | 
4619  |  |   [[nodiscard]] std::string to_string() const;  | 
4620  |  |  | 
4621  |  | };  // struct url_components  | 
4622  |  | }  // namespace ada  | 
4623  |  | #endif  | 
4624  |  | /* end file include/ada/url_components.h */  | 
4625  |  |  | 
4626  |  | namespace ada { | 
4627  |  |  | 
4628  |  | struct url_aggregator;  | 
4629  |  |  | 
4630  |  | // namespace parser { | 
4631  |  | // template <typename result_type>  | 
4632  |  | // result_type parse_url(std::string_view user_input,  | 
4633  |  | //                       const result_type* base_url = nullptr);  | 
4634  |  | // template <typename result_type, bool store_values>  | 
4635  |  | // result_type parse_url_impl(std::string_view user_input,  | 
4636  |  | //                            const result_type* base_url = nullptr);  | 
4637  |  | // }  | 
4638  |  |  | 
4639  |  | /**  | 
4640  |  |  * @brief Generic URL struct reliant on std::string instantiation.  | 
4641  |  |  *  | 
4642  |  |  * @details To disambiguate from a valid URL string it can also be referred to  | 
4643  |  |  * as a URL record. A URL is a struct that represents a universal identifier.  | 
4644  |  |  * Unlike the url_aggregator, the ada::url represents the different components  | 
4645  |  |  * of a parsed URL as independent std::string instances. This makes the  | 
4646  |  |  * structure heavier and more reliant on memory allocations. When getting  | 
4647  |  |  * components from the parsed URL, a new std::string is typically constructed.  | 
4648  |  |  *  | 
4649  |  |  * @see https://url.spec.whatwg.org/#url-representation  | 
4650  |  |  */  | 
4651  |  | struct url : url_base { | 
4652  |  |   url() = default;  | 
4653  |  |   url(const url &u) = default;  | 
4654  |  |   url(url &&u) noexcept = default;  | 
4655  |  |   url &operator=(url &&u) noexcept = default;  | 
4656  |  |   url &operator=(const url &u) = default;  | 
4657  | 0  |   ~url() override = default;  | 
4658  |  |  | 
4659  |  |   /**  | 
4660  |  |    * @private  | 
4661  |  |    * A URL's username is an ASCII string identifying a username. It is initially  | 
4662  |  |    * the empty string.  | 
4663  |  |    */  | 
4664  |  |   std::string username{}; | 
4665  |  |  | 
4666  |  |   /**  | 
4667  |  |    * @private  | 
4668  |  |    * A URL's password is an ASCII string identifying a password. It is initially  | 
4669  |  |    * the empty string.  | 
4670  |  |    */  | 
4671  |  |   std::string password{}; | 
4672  |  |  | 
4673  |  |   /**  | 
4674  |  |    * @private  | 
4675  |  |    * A URL's host is null or a host. It is initially null.  | 
4676  |  |    */  | 
4677  |  |   std::optional<std::string> host{}; | 
4678  |  |  | 
4679  |  |   /**  | 
4680  |  |    * @private  | 
4681  |  |    * A URL's port is either null or a 16-bit unsigned integer that identifies a  | 
4682  |  |    * networking port. It is initially null.  | 
4683  |  |    */  | 
4684  |  |   std::optional<uint16_t> port{}; | 
4685  |  |  | 
4686  |  |   /**  | 
4687  |  |    * @private  | 
4688  |  |    * A URL's path is either an ASCII string or a list of zero or more ASCII  | 
4689  |  |    * strings, usually identifying a location.  | 
4690  |  |    */  | 
4691  |  |   std::string path{}; | 
4692  |  |  | 
4693  |  |   /**  | 
4694  |  |    * @private  | 
4695  |  |    * A URL's query is either null or an ASCII string. It is initially null.  | 
4696  |  |    */  | 
4697  |  |   std::optional<std::string> query{}; | 
4698  |  |  | 
4699  |  |   /**  | 
4700  |  |    * @private  | 
4701  |  |    * A URL's fragment is either null or an ASCII string that can be used for  | 
4702  |  |    * further processing on the resource the URL's other components identify. It  | 
4703  |  |    * is initially null.  | 
4704  |  |    */  | 
4705  |  |   std::optional<std::string> hash{}; | 
4706  |  |  | 
4707  |  |   /** @return true if it has an host but it is the empty string */  | 
4708  |  |   [[nodiscard]] inline bool has_empty_hostname() const noexcept;  | 
4709  |  |   /** @return true if the URL has a (non default) port */  | 
4710  |  |   [[nodiscard]] inline bool has_port() const noexcept;  | 
4711  |  |   /** @return true if it has a host (included an empty host) */  | 
4712  |  |   [[nodiscard]] inline bool has_hostname() const noexcept;  | 
4713  |  |   [[nodiscard]] bool has_valid_domain() const noexcept override;  | 
4714  |  |  | 
4715  |  |   /**  | 
4716  |  |    * Returns a JSON string representation of this URL.  | 
4717  |  |    */  | 
4718  |  |   [[nodiscard]] std::string to_string() const override;  | 
4719  |  |  | 
4720  |  |   /**  | 
4721  |  |    * @see https://url.spec.whatwg.org/#dom-url-href  | 
4722  |  |    * @see https://url.spec.whatwg.org/#concept-url-serializer  | 
4723  |  |    */  | 
4724  |  |   [[nodiscard]] ada_really_inline std::string get_href() const noexcept;  | 
4725  |  |  | 
4726  |  |   /**  | 
4727  |  |    * The origin getter steps are to return the serialization of this's URL's  | 
4728  |  |    * origin. [HTML]  | 
4729  |  |    * @return a newly allocated string.  | 
4730  |  |    * @see https://url.spec.whatwg.org/#concept-url-origin  | 
4731  |  |    */  | 
4732  |  |   [[nodiscard]] std::string get_origin() const noexcept override;  | 
4733  |  |  | 
4734  |  |   /**  | 
4735  |  |    * The protocol getter steps are to return this's URL's scheme, followed by  | 
4736  |  |    * U+003A (:).  | 
4737  |  |    * @return a newly allocated string.  | 
4738  |  |    * @see https://url.spec.whatwg.org/#dom-url-protocol  | 
4739  |  |    */  | 
4740  |  |   [[nodiscard]] std::string get_protocol() const noexcept;  | 
4741  |  |  | 
4742  |  |   /**  | 
4743  |  |    * Return url's host, serialized, followed by U+003A (:) and url's port,  | 
4744  |  |    * serialized.  | 
4745  |  |    * When there is no host, this function returns the empty string.  | 
4746  |  |    * @return a newly allocated string.  | 
4747  |  |    * @see https://url.spec.whatwg.org/#dom-url-host  | 
4748  |  |    */  | 
4749  |  |   [[nodiscard]] std::string get_host() const noexcept;  | 
4750  |  |  | 
4751  |  |   /**  | 
4752  |  |    * Return this's URL's host, serialized.  | 
4753  |  |    * When there is no host, this function returns the empty string.  | 
4754  |  |    * @return a newly allocated string.  | 
4755  |  |    * @see https://url.spec.whatwg.org/#dom-url-hostname  | 
4756  |  |    */  | 
4757  |  |   [[nodiscard]] std::string get_hostname() const noexcept;  | 
4758  |  |  | 
4759  |  |   /**  | 
4760  |  |    * The pathname getter steps are to return the result of URL path serializing  | 
4761  |  |    * this's URL.  | 
4762  |  |    * @return a newly allocated string.  | 
4763  |  |    * @see https://url.spec.whatwg.org/#dom-url-pathname  | 
4764  |  |    */  | 
4765  |  |   [[nodiscard]] constexpr std::string_view get_pathname() const noexcept;  | 
4766  |  |  | 
4767  |  |   /**  | 
4768  |  |    * Compute the pathname length in bytes without instantiating a view or a  | 
4769  |  |    * string.  | 
4770  |  |    * @return size of the pathname in bytes  | 
4771  |  |    * @see https://url.spec.whatwg.org/#dom-url-pathname  | 
4772  |  |    */  | 
4773  |  |   [[nodiscard]] ada_really_inline size_t get_pathname_length() const noexcept;  | 
4774  |  |  | 
4775  |  |   /**  | 
4776  |  |    * Return U+003F (?), followed by this's URL's query.  | 
4777  |  |    * @return a newly allocated string.  | 
4778  |  |    * @see https://url.spec.whatwg.org/#dom-url-search  | 
4779  |  |    */  | 
4780  |  |   [[nodiscard]] std::string get_search() const noexcept;  | 
4781  |  |  | 
4782  |  |   /**  | 
4783  |  |    * The username getter steps are to return this's URL's username.  | 
4784  |  |    * @return a constant reference to the underlying string.  | 
4785  |  |    * @see https://url.spec.whatwg.org/#dom-url-username  | 
4786  |  |    */  | 
4787  |  |   [[nodiscard]] const std::string &get_username() const noexcept;  | 
4788  |  |  | 
4789  |  |   /**  | 
4790  |  |    * @return Returns true on successful operation.  | 
4791  |  |    * @see https://url.spec.whatwg.org/#dom-url-username  | 
4792  |  |    */  | 
4793  |  |   bool set_username(std::string_view input);  | 
4794  |  |  | 
4795  |  |   /**  | 
4796  |  |    * @return Returns true on success.  | 
4797  |  |    * @see https://url.spec.whatwg.org/#dom-url-password  | 
4798  |  |    */  | 
4799  |  |   bool set_password(std::string_view input);  | 
4800  |  |  | 
4801  |  |   /**  | 
4802  |  |    * @return Returns true on success.  | 
4803  |  |    * @see https://url.spec.whatwg.org/#dom-url-port  | 
4804  |  |    */  | 
4805  |  |   bool set_port(std::string_view input);  | 
4806  |  |  | 
4807  |  |   /**  | 
4808  |  |    * This function always succeeds.  | 
4809  |  |    * @see https://url.spec.whatwg.org/#dom-url-hash  | 
4810  |  |    */  | 
4811  |  |   void set_hash(std::string_view input);  | 
4812  |  |  | 
4813  |  |   /**  | 
4814  |  |    * This function always succeeds.  | 
4815  |  |    * @see https://url.spec.whatwg.org/#dom-url-search  | 
4816  |  |    */  | 
4817  |  |   void set_search(std::string_view input);  | 
4818  |  |  | 
4819  |  |   /**  | 
4820  |  |    * @return Returns true on success.  | 
4821  |  |    * @see https://url.spec.whatwg.org/#dom-url-search  | 
4822  |  |    */  | 
4823  |  |   bool set_pathname(std::string_view input);  | 
4824  |  |  | 
4825  |  |   /**  | 
4826  |  |    * @return Returns true on success.  | 
4827  |  |    * @see https://url.spec.whatwg.org/#dom-url-host  | 
4828  |  |    */  | 
4829  |  |   bool set_host(std::string_view input);  | 
4830  |  |  | 
4831  |  |   /**  | 
4832  |  |    * @return Returns true on success.  | 
4833  |  |    * @see https://url.spec.whatwg.org/#dom-url-hostname  | 
4834  |  |    */  | 
4835  |  |   bool set_hostname(std::string_view input);  | 
4836  |  |  | 
4837  |  |   /**  | 
4838  |  |    * @return Returns true on success.  | 
4839  |  |    * @see https://url.spec.whatwg.org/#dom-url-protocol  | 
4840  |  |    */  | 
4841  |  |   bool set_protocol(std::string_view input);  | 
4842  |  |  | 
4843  |  |   /**  | 
4844  |  |    * @see https://url.spec.whatwg.org/#dom-url-href  | 
4845  |  |    */  | 
4846  |  |   bool set_href(std::string_view input);  | 
4847  |  |  | 
4848  |  |   /**  | 
4849  |  |    * The password getter steps are to return this's URL's password.  | 
4850  |  |    * @return a constant reference to the underlying string.  | 
4851  |  |    * @see https://url.spec.whatwg.org/#dom-url-password  | 
4852  |  |    */  | 
4853  |  |   [[nodiscard]] const std::string &get_password() const noexcept;  | 
4854  |  |  | 
4855  |  |   /**  | 
4856  |  |    * Return this's URL's port, serialized.  | 
4857  |  |    * @return a newly constructed string representing the port.  | 
4858  |  |    * @see https://url.spec.whatwg.org/#dom-url-port  | 
4859  |  |    */  | 
4860  |  |   [[nodiscard]] std::string get_port() const noexcept;  | 
4861  |  |  | 
4862  |  |   /**  | 
4863  |  |    * Return U+0023 (#), followed by this's URL's fragment.  | 
4864  |  |    * @return a newly constructed string representing the hash.  | 
4865  |  |    * @see https://url.spec.whatwg.org/#dom-url-hash  | 
4866  |  |    */  | 
4867  |  |   [[nodiscard]] std::string get_hash() const noexcept;  | 
4868  |  |  | 
4869  |  |   /**  | 
4870  |  |    * A URL includes credentials if its username or password is not the empty  | 
4871  |  |    * string.  | 
4872  |  |    */  | 
4873  |  |   [[nodiscard]] ada_really_inline bool has_credentials() const noexcept;  | 
4874  |  |  | 
4875  |  |   /**  | 
4876  |  |    * Useful for implementing efficient serialization for the URL.  | 
4877  |  |    *  | 
4878  |  |    * https://user:pass@example.com:1234/foo/bar?baz#quux  | 
4879  |  |    *       |     |    |          | ^^^^|       |   |  | 
4880  |  |    *       |     |    |          | |   |       |   `----- hash_start  | 
4881  |  |    *       |     |    |          | |   |       `--------- search_start  | 
4882  |  |    *       |     |    |          | |   `----------------- pathname_start  | 
4883  |  |    *       |     |    |          | `--------------------- port  | 
4884  |  |    *       |     |    |          `----------------------- host_end  | 
4885  |  |    *       |     |    `---------------------------------- host_start  | 
4886  |  |    *       |     `--------------------------------------- username_end  | 
4887  |  |    *       `--------------------------------------------- protocol_end  | 
4888  |  |    *  | 
4889  |  |    * Inspired after servo/url  | 
4890  |  |    *  | 
4891  |  |    * @return a newly constructed component.  | 
4892  |  |    *  | 
4893  |  |    * @see  | 
4894  |  |    * https://github.com/servo/rust-url/blob/b65a45515c10713f6d212e6726719a020203cc98/url/src/quirks.rs#L31  | 
4895  |  |    */  | 
4896  |  |   [[nodiscard]] ada_really_inline ada::url_components get_components()  | 
4897  |  |       const noexcept;  | 
4898  |  |   /** @return true if the URL has a hash component */  | 
4899  |  |   [[nodiscard]] constexpr bool has_hash() const noexcept override;  | 
4900  |  |   /** @return true if the URL has a search component */  | 
4901  |  |   [[nodiscard]] constexpr bool has_search() const noexcept override;  | 
4902  |  |  | 
4903  |  |  private:  | 
4904  |  |   friend ada::url ada::parser::parse_url<ada::url>(std::string_view,  | 
4905  |  |                                                    const ada::url *);  | 
4906  |  |   friend ada::url_aggregator ada::parser::parse_url<ada::url_aggregator>(  | 
4907  |  |       std::string_view, const ada::url_aggregator *);  | 
4908  |  |   friend void ada::helpers::strip_trailing_spaces_from_opaque_path<ada::url>(  | 
4909  |  |       ada::url &url) noexcept;  | 
4910  |  |  | 
4911  |  |   friend ada::url ada::parser::parse_url_impl<ada::url, true>(std::string_view,  | 
4912  |  |                                                               const ada::url *);  | 
4913  |  |   friend ada::url_aggregator ada::parser::parse_url_impl<  | 
4914  |  |       ada::url_aggregator, true>(std::string_view, const ada::url_aggregator *);  | 
4915  |  |  | 
4916  |  |   inline void update_unencoded_base_hash(std::string_view input);  | 
4917  |  |   inline void update_base_hostname(std::string_view input);  | 
4918  |  |   inline void update_base_search(std::string_view input,  | 
4919  |  |                                  const uint8_t query_percent_encode_set[]);  | 
4920  |  |   inline void update_base_search(std::optional<std::string> &&input);  | 
4921  |  |   inline void update_base_pathname(std::string_view input);  | 
4922  |  |   inline void update_base_username(std::string_view input);  | 
4923  |  |   inline void update_base_password(std::string_view input);  | 
4924  |  |   inline void update_base_port(std::optional<uint16_t> input);  | 
4925  |  |  | 
4926  |  |   /**  | 
4927  |  |    * Sets the host or hostname according to override condition.  | 
4928  |  |    * Return true on success.  | 
4929  |  |    * @see https://url.spec.whatwg.org/#hostname-state  | 
4930  |  |    */  | 
4931  |  |   template <bool override_hostname = false>  | 
4932  |  |   bool set_host_or_hostname(std::string_view input);  | 
4933  |  |  | 
4934  |  |   /**  | 
4935  |  |    * Return true on success.  | 
4936  |  |    * @see https://url.spec.whatwg.org/#concept-ipv4-parser  | 
4937  |  |    */  | 
4938  |  |   [[nodiscard]] bool parse_ipv4(std::string_view input);  | 
4939  |  |  | 
4940  |  |   /**  | 
4941  |  |    * Return true on success.  | 
4942  |  |    * @see https://url.spec.whatwg.org/#concept-ipv6-parser  | 
4943  |  |    */  | 
4944  |  |   [[nodiscard]] bool parse_ipv6(std::string_view input);  | 
4945  |  |  | 
4946  |  |   /**  | 
4947  |  |    * Return true on success.  | 
4948  |  |    * @see https://url.spec.whatwg.org/#concept-opaque-host-parser  | 
4949  |  |    */  | 
4950  |  |   [[nodiscard]] bool parse_opaque_host(std::string_view input);  | 
4951  |  |  | 
4952  |  |   /**  | 
4953  |  |    * A URL's scheme is an ASCII string that identifies the type of URL and can  | 
4954  |  |    * be used to dispatch a URL for further processing after parsing. It is  | 
4955  |  |    * initially the empty string. We only set non_special_scheme when the scheme  | 
4956  |  |    * is non-special, otherwise we avoid constructing string.  | 
4957  |  |    *  | 
4958  |  |    * Special schemes are stored in ada::scheme::details::is_special_list so we  | 
4959  |  |    * typically do not need to store them in each url instance.  | 
4960  |  |    */  | 
4961  |  |   std::string non_special_scheme{}; | 
4962  |  |  | 
4963  |  |   /**  | 
4964  |  |    * A URL cannot have a username/password/port if its host is null or the empty  | 
4965  |  |    * string, or its scheme is "file".  | 
4966  |  |    */  | 
4967  |  |   [[nodiscard]] inline bool cannot_have_credentials_or_port() const;  | 
4968  |  |  | 
4969  |  |   ada_really_inline size_t parse_port(  | 
4970  |  |       std::string_view view, bool check_trailing_content) noexcept override;  | 
4971  |  |  | 
4972  | 0  |   ada_really_inline size_t parse_port(std::string_view view) noexcept override { | 
4973  | 0  |     return this->parse_port(view, false);  | 
4974  | 0  |   }  | 
4975  |  |  | 
4976  |  |   /**  | 
4977  |  |    * Parse the host from the provided input. We assume that  | 
4978  |  |    * the input does not contain spaces or tabs. Control  | 
4979  |  |    * characters and spaces are not trimmed (they should have  | 
4980  |  |    * been removed if needed).  | 
4981  |  |    * Return true on success.  | 
4982  |  |    * @see https://url.spec.whatwg.org/#host-parsing  | 
4983  |  |    */  | 
4984  |  |   [[nodiscard]] ada_really_inline bool parse_host(std::string_view input);  | 
4985  |  |  | 
4986  |  |   template <bool has_state_override = false>  | 
4987  |  |   [[nodiscard]] ada_really_inline bool parse_scheme(std::string_view input);  | 
4988  |  |  | 
4989  |  |   constexpr void clear_pathname() override;  | 
4990  |  |   constexpr void clear_search() override;  | 
4991  |  |   constexpr void set_protocol_as_file();  | 
4992  |  |  | 
4993  |  |   /**  | 
4994  |  |    * Parse the path from the provided input.  | 
4995  |  |    * Return true on success. Control characters not  | 
4996  |  |    * trimmed from the ends (they should have  | 
4997  |  |    * been removed if needed).  | 
4998  |  |    *  | 
4999  |  |    * The input is expected to be UTF-8.  | 
5000  |  |    *  | 
5001  |  |    * @see https://url.spec.whatwg.org/  | 
5002  |  |    */  | 
5003  |  |   ada_really_inline void parse_path(std::string_view input);  | 
5004  |  |  | 
5005  |  |   /**  | 
5006  |  |    * Set the scheme for this URL. The provided scheme should be a valid  | 
5007  |  |    * scheme string, be lower-cased, not contain spaces or tabs. It should  | 
5008  |  |    * have no spurious trailing or leading content.  | 
5009  |  |    */  | 
5010  |  |   inline void set_scheme(std::string &&new_scheme) noexcept;  | 
5011  |  |  | 
5012  |  |   /**  | 
5013  |  |    * Take the scheme from another URL. The scheme string is moved from the  | 
5014  |  |    * provided url.  | 
5015  |  |    */  | 
5016  |  |   constexpr void copy_scheme(ada::url &&u) noexcept;  | 
5017  |  |  | 
5018  |  |   /**  | 
5019  |  |    * Take the scheme from another URL. The scheme string is copied from the  | 
5020  |  |    * provided url.  | 
5021  |  |    */  | 
5022  |  |   constexpr void copy_scheme(const ada::url &u);  | 
5023  |  |  | 
5024  |  | };  // struct url  | 
5025  |  |  | 
5026  |  | inline std::ostream &operator<<(std::ostream &out, const ada::url &u);  | 
5027  |  | }  // namespace ada  | 
5028  |  |  | 
5029  |  | #endif  // ADA_URL_H  | 
5030  |  | /* end file include/ada/url.h */  | 
5031  |  |  | 
5032  |  | namespace ada { | 
5033  |  |  | 
5034  |  | template <class result_type = ada::url_aggregator>  | 
5035  |  | using result = tl::expected<result_type, ada::errors>;  | 
5036  |  |  | 
5037  |  | /**  | 
5038  |  |  * The URL parser takes a scalar value string input, with an optional null or  | 
5039  |  |  * base URL base (default null). The parser assumes the input is a valid ASCII  | 
5040  |  |  * or UTF-8 string.  | 
5041  |  |  *  | 
5042  |  |  * @param input the string input to analyze (must be valid ASCII or UTF-8)  | 
5043  |  |  * @param base_url the optional URL input to use as a base url.  | 
5044  |  |  * @return a parsed URL.  | 
5045  |  |  */  | 
5046  |  | template <class result_type = ada::url_aggregator>  | 
5047  |  | ada_warn_unused ada::result<result_type> parse(  | 
5048  |  |     std::string_view input, const result_type* base_url = nullptr);  | 
5049  |  |  | 
5050  |  | extern template ada::result<url> parse<url>(std::string_view input,  | 
5051  |  |                                             const url* base_url);  | 
5052  |  | extern template ada::result<url_aggregator> parse<url_aggregator>(  | 
5053  |  |     std::string_view input, const url_aggregator* base_url);  | 
5054  |  |  | 
5055  |  | /**  | 
5056  |  |  * Verifies whether the URL strings can be parsed. The function assumes  | 
5057  |  |  * that the inputs are valid ASCII or UTF-8 strings.  | 
5058  |  |  * @see https://url.spec.whatwg.org/#dom-url-canparse  | 
5059  |  |  * @return If URL can be parsed or not.  | 
5060  |  |  */  | 
5061  |  | bool can_parse(std::string_view input,  | 
5062  |  |                const std::string_view* base_input = nullptr);  | 
5063  |  |  | 
5064  |  | #if ADA_INCLUDE_URL_PATTERN  | 
5065  |  | /**  | 
5066  |  |  * Implementation of the URL pattern parsing algorithm.  | 
5067  |  |  * @see https://urlpattern.spec.whatwg.org  | 
5068  |  |  *  | 
5069  |  |  * @param input valid UTF-8 string or URLPatternInit struct  | 
5070  |  |  * @param base_url an optional valid UTF-8 string  | 
5071  |  |  * @param options an optional url_pattern_options struct  | 
5072  |  |  * @return url_pattern instance  | 
5073  |  |  */  | 
5074  |  | template <url_pattern_regex::regex_concept regex_provider>  | 
5075  |  | ada_warn_unused tl::expected<url_pattern<regex_provider>, errors>  | 
5076  |  | parse_url_pattern(std::variant<std::string_view, url_pattern_init>&& input,  | 
5077  |  |                   const std::string_view* base_url = nullptr,  | 
5078  |  |                   const url_pattern_options* options = nullptr);  | 
5079  |  | #endif  // ADA_INCLUDE_URL_PATTERN  | 
5080  |  |  | 
5081  |  | /**  | 
5082  |  |  * Computes a href string from a file path. The function assumes  | 
5083  |  |  * that the input is a valid ASCII or UTF-8 string.  | 
5084  |  |  * @return a href string (starts with file:://)  | 
5085  |  |  */  | 
5086  |  | std::string href_from_file(std::string_view path);  | 
5087  |  | }  // namespace ada  | 
5088  |  |  | 
5089  |  | #endif  // ADA_IMPLEMENTATION_H  | 
5090  |  | /* end file include/ada/implementation.h */  | 
5091  |  |  | 
5092  |  | #include <ostream>  | 
5093  |  | #include <string>  | 
5094  |  | #include <string_view>  | 
5095  |  | #include <unordered_map>  | 
5096  |  | #include <variant>  | 
5097  |  | #include <vector>  | 
5098  |  |  | 
5099  |  | #if ADA_TESTING  | 
5100  |  | #include <iostream>  | 
5101  |  | #endif  // ADA_TESTING  | 
5102  |  |  | 
5103  |  | #if ADA_INCLUDE_URL_PATTERN  | 
5104  |  | namespace ada { | 
5105  |  |  | 
5106  |  | enum class url_pattern_part_type : uint8_t { | 
5107  |  |   // The part represents a simple fixed text string.  | 
5108  |  |   FIXED_TEXT,  | 
5109  |  |   // The part represents a matching group with a custom regular expression.  | 
5110  |  |   REGEXP,  | 
5111  |  |   // The part represents a matching group that matches code points up to the  | 
5112  |  |   // next separator code point. This is typically used for a named group like  | 
5113  |  |   // ":foo" that does not have a custom regular expression.  | 
5114  |  |   SEGMENT_WILDCARD,  | 
5115  |  |   // The part represents a matching group that greedily matches all code points.  | 
5116  |  |   // This is typically used for the "*" wildcard matching group.  | 
5117  |  |   FULL_WILDCARD,  | 
5118  |  | };  | 
5119  |  |  | 
5120  |  | enum class url_pattern_part_modifier : uint8_t { | 
5121  |  |   // The part does not have a modifier.  | 
5122  |  |   none,  | 
5123  |  |   // The part has an optional modifier indicated by the U+003F (?) code point.  | 
5124  |  |   optional,  | 
5125  |  |   // The part has a "zero or more" modifier indicated by the U+002A (*) code  | 
5126  |  |   // point.  | 
5127  |  |   zero_or_more,  | 
5128  |  |   // The part has a "one or more" modifier indicated by the U+002B (+) code  | 
5129  |  |   // point.  | 
5130  |  |   one_or_more,  | 
5131  |  | };  | 
5132  |  |  | 
5133  |  | // @see https://urlpattern.spec.whatwg.org/#part  | 
5134  |  | class url_pattern_part { | 
5135  |  |  public:  | 
5136  |  |   url_pattern_part(url_pattern_part_type _type, std::string&& _value,  | 
5137  |  |                    url_pattern_part_modifier _modifier)  | 
5138  | 0  |       : type(_type), value(std::move(_value)), modifier(_modifier) {} | 
5139  |  |  | 
5140  |  |   url_pattern_part(url_pattern_part_type _type, std::string&& _value,  | 
5141  |  |                    url_pattern_part_modifier _modifier, std::string&& _name,  | 
5142  |  |                    std::string&& _prefix, std::string&& _suffix)  | 
5143  | 0  |       : type(_type),  | 
5144  | 0  |         value(std::move(_value)),  | 
5145  | 0  |         modifier(_modifier),  | 
5146  | 0  |         name(std::move(_name)),  | 
5147  | 0  |         prefix(std::move(_prefix)),  | 
5148  | 0  |         suffix(std::move(_suffix)) {} | 
5149  |  |   // A part has an associated type, a string, which must be set upon creation.  | 
5150  |  |   url_pattern_part_type type;  | 
5151  |  |   // A part has an associated value, a string, which must be set upon creation.  | 
5152  |  |   std::string value;  | 
5153  |  |   // A part has an associated modifier a string, which must be set upon  | 
5154  |  |   // creation.  | 
5155  |  |   url_pattern_part_modifier modifier;  | 
5156  |  |   // A part has an associated name, a string, initially the empty string.  | 
5157  |  |   std::string name{}; | 
5158  |  |   // A part has an associated prefix, a string, initially the empty string.  | 
5159  |  |   std::string prefix{}; | 
5160  |  |   // A part has an associated suffix, a string, initially the empty string.  | 
5161  |  |   std::string suffix{}; | 
5162  |  |  | 
5163  |  |   inline bool is_regexp() const noexcept;  | 
5164  |  | };  | 
5165  |  |  | 
5166  |  | // @see https://urlpattern.spec.whatwg.org/#options-header  | 
5167  |  | struct url_pattern_compile_component_options { | 
5168  |  |   url_pattern_compile_component_options() = default;  | 
5169  |  |   explicit url_pattern_compile_component_options(  | 
5170  |  |       std::optional<char> new_delimiter = std::nullopt,  | 
5171  |  |       std::optional<char> new_prefix = std::nullopt)  | 
5172  | 216  |       : delimiter(new_delimiter), prefix(new_prefix) {} | 
5173  |  |  | 
5174  |  |   inline std::string_view get_delimiter() const ada_warn_unused;  | 
5175  |  |   inline std::string_view get_prefix() const ada_warn_unused;  | 
5176  |  |  | 
5177  |  |   // @see https://urlpattern.spec.whatwg.org/#options-ignore-case  | 
5178  |  |   bool ignore_case = false;  | 
5179  |  |  | 
5180  |  |   static url_pattern_compile_component_options DEFAULT;  | 
5181  |  |   static url_pattern_compile_component_options HOSTNAME;  | 
5182  |  |   static url_pattern_compile_component_options PATHNAME;  | 
5183  |  |  | 
5184  |  |  private:  | 
5185  |  |   // @see https://urlpattern.spec.whatwg.org/#options-delimiter-code-point  | 
5186  |  |   std::optional<char> delimiter{}; | 
5187  |  |   // @see https://urlpattern.spec.whatwg.org/#options-prefix-code-point  | 
5188  |  |   std::optional<char> prefix{}; | 
5189  |  | };  | 
5190  |  |  | 
5191  |  | // The default options is an options struct with delimiter code point set to  | 
5192  |  | // the empty string and prefix code point set to the empty string.  | 
5193  |  | inline url_pattern_compile_component_options  | 
5194  |  |     url_pattern_compile_component_options::DEFAULT(std::nullopt, std::nullopt);  | 
5195  |  |  | 
5196  |  | // The hostname options is an options struct with delimiter code point set  | 
5197  |  | // "." and prefix code point set to the empty string.  | 
5198  |  | inline url_pattern_compile_component_options  | 
5199  |  |     url_pattern_compile_component_options::HOSTNAME('.', std::nullopt); | 
5200  |  |  | 
5201  |  | // The pathname options is an options struct with delimiter code point set  | 
5202  |  | // "/" and prefix code point set to "/".  | 
5203  |  | inline url_pattern_compile_component_options  | 
5204  |  |     url_pattern_compile_component_options::PATHNAME('/', '/'); | 
5205  |  |  | 
5206  |  | // A struct providing the URLPattern matching results for a single  | 
5207  |  | // URL component. The URLPatternComponentResult is only ever used  | 
5208  |  | // as a member attribute of a URLPatternResult struct. The  | 
5209  |  | // URLPatternComponentResult API is defined as part of the URLPattern  | 
5210  |  | // specification.  | 
5211  |  | struct url_pattern_component_result { | 
5212  |  |   std::string input;  | 
5213  |  |   std::unordered_map<std::string, std::optional<std::string>> groups;  | 
5214  |  |  | 
5215  |  |   bool operator==(const url_pattern_component_result&) const;  | 
5216  |  |  | 
5217  |  | #if ADA_TESTING  | 
5218  |  |   friend void PrintTo(const url_pattern_component_result& result,  | 
5219  |  |                       std::ostream* os) { | 
5220  |  |     *os << "input: '" << result.input << "', group: ";  | 
5221  |  |     for (const auto& group : result.groups) { | 
5222  |  |       *os << "(" << group.first << ", " << group.second.value_or("undefined") | 
5223  |  |           << ") ";  | 
5224  |  |     }  | 
5225  |  |   }  | 
5226  |  | #endif  // ADA_TESTING  | 
5227  |  | };  | 
5228  |  |  | 
5229  |  | template <url_pattern_regex::regex_concept regex_provider>  | 
5230  |  | class url_pattern_component { | 
5231  |  |  public:  | 
5232  | 0  |   url_pattern_component() = default;  | 
5233  |  |  | 
5234  |  |   // This function explicitly takes a std::string because it is moved.  | 
5235  |  |   // To avoid unnecessary copy, move each value while calling the constructor.  | 
5236  |  |   url_pattern_component(std::string&& new_pattern,  | 
5237  |  |                         typename regex_provider::regex_type&& new_regexp,  | 
5238  |  |                         std::vector<std::string>&& new_group_name_list,  | 
5239  |  |                         bool new_has_regexp_groups)  | 
5240  | 0  |       : regexp(std::move(new_regexp)),  | 
5241  | 0  |         pattern(std::move(new_pattern)),  | 
5242  | 0  |         group_name_list(std::move(new_group_name_list)),  | 
5243  | 0  |         has_regexp_groups(new_has_regexp_groups) {} | 
5244  |  |  | 
5245  |  |   // @see https://urlpattern.spec.whatwg.org/#compile-a-component  | 
5246  |  |   template <url_pattern_encoding_callback F>  | 
5247  |  |   static tl::expected<url_pattern_component, errors> compile(  | 
5248  |  |       std::string_view input, F& encoding_callback,  | 
5249  |  |       url_pattern_compile_component_options& options);  | 
5250  |  |  | 
5251  |  |   // @see https://urlpattern.spec.whatwg.org/#create-a-component-match-result  | 
5252  |  |   url_pattern_component_result create_component_match_result(  | 
5253  |  |       std::string&& input,  | 
5254  |  |       std::vector<std::optional<std::string>>&& exec_result);  | 
5255  |  |  | 
5256  |  | #if ADA_TESTING  | 
5257  |  |   friend void PrintTo(const url_pattern_component& component,  | 
5258  |  |                       std::ostream* os) { | 
5259  |  |     *os << "pattern: '" << component.pattern  | 
5260  |  |         << "', has_regexp_groups: " << component.has_regexp_groups  | 
5261  |  |         << "group_name_list: ";  | 
5262  |  |     for (const auto& name : component.group_name_list) { | 
5263  |  |       *os << name << ", ";  | 
5264  |  |     }  | 
5265  |  |   }  | 
5266  |  | #endif  // ADA_TESTING  | 
5267  |  |  | 
5268  |  |   typename regex_provider::regex_type regexp{}; | 
5269  |  |   std::string pattern{}; | 
5270  |  |   std::vector<std::string> group_name_list{}; | 
5271  |  |   bool has_regexp_groups = false;  | 
5272  |  | };  | 
5273  |  |  | 
5274  |  | // A URLPattern input can be either a string or a URLPatternInit object.  | 
5275  |  | // If it is a string, it must be a valid UTF-8 string.  | 
5276  |  | using url_pattern_input = std::variant<std::string_view, url_pattern_init>;  | 
5277  |  |  | 
5278  |  | // A struct providing the URLPattern matching results for all  | 
5279  |  | // components of a URL. The URLPatternResult API is defined as  | 
5280  |  | // part of the URLPattern specification.  | 
5281  |  | struct url_pattern_result { | 
5282  |  |   std::vector<url_pattern_input> inputs;  | 
5283  |  |   url_pattern_component_result protocol;  | 
5284  |  |   url_pattern_component_result username;  | 
5285  |  |   url_pattern_component_result password;  | 
5286  |  |   url_pattern_component_result hostname;  | 
5287  |  |   url_pattern_component_result port;  | 
5288  |  |   url_pattern_component_result pathname;  | 
5289  |  |   url_pattern_component_result search;  | 
5290  |  |   url_pattern_component_result hash;  | 
5291  |  | };  | 
5292  |  |  | 
5293  |  | struct url_pattern_options { | 
5294  |  |   bool ignore_case = false;  | 
5295  |  |  | 
5296  |  | #if ADA_TESTING  | 
5297  |  |   friend void PrintTo(const url_pattern_options& options, std::ostream* os) { | 
5298  |  |     *os << "ignore_case: '" << options.ignore_case;  | 
5299  |  |   }  | 
5300  |  | #endif  // ADA_TESTING  | 
5301  |  | };  | 
5302  |  |  | 
5303  |  | // URLPattern is a Web Platform standard API for matching URLs against a  | 
5304  |  | // pattern syntax (think of it as a regular expression for URLs). It is  | 
5305  |  | // defined in https://wicg.github.io/urlpattern.  | 
5306  |  | // More information about the URL Pattern syntax can be found at  | 
5307  |  | // https://developer.mozilla.org/en-US/docs/Web/API/URL_Pattern_API  | 
5308  |  | //  | 
5309  |  | // We require all strings to be valid UTF-8: it is the user's responsibility  | 
5310  |  | // to ensure that the provided strings are valid UTF-8.  | 
5311  |  | template <url_pattern_regex::regex_concept regex_provider>  | 
5312  |  | class url_pattern { | 
5313  |  |  public:  | 
5314  | 0  |   url_pattern() = default;  | 
5315  |  |  | 
5316  |  |   /**  | 
5317  |  |    * If non-null, base_url must pointer at a valid UTF-8 string.  | 
5318  |  |    * @see https://urlpattern.spec.whatwg.org/#dom-urlpattern-exec  | 
5319  |  |    */  | 
5320  |  |   result<std::optional<url_pattern_result>> exec(  | 
5321  |  |       const url_pattern_input& input,  | 
5322  |  |       const std::string_view* base_url = nullptr);  | 
5323  |  |  | 
5324  |  |   /**  | 
5325  |  |    * If non-null, base_url must pointer at a valid UTF-8 string.  | 
5326  |  |    * @see https://urlpattern.spec.whatwg.org/#dom-urlpattern-test  | 
5327  |  |    */  | 
5328  |  |   result<bool> test(const url_pattern_input& input,  | 
5329  |  |                     const std::string_view* base_url = nullptr);  | 
5330  |  |  | 
5331  |  |   /**  | 
5332  |  |    * @see https://urlpattern.spec.whatwg.org/#url-pattern-match  | 
5333  |  |    * This function expects a valid UTF-8 string if input is a string.  | 
5334  |  |    */  | 
5335  |  |   result<std::optional<url_pattern_result>> match(  | 
5336  |  |       const url_pattern_input& input,  | 
5337  |  |       const std::string_view* base_url_string = nullptr);  | 
5338  |  |  | 
5339  |  |   // @see https://urlpattern.spec.whatwg.org/#dom-urlpattern-protocol  | 
5340  |  |   [[nodiscard]] std::string_view get_protocol() const ada_lifetime_bound;  | 
5341  |  |   // @see https://urlpattern.spec.whatwg.org/#dom-urlpattern-username  | 
5342  |  |   [[nodiscard]] std::string_view get_username() const ada_lifetime_bound;  | 
5343  |  |   // @see https://urlpattern.spec.whatwg.org/#dom-urlpattern-password  | 
5344  |  |   [[nodiscard]] std::string_view get_password() const ada_lifetime_bound;  | 
5345  |  |   // @see https://urlpattern.spec.whatwg.org/#dom-urlpattern-hostname  | 
5346  |  |   [[nodiscard]] std::string_view get_hostname() const ada_lifetime_bound;  | 
5347  |  |   // @see https://urlpattern.spec.whatwg.org/#dom-urlpattern-port  | 
5348  |  |   [[nodiscard]] std::string_view get_port() const ada_lifetime_bound;  | 
5349  |  |   // @see https://urlpattern.spec.whatwg.org/#dom-urlpattern-pathname  | 
5350  |  |   [[nodiscard]] std::string_view get_pathname() const ada_lifetime_bound;  | 
5351  |  |   // @see https://urlpattern.spec.whatwg.org/#dom-urlpattern-search  | 
5352  |  |   [[nodiscard]] std::string_view get_search() const ada_lifetime_bound;  | 
5353  |  |   // @see https://urlpattern.spec.whatwg.org/#dom-urlpattern-hash  | 
5354  |  |   [[nodiscard]] std::string_view get_hash() const ada_lifetime_bound;  | 
5355  |  |  | 
5356  |  |   // If ignoreCase is true, the JavaScript regular expression created for each  | 
5357  |  |   // pattern must use the `vi` flag. Otherwise, they must use the `v` flag.  | 
5358  |  |   [[nodiscard]] bool ignore_case() const;  | 
5359  |  |  | 
5360  |  |   // @see https://urlpattern.spec.whatwg.org/#url-pattern-has-regexp-groups  | 
5361  |  |   [[nodiscard]] bool has_regexp_groups() const;  | 
5362  |  |  | 
5363  |  | #if ADA_TESTING  | 
5364  |  |   friend void PrintTo(const url_pattern& c, std::ostream* os) { | 
5365  |  |     *os << "protocol_component: '" << c.get_protocol() << ", ";  | 
5366  |  |     *os << "username_component: '" << c.get_username() << ", ";  | 
5367  |  |     *os << "password_component: '" << c.get_password() << ", ";  | 
5368  |  |     *os << "hostname_component: '" << c.get_hostname() << ", ";  | 
5369  |  |     *os << "port_component: '" << c.get_port() << ", ";  | 
5370  |  |     *os << "pathname_component: '" << c.get_pathname() << ", ";  | 
5371  |  |     *os << "search_component: '" << c.get_search() << ", ";  | 
5372  |  |     *os << "hash_component: '" << c.get_hash();  | 
5373  |  |   }  | 
5374  |  | #endif  // ADA_TESTING  | 
5375  |  |  | 
5376  |  |   template <url_pattern_regex::regex_concept P>  | 
5377  |  |   friend tl::expected<url_pattern<P>, errors> parser::parse_url_pattern_impl(  | 
5378  |  |       std::variant<std::string_view, url_pattern_init>&& input,  | 
5379  |  |       const std::string_view* base_url, const url_pattern_options* options);  | 
5380  |  |  | 
5381  |  |   /**  | 
5382  |  |    * @private  | 
5383  |  |    * We can not make this private due to a LLVM bug.  | 
5384  |  |    * Ref: https://github.com/ada-url/ada/pull/859  | 
5385  |  |    */  | 
5386  |  |   url_pattern_component<regex_provider> protocol_component{}; | 
5387  |  |   /**  | 
5388  |  |    * @private  | 
5389  |  |    * We can not make this private due to a LLVM bug.  | 
5390  |  |    * Ref: https://github.com/ada-url/ada/pull/859  | 
5391  |  |    */  | 
5392  |  |   url_pattern_component<regex_provider> username_component{}; | 
5393  |  |   /**  | 
5394  |  |    * @private  | 
5395  |  |    * We can not make this private due to a LLVM bug.  | 
5396  |  |    * Ref: https://github.com/ada-url/ada/pull/859  | 
5397  |  |    */  | 
5398  |  |   url_pattern_component<regex_provider> password_component{}; | 
5399  |  |   /**  | 
5400  |  |    * @private  | 
5401  |  |    * We can not make this private due to a LLVM bug.  | 
5402  |  |    * Ref: https://github.com/ada-url/ada/pull/859  | 
5403  |  |    */  | 
5404  |  |   url_pattern_component<regex_provider> hostname_component{}; | 
5405  |  |   /**  | 
5406  |  |    * @private  | 
5407  |  |    * We can not make this private due to a LLVM bug.  | 
5408  |  |    * Ref: https://github.com/ada-url/ada/pull/859  | 
5409  |  |    */  | 
5410  |  |   url_pattern_component<regex_provider> port_component{}; | 
5411  |  |   /**  | 
5412  |  |    * @private  | 
5413  |  |    * We can not make this private due to a LLVM bug.  | 
5414  |  |    * Ref: https://github.com/ada-url/ada/pull/859  | 
5415  |  |    */  | 
5416  |  |   url_pattern_component<regex_provider> pathname_component{}; | 
5417  |  |   /**  | 
5418  |  |    * @private  | 
5419  |  |    * We can not make this private due to a LLVM bug.  | 
5420  |  |    * Ref: https://github.com/ada-url/ada/pull/859  | 
5421  |  |    */  | 
5422  |  |   url_pattern_component<regex_provider> search_component{}; | 
5423  |  |   /**  | 
5424  |  |    * @private  | 
5425  |  |    * We can not make this private due to a LLVM bug.  | 
5426  |  |    * Ref: https://github.com/ada-url/ada/pull/859  | 
5427  |  |    */  | 
5428  |  |   url_pattern_component<regex_provider> hash_component{}; | 
5429  |  |   /**  | 
5430  |  |    * @private  | 
5431  |  |    * We can not make this private due to a LLVM bug.  | 
5432  |  |    * Ref: https://github.com/ada-url/ada/pull/859  | 
5433  |  |    */  | 
5434  |  |   bool ignore_case_ = false;  | 
5435  |  | };  | 
5436  |  | }  // namespace ada  | 
5437  |  | #endif  // ADA_INCLUDE_URL_PATTERN  | 
5438  |  | #endif  | 
5439  |  | /* end file include/ada/url_pattern.h */  | 
5440  |  | /* begin file include/ada/url_pattern_helpers.h */  | 
5441  |  | /**  | 
5442  |  |  * @file url_pattern_helpers.h  | 
5443  |  |  * @brief Declaration for the URLPattern helpers.  | 
5444  |  |  */  | 
5445  |  | #ifndef ADA_URL_PATTERN_HELPERS_H  | 
5446  |  | #define ADA_URL_PATTERN_HELPERS_H  | 
5447  |  |  | 
5448  |  |  | 
5449  |  | #include <string>  | 
5450  |  | #include <tuple>  | 
5451  |  | #include <vector>  | 
5452  |  |  | 
5453  |  | #if ADA_INCLUDE_URL_PATTERN  | 
5454  |  | namespace ada { | 
5455  |  | enum class errors : uint8_t;  | 
5456  |  | }  | 
5457  |  |  | 
5458  |  | namespace ada::url_pattern_helpers { | 
5459  |  |  | 
5460  |  | // @see https://urlpattern.spec.whatwg.org/#token  | 
5461  |  | enum class token_type : uint8_t { | 
5462  |  |   INVALID_CHAR,    // 0  | 
5463  |  |   OPEN,            // 1  | 
5464  |  |   CLOSE,           // 2  | 
5465  |  |   REGEXP,          // 3  | 
5466  |  |   NAME,            // 4  | 
5467  |  |   CHAR,            // 5  | 
5468  |  |   ESCAPED_CHAR,    // 6  | 
5469  |  |   OTHER_MODIFIER,  // 7  | 
5470  |  |   ASTERISK,        // 8  | 
5471  |  |   END,             // 9  | 
5472  |  | };  | 
5473  |  |  | 
5474  |  | #ifdef ADA_TESTING  | 
5475  |  | std::string to_string(token_type type);  | 
5476  |  | #endif  // ADA_TESTING  | 
5477  |  |  | 
5478  |  | // @see https://urlpattern.spec.whatwg.org/#tokenize-policy  | 
5479  |  | enum class token_policy { | 
5480  |  |   strict,  | 
5481  |  |   lenient,  | 
5482  |  | };  | 
5483  |  |  | 
5484  |  | // @see https://urlpattern.spec.whatwg.org/#tokens  | 
5485  |  | class token { | 
5486  |  |  public:  | 
5487  |  |   token(token_type _type, size_t _index, std::string&& _value)  | 
5488  | 0  |       : type(_type), index(_index), value(std::move(_value)) {} | 
5489  |  |  | 
5490  |  |   // A token has an associated type, a string, initially "invalid-char".  | 
5491  |  |   token_type type = token_type::INVALID_CHAR;  | 
5492  |  |  | 
5493  |  |   // A token has an associated index, a number, initially 0. It is the position  | 
5494  |  |   // of the first code point in the pattern string represented by the token.  | 
5495  |  |   size_t index = 0;  | 
5496  |  |  | 
5497  |  |   // A token has an associated value, a string, initially the empty string. It  | 
5498  |  |   // contains the code points from the pattern string represented by the token.  | 
5499  |  |   std::string value{}; | 
5500  |  | };  | 
5501  |  |  | 
5502  |  | // @see https://urlpattern.spec.whatwg.org/#pattern-parser  | 
5503  |  | template <url_pattern_encoding_callback F>  | 
5504  |  | class url_pattern_parser { | 
5505  |  |  public:  | 
5506  |  |   url_pattern_parser(F& encoding_callback_,  | 
5507  |  |                      std::string_view segment_wildcard_regexp_)  | 
5508  | 0  |       : encoding_callback(encoding_callback_),  | 
5509  | 0  |         segment_wildcard_regexp(segment_wildcard_regexp_) {} | 
5510  |  |  | 
5511  | 0  |   bool can_continue() const { return index < tokens.size(); } | 
5512  |  |  | 
5513  |  |   // @see https://urlpattern.spec.whatwg.org/#try-to-consume-a-token  | 
5514  |  |   token* try_consume_token(token_type type);  | 
5515  |  |   // @see https://urlpattern.spec.whatwg.org/#try-to-consume-a-modifier-token  | 
5516  |  |   token* try_consume_modifier_token();  | 
5517  |  |   // @see  | 
5518  |  |   // https://urlpattern.spec.whatwg.org/#try-to-consume-a-regexp-or-wildcard-token  | 
5519  |  |   token* try_consume_regexp_or_wildcard_token(const token* name_token);  | 
5520  |  |   // @see https://urlpattern.spec.whatwg.org/#consume-text  | 
5521  |  |   std::string consume_text();  | 
5522  |  |   // @see https://urlpattern.spec.whatwg.org/#consume-a-required-token  | 
5523  |  |   bool consume_required_token(token_type type);  | 
5524  |  |   // @see  | 
5525  |  |   // https://urlpattern.spec.whatwg.org/#maybe-add-a-part-from-the-pending-fixed-value  | 
5526  |  |   std::optional<errors> maybe_add_part_from_the_pending_fixed_value()  | 
5527  |  |       ada_warn_unused;  | 
5528  |  |   // @see https://urlpattern.spec.whatwg.org/#add-a-part  | 
5529  |  |   std::optional<errors> add_part(std::string_view prefix, token* name_token,  | 
5530  |  |                                  token* regexp_or_wildcard_token,  | 
5531  |  |                                  std::string_view suyffix,  | 
5532  |  |                                  token* modifier_token) ada_warn_unused;  | 
5533  |  |  | 
5534  |  |   std::vector<token> tokens{}; | 
5535  |  |   F& encoding_callback;  | 
5536  |  |   std::string segment_wildcard_regexp;  | 
5537  |  |   std::vector<url_pattern_part> parts{}; | 
5538  |  |   std::string pending_fixed_value{}; | 
5539  |  |   size_t index = 0;  | 
5540  |  |   size_t next_numeric_name = 0;  | 
5541  |  | };  | 
5542  |  |  | 
5543  |  | // @see https://urlpattern.spec.whatwg.org/#tokenizer  | 
5544  |  | class Tokenizer { | 
5545  |  |  public:  | 
5546  |  |   explicit Tokenizer(std::string_view new_input, token_policy new_policy)  | 
5547  | 0  |       : input(new_input), policy(new_policy) {} | 
5548  |  |  | 
5549  |  |   // @see https://urlpattern.spec.whatwg.org/#get-the-next-code-point  | 
5550  |  |   constexpr void get_next_code_point();  | 
5551  |  |  | 
5552  |  |   // @see https://urlpattern.spec.whatwg.org/#seek-and-get-the-next-code-point  | 
5553  |  |   constexpr void seek_and_get_next_code_point(size_t index);  | 
5554  |  |  | 
5555  |  |   // @see https://urlpattern.spec.whatwg.org/#add-a-token  | 
5556  |  |  | 
5557  |  |   void add_token(token_type type, size_t next_position, size_t value_position,  | 
5558  |  |                  size_t value_length);  | 
5559  |  |  | 
5560  |  |   // @see https://urlpattern.spec.whatwg.org/#add-a-token-with-default-length  | 
5561  |  |   void add_token_with_default_length(token_type type, size_t next_position,  | 
5562  |  |                                      size_t value_position);  | 
5563  |  |  | 
5564  |  |   // @see  | 
5565  |  |   // https://urlpattern.spec.whatwg.org/#add-a-token-with-default-position-and-length  | 
5566  |  |   void add_token_with_defaults(token_type type);  | 
5567  |  |  | 
5568  |  |   // @see https://urlpattern.spec.whatwg.org/#process-a-tokenizing-error  | 
5569  |  |   std::optional<errors> process_tokenizing_error(  | 
5570  |  |       size_t next_position, size_t value_position) ada_warn_unused;  | 
5571  |  |  | 
5572  |  |   friend tl::expected<std::vector<token>, errors> tokenize(  | 
5573  |  |       std::string_view input, token_policy policy);  | 
5574  |  |  | 
5575  |  |  private:  | 
5576  |  |   // has an associated input, a pattern string, initially the empty string.  | 
5577  |  |   std::string input;  | 
5578  |  |   // has an associated policy, a tokenize policy, initially "strict".  | 
5579  |  |   token_policy policy;  | 
5580  |  |   // has an associated token list, a token list, initially an empty list.  | 
5581  |  |   std::vector<token> token_list{}; | 
5582  |  |   // has an associated index, a number, initially 0.  | 
5583  |  |   size_t index = 0;  | 
5584  |  |   // has an associated next index, a number, initially 0.  | 
5585  |  |   size_t next_index = 0;  | 
5586  |  |   // has an associated code point, a Unicode code point, initially null.  | 
5587  |  |   char32_t code_point{}; | 
5588  |  | };  | 
5589  |  |  | 
5590  |  | // @see https://urlpattern.spec.whatwg.org/#constructor-string-parser  | 
5591  |  | template <url_pattern_regex::regex_concept regex_provider>  | 
5592  |  | struct constructor_string_parser { | 
5593  |  |   explicit constructor_string_parser(std::string_view new_input,  | 
5594  |  |                                      std::vector<token>&& new_token_list)  | 
5595  | 0  |       : input(new_input), token_list(std::move(new_token_list)) {} | 
5596  |  |   // @see https://urlpattern.spec.whatwg.org/#parse-a-constructor-string  | 
5597  |  |   static tl::expected<url_pattern_init, errors> parse(std::string_view input);  | 
5598  |  |  | 
5599  |  |   // @see https://urlpattern.spec.whatwg.org/#constructor-string-parser-state  | 
5600  |  |   enum class State { | 
5601  |  |     INIT,  | 
5602  |  |     PROTOCOL,  | 
5603  |  |     AUTHORITY,  | 
5604  |  |     USERNAME,  | 
5605  |  |     PASSWORD,  | 
5606  |  |     HOSTNAME,  | 
5607  |  |     PORT,  | 
5608  |  |     PATHNAME,  | 
5609  |  |     SEARCH,  | 
5610  |  |     HASH,  | 
5611  |  |     DONE,  | 
5612  |  |   };  | 
5613  |  |  | 
5614  |  |   // @see  | 
5615  |  |   // https://urlpattern.spec.whatwg.org/#compute-protocol-matches-a-special-scheme-flag  | 
5616  |  |   std::optional<errors> compute_protocol_matches_special_scheme_flag();  | 
5617  |  |  | 
5618  |  |  private:  | 
5619  |  |   // @see https://urlpattern.spec.whatwg.org/#rewind  | 
5620  |  |   constexpr void rewind();  | 
5621  |  |  | 
5622  |  |   // @see https://urlpattern.spec.whatwg.org/#is-a-hash-prefix  | 
5623  |  |   constexpr bool is_hash_prefix();  | 
5624  |  |  | 
5625  |  |   // @see https://urlpattern.spec.whatwg.org/#is-a-search-prefix  | 
5626  |  |   constexpr bool is_search_prefix();  | 
5627  |  |  | 
5628  |  |   // @see https://urlpattern.spec.whatwg.org/#change-state  | 
5629  |  |   void change_state(State state, size_t skip);  | 
5630  |  |  | 
5631  |  |   // @see https://urlpattern.spec.whatwg.org/#is-a-group-open  | 
5632  |  |   constexpr bool is_group_open() const;  | 
5633  |  |  | 
5634  |  |   // @see https://urlpattern.spec.whatwg.org/#is-a-group-close  | 
5635  |  |   constexpr bool is_group_close() const;  | 
5636  |  |  | 
5637  |  |   // @see https://urlpattern.spec.whatwg.org/#is-a-protocol-suffix  | 
5638  |  |   constexpr bool is_protocol_suffix() const;  | 
5639  |  |  | 
5640  |  |   // @see https://urlpattern.spec.whatwg.org/#next-is-authority-slashes  | 
5641  |  |   constexpr bool next_is_authority_slashes() const;  | 
5642  |  |  | 
5643  |  |   // @see https://urlpattern.spec.whatwg.org/#is-an-identity-terminator  | 
5644  |  |   constexpr bool is_an_identity_terminator() const;  | 
5645  |  |  | 
5646  |  |   // @see https://urlpattern.spec.whatwg.org/#is-a-pathname-start  | 
5647  |  |   constexpr bool is_pathname_start() const;  | 
5648  |  |  | 
5649  |  |   // @see https://urlpattern.spec.whatwg.org/#is-a-password-prefix  | 
5650  |  |   constexpr bool is_password_prefix() const;  | 
5651  |  |  | 
5652  |  |   // @see https://urlpattern.spec.whatwg.org/#is-an-ipv6-open  | 
5653  |  |   constexpr bool is_an_ipv6_open() const;  | 
5654  |  |  | 
5655  |  |   // @see https://urlpattern.spec.whatwg.org/#is-an-ipv6-close  | 
5656  |  |   constexpr bool is_an_ipv6_close() const;  | 
5657  |  |  | 
5658  |  |   // @see https://urlpattern.spec.whatwg.org/#is-a-port-prefix  | 
5659  |  |   constexpr bool is_port_prefix() const;  | 
5660  |  |  | 
5661  |  |   // @see https://urlpattern.spec.whatwg.org/#is-a-non-special-pattern-char  | 
5662  |  |   constexpr bool is_non_special_pattern_char(size_t index,  | 
5663  |  |                                              uint32_t value) const;  | 
5664  |  |  | 
5665  |  |   // @see https://urlpattern.spec.whatwg.org/#get-a-safe-token  | 
5666  |  |   constexpr const token* get_safe_token(size_t index) const;  | 
5667  |  |  | 
5668  |  |   // @see https://urlpattern.spec.whatwg.org/#make-a-component-string  | 
5669  |  |   std::string make_component_string();  | 
5670  |  |   // has an associated input, a string, which must be set upon creation.  | 
5671  |  |   std::string input;  | 
5672  |  |   // has an associated token list, a token list, which must be set upon  | 
5673  |  |   // creation.  | 
5674  |  |   std::vector<token> token_list;  | 
5675  |  |   // has an associated result, a URLPatternInit, initially set to a new  | 
5676  |  |   // URLPatternInit.  | 
5677  |  |   url_pattern_init result{}; | 
5678  |  |   // has an associated component start, a number, initially set to 0.  | 
5679  |  |   size_t component_start = 0;  | 
5680  |  |   // has an associated token index, a number, initially set to 0.  | 
5681  |  |   size_t token_index = 0;  | 
5682  |  |   // has an associated token increment, a number, initially set to 1.  | 
5683  |  |   size_t token_increment = 1;  | 
5684  |  |   // has an associated group depth, a number, initially set to 0.  | 
5685  |  |   size_t group_depth = 0;  | 
5686  |  |   // has an associated hostname IPv6 bracket depth, a number, initially set to  | 
5687  |  |   // 0.  | 
5688  |  |   size_t hostname_ipv6_bracket_depth = 0;  | 
5689  |  |   // has an associated protocol matches a special scheme flag, a boolean,  | 
5690  |  |   // initially set to false.  | 
5691  |  |   bool protocol_matches_a_special_scheme_flag = false;  | 
5692  |  |   // has an associated state, a string, initially set to "init".  | 
5693  |  |   State state = State::INIT;  | 
5694  |  | };  | 
5695  |  |  | 
5696  |  | // @see https://urlpattern.spec.whatwg.org/#canonicalize-a-protocol  | 
5697  |  | tl::expected<std::string, errors> canonicalize_protocol(std::string_view input);  | 
5698  |  |  | 
5699  |  | // @see https://wicg.github.io/urlpattern/#canonicalize-a-username  | 
5700  |  | tl::expected<std::string, errors> canonicalize_username(std::string_view input);  | 
5701  |  |  | 
5702  |  | // @see https://wicg.github.io/urlpattern/#canonicalize-a-password  | 
5703  |  | tl::expected<std::string, errors> canonicalize_password(std::string_view input);  | 
5704  |  |  | 
5705  |  | // @see https://wicg.github.io/urlpattern/#canonicalize-a-password  | 
5706  |  | tl::expected<std::string, errors> canonicalize_hostname(std::string_view input);  | 
5707  |  |  | 
5708  |  | // @see https://wicg.github.io/urlpattern/#canonicalize-an-ipv6-hostname  | 
5709  |  | tl::expected<std::string, errors> canonicalize_ipv6_hostname(  | 
5710  |  |     std::string_view input);  | 
5711  |  |  | 
5712  |  | // @see https://wicg.github.io/urlpattern/#canonicalize-a-port  | 
5713  |  | tl::expected<std::string, errors> canonicalize_port(std::string_view input);  | 
5714  |  |  | 
5715  |  | // @see https://wicg.github.io/urlpattern/#canonicalize-a-port  | 
5716  |  | tl::expected<std::string, errors> canonicalize_port_with_protocol(  | 
5717  |  |     std::string_view input, std::string_view protocol);  | 
5718  |  |  | 
5719  |  | // @see https://wicg.github.io/urlpattern/#canonicalize-a-pathname  | 
5720  |  | tl::expected<std::string, errors> canonicalize_pathname(std::string_view input);  | 
5721  |  |  | 
5722  |  | // @see https://wicg.github.io/urlpattern/#canonicalize-an-opaque-pathname  | 
5723  |  | tl::expected<std::string, errors> canonicalize_opaque_pathname(  | 
5724  |  |     std::string_view input);  | 
5725  |  |  | 
5726  |  | // @see https://wicg.github.io/urlpattern/#canonicalize-a-search  | 
5727  |  | tl::expected<std::string, errors> canonicalize_search(std::string_view input);  | 
5728  |  |  | 
5729  |  | // @see https://wicg.github.io/urlpattern/#canonicalize-a-hash  | 
5730  |  | tl::expected<std::string, errors> canonicalize_hash(std::string_view input);  | 
5731  |  |  | 
5732  |  | // @see https://urlpattern.spec.whatwg.org/#tokenize  | 
5733  |  | tl::expected<std::vector<token>, errors> tokenize(std::string_view input,  | 
5734  |  |                                                   token_policy policy);  | 
5735  |  |  | 
5736  |  | // @see https://urlpattern.spec.whatwg.org/#process-a-base-url-string  | 
5737  |  | std::string process_base_url_string(std::string_view input,  | 
5738  |  |                                     url_pattern_init::process_type type);  | 
5739  |  |  | 
5740  |  | // @see https://urlpattern.spec.whatwg.org/#escape-a-pattern-string  | 
5741  |  | std::string escape_pattern_string(std::string_view input);  | 
5742  |  |  | 
5743  |  | // @see https://urlpattern.spec.whatwg.org/#escape-a-regexp-string  | 
5744  |  | std::string escape_regexp_string(std::string_view input);  | 
5745  |  |  | 
5746  |  | // @see https://urlpattern.spec.whatwg.org/#is-an-absolute-pathname  | 
5747  |  | constexpr bool is_absolute_pathname(  | 
5748  |  |     std::string_view input, url_pattern_init::process_type type) noexcept;  | 
5749  |  |  | 
5750  |  | // @see https://urlpattern.spec.whatwg.org/#parse-a-pattern-string  | 
5751  |  | template <url_pattern_encoding_callback F>  | 
5752  |  | tl::expected<std::vector<url_pattern_part>, errors> parse_pattern_string(  | 
5753  |  |     std::string_view input, url_pattern_compile_component_options& options,  | 
5754  |  |     F& encoding_callback);  | 
5755  |  |  | 
5756  |  | // @see https://urlpattern.spec.whatwg.org/#generate-a-pattern-string  | 
5757  |  | std::string generate_pattern_string(  | 
5758  |  |     std::vector<url_pattern_part>& part_list,  | 
5759  |  |     url_pattern_compile_component_options& options);  | 
5760  |  |  | 
5761  |  | // @see  | 
5762  |  | // https://urlpattern.spec.whatwg.org/#generate-a-regular-expression-and-name-list  | 
5763  |  | std::tuple<std::string, std::vector<std::string>>  | 
5764  |  | generate_regular_expression_and_name_list(  | 
5765  |  |     const std::vector<url_pattern_part>& part_list,  | 
5766  |  |     url_pattern_compile_component_options options);  | 
5767  |  |  | 
5768  |  | // @see https://urlpattern.spec.whatwg.org/#hostname-pattern-is-an-ipv6-address  | 
5769  |  | bool is_ipv6_address(std::string_view input) noexcept;  | 
5770  |  |  | 
5771  |  | // @see  | 
5772  |  | // https://urlpattern.spec.whatwg.org/#protocol-component-matches-a-special-scheme  | 
5773  |  | template <url_pattern_regex::regex_concept regex_provider>  | 
5774  |  | bool protocol_component_matches_special_scheme(  | 
5775  |  |     ada::url_pattern_component<regex_provider>& input);  | 
5776  |  |  | 
5777  |  | // @see https://urlpattern.spec.whatwg.org/#convert-a-modifier-to-a-string  | 
5778  |  | std::string convert_modifier_to_string(url_pattern_part_modifier modifier);  | 
5779  |  |  | 
5780  |  | // @see https://urlpattern.spec.whatwg.org/#generate-a-segment-wildcard-regexp  | 
5781  |  | std::string generate_segment_wildcard_regexp(  | 
5782  |  |     url_pattern_compile_component_options options);  | 
5783  |  |  | 
5784  |  | }  // namespace ada::url_pattern_helpers  | 
5785  |  | #endif  // ADA_INCLUDE_URL_PATTERN  | 
5786  |  | #endif  | 
5787  |  | /* end file include/ada/url_pattern_helpers.h */  | 
5788  |  |  | 
5789  |  | #include <string>  | 
5790  |  | #include <string_view>  | 
5791  |  | #include <variant>  | 
5792  |  |  | 
5793  |  | namespace ada::parser { | 
5794  |  | #if ADA_INCLUDE_URL_PATTERN  | 
5795  |  | template <url_pattern_regex::regex_concept regex_provider>  | 
5796  |  | tl::expected<url_pattern<regex_provider>, errors> parse_url_pattern_impl(  | 
5797  |  |     std::variant<std::string_view, url_pattern_init>&& input,  | 
5798  | 0  |     const std::string_view* base_url, const url_pattern_options* options) { | 
5799  |  |   // Let init be null.  | 
5800  | 0  |   url_pattern_init init;  | 
5801  |  |  | 
5802  |  |   // If input is a scalar value string then:  | 
5803  | 0  |   if (std::holds_alternative<std::string_view>(input)) { | 
5804  |  |     // Set init to the result of running parse a constructor string given input.  | 
5805  | 0  |     auto parse_result =  | 
5806  | 0  |         url_pattern_helpers::constructor_string_parser<regex_provider>::parse(  | 
5807  | 0  |             std::get<std::string_view>(input));  | 
5808  | 0  |     if (!parse_result) { | 
5809  | 0  |       ada_log("constructor_string_parser::parse failed"); | 
5810  | 0  |       return tl::unexpected(parse_result.error());  | 
5811  | 0  |     }  | 
5812  | 0  |     init = std::move(*parse_result);  | 
5813  |  |     // If baseURL is null and init["protocol"] does not exist, then throw a  | 
5814  |  |     // TypeError.  | 
5815  | 0  |     if (!base_url && !init.protocol) { | 
5816  | 0  |       ada_log("base url is null and protocol is not set"); | 
5817  | 0  |       return tl::unexpected(errors::type_error);  | 
5818  | 0  |     }  | 
5819  |  |  | 
5820  |  |     // If baseURL is not null, set init["baseURL"] to baseURL.  | 
5821  | 0  |     if (base_url) { | 
5822  | 0  |       init.base_url = std::string(*base_url);  | 
5823  | 0  |     }  | 
5824  | 0  |   } else { | 
5825  |  |     // Assert: input is a URLPatternInit.  | 
5826  | 0  |     ADA_ASSERT_TRUE(std::holds_alternative<url_pattern_init>(input));  | 
5827  |  |     // If baseURL is not null, then throw a TypeError.  | 
5828  | 0  |     if (base_url) { | 
5829  | 0  |       ada_log("base url is not null"); | 
5830  | 0  |       return tl::unexpected(errors::type_error);  | 
5831  | 0  |     }  | 
5832  |  |     // Optimization: Avoid copy by moving the input value.  | 
5833  |  |     // Set init to input.  | 
5834  | 0  |     init = std::move(std::get<url_pattern_init>(input));  | 
5835  | 0  |   }  | 
5836  |  |  | 
5837  |  |   // Let processedInit be the result of process a URLPatternInit given init,  | 
5838  |  |   // "pattern", null, null, null, null, null, null, null, and null.  | 
5839  | 0  |   auto processed_init =  | 
5840  | 0  |       url_pattern_init::process(init, url_pattern_init::process_type::pattern);  | 
5841  | 0  |   if (!processed_init) { | 
5842  | 0  |     ada_log("url_pattern_init::process failed for init and 'pattern'"); | 
5843  | 0  |     return tl::unexpected(processed_init.error());  | 
5844  | 0  |   }  | 
5845  |  |  | 
5846  |  |   // For each componentName of  "protocol", "username", "password", "hostname",  | 
5847  |  |   // "port", "pathname", "search", "hash" If processedInit[componentName] does  | 
5848  |  |   // not exist, then set processedInit[componentName] to "*".  | 
5849  | 0  |   ADA_ASSERT_TRUE(processed_init.has_value());  | 
5850  | 0  |   if (!processed_init->protocol) processed_init->protocol = "*";  | 
5851  | 0  |   if (!processed_init->username) processed_init->username = "*";  | 
5852  | 0  |   if (!processed_init->password) processed_init->password = "*";  | 
5853  | 0  |   if (!processed_init->hostname) processed_init->hostname = "*";  | 
5854  | 0  |   if (!processed_init->port) processed_init->port = "*";  | 
5855  | 0  |   if (!processed_init->pathname) processed_init->pathname = "*";  | 
5856  | 0  |   if (!processed_init->search) processed_init->search = "*";  | 
5857  | 0  |   if (!processed_init->hash) processed_init->hash = "*";  | 
5858  |  | 
  | 
5859  | 0  |   ada_log("-- processed_init->protocol: ", processed_init->protocol.value()); | 
5860  | 0  |   ada_log("-- processed_init->username: ", processed_init->username.value()); | 
5861  | 0  |   ada_log("-- processed_init->password: ", processed_init->password.value()); | 
5862  | 0  |   ada_log("-- processed_init->hostname: ", processed_init->hostname.value()); | 
5863  | 0  |   ada_log("-- processed_init->port: ", processed_init->port.value()); | 
5864  | 0  |   ada_log("-- processed_init->pathname: ", processed_init->pathname.value()); | 
5865  | 0  |   ada_log("-- processed_init->search: ", processed_init->search.value()); | 
5866  | 0  |   ada_log("-- processed_init->hash: ", processed_init->hash.value()); | 
5867  |  |  | 
5868  |  |   // If processedInit["protocol"] is a special scheme and processedInit["port"]  | 
5869  |  |   // is a string which represents its corresponding default port in radix-10  | 
5870  |  |   // using ASCII digits then set processedInit["port"] to the empty string.  | 
5871  |  |   // TODO: Optimization opportunity.  | 
5872  | 0  |   if (scheme::is_special(*processed_init->protocol)) { | 
5873  | 0  |     std::string_view port = processed_init->port.value();  | 
5874  | 0  |     if (std::to_string(scheme::get_special_port(*processed_init->protocol)) ==  | 
5875  | 0  |         port) { | 
5876  | 0  |       processed_init->port->clear();  | 
5877  | 0  |     }  | 
5878  | 0  |   }  | 
5879  |  |  | 
5880  |  |   // Let urlPattern be a new URL pattern.  | 
5881  | 0  |   url_pattern<regex_provider> url_pattern_{}; | 
5882  |  |  | 
5883  |  |   // Set urlPattern's protocol component to the result of compiling a component  | 
5884  |  |   // given processedInit["protocol"], canonicalize a protocol, and default  | 
5885  |  |   // options.  | 
5886  | 0  |   auto protocol_component = url_pattern_component<regex_provider>::compile(  | 
5887  | 0  |       processed_init->protocol.value(),  | 
5888  | 0  |       url_pattern_helpers::canonicalize_protocol,  | 
5889  | 0  |       url_pattern_compile_component_options::DEFAULT);  | 
5890  | 0  |   if (!protocol_component) { | 
5891  | 0  |     ada_log("url_pattern_component::compile failed for protocol ", | 
5892  | 0  |             processed_init->protocol.value());  | 
5893  | 0  |     return tl::unexpected(protocol_component.error());  | 
5894  | 0  |   }  | 
5895  | 0  |   url_pattern_.protocol_component = std::move(*protocol_component);  | 
5896  |  |  | 
5897  |  |   // Set urlPattern's username component to the result of compiling a component  | 
5898  |  |   // given processedInit["username"], canonicalize a username, and default  | 
5899  |  |   // options.  | 
5900  | 0  |   auto username_component = url_pattern_component<regex_provider>::compile(  | 
5901  | 0  |       processed_init->username.value(),  | 
5902  | 0  |       url_pattern_helpers::canonicalize_username,  | 
5903  | 0  |       url_pattern_compile_component_options::DEFAULT);  | 
5904  | 0  |   if (!username_component) { | 
5905  | 0  |     ada_log("url_pattern_component::compile failed for username ", | 
5906  | 0  |             processed_init->username.value());  | 
5907  | 0  |     return tl::unexpected(username_component.error());  | 
5908  | 0  |   }  | 
5909  | 0  |   url_pattern_.username_component = std::move(*username_component);  | 
5910  |  |  | 
5911  |  |   // Set urlPattern's password component to the result of compiling a component  | 
5912  |  |   // given processedInit["password"], canonicalize a password, and default  | 
5913  |  |   // options.  | 
5914  | 0  |   auto password_component = url_pattern_component<regex_provider>::compile(  | 
5915  | 0  |       processed_init->password.value(),  | 
5916  | 0  |       url_pattern_helpers::canonicalize_password,  | 
5917  | 0  |       url_pattern_compile_component_options::DEFAULT);  | 
5918  | 0  |   if (!password_component) { | 
5919  | 0  |     ada_log("url_pattern_component::compile failed for password ", | 
5920  | 0  |             processed_init->password.value());  | 
5921  | 0  |     return tl::unexpected(password_component.error());  | 
5922  | 0  |   }  | 
5923  | 0  |   url_pattern_.password_component = std::move(*password_component);  | 
5924  |  |  | 
5925  |  |   // TODO: Optimization opportunity. The following if statement can be  | 
5926  |  |   // simplified.  | 
5927  |  |   // If the result running hostname pattern is an IPv6 address given  | 
5928  |  |   // processedInit["hostname"] is true, then set urlPattern's hostname component  | 
5929  |  |   // to the result of compiling a component given processedInit["hostname"],  | 
5930  |  |   // canonicalize an IPv6 hostname, and hostname options.  | 
5931  | 0  |   if (url_pattern_helpers::is_ipv6_address(processed_init->hostname.value())) { | 
5932  | 0  |     ada_log("processed_init->hostname is ipv6 address"); | 
5933  |  |     // then set urlPattern's hostname component to the result of compiling a  | 
5934  |  |     // component given processedInit["hostname"], canonicalize an IPv6 hostname,  | 
5935  |  |     // and hostname options.  | 
5936  | 0  |     auto hostname_component = url_pattern_component<regex_provider>::compile(  | 
5937  | 0  |         processed_init->hostname.value(),  | 
5938  | 0  |         url_pattern_helpers::canonicalize_ipv6_hostname,  | 
5939  | 0  |         url_pattern_compile_component_options::DEFAULT);  | 
5940  | 0  |     if (!hostname_component) { | 
5941  | 0  |       ada_log("url_pattern_component::compile failed for ipv6 hostname ", | 
5942  | 0  |               processed_init->hostname.value());  | 
5943  | 0  |       return tl::unexpected(hostname_component.error());  | 
5944  | 0  |     }  | 
5945  | 0  |     url_pattern_.hostname_component = std::move(*hostname_component);  | 
5946  | 0  |   } else { | 
5947  |  |     // Otherwise, set urlPattern's hostname component to the result of compiling  | 
5948  |  |     // a component given processedInit["hostname"], canonicalize a hostname, and  | 
5949  |  |     // hostname options.  | 
5950  | 0  |     auto hostname_component = url_pattern_component<regex_provider>::compile(  | 
5951  | 0  |         processed_init->hostname.value(),  | 
5952  | 0  |         url_pattern_helpers::canonicalize_hostname,  | 
5953  | 0  |         url_pattern_compile_component_options::HOSTNAME);  | 
5954  | 0  |     if (!hostname_component) { | 
5955  | 0  |       ada_log("url_pattern_component::compile failed for hostname ", | 
5956  | 0  |               processed_init->hostname.value());  | 
5957  | 0  |       return tl::unexpected(hostname_component.error());  | 
5958  | 0  |     }  | 
5959  | 0  |     url_pattern_.hostname_component = std::move(*hostname_component);  | 
5960  | 0  |   }  | 
5961  |  |  | 
5962  |  |   // Set urlPattern's port component to the result of compiling a component  | 
5963  |  |   // given processedInit["port"], canonicalize a port, and default options.  | 
5964  | 0  |   auto port_component = url_pattern_component<regex_provider>::compile(  | 
5965  | 0  |       processed_init->port.value(), url_pattern_helpers::canonicalize_port,  | 
5966  | 0  |       url_pattern_compile_component_options::DEFAULT);  | 
5967  | 0  |   if (!port_component) { | 
5968  | 0  |     ada_log("url_pattern_component::compile failed for port ", | 
5969  | 0  |             processed_init->port.value());  | 
5970  | 0  |     return tl::unexpected(port_component.error());  | 
5971  | 0  |   }  | 
5972  | 0  |   url_pattern_.port_component = std::move(*port_component);  | 
5973  |  |  | 
5974  |  |   // Let compileOptions be a copy of the default options with the ignore case  | 
5975  |  |   // property set to options["ignoreCase"].  | 
5976  | 0  |   auto compile_options = url_pattern_compile_component_options::DEFAULT;  | 
5977  | 0  |   if (options) { | 
5978  | 0  |     compile_options.ignore_case = options->ignore_case;  | 
5979  | 0  |   }  | 
5980  |  |  | 
5981  |  |   // TODO: Optimization opportunity: Simplify this if statement.  | 
5982  |  |   // If the result of running protocol component matches a special scheme given  | 
5983  |  |   // urlPattern's protocol component is true, then:  | 
5984  | 0  |   if (url_pattern_helpers::protocol_component_matches_special_scheme<  | 
5985  | 0  |           regex_provider>(url_pattern_.protocol_component)) { | 
5986  |  |     // Let pathCompileOptions be copy of the pathname options with the ignore  | 
5987  |  |     // case property set to options["ignoreCase"].  | 
5988  | 0  |     auto path_compile_options = url_pattern_compile_component_options::PATHNAME;  | 
5989  | 0  |     if (options) { | 
5990  | 0  |       path_compile_options.ignore_case = options->ignore_case;  | 
5991  | 0  |     }  | 
5992  |  |  | 
5993  |  |     // Set urlPattern's pathname component to the result of compiling a  | 
5994  |  |     // component given processedInit["pathname"], canonicalize a pathname, and  | 
5995  |  |     // pathCompileOptions.  | 
5996  | 0  |     auto pathname_component = url_pattern_component<regex_provider>::compile(  | 
5997  | 0  |         processed_init->pathname.value(),  | 
5998  | 0  |         url_pattern_helpers::canonicalize_pathname, path_compile_options);  | 
5999  | 0  |     if (!pathname_component) { | 
6000  | 0  |       ada_log("url_pattern_component::compile failed for pathname ", | 
6001  | 0  |               processed_init->pathname.value());  | 
6002  | 0  |       return tl::unexpected(pathname_component.error());  | 
6003  | 0  |     }  | 
6004  | 0  |     url_pattern_.pathname_component = std::move(*pathname_component);  | 
6005  | 0  |   } else { | 
6006  |  |     // Otherwise set urlPattern's pathname component to the result of compiling  | 
6007  |  |     // a component given processedInit["pathname"], canonicalize an opaque  | 
6008  |  |     // pathname, and compileOptions.  | 
6009  | 0  |     auto pathname_component = url_pattern_component<regex_provider>::compile(  | 
6010  | 0  |         processed_init->pathname.value(),  | 
6011  | 0  |         url_pattern_helpers::canonicalize_opaque_pathname, compile_options);  | 
6012  | 0  |     if (!pathname_component) { | 
6013  | 0  |       ada_log("url_pattern_component::compile failed for opaque pathname ", | 
6014  | 0  |               processed_init->pathname.value());  | 
6015  | 0  |       return tl::unexpected(pathname_component.error());  | 
6016  | 0  |     }  | 
6017  | 0  |     url_pattern_.pathname_component = std::move(*pathname_component);  | 
6018  | 0  |   }  | 
6019  |  |  | 
6020  |  |   // Set urlPattern's search component to the result of compiling a component  | 
6021  |  |   // given processedInit["search"], canonicalize a search, and compileOptions.  | 
6022  | 0  |   auto search_component = url_pattern_component<regex_provider>::compile(  | 
6023  | 0  |       processed_init->search.value(), url_pattern_helpers::canonicalize_search,  | 
6024  | 0  |       compile_options);  | 
6025  | 0  |   if (!search_component) { | 
6026  | 0  |     ada_log("url_pattern_component::compile failed for search ", | 
6027  | 0  |             processed_init->search.value());  | 
6028  | 0  |     return tl::unexpected(search_component.error());  | 
6029  | 0  |   }  | 
6030  | 0  |   url_pattern_.search_component = std::move(*search_component);  | 
6031  |  |  | 
6032  |  |   // Set urlPattern's hash component to the result of compiling a component  | 
6033  |  |   // given processedInit["hash"], canonicalize a hash, and compileOptions.  | 
6034  | 0  |   auto hash_component = url_pattern_component<regex_provider>::compile(  | 
6035  | 0  |       processed_init->hash.value(), url_pattern_helpers::canonicalize_hash,  | 
6036  | 0  |       compile_options);  | 
6037  | 0  |   if (!hash_component) { | 
6038  | 0  |     ada_log("url_pattern_component::compile failed for hash ", | 
6039  | 0  |             processed_init->hash.value());  | 
6040  | 0  |     return tl::unexpected(hash_component.error());  | 
6041  | 0  |   }  | 
6042  | 0  |   url_pattern_.hash_component = std::move(*hash_component);  | 
6043  |  |  | 
6044  |  |   // Return urlPattern.  | 
6045  | 0  |   return url_pattern_;  | 
6046  | 0  | }  | 
6047  |  | #endif  // ADA_INCLUDE_URL_PATTERN  | 
6048  |  |  | 
6049  |  | }  // namespace ada::parser  | 
6050  |  |  | 
6051  |  | #endif  // ADA_PARSER_INL_H  | 
6052  |  | /* end file include/ada/parser-inl.h */  | 
6053  |  | /* begin file include/ada/scheme-inl.h */  | 
6054  |  | /**  | 
6055  |  |  * @file scheme-inl.h  | 
6056  |  |  * @brief Definitions for the URL scheme.  | 
6057  |  |  */  | 
6058  |  | #ifndef ADA_SCHEME_INL_H  | 
6059  |  | #define ADA_SCHEME_INL_H  | 
6060  |  |  | 
6061  |  |  | 
6062  |  | namespace ada::scheme { | 
6063  |  |  | 
6064  |  | /**  | 
6065  |  |  * @namespace ada::scheme::details  | 
6066  |  |  * @brief Includes the definitions for scheme specific entities  | 
6067  |  |  */  | 
6068  |  | namespace details { | 
6069  |  | // for use with is_special and get_special_port  | 
6070  |  | // Spaces, if present, are removed from URL.  | 
6071  |  | constexpr std::string_view is_special_list[] = {"http", " ",   "https", "ws", | 
6072  |  |                                                 "ftp",  "wss", "file",  " "};  | 
6073  |  | // for use with get_special_port  | 
6074  |  | constexpr uint16_t special_ports[] = {80, 0, 443, 80, 21, 443, 0, 0}; | 
6075  |  | }  // namespace details  | 
6076  |  |  | 
6077  |  | /****  | 
6078  |  |  * @private  | 
6079  |  |  * In is_special, get_scheme_type, and get_special_port, we  | 
6080  |  |  * use a standard hashing technique to find the index of the scheme in  | 
6081  |  |  * the is_special_list. The hashing technique is based on the size of  | 
6082  |  |  * the scheme and the first character of the scheme. It ensures that we  | 
6083  |  |  * do at most one string comparison per call. If the protocol is  | 
6084  |  |  * predictible (e.g., it is always "http"), we can get a better average  | 
6085  |  |  * performance by using a simpler approach where we loop and compare  | 
6086  |  |  * scheme with all possible protocols starting with the most likely  | 
6087  |  |  * protocol. Doing multiple comparisons may have a poor worst case  | 
6088  |  |  * performance, however. In this instance, we choose a potentially  | 
6089  |  |  * slightly lower best-case performance for a better worst-case  | 
6090  |  |  * performance. We can revisit this choice at any time.  | 
6091  |  |  *  | 
6092  |  |  * Reference:  | 
6093  |  |  * Schmidt, Douglas C. "Gperf: A perfect hash function generator."  | 
6094  |  |  * More C++ gems 17 (2000).  | 
6095  |  |  *  | 
6096  |  |  * Reference: https://en.wikipedia.org/wiki/Perfect_hash_function  | 
6097  |  |  *  | 
6098  |  |  * Reference: https://github.com/ada-url/ada/issues/617  | 
6099  |  |  ****/  | 
6100  |  |  | 
6101  | 0  | ada_really_inline constexpr bool is_special(std::string_view scheme) { | 
6102  | 0  |   if (scheme.empty()) { | 
6103  | 0  |     return false;  | 
6104  | 0  |   }  | 
6105  | 0  |   int hash_value = (2 * scheme.size() + (unsigned)(scheme[0])) & 7;  | 
6106  | 0  |   const std::string_view target = details::is_special_list[hash_value];  | 
6107  | 0  |   return (target[0] == scheme[0]) && (target.substr(1) == scheme.substr(1));  | 
6108  | 0  | }  | 
6109  | 0  | constexpr uint16_t get_special_port(std::string_view scheme) noexcept { | 
6110  | 0  |   if (scheme.empty()) { | 
6111  | 0  |     return 0;  | 
6112  | 0  |   }  | 
6113  | 0  |   int hash_value = (2 * scheme.size() + (unsigned)(scheme[0])) & 7;  | 
6114  | 0  |   const std::string_view target = details::is_special_list[hash_value];  | 
6115  | 0  |   if ((target[0] == scheme[0]) && (target.substr(1) == scheme.substr(1))) { | 
6116  | 0  |     return details::special_ports[hash_value];  | 
6117  | 0  |   } else { | 
6118  | 0  |     return 0;  | 
6119  | 0  |   }  | 
6120  | 0  | }  | 
6121  | 0  | constexpr uint16_t get_special_port(ada::scheme::type type) noexcept { | 
6122  | 0  |   return details::special_ports[int(type)];  | 
6123  | 0  | }  | 
6124  | 0  | constexpr ada::scheme::type get_scheme_type(std::string_view scheme) noexcept { | 
6125  | 0  |   if (scheme.empty()) { | 
6126  | 0  |     return ada::scheme::NOT_SPECIAL;  | 
6127  | 0  |   }  | 
6128  | 0  |   int hash_value = (2 * scheme.size() + (unsigned)(scheme[0])) & 7;  | 
6129  | 0  |   const std::string_view target = details::is_special_list[hash_value];  | 
6130  | 0  |   if ((target[0] == scheme[0]) && (target.substr(1) == scheme.substr(1))) { | 
6131  | 0  |     return ada::scheme::type(hash_value);  | 
6132  | 0  |   } else { | 
6133  | 0  |     return ada::scheme::NOT_SPECIAL;  | 
6134  | 0  |   }  | 
6135  | 0  | }  | 
6136  |  |  | 
6137  |  | }  // namespace ada::scheme  | 
6138  |  |  | 
6139  |  | #endif  // ADA_SCHEME_INL_H  | 
6140  |  | /* end file include/ada/scheme-inl.h */  | 
6141  |  | /* begin file include/ada/serializers.h */  | 
6142  |  | /**  | 
6143  |  |  * @file serializers.h  | 
6144  |  |  * @brief Definitions for the URL serializers.  | 
6145  |  |  */  | 
6146  |  | #ifndef ADA_SERIALIZERS_H  | 
6147  |  | #define ADA_SERIALIZERS_H  | 
6148  |  |  | 
6149  |  |  | 
6150  |  | #include <array>  | 
6151  |  | #include <string>  | 
6152  |  |  | 
6153  |  | /**  | 
6154  |  |  * @namespace ada::serializers  | 
6155  |  |  * @brief Includes the definitions for URL serializers  | 
6156  |  |  */  | 
6157  |  | namespace ada::serializers { | 
6158  |  |  | 
6159  |  | /**  | 
6160  |  |  * Finds and returns the longest sequence of 0 values in a ipv6 input.  | 
6161  |  |  */  | 
6162  |  | void find_longest_sequence_of_ipv6_pieces(  | 
6163  |  |     const std::array<uint16_t, 8>& address, size_t& compress,  | 
6164  |  |     size_t& compress_length) noexcept;  | 
6165  |  |  | 
6166  |  | /**  | 
6167  |  |  * Serializes an ipv6 address.  | 
6168  |  |  * @details An IPv6 address is a 128-bit unsigned integer that identifies a  | 
6169  |  |  * network address.  | 
6170  |  |  * @see https://url.spec.whatwg.org/#concept-ipv6-serializer  | 
6171  |  |  */  | 
6172  |  | std::string ipv6(const std::array<uint16_t, 8>& address) noexcept;  | 
6173  |  |  | 
6174  |  | /**  | 
6175  |  |  * Serializes an ipv4 address.  | 
6176  |  |  * @details An IPv4 address is a 32-bit unsigned integer that identifies a  | 
6177  |  |  * network address.  | 
6178  |  |  * @see https://url.spec.whatwg.org/#concept-ipv4-serializer  | 
6179  |  |  */  | 
6180  |  | std::string ipv4(uint64_t address) noexcept;  | 
6181  |  |  | 
6182  |  | }  // namespace ada::serializers  | 
6183  |  |  | 
6184  |  | #endif  // ADA_SERIALIZERS_H  | 
6185  |  | /* end file include/ada/serializers.h */  | 
6186  |  | /* begin file include/ada/state.h */  | 
6187  |  | /**  | 
6188  |  |  * @file state.h  | 
6189  |  |  * @brief Definitions for the states of the URL state machine.  | 
6190  |  |  */  | 
6191  |  | #ifndef ADA_STATE_H  | 
6192  |  | #define ADA_STATE_H  | 
6193  |  |  | 
6194  |  |  | 
6195  |  | #include <string>  | 
6196  |  |  | 
6197  |  | namespace ada { | 
6198  |  |  | 
6199  |  | /**  | 
6200  |  |  * @see https://url.spec.whatwg.org/#url-parsing  | 
6201  |  |  */  | 
6202  |  | enum class state { | 
6203  |  |   /**  | 
6204  |  |    * @see https://url.spec.whatwg.org/#authority-state  | 
6205  |  |    */  | 
6206  |  |   AUTHORITY,  | 
6207  |  |  | 
6208  |  |   /**  | 
6209  |  |    * @see https://url.spec.whatwg.org/#scheme-start-state  | 
6210  |  |    */  | 
6211  |  |   SCHEME_START,  | 
6212  |  |  | 
6213  |  |   /**  | 
6214  |  |    * @see https://url.spec.whatwg.org/#scheme-state  | 
6215  |  |    */  | 
6216  |  |   SCHEME,  | 
6217  |  |  | 
6218  |  |   /**  | 
6219  |  |    * @see https://url.spec.whatwg.org/#host-state  | 
6220  |  |    */  | 
6221  |  |   HOST,  | 
6222  |  |  | 
6223  |  |   /**  | 
6224  |  |    * @see https://url.spec.whatwg.org/#no-scheme-state  | 
6225  |  |    */  | 
6226  |  |   NO_SCHEME,  | 
6227  |  |  | 
6228  |  |   /**  | 
6229  |  |    * @see https://url.spec.whatwg.org/#fragment-state  | 
6230  |  |    */  | 
6231  |  |   FRAGMENT,  | 
6232  |  |  | 
6233  |  |   /**  | 
6234  |  |    * @see https://url.spec.whatwg.org/#relative-state  | 
6235  |  |    */  | 
6236  |  |   RELATIVE_SCHEME,  | 
6237  |  |  | 
6238  |  |   /**  | 
6239  |  |    * @see https://url.spec.whatwg.org/#relative-slash-state  | 
6240  |  |    */  | 
6241  |  |   RELATIVE_SLASH,  | 
6242  |  |  | 
6243  |  |   /**  | 
6244  |  |    * @see https://url.spec.whatwg.org/#file-state  | 
6245  |  |    */  | 
6246  |  |   FILE,  | 
6247  |  |  | 
6248  |  |   /**  | 
6249  |  |    * @see https://url.spec.whatwg.org/#file-host-state  | 
6250  |  |    */  | 
6251  |  |   FILE_HOST,  | 
6252  |  |  | 
6253  |  |   /**  | 
6254  |  |    * @see https://url.spec.whatwg.org/#file-slash-state  | 
6255  |  |    */  | 
6256  |  |   FILE_SLASH,  | 
6257  |  |  | 
6258  |  |   /**  | 
6259  |  |    * @see https://url.spec.whatwg.org/#path-or-authority-state  | 
6260  |  |    */  | 
6261  |  |   PATH_OR_AUTHORITY,  | 
6262  |  |  | 
6263  |  |   /**  | 
6264  |  |    * @see https://url.spec.whatwg.org/#special-authority-ignore-slashes-state  | 
6265  |  |    */  | 
6266  |  |   SPECIAL_AUTHORITY_IGNORE_SLASHES,  | 
6267  |  |  | 
6268  |  |   /**  | 
6269  |  |    * @see https://url.spec.whatwg.org/#special-authority-slashes-state  | 
6270  |  |    */  | 
6271  |  |   SPECIAL_AUTHORITY_SLASHES,  | 
6272  |  |  | 
6273  |  |   /**  | 
6274  |  |    * @see https://url.spec.whatwg.org/#special-relative-or-authority-state  | 
6275  |  |    */  | 
6276  |  |   SPECIAL_RELATIVE_OR_AUTHORITY,  | 
6277  |  |  | 
6278  |  |   /**  | 
6279  |  |    * @see https://url.spec.whatwg.org/#query-state  | 
6280  |  |    */  | 
6281  |  |   QUERY,  | 
6282  |  |  | 
6283  |  |   /**  | 
6284  |  |    * @see https://url.spec.whatwg.org/#path-state  | 
6285  |  |    */  | 
6286  |  |   PATH,  | 
6287  |  |  | 
6288  |  |   /**  | 
6289  |  |    * @see https://url.spec.whatwg.org/#path-start-state  | 
6290  |  |    */  | 
6291  |  |   PATH_START,  | 
6292  |  |  | 
6293  |  |   /**  | 
6294  |  |    * @see https://url.spec.whatwg.org/#cannot-be-a-base-url-path-state  | 
6295  |  |    */  | 
6296  |  |   OPAQUE_PATH,  | 
6297  |  |  | 
6298  |  |   /**  | 
6299  |  |    * @see https://url.spec.whatwg.org/#port-state  | 
6300  |  |    */  | 
6301  |  |   PORT,  | 
6302  |  | };  | 
6303  |  |  | 
6304  |  | /**  | 
6305  |  |  * Stringify a URL state machine state.  | 
6306  |  |  */  | 
6307  |  | ada_warn_unused std::string to_string(ada::state s);  | 
6308  |  |  | 
6309  |  | }  // namespace ada  | 
6310  |  |  | 
6311  |  | #endif  // ADA_STATE_H  | 
6312  |  | /* end file include/ada/state.h */  | 
6313  |  | /* begin file include/ada/unicode.h */  | 
6314  |  | /**  | 
6315  |  |  * @file unicode.h  | 
6316  |  |  * @brief Definitions for all unicode specific functions.  | 
6317  |  |  */  | 
6318  |  | #ifndef ADA_UNICODE_H  | 
6319  |  | #define ADA_UNICODE_H  | 
6320  |  |  | 
6321  |  |  | 
6322  |  | #include <string>  | 
6323  |  | #include <string_view>  | 
6324  |  | #include <optional>  | 
6325  |  |  | 
6326  |  | /**  | 
6327  |  |  * Unicode operations. These functions are not part of our public API and may  | 
6328  |  |  * change at any time.  | 
6329  |  |  *  | 
6330  |  |  * @private  | 
6331  |  |  * @namespace ada::unicode  | 
6332  |  |  * @brief Includes the definitions for unicode operations  | 
6333  |  |  */  | 
6334  |  | namespace ada::unicode { | 
6335  |  |  | 
6336  |  | /**  | 
6337  |  |  * @private  | 
6338  |  |  * We receive a UTF-8 string representing a domain name.  | 
6339  |  |  * If the string is percent encoded, we apply percent decoding.  | 
6340  |  |  *  | 
6341  |  |  * Given a domain, we need to identify its labels.  | 
6342  |  |  * They are separated by label-separators:  | 
6343  |  |  *  | 
6344  |  |  * U+002E (.) FULL STOP  | 
6345  |  |  * U+FF0E FULLWIDTH FULL STOP  | 
6346  |  |  * U+3002 IDEOGRAPHIC FULL STOP  | 
6347  |  |  * U+FF61 HALFWIDTH IDEOGRAPHIC FULL STOP  | 
6348  |  |  *  | 
6349  |  |  * They are all mapped to U+002E.  | 
6350  |  |  *  | 
6351  |  |  * We process each label into a string that should not exceed 63 octets.  | 
6352  |  |  * If the string is already punycode (starts with "xn--"), then we must  | 
6353  |  |  * scan it to look for unallowed code points.  | 
6354  |  |  * Otherwise, if the string is not pure ASCII, we need to transcode it  | 
6355  |  |  * to punycode by following RFC 3454 which requires us to  | 
6356  |  |  * - Map characters  (see section 3),  | 
6357  |  |  * - Normalize (see section 4),  | 
6358  |  |  * - Reject forbidden characters,  | 
6359  |  |  * - Check for right-to-left characters and if so, check all requirements (see  | 
6360  |  |  * section 6),  | 
6361  |  |  * - Optionally reject based on unassigned code points (section 7).  | 
6362  |  |  *  | 
6363  |  |  * The Unicode standard provides a table of code points with a mapping, a list  | 
6364  |  |  * of forbidden code points and so forth. This table is subject to change and  | 
6365  |  |  * will vary based on the implementation. For Unicode 15, the table is at  | 
6366  |  |  * https://www.unicode.org/Public/idna/15.0.0/IdnaMappingTable.txt  | 
6367  |  |  * If you use ICU, they parse this table and map it to code using a Python  | 
6368  |  |  * script.  | 
6369  |  |  *  | 
6370  |  |  * The resulting strings should not exceed 255 octets according to RFC 1035  | 
6371  |  |  * section 2.3.4. ICU checks for label size and domain size, but these errors  | 
6372  |  |  * are ignored.  | 
6373  |  |  *  | 
6374  |  |  * @see https://url.spec.whatwg.org/#concept-domain-to-ascii  | 
6375  |  |  *  | 
6376  |  |  */  | 
6377  |  | bool to_ascii(std::optional<std::string>& out, std::string_view plain,  | 
6378  |  |               size_t first_percent);  | 
6379  |  |  | 
6380  |  | /**  | 
6381  |  |  * @private  | 
6382  |  |  * Checks if the input has tab or newline characters.  | 
6383  |  |  *  | 
6384  |  |  * @attention The has_tabs_or_newline function is a bottleneck and it is simple  | 
6385  |  |  * enough that compilers like GCC can 'autovectorize it'.  | 
6386  |  |  */  | 
6387  |  | ada_really_inline bool has_tabs_or_newline(  | 
6388  |  |     std::string_view user_input) noexcept;  | 
6389  |  |  | 
6390  |  | /**  | 
6391  |  |  * @private  | 
6392  |  |  * Checks if the input is a forbidden host code point.  | 
6393  |  |  * @see https://url.spec.whatwg.org/#forbidden-host-code-point  | 
6394  |  |  */  | 
6395  |  | ada_really_inline constexpr bool is_forbidden_host_code_point(char c) noexcept;  | 
6396  |  |  | 
6397  |  | /**  | 
6398  |  |  * @private  | 
6399  |  |  * Checks if the input contains a forbidden domain code point.  | 
6400  |  |  * @see https://url.spec.whatwg.org/#forbidden-domain-code-point  | 
6401  |  |  */  | 
6402  |  | ada_really_inline constexpr bool contains_forbidden_domain_code_point(  | 
6403  |  |     const char* input, size_t length) noexcept;  | 
6404  |  |  | 
6405  |  | /**  | 
6406  |  |  * @private  | 
6407  |  |  * Checks if the input contains a forbidden domain code point in which case  | 
6408  |  |  * the first bit is set to 1. If the input contains an upper case ASCII letter,  | 
6409  |  |  * then the second bit is set to 1.  | 
6410  |  |  * @see https://url.spec.whatwg.org/#forbidden-domain-code-point  | 
6411  |  |  */  | 
6412  |  | ada_really_inline constexpr uint8_t  | 
6413  |  | contains_forbidden_domain_code_point_or_upper(const char* input,  | 
6414  |  |                                               size_t length) noexcept;  | 
6415  |  |  | 
6416  |  | /**  | 
6417  |  |  * @private  | 
6418  |  |  * Checks if the input is a forbidden domain code point.  | 
6419  |  |  * @see https://url.spec.whatwg.org/#forbidden-domain-code-point  | 
6420  |  |  */  | 
6421  |  | ada_really_inline constexpr bool is_forbidden_domain_code_point(  | 
6422  |  |     char c) noexcept;  | 
6423  |  |  | 
6424  |  | /**  | 
6425  |  |  * @private  | 
6426  |  |  * Checks if the input is alphanumeric, '+', '-' or '.'  | 
6427  |  |  */  | 
6428  |  | ada_really_inline constexpr bool is_alnum_plus(char c) noexcept;  | 
6429  |  |  | 
6430  |  | /**  | 
6431  |  |  * @private  | 
6432  |  |  * @details An ASCII hex digit is an ASCII upper hex digit or ASCII lower hex  | 
6433  |  |  * digit. An ASCII upper hex digit is an ASCII digit or a code point in the  | 
6434  |  |  * range U+0041 (A) to U+0046 (F), inclusive. An ASCII lower hex digit is an  | 
6435  |  |  * ASCII digit or a code point in the range U+0061 (a) to U+0066 (f), inclusive.  | 
6436  |  |  */  | 
6437  |  | ada_really_inline constexpr bool is_ascii_hex_digit(char c) noexcept;  | 
6438  |  |  | 
6439  |  | /**  | 
6440  |  |  * @private  | 
6441  |  |  * An ASCII digit is a code point in the range U+0030 (0) to U+0039 (9),  | 
6442  |  |  * inclusive.  | 
6443  |  |  */  | 
6444  |  | ada_really_inline constexpr bool is_ascii_digit(char c) noexcept;  | 
6445  |  |  | 
6446  |  | /**  | 
6447  |  |  * @private  | 
6448  |  |  * @details If a char is between U+0000 and U+007F inclusive, then it's an ASCII  | 
6449  |  |  * character.  | 
6450  |  |  */  | 
6451  |  | ada_really_inline constexpr bool is_ascii(char32_t c) noexcept;  | 
6452  |  |  | 
6453  |  | /**  | 
6454  |  |  * @private  | 
6455  |  |  * Checks if the input is a C0 control or space character.  | 
6456  |  |  *  | 
6457  |  |  * @details A C0 control or space is a C0 control or U+0020 SPACE.  | 
6458  |  |  * A C0 control is a code point in the range U+0000 NULL to U+001F INFORMATION  | 
6459  |  |  * SEPARATOR ONE, inclusive.  | 
6460  |  |  */  | 
6461  |  | ada_really_inline constexpr bool is_c0_control_or_space(char c) noexcept;  | 
6462  |  |  | 
6463  |  | /**  | 
6464  |  |  * @private  | 
6465  |  |  * Checks if the input is a ASCII tab or newline character.  | 
6466  |  |  *  | 
6467  |  |  * @details An ASCII tab or newline is U+0009 TAB, U+000A LF, or U+000D CR.  | 
6468  |  |  */  | 
6469  |  | ada_really_inline constexpr bool is_ascii_tab_or_newline(char c) noexcept;  | 
6470  |  |  | 
6471  |  | /**  | 
6472  |  |  * @private  | 
6473  |  |  * @details A double-dot path segment must be ".." or an ASCII case-insensitive  | 
6474  |  |  * match for ".%2e", "%2e.", or "%2e%2e".  | 
6475  |  |  */  | 
6476  |  | ada_really_inline constexpr bool is_double_dot_path_segment(  | 
6477  |  |     std::string_view input) noexcept;  | 
6478  |  |  | 
6479  |  | /**  | 
6480  |  |  * @private  | 
6481  |  |  * @details A single-dot path segment must be "." or an ASCII case-insensitive  | 
6482  |  |  * match for "%2e".  | 
6483  |  |  */  | 
6484  |  | ada_really_inline constexpr bool is_single_dot_path_segment(  | 
6485  |  |     std::string_view input) noexcept;  | 
6486  |  |  | 
6487  |  | /**  | 
6488  |  |  * @private  | 
6489  |  |  * @details ipv4 character might contain 0-9 or a-f character ranges.  | 
6490  |  |  */  | 
6491  |  | ada_really_inline constexpr bool is_lowercase_hex(char c) noexcept;  | 
6492  |  |  | 
6493  |  | /**  | 
6494  |  |  * @private  | 
6495  |  |  * @details Convert hex to binary. Caller is responsible to ensure that  | 
6496  |  |  * the parameter is an hexadecimal digit (0-9, A-F, a-f).  | 
6497  |  |  */  | 
6498  |  | ada_really_inline unsigned constexpr convert_hex_to_binary(char c) noexcept;  | 
6499  |  |  | 
6500  |  | /**  | 
6501  |  |  * @private  | 
6502  |  |  * first_percent should be  = input.find('%') | 
6503  |  |  *  | 
6504  |  |  * @todo It would be faster as noexcept maybe, but it could be unsafe since.  | 
6505  |  |  * @author Node.js  | 
6506  |  |  * @see https://github.com/nodejs/node/blob/main/src/node_url.cc#L245  | 
6507  |  |  * @see https://encoding.spec.whatwg.org/#utf-8-decode-without-bom  | 
6508  |  |  */  | 
6509  |  | std::string percent_decode(std::string_view input, size_t first_percent);  | 
6510  |  |  | 
6511  |  | /**  | 
6512  |  |  * @private  | 
6513  |  |  * Returns a percent-encoding string whether percent encoding was needed or not.  | 
6514  |  |  * @see https://github.com/nodejs/node/blob/main/src/node_url.cc#L226  | 
6515  |  |  */  | 
6516  |  | std::string percent_encode(std::string_view input,  | 
6517  |  |                            const uint8_t character_set[]);  | 
6518  |  | /**  | 
6519  |  |  * @private  | 
6520  |  |  * Returns a percent-encoded string version of input, while starting the percent  | 
6521  |  |  * encoding at the provided index.  | 
6522  |  |  * @see https://github.com/nodejs/node/blob/main/src/node_url.cc#L226  | 
6523  |  |  */  | 
6524  |  | std::string percent_encode(std::string_view input,  | 
6525  |  |                            const uint8_t character_set[], size_t index);  | 
6526  |  | /**  | 
6527  |  |  * @private  | 
6528  |  |  * Returns true if percent encoding was needed, in which case, we store  | 
6529  |  |  * the percent-encoded content in 'out'. If the boolean 'append' is set to  | 
6530  |  |  * true, the content is appended to 'out'.  | 
6531  |  |  * If percent encoding is not needed, out is left unchanged.  | 
6532  |  |  * @see https://github.com/nodejs/node/blob/main/src/node_url.cc#L226  | 
6533  |  |  */  | 
6534  |  | template <bool append>  | 
6535  |  | bool percent_encode(std::string_view input, const uint8_t character_set[],  | 
6536  |  |                     std::string& out);  | 
6537  |  | /**  | 
6538  |  |  * @private  | 
6539  |  |  * Returns the index at which percent encoding should start, or (equivalently),  | 
6540  |  |  * the length of the prefix that does not require percent encoding.  | 
6541  |  |  */  | 
6542  |  | ada_really_inline size_t percent_encode_index(std::string_view input,  | 
6543  |  |                                               const uint8_t character_set[]);  | 
6544  |  | /**  | 
6545  |  |  * @private  | 
6546  |  |  * Lowers the string in-place, assuming that the content is ASCII.  | 
6547  |  |  * Return true if the content was ASCII.  | 
6548  |  |  */  | 
6549  |  | constexpr bool to_lower_ascii(char* input, size_t length) noexcept;  | 
6550  |  | }  // namespace ada::unicode  | 
6551  |  |  | 
6552  |  | #endif  // ADA_UNICODE_H  | 
6553  |  | /* end file include/ada/unicode.h */  | 
6554  |  | /* begin file include/ada/url_base-inl.h */  | 
6555  |  | /**  | 
6556  |  |  * @file url_base-inl.h  | 
6557  |  |  * @brief Inline functions for url base  | 
6558  |  |  */  | 
6559  |  | #ifndef ADA_URL_BASE_INL_H  | 
6560  |  | #define ADA_URL_BASE_INL_H  | 
6561  |  |  | 
6562  |  |  | 
6563  |  | #include <string>  | 
6564  |  | #if ADA_REGULAR_VISUAL_STUDIO  | 
6565  |  | #include <intrin.h>  | 
6566  |  | #endif  // ADA_REGULAR_VISUAL_STUDIO  | 
6567  |  |  | 
6568  |  | namespace ada { | 
6569  |  |  | 
6570  |  | [[nodiscard]] ada_really_inline constexpr bool url_base::is_special()  | 
6571  | 0  |     const noexcept { | 
6572  | 0  |   return type != ada::scheme::NOT_SPECIAL;  | 
6573  | 0  | }  | 
6574  |  |  | 
6575  | 0  | [[nodiscard]] inline uint16_t url_base::get_special_port() const noexcept { | 
6576  | 0  |   return ada::scheme::get_special_port(type);  | 
6577  | 0  | }  | 
6578  |  |  | 
6579  |  | [[nodiscard]] ada_really_inline uint16_t  | 
6580  | 0  | url_base::scheme_default_port() const noexcept { | 
6581  | 0  |   return scheme::get_special_port(type);  | 
6582  | 0  | }  | 
6583  |  |  | 
6584  |  | }  // namespace ada  | 
6585  |  |  | 
6586  |  | #endif  // ADA_URL_BASE_INL_H  | 
6587  |  | /* end file include/ada/url_base-inl.h */  | 
6588  |  | /* begin file include/ada/url-inl.h */  | 
6589  |  | /**  | 
6590  |  |  * @file url-inl.h  | 
6591  |  |  * @brief Definitions for the URL  | 
6592  |  |  */  | 
6593  |  | #ifndef ADA_URL_INL_H  | 
6594  |  | #define ADA_URL_INL_H  | 
6595  |  |  | 
6596  |  |  | 
6597  |  | #include <charconv>  | 
6598  |  | #include <optional>  | 
6599  |  | #include <string>  | 
6600  |  | #if ADA_REGULAR_VISUAL_STUDIO  | 
6601  |  | #include <intrin.h>  | 
6602  |  | #endif  // ADA_REGULAR_VISUAL_STUDIO  | 
6603  |  |  | 
6604  |  | namespace ada { | 
6605  | 0  | [[nodiscard]] ada_really_inline bool url::has_credentials() const noexcept { | 
6606  | 0  |   return !username.empty() || !password.empty();  | 
6607  | 0  | }  | 
6608  | 0  | [[nodiscard]] ada_really_inline bool url::has_port() const noexcept { | 
6609  | 0  |   return port.has_value();  | 
6610  | 0  | }  | 
6611  | 0  | [[nodiscard]] inline bool url::cannot_have_credentials_or_port() const { | 
6612  | 0  |   return !host.has_value() || host.value().empty() ||  | 
6613  | 0  |          type == ada::scheme::type::FILE;  | 
6614  | 0  | }  | 
6615  | 0  | [[nodiscard]] inline bool url::has_empty_hostname() const noexcept { | 
6616  | 0  |   if (!host.has_value()) { | 
6617  | 0  |     return false;  | 
6618  | 0  |   }  | 
6619  | 0  |   return host.value().empty();  | 
6620  | 0  | }  | 
6621  | 0  | [[nodiscard]] inline bool url::has_hostname() const noexcept { | 
6622  | 0  |   return host.has_value();  | 
6623  | 0  | }  | 
6624  | 0  | inline std::ostream &operator<<(std::ostream &out, const ada::url &u) { | 
6625  | 0  |   return out << u.to_string();  | 
6626  | 0  | }  | 
6627  |  |  | 
6628  | 0  | [[nodiscard]] size_t url::get_pathname_length() const noexcept { | 
6629  | 0  |   return path.size();  | 
6630  | 0  | }  | 
6631  |  |  | 
6632  | 0  | [[nodiscard]] constexpr std::string_view url::get_pathname() const noexcept { | 
6633  | 0  |   return path;  | 
6634  | 0  | }  | 
6635  |  |  | 
6636  |  | [[nodiscard]] ada_really_inline ada::url_components url::get_components()  | 
6637  | 0  |     const noexcept { | 
6638  | 0  |   url_components out{}; | 
6639  | 0  | 
  | 
6640  | 0  |   // protocol ends with ':'. for example: "https:"  | 
6641  | 0  |   out.protocol_end = uint32_t(get_protocol().size());  | 
6642  | 0  | 
  | 
6643  | 0  |   // Trailing index is always the next character of the current one.  | 
6644  | 0  |   // NOLINTNEXTLINE(clang-analyzer-deadcode.DeadStores)  | 
6645  | 0  |   size_t running_index = out.protocol_end;  | 
6646  | 0  | 
  | 
6647  | 0  |   if (host.has_value()) { | 
6648  | 0  |     // 2 characters for "//" and 1 character for starting index  | 
6649  | 0  |     out.host_start = out.protocol_end + 2;  | 
6650  | 0  | 
  | 
6651  | 0  |     if (has_credentials()) { | 
6652  | 0  |       out.username_end = uint32_t(out.host_start + username.size());  | 
6653  | 0  | 
  | 
6654  | 0  |       out.host_start += uint32_t(username.size());  | 
6655  | 0  | 
  | 
6656  | 0  |       if (!password.empty()) { | 
6657  | 0  |         out.host_start += uint32_t(password.size() + 1);  | 
6658  | 0  |       }  | 
6659  | 0  | 
  | 
6660  | 0  |       out.host_end = uint32_t(out.host_start + host.value().size());  | 
6661  | 0  |     } else { | 
6662  | 0  |       out.username_end = out.host_start;  | 
6663  | 0  | 
  | 
6664  | 0  |       // Host does not start with "@" if it does not include credentials.  | 
6665  | 0  |       out.host_end = uint32_t(out.host_start + host.value().size()) - 1;  | 
6666  | 0  |     }  | 
6667  | 0  | 
  | 
6668  | 0  |     running_index = out.host_end + 1;  | 
6669  | 0  |   } else { | 
6670  | 0  |     // Update host start and end date to the same index, since it does not  | 
6671  | 0  |     // exist.  | 
6672  | 0  |     out.host_start = out.protocol_end;  | 
6673  | 0  |     out.host_end = out.host_start;  | 
6674  | 0  | 
  | 
6675  | 0  |     if (!has_opaque_path && path.starts_with("//")) { | 
6676  | 0  |       // If url's host is null, url does not have an opaque path, url's path's  | 
6677  | 0  |       // size is greater than 1, and url's path[0] is the empty string, then  | 
6678  | 0  |       // append U+002F (/) followed by U+002E (.) to output.  | 
6679  | 0  |       running_index = out.protocol_end + 2;  | 
6680  | 0  |     } else { | 
6681  | 0  |       running_index = out.protocol_end;  | 
6682  | 0  |     }  | 
6683  | 0  |   }  | 
6684  | 0  | 
  | 
6685  | 0  |   if (port.has_value()) { | 
6686  | 0  |     out.port = *port;  | 
6687  | 0  |     running_index += helpers::fast_digit_count(*port) + 1;  // Port omits ':'  | 
6688  | 0  |   }  | 
6689  | 0  | 
  | 
6690  | 0  |   out.pathname_start = uint32_t(running_index);  | 
6691  | 0  | 
  | 
6692  | 0  |   running_index += path.size();  | 
6693  | 0  | 
  | 
6694  | 0  |   if (query.has_value()) { | 
6695  | 0  |     out.search_start = uint32_t(running_index);  | 
6696  | 0  |     running_index += get_search().size();  | 
6697  | 0  |     if (get_search().empty()) { | 
6698  | 0  |       running_index++;  | 
6699  | 0  |     }  | 
6700  | 0  |   }  | 
6701  | 0  | 
  | 
6702  | 0  |   if (hash.has_value()) { | 
6703  | 0  |     out.hash_start = uint32_t(running_index);  | 
6704  | 0  |   }  | 
6705  | 0  | 
  | 
6706  | 0  |   return out;  | 
6707  | 0  | }  | 
6708  |  |  | 
6709  | 0  | inline void url::update_base_hostname(std::string_view input) { host = input; } | 
6710  |  |  | 
6711  | 0  | inline void url::update_unencoded_base_hash(std::string_view input) { | 
6712  | 0  |   // We do the percent encoding  | 
6713  | 0  |   hash = unicode::percent_encode(input,  | 
6714  | 0  |                                  ada::character_sets::FRAGMENT_PERCENT_ENCODE);  | 
6715  | 0  | }  | 
6716  |  |  | 
6717  |  | inline void url::update_base_search(std::string_view input,  | 
6718  | 0  |                                     const uint8_t query_percent_encode_set[]) { | 
6719  | 0  |   query = ada::unicode::percent_encode(input, query_percent_encode_set);  | 
6720  | 0  | }  | 
6721  |  |  | 
6722  | 0  | inline void url::update_base_search(std::optional<std::string> &&input) { | 
6723  | 0  |   query = std::move(input);  | 
6724  | 0  | }  | 
6725  |  |  | 
6726  | 0  | inline void url::update_base_pathname(const std::string_view input) { | 
6727  | 0  |   path = input;  | 
6728  | 0  | }  | 
6729  |  |  | 
6730  | 0  | inline void url::update_base_username(const std::string_view input) { | 
6731  | 0  |   username = input;  | 
6732  | 0  | }  | 
6733  |  |  | 
6734  | 0  | inline void url::update_base_password(const std::string_view input) { | 
6735  | 0  |   password = input;  | 
6736  | 0  | }  | 
6737  |  |  | 
6738  | 0  | inline void url::update_base_port(std::optional<uint16_t> input) { | 
6739  | 0  |   port = input;  | 
6740  | 0  | }  | 
6741  |  |  | 
6742  | 0  | constexpr void url::clear_pathname() { path.clear(); } | 
6743  |  |  | 
6744  | 0  | constexpr void url::clear_search() { query = std::nullopt; } | 
6745  |  |  | 
6746  | 0  | [[nodiscard]] constexpr bool url::has_hash() const noexcept { | 
6747  | 0  |   return hash.has_value();  | 
6748  | 0  | }  | 
6749  |  |  | 
6750  | 0  | [[nodiscard]] constexpr bool url::has_search() const noexcept { | 
6751  | 0  |   return query.has_value();  | 
6752  | 0  | }  | 
6753  |  |  | 
6754  | 0  | constexpr void url::set_protocol_as_file() { type = ada::scheme::type::FILE; } | 
6755  |  |  | 
6756  | 0  | inline void url::set_scheme(std::string &&new_scheme) noexcept { | 
6757  | 0  |   type = ada::scheme::get_scheme_type(new_scheme);  | 
6758  | 0  |   // We only move the 'scheme' if it is non-special.  | 
6759  | 0  |   if (!is_special()) { | 
6760  | 0  |     non_special_scheme = std::move(new_scheme);  | 
6761  | 0  |   }  | 
6762  | 0  | }  | 
6763  |  |  | 
6764  | 0  | constexpr void url::copy_scheme(ada::url &&u) noexcept { | 
6765  | 0  |   non_special_scheme = u.non_special_scheme;  | 
6766  | 0  |   type = u.type;  | 
6767  | 0  | }  | 
6768  |  |  | 
6769  | 0  | constexpr void url::copy_scheme(const ada::url &u) { | 
6770  | 0  |   non_special_scheme = u.non_special_scheme;  | 
6771  | 0  |   type = u.type;  | 
6772  | 0  | }  | 
6773  |  |  | 
6774  | 0  | [[nodiscard]] ada_really_inline std::string url::get_href() const noexcept { | 
6775  | 0  |   std::string output = get_protocol();  | 
6776  |  | 
  | 
6777  | 0  |   if (host.has_value()) { | 
6778  | 0  |     output += "//";  | 
6779  | 0  |     if (has_credentials()) { | 
6780  | 0  |       output += username;  | 
6781  | 0  |       if (!password.empty()) { | 
6782  | 0  |         output += ":" + get_password();  | 
6783  | 0  |       }  | 
6784  | 0  |       output += "@";  | 
6785  | 0  |     }  | 
6786  | 0  |     output += host.value();  | 
6787  | 0  |     if (port.has_value()) { | 
6788  | 0  |       output += ":" + get_port();  | 
6789  | 0  |     }  | 
6790  | 0  |   } else if (!has_opaque_path && path.starts_with("//")) { | 
6791  |  |     // If url's host is null, url does not have an opaque path, url's path's  | 
6792  |  |     // size is greater than 1, and url's path[0] is the empty string, then  | 
6793  |  |     // append U+002F (/) followed by U+002E (.) to output.  | 
6794  | 0  |     output += "/.";  | 
6795  | 0  |   }  | 
6796  | 0  |   output += path;  | 
6797  | 0  |   if (query.has_value()) { | 
6798  | 0  |     output += "?" + query.value();  | 
6799  | 0  |   }  | 
6800  | 0  |   if (hash.has_value()) { | 
6801  | 0  |     output += "#" + hash.value();  | 
6802  | 0  |   }  | 
6803  | 0  |   return output;  | 
6804  | 0  | }  | 
6805  |  |  | 
6806  |  | ada_really_inline size_t url::parse_port(std::string_view view,  | 
6807  | 0  |                                          bool check_trailing_content) noexcept { | 
6808  | 0  |   ada_log("parse_port('", view, "') ", view.size()); | 
6809  | 0  |   if (!view.empty() && view[0] == '-') { | 
6810  | 0  |     ada_log("parse_port: view[0] == '0' && view.size() > 1"); | 
6811  | 0  |     is_valid = false;  | 
6812  | 0  |     return 0;  | 
6813  | 0  |   }  | 
6814  | 0  |   uint16_t parsed_port{}; | 
6815  | 0  |   auto r = std::from_chars(view.data(), view.data() + view.size(), parsed_port);  | 
6816  | 0  |   if (r.ec == std::errc::result_out_of_range) { | 
6817  | 0  |     ada_log("parse_port: r.ec == std::errc::result_out_of_range"); | 
6818  | 0  |     is_valid = false;  | 
6819  | 0  |     return 0;  | 
6820  | 0  |   }  | 
6821  | 0  |   ada_log("parse_port: ", parsed_port); | 
6822  | 0  |   const auto consumed = size_t(r.ptr - view.data());  | 
6823  | 0  |   ada_log("parse_port: consumed ", consumed); | 
6824  | 0  |   if (check_trailing_content) { | 
6825  | 0  |     is_valid &=  | 
6826  | 0  |         (consumed == view.size() || view[consumed] == '/' ||  | 
6827  | 0  |          view[consumed] == '?' || (is_special() && view[consumed] == '\\'));  | 
6828  | 0  |   }  | 
6829  | 0  |   ada_log("parse_port: is_valid = ", is_valid); | 
6830  | 0  |   if (is_valid) { | 
6831  | 0  |     // scheme_default_port can return 0, and we should allow 0 as a base port.  | 
6832  | 0  |     auto default_port = scheme_default_port();  | 
6833  | 0  |     bool is_port_valid = (default_port == 0 && parsed_port == 0) ||  | 
6834  | 0  |                          (default_port != parsed_port);  | 
6835  | 0  |     port = (r.ec == std::errc() && is_port_valid) ? std::optional(parsed_port)  | 
6836  | 0  |                                                   : std::nullopt;  | 
6837  | 0  |   }  | 
6838  | 0  |   return consumed;  | 
6839  | 0  | }  | 
6840  |  |  | 
6841  |  | }  // namespace ada  | 
6842  |  |  | 
6843  |  | #endif  // ADA_URL_H  | 
6844  |  | /* end file include/ada/url-inl.h */  | 
6845  |  | /* begin file include/ada/url_components-inl.h */  | 
6846  |  | /**  | 
6847  |  |  * @file url_components.h  | 
6848  |  |  * @brief Declaration for the URL Components  | 
6849  |  |  */  | 
6850  |  | #ifndef ADA_URL_COMPONENTS_INL_H  | 
6851  |  | #define ADA_URL_COMPONENTS_INL_H  | 
6852  |  |  | 
6853  |  |  | 
6854  |  | namespace ada { | 
6855  |  |  | 
6856  |  | [[nodiscard]] constexpr bool url_components::check_offset_consistency()  | 
6857  | 0  |     const noexcept { | 
6858  | 0  |   /**  | 
6859  | 0  |    * https://user:pass@example.com:1234/foo/bar?baz#quux  | 
6860  | 0  |    *       |     |    |          | ^^^^|       |   |  | 
6861  | 0  |    *       |     |    |          | |   |       |   `----- hash_start  | 
6862  | 0  |    *       |     |    |          | |   |       `--------- search_start  | 
6863  | 0  |    *       |     |    |          | |   `----------------- pathname_start  | 
6864  | 0  |    *       |     |    |          | `--------------------- port  | 
6865  | 0  |    *       |     |    |          `----------------------- host_end  | 
6866  | 0  |    *       |     |    `---------------------------------- host_start  | 
6867  | 0  |    *       |     `--------------------------------------- username_end  | 
6868  | 0  |    *       `--------------------------------------------- protocol_end  | 
6869  | 0  |    */  | 
6870  | 0  |   // These conditions can be made more strict.  | 
6871  | 0  |   if (protocol_end == url_components::omitted) { | 
6872  | 0  |     return false;  | 
6873  | 0  |   }  | 
6874  | 0  |   uint32_t index = protocol_end;  | 
6875  | 0  | 
  | 
6876  | 0  |   if (username_end == url_components::omitted) { | 
6877  | 0  |     return false;  | 
6878  | 0  |   }  | 
6879  | 0  |   if (username_end < index) { | 
6880  | 0  |     return false;  | 
6881  | 0  |   }  | 
6882  | 0  |   index = username_end;  | 
6883  | 0  | 
  | 
6884  | 0  |   if (host_start == url_components::omitted) { | 
6885  | 0  |     return false;  | 
6886  | 0  |   }  | 
6887  | 0  |   if (host_start < index) { | 
6888  | 0  |     return false;  | 
6889  | 0  |   }  | 
6890  | 0  |   index = host_start;  | 
6891  | 0  | 
  | 
6892  | 0  |   if (port != url_components::omitted) { | 
6893  | 0  |     if (port > 0xffff) { | 
6894  | 0  |       return false;  | 
6895  | 0  |     }  | 
6896  | 0  |     uint32_t port_length = helpers::fast_digit_count(port) + 1;  | 
6897  | 0  |     if (index + port_length < index) { | 
6898  | 0  |       return false;  | 
6899  | 0  |     }  | 
6900  | 0  |     index += port_length;  | 
6901  | 0  |   }  | 
6902  | 0  | 
  | 
6903  | 0  |   if (pathname_start == url_components::omitted) { | 
6904  | 0  |     return false;  | 
6905  | 0  |   }  | 
6906  | 0  |   if (pathname_start < index) { | 
6907  | 0  |     return false;  | 
6908  | 0  |   }  | 
6909  | 0  |   index = pathname_start;  | 
6910  | 0  | 
  | 
6911  | 0  |   if (search_start != url_components::omitted) { | 
6912  | 0  |     if (search_start < index) { | 
6913  | 0  |       return false;  | 
6914  | 0  |     }  | 
6915  | 0  |     index = search_start;  | 
6916  | 0  |   }  | 
6917  | 0  | 
  | 
6918  | 0  |   if (hash_start != url_components::omitted) { | 
6919  | 0  |     if (hash_start < index) { | 
6920  | 0  |       return false;  | 
6921  | 0  |     }  | 
6922  | 0  |   }  | 
6923  | 0  | 
  | 
6924  | 0  |   return true;  | 
6925  | 0  | }  | 
6926  |  |  | 
6927  |  | }  // namespace ada  | 
6928  |  | #endif  | 
6929  |  | /* end file include/ada/url_components-inl.h */  | 
6930  |  | /* begin file include/ada/url_aggregator.h */  | 
6931  |  | /**  | 
6932  |  |  * @file url_aggregator.h  | 
6933  |  |  * @brief Declaration for the basic URL definitions  | 
6934  |  |  */  | 
6935  |  | #ifndef ADA_URL_AGGREGATOR_H  | 
6936  |  | #define ADA_URL_AGGREGATOR_H  | 
6937  |  |  | 
6938  |  | #include <ostream>  | 
6939  |  | #include <string>  | 
6940  |  | #include <string_view>  | 
6941  |  | #include <variant>  | 
6942  |  |  | 
6943  |  |  | 
6944  |  | namespace ada { | 
6945  |  |  | 
6946  |  | namespace parser {} | 
6947  |  |  | 
6948  |  | /**  | 
6949  |  |  * @brief Lightweight URL struct.  | 
6950  |  |  *  | 
6951  |  |  * @details The url_aggregator class aims to minimize temporary memory  | 
6952  |  |  * allocation while representing a parsed URL. Internally, it contains a single  | 
6953  |  |  * normalized URL (the href), and it makes available the components, mostly  | 
6954  |  |  * using std::string_view.  | 
6955  |  |  */  | 
6956  |  | struct url_aggregator : url_base { | 
6957  | 0  |   url_aggregator() = default;  | 
6958  |  |   url_aggregator(const url_aggregator &u) = default;  | 
6959  | 0  |   url_aggregator(url_aggregator &&u) noexcept = default;  | 
6960  | 0  |   url_aggregator &operator=(url_aggregator &&u) noexcept = default;  | 
6961  |  |   url_aggregator &operator=(const url_aggregator &u) = default;  | 
6962  | 0  |   ~url_aggregator() override = default;  | 
6963  |  |  | 
6964  |  |   bool set_href(std::string_view input);  | 
6965  |  |   bool set_host(std::string_view input);  | 
6966  |  |   bool set_hostname(std::string_view input);  | 
6967  |  |   bool set_protocol(std::string_view input);  | 
6968  |  |   bool set_username(std::string_view input);  | 
6969  |  |   bool set_password(std::string_view input);  | 
6970  |  |   bool set_port(std::string_view input);  | 
6971  |  |   bool set_pathname(std::string_view input);  | 
6972  |  |   void set_search(std::string_view input);  | 
6973  |  |   void set_hash(std::string_view input);  | 
6974  |  |  | 
6975  |  |   [[nodiscard]] bool has_valid_domain() const noexcept override;  | 
6976  |  |   /**  | 
6977  |  |    * The origin getter steps are to return the serialization of this's URL's  | 
6978  |  |    * origin. [HTML]  | 
6979  |  |    * @return a newly allocated string.  | 
6980  |  |    * @see https://url.spec.whatwg.org/#concept-url-origin  | 
6981  |  |    */  | 
6982  |  |   [[nodiscard]] std::string get_origin() const noexcept override;  | 
6983  |  |   /**  | 
6984  |  |    * Return the normalized string.  | 
6985  |  |    * This function does not allocate memory.  | 
6986  |  |    * It is highly efficient.  | 
6987  |  |    * @return a constant reference to the underlying normalized URL.  | 
6988  |  |    * @see https://url.spec.whatwg.org/#dom-url-href  | 
6989  |  |    * @see https://url.spec.whatwg.org/#concept-url-serializer  | 
6990  |  |    */  | 
6991  |  |   [[nodiscard]] constexpr std::string_view get_href() const noexcept  | 
6992  |  |       ada_lifetime_bound;  | 
6993  |  |   /**  | 
6994  |  |    * The username getter steps are to return this's URL's username.  | 
6995  |  |    * This function does not allocate memory.  | 
6996  |  |    * @return a lightweight std::string_view.  | 
6997  |  |    * @see https://url.spec.whatwg.org/#dom-url-username  | 
6998  |  |    */  | 
6999  |  |   [[nodiscard]] std::string_view get_username() const noexcept  | 
7000  |  |       ada_lifetime_bound;  | 
7001  |  |   /**  | 
7002  |  |    * The password getter steps are to return this's URL's password.  | 
7003  |  |    * This function does not allocate memory.  | 
7004  |  |    * @return a lightweight std::string_view.  | 
7005  |  |    * @see https://url.spec.whatwg.org/#dom-url-password  | 
7006  |  |    */  | 
7007  |  |   [[nodiscard]] std::string_view get_password() const noexcept  | 
7008  |  |       ada_lifetime_bound;  | 
7009  |  |   /**  | 
7010  |  |    * Return this's URL's port, serialized.  | 
7011  |  |    * This function does not allocate memory.  | 
7012  |  |    * @return a lightweight std::string_view.  | 
7013  |  |    * @see https://url.spec.whatwg.org/#dom-url-port  | 
7014  |  |    */  | 
7015  |  |   [[nodiscard]] std::string_view get_port() const noexcept ada_lifetime_bound;  | 
7016  |  |   /**  | 
7017  |  |    * Return U+0023 (#), followed by this's URL's fragment.  | 
7018  |  |    * This function does not allocate memory.  | 
7019  |  |    * @return a lightweight std::string_view..  | 
7020  |  |    * @see https://url.spec.whatwg.org/#dom-url-hash  | 
7021  |  |    */  | 
7022  |  |   [[nodiscard]] std::string_view get_hash() const noexcept ada_lifetime_bound;  | 
7023  |  |   /**  | 
7024  |  |    * Return url's host, serialized, followed by U+003A (:) and url's port,  | 
7025  |  |    * serialized.  | 
7026  |  |    * This function does not allocate memory.  | 
7027  |  |    * When there is no host, this function returns the empty view.  | 
7028  |  |    * @return a lightweight std::string_view.  | 
7029  |  |    * @see https://url.spec.whatwg.org/#dom-url-host  | 
7030  |  |    */  | 
7031  |  |   [[nodiscard]] std::string_view get_host() const noexcept ada_lifetime_bound;  | 
7032  |  |   /**  | 
7033  |  |    * Return this's URL's host, serialized.  | 
7034  |  |    * This function does not allocate memory.  | 
7035  |  |    * When there is no host, this function returns the empty view.  | 
7036  |  |    * @return a lightweight std::string_view.  | 
7037  |  |    * @see https://url.spec.whatwg.org/#dom-url-hostname  | 
7038  |  |    */  | 
7039  |  |   [[nodiscard]] std::string_view get_hostname() const noexcept  | 
7040  |  |       ada_lifetime_bound;  | 
7041  |  |   /**  | 
7042  |  |    * The pathname getter steps are to return the result of URL path serializing  | 
7043  |  |    * this's URL.  | 
7044  |  |    * This function does not allocate memory.  | 
7045  |  |    * @return a lightweight std::string_view.  | 
7046  |  |    * @see https://url.spec.whatwg.org/#dom-url-pathname  | 
7047  |  |    */  | 
7048  |  |   [[nodiscard]] constexpr std::string_view get_pathname() const noexcept  | 
7049  |  |       ada_lifetime_bound;  | 
7050  |  |   /**  | 
7051  |  |    * Compute the pathname length in bytes without instantiating a view or a  | 
7052  |  |    * string.  | 
7053  |  |    * @return size of the pathname in bytes  | 
7054  |  |    * @see https://url.spec.whatwg.org/#dom-url-pathname  | 
7055  |  |    */  | 
7056  |  |   [[nodiscard]] ada_really_inline uint32_t get_pathname_length() const noexcept;  | 
7057  |  |   /**  | 
7058  |  |    * Return U+003F (?), followed by this's URL's query.  | 
7059  |  |    * This function does not allocate memory.  | 
7060  |  |    * @return a lightweight std::string_view.  | 
7061  |  |    * @see https://url.spec.whatwg.org/#dom-url-search  | 
7062  |  |    */  | 
7063  |  |   [[nodiscard]] std::string_view get_search() const noexcept ada_lifetime_bound;  | 
7064  |  |   /**  | 
7065  |  |    * The protocol getter steps are to return this's URL's scheme, followed by  | 
7066  |  |    * U+003A (:).  | 
7067  |  |    * This function does not allocate memory.  | 
7068  |  |    * @return a lightweight std::string_view.  | 
7069  |  |    * @see https://url.spec.whatwg.org/#dom-url-protocol  | 
7070  |  |    */  | 
7071  |  |   [[nodiscard]] std::string_view get_protocol() const noexcept  | 
7072  |  |       ada_lifetime_bound;  | 
7073  |  |  | 
7074  |  |   /**  | 
7075  |  |    * A URL includes credentials if its username or password is not the empty  | 
7076  |  |    * string.  | 
7077  |  |    */  | 
7078  |  |   [[nodiscard]] ada_really_inline constexpr bool has_credentials()  | 
7079  |  |       const noexcept;  | 
7080  |  |  | 
7081  |  |   /**  | 
7082  |  |    * Useful for implementing efficient serialization for the URL.  | 
7083  |  |    *  | 
7084  |  |    * https://user:pass@example.com:1234/foo/bar?baz#quux  | 
7085  |  |    *       |     |    |          | ^^^^|       |   |  | 
7086  |  |    *       |     |    |          | |   |       |   `----- hash_start  | 
7087  |  |    *       |     |    |          | |   |       `--------- search_start  | 
7088  |  |    *       |     |    |          | |   `----------------- pathname_start  | 
7089  |  |    *       |     |    |          | `--------------------- port  | 
7090  |  |    *       |     |    |          `----------------------- host_end  | 
7091  |  |    *       |     |    `---------------------------------- host_start  | 
7092  |  |    *       |     `--------------------------------------- username_end  | 
7093  |  |    *       `--------------------------------------------- protocol_end  | 
7094  |  |    *  | 
7095  |  |    * Inspired after servo/url  | 
7096  |  |    *  | 
7097  |  |    * @return a constant reference to the underlying component attribute.  | 
7098  |  |    *  | 
7099  |  |    * @see  | 
7100  |  |    * https://github.com/servo/rust-url/blob/b65a45515c10713f6d212e6726719a020203cc98/url/src/quirks.rs#L31  | 
7101  |  |    */  | 
7102  |  |   [[nodiscard]] ada_really_inline const url_components &get_components()  | 
7103  |  |       const noexcept;  | 
7104  |  |   /**  | 
7105  |  |    * Returns a string representation of this URL.  | 
7106  |  |    */  | 
7107  |  |   [[nodiscard]] std::string to_string() const override;  | 
7108  |  |   /**  | 
7109  |  |    * Returns a string diagram of this URL.  | 
7110  |  |    */  | 
7111  |  |   [[nodiscard]] std::string to_diagram() const;  | 
7112  |  |  | 
7113  |  |   /**  | 
7114  |  |    * Verifies that the parsed URL could be valid. Useful for debugging purposes.  | 
7115  |  |    * @return true if the URL is valid, otherwise return true of the offsets are  | 
7116  |  |    * possible.  | 
7117  |  |    */  | 
7118  |  |   [[nodiscard]] constexpr bool validate() const noexcept;  | 
7119  |  |  | 
7120  |  |   /** @return true if it has an host but it is the empty string */  | 
7121  |  |   [[nodiscard]] constexpr bool has_empty_hostname() const noexcept;  | 
7122  |  |   /** @return true if it has a host (included an empty host) */  | 
7123  |  |   [[nodiscard]] constexpr bool has_hostname() const noexcept;  | 
7124  |  |   /** @return true if the URL has a non-empty username */  | 
7125  |  |   [[nodiscard]] constexpr bool has_non_empty_username() const noexcept;  | 
7126  |  |   /** @return true if the URL has a non-empty password */  | 
7127  |  |   [[nodiscard]] constexpr bool has_non_empty_password() const noexcept;  | 
7128  |  |   /** @return true if the URL has a (non default) port */  | 
7129  |  |   [[nodiscard]] constexpr bool has_port() const noexcept;  | 
7130  |  |   /** @return true if the URL has a password */  | 
7131  |  |   [[nodiscard]] constexpr bool has_password() const noexcept;  | 
7132  |  |   /** @return true if the URL has a hash component */  | 
7133  |  |   [[nodiscard]] constexpr bool has_hash() const noexcept override;  | 
7134  |  |   /** @return true if the URL has a search component */  | 
7135  |  |   [[nodiscard]] constexpr bool has_search() const noexcept override;  | 
7136  |  |  | 
7137  |  |   inline void clear_port();  | 
7138  |  |   inline void clear_hash();  | 
7139  |  |   inline void clear_search() override;  | 
7140  |  |  | 
7141  |  |  private:  | 
7142  |  |   // helper methods  | 
7143  |  |   friend void helpers::strip_trailing_spaces_from_opaque_path<url_aggregator>(  | 
7144  |  |       url_aggregator &url) noexcept;  | 
7145  |  |   // parse_url methods  | 
7146  |  |   friend url_aggregator parser::parse_url<url_aggregator>(  | 
7147  |  |       std::string_view, const url_aggregator *);  | 
7148  |  |  | 
7149  |  |   friend url_aggregator parser::parse_url_impl<url_aggregator, true>(  | 
7150  |  |       std::string_view, const url_aggregator *);  | 
7151  |  |   friend url_aggregator parser::parse_url_impl<url_aggregator, false>(  | 
7152  |  |       std::string_view, const url_aggregator *);  | 
7153  |  |  | 
7154  |  | #if ADA_INCLUDE_URL_PATTERN  | 
7155  |  |   // url_pattern methods  | 
7156  |  |   template <url_pattern_regex::regex_concept regex_provider>  | 
7157  |  |   friend tl::expected<url_pattern<regex_provider>, errors>  | 
7158  |  |   parse_url_pattern_impl(  | 
7159  |  |       std::variant<std::string_view, url_pattern_init> &&input,  | 
7160  |  |       const std::string_view *base_url, const url_pattern_options *options);  | 
7161  |  | #endif  // ADA_INCLUDE_URL_PATTERN  | 
7162  |  |  | 
7163  |  |   std::string buffer{}; | 
7164  |  |   url_components components{}; | 
7165  |  |  | 
7166  |  |   /**  | 
7167  |  |    * Returns true if neither the search, nor the hash nor the pathname  | 
7168  |  |    * have been set.  | 
7169  |  |    * @return true if the buffer is ready to receive the path.  | 
7170  |  |    */  | 
7171  |  |   [[nodiscard]] ada_really_inline bool is_at_path() const noexcept;  | 
7172  |  |  | 
7173  |  |   inline void add_authority_slashes_if_needed() noexcept;  | 
7174  |  |  | 
7175  |  |   /**  | 
7176  |  |    * To optimize performance, you may indicate how much memory to allocate  | 
7177  |  |    * within this instance.  | 
7178  |  |    */  | 
7179  |  |   constexpr void reserve(uint32_t capacity);  | 
7180  |  |  | 
7181  |  |   ada_really_inline size_t parse_port(  | 
7182  |  |       std::string_view view, bool check_trailing_content) noexcept override;  | 
7183  |  |  | 
7184  | 0  |   ada_really_inline size_t parse_port(std::string_view view) noexcept override { | 
7185  | 0  |     return this->parse_port(view, false);  | 
7186  | 0  |   }  | 
7187  |  |  | 
7188  |  |   /**  | 
7189  |  |    * Return true on success. The 'in_place' parameter indicates whether the  | 
7190  |  |    * the string_view input is pointing in the buffer. When in_place is false,  | 
7191  |  |    * we must nearly always update the buffer.  | 
7192  |  |    * @see https://url.spec.whatwg.org/#concept-ipv4-parser  | 
7193  |  |    */  | 
7194  |  |   [[nodiscard]] bool parse_ipv4(std::string_view input, bool in_place);  | 
7195  |  |  | 
7196  |  |   /**  | 
7197  |  |    * Return true on success.  | 
7198  |  |    * @see https://url.spec.whatwg.org/#concept-ipv6-parser  | 
7199  |  |    */  | 
7200  |  |   [[nodiscard]] bool parse_ipv6(std::string_view input);  | 
7201  |  |  | 
7202  |  |   /**  | 
7203  |  |    * Return true on success.  | 
7204  |  |    * @see https://url.spec.whatwg.org/#concept-opaque-host-parser  | 
7205  |  |    */  | 
7206  |  |   [[nodiscard]] bool parse_opaque_host(std::string_view input);  | 
7207  |  |  | 
7208  |  |   ada_really_inline void parse_path(std::string_view input);  | 
7209  |  |  | 
7210  |  |   /**  | 
7211  |  |    * A URL cannot have a username/password/port if its host is null or the empty  | 
7212  |  |    * string, or its scheme is "file".  | 
7213  |  |    */  | 
7214  |  |   [[nodiscard]] constexpr bool cannot_have_credentials_or_port() const;  | 
7215  |  |  | 
7216  |  |   template <bool override_hostname = false>  | 
7217  |  |   bool set_host_or_hostname(std::string_view input);  | 
7218  |  |  | 
7219  |  |   ada_really_inline bool parse_host(std::string_view input);  | 
7220  |  |  | 
7221  |  |   inline void update_base_authority(std::string_view base_buffer,  | 
7222  |  |                                     const url_components &base);  | 
7223  |  |   inline void update_unencoded_base_hash(std::string_view input);  | 
7224  |  |   inline void update_base_hostname(std::string_view input);  | 
7225  |  |   inline void update_base_search(std::string_view input);  | 
7226  |  |   inline void update_base_search(std::string_view input,  | 
7227  |  |                                  const uint8_t *query_percent_encode_set);  | 
7228  |  |   inline void update_base_pathname(std::string_view input);  | 
7229  |  |   inline void update_base_username(std::string_view input);  | 
7230  |  |   inline void append_base_username(std::string_view input);  | 
7231  |  |   inline void update_base_password(std::string_view input);  | 
7232  |  |   inline void append_base_password(std::string_view input);  | 
7233  |  |   inline void update_base_port(uint32_t input);  | 
7234  |  |   inline void append_base_pathname(std::string_view input);  | 
7235  |  |   [[nodiscard]] inline uint32_t retrieve_base_port() const;  | 
7236  |  |   constexpr void clear_hostname();  | 
7237  |  |   constexpr void clear_password();  | 
7238  |  |   constexpr void clear_pathname() override;  | 
7239  |  |   [[nodiscard]] constexpr bool has_dash_dot() const noexcept;  | 
7240  |  |   void delete_dash_dot();  | 
7241  |  |   inline void consume_prepared_path(std::string_view input);  | 
7242  |  |   template <bool has_state_override = false>  | 
7243  |  |   [[nodiscard]] ada_really_inline bool parse_scheme_with_colon(  | 
7244  |  |       std::string_view input);  | 
7245  |  |   ada_really_inline uint32_t replace_and_resize(uint32_t start, uint32_t end,  | 
7246  |  |                                                 std::string_view input);  | 
7247  |  |   [[nodiscard]] constexpr bool has_authority() const noexcept;  | 
7248  |  |   constexpr void set_protocol_as_file();  | 
7249  |  |   inline void set_scheme(std::string_view new_scheme) noexcept;  | 
7250  |  |   /**  | 
7251  |  |    * Fast function to set the scheme from a view with a colon in the  | 
7252  |  |    * buffer, does not change type.  | 
7253  |  |    */  | 
7254  |  |   inline void set_scheme_from_view_with_colon(  | 
7255  |  |       std::string_view new_scheme_with_colon) noexcept;  | 
7256  |  |   inline void copy_scheme(const url_aggregator &u) noexcept;  | 
7257  |  |  | 
7258  |  |   inline void update_host_to_base_host(const std::string_view input) noexcept;  | 
7259  |  |  | 
7260  |  | };  // url_aggregator  | 
7261  |  |  | 
7262  |  | inline std::ostream &operator<<(std::ostream &out, const url &u);  | 
7263  |  | }  // namespace ada  | 
7264  |  |  | 
7265  |  | #endif  | 
7266  |  | /* end file include/ada/url_aggregator.h */  | 
7267  |  | /* begin file include/ada/url_aggregator-inl.h */  | 
7268  |  | /**  | 
7269  |  |  * @file url_aggregator-inl.h  | 
7270  |  |  * @brief Inline functions for url aggregator  | 
7271  |  |  */  | 
7272  |  | #ifndef ADA_URL_AGGREGATOR_INL_H  | 
7273  |  | #define ADA_URL_AGGREGATOR_INL_H  | 
7274  |  |  | 
7275  |  | /* begin file include/ada/unicode-inl.h */  | 
7276  |  | /**  | 
7277  |  |  * @file unicode-inl.h  | 
7278  |  |  * @brief Definitions for unicode operations.  | 
7279  |  |  */  | 
7280  |  | #ifndef ADA_UNICODE_INL_H  | 
7281  |  | #define ADA_UNICODE_INL_H  | 
7282  |  |  | 
7283  |  | /**  | 
7284  |  |  * Unicode operations. These functions are not part of our public API and may  | 
7285  |  |  * change at any time.  | 
7286  |  |  *  | 
7287  |  |  * private  | 
7288  |  |  * @namespace ada::unicode  | 
7289  |  |  * @brief Includes the declarations for unicode operations  | 
7290  |  |  */  | 
7291  |  | namespace ada::unicode { | 
7292  |  | ada_really_inline size_t percent_encode_index(const std::string_view input,  | 
7293  | 0  |                                               const uint8_t character_set[]) { | 
7294  | 0  |   const char* data = input.data();  | 
7295  | 0  |   const size_t size = input.size();  | 
7296  | 0  | 
  | 
7297  | 0  |   // Process 8 bytes at a time using unrolled loop  | 
7298  | 0  |   size_t i = 0;  | 
7299  | 0  |   for (; i + 8 <= size; i += 8) { | 
7300  | 0  |     unsigned char chunk[8];  | 
7301  | 0  |     std::memcpy(&chunk, data + i,  | 
7302  | 0  |                 8);  // entices compiler to unconditionally process 8 characters  | 
7303  | 0  | 
  | 
7304  | 0  |     // Check 8 characters at once  | 
7305  | 0  |     for (size_t j = 0; j < 8; j++) { | 
7306  | 0  |       if (character_sets::bit_at(character_set, chunk[j])) { | 
7307  | 0  |         return i + j;  | 
7308  | 0  |       }  | 
7309  | 0  |     }  | 
7310  | 0  |   }  | 
7311  | 0  | 
  | 
7312  | 0  |   // Handle remaining bytes  | 
7313  | 0  |   for (; i < size; i++) { | 
7314  | 0  |     if (character_sets::bit_at(character_set, data[i])) { | 
7315  | 0  |       return i;  | 
7316  | 0  |     }  | 
7317  | 0  |   }  | 
7318  | 0  | 
  | 
7319  | 0  |   return size;  | 
7320  | 0  | }  | 
7321  |  | }  // namespace ada::unicode  | 
7322  |  |  | 
7323  |  | #endif  // ADA_UNICODE_INL_H  | 
7324  |  | /* end file include/ada/unicode-inl.h */  | 
7325  |  |  | 
7326  |  | #include <charconv>  | 
7327  |  | #include <ostream>  | 
7328  |  | #include <string_view>  | 
7329  |  |  | 
7330  |  | namespace ada { | 
7331  |  |  | 
7332  |  | inline void url_aggregator::update_base_authority(  | 
7333  | 0  |     std::string_view base_buffer, const ada::url_components &base) { | 
7334  | 0  |   std::string_view input = base_buffer.substr(  | 
7335  | 0  |       base.protocol_end, base.host_start - base.protocol_end);  | 
7336  | 0  |   ada_log("url_aggregator::update_base_authority ", input); | 
7337  | 0  | 
  | 
7338  | 0  |   bool input_starts_with_dash = input.starts_with("//"); | 
7339  | 0  |   uint32_t diff = components.host_start - components.protocol_end;  | 
7340  | 0  | 
  | 
7341  | 0  |   buffer.erase(components.protocol_end,  | 
7342  | 0  |                components.host_start - components.protocol_end);  | 
7343  | 0  |   components.username_end = components.protocol_end;  | 
7344  | 0  | 
  | 
7345  | 0  |   if (input_starts_with_dash) { | 
7346  | 0  |     input.remove_prefix(2);  | 
7347  | 0  |     diff += 2;  // add "//"  | 
7348  | 0  |     buffer.insert(components.protocol_end, "//");  | 
7349  | 0  |     components.username_end += 2;  | 
7350  | 0  |   }  | 
7351  | 0  | 
  | 
7352  | 0  |   size_t password_delimiter = input.find(':'); | 
7353  | 0  | 
  | 
7354  | 0  |   // Check if input contains both username and password by checking the  | 
7355  | 0  |   // delimiter: ":" A typical input that contains authority would be "user:pass"  | 
7356  | 0  |   if (password_delimiter != std::string_view::npos) { | 
7357  | 0  |     // Insert both username and password  | 
7358  | 0  |     std::string_view username = input.substr(0, password_delimiter);  | 
7359  | 0  |     std::string_view password = input.substr(password_delimiter + 1);  | 
7360  | 0  | 
  | 
7361  | 0  |     buffer.insert(components.protocol_end + diff, username);  | 
7362  | 0  |     diff += uint32_t(username.size());  | 
7363  | 0  |     buffer.insert(components.protocol_end + diff, ":");  | 
7364  | 0  |     components.username_end = components.protocol_end + diff;  | 
7365  | 0  |     buffer.insert(components.protocol_end + diff + 1, password);  | 
7366  | 0  |     diff += uint32_t(password.size()) + 1;  | 
7367  | 0  |   } else if (!input.empty()) { | 
7368  | 0  |     // Insert only username  | 
7369  | 0  |     buffer.insert(components.protocol_end + diff, input);  | 
7370  | 0  |     components.username_end =  | 
7371  | 0  |         components.protocol_end + diff + uint32_t(input.size());  | 
7372  | 0  |     diff += uint32_t(input.size());  | 
7373  | 0  |   }  | 
7374  | 0  | 
  | 
7375  | 0  |   components.host_start += diff;  | 
7376  | 0  | 
  | 
7377  | 0  |   if (buffer.size() > base.host_start && buffer[base.host_start] != '@') { | 
7378  | 0  |     buffer.insert(components.host_start, "@");  | 
7379  | 0  |     diff++;  | 
7380  | 0  |   }  | 
7381  | 0  |   components.host_end += diff;  | 
7382  | 0  |   components.pathname_start += diff;  | 
7383  | 0  |   if (components.search_start != url_components::omitted) { | 
7384  | 0  |     components.search_start += diff;  | 
7385  | 0  |   }  | 
7386  | 0  |   if (components.hash_start != url_components::omitted) { | 
7387  | 0  |     components.hash_start += diff;  | 
7388  | 0  |   }  | 
7389  | 0  | }  | 
7390  |  |  | 
7391  | 0  | inline void url_aggregator::update_unencoded_base_hash(std::string_view input) { | 
7392  | 0  |   ada_log("url_aggregator::update_unencoded_base_hash ", input, " [", | 
7393  | 0  |           input.size(), " bytes], buffer is '", buffer, "' [", buffer.size(),  | 
7394  | 0  |           " bytes] components.hash_start = ", components.hash_start);  | 
7395  | 0  |   ADA_ASSERT_TRUE(validate());  | 
7396  | 0  |   ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));  | 
7397  | 0  |   if (components.hash_start != url_components::omitted) { | 
7398  | 0  |     buffer.resize(components.hash_start);  | 
7399  | 0  |   }  | 
7400  | 0  |   components.hash_start = uint32_t(buffer.size());  | 
7401  | 0  |   buffer += "#";  | 
7402  | 0  |   bool encoding_required = unicode::percent_encode<true>(  | 
7403  | 0  |       input, ada::character_sets::FRAGMENT_PERCENT_ENCODE, buffer);  | 
7404  | 0  |   // When encoding_required is false, then buffer is left unchanged, and percent  | 
7405  | 0  |   // encoding was not deemed required.  | 
7406  | 0  |   if (!encoding_required) { | 
7407  | 0  |     buffer.append(input);  | 
7408  | 0  |   }  | 
7409  | 0  |   ada_log("url_aggregator::update_unencoded_base_hash final buffer is '", | 
7410  | 0  |           buffer, "' [", buffer.size(), " bytes]");  | 
7411  | 0  |   ADA_ASSERT_TRUE(validate());  | 
7412  | 0  | }  | 
7413  |  |  | 
7414  |  | ada_really_inline uint32_t url_aggregator::replace_and_resize(  | 
7415  | 0  |     uint32_t start, uint32_t end, std::string_view input) { | 
7416  | 0  |   uint32_t current_length = end - start;  | 
7417  | 0  |   uint32_t input_size = uint32_t(input.size());  | 
7418  | 0  |   uint32_t new_difference = input_size - current_length;  | 
7419  | 0  | 
  | 
7420  | 0  |   if (current_length == 0) { | 
7421  | 0  |     buffer.insert(start, input);  | 
7422  | 0  |   } else if (input_size == current_length) { | 
7423  | 0  |     buffer.replace(start, input_size, input);  | 
7424  | 0  |   } else if (input_size < current_length) { | 
7425  | 0  |     buffer.erase(start, current_length - input_size);  | 
7426  | 0  |     buffer.replace(start, input_size, input);  | 
7427  | 0  |   } else { | 
7428  | 0  |     buffer.replace(start, current_length, input.substr(0, current_length));  | 
7429  | 0  |     buffer.insert(start + current_length, input.substr(current_length));  | 
7430  | 0  |   }  | 
7431  | 0  | 
  | 
7432  | 0  |   return new_difference;  | 
7433  | 0  | }  | 
7434  |  |  | 
7435  | 0  | inline void url_aggregator::update_base_hostname(const std::string_view input) { | 
7436  | 0  |   ada_log("url_aggregator::update_base_hostname ", input, " [", input.size(), | 
7437  | 0  |           " bytes], buffer is '", buffer, "' [", buffer.size(), " bytes]");  | 
7438  | 0  |   ADA_ASSERT_TRUE(validate());  | 
7439  | 0  |   ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));  | 
7440  | 0  | 
  | 
7441  | 0  |   // This next line is required for when parsing a URL like `foo://`  | 
7442  | 0  |   add_authority_slashes_if_needed();  | 
7443  | 0  | 
  | 
7444  | 0  |   bool has_credentials = components.protocol_end + 2 < components.host_start;  | 
7445  | 0  |   uint32_t new_difference =  | 
7446  | 0  |       replace_and_resize(components.host_start, components.host_end, input);  | 
7447  | 0  | 
  | 
7448  | 0  |   if (has_credentials) { | 
7449  | 0  |     buffer.insert(components.host_start, "@");  | 
7450  | 0  |     new_difference++;  | 
7451  | 0  |   }  | 
7452  | 0  |   components.host_end += new_difference;  | 
7453  | 0  |   components.pathname_start += new_difference;  | 
7454  | 0  |   if (components.search_start != url_components::omitted) { | 
7455  | 0  |     components.search_start += new_difference;  | 
7456  | 0  |   }  | 
7457  | 0  |   if (components.hash_start != url_components::omitted) { | 
7458  | 0  |     components.hash_start += new_difference;  | 
7459  | 0  |   }  | 
7460  | 0  |   ADA_ASSERT_TRUE(validate());  | 
7461  | 0  | }  | 
7462  |  |  | 
7463  |  | [[nodiscard]] ada_really_inline uint32_t  | 
7464  | 0  | url_aggregator::get_pathname_length() const noexcept { | 
7465  | 0  |   ada_log("url_aggregator::get_pathname_length"); | 
7466  | 0  |   uint32_t ending_index = uint32_t(buffer.size());  | 
7467  | 0  |   if (components.search_start != url_components::omitted) { | 
7468  | 0  |     ending_index = components.search_start;  | 
7469  | 0  |   } else if (components.hash_start != url_components::omitted) { | 
7470  | 0  |     ending_index = components.hash_start;  | 
7471  | 0  |   }  | 
7472  | 0  |   return ending_index - components.pathname_start;  | 
7473  | 0  | }  | 
7474  |  |  | 
7475  |  | [[nodiscard]] ada_really_inline bool url_aggregator::is_at_path()  | 
7476  | 0  |     const noexcept { | 
7477  | 0  |   return buffer.size() == components.pathname_start;  | 
7478  | 0  | }  | 
7479  |  |  | 
7480  | 0  | inline void url_aggregator::update_base_search(std::string_view input) { | 
7481  | 0  |   ada_log("url_aggregator::update_base_search ", input); | 
7482  | 0  |   ADA_ASSERT_TRUE(validate());  | 
7483  | 0  |   ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));  | 
7484  | 0  |   if (input.empty()) { | 
7485  | 0  |     clear_search();  | 
7486  | 0  |     return;  | 
7487  | 0  |   }  | 
7488  | 0  | 
  | 
7489  | 0  |   if (input[0] == '?') { | 
7490  | 0  |     input.remove_prefix(1);  | 
7491  | 0  |   }  | 
7492  | 0  | 
  | 
7493  | 0  |   if (components.hash_start == url_components::omitted) { | 
7494  | 0  |     if (components.search_start == url_components::omitted) { | 
7495  | 0  |       components.search_start = uint32_t(buffer.size());  | 
7496  | 0  |       buffer += "?";  | 
7497  | 0  |     } else { | 
7498  | 0  |       buffer.resize(components.search_start + 1);  | 
7499  | 0  |     }  | 
7500  | 0  | 
  | 
7501  | 0  |     buffer.append(input);  | 
7502  | 0  |   } else { | 
7503  | 0  |     if (components.search_start == url_components::omitted) { | 
7504  | 0  |       components.search_start = components.hash_start;  | 
7505  | 0  |     } else { | 
7506  | 0  |       buffer.erase(components.search_start,  | 
7507  | 0  |                    components.hash_start - components.search_start);  | 
7508  | 0  |       components.hash_start = components.search_start;  | 
7509  | 0  |     }  | 
7510  | 0  | 
  | 
7511  | 0  |     buffer.insert(components.search_start, "?");  | 
7512  | 0  |     buffer.insert(components.search_start + 1, input);  | 
7513  | 0  |     components.hash_start += uint32_t(input.size() + 1);  // Do not forget `?`  | 
7514  | 0  |   }  | 
7515  | 0  | 
  | 
7516  | 0  |   ADA_ASSERT_TRUE(validate());  | 
7517  | 0  | }  | 
7518  |  |  | 
7519  |  | inline void url_aggregator::update_base_search(  | 
7520  | 0  |     std::string_view input, const uint8_t query_percent_encode_set[]) { | 
7521  | 0  |   ada_log("url_aggregator::update_base_search ", input, | 
7522  | 0  |           " with encoding parameter ", to_string(), "\n", to_diagram());  | 
7523  | 0  |   ADA_ASSERT_TRUE(validate());  | 
7524  | 0  |   ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));  | 
7525  | 0  | 
  | 
7526  | 0  |   if (components.hash_start == url_components::omitted) { | 
7527  | 0  |     if (components.search_start == url_components::omitted) { | 
7528  | 0  |       components.search_start = uint32_t(buffer.size());  | 
7529  | 0  |       buffer += "?";  | 
7530  | 0  |     } else { | 
7531  | 0  |       buffer.resize(components.search_start + 1);  | 
7532  | 0  |     }  | 
7533  | 0  | 
  | 
7534  | 0  |     bool encoding_required =  | 
7535  | 0  |         unicode::percent_encode<true>(input, query_percent_encode_set, buffer);  | 
7536  | 0  |     // When encoding_required is false, then buffer is left unchanged, and  | 
7537  | 0  |     // percent encoding was not deemed required.  | 
7538  | 0  |     if (!encoding_required) { | 
7539  | 0  |       buffer.append(input);  | 
7540  | 0  |     }  | 
7541  | 0  |   } else { | 
7542  | 0  |     if (components.search_start == url_components::omitted) { | 
7543  | 0  |       components.search_start = components.hash_start;  | 
7544  | 0  |     } else { | 
7545  | 0  |       buffer.erase(components.search_start,  | 
7546  | 0  |                    components.hash_start - components.search_start);  | 
7547  | 0  |       components.hash_start = components.search_start;  | 
7548  | 0  |     }  | 
7549  | 0  | 
  | 
7550  | 0  |     buffer.insert(components.search_start, "?");  | 
7551  | 0  |     size_t idx =  | 
7552  | 0  |         ada::unicode::percent_encode_index(input, query_percent_encode_set);  | 
7553  | 0  |     if (idx == input.size()) { | 
7554  | 0  |       buffer.insert(components.search_start + 1, input);  | 
7555  | 0  |       components.hash_start += uint32_t(input.size() + 1);  // Do not forget `?`  | 
7556  | 0  |     } else { | 
7557  | 0  |       buffer.insert(components.search_start + 1, input, 0, idx);  | 
7558  | 0  |       input.remove_prefix(idx);  | 
7559  | 0  |       // We only create a temporary string if we need percent encoding and  | 
7560  | 0  |       // we attempt to create as small a temporary string as we can.  | 
7561  | 0  |       std::string encoded =  | 
7562  | 0  |           ada::unicode::percent_encode(input, query_percent_encode_set);  | 
7563  | 0  |       buffer.insert(components.search_start + idx + 1, encoded);  | 
7564  | 0  |       components.hash_start +=  | 
7565  | 0  |           uint32_t(encoded.size() + idx + 1);  // Do not forget `?`  | 
7566  | 0  |     }  | 
7567  | 0  |   }  | 
7568  | 0  | 
  | 
7569  | 0  |   ADA_ASSERT_TRUE(validate());  | 
7570  | 0  | }  | 
7571  |  |  | 
7572  | 0  | inline void url_aggregator::update_base_pathname(const std::string_view input) { | 
7573  | 0  |   ada_log("url_aggregator::update_base_pathname '", input, "' [", input.size(), | 
7574  | 0  |           " bytes] \n", to_diagram());  | 
7575  | 0  |   ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));  | 
7576  | 0  |   ADA_ASSERT_TRUE(validate());  | 
7577  | 0  | 
  | 
7578  | 0  |   const bool begins_with_dashdash = input.starts_with("//"); | 
7579  | 0  |   if (!begins_with_dashdash && has_dash_dot()) { | 
7580  | 0  |     // We must delete the ./  | 
7581  | 0  |     delete_dash_dot();  | 
7582  | 0  |   }  | 
7583  | 0  | 
  | 
7584  | 0  |   if (begins_with_dashdash && !has_opaque_path && !has_authority() &&  | 
7585  | 0  |       !has_dash_dot()) { | 
7586  | 0  |     // If url's host is null, url does not have an opaque path, url's path's  | 
7587  | 0  |     // size is greater than 1, then append U+002F (/) followed by U+002E (.) to  | 
7588  | 0  |     // output.  | 
7589  | 0  |     buffer.insert(components.pathname_start, "/.");  | 
7590  | 0  |     components.pathname_start += 2;  | 
7591  | 0  |   }  | 
7592  | 0  | 
  | 
7593  | 0  |   uint32_t difference = replace_and_resize(  | 
7594  | 0  |       components.pathname_start,  | 
7595  | 0  |       components.pathname_start + get_pathname_length(), input);  | 
7596  | 0  |   if (components.search_start != url_components::omitted) { | 
7597  | 0  |     components.search_start += difference;  | 
7598  | 0  |   }  | 
7599  | 0  |   if (components.hash_start != url_components::omitted) { | 
7600  | 0  |     components.hash_start += difference;  | 
7601  | 0  |   }  | 
7602  | 0  |   ADA_ASSERT_TRUE(validate());  | 
7603  | 0  | }  | 
7604  |  |  | 
7605  | 0  | inline void url_aggregator::append_base_pathname(const std::string_view input) { | 
7606  | 0  |   ada_log("url_aggregator::append_base_pathname ", input, " ", to_string(), | 
7607  | 0  |           "\n", to_diagram());  | 
7608  | 0  |   ADA_ASSERT_TRUE(validate());  | 
7609  | 0  |   ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));  | 
7610  | 0  | #if ADA_DEVELOPMENT_CHECKS  | 
7611  | 0  |   // computing the expected password.  | 
7612  | 0  |   std::string path_expected(get_pathname());  | 
7613  | 0  |   path_expected.append(input);  | 
7614  | 0  | #endif  // ADA_DEVELOPMENT_CHECKS  | 
7615  | 0  |   uint32_t ending_index = uint32_t(buffer.size());  | 
7616  | 0  |   if (components.search_start != url_components::omitted) { | 
7617  | 0  |     ending_index = components.search_start;  | 
7618  | 0  |   } else if (components.hash_start != url_components::omitted) { | 
7619  | 0  |     ending_index = components.hash_start;  | 
7620  | 0  |   }  | 
7621  | 0  |   buffer.insert(ending_index, input);  | 
7622  | 0  | 
  | 
7623  | 0  |   if (components.search_start != url_components::omitted) { | 
7624  | 0  |     components.search_start += uint32_t(input.size());  | 
7625  | 0  |   }  | 
7626  | 0  |   if (components.hash_start != url_components::omitted) { | 
7627  | 0  |     components.hash_start += uint32_t(input.size());  | 
7628  | 0  |   }  | 
7629  | 0  | #if ADA_DEVELOPMENT_CHECKS  | 
7630  | 0  |   std::string path_after = std::string(get_pathname());  | 
7631  | 0  |   ADA_ASSERT_EQUAL(  | 
7632  | 0  |       path_expected, path_after,  | 
7633  | 0  |       "append_base_pathname problem after inserting " + std::string(input));  | 
7634  | 0  | #endif  // ADA_DEVELOPMENT_CHECKS  | 
7635  | 0  |   ADA_ASSERT_TRUE(validate());  | 
7636  | 0  | }  | 
7637  |  |  | 
7638  | 0  | inline void url_aggregator::update_base_username(const std::string_view input) { | 
7639  | 0  |   ada_log("url_aggregator::update_base_username '", input, "' ", to_string(), | 
7640  | 0  |           "\n", to_diagram());  | 
7641  | 0  |   ADA_ASSERT_TRUE(validate());  | 
7642  | 0  |   ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));  | 
7643  | 0  | 
  | 
7644  | 0  |   add_authority_slashes_if_needed();  | 
7645  | 0  | 
  | 
7646  | 0  |   bool has_password = has_non_empty_password();  | 
7647  | 0  |   bool host_starts_with_at = buffer.size() > components.host_start &&  | 
7648  | 0  |                              buffer[components.host_start] == '@';  | 
7649  | 0  |   uint32_t diff = replace_and_resize(components.protocol_end + 2,  | 
7650  | 0  |                                      components.username_end, input);  | 
7651  | 0  | 
  | 
7652  | 0  |   components.username_end += diff;  | 
7653  | 0  |   components.host_start += diff;  | 
7654  | 0  | 
  | 
7655  | 0  |   if (!input.empty() && !host_starts_with_at) { | 
7656  | 0  |     buffer.insert(components.host_start, "@");  | 
7657  | 0  |     diff++;  | 
7658  | 0  |   } else if (input.empty() && host_starts_with_at && !has_password) { | 
7659  | 0  |     // Input is empty, there is no password, and we need to remove "@" from  | 
7660  | 0  |     // hostname  | 
7661  | 0  |     buffer.erase(components.host_start, 1);  | 
7662  | 0  |     diff--;  | 
7663  | 0  |   }  | 
7664  | 0  | 
  | 
7665  | 0  |   components.host_end += diff;  | 
7666  | 0  |   components.pathname_start += diff;  | 
7667  | 0  |   if (components.search_start != url_components::omitted) { | 
7668  | 0  |     components.search_start += diff;  | 
7669  | 0  |   }  | 
7670  | 0  |   if (components.hash_start != url_components::omitted) { | 
7671  | 0  |     components.hash_start += diff;  | 
7672  | 0  |   }  | 
7673  | 0  |   ADA_ASSERT_TRUE(validate());  | 
7674  | 0  | }  | 
7675  |  |  | 
7676  | 0  | inline void url_aggregator::append_base_username(const std::string_view input) { | 
7677  | 0  |   ada_log("url_aggregator::append_base_username ", input); | 
7678  | 0  |   ADA_ASSERT_TRUE(validate());  | 
7679  | 0  |   ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));  | 
7680  | 0  | #if ADA_DEVELOPMENT_CHECKS  | 
7681  | 0  |   // computing the expected password.  | 
7682  | 0  |   std::string username_expected(get_username());  | 
7683  | 0  |   username_expected.append(input);  | 
7684  | 0  | #endif  // ADA_DEVELOPMENT_CHECKS  | 
7685  | 0  |   add_authority_slashes_if_needed();  | 
7686  | 0  | 
  | 
7687  | 0  |   // If input is empty, do nothing.  | 
7688  | 0  |   if (input.empty()) { | 
7689  | 0  |     return;  | 
7690  | 0  |   }  | 
7691  | 0  | 
  | 
7692  | 0  |   uint32_t difference = uint32_t(input.size());  | 
7693  | 0  |   buffer.insert(components.username_end, input);  | 
7694  | 0  |   components.username_end += difference;  | 
7695  | 0  |   components.host_start += difference;  | 
7696  | 0  | 
  | 
7697  | 0  |   if (buffer[components.host_start] != '@' &&  | 
7698  | 0  |       components.host_start != components.host_end) { | 
7699  | 0  |     buffer.insert(components.host_start, "@");  | 
7700  | 0  |     difference++;  | 
7701  | 0  |   }  | 
7702  | 0  | 
  | 
7703  | 0  |   components.host_end += difference;  | 
7704  | 0  |   components.pathname_start += difference;  | 
7705  | 0  |   if (components.search_start != url_components::omitted) { | 
7706  | 0  |     components.search_start += difference;  | 
7707  | 0  |   }  | 
7708  | 0  |   if (components.hash_start != url_components::omitted) { | 
7709  | 0  |     components.hash_start += difference;  | 
7710  | 0  |   }  | 
7711  | 0  | #if ADA_DEVELOPMENT_CHECKS  | 
7712  | 0  |   std::string username_after(get_username());  | 
7713  | 0  |   ADA_ASSERT_EQUAL(  | 
7714  | 0  |       username_expected, username_after,  | 
7715  | 0  |       "append_base_username problem after inserting " + std::string(input));  | 
7716  | 0  | #endif  // ADA_DEVELOPMENT_CHECKS  | 
7717  | 0  |   ADA_ASSERT_TRUE(validate());  | 
7718  | 0  | }  | 
7719  |  |  | 
7720  | 0  | constexpr void url_aggregator::clear_password() { | 
7721  | 0  |   ada_log("url_aggregator::clear_password ", to_string()); | 
7722  | 0  |   ADA_ASSERT_TRUE(validate());  | 
7723  | 0  |   if (!has_password()) { | 
7724  | 0  |     return;  | 
7725  | 0  |   }  | 
7726  | 0  | 
  | 
7727  | 0  |   uint32_t diff = components.host_start - components.username_end;  | 
7728  | 0  |   buffer.erase(components.username_end, diff);  | 
7729  | 0  |   components.host_start -= diff;  | 
7730  | 0  |   components.host_end -= diff;  | 
7731  | 0  |   components.pathname_start -= diff;  | 
7732  | 0  |   if (components.search_start != url_components::omitted) { | 
7733  | 0  |     components.search_start -= diff;  | 
7734  | 0  |   }  | 
7735  | 0  |   if (components.hash_start != url_components::omitted) { | 
7736  | 0  |     components.hash_start -= diff;  | 
7737  | 0  |   }  | 
7738  | 0  | }  | 
7739  |  |  | 
7740  | 0  | inline void url_aggregator::update_base_password(const std::string_view input) { | 
7741  | 0  |   ada_log("url_aggregator::update_base_password ", input); | 
7742  | 0  |   ADA_ASSERT_TRUE(validate());  | 
7743  | 0  |   ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));  | 
7744  | 0  | 
  | 
7745  | 0  |   add_authority_slashes_if_needed();  | 
7746  | 0  | 
  | 
7747  | 0  |   // TODO: Optimization opportunity. Merge the following removal functions.  | 
7748  | 0  |   if (input.empty()) { | 
7749  | 0  |     clear_password();  | 
7750  | 0  | 
  | 
7751  | 0  |     // Remove username too, if it is empty.  | 
7752  | 0  |     if (!has_non_empty_username()) { | 
7753  | 0  |       update_base_username(""); | 
7754  | 0  |     }  | 
7755  | 0  | 
  | 
7756  | 0  |     return;  | 
7757  | 0  |   }  | 
7758  | 0  | 
  | 
7759  | 0  |   bool password_exists = has_password();  | 
7760  | 0  |   uint32_t difference = uint32_t(input.size());  | 
7761  | 0  | 
  | 
7762  | 0  |   if (password_exists) { | 
7763  | 0  |     uint32_t current_length =  | 
7764  | 0  |         components.host_start - components.username_end - 1;  | 
7765  | 0  |     buffer.erase(components.username_end + 1, current_length);  | 
7766  | 0  |     difference -= current_length;  | 
7767  | 0  |   } else { | 
7768  | 0  |     buffer.insert(components.username_end, ":");  | 
7769  | 0  |     difference++;  | 
7770  | 0  |   }  | 
7771  | 0  | 
  | 
7772  | 0  |   buffer.insert(components.username_end + 1, input);  | 
7773  | 0  |   components.host_start += difference;  | 
7774  | 0  | 
  | 
7775  | 0  |   // The following line is required to add "@" to hostname. When updating  | 
7776  | 0  |   // password if hostname does not start with "@", it is "update_base_password"s  | 
7777  | 0  |   // responsibility to set it.  | 
7778  | 0  |   if (buffer[components.host_start] != '@') { | 
7779  | 0  |     buffer.insert(components.host_start, "@");  | 
7780  | 0  |     difference++;  | 
7781  | 0  |   }  | 
7782  | 0  | 
  | 
7783  | 0  |   components.host_end += difference;  | 
7784  | 0  |   components.pathname_start += difference;  | 
7785  | 0  |   if (components.search_start != url_components::omitted) { | 
7786  | 0  |     components.search_start += difference;  | 
7787  | 0  |   }  | 
7788  | 0  |   if (components.hash_start != url_components::omitted) { | 
7789  | 0  |     components.hash_start += difference;  | 
7790  | 0  |   }  | 
7791  | 0  |   ADA_ASSERT_TRUE(validate());  | 
7792  | 0  | }  | 
7793  |  |  | 
7794  | 0  | inline void url_aggregator::append_base_password(const std::string_view input) { | 
7795  | 0  |   ada_log("url_aggregator::append_base_password ", input, " ", to_string(), | 
7796  | 0  |           "\n", to_diagram());  | 
7797  | 0  |   ADA_ASSERT_TRUE(validate());  | 
7798  | 0  |   ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));  | 
7799  | 0  | #if ADA_DEVELOPMENT_CHECKS  | 
7800  | 0  |   // computing the expected password.  | 
7801  | 0  |   std::string password_expected = std::string(get_password());  | 
7802  | 0  |   password_expected.append(input);  | 
7803  | 0  | #endif  // ADA_DEVELOPMENT_CHECKS  | 
7804  | 0  |   add_authority_slashes_if_needed();  | 
7805  | 0  | 
  | 
7806  | 0  |   // If input is empty, do nothing.  | 
7807  | 0  |   if (input.empty()) { | 
7808  | 0  |     return;  | 
7809  | 0  |   }  | 
7810  | 0  | 
  | 
7811  | 0  |   uint32_t difference = uint32_t(input.size());  | 
7812  | 0  |   if (has_password()) { | 
7813  | 0  |     buffer.insert(components.host_start, input);  | 
7814  | 0  |   } else { | 
7815  | 0  |     difference++;  // Increment for ":"  | 
7816  | 0  |     buffer.insert(components.username_end, ":");  | 
7817  | 0  |     buffer.insert(components.username_end + 1, input);  | 
7818  | 0  |   }  | 
7819  | 0  |   components.host_start += difference;  | 
7820  | 0  | 
  | 
7821  | 0  |   // The following line is required to add "@" to hostname. When updating  | 
7822  | 0  |   // password if hostname does not start with "@", it is "append_base_password"s  | 
7823  | 0  |   // responsibility to set it.  | 
7824  | 0  |   if (buffer[components.host_start] != '@') { | 
7825  | 0  |     buffer.insert(components.host_start, "@");  | 
7826  | 0  |     difference++;  | 
7827  | 0  |   }  | 
7828  | 0  | 
  | 
7829  | 0  |   components.host_end += difference;  | 
7830  | 0  |   components.pathname_start += difference;  | 
7831  | 0  |   if (components.search_start != url_components::omitted) { | 
7832  | 0  |     components.search_start += difference;  | 
7833  | 0  |   }  | 
7834  | 0  |   if (components.hash_start != url_components::omitted) { | 
7835  | 0  |     components.hash_start += difference;  | 
7836  | 0  |   }  | 
7837  | 0  | #if ADA_DEVELOPMENT_CHECKS  | 
7838  | 0  |   std::string password_after(get_password());  | 
7839  | 0  |   ADA_ASSERT_EQUAL(  | 
7840  | 0  |       password_expected, password_after,  | 
7841  | 0  |       "append_base_password problem after inserting " + std::string(input));  | 
7842  | 0  | #endif  // ADA_DEVELOPMENT_CHECKS  | 
7843  | 0  |   ADA_ASSERT_TRUE(validate());  | 
7844  | 0  | }  | 
7845  |  |  | 
7846  | 0  | inline void url_aggregator::update_base_port(uint32_t input) { | 
7847  | 0  |   ada_log("url_aggregator::update_base_port"); | 
7848  | 0  |   ADA_ASSERT_TRUE(validate());  | 
7849  | 0  |   if (input == url_components::omitted) { | 
7850  | 0  |     clear_port();  | 
7851  | 0  |     return;  | 
7852  | 0  |   }  | 
7853  | 0  |   // calling std::to_string(input.value()) is unfortunate given that the port  | 
7854  | 0  |   // value is probably already available as a string.  | 
7855  | 0  |   std::string value = helpers::concat(":", std::to_string(input)); | 
7856  | 0  |   uint32_t difference = uint32_t(value.size());  | 
7857  | 0  | 
  | 
7858  | 0  |   if (components.port != url_components::omitted) { | 
7859  | 0  |     difference -= components.pathname_start - components.host_end;  | 
7860  | 0  |     buffer.erase(components.host_end,  | 
7861  | 0  |                  components.pathname_start - components.host_end);  | 
7862  | 0  |   }  | 
7863  | 0  | 
  | 
7864  | 0  |   buffer.insert(components.host_end, value);  | 
7865  | 0  |   components.pathname_start += difference;  | 
7866  | 0  |   if (components.search_start != url_components::omitted) { | 
7867  | 0  |     components.search_start += difference;  | 
7868  | 0  |   }  | 
7869  | 0  |   if (components.hash_start != url_components::omitted) { | 
7870  | 0  |     components.hash_start += difference;  | 
7871  | 0  |   }  | 
7872  | 0  |   components.port = input;  | 
7873  | 0  |   ADA_ASSERT_TRUE(validate());  | 
7874  | 0  | }  | 
7875  |  |  | 
7876  | 0  | inline void url_aggregator::clear_port() { | 
7877  | 0  |   ada_log("url_aggregator::clear_port"); | 
7878  | 0  |   ADA_ASSERT_TRUE(validate());  | 
7879  | 0  |   if (components.port == url_components::omitted) { | 
7880  | 0  |     return;  | 
7881  | 0  |   }  | 
7882  | 0  |   uint32_t length = components.pathname_start - components.host_end;  | 
7883  | 0  |   buffer.erase(components.host_end, length);  | 
7884  | 0  |   components.pathname_start -= length;  | 
7885  | 0  |   if (components.search_start != url_components::omitted) { | 
7886  | 0  |     components.search_start -= length;  | 
7887  | 0  |   }  | 
7888  | 0  |   if (components.hash_start != url_components::omitted) { | 
7889  | 0  |     components.hash_start -= length;  | 
7890  | 0  |   }  | 
7891  | 0  |   components.port = url_components::omitted;  | 
7892  | 0  |   ADA_ASSERT_TRUE(validate());  | 
7893  | 0  | }  | 
7894  |  |  | 
7895  | 0  | [[nodiscard]] inline uint32_t url_aggregator::retrieve_base_port() const { | 
7896  | 0  |   ada_log("url_aggregator::retrieve_base_port"); | 
7897  | 0  |   return components.port;  | 
7898  | 0  | }  | 
7899  |  |  | 
7900  | 0  | inline void url_aggregator::clear_search() { | 
7901  | 0  |   ada_log("url_aggregator::clear_search"); | 
7902  | 0  |   ADA_ASSERT_TRUE(validate());  | 
7903  | 0  |   if (components.search_start == url_components::omitted) { | 
7904  | 0  |     return;  | 
7905  | 0  |   }  | 
7906  | 0  | 
  | 
7907  | 0  |   if (components.hash_start == url_components::omitted) { | 
7908  | 0  |     buffer.resize(components.search_start);  | 
7909  | 0  |   } else { | 
7910  | 0  |     buffer.erase(components.search_start,  | 
7911  | 0  |                  components.hash_start - components.search_start);  | 
7912  | 0  |     components.hash_start = components.search_start;  | 
7913  | 0  |   }  | 
7914  | 0  | 
  | 
7915  | 0  |   components.search_start = url_components::omitted;  | 
7916  | 0  | 
  | 
7917  | 0  | #if ADA_DEVELOPMENT_CHECKS  | 
7918  | 0  |   ADA_ASSERT_EQUAL(get_search(), "",  | 
7919  | 0  |                    "search should have been cleared on buffer=" + buffer +  | 
7920  | 0  |                        " with " + components.to_string() + "\n" + to_diagram());  | 
7921  | 0  | #endif  | 
7922  | 0  |   ADA_ASSERT_TRUE(validate());  | 
7923  | 0  | }  | 
7924  |  |  | 
7925  | 0  | inline void url_aggregator::clear_hash() { | 
7926  | 0  |   ada_log("url_aggregator::clear_hash"); | 
7927  | 0  |   ADA_ASSERT_TRUE(validate());  | 
7928  | 0  |   if (components.hash_start == url_components::omitted) { | 
7929  | 0  |     return;  | 
7930  | 0  |   }  | 
7931  | 0  |   buffer.resize(components.hash_start);  | 
7932  | 0  |   components.hash_start = url_components::omitted;  | 
7933  | 0  | 
  | 
7934  | 0  | #if ADA_DEVELOPMENT_CHECKS  | 
7935  | 0  |   ADA_ASSERT_EQUAL(get_hash(), "",  | 
7936  | 0  |                    "hash should have been cleared on buffer=" + buffer +  | 
7937  | 0  |                        " with " + components.to_string() + "\n" + to_diagram());  | 
7938  | 0  | #endif  | 
7939  | 0  |   ADA_ASSERT_TRUE(validate());  | 
7940  | 0  | }  | 
7941  |  |  | 
7942  | 0  | constexpr void url_aggregator::clear_pathname() { | 
7943  | 0  |   ada_log("url_aggregator::clear_pathname"); | 
7944  | 0  |   ADA_ASSERT_TRUE(validate());  | 
7945  | 0  |   uint32_t ending_index = uint32_t(buffer.size());  | 
7946  | 0  |   if (components.search_start != url_components::omitted) { | 
7947  | 0  |     ending_index = components.search_start;  | 
7948  | 0  |   } else if (components.hash_start != url_components::omitted) { | 
7949  | 0  |     ending_index = components.hash_start;  | 
7950  | 0  |   }  | 
7951  | 0  |   uint32_t pathname_length = ending_index - components.pathname_start;  | 
7952  | 0  |   buffer.erase(components.pathname_start, pathname_length);  | 
7953  | 0  |   uint32_t difference = pathname_length;  | 
7954  | 0  |   if (components.pathname_start == components.host_end + 2 &&  | 
7955  | 0  |       buffer[components.host_end] == '/' &&  | 
7956  | 0  |       buffer[components.host_end + 1] == '.') { | 
7957  | 0  |     components.pathname_start -= 2;  | 
7958  | 0  |     buffer.erase(components.host_end, 2);  | 
7959  | 0  |     difference += 2;  | 
7960  | 0  |   }  | 
7961  | 0  |   if (components.search_start != url_components::omitted) { | 
7962  | 0  |     components.search_start -= difference;  | 
7963  | 0  |   }  | 
7964  | 0  |   if (components.hash_start != url_components::omitted) { | 
7965  | 0  |     components.hash_start -= difference;  | 
7966  | 0  |   }  | 
7967  | 0  |   ada_log("url_aggregator::clear_pathname completed, running checks..."); | 
7968  | 0  | #if ADA_DEVELOPMENT_CHECKS  | 
7969  | 0  |   ADA_ASSERT_EQUAL(get_pathname(), "",  | 
7970  | 0  |                    "pathname should have been cleared on buffer=" + buffer +  | 
7971  | 0  |                        " with " + components.to_string() + "\n" + to_diagram());  | 
7972  | 0  | #endif  | 
7973  | 0  |   ADA_ASSERT_TRUE(validate());  | 
7974  | 0  |   ada_log("url_aggregator::clear_pathname completed, running checks... ok"); | 
7975  | 0  | }  | 
7976  |  |  | 
7977  | 0  | constexpr void url_aggregator::clear_hostname() { | 
7978  | 0  |   ada_log("url_aggregator::clear_hostname"); | 
7979  | 0  |   ADA_ASSERT_TRUE(validate());  | 
7980  | 0  |   if (!has_authority()) { | 
7981  | 0  |     return;  | 
7982  | 0  |   }  | 
7983  | 0  |   ADA_ASSERT_TRUE(has_authority());  | 
7984  | 0  | 
  | 
7985  | 0  |   uint32_t hostname_length = components.host_end - components.host_start;  | 
7986  | 0  |   uint32_t start = components.host_start;  | 
7987  | 0  | 
  | 
7988  | 0  |   // If hostname starts with "@", we should not remove that character.  | 
7989  | 0  |   if (hostname_length > 0 && buffer[start] == '@') { | 
7990  | 0  |     start++;  | 
7991  | 0  |     hostname_length--;  | 
7992  | 0  |   }  | 
7993  | 0  |   buffer.erase(start, hostname_length);  | 
7994  | 0  |   components.host_end = start;  | 
7995  | 0  |   components.pathname_start -= hostname_length;  | 
7996  | 0  |   if (components.search_start != url_components::omitted) { | 
7997  | 0  |     components.search_start -= hostname_length;  | 
7998  | 0  |   }  | 
7999  | 0  |   if (components.hash_start != url_components::omitted) { | 
8000  | 0  |     components.hash_start -= hostname_length;  | 
8001  | 0  |   }  | 
8002  | 0  | #if ADA_DEVELOPMENT_CHECKS  | 
8003  | 0  |   ADA_ASSERT_EQUAL(get_hostname(), "",  | 
8004  | 0  |                    "hostname should have been cleared on buffer=" + buffer +  | 
8005  | 0  |                        " with " + components.to_string() + "\n" + to_diagram());  | 
8006  | 0  | #endif  | 
8007  | 0  |   ADA_ASSERT_TRUE(has_authority());  | 
8008  | 0  |   ADA_ASSERT_EQUAL(has_empty_hostname(), true,  | 
8009  | 0  |                    "hostname should have been cleared on buffer=" + buffer +  | 
8010  | 0  |                        " with " + components.to_string() + "\n" + to_diagram());  | 
8011  | 0  |   ADA_ASSERT_TRUE(validate());  | 
8012  | 0  | }  | 
8013  |  |  | 
8014  | 0  | [[nodiscard]] constexpr bool url_aggregator::has_hash() const noexcept { | 
8015  | 0  |   ada_log("url_aggregator::has_hash"); | 
8016  | 0  |   return components.hash_start != url_components::omitted;  | 
8017  | 0  | }  | 
8018  |  |  | 
8019  | 0  | [[nodiscard]] constexpr bool url_aggregator::has_search() const noexcept { | 
8020  | 0  |   ada_log("url_aggregator::has_search"); | 
8021  | 0  |   return components.search_start != url_components::omitted;  | 
8022  | 0  | }  | 
8023  |  |  | 
8024  | 0  | constexpr bool url_aggregator::has_credentials() const noexcept { | 
8025  | 0  |   ada_log("url_aggregator::has_credentials"); | 
8026  | 0  |   return has_non_empty_username() || has_non_empty_password();  | 
8027  | 0  | }  | 
8028  |  |  | 
8029  | 0  | constexpr bool url_aggregator::cannot_have_credentials_or_port() const { | 
8030  | 0  |   ada_log("url_aggregator::cannot_have_credentials_or_port"); | 
8031  | 0  |   return type == ada::scheme::type::FILE ||  | 
8032  | 0  |          components.host_start == components.host_end;  | 
8033  | 0  | }  | 
8034  |  |  | 
8035  |  | [[nodiscard]] ada_really_inline const ada::url_components &  | 
8036  | 0  | url_aggregator::get_components() const noexcept { | 
8037  | 0  |   return components;  | 
8038  | 0  | }  | 
8039  |  |  | 
8040  |  | [[nodiscard]] constexpr bool ada::url_aggregator::has_authority()  | 
8041  | 0  |     const noexcept { | 
8042  | 0  |   ada_log("url_aggregator::has_authority"); | 
8043  | 0  |   // Performance: instead of doing this potentially expensive check, we could  | 
8044  | 0  |   // have a boolean in the struct.  | 
8045  | 0  |   return components.protocol_end + 2 <= components.host_start &&  | 
8046  | 0  |          helpers::substring(buffer, components.protocol_end,  | 
8047  | 0  |                             components.protocol_end + 2) == "//";  | 
8048  | 0  | }  | 
8049  |  |  | 
8050  | 0  | inline void ada::url_aggregator::add_authority_slashes_if_needed() noexcept { | 
8051  | 0  |   ada_log("url_aggregator::add_authority_slashes_if_needed"); | 
8052  | 0  |   ADA_ASSERT_TRUE(validate());  | 
8053  | 0  |   // Protocol setter will insert `http:` to the URL. It is up to hostname setter  | 
8054  | 0  |   // to insert  | 
8055  | 0  |   // `//` initially to the buffer, since it depends on the hostname existence.  | 
8056  | 0  |   if (has_authority()) { | 
8057  | 0  |     return;  | 
8058  | 0  |   }  | 
8059  | 0  |   // Performance: the common case is components.protocol_end == buffer.size()  | 
8060  | 0  |   // Optimization opportunity: in many cases, the "//" is part of the input and  | 
8061  | 0  |   // the insert could be fused with another insert.  | 
8062  | 0  |   buffer.insert(components.protocol_end, "//");  | 
8063  | 0  |   components.username_end += 2;  | 
8064  | 0  |   components.host_start += 2;  | 
8065  | 0  |   components.host_end += 2;  | 
8066  | 0  |   components.pathname_start += 2;  | 
8067  | 0  |   if (components.search_start != url_components::omitted) { | 
8068  | 0  |     components.search_start += 2;  | 
8069  | 0  |   }  | 
8070  | 0  |   if (components.hash_start != url_components::omitted) { | 
8071  | 0  |     components.hash_start += 2;  | 
8072  | 0  |   }  | 
8073  | 0  |   ADA_ASSERT_TRUE(validate());  | 
8074  | 0  | }  | 
8075  |  |  | 
8076  | 0  | constexpr void ada::url_aggregator::reserve(uint32_t capacity) { | 
8077  | 0  |   buffer.reserve(capacity);  | 
8078  | 0  | }  | 
8079  |  |  | 
8080  | 0  | constexpr bool url_aggregator::has_non_empty_username() const noexcept { | 
8081  | 0  |   ada_log("url_aggregator::has_non_empty_username"); | 
8082  | 0  |   return components.protocol_end + 2 < components.username_end;  | 
8083  | 0  | }  | 
8084  |  |  | 
8085  | 0  | constexpr bool url_aggregator::has_non_empty_password() const noexcept { | 
8086  | 0  |   ada_log("url_aggregator::has_non_empty_password"); | 
8087  | 0  |   return components.host_start - components.username_end > 0;  | 
8088  | 0  | }  | 
8089  |  |  | 
8090  | 0  | constexpr bool url_aggregator::has_password() const noexcept { | 
8091  | 0  |   ada_log("url_aggregator::has_password"); | 
8092  | 0  |   // This function does not care about the length of the password  | 
8093  | 0  |   return components.host_start > components.username_end &&  | 
8094  | 0  |          buffer[components.username_end] == ':';  | 
8095  | 0  | }  | 
8096  |  |  | 
8097  | 0  | constexpr bool url_aggregator::has_empty_hostname() const noexcept { | 
8098  | 0  |   if (!has_hostname()) { | 
8099  | 0  |     return false;  | 
8100  | 0  |   }  | 
8101  | 0  |   if (components.host_start == components.host_end) { | 
8102  | 0  |     return true;  | 
8103  | 0  |   }  | 
8104  | 0  |   if (components.host_end > components.host_start + 1) { | 
8105  | 0  |     return false;  | 
8106  | 0  |   }  | 
8107  | 0  |   return components.username_end != components.host_start;  | 
8108  | 0  | }  | 
8109  |  |  | 
8110  | 0  | constexpr bool url_aggregator::has_hostname() const noexcept { | 
8111  | 0  |   return has_authority();  | 
8112  | 0  | }  | 
8113  |  |  | 
8114  | 0  | constexpr bool url_aggregator::has_port() const noexcept { | 
8115  | 0  |   ada_log("url_aggregator::has_port"); | 
8116  | 0  |   // A URL cannot have a username/password/port if its host is null or the empty  | 
8117  | 0  |   // string, or its scheme is "file".  | 
8118  | 0  |   return has_hostname() && components.pathname_start != components.host_end;  | 
8119  | 0  | }  | 
8120  |  |  | 
8121  | 0  | [[nodiscard]] constexpr bool url_aggregator::has_dash_dot() const noexcept { | 
8122  | 0  |   // If url's host is null, url does not have an opaque path, url's path's size  | 
8123  | 0  |   // is greater than 1, and url's path[0] is the empty string, then append  | 
8124  | 0  |   // U+002F (/) followed by U+002E (.) to output.  | 
8125  | 0  |   ada_log("url_aggregator::has_dash_dot"); | 
8126  | 0  | #if ADA_DEVELOPMENT_CHECKS  | 
8127  | 0  |   // If pathname_start and host_end are exactly two characters apart, then we  | 
8128  | 0  |   // either have a one-digit port such as http://test.com:5?param=1 or else we  | 
8129  | 0  |   // have a /.: sequence such as "non-spec:/.//". We test that this is the case.  | 
8130  | 0  |   if (components.pathname_start == components.host_end + 2) { | 
8131  | 0  |     ADA_ASSERT_TRUE((buffer[components.host_end] == '/' &&  | 
8132  | 0  |                      buffer[components.host_end + 1] == '.') ||  | 
8133  | 0  |                     (buffer[components.host_end] == ':' &&  | 
8134  | 0  |                      checkers::is_digit(buffer[components.host_end + 1])));  | 
8135  | 0  |   }  | 
8136  | 0  |   if (components.pathname_start == components.host_end + 2 &&  | 
8137  | 0  |       buffer[components.host_end] == '/' &&  | 
8138  | 0  |       buffer[components.host_end + 1] == '.') { | 
8139  | 0  |     ADA_ASSERT_TRUE(components.pathname_start + 1 < buffer.size());  | 
8140  | 0  |     ADA_ASSERT_TRUE(buffer[components.pathname_start] == '/');  | 
8141  | 0  |     ADA_ASSERT_TRUE(buffer[components.pathname_start + 1] == '/');  | 
8142  | 0  |   }  | 
8143  | 0  | #endif  | 
8144  | 0  |   // Performance: it should be uncommon for components.pathname_start ==  | 
8145  | 0  |   // components.host_end + 2 to be true. So we put this check first in the  | 
8146  | 0  |   // sequence. Most times, we do not have an opaque path. Checking for '/.' is  | 
8147  | 0  |   // more expensive, but should be uncommon.  | 
8148  | 0  |   return components.pathname_start == components.host_end + 2 &&  | 
8149  | 0  |          !has_opaque_path && buffer[components.host_end] == '/' &&  | 
8150  | 0  |          buffer[components.host_end + 1] == '.';  | 
8151  | 0  | }  | 
8152  |  |  | 
8153  |  | [[nodiscard]] constexpr std::string_view url_aggregator::get_href()  | 
8154  | 0  |     const noexcept ada_lifetime_bound { | 
8155  | 0  |   ada_log("url_aggregator::get_href"); | 
8156  | 0  |   return buffer;  | 
8157  | 0  | }  | 
8158  |  |  | 
8159  |  | ada_really_inline size_t url_aggregator::parse_port(  | 
8160  | 0  |     std::string_view view, bool check_trailing_content) noexcept { | 
8161  | 0  |   ada_log("url_aggregator::parse_port('", view, "') ", view.size()); | 
8162  | 0  |   if (!view.empty() && view[0] == '-') { | 
8163  | 0  |     ada_log("parse_port: view[0] == '0' && view.size() > 1"); | 
8164  | 0  |     is_valid = false;  | 
8165  | 0  |     return 0;  | 
8166  | 0  |   }  | 
8167  | 0  |   uint16_t parsed_port{}; | 
8168  | 0  |   auto r = std::from_chars(view.data(), view.data() + view.size(), parsed_port);  | 
8169  | 0  |   if (r.ec == std::errc::result_out_of_range) { | 
8170  | 0  |     ada_log("parse_port: r.ec == std::errc::result_out_of_range"); | 
8171  | 0  |     is_valid = false;  | 
8172  | 0  |     return 0;  | 
8173  | 0  |   }  | 
8174  | 0  |   ada_log("parse_port: ", parsed_port); | 
8175  | 0  |   const size_t consumed = size_t(r.ptr - view.data());  | 
8176  | 0  |   ada_log("parse_port: consumed ", consumed); | 
8177  | 0  |   if (check_trailing_content) { | 
8178  | 0  |     is_valid &=  | 
8179  | 0  |         (consumed == view.size() || view[consumed] == '/' ||  | 
8180  | 0  |          view[consumed] == '?' || (is_special() && view[consumed] == '\\'));  | 
8181  | 0  |   }  | 
8182  | 0  |   ada_log("parse_port: is_valid = ", is_valid); | 
8183  | 0  |   if (is_valid) { | 
8184  | 0  |     ada_log("parse_port", r.ec == std::errc()); | 
8185  | 0  |     // scheme_default_port can return 0, and we should allow 0 as a base port.  | 
8186  | 0  |     auto default_port = scheme_default_port();  | 
8187  | 0  |     bool is_port_valid = (default_port == 0 && parsed_port == 0) ||  | 
8188  | 0  |                          (default_port != parsed_port);  | 
8189  | 0  |     if (r.ec == std::errc() && is_port_valid) { | 
8190  | 0  |       update_base_port(parsed_port);  | 
8191  | 0  |     } else { | 
8192  | 0  |       clear_port();  | 
8193  | 0  |     }  | 
8194  | 0  |   }  | 
8195  | 0  |   return consumed;  | 
8196  | 0  | }  | 
8197  |  |  | 
8198  | 0  | constexpr void url_aggregator::set_protocol_as_file() { | 
8199  | 0  |   ada_log("url_aggregator::set_protocol_as_file "); | 
8200  | 0  |   ADA_ASSERT_TRUE(validate());  | 
8201  | 0  |   type = ada::scheme::type::FILE;  | 
8202  | 0  |   // next line could overflow but unsigned arithmetic has well-defined  | 
8203  | 0  |   // overflows.  | 
8204  | 0  |   uint32_t new_difference = 5 - components.protocol_end;  | 
8205  | 0  | 
  | 
8206  | 0  |   if (buffer.empty()) { | 
8207  | 0  |     buffer.append("file:"); | 
8208  | 0  |   } else { | 
8209  | 0  |     buffer.erase(0, components.protocol_end);  | 
8210  | 0  |     buffer.insert(0, "file:");  | 
8211  | 0  |   }  | 
8212  | 0  |   components.protocol_end = 5;  | 
8213  | 0  | 
  | 
8214  | 0  |   // Update the rest of the components.  | 
8215  | 0  |   components.username_end += new_difference;  | 
8216  | 0  |   components.host_start += new_difference;  | 
8217  | 0  |   components.host_end += new_difference;  | 
8218  | 0  |   components.pathname_start += new_difference;  | 
8219  | 0  |   if (components.search_start != url_components::omitted) { | 
8220  | 0  |     components.search_start += new_difference;  | 
8221  | 0  |   }  | 
8222  | 0  |   if (components.hash_start != url_components::omitted) { | 
8223  | 0  |     components.hash_start += new_difference;  | 
8224  | 0  |   }  | 
8225  | 0  |   ADA_ASSERT_TRUE(validate());  | 
8226  | 0  | }  | 
8227  |  |  | 
8228  | 0  | [[nodiscard]] constexpr bool url_aggregator::validate() const noexcept { | 
8229  | 0  |   if (!is_valid) { | 
8230  | 0  |     return true;  | 
8231  | 0  |   }  | 
8232  | 0  |   if (!components.check_offset_consistency()) { | 
8233  | 0  |     ada_log("url_aggregator::validate inconsistent components \n", | 
8234  | 0  |             to_diagram());  | 
8235  | 0  |     return false;  | 
8236  | 0  |   }  | 
8237  | 0  |   // We have a credible components struct, but let us investivate more  | 
8238  | 0  |   // carefully:  | 
8239  | 0  |   /**  | 
8240  | 0  |    * https://user:pass@example.com:1234/foo/bar?baz#quux  | 
8241  | 0  |    *       |     |    |          | ^^^^|       |   |  | 
8242  | 0  |    *       |     |    |          | |   |       |   `----- hash_start  | 
8243  | 0  |    *       |     |    |          | |   |       `--------- search_start  | 
8244  | 0  |    *       |     |    |          | |   `----------------- pathname_start  | 
8245  | 0  |    *       |     |    |          | `--------------------- port  | 
8246  | 0  |    *       |     |    |          `----------------------- host_end  | 
8247  | 0  |    *       |     |    `---------------------------------- host_start  | 
8248  | 0  |    *       |     `--------------------------------------- username_end  | 
8249  | 0  |    *       `--------------------------------------------- protocol_end  | 
8250  | 0  |    */  | 
8251  | 0  |   if (components.protocol_end == url_components::omitted) { | 
8252  | 0  |     ada_log("url_aggregator::validate omitted protocol_end \n", to_diagram()); | 
8253  | 0  |     return false;  | 
8254  | 0  |   }  | 
8255  | 0  |   if (components.username_end == url_components::omitted) { | 
8256  | 0  |     ada_log("url_aggregator::validate omitted username_end \n", to_diagram()); | 
8257  | 0  |     return false;  | 
8258  | 0  |   }  | 
8259  | 0  |   if (components.host_start == url_components::omitted) { | 
8260  | 0  |     ada_log("url_aggregator::validate omitted host_start \n", to_diagram()); | 
8261  | 0  |     return false;  | 
8262  | 0  |   }  | 
8263  | 0  |   if (components.host_end == url_components::omitted) { | 
8264  | 0  |     ada_log("url_aggregator::validate omitted host_end \n", to_diagram()); | 
8265  | 0  |     return false;  | 
8266  | 0  |   }  | 
8267  | 0  |   if (components.pathname_start == url_components::omitted) { | 
8268  | 0  |     ada_log("url_aggregator::validate omitted pathname_start \n", to_diagram()); | 
8269  | 0  |     return false;  | 
8270  | 0  |   }  | 
8271  | 0  | 
  | 
8272  | 0  |   if (components.protocol_end > buffer.size()) { | 
8273  | 0  |     ada_log("url_aggregator::validate protocol_end overflow \n", to_diagram()); | 
8274  | 0  |     return false;  | 
8275  | 0  |   }  | 
8276  | 0  |   if (components.username_end > buffer.size()) { | 
8277  | 0  |     ada_log("url_aggregator::validate username_end overflow \n", to_diagram()); | 
8278  | 0  |     return false;  | 
8279  | 0  |   }  | 
8280  | 0  |   if (components.host_start > buffer.size()) { | 
8281  | 0  |     ada_log("url_aggregator::validate host_start overflow \n", to_diagram()); | 
8282  | 0  |     return false;  | 
8283  | 0  |   }  | 
8284  | 0  |   if (components.host_end > buffer.size()) { | 
8285  | 0  |     ada_log("url_aggregator::validate host_end overflow \n", to_diagram()); | 
8286  | 0  |     return false;  | 
8287  | 0  |   }  | 
8288  | 0  |   if (components.pathname_start > buffer.size()) { | 
8289  | 0  |     ada_log("url_aggregator::validate pathname_start overflow \n", | 
8290  | 0  |             to_diagram());  | 
8291  | 0  |     return false;  | 
8292  | 0  |   }  | 
8293  | 0  | 
  | 
8294  | 0  |   if (components.protocol_end > 0) { | 
8295  | 0  |     if (buffer[components.protocol_end - 1] != ':') { | 
8296  | 0  |       ada_log(  | 
8297  | 0  |           "url_aggregator::validate missing : at the end of the protocol \n",  | 
8298  | 0  |           to_diagram());  | 
8299  | 0  |       return false;  | 
8300  | 0  |     }  | 
8301  | 0  |   }  | 
8302  | 0  | 
  | 
8303  | 0  |   if (components.username_end != buffer.size() &&  | 
8304  | 0  |       components.username_end > components.protocol_end + 2) { | 
8305  | 0  |     if (buffer[components.username_end] != ':' &&  | 
8306  | 0  |         buffer[components.username_end] != '@') { | 
8307  | 0  |       ada_log(  | 
8308  | 0  |           "url_aggregator::validate missing : or @ at the end of the username "  | 
8309  | 0  |           "\n",  | 
8310  | 0  |           to_diagram());  | 
8311  | 0  |       return false;  | 
8312  | 0  |     }  | 
8313  | 0  |   }  | 
8314  | 0  | 
  | 
8315  | 0  |   if (components.host_start != buffer.size()) { | 
8316  | 0  |     if (components.host_start > components.username_end) { | 
8317  | 0  |       if (buffer[components.host_start] != '@') { | 
8318  | 0  |         ada_log(  | 
8319  | 0  |             "url_aggregator::validate missing @ at the end of the password \n",  | 
8320  | 0  |             to_diagram());  | 
8321  | 0  |         return false;  | 
8322  | 0  |       }  | 
8323  | 0  |     } else if (components.host_start == components.username_end &&  | 
8324  | 0  |                components.host_end > components.host_start) { | 
8325  | 0  |       if (components.host_start == components.protocol_end + 2) { | 
8326  | 0  |         if (buffer[components.protocol_end] != '/' ||  | 
8327  | 0  |             buffer[components.protocol_end + 1] != '/') { | 
8328  | 0  |           ada_log(  | 
8329  | 0  |               "url_aggregator::validate missing // between protocol and host "  | 
8330  | 0  |               "\n",  | 
8331  | 0  |               to_diagram());  | 
8332  | 0  |           return false;  | 
8333  | 0  |         }  | 
8334  | 0  |       } else { | 
8335  | 0  |         if (components.host_start > components.protocol_end &&  | 
8336  | 0  |             buffer[components.host_start] != '@') { | 
8337  | 0  |           ada_log(  | 
8338  | 0  |               "url_aggregator::validate missing @ at the end of the username "  | 
8339  | 0  |               "\n",  | 
8340  | 0  |               to_diagram());  | 
8341  | 0  |           return false;  | 
8342  | 0  |         }  | 
8343  | 0  |       }  | 
8344  | 0  |     } else { | 
8345  | 0  |       if (components.host_end != components.host_start) { | 
8346  | 0  |         ada_log("url_aggregator::validate expected omitted host \n", | 
8347  | 0  |                 to_diagram());  | 
8348  | 0  |         return false;  | 
8349  | 0  |       }  | 
8350  | 0  |     }  | 
8351  | 0  |   }  | 
8352  | 0  |   if (components.host_end != buffer.size() &&  | 
8353  | 0  |       components.pathname_start > components.host_end) { | 
8354  | 0  |     if (components.pathname_start == components.host_end + 2 &&  | 
8355  | 0  |         buffer[components.host_end] == '/' &&  | 
8356  | 0  |         buffer[components.host_end + 1] == '.') { | 
8357  | 0  |       if (components.pathname_start + 1 >= buffer.size() ||  | 
8358  | 0  |           buffer[components.pathname_start] != '/' ||  | 
8359  | 0  |           buffer[components.pathname_start + 1] != '/') { | 
8360  | 0  |         ada_log(  | 
8361  | 0  |             "url_aggregator::validate expected the path to begin with // \n",  | 
8362  | 0  |             to_diagram());  | 
8363  | 0  |         return false;  | 
8364  | 0  |       }  | 
8365  | 0  |     } else if (buffer[components.host_end] != ':') { | 
8366  | 0  |       ada_log("url_aggregator::validate missing : at the port \n", | 
8367  | 0  |               to_diagram());  | 
8368  | 0  |       return false;  | 
8369  | 0  |     }  | 
8370  | 0  |   }  | 
8371  | 0  |   if (components.pathname_start != buffer.size() &&  | 
8372  | 0  |       components.pathname_start < components.search_start &&  | 
8373  | 0  |       components.pathname_start < components.hash_start && !has_opaque_path) { | 
8374  | 0  |     if (buffer[components.pathname_start] != '/') { | 
8375  | 0  |       ada_log("url_aggregator::validate missing / at the path \n", | 
8376  | 0  |               to_diagram());  | 
8377  | 0  |       return false;  | 
8378  | 0  |     }  | 
8379  | 0  |   }  | 
8380  | 0  |   if (components.search_start != url_components::omitted) { | 
8381  | 0  |     if (buffer[components.search_start] != '?') { | 
8382  | 0  |       ada_log("url_aggregator::validate missing ? at the search \n", | 
8383  | 0  |               to_diagram());  | 
8384  | 0  |       return false;  | 
8385  | 0  |     }  | 
8386  | 0  |   }  | 
8387  | 0  |   if (components.hash_start != url_components::omitted) { | 
8388  | 0  |     if (buffer[components.hash_start] != '#') { | 
8389  | 0  |       ada_log("url_aggregator::validate missing # at the hash \n", | 
8390  | 0  |               to_diagram());  | 
8391  | 0  |       return false;  | 
8392  | 0  |     }  | 
8393  | 0  |   }  | 
8394  | 0  | 
  | 
8395  | 0  |   return true;  | 
8396  | 0  | }  | 
8397  |  |  | 
8398  |  | [[nodiscard]] constexpr std::string_view url_aggregator::get_pathname()  | 
8399  | 0  |     const noexcept ada_lifetime_bound { | 
8400  | 0  |   ada_log("url_aggregator::get_pathname pathname_start = ", | 
8401  | 0  |           components.pathname_start, " buffer.size() = ", buffer.size(),  | 
8402  | 0  |           " components.search_start = ", components.search_start,  | 
8403  | 0  |           " components.hash_start = ", components.hash_start);  | 
8404  | 0  |   auto ending_index = uint32_t(buffer.size());  | 
8405  | 0  |   if (components.search_start != url_components::omitted) { | 
8406  | 0  |     ending_index = components.search_start;  | 
8407  | 0  |   } else if (components.hash_start != url_components::omitted) { | 
8408  | 0  |     ending_index = components.hash_start;  | 
8409  | 0  |   }  | 
8410  | 0  |   return helpers::substring(buffer, components.pathname_start, ending_index);  | 
8411  | 0  | }  | 
8412  |  |  | 
8413  |  | inline std::ostream &operator<<(std::ostream &out,  | 
8414  | 0  |                                 const ada::url_aggregator &u) { | 
8415  | 0  |   return out << u.to_string();  | 
8416  | 0  | }  | 
8417  |  |  | 
8418  |  | void url_aggregator::update_host_to_base_host(  | 
8419  | 0  |     const std::string_view input) noexcept { | 
8420  | 0  |   ada_log("url_aggregator::update_host_to_base_host ", input); | 
8421  | 0  |   ADA_ASSERT_TRUE(validate());  | 
8422  | 0  |   ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));  | 
8423  | 0  |   if (type != ada::scheme::type::FILE) { | 
8424  | 0  |     // Let host be the result of host parsing host_view with url is not special.  | 
8425  | 0  |     if (input.empty() && !is_special()) { | 
8426  | 0  |       if (has_hostname()) { | 
8427  | 0  |         clear_hostname();  | 
8428  | 0  |       } else if (has_dash_dot()) { | 
8429  | 0  |         add_authority_slashes_if_needed();  | 
8430  | 0  |         delete_dash_dot();  | 
8431  | 0  |       }  | 
8432  | 0  |       return;  | 
8433  | 0  |     }  | 
8434  | 0  |   }  | 
8435  | 0  |   update_base_hostname(input);  | 
8436  | 0  |   ADA_ASSERT_TRUE(validate());  | 
8437  | 0  |   return;  | 
8438  | 0  | }  | 
8439  |  | }  // namespace ada  | 
8440  |  |  | 
8441  |  | #endif  // ADA_URL_AGGREGATOR_INL_H  | 
8442  |  | /* end file include/ada/url_aggregator-inl.h */  | 
8443  |  | /* begin file include/ada/url_search_params.h */  | 
8444  |  | /**  | 
8445  |  |  * @file url_search_params.h  | 
8446  |  |  * @brief Declaration for the URL Search Params  | 
8447  |  |  */  | 
8448  |  | #ifndef ADA_URL_SEARCH_PARAMS_H  | 
8449  |  | #define ADA_URL_SEARCH_PARAMS_H  | 
8450  |  |  | 
8451  |  | #include <optional>  | 
8452  |  | #include <string>  | 
8453  |  | #include <string_view>  | 
8454  |  | #include <vector>  | 
8455  |  |  | 
8456  |  | namespace ada { | 
8457  |  |  | 
8458  |  | enum class url_search_params_iter_type { | 
8459  |  |   KEYS,  | 
8460  |  |   VALUES,  | 
8461  |  |   ENTRIES,  | 
8462  |  | };  | 
8463  |  |  | 
8464  |  | template <typename T, url_search_params_iter_type Type>  | 
8465  |  | struct url_search_params_iter;  | 
8466  |  |  | 
8467  |  | typedef std::pair<std::string_view, std::string_view> key_value_view_pair;  | 
8468  |  |  | 
8469  |  | using url_search_params_keys_iter =  | 
8470  |  |     url_search_params_iter<std::string_view, url_search_params_iter_type::KEYS>;  | 
8471  |  | using url_search_params_values_iter =  | 
8472  |  |     url_search_params_iter<std::string_view,  | 
8473  |  |                            url_search_params_iter_type::VALUES>;  | 
8474  |  | using url_search_params_entries_iter =  | 
8475  |  |     url_search_params_iter<key_value_view_pair,  | 
8476  |  |                            url_search_params_iter_type::ENTRIES>;  | 
8477  |  |  | 
8478  |  | /**  | 
8479  |  |  * We require all strings to be valid UTF-8. It is the user's responsibility to  | 
8480  |  |  * ensure that the provided strings are valid UTF-8.  | 
8481  |  |  * @see https://url.spec.whatwg.org/#interface-urlsearchparams  | 
8482  |  |  */  | 
8483  |  | struct url_search_params { | 
8484  |  |   url_search_params() = default;  | 
8485  |  |  | 
8486  |  |   /**  | 
8487  |  |    * @see  | 
8488  |  |    * https://github.com/web-platform-tests/wpt/blob/master/url/urlsearchparams-constructor.any.js  | 
8489  |  |    */  | 
8490  | 0  |   explicit url_search_params(const std::string_view input) { | 
8491  | 0  |     initialize(input);  | 
8492  | 0  |   }  | 
8493  |  |  | 
8494  |  |   url_search_params(const url_search_params &u) = default;  | 
8495  |  |   url_search_params(url_search_params &&u) noexcept = default;  | 
8496  |  |   url_search_params &operator=(url_search_params &&u) noexcept = default;  | 
8497  |  |   url_search_params &operator=(const url_search_params &u) = default;  | 
8498  |  |   ~url_search_params() = default;  | 
8499  |  |  | 
8500  |  |   [[nodiscard]] inline size_t size() const noexcept;  | 
8501  |  |  | 
8502  |  |   /**  | 
8503  |  |    * Both key and value must be valid UTF-8.  | 
8504  |  |    * @see https://url.spec.whatwg.org/#dom-urlsearchparams-append  | 
8505  |  |    */  | 
8506  |  |   inline void append(std::string_view key, std::string_view value);  | 
8507  |  |  | 
8508  |  |   /**  | 
8509  |  |    * @see https://url.spec.whatwg.org/#dom-urlsearchparams-delete  | 
8510  |  |    */  | 
8511  |  |   inline void remove(std::string_view key);  | 
8512  |  |   inline void remove(std::string_view key, std::string_view value);  | 
8513  |  |  | 
8514  |  |   /**  | 
8515  |  |    * @see https://url.spec.whatwg.org/#dom-urlsearchparams-get  | 
8516  |  |    */  | 
8517  |  |   inline std::optional<std::string_view> get(std::string_view key);  | 
8518  |  |  | 
8519  |  |   /**  | 
8520  |  |    * @see https://url.spec.whatwg.org/#dom-urlsearchparams-getall  | 
8521  |  |    */  | 
8522  |  |   inline std::vector<std::string> get_all(std::string_view key);  | 
8523  |  |  | 
8524  |  |   /**  | 
8525  |  |    * @see https://url.spec.whatwg.org/#dom-urlsearchparams-has  | 
8526  |  |    */  | 
8527  |  |   inline bool has(std::string_view key) noexcept;  | 
8528  |  |   inline bool has(std::string_view key, std::string_view value) noexcept;  | 
8529  |  |  | 
8530  |  |   /**  | 
8531  |  |    * Both key and value must be valid UTF-8.  | 
8532  |  |    * @see https://url.spec.whatwg.org/#dom-urlsearchparams-set  | 
8533  |  |    */  | 
8534  |  |   inline void set(std::string_view key, std::string_view value);  | 
8535  |  |  | 
8536  |  |   /**  | 
8537  |  |    * @see https://url.spec.whatwg.org/#dom-urlsearchparams-sort  | 
8538  |  |    */  | 
8539  |  |   inline void sort();  | 
8540  |  |  | 
8541  |  |   /**  | 
8542  |  |    * @see https://url.spec.whatwg.org/#urlsearchparams-stringification-behavior  | 
8543  |  |    */  | 
8544  |  |   inline std::string to_string() const;  | 
8545  |  |  | 
8546  |  |   /**  | 
8547  |  |    * Returns a simple JS-style iterator over all of the keys in this  | 
8548  |  |    * url_search_params. The keys in the iterator are not unique. The valid  | 
8549  |  |    * lifespan of the iterator is tied to the url_search_params. The iterator  | 
8550  |  |    * must be freed when you're done with it.  | 
8551  |  |    * @see https://url.spec.whatwg.org/#interface-urlsearchparams  | 
8552  |  |    */  | 
8553  |  |   inline url_search_params_keys_iter get_keys();  | 
8554  |  |  | 
8555  |  |   /**  | 
8556  |  |    * Returns a simple JS-style iterator over all of the values in this  | 
8557  |  |    * url_search_params. The valid lifespan of the iterator is tied to the  | 
8558  |  |    * url_search_params. The iterator must be freed when you're done with it.  | 
8559  |  |    * @see https://url.spec.whatwg.org/#interface-urlsearchparams  | 
8560  |  |    */  | 
8561  |  |   inline url_search_params_values_iter get_values();  | 
8562  |  |  | 
8563  |  |   /**  | 
8564  |  |    * Returns a simple JS-style iterator over all of the entries in this  | 
8565  |  |    * url_search_params. The entries are pairs of keys and corresponding values.  | 
8566  |  |    * The valid lifespan of the iterator is tied to the url_search_params. The  | 
8567  |  |    * iterator must be freed when you're done with it.  | 
8568  |  |    * @see https://url.spec.whatwg.org/#interface-urlsearchparams  | 
8569  |  |    */  | 
8570  |  |   inline url_search_params_entries_iter get_entries();  | 
8571  |  |  | 
8572  |  |   /**  | 
8573  |  |    * C++ style conventional iterator support. const only because we  | 
8574  |  |    * do not really want the params to be modified via the iterator.  | 
8575  |  |    */  | 
8576  | 0  |   inline auto begin() const { return params.begin(); } | 
8577  | 0  |   inline auto end() const { return params.end(); } | 
8578  | 0  |   inline auto front() const { return params.front(); } | 
8579  | 0  |   inline auto back() const { return params.back(); } | 
8580  | 0  |   inline auto operator[](size_t index) const { return params[index]; } | 
8581  |  |  | 
8582  |  |   /**  | 
8583  |  |    * @private  | 
8584  |  |    * Used to reset the search params to a new input.  | 
8585  |  |    * Used primarily for C API.  | 
8586  |  |    * @param input  | 
8587  |  |    */  | 
8588  |  |   void reset(std::string_view input);  | 
8589  |  |  | 
8590  |  |  private:  | 
8591  |  |   typedef std::pair<std::string, std::string> key_value_pair;  | 
8592  |  |   std::vector<key_value_pair> params{}; | 
8593  |  |  | 
8594  |  |   /**  | 
8595  |  |    * The init parameter must be valid UTF-8.  | 
8596  |  |    * @see https://url.spec.whatwg.org/#concept-urlencoded-parser  | 
8597  |  |    */  | 
8598  |  |   void initialize(std::string_view init);  | 
8599  |  |  | 
8600  |  |   template <typename T, url_search_params_iter_type Type>  | 
8601  |  |   friend struct url_search_params_iter;  | 
8602  |  | };  // url_search_params  | 
8603  |  |  | 
8604  |  | /**  | 
8605  |  |  * Implements a non-conventional iterator pattern that is closer in style to  | 
8606  |  |  * JavaScript's definition of an iterator.  | 
8607  |  |  *  | 
8608  |  |  * @see https://webidl.spec.whatwg.org/#idl-iterable  | 
8609  |  |  */  | 
8610  |  | template <typename T, url_search_params_iter_type Type>  | 
8611  |  | struct url_search_params_iter { | 
8612  |  |   inline url_search_params_iter() : params(EMPTY) {} | 
8613  |  |   url_search_params_iter(const url_search_params_iter &u) = default;  | 
8614  |  |   url_search_params_iter(url_search_params_iter &&u) noexcept = default;  | 
8615  |  |   url_search_params_iter &operator=(url_search_params_iter &&u) noexcept =  | 
8616  |  |       default;  | 
8617  |  |   url_search_params_iter &operator=(const url_search_params_iter &u) = default;  | 
8618  |  |   ~url_search_params_iter() = default;  | 
8619  |  |  | 
8620  |  |   /**  | 
8621  |  |    * Return the next item in the iterator or std::nullopt if done.  | 
8622  |  |    */  | 
8623  |  |   inline std::optional<T> next();  | 
8624  |  |  | 
8625  |  |   inline bool has_next() const;  | 
8626  |  |  | 
8627  |  |  private:  | 
8628  |  |   static url_search_params EMPTY;  | 
8629  |  |   inline url_search_params_iter(url_search_params ¶ms_) : params(params_) {} | 
8630  |  |  | 
8631  |  |   url_search_params ¶ms;  | 
8632  |  |   size_t pos = 0;  | 
8633  |  |  | 
8634  |  |   friend struct url_search_params;  | 
8635  |  | };  | 
8636  |  |  | 
8637  |  | }  // namespace ada  | 
8638  |  | #endif  | 
8639  |  | /* end file include/ada/url_search_params.h */  | 
8640  |  | /* begin file include/ada/url_search_params-inl.h */  | 
8641  |  | /**  | 
8642  |  |  * @file url_search_params-inl.h  | 
8643  |  |  * @brief Inline declarations for the URL Search Params  | 
8644  |  |  */  | 
8645  |  | #ifndef ADA_URL_SEARCH_PARAMS_INL_H  | 
8646  |  | #define ADA_URL_SEARCH_PARAMS_INL_H  | 
8647  |  |  | 
8648  |  |  | 
8649  |  | #include <algorithm>  | 
8650  |  | #include <optional>  | 
8651  |  | #include <ranges>  | 
8652  |  | #include <string>  | 
8653  |  | #include <string_view>  | 
8654  |  | #include <vector>  | 
8655  |  |  | 
8656  |  | namespace ada { | 
8657  |  |  | 
8658  |  | // A default, empty url_search_params for use with empty iterators.  | 
8659  |  | template <typename T, ada::url_search_params_iter_type Type>  | 
8660  |  | url_search_params url_search_params_iter<T, Type>::EMPTY;  | 
8661  |  |  | 
8662  | 0  | inline void url_search_params::reset(std::string_view input) { | 
8663  | 0  |   params.clear();  | 
8664  | 0  |   initialize(input);  | 
8665  | 0  | }  | 
8666  |  |  | 
8667  | 0  | inline void url_search_params::initialize(std::string_view input) { | 
8668  | 0  |   if (!input.empty() && input.front() == '?') { | 
8669  | 0  |     input.remove_prefix(1);  | 
8670  | 0  |   }  | 
8671  | 0  | 
  | 
8672  | 0  |   auto process_key_value = [&](const std::string_view current) { | 
8673  | 0  |     auto equal = current.find('='); | 
8674  | 0  | 
  | 
8675  | 0  |     if (equal == std::string_view::npos) { | 
8676  | 0  |       std::string name(current);  | 
8677  | 0  |       std::ranges::replace(name, '+', ' ');  | 
8678  | 0  |       params.emplace_back(unicode::percent_decode(name, name.find('%')), ""); | 
8679  | 0  |     } else { | 
8680  | 0  |       std::string name(current.substr(0, equal));  | 
8681  | 0  |       std::string value(current.substr(equal + 1));  | 
8682  | 0  | 
  | 
8683  | 0  |       std::ranges::replace(name, '+', ' ');  | 
8684  | 0  |       std::ranges::replace(value, '+', ' ');  | 
8685  | 0  | 
  | 
8686  | 0  |       params.emplace_back(unicode::percent_decode(name, name.find('%')), | 
8687  | 0  |                           unicode::percent_decode(value, value.find('%'))); | 
8688  | 0  |     }  | 
8689  | 0  |   };  | 
8690  | 0  | 
  | 
8691  | 0  |   while (!input.empty()) { | 
8692  | 0  |     auto ampersand_index = input.find('&'); | 
8693  | 0  | 
  | 
8694  | 0  |     if (ampersand_index == std::string_view::npos) { | 
8695  | 0  |       if (!input.empty()) { | 
8696  | 0  |         process_key_value(input);  | 
8697  | 0  |       }  | 
8698  | 0  |       break;  | 
8699  | 0  |     } else if (ampersand_index != 0) { | 
8700  | 0  |       process_key_value(input.substr(0, ampersand_index));  | 
8701  | 0  |     }  | 
8702  | 0  | 
  | 
8703  | 0  |     input.remove_prefix(ampersand_index + 1);  | 
8704  | 0  |   }  | 
8705  | 0  | }  | 
8706  |  |  | 
8707  |  | inline void url_search_params::append(const std::string_view key,  | 
8708  | 0  |                                       const std::string_view value) { | 
8709  | 0  |   params.emplace_back(key, value);  | 
8710  | 0  | }  | 
8711  |  |  | 
8712  | 0  | inline size_t url_search_params::size() const noexcept { return params.size(); } | 
8713  |  |  | 
8714  |  | inline std::optional<std::string_view> url_search_params::get(  | 
8715  | 0  |     const std::string_view key) { | 
8716  | 0  |   auto entry = std::ranges::find_if(  | 
8717  | 0  |       params, [&key](const auto ¶m) { return param.first == key; }); | 
8718  | 0  | 
  | 
8719  | 0  |   if (entry == params.end()) { | 
8720  | 0  |     return std::nullopt;  | 
8721  | 0  |   }  | 
8722  | 0  | 
  | 
8723  | 0  |   return entry->second;  | 
8724  | 0  | }  | 
8725  |  |  | 
8726  |  | inline std::vector<std::string> url_search_params::get_all(  | 
8727  | 0  |     const std::string_view key) { | 
8728  | 0  |   std::vector<std::string> out{}; | 
8729  | 0  | 
  | 
8730  | 0  |   for (auto ¶m : params) { | 
8731  | 0  |     if (param.first == key) { | 
8732  | 0  |       out.emplace_back(param.second);  | 
8733  | 0  |     }  | 
8734  | 0  |   }  | 
8735  | 0  | 
  | 
8736  | 0  |   return out;  | 
8737  | 0  | }  | 
8738  |  |  | 
8739  | 0  | inline bool url_search_params::has(const std::string_view key) noexcept { | 
8740  | 0  |   auto entry = std::ranges::find_if(  | 
8741  | 0  |       params, [&key](const auto ¶m) { return param.first == key; }); | 
8742  | 0  |   return entry != params.end();  | 
8743  | 0  | }  | 
8744  |  |  | 
8745  |  | inline bool url_search_params::has(std::string_view key,  | 
8746  | 0  |                                    std::string_view value) noexcept { | 
8747  | 0  |   auto entry = std::ranges::find_if(params, [&key, &value](const auto ¶m) { | 
8748  | 0  |     return param.first == key && param.second == value;  | 
8749  | 0  |   });  | 
8750  | 0  |   return entry != params.end();  | 
8751  | 0  | }  | 
8752  |  |  | 
8753  | 0  | inline std::string url_search_params::to_string() const { | 
8754  | 0  |   auto character_set = ada::character_sets::WWW_FORM_URLENCODED_PERCENT_ENCODE;  | 
8755  | 0  |   std::string out{}; | 
8756  | 0  |   for (size_t i = 0; i < params.size(); i++) { | 
8757  | 0  |     auto key = ada::unicode::percent_encode(params[i].first, character_set);  | 
8758  | 0  |     auto value = ada::unicode::percent_encode(params[i].second, character_set);  | 
8759  | 0  | 
  | 
8760  | 0  |     // Performance optimization: Move this inside percent_encode.  | 
8761  | 0  |     std::ranges::replace(key, ' ', '+');  | 
8762  | 0  |     std::ranges::replace(value, ' ', '+');  | 
8763  | 0  | 
  | 
8764  | 0  |     if (i != 0) { | 
8765  | 0  |       out += "&";  | 
8766  | 0  |     }  | 
8767  | 0  |     out.append(key);  | 
8768  | 0  |     out += "=";  | 
8769  | 0  |     out.append(value);  | 
8770  | 0  |   }  | 
8771  | 0  |   return out;  | 
8772  | 0  | }  | 
8773  |  |  | 
8774  |  | inline void url_search_params::set(const std::string_view key,  | 
8775  | 0  |                                    const std::string_view value) { | 
8776  | 0  |   const auto find = [&key](const auto ¶m) { return param.first == key; }; | 
8777  | 0  | 
  | 
8778  | 0  |   auto it = std::ranges::find_if(params, find);  | 
8779  | 0  | 
  | 
8780  | 0  |   if (it == params.end()) { | 
8781  | 0  |     params.emplace_back(key, value);  | 
8782  | 0  |   } else { | 
8783  | 0  |     it->second = value;  | 
8784  | 0  |     params.erase(std::remove_if(std::next(it), params.end(), find),  | 
8785  | 0  |                  params.end());  | 
8786  | 0  |   }  | 
8787  | 0  | }  | 
8788  |  |  | 
8789  | 0  | inline void url_search_params::remove(const std::string_view key) { | 
8790  | 0  |   std::erase_if(params,  | 
8791  | 0  |                 [&key](const auto ¶m) { return param.first == key; }); | 
8792  | 0  | }  | 
8793  |  |  | 
8794  |  | inline void url_search_params::remove(const std::string_view key,  | 
8795  | 0  |                                       const std::string_view value) { | 
8796  | 0  |   std::erase_if(params, [&key, &value](const auto ¶m) { | 
8797  | 0  |     return param.first == key && param.second == value;  | 
8798  | 0  |   });  | 
8799  | 0  | }  | 
8800  |  |  | 
8801  | 0  | inline void url_search_params::sort() { | 
8802  | 0  |   // We rely on the fact that the content is valid UTF-8.  | 
8803  | 0  |   std::ranges::stable_sort(params, [](const key_value_pair &lhs,  | 
8804  | 0  |                                       const key_value_pair &rhs) { | 
8805  | 0  |     size_t i = 0, j = 0;  | 
8806  | 0  |     uint32_t low_surrogate1 = 0, low_surrogate2 = 0;  | 
8807  | 0  |     while ((i < lhs.first.size() || low_surrogate1 != 0) &&  | 
8808  | 0  |            (j < rhs.first.size() || low_surrogate2 != 0)) { | 
8809  | 0  |       uint32_t codePoint1 = 0, codePoint2 = 0;  | 
8810  | 0  | 
  | 
8811  | 0  |       if (low_surrogate1 != 0) { | 
8812  | 0  |         codePoint1 = low_surrogate1;  | 
8813  | 0  |         low_surrogate1 = 0;  | 
8814  | 0  |       } else { | 
8815  | 0  |         uint8_t c1 = uint8_t(lhs.first[i]);  | 
8816  | 0  |         if (c1 <= 0x7F) { | 
8817  | 0  |           codePoint1 = c1;  | 
8818  | 0  |           i++;  | 
8819  | 0  |         } else if (c1 <= 0xDF) { | 
8820  | 0  |           codePoint1 = ((c1 & 0x1F) << 6) | (uint8_t(lhs.first[i + 1]) & 0x3F);  | 
8821  | 0  |           i += 2;  | 
8822  | 0  |         } else if (c1 <= 0xEF) { | 
8823  | 0  |           codePoint1 = ((c1 & 0x0F) << 12) |  | 
8824  | 0  |                        ((uint8_t(lhs.first[i + 1]) & 0x3F) << 6) |  | 
8825  | 0  |                        (uint8_t(lhs.first[i + 2]) & 0x3F);  | 
8826  | 0  |           i += 3;  | 
8827  | 0  |         } else { | 
8828  | 0  |           codePoint1 = ((c1 & 0x07) << 18) |  | 
8829  | 0  |                        ((uint8_t(lhs.first[i + 1]) & 0x3F) << 12) |  | 
8830  | 0  |                        ((uint8_t(lhs.first[i + 2]) & 0x3F) << 6) |  | 
8831  | 0  |                        (uint8_t(lhs.first[i + 3]) & 0x3F);  | 
8832  | 0  |           i += 4;  | 
8833  | 0  | 
  | 
8834  | 0  |           codePoint1 -= 0x10000;  | 
8835  | 0  |           uint16_t high_surrogate = uint16_t(0xD800 + (codePoint1 >> 10));  | 
8836  | 0  |           low_surrogate1 = uint16_t(0xDC00 + (codePoint1 & 0x3FF));  | 
8837  | 0  |           codePoint1 = high_surrogate;  | 
8838  | 0  |         }  | 
8839  | 0  |       }  | 
8840  | 0  | 
  | 
8841  | 0  |       if (low_surrogate2 != 0) { | 
8842  | 0  |         codePoint2 = low_surrogate2;  | 
8843  | 0  |         low_surrogate2 = 0;  | 
8844  | 0  |       } else { | 
8845  | 0  |         uint8_t c2 = uint8_t(rhs.first[j]);  | 
8846  | 0  |         if (c2 <= 0x7F) { | 
8847  | 0  |           codePoint2 = c2;  | 
8848  | 0  |           j++;  | 
8849  | 0  |         } else if (c2 <= 0xDF) { | 
8850  | 0  |           codePoint2 = ((c2 & 0x1F) << 6) | (uint8_t(rhs.first[j + 1]) & 0x3F);  | 
8851  | 0  |           j += 2;  | 
8852  | 0  |         } else if (c2 <= 0xEF) { | 
8853  | 0  |           codePoint2 = ((c2 & 0x0F) << 12) |  | 
8854  | 0  |                        ((uint8_t(rhs.first[j + 1]) & 0x3F) << 6) |  | 
8855  | 0  |                        (uint8_t(rhs.first[j + 2]) & 0x3F);  | 
8856  | 0  |           j += 3;  | 
8857  | 0  |         } else { | 
8858  | 0  |           codePoint2 = ((c2 & 0x07) << 18) |  | 
8859  | 0  |                        ((uint8_t(rhs.first[j + 1]) & 0x3F) << 12) |  | 
8860  | 0  |                        ((uint8_t(rhs.first[j + 2]) & 0x3F) << 6) |  | 
8861  | 0  |                        (uint8_t(rhs.first[j + 3]) & 0x3F);  | 
8862  | 0  |           j += 4;  | 
8863  | 0  |           codePoint2 -= 0x10000;  | 
8864  | 0  |           uint16_t high_surrogate = uint16_t(0xD800 + (codePoint2 >> 10));  | 
8865  | 0  |           low_surrogate2 = uint16_t(0xDC00 + (codePoint2 & 0x3FF));  | 
8866  | 0  |           codePoint2 = high_surrogate;  | 
8867  | 0  |         }  | 
8868  | 0  |       }  | 
8869  | 0  | 
  | 
8870  | 0  |       if (codePoint1 != codePoint2) { | 
8871  | 0  |         return (codePoint1 < codePoint2);  | 
8872  | 0  |       }  | 
8873  | 0  |     }  | 
8874  | 0  |     return (j < rhs.first.size() || low_surrogate2 != 0);  | 
8875  | 0  |   });  | 
8876  | 0  | }  | 
8877  |  |  | 
8878  | 0  | inline url_search_params_keys_iter url_search_params::get_keys() { | 
8879  | 0  |   return url_search_params_keys_iter(*this);  | 
8880  | 0  | }  | 
8881  |  |  | 
8882  |  | /**  | 
8883  |  |  * @see https://url.spec.whatwg.org/#interface-urlsearchparams  | 
8884  |  |  */  | 
8885  | 0  | inline url_search_params_values_iter url_search_params::get_values() { | 
8886  | 0  |   return url_search_params_values_iter(*this);  | 
8887  | 0  | }  | 
8888  |  |  | 
8889  |  | /**  | 
8890  |  |  * @see https://url.spec.whatwg.org/#interface-urlsearchparams  | 
8891  |  |  */  | 
8892  | 0  | inline url_search_params_entries_iter url_search_params::get_entries() { | 
8893  | 0  |   return url_search_params_entries_iter(*this);  | 
8894  | 0  | }  | 
8895  |  |  | 
8896  |  | template <typename T, url_search_params_iter_type Type>  | 
8897  | 0  | inline bool url_search_params_iter<T, Type>::has_next() const { | 
8898  | 0  |   return pos < params.params.size();  | 
8899  | 0  | } Unexecuted instantiation: ada::url_search_params_iter<std::__1::basic_string_view<char, std::__1::char_traits<char> >, (ada::url_search_params_iter_type)0>::has_next() const Unexecuted instantiation: ada::url_search_params_iter<std::__1::basic_string_view<char, std::__1::char_traits<char> >, (ada::url_search_params_iter_type)1>::has_next() const Unexecuted instantiation: ada::url_search_params_iter<std::__1::pair<std::__1::basic_string_view<char, std::__1::char_traits<char> >, std::__1::basic_string_view<char, std::__1::char_traits<char> > >, (ada::url_search_params_iter_type)2>::has_next() const  | 
8900  |  |  | 
8901  |  | template <>  | 
8902  | 0  | inline std::optional<std::string_view> url_search_params_keys_iter::next() { | 
8903  | 0  |   if (!has_next()) { | 
8904  | 0  |     return std::nullopt;  | 
8905  | 0  |   }  | 
8906  | 0  |   return params.params[pos++].first;  | 
8907  | 0  | }  | 
8908  |  |  | 
8909  |  | template <>  | 
8910  | 0  | inline std::optional<std::string_view> url_search_params_values_iter::next() { | 
8911  | 0  |   if (!has_next()) { | 
8912  | 0  |     return std::nullopt;  | 
8913  | 0  |   }  | 
8914  | 0  |   return params.params[pos++].second;  | 
8915  | 0  | }  | 
8916  |  |  | 
8917  |  | template <>  | 
8918  |  | inline std::optional<key_value_view_pair>  | 
8919  | 0  | url_search_params_entries_iter::next() { | 
8920  | 0  |   if (!has_next()) { | 
8921  | 0  |     return std::nullopt;  | 
8922  | 0  |   }  | 
8923  | 0  |   return params.params[pos++];  | 
8924  | 0  | }  | 
8925  |  |  | 
8926  |  | }  // namespace ada  | 
8927  |  |  | 
8928  |  | #endif  // ADA_URL_SEARCH_PARAMS_INL_H  | 
8929  |  | /* end file include/ada/url_search_params-inl.h */  | 
8930  |  |  | 
8931  |  | /* begin file include/ada/url_pattern-inl.h */  | 
8932  |  | /**  | 
8933  |  |  * @file url_pattern-inl.h  | 
8934  |  |  * @brief Declaration for the URLPattern inline functions.  | 
8935  |  |  */  | 
8936  |  | #ifndef ADA_URL_PATTERN_INL_H  | 
8937  |  | #define ADA_URL_PATTERN_INL_H  | 
8938  |  |  | 
8939  |  |  | 
8940  |  | #include <algorithm>  | 
8941  |  | #include <string_view>  | 
8942  |  | #include <utility>  | 
8943  |  |  | 
8944  |  | #if ADA_INCLUDE_URL_PATTERN  | 
8945  |  | namespace ada { | 
8946  |  |  | 
8947  | 0  | inline bool url_pattern_init::operator==(const url_pattern_init& other) const { | 
8948  | 0  |   return protocol == other.protocol && username == other.username &&  | 
8949  | 0  |          password == other.password && hostname == other.hostname &&  | 
8950  | 0  |          port == other.port && search == other.search && hash == other.hash &&  | 
8951  | 0  |          pathname == other.pathname;  | 
8952  | 0  | }  | 
8953  |  |  | 
8954  |  | inline bool url_pattern_component_result::operator==(  | 
8955  | 0  |     const url_pattern_component_result& other) const { | 
8956  | 0  |   return input == other.input && groups == other.groups;  | 
8957  | 0  | }  | 
8958  |  |  | 
8959  |  | template <url_pattern_regex::regex_concept regex_provider>  | 
8960  |  | url_pattern_component_result  | 
8961  |  | url_pattern_component<regex_provider>::create_component_match_result(  | 
8962  |  |     std::string&& input,  | 
8963  | 0  |     std::vector<std::optional<std::string>>&& exec_result) { | 
8964  |  |   // Let result be a new URLPatternComponentResult.  | 
8965  |  |   // Set result["input"] to input.  | 
8966  |  |   // Let groups be a record<USVString, (USVString or undefined)>.  | 
8967  | 0  |   auto result =  | 
8968  | 0  |       url_pattern_component_result{.input = std::move(input), .groups = {}}; | 
8969  |  |  | 
8970  |  |   // Optimization: Let's reserve the size.  | 
8971  | 0  |   result.groups.reserve(exec_result.size());  | 
8972  |  |  | 
8973  |  |   // We explicitly start iterating from 0 even though the spec  | 
8974  |  |   // says we should start from 1. This case is handled by the  | 
8975  |  |   // std_regex_provider.  | 
8976  | 0  |   for (size_t index = 0; index < exec_result.size(); index++) { | 
8977  | 0  |     result.groups.insert({ | 
8978  | 0  |         group_name_list[index],  | 
8979  | 0  |         std::move(exec_result[index]),  | 
8980  | 0  |     });  | 
8981  | 0  |   }  | 
8982  | 0  |   return result;  | 
8983  | 0  | }  | 
8984  |  |  | 
8985  |  | template <url_pattern_regex::regex_concept regex_provider>  | 
8986  |  | std::string_view url_pattern<regex_provider>::get_protocol() const  | 
8987  | 0  |     ada_lifetime_bound { | 
8988  |  |   // Return this's associated URL pattern's protocol component's pattern string.  | 
8989  | 0  |   return protocol_component.pattern;  | 
8990  | 0  | }  | 
8991  |  | template <url_pattern_regex::regex_concept regex_provider>  | 
8992  |  | std::string_view url_pattern<regex_provider>::get_username() const  | 
8993  | 0  |     ada_lifetime_bound { | 
8994  |  |   // Return this's associated URL pattern's username component's pattern string.  | 
8995  | 0  |   return username_component.pattern;  | 
8996  | 0  | }  | 
8997  |  | template <url_pattern_regex::regex_concept regex_provider>  | 
8998  |  | std::string_view url_pattern<regex_provider>::get_password() const  | 
8999  | 0  |     ada_lifetime_bound { | 
9000  |  |   // Return this's associated URL pattern's password component's pattern string.  | 
9001  | 0  |   return password_component.pattern;  | 
9002  | 0  | }  | 
9003  |  | template <url_pattern_regex::regex_concept regex_provider>  | 
9004  |  | std::string_view url_pattern<regex_provider>::get_hostname() const  | 
9005  | 0  |     ada_lifetime_bound { | 
9006  |  |   // Return this's associated URL pattern's hostname component's pattern string.  | 
9007  | 0  |   return hostname_component.pattern;  | 
9008  | 0  | }  | 
9009  |  | template <url_pattern_regex::regex_concept regex_provider>  | 
9010  |  | std::string_view url_pattern<regex_provider>::get_port() const  | 
9011  | 0  |     ada_lifetime_bound { | 
9012  |  |   // Return this's associated URL pattern's port component's pattern string.  | 
9013  | 0  |   return port_component.pattern;  | 
9014  | 0  | }  | 
9015  |  | template <url_pattern_regex::regex_concept regex_provider>  | 
9016  |  | std::string_view url_pattern<regex_provider>::get_pathname() const  | 
9017  | 0  |     ada_lifetime_bound { | 
9018  |  |   // Return this's associated URL pattern's pathname component's pattern string.  | 
9019  | 0  |   return pathname_component.pattern;  | 
9020  | 0  | }  | 
9021  |  | template <url_pattern_regex::regex_concept regex_provider>  | 
9022  |  | std::string_view url_pattern<regex_provider>::get_search() const  | 
9023  | 0  |     ada_lifetime_bound { | 
9024  |  |   // Return this's associated URL pattern's search component's pattern string.  | 
9025  | 0  |   return search_component.pattern;  | 
9026  | 0  | }  | 
9027  |  | template <url_pattern_regex::regex_concept regex_provider>  | 
9028  |  | std::string_view url_pattern<regex_provider>::get_hash() const  | 
9029  | 0  |     ada_lifetime_bound { | 
9030  |  |   // Return this's associated URL pattern's hash component's pattern string.  | 
9031  | 0  |   return hash_component.pattern;  | 
9032  | 0  | }  | 
9033  |  | template <url_pattern_regex::regex_concept regex_provider>  | 
9034  |  | bool url_pattern<regex_provider>::ignore_case() const { | 
9035  |  |   return ignore_case_;  | 
9036  |  | }  | 
9037  |  | template <url_pattern_regex::regex_concept regex_provider>  | 
9038  | 0  | bool url_pattern<regex_provider>::has_regexp_groups() const { | 
9039  |  |   // If this's associated URL pattern's has regexp groups, then return true.  | 
9040  | 0  |   return protocol_component.has_regexp_groups ||  | 
9041  | 0  |          username_component.has_regexp_groups ||  | 
9042  | 0  |          password_component.has_regexp_groups ||  | 
9043  | 0  |          hostname_component.has_regexp_groups ||  | 
9044  | 0  |          port_component.has_regexp_groups ||  | 
9045  | 0  |          pathname_component.has_regexp_groups ||  | 
9046  | 0  |          search_component.has_regexp_groups || hash_component.has_regexp_groups;  | 
9047  | 0  | }  | 
9048  |  |  | 
9049  | 0  | inline bool url_pattern_part::is_regexp() const noexcept { | 
9050  | 0  |   return type == url_pattern_part_type::REGEXP;  | 
9051  | 0  | }  | 
9052  |  |  | 
9053  |  | inline std::string_view url_pattern_compile_component_options::get_delimiter()  | 
9054  | 0  |     const { | 
9055  | 0  |   if (delimiter) { | 
9056  | 0  |     return {&delimiter.value(), 1}; | 
9057  | 0  |   }  | 
9058  | 0  |   return {}; | 
9059  | 0  | }  | 
9060  |  |  | 
9061  |  | inline std::string_view url_pattern_compile_component_options::get_prefix()  | 
9062  | 0  |     const { | 
9063  | 0  |   if (prefix) { | 
9064  | 0  |     return {&prefix.value(), 1}; | 
9065  | 0  |   }  | 
9066  | 0  |   return {}; | 
9067  | 0  | }  | 
9068  |  |  | 
9069  |  | template <url_pattern_regex::regex_concept regex_provider>  | 
9070  |  | template <url_pattern_encoding_callback F>  | 
9071  |  | tl::expected<url_pattern_component<regex_provider>, errors>  | 
9072  |  | url_pattern_component<regex_provider>::compile(  | 
9073  |  |     std::string_view input, F& encoding_callback,  | 
9074  | 0  |     url_pattern_compile_component_options& options) { | 
9075  | 0  |   ada_log("url_pattern_component::compile input: ", input); | 
9076  |  |   // Let part list be the result of running parse a pattern string given input,  | 
9077  |  |   // options, and encoding callback.  | 
9078  | 0  |   auto part_list = url_pattern_helpers::parse_pattern_string(input, options,  | 
9079  | 0  |                                                              encoding_callback);  | 
9080  |  | 
  | 
9081  | 0  |   if (!part_list) { | 
9082  | 0  |     ada_log("parse_pattern_string failed"); | 
9083  | 0  |     return tl::unexpected(part_list.error());  | 
9084  | 0  |   }  | 
9085  |  |  | 
9086  |  |   // Let (regular expression string, name list) be the result of running  | 
9087  |  |   // generate a regular expression and name list given part list and options.  | 
9088  | 0  |   auto [regular_expression_string, name_list] =  | 
9089  | 0  |       url_pattern_helpers::generate_regular_expression_and_name_list(*part_list,  | 
9090  | 0  |                                                                      options);  | 
9091  |  | 
  | 
9092  | 0  |   ada_log("regular expression string: ", regular_expression_string); | 
9093  |  |  | 
9094  |  |   // Let pattern string be the result of running generate a pattern  | 
9095  |  |   // string given part list and options.  | 
9096  | 0  |   auto pattern_string =  | 
9097  | 0  |       url_pattern_helpers::generate_pattern_string(*part_list, options);  | 
9098  |  |  | 
9099  |  |   // Let regular expression be RegExpCreate(regular expression string,  | 
9100  |  |   // flags). If this throws an exception, catch it, and throw a  | 
9101  |  |   // TypeError.  | 
9102  | 0  |   std::optional<typename regex_provider::regex_type> regular_expression =  | 
9103  | 0  |       regex_provider::create_instance(regular_expression_string,  | 
9104  | 0  |                                       options.ignore_case);  | 
9105  |  | 
  | 
9106  | 0  |   if (!regular_expression) { | 
9107  | 0  |     return tl::unexpected(errors::type_error);  | 
9108  | 0  |   }  | 
9109  |  |  | 
9110  |  |   // For each part of part list:  | 
9111  |  |   // - If part's type is "regexp", then set has regexp groups to true.  | 
9112  | 0  |   const auto has_regexp = [](const auto& part) { return part.is_regexp(); }; | 
9113  | 0  |   const bool has_regexp_groups = std::ranges::any_of(*part_list, has_regexp);  | 
9114  |  | 
  | 
9115  | 0  |   ada_log("has regexp groups: ", has_regexp_groups); | 
9116  |  |  | 
9117  |  |   // Return a new component whose pattern string is pattern string, regular  | 
9118  |  |   // expression is regular expression, group name list is name list, and has  | 
9119  |  |   // regexp groups is has regexp groups.  | 
9120  | 0  |   return url_pattern_component<regex_provider>(  | 
9121  | 0  |       std::move(pattern_string), std::move(*regular_expression),  | 
9122  | 0  |       std::move(name_list), has_regexp_groups);  | 
9123  | 0  | }  | 
9124  |  |  | 
9125  |  | template <url_pattern_regex::regex_concept regex_provider>  | 
9126  |  | result<std::optional<url_pattern_result>> url_pattern<regex_provider>::exec(  | 
9127  | 0  |     const url_pattern_input& input, const std::string_view* base_url) { | 
9128  |  |   // Return the result of match given this's associated URL pattern, input, and  | 
9129  |  |   // baseURL if given.  | 
9130  | 0  |   return match(input, base_url);  | 
9131  | 0  | }  | 
9132  |  |  | 
9133  |  | template <url_pattern_regex::regex_concept regex_provider>  | 
9134  |  | result<bool> url_pattern<regex_provider>::test(  | 
9135  | 0  |     const url_pattern_input& input, const std::string_view* base_url) { | 
9136  |  |   // TODO: Optimization opportunity. Rather than returning `url_pattern_result`  | 
9137  |  |   // Implement a fast path just like `can_parse()` in ada_url.  | 
9138  |  |   // Let result be the result of match given this's associated URL pattern,  | 
9139  |  |   // input, and baseURL if given.  | 
9140  |  |   // If result is null, return false.  | 
9141  | 0  |   if (auto result = match(input, base_url); result.has_value()) { | 
9142  | 0  |     return result->has_value();  | 
9143  | 0  |   }  | 
9144  | 0  |   return tl::unexpected(errors::type_error);  | 
9145  | 0  | }  | 
9146  |  |  | 
9147  |  | template <url_pattern_regex::regex_concept regex_provider>  | 
9148  |  | result<std::optional<url_pattern_result>> url_pattern<regex_provider>::match(  | 
9149  | 0  |     const url_pattern_input& input, const std::string_view* base_url_string) { | 
9150  | 0  |   std::string protocol{}; | 
9151  | 0  |   std::string username{}; | 
9152  | 0  |   std::string password{}; | 
9153  | 0  |   std::string hostname{}; | 
9154  | 0  |   std::string port{}; | 
9155  | 0  |   std::string pathname{}; | 
9156  | 0  |   std::string search{}; | 
9157  | 0  |   std::string hash{}; | 
9158  |  |  | 
9159  |  |   // Let inputs be an empty list.  | 
9160  |  |   // Append input to inputs.  | 
9161  | 0  |   std::vector inputs{input}; | 
9162  |  |  | 
9163  |  |   // If input is a URLPatternInit then:  | 
9164  | 0  |   if (std::holds_alternative<url_pattern_init>(input)) { | 
9165  | 0  |     ada_log(  | 
9166  | 0  |         "url_pattern::match called with url_pattern_init and base_url_string=",  | 
9167  | 0  |         base_url_string);  | 
9168  |  |     // If baseURLString was given, throw a TypeError.  | 
9169  | 0  |     if (base_url_string) { | 
9170  | 0  |       ada_log("failed to match because base_url_string was given"); | 
9171  | 0  |       return tl::unexpected(errors::type_error);  | 
9172  | 0  |     }  | 
9173  |  |  | 
9174  |  |     // Let applyResult be the result of process a URLPatternInit given input,  | 
9175  |  |     // "url", protocol, username, password, hostname, port, pathname, search,  | 
9176  |  |     // and hash.  | 
9177  | 0  |     auto apply_result = url_pattern_init::process(  | 
9178  | 0  |         std::get<url_pattern_init>(input), url_pattern_init::process_type::url,  | 
9179  | 0  |         protocol, username, password, hostname, port, pathname, search, hash);  | 
9180  |  |  | 
9181  |  |     // If this throws an exception, catch it, and return null.  | 
9182  | 0  |     if (!apply_result.has_value()) { | 
9183  | 0  |       ada_log("match returned std::nullopt because process threw"); | 
9184  | 0  |       return std::nullopt;  | 
9185  | 0  |     }  | 
9186  |  |  | 
9187  |  |     // Set protocol to applyResult["protocol"].  | 
9188  | 0  |     ADA_ASSERT_TRUE(apply_result->protocol.has_value());  | 
9189  | 0  |     protocol = std::move(apply_result->protocol.value());  | 
9190  |  |  | 
9191  |  |     // Set username to applyResult["username"].  | 
9192  | 0  |     ADA_ASSERT_TRUE(apply_result->username.has_value());  | 
9193  | 0  |     username = std::move(apply_result->username.value());  | 
9194  |  |  | 
9195  |  |     // Set password to applyResult["password"].  | 
9196  | 0  |     ADA_ASSERT_TRUE(apply_result->password.has_value());  | 
9197  | 0  |     password = std::move(apply_result->password.value());  | 
9198  |  |  | 
9199  |  |     // Set hostname to applyResult["hostname"].  | 
9200  | 0  |     ADA_ASSERT_TRUE(apply_result->hostname.has_value());  | 
9201  | 0  |     hostname = std::move(apply_result->hostname.value());  | 
9202  |  |  | 
9203  |  |     // Set port to applyResult["port"].  | 
9204  | 0  |     ADA_ASSERT_TRUE(apply_result->port.has_value());  | 
9205  | 0  |     port = std::move(apply_result->port.value());  | 
9206  |  |  | 
9207  |  |     // Set pathname to applyResult["pathname"].  | 
9208  | 0  |     ADA_ASSERT_TRUE(apply_result->pathname.has_value());  | 
9209  | 0  |     pathname = std::move(apply_result->pathname.value());  | 
9210  |  |  | 
9211  |  |     // Set search to applyResult["search"].  | 
9212  | 0  |     ADA_ASSERT_TRUE(apply_result->search.has_value());  | 
9213  | 0  |     if (apply_result->search->starts_with("?")) { | 
9214  | 0  |       search = apply_result->search->substr(1);  | 
9215  | 0  |     } else { | 
9216  | 0  |       search = std::move(apply_result->search.value());  | 
9217  | 0  |     }  | 
9218  |  |  | 
9219  |  |     // Set hash to applyResult["hash"].  | 
9220  | 0  |     ADA_ASSERT_TRUE(apply_result->hash.has_value());  | 
9221  | 0  |     ADA_ASSERT_TRUE(!apply_result->hash->starts_with("#")); | 
9222  | 0  |     hash = std::move(apply_result->hash.value());  | 
9223  | 0  |   } else { | 
9224  | 0  |     ADA_ASSERT_TRUE(std::holds_alternative<std::string_view>(input));  | 
9225  |  |  | 
9226  |  |     // Let baseURL be null.  | 
9227  | 0  |     result<url_aggregator> base_url;  | 
9228  |  |  | 
9229  |  |     // If baseURLString was given, then:  | 
9230  | 0  |     if (base_url_string) { | 
9231  |  |       // Let baseURL be the result of parsing baseURLString.  | 
9232  | 0  |       base_url = ada::parse<url_aggregator>(*base_url_string, nullptr);  | 
9233  |  |  | 
9234  |  |       // If baseURL is failure, return null.  | 
9235  | 0  |       if (!base_url) { | 
9236  | 0  |         ada_log("match returned std::nullopt because failed to parse base_url=", | 
9237  | 0  |                 *base_url_string);  | 
9238  | 0  |         return std::nullopt;  | 
9239  | 0  |       }  | 
9240  |  |  | 
9241  |  |       // Append baseURLString to inputs.  | 
9242  | 0  |       inputs.emplace_back(*base_url_string);  | 
9243  | 0  |     }  | 
9244  |  |  | 
9245  | 0  |     url_aggregator* base_url_value =  | 
9246  | 0  |         base_url.has_value() ? &*base_url : nullptr;  | 
9247  |  |  | 
9248  |  |     // Set url to the result of parsing input given baseURL.  | 
9249  | 0  |     auto url = ada::parse<url_aggregator>(std::get<std::string_view>(input),  | 
9250  | 0  |                                           base_url_value);  | 
9251  |  |  | 
9252  |  |     // If url is failure, return null.  | 
9253  | 0  |     if (!url) { | 
9254  | 0  |       ada_log("match returned std::nullopt because url failed"); | 
9255  | 0  |       return std::nullopt;  | 
9256  | 0  |     }  | 
9257  |  |  | 
9258  |  |     // Set protocol to url's scheme.  | 
9259  |  |     // IMPORTANT: Not documented on the URLPattern spec, but protocol suffix ':'  | 
9260  |  |     // is removed. Similar work was done on workerd:  | 
9261  |  |     // https://github.com/cloudflare/workerd/blob/8620d14012513a6ce04d079e401d3becac3c67bd/src/workerd/jsg/url.c%2B%2B#L2038  | 
9262  | 0  |     protocol = url->get_protocol().substr(0, url->get_protocol().size() - 1);  | 
9263  |  |     // Set username to url's username.  | 
9264  | 0  |     username = url->get_username();  | 
9265  |  |     // Set password to url's password.  | 
9266  | 0  |     password = url->get_password();  | 
9267  |  |     // Set hostname to url's host, serialized, or the empty string if the value  | 
9268  |  |     // is null.  | 
9269  | 0  |     hostname = url->get_hostname();  | 
9270  |  |     // Set port to url's port, serialized, or the empty string if the value is  | 
9271  |  |     // null.  | 
9272  | 0  |     port = url->get_port();  | 
9273  |  |     // Set pathname to the result of URL path serializing url.  | 
9274  | 0  |     pathname = url->get_pathname();  | 
9275  |  |     // Set search to url's query or the empty string if the value is null.  | 
9276  |  |     // IMPORTANT: Not documented on the URLPattern spec, but search prefix '?'  | 
9277  |  |     // is removed. Similar work was done on workerd:  | 
9278  |  |     // https://github.com/cloudflare/workerd/blob/8620d14012513a6ce04d079e401d3becac3c67bd/src/workerd/jsg/url.c%2B%2B#L2232  | 
9279  | 0  |     if (url->has_search()) { | 
9280  | 0  |       auto view = url->get_search();  | 
9281  | 0  |       search = view.starts_with("?") ? url->get_search().substr(1) : view; | 
9282  | 0  |     }  | 
9283  |  |     // Set hash to url's fragment or the empty string if the value is null.  | 
9284  |  |     // IMPORTANT: Not documented on the URLPattern spec, but hash prefix '#' is  | 
9285  |  |     // removed. Similar work was done on workerd:  | 
9286  |  |     // https://github.com/cloudflare/workerd/blob/8620d14012513a6ce04d079e401d3becac3c67bd/src/workerd/jsg/url.c%2B%2B#L2242  | 
9287  | 0  |     if (url->has_hash()) { | 
9288  | 0  |       auto view = url->get_hash();  | 
9289  | 0  |       hash = view.starts_with("#") ? url->get_hash().substr(1) : view; | 
9290  | 0  |     }  | 
9291  | 0  |   }  | 
9292  |  |  | 
9293  |  |   // Let protocolExecResult be RegExpBuiltinExec(urlPattern's protocol  | 
9294  |  |   // component's regular expression, protocol).  | 
9295  | 0  |   auto protocol_exec_result =  | 
9296  | 0  |       regex_provider::regex_search(protocol, protocol_component.regexp);  | 
9297  |  | 
  | 
9298  | 0  |   if (!protocol_exec_result) { | 
9299  | 0  |     return std::nullopt;  | 
9300  | 0  |   }  | 
9301  |  |  | 
9302  |  |   // Let usernameExecResult be RegExpBuiltinExec(urlPattern's username  | 
9303  |  |   // component's regular expression, username).  | 
9304  | 0  |   auto username_exec_result =  | 
9305  | 0  |       regex_provider::regex_search(username, username_component.regexp);  | 
9306  |  | 
  | 
9307  | 0  |   if (!username_exec_result) { | 
9308  | 0  |     return std::nullopt;  | 
9309  | 0  |   }  | 
9310  |  |  | 
9311  |  |   // Let passwordExecResult be RegExpBuiltinExec(urlPattern's password  | 
9312  |  |   // component's regular expression, password).  | 
9313  | 0  |   auto password_exec_result =  | 
9314  | 0  |       regex_provider::regex_search(password, password_component.regexp);  | 
9315  |  | 
  | 
9316  | 0  |   if (!password_exec_result) { | 
9317  | 0  |     return std::nullopt;  | 
9318  | 0  |   }  | 
9319  |  |  | 
9320  |  |   // Let hostnameExecResult be RegExpBuiltinExec(urlPattern's hostname  | 
9321  |  |   // component's regular expression, hostname).  | 
9322  | 0  |   auto hostname_exec_result =  | 
9323  | 0  |       regex_provider::regex_search(hostname, hostname_component.regexp);  | 
9324  |  | 
  | 
9325  | 0  |   if (!hostname_exec_result) { | 
9326  | 0  |     return std::nullopt;  | 
9327  | 0  |   }  | 
9328  |  |  | 
9329  |  |   // Let portExecResult be RegExpBuiltinExec(urlPattern's port component's  | 
9330  |  |   // regular expression, port).  | 
9331  | 0  |   auto port_exec_result =  | 
9332  | 0  |       regex_provider::regex_search(port, port_component.regexp);  | 
9333  |  | 
  | 
9334  | 0  |   if (!port_exec_result) { | 
9335  | 0  |     return std::nullopt;  | 
9336  | 0  |   }  | 
9337  |  |  | 
9338  |  |   // Let pathnameExecResult be RegExpBuiltinExec(urlPattern's pathname  | 
9339  |  |   // component's regular expression, pathname).  | 
9340  | 0  |   auto pathname_exec_result =  | 
9341  | 0  |       regex_provider::regex_search(pathname, pathname_component.regexp);  | 
9342  |  | 
  | 
9343  | 0  |   if (!pathname_exec_result) { | 
9344  | 0  |     return std::nullopt;  | 
9345  | 0  |   }  | 
9346  |  |  | 
9347  |  |   // Let searchExecResult be RegExpBuiltinExec(urlPattern's search component's  | 
9348  |  |   // regular expression, search).  | 
9349  | 0  |   auto search_exec_result =  | 
9350  | 0  |       regex_provider::regex_search(search, search_component.regexp);  | 
9351  |  | 
  | 
9352  | 0  |   if (!search_exec_result) { | 
9353  | 0  |     return std::nullopt;  | 
9354  | 0  |   }  | 
9355  |  |  | 
9356  |  |   // Let hashExecResult be RegExpBuiltinExec(urlPattern's hash component's  | 
9357  |  |   // regular expression, hash).  | 
9358  | 0  |   auto hash_exec_result =  | 
9359  | 0  |       regex_provider::regex_search(hash, hash_component.regexp);  | 
9360  |  | 
  | 
9361  | 0  |   if (!hash_exec_result) { | 
9362  | 0  |     return std::nullopt;  | 
9363  | 0  |   }  | 
9364  |  |  | 
9365  |  |   // Let result be a new URLPatternResult.  | 
9366  | 0  |   auto result = url_pattern_result{}; | 
9367  |  |   // Set result["inputs"] to inputs.  | 
9368  | 0  |   result.inputs = std::move(inputs);  | 
9369  |  |   // Set result["protocol"] to the result of creating a component match result  | 
9370  |  |   // given urlPattern's protocol component, protocol, and protocolExecResult.  | 
9371  | 0  |   result.protocol = protocol_component.create_component_match_result(  | 
9372  | 0  |       std::move(protocol), std::move(*protocol_exec_result));  | 
9373  |  |  | 
9374  |  |   // Set result["username"] to the result of creating a component match result  | 
9375  |  |   // given urlPattern's username component, username, and usernameExecResult.  | 
9376  | 0  |   result.username = username_component.create_component_match_result(  | 
9377  | 0  |       std::move(username), std::move(*username_exec_result));  | 
9378  |  |  | 
9379  |  |   // Set result["password"] to the result of creating a component match result  | 
9380  |  |   // given urlPattern's password component, password, and passwordExecResult.  | 
9381  | 0  |   result.password = password_component.create_component_match_result(  | 
9382  | 0  |       std::move(password), std::move(*password_exec_result));  | 
9383  |  |  | 
9384  |  |   // Set result["hostname"] to the result of creating a component match result  | 
9385  |  |   // given urlPattern's hostname component, hostname, and hostnameExecResult.  | 
9386  | 0  |   result.hostname = hostname_component.create_component_match_result(  | 
9387  | 0  |       std::move(hostname), std::move(*hostname_exec_result));  | 
9388  |  |  | 
9389  |  |   // Set result["port"] to the result of creating a component match result given  | 
9390  |  |   // urlPattern's port component, port, and portExecResult.  | 
9391  | 0  |   result.port = port_component.create_component_match_result(  | 
9392  | 0  |       std::move(port), std::move(*port_exec_result));  | 
9393  |  |  | 
9394  |  |   // Set result["pathname"] to the result of creating a component match result  | 
9395  |  |   // given urlPattern's pathname component, pathname, and pathnameExecResult.  | 
9396  | 0  |   result.pathname = pathname_component.create_component_match_result(  | 
9397  | 0  |       std::move(pathname), std::move(*pathname_exec_result));  | 
9398  |  |  | 
9399  |  |   // Set result["search"] to the result of creating a component match result  | 
9400  |  |   // given urlPattern's search component, search, and searchExecResult.  | 
9401  | 0  |   result.search = search_component.create_component_match_result(  | 
9402  | 0  |       std::move(search), std::move(*search_exec_result));  | 
9403  |  |  | 
9404  |  |   // Set result["hash"] to the result of creating a component match result given  | 
9405  |  |   // urlPattern's hash component, hash, and hashExecResult.  | 
9406  | 0  |   result.hash = hash_component.create_component_match_result(  | 
9407  | 0  |       std::move(hash), std::move(*hash_exec_result));  | 
9408  |  | 
  | 
9409  | 0  |   return result;  | 
9410  | 0  | }  | 
9411  |  |  | 
9412  |  | }  // namespace ada  | 
9413  |  | #endif  // ADA_INCLUDE_URL_PATTERN  | 
9414  |  | #endif  | 
9415  |  | /* end file include/ada/url_pattern-inl.h */  | 
9416  |  | /* begin file include/ada/url_pattern_helpers-inl.h */  | 
9417  |  | /**  | 
9418  |  |  * @file url_pattern_helpers-inl.h  | 
9419  |  |  * @brief Declaration for the URLPattern helpers.  | 
9420  |  |  */  | 
9421  |  | #ifndef ADA_URL_PATTERN_HELPERS_INL_H  | 
9422  |  | #define ADA_URL_PATTERN_HELPERS_INL_H  | 
9423  |  |  | 
9424  |  | #include <optional>  | 
9425  |  | #include <string_view>  | 
9426  |  |  | 
9427  |  |  | 
9428  |  | #if ADA_INCLUDE_URL_PATTERN  | 
9429  |  | namespace ada::url_pattern_helpers { | 
9430  |  | #if defined(ADA_TESTING) || defined(ADA_LOGGING)  | 
9431  | 0  | inline std::string to_string(token_type type) { | 
9432  | 0  |   switch (type) { | 
9433  | 0  |     case token_type::INVALID_CHAR:  | 
9434  | 0  |       return "INVALID_CHAR";  | 
9435  | 0  |     case token_type::OPEN:  | 
9436  | 0  |       return "OPEN";  | 
9437  | 0  |     case token_type::CLOSE:  | 
9438  | 0  |       return "CLOSE";  | 
9439  | 0  |     case token_type::REGEXP:  | 
9440  | 0  |       return "REGEXP";  | 
9441  | 0  |     case token_type::NAME:  | 
9442  | 0  |       return "NAME";  | 
9443  | 0  |     case token_type::CHAR:  | 
9444  | 0  |       return "CHAR";  | 
9445  | 0  |     case token_type::ESCAPED_CHAR:  | 
9446  | 0  |       return "ESCAPED_CHAR";  | 
9447  | 0  |     case token_type::OTHER_MODIFIER:  | 
9448  | 0  |       return "OTHER_MODIFIER";  | 
9449  | 0  |     case token_type::ASTERISK:  | 
9450  | 0  |       return "ASTERISK";  | 
9451  | 0  |     case token_type::END:  | 
9452  | 0  |       return "END";  | 
9453  | 0  |     default:  | 
9454  | 0  |       ada::unreachable();  | 
9455  | 0  |   }  | 
9456  | 0  | }  | 
9457  |  | #endif  // defined(ADA_TESTING) || defined(ADA_LOGGING)  | 
9458  |  |  | 
9459  |  | template <url_pattern_regex::regex_concept regex_provider>  | 
9460  | 0  | constexpr void constructor_string_parser<regex_provider>::rewind() { | 
9461  |  |   // Set parser's token index to parser's component start.  | 
9462  | 0  |   token_index = component_start;  | 
9463  |  |   // Set parser's token increment to 0.  | 
9464  | 0  |   token_increment = 0;  | 
9465  | 0  | }  | 
9466  |  |  | 
9467  |  | template <url_pattern_regex::regex_concept regex_provider>  | 
9468  | 0  | constexpr bool constructor_string_parser<regex_provider>::is_hash_prefix() { | 
9469  |  |   // Return the result of running is a non-special pattern char given parser,  | 
9470  |  |   // parser's token index and "#".  | 
9471  | 0  |   return is_non_special_pattern_char(token_index, '#');  | 
9472  | 0  | }  | 
9473  |  |  | 
9474  |  | template <url_pattern_regex::regex_concept regex_provider>  | 
9475  | 0  | constexpr bool constructor_string_parser<regex_provider>::is_search_prefix() { | 
9476  |  |   // If result of running is a non-special pattern char given parser, parser's  | 
9477  |  |   // token index and "?" is true, then return true.  | 
9478  | 0  |   if (is_non_special_pattern_char(token_index, '?')) { | 
9479  | 0  |     return true;  | 
9480  | 0  |   }  | 
9481  |  |  | 
9482  |  |   // If parser's token list[parser's token index]'s value is not "?", then  | 
9483  |  |   // return false.  | 
9484  | 0  |   if (token_list[token_index].value != "?") { | 
9485  | 0  |     return false;  | 
9486  | 0  |   }  | 
9487  |  |  | 
9488  |  |   // If previous index is less than 0, then return true.  | 
9489  | 0  |   if (token_index == 0) return true;  | 
9490  |  |   // Let previous index be parser's token index - 1.  | 
9491  | 0  |   auto previous_index = token_index - 1;  | 
9492  |  |   // Let previous token be the result of running get a safe token given parser  | 
9493  |  |   // and previous index.  | 
9494  | 0  |   auto previous_token = get_safe_token(previous_index);  | 
9495  | 0  |   ADA_ASSERT_TRUE(previous_token);  | 
9496  |  |   // If any of the following are true, then return false:  | 
9497  |  |   // - previous token's type is "name".  | 
9498  |  |   // - previous token's type is "regexp".  | 
9499  |  |   // - previous token's type is "close".  | 
9500  |  |   // - previous token's type is "asterisk".  | 
9501  | 0  |   return !(previous_token->type == token_type::NAME ||  | 
9502  | 0  |            previous_token->type == token_type::REGEXP ||  | 
9503  | 0  |            previous_token->type == token_type::CLOSE ||  | 
9504  | 0  |            previous_token->type == token_type::ASTERISK);  | 
9505  | 0  | }  | 
9506  |  |  | 
9507  |  | template <url_pattern_regex::regex_concept regex_provider>  | 
9508  |  | constexpr bool  | 
9509  |  | constructor_string_parser<regex_provider>::is_non_special_pattern_char(  | 
9510  | 0  |     size_t index, uint32_t value) const { | 
9511  |  |   // Let token be the result of running get a safe token given parser and index.  | 
9512  | 0  |   auto token = get_safe_token(index);  | 
9513  | 0  |   ADA_ASSERT_TRUE(token);  | 
9514  |  |  | 
9515  |  |   // If token's value is not value, then return false.  | 
9516  |  |   // TODO: Remove this once we make sure get_safe_token returns a non-empty  | 
9517  |  |   // string.  | 
9518  | 0  |   if (!token->value.empty() &&  | 
9519  | 0  |       static_cast<uint32_t>(token->value[0]) != value) { | 
9520  | 0  |     return false;  | 
9521  | 0  |   }  | 
9522  |  |  | 
9523  |  |   // If any of the following are true:  | 
9524  |  |   // - token's type is "char";  | 
9525  |  |   // - token's type is "escaped-char"; or  | 
9526  |  |   // - token's type is "invalid-char",  | 
9527  |  |   // - then return true.  | 
9528  | 0  |   return token->type == token_type::CHAR ||  | 
9529  | 0  |          token->type == token_type::ESCAPED_CHAR ||  | 
9530  | 0  |          token->type == token_type::INVALID_CHAR;  | 
9531  | 0  | }  | 
9532  |  |  | 
9533  |  | template <url_pattern_regex::regex_concept regex_provider>  | 
9534  |  | constexpr const token*  | 
9535  | 0  | constructor_string_parser<regex_provider>::get_safe_token(size_t index) const { | 
9536  |  |   // If index is less than parser's token list's size, then return parser's  | 
9537  |  |   // token list[index].  | 
9538  | 0  |   if (index < token_list.size()) [[likely]] { | 
9539  | 0  |     return &token_list[index];  | 
9540  | 0  |   }  | 
9541  |  |  | 
9542  |  |   // Assert: parser's token list's size is greater than or equal to 1.  | 
9543  | 0  |   ADA_ASSERT_TRUE(!token_list.empty());  | 
9544  |  |  | 
9545  |  |   // Let token be parser's token list[last index].  | 
9546  |  |   // Assert: token's type is "end".  | 
9547  | 0  |   ADA_ASSERT_TRUE(token_list.back().type == token_type::END);  | 
9548  |  |  | 
9549  |  |   // Return token.  | 
9550  | 0  |   return &token_list.back();  | 
9551  | 0  | }  | 
9552  |  |  | 
9553  |  | template <url_pattern_regex::regex_concept regex_provider>  | 
9554  |  | constexpr bool constructor_string_parser<regex_provider>::is_group_open()  | 
9555  | 0  |     const { | 
9556  |  |   // If parser's token list[parser's token index]'s type is "open", then return  | 
9557  |  |   // true.  | 
9558  | 0  |   return token_list[token_index].type == token_type::OPEN;  | 
9559  | 0  | }  | 
9560  |  |  | 
9561  |  | template <url_pattern_regex::regex_concept regex_provider>  | 
9562  |  | constexpr bool constructor_string_parser<regex_provider>::is_group_close()  | 
9563  | 0  |     const { | 
9564  |  |   // If parser's token list[parser's token index]'s type is "close", then return  | 
9565  |  |   // true.  | 
9566  | 0  |   return token_list[token_index].type == token_type::CLOSE;  | 
9567  | 0  | }  | 
9568  |  |  | 
9569  |  | template <url_pattern_regex::regex_concept regex_provider>  | 
9570  |  | constexpr bool  | 
9571  | 0  | constructor_string_parser<regex_provider>::next_is_authority_slashes() const { | 
9572  |  |   // If the result of running is a non-special pattern char given parser,  | 
9573  |  |   // parser's token index + 1, and "/" is false, then return false.  | 
9574  | 0  |   if (!is_non_special_pattern_char(token_index + 1, '/')) { | 
9575  | 0  |     return false;  | 
9576  | 0  |   }  | 
9577  |  |   // If the result of running is a non-special pattern char given parser,  | 
9578  |  |   // parser's token index + 2, and "/" is false, then return false.  | 
9579  | 0  |   if (!is_non_special_pattern_char(token_index + 2, '/')) { | 
9580  | 0  |     return false;  | 
9581  | 0  |   }  | 
9582  | 0  |   return true;  | 
9583  | 0  | }  | 
9584  |  |  | 
9585  |  | template <url_pattern_regex::regex_concept regex_provider>  | 
9586  |  | constexpr bool constructor_string_parser<regex_provider>::is_protocol_suffix()  | 
9587  | 0  |     const { | 
9588  |  |   // Return the result of running is a non-special pattern char given parser,  | 
9589  |  |   // parser's token index, and ":".  | 
9590  | 0  |   return is_non_special_pattern_char(token_index, ':');  | 
9591  | 0  | }  | 
9592  |  |  | 
9593  |  | template <url_pattern_regex::regex_concept regex_provider>  | 
9594  |  | void constructor_string_parser<regex_provider>::change_state(State new_state,  | 
9595  | 0  |                                                              size_t skip) { | 
9596  |  |   // If parser's state is not "init", not "authority", and not "done", then set  | 
9597  |  |   // parser's result[parser's state] to the result of running make a component  | 
9598  |  |   // string given parser.  | 
9599  | 0  |   if (state != State::INIT && state != State::AUTHORITY &&  | 
9600  | 0  |       state != State::DONE) { | 
9601  | 0  |     auto value = make_component_string();  | 
9602  |  |     // TODO: Simplify this.  | 
9603  | 0  |     switch (state) { | 
9604  | 0  |       case State::PROTOCOL: { | 
9605  | 0  |         result.protocol = value;  | 
9606  | 0  |         break;  | 
9607  | 0  |       }  | 
9608  | 0  |       case State::USERNAME: { | 
9609  | 0  |         result.username = value;  | 
9610  | 0  |         break;  | 
9611  | 0  |       }  | 
9612  | 0  |       case State::PASSWORD: { | 
9613  | 0  |         result.password = value;  | 
9614  | 0  |         break;  | 
9615  | 0  |       }  | 
9616  | 0  |       case State::HOSTNAME: { | 
9617  | 0  |         result.hostname = value;  | 
9618  | 0  |         break;  | 
9619  | 0  |       }  | 
9620  | 0  |       case State::PORT: { | 
9621  | 0  |         result.port = value;  | 
9622  | 0  |         break;  | 
9623  | 0  |       }  | 
9624  | 0  |       case State::PATHNAME: { | 
9625  | 0  |         result.pathname = value;  | 
9626  | 0  |         break;  | 
9627  | 0  |       }  | 
9628  | 0  |       case State::SEARCH: { | 
9629  | 0  |         result.search = value;  | 
9630  | 0  |         break;  | 
9631  | 0  |       }  | 
9632  | 0  |       case State::HASH: { | 
9633  | 0  |         result.hash = value;  | 
9634  | 0  |         break;  | 
9635  | 0  |       }  | 
9636  | 0  |       default:  | 
9637  | 0  |         ada::unreachable();  | 
9638  | 0  |     }  | 
9639  | 0  |   }  | 
9640  |  |  | 
9641  |  |   // If parser's state is not "init" and new state is not "done", then:  | 
9642  | 0  |   if (state != State::INIT && new_state != State::DONE) { | 
9643  |  |     // If parser's state is "protocol", "authority", "username", or "password";  | 
9644  |  |     // new state is "port", "pathname", "search", or "hash"; and parser's  | 
9645  |  |     // result["hostname"] does not exist, then set parser's result["hostname"]  | 
9646  |  |     // to the empty string.  | 
9647  | 0  |     if ((state == State::PROTOCOL || state == State::AUTHORITY ||  | 
9648  | 0  |          state == State::USERNAME || state == State::PASSWORD) &&  | 
9649  | 0  |         (new_state == State::PORT || new_state == State::PATHNAME ||  | 
9650  | 0  |          new_state == State::SEARCH || new_state == State::HASH) &&  | 
9651  | 0  |         !result.hostname)  | 
9652  | 0  |       result.hostname = "";  | 
9653  | 0  |   }  | 
9654  |  |  | 
9655  |  |   // If parser's state is "protocol", "authority", "username", "password",  | 
9656  |  |   // "hostname", or "port"; new state is "search" or "hash"; and parser's  | 
9657  |  |   // result["pathname"] does not exist, then:  | 
9658  | 0  |   if ((state == State::PROTOCOL || state == State::AUTHORITY ||  | 
9659  | 0  |        state == State::USERNAME || state == State::PASSWORD ||  | 
9660  | 0  |        state == State::HOSTNAME || state == State::PORT) &&  | 
9661  | 0  |       (new_state == State::SEARCH || new_state == State::HASH) &&  | 
9662  | 0  |       !result.pathname) { | 
9663  | 0  |     if (protocol_matches_a_special_scheme_flag) { | 
9664  | 0  |       result.pathname = "/";  | 
9665  | 0  |     } else { | 
9666  |  |       // Otherwise, set parser's result["pathname"] to the empty string.  | 
9667  | 0  |       result.pathname = "";  | 
9668  | 0  |     }  | 
9669  | 0  |   }  | 
9670  |  |  | 
9671  |  |   // If parser's state is "protocol", "authority", "username", "password",  | 
9672  |  |   // "hostname", "port", or "pathname"; new state is "hash"; and parser's  | 
9673  |  |   // result["search"] does not exist, then set parser's result["search"] to  | 
9674  |  |   // the empty string.  | 
9675  | 0  |   if ((state == State::PROTOCOL || state == State::AUTHORITY ||  | 
9676  | 0  |        state == State::USERNAME || state == State::PASSWORD ||  | 
9677  | 0  |        state == State::HOSTNAME || state == State::PORT ||  | 
9678  | 0  |        state == State::PATHNAME) &&  | 
9679  | 0  |       new_state == State::HASH && !result.search) { | 
9680  | 0  |     result.search = "";  | 
9681  | 0  |   }  | 
9682  |  |  | 
9683  |  |   // Set parser's state to new state.  | 
9684  | 0  |   state = new_state;  | 
9685  |  |   // Increment parser's token index by skip.  | 
9686  | 0  |   token_index += skip;  | 
9687  |  |   // Set parser's component start to parser's token index.  | 
9688  | 0  |   component_start = token_index;  | 
9689  |  |   // Set parser's token increment to 0.  | 
9690  | 0  |   token_increment = 0;  | 
9691  | 0  | }  | 
9692  |  |  | 
9693  |  | template <url_pattern_regex::regex_concept regex_provider>  | 
9694  | 0  | std::string constructor_string_parser<regex_provider>::make_component_string() { | 
9695  |  |   // Assert: parser's token index is less than parser's token list's size.  | 
9696  | 0  |   ADA_ASSERT_TRUE(token_index < token_list.size());  | 
9697  |  |  | 
9698  |  |   // Let token be parser's token list[parser's token index].  | 
9699  |  |   // Let end index be token's index.  | 
9700  | 0  |   const auto end_index = token_list[token_index].index;  | 
9701  |  |   // Let component start token be the result of running get a safe token given  | 
9702  |  |   // parser and parser's component start.  | 
9703  | 0  |   const auto component_start_token = get_safe_token(component_start);  | 
9704  | 0  |   ADA_ASSERT_TRUE(component_start_token);  | 
9705  |  |   // Let component start input index be component start token's index.  | 
9706  | 0  |   const auto component_start_input_index = component_start_token->index;  | 
9707  |  |   // Return the code point substring from component start input index to end  | 
9708  |  |   // index within parser's input.  | 
9709  | 0  |   return input.substr(component_start_input_index,  | 
9710  | 0  |                       end_index - component_start_input_index);  | 
9711  | 0  | }  | 
9712  |  |  | 
9713  |  | template <url_pattern_regex::regex_concept regex_provider>  | 
9714  |  | constexpr bool  | 
9715  | 0  | constructor_string_parser<regex_provider>::is_an_identity_terminator() const { | 
9716  |  |   // Return the result of running is a non-special pattern char given parser,  | 
9717  |  |   // parser's token index, and "@".  | 
9718  | 0  |   return is_non_special_pattern_char(token_index, '@');  | 
9719  | 0  | }  | 
9720  |  |  | 
9721  |  | template <url_pattern_regex::regex_concept regex_provider>  | 
9722  |  | constexpr bool constructor_string_parser<regex_provider>::is_pathname_start()  | 
9723  | 0  |     const { | 
9724  |  |   // Return the result of running is a non-special pattern char given parser,  | 
9725  |  |   // parser's token index, and "/".  | 
9726  | 0  |   return is_non_special_pattern_char(token_index, '/');  | 
9727  | 0  | }  | 
9728  |  |  | 
9729  |  | template <url_pattern_regex::regex_concept regex_provider>  | 
9730  |  | constexpr bool constructor_string_parser<regex_provider>::is_password_prefix()  | 
9731  | 0  |     const { | 
9732  |  |   // Return the result of running is a non-special pattern char given parser,  | 
9733  |  |   // parser's token index, and ":".  | 
9734  | 0  |   return is_non_special_pattern_char(token_index, ':');  | 
9735  | 0  | }  | 
9736  |  |  | 
9737  |  | template <url_pattern_regex::regex_concept regex_provider>  | 
9738  |  | constexpr bool constructor_string_parser<regex_provider>::is_an_ipv6_open()  | 
9739  | 0  |     const { | 
9740  |  |   // Return the result of running is a non-special pattern char given parser,  | 
9741  |  |   // parser's token index, and "[".  | 
9742  | 0  |   return is_non_special_pattern_char(token_index, '[');  | 
9743  | 0  | }  | 
9744  |  |  | 
9745  |  | template <url_pattern_regex::regex_concept regex_provider>  | 
9746  |  | constexpr bool constructor_string_parser<regex_provider>::is_an_ipv6_close()  | 
9747  | 0  |     const { | 
9748  |  |   // Return the result of running is a non-special pattern char given parser,  | 
9749  |  |   // parser's token index, and "]".  | 
9750  | 0  |   return is_non_special_pattern_char(token_index, ']');  | 
9751  | 0  | }  | 
9752  |  |  | 
9753  |  | template <url_pattern_regex::regex_concept regex_provider>  | 
9754  |  | constexpr bool constructor_string_parser<regex_provider>::is_port_prefix()  | 
9755  | 0  |     const { | 
9756  |  |   // Return the result of running is a non-special pattern char given parser,  | 
9757  |  |   // parser's token index, and ":".  | 
9758  | 0  |   return is_non_special_pattern_char(token_index, ':');  | 
9759  | 0  | }  | 
9760  |  |  | 
9761  | 0  | constexpr void Tokenizer::get_next_code_point() { | 
9762  | 0  |   ada_log("Tokenizer::get_next_code_point called with index=", next_index); | 
9763  | 0  |   ADA_ASSERT_TRUE(next_index < input.size());  | 
9764  | 0  |   // this assumes that we have a valid, non-truncated UTF-8 stream.  | 
9765  | 0  |   code_point = 0;  | 
9766  | 0  |   size_t number_bytes = 0;  | 
9767  | 0  |   unsigned char first_byte = input[next_index];  | 
9768  | 0  | 
  | 
9769  | 0  |   if ((first_byte & 0x80) == 0) { | 
9770  | 0  |     // 1-byte character (ASCII)  | 
9771  | 0  |     next_index++;  | 
9772  | 0  |     code_point = first_byte;  | 
9773  | 0  |     ada_log("Tokenizer::get_next_code_point returning ASCII code point=", | 
9774  | 0  |             uint32_t(code_point));  | 
9775  | 0  |     ada_log("Tokenizer::get_next_code_point next_index =", next_index, | 
9776  | 0  |             " input.size()=", input.size());  | 
9777  | 0  |     return;  | 
9778  | 0  |   }  | 
9779  | 0  |   ada_log("Tokenizer::get_next_code_point read first byte=", | 
9780  | 0  |           uint32_t(first_byte));  | 
9781  | 0  |   if ((first_byte & 0xE0) == 0xC0) { | 
9782  | 0  |     code_point = first_byte & 0x1F;  | 
9783  | 0  |     number_bytes = 2;  | 
9784  | 0  |     ada_log("Tokenizer::get_next_code_point two bytes"); | 
9785  | 0  |   } else if ((first_byte & 0xF0) == 0xE0) { | 
9786  | 0  |     code_point = first_byte & 0x0F;  | 
9787  | 0  |     number_bytes = 3;  | 
9788  | 0  |     ada_log("Tokenizer::get_next_code_point three bytes"); | 
9789  | 0  |   } else if ((first_byte & 0xF8) == 0xF0) { | 
9790  | 0  |     code_point = first_byte & 0x07;  | 
9791  | 0  |     number_bytes = 4;  | 
9792  | 0  |     ada_log("Tokenizer::get_next_code_point four bytes"); | 
9793  | 0  |   }  | 
9794  | 0  |   ADA_ASSERT_TRUE(number_bytes + next_index <= input.size());  | 
9795  | 0  | 
  | 
9796  | 0  |   for (size_t i = 1 + next_index; i < number_bytes + next_index; ++i) { | 
9797  | 0  |     unsigned char byte = input[i];  | 
9798  | 0  |     ada_log("Tokenizer::get_next_code_point read byte=", uint32_t(byte)); | 
9799  | 0  |     code_point = (code_point << 6) | (byte & 0x3F);  | 
9800  | 0  |   }  | 
9801  | 0  |   ada_log("Tokenizer::get_next_code_point returning non-ASCII code point=", | 
9802  | 0  |           uint32_t(code_point));  | 
9803  | 0  |   ada_log("Tokenizer::get_next_code_point next_index =", next_index, | 
9804  | 0  |           " input.size()=", input.size());  | 
9805  | 0  |   next_index += number_bytes;  | 
9806  | 0  | }  | 
9807  |  |  | 
9808  | 0  | constexpr void Tokenizer::seek_and_get_next_code_point(size_t new_index) { | 
9809  | 0  |   ada_log("Tokenizer::seek_and_get_next_code_point called with new_index=", | 
9810  | 0  |           new_index);  | 
9811  | 0  |   // Set tokenizer's next index to index.  | 
9812  | 0  |   next_index = new_index;  | 
9813  | 0  |   // Run get the next code point given tokenizer.  | 
9814  | 0  |   get_next_code_point();  | 
9815  | 0  | }  | 
9816  |  |  | 
9817  |  | inline void Tokenizer::add_token(token_type type, size_t next_position,  | 
9818  | 0  |                                  size_t value_position, size_t value_length) { | 
9819  | 0  |   ada_log("Tokenizer::add_token called with type=", to_string(type), | 
9820  | 0  |           " next_position=", next_position, " value_position=", value_position);  | 
9821  | 0  |   ADA_ASSERT_TRUE(next_position >= value_position);  | 
9822  | 0  | 
  | 
9823  | 0  |   // Let token be a new token.  | 
9824  | 0  |   // Set token's type to type.  | 
9825  | 0  |   // Set token's index to tokenizer's index.  | 
9826  | 0  |   // Set token's value to the code point substring from value position with  | 
9827  | 0  |   // length value length within tokenizer's input.  | 
9828  | 0  |   // Append token to the back of tokenizer's token list.  | 
9829  | 0  |   token_list.emplace_back(type, index,  | 
9830  | 0  |                           input.substr(value_position, value_length));  | 
9831  | 0  |   // Set tokenizer's index to next position.  | 
9832  | 0  |   index = next_position;  | 
9833  | 0  | }  | 
9834  |  |  | 
9835  |  | inline void Tokenizer::add_token_with_default_length(token_type type,  | 
9836  |  |                                                      size_t next_position,  | 
9837  | 0  |                                                      size_t value_position) { | 
9838  | 0  |   // Let computed length be next position - value position.  | 
9839  | 0  |   auto computed_length = next_position - value_position;  | 
9840  | 0  |   // Run add a token given tokenizer, type, next position, value position, and  | 
9841  | 0  |   // computed length.  | 
9842  | 0  |   add_token(type, next_position, value_position, computed_length);  | 
9843  | 0  | }  | 
9844  |  |  | 
9845  | 0  | inline void Tokenizer::add_token_with_defaults(token_type type) { | 
9846  | 0  |   ada_log("Tokenizer::add_token_with_defaults called with type=", | 
9847  | 0  |           to_string(type));  | 
9848  | 0  |   // Run add a token with default length given tokenizer, type, tokenizer's next  | 
9849  | 0  |   // index, and tokenizer's index.  | 
9850  | 0  |   add_token_with_default_length(type, next_index, index);  | 
9851  | 0  | }  | 
9852  |  |  | 
9853  |  | inline ada_warn_unused std::optional<errors>  | 
9854  |  | Tokenizer::process_tokenizing_error(size_t next_position,  | 
9855  | 0  |                                     size_t value_position) { | 
9856  | 0  |   // If tokenizer's policy is "strict", then throw a TypeError.  | 
9857  | 0  |   if (policy == token_policy::strict) { | 
9858  | 0  |     ada_log("process_tokenizing_error failed with next_position=", | 
9859  | 0  |             next_position, " value_position=", value_position);  | 
9860  | 0  |     return errors::type_error;  | 
9861  | 0  |   }  | 
9862  | 0  |   // Assert: tokenizer's policy is "lenient".  | 
9863  | 0  |   ADA_ASSERT_TRUE(policy == token_policy::lenient);  | 
9864  | 0  |   // Run add a token with default length given tokenizer, "invalid-char", next  | 
9865  | 0  |   // position, and value position.  | 
9866  | 0  |   add_token_with_default_length(token_type::INVALID_CHAR, next_position,  | 
9867  | 0  |                                 value_position);  | 
9868  | 0  |   return std::nullopt;  | 
9869  | 0  | }  | 
9870  |  |  | 
9871  |  | template <url_pattern_encoding_callback F>  | 
9872  | 0  | token* url_pattern_parser<F>::try_consume_modifier_token() { | 
9873  |  |   // Let token be the result of running try to consume a token given parser and  | 
9874  |  |   // "other-modifier".  | 
9875  | 0  |   auto token = try_consume_token(token_type::OTHER_MODIFIER);  | 
9876  |  |   // If token is not null, then return token.  | 
9877  | 0  |   if (token) return token;  | 
9878  |  |   // Set token to the result of running try to consume a token given parser and  | 
9879  |  |   // "asterisk".  | 
9880  |  |   // Return token.  | 
9881  | 0  |   return try_consume_token(token_type::ASTERISK);  | 
9882  | 0  | }  | 
9883  |  |  | 
9884  |  | template <url_pattern_encoding_callback F>  | 
9885  |  | token* url_pattern_parser<F>::try_consume_regexp_or_wildcard_token(  | 
9886  | 0  |     const token* name_token) { | 
9887  |  |   // Let token be the result of running try to consume a token given parser and  | 
9888  |  |   // "regexp".  | 
9889  | 0  |   auto token = try_consume_token(token_type::REGEXP);  | 
9890  |  |   // If name token is null and token is null, then set token to the result of  | 
9891  |  |   // running try to consume a token given parser and "asterisk".  | 
9892  | 0  |   if (!name_token && !token) { | 
9893  | 0  |     token = try_consume_token(token_type::ASTERISK);  | 
9894  | 0  |   }  | 
9895  |  |   // Return token.  | 
9896  | 0  |   return token;  | 
9897  | 0  | }  | 
9898  |  |  | 
9899  |  | template <url_pattern_encoding_callback F>  | 
9900  | 0  | token* url_pattern_parser<F>::try_consume_token(token_type type) { | 
9901  | 0  |   ada_log("url_pattern_parser::try_consume_token called with type=", | 
9902  | 0  |           to_string(type));  | 
9903  |  |   // Assert: parser's index is less than parser's token list size.  | 
9904  | 0  |   ADA_ASSERT_TRUE(index < tokens.size());  | 
9905  |  |   // Let next token be parser's token list[parser's index].  | 
9906  | 0  |   auto& next_token = tokens[index];  | 
9907  |  |   // If next token's type is not type return null.  | 
9908  | 0  |   if (next_token.type != type) return nullptr;  | 
9909  |  |   // Increase parser's index by 1.  | 
9910  | 0  |   index++;  | 
9911  |  |   // Return next token.  | 
9912  | 0  |   return &next_token;  | 
9913  | 0  | }  | 
9914  |  |  | 
9915  |  | template <url_pattern_encoding_callback F>  | 
9916  | 0  | std::string url_pattern_parser<F>::consume_text() { | 
9917  |  |   // Let result be the empty string.  | 
9918  | 0  |   std::string result{}; | 
9919  |  |   // While true:  | 
9920  | 0  |   while (true) { | 
9921  |  |     // Let token be the result of running try to consume a token given parser  | 
9922  |  |     // and "char".  | 
9923  | 0  |     auto token = try_consume_token(token_type::CHAR);  | 
9924  |  |     // If token is null, then set token to the result of running try to consume  | 
9925  |  |     // a token given parser and "escaped-char".  | 
9926  | 0  |     if (!token) token = try_consume_token(token_type::ESCAPED_CHAR);  | 
9927  |  |     // If token is null, then break.  | 
9928  | 0  |     if (!token) break;  | 
9929  |  |     // Append token's value to the end of result.  | 
9930  | 0  |     result.append(token->value);  | 
9931  | 0  |   }  | 
9932  |  |   // Return result.  | 
9933  | 0  |   return result;  | 
9934  | 0  | }  | 
9935  |  |  | 
9936  |  | template <url_pattern_encoding_callback F>  | 
9937  | 0  | bool url_pattern_parser<F>::consume_required_token(token_type type) { | 
9938  | 0  |   ada_log("url_pattern_parser::consume_required_token called with type=", | 
9939  | 0  |           to_string(type));  | 
9940  |  |   // Let result be the result of running try to consume a token given parser and  | 
9941  |  |   // type.  | 
9942  | 0  |   return try_consume_token(type) != nullptr;  | 
9943  | 0  | }  | 
9944  |  |  | 
9945  |  | template <url_pattern_encoding_callback F>  | 
9946  |  | std::optional<errors>  | 
9947  | 0  | url_pattern_parser<F>::maybe_add_part_from_the_pending_fixed_value() { | 
9948  |  |   // If parser's pending fixed value is the empty string, then return.  | 
9949  | 0  |   if (pending_fixed_value.empty()) { | 
9950  | 0  |     ada_log("pending_fixed_value is empty"); | 
9951  | 0  |     return std::nullopt;  | 
9952  | 0  |   }  | 
9953  |  |   // Let encoded value be the result of running parser's encoding callback given  | 
9954  |  |   // parser's pending fixed value.  | 
9955  | 0  |   auto encoded_value = encoding_callback(pending_fixed_value);  | 
9956  | 0  |   if (!encoded_value) { | 
9957  | 0  |     ada_log("failed to encode pending_fixed_value: ", pending_fixed_value); | 
9958  | 0  |     return encoded_value.error();  | 
9959  | 0  |   }  | 
9960  |  |   // Set parser's pending fixed value to the empty string.  | 
9961  | 0  |   pending_fixed_value.clear();  | 
9962  |  |   // Let part be a new part whose type is "fixed-text", value is encoded value,  | 
9963  |  |   // and modifier is "none".  | 
9964  |  |   // Append part to parser's part list.  | 
9965  | 0  |   parts.emplace_back(url_pattern_part_type::FIXED_TEXT,  | 
9966  | 0  |                      std::move(*encoded_value),  | 
9967  | 0  |                      url_pattern_part_modifier::none);  | 
9968  | 0  |   return std::nullopt;  | 
9969  | 0  | }  | 
9970  |  |  | 
9971  |  | template <url_pattern_encoding_callback F>  | 
9972  |  | std::optional<errors> url_pattern_parser<F>::add_part(  | 
9973  |  |     std::string_view prefix, token* name_token, token* regexp_or_wildcard_token,  | 
9974  | 0  |     std::string_view suffix, token* modifier_token) { | 
9975  |  |   // Let modifier be "none".  | 
9976  | 0  |   auto modifier = url_pattern_part_modifier::none;  | 
9977  |  |   // If modifier token is not null:  | 
9978  | 0  |   if (modifier_token) { | 
9979  |  |     // If modifier token's value is "?" then set modifier to "optional".  | 
9980  | 0  |     if (modifier_token->value == "?") { | 
9981  | 0  |       modifier = url_pattern_part_modifier::optional;  | 
9982  | 0  |     } else if (modifier_token->value == "*") { | 
9983  |  |       // Otherwise if modifier token's value is "*" then set modifier to  | 
9984  |  |       // "zero-or-more".  | 
9985  | 0  |       modifier = url_pattern_part_modifier::zero_or_more;  | 
9986  | 0  |     } else if (modifier_token->value == "+") { | 
9987  |  |       // Otherwise if modifier token's value is "+" then set modifier to  | 
9988  |  |       // "one-or-more".  | 
9989  | 0  |       modifier = url_pattern_part_modifier::one_or_more;  | 
9990  | 0  |     }  | 
9991  | 0  |   }  | 
9992  |  |   // If name token is null and regexp or wildcard token is null and modifier  | 
9993  |  |   // is "none":  | 
9994  | 0  |   if (!name_token && !regexp_or_wildcard_token &&  | 
9995  | 0  |       modifier == url_pattern_part_modifier::none) { | 
9996  |  |     // Append prefix to the end of parser's pending fixed value.  | 
9997  | 0  |     pending_fixed_value.append(prefix);  | 
9998  | 0  |     return std::nullopt;  | 
9999  | 0  |   }  | 
10000  |  |   // Run maybe add a part from the pending fixed value given parser.  | 
10001  | 0  |   if (auto error = maybe_add_part_from_the_pending_fixed_value()) { | 
10002  | 0  |     return *error;  | 
10003  | 0  |   }  | 
10004  |  |   // If name token is null and regexp or wildcard token is null:  | 
10005  | 0  |   if (!name_token && !regexp_or_wildcard_token) { | 
10006  |  |     // Assert: suffix is the empty string.  | 
10007  | 0  |     ADA_ASSERT_TRUE(suffix.empty());  | 
10008  |  |     // If prefix is the empty string, then return.  | 
10009  | 0  |     if (prefix.empty()) return std::nullopt;  | 
10010  |  |     // Let encoded value be the result of running parser's encoding callback  | 
10011  |  |     // given prefix.  | 
10012  | 0  |     auto encoded_value = encoding_callback(prefix);  | 
10013  | 0  |     if (!encoded_value) { | 
10014  | 0  |       return encoded_value.error();  | 
10015  | 0  |     }  | 
10016  |  |     // Let part be a new part whose type is "fixed-text", value is encoded  | 
10017  |  |     // value, and modifier is modifier.  | 
10018  |  |     // Append part to parser's part list.  | 
10019  | 0  |     parts.emplace_back(url_pattern_part_type::FIXED_TEXT,  | 
10020  | 0  |                        std::move(*encoded_value), modifier);  | 
10021  | 0  |     return std::nullopt;  | 
10022  | 0  |   }  | 
10023  |  |   // Let regexp value be the empty string.  | 
10024  | 0  |   std::string regexp_value{}; | 
10025  |  |   // If regexp or wildcard token is null, then set regexp value to parser's  | 
10026  |  |   // segment wildcard regexp.  | 
10027  | 0  |   if (!regexp_or_wildcard_token) { | 
10028  | 0  |     regexp_value = segment_wildcard_regexp;  | 
10029  | 0  |   } else if (regexp_or_wildcard_token->type == token_type::ASTERISK) { | 
10030  |  |     // Otherwise if regexp or wildcard token's type is "asterisk", then set  | 
10031  |  |     // regexp value to the full wildcard regexp value.  | 
10032  | 0  |     regexp_value = ".*";  | 
10033  | 0  |   } else { | 
10034  |  |     // Otherwise set regexp value to regexp or wildcard token's value.  | 
10035  | 0  |     regexp_value = regexp_or_wildcard_token->value;  | 
10036  | 0  |   }  | 
10037  |  |   // Let type be "regexp".  | 
10038  | 0  |   auto type = url_pattern_part_type::REGEXP;  | 
10039  |  |   // If regexp value is parser's segment wildcard regexp:  | 
10040  | 0  |   if (regexp_value == segment_wildcard_regexp) { | 
10041  |  |     // Set type to "segment-wildcard".  | 
10042  | 0  |     type = url_pattern_part_type::SEGMENT_WILDCARD;  | 
10043  |  |     // Set regexp value to the empty string.  | 
10044  | 0  |     regexp_value.clear();  | 
10045  | 0  |   } else if (regexp_value == ".*") { | 
10046  |  |     // Otherwise if regexp value is the full wildcard regexp value:  | 
10047  |  |     // Set type to "full-wildcard".  | 
10048  | 0  |     type = url_pattern_part_type::FULL_WILDCARD;  | 
10049  |  |     // Set regexp value to the empty string.  | 
10050  | 0  |     regexp_value.clear();  | 
10051  | 0  |   }  | 
10052  |  |   // Let name be the empty string.  | 
10053  | 0  |   std::string name{}; | 
10054  |  |   // If name token is not null, then set name to name token's value.  | 
10055  | 0  |   if (name_token) { | 
10056  | 0  |     name = name_token->value;  | 
10057  | 0  |   } else if (regexp_or_wildcard_token != nullptr) { | 
10058  |  |     // Otherwise if regexp or wildcard token is not null:  | 
10059  |  |     // Set name to parser's next numeric name, serialized.  | 
10060  | 0  |     name = std::to_string(next_numeric_name);  | 
10061  |  |     // Increment parser's next numeric name by 1.  | 
10062  | 0  |     next_numeric_name++;  | 
10063  | 0  |   }  | 
10064  |  |   // If the result of running is a duplicate name given parser and name is  | 
10065  |  |   // true, then throw a TypeError.  | 
10066  | 0  |   if (std::ranges::any_of(  | 
10067  | 0  |           parts, [&name](const auto& part) { return part.name == name; })) { | 
10068  | 0  |     return errors::type_error;  | 
10069  | 0  |   }  | 
10070  |  |   // Let encoded prefix be the result of running parser's encoding callback  | 
10071  |  |   // given prefix.  | 
10072  | 0  |   auto encoded_prefix = encoding_callback(prefix);  | 
10073  | 0  |   if (!encoded_prefix) return encoded_prefix.error();  | 
10074  |  |   // Let encoded suffix be the result of running parser's encoding callback  | 
10075  |  |   // given suffix.  | 
10076  | 0  |   auto encoded_suffix = encoding_callback(suffix);  | 
10077  | 0  |   if (!encoded_suffix) return encoded_suffix.error();  | 
10078  |  |   // Let part be a new part whose type is type, value is regexp value,  | 
10079  |  |   // modifier is modifier, name is name, prefix is encoded prefix, and suffix  | 
10080  |  |   // is encoded suffix.  | 
10081  |  |   // Append part to parser's part list.  | 
10082  | 0  |   parts.emplace_back(type, std::move(regexp_value), modifier, std::move(name),  | 
10083  | 0  |                      std::move(*encoded_prefix), std::move(*encoded_suffix));  | 
10084  | 0  |   return std::nullopt;  | 
10085  | 0  | }  | 
10086  |  |  | 
10087  |  | template <url_pattern_encoding_callback F>  | 
10088  |  | tl::expected<std::vector<url_pattern_part>, errors> parse_pattern_string(  | 
10089  |  |     std::string_view input, url_pattern_compile_component_options& options,  | 
10090  | 0  |     F& encoding_callback) { | 
10091  | 0  |   ada_log("parse_pattern_string input=", input); | 
10092  |  |   // Let parser be a new pattern parser whose encoding callback is encoding  | 
10093  |  |   // callback and segment wildcard regexp is the result of running generate a  | 
10094  |  |   // segment wildcard regexp given options.  | 
10095  | 0  |   auto parser = url_pattern_parser<F>(  | 
10096  | 0  |       encoding_callback, generate_segment_wildcard_regexp(options));  | 
10097  |  |   // Set parser's token list to the result of running tokenize given input and  | 
10098  |  |   // "strict".  | 
10099  | 0  |   auto tokenize_result = tokenize(input, token_policy::strict);  | 
10100  | 0  |   if (!tokenize_result) { | 
10101  | 0  |     ada_log("parse_pattern_string tokenize failed"); | 
10102  | 0  |     return tl::unexpected(tokenize_result.error());  | 
10103  | 0  |   }  | 
10104  | 0  |   parser.tokens = std::move(*tokenize_result);  | 
10105  |  |  | 
10106  |  |   // While parser's index is less than parser's token list's size:  | 
10107  | 0  |   while (parser.can_continue()) { | 
10108  |  |     // Let char token be the result of running try to consume a token given  | 
10109  |  |     // parser and "char".  | 
10110  | 0  |     auto char_token = parser.try_consume_token(token_type::CHAR);  | 
10111  |  |     // Let name token be the result of running try to consume a token given  | 
10112  |  |     // parser and "name".  | 
10113  | 0  |     auto name_token = parser.try_consume_token(token_type::NAME);  | 
10114  |  |     // Let regexp or wildcard token be the result of running try to consume a  | 
10115  |  |     // regexp or wildcard token given parser and name token.  | 
10116  | 0  |     auto regexp_or_wildcard_token =  | 
10117  | 0  |         parser.try_consume_regexp_or_wildcard_token(name_token);  | 
10118  |  |     // If name token is not null or regexp or wildcard token is not null:  | 
10119  | 0  |     if (name_token || regexp_or_wildcard_token) { | 
10120  |  |       // Let prefix be the empty string.  | 
10121  | 0  |       std::string prefix{}; | 
10122  |  |       // If char token is not null then set prefix to char token's value.  | 
10123  | 0  |       if (char_token) prefix = char_token->value;  | 
10124  |  |       // If prefix is not the empty string and not options's prefix code point:  | 
10125  | 0  |       if (!prefix.empty() && prefix != options.get_prefix()) { | 
10126  |  |         // Append prefix to the end of parser's pending fixed value.  | 
10127  | 0  |         parser.pending_fixed_value.append(prefix);  | 
10128  |  |         // Set prefix to the empty string.  | 
10129  | 0  |         prefix.clear();  | 
10130  | 0  |       }  | 
10131  |  |       // Run maybe add a part from the pending fixed value given parser.  | 
10132  | 0  |       if (auto error = parser.maybe_add_part_from_the_pending_fixed_value()) { | 
10133  | 0  |         ada_log("maybe_add_part_from_the_pending_fixed_value failed"); | 
10134  | 0  |         return tl::unexpected(*error);  | 
10135  | 0  |       }  | 
10136  |  |       // Let modifier token be the result of running try to consume a modifier  | 
10137  |  |       // token given parser.  | 
10138  | 0  |       auto modifier_token = parser.try_consume_modifier_token();  | 
10139  |  |       // Run add a part given parser, prefix, name token, regexp or wildcard  | 
10140  |  |       // token, the empty string, and modifier token.  | 
10141  | 0  |       if (auto error =  | 
10142  | 0  |               parser.add_part(prefix, name_token, regexp_or_wildcard_token, "",  | 
10143  | 0  |                               modifier_token)) { | 
10144  | 0  |         ada_log("parser.add_part failed"); | 
10145  | 0  |         return tl::unexpected(*error);  | 
10146  | 0  |       }  | 
10147  |  |       // Continue.  | 
10148  | 0  |       continue;  | 
10149  | 0  |     }  | 
10150  |  |  | 
10151  |  |     // Let fixed token be char token.  | 
10152  | 0  |     auto fixed_token = char_token;  | 
10153  |  |     // If fixed token is null, then set fixed token to the result of running try  | 
10154  |  |     // to consume a token given parser and "escaped-char".  | 
10155  | 0  |     if (!fixed_token)  | 
10156  | 0  |       fixed_token = parser.try_consume_token(token_type::ESCAPED_CHAR);  | 
10157  |  |     // If fixed token is not null:  | 
10158  | 0  |     if (fixed_token) { | 
10159  |  |       // Append fixed token's value to parser's pending fixed value.  | 
10160  | 0  |       parser.pending_fixed_value.append(fixed_token->value);  | 
10161  |  |       // Continue.  | 
10162  | 0  |       continue;  | 
10163  | 0  |     }  | 
10164  |  |     // Let open token be the result of running try to consume a token given  | 
10165  |  |     // parser and "open".  | 
10166  | 0  |     auto open_token = parser.try_consume_token(token_type::OPEN);  | 
10167  |  |     // If open token is not null:  | 
10168  | 0  |     if (open_token) { | 
10169  |  |       // Set prefix be the result of running consume text given parser.  | 
10170  | 0  |       auto prefix_ = parser.consume_text();  | 
10171  |  |       // Set name token to the result of running try to consume a token given  | 
10172  |  |       // parser and "name".  | 
10173  | 0  |       name_token = parser.try_consume_token(token_type::NAME);  | 
10174  |  |       // Set regexp or wildcard token to the result of running try to consume a  | 
10175  |  |       // regexp or wildcard token given parser and name token.  | 
10176  | 0  |       regexp_or_wildcard_token =  | 
10177  | 0  |           parser.try_consume_regexp_or_wildcard_token(name_token);  | 
10178  |  |       // Let suffix be the result of running consume text given parser.  | 
10179  | 0  |       auto suffix_ = parser.consume_text();  | 
10180  |  |       // Run consume a required token given parser and "close".  | 
10181  | 0  |       if (!parser.consume_required_token(token_type::CLOSE)) { | 
10182  | 0  |         ada_log("parser.consume_required_token failed"); | 
10183  | 0  |         return tl::unexpected(errors::type_error);  | 
10184  | 0  |       }  | 
10185  |  |       // Set modifier token to the result of running try to consume a modifier  | 
10186  |  |       // token given parser.  | 
10187  | 0  |       auto modifier_token = parser.try_consume_modifier_token();  | 
10188  |  |       // Run add a part given parser, prefix, name token, regexp or wildcard  | 
10189  |  |       // token, suffix, and modifier token.  | 
10190  | 0  |       if (auto error =  | 
10191  | 0  |               parser.add_part(prefix_, name_token, regexp_or_wildcard_token,  | 
10192  | 0  |                               suffix_, modifier_token)) { | 
10193  | 0  |         return tl::unexpected(*error);  | 
10194  | 0  |       }  | 
10195  |  |       // Continue.  | 
10196  | 0  |       continue;  | 
10197  | 0  |     }  | 
10198  |  |     // Run maybe add a part from the pending fixed value given parser.  | 
10199  | 0  |     if (auto error = parser.maybe_add_part_from_the_pending_fixed_value()) { | 
10200  | 0  |       ada_log("maybe_add_part_from_the_pending_fixed_value failed on line 992"); | 
10201  | 0  |       return tl::unexpected(*error);  | 
10202  | 0  |     }  | 
10203  |  |     // Run consume a required token given parser and "end".  | 
10204  | 0  |     if (!parser.consume_required_token(token_type::END)) { | 
10205  | 0  |       return tl::unexpected(errors::type_error);  | 
10206  | 0  |     }  | 
10207  | 0  |   }  | 
10208  | 0  |   ada_log("parser.parts size is: ", parser.parts.size()); | 
10209  |  |   // Return parser's part list.  | 
10210  | 0  |   return parser.parts;  | 
10211  | 0  | }  | 
10212  |  |  | 
10213  |  | template <url_pattern_regex::regex_concept regex_provider>  | 
10214  |  | bool protocol_component_matches_special_scheme(  | 
10215  | 0  |     url_pattern_component<regex_provider>& component) { | 
10216  |  |   // let's avoid unnecessary copy here.  | 
10217  | 0  |   auto& regex = component.regexp;  | 
10218  | 0  |   return regex_provider::regex_match("http", regex) || | 
10219  | 0  |          regex_provider::regex_match("https", regex) || | 
10220  | 0  |          regex_provider::regex_match("ws", regex) || | 
10221  | 0  |          regex_provider::regex_match("wss", regex) || | 
10222  | 0  |          regex_provider::regex_match("ftp", regex); | 
10223  | 0  | }  | 
10224  |  |  | 
10225  |  | template <url_pattern_regex::regex_concept regex_provider>  | 
10226  |  | inline std::optional<errors> constructor_string_parser<  | 
10227  | 0  |     regex_provider>::compute_protocol_matches_special_scheme_flag() { | 
10228  | 0  |   ada_log(  | 
10229  | 0  |       "constructor_string_parser::compute_protocol_matches_special_scheme_"  | 
10230  | 0  |       "flag");  | 
10231  |  |   // Let protocol string be the result of running make a component string given  | 
10232  |  |   // parser.  | 
10233  | 0  |   auto protocol_string = make_component_string();  | 
10234  |  |   // Let protocol component be the result of compiling a component given  | 
10235  |  |   // protocol string, canonicalize a protocol, and default options.  | 
10236  | 0  |   auto protocol_component = url_pattern_component<regex_provider>::compile(  | 
10237  | 0  |       protocol_string, canonicalize_protocol,  | 
10238  | 0  |       url_pattern_compile_component_options::DEFAULT);  | 
10239  | 0  |   if (!protocol_component) { | 
10240  | 0  |     ada_log("url_pattern_component::compile failed for protocol_string ", | 
10241  | 0  |             protocol_string);  | 
10242  | 0  |     return protocol_component.error();  | 
10243  | 0  |   }  | 
10244  |  |   // If the result of running protocol component matches a special scheme given  | 
10245  |  |   // protocol component is true, then set parser's protocol matches a special  | 
10246  |  |   // scheme flag to true.  | 
10247  | 0  |   if (protocol_component_matches_special_scheme(*protocol_component)) { | 
10248  | 0  |     protocol_matches_a_special_scheme_flag = true;  | 
10249  | 0  |   }  | 
10250  | 0  |   return std::nullopt;  | 
10251  | 0  | }  | 
10252  |  |  | 
10253  |  | template <url_pattern_regex::regex_concept regex_provider>  | 
10254  |  | tl::expected<url_pattern_init, errors>  | 
10255  | 0  | constructor_string_parser<regex_provider>::parse(std::string_view input) { | 
10256  | 0  |   ada_log("constructor_string_parser::parse input=", input); | 
10257  |  |   // Let parser be a new constructor string parser whose input is input and  | 
10258  |  |   // token list is the result of running tokenize given input and "lenient".  | 
10259  | 0  |   auto token_list = tokenize(input, token_policy::lenient);  | 
10260  | 0  |   if (!token_list) { | 
10261  | 0  |     return tl::unexpected(token_list.error());  | 
10262  | 0  |   }  | 
10263  | 0  |   auto parser = constructor_string_parser(input, std::move(*token_list));  | 
10264  |  |  | 
10265  |  |   // While parser's token index is less than parser's token list size:  | 
10266  | 0  |   while (parser.token_index < parser.token_list.size()) { | 
10267  |  |     // Set parser's token increment to 1.  | 
10268  | 0  |     parser.token_increment = 1;  | 
10269  |  |  | 
10270  |  |     // If parser's token list[parser's token index]'s type is "end" then:  | 
10271  | 0  |     if (parser.token_list[parser.token_index].type == token_type::END) { | 
10272  |  |       // If parser's state is "init":  | 
10273  | 0  |       if (parser.state == State::INIT) { | 
10274  |  |         // Run rewind given parser.  | 
10275  | 0  |         parser.rewind();  | 
10276  |  |         // If the result of running is a hash prefix given parser is true, then  | 
10277  |  |         // run change state given parser, "hash" and 1.  | 
10278  | 0  |         if (parser.is_hash_prefix()) { | 
10279  | 0  |           parser.change_state(State::HASH, 1);  | 
10280  | 0  |         } else if (parser.is_search_prefix()) { | 
10281  |  |           // Otherwise if the result of running is a search prefix given parser  | 
10282  |  |           // is true: Run change state given parser, "search" and 1.  | 
10283  | 0  |           parser.change_state(State::SEARCH, 1);  | 
10284  | 0  |         } else { | 
10285  |  |           // Run change state given parser, "pathname" and 0.  | 
10286  | 0  |           parser.change_state(State::PATHNAME, 0);  | 
10287  | 0  |         }  | 
10288  |  |         // Increment parser's token index by parser's token increment.  | 
10289  | 0  |         parser.token_index += parser.token_increment;  | 
10290  |  |         // Continue.  | 
10291  | 0  |         continue;  | 
10292  | 0  |       }  | 
10293  |  |  | 
10294  | 0  |       if (parser.state == State::AUTHORITY) { | 
10295  |  |         // If parser's state is "authority":  | 
10296  |  |         // Run rewind and set state given parser, and "hostname".  | 
10297  | 0  |         parser.rewind();  | 
10298  | 0  |         parser.change_state(State::HOSTNAME, 0);  | 
10299  |  |         // Increment parser's token index by parser's token increment.  | 
10300  | 0  |         parser.token_index += parser.token_increment;  | 
10301  |  |         // Continue.  | 
10302  | 0  |         continue;  | 
10303  | 0  |       }  | 
10304  |  |  | 
10305  |  |       // Run change state given parser, "done" and 0.  | 
10306  | 0  |       parser.change_state(State::DONE, 0);  | 
10307  |  |       // Break.  | 
10308  | 0  |       break;  | 
10309  | 0  |     }  | 
10310  |  |  | 
10311  |  |     // If the result of running is a group open given parser is true:  | 
10312  | 0  |     if (parser.is_group_open()) { | 
10313  |  |       // Increment parser's group depth by 1.  | 
10314  | 0  |       parser.group_depth += 1;  | 
10315  |  |       // Increment parser's token index by parser's token increment.  | 
10316  | 0  |       parser.token_index += parser.token_increment;  | 
10317  | 0  |     }  | 
10318  |  |  | 
10319  |  |     // If parser's group depth is greater than 0:  | 
10320  | 0  |     if (parser.group_depth > 0) { | 
10321  |  |       // If the result of running is a group close given parser is true, then  | 
10322  |  |       // decrement parser's group depth by 1.  | 
10323  | 0  |       if (parser.is_group_close()) { | 
10324  | 0  |         parser.group_depth -= 1;  | 
10325  | 0  |       } else { | 
10326  |  |         // Increment parser's token index by parser's token increment.  | 
10327  | 0  |         parser.token_index += parser.token_increment;  | 
10328  | 0  |         continue;  | 
10329  | 0  |       }  | 
10330  | 0  |     }  | 
10331  |  |  | 
10332  |  |     // Switch on parser's state and run the associated steps:  | 
10333  | 0  |     switch (parser.state) { | 
10334  | 0  |       case State::INIT: { | 
10335  |  |         // If the result of running is a protocol suffix given parser is true:  | 
10336  | 0  |         if (parser.is_protocol_suffix()) { | 
10337  |  |           // Run rewind and set state given parser and "protocol".  | 
10338  | 0  |           parser.rewind();  | 
10339  | 0  |           parser.change_state(State::PROTOCOL, 0);  | 
10340  | 0  |         }  | 
10341  | 0  |         break;  | 
10342  | 0  |       }  | 
10343  | 0  |       case State::PROTOCOL: { | 
10344  |  |         // If the result of running is a protocol suffix given parser is true:  | 
10345  | 0  |         if (parser.is_protocol_suffix()) { | 
10346  |  |           // Run compute protocol matches a special scheme flag given parser.  | 
10347  | 0  |           if (const auto error =  | 
10348  | 0  |                   parser.compute_protocol_matches_special_scheme_flag()) { | 
10349  | 0  |             ada_log("compute_protocol_matches_special_scheme_flag failed"); | 
10350  | 0  |             return tl::unexpected(*error);  | 
10351  | 0  |           }  | 
10352  |  |           // Let next state be "pathname".  | 
10353  | 0  |           auto next_state = State::PATHNAME;  | 
10354  |  |           // Let skip be 1.  | 
10355  | 0  |           auto skip = 1;  | 
10356  |  |           // If the result of running next is authority slashes given parser is  | 
10357  |  |           // true:  | 
10358  | 0  |           if (parser.next_is_authority_slashes()) { | 
10359  |  |             // Set next state to "authority".  | 
10360  | 0  |             next_state = State::AUTHORITY;  | 
10361  |  |             // Set skip to 3.  | 
10362  | 0  |             skip = 3;  | 
10363  | 0  |           } else if (parser.protocol_matches_a_special_scheme_flag) { | 
10364  |  |             // Otherwise if parser's protocol matches a special scheme flag is  | 
10365  |  |             // true, then set next state to "authority".  | 
10366  | 0  |             next_state = State::AUTHORITY;  | 
10367  | 0  |           }  | 
10368  |  |  | 
10369  |  |           // Run change state given parser, next state, and skip.  | 
10370  | 0  |           parser.change_state(next_state, skip);  | 
10371  | 0  |         }  | 
10372  | 0  |         break;  | 
10373  | 0  |       }  | 
10374  | 0  |       case State::AUTHORITY: { | 
10375  |  |         // If the result of running is an identity terminator given parser is  | 
10376  |  |         // true, then run rewind and set state given parser and "username".  | 
10377  | 0  |         if (parser.is_an_identity_terminator()) { | 
10378  | 0  |           parser.rewind();  | 
10379  | 0  |           parser.change_state(State::USERNAME, 0);  | 
10380  | 0  |         } else if (parser.is_pathname_start() || parser.is_search_prefix() ||  | 
10381  | 0  |                    parser.is_hash_prefix()) { | 
10382  |  |           // Otherwise if any of the following are true:  | 
10383  |  |           // - the result of running is a pathname start given parser;  | 
10384  |  |           // - the result of running is a search prefix given parser; or  | 
10385  |  |           // - the result of running is a hash prefix given parser,  | 
10386  |  |           // then run rewind and set state given parser and "hostname".  | 
10387  | 0  |           parser.rewind();  | 
10388  | 0  |           parser.change_state(State::HOSTNAME, 0);  | 
10389  | 0  |         }  | 
10390  | 0  |         break;  | 
10391  | 0  |       }  | 
10392  | 0  |       case State::USERNAME: { | 
10393  |  |         // If the result of running is a password prefix given parser is true,  | 
10394  |  |         // then run change state given parser, "password", and 1.  | 
10395  | 0  |         if (parser.is_password_prefix()) { | 
10396  | 0  |           parser.change_state(State::PASSWORD, 1);  | 
10397  | 0  |         } else if (parser.is_an_identity_terminator()) { | 
10398  |  |           // Otherwise if the result of running is an identity terminator given  | 
10399  |  |           // parser is true, then run change state given parser, "hostname",  | 
10400  |  |           // and 1.  | 
10401  | 0  |           parser.change_state(State::HOSTNAME, 1);  | 
10402  | 0  |         }  | 
10403  | 0  |         break;  | 
10404  | 0  |       }  | 
10405  | 0  |       case State::PASSWORD: { | 
10406  |  |         // If the result of running is an identity terminator given parser is  | 
10407  |  |         // true, then run change state given parser, "hostname", and 1.  | 
10408  | 0  |         if (parser.is_an_identity_terminator()) { | 
10409  | 0  |           parser.change_state(State::HOSTNAME, 1);  | 
10410  | 0  |         }  | 
10411  | 0  |         break;  | 
10412  | 0  |       }  | 
10413  | 0  |       case State::HOSTNAME: { | 
10414  |  |         // If the result of running is an IPv6 open given parser is true, then  | 
10415  |  |         // increment parser's hostname IPv6 bracket depth by 1.  | 
10416  | 0  |         if (parser.is_an_ipv6_open()) { | 
10417  | 0  |           parser.hostname_ipv6_bracket_depth += 1;  | 
10418  | 0  |         } else if (parser.is_an_ipv6_close()) { | 
10419  |  |           // Otherwise if the result of running is an IPv6 close given parser is  | 
10420  |  |           // true, then decrement parser's hostname IPv6 bracket depth by 1.  | 
10421  | 0  |           parser.hostname_ipv6_bracket_depth -= 1;  | 
10422  | 0  |         } else if (parser.is_port_prefix() &&  | 
10423  | 0  |                    parser.hostname_ipv6_bracket_depth == 0) { | 
10424  |  |           // Otherwise if the result of running is a port prefix given parser is  | 
10425  |  |           // true and parser's hostname IPv6 bracket depth is zero, then run  | 
10426  |  |           // change state given parser, "port", and 1.  | 
10427  | 0  |           parser.change_state(State::PORT, 1);  | 
10428  | 0  |         } else if (parser.is_pathname_start()) { | 
10429  |  |           // Otherwise if the result of running is a pathname start given parser  | 
10430  |  |           // is true, then run change state given parser, "pathname", and 0.  | 
10431  | 0  |           parser.change_state(State::PATHNAME, 0);  | 
10432  | 0  |         } else if (parser.is_search_prefix()) { | 
10433  |  |           // Otherwise if the result of running is a search prefix given parser  | 
10434  |  |           // is true, then run change state given parser, "search", and 1.  | 
10435  | 0  |           parser.change_state(State::SEARCH, 1);  | 
10436  | 0  |         } else if (parser.is_hash_prefix()) { | 
10437  |  |           // Otherwise if the result of running is a hash prefix given parser is  | 
10438  |  |           // true, then run change state given parser, "hash", and 1.  | 
10439  | 0  |           parser.change_state(State::HASH, 1);  | 
10440  | 0  |         }  | 
10441  |  | 
  | 
10442  | 0  |         break;  | 
10443  | 0  |       }  | 
10444  | 0  |       case State::PORT: { | 
10445  |  |         // If the result of running is a pathname start given parser is true,  | 
10446  |  |         // then run change state given parser, "pathname", and 0.  | 
10447  | 0  |         if (parser.is_pathname_start()) { | 
10448  | 0  |           parser.change_state(State::PATHNAME, 0);  | 
10449  | 0  |         } else if (parser.is_search_prefix()) { | 
10450  |  |           // Otherwise if the result of running is a search prefix given parser  | 
10451  |  |           // is true, then run change state given parser, "search", and 1.  | 
10452  | 0  |           parser.change_state(State::SEARCH, 1);  | 
10453  | 0  |         } else if (parser.is_hash_prefix()) { | 
10454  |  |           // Otherwise if the result of running is a hash prefix given parser is  | 
10455  |  |           // true, then run change state given parser, "hash", and 1.  | 
10456  | 0  |           parser.change_state(State::HASH, 1);  | 
10457  | 0  |         }  | 
10458  | 0  |         break;  | 
10459  | 0  |       }  | 
10460  | 0  |       case State::PATHNAME: { | 
10461  |  |         // If the result of running is a search prefix given parser is true,  | 
10462  |  |         // then run change state given parser, "search", and 1.  | 
10463  | 0  |         if (parser.is_search_prefix()) { | 
10464  | 0  |           parser.change_state(State::SEARCH, 1);  | 
10465  | 0  |         } else if (parser.is_hash_prefix()) { | 
10466  |  |           // Otherwise if the result of running is a hash prefix given parser is  | 
10467  |  |           // true, then run change state given parser, "hash", and 1.  | 
10468  | 0  |           parser.change_state(State::HASH, 1);  | 
10469  | 0  |         }  | 
10470  | 0  |         break;  | 
10471  | 0  |       }  | 
10472  | 0  |       case State::SEARCH: { | 
10473  |  |         // If the result of running is a hash prefix given parser is true, then  | 
10474  |  |         // run change state given parser, "hash", and 1.  | 
10475  | 0  |         if (parser.is_hash_prefix()) { | 
10476  | 0  |           parser.change_state(State::HASH, 1);  | 
10477  | 0  |         }  | 
10478  | 0  |         break;  | 
10479  | 0  |       }  | 
10480  | 0  |       case State::HASH: { | 
10481  |  |         // Do nothing  | 
10482  | 0  |         break;  | 
10483  | 0  |       }  | 
10484  | 0  |       default: { | 
10485  |  |         // Assert: This step is never reached.  | 
10486  | 0  |         unreachable();  | 
10487  | 0  |       }  | 
10488  | 0  |     }  | 
10489  |  |  | 
10490  |  |     // Increment parser's token index by parser's token increment.  | 
10491  | 0  |     parser.token_index += parser.token_increment;  | 
10492  | 0  |   }  | 
10493  |  |  | 
10494  |  |   // If parser's result contains "hostname" and not "port", then set parser's  | 
10495  |  |   // result["port"] to the empty string.  | 
10496  | 0  |   if (parser.result.hostname && !parser.result.port) { | 
10497  | 0  |     parser.result.port = "";  | 
10498  | 0  |   }  | 
10499  |  |  | 
10500  |  |   // Return parser's result.  | 
10501  | 0  |   return parser.result;  | 
10502  | 0  | }  | 
10503  |  |  | 
10504  |  | }  // namespace ada::url_pattern_helpers  | 
10505  |  | #endif  // ADA_INCLUDE_URL_PATTERN  | 
10506  |  | #endif  | 
10507  |  | /* end file include/ada/url_pattern_helpers-inl.h */  | 
10508  |  |  | 
10509  |  | // Public API  | 
10510  |  | /* begin file include/ada/ada_version.h */  | 
10511  |  | /**  | 
10512  |  |  * @file ada_version.h  | 
10513  |  |  * @brief Definitions for Ada's version number.  | 
10514  |  |  */  | 
10515  |  | #ifndef ADA_ADA_VERSION_H  | 
10516  |  | #define ADA_ADA_VERSION_H  | 
10517  |  |  | 
10518  | 72  | #define ADA_VERSION "3.3.0"  | 
10519  |  |  | 
10520  |  | namespace ada { | 
10521  |  |  | 
10522  |  | enum { | 
10523  |  |   ADA_VERSION_MAJOR = 3,  | 
10524  |  |   ADA_VERSION_MINOR = 3,  | 
10525  |  |   ADA_VERSION_REVISION = 0,  | 
10526  |  | };  | 
10527  |  |  | 
10528  |  | }  // namespace ada  | 
10529  |  |  | 
10530  |  | #endif  // ADA_ADA_VERSION_H  | 
10531  |  | /* end file include/ada/ada_version.h */  | 
10532  |  | /* begin file include/ada/implementation-inl.h */  | 
10533  |  | /**  | 
10534  |  |  * @file implementation-inl.h  | 
10535  |  |  */  | 
10536  |  | #ifndef ADA_IMPLEMENTATION_INL_H  | 
10537  |  | #define ADA_IMPLEMENTATION_INL_H  | 
10538  |  |  | 
10539  |  |  | 
10540  |  |  | 
10541  |  | #include <variant>  | 
10542  |  | #include <string_view>  | 
10543  |  |  | 
10544  |  | namespace ada { | 
10545  |  |  | 
10546  |  | #if ADA_INCLUDE_URL_PATTERN  | 
10547  |  | template <url_pattern_regex::regex_concept regex_provider>  | 
10548  |  | ada_warn_unused tl::expected<url_pattern<regex_provider>, errors>  | 
10549  |  | parse_url_pattern(std::variant<std::string_view, url_pattern_init>&& input,  | 
10550  |  |                   const std::string_view* base_url,  | 
10551  | 0  |                   const url_pattern_options* options) { | 
10552  | 0  |   return parser::parse_url_pattern_impl<regex_provider>(std::move(input),  | 
10553  | 0  |                                                         base_url, options);  | 
10554  | 0  | }  | 
10555  |  | #endif  // ADA_INCLUDE_URL_PATTERN  | 
10556  |  |  | 
10557  |  | }  // namespace ada  | 
10558  |  |  | 
10559  |  | #endif  // ADA_IMPLEMENTATION_INL_H  | 
10560  |  | /* end file include/ada/implementation-inl.h */  | 
10561  |  |  | 
10562  |  | #endif  // ADA_H  | 
10563  |  | /* end file include/ada.h */  |