summaryrefslogtreecommitdiffstats
path: root/include/raul/Path.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'include/raul/Path.hpp')
-rw-r--r--include/raul/Path.hpp359
1 files changed, 188 insertions, 171 deletions
diff --git a/include/raul/Path.hpp b/include/raul/Path.hpp
index f455049..8da985a 100644
--- a/include/raul/Path.hpp
+++ b/include/raul/Path.hpp
@@ -32,178 +32,195 @@ namespace Raul {
*
* @ingroup raul
*/
-class Path : public std::basic_string<char> {
+class Path : public std::basic_string<char>
+{
public:
- /** Attempt to construct an invalid Path. */
- class BadPath : public Exception {
- public:
- explicit BadPath(const std::string& path) : Exception(path) {}
- };
-
- /** Construct an uninitialzed path, because the STL is annoying. */
- Path() : std::basic_string<char>("/") {}
-
- /** Construct a Path from a C++ string.
- *
- * This will throw an exception if `path` is invalid. To avoid this, use
- * is_valid() first to check.
- */
- explicit Path(const std::basic_string<char>& path)
- : std::basic_string<char>(path)
- {
- if (!is_valid(path)) {
- throw BadPath(path);
- }
- }
-
- /** Construct a Path from a C string.
- *
- * This will throw an exception if `path` is invalid. To avoid this, use
- * is_valid() first to check.
- */
- explicit Path(const char* path)
- : std::basic_string<char>(path)
- {
- if (!is_valid(path)) {
- throw BadPath(path);
- }
- }
-
- Path(const Path& path) = default;
- Path& operator=(const Path& path) = default;
-
- Path(Path&& path) = default;
- Path& operator=(Path&& path) = default;
-
- ~Path() = default;
-
- /** Return true iff `c` is a valid Path character. */
- static inline bool is_valid_char(char c) {
- return c == '/' || Symbol::is_valid_char(c);
- }
-
- /** Return true iff `str` is a valid Path. */
- static inline bool is_valid(const std::basic_string<char>& str) {
- if (str.empty() || (str[0] != '/')) {
- return false; // Must start with '/'
- }
-
- if (str != "/" && *str.rbegin() == '/') {
- return false; // Must not end with '/' except for the root
- }
-
- for (size_t i = 1; i < str.length(); ++i) {
- if (!is_valid_char(str[i])) {
- return false; // All characters must be /, _, a-z, A-Z, 0-9
- }
-
- if (str[i - 1] == '/') {
- if (str[i] == '/') {
- return false; // Must not contain "//"
- }
-
- if (!Symbol::is_valid_start_char(str[i])) {
- return false; // Invalid symbol start character (digit)
- }
- }
- }
-
- return true;
- }
-
- /** Return true iff this path is the root path ("/"). */
- inline bool is_root() const { return *this == "/"; }
-
- /** Return true iff this path is a child of `parent` at any depth. */
- inline bool is_child_of(const Path& parent) const {
- const std::string parent_base = parent.base();
- return substr(0, parent_base.length()) == parent_base;
- }
-
- /** Return true iff this path is a parent of `child` at any depth. */
- inline bool is_parent_of(const Path& child) const {
- return child.is_child_of(*this);
- }
-
- /** Return the symbol of this path (everything after the last '/').
- *
- * This is what is called the "basename" for file paths, the "method name"
- * for OSC paths, and so on. Since the root path does not have a symbol,
- * this does not return a Raul::Symbol but may return the empty string.
- */
- inline const char* symbol() const {
- if (!is_root()) {
- const size_t last_sep = rfind('/');
- if (last_sep != std::string::npos) {
- return c_str() + last_sep + 1;
- }
- }
- return "";
- }
-
- /** Return the parent's path.
- *
- * Calling this on the path "/" will return "/".
- * This is the (deepest) "container path" for OSC paths.
- */
- inline Path parent() const {
- if (is_root()) {
- return *this;
- }
-
- const size_t first_sep = find('/');
- const size_t last_sep = find_last_of('/');
- return (first_sep == last_sep) ? Path("/") : Path(substr(0, last_sep));
- }
-
- /** Return a child Path of this path. */
- inline Path child(const Path& p) const {
- return p.is_root() ? *this : Path(base() + p.substr(1));
- }
-
- /** Return a direct child Path of this Path with the given Symbol. */
- inline Path child(const Raul::Symbol& symbol) const {
- return Path(base() + symbol.c_str());
- }
-
- /** Return path with a trailing "/".
- *
- * The returned string is such that appending a valid Symbol to it is
- * guaranteed to form a valid path.
- */
- inline std::string base() const {
- if (is_root()) {
- return *this;
- }
-
- return *this + '/';
- }
-
- /** Return the lowest common ancestor of a and b. */
- static inline Path lca(const Path& a, const Path& b) {
- const size_t len = std::min(a.length(), b.length());
- size_t last_sep = 0;
- for (size_t i = 0; i < len; ++i) {
- if (a[i] == '/' && b[i] == '/') {
- last_sep = i;
- }
- if (a[i] != b[i]) {
- break;
- }
- }
-
- if (last_sep <= 1) {
- return Path("/");
- }
-
- return Path(a.substr(0, last_sep));
- }
-
- /** Return true iff `child` is equal to, or a descendant of `parent`. */
- static inline bool descendant_comparator(const Path& parent,
- const Path& child) {
- return (child == parent || child.is_child_of(parent));
- }
+ /** Attempt to construct an invalid Path. */
+ class BadPath : public Exception
+ {
+ public:
+ explicit BadPath(const std::string& path)
+ : Exception(path)
+ {}
+ };
+
+ /** Construct an uninitialzed path, because the STL is annoying. */
+ Path()
+ : std::basic_string<char>("/")
+ {}
+
+ /** Construct a Path from a C++ string.
+ *
+ * This will throw an exception if `path` is invalid. To avoid this, use
+ * is_valid() first to check.
+ */
+ explicit Path(const std::basic_string<char>& path)
+ : std::basic_string<char>(path)
+ {
+ if (!is_valid(path)) {
+ throw BadPath(path);
+ }
+ }
+
+ /** Construct a Path from a C string.
+ *
+ * This will throw an exception if `path` is invalid. To avoid this, use
+ * is_valid() first to check.
+ */
+ explicit Path(const char* path)
+ : std::basic_string<char>(path)
+ {
+ if (!is_valid(path)) {
+ throw BadPath(path);
+ }
+ }
+
+ Path(const Path& path) = default;
+ Path& operator=(const Path& path) = default;
+
+ Path(Path&& path) = default;
+ Path& operator=(Path&& path) = default;
+
+ ~Path() = default;
+
+ /** Return true iff `c` is a valid Path character. */
+ static inline bool is_valid_char(char c)
+ {
+ return c == '/' || Symbol::is_valid_char(c);
+ }
+
+ /** Return true iff `str` is a valid Path. */
+ static inline bool is_valid(const std::basic_string<char>& str)
+ {
+ if (str.empty() || (str[0] != '/')) {
+ return false; // Must start with '/'
+ }
+
+ if (str != "/" && *str.rbegin() == '/') {
+ return false; // Must not end with '/' except for the root
+ }
+
+ for (size_t i = 1; i < str.length(); ++i) {
+ if (!is_valid_char(str[i])) {
+ return false; // All characters must be /, _, a-z, A-Z, 0-9
+ }
+
+ if (str[i - 1] == '/') {
+ if (str[i] == '/') {
+ return false; // Must not contain "//"
+ }
+
+ if (!Symbol::is_valid_start_char(str[i])) {
+ return false; // Invalid symbol start character (digit)
+ }
+ }
+ }
+
+ return true;
+ }
+
+ /** Return true iff this path is the root path ("/"). */
+ inline bool is_root() const { return *this == "/"; }
+
+ /** Return true iff this path is a child of `parent` at any depth. */
+ inline bool is_child_of(const Path& parent) const
+ {
+ const std::string parent_base = parent.base();
+ return substr(0, parent_base.length()) == parent_base;
+ }
+
+ /** Return true iff this path is a parent of `child` at any depth. */
+ inline bool is_parent_of(const Path& child) const
+ {
+ return child.is_child_of(*this);
+ }
+
+ /** Return the symbol of this path (everything after the last '/').
+ *
+ * This is what is called the "basename" for file paths, the "method name"
+ * for OSC paths, and so on. Since the root path does not have a symbol,
+ * this does not return a Raul::Symbol but may return the empty string.
+ */
+ inline const char* symbol() const
+ {
+ if (!is_root()) {
+ const size_t last_sep = rfind('/');
+ if (last_sep != std::string::npos) {
+ return c_str() + last_sep + 1;
+ }
+ }
+ return "";
+ }
+
+ /** Return the parent's path.
+ *
+ * Calling this on the path "/" will return "/".
+ * This is the (deepest) "container path" for OSC paths.
+ */
+ inline Path parent() const
+ {
+ if (is_root()) {
+ return *this;
+ }
+
+ const size_t first_sep = find('/');
+ const size_t last_sep = find_last_of('/');
+ return (first_sep == last_sep) ? Path("/") : Path(substr(0, last_sep));
+ }
+
+ /** Return a child Path of this path. */
+ inline Path child(const Path& p) const
+ {
+ return p.is_root() ? *this : Path(base() + p.substr(1));
+ }
+
+ /** Return a direct child Path of this Path with the given Symbol. */
+ inline Path child(const Raul::Symbol& symbol) const
+ {
+ return Path(base() + symbol.c_str());
+ }
+
+ /** Return path with a trailing "/".
+ *
+ * The returned string is such that appending a valid Symbol to it is
+ * guaranteed to form a valid path.
+ */
+ inline std::string base() const
+ {
+ if (is_root()) {
+ return *this;
+ }
+
+ return *this + '/';
+ }
+
+ /** Return the lowest common ancestor of a and b. */
+ static inline Path lca(const Path& a, const Path& b)
+ {
+ const size_t len = std::min(a.length(), b.length());
+ size_t last_sep = 0;
+ for (size_t i = 0; i < len; ++i) {
+ if (a[i] == '/' && b[i] == '/') {
+ last_sep = i;
+ }
+ if (a[i] != b[i]) {
+ break;
+ }
+ }
+
+ if (last_sep <= 1) {
+ return Path("/");
+ }
+
+ return Path(a.substr(0, last_sep));
+ }
+
+ /** Return true iff `child` is equal to, or a descendant of `parent`. */
+ static inline bool descendant_comparator(const Path& parent,
+ const Path& child)
+ {
+ return (child == parent || child.is_child_of(parent));
+ }
};
} // namespace Raul