From: ehofman Date: Wed, 24 Sep 2003 17:19:22 +0000 (+0000) Subject: Move FGEventMgr and FGSubsystemMgr over to SimGear, add SGEventMgr to FlightGear... X-Git-Url: https://git.mxchange.org/?a=commitdiff_plain;h=d22640ef4e938b523bdc30cd83370977d30de856;p=simgear.git Move FGEventMgr and FGSubsystemMgr over to SimGear, add SGEventMgr to FlightGear's globals structre and some small code cleanups --- diff --git a/configure.ac b/configure.ac index d3f68ffd..eac3f371 100644 --- a/configure.ac +++ b/configure.ac @@ -367,6 +367,7 @@ AC_CONFIG_FILES([ \ simgear/screen/Makefile \ simgear/serial/Makefile \ simgear/sound/Makefile \ + simgear/structure/Makefile \ simgear/threads/Makefile \ simgear/timing/Makefile \ simgear/xgl/Makefile \ diff --git a/simgear/Makefile.am b/simgear/Makefile.am index 9422b2eb..24681e0d 100644 --- a/simgear/Makefile.am +++ b/simgear/Makefile.am @@ -30,6 +30,7 @@ SUBDIRS = \ serial \ sound \ $(SGTHREAD_DIR) \ + structure \ timing \ xgl diff --git a/simgear/misc/Makefile.am b/simgear/misc/Makefile.am index 1d0ac77b..d8a4555f 100644 --- a/simgear/misc/Makefile.am +++ b/simgear/misc/Makefile.am @@ -3,8 +3,6 @@ includedir = @includedir@/misc lib_LIBRARIES = libsgmisc.a include_HEADERS = \ - commands.hxx \ - exception.hxx \ sg_path.hxx \ sgstream.hxx \ stopwatch.hxx \ @@ -14,8 +12,6 @@ include_HEADERS = \ zfstream.hxx libsgmisc_a_SOURCES = \ - commands.cxx \ - exception.cxx \ sg_path.cxx \ sgstream.cxx \ strutils.cxx \ diff --git a/simgear/misc/commands.cxx b/simgear/misc/commands.cxx deleted file mode 100644 index 2e2c5921..00000000 --- a/simgear/misc/commands.cxx +++ /dev/null @@ -1,64 +0,0 @@ -// commands.cxx - encapsulated commands. -// Started Spring 2001 by David Megginson, david@megginson.com -// This code is released into the Public Domain. -// -// $Id$ - -#include - -#include "commands.hxx" - - - -//////////////////////////////////////////////////////////////////////// -// Implementation of SGCommandMgr class. -//////////////////////////////////////////////////////////////////////// - - -SGCommandMgr::SGCommandMgr () -{ - // no-op -} - -SGCommandMgr::~SGCommandMgr () -{ - // no-op -} - -void -SGCommandMgr::addCommand (const string &name, command_t command) -{ - _commands[name] = command; -} - -SGCommandMgr::command_t -SGCommandMgr::getCommand (const string &name) const -{ - const command_map::const_iterator it = _commands.find(name); - return (it != _commands.end() ? it->second : 0); -} - -vector -SGCommandMgr::getCommandNames () const -{ - vector names; - command_map::const_iterator it = _commands.begin(); - command_map::const_iterator last = _commands.end(); - while (it != last) { - names.push_back(it->first); - it++; - } - return names; -} - -bool -SGCommandMgr::execute (const string &name, const SGPropertyNode * arg) const -{ - command_t command = getCommand(name); - if (command == 0) - return false; - else - return (*command)(arg); -} - -// end of commands.cxx diff --git a/simgear/misc/commands.hxx b/simgear/misc/commands.hxx deleted file mode 100644 index 4ab28a09..00000000 --- a/simgear/misc/commands.hxx +++ /dev/null @@ -1,111 +0,0 @@ -/** - * \file commands.hxx - * Interface definition for encapsulated commands. - * Started Spring 2001 by David Megginson, david@megginson.com - * This code is released into the Public Domain. - * - * $Id$ - */ - -#ifndef __COMMANDS_HXX -#define __COMMANDS_HXX - - -#include - -#include STL_STRING -#include -#include - -#include - -SG_USING_STD(string); -SG_USING_STD(map); -SG_USING_STD(vector); - - -/** - * Manage commands. - * - *

This class allows the application to register and unregister - * commands, and provides shortcuts for executing them. Commands are - * simple functions that take a const pointer to an SGPropertyNode: - * the function may use the nodes children as parameters.

