Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[wpilib] Make Color::HexString() constexpr #5985

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 0 additions & 13 deletions wpilibc/src/main/native/cpp/util/Color.cpp

This file was deleted.

11 changes: 0 additions & 11 deletions wpilibc/src/main/native/cpp/util/Color8Bit.cpp

This file was deleted.

12 changes: 11 additions & 1 deletion wpilibc/src/main/native/include/frc/util/Color.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

#include <fmt/core.h>
#include <wpi/StringExtras.h>
#include <wpi/ct_string.h>

namespace frc {

Expand Down Expand Up @@ -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;
Expand Down
8 changes: 7 additions & 1 deletion wpilibc/src/main/native/include/frc/util/Color8Bit.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

#include <fmt/core.h>
#include <wpi/StringExtras.h>
#include <wpi/ct_string.h>

#include "Color.h"

Expand Down Expand Up @@ -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;
Expand Down
11 changes: 9 additions & 2 deletions wpilibc/src/test/native/cpp/util/Color8BitTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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());

// Ensure conversion to std::string works
[[maybe_unused]] std::string str = color1.HexString();

EXPECT_EQ("#FF8040", color.HexString());
frc::Color8Bit color2{255, 128, 64};
EXPECT_EQ("#FF8040", color2.HexString());
}
11 changes: 9 additions & 2 deletions wpilibc/src/test/native/cpp/util/ColorTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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());

// Ensure conversion to std::string works
[[maybe_unused]] std::string str = color1.HexString();

EXPECT_EQ("#FF8040", color.HexString());
frc::Color color2{255, 128, 64};
EXPECT_EQ("#FF8040", color2.HexString());
}
75 changes: 69 additions & 6 deletions wpiutil/src/main/native/include/wpi/ct_string.h
Original file line number Diff line number Diff line change
Expand Up @@ -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"};
Expand All @@ -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();
Expand All @@ -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 {
calcmogul marked this conversation as resolved.
Show resolved Hide resolved
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]) {
calcmogul marked this conversation as resolved.
Show resolved Hide resolved
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(); }
Expand All @@ -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};
Expand All @@ -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);
}
Expand All @@ -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] = {};
Expand Down Expand Up @@ -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 = [] {
Expand Down