+void Application::PushState(State *s) {
+ if (!states.empty()) {
+ states.top()->OnPause();
+ }
+ states.emplace(s);
+ ++s->ref_count;
+ if (s->ref_count == 1) {
+ s->OnEnter();
+ }
+ s->OnResume();
+}
+
+State *Application::PopState() {
+ State *s = states.top();
+ states.pop();
+ s->OnPause();
+ s->OnExit();
+ if (!states.empty()) {
+ states.top()->OnResume();
+ }
+ return s;
+}
+
+State *Application::SwitchState(State *s_new) {
+ State *s_old = states.top();
+ states.top() = s_new;
+ --s_old->ref_count;
+ ++s_new->ref_count;
+ s_old->OnPause();
+ if (s_old->ref_count == 0) {
+ s_old->OnExit();
+ }
+ if (s_new->ref_count == 1) {
+ s_new->OnEnter();
+ }
+ s_new->OnResume();
+ return s_old;
+}
+
+State &Application::GetState() {
+ return *states.top();
+}
+
+bool Application::HasState() const noexcept {
+ return !states.empty();
+}
+
+
+void StateControl::Commit(Application &app) {
+ while (!cue.empty()) {
+ Memo m(cue.front());
+ cue.pop();
+ switch (m.cmd) {
+ case PUSH:
+ app.PushState(m.state);
+ break;
+ case SWITCH:
+ app.SwitchState(m.state);
+ break;
+ case POP:
+ app.PopState();
+ break;
+ case POP_ALL:
+ while (app.HasState()) {
+ app.PopState();
+ }
+ break;
+ }
+ }