Commit f6035f2d authored by Max Kellermann's avatar Max Kellermann

util/UriRelative: use std::string_view

Eliminates lots of implicit std::string temporaries.
parent c34a1e29
/* /*
* Copyright 2008-2019 Max Kellermann <max.kellermann@gmail.com> * Copyright 2008-2021 Max Kellermann <max.kellermann@gmail.com>
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions * modification, are permitted provided that the following conditions
...@@ -58,7 +58,7 @@ uri_is_child_or_same(const char *parent, const char *child) noexcept ...@@ -58,7 +58,7 @@ uri_is_child_or_same(const char *parent, const char *child) noexcept
} }
std::string std::string
uri_apply_base(const std::string &uri, const std::string &base) noexcept uri_apply_base(std::string_view uri, std::string_view base) noexcept
{ {
if (uri.front() == '/') { if (uri.front() == '/') {
/* absolute path: replace the whole URI path in base */ /* absolute path: replace the whole URI path in base */
...@@ -66,7 +66,7 @@ uri_apply_base(const std::string &uri, const std::string &base) noexcept ...@@ -66,7 +66,7 @@ uri_apply_base(const std::string &uri, const std::string &base) noexcept
auto i = base.find("://"); auto i = base.find("://");
if (i == base.npos) if (i == base.npos)
/* no scheme: override base completely */ /* no scheme: override base completely */
return uri; return std::string(uri);
/* find the first slash after the host part */ /* find the first slash after the host part */
i = base.find('/', i + 3); i = base.find('/', i + 3);
...@@ -74,7 +74,9 @@ uri_apply_base(const std::string &uri, const std::string &base) noexcept ...@@ -74,7 +74,9 @@ uri_apply_base(const std::string &uri, const std::string &base) noexcept
/* there's no URI path - simply append uri */ /* there's no URI path - simply append uri */
i = base.length(); i = base.length();
return base.substr(0, i) + uri; std::string out(base.substr(0, i));
out += uri;
return out;
} }
std::string out(base); std::string out(base);
...@@ -95,6 +97,13 @@ ClearFilename(StringView &path) noexcept ...@@ -95,6 +97,13 @@ ClearFilename(StringView &path) noexcept
path.size = 0; path.size = 0;
} }
static void
StripLeadingSlashes(StringView &s) noexcept
{
while (!s.empty() && s.front() == '/')
s.pop_front();
}
static bool static bool
ConsumeLastSegment(StringView &path) noexcept ConsumeLastSegment(StringView &path) noexcept
{ {
...@@ -111,22 +120,18 @@ ConsumeLastSegment(StringView &path) noexcept ...@@ -111,22 +120,18 @@ ConsumeLastSegment(StringView &path) noexcept
} }
static bool static bool
ConsumeSpecial(const char *&relative_path, StringView &base_path) noexcept ConsumeSpecial(StringView &relative_path, StringView &base_path) noexcept
{ {
while (true) { while (true) {
if (const char *a = StringAfterPrefix(relative_path, "./")) { if (relative_path.SkipPrefix("./")) {
while (*a == '/') StripLeadingSlashes(relative_path);
++a; } else if (relative_path.SkipPrefix("../")) {
relative_path = a; StripLeadingSlashes(relative_path);
} else if (const char *b = StringAfterPrefix(relative_path, "../")) {
while (*b == '/')
++b;
relative_path = b;
if (!ConsumeLastSegment(base_path)) if (!ConsumeLastSegment(base_path))
return false; return false;
} else if (StringIsEqual(relative_path, ".")) { } else if (relative_path.Equals(".")) {
++relative_path; relative_path.pop_front();
return true; return true;
} else } else
return true; return true;
...@@ -134,16 +139,14 @@ ConsumeSpecial(const char *&relative_path, StringView &base_path) noexcept ...@@ -134,16 +139,14 @@ ConsumeSpecial(const char *&relative_path, StringView &base_path) noexcept
} }
std::string std::string
uri_apply_relative(const std::string &relative_uri, uri_apply_relative(std::string_view relative_uri,
const std::string &base_uri) noexcept std::string_view base_uri) noexcept
{ {
if (relative_uri.empty()) if (relative_uri.empty())
return base_uri; return std::string(base_uri);
if (uri_has_scheme(relative_uri.c_str())) if (uri_has_scheme(relative_uri))
return relative_uri; return std::string(relative_uri);
const char *relative_path = relative_uri.c_str();
// TODO: support double slash at beginning of relative_uri // TODO: support double slash at beginning of relative_uri
if (relative_uri.front() == '/') { if (relative_uri.front() == '/') {
...@@ -152,7 +155,7 @@ uri_apply_relative(const std::string &relative_uri, ...@@ -152,7 +155,7 @@ uri_apply_relative(const std::string &relative_uri,
auto i = base_uri.find("://"); auto i = base_uri.find("://");
if (i == base_uri.npos) if (i == base_uri.npos)
/* no scheme: override base completely */ /* no scheme: override base completely */
return relative_uri; return std::string{relative_uri};
/* find the first slash after the host part */ /* find the first slash after the host part */
i = base_uri.find('/', i + 3); i = base_uri.find('/', i + 3);
...@@ -160,19 +163,22 @@ uri_apply_relative(const std::string &relative_uri, ...@@ -160,19 +163,22 @@ uri_apply_relative(const std::string &relative_uri,
/* there's no URI path - simply append uri */ /* there's no URI path - simply append uri */
i = base_uri.length(); i = base_uri.length();
return base_uri.substr(0, i) + relative_uri; std::string result{base_uri.substr(0, i)};
result.append(relative_uri);
return result;
} }
StringView relative_path{relative_uri};
const auto _base_path = uri_get_path(base_uri); const auto _base_path = uri_get_path(base_uri);
if (_base_path.data() == nullptr) { if (_base_path.data() == nullptr) {
std::string result(base_uri); std::string result(base_uri);
if (relative_uri.front() != '/') if (relative_path.front() != '/')
result.push_back('/'); result.push_back('/');
while (const char *a = StringAfterPrefix(relative_path, "./")) while (relative_path.SkipPrefix("./")) {}
relative_path = a; if (relative_path.StartsWith("../"))
if (StringStartsWith(relative_path, "../"))
return {}; return {};
if (!StringIsEqual(relative_path, ".")) if (!relative_path.Equals("."))
result += relative_path; result += relative_path;
return result; return result;
} }
......
/* /*
* Copyright 2008-2019 Max Kellermann <max.kellermann@gmail.com> * Copyright 2008-2021 Max Kellermann <max.kellermann@gmail.com>
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions * modification, are permitted provided that the following conditions
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#include "Compiler.h" #include "Compiler.h"
#include <string> #include <string>
#include <string_view>
/** /**
* Check whether #child specifies a resource "inside" the directory * Check whether #child specifies a resource "inside" the directory
...@@ -53,11 +54,11 @@ uri_is_child_or_same(const char *parent, const char *child) noexcept; ...@@ -53,11 +54,11 @@ uri_is_child_or_same(const char *parent, const char *child) noexcept;
*/ */
gcc_pure gcc_pure
std::string std::string
uri_apply_base(const std::string &uri, const std::string &base) noexcept; uri_apply_base(std::string_view uri, std::string_view base) noexcept;
gcc_pure gcc_pure
std::string std::string
uri_apply_relative(const std::string &relative_uri, uri_apply_relative(std::string_view relative_uri,
const std::string &base_uri) noexcept; std::string_view base_uri) noexcept;
#endif #endif
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment