// 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); template constexpr bool print(); // 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 u1 = mag<1> * metre; static_assert(is_of_type, metre_>>); static_assert(is_of_type); static_assert(get_canonical_unit(u1).mag == mag<1>); constexpr auto u2 = mag<2> * kilometre; static_assert(is_of_type, kilometre_>>); static_assert(is_of_type); static_assert(get_canonical_unit(u2).mag == mag<2000>); constexpr auto u3 = mag<42> * si::kilo; static_assert(is_of_type, si::kilo_>>); static_assert( is_of_type, per>>>); static_assert(get_canonical_unit(u3).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, 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>>); // derived unit normalization constexpr auto u4 = metre / second; static_assert(is_of_type>>); static_assert(get_canonical_unit(u4).mag == mag<1>); constexpr auto u5 = kilometre / second; static_assert(is_of_type>>); static_assert(is_of_type>>); static_assert(get_canonical_unit(u5).mag == mag<1000>); constexpr auto u6 = kilometre / hour; static_assert(is_of_type>>); static_assert(is_of_type>>); static_assert(get_canonical_unit(u6).mag == mag); constexpr auto u7 = mag<1000> * kilometre / hour; static_assert(is_of_type, kilometre_>, per>>); static_assert(is_of_type>>); static_assert(get_canonical_unit(u7).mag == mag); constexpr auto u8 = mag<1000> * (kilometre / hour); static_assert(is_of_type, derived_unit>>>); static_assert(is_of_type>>); static_assert(get_canonical_unit(u8).mag == mag); constexpr auto u9 = 1 / hour * (mag<1000> * kilometre); static_assert(is_of_type, kilometre_>, per>>); static_assert(is_of_type>>); static_assert(get_canonical_unit(u9).mag == mag); // comparisons of the same units static_assert(second == second); static_assert(metre / second == metre / second); // 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)); // one static_assert(metre / metre == one); // static_assert(metre * metre == square_metre); // static_assert(second * second == second_squared); // static_assert(second * second * second == second_cubed); // static_assert(second * (second * second) == second_cubed); // static_assert(second_squared * second == second_cubed); // static_assert(second * second_squared == second_cubed); // static_assert(1 / second * metre == metre / second); // static_assert(metre * (1 / second) == metre / second); // static_assert((metre / second) * (1 / second) == metre / second / second); // static_assert((metre / second) * (1 / second) == metre / (second * second)); // static_assert((metre / second) * (1 / second) == metre / second_squared); // static_assert(hertz == 1 / second); // static_assert(newton == kilogram * metre / second_squared); // static_assert(joule == kilogram * square_metre / second_squared); // static_assert(joule == newton * metre); // static_assert(watt == joule / second); // static_assert(watt == kilogram * square_metre / second_cubed); // static_assert(1 / frequency_dim == second); // static_assert(frequency_dim * second == one); // static_assert(metre * metre == area_dim); // static_assert(metre * metre != volume_dim); // static_assert(area_dim / metre == metre); // static_assert(metre * metre * metre == volume_dim); // static_assert(area_dim * metre == volume_dim); // static_assert(volume_dim / metre == area_dim); // static_assert(volume_dim / metre / metre == metre); // static_assert(area_dim * area_dim / metre == volume_dim); // static_assert(area_dim * (area_dim / metre) == volume_dim); // static_assert(volume_dim / (metre * metre) == metre); // static_assert(metre / second == speed_dim); // static_assert(metre * second != speed_dim); // static_assert(metre / second / second != speed_dim); // static_assert(metre / speed_dim == second); // static_assert(speed_dim * second == metre); // static_assert(metre / second / second == acceleration_dim); // static_assert(metre / (second * second) == acceleration_dim); // static_assert(speed_dim / second == acceleration_dim); // static_assert(speed_dim / acceleration_dim == second); // static_assert(acceleration_dim * second == speed_dim); // static_assert(acceleration_dim * (second * second) == metre); // static_assert(acceleration_dim / speed_dim == frequency_dim); // milli / milli == micro / micro; // milli * kilo == deci * deca; // Bq + Hz should not compile // Bq + Hz + 1/s should compile? // using namespace units; // 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 dim_length : base_dimension<"length", metre> {}; // struct second : named_unit {}; // struct hour : named_scaled_unit(), second> {}; // struct dim_time : base_dimension<"time", second> {}; // struct kelvin : named_unit {}; // #if !UNITS_COMP_MSVC // static_assert([](P) { // return !requires { typename prefixed_unit; }; // }(si::kilo{})); // no prefix allowed // #endif // struct metre_per_second : derived_unit {}; // struct dim_speed : // derived_dimension, units::exponent> {}; // struct kilometre_per_hour : derived_scaled_unit {}; // static_assert(equivalent); // static_assert(equivalent); // static_assert(compare(), metre>>, metre>); // static_assert(compare(), metre>>, centimetre>); // static_assert(compare>, yard>); // static_assert(compare(), metre>>, foot>); // static_assert(compare>, kilometre_per_hour>); // static_assert(centimetre::symbol == "cm"); // static_assert(kilometre::symbol == "km"); // static_assert(kilometre_per_hour::symbol == "km/h"); // static_assert(si::metre != si::kilometre); // static_assert(!equivalent(si::metre, si::kilometre)); // static_assert(convertible(si::metre, si::kilometre)); } // namespace