refactor: magnitude interface cleanup

This commit is contained in:
Mateusz Pusz
2024-10-04 17:22:15 +02:00
parent f07e518ff0
commit 07e4e795c1
9 changed files with 149 additions and 101 deletions

View File

@@ -56,6 +56,7 @@ add_mp_units_module(
include/mp-units/framework/dimension_concepts.h include/mp-units/framework/dimension_concepts.h
include/mp-units/framework/expression_template.h include/mp-units/framework/expression_template.h
include/mp-units/framework/magnitude.h include/mp-units/framework/magnitude.h
include/mp-units/framework/magnitude_concepts.h
include/mp-units/framework/quantity.h include/mp-units/framework/quantity.h
include/mp-units/framework/quantity_cast.h include/mp-units/framework/quantity_cast.h
include/mp-units/framework/quantity_concepts.h include/mp-units/framework/quantity_concepts.h

View File

@@ -79,9 +79,9 @@ struct conversion_value_traits {
static constexpr Magnitude auto num = _numerator(M); static constexpr Magnitude auto num = _numerator(M);
static constexpr Magnitude auto den = _denominator(M); static constexpr Magnitude auto den = _denominator(M);
static constexpr Magnitude auto irr = M * (den / num); static constexpr Magnitude auto irr = M * (den / num);
static constexpr T num_mult = get_value<T>(num); static constexpr T num_mult = _get_value<T>(num);
static constexpr T den_mult = get_value<T>(den); static constexpr T den_mult = _get_value<T>(den);
static constexpr T irr_mult = get_value<T>(irr); static constexpr T irr_mult = _get_value<T>(irr);
static constexpr T ratio = num_mult / den_mult * irr_mult; static constexpr T ratio = num_mult / den_mult * irr_mult;
}; };
@@ -120,10 +120,10 @@ template<Quantity To, typename FwdFrom, Quantity From = std::remove_cvref_t<FwdF
}; };
// scale the number // scale the number
if constexpr (is_integral(c_mag)) if constexpr (_is_integral(c_mag))
return scale([&](auto value) { return value * get_value<multiplier_type>(_numerator(c_mag)); }); return scale([&](auto value) { return value * _get_value<multiplier_type>(_numerator(c_mag)); });
else if constexpr (is_integral(pow<-1>(c_mag))) else if constexpr (_is_integral(_pow<-1>(c_mag)))
return scale([&](auto value) { return value / get_value<multiplier_type>(_denominator(c_mag)); }); return scale([&](auto value) { return value / _get_value<multiplier_type>(_denominator(c_mag)); });
else { else {
using value_traits = conversion_value_traits<c_mag, multiplier_type>; using value_traits = conversion_value_traits<c_mag, multiplier_type>;
if constexpr (std::is_floating_point_v<multiplier_type>) if constexpr (std::is_floating_point_v<multiplier_type>)

View File

@@ -30,6 +30,7 @@
#include <mp-units/framework/dimension_concepts.h> #include <mp-units/framework/dimension_concepts.h>
#include <mp-units/framework/expression_template.h> #include <mp-units/framework/expression_template.h>
#include <mp-units/framework/magnitude.h> #include <mp-units/framework/magnitude.h>
#include <mp-units/framework/magnitude_concepts.h>
#include <mp-units/framework/quantity.h> #include <mp-units/framework/quantity.h>
#include <mp-units/framework/quantity_cast.h> #include <mp-units/framework/quantity_cast.h>
#include <mp-units/framework/quantity_concepts.h> #include <mp-units/framework/quantity_concepts.h>

View File

@@ -32,6 +32,7 @@
#include <mp-units/ext/type_traits.h> #include <mp-units/ext/type_traits.h>
#include <mp-units/framework/customization_points.h> #include <mp-units/framework/customization_points.h>
#include <mp-units/framework/expression_template.h> #include <mp-units/framework/expression_template.h>
#include <mp-units/framework/magnitude_concepts.h>
#include <mp-units/framework/symbol_text.h> #include <mp-units/framework/symbol_text.h>
#include <mp-units/framework/unit_symbol_formatting.h> #include <mp-units/framework/unit_symbol_formatting.h>
@@ -61,68 +62,37 @@ using factorizer = wheel_factorizer<4>;
MP_UNITS_EXPORT template<symbol_text Symbol> MP_UNITS_EXPORT template<symbol_text Symbol>
struct mag_constant { struct mag_constant {
static constexpr auto symbol = Symbol; static constexpr auto _symbol_ = Symbol;
}; };
#else #else
MP_UNITS_EXPORT template<symbol_text Symbol, auto Value> MP_UNITS_EXPORT template<symbol_text Symbol, long double Value>
requires(Value > 0)
struct mag_constant { struct mag_constant {
static constexpr auto symbol = Symbol; static constexpr auto _symbol_ = Symbol;
static constexpr auto value = Value; static constexpr long double _value_ = Value;
}; };
#endif #endif
namespace detail {
MP_UNITS_EXPORT template<typename T>
concept MagConstant =
is_derived_from_specialization_of_v<T, mag_constant> && std::is_empty_v<T> && std::is_final_v<T> && requires {
{ +T::value } -> std::same_as<long double>;
};
template<typename T> template<typename T>
concept MagArg = std::integral<T> || MagConstant<T>; concept MagArg = std::integral<T> || MagConstant<T>;
/** }
* @brief Any type which can be used as a basis vector in a PowerV.
*
* We have two categories.
*
* The first is just an integral type (either `int` or `std::intmax_t`). This is for prime number bases.
* These can always be used directly as NTTPs.
*
* The second category is a _custom tag type_, which inherits from `mag_constant` and has a static member variable
* `value` of type `long double` that holds its value. We choose `long double` to get the greatest degree of precision;
* users who need a different type can convert from this at compile time. This category is for any irrational base
* we admit into our representation (on which, more details below).
*/
template<typename T>
concept PowerVBase = one_of<T, int, std::intmax_t> || MagConstant<T>;
// TODO Unify with `power` if UTPs (P1985) are accepted by the Committee // TODO Unify with `power` if UTPs (P1985) are accepted by the Committee
template<PowerVBase auto V, int Num, int... Den> template<detail::PowerVBase auto V, int Num, int... Den>
requires(detail::valid_ratio<Num, Den...> && !detail::ratio_one<Num, Den...>) requires(detail::valid_ratio<Num, Den...> && !detail::ratio_one<Num, Den...>)
struct power_v { struct power_v {
static constexpr auto base = V; static constexpr auto base = V;
static constexpr detail::ratio exponent{Num, Den...}; static constexpr detail::ratio exponent{Num, Den...};
}; };
template<typename T>
concept MagnitudeSpec = PowerVBase<T> || is_specialization_of_v<T, power_v>;
// TODO refactor to typenames?
template<MagnitudeSpec auto... Ms>
struct magnitude;
/**
* @brief Concept to detect whether T is a valid Magnitude.
*/
MP_UNITS_EXPORT template<typename T>
concept Magnitude = is_specialization_of_v<T, magnitude>;
namespace detail { namespace detail {
template<MagnitudeSpec Element> template<MagnitudeSpecExpr Element>
[[nodiscard]] consteval auto get_base(Element element) [[nodiscard]] consteval auto get_base(Element element)
{ {
if constexpr (is_specialization_of_v<Element, power_v>) if constexpr (is_specialization_of_v<Element, power_v>)
@@ -131,18 +101,18 @@ template<MagnitudeSpec Element>
return element; return element;
} }
template<MagnitudeSpec Element> template<MagnitudeSpecExpr Element>
[[nodiscard]] consteval auto get_base_value(Element element) [[nodiscard]] consteval auto get_base_value(Element element)
{ {
if constexpr (is_specialization_of_v<Element, power_v>) if constexpr (is_specialization_of_v<Element, power_v>)
return get_base_value(Element::base); return get_base_value(Element::base);
else if constexpr (MagConstant<Element>) else if constexpr (MagConstant<Element>)
return element.value; return element._value_;
else else
return element; return element;
} }
template<MagnitudeSpec Element> template<MagnitudeSpecExpr Element>
[[nodiscard]] MP_UNITS_CONSTEVAL ratio get_exponent(Element) [[nodiscard]] MP_UNITS_CONSTEVAL ratio get_exponent(Element)
{ {
if constexpr (is_specialization_of_v<Element, power_v>) if constexpr (is_specialization_of_v<Element, power_v>)
@@ -164,7 +134,7 @@ template<PowerVBase auto V, ratio R>
} }
} }
template<MagnitudeSpec M> template<MagnitudeSpecExpr M>
[[nodiscard]] consteval auto inverse(M) [[nodiscard]] consteval auto inverse(M)
{ {
return power_v_or_T<get_base(M{}), -1 * get_exponent(M{})>(); return power_v_or_T<get_base(M{}), -1 * get_exponent(M{})>();
@@ -178,7 +148,7 @@ using widen_t = conditional<std::is_arithmetic_v<T>,
T>; T>;
template<typename T> template<typename T>
[[nodiscard]] consteval widen_t<T> compute_base_power(MagnitudeSpec auto el) [[nodiscard]] consteval widen_t<T> compute_base_power(MagnitudeSpecExpr auto el)
{ {
// This utility can only handle integer powers. To compute rational powers at compile time, we'll // This utility can only handle integer powers. To compute rational powers at compile time, we'll
// need to write a custom function. // need to write a custom function.
@@ -210,23 +180,22 @@ template<typename T>
} }
} }
[[nodiscard]] consteval bool is_rational(MagnitudeSpec auto element) [[nodiscard]] consteval bool is_rational(MagnitudeSpecExpr auto element)
{ {
static_assert(!Magnitude<decltype(element)>); // magnitudes are handles by another overload return std::is_integral_v<decltype(get_base(element))> && get_exponent(element).den == 1;
return std::is_integral_v<decltype(get_base(element))> && (get_exponent(element).den == 1);
} }
[[nodiscard]] consteval bool is_integral(MagnitudeSpec auto element) [[nodiscard]] consteval bool is_integral(MagnitudeSpecExpr auto element)
{ {
static_assert(!Magnitude<decltype(element)>); // magnitudes are handles by another overload
return is_rational(element) && get_exponent(element).num > 0; return is_rational(element) && get_exponent(element).num > 0;
} }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Magnitude product implementation. // Magnitude product implementation.
[[nodiscard]] consteval bool less(MagnitudeSpec auto lhs, MagnitudeSpec auto rhs) [[nodiscard]] consteval bool less(MagnitudeSpecExpr auto lhs, MagnitudeSpecExpr auto rhs)
{ {
// clang-arm64 raises "error: implicit conversion from 'long' to 'long double' may lose precision" so we need an explicit cast // clang-arm64 raises "error: implicit conversion from 'long' to 'long double' may lose precision" so we need an
// explicit cast
using ct = std::common_type_t<decltype(get_base_value(lhs)), decltype(get_base_value(rhs))>; using ct = std::common_type_t<decltype(get_base_value(lhs)), decltype(get_base_value(rhs))>;
return static_cast<ct>(get_base_value(lhs)) < static_cast<ct>(get_base_value(rhs)); return static_cast<ct>(get_base_value(lhs)) < static_cast<ct>(get_base_value(rhs));
} }
@@ -358,7 +327,7 @@ template<typename CharT, std::output_iterator<CharT> Out, auto M, auto... Rest>
bool negative_power) bool negative_power)
{ {
auto to_symbol = [&]<typename T>(T v) { auto to_symbol = [&]<typename T>(T v) {
out = copy_symbol<CharT>(get_base(v).symbol, fmt.encoding, negative_power, out); out = copy_symbol<CharT>(get_base(v)._symbol_, fmt.encoding, negative_power, out);
constexpr ratio r = get_exponent(T{}); constexpr ratio r = get_exponent(T{});
return copy_symbol_exponent<CharT, abs(r.num), r.den>(fmt.encoding, negative_power, out); return copy_symbol_exponent<CharT, abs(r.num), r.den>(fmt.encoding, negative_power, out);
}; };
@@ -370,7 +339,7 @@ template<typename CharT, Magnitude auto Num, Magnitude auto Den, Magnitude auto
constexpr Out magnitude_symbol_impl(Out out, const unit_symbol_formatting& fmt) constexpr Out magnitude_symbol_impl(Out out, const unit_symbol_formatting& fmt)
{ {
bool numerator = false; bool numerator = false;
constexpr auto num_value = get_value<std::intmax_t>(Num); constexpr auto num_value = _get_value<std::intmax_t>(Num);
if constexpr (num_value != 1) { if constexpr (num_value != 1) {
constexpr auto num = detail::regular<num_value>(); constexpr auto num = detail::regular<num_value>();
out = copy_symbol<CharT>(num, fmt.encoding, false, out); out = copy_symbol<CharT>(num, fmt.encoding, false, out);
@@ -386,7 +355,7 @@ constexpr Out magnitude_symbol_impl(Out out, const unit_symbol_formatting& fmt)
using enum unit_symbol_solidus; using enum unit_symbol_solidus;
bool denominator = false; bool denominator = false;
constexpr auto den_value = get_value<std::intmax_t>(Den); constexpr auto den_value = _get_value<std::intmax_t>(Den);
constexpr auto den_constants_size = magnitude_list_size(DenConstants); constexpr auto den_constants_size = magnitude_list_size(DenConstants);
constexpr auto den_size = (den_value != 1) + den_constants_size; constexpr auto den_size = (den_value != 1) + den_constants_size;
auto start_denominator = [&]() { auto start_denominator = [&]() {
@@ -437,20 +406,8 @@ constexpr Out magnitude_symbol_impl(Out out, const unit_symbol_formatting& fmt)
* Magnitudes can be treated as values. Each type encodes exactly one value. Users can multiply, divide, raise to * Magnitudes can be treated as values. Each type encodes exactly one value. Users can multiply, divide, raise to
* rational powers, and compare for equality. * rational powers, and compare for equality.
*/ */
template<MagnitudeSpec auto... Ms> template<detail::MagnitudeSpecExpr auto... Ms>
struct magnitude : detail::magnitude_base<magnitude<Ms...>> { struct magnitude : detail::magnitude_base<magnitude<Ms...>> {
[[nodiscard]] friend consteval bool is_integral(const magnitude&)
{
using namespace detail; // needed for recursive case when magnitudes are in the MagnitudeSpec
return (is_integral(Ms) && ...);
}
[[nodiscard]] friend consteval bool is_rational(const magnitude&)
{
using namespace detail; // needed for recursive case when magnitudes are in the MagnitudeSpec
return (is_rational(Ms) && ...);
}
template<Magnitude M> template<Magnitude M>
[[nodiscard]] friend consteval Magnitude auto operator*(magnitude m1, M m2) [[nodiscard]] friend consteval Magnitude auto operator*(magnitude m1, M m2)
{ {
@@ -462,7 +419,7 @@ struct magnitude : detail::magnitude_base<magnitude<Ms...>> {
return _multiply_impl(m1, m2); return _multiply_impl(m1, m2);
} }
[[nodiscard]] friend consteval auto operator/(magnitude l, Magnitude auto r) { return l * pow<-1>(r); } [[nodiscard]] friend consteval auto operator/(magnitude l, Magnitude auto r) { return l * _pow<-1>(r); }
template<Magnitude M2> template<Magnitude M2>
[[nodiscard]] friend consteval bool operator==(magnitude, M2) [[nodiscard]] friend consteval bool operator==(magnitude, M2)
@@ -470,12 +427,17 @@ struct magnitude : detail::magnitude_base<magnitude<Ms...>> {
return std::is_same_v<magnitude, M2>; return std::is_same_v<magnitude, M2>;
} }
private:
// all below functions should in fact be in a `detail` namespace but are placed here to benefit from the ADL
[[nodiscard]] friend consteval bool _is_integral(const magnitude&) { return (detail::is_integral(Ms) && ...); }
[[nodiscard]] friend consteval bool _is_rational(const magnitude&) { return (detail::is_rational(Ms) && ...); }
/** /**
* @brief The value of a Magnitude in a desired type T. * @brief The value of a Magnitude in a desired type T.
*/ */
template<typename T> template<typename T>
requires((detail::is_integral(Ms) && ...)) || treat_as_floating_point<T> requires((detail::is_integral(Ms) && ...)) || treat_as_floating_point<T>
[[nodiscard]] friend consteval T get_value(const magnitude&) [[nodiscard]] friend consteval T _get_value(const magnitude&)
{ {
// Force the expression to be evaluated in a constexpr context, to catch, e.g., overflow. // Force the expression to be evaluated in a constexpr context, to catch, e.g., overflow.
constexpr T result = detail::checked_static_cast<T>((detail::compute_base_power<T>(Ms) * ... * T{1})); constexpr T result = detail::checked_static_cast<T>((detail::compute_base_power<T>(Ms) * ... * T{1}));
@@ -485,7 +447,7 @@ struct magnitude : detail::magnitude_base<magnitude<Ms...>> {
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Magnitude rational powers implementation. // Magnitude rational powers implementation.
template<int Num, int Den = 1> template<int Num, int Den = 1>
[[nodiscard]] friend consteval auto pow(magnitude) [[nodiscard]] friend consteval auto _pow(magnitude)
{ {
if constexpr (Num == 0) { if constexpr (Num == 0) {
return magnitude<>{}; return magnitude<>{};
@@ -495,10 +457,6 @@ struct magnitude : detail::magnitude_base<magnitude<Ms...>> {
} }
} }
[[nodiscard]] friend consteval auto sqrt(magnitude m) { return pow<1, 2>(m); }
[[nodiscard]] friend consteval auto cbrt(magnitude m) { return pow<1, 3>(m); }
private:
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Magnitude numerator and denominator implementation. // Magnitude numerator and denominator implementation.
[[nodiscard]] friend consteval auto _numerator(magnitude) [[nodiscard]] friend consteval auto _numerator(magnitude)
@@ -506,7 +464,7 @@ private:
return (detail::integer_part(magnitude<Ms>{}) * ... * magnitude<>{}); return (detail::integer_part(magnitude<Ms>{}) * ... * magnitude<>{});
} }
[[nodiscard]] friend consteval auto _denominator(magnitude) { return _numerator(pow<-1>(magnitude{})); } [[nodiscard]] friend consteval auto _denominator(magnitude) { return _numerator(_pow<-1>(magnitude{})); }
[[nodiscard]] friend consteval auto _remove_positive_powers(magnitude) [[nodiscard]] friend consteval auto _remove_positive_powers(magnitude)
{ {
@@ -690,10 +648,6 @@ struct prime_factorization<1> {
template<std::intmax_t N> template<std::intmax_t N>
constexpr auto prime_factorization_v = prime_factorization<N>::value; constexpr auto prime_factorization_v = prime_factorization<N>::value;
} // namespace detail
namespace detail {
template<MagArg auto V> template<MagArg auto V>
[[nodiscard]] consteval Magnitude auto make_magnitude() [[nodiscard]] consteval Magnitude auto make_magnitude()
{ {
@@ -707,7 +661,7 @@ template<MagArg auto V>
MP_UNITS_EXPORT_BEGIN MP_UNITS_EXPORT_BEGIN
template<MagArg auto V> template<detail::MagArg auto V>
requires(detail::get_base_value(V) > 0) requires(detail::get_base_value(V) > 0)
constexpr Magnitude auto mag = detail::make_magnitude<V>(); constexpr Magnitude auto mag = detail::make_magnitude<V>();
@@ -718,16 +672,16 @@ constexpr Magnitude auto mag_ratio = detail::prime_factorization_v<N> / detail::
/** /**
* @brief Create a Magnitude which is some rational number raised to a rational power. * @brief Create a Magnitude which is some rational number raised to a rational power.
*/ */
template<MagArg auto Base, int Num, int Den = 1> template<detail::MagArg auto Base, int Num, int Den = 1>
requires(detail::get_base_value(Base) > 0) requires(detail::get_base_value(Base) > 0)
constexpr Magnitude auto mag_power = pow<Num, Den>(mag<Base>); constexpr Magnitude auto mag_power = _pow<Num, Den>(mag<Base>);
/** /**
* @brief A convenient Magnitude constant for pi, which we can manipulate like a regular number. * @brief A convenient Magnitude constant for pi, which we can manipulate like a regular number.
*/ */
#if defined MP_UNITS_COMP_CLANG || MP_UNITS_COMP_CLANG < 18 #if defined MP_UNITS_COMP_CLANG || MP_UNITS_COMP_CLANG < 18
inline constexpr struct pi final : mag_constant<symbol_text{u8"𝜋", "pi"}> { inline constexpr struct pi final : mag_constant<symbol_text{u8"𝜋", "pi"}> {
static constexpr auto value = std::numbers::pi_v<long double>; static constexpr auto _value_ = std::numbers::pi_v<long double>;
#else #else
inline constexpr struct pi final : mag_constant<symbol_text{u8"𝜋", "pi"}, std::numbers::pi_v<long double>> { inline constexpr struct pi final : mag_constant<symbol_text{u8"𝜋", "pi"}, std::numbers::pi_v<long double>> {
#endif #endif
@@ -744,7 +698,7 @@ template<MagArg auto Base, int Num, int Den>
requires(detail::get_base_value(Base) > 0) requires(detail::get_base_value(Base) > 0)
[[nodiscard]] consteval Magnitude auto mag_power_lazy() [[nodiscard]] consteval Magnitude auto mag_power_lazy()
{ {
return pow<Num, Den>(mag<Base>); return _pow<Num, Den>(mag<Base>);
} }
} // namespace detail } // namespace detail

View File

@@ -0,0 +1,92 @@
// The MIT License (MIT)
//
// Copyright (c) 2018 Mateusz Pusz
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
// IWYU pragma: private, include <mp-units/framework.h>
#include <mp-units/bits/module_macros.h>
#include <mp-units/ext/type_traits.h>
#include <mp-units/framework/expression_template.h>
#include <mp-units/framework/symbol_text.h>
#ifndef MP_UNITS_IN_MODULE_INTERFACE
#ifdef MP_UNITS_IMPORT_STD
import std;
#else
#include <concepts>
#endif
#endif
namespace mp_units {
#if defined MP_UNITS_COMP_CLANG || MP_UNITS_COMP_CLANG < 18
MP_UNITS_EXPORT template<symbol_text Symbol>
#else
MP_UNITS_EXPORT template<symbol_text Symbol, long double Value>
requires(Value > 0)
#endif
struct mag_constant;
MP_UNITS_EXPORT template<typename T>
concept MagConstant = detail::TagType<T> && is_derived_from_specialization_of_v<T, mag_constant>;
namespace detail {
/**
* @brief Any type which can be used as a basis vector in a PowerV.
*
* We have two categories.
*
* The first is just an integral type (either `int` or `std::intmax_t`). This is for prime number bases.
* These can always be used directly as NTTPs.
*
* The second category is a _custom tag type_, which inherits from `mag_constant` and has a static member variable
* `value` of type `long double` that holds its value. We choose `long double` to get the greatest degree of precision;
* users who need a different type can convert from this at compile time. This category is for any irrational base
* we admit into our representation (on which, more details below).
*/
template<typename T>
concept PowerVBase = one_of<T, int, std::intmax_t> || MagConstant<T>;
} // namespace detail
template<detail::PowerVBase auto V, int Num, int... Den>
requires(detail::valid_ratio<Num, Den...> && !detail::ratio_one<Num, Den...>)
struct power_v;
namespace detail {
template<typename T>
concept MagnitudeSpecExpr = PowerVBase<T> || is_specialization_of_v<T, power_v>;
}
template<detail::MagnitudeSpecExpr auto... Ms>
struct magnitude;
/**
* @brief Concept to detect whether T is a valid Magnitude.
*/
MP_UNITS_EXPORT template<typename T>
concept Magnitude = is_specialization_of_v<T, magnitude>;
} // namespace mp_units

View File

@@ -56,7 +56,7 @@ template<Unit UFrom, Unit UTo>
if constexpr (is_same_v<UFrom, UTo>) if constexpr (is_same_v<UFrom, UTo>)
return true; return true;
else else
return is_integral(get_canonical_unit(from).mag / get_canonical_unit(to).mag); return _is_integral(get_canonical_unit(from).mag / get_canonical_unit(to).mag);
} }
template<typename T> template<typename T>

View File

@@ -544,7 +544,7 @@ template<Unit T, symbol_text Symbol, Unit auto U, auto... Args>
template<typename F, int Num, int... Den, typename... Us> template<typename F, int Num, int... Den, typename... Us>
[[nodiscard]] consteval auto get_canonical_unit_impl(const power<F, Num, Den...>&, const type_list<Us...>&) [[nodiscard]] consteval auto get_canonical_unit_impl(const power<F, Num, Den...>&, const type_list<Us...>&)
{ {
auto mag = (mp_units::mag<1> * ... * pow<Num, Den...>(get_canonical_unit_impl(Us{}, Us{}).mag)); auto mag = (mp_units::mag<1> * ... * _pow<Num, Den...>(get_canonical_unit_impl(Us{}, Us{}).mag));
auto u = (one * ... * pow<Num, Den...>(get_canonical_unit_impl(Us{}, Us{}).reference_unit)); auto u = (one * ... * pow<Num, Den...>(get_canonical_unit_impl(Us{}, Us{}).reference_unit));
return canonical_unit{mag, u}; return canonical_unit{mag, u};
} }
@@ -556,9 +556,9 @@ template<typename T, typename F, int Num, int... Den>
if constexpr (requires { typename decltype(base.reference_unit)::_num_; }) { if constexpr (requires { typename decltype(base.reference_unit)::_num_; }) {
auto num = get_canonical_unit_impl(power<F, Num, Den...>{}, typename decltype(base.reference_unit)::_num_{}); auto num = get_canonical_unit_impl(power<F, Num, Den...>{}, typename decltype(base.reference_unit)::_num_{});
auto den = get_canonical_unit_impl(power<F, Num, Den...>{}, typename decltype(base.reference_unit)::_den_{}); auto den = get_canonical_unit_impl(power<F, Num, Den...>{}, typename decltype(base.reference_unit)::_den_{});
return canonical_unit{pow<Num, Den...>(base.mag) * num.mag / den.mag, num.reference_unit / den.reference_unit}; return canonical_unit{_pow<Num, Den...>(base.mag) * num.mag / den.mag, num.reference_unit / den.reference_unit};
} else { } else {
return canonical_unit{pow<Num, Den...>(base.mag), return canonical_unit{_pow<Num, Den...>(base.mag),
derived_unit<power<decltype(base.reference_unit), Num, Den...>>{}}; derived_unit<power<decltype(base.reference_unit), Num, Den...>>{}};
} }
} }
@@ -677,9 +677,9 @@ template<Unit U1, Unit U2>
constexpr auto canonical_lhs = get_canonical_unit(U1{}); constexpr auto canonical_lhs = get_canonical_unit(U1{});
constexpr auto canonical_rhs = get_canonical_unit(U2{}); constexpr auto canonical_rhs = get_canonical_unit(U2{});
if constexpr (is_integral(canonical_lhs.mag / canonical_rhs.mag)) if constexpr (_is_integral(canonical_lhs.mag / canonical_rhs.mag))
return u2; return u2;
else if constexpr (is_integral(canonical_rhs.mag / canonical_lhs.mag)) else if constexpr (_is_integral(canonical_rhs.mag / canonical_lhs.mag))
return u1; return u1;
else { else {
if constexpr (detail::unit_less<U1, U2>::value) if constexpr (detail::unit_less<U1, U2>::value)

View File

@@ -120,9 +120,9 @@ struct quantity_point_like_traits<std::chrono::time_point<C, std::chrono::durati
namespace detail { namespace detail {
[[nodiscard]] constexpr auto as_ratio(Magnitude auto m) [[nodiscard]] constexpr auto as_ratio(Magnitude auto m)
requires(is_rational(m)) requires(_is_rational(m))
{ {
return std::ratio<get_value<std::intmax_t>(_numerator(m)), get_value<std::intmax_t>(_denominator(m))>{}; return std::ratio<_get_value<std::intmax_t>(_numerator(m)), _get_value<std::intmax_t>(_denominator(m))>{};
} }
} // namespace detail } // namespace detail

View File

@@ -143,7 +143,7 @@ static_assert(unit_symbol<usf{.encoding = ascii}>(mag_ratio<1, 18000> * (metre /
// magnitude constants // magnitude constants
#if defined MP_UNITS_COMP_CLANG || MP_UNITS_COMP_CLANG < 18 #if defined MP_UNITS_COMP_CLANG || MP_UNITS_COMP_CLANG < 18
inline constexpr struct e final : mag_constant<"e"> { inline constexpr struct e final : mag_constant<"e"> {
static constexpr long double value = std::numbers::e_v<long double>; static constexpr long double _value_ = std::numbers::e_v<long double>;
#else #else
inline constexpr struct e final : mag_constant<"e", std::numbers::e_v<long double> > { inline constexpr struct e final : mag_constant<"e", std::numbers::e_v<long double> > {
#endif #endif