- * - * @author David Megginson, david@megginson.com - */ -class SGCommandMgr -{ -public: - - /** - * Type for a command function. - */ - typedef bool (*command_t) (const SGPropertyNode * arg); - - - /** - * Default constructor. - */ - SGCommandMgr (); - - - /** - * Destructor. - */ - virtual ~SGCommandMgr (); - - - /** - * Register a new command with the manager. - * - * @param name The command name. Any existing command with - * the same name will silently be overwritten. - * @param command A pointer to a one-arg function returning - * a bool result. The argument is always a const pointer to - * an SGPropertyNode (which may contain multiple values). - */ - virtual void addCommand (const string &name, command_t command); - - - /** - * Look up an existing command. - * - * @param name The command name. - * @return A pointer to the command, or 0 if there is no registered - * command with the name specified. - */ - virtual command_t getCommand (const string &name) const; - - - /** - * Get a list of all existing command names. - * - * @return A (possibly empty) vector of the names of all registered - * commands. - */ - virtual vector getCommandNames () const; - - - /** - * Execute a command. - * - * @param name The name of the command. - * @param arg A const pointer to an SGPropertyNode. The node - * may have a value and/or children, etc., so that it is possible - * to pass an arbitrarily complex data structure to a command. - * @return true if the command is present and executes successfully, - * false otherwise. - */ - virtual bool execute (const string &name, const SGPropertyNode * arg) const; - -private: - - typedef map command_map; - command_map _commands; - -}; - -#endif // __COMMANDS_HXX - -// end of commands.hxx diff --git a/simgear/misc/exception.cxx b/simgear/misc/exception.cxx deleted file mode 100644 index 75f4cf50..00000000 --- a/simgear/misc/exception.cxx +++ /dev/null @@ -1,307 +0,0 @@ -// exception.cxx - implementation of SimGear base exceptions. -// Started Summer 2001 by David Megginson, david@megginson.com -// This code is released into the Public Domain. -// -// $Id$ - - -#include "exception.hxx" -#include - - -//////////////////////////////////////////////////////////////////////// -// Implementation of sg_location class. -//////////////////////////////////////////////////////////////////////// - -sg_location::sg_location () - : _path(""), - _line(-1), - _column(-1), - _byte(-1) -{ -} - -sg_location::sg_location (const string &path, int line, int column) - : _path(path), - _line(line), - _column(column), - _byte(-1) -{ -} - -sg_location::~sg_location () -{ -} - -const string & -sg_location::getPath () const -{ - return _path; -} - -void -sg_location::setPath (const string &path) -{ - _path = path; -} - -int -sg_location::getLine () const -{ - return _line; -} - -void -sg_location::setLine (int line) -{ - _line = line; -} - -int -sg_location::getColumn () const -{ - return _column; -} - -void -sg_location::setColumn (int column) -{ - _column = column; -} - -int -sg_location::getByte () const -{ - return _byte; -} - -void -sg_location::setByte (int byte) -{ - _byte = byte; -} - -string -sg_location::asString () const -{ - char buf[128]; - string out = ""; - if (_path != (string)"") { - out += _path; - if (_line != -1 || _column != -1) - out += ",\n"; - } - if (_line != -1) { - sprintf(buf, "line %d", _line); - out += buf; - if (_column != -1) - out += ", "; - } - if (_column != -1) { - sprintf(buf, "column %d", _column); - out += buf; - } - return out; - -} - - - -//////////////////////////////////////////////////////////////////////// -// Implementation of sg_throwable class. -//////////////////////////////////////////////////////////////////////// - -sg_throwable::sg_throwable () - : _message(""), - _origin("") -{ -} - -sg_throwable::sg_throwable (const string &message, const string &origin) - : _message(message), - _origin(origin) -{ -} - -sg_throwable::~sg_throwable () -{ -} - -const string & -sg_throwable::getMessage () const -{ - return _message; -} - -const string -sg_throwable::getFormattedMessage () const -{ - return getMessage(); -} - -void -sg_throwable::setMessage (const string &message) -{ - _message = message; -} - -const string & -sg_throwable::getOrigin () const -{ - return _origin; -} - -void -sg_throwable::setOrigin (const string &origin) -{ - _origin = origin; -} - - - -//////////////////////////////////////////////////////////////////////// -// Implementation of sg_error class. -//////////////////////////////////////////////////////////////////////// - -sg_error::sg_error () - : sg_throwable () -{ -} - -sg_error::sg_error (const string &message, const string &origin) - : sg_throwable(message, origin) -{ -} - -sg_error::~sg_error () -{ -} - - - -//////////////////////////////////////////////////////////////////////// -// Implementation of sg_exception class. -//////////////////////////////////////////////////////////////////////// - -sg_exception::sg_exception () - : sg_throwable () -{ -} - -sg_exception::sg_exception (const string &message, const string &origin) - : sg_throwable(message, origin) -{ -} - -sg_exception::~sg_exception () -{ -} - - - -//////////////////////////////////////////////////////////////////////// -// Implementation of sg_io_exception. -//////////////////////////////////////////////////////////////////////// - -sg_io_exception::sg_io_exception () - : sg_exception() -{ -} - -sg_io_exception::sg_io_exception (const string &message, const string &origin) - : sg_exception(message, origin) -{ -} - -sg_io_exception::sg_io_exception (const string &message, - const sg_location &location, - const string &origin) - : sg_exception(message, origin), - _location(location) -{ -} - -sg_io_exception::~sg_io_exception () -{ -} - -const string -sg_io_exception::getFormattedMessage () const -{ - string ret = getMessage(); - ret += "\n at "; - ret += getLocation().asString(); - return ret; -} - -const sg_location & -sg_io_exception::getLocation () const -{ - return _location; -} - -void -sg_io_exception::setLocation (const sg_location &location) -{ - _location = location; -} - - - -//////////////////////////////////////////////////////////////////////// -// Implementation of sg_format_exception. -//////////////////////////////////////////////////////////////////////// - -sg_format_exception::sg_format_exception () - : sg_exception(), - _text("") -{ -} - -sg_format_exception::sg_format_exception (const string &message, - const string &text, - const string &origin) - : sg_exception(message, origin), - _text(text) -{ -} - -sg_format_exception::~sg_format_exception () -{ -} - -const string & -sg_format_exception::getText () const -{ - return _text; -} - -void -sg_format_exception::setText (const string &text) -{ - _text = text; -} - - - -//////////////////////////////////////////////////////////////////////// -// Implementation of sg_range_exception. -//////////////////////////////////////////////////////////////////////// - -sg_range_exception::sg_range_exception () - : sg_exception() -{ -} - -sg_range_exception::sg_range_exception (const string &message, - const string &origin) - : sg_exception(message, origin) -{ -} - -sg_range_exception::~sg_range_exception () -{ -} - - -// end of exception.cxx diff --git a/simgear/misc/exception.hxx b/simgear/misc/exception.hxx deleted file mode 100644 index 9de8ea8c..00000000 --- a/simgear/misc/exception.hxx +++ /dev/null @@ -1,182 +0,0 @@ -/** - * \file exception.hxx - * Interface definition for SimGear base exceptions. - * Started Spring 2001 by David Megginson, david@megginson.com - * This code is released into the Public Domain. - * - * $Id$ - */ - -#ifndef __SIMGEAR_MISC_EXCEPTION_HXX -#define __SIMGEAR_MISC_EXCEPTION_HXX 1 - -#include -#include STL_STRING - -SG_USING_STD(string); - - -/** - * Information encapsulating a single location in an external resource - * - * A position in the resource my optionally be provided, either by - * line number, line number and column number, or byte offset from the - * beginning of the resource. - */ -class sg_location -{ -public: - sg_location (); - sg_location (const string &path, int line = -1, int column = -1); - virtual ~sg_location (); - virtual const string &getPath () const; - virtual void setPath (const string &path); - virtual int getLine () const; - virtual void setLine (int line); - virtual int getColumn () const; - virtual void setColumn (int column); - virtual int getByte () const; - virtual void setByte (int byte); - virtual string asString () const; -private: - string _path; - int _line; - int _column; - int _byte; -}; - - -/** - * Abstract base class for all throwables. - */ -class sg_throwable -{ -public: - sg_throwable (); - sg_throwable (const string &message, const string &origin = ""); - virtual ~sg_throwable (); - virtual const string &getMessage () const; - virtual const string getFormattedMessage () const; - virtual void setMessage (const string &message); - virtual const string &getOrigin () const; - virtual void setOrigin (const string &origin); -private: - string _message; - string _origin; -}; - - - -/** - * An unexpected fatal error. - * - * Methods and functions show throw this exception when something - * very bad has happened (such as memory corruption or - * a totally unexpected internal value). Applications should catch - * this exception only at the top level if at all, and should - * normally terminate execution soon afterwards. - */ -class sg_error : public sg_throwable -{ -public: - sg_error (); - sg_error (const string &message, const string &origin = ""); - virtual ~sg_error (); -}; - - -/** - * Base class for all SimGear exceptions. - * - * SimGear-based code should throw this exception only when no - * more specific exception applies. It may not be caught until - * higher up in the application, where it is not possible to - * resume normal operations if desired. - * - * A caller can catch sg_exception by default to ensure that - * all exceptions are caught. Every SimGear exception can contain - * a human-readable error message and a human-readable string - * indicating the part of the application causing the exception - * (as an aid to debugging, only). - */ -class sg_exception : public sg_throwable -{ -public: - sg_exception (); - sg_exception (const string &message, const string &origin = ""); - virtual ~sg_exception (); -}; - - -/** - * An I/O-related SimGear exception. - * - * SimGear-based code should throw this exception when it fails - * to read from or write to an external resource, such as a file, - * socket, URL, or database. - * - * In addition to the functionality of sg_exception, an - * sg_io_exception may contain location information, such as the name - * of a file or URL, and possible also a location in that file or URL. - */ -class sg_io_exception : public sg_exception -{ -public: - sg_io_exception (); - sg_io_exception (const string &message, const string &origin = ""); - sg_io_exception (const string &message, const sg_location &location, - const string &origin = ""); - virtual ~sg_io_exception (); - virtual const string getFormattedMessage () const; - virtual const sg_location &getLocation () const; - virtual void setLocation (const sg_location &location); -private: - sg_location _location; -}; - - -/** - * A format-related SimGear exception. - * - * SimGear-based code should throw this exception when a string - * does not appear in the expected format (for example, a date - * string does not conform to ISO 8601). - * - * In addition to the functionality of sg_exception, an - * sg_format_exception can contain a copy of the original malformated - * text. - */ -class sg_format_exception : public sg_exception -{ -public: - sg_format_exception (); - sg_format_exception (const string &message, const string &text, - const string &origin = ""); - virtual ~sg_format_exception (); - virtual const string &getText () const; - virtual void setText (const string &text); -private: - string _text; -}; - - -/** - * A range-related SimGear exception. - * - * SimGear-based code should throw this exception when a value falls - * outside the range where it can reasonably be handled; examples - * include longitude outside the range -180:180, unrealistically high - * forces or velocities, an illegal airport code, etc. A range - * exception usually means that something has gone wrong internally. - */ -class sg_range_exception : public sg_exception -{ -public: - sg_range_exception (); - sg_range_exception (const string &message, const string &origin = ""); - virtual ~sg_range_exception (); -}; - -#endif - -// end of exception.hxx diff --git a/simgear/props/condition.cxx b/simgear/props/condition.cxx index b1314af4..014aff45 100644 --- a/simgear/props/condition.cxx +++ b/simgear/props/condition.cxx @@ -13,10 +13,9 @@ // #include STL_IOSTREAM -#include +#include #include "props.hxx" - #include "condition.hxx" SG_USING_STD(istream); diff --git a/simgear/scene/material/matlib.cxx b/simgear/scene/material/matlib.cxx index d6ba0382..9d0ee86d 100644 --- a/simgear/scene/material/matlib.cxx +++ b/simgear/scene/material/matlib.cxx @@ -37,7 +37,7 @@ #include #include -#include +#include #include #include STL_STRING diff --git a/simgear/scene/model/model.cxx b/simgear/scene/model/model.cxx index 311ee707..9d387ae2 100644 --- a/simgear/scene/model/model.cxx +++ b/simgear/scene/model/model.cxx @@ -17,13 +17,12 @@ #include #include -#include +#include #include #include #include #include "animation.hxx" - #include "model.hxx" SG_USING_STD(vector); diff --git a/simgear/structure/.cvsignore b/simgear/structure/.cvsignore new file mode 100644 index 00000000..e9955884 --- /dev/null +++ b/simgear/structure/.cvsignore @@ -0,0 +1,3 @@ +.deps +Makefile +Makefile.in diff --git a/simgear/structure/Makefile.am b/simgear/structure/Makefile.am new file mode 100644 index 00000000..386c9d94 --- /dev/null +++ b/simgear/structure/Makefile.am @@ -0,0 +1,20 @@ +includedir = @includedir@/structure + +lib_LIBRARIES = libsgstructure.a + +include_HEADERS = \ + callback.hxx \ + commands.hxx \ + exception.hxx \ + event_mgr.hxx \ + subsystem_mgr.hxx + +libsgstructure_a_SOURCES = \ + commands.cxx \ + exception.cxx \ + event_mgr.cxx\ + subsystem_mgr.cxx + + +INCLUDES = -I$(top_srcdir) + diff --git a/simgear/structure/callback.hxx b/simgear/structure/callback.hxx new file mode 100644 index 00000000..a5fab150 --- /dev/null +++ b/simgear/structure/callback.hxx @@ -0,0 +1,148 @@ +/************************************************************************** + * callback.hxx -- Wrapper classes to treat function and method pointers + * as objects. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id$ + **************************************************************************/ + +#ifndef _SG_CALLBACK_HXX +#define _SG_CALLBACK_HXX + +/** + * Abstract base class for all callbacks. + */ +class SGCallback +{ +public: + + /** + * + */ + virtual ~SGCallback() {} + + /** + * + */ + virtual SGCallback* clone() const = 0; + + /** + * Execute the callback function. + */ + virtual void operator()() = 0; + +protected: + /** + * + */ + SGCallback() {} + +private: + // Not implemented. + void operator=( const SGCallback& ); +}; + +/** + * Callback for invoking a file scope function. + */ +template< typename Fun > +class SGFunctionCallback : public SGCallback +{ +public: + /** + * + */ + SGFunctionCallback( const Fun& fun ) + : SGCallback(), f_(fun) {} + + SGCallback* clone() const + { + return new SGFunctionCallback( *this ); + } + + void operator()() { f_(); } + +private: + // Not defined. + SGFunctionCallback(); + +private: + Fun f_; +}; + +/** + * Callback for invoking a member function. + */ +template< class ObjPtr, typename MemFn > +class SGMethodCallback : public SGCallback +{ +public: + + /** + * + */ + SGMethodCallback( const ObjPtr& pObj, MemFn pMemFn ) + : SGCallback(), + pObj_(pObj), + pMemFn_(pMemFn) + { + } + + /** + * + */ + SGCallback* clone() const + { + return new SGMethodCallback( *this ); + } + + /** + * + */ + void operator()() + { + ((*pObj_).*pMemFn_)(); + } + +private: + // Not defined. + SGMethodCallback(); + +private: + ObjPtr pObj_; + MemFn pMemFn_; +}; + +/** + * Helper template functions. + */ + +template< typename Fun > +SGCallback* +make_callback( const Fun& fun ) +{ + return new SGFunctionCallback(fun); +} + +template< class ObjPtr, typename MemFn > +SGCallback* +make_callback( const ObjPtr& pObj, MemFn pMemFn ) +{ + return new SGMethodCallback(pObj, pMemFn ); +} + +#endif // _SG_CALLBACK_HXX + diff --git a/simgear/structure/commands.cxx b/simgear/structure/commands.cxx new file mode 100644 index 00000000..2e2c5921 --- /dev/null +++ b/simgear/structure/commands.cxx @@ -0,0 +1,64 @@ +// commands.cxx - encapsulated commands. +// Started Spring 2001 by David Megginson, david@megginson.com +// This code is released into the Public Domain. +// +// $Id$ + +#include + +#include "commands.hxx" + + + +//////////////////////////////////////////////////////////////////////// +// Implementation of SGCommandMgr class. +//////////////////////////////////////////////////////////////////////// + + +SGCommandMgr::SGCommandMgr () +{ + // no-op +} + +SGCommandMgr::~SGCommandMgr () +{ + // no-op +} + +void +SGCommandMgr::addCommand (const string &name, command_t command) +{ + _commands[name] = command; +} + +SGCommandMgr::command_t +SGCommandMgr::getCommand (const string &name) const +{ + const command_map::const_iterator it = _commands.find(name); + return (it != _commands.end() ? it->second : 0); +} + +vector +SGCommandMgr::getCommandNames () const +{ + vector names; + command_map::const_iterator it = _commands.begin(); + command_map::const_iterator last = _commands.end(); + while (it != last) { + names.push_back(it->first); + it++; + } + return names; +} + +bool +SGCommandMgr::execute (const string &name, const SGPropertyNode * arg) const +{ + command_t command = getCommand(name); + if (command == 0) + return false; + else + return (*command)(arg); +} + +// end of commands.cxx diff --git a/simgear/structure/commands.hxx b/simgear/structure/commands.hxx new file mode 100644 index 00000000..4ab28a09 --- /dev/null +++ b/simgear/structure/commands.hxx @@ -0,0 +1,111 @@ +/** + * \file commands.hxx + * Interface definition for encapsulated commands. + * Started Spring 2001 by David Megginson, david@megginson.com + * This code is released into the Public Domain. + * + * $Id$ + */ + +#ifndef __COMMANDS_HXX +#define __COMMANDS_HXX + + +#include + +#include STL_STRING +#include +#include + +#include + +SG_USING_STD(string); +SG_USING_STD(map); +SG_USING_STD(vector); + + +/** + * Manage commands. + * + *

