diff --git a/src/terrain/filter.cpp b/src/terrain/filter.cpp index 014f351098bd..5b3eab951dfa 100644 --- a/src/terrain/filter.cpp +++ b/src/terrain/filter.cpp @@ -33,6 +33,8 @@ #include "formula/callable_objects.hpp" #include "formula/formula.hpp" +#include + static lg::log_domain log_engine("engine"); #define ERR_NG LOG_STREAM(err, log_engine) #define WRN_NG LOG_STREAM(warn, log_engine) @@ -420,171 +422,88 @@ bool terrain_filter::match(const map_location& loc) const } return false; } - -void terrain_filter::get_locations(std::set& locs, bool with_border) const +//using a class to be able to firen it in terrain_filter +class terrain_filterimpl { - std::set match_set; - - // See if the caller provided an override to with_border - with_border = cfg_["include_borders"].to_bool(with_border); - - // None of the generators provided - if ( !cfg_.has_attribute("x") && !cfg_.has_attribute("y") - && !cfg_.has_attribute("find_in") - && !cfg_.has_attribute("area") ) { +public: + using location_set = std::set; + struct tno_start_set_yet {}; + struct tno_filter + { + bool operator()(const map_location&) const { return true; } + }; - //consider all locations on the map - int bs = fc_->get_disp_context().map().border_size(); - int w = with_border ? fc_->get_disp_context().map().w() + bs : fc_->get_disp_context().map().w(); - int h = with_border ? fc_->get_disp_context().map().h() + bs : fc_->get_disp_context().map().h(); - for (int x = with_border ? 0 - bs : 0; x < w; ++x) { - for (int y = with_border ? 0 - bs : 0; y < h; ++y) { - match_set.insert(map_location(x,y)); + template + static void filter_final(T&& src, location_set& dest, const terrain_filter&, const F1& f1, const F2& f2) + { + for (const map_location &loc : src) { + if (f1(loc) && f2(loc)) { + dest.insert(loc); } } - } else - - // Only the x,y attributes found - if ( (cfg_.has_attribute("x") || cfg_.has_attribute("y")) - && !cfg_.has_attribute("find_in") - && !cfg_.has_attribute("area") ) { - - std::vector xy_vector; - xy_vector = fc_->get_disp_context().map().parse_location_range(cfg_["x"], cfg_["y"], with_border); - match_set.insert(xy_vector.begin(), xy_vector.end()); - } else - - // Only find_in provided - if ( !cfg_.has_attribute("x") && !cfg_.has_attribute("y") - && cfg_.has_attribute("find_in") - && !cfg_.has_attribute("area") ) { + } - //use content of find_in as starting set - if (const game_data * gd = fc_->get_game_data()) { - try - { - variable_access_const vi = gd->get_variable_access_read(cfg_["find_in"]); - for (const config& cfg : vi.as_array()) - { - map_location test_loc(cfg, nullptr); - match_set.insert(test_loc); - } - } - catch(const invalid_variablename_exception&) - { - //Do nothing - } + template + static void filter_area(T&& src, location_set& dest, const terrain_filter& filter, const F1& f1) + { + if (filter.cfg_.has_attribute("area")) { + const std::set& area = filter.fc_->get_tod_man().get_area_by_id(filter.cfg_["area"]); + filter_final(src, dest, filter, f1, [&area](const map_location& loc) { return area.find(loc) != area.end(); }); } - } else - - // Only area provided - if ( !cfg_.has_attribute("x") && !cfg_.has_attribute("y") - && !cfg_.has_attribute("find_in") - && cfg_.has_attribute("area") ) { - - const std::set& area = fc_->get_tod_man().get_area_by_id(cfg_["area"]); - match_set.insert(area.begin(), area.end()); - } else - - // find_in + xy - if ( (cfg_.has_attribute("x") || cfg_.has_attribute("y")) - && cfg_.has_attribute("find_in") - && !cfg_.has_attribute("area") ) { - - std::vector xy_vector; - xy_vector = fc_->get_disp_context().map().parse_location_range(cfg_["x"], cfg_["y"], with_border); - match_set.insert(xy_vector.begin(), xy_vector.end()); - - // remove any locations not found in the specified variable - if (const game_data * gd = fc_->get_game_data()) { - try - { - std::set findin_locs; - variable_access_const vi = gd->get_variable_access_read(cfg_["find_in"]); - for (const config& cfg : vi.as_array()) - { - map_location test_loc(cfg, nullptr); - if (match_set.count(test_loc)) { - findin_locs.insert(test_loc); - } - } - match_set.swap(findin_locs); - } - catch(const invalid_variablename_exception&) - { - match_set.clear(); - } + else { + filter_final(src, dest, filter, f1, tno_filter()); } - } else - - // xy + area - if ( (cfg_.has_attribute("x") || cfg_.has_attribute("y")) - && !cfg_.has_attribute("find_in") - && cfg_.has_attribute("area") ) { - - std::vector xy_vector; - xy_vector = fc_->get_disp_context().map().parse_location_range(cfg_["x"], cfg_["y"], with_border); - const std::set& area = fc_->get_tod_man().get_area_by_id(cfg_["area"]); + } - for (const map_location& loc : xy_vector) { - if (area.count(loc) != 0) - match_set.insert(loc); + template + static void filter_xy(T&& src, location_set& dest, const terrain_filter& filter, bool with_border) + { + if (filter.cfg_.has_attribute("x") || filter.cfg_.has_attribute("y")) { + std::vector xy_vector = filter.fc_->get_disp_context().map().parse_location_range(filter.cfg_["x"], filter.cfg_["y"], with_border); + filter_area(src, dest, filter, [&xy_vector](const map_location& loc) { return std::find(xy_vector.begin(), xy_vector.end(), loc) != xy_vector.end(); }); } - } else - - // area + find_in - if ( !(cfg_.has_attribute("x") && cfg_.has_attribute("y")) - && cfg_.has_attribute("find_in") - && cfg_.has_attribute("area") ) { + else { + filter_area(src, dest, filter, tno_filter()); + } + } +}; +void terrain_filter::get_locations(std::set& locs, bool with_border) const +{ + std::set match_set; - const std::set& area = fc_->get_tod_man().get_area_by_id(cfg_["area"]); + // See if the caller provided an override to with_border + with_border = cfg_["include_borders"].to_bool(with_border); - //use content of find_in as starting set + if (cfg_.has_attribute("find_in")) { if (const game_data * gd = fc_->get_game_data()) { try { - variable_access_const vi = gd->get_variable_access_read(cfg_["find_in"]); - for (const config& cfg : vi.as_array()) - { - map_location test_loc(cfg, nullptr); - if (area.count(test_loc) != 0) - match_set.insert(test_loc); - } + auto ar = gd->get_variable_access_read(cfg_["find_in"]).as_array(); + terrain_filterimpl::filter_xy(ar | boost::adaptors::transformed([](const config& cfg) { return map_location(cfg, nullptr);}), match_set, *this, with_border); } - catch(const invalid_variablename_exception&) + catch (const invalid_variablename_exception&) { - match_set.clear(); + //Do nothing } } - } else - - // area + find_in + xy - if ( (cfg_.has_attribute("x") && cfg_.has_attribute("y")) - && cfg_.has_attribute("find_in") - && cfg_.has_attribute("area") ) { - - const std::vector& xy_vector = - fc_->get_disp_context().map().parse_location_range(cfg_["x"], cfg_["y"], with_border); - std::set xy_set(xy_vector.begin(), xy_vector.end()); - + } + else if (cfg_.has_attribute("x") || cfg_.has_attribute("y")) { + std::vector xy_vector = fc_->get_disp_context().map().parse_location_range(cfg_["x"], cfg_["y"], with_border); + terrain_filterimpl::filter_area(xy_vector, match_set, *this, terrain_filterimpl::tno_filter()); + } + else if (cfg_.has_attribute("area")) { const std::set& area = fc_->get_tod_man().get_area_by_id(cfg_["area"]); - - //use content of find_in as starting set - if (const game_data * gd = fc_->get_game_data()) { - try - { - variable_access_const vi = gd->get_variable_access_read(cfg_["find_in"]); - - for (const config &cfg : vi.as_array()) { - map_location test_loc(cfg, nullptr); - if (area.count(test_loc) != 0 && xy_set.count(test_loc) != 0) - match_set.insert(test_loc); - } - } - catch(const invalid_variablename_exception&) - { - //Do nothing + terrain_filterimpl::filter_final(area, match_set, *this, terrain_filterimpl::tno_filter(), terrain_filterimpl::tno_filter()); + } + else { + //consider all locations on the map + int bs = fc_->get_disp_context().map().border_size(); + int w = with_border ? fc_->get_disp_context().map().w() + bs : fc_->get_disp_context().map().w(); + int h = with_border ? fc_->get_disp_context().map().h() + bs : fc_->get_disp_context().map().h(); + for (int x = with_border ? 0 - bs : 0; x < w; ++x) { + for (int y = with_border ? 0 - bs : 0; y < h; ++y) { + match_set.insert(map_location(x, y)); } } } diff --git a/src/terrain/filter.hpp b/src/terrain/filter.hpp index 3c0dbf3c54e8..5f421cd10072 100644 --- a/src/terrain/filter.hpp +++ b/src/terrain/filter.hpp @@ -66,6 +66,7 @@ class terrain_filter : public xy_pred { void flatten(const bool flat_tod=true) { flat_ = flat_tod; } config to_config() const; + friend class terrain_filterimpl; private: bool match_internal(const map_location& loc, const bool ignore_xy) const;