5#ifndef ADA_URL_PATTERN_INL_H
6#define ADA_URL_PATTERN_INL_H
16#if ADA_INCLUDE_URL_PATTERN
19inline bool url_pattern_init::operator==(
const url_pattern_init& other)
const {
20 return protocol == other.protocol && username == other.username &&
21 password == other.password && hostname == other.hostname &&
22 port == other.port && search == other.search && hash == other.hash &&
23 pathname == other.pathname;
26inline bool url_pattern_component_result::operator==(
27 const url_pattern_component_result& other)
const {
28 return input == other.input && groups == other.groups;
31template <url_pattern_regex::regex_concept regex_prov
ider>
32url_pattern_component_result
33url_pattern_component<regex_provider>::create_component_match_result(
35 std::vector<std::optional<std::string>>&& exec_result) {
40 url_pattern_component_result{.input = std::move(input), .groups = {}};
43 result.groups.reserve(exec_result.size());
48 for (
size_t index = 0; index < exec_result.size(); index++) {
49 result.groups.emplace(group_name_list[index],
50 std::move(exec_result[index]));
55template <url_pattern_regex::regex_concept regex_prov
ider>
56std::string_view url_pattern<regex_provider>::get_protocol() const
59 return protocol_component.pattern;
61template <url_pattern_regex::regex_concept regex_prov
ider>
62std::string_view url_pattern<regex_provider>::get_username() const
65 return username_component.pattern;
67template <url_pattern_regex::regex_concept regex_prov
ider>
68std::string_view url_pattern<regex_provider>::get_password() const
71 return password_component.pattern;
73template <url_pattern_regex::regex_concept regex_prov
ider>
74std::string_view url_pattern<regex_provider>::get_hostname() const
77 return hostname_component.pattern;
79template <url_pattern_regex::regex_concept regex_prov
ider>
80std::string_view url_pattern<regex_provider>::get_port() const
83 return port_component.pattern;
85template <url_pattern_regex::regex_concept regex_prov
ider>
86std::string_view url_pattern<regex_provider>::get_pathname() const
89 return pathname_component.pattern;
91template <url_pattern_regex::regex_concept regex_prov
ider>
92std::string_view url_pattern<regex_provider>::get_search() const
95 return search_component.pattern;
97template <url_pattern_regex::regex_concept regex_prov
ider>
98std::string_view url_pattern<regex_provider>::get_hash() const
101 return hash_component.pattern;
103template <url_pattern_regex::regex_concept regex_prov
ider>
104bool url_pattern<regex_provider>::ignore_case()
const {
107template <url_pattern_regex::regex_concept regex_prov
ider>
108bool url_pattern<regex_provider>::has_regexp_groups()
const {
110 return protocol_component.has_regexp_groups ||
111 username_component.has_regexp_groups ||
112 password_component.has_regexp_groups ||
113 hostname_component.has_regexp_groups ||
114 port_component.has_regexp_groups ||
115 pathname_component.has_regexp_groups ||
116 search_component.has_regexp_groups || hash_component.has_regexp_groups;
119inline bool url_pattern_part::is_regexp() const noexcept {
120 return type == url_pattern_part_type::REGEXP;
123inline std::string_view url_pattern_compile_component_options::get_delimiter()
126 return {&delimiter.value(), 1};
131inline std::string_view url_pattern_compile_component_options::get_prefix()
134 return {&prefix.value(), 1};
139template <url_pattern_regex::regex_concept regex_prov
ider>
140template <url_pattern_encoding_callback F>
141tl::expected<url_pattern_component<regex_provider>,
errors>
142url_pattern_component<regex_provider>::compile(
143 std::string_view input, F& encoding_callback,
144 url_pattern_compile_component_options& options) {
145 ada_log(
"url_pattern_component::compile input: ", input);
148 auto part_list = url_pattern_helpers::parse_pattern_string(input, options,
152 ada_log(
"parse_pattern_string failed");
153 return tl::unexpected(part_list.error());
157 const auto has_regexp = [](
const auto& part) {
return part.is_regexp(); };
158 const bool has_regexp_groups = std::ranges::any_of(*part_list, has_regexp);
160 url_pattern_component_type component_type =
161 url_pattern_component_type::REGEXP;
162 std::string exact_match_value{};
164 if (part_list->empty()) {
165 component_type = url_pattern_component_type::EMPTY;
166 }
else if (part_list->size() == 1) {
167 const auto& part = (*part_list)[0];
168 if (part.type == url_pattern_part_type::FIXED_TEXT &&
169 part.modifier == url_pattern_part_modifier::none &&
170 !options.ignore_case) {
171 component_type = url_pattern_component_type::EXACT_MATCH;
172 exact_match_value = part.value;
173 }
else if (part.type == url_pattern_part_type::FULL_WILDCARD &&
174 part.modifier == url_pattern_part_modifier::none &&
175 part.prefix.empty() && part.suffix.empty()) {
176 component_type = url_pattern_component_type::FULL_WILDCARD;
181 if (component_type != url_pattern_component_type::REGEXP) {
182 auto pattern_string =
183 url_pattern_helpers::generate_pattern_string(*part_list, options);
186 std::vector<std::string> name_list;
187 if (component_type == url_pattern_component_type::FULL_WILDCARD &&
188 !part_list->empty()) {
189 name_list.push_back((*part_list)[0].name);
191 return url_pattern_component<regex_provider>(
192 std::move(pattern_string),
typename regex_provider::regex_type{},
193 std::move(name_list), has_regexp_groups, component_type,
194 std::move(exact_match_value));
198 auto [regular_expression_string, name_list] =
199 url_pattern_helpers::generate_regular_expression_and_name_list(*part_list,
201 auto pattern_string =
202 url_pattern_helpers::generate_pattern_string(*part_list, options);
204 std::optional<typename regex_provider::regex_type> regular_expression =
205 regex_provider::create_instance(regular_expression_string,
206 options.ignore_case);
207 if (!regular_expression) {
211 return url_pattern_component<regex_provider>(
212 std::move(pattern_string), std::move(*regular_expression),
213 std::move(name_list), has_regexp_groups, component_type,
214 std::move(exact_match_value));
217template <url_pattern_regex::regex_concept regex_prov
ider>
218bool url_pattern_component<regex_provider>::fast_test(
219 std::string_view input)
const noexcept {
222 if (type == url_pattern_component_type::FULL_WILDCARD) {
225 if (type == url_pattern_component_type::EXACT_MATCH) {
226 return input == exact_match_value;
228 if (type == url_pattern_component_type::EMPTY) {
229 return input.empty();
232 return regex_provider::regex_match(input, regexp);
235template <url_pattern_regex::regex_concept regex_prov
ider>
236std::optional<std::vector<std::optional<std::string>>>
237url_pattern_component<regex_provider>::fast_match(
238 std::string_view input)
const {
240 if (type == url_pattern_component_type::FULL_WILDCARD) {
243 if (input.empty() || group_name_list.empty()) {
244 return std::vector<std::optional<std::string>>{};
246 return std::vector<std::optional<std::string>>{std::string(input)};
248 if (type == url_pattern_component_type::EXACT_MATCH) {
249 if (input == exact_match_value) {
250 return std::vector<std::optional<std::string>>{};
254 if (type == url_pattern_component_type::EMPTY) {
256 return std::vector<std::optional<std::string>>{};
261 return regex_provider::regex_search(input, regexp);
264template <url_pattern_regex::regex_concept regex_prov
ider>
266 const url_pattern_input& input,
const std::string_view* base_url) {
269 return match(input, base_url);
272template <url_pattern_regex::regex_concept regex_prov
ider>
273bool url_pattern<regex_provider>::test_components(
274 std::string_view protocol, std::string_view username,
275 std::string_view password, std::string_view hostname, std::string_view port,
276 std::string_view pathname, std::string_view search,
277 std::string_view hash)
const {
278 return protocol_component.fast_test(protocol) &&
279 username_component.fast_test(username) &&
280 password_component.fast_test(password) &&
281 hostname_component.fast_test(hostname) &&
282 port_component.fast_test(port) &&
283 pathname_component.fast_test(pathname) &&
284 search_component.fast_test(search) && hash_component.fast_test(hash);
287template <url_pattern_regex::regex_concept regex_prov
ider>
289 const url_pattern_input& input,
const std::string_view* base_url_string) {
291 if (std::holds_alternative<url_pattern_init>(input)) {
292 if (base_url_string) {
296 std::string protocol{}, username{}, password{}, hostname{};
297 std::string port{}, pathname{}, search{}, hash{};
299 auto apply_result = url_pattern_init::process(
300 std::get<url_pattern_init>(input), url_pattern_init::process_type::url,
301 protocol, username, password, hostname, port, pathname, search, hash);
307 std::string_view search_view = *apply_result->search;
308 if (search_view.starts_with(
"?")) {
309 search_view.remove_prefix(1);
312 return test_components(*apply_result->protocol, *apply_result->username,
313 *apply_result->password, *apply_result->hostname,
314 *apply_result->port, *apply_result->pathname,
315 search_view, *apply_result->hash);
320 if (base_url_string) {
329 base_url.has_value() ? &*base_url :
nullptr);
336 if (protocol_view.ends_with(
":")) {
337 protocol_view.remove_suffix(1);
341 if (search_view.starts_with(
"?")) {
342 search_view.remove_prefix(1);
346 if (hash_view.starts_with(
"#")) {
347 hash_view.remove_prefix(1);
356template <url_pattern_regex::regex_concept regex_prov
ider>
358 const url_pattern_input& input,
const std::string_view* base_url_string) {
359 std::string protocol{};
360 std::string username{};
361 std::string password{};
362 std::string hostname{};
364 std::string pathname{};
365 std::string search{};
370 std::vector inputs{input};
373 if (std::holds_alternative<url_pattern_init>(input)) {
375 "url_pattern::match called with url_pattern_init and base_url_string=",
378 if (base_url_string) {
379 ada_log(
"failed to match because base_url_string was given");
386 auto apply_result = url_pattern_init::process(
387 std::get<url_pattern_init>(input), url_pattern_init::process_type::url,
388 protocol, username, password, hostname, port, pathname, search, hash);
391 if (!apply_result.has_value()) {
392 ada_log(
"match returned std::nullopt because process threw");
398 protocol = std::move(apply_result->protocol.value());
402 username = std::move(apply_result->username.value());
406 password = std::move(apply_result->password.value());
410 hostname = std::move(apply_result->hostname.value());
414 port = std::move(apply_result->port.value());
418 pathname = std::move(apply_result->pathname.value());
422 if (apply_result->search->starts_with(
"?")) {
423 search = apply_result->search->substr(1);
425 search = std::move(apply_result->search.value());
431 hash = std::move(apply_result->hash.value());
439 if (base_url_string) {
445 ada_log(
"match returned std::nullopt because failed to parse base_url=",
451 inputs.emplace_back(*base_url_string);
455 base_url.has_value() ? &*base_url :
nullptr;
463 ada_log(
"match returned std::nullopt because url failed");
490 search = view.starts_with(
"?") ?
url->
get_search().substr(1) : view;
498 hash = view.starts_with(
"#") ?
url->
get_hash().substr(1) : view;
507 auto protocol_exec_result = protocol_component.fast_match(protocol);
508 if (!protocol_exec_result) {
514 auto username_exec_result = username_component.fast_match(username);
515 if (!username_exec_result) {
521 auto password_exec_result = password_component.fast_match(password);
522 if (!password_exec_result) {
528 auto hostname_exec_result = hostname_component.fast_match(hostname);
529 if (!hostname_exec_result) {
535 auto port_exec_result = port_component.fast_match(port);
536 if (!port_exec_result) {
542 auto pathname_exec_result = pathname_component.fast_match(pathname);
543 if (!pathname_exec_result) {
549 auto search_exec_result = search_component.fast_match(search);
550 if (!search_exec_result) {
556 auto hash_exec_result = hash_component.fast_match(hash);
557 if (!hash_exec_result) {
562 auto result = url_pattern_result{};
564 result.inputs = std::move(inputs);
567 result.protocol = protocol_component.create_component_match_result(
568 std::move(protocol), std::move(*protocol_exec_result));
572 result.username = username_component.create_component_match_result(
573 std::move(username), std::move(*username_exec_result));
577 result.password = password_component.create_component_match_result(
578 std::move(password), std::move(*password_exec_result));
582 result.hostname = hostname_component.create_component_match_result(
583 std::move(hostname), std::move(*hostname_exec_result));
587 result.port = port_component.create_component_match_result(
588 std::move(port), std::move(*port_exec_result));
592 result.pathname = pathname_component.create_component_match_result(
593 std::move(pathname), std::move(*pathname_exec_result));
597 result.search = search_component.create_component_match_result(
598 std::move(search), std::move(*search_exec_result));
602 result.hash = hash_component.create_component_match_result(
603 std::move(hash), std::move(*hash_exec_result));
Cross-platform compiler macros and common definitions.
#define ADA_ASSERT_TRUE(COND)
#define ada_lifetime_bound
type
Enumeration of URL scheme types.
errors
Error codes for URL parsing operations.
template ada::result< url_aggregator > parse< url_aggregator >(std::string_view input, const url_aggregator *base_url)
tl::expected< result_type, ada::errors > result
Memory-efficient URL representation using a single buffer.
Represents a parsed URL with individual string components.
std::string get_search() const noexcept
constexpr std::string_view get_pathname() const noexcept
std::string get_hash() const noexcept
std::string get_hostname() const noexcept
const std::string & get_password() const noexcept
std::string get_port() const noexcept
const std::string & get_username() const noexcept
constexpr bool has_search() const noexcept override
std::string get_protocol() const noexcept
constexpr bool has_hash() const noexcept override
URLPattern API implementation.
Declaration for the URLPattern helpers.