summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--raul/Path.hpp130
-rw-r--r--raul/Symbol.hpp3
-rw-r--r--raul/URI.hpp25
-rw-r--r--src/Path.cpp85
4 files changed, 99 insertions, 144 deletions
diff --git a/raul/Path.hpp b/raul/Path.hpp
index 7404877..57bed80 100644
--- a/raul/Path.hpp
+++ b/raul/Path.hpp
@@ -20,27 +20,25 @@
#include <cassert>
#include <cctype>
#include <cstring>
+#include <exception>
#include <string>
#include "raul/Symbol.hpp"
-#include "raul/URI.hpp"
namespace Raul {
-/** A URI which is a path (for example a filesystem or OSC path).
+/** A restricted path of Symbols separated by, and beginning with, "/".
*
* This enforces that a Path is a valid path, where each fragment is a valid
* Symbol, separated by exactly one slash (/).
*
* A path is divided by slashes (/). The first character MUST be a slash, and
* the last character MUST NOT be a slash (except in the special case of the
- * root path "/", which is the only valid single-character path). A Path
- * is actually a URI, the relative path is appended to the root URI
- * automatically, so a Patch can always be used as a URI.
+ * root path "/", which is the only valid single-character path).
*
* \ingroup raul
*/
-class Path : public URI {
+class Path {
public:
class BadPath : public std::exception {
public:
@@ -51,79 +49,59 @@ public:
const std::string _path;
};
- /** Return the root path.
- * The default root path is the URI "path:/"
- *
- * A Path is either the root path, or a child of a root path (i.e. the root
- * path followed by a sequence of Symbols separated by '/')
- */
- static const Path root();
-
- /** Set the root path.
- * The default root path is the URI "path:/"
- *
- * Note this should be done on application start up. Changing the root
- * path while any Path objects exist will break things horribly; don't!
- *
- * The root can be set to any URI, there are no restrictions on valid
- * characters and such like there are for relative paths (but it must be
- * a valid URI, i.e. begin with a scheme, and in particular not begin
- * with '/'). Relative paths are appended to the root path's URI,
- * i.e. every Path, as a string, begins with the root URI. The part after
- * that is a strict path (a sequence of Symbols separated by '/').
- */
- static void set_root(const Raul::URI& uri);
-
- static bool is_path(const Raul::URI& uri);
-
/** Construct an uninitialzed path, because the STL is annoying. */
- Path() : URI(root()) {}
+ Path() : _str(g_intern_string("/")) {}
/** Construct a Path from an std::string.
*
* It is a fatal error to construct a Path from an invalid string,
* use is_valid first to check.
*/
- Path(const std::basic_string<char>& path);
+ Path(const std::basic_string<char>& path) throw (BadPath)
+ : _str(g_intern_string(path.c_str()))
+ {
+ if (!is_valid(path)) {
+ throw BadPath(path);
+ }
+ }
/** Construct a Path from a C string.
*
* It is a fatal error to construct a Path from an invalid string,
* use is_valid first to check.
*/
- Path(const char* cpath);
+ Path(const char* cpath) throw(BadPath)
+ : _str(g_intern_string(cpath))
+ {
+ if (!is_valid(cpath)) {
+ throw BadPath(cpath);
+ }
+ }
/** Construct a Path from another path.
*
* This is faster than constructing a path from the other path's string
* representation, since validity checking is avoided.
*/
- Path(const Path& copy) : URI(copy) {}
+ Path& operator=(const Path& other) {
+ _str = other._str;
+ return *this;
+ }
static bool is_valid(const std::basic_string<char>& path);
- static std::string pathify(const std::basic_string<char>& str);
+ /** Convert a string to a valid Path. */
+ static Path pathify(const std::basic_string<char>& str);
static void replace_invalid_chars(std::string& str,
size_t start,
bool replace_slash = false);
- bool is_root() const { return (*this) == root(); }
+ bool is_root() const { return !strcmp(_str, "/"); }
bool is_child_of(const Path& parent) const;
bool is_parent_of(const Path& child) const;
- Path child(const std::string& s) const {
- if (is_valid(s))
- return base() + Path(s).chop_scheme().substr(1);
- else
- return base() + s;
- }
-
- Path child(const Path& p) const {
- return base() + p.chop_scheme().substr(1);
- }
-
Path operator+(const Path& p) const { return child(p); }
/** Return the lowest common ancestor of a and b. */
@@ -135,7 +113,7 @@ public:
* The empty string may be returned (if the path is the root path).
*/
inline const char* symbol() const {
- if ((*this) != root()) {
+ if (!is_root()) {
const char* last_slash = strrchr(c_str(), '/');
if (last_slash) {
return last_slash + 1;
@@ -150,16 +128,20 @@ public:
* This is the (deepest) "container path" for OSC paths.
*/
inline Path parent() const {
- if ((*this) == root()) {
+ if (is_root()) {
return *this;
} else {
const std::string str(this->str());
const size_t first_slash = str.find('/');
const size_t last_slash = str.find_last_of('/');
- return (first_slash == last_slash) ? root() : str.substr(0, last_slash);
+ return (first_slash == last_slash) ? Path("/") : str.substr(0, last_slash);
}
}
+ Path child(const Path& p) const {
+ return base() + p.str().substr(1);
+ }
+
/** Return the path's child with the given symbol
*/
inline Path child(const Raul::Symbol& symbol) const {
@@ -173,7 +155,7 @@ public:
return "/";
} else {
assert(length() > base.base().length());
- return substr(base.base().length() - 1);
+ return str().substr(base.base().length() - 1);
}
}
@@ -184,32 +166,48 @@ public:
*/
inline const std::string base() const {
std::string ret = str();
- if ((*this) == root() && ret[ret.length() - 1] == '/')
+ if (is_root() && ret[ret.length() - 1] == '/')
return ret;
else
return ret + '/';
}
- /** Return path with a trailing "/".
- *
- * Returned value is guaranteed to be a valid parent path, i.e. a valid
- * child path can be made using parent.base() + symbol.
- */
- inline const std::string base_no_scheme() const {
- return base().substr(find(":") + 1);
- }
-
/** Return true if \a child is equal to, or a descendant of \a parent */
static bool descendant_comparator(const Path& parent, const Path& child) {
- return ( child == parent || (child.length() > parent.length() &&
- (!std::strncmp(parent.c_str(), child.c_str(), parent.length())
- && (parent == root() || child.str()[parent.length()] == '/'))) );
+ return (child == parent ||
+ (child.length() > parent.length() &&
+ (!std::strncmp(parent.c_str(), child.c_str(), parent.length())
+ && (parent.is_root() || child.str()[parent.length()] == '/'))) );
}
+ inline std::string substr(size_t start, size_t end=std::string::npos) const {
+ return str().substr(start, end);
+ }
+
+ inline bool operator<(const Path& path) const { return strcmp(_str, path.c_str()) < 0; }
+ inline bool operator<=(const Path& path) const { return (*this) == path || (*this) < path; }
+ inline bool operator==(const Path& path) const { return _str == path._str; }
+ inline bool operator!=(const Path& path) const { return _str != path._str; }
+
+ inline char operator[](int i) const { return _str[i]; }
+
+ inline size_t length() const { return str().length(); }
+ inline size_t find(const std::string& s) const { return str().find(s); }
+
+ inline const std::string str() const { return _str; }
+ inline const char* c_str() const { return _str; }
+
private:
- inline Path(bool unchecked, const URI& uri) : URI(uri) {}
+ const char* _str;
};
} // namespace Raul
+static inline
+std::ostream&
+operator<<(std::ostream& os, const Raul::Path& path)
+{
+ return (os << path.c_str());
+}
+
#endif // RAUL_PATH_HPP
diff --git a/raul/Symbol.hpp b/raul/Symbol.hpp
index b872e3a..dcf1f04 100644
--- a/raul/Symbol.hpp
+++ b/raul/Symbol.hpp
@@ -104,7 +104,8 @@ private:
} // namespace Raul
-static inline std::ostream& operator<<(std::ostream& os, const Raul::Symbol& symbol)
+static inline std::ostream&
+operator<<(std::ostream& os, const Raul::Symbol& symbol)
{
return (os << symbol.c_str());
}
diff --git a/raul/URI.hpp b/raul/URI.hpp
index bc64b8c..83454ca 100644
--- a/raul/URI.hpp
+++ b/raul/URI.hpp
@@ -23,6 +23,8 @@
#include <ostream>
#include <glib.h>
+#include "raul/Path.hpp"
+
namespace Raul {
/** Simple wrapper around standard string with useful URI-specific methods.
@@ -47,11 +49,12 @@ public:
* It is a fatal error to construct a URI from an invalid string,
* use is_valid first to check.
*/
- URI(const std::basic_string<char>& uri="nil:0")
+ URI(const std::basic_string<char>& uri="nil:0") throw(BadURI)
: _str(g_intern_string(uri.c_str()))
{
- if (!is_valid(uri))
+ if (!is_valid(uri)) {
throw BadURI(uri);
+ }
}
/** Construct a URI from a C string.
@@ -59,13 +62,18 @@ public:
* It is a fatal error to construct a URI from an invalid string,
* use is_valid first to check.
*/
- URI(const char* uri)
+ URI(const char* uri) throw(BadURI)
: _str(g_intern_string(uri))
{
if (!is_valid(uri))
throw BadURI(uri);
}
+ /** Construct a URI from a base URI and a Path. */
+ URI(const URI& base, const Path& path)
+ : _str(g_intern_string((base.str() + path.c_str()).c_str()))
+ {}
+
static bool is_valid(const std::basic_string<char>& uri) {
return uri.find(":") != std::string::npos;
}
@@ -95,22 +103,23 @@ public:
inline char operator[](int i) const { return _str[i]; }
- inline size_t length() const { return str().length(); }
- inline size_t find(const std::string& s) const { return str().find(s); }
- inline size_t find_last_of(char c) const { return str().find_last_of(c); }
+ inline size_t length() const { return str().length(); }
+ inline size_t find(const std::string& s) const { return str().find(s); }
+ inline size_t find_last_of(char c) const { return str().find_last_of(c); }
private:
const char* _str;
};
+} // namespace Raul
+
static inline
std::ostream&
-operator<<(std::ostream& os, const URI& uri)
+operator<<(std::ostream& os, const Raul::URI& uri)
{
return (os << uri.c_str());
}
-} // namespace Raul
#endif // RAUL_URI_HPP
diff --git a/src/Path.cpp b/src/Path.cpp
index 2bf194d..e3a529d 100644
--- a/src/Path.cpp
+++ b/src/Path.cpp
@@ -22,61 +22,22 @@ using std::string;
namespace Raul {
-static URI root_uri("path:/");
-
-const Path Path::root() { return Path(true, root_uri); }
-void Path::set_root(const Raul::URI& uri) { root_uri = uri.str(); }
-
-bool
-Path::is_path(const Raul::URI& uri)
-{
- return uri.length() >= root_uri.length()
- && uri.substr(0, root_uri.length()) == root_uri.str()
- && Path::is_valid(uri.str());
-}
-
-Path::Path(const std::basic_string<char>& path)
- : URI(path[0] == '/' ? root_uri.str() + path.substr(1) : path)
-{
- if (!is_valid(str()))
- throw BadPath(str());
-}
-
-Path::Path(const char* cpath)
- : URI(cpath[0] == '/' ? root_uri.str() + (cpath + 1) : cpath)
-{
- if (!is_valid(str()))
- throw BadPath(str());
-}
-
bool
-Path::is_valid(const std::basic_string<char>& path_str)
+Path::is_valid(const std::basic_string<char>& path)
{
- if (path_str.length() == 0)
+ if (path.empty() || path[0] != '/') {
return false;
+ }
- if (path_str == root_uri.str())
+ // Root path
+ if (path == "/") {
return true;
+ }
- if (path_str[0] != '/' &&
- (path_str.length() < root_uri.length()
- || path_str.substr(0, root_uri.length()) != root_uri.str()))
- return false;
-
- const string path = (path_str[0] == '/')
- ? path_str
- : path_str.substr(root_uri.length() - 1);
-
- // Must start with a /
- if (path[0] != '/')
- return false;
-
- // Must not end with a slash unless "/"
- if (path.length() > 1 && path[path.length()-1] == '/')
+ // Not root, must not end with a slash
+ if (*path.rbegin() == '/')
return false;
- assert(path.find_last_of("/") != string::npos);
-
// Double slash not allowed
if (path.find("//") != string::npos)
return false;
@@ -95,17 +56,11 @@ Path::is_valid(const std::basic_string<char>& path_str)
return true;
}
-/** Convert a string to a valid full path.
- *
- * The returned string is a valid relative path without the root prefix,
- * i.e. the returned string starts with '/' followed by valid symbols,
- * each separated by '/'.
- */
-string
+Path
Path::pathify(const std::basic_string<char>& str)
{
if (str.length() == 0)
- return root().chop_scheme(); // this might not be wise?
+ return Path("/"); // this might not be wise?
const size_t first_slash = str.find('/');
string path = (first_slash == string::npos)
@@ -120,13 +75,8 @@ Path::pathify(const std::basic_string<char>& str)
if (path != "/" && path[path.length() - 1] == '/')
path = path.substr(0, path.length() - 1); // chop trailing slash
- assert(path.find_last_of('/') != string::npos);
-
replace_invalid_chars(path, 0, false);
-
- assert(is_valid(path));
-
- return path;
+ return Path(path);
}
/** Replace any invalid characters in @a str with a suitable replacement.
@@ -181,7 +131,7 @@ bool
Path::is_child_of(const Path& parent) const
{
const string parent_base = parent.base();
- return (substr(0, parent_base.length()) == parent_base);
+ return (str().substr(0, parent_base.length()) == parent_base);
}
bool
@@ -191,11 +141,9 @@ Path::is_parent_of(const Path& child) const
}
Path
-Path::lca(const Path& patha, const Path& pathb)
+Path::lca(const Path& a, const Path& b)
{
- const std::string a = patha.chop_scheme();
- const std::string b = pathb.chop_scheme();
- size_t len = std::min(a.length(), b.length());
+ const size_t len = std::min(a.length(), b.length());
size_t last_slash = 0;
for (size_t i = 0; i < len; ++i) {
@@ -208,10 +156,9 @@ Path::lca(const Path& patha, const Path& pathb)
}
if (last_slash <= 1) {
- return root();
+ return Path("/");
}
- return Path(a.substr(0, last_slash));
+ return Path(a.str().substr(0, last_slash));
}
} // namespace Raul
-