forked from mpusz/mp-units
Design cleanup
- unknown_unit added - examples refactored - base_type renamed to downcast_base_type - scaled_unit renamed to named_scaled_unit - detail::reference_unit renamed to scaled_unit - quantity_test cleanup
This commit is contained in:
@@ -29,16 +29,16 @@ namespace units {
|
||||
|
||||
template<typename BaseType>
|
||||
struct downcast_base {
|
||||
using base_type = BaseType;
|
||||
using downcast_base_type = BaseType;
|
||||
friend auto downcast_guide(downcast_base);
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
concept Downcastable =
|
||||
requires {
|
||||
typename T::base_type;
|
||||
typename T::downcast_base_type;
|
||||
} &&
|
||||
std::derived_from<T, downcast_base<typename T::base_type>>;
|
||||
std::derived_from<T, downcast_base<typename T::downcast_base_type>>;
|
||||
|
||||
template<typename Target, Downcastable T>
|
||||
struct downcast_child : T {
|
||||
@@ -67,6 +67,6 @@ namespace units {
|
||||
using downcast = decltype(detail::downcast_impl<T>());
|
||||
|
||||
template<Downcastable T>
|
||||
using downcast_base_t = T::base_type;
|
||||
using downcast_base_t = T::downcast_base_type;
|
||||
|
||||
} // namespace units
|
||||
|
||||
@@ -27,15 +27,14 @@
|
||||
|
||||
namespace units {
|
||||
|
||||
namespace detail {
|
||||
template<typename R>
|
||||
concept UnitRatio = Ratio<R> && (R::num * R::den > 0);
|
||||
|
||||
template<typename U, Ratio R>
|
||||
struct reference_unit;
|
||||
|
||||
} // namespace detail
|
||||
template<typename U, UnitRatio R>
|
||||
struct scaled_unit;
|
||||
|
||||
// Unit
|
||||
template<typename T>
|
||||
concept Unit = is_derived_from_instantiation<T, detail::reference_unit>;
|
||||
concept Unit = is_derived_from_instantiation<T, scaled_unit>;
|
||||
|
||||
} // namespace units
|
||||
|
||||
@@ -246,15 +246,39 @@ struct derived_dimension<Child, U, E, ERest...> : downcast_child<Child, typename
|
||||
using coherent_unit = U;
|
||||
};
|
||||
|
||||
// unknown_unit
|
||||
struct unknown_unit {};
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<typename T>
|
||||
concept PredefinedDimension = Dimension<T> && requires { typename T::coherent_unit; };
|
||||
|
||||
template<Dimension D, Ratio R>
|
||||
auto unit_for_dimension_impl()
|
||||
{
|
||||
if constexpr(PredefinedDimension<D>) {
|
||||
return downcast<scaled_unit<typename D::coherent_unit::reference, R>>{};
|
||||
}
|
||||
else {
|
||||
return scaled_unit<unknown_unit, R>{};
|
||||
}
|
||||
}
|
||||
|
||||
template<Dimension D, Ratio R>
|
||||
using unit_for_dimension = decltype(unit_for_dimension_impl<D, R>());
|
||||
|
||||
}
|
||||
|
||||
// same_dim
|
||||
template<Dimension D1, Dimension D2>
|
||||
inline constexpr bool same_dim;
|
||||
inline constexpr bool same_dim = false;
|
||||
|
||||
template<BaseDimension D1, BaseDimension D2>
|
||||
inline constexpr bool same_dim<D1, D2> = std::is_same_v<D1, D2>;
|
||||
|
||||
template<DerivedDimension D1, DerivedDimension D2>
|
||||
inline constexpr bool same_dim<D1, D2> = std::is_same_v<typename D1::base_type, typename D2::base_type>;
|
||||
inline constexpr bool same_dim<D1, D2> = std::is_same_v<typename D1::downcast_base_type, typename D2::downcast_base_type>;
|
||||
|
||||
// dim_invert
|
||||
namespace detail {
|
||||
@@ -321,7 +345,7 @@ struct dimension_multiply_impl<D1, D2> {
|
||||
|
||||
template<BaseDimension D1, DerivedDimension D2>
|
||||
struct dimension_multiply_impl<D1, D2> {
|
||||
using type = downcast<merge_dimension<derived_dimension<exp<D1, 1>>, typename D2::base_type>>;
|
||||
using type = downcast<merge_dimension<derived_dimension<exp<D1, 1>>, typename D2::downcast_base_type>>;
|
||||
};
|
||||
|
||||
template<DerivedDimension D1, BaseDimension D2>
|
||||
@@ -331,7 +355,7 @@ struct dimension_multiply_impl<D1, D2> {
|
||||
|
||||
template<DerivedDimension D1, DerivedDimension D2>
|
||||
struct dimension_multiply_impl<D1, D2> {
|
||||
using type = downcast<merge_dimension<typename D1::base_type, typename D2::base_type>>;
|
||||
using type = downcast<merge_dimension<typename D1::downcast_base_type, typename D2::downcast_base_type>>;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
@@ -360,7 +384,7 @@ struct dimension_sqrt_impl<derived_dimension<exp<D, 2>>> {
|
||||
|
||||
template<DerivedDimension D>
|
||||
struct dimension_sqrt_impl<D> {
|
||||
using type = dimension_sqrt_impl<typename D::base_type>;
|
||||
using type = dimension_sqrt_impl<typename D::downcast_base_type>;
|
||||
};
|
||||
|
||||
template<typename... Es>
|
||||
@@ -371,7 +395,7 @@ struct dimension_sqrt_impl<derived_dimension<Es...>> {
|
||||
} // namespace detail
|
||||
|
||||
template<Dimension D>
|
||||
using dimension_sqrt = detail::dimension_sqrt_impl<typename D::base_type>::type;
|
||||
using dimension_sqrt = detail::dimension_sqrt_impl<typename D::downcast_base_type>::type;
|
||||
|
||||
// dimension_pow
|
||||
namespace detail {
|
||||
|
||||
@@ -39,7 +39,7 @@ namespace units {
|
||||
{
|
||||
using dim = dimension_pow<D, N>;
|
||||
using r = ratio_pow<typename U::ratio, N>;
|
||||
return quantity<dim, downcast<detail::reference_unit<typename dim::coherent_unit::reference, r>>, Rep>(static_cast<Rep>(std::pow(q.count(), N)));
|
||||
return quantity<dim, downcast<scaled_unit<typename dim::coherent_unit::reference, r>>, Rep>(static_cast<Rep>(std::pow(q.count(), N)));
|
||||
}
|
||||
|
||||
template<typename D, typename U, typename Rep>
|
||||
@@ -47,7 +47,7 @@ namespace units {
|
||||
{
|
||||
using dim = dimension_sqrt<typename U::dimension>;
|
||||
using r = ratio_sqrt<typename U::ratio>;
|
||||
return quantity<dim, downcast<detail::reference_unit<typename dim::coherent_unit::reference, r>>, Rep>(static_cast<Rep>(std::sqrt(q.count())));
|
||||
return quantity<dim, downcast<scaled_unit<typename dim::coherent_unit::reference, r>>, Rep>(static_cast<Rep>(std::sqrt(q.count())));
|
||||
}
|
||||
|
||||
} // namespace units
|
||||
|
||||
@@ -35,7 +35,7 @@ template<typename Dim, template<typename...> typename DimTemplate>
|
||||
concept DimensionOf = (Dimension<Dim> || BaseDimension<Dim>) && is_derived_from_instantiation<Dim, DimTemplate>;
|
||||
|
||||
template<typename Q, template<typename...> typename DimTemplate>
|
||||
concept QuantityOf = Quantity<Q> && is_derived_from_instantiation<Q::dimension, DimTemplate>;
|
||||
concept QuantityOf = Quantity<Q> && is_derived_from_instantiation<typename Q::dimension, DimTemplate>;
|
||||
|
||||
// ------------------------ base dimensions -----------------------------
|
||||
|
||||
|
||||
+13
-13
@@ -22,23 +22,23 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <units/dimensions/velocity.h>
|
||||
#include <units/physical/dimensions.h>
|
||||
#include <units/physical/si/velocity.h>
|
||||
|
||||
namespace units {
|
||||
namespace units::si {
|
||||
|
||||
struct acceleration : derived_dimension<acceleration, exp<velocity, 1>, exp<time, -1>> {};
|
||||
struct metre_per_second_sq : unit<metre_per_second_sq> {};
|
||||
struct dim_acceleration : physical::dim_acceleration<dim_acceleration, metre_per_second_sq, dim_length, dim_time> {};
|
||||
|
||||
template<typename T>
|
||||
concept Acceleration = QuantityOf<T, acceleration>;
|
||||
template<Unit U, Scalar Rep = double>
|
||||
using acceleration = quantity<dim_acceleration, U, Rep>;
|
||||
|
||||
struct metre_per_second_sq : coherent_derived_unit<metre_per_second_sq, acceleration> {};
|
||||
inline namespace literals {
|
||||
|
||||
inline namespace literals {
|
||||
// mps_sq
|
||||
constexpr auto operator""mps_sq(unsigned long long l) { return acceleration<metre_per_second_sq, std::int64_t>(l); }
|
||||
constexpr auto operator""mps_sq(long double l) { return acceleration<metre_per_second_sq, long double>(l); }
|
||||
|
||||
// mps_sq
|
||||
constexpr auto operator""mps_sq(unsigned long long l) { return quantity<metre_per_second_sq, std::int64_t>(l); }
|
||||
constexpr auto operator""mps_sq(long double l) { return quantity<metre_per_second_sq, long double>(l); }
|
||||
} // namespace literals
|
||||
|
||||
} // namespace literals
|
||||
|
||||
} // namespace units
|
||||
} // namespace units::si
|
||||
@@ -58,10 +58,10 @@ constexpr auto operator"" km(long double l) { return length<kilometre, long doub
|
||||
} // namespace literals
|
||||
|
||||
// US customary units
|
||||
struct yard : scaled_unit<yard, "yd", no_prefix, ratio<9'144, 10'000>, metre> {};
|
||||
struct foot : scaled_unit<foot, "ft", no_prefix, ratio<1, 3>, yard> {};
|
||||
struct inch : scaled_unit<inch, "in", no_prefix, ratio<1, 12>, foot> {};
|
||||
struct mile : scaled_unit<mile, "mi", no_prefix, ratio<1'760>, yard> {};
|
||||
struct yard : named_scaled_unit<yard, "yd", no_prefix, ratio<9'144, 10'000>, metre> {};
|
||||
struct foot : named_scaled_unit<foot, "ft", no_prefix, ratio<1, 3>, yard> {};
|
||||
struct inch : named_scaled_unit<inch, "in", no_prefix, ratio<1, 12>, foot> {};
|
||||
struct mile : named_scaled_unit<mile, "mi", no_prefix, ratio<1'760>, yard> {};
|
||||
|
||||
inline namespace literals {
|
||||
|
||||
|
||||
@@ -31,8 +31,8 @@ struct second : named_unit<second, "s", prefix> {};
|
||||
struct nanosecond : prefixed_unit<nanosecond, nano, second> {};
|
||||
struct microsecond : prefixed_unit<microsecond, micro, second> {};
|
||||
struct millisecond : prefixed_unit<millisecond, milli, second> {};
|
||||
struct minute : scaled_unit<minute, "min", no_prefix, ratio<60>, second> {};
|
||||
struct hour : scaled_unit<hour, "h", no_prefix, ratio<3600>, second> {};
|
||||
struct minute : named_scaled_unit<minute, "min", no_prefix, ratio<60>, second> {};
|
||||
struct hour : named_scaled_unit<hour, "h", no_prefix, ratio<3600>, second> {};
|
||||
|
||||
struct dim_time : physical::dim_time<second> {};
|
||||
|
||||
|
||||
@@ -74,7 +74,7 @@ struct common_quantity_impl<quantity<D, U, Rep1>, quantity<D, U, Rep2>, Rep> {
|
||||
template<typename D, typename U1, typename Rep1, typename U2, typename Rep2, typename Rep>
|
||||
struct common_quantity_impl<quantity<D, U1, Rep1>, quantity<D, U2, Rep2>, Rep> {
|
||||
using type = quantity<
|
||||
D, downcast<detail::reference_unit<typename U1::reference, common_ratio<typename U1::ratio, typename U2::ratio>>>,
|
||||
D, downcast<scaled_unit<typename U1::reference, common_ratio<typename U1::ratio, typename U2::ratio>>>,
|
||||
Rep>;
|
||||
};
|
||||
|
||||
@@ -154,7 +154,7 @@ template<Quantity To, typename D, typename U, typename Rep>
|
||||
{
|
||||
using c_ratio = ratio_divide<typename U::ratio, typename To::unit::ratio>;
|
||||
using c_rep = std::common_type_t<typename To::rep, Rep, intmax_t>;
|
||||
using ret_unit = downcast<detail::reference_unit<typename U::reference, typename To::unit::ratio>>;
|
||||
using ret_unit = downcast<scaled_unit<typename U::reference, typename To::unit::ratio>>;
|
||||
using ret = quantity<D, ret_unit, typename To::rep>;
|
||||
using cast = detail::quantity_cast_impl<ret, c_ratio, c_rep, c_ratio::num == 1, c_ratio::den == 1>;
|
||||
return cast::cast(q);
|
||||
@@ -410,7 +410,7 @@ public:
|
||||
template<class CharT, class Traits>
|
||||
friend std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& os, const quantity& q)
|
||||
{
|
||||
return os; // << q.count() << " " << detail::unit_text<quantity::unit>();
|
||||
return os << q.count(); // << " " << detail::unit_text<quantity::unit>(); TODO add support
|
||||
}
|
||||
};
|
||||
|
||||
@@ -466,7 +466,7 @@ template<typename D1, typename U1, typename Rep1, typename D2, typename U2, type
|
||||
{
|
||||
using dim = dimension_multiply<D1, D2>;
|
||||
using ratio = ratio_multiply<typename U1::ratio, typename U2::ratio>;
|
||||
using unit = downcast<detail::reference_unit<typename dim::coherent_unit::reference, ratio>>;
|
||||
using unit = detail::unit_for_dimension<dim, ratio>;
|
||||
using common_rep = decltype(lhs.count() * rhs.count());
|
||||
using ret = quantity<dim, unit, common_rep>;
|
||||
return ret(lhs.count() * rhs.count());
|
||||
@@ -480,7 +480,7 @@ template<typename D, Scalar Value, typename U, typename Rep>
|
||||
|
||||
using dim = dim_invert<D>;
|
||||
using ratio = ratio<U::ratio::den, U::ratio::num>;
|
||||
using unit = downcast<detail::reference_unit<typename dim::coherent_unit::reference, ratio>>;
|
||||
using unit = detail::unit_for_dimension<dim, ratio>;
|
||||
using common_rep = decltype(v / q.count());
|
||||
using ret = quantity<dim, unit, common_rep>;
|
||||
return ret(v / q.count());
|
||||
@@ -518,8 +518,8 @@ template<typename D1, typename U1, typename Rep1, typename D2, typename U2, type
|
||||
|
||||
using common_rep = decltype(lhs.count() / rhs.count());
|
||||
using dim = dimension_divide<D1, D2>;
|
||||
using unit = downcast<detail::reference_unit<typename dim::coherent_unit::reference,
|
||||
ratio_divide<typename U1::ratio, typename U2::ratio>>>;
|
||||
using ratio = ratio_divide<typename U1::ratio, typename U2::ratio>;
|
||||
using unit = detail::unit_for_dimension<dim, ratio>;
|
||||
using ret = quantity<dim, unit, common_rep>;
|
||||
return ret(lhs.count() / rhs.count());
|
||||
}
|
||||
|
||||
+22
-18
@@ -32,31 +32,35 @@
|
||||
|
||||
namespace units {
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<typename U, Ratio R>
|
||||
struct reference_unit : downcast_base<reference_unit<U, R>> {
|
||||
// scaled_unit
|
||||
template<typename U, UnitRatio R>
|
||||
struct scaled_unit : downcast_base<scaled_unit<U, R>> {
|
||||
using reference = U;
|
||||
using ratio = R;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
// UnitOf
|
||||
namespace detail {
|
||||
|
||||
template<typename U, typename D>
|
||||
concept SameReference = std::same_as<typename U::reference, typename D::coherent_unit::reference>;
|
||||
|
||||
}
|
||||
|
||||
template<typename U, typename D>
|
||||
concept UnitOf =
|
||||
Unit<U> &&
|
||||
Dimension<D> &&
|
||||
std::same_as<typename U::reference, typename D::coherent_unit::reference>;
|
||||
(std::same_as<typename U::reference, unknown_unit> || detail::SameReference<U, D>);
|
||||
|
||||
namespace detail {
|
||||
|
||||
// same_reference_units
|
||||
// same_scaled_units
|
||||
template<DerivedDimension D, Unit... Us>
|
||||
inline constexpr bool same_reference_units = false;
|
||||
inline constexpr bool same_scaled_units = false;
|
||||
|
||||
template<typename... Es, Unit... Us>
|
||||
inline constexpr bool same_reference_units<derived_dimension<Es...>, Us...> = (UnitOf<Us, typename Es::dimension> && ...);
|
||||
inline constexpr bool same_scaled_units<derived_dimension<Es...>, Us...> = (UnitOf<Us, typename Es::dimension> && ...);
|
||||
|
||||
// deduced_unit
|
||||
template<typename Result, int UnitExpNum, int UnitExpDen, typename UnitRatio>
|
||||
@@ -91,7 +95,7 @@ struct derived_ratio<derived_dimension<E, ERest...>, U, URest...> {
|
||||
|
||||
template<DerivedDimension D, Unit... Us>
|
||||
using deduced_unit =
|
||||
reference_unit<typename D::coherent_unit::reference, typename detail::derived_ratio<typename D::recipe, Us...>::ratio>;
|
||||
scaled_unit<typename D::coherent_unit::reference, typename detail::derived_ratio<typename D::recipe, Us...>::ratio>;
|
||||
|
||||
} // namespace detail
|
||||
|
||||
@@ -112,7 +116,7 @@ using deduced_unit =
|
||||
* @tparam Child inherited class type used by the downcasting facility (CRTP Idiom)
|
||||
*/
|
||||
template<typename Child>
|
||||
struct unit : downcast_child<Child, detail::reference_unit<Child, ratio<1>>> {
|
||||
struct unit : downcast_child<Child, scaled_unit<Child, ratio<1>>> {
|
||||
static constexpr bool is_named = false;
|
||||
using prefix_type = no_prefix;
|
||||
};
|
||||
@@ -130,7 +134,7 @@ struct unit : downcast_child<Child, detail::reference_unit<Child, ratio<1>>> {
|
||||
* @tparam PT no_prefix or a type of prefix family
|
||||
*/
|
||||
template<typename Child, basic_fixed_string Symbol, PrefixType PT>
|
||||
struct named_unit : downcast_child<Child, detail::reference_unit<Child, ratio<1>>> {
|
||||
struct named_unit : downcast_child<Child, scaled_unit<Child, ratio<1>>> {
|
||||
static constexpr bool is_named = true;
|
||||
static constexpr auto symbol = Symbol;
|
||||
using prefix_type = PT;
|
||||
@@ -150,8 +154,8 @@ struct named_unit : downcast_child<Child, detail::reference_unit<Child, ratio<1>
|
||||
* @tparam R a scale to apply to U
|
||||
* @tparam U a reference unit to scale
|
||||
*/
|
||||
template<typename Child, basic_fixed_string Symbol, PrefixType PT, Ratio R, Unit U>
|
||||
struct scaled_unit : downcast_child<Child, detail::reference_unit<typename U::reference, ratio_multiply<R, typename U::ratio>>> {
|
||||
template<typename Child, basic_fixed_string Symbol, PrefixType PT, UnitRatio R, Unit U>
|
||||
struct named_scaled_unit : downcast_child<Child, scaled_unit<typename U::reference, ratio_multiply<R, typename U::ratio>>> {
|
||||
static constexpr bool is_named = true;
|
||||
static constexpr auto symbol = Symbol;
|
||||
using prefix_type = PT;
|
||||
@@ -171,11 +175,11 @@ struct scaled_unit : downcast_child<Child, detail::reference_unit<typename U::re
|
||||
template<typename Child, Prefix P, Unit U>
|
||||
requires std::same_as<typename P::prefix_type, typename U::prefix_type>
|
||||
// TODO replace with the below code when gcc will stop to crash on it ;-)
|
||||
// struct prefixed_unit : scaled_unit<Child, P::symbol + U::symbol, typename P::prefix_type,
|
||||
// struct prefixed_unit : named_scaled_unit<Child, P::symbol + U::symbol, typename P::prefix_type,
|
||||
// ratio_multiply<typename P::ratio, typename U::ratio>,
|
||||
// typename U::reference> {};
|
||||
struct prefixed_unit :
|
||||
downcast_child<Child, detail::reference_unit<typename U::reference, ratio_multiply<typename P::ratio, typename U::ratio>>> {
|
||||
downcast_child<Child, scaled_unit<typename U::reference, ratio_multiply<typename P::ratio, typename U::ratio>>> {
|
||||
static constexpr bool is_named = true;
|
||||
static constexpr auto symbol = P::symbol + U::symbol;
|
||||
using prefix_type = P::prefix_type;
|
||||
@@ -194,7 +198,7 @@ struct prefixed_unit :
|
||||
* @tparam URest the units for the rest of dimensions from the recipe
|
||||
*/
|
||||
template<typename Child, DerivedDimension Dim, Unit U, Unit... URest>
|
||||
requires detail::same_reference_units<typename Dim::recipe, U, URest...> &&
|
||||
requires detail::same_scaled_units<typename Dim::recipe, U, URest...> &&
|
||||
(U::is_named && (URest::is_named && ... && true))
|
||||
struct deduced_unit : downcast_child<Child, detail::deduced_unit<Dim, U, URest...>> {
|
||||
static constexpr bool is_named = false;
|
||||
|
||||
Reference in New Issue
Block a user