This class allows the application to register and unregister + * commands, and provides shortcuts for executing them. Commands are + * simple functions that take a const pointer to an SGPropertyNode: + * the function may use the nodes children as parameters.

+ * + * @author David Megginson, david@megginson.com + */ +class SGCommandMgr +{ +public: + + /** + * Type for a command function. + */ + typedef bool (*command_t) (const SGPropertyNode * arg); + + + /** + * Default constructor. + */ + SGCommandMgr (); + + + /** + * Destructor. + */ + virtual ~SGCommandMgr (); + + + /** + * Register a new command with the manager. + * + * @param name The command name. Any existing command with + * the same name will silently be overwritten. + * @param command A pointer to a one-arg function returning + * a bool result. The argument is always a const pointer to + * an SGPropertyNode (which may contain multiple values). + */ + virtual void addCommand (const string &name, command_t command); + + + /** + * Look up an existing command. + * + * @param name The command name. + * @return A pointer to the command, or 0 if there is no registered + * command with the name specified. + */ + virtual command_t getCommand (const string &name) const; + + + /** + * Get a list of all existing command names. + * + * @return A (possibly empty) vector of the names of all registered + * commands. + */ + virtual vector getCommandNames () const; + + + /** + * Execute a command. + * + * @param name The name of the command. + * @param arg A const pointer to an SGPropertyNode. The node + * may have a value and/or children, etc., so that it is possible + * to pass an arbitrarily complex data structure to a command. + * @return true if the command is present and executes successfully, + * false otherwise. + */ + virtual bool execute (const string &name, const SGPropertyNode * arg) const; + +private: + + typedef map command_map; + command_map _commands; + +}; + +#endif // __COMMANDS_HXX + +// end of commands.hxx diff --git a/simgear/structure/event_mgr.cxx b/simgear/structure/event_mgr.cxx new file mode 100644 index 00000000..979420d7 --- /dev/null +++ b/simgear/structure/event_mgr.cxx @@ -0,0 +1,258 @@ +// +// SGEventMgr.cxx -- Event Manager +// +// Written by Bernie Bright, started April 2002. +// +// Copyright (C) 2002 Curtis L. Olson - curt@me.umn.edu +// +// 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., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// $Id$ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#include + +#include "event_mgr.hxx" + +SGEvent::SGEvent() + : _name(""), + _callback(0), + _subsystem(0), + _repeat_value(0), + _initial_value(0), + _ms_to_go(0), + _cum_time(0), + _min_time(100000), + _max_time(0), + _count(0) +{ +} + +SGEvent::SGEvent( const char* name, + SGCallback* cb, + interval_type repeat_value, + interval_type initial_value ) + : _name(name), + _callback(cb), + _subsystem(NULL), + _repeat_value(repeat_value), + _initial_value(initial_value), + _cum_time(0), + _min_time(100000), + _max_time(0), + _count(0) +{ + if (_initial_value < 0) + { + this->run(); + _ms_to_go = _repeat_value; + } + else + { + _ms_to_go = _initial_value; + } +} + +SGEvent::SGEvent( const char* name, + const SGSubsystem* subsystem, + interval_type repeat_value, + interval_type initial_value ) + : _name(name), + _callback(NULL), + _subsystem((SGSubsystem*)&subsystem), + _repeat_value(repeat_value), + _initial_value(initial_value), + _cum_time(0), + _min_time(100000), + _max_time(0), + _count(0) +{ + if (_initial_value < 0) + { + this->run(); + _ms_to_go = _repeat_value; + } + else + { + _ms_to_go = _initial_value; + } +} + + +SGEvent::~SGEvent() +{ + //delete callback_; +} + +void +SGEvent::run() +{ + SGTimeStamp start_time; + SGTimeStamp finish_time; + + start_time.stamp(); + + // run the event + if (_callback) + { + (*_callback)(); + } else if (_subsystem) + { + _subsystem->update(_repeat_value); + } + + finish_time.stamp(); + + ++_count; + + unsigned long duration = finish_time - start_time; + + _cum_time += duration; + + if ( duration < _min_time ) { + _min_time = duration; + } + + if ( duration > _max_time ) { + _max_time = duration; + } +} + +void +SGEvent::print_stats() const +{ + SG_LOG( SG_EVENT, SG_INFO, + " " << _name + << " int=" << _repeat_value / 1000.0 + << " cum=" << _cum_time + << " min=" << _min_time + << " max=" << _max_time + << " count=" << _count + << " ave=" << _cum_time / (double)_count ); +} + + + +SGEventMgr::SGEventMgr() +{ +} + +SGEventMgr::~SGEventMgr() +{ +} + +void +SGEventMgr::init() +{ + SG_LOG( SG_EVENT, SG_INFO, "Initializing event manager" ); + + event_table.clear(); +} + +void +SGEventMgr::reinit() +{ +} + + +void +SGEventMgr::bind() +{ +} + +void +SGEventMgr::unbind() +{ +} + +void +SGEventMgr::update( double dt ) +{ + int dt_ms = int(dt * 1000); + + if (dt_ms < 0) + { + SG_LOG( SG_GENERAL, SG_ALERT, + "SGEventMgr::update() called with negative delta T" ); + return; + } + + int min_value = 0; + event_container_type::iterator first = event_table.begin(); + event_container_type::iterator last = event_table.end(); + event_container_type::iterator event = event_table.end(); + + // Scan all events. Run one whose interval has expired. + while (first != last) + { + if (first->update( dt_ms )) + { + if (first->value() < min_value) + { + // Select event with largest negative value. + // Its been waiting longest. + min_value = first->value(); + event = first; + } + } + ++first; + } + + if (event != last) + { + event->run(); + + if (event->repeat_value() > 0) + { + event->reset(); + } + else + { + SG_LOG( SG_GENERAL, SG_DEBUG, "Deleting event " << event->name() ); + event_table.erase( event ); + } + } +} + +void +SGEventMgr::add( const SGEvent& event ) +{ + event_table.push_back( event ); + + SG_LOG( SG_EVENT, SG_INFO, "registered event " << event.name() + << " to run every " << event.repeat_value() << "ms" ); +} + +void +SGEventMgr::print_stats() const +{ + SG_LOG( SG_EVENT, SG_INFO, "" ); + SG_LOG( SG_EVENT, SG_INFO, "Event Stats" ); + SG_LOG( SG_EVENT, SG_INFO, "-----------" ); + + event_container_type::const_iterator first = event_table.begin(); + event_container_type::const_iterator last = event_table.end(); + for (; first != last; ++first) + { + first->print_stats(); + } + + SG_LOG( SG_EVENT, SG_INFO, "" ); +} diff --git a/simgear/structure/event_mgr.hxx b/simgear/structure/event_mgr.hxx new file mode 100644 index 00000000..bcfd2d25 --- /dev/null +++ b/simgear/structure/event_mgr.hxx @@ -0,0 +1,209 @@ +// eventmMgr.hxx -- periodic event scheduler +// +// Written by Curtis Olson, started December 1997. +// Modified by Bernie Bright, April 2002. +// +// Copyright (C) 1997 Curtis L. Olson - curt@infoplane.com +// +// 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., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// $Id$ + +#ifndef SG_EVENT_MGR_HXX +#define SG_EVENT_MGR_HXX 1 + +#include + +#include +#include +#include + +#include +#include + +SG_USING_STD(vector); +SG_USING_STD(string); + + +class SGEvent +{ + +public: + + typedef int interval_type; + +private: + + string _name; + SGCallback* _callback; + SGSubsystem* _subsystem; + interval_type _repeat_value; + interval_type _initial_value; + int _ms_to_go; + + unsigned long _cum_time; // cumulative processor time of this event + unsigned long _min_time; // time of quickest execution + unsigned long _max_time; // time of slowest execution + unsigned long _count; // number of times executed + +public: + + /** + * + */ + SGEvent(); + + SGEvent( const char* desc, + SGCallback* cb, + interval_type repeat_value, + interval_type initial_value ); + + SGEvent( const char* desc, + const SGSubsystem* subsystem, + interval_type repeat_value, + interval_type initial_value ); + + /** + * + */ + ~SGEvent(); + + /** + * + */ + inline void reset() + { + _ms_to_go = _repeat_value; + } + + /** + * Execute this event's callback. + */ + void run(); + + inline string name() const { return _name; } + inline interval_type repeat_value() const { return _repeat_value; } + inline int value() const { return _ms_to_go; } + + /** + * Display event statistics. + */ + void print_stats() const; + + /** + * Update the elapsed time for this event. + * @param dt_ms elapsed time in milliseconds. + * @return true if elapsed time has expired. + */ + inline bool update( int dt_ms ) + { + return (_ms_to_go -= dt_ms) <= 0; + } +}; + + +class SGEventMgr : public SGSubsystem +{ +private: + + typedef SGEvent::interval_type interval_type; + typedef vector< SGEvent > event_container_type; + + void add( const SGEvent& event ); + + // registered events. + event_container_type event_table; + + +public: + SGEventMgr(); + ~SGEventMgr(); + + /** + * Initialize the scheduling subsystem. + */ + void init(); + void reinit(); + void bind(); + void unbind(); + + /* + * Update the elapsed time for all events. + * @param dt elapsed time in seconds. + */ + void update( double dt ); + + /** + * register a free standing function to be executed some time in the future. + * @param desc A brief description of this callback for logging. + * @param cb The callback function to be executed. + * @param repeat_value repetition rate in milliseconds. + * @param initial_value initial delay value in milliseconds. A value of + * -1 means run immediately. + */ + template< typename Fun > + inline void add( const char* name, + const Fun& f, + interval_type repeat_value, + interval_type initial_value = -1 ) + { + this->add( SGEvent( name, + make_callback(f), + repeat_value, + initial_value ) ); + } + + /** + * register a subsystem of which the update function will be executed some + * time in the future. + * @param desc A brief description of this callback for logging. + * @param subsystem The subsystem of which the update function will be + * executed. + * @param repeat_value repetition rate in milliseconds. + * @param initial_value initial delay value in milliseconds. A value of + * -1 means run immediately. + */ + inline void add( const char* name, + const SGSubsystem* subsystem, + interval_type repeat_value, + interval_type initial_value = -1 ) + { + this->add( SGEvent( name, + subsystem, + repeat_value, + initial_value ) ); + } + + template< class ObjPtr, typename MemFn > + inline void add( const char* name, + const ObjPtr& p, + MemFn pmf, + interval_type repeat_value, + interval_type initial_value = -1 ) + { + this->add( SGEvent( name, + make_callback(p,pmf), + repeat_value, + initial_value ) ); + } + + /** + * Display statistics for all registered events. + */ + void print_stats() const; +}; + + +#endif //SG_EVENT_MGR_HXX diff --git a/simgear/structure/exception.cxx b/simgear/structure/exception.cxx new file mode 100644 index 00000000..75f4cf50 --- /dev/null +++ b/simgear/structure/exception.cxx @@ -0,0 +1,307 @@ +// exception.cxx - implementation of SimGear base exceptions. +// Started Summer 2001 by David Megginson, david@megginson.com +// This code is released into the Public Domain. +// +// $Id$ + + +#include "exception.hxx" +#include + + +//////////////////////////////////////////////////////////////////////// +// Implementation of sg_location class. +//////////////////////////////////////////////////////////////////////// + +sg_location::sg_location () + : _path(""), + _line(-1), + _column(-1), + _byte(-1) +{ +} + +sg_location::sg_location (const string &path, int line, int column) + : _path(path), + _line(line), + _column(column), + _byte(-1) +{ +} + +sg_location::~sg_location () +{ +} + +const string & +sg_location::getPath () const +{ + return _path; +} + +void +sg_location::setPath (const string &path) +{ + _path = path; +} + +int +sg_location::getLine () const +{ + return _line; +} + +void +sg_location::setLine (int line) +{ + _line = line; +} + +int +sg_location::getColumn () const +{ + return _column; +} + +void +sg_location::setColumn (int column) +{ + _column = column; +} + +int +sg_location::getByte () const +{ + return _byte; +} + +void +sg_location::setByte (int byte) +{ + _byte = byte; +} + +string +sg_location::asString () const +{ + char buf[128]; + string out = ""; + if (_path != (string)"") { + out += _path; + if (_line != -1 || _column != -1) + out += ",\n"; + } + if (_line != -1) { + sprintf(buf, "line %d", _line); + out += buf; + if (_column != -1) + out += ", "; + } + if (_column != -1) { + sprintf(buf, "column %d", _column); + out += buf; + } + return out; + +} + + + +//////////////////////////////////////////////////////////////////////// +// Implementation of sg_throwable class. +//////////////////////////////////////////////////////////////////////// + +sg_throwable::sg_throwable () + : _message(""), + _origin("") +{ +} + +sg_throwable::sg_throwable (const string &message, const string &origin) + : _message(message), + _origin(origin) +{ +} + +sg_throwable::~sg_throwable () +{ +} + +const string & +sg_throwable::getMessage () const +{ + return _message; +} + +const string +sg_throwable::getFormattedMessage () const +{ + return getMessage(); +} + +void +sg_throwable::setMessage (const string &message) +{ + _message = message; +} + +const string & +sg_throwable::getOrigin () const +{ + return _origin; +} + +void +sg_throwable::setOrigin (const string &origin) +{ + _origin = origin; +} + + + +//////////////////////////////////////////////////////////////////////// +// Implementation of sg_error class. +//////////////////////////////////////////////////////////////////////// + +sg_error::sg_error () + : sg_throwable () +{ +} + +sg_error::sg_error (const string &message, const string &origin) + : sg_throwable(message, origin) +{ +} + +sg_error::~sg_error () +{ +} + + + +//////////////////////////////////////////////////////////////////////// +// Implementation of sg_exception class. +//////////////////////////////////////////////////////////////////////// + +sg_exception::sg_exception () + : sg_throwable () +{ +} + +sg_exception::sg_exception (const string &message, const string &origin) + : sg_throwable(message, origin) +{ +} + +sg_exception::~sg_exception () +{ +} + + + +//////////////////////////////////////////////////////////////////////// +// Implementation of sg_io_exception. +//////////////////////////////////////////////////////////////////////// + +sg_io_exception::sg_io_exception () + : sg_exception() +{ +} + +sg_io_exception::sg_io_exception (const string &message, const string &origin) + : sg_exception(message, origin) +{ +} + +sg_io_exception::sg_io_exception (const string &message, + const sg_location &location, + const string &origin) + : sg_exception(message, origin), + _location(location) +{ +} + +sg_io_exception::~sg_io_exception () +{ +} + +const string +sg_io_exception::getFormattedMessage () const +{ + string ret = getMessage(); + ret += "\n at "; + ret += getLocation().asString(); + return ret; +} + +const sg_location & +sg_io_exception::getLocation () const +{ + return _location; +} + +void +sg_io_exception::setLocation (const sg_location &location) +{ + _location = location; +} + + + +//////////////////////////////////////////////////////////////////////// +// Implementation of sg_format_exception. +//////////////////////////////////////////////////////////////////////// + +sg_format_exception::sg_format_exception () + : sg_exception(), + _text("") +{ +} + +sg_format_exception::sg_format_exception (const string &message, + const string &text, + const string &origin) + : sg_exception(message, origin), + _text(text) +{ +} + +sg_format_exception::~sg_format_exception () +{ +} + +const string & +sg_format_exception::getText () const +{ + return _text; +} + +void +sg_format_exception::setText (const string &text) +{ + _text = text; +} + + + +//////////////////////////////////////////////////////////////////////// +// Implementation of sg_range_exception. +//////////////////////////////////////////////////////////////////////// + +sg_range_exception::sg_range_exception () + : sg_exception() +{ +} + +sg_range_exception::sg_range_exception (const string &message, + const string &origin) + : sg_exception(message, origin) +{ +} + +sg_range_exception::~sg_range_exception () +{ +} + + +// end of exception.cxx diff --git a/simgear/structure/exception.hxx b/simgear/structure/exception.hxx new file mode 100644 index 00000000..9de8ea8c --- /dev/null +++ b/simgear/structure/exception.hxx @@ -0,0 +1,182 @@ +/** + * \file exception.hxx + * Interface definition for SimGear base exceptions. + * Started Spring 2001 by David Megginson, david@megginson.com + * This code is released into the Public Domain. + * + * $Id$ + */ + +#ifndef __SIMGEAR_MISC_EXCEPTION_HXX +#define __SIMGEAR_MISC_EXCEPTION_HXX 1 + +#include +#include STL_STRING + +SG_USING_STD(string); + + +/** + * Information encapsulating a single location in an external resource + * + * A position in the resource my optionally be provided, either by + * line number, line number and column number, or byte offset from the + * beginning of the resource. + */ +class sg_location +{ +public: + sg_location (); + sg_location (const string &path, int line = -1, int column = -1); + virtual ~sg_location (); + virtual const string &getPath () const; + virtual void setPath (const string &path); + virtual int getLine () const; + virtual void setLine (int line); + virtual int getColumn () const; + virtual void setColumn (int column); + virtual int getByte () const; + virtual void setByte (int byte); + virtual string asString () const; +private: + string _path; + int _line; + int _column; + int _byte; +}; + + +/** + * Abstract base class for all throwables. + */ +class sg_throwable +{ +public: + sg_throwable (); + sg_throwable (const string &message, const string &origin = ""); + virtual ~sg_throwable (); + virtual const string &getMessage () const; + virtual const string getFormattedMessage () const; + virtual void setMessage (const string &message); + virtual const string &getOrigin () const; + virtual void setOrigin (const string &origin); +private: + string _message; + string _origin; +}; + + + +/** + * An unexpected fatal error. + * + * Methods and functions show throw this exception when something + * very bad has happened (such as memory corruption or + * a totally unexpected internal value). Applications should catch + * this exception only at the top level if at all, and should + * normally terminate execution soon afterwards. + */ +class sg_error : public sg_throwable +{ +public: + sg_error (); + sg_error (const string &message, const string &origin = ""); + virtual ~sg_error (); +}; + + +/** + * Base class for all SimGear exceptions. + * + * SimGear-based code should throw this exception only when no + * more specific exception applies. It may not be caught until + * higher up in the application, where it is not possible to + * resume normal operations if desired. + * + * A caller can catch sg_exception by default to ensure that + * all exceptions are caught. Every SimGear exception can contain + * a human-readable error message and a human-readable string + * indicating the part of the application causing the exception + * (as an aid to debugging, only). + */ +class sg_exception : public sg_throwable +{ +public: + sg_exception (); + sg_exception (const string &message, const string &origin = ""); + virtual ~sg_exception (); +}; + + +/** + * An I/O-related SimGear exception. + * + * SimGear-based code should throw this exception when it fails + * to read from or write to an external resource, such as a file, + * socket, URL, or database. + * + * In addition to the functionality of sg_exception, an + * sg_io_exception may contain location information, such as the name + * of a file or URL, and possible also a location in that file or URL. + */ +class sg_io_exception : public sg_exception +{ +public: + sg_io_exception (); + sg_io_exception (const string &message, const string &origin = ""); + sg_io_exception (const string &message, const sg_location &location, + const string &origin = ""); + virtual ~sg_io_exception (); + virtual const string getFormattedMessage () const; + virtual const sg_location &getLocation () const; + virtual void setLocation (const sg_location &location); +private: + sg_location _location; +}; + + +/** + * A format-related SimGear exception. + * + * SimGear-based code should throw this exception when a string + * does not appear in the expected format (for example, a date + * string does not conform to ISO 8601). + * + * In addition to the functionality of sg_exception, an + * sg_format_exception can contain a copy of the original malformated + * text. + */ +class sg_format_exception : public sg_exception +{ +public: + sg_format_exception (); + sg_format_exception (const string &message, const string &text, + const string &origin = ""); + virtual ~sg_format_exception (); + virtual const string &getText () const; + virtual void setText (const string &text); +private: + string _text; +}; + + +/** + * A range-related SimGear exception. + * + * SimGear-based code should throw this exception when a value falls + * outside the range where it can reasonably be handled; examples + * include longitude outside the range -180:180, unrealistically high + * forces or velocities, an illegal airport code, etc. A range + * exception usually means that something has gone wrong internally. + */ +class sg_range_exception : public sg_exception +{ +public: + sg_range_exception (); + sg_range_exception (const string &message, const string &origin = ""); + virtual ~sg_range_exception (); +}; + +#endif + +// end of exception.hxx diff --git a/simgear/structure/subsystem_mgr.cxx b/simgear/structure/subsystem_mgr.cxx new file mode 100644 index 00000000..8b1d5ea4 --- /dev/null +++ b/simgear/structure/subsystem_mgr.cxx @@ -0,0 +1,333 @@ + +#include + +#include "exception.hxx" +#include "subsystem_mgr.hxx" + + + +//////////////////////////////////////////////////////////////////////// +// Implementation of SGSubsystem +//////////////////////////////////////////////////////////////////////// + + +SGSubsystem::SGSubsystem () + : _suspended(false) +{ +} + +SGSubsystem::~SGSubsystem () +{ +} + +void +SGSubsystem::init () +{ +} + +void +SGSubsystem::reinit () +{ +} + +void +SGSubsystem::bind () +{ +} + +void +SGSubsystem::unbind () +{ +} + +void +SGSubsystem::suspend () +{ + _suspended = true; +} + +void +SGSubsystem::suspend (bool suspended) +{ + _suspended = suspended; +} + +void +SGSubsystem::resume () +{ + _suspended = false; +} + +bool +SGSubsystem::is_suspended () const +{ + return _suspended; +} + + + +//////////////////////////////////////////////////////////////////////// +// Implementation of SGSubsystemGroup. +//////////////////////////////////////////////////////////////////////// + +SGSubsystemGroup::SGSubsystemGroup () +{ +} + +SGSubsystemGroup::~SGSubsystemGroup () +{ + for (unsigned int i = 0; i < _members.size(); i++) + delete _members[i]; +} + +void +SGSubsystemGroup::init () +{ + for (unsigned int i = 0; i < _members.size(); i++) + _members[i]->subsystem->init(); +} + +void +SGSubsystemGroup::reinit () +{ + for (unsigned int i = 0; i < _members.size(); i++) + _members[i]->subsystem->reinit(); +} + +void +SGSubsystemGroup::bind () +{ + for (unsigned int i = 0; i < _members.size(); i++) + _members[i]->subsystem->bind(); +} + +void +SGSubsystemGroup::unbind () +{ + for (unsigned int i = 0; i < _members.size(); i++) + _members[i]->subsystem->unbind(); +} + +void +SGSubsystemGroup::update (double delta_time_sec) +{ + for (unsigned int i = 0; i < _members.size(); i++) + _members[i]->update(delta_time_sec); // indirect call +} + +void +SGSubsystemGroup::suspend () +{ + for (unsigned int i = 0; i < _members.size(); i++) + _members[i]->subsystem->suspend(); +} + +void +SGSubsystemGroup::resume () +{ + for (unsigned int i = 0; i < _members.size(); i++) + _members[i]->subsystem->resume(); +} + +bool +SGSubsystemGroup::is_suspended () const +{ + return false; +} + +void +SGSubsystemGroup::set_subsystem (const string &name, SGSubsystem * subsystem, + double min_step_sec) +{ + Member * member = get_member(name, true); + if (member->subsystem != 0) + delete member->subsystem; + member->name = name; + member->subsystem = subsystem; + member->min_step_sec = min_step_sec; +} + +SGSubsystem * +SGSubsystemGroup::get_subsystem (const string &name) +{ + Member * member = get_member(name); + if (member != 0) + return member->subsystem; + else + return 0; +} + +void +SGSubsystemGroup::remove_subsystem (const string &name) +{ + for (unsigned int i = 0; i < _members.size(); i++) { + if (name == _members[i]->name) { + _members.erase(_members.begin() + i); + return; + } + } +} + +bool +SGSubsystemGroup::has_subsystem (const string &name) const +{ + return (((SGSubsystemGroup *)this)->get_member(name) != 0); +} + +SGSubsystemGroup::Member * +SGSubsystemGroup::get_member (const string &name, bool create) +{ + for (unsigned int i = 0; i < _members.size(); i++) { + if (_members[i]->name == name) + return _members[i]; + } + if (create) { + Member * member = new Member; + _members.push_back(member); + return member; + } else { + return 0; + } +} + + + +//////////////////////////////////////////////////////////////////////// +// Implementation of SGSubsystemGroup::Member +//////////////////////////////////////////////////////////////////////// + + +SGSubsystemGroup::Member::Member () + : name(""), + subsystem(0), + min_step_sec(0), + elapsed_sec(0) +{ +} + +SGSubsystemGroup::Member::Member (const Member &) +{ + Member(); +} + +SGSubsystemGroup::Member::~Member () +{ + // FIXME: causes a crash +// delete subsystem; +} + +void +SGSubsystemGroup::Member::update (double delta_time_sec) +{ + elapsed_sec += delta_time_sec; + if (elapsed_sec >= min_step_sec) { + if (!subsystem->is_suspended()) { + subsystem->update(elapsed_sec); + elapsed_sec = 0; + } + } +} + + + +//////////////////////////////////////////////////////////////////////// +// Implementation of SGSubsystemMgr. +//////////////////////////////////////////////////////////////////////// + + +SGSubsystemMgr::SGSubsystemMgr () +{ +} + +SGSubsystemMgr::~SGSubsystemMgr () +{ +} + +void +SGSubsystemMgr::init () +{ + for (int i = 0; i < MAX_GROUPS; i++) + _groups[i].init(); +} + +void +SGSubsystemMgr::reinit () +{ + for (int i = 0; i < MAX_GROUPS; i++) + _groups[i].reinit(); +} + +void +SGSubsystemMgr::bind () +{ + for (int i = 0; i < MAX_GROUPS; i++) + _groups[i].bind(); +} + +void +SGSubsystemMgr::unbind () +{ + for (int i = 0; i < MAX_GROUPS; i++) + _groups[i].unbind(); +} + +void +SGSubsystemMgr::update (double delta_time_sec) +{ + for (int i = 0; i < MAX_GROUPS; i++) { + _groups[i].update(delta_time_sec); + } +} + +void +SGSubsystemMgr::suspend () +{ + for (int i = 0; i < MAX_GROUPS; i++) + _groups[i].suspend(); +} + +void +SGSubsystemMgr::resume () +{ + for (int i = 0; i < MAX_GROUPS; i++) + _groups[i].resume(); +} + +bool +SGSubsystemMgr::is_suspended () const +{ + return false; +} + +void +SGSubsystemMgr::add (const char * name, SGSubsystem * subsystem, + GroupType group, double min_time_sec) +{ + SG_LOG(SG_GENERAL, SG_INFO, "Adding subsystem " << name); + get_group(group)->set_subsystem(name, subsystem, min_time_sec); + + if (_subsystem_map.find(name) != _subsystem_map.end()) { + SG_LOG(SG_GENERAL, SG_ALERT, "Adding duplicate subsystem " << name); + throw sg_exception("duplicate subsystem"); + } + _subsystem_map[name] = subsystem; +} + +SGSubsystemGroup * +SGSubsystemMgr::get_group (GroupType group) +{ + return &(_groups[group]); +} + +SGSubsystem * +SGSubsystemMgr::get_subsystem (const string &name) +{ + map::iterator s =_subsystem_map.find(name); + + if (s == _subsystem_map.end()) + return 0; + else + return s->second; +} + +// end of fgfs.cxx diff --git a/simgear/structure/subsystem_mgr.hxx b/simgear/structure/subsystem_mgr.hxx new file mode 100644 index 00000000..cd612335 --- /dev/null +++ b/simgear/structure/subsystem_mgr.hxx @@ -0,0 +1,345 @@ +// Written by David Megginson, started 2000-12 +// +// Copyright (C) 2000 David Megginson, david@megginson.com +// +// 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., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// $Id$ + + +#ifndef __SUBSYSTEM_MGR_HXX +#define __SUBSYSTEM_MGR_HXX 1 + + +#include + +#if 0 +#ifdef HAVE_WINDOWS_H +# include +# include +#endif + +#include STL_STRING +SG_USING_STD(string); + +#include +SG_USING_STD(vector); +#endif + +#include +SG_USING_STD(map); + +#include + + + +/** + * Basic interface for all FlightGear subsystems. + * + *

