mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-06-19 00:41:43 +00:00
[wpilib] Make Color::HexString() constexpr (#5985)
Related improvements to wpi::ct_string: * Implicitly convert to std::string * Add operator== for std::string, std::string_view, and const Char*
This commit is contained in:
@@ -1,13 +0,0 @@
|
||||
// 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 "frc/util/Color.h"
|
||||
|
||||
using namespace frc;
|
||||
|
||||
std::string Color::HexString() const {
|
||||
return fmt::format("#{:02X}{:02X}{:02X}", static_cast<int>(255.0 * red),
|
||||
static_cast<int>(255.0 * green),
|
||||
static_cast<int>(255.0 * blue));
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
// 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 "frc/util/Color8Bit.h"
|
||||
|
||||
using namespace frc;
|
||||
|
||||
std::string Color8Bit::HexString() const {
|
||||
return fmt::format("#{:02X}{:02X}{:02X}", red, green, blue);
|
||||
}
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
#include <fmt/core.h>
|
||||
#include <wpi/StringExtras.h>
|
||||
#include <wpi/ct_string.h>
|
||||
|
||||
namespace frc {
|
||||
|
||||
@@ -851,7 +852,16 @@ class Color {
|
||||
*
|
||||
* @return a string of the format <tt>\#RRGGBB</tt>
|
||||
*/
|
||||
std::string HexString() const;
|
||||
constexpr auto HexString() const {
|
||||
const int r = 255.0 * red;
|
||||
const int g = 255.0 * green;
|
||||
const int b = 255.0 * blue;
|
||||
|
||||
return wpi::ct_string<char, std::char_traits<char>, 7>{
|
||||
{'#', wpi::hexdigit(r / 16), wpi::hexdigit(r % 16),
|
||||
wpi::hexdigit(g / 16), wpi::hexdigit(g % 16), wpi::hexdigit(b / 16),
|
||||
wpi::hexdigit(b % 16)}};
|
||||
}
|
||||
|
||||
double red = 0.0;
|
||||
double green = 0.0;
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
#include <fmt/core.h>
|
||||
#include <wpi/StringExtras.h>
|
||||
#include <wpi/ct_string.h>
|
||||
|
||||
#include "Color.h"
|
||||
|
||||
@@ -107,7 +108,12 @@ class Color8Bit {
|
||||
*
|
||||
* @return a string of the format <tt>\#RRGGBB</tt>
|
||||
*/
|
||||
std::string HexString() const;
|
||||
constexpr auto HexString() const {
|
||||
return wpi::ct_string<char, std::char_traits<char>, 7>{
|
||||
{'#', wpi::hexdigit(red / 16), wpi::hexdigit(red % 16),
|
||||
wpi::hexdigit(green / 16), wpi::hexdigit(green % 16),
|
||||
wpi::hexdigit(blue / 16), wpi::hexdigit(blue % 16)}};
|
||||
}
|
||||
|
||||
int red = 0;
|
||||
int green = 0;
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
// 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 <string>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "frc/util/Color8Bit.h"
|
||||
@@ -56,7 +58,12 @@ TEST(Color8BitTest, ImplicitConversionToColor) {
|
||||
}
|
||||
|
||||
TEST(Color8BitTest, ToHexString) {
|
||||
constexpr frc::Color8Bit color{255, 128, 64};
|
||||
constexpr frc::Color8Bit color1{255, 128, 64};
|
||||
EXPECT_EQ("#FF8040", color1.HexString());
|
||||
|
||||
EXPECT_EQ("#FF8040", color.HexString());
|
||||
// Ensure conversion to std::string works
|
||||
[[maybe_unused]] std::string str = color1.HexString();
|
||||
|
||||
frc::Color8Bit color2{255, 128, 64};
|
||||
EXPECT_EQ("#FF8040", color2.HexString());
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
// 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 <string>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "frc/util/Color.h"
|
||||
@@ -56,7 +58,12 @@ TEST(ColorTest, FromHSV) {
|
||||
}
|
||||
|
||||
TEST(ColorTest, ToHexString) {
|
||||
constexpr frc::Color color{255, 128, 64};
|
||||
constexpr frc::Color color1{255, 128, 64};
|
||||
EXPECT_EQ("#FF8040", color1.HexString());
|
||||
|
||||
EXPECT_EQ("#FF8040", color.HexString());
|
||||
// Ensure conversion to std::string works
|
||||
[[maybe_unused]] std::string str = color1.HexString();
|
||||
|
||||
frc::Color color2{255, 128, 64};
|
||||
EXPECT_EQ("#FF8040", color2.HexString());
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ struct ct_string {
|
||||
|
||||
template <size_t M>
|
||||
requires(M <= (N + 1))
|
||||
consteval ct_string(Char const (&s)[M]) { // NOLINT
|
||||
constexpr ct_string(Char const (&s)[M]) { // NOLINT
|
||||
if constexpr (M == (N + 1)) {
|
||||
if (s[N] != Char{}) {
|
||||
throw std::logic_error{"char array not null terminated"};
|
||||
@@ -50,7 +50,7 @@ struct ct_string {
|
||||
}
|
||||
}
|
||||
|
||||
explicit consteval ct_string(std::basic_string_view<Char, Traits> s) {
|
||||
explicit constexpr ct_string(std::basic_string_view<Char, Traits> s) {
|
||||
// avoid dependency on <algorithm>
|
||||
// auto p = std::ranges::copy(s, chars.begin()).out;
|
||||
auto p = chars.begin();
|
||||
@@ -63,6 +63,64 @@ struct ct_string {
|
||||
}
|
||||
}
|
||||
|
||||
constexpr bool operator==(const ct_string<Char, Traits, N>&) const = default;
|
||||
|
||||
constexpr bool operator==(const std::basic_string<Char, Traits>& rhs) const {
|
||||
if (size() != rhs.size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < size(); ++i) {
|
||||
if (chars[i] != rhs[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
constexpr bool operator==(std::basic_string_view<Char, Traits> rhs) const {
|
||||
if (size() != rhs.size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < size(); ++i) {
|
||||
if (chars[i] != rhs[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <size_t M>
|
||||
requires(N + 1 == M)
|
||||
constexpr bool operator==(Char const (&rhs)[M]) const {
|
||||
for (size_t i = 0; i < M; ++i) {
|
||||
if (chars[i] != rhs[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
constexpr bool operator==(const Char* rhs) const {
|
||||
for (size_t i = 0; i < N + 1; ++i) {
|
||||
if (chars[i] != rhs[i]) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If index of rhs's null terminator is less than lhs's size - 1, rhs is
|
||||
// shorter than lhs
|
||||
if (rhs[i] == '\0' && i < N) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
constexpr auto size() const noexcept { return N; }
|
||||
|
||||
constexpr auto begin() const noexcept { return chars.begin(); }
|
||||
@@ -71,6 +129,11 @@ struct ct_string {
|
||||
constexpr auto data() const noexcept { return chars.data(); }
|
||||
constexpr auto c_str() const noexcept { return chars.data(); }
|
||||
|
||||
constexpr operator std::basic_string<Char, Traits>() // NOLINT
|
||||
const noexcept {
|
||||
return std::basic_string<Char, Traits>{chars.data(), N};
|
||||
}
|
||||
|
||||
constexpr operator std::basic_string_view<Char, Traits>() // NOLINT
|
||||
const noexcept {
|
||||
return std::basic_string_view<Char, Traits>{chars.data(), N};
|
||||
@@ -82,13 +145,13 @@ ct_string(Char const (&s)[M]) -> ct_string<Char, std::char_traits<Char>, M - 1>;
|
||||
|
||||
inline namespace literals {
|
||||
template <ct_string S>
|
||||
consteval auto operator""_ct_string() {
|
||||
constexpr auto operator""_ct_string() {
|
||||
return S;
|
||||
}
|
||||
} // namespace literals
|
||||
|
||||
template <typename Char, typename Traits, size_t N1, size_t N2>
|
||||
consteval auto operator+(ct_string<Char, Traits, N1> const& s1,
|
||||
constexpr auto operator+(ct_string<Char, Traits, N1> const& s1,
|
||||
ct_string<Char, Traits, N2> const& s2) noexcept {
|
||||
return Concat(s1, s2);
|
||||
}
|
||||
@@ -102,7 +165,7 @@ consteval auto operator+(ct_string<Char, Traits, N1> const& s1,
|
||||
* @return concatenated string
|
||||
*/
|
||||
template <typename Char, typename Traits, size_t N1, size_t... N>
|
||||
consteval auto Concat(ct_string<Char, Traits, N1> const& s1,
|
||||
constexpr auto Concat(ct_string<Char, Traits, N1> const& s1,
|
||||
ct_string<Char, Traits, N> const&... s) {
|
||||
// Need a dummy array to instantiate a ct_string.
|
||||
constexpr Char dummy[1] = {};
|
||||
@@ -136,7 +199,7 @@ consteval auto Concat(ct_string<Char, Traits, N1> const& s1,
|
||||
template <intmax_t N, int Base = 10, typename Char = char,
|
||||
typename Traits = std::char_traits<Char>>
|
||||
requires(Base >= 2 && Base <= 36)
|
||||
consteval auto NumToCtString() {
|
||||
constexpr auto NumToCtString() {
|
||||
constexpr char digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
|
||||
auto buflen = [] {
|
||||
|
||||
Reference in New Issue
Block a user