- Use a NotifyLock instead of (History|Simulation)::set_notify_enabled() method, which is more elegant and also exception-safe

- Delete set_notify_enabled() method from ConcreteHistory; it was both wrong and useless, and caused impredictable behaviour!
- Don't make some methods of History and Simulation virtual if we don't want the user to override them
- Loading from file and jumping to an instant of the simulation should be much quickier now

git-svn-id: svn://svn.gna.org/svn/sgpemv2/trunk@1170 3ecf2c5c-341e-0410-92b4-d18e462d057c
This commit is contained in:
tchernobog 2006-09-15 09:34:12 +00:00
parent 737324f250
commit 83b655496f
11 changed files with 94 additions and 73 deletions

View File

@ -70,7 +70,7 @@ void XMLSerializer::restore_snapshot(const Glib::ustring& filename, History& his
// DEBUG - remove me when finished // DEBUG - remove me when finished
// disable notifications over history until the end of this method // disable notifications over history until the end of this method
bool was_enabled = hist.set_notify_enabled(false); History::LockNotify h_lock(hist);
#ifdef LIBXML_SAX1_ENABLED #ifdef LIBXML_SAX1_ENABLED
xmlDocPtr doc; xmlDocPtr doc;
@ -107,8 +107,6 @@ void XMLSerializer::restore_snapshot(const Glib::ustring& filename, History& his
#error Compilation of LIBXML with SAX1 support must be enabled #error Compilation of LIBXML with SAX1 support must be enabled
#endif /* LIBXML_SAX1_ENABLED */ #endif /* LIBXML_SAX1_ENABLED */
// Re-enable notifications over history observers
hist.set_notify_enabled(was_enabled);
} }

View File

@ -166,7 +166,7 @@ AddRequestDialog::run_edit(Request& request)
{ {
assert(_list_model->children()); assert(_list_model->children());
bool was_enabled = history.set_notify_enabled(false); History::LockNotify h_lock(history);
// I know it's a bit hack-ish, but do you know an elegant alternative way? // I know it's a bit hack-ish, but do you know an elegant alternative way?
for(Iseq<vector<SubRequest*>::iterator> it = iseq(subrequests); it; ++it) for(Iseq<vector<SubRequest*>::iterator> it = iseq(subrequests); it; ++it)
@ -178,8 +178,6 @@ AddRequestDialog::run_edit(Request& request)
for(Iseq<TreeIter> it = iseq(sreq_container); it; ++it) for(Iseq<TreeIter> it = iseq(sreq_container); it; ++it)
history.add_subrequest(request, (*it)[_list_key_column], (*it)[_list_duration_column]); history.add_subrequest(request, (*it)[_list_key_column], (*it)[_list_duration_column]);
history.set_notify_enabled(was_enabled);
} }
hide(); hide();

View File

@ -523,14 +523,6 @@ ConcreteHistory::reset(bool notify)
notify_change(); notify_change();
} }
void
ConcreteHistory::notify_change()
{
History::RegisteredObservers::iterator it;
for (it = _observers.begin(); it != _observers.end(); it++)
(*it)->update(*this);
}
bool bool
ConcreteHistory::is_sealed() const ConcreteHistory::is_sealed() const

View File

@ -124,8 +124,6 @@ namespace sgpem
typedef std::vector<ConcreteEnvironment*> Snapshots; typedef std::vector<ConcreteEnvironment*> Snapshots;
Snapshots _snapshots; Snapshots _snapshots;
virtual void notify_change();
private: private:
// Disable assignment, implement it only if needed // Disable assignment, implement it only if needed
ConcreteHistory& operator=(const ConcreteHistory& op2); ConcreteHistory& operator=(const ConcreteHistory& op2);

View File

