Skip to content

Commit

Permalink
refactor: perfect forwarding interfaces improved
Browse files Browse the repository at this point in the history
  • Loading branch information
mpusz committed Sep 6, 2024
1 parent cbe37cd commit 664d52c
Show file tree
Hide file tree
Showing 8 changed files with 216 additions and 255 deletions.
24 changes: 12 additions & 12 deletions src/core/include/mp-units/bits/sudo_cast.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,10 +91,10 @@ struct conversion_value_traits {
*
* @tparam To a target quantity type to cast to
*/
template<Quantity To, typename FwdFrom, typename From = std::remove_cvref_t<FwdFrom>>
requires Quantity<From> && (castable(From::quantity_spec, To::quantity_spec)) &&
((From::unit == To::unit && std::constructible_from<typename To::rep, typename From::rep>) ||
(From::unit != To::unit)) // && scalable_with_<typename To::rep>))
template<Quantity To, typename FwdFrom, Quantity From = std::remove_cvref_t<FwdFrom>>
requires(castable(From::quantity_spec, To::quantity_spec)) &&
((From::unit == To::unit && std::constructible_from<typename To::rep, typename From::rep>) ||
(From::unit != To::unit)) // && scalable_with_<typename To::rep>))
// TODO how to constrain the second part here?
[[nodiscard]] constexpr To sudo_cast(FwdFrom&& q)
{
Expand Down Expand Up @@ -143,17 +143,17 @@ template<Quantity To, typename FwdFrom, typename From = std::remove_cvref_t<FwdF
*
* @tparam ToQP a target quantity point type to which to cast to
*/
template<QuantityPoint ToQP, typename FwdFromQP, typename FromQP = std::remove_cvref_t<FwdFromQP>>
requires QuantityPoint<FromQP> && (castable(FromQP::quantity_spec, ToQP::quantity_spec)) &&
(detail::same_absolute_point_origins(ToQP::point_origin, FromQP::point_origin)) &&
((FromQP::unit == ToQP::unit && std::constructible_from<typename ToQP::rep, typename FromQP::rep>) ||
(FromQP::unit != ToQP::unit))
template<QuantityPoint ToQP, typename FwdFromQP, QuantityPoint FromQP = std::remove_cvref_t<FwdFromQP>>
requires(castable(FromQP::quantity_spec, ToQP::quantity_spec)) &&
(detail::same_absolute_point_origins(ToQP::point_origin, FromQP::point_origin)) &&
((FromQP::unit == ToQP::unit && std::constructible_from<typename ToQP::rep, typename FromQP::rep>) ||
(FromQP::unit != ToQP::unit))
[[nodiscard]] constexpr QuantityPoint auto sudo_cast(FwdFromQP&& qp)
{
if constexpr (is_same_v<std::remove_const_t<decltype(ToQP::point_origin)>,
std::remove_const_t<decltype(FromQP::point_origin)>>) {
return quantity_point{
sudo_cast<typename ToQP::quantity_type>(std::forward<FromQP>(qp).quantity_from(FromQP::point_origin)),
sudo_cast<typename ToQP::quantity_type>(std::forward<FwdFromQP>(qp).quantity_from(FromQP::point_origin)),
FromQP::point_origin};
} else {
// it's unclear how hard we should try to avoid truncation here. For now, the only corner case we cater for,
Expand All @@ -176,15 +176,15 @@ template<QuantityPoint ToQP, typename FwdFromQP, typename FromQP = std::remove_c
// unit, we obtain the largest possible range while not causing truncation of fractional values. This is optimal
// for the offset computation.
return sudo_cast<ToQP>(
sudo_cast<quantity_point<FromQP::reference, FromQP::point_origin, c_rep_type>>(std::forward<FromQP>(qp))
sudo_cast<quantity_point<FromQP::reference, FromQP::point_origin, c_rep_type>>(std::forward<FwdFromQP>(qp))
.point_for(ToQP::point_origin));
} else {
// new unit may have a larger unit magnitude; we first need to convert to the new unit (potentially causing
// truncation, but no more than if we did the conversion later), but make sure we keep the larger of the two
// representation types. Then, we can perform the offset computation.
return sudo_cast<ToQP>(
sudo_cast<quantity_point<make_reference(FromQP::quantity_spec, ToQP::unit), FromQP::point_origin, c_rep_type>>(
std::forward<FromQP>(qp))
std::forward<FwdFromQP>(qp))
.point_for(ToQP::point_origin));
}
}
Expand Down
15 changes: 6 additions & 9 deletions src/core/include/mp-units/framework/construction_helpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,22 +39,19 @@ namespace mp_units {

template<Reference R>
struct delta_ {
template<typename Rep>
requires RepresentationOf<std::remove_cvref_t<Rep>, get_quantity_spec(R{}).character>
[[nodiscard]] constexpr quantity<R{}, std::remove_cvref_t<Rep>> operator()(Rep&& lhs) const
template<typename FwdRep, RepresentationOf<get_quantity_spec(R{}).character> Rep = std::remove_cvref_t<FwdRep>>
[[nodiscard]] constexpr quantity<R{}, Rep> operator()(FwdRep&& lhs) const
{
return quantity{std::forward<Rep>(lhs), R{}};
return quantity{std::forward<FwdRep>(lhs), R{}};
}
};

template<Reference R>
struct absolute_ {
template<typename Rep>
requires RepresentationOf<std::remove_cvref_t<Rep>, get_quantity_spec(R{}).character>
[[nodiscard]] constexpr quantity_point<R{}, default_point_origin(R{}), std::remove_cvref_t<Rep>> operator()(
Rep&& lhs) const
template<typename FwdRep, RepresentationOf<get_quantity_spec(R{}).character> Rep = std::remove_cvref_t<FwdRep>>
[[nodiscard]] constexpr quantity_point<R{}, default_point_origin(R{}), Rep> operator()(FwdRep&& lhs) const
{
return quantity_point{quantity{std::forward<Rep>(lhs), R{}}};
return quantity_point{quantity{std::forward<FwdRep>(lhs), R{}}};
}
};

Expand Down
142 changes: 69 additions & 73 deletions src/core/include/mp-units/framework/quantity.h
Original file line number Diff line number Diff line change
Expand Up @@ -168,22 +168,23 @@ class quantity {
quantity(quantity&&) = default;
~quantity() = default;

template<typename Value, Reference R2>
requires detail::SameValueAs<R2{}, R, std::remove_cvref_t<Value>, Rep>
constexpr quantity(Value&& v, R2) : numerical_value_is_an_implementation_detail_(std::forward<Value>(v))
template<typename FwdValue, Reference R2>
requires detail::SameValueAs<R2{}, R, std::remove_cvref_t<FwdValue>, Rep>
constexpr quantity(FwdValue&& v, R2) : numerical_value_is_an_implementation_detail_(std::forward<FwdValue>(v))
{
}

template<typename Value, Reference R2>
requires(!detail::SameValueAs<R2{}, R, std::remove_cvref_t<Value>, Rep>) &&
detail::QuantityConvertibleTo<quantity<R2{}, std::remove_cvref_t<Value>>, quantity>
constexpr quantity(Value&& v, R2) : quantity(quantity<R2{}, std::remove_cvref_t<Value>>{std::forward<Value>(v), R2{}})
template<typename FwdValue, Reference R2, typename Value = std::remove_cvref_t<FwdValue>>
requires(!detail::SameValueAs<R2{}, R, Value, Rep>) &&
detail::QuantityConvertibleTo<quantity<R2{}, Value>, quantity>
constexpr quantity(FwdValue&& v, R2) : quantity(quantity<R2{}, Value>{std::forward<FwdValue>(v), R2{}})
{
}

template<detail::ValuePreservingTo<Rep> Value>
template<detail::ValuePreservingTo<Rep> FwdValue>
requires(unit == ::mp_units::one)
constexpr explicit(false) quantity(Value&& v) : numerical_value_is_an_implementation_detail_(std::forward<Value>(v))
constexpr explicit(false) quantity(FwdValue&& v) :
numerical_value_is_an_implementation_detail_(std::forward<FwdValue>(v))
{
}

Expand All @@ -209,11 +210,11 @@ class quantity {
quantity& operator=(const quantity&) = default;
quantity& operator=(quantity&&) = default;

template<detail::ValuePreservingTo<Rep> Value>
template<detail::ValuePreservingTo<Rep> FwdValue>
requires(unit == ::mp_units::one)
constexpr quantity& operator=(Value&& v)
constexpr quantity& operator=(FwdValue&& v)
{
numerical_value_is_an_implementation_detail_ = std::forward<Value>(v);
numerical_value_is_an_implementation_detail_ = std::forward<FwdValue>(v);
return *this;
}

Expand Down Expand Up @@ -355,16 +356,16 @@ class quantity {
return ::mp_units::quantity{-numerical_value_is_an_implementation_detail_, reference};
}

template<typename Q>
friend constexpr decltype(auto) operator++(Q&& q)
requires std::derived_from<std::remove_cvref_t<Q>, quantity> && requires(rep v) {
template<typename FwdQ, std::derived_from<quantity> Q = std::remove_cvref_t<FwdQ>>
friend constexpr decltype(auto) operator++(FwdQ&& q)
requires requires(rep v) {
{
++v
} -> std::same_as<rep&>;
}
{
++q.numerical_value_is_an_implementation_detail_;
return std::forward<Q>(q);
return std::forward<FwdQ>(q);
}

[[nodiscard]] constexpr QuantityOf<quantity_spec> auto operator++(int)
Expand All @@ -377,16 +378,16 @@ class quantity {
return ::mp_units::quantity{numerical_value_is_an_implementation_detail_++, reference};
}

template<typename Q>
friend constexpr decltype(auto) operator--(Q&& q)
requires std::derived_from<std::remove_cvref_t<Q>, quantity> && requires(rep v) {
template<typename FwdQ, std::derived_from<quantity> Q = std::remove_cvref_t<FwdQ>>
friend constexpr decltype(auto) operator--(FwdQ&& q)
requires requires(rep v) {
{
--v
} -> std::same_as<rep&>;
}
{
--q.numerical_value_is_an_implementation_detail_;
return std::forward<Q>(q);
return std::forward<FwdQ>(q);
}

[[nodiscard]] constexpr QuantityOf<quantity_spec> auto operator--(int)
Expand All @@ -400,97 +401,92 @@ class quantity {
}

// compound assignment operators
template<typename Q>
requires std::derived_from<std::remove_cvref_t<Q>, quantity> && requires(rep a, rep b) {
template<typename FwdQ, std::derived_from<quantity> Q = std::remove_cvref_t<FwdQ>>
requires requires(rep a, rep b) {
{
a += b
} -> std::same_as<rep&>;
}
friend constexpr decltype(auto) operator+=(Q&& lhs, const quantity& rhs)
friend constexpr decltype(auto) operator+=(FwdQ&& lhs, const quantity& rhs)
{
lhs.numerical_value_is_an_implementation_detail_ += rhs.numerical_value_is_an_implementation_detail_;
return std::forward<Q>(lhs);
return std::forward<FwdQ>(lhs);
}

template<typename Q>
requires std::derived_from<std::remove_cvref_t<Q>, quantity> && requires(rep a, rep b) {
template<typename FwdQ, std::derived_from<quantity> Q = std::remove_cvref_t<FwdQ>>
requires requires(rep a, rep b) {
{
a -= b
} -> std::same_as<rep&>;
}
friend constexpr decltype(auto) operator-=(Q&& lhs, const quantity& rhs)
friend constexpr decltype(auto) operator-=(FwdQ&& lhs, const quantity& rhs)
{
lhs.numerical_value_is_an_implementation_detail_ -= rhs.numerical_value_is_an_implementation_detail_;
return std::forward<Q>(lhs);
return std::forward<FwdQ>(lhs);
}

template<typename Q>
requires std::derived_from<std::remove_cvref_t<Q>, quantity> && (!treat_as_floating_point<rep>) &&
requires(rep a, rep b) {
{
a %= b
} -> std::same_as<rep&>;
}
friend constexpr decltype(auto) operator%=(Q&& lhs, const quantity& rhs)
template<typename FwdQ, std::derived_from<quantity> Q = std::remove_cvref_t<FwdQ>>
requires(!treat_as_floating_point<rep>) && requires(rep a, rep b) {
{
a %= b
} -> std::same_as<rep&>;
}
friend constexpr decltype(auto) operator%=(FwdQ&& lhs, const quantity& rhs)

{
MP_UNITS_EXPECTS_DEBUG(rhs != zero());
lhs.numerical_value_is_an_implementation_detail_ %= rhs.numerical_value_is_an_implementation_detail_;
return std::forward<Q>(lhs);
return std::forward<FwdQ>(lhs);
}

template<typename Q, typename Value>
requires std::derived_from<std::remove_cvref_t<Q>, quantity> && (!Quantity<Value>) &&
requires(rep a, const Value b) {
{
a *= b
} -> std::same_as<rep&>;
}
friend constexpr decltype(auto) operator*=(Q&& lhs, const Value& v)
template<typename FwdQ, typename Value, std::derived_from<quantity> Q = std::remove_cvref_t<FwdQ>>
requires(!Quantity<Value>) && requires(rep a, const Value b) {
{
a *= b
} -> std::same_as<rep&>;
}
friend constexpr decltype(auto) operator*=(FwdQ&& lhs, const Value& v)
{
lhs.numerical_value_is_an_implementation_detail_ *= v;
return std::forward<Q>(lhs);
return std::forward<FwdQ>(lhs);
}

template<typename Q1, QuantityOf<dimensionless> Q2>
requires std::derived_from<std::remove_cvref_t<Q1>, quantity> && (Q2::unit == ::mp_units::one) &&
requires(rep a, const typename Q2::rep b) {
{
a *= b
} -> std::same_as<rep&>;
}
friend constexpr decltype(auto) operator*=(Q1&& lhs, const Q2& rhs)
template<typename FwdQ1, QuantityOf<dimensionless> Q2, std::derived_from<quantity> Q1 = std::remove_cvref_t<FwdQ1>>
requires(Q2::unit == ::mp_units::one) && requires(rep a, const typename Q2::rep b) {
{
a *= b
} -> std::same_as<rep&>;
}
friend constexpr decltype(auto) operator*=(FwdQ1&& lhs, const Q2& rhs)
{
lhs.numerical_value_is_an_implementation_detail_ *= rhs.numerical_value_is_an_implementation_detail_;
return std::forward<Q1>(lhs);
return std::forward<FwdQ1>(lhs);
}

template<typename Q, typename Value>
requires std::derived_from<std::remove_cvref_t<Q>, quantity> && (!Quantity<Value>) &&
requires(rep a, const Value b) {
{
a /= b
} -> std::same_as<rep&>;
}
friend constexpr decltype(auto) operator/=(Q&& lhs, const Value& v)
template<typename FwdQ, typename Value, std::derived_from<quantity> Q = std::remove_cvref_t<FwdQ>>
requires(!Quantity<Value>) && requires(rep a, const Value b) {
{
a /= b
} -> std::same_as<rep&>;
}
friend constexpr decltype(auto) operator/=(FwdQ&& lhs, const Value& v)
{
MP_UNITS_EXPECTS_DEBUG(v != quantity_values<Value>::zero());
lhs.numerical_value_is_an_implementation_detail_ /= v;
return std::forward<Q>(lhs);
return std::forward<FwdQ>(lhs);
}

template<typename Q1, QuantityOf<dimensionless> Q2>
requires std::derived_from<std::remove_cvref_t<Q1>, quantity> && (Q2::unit == ::mp_units::one) &&
requires(rep a, const typename Q2::rep b) {
{
a /= b
} -> std::same_as<rep&>;
}
friend constexpr decltype(auto) operator/=(Q1&& lhs, const Q2& rhs)
template<typename FwdQ1, QuantityOf<dimensionless> Q2, std::derived_from<quantity> Q1 = std::remove_cvref_t<FwdQ1>>
requires(Q2::unit == ::mp_units::one) && requires(rep a, const typename Q2::rep b) {
{
a /= b
} -> std::same_as<rep&>;
}
friend constexpr decltype(auto) operator/=(FwdQ1&& lhs, const Q2& rhs)
{
MP_UNITS_EXPECTS_DEBUG(rhs != rhs.zero());
lhs.numerical_value_is_an_implementation_detail_ /= rhs.numerical_value_is_an_implementation_detail_;
return std::forward<Q1>(lhs);
return std::forward<FwdQ1>(lhs);
}

// binary operators on quantities
Expand Down
21 changes: 9 additions & 12 deletions src/core/include/mp-units/framework/quantity_cast.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,13 +56,11 @@ namespace mp_units {
*
* @tparam ToQS a quantity specification to use for a target quantity
*/
template<QuantitySpec auto ToQS, typename Q>
requires Quantity<std::remove_cvref_t<Q>> &&
detail::QuantitySpecCastableTo<std::remove_reference_t<Q>::quantity_spec, ToQS>
[[nodiscard]] constexpr Quantity auto quantity_cast(Q&& q)
template<QuantitySpec auto ToQS, typename FwdQ, Quantity Q = std::remove_cvref_t<FwdQ>>
requires detail::QuantitySpecCastableTo<Q::quantity_spec, ToQS>
[[nodiscard]] constexpr Quantity auto quantity_cast(FwdQ&& q)
{
return quantity{std::forward<Q>(q).numerical_value_is_an_implementation_detail_,
make_reference(ToQS, std::remove_reference_t<Q>::unit)};
return quantity{std::forward<FwdQ>(q).numerical_value_is_an_implementation_detail_, make_reference(ToQS, Q::unit)};
}

/**
Expand All @@ -82,13 +80,12 @@ template<QuantitySpec auto ToQS, typename Q>
*
* @tparam ToQS a quantity specification to use for a target quantity point
*/
template<QuantitySpec auto ToQS, typename QP>
requires QuantityPoint<std::remove_cvref_t<QP>> &&
detail::QuantitySpecCastableTo<std::remove_reference_t<QP>::quantity_spec, ToQS>
[[nodiscard]] constexpr QuantityPoint auto quantity_cast(QP&& qp)
template<QuantitySpec auto ToQS, typename FwdQP, QuantityPoint QP = std::remove_cvref_t<FwdQP>>
requires detail::QuantitySpecCastableTo<QP::quantity_spec, ToQS>
[[nodiscard]] constexpr QuantityPoint auto quantity_cast(FwdQP&& qp)
{
return QP{quantity_cast<ToQS>(std::forward<QP>(qp).quantity_from_origin_is_an_implementation_detail_),
std::remove_reference_t<QP>::point_origin};
return QP{quantity_cast<ToQS>(std::forward<FwdQP>(qp).quantity_from_origin_is_an_implementation_detail_),
QP::point_origin};
}

} // namespace mp_units
Loading

0 comments on commit 664d52c

Please sign in to comment.