From 6a9dcb30def15d28b499c65c6dccca08a9be78ba Mon Sep 17 00:00:00 2001 From: Chip Hogg Date: Thu, 7 Jul 2022 19:00:38 +0000 Subject: [PATCH 01/52] Migrate explicit-`exp` inputs --- example/custom_systems.cpp | 2 +- .../si-hep/include/units/isq/si/hep/area.h | 2 +- .../si-hep/include/units/isq/si/hep/mass.h | 15 +++++++++++---- .../si-hep/include/units/isq/si/hep/momentum.h | 3 ++- .../si-iau/include/units/isq/si/iau/length.h | 2 +- .../include/units/isq/si/international/length.h | 2 +- .../include/units/isq/si/typographic/length.h | 13 +++++++++---- .../si/include/units/isq/si/catalytic_activity.h | 3 ++- src/systems/si/include/units/isq/si/energy.h | 3 ++- src/systems/si/include/units/isq/si/mass.h | 4 +++- test/unit_test/static/quantity_test.cpp | 7 +++---- test/unit_test/static/unit_test.cpp | 6 +++--- 12 files changed, 39 insertions(+), 23 deletions(-) diff --git a/example/custom_systems.cpp b/example/custom_systems.cpp index b2c3419d..4604be9e 100644 --- a/example/custom_systems.cpp +++ b/example/custom_systems.cpp @@ -54,7 +54,7 @@ using length = quantity; namespace fps { -struct foot : named_scaled_unit(), metre> {}; +struct foot : named_scaled_unit(), metre> {}; struct yard : named_scaled_unit(), foot> {}; struct dim_length : base_dimension<"L", foot> {}; diff --git a/src/systems/si-hep/include/units/isq/si/hep/area.h b/src/systems/si-hep/include/units/isq/si/hep/area.h index e08b59eb..658a12a8 100644 --- a/src/systems/si-hep/include/units/isq/si/hep/area.h +++ b/src/systems/si-hep/include/units/isq/si/hep/area.h @@ -37,7 +37,7 @@ namespace units::isq::si::hep { // effective cross-sectional area according to EU council directive 80/181/EEC // https://eur-lex.europa.eu/legal-content/EN/TXT/PDF/?uri=CELEX:01980L0181-20090527#page=10 // https://www.fedlex.admin.ch/eli/cc/1994/3109_3109_3109/de -struct barn : named_scaled_unit(), square_metre> {}; +struct barn : named_scaled_unit(as_magnitude<10>()), square_metre> {}; struct yocto_barn : prefixed_unit {}; struct zepto_barn : prefixed_unit {}; struct atto_barn : prefixed_unit {}; diff --git a/src/systems/si-hep/include/units/isq/si/hep/mass.h b/src/systems/si-hep/include/units/isq/si/hep/mass.h index e4a895e0..754c2a61 100644 --- a/src/systems/si-hep/include/units/isq/si/hep/mass.h +++ b/src/systems/si-hep/include/units/isq/si/hep/mass.h @@ -44,7 +44,8 @@ namespace units::isq::si::hep { struct eV_per_c2 : named_scaled_unit(), kilogram> {}; + as_magnitude() * pow<-35>(as_magnitude<10>()), + kilogram> {}; struct feV_per_c2 : prefixed_unit {}; struct peV_per_c2 : prefixed_unit {}; struct neV_per_c2 : prefixed_unit {}; @@ -60,11 +61,17 @@ struct PeV_per_c2 : prefixed_unit {}; struct EeV_per_c2 : prefixed_unit {}; struct YeV_per_c2 : prefixed_unit {}; struct electron_mass : - named_scaled_unit(), kilogram> {}; + named_scaled_unit() * pow<-31>(as_magnitude<10>()), + kilogram> {}; struct proton_mass : - named_scaled_unit(), kilogram> {}; + named_scaled_unit() * pow<-27>(as_magnitude<10>()), + kilogram> {}; struct neutron_mass : - named_scaled_unit(), kilogram> {}; + named_scaled_unit() * pow<-27>(as_magnitude<10>()), + kilogram> {}; struct dim_mass : isq::dim_mass {}; diff --git a/src/systems/si-hep/include/units/isq/si/hep/momentum.h b/src/systems/si-hep/include/units/isq/si/hep/momentum.h index c6791501..ab87fb4a 100644 --- a/src/systems/si-hep/include/units/isq/si/hep/momentum.h +++ b/src/systems/si-hep/include/units/isq/si/hep/momentum.h @@ -41,7 +41,8 @@ namespace units::isq::si::hep { struct kilogram_metre_per_second : derived_unit {}; struct eV_per_c : - named_scaled_unit(), + named_scaled_unit() * pow<-35>(as_magnitude<10>()), kilogram_metre_per_second> {}; struct feV_per_c : prefixed_unit {}; struct peV_per_c : prefixed_unit {}; diff --git a/src/systems/si-iau/include/units/isq/si/iau/length.h b/src/systems/si-iau/include/units/isq/si/iau/length.h index d2e184a1..e4066edb 100644 --- a/src/systems/si-iau/include/units/isq/si/iau/length.h +++ b/src/systems/si-iau/include/units/isq/si/iau/length.h @@ -42,7 +42,7 @@ struct light_year : named_scaled_unit(), si::metre> {}; // https://en.wikipedia.org/wiki/Angstrom -struct angstrom : named_scaled_unit(), si::metre> {}; +struct angstrom : named_scaled_unit(as_magnitude<10>()), si::metre> {}; #ifndef UNITS_NO_LITERALS diff --git a/src/systems/si-international/include/units/isq/si/international/length.h b/src/systems/si-international/include/units/isq/si/international/length.h index b61bd2cf..5e3bab57 100644 --- a/src/systems/si-international/include/units/isq/si/international/length.h +++ b/src/systems/si-international/include/units/isq/si/international/length.h @@ -37,7 +37,7 @@ namespace units::isq::si::international { // si::international yard // https://en.wikipedia.org/wiki/International_yard_and_pound -struct yard : named_scaled_unit(), si::metre> {}; +struct yard : named_scaled_unit(), si::metre> {}; // si::international foot // https://en.wikipedia.org/wiki/Foot_(unit)#International_foot diff --git a/src/systems/si-typographic/include/units/isq/si/typographic/length.h b/src/systems/si-typographic/include/units/isq/si/typographic/length.h index e69c31c6..ecd56afd 100644 --- a/src/systems/si-typographic/include/units/isq/si/typographic/length.h +++ b/src/systems/si-typographic/include/units/isq/si/typographic/length.h @@ -38,11 +38,16 @@ namespace units::isq::si::typographic { // TODO Conflicts with (https://en.wikipedia.org/wiki/Pica_(typography)), verify correctness of below conversion factors // and provide hyperlinks to definitions struct pica_comp : - named_scaled_unit(), si::metre> {}; -struct pica_prn : named_scaled_unit(), si::metre> {}; + named_scaled_unit() * pow<-9>(as_magnitude<10>()), si::metre> {}; +struct pica_prn : + named_scaled_unit() * pow<-3>(as_magnitude<10>()), + si::metre> {}; struct point_comp : - named_scaled_unit(), si::metre> {}; -struct point_prn : named_scaled_unit(), si::metre> {}; + named_scaled_unit() * pow<-4>(as_magnitude<10>()), + si::metre> {}; +struct point_prn : + named_scaled_unit() * pow<-4>(as_magnitude<10>()), + si::metre> {}; #ifndef UNITS_NO_LITERALS diff --git a/src/systems/si/include/units/isq/si/catalytic_activity.h b/src/systems/si/include/units/isq/si/catalytic_activity.h index 07ca426f..562eb0fa 100644 --- a/src/systems/si/include/units/isq/si/catalytic_activity.h +++ b/src/systems/si/include/units/isq/si/catalytic_activity.h @@ -58,7 +58,8 @@ struct exakatal : prefixed_unit {}; struct zettakatal : prefixed_unit {}; struct yottakatal : prefixed_unit {}; -struct enzyme_unit : named_scaled_unit(), katal> {}; +struct enzyme_unit : + named_scaled_unit() * pow<-6>(as_magnitude<10>()), katal> {}; struct dim_catalytic_activity : isq::dim_catalytic_activity {}; diff --git a/src/systems/si/include/units/isq/si/energy.h b/src/systems/si/include/units/isq/si/energy.h index cf0eba26..c9eca1cb 100644 --- a/src/systems/si/include/units/isq/si/energy.h +++ b/src/systems/si/include/units/isq/si/energy.h @@ -56,7 +56,8 @@ struct yottajoule : prefixed_unit {}; // N.B. electron charge (and eV) is an exact constant: // https://www.bipm.org/documents/20126/41483022/SI-Brochure-9.pdf#page=147 struct electronvolt : - named_scaled_unit(), joule> {}; + named_scaled_unit() * pow<-19>(as_magnitude<10>()), joule> {}; struct gigaelectronvolt : prefixed_unit {}; struct dim_energy : isq::dim_energy {}; diff --git a/src/systems/si/include/units/isq/si/mass.h b/src/systems/si/include/units/isq/si/mass.h index 53a574f4..e4d935d1 100644 --- a/src/systems/si/include/units/isq/si/mass.h +++ b/src/systems/si/include/units/isq/si/mass.h @@ -79,7 +79,9 @@ struct zettatonne : prefixed_unit {}; struct yottatonne : prefixed_unit {}; struct dalton : - named_scaled_unit(), kilogram> {}; + named_scaled_unit() * pow<-27>(as_magnitude<10>()), + kilogram> {}; struct dim_mass : isq::dim_mass {}; diff --git a/test/unit_test/static/quantity_test.cpp b/test/unit_test/static/quantity_test.cpp index cf346a27..a47c5782 100644 --- a/test/unit_test/static/quantity_test.cpp +++ b/test/unit_test/static/quantity_test.cpp @@ -579,8 +579,7 @@ static_assert(is_same_v>); -static_assert( - compare(), metre>, std::int64_t>>); +static_assert(compare(), metre>, std::int64_t>>); static_assert( compare, exponent>, scaled_unit(), unknown_coherent_unit>, std::int64_t>>); @@ -590,7 +589,7 @@ static_assert( static_assert(compare>); static_assert(compare>, - scaled_unit(), unknown_coherent_unit>, std::int64_t>>); + scaled_unit(), unknown_coherent_unit>, std::int64_t>>); static_assert(compare(), one>, std::int64_t>>); static_assert(compare>); static_assert( @@ -889,7 +888,7 @@ static_assert(is_same_v, units::exponent>, scaled_unit(), unknown_coherent_unit>, std::int64_t>>); static_assert( - is_same_v(), metre>, std::int64_t>>); + is_same_v(), metre>, std::int64_t>>); #else diff --git a/test/unit_test/static/unit_test.cpp b/test/unit_test/static/unit_test.cpp index 128fac3d..c4d4baf6 100644 --- a/test/unit_test/static/unit_test.cpp +++ b/test/unit_test/static/unit_test.cpp @@ -36,12 +36,12 @@ using namespace units::isq; struct metre : named_unit {}; struct centimetre : prefixed_unit {}; struct kilometre : prefixed_unit {}; -struct yard : named_scaled_unit(), metre> {}; +struct yard : named_scaled_unit(), metre> {}; struct foot : named_scaled_unit(), yard> {}; struct dim_length : base_dimension<"length", metre> {}; struct second : named_unit {}; -struct hour : named_scaled_unit(), second> {}; +struct hour : named_scaled_unit(), second> {}; struct dim_time : base_dimension<"time", second> {}; struct kelvin : named_unit {}; @@ -60,7 +60,7 @@ struct kilometre_per_hour : derived_scaled_unit); static_assert(equivalent); static_assert(compare(), metre>>, metre>); -static_assert(compare(), metre>>, centimetre>); +static_assert(compare(), metre>>, centimetre>); static_assert(compare>, yard>); static_assert(compare(), metre>>, foot>); static_assert(compare>, kilometre_per_hour>); From 7fd6913b732d6226ff50f86a7a9269213465b611 Mon Sep 17 00:00:00 2001 From: Chip Hogg Date: Thu, 7 Jul 2022 19:19:08 +0000 Subject: [PATCH 02/52] Replace `exp` with `0` everywhere, and remove it This lets us remove a ton of special-casing throughout the codebase, and just generally makes things a lot simpler. We also remove the ability to take rational powers of `ratio`, including `sqrt` and `cbrt` helpers, because these are intrinsically ill-defined. Fixes #369. --- example/custom_systems.cpp | 5 +- src/core/include/units/bits/ratio_maths.h | 112 ++------------------- src/core/include/units/chrono.h | 7 +- src/core/include/units/magnitude.h | 8 +- src/core/include/units/ratio.h | 117 ++++------------------ test/unit_test/runtime/magnitude_test.cpp | 7 -- test/unit_test/static/ratio_test.cpp | 42 -------- 7 files changed, 28 insertions(+), 270 deletions(-) diff --git a/example/custom_systems.cpp b/example/custom_systems.cpp index 4604be9e..90a63dae 100644 --- a/example/custom_systems.cpp +++ b/example/custom_systems.cpp @@ -94,10 +94,7 @@ void unknown_dimensions() std::cout << si_fps_area << "\n"; } -std::ostream& operator<<(std::ostream& os, const ratio& r) -{ - return os << "ratio{" << r.num << ", " << r.den << ", " << r.exp << "}"; -} +std::ostream& operator<<(std::ostream& os, const ratio& r) { return os << "ratio{" << r.num << ", " << r.den << "}"; } template std::ostream& operator<<(std::ostream& os, const U& u) diff --git a/src/core/include/units/bits/ratio_maths.h b/src/core/include/units/bits/ratio_maths.h index d9a6494a..a6cbea4c 100644 --- a/src/core/include/units/bits/ratio_maths.h +++ b/src/core/include/units/bits/ratio_maths.h @@ -39,108 +39,20 @@ template return v < 0 ? -v : v; } -// the following functions enable gcd and related computations on ratios -// with exponents. They avoid overflow. Further information here: -// https://github.com/mpusz/units/issues/62#issuecomment-588152833 - -// Computes (a * b) mod m relies on unsigned integer arithmetic, should not -// overflow -[[nodiscard]] constexpr std::uint64_t mulmod(std::uint64_t a, std::uint64_t b, std::uint64_t m) -{ - std::uint64_t res = 0; - - if (b >= m) { - if (m > UINT64_MAX / 2u) { - b -= m; - } else { - b %= m; - } - } - - while (a != 0) { - if (a & 1) { - if (b >= m - res) { - res -= m; - } - res += b; - } - a >>= 1; - - std::uint64_t temp_b = b; - if (b >= m - b) { - temp_b -= m; - } - b += temp_b; - } - - return res; -} - -// Calculates (a ^ e) mod m , should not overflow. -[[nodiscard]] constexpr std::uint64_t modpow(std::uint64_t a, std::uint64_t e, std::uint64_t m) -{ - a %= m; - std::uint64_t result = 1; - - while (e > 0) { - if (e & 1) { - result = mulmod(result, a, m); - } - a = mulmod(a, a, m); - e >>= 1; - } - return result; -} - -// gcd(a * 10 ^ e, b), should not overflow -[[nodiscard]] constexpr std::intmax_t gcdpow(std::intmax_t a, std::intmax_t e, std::intmax_t b) noexcept -{ - assert(a > 0); - assert(e >= 0); - assert(b > 0); - - // gcd(i, j) = gcd(j, i mod j) for j != 0 Euclid; - // - // gcd(a 10^e, b) = gcd(b, a 10^e mod b) - // - // (a 10^e) mod b -> [ (a mod b) (10^e mod b) ] mod b - - return std::gcd( - b, static_cast(mulmod(static_cast(a % b), - modpow(10, static_cast(e), static_cast(b)), - static_cast(b)))); -} - -constexpr void cwap(std::intmax_t& lhs, std::intmax_t& rhs) -{ - std::intmax_t tmp = lhs; - lhs = rhs; - rhs = tmp; -} - -// Computes the rational gcd of n1/d1 x 10^e1 and n2/d2 x 10^e2 -[[nodiscard]] constexpr auto gcd_frac(std::intmax_t n1, std::intmax_t d1, std::intmax_t e1, std::intmax_t n2, - std::intmax_t d2, std::intmax_t e2) noexcept +// Computes the rational gcd of n1/d1 and n2/d2 +[[nodiscard]] constexpr auto gcd_frac(std::intmax_t n1, std::intmax_t d1, std::intmax_t n2, std::intmax_t d2) noexcept { // Short cut for equal ratios - if (n1 == n2 && d1 == d2 && e1 == e2) { - return std::array{n1, d1, e1}; + if (n1 == n2 && d1 == d2) { + return std::array{n1, d1}; } - if (e2 > e1) { - detail::cwap(n1, n2); - detail::cwap(d1, d2); - detail::cwap(e1, e2); - } - - std::intmax_t exp = e2; // minimum - // gcd(a/b,c/d) = gcd(a⋅d, c⋅b) / b⋅d assert(std::numeric_limits::max() / n1 > d2); assert(std::numeric_limits::max() / n2 > d1); - std::intmax_t num = detail::gcdpow(n1 * d2, e1 - e2, n2 * d1); + std::intmax_t num = std::gcd(n1 * d2, n2 * d1); assert(std::numeric_limits::max() / d1 > d2); @@ -148,29 +60,19 @@ constexpr void cwap(std::intmax_t& lhs, std::intmax_t& rhs) std::intmax_t gcd = std::gcd(num, den); - return std::array{num / gcd, den / gcd, exp}; + return std::array{num / gcd, den / gcd}; } -constexpr void normalize(std::intmax_t& num, std::intmax_t& den, std::intmax_t& exp) +constexpr void normalize(std::intmax_t& num, std::intmax_t& den) { if (num == 0) { den = 1; - exp = 0; return; } std::intmax_t gcd = std::gcd(num, den); num = num * (den < 0 ? -1 : 1) / gcd; den = detail::abs(den) / gcd; - - while (num % 10 == 0) { - num /= 10; - ++exp; - } - while (den % 10 == 0) { - den /= 10; - --exp; - } } [[nodiscard]] constexpr std::intmax_t safe_multiply(std::intmax_t lhs, std::intmax_t rhs) diff --git a/src/core/include/units/chrono.h b/src/core/include/units/chrono.h index 91b4ab6b..d7c9fc91 100644 --- a/src/core/include/units/chrono.h +++ b/src/core/include/units/chrono.h @@ -75,12 +75,7 @@ constexpr std::intmax_t pow_10(std::intmax_t v) template constexpr auto to_std_ratio_impl() { - if constexpr (R.exp == 0) - return std::ratio{}; - else if constexpr (R.exp > 0) - return std::ratio{}; - else - return std::ratio{}; + return std::ratio{}; } } // namespace detail diff --git a/src/core/include/units/magnitude.h b/src/core/include/units/magnitude.h index 1257e132..47bb1aee 100644 --- a/src/core/include/units/magnitude.h +++ b/src/core/include/units/magnitude.h @@ -189,9 +189,6 @@ constexpr widen_t compute_base_power(BasePower auto bp) if (bp.power.den != 1) { throw std::invalid_argument{"Rational powers not yet supported"}; } - if (bp.power.exp < 0) { - throw std::invalid_argument{"Unsupported exp value"}; - } if (bp.power.num < 0) { if constexpr (std::is_integral_v) { @@ -344,7 +341,7 @@ inline constexpr bool is_base_power_pack_valid = all_base_powers_valid & constexpr bool is_rational(BasePower auto bp) { - return std::is_integral_v && (bp.power.den == 1) && (bp.power.exp >= 0); + return std::is_integral_v && (bp.power.den == 1); } constexpr bool is_integral(BasePower auto bp) { return is_rational(bp) && bp.power.num > 0; } @@ -652,8 +649,7 @@ template requires(R.num > 0) constexpr Magnitude auto as_magnitude() { - return pow(detail::prime_factorization_v<10>) * detail::prime_factorization_v / - detail::prime_factorization_v; + return detail::prime_factorization_v / detail::prime_factorization_v; } namespace detail { diff --git a/src/core/include/units/ratio.h b/src/core/include/units/ratio.h index b57ce06d..a469d4c2 100644 --- a/src/core/include/units/ratio.h +++ b/src/core/include/units/ratio.h @@ -43,42 +43,28 @@ constexpr ratio inverse(const ratio& r); /** * @brief Provides compile-time rational arithmetic support. * - * This class is really similar to @c std::ratio but gets an additional `Exp` - * template parameter that defines the exponent of the ratio. Another important - * difference is the fact that the objects of that class are used as class NTTPs - * rather then a type template parameter kind. + * This class is really similar to @c std::ratio. An important difference is the fact that the objects of that class + * are used as class NTTPs rather then a type template parameter kind. */ struct ratio { std::intmax_t num; std::intmax_t den; - std::intmax_t exp; - constexpr explicit(false) ratio(std::intmax_t n, std::intmax_t d = 1, std::intmax_t e = 0) : num(n), den(d), exp(e) + constexpr explicit(false) ratio(std::intmax_t n, std::intmax_t d = 1) : num(n), den(d) { gsl_Expects(den != 0); - detail::normalize(num, den, exp); + detail::normalize(num, den); } [[nodiscard]] friend constexpr bool operator==(const ratio&, const ratio&) = default; [[nodiscard]] friend constexpr auto operator<=>(const ratio& lhs, const ratio& rhs) { return (lhs - rhs).num <=> 0; } - [[nodiscard]] friend constexpr ratio operator-(const ratio& r) { return ratio(-r.num, r.den, r.exp); } + [[nodiscard]] friend constexpr ratio operator-(const ratio& r) { return ratio(-r.num, r.den); } [[nodiscard]] friend constexpr ratio operator+(ratio lhs, ratio rhs) { - // First, get the inputs into a common exponent. - const auto common_exp = std::min(lhs.exp, rhs.exp); - auto commonify = [common_exp](ratio& r) { - while (r.exp > common_exp) { - r.num *= 10; - --r.exp; - } - }; - commonify(lhs); - commonify(rhs); - - return ratio{lhs.num * rhs.den + lhs.den * rhs.num, lhs.den * rhs.den, common_exp}; + return ratio{lhs.num * rhs.den + lhs.den * rhs.num, lhs.den * rhs.den}; } [[nodiscard]] friend constexpr ratio operator-(const ratio& lhs, const ratio& rhs) { return lhs + (-rhs); } @@ -88,96 +74,31 @@ struct ratio { const std::intmax_t gcd1 = std::gcd(lhs.num, rhs.den); const std::intmax_t gcd2 = std::gcd(rhs.num, lhs.den); return ratio(detail::safe_multiply(lhs.num / gcd1, rhs.num / gcd2), - detail::safe_multiply(lhs.den / gcd2, rhs.den / gcd1), lhs.exp + rhs.exp); + detail::safe_multiply(lhs.den / gcd2, rhs.den / gcd1)); } [[nodiscard]] friend constexpr ratio operator/(const ratio& lhs, const ratio& rhs) { return lhs * inverse(rhs); } - [[nodiscard]] friend constexpr std::intmax_t numerator(const ratio& r) - { - std::intmax_t true_num = r.num; - for (auto i = r.exp; i > 0; --i) { - true_num *= 10; - } - return true_num; - } + [[nodiscard]] friend constexpr std::intmax_t numerator(const ratio& r) { return r.num; } - [[nodiscard]] friend constexpr std::intmax_t denominator(const ratio& r) - { - std::intmax_t true_den = r.den; - for (auto i = r.exp; i < 0; ++i) { - true_den *= 10; - } - return true_den; - } + [[nodiscard]] friend constexpr std::intmax_t denominator(const ratio& r) { return r.den; } }; -[[nodiscard]] constexpr ratio inverse(const ratio& r) { return ratio(r.den, r.num, -r.exp); } +[[nodiscard]] constexpr ratio inverse(const ratio& r) { return ratio(r.den, r.num); } -[[nodiscard]] constexpr bool is_integral(const ratio& r) -{ - if (r.exp < 0) { - return false; - } else { - return detail::gcdpow(r.num, r.exp, r.den) == r.den; - } -} +[[nodiscard]] constexpr bool is_integral(const ratio& r) { return r.num % r.den == 0; } -namespace detail { - -[[nodiscard]] constexpr auto make_exp_align(const ratio& r, std::intmax_t alignment) -{ - gsl_Expects(alignment > 0); - const std::intmax_t rem = r.exp % alignment; - - if (rem == 0) { // already aligned - return std::array{r.num, r.den, r.exp}; - } - - if (r.exp > 0) { // remainder is positive - return std::array{r.num * ipow10(rem), r.den, r.exp - rem}; - } - - // remainder is negative - return std::array{r.num, r.den * ipow10(-rem), r.exp - rem}; -} - -template - requires gt_zero -[[nodiscard]] constexpr ratio root(const ratio& r) -{ - if constexpr (N == 1) { - return r; - } else { - if (r.num == 0) { - return ratio(0); - } - - const auto aligned = make_exp_align(r, N); - return ratio(iroot(aligned[0]), iroot(aligned[1]), aligned[2] / N); - } -} - -} // namespace detail - -template - requires detail::non_zero +template [[nodiscard]] constexpr ratio pow(const ratio& r) { if constexpr (Num == 0) { return ratio(1); - } else if constexpr (Num == Den) { + } else if constexpr (Num == 1) { return r; } else { - // simplify factors first and compute power for positive exponent - constexpr std::intmax_t gcd = std::gcd(Num, Den); - constexpr std::intmax_t num = detail::abs(Num / gcd); - constexpr std::intmax_t den = detail::abs(Den / gcd); + const ratio result = detail::pow_impl(r); - // integer root loses precision so do pow first - const ratio result = detail::root(detail::pow_impl(r)); - - if constexpr (Num * Den < 0) { // account for negative exponent + if constexpr (Num < 0) { // account for negative exponent return inverse(result); } else { return result; @@ -185,15 +106,11 @@ template } } -[[nodiscard]] constexpr ratio sqrt(const ratio& r) { return pow<1, 2>(r); } - -[[nodiscard]] constexpr ratio cbrt(const ratio& r) { return pow<1, 3>(r); } - // common_ratio [[nodiscard]] constexpr ratio common_ratio(const ratio& r1, const ratio& r2) { - const auto res = detail::gcd_frac(r1.num, r1.den, r1.exp, r2.num, r2.den, r2.exp); - return ratio(res[0], res[1], res[2]); + const auto res = detail::gcd_frac(r1.num, r1.den, r2.num, r2.den); + return ratio(res[0], res[1]); } } // namespace units diff --git a/test/unit_test/runtime/magnitude_test.cpp b/test/unit_test/runtime/magnitude_test.cpp index 9fa0aa98..8b80a60d 100644 --- a/test/unit_test/runtime/magnitude_test.cpp +++ b/test/unit_test/runtime/magnitude_test.cpp @@ -154,13 +154,6 @@ TEST_CASE("make_ratio performs prime factorization correctly") SECTION("Supports fractions") { CHECK(as_magnitude() == magnitude{}); } - SECTION("Supports nonzero exp") - { - constexpr ratio r{3, 1, 2}; - REQUIRE(r.exp == 2); - CHECK(as_magnitude() == as_magnitude<300>()); - } - SECTION("Can handle prime factor which would be large enough to overflow int") { // This was taken from a case which failed when we used `int` for our base to store prime numbers. diff --git a/test/unit_test/static/ratio_test.cpp b/test/unit_test/static/ratio_test.cpp index ad966950..87d36443 100644 --- a/test/unit_test/static/ratio_test.cpp +++ b/test/unit_test/static/ratio_test.cpp @@ -28,11 +28,6 @@ using namespace units; static_assert(ratio(2, 4) == ratio(1, 2)); -// basic exponents tests -static_assert(ratio(2, 40, 1) == ratio(1, 20, 1)); -static_assert(ratio(20, 4, -1) == ratio(10, 2, -1)); -static_assert(ratio(200, 5) == ratio(20'000, 50, -1)); - static_assert(ratio(1) * ratio(3, 8) == ratio(3, 8)); static_assert(ratio(3, 8) * ratio(1) == ratio(3, 8)); static_assert(ratio(4) * ratio(1, 8) == ratio(1, 2)); @@ -45,21 +40,12 @@ static_assert(-ratio(3, 8) == ratio(-3, 8)); // ratio addition static_assert(ratio(1, 2) + ratio(1, 3) == ratio(5, 6)); -static_assert(ratio(1, 3, 2) + ratio(11, 6) == ratio(211, 6)); // 100/3 + 11/6 - -// multiply with exponents -static_assert(ratio(1, 8, 2) * ratio(2, 1, 4) == ratio(1, 4, 6)); -static_assert(ratio(1, 2, -4) * ratio(8, 1, 3) == ratio(4, 1, -1)); static_assert(ratio(4) / ratio(2) == ratio(2)); static_assert(ratio(2) / ratio(8) == ratio(1, 4)); static_assert(ratio(1, 8) / ratio(2) == ratio(1, 16)); static_assert(ratio(6) / ratio(3) == ratio(2)); -// divide with exponents -static_assert(ratio(1, 8, -6) / ratio(2, 1, -8) == ratio(1, 16, 2)); -static_assert(ratio(6, 1, 4) / ratio(3) == ratio(2, 1, 4)); - static_assert(pow<0>(ratio(2)) == ratio(1)); static_assert(pow<1>(ratio(2)) == ratio(2)); static_assert(pow<2>(ratio(2)) == ratio(4)); @@ -69,27 +55,6 @@ static_assert(pow<1>(ratio(1, 2)) == ratio(1, 2)); static_assert(pow<2>(ratio(1, 2)) == ratio(1, 4)); static_assert(pow<3>(ratio(1, 2)) == ratio(1, 8)); -// pow with exponents -static_assert(pow<2>(ratio(1, 2, 3)) == ratio(1, 4, 6)); -static_assert(pow<4, 2>(ratio(1, 2, 3)) == ratio(1, 4, 6)); -static_assert(pow<3>(ratio(1, 2, -6)) == ratio(1, 8, -18)); - -static_assert(sqrt(ratio(9)) == ratio(3)); -static_assert(cbrt(ratio(27)) == ratio(3)); -static_assert(sqrt(ratio(4)) == ratio(2)); -static_assert(cbrt(ratio(8)) == ratio(2)); -static_assert(sqrt(ratio(1)) == ratio(1)); -static_assert(cbrt(ratio(1)) == ratio(1)); -static_assert(sqrt(ratio(0)) == ratio(0)); -static_assert(cbrt(ratio(0)) == ratio(0)); -static_assert(sqrt(ratio(1, 4)) == ratio(1, 2)); -static_assert(cbrt(ratio(1, 8)) == ratio(1, 2)); - -// sqrt with exponents -static_assert(sqrt(ratio(9, 1, 2)) == ratio(3, 1, 1)); -static_assert(cbrt(ratio(27, 1, 3)) == ratio(3, 1, 1)); -static_assert(cbrt(ratio(27, 1, 2)) == ratio(13, 1, 0)); - // common_ratio static_assert(common_ratio(ratio(1), ratio(1000)) == ratio(1)); static_assert(common_ratio(ratio(1000), ratio(1)) == ratio(1)); @@ -98,20 +63,13 @@ static_assert(common_ratio(ratio(1, 1000), ratio(1)) == ratio(1, 1000)); static_assert(common_ratio(ratio(100, 1), ratio(10, 1)) == ratio(10, 1)); static_assert(common_ratio(ratio(100, 1), ratio(1, 10)) == ratio(1, 10)); -// common ratio with exponents -static_assert(common_ratio(ratio(1), ratio(1, 1, 3)) == ratio(1)); -static_assert(common_ratio(ratio(10, 1, -1), ratio(1, 1, -3)) == ratio(1, 1, -3)); - // numerator and denominator static_assert(numerator(ratio(3, 4)) == 3); -static_assert(numerator(ratio(3, 7, 2)) == 300); static_assert(denominator(ratio(3, 4)) == 4); -static_assert(denominator(ratio(3, 7, -2)) == 700); // comparison static_assert((ratio(3, 4) <=> ratio(6, 8)) == (0 <=> 0)); static_assert((ratio(3, 4) <=> ratio(-3, 4)) == (0 <=> -1)); static_assert((ratio(-3, 4) <=> ratio(3, -4)) == (0 <=> 0)); -static_assert((ratio(1, 1, 1) <=> ratio(10)) == (0 <=> 0)); } // namespace From 7e591115fa4cc0d8573f5df94ca5faebd5c93626 Mon Sep 17 00:00:00 2001 From: Chip Hogg Date: Thu, 7 Jul 2022 19:22:26 +0000 Subject: [PATCH 03/52] Remove ratio's `numerator()` and `denominator()` These have now become trivial. --- src/core/include/units/magnitude.h | 10 +++++----- src/core/include/units/ratio.h | 4 ---- test/unit_test/static/ratio_test.cpp | 4 ---- 3 files changed, 5 insertions(+), 13 deletions(-) diff --git a/src/core/include/units/magnitude.h b/src/core/include/units/magnitude.h index 47bb1aee..3e1e7a19 100644 --- a/src/core/include/units/magnitude.h +++ b/src/core/include/units/magnitude.h @@ -198,7 +198,7 @@ constexpr widen_t compute_base_power(BasePower auto bp) } } - auto power = numerator(bp.power); + auto power = bp.power.num; return int_power(static_cast>(bp.get_base()), power); } @@ -495,8 +495,8 @@ namespace detail { template constexpr auto integer_part(magnitude) { - constexpr auto power_num = numerator(BP.power); - constexpr auto power_den = denominator(BP.power); + constexpr auto power_num = BP.power.num; + constexpr auto power_den = BP.power.den; if constexpr (std::is_integral_v && (power_num >= power_den)) { constexpr auto largest_integer_power = [=](BasePower auto bp) { @@ -553,7 +553,7 @@ namespace detail { template constexpr auto remove_positive_power(magnitude m) { - if constexpr (numerator(BP.power) < 0) { + if constexpr (BP.power.num < 0) { return m; } else { return magnitude<>{}; @@ -659,7 +659,7 @@ constexpr ratio get_power(T base, magnitude) return ((BPs.get_base() == base ? BPs.power : ratio{0}) + ... + ratio{0}); } -constexpr std::intmax_t integer_part(ratio r) { return numerator(r) / denominator(r); } +constexpr std::intmax_t integer_part(ratio r) { return r.num / r.den; } constexpr std::intmax_t extract_power_of_10(Magnitude auto m) { diff --git a/src/core/include/units/ratio.h b/src/core/include/units/ratio.h index a469d4c2..d0bd8ec3 100644 --- a/src/core/include/units/ratio.h +++ b/src/core/include/units/ratio.h @@ -78,10 +78,6 @@ struct ratio { } [[nodiscard]] friend constexpr ratio operator/(const ratio& lhs, const ratio& rhs) { return lhs * inverse(rhs); } - - [[nodiscard]] friend constexpr std::intmax_t numerator(const ratio& r) { return r.num; } - - [[nodiscard]] friend constexpr std::intmax_t denominator(const ratio& r) { return r.den; } }; [[nodiscard]] constexpr ratio inverse(const ratio& r) { return ratio(r.den, r.num); } diff --git a/test/unit_test/static/ratio_test.cpp b/test/unit_test/static/ratio_test.cpp index 87d36443..02828115 100644 --- a/test/unit_test/static/ratio_test.cpp +++ b/test/unit_test/static/ratio_test.cpp @@ -63,10 +63,6 @@ static_assert(common_ratio(ratio(1, 1000), ratio(1)) == ratio(1, 1000)); static_assert(common_ratio(ratio(100, 1), ratio(10, 1)) == ratio(10, 1)); static_assert(common_ratio(ratio(100, 1), ratio(1, 10)) == ratio(1, 10)); -// numerator and denominator -static_assert(numerator(ratio(3, 4)) == 3); -static_assert(denominator(ratio(3, 4)) == 4); - // comparison static_assert((ratio(3, 4) <=> ratio(6, 8)) == (0 <=> 0)); static_assert((ratio(3, 4) <=> ratio(-3, 4)) == (0 <=> -1)); From f6332c849fbd0fb76a1fed2ce44e600e663e886f Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Tue, 26 Jul 2022 09:38:04 +0200 Subject: [PATCH 04/52] build(conan): `self.info.header_only()` will be removed in Conan 2.0 --- conanfile.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/conanfile.py b/conanfile.py index a673412e..3f6e399e 100644 --- a/conanfile.py +++ b/conanfile.py @@ -32,7 +32,7 @@ from conans.errors import ConanInvalidConfiguration # TODO replace with new tools for Conan 2.0 from conans.tools import check_min_cppstd, get_env -required_conan_version = ">=1.48.0" +required_conan_version = ">=1.50.0" class MPUnitsConan(ConanFile): @@ -169,7 +169,7 @@ class MPUnitsConan(ConanFile): cmake.test() def package_id(self): - self.info.header_only() + self.info.clear() def package(self): copy( From 2405c83da17eb2d9c4f5b5bc9be1543383de5408 Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Tue, 26 Jul 2022 09:53:26 +0200 Subject: [PATCH 05/52] build(conan): Switched to `conan.tools.build.check_min_cppstd` --- conanfile.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/conanfile.py b/conanfile.py index 3f6e399e..40eb99fa 100644 --- a/conanfile.py +++ b/conanfile.py @@ -25,12 +25,13 @@ import re from conan import ConanFile from conan.tools.cmake import CMake, CMakeDeps, CMakeToolchain +from conan.tools.build import check_min_cppstd from conan.tools.files import copy, load, rmdir from conan.tools.scm import Version from conans.errors import ConanInvalidConfiguration -# TODO replace with new tools for Conan 2.0 -from conans.tools import check_min_cppstd, get_env +# TODO remove when `CONAN_RUN_TESTS` will be replaced with a `[conf]` variable +from conans.tools import get_env required_conan_version = ">=1.50.0" From 5dcfa7077ef772e4d0f70e937d65dc6d3ae75bde Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Tue, 26 Jul 2022 10:02:15 +0200 Subject: [PATCH 06/52] docs: Dependencies chapter updated --- docs/usage.rst | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/usage.rst b/docs/usage.rst index 9e1ebe10..0cc583ea 100644 --- a/docs/usage.rst +++ b/docs/usage.rst @@ -22,8 +22,8 @@ This repository contains three independent CMake-based projects: - when this library will become part of the C++ standard it will have no external dependencies but until then it depends on: - - `{fmt} `_ to provide text formatting of quantities. - `gsl-lite `_ to verify runtime contracts with the ``gsl_Expects`` macro. + - [for compilers other than VS2022] `{fmt} `_ to provide text formatting of quantities. - [only for clang < 14 with libc++] `range-v3 `_ to provide needed C++20 concepts and utilities. - *.* @@ -36,9 +36,13 @@ This repository contains three independent CMake-based projects: - `linear algebra `_ library based on proposal `P1385 `_ used in some examples and tests. + + - in case you also want to build the project's documentation you will need: + - `Doxygen `_ to extract C++ entities information from the source code. - `Sphinx `_ to build the documentation. + - `Sphinx ReadTheDocs Theme `_ - `Sphinx recommonmark `_. - `Breathe `_ as a bridge between the Sphinx and Doxygen documentation systems. From a1d43c2613f6b54f5eee742139dda3b5c5505b2d Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Tue, 26 Jul 2022 11:30:38 +0200 Subject: [PATCH 07/52] chore: Conan 1.X temporary files added to `.gitignore` --- .gitignore | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.gitignore b/.gitignore index a4547914..f957836c 100644 --- a/.gitignore +++ b/.gitignore @@ -46,3 +46,11 @@ CMakeUserPresets.json # Conan *.pyc /test_package/build/ + +# Conan internal files +# TODO Remove for Conan 2.0 +conan_paths.cmake +conan.lock +conanbuildinfo.txt +conaninfo.txt +graph_info.json From e7d6b7a9b01cc08dd5dc2c897e079d202b517ea8 Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Tue, 26 Jul 2022 12:26:47 +0200 Subject: [PATCH 08/52] build(conan): Imports reordered to make pre-commit happy --- conanfile.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conanfile.py b/conanfile.py index 40eb99fa..0fccdad0 100644 --- a/conanfile.py +++ b/conanfile.py @@ -24,8 +24,8 @@ import os import re from conan import ConanFile -from conan.tools.cmake import CMake, CMakeDeps, CMakeToolchain from conan.tools.build import check_min_cppstd +from conan.tools.cmake import CMake, CMakeDeps, CMakeToolchain, cmake_layout from conan.tools.files import copy, load, rmdir from conan.tools.scm import Version from conans.errors import ConanInvalidConfiguration From 0adee83866f4dd1d85ff60078e3c025c58703fd3 Mon Sep 17 00:00:00 2001 From: Chip Hogg Date: Wed, 27 Jul 2022 14:30:38 +0000 Subject: [PATCH 09/52] Use `mag_power` to make callsites more concise --- src/core/include/units/magnitude.h | 10 ++++++++++ src/systems/si-hep/include/units/isq/si/hep/area.h | 2 +- src/systems/si-hep/include/units/isq/si/hep/mass.h | 12 ++++-------- .../si-hep/include/units/isq/si/hep/momentum.h | 2 +- src/systems/si-iau/include/units/isq/si/iau/length.h | 2 +- .../include/units/isq/si/typographic/length.h | 10 +++++----- .../si/include/units/isq/si/catalytic_activity.h | 3 +-- src/systems/si/include/units/isq/si/energy.h | 4 ++-- src/systems/si/include/units/isq/si/mass.h | 4 ++-- 9 files changed, 27 insertions(+), 22 deletions(-) diff --git a/src/core/include/units/magnitude.h b/src/core/include/units/magnitude.h index 3e1e7a19..d3ab7181 100644 --- a/src/core/include/units/magnitude.h +++ b/src/core/include/units/magnitude.h @@ -652,6 +652,16 @@ constexpr Magnitude auto as_magnitude() return detail::prime_factorization_v / detail::prime_factorization_v; } +/** + * @brief Create a Magnitude which is some rational number raised to a rational power. + */ +template + requires(Base.num > 0) +constexpr Magnitude auto mag_power() +{ + return pow(as_magnitude()); +} + namespace detail { template constexpr ratio get_power(T base, magnitude) diff --git a/src/systems/si-hep/include/units/isq/si/hep/area.h b/src/systems/si-hep/include/units/isq/si/hep/area.h index 658a12a8..65130f8a 100644 --- a/src/systems/si-hep/include/units/isq/si/hep/area.h +++ b/src/systems/si-hep/include/units/isq/si/hep/area.h @@ -37,7 +37,7 @@ namespace units::isq::si::hep { // effective cross-sectional area according to EU council directive 80/181/EEC // https://eur-lex.europa.eu/legal-content/EN/TXT/PDF/?uri=CELEX:01980L0181-20090527#page=10 // https://www.fedlex.admin.ch/eli/cc/1994/3109_3109_3109/de -struct barn : named_scaled_unit(as_magnitude<10>()), square_metre> {}; +struct barn : named_scaled_unit(), square_metre> {}; struct yocto_barn : prefixed_unit {}; struct zepto_barn : prefixed_unit {}; struct atto_barn : prefixed_unit {}; diff --git a/src/systems/si-hep/include/units/isq/si/hep/mass.h b/src/systems/si-hep/include/units/isq/si/hep/mass.h index 754c2a61..c3b3bd99 100644 --- a/src/systems/si-hep/include/units/isq/si/hep/mass.h +++ b/src/systems/si-hep/include/units/isq/si/hep/mass.h @@ -44,8 +44,7 @@ namespace units::isq::si::hep { struct eV_per_c2 : named_scaled_unit() * pow<-35>(as_magnitude<10>()), - kilogram> {}; + as_magnitude() * mag_power<10, -35>(), kilogram> {}; struct feV_per_c2 : prefixed_unit {}; struct peV_per_c2 : prefixed_unit {}; struct neV_per_c2 : prefixed_unit {}; @@ -62,16 +61,13 @@ struct EeV_per_c2 : prefixed_unit {}; struct YeV_per_c2 : prefixed_unit {}; struct electron_mass : named_scaled_unit() * pow<-31>(as_magnitude<10>()), - kilogram> {}; + as_magnitude() * mag_power<10, -31>(), kilogram> {}; struct proton_mass : named_scaled_unit() * pow<-27>(as_magnitude<10>()), - kilogram> {}; + as_magnitude() * mag_power<10, -27>(), kilogram> {}; struct neutron_mass : named_scaled_unit() * pow<-27>(as_magnitude<10>()), - kilogram> {}; + as_magnitude() * mag_power<10, -27>(), kilogram> {}; struct dim_mass : isq::dim_mass {}; diff --git a/src/systems/si-hep/include/units/isq/si/hep/momentum.h b/src/systems/si-hep/include/units/isq/si/hep/momentum.h index ab87fb4a..dbc66c57 100644 --- a/src/systems/si-hep/include/units/isq/si/hep/momentum.h +++ b/src/systems/si-hep/include/units/isq/si/hep/momentum.h @@ -42,7 +42,7 @@ struct kilogram_metre_per_second : derived_unit {}; struct eV_per_c : named_scaled_unit() * pow<-35>(as_magnitude<10>()), + as_magnitude() * mag_power<10, -35>(), kilogram_metre_per_second> {}; struct feV_per_c : prefixed_unit {}; struct peV_per_c : prefixed_unit {}; diff --git a/src/systems/si-iau/include/units/isq/si/iau/length.h b/src/systems/si-iau/include/units/isq/si/iau/length.h index e4066edb..bf0226c3 100644 --- a/src/systems/si-iau/include/units/isq/si/iau/length.h +++ b/src/systems/si-iau/include/units/isq/si/iau/length.h @@ -42,7 +42,7 @@ struct light_year : named_scaled_unit(), si::metre> {}; // https://en.wikipedia.org/wiki/Angstrom -struct angstrom : named_scaled_unit(as_magnitude<10>()), si::metre> {}; +struct angstrom : named_scaled_unit(), si::metre> {}; #ifndef UNITS_NO_LITERALS diff --git a/src/systems/si-typographic/include/units/isq/si/typographic/length.h b/src/systems/si-typographic/include/units/isq/si/typographic/length.h index ecd56afd..899bd4e6 100644 --- a/src/systems/si-typographic/include/units/isq/si/typographic/length.h +++ b/src/systems/si-typographic/include/units/isq/si/typographic/length.h @@ -38,15 +38,15 @@ namespace units::isq::si::typographic { // TODO Conflicts with (https://en.wikipedia.org/wiki/Pica_(typography)), verify correctness of below conversion factors // and provide hyperlinks to definitions struct pica_comp : - named_scaled_unit() * pow<-9>(as_magnitude<10>()), si::metre> {}; + named_scaled_unit() * mag_power<10, -9>(), si::metre> {}; struct pica_prn : - named_scaled_unit() * pow<-3>(as_magnitude<10>()), - si::metre> {}; + named_scaled_unit() * mag_power<10, -3>(), si::metre> { +}; struct point_comp : - named_scaled_unit() * pow<-4>(as_magnitude<10>()), + named_scaled_unit() * mag_power<10, -4>(), si::metre> {}; struct point_prn : - named_scaled_unit() * pow<-4>(as_magnitude<10>()), + named_scaled_unit() * mag_power<10, -4>(), si::metre> {}; #ifndef UNITS_NO_LITERALS diff --git a/src/systems/si/include/units/isq/si/catalytic_activity.h b/src/systems/si/include/units/isq/si/catalytic_activity.h index 562eb0fa..397de5c4 100644 --- a/src/systems/si/include/units/isq/si/catalytic_activity.h +++ b/src/systems/si/include/units/isq/si/catalytic_activity.h @@ -58,8 +58,7 @@ struct exakatal : prefixed_unit {}; struct zettakatal : prefixed_unit {}; struct yottakatal : prefixed_unit {}; -struct enzyme_unit : - named_scaled_unit() * pow<-6>(as_magnitude<10>()), katal> {}; +struct enzyme_unit : named_scaled_unit() * mag_power<10, -6>(), katal> {}; struct dim_catalytic_activity : isq::dim_catalytic_activity {}; diff --git a/src/systems/si/include/units/isq/si/energy.h b/src/systems/si/include/units/isq/si/energy.h index c9eca1cb..d5edf645 100644 --- a/src/systems/si/include/units/isq/si/energy.h +++ b/src/systems/si/include/units/isq/si/energy.h @@ -56,8 +56,8 @@ struct yottajoule : prefixed_unit {}; // N.B. electron charge (and eV) is an exact constant: // https://www.bipm.org/documents/20126/41483022/SI-Brochure-9.pdf#page=147 struct electronvolt : - named_scaled_unit() * pow<-19>(as_magnitude<10>()), joule> {}; + named_scaled_unit() * mag_power<10, -19>(), + joule> {}; struct gigaelectronvolt : prefixed_unit {}; struct dim_energy : isq::dim_energy {}; diff --git a/src/systems/si/include/units/isq/si/mass.h b/src/systems/si/include/units/isq/si/mass.h index e4d935d1..e57d2c0b 100644 --- a/src/systems/si/include/units/isq/si/mass.h +++ b/src/systems/si/include/units/isq/si/mass.h @@ -80,8 +80,8 @@ struct yottatonne : prefixed_unit {}; struct dalton : named_scaled_unit() * pow<-27>(as_magnitude<10>()), - kilogram> {}; + as_magnitude() * mag_power<10, -27>(), kilogram> { +}; struct dim_mass : isq::dim_mass {}; From ea83af8aa9fc05ef68e14b4dbdbb5999629ba35d Mon Sep 17 00:00:00 2001 From: Chip Hogg Date: Fri, 29 Jul 2022 01:46:06 +0000 Subject: [PATCH 10/52] Rename `as_magnitude<...>()` to `mag<...>()` This is easier to write and to read. --- example/custom_systems.cpp | 6 +- .../include/units/bits/derived_scaled_unit.h | 3 +- src/core/include/units/bits/unit_text.h | 4 +- src/core/include/units/chrono.h | 4 +- .../include/units/generic/dimensionless.h | 2 +- src/core/include/units/magnitude.h | 6 +- src/core/include/units/unit.h | 4 +- .../units/isq/iec80000/binary_prefixes.h | 16 +- .../units/isq/iec80000/storage_capacity.h | 2 +- .../si-fps/include/units/isq/si/fps/force.h | 2 +- .../si-fps/include/units/isq/si/fps/length.h | 2 +- .../si-fps/include/units/isq/si/fps/mass.h | 18 +- .../si-fps/include/units/isq/si/fps/power.h | 2 +- .../include/units/isq/si/fps/pressure.h | 5 +- .../si-hep/include/units/isq/si/hep/mass.h | 14 +- .../include/units/isq/si/hep/momentum.h | 3 +- .../si-iau/include/units/isq/si/iau/length.h | 4 +- .../include/units/isq/si/imperial/length.h | 4 +- .../units/isq/si/international/length.h | 14 +- .../include/units/isq/si/typographic/length.h | 12 +- .../include/units/isq/si/uscs/length.h | 6 +- .../include/units/isq/si/catalytic_activity.h | 2 +- src/systems/si/include/units/isq/si/energy.h | 3 +- src/systems/si/include/units/isq/si/length.h | 2 +- .../si/include/units/isq/si/luminous_flux.h | 2 +- .../include/units/isq/si/magnetic_induction.h | 2 +- src/systems/si/include/units/isq/si/mass.h | 5 +- .../si/include/units/isq/si/prefixes.h | 40 ++--- src/systems/si/include/units/isq/si/time.h | 6 +- test/unit_test/runtime/fmt_test.cpp | 4 +- test/unit_test/runtime/fmt_units_test.cpp | 2 +- test/unit_test/runtime/magnitude_test.cpp | 155 +++++++++--------- test/unit_test/static/quantity_kind_test.cpp | 6 +- test/unit_test/static/quantity_test.cpp | 35 ++-- test/unit_test/static/si_test.cpp | 4 +- test/unit_test/static/unit_test.cpp | 12 +- 36 files changed, 196 insertions(+), 217 deletions(-) diff --git a/example/custom_systems.cpp b/example/custom_systems.cpp index 90a63dae..9fe72f4e 100644 --- a/example/custom_systems.cpp +++ b/example/custom_systems.cpp @@ -33,7 +33,7 @@ using namespace units; namespace fps { struct foot : named_unit {}; -struct yard : named_scaled_unit(), foot> {}; +struct yard : named_scaled_unit(), foot> {}; struct dim_length : base_dimension<"L", foot> {}; @@ -54,8 +54,8 @@ using length = quantity; namespace fps { -struct foot : named_scaled_unit(), metre> {}; -struct yard : named_scaled_unit(), foot> {}; +struct foot : named_scaled_unit(), metre> {}; +struct yard : named_scaled_unit(), foot> {}; struct dim_length : base_dimension<"L", foot> {}; diff --git a/src/core/include/units/bits/derived_scaled_unit.h b/src/core/include/units/bits/derived_scaled_unit.h index 5a8b4cd7..ecdaf48f 100644 --- a/src/core/include/units/bits/derived_scaled_unit.h +++ b/src/core/include/units/bits/derived_scaled_unit.h @@ -39,8 +39,7 @@ inline constexpr bool compatible_units, Us...> = (UnitOf constexpr Magnitude auto derived_mag(exponent_list) { - return (as_magnitude<1>() * ... * - pow(Us::mag / dimension_unit::mag)); + return (mag<1>() * ... * pow(Us::mag / dimension_unit::mag)); } template diff --git a/src/core/include/units/bits/unit_text.h b/src/core/include/units/bits/unit_text.h index f546a251..db0cf31a 100644 --- a/src/core/include/units/bits/unit_text.h +++ b/src/core/include/units/bits/unit_text.h @@ -37,7 +37,7 @@ constexpr auto magnitude_text() { constexpr auto exp10 = extract_power_of_10(M); - constexpr Magnitude auto base = M / pow(as_magnitude<10>()); + constexpr Magnitude auto base = M / pow(mag<10>()); constexpr Magnitude auto num = numerator(base); constexpr Magnitude auto den = denominator(base); static_assert(base == num / den, "Printing rational powers, or irrational bases, not yet supported"); @@ -72,7 +72,7 @@ constexpr auto magnitude_text() template constexpr auto prefix_or_magnitude_text() { - if constexpr (M == as_magnitude<1>()) { + if constexpr (M == mag<1>()) { // no ratio/prefix return basic_fixed_string(""); } else { diff --git a/src/core/include/units/chrono.h b/src/core/include/units/chrono.h index d7c9fc91..4bd918b9 100644 --- a/src/core/include/units/chrono.h +++ b/src/core/include/units/chrono.h @@ -34,7 +34,7 @@ namespace units { template struct quantity_like_traits> { private: - static constexpr auto mag = as_magnitude(); + static constexpr auto mag = mag(); public: using dimension = isq::si::dim_time; using unit = downcast_unit; @@ -48,7 +48,7 @@ struct clock_origin : point_origin {}; template struct quantity_point_like_traits>> { private: - static constexpr auto mag = as_magnitude(); + static constexpr auto mag = mag(); public: using origin = clock_origin; using unit = downcast_unit; diff --git a/src/core/include/units/generic/dimensionless.h b/src/core/include/units/generic/dimensionless.h index fc7b97e6..576547e6 100644 --- a/src/core/include/units/generic/dimensionless.h +++ b/src/core/include/units/generic/dimensionless.h @@ -31,7 +31,7 @@ namespace units { struct one : derived_unit {}; -struct percent : named_scaled_unit(), one> {}; +struct percent : named_scaled_unit(), one> {}; /** * @brief Dimension one diff --git a/src/core/include/units/magnitude.h b/src/core/include/units/magnitude.h index d3ab7181..c81fb538 100644 --- a/src/core/include/units/magnitude.h +++ b/src/core/include/units/magnitude.h @@ -596,7 +596,7 @@ constexpr auto common_magnitude(magnitude, magnitude) } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// `as_magnitude()` implementation. +// `mag()` implementation. // Sometimes we need to give the compiler a "shortcut" when factorizing large numbers (specifically, numbers whose // _first factor_ is very large). If we don't, we can run into limits on the number of constexpr steps or iterations. @@ -647,7 +647,7 @@ inline constexpr auto prime_factorization_v = prime_factorization::value; */ template requires(R.num > 0) -constexpr Magnitude auto as_magnitude() +constexpr Magnitude auto mag() { return detail::prime_factorization_v / detail::prime_factorization_v; } @@ -659,7 +659,7 @@ template requires(Base.num > 0) constexpr Magnitude auto mag_power() { - return pow(as_magnitude()); + return pow(mag()); } namespace detail { diff --git a/src/core/include/units/unit.h b/src/core/include/units/unit.h index 52b9779c..59e8c327 100644 --- a/src/core/include/units/unit.h +++ b/src/core/include/units/unit.h @@ -80,7 +80,7 @@ struct same_unit_reference : is_same -struct named_unit : downcast_dispatch(), Child>> { +struct named_unit : downcast_dispatch(), Child>> { static constexpr auto symbol = Symbol; }; @@ -126,7 +126,7 @@ struct prefixed_unit : downcast_dispatch -struct derived_unit : downcast_dispatch(), Child>> {}; +struct derived_unit : downcast_dispatch(), Child>> {}; /** * @brief A unit with a deduced ratio and symbol diff --git a/src/systems/isq-iec80000/include/units/isq/iec80000/binary_prefixes.h b/src/systems/isq-iec80000/include/units/isq/iec80000/binary_prefixes.h index 25fdaaa9..a9fe73dd 100644 --- a/src/systems/isq-iec80000/include/units/isq/iec80000/binary_prefixes.h +++ b/src/systems/isq-iec80000/include/units/isq/iec80000/binary_prefixes.h @@ -26,13 +26,13 @@ namespace units::isq::iec80000 { -struct kibi : prefix(as_magnitude<2>())> {}; -struct mebi : prefix(as_magnitude<2>())> {}; -struct gibi : prefix(as_magnitude<2>())> {}; -struct tebi : prefix(as_magnitude<2>())> {}; -struct pebi : prefix(as_magnitude<2>())> {}; -struct exbi : prefix(as_magnitude<2>())> {}; -struct zebi : prefix(as_magnitude<2>())> {}; -struct yobi : prefix(as_magnitude<2>())> {}; +struct kibi : prefix(mag<2>())> {}; +struct mebi : prefix(mag<2>())> {}; +struct gibi : prefix(mag<2>())> {}; +struct tebi : prefix(mag<2>())> {}; +struct pebi : prefix(mag<2>())> {}; +struct exbi : prefix(mag<2>())> {}; +struct zebi : prefix(mag<2>())> {}; +struct yobi : prefix(mag<2>())> {}; } // namespace units::isq::iec80000 diff --git a/src/systems/isq-iec80000/include/units/isq/iec80000/storage_capacity.h b/src/systems/isq-iec80000/include/units/isq/iec80000/storage_capacity.h index eaf7a7ca..2ca2f0d7 100644 --- a/src/systems/isq-iec80000/include/units/isq/iec80000/storage_capacity.h +++ b/src/systems/isq-iec80000/include/units/isq/iec80000/storage_capacity.h @@ -53,7 +53,7 @@ struct tebibit : prefixed_unit {}; struct pebibit : prefixed_unit {}; struct exbibit : prefixed_unit {}; -struct byte : named_scaled_unit(), bit> {}; +struct byte : named_scaled_unit(), bit> {}; struct kilobyte : prefixed_unit {}; struct megabyte : prefixed_unit {}; diff --git a/src/systems/si-fps/include/units/isq/si/fps/force.h b/src/systems/si-fps/include/units/isq/si/fps/force.h index a026bd79..f8569719 100644 --- a/src/systems/si-fps/include/units/isq/si/fps/force.h +++ b/src/systems/si-fps/include/units/isq/si/fps/force.h @@ -40,7 +40,7 @@ namespace units::isq::si::fps { struct poundal : named_unit {}; // https://en.wikipedia.org/wiki/Pound_(force) -struct pound_force : named_scaled_unit(), poundal> {}; +struct pound_force : named_scaled_unit(), poundal> {}; struct kilopound_force : prefixed_unit {}; diff --git a/src/systems/si-fps/include/units/isq/si/fps/length.h b/src/systems/si-fps/include/units/isq/si/fps/length.h index 04a9e930..adc29a8d 100644 --- a/src/systems/si-fps/include/units/isq/si/fps/length.h +++ b/src/systems/si-fps/include/units/isq/si/fps/length.h @@ -48,7 +48,7 @@ struct thousandth : alias_unit {}; struct kiloyard : prefixed_unit {}; -struct nautical_mile : named_scaled_unit(), yard> {}; +struct nautical_mile : named_scaled_unit(), yard> {}; struct dim_length : isq::dim_length {}; diff --git a/src/systems/si-fps/include/units/isq/si/fps/mass.h b/src/systems/si-fps/include/units/isq/si/fps/mass.h index 16b23f0a..246aba06 100644 --- a/src/systems/si-fps/include/units/isq/si/fps/mass.h +++ b/src/systems/si-fps/include/units/isq/si/fps/mass.h @@ -35,28 +35,28 @@ namespace units::isq::si::fps { // https://en.wikipedia.org/wiki/Pound_(mass) -struct pound : named_scaled_unit(), si::kilogram> {}; +struct pound : named_scaled_unit(), si::kilogram> {}; struct dim_mass : isq::dim_mass {}; template U, Representation Rep = double> using mass = quantity; -struct grain : named_scaled_unit(), pound> {}; +struct grain : named_scaled_unit(), pound> {}; -struct dram : named_scaled_unit(), pound> {}; +struct dram : named_scaled_unit(), pound> {}; -struct ounce : named_scaled_unit(), pound> {}; +struct ounce : named_scaled_unit(), pound> {}; -struct stone : named_scaled_unit(), pound> {}; +struct stone : named_scaled_unit(), pound> {}; -struct quarter : named_scaled_unit(), pound> {}; +struct quarter : named_scaled_unit(), pound> {}; -struct hundredweight : named_scaled_unit(), pound> {}; +struct hundredweight : named_scaled_unit(), pound> {}; -struct short_ton : named_scaled_unit(), pound> {}; +struct short_ton : named_scaled_unit(), pound> {}; -struct long_ton : named_scaled_unit(), pound> {}; +struct long_ton : named_scaled_unit(), pound> {}; #ifndef UNITS_NO_LITERALS diff --git a/src/systems/si-fps/include/units/isq/si/fps/power.h b/src/systems/si-fps/include/units/isq/si/fps/power.h index 931c08f4..85930563 100644 --- a/src/systems/si-fps/include/units/isq/si/fps/power.h +++ b/src/systems/si-fps/include/units/isq/si/fps/power.h @@ -42,7 +42,7 @@ struct dim_power : isq::dim_power {}; -struct horse_power : named_scaled_unit(), foot_pound_force_per_second> {}; +struct horse_power : named_scaled_unit(), foot_pound_force_per_second> {}; template U, Representation Rep = double> using power = quantity; diff --git a/src/systems/si-fps/include/units/isq/si/fps/pressure.h b/src/systems/si-fps/include/units/isq/si/fps/pressure.h index 4b036fc1..e155d961 100644 --- a/src/systems/si-fps/include/units/isq/si/fps/pressure.h +++ b/src/systems/si-fps/include/units/isq/si/fps/pressure.h @@ -44,11 +44,10 @@ template U, Representation Rep = double> using pressure = quantity; struct pound_force_per_foot_sq : - named_scaled_unit(), - poundal_per_foot_sq> {}; + named_scaled_unit(), poundal_per_foot_sq> {}; struct pound_force_per_inch_sq : - named_scaled_unit(), pound_force_per_foot_sq> {}; + named_scaled_unit(), pound_force_per_foot_sq> {}; struct kilopound_force_per_inch_sq : prefixed_unit {}; diff --git a/src/systems/si-hep/include/units/isq/si/hep/mass.h b/src/systems/si-hep/include/units/isq/si/hep/mass.h index c3b3bd99..cf97b869 100644 --- a/src/systems/si-hep/include/units/isq/si/hep/mass.h +++ b/src/systems/si-hep/include/units/isq/si/hep/mass.h @@ -44,7 +44,7 @@ namespace units::isq::si::hep { struct eV_per_c2 : named_scaled_unit() * mag_power<10, -35>(), kilogram> {}; + mag() * mag_power<10, -35>(), kilogram> {}; struct feV_per_c2 : prefixed_unit {}; struct peV_per_c2 : prefixed_unit {}; struct neV_per_c2 : prefixed_unit {}; @@ -60,14 +60,14 @@ struct PeV_per_c2 : prefixed_unit {}; struct EeV_per_c2 : prefixed_unit {}; struct YeV_per_c2 : prefixed_unit {}; struct electron_mass : - named_scaled_unit() * mag_power<10, -31>(), kilogram> {}; + named_scaled_unit() * mag_power<10, -31>(), + kilogram> {}; struct proton_mass : - named_scaled_unit() * mag_power<10, -27>(), kilogram> {}; + named_scaled_unit() * mag_power<10, -27>(), + kilogram> {}; struct neutron_mass : - named_scaled_unit() * mag_power<10, -27>(), kilogram> {}; + named_scaled_unit() * mag_power<10, -27>(), + kilogram> {}; struct dim_mass : isq::dim_mass {}; diff --git a/src/systems/si-hep/include/units/isq/si/hep/momentum.h b/src/systems/si-hep/include/units/isq/si/hep/momentum.h index dbc66c57..a03ae821 100644 --- a/src/systems/si-hep/include/units/isq/si/hep/momentum.h +++ b/src/systems/si-hep/include/units/isq/si/hep/momentum.h @@ -41,8 +41,7 @@ namespace units::isq::si::hep { struct kilogram_metre_per_second : derived_unit {}; struct eV_per_c : - named_scaled_unit() * mag_power<10, -35>(), + named_scaled_unit() * mag_power<10, -35>(), kilogram_metre_per_second> {}; struct feV_per_c : prefixed_unit {}; struct peV_per_c : prefixed_unit {}; diff --git a/src/systems/si-iau/include/units/isq/si/iau/length.h b/src/systems/si-iau/include/units/isq/si/iau/length.h index bf0226c3..974dd8fc 100644 --- a/src/systems/si-iau/include/units/isq/si/iau/length.h +++ b/src/systems/si-iau/include/units/isq/si/iau/length.h @@ -36,10 +36,10 @@ namespace units::isq::si::iau { // https://en.wikipedia.org/wiki/Light-year -struct light_year : named_scaled_unit(), si::metre> {}; +struct light_year : named_scaled_unit(), si::metre> {}; // https://en.wikipedia.org/wiki/Parsec -struct parsec : named_scaled_unit(), si::metre> {}; +struct parsec : named_scaled_unit(), si::metre> {}; // https://en.wikipedia.org/wiki/Angstrom struct angstrom : named_scaled_unit(), si::metre> {}; diff --git a/src/systems/si-imperial/include/units/isq/si/imperial/length.h b/src/systems/si-imperial/include/units/isq/si/imperial/length.h index 5f4be435..f6c278f4 100644 --- a/src/systems/si-imperial/include/units/isq/si/imperial/length.h +++ b/src/systems/si-imperial/include/units/isq/si/imperial/length.h @@ -35,10 +35,10 @@ namespace units::isq::si::imperial { // https://en.wikipedia.org/wiki/Chain_(unit) -struct chain : named_scaled_unit(), si::international::yard> {}; +struct chain : named_scaled_unit(), si::international::yard> {}; // https://en.wikipedia.org/wiki/Rod_(unit) -struct rod : named_scaled_unit(), chain> {}; +struct rod : named_scaled_unit(), chain> {}; #ifndef UNITS_NO_LITERALS diff --git a/src/systems/si-international/include/units/isq/si/international/length.h b/src/systems/si-international/include/units/isq/si/international/length.h index 5e3bab57..3940cb34 100644 --- a/src/systems/si-international/include/units/isq/si/international/length.h +++ b/src/systems/si-international/include/units/isq/si/international/length.h @@ -37,30 +37,30 @@ namespace units::isq::si::international { // si::international yard // https://en.wikipedia.org/wiki/International_yard_and_pound -struct yard : named_scaled_unit(), si::metre> {}; +struct yard : named_scaled_unit(), si::metre> {}; // si::international foot // https://en.wikipedia.org/wiki/Foot_(unit)#International_foot -struct foot : named_scaled_unit(), yard> {}; +struct foot : named_scaled_unit(), yard> {}; // https://en.wikipedia.org/wiki/Fathom#International_fathom -struct fathom : named_scaled_unit(), yard> {}; +struct fathom : named_scaled_unit(), yard> {}; // si::international inch // https://en.wikipedia.org/wiki/Inch#Equivalences -struct inch : named_scaled_unit(), yard> {}; +struct inch : named_scaled_unit(), yard> {}; // intrnational mile // https://en.wikipedia.org/wiki/Mile#International_mile -struct mile : named_scaled_unit(), si::kilometre> {}; +struct mile : named_scaled_unit(), si::kilometre> {}; // si::international nautical mile // https://en.wikipedia.org/wiki/Nautical_mile -struct nautical_mile : named_scaled_unit(), si::metre> {}; +struct nautical_mile : named_scaled_unit(), si::metre> {}; // thou // https://en.wikipedia.org/wiki/Thousandth_of_an_inch -struct thou : named_scaled_unit(), inch> {}; +struct thou : named_scaled_unit(), inch> {}; // mil - different name for thou // https://en.wikipedia.org/wiki/Thousandth_of_an_inch diff --git a/src/systems/si-typographic/include/units/isq/si/typographic/length.h b/src/systems/si-typographic/include/units/isq/si/typographic/length.h index 899bd4e6..e5b409c6 100644 --- a/src/systems/si-typographic/include/units/isq/si/typographic/length.h +++ b/src/systems/si-typographic/include/units/isq/si/typographic/length.h @@ -37,17 +37,13 @@ namespace units::isq::si::typographic { // TODO Conflicts with (https://en.wikipedia.org/wiki/Pica_(typography)), verify correctness of below conversion factors // and provide hyperlinks to definitions -struct pica_comp : - named_scaled_unit() * mag_power<10, -9>(), si::metre> {}; +struct pica_comp : named_scaled_unit() * mag_power<10, -9>(), si::metre> {}; struct pica_prn : - named_scaled_unit() * mag_power<10, -3>(), si::metre> { -}; + named_scaled_unit() * mag_power<10, -3>(), si::metre> {}; struct point_comp : - named_scaled_unit() * mag_power<10, -4>(), - si::metre> {}; + named_scaled_unit() * mag_power<10, -4>(), si::metre> {}; struct point_prn : - named_scaled_unit() * mag_power<10, -4>(), - si::metre> {}; + named_scaled_unit() * mag_power<10, -4>(), si::metre> {}; #ifndef UNITS_NO_LITERALS diff --git a/src/systems/si-uscs/include/units/isq/si/uscs/length.h b/src/systems/si-uscs/include/units/isq/si/uscs/length.h index fe4eb9f1..e2dafbb5 100644 --- a/src/systems/si-uscs/include/units/isq/si/uscs/length.h +++ b/src/systems/si-uscs/include/units/isq/si/uscs/length.h @@ -36,14 +36,14 @@ namespace units::isq::si::uscs { // https://en.wikipedia.org/wiki/Foot_(unit)#US_survey_foot // https://www.nist.gov/pml/special-publication-811/nist-guide-si-appendix-b-conversion-factors#B6 -struct foot : named_scaled_unit(), si::metre> {}; +struct foot : named_scaled_unit(), si::metre> {}; // https://www.nist.gov/pml/special-publication-811/nist-guide-si-appendix-b-conversion-factors#B6 -struct fathom : named_scaled_unit(), foot> {}; +struct fathom : named_scaled_unit(), foot> {}; // https://en.wikipedia.org/wiki/Mile#U.S._survey_mile // https://www.nist.gov/pml/special-publication-811/nist-guide-si-appendix-b-conversion-factors#B6 -struct mile : named_scaled_unit(), foot> {}; +struct mile : named_scaled_unit(), foot> {}; #ifndef UNITS_NO_LITERALS diff --git a/src/systems/si/include/units/isq/si/catalytic_activity.h b/src/systems/si/include/units/isq/si/catalytic_activity.h index 397de5c4..926705d6 100644 --- a/src/systems/si/include/units/isq/si/catalytic_activity.h +++ b/src/systems/si/include/units/isq/si/catalytic_activity.h @@ -58,7 +58,7 @@ struct exakatal : prefixed_unit {}; struct zettakatal : prefixed_unit {}; struct yottakatal : prefixed_unit {}; -struct enzyme_unit : named_scaled_unit() * mag_power<10, -6>(), katal> {}; +struct enzyme_unit : named_scaled_unit() * mag_power<10, -6>(), katal> {}; struct dim_catalytic_activity : isq::dim_catalytic_activity {}; diff --git a/src/systems/si/include/units/isq/si/energy.h b/src/systems/si/include/units/isq/si/energy.h index d5edf645..7511c4d0 100644 --- a/src/systems/si/include/units/isq/si/energy.h +++ b/src/systems/si/include/units/isq/si/energy.h @@ -56,8 +56,7 @@ struct yottajoule : prefixed_unit {}; // N.B. electron charge (and eV) is an exact constant: // https://www.bipm.org/documents/20126/41483022/SI-Brochure-9.pdf#page=147 struct electronvolt : - named_scaled_unit() * mag_power<10, -19>(), - joule> {}; + named_scaled_unit() * mag_power<10, -19>(), joule> {}; struct gigaelectronvolt : prefixed_unit {}; struct dim_energy : isq::dim_energy {}; diff --git a/src/systems/si/include/units/isq/si/length.h b/src/systems/si/include/units/isq/si/length.h index aefebdbb..6585ed92 100644 --- a/src/systems/si/include/units/isq/si/length.h +++ b/src/systems/si/include/units/isq/si/length.h @@ -56,7 +56,7 @@ struct exametre : prefixed_unit {}; struct zettametre : prefixed_unit {}; struct yottametre : prefixed_unit {}; -struct astronomical_unit : named_scaled_unit(), metre> {}; +struct astronomical_unit : named_scaled_unit(), metre> {}; struct dim_length : isq::dim_length {}; diff --git a/src/systems/si/include/units/isq/si/luminous_flux.h b/src/systems/si/include/units/isq/si/luminous_flux.h index f2b30290..a1de8d48 100644 --- a/src/systems/si/include/units/isq/si/luminous_flux.h +++ b/src/systems/si/include/units/isq/si/luminous_flux.h @@ -36,7 +36,7 @@ namespace units::isq::si { // TODO Is this correct? Should we account for steradian here? How? -struct lumen : named_scaled_unit(), watt> {}; +struct lumen : named_scaled_unit(), watt> {}; using dim_luminous_flux = dim_power; diff --git a/src/systems/si/include/units/isq/si/magnetic_induction.h b/src/systems/si/include/units/isq/si/magnetic_induction.h index 74bd7ca6..529a7f9a 100644 --- a/src/systems/si/include/units/isq/si/magnetic_induction.h +++ b/src/systems/si/include/units/isq/si/magnetic_induction.h @@ -56,7 +56,7 @@ struct exatesla : prefixed_unit {}; struct zettatesla : prefixed_unit {}; struct yottatesla : prefixed_unit {}; -struct gauss : named_scaled_unit(), tesla> {}; +struct gauss : named_scaled_unit(), tesla> {}; struct dim_magnetic_induction : isq::dim_magnetic_induction {}; diff --git a/src/systems/si/include/units/isq/si/mass.h b/src/systems/si/include/units/isq/si/mass.h index e57d2c0b..d57069d8 100644 --- a/src/systems/si/include/units/isq/si/mass.h +++ b/src/systems/si/include/units/isq/si/mass.h @@ -79,9 +79,8 @@ struct zettatonne : prefixed_unit {}; struct yottatonne : prefixed_unit {}; struct dalton : - named_scaled_unit() * mag_power<10, -27>(), kilogram> { -}; + named_scaled_unit() * mag_power<10, -27>(), + kilogram> {}; struct dim_mass : isq::dim_mass {}; diff --git a/src/systems/si/include/units/isq/si/prefixes.h b/src/systems/si/include/units/isq/si/prefixes.h index 5ee1ec04..562370b6 100644 --- a/src/systems/si/include/units/isq/si/prefixes.h +++ b/src/systems/si/include/units/isq/si/prefixes.h @@ -27,26 +27,26 @@ namespace units::isq::si { // clang-format off -struct yocto : prefix(as_magnitude<10>())> {}; -struct zepto : prefix(as_magnitude<10>())> {}; -struct atto : prefix(as_magnitude<10>())> {}; -struct femto : prefix(as_magnitude<10>())> {}; -struct pico : prefix(as_magnitude<10>())> {}; -struct nano : prefix(as_magnitude<10>())> {}; -struct micro : prefix(as_magnitude<10>())> {}; -struct milli : prefix(as_magnitude<10>())> {}; -struct centi : prefix(as_magnitude<10>())> {}; -struct deci : prefix(as_magnitude<10>())> {}; -struct deca : prefix(as_magnitude<10>())> {}; -struct hecto : prefix(as_magnitude<10>())> {}; -struct kilo : prefix(as_magnitude<10>())> {}; -struct mega : prefix(as_magnitude<10>())> {}; -struct giga : prefix(as_magnitude<10>())> {}; -struct tera : prefix(as_magnitude<10>())> {}; -struct peta : prefix(as_magnitude<10>())> {}; -struct exa : prefix(as_magnitude<10>())> {}; -struct zetta : prefix(as_magnitude<10>())> {}; -struct yotta : prefix(as_magnitude<10>())> {}; +struct yocto : prefix(mag<10>())> {}; +struct zepto : prefix(mag<10>())> {}; +struct atto : prefix(mag<10>())> {}; +struct femto : prefix(mag<10>())> {}; +struct pico : prefix(mag<10>())> {}; +struct nano : prefix(mag<10>())> {}; +struct micro : prefix(mag<10>())> {}; +struct milli : prefix(mag<10>())> {}; +struct centi : prefix(mag<10>())> {}; +struct deci : prefix(mag<10>())> {}; +struct deca : prefix(mag<10>())> {}; +struct hecto : prefix(mag<10>())> {}; +struct kilo : prefix(mag<10>())> {}; +struct mega : prefix(mag<10>())> {}; +struct giga : prefix(mag<10>())> {}; +struct tera : prefix(mag<10>())> {}; +struct peta : prefix(mag<10>())> {}; +struct exa : prefix(mag<10>())> {}; +struct zetta : prefix(mag<10>())> {}; +struct yotta : prefix(mag<10>())> {}; // clang-format on } // namespace units::isq::si diff --git a/src/systems/si/include/units/isq/si/time.h b/src/systems/si/include/units/isq/si/time.h index 17f47804..f023377a 100644 --- a/src/systems/si/include/units/isq/si/time.h +++ b/src/systems/si/include/units/isq/si/time.h @@ -43,9 +43,9 @@ struct picosecond : prefixed_unit {}; struct nanosecond : prefixed_unit {}; struct microsecond : prefixed_unit {}; struct millisecond : prefixed_unit {}; -struct minute : named_scaled_unit(), second> {}; -struct hour : named_scaled_unit(), minute> {}; -struct day : named_scaled_unit(), hour> {}; +struct minute : named_scaled_unit(), second> {}; +struct hour : named_scaled_unit(), minute> {}; +struct day : named_scaled_unit(), hour> {}; struct dim_time : isq::dim_time {}; diff --git a/test/unit_test/runtime/fmt_test.cpp b/test/unit_test/runtime/fmt_test.cpp index 7cc0f748..bd317b91 100644 --- a/test/unit_test/runtime/fmt_test.cpp +++ b/test/unit_test/runtime/fmt_test.cpp @@ -84,7 +84,7 @@ TEST_CASE("operator<< on a quantity", "[text][ostream][fmt]") { SECTION("in terms of base units") { - const length(as_magnitude<10>()), metre>> q(123); + const length(mag<10>()), metre>> q(123); os << q; SECTION("iostream") { CHECK(os.str() == "123 Mm"); } @@ -96,7 +96,7 @@ TEST_CASE("operator<< on a quantity", "[text][ostream][fmt]") SECTION("in terms of derived units") { - const energy(as_magnitude<10>()), joule>> q(60); + const energy(mag<10>()), joule>> q(60); os << q; SECTION("iostream") { CHECK(os.str() == "60 cJ"); } diff --git a/test/unit_test/runtime/fmt_units_test.cpp b/test/unit_test/runtime/fmt_units_test.cpp index 0f611eed..002e58fd 100644 --- a/test/unit_test/runtime/fmt_units_test.cpp +++ b/test/unit_test/runtime/fmt_units_test.cpp @@ -327,7 +327,7 @@ TEST_CASE("std::format on synthesized unit symbols", "[text][fmt]") SECTION("unknown scaled unit with reference different than the dimension's coherent unit") { // TODO(chogg): Reinstate after format/Magnitude redesign. - // constexpr auto mag = units::as_magnitude(); + // constexpr auto mag = units::mag(); // CHECK(STD_FMT::format("{}", mass>(1)) == "1 [2/3 × 10⁻³] kg"); // CHECK(STD_FMT::format("{:%Q %Aq}", mass>(1)) == "1 [2/3 x 10^-3] kg"); } diff --git a/test/unit_test/runtime/magnitude_test.cpp b/test/unit_test/runtime/magnitude_test.cpp index 8b80a60d..a861b66c 100644 --- a/test/unit_test/runtime/magnitude_test.cpp +++ b/test/unit_test/runtime/magnitude_test.cpp @@ -66,7 +66,7 @@ void check_same_type_and_value(T actual, U expected) template void check_ratio_round_trip_is_identity() { - constexpr Magnitude auto m = as_magnitude(); + constexpr Magnitude auto m = mag(); constexpr ratio round_trip = ratio{ get_value(numerator(m)), get_value(denominator(m)), @@ -125,10 +125,10 @@ TEST_CASE("base_power") SECTION("product with inverse equals identity") { - auto check_product_with_inverse_is_identity = [](auto x) { CHECK(x * pow<-1>(x) == as_magnitude<1>()); }; + auto check_product_with_inverse_is_identity = [](auto x) { CHECK(x * pow<-1>(x) == mag<1>()); }; - check_product_with_inverse_is_identity(as_magnitude<3>()); - check_product_with_inverse_is_identity(as_magnitude()); + check_product_with_inverse_is_identity(mag<3>()); + check_product_with_inverse_is_identity(mag()); check_product_with_inverse_is_identity(pi_to_the()); } @@ -144,21 +144,21 @@ TEST_CASE("make_ratio performs prime factorization correctly") { SECTION("Performs prime factorization when denominator is 1") { - CHECK(as_magnitude<1>() == magnitude<>{}); - CHECK(as_magnitude<2>() == magnitude{}); - CHECK(as_magnitude<3>() == magnitude{}); - CHECK(as_magnitude<4>() == magnitude{}); + CHECK(mag<1>() == magnitude<>{}); + CHECK(mag<2>() == magnitude{}); + CHECK(mag<3>() == magnitude{}); + CHECK(mag<4>() == magnitude{}); - CHECK(as_magnitude<792>() == magnitude{}); + CHECK(mag<792>() == magnitude{}); } - SECTION("Supports fractions") { CHECK(as_magnitude() == magnitude{}); } + SECTION("Supports fractions") { CHECK(mag() == magnitude{}); } SECTION("Can handle prime factor which would be large enough to overflow int") { // This was taken from a case which failed when we used `int` for our base to store prime numbers. // The failure was due to a prime factor which is larger than 2^31. - as_magnitude(); + mag(); } SECTION("Can bypass computing primes by providing known_first_factor") @@ -169,7 +169,7 @@ TEST_CASE("make_ratio performs prime factorization correctly") // In this case, we test that we can represent the largest prime that fits in a signed 64-bit int. The reason this // test can pass is that we have provided the answer, by specializing the `known_first_factor` variable template // above in this file. - as_magnitude<9'223'372'036'854'775'783>(); + mag<9'223'372'036'854'775'783>(); } } @@ -177,7 +177,7 @@ TEST_CASE("magnitude converts to numerical value") { SECTION("Positive integer powers of integer bases give integer values") { - constexpr auto mag_412 = as_magnitude<412>(); + constexpr auto mag_412 = mag<412>(); check_same_type_and_value(get_value(mag_412), 412); check_same_type_and_value(get_value(mag_412), std::size_t{412}); check_same_type_and_value(get_value(mag_412), 412.0f); @@ -186,7 +186,7 @@ TEST_CASE("magnitude converts to numerical value") SECTION("Negative integer powers of integer bases compute correct values") { - constexpr auto mag_0p125 = as_magnitude(); + constexpr auto mag_0p125 = mag(); check_same_type_and_value(get_value(mag_0p125), 0.125f); check_same_type_and_value(get_value(mag_0p125), 0.125); } @@ -219,20 +219,20 @@ TEST_CASE("magnitude converts to numerical value") // Naturally, we cannot actually write a test to verify a compiler error. But any of these can // be uncommented if desired to verify that it breaks the build. - // get_value(as_magnitude<412>()); + // get_value(mag<412>()); // Would work for pow<62>: - // get_value(pow<63>(as_magnitude<2>())); + // get_value(pow<63>(mag<2>())); // Would work for pow<63>: - // get_value(pow<64>(as_magnitude<2>())); + // get_value(pow<64>(mag<2>())); - get_value(pow<308>(as_magnitude<10>())); // Compiles, correctly. - // get_value(pow<309>(as_magnitude<10>())); - // get_value(pow<3099>(as_magnitude<10>())); - // get_value(pow<3099999>(as_magnitude<10>())); + get_value(pow<308>(mag<10>())); // Compiles, correctly. + // get_value(pow<309>(mag<10>())); + // get_value(pow<3099>(mag<10>())); + // get_value(pow<3099999>(mag<10>())); - auto sqrt_2 = pow(as_magnitude<2>()); + auto sqrt_2 = pow(mag<2>()); CHECK(!is_integral(sqrt_2)); // get_value(sqrt_2); } @@ -242,46 +242,40 @@ TEST_CASE("Equality works for magnitudes") { SECTION("Equivalent ratios are equal") { - CHECK(as_magnitude<1>() == as_magnitude<1>()); - CHECK(as_magnitude<3>() == as_magnitude<3>()); - CHECK(as_magnitude() == as_magnitude()); + CHECK(mag<1>() == mag<1>()); + CHECK(mag<3>() == mag<3>()); + CHECK(mag() == mag()); } SECTION("Different ratios are unequal") { - CHECK(as_magnitude<3>() != as_magnitude<5>()); - CHECK(as_magnitude<3>() != as_magnitude()); + CHECK(mag<3>() != mag<5>()); + CHECK(mag<3>() != mag()); } SECTION("Supports constexpr") { - constexpr auto eq = (as_magnitude() == as_magnitude()); + constexpr auto eq = (mag() == mag()); CHECK(!eq); } } TEST_CASE("Multiplication works for magnitudes") { - SECTION("Reciprocals reduce to null magnitude") - { - CHECK(as_magnitude() * as_magnitude() == as_magnitude<1>()); - } + SECTION("Reciprocals reduce to null magnitude") { CHECK(mag() * mag() == mag<1>()); } - SECTION("Products work as expected") - { - CHECK(as_magnitude() * as_magnitude() == as_magnitude()); - } + SECTION("Products work as expected") { CHECK(mag() * mag() == mag()); } SECTION("Products handle pi correctly") { - CHECK(pi_to_the<1>() * as_magnitude() * pi_to_the() == + CHECK(pi_to_the<1>() * mag() * pi_to_the() == magnitude{ratio{1, 2}}>{}); } SECTION("Supports constexpr") { - constexpr auto p = as_magnitude() * as_magnitude(); - CHECK(p == as_magnitude()); + constexpr auto p = mag() * mag(); + CHECK(p == mag()); } } @@ -289,20 +283,20 @@ TEST_CASE("Common Magnitude") { SECTION("Identity for identical magnitudes") { - CHECK(common_magnitude(as_magnitude<1>(), as_magnitude<1>()) == as_magnitude<1>()); - CHECK(common_magnitude(as_magnitude<15>(), as_magnitude<15>()) == as_magnitude<15>()); + CHECK(common_magnitude(mag<1>(), mag<1>()) == mag<1>()); + CHECK(common_magnitude(mag<15>(), mag<15>()) == mag<15>()); CHECK(common_magnitude(pi_to_the(), pi_to_the()) == pi_to_the()); } SECTION("Greatest Common Factor for integers") { - CHECK(common_magnitude(as_magnitude<24>(), as_magnitude<36>()) == as_magnitude<12>()); - CHECK(common_magnitude(as_magnitude<24>(), as_magnitude<37>()) == as_magnitude<1>()); + CHECK(common_magnitude(mag<24>(), mag<36>()) == mag<12>()); + CHECK(common_magnitude(mag<24>(), mag<37>()) == mag<1>()); } SECTION("Handles fractions") { - CHECK(common_magnitude(as_magnitude(), as_magnitude()) == as_magnitude()); + CHECK(common_magnitude(mag(), mag()) == mag()); } } @@ -310,19 +304,16 @@ TEST_CASE("Division works for magnitudes") { SECTION("Dividing anything by itself reduces to null magnitude") { - CHECK(as_magnitude() / as_magnitude() == as_magnitude<1>()); - CHECK(as_magnitude<15>() / as_magnitude<15>() == as_magnitude<1>()); + CHECK(mag() / mag() == mag<1>()); + CHECK(mag<15>() / mag<15>() == mag<1>()); } - SECTION("Quotients work as expected") - { - CHECK(as_magnitude() / as_magnitude() == as_magnitude()); - } + SECTION("Quotients work as expected") { CHECK(mag() / mag() == mag()); } SECTION("Supports constexpr") { - constexpr auto q = as_magnitude() / as_magnitude(); - CHECK(q == as_magnitude()); + constexpr auto q = mag() / mag(); + CHECK(q == mag()); } } @@ -330,17 +321,17 @@ TEST_CASE("Can raise Magnitudes to rational powers") { SECTION("Anything to the 0 is 1") { - CHECK(pow<0>(as_magnitude<1>()) == as_magnitude<1>()); - CHECK(pow<0>(as_magnitude<123>()) == as_magnitude<1>()); - CHECK(pow<0>(as_magnitude()) == as_magnitude<1>()); - CHECK(pow<0>(pi_to_the()) == as_magnitude<1>()); + CHECK(pow<0>(mag<1>()) == mag<1>()); + CHECK(pow<0>(mag<123>()) == mag<1>()); + CHECK(pow<0>(mag()) == mag<1>()); + CHECK(pow<0>(pi_to_the()) == mag<1>()); } SECTION("Anything to the 1 is itself") { - CHECK(pow<1>(as_magnitude<1>()) == as_magnitude<1>()); - CHECK(pow<1>(as_magnitude<123>()) == as_magnitude<123>()); - CHECK(pow<1>(as_magnitude()) == as_magnitude()); + CHECK(pow<1>(mag<1>()) == mag<1>()); + CHECK(pow<1>(mag<123>()) == mag<123>()); + CHECK(pow<1>(mag()) == mag()); CHECK(pow<1>(pi_to_the()) == pi_to_the()); } @@ -359,11 +350,11 @@ TEST_CASE("can distinguish integral, rational, and irrational magnitudes") CHECK(is_rational(m)); }; check_rational_and_integral(magnitude<>{}); - check_rational_and_integral(as_magnitude<1>()); - check_rational_and_integral(as_magnitude<3>()); - check_rational_and_integral(as_magnitude<8>()); - check_rational_and_integral(as_magnitude<412>()); - check_rational_and_integral(as_magnitude()); + check_rational_and_integral(mag<1>()); + check_rational_and_integral(mag<3>()); + check_rational_and_integral(mag<8>()); + check_rational_and_integral(mag<412>()); + check_rational_and_integral(mag()); } SECTION("Fractional magnitudes are rational, but not integral") @@ -372,8 +363,8 @@ TEST_CASE("can distinguish integral, rational, and irrational magnitudes") CHECK(!is_integral(m)); CHECK(is_rational(m)); }; - check_rational_but_not_integral(as_magnitude()); - check_rational_but_not_integral(as_magnitude()); + check_rational_but_not_integral(mag()); + check_rational_but_not_integral(mag()); } } @@ -390,17 +381,17 @@ TEST_CASE("Constructing ratio from rational magnitude") SECTION("Rational magnitude converts to ratio") { - constexpr ratio r = as_ratio(as_magnitude()); + constexpr ratio r = as_ratio(mag()); CHECK(r == ratio{22, 7}); } SECTION("Irrational magnitude does not convert to ratio") { // The following code should not compile. - // as_ratio(pow(as_magnitude<2>())); + // as_ratio(pow(mag<2>())); // The following code should not compile. - // as_ratio(as_magnitude<180>() / pi_to_the<1>()); + // as_ratio(mag<180>() / pi_to_the<1>()); } } @@ -607,26 +598,26 @@ TEST_CASE("extract_power_of_10") { SECTION("Picks out positive powers") { - CHECK(extract_power_of_10(as_magnitude<10>()) == 1); - CHECK(extract_power_of_10(as_magnitude<20>()) == 1); - CHECK(extract_power_of_10(as_magnitude<40>()) == 1); - CHECK(extract_power_of_10(as_magnitude<50>()) == 1); - CHECK(extract_power_of_10(as_magnitude<100>()) == 2); + CHECK(extract_power_of_10(mag<10>()) == 1); + CHECK(extract_power_of_10(mag<20>()) == 1); + CHECK(extract_power_of_10(mag<40>()) == 1); + CHECK(extract_power_of_10(mag<50>()) == 1); + CHECK(extract_power_of_10(mag<100>()) == 2); } SECTION("Picks out negative powers") { - constexpr auto ONE = as_magnitude<1>(); - CHECK(extract_power_of_10(ONE / as_magnitude<10>()) == -1); - CHECK(extract_power_of_10(ONE / as_magnitude<20>()) == -1); - CHECK(extract_power_of_10(ONE / as_magnitude<40>()) == -1); - CHECK(extract_power_of_10(ONE / as_magnitude<50>()) == -1); - CHECK(extract_power_of_10(ONE / as_magnitude<100>()) == -2); + constexpr auto ONE = mag<1>(); + CHECK(extract_power_of_10(ONE / mag<10>()) == -1); + CHECK(extract_power_of_10(ONE / mag<20>()) == -1); + CHECK(extract_power_of_10(ONE / mag<40>()) == -1); + CHECK(extract_power_of_10(ONE / mag<50>()) == -1); + CHECK(extract_power_of_10(ONE / mag<100>()) == -2); } - SECTION("Zero if signs disagree") { CHECK(extract_power_of_10(as_magnitude<2>() / as_magnitude<5>()) == 0); } + SECTION("Zero if signs disagree") { CHECK(extract_power_of_10(mag<2>() / mag<5>()) == 0); } - SECTION("Handles rational powers") { CHECK(extract_power_of_10(sqrt(as_magnitude<1000>())) == 1); } + SECTION("Handles rational powers") { CHECK(extract_power_of_10(sqrt(mag<1000>())) == 1); } } } // namespace diff --git a/test/unit_test/static/quantity_kind_test.cpp b/test/unit_test/static/quantity_kind_test.cpp index c421ec12..1d246f23 100644 --- a/test/unit_test/static/quantity_kind_test.cpp +++ b/test/unit_test/static/quantity_kind_test.cpp @@ -456,9 +456,9 @@ concept invalid_compound_assignments = requires !requires { w *= m; }; requires !requires { w /= m; }; requires !requires { w %= m; }; - requires !requires { w *= quantity_kind, scaled_unit(), one>, int>{1}; }; - requires !requires { w /= quantity_kind, scaled_unit(), one>, int>{1}; }; - requires !requires { w %= quantity_kind, scaled_unit(), one>, int>{1}; }; + requires !requires { w *= quantity_kind, scaled_unit(), one>, int>{1}; }; + requires !requires { w /= quantity_kind, scaled_unit(), one>, int>{1}; }; + requires !requires { w %= quantity_kind, scaled_unit(), one>, int>{1}; }; requires !requires { w %= 1.0; }; requires !requires { w %= quantity(1.0); }; requires !requires { w %= 1.0 * (w / w); }; diff --git a/test/unit_test/static/quantity_test.cpp b/test/unit_test/static/quantity_test.cpp index a47c5782..576c6679 100644 --- a/test/unit_test/static/quantity_test.cpp +++ b/test/unit_test/static/quantity_test.cpp @@ -498,7 +498,7 @@ static_assert(compare> static_assert(compare>); static_assert(compare>); static_assert(compare(1) / 1_q_s), - frequency(), hertz>, std::int64_t>>); + frequency(), hertz>, std::int64_t>>); static_assert(is_same_v); static_assert(is_same_v); @@ -529,7 +529,7 @@ static_assert(compare> static_assert(compare>); static_assert(compare>); static_assert(compare(1) / 1._q_s), - frequency(), hertz>, long double>>); + frequency(), hertz>, long double>>); static_assert(compare>); static_assert(compare>); static_assert(compare(1)), length>); @@ -551,7 +551,7 @@ static_assert(compare> static_assert(compare>); static_assert(compare>); static_assert(compare(1) / 1_q_s), - frequency(), hertz>, long double>>); + frequency(), hertz>, long double>>); // different units static_assert(compare>); @@ -579,24 +579,23 @@ static_assert(is_same_v>); -static_assert(compare(), metre>, std::int64_t>>); +static_assert(compare(), metre>, std::int64_t>>); static_assert( compare, exponent>, - scaled_unit(), unknown_coherent_unit>, std::int64_t>>); + scaled_unit(), unknown_coherent_unit>, std::int64_t>>); static_assert(compare>); -static_assert( - compare(), hertz>, std::int64_t>>); +static_assert(compare(), hertz>, std::int64_t>>); static_assert(compare>); -static_assert(compare>, - scaled_unit(), unknown_coherent_unit>, std::int64_t>>); -static_assert(compare(), one>, std::int64_t>>); +static_assert( + compare>, + scaled_unit(), unknown_coherent_unit>, std::int64_t>>); +static_assert(compare(), one>, std::int64_t>>); static_assert(compare>); static_assert( - compare(), metre_per_second>, std::int64_t>>); + compare(), metre_per_second>, std::int64_t>>); static_assert( compare, exponent>, - scaled_unit(), unknown_coherent_unit>, std::int64_t>>); + scaled_unit(), unknown_coherent_unit>, std::int64_t>>); static_assert((1_q_m + 1_q_m).number() == 2); static_assert((1_q_m + 1_q_km).number() == 1001); @@ -886,9 +885,8 @@ static_assert(!is_same_v(2_q_dm3)), volume, units::exponent>, - scaled_unit(), unknown_coherent_unit>, std::int64_t>>); -static_assert( - is_same_v(), metre>, std::int64_t>>); + scaled_unit(), unknown_coherent_unit>, std::int64_t>>); +static_assert(is_same_v(), metre>, std::int64_t>>); #else @@ -918,8 +916,7 @@ static_assert(same(quotient_remainder_theorem(3'000 * m, 400), 3'000 * m)); static_assert(comp(quotient_remainder_theorem(3'000 * m, quantity(400)), 3'000 * m)); static_assert(comp(quotient_remainder_theorem(3 * km, quantity(400)), 3 * km)); static_assert(comp(quotient_remainder_theorem(3 * km, quantity(2)), 3 * km)); -static_assert( - comp(quotient_remainder_theorem(3 * km, dimensionless(), one>, int>(400)), - 3 * km)); +static_assert(comp(quotient_remainder_theorem(3 * km, dimensionless(), one>, int>(400)), + 3 * km)); } // namespace diff --git a/test/unit_test/static/si_test.cpp b/test/unit_test/static/si_test.cpp index 02960463..103e1837 100644 --- a/test/unit_test/static/si_test.cpp +++ b/test/unit_test/static/si_test.cpp @@ -43,7 +43,7 @@ static_assert(1_q_au == 149'597'870'700_q_m); static_assert(1_q_km + 1_q_m == 1001_q_m); static_assert(10_q_km / 5_q_km == 2); static_assert(10_q_km / 5_q_km < 3); -static_assert(100_q_mm / 5_q_cm == dimensionless(), one>>(20)); +static_assert(100_q_mm / 5_q_cm == dimensionless(), one>>(20)); static_assert(100_q_mm / 5_q_cm == dimensionless(2)); static_assert(10_q_km / 2 == 5_q_km); @@ -107,7 +107,7 @@ static_assert(1000 / 1_q_s == 1_q_kHz); static_assert(1 / 1_q_ms == 1_q_kHz); static_assert(3.2_q_GHz == 3'200'000'000_q_Hz); static_assert((10_q_Hz * 1_q_min).number() == 10); -static_assert(10_q_Hz * 1_q_min == dimensionless(), one>>(10)); +static_assert(10_q_Hz * 1_q_min == dimensionless(), one>>(10)); static_assert(10_q_Hz * 1_q_min == dimensionless(600)); static_assert(2 / 1_q_Hz == 2_q_s); diff --git a/test/unit_test/static/unit_test.cpp b/test/unit_test/static/unit_test.cpp index c4d4baf6..ded5edad 100644 --- a/test/unit_test/static/unit_test.cpp +++ b/test/unit_test/static/unit_test.cpp @@ -36,12 +36,12 @@ using namespace units::isq; struct metre : named_unit {}; struct centimetre : prefixed_unit {}; struct kilometre : prefixed_unit {}; -struct yard : named_scaled_unit(), metre> {}; -struct foot : named_scaled_unit(), yard> {}; +struct yard : named_scaled_unit(), metre> {}; +struct foot : named_scaled_unit(), yard> {}; struct dim_length : base_dimension<"length", metre> {}; struct second : named_unit {}; -struct hour : named_scaled_unit(), second> {}; +struct hour : named_scaled_unit(), second> {}; struct dim_time : base_dimension<"time", second> {}; struct kelvin : named_unit {}; @@ -59,10 +59,10 @@ struct kilometre_per_hour : derived_scaled_unit); static_assert(equivalent); -static_assert(compare(), metre>>, metre>); -static_assert(compare(), metre>>, centimetre>); +static_assert(compare(), metre>>, metre>); +static_assert(compare(), metre>>, centimetre>); static_assert(compare>, yard>); -static_assert(compare(), metre>>, foot>); +static_assert(compare(), metre>>, foot>); static_assert(compare>, kilometre_per_hour>); static_assert(centimetre::symbol == "cm"); From f6f7f9bafb63544a1e43328be62e736073800b49 Mon Sep 17 00:00:00 2001 From: Chip Hogg Date: Fri, 29 Jul 2022 14:16:49 +0000 Subject: [PATCH 11/52] Explicitly qualify `mag<>` that initializes `mag` member This should fix clang's complaint. --- src/core/include/units/chrono.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/include/units/chrono.h b/src/core/include/units/chrono.h index 4bd918b9..d7b900a1 100644 --- a/src/core/include/units/chrono.h +++ b/src/core/include/units/chrono.h @@ -34,7 +34,7 @@ namespace units { template struct quantity_like_traits> { private: - static constexpr auto mag = mag(); + static constexpr auto mag = ::units::mag(); public: using dimension = isq::si::dim_time; using unit = downcast_unit; @@ -48,7 +48,7 @@ struct clock_origin : point_origin {}; template struct quantity_point_like_traits>> { private: - static constexpr auto mag = mag(); + static constexpr auto mag = ::units::mag(); public: using origin = clock_origin; using unit = downcast_unit; From e988e1d74e4ae886c1fb8c63b1a68fb7aaca7e85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johel=20Ernesto=20Guerrero=20Pe=C3=B1a?= Date: Fri, 29 Jul 2022 17:17:07 -0400 Subject: [PATCH 12/52] refactor: update hacks for LLVM 16 --- src/core/include/units/quantity.h | 2 +- test/unit_test/static/quantity_test.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/include/units/quantity.h b/src/core/include/units/quantity.h index 6f9f9d0c..3b45cba2 100644 --- a/src/core/include/units/quantity.h +++ b/src/core/include/units/quantity.h @@ -444,7 +444,7 @@ public: }; // CTAD -#if !UNITS_COMP_CLANG || UNITS_COMP_CLANG > 15 +#if !UNITS_COMP_CLANG || UNITS_COMP_CLANG > 16 template explicit(false) quantity(Rep&&)->quantity; #endif diff --git a/test/unit_test/static/quantity_test.cpp b/test/unit_test/static/quantity_test.cpp index 576c6679..d631d1a6 100644 --- a/test/unit_test/static/quantity_test.cpp +++ b/test/unit_test/static/quantity_test.cpp @@ -287,7 +287,7 @@ static_assert(get_length_derived_quantity() == 1_q_m); // CTAD ///////// -#if UNITS_COMP_GCC >= 11 || UNITS_COMP_CLANG > 15 +#if UNITS_COMP_GCC >= 11 || UNITS_COMP_CLANG > 16 static_assert(std::is_same_v); static_assert(std::is_same_v); static_assert( From 5efbda75d563d49a1637bae241155140161c2842 Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Sat, 30 Jul 2022 10:57:59 +0200 Subject: [PATCH 13/52] build(conan): `cmake_layout` import added too early by an accident --- conanfile.py | 34 ++++------------------------------ 1 file changed, 4 insertions(+), 30 deletions(-) diff --git a/conanfile.py b/conanfile.py index 0fccdad0..019150cb 100644 --- a/conanfile.py +++ b/conanfile.py @@ -25,7 +25,7 @@ import re from conan import ConanFile from conan.tools.build import check_min_cppstd -from conan.tools.cmake import CMake, CMakeDeps, CMakeToolchain, cmake_layout +from conan.tools.cmake import CMake, CMakeDeps, CMakeToolchain from conan.tools.files import copy, load, rmdir from conan.tools.scm import Version from conans.errors import ConanInvalidConfiguration @@ -152,6 +152,9 @@ class MPUnitsConan(ConanFile): # # build_docs has sense only in a development or CI build # del self.options.build_docs + def layout(self): + cmake_layout(self) + def generate(self): tc = CMakeToolchain(self) tc.variables["UNITS_DOWNCAST_MODE"] = str(self.options.downcast_mode).upper() @@ -188,7 +191,6 @@ class MPUnitsConan(ConanFile): # core self.cpp_info.components["core"].requires = ["gsl-lite::gsl-lite"] - self.cpp_info.components["core"].includedirs = ["include"] if compiler == "Visual Studio": self.cpp_info.components["core"].cxxflags = ["/utf-8"] if self._use_range_v3: @@ -196,49 +198,21 @@ class MPUnitsConan(ConanFile): # rest self.cpp_info.components["core-io"].requires = ["core"] - self.cpp_info.components["core-io"].includedirs = ["include"] - self.cpp_info.components["core-fmt"].requires = ["core"] - self.cpp_info.components["core-fmt"].includedirs = ["include"] if self._use_libfmt: self.cpp_info.components["core-fmt"].requires.append("fmt::fmt") - self.cpp_info.components["isq"].requires = ["core"] - self.cpp_info.components["isq"].includedirs = ["include"] - self.cpp_info.components["isq-natural"].requires = ["isq"] - self.cpp_info.components["isq-natural"].includedirs = ["include"] - self.cpp_info.components["si"].requires = ["isq"] - self.cpp_info.components["si"].includedirs = ["include"] - self.cpp_info.components["si-cgs"].requires = ["si"] - self.cpp_info.components["si-cgs"].includedirs = ["include"] - self.cpp_info.components["si-fps"].requires = ["si-international"] - self.cpp_info.components["si-fps"].includedirs = ["include"] - self.cpp_info.components["si-hep"].requires = ["si"] - self.cpp_info.components["si-hep"].includedirs = ["include"] - self.cpp_info.components["si-iau"].requires = ["si"] - self.cpp_info.components["si-iau"].includedirs = ["include"] - self.cpp_info.components["si-imperial"].requires = ["si"] - self.cpp_info.components["si-imperial"].includedirs = ["include"] - self.cpp_info.components["si-international"].requires = ["si"] - self.cpp_info.components["si-international"].includedirs = ["include"] - self.cpp_info.components["si-typographic"].requires = ["si"] - self.cpp_info.components["si-typographic"].includedirs = ["include"] - self.cpp_info.components["si-uscs"].requires = ["si"] - self.cpp_info.components["si-uscs"].includedirs = ["include"] - self.cpp_info.components["isq-iec80000"].requires = ["si"] - self.cpp_info.components["isq-iec80000"].includedirs = ["include"] - self.cpp_info.components["systems"].requires = [ "isq", "isq-natural", From 2e410278baa4301011511dfa57c3a4167a606b0e Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Sat, 30 Jul 2022 14:29:17 +0200 Subject: [PATCH 14/52] Revert "build(conan): `cmake_layout` import added too early by an accident" This reverts commit 5efbda75d563d49a1637bae241155140161c2842. --- conanfile.py | 34 ++++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/conanfile.py b/conanfile.py index 019150cb..0fccdad0 100644 --- a/conanfile.py +++ b/conanfile.py @@ -25,7 +25,7 @@ import re from conan import ConanFile from conan.tools.build import check_min_cppstd -from conan.tools.cmake import CMake, CMakeDeps, CMakeToolchain +from conan.tools.cmake import CMake, CMakeDeps, CMakeToolchain, cmake_layout from conan.tools.files import copy, load, rmdir from conan.tools.scm import Version from conans.errors import ConanInvalidConfiguration @@ -152,9 +152,6 @@ class MPUnitsConan(ConanFile): # # build_docs has sense only in a development or CI build # del self.options.build_docs - def layout(self): - cmake_layout(self) - def generate(self): tc = CMakeToolchain(self) tc.variables["UNITS_DOWNCAST_MODE"] = str(self.options.downcast_mode).upper() @@ -191,6 +188,7 @@ class MPUnitsConan(ConanFile): # core self.cpp_info.components["core"].requires = ["gsl-lite::gsl-lite"] + self.cpp_info.components["core"].includedirs = ["include"] if compiler == "Visual Studio": self.cpp_info.components["core"].cxxflags = ["/utf-8"] if self._use_range_v3: @@ -198,21 +196,49 @@ class MPUnitsConan(ConanFile): # rest self.cpp_info.components["core-io"].requires = ["core"] + self.cpp_info.components["core-io"].includedirs = ["include"] + self.cpp_info.components["core-fmt"].requires = ["core"] + self.cpp_info.components["core-fmt"].includedirs = ["include"] if self._use_libfmt: self.cpp_info.components["core-fmt"].requires.append("fmt::fmt") + self.cpp_info.components["isq"].requires = ["core"] + self.cpp_info.components["isq"].includedirs = ["include"] + self.cpp_info.components["isq-natural"].requires = ["isq"] + self.cpp_info.components["isq-natural"].includedirs = ["include"] + self.cpp_info.components["si"].requires = ["isq"] + self.cpp_info.components["si"].includedirs = ["include"] + self.cpp_info.components["si-cgs"].requires = ["si"] + self.cpp_info.components["si-cgs"].includedirs = ["include"] + self.cpp_info.components["si-fps"].requires = ["si-international"] + self.cpp_info.components["si-fps"].includedirs = ["include"] + self.cpp_info.components["si-hep"].requires = ["si"] + self.cpp_info.components["si-hep"].includedirs = ["include"] + self.cpp_info.components["si-iau"].requires = ["si"] + self.cpp_info.components["si-iau"].includedirs = ["include"] + self.cpp_info.components["si-imperial"].requires = ["si"] + self.cpp_info.components["si-imperial"].includedirs = ["include"] + self.cpp_info.components["si-international"].requires = ["si"] + self.cpp_info.components["si-international"].includedirs = ["include"] + self.cpp_info.components["si-typographic"].requires = ["si"] + self.cpp_info.components["si-typographic"].includedirs = ["include"] + self.cpp_info.components["si-uscs"].requires = ["si"] + self.cpp_info.components["si-uscs"].includedirs = ["include"] + self.cpp_info.components["isq-iec80000"].requires = ["si"] + self.cpp_info.components["isq-iec80000"].includedirs = ["include"] + self.cpp_info.components["systems"].requires = [ "isq", "isq-natural", From 7cd168377f39b5acf7bb2d1e1370b5737780891a Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Sat, 30 Jul 2022 14:30:16 +0200 Subject: [PATCH 15/52] build(conan): Conanfile fixed after the last wrong commit --- conanfile.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conanfile.py b/conanfile.py index 0fccdad0..f9d3dcb1 100644 --- a/conanfile.py +++ b/conanfile.py @@ -25,7 +25,7 @@ import re from conan import ConanFile from conan.tools.build import check_min_cppstd -from conan.tools.cmake import CMake, CMakeDeps, CMakeToolchain, cmake_layout +from conan.tools.cmake import CMake, CMakeDeps, CMakeToolchain from conan.tools.files import copy, load, rmdir from conan.tools.scm import Version from conans.errors import ConanInvalidConfiguration From 5bd378a835909120f58a61d2c89c8732ff775080 Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Sun, 31 Jul 2022 15:45:40 +0200 Subject: [PATCH 16/52] refactor: `base_units_ratio.h` renamed to `absolute_magnitude.h` --- .../units/bits/{base_units_ratio.h => absolute_magnitude.h} | 0 src/core/include/units/derived_dimension.h | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename src/core/include/units/bits/{base_units_ratio.h => absolute_magnitude.h} (100%) diff --git a/src/core/include/units/bits/base_units_ratio.h b/src/core/include/units/bits/absolute_magnitude.h similarity index 100% rename from src/core/include/units/bits/base_units_ratio.h rename to src/core/include/units/bits/absolute_magnitude.h diff --git a/src/core/include/units/derived_dimension.h b/src/core/include/units/derived_dimension.h index cfe0830c..8033f463 100644 --- a/src/core/include/units/derived_dimension.h +++ b/src/core/include/units/derived_dimension.h @@ -23,7 +23,7 @@ #pragma once #include -#include +#include #include #include #include From bb5c02e09e91d76d0a809690656da75d92bdbb9f Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Mon, 1 Aug 2022 10:03:55 +0200 Subject: [PATCH 17/52] fix: Quantity inversion operation fixed Resolves #367 --- src/core/include/units/quantity.h | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/core/include/units/quantity.h b/src/core/include/units/quantity.h index 3b45cba2..c1e99d29 100644 --- a/src/core/include/units/quantity.h +++ b/src/core/include/units/quantity.h @@ -405,11 +405,7 @@ public: requires(!Quantity) && (invoke_result_convertible_to_, const Value&, rep>) [[nodiscard]] friend constexpr Quantity auto operator/(const Value& v, const quantity& q) { - gsl_ExpectsAudit(q.number() != quantity_values::zero()); - using dim = dim_invert; - using ret_unit = downcast_unit(U::mag)>; - using ret = quantity, Value, rep>>; - return ret(v / q.number()); + return detail::make_quantity<::units::reference{} / reference>(v / q.number()); } template From 0ebf85b9db431360746f67b8a8c46cc3a572e83a Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Mon, 1 Aug 2022 11:59:00 +0200 Subject: [PATCH 18/52] fix: `unknown_coherent_unit` fixed --- example/custom_systems.cpp | 8 +++--- src/core/include/units/base_dimension.h | 1 + .../include/units/bits/absolute_magnitude.h | 2 +- src/core/include/units/bits/common_type.h | 8 +++--- .../include/units/bits/derived_scaled_unit.h | 2 +- src/core/include/units/bits/dimension_op.h | 4 +-- src/core/include/units/bits/equivalent.h | 4 +-- src/core/include/units/bits/quantity_of.h | 7 ++--- src/core/include/units/derived_dimension.h | 8 +++--- src/core/include/units/quantity_cast.h | 18 ++++--------- src/core/include/units/reference.h | 19 +++++--------- src/core/include/units/unit.h | 7 ++++- .../static/dimensions_concepts_test.cpp | 11 +++++--- test/unit_test/static/quantity_test.cpp | 26 ++++++++++++------- test/unit_test/static/si_cgs_test.cpp | 19 +++++++++++++- 15 files changed, 82 insertions(+), 62 deletions(-) diff --git a/example/custom_systems.cpp b/example/custom_systems.cpp index 9fe72f4e..c708bf0f 100644 --- a/example/custom_systems.cpp +++ b/example/custom_systems.cpp @@ -84,14 +84,14 @@ void conversions() void unknown_dimensions() { constexpr auto fps_yard = fps::length(1.); - constexpr auto fps_area = quantity_cast(fps_yard * fps_yard); + constexpr auto fps_area = fps_yard * fps_yard; std::cout << fps_yard << "\n"; - std::cout << fps_area << "\n"; + std::cout << quantity_cast(fps_area) << "\n"; constexpr auto si_fps_yard = si::fps::length(1.); - constexpr auto si_fps_area = quantity_cast(si_fps_yard * si_fps_yard); + constexpr auto si_fps_area = si_fps_yard * si_fps_yard; std::cout << si_fps_yard << "\n"; - std::cout << si_fps_area << "\n"; + std::cout << quantity_cast(si_fps_area) << "\n"; } std::ostream& operator<<(std::ostream& os, const ratio& r) { return os << "ratio{" << r.num << ", " << r.den << "}"; } diff --git a/src/core/include/units/base_dimension.h b/src/core/include/units/base_dimension.h index 7515d97b..0af40adb 100644 --- a/src/core/include/units/base_dimension.h +++ b/src/core/include/units/base_dimension.h @@ -54,6 +54,7 @@ template struct base_dimension { static constexpr auto symbol = Symbol; ///< Unique base dimension identifier using base_unit = U; ///< Base unit adopted for this dimension + static constexpr UNITS_MSVC_WORKAROUND(Magnitude) auto mag = magnitude{}; }; // base_dimension_less diff --git a/src/core/include/units/bits/absolute_magnitude.h b/src/core/include/units/bits/absolute_magnitude.h index 2d9703e3..0216313f 100644 --- a/src/core/include/units/bits/absolute_magnitude.h +++ b/src/core/include/units/bits/absolute_magnitude.h @@ -42,7 +42,7 @@ namespace units::detail { template constexpr Magnitude auto absolute_magnitude(exponent_list) { - return (pow(Es::dimension::base_unit::mag) * ... * magnitude<>{}); + return (magnitude<>{} * ... * pow(Es::dimension::base_unit::mag)); } } // namespace units::detail diff --git a/src/core/include/units/bits/common_type.h b/src/core/include/units/bits/common_type.h index 46f7cb5f..8955d5ab 100644 --- a/src/core/include/units/bits/common_type.h +++ b/src/core/include/units/bits/common_type.h @@ -66,15 +66,13 @@ struct common_quantity_reference_impl, reference> { template struct common_quantity_reference_impl, reference> { + static constexpr UNITS_MSVC_WORKAROUND(Magnitude) auto mag = common_magnitude(reference::mag, + reference::mag); using dimension = conditional, D2, D1>; - static constexpr UNITS_MSVC_WORKAROUND(Magnitude) auto m1 = D1::base_units_ratio * U1::mag; - static constexpr UNITS_MSVC_WORKAROUND(Magnitude) auto m2 = D2::base_units_ratio * U2::mag; - static constexpr UNITS_MSVC_WORKAROUND(Magnitude) auto cm = common_magnitude(m1, m2); - using unit = downcast_unit; + using unit = downcast_unit; using type = reference; }; - template Q2> using common_quantity_reference = TYPENAME detail::common_quantity_reference_impl, diff --git a/src/core/include/units/bits/derived_scaled_unit.h b/src/core/include/units/bits/derived_scaled_unit.h index ecdaf48f..d62b6f45 100644 --- a/src/core/include/units/bits/derived_scaled_unit.h +++ b/src/core/include/units/bits/derived_scaled_unit.h @@ -39,7 +39,7 @@ inline constexpr bool compatible_units, Us...> = (UnitOf constexpr Magnitude auto derived_mag(exponent_list) { - return (mag<1>() * ... * pow(Us::mag / dimension_unit::mag)); + return (magnitude<>{} * ... * pow(Us::mag / dimension_unit::mag)); } template diff --git a/src/core/include/units/bits/dimension_op.h b/src/core/include/units/bits/dimension_op.h index 88580625..820fbc82 100644 --- a/src/core/include/units/bits/dimension_op.h +++ b/src/core/include/units/bits/dimension_op.h @@ -37,12 +37,12 @@ namespace units { * * Sometimes a temporary partial result of a complex calculation may not result in a predefined * dimension. In such a case an `unknown_dimension` is created with a coherent unit of `unknown_coherent_unit` - * and ratio(1). + * with a magnitude being the absolute one of all the exponents of such a dimension. * * @tparam Es the list of exponents of ingredient dimensions */ template -struct unknown_dimension : derived_dimension, unknown_coherent_unit, Es...> {}; +struct unknown_dimension : derived_dimension, unknown_coherent_unit, Es...> {}; namespace detail { diff --git a/src/core/include/units/bits/equivalent.h b/src/core/include/units/bits/equivalent.h index 5bdac612..2fa174ba 100644 --- a/src/core/include/units/bits/equivalent.h +++ b/src/core/include/units/bits/equivalent.h @@ -23,6 +23,7 @@ #pragma once #include +#include #include namespace units { @@ -72,8 +73,7 @@ struct equivalent_impl : // additionally accounts for unknown dimensions template struct equivalent_unit : - std::disjunction, - std::bool_constant::mag == U2::mag / dimension_unit::mag>> {}; + std::disjunction, std::bool_constant::mag == reference::mag>> {}; // point origins diff --git a/src/core/include/units/bits/quantity_of.h b/src/core/include/units/bits/quantity_of.h index ef7e8d77..1e53d22b 100644 --- a/src/core/include/units/bits/quantity_of.h +++ b/src/core/include/units/bits/quantity_of.h @@ -37,9 +37,10 @@ inline constexpr bool same_exponents_of = false; template typename DimTemplate> inline constexpr bool same_exponents_of, DimTemplate> = - requires { typename DimTemplate, unknown_coherent_unit, typename Es::dimension...>; } && - std::same_as, typename DimTemplate, unknown_coherent_unit, - typename Es::dimension...>::recipe>; + requires { + typename DimTemplate, unknown_coherent_unit, typename Es::dimension...>; + }&& std::same_as, typename DimTemplate, unknown_coherent_unit, + typename Es::dimension...>::recipe>; } // namespace detail diff --git a/src/core/include/units/derived_dimension.h b/src/core/include/units/derived_dimension.h index 8033f463..0af2e096 100644 --- a/src/core/include/units/derived_dimension.h +++ b/src/core/include/units/derived_dimension.h @@ -72,8 +72,8 @@ using make_dimension = TYPENAME to_derived_dimension_base< * and in CGS barye. Those two units are not directly related with each other with some ratio. As they both are * coherent units of their dimensions, the ratio between them is directly determined by the ratios of base units * defined in base dimensions end their exponents in the derived dimension recipe. To provide interoperability of - * such quantities of different systems base_units_ratio is being used. The result of the division of two - * base_units_ratio of two quantities of equivalent dimensions in two different systems gives a ratio between their + * such quantities of different systems mag is being used. The result of the division of two + * mag of two quantities of equivalent dimensions in two different systems gives a ratio between their * coherent units. Alternatively, the user would always have to directly define a barye in terms of pascal or vice * versa. * @@ -85,8 +85,8 @@ template struct derived_dimension : downcast_dispatch> { using recipe = exponent_list; using coherent_unit = U; - static constexpr UNITS_MSVC_WORKAROUND(Magnitude) auto base_units_ratio = - detail::absolute_magnitude(typename derived_dimension::exponents()); + static constexpr UNITS_MSVC_WORKAROUND(Magnitude) auto mag = + detail::absolute_magnitude(typename derived_dimension::exponents()) / U::mag; }; } // namespace units diff --git a/src/core/include/units/quantity_cast.h b/src/core/include/units/quantity_cast.h index fdb90aef..5295f3a1 100644 --- a/src/core/include/units/quantity_cast.h +++ b/src/core/include/units/quantity_cast.h @@ -28,6 +28,7 @@ #include #include #include +#include UNITS_DIAGNOSTIC_PUSH // warning C4244: 'argument': conversion from 'intmax_t' to 'T', possible loss of data with T=int @@ -49,17 +50,8 @@ class quantity_point_kind; namespace detail { -template -inline constexpr Magnitude auto quantity_magnitude = std::enable_if_t, magnitude<>>{}; - -template -inline constexpr Magnitude auto quantity_magnitude> = [] { - if constexpr (BaseDimension) { - return U::mag; - } else { - return D::base_units_ratio * U::mag / D::coherent_unit::mag; - } -}(); +template +inline constexpr Magnitude auto quantity_magnitude = decltype(Q::reference)::mag; template inline constexpr ratio quantity_ratio = as_ratio(quantity_magnitude); @@ -79,8 +71,8 @@ template struct cast_traits; template - requires common_type_with_, - std::intmax_t> struct cast_traits { + requires common_type_with_, std::intmax_t> +struct cast_traits { using ratio_type = std::common_type_t, std::intmax_t>; using rep_type = ratio_type; }; diff --git a/src/core/include/units/reference.h b/src/core/include/units/reference.h index 200cc2fb..c6a68fb1 100644 --- a/src/core/include/units/reference.h +++ b/src/core/include/units/reference.h @@ -35,27 +35,21 @@ struct reference; namespace detail { -template -using reference_multiply_impl = - reference::mag) * (U2::mag / dimension_unit::mag) * - dimension_unit::mag>>; +template +using reference_multiply_impl = reference>; -template -using reference_divide_impl = - reference::mag) / (U2::mag / dimension_unit::mag) * - dimension_unit::mag>>; +template +using reference_divide_impl = reference>; } // namespace detail template using reference_multiply = - detail::reference_multiply_impl, - typename R1::dimension, typename R1::unit, typename R2::dimension, typename R2::unit>; + detail::reference_multiply_impl, R1, R2>; template using reference_divide = - detail::reference_divide_impl, - typename R1::dimension, typename R1::unit, typename R2::dimension, typename R2::unit>; + detail::reference_divide_impl, R1, R2>; /** * @brief The type for quantity references @@ -100,6 +94,7 @@ template U> struct reference { using dimension = D; using unit = U; + static constexpr UNITS_MSVC_WORKAROUND(Magnitude) auto mag = dimension::mag * unit::mag; // Hidden Friends // Below friend functions are to be found via argument-dependent lookup only diff --git a/src/core/include/units/unit.h b/src/core/include/units/unit.h index 59e8c327..dbba2ecf 100644 --- a/src/core/include/units/unit.h +++ b/src/core/include/units/unit.h @@ -24,6 +24,7 @@ #include #include +#include // IWYU pragma: begin_exports #include @@ -58,6 +59,7 @@ inline constexpr bool can_be_prefixed = false; * @tparam M a Magnitude representing the (relative) size of this unit * @tparam U a unit to use as a reference for this dimension */ +// TODO Replace `typename` with `Unit` template struct scaled_unit : downcast_base> { static constexpr UNITS_MSVC_WORKAROUND(Magnitude) auto mag = M; @@ -188,7 +190,10 @@ struct prefixed_alias_unit : U { * * Used as a coherent unit of an unknown dimension. */ -struct unknown_coherent_unit : derived_unit {}; +template +struct unknown_coherent_unit : + downcast_dispatch, + scaled_unit()), unknown_coherent_unit>> {}; namespace detail { diff --git a/test/unit_test/static/dimensions_concepts_test.cpp b/test/unit_test/static/dimensions_concepts_test.cpp index 2b237250..f96a11dc 100644 --- a/test/unit_test/static/dimensions_concepts_test.cpp +++ b/test/unit_test/static/dimensions_concepts_test.cpp @@ -58,7 +58,8 @@ static_assert(!Area>); static_assert(Volume>); static_assert(!Volume>); #if UNITS_DOWNCAST_MODE == 0 -static_assert(Volume>, unknown_coherent_unit>>); +static_assert( + Volume>, unknown_coherent_unit>>>); #endif static_assert(Speed>); @@ -68,21 +69,23 @@ static_assert(Acceleration>); static_assert(!Acceleration>); #if UNITS_DOWNCAST_MODE == 0 static_assert(Acceleration, exponent>, - unknown_coherent_unit>>); + unknown_coherent_unit, exponent>>>); #endif static_assert(Force>); static_assert(!Force>); #if UNITS_DOWNCAST_MODE == 0 // static_assert(Force, exponent, -// exponent>, unknown_coherent_unit>>); +// exponent>, unknown_coherent_unit, +// exponent>>); #endif static_assert(Energy>); static_assert(!Energy>); #if UNITS_DOWNCAST_MODE == 0 // static_assert(Energy, exponent, -// exponent>, unknown_coherent_unit>>); +// exponent>, unknown_coherent_unit, +// exponent>>); #endif static_assert(Power>); diff --git a/test/unit_test/static/quantity_test.cpp b/test/unit_test/static/quantity_test.cpp index d631d1a6..f510e2b4 100644 --- a/test/unit_test/static/quantity_test.cpp +++ b/test/unit_test/static/quantity_test.cpp @@ -581,21 +581,26 @@ static_assert(is_same_v>); static_assert(compare(), metre>, std::int64_t>>); static_assert( - compare, exponent>, - scaled_unit(), unknown_coherent_unit>, std::int64_t>>); + compare, exponent>, + scaled_unit(), unknown_coherent_unit, exponent>>, + std::int64_t>>); static_assert(compare>); static_assert(compare(), hertz>, std::int64_t>>); static_assert(compare>); static_assert( - compare>, - scaled_unit(), unknown_coherent_unit>, std::int64_t>>); + compare>, + scaled_unit(), unknown_coherent_unit>>, std::int64_t>>); static_assert(compare(), one>, std::int64_t>>); static_assert(compare>); static_assert( compare(), metre_per_second>, std::int64_t>>); static_assert( - compare, exponent>, - scaled_unit(), unknown_coherent_unit>, std::int64_t>>); + compare, exponent>, + scaled_unit(), unknown_coherent_unit, exponent>>, + std::int64_t>>); static_assert((1_q_m + 1_q_m).number() == 2); static_assert((1_q_m + 1_q_km).number() == 1001); @@ -883,9 +888,12 @@ static_assert(!is_same_v(2_q_dm3)), volume, units::exponent>, - scaled_unit(), unknown_coherent_unit>, std::int64_t>>); +static_assert( + is_same_v, units::exponent>, + scaled_unit(), + unknown_coherent_unit, units::exponent>>, + std::int64_t>>); static_assert(is_same_v(), metre>, std::int64_t>>); #else diff --git a/test/unit_test/static/si_cgs_test.cpp b/test/unit_test/static/si_cgs_test.cpp index 42e91ad8..01f4379e 100644 --- a/test/unit_test/static/si_cgs_test.cpp +++ b/test/unit_test/static/si_cgs_test.cpp @@ -116,7 +116,7 @@ static_assert(si::length(1) + quantity_cast>(10 static_assert(100_q_cm + quantity_cast>(si::length(1)) == 200_q_cm); static_assert(quantity_cast>(si::length(1)) + 100_q_cm == 200_q_cm); -// substraction +// subtraction static_assert(500_q_cm - si::length(1) == si::length(4)); static_assert(si::length(5) - 100_q_cm == si::length(4)); @@ -150,6 +150,23 @@ static_assert(si::area(4) / quantity_cast>(si::area(4)) / 200._q_cm == 200_q_cm); +static_assert(si::cgs::length(50) == si::length(50)); +static_assert(si::cgs::mass(50) == si::mass(50)); + +static_assert(1 / si::cgs::length(50) == 1 / si::length(50)); +static_assert(1 / si::cgs::length(50) == 1 / si::length(50)); + +static_assert(1 / si::cgs::mass(50) == 1 / si::mass(50)); +static_assert(1 / si::cgs::mass(50) == 1 / si::mass(50)); + +static_assert(si::cgs::length(50) * si::cgs::mass(50) == + si::length(50) * si::mass(50)); +static_assert(si::cgs::length(50) * si::cgs::mass(50) == + si::length(50) * si::mass(50)); + +static_assert(si::cgs::length(50) / si::cgs::mass(50) == + si::length(50) / si::mass(50)); + } // namespace cgs_test } // namespace From d310bb1b8de5f8d4f632009c5366054f7b36a413 Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Mon, 1 Aug 2022 11:59:45 +0200 Subject: [PATCH 19/52] docs: Documentation updated for the latest `unknown_coherent_unit` changes --- docs/use_cases/extensions.rst | 12 ++++++------ docs/use_cases/unknown_dimensions.rst | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/use_cases/extensions.rst b/docs/use_cases/extensions.rst index fd9db565..fd2281a8 100644 --- a/docs/use_cases/extensions.rst +++ b/docs/use_cases/extensions.rst @@ -258,14 +258,14 @@ Even though the base dimension of ``si::fps`` is defined in terms of ``si::metre`` foot is preserved as the base unit of length in both systems:: constexpr auto fps_yard = fps::length(1.); - constexpr auto fps_area = quantity_cast(fps_yard * fps_yard); - std::cout << fps_yard << "\n"; // 1 yd - std::cout << fps_area << "\n"; // 9 ft² + constexpr auto fps_area = fps_yard * fps_yard; + std::cout << fps_yard << "\n"; // 1 yd + std::cout << quantity_cast(fps_area) << "\n"; // 9 ft² constexpr auto si_fps_yard = si::fps::length(1.); - constexpr auto si_fps_area = quantity_cast(si_fps_yard * si_fps_yard); - std::cout << si_fps_yard << "\n"; // 1 yd - std::cout << si_fps_area << "\n"; // 9 ft² + constexpr auto si_fps_area = si_fps_yard * si_fps_yard; + std::cout << si_fps_yard << "\n"; // 1 yd + std::cout << quantity_cast(si_fps_area) << "\n"; // 9 ft² In most cases we want conversions between systems and that is why nearly all systems provided with this library are implemented in terms on the :term:`SI` diff --git a/docs/use_cases/unknown_dimensions.rst b/docs/use_cases/unknown_dimensions.rst index d23e227f..f3e3140d 100644 --- a/docs/use_cases/unknown_dimensions.rst +++ b/docs/use_cases/unknown_dimensions.rst @@ -52,7 +52,7 @@ dimensions used in the division operation: static_assert(std::is_same_v, exponent>>); static_assert(std::is_same_v>); + scaled_unit, exponent>>>>); .. important:: @@ -81,7 +81,7 @@ this particular unknown derived dimension. In case we would like to print the result in terms of base units we can simply do the following:: - auto s = quantity_cast(result); + auto s = quantity_cast(result); std::cout << "Speed: " << s << '\n'; // prints 'Speed: 20 m/s' .. seealso:: From 804d4e1cd4f703cd54beb8119063876539f566ff Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Mon, 1 Aug 2022 18:29:03 +0200 Subject: [PATCH 20/52] build(conan): `cmake_layout` support added --- conanfile.py | 34 ++++------------------------------ test_package/conanfile.py | 13 ++++++++++--- 2 files changed, 14 insertions(+), 33 deletions(-) diff --git a/conanfile.py b/conanfile.py index f9d3dcb1..5be2c2e3 100644 --- a/conanfile.py +++ b/conanfile.py @@ -25,7 +25,7 @@ import re from conan import ConanFile from conan.tools.build import check_min_cppstd -from conan.tools.cmake import CMake, CMakeDeps, CMakeToolchain +from conan.tools.cmake import CMake, CMakeDeps, CMakeToolchain, cmake_layout from conan.tools.files import copy, load, rmdir from conan.tools.scm import Version from conans.errors import ConanInvalidConfiguration @@ -152,6 +152,9 @@ class MPUnitsConan(ConanFile): # # build_docs has sense only in a development or CI build # del self.options.build_docs + def layout(self): + cmake_layout(self) + def generate(self): tc = CMakeToolchain(self) tc.variables["UNITS_DOWNCAST_MODE"] = str(self.options.downcast_mode).upper() @@ -188,7 +191,6 @@ class MPUnitsConan(ConanFile): # core self.cpp_info.components["core"].requires = ["gsl-lite::gsl-lite"] - self.cpp_info.components["core"].includedirs = ["include"] if compiler == "Visual Studio": self.cpp_info.components["core"].cxxflags = ["/utf-8"] if self._use_range_v3: @@ -196,49 +198,21 @@ class MPUnitsConan(ConanFile): # rest self.cpp_info.components["core-io"].requires = ["core"] - self.cpp_info.components["core-io"].includedirs = ["include"] - self.cpp_info.components["core-fmt"].requires = ["core"] - self.cpp_info.components["core-fmt"].includedirs = ["include"] if self._use_libfmt: self.cpp_info.components["core-fmt"].requires.append("fmt::fmt") - self.cpp_info.components["isq"].requires = ["core"] - self.cpp_info.components["isq"].includedirs = ["include"] - self.cpp_info.components["isq-natural"].requires = ["isq"] - self.cpp_info.components["isq-natural"].includedirs = ["include"] - self.cpp_info.components["si"].requires = ["isq"] - self.cpp_info.components["si"].includedirs = ["include"] - self.cpp_info.components["si-cgs"].requires = ["si"] - self.cpp_info.components["si-cgs"].includedirs = ["include"] - self.cpp_info.components["si-fps"].requires = ["si-international"] - self.cpp_info.components["si-fps"].includedirs = ["include"] - self.cpp_info.components["si-hep"].requires = ["si"] - self.cpp_info.components["si-hep"].includedirs = ["include"] - self.cpp_info.components["si-iau"].requires = ["si"] - self.cpp_info.components["si-iau"].includedirs = ["include"] - self.cpp_info.components["si-imperial"].requires = ["si"] - self.cpp_info.components["si-imperial"].includedirs = ["include"] - self.cpp_info.components["si-international"].requires = ["si"] - self.cpp_info.components["si-international"].includedirs = ["include"] - self.cpp_info.components["si-typographic"].requires = ["si"] - self.cpp_info.components["si-typographic"].includedirs = ["include"] - self.cpp_info.components["si-uscs"].requires = ["si"] - self.cpp_info.components["si-uscs"].includedirs = ["include"] - self.cpp_info.components["isq-iec80000"].requires = ["si"] - self.cpp_info.components["isq-iec80000"].includedirs = ["include"] - self.cpp_info.components["systems"].requires = [ "isq", "isq-natural", diff --git a/test_package/conanfile.py b/test_package/conanfile.py index 4f4506f5..e71afd55 100644 --- a/test_package/conanfile.py +++ b/test_package/conanfile.py @@ -20,14 +20,17 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. +import os + from conan import ConanFile from conan.tools.build import cross_building -from conan.tools.cmake import CMake +from conan.tools.cmake import CMake, cmake_layout class TestPackageConan(ConanFile): settings = "os", "compiler", "build_type", "arch" - generators = "CMakeToolchain", "CMakeDeps" + generators = "CMakeDeps", "CMakeToolchain", "VirtualBuildEnv", "VirtualRunEnv" + apply_env = False test_type = "explicit" # TODO Remove for Conan 2.0 def requirements(self): @@ -38,6 +41,10 @@ class TestPackageConan(ConanFile): cmake.configure() cmake.build() + def layout(self): + cmake_layout(self) + def test(self): if not cross_building(self): - self.run("test_package", run_environment=True) + cmd = os.path.join(self.cpp.build.bindirs[0], "test_package") + self.run(cmd, env="conanrun") From 9c10b1cdbe87266adaac1e9b34f09f3ba9558a49 Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Mon, 1 Aug 2022 18:29:49 +0200 Subject: [PATCH 21/52] docs: "Usage" documentation updated with CMake presets usage --- docs/usage.rst | 136 +++++++++++++++++++++++++++++++++---------------- 1 file changed, 93 insertions(+), 43 deletions(-) diff --git a/docs/usage.rst b/docs/usage.rst index 0cc583ea..109f69a3 100644 --- a/docs/usage.rst +++ b/docs/usage.rst @@ -86,26 +86,42 @@ in *~/.conan/profiles* directory. An example profile can look as follows: arch=x86_64 arch_build=x86_64 compiler=gcc - compiler.version=10 + compiler.version=12 compiler.cppstd=20 compiler.libcxx=libstdc++11 build_type=Release - [options] - [build_requires] - - [conf] - tools.cmake.cmaketoolchain:generator=Ninja - [env] - CC=/usr/bin/gcc-10 - CXX=/usr/bin/g++-10 + CC=/usr/bin/gcc-12 + CXX=/usr/bin/g++-12 .. tip:: Please note that **mp-units** library requires C++20 to be set either in a Conan profile or forced via Conan command line. If you do the former, you will not need to provide ``-s compiler.cppstd=20`` - every time your run a Conan command line (as it is suggested below). + every time your run a Conan command line (as provided in the command line instructions below). + +Additionally, it is recommended to set Ninja as a CMake generator for Conan. To do so you should create +a *~/.conan/global.conf* file that will set ``tools.cmake.cmaketoolchain:generator`` to one of Ninja +generators. For example: + +.. code-block:: text + + tools.cmake.cmaketoolchain:generator="Ninja Multi-Config" + +.. note:: + + *~/.conan/global.conf* file may also set ``tools.cmake.cmake_layout:build_folder_vars``` which + `makes working with several compilers or build configurations easier + `_. + For example the below line will force Conan to generate separate CMake presets and folders for each compiler: + + .. code-block:: text + + tools.cmake.cmake_layout:build_folder_vars=["settings.compiler", "settings.compiler.version"] + + In such a case you will need to use a configuration specific preset name in the Conan instructions provided below + rather then just ``default`` and ``release`` (i.e. ``gcc-11`` and ``gcc-11-release``) Build Options @@ -207,6 +223,21 @@ UNITS_USE_LIBFMT Enables usage of `{fmt} `_ library instead of the C++20 Standard Library feature. +CMake with Presets Support +-------------------------- + +It is recommended to use at least CMake 3.23 to build this project as this version introduced a support +for CMake Presets schema version 4 used now by Conan to generate presets files. All build instructions +below assume that you have such a support. If not, your CMake invocations have to be replaced to something +like: + +.. code-block:: shell + + mkdir build && cd build + cmake .. -G "Ninja Multi-Config" -DCMAKE_TOOLCHAIN_FILE=/conan_toolchain.cmake + cmake --build . --config Release + + Installation and Reuse ---------------------- @@ -298,8 +329,8 @@ library release the following steps may be performed: mkdir my_project/build && cd my_project/build conan install .. -pr -s compiler.cppstd=20 -b=missing - cmake .. -DCMAKE_TOOLCHAIN_FILE=conan_toolchain.cmake -DCMAKE_BUILD_TYPE=Release - cmake --build . + cmake .. -G "Ninja Multi-Config" -DCMAKE_TOOLCHAIN_FILE=conan_toolchain.cmake + cmake --build . --config Release Conan + CMake (Live At Head) @@ -333,6 +364,9 @@ differences: [requires] mp-units/0.8.0@mpusz/testing + [layout] + cmake_layout + [generators] CMakeToolchain CMakeDeps @@ -347,10 +381,9 @@ differences: .. code-block:: shell - mkdir my_project/build && cd my_project/build - conan install .. -pr -s compiler.cppstd=20 -b=outdated -u - cmake .. -DCMAKE_TOOLCHAIN_FILE=conan_toolchain.cmake -DCMAKE_BUILD_TYPE=Release - cmake --build . + conan install . -pr -s compiler.cppstd=20 -b=outdated -u + cmake --preset default + cmake --build --preset release Install @@ -362,43 +395,60 @@ to find it, it is enough to perform the following steps: .. code-block:: shell - mkdir units/build && cd units/build - conan install .. -pr -s compiler.cppstd=20 -b=missing - cmake ../src -DCMAKE_TOOLCHAIN_FILE=conan_toolchain.cmake -DCMAKE_BUILD_TYPE=Release - cmake --install . --prefix + conan install . -pr -s compiler.cppstd=20 -b=missing + mv CMakeUserPresets.json src + cd src + cmake --preset default -DCMAKE_INSTALL_PREFIX= + cmake --build --preset release --target install -Contributing (or just building all the tests, examples, and documentation) --------------------------------------------------------------------------- +Contributing (or just building all the tests and examples) +---------------------------------------------------------- -In case you would like to build all the source code (with unit tests and examples) and documentation -in **mp-units** repository, you should: +In case you would like to build all the source code (with unit tests and examples) in **mp-units** repository, +you should: -1. Add remotes of additional Conan dependencies. -2. Use the *CMakeLists.txt* from the top-level directory. -3. Obtain Python dependencies. -4. Run Conan with `CONAN_RUN_TESTS`_ = ``True``. +1. Use the *CMakeLists.txt* from the top-level directory. +2. Run Conan with `CONAN_RUN_TESTS`_ = ``True`` + (use ``-o build_docs=False`` if you want to skip the documentation generation). + +.. code-block:: shell + + git clone https://github.com/mpusz/units.git && cd units + conan install . -pr -s compiler.cppstd=20 -e mp-units:CONAN_RUN_TESTS=True -o build_docs=False -b outdated -u + conan build . + +The above will download and install all of the dependencies needed for the development of the library, +build all of the source code and run unit tests. + +If you prefer to build the project via CMake rather then Conan, then you should replace the last ``conan build .`` +step with the explicit CMake build: + +.. code-block:: shell + + cmake --preset default + cmake --build --preset release + cmake --build --preset release --target test + + +Building documentation +---------------------- + +In case you would like to build the project's documentation, you should: + +1. Use the *CMakeLists.txt* from the top-level directory. +2. Obtain Python dependencies. +3. Run Conan with `CONAN_RUN_TESTS`_ = ``True``. .. code-block:: shell git clone https://github.com/mpusz/units.git && cd units pip3 install -r docs/requirements.txt - mkdir units/build && cd units/build - conan install .. -pr -s compiler.cppstd=20 -e mp-units:CONAN_RUN_TESTS=True -b outdated -u - conan build .. + conan install . -pr -s compiler.cppstd=20 -e mp-units:CONAN_RUN_TESTS=True -b missing + cmake --preset default + cmake --build --preset release --target documentation -The above will download and install all of the dependencies needed for the development of the library, -build all of the source code and documentation, and run unit tests. - -If you prefer to build the project via CMake rather then Conan, then you should replace the last ``conan build ..`` -step with the CMake build: - -.. code-block:: shell - - # ... - cmake .. -DCMAKE_TOOLCHAIN_FILE=conan_toolchain.cmake -DCMAKE_BUILD_TYPE=Release - cmake --build . - ctest +The above will download and install all of the dependencies needed and build the documentation. Packaging From 9b1c9f16f1a4ebcddea78838185c42ed4d9ba541 Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Mon, 1 Aug 2022 18:31:03 +0200 Subject: [PATCH 22/52] ci: Check CMake version --- .github/workflows/ci-test-package-cmake.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/ci-test-package-cmake.yml b/.github/workflows/ci-test-package-cmake.yml index 2c6440ac..d577183e 100644 --- a/.github/workflows/ci-test-package-cmake.yml +++ b/.github/workflows/ci-test-package-cmake.yml @@ -200,6 +200,7 @@ jobs: shell: cmd working-directory: build/${{ matrix.build_type }} run: | + cmake --version call conanvcvars.bat cmake ../../src -DCMAKE_TOOLCHAIN_FILE=conan_toolchain.cmake -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} - name: Configure mp-units CMake @@ -207,6 +208,7 @@ jobs: shell: bash working-directory: build/${{ matrix.build_type }} run: | + cmake --version cmake ../../src -DCMAKE_TOOLCHAIN_FILE=conan_toolchain.cmake -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} - name: Install mp-units shell: bash From 1c5061338fc023dc3e7e4d29c536756740f22fcf Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Tue, 2 Aug 2022 08:30:14 +0200 Subject: [PATCH 23/52] ci: GitHub actions updated with CMake presets usage --- .github/workflows/ci-test-package-cmake.yml | 84 +++++++++++---------- .github/workflows/documentation.yml | 7 +- 2 files changed, 49 insertions(+), 42 deletions(-) diff --git a/.github/workflows/ci-test-package-cmake.yml b/.github/workflows/ci-test-package-cmake.yml index d577183e..de568789 100644 --- a/.github/workflows/ci-test-package-cmake.yml +++ b/.github/workflows/ci-test-package-cmake.yml @@ -113,6 +113,10 @@ jobs: CMAKE_GENERATOR: Ninja steps: + - name: Downcase 'build_type' + run: | + build_type=${{ matrix.build_type }} + echo "build_type=${build_type,,}" >> ${GITHUB_ENV} - uses: actions/checkout@v2 - name: Cache Conan data uses: actions/cache@v2 @@ -177,12 +181,11 @@ jobs: run: | conan config init conan remote add upload https://mpusz.jfrog.io/artifactory/api/conan/conan-oss - conan profile update settings.build_type=${{ matrix.build_type }} default conan profile update settings.compiler.cppstd=20 default if [[ "${{ matrix.config.compiler.type }}" == "GCC" || "${{ matrix.config.compiler.type }}" == "CLANG" ]]; then conan profile update settings.compiler.libcxx=${{ matrix.config.lib }} default fi - conan profile update conf.tools.cmake.cmaketoolchain:generator=Ninja default + conan profile update conf.tools.cmake.cmaketoolchain:generator="Ninja Multi-Config" default conan profile show default # - name: Add support for clang-13 to Conan's settings.yml # # TODO Remove when Conan will support clang-13 @@ -193,65 +196,70 @@ jobs: - name: Install Conan dependencies shell: bash run: | - mkdir -p build/${{ matrix.build_type }} && cd build/${{ matrix.build_type }} - conan install ../.. -b outdated -u + conan install . -s build_type=${{ matrix.build_type }} -b outdated -u + mv CMakeUserPresets.json src - name: Configure mp-units CMake if: matrix.config.compiler.type == 'VISUAL' shell: cmd - working-directory: build/${{ matrix.build_type }} + working-directory: src run: | cmake --version - call conanvcvars.bat - cmake ../../src -DCMAKE_TOOLCHAIN_FILE=conan_toolchain.cmake -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} + ..\build\generators\conanbuild.bat + cmake --preset default -DCMAKE_INSTALL_PREFIX=../out - name: Configure mp-units CMake if: matrix.config.compiler.type != 'VISUAL' shell: bash - working-directory: build/${{ matrix.build_type }} + working-directory: src run: | cmake --version - cmake ../../src -DCMAKE_TOOLCHAIN_FILE=conan_toolchain.cmake -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} + cmake --preset default -DCMAKE_INSTALL_PREFIX=../out - name: Install mp-units shell: bash - working-directory: build/${{ matrix.build_type }} + working-directory: src run: | - cmake --install . --prefix test_package - - name: Install dependencies for test_package + cmake --build --preset ${build_type} --target install + - name: Provide dependencies for test_package shell: bash + working-directory: test_package run: | - mkdir -p test_package/build/${{ matrix.build_type }} && cd test_package/build/${{ matrix.build_type }} - conan install ../../.. + cp ../src/CMakeUserPresets.json . - name: Build test_package CMake (local build) if: matrix.config.compiler.type == 'VISUAL' shell: cmd - working-directory: test_package/build/${{ matrix.build_type }} + working-directory: test_package run: | - call conanvcvars.bat - cmake ../.. -DCMAKE_TOOLCHAIN_FILE=conan_toolchain.cmake -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} -Dmp-units_DIR=${{ github.workspace }}/build/${{ matrix.build_type }} - cmake --build . + ..\build\generators\conanbuild.bat + cmake --preset default -Dmp-units_DIR=../build -Bbuild/local + cmake --build build/local --config ${{ matrix.build_type }} - name: Build test_package CMake (local build) if: matrix.config.compiler.type != 'VISUAL' shell: bash - working-directory: test_package/build/${{ matrix.build_type }} + working-directory: test_package run: | - cmake ../.. -DCMAKE_TOOLCHAIN_FILE=conan_toolchain.cmake -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} -Dmp-units_DIR=${{ github.workspace }}/build/${{ matrix.build_type }} - cmake --build . - - name: Build test_package CMake (installation) - if: matrix.config.compiler.type == 'VISUAL' - shell: cmd - working-directory: test_package/build/${{ matrix.build_type }} - run: | - call conanvcvars.bat - cmake ../.. -DCMAKE_TOOLCHAIN_FILE=conan_toolchain.cmake -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} -DCMAKE_INSTALL_PREFIX=../../../build/${{ matrix.build_type }}/test_package - cmake --build . - - name: Build test_package CMake (installation) - if: matrix.config.compiler.type != 'VISUAL' + cmake --preset default -Dmp-units_DIR=../build -Bbuild/local + cmake --build build/local --config ${{ matrix.build_type }} + - name: Run test_package (local build) shell: bash - working-directory: test_package/build/${{ matrix.build_type }} - run: | - cmake ../.. -DCMAKE_TOOLCHAIN_FILE=conan_toolchain.cmake -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} -DCMAKE_INSTALL_PREFIX=../../../build/${{ matrix.build_type }}/test_package - cmake --build . - - name: Run test_package - shell: bash - working-directory: test_package/build/${{ matrix.build_type }} + working-directory: test_package/build/local/${{ matrix.build_type }} + run: | + ./test_package + - name: Build test_package CMake (installation) + if: matrix.config.compiler.type == 'VISUAL' + shell: cmd + working-directory: test_package/build/${{ matrix.build_type }} + run: | + ..\build\generators\conanbuild.bat + cmake --preset default -DCMAKE_INSTALL_PREFIX=../out -Bbuild/install + cmake --build build/install --config ${{ matrix.build_type }} + - name: Build test_package CMake (installation) + if: matrix.config.compiler.type != 'VISUAL' + shell: bash + working-directory: test_package/build/${{ matrix.build_type }} + run: | + cmake --preset default -DCMAKE_INSTALL_PREFIX=../out -Bbuild/install + cmake --build build/install --config ${{ matrix.build_type }} + - name: Run test_package (installation) + shell: bash + working-directory: test_package/build/install/${{ matrix.build_type }} run: | ./test_package diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml index 9ab7c1ed..cabc30cb 100644 --- a/.github/workflows/documentation.yml +++ b/.github/workflows/documentation.yml @@ -78,16 +78,15 @@ jobs: conan remote add -i 0 upload https://mpusz.jfrog.io/artifactory/api/conan/conan-oss - name: Install Conan dependencies run: | - mkdir build && cd build - conan install .. -s compiler.cppstd=20 -s compiler.libcxx=libstdc++11 -e mp-units:CONAN_RUN_TESTS=True -b outdated -u + conan install . -s compiler.cppstd=20 -s compiler.libcxx=libstdc++11 -c tools.cmake.cmaketoolchain:generator="Ninja Multi-Config" -e mp-units:CONAN_RUN_TESTS=True -b outdated -u - name: Configure CMake working-directory: build run: | - cmake .. -DCMAKE_TOOLCHAIN_FILE=conan_toolchain.cmake -DCMAKE_BUILD_TYPE=Release + cmake --preset default - name: Generate documentation working-directory: build run: | - cmake --build . --target documentation --config Release + cmake --build --preset Release --target documentation - name: Deploy documentation if: github.ref == 'refs/heads/master' uses: peaceiris/actions-gh-pages@v3 From 82f018f216f74849ad3c94e42ba50967c71a384f Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Tue, 2 Aug 2022 08:39:59 +0200 Subject: [PATCH 24/52] ci: `working-directory` fixed --- .github/workflows/ci-test-package-cmake.yml | 4 ++-- .github/workflows/documentation.yml | 2 -- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci-test-package-cmake.yml b/.github/workflows/ci-test-package-cmake.yml index de568789..d14e6d3a 100644 --- a/.github/workflows/ci-test-package-cmake.yml +++ b/.github/workflows/ci-test-package-cmake.yml @@ -246,7 +246,7 @@ jobs: - name: Build test_package CMake (installation) if: matrix.config.compiler.type == 'VISUAL' shell: cmd - working-directory: test_package/build/${{ matrix.build_type }} + working-directory: test_package run: | ..\build\generators\conanbuild.bat cmake --preset default -DCMAKE_INSTALL_PREFIX=../out -Bbuild/install @@ -254,7 +254,7 @@ jobs: - name: Build test_package CMake (installation) if: matrix.config.compiler.type != 'VISUAL' shell: bash - working-directory: test_package/build/${{ matrix.build_type }} + working-directory: test_package run: | cmake --preset default -DCMAKE_INSTALL_PREFIX=../out -Bbuild/install cmake --build build/install --config ${{ matrix.build_type }} diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml index cabc30cb..68a3f979 100644 --- a/.github/workflows/documentation.yml +++ b/.github/workflows/documentation.yml @@ -80,11 +80,9 @@ jobs: run: | conan install . -s compiler.cppstd=20 -s compiler.libcxx=libstdc++11 -c tools.cmake.cmaketoolchain:generator="Ninja Multi-Config" -e mp-units:CONAN_RUN_TESTS=True -b outdated -u - name: Configure CMake - working-directory: build run: | cmake --preset default - name: Generate documentation - working-directory: build run: | cmake --build --preset Release --target documentation - name: Deploy documentation From f24f87302f0e4939c8cd88118faf28189f52c8c4 Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Tue, 2 Aug 2022 08:51:52 +0200 Subject: [PATCH 25/52] ci: CMake preset name fixed in documentation script --- .github/workflows/documentation.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml index 68a3f979..f72ecf86 100644 --- a/.github/workflows/documentation.yml +++ b/.github/workflows/documentation.yml @@ -84,7 +84,7 @@ jobs: cmake --preset default - name: Generate documentation run: | - cmake --build --preset Release --target documentation + cmake --build --preset release --target documentation - name: Deploy documentation if: github.ref == 'refs/heads/master' uses: peaceiris/actions-gh-pages@v3 From a134d74ca28a7500e20fe8cbfe074fce69e3e448 Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Tue, 2 Aug 2022 08:56:16 +0200 Subject: [PATCH 26/52] ci: Downcase 'build_type' now uses a GitHub action --- .github/workflows/ci-test-package-cmake.yml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci-test-package-cmake.yml b/.github/workflows/ci-test-package-cmake.yml index d14e6d3a..2a814997 100644 --- a/.github/workflows/ci-test-package-cmake.yml +++ b/.github/workflows/ci-test-package-cmake.yml @@ -114,9 +114,10 @@ jobs: steps: - name: Downcase 'build_type' - run: | - build_type=${{ matrix.build_type }} - echo "build_type=${build_type,,}" >> ${GITHUB_ENV} + id: build_type + uses: ASzc/change-string-case-action@v2 + with: + string: ${{ matrix.build_type }} - uses: actions/checkout@v2 - name: Cache Conan data uses: actions/cache@v2 @@ -217,7 +218,7 @@ jobs: shell: bash working-directory: src run: | - cmake --build --preset ${build_type} --target install + cmake --build --preset ${{ steps.build_type.outputs.lowercase }} --target install - name: Provide dependencies for test_package shell: bash working-directory: test_package From db6c46ad3ae2952e605a91fc163aefa20e46ba8d Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Tue, 2 Aug 2022 09:07:59 +0200 Subject: [PATCH 27/52] ci: conanvcvars.bat call fixed --- .github/workflows/ci-test-package-cmake.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci-test-package-cmake.yml b/.github/workflows/ci-test-package-cmake.yml index 2a814997..5da0d975 100644 --- a/.github/workflows/ci-test-package-cmake.yml +++ b/.github/workflows/ci-test-package-cmake.yml @@ -205,7 +205,7 @@ jobs: working-directory: src run: | cmake --version - ..\build\generators\conanbuild.bat + call ..\build\generators\conanvcvars.bat cmake --preset default -DCMAKE_INSTALL_PREFIX=../out - name: Configure mp-units CMake if: matrix.config.compiler.type != 'VISUAL' @@ -229,7 +229,7 @@ jobs: shell: cmd working-directory: test_package run: | - ..\build\generators\conanbuild.bat + call ..\build\generators\conanvcvars.bat cmake --preset default -Dmp-units_DIR=../build -Bbuild/local cmake --build build/local --config ${{ matrix.build_type }} - name: Build test_package CMake (local build) @@ -249,7 +249,7 @@ jobs: shell: cmd working-directory: test_package run: | - ..\build\generators\conanbuild.bat + call ..\build\generators\conanvcvars.bat cmake --preset default -DCMAKE_INSTALL_PREFIX=../out -Bbuild/install cmake --build build/install --config ${{ matrix.build_type }} - name: Build test_package CMake (installation) From 82e808855f6dba66e1966d23482d05704b011b85 Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Tue, 2 Aug 2022 09:42:31 +0200 Subject: [PATCH 28/52] ci: `ci-test-package-cmake.yml` updated to the `ci-conan.yml` state --- .github/workflows/ci-test-package-cmake.yml | 94 +++++++++++++++------ 1 file changed, 70 insertions(+), 24 deletions(-) diff --git a/.github/workflows/ci-test-package-cmake.yml b/.github/workflows/ci-test-package-cmake.yml index 5da0d975..8dbb8423 100644 --- a/.github/workflows/ci-test-package-cmake.yml +++ b/.github/workflows/ci-test-package-cmake.yml @@ -43,48 +43,93 @@ jobs: matrix: config: - { - name: "Windows MSVC 2019", - os: windows-latest, - compiler: { type: VISUAL, version: 16, cc: "", cxx: "" }, + name: "Windows MSVC 14.2", + os: windows-2019, + compiler: + { type: VISUAL, version: 16, std: 20, cc: "cl", cxx: "cl" }, } - { - name: "Ubuntu GCC 10.3.0", - os: ubuntu-20.04, - compiler: { type: GCC, version: 10, cc: "gcc-10", cxx: "g++-10" }, - lib: "libstdc++11", + name: "Windows MSVC 14.3", + os: windows-2022, + compiler: + { type: MSVC, version: 193, std: 23, cc: "cl", cxx: "cl" }, } - { - name: "Ubuntu GCC 11.1.0", - os: ubuntu-20.04, - compiler: { type: GCC, version: 11, cc: "gcc-11", cxx: "g++-11" }, - lib: "libstdc++11", - } - - { - name: "Ubuntu Clang 12.0.0 + libstdc++11", + name: "Ubuntu GCC-10", os: ubuntu-20.04, compiler: - { type: CLANG, version: 12, cc: "clang-12", cxx: "clang++-12" }, + { + type: GCC, + version: 10, + cc: "gcc-10", + cxx: "g++-10", + std: 20, + }, lib: "libstdc++11", } - { - name: "Ubuntu Clang 12.0.0 + libc++", + name: "Ubuntu GCC-11", os: ubuntu-20.04, compiler: - { type: CLANG, version: 12, cc: "clang-12", cxx: "clang++-12" }, + { + type: GCC, + version: 11, + cc: "gcc-11", + cxx: "g++-11", + std: 20, + }, + lib: "libstdc++11", + } + - { + name: "Ubuntu Clang-12 + libstdc++11", + os: ubuntu-20.04, + compiler: + { + type: CLANG, + version: 12, + cc: "clang-12", + cxx: "clang++-12", + std: 20, + }, + lib: "libstdc++11", + } + - { + name: "Ubuntu Clang-12 + libc++", + os: ubuntu-20.04, + compiler: + { + type: CLANG, + version: 12, + cc: "clang-12", + cxx: "clang++-12", + std: 20, + }, lib: "libc++", } - { - name: "Ubuntu Clang 13.0.0 + libc++", + name: "Ubuntu Clang-13 + libc++", os: ubuntu-20.04, compiler: - { type: CLANG, version: 13, cc: "clang-13", cxx: "clang++-13" }, + { + type: CLANG, + version: 13, + cc: "clang-13", + cxx: "clang++-13", + std: 20, + }, lib: "libc++", } - { - name: "Ubuntu Clang 14.0.0 + libc++", + name: "Ubuntu Clang-14 + libc++", os: ubuntu-20.04, compiler: - { type: CLANG, version: 14, cc: "clang-14", cxx: "clang++-14" }, + { + type: CLANG, + version: 14, + cc: "clang-14", + cxx: "clang++-14", + std: 20, + }, lib: "libc++", } - { @@ -96,6 +141,7 @@ jobs: version: "13.0", cc: "clang", cxx: "clang++", + std: 20, }, } # In case a Conan docker image will be needed to provide a specific configuration we can use a Docker image as follows @@ -110,7 +156,6 @@ jobs: env: CC: ${{ matrix.config.compiler.cc }} CXX: ${{ matrix.config.compiler.cxx }} - CMAKE_GENERATOR: Ninja steps: - name: Downcase 'build_type' @@ -182,10 +227,11 @@ jobs: run: | conan config init conan remote add upload https://mpusz.jfrog.io/artifactory/api/conan/conan-oss - conan profile update settings.compiler.cppstd=20 default if [[ "${{ matrix.config.compiler.type }}" == "GCC" || "${{ matrix.config.compiler.type }}" == "CLANG" ]]; then conan profile update settings.compiler.libcxx=${{ matrix.config.lib }} default fi + conan profile update settings.compiler.cppstd=${{ matrix.config.compiler.std }} default + conan profile update settings.build_type=${{ matrix.build_type }} default conan profile update conf.tools.cmake.cmaketoolchain:generator="Ninja Multi-Config" default conan profile show default # - name: Add support for clang-13 to Conan's settings.yml @@ -197,7 +243,7 @@ jobs: - name: Install Conan dependencies shell: bash run: | - conan install . -s build_type=${{ matrix.build_type }} -b outdated -u + conan install . -b outdated -u mv CMakeUserPresets.json src - name: Configure mp-units CMake if: matrix.config.compiler.type == 'VISUAL' From 938a25c9a3a4a98442ffee71096929b176a3dbe6 Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Tue, 2 Aug 2022 10:44:25 +0200 Subject: [PATCH 29/52] ci: MSVC compiler paths removed --- .github/workflows/ci-test-package-cmake.yml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci-test-package-cmake.yml b/.github/workflows/ci-test-package-cmake.yml index 8dbb8423..0d80ee15 100644 --- a/.github/workflows/ci-test-package-cmake.yml +++ b/.github/workflows/ci-test-package-cmake.yml @@ -45,14 +45,12 @@ jobs: - { name: "Windows MSVC 14.2", os: windows-2019, - compiler: - { type: VISUAL, version: 16, std: 20, cc: "cl", cxx: "cl" }, + compiler: { type: VISUAL, version: 16, cc: "", cxx: "", std: 20 }, } - { name: "Windows MSVC 14.3", os: windows-2022, - compiler: - { type: MSVC, version: 193, std: 23, cc: "cl", cxx: "cl" }, + compiler: { type: MSVC, version: 193, cc: "", cxx: "", std: 23 }, } - { name: "Ubuntu GCC-10", From 6557647ce94f043e91930099b0dd2ab0381f04c2 Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Tue, 2 Aug 2022 12:57:09 +0200 Subject: [PATCH 30/52] ci: MSVC condition added to VS-specific branches --- .github/workflows/ci-test-package-cmake.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci-test-package-cmake.yml b/.github/workflows/ci-test-package-cmake.yml index 0d80ee15..edfc3854 100644 --- a/.github/workflows/ci-test-package-cmake.yml +++ b/.github/workflows/ci-test-package-cmake.yml @@ -244,7 +244,7 @@ jobs: conan install . -b outdated -u mv CMakeUserPresets.json src - name: Configure mp-units CMake - if: matrix.config.compiler.type == 'VISUAL' + if: matrix.config.compiler.type == 'VISUAL' || matrix.config.compiler.type == 'MSVC' shell: cmd working-directory: src run: | @@ -252,7 +252,7 @@ jobs: call ..\build\generators\conanvcvars.bat cmake --preset default -DCMAKE_INSTALL_PREFIX=../out - name: Configure mp-units CMake - if: matrix.config.compiler.type != 'VISUAL' + if: matrix.config.compiler.type != 'VISUAL' && matrix.config.compiler.type != 'MSVC' shell: bash working-directory: src run: | @@ -269,7 +269,7 @@ jobs: run: | cp ../src/CMakeUserPresets.json . - name: Build test_package CMake (local build) - if: matrix.config.compiler.type == 'VISUAL' + if: matrix.config.compiler.type == 'VISUAL' || matrix.config.compiler.type == 'MSVC' shell: cmd working-directory: test_package run: | @@ -277,7 +277,7 @@ jobs: cmake --preset default -Dmp-units_DIR=../build -Bbuild/local cmake --build build/local --config ${{ matrix.build_type }} - name: Build test_package CMake (local build) - if: matrix.config.compiler.type != 'VISUAL' + if: matrix.config.compiler.type != 'VISUAL' && matrix.config.compiler.type != 'MSVC' shell: bash working-directory: test_package run: | @@ -289,7 +289,7 @@ jobs: run: | ./test_package - name: Build test_package CMake (installation) - if: matrix.config.compiler.type == 'VISUAL' + if: matrix.config.compiler.type == 'VISUAL' || matrix.config.compiler.type == 'MSVC' shell: cmd working-directory: test_package run: | @@ -297,7 +297,7 @@ jobs: cmake --preset default -DCMAKE_INSTALL_PREFIX=../out -Bbuild/install cmake --build build/install --config ${{ matrix.build_type }} - name: Build test_package CMake (installation) - if: matrix.config.compiler.type != 'VISUAL' + if: matrix.config.compiler.type != 'VISUAL' && matrix.config.compiler.type != 'MSVC' shell: bash working-directory: test_package run: | From 9944de10f9f9bf0ef5d954b8d5beb2a672eb6434 Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Tue, 2 Aug 2022 15:10:21 +0200 Subject: [PATCH 31/52] ci: `fmt` dependency checked only when `UNITS_USE_LIBFMT` is set --- src/mp-unitsConfig.cmake | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/mp-unitsConfig.cmake b/src/mp-unitsConfig.cmake index 8b63a787..668fd97d 100644 --- a/src/mp-unitsConfig.cmake +++ b/src/mp-unitsConfig.cmake @@ -30,6 +30,7 @@ function(__check_libcxx_in_use variable) set(${variable} ${${variable}} PARENT_SCOPE) list(POP_BACK CMAKE_MESSAGE_INDENT) + if(${variable}) message(CHECK_PASS "found") else() @@ -39,15 +40,21 @@ function(__check_libcxx_in_use variable) endfunction() include(CMakeFindDependencyMacro) -find_dependency(fmt) + +if(UNITS_USE_LIBFMT) + find_dependency(fmt) +endif() + find_dependency(gsl-lite) # add range-v3 dependency only for clang + libc++ if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") __check_libcxx_in_use(__units_libcxx) + if(__units_libcxx AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS "14") find_dependency(range-v3) endif() + unset(__units_libcxx) endif() From 6147348b88a70e4ed751445dc2b42522fed7ede6 Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Tue, 2 Aug 2022 15:41:20 +0200 Subject: [PATCH 32/52] ci: ci-conan no longer uses conan-package-tools --- .github/workflows/ci-conan.yml | 72 +++++++++++++++++++--------------- 1 file changed, 40 insertions(+), 32 deletions(-) diff --git a/.github/workflows/ci-conan.yml b/.github/workflows/ci-conan.yml index 0c1ad283..33f1a1d7 100644 --- a/.github/workflows/ci-conan.yml +++ b/.github/workflows/ci-conan.yml @@ -41,14 +41,12 @@ jobs: - { name: "Windows MSVC 14.2", os: windows-2019, - compiler: - { type: VISUAL, version: 16, std: 20, cc: "cl", cxx: "cl" }, + compiler: { type: VISUAL, version: 16, cc: "", cxx: "", std: 20 }, } - { name: "Windows MSVC 14.3", os: windows-2022, - compiler: - { type: MSVC, version: 193, std: 23, cc: "cl", cxx: "cl" }, + compiler: { type: MSVC, version: 193, cc: "", cxx: "", std: 23 }, } - { name: "Ubuntu GCC-10", @@ -140,17 +138,26 @@ jobs: std: 20, }, } - # In case a Conan docker image will be needed to provide a specific configuration we can use a Docker image as follows - # - { - # name: "Ubuntu GCC 10.2.0", - # os: ubuntu-20.04, - # compiler: { type: GCC, version: 10, cc: "gcc-10", cxx: "g++-10" }, - # docker_image: conanio/gcc10 - # } build_type: ["Release", "Debug"] downcast_mode: ["on", "auto"] + + env: + CC: ${{ matrix.config.compiler.cc }} + CXX: ${{ matrix.config.compiler.cxx }} + steps: - uses: actions/checkout@v2 + - name: Cache Conan data + uses: actions/cache@v2 + env: + cache-name: cache-conan-data + with: + path: ~/.conan/data + key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/metadata.json') }} + restore-keys: | + ${{ runner.os }}-build-${{ env.cache-name }}- + ${{ runner.os }}-build- + ${{ runner.os }}- - uses: hendrikmuhs/ccache-action@v1 if: runner.os == 'Linux' with: @@ -199,20 +206,21 @@ jobs: uses: actions/setup-python@v2 with: python-version: "3.8" - - name: Install Conan Package Tools + - name: Install Conan + shell: bash run: | - pip install -U conan_package_tools + pip install -U conan - name: Configure Conan - # TODO Find a proper syntax to make the below work - # if: !matrix.config.docker_image shell: bash run: | conan config init + conan remote add upload https://mpusz.jfrog.io/artifactory/api/conan/conan-oss if [[ "${{ matrix.config.compiler.type }}" == "GCC" || "${{ matrix.config.compiler.type }}" == "CLANG" ]]; then conan profile update settings.compiler.libcxx=${{ matrix.config.lib }} default fi conan profile update settings.compiler.cppstd=${{ matrix.config.compiler.std }} default - conan profile update conf.tools.cmake.cmaketoolchain:generator=Ninja default + conan profile update settings.build_type=${{ matrix.build_type }} default + conan profile update conf.tools.cmake.cmaketoolchain:generator="Ninja Multi-Config" default conan profile show default # - name: Add support for clang-13 to Conan's settings.yml # # TODO Remove when Conan will support clang-13 @@ -220,21 +228,21 @@ jobs: # shell: bash # run: | # sed -i -e 's/"8", "9", "10", "11", "12"]/"8", "9", "10", "11", "12", "13"]/' ~/.conan/settings.yml - - name: Run Conan Package Tools + - name: Set channel shell: bash - env: - CONAN_USERNAME: mpusz - CONAN_OPTIONS: mp-units:build_docs=False,mp-units:downcast_mode=${{ matrix.downcast_mode }} - CONAN_UPLOAD: https://mpusz.jfrog.io/artifactory/api/conan/conan-oss - CONAN_LOGIN_USERNAME: ${{ secrets.CONAN_LOGIN_USERNAME }} - CONAN_PASSWORD: ${{ secrets.CONAN_PASSWORD }} - CONAN_CMAKE_GENERATOR: Ninja - CONAN_BUILD_TYPES: ${{ matrix.build_type }} - CC: ${{ matrix.config.compiler.cc }} - CXX: ${{ matrix.config.compiler.cxx }} - CONAN_${{ matrix.config.compiler.type }}_VERSIONS: ${{ matrix.config.compiler.version }} run: | - if [ ! -z "${{ matrix.config.docker_image }}" ]; then - export CONAN_DOCKER_IMAGE=${{ matrix.config.docker_image }} - fi - python build.py + [[ `git tag --contains ${{ github.sha }}` =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]] && CHANNEL=stable || CHANNEL=testing + echo "CHANNEL=${CHANNEL}" >> ${GITHUB_ENV} + - name: Create Conan package + shell: bash + run: | + conan create . mpusz/testing -e mp-units:CONAN_RUN_TESTS=True -o mp-units:build_docs=False -o mp-units:downcast_mode=${{ matrix.downcast_mode }} -b mp-units outdated -u + - name: Upload mp-units Conan package + shell: bash + run: | + conan user ${{ secrets.CONAN_LOGIN_USERNAME }} -r https://mpusz.jfrog.io/artifactory/api/conan/conan-oss -p ${{ secrets.CONAN_PASSWORD }} + conan upload "mp-units*" --all -r https://mpusz.jfrog.io/artifactory/api/conan/conan-oss --confirm + - name: Remove mp-units package from Conan local cache + shell: bash + run: | + conan remove mp-units -f From 5fc4820102aa3d658c84a160bdd0d83eb9ddb247 Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Tue, 2 Aug 2022 15:44:40 +0200 Subject: [PATCH 33/52] ci: `-b outdated` fixed --- .github/workflows/ci-conan.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci-conan.yml b/.github/workflows/ci-conan.yml index 33f1a1d7..361030f8 100644 --- a/.github/workflows/ci-conan.yml +++ b/.github/workflows/ci-conan.yml @@ -236,7 +236,7 @@ jobs: - name: Create Conan package shell: bash run: | - conan create . mpusz/testing -e mp-units:CONAN_RUN_TESTS=True -o mp-units:build_docs=False -o mp-units:downcast_mode=${{ matrix.downcast_mode }} -b mp-units outdated -u + conan create . mpusz/testing -e mp-units:CONAN_RUN_TESTS=True -o mp-units:build_docs=False -o mp-units:downcast_mode=${{ matrix.downcast_mode }} -b mp-units -b outdated -u - name: Upload mp-units Conan package shell: bash run: | From 6f791c7cc4c9f31cdc9718074a4a9f94904450cc Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Tue, 2 Aug 2022 15:59:29 +0200 Subject: [PATCH 34/52] ci: Conan remote usage fixed --- .github/workflows/ci-conan.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci-conan.yml b/.github/workflows/ci-conan.yml index 361030f8..8af77be7 100644 --- a/.github/workflows/ci-conan.yml +++ b/.github/workflows/ci-conan.yml @@ -214,7 +214,7 @@ jobs: shell: bash run: | conan config init - conan remote add upload https://mpusz.jfrog.io/artifactory/api/conan/conan-oss + conan remote add artifactory https://mpusz.jfrog.io/artifactory/api/conan/conan-oss if [[ "${{ matrix.config.compiler.type }}" == "GCC" || "${{ matrix.config.compiler.type }}" == "CLANG" ]]; then conan profile update settings.compiler.libcxx=${{ matrix.config.lib }} default fi @@ -240,8 +240,8 @@ jobs: - name: Upload mp-units Conan package shell: bash run: | - conan user ${{ secrets.CONAN_LOGIN_USERNAME }} -r https://mpusz.jfrog.io/artifactory/api/conan/conan-oss -p ${{ secrets.CONAN_PASSWORD }} - conan upload "mp-units*" --all -r https://mpusz.jfrog.io/artifactory/api/conan/conan-oss --confirm + conan user ${{ secrets.CONAN_LOGIN_USERNAME }} -r artifactory -p ${{ secrets.CONAN_PASSWORD }} + conan upload "mp-units*" --all -r artifactory --confirm - name: Remove mp-units package from Conan local cache shell: bash run: | From c00d8990f41ffcd1f90bdbcc65217e1ad8851e56 Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Tue, 2 Aug 2022 16:15:59 +0200 Subject: [PATCH 35/52] ci: Conan package will be uploaded only either for a 'stable' channel or for a commit on a master branch --- .github/workflows/ci-conan.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci-conan.yml b/.github/workflows/ci-conan.yml index 8af77be7..0b11c977 100644 --- a/.github/workflows/ci-conan.yml +++ b/.github/workflows/ci-conan.yml @@ -238,6 +238,7 @@ jobs: run: | conan create . mpusz/testing -e mp-units:CONAN_RUN_TESTS=True -o mp-units:build_docs=False -o mp-units:downcast_mode=${{ matrix.downcast_mode }} -b mp-units -b outdated -u - name: Upload mp-units Conan package + if: github.ref == 'refs/heads/master' || env.CHANNEL == 'stable' shell: bash run: | conan user ${{ secrets.CONAN_LOGIN_USERNAME }} -r artifactory -p ${{ secrets.CONAN_PASSWORD }} From 8c01f8dd65b024fee095c79d11350d397f5947b3 Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Tue, 2 Aug 2022 16:16:40 +0200 Subject: [PATCH 36/52] ci: `ci-test-package-cmake.yml` cleanup --- .github/workflows/ci-test-package-cmake.yml | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/.github/workflows/ci-test-package-cmake.yml b/.github/workflows/ci-test-package-cmake.yml index edfc3854..4dc9d15a 100644 --- a/.github/workflows/ci-test-package-cmake.yml +++ b/.github/workflows/ci-test-package-cmake.yml @@ -142,13 +142,6 @@ jobs: std: 20, }, } - # In case a Conan docker image will be needed to provide a specific configuration we can use a Docker image as follows - # - { - # name: "Ubuntu GCC 10.2.0", - # os: ubuntu-20.04, - # compiler: { type: GCC, version: 10, cc: "gcc-10", cxx: "g++-10" }, - # docker_image: conanio/gcc10 - # } build_type: ["Release", "Debug"] env: @@ -224,7 +217,7 @@ jobs: shell: bash run: | conan config init - conan remote add upload https://mpusz.jfrog.io/artifactory/api/conan/conan-oss + conan remote add artifactory https://mpusz.jfrog.io/artifactory/api/conan/conan-oss if [[ "${{ matrix.config.compiler.type }}" == "GCC" || "${{ matrix.config.compiler.type }}" == "CLANG" ]]; then conan profile update settings.compiler.libcxx=${{ matrix.config.lib }} default fi From d500f3009b0cff333cf56c25bf71f4cb21af5c15 Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Tue, 2 Aug 2022 16:47:17 +0200 Subject: [PATCH 37/52] ci: `build.py` removed as it is no longer needed --- build.py | 46 ---------------------------------------------- 1 file changed, 46 deletions(-) delete mode 100644 build.py diff --git a/build.py b/build.py deleted file mode 100644 index e3bc1a56..00000000 --- a/build.py +++ /dev/null @@ -1,46 +0,0 @@ -# The MIT License (MIT) -# -# Copyright (c) 2018 Mateusz Pusz -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. - -# The following environment variables are required -# - CONAN_USERNAME -# - CONAN_UPLOAD -# - CONAN_LOGIN_USERNAME -# - CONAN_PASSWORD - -from cpt.packager import ConanMultiPackager - -if __name__ == "__main__": - builder = ConanMultiPackager( - # package id - channel="testing", - stable_branch_pattern=r"v\d+\.\d+\.\d+.*", - # dependencies - build_policy=["mp-units", "outdated"], - upload_dependencies="all", - pip_install=["sphinx", "recommonmark", "breathe"], - # build configurations - archs=["x86_64"], # limit to 64-bit only - ) - builder.add_common_builds(pure_c=True) - for settings, options, env_vars, build_requires, reference in builder.items: - env_vars["mp-units:CONAN_RUN_TESTS"] = "True" - builder.run() From aab2a20505b2d8e9081bc7b1f1b539b74725df0c Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Tue, 2 Aug 2022 17:09:05 +0200 Subject: [PATCH 38/52] build(conan): Environment variables replaced with Conan configuration properties --- conanfile.py | 32 +++++++++++++------------------- 1 file changed, 13 insertions(+), 19 deletions(-) diff --git a/conanfile.py b/conanfile.py index 5be2c2e3..208b50ba 100644 --- a/conanfile.py +++ b/conanfile.py @@ -30,9 +30,6 @@ from conan.tools.files import copy, load, rmdir from conan.tools.scm import Version from conans.errors import ConanInvalidConfiguration -# TODO remove when `CONAN_RUN_TESTS` will be replaced with a `[conf]` variable -from conans.tools import get_env - required_conan_version = ">=1.50.0" @@ -57,8 +54,8 @@ class MPUnitsConan(ConanFile): url = "https://github.com/mpusz/units" settings = "os", "compiler", "build_type", "arch" requires = "gsl-lite/0.40.0" - options = {"downcast_mode": ["off", "on", "auto"], "build_docs": [True, False]} - default_options = {"downcast_mode": "on", "build_docs": True} + options = {"downcast_mode": ["off", "on", "auto"]} + default_options = {"downcast_mode": "on"} exports = ["LICENSE.md"] exports_sources = [ "docs/*", @@ -72,8 +69,12 @@ class MPUnitsConan(ConanFile): generators = "cmake_paths" @property - def _run_tests(self): - return get_env("CONAN_RUN_TESTS", False) + def _build_all(self): + return bool(self.conf["user.build:all"]) + + @property + def _skip_docs(self): + return bool(self.conf["user.build:skip_docs"]) @property def _use_libfmt(self): @@ -113,10 +114,10 @@ class MPUnitsConan(ConanFile): self.requires("range-v3/0.11.0") def build_requirements(self): - if self._run_tests: + if self._build_all: self.test_requires("catch2/2.13.9") self.test_requires("wg21-linear_algebra/0.7.2") - if self.options.build_docs: + if not self._skip_docs: self.tool_requires("doxygen/1.9.4") # TODO Replace with `valdate()` for Conan 2.0 (https://github.com/conan-io/conan/issues/10723) @@ -146,20 +147,13 @@ class MPUnitsConan(ConanFile): raise ConanInvalidConfiguration("Unsupported compiler") check_min_cppstd(self, 20) - # TODO Uncomment this when environment is supported in the Conan toolchain - # def config_options(self): - # if not self._run_tests: - # # build_docs has sense only in a development or CI build - # del self.options.build_docs - def layout(self): cmake_layout(self) def generate(self): tc = CMakeToolchain(self) tc.variables["UNITS_DOWNCAST_MODE"] = str(self.options.downcast_mode).upper() - # if self._run_tests: # TODO Enable this when environment is supported in the Conan toolchain - tc.variables["UNITS_BUILD_DOCS"] = bool(self.options.build_docs) + tc.variables["UNITS_BUILD_DOCS"] = self._build_all and not self._skip_docs tc.variables["UNITS_USE_LIBFMT"] = self._use_libfmt tc.generate() deps = CMakeDeps(self) @@ -167,9 +161,9 @@ class MPUnitsConan(ConanFile): def build(self): cmake = CMake(self) - cmake.configure(build_script_folder=None if self._run_tests else "src") + cmake.configure(build_script_folder=None if self._build_all else "src") cmake.build() - if self._run_tests: + if self._build_all: cmake.test() def package_id(self): From 8a35dcc73fcd5483e6be6be7575096a28576ebf9 Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Tue, 2 Aug 2022 17:17:51 +0200 Subject: [PATCH 39/52] ci: CI scripts updated to use Conan configuration properties --- .github/workflows/ci-conan.yml | 2 +- .github/workflows/codeql-analysis.yml | 102 +++++++++++++------------- .github/workflows/documentation.yml | 2 +- 3 files changed, 53 insertions(+), 53 deletions(-) diff --git a/.github/workflows/ci-conan.yml b/.github/workflows/ci-conan.yml index 0b11c977..2da635ce 100644 --- a/.github/workflows/ci-conan.yml +++ b/.github/workflows/ci-conan.yml @@ -236,7 +236,7 @@ jobs: - name: Create Conan package shell: bash run: | - conan create . mpusz/testing -e mp-units:CONAN_RUN_TESTS=True -o mp-units:build_docs=False -o mp-units:downcast_mode=${{ matrix.downcast_mode }} -b mp-units -b outdated -u + conan create . mpusz/testing -o mp-units:downcast_mode=${{ matrix.downcast_mode }} -c user.build:all=True -c user.build:skip_docs=True -b mp-units -b outdated -u - name: Upload mp-units Conan package if: github.ref == 'refs/heads/master' || env.CHANNEL == 'stable' shell: bash diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 931eadf4..092c1deb 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -14,13 +14,13 @@ name: "CodeQL" on: push: - branches: [ master ] + branches: [master] paths-ignore: - - 'docs/**' + - "docs/**" pull_request: - branches: [ master ] + branches: [master] paths-ignore: - - 'docs/**' + - "docs/**" jobs: analyze: @@ -33,59 +33,59 @@ jobs: strategy: fail-fast: false matrix: - language: [ 'cpp', 'python' ] + language: ["cpp", "python"] # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ] # Learn more... # https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection steps: - - name: Checkout repository - uses: actions/checkout@v2 + - name: Checkout repository + uses: actions/checkout@v2 - # Initializes the CodeQL tools for scanning. - - name: Initialize CodeQL - uses: github/codeql-action/init@v1 - with: - languages: ${{ matrix.language }} - # If you wish to specify custom queries, you can do so here or in a config file. - # By default, queries listed here will override any specified in a config file. - # Prefix the list here with "+" to use these queries and those in the config file. - # queries: ./path/to/local/query, your-org/your-repo/queries@main + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v2 + with: + languages: ${{ matrix.language }} + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. + # queries: ./path/to/local/query, your-org/your-repo/queries@main - # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). - # If this step fails, then you should remove it and run the build manually (see below) - - name: Autobuild - if: matrix.language != 'cpp' - uses: github/codeql-action/autobuild@v1 + # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). + # If this step fails, then you should remove it and run the build manually (see below) + - name: Autobuild + if: matrix.language != 'cpp' + uses: github/codeql-action/autobuild@v2 - # ℹ️ Command-line programs to run using the OS shell. - # 📚 https://git.io/JvXDl + # ℹ️ Command-line programs to run using the OS shell. + # 📚 https://git.io/JvXDl - - name: Cache Conan data - if: matrix.language == 'cpp' - uses: actions/cache@v2 - env: - cache-name: cache-conan-data - with: - path: ~/.conan/data - key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/metadata.json') }} - restore-keys: | - ${{ runner.os }}-build-${{ env.cache-name }}- - ${{ runner.os }}-build- - ${{ runner.os }}- - - name: Set up Python - if: matrix.language == 'cpp' - uses: actions/setup-python@v2 - with: - python-version: '3.8' - - name: Conan build - if: matrix.language == 'cpp' - run: | - pip install -U conan - conan config init - conan remote add upload https://mpusz.jfrog.io/artifactory/api/conan/conan-oss - mkdir _lgtm_build_dir && cd _lgtm_build_dir - conan install .. -s compiler.cppstd=20 -s compiler.libcxx=libstdc++11 -o mp-units:build_docs=False -e mp-units:CONAN_RUN_TESTS=True -b outdated -u - conan build .. - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v1 + - name: Cache Conan data + if: matrix.language == 'cpp' + uses: actions/cache@v2 + env: + cache-name: cache-conan-data + with: + path: ~/.conan/data + key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/metadata.json') }} + restore-keys: | + ${{ runner.os }}-build-${{ env.cache-name }}- + ${{ runner.os }}-build- + ${{ runner.os }}- + - name: Set up Python + if: matrix.language == 'cpp' + uses: actions/setup-python@v2 + with: + python-version: "3.8" + - name: Conan build + if: matrix.language == 'cpp' + run: | + pip install -U conan + conan config init + conan remote add upload https://mpusz.jfrog.io/artifactory/api/conan/conan-oss + mkdir _lgtm_build_dir && cd _lgtm_build_dir + conan install .. -s compiler.cppstd=20 -s compiler.libcxx=libstdc++11 -c mp-units:user.build:all=True -c user.build:skip_docs=True -b outdated -u + conan build .. + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v1 diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml index f72ecf86..0655eae8 100644 --- a/.github/workflows/documentation.yml +++ b/.github/workflows/documentation.yml @@ -78,7 +78,7 @@ jobs: conan remote add -i 0 upload https://mpusz.jfrog.io/artifactory/api/conan/conan-oss - name: Install Conan dependencies run: | - conan install . -s compiler.cppstd=20 -s compiler.libcxx=libstdc++11 -c tools.cmake.cmaketoolchain:generator="Ninja Multi-Config" -e mp-units:CONAN_RUN_TESTS=True -b outdated -u + conan install . -s compiler.cppstd=20 -s compiler.libcxx=libstdc++11 -c user.build:all=True -c tools.cmake.cmaketoolchain:generator="Ninja Multi-Config" -b outdated -u - name: Configure CMake run: | cmake --preset default From edf59ac47ca914a08bec318f9b715163e24aab9d Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Tue, 2 Aug 2022 17:25:40 +0200 Subject: [PATCH 40/52] docs: Usage page updated for new Conan configuration properties --- docs/usage.rst | 47 +++++++++++++++++++++++------------------------ 1 file changed, 23 insertions(+), 24 deletions(-) diff --git a/docs/usage.rst b/docs/usage.rst index 109f69a3..a73e88a8 100644 --- a/docs/usage.rst +++ b/docs/usage.rst @@ -127,22 +127,6 @@ generators. For example: Build Options ------------- -Environment Variables -^^^^^^^^^^^^^^^^^^^^^ - -CONAN_RUN_TESTS -+++++++++++++++ - -**Values**: ``True``/``False`` - -**Defaulted to**: ``False`` - -Enables compilation of all the source code (tests and examples) and building the documentation. -To support this it requires some additional Conan build dependencies described in -`Repository Structure and Dependencies`_. -It also runs unit tests during Conan build. - - Conan Options ^^^^^^^^^^^^^ @@ -159,15 +143,30 @@ Specifies how :ref:`design/downcasting:The Downcasting Facility` works: - ``on`` - downcasting always forced -> compile-time errors in case of duplicated definitions - ``automatic`` - downcasting automatically enabled if no collisions are present -build_docs -++++++++++ +Conan Configuration Properties +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +build_all ++++++++++ **Values**: ``True``/``False`` -**Defaulted to**: ``True`` +**Defaulted to**: ``False`` -If enabled, Conan installs the documentation generation dependencies (i.e. doxygen). -Additionally, enables project documentation generation when the project is being built by Conan. +Enables compilation of all the source code (tests and examples) and generating the documentation. +To support this it requires some additional Conan build dependencies described in +`Repository Structure and Dependencies`_. +It also runs unit tests during Conan build (unless ``tools.build:skip_test`` configuration property is set to ``True``) + +skip_docs ++++++++++ + +**Values**: ``True``/``False`` + +**Defaulted to**: ``False`` + +If `build_all`_ is enabled, among others, Conan installs the documentation generation dependencies (i.e. doxygen) and +turns on the project documentation generation. Such behavior can be disabled with this option. CMake Options ^^^^^^^^^^^^^ @@ -415,7 +414,7 @@ you should: .. code-block:: shell git clone https://github.com/mpusz/units.git && cd units - conan install . -pr -s compiler.cppstd=20 -e mp-units:CONAN_RUN_TESTS=True -o build_docs=False -b outdated -u + conan install . -pr -s compiler.cppstd=20 -c mp-units:user.build:all=True -c user.build:skip_docs=True -b outdated -u conan build . The above will download and install all of the dependencies needed for the development of the library, @@ -444,7 +443,7 @@ In case you would like to build the project's documentation, you should: git clone https://github.com/mpusz/units.git && cd units pip3 install -r docs/requirements.txt - conan install . -pr -s compiler.cppstd=20 -e mp-units:CONAN_RUN_TESTS=True -b missing + conan install . -pr -s compiler.cppstd=20 -c mp-units:user.build:all=True -b missing cmake --preset default cmake --build --preset release --target documentation @@ -458,7 +457,7 @@ To test CMake installation and Conan packaging or create a Conan package run: .. code-block:: shell - conan create . / -pr -s compiler.cppstd=20 -e mp-units:CONAN_RUN_TESTS=True -b outdated -u + conan create . / -pr -s compiler.cppstd=20 -c mp-units:user.build:all=True -c user.build:skip_docs=True -b outdated -u The above will create a Conan package and run tests provided in *./test_package* directory. From 25e868a16fc811ec76da6b3beb66a9c613b4154e Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Tue, 2 Aug 2022 18:33:58 +0200 Subject: [PATCH 41/52] docs: Some outdated TODO comments removed --- .github/workflows/ci-conan.yml | 2 -- .github/workflows/ci-test-package-cmake.yml | 2 -- cmake/documentation.cmake | 4 ++-- docs/framework/units.rst | 3 --- 4 files changed, 2 insertions(+), 9 deletions(-) diff --git a/.github/workflows/ci-conan.yml b/.github/workflows/ci-conan.yml index 2da635ce..3903e4b1 100644 --- a/.github/workflows/ci-conan.yml +++ b/.github/workflows/ci-conan.yml @@ -187,8 +187,6 @@ jobs: run: | sudo xcode-select -s "/Applications/Xcode_13.0.app" - name: Install Ninja - # TODO Find a proper syntax to make the below work - # if: !matrix.config.docker_image shell: bash run: | if [ $RUNNER_OS == 'Linux' ]; then diff --git a/.github/workflows/ci-test-package-cmake.yml b/.github/workflows/ci-test-package-cmake.yml index 4dc9d15a..7dfaa473 100644 --- a/.github/workflows/ci-test-package-cmake.yml +++ b/.github/workflows/ci-test-package-cmake.yml @@ -190,8 +190,6 @@ jobs: run: | sudo xcode-select -s "/Applications/Xcode_13.0.app" - name: Install Ninja - # TODO Find a proper syntax to make the below work - # if: !matrix.config.docker_image shell: bash run: | if [ $RUNNER_OS == 'Linux' ]; then diff --git a/cmake/documentation.cmake b/cmake/documentation.cmake index 3e6b239d..6d272bcd 100644 --- a/cmake/documentation.cmake +++ b/cmake/documentation.cmake @@ -22,8 +22,8 @@ cmake_minimum_required(VERSION 3.5) -find_package(Doxygen MODULE REQUIRED -)# TODO Switch to CONFIG when Conan will start supporting imported executables in CMakeDeps +# TODO Switch to CONFIG when Conan will start supporting imported executables in CMakeDeps +find_package(Doxygen MODULE REQUIRED) find_package(Sphinx REQUIRED) # diff --git a/docs/framework/units.rst b/docs/framework/units.rst index f9981ba5..9e739112 100644 --- a/docs/framework/units.rst +++ b/docs/framework/units.rst @@ -188,9 +188,6 @@ and define units like:: struct electronvolt : named_scaled_unit {}; -.. - TODO Submit a bug for above lexing problem - Finally, the last of the `named_scaled_unit` class template parameters provide a reference unit for scaling. Please note that it can be a dimension's base/coherent unit (like ``si::second``) or any other unit (i.e. ``si::minute``, From 3478c462fa67cabcf9d3577361d7031d13fb8c4a Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Tue, 2 Aug 2022 18:35:11 +0200 Subject: [PATCH 42/52] docs: Custom pygments cpp lexer no longer needed --- docs/conf.py | 481 +-------------------------------------------------- 1 file changed, 2 insertions(+), 479 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 54aa719b..75d699cd 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -1,488 +1,11 @@ -# -*- coding: utf-8 -*- -""" - pygments.lexers.c_cpp - ~~~~~~~~~~~~~~~~~~~~~ - - Lexers for C/C++ languages. - - :copyright: Copyright 2006-2019 by the Pygments team, see AUTHORS. - :license: BSD, see LICENSE for details. -""" - -import os -import re -import subprocess - -from pygments.lexer import ( - RegexLexer, - bygroups, - default, - include, - inherit, - this, - using, - words, -) -from pygments.token import ( - Comment, - Error, - Keyword, - Name, - Number, - Operator, - Punctuation, - String, - Text, -) -from pygments.util import get_bool_opt -from sphinx.highlighting import lexers - - -class MyCFamilyLexer(RegexLexer): - #: optional Comment or Whitespace - _ws = r"(?:\s|//.*?\n|/[*].*?[*]/)+" - - # The trailing ?, rather than *, avoids a geometric performance drop here. - #: only one /* */ style comment - _ws1 = r"\s*(?:/[*].*?[*]/\s*)?" - - tokens = { - "whitespace": [ - # preprocessor directives: without whitespace - (r"^#if\s+0", Comment.Preproc, "if0"), - ("^#", Comment.Preproc, "macro"), - # or with whitespace - ( - "^(" + _ws1 + r")(#if\s+0)", - bygroups(using(this), Comment.Preproc), - "if0", - ), - ("^(" + _ws1 + ")(#)", bygroups(using(this), Comment.Preproc), "macro"), - (r"\n", Text), - (r"\s+", Text), - (r"\\\n", Text), # line continuation - (r"//(\n|[\w\W]*?[^\\]\n)", Comment.Single), - (r"/(\\\n)?[*][\w\W]*?[*](\\\n)?/", Comment.Multiline), - # Open until EOF, so no ending delimeter - (r"/(\\\n)?[*][\w\W]*", Comment.Multiline), - ], - "statements": [ - (r'(L?)(")', bygroups(String.Affix, String), "string"), - ( - r"(L?)(')(\\.|\\[0-7]{1,3}|\\x[a-fA-F0-9]{1,2}|[^\\\'\n])(')", - bygroups(String.Affix, String.Char, String.Char, String.Char), - ), - (r"\*/", Error), - (r"[~!%^&*+=|?:<>/-]", Operator), - (r"[()\[\],.]", Punctuation), - ( - words( - ( - "asm", - "auto", - "break", - "case", - "const", - "continue", - "default", - "do", - "else", - "enum", - "extern", - "for", - "goto", - "if", - "register", - "restricted", - "return", - "sizeof", - "static", - "struct", - "switch", - "typedef", - "union", - "volatile", - "while", - ), - suffix=r"\b", - ), - Keyword, - ), - ( - r"(bool|int|long|float|short|double|char|unsigned|signed|void)\b", - Keyword.Type, - ), - ( - words( - ( - "inline", - "_inline", - "__inline", - "naked", - "restrict", - "thread", - "typename", - ), - suffix=r"\b", - ), - Keyword.Reserved, - ), - # Vector intrinsics - (r"(__m(128i|128d|128|64))\b", Keyword.Reserved), - # Microsoft-isms - ( - words( - ( - "asm", - "int8", - "based", - "except", - "int16", - "stdcall", - "cdecl", - "fastcall", - "int32", - "declspec", - "finally", - "int64", - "try", - "leave", - "wchar_t", - "w64", - "unaligned", - "raise", - "noop", - "identifier", - "forceinline", - "assume", - ), - prefix=r"__", - suffix=r"\b", - ), - Keyword.Reserved, - ), - (r"(true|false|NULL)\b", Name.Builtin), - (r"([a-zA-Z_]\w*)(\s*)(:)(?!:)", bygroups(Name.Label, Text, Punctuation)), - (r"[a-zA-Z_]\w*", Name), - ], - "root": [ - include("whitespace"), - # functions - ( - r"((?:[\w*\s])+?(?:\s|[*]))" # return arguments - r"([a-zA-Z_]\w*)" # method name - r"(\s*\([^;]*?\))" # signature - r"([^;{]*)(\{)", - bygroups( - using(this), Name.Function, using(this), using(this), Punctuation - ), - "function", - ), - # function declarations - ( - r"((?:[\w*\s])+?(?:\s|[*]))" # return arguments - r"([a-zA-Z_]\w*)" # method name - r"(\s*\([^;]*?\))" # signature - r"([^;]*)(;)", - bygroups( - using(this), Name.Function, using(this), using(this), Punctuation - ), - ), - default("statement"), - ], - "statement": [ - include("whitespace"), - include("statements"), - ("[{}]", Punctuation), - (";", Punctuation, "#pop"), - ], - "function": [ - include("whitespace"), - include("statements"), - (";", Punctuation), - (r"\{", Punctuation, "#push"), - (r"\}", Punctuation, "#pop"), - ], - "string": [ - (r'"', String, "#pop"), - ( - r'\\([\\abfnrtv"\']|x[a-fA-F0-9]{2,4}|' - r"u[a-fA-F0-9]{4}|U[a-fA-F0-9]{8}|[0-7]{1,3})", - String.Escape, - ), - (r'[^\\"\n]+', String), # all other characters - (r"\\\n", String), # line continuation - (r"\\", String), # stray backslash - ], - "macro": [ - ( - r"(include)(" + _ws1 + r")([^\n]+)", - bygroups(Comment.Preproc, Text, Comment.PreprocFile), - ), - (r"[^/\n]+", Comment.Preproc), - (r"/[*](.|\n)*?[*]/", Comment.Multiline), - (r"//.*?\n", Comment.Single, "#pop"), - (r"/", Comment.Preproc), - (r"(?<=\\)\n", Comment.Preproc), - (r"\n", Comment.Preproc, "#pop"), - ], - "if0": [ - (r"^\s*#if.*?(?)", Text, "#pop"), - ], - } - - def analyse_text(text): - if re.search("#include <[a-z_]+>", text): - return 0.2 - if re.search("using namespace ", text): - return 0.4 - - -lexers["cpp"] = MyCppLexer(startinline=True) - -# TODO Remove the above when Pygments release with fixes is available - - # Configuration file for the Sphinx documentation builder. # # This file only contains a selection of the most common options. # For a full list see the documentation: # https://www.sphinx-doc.org/en/master/usage/configuration.html +import re + def get_version(): try: From 6267b3372c165918222eface35f3fb53eba89693 Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Tue, 2 Aug 2022 18:35:52 +0200 Subject: [PATCH 43/52] docs: READTHEDOCS build support removed --- docs/conf.py | 22 +--------------------- 1 file changed, 1 insertion(+), 21 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 75d699cd..06acf0a1 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -121,29 +121,9 @@ html_css_files = ["css/custom.css"] # -- Breathe configuration --------------------------------------------------- -def configureDoxyfile(input_dir, output_dir): - with open("Doxyfile.in", "r") as file: - filedata = file.read() - - filedata = filedata.replace("@DOXYGEN_INPUT_DIR@", input_dir) - filedata = filedata.replace("@DOXYGEN_OUTPUT_DIR@", output_dir) - - with open("Doxyfile", "w") as file: - file.write(filedata) - - -# Check if we're running on Read the Docs' servers -read_the_docs_build = os.environ.get("READTHEDOCS", None) == "True" - # This should be a dictionary in which the keys are project names and the values # are paths to the folder containing the doxygen output for that project. -breathe_projects = {} -if read_the_docs_build: - input_dir = "../src" - output_dir = "build" - configureDoxyfile(input_dir, output_dir) - subprocess.call("doxygen", shell=True) - breathe_projects["mp-units"] = output_dir + "/xml" +breathe_projects = {"mp-units": "build/xml"} # This should match one of the keys in the breathe_projects dictionary and # indicates which project should be used when the project is not specified on From 0f37d0af60ed0fc428c6f0c3b6abf951b4b41cbc Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Tue, 2 Aug 2022 18:36:17 +0200 Subject: [PATCH 44/52] docs: Broken links in the documentation fixed --- docs/reference/core/concepts.rst | 5 +++++ docs/usage.rst | 4 ++-- docs/use_cases/interoperability.rst | 2 +- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/docs/reference/core/concepts.rst b/docs/reference/core/concepts.rst index 99f38ce9..2fd5e130 100644 --- a/docs/reference/core/concepts.rst +++ b/docs/reference/core/concepts.rst @@ -63,6 +63,11 @@ Concepts A concept matching all quantity-like types other than specialization of :class:`quantity`. Satisfied by all types for which a correct specialization of :class:`quantity_like_traits` type trait is provided. +.. concept:: template QuantityPointLike + + A concept matching all quantity-point-like types other than specialization of :class:`quantity_point`. + Satisfied by all types for which a correct specialization of :class:`quantity_point_like_traits` type trait is provided. + .. concept:: template WrappedQuantity A concept matching types that wrap quantity objects. Satisfied by all wrapper types that diff --git a/docs/usage.rst b/docs/usage.rst index a73e88a8..c8a22e3b 100644 --- a/docs/usage.rst +++ b/docs/usage.rst @@ -408,7 +408,7 @@ In case you would like to build all the source code (with unit tests and example you should: 1. Use the *CMakeLists.txt* from the top-level directory. -2. Run Conan with `CONAN_RUN_TESTS`_ = ``True`` +2. Run Conan with `build_all`_ = ``True`` (use ``-o build_docs=False`` if you want to skip the documentation generation). .. code-block:: shell @@ -437,7 +437,7 @@ In case you would like to build the project's documentation, you should: 1. Use the *CMakeLists.txt* from the top-level directory. 2. Obtain Python dependencies. -3. Run Conan with `CONAN_RUN_TESTS`_ = ``True``. +3. Run Conan with `build_all`_ = ``True``. .. code-block:: shell diff --git a/docs/use_cases/interoperability.rst b/docs/use_cases/interoperability.rst index a229b018..40f58501 100644 --- a/docs/use_cases/interoperability.rst +++ b/docs/use_cases/interoperability.rst @@ -59,7 +59,7 @@ It works just like `quantity_like_traits`, except that ``number(T)`` is replaced with ``relative(T)`` that returns the `QuantityLike` value and ``dimension`` is replaced with ``origin``. -Similar to `quantity` and `quantity_kind`, `quantity_point` and `quantity_kind_point` +Similar to `quantity` and `quantity_kind`, `quantity_point` and `quantity_point_kind` provide a deduction guide from `QuantityPointLike`:: using namespace std::chrono_literals; From 9aa3fd4d00ee9e6dea3f4a67cc10bf06e5e3e634 Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Wed, 3 Aug 2022 11:29:20 +0200 Subject: [PATCH 45/52] fix: `prefixed_alias_unit` constraints fixed --- docs/reference/core/concepts.rst | 5 +++++ src/core/include/units/bits/basic_concepts.h | 15 +++++++++++++++ src/core/include/units/unit.h | 12 +++++------- 3 files changed, 25 insertions(+), 7 deletions(-) diff --git a/docs/reference/core/concepts.rst b/docs/reference/core/concepts.rst index 2fd5e130..e835c0bd 100644 --- a/docs/reference/core/concepts.rst +++ b/docs/reference/core/concepts.rst @@ -45,6 +45,11 @@ Concepts A concept matching all unit types that have an atomic text symbol that can be used to aggregate it with other named units to form a final symbol of a derived unit. +.. concept:: template AliasUnit + + A concept matching all alias unit types in the library. Satisfied by all unit types derived + from the instantiation of :class:`alias_unit`. + .. concept:: template UnitOf A concept matching only units of a specified dimension. Satisfied by all unit types that diff --git a/src/core/include/units/bits/basic_concepts.h b/src/core/include/units/bits/basic_concepts.h index 28776ab9..ac073b28 100644 --- a/src/core/include/units/bits/basic_concepts.h +++ b/src/core/include/units/bits/basic_concepts.h @@ -29,6 +29,7 @@ #include #include #include +#include // IWYU pragma: end_exports #include @@ -86,6 +87,20 @@ inline constexpr bool is_named = false; template concept NamedUnit = Unit && detail::is_named; +template +struct alias_unit; + +// TODO: Remove when P1985 accepted +namespace detail { + +template +void to_base_alias_unit(const volatile alias_unit*); + +} // namespace detail + +template +concept AliasUnit = requires(T* t) { detail::to_base_alias_unit(t); }; + // BaseDimension template struct base_dimension; diff --git a/src/core/include/units/unit.h b/src/core/include/units/unit.h index dbba2ecf..c388369c 100644 --- a/src/core/include/units/unit.h +++ b/src/core/include/units/unit.h @@ -58,8 +58,10 @@ inline constexpr bool can_be_prefixed = false; * * @tparam M a Magnitude representing the (relative) size of this unit * @tparam U a unit to use as a reference for this dimension + * + * @note U cannot be constrained with Unit as for some specializations (i.e. named_unit) + * it gets the incomplete child's type with the CRTP idiom. */ -// TODO Replace `typename` with `Unit` template struct scaled_unit : downcast_base> { static constexpr UNITS_MSVC_WORKAROUND(Magnitude) auto mag = M; @@ -175,12 +177,8 @@ struct alias_unit : U { * @tparam P prefix to be appied to the reference unit * @tparam AU reference alias unit */ -// TODO gcc bug: 95015 -// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=95015 -// template -// requires (!AliasUnit) -template - requires detail::can_be_prefixed +template + requires(!AliasUnit) struct prefixed_alias_unit : U { static constexpr auto symbol = P::symbol + AU::symbol; }; From dd4679459d82303a3545f76bf648a64726021d87 Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Wed, 3 Aug 2022 12:29:49 +0200 Subject: [PATCH 46/52] feat: `hypot` support added --- .../glide_computer/include/glide_computer.h | 8 ++-- src/core/include/units/math.h | 46 +++++++++++++++++++ 2 files changed, 49 insertions(+), 5 deletions(-) diff --git a/example/glide_computer/include/glide_computer.h b/example/glide_computer/include/glide_computer.h index c515868c..c846b72d 100644 --- a/example/glide_computer/include/glide_computer.h +++ b/example/glide_computer/include/glide_computer.h @@ -157,9 +157,8 @@ public: using legs = std::vector; template - requires std::same_as, - waypoint> explicit task(const R& r) : - waypoints_(std::ranges::begin(r), std::ranges::end(r)) + requires std::same_as, waypoint> + explicit task(const R& r) : waypoints_(std::ranges::begin(r), std::ranges::end(r)) { } @@ -215,8 +214,7 @@ constexpr height agl(altitude glider_alt, altitude terrain_level) { return glide inline units::isq::si::length length_3d(distance dist, height h) { - // TODO support for hypot(q, q) - return sqrt(pow<2>(dist.common()) + pow<2>(h.common())); + return hypot(dist.common(), h.common()); } distance glide_distance(const flight_point& pos, const glider& g, const task& t, const safety& s, altitude ground_alt); diff --git a/src/core/include/units/math.h b/src/core/include/units/math.h index 0de45139..2e9e7027 100644 --- a/src/core/include/units/math.h +++ b/src/core/include/units/math.h @@ -301,4 +301,50 @@ template D, typename U, std::s return ::units::round(q); } +/** + * @brief Computes the square root of the sum of the squares of x and y, + * without undue overflow or underflow at intermediate stages of the computation + */ +template +[[nodiscard]] inline std::common_type_t hypot(const Q1& x, const Q2& y) noexcept + requires requires { typename std::common_type_t; } && + requires(std::common_type_t q) { + pow<2>(x); + pow<2>(y); + sqrt(pow<2>(x) + pow<2>(y)); + requires requires { hypot(q.number(), q.number()); } || requires { std::hypot(q.number(), q.number()); }; + } +{ + using type = std::common_type_t; + type xx = x; + type yy = y; + using std::hypot; + return type(hypot(xx.number(), yy.number())); +} + +/** + * @brief Computes the square root of the sum of the squares of x, y, and z, + * without undue overflow or underflow at intermediate stages of the computation + */ +template +[[nodiscard]] inline std::common_type_t, Q3> hypot(const Q1& x, const Q2& y, + const Q3& z) noexcept + requires requires { typename std::common_type_t, Q3>; } && + requires(std::common_type_t, Q3> q) { + pow<2>(x); + pow<2>(y); + pow<2>(z); + sqrt(pow<2>(x) + pow<2>(y) + pow<2>(z)); + requires requires { hypot(q.number(), q.number(), q.number()); } || + requires { std::hypot(q.number(), q.number(), q.number()); }; + } +{ + using type = std::common_type_t, Q3>; + type xx = x; + type yy = y; + type zz = z; + using std::hypot; + return type(hypot(xx.number(), yy.number(), zz.number())); +} + } // namespace units From b252da0fe1643e9b5080f0487da2ae25b6978921 Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Wed, 3 Aug 2022 13:10:59 +0200 Subject: [PATCH 47/52] test: `hypot` unit tests added --- test/unit_test/runtime/math_test.cpp | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/test/unit_test/runtime/math_test.cpp b/test/unit_test/runtime/math_test.cpp index d74c93ef..22464106 100644 --- a/test/unit_test/runtime/math_test.cpp +++ b/test/unit_test/runtime/math_test.cpp @@ -22,6 +22,7 @@ #include #include +#include #include #include #include @@ -30,7 +31,7 @@ using namespace units; using namespace units::isq; -using namespace units::isq::si; +using namespace units::isq::si::literals; // classical @@ -363,3 +364,21 @@ TEMPLATE_PRODUCT_TEST_CASE_SIG("detail::iroot()", "[math][pow][iroot]", (std: ROOT_TEST_CASE(CompileRoot) ROOT_TEST_CASE(RuntimeRoot) + +TEST_CASE("hypot functions", "[hypot]") +{ + using namespace units::aliases::isq::si; + + SECTION("hypot of 3 kilometres with 4 kilometres should be 5 kilometres") + { + REQUIRE(hypot(km<>(3.), km<>(4.)) == km<>(5.)); + } + SECTION("hypot should work with different units of the same dimension") + { + REQUIRE(hypot(km<>(3.), m<>(4000.)) == km<>(5.)); + } + SECTION("hypot should work with different but equivalent dimensions") + { + REQUIRE(hypot(km<>(3.), cgs::length::cm<>(400'000.)) == km<>(5.)); + } +} From 4c8b3ce290693fc4c53347966019027830ef5ee1 Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Wed, 3 Aug 2022 13:12:24 +0200 Subject: [PATCH 48/52] test: Commented out `ceil` unit test enabled as it works correctly now --- test/unit_test/runtime/math_test.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/unit_test/runtime/math_test.cpp b/test/unit_test/runtime/math_test.cpp index 22464106..2f4c223f 100644 --- a/test/unit_test/runtime/math_test.cpp +++ b/test/unit_test/runtime/math_test.cpp @@ -187,10 +187,10 @@ TEST_CASE("ceil functions", "[ceil]") { REQUIRE(ceil(1999._q_ms) == 2_q_s); } - // TODO does not work, probably due to a bug in fpow10() see #311 - // SECTION ("ceil -1000. milliseconds with target unit second should be -1 second") { - // REQUIRE(ceil(-1000._q_ms) == -1_q_s); - // } + SECTION("ceil -1000. milliseconds with target unit second should be -1 second") + { + REQUIRE(ceil(-1000._q_ms) == -1_q_s); + } SECTION("ceil -999. milliseconds with target unit second should be 0 seconds") { REQUIRE(ceil(-999._q_ms) == 0_q_s); From 4313df390c853a95eb34d809402bc0a7f444d3b8 Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Wed, 3 Aug 2022 13:34:45 +0200 Subject: [PATCH 49/52] refactor: `hypot` refactored to use variadic `common_type` version --- src/core/include/units/math.h | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/core/include/units/math.h b/src/core/include/units/math.h index 2e9e7027..6afb3b44 100644 --- a/src/core/include/units/math.h +++ b/src/core/include/units/math.h @@ -327,10 +327,9 @@ template * without undue overflow or underflow at intermediate stages of the computation */ template -[[nodiscard]] inline std::common_type_t, Q3> hypot(const Q1& x, const Q2& y, - const Q3& z) noexcept - requires requires { typename std::common_type_t, Q3>; } && - requires(std::common_type_t, Q3> q) { +[[nodiscard]] inline std::common_type_t hypot(const Q1& x, const Q2& y, const Q3& z) noexcept + requires requires { typename std::common_type_t; } && + requires(std::common_type_t q) { pow<2>(x); pow<2>(y); pow<2>(z); @@ -339,7 +338,7 @@ template requires { std::hypot(q.number(), q.number(), q.number()); }; } { - using type = std::common_type_t, Q3>; + using type = std::common_type_t; type xx = x; type yy = y; type zz = z; From a1e1b70b9246e19c849e80ccd7270d4704442546 Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Wed, 3 Aug 2022 13:35:18 +0200 Subject: [PATCH 50/52] test: Unit tests for 3-argument `hypot` added --- test/unit_test/runtime/math_test.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/test/unit_test/runtime/math_test.cpp b/test/unit_test/runtime/math_test.cpp index 2f4c223f..783480db 100644 --- a/test/unit_test/runtime/math_test.cpp +++ b/test/unit_test/runtime/math_test.cpp @@ -369,16 +369,19 @@ TEST_CASE("hypot functions", "[hypot]") { using namespace units::aliases::isq::si; - SECTION("hypot of 3 kilometres with 4 kilometres should be 5 kilometres") + SECTION("hypot should work on the same quantities") { REQUIRE(hypot(km<>(3.), km<>(4.)) == km<>(5.)); + REQUIRE(hypot(km<>(2.), km<>(3.), km<>(6.)) == km<>(7.)); } SECTION("hypot should work with different units of the same dimension") { REQUIRE(hypot(km<>(3.), m<>(4000.)) == km<>(5.)); + REQUIRE(hypot(km<>(2.), m<>(3000.), km<>(6.)) == km<>(7.)); } SECTION("hypot should work with different but equivalent dimensions") { REQUIRE(hypot(km<>(3.), cgs::length::cm<>(400'000.)) == km<>(5.)); + REQUIRE(hypot(km<>(2.), cgs::length::cm<>(300'000.), km<>(6.)) == km<>(7.)); } } From 4e044c4e43df5d3988a8459a5c5fd9d62951d7db Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Wed, 3 Aug 2022 13:51:18 +0200 Subject: [PATCH 51/52] refactor: `hypot` was overconstrained --- src/core/include/units/math.h | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/core/include/units/math.h b/src/core/include/units/math.h index 6afb3b44..3c67e945 100644 --- a/src/core/include/units/math.h +++ b/src/core/include/units/math.h @@ -309,9 +309,6 @@ template [[nodiscard]] inline std::common_type_t hypot(const Q1& x, const Q2& y) noexcept requires requires { typename std::common_type_t; } && requires(std::common_type_t q) { - pow<2>(x); - pow<2>(y); - sqrt(pow<2>(x) + pow<2>(y)); requires requires { hypot(q.number(), q.number()); } || requires { std::hypot(q.number(), q.number()); }; } { @@ -330,10 +327,6 @@ template [[nodiscard]] inline std::common_type_t hypot(const Q1& x, const Q2& y, const Q3& z) noexcept requires requires { typename std::common_type_t; } && requires(std::common_type_t q) { - pow<2>(x); - pow<2>(y); - pow<2>(z); - sqrt(pow<2>(x) + pow<2>(y) + pow<2>(z)); requires requires { hypot(q.number(), q.number(), q.number()); } || requires { std::hypot(q.number(), q.number(), q.number()); }; } From 1957e4424c603bd6a59dc0fb0ddacd83bddcf931 Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Wed, 3 Aug 2022 17:09:15 +0200 Subject: [PATCH 52/52] docs: TODO comments cleanup in mixed system unit test files --- test/unit_test/static/si_cgs_test.cpp | 9 +++++---- test/unit_test/static/si_fps_test.cpp | 10 ++++++---- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/test/unit_test/static/si_cgs_test.cpp b/test/unit_test/static/si_cgs_test.cpp index 01f4379e..8c817f08 100644 --- a/test/unit_test/static/si_cgs_test.cpp +++ b/test/unit_test/static/si_cgs_test.cpp @@ -127,8 +127,8 @@ static_assert(quantity_cast>(si::length(2) == si::area(4)); // TODO Add support for -// comparing of an unknown_dimension +// TODO Add support for comparing of an unknown_dimension +// static_assert(200._q_cm * si::length(2) == si::area(4)); static_assert(quantity_cast(200._q_cm) * si::length(2) == si::area(4)); static_assert(200._q_cm * quantity_cast(si::length(2)) == 40'000_q_cm2); @@ -142,8 +142,9 @@ static_assert(200._q_cm * quantity_cast(si::length(4) / 200_q_cm == si::length(2)); // TODO Add support for -// comparing of an unknown_dimension +// TODO Add support for comparing of an unknown_dimension +// static_assert(si::area(4) / 200_q_cm == si::length(2)); +// static_assert(400._q_cm / si::length(2) == 2); static_assert(si::area(4) / quantity_cast>(200_q_cm) == si::length(2)); diff --git a/test/unit_test/static/si_fps_test.cpp b/test/unit_test/static/si_fps_test.cpp index bb023c8c..0f630fa3 100644 --- a/test/unit_test/static/si_fps_test.cpp +++ b/test/unit_test/static/si_fps_test.cpp @@ -157,8 +157,8 @@ static_assert(quantity_cast>(si::length(2) == si::area(1.2192)); // TODO Add support for -// comparing of an unknown_dimension +// TODO Add support for comparing of an unknown_dimension +// static_assert(2 * ft * si::length(2) == si::area(1.2192)); static_assert(quantity_cast>(2. * ft) * si::length(2) == si::area(1.2192)); static_assert(quantity_cast>(2. * ft) * si::length(0.6096) == @@ -167,8 +167,10 @@ static_assert(2. * ft * quantity_cast>(si::length // division -// static_assert(si::area(4) / 200_q_cm == si::length(2)); // TODO Add support for -// comparing of an unknown_dimension +// TODO Add support for comparing of an unknown_dimension +// static_assert(si::area(4) / 200_q_cm == si::length(2)); +// static_assert(400._q_cm / si::length(2) == 2); + static_assert(si::area(1.48644864) / quantity_cast>(4 * ft) == si::length(1.2192)); // 16 ft2 / 4 ft = 4 ft static_assert(quantity_cast>(si::area(1.48644864)) / (4. * ft) ==