whiteboard/visitor.hpp

Go to the documentation of this file.
00001 /* $Id: visitor.hpp 53969 2012-04-22 23:01:46Z gabba $ */
00002 /*
00003  Copyright (C) 2010 - 2012 by Gabriel Morin <gabrielmorin (at) gmail (dot) com>
00004  Part of the Battle for Wesnoth Project http://www.wesnoth.org
00005 
00006  This program is free software; you can redistribute it and/or modify
00007  it under the terms of the GNU General Public License as published by
00008  the Free Software Foundation; either version 2 of the License, or
00009    (at your option) any later version.
00010  This program is distributed in the hope that it will be useful,
00011  but WITHOUT ANY WARRANTY.
00012 
00013  See the COPYING file for more details.
00014  */
00015 
00016 /**
00017  * @file
00018  * Two classes are presented in this file: enable_visit_all and visitor.
00019  * enable_visit_all is a class template that provides the all-too-common iteration
00020  *   code that iterates over every planned action from every team, starting with the
00021  *   current-turn team. Using "static polymorphism," derived classes can customize
00022  *   the iteration by overriding some functions.
00023  * visitor is an abstract interface that simply provides derived classes with the
00024  *   mechanism for the double dispatch used in the Visitor Pattern:
00025  *       action.accept(visitor)   calls    visitor.visit_***(action)
00026  * Derived classes will usually derive from both of these.
00027  * Example usage is seen is highlight_visitor and mapbuilder.
00028  */
00029 
00030 #ifndef WB_VISITOR_HPP_
00031 #define WB_VISITOR_HPP_
00032 
00033 #include "action.hpp"
00034 #include "side_actions.hpp"
00035 
00036 #include "foreach.hpp"
00037 #include "play_controller.hpp"
00038 #include "resources.hpp"
00039 
00040 #include <boost/noncopyable.hpp>
00041 
00042 namespace wb
00043 {
00044 
00045 /**
00046  * enable_visit_all: A base class template, using the so-called CRTP. This is the
00047  *   "static polymorphism" part.
00048  * If you want visit_all() and reverse_visit_all() in your class,
00049  *   you should derive from this class template.
00050  * Derived classes can "override" the following:
00051  *   visit (required), pre_visit_team, post_visit_team
00052  * Derived classes should declare enable_visit_all<Derived> as a friend, or
00053  *   else make the overridden functions public.
00054  */
00055 template<typename Derived>
00056 class enable_visit_all
00057 {
00058 public:
00059     void visit_all() { visit_all_helper(false); }
00060     void reverse_visit_all() { visit_all_helper(true); }
00061 
00062 protected:
00063     /**
00064      * visit():
00065      *   @return Whether or not to continue any visitation after this action.
00066      * The fcn is commented out because derived classes are required to implement it.
00067      */
00068     //bool visit(size_t team_index, team&, side_actions&, side_actions::iterator);
00069 
00070     ///@return Whether or not to visit any of the contents of sa.
00071     bool pre_visit_team(size_t /*turn*/, size_t /*team_index*/, team&, side_actions& sa) { return !sa.hidden(); }
00072     ///@return Whether or not to visit any more teams after this one.
00073     bool post_visit_team(size_t /*turn*/, size_t /*team_index*/, team&, side_actions&) { return true; }
00074 
00075 private:
00076     void visit_all_helper( const bool reverse)
00077     {
00078         assert(resources::teams != NULL);
00079 
00080         Derived* const new_this = static_cast<Derived*>(this);
00081 
00082         //Determine how many turns' worth of plans there are
00083         size_t max_turns = 0;
00084         foreach(team& t, *resources::teams)
00085             max_turns = std::max(max_turns,t.get_side_actions()->num_turns());
00086 
00087         size_t const current_team = resources::controller->current_side() - 1;
00088         size_t const num_teams = resources::teams->size();
00089         //for each turn with any planned actions
00090         for(size_t turn_iter=0; turn_iter<max_turns; ++turn_iter)
00091         {
00092             size_t const turn = (reverse? max_turns-1-turn_iter: turn_iter);
00093 
00094             //for each team
00095             for(size_t team_iter = 0; team_iter < num_teams; ++team_iter)
00096             {
00097                 size_t const team_index
00098                         = (current_team+num_teams+(reverse? -1-team_iter: team_iter)) % num_teams;
00099                 team& t = resources::teams->at(team_index);
00100                 side_actions& sa = *t.get_side_actions();
00101                 if(!new_this->pre_visit_team(turn_iter, team_index, t, sa))
00102                     continue; //< Skip this team's actions
00103 
00104                 if(reverse)
00105                 {
00106                     side_actions::rrange_t acts = sa.riter_turn(turn);
00107                     side_actions::reverse_iterator itor = acts.first;
00108                     side_actions::reverse_iterator end  = acts.second;
00109                     while(itor!=end) {
00110                         ++itor;
00111                         if(!new_this->process(team_index,t,sa,itor.base()))
00112                             return; //< Early abort
00113                     }
00114                 }
00115                 else //forward
00116                 {
00117                     side_actions::range_t  acts = sa.iter_turn(turn);
00118                     side_actions::iterator itor = acts.first;
00119                     side_actions::iterator end  = acts.second;
00120                     for(; itor!=end; ++itor)
00121                         if(!new_this->process(team_index,t,sa,itor))
00122                             return; //< Early abort
00123                 }
00124                 if(!new_this->post_visit_team(turn_iter, team_index, t, sa))
00125                     break; //< Early abort
00126             }
00127         }
00128     }
00129 };
00130 
00131 /**
00132  * visitor: This is the "dynamic polymorphism" part.
00133  * Abstract base class for all the visitors (cf GoF Visitor Design Pattern)
00134  *   the whiteboard uses.
00135  * visitor does not inherit from enable_visit_all because it tends to make it more
00136  *   "difficult" for derived classes to inherit from both visitor and enable_visit_all.
00137  */
00138 class visitor
00139     : private boost::noncopyable
00140 {
00141 
00142 public:
00143 
00144     virtual void visit(move_ptr move) = 0;
00145     virtual void visit(attack_ptr attack) = 0;
00146     virtual void visit(recruit_ptr recruit) = 0;
00147     virtual void visit(recall_ptr recall) = 0;
00148     virtual void visit(suppose_dead_ptr sup_d) = 0;
00149 
00150 protected:
00151     visitor() {}
00152     virtual ~visitor() {} //Not intended for polymorphic deletion
00153 
00154     /**
00155      * This function is available for derived classes so they can inherit from enable_visit_all
00156      * without having to override visit(); i.e., the below implementation can be used as a
00157      * default.
00158      */
00159     bool process(size_t /*team_index*/, team&, side_actions&, side_actions::iterator itor)
00160         { (*itor)->accept(*this);   return true; }
00161 
00162     //Utility fcn for derived classes that don't need to customize the iteration.
00163     void visit_all_actions() {visitor_helper::visit_all_actions_helper(this);}
00164 
00165 private:
00166     struct visitor_helper
00167         : enable_visit_all<visitor_helper>
00168     {
00169         bool process(size_t /*team_index*/, team&, side_actions&, side_actions::iterator itor)
00170             { (*itor)->accept(*v_);   return true; }
00171 
00172         static void visit_all_actions_helper(visitor* v)
00173         {
00174             static visitor_helper vh;
00175             vh.v_ = v;
00176             vh.visit_all();
00177         }
00178 
00179         visitor* v_;
00180     };
00181 };
00182 
00183 }
00184 
00185 #endif /* WB_VISITOR_HPP_ */
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines

Generated by doxygen 1.7.1 on Fri May 25 2012 01:03:15 for The Battle for Wesnoth
Gna! | Forum | Wiki | CIA | devdocs