From 350df1dc2f5b7bb59715e2b4d63ce1e3bf040b30 Mon Sep 17 00:00:00 2001 From: Vladyslav Baranovskyi Date: Thu, 19 Sep 2024 16:26:42 +0300 Subject: [PATCH 1/3] UnitFormatter class + several tests --- openVulkanoCpp/Base/UnitFormatter.cpp | 67 +++++++++++++++++++++++++++ openVulkanoCpp/Base/UnitFormatter.hpp | 23 +++++++++ tests/UnitFormatter.cpp | 33 +++++++++++++ 3 files changed, 123 insertions(+) create mode 100644 openVulkanoCpp/Base/UnitFormatter.cpp create mode 100644 openVulkanoCpp/Base/UnitFormatter.hpp create mode 100644 tests/UnitFormatter.cpp diff --git a/openVulkanoCpp/Base/UnitFormatter.cpp b/openVulkanoCpp/Base/UnitFormatter.cpp new file mode 100644 index 0000000..55de4ee --- /dev/null +++ b/openVulkanoCpp/Base/UnitFormatter.cpp @@ -0,0 +1,67 @@ +/* +* This Source Code Form is subject to the terms of the Mozilla Public +* License, v. 2.0. If a copy of the MPL was not distributed with this +* file, You can obtain one at https://mozilla.org/MPL/2.0/. +*/ + +#include "UnitFormatter.hpp" +#include +#include +#include + +namespace +{ + template static std::string formatValue(T value, int precision) + { + std::ostringstream stream; + stream << std::fixed << std::setprecision(precision) << value; + return stream.str(); + } +} + +namespace OpenVulkano +{ + UnitFormatter::UnitFormatter(bool useMetric, int precisionDigits) : metric(useMetric), precision(precisionDigits) {} + + std::string UnitFormatter::Format(units::length::meter_t distance) + { + if (metric) + { + if (distance >= units::length::kilometer_t(1)) + { + return formatValue(units::length::kilometer_t(distance).value(), precision) + " km"; + } + return formatValue(distance.value(), precision) + " m"; + } + else + { + auto distanceFeet = units::length::foot_t(distance).value(); + if (distanceFeet >= 5280.0) + { + return formatValue(units::length::mile_t(distance).value(), precision) + " mi"; + } + return formatValue(distanceFeet, precision) + " ft"; + } + } + + std::string UnitFormatter::Format(units::area::square_meter_t area) + { + if (metric) + { + if (area >= units::area::square_kilometer_t(1)) + { + return formatValue(units::area::square_kilometer_t(area).value(), precision) + " km²"; + } + return formatValue(area.value(), precision) + " m²"; + } + else + { + auto areaSquareFeet = units::area::square_foot_t(area).value(); + if (areaSquareFeet >= 27878400.0) + { + return formatValue(units::area::square_mile_t(area).value(), precision) + " mi²"; + } + return formatValue(areaSquareFeet, precision) + " ft²"; + } + } +} \ No newline at end of file diff --git a/openVulkanoCpp/Base/UnitFormatter.hpp b/openVulkanoCpp/Base/UnitFormatter.hpp new file mode 100644 index 0000000..4d59107 --- /dev/null +++ b/openVulkanoCpp/Base/UnitFormatter.hpp @@ -0,0 +1,23 @@ +/* +* This Source Code Form is subject to the terms of the Mozilla Public +* License, v. 2.0. If a copy of the MPL was not distributed with this +* file, You can obtain one at https://mozilla.org/MPL/2.0/. +*/ +#pragma once + +#include +#include + +namespace OpenVulkano +{ + class UnitFormatter + { + bool metric = true; + int precision = 3; + + public: + UnitFormatter(bool useMetric = true, int precisionDigits = 3); + std::string Format(units::length::meter_t distance); + std::string Format(units::area::square_meter_t area); + }; +} \ No newline at end of file diff --git a/tests/UnitFormatter.cpp b/tests/UnitFormatter.cpp new file mode 100644 index 0000000..b7f9416 --- /dev/null +++ b/tests/UnitFormatter.cpp @@ -0,0 +1,33 @@ +/* +* This Source Code Form is subject to the terms of the Mozilla Public +* License, v. 2.0. If a copy of the MPL was not distributed with this +* file, You can obtain one at https://mozilla.org/MPL/2.0/. +*/ + +#include + +#include "Base/UnitFormatter.hpp" + +using namespace units::literals; + +TEST_CASE("testUnitFormatter", "[UnitFormatter]") +{ + OpenVulkano::UnitFormatter metricFormatter(true, 2); + OpenVulkano::UnitFormatter imperialFormatter(false, 2); + + units::length::meter_t positiveDistance = 1500.0_m; + units::length::meter_t smallDistance = 0.5_m; + units::length::meter_t negativeDistance = -100.0_m; + units::area::square_meter_t smallArea(0.005); + units::area::square_meter_t negativeArea(-50.0); + + REQUIRE(metricFormatter.Format(positiveDistance) == "1.50 km"); + REQUIRE(metricFormatter.Format(smallDistance) == "0.50 m"); + REQUIRE(metricFormatter.Format(negativeDistance) == "-100.00 m"); + REQUIRE(metricFormatter.Format(smallArea) == "0.01 m²"); + REQUIRE(metricFormatter.Format(negativeArea) == "-50.00 m²"); + REQUIRE(imperialFormatter.Format(smallDistance) == "1.64 ft"); + REQUIRE(imperialFormatter.Format(negativeDistance) == "-328.08 ft"); + REQUIRE(imperialFormatter.Format(smallArea) == "0.05 ft²"); + REQUIRE(imperialFormatter.Format(negativeArea) == "-538.20 ft²"); +} From c01155d8e4be26fd7a133820a86737652234a43a Mon Sep 17 00:00:00 2001 From: Vladyslav Baranovskyi Date: Fri, 20 Sep 2024 12:44:01 +0300 Subject: [PATCH 2/3] Option to trim zeros at the end, more tests --- openVulkanoCpp/Base/UnitFormatter.cpp | 56 ++++++++++++++++++++------- openVulkanoCpp/Base/UnitFormatter.hpp | 3 +- tests/UnitFormatter.cpp | 41 ++++++++++++++++++-- 3 files changed, 81 insertions(+), 19 deletions(-) diff --git a/openVulkanoCpp/Base/UnitFormatter.cpp b/openVulkanoCpp/Base/UnitFormatter.cpp index 55de4ee..b0a4e1b 100644 --- a/openVulkanoCpp/Base/UnitFormatter.cpp +++ b/openVulkanoCpp/Base/UnitFormatter.cpp @@ -11,36 +11,61 @@ namespace { - template static std::string formatValue(T value, int precision) + template std::string FormatValue(T value, int precision, bool trimTrailingZeros = false) { - std::ostringstream stream; - stream << std::fixed << std::setprecision(precision) << value; - return stream.str(); + std::ostringstream out; + out << std::fixed << std::setprecision(precision) << value; + std::string result = out.str(); + + if (trimTrailingZeros && result.find('.') != std::string::npos) + { + result.erase(result.find_last_not_of('0') + 1); + + if (result.back() == '.') + { + result.pop_back(); + } + } + + return result; } } namespace OpenVulkano { - UnitFormatter::UnitFormatter(bool useMetric, int precisionDigits) : metric(useMetric), precision(precisionDigits) {} + UnitFormatter::UnitFormatter(bool useMetric, int precisionDigits, bool doTrimTrailingZeros) + : metric(useMetric), precision(precisionDigits), trimTrailingZeros(doTrimTrailingZeros) + { + } std::string UnitFormatter::Format(units::length::meter_t distance) { if (metric) { - if (distance >= units::length::kilometer_t(1)) + if (distance > units::length::meter_t(0) && distance < units::length::meter_t(0.1)) { - return formatValue(units::length::kilometer_t(distance).value(), precision) + " km"; + return FormatValue(units::length::millimeter_t(distance).value(), precision, trimTrailingZeros) + " mm"; } - return formatValue(distance.value(), precision) + " m"; + else if (distance >= units::length::kilometer_t(1)) + { + return FormatValue(units::length::kilometer_t(distance).value(), precision, trimTrailingZeros) + " km"; + } + return FormatValue(distance.value(), precision, trimTrailingZeros) + " m"; } else { auto distanceFeet = units::length::foot_t(distance).value(); - if (distanceFeet >= 5280.0) + auto distanceInches = units::length::inch_t(distance).value(); + + if (distanceFeet > 0 && distanceFeet < 0.1) { - return formatValue(units::length::mile_t(distance).value(), precision) + " mi"; + return FormatValue(distanceInches, precision, trimTrailingZeros) + " in"; } - return formatValue(distanceFeet, precision) + " ft"; + else if (distanceFeet >= 5280.0) + { + return FormatValue(units::length::mile_t(distance).value(), precision, trimTrailingZeros) + " mi"; + } + return FormatValue(distanceFeet, precision, trimTrailingZeros) + " ft"; } } @@ -50,18 +75,19 @@ namespace OpenVulkano { if (area >= units::area::square_kilometer_t(1)) { - return formatValue(units::area::square_kilometer_t(area).value(), precision) + " km²"; + return FormatValue(units::area::square_kilometer_t(area).value(), precision, trimTrailingZeros) + + " km²"; } - return formatValue(area.value(), precision) + " m²"; + return FormatValue(area.value(), precision, trimTrailingZeros) + " m²"; } else { auto areaSquareFeet = units::area::square_foot_t(area).value(); if (areaSquareFeet >= 27878400.0) { - return formatValue(units::area::square_mile_t(area).value(), precision) + " mi²"; + return FormatValue(units::area::square_mile_t(area).value(), precision, trimTrailingZeros) + " mi²"; } - return formatValue(areaSquareFeet, precision) + " ft²"; + return FormatValue(areaSquareFeet, precision, trimTrailingZeros) + " ft²"; } } } \ No newline at end of file diff --git a/openVulkanoCpp/Base/UnitFormatter.hpp b/openVulkanoCpp/Base/UnitFormatter.hpp index 4d59107..ebfd8ea 100644 --- a/openVulkanoCpp/Base/UnitFormatter.hpp +++ b/openVulkanoCpp/Base/UnitFormatter.hpp @@ -14,9 +14,10 @@ namespace OpenVulkano { bool metric = true; int precision = 3; + bool trimTrailingZeros = true; public: - UnitFormatter(bool useMetric = true, int precisionDigits = 3); + UnitFormatter(bool useMetric = true, int precisionDigits = 3, bool doTrimTrailingZeros = true); std::string Format(units::length::meter_t distance); std::string Format(units::area::square_meter_t area); }; diff --git a/tests/UnitFormatter.cpp b/tests/UnitFormatter.cpp index b7f9416..8f2d2b3 100644 --- a/tests/UnitFormatter.cpp +++ b/tests/UnitFormatter.cpp @@ -10,14 +10,16 @@ using namespace units::literals; -TEST_CASE("testUnitFormatter", "[UnitFormatter]") +TEST_CASE("testUnitFormatterWithTrailingZeros", "[UnitFormatter]") { - OpenVulkano::UnitFormatter metricFormatter(true, 2); - OpenVulkano::UnitFormatter imperialFormatter(false, 2); + OpenVulkano::UnitFormatter metricFormatter(true, 2, false); + OpenVulkano::UnitFormatter imperialFormatter(false, 2, false); units::length::meter_t positiveDistance = 1500.0_m; units::length::meter_t smallDistance = 0.5_m; units::length::meter_t negativeDistance = -100.0_m; + units::length::meter_t smallDistanceMetric = 0.05_m; + units::length::meter_t smallDistanceImperial = 0.03_m; units::area::square_meter_t smallArea(0.005); units::area::square_meter_t negativeArea(-50.0); @@ -30,4 +32,37 @@ TEST_CASE("testUnitFormatter", "[UnitFormatter]") REQUIRE(imperialFormatter.Format(negativeDistance) == "-328.08 ft"); REQUIRE(imperialFormatter.Format(smallArea) == "0.05 ft²"); REQUIRE(imperialFormatter.Format(negativeArea) == "-538.20 ft²"); + REQUIRE(metricFormatter.Format(smallDistanceMetric) == "50.00 mm"); + REQUIRE(imperialFormatter.Format(smallDistanceImperial) == "1.18 in"); } + +TEST_CASE("testUnitFormatterWithoutTrailingZeros", "[UnitFormatter]") +{ + OpenVulkano::UnitFormatter metricFormatter(true, 2); + OpenVulkano::UnitFormatter imperialFormatter(false, 2); + + units::length::meter_t positiveDistance = 1500.0_m; + units::length::meter_t smallDistance = 0.5_m; + units::length::meter_t negativeDistance = -100.0_m; + units::length::meter_t smallDistanceMetric = 0.05_m; + units::length::meter_t smallDistanceImperial = 0.03_m; + units::length::meter_t mediumDistanceMetric = 0.5_m; + units::length::meter_t largeDistanceMetric = 100.0_m; + units::area::square_meter_t smallArea(0.005); + units::area::square_meter_t negativeArea(-50.0); + + REQUIRE(metricFormatter.Format(positiveDistance) == "1.5 km"); + REQUIRE(metricFormatter.Format(smallDistance) == "0.5 m"); + REQUIRE(metricFormatter.Format(negativeDistance) == "-100 m"); + REQUIRE(metricFormatter.Format(smallArea) == "0.01 m²"); + REQUIRE(metricFormatter.Format(negativeArea) == "-50 m²"); + REQUIRE(imperialFormatter.Format(smallDistance) == "1.64 ft"); + REQUIRE(imperialFormatter.Format(negativeDistance) == "-328.08 ft"); + REQUIRE(imperialFormatter.Format(smallArea) == "0.05 ft²"); + REQUIRE(imperialFormatter.Format(negativeArea) == "-538.2 ft²"); + REQUIRE(metricFormatter.Format(smallDistanceMetric) == "50 mm"); + REQUIRE(imperialFormatter.Format(smallDistanceImperial) == "1.18 in"); + REQUIRE(metricFormatter.Format(smallDistanceMetric) == "50 mm"); + REQUIRE(metricFormatter.Format(mediumDistanceMetric) == "0.5 m"); + REQUIRE(metricFormatter.Format(largeDistanceMetric) == "100 m"); +} \ No newline at end of file From ad7997cdf50e9e1dcd55635e51267a5a826887c0 Mon Sep 17 00:00:00 2001 From: Vladyslav Baranovskyi Date: Mon, 23 Sep 2024 16:09:58 +0300 Subject: [PATCH 3/3] Made Format methods const and nodiscard, passing suffix to the Format function --- openVulkanoCpp/Base/UnitFormatter.cpp | 30 +++++++++++++-------------- openVulkanoCpp/Base/UnitFormatter.hpp | 4 ++-- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/openVulkanoCpp/Base/UnitFormatter.cpp b/openVulkanoCpp/Base/UnitFormatter.cpp index b0a4e1b..a2ee422 100644 --- a/openVulkanoCpp/Base/UnitFormatter.cpp +++ b/openVulkanoCpp/Base/UnitFormatter.cpp @@ -11,7 +11,8 @@ namespace { - template std::string FormatValue(T value, int precision, bool trimTrailingZeros = false) + template + std::string FormatValue(T value, int precision, bool trimTrailingZeros, const std::string& suffix) { std::ostringstream out; out << std::fixed << std::setprecision(precision) << value; @@ -26,7 +27,7 @@ namespace result.pop_back(); } } - + result += suffix; return result; } } @@ -38,19 +39,19 @@ namespace OpenVulkano { } - std::string UnitFormatter::Format(units::length::meter_t distance) + std::string UnitFormatter::Format(units::length::meter_t distance) const { if (metric) { if (distance > units::length::meter_t(0) && distance < units::length::meter_t(0.1)) { - return FormatValue(units::length::millimeter_t(distance).value(), precision, trimTrailingZeros) + " mm"; + return FormatValue(units::length::millimeter_t(distance).value(), precision, trimTrailingZeros, " mm"); } else if (distance >= units::length::kilometer_t(1)) { - return FormatValue(units::length::kilometer_t(distance).value(), precision, trimTrailingZeros) + " km"; + return FormatValue(units::length::kilometer_t(distance).value(), precision, trimTrailingZeros, " km"); } - return FormatValue(distance.value(), precision, trimTrailingZeros) + " m"; + return FormatValue(distance.value(), precision, trimTrailingZeros, " m"); } else { @@ -59,35 +60,34 @@ namespace OpenVulkano if (distanceFeet > 0 && distanceFeet < 0.1) { - return FormatValue(distanceInches, precision, trimTrailingZeros) + " in"; + return FormatValue(distanceInches, precision, trimTrailingZeros, " in"); } else if (distanceFeet >= 5280.0) { - return FormatValue(units::length::mile_t(distance).value(), precision, trimTrailingZeros) + " mi"; + return FormatValue(units::length::mile_t(distance).value(), precision, trimTrailingZeros, " mi"); } - return FormatValue(distanceFeet, precision, trimTrailingZeros) + " ft"; + return FormatValue(distanceFeet, precision, trimTrailingZeros, " ft"); } } - std::string UnitFormatter::Format(units::area::square_meter_t area) + std::string UnitFormatter::Format(units::area::square_meter_t area) const { if (metric) { if (area >= units::area::square_kilometer_t(1)) { - return FormatValue(units::area::square_kilometer_t(area).value(), precision, trimTrailingZeros) - + " km²"; + return FormatValue(units::area::square_kilometer_t(area).value(), precision, trimTrailingZeros, " km²"); } - return FormatValue(area.value(), precision, trimTrailingZeros) + " m²"; + return FormatValue(area.value(), precision, trimTrailingZeros, " m²"); } else { auto areaSquareFeet = units::area::square_foot_t(area).value(); if (areaSquareFeet >= 27878400.0) { - return FormatValue(units::area::square_mile_t(area).value(), precision, trimTrailingZeros) + " mi²"; + return FormatValue(units::area::square_mile_t(area).value(), precision, trimTrailingZeros, " mi²"); } - return FormatValue(areaSquareFeet, precision, trimTrailingZeros) + " ft²"; + return FormatValue(areaSquareFeet, precision, trimTrailingZeros, " ft²"); } } } \ No newline at end of file diff --git a/openVulkanoCpp/Base/UnitFormatter.hpp b/openVulkanoCpp/Base/UnitFormatter.hpp index ebfd8ea..3e17543 100644 --- a/openVulkanoCpp/Base/UnitFormatter.hpp +++ b/openVulkanoCpp/Base/UnitFormatter.hpp @@ -18,7 +18,7 @@ namespace OpenVulkano public: UnitFormatter(bool useMetric = true, int precisionDigits = 3, bool doTrimTrailingZeros = true); - std::string Format(units::length::meter_t distance); - std::string Format(units::area::square_meter_t area); + [[nodiscard]] std::string Format(units::length::meter_t distance) const; + [[nodiscard]] std::string Format(units::area::square_meter_t area) const; }; } \ No newline at end of file