Skip to content

Commit

Permalink
replace unit filter with a function object
Browse files Browse the repository at this point in the history
This allows us to separate the parsing of the filter from its
invocation, similar to the side filter and terrain filter, and
can speed things up if we move it outside of key loops
  • Loading branch information
cbeck88 committed Jul 3, 2014
1 parent 18159f0 commit 383046b
Show file tree
Hide file tree
Showing 17 changed files with 219 additions and 147 deletions.
14 changes: 4 additions & 10 deletions src/actions/create.cpp
Expand Up @@ -431,11 +431,8 @@ namespace { // Helpers for get_recalls()
// Only units that match the leader's recall filter are valid.
scoped_recall_unit this_unit("this_unit", save_id, leader_team.recall_list().find_index(recall_unit.id()));

const vconfig & rfilter = vconfig(leader->recall_filter());
if ( unit_filter::matches_filter( rfilter,
recall_unit,
map_location::null_location(),
resources::filter_con) )
const unit_filter ufilt(vconfig(leader->recall_filter()), resources::filter_con);
if ( ufilt(recall_unit, map_location::null_location()) )
{
result.push_back(recall_unit_ptr);
if ( already_added != NULL )
Expand Down Expand Up @@ -534,11 +531,8 @@ namespace { // Helpers for check_recall_location()
scoped_recall_unit this_unit("this_unit", recall_team.save_id(),
recall_team.recall_list().find_index(recall_unit.id()));

const vconfig & rfilter = vconfig(recaller.recall_filter());
if ( !unit_filter::matches_filter(rfilter,
recall_unit,
map_location::null_location(),
resources::filter_con) )
const unit_filter ufilt(vconfig(recaller.recall_filter()), resources::filter_con);
if ( !ufilt(recall_unit, map_location::null_location()) )
return RECRUIT_NO_ABLE_LEADER;

// Make sure the unit is on a keep.
Expand Down
6 changes: 4 additions & 2 deletions src/ai/composite/goal.cpp
Expand Up @@ -135,8 +135,9 @@ void target_unit_goal::add_targets(std::back_insert_iterator< std::vector< targe
if (!criteria) return;

//find the enemy leaders and explicit targets
const unit_filter ufilt(vconfig(criteria), resources::filter_con);
BOOST_FOREACH(const unit &u, *resources::units) {
if (unit_filter::matches_filter(vconfig(criteria), u, u.get_location(), resources::filter_con)) {
if (ufilt( u )) {
LOG_AI_GOAL << "found explicit target unit at ... " << u.get_location() << " with value: " << value() << "\n";
*target_list = target(u.get_location(), value(), target::EXPLICIT);
}
Expand Down Expand Up @@ -259,13 +260,14 @@ void protect_goal::add_targets(std::back_insert_iterator< std::vector< target >

std::set<map_location> items;
if (protect_unit_) {
const unit_filter ufilt(vconfig(criteria), resources::filter_con);
BOOST_FOREACH(const unit &u, units)
{
if (protect_only_own_unit_ && u.side() != get_side()) {
continue;
}
//TODO: we will protect hidden units, by not testing for invisibility to current side
if (unit_filter::matches_filter(vconfig(criteria), u, u.get_location(), resources::filter_con)) {
if (ufilt(u)) {
DBG_AI_GOAL << "side " << get_side() << ": in " << goal_type << ": " << u.get_location() << " should be protected\n";
items.insert(u.get_location());
}
Expand Down
8 changes: 4 additions & 4 deletions src/ai/recruitment/recruitment.cpp
Expand Up @@ -252,8 +252,8 @@ void recruitment::execute() {
// we'll check if we can do a recall instead of a recruitment.
BOOST_FOREACH(const unit_const_ptr & recall, current_team().recall_list()) {
// Check if this leader is allowed to recall this unit.
vconfig filter = vconfig(leader->recall_filter());
if (!unit_filter::matches_filter(filter, *recall, map_location::null_location(), resources::filter_con)) {
const unit_filter ufilt( vconfig(leader->recall_filter()), resources::filter_con);
if (!ufilt(*recall, map_location::null_location())) {
continue;
}
data.recruits.insert(recall->type_id());
Expand Down Expand Up @@ -477,8 +477,8 @@ const std::string* recruitment::get_appropriate_recall(const std::string& type,
continue;
}
// Check if this leader is allowed to recall this unit.
vconfig filter = vconfig(leader_data.leader->recall_filter());
if (!unit_filter::matches_filter(filter, *recall_unit, map_location::null_location(), resources::filter_con)) {
const unit_filter ufilt(vconfig(leader_data.leader->recall_filter()), resources::filter_con);
if (!ufilt(*recall_unit, map_location::null_location())) {
LOG_AI_RECRUITMENT << "Refused recall because of filter: " << recall_unit->id() << "\n";
continue;
}
Expand Down
38 changes: 20 additions & 18 deletions src/ai/testing/aspect_attacks.cpp
Expand Up @@ -74,9 +74,10 @@ boost::shared_ptr<attacks_vector> aspect_attacks::analyze_targets() const
unit_map& units_ = *resources::units;

std::vector<map_location> unit_locs;
const unit_filter filt_own(vconfig(filter_own_), resources::filter_con);
for(unit_map::const_iterator i = units_.begin(); i != units_.end(); ++i) {
if (i->side() == get_side() && i->attacks_left() && !(i->can_recruit() && get_passive_leader())) {
if (!unit_filter::matches_filter(vconfig(filter_own_), *i, i->get_location(), resources::filter_con)) {
if (!filt_own(*i)) {
continue;
}
unit_locs.push_back(i->get_location());
Expand All @@ -92,25 +93,26 @@ boost::shared_ptr<attacks_vector> aspect_attacks::analyze_targets() const

unit_stats_cache().clear();

const unit_filter filt_en(vconfig(filter_enemy_), resources::filter_con);
for(unit_map::const_iterator j = units_.begin(); j != units_.end(); ++j) {

// Attack anyone who is on the enemy side,
// and who is not invisible or petrified.
if (current_team().is_enemy(j->side()) && !j->incapacitated() &&
!j->invisible(j->get_location()))
{
if (!unit_filter::matches_filter(vconfig(filter_enemy_), *j, j->get_location(), resources::filter_con)) {
continue;
}
map_location adjacent[6];
get_adjacent_tiles(j->get_location(), adjacent);
attack_analysis analysis;
analysis.target = j->get_location();
analysis.vulnerability = 0.0;
analysis.support = 0.0;
do_attack_analysis(j->get_location(), srcdst, dstsrc,
fullmove_srcdst, fullmove_dstsrc, enemy_srcdst, enemy_dstsrc,
adjacent,used_locations,unit_locs,*res,analysis, current_team());
// Attack anyone who is on the enemy side,
// and who is not invisible or petrified.
if (current_team().is_enemy(j->side()) && !j->incapacitated() &&
!j->invisible(j->get_location()))
{
if (!filt_en( *j)) {
continue;
}
map_location adjacent[6];
get_adjacent_tiles(j->get_location(), adjacent);
attack_analysis analysis;
analysis.target = j->get_location();
analysis.vulnerability = 0.0;
analysis.support = 0.0;
do_attack_analysis(j->get_location(), srcdst, dstsrc,
fullmove_srcdst, fullmove_dstsrc, enemy_srcdst, enemy_dstsrc,
adjacent,used_locations,unit_locs,*res,analysis, current_team());
}
}
return res;
Expand Down
44 changes: 28 additions & 16 deletions src/game_events/action_wml.cpp
Expand Up @@ -405,8 +405,9 @@ namespace { // Support functions
} else if(speaker_str == "second_unit") {
speaker = units->find(event_info.loc2);
} else if(speaker_str != "narrator") {
const unit_filter ufilt(cfg, resources::filter_con);
for(speaker = units->begin(); speaker != units->end(); ++speaker){
if ( unit_filter::matches_filter(cfg,*speaker, resources::filter_con) )
if ( ufilt(*speaker) )
break;
}
}
Expand Down Expand Up @@ -778,8 +779,9 @@ WML_HANDLER_FUNCTION(heal_unit, event_info, cfg)
const vconfig & healers_filter = cfg.child("filter_second");
std::vector<unit*> healers;
if (!healers_filter.null()) {
const unit_filter ufilt(healers_filter, resources::filter_con);
BOOST_FOREACH(unit& u, *units) {
if ( unit_filter::matches_filter(healers_filter,u, resources::filter_con) && u.has_ability_type("heals") ) {
if ( ufilt(u) && u.has_ability_type("heals") ) {
healers.push_back(&u);
}
}
Expand All @@ -794,13 +796,15 @@ WML_HANDLER_FUNCTION(heal_unit, event_info, cfg)
const vconfig & healed_filter = cfg.child("filter");
bool only_unit_at_loc1 = healed_filter.null();
bool heal_amount_to_set = true;

const unit_filter ufilt(healed_filter, resources::filter_con);
for(unit_map::unit_iterator u = units->begin(); u != units->end(); ++u) {
if (only_unit_at_loc1)
{
u = units->find(event_info.loc1);
if(!u.valid()) return;
}
else if ( !unit_filter::matches_filter(healed_filter,*u, resources::filter_con) ) continue;
else if ( !ufilt(*u) ) continue;

int heal_amount = u->max_hitpoints() - u->hitpoints();
if(amount.blank() || amount == "full") u->set_hitpoints(u->max_hitpoints());
Expand Down Expand Up @@ -857,9 +861,10 @@ WML_HANDLER_FUNCTION(kill, event_info, cfg)
if(cfg["fire_event"].to_bool() && secondary_unit)
{
secondary_unit = false;
const unit_filter ufilt(cfg.child("secondary_unit"), resources::filter_con);
for(unit_map::const_unit_iterator unit = resources::units->begin();
unit != resources::units->end(); ++unit) {
if ( unit_filter::matches_filter(cfg.child("secondary_unit"), *unit, resources::filter_con) )
if ( ufilt( *unit) )
{
killer_loc = entity_location(*unit);
secondary_unit = true;
Expand All @@ -873,8 +878,9 @@ WML_HANDLER_FUNCTION(kill, event_info, cfg)

//Find all the dead units first, because firing events ruins unit_map iteration
std::vector<unit *> dead_men_walking;
const unit_filter ufilt(cfg, resources::filter_con);
BOOST_FOREACH(unit & u, *resources::units){
if ( unit_filter::matches_filter(cfg,u, resources::filter_con) ) {
if ( ufilt(u) ) {
dead_men_walking.push_back(&u);
}
}
Expand Down Expand Up @@ -942,13 +948,14 @@ WML_HANDLER_FUNCTION(kill, event_info, cfg)
if((cfg_x.empty() || cfg_x == "recall")
&& (cfg_y.empty() || cfg_y == "recall"))
{
const unit_filter ufilt(cfg, resources::filter_con);
//remove the unit from the corresponding team's recall list
for(std::vector<team>::iterator pi = resources::teams->begin();
pi!=resources::teams->end(); ++pi)
{
for(std::vector<unit_ptr>::iterator j = pi->recall_list().begin(); j != pi->recall_list().end();) { //TODO: This block is really messy, cleanup somehow...
scoped_recall_unit auto_store("this_unit", pi->save_id(), j - pi->recall_list().begin());
if (unit_filter::matches_filter(cfg, *(*j), map_location(), resources::filter_con)) {
if (ufilt( *(*j), map_location() )) {
j = pi->recall_list().erase(j);
} else {
++j;
Expand Down Expand Up @@ -1415,8 +1422,9 @@ WML_HANDLER_FUNCTION(object, event_info, cfg)

map_location loc;
if(!filter.null()) {
const unit_filter ufilt(filter, resources::filter_con);
BOOST_FOREACH(const unit &u, *resources::units) {
if ( unit_filter::matches_filter(filter,u, resources::filter_con) ) {
if ( ufilt(u) ) {
loc = u.get_location();
break;
}
Expand All @@ -1431,7 +1439,7 @@ WML_HANDLER_FUNCTION(object, event_info, cfg)

std::string command_type = "then";

if ( u != resources::units->end() && (filter.null() || unit_filter::matches_filter(filter,*u, resources::filter_con)) )
if ( u != resources::units->end() && (filter.null() || unit_filter(filter, resources::filter_con).matches(*u)) )
{
///@deprecated This can be removed (and a proper duration=level implemented) after 1.11.2
/// Don't forget to remove it from wmllint too!
Expand Down Expand Up @@ -1527,7 +1535,7 @@ WML_HANDLER_FUNCTION(recall, /*event_info*/, cfg)
*/
temp_config["x"] = "recall";
temp_config["y"] = "recall";
vconfig unit_filter(temp_config);
vconfig unit_filter_cfg(temp_config);
const vconfig & leader_filter = cfg.child("secondary_unit");

for(int index = 0; index < int(resources::teams->size()); ++index) {
Expand All @@ -1543,10 +1551,12 @@ WML_HANDLER_FUNCTION(recall, /*event_info*/, cfg)
recall_list_manager & avail = (*resources::teams)[index].recall_list();
std::vector<unit_map::unit_iterator> leaders = resources::units->find_leaders(index + 1);

const unit_filter ufilt(unit_filter_cfg, resources::filter_con);
const unit_filter lfilt(leader_filter, resources::filter_con); // Note that if leader_filter is null, this correctly gives a null filter that matches all units.
for(std::vector<unit_ptr>::iterator u = avail.begin(); u != avail.end(); ++u) {
DBG_NG << "checking unit against filter...\n";
scoped_recall_unit auto_store("this_unit", player_id, u - avail.begin());
if (unit_filter::matches_filter(unit_filter, *(*u), map_location(), resources::filter_con)) {
if (ufilt(*(*u), map_location())) {
DBG_NG << (*u)->id() << " matched the filter...\n";
const unit_ptr to_recruit = *u;
const unit* pass_check = to_recruit.get();
Expand All @@ -1557,8 +1567,8 @@ WML_HANDLER_FUNCTION(recall, /*event_info*/, cfg)
BOOST_FOREACH(unit_map::const_unit_iterator leader, leaders) {
DBG_NG << "...considering " + leader->id() + " as the recalling leader...\n";
map_location loc = cfg_loc;
if ( (leader_filter.null() || unit_filter::matches_filter(leader_filter, *leader, resources::filter_con)) &&
unit_filter::matches_filter(vconfig(leader->recall_filter()), *(*u),map_location(), resources::filter_con) ) {
if ( lfilt(*leader) &&
unit_filter(vconfig(leader->recall_filter()), resources::filter_con).matches( *(*u),map_location() ) ) {
DBG_NG << "...matched the leader filter and is able to recall the unit.\n";
if(!resources::gameboard->map().on_board(loc))
loc = leader->get_location();
Expand Down Expand Up @@ -1720,13 +1730,13 @@ WML_HANDLER_FUNCTION(role, /*event_info*/, cfg)
std::vector<std::string>::iterator ti = types.begin(),
ti_end = types.end();
// loop to give precedence based on type order
const unit_filter ufilt(filter, resources::filter_con);
do {
if (has_any_types) {
item["type"] = *ti;
}
unit_map::iterator itor;
BOOST_FOREACH(unit &u, *resources::units) {
if ( unit_filter::matches_filter(filter,u, resources::filter_con) ) {
if ( ufilt(u) ) {
u.set_role(cfg["role"]);
found = true;
break;
Expand All @@ -1746,6 +1756,7 @@ WML_HANDLER_FUNCTION(role, /*event_info*/, cfg)
}
// loop to give precedence based on type order
std::vector<std::string>::iterator ti = types.begin();
const unit_filter ufilt(filter, resources::filter_con);
do {
if (has_any_types) {
item["type"] = *ti;
Expand All @@ -1763,7 +1774,7 @@ WML_HANDLER_FUNCTION(role, /*event_info*/, cfg)
for(size_t i=0; i < pi->recall_list().size(); ++i) {
unit_ptr u = pi->recall_list()[i];
scoped_recall_unit auto_store("this_unit", player_id, i); //TODO: Should this not be inside the if? Explain me.
if (unit_filter::matches_filter(filter, *u, map_location(), resources::filter_con)) {
if (ufilt( *u, map_location() )) {
u->set_role(cfg["role"]);
found=true;
break;
Expand Down Expand Up @@ -2286,8 +2297,9 @@ WML_HANDLER_FUNCTION(teleport, event_info, cfg)
// Search for a valid unit filter, and if we have one, look for the matching unit
const vconfig & filter = cfg.child("filter");
if(!filter.null()) {
const unit_filter ufilt(filter, resources::filter_con);
for (u = resources::units->begin(); u != resources::units->end(); ++u){
if ( unit_filter::matches_filter(filter,*u, resources::filter_con) )
if ( ufilt(*u) )
break;
}
}
Expand Down
6 changes: 4 additions & 2 deletions src/game_events/conditional_wml.cpp
Expand Up @@ -74,9 +74,10 @@ namespace { // Support functions
std::vector<std::pair<int,int> > counts = (*u).has_attribute("count")
? utils::parse_ranges((*u)["count"]) : default_counts;
int match_count = 0;
const unit_filter ufilt(*u, resources::filter_con);
BOOST_FOREACH(const unit &i, *resources::units)
{
if ( i.hitpoints() > 0 && unit_filter::matches_filter(*u,i, resources::filter_con) ) {
if ( i.hitpoints() > 0 && ufilt(i) ) {
++match_count;
if(counts == default_counts) {
// by default a single match is enough, so avoid extra work
Expand All @@ -86,6 +87,7 @@ namespace { // Support functions
}
if ((*u)["search_recall_list"].to_bool())
{
const unit_filter ufilt(*u, resources::filter_con);
for(std::vector<team>::iterator team = resources::teams->begin();
team!=resources::teams->end(); ++team)
{
Expand All @@ -97,7 +99,7 @@ namespace { // Support functions
break;
}
scoped_recall_unit auto_store("this_unit", team->save_id(), t);
if ( unit_filter::matches_filter(*u,*team->recall_list()[t], resources::filter_con) ) {
if ( ufilt( *team->recall_list()[t] ) ) {
++match_count;
}
}
Expand Down
3 changes: 1 addition & 2 deletions src/game_events/entity_location.cpp
Expand Up @@ -20,7 +20,6 @@
#include "global.hpp"
#include "entity_location.hpp"

#include "../game_board.hpp"
#include "../resources.hpp"
#include "../unit.hpp"
#include "../unit_filter.hpp"
Expand Down Expand Up @@ -101,7 +100,7 @@ bool entity_location::matches_unit_filter(const unit_map::const_iterator & un_it

// Filter the unit at the filter location (should be the unit's
// location if no special filter location was specified).
return unit_filter::matches_filter(filter, *un_it, filter_loc_, resources::filter_con) &&
return unit_filter(filter, resources::filter_con).matches(*un_it, filter_loc_) &&
matches_unit(un_it);
}

Expand Down
3 changes: 2 additions & 1 deletion src/pathfind/teleport.cpp
Expand Up @@ -76,7 +76,8 @@ void teleport_group::get_teleport_pair(
vconfig filter(cfg_.child_or_empty("filter"), true);
vconfig source(cfg_.child_or_empty("source"), true);
vconfig target(cfg_.child_or_empty("target"), true);
if (unit_filter::matches_filter(filter, u, loc, resources::filter_con)) {
const unit_filter ufilt(filter, resources::filter_con);
if (ufilt.matches(u, loc)) {

scoped_xy_unit teleport_unit("teleport_unit", loc.x, loc.y, *resources::units);

Expand Down

0 comments on commit 383046b

Please sign in to comment.