From 72292ac7d302d7bfa54c639879da01ab02528dfd Mon Sep 17 00:00:00 2001 From: Sriman Achanta <68172138+srimanachanta@users.noreply.github.com> Date: Sun, 5 Feb 2023 17:09:32 -0500 Subject: [PATCH 01/10] added --- .../src/main/native/include/frc/util/Color.h | 18 ++++++++++++++++++ .../main/native/include/frc/util/Color8Bit.h | 18 ++++++++++++++++++ .../java/edu/wpi/first/wpilibj/util/Color.java | 16 ++++++++++++++++ .../edu/wpi/first/wpilibj/util/Color8Bit.java | 16 ++++++++++++++++ 4 files changed, 68 insertions(+) diff --git a/wpilibc/src/main/native/include/frc/util/Color.h b/wpilibc/src/main/native/include/frc/util/Color.h index 87d8c12f497..f7020814ac1 100644 --- a/wpilibc/src/main/native/include/frc/util/Color.h +++ b/wpilibc/src/main/native/include/frc/util/Color.h @@ -5,6 +5,7 @@ #pragma once #include +#include #include namespace frc { @@ -811,6 +812,23 @@ class Color { } } + /** + * Create a Color from a hex string. Throws an exception if the Hex String is + * invalid. + * + * @param hexString a string of the format #RRGGBB + * @return Color object from hex string. + */ + static constexpr Color FromHexString(std::string hexString) { + if (hexString.length() != 7 || !hexString.starts_with("#")) { + throw std::invalid_argument("Invalid Hex String for Color"); + } + + int r, g, b; + std::sscanf(hexString.c_str(), "#%02x%02x%02x", &r, &g, &b); + return Color(r / 255, g / 255, b / 255); + } + /** * Return this color represented as a hex string. * diff --git a/wpilibc/src/main/native/include/frc/util/Color8Bit.h b/wpilibc/src/main/native/include/frc/util/Color8Bit.h index 10afead93dc..2b7a57f408b 100644 --- a/wpilibc/src/main/native/include/frc/util/Color8Bit.h +++ b/wpilibc/src/main/native/include/frc/util/Color8Bit.h @@ -5,6 +5,7 @@ #pragma once #include +#include #include #include "Color.h" @@ -44,6 +45,23 @@ class Color8Bit { return Color(red / 255.0, green / 255.0, blue / 255.0); } + /** + * Create a Color8Bit from a hex string. Throws an exception if the Hex String + * is invalid. + * + * @param hexString a string of the format #RRGGBB + * @return Color8Bit object from hex string. + */ + static constexpr Color8Bit FromHexString(std::string hexString) { + if (hexString.length() != 7 || !hexString.starts_with("#")) { + throw std::invalid_argument("Invalid Hex String for Color"); + } + + int r, g, b; + std::sscanf(hexString.c_str(), "#%02x%02x%02x", &r, &g, &b); + return Color8Bit(r, g, b); + } + constexpr bool operator==(const Color8Bit&) const = default; /** diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/util/Color.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/util/Color.java index 2defbd8ad36..049b7e6e94e 100644 --- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/util/Color.java +++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/util/Color.java @@ -115,6 +115,22 @@ public static Color fromHSV(int h, int s, int v) { } } + /** + * Create a Color from a hex string. Throws an exception if the Hex String is invalid. + * + * @param hexString a string of the format #RRGGBB + * @return Color object from hex string. + */ + public static Color fromHexString(String hexString) { + if (hexString.length() != 7 || !hexString.startsWith("#")) + throw new IllegalArgumentException("Invalid Hex String"); + + return new Color( + Integer.valueOf(hexString.substring(1, 3), 16) / 255.0, + Integer.valueOf(hexString.substring(3, 5), 16) / 255.0, + Integer.valueOf(hexString.substring(5, 7), 16) / 255.0); + } + @Override public boolean equals(Object other) { if (this == other) { diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/util/Color8Bit.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/util/Color8Bit.java index 32606731006..4246a55d1c0 100644 --- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/util/Color8Bit.java +++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/util/Color8Bit.java @@ -36,6 +36,22 @@ public Color8Bit(Color color) { this((int) (color.red * 255), (int) (color.green * 255), (int) (color.blue * 255)); } + /** + * Create a Color8Bit from a hex string. Throws an exception if the Hex String is invalid. + * + * @param hexString a string of the format #RRGGBB + * @return Color8Bit object from hex string. + */ + public static Color8Bit fromHexString(String hexString) { + if (hexString.length() != 7 || !hexString.startsWith("#")) + throw new IllegalArgumentException("Invalid Hex String"); + + return new Color8Bit( + Integer.valueOf(hexString.substring(1, 3), 16), + Integer.valueOf(hexString.substring(3, 5), 16), + Integer.valueOf(hexString.substring(5, 7), 16)); + } + @Override public boolean equals(Object other) { if (this == other) { From 1ea9f33de850d83390673a990b8628af5725ced7 Mon Sep 17 00:00:00 2001 From: Sriman Achanta <68172138+srimanachanta@users.noreply.github.com> Date: Sun, 5 Feb 2023 17:15:33 -0500 Subject: [PATCH 02/10] Fix documentation --- wpilibc/src/main/native/include/frc/util/Color.h | 2 +- wpilibc/src/main/native/include/frc/util/Color8Bit.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/wpilibc/src/main/native/include/frc/util/Color.h b/wpilibc/src/main/native/include/frc/util/Color.h index f7020814ac1..c18493ae688 100644 --- a/wpilibc/src/main/native/include/frc/util/Color.h +++ b/wpilibc/src/main/native/include/frc/util/Color.h @@ -816,7 +816,7 @@ class Color { * Create a Color from a hex string. Throws an exception if the Hex String is * invalid. * - * @param hexString a string of the format #RRGGBB + * @param hexString a string of the format \#RRGGBB * @return Color object from hex string. */ static constexpr Color FromHexString(std::string hexString) { diff --git a/wpilibc/src/main/native/include/frc/util/Color8Bit.h b/wpilibc/src/main/native/include/frc/util/Color8Bit.h index 2b7a57f408b..f1de75e1328 100644 --- a/wpilibc/src/main/native/include/frc/util/Color8Bit.h +++ b/wpilibc/src/main/native/include/frc/util/Color8Bit.h @@ -49,7 +49,7 @@ class Color8Bit { * Create a Color8Bit from a hex string. Throws an exception if the Hex String * is invalid. * - * @param hexString a string of the format #RRGGBB + * @param hexString a string of the format \#RRGGBB * @return Color8Bit object from hex string. */ static constexpr Color8Bit FromHexString(std::string hexString) { From e259f59fb5e235fe394fd6853cfcc66a37426b85 Mon Sep 17 00:00:00 2001 From: Tyler Veness Date: Thu, 30 Nov 2023 23:06:48 -0800 Subject: [PATCH 03/10] Address review comments for Color classes --- .../src/main/native/include/frc/util/Color.h | 30 +++++++++++++------ .../main/native/include/frc/util/Color8Bit.h | 28 ++++++++++++----- .../edu/wpi/first/wpilibj/util/Color.java | 14 +++++---- .../edu/wpi/first/wpilibj/util/Color8Bit.java | 8 +++-- 4 files changed, 54 insertions(+), 26 deletions(-) diff --git a/wpilibc/src/main/native/include/frc/util/Color.h b/wpilibc/src/main/native/include/frc/util/Color.h index c18493ae688..44f8f42c325 100644 --- a/wpilibc/src/main/native/include/frc/util/Color.h +++ b/wpilibc/src/main/native/include/frc/util/Color.h @@ -7,6 +7,10 @@ #include #include #include +#include + +#include +#include namespace frc { @@ -813,20 +817,28 @@ class Color { } /** - * Create a Color from a hex string. Throws an exception if the Hex String is - * invalid. + * Create a Color from a hex string. * * @param hexString a string of the format \#RRGGBB * @return Color object from hex string. - */ - static constexpr Color FromHexString(std::string hexString) { - if (hexString.length() != 7 || !hexString.starts_with("#")) { - throw std::invalid_argument("Invalid Hex String for Color"); + * @throws std::invalid_argument if the hex string is invalid. + */ + static constexpr Color FromHexString(std::string_view hexString) { + if (hexString.length() != 7 || !hexString.starts_with("#") || + !wpi::isHexDigit(hexString[1]) || !wpi::isHexDigit(hexString[2]) || + !wpi::isHexDigit(hexString[3]) || !wpi::isHexDigit(hexString[4]) || + !wpi::isHexDigit(hexString[5]) || !wpi::isHexDigit(hexString[6])) { + throw std::invalid_argument( + fmt::format("Invalid hex string for Color \"{}\"", hexString)); } - int r, g, b; - std::sscanf(hexString.c_str(), "#%02x%02x%02x", &r, &g, &b); - return Color(r / 255, g / 255, b / 255); + int r = wpi::hexDigitValue(hexString[0]) * 16 + + wpi::hexDigitValue(hexString[1]); + int g = wpi::hexDigitValue(hexString[2]) * 16 + + wpi::hexDigitValue(hexString[3]); + int b = wpi::hexDigitValue(hexString[4]) * 16 + + wpi::hexDigitValue(hexString[5]); + return Color{r, g, b}; } /** diff --git a/wpilibc/src/main/native/include/frc/util/Color8Bit.h b/wpilibc/src/main/native/include/frc/util/Color8Bit.h index f1de75e1328..65aa7c557c4 100644 --- a/wpilibc/src/main/native/include/frc/util/Color8Bit.h +++ b/wpilibc/src/main/native/include/frc/util/Color8Bit.h @@ -7,6 +7,10 @@ #include #include #include +#include + +#include +#include #include "Color.h" @@ -46,20 +50,28 @@ class Color8Bit { } /** - * Create a Color8Bit from a hex string. Throws an exception if the Hex String - * is invalid. + * Create a Color8Bit from a hex string. * * @param hexString a string of the format \#RRGGBB * @return Color8Bit object from hex string. + * @throws std::invalid_argument if the hex string is invalid. */ - static constexpr Color8Bit FromHexString(std::string hexString) { - if (hexString.length() != 7 || !hexString.starts_with("#")) { - throw std::invalid_argument("Invalid Hex String for Color"); + static constexpr Color8Bit FromHexString(std::string_view hexString) { + if (hexString.length() != 7 || !hexString.starts_with("#") || + !wpi::isHexDigit(hexString[1]) || !wpi::isHexDigit(hexString[2]) || + !wpi::isHexDigit(hexString[3]) || !wpi::isHexDigit(hexString[4]) || + !wpi::isHexDigit(hexString[5]) || !wpi::isHexDigit(hexString[6])) { + throw std::invalid_argument( + fmt::format("Invalid hex string for Color \"{}\"", hexString)); } - int r, g, b; - std::sscanf(hexString.c_str(), "#%02x%02x%02x", &r, &g, &b); - return Color8Bit(r, g, b); + int r = wpi::hexDigitValue(hexString[0]) * 16 + + wpi::hexDigitValue(hexString[1]); + int g = wpi::hexDigitValue(hexString[2]) * 16 + + wpi::hexDigitValue(hexString[3]); + int b = wpi::hexDigitValue(hexString[4]) * 16 + + wpi::hexDigitValue(hexString[5]); + return Color8Bit{r, g, b}; } constexpr bool operator==(const Color8Bit&) const = default; diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/util/Color.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/util/Color.java index 049b7e6e94e..98b8da63bff 100644 --- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/util/Color.java +++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/util/Color.java @@ -116,19 +116,21 @@ public static Color fromHSV(int h, int s, int v) { } /** - * Create a Color from a hex string. Throws an exception if the Hex String is invalid. + * Create a Color from a hex string. * * @param hexString a string of the format #RRGGBB * @return Color object from hex string. + * @throws IllegalArgumentException if the hex string is invalid. */ public static Color fromHexString(String hexString) { - if (hexString.length() != 7 || !hexString.startsWith("#")) - throw new IllegalArgumentException("Invalid Hex String"); + if (hexString.length() != 7 || !hexString.startsWith("#")) { + throw new IllegalArgumentException("Invalid hex string \"" + hexString + "\""); + } return new Color( - Integer.valueOf(hexString.substring(1, 3), 16) / 255.0, - Integer.valueOf(hexString.substring(3, 5), 16) / 255.0, - Integer.valueOf(hexString.substring(5, 7), 16) / 255.0); + Integer.valueOf(hexString.substring(1, 3), 16), + Integer.valueOf(hexString.substring(3, 5), 16), + Integer.valueOf(hexString.substring(5, 7), 16)); } @Override diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/util/Color8Bit.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/util/Color8Bit.java index 4246a55d1c0..8e018ad5e4a 100644 --- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/util/Color8Bit.java +++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/util/Color8Bit.java @@ -37,14 +37,16 @@ public Color8Bit(Color color) { } /** - * Create a Color8Bit from a hex string. Throws an exception if the Hex String is invalid. + * Create a Color8Bit from a hex string. * * @param hexString a string of the format #RRGGBB * @return Color8Bit object from hex string. + * @throws IllegalArgumentException if the hex string is invalid. */ public static Color8Bit fromHexString(String hexString) { - if (hexString.length() != 7 || !hexString.startsWith("#")) - throw new IllegalArgumentException("Invalid Hex String"); + if (hexString.length() != 7 || !hexString.startsWith("#")) { + throw new IllegalArgumentException("Invalid hex string \"" + hexString + "\""); + } return new Color8Bit( Integer.valueOf(hexString.substring(1, 3), 16), From b26bd0ca4b344223def7c8e590b8dfab341faf7d Mon Sep 17 00:00:00 2001 From: Tyler Veness Date: Fri, 1 Dec 2023 00:02:04 -0800 Subject: [PATCH 04/10] Make hex string conversion constexpr and add test stubs --- wpilibc/src/main/native/cpp/util/Color.cpp | 15 ----------- .../src/main/native/cpp/util/Color8Bit.cpp | 13 --------- .../src/main/native/include/frc/util/Color.h | 22 ++++++++++++++- .../main/native/include/frc/util/Color8Bit.h | 22 ++++++++++++--- .../test/native/cpp/util/Color8BitTest.cpp | 19 +++++++++++++ .../src/test/native/cpp/util/ColorTest.cpp | 19 +++++++++++++ .../wpi/first/wpilibj/util/Color8BitTest.java | 24 +++++++++++++++++ .../edu/wpi/first/wpilibj/util/ColorTest.java | 27 +++++++++++++++++++ 8 files changed, 129 insertions(+), 32 deletions(-) delete mode 100644 wpilibc/src/main/native/cpp/util/Color.cpp delete mode 100644 wpilibc/src/main/native/cpp/util/Color8Bit.cpp create mode 100644 wpilibc/src/test/native/cpp/util/Color8BitTest.cpp create mode 100644 wpilibc/src/test/native/cpp/util/ColorTest.cpp create mode 100644 wpilibj/src/test/java/edu/wpi/first/wpilibj/util/Color8BitTest.java create mode 100644 wpilibj/src/test/java/edu/wpi/first/wpilibj/util/ColorTest.java diff --git a/wpilibc/src/main/native/cpp/util/Color.cpp b/wpilibc/src/main/native/cpp/util/Color.cpp deleted file mode 100644 index e3adaf2db3f..00000000000 --- a/wpilibc/src/main/native/cpp/util/Color.cpp +++ /dev/null @@ -1,15 +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" - -#include - -using namespace frc; - -std::string Color::HexString() const { - return fmt::format("#{:02X}{:02X}{:02X}", static_cast(255.0 * red), - static_cast(255.0 * green), - static_cast(255.0 * blue)); -} diff --git a/wpilibc/src/main/native/cpp/util/Color8Bit.cpp b/wpilibc/src/main/native/cpp/util/Color8Bit.cpp deleted file mode 100644 index af200a294b5..00000000000 --- a/wpilibc/src/main/native/cpp/util/Color8Bit.cpp +++ /dev/null @@ -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/Color8Bit.h" - -#include - -using namespace frc; - -std::string Color8Bit::HexString() const { - return fmt::format("#{:02X}{:02X}{:02X}", red, green, blue); -} diff --git a/wpilibc/src/main/native/include/frc/util/Color.h b/wpilibc/src/main/native/include/frc/util/Color.h index 44f8f42c325..b51e462d405 100644 --- a/wpilibc/src/main/native/include/frc/util/Color.h +++ b/wpilibc/src/main/native/include/frc/util/Color.h @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -846,7 +847,26 @@ class Color { * * @return a string of the format \#RRGGBB */ - std::string HexString() const; + constexpr std::string HexString() const { + int r = static_cast(255.0 * red); + int g = static_cast(255.0 * green); + int b = static_cast(255.0 * blue); + + if (std::is_constant_evaluated()) { + std::string str = "#"; + + str += wpi::hexdigit(r / 16); + str += wpi::hexdigit(r % 16); + str += wpi::hexdigit(g / 16); + str += wpi::hexdigit(g % 16); + str += wpi::hexdigit(b / 16); + str += wpi::hexdigit(b % 16); + + return str; + } else { + return fmt::format("#{:02X}{:02X}{:02X}", r, g, b); + } + } double red = 0.0; double green = 0.0; diff --git a/wpilibc/src/main/native/include/frc/util/Color8Bit.h b/wpilibc/src/main/native/include/frc/util/Color8Bit.h index 65aa7c557c4..520969e7799 100644 --- a/wpilibc/src/main/native/include/frc/util/Color8Bit.h +++ b/wpilibc/src/main/native/include/frc/util/Color8Bit.h @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -45,6 +46,8 @@ class Color8Bit { green(color.green * 255), blue(color.blue * 255) {} + constexpr bool operator==(const Color8Bit&) const = default; + constexpr operator Color() const { // NOLINT return Color(red / 255.0, green / 255.0, blue / 255.0); } @@ -74,14 +77,27 @@ class Color8Bit { return Color8Bit{r, g, b}; } - constexpr bool operator==(const Color8Bit&) const = default; - /** * Return this color represented as a hex string. * * @return a string of the format \#RRGGBB */ - std::string HexString() const; + constexpr std::string HexString() const { + if (std::is_constant_evaluated()) { + std::string str = "#"; + + str += wpi::hexdigit(red / 16); + str += wpi::hexdigit(red % 16); + str += wpi::hexdigit(green / 16); + str += wpi::hexdigit(green % 16); + str += wpi::hexdigit(blue / 16); + str += wpi::hexdigit(blue % 16); + + return str; + } else { + return fmt::format("#{:02X}{:02X}{:02X}", red, green, blue); + } + } int red = 0; int green = 0; diff --git a/wpilibc/src/test/native/cpp/util/Color8BitTest.cpp b/wpilibc/src/test/native/cpp/util/Color8BitTest.cpp new file mode 100644 index 00000000000..bb59eb54b6b --- /dev/null +++ b/wpilibc/src/test/native/cpp/util/Color8BitTest.cpp @@ -0,0 +1,19 @@ +// 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 "frc/util/Color8Bit.h" + +TEST(Color8BitTest, ConstructDefault) {} + +TEST(Color8BitTest, ConstructFromInts) {} + +TEST(Color8BitTest, ConstructFromColor) {} + +TEST(Color8BitTest, ImplicitConversionToColor) {} + +TEST(Color8BitTest, FromHexString) {} + +TEST(Color8BitTest, HexString) {} diff --git a/wpilibc/src/test/native/cpp/util/ColorTest.cpp b/wpilibc/src/test/native/cpp/util/ColorTest.cpp new file mode 100644 index 00000000000..b01ef7dc620 --- /dev/null +++ b/wpilibc/src/test/native/cpp/util/ColorTest.cpp @@ -0,0 +1,19 @@ +// 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 "frc/util/Color.h" + +TEST(ColorTest, ConstructDefault) {} + +TEST(ColorTest, ConstructFromDoubles) {} + +TEST(ColorTest, ConstructFromInts) {} + +TEST(ColorTest, FromHSV) {} + +TEST(ColorTest, FromHexString) {} + +TEST(ColorTest, HexString) {} diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/util/Color8BitTest.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/util/Color8BitTest.java new file mode 100644 index 00000000000..9b9d44d078c --- /dev/null +++ b/wpilibj/src/test/java/edu/wpi/first/wpilibj/util/Color8BitTest.java @@ -0,0 +1,24 @@ +// 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. + +package edu.wpi.first.wpilibj; + +import org.junit.jupiter.api.Test; + +class Color8BitTest { + @Test + void testConstructDefault() {} + + @Test + void testConstructFromInts() {} + + @Test + void testConstructFromColor() {} + + @Test + void testFromHexString() {} + + @Test + void testHexString() {} +} diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/util/ColorTest.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/util/ColorTest.java new file mode 100644 index 00000000000..2d9f899a82a --- /dev/null +++ b/wpilibj/src/test/java/edu/wpi/first/wpilibj/util/ColorTest.java @@ -0,0 +1,27 @@ +// 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. + +package edu.wpi.first.wpilibj; + +import org.junit.jupiter.api.Test; + +class ColorTest { + @Test + void testConstructDefault() {} + + @Test + void testConstructFromDoubles() {} + + @Test + void testConstructFromInts() {} + + @Test + void testFromHSV() {} + + @Test + void testFromHexString() {} + + @Test + void testHexString() {} +} From 3fbcb9cad71442960333570e3c695253973818ee Mon Sep 17 00:00:00 2001 From: Tyler Veness Date: Fri, 1 Dec 2023 00:08:17 -0800 Subject: [PATCH 05/10] Fix test package --- .../src/test/java/edu/wpi/first/wpilibj/util/Color8BitTest.java | 2 +- wpilibj/src/test/java/edu/wpi/first/wpilibj/util/ColorTest.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/util/Color8BitTest.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/util/Color8BitTest.java index 9b9d44d078c..c9badc093d9 100644 --- a/wpilibj/src/test/java/edu/wpi/first/wpilibj/util/Color8BitTest.java +++ b/wpilibj/src/test/java/edu/wpi/first/wpilibj/util/Color8BitTest.java @@ -2,7 +2,7 @@ // 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. -package edu.wpi.first.wpilibj; +package edu.wpi.first.wpilibj.util; import org.junit.jupiter.api.Test; diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/util/ColorTest.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/util/ColorTest.java index 2d9f899a82a..901b6483ff1 100644 --- a/wpilibj/src/test/java/edu/wpi/first/wpilibj/util/ColorTest.java +++ b/wpilibj/src/test/java/edu/wpi/first/wpilibj/util/ColorTest.java @@ -2,7 +2,7 @@ // 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. -package edu.wpi.first.wpilibj; +package edu.wpi.first.wpilibj.util; import org.junit.jupiter.api.Test; From b572e4bb98e7bfbc9a00c7cffb051975dbdbe98a Mon Sep 17 00:00:00 2001 From: Tyler Veness Date: Fri, 1 Dec 2023 00:17:26 -0800 Subject: [PATCH 06/10] Make hex string factory a constructor --- .../src/main/native/include/frc/util/Color.h | 52 ++++++++++--------- .../main/native/include/frc/util/Color8Bit.h | 23 ++++++++ .../test/native/cpp/util/Color8BitTest.cpp | 4 +- .../src/test/native/cpp/util/ColorTest.cpp | 4 +- .../edu/wpi/first/wpilibj/util/Color.java | 34 ++++++------ .../edu/wpi/first/wpilibj/util/Color8Bit.java | 12 ++--- .../wpi/first/wpilibj/util/Color8BitTest.java | 2 +- .../edu/wpi/first/wpilibj/util/ColorTest.java | 4 +- 8 files changed, 78 insertions(+), 57 deletions(-) diff --git a/wpilibc/src/main/native/include/frc/util/Color.h b/wpilibc/src/main/native/include/frc/util/Color.h index b51e462d405..dcd8489fc04 100644 --- a/wpilibc/src/main/native/include/frc/util/Color.h +++ b/wpilibc/src/main/native/include/frc/util/Color.h @@ -769,6 +769,33 @@ class Color { constexpr Color(int r, int g, int b) : Color(r / 255.0, g / 255.0, b / 255.0) {} + /** + * Constructs a Color from a hex string. + * + * @param hexString a string of the format \#RRGGBB + * @throws std::invalid_argument if the hex string is invalid. + */ + explicit constexpr Color(std::string_view hexString) { + if (hexString.length() != 7 || !hexString.starts_with("#") || + !wpi::isHexDigit(hexString[1]) || !wpi::isHexDigit(hexString[2]) || + !wpi::isHexDigit(hexString[3]) || !wpi::isHexDigit(hexString[4]) || + !wpi::isHexDigit(hexString[5]) || !wpi::isHexDigit(hexString[6])) { + throw std::invalid_argument( + fmt::format("Invalid hex string for Color \"{}\"", hexString)); + } + + int r = wpi::hexDigitValue(hexString[0]) * 16 + + wpi::hexDigitValue(hexString[1]); + int g = wpi::hexDigitValue(hexString[2]) * 16 + + wpi::hexDigitValue(hexString[3]); + int b = wpi::hexDigitValue(hexString[4]) * 16 + + wpi::hexDigitValue(hexString[5]); + + red = r / 255.0; + green = g / 255.0; + blue = b / 255.0; + } + constexpr bool operator==(const Color&) const = default; /** @@ -817,31 +844,6 @@ class Color { } } - /** - * Create a Color from a hex string. - * - * @param hexString a string of the format \#RRGGBB - * @return Color object from hex string. - * @throws std::invalid_argument if the hex string is invalid. - */ - static constexpr Color FromHexString(std::string_view hexString) { - if (hexString.length() != 7 || !hexString.starts_with("#") || - !wpi::isHexDigit(hexString[1]) || !wpi::isHexDigit(hexString[2]) || - !wpi::isHexDigit(hexString[3]) || !wpi::isHexDigit(hexString[4]) || - !wpi::isHexDigit(hexString[5]) || !wpi::isHexDigit(hexString[6])) { - throw std::invalid_argument( - fmt::format("Invalid hex string for Color \"{}\"", hexString)); - } - - int r = wpi::hexDigitValue(hexString[0]) * 16 + - wpi::hexDigitValue(hexString[1]); - int g = wpi::hexDigitValue(hexString[2]) * 16 + - wpi::hexDigitValue(hexString[3]); - int b = wpi::hexDigitValue(hexString[4]) * 16 + - wpi::hexDigitValue(hexString[5]); - return Color{r, g, b}; - } - /** * Return this color represented as a hex string. * diff --git a/wpilibc/src/main/native/include/frc/util/Color8Bit.h b/wpilibc/src/main/native/include/frc/util/Color8Bit.h index 520969e7799..d41a113dc64 100644 --- a/wpilibc/src/main/native/include/frc/util/Color8Bit.h +++ b/wpilibc/src/main/native/include/frc/util/Color8Bit.h @@ -46,6 +46,29 @@ class Color8Bit { green(color.green * 255), blue(color.blue * 255) {} + /** + * Constructs a Color8Bit from a hex string. + * + * @param hexString a string of the format \#RRGGBB + * @throws std::invalid_argument if the hex string is invalid. + */ + explicit constexpr Color8Bit(std::string_view hexString) { + if (hexString.length() != 7 || !hexString.starts_with("#") || + !wpi::isHexDigit(hexString[1]) || !wpi::isHexDigit(hexString[2]) || + !wpi::isHexDigit(hexString[3]) || !wpi::isHexDigit(hexString[4]) || + !wpi::isHexDigit(hexString[5]) || !wpi::isHexDigit(hexString[6])) { + throw std::invalid_argument( + fmt::format("Invalid hex string for Color \"{}\"", hexString)); + } + + red = wpi::hexDigitValue(hexString[0]) * 16 + + wpi::hexDigitValue(hexString[1]); + green = wpi::hexDigitValue(hexString[2]) * 16 + + wpi::hexDigitValue(hexString[3]); + blue = wpi::hexDigitValue(hexString[4]) * 16 + + wpi::hexDigitValue(hexString[5]); + } + constexpr bool operator==(const Color8Bit&) const = default; constexpr operator Color() const { // NOLINT diff --git a/wpilibc/src/test/native/cpp/util/Color8BitTest.cpp b/wpilibc/src/test/native/cpp/util/Color8BitTest.cpp index bb59eb54b6b..544a8a1dbbb 100644 --- a/wpilibc/src/test/native/cpp/util/Color8BitTest.cpp +++ b/wpilibc/src/test/native/cpp/util/Color8BitTest.cpp @@ -12,8 +12,8 @@ TEST(Color8BitTest, ConstructFromInts) {} TEST(Color8BitTest, ConstructFromColor) {} -TEST(Color8BitTest, ImplicitConversionToColor) {} +TEST(Color8BitTest, ConstructFromHexString) {} -TEST(Color8BitTest, FromHexString) {} +TEST(Color8BitTest, ImplicitConversionToColor) {} TEST(Color8BitTest, HexString) {} diff --git a/wpilibc/src/test/native/cpp/util/ColorTest.cpp b/wpilibc/src/test/native/cpp/util/ColorTest.cpp index b01ef7dc620..675cf13626b 100644 --- a/wpilibc/src/test/native/cpp/util/ColorTest.cpp +++ b/wpilibc/src/test/native/cpp/util/ColorTest.cpp @@ -12,8 +12,8 @@ TEST(ColorTest, ConstructFromDoubles) {} TEST(ColorTest, ConstructFromInts) {} -TEST(ColorTest, FromHSV) {} +TEST(ColorTest, ConstructFromHexString) {} -TEST(ColorTest, FromHexString) {} +TEST(ColorTest, FromHSV) {} TEST(ColorTest, HexString) {} diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/util/Color.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/util/Color.java index 98b8da63bff..c9787325fa8 100644 --- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/util/Color.java +++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/util/Color.java @@ -69,6 +69,22 @@ private Color(double red, double green, double blue, String name) { this.m_name = name; } + /** + * Constructs a Color from a hex string. + * + * @param hexString a string of the format #RRGGBB + * @throws IllegalArgumentException if the hex string is invalid. + */ + public Color(String hexString) { + if (hexString.length() != 7 || !hexString.startsWith("#")) { + throw new IllegalArgumentException("Invalid hex string \"" + hexString + "\""); + } + + this.red = Integer.valueOf(hexString.substring(1, 3), 16) / 255.0; + this.green = Integer.valueOf(hexString.substring(3, 5), 16) / 255.0; + this.blue = Integer.valueOf(hexString.substring(5, 7), 16) / 255.0; + } + /** * Creates a Color from HSV values. * @@ -115,24 +131,6 @@ public static Color fromHSV(int h, int s, int v) { } } - /** - * Create a Color from a hex string. - * - * @param hexString a string of the format #RRGGBB - * @return Color object from hex string. - * @throws IllegalArgumentException if the hex string is invalid. - */ - public static Color fromHexString(String hexString) { - if (hexString.length() != 7 || !hexString.startsWith("#")) { - throw new IllegalArgumentException("Invalid hex string \"" + hexString + "\""); - } - - return new Color( - Integer.valueOf(hexString.substring(1, 3), 16), - Integer.valueOf(hexString.substring(3, 5), 16), - Integer.valueOf(hexString.substring(5, 7), 16)); - } - @Override public boolean equals(Object other) { if (this == other) { diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/util/Color8Bit.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/util/Color8Bit.java index 8e018ad5e4a..e9e0e8880b3 100644 --- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/util/Color8Bit.java +++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/util/Color8Bit.java @@ -37,21 +37,19 @@ public Color8Bit(Color color) { } /** - * Create a Color8Bit from a hex string. + * Constructs a Color8Bit from a hex string. * * @param hexString a string of the format #RRGGBB - * @return Color8Bit object from hex string. * @throws IllegalArgumentException if the hex string is invalid. */ - public static Color8Bit fromHexString(String hexString) { + public Color8Bit(String hexString) { if (hexString.length() != 7 || !hexString.startsWith("#")) { throw new IllegalArgumentException("Invalid hex string \"" + hexString + "\""); } - return new Color8Bit( - Integer.valueOf(hexString.substring(1, 3), 16), - Integer.valueOf(hexString.substring(3, 5), 16), - Integer.valueOf(hexString.substring(5, 7), 16)); + this.red = Integer.valueOf(hexString.substring(1, 3), 16); + this.green = Integer.valueOf(hexString.substring(3, 5), 16); + this.blue = Integer.valueOf(hexString.substring(5, 7), 16); } @Override diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/util/Color8BitTest.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/util/Color8BitTest.java index c9badc093d9..16c66c07367 100644 --- a/wpilibj/src/test/java/edu/wpi/first/wpilibj/util/Color8BitTest.java +++ b/wpilibj/src/test/java/edu/wpi/first/wpilibj/util/Color8BitTest.java @@ -17,7 +17,7 @@ void testConstructFromInts() {} void testConstructFromColor() {} @Test - void testFromHexString() {} + void testConstructFromHexString() {} @Test void testHexString() {} diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/util/ColorTest.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/util/ColorTest.java index 901b6483ff1..f2a8b30978a 100644 --- a/wpilibj/src/test/java/edu/wpi/first/wpilibj/util/ColorTest.java +++ b/wpilibj/src/test/java/edu/wpi/first/wpilibj/util/ColorTest.java @@ -17,10 +17,10 @@ void testConstructFromDoubles() {} void testConstructFromInts() {} @Test - void testFromHSV() {} + void testConstructFromHexString() {} @Test - void testFromHexString() {} + void testFromHSV() {} @Test void testHexString() {} From e2dcdcd2ca1e1eadb5c3114d7a14ab29f5315046 Mon Sep 17 00:00:00 2001 From: Tyler Veness Date: Fri, 1 Dec 2023 00:20:09 -0800 Subject: [PATCH 07/10] Rename tests --- wpilibc/src/test/native/cpp/util/Color8BitTest.cpp | 2 +- wpilibc/src/test/native/cpp/util/ColorTest.cpp | 2 +- .../src/test/java/edu/wpi/first/wpilibj/util/Color8BitTest.java | 2 +- wpilibj/src/test/java/edu/wpi/first/wpilibj/util/ColorTest.java | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/wpilibc/src/test/native/cpp/util/Color8BitTest.cpp b/wpilibc/src/test/native/cpp/util/Color8BitTest.cpp index 544a8a1dbbb..69e36fbe4f0 100644 --- a/wpilibc/src/test/native/cpp/util/Color8BitTest.cpp +++ b/wpilibc/src/test/native/cpp/util/Color8BitTest.cpp @@ -16,4 +16,4 @@ TEST(Color8BitTest, ConstructFromHexString) {} TEST(Color8BitTest, ImplicitConversionToColor) {} -TEST(Color8BitTest, HexString) {} +TEST(Color8BitTest, ToHexString) {} diff --git a/wpilibc/src/test/native/cpp/util/ColorTest.cpp b/wpilibc/src/test/native/cpp/util/ColorTest.cpp index 675cf13626b..9b9eea7e078 100644 --- a/wpilibc/src/test/native/cpp/util/ColorTest.cpp +++ b/wpilibc/src/test/native/cpp/util/ColorTest.cpp @@ -16,4 +16,4 @@ TEST(ColorTest, ConstructFromHexString) {} TEST(ColorTest, FromHSV) {} -TEST(ColorTest, HexString) {} +TEST(ColorTest, ToHexString) {} diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/util/Color8BitTest.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/util/Color8BitTest.java index 16c66c07367..42abf020d76 100644 --- a/wpilibj/src/test/java/edu/wpi/first/wpilibj/util/Color8BitTest.java +++ b/wpilibj/src/test/java/edu/wpi/first/wpilibj/util/Color8BitTest.java @@ -20,5 +20,5 @@ void testConstructFromColor() {} void testConstructFromHexString() {} @Test - void testHexString() {} + void testToHexString() {} } diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/util/ColorTest.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/util/ColorTest.java index f2a8b30978a..fdd8fbd6870 100644 --- a/wpilibj/src/test/java/edu/wpi/first/wpilibj/util/ColorTest.java +++ b/wpilibj/src/test/java/edu/wpi/first/wpilibj/util/ColorTest.java @@ -23,5 +23,5 @@ void testConstructFromHexString() {} void testFromHSV() {} @Test - void testHexString() {} + void testToHexString() {} } From fc3cbe307bdf0033ae1d3f797f3a8fcfb3f94eab Mon Sep 17 00:00:00 2001 From: Tyler Veness Date: Fri, 1 Dec 2023 08:45:57 -0800 Subject: [PATCH 08/10] Make HexString() not constexpr --- .../src/main/native/include/frc/util/Color.h | 24 ++++--------------- .../main/native/include/frc/util/Color8Bit.h | 18 ++------------ 2 files changed, 6 insertions(+), 36 deletions(-) diff --git a/wpilibc/src/main/native/include/frc/util/Color.h b/wpilibc/src/main/native/include/frc/util/Color.h index dcd8489fc04..e9d7a53070e 100644 --- a/wpilibc/src/main/native/include/frc/util/Color.h +++ b/wpilibc/src/main/native/include/frc/util/Color.h @@ -8,7 +8,6 @@ #include #include #include -#include #include #include @@ -849,25 +848,10 @@ class Color { * * @return a string of the format \#RRGGBB */ - constexpr std::string HexString() const { - int r = static_cast(255.0 * red); - int g = static_cast(255.0 * green); - int b = static_cast(255.0 * blue); - - if (std::is_constant_evaluated()) { - std::string str = "#"; - - str += wpi::hexdigit(r / 16); - str += wpi::hexdigit(r % 16); - str += wpi::hexdigit(g / 16); - str += wpi::hexdigit(g % 16); - str += wpi::hexdigit(b / 16); - str += wpi::hexdigit(b % 16); - - return str; - } else { - return fmt::format("#{:02X}{:02X}{:02X}", r, g, b); - } + std::string HexString() const { + return fmt::format("#{:02X}{:02X}{:02X}", static_cast(255.0 * red), + static_cast(255.0 * green), + static_cast(255.0 * blue)); } double red = 0.0; diff --git a/wpilibc/src/main/native/include/frc/util/Color8Bit.h b/wpilibc/src/main/native/include/frc/util/Color8Bit.h index d41a113dc64..5ea92e29806 100644 --- a/wpilibc/src/main/native/include/frc/util/Color8Bit.h +++ b/wpilibc/src/main/native/include/frc/util/Color8Bit.h @@ -8,7 +8,6 @@ #include #include #include -#include #include #include @@ -105,21 +104,8 @@ class Color8Bit { * * @return a string of the format \#RRGGBB */ - constexpr std::string HexString() const { - if (std::is_constant_evaluated()) { - std::string str = "#"; - - str += wpi::hexdigit(red / 16); - str += wpi::hexdigit(red % 16); - str += wpi::hexdigit(green / 16); - str += wpi::hexdigit(green % 16); - str += wpi::hexdigit(blue / 16); - str += wpi::hexdigit(blue % 16); - - return str; - } else { - return fmt::format("#{:02X}{:02X}{:02X}", red, green, blue); - } + std::string HexString() const { + return fmt::format("#{:02X}{:02X}{:02X}", red, green, blue); } int red = 0; From 8f68b66bb9974af38a633050ea0fcbce2c52b7c5 Mon Sep 17 00:00:00 2001 From: Tyler Veness Date: Fri, 1 Dec 2023 09:33:54 -0800 Subject: [PATCH 09/10] Add tests --- .../src/main/native/include/frc/util/Color.h | 15 +++-- .../main/native/include/frc/util/Color8Bit.h | 15 +++-- .../test/native/cpp/util/Color8BitTest.cpp | 55 +++++++++++++++-- .../src/test/native/cpp/util/ColorTest.cpp | 55 +++++++++++++++-- .../edu/wpi/first/wpilibj/util/Color.java | 7 +++ .../edu/wpi/first/wpilibj/util/Color8Bit.java | 7 +++ .../wpi/first/wpilibj/util/Color8BitTest.java | 51 ++++++++++++++-- .../edu/wpi/first/wpilibj/util/ColorTest.java | 59 +++++++++++++++++-- 8 files changed, 229 insertions(+), 35 deletions(-) diff --git a/wpilibc/src/main/native/include/frc/util/Color.h b/wpilibc/src/main/native/include/frc/util/Color.h index e9d7a53070e..3e4567373d7 100644 --- a/wpilibc/src/main/native/include/frc/util/Color.h +++ b/wpilibc/src/main/native/include/frc/util/Color.h @@ -744,6 +744,9 @@ class Color { */ static const Color kYellowGreen; + /** + * Constructs a default color (black). + */ constexpr Color() = default; /** @@ -783,12 +786,12 @@ class Color { fmt::format("Invalid hex string for Color \"{}\"", hexString)); } - int r = wpi::hexDigitValue(hexString[0]) * 16 + - wpi::hexDigitValue(hexString[1]); - int g = wpi::hexDigitValue(hexString[2]) * 16 + - wpi::hexDigitValue(hexString[3]); - int b = wpi::hexDigitValue(hexString[4]) * 16 + - wpi::hexDigitValue(hexString[5]); + int r = wpi::hexDigitValue(hexString[1]) * 16 + + wpi::hexDigitValue(hexString[2]); + int g = wpi::hexDigitValue(hexString[3]) * 16 + + wpi::hexDigitValue(hexString[4]); + int b = wpi::hexDigitValue(hexString[5]) * 16 + + wpi::hexDigitValue(hexString[6]); red = r / 255.0; green = g / 255.0; diff --git a/wpilibc/src/main/native/include/frc/util/Color8Bit.h b/wpilibc/src/main/native/include/frc/util/Color8Bit.h index 5ea92e29806..559559bcd14 100644 --- a/wpilibc/src/main/native/include/frc/util/Color8Bit.h +++ b/wpilibc/src/main/native/include/frc/util/Color8Bit.h @@ -21,6 +21,9 @@ namespace frc { */ class Color8Bit { public: + /** + * Constructs a default color (black). + */ constexpr Color8Bit() = default; /** @@ -60,12 +63,12 @@ class Color8Bit { fmt::format("Invalid hex string for Color \"{}\"", hexString)); } - red = wpi::hexDigitValue(hexString[0]) * 16 + - wpi::hexDigitValue(hexString[1]); - green = wpi::hexDigitValue(hexString[2]) * 16 + - wpi::hexDigitValue(hexString[3]); - blue = wpi::hexDigitValue(hexString[4]) * 16 + - wpi::hexDigitValue(hexString[5]); + red = wpi::hexDigitValue(hexString[1]) * 16 + + wpi::hexDigitValue(hexString[2]); + green = wpi::hexDigitValue(hexString[3]) * 16 + + wpi::hexDigitValue(hexString[4]); + blue = wpi::hexDigitValue(hexString[5]) * 16 + + wpi::hexDigitValue(hexString[6]); } constexpr bool operator==(const Color8Bit&) const = default; diff --git a/wpilibc/src/test/native/cpp/util/Color8BitTest.cpp b/wpilibc/src/test/native/cpp/util/Color8BitTest.cpp index 69e36fbe4f0..e0b26dd5790 100644 --- a/wpilibc/src/test/native/cpp/util/Color8BitTest.cpp +++ b/wpilibc/src/test/native/cpp/util/Color8BitTest.cpp @@ -6,14 +6,57 @@ #include "frc/util/Color8Bit.h" -TEST(Color8BitTest, ConstructDefault) {} +TEST(Color8BitTest, ConstructDefault) { + constexpr frc::Color8Bit color; -TEST(Color8BitTest, ConstructFromInts) {} + EXPECT_EQ(0, color.red); + EXPECT_EQ(0, color.green); + EXPECT_EQ(0, color.blue); +} -TEST(Color8BitTest, ConstructFromColor) {} +TEST(Color8BitTest, ConstructFromInts) { + constexpr frc::Color8Bit color{255, 128, 64}; -TEST(Color8BitTest, ConstructFromHexString) {} + EXPECT_EQ(255, color.red); + EXPECT_EQ(128, color.green); + EXPECT_EQ(64, color.blue); +} -TEST(Color8BitTest, ImplicitConversionToColor) {} +TEST(Color8BitTest, ConstructFromColor) { + constexpr frc::Color8Bit color{frc::Color{255, 128, 64}}; -TEST(Color8BitTest, ToHexString) {} + EXPECT_EQ(255, color.red); + EXPECT_EQ(128, color.green); + EXPECT_EQ(64, color.blue); +} + +TEST(Color8BitTest, ConstructFromHexString) { + constexpr frc::Color8Bit color{"#FF8040"}; + + EXPECT_EQ(255, color.red); + EXPECT_EQ(128, color.green); + EXPECT_EQ(64, color.blue); + + // No leading # + EXPECT_THROW(frc::Color8Bit{"112233"}, std::invalid_argument); + + // Too long + EXPECT_THROW(frc::Color8Bit{"#11223344"}, std::invalid_argument); + + // Invalid hex characters + EXPECT_THROW(frc::Color8Bit{"#$$$$$$"}, std::invalid_argument); +} + +TEST(Color8BitTest, ImplicitConversionToColor) { + frc::Color color = frc::Color8Bit{255, 128, 64}; + + EXPECT_NEAR(1.0, color.red, 1e-2); + EXPECT_NEAR(0.5, color.green, 1e-2); + EXPECT_NEAR(0.25, color.blue, 1e-2); +} + +TEST(Color8BitTest, ToHexString) { + constexpr frc::Color8Bit color{255, 128, 64}; + + EXPECT_EQ("#FF8040", color.HexString()); +} diff --git a/wpilibc/src/test/native/cpp/util/ColorTest.cpp b/wpilibc/src/test/native/cpp/util/ColorTest.cpp index 9b9eea7e078..c76c7f1da29 100644 --- a/wpilibc/src/test/native/cpp/util/ColorTest.cpp +++ b/wpilibc/src/test/native/cpp/util/ColorTest.cpp @@ -6,14 +6,57 @@ #include "frc/util/Color.h" -TEST(ColorTest, ConstructDefault) {} +TEST(ColorTest, ConstructDefault) { + constexpr frc::Color color; -TEST(ColorTest, ConstructFromDoubles) {} + EXPECT_DOUBLE_EQ(0.0, color.red); + EXPECT_DOUBLE_EQ(0.0, color.green); + EXPECT_DOUBLE_EQ(0.0, color.blue); +} -TEST(ColorTest, ConstructFromInts) {} +TEST(ColorTest, ConstructFromDoubles) { + constexpr frc::Color color{1.0, 0.5, 0.25}; -TEST(ColorTest, ConstructFromHexString) {} + EXPECT_NEAR(1.0, color.red, 1e-2); + EXPECT_NEAR(0.5, color.green, 1e-2); + EXPECT_NEAR(0.25, color.blue, 1e-2); +} -TEST(ColorTest, FromHSV) {} +TEST(ColorTest, ConstructFromInts) { + constexpr frc::Color color{255, 128, 64}; -TEST(ColorTest, ToHexString) {} + EXPECT_NEAR(1.0, color.red, 1e-2); + EXPECT_NEAR(0.5, color.green, 1e-2); + EXPECT_NEAR(0.25, color.blue, 1e-2); +} + +TEST(ColorTest, ConstructFromHexString) { + constexpr frc::Color color{"#FF8040"}; + + EXPECT_NEAR(1.0, color.red, 1e-2); + EXPECT_NEAR(0.5, color.green, 1e-2); + EXPECT_NEAR(0.25, color.blue, 1e-2); + + // No leading # + EXPECT_THROW(frc::Color{"112233"}, std::invalid_argument); + + // Too long + EXPECT_THROW(frc::Color{"#11223344"}, std::invalid_argument); + + // Invalid hex characters + EXPECT_THROW(frc::Color{"#$$$$$$"}, std::invalid_argument); +} + +TEST(ColorTest, FromHSV) { + constexpr frc::Color color = frc::Color::FromHSV(90, 128, 64); + + EXPECT_DOUBLE_EQ(0.1256103515625, color.red); + EXPECT_DOUBLE_EQ(0.2510986328125, color.green); + EXPECT_DOUBLE_EQ(0.2510986328125, color.blue); +} + +TEST(ColorTest, ToHexString) { + constexpr frc::Color color{255, 128, 64}; + + EXPECT_EQ("#FF8040", color.HexString()); +} diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/util/Color.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/util/Color.java index c9787325fa8..706795dd701 100644 --- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/util/Color.java +++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/util/Color.java @@ -21,6 +21,13 @@ public class Color { public final double blue; private String m_name; + /** Constructs a default color (black). */ + public Color() { + red = 0.0; + green = 0.0; + blue = 0.0; + } + /** * Constructs a Color from doubles. * diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/util/Color8Bit.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/util/Color8Bit.java index e9e0e8880b3..5d916e1941a 100644 --- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/util/Color8Bit.java +++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/util/Color8Bit.java @@ -14,6 +14,13 @@ public class Color8Bit { public final int green; public final int blue; + /** Constructs a default color (black). */ + public Color8Bit() { + red = 0; + green = 0; + blue = 0; + } + /** * Constructs a Color8Bit. * diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/util/Color8BitTest.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/util/Color8BitTest.java index 42abf020d76..499ecbde80c 100644 --- a/wpilibj/src/test/java/edu/wpi/first/wpilibj/util/Color8BitTest.java +++ b/wpilibj/src/test/java/edu/wpi/first/wpilibj/util/Color8BitTest.java @@ -4,21 +4,62 @@ package edu.wpi.first.wpilibj.util; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + import org.junit.jupiter.api.Test; class Color8BitTest { @Test - void testConstructDefault() {} + void testConstructDefault() { + var color = new Color8Bit(); + + assertEquals(0, color.red); + assertEquals(0, color.green); + assertEquals(0, color.blue); + } @Test - void testConstructFromInts() {} + void testConstructFromInts() { + var color = new Color8Bit(255, 128, 64); + + assertEquals(255, color.red); + assertEquals(128, color.green); + assertEquals(64, color.blue); + } @Test - void testConstructFromColor() {} + void testConstructFromColor() { + var color = new Color8Bit(new Color(255, 128, 64)); + + assertEquals(255, color.red); + assertEquals(128, color.green); + assertEquals(64, color.blue); + } @Test - void testConstructFromHexString() {} + void testConstructFromHexString() { + var color = new Color8Bit("#FF8040"); + + assertEquals(255, color.red); + assertEquals(128, color.green); + assertEquals(64, color.blue); + + // No leading # + assertThrows(IllegalArgumentException.class, () -> new Color8Bit("112233")); + + // Too long + assertThrows(IllegalArgumentException.class, () -> new Color8Bit("#11223344")); + + // Invalid hex characters + assertThrows(IllegalArgumentException.class, () -> new Color8Bit("#$$$$$$")); + } @Test - void testToHexString() {} + void testToHexString() { + var color = new Color8Bit(255, 128, 64); + + assertEquals("#FF8040", color.toHexString()); + assertEquals("#FF8040", color.toString()); + } } diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/util/ColorTest.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/util/ColorTest.java index fdd8fbd6870..c6af4e35c21 100644 --- a/wpilibj/src/test/java/edu/wpi/first/wpilibj/util/ColorTest.java +++ b/wpilibj/src/test/java/edu/wpi/first/wpilibj/util/ColorTest.java @@ -4,24 +4,71 @@ package edu.wpi.first.wpilibj.util; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + import org.junit.jupiter.api.Test; class ColorTest { @Test - void testConstructDefault() {} + void testConstructDefault() { + var color = new Color(); + + assertEquals(0.0, color.red); + assertEquals(0.0, color.green); + assertEquals(0.0, color.blue); + } @Test - void testConstructFromDoubles() {} + void testConstructFromDoubles() { + var color = new Color(1.0, 0.5, 0.25); + + assertEquals(1.0, color.red, 1e-2); + assertEquals(0.5, color.green, 1e-2); + assertEquals(0.25, color.blue, 1e-2); + } @Test - void testConstructFromInts() {} + void testConstructFromInts() { + var color = new Color(255, 128, 64); + + assertEquals(1.0, color.red, 1e-2); + assertEquals(0.5, color.green, 1e-2); + assertEquals(0.25, color.blue, 1e-2); + } @Test - void testConstructFromHexString() {} + void testConstructFromHexString() { + var color = new Color("#FF8040"); + + assertEquals(1.0, color.red, 1e-2); + assertEquals(0.5, color.green, 1e-2); + assertEquals(0.25, color.blue, 1e-2); + + // No leading # + assertThrows(IllegalArgumentException.class, () -> new Color("112233")); + + // Too long + assertThrows(IllegalArgumentException.class, () -> new Color("#11223344")); + + // Invalid hex characters + assertThrows(IllegalArgumentException.class, () -> new Color("#$$$$$$")); + } @Test - void testFromHSV() {} + void testFromHSV() { + var color = Color.fromHSV(90, 128, 64); + + assertEquals(0.125732421875, color.red); + assertEquals(0.251220703125, color.green); + assertEquals(0.251220703125, color.blue); + } @Test - void testToHexString() {} + void testToHexString() { + var color = new Color(255, 128, 64); + + assertEquals("#FF8040", color.toHexString()); + assertEquals("#FF8040", color.toString()); + } } From f2e501995244377109b5bb1a8e26c967c69c0d99 Mon Sep 17 00:00:00 2001 From: Tyler Veness Date: Fri, 1 Dec 2023 09:41:16 -0800 Subject: [PATCH 10/10] Move non-constexpr function to .cpp file --- wpilibc/src/main/native/cpp/util/Color.cpp | 13 +++++++++++++ wpilibc/src/main/native/cpp/util/Color8Bit.cpp | 11 +++++++++++ wpilibc/src/main/native/include/frc/util/Color.h | 6 +----- .../src/main/native/include/frc/util/Color8Bit.h | 4 +--- 4 files changed, 26 insertions(+), 8 deletions(-) create mode 100644 wpilibc/src/main/native/cpp/util/Color.cpp create mode 100644 wpilibc/src/main/native/cpp/util/Color8Bit.cpp diff --git a/wpilibc/src/main/native/cpp/util/Color.cpp b/wpilibc/src/main/native/cpp/util/Color.cpp new file mode 100644 index 00000000000..6923c9cbec1 --- /dev/null +++ b/wpilibc/src/main/native/cpp/util/Color.cpp @@ -0,0 +1,13 @@ +// 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(255.0 * red), + static_cast(255.0 * green), + static_cast(255.0 * blue)); +} diff --git a/wpilibc/src/main/native/cpp/util/Color8Bit.cpp b/wpilibc/src/main/native/cpp/util/Color8Bit.cpp new file mode 100644 index 00000000000..e8e46567d70 --- /dev/null +++ b/wpilibc/src/main/native/cpp/util/Color8Bit.cpp @@ -0,0 +1,11 @@ +// 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); +} diff --git a/wpilibc/src/main/native/include/frc/util/Color.h b/wpilibc/src/main/native/include/frc/util/Color.h index 3e4567373d7..b5855e23ce8 100644 --- a/wpilibc/src/main/native/include/frc/util/Color.h +++ b/wpilibc/src/main/native/include/frc/util/Color.h @@ -851,11 +851,7 @@ class Color { * * @return a string of the format \#RRGGBB */ - std::string HexString() const { - return fmt::format("#{:02X}{:02X}{:02X}", static_cast(255.0 * red), - static_cast(255.0 * green), - static_cast(255.0 * blue)); - } + std::string HexString() const; double red = 0.0; double green = 0.0; diff --git a/wpilibc/src/main/native/include/frc/util/Color8Bit.h b/wpilibc/src/main/native/include/frc/util/Color8Bit.h index 559559bcd14..77bdc9f0ee5 100644 --- a/wpilibc/src/main/native/include/frc/util/Color8Bit.h +++ b/wpilibc/src/main/native/include/frc/util/Color8Bit.h @@ -107,9 +107,7 @@ class Color8Bit { * * @return a string of the format \#RRGGBB */ - std::string HexString() const { - return fmt::format("#{:02X}{:02X}{:02X}", red, green, blue); - } + std::string HexString() const; int red = 0; int green = 0;