#pragma once #include "assert.hpp" #include "step_function.hpp" #include "types.hpp" #include #include #include #include "time.hpp" enum class ReturnTag { Repeat, Next, Previous, Goto, }; struct Return { ReturnTag tag; union { isize index; }; }; using namespace std::chrono_literals; class Stepped { using duration_type = std::chrono::system_clock::duration; using step_return_type = std::pair; using step_type = std::function; std::vector m_steps; isize m_current_step; duration_type m_current_wait_duration; util::Delta m_delta; auto inc_step() -> void; auto dec_step() -> void; public: Stepped() : m_current_step(0), m_steps(), m_delta(), m_current_wait_duration(0ms) {} auto add_step(const step_type& step) -> void; auto run() -> void; auto reset() -> void; }; /// IMPLEMENTATION using namespace std::chrono_literals; auto Stepped::inc_step() -> void { if (++m_current_step >= m_steps.size()) { m_current_step = 0; } } auto Stepped::dec_step() -> void { if (--m_current_step < 0) { m_current_step = m_steps.size() - 1; } } auto Stepped::add_step(const step_type &step) -> void { m_steps.push_back(step); } auto Stepped::reset() -> void { m_current_step = 0; m_current_wait_duration = 0ms; } auto Stepped::run() -> void { if (m_delta.has_elapsed(m_current_wait_duration)) { util::assert(m_current_step < m_steps.size()); auto&& [result, next_wait_duration] = m_steps[m_current_step](); switch (result.tag) { case ReturnTag::Repeat: break; case ReturnTag::Next: inc_step(); break; case ReturnTag::Previous: dec_step(); break; case ReturnTag::Goto: { util::assert(result.index < m_steps.size() && result.index >= 0); m_current_step = result.index; break; } } m_current_wait_duration = next_wait_duration; } }