API Reference
This page summarizes the public API of the Path module. It is meant for quick lookup while writing or reviewing code. For the design model and workflow, start with the overview, quick start, and topic pages in this section.
Header
Use the public Path header in application and module code:
#include <vix/path.hpp>All public APIs are declared in the vix::path namespace.
namespace vix::path
{
}The module is lexical. It transforms and analyzes path strings without accessing the real filesystem.
Result types
Path operations that can fail return Vix results.
using PathResult = vix::error::Result<std::string>;
using PathListResult = vix::error::Result<std::vector<std::string>>;
using PathPartsResult = vix::error::Result<PathParts>;PathResult is used by operations that return one path string. PathListResult is reserved for operations that return multiple path segments. PathPartsResult is used by split().
auto path = vix::path::normalize("src/./main.cpp");
if (!path) {
return path.error();
}
std::string value = path.value();A failed result contains a structured vix::error::Error.
PathStyle
enum class PathStyle
{
Native,
Posix,
Windows
};PathStyle controls the syntax rules used by path operations.
Native follows the current platform. Posix uses POSIX-style output and prefers /. Windows uses Windows-style output, prefers \, and recognizes Windows drive roots and UNC-style roots.
vix::path::PathOptions options;
options.style = vix::path::PathStyle::Posix;PathOptions
struct PathOptions
{
PathStyle style{PathStyle::Native};
bool collapse_separators{true};
bool remove_dot_segments{true};
bool resolve_dot_dot_segments{true};
bool preserve_trailing_separator{false};
};PathOptions controls lexical path transformations.
style selects native, POSIX, or Windows rules. remove_dot_segments controls whether . segments are removed. resolve_dot_dot_segments controls whether .. segments are resolved when possible. preserve_trailing_separator keeps a trailing separator only when the input path already had one.
collapse_separators is part of the public options model. In the current implementation, normalization rebuilds paths from parsed segments and produces clean separator output, so code should not rely on setting collapse_separators to false to preserve repeated separators.
PathParts
struct PathParts
{
std::string root;
std::string dirname;
std::string filename;
std::string stem;
std::string extension;
};PathParts is returned by split().
root stores the detected root portion. dirname stores the directory portion without the final filename. filename stores the final filename component. stem stores the filename without its final extension. extension stores the final extension, including the leading dot when present.
auto parts = vix::path::split("/home/user/main.cpp");
if (!parts) {
return parts.error();
}
// parts.value().root == "/"
// parts.value().dirname == "/home/user"
// parts.value().filename == "main.cpp"
// parts.value().stem == "main"
// parts.value().extension == ".cpp"PathErrorCode
enum class PathErrorCode
{
None = 0,
EmptyPath,
InvalidPath,
InvalidSegment,
InvalidRoot,
IncompatibleRoots,
CannotComputeRelative,
TraversalAboveRoot
};PathErrorCode describes lexical path failures.
These are path-level errors, not filesystem errors. They describe invalid path input, incompatible roots, and invalid lexical traversal.
path_error_category
[[nodiscard]] constexpr vix::error::ErrorCategory
path_error_category() noexcept;Returns the default Path error category.
auto category = vix::path::path_error_category();
// category.name() == "path"to_error_code
[[nodiscard]] constexpr vix::error::ErrorCode
to_error_code(PathErrorCode code) noexcept;Converts a PathErrorCode into the shared Vix ErrorCode model.
All current path-specific failures map to vix::error::ErrorCode::InvalidArgument, except PathErrorCode::None, which maps to Ok.
auto code = vix::path::to_error_code(
vix::path::PathErrorCode::EmptyPath
);to_string
[[nodiscard]] const char* to_string(PathErrorCode code) noexcept;Returns a stable string name for a path error code.
const char* name = vix::path::to_string(
vix::path::PathErrorCode::IncompatibleRoots
);
// name == "incompatible_roots"make_path_error
[[nodiscard]] vix::error::Error make_path_error(
PathErrorCode code,
std::string message
);Builds a structured vix::error::Error using the converted shared error code, the path category, and the provided message.
return vix::path::make_path_error(
vix::path::PathErrorCode::InvalidPath,
"expected a project-relative path"
);Separator helpers
preferred_separator
[[nodiscard]] char preferred_separator(
PathStyle style = PathStyle::Native
) noexcept;Returns the preferred separator for a path style.
char sep = vix::path::preferred_separator(
vix::path::PathStyle::Posix
);
// sep == '/'For PathStyle::Windows, the result is \. For PathStyle::Native, the result depends on the current platform.
is_separator
[[nodiscard]] constexpr bool is_separator(char c) noexcept;Returns true when the character is a recognized path separator.
bool slash = vix::path::is_separator('/');
bool backslash = vix::path::is_separator('\\');
bool regular = vix::path::is_separator('x');Both / and \ are treated as separators for lexical path processing.
has_leading_separator
[[nodiscard]] bool has_leading_separator(
std::string_view path
) noexcept;Returns true when the path starts with a separator.
bool leading = vix::path::has_leading_separator("/tmp");has_trailing_separator
[[nodiscard]] bool has_trailing_separator(
std::string_view path
) noexcept;Returns true when the path ends with a separator.
bool trailing = vix::path::has_trailing_separator("/tmp/");These helpers are lexical checks. They do not determine whether the path is a real directory.
Path checks
is_absolute
[[nodiscard]] bool is_absolute(
std::string_view path,
PathStyle style = PathStyle::Native
) noexcept;Returns true when the path is lexically absolute for the selected style.
bool absolute = vix::path::is_absolute(
"/usr/bin",
vix::path::PathStyle::Posix
);With Windows style, drive-root paths and UNC-style roots are recognized.
bool drive = vix::path::is_absolute(
"C:\\Windows",
vix::path::PathStyle::Windows
);is_relative
[[nodiscard]] bool is_relative(
std::string_view path,
PathStyle style = PathStyle::Native
) noexcept;Returns true when the path is lexically relative for the selected style.
bool relative = vix::path::is_relative(
"docs/readme.md",
vix::path::PathStyle::Posix
);is_relative() is the opposite of is_absolute().
Joining and normalization
join
[[nodiscard]] PathResult join(
std::string_view left,
std::string_view right,
const PathOptions& options = {}
);
[[nodiscard]] PathResult join(
std::string_view a,
std::string_view b,
std::string_view c,
const PathOptions& options = {}
);Joins two or three path fragments using lexical rules, then normalizes the result.
vix::path::PathOptions options;
options.style = vix::path::PathStyle::Posix;
auto path = vix::path::join("/usr/", "/bin", options);
// path.value() == "/usr/bin"If one side is empty, the non-empty side is normalized and returned. If both sides are empty, the function returns a path error.
normalize
[[nodiscard]] PathResult normalize(
std::string_view path,
const PathOptions& options = {}
);Normalizes a path lexically.
vix::path::PathOptions options;
options.style = vix::path::PathStyle::Posix;
auto path = vix::path::normalize(
"/a//b/./c/../d",
options
);
// path.value() == "/a/b/d"Normalization may collapse repeated separators, remove . segments, resolve .. segments when possible, and rebuild the path with the preferred separator for the selected style.
The function returns an error when the path is empty or when resolving .. would move above an absolute root.
lexically_normal
[[nodiscard]] PathResult lexically_normal(
std::string_view path,
const PathOptions& options = {}
);Returns the lexically normal form of a path.
vix::path::PathOptions options;
options.style = vix::path::PathStyle::Posix;
auto path = vix::path::lexically_normal(
"/x//y/./z/../a",
options
);
// path.value() == "/x/y/a"lexically_normal() delegates to normalize().
Components
filename
[[nodiscard]] PathResult filename(std::string_view path);Returns the final filename component of a path.
auto name = vix::path::filename("/home/user/main.cpp");
// name.value() == "main.cpp"The function removes trailing separators before extracting the final component. An empty path returns a path error.
basename
[[nodiscard]] PathResult basename(std::string_view path);Returns the basename of a path.
auto base = vix::path::basename("/var/log/system.log");
// base.value() == "system.log"In this module, basename() is equivalent to filename().
parent
[[nodiscard]] PathResult parent(std::string_view path);Returns the parent path.
auto dir = vix::path::parent("/home/user/main.cpp");
// dir.value() == "/home/user"When there is no parent component, the function succeeds with an empty string. An empty input path returns a path error.
dirname
[[nodiscard]] PathResult dirname(std::string_view path);Returns the directory portion of a path.
auto dir = vix::path::dirname("/var/log/system.log");
// dir.value() == "/var/log"In this module, dirname() is equivalent to parent().
stem
[[nodiscard]] PathResult stem(std::string_view path);Returns the filename without its final extension.
auto st = vix::path::stem("/home/user/main.cpp");
// st.value() == "main"If the filename has no extension, the filename is returned unchanged. Special names such as . and .. are preserved.
extension
[[nodiscard]] PathResult extension(std::string_view path);Returns the final extension of a path, including the leading dot.
auto ext = vix::path::extension("/home/user/main.cpp");
// ext.value() == ".cpp"If the filename has no extension, the function succeeds with an empty string. A leading dot alone does not count as a normal extension, so .env has no extension under this rule.
has_extension
[[nodiscard]] bool has_extension(std::string_view path) noexcept;Returns true when the final filename component has an extension.
bool has = vix::path::has_extension("/home/user/main.cpp");
// has == truebool has = vix::path::has_extension("/home/user/Makefile");
// has == falseIf the path cannot produce a valid filename, the function returns false.
replace_extension
[[nodiscard]] PathResult replace_extension(
std::string_view path,
std::string_view new_extension
);Replaces the final extension of a path.
auto path = vix::path::replace_extension(
"/home/user/main.cpp",
"hpp"
);
// path.value() == "/home/user/main.hpp"If new_extension is non-empty and does not start with ., the module adds one. If the path has no extension, the new extension is appended. If new_extension is empty, the existing extension is removed.
split
[[nodiscard]] PathPartsResult split(std::string_view path);Splits a path into structured components.
auto parts = vix::path::split("/home/user/main.cpp");
if (!parts) {
return parts.error();
}
// parts.value().root == "/"
// parts.value().dirname == "/home/user"
// parts.value().filename == "main.cpp"
// parts.value().stem == "main"
// parts.value().extension == ".cpp"An empty path returns a path error.
Absolute and relative paths
absolute
[[nodiscard]] PathResult absolute(
std::string_view path,
std::string_view base,
const PathOptions& options = {}
);Resolves a path to an absolute lexical path using a base path.
vix::path::PathOptions options;
options.style = vix::path::PathStyle::Posix;
auto path = vix::path::absolute(
"docs/readme.md",
"/home/gaspard",
options
);
// path.value() == "/home/gaspard/docs/readme.md"If path is already absolute, it is normalized and returned. If path is relative, base must be non-empty and absolute for the selected style.
The function does not access the filesystem.
relative
[[nodiscard]] PathResult relative(
std::string_view target,
std::string_view base,
const PathOptions& options = {}
);Computes a lexical relative path from base to target.
vix::path::PathOptions options;
options.style = vix::path::PathStyle::Posix;
auto path = vix::path::relative(
"/home/gaspard/docs/readme.md",
"/home/gaspard",
options
);
// path.value() == "docs/readme.md"relative() delegates to lexically_relative().
lexically_relative
[[nodiscard]] PathResult lexically_relative(
std::string_view target,
std::string_view base,
const PathOptions& options = {}
);Computes a relative path by normalizing both paths, comparing their path segments, and producing a lexical route from base to target.
vix::path::PathOptions options;
options.style = vix::path::PathStyle::Posix;
auto path = vix::path::lexically_relative(
"/a/b/c/file.txt",
"/a/b/d",
options
);
// path.value() == "../c/file.txt"If the target and base have incompatible roots, the function returns a path error.
When both paths normalize to the same location, the result is ".".
lexically_proximate
[[nodiscard]] PathResult lexically_proximate(
std::string_view target,
std::string_view base,
const PathOptions& options = {}
);Computes a lexical relative path when possible. If that cannot be done, the function returns the normalized target path.
vix::path::PathOptions options;
options.style = vix::path::PathStyle::Windows;
auto path = vix::path::lexically_proximate(
"D:\\docs\\file.txt",
"C:\\base",
options
);
// path.value() == "D:\\docs\\file.txt"This is useful when a relative display path is preferred but not required.
Minimal example
#include <iostream>
#include <vix/path.hpp>
int main()
{
vix::path::PathOptions options;
options.style = vix::path::PathStyle::Posix;
auto joined = vix::path::join(
"/home/gaspard/project/",
"./src//main.cpp",
options
);
if (!joined) {
std::cerr << joined.error().message() << '\n';
return 1;
}
auto header = vix::path::replace_extension(
joined.value(),
"hpp"
);
if (!header) {
std::cerr << header.error().message() << '\n';
return 1;
}
auto display = vix::path::relative(
header.value(),
"/home/gaspard/project",
options
);
if (!display) {
std::cerr << display.error().message() << '\n';
return 1;
}
std::cout << display.value() << '\n';
return 0;
}This example only prepares path strings. It does not check whether the paths exist and it does not perform filesystem operations.
This completes the Path module reference.