From: <sv...@ww...> - 2005-11-13 01:08:48
|
Author: mkrose Date: 2005-11-12 17:08:39 -0800 (Sat, 12 Nov 2005) New Revision: 1668 Added: trunk/CSP/SimCore/Util/LocalUpdate.cpp trunk/CSP/SimCore/Util/LocalUpdate.h Log: Add a helper class for dispatching occasional update callbacks from an UpdateTarget handler. Browse at: https://www.zerobar.net/viewcvs/viewcvs.cgi?view=rev&rev=1668 Added: trunk/CSP/SimCore/Util/LocalUpdate.cpp =================================================================== --- trunk/CSP/SimCore/Util/LocalUpdate.cpp 2005-11-12 20:22:53 UTC (rev 1667) +++ trunk/CSP/SimCore/Util/LocalUpdate.cpp 2005-11-13 01:08:39 UTC (rev 1668) @@ -0,0 +1,94 @@ +// Combat Simulator Project - CSPSim +// Copyright (C) 2005 The Combat Simulator Project +// http://csp.sourceforge.net +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + +/** + * @file LocalUpdate.cpp + * + **/ + +#include <SimCore/Util/LocalUpdate.h> +#include <algorithm> +#include <cassert> + + +namespace simcore { + +/** Internal helper class for managing update callbacks. Stores the callback + * and tracks update intervals. + */ +class LocalUpdate::PriorityHandler { +public: + PriorityHandler(Callback const &handler, double interval): m_Handler(handler), m_Next(-1), m_Last(-1), m_Interval(interval) { + assert(interval > 0.0); + if (m_Interval <= 0) m_Interval = 0.001; + } + + bool update(double t) { + bool remove = false; + double delay = m_Interval; + if (m_Next >= 0) { + const double elapsed_time = t - m_Last; + const double delta = m_Handler(elapsed_time); + if (delta > 0) delay = delta; else if (delta < 0) remove = true; + } + m_Last = t; + m_Next = t + delay; + return !remove; + } + + double next() const { return m_Next; } + double interval() const { return m_Interval; } + + struct Order { + inline bool operator()(PriorityHandler const *lhs, PriorityHandler const *rhs) { return lhs->next() > rhs->next(); } + }; + +private: + Callback m_Handler; + double m_Next; + double m_Last; + double m_Interval; +}; + + +LocalUpdate::~LocalUpdate() { + for (unsigned i = 0; i < m_Queue.size(); ++i) delete m_Queue[i]; +} + +void LocalUpdate::_addHandler(Callback const &handler, double interval) { + m_Queue.push_back(new PriorityHandler(handler, interval)); + std::push_heap(m_Queue.begin(), m_Queue.end(), PriorityHandler::Order()); +} + +void LocalUpdate::dispatch() { + assert(!m_Queue.empty()); + while (m_Queue.front()->next() <= m_Time) { + std::pop_heap(m_Queue.begin(), m_Queue.end(), PriorityHandler::Order()); + if (!m_Queue.back()->update(m_Time)) { + delete m_Queue.back(); + m_Queue.pop_back(); + } else { + std::push_heap(m_Queue.begin(), m_Queue.end(), PriorityHandler::Order()); + } + } + if (!m_Queue.empty()) m_Next = m_Queue.front()->next(); +} + +} // namespace + Added: trunk/CSP/SimCore/Util/LocalUpdate.h =================================================================== --- trunk/CSP/SimCore/Util/LocalUpdate.h 2005-11-12 20:22:53 UTC (rev 1667) +++ trunk/CSP/SimCore/Util/LocalUpdate.h 2005-11-13 01:08:39 UTC (rev 1668) @@ -0,0 +1,121 @@ +// Combat Simulator Project - CSPSim +// Copyright (C) 2005 The Combat Simulator Project +// http://csp.sourceforge.net +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + +/** + * @file LocalUpdate.h + * + **/ + +#ifndef __SIMCORE_UTIL_LOCALUPDATE_H__ +#define __SIMCORE_UTIL_LOCALUPDATE_H__ + +#include <vector> +#include <sigc++/slot.h> + + +namespace simcore { + +/** A utility class for coordinating infrequest events within a SynchronousUpdate + * handler. An UpdateTarget can register to receive updates at a given interval, + * but often the handler needs to perform multiple tasks, each at different + * intervals. This class allows the UpdateTarget handler to efficiently dispatch + * updates to multiple subhandlers on independent schedules. + * + * Note that LocalUpdate retains pointers to the handler class. The safest use + * is to make LocalUpdate a member variable, and only add handlers in the same + * instance. + * + * Example: + * + * @code + * class AircraftConsole: public UpdateTarget { + * public: + * + * Aircraft() { + * // update warning lights every 0.5 seconds, and displays every 0.05 seconds. + * m_UpdateDispatch.addHandler(this, &AircraftConsole::updateWarningLights, 0.5); + * m_UpdateDispatch.addHandler(this, &AircraftConsole::updateDisplays, 0.05); + * } + * + * private: + * + * // normal UpdateTarget handler. + * virtual double update(double dt) { + * // optional: other update code here. + * + * // return the interval to the next scheduled event so that the UpdateMaster + * // won't call this method unnecessarily. note that if update() does high- + * // priority work as well it might be appropriate to return 0 instead. + * return m_UpdateDispatch(dt); + * } + * + * // local update handlers. + * // note that the return value of the handler has the following meaning: + * // < 0: disable this handler. no further calls will be made to the handler + * // unless addHandler is called again. + * // = 0: run again after the default handler interval has expired. + * // > 0: run again after this time interval has expired. + * + * double updateWarningLights(double dt); + * double updateDisplays(double dt); + * + * LocalUpdate m_UpdateDispatch; + * }; + * @endcode + */ +class LocalUpdate { +public: + LocalUpdate(): m_Time(0), m_Next(0) { } + ~LocalUpdate(); + + /** Register a handler to receive updates at the specified interval, in seconds. + * The interval must be greater than zero. + */ + template <class C> void addHandler(C *target, double (C::*method)(double), double interval) { + _addHandler(sigc::mem_fun(target, method), interval); + } + + /** Dispatch updates to all handlers that are ready. Returns the time interval + * to the next waiting handler. + */ + double operator()(double dt) { + m_Time += dt; + if (m_Time > m_Next && !m_Queue.empty()) dispatch(); + // note: returns negative values if the queue is empty, which if returned directly + // by the UpdateTarget will disconnect it from the UpdateMaster. this may or may + // not be what is intended, but there's no obviously better thing to do here. + return m_Next - m_Time; + } + +private: + typedef sigc::slot<double, double> Callback; + class PriorityHandler; + + double m_Time; // internal time (not absolute) + double m_Next; // time of the next handler call + std::vector<PriorityHandler*> m_Queue; + + void _addHandler(Callback const &cb, double interval); + void dispatch(); +}; + +} // namespace + +#endif // __SIMCORE_UTIL_LOCALUPDATE_H__ + |