forked from mpusz/mp-units
Migrate units from ratio to Magnitude
This commit is huge, but hopefully the cognitive load is not too bad. The bulk of this commit is just some fairly mechanical updates from `ratio` to `Magnitude`. Other things to call out: - `UnitRatio` goes away. We don't need this concept, because Magnitude can't even _represent_ anything that doesn't satisfy it. - I commented out some formatting test cases where the precise expression changes, but the number is completely equivalent. We will need to decide how we want to handle Magnitude formatting as a separate, follow-on task. But at least Magnitude gives us all the tools we'll need to do so!
This commit is contained in:
@@ -45,14 +45,4 @@ constexpr Magnitude auto absolute_magnitude(exponent_list<Es...>)
|
||||
return (pow<ratio{Es::num, Es::den}>(Es::dimension::base_unit::mag) * ... * magnitude<>{});
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Calculates the common ratio of all the references of base units in the derived dimension
|
||||
*/
|
||||
template<typename... Es>
|
||||
constexpr ratio base_units_ratio(exponent_list<Es...> es)
|
||||
{
|
||||
return as_ratio(absolute_magnitude(es));
|
||||
}
|
||||
|
||||
|
||||
} // namespace units::detail
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
#include <units/bits/external/fixed_string.h>
|
||||
#include <units/bits/external/type_traits.h>
|
||||
#include <units/customization_points.h>
|
||||
#include <units/ratio.h>
|
||||
#include <units/magnitude.h>
|
||||
// IWYU pragma: end_exports
|
||||
|
||||
#include <cstdint>
|
||||
@@ -67,24 +67,15 @@ void to_prefix_base(const volatile prefix_base<PF, R>*);
|
||||
template<typename T>
|
||||
concept Prefix = requires(T* t) { detail::to_prefix_base(t); };
|
||||
|
||||
/**
|
||||
* @brief A concept matching unit's ratio
|
||||
*
|
||||
* Satisfied by all ratio values for which `R.num > 0` and `R.den > 0`.
|
||||
*/
|
||||
template<ratio R>
|
||||
concept UnitRatio = (R.num > 0) && (R.den > 0);
|
||||
|
||||
// Unit
|
||||
template<ratio R, typename U>
|
||||
requires UnitRatio<R>
|
||||
template<Magnitude auto M, typename U>
|
||||
struct scaled_unit;
|
||||
|
||||
// TODO: Remove when P1985 accepted
|
||||
namespace detail {
|
||||
|
||||
template<ratio R, typename U>
|
||||
void to_base_scaled_unit(const volatile scaled_unit<R, U>*);
|
||||
template<Magnitude auto M, typename U>
|
||||
void to_base_scaled_unit(const volatile scaled_unit<M, U>*);
|
||||
|
||||
} // namespace detail
|
||||
|
||||
|
||||
@@ -55,22 +55,22 @@ struct common_quantity_reference_impl<reference<D, U>, reference<D, U>> {
|
||||
|
||||
template<typename D, typename U1, typename U2>
|
||||
struct common_quantity_reference_impl<reference<D, U1>, reference<D, U2>> {
|
||||
using type = reference<D, downcast_unit<D, common_ratio(U1::ratio, U2::ratio)>>;
|
||||
using type = reference<D, downcast_unit<D, common_magnitude(U1::mag, U2::mag)>>;
|
||||
};
|
||||
|
||||
template<typename D1, typename U1, typename D2, typename U2>
|
||||
requires(same_unit_reference<dimension_unit<D1>, dimension_unit<D2>>::value)
|
||||
struct common_quantity_reference_impl<reference<D1, U1>, reference<D2, U2>> {
|
||||
using type = reference<D1, downcast_unit<D1, common_ratio(U1::ratio, U2::ratio)>>;
|
||||
using type = reference<D1, downcast_unit<D1, common_magnitude(U1::mag, U2::mag)>>;
|
||||
};
|
||||
|
||||
template<typename D1, typename U1, typename D2, typename U2>
|
||||
struct common_quantity_reference_impl<reference<D1, U1>, reference<D2, U2>> {
|
||||
using dimension = conditional<is_specialization_of<D1, unknown_dimension>, D2, D1>;
|
||||
static constexpr ratio r1 = D1::base_units_ratio * U1::ratio;
|
||||
static constexpr ratio r2 = D2::base_units_ratio * U2::ratio;
|
||||
static constexpr ratio cr = common_ratio(r1, r2);
|
||||
using unit = downcast_unit<dimension, cr / dimension::base_units_ratio>;
|
||||
static constexpr Magnitude auto m1 = D1::base_units_ratio * U1::mag;
|
||||
static constexpr Magnitude auto m2 = D2::base_units_ratio * U2::mag;
|
||||
static constexpr Magnitude auto cm = common_magnitude(m1, m2);
|
||||
using unit = downcast_unit<dimension, cm / dimension::base_units_ratio>;
|
||||
using type = reference<dimension, unit>;
|
||||
};
|
||||
|
||||
|
||||
@@ -43,12 +43,6 @@ constexpr Magnitude auto derived_mag(exponent_list<Es...>)
|
||||
pow<ratio{Es::num, Es::den}>(Us::mag / dimension_unit<typename Es::dimension>::mag));
|
||||
}
|
||||
|
||||
template<Unit... Us, typename... Es>
|
||||
constexpr ratio derived_ratio(exponent_list<Es...> es)
|
||||
{
|
||||
return as_ratio(derived_mag<Us...>(es));
|
||||
}
|
||||
|
||||
template<DerivedDimension D, Unit... Us>
|
||||
using derived_unit = scaled_unit<derived_mag<Us...>(typename D::recipe()), typename D::coherent_unit::reference>;
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ namespace units {
|
||||
template<typename Rep, typename Period>
|
||||
struct quantity_like_traits<std::chrono::duration<Rep, Period>> {
|
||||
using dimension = isq::si::dim_time;
|
||||
using unit = downcast_unit<dimension, ratio(Period::num, Period::den)>;
|
||||
using unit = downcast_unit<dimension, as_magnitude<ratio(Period::num, Period::den)>()>;
|
||||
using rep = Rep;
|
||||
[[nodiscard]] static constexpr rep number(const std::chrono::duration<Rep, Period>& q) { return q.count(); }
|
||||
};
|
||||
@@ -45,7 +45,7 @@ struct clock_origin : point_origin<isq::si::dim_time> {};
|
||||
template<typename C, typename Rep, typename Period>
|
||||
struct quantity_point_like_traits<std::chrono::time_point<C, std::chrono::duration<Rep, Period>>> {
|
||||
using origin = clock_origin<C>;
|
||||
using unit = downcast_unit<typename origin::dimension, ratio(Period::num, Period::den)>;
|
||||
using unit = downcast_unit<typename origin::dimension, as_magnitude<ratio(Period::num, Period::den)>()>;
|
||||
using rep = Rep;
|
||||
[[nodiscard]] static constexpr auto relative(const std::chrono::time_point<C, std::chrono::duration<Rep, Period>>& qp)
|
||||
{
|
||||
|
||||
@@ -85,7 +85,8 @@ template<typename Child, Unit U, Exponent... Es>
|
||||
struct derived_dimension : downcast_dispatch<Child, typename detail::make_dimension<Es...>> {
|
||||
using recipe = exponent_list<Es...>;
|
||||
using coherent_unit = U;
|
||||
static constexpr ratio base_units_ratio = detail::base_units_ratio(typename derived_dimension::exponents());
|
||||
static constexpr Magnitude auto base_units_ratio =
|
||||
detail::absolute_magnitude(typename derived_dimension::exponents());
|
||||
};
|
||||
|
||||
} // namespace units
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
namespace units {
|
||||
|
||||
struct one : named_unit<one, "", no_prefix> {};
|
||||
struct percent : named_scaled_unit<percent, "%", no_prefix, ratio(1, 100), one> {};
|
||||
struct percent : named_scaled_unit<percent, "%", no_prefix, as_magnitude<ratio(1, 100)>(), one> {};
|
||||
|
||||
/**
|
||||
* @brief Dimension one
|
||||
|
||||
@@ -57,7 +57,7 @@ template<std::intmax_t Num, std::intmax_t Den = 1, Quantity Q>
|
||||
return rep(1);
|
||||
} else {
|
||||
using dim = dimension_pow<typename Q::dimension, Num, Den>;
|
||||
using unit = downcast_unit<dim, pow<Num, Den>(Q::unit::ratio)>;
|
||||
using unit = downcast_unit<dim, pow<ratio{Num, Den}>(Q::unit::mag)>;
|
||||
using std::pow;
|
||||
return quantity<dim, unit, rep>(
|
||||
static_cast<rep>(pow(q.number(), static_cast<double>(Num) / static_cast<double>(Den))));
|
||||
@@ -77,7 +77,7 @@ template<Quantity Q>
|
||||
requires requires { sqrt(q.number()); } || requires { std::sqrt(q.number()); }
|
||||
{
|
||||
using dim = dimension_pow<typename Q::dimension, 1, 2>;
|
||||
using unit = downcast_unit<dim, sqrt(Q::unit::ratio)>;
|
||||
using unit = downcast_unit<dim, pow<ratio{1, 2}>(Q::unit::mag)>;
|
||||
using rep = TYPENAME Q::rep;
|
||||
using std::sqrt;
|
||||
return quantity<dim, unit, rep>(static_cast<rep>(sqrt(q.number())));
|
||||
@@ -96,7 +96,7 @@ template<Quantity Q>
|
||||
requires requires { cbrt(q.number()); } || requires { std::cbrt(q.number()); }
|
||||
{
|
||||
using dim = dimension_pow<typename Q::dimension, 1, 3>;
|
||||
using unit = downcast_unit<dim, cbrt(Q::unit::ratio)>;
|
||||
using unit = downcast_unit<dim, pow<ratio{1, 3}>(Q::unit::mag)>;
|
||||
using rep = TYPENAME Q::rep;
|
||||
using std::cbrt;
|
||||
return quantity<dim, unit, rep>(static_cast<rep>(cbrt(q.number())));
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include <units/bits/basic_concepts.h>
|
||||
#include <units/bits/external/downcasting.h>
|
||||
// IWYU pragma: begin_exports
|
||||
#include <units/magnitude.h>
|
||||
#include <units/ratio.h>
|
||||
#include <units/symbol_text.h>
|
||||
// IWYU pragma: end_exports
|
||||
@@ -52,6 +53,7 @@ template<PrefixFamily PF, ratio R>
|
||||
struct prefix_base : downcast_base<prefix_base<PF, R>> {
|
||||
using prefix_family = PF;
|
||||
static constexpr ::units::ratio ratio = R;
|
||||
static constexpr Magnitude auto mag = as_magnitude<R>();
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
@@ -402,7 +402,7 @@ public:
|
||||
{
|
||||
gsl_ExpectsAudit(q.number() != quantity_values<rep>::zero());
|
||||
using dim = dim_invert<D>;
|
||||
using ret_unit = downcast_unit<dim, inverse(U::ratio)>;
|
||||
using ret_unit = downcast_unit<dim, pow<-1>(U::mag)>;
|
||||
using ret = quantity<dim, ret_unit, std::invoke_result_t<std::divides<>, Value, rep>>;
|
||||
return ret(v / q.number());
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include <units/bits/pow.h>
|
||||
#include <units/concepts.h>
|
||||
#include <units/customization_points.h>
|
||||
#include <units/magnitude.h>
|
||||
|
||||
UNITS_DIAGNOSTIC_PUSH
|
||||
// warning C4244: 'argument': conversion from 'intmax_t' to 'T', possible loss of data with T=int
|
||||
@@ -49,25 +50,31 @@ class quantity_point_kind;
|
||||
namespace detail {
|
||||
|
||||
template<typename T>
|
||||
inline constexpr ratio quantity_ratio = std::enable_if_t<!Quantity<T>>{};
|
||||
inline constexpr Magnitude auto quantity_magnitude = std::enable_if_t<!Quantity<T>, magnitude<>>{};
|
||||
|
||||
template<typename D, typename U, typename Rep>
|
||||
inline constexpr ratio quantity_ratio<quantity<D, U, Rep>> = [] {
|
||||
inline constexpr Magnitude auto quantity_magnitude<quantity<D, U, Rep>> = [] {
|
||||
if constexpr (BaseDimension<D>) {
|
||||
return U::ratio;
|
||||
return U::mag;
|
||||
} else {
|
||||
return D::base_units_ratio * U::ratio / D::coherent_unit::ratio;
|
||||
return D::base_units_ratio * U::mag / D::coherent_unit::mag;
|
||||
}
|
||||
}();
|
||||
|
||||
template<typename T>
|
||||
inline constexpr ratio quantity_ratio = std::enable_if_t<!Quantity<T>>{};
|
||||
|
||||
template<typename D, typename U, typename Rep>
|
||||
inline constexpr ratio quantity_ratio<quantity<D, U, Rep>> = as_ratio(quantity_magnitude<quantity<D, U, Rep>>);
|
||||
|
||||
template<typename QFrom, typename QTo>
|
||||
inline constexpr ratio cast_ratio = [] {
|
||||
inline constexpr Magnitude auto cast_magnitude = [] {
|
||||
using FromU = TYPENAME QFrom::unit;
|
||||
using ToU = TYPENAME QTo::unit;
|
||||
if constexpr (same_unit_reference<FromU, ToU>::value) {
|
||||
return FromU::ratio / ToU::ratio;
|
||||
return FromU::mag / ToU::mag;
|
||||
} else {
|
||||
return quantity_ratio<QFrom> / quantity_ratio<QTo>;
|
||||
return quantity_magnitude<QFrom> / quantity_magnitude<QTo>;
|
||||
}
|
||||
}();
|
||||
|
||||
@@ -112,24 +119,16 @@ template<Quantity To, typename D, typename U, scalable_with_<typename To::rep> R
|
||||
using traits = detail::cast_traits<Rep, typename To::rep>;
|
||||
using ratio_type = TYPENAME traits::ratio_type;
|
||||
using rep_type = TYPENAME traits::rep_type;
|
||||
constexpr auto c_ratio = detail::cast_ratio<quantity<D, U, Rep>, To>;
|
||||
constexpr Magnitude auto c_mag = detail::cast_magnitude<quantity<D, U, Rep>, To>;
|
||||
|
||||
if constexpr (treat_as_floating_point<rep_type>) {
|
||||
return To(
|
||||
static_cast<TYPENAME To::rep>(static_cast<rep_type>(q.number()) *
|
||||
(static_cast<ratio_type>(c_ratio.num) * detail::fpow10<ratio_type>(c_ratio.exp) /
|
||||
static_cast<ratio_type>(c_ratio.den))));
|
||||
static_cast<TYPENAME To::rep>(static_cast<rep_type>(q.number()) * (get_value<ratio_type>(numerator(c_mag)) /
|
||||
get_value<ratio_type>(denominator(c_mag)))));
|
||||
} else {
|
||||
if constexpr (c_ratio.exp > 0) {
|
||||
return To(static_cast<TYPENAME To::rep>(
|
||||
static_cast<rep_type>(q.number()) *
|
||||
(static_cast<ratio_type>(c_ratio.num) * static_cast<ratio_type>(detail::ipow10(c_ratio.exp))) /
|
||||
static_cast<ratio_type>(c_ratio.den)));
|
||||
} else {
|
||||
return To(static_cast<TYPENAME To::rep>(
|
||||
static_cast<rep_type>(q.number()) * static_cast<ratio_type>(c_ratio.num) /
|
||||
(static_cast<ratio_type>(c_ratio.den) * static_cast<ratio_type>(detail::ipow10(-c_ratio.exp)))));
|
||||
}
|
||||
return To(
|
||||
static_cast<TYPENAME To::rep>(static_cast<rep_type>(q.number()) * get_value<ratio_type>(numerator(c_mag)) /
|
||||
get_value<ratio_type>(denominator(c_mag))));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -149,7 +148,7 @@ template<Dimension ToD, typename D, typename U, typename Rep>
|
||||
requires equivalent<ToD, D>
|
||||
[[nodiscard]] constexpr auto quantity_cast(const quantity<D, U, Rep>& q)
|
||||
{
|
||||
return quantity_cast<quantity<ToD, downcast_unit<ToD, U::ratio>, Rep>>(q);
|
||||
return quantity_cast<quantity<ToD, downcast_unit<ToD, U::mag>, Rep>>(q);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -37,13 +37,13 @@ namespace detail {
|
||||
|
||||
template<typename D, typename D1, typename U1, typename D2, typename U2>
|
||||
using reference_multiply_impl =
|
||||
reference<D, downcast_unit<D, (U1::ratio / dimension_unit<D1>::ratio) * (U2::ratio / dimension_unit<D2>::ratio) *
|
||||
dimension_unit<D>::ratio>>;
|
||||
reference<D, downcast_unit<D, (U1::mag / dimension_unit<D1>::mag) * (U2::mag / dimension_unit<D2>::mag) *
|
||||
dimension_unit<D>::mag>>;
|
||||
|
||||
template<typename D, typename D1, typename U1, typename D2, typename U2>
|
||||
using reference_divide_impl =
|
||||
reference<D, downcast_unit<D, (U1::ratio / dimension_unit<D1>::ratio) / (U2::ratio / dimension_unit<D2>::ratio) *
|
||||
dimension_unit<D>::ratio>>;
|
||||
reference<D, downcast_unit<D, (U1::mag / dimension_unit<D1>::mag) / (U2::mag / dimension_unit<D2>::mag) *
|
||||
dimension_unit<D>::mag>>;
|
||||
|
||||
} // namespace detail
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
// IWYU pragma: begin_exports
|
||||
#include <units/bits/derived_unit.h>
|
||||
#include <units/bits/external/fixed_string.h>
|
||||
#include <units/magnitude.h>
|
||||
#include <units/prefix.h>
|
||||
#include <units/ratio.h>
|
||||
#include <units/symbol_text.h>
|
||||
@@ -47,20 +48,18 @@ namespace units {
|
||||
* (i.e. all length units are expressed in terms of meter, all mass units are expressed in
|
||||
* terms of gram, ...)
|
||||
*
|
||||
* @tparam R a ratio of a reference unit
|
||||
* @tparam M a Magnitude representing the (relative) size of this unit
|
||||
* @tparam U a unit to use as a reference for this dimension
|
||||
*/
|
||||
template<ratio R, typename U>
|
||||
requires UnitRatio<R>
|
||||
struct scaled_unit : downcast_base<scaled_unit<R, U>> {
|
||||
static constexpr ::units::ratio ratio = R;
|
||||
template<Magnitude auto M, typename U>
|
||||
struct scaled_unit : downcast_base<scaled_unit<M, U>> {
|
||||
static constexpr ::units::ratio ratio = as_ratio(M);
|
||||
static constexpr Magnitude auto mag = M;
|
||||
using reference = U;
|
||||
};
|
||||
|
||||
template<Dimension D, auto R>
|
||||
// template<Dimension D, ratio R> // TODO: GCC crash!!!
|
||||
requires UnitRatio<R>
|
||||
using downcast_unit = downcast<scaled_unit<R, typename dimension_unit<D>::reference>>;
|
||||
template<Dimension D, Magnitude auto M>
|
||||
using downcast_unit = downcast<scaled_unit<M, typename dimension_unit<D>::reference>>;
|
||||
|
||||
template<Unit U1, Unit U2>
|
||||
struct same_unit_reference : is_same<typename U1::reference, typename U2::reference> {};
|
||||
@@ -74,7 +73,7 @@ struct same_unit_reference : is_same<typename U1::reference, typename U2::refere
|
||||
* @tparam Child inherited class type used by the downcasting facility (CRTP Idiom)
|
||||
*/
|
||||
template<typename Child>
|
||||
struct unit : downcast_dispatch<Child, scaled_unit<ratio(1), Child>> {
|
||||
struct unit : downcast_dispatch<Child, scaled_unit<as_magnitude<1>(), Child>> {
|
||||
static constexpr bool is_named = false;
|
||||
using prefix_family = no_prefix;
|
||||
};
|
||||
@@ -92,7 +91,7 @@ struct unit : downcast_dispatch<Child, scaled_unit<ratio(1), Child>> {
|
||||
* @tparam PF no_prefix or a type of prefix family
|
||||
*/
|
||||
template<typename Child, basic_symbol_text Symbol, PrefixFamily PF>
|
||||
struct named_unit : downcast_dispatch<Child, scaled_unit<ratio(1), Child>> {
|
||||
struct named_unit : downcast_dispatch<Child, scaled_unit<as_magnitude<1>(), Child>> {
|
||||
static constexpr bool is_named = true;
|
||||
static constexpr auto symbol = Symbol;
|
||||
using prefix_family = PF;
|
||||
@@ -109,12 +108,11 @@ struct named_unit : downcast_dispatch<Child, scaled_unit<ratio(1), Child>> {
|
||||
* @tparam Child inherited class type used by the downcasting facility (CRTP Idiom)
|
||||
* @tparam Symbol a short text representation of the unit
|
||||
* @tparam PF no_prefix or a type of prefix family
|
||||
* @tparam R a scale to apply to U
|
||||
* @tparam M the Magnitude by which to scale U
|
||||
* @tparam U a reference unit to scale
|
||||
*/
|
||||
template<typename Child, basic_symbol_text Symbol, PrefixFamily PF, ratio R, Unit U>
|
||||
requires UnitRatio<R>
|
||||
struct named_scaled_unit : downcast_dispatch<Child, scaled_unit<R * U::ratio, typename U::reference>> {
|
||||
template<typename Child, basic_symbol_text Symbol, PrefixFamily PF, Magnitude auto M, Unit U>
|
||||
struct named_scaled_unit : downcast_dispatch<Child, scaled_unit<M * U::mag, typename U::reference>> {
|
||||
static constexpr bool is_named = true;
|
||||
static constexpr auto symbol = Symbol;
|
||||
using prefix_family = PF;
|
||||
@@ -133,7 +131,7 @@ struct named_scaled_unit : downcast_dispatch<Child, scaled_unit<R * U::ratio, ty
|
||||
*/
|
||||
template<typename Child, Prefix P, Unit U>
|
||||
requires U::is_named && std::same_as<typename P::prefix_family, typename U::prefix_family>
|
||||
struct prefixed_unit : downcast_dispatch<Child, scaled_unit<P::ratio * U::ratio, typename U::reference>> {
|
||||
struct prefixed_unit : downcast_dispatch<Child, scaled_unit<P::mag * U::mag, typename U::reference>> {
|
||||
static constexpr bool is_named = true;
|
||||
static constexpr auto symbol = P::symbol + U::symbol;
|
||||
using prefix_family = no_prefix;
|
||||
|
||||
Reference in New Issue
Block a user