Skip to content

Instantly share code, notes, and snippets.

@CoffeeVampir3
Created November 27, 2023 03:01
Show Gist options
  • Save CoffeeVampir3/958b758ccbcbb9124d8e9c44e00fa4a2 to your computer and use it in GitHub Desktop.
Save CoffeeVampir3/958b758ccbcbb9124d8e9c44e00fa4a2 to your computer and use it in GitHub Desktop.
State Machine Thing
#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