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 QTCLASSHELPERMACROS_H |
5 | #define QTCLASSHELPERMACROS_H |
6 | |
7 | #include <QtCore/qtconfigmacros.h> |
8 | |
9 | #if 0 |
10 | #pragma qt_class(QtClassHelperMacros) |
11 | #pragma qt_sync_stop_processing |
12 | #endif |
13 | |
14 | QT_BEGIN_NAMESPACE |
15 | |
16 | #if defined(__cplusplus) |
17 | |
18 | /* |
19 | Some classes do not permit copies to be made of an object. These |
20 | classes contains a private copy constructor and assignment |
21 | operator to disable copying (the compiler gives an error message). |
22 | */ |
23 | #define Q_DISABLE_COPY(Class) \ |
24 | Class(const Class &) = delete;\ |
25 | Class &operator=(const Class &) = delete; |
26 | |
27 | #define Q_DISABLE_COPY_MOVE(Class) \ |
28 | Q_DISABLE_COPY(Class) \ |
29 | Class(Class &&) = delete; \ |
30 | Class &operator=(Class &&) = delete; |
31 | |
32 | /* |
33 | Implementing a move assignment operator using an established |
34 | technique (move-and-swap, pure swap) is just boilerplate. |
35 | Here's a couple of *private* macros for convenience. |
36 | |
37 | To know which one to use: |
38 | |
39 | * if you don't have a move constructor (*) => use pure swap; |
40 | * if you have a move constructor, then |
41 | * if your class holds just memory (no file handles, no user-defined |
42 | datatypes, etc.) => use pure swap; |
43 | * use move and swap. |
44 | |
45 | The preference should always go for the move-and-swap one, as it |
46 | will deterministically destroy the data previously held in *this, |
47 | and not "dump" it in the moved-from object (which may then be alive |
48 | for longer). |
49 | |
50 | The requirement for either macro is the presence of a member swap(), |
51 | which any value class that defines its own special member functions |
52 | should have anyhow. |
53 | |
54 | (*) Many value classes in Qt do not have move constructors; mostly, |
55 | the implicitly shared classes using QSharedDataPointer and friends. |
56 | The reason is mostly historical: those classes require either an |
57 | out-of-line move constructor, which we could not provide before we |
58 | made C++11 mandatory (and that we don't like anyhow), or |
59 | an out-of-line dtor for the Q(E)DSP<Private> member (cf. QPixmap). |
60 | |
61 | If you can however add a move constructor to a class lacking it, |
62 | consider doing so, then reevaluate which macro to choose. |
63 | */ |
64 | #define QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(Class) \ |
65 | Class &operator=(Class &&other) noexcept { \ |
66 | Class moved(std::move(other)); \ |
67 | swap(moved); \ |
68 | return *this; \ |
69 | } |
70 | |
71 | #define QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_PURE_SWAP(Class) \ |
72 | Class &operator=(Class &&other) noexcept { \ |
73 | swap(other); \ |
74 | return *this; \ |
75 | } |
76 | |
77 | template <typename T> inline T *qGetPtrHelper(T *ptr) noexcept { return ptr; } |
78 | template <typename Ptr> inline auto qGetPtrHelper(Ptr &ptr) noexcept -> decltype(ptr.get()) |
79 | { static_assert(noexcept(ptr.get()), "Smart d pointers for Q_DECLARE_PRIVATE must have noexcept get()" ); return ptr.get(); } |
80 | |
81 | class QObject; |
82 | class QObjectPrivate; |
83 | namespace QtPrivate { |
84 | template <typename ObjPrivate> void assertObjectType(QObjectPrivate *d); |
85 | inline const QObject *getQObject(const QObjectPrivate *d); |
86 | } |
87 | |
88 | #define Q_DECLARE_PRIVATE(Class) \ |
89 | inline Class##Private* d_func() noexcept \ |
90 | { Q_CAST_IGNORE_ALIGN(return reinterpret_cast<Class##Private *>(qGetPtrHelper(d_ptr));) } \ |
91 | inline const Class##Private* d_func() const noexcept \ |
92 | { Q_CAST_IGNORE_ALIGN(return reinterpret_cast<const Class##Private *>(qGetPtrHelper(d_ptr));) } \ |
93 | friend class Class##Private; |
94 | |
95 | #define Q_DECLARE_PRIVATE_D(Dptr, Class) \ |
96 | inline Class##Private* d_func() noexcept \ |
97 | { Q_CAST_IGNORE_ALIGN(return reinterpret_cast<Class##Private *>(qGetPtrHelper(Dptr));) } \ |
98 | inline const Class##Private* d_func() const noexcept \ |
99 | { Q_CAST_IGNORE_ALIGN(return reinterpret_cast<const Class##Private *>(qGetPtrHelper(Dptr));) } \ |
100 | friend class Class##Private; |
101 | |
102 | #define Q_DECLARE_PUBLIC(Class) \ |
103 | inline Class* q_func() noexcept { return static_cast<Class *>(q_ptr); } \ |
104 | inline const Class* q_func() const noexcept { return static_cast<const Class *>(q_ptr); } \ |
105 | friend class Class; \ |
106 | friend const QObject *QtPrivate::getQObject(const QObjectPrivate *d); \ |
107 | template <typename ObjPrivate> friend void QtPrivate::assertObjectType(QObjectPrivate *d); |
108 | |
109 | #define Q_D(Class) Class##Private * const d = d_func() |
110 | #define Q_Q(Class) Class * const q = q_func() |
111 | |
112 | /* |
113 | Specialize a shared type with: |
114 | |
115 | Q_DECLARE_SHARED(type) |
116 | |
117 | where 'type' is the name of the type to specialize. NOTE: shared |
118 | types must define a member-swap, and be defined in the same |
119 | namespace as Qt for this to work. |
120 | */ |
121 | |
122 | #define Q_DECLARE_SHARED(TYPE) \ |
123 | Q_DECLARE_TYPEINFO(TYPE, Q_RELOCATABLE_TYPE); \ |
124 | inline void swap(TYPE &value1, TYPE &value2) \ |
125 | noexcept(noexcept(value1.swap(value2))) \ |
126 | { value1.swap(value2); } |
127 | |
128 | #endif // __cplusplus |
129 | |
130 | QT_END_NAMESPACE |
131 | |
132 | #endif // QTCLASSHELPERMACROS_H |
133 | |