Merge branch 'wfl_memleak_fix'

This commit is contained in:
Celtic Minstrel 2017-04-08 20:22:00 -04:00
commit 795592fe12
23 changed files with 237 additions and 190 deletions

View file

@ -342,7 +342,7 @@ public:
{
std::vector<wfl::variant> 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<attack_analysis>(*i));
}
var = wfl::variant(vars);
}

View file

@ -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<location_callable>(target));
} else if(key == "movements") {
std::vector<variant> 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<map_formula_callable>(nullptr);
item->add("src", variant(std::make_shared<location_callable>(movements[n].first)));
item->add("dst", variant(std::make_shared<location_callable>(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<variant> 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<location_callable>(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<wfl::safe_call_result>(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<wfl::safe_call_result>(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<wfl::safe_call_result>(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<wfl::safe_call_result>(fake_ptr(), result->get_status()));
}
}
return wfl::variant(true);

View file

@ -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<location_callable>(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<team_callable>(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<variant> vars;
for(std::vector<team>::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<team_callable>(*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<unit_type_callable>(*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<unit_type_callable>(*ut));
}
}
}
@ -454,7 +455,7 @@ variant formula_ai::get_value(const std::string& key) const
{
std::vector<variant> 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<unit_callable>(*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<unit_callable>(u));
}
for( size_t i = 0; i<tmp.size(); ++i)
vars.emplace_back(tmp[i]);
@ -479,7 +480,7 @@ variant formula_ai::get_value(const std::string& key) const
std::vector<variant> 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<unit_callable>(*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<unit_callable>(*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<move_map_callable>(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<move_map_callable>(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<unit_callable>(*i));
} else if(key == "recall_list")
{
std::vector<variant> tmp;
for(std::vector<unit_ptr >::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<unit_callable>(**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<gamemap_callable>(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<location_callable>(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();

View file

@ -166,13 +166,14 @@ private:
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

View file

@ -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<const formula_ai*>(for_fai);
assert(fai != nullptr); // Why not just use dynamic_cast<formula_ai&> instead then?
return *const_cast<formula_ai*>(fai)->ai_ptr_;
ai_context& get_ai_context(wfl::const_formula_callable_ptr for_fai) {
auto fai = std::dynamic_pointer_cast<const formula_ai>(for_fai);
assert(fai != nullptr);
return *std::const_pointer_cast<formula_ai>(fai)->ai_ptr_;
}
}
@ -50,7 +50,7 @@ variant move_map_callable::get_value(const std::string& key) const
std::vector<variant> 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<move_callable>(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<safe_call_result>(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<safe_call_result>(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<location_callable>(src_));
} else if(key == "defender") {
return variant(new location_callable(dst_));
return variant(std::make_shared<location_callable>(dst_));
} else if(key == "move_from") {
return variant(new location_callable(move_from_));
return variant(std::make_shared<location_callable>(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<safe_call_result>(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<safe_call_result>(fake_ptr(), attack_result->get_status()));
}
}
@ -287,7 +287,7 @@ void attack_map_callable::collect_possible_attacks(std::vector<variant>& 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<attack_callable>(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<location_callable>(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<safe_call_result>(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<location_callable>(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<safe_call_result>(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<location_callable>(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<safe_call_result>(fake_ptr(), status));
}
variant fallback_callable::execute_self(variant) {

View file

@ -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<location_callable>(src_));
} else if(key == "dst") {
return variant(new location_callable(dst_));
return variant(std::make_shared<location_callable>(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<location_callable>(src_));
} else if(key == "dst") {
return variant(new location_callable(dst_));
return variant(std::make_shared<location_callable>(dst_));
} else {
return variant();
}

View file

@ -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<const formula_callable*>(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<unit_callable>(*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<const formula_callable*>(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<unit_callable>(*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<unit_callable>(*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<variant> my_units_flt;
std::vector<variant> 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<const unit_callable>();
if(u_callable == nullptr) {
auto u_callable = (*i).try_convert<const unit_callable>();
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<const unit_callable>();
if(u_callable == nullptr) {
auto u_callable = (*i).try_convert<const unit_callable>();
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<unit_callable>();
auto enemy_unit_callable = my_units_flt[my_unit].convert_to<unit_callable>();
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<unit_callable>();
if(ai->can_reach_unit(my_unit_callable->get_location(), enemy_unit_callable->get_location())) {
map_formula_callable callable(static_cast<const formula_callable*>(ai));
map_formula_callable callable(ai->fake_ptr());
callable.add("me", filtered_my_units[my_unit]);
callable.add("target", filtered_enemy_units[enemy_unit]);

View file

@ -55,7 +55,7 @@ namespace {
class unit_adapter {
public:
unit_adapter(const variant& arg) : unit_type_(), unit_() {
const unit_callable* unit = arg.try_convert<unit_callable>();
auto unit = arg.try_convert<unit_callable>();
if (unit) {
unit_ = &unit->get_unit();
@ -361,9 +361,9 @@ private:
if( valid ) {
if( enemy_border )
res.insert( std::pair<variant, variant>(variant(new location_callable(map_location(x, y))), variant(scores[0][i] + 10000) ));
res.emplace(variant(std::make_shared<location_callable>(map_location(x, y))), variant(scores[0][i] + 10000));
else
res.insert( std::pair<variant, variant>(variant(new location_callable(map_location(x, y))), variant(scores[0][i] ) ));
res.emplace(variant(std::make_shared<location_callable>(map_location(x, y))), variant(scores[0][i]));
}
}
}
@ -400,7 +400,7 @@ private:
}
if( best_i != -1)
return variant(new location_callable(items[best_i].convert_to<location_callable>()->loc()));
return variant(std::make_shared<location_callable>(items[best_i].convert_to<location_callable>()->loc()));
else
return variant();
}
@ -423,7 +423,7 @@ private:
std::vector<variant> 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<location_callable>(adj[n]));
}
return variant(v);
@ -448,7 +448,7 @@ private:
return variant();
if(!range)
return variant(new location_callable(loc));
return variant(std::make_shared<location_callable>(loc));
std::vector<map_location> res;
@ -456,11 +456,11 @@ private:
std::vector<variant> v;
v.reserve(res.size()+1);
v.emplace_back(new location_callable(loc));
v.emplace_back(std::make_shared<location_callable>(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<location_callable>(res[n]));
}
return variant(v);
@ -548,7 +548,7 @@ private:
std::vector<variant> res;
for (const map_location& ml : visited_locs) {
res.push_back( variant(new location_callable( ml ) ) );
res.push_back( variant(std::make_shared<location_callable>( ml ) ) );
}
return variant(res);
@ -577,9 +577,9 @@ private:
return variant();
}
const unit_callable* u_call = u.try_convert<unit_callable>();
auto u_call = u.try_convert<unit_callable>();
if (u_call == nullptr) {
if(!u_call) {
return variant();
}
@ -625,7 +625,7 @@ private:
}
if( best_i != -1)
return variant(new location_callable(ai_.get_keeps_cache()[best_i].convert_to<location_callable>()->loc()));
return variant(std::make_shared<location_callable>(ai_.get_keeps_cache()[best_i].convert_to<location_callable>()->loc()));
else
return variant();
}
@ -653,7 +653,7 @@ private:
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<location_callable>(ai_.suitable_keep(loc,unit_paths)));
}
formula_ai& ai_;
@ -683,7 +683,7 @@ private:
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<location_callable>(map_location(i, j)));
}
return variant(vars);
@ -714,7 +714,7 @@ private:
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<unit_callable>(*un));
}
}
++un;
@ -780,7 +780,7 @@ private:
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<outcome_callable>(hitLeft, prob, status));
hitLeft.clear();
prob.clear();
status.clear();
@ -803,7 +803,7 @@ private:
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<outcome_callable>(hitLeft, prob, status));
return variant(vars);
}
};
@ -819,7 +819,7 @@ public:
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<ai::attack_analysis>();
auto analysis = attack.convert_to<ai::attack_analysis>();
//unit_map units_with_moves(resources::gameboard->units());
//typedef std::pair<map_location, map_location> mv;
//for(const mv &m : analysis->movements) {
@ -830,13 +830,13 @@ private:
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<int>(analysis->chance_to_kill*100)));
vars.emplace_back(std::make_shared<position_callable>(/*&units,*/ static_cast<int>(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<int>(100 - analysis->chance_to_kill*100)));
vars.emplace_back(std::make_shared<position_callable>(/*&units,*/ static_cast<int>(100 - analysis->chance_to_kill*100)));
}
return variant(vars);
@ -872,7 +872,7 @@ private:
const unit_type *ut = unit_types.find(type);
if(ut) {
return variant(new unit_type_callable(*ut));
return variant(std::make_shared<unit_type_callable>(*ut));
}
return variant();
@ -889,7 +889,7 @@ public:
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<ai::attack_analysis>();
auto analysis = act.convert_to<ai::attack_analysis>();
return variant(analysis->rating(ai_.get_aggression(),ai_)*1000,variant::DECIMAL_VARIANT);
}
@ -911,7 +911,7 @@ private:
loc = args()[1]->evaluate(variables, add_debug_info(fdb, 1, "recall:location")).convert_to<location_callable>()->loc();
}
return variant(new recall_callable(loc, id));
return variant(std::make_shared<recall_callable>(loc, id));
}
};
@ -929,7 +929,7 @@ private:
loc = args()[1]->evaluate(variables, add_debug_info(fdb, 1, "recruit:location")).convert_to<location_callable>()->loc();
}
return variant(new recruit_callable(loc, type));
return variant(std::make_shared<recruit_callable>(loc, type));
}
};
@ -974,7 +974,7 @@ private:
}
for (std::vector<map_location>::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<location_callable>(*loc_iter) ));
}
return variant(locations);
@ -1027,7 +1027,7 @@ private:
for (std::vector<map_location>::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<location_callable>(*loc_iter) ));
else
break;
}
@ -1095,7 +1095,7 @@ private:
if (loc==map_location::null_location()) {
return variant();
}
return variant(new location_callable(loc));
return variant(std::make_shared<location_callable>(loc));
}
const formula_ai& ai_;
@ -1113,7 +1113,7 @@ private:
const map_location src = args()[0]->evaluate(variables, add_debug_info(fdb, 0, "move:src")).convert_to<location_callable>()->loc();
const map_location dst = args()[1]->evaluate(variables, add_debug_info(fdb, 1, "move:dst")).convert_to<location_callable>()->loc();
LOG_AI << "move(): " << src << ", " << dst << ")\n";
return variant(new move_callable(src, dst));
return variant(std::make_shared<move_callable>(src, dst));
}
};
@ -1128,7 +1128,7 @@ private:
const map_location src = args()[0]->evaluate(variables, add_debug_info(fdb, 0, "move_partial:src")).convert_to<location_callable>()->loc();
const map_location dst = args()[1]->evaluate(variables, add_debug_info(fdb, 1, "move_partial:dst")).convert_to<location_callable>()->loc();
LOG_AI << "move_partial(): " << src << ", " << dst << ")\n";
return variant(new move_partial_callable(src, dst));
return variant(std::make_shared<move_partial_callable>(src, dst));
}
};
@ -1140,7 +1140,7 @@ public:
{}
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<location_callable>()->loc()));
return variant(std::make_shared<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<location_callable>()->loc()));
}
};
@ -1155,7 +1155,7 @@ private:
// 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<fallback_callable>());
}
};
@ -1175,7 +1175,7 @@ private:
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<attack_callable>(move_from, src, dst, weapon));
}
};
@ -1284,10 +1284,10 @@ private:
if (loc_var.is_null()) {
return variant();
}
const location_callable* loc = loc_var.convert_to<location_callable>();
auto loc = loc_var.convert_to<location_callable>();
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<unit_callable>(*i));
} else {
return variant();
}
@ -1314,7 +1314,7 @@ private:
std::pair<Itor,Itor> 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<location_callable>(i->second));
}
return variant(vars);
@ -1339,7 +1339,7 @@ private:
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<unit_callable>(*un));
++range.first;
}
@ -1361,8 +1361,8 @@ private:
return variant();
}
const unit_callable* u_call = u.try_convert<unit_callable>();
const unit_type_callable* u_type = u.try_convert<unit_type_callable>();
auto u_call = u.try_convert<unit_callable>();
auto u_type = u.try_convert<unit_type_callable>();
const map_location& loc = loc_var.convert_to<location_callable>()->loc();
if (u_call)
@ -1411,8 +1411,8 @@ private:
return variant();
}
const unit_callable* u_call = u.try_convert<unit_callable>();
const unit_type_callable* u_type = u.try_convert<unit_type_callable>();
auto u_call = u.try_convert<unit_callable>();
auto u_type = u.try_convert<unit_type_callable>();
const map_location& loc = loc_var.convert_to<location_callable>()->loc();
if (u_call)
@ -1455,8 +1455,8 @@ private:
return variant();
}
//we can pass to this function either unit_callable or unit_type callable
const unit_callable* u_call = u.try_convert<unit_callable>();
const unit_type_callable* u_type = u.try_convert<unit_type_callable>();
auto u_call = u.try_convert<unit_callable>();
auto u_type = u.try_convert<unit_type_callable>();
const map_location& loc = loc_var.convert_to<location_callable>()->loc();
if (u_call)

