Created
November 27, 2023 03:01
-
-
Save CoffeeVampir3/958b758ccbcbb9124d8e9c44e00fa4a2 to your computer and use it in GitHub Desktop.
State Machine Thing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <coroutine> | |
#include <iostream> | |
#include <utility> | |
#include <vector> | |
#include <list> | |
#include <deque> | |
#include <functional> | |
struct Task { | |
struct promise_type; | |
using TaskHandle = std::coroutine_handle<promise_type>; | |
struct promise_type { | |
void unhandled_exception() noexcept {} | |
Task get_return_object() { return Task{this}; } | |
std::suspend_always initial_suspend() noexcept { return {}; } | |
std::suspend_always final_suspend() noexcept { return {}; } | |
void return_void() const noexcept {} | |
}; | |
TaskHandle Handle; | |
explicit Task(promise_type* Promise) noexcept : Handle{TaskHandle::from_promise(*Promise)} {} | |
}; | |
struct TaskSequence { | |
std::list<std::coroutine_handle<>> Tasks{}; | |
bool Run() { | |
while(!Tasks.empty() && Tasks.front().done()) { | |
Tasks.pop_front(); | |
} | |
if(Tasks.empty()) return false; | |
Tasks.front().resume(); | |
return true; | |
} | |
TaskSequence& Add(Task Task) { | |
Tasks.push_back(Task.Handle); | |
return *this; | |
} | |
}; | |
struct StateInterleave { | |
using TransitionAndConstructor = std::pair<std::coroutine_handle<>, std::function<StateInterleave()>>; | |
std::coroutine_handle<> MainTask{}; | |
std::deque<TransitionAndConstructor> Transitions{}; | |
std::function<StateInterleave()> RunUntil() { | |
auto Task = Transitions.front().first; | |
Task.resume(); | |
if(Task.done()) return Transitions.front().second; | |
MainTask.resume(); | |
// Move the task to the end of the queue | |
Transitions.push_back(Transitions.front()); | |
Transitions.pop_front(); | |
return nullptr; | |
} | |
StateInterleave& State(Task Main) { | |
MainTask = Main.Handle; | |
return *this; | |
} | |
StateInterleave& Transition(Task TransitionTask, std::function<StateInterleave()> StateConstructor) { | |
Transitions.emplace_back(TransitionTask.Handle, StateConstructor); | |
return *this; | |
} | |
}; | |
Task TaskB() { | |
std::cout << "Task B1\n"; | |
co_await std::suspend_always{}; | |
std::cout << "Task B2\n"; | |
co_await std::suspend_always{}; | |
std::cout << "Task B3\n"; | |
co_await std::suspend_always{}; | |
std::cout << "Task B4\n"; | |
} | |
Task TaskA() { | |
std::cout << "Task A1\n"; | |
co_await std::suspend_always{}; | |
std::cout << "Task A2\n"; | |
co_await std::suspend_always{}; | |
std::cout << "Task A3\n"; | |
} | |
Task ExampleMainTask() { | |
while(true) { | |
std::cout << "Walking Task!\n"; | |
co_await std::suspend_always{}; | |
} | |
} | |
Task AttackTask() { | |
while(true) { | |
std::cout << "Attacking Task!\n"; | |
co_await std::suspend_always{}; | |
} | |
} | |
StateInterleave StateOne(); | |
StateInterleave StateTwo(); | |
StateInterleave StateOne() { | |
StateInterleave Seq{}; | |
return Seq | |
.State(ExampleMainTask()) | |
.Transition(TaskA(), StateTwo) | |
.Transition(TaskB(), StateTwo); | |
} | |
StateInterleave StateTwo() { | |
StateInterleave Seq{}; | |
return Seq | |
.State(AttackTask()) | |
.Transition(TaskA(), StateOne) | |
.Transition(TaskB(), StateOne); | |
} | |
Task MainTask() { | |
auto Seq = StateOne(); | |
for(int i = 3; i > 0; i--) { | |
while(true) { | |
auto Result = Seq.RunUntil(); | |
if(Result) { | |
Seq = Result(); | |
break; | |
} | |
co_await std::suspend_always{}; | |
} | |
} | |
} | |
int main() { | |
auto T = MainTask(); | |
while(!T.Handle.done()) T.Handle.resume(); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment