QCalendar: Thread-safe calendar backend registration
All calendar backend accounting was moved into QCalendarRegistry class (renamed from Registry). Calendar backends are no longer registered inside constructors, because in multithreaded environment this may lead to incompletely initialized instances becoming visible via QCalendar API in multithreaded environment. All system backends are registered by QCalendarRegistry itself when they are needed. New method QCalendarBackend::registerCustomBackend() is provided to register any 3rd-party calendar backends. Registration by names was also simplified. The list of names is now passed to QCalendarBackend::registerCustomBackend(). The checks are provided to ensure that all system backends have non-conflicting names. Name conflicts for custom backends are resolved in favor of earlier registered backends, as it is already the case in the existing code. The documentation was updated to reflect that. Method QCalendarBackend::names() was added to query the list of names associated with a backend after it is registered. Calendar backend deregistration was completely removed because it is not possible to perform it safely without reference counting. Fixes: QTBUG-93004 Pick-to: 6.2 Change-Id: I0ab1eccc02fdd1e1c66b5e5dd076c93de32d5a49 Reviewed-by: Paul Wicking <paul.wicking@qt.io> Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
This commit is contained in:
parent
f84adba102
commit
d0ae1ef33a
File diff suppressed because it is too large
Load Diff
@ -132,7 +132,7 @@ public:
|
||||
Q_ENUM(System)
|
||||
class SystemId
|
||||
{
|
||||
const size_t id;
|
||||
size_t id;
|
||||
friend class QCalendarBackend;
|
||||
constexpr bool isInEnum() const { return id <= size_t(QCalendar::System::Last); }
|
||||
constexpr explicit SystemId(QCalendar::System e) : id(size_t(e)) { }
|
||||
|
@ -61,6 +61,10 @@
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
namespace QtPrivate {
|
||||
class QCalendarRegistry;
|
||||
}
|
||||
|
||||
// Locale-related parts, mostly handled in ../text/qlocale.cpp
|
||||
|
||||
struct QCalendarLocale {
|
||||
@ -90,9 +94,14 @@ struct QCalendarLocale {
|
||||
class Q_CORE_EXPORT QCalendarBackend
|
||||
{
|
||||
friend class QCalendar;
|
||||
friend class QtPrivate::QCalendarRegistry;
|
||||
|
||||
public:
|
||||
virtual ~QCalendarBackend();
|
||||
virtual QString name() const = 0;
|
||||
|
||||
QStringList names() const;
|
||||
|
||||
QCalendar::System calendarSystem() const;
|
||||
QCalendar::SystemId calendarId() const { return m_id; }
|
||||
// Date queries:
|
||||
@ -131,25 +140,29 @@ public:
|
||||
QDate dateOnly, QTime timeOnly,
|
||||
const QLocale &locale) const;
|
||||
|
||||
bool isGregorian() const;
|
||||
|
||||
QCalendar::SystemId registerCustomBackend(const QStringList &names);
|
||||
|
||||
// Calendar enumeration by name:
|
||||
static QStringList availableCalendars();
|
||||
|
||||
protected:
|
||||
QCalendarBackend(const QString &name, QCalendar::System system = QCalendar::System::User);
|
||||
|
||||
// Locale support:
|
||||
virtual const QCalendarLocale *localeMonthIndexData() const = 0;
|
||||
virtual const char16_t *localeMonthData() const = 0;
|
||||
|
||||
bool registerAlias(const QString &name);
|
||||
|
||||
private:
|
||||
const QCalendar::SystemId m_id;
|
||||
QCalendar::SystemId m_id;
|
||||
|
||||
void setIndex(size_t index);
|
||||
|
||||
// QCalendar's access to its registry:
|
||||
static const QCalendarBackend *fromName(QAnyStringView name);
|
||||
static const QCalendarBackend *fromId(QCalendar::SystemId id);
|
||||
// QCalendar's access to singletons:
|
||||
static const QCalendarBackend *fromEnum(QCalendar::System system);
|
||||
static const QCalendarBackend *gregorian();
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
@ -60,20 +60,19 @@ using namespace QRoundingDown;
|
||||
\sa QRomanCalendar, QJulianCalendar, QCalendar
|
||||
*/
|
||||
|
||||
QGregorianCalendar::QGregorianCalendar()
|
||||
: QRomanCalendar(QStringLiteral("Gregorian"), QCalendar::System::Gregorian)
|
||||
{
|
||||
if (calendarId().isValid()) {
|
||||
Q_ASSERT(calendarSystem() == QCalendar::System::Gregorian);
|
||||
registerAlias(QStringLiteral("gregory"));
|
||||
} // else: being ignored in favor of a duplicate created at the same time
|
||||
}
|
||||
|
||||
QString QGregorianCalendar::name() const
|
||||
{
|
||||
return QStringLiteral("Gregorian");
|
||||
}
|
||||
|
||||
QStringList QGregorianCalendar::nameList()
|
||||
{
|
||||
return {
|
||||
QStringLiteral("Gregorian"),
|
||||
QStringLiteral("gregory"),
|
||||
};
|
||||
}
|
||||
|
||||
bool QGregorianCalendar::isLeapYear(int year) const
|
||||
{
|
||||
return leapTest(year);
|
||||
|
@ -60,9 +60,9 @@ class Q_CORE_EXPORT QGregorianCalendar : public QRomanCalendar
|
||||
// TODO: provide static methods, called by the overrides, that can be called
|
||||
// directly by QDate to optimize various parts.
|
||||
public:
|
||||
QGregorianCalendar();
|
||||
// Calendar property:
|
||||
QString name() const override;
|
||||
static QStringList nameList();
|
||||
// Date queries:
|
||||
bool isLeapYear(int year) const override;
|
||||
// Julian Day conversions:
|
||||
|
@ -73,9 +73,6 @@ public:
|
||||
protected:
|
||||
const QCalendarLocale *localeMonthIndexData() const override;
|
||||
const char16_t *localeMonthData() const override;
|
||||
// (The INTEGRITY compiler got upset at: using QCalendarBackend:QCalendarBackend;)
|
||||
QHijriCalendar(const QString &name, QCalendar::System id = QCalendar::System::User)
|
||||
: QCalendarBackend(name, id) {}
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
@ -72,23 +72,22 @@ using namespace QRoundingDown;
|
||||
\sa QHijriCalendar, QCalendar
|
||||
*/
|
||||
|
||||
QIslamicCivilCalendar::QIslamicCivilCalendar()
|
||||
: QHijriCalendar(QStringLiteral("Islamic Civil"), QCalendar::System::IslamicCivil)
|
||||
{
|
||||
if (calendarId().isValid()) {
|
||||
Q_ASSERT(calendarSystem() == QCalendar::System::IslamicCivil);
|
||||
registerAlias(QStringLiteral("islamic-civil")); // CLDR name
|
||||
registerAlias(QStringLiteral("islamicc")); // old CLDR name, still (2018) used by Mozilla
|
||||
// Until we have a oncrete implementation that knows all the needed ephemerides:
|
||||
registerAlias(QStringLiteral("Islamic"));
|
||||
} // else: being ignored in favor of a duplicate created at the same time
|
||||
}
|
||||
|
||||
QString QIslamicCivilCalendar::name() const
|
||||
{
|
||||
return QStringLiteral("Islamic Civil");
|
||||
}
|
||||
|
||||
QStringList QIslamicCivilCalendar::nameList()
|
||||
{
|
||||
return {
|
||||
QStringLiteral("Islamic Civil"),
|
||||
QStringLiteral("islamic-civil"), // CLDR name
|
||||
QStringLiteral("islamicc"), // old CLDR name, still (2018) used by Mozilla
|
||||
// Until we have a concrete implementation that knows all the needed ephemerides:
|
||||
QStringLiteral("Islamic"),
|
||||
};
|
||||
}
|
||||
|
||||
bool QIslamicCivilCalendar::isLeapYear(int year) const
|
||||
{
|
||||
if (year == QCalendar::Unspecified)
|
||||
|
@ -60,9 +60,9 @@ QT_BEGIN_NAMESPACE
|
||||
class Q_CORE_EXPORT QIslamicCivilCalendar : public QHijriCalendar
|
||||
{
|
||||
public:
|
||||
QIslamicCivilCalendar();
|
||||
// Calendar properties:
|
||||
QString name() const override;
|
||||
static QStringList nameList();
|
||||
// Date queries:
|
||||
bool isLeapYear(int year) const override;
|
||||
// Julian Day conversions:
|
||||
|
@ -113,20 +113,19 @@ qint64 firstDayOfYear(int year, int cycleNo)
|
||||
page on Solar Hijri Calendar}
|
||||
*/
|
||||
|
||||
QJalaliCalendar::QJalaliCalendar()
|
||||
: QCalendarBackend(QStringLiteral("Jalali"), QCalendar::System::Jalali)
|
||||
{
|
||||
if (calendarId().isValid()) {
|
||||
Q_ASSERT(calendarSystem() == QCalendar::System::Jalali);
|
||||
registerAlias(QStringLiteral("Persian"));
|
||||
} // else: being ignored in favor of a duplicate created at the same time
|
||||
}
|
||||
|
||||
QString QJalaliCalendar::name() const
|
||||
{
|
||||
return QStringLiteral("Jalali");
|
||||
}
|
||||
|
||||
QStringList QJalaliCalendar::nameList()
|
||||
{
|
||||
return {
|
||||
QStringLiteral("Jalali"),
|
||||
QStringLiteral("Persian"),
|
||||
};
|
||||
}
|
||||
|
||||
bool QJalaliCalendar::isLeapYear(int year) const
|
||||
{
|
||||
if (year == QCalendar::Unspecified)
|
||||
|
@ -60,9 +60,9 @@ QT_BEGIN_NAMESPACE
|
||||
class Q_CORE_EXPORT QJalaliCalendar : public QCalendarBackend
|
||||
{
|
||||
public:
|
||||
QJalaliCalendar();
|
||||
// Calendar properties:
|
||||
QString name() const override;
|
||||
static QStringList nameList();
|
||||
// Date queries:
|
||||
int daysInMonth(int month, int year = QCalendar::Unspecified) const override;
|
||||
bool isLeapYear(int year) const override;
|
||||
|
@ -75,17 +75,16 @@ using namespace QRoundingDown;
|
||||
Julian Calendar}
|
||||
*/
|
||||
|
||||
QJulianCalendar::QJulianCalendar()
|
||||
: QRomanCalendar(QStringLiteral("Julian"), QCalendar::System::Julian)
|
||||
{
|
||||
Q_ASSERT(calendarSystem() == QCalendar::System::Julian || !calendarId().isValid());
|
||||
}
|
||||
|
||||
QString QJulianCalendar::name() const
|
||||
{
|
||||
return QStringLiteral("Julian");
|
||||
}
|
||||
|
||||
QStringList QJulianCalendar::nameList()
|
||||
{
|
||||
return { QStringLiteral("Julian") };
|
||||
}
|
||||
|
||||
bool QJulianCalendar::isLeapYear(int year) const
|
||||
{
|
||||
if (year == QCalendar::Unspecified || !year)
|
||||
|
@ -58,9 +58,9 @@ QT_BEGIN_NAMESPACE
|
||||
class Q_CORE_EXPORT QJulianCalendar : public QRomanCalendar
|
||||
{
|
||||
public:
|
||||
QJulianCalendar();
|
||||
// Calendar properties:
|
||||
QString name() const override;
|
||||
static QStringList nameList();
|
||||
// Date queries:
|
||||
bool isLeapYear(int year) const override;
|
||||
// Julian Day conversions:
|
||||
|
@ -73,17 +73,16 @@ using namespace QRoundingDown;
|
||||
page on Milanković Calendar}
|
||||
*/
|
||||
|
||||
QMilankovicCalendar::QMilankovicCalendar()
|
||||
: QRomanCalendar(QStringLiteral("Milankovic"), QCalendar::System::Milankovic)
|
||||
{
|
||||
Q_ASSERT(calendarSystem() == QCalendar::System::Milankovic || !calendarId().isValid());
|
||||
}
|
||||
|
||||
QString QMilankovicCalendar::name() const
|
||||
{
|
||||
return QStringLiteral("Milankovic");
|
||||
}
|
||||
|
||||
QStringList QMilankovicCalendar::nameList()
|
||||
{
|
||||
return { QStringLiteral("Milankovic") };
|
||||
}
|
||||
|
||||
bool QMilankovicCalendar::isLeapYear(int year) const
|
||||
{
|
||||
if (year == QCalendar::Unspecified)
|
||||
|
@ -58,9 +58,9 @@ QT_BEGIN_NAMESPACE
|
||||
class Q_CORE_EXPORT QMilankovicCalendar : public QRomanCalendar
|
||||
{
|
||||
public:
|
||||
QMilankovicCalendar();
|
||||
// Calendar properties:
|
||||
QString name() const override;
|
||||
static QStringList nameList();
|
||||
// Date queries:
|
||||
bool isLeapYear(int year) const override;
|
||||
// Julian Day conversions:
|
||||
|
@ -69,9 +69,6 @@ protected:
|
||||
// locale support:
|
||||
const QCalendarLocale *localeMonthIndexData() const override;
|
||||
const char16_t *localeMonthData() const override;
|
||||
// (The INTEGRITY compiler got upset at: using QCalendarBackend:QCalendarBackend;)
|
||||
QRomanCalendar(const QString &name, QCalendar::System id = QCalendar::System::User)
|
||||
: QCalendarBackend(name, id) {}
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
Loading…
Reference in New Issue
Block a user