#pragma once #include "gridfire/trigger/trigger_abstract.h" #include "gridfire/trigger/trigger_result.h" #include #include #include namespace gridfire::trigger { template class LogicalTrigger : public Trigger {}; template class AndTrigger final : public LogicalTrigger { public: AndTrigger(std::unique_ptr> A, std::unique_ptr> B); ~AndTrigger() override = default; bool check(const TriggerContextStruct& ctx) const override; void update(const TriggerContextStruct& ctx) override; void reset() override; std::string name() const override; TriggerResult why(const TriggerContextStruct& ctx) const override; std::string describe() const override; size_t numTriggers() const override; size_t numMisses() const override; private: std::unique_ptr> m_A; std::unique_ptr> m_B; mutable size_t m_hits = 0; mutable size_t m_misses = 0; mutable size_t m_updates = 0; mutable size_t m_resets = 0; }; template class OrTrigger final : public LogicalTrigger { public: OrTrigger(std::unique_ptr> A, std::unique_ptr> B); ~OrTrigger() override = default; bool check(const TriggerContextStruct& ctx) const override; void update(const TriggerContextStruct& ctx) override; void reset() override; std::string name() const override; TriggerResult why(const TriggerContextStruct& ctx) const override; std::string describe() const override; size_t numTriggers() const override; size_t numMisses() const override; private: std::unique_ptr> m_A; std::unique_ptr> m_B; mutable size_t m_hits = 0; mutable size_t m_misses = 0; mutable size_t m_updates = 0; mutable size_t m_resets = 0; }; template class NotTrigger final : public LogicalTrigger { public: explicit NotTrigger(std::unique_ptr> A); ~NotTrigger() override = default; bool check(const TriggerContextStruct& ctx) const override; void update(const TriggerContextStruct& ctx) override; void reset() override; std::string name() const override; TriggerResult why(const TriggerContextStruct& ctx) const override; std::string describe() const override; size_t numTriggers() const override; size_t numMisses() const override; private: std::unique_ptr> m_A; mutable size_t m_hits = 0; mutable size_t m_misses = 0; mutable size_t m_updates = 0; mutable size_t m_resets = 0; }; template class EveryNthTrigger final : public LogicalTrigger { public: explicit EveryNthTrigger(std::unique_ptr> A, size_t N); ~EveryNthTrigger() override = default; bool check(const TriggerContextStruct& ctx) const override; void update(const TriggerContextStruct& ctx) override; void reset() override; std::string name() const override; TriggerResult why(const TriggerContextStruct& ctx) const override; std::string describe() const override; size_t numTriggers() const override; size_t numMisses() const override; private: std::unique_ptr> m_A; size_t m_N; mutable size_t m_counter = 0; mutable size_t m_hits = 0; mutable size_t m_misses = 0; mutable size_t m_updates = 0; mutable size_t m_resets = 0; }; /////////////////////////////// // Templated Implementations // /////////////////////////////// template AndTrigger::AndTrigger( std::unique_ptr> A, std::unique_ptr> B ) : m_A(std::move(A)), m_B(std::move(B)) {} template bool AndTrigger::check(const TriggerContextStruct &ctx) const { const bool valid = m_A->check(ctx) && m_B->check(ctx); if (valid) { m_hits++; } else { m_misses++; } return valid; } template void AndTrigger::update(const TriggerContextStruct &ctx) { m_A->update(ctx); m_B->update(ctx); m_updates++; } template void AndTrigger::reset() { m_A->reset(); m_B->reset(); m_resets++; m_hits = 0; m_misses = 0; m_updates = 0; } template std::string AndTrigger::name() const { return "AND Trigger"; } template TriggerResult AndTrigger::why(const TriggerContextStruct &ctx) const { TriggerResult result; result.name = name(); TriggerResult A_result = m_A->why(ctx); result.causes.push_back(A_result); if (!A_result.value) { // Short Circuit result.value = false; result.description = "Failed because A (" + A_result.name + ") is false."; return result; } TriggerResult B_result = m_B->why(ctx); result.causes.push_back(B_result); if (!B_result.value) { result.value = false; result.description = "Failed because B (" + B_result.name + ") is false."; return result; } result.value = true; result.description = "Succeeded because both A (" + A_result.name + ") and B (" + B_result.description + ") are true."; return result; } template std::string AndTrigger::describe() const { return "(" + m_A->describe() + ") AND (" + m_B->describe() + ")"; } template size_t AndTrigger::numTriggers() const { return m_hits; } template size_t AndTrigger::numMisses() const { return m_misses; } template OrTrigger::OrTrigger( std::unique_ptr> A, std::unique_ptr> B ) : m_A(std::move(A)), m_B(std::move(B)) {} template bool OrTrigger::check(const TriggerContextStruct &ctx) const { const bool valid = m_A->check(ctx) || m_B->check(ctx); if (valid) { m_hits++; } else { m_misses++; } return valid; } template void OrTrigger::update(const TriggerContextStruct &ctx) { m_A->update(ctx); m_B->update(ctx); m_updates++; } template void OrTrigger::reset() { m_A->reset(); m_B->reset(); m_resets++; m_hits = 0; m_misses = 0; m_updates = 0; } template std::string OrTrigger::name() const { return "OR Trigger"; } template TriggerResult OrTrigger::why(const TriggerContextStruct &ctx) const { TriggerResult result; result.name = name(); TriggerResult A_result = m_A->why(ctx); result.causes.push_back(A_result); if (A_result.value) { // Short Circuit result.value = true; result.description = "Succeeded because A (" + A_result.name + ") is true."; return result; } TriggerResult B_result = m_B->why(ctx); result.causes.push_back(B_result); if (B_result.value) { result.value = true; result.description = "Succeeded because B (" + B_result.name + ") is true."; return result; } result.value = false; result.description = "Failed because both A (" + A_result.name + ") and B (" + B_result.name + ") are false."; return result; } template std::string OrTrigger::describe() const { return "(" + m_A->describe() + ") OR (" + m_B->describe() + ")"; } template size_t OrTrigger::numTriggers() const { return m_hits; } template size_t OrTrigger::numMisses() const { return m_misses; } template NotTrigger::NotTrigger( std::unique_ptr> A ) : m_A(std::move(A)) {} template bool NotTrigger::check(const TriggerContextStruct &ctx) const { const bool valid = !m_A->check(ctx); if (valid) { m_hits++; } else { m_misses++; } return valid; } template void NotTrigger::update(const TriggerContextStruct &ctx) { m_A->update(ctx); m_updates++; } template void NotTrigger::reset() { m_A->reset(); m_resets++; m_hits = 0; m_misses = 0; m_updates = 0; } template std::string NotTrigger::name() const { return "NOT Trigger"; } template TriggerResult NotTrigger::why(const TriggerContextStruct &ctx) const { TriggerResult result; result.name = name(); TriggerResult A_result = m_A->why(ctx); result.causes.push_back(A_result); if (A_result.value) { result.value = false; result.description = "Failed because A (" + A_result.name + ") is true."; return result; } result.value = true; result.description = "Succeeded because A (" + A_result.name + ") is false."; return result; } template std::string NotTrigger::describe() const { return "NOT (" + m_A->describe() + ")"; } template size_t NotTrigger::numTriggers() const { return m_hits; } template size_t NotTrigger::numMisses() const { return m_misses; } template EveryNthTrigger::EveryNthTrigger(std::unique_ptr> A, const size_t N) : m_A(std::move(A)), m_N(N) { if (N == 0) { throw std::invalid_argument("N must be greater than 0."); } } template bool EveryNthTrigger::check(const TriggerContextStruct &ctx) const { if (m_A->check(ctx) && (m_counter % m_N == 0)) { m_hits++; return true; } m_misses++; return false; } template void EveryNthTrigger::update(const TriggerContextStruct &ctx) { if (m_A->check(ctx)) { m_counter++; } m_A->update(ctx); m_updates++; } template void EveryNthTrigger::reset() { m_A->reset(); m_resets++; m_counter = 0; m_hits = 0; m_misses = 0; m_updates = 0; } template std::string EveryNthTrigger::name() const { return "Every Nth Trigger"; } template TriggerResult EveryNthTrigger::why(const TriggerContextStruct &ctx) const { TriggerResult result; result.name = name(); TriggerResult A_result = m_A->why(ctx); result.causes.push_back(A_result); if (!A_result.value) { result.value = false; result.description = "Failed because A (" + A_result.name + ") is false."; return result; } if (m_counter % m_N == 0) { result.value = true; result.description = "Succeeded because A (" + A_result.name + ") is true and the counter (" + std::to_string(m_counter) + ") is a multiple of N (" + std::to_string(m_N) + ")."; return result; } result.value = false; result.description = "Failed because the counter (" + std::to_string(m_counter) + ") is not a multiple of N (" + std::to_string(m_N) + ")."; return result; } template std::string EveryNthTrigger::describe() const { return "Every " + std::to_string(m_N) + "th (" + m_A->describe() + ")"; } template size_t EveryNthTrigger::numTriggers() const { return m_hits; } template size_t EveryNthTrigger::numMisses() const { return m_misses; } }