Skip to content

Commit 2d1bf8a

Browse files
committed
refactor: constraints refactoring
1 parent d441a90 commit 2d1bf8a

File tree

7 files changed

+185
-213
lines changed

7 files changed

+185
-213
lines changed

src/core/include/mp-units/framework/quantity.h

Lines changed: 109 additions & 116 deletions
Large diffs are not rendered by default.

src/core/include/mp-units/framework/quantity_point.h

Lines changed: 20 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -330,43 +330,44 @@ class quantity_point {
330330
}
331331

332332
// unit conversions
333-
template<detail::UnitCompatibleWith<unit, quantity_spec> ToU>
334-
requires detail::QuantityConvertibleTo<quantity_type, quantity<detail::make_reference(quantity_spec, ToU{}), Rep>>
333+
template<detail::WeakUnitOf<quantity_spec> ToU>
334+
requires detail::ValuePreservingScaling1Rep<unit, ToU{}, rep>
335335
[[nodiscard]] constexpr QuantityPointOf<quantity_spec> auto in(ToU) const
336336
{
337337
return ::mp_units::quantity_point{quantity_ref_from(point_origin).in(ToU{}), point_origin};
338338
}
339339

340340
template<RepresentationOf<quantity_spec> ToRep>
341-
requires detail::QuantityConvertibleTo<quantity_type, quantity<reference, ToRep>>
341+
requires detail::ValuePreservingConstruction<ToRep, rep>
342342
[[nodiscard]] constexpr QuantityPointOf<quantity_spec> auto in() const
343343
{
344344
return ::mp_units::quantity_point{quantity_ref_from(point_origin).template in<ToRep>(), point_origin};
345345
}
346346

347-
template<RepresentationOf<quantity_spec> ToRep, detail::UnitCompatibleWith<unit, quantity_spec> ToU>
348-
requires detail::QuantityConvertibleTo<quantity_type, quantity<detail::make_reference(quantity_spec, ToU{}), ToRep>>
347+
template<RepresentationOf<quantity_spec> ToRep, detail::WeakUnitOf<quantity_spec> ToU>
348+
requires detail::ValuePreservingConstruction<ToRep, rep> &&
349+
detail::ValuePreservingScaling2Reps<unit, rep, ToU{}, ToRep>
349350
[[nodiscard]] constexpr QuantityPointOf<quantity_spec> auto in(ToU) const
350351
{
351352
return ::mp_units::quantity_point{quantity_ref_from(point_origin).template in<ToRep>(ToU{}), point_origin};
352353
}
353354

354-
template<detail::UnitCompatibleWith<unit, quantity_spec> ToU>
355-
requires requires(const quantity_type q) { value_cast<ToU{}>(q); }
355+
template<detail::WeakUnitOf<quantity_spec> ToU>
356+
requires detail::SaneScaling<unit, ToU{}, rep>
356357
[[nodiscard]] constexpr QuantityPointOf<quantity_spec> auto force_in(ToU) const
357358
{
358359
return ::mp_units::quantity_point{quantity_ref_from(point_origin).force_in(ToU{}), point_origin};
359360
}
360361

361362
template<RepresentationOf<quantity_spec> ToRep>
362-
requires requires(const quantity_type q) { value_cast<ToRep>(q); }
363+
requires std::constructible_from<ToRep, rep>
363364
[[nodiscard]] constexpr QuantityPointOf<quantity_spec> auto force_in() const
364365
{
365366
return ::mp_units::quantity_point{quantity_ref_from(point_origin).template force_in<ToRep>(), point_origin};
366367
}
367368

