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