diff --git a/src/ai/composite/value_translator.hpp b/src/ai/composite/value_translator.hpp index 76e9ddd616def..d15c63b0955c4 100644 --- a/src/ai/composite/value_translator.hpp +++ b/src/ai/composite/value_translator.hpp @@ -342,7 +342,7 @@ class variant_value_translator { { std::vector vars; for(attacks_vector::const_iterator i = value.begin(); i != value.end(); ++i) { - vars.emplace_back(new attack_analysis(*i)); + vars.emplace_back(std::make_shared(*i)); } var = wfl::variant(vars); } diff --git a/src/ai/default/attack.cpp b/src/ai/default/attack.cpp index 7fdc1bb0438ec..e5f6f3b0c4468 100644 --- a/src/ai/default/attack.cpp +++ b/src/ai/default/attack.cpp @@ -40,7 +40,7 @@ static lg::log_domain log_ai("ai/attack"); namespace ai { -extern ai_context& get_ai_context(const wfl::formula_callable* for_fai); +extern ai_context& get_ai_context(wfl::const_formula_callable_ptr for_fai); void attack_analysis::analyze(const gamemap& map, unit_map& units, const readonly_context& ai_obj, @@ -335,13 +335,13 @@ wfl::variant attack_analysis::get_value(const std::string& key) const { using namespace wfl; if(key == "target") { - return variant(new location_callable(target)); + return variant(std::make_shared(target)); } else if(key == "movements") { std::vector res; for(size_t n = 0; n != movements.size(); ++n) { - map_formula_callable* item = new map_formula_callable(nullptr); - item->add("src", variant(new location_callable(movements[n].first))); - item->add("dst", variant(new location_callable(movements[n].second))); + auto item = std::make_shared(nullptr); + item->add("src", variant(std::make_shared(movements[n].first))); + item->add("dst", variant(std::make_shared(movements[n].second))); res.emplace_back(item); } @@ -349,7 +349,7 @@ wfl::variant attack_analysis::get_value(const std::string& key) const } else if(key == "units") { std::vector res; for(size_t n = 0; n != movements.size(); ++n) { - res.emplace_back(new location_callable(movements[n].first)); + res.emplace_back(std::make_shared(movements[n].first)); } return variant(res); @@ -429,7 +429,7 @@ wfl::variant attack_analysis::execute_self(wfl::variant ctxt) { //check if target is still valid unit = units.find(att_dst); if(unit == units.end()) { - return wfl::variant(new wfl::safe_call_result(this, attack_result::E_EMPTY_DEFENDER, move_from)); + return wfl::variant(std::make_shared(fake_ptr(), attack_result::E_EMPTY_DEFENDER, move_from)); } //check if we need to move @@ -437,14 +437,14 @@ wfl::variant attack_analysis::execute_self(wfl::variant ctxt) { //now check if location to which we want to move is still unoccupied unit = units.find(att_src); if(unit != units.end()) { - return wfl::variant(new wfl::safe_call_result(this, move_result::E_NO_UNIT, move_from)); + return wfl::variant(std::make_shared(fake_ptr(), move_result::E_NO_UNIT, move_from)); } ai::move_result_ptr result = get_ai_context(ctxt.as_callable()).execute_move_action(move_from, att_src); if(!result->is_ok()) { //move part failed LOG_AI << "ERROR #" << result->get_status() << " while executing 'attack' formula function\n" << std::endl; - return wfl::variant(new wfl::safe_call_result(this, result->get_status(), result->get_unit_location())); + return wfl::variant(std::make_shared(fake_ptr(), result->get_status(), result->get_unit_location())); } } @@ -453,7 +453,7 @@ wfl::variant attack_analysis::execute_self(wfl::variant ctxt) { if(!result->is_ok()) { //attack failed LOG_AI << "ERROR #" << result->get_status() << " while executing 'attack' formula function\n" << std::endl; - return wfl::variant(new wfl::safe_call_result(this, result->get_status())); + return wfl::variant(std::make_shared(fake_ptr(), result->get_status())); } } return wfl::variant(true); diff --git a/src/ai/formula/ai.cpp b/src/ai/formula/ai.cpp index 8191938aac289..05589829522dc 100644 --- a/src/ai/formula/ai.cpp +++ b/src/ai/formula/ai.cpp @@ -105,6 +105,7 @@ formula_ai::formula_ai(readonly_context &context, const config &cfg) cfg_(cfg), recursion_counter_(context.get_recursion_count()), keeps_cache_(), + attacks_callable(*this, resources::gameboard->units()), // infinite_loop_guardian_(), vars_(), function_table_(*this) @@ -162,13 +163,13 @@ std::string formula_ai::evaluate(const std::string& formula_str) formula f(formula_str, &function_table_); - map_formula_callable callable(this); + map_formula_callable callable(fake_ptr()); //formula_debugger fdb; const variant v = f.evaluate(callable,nullptr); if (ai_ptr_) { - variant var = variant(this).execute_variant(v); + variant var = variant(this->fake_ptr()).execute_variant(v); if ( !var.is_empty() ) { return "Made move: " + var.to_debug_string(); @@ -194,7 +195,7 @@ wfl::variant formula_ai::make_action(wfl::const_formula_ptr formula_, const wfl: variant res; if (ai_ptr_) { - res = variant(this).execute_variant(var); + res = variant(this->fake_ptr()).execute_variant(var); } else { ERR_AI << "skipped execution of action because ai context is not set correctly" << std::endl; } @@ -276,7 +277,7 @@ variant villages_from_set(const Container& villages, if(exclude && exclude->count(loc)) { continue; } - vars.emplace_back(new location_callable(loc)); + vars.emplace_back(std::make_shared(loc)); } return variant(vars); @@ -368,7 +369,7 @@ variant formula_ai::get_value(const std::string& key) const } else if(key == "my_side") { - return variant(new team_callable(resources::gameboard->teams()[get_side()-1])); + return variant(std::make_shared(resources::gameboard->teams()[get_side()-1])); } else if(key == "my_side_number") { @@ -378,7 +379,7 @@ variant formula_ai::get_value(const std::string& key) const { std::vector vars; for(std::vector::const_iterator i = resources::gameboard->teams().begin(); i != resources::gameboard->teams().end(); ++i) { - vars.emplace_back(new team_callable(*i)); + vars.emplace_back(std::make_shared(*i)); } return variant(vars); @@ -415,7 +416,7 @@ variant formula_ai::get_value(const std::string& key) const const unit_type *ut = unit_types.find(*i); if (ut) { - vars.emplace_back(new unit_type_callable(*ut)); + vars.emplace_back(std::make_shared(*ut)); } } return variant(vars); @@ -441,7 +442,7 @@ variant formula_ai::get_value(const std::string& key) const const unit_type *ut = unit_types.find(*str_it); if (ut) { - tmp[i].emplace_back(new unit_type_callable(*ut)); + tmp[i].emplace_back(std::make_shared(*ut)); } } } @@ -454,7 +455,7 @@ variant formula_ai::get_value(const std::string& key) const { std::vector vars; for(unit_map::const_iterator i = units.begin(); i != units.end(); ++i) { - vars.emplace_back(new unit_callable(*i)); + vars.emplace_back(std::make_shared(*i)); } return variant(vars); @@ -468,7 +469,7 @@ variant formula_ai::get_value(const std::string& key) const tmp.push_back( v ); } for(const unit &u : units) { - tmp[u.side() - 1].emplace_back(new unit_callable(u)); + tmp[u.side() - 1].emplace_back(std::make_shared(u)); } for( size_t i = 0; i vars; for(unit_map::const_iterator i = units.begin(); i != units.end(); ++i) { if (i->side() == get_side()) { - vars.emplace_back(new unit_callable(*i)); + vars.emplace_back(std::make_shared(*i)); } } return variant(vars); @@ -490,7 +491,7 @@ variant formula_ai::get_value(const std::string& key) const for(unit_map::const_iterator i = units.begin(); i != units.end(); ++i) { if (current_team().is_enemy(i->side())) { if (!i->incapacitated()) { - vars.emplace_back(new unit_callable(*i)); + vars.emplace_back(std::make_shared(*i)); } } } @@ -498,14 +499,14 @@ variant formula_ai::get_value(const std::string& key) const } else if(key == "my_moves") { - return variant(new move_map_callable(get_srcdst(), get_dstsrc(), units)); + return variant(std::make_shared(get_srcdst(), get_dstsrc(), units)); } else if(key == "my_attacks") { - return variant(new attack_map_callable(*this, units)); + return variant(attacks_callable.fake_ptr()); } else if(key == "enemy_moves") { - return variant(new move_map_callable(get_enemy_srcdst(), get_enemy_dstsrc(), units)); + return variant(std::make_shared(get_enemy_srcdst(), get_enemy_dstsrc(), units)); } else if(key == "my_leader") { @@ -513,27 +514,27 @@ variant formula_ai::get_value(const std::string& key) const if(i == units.end()) { return variant(); } - return variant(new unit_callable(*i)); + return variant(std::make_shared(*i)); } else if(key == "recall_list") { std::vector tmp; for(std::vector::const_iterator i = current_team().recall_list().begin(); i != current_team().recall_list().end(); ++i) { - tmp.push_back( variant( new unit_callable(**i) ) ); + tmp.push_back( variant(std::make_shared(**i) ) ); } return variant(tmp); } else if(key == "vars") { - return variant(&vars_); + return variant(vars_.fake_ptr()); } else if(key == "keeps") { return get_keeps(); } else if(key == "map") { - return variant(new gamemap_callable(resources::gameboard->map())); + return variant(std::make_shared(resources::gameboard->map())); } else if(key == "villages") { return villages_from_set(resources::gameboard->map().villages()); @@ -609,7 +610,7 @@ variant formula_ai::get_keeps() const get_adjacent_tiles(loc,adj); for(size_t n = 0; n != 6; ++n) { if(resources::gameboard->map().is_castle(adj[n])) { - vars.emplace_back(new location_callable(loc)); + vars.emplace_back(std::make_shared(loc)); break; } } @@ -683,7 +684,7 @@ void formula_ai::evaluate_candidate_action(ca_ptr fai_ca) bool formula_ai::execute_candidate_action(ca_ptr fai_ca) { - map_formula_callable callable(this); + map_formula_callable callable(fake_ptr()); fai_ca->update_callable_map( callable ); const_formula_ptr move_formula(fai_ca->get_action()); return !make_action(move_formula, callable).is_empty(); diff --git a/src/ai/formula/ai.hpp b/src/ai/formula/ai.hpp index f550b576d2668..1fbb3f21760b1 100644 --- a/src/ai/formula/ai.hpp +++ b/src/ai/formula/ai.hpp @@ -166,13 +166,14 @@ class formula_ai : public readonly_context_proxy, public wfl::formula_callable { virtual void get_inputs(wfl::formula_input_vector& inputs) const override; mutable wfl::variant keeps_cache_; + wfl::attack_map_callable attacks_callable; // gamestate_change_observer infinite_loop_guardian_; wfl::map_formula_callable vars_; wfl::ai_function_symbol_table function_table_; friend class ai_default; - friend ai_context& get_ai_context(const formula_callable* for_fai); + friend ai_context& get_ai_context(wfl::const_formula_callable_ptr for_fai); }; } //end of namespace ai diff --git a/src/ai/formula/callable_objects.cpp b/src/ai/formula/callable_objects.cpp index e4a178acf5393..2f394c40703cd 100644 --- a/src/ai/formula/callable_objects.cpp +++ b/src/ai/formula/callable_objects.cpp @@ -33,10 +33,10 @@ static lg::log_domain log_formula_ai("ai/engine/fai"); namespace ai { -ai_context& get_ai_context(const wfl::formula_callable* for_fai) { - const formula_ai* fai = dynamic_cast(for_fai); - assert(fai != nullptr); // Why not just use dynamic_cast instead then? - return *const_cast(fai)->ai_ptr_; +ai_context& get_ai_context(wfl::const_formula_callable_ptr for_fai) { + auto fai = std::dynamic_pointer_cast(for_fai); + assert(fai != nullptr); + return *std::const_pointer_cast(fai)->ai_ptr_; } } @@ -50,7 +50,7 @@ variant move_map_callable::get_value(const std::string& key) const std::vector vars; for(move_map::const_iterator i = srcdst_.begin(); i != srcdst_.end(); ++i) { if( i->first == i->second || units_.count(i->second) == 0) { - move_callable* item = new move_callable(i->first, i->second); + auto item = std::make_shared(i->first, i->second); vars.emplace_back(item); } } @@ -91,7 +91,7 @@ variant move_callable::execute_self(variant ctxt) { if(!move_result->is_ok()) { LOG_AI << "ERROR #" << move_result->get_status() << " while executing 'move' formula function\n" << std::endl; - return variant(new safe_call_result(this, move_result->get_status(), move_result->get_unit_location())); + return variant(std::make_shared(fake_ptr(), move_result->get_status(), move_result->get_unit_location())); } return variant(move_result->is_gamestate_changed()); @@ -120,7 +120,7 @@ variant move_partial_callable::execute_self(variant ctxt) { if(!move_result->is_ok()) { LOG_AI << "ERROR #" << move_result->get_status() << " while executing 'move_partial' formula function\n" << std::endl; - return variant(new safe_call_result(this, move_result->get_status(), move_result->get_unit_location())); + return variant(std::make_shared(fake_ptr(), move_result->get_status(), move_result->get_unit_location())); } return variant(move_result->is_gamestate_changed()); @@ -169,11 +169,11 @@ attack_callable::attack_callable(const map_location& move_from, variant attack_callable::get_value(const std::string& key) const { if(key == "attack_from") { - return variant(new location_callable(src_)); + return variant(std::make_shared(src_)); } else if(key == "defender") { - return variant(new location_callable(dst_)); + return variant(std::make_shared(dst_)); } else if(key == "move_from") { - return variant(new location_callable(move_from_)); + return variant(std::make_shared(move_from_)); } else { return variant(); } @@ -225,7 +225,7 @@ variant attack_callable::execute_self(variant ctxt) { if(!move_result->is_ok()) { //move part failed LOG_AI << "ERROR #" << move_result->get_status() << " while executing 'attack' formula function\n" << std::endl; - return variant(new safe_call_result(this, move_result->get_status(), move_result->get_unit_location())); + return variant(std::make_shared(fake_ptr(), move_result->get_status(), move_result->get_unit_location())); } } @@ -236,7 +236,7 @@ variant attack_callable::execute_self(variant ctxt) { if(!attack_result->is_ok()) { //attack failed LOG_AI << "ERROR #" << attack_result->get_status() << " while executing 'attack' formula function\n" << std::endl; - return variant(new safe_call_result(this, attack_result->get_status())); + return variant(std::make_shared(fake_ptr(), attack_result->get_status())); } } @@ -287,7 +287,7 @@ void attack_map_callable::collect_possible_attacks(std::vector& vars, m unit->invisible(unit->get_location(), *resources::gameboard)) continue; /* add attacks with default weapon */ - attack_callable* item = new attack_callable(attacker_location, attack_position, adj[n], -1); + auto item = std::make_shared(attacker_location, attack_position, adj[n], -1); vars.emplace_back(item); } } @@ -297,7 +297,7 @@ variant recall_callable::get_value(const std::string& key) const { if( key == "id") return variant(id_); if( key == "loc") - return variant(new location_callable(loc_)); + return variant(std::make_shared(loc_)); return variant(); } @@ -314,7 +314,7 @@ variant recall_callable::execute_self(variant ctxt) { recall_result->execute(); } else { LOG_AI << "ERROR #" << recall_result->get_status() << " while executing 'recall' formula function\n" << std::endl; - return variant(new safe_call_result(this, recall_result->get_status())); + return variant(std::make_shared(fake_ptr(), recall_result->get_status())); } return variant(recall_result->is_gamestate_changed()); @@ -324,7 +324,7 @@ variant recruit_callable::get_value(const std::string& key) const { if( key == "unit_type") return variant(type_); if( key == "recruit_loc") - return variant(new location_callable(loc_)); + return variant(std::make_shared(loc_)); return variant(); } @@ -343,7 +343,7 @@ variant recruit_callable::execute_self(variant ctxt) { recruit_result->execute(); } else { LOG_AI << "ERROR #" << recruit_result->get_status() << " while executing 'recruit' formula function\n" << std::endl; - return variant(new safe_call_result(this, recruit_result->get_status())); + return variant(std::make_shared(fake_ptr(), recruit_result->get_status())); } //is_gamestate_changed()==true means that the game state was somehow changed by action. @@ -353,7 +353,7 @@ variant recruit_callable::execute_self(variant ctxt) { variant set_unit_var_callable::get_value(const std::string& key) const { if(key == "loc") - return variant(new location_callable(loc_)); + return variant(std::make_shared(loc_)); if(key == "key") return variant(key_); @@ -390,7 +390,7 @@ variant set_unit_var_callable::execute_self(variant ctxt) { } ERR_AI << "ERROR #" << status << " while executing 'set_unit_var' formula function" << std::endl; - return variant(new safe_call_result(this, status)); + return variant(std::make_shared(fake_ptr(), status)); } variant fallback_callable::execute_self(variant) { diff --git a/src/ai/formula/callable_objects.hpp b/src/ai/formula/callable_objects.hpp index dcb13f42ba5de..22f386bb0aa74 100644 --- a/src/ai/formula/callable_objects.hpp +++ b/src/ai/formula/callable_objects.hpp @@ -72,9 +72,9 @@ class move_callable : public action_callable { map_location src_, dst_; variant get_value(const std::string& key) const override { if(key == "src") { - return variant(new location_callable(src_)); + return variant(std::make_shared(src_)); } else if(key == "dst") { - return variant(new location_callable(dst_)); + return variant(std::make_shared(dst_)); } else { return variant(); } @@ -101,9 +101,9 @@ class move_partial_callable : public action_callable { map_location src_, dst_; variant get_value(const std::string& key) const override { if(key == "src") { - return variant(new location_callable(src_)); + return variant(std::make_shared(src_)); } else if(key == "dst") { - return variant(new location_callable(dst_)); + return variant(std::make_shared(dst_)); } else { return variant(); } diff --git a/src/ai/formula/candidates.cpp b/src/ai/formula/candidates.cpp index 8e63403490a0b..a9e6102dc8334 100644 --- a/src/ai/formula/candidates.cpp +++ b/src/ai/formula/candidates.cpp @@ -77,7 +77,7 @@ candidate_action_with_filters::candidate_action_with_filters( variant candidate_action_with_filters::do_filtering(ai::formula_ai* ai, variant& input, const_formula_ptr formula) { - map_formula_callable callable(static_cast(ai)); + map_formula_callable callable(ai->fake_ptr()); callable.add("input", input); return formula::evaluate(formula, callable); @@ -102,7 +102,7 @@ void move_candidate_action::evaluate(ai::formula_ai* ai, unit_map& units) for(unit_map::unit_iterator i = units.begin() ; i != units.end() ; ++i) { if (i->side() == ai->get_side() && i->movement_left() > 0) { - unit_vector.emplace_back(new unit_callable(*i)); + unit_vector.emplace_back(std::make_shared(*i)); } } @@ -122,7 +122,7 @@ void move_candidate_action::evaluate(ai::formula_ai* ai, unit_map& units) for(variant_iterator i = filtered_units.begin() ; i != filtered_units.end() ; ++i) { - map_formula_callable callable(static_cast(ai)); + map_formula_callable callable(ai->fake_ptr()); callable.add("me", *i); int res = execute_formula(eval_, callable, ai); @@ -161,12 +161,12 @@ void attack_candidate_action::evaluate(ai::formula_ai* ai, unit_map& units) if (i->side() == ai->get_side()) { if (i->attacks_left()) { - my_res.emplace_back(new unit_callable(*i)); + my_res.emplace_back(std::make_shared(*i)); } } else { if (ai->current_team().is_enemy(i->side()) && !i->incapacitated() && !i->invisible(i->get_location(), *resources::gameboard)) { - enemy_res.emplace_back(new unit_callable(*i)); + enemy_res.emplace_back(std::make_shared(*i)); } } } @@ -199,33 +199,35 @@ void attack_candidate_action::evaluate(ai::formula_ai* ai, unit_map& units) return; } - std::vector< const unit_callable* > my_units_flt; - std::vector< const unit_callable* > enemy_units_flt; + std::vector my_units_flt; + std::vector enemy_units_flt; for(variant_iterator i = filtered_my_units.begin() ; i != filtered_my_units.end() ; ++i) { - const unit_callable* u_callable = (*i).try_convert(); - if(u_callable == nullptr) { + auto u_callable = (*i).try_convert(); + if(!u_callable) { ERR_AI << "ERROR in "<< get_name() << "Candidate Action: Filter formula returned table that does not contain units" << std::endl; return; } - my_units_flt.push_back(u_callable); + my_units_flt.emplace_back(u_callable); } for(variant_iterator i = filtered_enemy_units.begin() ; i != filtered_enemy_units.end() ; ++i) { - const unit_callable* u_callable = (*i).try_convert(); - if(u_callable == nullptr) { + auto u_callable = (*i).try_convert(); + if(!u_callable) { ERR_AI << "ERROR in "<< get_name() << "Candidate Action: Filter formula returned table that does not contain units" << std::endl; return; } - enemy_units_flt.push_back(u_callable); + enemy_units_flt.emplace_back(u_callable); } for( size_t my_unit = 0 ; my_unit < my_units_flt.size() ; ++my_unit){ - const unit_callable* my_unit_callalbe = my_units_flt[my_unit]; + auto my_unit_callable = my_units_flt[my_unit].convert_to(); + auto enemy_unit_callable = my_units_flt[my_unit].convert_to(); for( size_t enemy_unit = 0 ; enemy_unit < enemy_units_flt.size() ; ++enemy_unit){ - if( ai->can_reach_unit( my_unit_callalbe->get_location(), enemy_units_flt[enemy_unit]->get_location() )) { + auto enemy_unit_callable = enemy_units_flt[enemy_unit].convert_to(); + if(ai->can_reach_unit(my_unit_callable->get_location(), enemy_unit_callable->get_location())) { - map_formula_callable callable(static_cast(ai)); + map_formula_callable callable(ai->fake_ptr()); callable.add("me", filtered_my_units[my_unit]); callable.add("target", filtered_enemy_units[enemy_unit]); diff --git a/src/ai/formula/function_table.cpp b/src/ai/formula/function_table.cpp index 471359ddb81c4..17f86de5a7c74 100644 --- a/src/ai/formula/function_table.cpp +++ b/src/ai/formula/function_table.cpp @@ -55,7 +55,7 @@ namespace { class unit_adapter { public: unit_adapter(const variant& arg) : unit_type_(), unit_() { - const unit_callable* unit = arg.try_convert(); + auto unit = arg.try_convert(); if (unit) { unit_ = &unit->get_unit(); @@ -361,9 +361,9 @@ class calculate_map_ownership_function : public function_expression { if( valid ) { if( enemy_border ) - res.insert( std::pair(variant(new location_callable(map_location(x, y))), variant(scores[0][i] + 10000) )); + res.emplace(variant(std::make_shared(map_location(x, y))), variant(scores[0][i] + 10000)); else - res.insert( std::pair(variant(new location_callable(map_location(x, y))), variant(scores[0][i] ) )); + res.emplace(variant(std::make_shared(map_location(x, y))), variant(scores[0][i])); } } } @@ -400,7 +400,7 @@ class nearest_loc_function : public function_expression { } if( best_i != -1) - return variant(new location_callable(items[best_i].convert_to()->loc())); + return variant(std::make_shared(items[best_i].convert_to()->loc())); else return variant(); } @@ -423,7 +423,7 @@ class adjacent_locs_function : public function_expression { std::vector v; for(int n = 0; n != 6; ++n) { if (resources::gameboard->map().on_board(adj[n]) ) - v.emplace_back(new location_callable(adj[n])); + v.emplace_back(std::make_shared(adj[n])); } return variant(v); @@ -448,7 +448,7 @@ class locations_in_radius_function : public function_expression { return variant(); if(!range) - return variant(new location_callable(loc)); + return variant(std::make_shared(loc)); std::vector res; @@ -456,11 +456,11 @@ class locations_in_radius_function : public function_expression { std::vector v; v.reserve(res.size()+1); - v.emplace_back(new location_callable(loc)); + v.emplace_back(std::make_shared(loc)); for(size_t n = 0; n != res.size(); ++n) { if (resources::gameboard->map().on_board(res[n]) ) - v.emplace_back(new location_callable(res[n])); + v.emplace_back(std::make_shared(res[n])); } return variant(v); @@ -548,7 +548,7 @@ class castle_locs_function : public function_expression { std::vector res; for (const map_location& ml : visited_locs) { - res.push_back( variant(new location_callable( ml ) ) ); + res.push_back( variant(std::make_shared( ml ) ) ); } return variant(res); @@ -577,9 +577,9 @@ class timeofday_modifier_function : public function_expression { return variant(); } - const unit_callable* u_call = u.try_convert(); + auto u_call = u.try_convert(); - if (u_call == nullptr) { + if(!u_call) { return variant(); } @@ -625,7 +625,7 @@ class nearest_keep_function : public function_expression { } if( best_i != -1) - return variant(new location_callable(ai_.get_keeps_cache()[best_i].convert_to()->loc())); + return variant(std::make_shared(ai_.get_keeps_cache()[best_i].convert_to()->loc())); else return variant(); } @@ -653,7 +653,7 @@ class suitable_keep_function : public function_expression { return variant(); } const pathfind::paths unit_paths(*u, false, true, ai_.current_team()); - return variant(new location_callable(ai_.suitable_keep(loc,unit_paths))); + return variant(std::make_shared(ai_.suitable_keep(loc,unit_paths))); } formula_ai& ai_; @@ -683,7 +683,7 @@ class find_shroud_function : public function_expression { for(int i = 0; i < w; ++i) for(int j = 0; j < h; ++j) { if(ai_.current_team().shrouded(map_location(i,j))) - vars.emplace_back(new location_callable(map_location(i, j))); + vars.emplace_back(std::make_shared(map_location(i, j))); } return variant(vars); @@ -714,7 +714,7 @@ class close_enemies_function : public function_expression { while (un != end) { if (distance_between(loc, un->get_location()) <= range) { if (un->side() != ai_.get_side()) {//fixme: ignores allied units - vars.emplace_back(new unit_callable(*un)); + vars.emplace_back(std::make_shared(*un)); } } ++un; @@ -780,7 +780,7 @@ class calculate_outcome_function : public function_expression { status.emplace_back("Stoned"); if (bc.get_defender_stats().plagues && hitLeft[0].as_int() == 0) status.emplace_back("Zombiefied"); - vars.emplace_back(new outcome_callable(hitLeft, prob, status)); + vars.emplace_back(std::make_shared(hitLeft, prob, status)); hitLeft.clear(); prob.clear(); status.clear(); @@ -803,7 +803,7 @@ class calculate_outcome_function : public function_expression { status.emplace_back("Stoned"); if (bc.get_attacker_stats().plagues && hitLeft[0].as_int() == 0) status.emplace_back("Zombiefied"); - vars.emplace_back(new outcome_callable(hitLeft, prob, status)); + vars.emplace_back(std::make_shared(hitLeft, prob, status)); return variant(vars); } }; @@ -819,7 +819,7 @@ class outcomes_function : public function_expression { private: variant execute(const formula_callable& variables, formula_debugger *fdb) const { variant attack = args()[0]->evaluate(variables,add_debug_info(fdb,0,"outcomes:attack")); - ai::attack_analysis* analysis = attack.convert_to(); + auto analysis = attack.convert_to(); //unit_map units_with_moves(resources::gameboard->units()); //typedef std::pair mv; //for(const mv &m : analysis->movements) { @@ -830,13 +830,13 @@ class outcomes_function : public function_expression { if(analysis->chance_to_kill > 0.0) { //unit_map units(units_with_moves); //units.erase(analysis->target); - vars.emplace_back(new position_callable(/*&units,*/ static_cast(analysis->chance_to_kill*100))); + vars.emplace_back(std::make_shared(/*&units,*/ static_cast(analysis->chance_to_kill*100))); } if(analysis->chance_to_kill < 1.0) { //unit_map units(units_with_moves); - vars.emplace_back(new position_callable(/*&units,*/ static_cast(100 - analysis->chance_to_kill*100))); + vars.emplace_back(std::make_shared(/*&units,*/ static_cast(100 - analysis->chance_to_kill*100))); } return variant(vars); @@ -872,7 +872,7 @@ class get_unit_type_function : public function_expression { const unit_type *ut = unit_types.find(type); if(ut) { - return variant(new unit_type_callable(*ut)); + return variant(std::make_shared(*ut)); } return variant(); @@ -889,7 +889,7 @@ class rate_action_function : public function_expression { private: variant execute(const formula_callable& variables, formula_debugger *fdb) const { variant act = args()[0]->evaluate(variables,add_debug_info(fdb,0,"rate_action:action")); - ai::attack_analysis* analysis = act.convert_to(); + auto analysis = act.convert_to(); return variant(analysis->rating(ai_.get_aggression(),ai_)*1000,variant::DECIMAL_VARIANT); } @@ -911,7 +911,7 @@ class recall_function : public function_expression { loc = args()[1]->evaluate(variables, add_debug_info(fdb, 1, "recall:location")).convert_to()->loc(); } - return variant(new recall_callable(loc, id)); + return variant(std::make_shared(loc, id)); } }; @@ -929,7 +929,7 @@ class recruit_function : public function_expression { loc = args()[1]->evaluate(variables, add_debug_info(fdb, 1, "recruit:location")).convert_to()->loc(); } - return variant(new recruit_callable(loc, type)); + return variant(std::make_shared(loc, type)); } }; @@ -974,7 +974,7 @@ class shortest_path_function : public function_expression { } for (std::vector::const_iterator loc_iter = route.steps.begin() + 1 ; loc_iter !=route.steps.end(); ++loc_iter) { - locations.push_back( variant( new location_callable(*loc_iter) )); + locations.push_back( variant(std::make_shared(*loc_iter) )); } return variant(locations); @@ -1027,7 +1027,7 @@ class simplest_path_function : public function_expression { for (std::vector::const_iterator loc_iter = route.steps.begin() + 1 ; loc_iter !=route.steps.end(); ++loc_iter) { if (unit_it->movement_cost((resources::gameboard->map())[*loc_iter]) < movetype::UNREACHABLE ) - locations.push_back( variant( new location_callable(*loc_iter) )); + locations.push_back( variant(std::make_shared(*loc_iter) )); else break; } @@ -1095,7 +1095,7 @@ class next_hop_function : public function_expression { if (loc==map_location::null_location()) { return variant(); } - return variant(new location_callable(loc)); + return variant(std::make_shared(loc)); } const formula_ai& ai_; @@ -1113,7 +1113,7 @@ class move_function : public function_expression { const map_location src = args()[0]->evaluate(variables, add_debug_info(fdb, 0, "move:src")).convert_to()->loc(); const map_location dst = args()[1]->evaluate(variables, add_debug_info(fdb, 1, "move:dst")).convert_to()->loc(); LOG_AI << "move(): " << src << ", " << dst << ")\n"; - return variant(new move_callable(src, dst)); + return variant(std::make_shared(src, dst)); } }; @@ -1128,7 +1128,7 @@ class move_partial_function : public function_expression { const map_location src = args()[0]->evaluate(variables, add_debug_info(fdb, 0, "move_partial:src")).convert_to()->loc(); const map_location dst = args()[1]->evaluate(variables, add_debug_info(fdb, 1, "move_partial:dst")).convert_to()->loc(); LOG_AI << "move_partial(): " << src << ", " << dst << ")\n"; - return variant(new move_partial_callable(src, dst)); + return variant(std::make_shared(src, dst)); } }; @@ -1140,7 +1140,7 @@ class set_unit_var_function : public function_expression { {} private: variant execute(const formula_callable& variables, formula_debugger *fdb) const { - return variant(new set_unit_var_callable(args()[0]->evaluate(variables,add_debug_info(fdb,0,"set_unit_var:key")).as_string(), args()[1]->evaluate(variables,add_debug_info(fdb,1,"set_unit_var:value")), args()[2]->evaluate(variables,add_debug_info(fdb,2,"set_unit_var:unit_location")).convert_to()->loc())); + return variant(std::make_shared(args()[0]->evaluate(variables,add_debug_info(fdb,0,"set_unit_var:key")).as_string(), args()[1]->evaluate(variables,add_debug_info(fdb,1,"set_unit_var:value")), args()[2]->evaluate(variables,add_debug_info(fdb,2,"set_unit_var:unit_location")).convert_to()->loc())); } }; @@ -1155,7 +1155,7 @@ class fallback_function : public function_expression { // The parameter is not used, but is accepted for legacy compatibility if(args().size() == 1 && args()[0]->evaluate(variables).as_string() != "human") return variant(); - return variant(new fallback_callable); + return variant(std::make_shared()); } }; @@ -1175,7 +1175,7 @@ class attack_function : public function_expression { ERR_AI << "AI ERROR: Formula produced illegal attack: " << move_from << " -> " << src << " -> " << dst << std::endl; return variant(); } - return variant(new attack_callable(move_from, src, dst, weapon)); + return variant(std::make_shared(move_from, src, dst, weapon)); } }; @@ -1284,10 +1284,10 @@ class unit_at_function : public function_expression { if (loc_var.is_null()) { return variant(); } - const location_callable* loc = loc_var.convert_to(); + auto loc = loc_var.convert_to(); const unit_map::const_iterator i = resources::gameboard->units().find(loc->loc()); if(i != resources::gameboard->units().end()) { - return variant(new unit_callable(*i)); + return variant(std::make_shared(*i)); } else { return variant(); } @@ -1314,7 +1314,7 @@ class unit_moves_function : public function_expression { std::pair range = srcdst.equal_range(loc); for(Itor i = range.first; i != range.second; ++i) { - vars.emplace_back(new location_callable(i->second)); + vars.emplace_back(std::make_shared(i->second)); } return variant(vars); @@ -1339,7 +1339,7 @@ class units_can_reach_function : public function_expression { while(range.first != range.second) { unit_map::const_iterator un = resources::gameboard->units().find(range.first->second); assert(un != resources::gameboard->units().end()); - vars.emplace_back(new unit_callable(*un)); + vars.emplace_back(std::make_shared(*un)); ++range.first; } @@ -1361,8 +1361,8 @@ class defense_on_function : public function_expression { return variant(); } - const unit_callable* u_call = u.try_convert(); - const unit_type_callable* u_type = u.try_convert(); + auto u_call = u.try_convert(); + auto u_type = u.try_convert(); const map_location& loc = loc_var.convert_to()->loc(); if (u_call) @@ -1411,8 +1411,8 @@ class chance_to_hit_function : public function_expression { return variant(); } - const unit_callable* u_call = u.try_convert(); - const unit_type_callable* u_type = u.try_convert(); + auto u_call = u.try_convert(); + auto u_type = u.try_convert(); const map_location& loc = loc_var.convert_to()->loc(); if (u_call) @@ -1455,8 +1455,8 @@ class movement_cost_function : public function_expression { return variant(); } //we can pass to this function either unit_callable or unit_type callable - const unit_callable* u_call = u.try_convert(); - const unit_type_callable* u_type = u.try_convert(); + auto u_call = u.try_convert(); + auto u_type = u.try_convert(); const map_location& loc = loc_var.convert_to()->loc(); if (u_call) diff --git a/src/ai/formula/stage_side_formulas.cpp b/src/ai/formula/stage_side_formulas.cpp index 8f6aad5d7580f..5617d1d22a3bf 100644 --- a/src/ai/formula/stage_side_formulas.cpp +++ b/src/ai/formula/stage_side_formulas.cpp @@ -45,7 +45,7 @@ stage_side_formulas::~stage_side_formulas() bool stage_side_formulas::do_play_stage() { - wfl::map_formula_callable callable(&fai_); + wfl::map_formula_callable callable(fai_.fake_ptr()); try { if (move_formula_) { while( !fai_.make_action(move_formula_,callable).is_empty() ) { } diff --git a/src/ai/formula/stage_unit_formulas.cpp b/src/ai/formula/stage_unit_formulas.cpp index 2f6eedfe95c54..a58e48127edd4 100644 --- a/src/ai/formula/stage_unit_formulas.cpp +++ b/src/ai/formula/stage_unit_formulas.cpp @@ -66,8 +66,8 @@ bool stage_unit_formulas::do_play_stage() try { wfl::const_formula_ptr priority_formula(fai_.create_optional_formula(i->formula_manager().get_priority_formula())); if (priority_formula) { - wfl::map_formula_callable callable(&fai_); - callable.add("me", wfl::variant(new wfl::unit_callable(*i))); + wfl::map_formula_callable callable(fai_.fake_ptr()); + callable.add("me", wfl::variant(std::make_shared(*i))); priority = (wfl::formula::evaluate(priority_formula, callable)).as_int(); } else { WRN_AI << "priority formula skipped, maybe it's empty or incorrect"<< std::endl; @@ -99,8 +99,8 @@ bool stage_unit_formulas::do_play_stage() try { wfl::const_formula_ptr formula(fai_.create_optional_formula(i->formula_manager().get_formula())); if (formula) { - wfl::map_formula_callable callable(&fai_); - callable.add("me", wfl::variant(new wfl::unit_callable(*i))); + wfl::map_formula_callable callable(fai_.fake_ptr()); + callable.add("me", wfl::variant(std::make_shared(*i))); fai_.make_action(formula, callable); } else { WRN_AI << "unit formula skipped, maybe it's empty or incorrect" << std::endl; @@ -121,8 +121,8 @@ bool stage_unit_formulas::do_play_stage() try { wfl::const_formula_ptr loop_formula(fai_.create_optional_formula(i->formula_manager().get_loop_formula())); if (loop_formula) { - wfl::map_formula_callable callable(&fai_); - callable.add("me", wfl::variant(new wfl::unit_callable(*i))); + wfl::map_formula_callable callable(fai_.fake_ptr()); + callable.add("me", wfl::variant(std::make_shared(*i))); while ( !fai_.make_action(loop_formula, callable).is_empty() && i.valid() ) { } diff --git a/src/formula/callable.hpp b/src/formula/callable.hpp index 8522db9a15842..49388266fd4e9 100644 --- a/src/formula/callable.hpp +++ b/src/formula/callable.hpp @@ -15,6 +15,7 @@ #ifndef FORMULA_CALLABLE_HPP_INCLUDED #define FORMULA_CALLABLE_HPP_INCLUDED +#include "formula/callable_fwd.hpp" #include "formula/variant.hpp" #include @@ -30,12 +31,26 @@ class formula_callable public: explicit formula_callable(bool has_self = true) : type_(FORMULA_C), has_self_(has_self) {} - virtual ~formula_callable() {} + virtual ~formula_callable() { + for(auto& d : dtor_notify) { + if(d) { + d->notify_dead(); + } + } + } + + formula_callable_ptr fake_ptr() { + return formula_callable_ptr(this, [](const formula_callable*){}); + } + + const_formula_callable_ptr fake_ptr() const { + return const_formula_callable_ptr(this, [](const formula_callable*){}); + } variant query_value(const std::string& key) const { if(has_self_ && key == "self") { - return variant(this); + return variant(fake_ptr()); } return get_value(key); } @@ -54,14 +69,14 @@ class formula_callable virtual void get_inputs(formula_input_vector& /*inputs*/) const {} - bool equals(const formula_callable* other) const + bool equals(const formula_callable& other) const { - return do_compare(other) == 0; + return do_compare(&other) == 0; } - bool less(const formula_callable* other) const + bool less(const formula_callable& other) const { - return do_compare(other) < 0; + return do_compare(&other) < 0; } bool has_key(const std::string& key) const @@ -76,6 +91,14 @@ class formula_callable serialize_to_string(str); } + void subscribe_dtor(callable_die_subscriber* d) const { + dtor_notify.insert(d); + } + + void unsubscribe_dtor(callable_die_subscriber* d) const { + dtor_notify.erase(d); + } + protected: template static variant convert_map(const std::map& input_map) @@ -150,6 +173,8 @@ class formula_callable TYPE type_; + mutable std::set dtor_notify; + private: virtual variant get_value(const std::string& key) const = 0; bool has_self_; @@ -219,7 +244,7 @@ class formula_variant_callable_with_backup : public formula_callable class map_formula_callable : public formula_callable { public: - explicit map_formula_callable(const formula_callable* fallback = nullptr) + explicit map_formula_callable(const_formula_callable_ptr fallback = nullptr) : formula_callable(false) , values_() , fallback_(fallback) @@ -231,7 +256,7 @@ class map_formula_callable : public formula_callable return *this; } - void set_fallback(const formula_callable* fallback) + void set_fallback(const_formula_callable_ptr fallback) { fallback_ = fallback; } @@ -275,7 +300,7 @@ class map_formula_callable : public formula_callable } std::map values_; - const formula_callable* fallback_; + const_formula_callable_ptr fallback_; }; using map_formula_callable_ptr = std::shared_ptr; diff --git a/src/formula/callable_fwd.hpp b/src/formula/callable_fwd.hpp index 5cccb705c4cf0..aa3a6e3e00c28 100644 --- a/src/formula/callable_fwd.hpp +++ b/src/formula/callable_fwd.hpp @@ -17,12 +17,17 @@ #include #include +#include namespace wfl { class formula_callable; class formula_debugger; +struct callable_die_subscriber { + virtual void notify_dead() {} +}; + enum FORMULA_ACCESS_TYPE { FORMULA_READ_ONLY, FORMULA_WRITE_ONLY, FORMULA_READ_WRITE }; struct formula_input { @@ -36,7 +41,8 @@ struct formula_input { using formula_input_vector = std::vector; using formula_callable_ptr = std::shared_ptr; using const_formula_callable_ptr = std::shared_ptr; -using formula_seen_stack = std::vector; +using formula_seen_stack = std::vector; + } #endif diff --git a/src/formula/callable_objects.cpp b/src/formula/callable_objects.cpp index 8502f2e086155..6b9e07eb1ecc0 100644 --- a/src/formula/callable_objects.cpp +++ b/src/formula/callable_objects.cpp @@ -169,7 +169,7 @@ variant unit_callable::get_value(const std::string& key) const return variant(); } - return variant(new location_callable(loc_)); + return variant(std::make_shared(loc_)); } else if(key == "id") { return variant(u_.id()); } else if(key == "type") { @@ -185,7 +185,7 @@ variant unit_callable::get_value(const std::string& key) const } else if(key == "attacks") { std::vector res; for(const attack_type& att : u_.attacks()) { - res.emplace_back(new attack_type_callable(att)); + res.emplace_back(std::make_shared(att)); } return variant(res); @@ -249,12 +249,12 @@ variant unit_callable::get_value(const std::string& key) const return variant(map_location::write_direction(u_.facing())); } else if(key == "vars") { if(u_.formula_manager().formula_vars()) { - return variant(u_.formula_manager().formula_vars().get()); + return variant(u_.formula_manager().formula_vars()); } return variant(); } else if(key == "wml_vars") { - return variant(new config_callable(u_.variables())); + return variant(std::make_shared(u_.variables())); } else if(key == "n" || key == "s" || key == "ne" || key == "se" || key == "nw" || key == "sw" || key == "lawful" || key == "neutral" || key == "chaotic" || key == "liminal" || key == "male" || key == "female") @@ -340,7 +340,7 @@ variant unit_type_callable::get_value(const std::string& key) const } else if(key == "attacks") { std::vector res; for(const attack_type& att : u_.attacks()) { - res.emplace_back(new attack_type_callable(att)); + res.emplace_back(std::make_shared(att)); } return variant(res); @@ -419,15 +419,15 @@ variant config_callable::get_value(const std::string& key) const } else if(cfg_.has_child(key)) { std::vector result; for(const auto& child : cfg_.child_range(key)) { - result.emplace_back(new config_callable(child)); + result.emplace_back(std::make_shared(child)); } return variant(result); } else if(key == "__all_children") { std::vector result; for(const auto& child : cfg_.all_children_range()) { - const variant cfg_child(new config_callable(child.cfg)); - const variant kv(new key_value_pair(variant(child.key), cfg_child)); + const variant cfg_child(std::make_shared(child.cfg)); + const variant kv(std::make_shared(variant(child.key), cfg_child)); result.push_back(kv); } @@ -435,7 +435,7 @@ variant config_callable::get_value(const std::string& key) const } else if(key == "__children") { std::map > build; for(const auto& child : cfg_.all_children_range()) { - const variant cfg_child(new config_callable(child.cfg)); + const variant cfg_child(std::make_shared(child.cfg)); build[child.key].push_back(cfg_child); } @@ -491,7 +491,7 @@ variant terrain_callable::get_value(const std::string& key) const } else if(key == "y") { return variant(loc_.wml_y()); } else if(key == "loc") { - return variant(new location_callable(loc_)); + return variant(std::make_shared(loc_)); } else if(key == "id") { return variant(std::string(t_.id())); } else if(key == "name") { @@ -563,7 +563,7 @@ variant gamemap_callable::get_value(const std::string& key) const for(int i = 0; i < w; i++) { for(int j = 0; j < h; j++) { const map_location loc(i, j); - vars.emplace_back(new terrain_callable(gamemap_.get_terrain_info(loc), loc)); + vars.emplace_back(std::make_shared(gamemap_.get_terrain_info(loc), loc)); } } @@ -667,7 +667,7 @@ variant team_callable::get_value(const std::string& key) const return variant(result); } else if(key == "wml_vars") { - return variant(new config_callable(team_.variables())); + return variant(std::make_shared(team_.variables())); } return variant(); @@ -693,7 +693,7 @@ void set_var_callable::get_inputs(formula_input_vector& inputs) const variant set_var_callable::execute_self(variant ctxt) { //if(infinite_loop_guardian_.set_var_check()) { - if(formula_callable* obj = ctxt.try_convert()) { + if(auto obj = ctxt.try_convert()) { LOG_SF << "Setting variable: " << key_ << " -> " << value_.to_debug_string() << "\n"; obj->mutate_value(key_, value_); return variant(true); @@ -702,7 +702,7 @@ variant set_var_callable::execute_self(variant ctxt) //too many calls in a row - possible infinite loop ERR_SF << "ERROR #" << 5001 << " while executing 'set_var' formula function" << std::endl; - return variant(new safe_call_result(this, 5001)); + return variant(std::make_shared(fake_ptr(), 5001)); } variant safe_call_callable::get_value(const std::string& key) const @@ -725,7 +725,7 @@ void safe_call_callable::get_inputs(formula_input_vector& inputs) const variant safe_call_callable::execute_self(variant ctxt) { variant res; - if(action_callable* action = main_.try_convert()) { + if(auto action = main_.try_convert()) { res = action->execute_self(ctxt); } @@ -752,13 +752,13 @@ variant safe_call_result::get_value(const std::string& key) const if(key == "status") { return variant(status_); } else if(key == "object") { - if(failed_callable_ != nullptr) { + if(failed_callable_) { return variant(failed_callable_); } return variant(); } else if(key == "current_loc" && current_unit_location_ != map_location()) { - return variant(new location_callable(current_unit_location_)); + return variant(std::make_shared(current_unit_location_)); } return variant(); diff --git a/src/formula/callable_objects.hpp b/src/formula/callable_objects.hpp index 7bb2dfcc58a5d..77df52b59193e 100644 --- a/src/formula/callable_objects.hpp +++ b/src/formula/callable_objects.hpp @@ -224,14 +224,14 @@ class safe_call_callable : public action_callable class safe_call_result : public formula_callable { public: - safe_call_result(const formula_callable* callable, int status, const map_location& loc = map_location()) + safe_call_result(const_formula_callable_ptr callable, int status, const map_location& loc = map_location()) : failed_callable_(callable) , current_unit_location_(loc) , status_(status) {} private: - const formula_callable* failed_callable_; + const_formula_callable_ptr failed_callable_; const map_location current_unit_location_; const int status_; diff --git a/src/formula/function.cpp b/src/formula/function.cpp index 58643a0d7c5eb..3e0b366eb51fe 100644 --- a/src/formula/function.cpp +++ b/src/formula/function.cpp @@ -114,7 +114,7 @@ class dir_function : public function_expression { private: variant execute(const formula_callable& variables, formula_debugger *fdb) const { variant var = args()[0]->evaluate(variables, fdb); - const formula_callable* callable = var.as_callable(); + auto callable = var.as_callable(); formula_input_vector inputs = callable->inputs(); std::vector res; for(size_t i=0; i()) + if(auto kv = (*it).try_convert()) tmp[kv->query_value("key")] = kv->query_value("value"); else { std::map::iterator map_it = tmp.find( *it ); @@ -1427,7 +1427,7 @@ class loc_function : public function_expression { {} private: variant execute(const formula_callable& variables, formula_debugger *fdb) const { - return variant(new location_callable(map_location( + return variant(std::make_shared(map_location( args()[0]->evaluate(variables,add_debug_info(fdb,0,"loc:x")).as_int(), args()[1]->evaluate(variables,add_debug_info(fdb,1,"loc:y")).as_int(), wml_loc()))); } @@ -1440,7 +1440,7 @@ class pair_function : public function_expression { {} private: variant execute(const formula_callable& variables, formula_debugger *fdb) const { - return variant(new key_value_pair( + return variant(std::make_shared( args()[0]->evaluate(variables,add_debug_info(fdb,0,"pair:key")), args()[1]->evaluate(variables,add_debug_info(fdb,1,"pair_value")) )); @@ -1487,7 +1487,7 @@ class safe_call_function : public function_expression { const variant main = args()[0]->evaluate(variables, fdb); const expression_ptr backup_formula = args()[1]; - return variant(new safe_call_callable(main, backup_formula)); + return variant(std::make_shared(main, backup_formula)); } }; @@ -1497,7 +1497,7 @@ class set_var_function : public function_expression { : function_expression("set_var", args, 2, 2) {} private: variant execute(const formula_callable& variables, formula_debugger *fdb) const { - return variant(new set_var_callable(args()[0]->evaluate(variables, add_debug_info(fdb, 0, "set_var:key")).as_string(), args()[1]->evaluate(variables, add_debug_info(fdb, 1, "set_var:value")))); + return variant(std::make_shared(args()[0]->evaluate(variables, add_debug_info(fdb, 0, "set_var:key")).as_string(), args()[1]->evaluate(variables, add_debug_info(fdb, 1, "set_var:value")))); } }; diff --git a/src/formula/variant.cpp b/src/formula/variant.cpp index d340b994ea5d1..a6a5211052f2b 100644 --- a/src/formula/variant.cpp +++ b/src/formula/variant.cpp @@ -162,7 +162,7 @@ variant::variant(double n, variant::DECIMAL_VARIANT_TYPE) assert(value_.get()); } -variant::variant(const formula_callable* callable) +variant::variant(const_formula_callable_ptr callable) : value_(std::make_shared(callable)) { assert(value_.get()); @@ -682,7 +682,7 @@ variant variant::execute_variant(const variant& var) continue; } - if(action_callable* action = vars.top().try_convert()) { + if(auto action = vars.top().try_convert()) { variant res = action->execute_self(*this); if(res.is_int() && res.as_bool()) { made_moves.push_back(vars.top()); diff --git a/src/formula/variant.hpp b/src/formula/variant.hpp index 52418e0c2f905..a4297e411c244 100644 --- a/src/formula/variant.hpp +++ b/src/formula/variant.hpp @@ -34,7 +34,7 @@ class variant explicit variant(int n); variant(int n, DECIMAL_VARIANT_TYPE /*type*/); variant(double n, DECIMAL_VARIANT_TYPE /*type*/); - explicit variant(const formula_callable* callable); + variant(const_formula_callable_ptr callable); explicit variant(const std::vector& array); explicit variant(const std::string& str); explicit variant(const std::map& map); @@ -71,26 +71,26 @@ class variant const std::string& as_string() const; - const formula_callable* as_callable() const + const_formula_callable_ptr as_callable() const { must_be(VARIANT_TYPE::TYPE_CALLABLE); return value_cast()->get_callable(); } template - T* try_convert() const + std::shared_ptr try_convert() const { if(!is_callable()) { return nullptr; } - return dynamic_cast(const_cast(as_callable())); + return std::dynamic_pointer_cast(std::const_pointer_cast(as_callable())); } template - T* convert_to() const + std::shared_ptr convert_to() const { - T* res = dynamic_cast(const_cast(as_callable())); + std::shared_ptr res = std::dynamic_pointer_cast(std::const_pointer_cast(as_callable())); if(!res) { throw type_error("could not convert type"); } diff --git a/src/formula/variant_value.cpp b/src/formula/variant_value.cpp index 62ac6e35f4a71..f052df585d1ae 100644 --- a/src/formula/variant_value.cpp +++ b/src/formula/variant_value.cpp @@ -75,9 +75,19 @@ std::string variant_decimal::to_string_impl(const bool sign_value) const return ss.str(); } -variant_callable::variant_callable(const formula_callable* callable) +variant_callable::variant_callable(const_formula_callable_ptr callable) : callable_(callable) -{} +{ + if(callable_) { + callable_->subscribe_dtor(this); + } +} + +variant_callable::~variant_callable() { + if(callable_) { + callable_->unsubscribe_dtor(this); + } +} std::string variant_callable::get_serialized_string() const { @@ -133,13 +143,13 @@ std::string variant_callable::get_debug_string(formula_seen_stack& seen, bool ve bool variant_callable::equals(variant_value_base& other) const { variant_callable& other_ref = value_ref_cast(other); - return callable_ ? callable_->equals(other_ref.callable_) : callable_ == other_ref.callable_; + return callable_ ? callable_->equals(*other_ref.callable_) : callable_ == other_ref.callable_; } bool variant_callable::less_than(variant_value_base& other) const { variant_callable& other_ref = value_ref_cast(other); - return callable_ ? callable_->less(other_ref.callable_) : other_ref.callable_ != nullptr; + return callable_ ? callable_->less(*other_ref.callable_) : other_ref.callable_ != nullptr; } boost::iterator_range variant_callable::make_iterator() const @@ -359,7 +369,7 @@ bool variant_map::less_than(variant_value_base& other) const variant variant_map::deref_iterator(const boost::any& iter) const { const variant_map_raw::value_type& p = *boost::any_cast(iter); - key_value_pair* the_pair = new key_value_pair(p.first, p.second); + auto the_pair = std::make_shared(p.first, p.second); return variant(the_pair); } diff --git a/src/formula/variant_value.hpp b/src/formula/variant_value.hpp index 26e8a0ed4e1c6..78b546ea35121 100644 --- a/src/formula/variant_value.hpp +++ b/src/formula/variant_value.hpp @@ -309,10 +309,11 @@ class variant_decimal : public variant_numeric }; -class variant_callable : public variant_value_base +class variant_callable : public variant_value_base, private callable_die_subscriber { public: - explicit variant_callable(const formula_callable* callable); + explicit variant_callable(const_formula_callable_ptr callable); + ~variant_callable(); virtual bool as_bool() const override { @@ -324,7 +325,7 @@ class variant_callable : public variant_value_base return 1; } - const formula_callable* get_callable() const + const_formula_callable_ptr get_callable() const { return callable_; } @@ -358,9 +359,10 @@ class variant_callable : public variant_value_base } private: - const formula_callable* callable_; + void notify_dead() override {callable_.reset();} mutable formula_input_vector inputs; // for iteration + const_formula_callable_ptr callable_; }; diff --git a/src/scripting/lua_formula_bridge.cpp b/src/scripting/lua_formula_bridge.cpp index 60ee62d76d608..8607d3b98ac3e 100644 --- a/src/scripting/lua_formula_bridge.cpp +++ b/src/scripting/lua_formula_bridge.cpp @@ -140,7 +140,7 @@ void luaW_pushfaivariant(lua_State* L, variant val) { } } else if(val.is_callable()) { // First try a few special cases - if(unit_callable* u_ref = val.try_convert()) { + if(auto u_ref = val.try_convert()) { const unit& u = u_ref->get_unit(); unit_map::iterator un_it = resources::gameboard->units().find(u.get_location()); if(&*un_it == &u) { @@ -148,11 +148,11 @@ void luaW_pushfaivariant(lua_State* L, variant val) { } else { luaW_pushunit(L, u.side(), u.underlying_id()); } - } else if(location_callable* loc_ref = val.try_convert()) { + } else if(auto loc_ref = val.try_convert()) { luaW_pushlocation(L, loc_ref->loc()); } else { // If those fail, convert generically to a map - const formula_callable* obj = val.as_callable(); + auto obj = val.as_callable(); formula_input_vector inputs; obj->get_inputs(inputs); lua_newtable(L); @@ -179,7 +179,7 @@ variant luaW_tofaivariant(lua_State* L, int i) { case LUA_TSTRING: return variant(lua_tostring(L, i)); case LUA_TTABLE: - return variant(new lua_callable(L, i)); + return variant(std::make_shared(L, i)); case LUA_TUSERDATA: static t_string tstr; static vconfig vcfg = vconfig::unconstructed_vconfig(); @@ -187,11 +187,11 @@ variant luaW_tofaivariant(lua_State* L, int i) { if(luaW_totstring(L, i, tstr)) { return variant(tstr.str()); } else if(luaW_tovconfig(L, i, vcfg)) { - return variant(new config_callable(vcfg.get_parsed_config())); + return variant(std::make_shared(vcfg.get_parsed_config())); } else if(unit* u = luaW_tounit(L, i)) { - return variant(new unit_callable(*u)); + return variant(std::make_shared(*u)); } else if(luaW_tolocation(L, i, loc)) { - return variant(new location_callable(loc)); + return variant(std::make_shared(loc)); } break; } diff --git a/src/tests/test_formula_core.cpp b/src/tests/test_formula_core.cpp index 39657a7996538..a038f70291ef5 100644 --- a/src/tests/test_formula_core.cpp +++ b/src/tests/test_formula_core.cpp @@ -44,12 +44,12 @@ class mock_party : public formula_callable { i_[2].add("strength",variant(14)); std::vector members; for(int n = 0; n != 3; ++n) { - members.emplace_back(&i_[n]); + members.emplace_back(i_[n].fake_ptr()); } return variant(members); } else if(key == "char") { - return variant(&c_); + return variant(c_.fake_ptr()); } else { return variant(0); } diff --git a/src/units/filter.cpp b/src/units/filter.cpp index ad6e7841d90e8..6da50513cc281 100644 --- a/src/units/filter.cpp +++ b/src/units/filter.cpp @@ -591,10 +591,10 @@ bool basic_unit_filter_impl::internal_matches_filter(const unit & u, const map_l if (!vcfg["formula"].blank()) { try { const wfl::unit_callable main(loc,u); - wfl::map_formula_callable callable(&main); + wfl::map_formula_callable callable(main.fake_ptr()); if (u2) { std::shared_ptr secondary(new wfl::unit_callable(*u2)); - callable.add("other", wfl::variant(secondary.get())); + callable.add("other", wfl::variant(secondary)); // It's not destroyed upon scope exit because the variant holds a reference } const wfl::formula form(vcfg["formula"]);