mirror of
https://github.com/mpusz/mp-units.git
synced 2025-08-09 23:24:27 +02:00
feat: system's definition highly simplified by removing the need for a system_reference
for most cases
This commit is contained in:
@@ -28,8 +28,7 @@ using namespace units;
|
||||
using namespace units::si::unit_symbols;
|
||||
|
||||
// clang-format off
|
||||
inline constexpr struct activity_dim : decltype(1 / isq::time_dim) {} activity_dim;
|
||||
inline constexpr struct activity : system_reference<activity_dim, si::becquerel> {} activity;
|
||||
DERIVED_DIMENSION(activity, decltype(1 / isq::time));
|
||||
// clang-format on
|
||||
|
||||
// check for invalid prefixes
|
||||
@@ -46,85 +45,84 @@ static_assert(can_not_be_prefixed<si::milli_, si::hectare>);
|
||||
static_assert(can_not_be_prefixed<si::milli_, si::metre / si::second>);
|
||||
|
||||
// Named quantity/dimension and unit
|
||||
static_assert(
|
||||
is_same_v<decltype(5 * si::power[W]), quantity<reference<struct isq::power_dim, struct si::watt>{}, int>>);
|
||||
static_assert(is_same_v<decltype(5 * isq::power[W]), quantity<reference<struct isq::power, struct si::watt>{}, int>>);
|
||||
|
||||
// Named quantity/dimension and derived (unnamed) unit
|
||||
static_assert(
|
||||
is_same_v<decltype(5 * si::speed[m / s]),
|
||||
quantity<reference<struct isq::speed_dim, derived_unit<struct si::metre, per<struct si::second>>>{}, int>>);
|
||||
is_same_v<decltype(5 * isq::speed[m / s]),
|
||||
quantity<reference<struct isq::speed, derived_unit<struct si::metre, per<struct si::second>>>{}, int>>);
|
||||
|
||||
// Derived (unnamed) quantity/dimension and derived (unnamed) unit
|
||||
static_assert(is_same_v<decltype(10 * si::length[m] / (2 * si::time[s])),
|
||||
quantity<reference<derived_dimension<struct isq::length_dim, per<struct isq::time_dim>>,
|
||||
static_assert(is_same_v<decltype(10 * isq::length[m] / (2 * isq::time[s])),
|
||||
quantity<reference<derived_dimension<struct isq::length, per<struct isq::time>>,
|
||||
derived_unit<struct si::metre, per<struct si::second>>>{},
|
||||
int>>);
|
||||
|
||||
// Base quantity as a result of dimensional transformation
|
||||
static_assert(is_same_v<decltype(5 * si::speed[m / s] * (5 * si::time[s])),
|
||||
quantity<reference<struct isq::length_dim, struct si::metre>{}, int>>);
|
||||
static_assert(is_same_v<decltype(5 * isq::speed[m / s] * (5 * isq::time[s])),
|
||||
quantity<reference<struct isq::length, struct si::metre>{}, int>>);
|
||||
|
||||
// Dimensionless
|
||||
static_assert(is_same_v<decltype(20 * si::speed[m / s] / (10 * si::length[m]) * (5 * si::time[s])),
|
||||
quantity<reference<struct one_dim, struct one>{}, int>>);
|
||||
static_assert(is_same_v<decltype(20 * isq::speed[m / s] / (10 * isq::length[m]) * (5 * isq::time[s])),
|
||||
quantity<reference<struct dimensionless, struct one>{}, int>>);
|
||||
|
||||
// Comparisons
|
||||
|
||||
// Same dimension type & different unit
|
||||
// static_assert(1000 * si::length[m] == 1 * si::length[km]);
|
||||
// static_assert(1000 * isq::length[m] == 1 * isq::length[km]);
|
||||
|
||||
// Named and derived dimensions (same units)
|
||||
static_assert(10 * si::length[m] / (2 * si::time[s]) == 5 * si::speed[m / s]);
|
||||
static_assert(5 * si::speed[m / s] == 10 * si::length[m] / (2 * si::time[s]));
|
||||
static_assert(10 * isq::length[m] / (2 * isq::time[s]) == 5 * isq::speed[m / s]);
|
||||
static_assert(5 * isq::speed[m / s] == 10 * isq::length[m] / (2 * isq::time[s]));
|
||||
|
||||
// Same named dimension & different but equivalent unit
|
||||
static_assert(10 * si::frequency[1 / s] == 10 * si::frequency[Hz]);
|
||||
static_assert(10 * si::frequency[Hz] == 10 * si::frequency[1 / s]);
|
||||
static_assert(10 * isq::frequency[1 / s] == 10 * isq::frequency[Hz]);
|
||||
static_assert(10 * isq::frequency[Hz] == 10 * isq::frequency[1 / s]);
|
||||
|
||||
// Named and derived dimensions (different but equivalent units)
|
||||
static_assert(10 / (2 * si::time[s]) == 5 * si::frequency[Hz]);
|
||||
static_assert(5 * si::frequency[Hz] == 10 / (2 * si::time[s]));
|
||||
static_assert(5 * si::force[N] * (2 * si::length[m]) == 10 * si::energy[J]);
|
||||
static_assert(10 * si::energy[J] == 5 * si::force[N] * (2 * si::length[m]));
|
||||
static_assert(10 / (2 * isq::time[s]) == 5 * isq::frequency[Hz]);
|
||||
static_assert(5 * isq::frequency[Hz] == 10 / (2 * isq::time[s]));
|
||||
static_assert(5 * isq::force[N] * (2 * isq::length[m]) == 10 * isq::energy[J]);
|
||||
static_assert(10 * isq::energy[J] == 5 * isq::force[N] * (2 * isq::length[m]));
|
||||
|
||||
// Different named dimensions
|
||||
template<Reference auto R1, Reference auto R2>
|
||||
concept invalid_comparison = !requires { 2 * R1 == 2 * R2; } && !requires { 2 * R2 == 2 * R1; };
|
||||
static_assert(invalid_comparison<activity[Bq], si::frequency[Hz]>);
|
||||
static_assert(invalid_comparison<activity[Bq], isq::frequency[Hz]>);
|
||||
|
||||
// Arithmetics
|
||||
|
||||
// Named and derived dimensions (same units)
|
||||
static_assert(10 * si::length[m] / (2 * si::time[s]) + 5 * si::speed[m / s] == 10 * si::speed[m / s]);
|
||||
static_assert(5 * si::speed[m / s] + 10 * si::length[m] / (2 * si::time[s]) == 10 * si::speed[m / s]);
|
||||
static_assert(10 * si::length[m] / (2 * si::time[s]) - 5 * si::speed[m / s] == 0 * si::speed[m / s]);
|
||||
static_assert(5 * si::speed[m / s] - 10 * si::length[m] / (2 * si::time[s]) == 0 * si::speed[m / s]);
|
||||
static_assert(10 * isq::length[m] / (2 * isq::time[s]) + 5 * isq::speed[m / s] == 10 * isq::speed[m / s]);
|
||||
static_assert(5 * isq::speed[m / s] + 10 * isq::length[m] / (2 * isq::time[s]) == 10 * isq::speed[m / s]);
|
||||
static_assert(10 * isq::length[m] / (2 * isq::time[s]) - 5 * isq::speed[m / s] == 0 * isq::speed[m / s]);
|
||||
static_assert(5 * isq::speed[m / s] - 10 * isq::length[m] / (2 * isq::time[s]) == 0 * isq::speed[m / s]);
|
||||
static_assert(
|
||||
is_same_v<decltype(10 * si::length[m] / (2 * si::time[s]) + 5 * si::speed[m / s]),
|
||||
quantity<reference<struct isq::speed_dim, derived_unit<struct si::metre, per<struct si::second>>>{}, int>>);
|
||||
is_same_v<decltype(10 * isq::length[m] / (2 * isq::time[s]) + 5 * isq::speed[m / s]),
|
||||
quantity<reference<struct isq::speed, derived_unit<struct si::metre, per<struct si::second>>>{}, int>>);
|
||||
static_assert(
|
||||
is_same_v<decltype(5 * si::speed[m / s] + 10 * si::length[m] / (2 * si::time[s])),
|
||||
quantity<reference<struct isq::speed_dim, derived_unit<struct si::metre, per<struct si::second>>>{}, int>>);
|
||||
is_same_v<decltype(5 * isq::speed[m / s] + 10 * isq::length[m] / (2 * isq::time[s])),
|
||||
quantity<reference<struct isq::speed, derived_unit<struct si::metre, per<struct si::second>>>{}, int>>);
|
||||
static_assert(
|
||||
is_same_v<decltype(10 * si::length[m] / (2 * si::time[s]) - 5 * si::speed[m / s]),
|
||||
quantity<reference<struct isq::speed_dim, derived_unit<struct si::metre, per<struct si::second>>>{}, int>>);
|
||||
is_same_v<decltype(10 * isq::length[m] / (2 * isq::time[s]) - 5 * isq::speed[m / s]),
|
||||
quantity<reference<struct isq::speed, derived_unit<struct si::metre, per<struct si::second>>>{}, int>>);
|
||||
static_assert(
|
||||
is_same_v<decltype(5 * si::speed[m / s] - 10 * si::length[m] / (2 * si::time[s])),
|
||||
quantity<reference<struct isq::speed_dim, derived_unit<struct si::metre, per<struct si::second>>>{}, int>>);
|
||||
is_same_v<decltype(5 * isq::speed[m / s] - 10 * isq::length[m] / (2 * isq::time[s])),
|
||||
quantity<reference<struct isq::speed, derived_unit<struct si::metre, per<struct si::second>>>{}, int>>);
|
||||
|
||||
// Named and derived dimensions (different units)
|
||||
static_assert(10 / (2 * si::time[s]) + 5 * si::frequency[Hz] == 10 * si::frequency[Hz]);
|
||||
static_assert(5 * si::frequency[Hz] + 10 / (2 * si::time[s]) == 10 * si::frequency[Hz]);
|
||||
static_assert(10 / (2 * si::time[s]) - 5 * si::frequency[Hz] == 0 * si::frequency[Hz]);
|
||||
static_assert(5 * si::frequency[Hz] - 10 / (2 * si::time[s]) == 0 * si::frequency[Hz]);
|
||||
static_assert(is_same_v<decltype(10 / (2 * si::time[s]) + 5 * si::frequency[Hz]),
|
||||
quantity<reference<struct isq::frequency_dim, struct si::hertz>{}, int>>);
|
||||
static_assert(is_same_v<decltype(5 * si::frequency[Hz] + 10 / (2 * si::time[s])),
|
||||
quantity<reference<struct isq::frequency_dim, struct si::hertz>{}, int>>);
|
||||
static_assert(is_same_v<decltype(10 / (2 * si::time[s]) - 5 * si::frequency[Hz]),
|
||||
quantity<reference<struct isq::frequency_dim, struct si::hertz>{}, int>>);
|
||||
static_assert(is_same_v<decltype(5 * si::frequency[Hz] - 10 / (2 * si::time[s])),
|
||||
quantity<reference<struct isq::frequency_dim, struct si::hertz>{}, int>>);
|
||||
static_assert(10 / (2 * isq::time[s]) + 5 * isq::frequency[Hz] == 10 * isq::frequency[Hz]);
|
||||
static_assert(5 * isq::frequency[Hz] + 10 / (2 * isq::time[s]) == 10 * isq::frequency[Hz]);
|
||||
static_assert(10 / (2 * isq::time[s]) - 5 * isq::frequency[Hz] == 0 * isq::frequency[Hz]);
|
||||
static_assert(5 * isq::frequency[Hz] - 10 / (2 * isq::time[s]) == 0 * isq::frequency[Hz]);
|
||||
static_assert(is_same_v<decltype(10 / (2 * isq::time[s]) + 5 * isq::frequency[Hz]),
|
||||
quantity<reference<struct isq::frequency, struct si::hertz>{}, int>>);
|
||||
static_assert(is_same_v<decltype(5 * isq::frequency[Hz] + 10 / (2 * isq::time[s])),
|
||||
quantity<reference<struct isq::frequency, struct si::hertz>{}, int>>);
|
||||
static_assert(is_same_v<decltype(10 / (2 * isq::time[s]) - 5 * isq::frequency[Hz]),
|
||||
quantity<reference<struct isq::frequency, struct si::hertz>{}, int>>);
|
||||
static_assert(is_same_v<decltype(5 * isq::frequency[Hz] - 10 / (2 * isq::time[s])),
|
||||
quantity<reference<struct isq::frequency, struct si::hertz>{}, int>>);
|
||||
|
||||
// Different named dimensions
|
||||
template<typename... Ts>
|
||||
@@ -132,50 +130,49 @@ consteval bool invalid_arithmetic(Ts... ts)
|
||||
{
|
||||
return !requires { (... + ts); } && !requires { (... - ts); };
|
||||
}
|
||||
static_assert(invalid_arithmetic(5 * activity[Bq], 5 * si::frequency[Hz]));
|
||||
static_assert(invalid_arithmetic(5 * activity[Bq], 10 / (2 * si::time[s]), 5 * si::frequency[Hz]));
|
||||
static_assert(invalid_arithmetic(5 * activity[Bq], 5 * isq::frequency[Hz]));
|
||||
static_assert(invalid_arithmetic(5 * activity[Bq], 10 / (2 * isq::time[s]), 5 * isq::frequency[Hz]));
|
||||
|
||||
// Implicit conversions allowed between quantities of `convertible` references
|
||||
constexpr quantity<si::speed[km / h]> speed = 120 * si::length[km] / (2 * si::time[h]);
|
||||
constexpr quantity<isq::speed[km / h]> speed = 120 * isq::length[km] / (2 * isq::time[h]);
|
||||
|
||||
// Explicit casts allow changing all or only a part of the type
|
||||
static_assert(
|
||||
std::is_same_v<
|
||||
decltype(quantity_cast<isq::speed_dim>(120 * si::length[km] / (2 * si::time[h]))),
|
||||
quantity<reference<struct isq::speed_dim,
|
||||
derived_unit<std::remove_const_t<decltype(si::kilo<si::metre>)>, per<struct si::hour>>>{},
|
||||
int>>);
|
||||
auto q3 = quantity_cast<m / s>(120 * si::length[km] / (2 * si::time[h]));
|
||||
auto q4 = quantity_cast<si::speed[m / s]>(120 * si::length[km] / (2 * si::time[h]));
|
||||
auto q5 = quantity_cast<double>(120 * si::length[km] / (2 * si::time[h]));
|
||||
auto q6 = quantity_cast<quantity<si::speed[m / s], double>>(120 * si::length[km] / (2 * si::time[h]));
|
||||
std::is_same_v<decltype(quantity_cast<isq::speed>(120 * isq::length[km] / (2 * isq::time[h]))),
|
||||
quantity<reference<struct isq::speed, derived_unit<std::remove_const_t<decltype(si::kilo<si::metre>)>,
|
||||
per<struct si::hour>>>{},
|
||||
int>>);
|
||||
auto q3 = quantity_cast<m / s>(120 * isq::length[km] / (2 * isq::time[h]));
|
||||
auto q4 = quantity_cast<isq::speed[m / s]>(120 * isq::length[km] / (2 * isq::time[h]));
|
||||
auto q5 = quantity_cast<double>(120 * isq::length[km] / (2 * isq::time[h]));
|
||||
auto q6 = quantity_cast<quantity<isq::speed[m / s], double>>(120 * isq::length[km] / (2 * isq::time[h]));
|
||||
|
||||
// cast 1 / time_dim to use Hz
|
||||
// cast 1 / time to use Hz
|
||||
|
||||
// static_assert(quantity_of<decltype(60 * si::speed[km / h]), isq::speed_dim>);
|
||||
// static_assert(quantity_of<decltype(120 * si::length[km] / (2 * si::time[h])), isq::speed_dim>);
|
||||
// static_assert(quantity_of<decltype(120 * si::length[km] / (2 * si::time[h])), si::speed[km / h]>);
|
||||
// static_assert(!quantity_of<decltype(120 * si::length[km] / (2 * si::time[h])), si::speed[m / s]>);
|
||||
// static_assert(quantity_of<decltype(60 * isq::speed[km / h]), isq::speed>);
|
||||
// static_assert(quantity_of<decltype(120 * isq::length[km] / (2 * isq::time[h])), isq::speed>);
|
||||
// static_assert(quantity_of<decltype(120 * isq::length[km] / (2 * isq::time[h])), isq::speed[km / h]>);
|
||||
// static_assert(!quantity_of<decltype(120 * isq::length[km] / (2 * isq::time[h])), isq::speed[m / s]>);
|
||||
|
||||
|
||||
// quantity<reference<speed_dim, derived_unit<si::metre, per<si::second>>>, int> s = 5 * speed[m / s];
|
||||
// quantity<reference<derived_dimension<length_dim, per<time_dim>>, derived_unit<metre, per<second>>>, int> q =
|
||||
// 10 * length[m] / (2 * si::time[s]);
|
||||
// quantity<reference<speed, derived_unit<si::metre, per<si::second>>>, int> s = 5 * speed[m / s];
|
||||
// quantity<reference<derived_dimension<length, per<time>>, derived_unit<metre, per<second>>>, int> q =
|
||||
// 10 * length[m] / (2 * isq::time[s]);
|
||||
|
||||
// auto q1 = 10 * length[m] / (2 * si::time[s]) + 5 * speed[m / s]; // should this be allowed?
|
||||
// bool b1 = (10 * length[m] / (2 * si::time[s]) == 5 * speed[m / s]); // should this be allowed?
|
||||
// auto q1 = 10 * length[m] / (2 * isq::time[s]) + 5 * speed[m / s]; // should this be allowed?
|
||||
// bool b1 = (10 * length[m] / (2 * isq::time[s]) == 5 * speed[m / s]); // should this be allowed?
|
||||
|
||||
// auto q2 = 10 / (2 * si::time[s]) + 5 * frequency[Hz]; // should this be allowed?
|
||||
// bool b2 = (10 / (2 * si::time[s]) == 5 * frequency[Hz]); // should this be allowed?
|
||||
// auto q2 = 10 / (2 * isq::time[s]) + 5 * frequency[Hz]; // should this be allowed?
|
||||
// bool b2 = (10 / (2 * isq::time[s]) == 5 * frequency[Hz]); // should this be allowed?
|
||||
|
||||
// auto q3 = 5 * activity[Bq] + 5 * frequency[Hz]; // should this be allowed?
|
||||
// auto b3 = (5 * activity[Bq] == 5 * frequency[Hz]); // should this be allowed?
|
||||
|
||||
// auto q4 = 5 * activity[Bq] + 10 / (2 * si::time[s]) + 5 * frequency[Hz]; // should this be allowed?
|
||||
// auto q4 = 5 * activity[Bq] + 10 / (2 * isq::time[s]) + 5 * frequency[Hz]; // should this be allowed?
|
||||
|
||||
// auto q5 = 120 * length[km] / (2 * si::time[h]); // not speed
|
||||
// auto q6 = quantity_cast<dim_speed>(120 * length[km] / (2 * si::time[h]));
|
||||
// auto q7 = quantity_cast<speed[m / s]>(120 * length[km] / (2 * si::time[h]));
|
||||
// auto q5 = 120 * length[km] / (2 * isq::time[h]); // not speed
|
||||
// auto q6 = quantity_cast<dim_speed>(120 * length[km] / (2 * isq::time[h]));
|
||||
// auto q7 = quantity_cast<speed[m / s]>(120 * length[km] / (2 * isq::time[h]));
|
||||
// quantity<speed[km / h]> s = q5; // should this implicit conversion be allowed?
|
||||
|
||||
} // namespace
|
||||
@@ -192,10 +189,12 @@ namespace units::isq::si {
|
||||
|
||||
// quantity tests
|
||||
// static_assert(
|
||||
// is_exactly_quantity_of<decltype(4 * length[km] / (2 * length[m])), one_dim, derived_unit<kilometre, per<metre>>>);
|
||||
// is_exactly_quantity_of<decltype(4 * length[km] / (2 * length[m])), dimensionless, derived_unit<kilometre,
|
||||
// per<metre>>>);
|
||||
|
||||
// static_assert(QuantityOf<decltype(4 * length[km] / (2 * length[m])), one_dim, derived_unit<kilometre, per<metre>>);
|
||||
// static_assert(QuantityOf<decltype(4 * length[km] / (2 * length[m])), one_dim, derived_unit<metre, per<millimetre>>);
|
||||
// static_assert(QuantityOf<decltype(4 * length[km] / (2 * length[m])), dimensionless, derived_unit<kilometre,
|
||||
// per<metre>>); static_assert(QuantityOf<decltype(4 * length[km] / (2 * length[m])), dimensionless, derived_unit<metre,
|
||||
// per<millimetre>>);
|
||||
// // TODO Should this compile?
|
||||
|
||||
} // namespace units::isq::si
|
||||
@@ -205,21 +204,37 @@ namespace units::isq::si {
|
||||
// using namespace units::si::unit_symbols;
|
||||
|
||||
// /* Frequency */ auto freq1 = 20 * frequency[Hz];
|
||||
// // /* Frequency */ auto freq2 = 20 / (1 * si::time[s]);
|
||||
// // /* Frequency */ auto freq2 = 20 / (1 * isq::time[s]);
|
||||
// quantity<frequency[Hz]> freq3(20);
|
||||
// quantity<frequency[1 / s]> freq4(20);
|
||||
// quantity<dimensionless[one] / si::time[s]> freq5(20);
|
||||
// quantity<dimensionless[one] / isq::time[s]> freq5(20);
|
||||
|
||||
// /* Speed */ auto speed1 = 20 * speed[m / s];
|
||||
// /* Speed */ auto speed2 = 20 * (length[m] / si::time[s]);
|
||||
// /* Speed */ auto speed2 = 20 * (length[m] / isq::time[s]);
|
||||
// quantity<speed[km / s]> speed3(20);
|
||||
// quantity<length[m] / si::time[s]> speed4(20);
|
||||
// quantity<length[m] / isq::time[s]> speed4(20);
|
||||
|
||||
|
||||
// constexpr auto avg_speed(quantity<length[km]> d, quantity<si::time[h]> t) { return d / t; }
|
||||
// constexpr auto avg_speed(quantity<length[km]> d, quantity<isq::time[h]> t) { return d / t; }
|
||||
|
||||
#include <iostream>
|
||||
|
||||
int main()
|
||||
{
|
||||
using enum text_encoding;
|
||||
using enum unit_symbol_denominator;
|
||||
using enum unit_symbol_separator;
|
||||
|
||||
std::cout << unit_symbol(si::kilogram / si::metre / square<si::second>, {.denominator = always_solidus}) << "\n";
|
||||
// std::cout << unit_symbol(si::metre / si::second, {.denominator = unit_symbol_denominator::always_negative}) <<
|
||||
// "\n"; std::cout << unit_symbol(si::metre / si::second, {.denominator = unit_symbol_denominator::always_negative})
|
||||
// <<
|
||||
// "\n";
|
||||
// static_assert(unit_symbol(metre / second, {.denominator = always_negative, .separator = dot}) == "m⋅s⁻¹");
|
||||
|
||||
// std::cout << get_unit_symbol(si::minute / square<si::second>).standard().c_str() << "\n";
|
||||
// std::cout << get_unit_symbol(si::joule / si::minute).standard().c_str() << "\n";
|
||||
|
||||
// print<decltype(speed)>();
|
||||
// print<decltype(freq1)>();
|
||||
// // print<decltype(freq2)>();
|
||||
@@ -239,19 +254,19 @@ int main()
|
||||
// joule * erg???
|
||||
// joule / erg???
|
||||
|
||||
// auto d1 = 42 * isq::length_dim[si::kilo<si::metre>];
|
||||
// auto d2 = 42 * isq::length_dim[cgs::centimetre];
|
||||
// auto d1 = 42 * isq::length[si::kilo<si::metre>];
|
||||
// auto d2 = 42 * isq::length[cgs::centimetre];
|
||||
|
||||
// auto s1 = 42 * isq::speed_dim[si::metre / si::second];
|
||||
// auto s2 = 42 * isq::speed_dim[cgs::centimetre / si::second];
|
||||
// auto e1 = 42 * isq::energy_dim[si::joule];
|
||||
// auto e2 = 42 * isq::energy_dim[cgs::erg];
|
||||
// auto e2_bad = 42 * isq::energy_dim[cgs::erg / si::second];
|
||||
// auto p1 = 42 * isq::power_dim[si::watt];
|
||||
// auto p2 = 42 * isq::power_dim[cgs::erg / si::second];
|
||||
// auto s1 = 42 * isq::speed[si::metre / si::second];
|
||||
// auto s2 = 42 * isq::speed[cgs::centimetre / si::second];
|
||||
// auto e1 = 42 * isq::energy[si::joule];
|
||||
// auto e2 = 42 * isq::energy[cgs::erg];
|
||||
// auto e2_bad = 42 * isq::energy[cgs::erg / si::second];
|
||||
// auto p1 = 42 * isq::power[si::watt];
|
||||
// auto p2 = 42 * isq::power[cgs::erg / si::second];
|
||||
|
||||
// type of Rep{1} * (mag<ratio(662'607'015, 100'000'000)> * mag_power<10, -34> * energy[joule] * time[second])
|
||||
// and inline constexpr auto planck_constant = Rep{1} * mag_planck * energy[joule] * time[second];
|
||||
|
||||
|
||||
// quantity_cast on equivalent dimensions
|
||||
// quantity_cast on equivalent dimensions
|
||||
|
@@ -102,7 +102,11 @@ template<typename T>
|
||||
concept AliasUnit = requires(T* t) { detail::to_base_alias_unit(t); };
|
||||
|
||||
// BaseDimension
|
||||
template<basic_fixed_string Symbol, NamedUnit U>
|
||||
#ifdef __cpp_explicit_this_parameter__
|
||||
template<basic_fixed_string Symbol>
|
||||
#else
|
||||
template<typename Self, basic_fixed_string Symbol>
|
||||
#endif
|
||||
struct base_dimension;
|
||||
|
||||
namespace detail {
|
||||
|
@@ -457,6 +457,9 @@ template<std::intmax_t Num, std::intmax_t Den, template<typename...> typename To
|
||||
*
|
||||
* @tparam Num Exponent numerator
|
||||
* @tparam Den Exponent denominator
|
||||
* @tparam To destination type list to put the result to
|
||||
* @tparam OneType type that represents the value `1`
|
||||
* @tparam Pred binary less then predicate
|
||||
* @tparam T Expression being the base of the operation
|
||||
*/
|
||||
template<std::intmax_t Num, std::intmax_t Den, template<typename...> typename To, typename OneType,
|
||||
@@ -467,6 +470,44 @@ template<std::intmax_t Num, std::intmax_t Den, template<typename...> typename To
|
||||
return expr_pow_impl<Num, Den, To, OneType, Pred>(typename T::_num_{}, typename T::_den_{});
|
||||
}
|
||||
|
||||
|
||||
// expr_map
|
||||
|
||||
template<typename T, template<typename...> typename Proj>
|
||||
struct expr_type_map {
|
||||
using type = Proj<T>;
|
||||
};
|
||||
|
||||
template<typename F, int... Ints, template<typename...> typename Proj>
|
||||
struct expr_type_map<power<F, Ints...>, Proj> {
|
||||
using type = power<Proj<F>, Ints...>;
|
||||
};
|
||||
|
||||
template<template<typename...> typename Proj, template<typename...> typename To, typename OneType,
|
||||
template<typename, typename> typename Pred, typename... Nums, typename... Dens>
|
||||
[[nodiscard]] consteval auto expr_map_impl(type_list<Nums...>, type_list<Dens...>)
|
||||
{
|
||||
using nums = type_list_sort<type_list<typename expr_type_map<Nums, Proj>::type...>, Pred>;
|
||||
using dens = type_list_sort<type_list<typename expr_type_map<Dens, Proj>::type...>, Pred>;
|
||||
return detail::get_optimized_expression<nums, dens, OneType, Pred, To>();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Maps contents of one expression template to another resulting in a different type list
|
||||
*
|
||||
* @tparam Proj Projection to be used for mapping
|
||||
* @tparam To destination type list to put the result to
|
||||
* @tparam OneType type that represents the value `1`
|
||||
* @tparam Pred binary less then predicate
|
||||
* @tparam T expression template to map from
|
||||
*/
|
||||
template<template<typename...> typename Proj, template<typename...> typename To, typename OneType,
|
||||
template<typename, typename> typename Pred, typename T>
|
||||
[[nodiscard]] consteval auto expr_map(T)
|
||||
{
|
||||
return expr_map_impl<Proj, To, OneType, Pred>(typename T::_num_{}, typename T::_den_{});
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace units
|
||||
|
@@ -25,64 +25,10 @@
|
||||
#include <units/bits/expression_template.h>
|
||||
#include <units/bits/external/fixed_string.h>
|
||||
#include <units/bits/external/type_traits.h>
|
||||
#include <units/unit.h>
|
||||
|
||||
namespace units {
|
||||
|
||||
/**
|
||||
* @brief A dimension of a base quantity
|
||||
*
|
||||
* Base quantity is a quantity in a conventionally chosen subset of a given system of quantities, where no quantity
|
||||
* in the subset can be expressed in terms of the other quantities within that subset. They are referred to as
|
||||
* being mutually independent since a base quantity cannot be expressed as a product of powers of the other base
|
||||
* quantities.
|
||||
*
|
||||
* Symbol template parameters is an unique identifier of the base dimension. The same identifiers can be multiplied
|
||||
* and divided which will result with an adjustment of its factor in an exponent of a derived_dimension
|
||||
* (in case of zero the dimension will be simplified and removed from further analysis of current expresion).
|
||||
*
|
||||
* User should derive a strong type from this class template rather than use it directly in the source code.
|
||||
* For example:
|
||||
*
|
||||
* @code{.cpp}
|
||||
* inline constexpr struct length_dim : base_dimension<"L"> {} length_dim;
|
||||
* inline constexpr struct time_dim : base_dimension<"T"> {} time_dim;
|
||||
* inline constexpr struct mass_dim : base_dimension<"M"> {} mass_dim;
|
||||
* @endcode
|
||||
*
|
||||
* @note A common convention in this library is to assign the same name for a type and an object of this type.
|
||||
* Besides defining them user never works with the dimension types in the source code. All operations
|
||||
* are done on the objects. Contrarily, the dimension types are the only one visible in the compilation
|
||||
* errors. Having them of the same names improves user experience and somehow blurs those separate domains.
|
||||
*
|
||||
* @tparam Symbol an unique identifier of the base dimension used to provide dimensional analysis support
|
||||
*/
|
||||
template<basic_fixed_string Symbol>
|
||||
struct base_dimension {
|
||||
static constexpr auto symbol = Symbol; ///< Unique base dimension identifier
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<basic_fixed_string Symbol>
|
||||
void to_base_base_dimension(const volatile base_dimension<Symbol>*);
|
||||
|
||||
template<typename T>
|
||||
inline constexpr bool is_specialization_of_base_dimension = false;
|
||||
|
||||
template<basic_fixed_string Symbol>
|
||||
inline constexpr bool is_specialization_of_base_dimension<base_dimension<Symbol>> = true;
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/**
|
||||
* @brief A concept matching all named base dimensions in the library.
|
||||
*
|
||||
* Satisfied by all dimension types derived from a specialization of `base_dimension`.
|
||||
*/
|
||||
template<typename T>
|
||||
concept BaseDimension = requires(T* t) { detail::to_base_base_dimension(t); } &&
|
||||
(!detail::is_specialization_of_base_dimension<T>);
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<typename T>
|
||||
@@ -107,6 +53,66 @@ concept DerivedDimension = detail::is_derived_dimension<T>;
|
||||
template<typename T>
|
||||
concept Dimension = BaseDimension<T> || DerivedDimension<T>;
|
||||
|
||||
|
||||
namespace detail {
|
||||
|
||||
[[nodiscard]] consteval Dimension auto get_dimension_for(Unit auto);
|
||||
|
||||
}
|
||||
|
||||
template<Dimension D, Unit U>
|
||||
struct reference;
|
||||
|
||||
/**
|
||||
* @brief A dimension of a base quantity
|
||||
*
|
||||
* Base quantity is a quantity in a conventionally chosen subset of a given system of quantities, where no quantity
|
||||
* in the subset can be expressed in terms of the other quantities within that subset. They are referred to as
|
||||
* being mutually independent since a base quantity cannot be expressed as a product of powers of the other base
|
||||
* quantities.
|
||||
*
|
||||
* Symbol template parameters is an unique identifier of the base dimension. The same identifiers can be multiplied
|
||||
* and divided which will result with an adjustment of its factor in an exponent of a derived_dimension
|
||||
* (in case of zero the dimension will be simplified and removed from further analysis of current expresion).
|
||||
*
|
||||
* User should derive a strong type from this class template rather than use it directly in the source code.
|
||||
* For example:
|
||||
*
|
||||
* @code{.cpp}
|
||||
* inline constexpr struct length : base_dimension<"L"> {} length;
|
||||
* inline constexpr struct time : base_dimension<"T"> {} time;
|
||||
* inline constexpr struct mass : base_dimension<"M"> {} mass;
|
||||
* @endcode
|
||||
*
|
||||
* @note A common convention in this library is to assign the same name for a type and an object of this type.
|
||||
* Besides defining them user never works with the dimension types in the source code. All operations
|
||||
* are done on the objects. Contrarily, the dimension types are the only one visible in the compilation
|
||||
* errors. Having them of the same names improves user experience and somehow blurs those separate domains.
|
||||
*
|
||||
* @tparam Symbol an unique identifier of the base dimension used to provide dimensional analysis support
|
||||
*/
|
||||
#ifdef __cpp_explicit_this_parameter__
|
||||
template<basic_fixed_string Symbol>
|
||||
#else
|
||||
template<typename Self, basic_fixed_string Symbol>
|
||||
#endif
|
||||
struct base_dimension {
|
||||
static constexpr auto symbol = Symbol; ///< Unique base dimension identifier
|
||||
|
||||
#ifdef __cpp_explicit_this_parameter__
|
||||
template<Unit U, typename Self>
|
||||
requires(convertible(Self{}, detail::get_dimension_for(U{})))
|
||||
[[nodiscard]] constexpr reference<Self, U> operator[](this const Self, U)
|
||||
#else
|
||||
template<Unit U>
|
||||
requires(convertible(Self{}, detail::get_dimension_for(U{})))
|
||||
[[nodiscard]] constexpr reference<Self, U> operator[](U) const
|
||||
#endif
|
||||
{
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<BaseDimension Lhs, BaseDimension Rhs>
|
||||
@@ -116,12 +122,13 @@ template<typename T1, typename T2>
|
||||
using type_list_of_base_dimension_less = expr_less<T1, T2, base_dimension_less>;
|
||||
|
||||
template<typename T>
|
||||
inline constexpr bool is_one_dim = false;
|
||||
inline constexpr bool is_dimensionless = false;
|
||||
|
||||
template<typename T>
|
||||
inline constexpr bool is_power_of_dim =
|
||||
requires {
|
||||
requires is_specialization_of_power<T> && (BaseDimension<typename T::factor> || is_one_dim<typename T::factor>);
|
||||
requires is_specialization_of_power<T> &&
|
||||
(BaseDimension<typename T::factor> || is_dimensionless<typename T::factor>);
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
@@ -129,15 +136,15 @@ inline constexpr bool is_per_of_dims = false;
|
||||
|
||||
template<typename... Ts>
|
||||
inline constexpr bool is_per_of_dims<per<Ts...>> =
|
||||
(... && (BaseDimension<Ts> || is_one_dim<Ts> || is_power_of_dim<Ts>));
|
||||
(... && (BaseDimension<Ts> || is_dimensionless<Ts> || is_power_of_dim<Ts>));
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template<typename T>
|
||||
concept DerivedDimensionSpec =
|
||||
BaseDimension<T> || detail::is_one_dim<T> || detail::is_power_of_dim<T> || detail::is_per_of_dims<T>;
|
||||
BaseDimension<T> || detail::is_dimensionless<T> || detail::is_power_of_dim<T> || detail::is_per_of_dims<T>;
|
||||
|
||||
template<DerivedDimensionSpec... Ds>
|
||||
template<typename...>
|
||||
struct derived_dimension;
|
||||
|
||||
namespace detail {
|
||||
@@ -160,47 +167,83 @@ struct derived_dimension_impl : detail::expr_fractions<derived_dimension<>, Ds..
|
||||
* more digestable for the user. The positive exponents are ordered first and all negative exponents are put as a list
|
||||
* into the `per<...>` class template. If a power of exponent is different than `1` the dimension type is enclosed in
|
||||
* `power<Dim, Num, Den>` class template. Otherwise, it is just put directly in the list without any wrapper. There
|
||||
* is also one special case. In case all of the exponents are negative than the `one_dim` being a dimension of
|
||||
* is also one special case. In case all of the exponents are negative than the `dimensionless` being a dimension of
|
||||
* a dimensionless quantity is put in the front to increase the readability.
|
||||
*
|
||||
* For example:
|
||||
*
|
||||
* @code{.cpp}
|
||||
* inline constexpr struct frequency_dim : decltype(1 / time_dim) {} frequency_dim;
|
||||
* inline constexpr struct speed_dim : decltype(length_dim / time_dim) {} speed_dim;
|
||||
* inline constexpr struct acceleration_dim : decltype(speed_dim / time_dim) {} acceleration_dim;
|
||||
* inline constexpr struct force_dim : decltype(mass_dim * acceleration_dim) {} force_dim;
|
||||
* inline constexpr struct energy_dim : decltype(force_dim * length_dim) {} energy_dim;
|
||||
* inline constexpr struct moment_of_force_dim : decltype(length_dim * force_dim) {} moment_of_force_dim;
|
||||
* inline constexpr struct torque_dim : decltype(moment_of_force_dim) {} torque_dim;
|
||||
* DERIVED_DIMENSION(frequency, 1 / time);
|
||||
* DERIVED_DIMENSION(speed, length / time);
|
||||
* DERIVED_DIMENSION(acceleration, speed / time);
|
||||
* DERIVED_DIMENSION(force, mass * acceleration);
|
||||
* DERIVED_DIMENSION(energy, force * length);
|
||||
* DERIVED_DIMENSION(moment_of_force, length * force);
|
||||
* DERIVED_DIMENSION(torque, moment_of_force);
|
||||
* @endcode
|
||||
*
|
||||
* - `frequency_dim` will be derived from type `derived_dimension<one_dim, per<time_dim>>`
|
||||
* - `speed_dim` will be derived from type `derived_dimension<length_dim, per<time_dim>>`
|
||||
* - `acceleration_dim` will be derived from type `derived_dimension<length_dim, per<power<time_dim, 2>>>`
|
||||
* - `force_dim` will be derived from type `derived_dimension<length_dim, mass_dim, per<power<time_dim, 2>>>`
|
||||
* - `energy_dim` will be derived from type `derived_dimension<power<length_dim, 2>, mass_dim, per<power<time_dim, 2>>>`
|
||||
* - `frequency` will be derived from type `derived_dimension<dimensionless, per<time>>`
|
||||
* - `speed` will be derived from type `derived_dimension<length, per<time>>`
|
||||
* - `acceleration` will be derived from type `derived_dimension<length, per<power<time, 2>>>`
|
||||
* - `force` will be derived from type `derived_dimension<length, mass, per<power<time, 2>>>`
|
||||
* - `energy` will be derived from type `derived_dimension<power<length, 2>, mass, per<power<time, 2>>>`
|
||||
*
|
||||
* @note A common convention in this library is to assign the same name for a type and an object of this type.
|
||||
* Besides defining them user never works with the dimension types in the source code. All operations
|
||||
* are done on the objects. Contrarily, the dimension types are the only one visible in the compilation
|
||||
* errors. Having them of the same names improves user experience and somehow blurs those separate domains.
|
||||
*
|
||||
* Two dimensions are deemed equal when they are of the same type. With that strong type `speed_dim` and
|
||||
* `derived_dimension<length_dim, per<time_dim>>` are considered not equal. They are convertible though.
|
||||
* Two dimensions are deemed equal when they are of the same type. With that strong type `speed` and
|
||||
* `derived_dimension<length, per<time>>` are considered not equal. They are convertible though.
|
||||
* User can implicitly convert up and down the inheritance hierarchy between those two.
|
||||
* `torque_dim` and `moment_of_force_dim` are convertible as well. However, `energy_dim` and `torque_dim`
|
||||
* `torque` and `moment_of_force` are convertible as well. However, `energy` and `torque`
|
||||
* are not convertible as they do not inherit from each other. They are from two separate branches of
|
||||
* dimensionally equivalent quantities.
|
||||
*
|
||||
* @tparam Ds a parameter pack consisting tokens allowed in the dimension specification
|
||||
* (base dimensions, `one_dim`, `power<Dim, Num, Den>`, `per<...>`)
|
||||
* (base dimensions, `dimensionless`, `power<Dim, Num, Den>`, `per<...>`)
|
||||
*
|
||||
* @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 dimensional arithmetic equation provided by the user.
|
||||
*/
|
||||
#ifdef __cpp_explicit_this_parameter__
|
||||
|
||||
template<DerivedDimensionSpec... Ds>
|
||||
struct derived_dimension : detail::derived_dimension_impl<Ds...> {};
|
||||
struct derived_dimension : detail::derived_dimension_impl<Ds...> {
|
||||
template<Unit U, typename Self>
|
||||
requires(convertible(Self{}, detail::get_dimension_for(U{})))
|
||||
[[nodiscard]] constexpr reference<Self, U> operator[](this const Self, U)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
template<typename...>
|
||||
struct derived_dimension;
|
||||
|
||||
template<DerivedDimensionSpec... Ds>
|
||||
struct derived_dimension<Ds...> : detail::derived_dimension_impl<Ds...> {
|
||||
template<Unit U>
|
||||
requires(convertible(derived_dimension{}, detail::get_dimension_for(U{})))
|
||||
[[nodiscard]] constexpr reference<derived_dimension, U> operator[](U) const
|
||||
{
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Self, DerivedDimension D>
|
||||
struct derived_dimension<Self, D> : D {
|
||||
template<Unit U>
|
||||
requires(convertible(Self{}, detail::get_dimension_for(U{})))
|
||||
[[nodiscard]] constexpr reference<Self, U> operator[](U) const
|
||||
{
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
namespace detail {
|
||||
|
||||
@@ -223,13 +266,13 @@ inline constexpr bool is_derived_dimension<T> = true;
|
||||
* Dimension for which all the exponents of the factors corresponding to the base
|
||||
* dimensions are zero. Also commonly named as "dimensionless".
|
||||
*/
|
||||
inline constexpr struct one_dim : derived_dimension<> {
|
||||
} one_dim;
|
||||
inline constexpr struct dimensionless : derived_dimension<> {
|
||||
} dimensionless;
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<>
|
||||
inline constexpr bool is_one_dim<struct one_dim> = true;
|
||||
inline constexpr bool is_dimensionless<struct dimensionless> = true;
|
||||
|
||||
template<Dimension T>
|
||||
struct dim_type_impl {
|
||||
@@ -252,14 +295,14 @@ using dim_type = dim_type_impl<T>::type;
|
||||
template<Dimension Lhs, Dimension Rhs>
|
||||
[[nodiscard]] consteval Dimension auto operator*(Lhs, Rhs)
|
||||
{
|
||||
return detail::expr_multiply<derived_dimension, struct one_dim, detail::type_list_of_base_dimension_less>(
|
||||
return detail::expr_multiply<derived_dimension, struct dimensionless, detail::type_list_of_base_dimension_less>(
|
||||
detail::dim_type<Lhs>{}, detail::dim_type<Rhs>{});
|
||||
}
|
||||
|
||||
template<Dimension Lhs, Dimension Rhs>
|
||||
[[nodiscard]] consteval Dimension auto operator/(Lhs, Rhs)
|
||||
{
|
||||
return detail::expr_divide<derived_dimension, struct one_dim, detail::type_list_of_base_dimension_less>(
|
||||
return detail::expr_divide<derived_dimension, struct dimensionless, detail::type_list_of_base_dimension_less>(
|
||||
detail::dim_type<Lhs>{}, detail::dim_type<Rhs>{});
|
||||
}
|
||||
|
||||
@@ -267,7 +310,7 @@ template<Dimension D>
|
||||
[[nodiscard]] consteval Dimension auto operator/(int value, D)
|
||||
{
|
||||
gsl_Expects(value == 1);
|
||||
return detail::expr_invert<derived_dimension, struct one_dim>(detail::dim_type<D>{});
|
||||
return detail::expr_invert<derived_dimension, struct dimensionless>(detail::dim_type<D>{});
|
||||
}
|
||||
|
||||
template<Dimension D>
|
||||
@@ -304,9 +347,38 @@ template<std::intmax_t Num, std::intmax_t Den = 1, Dimension D>
|
||||
else
|
||||
return derived_dimension<power<D, Num, Den>>{};
|
||||
} else
|
||||
return detail::expr_pow<Num, Den, derived_dimension, struct one_dim, detail::type_list_of_base_dimension_less>(d);
|
||||
return detail::expr_pow<Num, Den, derived_dimension, struct dimensionless,
|
||||
detail::type_list_of_base_dimension_less>(d);
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<Unit U>
|
||||
[[nodiscard]] consteval Dimension auto get_dimension_for_impl(U)
|
||||
requires requires { U::base_dimension; }
|
||||
{
|
||||
return U::base_dimension;
|
||||
}
|
||||
|
||||
template<Unit U>
|
||||
requires requires { U::base_dimension; }
|
||||
using to_base_dimension = std::remove_const_t<decltype(U::base_dimension)>;
|
||||
|
||||
template<typename... Us>
|
||||
[[nodiscard]] consteval Dimension auto get_dimension_for_impl(const derived_unit<Us...>& u)
|
||||
{
|
||||
return detail::expr_map<to_base_dimension, derived_dimension, struct dimensionless,
|
||||
detail::type_list_of_base_dimension_less>(u);
|
||||
}
|
||||
|
||||
[[nodiscard]] consteval Dimension auto get_dimension_for(Unit auto u)
|
||||
{
|
||||
return get_dimension_for_impl(get_canonical_unit(u).reference_unit);
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
|
||||
// TODO consider adding the support for text output of the dimensional equation
|
||||
|
||||
} // namespace units
|
||||
@@ -327,3 +399,26 @@ struct common_type<D1, D2> {
|
||||
};
|
||||
|
||||
} // namespace std
|
||||
|
||||
|
||||
#ifdef __cpp_explicit_this_parameter__
|
||||
|
||||
#define BASE_DIMENSION(name, symbol) \
|
||||
inline constexpr struct name : base_dimension<symbol> { \
|
||||
} name
|
||||
|
||||
#define DERIVED_DIMENSION(name, base) \
|
||||
inline constexpr struct name : base { \
|
||||
} name
|
||||
|
||||
#else
|
||||
|
||||
#define BASE_DIMENSION(name, symbol) \
|
||||
inline constexpr struct name : base_dimension<name, symbol> { \
|
||||
} name
|
||||
|
||||
#define DERIVED_DIMENSION(name, base) \
|
||||
inline constexpr struct name : derived_dimension<name, base> { \
|
||||
} name
|
||||
|
||||
#endif
|
||||
|
@@ -48,7 +48,7 @@ inline constexpr auto make_quantity = [](Representation auto&& v) {
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
concept quantity_one = Quantity<T> && (T::dimension == one_dim) && (T::unit == one);
|
||||
concept quantity_one = Quantity<T> && (T::dimension == dimensionless) && (T::unit == one);
|
||||
|
||||
} // namespace detail
|
||||
|
||||
@@ -506,7 +506,7 @@ template<Quantity Q1, Quantity Q2>
|
||||
|
||||
template<Quantity Q1, Quantity Q2>
|
||||
requires(!floating_point_<typename Q1::rep>) && (!floating_point_<typename Q2::rep>) &&
|
||||
(std::convertible_to<Q2, Q1> || quantity_of<Q2, one_dim>) &&
|
||||
(std::convertible_to<Q2, Q1> || quantity_of<Q2, dimensionless>) &&
|
||||
(quantity_value_for_<std::modulus<>, typename Q1::rep, typename Q2::rep>)
|
||||
[[nodiscard]] constexpr Quantity auto operator%(const Q1& lhs, const Q2& rhs)
|
||||
{
|
||||
|
@@ -162,9 +162,6 @@ struct system_reference {
|
||||
}
|
||||
};
|
||||
|
||||
inline constexpr struct dimensionless : system_reference<one_dim, one> {
|
||||
} dimensionless;
|
||||
|
||||
} // namespace units
|
||||
|
||||
namespace std {
|
||||
|
@@ -29,19 +29,52 @@
|
||||
#include <units/bits/external/type_name.h>
|
||||
#include <units/bits/external/type_traits.h>
|
||||
#include <units/magnitude.h>
|
||||
#include <units/ratio.h>
|
||||
#include <units/symbol_text.h>
|
||||
#include <iterator>
|
||||
#include <string>
|
||||
|
||||
// #include <units/bits/derived_symbol_text.h>
|
||||
|
||||
// IWYU pragma: begin_exports
|
||||
// #include <units/bits/absolute_magnitude.h>
|
||||
// #include <units/ratio.h>
|
||||
// IWYU pragma: end_exports
|
||||
|
||||
namespace units {
|
||||
|
||||
#ifdef __cpp_explicit_this_parameter__
|
||||
template<basic_fixed_string Symbol>
|
||||
#else
|
||||
template<typename Self, basic_fixed_string Symbol>
|
||||
#endif
|
||||
struct base_dimension;
|
||||
|
||||
namespace detail {
|
||||
|
||||
#ifdef __cpp_explicit_this_parameter__
|
||||
template<basic_fixed_string Symbol>
|
||||
void to_base_base_dimension(const volatile base_dimension<Symbol>*);
|
||||
#else
|
||||
template<typename Self, basic_fixed_string Symbol>
|
||||
void to_base_base_dimension(const volatile base_dimension<Self, Symbol>*);
|
||||
#endif
|
||||
|
||||
template<typename T>
|
||||
inline constexpr bool is_specialization_of_base_dimension = false;
|
||||
|
||||
#ifdef __cpp_explicit_this_parameter__
|
||||
template<basic_fixed_string Symbol>
|
||||
inline constexpr bool is_specialization_of_base_dimension<base_dimension<Symbol>> = true;
|
||||
#else
|
||||
template<typename Self, basic_fixed_string Symbol>
|
||||
inline constexpr bool is_specialization_of_base_dimension<base_dimension<Self, Symbol>> = true;
|
||||
#endif
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/**
|
||||
* @brief A concept matching all named base dimensions in the library.
|
||||
*
|
||||
* Satisfied by all dimension types derived from a specialization of `base_dimension`.
|
||||
*/
|
||||
template<typename T>
|
||||
concept BaseDimension = requires(T* t) { detail::to_base_base_dimension(t); } &&
|
||||
(!detail::is_specialization_of_base_dimension<T>);
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<typename T>
|
||||
@@ -86,14 +119,16 @@ inline constexpr bool is_specialization_of_scaled_unit<scaled_unit<M, U>> = true
|
||||
/**
|
||||
* @brief A named unit
|
||||
*
|
||||
* Defines a unit with a special name.
|
||||
* Defines a unit with a special name. It may be used to provide a base unit in the system
|
||||
* of units (i.e. `metre`) or a name assigned to another scaled or derived unit
|
||||
* (i.e. `hour`, `joule`).
|
||||
* Most of the named units may be composed with a prefix to create a `prefixed_unit`.
|
||||
*
|
||||
* For example:
|
||||
*
|
||||
* @code{.cpp}
|
||||
* inline constexpr struct second : named_unit<"s"> {} second;
|
||||
* inline constexpr struct metre : named_unit<"m"> {} metre;
|
||||
* inline constexpr struct second : named_unit<"s", time> {} second;
|
||||
* inline constexpr struct metre : named_unit<"m", length> {} metre;
|
||||
* inline constexpr struct hertz : named_unit<"Hz", 1 / second> {} hertz;
|
||||
* inline constexpr struct newton : named_unit<"N", kilogram * metre / square<second>> {} newton;
|
||||
* inline constexpr struct degree_Celsius : named_unit<basic_symbol_text{"\u00B0C", "`C"}, kelvin> {} degree_Celsius;
|
||||
@@ -111,11 +146,33 @@ template<basic_symbol_text Symbol, auto...>
|
||||
struct named_unit;
|
||||
|
||||
/**
|
||||
* @brief Specialization for base unit
|
||||
* @brief Specialization for unit of a specified base dimension
|
||||
*
|
||||
* Defines a base unit in the system of units (i.e. `metre`).
|
||||
* or a name assigned to another scaled or derived unit (i.e. `hour`, `joule`).
|
||||
* Most of the named units may be composed with a prefix to create a `prefixed_unit`.
|
||||
* This is the preferred way to define a measurement unit for a base dimension. For example `si::metre`
|
||||
* is a unit to measure `isq::length` in the SI system.
|
||||
*
|
||||
* @note It does not have to (or sometimes even can't) be a proper system's base unit. For example
|
||||
* a base unit of mass in the SI is `si::kilogram` but here you are about to provide an `si::gram`
|
||||
* and it will work just fine as those two are convertible to each other. A similar case would be
|
||||
* the `cgs::centimetre` that is a base unit for `isq::length` in the CGS system.
|
||||
*
|
||||
* @tparam Symbol a short text representation of the unit
|
||||
* @tparam BaseDimension base dimension measured with this unit
|
||||
*/
|
||||
template<basic_symbol_text Symbol, BaseDimension auto D>
|
||||
requires(!Symbol.empty())
|
||||
struct named_unit<Symbol, D> {
|
||||
static constexpr auto symbol = Symbol; ///< Unique base unit identifier
|
||||
static constexpr auto base_dimension = D;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Specialization for a unit that can be reused by several base dimensions
|
||||
*
|
||||
* This specialization is used in rare cases where more than one base dimension in a specific
|
||||
* system of units uses the same unit. For example in a hypothetical system of units where
|
||||
* constant for speed of light `c = 1`, length and time could be measured in seconds. In such
|
||||
* cases `system_reference` has to be used to explicitly express such a binding.
|
||||
*
|
||||
* @tparam Symbol a short text representation of the unit
|
||||
*/
|
||||
@@ -319,6 +376,9 @@ struct canonical_unit {
|
||||
U reference_unit;
|
||||
};
|
||||
|
||||
template<Unit T, basic_symbol_text Symbol, BaseDimension auto D>
|
||||
[[nodiscard]] consteval auto get_canonical_unit_impl(T t, const named_unit<Symbol, D>&);
|
||||
|
||||
template<Unit T, basic_symbol_text Symbol>
|
||||
[[nodiscard]] consteval auto get_canonical_unit_impl(T t, const named_unit<Symbol>&);
|
||||
|
||||
@@ -338,6 +398,12 @@ template<Unit T, auto M, typename U>
|
||||
return canonical_unit{M * base.mag, base.reference_unit};
|
||||
}
|
||||
|
||||
template<Unit T, basic_symbol_text Symbol, BaseDimension auto D>
|
||||
[[nodiscard]] consteval auto get_canonical_unit_impl(T t, const named_unit<Symbol, D>&)
|
||||
{
|
||||
return canonical_unit{mag<1>, t};
|
||||
}
|
||||
|
||||
template<Unit T, basic_symbol_text Symbol>
|
||||
[[nodiscard]] consteval auto get_canonical_unit_impl(T t, const named_unit<Symbol>&)
|
||||
{
|
||||
|
@@ -26,15 +26,13 @@
|
||||
|
||||
namespace units::isq {
|
||||
|
||||
// clang-format off
|
||||
inline constexpr struct length_dim : base_dimension<"L"> {} length_dim;
|
||||
inline constexpr struct mass_dim : base_dimension<"M"> {} mass_dim;
|
||||
inline constexpr struct time_dim : base_dimension<"T"> {} time_dim;
|
||||
inline constexpr struct electric_current_dim : base_dimension<"I"> {} electric_current_dim;
|
||||
BASE_DIMENSION(length, "L");
|
||||
BASE_DIMENSION(mass, "M");
|
||||
BASE_DIMENSION(time, "T");
|
||||
BASE_DIMENSION(electric_current, "I");
|
||||
// TODO Should the below use basic_symbol_text? How to name it for ASCII?
|
||||
inline constexpr struct thermodynamic_temperature_dim : base_dimension<"Θ"> {} thermodynamic_temperature_dim;
|
||||
inline constexpr struct amount_of_substance_dim : base_dimension<"N"> {} amount_of_substance_dim;
|
||||
inline constexpr struct luminous_intensity_dim : base_dimension<"J"> {} luminous_intensity_dim;
|
||||
// clang-format on
|
||||
BASE_DIMENSION(thermodynamic_temperature, "Θ");
|
||||
BASE_DIMENSION(amount_of_substance, "N");
|
||||
BASE_DIMENSION(luminous_intensity, "J");
|
||||
|
||||
} // namespace units::isq
|
||||
|
@@ -28,45 +28,45 @@
|
||||
|
||||
namespace units::isq {
|
||||
|
||||
// clang-format off
|
||||
// inline constexpr struct mass_dim : base_dimension<"M"> {} mass_dim;
|
||||
inline constexpr struct mass_density_dim : decltype(mass_dim / volume_dim) {} mass_density_dim;
|
||||
inline constexpr struct specific_volume_dim : decltype(1 / mass_density_dim) {} specific_volume_dim;
|
||||
inline constexpr struct relative_mass_density_dim : decltype(mass_density_dim / mass_density_dim) {} relative_mass_density_dim;
|
||||
inline constexpr struct surface_mass_density_dim : decltype(mass_dim / area_dim) {} surface_mass_density_dim;
|
||||
inline constexpr struct linear_mass_density_dim : decltype(mass_dim / length_dim) {} linear_mass_density_dim;
|
||||
inline constexpr struct momentum_dim : decltype(mass_dim * speed_dim) {} momentum_dim; // TODO velocity_dim?
|
||||
inline constexpr struct force_dim : decltype(mass_dim * acceleration_dim) {} force_dim; // TODO what is a correct equation here?
|
||||
// inline constexpr struct weight_dim : decltype(mass_dim * acceleration_dim) {} weight_dim; // TODO should we add it as a quantity or should it be a quantity_kind?
|
||||
// TODO Should we add other forces as well: static_friction_force, kinematic_friction_force, rolling_resistance, drag_force
|
||||
inline constexpr struct impulse_dim : decltype(force_dim / time_dim) {} impulse_dim;
|
||||
inline constexpr struct angular_momentum_dim : decltype(length_dim * momentum_dim) {} angular_momentum_dim; // TODO position_vector
|
||||
inline constexpr struct moment_of_inertia_dim : decltype(angular_momentum_dim * angular_velocity_dim) {} moment_of_inertia_dim;
|
||||
inline constexpr struct moment_of_force_dim : decltype(length_dim * force_dim) {} moment_of_force_dim; // TODO position_vector
|
||||
inline constexpr struct torque_dim : decltype(moment_of_force_dim) {} torque_dim; // TODO angle?
|
||||
inline constexpr struct angular_impulse_dim : decltype(moment_of_force_dim * time_dim) {} angular_impulse_dim;
|
||||
inline constexpr struct pressure_dim : decltype(force_dim / area_dim) {} pressure_dim;
|
||||
inline constexpr struct stress_dim : decltype(pressure_dim) {} stress_dim; // TODO tensor?
|
||||
inline constexpr struct normal_stress_dim : decltype(force_dim / area_dim) {} normal_stress_dim;
|
||||
inline constexpr struct strain_dim : decltype(stress_dim / stress_dim) {} strain_dim; // TODO what is a correct equation here?
|
||||
inline constexpr struct poisson_number_dim : decltype(length_dim / length_dim) {} poisson_number_dim; // TODO width?
|
||||
// inline constexpr struct mass : base_dimension<"M"> {} mass;
|
||||
DERIVED_DIMENSION(mass_density, decltype(mass / volume));
|
||||
DERIVED_DIMENSION(specific_volume, decltype(1 / mass_density));
|
||||
DERIVED_DIMENSION(relative_mass_density, decltype(mass_density / mass_density));
|
||||
DERIVED_DIMENSION(surface_mass_density, decltype(mass / area));
|
||||
DERIVED_DIMENSION(linear_mass_density, decltype(mass / length));
|
||||
DERIVED_DIMENSION(momentum, decltype(mass * speed)); // TODO velocity?
|
||||
DERIVED_DIMENSION(force, decltype(mass * acceleration)); // TODO what is a correct equation here?
|
||||
// DERIVED_DIMENSION(weight, decltype(mass * acceleration)); // TODO should we add it as a quantity or should it be a
|
||||
// quantity_kind?
|
||||
// TODO Should we add other forces as well: static_friction_force, kinematic_friction_force, rolling_resistance,
|
||||
// drag_force
|
||||
DERIVED_DIMENSION(impulse, decltype(force / time));
|
||||
DERIVED_DIMENSION(angular_momentum, decltype(length * momentum)); // TODO position_vector
|
||||
DERIVED_DIMENSION(moment_of_inertia, decltype(angular_momentum * angular_velocity));
|
||||
DERIVED_DIMENSION(moment_of_force, decltype(length * force)); // TODO position_vector
|
||||
DERIVED_DIMENSION(torque, decltype(moment_of_force)); // TODO angle?
|
||||
DERIVED_DIMENSION(angular_impulse, decltype(moment_of_force * time));
|
||||
DERIVED_DIMENSION(pressure, decltype(force / area));
|
||||
DERIVED_DIMENSION(stress, decltype(pressure)); // TODO tensor?
|
||||
DERIVED_DIMENSION(normal_stress, decltype(force / area));
|
||||
DERIVED_DIMENSION(strain, decltype(stress / stress)); // TODO what is a correct equation here?
|
||||
DERIVED_DIMENSION(poisson_number, decltype(length / length)); // TODO width?
|
||||
// TODO modulus quantities
|
||||
inline constexpr struct compressibility_dim : decltype(volume_dim / pressure_dim) {} compressibility_dim;
|
||||
inline constexpr struct second_axial_moment_of_area_dim : decltype(area_dim * area_dim) {} second_axial_moment_of_area_dim; // TODO what is a correct equation here?
|
||||
inline constexpr struct section_modulus_dim : decltype(second_axial_moment_of_area_dim / length_dim) {} section_modulus_dim; // TODO radial distance
|
||||
DERIVED_DIMENSION(compressibility, decltype(volume / pressure));
|
||||
DERIVED_DIMENSION(second_axial_moment_of_area, decltype(area * area)); // TODO what is a correct equation here?
|
||||
DERIVED_DIMENSION(section_modulus, decltype(second_axial_moment_of_area / length)); // TODO radial distance
|
||||
// TODO friction coefficients?
|
||||
inline constexpr struct dynamic_viscosity_dim : decltype(stress_dim * length_dim / speed_dim) {} dynamic_viscosity_dim; // TODO shear stress, velocity
|
||||
inline constexpr struct kinematic_viscosity_dim : decltype(dynamic_viscosity_dim / mass_density_dim) {} kinematic_viscosity_dim;
|
||||
inline constexpr struct surface_tension_dim : decltype(force_dim / length_dim) {} surface_tension_dim; // TODO what is a correct equation here?
|
||||
inline constexpr struct power_dim : decltype(force_dim * speed_dim) {} power_dim;
|
||||
// TODO what about energy (potential and kinetic as separate quantities will prevent an equation for mechanical one, is it expected?)
|
||||
inline constexpr struct efficiency_dim : decltype(power_dim / power_dim) {} efficiency_dim;
|
||||
inline constexpr struct mass_flow_dim : decltype(mass_density_dim * speed_dim) {} mass_flow_dim; // TODO velocity
|
||||
inline constexpr struct mass_flow_rate_dim : decltype(mass_flow_dim * area_dim) {} mass_flow_rate_dim;
|
||||
inline constexpr struct mass_change_rate_dim : decltype(mass_dim / time_dim) {} mass_change_rate_dim;
|
||||
inline constexpr struct volume_flow_rate_dim : decltype(speed_dim * area_dim) {} volume_flow_rate_dim; // TODO velocity
|
||||
// inline constexpr struct action_dim : decltype(energy_dim * time_dim) {} action_dim; // TODO make it compile
|
||||
|
||||
// clang-format on
|
||||
DERIVED_DIMENSION(dynamic_viscosity, decltype(stress * length / speed)); // TODO shear stress, velocity
|
||||
DERIVED_DIMENSION(kinematic_viscosity, decltype(dynamic_viscosity / mass_density));
|
||||
DERIVED_DIMENSION(surface_tension, decltype(force / length)); // TODO what is a correct equation here?
|
||||
DERIVED_DIMENSION(power, decltype(force * speed));
|
||||
// TODO what about energy (potential and kinetic as separate quantities will prevent an equation for mechanical one, is
|
||||
// it expected?)
|
||||
DERIVED_DIMENSION(efficiency, decltype(power / power));
|
||||
DERIVED_DIMENSION(mass_flow, decltype(mass_density * speed)); // TODO velocity
|
||||
DERIVED_DIMENSION(mass_flow_rate, decltype(mass_flow * area));
|
||||
DERIVED_DIMENSION(mass_change_rate, decltype(mass / time));
|
||||
DERIVED_DIMENSION(volume_flow_rate, decltype(speed * area)); // TODO velocity
|
||||
// DERIVED_DIMENSION(action, decltype(energy * time)); // TODO make it compile
|
||||
|
||||
} // namespace units::isq
|
||||
|
@@ -27,42 +27,40 @@
|
||||
|
||||
namespace units::isq {
|
||||
|
||||
// clang-format off
|
||||
// inline constexpr struct length_dim : base_dimension<"L"> {} length_dim;
|
||||
inline constexpr struct curvature_dim : decltype(1 / length_dim) {} curvature_dim;
|
||||
inline constexpr struct area_dim : decltype(length_dim * length_dim) {} area_dim;
|
||||
inline constexpr struct volume_dim : decltype(length_dim * length_dim * length_dim) {} volume_dim;
|
||||
inline constexpr struct angular_measure_dim : decltype(length_dim / length_dim) {} angular_measure_dim;
|
||||
inline constexpr struct angular_displacement_dim : decltype(length_dim / length_dim) {} angular_displacement_dim;
|
||||
inline constexpr struct phase_angle_dim : decltype(length_dim / length_dim) {} phase_angle_dim;
|
||||
inline constexpr struct solid_angular_measure_dim : decltype(area_dim / (length_dim * length_dim)) {} solid_angular_measure_dim;
|
||||
// inline constexpr struct time_dim : base_dimension<"T"> {} time_dim; // TODO called duration in ISO 80000
|
||||
// inline constexpr struct length : base_dimension<"L"> {} length;
|
||||
DERIVED_DIMENSION(curvature, decltype(1 / length));
|
||||
DERIVED_DIMENSION(area, decltype(length * length));
|
||||
DERIVED_DIMENSION(volume, decltype(length * length * length));
|
||||
DERIVED_DIMENSION(angular_measure, decltype(length / length));
|
||||
DERIVED_DIMENSION(angular_displacement, decltype(length / length));
|
||||
DERIVED_DIMENSION(phase_angle, decltype(length / length));
|
||||
inline constexpr struct solid_angular_measure : decltype(area / (length * length)) {
|
||||
} solid_angular_measure;
|
||||
// inline constexpr struct time : base_dimension<"T"> {} time; // TODO called duration in ISO 80000
|
||||
// TODO there is also a velocity in ISO 80000
|
||||
inline constexpr struct speed_dim : decltype(length_dim / time_dim) {} speed_dim;
|
||||
inline constexpr struct acceleration_dim : decltype(speed_dim / time_dim) {} acceleration_dim;
|
||||
inline constexpr struct angular_velocity_dim : decltype(angular_displacement_dim / time_dim) {} angular_velocity_dim;
|
||||
inline constexpr struct angular_acceleration_dim : decltype(angular_velocity_dim / time_dim) {} angular_acceleration_dim;
|
||||
inline constexpr struct period_duration_dim : time_dim {} period_duration_dim;
|
||||
inline constexpr struct time_constant_dim : time_dim {} time_constant_dim;
|
||||
inline constexpr struct rotation_dim : angular_displacement_dim {} rotation_dim;
|
||||
inline constexpr struct frequency_dim : decltype(1 / time_dim) {} frequency_dim;
|
||||
inline constexpr struct rotational_frequency_dim : decltype(rotation_dim / time_dim) {} rotational_frequency_dim;
|
||||
inline constexpr struct angular_frequency_dim : decltype(angular_measure_dim / time_dim) {} angular_frequency_dim;
|
||||
inline constexpr struct wavelength_dim : length_dim {} wavelength_dim;
|
||||
inline constexpr struct repetency_dim : decltype(1 / wavelength_dim) {} repetency_dim;
|
||||
inline constexpr struct wave_vector_dim : decltype(1 / length_dim) {} wave_vector_dim;
|
||||
inline constexpr struct angular_repetency_dim : decltype(1 / wavelength_dim) {} angular_repetency_dim;
|
||||
inline constexpr struct phase_velocity_dim : decltype(angular_frequency_dim / angular_repetency_dim) {} phase_velocity_dim;
|
||||
inline constexpr struct damping_coefficient_dim : decltype(1 / time_constant_dim) {} damping_coefficient_dim;
|
||||
inline constexpr struct logarithmic_decrement_dim : decltype(damping_coefficient_dim * period_duration_dim) {} logarithmic_decrement_dim;
|
||||
inline constexpr struct attenuation_dim : decltype(1 / length_dim) {} attenuation_dim;
|
||||
inline constexpr struct phase_coefficient_dim : decltype(phase_angle_dim / length_dim) {} phase_coefficient_dim;
|
||||
inline constexpr struct propagation_coefficient_dim : decltype(1 / length_dim) {} propagation_coefficient_dim;
|
||||
// clang-format on
|
||||
DERIVED_DIMENSION(speed, decltype(length / time));
|
||||
DERIVED_DIMENSION(acceleration, decltype(speed / time));
|
||||
DERIVED_DIMENSION(angular_velocity, decltype(angular_displacement / time));
|
||||
DERIVED_DIMENSION(angular_acceleration, decltype(angular_velocity / time));
|
||||
inline constexpr struct period_duration : time {
|
||||
} period_duration;
|
||||
inline constexpr struct time_constant : time {
|
||||
} time_constant;
|
||||
inline constexpr struct rotation : angular_displacement {
|
||||
} rotation;
|
||||
DERIVED_DIMENSION(frequency, decltype(1 / time));
|
||||
DERIVED_DIMENSION(rotational_frequency, decltype(rotation / time));
|
||||
DERIVED_DIMENSION(angular_frequency, decltype(angular_measure / time));
|
||||
inline constexpr struct wavelength : length {
|
||||
} wavelength;
|
||||
DERIVED_DIMENSION(repetency, decltype(1 / wavelength));
|
||||
DERIVED_DIMENSION(wave_vector, decltype(1 / length));
|
||||
DERIVED_DIMENSION(angular_repetency, decltype(1 / wavelength));
|
||||
DERIVED_DIMENSION(phase_velocity, decltype(angular_frequency / angular_repetency));
|
||||
DERIVED_DIMENSION(damping_coefficient, decltype(1 / time_constant));
|
||||
DERIVED_DIMENSION(logarithmic_decrement, decltype(damping_coefficient * period_duration));
|
||||
DERIVED_DIMENSION(attenuation, decltype(1 / length));
|
||||
DERIVED_DIMENSION(phase_coefficient, decltype(phase_angle / length));
|
||||
DERIVED_DIMENSION(propagation_coefficient, decltype(1 / length));
|
||||
|
||||
} // namespace units::isq
|
||||
|
||||
|
||||
// inline constexpr struct force_dim : decltype(mass_dim * acceleration_dim) {} force_dim;
|
||||
// inline constexpr struct energy_dim : decltype(force_dim * length_dim) {} energy_dim;
|
||||
// inline constexpr struct power_dim : decltype(force_dim * speed_dim) {} power_dim;
|
||||
|
@@ -28,15 +28,12 @@
|
||||
|
||||
namespace units::isq {
|
||||
|
||||
// clang-format off
|
||||
// inline constexpr struct thermodynamic_temperature_dim : base_dimension<"Θ"> {} thermodynamic_temperature_dim;
|
||||
// inline constexpr struct thermodynamic_temperature : base_dimension<"Θ"> {} thermodynamic_temperature;
|
||||
// TODO Celsius temperature???
|
||||
|
||||
// inline constexpr struct mass_density_dim : decltype(mass_dim / volume_dim) {} mass_density_dim;
|
||||
// DERIVED_DIMENSION(mass_density, decltype(mass / volume));
|
||||
|
||||
|
||||
inline constexpr struct energy_dim : decltype(force_dim * length_dim) {} energy_dim;
|
||||
|
||||
// clang-format on
|
||||
DERIVED_DIMENSION(energy, decltype(force * length));
|
||||
|
||||
} // namespace units::isq
|
||||
|
@@ -42,16 +42,6 @@ inline constexpr struct poise : named_unit<"P", gram / (centimetre * second)> {}
|
||||
inline constexpr struct stokes : named_unit<"St", square<centimetre> / second> {} stokes;
|
||||
inline constexpr struct kayser : decltype(1 / centimetre) {} kayser;
|
||||
|
||||
inline constexpr struct length : system_reference<isq::length_dim, centimetre> {} length;
|
||||
inline constexpr struct mass : system_reference<isq::mass_dim, gram> {} mass;
|
||||
inline constexpr struct time : system_reference<isq::time_dim, second> {} time;
|
||||
inline constexpr struct speed : system_reference<isq::speed_dim, centimetre / second> {} speed;
|
||||
inline constexpr struct acceleration : system_reference<isq::acceleration_dim, gal> {} acceleration;
|
||||
inline constexpr struct force : system_reference<isq::force_dim, dyne> {} force;inline constexpr struct energy : system_reference<isq::energy_dim, erg> {} energy;
|
||||
inline constexpr struct power : system_reference<isq::power_dim, erg / second> {} power;
|
||||
inline constexpr struct dynamic_viscosity : system_reference<isq::dynamic_viscosity_dim, poise> {} dynamic_viscosity;
|
||||
inline constexpr struct kinematic_viscosity : system_reference<isq::kinematic_viscosity_dim, stokes> {} kinematic_viscosity;
|
||||
// inline constexpr struct wavenumber : system_reference<isq::wavenumber_dim, dyne> {} wavenumber;
|
||||
// clang-format on
|
||||
|
||||
} // namespace units::si::cgs
|
||||
|
@@ -23,15 +23,7 @@
|
||||
cmake_minimum_required(VERSION 3.19)
|
||||
|
||||
add_units_module(
|
||||
si
|
||||
DEPENDENCIES mp-units::isq
|
||||
HEADERS include/units/si/base_quantities.h
|
||||
include/units/si/constants.h
|
||||
include/units/si/mechanics.h
|
||||
include/units/si/prefixes.h
|
||||
include/units/si/si.h
|
||||
include/units/si/space_and_time.h
|
||||
include/units/si/thermodynamics.h
|
||||
include/units/si/unit_symbols.h
|
||||
include/units/si/units.h
|
||||
si DEPENDENCIES mp-units::isq
|
||||
HEADERS include/units/si/constants.h include/units/si/prefixes.h include/units/si/si.h
|
||||
include/units/si/unit_symbols.h include/units/si/units.h
|
||||
)
|
||||
|
@@ -1,43 +0,0 @@
|
||||
// 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <units/isq/base_dimensions.h>
|
||||
#include <units/reference.h>
|
||||
#include <units/si/units.h>
|
||||
|
||||
namespace units::si {
|
||||
|
||||
// inline constexpr struct time : system_reference<isq::time_dim, second> {} time;
|
||||
// inline constexpr struct length : system_reference<isq::length_dim, metre> {} length;
|
||||
// inline constexpr struct mass : system_reference<isq::mass_dim, kilogram> {} mass;
|
||||
inline constexpr struct electric_current : system_reference<isq::electric_current_dim, ampere> {
|
||||
} electric_current;
|
||||
inline constexpr struct thermodynamic_temperature : system_reference<isq::thermodynamic_temperature_dim, kelvin> {
|
||||
} thermodynamic_temperature;
|
||||
inline constexpr struct amount_of_substance : system_reference<isq::amount_of_substance_dim, kilogram> {
|
||||
} amount_of_substance;
|
||||
inline constexpr struct luminous_intensity : system_reference<isq::luminous_intensity_dim, candela> {
|
||||
} luminous_intensity;
|
||||
|
||||
} // namespace units::si
|
@@ -22,10 +22,10 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <units/isq/mechanics.h>
|
||||
#include <units/isq/space_and_time.h>
|
||||
#include <units/isq/thermodynamics.h>
|
||||
#include <units/quantity.h>
|
||||
#include <units/si/mechanics.h>
|
||||
#include <units/si/space_and_time.h>
|
||||
#include <units/si/thermodynamics.h>
|
||||
#include <units/si/units.h>
|
||||
|
||||
namespace units::si {
|
||||
@@ -38,10 +38,10 @@ inline constexpr struct mag_speed_of_light : decltype(mag<299'792'458>) {} mag_s
|
||||
// clang-format on
|
||||
|
||||
template<typename Rep = double>
|
||||
inline constexpr auto planck_constant = Rep{1} * (mag_planck * energy[joule] * time[second]);
|
||||
inline constexpr auto planck_constant = Rep{1} * (mag_planck * isq::energy[joule] * isq::time[second]);
|
||||
|
||||
template<typename Rep = double>
|
||||
inline constexpr auto speed_of_light = Rep{1} * speed[mag_speed_of_light * metre / second];
|
||||
inline constexpr auto speed_of_light = Rep{1} * isq::speed[mag_speed_of_light * metre / second];
|
||||
|
||||
// template<Representation Rep = double>
|
||||
// inline constexpr auto planck_constant = energy<joule, Rep>(6.62607015e-34) * time<second, Rep>(1);
|
||||
@@ -75,6 +75,6 @@ inline constexpr struct mag_standard_gravity : decltype(mag<ratio{980'665, 10'00
|
||||
// clang-format on
|
||||
|
||||
template<typename Rep = double>
|
||||
inline constexpr auto standard_gravity = Rep{1} * acceleration[mag_standard_gravity * metre / square<second>];
|
||||
inline constexpr auto standard_gravity = Rep{1} * isq::acceleration[mag_standard_gravity * metre / square<second>];
|
||||
|
||||
} // namespace units::si
|
||||
|
@@ -1,68 +0,0 @@
|
||||
// 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <units/isq/mechanics.h>
|
||||
#include <units/isq/space_and_time.h>
|
||||
#include <units/reference.h>
|
||||
#include <units/si/units.h>
|
||||
|
||||
namespace units::si {
|
||||
|
||||
// clang-format off
|
||||
inline constexpr struct mass : system_reference<isq::mass_dim, kilogram> {} mass;
|
||||
inline constexpr struct mass_density : system_reference<isq::mass_density_dim, kilogram / cubic<metre>> {} mass_density;
|
||||
inline constexpr struct specific_volume : system_reference<isq::specific_volume_dim, cubic<metre> / kilogram> {} specific_volume;
|
||||
inline constexpr struct relative_mass_density : system_reference<isq::relative_mass_density_dim, one> {} relative_mass_density;
|
||||
inline constexpr struct surface_mass_density : system_reference<isq::surface_mass_density_dim, kilogram / square<metre>> {} surface_mass_density;
|
||||
inline constexpr struct linear_mass_density : system_reference<isq::linear_mass_density_dim, kilogram / metre> {} linear_mass_density;
|
||||
inline constexpr struct momentum : system_reference<isq::momentum_dim, kilogram * metre / second> {} momentum;
|
||||
inline constexpr struct force : system_reference<isq::force_dim, newton> {} force;
|
||||
// inline constexpr struct weight : system_reference<isq::weight_dim, newton> {} weight;
|
||||
inline constexpr struct impulse : system_reference<isq::impulse_dim, newton * second> {} impulse;
|
||||
inline constexpr struct angular_momentum : system_reference<isq::angular_momentum_dim, kilogram * square<metre> / second> {} angular_momentum; // TODO radian?
|
||||
inline constexpr struct moment_of_inertia : system_reference<isq::moment_of_inertia_dim, kilogram * square<metre>> {} moment_of_inertia;
|
||||
inline constexpr struct moment_of_force : system_reference<isq::moment_of_force_dim, newton * metre> {} moment_of_force;
|
||||
inline constexpr struct torque : system_reference<isq::torque_dim, newton * metre> {} torque;
|
||||
inline constexpr struct angular_impulse : system_reference<isq::angular_impulse_dim, newton * metre * second> {} angular_impulse;
|
||||
inline constexpr struct pressure : system_reference<isq::pressure_dim, pascal> {} pressure;
|
||||
inline constexpr struct stress : system_reference<isq::stress_dim, pascal> {} stress;
|
||||
inline constexpr struct normal_stress : system_reference<isq::normal_stress_dim, pascal> {} normal_stress;
|
||||
inline constexpr struct strain : system_reference<isq::strain_dim, one> {} strain;
|
||||
inline constexpr struct poisson_number : system_reference<isq::poisson_number_dim, one> {} poisson_number;
|
||||
inline constexpr struct compressibility : system_reference<isq::compressibility_dim, 1 / pascal> {} compressibility;
|
||||
inline constexpr struct second_axial_moment_of_area : system_reference<isq::second_axial_moment_of_area_dim, square<metre> * square<metre>> {} second_axial_moment_of_area;
|
||||
inline constexpr struct section_modulus : system_reference<isq::section_modulus_dim, cubic<metre>> {} section_modulus;
|
||||
inline constexpr struct dynamic_viscosity : system_reference<isq::dynamic_viscosity_dim, pascal * second> {} dynamic_viscosity;
|
||||
inline constexpr struct kinematic_viscosity : system_reference<isq::kinematic_viscosity_dim, square<metre> / second> {} kinematic_viscosity;
|
||||
inline constexpr struct surface_tension : system_reference<isq::surface_tension_dim, newton / metre> {} surface_tension;
|
||||
inline constexpr struct power : system_reference<isq::power_dim, watt> {} power;
|
||||
inline constexpr struct efficiency : system_reference<isq::efficiency_dim, one> {} efficiency;
|
||||
inline constexpr struct mass_flow : system_reference<isq::mass_flow_dim, kilogram / (square<metre> * second)> {} mass_flow;
|
||||
inline constexpr struct mass_flow_rate : system_reference<isq::mass_flow_rate_dim, kilogram / second> {} mass_flow_rate;
|
||||
inline constexpr struct mass_change_rate : system_reference<isq::mass_change_rate_dim, kilogram / second> {} mass_change_rate;
|
||||
inline constexpr struct volume_flow_rate : system_reference<isq::volume_flow_rate_dim, cubic<metre> / second> {} volume_flow_rate;
|
||||
// inline constexpr struct action : system_reference<isq::action_dim, joule* second> {} action; // TODO make it compile
|
||||
// clang-format on
|
||||
|
||||
} // namespace units::si
|
@@ -22,11 +22,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <units/si/base_quantities.h>
|
||||
#include <units/si/constants.h>
|
||||
#include <units/si/mechanics.h>
|
||||
#include <units/si/prefixes.h>
|
||||
#include <units/si/space_and_time.h>
|
||||
#include <units/si/thermodynamics.h>
|
||||
#include <units/si/unit_symbols.h>
|
||||
#include <units/si/units.h>
|
||||
|
@@ -1,64 +0,0 @@
|
||||
// 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <units/isq/space_and_time.h>
|
||||
#include <units/reference.h>
|
||||
#include <units/si/units.h>
|
||||
|
||||
namespace units::si {
|
||||
|
||||
// clang-format off
|
||||
inline constexpr struct length : system_reference<isq::length_dim, metre> {} length;
|
||||
inline constexpr struct curvature : system_reference<isq::curvature_dim, 1 / metre> {} curvature;
|
||||
inline constexpr struct area : system_reference<isq::area_dim, square<metre>> {} area;
|
||||
inline constexpr struct volume : system_reference<isq::volume_dim, cubic<metre>> {} volume;
|
||||
inline constexpr struct angular_measure : system_reference<isq::angular_measure_dim, radian> {} angular_measure;
|
||||
inline constexpr struct angular_displacement : system_reference<isq::angular_displacement_dim, radian> {} angular_displacement;
|
||||
inline constexpr struct phase_angle : system_reference<isq::phase_angle_dim, radian> {} phase_angle;
|
||||
inline constexpr struct solid_angular_measure : system_reference<isq::solid_angular_measure_dim, steradian> {} solid_angular_measure;
|
||||
inline constexpr struct time : system_reference<isq::time_dim, second> {} time; // TODO called duration in ISO 80000
|
||||
// TODO there is also a velocity in ISO 80000
|
||||
inline constexpr struct speed : system_reference<isq::speed_dim, metre / second> {} speed;
|
||||
inline constexpr struct acceleration : system_reference<isq::acceleration_dim, metre / square<second>> {} acceleration;
|
||||
inline constexpr struct angular_velocity : system_reference<isq::angular_velocity_dim, radian / second> {} angular_velocity;
|
||||
inline constexpr struct angular_acceleration : system_reference<isq::angular_acceleration_dim, radian / square<second>> {} angular_acceleration;
|
||||
inline constexpr struct period_duration : system_reference<isq::period_duration_dim, second> {} period_duration;
|
||||
inline constexpr struct time_constant : system_reference<isq::time_constant_dim, second> {} time_constant;
|
||||
inline constexpr struct rotation : system_reference<isq::rotation_dim, one> {} rotation;
|
||||
inline constexpr struct frequency : system_reference<isq::frequency_dim, hertz> {} frequency;
|
||||
inline constexpr struct rotational_frequency : system_reference<isq::rotational_frequency_dim, hertz> {} rotational_frequency;
|
||||
inline constexpr struct angular_frequency : system_reference<isq::angular_frequency_dim, radian / second> {} angular_frequency;
|
||||
inline constexpr struct wavelength : system_reference<isq::wavelength_dim, metre> {} wavelength;
|
||||
inline constexpr struct repetency : system_reference<isq::repetency_dim, 1 / metre> {} repetency;
|
||||
inline constexpr struct wave_vector : system_reference<isq::wave_vector_dim, 1 / metre> {} wave_vector;
|
||||
inline constexpr struct angular_repetency : system_reference<isq::angular_repetency_dim, 1 / metre> {} angular_repetency;
|
||||
inline constexpr struct phase_velocity : system_reference<isq::phase_velocity_dim, metre / second> {} phase_velocity;
|
||||
inline constexpr struct damping_coefficient : system_reference<isq::damping_coefficient_dim, 1 / second> {} damping_coefficient;
|
||||
inline constexpr struct logarithmic_decrement : system_reference<isq::logarithmic_decrement_dim, one> {} logarithmic_decrement;
|
||||
inline constexpr struct attenuation : system_reference<isq::attenuation_dim, 1 / metre> {} attenuation;
|
||||
inline constexpr struct phase_coefficient : system_reference<isq::phase_coefficient_dim, radian / metre> {} phase_coefficient;
|
||||
inline constexpr struct propagation_coefficient : system_reference<isq::propagation_coefficient_dim, 1 / metre> {} propagation_coefficient;
|
||||
// clang-format on
|
||||
|
||||
} // namespace units::si
|
@@ -1,39 +0,0 @@
|
||||
// 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <units/isq/mechanics.h>
|
||||
// #include <units/isq/space_and_time.h>
|
||||
#include <units/isq/thermodynamics.h>
|
||||
#include <units/reference.h>
|
||||
#include <units/si/units.h>
|
||||
|
||||
namespace units::si {
|
||||
|
||||
// inline constexpr struct thermodynamic_temperature : system_reference<isq::thermodynamic_temperature_dim, kelvin> {}
|
||||
// thermodynamic_temperature;
|
||||
|
||||
inline constexpr struct energy : system_reference<isq::energy_dim, joule> {
|
||||
} energy;
|
||||
|
||||
} // namespace units::si
|
@@ -22,6 +22,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <units/isq/base_dimensions.h>
|
||||
#include <units/si/prefixes.h>
|
||||
#include <units/unit.h>
|
||||
|
||||
@@ -29,14 +30,14 @@ namespace units::si {
|
||||
|
||||
// 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 second : named_unit<"s", isq::time> {} second;
|
||||
inline constexpr struct metre : named_unit<"m", isq::length> {} metre;
|
||||
inline constexpr struct gram : named_unit<"g", isq::mass> {} gram;
|
||||
inline constexpr struct kilogram : decltype(kilo<gram>) {} kilogram;
|
||||
inline constexpr struct ampere : named_unit<"A"> {} ampere;
|
||||
inline constexpr struct kelvin : named_unit<"K"> {} kelvin;
|
||||
inline constexpr struct mole : named_unit<"mol"> {} mole;
|
||||
inline constexpr struct candela : named_unit<"cd"> {} candela;
|
||||
inline constexpr struct ampere : named_unit<"A", isq::electric_current> {} ampere;
|
||||
inline constexpr struct kelvin : named_unit<"K", isq::thermodynamic_temperature> {} kelvin;
|
||||
inline constexpr struct mole : named_unit<"mol", isq::amount_of_substance> {} mole;
|
||||
inline constexpr struct candela : named_unit<"cd", isq::luminous_intensity> {} candela;
|
||||
|
||||
// derived named units
|
||||
inline constexpr struct radian : named_unit<"rad", metre / metre> {} radian;
|
||||
@@ -90,7 +91,7 @@ inline constexpr struct electronvolt : named_unit<"eV", mag<ratio{1'602'176'634,
|
||||
namespace units {
|
||||
|
||||
template<>
|
||||
inline constexpr bool unit_can_be_prefixed<si::degree_Celsius> = false;
|
||||
inline constexpr bool unit_can_be_prefixed<si::degree_Celsius> = false; // TODO Is it true?
|
||||
template<>
|
||||
inline constexpr bool unit_can_be_prefixed<si::minute> = false;
|
||||
template<>
|
||||
|
@@ -35,7 +35,6 @@ cmake_minimum_required(VERSION 3.2)
|
||||
add_library(
|
||||
unit_tests_static
|
||||
dimension_test.cpp
|
||||
|
||||
# angle_test.cpp
|
||||
# cgs_test.cpp
|
||||
# chrono_test.cpp
|
||||
@@ -49,7 +48,6 @@ add_library(
|
||||
# iec80000_test.cpp
|
||||
# kind_test.cpp
|
||||
magnitude_test.cpp
|
||||
|
||||
# math_test.cpp
|
||||
# point_origin_test.cpp
|
||||
# prime_test.cpp
|
||||
@@ -62,7 +60,6 @@ add_library(
|
||||
# symbol_text_test.cpp
|
||||
type_list_test.cpp
|
||||
unit_test.cpp
|
||||
|
||||
# us_test.cpp
|
||||
)
|
||||
|
||||
|
@@ -20,206 +20,199 @@
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
#include "test_tools.h"
|
||||
#include <units/dimension.h>
|
||||
|
||||
namespace {
|
||||
|
||||
using namespace units;
|
||||
|
||||
template<auto V, typename T>
|
||||
inline constexpr bool is_of_type = std::is_same_v<std::remove_cvref_t<decltype(V)>, T>;
|
||||
|
||||
using one_dim_ = struct one_dim;
|
||||
using dimensionless_ = struct dimensionless;
|
||||
|
||||
// clang-format off
|
||||
inline constexpr struct length_dim_ : base_dimension<"L"> {} length_dim;
|
||||
inline constexpr struct time_dim_ : base_dimension<"T"> {} time_dim;
|
||||
inline constexpr struct mass_dim_ : base_dimension<"M"> {} mass_dim;
|
||||
BASE_DIMENSION_(length, "L");
|
||||
BASE_DIMENSION_(time, "T");
|
||||
BASE_DIMENSION_(mass, "M");
|
||||
|
||||
inline constexpr struct frequency_dim_ : decltype(1 / time_dim) {} frequency_dim;
|
||||
inline constexpr struct action_dim_ : decltype(1 / time_dim) {} action_dim;
|
||||
inline constexpr struct area_dim_ : decltype(length_dim * length_dim) {} area_dim;
|
||||
inline constexpr struct volume_dim_ : decltype(area_dim * length_dim) {} volume_dim;
|
||||
inline constexpr struct speed_dim_ : decltype(length_dim / time_dim) {} speed_dim;
|
||||
inline constexpr struct velocity_dim_ : speed_dim_ {} velocity_dim;
|
||||
inline constexpr struct acceleration_dim_ : decltype(speed_dim / time_dim) {} acceleration_dim;
|
||||
inline constexpr struct force_dim_ : decltype(mass_dim * acceleration_dim) {} force_dim;
|
||||
inline constexpr struct moment_of_force_dim_ : decltype(length_dim * force_dim) {} moment_of_force_dim;
|
||||
inline constexpr struct torque_dim_ : decltype(moment_of_force_dim) {} torque_dim;
|
||||
inline constexpr struct pressure_dim_ : decltype(force_dim / area_dim) {} pressure_dim;
|
||||
inline constexpr struct stress_dim_ : decltype(pressure_dim) {} stress_dim;
|
||||
inline constexpr struct strain_dim_ : decltype(stress_dim / stress_dim) {} strain_dim;
|
||||
inline constexpr struct power_dim_ : decltype(force_dim * speed_dim) {} power_dim;
|
||||
inline constexpr struct efficiency_dim_ : decltype(power_dim / power_dim) {} efficiency_dim;
|
||||
inline constexpr struct energy_dim_ : decltype(force_dim * length_dim) {} energy_dim;
|
||||
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));
|
||||
inline constexpr struct velocity_ : speed_ {} velocity;
|
||||
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_(pressure, decltype(force / area));
|
||||
DERIVED_DIMENSION_(stress, decltype(pressure));
|
||||
DERIVED_DIMENSION_(strain, decltype(stress / stress));
|
||||
DERIVED_DIMENSION_(power, decltype(force * speed));
|
||||
DERIVED_DIMENSION_(efficiency, decltype(power / power));
|
||||
DERIVED_DIMENSION_(energy, decltype(force * length));
|
||||
// clang-format on
|
||||
|
||||
// concepts verification
|
||||
static_assert(BaseDimension<length_dim_>);
|
||||
static_assert(!BaseDimension<frequency_dim_>);
|
||||
static_assert(!DerivedDimension<length_dim_>);
|
||||
static_assert(DerivedDimension<frequency_dim_>);
|
||||
static_assert(Dimension<length_dim_>);
|
||||
static_assert(Dimension<frequency_dim_>);
|
||||
static_assert(BaseDimension<length_>);
|
||||
static_assert(!BaseDimension<frequency_>);
|
||||
static_assert(!DerivedDimension<length_>);
|
||||
static_assert(DerivedDimension<frequency_>);
|
||||
static_assert(Dimension<length_>);
|
||||
static_assert(Dimension<frequency_>);
|
||||
|
||||
static_assert(DerivedDimension<one_dim_>);
|
||||
static_assert(DerivedDimension<decltype(length_dim / length_dim)>); // one_dim
|
||||
static_assert(BaseDimension<decltype(speed_dim * time_dim)>); // length_dim
|
||||
static_assert(DerivedDimension<dimensionless_>);
|
||||
static_assert(DerivedDimension<decltype(length / length)>); // dimensionless
|
||||
static_assert(BaseDimension<decltype(speed * time)>); // length
|
||||
|
||||
// derived dimension expression template syntax verification
|
||||
static_assert(is_of_type<1 / time_dim, derived_dimension<one_dim_, per<time_dim_>>>);
|
||||
static_assert(is_of_type<1 / (1 / time_dim), time_dim_>);
|
||||
static_assert(is_of_type<1 / time, derived_dimension<dimensionless_, per<time_>>>);
|
||||
static_assert(is_of_type<1 / (1 / time), time_>);
|
||||
|
||||
static_assert(is_of_type<one_dim * time_dim, time_dim_>);
|
||||
static_assert(is_of_type<time_dim * one_dim, time_dim_>);
|
||||
static_assert(is_of_type<one_dim * (1 / time_dim), derived_dimension<one_dim_, per<time_dim_>>>);
|
||||
static_assert(is_of_type<1 / time_dim * one_dim, derived_dimension<one_dim_, per<time_dim_>>>);
|
||||
static_assert(is_of_type<dimensionless * time, time_>);
|
||||
static_assert(is_of_type<time * dimensionless, time_>);
|
||||
static_assert(is_of_type<dimensionless * (1 / time), derived_dimension<dimensionless_, per<time_>>>);
|
||||
static_assert(is_of_type<1 / time * dimensionless, derived_dimension<dimensionless_, per<time_>>>);
|
||||
|
||||
static_assert(is_of_type<length_dim * time_dim, derived_dimension<length_dim_, time_dim_>>);
|
||||
static_assert(is_of_type<length_dim * length_dim, derived_dimension<power<length_dim_, 2>>>);
|
||||
static_assert(is_of_type<length * time, derived_dimension<length_, time_>>);
|
||||
static_assert(is_of_type<length * length, derived_dimension<units::power<length_, 2>>>);
|
||||
|
||||
static_assert(is_of_type<length_dim * length_dim * time_dim, derived_dimension<power<length_dim_, 2>, time_dim_>>);
|
||||
static_assert(is_of_type<length_dim * time_dim * length_dim, derived_dimension<power<length_dim_, 2>, time_dim_>>);
|
||||
static_assert(is_of_type<length * length * time, derived_dimension<units::power<length_, 2>, time_>>);
|
||||
static_assert(is_of_type<length * time * length, derived_dimension<units::power<length_, 2>, time_>>);
|
||||
|
||||
static_assert(is_of_type<length_dim*(time_dim* length_dim), derived_dimension<power<length_dim_, 2>, time_dim_>>);
|
||||
static_assert(is_of_type<time_dim*(length_dim* length_dim), derived_dimension<power<length_dim_, 2>, time_dim_>>);
|
||||
static_assert(is_of_type<length*(time* length), derived_dimension<units::power<length_, 2>, time_>>);
|
||||
static_assert(is_of_type<time*(length* length), derived_dimension<units::power<length_, 2>, time_>>);
|
||||
|
||||
static_assert(is_of_type<1 / time_dim * length_dim, derived_dimension<length_dim_, per<time_dim_>>>);
|
||||
static_assert(is_of_type<1 / time_dim * time_dim, one_dim_>);
|
||||
static_assert(is_of_type<1 / time * length, derived_dimension<length_, per<time_>>>);
|
||||
static_assert(is_of_type<1 / time * time, dimensionless_>);
|
||||
|
||||
static_assert(is_of_type<time_dim / one_dim, time_dim_>);
|
||||
static_assert(is_of_type<1 / time_dim / one_dim, derived_dimension<one_dim_, per<time_dim_>>>);
|
||||
static_assert(is_of_type<time / dimensionless, time_>);
|
||||
static_assert(is_of_type<1 / time / dimensionless, derived_dimension<dimensionless_, per<time_>>>);
|
||||
|
||||
static_assert(is_of_type<length_dim / time_dim * time_dim, length_dim_>);
|
||||
static_assert(is_of_type<1 / time_dim * (1 / time_dim), derived_dimension<one_dim_, per<power<time_dim_, 2>>>>);
|
||||
static_assert(is_of_type<1 / (time_dim * time_dim), derived_dimension<one_dim_, per<power<time_dim_, 2>>>>);
|
||||
static_assert(is_of_type<1 / (1 / (time_dim * time_dim)), derived_dimension<power<time_dim_, 2>>>);
|
||||
static_assert(is_of_type<length / time * time, length_>);
|
||||
static_assert(is_of_type<1 / time * (1 / time), derived_dimension<dimensionless_, per<units::power<time_, 2>>>>);
|
||||
static_assert(is_of_type<1 / (time * time), derived_dimension<dimensionless_, per<units::power<time_, 2>>>>);
|
||||
static_assert(is_of_type<1 / (1 / (time * time)), derived_dimension<units::power<time_, 2>>>);
|
||||
|
||||
static_assert(is_of_type<length / time * (1 / time), derived_dimension<length_, per<units::power<time_, 2>>>>);
|
||||
static_assert(
|
||||
is_of_type<length_dim / time_dim * (1 / time_dim), derived_dimension<length_dim_, per<power<time_dim_, 2>>>>);
|
||||
static_assert(is_of_type<length_dim / time_dim*(length_dim / time_dim),
|
||||
derived_dimension<power<length_dim_, 2>, per<power<time_dim_, 2>>>>);
|
||||
static_assert(is_of_type<length_dim / time_dim*(time_dim / length_dim), one_dim_>);
|
||||
is_of_type<length / time*(length / time), derived_dimension<units::power<length_, 2>, per<units::power<time_, 2>>>>);
|
||||
static_assert(is_of_type<length / time*(time / length), dimensionless_>);
|
||||
|
||||
static_assert(is_of_type<speed_dim / acceleration_dim, time_dim_>);
|
||||
static_assert(is_of_type<acceleration_dim / speed_dim, derived_dimension<one_dim_, per<time_dim_>>>);
|
||||
static_assert(is_of_type<speed_dim * speed_dim / length_dim, derived_dimension<length_dim_, per<power<time_dim_, 2>>>>);
|
||||
static_assert(
|
||||
is_of_type<1 / (speed_dim * speed_dim) * length_dim, derived_dimension<power<time_dim_, 2>, per<length_dim_>>>);
|
||||
static_assert(is_of_type<speed / acceleration, time_>);
|
||||
static_assert(is_of_type<acceleration / speed, derived_dimension<dimensionless_, per<time_>>>);
|
||||
static_assert(is_of_type<speed * speed / length, derived_dimension<length_, per<units::power<time_, 2>>>>);
|
||||
static_assert(is_of_type<1 / (speed * speed) * length, derived_dimension<units::power<time_, 2>, per<length_>>>);
|
||||
|
||||
// comparisons of the same dimensions
|
||||
static_assert(length_dim == length_dim);
|
||||
static_assert(speed_dim == speed_dim);
|
||||
static_assert(length == length);
|
||||
static_assert(speed == speed);
|
||||
|
||||
// comparisons of equivalent dimensions (named vs unnamed/derived)
|
||||
static_assert(length_dim / length_dim == one_dim);
|
||||
static_assert(length / length == dimensionless);
|
||||
|
||||
static_assert(1 / time_dim != frequency_dim);
|
||||
static_assert(convertible(1 / time_dim, frequency_dim));
|
||||
static_assert(1 / frequency_dim == time_dim);
|
||||
static_assert(frequency_dim * time_dim == one_dim);
|
||||
static_assert(std::is_same_v<std::common_type_t<decltype(1 / time_dim), decltype(frequency_dim)>, frequency_dim_>);
|
||||
static_assert(std::is_same_v<std::common_type_t<decltype(frequency_dim), decltype(1 / time_dim)>, frequency_dim_>);
|
||||
static_assert(1 / time != frequency);
|
||||
static_assert(convertible(1 / time, frequency));
|
||||
static_assert(1 / frequency == time);
|
||||
static_assert(frequency * time == dimensionless);
|
||||
static_assert(std::is_same_v<std::common_type_t<decltype(1 / time), decltype(frequency)>, frequency_>);
|
||||
static_assert(std::is_same_v<std::common_type_t<decltype(frequency), decltype(1 / time)>, frequency_>);
|
||||
|
||||
static_assert(length_dim * length_dim != area_dim);
|
||||
static_assert(convertible(length_dim * length_dim, area_dim));
|
||||
static_assert(length_dim * length_dim != volume_dim);
|
||||
static_assert(area_dim / length_dim == length_dim);
|
||||
static_assert(std::is_same_v<std::common_type_t<decltype(length_dim * length_dim), decltype(area_dim)>, area_dim_>);
|
||||
static_assert(std::is_same_v<std::common_type_t<decltype(area_dim), decltype(length_dim * length_dim)>, area_dim_>);
|
||||
static_assert(length * length != area);
|
||||
static_assert(convertible(length * length, area));
|
||||
static_assert(length * length != volume);
|
||||
static_assert(area / length == length);
|
||||
static_assert(std::is_same_v<std::common_type_t<decltype(length * length), decltype(area)>, area_>);
|
||||
static_assert(std::is_same_v<std::common_type_t<decltype(area), decltype(length * length)>, area_>);
|
||||
|
||||
static_assert(length_dim * length_dim * length_dim != volume_dim);
|
||||
static_assert(area_dim * length_dim != volume_dim);
|
||||
static_assert(volume_dim / length_dim != area_dim);
|
||||
static_assert(volume_dim / length_dim / length_dim == length_dim);
|
||||
static_assert(area_dim * area_dim / length_dim != volume_dim);
|
||||
static_assert(area_dim * (area_dim / length_dim) != volume_dim);
|
||||
static_assert(volume_dim / (length_dim * length_dim) == length_dim);
|
||||
static_assert(length * length * length != volume);
|
||||
static_assert(area * length != volume);
|
||||
static_assert(volume / length != area);
|
||||
static_assert(volume / length / length == length);
|
||||
static_assert(area * area / length != volume);
|
||||
static_assert(area * (area / length) != volume);
|
||||
static_assert(volume / (length * length) == length);
|
||||
|
||||
static_assert(length_dim / time_dim != speed_dim);
|
||||
static_assert(length_dim * time_dim != speed_dim);
|
||||
static_assert(length_dim / time_dim / time_dim != speed_dim);
|
||||
static_assert(length_dim / speed_dim == time_dim);
|
||||
static_assert(speed_dim * time_dim == length_dim);
|
||||
static_assert(std::is_same_v<std::common_type_t<decltype(length_dim / time_dim), decltype(speed_dim)>, speed_dim_>);
|
||||
static_assert(std::is_same_v<std::common_type_t<decltype(speed_dim), decltype(length_dim / time_dim)>, speed_dim_>);
|
||||
static_assert(std::is_same_v<std::common_type_t<decltype(length_dim / time_dim), decltype(length_dim / time_dim)>,
|
||||
decltype(length_dim / time_dim)>);
|
||||
static_assert(length / time != speed);
|
||||
static_assert(length * time != speed);
|
||||
static_assert(length / time / time != speed);
|
||||
static_assert(length / speed == time);
|
||||
static_assert(speed * time == length);
|
||||
static_assert(std::is_same_v<std::common_type_t<decltype(length / time), decltype(speed)>, speed_>);
|
||||
static_assert(std::is_same_v<std::common_type_t<decltype(speed), decltype(length / time)>, speed_>);
|
||||
static_assert(
|
||||
std::is_same_v<std::common_type_t<decltype(length / time), decltype(length / time)>, decltype(length / time)>);
|
||||
|
||||
static_assert(length_dim / time_dim / time_dim != acceleration_dim);
|
||||
static_assert(length_dim / (time_dim * time_dim) != acceleration_dim);
|
||||
static_assert(speed_dim / time_dim != acceleration_dim);
|
||||
static_assert(speed_dim / acceleration_dim == time_dim);
|
||||
static_assert(acceleration_dim * time_dim != speed_dim);
|
||||
static_assert(acceleration_dim * (time_dim * time_dim) == length_dim);
|
||||
static_assert(acceleration_dim / speed_dim != frequency_dim);
|
||||
static_assert(length / time / time != acceleration);
|
||||
static_assert(length / (time * time) != acceleration);
|
||||
static_assert(speed / time != acceleration);
|
||||
static_assert(speed / acceleration == time);
|
||||
static_assert(acceleration * time != speed);
|
||||
static_assert(acceleration * (time * time) == length);
|
||||
static_assert(acceleration / speed != frequency);
|
||||
|
||||
// comparison of convertible named dimensions
|
||||
static_assert(velocity_dim != speed_dim);
|
||||
static_assert(convertible(speed_dim, velocity_dim));
|
||||
static_assert(std::is_same_v<std::common_type_t<decltype(velocity_dim), decltype(speed_dim)>, velocity_dim_>);
|
||||
static_assert(std::is_same_v<std::common_type_t<decltype(speed_dim), decltype(velocity_dim)>, velocity_dim_>);
|
||||
static_assert(velocity != speed);
|
||||
static_assert(convertible(speed, velocity));
|
||||
static_assert(std::is_same_v<std::common_type_t<decltype(velocity), decltype(speed)>, velocity_>);
|
||||
static_assert(std::is_same_v<std::common_type_t<decltype(speed), decltype(velocity)>, velocity_>);
|
||||
|
||||
// comparison of convertible unnamed dimensions
|
||||
static_assert(
|
||||
is_of_type<mass_dim * acceleration_dim, derived_dimension<length_dim_, mass_dim_, per<power<time_dim_, 2>>>>);
|
||||
static_assert(
|
||||
is_of_type<acceleration_dim * mass_dim, derived_dimension<length_dim_, mass_dim_, per<power<time_dim_, 2>>>>);
|
||||
static_assert(mass_dim * acceleration_dim == acceleration_dim * mass_dim);
|
||||
static_assert(convertible(mass_dim * acceleration_dim, acceleration_dim* mass_dim));
|
||||
static_assert(is_of_type<mass * acceleration, derived_dimension<length_, mass_, per<units::power<time_, 2>>>>);
|
||||
static_assert(is_of_type<acceleration * mass, derived_dimension<length_, mass_, per<units::power<time_, 2>>>>);
|
||||
static_assert(mass * acceleration == acceleration * mass);
|
||||
static_assert(convertible(mass * acceleration, acceleration* mass));
|
||||
|
||||
// comparisons of equivalent but not convertible dimensions
|
||||
static_assert(energy_dim != torque_dim);
|
||||
static_assert(!convertible(energy_dim, torque_dim));
|
||||
static_assert(energy != torque);
|
||||
static_assert(!convertible(energy, torque));
|
||||
|
||||
static_assert(force_dim * length_dim != energy_dim);
|
||||
static_assert(force_dim * length_dim != torque_dim);
|
||||
static_assert(convertible(force_dim * length_dim, energy_dim));
|
||||
static_assert(convertible(force_dim * length_dim, torque_dim));
|
||||
static_assert(force * length != energy);
|
||||
static_assert(force * length != torque);
|
||||
static_assert(convertible(force * length, energy));
|
||||
static_assert(convertible(force * length, torque));
|
||||
template<auto T1, auto T2>
|
||||
concept no_common_type = requires {
|
||||
requires !requires { typename std::common_type_t<decltype(T1), decltype(T2)>; };
|
||||
requires !requires { typename std::common_type_t<decltype(T2), decltype(T1)>; };
|
||||
};
|
||||
static_assert(no_common_type<energy_dim, torque_dim>);
|
||||
static_assert(no_common_type<energy, torque>);
|
||||
|
||||
static_assert(frequency_dim != action_dim);
|
||||
static_assert(!convertible(frequency_dim, action_dim));
|
||||
static_assert(no_common_type<frequency_dim, action_dim>);
|
||||
static_assert(frequency != action);
|
||||
static_assert(!convertible(frequency, action));
|
||||
static_assert(no_common_type<frequency, action>);
|
||||
|
||||
// Dimensionless
|
||||
static_assert(convertible(power_dim / power_dim, efficiency_dim));
|
||||
static_assert(power_dim / power_dim != efficiency_dim);
|
||||
static_assert(one_dim != efficiency_dim);
|
||||
static_assert(convertible(power / power, efficiency));
|
||||
static_assert(power / power != efficiency);
|
||||
static_assert(dimensionless != efficiency);
|
||||
|
||||
static_assert(!convertible(efficiency_dim, strain_dim));
|
||||
static_assert(efficiency_dim != strain_dim);
|
||||
static_assert(!convertible(efficiency, strain));
|
||||
static_assert(efficiency != strain);
|
||||
|
||||
static_assert(stress_dim / stress_dim != strain_dim);
|
||||
static_assert(stress_dim / stress_dim != efficiency_dim);
|
||||
static_assert(convertible(stress_dim / stress_dim, strain_dim));
|
||||
static_assert(convertible(stress_dim / stress_dim, efficiency_dim));
|
||||
static_assert(stress / stress != strain);
|
||||
static_assert(stress / stress != efficiency);
|
||||
static_assert(convertible(stress / stress, strain));
|
||||
static_assert(convertible(stress / stress, efficiency));
|
||||
|
||||
// comparison of not equivalent dimensions
|
||||
static_assert(length_dim != time_dim);
|
||||
static_assert(!convertible(length_dim, time_dim));
|
||||
static_assert(length != time);
|
||||
static_assert(!convertible(length, time));
|
||||
|
||||
static_assert(acceleration_dim != speed_dim);
|
||||
static_assert(!convertible(acceleration_dim, speed_dim));
|
||||
static_assert(acceleration != speed);
|
||||
static_assert(!convertible(acceleration, speed));
|
||||
|
||||
// power
|
||||
static_assert(is_of_type<pow<2>(length_dim), derived_dimension<power<length_dim_, 2>>>);
|
||||
static_assert(is_of_type<pow<1, 2>(length_dim), derived_dimension<power<length_dim_, 1, 2>>>);
|
||||
static_assert(is_of_type<pow<1, 2>(length_dim* length_dim), length_dim_>);
|
||||
static_assert(is_of_type<pow<1, 3>(length_dim* length_dim* length_dim), length_dim_>);
|
||||
static_assert(is_of_type<pow<1, 3>(length_dim* length_dim), derived_dimension<power<length_dim_, 2, 3>>>);
|
||||
static_assert(is_of_type<pow<1, 2>(length_dim / time_dim),
|
||||
derived_dimension<power<length_dim_, 1, 2>, per<power<time_dim_, 1, 2>>>>);
|
||||
static_assert(is_of_type<pow<1, 2>(length_dim / (time_dim * time_dim)),
|
||||
derived_dimension<power<length_dim_, 1, 2>, per<time_dim_>>>);
|
||||
|
||||
static_assert(is_same_v<decltype(pow<2>(length_dim)), decltype(length_dim * length_dim)>);
|
||||
static_assert(is_of_type<pow<2>(length), derived_dimension<units::power<length_, 2>>>);
|
||||
static_assert(is_of_type<pow<1, 2>(length), derived_dimension<units::power<length_, 1, 2>>>);
|
||||
static_assert(is_of_type<pow<1, 2>(length* length), length_>);
|
||||
static_assert(is_of_type<pow<1, 3>(length* length* length), length_>);
|
||||
static_assert(is_of_type<pow<1, 3>(length* length), derived_dimension<units::power<length_, 2, 3>>>);
|
||||
static_assert(
|
||||
is_same_v<decltype(pow<2>(length_dim / time_dim)), decltype(length_dim * length_dim / time_dim / time_dim)>);
|
||||
is_of_type<pow<1, 2>(length / time), derived_dimension<units::power<length_, 1, 2>, per<units::power<time_, 1, 2>>>>);
|
||||
static_assert(
|
||||
is_of_type<pow<1, 2>(length / (time * time)), derived_dimension<units::power<length_, 1, 2>, per<time_>>>);
|
||||
|
||||
static_assert(is_same_v<decltype(pow<2>(length)), decltype(length * length)>);
|
||||
static_assert(is_same_v<decltype(pow<2>(length / time)), decltype(length * length / time / time)>);
|
||||
|
||||
} // namespace
|
||||
|
@@ -22,111 +22,139 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <units/bits/equivalent.h>
|
||||
#include <cassert>
|
||||
#include <concepts>
|
||||
#include <type_traits>
|
||||
|
||||
template<typename T, typename U>
|
||||
inline constexpr bool compare_impl = false;
|
||||
// template<typename T, typename U>
|
||||
// inline constexpr bool compare_impl = false;
|
||||
|
||||
template<typename T>
|
||||
inline constexpr bool compare_impl<T, T> = true;
|
||||
// template<typename T>
|
||||
// inline constexpr bool compare_impl<T, T> = true;
|
||||
|
||||
template<typename T, typename U>
|
||||
requires(UNITS_DOWNCAST_MODE == 0)
|
||||
inline constexpr bool compare_impl<T, U> = units::equivalent<T, U>;
|
||||
// template<typename T, typename U>
|
||||
// requires(UNITS_DOWNCAST_MODE == 0)
|
||||
// inline constexpr bool compare_impl<T, U> = units::equivalent<T, U>;
|
||||
|
||||
template<typename T, typename U>
|
||||
inline constexpr bool compare = compare_impl<std::remove_cvref_t<T>, std::remove_cvref_t<U>>;
|
||||
// template<typename T, typename U>
|
||||
// inline constexpr bool compare = compare_impl<std::remove_cvref_t<T>, std::remove_cvref_t<U>>;
|
||||
|
||||
template<typename T, typename... Us, typename... Vs>
|
||||
constexpr bool constructible_from(Vs...)
|
||||
{
|
||||
return std::constructible_from<T, Us..., Vs...>;
|
||||
}
|
||||
// template<typename T, typename... Us, typename... Vs>
|
||||
// constexpr bool constructible_from(Vs...)
|
||||
// {
|
||||
// return std::constructible_from<T, Us..., Vs...>;
|
||||
// }
|
||||
|
||||
template<class T>
|
||||
void convertible_from__(T);
|
||||
// template<class T>
|
||||
// void convertible_from__(T);
|
||||
|
||||
template<typename T, typename... Us>
|
||||
concept convertible_from_ = requires(Us... us) { convertible_from__<T>({us...}); };
|
||||
// template<typename T, typename... Us>
|
||||
// concept convertible_from_ = requires(Us... us) { convertible_from__<T>({us...}); };
|
||||
|
||||
template<typename T, typename... Us, typename... Vs>
|
||||
constexpr bool convertible_from(Vs...)
|
||||
{
|
||||
if constexpr (sizeof...(Us) + sizeof...(Vs) == 1)
|
||||
return std::is_convertible_v<Us..., Vs..., T>;
|
||||
else
|
||||
return convertible_from_<T, Us..., Vs...>;
|
||||
}
|
||||
// template<typename T, typename... Us, typename... Vs>
|
||||
// constexpr bool convertible_from(Vs...)
|
||||
// {
|
||||
// if constexpr (sizeof...(Us) + sizeof...(Vs) == 1)
|
||||
// return std::is_convertible_v<Us..., Vs..., T>;
|
||||
// else
|
||||
// return convertible_from_<T, Us..., Vs...>;
|
||||
// }
|
||||
|
||||
template<typename T, typename... Us, typename... Vs>
|
||||
constexpr bool constructible_or_convertible_from(Vs...)
|
||||
{
|
||||
return constructible_from<T, Us..., Vs...>() || convertible_from<T, Us..., Vs...>();
|
||||
}
|
||||
// template<typename T, typename... Us, typename... Vs>
|
||||
// constexpr bool constructible_or_convertible_from(Vs...)
|
||||
// {
|
||||
// return constructible_from<T, Us..., Vs...>() || convertible_from<T, Us..., Vs...>();
|
||||
// }
|
||||
|
||||
template<typename T, typename... Us, typename... Vs>
|
||||
constexpr bool constructible_and_convertible_from(Vs...)
|
||||
{
|
||||
return constructible_from<T, Us..., Vs...>() && convertible_from<T, Us..., Vs...>();
|
||||
}
|
||||
// template<typename T, typename... Us, typename... Vs>
|
||||
// constexpr bool constructible_and_convertible_from(Vs...)
|
||||
// {
|
||||
// return constructible_from<T, Us..., Vs...>() && convertible_from<T, Us..., Vs...>();
|
||||
// }
|
||||
|
||||
template<typename T, typename... Us>
|
||||
requires(constructible_from<T, Us...>())
|
||||
constexpr T construct_from(Us... us)
|
||||
{
|
||||
return T(us...);
|
||||
}
|
||||
// template<typename T, typename... Us>
|
||||
// requires(constructible_from<T, Us...>())
|
||||
// constexpr T construct_from(Us... us)
|
||||
// {
|
||||
// return T(us...);
|
||||
// }
|
||||
|
||||
template<typename T, typename... Us>
|
||||
requires(convertible_from<T, Us...>())
|
||||
constexpr T convert_from(Us... us)
|
||||
{
|
||||
if constexpr (sizeof...(Us) == 1)
|
||||
return [](T t) { return t; }(us...);
|
||||
else
|
||||
return {us...};
|
||||
}
|
||||
// template<typename T, typename... Us>
|
||||
// requires(convertible_from<T, Us...>())
|
||||
// constexpr T convert_from(Us... us)
|
||||
// {
|
||||
// if constexpr (sizeof...(Us) == 1)
|
||||
// return [](T t) { return t; }(us...);
|
||||
// else
|
||||
// return {us...};
|
||||
// }
|
||||
|
||||
template<std::equality_comparable T, typename... Us>
|
||||
requires(constructible_from<T, Us...>() && convertible_from<T, Us...>())
|
||||
constexpr T construct_and_convert_from(Us... us)
|
||||
{
|
||||
T t{construct_from<T>(us...)};
|
||||
assert(t == convert_from<T>(us...));
|
||||
return t;
|
||||
}
|
||||
// template<std::equality_comparable T, typename... Us>
|
||||
// requires(constructible_from<T, Us...>() && convertible_from<T, Us...>())
|
||||
// constexpr T construct_and_convert_from(Us... us)
|
||||
// {
|
||||
// T t{construct_from<T>(us...)};
|
||||
// assert(t == convert_from<T>(us...));
|
||||
// return t;
|
||||
// }
|
||||
|
||||
template<typename T, typename... Us>
|
||||
requires(constructible_from<T, Us...>() && !convertible_from<T, Us...>())
|
||||
constexpr T construct_from_only(Us... us)
|
||||
{
|
||||
return construct_from<T>(us...);
|
||||
}
|
||||
// template<typename T, typename... Us>
|
||||
// requires(constructible_from<T, Us...>() && !convertible_from<T, Us...>())
|
||||
// constexpr T construct_from_only(Us... us)
|
||||
// {
|
||||
// return construct_from<T>(us...);
|
||||
// }
|
||||
|
||||
// #if !defined(UNITS_COMP_GCC)
|
||||
// template<template<typename...> typename T, typename = std::void_t<>, typename... Us>
|
||||
// concept ctad_constructible_from_ = requires(Us... us) { T(us...); };
|
||||
// #else
|
||||
// template<template<typename...> typename T, typename = std::void_t<>, typename... Us>
|
||||
// inline constexpr bool ctad_constructible_from_ = false;
|
||||
|
||||
// template<template<typename...> typename T, typename... Us>
|
||||
// inline constexpr bool ctad_constructible_from_<T, std::void_t<decltype(T(Us{}...))>, Us...> = true;
|
||||
// #endif
|
||||
|
||||
// template<template<typename...> typename T, typename... Us, typename... Vs>
|
||||
// constexpr bool ctad_constructible_from(Vs...)
|
||||
// {
|
||||
// return ctad_constructible_from_<T, void, Us..., Vs...>;
|
||||
// }
|
||||
|
||||
// constexpr auto same = []<std::equality_comparable T>(T l, T r) { return l == r; };
|
||||
// constexpr auto comp = // TODO: Fix #205 to use `std::equality_comparable_with<T> U`.
|
||||
// []<typename T, typename U>(T l, U r)
|
||||
// requires compare<T, U>
|
||||
// {
|
||||
// return l == r;
|
||||
// };
|
||||
|
||||
// template<auto F>
|
||||
// requires requires { F(); }
|
||||
// inline constexpr bool require_constant_invocation = requires { new int[1][(F(), 1)]; };
|
||||
|
||||
template<auto V, typename T>
|
||||
inline constexpr bool is_of_type = std::is_same_v<std::remove_cvref_t<decltype(V)>, T>;
|
||||
|
||||
#ifdef __cpp_explicit_this_parameter__
|
||||
|
||||
#define BASE_DIMENSION_(name, symbol) \
|
||||
inline constexpr struct name##_ : base_dimension<symbol> { \
|
||||
} name
|
||||
|
||||
#define DERIVED_DIMENSION_(name, base) \
|
||||
inline constexpr struct name##_ : base { \
|
||||
} name
|
||||
|
||||
#if !defined(UNITS_COMP_GCC)
|
||||
template<template<typename...> typename T, typename = std::void_t<>, typename... Us>
|
||||
concept ctad_constructible_from_ = requires(Us... us) { T(us...); };
|
||||
#else
|
||||
template<template<typename...> typename T, typename = std::void_t<>, typename... Us>
|
||||
inline constexpr bool ctad_constructible_from_ = false;
|
||||
|
||||
template<template<typename...> typename T, typename... Us>
|
||||
inline constexpr bool ctad_constructible_from_<T, std::void_t<decltype(T(Us{}...))>, Us...> = true;
|
||||
#define BASE_DIMENSION_(name, symbol) \
|
||||
inline constexpr struct name##_ : base_dimension<name##_, symbol> { \
|
||||
} name
|
||||
|
||||
#define DERIVED_DIMENSION_(name, base) \
|
||||
inline constexpr struct name##_ : derived_dimension<name##_, base> { \
|
||||
} name
|
||||
|
||||
#endif
|
||||
|
||||
template<template<typename...> typename T, typename... Us, typename... Vs>
|
||||
constexpr bool ctad_constructible_from(Vs...)
|
||||
{
|
||||
return ctad_constructible_from_<T, void, Us..., Vs...>;
|
||||
}
|
||||
|
||||
constexpr auto same = []<std::equality_comparable T>(T l, T r) { return l == r; };
|
||||
constexpr auto comp = // TODO: Fix #205 to use `std::equality_comparable_with<T> U`.
|
||||
[]<typename T, typename U>(T l, U r) requires compare<T, U> { return l == r; };
|
||||
|
||||
template<auto F>
|
||||
requires requires { F(); }
|
||||
inline constexpr bool require_constant_invocation = requires { new int[1][(F(), 1)]; };
|
||||
|
@@ -20,6 +20,8 @@
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
#include "test_tools.h"
|
||||
#include <units/dimension.h>
|
||||
#include <units/si/prefixes.h>
|
||||
#include <units/unit.h>
|
||||
|
||||
@@ -28,18 +30,21 @@ namespace {
|
||||
using namespace units;
|
||||
using namespace units::detail;
|
||||
|
||||
template<auto V, typename T>
|
||||
inline constexpr bool is_of_type = std::is_same_v<std::remove_cvref_t<decltype(V)>, T>;
|
||||
|
||||
using one_ = struct one;
|
||||
|
||||
// base dimensions
|
||||
BASE_DIMENSION_(length, "L");
|
||||
BASE_DIMENSION_(time, "T");
|
||||
BASE_DIMENSION_(mass, "M");
|
||||
BASE_DIMENSION_(thermodynamic_temperature, "Θ");
|
||||
|
||||
// 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 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<gram>) {} kilogram;
|
||||
inline constexpr struct kelvin_ : named_unit<"K"> {} kelvin;
|
||||
inline constexpr struct kelvin_ : named_unit<"K", thermodynamic_temperature> {} kelvin;
|
||||
|
||||
// derived named units
|
||||
inline constexpr struct radian_ : named_unit<"rad", metre / metre> {} radian;
|
||||
|
Reference in New Issue
Block a user