use boost::string_view in config class

this replaces the older heterogenous lookup optmisation in config.?pp.
The advantage  is that it no longer requires different overloads for c
strings and std::string so it can easily be aplied to all config memeber
functions witout code duplication.
This commit is contained in:
gfgtdf 2017-04-29 19:42:05 +02:00 committed by GitHub
parent ceba081542
commit d405ec1c9d
2 changed files with 81 additions and 173 deletions

View file

@ -39,24 +39,6 @@ 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 config_implementation
{
/**
@ -69,7 +51,7 @@ struct config_implementation
static typename utils::const_clone<config, T>::reference
child(
T config
, const std::string& key
, config_key_type key
, const std::string& parent)
{
config->check_valid();
@ -461,7 +443,7 @@ config::config(const config& cfg) : values(cfg.values), children(), ordered_chil
append_children(cfg);
}
config::config(const std::string& child) : values(), children(), ordered_children()
config::config(config_key_type child) : values(), children(), ordered_children()
{
add_child(child);
}
@ -495,7 +477,7 @@ config &config::operator=(config &&cfg)
return *this;
}
bool config::valid_id(const std::string& id)
bool config::valid_id(config_key_type id)
{
if (id.empty()) {
return false;
@ -511,13 +493,13 @@ bool config::valid_id(const std::string& id)
return true;
}
bool config::has_attribute(const std::string &key) const
bool config::has_attribute(config_key_type key) const
{
check_valid();
return values.find(key) != values.end();
}
bool config::has_old_attribute(const std::string &key, const std::string &old_key, const std::string& msg) const
bool config::has_old_attribute(config_key_type key, const std::string &old_key, const std::string& msg) const
{
check_valid();
if (values.find(key) != values.end()) {
@ -531,7 +513,7 @@ bool config::has_old_attribute(const std::string &key, const std::string &old_ke
}
void config::remove_attribute(const std::string &key)
void config::remove_attribute(config_key_type key)
{
check_valid();
values.erase(key);
@ -582,7 +564,7 @@ void config::merge_children(const std::string& key)
merged_children.append(cfg);
}
clear_children(key);
clear_children_impl(key);
add_child(key,merged_children);
}
@ -598,13 +580,13 @@ void config::merge_children_by_attribute(const std::string& key, const std::stri
merged_children_map[cfg[attribute]].append(cfg);
}
clear_children(key);
clear_children_impl(key);
for (const config_map::value_type &i : merged_children_map) {
add_child(key,i.second);
}
}
config::child_itors config::child_range(const std::string& key)
config::child_itors config::child_range(config_key_type key)
{
check_valid();
@ -615,7 +597,7 @@ config::child_itors config::child_range(const std::string& key)
return child_itors(child_iterator(p->begin()), child_iterator(p->end()));
}
config::const_child_itors config::child_range(const std::string& key) const
config::const_child_itors config::child_range(config_key_type key) const
{
check_valid();
@ -626,7 +608,7 @@ config::const_child_itors config::child_range(const std::string& key) const
return const_child_itors(const_child_iterator(p->begin()), const_child_iterator(p->end()));
}
unsigned config::child_count(const std::string &key) const
unsigned config::child_count(config_key_type key) const
{
check_valid();
@ -649,14 +631,14 @@ unsigned config::attribute_count() const
});
}
bool config::has_child(const std::string &key) const
bool config::has_child(config_key_type key) const
{
check_valid();
return children.find(key) != children.end();
}
config &config::child(const std::string& key, int n)
config &config::child(config_key_type key, int n)
{
check_valid();
@ -681,46 +663,19 @@ config &config::child(const std::string& key, int n)
}
}
#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";
return invalid;
}
}
#endif
config& config::child(const std::string& key, const std::string& parent)
config& config::child(config_key_type key, const std::string& parent)
{
return config_implementation::child(this, key, parent);
}
const config& config::child(
const std::string& key
config_key_type key
, const std::string& parent) const
{
return config_implementation::child(this, key, parent);
}
const config & config::child_or_empty(const std::string& key) const
const config & config::child_or_empty(config_key_type key) const
{
static const config empty_cfg;
check_valid();
@ -732,7 +687,7 @@ const config & config::child_or_empty(const std::string& key) const
return empty_cfg;
}
config &config::child_or_add(const std::string &key)
config &config::child_or_add(config_key_type key)
{
child_map::const_iterator i = children.find(key);
if (i != children.end() && !i->second.empty())
@ -741,7 +696,7 @@ config &config::child_or_add(const std::string &key)
return add_child(key);
}
config& config::add_child(const std::string& key)
config& config::add_child(config_key_type key)
{
check_valid();
@ -751,7 +706,7 @@ config& config::add_child(const std::string& key)
return *v.back();
}
config& config::add_child(const std::string& key, const config& val)
config& config::add_child(config_key_type key, const config& val)
{
check_valid(val);
@ -761,7 +716,7 @@ config& config::add_child(const std::string& key, const config& val)
return *v.back();
}
config &config::add_child(const std::string &key, config &&val)
config &config::add_child(config_key_type key, config &&val)
{
check_valid(val);
@ -771,7 +726,7 @@ config &config::add_child(const std::string &key, config &&val)
return *v.back();
}
config &config::add_child_at(const std::string &key, const config &val, unsigned index)
config &config::add_child_at(config_key_type key, const config &val, unsigned index)
{
check_valid(val);
@ -818,7 +773,7 @@ private:
}
void config::clear_children(const std::string& key)
void config::clear_children_impl(config_key_type key)
{
check_valid();
@ -858,7 +813,7 @@ void config::splice_children(config &src, const std::string &key)
}
}
void config::recursive_clear_value(const std::string& key)
void config::recursive_clear_value(config_key_type key)
{
check_valid();
@ -899,7 +854,7 @@ config::all_children_iterator config::erase(const config::all_children_iterator&
return all_children_iterator(remove_child(i.i_->pos, i.i_->index));
}
void config::remove_child(const std::string &key, unsigned index)
void config::remove_child(config_key_type key, unsigned index)
{
check_valid();
@ -913,7 +868,7 @@ void config::remove_child(const std::string &key, unsigned index)
remove_child(i, index);
}
const config::attribute_value &config::operator[](const std::string &key) const
const config::attribute_value &config::operator[](config_key_type key) const
{
check_valid();
@ -923,32 +878,27 @@ 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
const config::attribute_value *config::get(config_key_type key) const
{
check_valid();
attribute_map::const_iterator i = values.find(key);
return i != values.end() ? &i->second : nullptr;
}
config::attribute_value &config::operator[](const std::string &key)
config::attribute_value& config::operator[](config_key_type key)
{
check_valid();
return values[key];
auto res = values.lower_bound(key);
if (res == values.end() || key != res->first) {
res = values.emplace_hint(res, std::piecewise_construct, std::forward_as_tuple(key), std::tuple<>());
}
return res->second;
}
const config::attribute_value &config::get_old_attribute(const std::string &key, const std::string &old_key, const std::string &msg) const
const config::attribute_value &config::get_old_attribute(config_key_type key, const std::string &old_key, const std::string &msg) const
{
check_valid();
@ -1010,26 +960,7 @@ config::attr_itors config::attribute_range()
return range;
}
namespace {
struct config_has_value {
config_has_value(const std::string& name, const std::string& value)
: name_(name), value_()
{
// TODO: This is assigned here instead of in the init-list because attribute_value doesn't have a matching constructor
value_ = value;
}
bool operator()(const config* cfg) const { return (*cfg)[name_] == value_; }
private:
std::string name_;
config::attribute_value value_;
};
} // end namespace
config &config::find_child(const std::string &key, const std::string &name,
config &config::find_child(config_key_type key, const std::string &name,
const std::string &value)
{
check_valid();
@ -1044,7 +975,7 @@ config &config::find_child(const std::string &key, const std::string &name,
const child_list::iterator j = std::find_if(i->second.begin(),
i->second.end(),
config_has_value(name,value));
[&](const config* cfg) { return (*cfg)[name] == value; });
if(j != i->second.end()) {
return **j;
} else {
@ -1542,8 +1473,8 @@ std::string config::hash() const
if (val.second.blank()) {
continue;
}
for (std::string::const_iterator c = val.first.begin(); c != val.first.end(); ++c) {
hash_str[i] ^= *c;
for (char c : val.first) {
hash_str[i] ^= c;
if (++i == hash_length) i = 0;
}
std::string base_str = val.second.t_str().base_str();

View file

@ -68,6 +68,18 @@
# define USE_HETEROGENOUS_LOOKUPS
#endif
#ifdef USE_HETEROGENOUS_LOOKUPS
#if BOOST_VERSION > 106100
#include <boost/utility/string_view.hpp>
using config_key_type = boost::string_view;
#else
#include <boost/utility/string_ref.hpp>
using config_key_type = boost::string_ref;
#endif
#else
using config_key_type = const std::string &;
#endif
class config;
class enum_tag;
@ -106,7 +118,7 @@ public:
/**
* Creates a config object with an empty child of name @a child.
*/
explicit config(const std::string &child);
explicit config(config_key_type child);
~config();
@ -453,9 +465,9 @@ public:
typedef boost::iterator_range<const_attribute_iterator> const_attr_itors;
typedef boost::iterator_range<attribute_iterator> attr_itors;
child_itors child_range(const std::string& key);
const_child_itors child_range(const std::string& key) const;
unsigned child_count(const std::string &key) const;
child_itors child_range(config_key_type key);
const_child_itors child_range(config_key_type key) const;
unsigned child_count(config_key_type key) const;
unsigned all_children_count() const;
/** Count the number of non-blank attributes */
unsigned attribute_count() const;
@ -467,12 +479,12 @@ public:
*
* @returns Whether a child is available.
*/
bool has_child(const std::string& key) const;
bool has_child(config_key_type key) const;
/**
* Returns the first child with the given @a key, or an empty config if there is none.
*/
const config & child_or_empty(const std::string &key) const;
const config & child_or_empty(config_key_type key) const;
/**
* Returns the nth child with the given @a key, or
@ -480,30 +492,16 @@ public:
* @note A negative @a n accesses from the end of the object.
* For instance, -1 is the index of the last child.
*/
config &child(const std::string& key, int n = 0);
config &child(config_key_type key, int n = 0);
#ifdef USE_HETEROGENOUS_LOOKUPS
template<int N>
config &child(const char(&key)[N], int n = 0)
{ return child_impl(key, N - 1, n); }
private:
config &child_impl(const char* key, int len, int n = 0);
public:
#endif
/**
* Returns the nth child with the given @a key, or
* a reference to an invalid config if there is none.
* @note A negative @a n accesses from the end of the object.
* For instance, -1 is the index of the last child.
*/
const config &child(const std::string& key, int n = 0) const
const config& child(config_key_type key, int n = 0) const
{ return const_cast<config *>(this)->child(key, n); }
#ifdef USE_HETEROGENOUS_LOOKUPS
template<int N>
const config &child(const char(&key)[N], int n = 0) const
{ return const_cast<config *>(this)->child_impl(key, N- 1, n); }
#endif
/**
* Returns a mandatory child node.
*
@ -518,7 +516,7 @@ public:
*
* @returns The wanted child node.
*/
config& child(const std::string& key, const std::string& parent);
config& child(config_key_type key, const std::string& parent);
/**
* Returns a mandatory child node.
@ -535,72 +533,54 @@ public:
* @returns The wanted child node.
*/
const config& child(
const std::string& key
config_key_type key
, const std::string& parent) const;
config& add_child(const std::string& key);
config& add_child(const std::string& key, const config& val);
config& add_child_at(const std::string &key, const config &val, unsigned index);
config& add_child(config_key_type key);
config& add_child(config_key_type key, const config& val);
config& add_child_at(config_key_type key, const config &val, unsigned index);
config &add_child(const std::string &key, config &&val);
config &add_child(config_key_type key, config &&val);
/**
* Returns a reference to the attribute with the given @a key.
* Creates it if it does not exist.
*/
attribute_value &operator[](const std::string &key);
attribute_value &operator[](config_key_type key);
/**
* Returns a reference to the attribute with the given @a key
* or to a dummy empty attribute if it does not exist.
*/
const attribute_value &operator[](const std::string &key) const;
const attribute_value &operator[](config_key_type 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<int N>
inline const attribute_value &operator[](const char (&key)[N]) const
{
//-1 for the terminating null character.
return get_attribute(key, N - 1);
}
template<int N>
inline attribute_value& operator[](const char (&key)[N])
{
return (*this)[std::string(key)];
}
#endif
/**
* Returns a pointer to the attribute with the given @a key
* or nullptr if it does not exist.
*/
const attribute_value *get(const std::string &key) const;
const attribute_value *get(config_key_type key) const;
/**
* Function to handle backward compatibility
* Get the value of key and if missing try old_key
* and log msg as a WML error (if not empty)
*/
const attribute_value &get_old_attribute(const std::string &key, const std::string &old_key, const std::string& msg = "") const;
const attribute_value &get_old_attribute(config_key_type key, const std::string &old_key, const std::string& msg = "") const;
/**
* Returns a reference to the first child with the given @a key.
* Creates the child if it does not yet exist.
*/
config &child_or_add(const std::string &key);
config &child_or_add(config_key_type key);
bool has_attribute(const std::string &key) const;
bool has_attribute(config_key_type key) const;
/**
* Function to handle backward compatibility
* Check if has key or old_key
* and log msg as a WML error (if not empty)
*/
bool has_old_attribute(const std::string &key, const std::string &old_key, const std::string& msg = "") const;
bool has_old_attribute(config_key_type key, const std::string &old_key, const std::string& msg = "") const;
void remove_attribute(const std::string &key);
void remove_attribute(config_key_type key);
void merge_attributes(const config &);
template<typename... T>
void remove_attributes(T... keys) {
@ -616,18 +596,18 @@ public:
* Returns the first child of tag @a key with a @a name attribute
* containing @a value.
*/
config &find_child(const std::string &key, const std::string &name,
config& find_child(config_key_type key, const std::string &name,
const std::string &value);
const config &find_child(const std::string &key, const std::string &name,
const config& find_child(config_key_type key, const std::string &name,
const std::string &value) const
{ return const_cast<config *>(this)->find_child(key, name, value); }
void clear_children(const std::string& key);
void clear_children_impl(config_key_type key);
template<typename... T>
void clear_children(T... keys) {
for(std::string key : {keys...}) {
clear_children(key);
for(auto key : {keys...}) {
clear_children_impl(key);
}
}
@ -636,8 +616,8 @@ public:
*/
void splice_children(config &src, const std::string &key);
void remove_child(const std::string &key, unsigned index);
void recursive_clear_value(const std::string& key);
void remove_child(config_key_type key, unsigned index);
void recursive_clear_value(config_key_type key);
void clear();
bool empty() const;
@ -872,9 +852,6 @@ public:
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.
*/