refactor: quantity_point refactored for V2

This commit is contained in:
Mateusz Pusz
2022-12-23 19:20:34 +01:00
parent 4efbf81814
commit a45088b859
4 changed files with 151 additions and 111 deletions

View File

@@ -175,4 +175,72 @@ concept quantity_like = requires(T q) {
} -> std::convertible_to<typename quantity_like_traits<T>::rep>;
};
template<QuantitySpec auto Q>
struct absolute_point_origin {
static constexpr QuantitySpec auto quantity_spec = Q;
};
namespace detail {
template<typename T>
inline constexpr bool is_quantity_point = false;
template<auto Q>
void to_base_specialization_of_absolute_point_origin(const volatile absolute_point_origin<Q>*);
template<typename T>
inline constexpr bool is_derived_from_specialization_of_absolute_point_origin =
requires(T * t) { to_base_specialization_of_absolute_point_origin(t); };
} // namespace detail
template<typename T>
concept QuantityPoint = detail::is_quantity_point<T>;
template<typename T>
concept point_origin = QuantityPoint<T> || detail::is_derived_from_specialization_of_absolute_point_origin<T>;
template<typename T, auto Q>
concept point_origin_for = point_origin<T> && QuantitySpec<std::remove_const_t<decltype(Q)>> &&
detail::is_kind_of(Q, T::quantity_spec);
template<Reference auto R, point_origin_for<R.quantity_spec> auto PO, RepresentationOf<R.quantity_spec.character> Rep>
class quantity_point;
namespace detail {
template<auto R, auto PO, typename Rep>
void to_base_specialization_of_quantity_point(const volatile quantity_point<R, PO, Rep>*);
template<typename T>
requires requires(T* t) { detail::to_base_specialization_of_quantity_point(t); }
inline constexpr bool is_quantity_point<T> = true;
} // namespace detail
template<typename QP, auto V>
concept quantity_point_of =
QuantityPoint<QP> &&
((Dimension<std::remove_const_t<decltype(V)>> && QP::dimension == V) ||
(QuantitySpec<std::remove_const_t<decltype(V)>> && detail::is_kind_of(QP::quantity_spec, V)) ||
(Reference<std::remove_const_t<decltype(V)>> && QP::reference == V) ||
(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)>>));
template<typename T>
concept quantity_point_like = requires(T q) {
quantity_point_like_traits<T>::reference;
quantity_point_like_traits<T>::point_origin;
typename quantity_point_like_traits<T>::rep;
requires Reference<std::remove_const_t<decltype(quantity_point_like_traits<T>::reference)>>;
requires point_origin<std::remove_const_t<decltype(quantity_point_like_traits<T>::point_origin)>>;
requires RepresentationOf<typename quantity_point_like_traits<T>::rep,
quantity_point_like_traits<T>::reference.quantity_spec.character>;
requires std::constructible_from<
typename quantity_point<quantity_point_like_traits<T>::reference, quantity_point_like_traits<T>::point_origin,
typename quantity_point_like_traits<T>::rep>::quantity_type,
decltype(quantity_point_like_traits<T>::relative(q))>;
};
} // namespace units

View File

