[[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:
parent
d56fbf14fe
commit
1a5810656b
12 changed files with 379 additions and 167 deletions
238
src/builder.cpp
238
src/builder.cpp
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 = ",")
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -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"]),
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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); }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
Loading…
Add table
Reference in a new issue