refactor: std::chrono support refactored for V2

This commit is contained in:
Mateusz Pusz
2022-12-23 19:21:01 +01:00
parent a45088b859
commit b9f2b7fe9d

View File

@@ -23,35 +23,56 @@
#pragma once
#include <units/customization_points.h>
// IWYU pragma: begin_exports
#include <units/isq/si/time.h>
#include <units/point_origin.h>
#include <units/isq/space_and_time.h>
#include <units/si/prefixes.h>
#include <units/si/units.h>
#include <chrono>
// IWYU pragma: end_exports
namespace units {
namespace detail {
template<typename Period>
[[nodiscard]] inline consteval auto time_unit_from_chrono_period()
{
using namespace si;
if constexpr (is_same_v<Period, std::chrono::nanoseconds::period>)
return nano<second>;
else if constexpr (is_same_v<Period, std::chrono::microseconds::period>)
return micro<second>;
else if constexpr (is_same_v<Period, std::chrono::milliseconds::period>)
return milli<second>;
else if constexpr (is_same_v<Period, std::chrono::seconds::period>)
return second;
else if constexpr (is_same_v<Period, std::chrono::minutes::period>)
return minute;
else if constexpr (is_same_v<Period, std::chrono::hours::period>)
return hour;
else if constexpr (is_same_v<Period, std::chrono::days::period>)
return day;
else
return mag<ratio{Period::num, Period::den}> * second;
}
} // namespace detail
template<typename Rep, typename Period>
struct quantity_like_traits<std::chrono::duration<Rep, Period>> {
private:
static constexpr auto mag = ::units::mag<ratio(Period::num, Period::den)>();
public:
using dimension = isq::si::dim_time;
using unit = downcast_unit<dimension, mag>;
static constexpr auto reference = isq::duration[detail::time_unit_from_chrono_period<Period>()];
using rep = Rep;
[[nodiscard]] static constexpr rep number(const std::chrono::duration<Rep, Period>& q) { return q.count(); }
};
template<typename C>
struct clock_origin : point_origin<isq::si::dim_time> {};
struct chrono_point_origin : absolute_point_origin<isq::time> {
using clock = C;
};
template<typename C, typename Rep, typename Period>
struct quantity_point_like_traits<std::chrono::time_point<C, std::chrono::duration<Rep, Period>>> {
private:
static constexpr auto mag = ::units::mag<ratio(Period::num, Period::den)>();
public:
using origin = clock_origin<C>;
using unit = downcast_unit<typename origin::dimension, mag>;
static constexpr auto reference = isq::time[detail::time_unit_from_chrono_period<Period>()];
static constexpr auto point_origin = chrono_point_origin<C>{};
using rep = Rep;
[[nodiscard]] static constexpr auto relative(const std::chrono::time_point<C, std::chrono::duration<Rep, Period>>& qp)
{
@@ -59,42 +80,24 @@ public:
}
};
namespace detail {
template<typename C, typename Rep, typename Period>
inline constexpr bool is_quantity_point_like<std::chrono::time_point<C, std::chrono::duration<Rep, Period>>> = true;
constexpr std::intmax_t pow_10(std::intmax_t v)
template<quantity_of<isq::time> Q>
[[nodiscard]] constexpr auto to_chrono_duration(const Q& q)
{
gsl_Expects(v > 0);
std::intmax_t res = 1;
for (std::intmax_t i = 0; i < v; i++) res *= 10;
return res;
constexpr auto canonical = detail::get_canonical_unit(Q::unit);
constexpr ratio r = as_ratio(canonical.mag);
return std::chrono::duration<typename Q::rep, std::ratio<r.num, r.den>>{q.number()};
}
template<ratio R>
constexpr auto to_std_ratio_impl()
template<quantity_point_of<isq::time> QP>
requires is_specialization_of<std::remove_const_t<decltype(QP::absolute_point_origin)>, chrono_point_origin>
[[nodiscard]] constexpr auto to_chrono_time_point(const QP& qp)
{
return std::ratio<R.num, R.den>{};
}
} // namespace detail
// TODO ICE below on gcc-11 when `ratio` is used instead of `auto`
template<auto R>
using to_std_ratio = decltype(detail::to_std_ratio_impl<R>());
template<typename U, typename Rep>
[[nodiscard]] constexpr auto to_std_duration(const quantity<isq::si::dim_time, U, Rep>& q)
{
return std::chrono::duration<Rep, to_std_ratio<as_ratio(U::mag)>>(q.number());
}
template<typename C, typename U, typename Rep>
[[nodiscard]] constexpr auto to_std_time_point(const quantity_point<clock_origin<C>, U, Rep>& qp)
{
using ret_type = std::chrono::time_point<C, std::chrono::duration<Rep, to_std_ratio<as_ratio(U::mag)>>>;
return ret_type(to_std_duration(qp.relative()));
using clock = TYPENAME decltype(QP::absolute_point_origin)::clock;
using rep = TYPENAME QP::rep;
constexpr auto canonical = detail::get_canonical_unit(QP::unit);
constexpr ratio r = as_ratio(canonical.mag);
using ret_type = std::chrono::time_point<clock, std::chrono::duration<rep, std::ratio<r.num, r.den>>>;
return ret_type(to_std_duration(qp.absolute()));
}
} // namespace units