// 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 #include #include namespace { using namespace units; using namespace units::detail; using dimension_one_ = struct dimension_one; using one_ = struct one; // base dimensions BASE_DIMENSION_(length, "L"); BASE_DIMENSION_(time, "T"); BASE_DIMENSION_(mass, "M"); DERIVED_DIMENSION_(frequency, decltype(1 / time)); DERIVED_DIMENSION_(action, decltype(1 / time)); DERIVED_DIMENSION_(area, decltype(length * length)); DERIVED_DIMENSION_(volume, decltype(area * length)); DERIVED_DIMENSION_(speed, decltype(length / time)); DERIVED_DIMENSION_(acceleration, decltype(speed / time)); DERIVED_DIMENSION_(force, decltype(mass * acceleration)); DERIVED_DIMENSION_(moment_of_force, decltype(length * force)); DERIVED_DIMENSION_(torque, decltype(moment_of_force)); DERIVED_DIMENSION_(power, decltype(force * speed)); DERIVED_DIMENSION_(efficiency, decltype(power / power)); DERIVED_DIMENSION_(energy, decltype(force * length)); // clang-format off // base units inline constexpr struct second_ : named_unit<"s", time> {} second; inline constexpr struct metre_ : named_unit<"m", length> {} metre; inline constexpr struct gram_ : named_unit<"g", mass> {} gram; inline constexpr struct kilogram_ : decltype(si::kilo) {} kilogram; namespace nu { // hypothetical natural system of units for c=1 inline constexpr struct second_ : named_unit<"s"> {} second; inline constexpr struct minute_ : named_unit<"min", mag<60> * second> {} minute; inline constexpr struct gram_ : named_unit<"g"> {} gram; inline constexpr struct kilogram_ : decltype(si::kilo) {} kilogram; inline constexpr struct time : system_reference {} time; inline constexpr struct length : system_reference {} length; inline constexpr struct speed : system_reference {} speed; inline constexpr struct force : system_reference {} force; } // 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 minute_ : named_unit<"min", mag<60> * second> {} minute; inline constexpr struct hour_ : named_unit<"h", mag<60> * minute> {} hour; inline constexpr struct kilometre_ : decltype(si::kilo) {} kilometre; // clang-format on // Named quantity/dimension and unit static_assert(is_same_v{}, int>>); // Named quantity/dimension and derived (unnamed) unit static_assert(is_same_v>{}>{}, int>>); // Derived (unnamed) quantity/dimension and derived (unnamed) unit static_assert( is_same_v< decltype(10 * length[metre] / (2 * time[second])), quantity>{}, derived_unit>{}>{}, int>>); // Base quantity as a result of dimensional transformation static_assert( is_same_v{}, int>>); // dimension_one static_assert(is_same_v{}, int>>); template concept invalid_operations = requires { requires !requires { 2 / 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 == s; }; requires !requires { s < s; }; requires !requires { s + 1 * time[second]; }; requires !requires { s - 1 * time[second]; }; requires !requires { s * 1 * time[second]; }; requires !requires { s / 1 * time[second]; }; requires !requires { s == 1 * time[second]; }; requires !requires { s < 1 * time[second]; }; requires !requires { 1 * time[second] + s; }; requires !requires { 1 * time[second] - s; }; requires !requires { 1 * time[second] * s; }; requires !requires { 1 * time[second] / s; }; requires !requires { 1 * time[second] == s; }; requires !requires { 1 * time[second] < s; }; }; static_assert(invalid_operations); static_assert( is_same_v< decltype(2 * length[metre] / (1 * time[second])), quantity>{}, derived_unit>{}>{}, int>>); static_assert( is_same_v< decltype(2 * (length[metre] / time[second])), quantity>{}, derived_unit>{}>{}, int>>); static_assert(is_same_v>{}>{}, int>>); constexpr auto m_per_s = speed[metre / second]; static_assert( is_same_v>{}>{}, int>>); static_assert( is_same_v< decltype(120 * length[kilometre] / (2 * time[hour])), quantity>{}, derived_unit>{}>{}, int>>); static_assert(120 * length[kilometre] / (2 * time[hour]) == 60 * speed[kilometre / hour]); static_assert( is_same_v< decltype([] { const auto distance = 120; const auto duration = 2; return distance * length[kilometre] / (duration * time[hour]); }()), quantity>{}, derived_unit>{}>{}, int>>); static_assert( is_same_v>{}, derived_unit>{}>{}, std::int64_t>>); static_assert( is_same_v>{}, derived_unit>{}>{}, long double>>); static_assert(is_same_v]), decltype(1. * area[square] / 4)>); static_assert(1. / 4 * area[square] == 1. * area[square] / 4); // Natural Units static_assert(is_same_v{}, int>>); static_assert(is_same_v{}, int>>); static_assert(is_same_v{}, int>>); static_assert(is_same_v{}, int>>); static_assert(is_same_v>{}, one>{}, int>>); static_assert(is_same_v>{}, one>{}, int>>); static_assert(is_same_v{}, int>>); static_assert(is_same_v{}, int>>); static_assert(is_same_v>{}, kilogram>{}, int>>); template concept invalid_nu_unit = !requires { dim[unit]; }; static_assert(invalid_nu_unit); static_assert(invalid_nu_unit); static_assert(invalid_nu_unit); static_assert(invalid_nu_unit); static_assert(invalid_nu_unit); static_assert(invalid_nu_unit); static_assert(invalid_nu_unit); } // namespace