summaryrefslogtreecommitdiffstats
path: root/raul
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2012-08-14 04:22:07 +0000
committerDavid Robillard <d@drobilla.net>2012-08-14 04:22:07 +0000
commit2a429ca76b97cca197f105b665271360b74f6917 (patch)
treed25d206910bd4a84050918693816240c26d7d0ae /raul
parent8bf87dc2367caf9d82dbda0382363cda400971dc (diff)
downloadraul-2a429ca76b97cca197f105b665271360b74f6917.tar.gz
raul-2a429ca76b97cca197f105b665271360b74f6917.tar.bz2
raul-2a429ca76b97cca197f105b665271360b74f6917.zip
Remove glib dependency.
Make Symbol, URI, and Path simpler derivatives of std::string. 100% test coverage by line for Symbol, URI, Path, AtomicInt, and AtomicPtr. Add Raul::Exception. git-svn-id: http://svn.drobilla.net/lad/trunk/raul@4686 a436a847-0d15-0410-975c-d299462d15a1
Diffstat (limited to 'raul')
-rw-r--r--raul/Configuration.hpp10
-rw-r--r--raul/Exception.hpp34
-rw-r--r--raul/Path.hpp219
-rw-r--r--raul/Symbol.hpp112
-rw-r--r--raul/URI.hpp115
5 files changed, 260 insertions, 230 deletions
diff --git a/raul/Configuration.hpp b/raul/Configuration.hpp
index 554b247..6e45d3c 100644
--- a/raul/Configuration.hpp
+++ b/raul/Configuration.hpp
@@ -22,12 +22,13 @@
#include <stdlib.h>
#include <string.h>
-#include <exception>
#include <list>
#include <map>
#include <ostream>
#include <string>
+#include "raul/Exception.hpp"
+
namespace Raul {
/** Program configuration (command line options and/or configuration file).
@@ -126,11 +127,8 @@ public:
void print_usage(const std::string& program, std::ostream& os);
- struct CommandLineError : public std::exception {
- explicit CommandLineError(const std::string& m) : msg(m) {}
- ~CommandLineError() throw() {}
- const char* what() const throw() { return msg.c_str(); }
- std::string msg;
+ struct CommandLineError : public Exception {
+ explicit CommandLineError(const std::string& m) : Exception(m) {}
};
void parse(int argc, char** argv) throw (CommandLineError);
diff --git a/raul/Exception.hpp b/raul/Exception.hpp
new file mode 100644
index 0000000..4969ab2
--- /dev/null
+++ b/raul/Exception.hpp
@@ -0,0 +1,34 @@
+/*
+ This file is part of Raul.
+ Copyright 2007-2012 David Robillard <http://drobilla.net>
+
+ Raul is free software: you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation, either version 3 of the License, or any later version.
+
+ Raul is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Raul. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <exception>
+#include <string>
+
+#ifndef RAUL_EXCEPTION_HPP
+#define RAUL_EXCEPTION_HPP
+
+/** An exception (unexpected error). */
+class Exception : public std::exception {
+public:
+ const char* what() const throw() { return _what.c_str(); }
+ ~Exception() throw() {}
+protected:
+ explicit Exception(const std::string& what) : _what(what) {}
+private:
+ const std::string _what;
+};
+
+#endif // RAUL_EXCEPTION_HPP
diff --git a/raul/Path.hpp b/raul/Path.hpp
index 57bed80..05fb029 100644
--- a/raul/Path.hpp
+++ b/raul/Path.hpp
@@ -17,48 +17,38 @@
#ifndef RAUL_PATH_HPP
#define RAUL_PATH_HPP
-#include <cassert>
-#include <cctype>
-#include <cstring>
-#include <exception>
#include <string>
+#include "raul/Exception.hpp"
#include "raul/Symbol.hpp"
namespace Raul {
/** 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 never ends with a "/", except for the root Path "/", which is the
+ * only valid single-character Path.
*
- * 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).
- *
- * \ingroup raul
+ * @ingroup raul
*/
-class Path {
+class Path : public std::basic_string<char> {
public:
- class BadPath : public std::exception {
+ /** Attempt to construct an invalid Path. */
+ class BadPath : public Exception {
public:
- explicit BadPath(const std::string& path) : _path(path) {}
- ~BadPath() throw() {}
- const char* what() const throw() { return _path.c_str(); }
- private:
- const std::string _path;
+ explicit BadPath(const std::string& path) : Exception(path) {}
};
/** Construct an uninitialzed path, because the STL is annoying. */
- Path() : _str(g_intern_string("/")) {}
+ Path() : std::basic_string<char>("/") {}
- /** Construct a Path from an std::string.
+ /** 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.
+ * This will throw an exception if @p path is invalid. To avoid this, use
+ * is_valid() first to check.
*/
- Path(const std::basic_string<char>& path) throw (BadPath)
- : _str(g_intern_string(path.c_str()))
+ explicit Path(const std::basic_string<char>& path)
+ : std::basic_string<char>(path)
{
if (!is_valid(path)) {
throw BadPath(path);
@@ -67,56 +57,81 @@ public:
/** 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.
+ * This will throw an exception if @p path is invalid. To avoid this, use
+ * is_valid() first to check.
*/
- Path(const char* cpath) throw(BadPath)
- : _str(g_intern_string(cpath))
+ explicit Path(const char* path)
+ : std::basic_string<char>(path)
{
- if (!is_valid(cpath)) {
- throw BadPath(cpath);
+ if (!is_valid(path)) {
+ throw BadPath(path);
}
}
- /** Construct a Path from another path.
+ /** Copy a Path.
*
- * This is faster than constructing a path from the other path's string
- * representation, since validity checking is avoided.
+ * Note this is faster than constructing a Path from another Path's string
+ * since validation is unnecessary.
*/
- Path& operator=(const Path& other) {
- _str = other._str;
- return *this;
+ Path(const Path& path)
+ : std::basic_string<char>(path)
+ {}
+
+ /** Return true iff @p c is a valid Path character. */
+ static inline bool is_valid_char(char c) {
+ return c == '/' || Symbol::is_valid_char(c);
}
- static bool is_valid(const std::basic_string<char>& path);
+ /** Return true iff @p 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 '/'
+ }
- /** Convert a string to a valid Path. */
- static Path pathify(const std::basic_string<char>& str);
+ if (str != "/" && *str.rbegin() == '/') {
+ return false; // Must not end with '/' except for the root
+ }
- static void replace_invalid_chars(std::string& str,
- size_t start,
- bool replace_slash = false);
+ 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
+ } else if (str[i - 1] == '/') {
+ if (str[i] == '/') {
+ return false; // Must not contain "//"
+ } else if (!Symbol::is_valid_start_char(str[i])) {
+ return false; // Invalid symbol start character (digit)
+ }
+ }
+ }
- bool is_root() const { return !strcmp(_str, "/"); }
+ return true;
+ }
- bool is_child_of(const Path& parent) const;
- bool is_parent_of(const Path& child) const;
+ /** Return true iff this path is the root path ("/"). */
+ inline bool is_root() const { return *this == "/"; }
- Path operator+(const Path& p) const { return child(p); }
+ /** Return true iff this path is a child of @p 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 the lowest common ancestor of a and b. */
- static Path lca(const Path& a, const Path& b);
+ /** Return true iff this path is a parent of @p 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 e.g. the "method name" for OSC paths, the filename
- * for filesystem paths, etc.
- * The empty string may be returned (if the path is the root path).
+ *
+ * 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 char* last_slash = strrchr(c_str(), '/');
- if (last_slash) {
- return last_slash + 1;
+ const size_t last_sep = rfind('/');
+ if (last_sep != std::string::npos) {
+ return c_str() + last_sep + 1;
}
}
return "";
@@ -131,83 +146,65 @@ public:
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) ? Path("/") : str.substr(0, last_slash);
+ 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));
}
}
- Path child(const Path& p) const {
- return base() + p.str().substr(1);
+ /** 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 the path's child with the given symbol
- */
+ /** Return a direct child Path of this Path with the given Symbol. */
inline Path child(const Raul::Symbol& symbol) const {
- return base() + symbol.c_str();
+ return Path(base() + symbol.c_str());
}
- /** Return path relative to some base path (chop prefix)
+ /** 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 Path relative_to_base(const Path& base) const {
- if ((*this) == base) {
- return "/";
+ inline const std::string base() const {
+ if (is_root()) {
+ return *this;
} else {
- assert(length() > base.base().length());
- return str().substr(base.base().length() - 1);
+ return *this + '/';
}
}
- /** 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() const {
- std::string ret = str();
- if (is_root() && ret[ret.length() - 1] == '/')
- return ret;
- else
- return ret + '/';
+ /** 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 if \a child is equal to, or a descendant of \a parent */
- static bool descendant_comparator(const Path& parent, const Path& child) {
+ /** Return true iff @p child is equal to, or a descendant of @p parent. */
+ static inline 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.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);
+ (!parent.compare(0, parent.length(), child, 0, parent.length())
+ && (parent.is_root() || child[parent.length()] == '/'))));
}
-
- 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:
- 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 dcf1f04..3f14cc2 100644
--- a/raul/Symbol.hpp
+++ b/raul/Symbol.hpp
@@ -17,45 +17,38 @@
#ifndef RAUL_SYMBOL_HPP
#define RAUL_SYMBOL_HPP
-#include <cctype>
-#include <cstring>
-#include <exception>
-#include <iostream>
#include <string>
-#include <glib.h>
+#include "raul/Exception.hpp"
namespace Raul {
-/** A restricted string (C identifier, which is a component of a Path).
+/** A restricted string which is a valid C identifier and Path component.
*
* A Symbol is a very restricted string suitable for use as an identifier.
* It is a valid LV2 symbol, URI fragment, filename, OSC path fragment,
- * and identifier for most programming languages (including C).
+ * and identifier for virtually all programming languages.
*
* Valid characters are _, a-z, A-Z, 0-9, except the first character which
* must not be 0-9.
*
- * \ingroup raul
+ * @ingroup raul
*/
-class Symbol {
+class Symbol : public std::basic_string<char> {
public:
- class BadSymbol : public std::exception {
+ /** Attempt to construct an invalid Symbol. */
+ class BadSymbol : public Exception {
public:
- explicit BadSymbol(const std::string& symbol) : _symbol(symbol) {}
- ~BadSymbol() throw() {}
- const char* what() const throw() { return _symbol.c_str(); }
- private:
- const std::string _symbol;
+ explicit BadSymbol(const std::string& symbol) : Exception(symbol) {}
};
- /** Construct a Symbol from an std::string.
+ /** Construct a Symbol from a C++ string.
*
- * It is a fatal error to construct a Symbol from an invalid string,
- * use is_valid first to check.
+ * This will throw an exception if @p symbol is invalid. To avoid this,
+ * use is_valid() first to check.
*/
- explicit Symbol(const std::basic_string<char>& symbol) throw(BadSymbol)
- : _str(g_intern_string(symbol.c_str()))
+ explicit Symbol(const std::basic_string<char>& symbol)
+ : std::basic_string<char>(symbol)
{
if (!is_valid(symbol)) {
throw BadSymbol(symbol);
@@ -64,50 +57,71 @@ public:
/** Construct a Symbol from a C string.
*
- * It is a fatal error to construct a Symbol from an invalid string,
- * use is_valid first to check.
+ * This will throw an exception if @p symbol is invalid. To avoid this,
+ * use is_valid() first to check.
*/
- explicit Symbol(const char* csymbol) throw(BadSymbol)
- : _str(g_intern_string(csymbol))
+ explicit Symbol(const char* symbol)
+ : std::basic_string<char>(symbol)
{
- if (!is_valid(csymbol)) {
- throw BadSymbol(csymbol);
+ if (!is_valid(symbol)) {
+ throw BadSymbol(symbol);
}
}
- Symbol& operator=(const Symbol& other) {
- _str = other._str;
- return *this;
- }
-
- inline const char* c_str() const { return _str; }
+ /** Copy a Symbol.
+ *
+ * Note this is faster than constructing a Symbol from another Symbol's
+ * string since validation is unnecessary.
+ */
+ Symbol(const Symbol& symbol)
+ : std::basic_string<char>(symbol)
+ {}
- inline bool operator==(const Symbol& other) const {
- return _str == other._str;
+ /** Return true iff @p c is a valid Symbol start character. */
+ static inline bool is_valid_start_char(char c) {
+ return (c == '_') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
}
- inline bool operator!=(const Symbol& other) const {
- return _str != other._str;
+ /** Return true iff @p c is a valid Symbol character. */
+ static inline bool is_valid_char(char c) {
+ return is_valid_start_char(c) || (c >= '0' && c <= '9');
}
- inline bool operator<(const Symbol& other) const {
- return strcmp(_str, other._str) < 0;
- }
+ /** Return true iff @p str is a valid Symbol. */
+ static inline bool is_valid(const std::basic_string<char>& str) {
+ if (str.empty() || (str[0] >= '0' && str[0] <= '9')) {
+ return false; // Must start with a letter or underscore
+ }
- static bool is_valid(const std::basic_string<char>& symbol);
+ for (size_t i = 0; i < str.length(); ++i) {
+ if (!is_valid_char(str[i])) {
+ return false; // All characters must be _, a-z, A-Z, 0-9
+ }
+ }
- static Raul::Symbol symbolify(const std::basic_string<char>& str);
+ return true;
+ }
+
+ /** Convert a string to a valid symbol.
+ *
+ * This will make a best effort at turning @a str into a complete, valid
+ * Symbol, and will always return one.
+ */
+ static inline Symbol symbolify(const std::basic_string<char>& in) {
+ if (in.empty()) {
+ return Symbol("_");
+ }
-private:
- const char* _str;
+ std::basic_string<char> out(in);
+ for (size_t i = 0; i < in.length(); ++i) {
+ if (!is_valid_char(out[i])) {
+ out[i] = '_';
+ }
+ }
+ return Symbol(out);
+ }
};
} // namespace Raul
-static inline std::ostream&
-operator<<(std::ostream& os, const Raul::Symbol& symbol)
-{
- return (os << symbol.c_str());
-}
-
#endif // RAUL_SYMBOL_HPP
diff --git a/raul/URI.hpp b/raul/URI.hpp
index 83454ca..b2ccad7 100644
--- a/raul/URI.hpp
+++ b/raul/URI.hpp
@@ -18,39 +18,30 @@
#define RAUL_URI_HPP
#include <string>
-#include <cstring>
-#include <exception>
-#include <ostream>
-#include <glib.h>
-#include "raul/Path.hpp"
+#include "raul/Exception.hpp"
namespace Raul {
-/** Simple wrapper around standard string with useful URI-specific methods.
+/** A URI (RFC3986) string.
*
- * This "should" be used for proper URIs (RFC3986), but not much support or
- * validation is built-in yet. The URI string MUST have a scheme though.
- * \ingroup raul
+ * @ingroup raul
*/
-class URI {
+class URI : public std::basic_string<char> {
public:
- class BadURI : public std::exception {
+ /** Attempt to construct an invalid URI. */
+ class BadURI : public Exception {
public:
- explicit BadURI(const std::string& uri) : _uri(uri) {}
- ~BadURI() throw() {}
- const char* what() const throw() { return _uri.c_str(); }
- private:
- const std::string _uri;
+ explicit BadURI(const std::string& uri) : Exception(uri) {}
};
- /** Construct a URI from an std::string.
+ /** Construct a URI from a C++ string.
*
- * It is a fatal error to construct a URI from an invalid string,
- * use is_valid first to check.
+ * This will throw an exception if @p uri is invalid. To avoid this, use
+ * is_valid() first to check.
*/
- URI(const std::basic_string<char>& uri="nil:0") throw(BadURI)
- : _str(g_intern_string(uri.c_str()))
+ explicit URI(const std::basic_string<char>& uri)
+ : std::basic_string<char>(uri)
{
if (!is_valid(uri)) {
throw BadURI(uri);
@@ -59,67 +50,63 @@ public:
/** Construct a URI from a C string.
*
- * It is a fatal error to construct a URI from an invalid string,
- * use is_valid first to check.
+ * This will throw an exception if @p uri is invalid. To avoid this, use
+ * is_valid() first to check.
*/
- URI(const char* uri) throw(BadURI)
- : _str(g_intern_string(uri))
+ explicit URI(const char* uri)
+ : std::basic_string<char>(uri)
{
- if (!is_valid(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()))
+ /** Copy a URI.
+ *
+ * Note this is faster than constructing a URI from another URI's string
+ * since validation is unnecessary.
+ */
+ URI(const URI& uri)
+ : std::basic_string<char>(uri)
{}
- static bool is_valid(const std::basic_string<char>& uri) {
- return uri.find(":") != std::string::npos;
+ /** Return true iff @p c is a valid URI start character. */
+ static inline bool is_valid_start_char(char c) {
+ return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
}
- /** Return path with everything up to and including the first occurence of str chopped */
- inline const std::string chop_start(const std::string& str) const {
- return substr(find(str) + str.length());
+ /** Return true iff @p c is a valid URI scheme character. */
+ static inline bool is_valid_scheme_char(char c) {
+ // S3.1: scheme ::= ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
+ return is_valid_start_char(c) || (c >= '0' && c <= '9') ||
+ c == '+' || c == '-' || c == '.';
}
- /** Return the URI with the scheme removed (as a string) */
- std::string chop_scheme() const { return chop_start(":"); }
-
- /** Return the URI scheme (everything before the first ':') */
- inline std::string scheme() const { return substr(0, find(":")); }
+ /** Return true iff @p str is a valid URI.
+ *
+ * Currently this only checks that @p starts with a valid URI scheme.
+ */
+ static inline bool is_valid(const std::basic_string<char>& str) {
+ if (!is_valid_start_char(str[0])) {
+ return false; // Must start with a-z A-Z
+ }
- inline const std::string str() const { return _str; }
- inline const char* c_str() const { return _str; }
+ for (size_t i = 1; i < str.length(); ++i) {
+ if (str[i] == ':') {
+ return true; // Starts with a valid scheme
+ } else if (!is_valid_scheme_char(str[i])) {
+ return false; // Invalid scheme character encountered
+ }
+ }
- inline std::string substr(size_t start, size_t end=std::string::npos) const {
- return str().substr(start, end);
+ return false; // Must start with a scheme followed by ':'
}
- inline bool operator<(const URI& uri) const { return strcmp(_str, uri.c_str()) < 0; }
- inline bool operator<=(const URI& uri) const { return (*this) == uri || (*this) < uri; }
- inline bool operator==(const URI& uri) const { return _str == uri._str; }
- inline bool operator!=(const URI& uri) const { return _str != uri._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 size_t find_last_of(char c) const { return str().find_last_of(c); }
-
-private:
- const char* _str;
+ /** Return the URI scheme (everything before the first ':') */
+ inline std::string scheme() const { return substr(0, find(":")); }
};
} // namespace Raul
-static inline
-std::ostream&
-operator<<(std::ostream& os, const Raul::URI& uri)
-{
- return (os << uri.c_str());
-}
-
-
#endif // RAUL_URI_HPP