forked from mpusz/mp-units
feat: common_unit support added
This commit is contained in:
@@ -260,3 +260,31 @@ This is why we provide both versions of identifiers for such units.
|
||||
quantity resistance = 60 * kΩ;
|
||||
quantity capacitance = 100 * µF;
|
||||
```
|
||||
|
||||
|
||||
## Common units
|
||||
|
||||
Adding or subtracting two quantities of different units will force the library to find a common
|
||||
unit for those. This is to prevent data truncation. For the cases when one of the units is an
|
||||
integral multiple of the another, the resulting quantity will use a "smaller" one in its result.
|
||||
For example:
|
||||
|
||||
```cpp
|
||||
static_assert((1 * kg + 1 * g).unit == g);
|
||||
static_assert((1 * km + 1 * mm).unit == mm);
|
||||
static_assert((1 * yd + 1 * mi).unit == yd);
|
||||
```
|
||||
|
||||
However, in many cases an arithmetic on quantities of different units will result in a yet another
|
||||
unit. This happens when none of the source units is an integral multiple of another. In such cases,
|
||||
the library returns a special type that denotes that we are dealing with a common unit of such
|
||||
an equation:
|
||||
|
||||
```cpp
|
||||
quantity q = 1 * km + 1 * mi; // quantity<common_unit<international::mile, si::kilo_<si::metre>>{}, int>
|
||||
```
|
||||
|
||||
!!! note
|
||||
|
||||
A user should never explicitly instantiate a `common_unit` class template. The library's
|
||||
framework will do it based on the provided quantity equation.
|
||||
|
||||
@@ -268,6 +268,31 @@ The above prints:
|
||||
kg⋅m⋅s⁻²
|
||||
```
|
||||
|
||||
## Symbols of common units
|
||||
|
||||
Some [common units](systems_of_units.md#common-units) expressed with a specialization of the
|
||||
`common_unit` class template need special printing rules for their symbols. As they represent
|
||||
a minimum set of common units resulting from the addition or subtraction of multiple quantities,
|
||||
we print all of them as a scaled version of the source unit. For example the following:
|
||||
|
||||
```cpp
|
||||
std::cout << 1 * km + 1 * mi << "\n";
|
||||
std::cout << 1 * nmi + 1 * mi << "\n";
|
||||
std::cout << 1 * km / h + 1 * m / s << "\n";
|
||||
```
|
||||
|
||||
will print:
|
||||
|
||||
```text
|
||||
40771 ([1/25146] mi = [1/15625] km)
|
||||
108167 ([1/50292] mi = [1/57875] nmi)
|
||||
23 ([1/5] km/h = [1/18] m/s)
|
||||
```
|
||||
|
||||
Thanks to the above, it might be easier for the user to reason about the magnitude of the resulting
|
||||
unit and its impact on the value stored in the quantity.
|
||||
|
||||
|
||||
## `space_before_unit_symbol` customization point
|
||||
|
||||
The [SI Brochure](../../appendix/references.md#SIBrochure) says:
|
||||
|
||||
@@ -50,6 +50,7 @@ import std;
|
||||
#include <cstdint>
|
||||
#include <iterator>
|
||||
#include <string_view>
|
||||
#include <tuple>
|
||||
#if MP_UNITS_HOSTED
|
||||
#include <string>
|
||||
#endif
|
||||
@@ -404,6 +405,46 @@ struct prefixed_unit : decltype(M * U)::_base_type_ {
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<Unit U1, Unit U2>
|
||||
requires(convertible(U1{}, U2{}))
|
||||
[[nodiscard]] consteval Unit auto get_common_scaled_unit(U1, U2)
|
||||
{
|
||||
constexpr auto canonical_lhs = get_canonical_unit(U1{});
|
||||
constexpr auto canonical_rhs = get_canonical_unit(U2{});
|
||||
constexpr auto common_magnitude = _common_magnitude(canonical_lhs.mag, canonical_rhs.mag);
|
||||
return scaled_unit<common_magnitude, decltype(canonical_lhs.reference_unit)>{};
|
||||
}
|
||||
|
||||
[[nodiscard]] consteval Unit auto get_common_scaled_unit(Unit auto u1, Unit auto u2, Unit auto u3, Unit auto... rest)
|
||||
requires requires { get_common_scaled_unit(get_common_scaled_unit(u1, u2), u3, rest...); }
|
||||
{
|
||||
return get_common_scaled_unit(get_common_scaled_unit(u1, u2), u3, rest...);
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/**
|
||||
* @brief Measurement unit for an accumulation of two quantities of different units
|
||||
*
|
||||
* While adding two quantities of different units we can often identify which of those unit should be used
|
||||
* to prevent data truncation. For example, adding `1 * m + 1 * mm` will end up in a quantity expressed in
|
||||
* millimeters. However, for some cases this is not possible. Choosing any of the units from the arguments
|
||||
* of the addition would result in a data truncation. For example, a common unit for `1 * km + 1 * mi` is
|
||||
* `[8/125] m`. Instead of returning such a complex unit type the library will return a `common_unit<mi, km>`.
|
||||
* This type is convertible to both `mi` and `km` without risking data truncation, but is not equal to any
|
||||
* of them.
|
||||
*
|
||||
* @note User should not instantiate this type! It is not exported from the C++ module. The library will
|
||||
* instantiate this type automatically based on the unit arithmetic equation provided by the user.
|
||||
*/
|
||||
template<Unit U1, Unit U2, Unit... Rest>
|
||||
struct common_unit final : decltype(detail::get_common_scaled_unit(U1{}, U2{}, Rest{}...))::_base_type_
|
||||
{
|
||||
using _base_type_ = common_unit; // exposition only
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<typename T>
|
||||
struct is_one : std::false_type {};
|
||||
|
||||
@@ -648,12 +689,62 @@ template<Unit U1, Unit U2>
|
||||
else if constexpr (is_integral(canonical_rhs.mag / canonical_lhs.mag))
|
||||
return u1;
|
||||
else {
|
||||
constexpr auto common_magnitude = _common_magnitude(canonical_lhs.mag, canonical_rhs.mag);
|
||||
return scaled_unit<common_magnitude, decltype(canonical_lhs.reference_unit)>{};
|
||||
if constexpr (detail::unit_less<U1, U2>::value)
|
||||
return common_unit<U1, U2>{};
|
||||
else
|
||||
return common_unit<U2, U1>{};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<TypeList List, Unit NewUnit, bool Included, Unit... Us>
|
||||
struct collapse_common_unit_impl;
|
||||
|
||||
template<TypeList List, Unit NewUnit, bool Included, Unit Front, Unit... Rest>
|
||||
struct collapse_common_unit_impl<List, NewUnit, Included, Front, Rest...> {
|
||||
using cu = decltype(get_common_unit(NewUnit{}, Front{}));
|
||||
using type =
|
||||
conditional<is_specialization_of<cu, common_unit>,
|
||||
typename collapse_common_unit_impl<type_list_push_back<List, Front>, NewUnit, Included, Rest...>::type,
|
||||
typename collapse_common_unit_impl<type_list_push_back<List, cu>, NewUnit, true, Rest...>::type>;
|
||||
};
|
||||
|
||||
template<TypeList List, Unit NewUnit>
|
||||
struct collapse_common_unit_impl<List, NewUnit, false> {
|
||||
using type = type_list_push_back<List, NewUnit>;
|
||||
};
|
||||
|
||||
template<TypeList List, Unit NewUnit>
|
||||
struct collapse_common_unit_impl<List, NewUnit, true> {
|
||||
using type = List;
|
||||
};
|
||||
|
||||
template<Unit NewUnit, Unit... Us>
|
||||
using collapse_common_unit = type_list_unique<
|
||||
type_list_sort<typename collapse_common_unit_impl<type_list<>, NewUnit, false, Us...>::type, type_list_of_unit_less>>;
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template<Unit... Us, Unit NewUnit>
|
||||
requires(convertible(common_unit<Us...>{}, NewUnit{}))
|
||||
[[nodiscard]] consteval Unit auto get_common_unit(common_unit<Us...>, NewUnit)
|
||||
{
|
||||
using type = detail::collapse_common_unit<NewUnit, Us...>;
|
||||
if constexpr (detail::type_list_size<type> == 1)
|
||||
return detail::type_list_front<type>{};
|
||||
else
|
||||
return detail::type_list_map<type, common_unit>{};
|
||||
}
|
||||
|
||||
template<Unit... Us, Unit NewUnit>
|
||||
requires(convertible(common_unit<Us...>{}, NewUnit{}))
|
||||
[[nodiscard]] consteval Unit auto get_common_unit(NewUnit nu, common_unit<Us...> cu)
|
||||
{
|
||||
return get_common_unit(cu, nu);
|
||||
}
|
||||
|
||||
[[nodiscard]] consteval Unit auto get_common_unit(Unit auto u1, Unit auto u2, Unit auto u3, Unit auto... rest)
|
||||
requires requires { get_common_unit(get_common_unit(u1, u2), u3, rest...); }
|
||||
{
|
||||
@@ -743,6 +834,33 @@ constexpr Out unit_symbol_impl(Out out, const scaled_unit_impl<M, U>& u, const u
|
||||
}
|
||||
}
|
||||
|
||||
template<typename... Us, Unit U>
|
||||
[[nodiscard]] consteval Unit auto get_common_unit_in(common_unit<Us...>, U u)
|
||||
{
|
||||
constexpr auto canonical_u = get_canonical_unit(u);
|
||||
constexpr Magnitude auto mag = common_unit<Us...>::mag / canonical_u.mag;
|
||||
return scaled_unit<mag, U>{};
|
||||
}
|
||||
|
||||
template<typename CharT, std::output_iterator<CharT> Out, typename U, typename... Rest>
|
||||
constexpr Out unit_symbol_impl(Out out, const common_unit<U, Rest...>&, const unit_symbol_formatting& fmt,
|
||||
bool negative_power)
|
||||
{
|
||||
constexpr std::string_view separator(" = ");
|
||||
auto print_unit = [&]<Unit Arg>(Arg) {
|
||||
constexpr auto u = get_common_unit_in(common_unit<U, Rest...>{}, Arg{});
|
||||
unit_symbol_impl<CharT>(out, u, fmt, negative_power);
|
||||
};
|
||||
*out++ = '(';
|
||||
print_unit(U{});
|
||||
for_each(std::tuple<Rest...>{}, [&]<Unit Arg>(Arg) {
|
||||
detail::copy(std::begin(separator), std::end(separator), out);
|
||||
print_unit(Arg{});
|
||||
});
|
||||
*out++ = ')';
|
||||
return out;
|
||||
}
|
||||
|
||||
template<typename CharT, std::output_iterator<CharT> Out, typename F, int Num, int... Den>
|
||||
constexpr auto unit_symbol_impl(Out out, const power<F, Num, Den...>&, const unit_symbol_formatting& fmt,
|
||||
bool negative_power)
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
|
||||
#include <mp-units/systems/iau.h>
|
||||
#include <mp-units/systems/iec.h>
|
||||
#include <mp-units/systems/international.h>
|
||||
#include <mp-units/systems/si.h>
|
||||
#ifdef MP_UNITS_IMPORT_STD
|
||||
import std;
|
||||
@@ -34,6 +35,7 @@ namespace {
|
||||
using namespace mp_units;
|
||||
using namespace mp_units::si;
|
||||
using namespace mp_units::iec;
|
||||
using namespace mp_units::international;
|
||||
|
||||
using enum text_encoding;
|
||||
using enum unit_symbol_solidus;
|
||||
@@ -114,6 +116,14 @@ static_assert(unit_symbol(mag<60> * second) == "[6 × 10¹] s");
|
||||
static_assert(unit_symbol<unit_symbol_formatting{.encoding = ascii}>(mag<60> * second) == "[6 x 10^1] s");
|
||||
static_assert(unit_symbol(mag_ratio<1, 18> * metre / second) == "[1/18] m/s");
|
||||
|
||||
// common units
|
||||
static_assert(unit_symbol(get_common_unit(kilo<metre>, mile)) == "([1/25146] mi = [1/15625] km)");
|
||||
static_assert(unit_symbol(get_common_unit(kilo<metre> / hour, metre / second)) == "([1/5] km/h = [1/18] m/s)");
|
||||
static_assert(unit_symbol(get_common_unit(kilo<metre> / hour, metre / second) / second) ==
|
||||
"([1/5] km/h = [1/18] m/s)/s");
|
||||
static_assert(unit_symbol(get_common_unit(kilo<metre> / hour, metre / second) * second) ==
|
||||
"([1/5] km/h = [1/18] m/s) s");
|
||||
|
||||
// derived units
|
||||
static_assert(unit_symbol(one) == ""); // NOLINT(readability-container-size-empty)
|
||||
static_assert(unit_symbol(percent) == "%");
|
||||
|
||||
+97
-48
@@ -51,11 +51,17 @@ QUANTITY_SPEC_(mass, dim_mass);
|
||||
QUANTITY_SPEC_(time, dim_time);
|
||||
QUANTITY_SPEC_(thermodynamic_temperature, dim_thermodynamic_temperature);
|
||||
|
||||
// prefixes
|
||||
template<PrefixableUnit U> struct milli_ final : prefixed_unit<"m", mag_power<10, -3>, U{}> {};
|
||||
template<PrefixableUnit U> struct kilo_ final : prefixed_unit<"k", mag_power<10, 3>, U{}> {};
|
||||
template<PrefixableUnit auto U> constexpr milli_<MP_UNITS_REMOVE_CONST(decltype(U))> milli;
|
||||
template<PrefixableUnit auto U> constexpr kilo_<MP_UNITS_REMOVE_CONST(decltype(U))> kilo;
|
||||
|
||||
// base units
|
||||
inline constexpr struct second_ final : named_unit<"s", kind_of<time>> {} second;
|
||||
inline constexpr struct metre_ final : named_unit<"m", kind_of<length>> {} metre;
|
||||
inline constexpr struct gram_ final : named_unit<"g", kind_of<mass>> {} gram;
|
||||
inline constexpr auto kilogram = si::kilo<gram>;
|
||||
inline constexpr auto kilogram = kilo<gram>;
|
||||
inline constexpr struct kelvin_ final : named_unit<"K", kind_of<thermodynamic_temperature>> {} kelvin;
|
||||
|
||||
// hypothetical natural units for c=1
|
||||
@@ -78,9 +84,10 @@ inline constexpr struct degree_ final : named_unit<symbol_text{u8"°", "deg"}, m
|
||||
|
||||
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 = si::kilo<metre>;
|
||||
inline constexpr auto kilojoule = si::kilo<joule>;
|
||||
inline constexpr auto kilometre = kilo<metre>;
|
||||
inline constexpr auto kilojoule = kilo<joule>;
|
||||
|
||||
// physical constant units
|
||||
inline constexpr struct standard_gravity_ final : named_unit<symbol_text{u8"g₀", "g_0"}, mag_ratio<980'665, 100'000> * metre / square(second)> {} standard_gravity;
|
||||
@@ -96,7 +103,7 @@ static_assert(Unit<decltype(kilogram)>);
|
||||
static_assert(Unit<hertz_>);
|
||||
static_assert(Unit<newton_>);
|
||||
static_assert(Unit<minute_>);
|
||||
static_assert(Unit<decltype(si::kilo<gram>)>);
|
||||
static_assert(Unit<decltype(kilo<gram>)>);
|
||||
static_assert(Unit<decltype(square(metre))>);
|
||||
static_assert(Unit<decltype(cubic(metre))>);
|
||||
static_assert(Unit<decltype(mag<60> * second)>);
|
||||
@@ -113,7 +120,7 @@ static_assert(PrefixableUnit<minute_>);
|
||||
static_assert(PrefixableUnit<radian_>);
|
||||
static_assert(!PrefixableUnit<decltype(kilogram)>);
|
||||
static_assert(!PrefixableUnit<decltype(kilojoule)>);
|
||||
static_assert(!PrefixableUnit<decltype(si::kilo<gram>)>);
|
||||
static_assert(!PrefixableUnit<decltype(kilo<gram>)>);
|
||||
static_assert(!PrefixableUnit<decltype(square(metre))>);
|
||||
static_assert(!PrefixableUnit<decltype(cubic(metre))>);
|
||||
static_assert(!PrefixableUnit<decltype(mag<60> * second)>);
|
||||
@@ -196,14 +203,14 @@ static_assert(standard_gravity != metre / square(second)); // magnitude is diff
|
||||
static_assert(standard_gravity.symbol == symbol_text{u8"g₀", "g_0"});
|
||||
|
||||
// prefixed_unit
|
||||
static_assert(is_of_type<kilometre, std::remove_const_t<decltype(si::kilo<metre>)>>);
|
||||
static_assert(is_of_type<kilometre, std::remove_const_t<decltype(kilo<metre>)>>);
|
||||
static_assert(is_of_type<get_canonical_unit(kilometre).reference_unit, metre_>);
|
||||
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<kilojoule, std::remove_const_t<decltype(si::kilo<joule>)>>);
|
||||
static_assert(is_of_type<kilojoule, std::remove_const_t<decltype(kilo<joule>)>>);
|
||||
static_assert(is_of_type<get_canonical_unit(kilojoule).reference_unit,
|
||||
derived_unit<gram_, power<metre_, 2>, per<power<second_, 2>>>>);
|
||||
static_assert(get_canonical_unit(kilojoule).mag == mag<1'000'000>);
|
||||
@@ -211,11 +218,11 @@ static_assert(convertible(kilojoule, joule));
|
||||
static_assert(kilojoule != joule);
|
||||
static_assert(kilojoule.symbol == "kJ");
|
||||
|
||||
static_assert(is_of_type<si::kilo<metre>, si::kilo_<metre_>>);
|
||||
static_assert(is_of_type<si::kilo<joule>, si::kilo_<joule_>>);
|
||||
static_assert(is_of_type<kilo<metre>, kilo_<metre_>>);
|
||||
static_assert(is_of_type<kilo<joule>, kilo_<joule_>>);
|
||||
|
||||
static_assert(
|
||||
is_of_type<kilometre / metre, derived_unit<std::remove_const_t<decltype(si::kilo<metre>)>, per<metre_>>>); // !!!
|
||||
is_of_type<kilometre / metre, derived_unit<std::remove_const_t<decltype(kilo<metre>)>, per<metre_>>>); // !!!
|
||||
|
||||
|
||||
// prefixes
|
||||
@@ -256,12 +263,12 @@ static_assert(is_of_type<get_canonical_unit(m_2).reference_unit, metre_>);
|
||||
static_assert(get_canonical_unit(m_2).mag == mag<2>);
|
||||
|
||||
constexpr auto km_2 = mag<2> * kilometre;
|
||||
static_assert(is_of_type<km_2, scaled_unit<mag<2>, si::kilo_<metre_>>>);
|
||||
static_assert(is_of_type<km_2, scaled_unit<mag<2>, kilo_<metre_>>>);
|
||||
static_assert(is_of_type<get_canonical_unit(km_2).reference_unit, metre_>);
|
||||
static_assert(get_canonical_unit(km_2).mag == mag<2000>);
|
||||
|
||||
constexpr auto kJ_42 = mag<42> * si::kilo<joule>;
|
||||
static_assert(is_of_type<kJ_42, scaled_unit<mag<42>, si::kilo_<joule_>>>);
|
||||
constexpr auto kJ_42 = mag<42> * kilo<joule>;
|
||||
static_assert(is_of_type<kJ_42, scaled_unit<mag<42>, kilo_<joule_>>>);
|
||||
static_assert(
|
||||
is_of_type<get_canonical_unit(kJ_42).reference_unit, derived_unit<gram_, power<metre_, 2>, per<power<second_, 2>>>>);
|
||||
static_assert(get_canonical_unit(kJ_42).mag == mag<42'000'000>);
|
||||
@@ -350,12 +357,12 @@ static_assert(is_of_type<get_canonical_unit(m_per_s).reference_unit, derived_uni
|
||||
static_assert(get_canonical_unit(m_per_s).mag == mag<1>);
|
||||
|
||||
constexpr auto km_per_s = kilometre / second;
|
||||
static_assert(is_of_type<km_per_s, derived_unit<si::kilo_<metre_>, per<second_>>>);
|
||||
static_assert(is_of_type<km_per_s, derived_unit<kilo_<metre_>, per<second_>>>);
|
||||
static_assert(is_of_type<get_canonical_unit(km_per_s).reference_unit, derived_unit<metre_, per<second_>>>);
|
||||
static_assert(get_canonical_unit(km_per_s).mag == mag<1000>);
|
||||
|
||||
constexpr auto km_per_h = kilometre / hour;
|
||||
static_assert(is_of_type<km_per_h, derived_unit<si::kilo_<metre_>, per<hour_>>>);
|
||||
static_assert(is_of_type<km_per_h, derived_unit<kilo_<metre_>, per<hour_>>>);
|
||||
static_assert(is_of_type<get_canonical_unit(km_per_h).reference_unit, derived_unit<metre_, per<second_>>>);
|
||||
static_assert(get_canonical_unit(km_per_h).mag == mag_ratio<1000, 3600>);
|
||||
|
||||
@@ -377,17 +384,17 @@ static_assert(is_of_type<get_canonical_unit(standard_gravity / speed_of_light_in
|
||||
|
||||
// operations commutativity
|
||||
constexpr auto u1 = mag<1000> * kilometre / hour;
|
||||
static_assert(is_of_type<u1, scaled_unit<mag<1000>, derived_unit<si::kilo_<metre_>, per<hour_>>>>);
|
||||
static_assert(is_of_type<u1, scaled_unit<mag<1000>, derived_unit<kilo_<metre_>, per<hour_>>>>);
|
||||
static_assert(is_of_type<get_canonical_unit(u1).reference_unit, derived_unit<metre_, per<second_>>>);
|
||||
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<u2, scaled_unit<mag<1000>, derived_unit<si::kilo_<metre_>, per<hour_>>>>);
|
||||
static_assert(is_of_type<u2, scaled_unit<mag<1000>, derived_unit<kilo_<metre_>, per<hour_>>>>);
|
||||
static_assert(is_of_type<get_canonical_unit(u2).reference_unit, derived_unit<metre_, per<second_>>>);
|
||||
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<u3, scaled_unit<mag<1000>, derived_unit<si::kilo_<metre_>, per<hour_>>>>);
|
||||
static_assert(is_of_type<u3, scaled_unit<mag<1000>, derived_unit<kilo_<metre_>, per<hour_>>>>);
|
||||
static_assert(is_of_type<get_canonical_unit(u3).reference_unit, derived_unit<metre_, per<second_>>>);
|
||||
static_assert(get_canonical_unit(u3).mag == mag_ratio<1'000'000, 3'600>);
|
||||
|
||||
@@ -427,11 +434,11 @@ static_assert(invalid_operations<second>);
|
||||
// comparisons of the same units
|
||||
static_assert(second == second);
|
||||
static_assert(metre / second == metre / second);
|
||||
static_assert(si::milli<metre> / si::milli<second> == si::micro<metre> / si::micro<second>);
|
||||
static_assert(si::milli<metre> / si::micro<second> == si::micro<metre> / si::nano<second>);
|
||||
static_assert(si::micro<metre> / si::milli<second> == si::nano<metre> / si::micro<second>);
|
||||
static_assert(si::milli<metre> * si::kilo<metre> == si::deci<metre> * si::deca<metre>);
|
||||
static_assert(si::kilo<metre> * si::milli<metre> == si::deca<metre> * si::deci<metre>);
|
||||
static_assert(milli<metre> / milli<second> == si::micro<metre> / si::micro<second>);
|
||||
static_assert(milli<metre> / si::micro<second> == si::micro<metre> / si::nano<second>);
|
||||
static_assert(si::micro<metre> / milli<second> == si::nano<metre> / si::micro<second>);
|
||||
static_assert(milli<metre> * kilo<metre> == si::deci<metre> * si::deca<metre>);
|
||||
static_assert(kilo<metre> * milli<metre> == si::deca<metre> * si::deci<metre>);
|
||||
|
||||
// comparisons of equivalent units (named vs unnamed/derived)
|
||||
static_assert(one / second == hertz);
|
||||
@@ -442,11 +449,11 @@ static_assert(hertz == becquerel);
|
||||
static_assert(convertible(hertz, becquerel));
|
||||
|
||||
// comparisons of scaled units
|
||||
static_assert(si::kilo<metre> == kilometre);
|
||||
static_assert(mag<1000> * metre == si::kilo<metre>);
|
||||
static_assert(kilo<metre> == kilometre);
|
||||
static_assert(mag<1000> * metre == kilo<metre>);
|
||||
static_assert(mag<1000> * metre == kilometre);
|
||||
static_assert(convertible(si::kilo<metre>, kilometre));
|
||||
static_assert(convertible(mag<1000> * metre, si::kilo<metre>));
|
||||
static_assert(convertible(kilo<metre>, kilometre));
|
||||
static_assert(convertible(mag<1000> * metre, kilo<metre>));
|
||||
static_assert(convertible(mag<1000> * metre, kilometre));
|
||||
|
||||
static_assert(mag<60> * metre / second == metre / (mag_ratio<1, 60> * second));
|
||||
@@ -455,8 +462,8 @@ 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<metre> != kilometre);
|
||||
static_assert(convertible(si::milli<metre>, kilometre));
|
||||
static_assert(milli<metre> != kilometre);
|
||||
static_assert(convertible(milli<metre>, kilometre));
|
||||
|
||||
// comparisons of non-convertible units
|
||||
static_assert(metre != metre * metre);
|
||||
@@ -464,7 +471,7 @@ static_assert(!convertible(metre, metre* metre));
|
||||
|
||||
// one
|
||||
static_assert(is_of_type<metre / metre, one_>);
|
||||
static_assert(is_of_type<si::kilo<metre> / metre, derived_unit<si::kilo_<metre_>, per<metre_>>>);
|
||||
static_assert(is_of_type<kilo<metre> / metre, derived_unit<kilo_<metre_>, per<metre_>>>);
|
||||
static_assert(metre / metre == one);
|
||||
static_assert(hertz * second == one);
|
||||
static_assert(one * one == one);
|
||||
@@ -484,7 +491,7 @@ static_assert(watt == kilogram * square(metre) / cubic(second));
|
||||
// power
|
||||
static_assert(is_same_v<decltype(pow<2>(metre)), decltype(metre * metre)>);
|
||||
static_assert(is_same_v<decltype(pow<2>(kilometre)), decltype(kilometre * kilometre)>);
|
||||
static_assert(is_same_v<decltype(pow<2>(si::kilo<metre>)), decltype(si::kilo<metre> * si::kilo<metre>)>);
|
||||
static_assert(is_same_v<decltype(pow<2>(kilo<metre>)), decltype(kilo<metre> * kilo<metre>)>);
|
||||
static_assert(is_same_v<decltype(pow<2>(hour)), decltype(hour * hour)>);
|
||||
static_assert(is_same_v<decltype(pow<2>(mag<3600> * second)), decltype((mag<3600> * second) * (mag<3600> * second))>);
|
||||
static_assert(is_same_v<decltype(pow<2>(metre / second)), decltype(metre * metre / second / second)>);
|
||||
@@ -503,21 +510,21 @@ static_assert(is_of_type<pow<1, 3>(metre* metre* metre), metre_>);
|
||||
static_assert(is_of_type<pow<1, 3>(metre* metre), derived_unit<power<metre_, 2, 3>>>);
|
||||
static_assert(is_of_type<pow<1, 2>(metre / second), derived_unit<power<metre_, 1, 2>, per<power<second_, 1, 2>>>>);
|
||||
static_assert(is_of_type<pow<1, 2>(metre / (second * second)), derived_unit<power<metre_, 1, 2>, per<second_>>>);
|
||||
static_assert(is_of_type<kilometre * kilometre, derived_unit<power<si::kilo_<metre_>, 2>>>);
|
||||
static_assert(is_of_type<kilometre * kilometre, derived_unit<power<kilo_<metre_>, 2>>>);
|
||||
|
||||
static_assert(is_of_type<pow<2>(kilometre), derived_unit<power<si::kilo_<metre_>, 2>>>);
|
||||
static_assert(is_of_type<pow<2>(si::kilo<metre>), derived_unit<power<si::kilo_<metre_>, 2>>>);
|
||||
static_assert(is_of_type<pow<2>(kilometre), derived_unit<power<kilo_<metre_>, 2>>>);
|
||||
static_assert(is_of_type<pow<2>(kilo<metre>), derived_unit<power<kilo_<metre_>, 2>>>);
|
||||
static_assert(is_of_type<pow<2>(hour), derived_unit<power<hour_, 2>>>);
|
||||
static_assert(
|
||||
is_of_type<pow<2>(mag<3600>* second), scaled_unit<mag<3600> * mag<3600>, derived_unit<power<second_, 2>>>>);
|
||||
|
||||
// get_common_unit
|
||||
static_assert(is_of_type<get_common_unit(gram, gram), gram_>);
|
||||
static_assert(is_of_type<get_common_unit(kilogram, kilogram), si::kilo_<gram_>>);
|
||||
static_assert(is_of_type<get_common_unit(si::kilo<gram>, kilogram), si::kilo_<gram_>>);
|
||||
static_assert(is_of_type<get_common_unit(kilogram, si::kilo<gram>), si::kilo_<gram_>>);
|
||||
static_assert(is_of_type<get_common_unit(mag<1000>* gram, kilogram), si::kilo_<gram_>>);
|
||||
static_assert(is_of_type<get_common_unit(kilogram, mag<1000>* gram), si::kilo_<gram_>>);
|
||||
static_assert(is_of_type<get_common_unit(kilogram, kilogram), kilo_<gram_>>);
|
||||
static_assert(is_of_type<get_common_unit(kilo<gram>, kilogram), kilo_<gram_>>);
|
||||
static_assert(is_of_type<get_common_unit(kilogram, kilo<gram>), kilo_<gram_>>);
|
||||
static_assert(is_of_type<get_common_unit(mag<1000>* gram, kilogram), kilo_<gram_>>);
|
||||
static_assert(is_of_type<get_common_unit(kilogram, mag<1000>* gram), kilo_<gram_>>);
|
||||
static_assert(is_of_type<get_common_unit(one / second, hertz), hertz_>);
|
||||
static_assert(is_of_type<get_common_unit(hertz, one / second), hertz_>);
|
||||
static_assert(is_of_type<get_common_unit(gram, kilogram), gram_>);
|
||||
@@ -526,18 +533,60 @@ static_assert(is_of_type<get_common_unit(second, hour), second_>);
|
||||
static_assert(is_of_type<get_common_unit(hour, second), second_>);
|
||||
static_assert(is_of_type<get_common_unit(minute, hour), minute_>);
|
||||
static_assert(is_of_type<get_common_unit(hour, minute), minute_>);
|
||||
static_assert(is_of_type<get_common_unit(si::kilo<metre>, si::milli<metre>), si::milli_<metre_>>);
|
||||
static_assert(is_of_type<get_common_unit(si::milli<metre>, si::kilo<metre>), si::milli_<metre_>>);
|
||||
static_assert(is_of_type<get_common_unit(kilo<metre>, milli<metre>), milli_<metre_>>);
|
||||
static_assert(is_of_type<get_common_unit(milli<metre>, kilo<metre>), milli_<metre_>>);
|
||||
static_assert(is_of_type<get_common_unit(yard, mile), yard_>);
|
||||
static_assert(is_of_type<get_common_unit(mile, yard), yard_>);
|
||||
// TODO The below have long/unreadable magnitude types
|
||||
static_assert(is_of_type<get_common_unit(kilometre / hour, metre / second),
|
||||
scaled_unit<mag_ratio<1, 18>, derived_unit<metre_, per<second_>>>>);
|
||||
static_assert(is_of_type<get_common_unit(metre / second, kilometre / hour),
|
||||
scaled_unit<mag_ratio<1, 18>, derived_unit<metre_, per<second_>>>>);
|
||||
static_assert(is_of_type<get_common_unit(kilometre, mile), scaled_unit<mag_ratio<8, 125>, metre_>>);
|
||||
static_assert(is_of_type<get_common_unit(mile, kilometre), scaled_unit<mag_ratio<8, 125>, metre_>>);
|
||||
static_assert(
|
||||
is_of_type<get_common_unit(speed_of_light_in_vacuum, metre / second), derived_unit<metre_, per<second_>>>);
|
||||
|
||||
// those should return instantiations of the `common_unit` class template
|
||||
static_assert(is_of_type<get_common_unit(kilometre, mile), common_unit<kilo_<metre_>, mile_>>);
|
||||
static_assert(is_of_type<get_common_unit(mile, kilometre), common_unit<kilo_<metre_>, mile_>>);
|
||||
static_assert(is_of_type<get_common_unit(kilometre / hour, metre / second),
|
||||
common_unit<decltype(kilometre / hour), decltype(metre / second)>>);
|
||||
static_assert(is_of_type<get_common_unit(metre / second, kilometre / hour),
|
||||
common_unit<decltype(kilometre / hour), decltype(metre / second)>>);
|
||||
|
||||
static_assert(
|
||||
is_of_type<get_common_unit(mile, kilometre) / second, derived_unit<common_unit<kilo_<metre_>, mile_>, per<second_>>>);
|
||||
|
||||
static_assert(
|
||||
is_of_type<get_common_unit(kilometre, mile, nautical_mile), common_unit<kilo_<metre_>, mile_, nautical_mile_>>);
|
||||
static_assert(
|
||||
is_of_type<get_common_unit(nautical_mile, mile, kilometre), common_unit<kilo_<metre_>, mile_, nautical_mile_>>);
|
||||
static_assert(
|
||||
is_of_type<get_common_unit(kilometre, nautical_mile, mile), common_unit<kilo_<metre_>, mile_, nautical_mile_>>);
|
||||
|
||||
static_assert(is_of_type<get_common_unit(kilometre, get_common_unit(mile, nautical_mile)),
|
||||
common_unit<kilo_<metre_>, mile_, nautical_mile_>>);
|
||||
static_assert(is_of_type<get_common_unit(nautical_mile, get_common_unit(mile, kilometre)),
|
||||
common_unit<kilo_<metre_>, mile_, nautical_mile_>>);
|
||||
static_assert(is_of_type<get_common_unit(kilometre, get_common_unit(nautical_mile, mile)),
|
||||
common_unit<kilo_<metre_>, mile_, nautical_mile_>>);
|
||||
|
||||
static_assert(is_of_type<get_common_unit(kilometre, mile, kilometre), common_unit<kilo_<metre_>, mile_>>);
|
||||
static_assert(is_of_type<get_common_unit(mile, kilometre, kilometre), common_unit<kilo_<metre_>, mile_>>);
|
||||
static_assert(is_of_type<get_common_unit(kilometre, mile, mile), common_unit<kilo_<metre_>, mile_>>);
|
||||
static_assert(is_of_type<get_common_unit(mile, kilometre, mile), common_unit<kilo_<metre_>, mile_>>);
|
||||
static_assert(is_of_type<get_common_unit(mile, get_common_unit(kilometre, mile)), common_unit<kilo_<metre_>, mile_>>);
|
||||
static_assert(
|
||||
is_of_type<get_common_unit(kilometre, get_common_unit(kilometre, mile)), common_unit<kilo_<metre_>, mile_>>);
|
||||
|
||||
static_assert(is_of_type<get_common_unit(kilometre, mile, metre), common_unit<metre_, mile_>>);
|
||||
|
||||
static_assert(is_of_type<get_common_unit(kilometre, mile, milli<metre>), milli_<metre_>>);
|
||||
|
||||
// check underlying types
|
||||
static_assert(std::derived_from<decltype(get_common_unit(kilometre / hour, metre / second)),
|
||||
detail::scaled_unit_impl<mag_ratio<1, 18>, derived_unit<metre_, per<second_>>>>);
|
||||
static_assert(std::derived_from<decltype(get_common_unit(metre / second, kilometre / hour)),
|
||||
detail::scaled_unit_impl<mag_ratio<1, 18>, derived_unit<metre_, per<second_>>>>);
|
||||
static_assert(
|
||||
std::derived_from<decltype(get_common_unit(kilometre, mile)), detail::scaled_unit_impl<mag_ratio<8, 125>, metre_>>);
|
||||
static_assert(
|
||||
std::derived_from<decltype(get_common_unit(mile, kilometre)), detail::scaled_unit_impl<mag_ratio<8, 125>, metre_>>);
|
||||
static_assert(std::derived_from<decltype(get_common_unit(kilometre, mile, si::centi<metre>)),
|
||||
detail::scaled_unit_impl<mag_ratio<1, 500>, metre_>>);
|
||||
|
||||
} // namespace
|
||||
|
||||
Reference in New Issue
Block a user