368-
template<RepresentationOf<quantity_spec> ToRep, detail::UnitCompatibleWith<unit, quantity_spec> ToU>
369-
requires requires(const quantity_type q) { value_cast<ToU{}, ToRep>(q); }
369+
template<RepresentationOf<quantity_spec> ToRep, detail::WeakUnitOf<quantity_spec> ToU>
370+
requires std::constructible_from<ToRep, rep> && detail::SaneScaling<unit, ToU{}, rep>
370371
[[nodiscard]] constexpr QuantityPointOf<quantity_spec> auto force_in(ToU) const
371372
{
372373
return ::mp_units::quantity_point{quantity_ref_from(point_origin).template force_in<ToRep>(ToU{}), point_origin};
@@ -440,45 +441,41 @@ class quantity_point {
440441

441442
// compound assignment operators
442443
template<detail::Mutable<quantity_point> QP, auto R2, typename Rep2>
443-
requires detail::QuantityConvertibleTo<quantity<R2, Rep2>, quantity_type> &&
444-
requires(const quantity_type q) { quantity_from_origin_is_an_implementation_detail_ += q; }
444+
requires(implicitly_convertible(get_quantity_spec(R2), quantity_spec)) &&
445+
detail::ValuePreservingScaling2Reps<get_unit(R2), Rep2, unit, rep> &&
446+
requires(const quantity_type q) { quantity_from_origin_is_an_implementation_detail_ += q; }
445447
friend constexpr decltype(auto) operator+=(QP&& qp, const quantity<R2, Rep2>& q)
446448
{
447449
qp.quantity_from_origin_is_an_implementation_detail_ += q;
448450
return std::forward<QP>(qp);
449451
}
450452

451453
template<detail::Mutable<quantity_point> QP, auto R2, typename Rep2>
452-
requires detail::QuantityConvertibleTo<quantity<R2, Rep2>, quantity_type> &&
453-
requires(const quantity_type q) { quantity_from_origin_is_an_implementation_detail_ -= q; }
454+
requires(implicitly_convertible(get_quantity_spec(R2), quantity_spec)) &&
455+
detail::ValuePreservingScaling2Reps<get_unit(R2), Rep2, unit, rep> &&
456+
requires(const quantity_type q) { quantity_from_origin_is_an_implementation_detail_ -= q; }
454457
friend constexpr decltype(auto) operator-=(QP&& qp, const quantity<R2, Rep2>& q)
455458
{
456459
qp.quantity_from_origin_is_an_implementation_detail_ -= q;
457460
return std::forward<QP>(qp);
458461
}
459462

460463
// binary operators on quantity points
461-
template<std::derived_from<quantity_point> QP, auto R2, typename Rep2>
462-
// TODO simplify when gcc catches up
463-
requires ReferenceOf<MP_UNITS_REMOVE_CONST(decltype(R2)), PO._quantity_spec_>
464+
template<std::derived_from<quantity_point> QP, ReferenceOf<PO._quantity_spec_> auto R2, typename Rep2>
464465
[[nodiscard]] friend constexpr QuantityPoint auto operator+(const QP& qp, const quantity<R2, Rep2>& q)
465466
requires requires { qp.quantity_ref_from(PO) + q; }
466467
{
467468
return detail::make_quantity_point(qp.quantity_ref_from(PO) + q, PO);
468469
}
469470

470-
template<auto R1, typename Rep1, std::derived_from<quantity_point> QP>
471-
// TODO simplify when gcc catches up
472-
requires ReferenceOf<MP_UNITS_REMOVE_CONST(decltype(R1)), PO._quantity_spec_>
471+
template<ReferenceOf<PO._quantity_spec_> auto R1, typename Rep1, std::derived_from<quantity_point> QP>
473472
[[nodiscard]] friend constexpr QuantityPoint auto operator+(const quantity<R1, Rep1>& q, const QP& qp)
474473
requires requires { q + qp.quantity_ref_from(PO); }
475474
{
476475
return qp + q;
477476
}
478477

479-
template<std::derived_from<quantity_point> QP, auto R2, typename Rep2>
480-
// TODO simplify when gcc catches up
481-
requires ReferenceOf<MP_UNITS_REMOVE_CONST(decltype(R2)), PO._quantity_spec_>
478+
template<std::derived_from<quantity_point> QP, ReferenceOf<PO._quantity_spec_> auto R2, typename Rep2>
482479
[[nodiscard]] friend constexpr QuantityPoint auto operator-(const QP& qp, const quantity<R2, Rep2>& q)
483480
requires requires { qp.quantity_ref_from(PO) - q; }
484481
{

src/core/include/mp-units/framework/system_reference.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,7 @@ struct system_reference {
6565
static constexpr auto quantity_spec = Q;
6666
static constexpr auto coherent_unit = CoU;
6767

68-
template<Unit U>
69-
requires(interconvertible(coherent_unit, U{}))
68+
template<detail::UnitConvertibleTo<coherent_unit> U>
7069
#if MP_UNITS_COMP_MSVC
7170
[[nodiscard]] constexpr decltype(reference<MP_UNITS_REMOVE_CONST(decltype(Q)), U>{}) operator[](U) const
7271
#else

src/core/include/mp-units/framework/unit.h

Lines changed: 5 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -124,27 +124,6 @@ constexpr auto get_canonical_unit_result = get_canonical_unit_impl(U{}, U{});
124124
// Even though it is not exported, it is visible to the other module via ADL
125125
[[nodiscard]] consteval auto get_canonical_unit(Unit auto u) { return detail::get_canonical_unit_result<decltype(u)>; }
126126

127-
namespace detail {
128-
129-
// We are using a helper concept to benefit from short-circuiting
130-
template<typename U1, typename U2>
131-
concept PotentiallyInterConvertibleTo = Unit<U1> && Unit<U2> &&
132-
(!AssociatedUnit<U1> || !AssociatedUnit<U2> ||
133-
explicitly_convertible(get_quantity_spec(U1{}), get_quantity_spec(U2{})));
134-
} // namespace detail
135-
136-
// interconvertible
137-
template<Unit U1, Unit U2>
138-
[[nodiscard]] consteval bool interconvertible(U1 u1, U2 u2)
139-
{
140-
if constexpr (is_same_v<U1, U2>)
141-
return true;
142-
else if constexpr (detail::PotentiallyInterConvertibleTo<U1, U2>)
143-
return is_same_v<decltype(get_canonical_unit(u1).reference_unit), decltype(get_canonical_unit(u2).reference_unit)>;
144-
else
145-
return false;
146-
}
147-
148127
template<UnitMagnitude auto M, Unit U>
149128
requires(M != detail::unit_magnitude<>{} && M != mag<1>)
150129
struct scaled_unit;
@@ -427,8 +406,7 @@ struct prefixed_unit : decltype(M * U)::_base_type_ {
427406

428407
namespace detail {
429408

430-
template<Unit U1, Unit U2>
431-
requires(interconvertible(U1{}, U2{}))
409+
template<Unit U1, UnitConvertibleTo<U1{}> U2>
432410
[[nodiscard]] consteval Unit auto get_common_scaled_unit(U1, U2)
433411
{
434412
constexpr auto canonical_lhs = get_canonical_unit(U1{});
@@ -671,8 +649,7 @@ inline constexpr auto ppm = parts_per_million;
671649
// Common unit
672650
[[nodiscard]] consteval Unit auto get_common_unit(Unit auto u) { return u; }
673651

674-
template<Unit U1, Unit U2>
675-
requires(interconvertible(U1{}, U2{}))
652+
template<Unit U1, detail::UnitConvertibleTo<U1{}> U2>
676653
[[nodiscard]] consteval Unit auto get_common_unit(U1 u1, U2 u2)
677654
{
678655
if constexpr (is_same_v<U1, U2>)
@@ -732,8 +709,7 @@ using collapse_common_unit = type_list_unique<
732709

733710
} // namespace detail
734711

735-
template<Unit... Us, Unit NewUnit>
736-
requires(interconvertible(common_unit<Us...>{}, NewUnit{}))
712+
template<Unit... Us, detail::UnitConvertibleTo<common_unit<Us...>{}> NewUnit>
737713
[[nodiscard]] consteval Unit auto get_common_unit(common_unit<Us...>, NewUnit)
738714
{
739715
using type = detail::collapse_common_unit<NewUnit, Us...>;
@@ -743,15 +719,14 @@ template<Unit... Us, Unit NewUnit>
743719
return detail::type_list_map<type, common_unit>{};
744720
}
745721

746-
template<Unit... Us, Unit NewUnit>
747-
requires(interconvertible(common_unit<Us...>{}, NewUnit{}))
722+
template<Unit... Us, detail::UnitConvertibleTo<common_unit<Us...>{}> NewUnit>
748723
[[nodiscard]] consteval Unit auto get_common_unit(NewUnit nu, common_unit<Us...> cu)
749724
{
750725
return get_common_unit(cu, nu);
751726
}
752727

753728
template<Unit Front, Unit... Rest, Unit... Us>
754-
requires(interconvertible(common_unit<Front, Rest...>{}, common_unit<Us...>{}))
729+
requires(detail::UnitConvertibleTo<common_unit<Front, Rest...>, common_unit<Us...>{}>)
755730
[[nodiscard]] consteval Unit auto get_common_unit(common_unit<Front, Rest...>, common_unit<Us...>)
756731
{
757732
if constexpr (sizeof...(Rest) == 1)

src/core/include/mp-units/framework/unit_concepts.h

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -100,25 +100,27 @@ MP_UNITS_EXPORT template<typename U, auto QS>
100100
concept UnitOf = AssociatedUnit<U> && QuantitySpec<MP_UNITS_REMOVE_CONST(decltype(QS))> &&
101101
(implicitly_convertible(get_quantity_spec(U{}), QS));
102102

103-
MP_UNITS_EXPORT template<Unit U1, Unit U2>
104-
[[nodiscard]] consteval bool interconvertible(U1 u1, U2 u2);
105-
106103
namespace detail {
107104

105+
template<typename U, auto QS>
106+
concept UnitOf = UnitOf<U, QS>;
107+
108108
template<typename U, auto QS>
109109
concept WeakUnitOf =
110110
Unit<U> && QuantitySpec<MP_UNITS_REMOVE_CONST(decltype(QS))> && ((!AssociatedUnit<U>) || UnitOf<U, QS>);
111111

112-
/**
113-
* @brief A concept matching all units compatible with the provided unit and quantity spec
114-
*
115-
* Satisfied by all units that have the same canonical reference as `U2` and in case they
116-
* have associated quantity specification it should satisfy `UnitOf<QS>`.
117-
*/
118-
template<typename U, auto FromU, auto QS>
119-
concept UnitCompatibleWith =
120-
Unit<U> && Unit<MP_UNITS_REMOVE_CONST(decltype(FromU))> && QuantitySpec<MP_UNITS_REMOVE_CONST(decltype(QS))> &&
121-
WeakUnitOf<U, QS> && (interconvertible(FromU, U{}));
112+
template<auto U1, auto U2>
113+
concept UnitsOfCompatibleQuantities = explicitly_convertible(get_quantity_spec(U1), get_quantity_spec(U2));
114+
115+
template<auto U1, auto U2>
116+
concept ConvertibleUnits = (get_canonical_unit(U1).reference_unit == get_canonical_unit(U2).reference_unit);
117+
118+
template<typename U1, auto U2>
119+
concept UnitConvertibleTo =
120+
Unit<U1> && Unit<MP_UNITS_REMOVE_CONST(decltype(U2))> &&
121+
((U1{} == U2) || ((!AssociatedUnit<U1> || !AssociatedUnit<MP_UNITS_REMOVE_CONST(decltype(U2))> ||
122+
UnitsOfCompatibleQuantities<U1{}, U2>) &&
123+
ConvertibleUnits<U1{}, U2>));
122124

123125
template<typename T>
124126
concept OffsetUnit = Unit<T> && requires { T::_point_origin_; };

0 commit comments

Comments
 (0)