Loading services/incremental/path.cpp +8 −7 Original line number Diff line number Diff line Loading @@ -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() == '/') { 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; } Loading services/incremental/path.h +15 −5 Original line number Diff line number Diff line Loading @@ -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 services/incremental/test/path_test.cpp +20 −0 Original line number Diff line number Diff line Loading @@ -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 Loading
services/incremental/path.cpp +8 −7 Original line number Diff line number Diff line Loading @@ -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() == '/') { 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; } Loading
services/incremental/path.h +15 −5 Original line number Diff line number Diff line Loading @@ -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
services/incremental/test/path_test.cpp +20 −0 Original line number Diff line number Diff line Loading @@ -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