Skip to content

Commit

Permalink
reduce string allocations in urlpattern
Browse files Browse the repository at this point in the history
  • Loading branch information
anonrig committed Feb 15, 2025
1 parent 3037390 commit dc214ba
Show file tree
Hide file tree
Showing 6 changed files with 48 additions and 43 deletions.
4 changes: 2 additions & 2 deletions include/ada/parser-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,8 @@ tl::expected<url_pattern<regex_provider>, errors> parse_url_pattern_impl(

// Let processedInit be the result of process a URLPatternInit given init,
// "pattern", null, null, null, null, null, null, null, and null.
// TODO: Make "pattern" an enum to avoid creating a string everytime.
auto processed_init = url_pattern_init::process(init, "pattern");
auto processed_init =
url_pattern_init::process(init, url_pattern_init::process_type::pattern);
if (!processed_init) {
ada_log("url_pattern_init::process failed for init and 'pattern'");
return tl::unexpected(processed_init.error());
Expand Down
4 changes: 2 additions & 2 deletions include/ada/url_pattern-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -244,8 +244,8 @@ result<std::optional<url_pattern_result>> url_pattern<regex_provider>::match(
// "url", protocol, username, password, hostname, port, pathname, search,
// and hash.
auto apply_result = url_pattern_init::process(
std::get<url_pattern_init>(input), "url", protocol, username, password,
hostname, port, pathname, search, hash);
std::get<url_pattern_init>(input), url_pattern_init::process_type::url,
protocol, username, password, hostname, port, pathname, search, hash);

// If this throws an exception, catch it, and return null.
if (!apply_result.has_value()) {
Expand Down
6 changes: 3 additions & 3 deletions include/ada/url_pattern_helpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,7 @@ tl::expected<std::vector<token>, errors> tokenize(std::string_view input,

// @see https://urlpattern.spec.whatwg.org/#process-a-base-url-string
std::string process_base_url_string(std::string_view input,
std::string_view type);
url_pattern_init::process_type type);

// @see https://urlpattern.spec.whatwg.org/#escape-a-pattern-string
std::string escape_pattern_string(std::string_view input);
Expand All @@ -304,8 +304,8 @@ std::string escape_pattern_string(std::string_view input);
std::string escape_regexp_string(std::string_view input);

// @see https://urlpattern.spec.whatwg.org/#is-an-absolute-pathname
constexpr bool is_absolute_pathname(std::string_view input,
std::string_view type) noexcept;
constexpr bool is_absolute_pathname(
std::string_view input, url_pattern_init::process_type type) noexcept;

// @see https://urlpattern.spec.whatwg.org/#parse-a-pattern-string
template <url_pattern_encoding_callback F>
Expand Down
23 changes: 14 additions & 9 deletions include/ada/url_pattern_init.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,15 @@ concept url_pattern_encoding_callback = requires(F f, std::string_view sv) {
// API is defined as part of the URLPattern specification.
// All provided strings must be valid UTF-8.
struct url_pattern_init {
enum class process_type : uint8_t {
url,
pattern,
};

// All strings must be valid UTF-8.
// @see https://urlpattern.spec.whatwg.org/#process-a-urlpatterninit
static tl::expected<url_pattern_init, errors> process(
url_pattern_init init, std::string_view type,
url_pattern_init init, process_type type,
std::optional<std::string_view> protocol = std::nullopt,
std::optional<std::string_view> username = std::nullopt,
std::optional<std::string_view> password = std::nullopt,
Expand All @@ -49,35 +54,35 @@ struct url_pattern_init {

// @see https://urlpattern.spec.whatwg.org/#process-protocol-for-init
static tl::expected<std::string, errors> process_protocol(
std::string_view value, std::string_view type);
std::string_view value, process_type type);

// @see https://urlpattern.spec.whatwg.org/#process-username-for-init
static tl::expected<std::string, errors> process_username(
std::string_view value, std::string_view type);
std::string_view value, process_type type);

// @see https://urlpattern.spec.whatwg.org/#process-password-for-init
static tl::expected<std::string, errors> process_password(
std::string_view value, std::string_view type);
std::string_view value, process_type type);

// @see https://urlpattern.spec.whatwg.org/#process-hostname-for-init
static tl::expected<std::string, errors> process_hostname(
std::string_view value, std::string_view type);
std::string_view value, process_type type);

// @see https://urlpattern.spec.whatwg.org/#process-port-for-init
static tl::expected<std::string, errors> process_port(
std::string_view port, std::string_view protocol, std::string_view type);
std::string_view port, std::string_view protocol, process_type type);

// @see https://urlpattern.spec.whatwg.org/#process-pathname-for-init
static tl::expected<std::string, errors> process_pathname(
std::string_view value, std::string_view protocol, std::string_view type);
std::string_view value, std::string_view protocol, process_type type);

// @see https://urlpattern.spec.whatwg.org/#process-search-for-init
static tl::expected<std::string, errors> process_search(
std::string_view value, std::string_view type);
std::string_view value, process_type type);

