Skip to content

Commit

Permalink
feat: 💥 RepresentationOf concept now also accepts a QuantitySpec
Browse files Browse the repository at this point in the history
…and accepts any representation character for quantity kinds
  • Loading branch information
mpusz committed Nov 7, 2024
1 parent 75b50b8 commit da50348
Show file tree
Hide file tree
Showing 14 changed files with 88 additions and 76 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ As we remember, the `quantity` class template is defined as follows:

```cpp
template<Reference auto R,
RepresentationOf<get_quantity_spec(R).character> Rep = double>
RepresentationOf<get_quantity_spec(R)> Rep = double>
class quantity;
```

Expand Down
19 changes: 16 additions & 3 deletions docs/users_guide/framework_basics/concepts.md
Original file line number Diff line number Diff line change
Expand Up @@ -159,15 +159,28 @@ A `Reference` can either be:
[value of a quantity](../../appendix/glossary.md#quantity-value).


### `RepresentationOf<T, Ch>` { #RepresentationOf }
### `RepresentationOf<T, V>` { #RepresentationOf }

`RepresentationOf` concept is satisfied by all `Representation` types that are of a specified
[quantity character](../../appendix/glossary.md#character) `Ch`.
`RepresentationOf` concept is satisfied:

- if the type of `V` satisfies [`QuantitySpec`](#QuantitySpec):

- by all [`Representation`](#Representation) types when `V` describes
a [quantity kind](../../appendix/glossary.md#kind),
- otherwise, by [`Representation`](#Representation) types that are of
a [quantity character](../../appendix/glossary.md#character) associated with a provided
quantity specification `V`.

- if `V` is of `quantity_character` type:

- by [`Representation`](#Representation) types that are of a provided
[quantity character](../../appendix/glossary.md#character).

A user can declare a custom representation type to be of a specific character by providing the specialization
with `true` for one or more of the following variable templates:

- `is_scalar<T>`
- `is_complex<T>`
- `is_vector<T>`
- `is_tensor<T>`

Expand Down
4 changes: 2 additions & 2 deletions docs/users_guide/framework_basics/design_overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,7 @@ This is why a `quantity` class template is defined in the library as:

```cpp
template<Reference auto R,
RepresentationOf<get_quantity_spec(R).character> Rep = double>
RepresentationOf<get_quantity_spec(R)> Rep = double>
class quantity;
```

Expand Down Expand Up @@ -365,7 +365,7 @@ In the **mp-units** library, the quantity point is implemented as:
```cpp
template<Reference auto R,
PointOriginFor<get_quantity_spec(R)> auto PO,
RepresentationOf<get_quantity_spec(R).character> Rep = double>
RepresentationOf<get_quantity_spec(R)> Rep = double>
class quantity_point;
```

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ In the **mp-units** library, a quantity is represented with the following class

```cpp
template<Reference auto R,
RepresentationOf<get_quantity_spec(R).character> Rep = double>
RepresentationOf<get_quantity_spec(R)> Rep = double>
class quantity;
```

Expand Down
2 changes: 1 addition & 1 deletion docs/users_guide/framework_basics/the_affine_space.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ origin:
```cpp
template<Reference auto R,
PointOriginFor<get_quantity_spec(R)> auto PO = default_point_origin(R),
RepresentationOf<get_quantity_spec(R).character> Rep = double>
RepresentationOf<get_quantity_spec(R)> Rep = double>
class quantity_point;
```

Expand Down
4 changes: 2 additions & 2 deletions src/core/include/mp-units/framework/construction_helpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ namespace mp_units {

template<Reference R>
struct delta_ {
template<typename FwdRep, RepresentationOf<get_quantity_spec(R{}).character> Rep = std::remove_cvref_t<FwdRep>>
template<typename FwdRep, RepresentationOf<get_quantity_spec(R{})> Rep = std::remove_cvref_t<FwdRep>>
[[nodiscard]] constexpr quantity<MP_UNITS_EXPRESSION_WORKAROUND(R{}), Rep> operator()(FwdRep&& lhs) const
{
return quantity{std::forward<FwdRep>(lhs), R{}};
Expand All @@ -48,7 +48,7 @@ struct delta_ {

template<Reference R>
struct absolute_ {
template<typename FwdRep, RepresentationOf<get_quantity_spec(R{}).character> Rep = std::remove_cvref_t<FwdRep>>
template<typename FwdRep, RepresentationOf<get_quantity_spec(R{})> Rep = std::remove_cvref_t<FwdRep>>
[[nodiscard]] constexpr quantity_point<MP_UNITS_EXPRESSION_WORKAROUND(R{}), default_point_origin(R{}), Rep>
operator()(FwdRep&& lhs) const
{
Expand Down
78 changes: 38 additions & 40 deletions src/core/include/mp-units/framework/quantity.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,14 +78,15 @@ concept QuantityConvertibleTo =
// deduced thus the function is evaluated here and may emit truncating conversion or other warnings)
requires(QFrom q) { sudo_cast<QTo>(q); };

template<quantity_character Ch, typename Func, typename T, typename U>
concept InvokeResultOf = std::regular_invocable<Func, T, U> && RepresentationOf<std::invoke_result_t<Func, T, U>, Ch>;
template<auto QS, typename Func, typename T, typename U>
concept InvokeResultOf = QuantitySpec<MP_UNITS_REMOVE_CONST(decltype(QS))> && std::regular_invocable<Func, T, U> &&
RepresentationOf<std::invoke_result_t<Func, T, U>, QS>;

template<typename Func, typename Q1, typename Q2,
quantity_character Ch = std::invoke_result_t<Func, std::remove_const_t<decltype(Q1::quantity_spec)>,
std::remove_const_t<decltype(Q2::quantity_spec)>>::character>
concept InvocableQuantities =
Quantity<Q1> && Quantity<Q2> && InvokeResultOf<Ch, Func, typename Q1::rep, typename Q2::rep>;
auto QS = std::invoke_result_t<Func, std::remove_const_t<decltype(Q1::quantity_spec)>,
std::remove_const_t<decltype(Q2::quantity_spec)>>{}>
concept InvocableQuantities = QuantitySpec<MP_UNITS_REMOVE_CONST(decltype(QS))> && Quantity<Q1> && Quantity<Q2> &&
InvokeResultOf<QS, Func, typename Q1::rep, typename Q2::rep>;

// TODO remove the following when clang diagnostics improve
// https://github.com/llvm/llvm-project/issues/96660
Expand All @@ -104,7 +105,7 @@ concept CommonlyInvocableQuantities =
Quantity<Q1> && Quantity<Q2> && HaveCommonReference<Q1::reference, Q2::reference> &&
std::convertible_to<Q1, common_quantity_for<Func, Q1, Q2>> &&
std::convertible_to<Q2, common_quantity_for<Func, Q1, Q2>> &&
InvocableQuantities<Func, Q1, Q2, get_common_quantity_spec(Q1::quantity_spec, Q2::quantity_spec).character>;
InvocableQuantities<Func, Q1, Q2, get_common_quantity_spec(Q1::quantity_spec, Q2::quantity_spec)>;

template<auto R1, auto R2, typename Rep1, typename Rep2>
concept SameValueAs = (equivalent(get_unit(R1), get_unit(R2))) && std::convertible_to<Rep1, Rep2>;
Expand All @@ -128,7 +129,7 @@ MP_UNITS_EXPORT_BEGIN
* @tparam R a reference of the quantity providing all information about quantity properties
* @tparam Rep a type to be used to represent values of a quantity
*/
template<Reference auto R, RepresentationOf<get_quantity_spec(R).character> Rep = double>
template<Reference auto R, RepresentationOf<get_quantity_spec(R)> Rep = double>
class quantity {
public:
Rep numerical_value_is_an_implementation_detail_; ///< needs to be public for a structural type
Expand Down Expand Up @@ -227,14 +228,14 @@ class quantity {
return quantity<detail::make_reference(quantity_spec, ToU{}), Rep>{*this};
}

template<RepresentationOf<quantity_spec.character> ToRep>
template<RepresentationOf<quantity_spec> ToRep>
requires detail::QuantityConvertibleTo<quantity, quantity<reference, ToRep>>
[[nodiscard]] constexpr QuantityOf<quantity_spec> auto in() const
{
return quantity<reference, ToRep>{*this};
}

template<RepresentationOf<quantity_spec.character> ToRep, detail::UnitCompatibleWith<unit, quantity_spec> ToU>
template<RepresentationOf<quantity_spec> ToRep, detail::UnitCompatibleWith<unit, quantity_spec> ToU>
requires detail::QuantityConvertibleTo<quantity, quantity<detail::make_reference(quantity_spec, ToU{}), ToRep>>
[[nodiscard]] constexpr QuantityOf<quantity_spec> auto in(ToU) const
{
Expand All @@ -248,14 +249,14 @@ class quantity {
return value_cast<ToU{}>(*this);
}

template<RepresentationOf<quantity_spec.character> ToRep>
template<RepresentationOf<quantity_spec> ToRep>
requires requires(quantity q) { value_cast<ToRep>(q); }
[[nodiscard]] constexpr QuantityOf<quantity_spec> auto force_in() const
{
return value_cast<ToRep>(*this);
}

template<RepresentationOf<quantity_spec.character> ToRep, detail::UnitCompatibleWith<unit, quantity_spec> ToU>
template<RepresentationOf<quantity_spec> ToRep, detail::UnitCompatibleWith<unit, quantity_spec> ToU>
requires requires(quantity q) { value_cast<ToU{}, ToRep>(q); }
[[nodiscard]] constexpr QuantityOf<quantity_spec> auto force_in(ToU) const
{
Expand Down Expand Up @@ -474,17 +475,15 @@ class quantity {
ret::reference};
}

template<std::derived_from<quantity> Q, RepresentationOf<quantity_character::scalar> Value>
requires(Q::unit == ::mp_units::one) &&
detail::InvokeResultOf<quantity_character::scalar, std::plus<>, Rep, const Value&>
template<std::derived_from<quantity> Q, Representation Value>
requires(Q::unit == ::mp_units::one) && detail::InvokeResultOf<quantity_spec, std::plus<>, Rep, const Value&>
[[nodiscard]] friend constexpr Quantity auto operator+(const Q& lhs, const Value& rhs)
{
return lhs + ::mp_units::quantity{rhs};
}

template<std::derived_from<quantity> Q, RepresentationOf<quantity_character::scalar> Value>
requires(Q::unit == ::mp_units::one) &&
detail::InvokeResultOf<quantity_character::scalar, std::plus<>, Rep, const Value&>
template<std::derived_from<quantity> Q, Representation Value>
requires(Q::unit == ::mp_units::one) && detail::InvokeResultOf<quantity_spec, std::plus<>, Rep, const Value&>
[[nodiscard]] friend constexpr Quantity auto operator+(const Value& lhs, const Q& rhs)
{
return ::mp_units::quantity{lhs} + rhs;
Expand All @@ -501,17 +500,15 @@ class quantity {
ret::reference};
}

template<std::derived_from<quantity> Q, RepresentationOf<quantity_character::scalar> Value>
requires(Q::unit == ::mp_units::one) &&
detail::InvokeResultOf<quantity_character::scalar, std::minus<>, Rep, const Value&>
template<std::derived_from<quantity> Q, Representation Value>
requires(Q::unit == ::mp_units::one) && detail::InvokeResultOf<quantity_spec, std::minus<>, Rep, const Value&>
[[nodiscard]] friend constexpr Quantity auto operator-(const Q& lhs, const Value& rhs)
{
return lhs - ::mp_units::quantity{rhs};
}

template<std::derived_from<quantity> Q, RepresentationOf<quantity_character::scalar> Value>
requires(Q::unit == ::mp_units::one) &&
detail::InvokeResultOf<quantity_character::scalar, std::minus<>, Rep, const Value&>
template<std::derived_from<quantity> Q, Representation Value>
requires(Q::unit == ::mp_units::one) && detail::InvokeResultOf<quantity_spec, std::minus<>, Rep, const Value&>
[[nodiscard]] friend constexpr Quantity auto operator-(const Value& lhs, const Q& rhs)
{
return ::mp_units::quantity{lhs} - rhs;
Expand All @@ -530,17 +527,15 @@ class quantity {
ret::reference};
}

template<std::derived_from<quantity> Q, RepresentationOf<quantity_character::scalar> Value>
requires(Q::unit == ::mp_units::one) &&
detail::InvokeResultOf<quantity_character::scalar, std::modulus<>, Rep, const Value&>
template<std::derived_from<quantity> Q, Representation Value>
requires(Q::unit == ::mp_units::one) && detail::InvokeResultOf<quantity_spec, std::modulus<>, Rep, const Value&>
[[nodiscard]] friend constexpr Quantity auto operator%(const Q& lhs, const Value& rhs)
{
return lhs % ::mp_units::quantity{rhs};
}

template<std::derived_from<quantity> Q, RepresentationOf<quantity_character::scalar> Value>
requires(Q::unit == ::mp_units::one) &&
detail::InvokeResultOf<quantity_character::scalar, std::modulus<>, Rep, const Value&>
template<std::derived_from<quantity> Q, Representation Value>
requires(Q::unit == ::mp_units::one) && detail::InvokeResultOf<quantity_spec, std::modulus<>, Rep, const Value&>
[[nodiscard]] friend constexpr Quantity auto operator%(const Value& lhs, const Q& rhs)
{
return ::mp_units::quantity{lhs} % rhs;
Expand All @@ -555,15 +550,15 @@ class quantity {

template<std::derived_from<quantity> Q, typename Value>
requires(!Quantity<Value>) &&
(!Reference<Value>) && detail::InvokeResultOf<quantity_spec.character, std::multiplies<>, Rep, const Value&>
(!Reference<Value>) && detail::InvokeResultOf<quantity_spec, std::multiplies<>, Rep, const Value&>
[[nodiscard]] friend constexpr QuantityOf<quantity_spec> auto operator*(const Q& q, const Value& v)
{
return ::mp_units::quantity{q.numerical_value_ref_in(unit) * v, R};
}

template<typename Value, std::derived_from<quantity> Q>
requires(!Quantity<Value>) &&
(!Reference<Value>) && detail::InvokeResultOf<quantity_spec.character, std::multiplies<>, const Value&, Rep>
(!Reference<Value>) && detail::InvokeResultOf<quantity_spec, std::multiplies<>, const Value&, Rep>
[[nodiscard]] friend constexpr QuantityOf<quantity_spec> auto operator*(const Value& v, const Q& q)
{
return ::mp_units::quantity{v * q.numerical_value_ref_in(unit), R};
Expand All @@ -579,7 +574,7 @@ class quantity {

template<std::derived_from<quantity> Q, typename Value>
requires(!Quantity<Value>) &&
(!Reference<Value>) && detail::InvokeResultOf<quantity_spec.character, std::divides<>, Rep, const Value&>
(!Reference<Value>) && detail::InvokeResultOf<quantity_spec, std::divides<>, Rep, const Value&>
[[nodiscard]] friend constexpr QuantityOf<quantity_spec> auto operator/(const Q& q, const Value& v)
{
MP_UNITS_EXPECTS_DEBUG(v != quantity_values<Value>::zero());
Expand All @@ -588,7 +583,7 @@ class quantity {

template<typename Value, std::derived_from<quantity> Q>
requires(!Quantity<Value>) &&
(!Reference<Value>) && detail::InvokeResultOf<quantity_spec.character, std::divides<>, const Value&, Rep>
(!Reference<Value>) && detail::InvokeResultOf<quantity_spec, std::divides<>, const Value&, Rep>
[[nodiscard]] friend constexpr QuantityOf<inverse(quantity_spec)> auto operator/(const Value& v, const Q& q)
{
return ::mp_units::quantity{v / q.numerical_value_ref_in(unit), ::mp_units::one / R};
Expand All @@ -605,7 +600,7 @@ class quantity {
return ct_lhs.numerical_value_ref_in(ct::unit) == ct_rhs.numerical_value_ref_in(ct::unit);
}

template<std::derived_from<quantity> Q, RepresentationOf<quantity_character::scalar> Value>
template<std::derived_from<quantity> Q, Representation Value>
requires(Q::unit == ::mp_units::one) && std::equality_comparable_with<Rep, Value>
[[nodiscard]] friend constexpr bool operator==(const Q& lhs, const Value& rhs)
{
Expand All @@ -623,7 +618,7 @@ class quantity {
return ct_lhs.numerical_value_ref_in(ct::unit) <=> ct_rhs.numerical_value_ref_in(ct::unit);
}

template<std::derived_from<quantity> Q, RepresentationOf<quantity_character::scalar> Value>
template<std::derived_from<quantity> Q, Representation Value>
requires(Q::unit == ::mp_units::one) && std::three_way_comparable_with<Rep, Value>
[[nodiscard]] friend constexpr auto operator<=>(const Q& lhs, const Value& rhs)
{
Expand All @@ -650,18 +645,21 @@ template<mp_units::Quantity Q1, mp_units::Quantity Q2>
requires requires {
{ mp_units::get_common_reference(Q1::reference, Q2::reference) } -> mp_units::Reference;
typename std::common_type_t<typename Q1::rep, typename Q2::rep>;
requires mp_units::RepresentationOf<std::common_type_t<typename Q1::rep, typename Q2::rep>,
mp_units::get_common_quantity_spec(Q1::quantity_spec, Q2::quantity_spec)>;
}
struct std::common_type<Q1, Q2> {
using type = mp_units::quantity<mp_units::get_common_reference(Q1::reference, Q2::reference),
std::common_type_t<typename Q1::rep, typename Q2::rep>>;
};

template<mp_units::Quantity Q, mp_units::RepresentationOf<mp_units::quantity_character::scalar> Value>
requires(Q::unit == mp_units::one) && requires { typename std::common_type_t<typename Q::rep, Value>; }
template<mp_units::Quantity Q, mp_units::Representation Value>
requires(Q::unit == mp_units::one) &&
requires { typename mp_units::quantity<Q::reference, std::common_type_t<typename Q::rep, Value>>; }
struct std::common_type<Q, Value> {
using type = mp_units::quantity<Q::reference, std::common_type_t<typename Q::rep, Value>>;
};

template<mp_units::Quantity Q, mp_units::RepresentationOf<mp_units::quantity_character::scalar> Value>
requires(Q::unit == mp_units::one) && requires { typename std::common_type_t<typename Q::rep, Value>; }
template<mp_units::Quantity Q, mp_units::Representation Value>
requires requires { typename std::common_type<Q, Value>; }
struct std::common_type<Value, Q> : std::common_type<Q, Value> {};
2 changes: 1 addition & 1 deletion src/core/include/mp-units/framework/quantity_concepts.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@

namespace mp_units {

MP_UNITS_EXPORT template<Reference auto R, RepresentationOf<get_quantity_spec(R).character> Rep>
MP_UNITS_EXPORT template<Reference auto R, RepresentationOf<get_quantity_spec(R)> Rep>
class quantity;

namespace detail {
Expand Down
10 changes: 5 additions & 5 deletions src/core/include/mp-units/framework/quantity_point.h
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ template<PointOrigin PO>
* @tparam Rep a type to be used to represent values of a quantity point
*/
MP_UNITS_EXPORT template<Reference auto R, PointOriginFor<get_quantity_spec(R)> auto PO = default_point_origin(R),
RepresentationOf<get_quantity_spec(R).character> Rep = double>
RepresentationOf<get_quantity_spec(R)> Rep = double>
class quantity_point {
public:
// member types and values
Expand Down Expand Up @@ -329,14 +329,14 @@ class quantity_point {
return ::mp_units::quantity_point{quantity_ref_from(point_origin).in(ToU{}), point_origin};
}

template<RepresentationOf<quantity_spec.character> ToRep>
template<RepresentationOf<quantity_spec> ToRep>
requires detail::QuantityConvertibleTo<quantity_type, quantity<reference, ToRep>>
[[nodiscard]] constexpr QuantityPointOf<quantity_spec> auto in() const
{
return ::mp_units::quantity_point{quantity_ref_from(point_origin).template in<ToRep>(), point_origin};
}

template<RepresentationOf<quantity_spec.character> ToRep, detail::UnitCompatibleWith<unit, quantity_spec> ToU>
template<RepresentationOf<quantity_spec> ToRep, detail::UnitCompatibleWith<unit, quantity_spec> ToU>
requires detail::QuantityConvertibleTo<quantity_type, quantity<detail::make_reference(quantity_spec, ToU{}), ToRep>>
[[nodiscard]] constexpr QuantityPointOf<quantity_spec> auto in(ToU) const
{
Expand All @@ -350,14 +350,14 @@ class quantity_point {
return ::mp_units::quantity_point{quantity_ref_from(point_origin).force_in(ToU{}), point_origin};
}

template<RepresentationOf<quantity_spec.character> ToRep>
template<RepresentationOf<quantity_spec> ToRep>
requires requires(quantity_type q) { value_cast<ToRep>(q); }
[[nodiscard]] constexpr QuantityPointOf<quantity_spec> auto force_in() const
{
return ::mp_units::quantity_point{quantity_ref_from(point_origin).template force_in<ToRep>(), point_origin};
}

template<RepresentationOf<quantity_spec.character> ToRep, detail::UnitCompatibleWith<unit, quantity_spec> ToU>
template<RepresentationOf<quantity_spec> ToRep, detail::UnitCompatibleWith<unit, quantity_spec> ToU>
requires requires(quantity_type q) { value_cast<ToU{}, ToRep>(q); }
[[nodiscard]] constexpr QuantityPointOf<quantity_spec> auto force_in(ToU) const
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ MP_UNITS_EXPORT template<typename T, auto QS>
concept PointOriginFor = PointOrigin<T> && QuantitySpecOf<MP_UNITS_REMOVE_CONST(decltype(QS)), T::_quantity_spec_>;

MP_UNITS_EXPORT template<Reference auto R, PointOriginFor<get_quantity_spec(R)> auto PO,
RepresentationOf<get_quantity_spec(R).character> Rep>
RepresentationOf<get_quantity_spec(R)> Rep>
class quantity_point;

namespace detail {
Expand Down
Loading

0 comments on commit da50348

Please sign in to comment.