// 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 #include namespace { using namespace units; using namespace units::detail; template inline constexpr bool is_of_type = std::is_same_v, T>; using one_ = struct one; // clang-format off // base units inline constexpr struct second_ : named_unit<"s"> {} second; inline constexpr struct metre_ : named_unit<"m"> {} metre; inline constexpr struct gram_ : named_unit<"g"> {} gram; inline constexpr struct kilogram_ : decltype(si::kilo) {} kilogram; inline constexpr struct kelvin_ : named_unit<"K"> {} kelvin; // derived named units inline constexpr struct radian_ : named_unit<"rad", metre / metre> {} radian; inline constexpr struct steradian_ : named_unit<"sr", square / square> {} steradian; inline constexpr struct hertz_ : named_unit<"Hz", 1 / second> {} hertz; inline constexpr struct becquerel_ : named_unit<"Bq", 1 / second> {} becquerel; inline constexpr struct newton_ : named_unit<"N", kilogram * metre / square> {} newton; inline constexpr struct pascal_ : named_unit<"Pa", newton / square> {} pascal; inline constexpr struct joule_ : named_unit<"J", newton * metre> {} joule; inline constexpr struct watt_ : named_unit<"W", joule / second> {} watt; inline constexpr struct degree_Celsius_ : named_unit {} degree_Celsius; inline constexpr struct minute_ : named_unit<"min", mag<60> * second> {} minute; inline constexpr struct hour_ : named_unit<"h", mag<60> * minute> {} hour; inline constexpr struct day_ : named_unit<"d", mag<24> * hour> {} day; inline constexpr struct astronomical_unit_ : named_unit<"au", mag<149'597'870'700> * metre> {} astronomical_unit; inline constexpr struct degree_ : named_unit * radian> {} degree; inline constexpr struct are_ : named_unit<"a", square>> {} are; inline constexpr struct hectare_ : decltype(si::hecto) {} hectare; inline constexpr struct litre_ : named_unit<"l", cubic>> {} litre; inline constexpr struct tonne_ : named_unit<"t", mag<1000> * kilogram> {} tonne; inline constexpr struct dalton_ : named_unit<"Da", mag * mag_power<10, -27> * kilogram> {} dalton; inline constexpr struct electronvolt_ : named_unit<"eV", mag * mag_power<10, -19> * joule> {} electronvolt; inline constexpr struct kilometre_ : decltype(si::kilo) {} kilometre; inline constexpr struct kilojoule_ : decltype(si::kilo) {} kilojoule; // 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 * second)>); static_assert(Unit); static_assert(NamedUnit); static_assert(NamedUnit); static_assert(NamedUnit); static_assert(NamedUnit); static_assert(NamedUnit); static_assert(!NamedUnit); static_assert(!NamedUnit); static_assert(!NamedUnit); static_assert(!NamedUnit)>); static_assert(!NamedUnit)>); static_assert(!NamedUnit)>); static_assert(!NamedUnit * second)>); static_assert(!NamedUnit); // named unit static_assert(is_of_type); static_assert(is_of_type); static_assert(get_canonical_unit(metre).mag == mag<1>); static_assert(convertible(metre, metre)); static_assert(!convertible(metre, second)); 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(convertible(degree_Celsius, kelvin)); static_assert(degree_Celsius == kelvin); static_assert(is_of_type); static_assert(is_of_type); static_assert(get_canonical_unit(radian).mag == mag<1>); static_assert(convertible(minute, second)); static_assert(minute != second); static_assert(is_of_type); static_assert(is_of_type); static_assert(get_canonical_unit(steradian).mag == mag<1>); static_assert(convertible(radian, steradian)); // !!! 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(convertible(minute, second)); 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(convertible(hour, second)); static_assert(convertible(hour, minute)); static_assert(convertible(hour, hour)); 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(convertible(newton, newton)); 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(convertible(joule, joule)); static_assert(joule == joule); static_assert(joule != newton); // prefixed_unit static_assert(is_of_type); static_assert(is_of_type); static_assert(get_canonical_unit(kilometre).mag == mag<1000>); static_assert(convertible(kilometre, metre)); 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(convertible(kilojoule, joule)); static_assert(kilojoule != joule); static_assert(kilojoule.symbol == "kJ"); static_assert(is_of_type, si::kilo_>); static_assert(is_of_type, si::kilo_>); // prefixes 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 == basic_symbol_text{"µ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"); // 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 km_2 = mag<2> * kilometre; static_assert(is_of_type, kilometre_>>); static_assert(is_of_type); static_assert(get_canonical_unit(km_2).mag == mag<2000>); constexpr auto kJ_42 = mag<42> * si::kilo; static_assert(is_of_type, si::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<1 / second, derived_unit>>); static_assert(is_of_type<1 / (1 / second), second_>); static_assert(is_of_type); static_assert(is_of_type); static_assert(is_of_type>>); static_assert(is_of_type<1 / second * one, derived_unit>>); static_assert(is_of_type>); static_assert(is_of_type>>); static_assert(is_of_type, derived_unit>>); static_assert(is_of_type, derived_unit>>); static_assert(is_of_type * metre, derived_unit>>); static_assert(is_of_type, derived_unit>>); static_assert(is_of_type>>); static_assert(is_of_type, derived_unit>>>); static_assert(is_of_type / second, derived_unit>>>); 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<1 / second * metre, derived_unit>>); static_assert(is_of_type<1 / second * second, one_>); static_assert(is_of_type); static_assert(is_of_type<1 / second / one, derived_unit>>); static_assert(is_of_type); static_assert(is_of_type<1 / second * (1 / second), derived_unit>>>); static_assert(is_of_type<1 / (second * second), derived_unit>>>); static_assert(is_of_type<1 / (1 / (second * second)), derived_unit>>); 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(std::is_same_v); static_assert(std::is_same_v); static_assert(std::is_same_v); static_assert(std::is_same_v); static_assert(std::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>>); 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>>); static_assert(is_of_type>>); static_assert(get_canonical_unit(km_per_h).mag == mag); // operations commutativity constexpr auto u1 = mag<1000> * kilometre / hour; static_assert(is_of_type, derived_unit>>>); static_assert(is_of_type>>); static_assert(get_canonical_unit(u1).mag == mag); constexpr auto u2 = mag<1000> * (kilometre / hour); static_assert(is_of_type, derived_unit>>>); static_assert(is_of_type>>); static_assert(get_canonical_unit(u2).mag == mag); constexpr auto u3 = 1 / hour * (mag<1000> * kilometre); static_assert(is_of_type, derived_unit>>>); static_assert(is_of_type>>); static_assert(get_canonical_unit(u3).mag == mag); // comparisons of the same units static_assert(second == second); static_assert(metre / second == metre / second); static_assert(si::milli / si::milli == si::micro / si::micro); static_assert(si::milli / si::micro == si::micro / si::nano); static_assert(si::micro / si::milli == si::nano / si::micro); static_assert(si::milli * si::kilo == si::deci * si::deca); static_assert(si::kilo * si::milli == si::deca * si::deci); // comparisons of equivalent units (named vs unnamed/derived) static_assert(1 / second == hertz); static_assert(convertible(1 / second, hertz)); // comparisons of equivalent units of different quantities static_assert(hertz == becquerel); static_assert(convertible(hertz, becquerel)); // comparisons of scaled units static_assert(si::kilo == kilometre); static_assert(mag<1000> * metre == si::kilo); static_assert(mag<1000> * metre == kilometre); static_assert(convertible(si::kilo, kilometre)); static_assert(convertible(mag<1000> * metre, si::kilo)); static_assert(convertible(mag<1000> * metre, kilometre)); static_assert(metre != kilometre); static_assert(convertible(metre, kilometre)); static_assert(mag<100> * metre != kilometre); static_assert(convertible(mag<100> * metre, kilometre)); static_assert(si::milli != kilometre); static_assert(convertible(si::milli, kilometre)); // comparisons of non-convertible units static_assert(metre != metre * metre); static_assert(!convertible(metre, metre* metre)); // one static_assert(is_of_type); static_assert(metre / metre == one); static_assert(hertz * second == one); static_assert(hertz == 1 / second); static_assert(newton == kilogram * metre / square); static_assert(joule == kilogram * square / square); static_assert(joule == newton * metre); static_assert(watt == joule / second); static_assert(watt == kilogram * square / cubic); // static_assert(centimetre::symbol == "cm"); // static_assert(kilometre::symbol == "km"); // static_assert(kilometre_per_hour::symbol == "km/h"); } // namespace