Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qcalendarmath_p.h
Go to the documentation of this file.
1// Copyright (C) 2022 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:significant reason:default
4
5#ifndef QCALENDARMATH_P_H
6#define QCALENDARMATH_P_H
7
8//
9// W A R N I N G
10// -------------
11//
12// This file is not part of the Qt API. It exists for the convenience
13// of q*calendar.cpp. This header file may change from version to version
14// without notice, or even be removed.
15//
16// We mean it.
17//
18
19#include <QtCore/private/qglobal_p.h>
20#include <QtCore/QtAlgorithms>
21
23
24namespace QRoundingDown {
25// Note: qgregoriancalendar.cpp contains some static asserts to verify this all works.
27#ifdef Q_CC_MSVC
28// MSVC 2019 doesn't believe in the constexpr-ness of the #else clause's version :-(
29#define QCALMATH_ISPOW2(b) ((b > 0) && !(b & (b - 1))) // See #else's comment.
30#else
31// Subtracting one toggles the least significant set bit and any unset bits less
32// significant than it, leaving other bits unchanged. Thus the & of this with
33// the original number preserves all more significant bits, clearing the least
34// significant. If there are no such bits, either our number was 0 or it only
35// had one bit set, hence is a power of two.
36template <typename Int>
37inline constexpr bool isPowerOfTwo(Int b) { return b > 0 && (b & (b - 1)) == 0; }
38#define QCALMATH_ISPOW2(b) QRoundingDownPrivate::isPowerOfTwo(b)
39#endif
40}
41/*
42 Division, rounding down (rather than towards zero).
43
44 From C++11 onwards, integer division is defined to round towards zero, so we
45 can rely on that when implementing this. This is only used with denominator b
46 > 0, so we only have to treat negative numerator, a, specially.
47
48 If a is a multiple of b, adding 1 before and subtracting it after dividing by
49 b gets us to where we should be (albeit by an eccentric path), since the
50 adding caused rounding up, undone by the subtracting. Otherwise, adding 1
51 doesn't change the result of dividing by b; and we want one less than that
52 result. This is equivalent to subtracting b - 1 and simply dividing, except
53 when that subtraction would underflow.
54
55 For the remainder, with negative a, aside from having to add one and subtract
56 it later to deal with the exact multiples, we can simply use the truncating
57 remainder and then add b. When b is a power of two we can, of course, get the
58 remainder correctly by the same masking that works for positive a.
59*/
60
61// Fall-back, to ensure intelligible error messages on mis-use:
62template <unsigned b, typename Int, std::enable_if_t<(int(b) < 2), bool> = true>
63constexpr auto qDivMod(Int)
64{
65 static_assert(b, "Division by 0 is undefined");
66 // Use complement of earlier cases || new check, to ensure only one error:
67 static_assert(!b || int(b) > 0, "Denominator is too big");
68 static_assert(int(b) < 1 || b > 1, "Division by 1 is fautous");
69 struct R { Int quotient; Int remainder; };
70 return R { 0, 0 };
71}
72
73template <unsigned b, typename Int,
74 std::enable_if_t<(b > 1) && !QCALMATH_ISPOW2(b) && (int(b) > 0),
75 bool> = true>
76constexpr auto qDivMod(Int a)
77{
78 struct R { Int quotient; Int remainder; };
79 if constexpr (std::is_signed_v<Int>) {
80 if (a < 0) {
81 ++a; // can't overflow, it's negative
82 return R { Int(a / int(b) - 1), Int(a % int(b) - 1 + int(b)) };
83 }
84 }
85 return R { Int(a / int(b)), Int(a % int(b)) };
86}
87
88template <unsigned b, typename Int,
89 std::enable_if_t<(b > 1) && QCALMATH_ISPOW2(b) && (int(b) > 0),
90 bool> = true>
91constexpr auto qDivMod(Int a)
92{
93 constexpr unsigned w = qCountTrailingZeroBits(b);
94 struct R { Int quotient; Int remainder; };
95 if constexpr (std::is_signed_v<Int>) {
96 if (a < 0)
97 return R { Int((a + 1) / int(b) - 1), Int(a & int(b - 1)) };
98 }
99 return R { Int(a >> w), Int(a & int(b - 1)) };
100}
101
102#undef QCALMATH_ISPOW2
103// </kludge>
104
105template <unsigned b, typename Int> constexpr Int qDiv(Int a) { return qDivMod<b>(a).quotient; }
106template <unsigned b, typename Int> constexpr Int qMod(Int a) { return qDivMod<b>(a).remainder; }
107
108} // QRoundingDown
109
111// Julian Day number of Gregorian 1 BCE, February 29th:
112inline constexpr qint64 LeapDayGregorian1Bce = 1721119;
113// Aside from (maybe) some turns of centuries, one year in four is leap:
114inline constexpr unsigned FourYears = 4 * 365 + 1;
115inline constexpr unsigned FiveMonths = 31 + 30 + 31 + 30 + 31; // Mar-Jul or Aug-Dec.
116
117constexpr auto yearMonthToYearDays(int year, int month)
118{
119 // Pre-digests year and month to (possibly denormal) year count and day-within-year.
120 struct R { qint64 year; qint64 days; };
121 if (year < 0) // Represent -N BCE as 1-N so year numbering is contiguous.
122 ++year;
123 month -= 3; // Adjust month numbering so March = 0, ...
124 if (month < 0) { // and Jan = 10, Feb = 11, in the previous year.
125 --year;
126 month += 12;
127 }
128 return R { year, QRoundingDown::qDiv<5>(FiveMonths * month + 2) };
129}
130
131constexpr auto dayInYearToYmd(int dayInYear)
132{
133 // The year is an adjustment to the year for which dayInYear may be denormal.
134 struct R { int year; int month; int day; };
135 // Shared code for Julian and Milankovic (at least).
136 using namespace QRoundingDown;
137 const auto month5Day = qDivMod<FiveMonths>(5 * dayInYear + 2);
138 // Its remainder changes by 5 per day, except at roughly monthly quotient steps.
139 const auto yearMonth = qDivMod<12>(month5Day.quotient + 2);
140 return R { yearMonth.quotient, yearMonth.remainder + 1, qDiv<5>(month5Day.remainder) + 1 };
141}
142}
143
144QT_END_NAMESPACE
145
146#endif // QCALENDARMATH_P_H
\inmodule QtCore
Definition qatomic.h:114
\macro Q_ATOMIC_INTnn_IS_SUPPORTED
Definition qatomic.h:125
The QCalendarBackend class provides basic calendaring functions.
The QGregorianCalendar class implements the Gregorian calendar.
The QJulianCalendar class provides Julian calendar system implementation.
The QMilankovicCalendar class provides Milanković calendar system implementation.
The QRomanCalendar class is a shared base for calendars based on the ancient Roman calendar.
const QCalendarBackend * fromEnum(QCalendar::System system)
const QCalendarBackend * fromName(QAnyStringView name)
void registerCustomBackend(QCalendarBackend *backend, const QStringList &names)
bool isGregorian(const QCalendarBackend *backend) const
const QCalendarBackend * fromIndex(size_t index)
QStringList backendNames(const QCalendarBackend *backend)
const QCalendarBackend * gregorian()
constexpr qint64 LeapDayGregorian1Bce
constexpr auto dayInYearToYmd(int dayInYear)
constexpr auto yearMonthToYearDays(int year, int month)
constexpr unsigned FourYears
constexpr unsigned FiveMonths
constexpr Int qDiv(Int a)
constexpr Int qMod(Int a)
constexpr auto qDivMod(Int)
Combined button and popup list for selecting options.
#define SAFE_D()
Q_GLOBAL_STATIC(QtPrivate::QCalendarRegistry, calendarRegistry)
#define CASE(E, member)
#define QCALMATH_ISPOW2(b)
quint16 m_longMonthStandalone_size
QLocaleData::DataRange monthName(QLocale::FormatType type) const
quint16 m_shortMonthStandalone_idx
quint8 m_narrowMonthStandalone_size
quint8 m_shortMonthStandalone_size
quint16 m_longMonthStandalone_idx
quint16 m_narrowMonthStandalone_idx
QLocaleData::DataRange standaloneMonthName(QLocale::FormatType type) const
bool operator()(QAnyStringView lhs, QAnyStringView rhs) const
Definition qcalendar.cpp:32