diff options
author | David Robillard <d@drobilla.net> | 2010-02-02 20:37:50 +0000 |
---|---|---|
committer | David Robillard <d@drobilla.net> | 2010-02-02 20:37:50 +0000 |
commit | 36573e798c986e298c62daabed6036b12ea0314d (patch) | |
tree | c908c681c6f584831366283bf7c099b36f94ff52 | |
parent | 53648252376649bca9868aec48ad4a290e3ae073 (diff) | |
download | raul-36573e798c986e298c62daabed6036b12ea0314d.tar.gz raul-36573e798c986e298c62daabed6036b12ea0314d.tar.bz2 raul-36573e798c986e298c62daabed6036b12ea0314d.zip |
Use Glib string interning (quarks) to make Path/URI operator== very fast.
This avoids a ton of string comparison overhead in Ingen when setting various
properties (e.g. "ingen:value" was compared several times every time a port
value was changed, now this is just a single pointer comparison and the full
round trip of a value change does no string comparison at all, but is still
property based and RDFey).
git-svn-id: http://svn.drobilla.net/lad/trunk/raul@2408 a436a847-0d15-0410-975c-d299462d15a1
-rw-r--r-- | raul/Atom.hpp | 56 | ||||
-rw-r--r-- | raul/Path.hpp | 69 | ||||
-rw-r--r-- | raul/Symbol.hpp | 28 | ||||
-rw-r--r-- | raul/TableImpl.hpp | 4 | ||||
-rw-r--r-- | raul/URI.hpp | 37 | ||||
-rw-r--r-- | src/Configuration.cpp | 2 | ||||
-rw-r--r-- | src/Path.cpp | 4 | ||||
-rw-r--r-- | wscript | 5 |
8 files changed, 125 insertions, 80 deletions
diff --git a/raul/Atom.hpp b/raul/Atom.hpp index 5091453..3451604 100644 --- a/raul/Atom.hpp +++ b/raul/Atom.hpp @@ -24,9 +24,11 @@ #include <cstring> #include <string> #include <ostream> +#include <glib.h> namespace Raul { +class URI; /** A piece of data with some type. * @@ -54,17 +56,17 @@ public: Atom(bool val) : _type(BOOL), _bool_val(val) {} Atom(const char* val) : _type(STRING), _string_val(strdup(val)) {} - Atom(Type t, const std::string& val) : _type(t), _string_val(strdup(val.c_str())) {} + Atom(const std::string& val) : _type(STRING), _string_val(strdup(val.c_str())) {} + + /** URI constructor (@a t must be URI) */ + Atom(Type t, const std::string& val) : _type(t), _string_val(g_intern_string(val.c_str())) { + assert(t == URI); + } Atom(const char* type_uri, size_t size, void* val) : _type(BLOB), _blob_val(new BlobValue(type_uri, size, val)) {} - ~Atom() { - if (_type == URI || _type == STRING) - free(_string_val); - else if (_type == BLOB) - delete _blob_val; - } + ~Atom() { dealloc(); } Atom(const Atom& copy) : _type(copy._type) @@ -74,18 +76,14 @@ public: case INT: _int_val = copy._int_val; break; case FLOAT: _float_val = copy._float_val; break; case BOOL: _bool_val = copy._bool_val; break; - case URI: + case URI: _string_val = copy._string_val; break; case STRING: _string_val = strdup(copy._string_val); break; case BLOB: _blob_val = new BlobValue(*copy._blob_val); break; } } Atom& operator=(const Atom& other) { - if (_type == BLOB) - delete _blob_val; - else if (_type == STRING) - free(_string_val); - + dealloc(); _type = other._type; switch (_type) { @@ -93,7 +91,7 @@ public: case INT: _int_val = other._int_val; break; case FLOAT: _float_val = other._float_val; break; case BOOL: _bool_val = other._bool_val; break; - case URI: + case URI: _string_val = other._string_val; break; case STRING: _string_val = strdup(other._string_val); break; case BLOB: _blob_val = new BlobValue(*other._blob_val); break; } @@ -107,7 +105,7 @@ public: case INT: return _int_val == other._int_val; case FLOAT: return _float_val == other._float_val; case BOOL: return _bool_val == other._bool_val; - case URI: + case URI: return _string_val == other._string_val; case STRING: return strcmp(_string_val, other._string_val) == 0; case BLOB: return _blob_val == other._blob_val; } @@ -164,6 +162,24 @@ public: private: Type _type; + friend class Raul::URI; + Atom(const char* str, uint32_t magic) : _type(URI), _string_val(str) { + assert(magic == 12345); + assert(g_intern_string(str) == str); + } + + inline void dealloc() { + switch (_type) { + case STRING: + free(const_cast<char*>(_string_val)); + break; + case BLOB: + delete _blob_val; + default: + break; + } + } + class BlobValue { public: BlobValue(const char* type, size_t size, void* data) @@ -196,11 +212,11 @@ private: }; union { - int32_t _int_val; - float _float_val; - bool _bool_val; - char* _string_val; - BlobValue* _blob_val; + int32_t _int_val; + float _float_val; + bool _bool_val; + const char* _string_val; + BlobValue* _blob_val; }; }; diff --git a/raul/Path.hpp b/raul/Path.hpp index ffa8aa0..55f3926 100644 --- a/raul/Path.hpp +++ b/raul/Path.hpp @@ -58,10 +58,10 @@ public: static const std::string scheme; static const std::string prefix; static const size_t prefix_len; - static const std::string root_uri; + static const Path root; /** Construct an uninitialzed path, because the STL is annoying. */ - Path() : URI(root_uri) {} + Path() : URI(root) {} /** Construct a Path from an std::string. * @@ -99,60 +99,66 @@ public: static void replace_invalid_chars(std::string& str, size_t start, bool replace_slash = false); - bool is_root() const { return str() == root_uri; } + bool is_root() const { return (*this) == root; } 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 std::string(base()) + Path(s).chop_scheme().substr(1); + return base() + Path(s).chop_scheme().substr(1); else - return std::string(base()) + s; + return base() + s; } - Path operator+(const Path& p) const { return child(p); } - - /** Return the name of this object (everything after the last '/'). - * This is the "method name" for OSC paths. - * The empty string may be returned (if the path is "/"). - */ - inline std::string name() const { - if (str() == root_uri) - return ""; - else - return substr(find_last_of("/")+1); + Path child(const Path& p) const { + return base() + p.chop_scheme().substr(1); } + Path operator+(const Path& p) const { return child(p); } - /** Return the name of this object (everything after the last '/'). - * This is the "method name" for OSC paths. - * Note it is illegal to call this method on the path "/". + /** 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). */ - inline Symbol symbol() const { - return substr(find_last_of("/")+1); + inline const char* symbol() const { + if ((*this) != root) { + const char* last_slash = strrchr(c_str(), '/'); + if (last_slash) { + return last_slash + 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 (str() == root_uri) { - return str(); + if ((*this) == root) { + return *this; } else { - size_t last_slash = find_last_of("/"); - return (last_slash == prefix_len) ? root_uri : substr(0, last_slash); + const std::string str(this->str()); + const size_t last_slash = str.find_last_of('/'); + return (last_slash == prefix_len) ? root : str.substr(0, last_slash); } } + /** Return the path's child with the given name (symbol) + */ + inline Path child(const Raul::Symbol& symbol) const { + return base() + symbol.c_str(); + } + + /** Return path relative to some base path (chop prefix) */ inline Path relative_to_base(const Path& base) const { - if (str() == base) { + if ((*this) == base) { return "/"; } else { assert(length() > base.length()); @@ -167,10 +173,11 @@ public: * child path can be made using parent.base() + child_name. */ inline const std::string base() const { - if (str() == root_uri) - return str(); + std::string ret = str(); + if ((*this) == root && ret[ret.length() - 1] == '/') + return ret; else - return str() + "/"; + return ret + '/'; } /** Return path with a trailing "/". @@ -187,7 +194,7 @@ public: 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.str() == root_uri || child[parent.length()] == '/'))) ); + && (parent == root || child.str()[parent.length()] == '/'))) ); } }; diff --git a/raul/Symbol.hpp b/raul/Symbol.hpp index 8aa82c1..1a57886 100644 --- a/raul/Symbol.hpp +++ b/raul/Symbol.hpp @@ -23,6 +23,7 @@ #include <string> #include <cstring> #include <cassert> +#include <glib.h> namespace Raul { @@ -38,16 +39,15 @@ namespace Raul { * * \ingroup raul */ -class Symbol : public std::basic_string<char> { +class Symbol { public: - /** Construct a Symbol from an std::string. * * It is a fatal error to construct a Symbol from an invalid string, * use is_valid first to check. */ Symbol(const std::basic_string<char>& symbol) - : std::basic_string<char>(symbol) + : _str(g_intern_string(symbol.c_str())) { assert(is_valid(symbol)); } @@ -59,17 +59,35 @@ public: * use is_valid first to check. */ Symbol(const char* csymbol) - : std::basic_string<char>(csymbol) + : _str(g_intern_string(csymbol)) { assert(is_valid(csymbol)); } - static bool is_valid(const std::basic_string<char>& path); + inline const char* c_str() const { return _str; } + + inline bool operator==(const Symbol& other) const { + return _str == other._str; + } + + inline bool operator!=(const Symbol& other) const { + return _str != other._str; + } + + static bool is_valid(const std::basic_string<char>& symbol); static std::string symbolify(const std::basic_string<char>& str); + +private: + const char* _str; }; } // 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/TableImpl.hpp b/raul/TableImpl.hpp index 0b32a29..6b91d01 100644 --- a/raul/TableImpl.hpp +++ b/raul/TableImpl.hpp @@ -264,7 +264,7 @@ Table<K,T>::insert(const std::pair<K, T>& entry) const K& key = entry.first; const T& value = entry.second; - if (size() == 0 || (size() == 1 && key > _entries[0].first)) { + if (size() == 0 || (size() == 1 && _entries[0].first < key)) { _entries.push_back(entry); return std::make_pair(iterator(*this, size()-1), true); } else if (size() == 1) { @@ -291,7 +291,7 @@ Table<K,T>::insert(const std::pair<K, T>& entry) if (elem.first == key) { elem.second = value; return std::make_pair(iterator(*this, i), false); - } else if (elem.first > key) { + } else if (key < elem.first) { if (i == 0 || _entries[i-1].first < key) break; upper = i - 1; diff --git a/raul/URI.hpp b/raul/URI.hpp index 18e15ad..18fc8a2 100644 --- a/raul/URI.hpp +++ b/raul/URI.hpp @@ -19,8 +19,11 @@ #define RAUL_URI_HPP #include <string> +#include <cstring> #include <exception> #include <ostream> +#include <glib.h> +#include "raul/Atom.hpp" namespace Raul { @@ -30,7 +33,7 @@ namespace Raul { * 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. */ -class URI : protected std::basic_string<char> { +class URI { public: class BadURI : public std::exception { public: @@ -46,7 +49,7 @@ 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") : std::basic_string<char>(uri) { + URI(const std::basic_string<char>& uri="nil:0") : _str(g_intern_string(uri.c_str())) { if (!is_valid(uri)) throw BadURI(uri); } @@ -56,7 +59,7 @@ public: * It is a fatal error to construct a URI from an invalid string, * use is_valid first to check. */ - URI(const char* uri) : std::basic_string<char>(uri) { + URI(const char* uri) : _str(g_intern_string(uri)) { if (!is_valid(uri)) throw BadURI(uri); } @@ -65,7 +68,7 @@ public: return uri.find(":") != std::string::npos; } - /** Return path with every up to and including the first occurence of str */ + /** 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()); } @@ -76,33 +79,33 @@ public: /** Return the URI scheme (everything before the first ':') */ inline std::string scheme() const { return substr(0, find(":")); } - inline const std::string& str() const { return *this; } - inline const char* c_str() const { return str().c_str(); } - - inline operator const std::string() const { return str(); } - inline operator std::string() { return str(); } + inline const std::string str() const { return _str; } + inline const char* c_str() const { return _str; } inline std::string substr(size_t start, size_t end=std::string::npos) const { return str().substr(start, end); } - inline bool operator<(const URI& uri) const { return str() < uri; } - inline bool operator<=(const URI& uri) const { return str() <= uri; } - inline bool operator>(const URI& uri) const { return str() > uri; } - inline bool operator>=(const URI& uri) const { return str() >= uri; } - inline bool operator==(const URI& uri) const { return str() == uri; } - inline bool operator!=(const URI& uri) const { return str() != uri; } + 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 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(const std::string& s) const { return str().find_last_of(s); } + inline size_t find_last_of(char c) const { return str().find_last_of(c); } + + inline operator Raul::Atom() const { return Raul::Atom(_str, 12345); } + +private: + const char* _str; }; static inline std::ostream& operator<<(std::ostream& os, const URI& uri) { - return (os << uri.str()); + return (os << uri.c_str()); } } // namespace Raul diff --git a/src/Configuration.cpp b/src/Configuration.cpp index 1ea70a3..bc6cfbd 100644 --- a/src/Configuration.cpp +++ b/src/Configuration.cpp @@ -85,7 +85,7 @@ Configuration::set_value_from_string(Configuration::Option& option, const std::s } break; case Atom::STRING: - option.value = Atom(Atom::STRING, value); + option.value = Atom(value.c_str()); break; default: throw CommandLineError(string("bad option type `--") + option.name + "'"); diff --git a/src/Path.cpp b/src/Path.cpp index 512d91b..c0eb0df 100644 --- a/src/Path.cpp +++ b/src/Path.cpp @@ -24,7 +24,7 @@ namespace Raul { const string Path::scheme = "path"; const string Path::prefix = Path::scheme + ":"; const size_t Path::prefix_len = prefix.length(); -const string Path::root_uri = Path::prefix + "/"; +const Path Path::root = Path::prefix + "/"; bool Path::is_valid(const std::basic_string<char>& path_str) @@ -73,7 +73,7 @@ string Path::pathify(const std::basic_string<char>& str) { if (str.length() == 0) - return root_uri; // this might not be wise? + return root.str(); // this might not be wise? string path = (str.substr(0, prefix_len) == prefix) ? str : prefix + str; size_t start = prefix_len + 1; @@ -4,7 +4,7 @@ import Options import os # Version of this package (even if built as a child) -RAUL_VERSION = '0.6.2' +RAUL_VERSION = '0.6.3' # Library version (UNIX style major, minor, micro) # major increment <=> incompatible changes @@ -17,7 +17,8 @@ RAUL_VERSION = '0.6.2' # 0.6.0 = 3,0,0 # 0.6.1 = 4,0,0 (unreleased) # 0.6.2 = 5,0,0 (unreleased) -RAUL_LIB_VERSION = '5.0.0' +# 0.6.3 = 6,0,0 (unreleased) +RAUL_LIB_VERSION = '6.0.0' # Variables for 'waf dist' APPNAME = 'raul' |