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:
Mateusz Pusz
2019-12-06 12:18:39 +01:00
parent c48bfe2098
commit f31b26b5e5
22 changed files with 354 additions and 160 deletions
+4 -4
View File
@@ -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
+5 -6
View File
@@ -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
+30 -6
View File
@@ -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 {
+2 -2
View File
@@ -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
+1 -1
View File
@@ -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 -----------------------------
@@ -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
+4 -4
View File
@@ -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 {
+2 -2
View File
@@ -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> {};
+7 -7
View File
@@ -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
View File
@@ -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;