From 383046b469b9d53c3583f7748672a3d2a84f8198 Mon Sep 17 00:00:00 2001 From: Chris Beck Date: Thu, 3 Jul 2014 14:39:08 -0400 Subject: [PATCH] replace unit filter with a function object 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 --- src/actions/create.cpp | 14 +-- src/ai/composite/goal.cpp | 6 +- src/ai/recruitment/recruitment.cpp | 8 +- src/ai/testing/aspect_attacks.cpp | 38 +++---- src/game_events/action_wml.cpp | 44 +++++--- src/game_events/conditional_wml.cpp | 6 +- src/game_events/entity_location.cpp | 3 +- src/pathfind/teleport.cpp | 3 +- src/scripting/lua.cpp | 13 ++- src/side_filter.cpp | 9 +- src/terrain_filter.cpp | 4 +- src/unit.cpp | 2 +- src/unit_abilities.cpp | 19 ++-- src/unit_animation.cpp | 4 +- src/unit_display.cpp | 3 +- src/unit_filter.cpp | 162 +++++++++++++++++----------- src/unit_filter.hpp | 28 ++++- 17 files changed, 219 insertions(+), 147 deletions(-) diff --git a/src/actions/create.cpp b/src/actions/create.cpp index 530865bce6ef..6e8819c77b61 100644 --- a/src/actions/create.cpp +++ b/src/actions/create.cpp @@ -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 ) @@ -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. diff --git a/src/ai/composite/goal.cpp b/src/ai/composite/goal.cpp index b8e39eeac279..d3f1399ba484 100644 --- a/src/ai/composite/goal.cpp +++ b/src/ai/composite/goal.cpp @@ -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); } @@ -259,13 +260,14 @@ void protect_goal::add_targets(std::back_insert_iterator< std::vector< target > std::set 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()); } diff --git a/src/ai/recruitment/recruitment.cpp b/src/ai/recruitment/recruitment.cpp index 0df705509762..38e24080648b 100644 --- a/src/ai/recruitment/recruitment.cpp +++ b/src/ai/recruitment/recruitment.cpp @@ -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()); @@ -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; } diff --git a/src/ai/testing/aspect_attacks.cpp b/src/ai/testing/aspect_attacks.cpp index 0571864211dd..0b7741a5bfa2 100644 --- a/src/ai/testing/aspect_attacks.cpp +++ b/src/ai/testing/aspect_attacks.cpp @@ -74,9 +74,10 @@ boost::shared_ptr aspect_attacks::analyze_targets() const unit_map& units_ = *resources::units; std::vector 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()); @@ -92,25 +93,26 @@ boost::shared_ptr 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; diff --git a/src/game_events/action_wml.cpp b/src/game_events/action_wml.cpp index 0c225c7b1a3e..8eeebd04606d 100644 --- a/src/game_events/action_wml.cpp +++ b/src/game_events/action_wml.cpp @@ -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; } } @@ -778,8 +779,9 @@ WML_HANDLER_FUNCTION(heal_unit, event_info, cfg) const vconfig & healers_filter = cfg.child("filter_second"); std::vector 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); } } @@ -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()); @@ -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; @@ -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 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); } } @@ -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::iterator pi = resources::teams->begin(); pi!=resources::teams->end(); ++pi) { for(std::vector::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; @@ -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; } @@ -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! @@ -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) { @@ -1543,10 +1551,12 @@ WML_HANDLER_FUNCTION(recall, /*event_info*/, cfg) recall_list_manager & avail = (*resources::teams)[index].recall_list(); std::vector 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::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(); @@ -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(); @@ -1720,13 +1730,13 @@ WML_HANDLER_FUNCTION(role, /*event_info*/, cfg) std::vector::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; @@ -1746,6 +1756,7 @@ WML_HANDLER_FUNCTION(role, /*event_info*/, cfg) } // loop to give precedence based on type order std::vector::iterator ti = types.begin(); + const unit_filter ufilt(filter, resources::filter_con); do { if (has_any_types) { item["type"] = *ti; @@ -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; @@ -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; } } diff --git a/src/game_events/conditional_wml.cpp b/src/game_events/conditional_wml.cpp index 249b94e34031..fe814e55ebd5 100644 --- a/src/game_events/conditional_wml.cpp +++ b/src/game_events/conditional_wml.cpp @@ -74,9 +74,10 @@ namespace { // Support functions std::vector > 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 @@ -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::iterator team = resources::teams->begin(); team!=resources::teams->end(); ++team) { @@ -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; } } diff --git a/src/game_events/entity_location.cpp b/src/game_events/entity_location.cpp index 310b3c3f2bbf..1d8bfb80c8ff 100644 --- a/src/game_events/entity_location.cpp +++ b/src/game_events/entity_location.cpp @@ -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" @@ -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); } diff --git a/src/pathfind/teleport.cpp b/src/pathfind/teleport.cpp index aef34495cd1b..dda736148143 100644 --- a/src/pathfind/teleport.cpp +++ b/src/pathfind/teleport.cpp @@ -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); diff --git a/src/scripting/lua.cpp b/src/scripting/lua.cpp index 4cfb15b7dde9..e3e68371fbb8 100644 --- a/src/scripting/lua.cpp +++ b/src/scripting/lua.cpp @@ -856,10 +856,11 @@ static int intf_get_units(lua_State *L) lua_newtable(L); int i = 1; unit_map &units = *resources::units; + const unit_filter ufilt(filter, resources::filter_con); // note that if filter is null, this yields a null filter matching everything for (unit_map::const_unit_iterator ui = units.begin(), ui_end = units.end(); ui != ui_end; ++ui) { - if (!filter.null() && !unit_filter::matches_filter(filter, *ui, ui->get_location(), resources::filter_con)) + if (!ufilt(*ui)) continue; new(lua_newuserdata(L, sizeof(lua_unit))) lua_unit(ui->underlying_id()); lua_pushvalue(L, 1); @@ -896,11 +897,11 @@ static int intf_match_unit(lua_State *L) team &t = (*resources::teams)[side - 1]; scoped_recall_unit auto_store("this_unit", t.save_id(), t.recall_list().find_index(u->id())); - lua_pushboolean(L, unit_filter::matches_filter(filter, *u, map_location(), resources::filter_con)); + lua_pushboolean(L, unit_filter(filter, resources::filter_con).matches(*u, map_location())); return 1; } - lua_pushboolean(L, unit_filter::matches_filter(filter, *u, u->get_location(), resources::filter_con)); + lua_pushboolean(L, unit_filter(filter, resources::filter_con).matches(*u)); return 1; } @@ -922,6 +923,7 @@ static int intf_get_recall_units(lua_State *L) lua_rawget(L, LUA_REGISTRYINDEX); lua_newtable(L); int i = 1, s = 1; + const unit_filter ufilt(filter, resources::filter_con); BOOST_FOREACH(team &t, *resources::teams) { BOOST_FOREACH(unit_ptr & u, t.recall_list()) @@ -929,7 +931,7 @@ static int intf_get_recall_units(lua_State *L) if (!filter.null()) { scoped_recall_unit auto_store("this_unit", t.save_id(), t.recall_list().find_index(u->id())); - if (!unit_filter::matches_filter(filter, *u, map_location(), resources::filter_con)) + if (!ufilt( *u, map_location() )) continue; } new(lua_newuserdata(L, sizeof(lua_unit))) lua_unit(s, u->underlying_id()); @@ -2000,11 +2002,12 @@ static int intf_find_cost_map(lua_State *L) else if (!filter.null()) // 1. arg - filter { unit_map &units = *resources::units; + const unit_filter ufilt(filter, resources::filter_con); for (unit_map::const_unit_iterator ui = units.begin(), ui_end = units.end(); ui != ui_end; ++ui) { bool on_map = ui->get_location().valid(); - if (on_map && unit_filter::matches_filter(filter, *ui,ui->get_location(), resources::filter_con)) + if (on_map && ufilt(*ui)) { real_units. push_back(&(*ui)); } diff --git a/src/side_filter.cpp b/src/side_filter.cpp index a40acbd491aa..75074275e121 100644 --- a/src/side_filter.cpp +++ b/src/side_filter.cpp @@ -135,21 +135,22 @@ bool side_filter::match_internal(const team &t) const //Allow filtering on units if(cfg_.has_child("has_unit")) { - const vconfig& unit_filter = cfg_.child("has_unit"); + const vconfig & ufilt_cfg = cfg_.child("has_unit"); + const unit_filter ufilt(ufilt_cfg, fc_, flat_); bool found = false; BOOST_FOREACH(const unit &u, fc_->get_disp_context().units()) { if (u.side() != t.side()) { continue; } - if (unit_filter::matches_filter(unit_filter, u, u.get_location(), fc_, flat_)) { + if (ufilt(u)) { found = true; break; } } - if(!found && unit_filter["search_recall_list"].to_bool(false)) { + if(!found && ufilt_cfg["search_recall_list"].to_bool(false)) { BOOST_FOREACH(const unit_const_ptr & u, t.recall_list()) { scoped_recall_unit this_unit("this_unit", t.save_id(),t.recall_list().find_index(u->id())); - if(unit_filter::matches_filter(unit_filter, *u, u->get_location(), fc_, flat_)) { + if(ufilt(*u)) { found = true; break; } diff --git a/src/terrain_filter.cpp b/src/terrain_filter.cpp index 3a429425ff89..1958f619dcd3 100644 --- a/src/terrain_filter.cpp +++ b/src/terrain_filter.cpp @@ -153,9 +153,9 @@ bool terrain_filter::match_internal(const map_location& loc, const bool ignore_x //Allow filtering on unit if(cfg_.has_child("filter")) { - const vconfig& unit_filter = cfg_.child("filter"); + const unit_filter ufilt(vconfig(cfg_.child("filter")), fc_, flat_); const unit_map::const_iterator u = fc_->get_disp_context().units().find(loc); - if (u == fc_->get_disp_context().units().end() || !unit_filter::matches_filter(unit_filter, *u, loc, fc_, flat_)) + if (u == fc_->get_disp_context().units().end() || !ufilt( *u, loc)) return false; } diff --git a/src/unit.cpp b/src/unit.cpp index 444d4a7ad8f1..1cb630cfa4d8 100644 --- a/src/unit.cpp +++ b/src/unit.cpp @@ -1580,7 +1580,7 @@ void unit::add_modification(const std::string& mod_type, const config& mod, bool { // Apply SUF. if (const config &afilter = effect.child("filter")) - if (!unit_filter::matches_filter(vconfig(afilter), *this, loc_, resources::filter_con)) continue; + if (!unit_filter(vconfig(afilter), resources::filter_con).matches(*this, loc_)) continue; const std::string &apply_to = effect["apply_to"]; const std::string &apply_times = effect["times"]; diff --git a/src/unit_abilities.cpp b/src/unit_abilities.cpp index 7a02686f3104..354cdb6a9d56 100644 --- a/src/unit_abilities.cpp +++ b/src/unit_abilities.cpp @@ -297,7 +297,7 @@ bool unit::ability_active(const std::string& ability,const config& cfg,const map assert(resources::units && resources::gameboard && resources::teams && resources::tod_manager); if (const config &afilter = cfg.child("filter")) - if ( !unit_filter::matches_filter(vconfig(afilter), *this, loc, resources::filter_con, illuminates) ) + if ( !unit_filter(vconfig(afilter), resources::filter_con, illuminates).matches(*this, loc) ) return false; map_location adjacent[6]; @@ -306,6 +306,7 @@ bool unit::ability_active(const std::string& ability,const config& cfg,const map BOOST_FOREACH(const config &i, cfg.child_range("filter_adjacent")) { + const unit_filter ufilt(vconfig(i), resources::filter_con, illuminates); BOOST_FOREACH(const std::string &j, utils::split(i["adjacent"])) { map_location::DIRECTION index = @@ -315,21 +316,22 @@ bool unit::ability_active(const std::string& ability,const config& cfg,const map unit_map::const_iterator unit = units.find(adjacent[index]); if (unit == units.end()) return false; - if (!unit_filter::matches_filter(vconfig(i), *unit, unit->get_location(), resources::filter_con, illuminates)) + if (!ufilt( *unit )) return false; } } BOOST_FOREACH(const config &i, cfg.child_range("filter_adjacent_location")) { + terrain_filter adj_filter(vconfig(i), resources::filter_con); + adj_filter.flatten(illuminates); + BOOST_FOREACH(const std::string &j, utils::split(i["adjacent"])) { map_location::DIRECTION index = map_location::parse_direction(j); if (index == map_location::NDIRECTIONS) { continue; } - terrain_filter adj_filter(vconfig(i), resources::filter_con); - adj_filter.flatten(illuminates); if(!adj_filter.match(adjacent[index])) { return false; } @@ -348,12 +350,13 @@ bool unit::ability_affects_adjacent(const std::string& ability, const config& cf assert(dir >=0 && dir <= 5); static const std::string adjacent_names[6] = {"n","ne","se","s","sw","nw"}; + BOOST_FOREACH(const config &i, cfg.child_range("affect_adjacent")) { std::vector dirs = utils::split(i["adjacent"]); if(std::find(dirs.begin(),dirs.end(),adjacent_names[dir]) != dirs.end()) { if (const config &filter = i.child("filter")) { - if ( unit_filter::matches_filter(vconfig(filter), *this, loc, resources::filter_con, illuminates) ) + if ( unit_filter(vconfig(filter), resources::filter_con, illuminates).matches(*this, loc) ) return true; } else return true; @@ -371,7 +374,7 @@ bool unit::ability_affects_self(const std::string& ability,const config& cfg,con const config &filter = cfg.child("filter_self"); bool affect_self = cfg["affect_self"].to_bool(true); if (!filter || !affect_self) return affect_self; - return unit_filter::matches_filter(vconfig(filter), *this, loc, resources::filter_con, ability == "illuminates"); + return unit_filter(vconfig(filter), resources::filter_con, ability == "illuminates").matches(*this, loc); } bool unit::has_ability_type(const std::string& ability) const @@ -794,7 +797,7 @@ namespace { // Helpers for attack_type::special_active() return true; // Check for a unit match. - if ( !un_it.valid() || !unit_filter::matches_filter(vconfig(filter_child), *un_it, loc, resources::filter_con) ) + if ( !un_it.valid() || !unit_filter(vconfig(filter_child), resources::filter_con).matches(*un_it, loc) ) return false; // Check for a weapon match. @@ -884,7 +887,7 @@ bool attack_type::special_active(const config& special, AFFECTS whom, continue; unit_map::const_iterator unit = units.find(adjacent[index]); if ( unit == units.end() || - !unit_filter::matches_filter(vconfig(i), *unit, adjacent[index], resources::filter_con) ) + !unit_filter(vconfig(i), resources::filter_con).matches(*unit, adjacent[index]) ) //TODO: Should this filter get precomputed? return false; } } diff --git a/src/unit_animation.cpp b/src/unit_animation.cpp index 1ccb0a93116b..9e6df5b17c20 100644 --- a/src/unit_animation.cpp +++ b/src/unit_animation.cpp @@ -404,7 +404,7 @@ int unit_animation::matches(const display &disp, const map_location& loc,const m } std::vector::const_iterator myitor; for(myitor = unit_filter_.begin(); myitor != unit_filter_.end(); ++myitor) { - if (!unit_filter::matches_filter(vconfig(*myitor), *my_unit, loc, &disp)) return MATCH_FAIL; + if (!unit_filter(vconfig(*myitor), &disp).matches(*my_unit, loc)) return MATCH_FAIL; //TODO: Precalculate these ++result; } if(!secondary_unit_filter_.empty()) { @@ -413,7 +413,7 @@ int unit_animation::matches(const display &disp, const map_location& loc,const m if (unit->get_location() == second_loc) { std::vector::const_iterator second_itor; for(second_itor = secondary_unit_filter_.begin(); second_itor != secondary_unit_filter_.end(); ++second_itor) { - if (!unit_filter::matches_filter(vconfig(*second_itor), *unit, second_loc, &disp)) return MATCH_FAIL; + if (!unit_filter(vconfig(*second_itor), &disp).matches(*unit, second_loc)) return MATCH_FAIL; //TODO: Precalculate these result++; } diff --git a/src/unit_display.cpp b/src/unit_display.cpp index 1a46437d3a5b..73b3d3fccf06 100644 --- a/src/unit_display.cpp +++ b/src/unit_display.cpp @@ -773,8 +773,9 @@ void wml_animation_internal(unit_animator &animator, const vconfig &cfg, const m // and if we have one, look for the matching unit 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; } } diff --git a/src/unit_filter.cpp b/src/unit_filter.cpp index 492c4f105e97..387ea83e429c 100644 --- a/src/unit_filter.cpp +++ b/src/unit_filter.cpp @@ -32,29 +32,70 @@ #include -namespace { bool internal_matches_filter(const vconfig& filter, const unit & u, const map_location& loc, const filter_context * fc, bool use_flat_tod); } +bool unit_filter::matches(const unit & u) const { + return matches (u, u.get_location()); +} + +//bool unit_filter::matches(const unit & /*u*/, const map_location & /*loc*/) const { +// assert(false && "called match against a pure abstract unit_filter! this indicates a programmer error, this function must be overrided"); +// return false; +//} + +class null_unit_filter_impl : public unit_filter_abstract_impl { +public: + null_unit_filter_impl() {} + virtual bool matches(const unit & /*u*/, const map_location & /*loc*/) const { + return true; + } + + ~null_unit_filter_impl() {} +}; + +class basic_unit_filter_impl : public unit_filter_abstract_impl { +public: + basic_unit_filter_impl(const vconfig & vcfg, const filter_context & fc, bool flat_tod) + : vcfg_(vcfg) + , fc_(fc) + , use_flat_tod_(flat_tod) + {} + virtual bool matches(const unit & u, const map_location & loc) const; + + ~basic_unit_filter_impl() {} +private: + const vconfig & vcfg_; + const filter_context & fc_; + bool use_flat_tod_; -namespace unit_filter { + bool internal_matches_filter(const unit & u, const map_location & loc) const; +}; -bool matches_filter(const vconfig& filter, const unit & u, const filter_context * fc, bool use_flat_tod) -{ return matches_filter(filter, u, u.get_location(), fc, use_flat_tod); } +unit_filter::unit_filter(const vconfig & vcfg, const filter_context * fc, bool flat_tod) +{ + if (!fc) { + assert(false && "attempt to instantiate a unit filter with a null filter context!"); + } + if (vcfg.null()) { + impl_.reset(new null_unit_filter_impl()); + } + impl_.reset(new basic_unit_filter_impl(vcfg, *fc, flat_tod)); + //TODO: Add more efficient implementations for special cases +} -bool matches_filter(const vconfig& cfg, const unit & u, const map_location& loc, const filter_context * fc, bool use_flat_tod) +bool basic_unit_filter_impl::matches(const unit & u, const map_location& loc) const { bool matches = true; if(loc.valid()) { - assert(fc != NULL); - scoped_xy_unit auto_store("this_unit", loc.x, loc.y, fc->get_disp_context().units()); - matches = internal_matches_filter(cfg, u, loc, fc, use_flat_tod); + scoped_xy_unit auto_store("this_unit", loc.x, loc.y, fc_.get_disp_context().units()); + matches = internal_matches_filter(u, loc); } else { // If loc is invalid, then this is a recall list unit (already been scoped) - matches = internal_matches_filter(cfg, u, loc, fc, use_flat_tod); + matches = internal_matches_filter(u, loc); } // Handle [and], [or], and [not] with in-order precedence - vconfig::all_children_iterator cond = cfg.ordered_begin(); - vconfig::all_children_iterator cond_end = cfg.ordered_end(); + vconfig::all_children_iterator cond = vcfg_.ordered_begin(); + vconfig::all_children_iterator cond_end = vcfg_.ordered_end(); while(cond != cond_end) { @@ -63,15 +104,15 @@ bool matches_filter(const vconfig& cfg, const unit & u, const map_location& loc, // Handle [and] if(cond_name == "and") { - matches = matches && matches_filter(cond_filter,u, loc, fc, use_flat_tod); + matches = matches && unit_filter(cond_filter, &fc_, use_flat_tod_).matches(u, loc); } // Handle [or] else if(cond_name == "or") { - matches = matches || matches_filter(cond_filter,u, loc, fc,use_flat_tod); + matches = matches || unit_filter(cond_filter, &fc_, use_flat_tod_).matches(u, loc); } // Handle [not] else if(cond_name == "not") { - matches = matches && !matches_filter(cond_filter,u, loc, fc,use_flat_tod); + matches = matches && !unit_filter(cond_filter, &fc_, use_flat_tod_).matches(u, loc); } ++cond; @@ -79,18 +120,14 @@ bool matches_filter(const vconfig& cfg, const unit & u, const map_location& loc, return matches; } -} //end namespace unit_filter - -namespace { //begin anonymous namespace - -bool internal_matches_filter(const vconfig& cfg, const unit & u, const map_location& loc, const filter_context * fc, bool use_flat_tod) +bool basic_unit_filter_impl::internal_matches_filter(const unit & u, const map_location& loc) const { - config::attribute_value cfg_name = cfg["name"]; + config::attribute_value cfg_name = vcfg_["name"]; if (!cfg_name.blank() && cfg_name.str() != u.name()) { return false; } - const config::attribute_value cfg_id = cfg["id"]; + const config::attribute_value cfg_id = vcfg_["id"]; if (!cfg_id.blank()) { const std::string& id = cfg_id; const std::string& this_id = u.id(); @@ -109,35 +146,33 @@ bool internal_matches_filter(const vconfig& cfg, const unit & u, const map_locat } // Allow 'speaker' as an alternative to id, since people use it so often - config::attribute_value cfg_speaker = cfg["speaker"]; + config::attribute_value cfg_speaker = vcfg_["speaker"]; if (!cfg_speaker.blank() && cfg_speaker.str() != u.id()) { return false; } - if(cfg.has_child("filter_location")) { - assert(fc != NULL); - const vconfig& t_cfg = cfg.child("filter_location"); - terrain_filter t_filter(t_cfg, fc, use_flat_tod); + if(vcfg_.has_child("filter_location")) { + const vconfig& t_cfg = vcfg_.child("filter_location"); + terrain_filter t_filter(t_cfg, &fc_, use_flat_tod_); if(!t_filter.match(loc)) { return false; } } - const vconfig& filter_side = cfg.child("filter_side"); + const vconfig& filter_side = vcfg_.child("filter_side"); if(!filter_side.null()) { - side_filter s_filter(filter_side, fc); + side_filter s_filter(filter_side, &fc_); if(!s_filter.match(u.side())) return false; } // Also allow filtering on location ranges outside of the location filter - config::attribute_value cfg_x = cfg["x"]; - config::attribute_value cfg_y = cfg["y"]; + config::attribute_value cfg_x = vcfg_["x"]; + config::attribute_value cfg_y = vcfg_["y"]; if (!cfg_x.blank() || !cfg_y.blank()){ if(cfg_x == "recall" && cfg_y == "recall") { //locations on the map are considered to not be on a recall list - if ((!fc && loc.valid()) || - (fc && fc->get_disp_context().map().on_board(loc))) + if (fc_.get_disp_context().map().on_board(loc)) { return false; } @@ -149,7 +184,7 @@ bool internal_matches_filter(const vconfig& cfg, const unit & u, const map_locat } // The type could be a comma separated list of types - config::attribute_value cfg_type = cfg["type"]; + config::attribute_value cfg_type = vcfg_["type"]; if (!cfg_type.blank()) { const std::string type_ids = cfg_type.str(); @@ -173,7 +208,7 @@ bool internal_matches_filter(const vconfig& cfg, const unit & u, const map_locat } // The variation_type could be a comma separated list of types - config::attribute_value cfg_variation_type = cfg["variation"]; + config::attribute_value cfg_variation_type = vcfg_["variation"]; if (!cfg_variation_type.blank()) { const std::string type_ids = cfg_variation_type.str(); @@ -197,7 +232,7 @@ bool internal_matches_filter(const vconfig& cfg, const unit & u, const map_locat } // The has_variation_type could be a comma separated list of types - config::attribute_value cfg_has_variation_type = cfg["has_variation"]; + config::attribute_value cfg_has_variation_type = vcfg_["has_variation"]; if (!cfg_has_variation_type.blank()) { const std::string& var_ids = cfg_has_variation_type.str(); @@ -223,7 +258,7 @@ bool internal_matches_filter(const vconfig& cfg, const unit & u, const map_locat } } - config::attribute_value cfg_ability = cfg["ability"]; + config::attribute_value cfg_ability = vcfg_["ability"]; if (!cfg_ability.blank()) { std::string ability = cfg_ability; @@ -246,7 +281,7 @@ bool internal_matches_filter(const vconfig& cfg, const unit & u, const map_locat } } - config::attribute_value cfg_race = cfg["race"]; + config::attribute_value cfg_race = vcfg_["race"]; if (!cfg_race.blank()) { std::string race = cfg_race; @@ -258,12 +293,12 @@ bool internal_matches_filter(const vconfig& cfg, const unit & u, const map_locat } } - config::attribute_value cfg_gender = cfg["gender"]; + config::attribute_value cfg_gender = vcfg_["gender"]; if (!cfg_gender.blank() && string_gender(cfg_gender) != u.gender()) { return false; } - config::attribute_value cfg_side = cfg["side"]; + config::attribute_value cfg_side = vcfg_["side"]; if (!cfg_side.blank() && cfg_side.to_int() != u.side()) { std::string side = cfg_side; if ( side.find(',') == std::string::npos ) { @@ -275,7 +310,7 @@ bool internal_matches_filter(const vconfig& cfg, const unit & u, const map_locat } } - config::attribute_value cfg_has_weapon = cfg["has_weapon"]; + config::attribute_value cfg_has_weapon = vcfg_["has_weapon"]; if (!cfg_has_weapon.blank()) { std::string weapon = cfg_has_weapon; bool has_weapon = false; @@ -292,38 +327,38 @@ bool internal_matches_filter(const vconfig& cfg, const unit & u, const map_locat } } - config::attribute_value cfg_role = cfg["role"]; + config::attribute_value cfg_role = vcfg_["role"]; if (!cfg_role.blank() && cfg_role.str() != u.get_role()) { return false; } - config::attribute_value cfg_ai_special = cfg["ai_special"]; + config::attribute_value cfg_ai_special = vcfg_["ai_special"]; if (!cfg_ai_special.blank() && ((cfg_ai_special.str() == "guardian") != u.get_state(unit::STATE_GUARDIAN))) { return false; } - config::attribute_value cfg_canrecruit = cfg["canrecruit"]; + config::attribute_value cfg_canrecruit = vcfg_["canrecruit"]; if (!cfg_canrecruit.blank() && cfg_canrecruit.to_bool() != u.can_recruit()) { return false; } - config::attribute_value cfg_recall_cost = cfg["recall_cost"]; + config::attribute_value cfg_recall_cost = vcfg_["recall_cost"]; if (!cfg_recall_cost.blank() && cfg_recall_cost.to_int(-1) != u.recall_cost()) { return false; } - config::attribute_value cfg_level = cfg["level"]; + config::attribute_value cfg_level = vcfg_["level"]; if (!cfg_level.blank() && cfg_level.to_int(-1) != u.level()) { return false; } - config::attribute_value cfg_defense = cfg["defense"]; - if (!cfg_defense.blank() && cfg_defense.to_int(-1) != u.defense_modifier(fc->get_disp_context().map().get_terrain(loc))) { + config::attribute_value cfg_defense = vcfg_["defense"]; + if (!cfg_defense.blank() && cfg_defense.to_int(-1) != u.defense_modifier(fc_.get_disp_context().map().get_terrain(loc))) { return false; } - config::attribute_value cfg_movement = cfg["movement_cost"]; - if (!cfg_movement.blank() && cfg_movement.to_int(-1) != u.movement_cost(fc->get_disp_context().map().get_terrain(loc))) { + config::attribute_value cfg_movement = vcfg_["movement_cost"]; + if (!cfg_movement.blank() && cfg_movement.to_int(-1) != u.movement_cost(fc_.get_disp_context().map().get_terrain(loc))) { return false; } @@ -331,7 +366,7 @@ bool internal_matches_filter(const vconfig& cfg, const unit & u, const map_locat // If a key is in the unit and in the filter, they should match // filter only => not for us // unit only => not filtered - const vconfig::child_list& wmlcfgs = cfg.get_children("filter_wml"); + const vconfig::child_list& wmlcfgs = vcfg_.get_children("filter_wml"); if (!wmlcfgs.empty()) { config unit_cfg; for (unsigned i = 0; i < wmlcfgs.size(); ++i) @@ -355,14 +390,14 @@ bool internal_matches_filter(const vconfig& cfg, const unit & u, const map_locat } } - if (cfg.has_child("filter_vision")) { - const vconfig::child_list& vis_filt = cfg.get_children("filter_vision"); + if (vcfg_.has_child("filter_vision")) { + const vconfig::child_list& vis_filt = vcfg_.get_children("filter_vision"); vconfig::child_list::const_iterator i, i_end = vis_filt.end(); for (i = vis_filt.begin(); i != i_end; ++i) { bool visible = (*i)["visible"].to_bool(true); std::set viewers; // Use standard side filter - side_filter ssf(*i, fc); + side_filter ssf(*i, &fc_); std::vector sides = ssf.get_teams(); viewers.insert(sides.begin(), sides.end()); if (viewers.empty()) { @@ -370,7 +405,7 @@ bool internal_matches_filter(const vconfig& cfg, const unit & u, const map_locat } std::set::const_iterator viewer, viewer_end = viewers.end(); for (viewer = viewers.begin(); viewer != viewer_end; ++viewer) { - bool fogged = fc->get_disp_context().teams()[*viewer - 1].fogged(loc); + bool fogged = fc_.get_disp_context().teams()[*viewer - 1].fogged(loc); bool hiding = u.invisible(loc/*, false(?) */); bool unit_hidden = fogged || hiding; if (visible == unit_hidden) return false; @@ -378,13 +413,12 @@ bool internal_matches_filter(const vconfig& cfg, const unit & u, const map_locat } } - if (cfg.has_child("filter_adjacent")) { - assert(fc); - const unit_map& units = fc->get_disp_context().units(); + if (vcfg_.has_child("filter_adjacent")) { + const unit_map& units = fc_.get_disp_context().units(); map_location adjacent[6]; get_adjacent_tiles(loc, adjacent); vconfig::child_list::const_iterator i, i_end; - const vconfig::child_list& adj_filt = cfg.get_children("filter_adjacent"); + const vconfig::child_list& adj_filt = vcfg_.get_children("filter_adjacent"); for (i = adj_filt.begin(), i_end = adj_filt.end(); i != i_end; ++i) { int match_count=0; config::attribute_value i_adjacent = (*i)["adjacent"]; @@ -394,12 +428,12 @@ bool internal_matches_filter(const vconfig& cfg, const unit & u, const map_locat for (j = dirs.begin(); j != j_end; ++j) { unit_map::const_iterator unit_itor = units.find(adjacent[*j]); if (unit_itor == units.end() - || !unit_filter::matches_filter(*i, *unit_itor, unit_itor->get_location(), fc, use_flat_tod)) { + || !unit_filter(*i, &fc_, use_flat_tod_).matches(*unit_itor)) { continue; } config::attribute_value i_is_enemy = (*i)["is_enemy"]; if (i_is_enemy.blank() || i_is_enemy.to_bool() == - fc->get_disp_context().teams()[u.side() - 1].is_enemy(unit_itor->side())) { + fc_.get_disp_context().teams()[u.side() - 1].is_enemy(unit_itor->side())) { ++match_count; } } @@ -413,7 +447,7 @@ bool internal_matches_filter(const vconfig& cfg, const unit & u, const map_locat } } - config::attribute_value cfg_find_in = cfg["find_in"]; + config::attribute_value cfg_find_in = vcfg_["find_in"]; if (!cfg_find_in.blank()) { // Allow filtering by searching a stored variable of units variable_info vi(cfg_find_in, false, variable_info::TYPE_CONTAINER); @@ -429,14 +463,14 @@ bool internal_matches_filter(const vconfig& cfg, const unit & u, const map_locat return false; } } - config::attribute_value cfg_formula = cfg["formula"]; + config::attribute_value cfg_formula = vcfg_["formula"]; if (!cfg_formula.blank()) { if (!u.formula_manager().matches_filter(cfg_formula, loc, u)) { return false; } } - config::attribute_value cfg_lua_function = cfg["lua_function"]; + config::attribute_value cfg_lua_function = vcfg_["lua_function"]; if (!cfg_lua_function.blank()) { bool b = resources::lua_kernel->run_filter(cfg_lua_function.str().c_str(), u); if (!b) return false; @@ -444,5 +478,3 @@ bool internal_matches_filter(const vconfig& cfg, const unit & u, const map_locat return true; } - -} //end anonymous namespace diff --git a/src/unit_filter.hpp b/src/unit_filter.hpp index 1d8d8b757173..06c9e3d82417 100644 --- a/src/unit_filter.hpp +++ b/src/unit_filter.hpp @@ -23,17 +23,37 @@ * these to speed up repeated application of the filter. */ +#include + class filter_context; class unit; class vconfig; struct map_location; -namespace unit_filter { +class unit_filter_abstract_impl { +public: + virtual bool matches(const unit & u, const map_location & loc) const = 0; +}; + +class unit_filter { +public: + unit_filter(const vconfig & cfg, const filter_context * fc, bool use_flat_tod = false); //!< Constructs a unit filter from a config and a context. This function should give the most efficient implementation available. - bool matches_filter(const vconfig& cfg,const unit & u, const map_location& loc, const filter_context * board, bool use_flat_tod=false); + bool matches(const unit & u, const map_location & loc) const { + return impl_->matches(u,loc); + } /// Determine if *this matches @a filter at its current location. /// (Only use for units currently on the map; otherwise use the overload /// that takes a location, possibly with a null location.) - bool matches_filter(const vconfig& filter, const unit & u, const filter_context* board, bool use_flat_tod=false); + bool matches(const unit & u) const; + + bool operator()(const unit & u, const map_location & loc) const { + return matches(u,loc); + } -} + bool operator()(const unit & u) const { + return matches(u); + } +private: + boost::scoped_ptr impl_; +};