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
22#include <limits>
23
25
26namespace QRoundingDown {
27// Note: qgregoriancalendar.cpp contains some static asserts to verify this all works.
29#ifdef Q_CC_MSVC
30// MSVC 2019 doesn't believe in the constexpr-ness of the #else clause's version :-(
31#define QCALMATH_ISPOW2(b) ((b > 0) && !(b & (b - 1))) // See #else's comment.
32#else
33// Subtracting one toggles the least significant set bit and any unset bits less
34// significant than it, leaving other bits unchanged. Thus the & of this with
35// the original number preserves all more significant bits, clearing the least
36// significant. If there are no such bits, either our number was 0 or it only
37// had one bit set, hence is a power of two.
38template <typename Int>
39inline constexpr bool isPowerOfTwo(Int b) { return b > 0 && (b & (b - 1)) == 0; }
40#define QCALMATH_ISPOW2(b) QRoundingDownPrivate::isPowerOfTwo(b)
41#endif
42}
43/*
44 Division, rounding down (rather than towards zero).
45
46 From C++11 onwards, integer division is defined to round towards zero, so we
47 can rely on that when implementing this. This is only used with denominator b
48 > 0, so we only have to treat negative numerator, a, specially.
49
50 If a is a multiple of b, adding 1 before and subtracting it after dividing by
51 b gets us to where we should be (albeit by an eccentric path), since the
52 adding caused rounding up, undone by the subtracting. Otherwise, adding 1
53 doesn't change the result of dividing by b; and we want one less than that
54 result. This is equivalent to subtracting b - 1 and simply dividing, except
55 when that subtraction would underflow.
56
57 For the remainder, with negative a, aside from having to add one and subtract
58 it later to deal with the exact multiples, we can simply use the truncating
59 remainder and then add b. When b is a power of two we can, of course, get the
60 remainder correctly by the same masking that works for positive a.
61*/
62
63// Fall-back, to ensure intelligible error messages on mis-use:
64template <unsigned b, typename Int, std::enable_if_t<(int(b) < 2), bool> = true>
65constexpr auto qDivMod(Int)
66{
67 static_assert(b, "Division by 0 is undefined");
68 // Use complement of earlier cases || new check, to ensure only one error:
69 static_assert(!b || int(b) > 0, "Denominator is too big");
70 static_assert(int(b) < 1 || b > 1, "Division by 1 is fautous");
71 struct R { Int quotient; Int remainder; };
72 return R { 0, 0 };
73}
74
75template <unsigned b, typename Int,
76 std::enable_if_t<(b > 1) && !QCALMATH_ISPOW2(b) && (int(b) > 0),
77 bool> = true>
78constexpr auto qDivMod(Int a)
79{
80 struct R { Int quotient; Int remainder; };
81 if constexpr (std::is_signed_v<Int>) {
82 if (a < 0) {
83 ++a; // can't overflow, it's negative
84 return R { Int(a / int(b) - 1), Int(a % int(b) - 1 + int(b)) };
85 }
86 }
87 return R { Int(a / int(b)), Int(a % int(b)) };
88}
89
90template <unsigned b, typename Int,
91 std::enable_if_t<(b > 1) && QCALMATH_ISPOW2(b) && (int(b) > 0),
92 bool> = true>
93constexpr auto qDivMod(Int a)
94{
95 constexpr unsigned w = qCountTrailingZeroBits(b);
96 struct R { Int quotient; Int remainder; };
97 if constexpr (std::is_signed_v<Int>) {
98 if (a < 0)
99 return R { Int((a + 1) / int(b) - 1), Int(a & int(b - 1)) };
100 }
101 return R { Int(a >> w), Int(a & int(b - 1)) };
102}
103
104#undef QCALMATH_ISPOW2
105// </kludge>
106
107template <unsigned b, typename Int> constexpr Int qDiv(Int a) { return qDivMod<b>(a).quotient; }
108template <unsigned b, typename Int> constexpr Int qMod(Int a) { return qDivMod<b>(a).remainder; }
109
110} // QRoundingDown
111
113// Julian Day number of Gregorian 1 BCE, February 29th:
114inline constexpr qint64 LeapDayGregorian1Bce = 1721119;
115// Aside from (maybe) some turns of centuries, one year in four is leap:
116inline constexpr unsigned FourYears = 4 * 365 + 1;
117inline constexpr unsigned FiveMonths = 31 + 30 + 31 + 30 + 31; // Mar-Jul or Aug-Dec.
118
119constexpr auto yearMonthToYearDays(int year, int month)
120{
121 // Pre-digests year and month to (possibly denormal) year count and day-within-year.
122 struct R { qint64 year; qint64 days; };
123 if (year < 0) // Represent -N BCE as 1-N so year numbering is contiguous.
124 ++year;
125 month -= 3; // Adjust month numbering so March = 0, ...
126 if (month < 0) { // and Jan = 10, Feb = 11, in the previous year.
127 --year;
128 month += 12;
129 }
130 return R { year, QRoundingDown::qDiv<5>(FiveMonths * month + 2) };
131}
132
133constexpr auto dayInYearToYmd(int dayInYear)
134{
135 // The year is an adjustment to the year for which dayInYear may be denormal.
136 struct R { int year; int month; int day; };
137 // Shared code for Julian and Milankovic (at least).
138 using namespace QRoundingDown;
139 const auto month5Day = qDivMod<FiveMonths>(5 * dayInYear + 2);
140 // Its remainder changes by 5 per day, except at roughly monthly quotient steps.
141 const auto yearMonth = qDivMod<12>(month5Day.quotient + 2);
142 return R { yearMonth.quotient, yearMonth.remainder + 1, qDiv<5>(month5Day.remainder) + 1 };
143}
144}
145
146QT_END_NAMESPACE
147
148#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