feat: relative_point_origin support added

Relates to #414
This commit is contained in:
Mateusz Pusz
2023-08-01 17:24:01 +02:00
parent c12bf20703
commit b19bf0761c
4 changed files with 90 additions and 32 deletions

View File

@ -60,22 +60,44 @@ inline constexpr bool is_derived_from_specialization_of_absolute_point_origin =
template<typename T>
concept QuantityPoint = detail::is_quantity_point<T>;
template<QuantityPoint auto QP>
struct relative_point_origin;
namespace detail {
template<typename T>
inline constexpr bool is_specialization_of_relative_point_origin = false;
template<auto QP>
inline constexpr bool is_specialization_of_relative_point_origin<relative_point_origin<QP>> = true;
template<auto QP>
void to_base_specialization_of_relative_point_origin(const volatile relative_point_origin<QP>*);
template<typename T>
inline constexpr bool is_derived_from_specialization_of_relative_point_origin =
requires(T* t) { to_base_specialization_of_relative_point_origin(t); };
} // namespace detail
/**
* @brief A concept matching all quantity point origins in the library
*
* Satisfied by either quantity points or by all types derived from `absolute_point_origin` class template.
*/
template<typename T>
concept PointOrigin = QuantityPoint<T> || detail::is_derived_from_specialization_of_absolute_point_origin<T>;
concept PointOrigin = detail::is_derived_from_specialization_of_absolute_point_origin<T> ||
(detail::is_derived_from_specialization_of_relative_point_origin<T> &&
!detail::is_specialization_of_relative_point_origin<T>);
/**
* @brief A concept matching all quantity point origins for a specified quantity type in the library
*
* Satisfied by all quantity point origins that are defined using a provided quantity specification.
*/
template<typename T, auto Q>
template<typename T, auto QS>
concept PointOriginFor =
PointOrigin<T> && QuantitySpec<std::remove_const_t<decltype(Q)>> && implicitly_convertible(Q, T::quantity_spec);
PointOrigin<T> && QuantitySpec<std::remove_const_t<decltype(QS)>> && implicitly_convertible(QS, T::quantity_spec);
template<Reference auto R, PointOriginFor<get_quantity_spec(R)> auto PO,
RepresentationOf<get_quantity_spec(R).character> Rep>
@ -108,7 +130,8 @@ 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::absolute_point_origin)>, 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) &&

View File

@ -34,12 +34,18 @@ struct absolute_point_origin {
static constexpr QuantitySpec auto quantity_spec = Q;
};
template<QuantityPoint auto QP>
struct relative_point_origin {
static constexpr QuantityPoint auto parent_origin = QP;
static constexpr QuantitySpec auto quantity_spec = QP.quantity_spec;
};
namespace detail {
[[nodiscard]] consteval PointOrigin auto get_absolute_point_origin(PointOrigin auto po)
{
if constexpr (requires { po.absolute_point_origin; })
return po.absolute_point_origin;
if constexpr (requires { po.parent_origin.absolute_point_origin; })
return po.parent_origin.absolute_point_origin;
else
return po;
}
@ -145,7 +151,7 @@ public:
std::remove_const_t<decltype(point_origin)>>)
return relative();
else
return point_origin.absolute() + relative();
return point_origin.parent_origin.absolute() + relative();
}
template<Unit U>

View File

