[aquaskk-changes 349] CVS update: AquaSKK/src/statemachine

Back to archive index

t-suw****@users***** t-suw****@users*****
2007年 8月 26日 (日) 01:34:45 JST


Index: AquaSKK/src/statemachine/GenericStateMachine.h
diff -u /dev/null AquaSKK/src/statemachine/GenericStateMachine.h:1.1.2.1
--- /dev/null	Sun Aug 26 01:34:45 2007
+++ AquaSKK/src/statemachine/GenericStateMachine.h	Sun Aug 26 01:34:45 2007
@@ -0,0 +1,499 @@
+/* -*- C++ -*-
+
+   Generic State Machine Library for C++.
+
+   Copyright (c) 2006-2007, Tomotaka SUWA <t.suw****@mac*****>
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   Neither the name of the authors nor the names of its contributors
+   may be used to endorse or promote products derived from this
+   software without specific prior written permission.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+   FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+   COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+   INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+   BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+   LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+   CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+   LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+   ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+   POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef INC__GenericStateMachine__
+#define INC__GenericStateMachine__
+
+#include <cassert>
+#include <vector>
+#include <list>
+#include <algorithm>
+#include <functional>
+
+namespace statemachinecxx_sourceforge_jp {
+    // ======================================================================
+    // event types
+    // ======================================================================
+    enum EventTypes {
+        EXIT_EVENT = -3,
+        INIT_EVENT = -2,
+        ENTRY_EVENT = -1,
+	PROBE = 0,
+        USER_EVENT = 1
+    };
+
+    // ======================================================================
+    // event
+    // ======================================================================
+    template <class ParamType>
+    class GenericEvent {
+        int signal_;
+        ParamType param_;
+
+    public:
+        GenericEvent() {}
+        GenericEvent(int signal) : signal_(signal) {}
+        GenericEvent(int signal, const ParamType& param) : signal_(signal), param_(param) {}
+
+        operator int() const	    { return signal_; }
+        void SetSignal(int signal)  { signal_ = signal;}
+
+        const ParamType& Param() const		{ return param_; }
+        void SetParam(const ParamType& arg)	{ param_ = arg; }
+
+	bool IsSystem() const { return signal_ < USER_EVENT; }
+	bool IsUser() const { return !IsSystem(); }
+
+        static GenericEvent& Probe()	{ static GenericEvent evt(PROBE);	return evt; }
+        static GenericEvent& Entry()    { static GenericEvent evt(ENTRY_EVENT); return evt; }
+        static GenericEvent& Exit()     { static GenericEvent evt(EXIT_EVENT);  return evt; }
+        static GenericEvent& Init()     { static GenericEvent evt(INIT_EVENT);  return evt; }
+    };
+
+    // ======================================================================
+    // state
+    // ======================================================================
+    template <class StateContainer>
+    class GenericState {
+	typedef typename StateContainer::Handler Handler;
+
+        enum StateType {
+            UNKNOWN,
+            SUPER,
+            INITIAL,
+            TRANSITION,
+            SAVE_HISTORY,
+            SHALLOW_HISTORY,
+            DEEP_HISTORY,
+	    FORWARD,
+	    DEEP_FORWARD,
+            DEFER_EVENT
+        };
+
+        StateType type_;
+        Handler handler_;
+
+        GenericState(StateType type, Handler handler) : type_(type), handler_(handler) {}
+
+    public:
+        GenericState() : type_(UNKNOWN), handler_(0) {}
+	GenericState(Handler handler) : type_(SUPER), handler_(handler) {}
+
+        operator Handler() const { return handler_; }
+
+        bool IsSuper() const		{ return type_ == SUPER; }
+        bool IsInitial() const          { return type_ == INITIAL; }
+        bool IsTransition() const       { return type_ == TRANSITION; }
+        bool IsSaveHistory() const      { return type_ == SAVE_HISTORY; }
+        bool IsShallowHistory() const   { return type_ == SHALLOW_HISTORY; }
+        bool IsDeepHistory() const      { return type_ == DEEP_HISTORY; }
+        bool IsForward() const		{ return type_ == FORWARD; }
+        bool IsDeepForward() const	{ return type_ == DEEP_FORWARD; }
+        bool IsDeferEvent() const       { return type_ == DEFER_EVENT; }
+
+        static GenericState Initial(Handler handler)            { return GenericState(INITIAL, handler); }
+        static GenericState Transition(Handler handler)         { return GenericState(TRANSITION, handler); }
+        static GenericState SaveHistory()                       { return GenericState(SAVE_HISTORY, 0); }
+        static GenericState ShallowHistory(Handler handler)     { return GenericState(SHALLOW_HISTORY, handler); }
+        static GenericState DeepHistory(Handler handler)        { return GenericState(DEEP_HISTORY, handler); }
+        static GenericState Forward(Handler handler)		{ return GenericState(FORWARD, handler); }
+        static GenericState DeepForward(Handler handler)	{ return GenericState(DEEP_FORWARD, handler); }
+        static GenericState DeferEvent()                        { return GenericState(DEFER_EVENT, 0); }
+    };
+
+    // ======================================================================
+    // state history
+    // ======================================================================
+    template <typename Handler>
+    class GenericStateHistory {
+        typedef std::pair<Handler, Handler> History;
+        std::vector<Handler> keys_;
+        std::vector<History> values_;
+
+	enum HistoryTypes { SHALLOW, DEEP };
+
+        int lookup(const Handler key) const {
+            typename std::vector<Handler>::const_iterator iter = std::find(keys_.begin(), keys_.end(), key);
+
+	    if(iter == keys_.end()) return -1;
+
+	    return iter - keys_.begin();
+        }
+
+        const Handler get(Handler key, HistoryTypes type) const {
+            int pos = lookup(key);
+
+            if(pos < 0) return 0;
+
+	    return type == SHALLOW ? values_[pos].first : values_[pos].second;
+        }
+
+    public:
+        void Save(Handler key, Handler shallow, Handler deep) {
+            int pos = lookup(key);
+
+            if(pos < 0) {
+                keys_.push_back(key);
+                values_.push_back(std::make_pair(shallow, deep));
+            } else {
+                values_[pos] = std::make_pair(shallow, deep);
+            }
+        }
+
+        const Handler Shallow(Handler key) const {
+            return get(key, SHALLOW);
+        }
+
+        const Handler Deep(Handler key) const {
+            return get(key, DEEP);
+        }
+    };
+
+    // ======================================================================
+    // deferred event
+    // ======================================================================
+    template <typename Handler, typename Event>
+    class GenericDeferEvent {
+        typedef std::pair<Handler, Event> Entry;
+        std::list<Entry> queue_;
+
+        struct NotEqual : public std::unary_function<Entry, bool> {
+	    const Handler key;
+	    NotEqual(Handler arg) : key(arg) {}
+            bool operator()(const Entry& entry) const {
+                return key != entry.first;
+            }
+        };
+
+    public:
+        void Enqueue(const Handler key, const Event& event) {
+            queue_.push_back(std::make_pair(key, event));
+        }
+
+        bool Dequeue(const Handler key, Event& event) {
+            if(queue_.empty()) return false;
+
+            typename std::list<Entry>::iterator iter = std::find_if(queue_.begin(), queue_.end(), NotEqual(key));
+
+            if(iter != queue_.end()) {
+                event = iter->second;
+                queue_.erase(iter);
+                return true;
+            }
+
+            return false;
+        }
+    };
+
+    // ======================================================================
+    // empty inspector
+    // ======================================================================
+    template <typename Handler, typename Event>
+    struct EmptyInspector {
+	void operator()(const Handler handler, const Event& event) {}
+    };
+
+    // ======================================================================
+    // state machine
+    // ======================================================================
+    template <class StateContainer, template <typename Handler, typename Event> class Inspector = EmptyInspector>
+    class GenericStateMachine {
+        typedef typename StateContainer::Handler Handler;
+        typedef typename StateContainer::Event Event;
+        typedef typename StateContainer::State State;
+        typedef typename StateContainer::Output Output;
+
+        StateContainer container_;
+	Inspector<Handler, Event> inspector_;
+
+        Handler top_;
+        Handler active_;
+        Handler prior_;
+
+        GenericStateHistory<Handler> history_;
+        GenericDeferEvent<Handler, Event> queue_;
+
+	Event defer_;
+
+	typedef typename std::vector<Handler> Path;
+	typedef typename Path::iterator PathIterator;
+
+	Path path_;
+
+	// ------------------------------------------------------------
+	// invoke state function
+	// ------------------------------------------------------------
+	State invoke(const Handler handler, const Event& event) {
+	    inspector_(handler, event);
+	    return (container_.*handler)(event);
+	}
+
+	// ------------------------------------------------------------
+	// system event trigger
+	// ------------------------------------------------------------
+        State getSuperState(const Handler handler)	{ return invoke(handler, Event::Probe()); }
+        State entryAction(const Handler handler)	{ return invoke(handler, Event::Entry()); }
+        State initialTransition(const Handler handler)	{ return invoke(handler, Event::Init()); }
+        State exitAction(const Handler handler) {
+            State result = invoke(handler, Event::Exit());
+
+            if(result.IsSaveHistory()) {
+                assert(prior_ != 0 && "*** Shallow history not found ***");
+                history_.Save(handler, prior_, active_);
+            }
+
+            prior_ = handler;
+
+            return result;
+        }
+
+	// ------------------------------------------------------------
+	// initial transition trigger
+	// ------------------------------------------------------------
+        void initialize(const State& target) {
+            State state;
+
+            active_ = target;
+
+            for(state = initialTransition(active_); state.IsInitial() || state.IsShallowHistory();
+                state = initialTransition(active_)) {
+		assert(state != active_ && "*** An infinte loop detected. Check INIT_EVENT ***");
+                assert((getSuperState(state) == active_ || getSuperState(state) == getSuperState(active_))
+                       && "*** Initial transition must go to same or one level deep ***");
+
+                if(state.IsShallowHistory()) {
+                    Handler shallow = history_.Shallow(active_);
+                    if(!shallow) {
+                        history_.Save(active_, state, 0); // first time
+                        active_ = state;
+                    } else {
+                        active_ = shallow;
+                    }
+                } else {
+                    active_ = state;
+                }
+
+                entryAction(active_);
+            }
+
+            assert(state != 0 && state.IsSuper() &&
+		   "*** Initial transition must be ended by returning super state ***");
+        }
+
+	// ------------------------------------------------------------
+	// transition trigger
+	// ------------------------------------------------------------
+        void transition(const Handler source, const Handler target) {
+            assert(target != top_ && "*** Transition to TopState is not allowed ***");
+
+	    Handler tmp;
+
+	    // exit to source
+	    for(tmp = active_, prior_ = 0; tmp != source; tmp = getSuperState(tmp)) {
+		exitAction(tmp);
+	    }
+
+	    // exit to LCA(Least Common Ancestor) and record the path to the target
+	    do {
+		path_.push_back(target);
+
+		// (a) self transition
+		if(source == target) {
+		    exitAction(source);
+		    break;
+		}
+
+		// (b) go into substate(one level)
+		Handler targetSuper = getSuperState(target);
+		if(source == targetSuper) {
+		    break;
+		}
+
+		// (c) balanced transition
+		Handler sourceSuper = getSuperState(source);
+		if(sourceSuper == targetSuper) {
+		    exitAction(source);
+		    break;
+		}
+
+		// (d) leave from substate(one level)
+		if(sourceSuper == target) {
+		    exitAction(source);
+		    path_.clear();
+		    break;
+		}
+
+		// (e) go into substate(multiple level)
+		path_.push_back(targetSuper);
+		for(tmp = getSuperState(targetSuper); tmp != 0; tmp = getSuperState(tmp)) {
+		    if(source == tmp) {
+			break;
+		    }
+		    path_.push_back(tmp);
+		}
+		if(tmp != 0) break;
+
+		exitAction(source);
+
+		struct check {
+		    static bool exist(Path& path, const Handler handler) {
+			PathIterator iter = std::find(path.begin(), path.end(), handler);
+			if(iter != path.end()) {
+			    path.erase(iter, path.end());
+			    return true;
+			}
+			return false;
+		    }
+		};
+
+		// (f) unbalanced transition
+		if(check::exist(path_, sourceSuper)) {
+		    break;
+		}
+
+		// (g) leave from substate(multiple level)
+		for(tmp = sourceSuper; tmp != 0; tmp = getSuperState(tmp)) {
+		    if(check::exist(path_, tmp)) {
+			break;
+		    }
+		    exitAction(tmp);
+		}
+		if(tmp != 0) break;
+
+		assert(0 && "*** Invalid state transition form detected ***");
+	    } while(0);
+
+	    // go into the target
+	    while(!path_.empty()) {
+		entryAction(path_.back());
+		path_.pop_back();
+	    }
+        }
+
+    public:
+        GenericStateMachine() : top_(&StateContainer::TopState), active_(0) {}
+        GenericStateMachine(const StateContainer& src) : container_(src), top_(&StateContainer::TopState), active_(0) {}
+
+        ~GenericStateMachine() {
+            for(Handler tmp = active_; tmp != 0; tmp = getSuperState(tmp)) {
+                exitAction(tmp);
+            }
+        }
+
+        void Start() {
+            assert(active_ == 0 && "*** You can not call Start() twice ***");
+
+            initialize(State::Initial(top_));
+        }
+
+        void Dispatch(const Event& event) {
+            if(!active_) Start();
+
+            State next;
+
+            for(Handler source = active_; source != 0; source = next) {
+                next = invoke(source, event);
+
+		if(next.IsTransition() || next.IsDeepHistory() || next.IsForward() || next.IsDeepForward()) {
+		    if(next.IsDeepHistory() || next.IsDeepForward()) {
+			next = history_.Deep(next);
+			assert(next != 0 && "*** Deep history not found ***");
+		    }
+
+		    transition(source, next);
+		    initialize(next);
+
+		    if(next.IsForward() || next.IsDeepForward()) {
+			continue;
+		    } else {
+			while(queue_.Dequeue(next, defer_)) {
+			    Dispatch(defer_);	// recursion
+			}
+		    }
+		    break;
+		}
+
+		if(next.IsDeferEvent()) {
+		    queue_.Enqueue(next, event);
+		    break;
+		}
+
+		assert(!next.IsShallowHistory() && !next.IsSaveHistory() && !next.IsInitial() &&
+		       "*** Invalid state detected ***");
+            }
+        }
+
+        const Output& Result() const {
+            return container_.Result();
+        }
+    };
+
+    // ======================================================================
+    // state container traits
+    // ======================================================================
+    template <typename T>
+    struct StateContainerTraits {
+	typedef typename T::State State;
+	typedef typename T::Event Event;
+	typedef typename T::Handler Handler;
+	typedef typename T::Output Output;
+    };
+}
+
+// ======================================================================
+// helper macro
+// ======================================================================
+
+#define DECLARE_ImportantTypes(container, param, result)	\
+    typedef GenericState<container> State;			\
+    typedef GenericEvent<param> Event;				\
+    typedef State (container::*Handler)(const Event&);		\
+    typedef result Output;
+
+#define DECLARE_TopState(container, initial)		\
+    State TopState(const Event& event) {		\
+        switch(event) {					\
+        case INIT_EVENT:				\
+            return State::Initial(&container::initial); \
+        }						\
+        return 0;					\
+    }
+
+#define DECLARE_StateContainer(container, param, result, initial)	\
+    DECLARE_ImportantTypes(container, param, result)			\
+    DECLARE_TopState(container, initial)
+
+#endif	// INC__GenericStateMachine__


aquaskk-changes メーリングリストの案内
Back to archive index