From b6282d866293c615e2fa4ebff06b4600da3ac663 Mon Sep 17 00:00:00 2001 From: gfgtdf Date: Fri, 1 Apr 2016 03:09:29 +0200 Subject: [PATCH] use c++11 heterogeneous map lookups in config if possible. this means that codes like cfg.child("abcd") or cfg["abcd"] won't create a temporary std::string anymore. At least when cfg is const. --- src/config.cpp | 60 +++++++++++++++++++++++++++++++++++++++++++++++++- src/config.hpp | 45 +++++++++++++++++++++++++++++++++++-- 2 files changed, 102 insertions(+), 3 deletions(-) diff --git a/src/config.cpp b/src/config.cpp index d4a086a5b08b..78b650c5390e 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -42,6 +42,24 @@ static lg::log_domain log_config("config"); #define ERR_CF LOG_STREAM(err, log_config) #define DBG_CF LOG_STREAM(debug, log_config) + +#ifdef USE_HETEROGENOUS_LOOKUPS +struct config_simple_key +{ + const char* str; + int len; + + friend bool operator<(const config_simple_key& l, const std::string& r) + { + return r.compare(0, r.size(), l.str, l.len) > 0; + } + friend bool operator<(const std::string& l, const config_simple_key& r) + { + return l.compare(0, l.size(), r.str, r.len) < 0; + } +}; +#endif + struct tconfig_implementation { /** @@ -653,7 +671,34 @@ config &config::child(const std::string& key, int n) if (n < 0) n = i->second.size() + n; if(size_t(n) < i->second.size()) { return *i->second[n]; - } else { + } + else { + DBG_CF << "The config object has only »" << i->second.size() + << "« children named »" << key + << "«; request for the index »" << n << "« cannot be honored.\n"; + + return invalid; + } +} + +#ifdef USE_HETEROGENOUS_LOOKUPS +config &config::child_impl(const char* key, int len, int n) +{ + check_valid(); + + const child_map::const_iterator i = children.find(config_simple_key{ key, len }); + if (i == children.end()) { + DBG_CF << "The config object has no child named »" + << key << "«.\n"; + + return invalid; + } + + if (n < 0) n = i->second.size() + n; + if (size_t(n) < i->second.size()) { + return *i->second[n]; + } + else { DBG_CF << "The config object has only »" << i->second.size() << "« children named »" << key << "«; request for the index »" << n << "« cannot be honored.\n"; @@ -661,6 +706,7 @@ config &config::child(const std::string& key, int n) return invalid; } } +#endif config& config::child(const std::string& key, const std::string& parent) { @@ -877,6 +923,18 @@ const config::attribute_value &config::operator[](const std::string &key) const return empty_attribute; } +#ifdef USE_HETEROGENOUS_LOOKUPS +const config::attribute_value& config::get_attribute(const char* key, int len) const +{ + check_valid(); + + const attribute_map::const_iterator i = values.find(config_simple_key { key, len }); + if (i != values.end()) return i->second; + static const attribute_value empty_attribute; + return empty_attribute; +} + +#endif const config::attribute_value *config::get(const std::string &key) const { check_valid(); diff --git a/src/config.hpp b/src/config.hpp index fceeccfd1bdd..2806b1222ac8 100644 --- a/src/config.hpp +++ b/src/config.hpp @@ -50,6 +50,11 @@ #include "exceptions.hpp" #include "tstring.hpp" + //TODO: enable for gcc 5.0 and clang 3.4 +#if defined(_MSC_VER) && _MSC_VER >= 1900 +# define USE_HETEROGENOUS_LOOKUPS +#endif + class config; class enum_tag; @@ -99,7 +104,11 @@ class config { return this != &invalid; } typedef std::vector child_list; - typedef std::map child_map; + typedef std::map +#endif + > child_map; struct const_child_iterator; @@ -357,7 +366,13 @@ class config static const std::string s_true, s_false; }; - typedef std::map attribute_map; + typedef std::map< + std::string + , attribute_value +#ifdef USE_HETEROGENOUS_LOOKUPS + , std::less<> +#endif + > attribute_map; typedef attribute_map::value_type attribute; struct const_attribute_iterator @@ -415,6 +430,12 @@ class config */ config &child(const std::string& key, int n = 0); +#ifdef USE_HETEROGENOUS_LOOKUPS + template + config &child(const char(&key)[N], int n = 0) + { return child_impl(key, N - 1, n); } + config &child_impl(const char* key, int len, int n = 0); +#endif /** * Returns the nth child with the given @a key, or * a reference to an invalid config if there is none. @@ -424,6 +445,11 @@ class config const config &child(const std::string& key, int n = 0) const { return const_cast(this)->child(key, n); } +#ifdef USE_HETEROGENOUS_LOOKUPS + template + const config &child(const char(&key)[N], int n = 0) const + { return const_cast(this)->child_impl(key, N- 1, n); } +#endif /** * Returns a mandatory child node. * @@ -478,6 +504,18 @@ class config */ const attribute_value &operator[](const std::string &key) const; +#ifdef USE_HETEROGENOUS_LOOKUPS + /** + * Returns a reference to the attribute with the given @a key + * or to a dummy empty attribute if it does not exist. + */ + template + inline const attribute_value &operator[](const char (&key)[N]) const + { + //-1 for the terminating null character. + return get_attribute(key, N - 1); + } +#endif /** * Returns a pointer to the attribute with the given @a key * or nullptr if it does not exist. @@ -683,6 +721,9 @@ class config void swap(config& cfg); private: +#ifdef USE_HETEROGENOUS_LOOKUPS + const attribute_value& get_attribute(const char* key, int len) const; +#endif /** * Removes the child at position @a pos of @a l. */