This is an abstract interface that all FlightGear subsystems + * will eventually implement. It defines the basic operations for + * each subsystem: initialization, property binding and unbinding, and + * updating. Interfaces may define additional methods, but the + * preferred way of exchanging information with other subsystems is + * through the property tree.

+ * + *

To publish information through a property, a subsystem should + * bind it to a variable or (if necessary) a getter/setter pair in the + * bind() method, and release the property in the unbind() method:

+ * + *
+ * void MySubsystem::bind ()
+ * {
+ *   fgTie("/controls/flight/elevator", &_elevator);
+ *   fgSetArchivable("/controls/flight/elevator");
+ * }
+ *
+ * void MySubsystem::unbind ()
+ * {
+ *   fgUntie("/controls/flight/elevator");
+ * }
+ * 
+ * + *

To reference a property (possibly) from another subsystem, there + * are two alternatives. If the property will be referenced only + * infrequently (say, in the init() method), then the fgGet* methods + * declared in fg_props.hxx are the simplest:

+ * + *
+ * void MySubsystem::init ()
+ * {
+ *   _errorMargin = fgGetFloat("/display/error-margin-pct");
+ * }
+ * 
+ * + *

On the other hand, if the property will be referenced frequently + * (say, in the update() method), then the hash-table lookup required + * by the fgGet* methods might be too expensive; instead, the + * subsystem should obtain a reference to the actual property node in + * its init() function and use that reference in the main loop:

