Skip to content

Commit

Permalink
feat: numerical_value_ref_in disallowed for rvalues
Browse files Browse the repository at this point in the history
  • Loading branch information
mpusz committed Sep 13, 2023
1 parent 6a1e600 commit 2e26eed
Show file tree
Hide file tree
Showing 11 changed files with 261 additions and 304 deletions.
2 changes: 1 addition & 1 deletion example/currency.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ template<ReferenceOf<currency> auto To, ReferenceOf<currency> auto From, auto PO
quantity_point<To, PO, Rep> exchange_to(quantity_point<From, PO, Rep> q)
{
return quantity_point{zero + static_cast<Rep>(exchange_rate<q.unit, get_unit(To)>() *
(q - q.absolute_point_origin).numerical_value_ref_in(q.unit)) *
(q - q.absolute_point_origin).numerical_value_in(q.unit)) *
To};
}

Expand Down
4 changes: 2 additions & 2 deletions src/core-fmt/include/mp-units/format.h
Original file line number Diff line number Diff line change
Expand Up @@ -224,9 +224,9 @@ struct quantity_formatter {
const quantity_format_specs<CharT>& specs;
Locale loc;

explicit quantity_formatter(OutputIt o, quantity<Reference, Rep> q, const quantity_format_specs<CharT>& fspecs,
explicit quantity_formatter(OutputIt o, const quantity<Reference, Rep>& q, const quantity_format_specs<CharT>& fspecs,
Locale lc) :
out(o), val(std::move(q).numerical_value_ref_in(q.unit)), specs(fspecs), loc(std::move(lc))
out(o), val(q.numerical_value_ref_in(q.unit)), specs(fspecs), loc(std::move(lc))
{
}

Expand Down
4 changes: 2 additions & 2 deletions src/core/include/mp-units/bits/quantity_cast.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,9 @@ template<QuantitySpec auto ToQS, typename Q>
{
if constexpr (detail::QuantityKindSpec<std::remove_const_t<decltype(ToQS)>> &&
AssociatedUnit<std::remove_const_t<decltype(Q::unit)>>)
return make_quantity<Q::unit>(std::forward<Q>(q).numerical_value_ref_in(q.unit));
return make_quantity<Q::unit>(std::forward<Q>(q).numerical_value_);
else
return make_quantity<reference<ToQS, Q::unit>{}>(std::forward<Q>(q).numerical_value_ref_in(q.unit));
return make_quantity<reference<ToQS, Q::unit>{}>(std::forward<Q>(q).numerical_value_);
}

} // namespace mp_units
13 changes: 6 additions & 7 deletions src/core/include/mp-units/bits/sudo_cast.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,10 +63,10 @@ template<Quantity To, typename From>
if constexpr (q_unit == To::unit) {
// no scaling of the number needed
return make_quantity<To::reference>(static_cast<MP_UNITS_TYPENAME To::rep>(
std::forward<From>(q).numerical_value_ref_in(q_unit))); // this is the only (and recommended) way to do
// a truncating conversion on a number, so we are
// using static_cast to suppress all the compiler
// warnings on conversions
std::forward<From>(q).numerical_value_)); // this is the only (and recommended) way to do
// a truncating conversion on a number, so we are
// using static_cast to suppress all the compiler
// warnings on conversions
} else {
// scale the number
constexpr Magnitude auto c_mag = get_canonical_unit(q_unit).mag / get_canonical_unit(To::unit).mag;
Expand All @@ -78,9 +78,8 @@ template<Quantity To, typename From>
using multiplier_type =
conditional<treat_as_floating_point<c_rep_type>, std::common_type_t<c_mag_type, long double>, c_mag_type>;
constexpr auto val = [](Magnitude auto m) { return get_value<multiplier_type>(m); };
return static_cast<MP_UNITS_TYPENAME To::rep>(
static_cast<c_rep_type>(std::forward<From>(q).numerical_value_ref_in(q_unit)) * val(num) / val(den) *
val(irr)) *
return static_cast<MP_UNITS_TYPENAME To::rep>(static_cast<c_rep_type>(std::forward<From>(q).numerical_value_) *
val(num) / val(den) * val(irr)) *
To::reference;
}
}
Expand Down
57 changes: 19 additions & 38 deletions src/core/include/mp-units/quantity.h
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ class quantity {

template<detail::QuantityConvertibleTo<quantity> Q>
constexpr explicit(!std::convertible_to<typename Q::rep, Rep>) quantity(const Q& q) :
numerical_value_(detail::sudo_cast<quantity>(q).numerical_value_ref_in(unit))
numerical_value_(detail::sudo_cast<quantity>(q).numerical_value_)
{
}

Expand Down Expand Up @@ -157,52 +157,36 @@ class quantity {
}

// data access
#ifdef __cpp_explicit_this_parameter
template<typename Self, Unit U>
requires(U{} == unit)
[[nodiscard]] constexpr auto&& numerical_value_ref_in(this Self&& self, U) noexcept
{
return std::forward<Self>(self).numerical_value_;
}
#else
template<Unit U>
requires(U{} == unit)
[[nodiscard]] constexpr rep& numerical_value_ref_in(U) & noexcept
{
return numerical_value_;
}

template<Unit U>
requires(U{} == unit)
[[nodiscard]] constexpr const rep& numerical_value_ref_in(U) const& noexcept
{
return numerical_value_;
}

template<Unit U>
requires(U{} == unit)
[[nodiscard]] constexpr rep&& numerical_value_ref_in(U) && noexcept
{
return std::move(numerical_value_);
}
template<Unit U>
requires(U{} == unit)
[[nodiscard]] constexpr const rep&& numerical_value_ref_in(U) const&& noexcept
{
return std::move(numerical_value_);
}
#endif
constexpr const rep&& numerical_value_ref_in(U) const&& noexcept = delete;

template<Unit U>
requires requires(quantity q) { q.in(U{}); }
[[nodiscard]] constexpr rep numerical_value_in(U) const noexcept
{
return (*this).in(U{}).numerical_value_ref_in(U{});
return (*this).in(U{}).numerical_value_;
}

template<Unit U>
requires requires(quantity q) { q.force_in(U{}); }
[[nodiscard]] constexpr rep force_numerical_value_in(U) const noexcept
{
return (*this).force_in(U{}).numerical_value_ref_in(U{});
return (*this).force_in(U{}).numerical_value_;
}

// member unary operators
Expand All @@ -213,7 +197,7 @@ class quantity {
} -> std::common_with<rep>;
}
{
return make_quantity<reference>(+numerical_value_ref_in(unit));
return make_quantity<reference>(+numerical_value_);
}

