Reformat config and config attribute code

This commit is contained in:
Charles Dang 2017-05-22 10:49:13 +11:00
parent 96ca0b026e
commit 1707070d6f
2 changed files with 438 additions and 318 deletions

File diff suppressed because it is too large Load diff

View file

@ -23,13 +23,13 @@
#include "lexical_cast.hpp"
#include "log.hpp"
#include "utils/const_clone.hpp"
#include "utils/functional.hpp"
#include <cstdlib>
#include <cstring>
#include <deque>
#include <istream>
#include "utils/functional.hpp"
#include <boost/variant/apply_visitor.hpp>
#include <boost/variant/get.hpp>
#include <boost/variant/static_visitor.hpp>
@ -39,14 +39,12 @@ static lg::log_domain log_config("config");
#define ERR_CF LOG_STREAM(err, log_config)
#define DBG_CF LOG_STREAM(debug, log_config)
// Special string values.
const std::string config_attribute_value::s_yes("yes");
const std::string config_attribute_value::s_no("no");
const std::string config_attribute_value::s_true("true");
const std::string config_attribute_value::s_false("false");
/** Default implementation, but defined out-of-line for efficiency reasons. */
config_attribute_value::config_attribute_value()
: value_()
@ -59,39 +57,41 @@ config_attribute_value::~config_attribute_value()
}
/** Default implementation, but defined out-of-line for efficiency reasons. */
config_attribute_value::config_attribute_value(const config_attribute_value &that)
config_attribute_value::config_attribute_value(const config_attribute_value& that)
: value_(that.value_)
{
}
/** Default implementation, but defined out-of-line for efficiency reasons. */
config_attribute_value &config_attribute_value::operator=(const config_attribute_value &that)
config_attribute_value& config_attribute_value::operator=(const config_attribute_value& that)
{
value_ = that.value_;
return *this;
}
config_attribute_value &config_attribute_value::operator=(bool v)
config_attribute_value& config_attribute_value::operator=(bool v)
{
value_ = yes_no(v);
return *this;
}
config_attribute_value &config_attribute_value::operator=(int v)
config_attribute_value& config_attribute_value::operator=(int v)
{
value_ = v;
return *this;
}
config_attribute_value &config_attribute_value::operator=(long long v)
config_attribute_value& config_attribute_value::operator=(long long v)
{
if ( v > 0 )
if(v > 0) {
// We can store this unsigned.
return *this = static_cast<unsigned long long>(v);
}
if ( v >= INT_MIN )
if(v >= INT_MIN) {
// We can store this as an int.
return *this = static_cast<int>(v);
}
// Getting to this point should be rare. (Currently, getting here means
// something like there was so much draining in a campaign that the
@ -102,30 +102,32 @@ config_attribute_value &config_attribute_value::operator=(long long v)
return *this;
}
config_attribute_value &config_attribute_value::operator=(unsigned long long v)
config_attribute_value& config_attribute_value::operator=(unsigned long long v)
{
// Use int for smaller numbers.
if ( v <= INT_MAX )
if(v <= INT_MAX) {
return *this = static_cast<int>(v);
}
value_ = v;
return *this;
}
config_attribute_value &config_attribute_value::operator=(double v)
config_attribute_value& config_attribute_value::operator=(double v)
{
// Try to store integers in other types.
if ( v > 0.0 ) {
if(v > 0.0) {
// Convert to unsigned and pass this off to that assignment operator.
unsigned long long ull = static_cast<unsigned long long>(v);
if ( static_cast<double>(ull) == v )
if(static_cast<double>(ull) == v) {
return *this = ull;
}
else {
}
} else {
// Convert to integer and pass this off to that assignment operator.
int i = static_cast<int>(v);
if ( static_cast<double>(i) == v )
if(static_cast<double>(i) == v) {
return *this = i;
}
}
// If we get here, this does in fact get stored as a double.
@ -133,55 +135,78 @@ config_attribute_value &config_attribute_value::operator=(double v)
return *this;
}
namespace {
/**
* Attempts to convert @a source to the template type.
* This is to avoid "overzealous reinterpretations of certain WML strings as
* numeric types" (c.f. bug #19201).
* @returns true if the conversion was successful and the source string
* can be reobtained by streaming the result.
*/
template<typename To>
bool from_string_verify(const std::string & source, To & res)
{
// Check 1: convertable to the target type.
std::istringstream in_str(source);
if ( !(in_str >> res) )
return false;
// Check 2: convertable back to the same string.
std::ostringstream out_str;
out_str << res;
return out_str.str() == source;
namespace
{
/**
* Attempts to convert @a source to the template type.
* This is to avoid "overzealous reinterpretations of certain WML strings as
* numeric types" (c.f. bug #19201).
* @returns true if the conversion was successful and the source string
* can be reobtained by streaming the result.
*/
template<typename To>
bool from_string_verify(const std::string& source, To& res)
{
// Check 1: convertable to the target type.
std::istringstream in_str(source);
if(!(in_str >> res)) {
return false;
}
// Check 2: convertable back to the same string.
std::ostringstream out_str;
out_str << res;
return out_str.str() == source;
}
config_attribute_value &config_attribute_value::operator=(const std::string &v)
} // end anon namespace
config_attribute_value& config_attribute_value::operator=(const std::string& v)
{
// Handle some special strings.
if (v.empty()) { value_ = v; return *this; }
if ( v == s_yes ) { value_ = yes_no(true); return *this; }
if ( v == s_no ) { value_ = yes_no(false); return *this; }
if ( v == s_true ) { value_ = true_false(true); return *this; }
if ( v == s_false ) { value_ = true_false(false); return *this; }
if(v.empty()) {
value_ = v;
return *this;
}
if(v == s_yes) {
value_ = yes_no(true);
return *this;
}
if(v == s_no) {
value_ = yes_no(false);
return *this;
}
if(v == s_true) {
value_ = true_false(true);
return *this;
}
if(v == s_false) {
value_ = true_false(false);
return *this;
}
// Attempt to convert to a number.
char *eptr;
char* eptr;
double d = strtod(v.c_str(), &eptr);
if ( *eptr == '\0' ) {
if(*eptr == '\0') {
// Possibly a number. See what type it should be stored in.
// (All conversions will be from the string since the largest integer
// type could have more precision than a double.)
if ( d > 0.0 ) {
if(d > 0.0) {
// The largest type for positive integers is unsigned long long.
unsigned long long ull = 0;
if ( from_string_verify<unsigned long long>(v, ull) )
if(from_string_verify<unsigned long long>(v, ull)) {
return *this = ull;
}
else {
}
} else {
// The largest (variant) type for negative integers is int.
int i = 0;
if ( from_string_verify<int>(v, i) )
if(from_string_verify<int>(v, i)) {
return *this = i;
}
}
// This does not look like an integer, so it should be a double.
@ -189,7 +214,7 @@ config_attribute_value &config_attribute_value::operator=(const std::string &v)
// case this is a string that just looks like a numeric value).
std::ostringstream tester;
tester << d;
if ( tester.str() == v ) {
if(tester.str() == v) {
value_ = d;
return *this;
}
@ -200,46 +225,49 @@ config_attribute_value &config_attribute_value::operator=(const std::string &v)
return *this;
}
config_attribute_value &config_attribute_value::operator=(const t_string &v)
config_attribute_value& config_attribute_value::operator=(const t_string& v)
{
if (!v.translatable()) return *this = v.str();
if(!v.translatable()) {
return *this = v.str();
}
value_ = v;
return *this;
}
bool config_attribute_value::to_bool(bool def) const
{
if ( const yes_no *p = boost::get<const yes_no>(&value_) )
if(const yes_no* p = boost::get<const yes_no>(&value_))
return *p;
if ( const true_false *p = boost::get<const true_false>(&value_) )
if(const true_false* p = boost::get<const true_false>(&value_))
return *p;
// No other types are ever recognized as boolean.
return def;
}
namespace {
/// Visitor for converting a variant to a numeric type (T).
template <typename T>
class attribute_numeric_visitor : public boost::static_visitor<T>
{
public:
// Constructor stores the default value.
attribute_numeric_visitor(T def) : def_(def) {}
namespace
{
/// Visitor for converting a variant to a numeric type (T).
template<typename T>
class attribute_numeric_visitor : public boost::static_visitor<T>
{
public:
// Constructor stores the default value.
attribute_numeric_visitor(T def) : def_(def) {}
T operator()(boost::blank const &) const { return def_; }
T operator()(bool) const { return def_; }
T operator()(int i) const { return static_cast<T>(i); }
T operator()(unsigned long long u) const { return static_cast<T>(u); }
T operator()(double d) const { return static_cast<T>(d); }
T operator()(const std::string& s) const { return lexical_cast_default<T>(s, def_); }
T operator()(t_string const &) const { return def_; }
T operator()(boost::blank const &) const { return def_; }
T operator()(bool) const { return def_; }
T operator()(int i) const { return static_cast<T>(i); }
T operator()(unsigned long long u) const { return static_cast<T>(u); }
T operator()(double d) const { return static_cast<T>(d); }
T operator()(const std::string& s) const { return lexical_cast_default<T>(s, def_); }
T operator()(t_string const &) const { return def_; }
private:
const T def_;
};
}
private:
const T def_;
};
} // end anon namespace
int config_attribute_value::to_int(int def) const
{
@ -272,12 +300,13 @@ double config_attribute_value::to_double(double def) const
}
/// Visitor for converting a variant to a string.
class config_attribute_value::string_visitor
: public boost::static_visitor<std::string>
class config_attribute_value::string_visitor : public boost::static_visitor<std::string>
{
const std::string default_;
public:
string_visitor(const std::string& fallback) : default_(fallback) {}
std::string operator()(const boost::blank &) const { return default_; }
std::string operator()(const yes_no & b) const { return b.str(); }
std::string operator()(const true_false & b) const { return b.str(); }
@ -295,7 +324,10 @@ std::string config_attribute_value::str(const std::string& fallback) const
t_string config_attribute_value::t_str() const
{
if (const t_string *p = boost::get<const t_string>(&value_)) return *p;
if(const t_string* p = boost::get<const t_string>(&value_)) {
return *p;
}
return str();
}
@ -312,28 +344,45 @@ bool config_attribute_value::blank() const
*/
bool config_attribute_value::empty() const
{
if (boost::get<const boost::blank>(&value_)) return true;
if (const std::string *p = boost::get<const std::string>(&value_)) return p->empty();
if(boost::get<const boost::blank>(&value_)) {
return true;
}
if(const std::string* p = boost::get<const std::string>(&value_)) {
return p->empty();
}
return false;
}
/// Visitor handling equality checks.
class config_attribute_value::equality_visitor
: public boost::static_visitor<bool>
class config_attribute_value::equality_visitor : public boost::static_visitor<bool>
{
public:
// Most generic: not equal.
template <typename T, typename U>
bool operator()(const T &, const U &) const { return false; }
template<typename T, typename U>
bool operator()(const T&, const U&) const
{
return false;
}
// Same types are comparable and might be equal.
template <typename T>
bool operator()(const T & lhs, const T & rhs) const { return lhs == rhs; }
template<typename T>
bool operator()(const T& lhs, const T& rhs) const
{
return lhs == rhs;
}
// Boolean values can be compared.
bool operator()(const true_false & lhs, const yes_no & rhs) const { return bool(lhs) == bool(rhs); }
bool operator()(const yes_no & lhs, const true_false & rhs) const { return bool(lhs) == bool(rhs); }
bool operator()(const true_false& lhs, const yes_no& rhs) const
{
return bool(lhs) == bool(rhs);
}
bool operator()(const yes_no& lhs, const true_false& rhs) const
{
return bool(lhs) == bool(rhs);
}
};
/**
@ -341,7 +390,7 @@ public:
* Exception: Boolean synonyms can be equal ("yes" == "true").
* Note: Blanks have no string representation, so do not equal "" (an empty string).
*/
bool config_attribute_value::operator==(const config_attribute_value &other) const
bool config_attribute_value::operator==(const config_attribute_value& other) const
{
return boost::apply_visitor(equality_visitor(), value_, other.value_);
}
@ -352,7 +401,7 @@ bool config_attribute_value::operator==(const config_attribute_value &other) con
* Note: Blanks have no string representation, so do not equal "" (an empty string).
* Also note that translatable string are never equal to non translatable strings.
*/
bool config_attribute_value::equals(const std::string &str) const
bool config_attribute_value::equals(const std::string& str) const
{
config_attribute_value v;
v = str;
@ -363,7 +412,7 @@ bool config_attribute_value::equals(const std::string &str) const
// that's why we don't use it.
}
std::ostream &operator<<(std::ostream &os, const config_attribute_value &v)
std::ostream& operator<<(std::ostream& os, const config_attribute_value& v)
{
// Simple implementation, but defined out-of-line because of the templating
// involved.