@ -360,15 +360,20 @@ static_assert(!QuantityLike<int>);
// QuantityPoint
inline constexpr struct my_origin : absolute_point_origin<isq::length> {
} my_origin;
inline constexpr struct my_relative_origin :
relative_point_origin<quantity_point<isq::length[si::metre]>{42 * si::metre}> {
} my_relative_origin;
static_assert(QuantityPoint<quantity_point<si::metre>>);
static_assert(QuantityPoint<quantity_point<isq::length[si::metre]>>);
static_assert(QuantityPoint<quantity_point<isq::length[si::metre], absolute_point_origin<isq::length>{}, int>>);
static_assert(QuantityPoint<quantity_point<isq::radius[si::metre], absolute_point_origin<isq::length>{}, int>>);
static_assert(QuantityPoint<quantity_point<isq::radius[si::metre], my_origin>>);
static_assert(QuantityPoint<quantity_point<isq::radius[si::metre], my_relative_origin>>);
static_assert(!QuantityPoint<std::remove_const_t<decltype(isq::length[si::metre])>>);
static_assert(!QuantityPoint<absolute_point_origin<isq::length>>);
static_assert(!QuantityPoint<struct my_origin>);
static_assert(!QuantityPoint<struct my_relative_origin>);
static_assert(!QuantityPoint<std::chrono::seconds>);
static_assert(!QuantityPoint<std::chrono::time_point<std::chrono::system_clock>>);
static_assert(!QuantityPoint<int>);
@ -390,28 +395,41 @@ static_assert(
QuantityPointOf<quantity_point<isq::radius[si::metre], absolute_point_origin<isq::length>{}, int>, isq::radius>);
static_assert(QuantityPointOf<quantity_point<isq::radius[si::metre], my_origin>, isq::length>);
static_assert(QuantityPointOf<quantity_point<isq::radius[si::metre], my_origin>, isq::radius>);
static_assert(QuantityPointOf<quantity_point<isq::radius[si::metre], my_relative_origin>, isq::length>);
static_assert(QuantityPointOf<quantity_point<isq::radius[si::metre], my_relative_origin>, isq::radius>);
static_assert(QuantityPointOf<quantity_point<si::metre>, absolute_point_origin<isq::length>{}>);
static_assert(QuantityPointOf<quantity_point<si::metre>, absolute_point_origin<isq::radius>{}>);
static_assert(QuantityPointOf<quantity_point<si::metre>, my_origin>);
static_assert(!QuantityPointOf<quantity_point<si::metre>, my_origin>);
static_assert(!QuantityPointOf<quantity_point<si::metre>, my_relative_origin>);
static_assert(QuantityPointOf<quantity_point<isq::length[si::metre]>, absolute_point_origin<isq::length>{}>);
static_assert(!QuantityPointOf<quantity_point<isq::length[si::metre]>, absolute_point_origin<isq::radius>{}>);
static_assert(!QuantityPointOf<quantity_point<isq::length[si::metre]>, my_origin>);
static_assert(!QuantityPointOf<quantity_point<isq::length[si::metre]>, my_relative_origin>);
static_assert(QuantityPointOf<quantity_point<isq::radius[si::metre]>, absolute_point_origin<isq::length>{}>);
static_assert(QuantityPointOf<quantity_point<isq::radius[si::metre]>, absolute_point_origin<isq::radius>{}>);
static_assert(QuantityPointOf<quantity_point<isq::radius[si::metre]>, my_origin>);
static_assert(!QuantityPointOf<quantity_point<isq::radius[si::metre]>, my_origin>);
static_assert(!QuantityPointOf<quantity_point<isq::radius[si::metre]>, my_relative_origin>);
static_assert(QuantityPointOf<quantity_point<isq::radius[si::metre], my_origin>, my_origin>);
static_assert(QuantityPointOf<quantity_point<isq::radius[si::metre], my_origin>, absolute_point_origin<isq::length>{}>);
static_assert(QuantityPointOf<quantity_point<isq::radius[si::metre], my_relative_origin>, my_relative_origin>);
static_assert(
QuantityPointOf<quantity_point<isq::radius[si::metre], my_relative_origin>, absolute_point_origin<isq::length>{}>);
static_assert(
!QuantityPointOf<quantity_point<isq::radius[si::metre], my_origin>, absolute_point_origin<isq::length>{}>);
static_assert(
!QuantityPointOf<quantity_point<isq::radius[si::metre], my_origin>, absolute_point_origin<isq::radius>{}>);
static_assert(
!QuantityPointOf<quantity_point<isq::radius[si::metre], my_relative_origin>, absolute_point_origin<isq::radius>{}>);
// PointOrigin
static_assert(PointOrigin<absolute_point_origin<isq::length>>);
static_assert(PointOrigin<struct my_origin>);
static_assert(PointOrigin<quantity_point<si::metre>>);
static_assert(PointOrigin<quantity_point<isq::length[si::metre]>>);
static_assert(PointOrigin<quantity_point<isq::length[si::metre], absolute_point_origin<isq::length>{}, int>>);
static_assert(PointOrigin<quantity_point<isq::radius[si::metre], absolute_point_origin<isq::length>{}, int>>);
static_assert(PointOrigin<quantity_point<isq::radius[si::metre], my_origin>>);
static_assert(PointOrigin<struct my_relative_origin>);
static_assert(!PointOrigin<relative_point_origin<quantity_point<si::metre>{42 * si::metre}>>);
static_assert(!PointOrigin<quantity_point<si::metre>>);
static_assert(!PointOrigin<quantity_point<isq::length[si::metre]>>);
static_assert(!PointOrigin<quantity_point<isq::length[si::metre], absolute_point_origin<isq::length>{}, int>>);
static_assert(!PointOrigin<quantity_point<isq::radius[si::metre], absolute_point_origin<isq::length>{}, int>>);
static_assert(!PointOrigin<quantity_point<isq::radius[si::metre], my_origin>>);
static_assert(!PointOrigin<std::remove_const_t<decltype(isq::length[si::metre])>>);
static_assert(!PointOrigin<std::chrono::seconds>);
static_assert(!PointOrigin<std::chrono::time_point<std::chrono::system_clock>>);
@ -426,42 +444,48 @@ static_assert(!PointOriginFor<absolute_point_origin<isq::length>, isq::time>);
static_assert(PointOriginFor<struct my_origin, isq::length>);
static_assert(PointOriginFor<struct my_origin, isq::radius>);
static_assert(!PointOriginFor<struct my_origin, isq::time>);
static_assert(PointOriginFor<quantity_point<si::metre>, isq::length>);
static_assert(PointOriginFor<quantity_point<si::metre>, isq::radius>);
static_assert(PointOriginFor<struct my_relative_origin, isq::length>);
static_assert(PointOriginFor<struct my_relative_origin, isq::radius>);
static_assert(!PointOriginFor<struct my_relative_origin, isq::time>);
static_assert(!PointOriginFor<quantity_point<si::metre>, isq::length>);
static_assert(!PointOriginFor<quantity_point<si::metre>, isq::radius>);
static_assert(!PointOriginFor<quantity_point<si::metre>, isq::time>);
static_assert(PointOriginFor<quantity_point<isq::length[si::metre]>, isq::length>);
static_assert(PointOriginFor<quantity_point<isq::length[si::metre]>, isq::radius>);
static_assert(!PointOriginFor<quantity_point<isq::length[si::metre]>, isq::length>);
static_assert(!PointOriginFor<quantity_point<isq::length[si::metre]>, isq::radius>);
static_assert(!PointOriginFor<quantity_point<isq::length[si::metre]>, isq::time>);
static_assert(!PointOriginFor<quantity_point<isq::radius[si::metre]>, isq::length>);
static_assert(PointOriginFor<quantity_point<isq::radius[si::metre]>, isq::radius>);
static_assert(!PointOriginFor<quantity_point<isq::radius[si::metre]>, isq::radius>);
static_assert(!PointOriginFor<quantity_point<isq::radius[si::metre]>, isq::time>);
static_assert(
PointOriginFor<quantity_point<isq::length[si::metre], absolute_point_origin<isq::length>{}, int>, isq::length>);
!PointOriginFor<quantity_point<isq::length[si::metre], absolute_point_origin<isq::length>{}, int>, isq::length>);
static_assert(
PointOriginFor<quantity_point<isq::length[si::metre], absolute_point_origin<isq::length>{}, int>, isq::radius>);
!PointOriginFor<quantity_point<isq::length[si::metre], absolute_point_origin<isq::length>{}, int>, isq::radius>);
static_assert(
!PointOriginFor<quantity_point<isq::length[si::metre], absolute_point_origin<isq::length>{}, int>, isq::time>);
static_assert(
!PointOriginFor<quantity_point<isq::radius[si::metre], absolute_point_origin<isq::radius>{}, int>, isq::length>);
static_assert(
PointOriginFor<quantity_point<isq::radius[si::metre], absolute_point_origin<isq::radius>{}, int>, isq::radius>);
!PointOriginFor<quantity_point<isq::radius[si::metre], absolute_point_origin<isq::radius>{}, int>, isq::radius>);
static_assert(
!PointOriginFor<quantity_point<isq::radius[si::metre], absolute_point_origin<isq::radius>{}, int>, isq::time>);
static_assert(PointOriginFor<quantity_point<isq::length[si::metre], absolute_point_origin<kind_of<isq::length>>{}, int>,
isq::length>);
static_assert(PointOriginFor<quantity_point<isq::length[si::metre], absolute_point_origin<kind_of<isq::length>>{}, int>,
isq::radius>);
static_assert(!PointOriginFor<
quantity_point<isq::length[si::metre], absolute_point_origin<kind_of<isq::length>>{}, int>, isq::length>);
static_assert(!PointOriginFor<
quantity_point<isq::length[si::metre], absolute_point_origin<kind_of<isq::length>>{}, int>, isq::radius>);
static_assert(!PointOriginFor<
quantity_point<isq::length[si::metre], absolute_point_origin<kind_of<isq::length>>{}, int>, isq::time>);
static_assert(!PointOriginFor<
quantity_point<isq::radius[si::metre], absolute_point_origin<kind_of<isq::length>>{}, int>, isq::length>);
static_assert(PointOriginFor<quantity_point<isq::radius[si::metre], absolute_point_origin<kind_of<isq::length>>{}, int>,
isq::radius>);
static_assert(!PointOriginFor<
quantity_point<isq::radius[si::metre], absolute_point_origin<kind_of<isq::length>>{}, int>, isq::radius>);
static_assert(
!PointOriginFor<quantity_point<isq::radius[si::metre], absolute_point_origin<isq::length>{}, int>, isq::time>);
static_assert(!PointOriginFor<quantity_point<isq::radius[si::metre], my_origin>, isq::length>);
static_assert(PointOriginFor<quantity_point<isq::radius[si::metre], my_origin>, isq::radius>);
static_assert(!PointOriginFor<quantity_point<isq::radius[si::metre], my_origin>, isq::radius>);
static_assert(!PointOriginFor<quantity_point<isq::radius[si::metre], my_origin>, isq::time>);
static_assert(!PointOriginFor<quantity_point<isq::radius[si::metre], my_relative_origin>, isq::length>);
static_assert(!PointOriginFor<quantity_point<isq::radius[si::metre], my_relative_origin>, isq::radius>);
static_assert(!PointOriginFor<quantity_point<isq::radius[si::metre], my_relative_origin>, isq::time>);
static_assert(!PointOriginFor<std::remove_const_t<decltype(isq::length[si::metre])>, isq::length>);
static_assert(!PointOriginFor<std::chrono::seconds, isq::length>);
static_assert(!PointOriginFor<std::chrono::time_point<std::chrono::system_clock>, isq::length>);

View File

@ -39,8 +39,13 @@ using sys_seconds = std::chrono::time_point<std::chrono::system_clock, std::chro
inline constexpr struct mean_sea_level : absolute_point_origin<isq::height> {
} mean_sea_level;
inline constexpr quantity_point<isq::height[m], mean_sea_level> ground_level{42 * isq::height[m]};
inline constexpr quantity_point<isq::height[m], mean_sea_level> everest_base_camp{5364 * m};
inline constexpr struct ground_level :
relative_point_origin<quantity_point<isq::height[m], mean_sea_level>{42 * isq::height[m]}> {
} ground_level;
inline constexpr struct everest_base_camp :
relative_point_origin<quantity_point<isq::height[m], mean_sea_level>{5364 * m}> {
} everest_base_camp;
QUANTITY_SPEC(special_height, isq::height);
QUANTITY_SPEC(activity, 1 / isq::time);