From 1417755f89c597d43dd99b8ec136bddb2764cf66 Mon Sep 17 00:00:00 2001 From: Ryan Blue Date: Fri, 18 Oct 2024 03:40:05 -0400 Subject: [PATCH] Most of c++ impl Need to look it over some more and write some more comprehensive tests --- wpilibc/src/main/native/cpp/Alert.cpp | 98 ++++++++++++++++----- wpilibc/src/main/native/include/frc/Alert.h | 31 ++++++- wpilibc/src/test/native/cpp/AlertsTest.cpp | 18 ++-- 3 files changed, 115 insertions(+), 32 deletions(-) diff --git a/wpilibc/src/main/native/cpp/Alert.cpp b/wpilibc/src/main/native/cpp/Alert.cpp index c9523fab555..00f873e36c9 100644 --- a/wpilibc/src/main/native/cpp/Alert.cpp +++ b/wpilibc/src/main/native/cpp/Alert.cpp @@ -4,42 +4,71 @@ #include "frc/Alert.h" +#include + #include +#include #include +#include #include +#include #include -#include "frc/Timer.h" +#include "frc/Errors.h" #include "frc/smartdashboard/SmartDashboard.h" using namespace frc; +wpi::StringMap Alert::groups; + Alert::Alert(std::string_view text, AlertType type) : Alert("Alerts", text, type) {} -wpi::StringMap Alert::groups; - Alert::Alert(std::string_view group, std::string_view text, AlertType type) - : m_type(type), m_text(text) { + : m_type(type), m_text(text), m_group{group} { if (!groups.contains(group)) { - groups[group] = SendableAlerts(); - frc::SmartDashboard::PutData(group, &groups[group]); + frc::SmartDashboard::PutData(group, + &groups.try_emplace(group).first->getValue()); } - groups[group].m_alerts.push_back(std::shared_ptr(this)); +} + +Alert::~Alert() { + Set(false); } void Alert::Set(bool active) { - if (active && !m_active) { - m_activeStartTime = frc::Timer::GetFPGATimestamp(); + if (active == m_active) { + return; + } + + if (active) { + m_activeStartTime = frc::RobotController::GetFPGATime(); + groups[m_group].GetSetForType(m_type).emplace(m_activeStartTime, m_text); + } else { + groups[m_group].GetSetForType(m_type).erase({m_activeStartTime, m_text}); } m_active = active; } void Alert::SetText(std::string_view text) { + if (text == m_text) { + return; + } + + if (m_active) { + auto set = groups[m_group].GetSetForType(m_type); + auto iter = set.find({m_activeStartTime, m_text}); + auto hint = set.erase(iter); + set.emplace_hint(hint, m_activeStartTime, m_text); + } m_text = text; } +Alert::SendableAlerts::SendableAlerts() { + m_alerts.fill({}); +} + void Alert::SendableAlerts::InitSendable(nt::NTSendableBuilder& builder) { builder.SetSmartDashboardType("Alerts"); builder.AddStringArrayProperty( @@ -51,22 +80,45 @@ void Alert::SendableAlerts::InitSendable(nt::NTSendableBuilder& builder) { "infos", [this]() { return GetStrings(AlertType::kInfo); }, nullptr); } -std::vector Alert::SendableAlerts::GetStrings( +std::set& Alert::SendableAlerts::GetSetForType( + AlertType type) { + return const_cast&>( + std::as_const(*this).GetSetForType(type)); +} + +const std::set& Alert::SendableAlerts::GetSetForType( AlertType type) const { - wpi::SmallVector> alerts; - alerts.reserve(m_alerts.size()); - for (auto alert : m_alerts) { - if (alert->m_active && alert->m_type == type) { - alerts.push_back(alert); - } + switch (type) { + case AlertType::kInfo: + case AlertType::kWarning: + case AlertType::kError: + return m_alerts[static_cast(type)]; + default: + throw FRC_MakeError(frc::err::InvalidParameter, "Invalid Alert Type: {}", + type); } - std::sort(alerts.begin(), alerts.end(), [](const auto a, const auto b) { - return a->m_activeStartTime > b->m_activeStartTime; - }); - std::vector output{alerts.size()}; - for (unsigned int i = 0; i < alerts.size(); ++i) { - std::string text{alerts[i]->m_text}; - output[i] = text; +} + +std::vector Alert::SendableAlerts::GetStrings( + AlertType type) const { + auto set = GetSetForType(type); + std::vector output; + output.reserve(set.size()); + for (auto& alert : set) { + output.emplace_back(alert.text); } return output; } + +std::string frc::format_as(Alert::AlertType type) { + switch (type) { + case Alert::AlertType::kInfo: + return "kInfo"; + case Alert::AlertType::kWarning: + return "kWarning"; + case Alert::AlertType::kError: + return "kError"; + default: + return fmt::format("{}", fmt::underlying(type)); + } +} diff --git a/wpilibc/src/main/native/include/frc/Alert.h b/wpilibc/src/main/native/include/frc/Alert.h index dde95306e0c..2cd3deaed41 100644 --- a/wpilibc/src/main/native/include/frc/Alert.h +++ b/wpilibc/src/main/native/include/frc/Alert.h @@ -4,12 +4,15 @@ #pragma once +#include + +#include #include +#include #include #include #include -#include #include #include #include @@ -88,6 +91,11 @@ class Alert { */ Alert(std::string_view group, std::string_view text, AlertType type); + Alert(Alert&&) = default; + Alert& operator=(Alert&&) = default; + + ~Alert(); + /** * Sets whether the alert should currently be displayed. This method can be * safely called periodically. @@ -106,21 +114,36 @@ class Alert { private: AlertType m_type; + std::string m_text; + std::string m_group; // todo: could store iterator or reference to the actual + // SendableAlerts, would remove lookup bool m_active = false; - units::second_t m_activeStartTime; - std::string_view m_text; + uint64_t m_activeStartTime; + class PublishedAlert { + public: + uint64_t timestamp; + std::string text; // todo: This could be a string_view since deleting the + // Alert will erase this from the set + auto operator<=>(const PublishedAlert&) const = default; + }; class SendableAlerts : public nt::NTSendable, public wpi::SendableHelper { public: - wpi::SmallVector> m_alerts; + SendableAlerts(); void InitSendable(nt::NTSendableBuilder& builder) override; + std::set& GetSetForType(AlertType type); + const std::set& GetSetForType(AlertType type) const; + private: std::vector GetStrings(AlertType type) const; + std::array, 3> m_alerts; }; static wpi::StringMap groups; }; +std::string format_as(Alert::AlertType type); + } // namespace frc diff --git a/wpilibc/src/test/native/cpp/AlertsTest.cpp b/wpilibc/src/test/native/cpp/AlertsTest.cpp index 7cad06b2de0..b1e4a42f37e 100644 --- a/wpilibc/src/test/native/cpp/AlertsTest.cpp +++ b/wpilibc/src/test/native/cpp/AlertsTest.cpp @@ -1,12 +1,20 @@ -#include +// Copyright (c) FIRST and other WPILib contributors. +// Open Source Software; you can modify and/or share it under the terms of +// the WPILib BSD license file in the root directory of this project. + #include -#include + #include -TEST(AlertsTest, SmokeTest) { + +#include +#include + +TEST(AlertsTest, Smoke) { { frc::Alert("Thing A", frc::Alert::AlertType::kError); } frc::Alert a{"", frc::Alert::AlertType::kInfo}; { - std::string s = fmt::format("{}", std::chrono::steady_clock::now().time_since_epoch().count()); + std::string s = fmt::format( + "{}", std::chrono::steady_clock::now().time_since_epoch().count()); a = frc::Alert(s, frc::Alert::AlertType::kError); } -} \ No newline at end of file +}