// @see https://urlpattern.spec.whatwg.org/#process-hash-for-init
static tl::expected<std::string, errors> process_hash(std::string_view value,
std::string_view type);
process_type type);

#if ADA_TESTING
friend void PrintTo(const url_pattern_init& init, std::ostream* os) {
Expand Down
42 changes: 21 additions & 21 deletions src/url_pattern.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
namespace ada {

tl::expected<url_pattern_init, errors> url_pattern_init::process(
url_pattern_init init, std::string_view type,
url_pattern_init init, url_pattern_init::process_type type,
std::optional<std::string_view> protocol,
std::optional<std::string_view> username,
std::optional<std::string_view> password,
Expand Down Expand Up @@ -69,8 +69,8 @@ tl::expected<url_pattern_init, errors> url_pattern_init::process(
// If type is not "pattern" and init contains none of "protocol",
// "hostname", "port" and "username", then set result["username"] to the
// result of processing a base URL string given baseURL’s username and type.
if (type != "pattern" && !init.protocol && !init.hostname && !init.port &&
!init.username) {
if (type != process_type::pattern && !init.protocol && !init.hostname &&
!init.port && !init.username) {
result.username = url_pattern_helpers::process_base_url_string(
base_url->get_username(), type);
}
Expand All @@ -80,8 +80,8 @@ tl::expected<url_pattern_init, errors> url_pattern_init::process(
// "hostname", "port", "username" and "password", then set
// result["password"] to the result of processing a base URL string given
// baseURL’s password and type.
if (type != "pattern" && !init.protocol && !init.hostname && !init.port &&
!init.username && !init.password) {
if (type != process_type::pattern && !init.protocol && !init.hostname &&
!init.port && !init.username && !init.password) {
result.password = url_pattern_helpers::process_base_url_string(
base_url->get_password(), type);
}
Expand Down Expand Up @@ -255,56 +255,56 @@ tl::expected<url_pattern_init, errors> url_pattern_init::process(
}

tl::expected<std::string, errors> url_pattern_init::process_protocol(
std::string_view value, std::string_view type) {
std::string_view value, process_type type) {
ada_log("process_protocol=", value, " [", type, "]");
// Let strippedValue be the given value with a single trailing U+003A (:)
// removed, if any.
if (value.ends_with(":")) {
value.remove_suffix(1);
}
// If type is "pattern" then return strippedValue.
if (type == "pattern") {
if (type == process_type::pattern) {
return std::string(value);
}
// Return the result of running canonicalize a protocol given strippedValue.
return url_pattern_helpers::canonicalize_protocol(value);
}

tl::expected<std::string, errors> url_pattern_init::process_username(
std::string_view value, std::string_view type) {
std::string_view value, process_type type) {
// If type is "pattern" then return value.
if (type == "pattern") {
if (type == process_type::pattern) {
return std::string(value);
}
// Return the result of running canonicalize a username given value.
return url_pattern_helpers::canonicalize_username(value);
}

tl::expected<std::string, errors> url_pattern_init::process_password(
std::string_view value, std::string_view type) {
std::string_view value, process_type type) {
// If type is "pattern" then return value.
if (type == "pattern") {
if (type == process_type::pattern) {
return std::string(value);
}
// Return the result of running canonicalize a password given value.
return url_pattern_helpers::canonicalize_password(value);
}

tl::expected<std::string, errors> url_pattern_init::process_hostname(
std::string_view value, std::string_view type) {
std::string_view value, process_type type) {
ada_log("process_hostname value=", value, " type=", type);
// If type is "pattern" then return value.
if (type == "pattern") {
if (type == process_type::pattern) {
return std::string(value);
}
// Return the result of running canonicalize a hostname given value.
return url_pattern_helpers::canonicalize_hostname(value);
}

tl::expected<std::string, errors> url_pattern_init::process_port(
std::string_view port, std::string_view protocol, std::string_view type) {
std::string_view port, std::string_view protocol, process_type type) {
// If type is "pattern" then return portValue.
if (type == "pattern") {
if (type == process_type::pattern) {
return std::string(port);
}
// Return the result of running canonicalize a port given portValue and
Expand All @@ -313,9 +313,9 @@ tl::expected<std::string, errors> url_pattern_init::process_port(
}

tl::expected<std::string, errors> url_pattern_init::process_pathname(
std::string_view value, std::string_view protocol, std::string_view type) {
std::string_view value, std::string_view protocol, process_type type) {
// If type is "pattern" then return pathnameValue.
if (type == "pattern") {
if (type == process_type::pattern) {
return std::string(value);
}

Expand All @@ -331,31 +331,31 @@ tl::expected<std::string, errors> url_pattern_init::process_pathname(
}

tl::expected<std::string, errors> url_pattern_init::process_search(
std::string_view value, std::string_view type) {
std::string_view value, process_type type) {
// Let strippedValue be the given value with a single leading U+003F (?)
// removed, if any.
if (value.starts_with("?")) {
value.remove_prefix(1);
}
ADA_ASSERT_TRUE(!value.starts_with("?"));
// If type is "pattern" then return strippedValue.
if (type == "pattern") {
if (type == process_type::pattern) {
return std::string(value);
}
// Return the result of running canonicalize a search given strippedValue.
return url_pattern_helpers::canonicalize_search(value);
}

tl::expected<std::string, errors> url_pattern_init::process_hash(
std::string_view value, std::string_view type) {
std::string_view value, process_type type) {
// Let strippedValue be the given value with a single leading U+0023 (#)
// removed, if any.
if (value.starts_with("#")) {
value.remove_prefix(1);
}
ADA_ASSERT_TRUE(!value.starts_with("#"));
// If type is "pattern" then return strippedValue.
if (type == "pattern") {
if (type == process_type::pattern) {
return std::string(value);
}
// Return the result of running canonicalize a hash given strippedValue.
Expand Down
12 changes: 6 additions & 6 deletions src/url_pattern_helpers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -803,25 +803,25 @@ std::string escape_regexp_string(std::string_view input) {
}

std::string process_base_url_string(std::string_view input,
std::string_view type) {
url_pattern_init::process_type type) {
// If type is not "pattern" return input.
if (type != "pattern") {
if (type != url_pattern_init::process_type::pattern) {
return std::string(input);
}
// Return the result of escaping a pattern string given input.
return escape_pattern_string(input);
}

constexpr bool is_absolute_pathname(std::string_view input,
std::string_view type) noexcept {
constexpr bool is_absolute_pathname(
std::string_view input, url_pattern_init::process_type type) noexcept {
// If input is the empty string, then return false.
if (input.empty()) [[unlikely]] {
return false;
}
// If input[0] is U+002F (/), then return true.
if (input.starts_with("/")) return true;
// If type is "url", then return false.
if (type == "url") return false;
if (type == url_pattern_init::process_type::url) return false;
// If input’s code point length is less than 2, then return false.
if (input.size() < 2) return false;
// If input[0] is U+005C (\) and input[1] is U+002F (/), then return true.
Expand Down Expand Up @@ -1014,4 +1014,4 @@ std::string generate_pattern_string(
// Return result.
return result;
}
} // namespace ada::url_pattern_helpers
} // namespace ada::url_pattern_helpers

0 comments on commit dc214ba

Please sign in to comment.