@ -73,8 +73,8 @@ ConcreteSimulation::jump_to(History::position p) throw(UserInterruptException, N
// Disable momentarily updates for registered observers on // Disable momentarily updates for registered observers on
// sgpem::Simulation and sgpem::History. // sgpem::Simulation and sgpem::History.
bool his_enabled = _history.set_notify_enabled(false); History::LockNotify h_lock(_history);
bool sim_enabled = set_notify_enabled(false); Simulation::LockNotify s_lock(*this);
pause(); pause();
@ -82,30 +82,12 @@ ConcreteSimulation::jump_to(History::position p) throw(UserInterruptException, N
History::position increment = 0; History::position increment = 0;
while (yet_to_finish && p > _history.get_front() + increment) while (yet_to_finish && p > _history.get_front() + increment)
{ {
try yet_to_finish = step();
{ increment++;
yet_to_finish = step();
increment++;
}
catch(const CPUPolicyException&)
{
// Lookout that notifications have to be re-enabled.
_history.set_notify_enabled(his_enabled);
set_notify_enabled(sim_enabled);
throw;
}
} }
get_history().set_front(std::min(p, _history.get_size())); get_history().set_front(std::min(p, _history.get_size()));
if (!yet_to_finish) if (!yet_to_finish)
stop(); stop();
// Reenables updates to registered observers.
// Calls _history.notify_change() on reactivation.
_history.set_notify_enabled(his_enabled);
// Do the same for notifications on the state
// of Simulation
set_notify_enabled(sim_enabled);
} }

View File

@ -81,6 +81,5 @@ namespace sgpem
} }
#endif #endif

View File

@ -83,8 +83,15 @@ History::set_notify_enabled(bool enabled)
return old_value; return old_value;
} }
bool
History::is_notify_enabled() const // --------- History::LockNotify ---------------
History::LockNotify::LockNotify(History& history)
: _h(history), _was_enabled(_h.set_notify_enabled(false))
{ {
return _notify; }
History::LockNotify::~LockNotify()
{
_h.set_notify_enabled(_was_enabled);
} }

View File

@ -56,6 +56,10 @@ namespace sgpem
class SG_DLLEXPORT History class SG_DLLEXPORT History
{ {
public: public:
// Forward declaration
class LockNotify;
friend class History::LockNotify;
typedef unsigned int size_t; typedef unsigned int size_t;
typedef unsigned int time_t; typedef unsigned int time_t;
typedef unsigned int position; typedef unsigned int position;
@ -134,6 +138,14 @@ namespace sgpem
virtual void attach(HistoryObserver& observer); virtual void attach(HistoryObserver& observer);
virtual void detach(const HistoryObserver& observer); virtual void detach(const HistoryObserver& observer);
virtual void reset() = 0;
protected:
typedef std::vector<HistoryObserver*> RegisteredObservers;
RegisteredObservers _observers;
void notify_change();
/** \brief Enable/disable notifications to registered observers /** \brief Enable/disable notifications to registered observers
* *
* This is quite useful to disable momentarily notification while you * This is quite useful to disable momentarily notification while you
@ -142,26 +154,36 @@ namespace sgpem
* *
* \return The old value * \return The old value
*/ */
virtual bool set_notify_enabled(bool enabled = true); bool set_notify_enabled(bool enabled = true);
bool is_notify_enabled() const;
virtual void reset() = 0;
protected:
typedef std::vector<HistoryObserver*> RegisteredObservers;
RegisteredObservers _observers;
virtual void notify_change();
position _front; position _front;
private: private:
bool _notify; bool _notify;
} }; //~ class History
; //~ class History
/** \brief Disables notifications to History during the life of this object
*
* This class is useful if you've to do a lot of sequential operations on
* History that would reset it / notify its observers. For example, when loading
* from a file. In this case, create an object of this type on the stack.
* The destructor will take care of re-enabling notifications.
*/
class SG_DLLEXPORT History::LockNotify
{
public:
LockNotify(History& history);
~LockNotify();
private:
History& _h;
bool _was_enabled;
LockNotify(const LockNotify&);
LockNotify& operator=(const LockNotify&);
}; //~ class History::LockNotify
}//~ namespace sgpem }//~ namespace sgpem

