Q<Typed>Permission: don't use external state

There's no point in using the full implicit sharing machinery when the
type's state consists of two enums, a bool or, indeed, if the type has
no state at all. QRect has more state and isn't implicitly shared.

To remain extensible in the future, all that is required is that the
type contains space for an eventual d-pointer and that all access to
members (except swapping, and, as a consequence, the move SFMs, but
including the copy SMFs, ctors and dtor) is confined to out-of-line
functions.

So define a ShortData (name stolen from QDateTime) nested struct in
each of the stateful Q<Typed>Permission classes, of the same size as a
pointer, holding the trivially-relocatable fields we currently have.

If, in the future, fields are added such that the reserved[] space in
any given class' ShortData no longer suffices to hold them, or said
fields are not of Q_RELOCATABLE_TYPE, then the full d-pointer pattern
(with an actually defined Private, and detach()ing) can be implemented
_for that one class_.

The new-style classes are externally indistinguishable from the
implicitly-shared old-style ones, just a lot more efficient.

Inline the move-ctor, now that we can. This doesn't break
encapsulation, even when we eventually activate the d-pointer.

As a drive-by, drop the noexcept on the dtors - dtors are implicitly
noexcept, anyway.

Change-Id: Id90a39227277c6554ddd5895e8205485da1e39ca
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Giuseppe D'Angelo <giuseppe.dangelo@kdab.com>
Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@qt.io>
(cherry picked from commit cde904b38ab6ef1ddcc9a0cbcae766cf42d58d81)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
Marc Mutz 2023-01-13 10:11:46 +01:00 committed by Qt Cherry-pick Bot
parent 3c929d9618
commit 69c85f2dd5
2 changed files with 76 additions and 54 deletions

View File

@ -281,14 +281,17 @@ const void *QPermission::data(QMetaType requestedType) const
return m_data.data();
}
#define QT_DEFINE_PERMISSION_SPECIAL_FUNCTIONS(ClassName) \
ClassName::ClassName() : d(new ClassName##Private) {} \
#define QT_PERMISSION_IMPL_COMMON(ClassName) \
/* Class##Private is unused until we need it: */ \
static_assert(sizeof(ClassName) == sizeof(void*), \
"You have added too many members to " #ClassName "::ShortData. " \
"Decrease their size or switch to using a d-pointer."); \
ClassName::ClassName(const ClassName &other) noexcept = default; \
ClassName::ClassName(ClassName &&other) noexcept = default; \
ClassName::~ClassName() noexcept = default; \
ClassName &ClassName::operator=(const ClassName &other) noexcept = default;
ClassName::~ClassName() = default; \
ClassName &ClassName::operator=(const ClassName &other) noexcept = default; \
ClassName::ClassName() \
/* impl supplied by caller */
/*!
\class QCameraPermission
@ -309,8 +312,10 @@ const void *QPermission::data(QMetaType requestedType) const
\include permissions.qdocinc permission-metadata
*/
class QCameraPermissionPrivate : public QSharedData {};
QT_DEFINE_PERMISSION_SPECIAL_FUNCTIONS(QCameraPermission)
QT_PERMISSION_IMPL_COMMON(QCameraPermission)
: u{} // stateless, atm
{}
/*!
\class QMicrophonePermission
@ -331,8 +336,10 @@ QT_DEFINE_PERMISSION_SPECIAL_FUNCTIONS(QCameraPermission)
\include permissions.qdocinc permission-metadata
*/
class QMicrophonePermissionPrivate : public QSharedData {};
QT_DEFINE_PERMISSION_SPECIAL_FUNCTIONS(QMicrophonePermission)
QT_PERMISSION_IMPL_COMMON(QMicrophonePermission)
: u{} // stateless, atm
{}
/*!
\class QBluetoothPermission
@ -353,8 +360,10 @@ QT_DEFINE_PERMISSION_SPECIAL_FUNCTIONS(QMicrophonePermission)
\include permissions.qdocinc permission-metadata
*/
class QBluetoothPermissionPrivate : public QSharedData {};
QT_DEFINE_PERMISSION_SPECIAL_FUNCTIONS(QBluetoothPermission)
QT_PERMISSION_IMPL_COMMON(QBluetoothPermission)
: u{} // stateless, atm
{}
/*!
\class QLocationPermission
@ -389,17 +398,10 @@ QT_DEFINE_PERMISSION_SPECIAL_FUNCTIONS(QBluetoothPermission)
\include permissions.qdocinc permission-metadata
*/
class QLocationPermissionPrivate : public QSharedData
{
public:
using Accuracy = QLocationPermission::Accuracy;
Accuracy accuracy = Accuracy::Approximate;
using Availability = QLocationPermission::Availability;
Availability availability = Availability::WhenInUse;
};
QT_DEFINE_PERMISSION_SPECIAL_FUNCTIONS(QLocationPermission)
QT_PERMISSION_IMPL_COMMON(QLocationPermission)
: u{ShortData{Accuracy::Approximate, Availability::WhenInUse, {}}}
{}
/*!
\enum QLocationPermission::Accuracy
@ -426,8 +428,7 @@ QT_DEFINE_PERMISSION_SPECIAL_FUNCTIONS(QLocationPermission)
*/
void QLocationPermission::setAccuracy(Accuracy accuracy)
{
d.detach();
d->accuracy = accuracy;
u.data.accuracy = accuracy;
}
/*!
@ -435,7 +436,7 @@ void QLocationPermission::setAccuracy(Accuracy accuracy)
*/
QLocationPermission::Accuracy QLocationPermission::accuracy() const
{
return d->accuracy;
return u.data.accuracy;
}
/*!
@ -443,8 +444,7 @@ QLocationPermission::Accuracy QLocationPermission::accuracy() const
*/
void QLocationPermission::setAvailability(Availability availability)
{
d.detach();
d->availability = availability;
u.data.availability = availability;
}
/*!
@ -452,7 +452,7 @@ void QLocationPermission::setAvailability(Availability availability)
*/
QLocationPermission::Availability QLocationPermission::availability() const
{
return d->availability;
return u.data.availability;
}
/*!
@ -478,13 +478,10 @@ QLocationPermission::Availability QLocationPermission::availability() const
\include permissions.qdocinc permission-metadata
*/
class QContactsPermissionPrivate : public QSharedData
{
public:
bool isReadWrite = false;
};
QT_DEFINE_PERMISSION_SPECIAL_FUNCTIONS(QContactsPermission)
QT_PERMISSION_IMPL_COMMON(QContactsPermission)
: u{ShortData{false, {}}}
{}
/*!
Sets whether the request is for read-write (\a enable == \c true) or
@ -492,8 +489,7 @@ QT_DEFINE_PERMISSION_SPECIAL_FUNCTIONS(QContactsPermission)
*/
void QContactsPermission::setReadWrite(bool enable)
{
d.detach();
d->isReadWrite = enable;
u.data.readWrite = enable;
}
/*!
@ -502,7 +498,7 @@ void QContactsPermission::setReadWrite(bool enable)
*/
bool QContactsPermission::isReadWrite() const
{
return d->isReadWrite;
return u.data.readWrite;
}
/*!
@ -528,13 +524,10 @@ bool QContactsPermission::isReadWrite() const
\include permissions.qdocinc permission-metadata
*/
class QCalendarPermissionPrivate : public QSharedData
{
public:
bool isReadWrite = false;
};
QT_DEFINE_PERMISSION_SPECIAL_FUNCTIONS(QCalendarPermission)
QT_PERMISSION_IMPL_COMMON(QCalendarPermission)
: u{ShortData{false, {}}}
{}
/*!
Sets whether the request is for read-write (\a enable == \c true) or
@ -542,8 +535,7 @@ QT_DEFINE_PERMISSION_SPECIAL_FUNCTIONS(QCalendarPermission)
*/
void QCalendarPermission::setReadWrite(bool enable)
{
d.detach();
d->isReadWrite = enable;
u.data.readWrite = enable;
}
/*!
@ -552,7 +544,7 @@ void QCalendarPermission::setReadWrite(bool enable)
*/
bool QCalendarPermission::isReadWrite() const
{
return d->isReadWrite;
return u.data.readWrite;
}
/*!
@ -576,6 +568,8 @@ QDebug operator<<(QDebug debug, const QPermission &permission)
}
#endif
#undef QT_PERMISSION_IMPL_COMMON
QT_END_NAMESPACE
#include "moc_qpermissions.cpp"

View File

@ -77,21 +77,28 @@ private:
Q_GADGET_EXPORT(Q_CORE_EXPORT) \
using QtPermissionHelper = void; \
friend class QPermission; \
union U { \
U() : d(nullptr) {} \
U(ShortData _data) : data(_data) {} \
U(ClassName##Private *_d) : d(_d) {} \
ShortData data; \
ClassName##Private *d; \
} u; \
public: \
Q_CORE_EXPORT ClassName(); \
Q_CORE_EXPORT ClassName(const ClassName &other) noexcept; \
Q_CORE_EXPORT ClassName(ClassName &&other) noexcept; \
Q_CORE_EXPORT ~ClassName() noexcept; \
ClassName(ClassName &&other) noexcept \
: u{other.u} { other.u.d = nullptr; } \
Q_CORE_EXPORT ~ClassName(); \
Q_CORE_EXPORT ClassName &operator=(const ClassName &other) noexcept; \
QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_PURE_SWAP(ClassName) \
void swap(ClassName &other) noexcept { d.swap(other.d); } \
void swap(ClassName &other) noexcept { std::swap(u, other.u); } \
private: \
QtPrivate::QExplicitlySharedDataPointerV2<ClassName##Private> d;
/*end*/
class QLocationPermissionPrivate;
class QLocationPermission
{
QT_PERMISSION(QLocationPermission)
public:
enum Accuracy : quint8 {
Approximate,
@ -110,26 +117,46 @@ public:
Q_CORE_EXPORT void setAvailability(Availability availability);
Q_CORE_EXPORT Availability availability() const;
private:
struct ShortData {
Accuracy accuracy;
Availability availability;
char reserved[sizeof(void*) - sizeof(accuracy) - sizeof(availability)];
};
QT_PERMISSION(QLocationPermission)
};
Q_DECLARE_SHARED(QLocationPermission)
class QCalendarPermissionPrivate;
class QCalendarPermission
{
QT_PERMISSION(QCalendarPermission)
public:
Q_CORE_EXPORT void setReadWrite(bool enable);
Q_CORE_EXPORT bool isReadWrite() const;
private:
struct ShortData {
bool readWrite;
char reserved[sizeof(void*) - sizeof(readWrite)];
};
QT_PERMISSION(QCalendarPermission)
};
Q_DECLARE_SHARED(QCalendarPermission)
class QContactsPermissionPrivate;
class QContactsPermission
{
QT_PERMISSION(QContactsPermission)
public:
Q_CORE_EXPORT void setReadWrite(bool enable);
Q_CORE_EXPORT bool isReadWrite() const;
private:
struct ShortData {
bool readWrite;
char reserved[sizeof(void*) - sizeof(readWrite)];
};
QT_PERMISSION(QContactsPermission)
};
Q_DECLARE_SHARED(QContactsPermission)
@ -137,6 +164,7 @@ Q_DECLARE_SHARED(QContactsPermission)
class ClassName##Private; \
class ClassName \
{ \
struct ShortData { char reserved[sizeof(void*)]; }; \
QT_PERMISSION(ClassName) \
}; \
Q_DECLARE_SHARED(ClassName)