View file

@ -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() ) { }

View file

@ -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<wfl::unit_callable>(*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<wfl::unit_callable>(*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<wfl::unit_callable>(*i)));
while ( !fai_.make_action(loop_formula, callable).is_empty() && i.valid() )
{
}

View file

@ -15,6 +15,7 @@
#ifndef FORMULA_CALLABLE_HPP_INCLUDED
#define FORMULA_CALLABLE_HPP_INCLUDED
#include "formula/callable_fwd.hpp"
#include "formula/variant.hpp"
#include <iostream>
@ -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 @@ public:
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 @@ public:
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<typename T, typename K>
static variant convert_map(const std::map<T, K>& input_map)
@ -150,6 +173,8 @@ protected:
TYPE type_;
mutable std::set<callable_die_subscriber*> dtor_notify;
private:
virtual variant get_value(const std::string& key) const = 0;
bool has_self_;
@ -219,7 +244,7 @@ private:
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 @@ public:
return *this;
}
void set_fallback(const formula_callable* fallback)
void set_fallback(const_formula_callable_ptr fallback)
{
fallback_ = fallback;
}
@ -275,7 +300,7 @@ private:
}
std::map<std::string, variant> values_;
const formula_callable* fallback_;
const_formula_callable_ptr fallback_;
};
using map_formula_callable_ptr = std::shared_ptr<map_formula_callable>;

