feat: PointOrigin arithmetics support added

This commit is contained in:
Mateusz Pusz
2023-08-18 18:35:41 +02:00
parent 110986ee1f
commit 752408449f
3 changed files with 321 additions and 50 deletions
@@ -116,8 +116,34 @@ template<typename T>
requires is_derived_from_specialization_of_quantity_point<T>
inline constexpr bool is_quantity_point<T> = true;
// the below was introduced to workaround gcc-12 bug that produced an error
// "error: ‘const struct mp_units::isq::time’ has no member named ‘absolute_point_origin’"
template<typename PO1, typename PO2>
constexpr bool same_absolute_point_origins_lazy(PO1, PO2)
{
if constexpr (is_derived_from_specialization_of_relative_point_origin<PO1> &&
is_derived_from_specialization_of_relative_point_origin<PO2>)
return std::same_as<std::remove_const_t<decltype(PO1::absolute_point_origin)>,
std::remove_const_t<decltype(PO2::absolute_point_origin)>>;
else if constexpr (is_derived_from_specialization_of_relative_point_origin<PO1>)
return std::same_as<std::remove_const_t<decltype(PO1::absolute_point_origin)>, PO2>;
else if constexpr (is_derived_from_specialization_of_relative_point_origin<PO2>)
return std::same_as<PO1, std::remove_const_t<decltype(PO2::absolute_point_origin)>>;
else
return false;
}
} // namespace detail
template<typename PO1, auto PO2>
concept PointOriginOf =
PointOrigin<PO1> && PointOrigin<std::remove_const_t<decltype(PO2)>> &&
(std::same_as<PO1, std::remove_const_t<decltype(PO2)>> || detail::same_absolute_point_origins_lazy(PO1{}, PO2) ||
(detail::is_specialization_of_absolute_point_origin<PO1> &&
detail::is_specialization_of_absolute_point_origin<std::remove_const_t<decltype(PO2)>> &&
implicitly_convertible(PO1::quantity_spec, PO2.quantity_spec) &&
!detail::NestedQuantityKindSpecOf<PO1::quantity_spec, PO2.quantity_spec>));
/**
* @brief A concept matching all quantity points with provided dimension or quantity spec
*
@@ -127,15 +153,8 @@ inline constexpr bool is_quantity_point<T> = true;
*/
template<typename QP, auto V>
concept QuantityPointOf =
QuantityPoint<QP> &&
(ReferenceOf<std::remove_const_t<decltype(QP::reference)>, V> ||
(PointOrigin<std::remove_const_t<decltype(V)>> &&
(std::same_as<std::remove_const_t<decltype(QP::point_origin)>, std::remove_const_t<decltype(V)>> ||
std::same_as<std::remove_const_t<decltype(QP::absolute_point_origin)>, std::remove_const_t<decltype(V)>> ||
(detail::is_specialization_of_absolute_point_origin<std::remove_const_t<decltype(QP::absolute_point_origin)>> &&
detail::is_specialization_of_absolute_point_origin<std::remove_const_t<decltype(V)>> &&
implicitly_convertible(QP::absolute_point_origin.quantity_spec, V.quantity_spec) &&
!detail::DerivedFromQuantityKindSpecOf<QP::absolute_point_origin.quantity_spec, V.quantity_spec>))));
QuantityPoint<QP> && (ReferenceOf<std::remove_const_t<decltype(QP::reference)>, V> ||
PointOriginOf<std::remove_const_t<decltype(QP::absolute_point_origin)>, V>);
/**
* @brief A concept matching all external quantity point like types
+94 -26
View File
@@ -37,7 +37,9 @@ struct absolute_point_origin {
template<QuantityPoint auto QP>
struct relative_point_origin {
static constexpr QuantityPoint auto quantity_point = QP;
static constexpr QuantitySpec auto quantity_spec = QP.quantity_spec;
static constexpr QuantitySpec auto quantity_spec =
common_quantity_spec(QP.quantity_spec, QP.point_origin.quantity_spec);
static constexpr PointOrigin auto absolute_point_origin = QP.absolute_point_origin;
};
namespace detail {
@@ -114,16 +116,17 @@ public:
template<QuantityPointOf<absolute_point_origin> QP>
requires std::constructible_from<quantity_type, typename QP::quantity_type>
// TODO add perfect forwarding
constexpr explicit(!std::convertible_to<typename QP::quantity_type, quantity_type>) quantity_point(const QP& qp) :
q_([&] {
if constexpr (is_same_v<std::remove_const_t<decltype(point_origin)>,
std::remove_const_t<decltype(QP::point_origin)>>) {
return qp.relative();
} else if constexpr (detail::is_derived_from_specialization_of_relative_point_origin<
} else if constexpr (detail::is_derived_from_specialization_of_absolute_point_origin<
std::remove_const_t<decltype(point_origin)>>) {
return qp.absolute() - zero().absolute();
} else {
return qp.absolute();
} else {
return qp.absolute() - zero().absolute();
}
}())
{
@@ -146,11 +149,11 @@ public:
{
if constexpr (is_same_v<NewPO, std::remove_const_t<decltype(point_origin)>>) {
return *this;
} else if constexpr (detail::is_derived_from_specialization_of_relative_point_origin<NewPO>) {
auto q = absolute() - origin.quantity_point.absolute();
} else if constexpr (detail::is_derived_from_specialization_of_absolute_point_origin<NewPO>) {
auto q = absolute();
return quantity_point<reference, NewPO{}, typename decltype(q)::rep>(std::move(q));
} else {
auto q = absolute();
auto q = absolute() - origin.quantity_point.absolute();
return quantity_point<reference, NewPO{}, typename decltype(q)::rep>(std::move(q));
}
}
@@ -242,35 +245,57 @@ explicit quantity_point(QP)
template<auto R1, auto PO1, typename Rep1, auto R2, typename Rep2>
// TODO simplify when gcc catches up
requires ReferenceOf<std::remove_const_t<decltype(R2)>, get_quantity_spec(R1)>
[[nodiscard]] constexpr QuantityPoint auto operator+(const quantity_point<R1, PO1, Rep1>& lhs,
const quantity<R2, Rep2>& rhs)
requires requires { lhs.relative() + rhs; }
[[nodiscard]] constexpr QuantityPoint auto operator+(const quantity_point<R1, PO1, Rep1>& qp,
const quantity<R2, Rep2>& q)
requires requires { qp.relative() + q; }
{
const auto q = lhs.relative() + rhs;
using q_type = decltype(q);
return quantity_point<q_type::reference, PO1, typename q_type::rep>(q);
auto temp = qp.relative() + q;
using q_type = decltype(temp);
return quantity_point<q_type::reference, PO1, typename q_type::rep>(std::move(temp));
}
template<auto R1, typename Rep1, auto R2, auto PO2, typename Rep2>
// TODO simplify when gcc catches up
requires ReferenceOf<std::remove_const_t<decltype(R1)>, get_quantity_spec(R2)>
[[nodiscard]] constexpr QuantityPoint auto operator+(const quantity<R1, Rep1>& lhs,
const quantity_point<R2, PO2, Rep2>& rhs)
requires requires { rhs + lhs; }
[[nodiscard]] constexpr QuantityPoint auto operator+(const quantity<R1, Rep1>& q,
const quantity_point<R2, PO2, Rep2>& qp)
requires requires { q + qp.relative(); }
{
return rhs + lhs;
return qp + q;
}
template<PointOrigin PO, Quantity Q>
requires ReferenceOf<std::remove_const_t<decltype(Q::reference)>, PO::quantity_spec>
[[nodiscard]] constexpr quantity_point<Q::reference, PO{}, typename Q::rep> operator+(PO, Q&& q)
{
return quantity_point<Q::reference, PO{}, typename Q::rep>(std::forward<Q>(q));
}
template<Quantity Q, PointOrigin PO>
requires ReferenceOf<std::remove_const_t<decltype(Q::reference)>, PO::quantity_spec>
[[nodiscard]] constexpr quantity_point<Q::reference, PO{}, typename Q::rep> operator+(Q&& q, PO po)
{
return po + std::forward<Q>(q);
}
template<auto R1, auto PO1, typename Rep1, auto R2, typename Rep2>
// TODO simplify when gcc catches up
requires ReferenceOf<std::remove_const_t<decltype(R2)>, get_quantity_spec(R1)>
[[nodiscard]] constexpr QuantityPoint auto operator-(const quantity_point<R1, PO1, Rep1>& lhs,
const quantity<R2, Rep2>& rhs)
requires requires { lhs.relative() - rhs; }
[[nodiscard]] constexpr QuantityPoint auto operator-(const quantity_point<R1, PO1, Rep1>& qp,
const quantity<R2, Rep2>& q)
requires requires { qp.relative() - q; }
{
const auto q = lhs.relative() - rhs;
using q_type = decltype(q);
return quantity_point<q_type::reference, PO1, typename q_type::rep>(q);
const auto temp = qp.relative() - q;
using q_type = decltype(temp);
return quantity_point<q_type::reference, PO1, typename q_type::rep>(std::move(temp));
}
template<PointOrigin PO, Quantity Q>
requires ReferenceOf<std::remove_const_t<decltype(Q::reference)>, PO::quantity_spec>
[[nodiscard]] constexpr QuantityPoint auto operator-(PO po, const Q& q)
requires requires { -q; }
{
return po + (-q);
}
template<QuantityPoint QP1, QuantityPointOf<QP1::absolute_point_origin> QP2>
@@ -278,12 +303,55 @@ template<QuantityPoint QP1, QuantityPointOf<QP1::absolute_point_origin> QP2>
requires requires { lhs.absolute() - rhs.absolute(); }
{
if constexpr (is_same_v<std::remove_const_t<decltype(QP1::point_origin)>,
std::remove_const_t<decltype(QP2::point_origin)>>)
return lhs.relative() - rhs.relative();
else
std::remove_const_t<decltype(QP2::point_origin)>>) {
constexpr auto common_qs = common_quantity_spec(QP1::quantity_spec, QP1::point_origin.quantity_spec,
QP2::quantity_spec, QP2::point_origin.quantity_spec);
return quantity_cast<common_qs>(lhs.relative() - rhs.relative());
} else
return lhs.absolute() - rhs.absolute();
}
template<PointOrigin PO, QuantityPointOf<PO{}> QP>
requires ReferenceOf<std::remove_const_t<decltype(QP::reference)>, PO::quantity_spec>
[[nodiscard]] constexpr Quantity auto operator-(const QP& qp, PO)
{
constexpr auto common_qs = common_quantity_spec(PO::quantity_spec, QP::quantity_spec, QP::point_origin.quantity_spec);
if constexpr (detail::is_derived_from_specialization_of_absolute_point_origin<PO>) {
if constexpr (is_same_v<std::remove_const_t<PO>, std::remove_const_t<decltype(QP::point_origin)>>)
return quantity_cast<common_qs>(qp.relative());
else
return quantity_cast<common_qs>(qp.absolute());
} else {
if constexpr (is_same_v<std::remove_const_t<PO>, std::remove_const_t<decltype(QP::point_origin)>>)
return quantity_cast<common_qs>(qp.relative());
else
return quantity_cast<common_qs>(qp.absolute() - PO::quantity_point.absolute());
}
}
template<PointOrigin PO, QuantityPointOf<PO{}> QP>
requires ReferenceOf<std::remove_const_t<decltype(QP::reference)>, PO::quantity_spec>
[[nodiscard]] constexpr Quantity auto operator-(PO po, const QP& qp)
{
return -(qp - po);
}
template<PointOrigin PO1, PointOriginOf<PO1{}> PO2>
requires QuantitySpecOf<std::remove_const_t<decltype(PO1::quantity_spec)>, PO2::quantity_spec> &&
(detail::is_derived_from_specialization_of_relative_point_origin<PO1> ||
detail::is_derived_from_specialization_of_relative_point_origin<PO2>)
[[nodiscard]] constexpr Quantity auto operator-(PO1 po1, PO2 po2)
{
constexpr auto common_qs = common_quantity_spec(PO1::quantity_spec, PO2::quantity_spec);
if constexpr (detail::is_derived_from_specialization_of_absolute_point_origin<PO1>) {
return quantity_cast<common_qs>(-po2.quantity_point.absolute());
} else if constexpr (detail::is_derived_from_specialization_of_absolute_point_origin<PO2>) {
return quantity_cast<common_qs>(po1.quantity_point.absolute());
} else {
return quantity_cast<common_qs>(po1.quantity_point - po2.quantity_point);
}
}
template<QuantityPoint QP1, QuantityPointOf<QP1::absolute_point_origin> QP2>
requires std::three_way_comparable_with<typename QP1::quantity_type, typename QP2::quantity_type>
[[nodiscard]] constexpr auto operator<=>(const QP1& lhs, const QP2& rhs)