};
/**
- * Helper class to convert a POSIX-style pair of (seconds, subseconds)
- * to a std::chrono::duration type.
+ * Convert a timeval or a timespec to a std::chrono::duration with second
+ * granularity.
*
* The SubsecondRatio template parameter specifies what type of subseconds to
* return. This must have a numerator of 1.
* The input must be in normalized form: the subseconds field must be greater
* than or equal to 0, and less than SubsecondRatio::den (i.e., less than 1
* second).
- *
- * This default implementation is only used for unusual std::chrono::duration
- * types where neither the numerator nor denominator are 1.
- */
-template <typename Tgt>
-struct PosixTimeToDuration {
- template <typename SubsecondRatio, typename Seconds, typename Subseconds>
- static Expected<Tgt, ConversionCode> cast(
- Seconds seconds,
- Subseconds subseconds);
-};
-
-/**
- * Convert a timeval or a timespec to a std::chrono::duration with second
- * granularity.
*/
-template <typename Rep>
-struct PosixTimeToDuration<std::chrono::duration<Rep, std::ratio<1, 1>>> {
- using Tgt = std::chrono::duration<Rep, std::ratio<1, 1>>;
-
- template <typename SubsecondRatio, typename Seconds, typename Subseconds>
- static Expected<Tgt, ConversionCode> cast(
- Seconds seconds,
- Subseconds subseconds) {
- static_assert(Tgt::period::num == 1, "special case expecting num==1");
- static_assert(Tgt::period::den == 1, "special case expecting den==1");
- static_assert(
- SubsecondRatio::num == 1, "subsecond numerator should always be 1");
+template <
+ typename SubsecondRatio,
+ typename Seconds,
+ typename Subseconds,
+ typename Rep>
+auto posixTimeToDuration(
+ Seconds seconds,
+ Subseconds subseconds,
+ std::chrono::duration<Rep, std::ratio<1, 1>> dummy)
+ -> Expected<decltype(dummy), ConversionCode> {
+ using Tgt = decltype(dummy);
+ static_assert(Tgt::period::num == 1, "special case expecting num==1");
+ static_assert(Tgt::period::den == 1, "special case expecting den==1");
+ static_assert(
+ SubsecondRatio::num == 1, "subsecond numerator should always be 1");
- auto outputSeconds = tryTo<typename Tgt::rep>(seconds);
- if (outputSeconds.hasError()) {
- return makeUnexpected(outputSeconds.error());
- }
+ auto outputSeconds = tryTo<typename Tgt::rep>(seconds);
+ if (outputSeconds.hasError()) {
+ return makeUnexpected(outputSeconds.error());
+ }
- if (std::is_floating_point<typename Tgt::rep>::value) {
- return Tgt{typename Tgt::rep(seconds) +
- (typename Tgt::rep(subseconds) / SubsecondRatio::den)};
- }
+ if (std::is_floating_point<typename Tgt::rep>::value) {
+ return Tgt{typename Tgt::rep(seconds) +
+ (typename Tgt::rep(subseconds) / SubsecondRatio::den)};
+ }
- // If the value is negative, we have to round up a non-zero subseconds value
- if (UNLIKELY(outputSeconds.value() < 0) && subseconds > 0) {
- if (UNLIKELY(
- outputSeconds.value() ==
- std::numeric_limits<typename Tgt::rep>::lowest())) {
- return makeUnexpected(ConversionCode::NEGATIVE_OVERFLOW);
- }
- return Tgt{outputSeconds.value() + 1};
+ // If the value is negative, we have to round up a non-zero subseconds value
+ if (UNLIKELY(outputSeconds.value() < 0) && subseconds > 0) {
+ if (UNLIKELY(
+ outputSeconds.value() ==
+ std::numeric_limits<typename Tgt::rep>::lowest())) {
+ return makeUnexpected(ConversionCode::NEGATIVE_OVERFLOW);
}
-
- return Tgt{outputSeconds.value()};
+ return Tgt{outputSeconds.value() + 1};
}
-};
+
+ return Tgt{outputSeconds.value()};
+}
/**
* Convert a timeval or a timespec to a std::chrono::duration with subsecond
* granularity
*/
-template <typename Rep, std::intmax_t Denominator>
-struct PosixTimeToDuration<
- std::chrono::duration<Rep, std::ratio<1, Denominator>>> {
- using Tgt = std::chrono::duration<Rep, std::ratio<1, Denominator>>;
-
- template <typename SubsecondRatio, typename Seconds, typename Subseconds>
- static Expected<Tgt, ConversionCode> cast(
- Seconds seconds,
- Subseconds subseconds) {
- static_assert(Tgt::period::num == 1, "special case expecting num==1");
- static_assert(Tgt::period::den != 1, "special case expecting den!=1");
- static_assert(
- SubsecondRatio::num == 1, "subsecond numerator should always be 1");
+template <
+ typename SubsecondRatio,
+ typename Seconds,
+ typename Subseconds,
+ typename Rep,
+ std::intmax_t Denominator>
+auto posixTimeToDuration(
+ Seconds seconds,
+ Subseconds subseconds,
+ std::chrono::duration<Rep, std::ratio<1, Denominator>> dummy)
+ -> Expected<decltype(dummy), ConversionCode> {
+ using Tgt = decltype(dummy);
+ static_assert(Tgt::period::num == 1, "special case expecting num==1");
+ static_assert(Tgt::period::den != 1, "special case expecting den!=1");
+ static_assert(
+ SubsecondRatio::num == 1, "subsecond numerator should always be 1");
- auto errorCode = detail::CheckOverflowToDuration<
- std::is_floating_point<typename Tgt::rep>::value>::
- template check<Tgt, SubsecondRatio>(seconds, subseconds);
- if (errorCode != ConversionCode::SUCCESS) {
- return makeUnexpected(errorCode);
- }
+ auto errorCode = detail::CheckOverflowToDuration<
+ std::is_floating_point<typename Tgt::rep>::value>::
+ template check<Tgt, SubsecondRatio>(seconds, subseconds);
+ if (errorCode != ConversionCode::SUCCESS) {
+ return makeUnexpected(errorCode);
+ }
- if (LIKELY(seconds >= 0)) {
- return std::chrono::duration_cast<Tgt>(
- std::chrono::duration<typename Tgt::rep>{seconds}) +
- std::chrono::duration_cast<Tgt>(
- std::chrono::duration<typename Tgt::rep, SubsecondRatio>{
- subseconds});
- } else {
- // For negative numbers we have to round subseconds up towards zero, even
- // though it is a positive value, since the overall value is negative.
- return std::chrono::duration_cast<Tgt>(
- std::chrono::duration<typename Tgt::rep>{seconds + 1}) -
- std::chrono::duration_cast<Tgt>(
- std::chrono::duration<typename Tgt::rep, SubsecondRatio>{
- SubsecondRatio::den - subseconds});
- }
+ if (LIKELY(seconds >= 0)) {
+ return std::chrono::duration_cast<Tgt>(
+ std::chrono::duration<typename Tgt::rep>{seconds}) +
+ std::chrono::duration_cast<Tgt>(
+ std::chrono::duration<typename Tgt::rep, SubsecondRatio>{
+ subseconds});
+ } else {
+ // For negative numbers we have to round subseconds up towards zero, even
+ // though it is a positive value, since the overall value is negative.
+ return std::chrono::duration_cast<Tgt>(
+ std::chrono::duration<typename Tgt::rep>{seconds + 1}) -
+ std::chrono::duration_cast<Tgt>(
+ std::chrono::duration<typename Tgt::rep, SubsecondRatio>{
+ SubsecondRatio::den - subseconds});
}
-};
+}
/**
* Convert a timeval or a timespec to a std::chrono::duration with
* granularity coarser than 1 second.
*/
-template <typename Rep, std::intmax_t Numerator>
-struct PosixTimeToDuration<
- std::chrono::duration<Rep, std::ratio<Numerator, 1>>> {
- using Tgt = std::chrono::duration<Rep, std::ratio<Numerator, 1>>;
-
- template <typename SubsecondRatio, typename Seconds, typename Subseconds>
- static Expected<Tgt, ConversionCode> cast(
- Seconds seconds,
- Subseconds subseconds) {
- static_assert(Tgt::period::num != 1, "special case expecting num!=1");
- static_assert(Tgt::period::den == 1, "special case expecting den==1");
- static_assert(
- SubsecondRatio::num == 1, "subsecond numerator should always be 1");
+template <
+ typename SubsecondRatio,
+ typename Seconds,
+ typename Subseconds,
+ typename Rep,
+ std::intmax_t Numerator>
+auto posixTimeToDuration(
+ Seconds seconds,
+ Subseconds subseconds,
+ std::chrono::duration<Rep, std::ratio<Numerator, 1>> dummy)
+ -> Expected<decltype(dummy), ConversionCode> {
+ using Tgt = decltype(dummy);
+ static_assert(Tgt::period::num != 1, "special case expecting num!=1");
+ static_assert(Tgt::period::den == 1, "special case expecting den==1");
+ static_assert(
+ SubsecondRatio::num == 1, "subsecond numerator should always be 1");
- if (UNLIKELY(seconds < 0) && subseconds > 0) {
- // Increment seconds by one to handle truncation of negative numbers
- // properly.
- if (UNLIKELY(seconds == std::numeric_limits<Seconds>::lowest())) {
- return makeUnexpected(ConversionCode::NEGATIVE_OVERFLOW);
- }
- seconds += 1;
+ if (UNLIKELY(seconds < 0) && subseconds > 0) {
+ // Increment seconds by one to handle truncation of negative numbers
+ // properly.
+ if (UNLIKELY(seconds == std::numeric_limits<Seconds>::lowest())) {
+ return makeUnexpected(ConversionCode::NEGATIVE_OVERFLOW);
}
+ seconds += 1;
+ }
- if (std::is_floating_point<typename Tgt::rep>::value) {
- // Convert to the floating point type before performing the division
- return Tgt{static_cast<typename Tgt::rep>(seconds) / Tgt::period::num};
- } else {
- // Perform the division as an integer, and check that the result fits in
- // the output integer type
- auto outputValue = (seconds / Tgt::period::num);
- auto expectedOuput = tryTo<typename Tgt::rep>(outputValue);
- if (expectedOuput.hasError()) {
- return makeUnexpected(expectedOuput.error());
- }
-
- return Tgt{expectedOuput.value()};
+ if (std::is_floating_point<typename Tgt::rep>::value) {
+ // Convert to the floating point type before performing the division
+ return Tgt{static_cast<typename Tgt::rep>(seconds) / Tgt::period::num};
+ } else {
+ // Perform the division as an integer, and check that the result fits in
+ // the output integer type
+ auto outputValue = (seconds / Tgt::period::num);
+ auto expectedOuput = tryTo<typename Tgt::rep>(outputValue);
+ if (expectedOuput.hasError()) {
+ return makeUnexpected(expectedOuput.error());
}
+
+ return Tgt{expectedOuput.value()};
}
-};
+}
/**
- * PosixTimeToDuration::cast() implementation for the default case
- * with unusual durations where neither the numerator nor denominator are 1.
+ * Convert a timeval or timespec to a std::chrono::duration
+ *
+ * This overload is only used for unusual durations where neither the numerator
+ * nor denominator are 1.
*/
-template <typename Tgt>
-template <typename SubsecondRatio, typename Seconds, typename Subseconds>
-Expected<Tgt, ConversionCode> PosixTimeToDuration<Tgt>::cast(
+template <
+ typename SubsecondRatio,
+ typename Seconds,
+ typename Subseconds,
+ typename Rep,
+ std::intmax_t Denominator,
+ std::intmax_t Numerator>
+auto posixTimeToDuration(
Seconds seconds,
- Subseconds subseconds) {
+ Subseconds subseconds,
+ std::chrono::duration<Rep, std::ratio<Numerator, Denominator>> dummy)
+ -> Expected<decltype(dummy), ConversionCode> {
+ using Tgt = decltype(dummy);
static_assert(
Tgt::period::num != 1, "should use special-case code when num==1");
static_assert(
subseconds = remainder;
}
- using Converter = PosixTimeToDuration<Tgt>;
- return Converter::template cast<SubsecondRatio>(seconds, subseconds);
+ return posixTimeToDuration<SubsecondRatio>(seconds, subseconds, Tgt{});
}
} // namespace detail