refactor: quantity op+() and op-() reimplemented in terms of reference rather then quantity types

`common_quantity`, `common_quantity_for`, `common_quantity_point`, `common_quantity_kind`, and `common_quantity_point_kind` removed

Resolves #290
This commit is contained in:
Mateusz Pusz
2021-07-27 14:40:05 +02:00
parent 7f64e55d04
commit ed5749a52b
4 changed files with 47 additions and 48 deletions

View File

@@ -1,6 +1,8 @@
# Release notes
- **0.8.0 WIP**
- (!) refactor: `common_quantity`, `common_quantity_for`, `common_quantity_point`, `common_quantity_kind`, and `common_quantity_point_kind` removed
- refactor: `quantity` `op+()` and `op-()` reimplemented in terms of `reference` rather then `quantity` types
- (!) fix: add `quantity_point::origin`, like `std::chrono::time_point::clock`
- fix: account for different dimensions in `quantity_point_cast`'s constraint
- build: doxygen updated to 1.9.1

View File

@@ -28,6 +28,9 @@
namespace units {
template<Dimension D, UnitOf<D> U>
struct reference;
template<Dimension D, UnitOf<D> U, Representation Rep>
class quantity;
@@ -42,49 +45,42 @@ class quantity_point_kind;
namespace detail {
template<typename Q1, typename Q2, typename Rep>
struct common_quantity_impl;
template<typename R1, typename R2>
struct common_quantity_reference_impl;
template<typename D, typename U, typename Rep1, typename Rep2, typename Rep>
struct common_quantity_impl<quantity<D, U, Rep1>, quantity<D, U, Rep2>, Rep> {
using type = quantity<D, U, Rep>;
template<typename D, typename U>
struct common_quantity_reference_impl<reference<D, U>, reference<D, U>> {
using type = reference<D, U>;
};
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_unit<D, common_ratio(U1::ratio, U2::ratio)>, Rep>;
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)>>;
};
template<typename D1, typename U1, typename Rep1, typename D2, typename U2, typename Rep2, typename Rep>
template<typename D1, typename U1, typename D2, typename U2>
requires same_unit_reference<dimension_unit<D1>, dimension_unit<D2>>::value
struct common_quantity_impl<quantity<D1, U1, Rep1>, quantity<D2, U2, Rep2>, Rep> {
using type = quantity<D1, downcast_unit<D1, common_ratio(U1::ratio, U2::ratio)>, Rep>;
struct common_quantity_reference_impl<reference<D1, U1>, reference<D2, U2>> {
using type = reference<D1, downcast_unit<D1, common_ratio(U1::ratio, U2::ratio)>>;
};
template<typename D1, typename U1, typename Rep1, typename D2, typename U2, typename Rep2, typename Rep>
struct common_quantity_impl<quantity<D1, U1, Rep1>, quantity<D2, U2, Rep2>, Rep> {
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>;
using type = quantity<dimension, unit, Rep>;
using type = reference<dimension, unit>;
};
template<Quantity Q1, QuantityEquivalentTo<Q1> Q2>
using common_quantity_reference =
TYPENAME detail::common_quantity_reference_impl <
std::remove_const_t<decltype(Q1::reference)>, std::remove_const_t<decltype(Q2::reference)>>::type;
} // namespace detail
template<Quantity Q1, QuantityEquivalentTo<Q1> Q2, Representation Rep = std::common_type_t<typename Q1::rep, typename Q2::rep>>
using common_quantity = TYPENAME detail::common_quantity_impl<Q1, Q2, Rep>::type;
template<QuantityPoint QP1, QuantityPointEquivalentTo<QP1> QP2>
using common_quantity_point = std::common_type_t<QP1, QP2>;
template<QuantityKind QK1, QuantityKindEquivalentTo<QK1> QK2>
using common_quantity_kind = std::common_type_t<QK1, QK2>;
template<QuantityPointKind QPK1, QuantityPointKindEquivalentTo<QPK1> QPK2>
using common_quantity_point_kind = std::common_type_t<QPK1, QPK2>;
} // namespace units
namespace std {
@@ -92,7 +88,10 @@ namespace std {
template<units::Quantity Q1, units::QuantityEquivalentTo<Q1> Q2>
requires requires { typename common_type_t<typename Q1::rep, typename Q2::rep>; }
struct common_type<Q1, Q2> {
using type = units::common_quantity<Q1, Q2>;
private:
using ref = units::detail::common_quantity_reference<Q1, Q2>;
public:
using type = units::quantity<typename ref::dimension, typename ref::unit, common_type_t<typename Q1::rep, typename Q2::rep>>;
};
template<units::QuantityPoint QP1, units::QuantityPointEquivalentTo<QP1> QP2>

View File

@@ -23,7 +23,7 @@
#pragma once
#include <units/bits/common_quantity.h>
#include <units/bits/common_type.h>
#include <units/generic/dimensionless.h>
// IWYU pragma: begin_exports
@@ -90,10 +90,6 @@ concept have_quantity_for_ =
(!Quantity<V>) &&
quantity_value_for_<Func, typename Q::rep, V>;
template<typename Func, Quantity Q1, QuantityEquivalentTo<Q1> Q2>
requires quantity_value_for_<Func, typename Q1::rep, typename Q2::rep>
using common_quantity_for = common_quantity<Q1, Q2, std::invoke_result_t<Func, typename Q1::rep, typename Q2::rep>>;
template<QuantityLike Q>
using quantity_like_type = quantity<typename quantity_like_traits<Q>::dimension, typename quantity_like_traits<Q>::unit, typename quantity_like_traits<Q>::rep>;
@@ -400,7 +396,8 @@ template<Quantity Q1, QuantityEquivalentTo<Q1> Q2>
requires quantity_value_for_<std::plus<>, typename Q1::rep, typename Q2::rep>
[[nodiscard]] constexpr Quantity auto operator+(const Q1& lhs, const Q2& rhs)
{
using ret = common_quantity_for<std::plus<>, Q1, Q2>;
using ref = detail::common_quantity_reference<Q1, Q2>;
using ret = quantity<typename ref::dimension, typename ref::unit, decltype(lhs.number() + rhs.number())>;
return ret(ret(lhs).number() + ret(rhs).number());
}
@@ -408,7 +405,8 @@ template<Quantity Q1, QuantityEquivalentTo<Q1> Q2>
requires quantity_value_for_<std::minus<>, typename Q1::rep, typename Q2::rep>
[[nodiscard]] constexpr Quantity auto operator-(const Q1& lhs, const Q2& rhs)
{
using ret = common_quantity_for<std::minus<>, Q1, Q2>;
using ref = detail::common_quantity_reference<Q1, Q2>;
using ret = quantity<typename ref::dimension, typename ref::unit, decltype(lhs.number() - rhs.number())>;
return ret(ret(lhs).number() - ret(rhs).number());
}
@@ -442,7 +440,7 @@ template<Quantity Q1, QuantityEquivalentTo<Q1> Q2>
requires std::three_way_comparable_with<typename Q1::rep, typename Q2::rep>
[[nodiscard]] constexpr auto operator<=>(const Q1& lhs, const Q2& rhs)
{
using cq = common_quantity<Q1, Q2>;
using cq = std::common_type_t<Q1, Q2>;
return cq(lhs).number() <=> cq(rhs).number();
}
@@ -450,7 +448,7 @@ template<Quantity Q1, QuantityEquivalentTo<Q1> Q2>
requires std::equality_comparable_with<typename Q1::rep, typename Q2::rep>
[[nodiscard]] constexpr bool operator==(const Q1& lhs, const Q2& rhs)
{
using cq = common_quantity<Q1, Q2>;
using cq = std::common_type_t<Q1, Q2>;
return cq(lhs).number() == cq(rhs).number();
}

View File

@@ -22,7 +22,7 @@
#include <units/quantity_point.h>
#include "test_tools.h"
#include <units/bits/common_quantity.h>
#include <units/bits/common_type.h>
#include <units/bits/external/type_traits.h>
#include <units/chrono.h>
#include <units/isq/si/length.h>
@@ -233,17 +233,17 @@ static_assert(2_q_dm3 + quantity_point(2_q_cm3) == quantity_point(2002_q_ml));
static_assert(QuantityPoint<quantity_point<dynamic_origin<dim_length>, millimetre, int>>);
// common_quantity_point
// common_type
static_assert(compare<
common_quantity_point<quantity_point<dynamic_origin<dim_length>, metre, int>, quantity_point<dynamic_origin<dim_length>, kilometre, int>>,
quantity_point<dynamic_origin<dim_length>, metre, int>>);
static_assert(compare<common_quantity_point<quantity_point<dynamic_origin<dim_length>, kilometre, long long>,
quantity_point<dynamic_origin<dim_length>, metre, int>>,
quantity_point<dynamic_origin<dim_length>, metre, long long>>);
static_assert(compare<common_quantity_point<quantity_point<dynamic_origin<dim_length>, kilometre, long long>,
quantity_point<dynamic_origin<dim_length>, millimetre, double>>,
quantity_point<dynamic_origin<dim_length>, millimetre, double>>);
static_assert(compare<std::common_type_t<quantity_point<dynamic_origin<dim_length>, metre, int>,
quantity_point<dynamic_origin<dim_length>, kilometre, int>>,
quantity_point<dynamic_origin<dim_length>, metre, int>>);
static_assert(compare<std::common_type_t<quantity_point<dynamic_origin<dim_length>, kilometre, long long>,
quantity_point<dynamic_origin<dim_length>, metre, int>>,
quantity_point<dynamic_origin<dim_length>, metre, long long>>);
static_assert(compare<std::common_type_t<quantity_point<dynamic_origin<dim_length>, kilometre, long long>,
quantity_point<dynamic_origin<dim_length>, millimetre, double>>,
quantity_point<dynamic_origin<dim_length>, millimetre, double>>);
// common_type