+ * + *
+ * void MySubsystem::init ()
+ * {
+ *   _errorNode = fgGetNode("/display/error-margin-pct", true);
+ * }
+ *
+ * void MySubsystem::update (double delta_time_sec)
+ * {
+ *   do_something(_errorNode.getFloatValue());
+ * }
+ * 
+ * + *

The node returned will always be a pointer to SGPropertyNode, + * and the subsystem should not delete it in its destructor + * (the pointer belongs to the property tree, not the subsystem).

+ * + *

The program may ask the subsystem to suspend or resume + * sim-time-dependent operations; by default, the suspend() and + * resume() methods set the protected variable _suspended, + * which the subsystem can reference in its update() method, but + * subsystems may also override the suspend() and resume() methods to + * take different actions.

+ */ +class SGSubsystem +{ +public: + + /** + * Default constructor. + */ + SGSubsystem (); + + /** + * Virtual destructor to ensure that subclass destructors are called. + */ + virtual ~SGSubsystem (); + + + /** + * Initialize the subsystem. + * + *

This method should set up the state of the subsystem, but + * should not bind any properties. Note that any dependencies on + * the state of other subsystems should be placed here rather than + * in the constructor, so that FlightGear can control the + * initialization order.

+ */ + virtual void init (); + + + /** + * Reinitialize the subsystem. + * + *

This method should cause the subsystem to reinitialize itself, + * and (normally) to reload any configuration files.

+ */ + virtual void reinit (); + + + /** + * Acquire the subsystem's property bindings. + * + *

This method should bind all properties that the subsystem + * publishes. It will be invoked after init, but before any + * invocations of update.

+ */ + virtual void bind (); + + + /** + * Release the subsystem's property bindings. + * + *

This method should release all properties that the subsystem + * publishes. It will be invoked by FlightGear (not the destructor) + * just before the subsystem is removed.

+ */ + virtual void unbind (); + + + /** + * Update the subsystem. + * + *

FlightGear invokes this method every time the subsystem should + * update its state.

+ * + * @param delta_time_sec The delta time, in seconds, since the last + * update. On first update, delta time will be 0. + */ + virtual void update (double delta_time_sec) = 0; + + + /** + * Suspend operation of this subsystem. + * + *

This method instructs the subsystem to suspend + * sim-time-dependent operations until asked to resume. The update + * method will still be invoked so that the subsystem can take any + * non-time-dependent actions, such as updating the display.

+ * + *

It is not an error for the suspend method to be invoked when + * the subsystem is already suspended; the invocation should simply + * be ignored.

+ */ + virtual void suspend (); + + + /** + * Suspend or resum operation of this subsystem. + * + * @param suspended true if the subsystem should be suspended, false + * otherwise. + */ + virtual void suspend (bool suspended); + + + /** + * Resume operation of this subsystem. + * + *

This method instructs the subsystem to resume + * sim-time-depended operations. It is not an error for the resume + * method to be invoked when the subsystem is not suspended; the + * invocation should simply be ignored.

+ */ + virtual void resume (); + + + /** + * Test whether this subsystem is suspended. + * + * @return true if the subsystem is suspended, false if it is not. + */ + virtual bool is_suspended () const; + + +protected: + + bool _suspended; + +}; + + + +/** + * A group of FlightGear subsystems. + */ +class SGSubsystemGroup : public SGSubsystem +{ +public: + + SGSubsystemGroup (); + virtual ~SGSubsystemGroup (); + + virtual void init (); + virtual void reinit (); + virtual void bind (); + virtual void unbind (); + virtual void update (double delta_time_sec); + virtual void suspend (); + virtual void resume (); + virtual bool is_suspended () const; + + virtual void set_subsystem (const string &name, + SGSubsystem * subsystem, + double min_step_sec = 0); + virtual SGSubsystem * get_subsystem (const string &name); + virtual void remove_subsystem (const string &name); + virtual bool has_subsystem (const string &name) const; + +private: + + struct Member { + + Member (); + Member (const Member &member); + virtual ~Member (); + + virtual void update (double delta_time_sec); + + string name; + SGSubsystem * subsystem; + double min_step_sec; + double elapsed_sec; + }; + + Member * get_member (const string &name, bool create = false); + + vector _members; +}; + + + +/** + * Manage subsystems for FlightGear. + * + * This top-level subsystem will eventually manage all of the + * subsystems in FlightGear: it broadcasts its life-cycle events + * (init, bind, etc.) to all of the subsystems it manages. Subsystems + * are grouped to guarantee order of initialization and execution -- + * currently, the only two groups are INIT and GENERAL, but others + * will appear in the future. + * + * All subsystems are named as well as grouped, and subsystems can be + * looked up by name and cast to the appropriate subtype when another + * subsystem needs to invoke specialized methods. + * + * The subsystem manager owns the pointers to all the subsystems in + * it. + */ +class SGSubsystemMgr : public SGSubsystem +{ +public: + + /** + * Types of subsystem groups. + */ + enum GroupType { + INIT = 0, + GENERAL, + MAX_GROUPS + }; + + SGSubsystemMgr (); + virtual ~SGSubsystemMgr (); + + virtual void init (); + virtual void reinit (); + virtual void bind (); + virtual void unbind (); + virtual void update (double delta_time_sec); + virtual void suspend (); + virtual void resume (); + virtual bool is_suspended () const; + + virtual void add (const char * name, + SGSubsystem * subsystem, + GroupType group = GENERAL, + double min_time_sec = 0); + + virtual SGSubsystemGroup * get_group (GroupType group); + + virtual SGSubsystem * get_subsystem(const string &name); + +private: + + SGSubsystemGroup _groups[MAX_GROUPS]; + map _subsystem_map; + +}; + + + +#endif // __SUBSYSTEM_MGR_HXX + diff --git a/simgear/xml/easyxml.hxx b/simgear/xml/easyxml.hxx index 348151ef..d3f6a90a 100644 --- a/simgear/xml/easyxml.hxx +++ b/simgear/xml/easyxml.hxx @@ -9,8 +9,7 @@ #define __EASYXML_HXX #include - -#include +#include #include STL_IOSTREAM #include STL_STRING