[[t_token optimizations]]

1. Updated terrain_builder to use t_token in place of std::string to
facilitate fast copying, hashing and comparison

2. Added utils::parenthetical_split_token, a cached parenthetical
version of the string version

3. Made the lru_cache faster for the cache miss case.
This commit is contained in:
Thonsew 2011-09-08 19:17:55 +00:00
parent d56fbf14fe
commit 1a5810656b
12 changed files with 379 additions and 167 deletions

View file

@ -34,6 +34,37 @@ static lg::log_domain log_engine("engine");
terrain_builder::building_ruleset terrain_builder::building_rules_;
const config* terrain_builder::rules_cfg_ = NULL;
namespace{
//Static tokens are replacements for string literals in code
//They allow for fast comparison operations.
static const config::t_token z_invalid_tod("invalid_tod", false);
static const config::t_token z_image("image", false);
static const config::t_token z_layer("layer", false);
static const config::t_token z_base("base", false);
static const config::t_token z_center("center", false);
static const config::t_token z_variant("variant", false);
static const config::t_token z_name("name", false);
static const config::t_token z_variations("variations", false);
static const config::t_token z_tod("tod", false);
static const config::t_token z_random_start("random_start", false);
static const config::t_token z_type("type", false);
static const config::t_token z_has_flag("has_flag", false);
static const config::t_token z_set_no_flag("set_no_flag", false);
static const config::t_token z_x("x", false);
static const config::t_token z_y("y", false);
static const config::t_token z_probability("probability", false);
static const config::t_token z_map("map", false);
static const config::t_token z_tile("tile", false);
static const config::t_token z_loc("loc", false);
static const config::t_token z_pos("pos", false);
static const config::t_token z_set_flag("set_flag", false);
static const config::t_token z_no_flag("no_flag", false);
static const config::t_token z_rotations("rotations", false);
static const config::t_token z_precedence("precedence", false);
static const config::t_token z_terrain_graphics("terrain_graphics", false);
}
terrain_builder::rule_image::rule_image(int layer, int x, int y, bool global_image, int cx, int cy) :
layer(layer),
basex(x),
@ -49,11 +80,11 @@ terrain_builder::tile::tile() :
images(),
images_foreground(),
images_background(),
last_tod("invalid_tod"),
last_tod(z_invalid_tod),
sorted_images(false)
{}
void terrain_builder::tile::rebuild_cache(const std::string& tod, logs* log)
void terrain_builder::tile::rebuild_cache(const n_token::t_token& tod, logs* log)
{
images_background.clear();
images_foreground.clear();
@ -97,7 +128,7 @@ void terrain_builder::tile::clear()
sorted_images = false;
images_foreground.clear();
images_background.clear();
last_tod = "invalid_tod";
last_tod = z_invalid_tod;
}
static unsigned int get_noise(const map_location& loc, unsigned int index){
@ -148,7 +179,7 @@ const terrain_builder::tile& terrain_builder::tilemap::operator[] (const map_loc
}
terrain_builder::terrain_builder(const config& level,
const gamemap* m, const std::string& offmap_image) :
const gamemap* m, const n_token::t_token& offmap_image) :
map_(m),
tile_map_(map().w(), map().h()),
terrain_by_type_()
@ -206,7 +237,7 @@ void terrain_builder::change_map(const gamemap* m)
}
const terrain_builder::imagelist *terrain_builder::get_terrain_at(const map_location &loc,
const std::string &tod, const TERRAIN_TYPE terrain_type)
const n_token::t_token &tod, const TERRAIN_TYPE terrain_type)
{
if(!tile_map_.on_map(loc))
return NULL;
@ -285,11 +316,11 @@ void terrain_builder::rebuild_all()
build_terrains();
}
static bool image_exists(const std::string& name)
static bool image_exists(const n_token::t_token& name)
{
bool precached = name.find("..") == std::string::npos;
bool precached = (*name).find("..") == std::string::npos;
if(precached && image::precached_file_exists(n_token::t_token(name))) { //todo remove extra init
if(precached && image::precached_file_exists(name)) {
return true;
} else if(image::exists(name)) {
return true;
@ -298,28 +329,29 @@ static bool image_exists(const std::string& name)
return false;
}
static std::vector<std::string> get_variations(const std::string& base, const std::string& variations)
static std::vector<n_token::t_token> get_variations(const n_token::t_token& base, const n_token::t_token& variations)
{
/** @todo optimize this function */
std::vector<std::string> res;
std::vector<n_token::t_token> res;
if(variations.empty()){
res.push_back(base);
return res;
}
std::string::size_type pos = base.find("@V", 0);
std::string::size_type pos = (*base).find("@V", 0);
if(pos == std::string::npos) {
res.push_back(base);
return res;
}
std::vector<std::string> vars = utils::split(variations, ';', 0);
std::vector<n_token::t_token> vars = utils::split_token(variations, ';', 0);
foreach(const std::string& v, vars){
res.push_back(base);
foreach(const n_token::t_token& v, vars){
std::string::size_type pos = 0;
while ((pos = res.back().find("@V", pos)) != std::string::npos) {
res.back().replace(pos, 2, v);
pos += v.size();
std::string cbase(*base);
while ((pos = cbase.find("@V", pos)) != std::string::npos) {
cbase.replace(pos, 2, (*v));
pos += (*v).size();
}
res.push_back(n_token::t_token(cbase));
}
return res;
}
@ -339,27 +371,27 @@ bool terrain_builder::load_images(building_rule &rule)
foreach(rule_image_variant& variant, ri.variants)
{
std::vector<std::string> var_strings = get_variations(variant.image_string, variant.variations);
foreach(const std::string& var, var_strings)
std::vector<n_token::t_token> var_strings = get_variations(variant.image_string, variant.variations);
foreach(const n_token::t_token& var, var_strings)
{
/** @todo improve this, 99% of terrains are not animated. */
std::vector<std::string> frames = utils::parenthetical_split(var,',');
std::vector<n_token::t_token> frames = utils::parenthetical_split_token(var,',');
animated<image::locator> res;
foreach(const std::string& frame, frames)
foreach(const n_token::t_token& frame, frames)
{
const std::vector<std::string> items = utils::split(frame, ':');
const std::string& str = items.front();
const std::vector<n_token::t_token> items = utils::split_token(frame, ':');
const n_token::t_token& str = items.front();
const size_t tilde = str.find('~');
const size_t tilde = (*str).find('~');
bool has_tilde = tilde != std::string::npos;
const std::string filename = "terrain/" + (has_tilde ? str.substr(0,tilde) : str);
const n_token::t_token filename = n_token::t_token("terrain/" + (has_tilde ? (*str).substr(0,tilde) : str));
if(!image_exists(filename)){
continue; // ignore missing frames
}
const std::string modif = (has_tilde ? str.substr(tilde+1) : "");
const n_token::t_token modif = (has_tilde ? n_token::t_token((*str).substr(tilde+1)) : z_empty);
int time = 100;
if(items.size() > 1) {
@ -468,23 +500,25 @@ void terrain_builder::rotate(terrain_constraint &ret, int angle)
}
}
void terrain_builder::replace_rotate_tokens(std::string &s, int angle,
const std::vector<std::string> &replacement)
void terrain_builder::replace_rotate_tokens(n_token::t_token &s, int angle,
const std::vector<n_token::t_token> &replacement)
{
std::string::size_type pos = 0;
while ((pos = s.find("@R", pos)) != std::string::npos) {
if (pos + 2 >= s.size()) return;
unsigned i = s[pos + 2] - '0' + angle;
std::string scopy(*s);
while ((pos = scopy.find("@R", pos)) != std::string::npos) {
if (pos + 2 >= scopy.size()) { s = n_token::t_token(scopy); return; }
unsigned i = scopy[pos + 2] - '0' + angle;
if (i >= 6) i -= 6;
if (i >= 6) { pos += 2; continue; }
const std::string &r = replacement[i];
s.replace(pos, 3, r);
pos += r.size();
const n_token::t_token &r = replacement[i];
scopy.replace(pos, 3, r);
pos += r->size();
}
s = n_token::t_token(scopy);
}
void terrain_builder::replace_rotate_tokens(rule_image &image, int angle,
const std::vector<std::string> &replacement)
const std::vector<n_token::t_token> &replacement)
{
foreach(rule_image_variant& variant, image.variants) {
replace_rotate_tokens(variant, angle, replacement);
@ -492,7 +526,7 @@ void terrain_builder::replace_rotate_tokens(rule_image &image, int angle,
}
void terrain_builder::replace_rotate_tokens(rule_imagelist &list, int angle,
const std::vector<std::string> &replacement)
const std::vector<n_token::t_token> &replacement)
{
foreach (rule_image &img, list) {
replace_rotate_tokens(img, angle, replacement);
@ -500,18 +534,18 @@ void terrain_builder::replace_rotate_tokens(rule_imagelist &list, int angle,
}
void terrain_builder::replace_rotate_tokens(building_rule &rule, int angle,
const std::vector<std::string> &replacement)
const std::vector<n_token::t_token> &replacement)
{
foreach (terrain_constraint &cons, rule.constraints)
{
// Transforms attributes
foreach (std::string &flag, cons.set_flag) {
foreach (n_token::t_token &flag, cons.set_flag) {
replace_rotate_tokens(flag, angle, replacement);
}
foreach (std::string &flag, cons.no_flag) {
foreach (n_token::t_token &flag, cons.no_flag) {
replace_rotate_tokens(flag, angle, replacement);
}
foreach (std::string &flag, cons.has_flag) {
foreach (n_token::t_token &flag, cons.has_flag) {
replace_rotate_tokens(flag, angle, replacement);
}
replace_rotate_tokens(cons.images, angle, replacement);
@ -521,7 +555,7 @@ void terrain_builder::replace_rotate_tokens(building_rule &rule, int angle,
}
void terrain_builder::rotate_rule(building_rule &ret, int angle,
const std::vector<std::string> &rot)
const std::vector<n_token::t_token> &rot)
{
if (rot.size() != 6) {
ERR_NG << "invalid rotations\n";
@ -553,7 +587,7 @@ void terrain_builder::rotate_rule(building_rule &ret, int angle,
replace_rotate_tokens(ret, angle, rot);
}
terrain_builder::rule_image_variant::rule_image_variant(const std::string &image_string, const std::string& variations, const std::string& tod, bool random_start) :
terrain_builder::rule_image_variant::rule_image_variant(const n_token::t_token &image_string, const n_token::t_token& variations, const n_token::t_token& tod, bool random_start) :
image_string(image_string),
variations(variations),
images(),
@ -561,20 +595,20 @@ terrain_builder::rule_image_variant::rule_image_variant(const std::string &image
random_start(random_start)
{
if(!tod.empty()) {
const std::vector<std::string> tod_list = utils::split(tod);
const std::vector<n_token::t_token> tod_list = utils::split_token(tod);
tods.insert(tod_list.begin(), tod_list.end());
}
}
void terrain_builder::add_images_from_config(rule_imagelist& images, const config &cfg, bool global, int dx, int dy)
{
foreach (const config &img, cfg.child_range("image"))
foreach (const config &img, cfg.child_range(z_image))
{
int layer = img["layer"];
int layer = img[z_layer];
int basex = TILEWIDTH / 2 + dx, basey = TILEWIDTH / 2 + dy;
if (const config::attribute_value *base_ = img.get("base")) {
std::vector<std::string> base = utils::split(*base_);
if (const config::attribute_value *base_ = img.get(z_base)) {
std::vector<n_token::t_token> base = utils::split_token(*base_);
if(base.size() >= 2) {
basex = atoi(base[0].c_str());
basey = atoi(base[1].c_str());
@ -582,8 +616,8 @@ void terrain_builder::add_images_from_config(rule_imagelist& images, const confi
}
int center_x = -1, center_y = -1;
if (const config::attribute_value *center_ = img.get("center")) {
std::vector<std::string> center = utils::split(*center_);
if (const config::attribute_value *center_ = img.get(z_center)) {
std::vector<n_token::t_token> center = utils::split_token(*center_);
if(center.size() >= 2) {
center_x = atoi(center[0].c_str());
center_y = atoi(center[1].c_str());
@ -593,21 +627,21 @@ void terrain_builder::add_images_from_config(rule_imagelist& images, const confi
images.push_back(rule_image(layer, basex - dx, basey - dy, global, center_x, center_y));
// Adds the other variants of the image
foreach (const config &variant, img.child_range("variant"))
foreach (const config &variant, img.child_range(z_variant))
{
const std::string &name = variant["name"];
const std::string &variations = img["variations"];
const std::string &tod = variant["tod"];
bool random_start = variant["random_start"].to_bool(true);
const n_token::t_token &name = variant[z_name];
const n_token::t_token &variations = img[z_variations];
const n_token::t_token &tod = variant[z_tod];
bool random_start = variant[z_random_start].to_bool(true);
images.back().variants.push_back(rule_image_variant(name, variations, tod, random_start));
}
// Adds the main (default) variant of the image at the end,
// (will be used only if previous variants don't match)
const std::string &name = img["name"];
const std::string &variations = img["variations"];
bool random_start = img["random_start"].to_bool(true);
const n_token::t_token &name = img[z_name];
const n_token::t_token &variations = img[z_variations];
bool random_start = img[z_random_start].to_bool(true);
images.back().variants.push_back(rule_image_variant(name, variations, random_start));
}
}
@ -647,22 +681,22 @@ void terrain_builder::add_constraints(terrain_builder::constraint_set &constrain
{
terrain_constraint& constraint = add_constraints(constraints, loc,
t_translation::t_match(cfg["type"], t_translation::WILDCARD), global_images);
t_translation::t_match(cfg[z_type], t_translation::WILDCARD), global_images);
std::vector<std::string> item_string = utils::split(cfg["set_flag"]);
std::vector<n_token::t_token> item_string = utils::split_token(cfg[z_set_flag]);
constraint.set_flag.insert(constraint.set_flag.end(),
item_string.begin(), item_string.end());
item_string = utils::split(cfg["has_flag"]);
item_string = utils::split_token(cfg[z_has_flag]);
constraint.has_flag.insert(constraint.has_flag.end(),
item_string.begin(), item_string.end());
item_string = utils::split(cfg["no_flag"]);
item_string = utils::split_token(cfg[z_no_flag]);
constraint.no_flag.insert(constraint.no_flag.end(),
item_string.begin(), item_string.end());
item_string = utils::split(cfg["set_no_flag"]);
item_string = utils::split_token(cfg[z_set_no_flag]);
constraint.set_flag.insert(constraint.set_flag.end(),
item_string.begin(), item_string.end());
constraint.no_flag.insert(constraint.no_flag.end(),
@ -672,7 +706,7 @@ void terrain_builder::add_constraints(terrain_builder::constraint_set &constrain
add_images_from_config(constraint.images, cfg, false);
}
void terrain_builder::parse_mapstring(const std::string &mapstring,
void terrain_builder::parse_mapstring(const n_token::t_token &mapstring,
struct building_rule &br, anchormap& anchors,
const config& global_images)
{
@ -727,14 +761,14 @@ void terrain_builder::add_rule(building_ruleset &rules, building_rule &rule)
}
void terrain_builder::add_rotated_rules(building_ruleset &rules, building_rule &tpl,
const std::string &rotations)
const n_token::t_token &rotations)
{
if(rotations.empty()) {
// Adds the parsed built terrain to the list
add_rule(rules, tpl);
} else {
const std::vector<std::string>& rot = utils::split(rotations, ',');
const std::vector<n_token::t_token>& rot = utils::split_token(rotations, ',');
for(size_t angle = 0; angle < rot.size(); ++angle) {
/* Only 5% of the rules have valid images, so most of
@ -756,7 +790,7 @@ void terrain_builder::parse_config(const config &cfg, bool local)
log_scope("terrain_builder::parse_config");
// Parses the list of building rules (BRs)
foreach (const config &br, cfg.child_range("terrain_graphics"))
foreach (const config &br, cfg.child_range(z_terrain_graphics))
{
building_rule pbr; // Parsed Building rule
pbr.local = local;
@ -764,30 +798,30 @@ void terrain_builder::parse_config(const config &cfg, bool local)
// add_images_from_config(pbr.images, **br);
pbr.location_constraints =
map_location(br["x"].to_int() - 1, br["y"].to_int() - 1);
map_location(br[z_x].to_int() - 1, br[z_y].to_int() - 1);
pbr.probability = br["probability"].to_int(100);
pbr.probability = br[z_probability].to_int(100);
// Mapping anchor indices to anchor locations.
anchormap anchors;
// Parse the map= , if there is one (and fill the anchors list)
parse_mapstring(br["map"], pbr, anchors, br);
parse_mapstring(br[z_map], pbr, anchors, br);
// Parses the terrain constraints (TCs)
foreach (const config &tc, br.child_range("tile"))
foreach (const config &tc, br.child_range(z_tile))
{
// Adds the terrain constraint to the current built terrain's list
// of terrain constraints, if it does not exist.
map_location loc;
if (const config::attribute_value *v = tc.get("x")) {
if (const config::attribute_value *v = tc.get(z_x)) {
loc.x = *v;
}
if (const config::attribute_value *v = tc.get("y")) {
if (const config::attribute_value *v = tc.get(z_y)) {
loc.y = *v;
}
if (const config::attribute_value *v = tc.get("loc")) {
std::vector<std::string> sloc = utils::split(*v);
if (const config::attribute_value *v = tc.get(z_loc)) {
std::vector<n_token::t_token> sloc = utils::split_token(*v);
if(sloc.size() == 2) {
loc.x = atoi(sloc[0].c_str());
loc.y = atoi(sloc[1].c_str());
@ -796,7 +830,7 @@ void terrain_builder::parse_config(const config &cfg, bool local)
if(loc.valid()) {
add_constraints(pbr.constraints, loc, tc, br);
}
if (const config::attribute_value *v = tc.get("pos")) {
if (const config::attribute_value *v = tc.get(z_pos)) {
int pos = *v;
if(anchors.find(pos) == anchors.end()) {
WRN_NG << "Invalid anchor!\n";
@ -813,10 +847,10 @@ void terrain_builder::parse_config(const config &cfg, bool local)
}
}
const std::vector<std::string> global_set_flag = utils::split(br["set_flag"]);
const std::vector<std::string> global_no_flag = utils::split(br["no_flag"]);
const std::vector<std::string> global_has_flag = utils::split(br["has_flag"]);
const std::vector<std::string> global_set_no_flag = utils::split(br["set_no_flag"]);
const std::vector<n_token::t_token> global_set_flag = utils::split_token(br[z_set_flag]);
const std::vector<n_token::t_token> global_no_flag = utils::split_token(br[z_no_flag]);
const std::vector<n_token::t_token> global_has_flag = utils::split_token(br[z_has_flag]);
const std::vector<n_token::t_token> global_set_no_flag = utils::split_token(br[z_set_no_flag]);
foreach (terrain_constraint &constraint, pbr.constraints)
{
@ -833,9 +867,9 @@ void terrain_builder::parse_config(const config &cfg, bool local)
}
// Handles rotations
const std::string &rotations = br["rotations"];
const n_token::t_token &rotations = br[z_rotations];
pbr.precedence = br["precedence"];
pbr.precedence = br[z_precedence];
add_rotated_rules(building_rules_, pbr, rotations);
@ -858,7 +892,7 @@ void terrain_builder::parse_config(const config &cfg, bool local)
std::cerr << ">>>> New constraint: location = (" << constraint->second.loc
<< "), terrain types = '" << t_translation::write_list(constraint->second.terrain_types_match.terrain) << "'\n";
std::vector<std::string>::const_iterator flag;
std::vector<n_token::t_token>::const_iterator flag;
for(flag = constraint->second.set_flag.begin(); flag != constraint->second.set_flag.end(); ++flag) {
std::cerr << ">>>>>> Set_flag: " << *flag << "\n";
@ -874,25 +908,25 @@ void terrain_builder::parse_config(const config &cfg, bool local)
}
void terrain_builder::add_off_map_rule(const std::string& image)
void terrain_builder::add_off_map_rule(const n_token::t_token& image)
{
// Build a config object
config cfg;
config &item = cfg.add_child("terrain_graphics");
config &item = cfg.add_child(z_terrain_graphics);
config &tile = item.add_child("tile");
tile["x"] = 0;
tile["y"] = 0;
tile["type"] = t_translation::write_terrain_code(t_translation::OFF_MAP_USER);
config &tile = item.add_child(z_tile);
tile[z_x] = 0;
tile[z_y] = 0;
tile[z_type] = t_translation::write_terrain_code(t_translation::OFF_MAP_USER);
config &tile_image = tile.add_child("image");
tile_image["layer"] = -1000;
tile_image["name"] = image;
config &tile_image = tile.add_child(z_image);
tile_image[z_layer] = -1000;
tile_image[z_name] = image;
item["probability"] = 100;
item["no_flag"] = "base";
item["set_flag"] = "base";
item[z_probability] = 100;
item[z_no_flag] = z_base;
item[z_set_flag] = z_base;
// Parse the object
parse_global_config(cfg);
@ -928,16 +962,16 @@ bool terrain_builder::rule_matches(const terrain_builder::building_rule &rule,
return false;
}
const std::set<std::string> &flags = tile_map_[tloc].flags;
const boost::unordered_set<n_token::t_token> &flags = tile_map_[tloc].flags;
foreach (const std::string &s, cons.no_flag) {
// If a flag listed in "no_flag" is present, the rule does not match
foreach (const n_token::t_token &s, cons.no_flag) {
// If a flag listed in z_no_flag is present, the rule does not match
if (flags.find(s) != flags.end()) {
return false;
}
}
foreach (const std::string &s, cons.has_flag) {
// If a flag listed in "has_flag" is not present, this rule does not match
foreach (const n_token::t_token &s, cons.has_flag) {
// If a flag listed in z_has_flag is not present, this rule does not match
if (flags.find(s) == flags.end()) {
return false;
}
@ -965,7 +999,7 @@ void terrain_builder::apply_rule(const terrain_builder::building_rule &rule, con
}
// Sets flags
foreach (const std::string &flag, constraint.set_flag) {
foreach (const n_token::t_token &flag, constraint.set_flag) {
btile.flags.insert(flag);
}
@ -975,10 +1009,10 @@ void terrain_builder::apply_rule(const terrain_builder::building_rule &rule, con
// copied from text_surface::hash()
// but keep it separated because the needs are different
// and changing it will modify the map random variations
static unsigned int hash_str(const std::string& str)
static unsigned int hash_str(const n_token::t_token& str)
{
unsigned int h = 0;
for(std::string::const_iterator it = str.begin(), it_end = str.end(); it != it_end; ++it)
for(std::string::const_iterator it = str->begin(), it_end = str->end(); it != it_end; ++it)
h = ((h << 9) | (h >> (sizeof(int) * 8 - 9))) ^ (*it);
return h;
}

View file

@ -23,6 +23,7 @@
#include "animated.hpp"
#include "map_location.hpp"
#include "token.hpp"
#include "terrain_translation.hpp"
class config;
@ -87,7 +88,7 @@ public:
* and '.png' suffix
*/
terrain_builder(const config &level, const gamemap* map,
const std::string& offmap_image);
const n_token::t_token& offmap_image);
/** Set the config where we will parse the global terrain rules.
* This also flushes the terrain rules cache.
@ -123,7 +124,7 @@ public:
* to the parameters, or NULL if there is none.
*/
const imagelist *get_terrain_at(const map_location &loc,
const std::string &tod, TERRAIN_TYPE const terrain_type);
const n_token::t_token &tod, TERRAIN_TYPE const terrain_type);
/** Updates the animation at a given tile.
* Returns true if something has changed, and must be redrawn.
@ -156,7 +157,7 @@ public:
*/
struct rule_image_variant {
/** Constructor for the normal defaut case */
rule_image_variant(const std::string &image_string, const std::string& variations, bool random_start = true) :
rule_image_variant(const n_token::t_token &image_string, const n_token::t_token& variations, bool random_start = true) :
image_string(image_string),
variations(variations),
images(),
@ -165,7 +166,7 @@ public:
{};
/** Constructor for true [variant] cases */
rule_image_variant(const std::string &image_string, const std::string& variations, const std::string& tod, bool random_start = true);
rule_image_variant(const n_token::t_token &image_string, const n_token::t_token& variations, const n_token::t_token& tod, bool random_start = true);
/** A string representing either the filename for an image, or
* a list of images, with an optional timing for each image.
@ -184,12 +185,12 @@ public:
* in the animation.
*@endverbatim
*/
std::string image_string;
n_token::t_token image_string;
/** A semi-solon separated list of string used to replace
* @verbatim <code>@V</code> @endverbatim in image_string (if present)
*/
std::string variations;
n_token::t_token variations;
/** An animated image locator built according to the image string.
* This will be the image locator which will actually
@ -198,7 +199,7 @@ public:
std::vector< animated<image::locator> > images;
/** The Time of Day associated to this variant (if any)*/
std::set<std::string> tods;
boost::unordered_set<n_token::t_token> tods;
/** Indicate if the animation uses a random shift */
bool random_start;
@ -269,9 +270,9 @@ public:
map_location loc;
t_translation::t_match terrain_types_match;
std::vector<std::string> set_flag;
std::vector<std::string> no_flag;
std::vector<std::string> has_flag;
std::vector<n_token::t_token> set_flag;
std::vector<n_token::t_token> no_flag;
std::vector<n_token::t_token> has_flag;
rule_imagelist images;
};
@ -295,13 +296,13 @@ public:
*
* @param tod The current time-of-day
*/
void rebuild_cache(const std::string &tod, logs* log = NULL);
void rebuild_cache(const n_token::t_token &tod, logs* log = NULL);
/** Clears all data in this tile, and resets the cache */
void clear();
/** The list of flags present in this tile */
std::set<std::string> flags;
boost::unordered_set<n_token::t_token> flags;
/** Represent a rule_image applied with a random seed.*/
struct rule_image_rand{
@ -334,7 +335,7 @@ public:
/**
* The time-of-day to which the image caches correspond.
*/
std::string last_tod;
n_token::t_token last_tod;
/** Indicates if 'images' is sorted */
bool sorted_images;
@ -511,8 +512,8 @@ private:
* @param angle the angle for substituting the correct replacement.
* @param replacement the replacement strings.
*/
void replace_rotate_tokens(std::string &s, int angle,
const std::vector<std::string> &replacement);
void replace_rotate_tokens(n_token::t_token &s, int angle,
const std::vector<n_token::t_token> &replacement);
/**
* Replaces, in a given rule_image, rotation tokens with their values.
@ -523,7 +524,7 @@ private:
* @param replacement the replacement strings.
*/
void replace_rotate_tokens(rule_image &image, int angle,
const std::vector<std::string> &replacement);
const std::vector<n_token::t_token> &replacement);
/**
* Replaces, in a given rule_variant_image, rotation tokens with their values.
@ -535,7 +536,7 @@ private:
* @param replacement the replacement strings.
*/
void replace_rotate_tokens(rule_image_variant &variant, int angle,
const std::vector<std::string> &replacement)
const std::vector<n_token::t_token> &replacement)
{ replace_rotate_tokens(variant.image_string, angle, replacement); }
/**
@ -548,7 +549,7 @@ private:
* @param replacement the replacement strings.
*/
void replace_rotate_tokens(rule_imagelist &list, int angle,
const std::vector<std::string> &replacement);
const std::vector<n_token::t_token> &replacement);
/**
* Replaces, in a given building_rule, rotation tokens with their values.
@ -562,7 +563,7 @@ private:
* @param replacement the replacement strings.
*/
void replace_rotate_tokens(building_rule &rule, int angle,
const std::vector<std::string> &replacement);
const std::vector<n_token::t_token> &replacement);
/**
* Rotates a template rule to a given angle.
@ -601,7 +602,7 @@ private:
*
*/
void rotate_rule(building_rule &rule, int angle,
const std::vector<std::string> &angle_name);
const std::vector<n_token::t_token> &angle_name);
/**
* Parses a "config" object, which should contains [image] children,
@ -665,7 +666,7 @@ private:
* @param global_images A config object representing the images defined
* as direct children of the [terrain_graphics] rule.
*/
void parse_mapstring(const std::string &mapstring, struct building_rule &br,
void parse_mapstring(const n_token::t_token &mapstring, struct building_rule &br,
anchormap& anchors, const config& global_images);
/**
@ -687,7 +688,7 @@ private:
* template strings @verbatim (@Rn) @endverbatim
*/
void add_rotated_rules(building_ruleset& rules, building_rule& tpl,
const std::string &rotations);
const n_token::t_token &rotations);
/**
* Parses a configuration object containing [terrain_graphics] rules,
@ -706,7 +707,7 @@ private:
*
* @param image The filename of the image
*/
void add_off_map_rule(const std::string& image);
void add_off_map_rule(const n_token::t_token& image);
void flush_local_rules();
@ -780,7 +781,7 @@ private:
/**
* Shorthand typedef for a map associating a list of locations to a terrain type.
*/
typedef std::map<t_translation::t_terrain, std::vector<map_location> > terrain_by_type_map;
typedef boost::unordered_map<t_translation::t_terrain, std::vector<map_location> > terrain_by_type_map;
/**
* A map representing all locations whose terrain is of a given type.

View file

@ -640,7 +640,7 @@ std::vector<surface> display::get_fog_shroud_images(const map_location& loc, ima
}
std::vector<surface> display::get_terrain_images(const map_location &loc,
const std::string& timeid,
const n_token::t_token& timeid,
image::TYPE image_type,
TERRAIN_TYPE terrain_type)
{

View file

@ -538,7 +538,7 @@ protected:
enum TERRAIN_TYPE { BACKGROUND, FOREGROUND};
std::vector<surface> get_terrain_images(const map_location &loc,
const std::string& timeid,
const n_token::t_token& timeid,
image::TYPE type,
TERRAIN_TYPE terrain_type);

View file

@ -3226,7 +3226,7 @@ void console_handler::do_layers() {
terrain_builder& builder = disp.get_builder();
terrain_builder::tile* tile = builder.get_tile(loc);
const std::string& tod_id = disp.get_time_of_day(loc).id;
const n_token::t_token& tod_id = disp.get_time_of_day(loc).id;
terrain_builder::tile::logs tile_logs;
tile->rebuild_cache(tod_id, &tile_logs);

View file

@ -79,22 +79,43 @@ std::string &strip(std::string &str)
namespace {
static const uint CACHE_SIZE = 10000;
typedef std::pair<n_token::t_token, std::pair<char, int > > t_triad;
typedef std::vector<n_token::t_token > t_out;
struct t_split_triad {
n_token::t_token const val;
char c;
int flags;
t_split_triad(n_token::t_token const &v, char cc, int f) : val(v), c(cc), flags(f) {}
bool operator==(t_split_triad const & a) const {
return val ==a.val && c==a.c && flags==a.flags; }
};
size_t hash_value(t_split_triad const & a) {
size_t hash=0;
boost::hash_combine(hash, a.val);
boost::hash_combine(hash, a.c);
boost::hash_combine(hash, a.flags);
return hash;
}
///When a cache miss occurs calculate the split token
struct t_calc_cache_item {
t_out const operator()(t_triad const & x){
std::vector<std::string> vstr(split(static_cast<std::string const &>(x.first), x.second.first, x.second.second));
t_out const operator()(t_split_triad const & x) {
std::vector<std::string> vstr(split(static_cast<std::string const &>(x.val), x.c, x.flags));
t_out const retval(vstr.begin(), vstr.end());
return retval;
}
};
typedef n_lru_cache::t_lru_cache<t_triad, t_out, t_calc_cache_item> t_cache;
typedef n_lru_cache::t_lru_cache<t_split_triad, t_out, t_calc_cache_item> t_split_token_cache;
}
std::vector< n_token::t_token > split_token(n_token::t_token const &val, char c, int flags){
static t_cache my_cache(t_calc_cache_item(), CACHE_SIZE);
static t_split_token_cache my_cache(t_calc_cache_item(), CACHE_SIZE);
return my_cache.check(std::make_pair(val, std::make_pair(c,flags)));
return my_cache.check(t_split_triad(val, c, flags));
}
std::vector< std::string > split(std::string const &val, char c, int flags)
@ -131,6 +152,55 @@ std::vector< std::string > split(std::string const &val, char c, int flags)
return res;
}
}
namespace {
static const uint PAREN_CACHE_SIZE = 1000;
typedef std::vector<n_token::t_token > t_out;
struct t_paren_split_inputs {
n_token::t_token const val;
const char separator;
n_token::t_token const left;
n_token::t_token const right;
int flags;
t_paren_split_inputs(n_token::t_token const &val, const char separator, n_token::t_token const &left
, n_token::t_token const &right,int flags)
: val(val), separator(separator), left(left), right(right), flags(flags){}
bool operator==(t_paren_split_inputs const & a) const {
return val ==a.val && separator==a.separator && left==a.left && right==a.right && flags==a.flags; }
};
size_t hash_value(t_paren_split_inputs const & a){
size_t hash=0;
boost::hash_combine(hash,a.val);
boost::hash_combine(hash,a.separator);
boost::hash_combine(hash,a.left);
boost::hash_combine(hash,a.right);
boost::hash_combine(hash,a.flags);
return hash;
}
///When a cache miss occurs calculate the split token
struct t_calc_paren_cache_item {
t_out const operator()(t_paren_split_inputs const & x){
std::vector<std::string> vstr(utils::parenthetical_split((*x.val), x.separator, x.left, x.right, x.flags));
t_out const retval(vstr.begin(), vstr.end());
return retval;
}
};
typedef n_lru_cache::t_lru_cache<t_paren_split_inputs, t_out, t_calc_paren_cache_item> t_paren_cache;
}
namespace utils{
std::vector< n_token::t_token > parenthetical_split_token(n_token::t_token const &val,
const char separator, n_token::t_token const &left,
n_token::t_token const &right, int flags) {
static t_paren_cache my_cache(t_calc_paren_cache_item(), PAREN_CACHE_SIZE);
return my_cache.check( t_paren_split_inputs(val, separator, left, right, flags ) );
}
std::vector< std::string > parenthetical_split(std::string const &val,
const char separator, std::string const &left,

View file

@ -37,6 +37,14 @@ typedef std::string utf8_string;
class t_string;
namespace {
//Static tokens are replacements for string literals in code
//They allow for fast comparison, copying and hashing operations.
static const n_token::t_token z_lparen("(", false);
static const n_token::t_token z_rparen(")", false);
}
namespace utils {
extern const std::string unicode_minus;
@ -80,6 +88,11 @@ std::vector< std::string > parenthetical_split(std::string const &val,
const char separator = 0 , std::string const &left="(",
std::string const &right=")",int flags = REMOVE_EMPTY | STRIP_SPACES);
std::vector< n_token::t_token > parenthetical_split_token(n_token::t_token const &val,
const char separator = 0 , n_token::t_token const &left=z_lparen,
n_token::t_token const &right=z_rparen,int flags = REMOVE_EMPTY | STRIP_SPACES);
template <typename T>
std::string join(T const &v, const std::string& s = ",")
{

View file

@ -29,36 +29,72 @@ namespace{
static const uint CACHE_SIZE = 10;
static const uint STEP_SIZE = 1000;
struct t_gen_cache_item {
int operator()(int const & in) const {
return in + STEP_SIZE ; }
};
typedef n_lru_cache::t_lru_cache<int, int, t_gen_cache_item> t_cache;
void check_equal(int l, int r) {
int ll(l + STEP_SIZE);
BOOST_CHECK_MESSAGE(ll == r, "\nLeft \""<< ll <<"\"" << "should equal right \""<<r<<"\"\n"); }
void check_not_equal(int l, int r) {
int ll(l + STEP_SIZE);
BOOST_CHECK_MESSAGE(ll != r, "\nLeft \""<< ll <<"\"" << "should not equal right \""<<r<<"\"\n"); }
void check_present(int k, t_cache const & cache) {
bool t = cache.debugging_test_cache(k);
BOOST_CHECK_MESSAGE(t, "\nExpected Key \""<< k <<"\"" << " is missing\n"); }
void check_not_present(int k, t_cache const &cache) {
bool t = cache.debugging_test_cache(k);
BOOST_CHECK_MESSAGE(!t, "\nUnexpected Key \""<< k <<"\"" << " is present\n"); }
void check_empty(t_cache const & cache){
std::pair<bool, int> newest = cache.debugging_newest_item();
bool t = ! newest.first ;
BOOST_CHECK_MESSAGE(t, "\nExpected an empty cache, but it isn't ");}
void check_newest(int k, t_cache const & cache) {
std::pair<bool, int> newest = cache.debugging_newest_item();
bool t = newest.first && k == newest.second;
BOOST_CHECK_MESSAGE(t, "\nExpected newest item to be \""<< k <<"\"" << "but found \""<<newest.second<<"\"\n"); }
void check_oldest(int k, t_cache const & cache) {
std::pair<bool, int> oldest = cache.debugging_oldest_item();
bool t = oldest.first && k == oldest.second;
BOOST_CHECK_MESSAGE(t, "\nExpected oldest item to be \""<< k <<"\"" << "but found \""<<oldest.second<<"\"\n"); }
struct t_gen_cache_item {
int operator()(int const & in) const {
return in + STEP_SIZE ; }
};
}
BOOST_AUTO_TEST_CASE( test_lru_cache1 ) {
typedef n_lru_cache::t_lru_cache<int, int, t_gen_cache_item> t_cache;
static t_cache cache( t_gen_cache_item(), CACHE_SIZE);
for (int i = 1; i<20; ++i){
check_empty(cache);
cache.invalidate();
check_empty(cache);
for (unsigned int i = 1; i<20; ++i){
int from_cache(cache.check( i ));
check_newest(i, cache);
int hit_me(cache.check( 1 ));
check_newest(1, cache);
check_oldest(
(i<2) ? i :
(i<=CACHE_SIZE + 1) ? 2 :
( i<=CACHE_SIZE + 2) ? (i - CACHE_SIZE + 1) : (i - CACHE_SIZE + 2)
, cache);
cache.invalidate(4);
check_not_present(4, cache);
check_equal(1, hit_me);
check_equal(i, from_cache);
}
cache.invalidate();
check_empty(cache);
}

View file

@ -32,6 +32,12 @@ static lg::log_domain log_display("display");
#define LOG_DP LOG_STREAM(info, log_display)
#define ERR_DP LOG_STREAM(err, log_display)
namespace{
//Static tokens are replacements for string literals in code
//They allow for fast comparison operations.
static const config::t_token z_tile_image("tile_image", false);
}
namespace {
const int XDim = 1024;
const int YDim = 768;
@ -291,7 +297,7 @@ theme::tborder::tborder(const config& cfg) :
size(cfg["border_size"].to_double()),
background_image(cfg["background_image"]),
tile_image(cfg["tile_image"]),
tile_image(cfg[z_tile_image].token()),
corner_image_top_left(cfg["corner_image_top_left"]),
corner_image_bottom_left(cfg["corner_image_bottom_left"]),

View file

@ -77,7 +77,7 @@ class theme
double size;
std::string background_image;
std::string tile_image;
n_token::t_token tile_image;
std::string corner_image_top_left;
std::string corner_image_bottom_left;
@ -250,5 +250,5 @@ private:
tborder border_;
};
#endif

View file

@ -1387,7 +1387,7 @@ const unit_type *unit_type_data::find(const config::t_token& key, unit_type::BUI
void unit_type_data::check_types(const std::vector<config::t_token>& types) const
{
foreach(const config::t_token& type, types) {
if(!find(type)) throw game::game_error("unknown unit type: " + static_cast<std::string const &>(type));
if(!find(type)) { throw game::game_error("unknown unit type: " + type); }
}
}

View file

@ -34,58 +34,94 @@
namespace n_lru_cache {
template <typename T_key, typename T_value, typename T_comp>
template <typename T_key, typename T_value, typename T_compute_value>
class t_lru_cache{
public:
///Key value for the cache
///@pre supports operator== and boost::hash_value
///@pre doesn't contain any references as it is stored in a STL container
typedef T_key t_key;
///Value for the cache
///@pre doesn't contain any references as it is stored in a STL container
typedef T_value t_value;
typedef T_comp t_comp;
///A functor that computes the value from key
typedef T_compute_value t_comp;
private:
typedef std::list<t_key> t_lru_list;
typedef typename t_lru_list::iterator lru_iterator;
typedef lru_iterator iterator;
typedef std::pair<t_value, lru_iterator> t_valpos_pair;
typedef boost::unordered_map<t_key, t_valpos_pair> t_key_to_value;
typedef typename t_key_to_value::iterator kv_iterator;
///A map of keys to values
t_key_to_value key_to_valpos_;
///A list of the least recently used keys
t_lru_list lru_list_;
///The functor used to compute values from keys
t_comp comp_;
///The maximum size of cache before old items are discarded
size_t max_size_;
///A placeholder for insertion (see code).
t_value const dummy_item_;
///Counters for debugging
unsigned int stat_hit_, stat_miss_, stat_erased_;
public:
typedef lru_iterator iterator;
t_lru_cache(t_comp const & c, size_t max_size):key_to_valpos_(), lru_list_(), comp_(c), max_size_(max_size)
,stat_hit_(0), stat_miss_(0), stat_erased_(0){}
///Initialize the cache
///@param[in] c a functor to compute values from keys
///@param[in] max_size the maximum size of the cache before items are discarded
///@param[in] dummy_value a dummy value used internally to insert fake values into the cache
t_lru_cache(t_comp const & c, size_t max_size, t_value const & dummy_value = t_value())
: key_to_valpos_(), lru_list_(), comp_(c), max_size_(max_size), dummy_item_(dummy_value)
, stat_hit_(0), stat_miss_(0), stat_erased_(0){}
t_lru_cache(t_lru_cache const & a)
: key_to_valpos_(a.key_to_valpos_), lru_list_(a.lru_list_), comp_(a.comp_), max_size_(a.max_size_)
,stat_hit_(a.stat_hit_), stat_miss_(a.stat_miss_), stat_erased_(a.stat_erased_){}
: key_to_valpos_(a.key_to_valpos_), lru_list_(a.lru_list_), comp_(a.comp_)
, max_size_(a.max_size_), dummy_item_(a.dummy_item_)
, stat_hit_(a.stat_hit_), stat_miss_(a.stat_miss_), stat_erased_(a.stat_erased_){}
~t_lru_cache(){
//std::cerr<<"lru cache hits="<<stat_hit_<<" misses="<<stat_miss_<<" erased="<<stat_erased_<<"\n";
}
void set_comp(t_comp const & a){comp_ = a;}
void set_max_size(size_t m){max_size_=m; right_size();}
t_value & check(t_key const & k){ return check(k, comp_);}
///Check the cache for the value associated with key k.
t_value & check(t_key const & k){ return check(k, comp_); }
///Check the cache for the value associated with key k. Use lcomp to compute the value if not in the cache
template <typename X_comp>
t_value & check(t_key const & k, X_comp & lcomp){
kv_iterator found (key_to_valpos_.find(k));
if(found != key_to_valpos_.end()){ //Cache hit
// ++stat_hit_;
mark_used(found);
return found->second.first;
///Try to insert the dummy value.
///If it fails the returned value is a cache hit.
///If it succeeds then calculate the real cache value and store the result
std::pair<kv_iterator, bool> ins(
key_to_valpos_.insert(std::make_pair(k, std::make_pair(dummy_item_, lru_list_.begin() ))) );
bool found = ! ins.second ;
kv_iterator & kv_it(ins.first);
//cache hit
if(found){
//++stat_hit_;
mark_used(kv_it);
return kv_it->second.first;
}
// ++stat_miss_;
//cache miss
//++stat_miss_;
t_value val = lcomp(k);
mark_used(k);
std::pair<kv_iterator, bool> ins(key_to_valpos_.insert(std::make_pair(k, std::make_pair(val,lru_list_.begin() ))) );
t_valpos_pair & vp( kv_it->second);
vp.first=val;
vp.second=lru_list_.begin();
//resize the cache
right_size();
return ins.first->second.first;
return vp.first;
}
void invalidate(){
lru_list_.clear();
@ -95,11 +131,23 @@ public:
kv_iterator found (key_to_valpos_.find(k));
if(found != key_to_valpos_.end()){ //Cache hit
lru_list_.erase(found->second.second);
///todo Change to quick_erase when wesnoth supports boost 1.4?6
key_to_valpos_.erase(found);
}
}
iterator const end()const {return lru_list_.end();}
///For debugging only. Check for a cache hit.
///@note Don't use this in real code, just call check. It is faster
bool debugging_test_cache(t_key const & k) const {
typename t_key_to_value::const_iterator found (key_to_valpos_.find(k));
return (found != key_to_valpos_.end()); }
std::pair<bool, t_key> debugging_newest_item() const {
if (lru_list_.empty()){ return std::make_pair(false, t_key()); }
return std::make_pair(true, *lru_list_.begin()); }
std::pair<bool, t_key> debugging_oldest_item() const {
if (lru_list_.empty()){ return std::make_pair(false, t_key()); }
return std::make_pair(true, lru_list_.back()); }
private:
void mark_used(kv_iterator const & kv_iter){
lru_list_.erase(kv_iter->second.second);
@ -110,9 +158,13 @@ private:
lru_list_.push_front(k);
}
inline void right_size(){
if(key_to_valpos_.size() > max_size_){
// ++stat_erased_;
invalidate(lru_list_.back());
size_t size(key_to_valpos_.size());
if(size > max_size_){
size_t num_extra(size - max_size_);
for(size_t i=0; i<num_extra; ++i){
// ++stat_erased_;
invalidate(lru_list_.back());
}
}
}
};