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> template<typename T>
concept QuantityPoint = detail::is_quantity_point<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 * @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. * Satisfied by either quantity points or by all types derived from `absolute_point_origin` class template.
*/ */
template<typename T> 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 * @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. * 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 = 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, template<Reference auto R, PointOriginFor<get_quantity_spec(R)> auto PO,
RepresentationOf<get_quantity_spec(R).character> Rep> RepresentationOf<get_quantity_spec(R).character> Rep>
@ -108,7 +130,8 @@ concept QuantityPointOf =
QuantityPoint<QP> && QuantityPoint<QP> &&
(ReferenceOf<std::remove_const_t<decltype(QP::reference)>, V> || (ReferenceOf<std::remove_const_t<decltype(QP::reference)>, V> ||
(PointOrigin<std::remove_const_t<decltype(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(QP::absolute_point_origin)>> &&
detail::is_specialization_of_absolute_point_origin<std::remove_const_t<decltype(V)>> && detail::is_specialization_of_absolute_point_origin<std::remove_const_t<decltype(V)>> &&
implicitly_convertible(QP::absolute_point_origin.quantity_spec, V.quantity_spec) && 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; 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 { namespace detail {
[[nodiscard]] consteval PointOrigin auto get_absolute_point_origin(PointOrigin auto po) [[nodiscard]] consteval PointOrigin auto get_absolute_point_origin(PointOrigin auto po)
{ {
if constexpr (requires { po.absolute_point_origin; }) if constexpr (requires { po.parent_origin.absolute_point_origin; })
return po.absolute_point_origin; return po.parent_origin.absolute_point_origin;
else else
return po; return po;
} }
@ -145,7 +151,7 @@ public:
std::remove_const_t<decltype(point_origin)>>) std::remove_const_t<decltype(point_origin)>>)
return relative(); return relative();
else else
return point_origin.absolute() + relative(); return point_origin.parent_origin.absolute() + relative();
} }
template<Unit U> template<Unit U>

View File

@ -360,15 +360,20 @@ static_assert(!QuantityLike<int>);
// QuantityPoint // QuantityPoint
inline constexpr struct my_origin : absolute_point_origin<isq::length> { inline constexpr struct my_origin : absolute_point_origin<isq::length> {
} my_origin; } 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<si::metre>>);
static_assert(QuantityPoint<quantity_point<isq::length[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::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], 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_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<std::remove_const_t<decltype(isq::length[si::metre])>>);
static_assert(!QuantityPoint<absolute_point_origin<isq::length>>); static_assert(!QuantityPoint<absolute_point_origin<isq::length>>);
static_assert(!QuantityPoint<struct my_origin>); static_assert(!QuantityPoint<struct my_origin>);
static_assert(!QuantityPoint<struct my_relative_origin>);
static_assert(!QuantityPoint<std::chrono::seconds>); static_assert(!QuantityPoint<std::chrono::seconds>);
static_assert(!QuantityPoint<std::chrono::time_point<std::chrono::system_clock>>); static_assert(!QuantityPoint<std::chrono::time_point<std::chrono::system_clock>>);
static_assert(!QuantityPoint<int>); 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>); 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::length>);
static_assert(QuantityPointOf<quantity_point<isq::radius[si::metre], my_origin>, isq::radius>); 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::length>{}>);
static_assert(QuantityPointOf<quantity_point<si::metre>, absolute_point_origin<isq::radius>{}>); 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::length>{}>);
static_assert(!QuantityPointOf<quantity_point<isq::length[si::metre]>, absolute_point_origin<isq::radius>{}>); 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_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::length>{}>);
static_assert(QuantityPointOf<quantity_point<isq::radius[si::metre]>, absolute_point_origin<isq::radius>{}>); 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>, 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( static_assert(
!QuantityPointOf<quantity_point<isq::radius[si::metre], my_origin>, absolute_point_origin<isq::radius>{}>); !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 // PointOrigin
static_assert(PointOrigin<absolute_point_origin<isq::length>>); static_assert(PointOrigin<absolute_point_origin<isq::length>>);
static_assert(PointOrigin<struct my_origin>); static_assert(PointOrigin<struct my_origin>);
static_assert(PointOrigin<quantity_point<si::metre>>); static_assert(PointOrigin<struct my_relative_origin>);
static_assert(PointOrigin<quantity_point<isq::length[si::metre]>>); static_assert(!PointOrigin<relative_point_origin<quantity_point<si::metre>{42 * si::metre}>>);
static_assert(PointOrigin<quantity_point<isq::length[si::metre], absolute_point_origin<isq::length>{}, int>>); static_assert(!PointOrigin<quantity_point<si::metre>>);
static_assert(PointOrigin<quantity_point<isq::radius[si::metre], absolute_point_origin<isq::length>{}, int>>); static_assert(!PointOrigin<quantity_point<isq::length[si::metre]>>);
static_assert(PointOrigin<quantity_point<isq::radius[si::metre], my_origin>>); 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::remove_const_t<decltype(isq::length[si::metre])>>);
static_assert(!PointOrigin<std::chrono::seconds>); static_assert(!PointOrigin<std::chrono::seconds>);
static_assert(!PointOrigin<std::chrono::time_point<std::chrono::system_clock>>); 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::length>);
static_assert(PointOriginFor<struct my_origin, isq::radius>); static_assert(PointOriginFor<struct my_origin, isq::radius>);
static_assert(!PointOriginFor<struct my_origin, isq::time>); static_assert(!PointOriginFor<struct my_origin, isq::time>);
static_assert(PointOriginFor<quantity_point<si::metre>, isq::length>); static_assert(PointOriginFor<struct my_relative_origin, isq::length>);
static_assert(PointOriginFor<quantity_point<si::metre>, isq::radius>); 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<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::length>);
static_assert(PointOriginFor<quantity_point<isq::length[si::metre]>, isq::radius>); 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::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::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::radius[si::metre]>, isq::time>);
static_assert( 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( 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( static_assert(
!PointOriginFor<quantity_point<isq::length[si::metre], absolute_point_origin<isq::length>{}, int>, isq::time>); !PointOriginFor<quantity_point<isq::length[si::metre], absolute_point_origin<isq::length>{}, int>, isq::time>);
static_assert( static_assert(
!PointOriginFor<quantity_point<isq::radius[si::metre], absolute_point_origin<isq::radius>{}, int>, isq::length>); !PointOriginFor<quantity_point<isq::radius[si::metre], absolute_point_origin<isq::radius>{}, int>, isq::length>);
static_assert( 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( static_assert(
!PointOriginFor<quantity_point<isq::radius[si::metre], absolute_point_origin<isq::radius>{}, int>, isq::time>); !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>, static_assert(!PointOriginFor<
isq::length>); 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>, static_assert(!PointOriginFor<
isq::radius>); quantity_point<isq::length[si::metre], absolute_point_origin<kind_of<isq::length>>{}, int>, isq::radius>);
static_assert(!PointOriginFor< static_assert(!PointOriginFor<
quantity_point<isq::length[si::metre], absolute_point_origin<kind_of<isq::length>>{}, int>, isq::time>); quantity_point<isq::length[si::metre], absolute_point_origin<kind_of<isq::length>>{}, int>, isq::time>);
static_assert(!PointOriginFor< static_assert(!PointOriginFor<
quantity_point<isq::radius[si::metre], absolute_point_origin<kind_of<isq::length>>{}, int>, isq::length>); 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>, static_assert(!PointOriginFor<
isq::radius>); quantity_point<isq::radius[si::metre], absolute_point_origin<kind_of<isq::length>>{}, int>, isq::radius>);
static_assert( static_assert(
!PointOriginFor<quantity_point<isq::radius[si::metre], absolute_point_origin<isq::length>{}, int>, isq::time>); !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::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_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::remove_const_t<decltype(isq::length[si::metre])>, isq::length>);
static_assert(!PointOriginFor<std::chrono::seconds, isq::length>); static_assert(!PointOriginFor<std::chrono::seconds, isq::length>);
static_assert(!PointOriginFor<std::chrono::time_point<std::chrono::system_clock>, 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> { inline constexpr struct mean_sea_level : absolute_point_origin<isq::height> {
} mean_sea_level; } mean_sea_level;
inline constexpr quantity_point<isq::height[m], mean_sea_level> ground_level{42 * isq::height[m]}; inline constexpr struct ground_level :
inline constexpr quantity_point<isq::height[m], mean_sea_level> everest_base_camp{5364 * m}; 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(special_height, isq::height);
QUANTITY_SPEC(activity, 1 / isq::time); QUANTITY_SPEC(activity, 1 / isq::time);