Merge "[incfs] Optimize path::join for appending" into sc-dev

This commit is contained in:
Yurii Zubrytskyi
2021-03-23 23:09:05 +00:00
committed by Android (Google) Code Review
3 changed files with 43 additions and 12 deletions

View File

@@ -44,19 +44,20 @@ bool PathLess::operator()(std::string_view l, std::string_view r) const {
PathCharsLess());
}
static void preparePathComponent(std::string_view& path, bool trimFront) {
if (trimFront) {
while (!path.empty() && path.front() == '/') {
path.remove_prefix(1);
}
static void preparePathComponent(std::string_view& path, bool trimAll) {
// need to check for double front slash as a single one has a separate meaning in front
while (!path.empty() && path.front() == '/' &&
(trimAll || (path.size() > 1 && path[1] == '/'))) {
path.remove_prefix(1);
}
while (!path.empty() && path.back() == '/') {
// for the back we don't care about double-vs-single slash difference
while (path.size() > !trimAll && path.back() == '/') {
path.remove_suffix(1);
}
}
void details::append_next_path(std::string& target, std::string_view path) {
preparePathComponent(path, true);
preparePathComponent(path, !target.empty());
if (path.empty()) {
return;
}

View File

@@ -89,15 +89,25 @@ std::optional<bool> isEmptyDir(std::string_view dir);
bool startsWith(std::string_view path, std::string_view prefix);
template <class... Paths>
std::string join(std::string_view first, std::string_view second, Paths&&... paths) {
std::string result;
std::string join(std::string&& first, std::string_view second, Paths&&... paths) {
std::string& result = first;
{
using std::size;
result.reserve(first.size() + second.size() + 1 + (sizeof...(paths) + ... + size(paths)));
}
result.assign(first);
(details::append_next_path(result, second), ..., details::append_next_path(result, paths));
return result;
(details::append_next_path(result, second), ...,
details::append_next_path(result, std::forward<Paths>(paths)));
return std::move(result);
}
template <class... Paths>
std::string join(std::string_view first, std::string_view second, Paths&&... paths) {
return path::join(std::string(), first, second, std::forward<Paths>(paths)...);
}
template <class... Paths>
std::string join(const char* first, std::string_view second, Paths&&... paths) {
return path::join(std::string_view(first), second, std::forward<Paths>(paths)...);
}
} // namespace android::incremental::path

View File

@@ -40,4 +40,24 @@ TEST(Path, Comparator) {
EXPECT_TRUE(!PathLess()("/a/b", "/a"));
}
TEST(Path, Join) {
EXPECT_STREQ("", path::join("", "").c_str());
EXPECT_STREQ("/", path::join("", "/").c_str());
EXPECT_STREQ("/", path::join("/", "").c_str());
EXPECT_STREQ("/", path::join("/", "/").c_str());
EXPECT_STREQ("/", path::join("/"s, "/").c_str());
EXPECT_STREQ("/", path::join("/"sv, "/").c_str());
EXPECT_STREQ("/", path::join("/", "/", "/", "/", "/", "/", "/", "/", "/", "/").c_str());
EXPECT_STREQ("/a/b/c/d", path::join("/a/b/"s, "c", "d").c_str());
EXPECT_STREQ("/a/b/c/d", path::join("/a/b/", "c", "d").c_str());
EXPECT_STREQ("/a/b/c/d", path::join("/", "a/b/", "c", "d").c_str());
EXPECT_STREQ("/a/b/c/d", path::join("/", "a/b", "c", "d").c_str());
EXPECT_STREQ("/a/b/c/d", path::join("/", "//a/b//", "c", "d").c_str());
EXPECT_STREQ("/a/b/c/d", path::join("", "", "/", "//a/b//", "c", "d").c_str());
EXPECT_STREQ("/a/b/c/d", path::join(""s, "", "/", "//a/b//", "c", "d").c_str());
EXPECT_STREQ("/a/b/c/d", path::join("/a/b", "", "", "/", "", "/", "/", "/c", "d").c_str());
}
} // namespace android::incremental::path