- 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

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

View file

@ -124,8 +124,6 @@ namespace sgpem
typedef std::vector<ConcreteEnvironment*> Snapshots;
Snapshots _snapshots;
virtual void notify_change();
private:
// Disable assignment, implement it only if needed
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
// sgpem::Simulation and sgpem::History.
bool his_enabled = _history.set_notify_enabled(false);
bool sim_enabled = set_notify_enabled(false);
History::LockNotify h_lock(_history);
Simulation::LockNotify s_lock(*this);
pause();
@ -82,30 +82,12 @@ ConcreteSimulation::jump_to(History::position p) throw(UserInterruptException, N
History::position increment = 0;
while (yet_to_finish && p > _history.get_front() + increment)
{
try
{
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;
}
yet_to_finish = step();
increment++;
}
get_history().set_front(std::min(p, _history.get_size()));
if (!yet_to_finish)
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

View file

@ -83,8 +83,15 @@ History::set_notify_enabled(bool enabled)
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
{
public:
// Forward declaration
class LockNotify;
friend class History::LockNotify;
typedef unsigned int size_t;
typedef unsigned int time_t;
typedef unsigned int position;
@ -134,6 +138,14 @@ namespace sgpem
virtual void attach(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
*
* This is quite useful to disable momentarily notification while you
@ -142,26 +154,36 @@ namespace sgpem
*
* \return The old value
*/
virtual 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();
bool set_notify_enabled(bool enabled = true);
position _front;
private:
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

View file

@ -67,6 +67,9 @@ namespace sgpem
class SG_DLLEXPORT Simulation : public Singleton<ConcreteSimulation>
{
public:
class LockNotify;
friend class Simulation::LockNotify;
enum state
{
state_running = 0xdeafd0d0,
@ -170,6 +173,10 @@ namespace sgpem
virtual void attach(SimulationObserver& observer);
virtual void detach(const SimulationObserver& observer);
protected:
typedef std::vector<SimulationObserver*> RegisteredObservers;
RegisteredObservers _observers;
/** \brief Enable/disable notifications to registered observers
*
* This is quite useful to disable momentarily notification while you
@ -178,20 +185,36 @@ namespace sgpem
*
* \return The old value
*/
virtual bool set_notify_enabled(bool enabled = true);
bool is_notify_enabled() const;
protected:
typedef std::vector<SimulationObserver*> RegisteredObservers;
RegisteredObservers _observers;
bool set_notify_enabled(bool enabled = true);
Simulation(); // Constructor
virtual void notify_change();
void notify_change();
private:
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;
}
bool
Simulation::is_notify_enabled() const
// --------- Simulation::LockNotify ---------------
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);
}