add a splitFirst() function to PathFuncs

Summary:
Add a splitFirst() function that, if you think about a path as a linked list,
splits the head and the tail. Normally you could use the components
iterator, but split() is easier when the iteration is asynchronous and
requires lambda capture.

Reviewed By: pkaush

Differential Revision: D10154746

fbshipit-source-id: 6372a0bbde27f6596659ad1244cc96fa1f9eb6ff
This commit is contained in:
Chad Austin 2018-10-09 16:37:35 -07:00 committed by Facebook Github Bot
parent bf85e7ea15
commit d99eef5354
3 changed files with 44 additions and 5 deletions

View File

@ -245,6 +245,20 @@ AbsolutePath normalizeBestEffort(folly::StringPiece path) {
return normalizeBestEffort(path.str().c_str());
}
std::pair<PathComponentPiece, RelativePathPiece> splitFirst(
RelativePathPiece path) {
auto piece = path.stringPiece();
auto p = piece.find(kDirSeparator);
if (p != std::string::npos) {
return {PathComponentPiece{
folly::StringPiece{piece.begin(), piece.begin() + p}},
RelativePathPiece{
folly::StringPiece{piece.begin() + p + 1, piece.end()}}};
} else {
return {PathComponentPiece{piece}, RelativePathPiece{}};
}
}
void validatePathComponentLength(PathComponentPiece name) {
if (name.value().size() > kMaxPathComponentLength) {
folly::throwSystemErrorExplicit(

View File

@ -1051,7 +1051,7 @@ class RelativePathBase : public ComposedPathBase<
bool isParentDirOf(const RelativePathPiece& other) const {
return other.findParent(*this) != other.allPaths().end();
}
};
}; // namespace detail
/// Asserts that val is well formed absolute path
struct AbsolutePathSanityCheck {
@ -1179,8 +1179,9 @@ class AbsolutePathBase : public ComposedPathBase<
if (myIter != myPaths.end()) {
childIter++;
} else {
// We do not want to increment childIter here or else we will be missing
// a path component when we call remainder() after the while loop.
// We do not want to increment childIter here or else we will be
// missing a path component when we call remainder() after the while
// loop.
break;
}
}
@ -1233,8 +1234,8 @@ class AbsolutePathBase : public ComposedPathBase<
* An iterator over suffixes in a composed path.
*
* PathSuffixIterator always returns RelativePathPiece objects, even when
* iterating over an AbsolutePath. This is intentional, since the suffixes are
* relative to some other location inside the path.
* iterating over an AbsolutePath. This is intentional, since the suffixes
* are relative to some other location inside the path.
*
* For example, when iterating forwards over the path "foo/bar/baz", the
* iterator yields:
@ -1652,6 +1653,14 @@ normalizeBestEffort(const T& path) {
return normalizeBestEffort(path.c_str());
}
/**
* Splits a path into the first component and the remainder of the path.
* If the path has only one component, the remainder will be empty. If the
* path is empty, an exception is thrown.
*/
std::pair<PathComponentPiece, RelativePathPiece> splitFirst(
RelativePathPiece path);
/**
* Throws std::system_error with ENAMETOOLONG if the given PathComponent is
* longer than kMaxPathComponentLength.

View File

@ -515,6 +515,22 @@ TEST(PathFuncs, format) {
EXPECT_EQ("x(src/abc.def)", folly::sformat("x({})", relPiece));
}
TEST(PathFuncs, splitFirst) {
using SplitResult = decltype(splitFirst(std::declval<RelativePath>()));
RelativePath rp1{""};
EXPECT_THROW(splitFirst(rp1), std::domain_error);
RelativePath rp2{"foo"};
EXPECT_EQ((SplitResult{"foo", ""}), splitFirst(rp2));
RelativePath rp3{"foo/bar"};
EXPECT_EQ((SplitResult{"foo", "bar"}), splitFirst(rp3));
RelativePath rp4{"foo/bar/baz"};
EXPECT_EQ((SplitResult{"foo", "bar/baz"}), splitFirst(rp4));
}
namespace {
/*
* Helper class to create a temporary directory and cd into it while this