move variable_info to own file

and also move game_data::temporarites_ to that file as a static
variable.

This fixes variable_info being dependent on game_data.
This commit is contained in:
gfgtdf 2014-06-29 03:48:57 +02:00
parent 16938d397d
commit 5d3040c0b8
8 changed files with 266 additions and 209 deletions

View file

@ -905,6 +905,7 @@ set(wesnoth-main_SRC
unit_types.cpp
utils/sha1.cpp
variable.cpp
variable_info.cpp
variant.cpp
whiteboard/action.cpp
whiteboard/attack.cpp

View file

@ -537,6 +537,7 @@ wesnoth_sources = Split("""
unit_types.cpp
utils/sha1.cpp
variable.cpp
variable_info.cpp
variant.cpp
whiteboard/action.cpp
whiteboard/attack.cpp

View file

@ -75,7 +75,6 @@ game_data::game_data()
, wml_menu_items_()
, rng_()
, variables_()
, temporaries_()
, phase_(INITIAL)
, can_end_turn_(true)
, scenario_()
@ -88,7 +87,6 @@ game_data::game_data(const config& level)
, wml_menu_items_()
, rng_(level)
, variables_(level.child_or_empty("variables"))
, temporaries_()
, phase_(INITIAL)
, can_end_turn_(level["can_end_turn"].to_bool(true))
, scenario_(level["id"])
@ -104,7 +102,6 @@ game_data::game_data(const game_data& data)
, wml_menu_items_(data.wml_menu_items_)
, rng_(data.rng_)
, variables_(data.variables_)
, temporaries_()
, phase_(data.phase_)
, can_end_turn_(data.can_end_turn_)
, scenario_(data.scenario_)
@ -121,7 +118,7 @@ config::attribute_value game_data::get_variable_const(const std::string &key) co
variable_info to_get = get_variable_access(key, false, variable_info::TYPE_SCALAR);
if (!to_get.is_valid)
{
config::attribute_value &to_return = temporaries_[key];
config::attribute_value &to_return = variable_info::get_temporaries()[key];
if (key.size() > 7 && key.substr(key.size() - 7) == ".length") {
// length is a special attribute, so guarantee its correctness
to_return = 0;

View file

@ -22,7 +22,7 @@
#include "game_events/wmi_container.hpp"
#include "map_location.hpp"
#include "simple_rng.hpp"
#include "variable.hpp"
#include "variable_info.hpp"
#include <boost/shared_ptr.hpp>
@ -117,7 +117,6 @@ private:
game_events::wmi_container wml_menu_items_;
rand_rng::simple_rng rng_;
config variables_;
mutable config temporaries_; // lengths of arrays, etc.
friend struct variable_info;
PHASE phase_;
bool can_end_turn_;

View file

@ -443,174 +443,3 @@ void scoped_recall_unit::activate()
}
variable_info::variable_info(config& source, const std::string& varname,
bool force_valid, TYPE validation_type) :
vartype(validation_type),
is_valid(false),
key(),
explicit_index(false),
index(0),
vars(NULL)
{
vars = &source;//&resources::gamedata->variables_;
key = varname;
std::string::const_iterator itor = std::find(key.begin(),key.end(),'.');
int dot_index = key.find('.');
bool force_length = false;
// example varname = "unit_store.modifications.trait[0]"
while(itor != key.end()) { // subvar access
std::string element=key.substr(0,dot_index);
key = key.substr(dot_index+1);
size_t inner_index = 0;
const std::string::iterator index_start = std::find(element.begin(),element.end(),'[');
const bool inner_explicit_index = index_start != element.end();
if(inner_explicit_index) {
const std::string::iterator index_end = std::find(index_start,element.end(),']');
const std::string index_str(index_start+1,index_end);
inner_index = static_cast<size_t>(lexical_cast_default<int>(index_str));
if(inner_index > game_config::max_loop) {
ERR_NG << "variable_info: index greater than " << game_config::max_loop
<< ", truncated\n";
inner_index = game_config::max_loop;
}
element = std::string(element.begin(),index_start);
}
size_t size = vars->child_count(element);
if(size <= inner_index) {
if(force_valid) {
// Add elements to the array until the requested size is attained
if(inner_explicit_index || key != "length") {
for(; size <= inner_index; ++size) {
vars->add_child(element);
}
}
} else if(inner_explicit_index) {
WRN_NG << "variable_info: invalid WML array index, "
<< varname << std::endl;
return;
} else if(varname.length() >= 7 && varname.substr(varname.length()-7) == ".length") {
// require '.' to avoid matching suffixes -> requires varname over key to always find length
// return length 0 for non-existent WML array (handled below)
force_length = true;
} else {
WRN_NG << "variable_info: retrieving member of non-existent WML container, "
<< varname << std::endl;
return;
}
}
if((!inner_explicit_index && key == "length") || force_length) {
switch(vartype) {
case variable_info::TYPE_ARRAY:
case variable_info::TYPE_CONTAINER:
WRN_NG << "variable_info: using reserved WML variable as wrong type, "
<< varname << std::endl;
is_valid = force_valid || resources::gamedata->temporaries_.child(varname);
break;
case variable_info::TYPE_SCALAR:
default:
// Store the length of the array as a temporary variable
resources::gamedata->temporaries_[varname] = int(size);
is_valid = true;
break;
}
key = varname;
vars = &resources::gamedata->temporaries_;
return;
}
vars = &vars->child(element, inner_index);
itor = std::find(key.begin(),key.end(),'.');
dot_index = key.find('.');
} // end subvar access
const std::string::iterator index_start = std::find(key.begin(),key.end(),'[');
explicit_index = index_start != key.end();
if(explicit_index) {
const std::string::iterator index_end = std::find(index_start,key.end(),']');
const std::string index_str(index_start+1,index_end);
index = static_cast<size_t>(lexical_cast_default<int>(index_str));
if(index > game_config::max_loop) {
ERR_NG << "variable_info: index greater than " << game_config::max_loop
<< ", truncated\n";
index = game_config::max_loop;
}
key = std::string(key.begin(),index_start);
size_t size = vars->child_count(key);
if(size <= index) {
if(!force_valid) {
WRN_NG << "variable_info: invalid WML array index, " << varname << std::endl;
return;
}
for(; size <= index; ++size) {
vars->add_child(key);
}
}
switch(vartype) {
case variable_info::TYPE_ARRAY:
vars = &vars->child(key, index);
key = "__array";
is_valid = force_valid || vars->child(key);
break;
case variable_info::TYPE_SCALAR:
vars = &vars->child(key, index);
key = "__value";
is_valid = force_valid || vars->has_attribute(key);
break;
case variable_info::TYPE_CONTAINER:
case variable_info::TYPE_UNSPECIFIED:
default:
is_valid = true;
return;
}
if (force_valid) {
WRN_NG << "variable_info: using explicitly indexed "
"container as wrong WML type, " << varname << '\n';
}
explicit_index = false;
index = 0;
} else {
// Final variable is not an explicit index [...]
switch(vartype) {
case variable_info::TYPE_ARRAY:
case variable_info::TYPE_CONTAINER:
is_valid = force_valid || vars->child(key);
break;
case variable_info::TYPE_SCALAR:
is_valid = force_valid || vars->has_attribute(key);
break;
case variable_info::TYPE_UNSPECIFIED:
default:
is_valid = true;
break;
}
}
}
config::attribute_value &variable_info::as_scalar()
{
assert(is_valid);
return (*vars)[key];
}
config& variable_info::as_container() {
assert(is_valid);
if(explicit_index) {
// Empty data for explicit index was already created if it was needed
return vars->child(key, index);
}
if (config &temp = vars->child(key)) {
// The container exists, index not specified, return index 0
return temp;
}
// Add empty data for the new variable, since it does not exist yet
return vars->add_child(key);
}
variable_info::array_range variable_info::as_array() {
assert(is_valid);
return vars->child_range(key);
}

View file

@ -209,36 +209,4 @@ private:
unsigned int recall_index_;
};
/** Information on a WML variable. */
struct variable_info
{
typedef config::child_itors array_range;
/**
* TYPE: the correct variable type should be decided by the user of the info structure
* Note: an Array can also be considered a Container, since index 0 will be used by default
*/
enum TYPE { TYPE_SCALAR, //a Scalar variable resolves to a t_string attribute of *vars
TYPE_ARRAY, //an Array variable is a series of Containers
TYPE_CONTAINER, //a Container is a specific index of an Array (contains Scalars)
TYPE_UNSPECIFIED };
variable_info(config& source, const std::string& varname, bool force_valid=true,
TYPE validation_type=TYPE_UNSPECIFIED);
TYPE vartype; //default is TYPE_UNSPECIFIED
bool is_valid;
std::string key; //the name of the internal attribute or child
bool explicit_index; //true if query ended in [...] specifier
size_t index; //the index of the child
config *vars; //the containing node in game_data s variables
/**
* 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
*/
config::attribute_value &as_scalar();
config& as_container();
array_range as_array(); //range may be empty
};
#endif

210
src/variable_info.cpp Normal file
View file

@ -0,0 +1,210 @@
/*
Copyright (C) 2003 by David White <dave@whitevine.net>
Copyright (C) 2005 - 2014 by Philippe Plantier <ayin@anathas.org>
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
/**
* @file
* Manage WML-variables.
*/
#include "global.hpp"
#include "variable_info.hpp"
#include "log.hpp"
#include "game_config.hpp"
#include "util.hpp"
static lg::log_domain log_engine("engine");
#define LOG_NG LOG_STREAM(info, log_engine)
#define WRN_NG LOG_STREAM(warn, log_engine)
#define ERR_NG LOG_STREAM(err, log_engine)
namespace {
config temporaries;// lengths of arrays, etc.
}
config& variable_info::get_temporaries() { return temporaries; }
variable_info::variable_info(config& source, const std::string& varname,
bool force_valid, TYPE validation_type) :
vartype(validation_type),
is_valid(false),
key(),
explicit_index(false),
index(0),
vars(NULL)
{
vars = &source;//&resources::gamedata->variables_;
key = varname;
std::string::const_iterator itor = std::find(key.begin(),key.end(),'.');
int dot_index = key.find('.');
bool force_length = false;
// example varname = "unit_store.modifications.trait[0]"
while(itor != key.end()) { // subvar access
std::string element=key.substr(0,dot_index);
key = key.substr(dot_index+1);
size_t inner_index = 0;
const std::string::iterator index_start = std::find(element.begin(),element.end(),'[');
const bool inner_explicit_index = index_start != element.end();
if(inner_explicit_index) {
const std::string::iterator index_end = std::find(index_start,element.end(),']');
const std::string index_str(index_start+1,index_end);
inner_index = static_cast<size_t>(lexical_cast_default<int>(index_str));
if(inner_index > game_config::max_loop) {
ERR_NG << "variable_info: index greater than " << game_config::max_loop
<< ", truncated\n";
inner_index = game_config::max_loop;
}
element = std::string(element.begin(),index_start);
}
size_t size = vars->child_count(element);
if(size <= inner_index) {
if(force_valid) {
// Add elements to the array until the requested size is attained
if(inner_explicit_index || key != "length") {
for(; size <= inner_index; ++size) {
vars->add_child(element);
}
}
} else if(inner_explicit_index) {
WRN_NG << "variable_info: invalid WML array index, "
<< varname << std::endl;
return;
} else if(varname.length() >= 7 && varname.substr(varname.length()-7) == ".length") {
// require '.' to avoid matching suffixes -> requires varname over key to always find length
// return length 0 for non-existent WML array (handled below)
force_length = true;
} else {
WRN_NG << "variable_info: retrieving member of non-existent WML container, "
<< varname << std::endl;
return;
}
}
if((!inner_explicit_index && key == "length") || force_length) {
switch(vartype) {
case variable_info::TYPE_ARRAY:
case variable_info::TYPE_CONTAINER:
WRN_NG << "variable_info: using reserved WML variable as wrong type, "
<< varname << std::endl;
is_valid = force_valid || temporaries.child(varname);
break;
case variable_info::TYPE_SCALAR:
default:
// Store the length of the array as a temporary variable
temporaries[varname] = int(size);
is_valid = true;
break;
}
key = varname;
vars = &temporaries;
return;
}
vars = &vars->child(element, inner_index);
itor = std::find(key.begin(),key.end(),'.');
dot_index = key.find('.');
} // end subvar access
const std::string::iterator index_start = std::find(key.begin(),key.end(),'[');
explicit_index = index_start != key.end();
if(explicit_index) {
const std::string::iterator index_end = std::find(index_start,key.end(),']');
const std::string index_str(index_start+1,index_end);
index = static_cast<size_t>(lexical_cast_default<int>(index_str));
if(index > game_config::max_loop) {
ERR_NG << "variable_info: index greater than " << game_config::max_loop
<< ", truncated\n";
index = game_config::max_loop;
}
key = std::string(key.begin(),index_start);
size_t size = vars->child_count(key);
if(size <= index) {
if(!force_valid) {
WRN_NG << "variable_info: invalid WML array index, " << varname << std::endl;
return;
}
for(; size <= index; ++size) {
vars->add_child(key);
}
}
switch(vartype) {
case variable_info::TYPE_ARRAY:
vars = &vars->child(key, index);
key = "__array";
is_valid = force_valid || vars->child(key);
break;
case variable_info::TYPE_SCALAR:
vars = &vars->child(key, index);
key = "__value";
is_valid = force_valid || vars->has_attribute(key);
break;
case variable_info::TYPE_CONTAINER:
case variable_info::TYPE_UNSPECIFIED:
default:
is_valid = true;
return;
}
if (force_valid) {
WRN_NG << "variable_info: using explicitly indexed "
"container as wrong WML type, " << varname << '\n';
}
explicit_index = false;
index = 0;
} else {
// Final variable is not an explicit index [...]
switch(vartype) {
case variable_info::TYPE_ARRAY:
case variable_info::TYPE_CONTAINER:
is_valid = force_valid || vars->child(key);
break;
case variable_info::TYPE_SCALAR:
is_valid = force_valid || vars->has_attribute(key);
break;
case variable_info::TYPE_UNSPECIFIED:
default:
is_valid = true;
break;
}
}
}
config::attribute_value &variable_info::as_scalar()
{
assert(is_valid);
return (*vars)[key];
}
config& variable_info::as_container() {
assert(is_valid);
if(explicit_index) {
// Empty data for explicit index was already created if it was needed
return vars->child(key, index);
}
if (config &temp = vars->child(key)) {
// The container exists, index not specified, return index 0
return temp;
}
// Add empty data for the new variable, since it does not exist yet
return vars->add_child(key);
}
variable_info::array_range variable_info::as_array() {
assert(is_valid);
return vars->child_range(key);
}

52
src/variable_info.hpp Normal file
View file

@ -0,0 +1,52 @@
/*
Copyright (C) 2003 by David White <dave@whitevine.net>
Copyright (C) 2005 - 2014 by Philippe Plantier <ayin@anathas.org>
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
/** Information on a WML variable. */
#include "config.hpp"
#include <string>
struct variable_info
{
typedef config::child_itors array_range;
/**
* TYPE: the correct variable type should be decided by the user of the info structure
* Note: an Array can also be considered a Container, since index 0 will be used by default
*/
enum TYPE { TYPE_SCALAR, //a Scalar variable resolves to a t_string attribute of *vars
TYPE_ARRAY, //an Array variable is a series of Containers
TYPE_CONTAINER, //a Container is a specific index of an Array (contains Scalars)
TYPE_UNSPECIFIED };
variable_info(config& source, const std::string& varname, bool force_valid=true,
TYPE validation_type=TYPE_UNSPECIFIED);
TYPE vartype; //default is TYPE_UNSPECIFIED
bool is_valid;
std::string key; //the name of the internal attribute or child
bool explicit_index; //true if query ended in [...] specifier
size_t index; //the index of the child
config *vars; //the containing node in game_data s variables
/**
* 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
*/
config::attribute_value &as_scalar();
config& as_container();
array_range as_array(); //range may be empty
static config& get_temporaries();
};