[[nodiscard]] constexpr Quantity auto operator-() const
Expand All @@ -223,7 +207,7 @@ class quantity {
} -> std::common_with<rep>;
}
{
return make_quantity<reference>(-numerical_value_ref_in(unit));
return make_quantity<reference>(-numerical_value_);
}

constexpr quantity& operator++()
Expand Down Expand Up @@ -387,17 +371,15 @@ template<auto R1, typename Rep1, auto R2, typename Rep2>
[[nodiscard]] constexpr Quantity auto operator+(const quantity<R1, Rep1>& lhs, const quantity<R2, Rep2>& rhs)
{
using ret = detail::common_quantity_for<std::plus<>, quantity<R1, Rep1>, quantity<R2, Rep2>>;
return make_quantity<ret::reference>(ret(lhs).numerical_value_ref_in(ret::unit) +
ret(rhs).numerical_value_ref_in(ret::unit));
return make_quantity<ret::reference>(ret(lhs).numerical_value_ + ret(rhs).numerical_value_);
}

template<auto R1, typename Rep1, auto R2, typename Rep2>
requires detail::InvocableQuantities<std::minus<>, quantity<R1, Rep1>, quantity<R2, Rep2>>
[[nodiscard]] constexpr Quantity auto operator-(const quantity<R1, Rep1>& lhs, const quantity<R2, Rep2>& rhs)
{
using ret = detail::common_quantity_for<std::minus<>, quantity<R1, Rep1>, quantity<R2, Rep2>>;
return make_quantity<ret::reference>(ret(lhs).numerical_value_ref_in(ret::unit) -
ret(rhs).numerical_value_ref_in(ret::unit));
return make_quantity<ret::reference>(ret(lhs).numerical_value_ - ret(rhs).numerical_value_);
}

