forked from mpusz/mp-units
refactor: units nearly done
This commit is contained in:
@@ -22,16 +22,6 @@
|
||||
|
||||
#include <units/si/si.h>
|
||||
|
||||
|
||||
template<typename T>
|
||||
consteval bool print();
|
||||
|
||||
template<typename T, typename Expr>
|
||||
constexpr bool is_of_type(Expr)
|
||||
{
|
||||
return std::is_same_v<Expr, T>;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
using namespace units;
|
||||
@@ -42,6 +32,18 @@ inline constexpr struct activity_dim : decltype(1 / isq::time_dim) {} activity_d
|
||||
inline constexpr struct activity : system_reference<activity_dim, si::becquerel> {} activity;
|
||||
// clang-format on
|
||||
|
||||
// check for invalid prefixes
|
||||
|
||||
template<Unit auto V1>
|
||||
concept can_not_be_prefixed = !requires { typename si::milli_<V1>; };
|
||||
|
||||
static_assert(can_not_be_prefixed<si::degree_Celsius>);
|
||||
static_assert(can_not_be_prefixed<si::minute>);
|
||||
static_assert(can_not_be_prefixed<si::hour>);
|
||||
static_assert(can_not_be_prefixed<si::day>);
|
||||
static_assert(can_not_be_prefixed<si::kilogram>);
|
||||
static_assert(can_not_be_prefixed<si::hectare>);
|
||||
static_assert(can_not_be_prefixed<si::metre / si::second>);
|
||||
|
||||
// Named quantity/dimension and unit
|
||||
static_assert(
|
||||
@@ -68,24 +70,28 @@ static_assert(is_same_v<decltype(20 * si::speed[m / s] / (10 * si::length[m]) *
|
||||
|
||||
// Comparisons
|
||||
|
||||
// Same dimension type & different unit
|
||||
// static_assert(1000 * si::length[m] == 1 * si::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]));
|
||||
|
||||
// Named and derived dimensions (different units)
|
||||
// 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]);
|
||||
|
||||
// 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]));
|
||||
|
||||
// Different named dimensions
|
||||
template<Reference auto R1, Reference auto R2>
|
||||
concept invalid_comparison = requires {
|
||||
requires !requires { 2 * R1 == 2 * R2; };
|
||||
requires !requires { 2 * R2 == 2 * R1; };
|
||||
};
|
||||
concept invalid_comparison = !requires { 2 * R1 == 2 * R2; } && !requires { 2 * R2 == 2 * R1; };
|
||||
static_assert(invalid_comparison<activity[Bq], si::frequency[Hz]>);
|
||||
|
||||
// static_assert(print<decltype(10 * si::length[m] / (2 * si::time[s]) + 5 * si::speed[m / s])>());
|
||||
|
||||
// Arithmetics
|
||||
|
||||
// Named and derived dimensions (same units)
|
||||
@@ -124,14 +130,28 @@ static_assert(is_same_v<decltype(5 * si::frequency[Hz] - 10 / (2 * si::time[s]))
|
||||
template<typename... Ts>
|
||||
consteval bool invalid_arithmetic(Ts... ts)
|
||||
{
|
||||
return requires {
|
||||
requires !requires { (... + ts); };
|
||||
requires !requires { (... - 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]));
|
||||
|
||||
// Implicit conversions allowed between quantities of `convertible` references
|
||||
constexpr quantity<si::speed[km / h]> speed = 120 * si::length[km] / (2 * si::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]));
|
||||
|
||||
// cast 1 / time_dim 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]>);
|
||||
@@ -160,105 +180,6 @@ static_assert(invalid_arithmetic(5 * activity[Bq], 10 / (2 * si::time[s]), 5 * s
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace units::si {
|
||||
|
||||
// derived unit expression template syntax verification
|
||||
static_assert(is_of_type<derived_unit<struct one, per<struct second>>>(1 / second));
|
||||
static_assert(is_of_type<struct second>(1 / (1 / second)));
|
||||
|
||||
static_assert(is_of_type<struct second>(one * second));
|
||||
static_assert(is_of_type<struct second>(second * one));
|
||||
static_assert(is_of_type<derived_unit<struct one, per<struct second>>>(one * (1 / second)));
|
||||
static_assert(is_of_type<derived_unit<struct one, per<struct second>>>(1 / second * one));
|
||||
|
||||
static_assert(is_of_type<derived_unit<struct metre, struct second>>(metre * second));
|
||||
static_assert(is_of_type<derived_unit<units::power<struct metre, 2>>>(metre * metre));
|
||||
|
||||
static_assert(is_of_type<derived_unit<units::power<struct metre, 2>, struct second>>(metre * metre * second));
|
||||
static_assert(is_of_type<derived_unit<units::power<struct metre, 2>, struct second>>(metre * second * metre));
|
||||
|
||||
static_assert(is_of_type<derived_unit<units::power<struct metre, 2>, struct second>>(metre * (second * metre)));
|
||||
static_assert(is_of_type<derived_unit<units::power<struct metre, 2>, struct second>>(second * (metre * metre)));
|
||||
|
||||
static_assert(is_of_type<derived_unit<struct metre, per<struct second>>>(1 / second * metre));
|
||||
static_assert(is_of_type<struct one>(1 / second * second));
|
||||
|
||||
static_assert(is_of_type<struct second>(second / one));
|
||||
static_assert(is_of_type<derived_unit<struct one, per<struct second>>>(1 / second / one));
|
||||
|
||||
static_assert(is_of_type<struct metre>(metre / second * second));
|
||||
static_assert(is_of_type<derived_unit<struct one, per<units::power<struct second, 2>>>>(1 / second * (1 / second)));
|
||||
static_assert(is_of_type<derived_unit<struct one, per<units::power<struct second, 2>>>>(1 / (second * second)));
|
||||
static_assert(is_of_type<derived_unit<units::power<struct second, 2>>>(1 / (1 / (second * second))));
|
||||
|
||||
static_assert(is_of_type<derived_unit<struct metre, per<units::power<struct second, 2>>>>(metre / second *
|
||||
(1 / second)));
|
||||
static_assert(is_of_type<derived_unit<units::power<struct metre, 2>, per<units::power<struct second, 2>>>>(
|
||||
metre / second * (metre / second)));
|
||||
static_assert(is_of_type<struct one>(metre / second * (second / metre)));
|
||||
|
||||
static_assert(is_of_type<derived_unit<struct watt, per<struct joule>>>(watt / joule));
|
||||
static_assert(is_of_type<derived_unit<struct joule, per<struct watt>>>(joule / watt));
|
||||
|
||||
// comparisons of equivalent units
|
||||
static_assert(metre / metre == one);
|
||||
// static_assert(metre * metre == square_metre);
|
||||
// static_assert(second * second == second_squared);
|
||||
// static_assert(second * second * second == second_cubed);
|
||||
// static_assert(second * (second * second) == second_cubed);
|
||||
// static_assert(second_squared * second == second_cubed);
|
||||
// static_assert(second * second_squared == second_cubed);
|
||||
|
||||
// static_assert(1 / second * metre == metre / second);
|
||||
// static_assert(metre * (1 / second) == metre / second);
|
||||
// static_assert((metre / second) * (1 / second) == metre / second / second);
|
||||
// static_assert((metre / second) * (1 / second) == metre / (second * second));
|
||||
// static_assert((metre / second) * (1 / second) == metre / second_squared);
|
||||
|
||||
// static_assert(hertz == 1 / second);
|
||||
// static_assert(newton == kilogram * metre / second_squared);
|
||||
// static_assert(joule == kilogram * square_metre / second_squared);
|
||||
// static_assert(joule == newton * metre);
|
||||
// static_assert(watt == joule / second);
|
||||
// static_assert(watt == kilogram * square_metre / second_cubed);
|
||||
|
||||
// static_assert(1 / frequency_dim == second);
|
||||
// static_assert(frequency_dim * second == one);
|
||||
|
||||
// static_assert(metre * metre == area_dim);
|
||||
// static_assert(metre * metre != volume_dim);
|
||||
// static_assert(area_dim / metre == metre);
|
||||
|
||||
// static_assert(metre * metre * metre == volume_dim);
|
||||
// static_assert(area_dim * metre == volume_dim);
|
||||
// static_assert(volume_dim / metre == area_dim);
|
||||
// static_assert(volume_dim / metre / metre == metre);
|
||||
// static_assert(area_dim * area_dim / metre == volume_dim);
|
||||
// static_assert(area_dim * (area_dim / metre) == volume_dim);
|
||||
// static_assert(volume_dim / (metre * metre) == metre);
|
||||
|
||||
// static_assert(metre / second == speed_dim);
|
||||
// static_assert(metre * second != speed_dim);
|
||||
// static_assert(metre / second / second != speed_dim);
|
||||
// static_assert(metre / speed_dim == second);
|
||||
// static_assert(speed_dim * second == metre);
|
||||
|
||||
// static_assert(metre / second / second == acceleration_dim);
|
||||
// static_assert(metre / (second * second) == acceleration_dim);
|
||||
// static_assert(speed_dim / second == acceleration_dim);
|
||||
// static_assert(speed_dim / acceleration_dim == second);
|
||||
// static_assert(acceleration_dim * second == speed_dim);
|
||||
// static_assert(acceleration_dim * (second * second) == metre);
|
||||
// static_assert(acceleration_dim / speed_dim == frequency_dim);
|
||||
|
||||
|
||||
// Bq + Hz should not compile
|
||||
|
||||
// Bq + Hz + 1/s should compile?
|
||||
|
||||
|
||||
} // namespace units::si
|
||||
|
||||
namespace units {
|
||||
|
||||
template<typename T, Dimension auto D, Unit auto U>
|
||||
@@ -331,3 +252,6 @@ int main()
|
||||
|
||||
// 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
|
@@ -38,50 +38,12 @@
|
||||
|
||||
namespace units {
|
||||
|
||||
// namespace detail {
|
||||
|
||||
// template<typename>
|
||||
// inline constexpr bool can_be_prefixed = false;
|
||||
|
||||
// } // namespace detail
|
||||
|
||||
/**
|
||||
* @brief A common point for a hierarchy of units
|
||||
*
|
||||
* A unit is an entity defined and adopted by convention, with which any other quantity of
|
||||
* the same kind can be compared to express the ratio of the second quantity to the first
|
||||
* one as a number.
|
||||
*
|
||||
* All units of the same dimension can be convereted between each other. To allow this all of
|
||||
* them are expressed as different ratios of the same one proprietary chosen reference unit
|
||||
* (i.e. all length units are expressed in terms of meter, all mass units are expressed in
|
||||
* terms of gram, ...)
|
||||
*
|
||||
* @tparam M a Magnitude representing the (relative) size of this unit
|
||||
* @tparam U a unit to use as a reference for this dimension
|
||||
*
|
||||
* @note U cannot be constrained with Unit as for some specializations (i.e. named_unit)
|
||||
* it gets the incomplete child's type with the CRTP idiom.
|
||||
*/
|
||||
template<Magnitude auto M, typename U>
|
||||
struct scaled_unit {
|
||||
static constexpr UNITS_MSVC_WORKAROUND(Magnitude) auto mag = M;
|
||||
using reference = U;
|
||||
};
|
||||
|
||||
// TODO: Remove when P1985 accepted
|
||||
namespace detail {
|
||||
|
||||
template<Magnitude auto M, typename U>
|
||||
void to_base_scaled_unit(const volatile scaled_unit<M, U>*);
|
||||
|
||||
template<typename T>
|
||||
inline constexpr bool is_specialization_of_scaled_unit = false;
|
||||
inline constexpr bool is_unit = false;
|
||||
|
||||
template<Magnitude auto M, typename U>
|
||||
inline constexpr bool is_specialization_of_scaled_unit<scaled_unit<M, U>> = true;
|
||||
|
||||
} // namespace detail
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief A concept matching all unit types in the library
|
||||
@@ -89,129 +51,12 @@ inline constexpr bool is_specialization_of_scaled_unit<scaled_unit<M, U>> = true
|
||||
* Satisfied by all unit types derived from an specialization of :class:`scaled_unit`.
|
||||
*/
|
||||
template<typename T>
|
||||
concept Unit = requires(T* t) { detail::to_base_scaled_unit(t); };
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<typename>
|
||||
inline constexpr bool is_named = false;
|
||||
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
concept NamedUnit = Unit<T> && detail::is_named<T>;
|
||||
|
||||
template<Unit auto U1, Unit auto U2>
|
||||
struct same_unit_reference : is_same<typename decltype(U1)::reference, typename decltype(U2)::reference> {};
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<Unit U1, Unit U2>
|
||||
struct unit_less : std::bool_constant<type_name<U1>() < type_name<U2>()> {};
|
||||
|
||||
template<typename T1, typename T2>
|
||||
using type_list_of_unit_less = expr_less<T1, T2, unit_less>;
|
||||
|
||||
/**
|
||||
* @brief Unpacks the list of potentially derived dimensions to a list containing only base dimensions
|
||||
*
|
||||
* @tparam Es Exponents of potentially derived dimensions
|
||||
*/
|
||||
// template<typename NumList, typename DenList>
|
||||
// struct unit_extract;
|
||||
|
||||
// template<>
|
||||
// struct unit_extract<type_list<>, type_list<>> {
|
||||
// using num = type_list<>;
|
||||
// using den = type_list<>;
|
||||
// };
|
||||
|
||||
// template<typename T, typename... NRest, typename... Dens>
|
||||
// requires BaseUnit<T> || BaseUnit<typename T::factor>
|
||||
// struct unit_extract<type_list<T, NRest...>, type_list<Dens...>> {
|
||||
// using impl = unit_extract<type_list<NRest...>, type_list<Dens...>>;
|
||||
// using num = type_list_push_front<typename impl::num, T>;
|
||||
// using den = TYPENAME impl::den;
|
||||
// };
|
||||
|
||||
// template<typename T, typename... DRest>
|
||||
// requires BaseUnit<T> || BaseUnit<typename T::factor>
|
||||
// struct unit_extract<type_list<>, type_list<T, DRest...>> {
|
||||
// using impl = unit_extract<type_list<>, type_list<DRest...>>;
|
||||
// using num = TYPENAME impl::num;
|
||||
// using den = type_list_push_front<typename impl::den, T>;
|
||||
// };
|
||||
|
||||
// template<DerivedUnit T, typename... NRest, typename... Dens>
|
||||
// struct unit_extract<type_list<T, NRest...>, type_list<Dens...>> :
|
||||
// unit_extract<type_list_push_back<typename T::normalized_num, NRest...>,
|
||||
// type_list_push_back<typename T::normalized_den, Dens...>> {};
|
||||
|
||||
// template<DerivedUnit T, int... Ints, typename... NRest, typename... Dens>
|
||||
// struct unit_extract<type_list<power<T, Ints...>, NRest...>, type_list<Dens...>> :
|
||||
// unit_extract<type_list_push_back<typename expr_power<typename T::normalized_num, power<T, Ints...>::num,
|
||||
// power<T, Ints...>::den>::type,
|
||||
// NRest...>,
|
||||
// type_list_push_back<typename expr_power<typename T::normalized_den, power<T, Ints...>::num,
|
||||
// power<T, Ints...>::den>::type,
|
||||
// Dens...>> {};
|
||||
|
||||
|
||||
// template<DerivedUnit T, typename... DRest>
|
||||
// struct unit_extract<type_list<>, type_list<T, DRest...>> :
|
||||
// unit_extract<typename T::normalized_den, type_list_push_back<typename T::normalized_num, DRest...>> {};
|
||||
|
||||
// template<DerivedUnit T, int... Ints, typename... DRest>
|
||||
// struct unit_extract<type_list<>, type_list<power<T, Ints...>, DRest...>> :
|
||||
// unit_extract<typename expr_power<typename T::normalized_den, power<T, Ints...>::num, power<T,
|
||||
// Ints...>::den>::type,
|
||||
// type_list_push_back<typename expr_power<typename T::normalized_num, power<T, Ints...>::num,
|
||||
// power<T, Ints...>::den>::type,
|
||||
// DRest...>> {};
|
||||
|
||||
/**
|
||||
* @brief Converts user provided derived dimension specification into a valid units::normalized_dimension definition
|
||||
*
|
||||
* User provided definition of a derived dimension may contain the same base dimension repeated more than once on the
|
||||
* list possibly hidden in other derived units provided by the user. The process here should:
|
||||
* 1. Extract derived dimensions into exponents of base dimensions.
|
||||
* 2. Sort the exponents so the same dimensions are placed next to each other.
|
||||
* 3. Consolidate contiguous range of exponents of the same base dimensions to a one (or possibly zero) exponent for
|
||||
* this base dimension.
|
||||
*/
|
||||
template<typename OneTypeBase, typename... Us>
|
||||
struct normalized_unit : detail::expr_fractions<OneTypeBase, Us...> {
|
||||
// private:
|
||||
// using base = detail::expr_fractions<OneTypeBase, Us...>;
|
||||
// using extracted = unit_extract<typename base::num, typename base::den>;
|
||||
// using num_list = expr_consolidate<type_list_sort<typename extracted::num, type_list_of_unit_less>>;
|
||||
// using den_list = expr_consolidate<type_list_sort<typename extracted::den, type_list_of_unit_less>>;
|
||||
// using simple = expr_simplify<num_list, den_list, type_list_of_unit_less>;
|
||||
// public:
|
||||
// using normalized_num = TYPENAME simple::num;
|
||||
// using normalized_den = TYPENAME simple::den;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
// TODO add checking for `per` and power elements as well
|
||||
template<typename T>
|
||||
concept UnitSpec = Unit<T> || is_specialization_of<T, per> || detail::is_specialization_of_power<T>;
|
||||
concept Unit = detail::is_unit<T>;
|
||||
|
||||
// User should not instantiate this type!!!
|
||||
// It should not be exported from the module
|
||||
template<UnitSpec... Us>
|
||||
struct derived_unit : detail::normalized_unit<derived_unit<>, Us...>, scaled_unit<mag<1>, derived_unit<Us...>> {
|
||||
static constexpr bool is_base = false;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Unit one
|
||||
*
|
||||
* Unit of a dimensionless quantity.
|
||||
*/
|
||||
inline constexpr struct one : derived_unit<> {
|
||||
} one;
|
||||
template<Magnitude auto M, Unit U>
|
||||
struct scaled_unit {};
|
||||
|
||||
/**
|
||||
* @brief A named unit
|
||||
@@ -225,85 +70,186 @@ template<basic_symbol_text Symbol, auto...>
|
||||
struct named_unit;
|
||||
|
||||
template<basic_symbol_text Symbol>
|
||||
struct named_unit<Symbol> : scaled_unit<mag<1>, named_unit<Symbol>> {
|
||||
struct named_unit<Symbol> {
|
||||
static constexpr auto symbol = Symbol;
|
||||
static constexpr bool is_base = true;
|
||||
};
|
||||
|
||||
template<basic_symbol_text Symbol, Unit auto U>
|
||||
struct named_unit<Symbol, U> : decltype(U) {
|
||||
struct named_unit<Symbol, U> {
|
||||
static constexpr auto symbol = Symbol;
|
||||
static constexpr bool is_base = decltype(U)::is_base;
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<basic_symbol_text Symbol, auto... Args>
|
||||
void to_base_specialization_of_named_unit(const volatile named_unit<Symbol, Args...>*);
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template<typename T>
|
||||
concept NamedUnit = Unit<T> && requires(T* t) { detail::to_base_specialization_of_named_unit(t); };
|
||||
|
||||
template<Unit auto V>
|
||||
inline constexpr bool unit_can_be_prefixed = NamedUnit<std::remove_const_t<decltype(V)>>;
|
||||
|
||||
/**
|
||||
* @brief A prefixed unit
|
||||
*
|
||||
* Defines a new unit that is a scaled version of another unit by the provided prefix. It is
|
||||
* only possible to create such a unit if the given prefix type matches the one defined in a
|
||||
* reference unit.
|
||||
* coherent_unit unit.
|
||||
*
|
||||
* @tparam Child inherited class type used by the downcasting facility (CRTP Idiom)
|
||||
* @tparam P prefix to be appied to the reference unit
|
||||
* @tparam U reference unit
|
||||
* @tparam P prefix to be appied to the coherent_unit unit
|
||||
* @tparam U coherent_unit unit
|
||||
*/
|
||||
template<basic_symbol_text Symbol, Magnitude auto M, NamedUnit auto U>
|
||||
// requires detail::can_be_prefixed<U>
|
||||
struct prefixed_unit : scaled_unit<M* decltype(U)::mag, typename decltype(U)::reference> {
|
||||
// static constexpr auto symbol = symbol + decltype(U)::symbol;
|
||||
static constexpr bool is_base = decltype(U)::is_base;
|
||||
requires unit_can_be_prefixed<U>
|
||||
struct prefixed_unit : std::remove_const_t<decltype(M * U)> {
|
||||
static constexpr auto symbol = Symbol + U.symbol;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A coherent unit of a derived quantity
|
||||
*
|
||||
* Defines a new coherent unit of a derived quantity. It should be passed as a coherent unit
|
||||
* in the dimension's definition for such a quantity.
|
||||
*
|
||||
* @tparam Child inherited class type used by the downcasting facility (CRTP Idiom)
|
||||
*/
|
||||
// template<typename Child>
|
||||
// struct derived_unit : downcast_dispatch<Child, scaled_unit<mag<1>(), Child>> {};
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<basic_symbol_text Symbol, auto... Args>
|
||||
void is_named_impl(const volatile named_unit<Symbol, Args...>*);
|
||||
template<typename T>
|
||||
inline constexpr bool is_power_of_unit =
|
||||
requires { requires is_specialization_of_power<T> && Unit<typename T::factor>; };
|
||||
|
||||
template<basic_symbol_text Symbol, Magnitude auto M, NamedUnit auto U>
|
||||
void is_named_impl(const volatile prefixed_unit<Symbol, M, U>*);
|
||||
template<typename T>
|
||||
concept UnitLike = Unit<T> || is_power_of_unit<T>;
|
||||
|
||||
template<Unit U>
|
||||
inline constexpr bool is_named<U> = requires(U * u) { is_named_impl(u); };
|
||||
template<typename T>
|
||||
inline constexpr bool is_per_of_units = false;
|
||||
|
||||
// template<typename Child, basic_symbol_text Symbol>
|
||||
// void can_be_prefixed_impl(const volatile named_unit<Child, Symbol>*);
|
||||
|
||||
// template<typename Child, basic_symbol_text Symbol, Magnitude auto M, typename U>
|
||||
// void can_be_prefixed_impl(const volatile named_scaled_unit<Child, Symbol, M, U>*);
|
||||
|
||||
// template<typename U, basic_symbol_text Symbol>
|
||||
// void can_be_prefixed_impl(const volatile alias_unit<U, Symbol>*);
|
||||
|
||||
// template<Unit U>
|
||||
// inline constexpr bool can_be_prefixed<U> = requires(U * u) { can_be_prefixed_impl(u); };
|
||||
|
||||
// template<Magnitude auto M, typename U>
|
||||
// inline constexpr bool can_be_prefixed<scaled_unit<M, U>> = can_be_prefixed<typename U::reference>;
|
||||
template<typename... Ts>
|
||||
inline constexpr bool is_per_of_units<per<Ts...>> = (... && UnitLike<Ts>);
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template<typename T>
|
||||
concept UnitSpec = detail::UnitLike<T> || detail::is_per_of_units<T>;
|
||||
|
||||
// User should not instantiate this type!!!
|
||||
// It should not be exported from the module
|
||||
template<UnitSpec... Us>
|
||||
struct derived_unit : detail::expr_fractions<derived_unit<>, Us...> {};
|
||||
|
||||
/**
|
||||
* @brief Unit one
|
||||
*
|
||||
* Unit of a dimensionless quantity.
|
||||
*/
|
||||
inline constexpr struct one : derived_unit<> {
|
||||
} one;
|
||||
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<auto M, typename U>
|
||||
void is_unit_impl(const volatile scaled_unit<M, U>*);
|
||||
|
||||
template<basic_symbol_text Symbol, auto... Args>
|
||||
void is_unit_impl(const volatile named_unit<Symbol, Args...>*);
|
||||
|
||||
template<typename... Us>
|
||||
void is_unit_impl(const volatile derived_unit<Us...>*);
|
||||
|
||||
template<typename T>
|
||||
requires requires(T* t) { is_unit_impl(t); }
|
||||
inline constexpr bool is_unit<T> = true;
|
||||
|
||||
/**
|
||||
* @brief A common point for a hierarchy of units
|
||||
*
|
||||
* A unit is an entity defined and adopted by convention, with which any other quantity of
|
||||
* the same kind can be compared to express the ratio of the second quantity to the first
|
||||
* one as a number.
|
||||
*
|
||||
* All units of the same dimension can be convereted between each other. To allow this all of
|
||||
* them are expressed as different ratios of the same one proprietary chosen coherent_unit unit
|
||||
* (i.e. all length units are expressed in terms of meter, all mass units are expressed in
|
||||
* terms of gram, ...)
|
||||
*
|
||||
* @tparam M a Magnitude representing the (relative) size of this unit
|
||||
* @tparam U a unit to use as a coherent_unit for this dimension
|
||||
*
|
||||
* @note U cannot be constrained with Unit as for some specializations (i.e. named_unit)
|
||||
* it gets the incomplete child's type with the CRTP idiom.
|
||||
*/
|
||||
template<UnitLike U, Magnitude M>
|
||||
struct canonical_unit {
|
||||
U reference_unit;
|
||||
M mag;
|
||||
};
|
||||
|
||||
[[nodiscard]] constexpr auto get_canonical_unit(UnitLike auto u);
|
||||
|
||||
template<UnitLike T, auto M, typename U>
|
||||
[[nodiscard]] constexpr auto get_canonical_unit_impl(T, const volatile scaled_unit<M, U>&)
|
||||
{
|
||||
auto base = get_canonical_unit(U{});
|
||||
return canonical_unit{base.reference_unit, M * base.mag};
|
||||
}
|
||||
|
||||
template<UnitLike T, basic_symbol_text Symbol>
|
||||
[[nodiscard]] constexpr auto get_canonical_unit_impl(T t, const volatile named_unit<Symbol>&)
|
||||
{
|
||||
return canonical_unit{t, mag<1>};
|
||||
}
|
||||
|
||||
template<UnitLike T, basic_symbol_text Symbol, Unit auto U>
|
||||
[[nodiscard]] constexpr auto get_canonical_unit_impl(T, const volatile named_unit<Symbol, U>&)
|
||||
{
|
||||
return get_canonical_unit(U);
|
||||
}
|
||||
|
||||
template<UnitLike T, typename F, int Num, int... Den>
|
||||
[[nodiscard]] constexpr auto get_canonical_unit_impl(T, const volatile power<F, Num, Den...>&)
|
||||
{
|
||||
auto base = get_canonical_unit(F{});
|
||||
return canonical_unit{
|
||||
derived_unit<power_or_T<std::remove_const_t<decltype(base.reference_unit)>, power<F, Num, Den...>::exponent>>{},
|
||||
pow<power<F, Num, Den...>::exponent>(base.mag)};
|
||||
}
|
||||
|
||||
template<UnitLike T, UnitSpec... Us>
|
||||
[[nodiscard]] constexpr auto get_canonical_unit_impl(T, const volatile derived_unit<Us...>&)
|
||||
{
|
||||
if constexpr (type_list_size<typename derived_unit<Us...>::_den_> != 0) {
|
||||
auto num = get_canonical_unit(type_list_map<typename derived_unit<Us...>::_num_, derived_unit>{});
|
||||
auto den = get_canonical_unit(type_list_map<typename derived_unit<Us...>::_den_, derived_unit>{});
|
||||
return canonical_unit{num.reference_unit / den.reference_unit, num.mag / den.mag};
|
||||
} else {
|
||||
auto num = (one * ... * get_canonical_unit(Us{}).reference_unit);
|
||||
auto mag = (units::mag<1> * ... * get_canonical_unit(Us{}).mag);
|
||||
return canonical_unit{num, mag};
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr auto get_canonical_unit(UnitLike auto u) { return get_canonical_unit_impl(u, u); }
|
||||
|
||||
|
||||
template<Unit U1, Unit U2>
|
||||
struct unit_less : std::bool_constant<type_name<U1>() < type_name<U2>()> {};
|
||||
|
||||
template<typename T1, typename T2>
|
||||
using type_list_of_unit_less = expr_less<T1, T2, unit_less>;
|
||||
|
||||
} // namespace detail
|
||||
|
||||
|
||||
// Operators
|
||||
|
||||
template<Magnitude M, Unit U>
|
||||
[[nodiscard]] consteval Unit auto operator*(M mag, U)
|
||||
{
|
||||
return scaled_unit<mag, U>{};
|
||||
// TODO Try passing magnitude parameters rather than magnitude type itself in case of a trivial magnitude
|
||||
// (single integer, ratio...)
|
||||
return scaled_unit<mag, std::remove_const_t<U>>{};
|
||||
}
|
||||
|
||||
template<Magnitude M1, Magnitude auto M2, typename U>
|
||||
[[nodiscard]] consteval Unit auto operator*(M1 mag, scaled_unit<M2, U>)
|
||||
{
|
||||
return scaled_unit<mag * M2, U>{};
|
||||
}
|
||||
template<Magnitude M, Unit U>
|
||||
[[nodiscard]] consteval Unit auto operator*(U, M) = delete;
|
||||
|
||||
template<Unit U1, Unit U2>
|
||||
[[nodiscard]] consteval Unit auto operator*(U1, U2)
|
||||
@@ -324,72 +270,46 @@ template<Unit U>
|
||||
return detail::expr_invert<U, struct one, derived_unit>();
|
||||
}
|
||||
|
||||
template<Unit U>
|
||||
[[nodiscard]] consteval Unit auto operator/(U, int) = delete;
|
||||
|
||||
template<Unit U1, Unit U2>
|
||||
[[nodiscard]] consteval bool operator==(U1, U2)
|
||||
[[nodiscard]] consteval bool operator==(U1 lhs, U2 rhs)
|
||||
{
|
||||
return is_same_v<U1, U2>;
|
||||
auto canonical_lhs = detail::get_canonical_unit(lhs);
|
||||
auto canonical_rhs = detail::get_canonical_unit(rhs);
|
||||
return is_same_v<decltype(canonical_lhs.reference_unit), decltype(canonical_rhs.reference_unit)> &&
|
||||
canonical_lhs.mag == canonical_rhs.mag;
|
||||
}
|
||||
|
||||
|
||||
// template<BaseDimension D1, BaseDimension D2>
|
||||
// constexpr bool operator==(D1, D2)
|
||||
// {
|
||||
// return D1::symbol == D2::symbol;
|
||||
// }
|
||||
|
||||
// template<BaseDimension D1, Dimension D2>
|
||||
// requires(type_list_size<typename D2::normalized_den> == 0) && (type_list_size<typename D2::normalized_num> == 1) &&
|
||||
// BaseDimension<type_list_front<typename D2::normalized_num>>
|
||||
// constexpr bool operator==(D1, D2)
|
||||
// {
|
||||
// return D1::symbol == type_list_front<typename D2::normalized_num>::symbol;
|
||||
// }
|
||||
|
||||
// template<Dimension D1, BaseDimension D2>
|
||||
// requires(type_list_size<typename D1::normalized_den> == 0) && (type_list_size<typename D1::normalized_num> == 1) &&
|
||||
// BaseDimension<type_list_front<typename D1::normalized_num>>
|
||||
// constexpr bool operator==(D1, D2)
|
||||
// {
|
||||
// return type_list_front<typename D1::normalized_num>::symbol == D2::symbol;
|
||||
// }
|
||||
|
||||
// template<DerivedDimension D1, DerivedDimension D2>
|
||||
// constexpr bool operator==(D1, D2)
|
||||
// {
|
||||
// return std::is_same_v<typename D1::normalized_num, typename D2::normalized_num> &&
|
||||
// std::is_same_v<typename D1::normalized_den, typename D2::normalized_den>;
|
||||
// }
|
||||
|
||||
// TODO implement this
|
||||
// template<Dimension D1, Dimension D2>
|
||||
// [[nodiscard]] consteval bool equivalent(D1, D2)
|
||||
// {
|
||||
// return is_same_v<detail::dim_type<D1>, detail::dim_type<D2>>;
|
||||
// }
|
||||
|
||||
// Convertible
|
||||
template<Unit U1, Unit U2>
|
||||
[[nodiscard]] consteval bool convertible(U1, U2)
|
||||
[[nodiscard]] consteval bool convertible(U1 lhs, U2 rhs)
|
||||
{
|
||||
// TODO implement this
|
||||
return std::derived_from<U1, U2> || std::derived_from<U2, U1>;
|
||||
auto canonical_lhs = detail::get_canonical_unit(lhs);
|
||||
auto canonical_rhs = detail::get_canonical_unit(rhs);
|
||||
return is_same_v<decltype(canonical_lhs.reference_unit), decltype(canonical_rhs.reference_unit)>;
|
||||
}
|
||||
|
||||
// Helper types and variable factories
|
||||
template<Unit U>
|
||||
struct square_ : decltype(U{} * U{}) {};
|
||||
|
||||
template<Unit auto U>
|
||||
inline constexpr square_<std::remove_const_t<decltype(U)>> square;
|
||||
|
||||
template<Unit U>
|
||||
struct cubic_ : decltype(U{} * U{} * U{}) {};
|
||||
|
||||
// it is not allowed to use the same name for a variable and class template
|
||||
// (even though it works for objects of regular class types)
|
||||
template<Unit auto U>
|
||||
inline constexpr square_<std::remove_const_t<decltype(U)>> square;
|
||||
|
||||
template<Unit auto U>
|
||||
inline constexpr cubic_<std::remove_const_t<decltype(U)>> cubic;
|
||||
|
||||
} // namespace units
|
||||
|
||||
namespace std {
|
||||
|
||||
// TODO implement this
|
||||
template<units::Unit U1, units::Unit U2>
|
||||
requires(units::convertible(U1{}, U2{}))
|
||||
|
@@ -86,3 +86,16 @@ inline constexpr struct electronvolt : named_unit<"eV", mag<ratio{1'602'176'634,
|
||||
// clang-format on
|
||||
|
||||
} // namespace units::si
|
||||
|
||||
namespace units {
|
||||
|
||||
template<>
|
||||
inline constexpr bool unit_can_be_prefixed<si::degree_Celsius> = false;
|
||||
template<>
|
||||
inline constexpr bool unit_can_be_prefixed<si::minute> = false;
|
||||
template<>
|
||||
inline constexpr bool unit_can_be_prefixed<si::hour> = false;
|
||||
template<>
|
||||
inline constexpr bool unit_can_be_prefixed<si::day> = false;
|
||||
|
||||
} // namespace units
|
||||
|
@@ -35,6 +35,7 @@ cmake_minimum_required(VERSION 3.2)
|
||||
add_library(
|
||||
unit_tests_static
|
||||
dimension_test.cpp
|
||||
|
||||
# angle_test.cpp
|
||||
# cgs_test.cpp
|
||||
# chrono_test.cpp
|
||||
@@ -48,6 +49,7 @@ add_library(
|
||||
# iec80000_test.cpp
|
||||
# kind_test.cpp
|
||||
magnitude_test.cpp
|
||||
|
||||
# math_test.cpp
|
||||
# point_origin_test.cpp
|
||||
# prime_test.cpp
|
||||
@@ -59,7 +61,8 @@ add_library(
|
||||
# si_hep_test.cpp
|
||||
# symbol_text_test.cpp
|
||||
# type_list_test.cpp
|
||||
# unit_test.cpp
|
||||
unit_test.cpp
|
||||
|
||||
# us_test.cpp
|
||||
)
|
||||
|
||||
|
@@ -20,22 +20,26 @@
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
#include "test_tools.h"
|
||||
#include <units/base_dimension.h>
|
||||
#include <units/bits/equivalent.h>
|
||||
#include <units/bits/external/downcasting.h>
|
||||
#include <units/derived_dimension.h>
|
||||
#include <units/isq/si/prefixes.h>
|
||||
#include <units/si/prefixes.h>
|
||||
#include <units/unit.h>
|
||||
|
||||
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;
|
||||
|
||||
// clang-format off
|
||||
// base units
|
||||
inline constexpr struct second_ : named_unit<"s"> {} second;
|
||||
inline constexpr struct metre_ : named_unit<"m"> {} metre;
|
||||
inline constexpr struct gram_ : named_unit<"g"> {} gram;
|
||||
inline constexpr struct kilogram_ : decltype(kilo<gram>) {} kilogram;
|
||||
inline constexpr struct kilogram_ : decltype(si::kilo<gram>) {} kilogram;
|
||||
inline constexpr struct kelvin_ : named_unit<"K"> {} kelvin;
|
||||
|
||||
// derived named units
|
||||
inline constexpr struct radian_ : named_unit<"rad", metre / metre> {} radian;
|
||||
@@ -46,104 +50,371 @@ inline constexpr struct newton_ : named_unit<"N", kilogram * metre / square<seco
|
||||
inline constexpr struct pascal_ : named_unit<"Pa", newton / square<metre>> {} pascal;
|
||||
inline constexpr struct joule_ : named_unit<"J", newton * metre> {} joule;
|
||||
inline constexpr struct watt_ : named_unit<"W", joule / second> {} watt;
|
||||
inline constexpr struct degree_Celsius_ : named_unit<basic_symbol_text{"\u00B0C", "`C"}, kelvin> {} degree_Celsius;
|
||||
|
||||
inline constexpr struct minute_ : named_unit<"min", mag<60> * second> {} minute;
|
||||
inline constexpr struct hour_ : named_unit<"h", mag<60> * minute> {} hour;
|
||||
inline constexpr struct day_ : named_unit<"d", mag<24> * hour> {} day;
|
||||
inline constexpr struct astronomical_unit_ : named_unit<"au", mag<149'597'870'700> * metre> {} astronomical_unit;
|
||||
inline constexpr struct degree_ : named_unit<basic_symbol_text{"°", "deg"}, mag_pi / mag<180> * radian> {} degree;
|
||||
inline constexpr struct are_ : named_unit<"a", square<deca<metre>>> {} are;
|
||||
inline constexpr struct hectare_ : decltype(hecto<are>) {} hectare;
|
||||
inline constexpr struct litre_ : named_unit<"l", cubic<deci<metre>>> {} litre;
|
||||
inline constexpr struct are_ : named_unit<"a", square<si::deca<metre>>> {} are;
|
||||
inline constexpr struct hectare_ : decltype(si::hecto<are>) {} hectare;
|
||||
inline constexpr struct litre_ : named_unit<"l", cubic<si::deci<metre>>> {} litre;
|
||||
inline constexpr struct tonne_ : named_unit<"t", mag<1000> * kilogram> {} tonne;
|
||||
inline constexpr struct dalton_ : named_unit<"Da", mag<ratio{16'605'390'666'050, 10'000'000'000'000}> * mag_power<10, -27> * kilogram> {} dalton;
|
||||
inline constexpr struct electronvolt_ : named_unit<"eV", mag<ratio{1'602'176'634, 1'000'000'000}> * mag_power<10, -19> * joule> {} electronvolt;
|
||||
|
||||
inline constexpr struct kilometre_ : decltype(kilo<metre>) {} kilometre;
|
||||
inline constexpr struct kilometre_ : decltype(si::kilo<metre>) {} kilometre;
|
||||
inline constexpr struct kilojoule_ : decltype(si::kilo<joule>) {} kilojoule;
|
||||
// clang-format on
|
||||
|
||||
}
|
||||
|
||||
// concepts verification
|
||||
static_assert(Unit<metre_>);
|
||||
static_assert(Unit<kilogram_>);
|
||||
static_assert(Unit<hertz_>);
|
||||
static_assert(Unit<newton_>);
|
||||
static_assert(Unit<minute_>);
|
||||
static_assert(Unit<decltype(kilo<gram>)>);
|
||||
static_assert(Unit<decltype(si::kilo<gram>)>);
|
||||
static_assert(Unit<decltype(square<metre>)>);
|
||||
static_assert(Unit<decltype(cubic<metre>)>);
|
||||
static_assert(Unit<decltype(mag<60> * second)>);
|
||||
static_assert(Unit<kilometre_>);
|
||||
|
||||
static_assert(NamedUnit<metre_>);
|
||||
static_assert(NamedUnit<kilogram_>);
|
||||
static_assert(NamedUnit<hertz_>);
|
||||
static_assert(NamedUnit<newton_>);
|
||||
static_assert(NamedUnit<minute_>);
|
||||
static_assert(!NamedUnit<decltype(kilo<gram>)>);
|
||||
static_assert(NamedUnit<radian_>);
|
||||
static_assert(!NamedUnit<kilogram_>);
|
||||
static_assert(!NamedUnit<kilojoule_>);
|
||||
static_assert(!NamedUnit<hectare_>);
|
||||
static_assert(!NamedUnit<decltype(si::kilo<gram>)>);
|
||||
static_assert(!NamedUnit<decltype(square<metre>)>);
|
||||
static_assert(!NamedUnit<decltype(cubic<metre>)>);
|
||||
static_assert(!NamedUnit<decltype(mag<60> * second)>);
|
||||
static_assert(!NamedUnit<kilometre_>);
|
||||
|
||||
template<typename T>
|
||||
constexpr bool print();
|
||||
|
||||
static_assert(kilo<metre> == kilometre);
|
||||
static_assert(mag<1000> * metre == kilo<metre>);
|
||||
// named unit
|
||||
static_assert(is_of_type<metre, metre_>);
|
||||
static_assert(is_of_type<get_canonical_unit(metre).reference_unit, metre_>);
|
||||
static_assert(get_canonical_unit(metre).mag == mag<1>);
|
||||
static_assert(convertible(metre, metre));
|
||||
static_assert(!convertible(metre, second));
|
||||
static_assert(metre == metre);
|
||||
static_assert(metre != second);
|
||||
|
||||
static_assert(is_of_type<degree_Celsius, degree_Celsius_>);
|
||||
static_assert(is_of_type<get_canonical_unit(degree_Celsius).reference_unit, kelvin_>);
|
||||
static_assert(get_canonical_unit(degree_Celsius).mag == mag<1>);
|
||||
static_assert(convertible(degree_Celsius, kelvin));
|
||||
static_assert(degree_Celsius == kelvin);
|
||||
|
||||
static_assert(is_of_type<radian, radian_>);
|
||||
static_assert(is_of_type<get_canonical_unit(radian).reference_unit, one_>);
|
||||
static_assert(get_canonical_unit(radian).mag == mag<1>);
|
||||
static_assert(convertible(minute, second));
|
||||
static_assert(minute != second);
|
||||
|
||||
static_assert(is_of_type<steradian, steradian_>);
|
||||
static_assert(is_of_type<get_canonical_unit(steradian).reference_unit, one_>);
|
||||
static_assert(get_canonical_unit(steradian).mag == mag<1>);
|
||||
static_assert(convertible(radian, steradian)); // !!!
|
||||
static_assert(radian == steradian); // !!!
|
||||
|
||||
static_assert(is_of_type<minute, minute_>);
|
||||
static_assert(is_of_type<get_canonical_unit(minute).reference_unit, second_>);
|
||||
static_assert(get_canonical_unit(minute).mag == mag<60>);
|
||||
static_assert(convertible(minute, second));
|
||||
static_assert(minute != second);
|
||||
|
||||
static_assert(is_of_type<hour, hour_>);
|
||||
static_assert(is_of_type<get_canonical_unit(hour).reference_unit, second_>);
|
||||
static_assert(get_canonical_unit(hour).mag == mag<3600>);
|
||||
static_assert(convertible(hour, second));
|
||||
|
||||
static_assert(convertible(hour, minute));
|
||||
static_assert(convertible(hour, hour));
|
||||
static_assert(hour != second);
|
||||
static_assert(hour != minute);
|
||||
static_assert(hour == hour);
|
||||
|
||||
static_assert(is_of_type<newton, newton_>);
|
||||
static_assert(
|
||||
is_of_type<get_canonical_unit(newton).reference_unit, derived_unit<gram_, metre_, per<power<second_, 2>>>>);
|
||||
static_assert(get_canonical_unit(newton).mag == mag<1000>); // !!! (because of kilogram)
|
||||
static_assert(convertible(newton, newton));
|
||||
static_assert(newton == newton);
|
||||
|
||||
static_assert(is_of_type<joule, joule_>);
|
||||
static_assert(
|
||||
is_of_type<get_canonical_unit(joule).reference_unit, derived_unit<gram_, power<metre_, 2>, per<power<second_, 2>>>>);
|
||||
static_assert(get_canonical_unit(joule).mag == mag<1000>); // !!! (because of kilogram)
|
||||
static_assert(convertible(joule, joule));
|
||||
static_assert(joule == joule);
|
||||
static_assert(joule != newton);
|
||||
|
||||
|
||||
// prefixed_unit
|
||||
static_assert(is_of_type<kilometre, kilometre_>);
|
||||
static_assert(is_of_type<get_canonical_unit(kilometre).reference_unit, metre_>);
|
||||
static_assert(get_canonical_unit(kilometre).mag == mag<1000>);
|
||||
static_assert(convertible(kilometre, metre));
|
||||
static_assert(kilometre != metre);
|
||||
static_assert(kilometre.symbol == "km");
|
||||
|
||||
static_assert(is_of_type<kilojoule, kilojoule_>);
|
||||
static_assert(is_of_type<get_canonical_unit(kilojoule).reference_unit,
|
||||
derived_unit<gram_, power<metre_, 2>, per<power<second_, 2>>>>);
|
||||
static_assert(get_canonical_unit(kilojoule).mag == mag<1'000'000>);
|
||||
static_assert(convertible(kilojoule, joule));
|
||||
static_assert(kilojoule != joule);
|
||||
static_assert(kilojoule.symbol == "kJ");
|
||||
|
||||
static_assert(is_of_type<si::kilo<metre>, si::kilo_<metre>>);
|
||||
static_assert(is_of_type<si::kilo<joule>, si::kilo_<joule>>);
|
||||
|
||||
|
||||
// prefixes
|
||||
static_assert(si::yocto<metre>.symbol == "ym");
|
||||
static_assert(si::zepto<metre>.symbol == "zm");
|
||||
static_assert(si::atto<metre>.symbol == "am");
|
||||
static_assert(si::femto<metre>.symbol == "fm");
|
||||
static_assert(si::pico<metre>.symbol == "pm");
|
||||
static_assert(si::nano<metre>.symbol == "nm");
|
||||
static_assert(si::micro<metre>.symbol == basic_symbol_text{"µm", "um"});
|
||||
static_assert(si::milli<metre>.symbol == "mm");
|
||||
static_assert(si::centi<metre>.symbol == "cm");
|
||||
static_assert(si::deci<metre>.symbol == "dm");
|
||||
static_assert(si::deca<metre>.symbol == "dam");
|
||||
static_assert(si::hecto<metre>.symbol == "hm");
|
||||
static_assert(si::kilo<metre>.symbol == "km");
|
||||
static_assert(si::mega<metre>.symbol == "Mm");
|
||||
static_assert(si::giga<metre>.symbol == "Gm");
|
||||
static_assert(si::tera<metre>.symbol == "Tm");
|
||||
static_assert(si::peta<metre>.symbol == "Pm");
|
||||
static_assert(si::exa<metre>.symbol == "Em");
|
||||
static_assert(si::zetta<metre>.symbol == "Zm");
|
||||
static_assert(si::yotta<metre>.symbol == "Ym");
|
||||
|
||||
|
||||
// scaled_unit
|
||||
constexpr auto u1 = mag<1> * metre;
|
||||
static_assert(is_of_type<u1, scaled_unit<mag<1>, metre_>>);
|
||||
static_assert(is_of_type<get_canonical_unit(u1).reference_unit, metre_>);
|
||||
static_assert(get_canonical_unit(u1).mag == mag<1>);
|
||||
|
||||
constexpr auto u2 = mag<2> * kilometre;
|
||||
static_assert(is_of_type<u2, scaled_unit<mag<2>, kilometre_>>);
|
||||
static_assert(is_of_type<get_canonical_unit(u2).reference_unit, metre_>);
|
||||
static_assert(get_canonical_unit(u2).mag == mag<2000>);
|
||||
|
||||
constexpr auto u3 = mag<42> * si::kilo<joule>;
|
||||
static_assert(is_of_type<u3, scaled_unit<mag<42>, si::kilo_<joule>>>);
|
||||
static_assert(
|
||||
is_of_type<get_canonical_unit(u3).reference_unit, derived_unit<gram_, power<metre_, 2>, per<power<second_, 2>>>>);
|
||||
static_assert(get_canonical_unit(u3).mag == mag<42'000'000>);
|
||||
|
||||
|
||||
// derived unit expression template syntax verification
|
||||
static_assert(is_of_type<1 / second, derived_unit<one_, per<second_>>>);
|
||||
static_assert(is_of_type<1 / (1 / second), second_>);
|
||||
|
||||
static_assert(is_of_type<one * second, second_>);
|
||||
static_assert(is_of_type<second * one, second_>);
|
||||
static_assert(is_of_type<one * (1 / second), derived_unit<one_, per<second_>>>);
|
||||
static_assert(is_of_type<1 / second * one, derived_unit<one_, per<second_>>>);
|
||||
|
||||
static_assert(is_of_type<metre * second, derived_unit<metre_, second_>>);
|
||||
static_assert(is_of_type<metre * metre, derived_unit<power<metre_, 2>>>);
|
||||
|
||||
static_assert(is_of_type<metre * metre * second, derived_unit<power<metre_, 2>, second_>>);
|
||||
static_assert(is_of_type<metre * second * metre, derived_unit<power<metre_, 2>, second_>>);
|
||||
|
||||
static_assert(is_of_type<metre*(second* metre), derived_unit<power<metre_, 2>, second_>>);
|
||||
static_assert(is_of_type<second*(metre* metre), derived_unit<power<metre_, 2>, second_>>);
|
||||
|
||||
static_assert(is_of_type<1 / second * metre, derived_unit<metre_, per<second_>>>);
|
||||
static_assert(is_of_type<1 / second * second, one_>);
|
||||
|
||||
static_assert(is_of_type<second / one, second_>);
|
||||
static_assert(is_of_type<1 / second / one, derived_unit<one_, per<second_>>>);
|
||||
|
||||
static_assert(is_of_type<metre / second * second, metre_>);
|
||||
static_assert(is_of_type<1 / second * (1 / second), derived_unit<one_, per<power<second_, 2>>>>);
|
||||
static_assert(is_of_type<1 / (second * second), derived_unit<one_, per<power<second_, 2>>>>);
|
||||
static_assert(is_of_type<1 / (1 / (second * second)), derived_unit<power<second_, 2>>>);
|
||||
|
||||
static_assert(is_of_type<metre / second * (1 / second), derived_unit<metre_, per<power<second_, 2>>>>);
|
||||
static_assert(is_of_type<metre / second*(metre / second), derived_unit<power<metre_, 2>, per<power<second_, 2>>>>);
|
||||
static_assert(is_of_type<metre / second*(second / metre), one_>);
|
||||
|
||||
static_assert(is_of_type<watt / joule, derived_unit<watt_, per<joule_>>>);
|
||||
static_assert(is_of_type<joule / watt, derived_unit<joule_, per<watt_>>>);
|
||||
|
||||
|
||||
// derived unit normalization
|
||||
constexpr auto u4 = metre / second;
|
||||
static_assert(is_of_type<get_canonical_unit(u4).reference_unit, derived_unit<metre_, per<second_>>>);
|
||||
static_assert(get_canonical_unit(u4).mag == mag<1>);
|
||||
|
||||
constexpr auto u5 = kilometre / second;
|
||||
static_assert(is_of_type<u5, derived_unit<kilometre_, per<second_>>>);
|
||||
static_assert(is_of_type<get_canonical_unit(u5).reference_unit, derived_unit<metre_, per<second_>>>);
|
||||
static_assert(get_canonical_unit(u5).mag == mag<1000>);
|
||||
|
||||
constexpr auto u6 = kilometre / hour;
|
||||
static_assert(is_of_type<u6, derived_unit<kilometre_, per<hour_>>>);
|
||||
static_assert(is_of_type<get_canonical_unit(u6).reference_unit, derived_unit<metre_, per<second_>>>);
|
||||
static_assert(get_canonical_unit(u6).mag == mag<ratio{1000, 3600}>);
|
||||
|
||||
constexpr auto u7 = mag<1000> * kilometre / hour;
|
||||
static_assert(is_of_type<u7, derived_unit<scaled_unit<mag<1000>, kilometre_>, per<hour_>>>);
|
||||
static_assert(is_of_type<get_canonical_unit(u7).reference_unit, derived_unit<metre_, per<second_>>>);
|
||||
static_assert(get_canonical_unit(u7).mag == mag<ratio{1'000'000, 3'600}>);
|
||||
|
||||
constexpr auto u8 = mag<1000> * (kilometre / hour);
|
||||
static_assert(is_of_type<u8, scaled_unit<mag<1000>, derived_unit<kilometre_, per<hour_>>>>);
|
||||
static_assert(is_of_type<get_canonical_unit(u8).reference_unit, derived_unit<metre_, per<second_>>>);
|
||||
static_assert(get_canonical_unit(u8).mag == mag<ratio{1'000'000, 3'600}>);
|
||||
|
||||
constexpr auto u9 = 1 / hour * (mag<1000> * kilometre);
|
||||
static_assert(is_of_type<u9, derived_unit<scaled_unit<mag<1000>, kilometre_>, per<hour_>>>);
|
||||
static_assert(is_of_type<get_canonical_unit(u9).reference_unit, derived_unit<metre_, per<second_>>>);
|
||||
static_assert(get_canonical_unit(u9).mag == mag<ratio{1'000'000, 3'600}>);
|
||||
|
||||
// comparisons of the same units
|
||||
static_assert(second == second);
|
||||
static_assert(metre / second == metre / second);
|
||||
|
||||
// comparisons of equivalent units (named vs unnamed/derived)
|
||||
static_assert(1 / second == hertz);
|
||||
static_assert(convertible(1 / second, hertz));
|
||||
|
||||
// comparisons of equivalent but not convertible units
|
||||
static_assert(hertz == becquerel);
|
||||
static_assert(convertible(hertz, becquerel));
|
||||
|
||||
// comparisons of scaled units
|
||||
static_assert(si::kilo<metre> == kilometre);
|
||||
static_assert(mag<1000> * metre == si::kilo<metre>);
|
||||
static_assert(mag<1000> * metre == kilometre);
|
||||
static_assert(equivalent<kilo<metre>, kilometre>);
|
||||
static_assert(equivalent<mag<1000> * metre, kilo<metre>>);
|
||||
static_assert(equivalent<mag<1000> * metre, kilometre>);
|
||||
static_assert(convertible(si::kilo<metre>, kilometre));
|
||||
static_assert(convertible(mag<1000> * metre, si::kilo<metre>));
|
||||
static_assert(convertible(mag<1000> * metre, kilometre));
|
||||
|
||||
static_assert(metre != kilometre);
|
||||
static_assert(convertible(metre, kilometre));
|
||||
static_assert(mag<100> * metre != kilometre);
|
||||
static_assert(milli<metre> != kilometre);
|
||||
static_assert(!equivalent<metre, kilometre>);
|
||||
static_assert(!equivalent<mag<100> * metre, kilometre>);
|
||||
static_assert(!equivalent<milli<metre>, kilometre>);
|
||||
static_assert(convertible(mag<100> * metre, kilometre));
|
||||
static_assert(si::milli<metre> != kilometre);
|
||||
static_assert(convertible(si::milli<metre>, kilometre));
|
||||
|
||||
static_assert(1 / second != hertz);
|
||||
static_assert(becquerel != hertz);
|
||||
static_assert(equivalent<1 / second, hertz>);
|
||||
static_assert(!equivalent<becquerel, hertz>);
|
||||
// one
|
||||
static_assert(metre / metre == one);
|
||||
// static_assert(metre * metre == square_metre);
|
||||
// static_assert(second * second == second_squared);
|
||||
// static_assert(second * second * second == second_cubed);
|
||||
// static_assert(second * (second * second) == second_cubed);
|
||||
// static_assert(second_squared * second == second_cubed);
|
||||
// static_assert(second * second_squared == second_cubed);
|
||||
|
||||
using namespace units;
|
||||
using namespace units::isq;
|
||||
// static_assert(1 / second * metre == metre / second);
|
||||
// static_assert(metre * (1 / second) == metre / second);
|
||||
// static_assert((metre / second) * (1 / second) == metre / second / second);
|
||||
// static_assert((metre / second) * (1 / second) == metre / (second * second));
|
||||
// static_assert((metre / second) * (1 / second) == metre / second_squared);
|
||||
|
||||
struct metre : named_unit<metre, "m"> {};
|
||||
struct centimetre : prefixed_unit<centimetre, si::centi, metre> {};
|
||||
struct kilometre : prefixed_unit<kilometre, si::kilo, metre> {};
|
||||
struct yard : named_scaled_unit<yard, "yd", mag<ratio{9'144, 10'000}>(), metre> {};
|
||||
struct foot : named_scaled_unit<foot, "ft", mag<ratio(1, 3)>(), yard> {};
|
||||
struct dim_length : base_dimension<"length", metre> {};
|
||||
// static_assert(hertz == 1 / second);
|
||||
// static_assert(newton == kilogram * metre / second_squared);
|
||||
// static_assert(joule == kilogram * square_metre / second_squared);
|
||||
// static_assert(joule == newton * metre);
|
||||
// static_assert(watt == joule / second);
|
||||
// static_assert(watt == kilogram * square_metre / second_cubed);
|
||||
|
||||
struct second : named_unit<second, "s"> {};
|
||||
struct hour : named_scaled_unit<hour, "h", mag<3600>(), second> {};
|
||||
struct dim_time : base_dimension<"time", second> {};
|
||||
// static_assert(1 / frequency_dim == second);
|
||||
// static_assert(frequency_dim * second == one);
|
||||
|
||||
struct kelvin : named_unit<kelvin, "K"> {};
|
||||
// static_assert(metre * metre == area_dim);
|
||||
// static_assert(metre * metre != volume_dim);
|
||||
// static_assert(area_dim / metre == metre);
|
||||
|
||||
#if !UNITS_COMP_MSVC
|
||||
static_assert([]<Prefix P>(P) {
|
||||
return !requires { typename prefixed_unit<struct kilokilometre, P, kilometre>; };
|
||||
}(si::kilo{})); // no prefix allowed
|
||||
#endif
|
||||
// static_assert(metre * metre * metre == volume_dim);
|
||||
// static_assert(area_dim * metre == volume_dim);
|
||||
// static_assert(volume_dim / metre == area_dim);
|
||||
// static_assert(volume_dim / metre / metre == metre);
|
||||
// static_assert(area_dim * area_dim / metre == volume_dim);
|
||||
// static_assert(area_dim * (area_dim / metre) == volume_dim);
|
||||
// static_assert(volume_dim / (metre * metre) == metre);
|
||||
|
||||
struct metre_per_second : derived_unit<metre_per_second> {};
|
||||
struct dim_speed :
|
||||
derived_dimension<dim_speed, metre_per_second, units::exponent<dim_length, 1>, units::exponent<dim_time, -1>> {};
|
||||
struct kilometre_per_hour : derived_scaled_unit<kilometre_per_hour, dim_speed, kilometre, hour> {};
|
||||
// static_assert(metre / second == speed_dim);
|
||||
// static_assert(metre * second != speed_dim);
|
||||
// static_assert(metre / second / second != speed_dim);
|
||||
// static_assert(metre / speed_dim == second);
|
||||
// static_assert(speed_dim * second == metre);
|
||||
|
||||
static_assert(equivalent<metre::named_unit, metre>);
|
||||
static_assert(equivalent<metre::scaled_unit, metre>);
|
||||
static_assert(compare<downcast<scaled_unit<mag<1>(), metre>>, metre>);
|
||||
static_assert(compare<downcast<scaled_unit<mag<ratio(1, 100)>(), metre>>, centimetre>);
|
||||
static_assert(compare<downcast<scaled_unit<yard::mag, metre>>, yard>);
|
||||
static_assert(compare<downcast<scaled_unit<yard::mag / mag<3>(), metre>>, foot>);
|
||||
static_assert(compare<downcast<scaled_unit<kilometre::mag / hour::mag, metre_per_second>>, kilometre_per_hour>);
|
||||
// static_assert(metre / second / second == acceleration_dim);
|
||||
// static_assert(metre / (second * second) == acceleration_dim);
|
||||
// static_assert(speed_dim / second == acceleration_dim);
|
||||
// static_assert(speed_dim / acceleration_dim == second);
|
||||
// static_assert(acceleration_dim * second == speed_dim);
|
||||
// static_assert(acceleration_dim * (second * second) == metre);
|
||||
// static_assert(acceleration_dim / speed_dim == frequency_dim);
|
||||
|
||||
|
||||
// milli<metre> / milli<second> == micro<metre> / micro<second>;
|
||||
// milli<metre> * kilo<metre> == deci<metre> * deca<metre>;
|
||||
|
||||
// Bq + Hz should not compile
|
||||
|
||||
// Bq + Hz + 1/s should compile?
|
||||
|
||||
|
||||
// using namespace units;
|
||||
// using namespace units::isq;
|
||||
|
||||
// struct metre : named_unit<metre, "m"> {};
|
||||
// struct centimetre : prefixed_unit<centimetre, si::centi, metre> {};
|
||||
// struct kilometre : prefixed_unit<kilometre, si::kilo, metre> {};
|
||||
// struct yard : named_scaled_unit<yard, "yd", mag<ratio{9'144, 10'000}>(), metre> {};
|
||||
// struct foot : named_scaled_unit<foot, "ft", mag<ratio(1, 3)>(), yard> {};
|
||||
// struct dim_length : base_dimension<"length", metre> {};
|
||||
|
||||
// struct second : named_unit<second, "s"> {};
|
||||
// struct hour : named_scaled_unit<hour, "h", mag<3600>(), second> {};
|
||||
// struct dim_time : base_dimension<"time", second> {};
|
||||
|
||||
// struct kelvin : named_unit<kelvin, "K"> {};
|
||||
|
||||
// #if !UNITS_COMP_MSVC
|
||||
// static_assert([]<Prefix P>(P) {
|
||||
// return !requires { typename prefixed_unit<struct kilokilometre, P, kilometre>; };
|
||||
// }(si::kilo{})); // no prefix allowed
|
||||
// #endif
|
||||
|
||||
// struct metre_per_second : derived_unit<metre_per_second> {};
|
||||
// struct dim_speed :
|
||||
// derived_dimension<dim_speed, metre_per_second, units::exponent<dim_length, 1>, units::exponent<dim_time, -1>> {};
|
||||
// struct kilometre_per_hour : derived_scaled_unit<kilometre_per_hour, dim_speed, kilometre, hour> {};
|
||||
|
||||
// static_assert(equivalent<metre::named_unit, metre>);
|
||||
// static_assert(equivalent<metre::scaled_unit, metre>);
|
||||
// static_assert(compare<downcast<scaled_unit<mag<1>(), metre>>, metre>);
|
||||
// static_assert(compare<downcast<scaled_unit<mag<ratio(1, 100)>(), metre>>, centimetre>);
|
||||
// static_assert(compare<downcast<scaled_unit<yard::mag, metre>>, yard>);
|
||||
// static_assert(compare<downcast<scaled_unit<yard::mag / mag<3>(), metre>>, foot>);
|
||||
// static_assert(compare<downcast<scaled_unit<kilometre::mag / hour::mag, metre_per_second>>, kilometre_per_hour>);
|
||||
|
||||
// static_assert(centimetre::symbol == "cm");
|
||||
// static_assert(kilometre::symbol == "km");
|
||||
// static_assert(kilometre_per_hour::symbol == "km/h");
|
||||
|
||||
|
||||
// static_assert(si::metre != si::kilometre);
|
||||
// static_assert(!equivalent(si::metre, si::kilometre));
|
||||
// static_assert(convertible(si::metre, si::kilometre));
|
||||
|
||||
static_assert(centimetre::symbol == "cm");
|
||||
static_assert(kilometre::symbol == "km");
|
||||
static_assert(kilometre_per_hour::symbol == "km/h");
|
||||
|
||||
} // namespace
|
||||
|
Reference in New Issue
Block a user