Brief description
The following code fails to compile due to an int addition overflow:
#include <chrono>
using namespace std::chrono;
constexpr auto wd = weekday(sys_days::max());
https://godbolt.org/z/K6dW7bvYq
Details
The overflow occurs in the evaluation of _Tp + 4 below
_NODISCARD static constexpr unsigned int _Weekday_from_days(int _Tp) noexcept {
return static_cast<unsigned int>(_Tp >= -4 ? (_Tp + 4) % 7 : (_Tp + 5) % 7 + 6);
}
Indeed, this addition overflows whenever _Tp > INT_MAX - 4.
Fixes
Provided that the range of long long int is larger than that of int, the obvious fix is declaring _Tp as long long int and an alternative is this:
_NODISCARD static constexpr unsigned int _Weekday_from_days(int _Tp) noexcept {
auto const m = unsigned(_Tp) + (_Tp >= 0 ? 4 : 0);
auto const w = m % 7;
__assume(w != 7); // not necessary but improves codegen
return w;
}
This alternative is better than the obvious fix and better than the current implementation. Indeed, with this fix the codegen of weekday::weekday(const sys_days&) becomes branch-free and avoids div instructions on x64, x86 and arm64.
Test
The alternative above works as an exhaustive test shows:
int main() {
unsigned int encoding = weekday(sys_days::min()).c_encoding();
for (auto s = sys_days::min(); s < sys_days::max(); s += days(1)) {
assert(weekday_ctr(s).c_encoding() == encoding);
++encoding;
if (encoding == 7)
encoding = 0;
}
// One more to go:
assert(weekday_ctr(sys_days::max()).c_encoding() == encoding);
std::puts("Success.");
}
(where weekday_ctr is an impersonation of weekday::weekday(const sys_days&) using the fixed _Weekday_from_days.)
Brief description
The following code fails to compile due to an
intaddition overflow:https://godbolt.org/z/K6dW7bvYq
Details
The overflow occurs in the evaluation of
_Tp + 4belowIndeed, this addition overflows whenever
_Tp > INT_MAX - 4.Fixes
Provided that the range of
long long intis larger than that ofint, the obvious fix is declaring_Tpaslong long intand an alternative is this:This alternative is better than the obvious fix and better than the current implementation. Indeed, with this fix the codegen of
weekday::weekday(const sys_days&)becomes branch-free and avoidsdivinstructions on x64, x86 and arm64.Test
The alternative above works as an exhaustive test shows:
(where
weekday_ctris an impersonation ofweekday::weekday(const sys_days&)using the fixed_Weekday_from_days.)