vendredi 6 août 2021

is it possible to overload std::chrono::duration_cast?

I have a device that reports time as integer seconds and fractional seconds in clock ticks. For this particular device, the clock operates a 256MHz. I've defined a custom resolution that I use in duration and time_points:

using Res = std::chrono::duration<uint64_t, std::ratio<1, 256'000'000>>;

(unless it is pertinent, I'd rather not debate uint vs int).

This resolution is adequate for representing times since 1970, with overflow around 2763.

Given,

#include <iostream>
#include <chrono>

int main() {
    using Res = std::chrono::duration<uint64_t, std::ratio<1, 256'000'000>>;
    using namespace std::chrono;
    using TimePoint = time_point<system_clock, Res>;

    auto s_now = system_clock::now();

    auto simple = time_point_cast<Res>(s_now);

    auto s_sec = duration_cast<seconds>(s_now.time_since_epoch());
    auto hard = TimePoint(Res(s_sec));
    hard += duration_cast<Res>(s_now.time_since_epoch() - s_sec);

    std::cout << "s_now  " << s_now.time_since_epoch().count() << "\t" << s_sec.count() << "\n"
              << "simple " << simple.time_since_epoch().count() << "\t" << duration_cast<seconds>(simple.time_since_epoch()).count() << "\n"
              << "hard   " << hard.time_since_epoch().count()  << "\t" << duration_cast<seconds>(hard.time_since_epoch()).count() << "\n"
;
    return 0;
}

then simple is not equal to hard. The output might be something like this:

s_now  1628286679505051812  1628286679
simple 121693484773940438   475365174
hard   416841389953293263   1628286679

What happens is that time_point_cast overflows the int Rep for system_clock::duration.

Based on https://stackoverflow.com/a/51226923/9220132 it would seem that this is legal and moral, but it does not taste great. This limitation is a much too easy to produce source of bugs.

If there were a way for me to define the implementation of casting to my very high resolution type such that I protect against overflow, that would be ideal. Knowing to use a custom helper function instead of casting is just asking for trouble, because someone will forget some time and the bug might go unnoticed into production.

Aucun commentaire:

Enregistrer un commentaire