⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 statemachine.h

📁 MiniSip Client with DomainKeys Authentication, Sip, Audio communications, Echo Cancel
💻 H
字号:
/*  Copyright (C) 2005, 2004 Erik Eliasson, Johan Bilien    This library is free software; you can redistribute it and/or  modify it under the terms of the GNU Lesser General Public  License as published by the Free Software Foundation; either  version 2.1 of the License, or (at your option) any later version.  This library 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  Lesser General Public License for more details.  You should have received a copy of the GNU Lesser General Public  License along with this library; if not, write to the Free Software  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA*//* * Authors: Erik Eliasson <eliasson@it.kth.se> *          Johan Bilien <jobi@via.ecp.fr>*//** * StateMachine.h * Template implementation of state machine logic. * The state machine has any number of states, "State", * any number of transitions between the states, * "StateTransition" and each transition has an action * that will be executed if the transition is taken. * * The type of the input the state machine will accept * is given as the only argument to the classes. * * State Machines are expected to ha * * ExampleSM.cxx is an example of how it can be used. * @author Erik Eliasson, eliasson@imit.kth.se * (C) 2003 Erik Eliasson*/#ifndef STATEMACHINE_H#define STATEMACHINE_H#include <libmutil/libmutil_config.h>#include<string>#include<list>#include<libmutil/TimeoutProvider.h>#include<libmutil/MemObject.h>#include<libmutil/massert.h>#ifdef MSM_DEBUG#include<libmutil/dbg.h> #endiftemplate<class CommandType, class TimeoutType> class StateTransition;template<class CommandType, class TimeoutType> class State;/** * Implementation of a generic state machine. * * A special state, StateMachine::anyState with the name "libmutil_any", * can be used as from-state in a transition. Such a transition will * be tried regardless of the current state. * * If the anyState/("libmutil_any") is used as destination state,  * the state of the machine will not change. A transition from  * anyState to anyState can be used to trap commands without  * affecting the state. *  * Note 1:  State machines, states and transitions are using the MRef/MObject * classes to handle "garbage collection". The state machines and the * transitions reference each other. Therefore we must break the circle  * so that the it becomes a chain that is not referenced by anyone (and therefore will * be freed). For this purpose you have the freeStateMachine method which * you (unfortunately) must run on any object you want to be removed * from the heap. * * Note 2: The state machine calls an action method to  *  a) determine if the transaction should be done and  *  b) perform the action associated with the transition. * This is done in a single call to a action method, and  * therefore the state machine has not transitioned into  * it's new state when the action is executed. Special  * attention has to be given to situations where an action  * sends a new command to the same machine (recursion) since  * the current state of the machine has not yet been updated  * with the target state of the transition.  * * An action method for an integer state machine typically  * looks like: *   bool MyStateMachine::myTransitionAction(const int& input){ *           if (input=='1'){ *	             doActionMagic(); *	             return true; *           }else{ *                   return false; *           } *   } *   */template<class CommandType, class TimeoutType> class StateMachine : public virtual MObject{	public:		MRef<State<CommandType, TimeoutType> *> anyState;				/**		 * Initializes the state machine to have no states and no		 * transitions.		 * 		 * @param tp	Timeoutprovider that the state machine will		 * 		use for timeouts.		 */		StateMachine( MRef<TimeoutProvider<TimeoutType, MRef<StateMachine<CommandType, TimeoutType> *>  > *> tp): 				current_state(NULL), 				timeoutProvider(tp)		{			anyState = new State<CommandType,TimeoutType>(this,"libmutil_any");		}							virtual ~StateMachine(){		}		/**		 * De-allocates the state machine. After calling this		 * method, the state machine can not be used.		 *		 * Purpose: The state machine contains "reference loops"		 * that makes the MRef/MObject garbage collection not		 * free the resources unless the "freeStateMachine" method		 * has been called. 		 * After calling this method, the state machine can be		 * garbage collected as an ordinary MObject.		 *		 */		void freeStateMachine(){			current_state=NULL;			timeoutProvider=NULL;			anyState=NULL;			for (typename std::list<MRef<State<CommandType,TimeoutType> *> >::iterator i=states.begin(); 					i!=states.end(); i++){				(*i)->freeState();			//Break the state<---->transition circle			}							states.clear();		}				std::string getMemObjectType(){return "StateMachine";}				/**		 * Adds a state that will have no transitions connected to		 * it to the state machine. If it is the first state added		 * to the machine it will be set as the current state.		 */		void addState(MRef<State<CommandType, TimeoutType> *> state){			if (!current_state)				current_state = state;			states.push_back(state);		}		/**		 * When a state is created it is given a name. This method		 * returns the first state with a matching name.		 */		MRef<State<CommandType, TimeoutType> *> getState(const std::string &name){			for (typename std::list<MRef<State<CommandType,TimeoutType> *> >::iterator i=states.begin(); i!=states.end(); i++)				if ((*i)->getName()==name)					return *i;			return NULL;		}		/**		 * A state machine has a current state that can only be		 * NULL if the state machine has no state. This method		 * sets which state is the current one (the state that		 * the machine is in). Although allowed, a user of this 		 * class should not set the current state to be		 * anyState ("libmutil_any").		 */		void setCurrentState(MRef<State<CommandType,TimeoutType> *> state){			current_state = state;		}				/**		 * Each state is assigned a name (that is not required to be		 * unique) when it is created. This method returns the name		 * assigned to the state that the machine is in.		 */		std::string getCurrentStateName() const{			return current_state->getName();		}		/**		 * Handles input to the state machine. The machine can		 * react on the input depending on which state it is		 * in and which transitions that state has.		 *		 * A state machine will try (in the following order) until		 * a the action associated with the transition returns true		 * or all has been tried:		 *  1. All transitions in the current state in the		 *     order they were added.		 *  2. All transitions in the anyState/("libmutil_any") 		 *     state in the order they were added.		 * 		 * @return TRUE is returned if a transition/action was		 * 	   taken and FALSE if no transition was triggered.		 */		virtual bool handleCommand(const CommandType &command){			if (current_state){				return current_state->handleCommand(command) || anyState->handleCommand(command);			}else{				return false;			}		}		/**		 * Requests a timeout that will be sent to this state		 * machine.		 */		void requestTimeout(int32_t ms, const TimeoutType &command){			timeoutProvider->request_timeout(ms, this, command);		}		/**		 * Cancels a previously requested timeout. If the timeout		 * does not exist (it might have expired/fired) this		 * call has no effect.		 */		void cancelTimeout(const TimeoutType &command){			timeoutProvider->cancel_request(this, command);		}		MRef< TimeoutProvider<TimeoutType, MRef<StateMachine<CommandType,TimeoutType> *> > *> getTimeoutProvider(){return timeoutProvider;}		virtual void handleTimeout(const TimeoutType &){std::cerr <<"WARNING: UNIMPLEMENTED handleTimeout"<<std::endl;};		/**		 * This method should not be called by an application. It		 * is required by Timeoutprovider.		 */		void timeout(const TimeoutType &command){handleTimeout(command);};	private:		std::list<MRef<State<CommandType,TimeoutType>*> > states;		MRef<State<CommandType,TimeoutType>*> current_state;		MRef< TimeoutProvider<TimeoutType, MRef<StateMachine<CommandType,TimeoutType> *> > *> timeoutProvider;		};template<class CommandType, class TimeoutType>class State : public MObject{	public:		State(MRef<StateMachine<CommandType,TimeoutType> *> stateMachine, 				const std::string &name):					stateMachine(stateMachine),					name(name)		{}		~State(){			freeState();		}		void freeState(){			stateMachine=NULL; 			transitions.clear();			}		std::string getMemObjectType(){return "State";}				void register_transition(MRef<StateTransition<CommandType, TimeoutType> *> transition){			transitions.push_back(transition);		}		MRef<StateTransition<CommandType, TimeoutType> *> getTransition(const std::string &name){			for (typename std::list<MRef<StateTransition<CommandType,TimeoutType> *> >::iterator i=transitions.begin(); i!=transitions.end(); i++)				if ((*i)->getName()==name)					return *i;			return NULL;		}		bool removeTransition(const std::string &name){			for (typename std::list<MRef<StateTransition<CommandType,TimeoutType> *> >::iterator i=transitions.begin(); i!=transitions.end(); i++){				if ((*i)->getName()==name){					transitions.erase(i);					return true;				}			}			return false;		}				bool handleCommand(const CommandType &command){			for (typename std::list<MRef<StateTransition<CommandType,TimeoutType> *> >::iterator i=transitions.begin(); i!=transitions.end(); i++){				if ((*i)->handleCommand(command)){					return true;				}			}			return false;		}		std::string getName(){			return name;		}			private:		MRef<StateMachine<CommandType, TimeoutType> *>stateMachine;		std::string name;		std::list<MRef<StateTransition<CommandType,TimeoutType>*> > transitions;};template<class CommandType, class TimeoutType>class StateTransition : public MObject{	public:			StateTransition(MRef<StateMachine<CommandType, TimeoutType> *> stateMachine, 				const std::string &name, 				bool (StateMachine<CommandType, TimeoutType>::*a)(const CommandType& ),				MRef<State<CommandType,TimeoutType> *> from_state, 				MRef<State<CommandType,TimeoutType> *> to_state):					stateMachine(stateMachine), 					name(name), 					action(a),					from_state(from_state),					to_state(to_state)		{			from_state->register_transition(this);		}		~StateTransition(){			stateMachine=NULL;	//Note: Setting the references to null			from_state=NULL;	//makes sure we have no circular referencing			to_state=NULL; 		}						std::string getMemObjectType(){return "StateTransition";}		bool handleCommand(const CommandType &c){			bool handled;			massert(action!=(bool (StateMachine<CommandType,TimeoutType>::*)(const CommandType& ))NULL);			if (handled= ((**stateMachine).*action)(c) ){				if ( !(to_state == stateMachine->anyState) )					stateMachine->setCurrentState(to_state);#ifdef MSM_DEBUG				if( outputStateMachineDebug ) {					merr << "MSM_DEBUG: "<<from_state->getName()<<" --> "<< to_state->getName()<<":\t" << stateMachine->getMemObjectType() << ": transition: " << name;		#ifdef MSM_DEBUG_COMMAND					merr << " ("<< c << ")";		#endif					merr << end;				}#endif			}#ifdef MSM_DEBUG			else if( outputStateMachineDebug ) {								//Activate if needed ... it produces quite some extra debug ... 				//merr << "MSM_DEBUG: " << stateMachine->getMemObjectType() << ": Transition Failed: " << name << ": " << from_state->getName()				//	<<" -> "<<to_state->getName() << end;			}#endif			return handled;		}		std::string getName(){return name;}	private:		MRef<StateMachine<CommandType,TimeoutType> *> stateMachine;		std::string name;		bool (StateMachine<CommandType, TimeoutType>::*action)(const CommandType& );				MRef<State<CommandType, TimeoutType> *>from_state;		MRef<State<CommandType, TimeoutType> *>to_state;};#endif

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -