Provide calendar backends with a unique ID

Registration by ID allows for detection of duplicate instantiation of
built-in back-ends, which can be detected and flagged by setting the
ID to ~size_t(0) instead of the enum value for which it sought to be
registered. A new method, calendarId(), is provided to access this;
while the old calendarSystem() becomes non-virtual, as it can be
inferred (when registration was successful) from the ID.

Make registration by name or alias conditional on successful
registration by ID. Previously, failed registration by name precluded
registration by ID, which now becomes the authoritative registration.
This incidentally makes it possible to add a QCalendar constructor
taking the unique ID of a backend, for use in conjunction with custom
calendar implementations.

Change-Id: Ib22925a8ac3ef9439a09ec3855f6231cf9b91c21
Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
bb10
Edward Welbourne 2020-11-16 16:48:22 +01:00
parent 6fa9f487db
commit 755c678f0f
13 changed files with 291 additions and 137 deletions

View File

@ -81,7 +81,9 @@ inline size_t qHash(const CalendarName &key, size_t seed = 0) noexcept
return qHash(key.toLower(), seed);
}
constexpr size_t invalidBackendId = ~size_t(0);
static QBasicMutex registryMutex; // Protects registry from concurrent access
struct Registry
{
std::vector<QCalendarBackend *> byId;
@ -104,7 +106,7 @@ struct Registry
bool registerName(QCalendarBackend *calendar, const QString &name)
{
Q_ASSERT(!name.isEmpty());
if (status.loadRelaxed() > 1 || name.isEmpty())
if (status.loadRelaxed() > 1 || name.isEmpty() || calendar->calendarId() == invalidBackendId)
return false;
const auto lock = qt_scoped_lock(registryMutex);
@ -118,21 +120,38 @@ struct Registry
byName.insert(name, calendar);
return true;
}
void addCalendar(QCalendarBackend *calendar, const QString &name, QCalendar::System id)
/*
\internal
Registers a backend by ID and returns its ID.
If \a id is QCalendar::System::User, a new unique ID is allocated;
otherwise, \a id must be a member of the QCalendar::System enumeration
and the \a calendar is registered with that as its ID unless this ID is
already in use, in which case registration fails and \c{~size_t(0)} is
returned. In (only) this last case, the caller is responsible for
destruction. Otherwise, registry destruction will take care of it on
program exit.
*/
size_t registerId(QCalendarBackend *calendar, QCalendar::System system)
{
if (status.loadRelaxed() > 1 || name.isEmpty() || !registerName(calendar, name))
return;
if (status.loadRelaxed() > 1)
return invalidBackendId;
const auto lock = qt_scoped_lock(registryMutex);
if (id == QCalendar::System::User) {
size_t index = size_t(system);
if (system == QCalendar::System::User) {
index = byId.size();
byId.push_back(calendar);
populate(); // So that name registration can't pre-empt a standard calendar.
} else if (byId[index] == nullptr) {
Q_ASSERT(byId.size() > index);
Q_ASSERT(byId[index] == nullptr);
byId[index] = calendar;
} else {
Q_ASSERT(byId.size() > size_t(id));
Q_ASSERT(byId[size_t(id)] == nullptr);
byId[size_t(id)] = calendar;
return invalidBackendId;
}
if (id == QCalendar::System::Gregorian) {
// We succeeded in registering the name, so must be the first
// instantiator of QGregorianCalendar to get here.
if (system == QCalendar::System::Gregorian) {
// Only the first QGregorianCalendar can get here, so this should succeed:
const bool ok = gregorianCalendar.testAndSetRelease(nullptr, calendar);
#if defined(QT_FORCE_ASSERTS) || !defined(QT_NO_DEBUG)
Q_ASSERT(ok);
@ -140,6 +159,29 @@ struct Registry
Q_UNUSED(ok);
#endif
}
return index;
}
/*
\internal
Should not normally be needed and is expensive.
Removes all references to this calendar from the registry.
*/
void unRegister(QCalendarBackend *calendar)
{
if (status.loadRelaxed() > 1)
return;
const auto lock = qt_scoped_lock(registryMutex);
const size_t id = calendar->calendarId();
if (~id && byId[id] == calendar)
byId[id] = nullptr; // potentially purge nullptr entries from tail of byId[Last+1:] ?
for (auto i = byName.begin(); i != byName.end(); ) {
if (i.value() == calendar)
i = byName.erase(i);
else
++i;
}
}
/*
\internal
@ -169,7 +211,7 @@ struct Registry
}
};
}
} // anonymous namespace
Q_GLOBAL_STATIC(Registry, calendarRegistry);
@ -207,9 +249,8 @@ static const QCalendarBackend *backendFromEnum(QCalendar::System system)
}
if (!backend)
return backend;
const QString name = backend->name();
// Check for successful registration:
if (calendarRegistry->registerName(backend, name)) {
if (~backend->calendarId()) {
#if defined(QT_FORCE_ASSERTS) || !defined(QT_NO_DEBUG)
const auto lock = qt_scoped_lock(registryMutex);
Q_ASSERT(backend == calendarRegistry->byId[size_t(system)]);
@ -250,17 +291,26 @@ static const QCalendarBackend *backendFromEnum(QCalendar::System system)
pure virtual methods. It may also override some other virtual methods, as
needed.
Most backends are pure code, with no data elements. Such backends should
normally be implemented as singletons. For a backend to be added to the
QCalendar::System \c enum, it must be such a singleton, with a case in
backendFromEnum()'s switch statement (above) to instantiate it.
Most backends are pure code, with only one data element (this base-classe's
\c m_id). Such backends should normally be implemented as singletons. For a
backend to be added to the QCalendar::System \c enum, it must be such a
singleton, with a case in backendFromEnum()'s switch statement (above) to
instantiate it.
\section1 Instantiating backends
Backends may be defined by third-party, plugin or user code. When such
custom backends are instantiated, in their calls to the QCalendarBackend
base-class constructor, each instance should pass a distinct primary name to
the base-class constructor and omit the \c system parameter.
base-class constructor, each instance should pass a distinct primary name
and omit the \c system parameter. Each shall be alloced a unique ID, by
which client code may access it. A custom backend instance can be created
with an empty name if access by name is not needed, or impractical
(e.g. because the backend is not a singleton and constructing names for each
instance would not make sense). Otherwise, each backend should be created
with a distinct name, as only the first with each name will be registered by
name. On the other hand, if a backend already exists for the given name,
most likely it implements the same calendar, so there may be no need for the
new backend.
A backend class that has instance variables as well as code may be
instantiated many times, each with a distinct primary name, to implement
@ -276,118 +326,178 @@ static const QCalendarBackend *backendFromEnum(QCalendar::System system)
the registry in which QCalendar records backends.
The single exception to this is that each backend's instantiator should
verify that it was registered successfully with its primary name. It can do
this by calling registerAlias() with that name; this will return true if it
is already registered with the name. If it returns false, the instantiation
has used a name that was already in use so the new backend has not been
registered and the instantiator retains ownership of the backend instance;
it will not be accessible to QCalendar. (Since registerAlias() is protected,
a custom backend's class shall typically need to provide a method to perform
this check for its instantiator.)
verify that it was registered successfully. If its calendarId() is
\c{~size_t(0)}, it has not been registered and attempts to register aliases
for it shall fail. In such a case, the instantiator retains ownership of the
backend instance; it will not be accessible to QCalendar. Note that (since
Qt 6.1) a backend may be successfully registered by ID without being
registered by name with its primary name, if that name was already in use by
some backend registered before it.
Built-in backends, identified by QCalendar::System values other than User,
should only be instantiated by code in the implementation of QCalendar; no
other code should ever instantiate one. As noted above, such a backend must
be a singleton. Its constructor passes down the \c enum member that
identifies it as \c system to the base-class constructor.
identifies it as \c system to the base-class constructor; this is also its
calendarSystem(). Its unique ID (see \l calendarId()) shall be the \c size_t
equivalent to this \c system value.
The shareable base-classes for backends, QRomanCalendar and QHijriCalendar,
are not themselves identified by QCalendar::System and may be used as
base-classes for custom calendar backends, but cannot be instantiated
themselves.
\sa registerAlias(), QDate, QDateTime, QDateEdit, QDateTimeEdit,
QCalendarWidget
\sa registerAlias(), calendarId(), QDate, QDateTime, QDateEdit,
QDateTimeEdit, QCalendarWidget
*/
/*!
Constructs the calendar and registers it under \a name using \a system.
Constructs the calendar backend and registers it.
On successful registration, the calendar backend registry takes over
ownership of the instance and shall delete it on program exit in the course
of the registry's own destruction. The instance can determine whether it was
successfully registered by calling registerAlias() with the same \a name it
passed to this base-class constructor. If that returns \c false, the
instance has not been registered, QCalendar cannot use it, it should not
attempt to register any other aliases and the code that instantiated the
backend is responsible for deleting it.
successfully registered by testing \c{~calendarId()}: this shall be zero
precisely if registration failed. QCalendar cannot use an unregistered
backend and the code that instantiated it is responsible for deleting it.
The \a system is optional and should only be passed by built-in
implementations of the standard calendars documented in \l
QCalendar::System. Custom backends should not pass \a system.
QCalendar::System. When \a system is passed, unless a backend is already
registered for this \c enum value, the backend is registered with
\c{size_t(system)} as its ID. Custom backends should not pass \a
system. When it is not passed, the backend is allocated a unique calendar
ID, which shall be accessible as \l calendarId(). This ID can (since Qt 6.1)
be used to instantiate a QCalendar using the given backend, avoiding
problems with potential clashes of name or alias.
Only one backend instance should ever be registered for any given \a system:
in the event of a backend being created when one with the same \a system
already exists, the new backend is not registered. The \a name passed with a
\a system (other than \l{QCalendar::System}{User}) must be the \c{name()} of
the backend constructed.
already exists, the new backend is not registered and calendarSystem() shall
return \l{QCalendar::System}{User}. Code that instantiates a backend with a
\a system other than \l{QCalendar::System}{User} must check calendarSystem()
when doing so and take responsibility for destruction of the instance if
this shows it has not been registered. The \a name passed with a \a system
(other than \l{QCalendar::System}{User}) must be the \c{name()} of the
backend constructed.
The \a name must be non-empty and unique; after one backend has been
The \a name may be empty, for example when the backend is only used by ID.
Otherwise, the \a name should be unique; after one backend has been
registered for a name or alias, no other backend can be registered with that
name. The presence of another backend registered with the same name may mean
the backend is redundant, as the system already has a backend to handle the
given calendar type.
name or alias. The backend can test whether instantiation successfully
registered its primary name by calling registerAlias() on that name. The
presence of another backend registered with the same name may mean the
backend is redundant, as the system already has a backend to handle the
given calendar type. Even when a custom backend fails to register by name,
it is still registered by ID and can (since Qt 6.1) register aliases
(although these will also fail if another backend registered for them
first), despite failing to register its primary name.
QCalendar can only access a custom backend using its ID or a name or alias
which the backend has successfully registered. If a backend fails to
register with its primary name or any aliases, the code that instantiated it
may delete it, if it has not shared the ID with any code that may have
instantiated a QCalendar using the ID. There is no need to do this, as the
registry shall take care of deleting it on program termination. Once the ID
has been shared with other code, however, or if the backend does succeed in
registering a name or any aliases, other code may have QCalendar instances
using the backend, so deletion would lead to undefined behavior.
\note \c{QCalendar(name).isValid()} will return true precisely when the
given \c name is in use already. This can be used as a test before
instantiating a backend with the given \c name.
\sa calendarSystem(), registerAlias()
\sa calendarId(), calendarSystem(), registerAlias()
*/
QCalendarBackend::QCalendarBackend(const QString &name, QCalendar::System system)
{
Q_ASSERT(!name.isEmpty());
// Will lock the registry mutex on its own, so no need to do it here:
calendarRegistry->addCalendar(this, name, system);
: m_id(calendarRegistry->registerId(this, system))
{
// System calendars *must* pass non-empty name:
Q_ASSERT(system == QCalendar::System::User || !name.isEmpty());
if (calendarSystem() == system) { // Successfully registered by ID:
if (!name.isEmpty())
calendarRegistry->registerName(this, name);
} else {
Q_ASSERT(size_t(system) <= size_t(QCalendar::System::Last));
}
}
/*!
Destroys the calendar.
Destroys the calendar backend.
Client code should only call this if instantiation failed to register the
backend, as revealed by the instanee failing to registerAlias() with the
name it passed to this base-class's constructor. Only a backend that fails
to register can safely be deleted; and the client code that instantiated it
is indeed responsible for deleting it.
Each calendar backend, once instantiated and successfully registered by ID,
shall exist for the lifetime of the program. Its destruction is taken care
of by the calendar backend registry on program termination. Destroying a
successfully-registered backend otherwise may leave existing QCalendar
instances referencing the destroyed calendar, with undefined results.
Once a backend has been successfully registered, there may be QCalendar
instances using it; deleting it while they still reference it would lead to
undefined behavior. Such a backend shall be deleted when the calendar
backend registry is deleted on program exit; the registry takes over
ownership of the instance on successful registration.
However, if a backend, when instantiated, has calendarId() equal to
\c{~size_t(0)}, it has not been registered and cannot be accessed by
QCalendar. Code that instantiates backends must check for this and delete
the unusable backend object, as it shall be leaked otherwise. This is the
only case in which client code needs to delete a backend.
\sa registerAlias()
If a backend has not been registered for any names (and, from 6.1, its ID
has not been shared with other code that could have used it to instantiate a
QCalendar) it may safely be deleted, but there is no need to do so.
\sa calendarId()
*/
QCalendarBackend::~QCalendarBackend()
{
// Either the registry is destroying itself, in which case it takes care of
// dropping any references to this, or this never got registered, so there
// is no need to tell the registry to forget it.
// No registration to undo unless registry exists and gave this a valid ID:
if (calendarRegistry.exists() && ~calendarId())
calendarRegistry->unRegister(this);
}
/*!
\since 6.2
\fn size_t QCalendarBackend::calendarId() const
Each backend is allocated an ID when successfully registered as part of
instantiation. A backend for which calendarId() is \c{~size_t(0)} has not
been successfully registered and the code that created it must take care to
ensure it is deleted; it also cannot be used, as it is not known to any of
the available ways to create a QCalendar.
\sa calendarSystem(), fromId()
*/
/*!
The calendar system of this calendar.
Each calendar backend constructible from the QCalendar::System \c enum
should return the member of that \c enum that produces it. Other calendars
should return User.
For systems successfully registered with a member of QCalendar::System other
than User, this is just the registered \c enum value; all others have
User. If a backend tried to register itself with an \c enum member other
than User and finds its calendarSystem() is User, the code that created it
shall be responsible for its deletion; otherwise, the calendar register
shall take responsiblity for deleting it on exit.
\sa QCalendarBackend::fromEnum()
\sa fromEnum(), calendarId()
*/
QCalendar::System QCalendarBackend::calendarSystem() const
{
return QCalendar::System::User;
if (m_id > size_t(QCalendar::System::Last))
return QCalendar::System::User;
return QCalendar::System(m_id);
}
/*!
\fn QString QCalendarBackend::name() const;
This pure virtual method should be overloaded by each backend implementation
to return the name that the backend passes to the base-class as its name.
to return a name for which the backend has been successfully registered.
\sa registerAlias()
*/
/*!
The primary name of this calendar.
The calendar may also be known by some aliases. A calendar instantiated by
name may use such an alias, in which case its name() need not match the
alias by which it was instantiated.
*/
QString QCalendar::name() const
{
@ -744,21 +854,23 @@ QStringList QCalendarBackend::availableCalendars()
}
/*!
Registers an alias for this calendar backend. Once a backend is registered,
its name will be included in the list of available calendars and the
calendar can be instantiated by name.
Registers an alias for this calendar backend.
Once a backend is registered, the alias will be included in the list of
available calendars and the calendar can be instantiated by name.
Returns \c false if the given \a name is already in use by a different
backend or \c true if this calendar is already registered with this
name. (This can be used, with its primary name, to test whether a backend's
construction successfully registered it.) Otherwise it registers this
calendar backend for this name and returns \c true.
backend or the backend has not been registered successfully by ID or \c true
if this calendar is already registered with this name. (This can be used,
with its primary name, to test whether a backend's construction successfully
registered this name for it.) Otherwise it registers this calendar backend
for this name and returns \c true.
\sa availableCalendars(), fromName()
*/
bool QCalendarBackend::registerAlias(const QString &name)
{
if (calendarRegistry.isDestroyed() || name.isEmpty())
if (!calendarRegistry.exists() || name.isEmpty())
return false;
// Constructing this accessed the registry, so ensured it exists:
Q_ASSERT(calendarRegistry.exists());
@ -774,12 +886,12 @@ bool QCalendarBackend::registerAlias(const QString &name)
If the given \a name is present in availableCalendars(), the backend
matching it is returned; otherwise, \c nullptr is returned. Matching of
names ignores case. Note that this won't provoke construction of a calendar
backend, it will only return ones that have been instantiated (and not yet
destroyed) by some other means. However, calendars available via the
QCalendar::System \c enum are always registered when this is called.
names ignores case. Note that this does not provoke construction of a
calendar backend, other than those available via \l fromEnum(): it will only
return ones that have been instantiated (and not yet destroyed) by some
other means.
\sa availableCalendars(), registerAlias(), fromEnum()
\sa availableCalendars(), registerAlias(), fromEnum(), fromId()
*/
const QCalendarBackend *QCalendarBackend::fromName(QStringView name)
{
@ -805,6 +917,29 @@ const QCalendarBackend *QCalendarBackend::fromName(QLatin1String name)
return it == calendarRegistry->byName.end() ? nullptr : *it;
}
/*!
\internal
Returns a pointer to a calendar backend, specified by ID.
If a calendar with ID \a id is known to the calendar registry, the backend
with this ID is returned; otherwise, \c nullptr is returned. Note that this
does not provoke construction of a calendar backend, other than those
available via \l fromEnum(): it will only return ones that have been
instantiated (and not yet destroyed) by some other means.
\sa fromEnum(), calendarId()
*/
const QCalendarBackend *QCalendarBackend::fromId(size_t id)
{
if (calendarRegistry.isDestroyed() || !~id)
return nullptr;
if (auto *c = id < calendarRegistry->byId.size() ? calendarRegistry->byId[id] : nullptr)
return c;
if (id <= size_t(QCalendar::System::Last))
return fromEnum(QCalendar::System(id));
return nullptr;
}
/*!
\internal
Returns a pointer to a calendar backend, specified by \c enum.
@ -812,14 +947,18 @@ const QCalendarBackend *QCalendarBackend::fromName(QLatin1String name)
This will instantiate the indicated calendar (which will enable fromName()
to return it subsequently), but only for the Qt-supported calendars for
which (where relevant) the appropriate feature has been enabled.
\sa fromName(), fromId()
*/
const QCalendarBackend *QCalendarBackend::fromEnum(QCalendar::System system)
{
Q_ASSERT(system == QCalendar::System::User
|| size_t(system) <= size_t(QCalendar::System::Last));
if (calendarRegistry.isDestroyed() || system == QCalendar::System::User)
return nullptr;
{
const auto registryLock = qt_scoped_lock(registryMutex);
Q_ASSERT(calendarRegistry->byId.size() >= size_t(system));
Q_ASSERT(calendarRegistry->byId.size() > size_t(system));
if (auto *c = calendarRegistry->byId[size_t(system)])
return c;
}
@ -848,7 +987,8 @@ const QCalendarBackend *QCalendarBackend::fromEnum(QCalendar::System system)
calendars may be constructed by name, once they have been constructed. (Thus
plugins instantiate their calendar backend to register it.) Built-in
backends, accessible via QCalendar::System, are also always available by
name.
name. Calendars using custom backends may also be constructed using a unique
ID allocated to the backend on construction.
A QCalendar value is immutable.
@ -879,7 +1019,7 @@ const QCalendarBackend *QCalendarBackend::fromEnum(QCalendar::System system)
Constructs a calendar object.
The choice of calendar to use may be indicated as \a system, using the
The choice of calendar to use may be indicated by \a system, using the
enumeration QCalendar::System, or by \a name, using a string (either Unicode
or Latin 1). Construction by name may depend on an instance of the given
calendar being constructed by other means first. With no argument, the
@ -900,20 +1040,45 @@ QCalendar::QCalendar()
delete fresh;
Q_ASSERT(d);
}
Q_ASSERT(~d->calendarId());
}
QCalendar::QCalendar(QCalendar::System system)
: d(QCalendarBackend::fromEnum(system))
{
// If system is valid, we should get a valid d for that system.
Q_ASSERT(uint(system) > uint(QCalendar::System::Last) || (d && d->calendarSystem() == system));
Q_ASSERT(uint(system) > uint(QCalendar::System::Last)
|| (d && d->calendarId() == size_t(system)));
}
/*!
\overload
\since 6.2
Constructs a calendar object.
When using a custom calendar implementation, its backend is allocated a unique
ID when created; passing that as \a id to this constructor will get a
QCalendar using that backend. This can be useful when the backend is not
registered by name.
*/
QCalendar::QCalendar(size_t id)
: d(QCalendarBackend::fromId(id))
{
Q_ASSERT(!d || d->calendarId() == id);
}
QCalendar::QCalendar(QLatin1String name)
: d(QCalendarBackend::fromName(name)) {}
: d(QCalendarBackend::fromName(name))
{
Q_ASSERT(!d || ~d->calendarId());
}
QCalendar::QCalendar(QStringView name)
: d(QCalendarBackend::fromName(name)) {}
: d(QCalendarBackend::fromName(name))
{
Q_ASSERT(!d || ~d->calendarId());
}
/*!
\fn bool QCalendar::isValid() const

View File

@ -135,6 +135,7 @@ public:
explicit QCalendar(System system);
explicit QCalendar(QLatin1String name);
explicit QCalendar(QStringView name);
explicit QCalendar(size_t id);
// QCalendar is a trivially copyable value type.
bool isValid() const { return d != nullptr; }

View File

@ -92,7 +92,8 @@ class Q_CORE_EXPORT QCalendarBackend
public:
virtual ~QCalendarBackend();
virtual QString name() const = 0;
virtual QCalendar::System calendarSystem() const;
QCalendar::System calendarSystem() const;
size_t calendarId() const { return m_id; }
// Date queries:
virtual int daysInMonth(int month, int year = QCalendar::Unspecified) const = 0;
virtual int daysInYear(int year) const;
@ -142,9 +143,11 @@ protected:
bool registerAlias(const QString &name);
private:
const size_t m_id = ~size_t(0);
// QCalendar's access to its registry:
static const QCalendarBackend *fromName(QStringView name);
static const QCalendarBackend *fromName(QLatin1String name);
static const QCalendarBackend *fromId(size_t id);
// QCalendar's access to singletons:
static const QCalendarBackend *fromEnum(QCalendar::System system);
};

View File

@ -1,6 +1,6 @@
/****************************************************************************
**
** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
@ -63,7 +63,10 @@ using namespace QRoundingDown;
QGregorianCalendar::QGregorianCalendar()
: QRomanCalendar(QStringLiteral("Gregorian"), QCalendar::System::Gregorian)
{
registerAlias(QStringLiteral("gregory"));
if (~calendarId()) {
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
@ -71,11 +74,6 @@ QString QGregorianCalendar::name() const
return QStringLiteral("Gregorian");
}
QCalendar::System QGregorianCalendar::calendarSystem() const
{
return QCalendar::System::Gregorian;
}
bool QGregorianCalendar::isLeapYear(int year) const
{
return leapTest(year);

View File

@ -1,6 +1,6 @@
/****************************************************************************
**
** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
@ -61,9 +61,8 @@ class Q_CORE_EXPORT QGregorianCalendar : public QRomanCalendar
// directly by QDate to optimize various parts.
public:
QGregorianCalendar();
// CAlendar properties:
// Calendar property:
QString name() const override;
QCalendar::System calendarSystem() const override;
// Date queries:
bool isLeapYear(int year) const override;
// Julian Day conversions:

View File

@ -1,6 +1,6 @@
/****************************************************************************
**
** Copyright (C) 2018 The Qt Company Ltd.
** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
@ -75,10 +75,13 @@ using namespace QRoundingDown;
QIslamicCivilCalendar::QIslamicCivilCalendar()
: QHijriCalendar(QStringLiteral("Islamic Civil"), 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"));
if (~calendarId()) {
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
@ -86,11 +89,6 @@ QString QIslamicCivilCalendar::name() const
return QStringLiteral("Islamic Civil");
}
QCalendar::System QIslamicCivilCalendar::calendarSystem() const
{
return QCalendar::System::IslamicCivil;
}
bool QIslamicCivilCalendar::isLeapYear(int year) const
{
if (year == QCalendar::Unspecified)

View File

@ -1,6 +1,6 @@
/****************************************************************************
**
** Copyright (C) 2018 The Qt Company Ltd.
** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
@ -63,7 +63,6 @@ public:
QIslamicCivilCalendar();
// Calendar properties:
QString name() const override;
QCalendar::System calendarSystem() const override;
// Date queries:
bool isLeapYear(int year) const override;
// Julian Day conversions:

View File

@ -116,7 +116,10 @@ qint64 firstDayOfYear(int year, int cycleNo)
QJalaliCalendar::QJalaliCalendar()
: QCalendarBackend(QStringLiteral("Jalali"), QCalendar::System::Jalali)
{
registerAlias(QStringLiteral("Persian"));
if (~calendarId()) {
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
@ -124,11 +127,6 @@ QString QJalaliCalendar::name() const
return QStringLiteral("Jalali");
}
QCalendar::System QJalaliCalendar::calendarSystem() const
{
return QCalendar::System::Jalali;
}
bool QJalaliCalendar::isLeapYear(int year) const
{
if (year == QCalendar::Unspecified)

View File

@ -63,7 +63,6 @@ public:
QJalaliCalendar();
// Calendar properties:
QString name() const override;
QCalendar::System calendarSystem() const override;
// Date queries:
int daysInMonth(int month, int year = QCalendar::Unspecified) const override;
bool isLeapYear(int year) const override;

View File

@ -1,6 +1,6 @@
/****************************************************************************
**
** Copyright (C) 2018 The Qt Company Ltd.
** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
@ -76,18 +76,16 @@ using namespace QRoundingDown;
*/
QJulianCalendar::QJulianCalendar()
: QRomanCalendar(QStringLiteral("Julian"), QCalendar::System::Julian) {}
: QRomanCalendar(QStringLiteral("Julian"), QCalendar::System::Julian)
{
Q_ASSERT(calendarSystem() == QCalendar::System::Julian || !~calendarId());
}
QString QJulianCalendar::name() const
{
return QStringLiteral("Julian");
}
QCalendar::System QJulianCalendar::calendarSystem() const
{
return QCalendar::System::Julian;
}
bool QJulianCalendar::isLeapYear(int year) const
{
if (year == QCalendar::Unspecified || !year)

View File

@ -1,6 +1,6 @@
/****************************************************************************
**
** Copyright (C) 2018 The Qt Company Ltd.
** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
@ -61,7 +61,6 @@ public:
QJulianCalendar();
// Calendar properties:
QString name() const override;
QCalendar::System calendarSystem() const override;
// Date queries:
bool isLeapYear(int year) const override;
// Julian Day conversions:

View File

@ -1,6 +1,6 @@
/****************************************************************************
**
** Copyright (C) 2018 The Qt Company Ltd.
** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
@ -74,18 +74,16 @@ using namespace QRoundingDown;
*/
QMilankovicCalendar::QMilankovicCalendar()
: QRomanCalendar(QStringLiteral("Milankovic"), QCalendar::System::Milankovic) {}
: QRomanCalendar(QStringLiteral("Milankovic"), QCalendar::System::Milankovic)
{
Q_ASSERT(calendarSystem() == QCalendar::System::Milankovic || !~calendarId());
}
QString QMilankovicCalendar::name() const
{
return QStringLiteral("Milankovic");
}
QCalendar::System QMilankovicCalendar::calendarSystem() const
{
return QCalendar::System::Milankovic;
}
bool QMilankovicCalendar::isLeapYear(int year) const
{
if (year == QCalendar::Unspecified)

View File

@ -1,6 +1,6 @@
/****************************************************************************
**
** Copyright (C) 2018 The Qt Company Ltd.
** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
@ -61,7 +61,6 @@ public:
QMilankovicCalendar();
// Calendar properties:
QString name() const override;
QCalendar::System calendarSystem() const override;
// Date queries:
bool isLeapYear(int year) const override;
// Julian Day conversions: