Manipulating Paths
Plywood provides the WindowsPath and PosixPath classes for manipulating filesystem paths. All member functions are static and accept StringView arguments:
PosixPath::join("path/to", "file"); // "path/to/file"
WindowsPath::split("path\\to\\file"); // {"path\\to", "file"}
Plywood also provides NativePath, a type alias for either WindowsPath or PosixPath depending on the target platform:
NativePath::join(PLY_WORKSPACE_FOLDER, "repos/plywood/docs");
You'll likely use NativePath most often, but there's nothing to stop you from using WindowsPath on POSIX or PosixPath on Windows.
The WindowsPath class recognizes both forward and backslash characters as path separators. Its join(), normalize() and makeRelative() functions normalize all path separators to backslashes.
The PosixPath class only treats forward slashes as path separators.
Neither of these classes interact with the filesystem in any way. These path manipulation functions operate purely on strings.
You can also manipulate paths indirectly using a PathFormat object, which can be obtained by calling format(). All WindowsPath and PosixPath member functions are static, and all PathFormat member functions are non-static.
Normalized Paths
The join(), normalize() and makeRelative() member functions all return normalized paths. A normalized path is one in which redundant path separators are collapsed, references to the current directory "." are discarded unless it is the only component, and references to the parent directory ".." collapse the parent directory if there is one. A normalized WindowsPath contains no forward slashes and uses only backslashes as path separators. An empty string is normalized to ".". Normalized paths may or may not include a trailing path separator; see each function for further details.
Unicode Support
UTF-8 is the preferred character encoding for paths, but for practical purposes, the only characters treated specially are / \ . : and ASCII letters. Therefore, these path functions work just as well with ISO 8859-1, Windows-1252 and pure ASCII strings.
The FileSystem functions, on the other hand, do expect UTF-8 strings.
See Unicode Support for more information.
Header File
#include <ply-runtime/filesystem/Path.h>
Also included from <ply-runtime/Base.h>.
Member Functions
static const char& sepByte()-
WindowsPathreturns a backslash.PosixPathreturns a forward slash. static bool isSepByte(char c)-
WindowsPathreturnstrueifcis a forward or backslash.PosixPathreturnstrueifcis a forward slash. static bool endsWithSep(StringView path)-
WindowsPathreturnstrueifpathends with a forward or backslash.PosixPathreturnstrueifpathends with a forward slash. static bool hasDriveLetter(StringView path)-
WindowsPathreturnstrueifpathbegins with a drive letter prefix such as"C:".PosixPathalways returnsfalse. static StringView getDriveLetter(StringView path)-
If
pathbegins with a drive letter such as"C:",WindowsPathreturns the drive letter including the colon.PosixPathalways returns an empty string. static bool isAbsolute(StringView path)-
WindowsPathreturnstrueifpathbegins with a drive letter and path separator.PosixPathreturnstrueifpathbegins with'/'.WindowsPath::isAbsolute("C:\\"); // true WindowsPath::isAbsolute("d:/my/path"); // true WindowsPath::isAbsolute("C:file"); // false WindowsPath::isAbsolute("\\my\\path"); // false PosixPath::isAbsolute("/my/path"); // trueAn empty string satisfies neither
isAbsolute()norisRelative(). ForWindowsPath, a path that begin with a drive letter or path separator only (such as"C:file"and"\\my\\path") satisfies neitherisAbsolute()norisRelative().You can make a path absolute using
FileSystem::getAbsolutePath(). static bool isRelative(StringView path)-
Returns
trueifpathis non-empty and does not begin with a drive letter or path separator.WindowsPath::isRelative("file"); // true WindowsPath::isRelative("my\\path"); // true WindowsPath::isRelative("C:file"); // false WindowsPath::isRelative("\\my\\path"); // false PosixPath::isRelative("my/path"); // trueAn empty string satisfies neither
isAbsolute()norisRelative(). ForWindowsPath, a path that begin with a drive letter or path separator only (such as"C:file"and"\\my\\path") satisfies neitherisAbsolute()norisRelative(). static Tuple<StringView, StringView> split(StringView path)-
Splits
pathinto aTuplewheresecondis the last path component andfirstis everything leading up to that. Similar toos.path.split()in Python.secondwill never contain a path separator; ifpathends with a path separator,secondwill be empty. If there is no path separator inpath,firstwill be empty. Trailing slashes are stripped fromfirstunless it is the root.WindowsPath::split()does not convert forward slashes to backslashes.PosixPath::split("path/to/file"); // {"path/to", "file"} PosixPath::split("path/to/folder/"); // {"path/to/folder", ""} PosixPath::split("/file_in_root"); // {"/", "file_in_root"} PosixPath::split("file"); // {"", "file"} WindowsPath::split("path\\to\\file"); // {"path\\to", "file"} WindowsPath::split("path/to/file"); // {"path/to", "file"} static Array<StringView> splitFull(StringView path)-
Splits
pathinto an array of items where each item contains a single path component. WhenWindowsPathis given an absolute path, it returns the drive letter and first path separator as the first component. WhenPosixPathis given an absolute path, it returns"/"as the first component. None of the other components contain a path separator. Ifpathends with a path separator, the last component is an empty string.PosixPath::splitFull("path/to/file"); // {"path", "to", "file"} PosixPath::splitFull("path/to/folder/"); // {"path", "to", "folder", ""} PosixPath::splitFull("/file_in_root"); // {"/", "file_in_root"} WindowsPath::splitFull("path\\to/file"); // {"path", "to", "file"} WindowsPath::splitFull("C:\\file_in_root"); // {"C:\\", "file_in_root"} static Tuple<StringView, StringView> splitExt(StringView path)-
Splits
pathinto aTuplesuch thatfirst + second == path, andsecondis empty or begins with a period and contains at most one period. Similar toos.path.splitext()in Python. Leading periods on the basename, as in".gitignore", are ignored.PosixPath::splitExt("file.txt"); // {"file", ".txt"} PosixPath::splitExt("file"); // {"file"} PosixPath::splitExt("file.tar.gz"); // {"file.tar", ".gz"} PosixPath::splitExt("path/to/file.txt"); // {"path/to/file", ".txt"} PosixPath::splitExt("folder.tmp/"); // {"folder.tmp/", ""} PosixPath::splitExt("folder.tmp/file"); // {"folder.tmp/file", ""} PosixPath::splitExt(".gitignore"); // {".gitignore", ""} PosixPath::splitExt("path/to/.gitignore"); // {"path/to/.gitignore", ""} static String join(components...)-
Joins one or more path components together and normalizes the result. Note that this function is not the same as
os.path.join()in Python. It's closer (but not identical) toos.path.normpath(os.path.join())in Python.The returned path has a trailing slash if and only if the last component has a trailing slash or is an empty string. If any argument is an absolute path, all previous arguments are thrown away except for any drive letter that was encountered. For
WindowsPath, if any argument contains a drive letter, all previous arguments are thrown away.PosixPath::join("path/to", "file"); // "path/to/file" PosixPath::join("path/to", "folder/"); // "path/to/folder/" PosixPath::join("path/to", "folder", ""); // "path/to/folder/" PosixPath::join("path/to", "./file"); // "path/to/file" PosixPath::join("path/to/file", "../other"); // "path/to/other" WindowsPath::join("C:\\", "bad/slash"); // "C:\\bad\\slash" static String normalize(components...)-
Equivalent to
join(). static bool isNormalized(StringView path)-
Equivalent to
path == normalize(path). static String makeRelative(StringView ancestor, StringView descendant)-
Returns a new path
relativesuch thatjoin(ancestor, relative)is equivalent todescendant. Ifancestoris an absolute path,descendantmust also be an absolute path, and ifancestoris a relative path,descendantmust also be a relative path. The returned path is normalized. The returned path has a trailing slash if and only ifdescendanthas a trailing slash.PosixPath::makeRelative("/path/to", "/path/to/file"); // "file" PosixPath::makeRelative("/path/to/", "/path/to/file"); // "file" PosixPath::makeRelative("/path/to", "/path/to/a/b"); // "a/b" PosixPath::makeRelative("/path/to/file", "/path/to/other"); // "../other" PosixPath::makeRelative("/path/to/file", "/path/to/other/"); // "../other/" PosixPath::makeRelative("path/to", "path/to"); // "." PosixPath::makeRelative("path/to/", "path/to"); // "." PosixPath::makeRelative("path/to", "path/to/"); // "./" static PathFormat format()-
Returns a
PathFormatobject that exposes the same functionality asWindowsPathorPosixPath, but using non-static member functions instead of static member functions. You can pass thePathFormatobject to other functions to perform platform-specific path manipulation indirectly. static HybridString from<SrcFormat>(StringView path)-
Converts the path separators in
path.PosixPath::from<WindowsPath>()converts all backslashes to forward slashes.WindowsPath::from<PosixPath>()andWindowsPath::from<WindowsPath>()convert all forward slashes to backslashes. Otherwise the returned string is identical.// Returns "path\\to\\file": WindowsPath::from<PosixPath>("path/to/file"); // Returns "C:/path/to/file": PosixPath::from<WindowsPath>("C:\\path\\to\\file"); static HybridString from(const PathFormat& srcFormat, StringView path)-
Same as the previous function, but the source format is determined by function argument instead of template argument.
// Returns "path\\to\\file": WindowsPath::from(PosixPath::format(), "path/to/file"); // Returns "C:/path/to/file": PosixPath::from(WindowsPath::format(), "C:\\path\\to\\file");