From f82fdb224e6bb51b780745c8f03dcd959b59b6e1 Mon Sep 17 00:00:00 2001 From: Celtic Minstrel Date: Sat, 9 Nov 2019 19:49:31 -0500 Subject: [PATCH] Enable filtering by upkeep in SUF Supports both numeric values and the special values loyal, free, full. Closes #3333 --- src/units/filter.cpp | 15 +++++++++++++++ src/units/unit.cpp | 14 ++++---------- src/units/unit.hpp | 35 +++++++++++++++++++++++++++++++++++ 3 files changed, 54 insertions(+), 10 deletions(-) diff --git a/src/units/filter.cpp b/src/units/filter.cpp index d8aa2dae5469..60629d74edb3 100644 --- a/src/units/filter.cpp +++ b/src/units/filter.cpp @@ -433,6 +433,21 @@ void unit_filter_compound::fill(vconfig cfg) return gender == args.u.gender(); } ); + + create_attribute(literal["upkeep"], + [](const config::attribute_value& c) -> unit::upkeep_t + { + try { + return c.apply_visitor(unit::upkeep_parser_visitor()); + } catch(std::invalid_argument&) { + return unit::upkeep_full(); + } + }, + [](unit::upkeep_t upkeep, const unit_filter_args& args) + { + return args.u.upkeep() == boost::apply_visitor(unit::upkeep_value_visitor(args.u), upkeep); + } + ); create_attribute(literal["side"], [](const config::attribute_value& c) diff --git a/src/units/unit.cpp b/src/units/unit.cpp index b474ec8be43e..03c01dc05668 100644 --- a/src/units/unit.cpp +++ b/src/units/unit.cpp @@ -2635,16 +2635,10 @@ void unit::parse_upkeep(const config::attribute_value& upkeep) return; } - // TODO: create abetter way to check whether it is actually an int. - int upkeep_int = upkeep.to_int(-99); - if(upkeep_int != -99) { - upkeep_ = upkeep_int; - } else if(upkeep == upkeep_loyal::type() || upkeep == "free") { - upkeep_ = upkeep_loyal(); - } else if(upkeep == upkeep_full::type()) { - upkeep_ = upkeep_full(); - } else { - WRN_UT << "Found invalid upkeep=\"" << upkeep << "\" in a unit" << std::endl; + try { + upkeep_ = upkeep.apply_visitor(upkeep_parser_visitor()); + } catch(std::invalid_argument& e) { + WRN_UT << "Found invalid upkeep=\"" << e.what() << "\" in a unit" << std::endl; upkeep_ = upkeep_full(); } } diff --git a/src/units/unit.hpp b/src/units/unit.hpp index ad9451558e6d..50eed840bbcf 100644 --- a/src/units/unit.hpp +++ b/src/units/unit.hpp @@ -1132,6 +1132,41 @@ class unit }; using upkeep_t = boost::variant; + + /** Visitor helper class to parse the upkeep value from a config. */ + class upkeep_parser_visitor : public boost::static_visitor + { + public: + template + std::enable_if_t::value, upkeep_t> + operator()(N n) const + { + if(n == 0) return upkeep_loyal(); + if(n < 0) throw std::invalid_argument(std::to_string(n)); + return n; + } + + template + std::enable_if_t::value && !std::is_arithmetic::value, upkeep_t> + operator()(B b) const + { + throw std::invalid_argument(b.str()); + } + + upkeep_t operator()(boost::blank) const + { + return upkeep_full(); + } + + upkeep_t operator()(const std::string& s) const + { + if(s == "loyal" || s == "free") + return upkeep_loyal(); + if(s == "full") + return upkeep_full(); + throw std::invalid_argument(s); + } + }; /** * Gets the raw variant controlling the upkeep value.