30 #include <type_traits> 42 template <
typename Rep,
typename Period>
46 template <
typename Clock,
typename Duration>
59 template <
typename Tgt,
typename Src>
74 template <
typename Src>
80 if (value < std::numeric_limits<time_t>::lowest()) {
85 return static_cast<time_t
>(
value);
95 template <
typename SubsecondRatio,
typename Rep>
97 const std::chrono::duration<Rep, std::ratio<1, 1>>& duration) {
99 SubsecondRatio::num == 1,
"subsecond numerator should always be 1");
102 if (sec.hasError()) {
106 time_t secValue = sec.value();
109 auto fraction = (duration.count() - secValue);
110 subsec =
static_cast<long>(fraction * SubsecondRatio::den);
111 if (duration.count() < 0 && fraction < 0) {
112 if (secValue == std::numeric_limits<time_t>::lowest()) {
116 subsec += SubsecondRatio::den;
119 return std::pair<time_t, long>{secValue, subsec};
126 template <
typename SubsecondRatio,
typename Rep, std::
intmax_t Denominator>
128 const std::chrono::duration<Rep, std::ratio<1, Denominator>>& duration) {
129 static_assert(Denominator != 1,
"special case expecting den != 1");
131 SubsecondRatio::num == 1,
"subsecond numerator should always be 1");
134 if (sec.hasError()) {
137 auto secTimeT = sec.value();
139 auto remainder = duration.count() - (secTimeT * Denominator);
140 auto subsec = (remainder * SubsecondRatio::den) / Denominator;
141 if (
UNLIKELY(duration.count() < 0) && remainder != 0) {
142 if (secTimeT == std::numeric_limits<time_t>::lowest()) {
146 subsec += SubsecondRatio::den;
149 return std::pair<time_t, long>{secTimeT, subsec};
156 template <
typename SubsecondRatio,
typename Rep, std::
intmax_t Numerator>
158 const std::chrono::duration<Rep, std::ratio<Numerator, 1>>& duration) {
159 static_assert(Numerator != 1,
"special case expecting num!=1");
161 SubsecondRatio::num == 1,
"subsecond numerator should always be 1");
164 constexpr
auto minValue = std::numeric_limits<time_t>::lowest() / Numerator;
165 if (duration.count() > maxValue) {
168 if (duration.count() < minValue) {
174 auto secOriginalRep = (duration.count() * Numerator);
175 auto sec =
static_cast<time_t
>(secOriginalRep);
179 auto fraction = secOriginalRep - sec;
180 subsec =
static_cast<long>(fraction * SubsecondRatio::den);
181 if (duration.count() < 0 && fraction < 0) {
182 if (sec == std::numeric_limits<time_t>::lowest()) {
186 subsec += SubsecondRatio::den;
189 return std::pair<time_t, long>{sec, subsec};
197 template <
typename T,
bool IsFloatingPo
int,
bool IsSigned>
199 template <
typename T,
bool IsSigned>
203 template <
typename T>
207 template <
typename T>
214 template <
typename Rep,
typename Period>
220 std::ratio<1, Period::den>>;
228 template <
typename SubsecondRatio,
typename Rep,
typename Period>
230 const std::chrono::duration<Rep, Period>& duration) {
231 static_assert(Period::num != 1,
"should use special-case code when num==1");
232 static_assert(Period::den != 1,
"should use special-case code when den==1");
234 SubsecondRatio::num == 1,
"subsecond numerator should always be 1");
239 using IntermediateRep =
typename IntermediateType::rep;
243 constexpr
auto maxInput =
245 if (duration.count() > maxInput) {
248 constexpr
auto minInput =
250 if (duration.count() < minInput) {
254 IntermediateType{
static_cast<IntermediateRep
>(duration.count()) *
255 static_cast<IntermediateRep>(Period::num)};
257 return durationToPosixTime<SubsecondRatio>(intermediate);
267 template <
bool IsFloatingPo
int>
271 typename SubsecondRatio,
276 Tgt::period::num == 1,
277 "this implementation should only be used for subsecond granularity " 282 SubsecondRatio::num == 1,
"subsecond numerator should always be 1");
284 if (
LIKELY(seconds >= 0)) {
286 constexpr
auto maxSeconds = maxCount / Tgt::period::den;
289 if (
LIKELY(unsignedSeconds < maxSeconds)) {
293 if (
UNLIKELY(unsignedSeconds == maxSeconds)) {
294 constexpr
auto maxRemainder =
295 maxCount - (maxSeconds * Tgt::period::den);
296 constexpr
auto maxSubseconds =
297 (maxRemainder * SubsecondRatio::den) / Tgt::period::den;
298 if (subseconds <= 0) {
309 constexpr
auto minCount =
310 to_signed(std::numeric_limits<typename Tgt::rep>::lowest());
311 constexpr
auto minSeconds = (minCount / Tgt::period::den);
312 if (
LIKELY(seconds >= minSeconds)) {
316 if (
UNLIKELY(seconds == minSeconds - 1)) {
317 constexpr
auto maxRemainder =
318 minCount - (minSeconds * Tgt::period::den) + Tgt::period::den;
319 constexpr
auto maxSubseconds =
320 (maxRemainder * SubsecondRatio::den) / Tgt::period::den;
321 if (subseconds <= 0) {
324 if (subseconds >= maxSubseconds) {
337 typename SubsecondRatio,
346 SubsecondRatio::num == 1,
"subsecond numerator should always be 1");
354 "unusually limited floating point type");
356 std::numeric_limits<typename Tgt::rep>::lowest() <=
357 std::numeric_limits<Seconds>::lowest(),
358 "unusually limited floating point type");
376 typename SubsecondRatio,
382 Subseconds subseconds,
383 std::chrono::duration<Rep, std::ratio<1, 1>>
dummy)
385 using Tgt = decltype(
dummy);
386 static_assert(Tgt::period::num == 1,
"special case expecting num==1");
387 static_assert(Tgt::period::den == 1,
"special case expecting den==1");
389 SubsecondRatio::num == 1,
"subsecond numerator should always be 1");
391 auto outputSeconds = tryTo<typename Tgt::rep>(seconds);
392 if (outputSeconds.hasError()) {
397 return Tgt{
typename Tgt::rep(seconds) +
398 (
typename Tgt::rep(subseconds) / SubsecondRatio::den)};
402 if (
UNLIKELY(outputSeconds.value() < 0) && subseconds > 0) {
404 outputSeconds.value() ==
405 std::numeric_limits<typename Tgt::rep>::lowest())) {
408 return Tgt{outputSeconds.value() + 1};
411 return Tgt{outputSeconds.value()};
419 typename SubsecondRatio,
423 std::intmax_t Denominator>
426 Subseconds subseconds,
427 std::chrono::duration<Rep, std::ratio<1, Denominator>>
dummy)
429 using Tgt = decltype(
dummy);
430 static_assert(Tgt::period::num == 1,
"special case expecting num==1");
431 static_assert(Tgt::period::den != 1,
"special case expecting den!=1");
433 SubsecondRatio::num == 1,
"subsecond numerator should always be 1");
437 template check<Tgt, SubsecondRatio>(seconds, subseconds);
442 if (
LIKELY(seconds >= 0)) {
443 return std::chrono::duration_cast<Tgt>(
444 std::chrono::duration<typename Tgt::rep>{seconds}) +
445 std::chrono::duration_cast<Tgt>(
446 std::chrono::duration<typename Tgt::rep, SubsecondRatio>{
451 return std::chrono::duration_cast<Tgt>(
452 std::chrono::duration<typename Tgt::rep>{seconds + 1}) -
453 std::chrono::duration_cast<Tgt>(
454 std::chrono::duration<typename Tgt::rep, SubsecondRatio>{
455 SubsecondRatio::den - subseconds});
464 typename SubsecondRatio,
468 std::intmax_t Numerator>
471 Subseconds subseconds,
472 std::chrono::duration<Rep, std::ratio<Numerator, 1>>
dummy)
474 using Tgt = decltype(
dummy);
475 static_assert(Tgt::period::num != 1,
"special case expecting num!=1");
476 static_assert(Tgt::period::den == 1,
"special case expecting den==1");
478 SubsecondRatio::num == 1,
"subsecond numerator should always be 1");
480 if (
UNLIKELY(seconds < 0) && subseconds > 0) {
483 if (
UNLIKELY(seconds == std::numeric_limits<Seconds>::lowest())) {
491 return Tgt{
static_cast<typename Tgt::rep
>(seconds) / Tgt::period::num};
495 auto outputValue = (seconds / Tgt::period::num);
496 auto expectedOuput = tryTo<typename Tgt::rep>(outputValue);
497 if (expectedOuput.hasError()) {
501 return Tgt{expectedOuput.value()};
512 typename SubsecondRatio,
516 std::intmax_t Denominator,
517 std::intmax_t Numerator>
520 Subseconds subseconds,
521 std::chrono::duration<Rep, std::ratio<Numerator, Denominator>>
dummy)
523 using Tgt = decltype(
dummy);
525 Tgt::period::num != 1,
"should use special-case code when num==1");
527 Tgt::period::den != 1,
"should use special-case code when den==1");
529 SubsecondRatio::num == 1,
"subsecond numerator should always be 1");
538 using IntermediateType =
540 auto intermediate = posixTimeToDuration<SubsecondRatio>(
541 seconds, subseconds, IntermediateType{});
542 if (intermediate.hasError()) {
547 return tryTo<typename Tgt::rep>(
548 intermediate.value().count() / Tgt::period::num)
549 .then([](
typename Tgt::rep tgt) {
return Tgt{tgt}; });
554 typename SubsecondRatio,
559 Subseconds subseconds) {
561 SubsecondRatio::num == 1,
"subsecond numerator should always be 1");
565 const auto overflowSeconds = (subseconds / SubsecondRatio::den);
566 const auto remainder = (subseconds % SubsecondRatio::den);
567 if (std::numeric_limits<Seconds>::lowest() + 1 - overflowSeconds >
571 seconds = seconds - 1 + overflowSeconds;
572 subseconds = remainder + SubsecondRatio::den;
573 }
else if (
UNLIKELY(subseconds >= SubsecondRatio::den)) {
574 const auto overflowSeconds = (subseconds / SubsecondRatio::den);
575 const auto remainder = (subseconds % SubsecondRatio::den);
579 seconds += overflowSeconds;
580 subseconds = remainder;
583 return posixTimeToDuration<SubsecondRatio>(seconds, subseconds, Tgt{});
591 template <
typename Tgt>
592 typename std::enable_if<
596 return detail::tryPosixTimeToDuration<Tgt, std::nano>(ts.tv_sec, ts.tv_nsec);
602 template <
typename Tgt>
603 typename std::enable_if<
604 detail::is_duration<Tgt>::value,
607 return detail::tryPosixTimeToDuration<Tgt, std::micro>(tv.tv_sec, tv.tv_usec);
613 template <
typename Tgt,
typename Src>
614 typename std::enable_if<
618 return tryTo<typename Tgt::duration>(
value).then(
619 [](
typename Tgt::duration result) {
return Tgt(result); });
625 template <
typename Tgt,
typename Rep,
typename Period>
626 typename std::enable_if<
629 tryTo(
const std::chrono::duration<Rep, Period>& duration) {
630 auto result = detail::durationToPosixTime<std::nano>(duration);
631 if (result.hasError()) {
636 ts.tv_sec = result.value().first;
637 ts.tv_nsec = result.value().second;
644 template <
typename Tgt,
typename Rep,
typename Period>
645 typename std::enable_if<
648 tryTo(
const std::chrono::duration<Rep, Period>& duration) {
649 auto result = detail::durationToPosixTime<std::micro>(duration);
650 if (result.hasError()) {
655 tv.tv_sec = result.value().first;
656 tv.tv_usec = result.value().second;
663 template <
typename Tgt,
typename Clock,
typename Duration>
664 typename std::enable_if<
667 tryTo(
const std::chrono::time_point<Clock, Duration>& timePoint) {
668 return tryTo<Tgt>(timePoint.time_since_epoch());
674 template <
typename Tgt,
typename Src>
678 return tryTo<Tgt>(
value).thenOrThrow(
679 [](Tgt res) {
return res; },
static ConversionCode check(Seconds seconds, Subseconds subseconds)
static ConversionCode check(Seconds, Subseconds)
auto posixTimeToDuration(Seconds seconds, Subseconds subseconds, std::chrono::duration< Rep, std::ratio< 1, 1 >> dummy) -> Expected< decltype(dummy), ConversionCode >
—— Concurrent Priority Queue Implementation ——
Expected< Tgt, ConversionCode > tryPosixTimeToDuration(Seconds seconds, Subseconds subseconds)
bool_constant< true > true_type
constexpr auto to_unsigned(T const &t) -> typename std::make_unsigned< T >::type
static Expected< std::pair< time_t, long >, ConversionCode > durationToPosixTime(const std::chrono::duration< Rep, std::ratio< 1, 1 >> &duration)
std::enable_if< detail::is_chrono_conversion< Tgt, Src >::value, Tgt >::type to(const Src &value)
constexpr Unexpected< typename std::decay< Error >::type > makeUnexpected(Error &&)
static const char *const value
constexpr auto to_signed(T const &t) -> typename std::make_signed< T >::type
Expected< time_t, ConversionCode > chronoRangeCheck(Src value)
uint64_t value(const typename LockFreeRingBuffer< T, Atom >::Cursor &rbcursor)
bool_constant< false > false_type
std::enable_if< detail::is_duration< Tgt >::value, Expected< Tgt, ConversionCode > >::type tryTo(const struct timespec &ts)
std::chrono::duration< typename IntermediateTimeRep< Rep, std::is_floating_point< Rep >::value, std::is_signed< Rep >::value >::type, std::ratio< 1, Period::den >> IntermediateDuration
ConversionError makeConversionError(ConversionCode code, StringPiece input)