View File

@ -67,6 +67,9 @@ namespace sgpem
class SG_DLLEXPORT Simulation : public Singleton<ConcreteSimulation> class SG_DLLEXPORT Simulation : public Singleton<ConcreteSimulation>
{ {
public: public:
class LockNotify;
friend class Simulation::LockNotify;
enum state enum state
{ {
state_running = 0xdeafd0d0, state_running = 0xdeafd0d0,
@ -170,6 +173,10 @@ namespace sgpem
virtual void attach(SimulationObserver& observer); virtual void attach(SimulationObserver& observer);
virtual void detach(const SimulationObserver& observer); virtual void detach(const SimulationObserver& observer);
protected:
typedef std::vector<SimulationObserver*> RegisteredObservers;
RegisteredObservers _observers;
/** \brief Enable/disable notifications to registered observers /** \brief Enable/disable notifications to registered observers
* *
* This is quite useful to disable momentarily notification while you * This is quite useful to disable momentarily notification while you
@ -178,20 +185,36 @@ namespace sgpem
* *
* \return The old value * \return The old value
*/ */
virtual bool set_notify_enabled(bool enabled = true); bool set_notify_enabled(bool enabled = true);
bool is_notify_enabled() const;
protected:
typedef std::vector<SimulationObserver*> RegisteredObservers;
RegisteredObservers _observers;
Simulation(); // Constructor Simulation(); // Constructor
virtual void notify_change(); void notify_change();
private: private:
bool _notify; bool _notify;
}; }; //~ class Simulation
/** \brief Disables notifications to Simulation during the life of this object
*
* This class is useful if you've to do a lot of sequential operations on
* Simulation that would reset it / notify its observers. For example, when loading
* from a file. In this case, create an object of this type on the stack.
* The destructor will take care of re-enabling notifications.
*/
class SG_DLLEXPORT Simulation::LockNotify
{
public:
LockNotify(Simulation& simulation);
~LockNotify();
private:
Simulation& _s;
bool _was_enabled;
LockNotify(const LockNotify&);
LockNotify& operator=(const LockNotify&);
}; //~ class Simulation::LockNotify
} }

View File

@ -89,8 +89,14 @@ Simulation::set_notify_enabled(bool enabled)
return old_value; return old_value;
} }
bool // --------- Simulation::LockNotify ---------------
Simulation::is_notify_enabled() const
Simulation::LockNotify::LockNotify(Simulation& simulation)
: _s(simulation), _was_enabled(_s.set_notify_enabled(false))
{ {
return _notify; }
Simulation::LockNotify::~LockNotify()
{
_s.set_notify_enabled(_was_enabled);
} }

View File

@ -84,9 +84,6 @@ JumpToDialog::start()
// start listening to simulation updates // start listening to simulation updates
sim.attach(*this); sim.attach(*this);
// remember state of notifications for History
bool reenable = h.is_notify_enabled();
try try
{ {
if(_target_instant < h.get_size() - 1) if(_target_instant < h.get_size() - 1)
@ -94,9 +91,9 @@ JumpToDialog::start()
else else
sim.jump_to(h.get_size() - 1); sim.jump_to(h.get_size() - 1);
// disable notifications since we could call // disable notifications on History since we could call
// run() a lot of times // run() a lot of times
h.set_notify_enabled(false); History::LockNotify h_lock(h);
while(h.get_front() <= _target_instant) while(h.get_front() <= _target_instant)
{ {
sim.run(); sim.run();
@ -149,7 +146,6 @@ JumpToDialog::start()
// Ending successfully: detach me, reenable notifications, // Ending successfully: detach me, reenable notifications,
// and emit response ``okay'' // and emit response ``okay''
sim.detach(*this); sim.detach(*this);
h.set_notify_enabled(reenable);
response(Gtk::RESPONSE_OK); response(Gtk::RESPONSE_OK);
} }