Prevented t_string non-const references from being returned by functions.
(Original patch #1139 by Frank Richter.) This avoids leaking an implementation detail from the config class and opens the door to a considerable reduction of the memory footprint of lexical data.
This commit is contained in:
parent
ddd0dab6f0
commit
1896b603f1
16 changed files with 71 additions and 47 deletions
|
@ -82,6 +82,9 @@
|
|||
comment = "Naming hotseat players, delay shroud updates on game start."
|
||||
ircuser = "gabm"
|
||||
[/entry]
|
||||
[entry]
|
||||
name = "Frank Richter (res)"
|
||||
[/entry]
|
||||
[entry]
|
||||
name = "Greg Copeland (Oracle)"
|
||||
comment = "coding; Server optimizations."
|
||||
|
|
|
@ -396,13 +396,6 @@ void config::remove_child(const std::string& key, size_t index)
|
|||
delete res;
|
||||
}
|
||||
|
||||
t_string& config::operator[](const std::string& key)
|
||||
{
|
||||
check_valid();
|
||||
|
||||
return values[key];
|
||||
}
|
||||
|
||||
const t_string& config::operator[](const std::string& key) const
|
||||
{
|
||||
return get_attribute(key);
|
||||
|
|
|
@ -176,6 +176,39 @@ public:
|
|||
Itor i_;
|
||||
};
|
||||
|
||||
class proxy_string
|
||||
{
|
||||
t_string &real_str_;
|
||||
public:
|
||||
proxy_string(config &owner, const std::string &key)
|
||||
: real_str_(owner.values[key]) {}
|
||||
|
||||
proxy_string &operator=(const proxy_string &other)
|
||||
{ return this->operator=(other.real_str_); }
|
||||
|
||||
proxy_string& operator=(const char *str)
|
||||
{ real_str_ = str; return *this; }
|
||||
proxy_string& operator=(const t_string &str)
|
||||
{ real_str_ = str; return *this; }
|
||||
proxy_string& operator=(const std::string &str)
|
||||
{ real_str_ = str; return *this; }
|
||||
|
||||
proxy_string& operator+=(const std::string &str)
|
||||
{ real_str_ += str; return *this; }
|
||||
|
||||
// t_string 'emulation' methods
|
||||
bool empty() const { return real_str_.empty(); }
|
||||
const char *c_str() const { return real_str_.c_str(); }
|
||||
std::string to_serialized() const { return real_str_.to_serialized(); }
|
||||
|
||||
const std::string &str() const { return real_str_.str(); }
|
||||
operator std::string() const { return real_str_.str(); }
|
||||
operator t_string() const { return real_str_; }
|
||||
|
||||
inline friend std::ostream& operator<<(std::ostream &os, const proxy_string &str)
|
||||
{ return os << str.real_str_; }
|
||||
};
|
||||
|
||||
typedef std::pair<const_attribute_iterator,const_attribute_iterator> const_attr_itors;
|
||||
|
||||
typedef std::pair<child_list::iterator, child_list::iterator> child_itors_bak;
|
||||
|
@ -206,7 +239,9 @@ public:
|
|||
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, size_t index);
|
||||
t_string& operator[](const std::string& key);
|
||||
|
||||
proxy_string operator[](const std::string& key)
|
||||
{ return proxy_string(*this, key); }
|
||||
const t_string& operator[](const std::string& key) const;
|
||||
|
||||
/**
|
||||
|
|
|
@ -30,13 +30,11 @@ class string_map_variable_set : public variable_set
|
|||
public:
|
||||
string_map_variable_set(const string_map& map) : map_(map) {};
|
||||
|
||||
virtual const t_string& get_variable_const (const std::string& key) const
|
||||
virtual t_string get_variable_const (const std::string& key) const
|
||||
{
|
||||
static const t_string empty_string = "";
|
||||
|
||||
const string_map::const_iterator itor = map_.find(key);
|
||||
if(itor == map_.end()) {
|
||||
return empty_string;
|
||||
if (itor == map_.end()) {
|
||||
return t_string();
|
||||
} else {
|
||||
return itor->second;
|
||||
}
|
||||
|
|
|
@ -176,7 +176,7 @@ namespace {
|
|||
}
|
||||
private:
|
||||
static unsigned instance_count;
|
||||
t_string x1_, x2_, y1_, y2_;
|
||||
std::string x1_, x2_, y1_, y2_;
|
||||
};
|
||||
unsigned pump_manager::instance_count=0;
|
||||
|
||||
|
@ -1107,21 +1107,16 @@ WML_HANDLER_FUNCTION(move_unit_fake, /*event_info*/, cfg)
|
|||
}
|
||||
|
||||
// Helper function(s) for [set_variable]
|
||||
namespace {
|
||||
bool isint(const std::string &var) {
|
||||
return var.find('.') == std::string::npos;
|
||||
}
|
||||
bool isint(const t_string &var) {
|
||||
return isint(var.str());
|
||||
}
|
||||
} // End anonymous namespace
|
||||
static bool isint(const std::string &var) {
|
||||
return var.find('.') == std::string::npos;
|
||||
}
|
||||
|
||||
WML_HANDLER_FUNCTION(set_variable, /*event_info*/, cfg)
|
||||
{
|
||||
game_state *state_of_game = resources::state_of_game;
|
||||
|
||||
const std::string name = cfg["name"];
|
||||
t_string& var = state_of_game->get_variable(name);
|
||||
config::proxy_string var = state_of_game->get_variable(name);
|
||||
|
||||
const t_string &literal = cfg.get_config()["literal"]; // no $var substitution
|
||||
if(literal.empty() == false) {
|
||||
|
@ -1163,7 +1158,7 @@ WML_HANDLER_FUNCTION(set_variable, /*event_info*/, cfg)
|
|||
|
||||
const std::string multiply = cfg["multiply"];
|
||||
if(multiply.empty() == false) {
|
||||
if(isint(var) && isint(multiply)) {
|
||||
if(isint(var.str()) && isint(multiply)) {
|
||||
var = str_cast( std::atoi(var.c_str()) * std::atoi(multiply.c_str()) );
|
||||
} else {
|
||||
var = str_cast( std::atof(var.c_str()) * std::atof(multiply.c_str()) );
|
||||
|
@ -1176,7 +1171,7 @@ WML_HANDLER_FUNCTION(set_variable, /*event_info*/, cfg)
|
|||
ERR_NG << "division by zero on variable " << name << "\n";
|
||||
return;
|
||||
}
|
||||
if(isint(var) && isint(divide)) {
|
||||
if(isint(var.str()) && isint(divide)) {
|
||||
var = str_cast( std::atoi(var.c_str()) / std::atoi(divide.c_str()) );
|
||||
} else {
|
||||
var = str_cast( std::atof(var.c_str()) / std::atof(divide.c_str()) );
|
||||
|
@ -1189,7 +1184,7 @@ WML_HANDLER_FUNCTION(set_variable, /*event_info*/, cfg)
|
|||
ERR_NG << "division by zero on variable " << name << "\n";
|
||||
return;
|
||||
}
|
||||
if(isint(var) && isint(modulo)) {
|
||||
if(isint(var.str()) && isint(modulo)) {
|
||||
var = str_cast( std::atoi(var.c_str()) % std::atoi(modulo.c_str()) );
|
||||
} else {
|
||||
double value = std::fmod( std::atof(var.c_str()), std::atof(modulo.c_str()) );
|
||||
|
|
|
@ -462,16 +462,16 @@ void extract_summary_from_config(config& cfg_save, config& cfg_summary)
|
|||
}
|
||||
}
|
||||
|
||||
t_string& game_state::get_variable(const std::string& key)
|
||||
config::proxy_string game_state::get_variable(const std::string& key)
|
||||
{
|
||||
return variable_info(key, true, variable_info::TYPE_SCALAR).as_scalar();
|
||||
}
|
||||
|
||||
const t_string& game_state::get_variable_const(const std::string& key) const
|
||||
t_string game_state::get_variable_const(const std::string& key) const
|
||||
{
|
||||
variable_info to_get(key, false, variable_info::TYPE_SCALAR);
|
||||
if(!to_get.is_valid) {
|
||||
t_string& to_return = temporaries[key];
|
||||
config::proxy_string to_return = temporaries[key];
|
||||
if (key.size() > 7 && key.substr(key.size()-7) == ".length") {
|
||||
// length is a special attribute, so guarantee its correctness
|
||||
to_return = "0";
|
||||
|
|
|
@ -96,8 +96,8 @@ public:
|
|||
|
||||
// Variable access
|
||||
|
||||
t_string& get_variable(const std::string& varname);
|
||||
virtual const t_string& get_variable_const(const std::string& varname) const;
|
||||
config::proxy_string get_variable(const std::string &varname);
|
||||
virtual t_string get_variable_const(const std::string& varname) const;
|
||||
config& get_variable_cfg(const std::string& varname);
|
||||
variable_info::array_range get_variable_cfgs(const std::string& varname);
|
||||
|
||||
|
|
|
@ -1490,8 +1490,8 @@ void connect::lists_init()
|
|||
int side_num = 1;
|
||||
foreach (config &side, sides)
|
||||
{
|
||||
t_string &team_name = side["team_name"];
|
||||
t_string &user_team_name = side["user_team_name"];
|
||||
config::proxy_string team_name = side["team_name"];
|
||||
config::proxy_string user_team_name = side["user_team_name"];
|
||||
|
||||
if(team_name.empty())
|
||||
team_name = lexical_cast<std::string>(side_num);
|
||||
|
@ -1516,7 +1516,7 @@ void connect::lists_init()
|
|||
foreach (config &side, sides)
|
||||
{
|
||||
const std::string side_num = lexical_cast<std::string>(_side_num);
|
||||
t_string &team_name = side["team_name"];
|
||||
config::proxy_string team_name = side["team_name"];
|
||||
|
||||
if(team_name.empty())
|
||||
team_name = side_num;
|
||||
|
|
|
@ -320,8 +320,8 @@ LEVEL_RESULT playsingle_controller::play_scenario(
|
|||
// Log before prestart events: they do weird things.
|
||||
if (first_human_team_ != -1) { //sp logs
|
||||
log.start(gamestate_, teams_[first_human_team_],
|
||||
loading_game_ ? gamestate_.get_variable("turn_number") : "",
|
||||
number_of_turns(), resources::game_map->write());
|
||||
loading_game_ ? gamestate_.get_variable("turn_number").c_str() : "",
|
||||
number_of_turns(), resources::game_map->write());
|
||||
} else { //ai vs. ai upload logs
|
||||
log.start(gamestate_, resources::game_map->write());
|
||||
}
|
||||
|
|
|
@ -248,7 +248,7 @@ void _set_idle_anim_rate(const int rate)
|
|||
preferences::set("idle_anim_rate", lexical_cast<std::string>(rate));
|
||||
}
|
||||
|
||||
const std::string& language()
|
||||
std::string language()
|
||||
{
|
||||
return prefs["locale"];
|
||||
}
|
||||
|
|
|
@ -74,7 +74,7 @@ namespace preferences {
|
|||
int idle_anim_rate();
|
||||
void _set_idle_anim_rate(const int rate);
|
||||
|
||||
const std::string& language();
|
||||
std::string language();
|
||||
void set_language(const std::string& s);
|
||||
|
||||
// Don't rename it to sound() because of a gcc-3.3 branch bug,
|
||||
|
|
|
@ -33,7 +33,7 @@ class variable_set
|
|||
public:
|
||||
virtual ~variable_set();
|
||||
|
||||
virtual const t_string& get_variable_const(const std::string& id) const = 0;
|
||||
virtual t_string get_variable_const(const std::string& id) const = 0;
|
||||
};
|
||||
|
||||
/** The type we use to represent Unicode strings. */
|
||||
|
|
|
@ -166,13 +166,14 @@ static void expand_partialresolution(config& dst_cfg, const config& top_cfg)
|
|||
// follow the inheritance hierarchy and push all the nodes on the stack
|
||||
std::vector<const config*> parent_stack(1, (*i));
|
||||
const config* parent;
|
||||
const t_string* parent_id = &((**i)["inherits"]);
|
||||
while (!*(parent = &top_cfg.find_child("resolution", "id", (*parent_id)))) {
|
||||
parent = &top_cfg.find_child("partialresolution", "id", (*parent_id));
|
||||
std::string parent_id = (**i)["inherits"];
|
||||
while (!*(parent = &top_cfg.find_child("resolution", "id", parent_id)))
|
||||
{
|
||||
parent = &top_cfg.find_child("partialresolution", "id", parent_id);
|
||||
if (!*parent)
|
||||
throw config::error("[partialresolution] refers to non-existant [resolution] " + (*parent_id).str());
|
||||
throw config::error("[partialresolution] refers to non-existant [resolution] " + parent_id);
|
||||
parent_stack.push_back(parent);
|
||||
parent_id = &((*parent)["inherits"]);
|
||||
parent_id = (*parent)["inherits"];
|
||||
}
|
||||
|
||||
// Add the parent resolution and apply all the modifications of its children
|
||||
|
|
|
@ -121,7 +121,6 @@ public:
|
|||
|
||||
operator t_string_base() const { return get(); }
|
||||
t_string& operator=(const t_string& o) { super::operator=(o); return *this; }
|
||||
t_string& operator=(const std::string& o) { super::operator=(base(o)); return *this; }
|
||||
t_string& operator=(const char* o) { super::operator=(base(o)); return *this; }
|
||||
|
||||
t_string operator+(const t_string& o) const { return get() + o.get(); }
|
||||
|
|
|
@ -716,7 +716,7 @@ variable_info::variable_info(const std::string& varname,
|
|||
}
|
||||
}
|
||||
|
||||
t_string& variable_info::as_scalar() {
|
||||
config::proxy_string variable_info::as_scalar() {
|
||||
assert(is_valid);
|
||||
return (*vars)[key];
|
||||
}
|
||||
|
|
|
@ -211,7 +211,7 @@ public:
|
|||
* Results: after deciding the desired type, these methods can retrieve the result
|
||||
* Note: first you should force_valid or check is_valid, otherwise these may fail
|
||||
*/
|
||||
t_string& as_scalar();
|
||||
config::proxy_string as_scalar();
|
||||
config& as_container();
|
||||
array_range as_array(); //range may be empty
|
||||
};
|
||||
|
|
Loading…
Add table
Reference in a new issue