From 3c9a6e9a15092db11c543c8bae51957b176fcedd Mon Sep 17 00:00:00 2001 From: Yedidya Feldblum Date: Mon, 20 Nov 2017 13:29:48 -0800 Subject: [PATCH] No need for a wrapping structure for posixTimeToDuration Summary: [Folly] No need for a wrapping structure for `posixTimeToDuration`. We can just use a variant of tag dispatch. In this variant, we pass to `posixTimeToDuration` a default-initialized value of the desired return type and we write overload templates for each possible variant. The argument is used purely for overload resolution and return type deduction, not for its runtime value. It is slightly different from tag dispatch because we do not use separate types which are purely tag types. Reviewed By: simpkins Differential Revision: D6371572 fbshipit-source-id: 1987dee31fceec8733caa61495e96489dbf1ca39 --- folly/chrono/Conv.h | 250 ++++++++++++++++++++++---------------------- 1 file changed, 125 insertions(+), 125 deletions(-) diff --git a/folly/chrono/Conv.h b/folly/chrono/Conv.h index 95aff32a..688658ec 100644 --- a/folly/chrono/Conv.h +++ b/folly/chrono/Conv.h @@ -323,8 +323,8 @@ struct CheckOverflowToDuration { }; /** - * 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. @@ -332,155 +332,156 @@ struct CheckOverflowToDuration { * 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 -struct PosixTimeToDuration { - template - static Expected cast( - Seconds seconds, - Subseconds subseconds); -}; - -/** - * Convert a timeval or a timespec to a std::chrono::duration with second - * granularity. */ -template -struct PosixTimeToDuration>> { - using Tgt = std::chrono::duration>; - - template - static Expected 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> dummy) + -> Expected { + 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(seconds); - if (outputSeconds.hasError()) { - return makeUnexpected(outputSeconds.error()); - } + auto outputSeconds = tryTo(seconds); + if (outputSeconds.hasError()) { + return makeUnexpected(outputSeconds.error()); + } - if (std::is_floating_point::value) { - return Tgt{typename Tgt::rep(seconds) + - (typename Tgt::rep(subseconds) / SubsecondRatio::den)}; - } + if (std::is_floating_point::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::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::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 -struct PosixTimeToDuration< - std::chrono::duration>> { - using Tgt = std::chrono::duration>; - - template - static Expected 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> dummy) + -> Expected { + 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::value>:: - template check(seconds, subseconds); - if (errorCode != ConversionCode::SUCCESS) { - return makeUnexpected(errorCode); - } + auto errorCode = detail::CheckOverflowToDuration< + std::is_floating_point::value>:: + template check(seconds, subseconds); + if (errorCode != ConversionCode::SUCCESS) { + return makeUnexpected(errorCode); + } - if (LIKELY(seconds >= 0)) { - return std::chrono::duration_cast( - std::chrono::duration{seconds}) + - std::chrono::duration_cast( - std::chrono::duration{ - 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( - std::chrono::duration{seconds + 1}) - - std::chrono::duration_cast( - std::chrono::duration{ - SubsecondRatio::den - subseconds}); - } + if (LIKELY(seconds >= 0)) { + return std::chrono::duration_cast( + std::chrono::duration{seconds}) + + std::chrono::duration_cast( + std::chrono::duration{ + 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( + std::chrono::duration{seconds + 1}) - + std::chrono::duration_cast( + std::chrono::duration{ + SubsecondRatio::den - subseconds}); } -}; +} /** * Convert a timeval or a timespec to a std::chrono::duration with * granularity coarser than 1 second. */ -template -struct PosixTimeToDuration< - std::chrono::duration>> { - using Tgt = std::chrono::duration>; - - template - static Expected 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> dummy) + -> Expected { + 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::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::lowest())) { + return makeUnexpected(ConversionCode::NEGATIVE_OVERFLOW); } + seconds += 1; + } - if (std::is_floating_point::value) { - // Convert to the floating point type before performing the division - return Tgt{static_cast(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(outputValue); - if (expectedOuput.hasError()) { - return makeUnexpected(expectedOuput.error()); - } - - return Tgt{expectedOuput.value()}; + if (std::is_floating_point::value) { + // Convert to the floating point type before performing the division + return Tgt{static_cast(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(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 -template -Expected PosixTimeToDuration::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> dummy) + -> Expected { + using Tgt = decltype(dummy); static_assert( Tgt::period::num != 1, "should use special-case code when num==1"); static_assert( @@ -534,8 +535,7 @@ Expected tryPosixTimeToDuration( subseconds = remainder; } - using Converter = PosixTimeToDuration; - return Converter::template cast(seconds, subseconds); + return posixTimeToDuration(seconds, subseconds, Tgt{}); } } // namespace detail -- 2.34.1