mirror of
https://github.com/mpusz/mp-units.git
synced 2025-08-03 12:24:26 +02:00
feat: Added support for natural units-like systems + dimension_one
cleanup
This commit is contained in:
@@ -44,27 +44,6 @@ static_assert(can_not_be_prefixed<si::milli_, si::kilogram>);
|
||||
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 * 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 * 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 * 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 * 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 * isq::speed[m / s] / (10 * isq::length[m]) * (5 * isq::time[s])),
|
||||
quantity<reference<struct dimensionless, struct one>{}, int>>);
|
||||
|
||||
// Comparisons
|
||||
|
||||
|
@@ -472,23 +472,47 @@ template<std::intmax_t Num, std::intmax_t Den, template<typename...> typename To
|
||||
|
||||
|
||||
// expr_map
|
||||
template<typename T, template<typename> typename Proj>
|
||||
struct expr_type_map;
|
||||
|
||||
template<typename T, template<typename...> typename Proj>
|
||||
struct expr_type_map {
|
||||
template<typename T, template<typename> typename Proj>
|
||||
requires requires { typename Proj<T>; }
|
||||
struct expr_type_map<T, Proj> {
|
||||
using type = Proj<T>;
|
||||
};
|
||||
|
||||
template<typename F, int... Ints, template<typename...> typename Proj>
|
||||
template<typename F, int... Ints, template<typename> typename Proj>
|
||||
requires requires { typename Proj<F>; }
|
||||
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>
|
||||
template<typename T, template<typename> typename Proj>
|
||||
concept expr_type_projectable = (requires { typename Proj<T>; } ||
|
||||
(is_specialization_of_power<T> && requires { typename Proj<typename T::factor>; }));
|
||||
|
||||
template<typename T, template<typename> typename Proj>
|
||||
inline constexpr bool expr_projectable_impl = false;
|
||||
|
||||
template<typename... Ts, template<typename> typename Proj>
|
||||
inline constexpr bool expr_projectable_impl<type_list<Ts...>, Proj> = (... && expr_type_projectable<Ts, Proj>);
|
||||
|
||||
template<typename T, template<typename> typename Proj>
|
||||
concept expr_projectable = requires {
|
||||
typename T::_num_;
|
||||
typename T::_den_;
|
||||
requires type_list_size<typename T::_num_> + type_list_size<typename T::_den_> > 0;
|
||||
requires expr_projectable_impl<typename T::_num_, Proj>;
|
||||
requires expr_projectable_impl<typename T::_den_, Proj>;
|
||||
};
|
||||
|
||||
template<template<typename> typename Proj, template<typename...> typename To, typename OneType,
|
||||
template<typename, typename> typename Pred, expr_type_projectable<Proj>... Nums,
|
||||
expr_type_projectable<Proj>... 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>;
|
||||
using nums = type_list_sort<type_list<typename expr_type_map<std::remove_const_t<Nums>, Proj>::type...>, Pred>;
|
||||
using dens = type_list_sort<type_list<typename expr_type_map<std::remove_const_t<Dens>, Proj>::type...>, Pred>;
|
||||
return detail::get_optimized_expression<nums, dens, OneType, Pred, To>();
|
||||
}
|
||||
|
||||
@@ -501,8 +525,8 @@ template<template<typename...> typename Proj, template<typename...> typename To,
|
||||
* @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>
|
||||
template<template<typename> typename Proj, template<typename...> typename To, typename OneType,
|
||||
template<typename, typename> typename Pred, expr_projectable<Proj> T>
|
||||
[[nodiscard]] consteval auto expr_map(T)
|
||||
{
|
||||
return expr_map_impl<Proj, To, OneType, Pred>(typename T::_num_{}, typename T::_den_{});
|
||||
|
@@ -53,13 +53,16 @@ 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<Unit auto U, Dimension auto Dim>
|
||||
inline constexpr bool is_valid_unit_for_dimension = false;
|
||||
|
||||
}
|
||||
|
||||
template<typename U, typename Dim>
|
||||
concept valid_unit_for_dimension = Unit<U> && Dimension<Dim> && detail::is_valid_unit_for_dimension<U{}, Dim{}>;
|
||||
|
||||
template<Dimension D, Unit U>
|
||||
struct reference;
|
||||
|
||||
@@ -100,12 +103,10 @@ 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{})))
|
||||
template<typename Self, valid_unit_for_dimension<Self> U>
|
||||
[[nodiscard]] constexpr reference<Self, U> operator[](this const Self, U)
|
||||
#else
|
||||
template<Unit U>
|
||||
requires(convertible(Self{}, detail::get_dimension_for(U{})))
|
||||
template<valid_unit_for_dimension<Self> U>
|
||||
[[nodiscard]] constexpr reference<Self, U> operator[](U) const
|
||||
#endif
|
||||
{
|
||||
@@ -122,13 +123,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_dimensionless = false;
|
||||
inline constexpr bool is_dimension_one = false;
|
||||
|
||||
template<typename T>
|
||||
inline constexpr bool is_power_of_dim =
|
||||
requires {
|
||||
requires is_specialization_of_power<T> &&
|
||||
(BaseDimension<typename T::factor> || is_dimensionless<typename T::factor>);
|
||||
(BaseDimension<typename T::factor> || is_dimension_one<typename T::factor>);
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
@@ -136,13 +137,13 @@ inline constexpr bool is_per_of_dims = false;
|
||||
|
||||
template<typename... Ts>
|
||||
inline constexpr bool is_per_of_dims<per<Ts...>> =
|
||||
(... && (BaseDimension<Ts> || is_dimensionless<Ts> || is_power_of_dim<Ts>));
|
||||
(... && (BaseDimension<Ts> || is_dimension_one<Ts> || is_power_of_dim<Ts>));
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template<typename T>
|
||||
concept DerivedDimensionSpec =
|
||||
BaseDimension<T> || detail::is_dimensionless<T> || detail::is_power_of_dim<T> || detail::is_per_of_dims<T>;
|
||||
BaseDimension<T> || detail::is_dimension_one<T> || detail::is_power_of_dim<T> || detail::is_per_of_dims<T>;
|
||||
|
||||
template<typename...>
|
||||
struct derived_dimension;
|
||||
@@ -167,7 +168,7 @@ 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 `dimensionless` being a dimension of
|
||||
* is also one special case. In case all of the exponents are negative than the `dimension_one` being a dimension of
|
||||
* a dimensionless quantity is put in the front to increase the readability.
|
||||
*
|
||||
* For example:
|
||||
@@ -182,7 +183,7 @@ struct derived_dimension_impl : detail::expr_fractions<derived_dimension<>, Ds..
|
||||
* DERIVED_DIMENSION(torque, moment_of_force);
|
||||
* @endcode
|
||||
*
|
||||
* - `frequency` will be derived from type `derived_dimension<dimensionless, per<time>>`
|
||||
* - `frequency` will be derived from type `derived_dimension<dimension_one, 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>>>`
|
||||
@@ -201,7 +202,7 @@ struct derived_dimension_impl : detail::expr_fractions<derived_dimension<>, Ds..
|
||||
* dimensionally equivalent quantities.
|
||||
*
|
||||
* @tparam Ds a parameter pack consisting tokens allowed in the dimension specification
|
||||
* (base dimensions, `dimensionless`, `power<Dim, Num, Den>`, `per<...>`)
|
||||
* (base dimensions, `dimension_one`, `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.
|
||||
@@ -210,8 +211,8 @@ struct derived_dimension_impl : detail::expr_fractions<derived_dimension<>, Ds..
|
||||
|
||||
template<DerivedDimensionSpec... Ds>
|
||||
struct derived_dimension : detail::derived_dimension_impl<Ds...> {
|
||||
template<Unit U, typename Self>
|
||||
requires(convertible(Self{}, detail::get_dimension_for(U{})))
|
||||
template<typename Self, Unit U>
|
||||
requires valid_unit_for_dimension<U, Self> || (sizeof...(Ds) == 0 && convertible(U{}, one))
|
||||
[[nodiscard]] constexpr reference<Self, U> operator[](this const Self, U)
|
||||
{
|
||||
return {};
|
||||
@@ -226,7 +227,7 @@ 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{})))
|
||||
requires valid_unit_for_dimension<U, derived_dimension> || (sizeof...(Ds) == 0 && convertible(U{}, one))
|
||||
[[nodiscard]] constexpr reference<derived_dimension, U> operator[](U) const
|
||||
{
|
||||
return {};
|
||||
@@ -236,7 +237,8 @@ struct derived_dimension<Ds...> : detail::derived_dimension_impl<Ds...> {
|
||||
template<typename Self, DerivedDimension D>
|
||||
struct derived_dimension<Self, D> : D {
|
||||
template<Unit U>
|
||||
requires(convertible(Self{}, detail::get_dimension_for(U{})))
|
||||
requires valid_unit_for_dimension<U, Self> ||
|
||||
(convertible(derived_dimension{}, derived_dimension<>{}) && convertible(U{}, one))
|
||||
[[nodiscard]] constexpr reference<Self, U> operator[](U) const
|
||||
{
|
||||
return {};
|
||||
@@ -266,13 +268,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 dimensionless : derived_dimension<> {
|
||||
} dimensionless;
|
||||
inline constexpr struct dimension_one : derived_dimension<> {
|
||||
} dimension_one;
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<>
|
||||
inline constexpr bool is_dimensionless<struct dimensionless> = true;
|
||||
inline constexpr bool is_dimension_one<struct dimension_one> = true;
|
||||
|
||||
template<Dimension T>
|
||||
struct dim_type_impl {
|
||||
@@ -295,14 +297,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 dimensionless, detail::type_list_of_base_dimension_less>(
|
||||
return detail::expr_multiply<derived_dimension, struct dimension_one, 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 dimensionless, detail::type_list_of_base_dimension_less>(
|
||||
return detail::expr_divide<derived_dimension, struct dimension_one, detail::type_list_of_base_dimension_less>(
|
||||
detail::dim_type<Lhs>{}, detail::dim_type<Rhs>{});
|
||||
}
|
||||
|
||||
@@ -310,7 +312,7 @@ template<Dimension D>
|
||||
[[nodiscard]] consteval Dimension auto operator/(int value, D)
|
||||
{
|
||||
gsl_Expects(value == 1);
|
||||
return detail::expr_invert<derived_dimension, struct dimensionless>(detail::dim_type<D>{});
|
||||
return detail::expr_invert<derived_dimension, struct dimension_one>(detail::dim_type<D>{});
|
||||
}
|
||||
|
||||
template<Dimension D>
|
||||
@@ -347,7 +349,7 @@ 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 dimensionless,
|
||||
return detail::expr_pow<Num, Den, derived_dimension, struct dimension_one,
|
||||
detail::type_list_of_base_dimension_less>(d);
|
||||
}
|
||||
|
||||
@@ -366,16 +368,24 @@ 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)
|
||||
requires detail::expr_projectable<derived_unit<Us...>, to_base_dimension>
|
||||
{
|
||||
return detail::expr_map<to_base_dimension, derived_dimension, struct dimensionless,
|
||||
return detail::expr_map<to_base_dimension, derived_dimension, struct dimension_one,
|
||||
detail::type_list_of_base_dimension_less>(u);
|
||||
}
|
||||
|
||||
[[nodiscard]] consteval Dimension auto get_dimension_for(Unit auto u)
|
||||
template<typename U>
|
||||
concept associated_unit = Unit<U> && requires(U u) { get_dimension_for_impl(get_canonical_unit(u).reference_unit); };
|
||||
|
||||
[[nodiscard]] consteval Dimension auto get_dimension_for(associated_unit auto u)
|
||||
{
|
||||
return get_dimension_for_impl(get_canonical_unit(u).reference_unit);
|
||||
}
|
||||
|
||||
template<Unit auto U, Dimension auto Dim>
|
||||
requires requires { detail::get_dimension_for(U); } && (convertible(Dim, detail::get_dimension_for(U)))
|
||||
inline constexpr bool is_valid_unit_for_dimension<U, Dim> = true;
|
||||
|
||||
} // namespace detail
|
||||
|
||||
|
||||
|
@@ -48,7 +48,7 @@ inline constexpr auto make_quantity = [](Representation auto&& v) {
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
concept quantity_one = Quantity<T> && (T::dimension == dimensionless) && (T::unit == one);
|
||||
concept quantity_one = Quantity<T> && (T::dimension == dimension_one) && (T::unit == one);
|
||||
|
||||
} // namespace detail
|
||||
|
||||
@@ -419,7 +419,7 @@ public:
|
||||
requires(!Quantity<Value>) && (invoke_result_convertible_to_<rep, std::divides<>, const Value&, rep>)
|
||||
[[nodiscard]] friend constexpr Quantity auto operator/(const Value& v, const quantity& q)
|
||||
{
|
||||
return detail::make_quantity<dimensionless[::units::one] / reference>(v / q.number());
|
||||
return detail::make_quantity<dimension_one[::units::one] / reference>(v / q.number());
|
||||
}
|
||||
|
||||
template<typename Value>
|
||||
@@ -463,7 +463,7 @@ template<auto R, typename Rep>
|
||||
explicit(false) quantity(quantity<R, Rep>) -> quantity<R, Rep>;
|
||||
|
||||
template<Representation Rep>
|
||||
explicit(false) quantity(Rep)->quantity<dimensionless[one], Rep>;
|
||||
explicit(false) quantity(Rep)->quantity<dimension_one[one], Rep>;
|
||||
|
||||
template<QuantityLike Q>
|
||||
explicit quantity(Q)
|
||||
@@ -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, dimensionless>) &&
|
||||
(std::convertible_to<Q2, Q1> || quantity_of<Q2, dimension_one>) &&
|
||||
(quantity_value_for_<std::modulus<>, typename Q1::rep, typename Q2::rep>)
|
||||
[[nodiscard]] constexpr Quantity auto operator%(const Q1& lhs, const Q2& rhs)
|
||||
{
|
||||
|
@@ -28,22 +28,6 @@
|
||||
|
||||
namespace units {
|
||||
|
||||
template<Dimension auto Dim, Unit auto CoU>
|
||||
struct system_reference;
|
||||
|
||||
// namespace detail {
|
||||
|
||||
// template<typename Child, auto Dim, auto CoU>
|
||||
// void to_base_specialization_of_inline constexpr struct const volatile system_reference<Child : system_reference<Dim,
|
||||
// CoU>*> {} const volatile system_reference<Child;
|
||||
|
||||
// template<typename T>
|
||||
// // inline constexpr bool // TODO: Replace with concept when it works with MSVC
|
||||
// concept is_derived_from_specialization_of_system_reference =
|
||||
// requires(T* t) { detail::to_base_specialization_of_system_reference(t); };
|
||||
|
||||
// } // namespace detail
|
||||
|
||||
/**
|
||||
* @brief The type for quantity references
|
||||
*
|
||||
@@ -83,15 +67,6 @@ struct system_reference;
|
||||
* The following syntaxes are not allowed:
|
||||
* `2 / s`, `km * 3`, `s / 4`, `70 * km / h`.
|
||||
*/
|
||||
// template<typename R, Unit U>
|
||||
// requires detail::is_derived_from_specialization_of_system_reference<R>
|
||||
// struct reference<R, U> {
|
||||
// using system_reference = R;
|
||||
// static constexpr auto dimension = R::dimension;
|
||||
// static constexpr U unit{};
|
||||
// // static constexpr UNITS_MSVC_WORKAROUND(Magnitude) auto mag = dimension::mag * unit::mag;
|
||||
// };
|
||||
|
||||
template<Dimension D, Unit U>
|
||||
struct reference {
|
||||
static constexpr D dimension{};
|
||||
@@ -107,13 +82,6 @@ template<Magnitude M, Reference R>
|
||||
return {};
|
||||
}
|
||||
|
||||
// template<Magnitude M, Reference R>
|
||||
// requires requires { typename R::system_reference; }
|
||||
// [[nodiscard]] consteval reference<typename R::system_reference, decltype(M{} * R::unit)> operator*(M, R)
|
||||
// {
|
||||
// return {};
|
||||
// }
|
||||
|
||||
template<Reference R1, Reference R2>
|
||||
[[nodiscard]] consteval reference<decltype(R1::dimension * R2::dimension), decltype(R1::unit * R2::unit)> operator*(R1,
|
||||
R2)
|
||||
@@ -142,14 +110,9 @@ template<Reference R1, Reference R2>
|
||||
return convertible(R1::dimension, R2::dimension) && convertible(R1::unit, R2::unit);
|
||||
}
|
||||
|
||||
// template<Reference R1, Reference R2>
|
||||
// [[nodiscard]] consteval bool castable(R1, R2)
|
||||
// {
|
||||
// return equivalent(R1::dimension, R2::dimension) && convertible(R1::unit, R2::unit);
|
||||
// }
|
||||
|
||||
|
||||
template<Dimension auto Dim, Unit auto CoU>
|
||||
requires(!detail::associated_unit<std::remove_const_t<decltype(CoU)>>)
|
||||
struct system_reference {
|
||||
static constexpr auto dimension = Dim;
|
||||
static constexpr auto coherent_unit = CoU;
|
||||
|
@@ -148,8 +148,10 @@ struct named_unit;
|
||||
/**
|
||||
* @brief Specialization for unit of a specified base dimension
|
||||
*
|
||||
* 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.
|
||||
* Associates a unit with a specified base dimension.
|
||||
* For example `si::metre` is a unit to measure `isq::length` in the SI system.
|
||||
*
|
||||
* @note This is the preferred way to define a measurement unit for a specific base dimension.
|
||||
*
|
||||
* @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`
|
||||
@@ -170,9 +172,9 @@ struct named_unit<Symbol, 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.
|
||||
* system of units uses the same unit. For example in a hypothetical system of natural 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
|
||||
*/
|
||||
@@ -337,7 +339,6 @@ struct derived_unit : detail::expr_fractions<derived_unit<>, Us...> {};
|
||||
inline constexpr struct one : derived_unit<> {
|
||||
} one;
|
||||
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<auto M, typename U>
|
||||
|
@@ -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,11 +49,13 @@ add_library(
|
||||
# iec80000_test.cpp
|
||||
# kind_test.cpp
|
||||
magnitude_test.cpp
|
||||
|
||||
# math_test.cpp
|
||||
# point_origin_test.cpp
|
||||
# prime_test.cpp
|
||||
ratio_test.cpp
|
||||
# references_test.cpp
|
||||
reference_test.cpp
|
||||
|
||||
# si_test.cpp
|
||||
# si_cgs_test.cpp
|
||||
# si_fps_test.cpp
|
||||
@@ -60,6 +63,7 @@ add_library(
|
||||
# symbol_text_test.cpp
|
||||
type_list_test.cpp
|
||||
unit_test.cpp
|
||||
|
||||
# us_test.cpp
|
||||
)
|
||||
|
||||
|
@@ -22,18 +22,23 @@
|
||||
|
||||
#include "test_tools.h"
|
||||
#include <units/dimension.h>
|
||||
#include <units/quantity.h>
|
||||
#include <units/reference.h>
|
||||
#include <units/unit.h>
|
||||
|
||||
namespace {
|
||||
|
||||
using namespace units;
|
||||
|
||||
using dimensionless_ = struct dimensionless;
|
||||
using dimension_one_ = struct dimension_one;
|
||||
|
||||
// clang-format off
|
||||
BASE_DIMENSION_(length, "L");
|
||||
BASE_DIMENSION_(time, "T");
|
||||
BASE_DIMENSION_(mass, "M");
|
||||
|
||||
inline constexpr struct second_ : named_unit<"s", time> {} second;
|
||||
|
||||
DERIVED_DIMENSION_(frequency, decltype(1 / time));
|
||||
DERIVED_DIMENSION_(action, decltype(1 / time));
|
||||
DERIVED_DIMENSION_(area, decltype(length * length));
|
||||
@@ -60,18 +65,18 @@ static_assert(DerivedDimension<frequency_>);
|
||||
static_assert(Dimension<length_>);
|
||||
static_assert(Dimension<frequency_>);
|
||||
|
||||
static_assert(DerivedDimension<dimensionless_>);
|
||||
static_assert(DerivedDimension<decltype(length / length)>); // dimensionless
|
||||
static_assert(DerivedDimension<dimension_one_>);
|
||||
static_assert(DerivedDimension<decltype(length / length)>); // dimension_one
|
||||
static_assert(BaseDimension<decltype(speed * time)>); // length
|
||||
|
||||
// derived dimension expression template syntax verification
|
||||
static_assert(is_of_type<1 / time, derived_dimension<dimensionless_, per<time_>>>);
|
||||
static_assert(is_of_type<1 / time, derived_dimension<dimension_one_, per<time_>>>);
|
||||
static_assert(is_of_type<1 / (1 / time), time_>);
|
||||
|
||||
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<dimension_one * time, time_>);
|
||||
static_assert(is_of_type<time * dimension_one, time_>);
|
||||
static_assert(is_of_type<dimension_one * (1 / time), derived_dimension<dimension_one_, per<time_>>>);
|
||||
static_assert(is_of_type<1 / time * dimension_one, derived_dimension<dimension_one_, per<time_>>>);
|
||||
|
||||
static_assert(is_of_type<length * time, derived_dimension<length_, time_>>);
|
||||
static_assert(is_of_type<length * length, derived_dimension<units::power<length_, 2>>>);
|
||||
@@ -83,37 +88,79 @@ static_assert(is_of_type<length*(time* length), derived_dimension<units::power<l
|
||||
static_assert(is_of_type<time*(length* length), derived_dimension<units::power<length_, 2>, time_>>);
|
||||
|
||||
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<1 / time * time, dimension_one_>);
|
||||
|
||||
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<time / dimension_one, time_>);
|
||||
static_assert(is_of_type<1 / time / dimension_one, derived_dimension<dimension_one_, per<time_>>>);
|
||||
|
||||
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 / time * (1 / time), derived_dimension<dimension_one_, per<units::power<time_, 2>>>>);
|
||||
static_assert(is_of_type<1 / (time * time), derived_dimension<dimension_one_, 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 / 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<length / time*(time / length), dimension_one_>);
|
||||
|
||||
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<acceleration / speed, derived_dimension<dimension_one_, 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_>>>);
|
||||
|
||||
template<auto& t>
|
||||
concept invalid_operations = requires {
|
||||
requires !requires { t < t; };
|
||||
requires !requires { t / 2; };
|
||||
requires !requires { 2 * t; };
|
||||
requires !requires { t * 2; };
|
||||
requires !requires { t + 2; };
|
||||
requires !requires { 2 + t; };
|
||||
requires !requires { t + t; };
|
||||
requires !requires { t - 2; };
|
||||
requires !requires { 2 - t; };
|
||||
requires !requires { t - t; };
|
||||
requires !requires { t == 2; };
|
||||
requires !requires { 2 == t; };
|
||||
requires !requires { t < 2; };
|
||||
requires !requires { 2 < t; };
|
||||
requires !requires { t + time[second]; };
|
||||
requires !requires { t - time[second]; };
|
||||
requires !requires { t* time[second]; };
|
||||
requires !requires { t / time[second]; };
|
||||
requires !requires { t == time[second]; };
|
||||
requires !requires { t < time[second]; };
|
||||
requires !requires { time[second] + t; };
|
||||
requires !requires { time[second] - t; };
|
||||
requires !requires { time[second] * t; };
|
||||
requires !requires { time[second] / t; };
|
||||
requires !requires { time[second] == t; };
|
||||
requires !requires { time[second] < t; };
|
||||
requires !requires { t + 1 * time[second]; };
|
||||
requires !requires { t - 1 * time[second]; };
|
||||
requires !requires { t * 1 * time[second]; };
|
||||
requires !requires { t / 1 * time[second]; };
|
||||
requires !requires { t == 1 * time[second]; };
|
||||
requires !requires { t == 1 * time[second]; };
|
||||
requires !requires { 1 * time[second] + t; };
|
||||
requires !requires { 1 * time[second] - t; };
|
||||
requires !requires { 1 * time[second] * t; };
|
||||
requires !requires { 1 * time[second] == t; };
|
||||
requires !requires { 1 * time[second] < t; };
|
||||
};
|
||||
static_assert(invalid_operations<time>);
|
||||
|
||||
// comparisons of the same dimensions
|
||||
static_assert(length == length);
|
||||
static_assert(speed == speed);
|
||||
|
||||
// comparisons of equivalent dimensions (named vs unnamed/derived)
|
||||
static_assert(length / length == dimensionless);
|
||||
static_assert(length / length == dimension_one);
|
||||
|
||||
static_assert(1 / time != frequency);
|
||||
static_assert(convertible(1 / time, frequency));
|
||||
static_assert(1 / frequency == time);
|
||||
static_assert(frequency * time == dimensionless);
|
||||
static_assert(frequency * time == dimension_one);
|
||||
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_>);
|
||||
|
||||
@@ -181,10 +228,10 @@ static_assert(frequency != action);
|
||||
static_assert(!convertible(frequency, action));
|
||||
static_assert(no_common_type<frequency, action>);
|
||||
|
||||
// Dimensionless
|
||||
// dimension_one
|
||||
static_assert(convertible(power / power, efficiency));
|
||||
static_assert(power / power != efficiency);
|
||||
static_assert(dimensionless != efficiency);
|
||||
static_assert(dimension_one != efficiency);
|
||||
|
||||
static_assert(!convertible(efficiency, strain));
|
||||
static_assert(efficiency != strain);
|
||||
|
@@ -55,8 +55,8 @@ struct height_kind : kind<height_kind, dim_length> {};
|
||||
struct horizontal_area_kind : derived_kind<horizontal_area_kind, dim_area, width_kind> {};
|
||||
struct rate_of_climb_kind : derived_kind<rate_of_climb_kind, dim_speed, height_kind> {};
|
||||
|
||||
struct apple : kind<apple, dim_one> {};
|
||||
struct orange : kind<orange, dim_one> {};
|
||||
struct apple : kind<apple, dimension_one> {};
|
||||
struct orange : kind<orange, dimension_one> {};
|
||||
|
||||
struct time_kind : kind<time_kind, dim_time> {};
|
||||
|
||||
@@ -420,7 +420,7 @@ static_assert((std::uint8_t(255) * m %= quantity(256)) ==
|
||||
(width<metre, std::uint8_t>(255 * m) %= quantity(256)).common());
|
||||
// static_assert((std::uint8_t(255) * m %= 256 * m) ==
|
||||
// (width<metre, std::uint8_t>(255 * m) %=
|
||||
// quantity_kind<downcast_kind<width_kind, dim_one>, one, std::uint8_t>(256)).common()); // UB
|
||||
// quantity_kind<downcast_kind<width_kind, dimension_one>, one, std::uint8_t>(256)).common()); // UB
|
||||
// static_assert((std::uint8_t(255) * m %= 256 * m) !=
|
||||
// (width<metre, std::uint8_t>(255 * m) %= width<metre, std::uint8_t>(256 * m)).common()); // UB
|
||||
static_assert((std::uint8_t(255) * m %= 257) == (width<metre, std::uint8_t>(255 * m) %= 257).common());
|
||||
@@ -428,7 +428,7 @@ static_assert((std::uint8_t(255) * m %= quantity(257)) ==
|
||||
(width<metre, std::uint8_t>(255 * m) %= quantity(257)).common());
|
||||
static_assert((std::uint8_t(255) * m %= 257 * m) ==
|
||||
(width<metre, std::uint8_t>(255 * m) %=
|
||||
quantity_kind<downcast_kind<width_kind, dim_one>, one, std::uint8_t>(257))
|
||||
quantity_kind<downcast_kind<width_kind, dimension_one>, one, std::uint8_t>(257))
|
||||
.common());
|
||||
static_assert((std::uint8_t(255) * m %= 257 * m) ==
|
||||
(width<metre, std::uint8_t>(255 * m) %= width<metre, std::uint8_t>(257 * m)).common());
|
||||
@@ -456,9 +456,15 @@ concept invalid_compound_assignments =
|
||||
requires !requires { w *= m; };
|
||||
requires !requires { w /= m; };
|
||||
requires !requires { w %= m; };
|
||||
requires !requires { w *= quantity_kind<downcast_kind<Width, dim_one>, scaled_unit<mag<1000>(), one>, int>{1}; };
|
||||
requires !requires { w /= quantity_kind<downcast_kind<Width, dim_one>, scaled_unit<mag<1000>(), one>, int>{1}; };
|
||||
requires !requires { w %= quantity_kind<downcast_kind<Width, dim_one>, scaled_unit<mag<1000>(), one>, int>{1}; };
|
||||
requires !requires {
|
||||
w *= quantity_kind<downcast_kind<Width, dimension_one>, scaled_unit<mag<1000>(), one>, int>{1};
|
||||
};
|
||||
requires !requires {
|
||||
w /= quantity_kind<downcast_kind<Width, dimension_one>, scaled_unit<mag<1000>(), one>, int>{1};
|
||||
};
|
||||
requires !requires {
|
||||
w %= quantity_kind<downcast_kind<Width, dimension_one>, scaled_unit<mag<1000>(), one>, int>{1};
|
||||
};
|
||||
requires !requires { w %= 1.0; };
|
||||
requires !requires { w %= quantity(1.0); };
|
||||
requires !requires { w %= 1.0 * (w / w); };
|
||||
@@ -510,15 +516,15 @@ static_assert(!std::is_invocable_v<std::minus<>, width<metre>, height<metre>>);
|
||||
static_assert(!std::is_invocable_v<std::minus<>, width<metre>, reference<dim_length, metre>>);
|
||||
|
||||
// clang-format off
|
||||
static_assert(!std::is_invocable_v<std::plus<>, quantity_kind<downcast_kind<width_kind, dim_one>, one>, quantity_kind<downcast_kind<height_kind, dim_one>, one>>);
|
||||
static_assert(!std::is_invocable_v<std::plus<>, quantity_kind<downcast_kind<width_kind, dim_one>, one>, quantity_kind< height_kind, metre>>);
|
||||
static_assert(!std::is_invocable_v<std::plus<>, quantity_kind< width_kind, metre>, quantity_kind<downcast_kind<height_kind, dim_one>, one>>);
|
||||
static_assert(!std::is_invocable_v<std::plus<>, quantity_kind<downcast_kind<width_kind, dimension_one>, one>, quantity_kind<downcast_kind<height_kind, dimension_one>, one>>);
|
||||
static_assert(!std::is_invocable_v<std::plus<>, quantity_kind<downcast_kind<width_kind, dimension_one>, one>, quantity_kind< height_kind, metre>>);
|
||||
static_assert(!std::is_invocable_v<std::plus<>, quantity_kind< width_kind, metre>, quantity_kind<downcast_kind<height_kind, dimension_one>, one>>);
|
||||
static_assert(!std::is_invocable_v<std::plus<>, quantity_kind<downcast_kind<width_kind, dim_time>, day>, quantity_kind< height_kind, metre>>);
|
||||
static_assert(!std::is_invocable_v<std::plus<>, quantity_kind< width_kind, metre>, quantity_kind<downcast_kind<height_kind, dim_time>, day>>);
|
||||
static_assert(!std::is_invocable_v<std::plus<>, quantity_kind<downcast_kind<width_kind, dim_time>, day>, quantity_kind<downcast_kind<height_kind, dim_time>, day>>);
|
||||
static_assert(!std::is_invocable_v<std::minus<>, quantity_kind<downcast_kind<width_kind, dim_one>, one>, quantity_kind<downcast_kind<height_kind, dim_one>, one>>);
|
||||
static_assert(!std::is_invocable_v<std::minus<>, quantity_kind<downcast_kind<width_kind, dim_one>, one>, quantity_kind< height_kind, metre>>);
|
||||
static_assert(!std::is_invocable_v<std::minus<>, quantity_kind< width_kind, metre>, quantity_kind<downcast_kind<height_kind, dim_one>, one>>);
|
||||
static_assert(!std::is_invocable_v<std::minus<>, quantity_kind<downcast_kind<width_kind, dimension_one>, one>, quantity_kind<downcast_kind<height_kind, dimension_one>, one>>);
|
||||
static_assert(!std::is_invocable_v<std::minus<>, quantity_kind<downcast_kind<width_kind, dimension_one>, one>, quantity_kind< height_kind, metre>>);
|
||||
static_assert(!std::is_invocable_v<std::minus<>, quantity_kind< width_kind, metre>, quantity_kind<downcast_kind<height_kind, dimension_one>, one>>);
|
||||
static_assert(!std::is_invocable_v<std::minus<>, quantity_kind<downcast_kind<width_kind, dim_time>, day>, quantity_kind< height_kind, metre>>);
|
||||
static_assert(!std::is_invocable_v<std::minus<>, quantity_kind< width_kind, metre>, quantity_kind<downcast_kind<height_kind, dim_time>, day>>);
|
||||
static_assert(!std::is_invocable_v<std::minus<>, quantity_kind<downcast_kind<width_kind, dim_time>, day>, quantity_kind<downcast_kind<height_kind, dim_time>, day>>);
|
||||
@@ -538,17 +544,17 @@ static_assert(comp(quantity(2) * width<metre, int>(3 * m), width<metre, int>(6 *
|
||||
static_assert(comp(quantity(2) * width<metre, double>(3. * m), width<metre, double>(6. * m)));
|
||||
static_assert(comp(quantity(2.) * width<metre, int>(3 * m), width<metre, double>(6. * m)));
|
||||
|
||||
static_assert(comp(width<metre, int>(2 * m) * quantity_kind<downcast_kind<width_kind, dim_one>, one, int>(3),
|
||||
static_assert(comp(width<metre, int>(2 * m) * quantity_kind<downcast_kind<width_kind, dimension_one>, one, int>(3),
|
||||
width<metre, int>(6 * m)));
|
||||
static_assert(comp(width<metre, int>(2 * m) * quantity_kind<downcast_kind<width_kind, dim_one>, one, double>(3.),
|
||||
static_assert(comp(width<metre, int>(2 * m) * quantity_kind<downcast_kind<width_kind, dimension_one>, one, double>(3.),
|
||||
width<metre, double>(6. * m)));
|
||||
static_assert(comp(width<metre, double>(2. * m) * quantity_kind<downcast_kind<width_kind, dim_one>, one, int>(3),
|
||||
static_assert(comp(width<metre, double>(2. * m) * quantity_kind<downcast_kind<width_kind, dimension_one>, one, int>(3),
|
||||
width<metre, double>(6. * m)));
|
||||
static_assert(comp(quantity_kind<downcast_kind<width_kind, dim_one>, one, int>(2) * width<metre, int>(3 * m),
|
||||
static_assert(comp(quantity_kind<downcast_kind<width_kind, dimension_one>, one, int>(2) * width<metre, int>(3 * m),
|
||||
width<metre, int>(6 * m)));
|
||||
static_assert(comp(quantity_kind<downcast_kind<width_kind, dim_one>, one, int>(2) * width<metre, double>(3. * m),
|
||||
static_assert(comp(quantity_kind<downcast_kind<width_kind, dimension_one>, one, int>(2) * width<metre, double>(3. * m),
|
||||
width<metre, double>(6. * m)));
|
||||
static_assert(comp(quantity_kind<downcast_kind<width_kind, dim_one>, one, double>(2.) * width<metre, int>(3 * m),
|
||||
static_assert(comp(quantity_kind<downcast_kind<width_kind, dimension_one>, one, double>(2.) * width<metre, int>(3 * m),
|
||||
width<metre, double>(6. * m)));
|
||||
|
||||
static_assert(comp(height<metre, int>(2 * m) * (3 * Hz), rate_of_climb<metre_per_second, int>(6 * (m / s))));
|
||||
@@ -559,9 +565,9 @@ static_assert(comp((2 * Hz) * height<metre, double>(3. * m), rate_of_climb<metre
|
||||
static_assert(comp((2. * Hz) * height<metre, int>(3 * m), rate_of_climb<metre_per_second, double>(6. * (m / s))));
|
||||
|
||||
static_assert(comp(quantity_kind<time_kind, second, int>(2 * s) * (3 * Hz),
|
||||
quantity_kind<downcast_kind<time_kind, dim_one>, one, int>(6)));
|
||||
quantity_kind<downcast_kind<time_kind, dimension_one>, one, int>(6)));
|
||||
static_assert(comp((3 * Hz) * quantity_kind<time_kind, second, int>(2 * s),
|
||||
quantity_kind<downcast_kind<time_kind, dim_one>, one, int>(6)));
|
||||
quantity_kind<downcast_kind<time_kind, dimension_one>, one, int>(6)));
|
||||
|
||||
static_assert(comp(apples<one, int>(2) * quantity(2), apples<one, int>(4)));
|
||||
static_assert(comp(quantity(2) * apples<one, int>(2), apples<one, int>(4)));
|
||||
@@ -579,7 +585,7 @@ static_assert(comp(apples<one, int>(2) * (2 / apples<one, int>(1)), apples<one,
|
||||
static_assert(comp(width<kilometre>(4 * m) * (1 * mm), horizontal_area<square_metre>(4 * (m * mm))));
|
||||
static_assert(comp(width<kilometre>(2 * m) * width<millimetre>(2 * m), horizontal_area<square_metre>(4 * (m * m))));
|
||||
static_assert(comp(width<metre>(2 * m) * (1 / width<metre>(2 * m)),
|
||||
quantity_kind<downcast_kind<width_kind, dim_one>, one>(1)));
|
||||
quantity_kind<downcast_kind<width_kind, dimension_one>, one>(1)));
|
||||
|
||||
static_assert(same(width<metre, int>(2 * m) / 3, width<metre, int>(0 * m)));
|
||||
static_assert(same(width<metre, int>(2 * m) / 3., width<metre, double>(2 / 3. * m)));
|
||||
@@ -589,11 +595,12 @@ static_assert(comp(width<metre, int>(2 * m) / quantity(3), width<metre, int>(0 *
|
||||
static_assert(comp(width<metre, int>(2 * m) / quantity(3.), width<metre, double>(2 / 3. * m)));
|
||||
static_assert(comp(width<metre, double>(2. * m) / quantity(3), width<metre, double>(2. / 3 * m)));
|
||||
|
||||
static_assert(comp(width<metre, int>(2 * m) / quantity_kind<downcast_kind<width_kind, dim_one>, one, int>(3),
|
||||
static_assert(comp(width<metre, int>(2 * m) / quantity_kind<downcast_kind<width_kind, dimension_one>, one, int>(3),
|
||||
width<metre, int>(0 * m)));
|
||||
static_assert(comp(width<metre, int>(2 * m) / quantity_kind<downcast_kind<width_kind, dim_one>, one, double>(3.),
|
||||
static_assert(comp(width<metre, int>(2 * m) / quantity_kind<downcast_kind<width_kind, dimension_one>, one, double>(3.),
|
||||
width<metre, double>(2 / 3. * m)));
|
||||
static_assert(comp(width<metre, double>(2. * m) / quantity_kind<downcast_kind<width_kind, dim_one>, one, double>(3),
|
||||
static_assert(comp(width<metre, double>(2. * m) /
|
||||
quantity_kind<downcast_kind<width_kind, dimension_one>, one, double>(3),
|
||||
width<metre, double>(2. / 3 * m)));
|
||||
|
||||
static_assert(comp(2 / quantity_kind<time_kind, second, int>(3 * s),
|
||||
@@ -610,13 +617,13 @@ static_assert(comp(quantity(2) / quantity_kind<time_kind, second, double>(3. * s
|
||||
static_assert(comp(quantity(2.) / quantity_kind<time_kind, second, int>(3 * s),
|
||||
quantity_kind<downcast_kind<time_kind, dim_frequency>, hertz, double>(2 / 3. / (1 * s))));
|
||||
|
||||
static_assert(comp(quantity_kind<downcast_kind<time_kind, dim_one>, one, int>(2) /
|
||||
static_assert(comp(quantity_kind<downcast_kind<time_kind, dimension_one>, one, int>(2) /
|
||||
quantity_kind<time_kind, second, int>(3 * s),
|
||||
quantity_kind<downcast_kind<time_kind, dim_frequency>, hertz, int>(2 / 3 / (1 * s))));
|
||||
static_assert(comp(quantity_kind<downcast_kind<time_kind, dim_one>, one, int>(2) /
|
||||
static_assert(comp(quantity_kind<downcast_kind<time_kind, dimension_one>, one, int>(2) /
|
||||
quantity_kind<time_kind, second, double>(3. * s),
|
||||
quantity_kind<downcast_kind<time_kind, dim_frequency>, hertz, double>(2 / 3. / (1 * s))));
|
||||
static_assert(comp(quantity_kind<downcast_kind<time_kind, dim_one>, one, double>(2.) /
|
||||
static_assert(comp(quantity_kind<downcast_kind<time_kind, dimension_one>, one, double>(2.) /
|
||||
quantity_kind<time_kind, second, int>(3 * s),
|
||||
quantity_kind<downcast_kind<time_kind, dim_frequency>, hertz, double>(2 / 3. / (1 * s))));
|
||||
|
||||
@@ -631,25 +638,25 @@ static_assert(comp(width<metre, int>(2 * m) / dimensionless<percent, double>(3),
|
||||
static_assert(same(width<metre, int>(2 * m) % dimensionless<percent, int>(3), width<metre, int>(2 * m)));
|
||||
|
||||
static_assert(comp(height<metre, int>(2 * m) / (3 * m),
|
||||
quantity_kind<downcast_kind<height_kind, dim_one>, one, int>(0)));
|
||||
quantity_kind<downcast_kind<height_kind, dimension_one>, one, int>(0)));
|
||||
static_assert(comp(height<metre, int>(2 * m) / (3. * m),
|
||||
quantity_kind<downcast_kind<height_kind, dim_one>, one, double>(2 / 3.)));
|
||||
quantity_kind<downcast_kind<height_kind, dimension_one>, one, double>(2 / 3.)));
|
||||
static_assert(comp(height<metre, double>(2. * m) / (3 * m),
|
||||
quantity_kind<downcast_kind<height_kind, dim_one>, one, double>(2. / 3)));
|
||||
quantity_kind<downcast_kind<height_kind, dimension_one>, one, double>(2. / 3)));
|
||||
|
||||
static_assert(comp((2 * m) / height<metre, int>(3 * m),
|
||||
quantity_kind<downcast_kind<height_kind, dim_one>, one, int>(0)));
|
||||
quantity_kind<downcast_kind<height_kind, dimension_one>, one, int>(0)));
|
||||
static_assert(comp((2 * m) / height<metre, double>(3. * m),
|
||||
quantity_kind<downcast_kind<height_kind, dim_one>, one, double>(2 / 3.)));
|
||||
quantity_kind<downcast_kind<height_kind, dimension_one>, one, double>(2 / 3.)));
|
||||
static_assert(comp((2. * m) / height<metre, int>(3 * m),
|
||||
quantity_kind<downcast_kind<height_kind, dim_one>, one, double>(2. / 3)));
|
||||
quantity_kind<downcast_kind<height_kind, dimension_one>, one, double>(2. / 3)));
|
||||
|
||||
static_assert(comp(width<metre, int>(8 * m) / width<metre, int>(2 * m),
|
||||
quantity_kind<downcast_kind<width_kind, dim_one>, one, int>(4)));
|
||||
quantity_kind<downcast_kind<width_kind, dimension_one>, one, int>(4)));
|
||||
static_assert(comp(width<metre, int>(8 * m) / width<metre, double>(2 * m),
|
||||
quantity_kind<downcast_kind<width_kind, dim_one>, one, double>(4.0)));
|
||||
quantity_kind<downcast_kind<width_kind, dimension_one>, one, double>(4.0)));
|
||||
static_assert(comp(width<metre, double>(8 * m) / width<metre, int>(2 * m),
|
||||
quantity_kind<downcast_kind<width_kind, dim_one>, one, double>(4.0)));
|
||||
quantity_kind<downcast_kind<width_kind, dimension_one>, one, double>(4.0)));
|
||||
|
||||
static_assert(comp(apples<one, int>(8) / apples<one, int>(2), apples<one, int>(4)));
|
||||
static_assert(comp(apples<one, int>(8) / (2 / apples<one, int>(1)), apples<one, int>(4)));
|
||||
@@ -684,21 +691,21 @@ static_assert(!std::is_invocable_v<std::modulus<>, width<metre, int>, double>);
|
||||
static_assert(!std::is_invocable_v<std::modulus<>, width<metre, int>, width<metre, double>>);
|
||||
|
||||
// clang-format off
|
||||
static_assert(!std::is_invocable_v<std::multiplies<>, quantity_kind<downcast_kind<width_kind, dim_one>, one>, quantity_kind<downcast_kind<height_kind, dim_one>, one>>);
|
||||
static_assert(!std::is_invocable_v<std::multiplies<>, quantity_kind<downcast_kind<width_kind, dim_one>, one>, quantity_kind< height_kind, metre>>);
|
||||
static_assert(!std::is_invocable_v<std::multiplies<>, quantity_kind< width_kind, metre>, quantity_kind<downcast_kind<height_kind, dim_one>, one>>);
|
||||
static_assert(!std::is_invocable_v<std::multiplies<>, quantity_kind<downcast_kind<width_kind, dimension_one>, one>, quantity_kind<downcast_kind<height_kind, dimension_one>, one>>);
|
||||
static_assert(!std::is_invocable_v<std::multiplies<>, quantity_kind<downcast_kind<width_kind, dimension_one>, one>, quantity_kind< height_kind, metre>>);
|
||||
static_assert(!std::is_invocable_v<std::multiplies<>, quantity_kind< width_kind, metre>, quantity_kind<downcast_kind<height_kind, dimension_one>, one>>);
|
||||
static_assert(!std::is_invocable_v<std::multiplies<>, quantity_kind<downcast_kind<width_kind, dim_time>, day>, quantity_kind< height_kind, metre>>);
|
||||
static_assert(!std::is_invocable_v<std::multiplies<>, quantity_kind< width_kind, metre>, quantity_kind<downcast_kind<height_kind, dim_time>, day>>);
|
||||
static_assert(!std::is_invocable_v<std::multiplies<>, quantity_kind<downcast_kind<width_kind, dim_time>, day>, quantity_kind<downcast_kind<height_kind, dim_time>, day>>);
|
||||
static_assert(!std::is_invocable_v<std::divides<>, quantity_kind<downcast_kind<width_kind, dim_one>, one>, quantity_kind<downcast_kind<height_kind, dim_one>, one>>);
|
||||
static_assert(!std::is_invocable_v<std::divides<>, quantity_kind<downcast_kind<width_kind, dim_one>, one>, quantity_kind< height_kind, metre>>);
|
||||
static_assert(!std::is_invocable_v<std::divides<>, quantity_kind< width_kind, metre>, quantity_kind<downcast_kind<height_kind, dim_one>, one>>);
|
||||
static_assert(!std::is_invocable_v<std::divides<>, quantity_kind<downcast_kind<width_kind, dimension_one>, one>, quantity_kind<downcast_kind<height_kind, dimension_one>, one>>);
|
||||
static_assert(!std::is_invocable_v<std::divides<>, quantity_kind<downcast_kind<width_kind, dimension_one>, one>, quantity_kind< height_kind, metre>>);
|
||||
static_assert(!std::is_invocable_v<std::divides<>, quantity_kind< width_kind, metre>, quantity_kind<downcast_kind<height_kind, dimension_one>, one>>);
|
||||
static_assert(!std::is_invocable_v<std::divides<>, quantity_kind<downcast_kind<width_kind, dim_time>, day>, quantity_kind< height_kind, metre>>);
|
||||
static_assert(!std::is_invocable_v<std::divides<>, quantity_kind< width_kind, metre>, quantity_kind<downcast_kind<height_kind, dim_time>, day>>);
|
||||
static_assert(!std::is_invocable_v<std::divides<>, quantity_kind<downcast_kind<width_kind, dim_time>, day>, quantity_kind<downcast_kind<height_kind, dim_time>, day>>);
|
||||
static_assert(!std::is_invocable_v<std::modulus<>, quantity_kind<downcast_kind<width_kind, dim_one>, one>, quantity_kind<downcast_kind<height_kind, dim_one>, one>>);
|
||||
static_assert(!std::is_invocable_v<std::modulus<>, quantity_kind<downcast_kind<width_kind, dim_one>, one>, quantity_kind< height_kind, metre>>);
|
||||
static_assert(!std::is_invocable_v<std::modulus<>, quantity_kind< width_kind, metre>, quantity_kind<downcast_kind<height_kind, dim_one>, one>>);
|
||||
static_assert(!std::is_invocable_v<std::modulus<>, quantity_kind<downcast_kind<width_kind, dimension_one>, one>, quantity_kind<downcast_kind<height_kind, dimension_one>, one>>);
|
||||
static_assert(!std::is_invocable_v<std::modulus<>, quantity_kind<downcast_kind<width_kind, dimension_one>, one>, quantity_kind< height_kind, metre>>);
|
||||
static_assert(!std::is_invocable_v<std::modulus<>, quantity_kind< width_kind, metre>, quantity_kind<downcast_kind<height_kind, dimension_one>, one>>);
|
||||
static_assert(!std::is_invocable_v<std::modulus<>, quantity_kind<downcast_kind<width_kind, dim_time>, day>, quantity_kind< height_kind, metre>>);
|
||||
static_assert(!std::is_invocable_v<std::modulus<>, quantity_kind< width_kind, metre>, quantity_kind<downcast_kind<height_kind, dim_time>, day>>);
|
||||
static_assert(!std::is_invocable_v<std::modulus<>, quantity_kind<downcast_kind<width_kind, dim_time>, day>, quantity_kind<downcast_kind<height_kind, dim_time>, day>>);
|
||||
@@ -834,7 +841,7 @@ concept invalid_cast =
|
||||
quantity_kind<Width, metre, int>(1 * m));
|
||||
};
|
||||
requires !requires {
|
||||
quantity_kind_cast<quantity_point<dynamic_origin<dim_one>, one, int>>(
|
||||
quantity_kind_cast<quantity_point<dynamic_origin<dimension_one>, one, int>>(
|
||||
quantity_kind<Width, metre, int>(1 * m));
|
||||
};
|
||||
};
|
||||
|
201
test/unit_test/static/reference_test.cpp
Normal file
201
test/unit_test/static/reference_test.cpp
Normal file
@@ -0,0 +1,201 @@
|
||||
// The MIT License (MIT)
|
||||
//
|
||||
// Copyright (c) 2018 Mateusz Pusz
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
#include "test_tools.h"
|
||||
#include <units/dimension.h>
|
||||
#include <units/quantity.h>
|
||||
#include <units/reference.h>
|
||||
#include <units/si/prefixes.h>
|
||||
#include <units/unit.h>
|
||||
|
||||
namespace {
|
||||
|
||||
using namespace units;
|
||||
using namespace units::detail;
|
||||
|
||||
using dimension_one_ = struct dimension_one;
|
||||
using one_ = struct one;
|
||||
|
||||
// base dimensions
|
||||
BASE_DIMENSION_(length, "L");
|
||||
BASE_DIMENSION_(time, "T");
|
||||
BASE_DIMENSION_(mass, "M");
|
||||
|
||||
DERIVED_DIMENSION_(frequency, decltype(1 / time));
|
||||
DERIVED_DIMENSION_(action, decltype(1 / time));
|
||||
DERIVED_DIMENSION_(area, decltype(length * length));
|
||||
DERIVED_DIMENSION_(volume, decltype(area * length));
|
||||
DERIVED_DIMENSION_(speed, decltype(length / time));
|
||||
DERIVED_DIMENSION_(acceleration, decltype(speed / time));
|
||||
DERIVED_DIMENSION_(force, decltype(mass * acceleration));
|
||||
DERIVED_DIMENSION_(moment_of_force, decltype(length * force));
|
||||
DERIVED_DIMENSION_(torque, decltype(moment_of_force));
|
||||
DERIVED_DIMENSION_(power, decltype(force * speed));
|
||||
DERIVED_DIMENSION_(efficiency, decltype(power / power));
|
||||
DERIVED_DIMENSION_(energy, decltype(force * length));
|
||||
|
||||
// clang-format off
|
||||
// base units
|
||||
inline constexpr struct second_ : named_unit<"s", time> {} second;
|
||||
inline constexpr struct metre_ : named_unit<"m", length> {} metre;
|
||||
inline constexpr struct gram_ : named_unit<"g", mass> {} gram;
|
||||
inline constexpr struct kilogram_ : decltype(si::kilo<gram>) {} kilogram;
|
||||
|
||||
namespace nu {
|
||||
// hypothetical natural system of units for c=1
|
||||
|
||||
inline constexpr struct second_ : named_unit<"s"> {} second;
|
||||
inline constexpr struct minute_ : named_unit<"min", mag<60> * second> {} minute;
|
||||
inline constexpr struct gram_ : named_unit<"g"> {} gram;
|
||||
inline constexpr struct kilogram_ : decltype(si::kilo<gram>) {} kilogram;
|
||||
|
||||
inline constexpr struct time : system_reference<time_{}, second> {} time;
|
||||
inline constexpr struct length : system_reference<length_{}, second> {} length;
|
||||
inline constexpr struct speed : system_reference<speed_{}, second / second> {} speed;
|
||||
inline constexpr struct force : system_reference<force_{}, kilogram / second> {} force;
|
||||
|
||||
}
|
||||
|
||||
// derived named units
|
||||
inline constexpr struct radian_ : named_unit<"rad", metre / metre> {} radian;
|
||||
inline constexpr struct steradian_ : named_unit<"sr", square<metre> / square<metre>> {} steradian;
|
||||
inline constexpr struct hertz_ : named_unit<"Hz", 1 / second> {} hertz;
|
||||
inline constexpr struct becquerel_ : named_unit<"Bq", 1 / second> {} becquerel;
|
||||
inline constexpr struct newton_ : named_unit<"N", kilogram * metre / square<second>> {} newton;
|
||||
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 minute_ : named_unit<"min", mag<60> * second> {} minute;
|
||||
inline constexpr struct hour_ : named_unit<"h", mag<60> * minute> {} hour;
|
||||
inline constexpr struct kilometre_ : decltype(si::kilo<metre>) {} kilometre;
|
||||
// clang-format on
|
||||
|
||||
// Named quantity/dimension and unit
|
||||
static_assert(is_same_v<decltype(5 * power[watt]), quantity<reference<power_, watt_>{}, int>>);
|
||||
|
||||
// Named quantity/dimension and derived (unnamed) unit
|
||||
static_assert(is_same_v<decltype(5 * speed[metre / second]),
|
||||
quantity<reference<speed_, derived_unit<metre_, per<second_>>>{}, int>>);
|
||||
|
||||
// Derived (unnamed) quantity/dimension and derived (unnamed) unit
|
||||
static_assert(
|
||||
is_same_v<decltype(10 * length[metre] / (2 * time[second])),
|
||||
quantity<reference<derived_dimension<length_, per<time_>>, derived_unit<metre_, per<second_>>>{}, int>>);
|
||||
|
||||
// Base quantity as a result of dimensional transformation
|
||||
static_assert(
|
||||
is_same_v<decltype(5 * speed[metre / second] * (5 * time[second])), quantity<reference<length_, metre_>{}, int>>);
|
||||
|
||||
// dimension_one
|
||||
static_assert(is_same_v<decltype(20 * speed[metre / second] / (10 * length[metre]) * (5 * time[second])),
|
||||
quantity<reference<dimension_one_, one_>{}, int>>);
|
||||
|
||||
template<auto s>
|
||||
concept invalid_operations = requires {
|
||||
requires !requires { 2 / s; };
|
||||
requires !requires { s / 2; };
|
||||
requires !requires { s * 2; };
|
||||
requires !requires { s + 2; };
|
||||
requires !requires { 2 + s; };
|
||||
requires !requires { s + s; };
|
||||
requires !requires { s - 2; };
|
||||
requires !requires { 2 - s; };
|
||||
requires !requires { s - s; };
|
||||
requires !requires { s == s; };
|
||||
requires !requires { s < s; };
|
||||
requires !requires { s + 1 * time[second]; };
|
||||
requires !requires { s - 1 * time[second]; };
|
||||
requires !requires { s * 1 * time[second]; };
|
||||
requires !requires { s / 1 * time[second]; };
|
||||
requires !requires { s == 1 * time[second]; };
|
||||
requires !requires { s < 1 * time[second]; };
|
||||
requires !requires { 1 * time[second] + s; };
|
||||
requires !requires { 1 * time[second] - s; };
|
||||
requires !requires { 1 * time[second] * s; };
|
||||
requires !requires { 1 * time[second] / s; };
|
||||
requires !requires { 1 * time[second] == s; };
|
||||
requires !requires { 1 * time[second] < s; };
|
||||
};
|
||||
static_assert(invalid_operations<time[second]>);
|
||||
|
||||
static_assert(
|
||||
is_same_v<decltype(2 * length[metre] / (1 * time[second])),
|
||||
quantity<reference<derived_dimension<length_, per<time_>>, derived_unit<metre_, per<second_>>>{}, int>>);
|
||||
static_assert(
|
||||
is_same_v<decltype(2 * (length[metre] / time[second])),
|
||||
quantity<reference<derived_dimension<length_, per<time_>>, derived_unit<metre_, per<second_>>>{}, int>>);
|
||||
static_assert(is_same_v<decltype(2 * (speed[metre / second])),
|
||||
quantity<reference<speed_, derived_unit<metre_, per<second_>>>{}, int>>);
|
||||
|
||||
constexpr auto m_per_s = speed[metre / second];
|
||||
static_assert(is_same_v<decltype(2 * m_per_s), quantity<reference<speed_, derived_unit<metre_, per<second_>>>{}, int>>);
|
||||
|
||||
static_assert(
|
||||
is_same_v<decltype(120 * length[kilometre] / (2 * time[hour])),
|
||||
quantity<reference<derived_dimension<length_, per<time_>>, derived_unit<kilometre_, per<hour_>>>{}, int>>);
|
||||
static_assert(120 * length[kilometre] / (2 * time[hour]) == 60 * speed[kilometre / hour]);
|
||||
static_assert(
|
||||
is_same_v<decltype([] {
|
||||
const auto distance = 120;
|
||||
const auto duration = 2;
|
||||
return distance * length[kilometre] / (duration * time[hour]);
|
||||
}()),
|
||||
quantity<reference<derived_dimension<length_, per<time_>>, derived_unit<kilometre_, per<hour_>>>{}, int>>);
|
||||
static_assert(
|
||||
is_same_v<
|
||||
decltype(std::int64_t{120} * length[kilometre] / (2 * time[hour])),
|
||||
quantity<reference<derived_dimension<length_, per<time_>>, derived_unit<kilometre_, per<hour_>>>{}, std::int64_t>>);
|
||||
static_assert(
|
||||
is_same_v<
|
||||
decltype(120.L * length[kilometre] / (2 * time[hour])),
|
||||
quantity<reference<derived_dimension<length_, per<time_>>, derived_unit<kilometre_, per<hour_>>>{}, long double>>);
|
||||
|
||||
static_assert(is_same_v<decltype(1. / 4 * area[square<metre>]), decltype(1. * area[square<metre>] / 4)>);
|
||||
static_assert(1. / 4 * area[square<metre>] == 1. * area[square<metre>] / 4);
|
||||
|
||||
// Natural Units
|
||||
static_assert(is_same_v<decltype(42 * nu::time[nu::second]), quantity<reference<time_, nu::second_>{}, int>>);
|
||||
static_assert(is_same_v<decltype(42 * nu::time[nu::minute]), quantity<reference<time_, nu::minute_>{}, int>>);
|
||||
static_assert(is_same_v<decltype(42 * nu::length[nu::second]), quantity<reference<length_, nu::second_>{}, int>>);
|
||||
static_assert(is_same_v<decltype(42 * nu::length[nu::minute]), quantity<reference<length_, nu::minute_>{}, int>>);
|
||||
static_assert(is_same_v<decltype(42 * (nu::length[nu::second] / nu::time[nu::second])),
|
||||
quantity<reference<derived_dimension<length_, per<time_>>, one_>{}, int>>);
|
||||
static_assert(is_same_v<decltype(42 * nu::length[nu::second] / (42 * nu::time[nu::second])),
|
||||
quantity<reference<derived_dimension<length_, per<time_>>, one_>{}, int>>);
|
||||
static_assert(is_same_v<decltype(42 * nu::speed[nu::second / nu::second]), quantity<reference<speed_, one_>{}, int>>);
|
||||
static_assert(is_same_v<decltype(42 * nu::speed[one]), quantity<reference<speed_, one_>{}, int>>);
|
||||
static_assert(is_same_v<decltype(42 * mass[kilogram] * (1 * nu::length[nu::second]) / (1 * nu::time[nu::second])),
|
||||
quantity<reference<derived_dimension<length_, mass_, per<time_>>, kilogram_>{}, int>>);
|
||||
|
||||
template<auto dim, auto unit>
|
||||
concept invalid_nu_unit = !requires { dim[unit]; };
|
||||
|
||||
static_assert(invalid_nu_unit<time, nu::second>);
|
||||
static_assert(invalid_nu_unit<nu::time, second>);
|
||||
static_assert(invalid_nu_unit<length / time, nu::second / nu::second>);
|
||||
static_assert(invalid_nu_unit<speed, nu::second / nu::second>);
|
||||
static_assert(invalid_nu_unit<speed, nu::second / second>);
|
||||
static_assert(invalid_nu_unit<mass * length / time, kilogram * nu::second / nu::second>);
|
||||
static_assert(invalid_nu_unit<force, kilogram * nu::second / nu::second>);
|
||||
|
||||
} // namespace
|
@@ -1,93 +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.
|
||||
|
||||
#include "test_tools.h"
|
||||
#include <units/bits/external/hacks.h>
|
||||
#include <units/bits/external/type_traits.h>
|
||||
#include <units/isq/si/area.h>
|
||||
#include <units/isq/si/length.h>
|
||||
#include <units/isq/si/speed.h>
|
||||
#include <units/isq/si/time.h>
|
||||
|
||||
using namespace units;
|
||||
using namespace units::isq;
|
||||
using namespace units::isq::si;
|
||||
using namespace units::isq::si::references;
|
||||
|
||||
static_assert(2 * m == 2_q_m);
|
||||
static_assert(2 * s == 2_q_s);
|
||||
template<auto& s>
|
||||
concept invalid_operations = requires {
|
||||
requires !requires { 2 / s; };
|
||||
requires !requires { s / 2; };
|
||||
requires !requires { s * 2; };
|
||||
requires !requires { s + 2; };
|
||||
requires !requires { 2 + s; };
|
||||
requires !requires { s + s; };
|
||||
requires !requires { s - 2; };
|
||||
requires !requires { 2 - s; };
|
||||
requires !requires { s - s; };
|
||||
requires !requires { s + 1_q_s; };
|
||||
requires !requires { s - 1_q_s; };
|
||||
requires !requires { s * 1_q_s; };
|
||||
requires !requires { s / 1_q_s; };
|
||||
requires !requires { 1_q_s + s; };
|
||||
requires !requires { 1_q_s - s; };
|
||||
requires !requires { 1_q_s * s; };
|
||||
requires !requires { 1_q_s / s; };
|
||||
};
|
||||
static_assert(invalid_operations<s>);
|
||||
|
||||
static_assert(2_q_m / (1 * s) == 2_q_m_per_s);
|
||||
static_assert(2 * (m / s) == 2_q_m_per_s);
|
||||
|
||||
#if !(UNITS_COMP_GCC == 10 && UNITS_COMP_GCC_MINOR == 1) // GCC 10.1.0 ICEs
|
||||
constexpr auto m_per_s = m / s;
|
||||
static_assert(2 * ::m_per_s == 2_q_m_per_s);
|
||||
#endif
|
||||
|
||||
static_assert(120 * km / (2 * h) == 60_q_km_per_h);
|
||||
static_assert([] {
|
||||
const auto length{120};
|
||||
const auto duration{2};
|
||||
return length * km / (duration * h);
|
||||
}() == 60_q_km_per_h);
|
||||
static_assert(compare<decltype(std::int64_t{120} * km / (2 * h)), decltype(60_q_km_per_h)>);
|
||||
static_assert(compare<decltype(120.L * km / (2 * h)), decltype(60._q_km_per_h)>);
|
||||
|
||||
static_assert(1. / 4 * m2 == 1._q_m2 / 4);
|
||||
|
||||
UNITS_DIAGNOSTIC_PUSH
|
||||
UNITS_DIAGNOSTIC_IGNORE_SHADOW
|
||||
constexpr bool test_hiding()
|
||||
{
|
||||
Speed auto v0 = 10 * (m / s);
|
||||
signed s = 2; // hides ^
|
||||
Length auto v = 20 * m / s;
|
||||
/* */ v0 = 10 * (m / ::s);
|
||||
return !is_same_v<decltype(v0), decltype(v)>;
|
||||
}
|
||||
|
||||
static_assert(test_hiding());
|
||||
UNITS_DIAGNOSTIC_POP
|
||||
|
||||
int main() {}
|
@@ -22,6 +22,7 @@
|
||||
|
||||
#include "test_tools.h"
|
||||
#include <units/dimension.h>
|
||||
#include <units/reference.h>
|
||||
#include <units/si/prefixes.h>
|
||||
#include <units/unit.h>
|
||||
|
||||
@@ -46,6 +47,9 @@ 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", thermodynamic_temperature> {} kelvin;
|
||||
|
||||
// hypothetical natural units for c=1
|
||||
inline constexpr struct nu_second_ : named_unit<"s"> {} nu_second;
|
||||
|
||||
// derived named units
|
||||
inline constexpr struct radian_ : named_unit<"rad", metre / metre> {} radian;
|
||||
inline constexpr struct steradian_ : named_unit<"sr", square<metre> / square<metre>> {} steradian;
|
||||
@@ -79,6 +83,8 @@ inline constexpr struct kilojoule_ : decltype(si::kilo<joule>) {} kilojoule;
|
||||
|
||||
// concepts verification
|
||||
static_assert(Unit<metre_>);
|
||||
static_assert(Unit<second_>);
|
||||
static_assert(Unit<nu_second_>);
|
||||
static_assert(Unit<kilogram_>);
|
||||
static_assert(Unit<hertz_>);
|
||||
static_assert(Unit<newton_>);
|
||||
@@ -87,6 +93,10 @@ 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<decltype(second * second)>);
|
||||
static_assert(Unit<decltype(nu_second * nu_second)>);
|
||||
static_assert(Unit<decltype(metre / second)>);
|
||||
static_assert(Unit<decltype(nu_second / nu_second)>);
|
||||
static_assert(Unit<kilometre_>);
|
||||
|
||||
static_assert(NamedUnit<metre_>);
|
||||
@@ -121,8 +131,12 @@ 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<degree, degree_>);
|
||||
static_assert(is_of_type<get_canonical_unit(degree).reference_unit, one_>);
|
||||
static_assert(get_canonical_unit(degree).mag == mag_pi / mag<180>);
|
||||
static_assert(convertible(radian, degree));
|
||||
static_assert(radian != degree);
|
||||
|
||||
static_assert(is_of_type<steradian, steradian_>);
|
||||
static_assert(is_of_type<get_canonical_unit(steradian).reference_unit, one_>);
|
||||
@@ -162,6 +176,7 @@ static_assert(convertible(joule, joule));
|
||||
static_assert(joule == joule);
|
||||
static_assert(joule != newton);
|
||||
|
||||
static_assert(is_of_type<nu_second / nu_second, one_>);
|
||||
|
||||
// prefixed_unit
|
||||
static_assert(is_of_type<kilometre, kilometre_>);
|
||||
@@ -182,6 +197,10 @@ 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>>);
|
||||
|
||||
// TODO Should the below be a scaled version of metre^2?
|
||||
static_assert(is_of_type<kilometre * metre, derived_unit<kilometre_, metre_>>); // !!!
|
||||
static_assert(is_of_type<kilometre / metre, derived_unit<kilometre_, per<metre_>>>); // !!!
|
||||
|
||||
|
||||
// prefixes
|
||||
static_assert(si::yocto<metre>.symbol == "ym");
|
||||
@@ -314,6 +333,48 @@ static_assert(is_of_type<u3, scaled_unit<mag<1000>, derived_unit<kilometre_, per
|
||||
static_assert(is_of_type<get_canonical_unit(u3).reference_unit, derived_unit<metre_, per<second_>>>);
|
||||
static_assert(get_canonical_unit(u3).mag == mag<ratio{1'000'000, 3'600}>);
|
||||
|
||||
template<auto& s>
|
||||
concept invalid_operations = requires {
|
||||
requires !requires { s < s; };
|
||||
requires !requires { s / 2; };
|
||||
requires !requires { 2 * s; };
|
||||
requires !requires { s * 2; };
|
||||
requires !requires { s + 2; };
|
||||
requires !requires { 2 + s; };
|
||||
requires !requires { s + s; };
|
||||
requires !requires { s - 2; };
|
||||
requires !requires { 2 - s; };
|
||||
requires !requires { s - s; };
|
||||
requires !requires { s == 2; };
|
||||
requires !requires { 2 == s; };
|
||||
requires !requires { s < 2; };
|
||||
requires !requires { 2 < s; };
|
||||
requires !requires { s + time[second]; };
|
||||
requires !requires { s - time[second]; };
|
||||
requires !requires { s* time[second]; };
|
||||
requires !requires { s / time[second]; };
|
||||
requires !requires { s == time[second]; };
|
||||
requires !requires { s < time[second]; };
|
||||
requires !requires { time[second] + s; };
|
||||
requires !requires { time[second] - s; };
|
||||
requires !requires { time[second] * s; };
|
||||
requires !requires { time[second] / s; };
|
||||
requires !requires { time[second] == s; };
|
||||
requires !requires { time[second] < s; };
|
||||
requires !requires { s + 1 * time[second]; };
|
||||
requires !requires { s - 1 * time[second]; };
|
||||
requires !requires { s * 1 * time[second]; };
|
||||
requires !requires { s / 1 * time[second]; };
|
||||
requires !requires { s == 1 * time[second]; };
|
||||
requires !requires { s == 1 * time[second]; };
|
||||
requires !requires { 1 * time[second] + s; };
|
||||
requires !requires { 1 * time[second] - s; };
|
||||
requires !requires { 1 * time[second] * s; };
|
||||
requires !requires { 1 * time[second] == s; };
|
||||
requires !requires { 1 * time[second] < s; };
|
||||
};
|
||||
static_assert(invalid_operations<second>);
|
||||
|
||||
// comparisons of the same units
|
||||
static_assert(second == second);
|
||||
static_assert(metre / second == metre / second);
|
||||
@@ -449,6 +510,12 @@ static_assert(unit_symbol(square<metre>) == "m²");
|
||||
static_assert(unit_symbol(square<metre>, {.encoding = ascii}) == "m^2");
|
||||
static_assert(unit_symbol(cubic<metre>) == "m³");
|
||||
static_assert(unit_symbol(cubic<metre>, {.encoding = ascii}) == "m^3");
|
||||
static_assert(unit_symbol(kilometre * metre) == "km m");
|
||||
static_assert(unit_symbol(kilometre * metre, {.separator = dot}) == "km⋅m");
|
||||
static_assert(unit_symbol(metre / metre) == "");
|
||||
static_assert(unit_symbol(kilometre / metre) == "km/m");
|
||||
static_assert(unit_symbol(kilometre / metre, {.denominator = always_negative}) == "km m⁻¹");
|
||||
static_assert(unit_symbol(kilometre / metre, {.encoding = ascii, .denominator = always_negative}) == "km m^-1");
|
||||
static_assert(unit_symbol(metre / second) == "m/s");
|
||||
static_assert(unit_symbol(metre / second, {.denominator = always_solidus}) == "m/s");
|
||||
static_assert(unit_symbol(metre / second, {.denominator = always_negative}) == "m s⁻¹");
|
||||
|
Reference in New Issue
Block a user