From 7b199f16e6cec7e05ee9503e4d103a747c26f043 Mon Sep 17 00:00:00 2001 From: Liam Teale Date: Thu, 26 Dec 2024 22:48:03 -0800 Subject: [PATCH 01/10] make Number able to be converted to double implicitly --- include/units/units.hpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/include/units/units.hpp b/include/units/units.hpp index 500687c..9966703 100644 --- a/include/units/units.hpp +++ b/include/units/units.hpp @@ -261,7 +261,7 @@ template constexpr bool operator>(const Q& lhs, con return (lhs.internal() > rhs.internal()); } -#define NEW_UNIT(Name, suffix, m, l, t, i, a, o, j, n) \ +#define NEW_UNIT_FULL(Name, suffix, m, l, t, i, a, o, j, n, extra) \ class Name : public Quantity, std::ratio, std::ratio, std::ratio, std::ratio, \ std::ratio, std::ratio, std::ratio> { \ public: \ @@ -273,6 +273,7 @@ template constexpr bool operator>(const Q& lhs, con value) \ : Quantity, std::ratio, std::ratio, std::ratio, std::ratio, std::ratio, \ std::ratio, std::ratio>(value) {}; \ + extra \ }; \ template <> struct LookupName, std::ratio, std::ratio, std::ratio, std::ratio, \ std::ratio, std::ratio, std::ratio>> { \ @@ -294,6 +295,8 @@ template constexpr bool operator>(const Q& lhs, con constexpr inline Name from_##suffix(double value) { return Name(value); } \ constexpr inline double to_##suffix(Name quantity) { return quantity.internal(); } +#define NEW_UNIT(Name, suffix, m, l, t, i, a, o, j, n) NEW_UNIT_FULL(Name, suffix, m, l, t, i, a, o, j, n, ) + #define NEW_UNIT_LITERAL(Name, suffix, multiple) \ [[maybe_unused]] constexpr Name suffix = multiple; \ constexpr Name operator""_##suffix(long double value) { return static_cast(value) * multiple; } \ @@ -312,7 +315,7 @@ template constexpr bool operator>(const Q& lhs, con NEW_UNIT_LITERAL(Name, u##base, base / 1E6) \ NEW_UNIT_LITERAL(Name, n##base, base / 1E9) -NEW_UNIT(Number, num, 0, 0, 0, 0, 0, 0, 0, 0) +NEW_UNIT_FULL(Number, num, 0, 0, 0, 0, 0, 0, 0, 0, constexpr operator double() { return this->value; }) NEW_UNIT_LITERAL(Number, percent, num / 100.0); NEW_UNIT(Mass, kg, 1, 0, 0, 0, 0, 0, 0, 0) From efe1b9e7bf9ce0002e3e161846d9ef38c6471c2e Mon Sep 17 00:00:00 2001 From: Liam Teale Date: Thu, 26 Dec 2024 22:51:46 -0800 Subject: [PATCH 02/10] remove unnecessary references to Number --- include/units/Angle.hpp | 12 ------------ include/units/Temperature.hpp | 8 -------- 2 files changed, 20 deletions(-) diff --git a/include/units/Angle.hpp b/include/units/Angle.hpp index b3f48b4..34e837e 100644 --- a/include/units/Angle.hpp +++ b/include/units/Angle.hpp @@ -101,37 +101,25 @@ static inline Angle constrainAngle180(Angle in) { // Standard orientation constexpr inline Angle from_stRad(double value) { return Angle(value); } -constexpr inline Angle from_stRad(Number value) { return Angle(value.internal()); } - constexpr inline double to_stRad(Angle quantity) { return quantity.internal(); } constexpr inline Angle from_stDeg(double value) { return value * deg; } -constexpr inline Angle from_stDeg(Number value) { return value * deg; } - constexpr inline double to_stDeg(Angle quantity) { return quantity.convert(deg); } constexpr inline Angle from_stRot(double value) { return value * rot; } -constexpr inline Angle from_stRot(Number value) { return value * rot; } - constexpr inline double to_stRot(Angle quantity) { return quantity.convert(rot); } // Compass orientation constexpr inline Angle from_cRad(double value) { return 90 * deg - Angle(value); } -constexpr inline Angle from_cRad(Number value) { return 90 * deg - Angle(value.internal()); } - constexpr inline double to_cRad(Angle quantity) { return quantity.internal(); } constexpr inline Angle from_cDeg(double value) { return (90 - value) * deg; } -constexpr inline Angle from_cDeg(Number value) { return (90 - value.internal()) * deg; } - constexpr inline double to_cDeg(Angle quantity) { return (90 * deg - quantity).convert(deg); } constexpr inline Angle from_cRot(double value) { return (90 - value) * deg; } -constexpr inline Angle from_cRot(Number value) { return (90 - value.internal()) * deg; } - constexpr inline double to_cRot(Angle quantity) { return (90 * deg - quantity).convert(rot); } \ No newline at end of file diff --git a/include/units/Temperature.hpp b/include/units/Temperature.hpp index be5cb5d..be7bf86 100644 --- a/include/units/Temperature.hpp +++ b/include/units/Temperature.hpp @@ -50,22 +50,14 @@ namespace units { constexpr inline Temperature from_kelvin(double value) { return Temperature(value); } -constexpr inline Temperature from_kelvin(Number value) { return Temperature(value.internal()); } - constexpr inline double to_kelvin(Temperature quantity) { return quantity.internal(); } constexpr inline Temperature from_celsius(double value) { return Temperature(value + 273.15); } -constexpr inline Temperature from_celsius(Number value) { return Temperature(value.internal() + 273.15); } - constexpr inline double to_celsius(Temperature quantity) { return quantity.internal() - 273.15; } constexpr inline Temperature from_fahrenheit(double value) { return Temperature((value - 32) * (5.0 / 9.0) + 273.15); } -constexpr inline Temperature from_fahrenheit(Number value) { - return Temperature((value.internal() - 32) * (5.0 / 9.0) + 273.15); -} - constexpr inline double to_fahrenheit(Temperature quantity) { return (quantity.internal() - 273.15) * (9.0 / 5.0) + 32; } From 0e72c487149de3da54ae1b789a9eae455d8b39be Mon Sep 17 00:00:00 2001 From: Liam Teale Date: Thu, 26 Dec 2024 23:24:53 -0800 Subject: [PATCH 03/10] use variadic macro arg for NEW_UNIT --- include/units/units.hpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/include/units/units.hpp b/include/units/units.hpp index 9966703..ffbb20d 100644 --- a/include/units/units.hpp +++ b/include/units/units.hpp @@ -261,7 +261,7 @@ template constexpr bool operator>(const Q& lhs, con return (lhs.internal() > rhs.internal()); } -#define NEW_UNIT_FULL(Name, suffix, m, l, t, i, a, o, j, n, extra) \ +#define NEW_UNIT(Name, suffix, m, l, t, i, a, o, j, n, ...) \ class Name : public Quantity, std::ratio, std::ratio, std::ratio, std::ratio, \ std::ratio, std::ratio, std::ratio> { \ public: \ @@ -273,7 +273,7 @@ template constexpr bool operator>(const Q& lhs, con value) \ : Quantity, std::ratio, std::ratio, std::ratio, std::ratio, std::ratio, \ std::ratio, std::ratio>(value) {}; \ - extra \ + __VA_ARGS__ \ }; \ template <> struct LookupName, std::ratio, std::ratio, std::ratio, std::ratio, \ std::ratio, std::ratio, std::ratio>> { \ @@ -295,8 +295,6 @@ template constexpr bool operator>(const Q& lhs, con constexpr inline Name from_##suffix(double value) { return Name(value); } \ constexpr inline double to_##suffix(Name quantity) { return quantity.internal(); } -#define NEW_UNIT(Name, suffix, m, l, t, i, a, o, j, n) NEW_UNIT_FULL(Name, suffix, m, l, t, i, a, o, j, n, ) - #define NEW_UNIT_LITERAL(Name, suffix, multiple) \ [[maybe_unused]] constexpr Name suffix = multiple; \ constexpr Name operator""_##suffix(long double value) { return static_cast(value) * multiple; } \ @@ -315,7 +313,7 @@ template constexpr bool operator>(const Q& lhs, con NEW_UNIT_LITERAL(Name, u##base, base / 1E6) \ NEW_UNIT_LITERAL(Name, n##base, base / 1E9) -NEW_UNIT_FULL(Number, num, 0, 0, 0, 0, 0, 0, 0, 0, constexpr operator double() { return this->value; }) +NEW_UNIT(Number, num, 0, 0, 0, 0, 0, 0, 0, 0, constexpr operator double() { return this->value; }) NEW_UNIT_LITERAL(Number, percent, num / 100.0); NEW_UNIT(Mass, kg, 1, 0, 0, 0, 0, 0, 0, 0) From 6803b03f5d8aeac4e4c829819e522e4f6c274403 Mon Sep 17 00:00:00 2001 From: Liam Teale Date: Sat, 28 Dec 2024 14:26:14 -0800 Subject: [PATCH 04/10] make Number implicitly convertible to and from any arithmetic type --- include/units/units.hpp | 59 ++++++++++++++++++++++++++++++++++++++--- src/main.cpp | 9 ++++--- 2 files changed, 60 insertions(+), 8 deletions(-) diff --git a/include/units/units.hpp b/include/units/units.hpp index ffbb20d..deef8bf 100644 --- a/include/units/units.hpp +++ b/include/units/units.hpp @@ -261,7 +261,7 @@ template constexpr bool operator>(const Q& lhs, con return (lhs.internal() > rhs.internal()); } -#define NEW_UNIT(Name, suffix, m, l, t, i, a, o, j, n, ...) \ +#define NEW_UNIT(Name, suffix, m, l, t, i, a, o, j, n) \ class Name : public Quantity, std::ratio, std::ratio, std::ratio, std::ratio, \ std::ratio, std::ratio, std::ratio> { \ public: \ @@ -273,7 +273,6 @@ template constexpr bool operator>(const Q& lhs, con value) \ : Quantity, std::ratio, std::ratio, std::ratio, std::ratio, std::ratio, \ std::ratio, std::ratio>(value) {}; \ - __VA_ARGS__ \ }; \ template <> struct LookupName, std::ratio, std::ratio, std::ratio, std::ratio, \ std::ratio, std::ratio, std::ratio>> { \ @@ -313,8 +312,60 @@ template constexpr bool operator>(const Q& lhs, con NEW_UNIT_LITERAL(Name, u##base, base / 1E6) \ NEW_UNIT_LITERAL(Name, n##base, base / 1E9) -NEW_UNIT(Number, num, 0, 0, 0, 0, 0, 0, 0, 0, constexpr operator double() { return this->value; }) -NEW_UNIT_LITERAL(Number, percent, num / 100.0); +/* Number is a special type, because it can be implicitly converted to and from any arithmetic type */ +class Number : public Quantity, std::ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<0>, + std::ratio<0>, std::ratio<0>> { + public: + template constexpr Number(T value) + : Quantity, std::ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<0>, + std::ratio<0>, std::ratio<0>>(double(value)) {} + + constexpr Number(Quantity, std::ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<0>, + std::ratio<0>, std::ratio<0>, std::ratio<0>> + value) + : Quantity, std::ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<0>, + std::ratio<0>, std::ratio<0>>(value) {}; + + template constexpr operator T() const { return T(value); } +}; + +template <> struct LookupName, std::ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<0>, + std::ratio<0>, std::ratio<0>, std::ratio<0>>> { + using Named = Number; +}; + +[[maybe_unused]] constexpr Number num = Number(1.0); + +constexpr Number operator""_num(long double value) { + return Number(Quantity, std::ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<0>, + std::ratio<0>, std::ratio<0>>(static_cast(value))); +} + +constexpr Number operator""_num(unsigned long long value) { + return Number(Quantity, std::ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<0>, + std::ratio<0>, std::ratio<0>>(static_cast(value))); +} + +inline std::ostream& operator<<(std::ostream& os, const Number& quantity) { + os << quantity.internal() << " " << num; + return os; +} + +constexpr inline Number from_num(double value) { return Number(value); } + +constexpr inline double to_num(Number quantity) { return quantity.internal(); } + +[[maybe_unused]] constexpr Number percent = num / 100.0; + +constexpr Number operator""_percent(long double value) { return value / 100.0; } + +constexpr Number operator""_percent(unsigned long long value) { return value / 100.0; } + +constexpr inline Number from_percent(double value) { return value / 100.0; } + +constexpr inline Number from_percent(Number value) { return value / 100.0; } + +constexpr inline double to_percent(Number quantity) { return quantity.internal() * 100.0; } NEW_UNIT(Mass, kg, 1, 0, 0, 0, 0, 0, 0, 0) NEW_UNIT_LITERAL(Mass, g, kg / 1000) diff --git a/src/main.cpp b/src/main.cpp index dff5905..1cff351 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -47,10 +47,11 @@ void initialize() { Length z = toLinear(y, 2_cm); static_assert(Angle(5.1) >= Quantity, std::ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<1>, std::ratio<0>, std::ratio<0>, std::ratio<0>>(5.0)); - units::clamp(2_cDeg, a.theta(), Quantity, std::ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<1>, - std::ratio<0>, std::ratio<0>, std::ratio<0>>(5.0)); - units::max(10_celsius, Quantity, std::ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<1>, - std::ratio<0>, std::ratio<0>>(1.0)); + units::clamp(2_cDeg, a.theta(), + Quantity, std::ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<1>, std::ratio<0>, + std::ratio<0>, std::ratio<0>>(5.0)); + units::max(10_celsius, Quantity, std::ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<0>, + std::ratio<1>, std::ratio<0>, std::ratio<0>>(1.0)); } /** From 6f3befe5ba262865a6e4d7fcac008f84990d12a5 Mon Sep 17 00:00:00 2001 From: Liam Teale Date: Sat, 28 Dec 2024 17:11:28 -0800 Subject: [PATCH 05/10] remove Number implicit conversion --- include/units/units.hpp | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/include/units/units.hpp b/include/units/units.hpp index 0cb6fff..63d4cb5 100644 --- a/include/units/units.hpp +++ b/include/units/units.hpp @@ -325,8 +325,6 @@ class Number : public Quantity, std::ratio<0>, std::ratio<0>, std: value) : Quantity, std::ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<0>>(value) {}; - - template constexpr operator T() const { return T(value); } }; template <> struct LookupName, std::ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<0>, @@ -355,17 +353,7 @@ constexpr inline Number from_num(double value) { return Number(value); } constexpr inline double to_num(Number quantity) { return quantity.internal(); } -[[maybe_unused]] constexpr Number percent = num / 100.0; - -constexpr Number operator""_percent(long double value) { return value / 100.0; } - -constexpr Number operator""_percent(unsigned long long value) { return value / 100.0; } - -constexpr inline Number from_percent(double value) { return value / 100.0; } - -constexpr inline Number from_percent(Number value) { return value / 100.0; } - -constexpr inline double to_percent(Number quantity) { return quantity.internal() * 100.0; } +NEW_UNIT_LITERAL(Number, percent, num / 100) NEW_UNIT(Mass, kg, 1, 0, 0, 0, 0, 0, 0, 0) NEW_UNIT_LITERAL(Mass, g, kg / 1000) From dcd93b05819f05a15ac1681f32fdcfb91a280d47 Mon Sep 17 00:00:00 2001 From: Liam Teale Date: Sat, 28 Dec 2024 17:26:00 -0800 Subject: [PATCH 06/10] use Number instead of double for `from_` literal operator --- include/units/Angle.hpp | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/include/units/Angle.hpp b/include/units/Angle.hpp index 34e837e..3c81e16 100644 --- a/include/units/Angle.hpp +++ b/include/units/Angle.hpp @@ -48,8 +48,6 @@ NEW_UNIT_LITERAL(AngularJerk, rpm3, rot / min / min / min) // Standard orientation constexpr Angle operator""_stRad(long double value) { return Angle(static_cast(value)); } -constexpr Angle operator""_stRad(unsigned long long value) { return Angle(static_cast(value)); } - constexpr Angle operator""_stDeg(long double value) { return static_cast(value) * deg; } constexpr Angle operator""_stDeg(unsigned long long value) { return static_cast(value) * deg; } @@ -99,27 +97,27 @@ static inline Angle constrainAngle180(Angle in) { // Angle to/from operators // Standard orientation -constexpr inline Angle from_stRad(double value) { return Angle(value); } +constexpr inline Angle from_stRad(Number value) { return Angle(value.internal()); } constexpr inline double to_stRad(Angle quantity) { return quantity.internal(); } -constexpr inline Angle from_stDeg(double value) { return value * deg; } +constexpr inline Angle from_stDeg(Number value) { return value * deg; } constexpr inline double to_stDeg(Angle quantity) { return quantity.convert(deg); } -constexpr inline Angle from_stRot(double value) { return value * rot; } +constexpr inline Angle from_stRot(Number value) { return value * rot; } constexpr inline double to_stRot(Angle quantity) { return quantity.convert(rot); } // Compass orientation -constexpr inline Angle from_cRad(double value) { return 90 * deg - Angle(value); } +constexpr inline Angle from_cRad(Number value) { return 90 * deg - Angle(value.internal()); } constexpr inline double to_cRad(Angle quantity) { return quantity.internal(); } -constexpr inline Angle from_cDeg(double value) { return (90 - value) * deg; } +constexpr inline Angle from_cDeg(Number value) { return (90 - value.internal()) * deg; } constexpr inline double to_cDeg(Angle quantity) { return (90 * deg - quantity).convert(deg); } -constexpr inline Angle from_cRot(double value) { return (90 - value) * deg; } +constexpr inline Angle from_cRot(Number value) { return (90 - value.internal()) * deg; } constexpr inline double to_cRot(Angle quantity) { return (90 * deg - quantity).convert(rot); } \ No newline at end of file From d33ed9d18123dafa6cbece9ab9a25c3e5814870f Mon Sep 17 00:00:00 2001 From: Liam Teale Date: Sat, 28 Dec 2024 17:33:16 -0800 Subject: [PATCH 07/10] add `from_##suffix` overload for Number --- include/units/units.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/include/units/units.hpp b/include/units/units.hpp index 63d4cb5..18e7ea7 100644 --- a/include/units/units.hpp +++ b/include/units/units.hpp @@ -292,6 +292,7 @@ template constexpr bool operator>(const Q& lhs, con return os; \ } \ constexpr inline Name from_##suffix(double value) { return Name(value); } \ + constexpr inline Name from_##suffix(Number value) { return Name(value.internal()); } \ constexpr inline double to_##suffix(Name quantity) { return quantity.internal(); } #define NEW_UNIT_LITERAL(Name, suffix, multiple) \ From ceb95b5aede1353f6b43d36bd4ee8d3adf51905a Mon Sep 17 00:00:00 2001 From: Liam Teale Date: Sat, 28 Dec 2024 17:34:37 -0800 Subject: [PATCH 08/10] remove unnecessary `from_##suffix` literal --- include/units/units.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/include/units/units.hpp b/include/units/units.hpp index 18e7ea7..015eb6e 100644 --- a/include/units/units.hpp +++ b/include/units/units.hpp @@ -299,7 +299,6 @@ template constexpr bool operator>(const Q& lhs, con [[maybe_unused]] constexpr Name suffix = multiple; \ constexpr Name operator""_##suffix(long double value) { return static_cast(value) * multiple; } \ constexpr Name operator""_##suffix(unsigned long long value) { return static_cast(value) * multiple; } \ - constexpr inline Name from_##suffix(double value) { return value * multiple; } \ constexpr inline Name from_##suffix(Number value) { return value.internal() * multiple; } \ constexpr inline double to_##suffix(Name quantity) { return quantity.convert(multiple); } From 9f0554c4fd38fa94672ceda4a888be5650865ffe Mon Sep 17 00:00:00 2001 From: Liam Teale Date: Sat, 28 Dec 2024 17:36:15 -0800 Subject: [PATCH 09/10] remove unnecessary Temperature literals --- include/units/Temperature.hpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/include/units/Temperature.hpp b/include/units/Temperature.hpp index be7bf86..faf1070 100644 --- a/include/units/Temperature.hpp +++ b/include/units/Temperature.hpp @@ -48,15 +48,17 @@ constexpr Temperature operator""_fahrenheit(unsigned long long value) { namespace units { -constexpr inline Temperature from_kelvin(double value) { return Temperature(value); } +constexpr inline Temperature from_kelvin(Number value) { return Temperature(value.internal()); } constexpr inline double to_kelvin(Temperature quantity) { return quantity.internal(); } -constexpr inline Temperature from_celsius(double value) { return Temperature(value + 273.15); } +constexpr inline Temperature from_celsius(Number value) { return Temperature(value.internal() + 273.15); } constexpr inline double to_celsius(Temperature quantity) { return quantity.internal() - 273.15; } -constexpr inline Temperature from_fahrenheit(double value) { return Temperature((value - 32) * (5.0 / 9.0) + 273.15); } +constexpr inline Temperature from_fahrenheit(Number value) { + return Temperature((value.internal() - 32) * (5.0 / 9.0) + 273.15); +} constexpr inline double to_fahrenheit(Temperature quantity) { return (quantity.internal() - 273.15) * (9.0 / 5.0) + 32; From b9b78f300b6cedf210438e4928e0e8e388f5a15c Mon Sep 17 00:00:00 2001 From: Liam Teale Date: Sat, 28 Dec 2024 18:19:14 -0800 Subject: [PATCH 10/10] add missing Angle literal --- include/units/Angle.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/units/Angle.hpp b/include/units/Angle.hpp index 3c81e16..40b4f99 100644 --- a/include/units/Angle.hpp +++ b/include/units/Angle.hpp @@ -48,6 +48,8 @@ NEW_UNIT_LITERAL(AngularJerk, rpm3, rot / min / min / min) // Standard orientation constexpr Angle operator""_stRad(long double value) { return Angle(static_cast(value)); } +constexpr Angle operator""_stRad(unsigned long long value) { return Angle(static_cast(value)); } + constexpr Angle operator""_stDeg(long double value) { return static_cast(value) * deg; } constexpr Angle operator""_stDeg(unsigned long long value) { return static_cast(value) * deg; }