mt4cpp
Command.hpp
Go to the documentation of this file.
1 /**
2  * \file Command.hpp
3  * \brief The command module (Command base class, progress, command description).
4  */
5 
6 
7 #ifndef MT4CPP_COMMAND_HPP
8 #define MT4CPP_COMMAND_HPP
9 
10 #include <boost/smart_ptr.hpp>
11 #include <boost/thread.hpp>
12 
13 #if defined(_MSC_VER) && (_MSC_VER >= 1400)
14 // pass not-fully initialized pointer in Command c-tor (pointer of this) in progress_ member
15 // Command() : counter_(0), haltFlag_(false), progress_(*this)
16 // this warning is useless here
17 #pragma warning(disable:4355)
18 #endif
19 
20 
21 namespace mt4cpp {
22 
23  /** Command unique ID indentifier */
24  typedef long CommandID;
25 
26  /** \brief the descriptor of command */
27  struct CommandDesc {
28 
29  /** \brief available states of Command
30  NONE - command created, but not put in activation queue
31  QUEUED - command is waiting for execusion at the activation queue
32  PENDING - command is being executed now
33  INTERRUPTED - command execution has been interrupted
34  EXCEPTION - during command execution an exception was catched
35  DONE - command code has been done successfully
36  */
37  enum State { NONE, QUEUED, PENDING, INTERRUPTED, EXCEPTION, DONE };
38 
39  CommandID id_; //!< command unique ID
40  State state_; //!< command state
41  double progress_; //!< command progress
42 
43  /** c-tor */
44  CommandDesc() : id_(0), state_(NONE), progress_(0.0) {}
45  };
46 
47  /** forward declaration */
48  class Command;
49 
50  /** abstract class of command observer */
52  public:
53  CommandObserver() { }
54  /** new progress */
55  virtual void notifyProgress(const Command&, double progress) = 0;
56 
57  /** next step */
58  virtual void notifyStep(const Command&) = 0;
59 
60  /** change command state */
61  virtual void notifyState(const Command&, CommandDesc::State state) = 0;
62 
63  virtual ~CommandObserver() { }
64  };
65 
66  /** smart pointer to observer objects */
67  typedef boost::shared_ptr<CommandObserver> PCommandObserver;
68 
69 
70  /*! \brief
71  class to set the progress of given command. Subject in Obverver design pattern.
72  It also check the 'halt-command' flag and if it is set it throws exception UserBreakException.
73  */
74  class Progress {
75  public:
76  //constructor, progress from 0 to 100% for given command
77  Progress( Command& cmd );
78  //copy constructor
79  Progress( const Progress& p ) : command_(p.command_), observers_(p.observers_), start_(p.start_), finish_(p.finish_) {}
80 
81  /** creates sub-progress, the notification of the same observers,
82  but the output progress is recalulated (0% is the 'st', 100% is the 'fi') */
83  Progress( const Progress& parent, double st, double fi) : command_(parent.command_), observers_(parent.observers_) {
84  double wsp = parent.finish_ - parent.start_;
85  start_ = parent.start_ + st * wsp;
86  finish_ = parent.start_ + fi * wsp;
87  }
88 
89  /* \brief change the command progress (stored in Command::CommandDescription)
90  Notify all observers about the progress.
91  The parameter current from 0 to 1 (100%) is recalculated to notify about progress from 'start' to 'finish'.
92  */
93  void setProgress( double current );
94 
95  //! notify all observers, increase the progress
96  void step();
97 
98  /* \brief notify all observers about the new state of command
99  */
100  void changeState( CommandDesc::State state ) {
101  std::for_each( observers_.begin(), observers_.end(),
102  boost::bind(&CommandObserver::notifyState, _1, boost::cref(command_), state ) );
103  }
104 
105  //! add observer
106  void attach(PCommandObserver observer) { observers_.push_back(observer); }
107  private:
108  Progress& operator=(const Progress& prog); //<! assign not allowed
109 
110  Command& command_; //!< command for which the progress is calculated
111 
112  std::vector<PCommandObserver> observers_; //<! observers
113 
114  double start_; //<! starting progress
115  double finish_; //<! finishing progress
116  };
117 
118 
119  /** The basic class of command, which is executed by scheduler. */
120  class Command : boost::noncopyable {
121  public:
122  Command() : counter_(0), haltFlag_(false), progress_(*this) {}
123  /** destructor */
124  virtual ~Command() { }
125 
126  /** the method called by scheduler. It calls the operator() of command. */
127  void execute() {
128  try {
129  setState(CommandDesc::PENDING);
130  operator()(progress_);
131  setState(CommandDesc::DONE);
132  } catch(boost::thread_interrupted&) {
133  setState(CommandDesc::INTERRUPTED);
134  } catch(...) {
135  setState(CommandDesc::EXCEPTION);
136  }
137  }
138 
139  /** returns the command actual state and progress */
141  boost::mutex::scoped_lock lock(m_);
142  return CommandDesc(descriptor_);
143  }
144 
145  /** mutator - change the command progress (called by Progress::setProgress() )*/
146  void setProgress(double new_progress) {
147  boost::mutex::scoped_lock lock(m_);
148  descriptor_.progress_ = new_progress;
149  }
150 
151  /** mutator - change the command state (called by Scheduler ) */
152  void setState(CommandDesc::State new_state) {
153  {
154  boost::mutex::scoped_lock lock(m_);
155  descriptor_.state_ = new_state;
156  }
157  progress_.changeState( new_state );
158 
159  }
160 
161  /** mutator - change the commmand id (called by Scheduler ) */
162  void setId(long new_id) {
163  boost::mutex::scoped_lock lock(m_);
164  descriptor_.id_ = new_id;
165  }
166 
167  /** Suggest the command to break execution (ie sets the flags) */
168  void halt() {
169  haltFlag_ = true;
170  }
171 
172  /** Check the halt flag and throws the exception if set */
173  void checkHaltFlag() const {
174  if(haltFlag_) throw boost::thread_interrupted();
175  }
176 
177  /** the accessor to the counter */
178  int getCounter() const { return counter_; }
179 
180  /** add observer (add observer to command) */
181  void attach(PCommandObserver observer) { progress_.attach(observer); }
182 
183  /** for intrusive_ptr */
184  friend void intrusive_ptr_add_ref(Command* ptr);
185  friend void intrusive_ptr_release(Command* ptr);
186  protected:
187  mutable boost::mutex m_;
188  private:
189  /** the method which implements the specific task of command.
190  The private members can be overlapped */
191  virtual void operator()(Progress& p) = 0;
192 
193  CommandDesc descriptor_; //!< the command state, progress and id
194 
195  int counter_; /** counter for intrusive ptr */
196  volatile bool haltFlag_; //!< flag set if the command should stop its execution
197 
198  Progress progress_; //!< progress for given command
199  };
200 
201  /** read the command state (helper) */
202  inline CommandDesc::State getState(const Command& cmd) {
203  return cmd.getDescriptor().state_;
204  }
205 
206  inline void intrusive_ptr_add_ref(Command* cmd) {
207  boost::mutex::scoped_lock lock(cmd->m_); //critical section
208  ++(cmd->counter_);
209  }
210  inline void intrusive_ptr_release(Command* cmd) {
211  bool del = false;
212  {
213  boost::mutex::scoped_lock lock(cmd->m_); //critical section
214  del = ! --(cmd->counter_);
215  }
216  if(del)
217  delete cmd;
218 
219  }
220 
221  /** the smart pointer to command.
222  intrusive_ptr because of multithread env (mutex blocks the counter )
223  */
224  typedef boost::intrusive_ptr<Command> PCommand;
225 
226 
227  /**
228  \brief holder with the type and pointer to command as well as the base class of command (smart pointer)
229  */
230  template<typename T> class CommandHolder {
231  public:
232  //! the command type
233  typedef T CommandType;
234 
235  CommandHolder(T* cmd) : obsCmd_(cmd), cmd_(cmd) { }
236 
237  T* getObsCmd() { return obsCmd_; }
238  PCommand get() { return cmd_; }
239  private:
240  T* obsCmd_;
241  PCommand cmd_;
242  };
243 
244 } //namespace mt4cpp
245 
246 //-------------------------------------------------------------------------------------------
247 //
248 // implementation
249 //
250 //-------------------------------------------------------------------------------------------
251 
252 namespace mt4cpp {
253 
254  //constructor, progress from 0 to 100% for given command
255  inline Progress::Progress( Command& cmd ) : command_(cmd), start_(0), finish_(1)
256  {
257  }
258 
259  /* \brief change the command progress (stored in Command::CommandDescription)
260  Notify all observers about the progress.
261  The parameter current from 0 to 1 (100%) is recalculated to notify about progress from 'start' to 'finish'.
262  */
263  inline void Progress::setProgress( double current ) {
264  command_.checkHaltFlag();
265  command_.setProgress( start_ + (finish_ - start_)*current );
266  std::for_each( observers_.begin(), observers_.end(),
267  boost::bind(&CommandObserver::notifyProgress, _1, boost::cref(command_), start_ + (finish_ - start_)*current ) );
268  }
269 
270  //! notify all observers, increase the progress
271  inline void Progress::step() {
272  command_.checkHaltFlag();
273  std::for_each( observers_.begin(), observers_.end(),
274  boost::bind(&CommandObserver::notifyStep, _1, boost::cref(command_) ) );
275  }
276 
277 } //namespace mt4cpp
278 
279 #endif //MT4CPP_COMMAND_HPP
void attach(PCommandObserver observer)
add observer
Definition: Command.hpp:106
void setId(long new_id)
Definition: Command.hpp:162
CommandID id_
command unique ID
Definition: Command.hpp:39
void attach(PCommandObserver observer)
Definition: Command.hpp:181
void setState(CommandDesc::State new_state)
Definition: Command.hpp:152
State
available states of Command NONE - command created, but not put in activation queue QUEUED - command ...
Definition: Command.hpp:37
CommandDesc()
Definition: Command.hpp:44
void execute()
Definition: Command.hpp:127
Definition: Command.hpp:21
T CommandType
the command type
Definition: Command.hpp:233
double progress_
command progress
Definition: Command.hpp:41
Definition: Command.hpp:120
holder with the type and pointer to command as well as the base class of command (smart pointer) ...
Definition: Command.hpp:230
friend void intrusive_ptr_add_ref(Command *ptr)
Definition: Command.hpp:206
CommandDesc getDescriptor() const
Definition: Command.hpp:140
void setProgress(double new_progress)
Definition: Command.hpp:146
void halt()
Definition: Command.hpp:168
void step()
notify all observers, increase the progress
Definition: Command.hpp:271
class to set the progress of given command. Subject in Obverver design pattern. It also check the 'ha...
Definition: Command.hpp:74
Definition: Command.hpp:51
State state_
command state
Definition: Command.hpp:40
virtual void notifyProgress(const Command &, double progress)=0
virtual void notifyState(const Command &, CommandDesc::State state)=0
Progress(const Progress &parent, double st, double fi)
Definition: Command.hpp:83
int getCounter() const
Definition: Command.hpp:178
virtual void notifyStep(const Command &)=0
virtual ~Command()
Definition: Command.hpp:124
void checkHaltFlag() const
Definition: Command.hpp:173
the descriptor of command
Definition: Command.hpp:27