@@ -142,8 +142,9 @@ struct quantity_like_traits;
/**
* @brief Provides support for external quantity point-like types
*
* The type trait should provide the following nested type aliases: @c origin, @c unit, @c rep,
* and a static member function @c relative(T) that will return the quantity-like value of the quantity point.
* The type trait should provide nested @c reference and @c origin objects,
* a type alias @c rep, and a static member function @c relative(T) that will return
* the quantity-like value of the quantity point.
*
* Usage example can be found in @c units/chrono.h header file.
*

View File

@@ -1,34 +0,0 @@
// The MIT License (MIT)
//
// Copyright (c) 2018 Mateusz Pusz
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
#include <units/bits/basic_concepts.h>
namespace units {
template<Dimension D>
struct point_origin {
using dimension = D;
};
} // namespace units

View File

@@ -23,119 +23,133 @@
#pragma once
// IWYU pragma: begin_exports
#include <units/point_origin.h>
#include <units/customization_points.h>
#include <units/quantity.h>
#include <compare>
// IWYU pragma: end_exports
#include <units/customization_points.h>
#include <units/generic/dimensionless.h>
namespace units {
/**
* @brief A statically unspecified quantity point origin
*
* An origin, unspecified in the type system, from which an absolute quantity is measured from.
*
* @tparam D a dimension of the quantity point (can be either a BaseDimension or a DerivedDimension)
*/
template<Dimension D>
struct dynamic_origin : point_origin<D> {
template<Dimension D2>
using rebind = dynamic_origin<D2>;
};
namespace detail {
[[nodiscard]] consteval point_origin auto get_absolute_point_origin(point_origin auto po)
{
if constexpr (requires { po.absolute_point_origin; })
return po.absolute_point_origin;
else
return po;
}
template<quantity_point_like QP>
using quantity_point_like_type =
quantity_point<quantity_point_like_traits<QP>::reference, quantity_point_like_traits<QP>::point_origin,
typename quantity_point_like_traits<QP>::rep>;
} // namespace detail
/**
* @brief A quantity point
*
* An absolute quantity measured from an origin.
*
* @tparam O a type that represents the origin from which the quantity point is measured from
* @tparam U a measurement unit of the quantity point
* @tparam R a reference of the quantity point providing all information about quantity properties
* @tparam PO a type that represents the origin point from which the quantity point is measured from
* @tparam Rep a type to be used to represent values of a quantity point
*/
template<PointOrigin O, UnitOf<typename O::dimension> U, Representation Rep = double>
template<Reference auto R, point_origin_for<R.quantity_spec> auto PO = absolute_point_origin<R.quantity_spec>{},
RepresentationOf<R.quantity_spec.character> Rep = double>
class quantity_point {
public:
using origin = O;
using quantity_type = quantity<typename origin::dimension, U, Rep>;
using dimension = typename quantity_type::dimension;
using unit = typename quantity_type::unit;
using rep = typename quantity_type::rep;
static constexpr units::reference<dimension, unit> reference{};
// member types and values
static constexpr Reference auto reference = R;
static constexpr QuantitySpec auto quantity_spec = reference.quantity_spec;
static constexpr Dimension auto dimension = reference.dimension;
static constexpr Unit auto unit = reference.unit;
static constexpr point_origin auto absolute_point_origin = detail::get_absolute_point_origin(PO);
static constexpr point_origin auto point_origin = PO;
using rep = Rep;
using quantity_type = quantity<reference, Rep>;
private:
quantity_type q_{};
quantity_type q_; // needs to be public for a structural type
public:
// static member functions
[[nodiscard]] static constexpr quantity_point min() noexcept
requires requires { quantity_type::min(); }
{
return quantity_point{quantity_type::min()};
}
[[nodiscard]] static constexpr quantity_point max() noexcept
requires requires { quantity_type::max(); }
{
return quantity_point{quantity_type::max()};
}
// construction, assignment, destruction
quantity_point() = default;
quantity_point(const quantity_point&) = default;
quantity_point(quantity_point&&) = default;
template<typename T>
requires std::constructible_from<quantity_type, T>
constexpr explicit quantity_point(T&& t) : q_(std::forward<T>(t))
constexpr explicit quantity_point(T&& v) : q_(std::forward<T>(v))
{
}
template<QuantityPointOf<origin> QP2>
template<quantity_point_of<point_origin> QP2>
requires std::convertible_to<typename QP2::quantity_type, quantity_type>
constexpr explicit(false) quantity_point(const QP2& qp) : q_(qp.relative())
{
}
template<QuantityPointLike QP>
constexpr explicit quantity_point(const QP& qp)
requires std::is_constructible_v<quantity_type, decltype(quantity_point_like_traits<QP>::relative(qp))> &&
equivalent<origin, typename quantity_point_like_traits<QP>::origin>
: q_(quantity_point_like_traits<QP>::relative(qp))
template<quantity_point_like QP>
requires std::same_as<std::remove_const_t<decltype(quantity_point_like_traits<QP>::point_origin)>,
std::remove_const_t<decltype(point_origin)>> &&
std::convertible_to<typename detail::quantity_point_like_type<QP>::quantity_type, quantity_type>
constexpr explicit quantity_point(const QP& qp) :
q_(typename detail::quantity_point_like_type<QP>::quantity_type{quantity_point_like_traits<QP>::relative(qp)})
{
}
quantity_point& operator=(const quantity_point&) = default;
quantity_point& operator=(quantity_point&&) = default;
[[nodiscard]] constexpr quantity_type& relative() & noexcept { return q_; }
// data access
[[nodiscard]] constexpr const quantity_type& relative() const& noexcept { return q_; }
[[nodiscard]] constexpr quantity_type&& relative() && noexcept { return std::move(q_); }
[[nodiscard]] constexpr const quantity_type&& relative() const&& noexcept { return std::move(q_); }
[[nodiscard]] static constexpr quantity_point min() noexcept
requires requires { quantity_type::min(); }
[[nodiscard]] constexpr Quantity auto absolute() const noexcept
{
return quantity_point(quantity_type::min());
}
[[nodiscard]] static constexpr quantity_point max() noexcept
requires requires { quantity_type::max(); }
{
return quantity_point(quantity_type::max());
if constexpr (detail::is_derived_from_specialization_of_absolute_point_origin<
std::remove_const_t<decltype(point_origin)>>)
return relative();
else
return point_origin.absolute() + relative();
}
// member unary operators
constexpr quantity_point& operator++()
requires requires(quantity_type q) { ++q; }
requires requires { ++q_; }
{
++q_;
return *this;
}
[[nodiscard]] constexpr quantity_point operator++(int)
requires requires(quantity_type q) { q++; }
requires requires { q_++; }
{
return quantity_point(q_++);
}
constexpr quantity_point& operator--()
requires requires(quantity_type q) { --q; }
requires requires { --q_; }
{
--q_;
return *this;
}
[[nodiscard]] constexpr quantity_point operator--(int)
requires requires(quantity_type q) { q--; }
requires requires { q_--; }
{
return quantity_point(q_--);
}
@@ -148,7 +162,7 @@ public:
}
constexpr quantity_point& operator-=(const quantity_type& q)
requires requires(quantity_type q1, quantity_type q2) { q1 -= q2; }
requires requires { q_ -= q; }
{
q_ -= q;
return *this;
@@ -156,15 +170,13 @@ public:
// Hidden Friends
// Below friend functions are to be found via argument-dependent lookup only
template<Quantity Q>
[[nodiscard]] friend constexpr QuantityPoint auto operator+(const quantity_point& lhs, const Q& rhs)
requires requires(quantity_type q) { q + rhs; }
{
const auto q = lhs.relative() + rhs;
using q_type = decltype(q);
return quantity_point<rebind_point_origin_dimension<origin, typename q_type::dimension>, typename q_type::unit,
typename q_type::rep>(q);
return quantity_point<q_type::reference, point_origin, typename q_type::rep>(q);
}
template<Quantity Q>
@@ -180,25 +192,24 @@ public:
{
const auto q = lhs.relative() - rhs;
using q_type = decltype(q);
return quantity_point<rebind_point_origin_dimension<origin, typename q_type::dimension>, typename q_type::unit,
typename q_type::rep>(q);
return quantity_point<q_type::reference, point_origin, typename q_type::rep>(q);
}
template<QuantityPointOf<origin> QP>
template<quantity_point_of<absolute_point_origin> QP>
[[nodiscard]] friend constexpr Quantity auto operator-(const quantity_point& lhs, const QP& rhs)
requires requires(quantity_type q) { q - rhs.relative(); }
requires requires(quantity_type q) { q - rhs.absolute(); }
{
return lhs.relative() - rhs.relative();
return lhs.absolute() - rhs.absolute();
}
template<QuantityPointOf<origin> QP>
template<quantity_point_of<absolute_point_origin> QP>
requires std::three_way_comparable_with<quantity_type, typename QP::quantity_type>
[[nodiscard]] friend constexpr auto operator<=>(const quantity_point& lhs, const QP& rhs)
{
return lhs.relative() <=> rhs.relative();
}
template<QuantityPointOf<origin> QP>
template<quantity_point_of<absolute_point_origin> QP>
requires std::equality_comparable_with<quantity_type, typename QP::quantity_type>
[[nodiscard]] friend constexpr bool operator==(const quantity_point& lhs, const QP& rhs)
{
@@ -206,27 +217,21 @@ public:
}
};
// CTAD
template<Representation Rep>
explicit quantity_point(Rep) -> quantity_point<dynamic_origin<dim_one>, one, Rep>;
explicit quantity_point(Rep) -> quantity_point<dimensionless[one], absolute_point_origin<dimensionless>{}, Rep>;
template<Quantity Q>
explicit quantity_point(Q) -> quantity_point<dynamic_origin<typename Q::dimension>, typename Q::unit, typename Q::rep>;
explicit quantity_point(Q) -> quantity_point<Q::reference, absolute_point_origin<Q::quantity_spec>{}, typename Q::rep>;
template<QuantityLike Q>
template<quantity_like Q>
explicit quantity_point(Q)
-> quantity_point<dynamic_origin<typename quantity_like_traits<Q>::dimension>, typename quantity_like_traits<Q>::unit,
-> quantity_point<quantity_like_traits<Q>::reference, absolute_point_origin<quantity_like_traits<Q>::quantity_spec>{},
typename quantity_like_traits<Q>::rep>;
template<QuantityPointLike QP>
template<quantity_point_like QP>
explicit quantity_point(QP)
-> quantity_point<typename quantity_point_like_traits<QP>::origin, typename quantity_point_like_traits<QP>::unit,
-> quantity_point<quantity_point_like_traits<QP>::reference, quantity_point_like_traits<QP>::point_origin,
typename quantity_point_like_traits<QP>::rep>;
namespace detail {
template<typename O, typename U, typename Rep>
inline constexpr bool is_quantity_point<quantity_point<O, U, Rep>> = true;
} // namespace detail
} // namespace units