// 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. #include "test_tools.h" #include #include #include #include #ifdef MP_UNITS_IMPORT_STD import std; #else #include #endif namespace { using namespace mp_units; using namespace mp_units::detail; using one_ = struct one; using percent_ = struct percent; // clang-format off // prefixes template struct milli_ final : prefixed_unit<"m", mag_power<10, -3>, U{}> {}; template struct kilo_ final : prefixed_unit<"k", mag_power<10, 3>, U{}> {}; template constexpr milli_ milli; template constexpr kilo_ kilo; // base units inline constexpr struct second_ final : named_unit<"s", kind_of> {} second; inline constexpr struct metre_ final : named_unit<"m", kind_of> {} metre; inline constexpr struct gram_ final : named_unit<"g", kind_of> {} gram; inline constexpr auto kilogram = kilo; inline constexpr struct kelvin_ final : named_unit<"K", kind_of> {} kelvin; inline constexpr struct beat_ final : named_unit<"beat", one> {} beat; inline constexpr struct cow_ final : named_unit<"cow", kind_of> {} cow; // derived named units inline constexpr struct radian_ final : named_unit<"rad", metre / metre, kind_of> {} radian; inline constexpr struct revolution_ final : named_unit<"rev", mag<2> * π * radian> {} revolution; inline constexpr struct steradian_ final : named_unit<"sr", square(metre) / square(metre), kind_of> {} steradian; inline constexpr struct hertz_ final : named_unit<"Hz", inverse(second), kind_of> {} hertz; inline constexpr struct becquerel_ final : named_unit<"Bq", inverse(second), kind_of> {} becquerel; inline constexpr struct newton_ final : named_unit<"N", kilogram * metre / square(second)> {} newton; inline constexpr struct pascal_ final : named_unit<"Pa", newton / square(metre)> {} pascal; inline constexpr struct joule_ final : named_unit<"J", newton * metre> {} joule; inline constexpr struct watt_ final : named_unit<"W", joule / second> {} watt; inline constexpr struct degree_Celsius_ final : named_unit {} degree_Celsius; inline constexpr struct degree_Fahrenheit_ final : named_unit * degree_Celsius> {} degree_Fahrenheit; inline constexpr struct minute_ final : named_unit<"min", mag<60> * second> {} minute; inline constexpr struct hour_ final : named_unit<"h", mag<60> * minute> {} hour; inline constexpr struct degree_ final : named_unit * π * radian> {} degree; inline constexpr struct yard_ final : named_unit<"yd", mag_ratio<9'144, 10'000> * metre> {} yard; inline constexpr struct mile_ final : named_unit<"mi", mag<1760> * yard> {} mile; inline constexpr struct nautical_mile_ final : named_unit<"nmi", mag<1852> * metre> {} nautical_mile; inline constexpr auto kilometre = kilo; inline constexpr auto kilojoule = kilo; // physical constant units inline constexpr struct standard_gravity_ final : named_unit * metre / square(second)> {} standard_gravity; inline constexpr struct speed_of_light_in_vacuum_ final : named_unit<"c", mag<299'792'458> * metre / second> {} speed_of_light_in_vacuum; // clang-format on // concepts verification static_assert(Unit); static_assert(Unit); static_assert(Unit); static_assert(Unit); static_assert(Unit); static_assert(Unit); static_assert(Unit>); static_assert(Unit); static_assert(Unit); static_assert(Unit * second)>); static_assert(Unit); static_assert(Unit); static_assert(Unit); static_assert(PrefixableUnit); static_assert(PrefixableUnit); static_assert(PrefixableUnit); static_assert(PrefixableUnit); static_assert(PrefixableUnit); static_assert(!PrefixableUnit); static_assert(!PrefixableUnit); static_assert(!PrefixableUnit>); static_assert(!PrefixableUnit); static_assert(!PrefixableUnit); static_assert(!PrefixableUnit * second)>); static_assert(!PrefixableUnit); // named unit static_assert(is_of_type); static_assert(is_of_type); static_assert(get_canonical_unit(metre).mag == mag<1>); static_assert(metre == metre); static_assert(metre != second); static_assert(is_of_type); static_assert(is_of_type); static_assert(get_canonical_unit(degree_Celsius).mag == mag<1>); static_assert(degree_Celsius != kelvin); static_assert(equivalent(degree_Celsius, kelvin)); static_assert(is_of_type); static_assert(is_of_type); static_assert(get_canonical_unit(radian).mag == mag<1>); static_assert(is_of_type); static_assert(is_of_type); static_assert(get_canonical_unit(degree).mag == mag / mag<180>); static_assert(radian != degree); static_assert(radian != one); static_assert(is_of_type); static_assert(is_of_type); static_assert(get_canonical_unit(steradian).mag == mag<1>); static_assert(radian != steradian); static_assert(is_of_type); static_assert(is_of_type); static_assert(get_canonical_unit(minute).mag == mag<60>); static_assert(minute != second); static_assert(is_of_type); static_assert(is_of_type); static_assert(get_canonical_unit(hour).mag == mag<3600>); static_assert(hour != second); static_assert(hour != minute); static_assert(hour == hour); static_assert(is_of_type); static_assert( is_of_type>>>); static_assert(get_canonical_unit(newton).mag == mag<1000>); // !!! (because of kilogram) static_assert(newton == newton); static_assert(is_of_type); static_assert( is_of_type, per>>>); static_assert(get_canonical_unit(joule).mag == mag<1000>); // !!! (because of kilogram) static_assert(joule == joule); static_assert(joule != newton); // constant_unit static_assert(is_of_type); static_assert( is_of_type>>>); static_assert(get_canonical_unit(standard_gravity).mag == mag_ratio<980'665, 100'000>); static_assert(standard_gravity == standard_gravity); static_assert(standard_gravity != metre / square(second)); // magnitude is different static_assert(standard_gravity._symbol_ == symbol_text{u8"g₀", "g_0"}); // prefixed_unit static_assert(is_of_type)>); static_assert(is_of_type); static_assert(get_canonical_unit(kilometre).mag == mag<1000>); static_assert(kilometre != metre); static_assert(kilometre._symbol_ == "km"); static_assert(is_of_type)>); static_assert(is_of_type, per>>>); static_assert(get_canonical_unit(kilojoule).mag == mag<1'000'000>); static_assert(kilojoule != joule); static_assert(kilojoule._symbol_ == "kJ"); static_assert(is_of_type, kilo_>); static_assert(is_of_type, kilo_>); static_assert(is_of_type), per>>); // !!! // prefixes static_assert(si::quecto._symbol_ == "qm"); static_assert(si::ronto._symbol_ == "rm"); static_assert(si::yocto._symbol_ == "ym"); static_assert(si::zepto._symbol_ == "zm"); static_assert(si::atto._symbol_ == "am"); static_assert(si::femto._symbol_ == "fm"); static_assert(si::pico._symbol_ == "pm"); static_assert(si::nano._symbol_ == "nm"); static_assert(si::micro._symbol_ == symbol_text{u8"µm", "um"}); static_assert(si::milli._symbol_ == "mm"); static_assert(si::centi._symbol_ == "cm"); static_assert(si::deci._symbol_ == "dm"); static_assert(si::deca._symbol_ == "dam"); static_assert(si::hecto._symbol_ == "hm"); static_assert(si::kilo._symbol_ == "km"); static_assert(si::mega._symbol_ == "Mm"); static_assert(si::giga._symbol_ == "Gm"); static_assert(si::tera._symbol_ == "Tm"); static_assert(si::peta._symbol_ == "Pm"); static_assert(si::exa._symbol_ == "Em"); static_assert(si::zetta._symbol_ == "Zm"); static_assert(si::yotta._symbol_ == "Ym"); static_assert(si::ronna._symbol_ == "Rm"); static_assert(si::quetta._symbol_ == "Qm"); // scaled_unit constexpr auto m_1 = mag<1> * metre; static_assert(is_of_type); static_assert(is_of_type); static_assert(get_canonical_unit(m_1).mag == mag<1>); constexpr auto m_2 = mag<2> * metre; static_assert(is_of_type, metre_>>); static_assert(is_of_type); static_assert(get_canonical_unit(m_2).mag == mag<2>); constexpr auto m_3 = mag_ratio<1, 2> * m_2; static_assert(is_of_type); static_assert(is_of_type); static_assert(get_canonical_unit(m_3).mag == mag<1>); constexpr auto m_4 = mag_ratio<1, 2> * (mag<4> * metre); static_assert(is_of_type, metre_>>); static_assert(is_of_type); static_assert(get_canonical_unit(m_4).mag == mag<2>); constexpr auto km_2 = mag<2> * kilometre; static_assert(is_of_type, kilo_>>); static_assert(is_of_type); static_assert(get_canonical_unit(km_2).mag == mag<2000>); constexpr auto kJ_42 = mag<42> * kilo; static_assert(is_of_type, kilo_>>); static_assert( is_of_type, per>>>); static_assert(get_canonical_unit(kJ_42).mag == mag<42'000'000>); // derived unit expression template syntax verification static_assert(is_of_type>>); static_assert(is_of_type); static_assert(is_of_type); static_assert(is_of_type); static_assert(is_of_type>>); static_assert(is_of_type>>); static_assert(is_of_type>); static_assert(is_of_type>>); static_assert(is_of_type>>); static_assert(is_of_type>>); static_assert(is_of_type>>); static_assert(is_of_type>>); static_assert(is_of_type); static_assert(is_of_type>>); static_assert(is_of_type); static_assert(is_of_type>>); static_assert(is_of_type>>>); static_assert(is_of_type>>>); static_assert(is_of_type, second_>>); static_assert(is_of_type, second_>>); static_assert(is_of_type, second_>>); static_assert(is_of_type, second_>>); static_assert(is_of_type>>); static_assert(is_of_type); static_assert(is_of_type); static_assert(is_of_type>>); static_assert(is_of_type); static_assert(is_of_type>>>); static_assert(is_of_type>>>); static_assert(is_of_type>>); static_assert(is_of_type>>>); static_assert(is_of_type, per>>>); static_assert(is_of_type); static_assert(is_of_type>>); static_assert(is_of_type>>); static_assert(is_of_type>>); static_assert(is_of_type); static_assert(is_of_type); static_assert(is_of_type>>); static_assert(is_of_type, per>>); static_assert( is_of_type, per>>); static_assert(is_of_type, per>>); static_assert(is_of_type, per>>); static_assert(is_of_type<(metre * square(second) / gram) * one, derived_unit, per>>); static_assert(is_of_type, per>>); static_assert(is_of_type>); static_assert(is_of_type>); static_assert(is_of_type>>); static_assert(is_of_type>>); static_assert(is_of_type); static_assert(is_of_type>); static_assert(is_of_type>); static_assert(is_same_v); static_assert(is_same_v); static_assert(is_same_v); static_assert(is_same_v); static_assert(is_same_v); // derived unit normalization constexpr auto m_per_s = metre / second; static_assert(is_of_type>>); static_assert(get_canonical_unit(m_per_s).mag == mag<1>); constexpr auto km_per_s = kilometre / second; static_assert(is_of_type, per>>); static_assert(is_of_type>>); static_assert(get_canonical_unit(km_per_s).mag == mag<1000>); constexpr auto km_per_h = kilometre / hour; static_assert(is_of_type, per>>); static_assert(is_of_type>>); static_assert(get_canonical_unit(km_per_h).mag == mag_ratio<1000, 3600>); static_assert(is_of_type>>); static_assert(is_of_type); static_assert( is_of_type>>>); static_assert( is_of_type, per>>); static_assert( is_of_type>>>); static_assert(get_canonical_unit(standard_gravity).mag == mag_ratio<980'665, 100'000>); static_assert(is_of_type>>>); static_assert(is_of_type>>); // operations commutativity constexpr auto u1 = mag<1000> * kilometre / hour; static_assert(is_of_type, kilo_>, per>>); static_assert(is_of_type>>); static_assert(get_canonical_unit(u1).mag == mag_ratio<1'000'000, 3'600>); constexpr auto u2 = mag<1000> * (kilometre / hour); static_assert(is_of_type, derived_unit, per>>>); static_assert(is_of_type>>); static_assert(get_canonical_unit(u2).mag == mag_ratio<1'000'000, 3'600>); constexpr auto u3 = one / hour * (mag<1000> * kilometre); static_assert(is_of_type, kilo_>, per>>); static_assert(is_of_type>>); static_assert(get_canonical_unit(u3).mag == mag_ratio<1'000'000, 3'600>); template concept invalid_operations = requires { requires !requires { s < s; }; requires !requires { s / 2; }; requires !requires { s * 2; }; requires !requires { s + 2; }; requires !requires { 2 + s; }; requires !requires { s + s; }; requires !requires { s - 2; }; requires !requires { 2 - s; }; requires !requires { s - s; }; requires !requires { s == 2; }; requires !requires { 2 == s; }; requires !requires { s < 2; }; requires !requires { 2 < s; }; requires !requires { s + isq::duration[second]; }; requires !requires { s - isq::duration[second]; }; requires !requires { s < isq::duration[second]; }; requires !requires { isq::duration[second] + s; }; requires !requires { isq::duration[second] - s; }; requires !requires { s + 1 * isq::duration[second]; }; requires !requires { s - 1 * isq::duration[second]; }; requires !requires { s * 1 * isq::duration[second]; }; requires !requires { s / 1 * isq::duration[second]; }; requires !requires { s == 1 * isq::duration[second]; }; requires !requires { s == 1 * isq::duration[second]; }; requires !requires { 1 * isq::duration[second] + s; }; requires !requires { 1 * isq::duration[second] - s; }; requires !requires { 1 * isq::duration[second] == s; }; requires !requires { 1 * isq::duration[second] < s; }; }; static_assert(invalid_operations); // comparisons of the same units static_assert(second == second); static_assert(metre / second == metre / second); static_assert(milli / milli != si::micro / si::micro); static_assert(equivalent(milli / milli, si::micro / si::micro)); static_assert(milli / si::micro != si::micro / si::nano); static_assert(equivalent(milli / si::micro, si::micro / si::nano)); static_assert(si::micro / milli != si::nano / si::micro); static_assert(equivalent(si::micro / milli, si::nano / si::micro)); static_assert(milli * kilo != si::deci * si::deca); static_assert(equivalent(milli * kilo, si::deci* si::deca)); static_assert(kilo * milli != si::deca * si::deci); static_assert(equivalent(kilo * milli, si::deca* si::deci)); // comparisons of equivalent units (named vs unnamed/derived) static_assert(one / second != hertz); static_assert(equivalent(one / second, hertz)); // comparisons of equivalent units of different quantities static_assert(hertz != becquerel); // comparisons of scaled units static_assert(kilo == kilometre); static_assert(mag<1000> * metre != kilo); static_assert(equivalent(mag<1000> * metre, kilo)); static_assert(mag<1000> * metre != kilometre); static_assert(equivalent(mag<1000> * metre, kilometre)); static_assert(mag<60> * metre / second != metre / (mag_ratio<1, 60> * second)); static_assert(equivalent(mag<60> * metre / second, metre / (mag_ratio<1, 60> * second))); // static_assert(mag * one * metre == mag * metre); // static_assert(mag * metre / (mag * one) == metre); // static_assert(mag * one / (mag * metre) == one / metre); static_assert(metre != kilometre); static_assert(mag<100> * metre != kilometre); static_assert(milli != kilometre); // comparisons of non-compatible units static_assert(metre != metre * metre); // one static_assert(is_of_type); static_assert(is_of_type / metre, derived_unit, per>>); static_assert(metre / metre == one); static_assert(hertz * second != one); static_assert(equivalent(hertz * second, one)); static_assert(one * one == one); static_assert(is_of_type); static_assert(one * percent == percent); static_assert(percent * one == percent); static_assert(is_of_type); static_assert(is_of_type); static_assert(hertz != one / second); static_assert(equivalent(hertz, one / second)); static_assert(newton != kilogram * metre / square(second)); static_assert(equivalent(newton, kilogram* metre / square(second))); static_assert(joule != kilogram * square(metre) / square(second)); static_assert(equivalent(joule, kilogram* square(metre) / square(second))); static_assert(joule != newton * metre); static_assert(equivalent(joule, newton* metre)); static_assert(watt != joule / second); static_assert(equivalent(watt, joule / second)); static_assert(watt != kilogram * square(metre) / cubic(second)); static_assert(equivalent(watt, kilogram* square(metre) / cubic(second))); // power static_assert(is_same_v(metre)), decltype(metre * metre)>); static_assert(is_same_v(kilometre)), decltype(kilometre * kilometre)>); static_assert(is_same_v(kilo)), decltype(kilo * kilo)>); static_assert(is_same_v(hour)), decltype(hour * hour)>); static_assert(is_same_v(mag<3600> * second)), decltype((mag<3600> * second) * (mag<3600> * second))>); static_assert(is_same_v(metre / second)), decltype(metre * metre / second / second)>); static_assert(is_same_v(kilometre / hour)), decltype(kilometre * kilometre / hour / hour)>); static_assert(is_of_type(metre), one_>); static_assert(is_of_type(metre), metre_>); static_assert(is_of_type(metre), metre_>); static_assert(is_of_type(one), one_>); static_assert(is_of_type(percent), derived_unit>>); static_assert(is_of_type(radian), derived_unit>>); static_assert(is_of_type(metre), derived_unit>>); static_assert(is_of_type(metre), derived_unit>>); static_assert(is_of_type(metre* metre), metre_>); static_assert(is_of_type(metre* metre* metre), metre_>); static_assert(is_of_type(metre* metre), derived_unit>>); static_assert(is_of_type(metre / second), derived_unit, per>>>); static_assert(is_of_type(metre / (second * second)), derived_unit, per>>); static_assert(is_of_type, 2>>>); static_assert(is_of_type(kilometre), derived_unit, 2>>>); static_assert(is_of_type(kilo), derived_unit, 2>>>); static_assert(is_of_type(hour), derived_unit>>); static_assert(is_of_type(mag<3600>* second), derived_unit, second_>, 2>>>); // get_common_unit static_assert(is_of_type); static_assert(is_of_type>); static_assert(is_of_type, kilogram), kilo_>); static_assert(is_of_type), kilo_>); static_assert(is_of_type* gram, kilogram), kilo_>); static_assert(is_of_type* gram), kilo_>); static_assert(is_of_type); static_assert(is_of_type); static_assert(is_of_type); static_assert(is_of_type); static_assert(is_of_type); static_assert(is_of_type); static_assert(is_of_type); static_assert(is_of_type); static_assert(is_of_type, milli), milli_>); static_assert(is_of_type, kilo), milli_>); static_assert(is_of_type); static_assert(is_of_type); static_assert( is_of_type>>); static_assert(is_of_type); static_assert(is_of_type); template concept no_common_unit = requires { requires !requires { get_common_unit(u, one); }; }; static_assert(no_common_unit); // those should return instantiations of the `common_unit` class template static_assert(is_of_type, mile_>>); static_assert(is_of_type, mile_>>); static_assert(is_of_type>); static_assert(is_of_type>); static_assert(is_of_type>); static_assert( is_of_type>); static_assert(is_of_type* degree_Celsius, si::milli)), decltype(get_common_unit(degree_Fahrenheit, si::milli))>); static_assert( is_of_type, mile_>, per>>); static_assert( is_of_type, mile_, nautical_mile_>>); static_assert( is_of_type, mile_, nautical_mile_>>); static_assert( is_of_type, mile_, nautical_mile_>>); static_assert(is_of_type, mile_, nautical_mile_>>); static_assert(is_of_type, mile_, nautical_mile_>>); static_assert(is_of_type, mile_, nautical_mile_>>); static_assert(is_of_type, mile_>>); static_assert(is_of_type, mile_>>); static_assert(is_of_type, mile_>>); static_assert(is_of_type, mile_>>); static_assert(is_of_type, mile_>>); static_assert( is_of_type, mile_>>); static_assert(is_of_type>); static_assert(is_of_type), milli_>); // check underlying types static_assert(std::derived_from, derived_unit>>>); static_assert(std::derived_from, derived_unit>>>); static_assert( std::derived_from, metre_>>); static_assert( std::derived_from, metre_>>); static_assert(std::derived_from)), detail::scaled_unit_impl, metre_>>); } // namespace