template<auto R1, typename Rep1, auto R2, typename Rep2>
Expand All @@ -407,40 +389,39 @@ template<auto R1, typename Rep1, auto R2, typename Rep2>
{
gsl_ExpectsAudit(rhs != rhs.zero());
using ret = detail::common_quantity_for<std::modulus<>, quantity<R1, Rep1>, quantity<R2, Rep2>>;
return make_quantity<ret::reference>(ret(lhs).numerical_value_ref_in(ret::unit) %
ret(rhs).numerical_value_ref_in(ret::unit));
return make_quantity<ret::reference>(ret(lhs).numerical_value_ % ret(rhs).numerical_value_);
}

template<auto R1, typename Rep1, auto R2, typename Rep2>
requires detail::InvokeResultOf<(get_quantity_spec(R1) * get_quantity_spec(R2)).character, std::multiplies<>, Rep1,
Rep2>
[[nodiscard]] constexpr Quantity auto operator*(const quantity<R1, Rep1>& lhs, const quantity<R2, Rep2>& rhs)
{
return make_quantity<R1 * R2>(lhs.numerical_value_ref_in(get_unit(R1)) * rhs.numerical_value_ref_in(get_unit(R2)));
return make_quantity<R1 * R2>(lhs.numerical_value_ * rhs.numerical_value_);
}

template<auto R, typename Rep, typename Value>
requires(!Quantity<Value>) &&
detail::InvokeResultOf<get_quantity_spec(R).character, std::multiplies<>, Rep, const Value&>
[[nodiscard]] constexpr Quantity auto operator*(const quantity<R, Rep>& q, const Value& v)
{
return make_quantity<R>(q.numerical_value_ref_in(get_unit(R)) * v);
return make_quantity<R>(q.numerical_value_ * v);
}

template<typename Value, auto R, typename Rep>
requires(!Quantity<Value>) &&
detail::InvokeResultOf<get_quantity_spec(R).character, std::multiplies<>, const Value&, Rep>
[[nodiscard]] constexpr Quantity auto operator*(const Value& v, const quantity<R, Rep>& q)
{
return make_quantity<R>(v * q.numerical_value_ref_in(get_unit(R)));
return make_quantity<R>(v * q.numerical_value_);
}

template<auto R1, typename Rep1, auto R2, typename Rep2>
requires detail::InvokeResultOf<(get_quantity_spec(R1) / get_quantity_spec(R2)).character, std::divides<>, Rep1, Rep2>
[[nodiscard]] constexpr Quantity auto operator/(const quantity<R1, Rep1>& lhs, const quantity<R2, Rep2>& rhs)
{
gsl_ExpectsAudit(rhs != rhs.zero());
return make_quantity<R1 / R2>(lhs.numerical_value_ref_in(get_unit(R1)) / rhs.numerical_value_ref_in(get_unit(R2)));
return make_quantity<R1 / R2>(lhs.numerical_value_ / rhs.numerical_value_);
}

template<auto R, typename Rep, typename Value>
Expand All @@ -449,15 +430,15 @@ template<auto R, typename Rep, typename Value>
[[nodiscard]] constexpr Quantity auto operator/(const quantity<R, Rep>& q, const Value& v)
{
gsl_ExpectsAudit(v != quantity_values<Value>::zero());
return make_quantity<R>(q.numerical_value_ref_in(get_unit(R)) / v);
return make_quantity<R>(q.numerical_value_ / v);
}

template<typename Value, auto R, typename Rep>
requires(!Quantity<Value>) &&
detail::InvokeResultOf<get_quantity_spec(R).character, std::divides<>, const Value&, Rep>
[[nodiscard]] constexpr Quantity auto operator/(const Value& v, const quantity<R, Rep>& q)
{
return make_quantity<::mp_units::one / R>(v / q.numerical_value_ref_in(get_unit(R)));
return make_quantity<::mp_units::one / R>(v / q.numerical_value_);
}