View file

@ -17,12 +17,17 @@
#include <memory>
#include <vector>
#include <string>
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<formula_input>;
using formula_callable_ptr = std::shared_ptr<formula_callable>;
using const_formula_callable_ptr = std::shared_ptr<const formula_callable>;
using formula_seen_stack = std::vector<const formula_callable*>;
using formula_seen_stack = std::vector<const_formula_callable_ptr>;
}
#endif

View file

@ -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<location_callable>(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<variant> res;
for(const attack_type& att : u_.attacks()) {
res.emplace_back(new attack_type_callable(att));
res.emplace_back(std::make_shared<attack_type_callable>(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<config_callable>(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<variant> res;
for(const attack_type& att : u_.attacks()) {
res.emplace_back(new attack_type_callable(att));
res.emplace_back(std::make_shared<attack_type_callable>(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<variant> result;
for(const auto& child : cfg_.child_range(key)) {
result.emplace_back(new config_callable(child));
result.emplace_back(std::make_shared<config_callable>(child));
}
return variant(result);
} else if(key == "__all_children") {
std::vector<variant> 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<config_callable>(child.cfg));
const variant kv(std::make_shared<key_value_pair>(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<std::string, std::vector<variant> > 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<config_callable>(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<location_callable>(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<terrain_callable>(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<config_callable>(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<formula_callable>()) {
if(auto obj = ctxt.try_convert<formula_callable>()) {
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<safe_call_result>(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<action_callable>()) {
if(auto action = main_.try_convert<action_callable>()) {
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<location_callable>(current_unit_location_));
}
return variant();

View file

@ -224,14 +224,14 @@ private:
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_;

View file

@ -114,7 +114,7 @@ public:
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<variant> res;
for(size_t i=0; i<inputs.size(); ++i) {
@ -422,7 +422,7 @@ private:
} else
{
for(variant_iterator it = var_1.begin(); it != var_1.end(); ++it) {
if (key_value_pair* kv = (*it).try_convert<key_value_pair>())
if(auto kv = (*it).try_convert<key_value_pair>())
tmp[kv->query_value("key")] = kv->query_value("value");
else {
std::map<variant, variant>::iterator map_it = tmp.find( *it );
@ -1427,7 +1427,7 @@ public:
{}
private:
variant execute(const formula_callable& variables, formula_debugger *fdb) const {
return variant(new location_callable(map_location(
return variant(std::make_shared<location_callable>(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 @@ public:
{}
private:
variant execute(const formula_callable& variables, formula_debugger *fdb) const {
return variant(new key_value_pair(
return variant(std::make_shared<key_value_pair>(
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 @@ private:
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<safe_call_callable>(main, backup_formula));
}
};
@ -1497,7 +1497,7 @@ public:
: 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<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"))));
}
};

View file

@ -162,12 +162,6 @@ variant::variant(double n, variant::DECIMAL_VARIANT_TYPE)
assert(value_.get());
}
variant::variant(const formula_callable* callable)
: value_(std::make_shared<variant_callable>(callable))
{
assert(value_.get());
}
variant::variant(const std::vector<variant>& vec)
: value_((std::make_shared<variant_list>(vec)))
{
@ -682,7 +676,7 @@ variant variant::execute_variant(const variant& var)
continue;
}
if(action_callable* action = vars.top().try_convert<action_callable>()) {
if(auto action = vars.top().try_convert<action_callable>()) {
variant res = action->execute_self(*this);
if(res.is_int() && res.as_bool()) {
made_moves.push_back(vars.top());

View file

@ -34,11 +34,17 @@ public:
explicit variant(int n);
variant(int n, DECIMAL_VARIANT_TYPE /*type*/);
variant(double n, DECIMAL_VARIANT_TYPE /*type*/);
explicit variant(const formula_callable* callable);
explicit variant(const std::vector<variant>& array);
explicit variant(const std::string& str);
explicit variant(const std::map<variant, variant>& map);
template<typename T>
variant(std::shared_ptr<T> callable)
: value_(std::make_shared<variant_callable>(callable))
{
assert(value_.get());
}
variant& operator=(const variant& v);
variant operator[](size_t n) const;
@ -71,26 +77,26 @@ public:
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<variant_callable>()->get_callable();
}
template<typename T>
T* try_convert() const
std::shared_ptr<T> try_convert() const
{
if(!is_callable()) {
return nullptr;
}
return dynamic_cast<T*>(const_cast<formula_callable*>(as_callable()));
return std::dynamic_pointer_cast<T>(std::const_pointer_cast<formula_callable>(as_callable()));
}
template<typename T>
T* convert_to() const
std::shared_ptr<T> convert_to() const
{
T* res = dynamic_cast<T*>(const_cast<formula_callable*>(as_callable()));
std::shared_ptr<T> res = std::dynamic_pointer_cast<T>(std::const_pointer_cast<formula_callable>(as_callable()));
if(!res) {
throw type_error("could not convert type");
}

View file

@ -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<variant_callable>(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<variant_callable>(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_iterator> 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<const variant_map_raw::const_iterator&>(iter);
key_value_pair* the_pair = new key_value_pair(p.first, p.second);
auto the_pair = std::make_shared<key_value_pair>(p.first, p.second);
return variant(the_pair);
}

View file

@ -311,10 +311,11 @@ private:
};
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
{
@ -326,7 +327,7 @@ public:
return 1;
}
const formula_callable* get_callable() const
const_formula_callable_ptr get_callable() const
{
return callable_;
}
@ -360,9 +361,10 @@ public:
}
private:
const formula_callable* callable_;
void notify_dead() override {callable_.reset();}
mutable formula_input_vector inputs; // for iteration
const_formula_callable_ptr callable_;
};

View file

@ -1320,7 +1320,7 @@ void image_shape::draw(surface& canvas,
local_variables.add("clip_y", wfl::variant(clip_y));
// Execute the provided actions for this context.
wfl::variant(&variables).execute_variant(actions_formula_.evaluate(local_variables));
wfl::variant(variables.fake_ptr()).execute_variant(actions_formula_.evaluate(local_variables));
// Copy the data to local variables to avoid overwriting the originals.
SDL_Rect src_clip = src_clip_;

View file

@ -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<unit_callable>()) {
if(auto u_ref = val.try_convert<unit_callable>()) {
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<location_callable>()) {
} else if(auto loc_ref = val.try_convert<location_callable>()) {
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<lua_callable>(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<config_callable>(vcfg.get_parsed_config()));
} else if(unit* u = luaW_tounit(L, i)) {
return variant(new unit_callable(*u));
return variant(std::make_shared<unit_callable>(*u));
} else if(luaW_tolocation(L, i, loc)) {
return variant(new location_callable(loc));
return variant(std::make_shared<location_callable>(loc));
}
break;
}

View file

@ -44,12 +44,12 @@ class mock_party : public formula_callable {
i_[2].add("strength",variant(14));
std::vector<variant> 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);
}

View file

@ -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<wfl::unit_callable> 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"]);