Refactor QGregorianCalendar::julianFromParts to return std::optional

It's a private static used to optimize internal use, so we can freely
get rid of its out parameter this way.

Change-Id: Id62612987f10ecbbd9702610fd172286adbfd442
Reviewed-by: Marc Mutz <marc.mutz@qt.io>
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
Edward Welbourne 2023-04-26 20:43:24 +02:00
parent 22909abeae
commit 4c93b9c1d0
5 changed files with 43 additions and 48 deletions

View File

@ -63,9 +63,9 @@ static inline QDate fixedDate(QCalendar::YearMonthDay parts)
{
if (parts.year) {
parts.day = qMin(parts.day, QGregorianCalendar::monthLength(parts.month, parts.year));
qint64 jd;
if (QGregorianCalendar::julianFromParts(parts.year, parts.month, parts.day, &jd))
return QDate::fromJulianDay(jd);
const auto jd = QGregorianCalendar::julianFromParts(parts.year, parts.month, parts.day);
if (jd)
return QDate::fromJulianDay(*jd);
}
return QDate();
}
@ -437,9 +437,7 @@ QDate::QDate(int y, int m, int d)
{
static_assert(QDate::maxJd() == JulianDayMax);
static_assert(QDate::minJd() == JulianDayMin);
if (!QGregorianCalendar::julianFromParts(y, m, d, &jd))
jd = nullJd();
jd = QGregorianCalendar::julianFromParts(y, m, d).value_or(nullJd());
}
QDate::QDate(int y, int m, int d, QCalendar cal)
@ -698,9 +696,8 @@ int QDate::dayOfYear(QCalendar cal) const
int QDate::dayOfYear() const
{
if (isValid()) {
qint64 first;
if (QGregorianCalendar::julianFromParts(year(), 1, 1, &first))
return jd - first + 1;
if (const auto first = QGregorianCalendar::julianFromParts(year(), 1, 1))
return jd - *first + 1;
}
return 0;
}
@ -1303,11 +1300,9 @@ QString QDate::toString(QStringView format, QCalendar cal) const
*/
bool QDate::setDate(int year, int month, int day)
{
if (QGregorianCalendar::julianFromParts(year, month, day, &jd))
return true;
jd = nullJd();
return false;
const auto maybe = QGregorianCalendar::julianFromParts(year, month, day);
jd = maybe.value_or(nullJd());
return bool(maybe);
}
/*!
@ -2698,10 +2693,11 @@ QDateTimePrivate::ZoneState QDateTimePrivate::expressUtcAsLocal(qint64 utcMSecs)
// dates might be right, and adjust by the number of days that was off:
const qint64 jd = msecsToJulianDay(utcMSecs);
const auto ymd = QGregorianCalendar::partsFromJulian(jd);
qint64 fakeJd, diffMillis, fakeUtc;
if (Q_UNLIKELY(!QGregorianCalendar::julianFromParts(systemTimeYearMatching(ymd.year),
ymd.month, ymd.day, &fakeJd)
|| mul_overflow(jd - fakeJd, std::integral_constant<qint64, MSECS_PER_DAY>(),
qint64 diffMillis, fakeUtc;
const auto fakeJd = QGregorianCalendar::julianFromParts(systemTimeYearMatching(ymd.year),
ymd.month, ymd.day);
if (Q_UNLIKELY(!fakeJd
|| mul_overflow(jd - *fakeJd, std::integral_constant<qint64, MSECS_PER_DAY>(),
&diffMillis)
|| sub_overflow(utcMSecs, diffMillis, &fakeUtc))) {
return result;
@ -2724,11 +2720,11 @@ static auto millisToWithinRange(qint64 millis)
qint64 shifted = 0;
bool good = false;
} result;
qint64 jd = msecsToJulianDay(millis), fakeJd;
qint64 jd = msecsToJulianDay(millis);
auto ymd = QGregorianCalendar::partsFromJulian(jd);
result.good = QGregorianCalendar::julianFromParts(systemTimeYearMatching(ymd.year),
ymd.month, ymd.day, &fakeJd)
&& !daysAndMillisOverflow(fakeJd - jd, millis, &result.shifted);
const auto fakeJd = QGregorianCalendar::julianFromParts(systemTimeYearMatching(ymd.year),
ymd.month, ymd.day);
result.good = fakeJd && !daysAndMillisOverflow(*fakeJd - jd, millis, &result.shifted);
return result;
}

View File

@ -98,7 +98,10 @@ int QGregorianCalendar::weekDayOfJulian(qint64 jd)
bool QGregorianCalendar::dateToJulianDay(int year, int month, int day, qint64 *jd) const
{
return julianFromParts(year, month, day, jd);
const auto maybe = julianFromParts(year, month, day);
if (maybe)
*jd = *maybe;
return bool(maybe);
}
QCalendar::YearMonthDay QGregorianCalendar::julianDayToDate(qint64 jd) const
@ -175,17 +178,15 @@ constexpr qint64 BaseJd = LeapDayGregorian1Bce;
// Every four centures there are 97 leap years:
constexpr unsigned FourCenturies = 400 * 365 + 97;
bool QGregorianCalendar::julianFromParts(int year, int month, int day, qint64 *jd)
std::optional<qint64> QGregorianCalendar::julianFromParts(int year, int month, int day)
{
Q_ASSERT(jd);
if (!validParts(year, month, day))
return false;
return std::nullopt;
const auto yearDays = yearMonthToYearDays(year, month);
const qint64 y = yearDays.year;
const qint64 fromYear = 365 * y + qDiv<4>(y) - qDiv<100>(y) + qDiv<400>(y);
*jd = fromYear + yearDays.days + day + BaseJd ;
return true;
return fromYear + yearDays.days + day + BaseJd;
}
QCalendar::YearMonthDay QGregorianCalendar::partsFromJulian(qint64 jd)

View File

@ -17,6 +17,8 @@
#include "qromancalendar_p.h"
#include <optional>
QT_BEGIN_NAMESPACE
class Q_CORE_EXPORT QGregorianCalendar : public QRomanCalendar
@ -45,7 +47,7 @@ public:
static int monthLength(int month, int year);
static bool validParts(int year, int month, int day);
static QCalendar::YearMonthDay partsFromJulian(qint64 jd);
static bool julianFromParts(int year, int month, int day, qint64 *jd);
static std::optional<qint64> julianFromParts(int year, int month, int day);
// Used internally:
static int yearStartWeekDay(int year);
static int yearSharingWeekDays(QDate date);

View File

@ -167,10 +167,8 @@ struct tm timeToTm(qint64 localDay, int secs, QDateTimePrivate::DaylightStatus d
inline std::optional<qint64> tmToJd(const struct tm &date)
{
qint64 jd;
return QGregorianCalendar::julianFromParts(qYearFromTmYear(date.tm_year),
date.tm_mon + 1, date.tm_mday, &jd)
? std::optional<qint64>(jd) : std::nullopt;
date.tm_mon + 1, date.tm_mday);
}
#define IC(N) std::integral_constant<qint64, N>()
@ -374,9 +372,7 @@ QDateTimePrivate::ZoneState mapLocalTime(qint64 local, QDateTimePrivate::Dayligh
SystemMillisRange computeSystemMillisRange()
{
// Assert this here, as this is called just once, in a static initialization.
[[maybe_unused]] qint64 epochJd;
Q_ASSERT(QGregorianCalendar::julianFromParts(1970, 1, 1, &epochJd)
&& epochJd == JULIAN_DAY_FOR_EPOCH);
Q_ASSERT(QGregorianCalendar::julianFromParts(1970, 1, 1) == JULIAN_DAY_FOR_EPOCH);
constexpr qint64 TIME_T_MAX = std::numeric_limits<time_t>::max();
using Bounds = std::numeric_limits<qint64>;

View File

@ -368,13 +368,12 @@ void tst_QCalendar::gregory()
// dateToJulianDay() and weekDayOfJulian():
if (!year) // No year zero.
continue;
qint64 first, last;
QVERIFY2(QGregorianCalendar::julianFromParts(year, 1, 1, &first),
"Only year zero should lack a first day");
const auto first = QGregorianCalendar::julianFromParts(year, 1, 1);
QVERIFY2(first, "Only year zero should lack a first day");
QCOMPARE(QGregorianCalendar::yearStartWeekDay(year),
QGregorianCalendar::weekDayOfJulian(first));
QVERIFY2(QGregorianCalendar::julianFromParts(year, 12, 31, &last),
"Only year zero should lack a last day");
QGregorianCalendar::weekDayOfJulian(*first));
const auto last = QGregorianCalendar::julianFromParts(year, 12, 31);
QVERIFY2(last, "Only year zero should lack a last day");
const int lastTwo = (year + (year < 0 ? 1 : 0)) % 100 + (year < -1 ? 100 : 0);
const QDate probe(year, lastTwo && lastTwo <= 12 ? lastTwo : 8,
@ -392,13 +391,14 @@ void tst_QCalendar::gregory()
if (year > 0 && lastTwo > 31)
QCOMPARE(match % 100, lastTwo);
// Its first and last days of the year match those of year:
qint64 day;
QVERIFY(QGregorianCalendar::julianFromParts(match, 1, 1, &day));
QCOMPARE(QGregorianCalendar::weekDayOfJulian(day),
QGregorianCalendar::weekDayOfJulian(first));
QVERIFY(QGregorianCalendar::julianFromParts(match, 12, 31, &day));
QCOMPARE(QGregorianCalendar::weekDayOfJulian(day),
QGregorianCalendar::weekDayOfJulian(last));
auto day = QGregorianCalendar::julianFromParts(match, 1, 1);
QVERIFY(day);
QCOMPARE(QGregorianCalendar::weekDayOfJulian(*day),
QGregorianCalendar::weekDayOfJulian(*first));
day = QGregorianCalendar::julianFromParts(match, 12, 31);
QVERIFY(day);
QCOMPARE(QGregorianCalendar::weekDayOfJulian(*day),
QGregorianCalendar::weekDayOfJulian(*last));
}
}
}