template<auto R1, typename Rep1, auto R2, typename Rep2>
Expand All @@ -466,7 +447,7 @@ template<auto R1, typename Rep1, auto R2, typename Rep2>
[[nodiscard]] constexpr bool operator==(const quantity<R1, Rep1>& lhs, const quantity<R2, Rep2>& rhs)
{
using ct = std::common_type_t<quantity<R1, Rep1>, quantity<R2, Rep2>>;
return ct(lhs).numerical_value_ref_in(ct::unit) == ct(rhs).numerical_value_ref_in(ct::unit);
return ct(lhs).numerical_value_ == ct(rhs).numerical_value_;
}

template<auto R1, typename Rep1, auto R2, typename Rep2>
Expand All @@ -475,7 +456,7 @@ template<auto R1, typename Rep1, auto R2, typename Rep2>
[[nodiscard]] constexpr auto operator<=>(const quantity<R1, Rep1>& lhs, const quantity<R2, Rep2>& rhs)
{
using ct = std::common_type_t<quantity<R1, Rep1>, quantity<R2, Rep2>>;
return ct(lhs).numerical_value_ref_in(ct::unit) <=> ct(rhs).numerical_value_ref_in(ct::unit);
return ct(lhs).numerical_value_ <=> ct(rhs).numerical_value_;
}

// make_quantity
Expand Down
9 changes: 3 additions & 6 deletions src/core/include/mp-units/quantity_spec.h
Original file line number Diff line number Diff line change
Expand Up @@ -111,8 +111,7 @@ struct quantity_spec_interface {
requires Quantity<std::remove_cvref_t<Q>> &&
(explicitly_convertible(std::remove_reference_t<Q>::quantity_spec, self))
{
return make_quantity<reference<self, std::remove_cvref_t<Q>::unit>{}>(
std::forward<Q>(q).numerical_value_ref_in(q.unit));
return make_quantity<reference<self, std::remove_cvref_t<Q>::unit>{}>(std::forward<Q>(q).numerical_value_);
}
#else
template<typename Self_ = Self, UnitOf<Self_{}> U>
Expand All @@ -129,8 +128,7 @@ struct quantity_spec_interface {
(explicitly_convertible(std::remove_reference_t<Q>::quantity_spec, Self_{}))
[[nodiscard]] constexpr Quantity auto operator()(Q&& q) const
{
return make_quantity<reference<Self{}, std::remove_cvref_t<Q>::unit>{}>(
std::forward<Q>(q).numerical_value_ref_in(q.unit));
return make_quantity<reference<Self{}, std::remove_cvref_t<Q>::unit>{}>(std::forward<Q>(q).numerical_value_);
}
#endif
};
Expand Down Expand Up @@ -309,8 +307,7 @@ struct quantity_spec<Self, QS, Args...> : std::remove_const_t<decltype(QS)> {
(explicitly_convertible(std::remove_reference_t<Q>::quantity_spec, Self_{}))
[[nodiscard]] constexpr Quantity auto operator()(Q&& q) const
{
return make_quantity<reference<Self{}, std::remove_cvref_t<Q>::unit>{}>(
std::forward<Q>(q).numerical_value_ref_in(q.unit));
return make_quantity<reference<Self{}, std::remove_cvref_t<Q>::unit>{}>(std::forward<Q>(q).numerical_value_);
}
#endif
};
Expand Down
4 changes: 2 additions & 2 deletions test/unit_test/runtime/almost_equals.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ struct AlmostEqualsMatcher : Catch::Matchers::MatcherGenericBase {
{
using std::abs;
using common = std::common_type_t<T, U>;
const auto x = common(target_).numerical_value_ref_in(common::unit);
const auto y = common(other).numerical_value_ref_in(common::unit);
const auto x = common(target_).numerical_value_in(common::unit);
const auto y = common(other).numerical_value_in(common::unit);
const auto maxXYOne = std::max({typename T::rep{1}, abs(x), abs(y)});
return abs(x - y) <= std::numeric_limits<typename T::rep>::epsilon() * maxXYOne;
}
Expand Down
Loading

0 comments on commit 2e26eed

Please sign in to comment.