1/****************************************************************************
2**
3** Copyright (C) 2011 Thiago Macieira <thiago@kde.org>
4** Copyright (C) 2018 Intel Corporation.
5** Contact: https://www.qt.io/licensing/
6**
7** This file is part of the QtCore module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial License Usage
11** Licensees holding valid commercial Qt licenses may use this file in
12** accordance with the commercial license agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and The Qt Company. For licensing terms
15** and conditions see https://www.qt.io/terms-conditions. For further
16** information use the contact form at https://www.qt.io/contact-us.
17**
18** GNU Lesser General Public License Usage
19** Alternatively, this file may be used under the terms of the GNU Lesser
20** General Public License version 3 as published by the Free Software
21** Foundation and appearing in the file LICENSE.LGPL3 included in the
22** packaging of this file. Please review the following information to
23** ensure the GNU Lesser General Public License version 3 requirements
24** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
25**
26** GNU General Public License Usage
27** Alternatively, this file may be used under the terms of the GNU
28** General Public License version 2.0 or (at your option) the GNU General
29** Public license version 3 or any later version approved by the KDE Free
30** Qt Foundation. The licenses are as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
32** included in the packaging of this file. Please review the following
33** information to ensure the GNU General Public License requirements will
34** be met: https://www.gnu.org/licenses/gpl-2.0.html and
35** https://www.gnu.org/licenses/gpl-3.0.html.
36**
37** $QT_END_LICENSE$
38**
39****************************************************************************/
40
41#include <QtCore/qatomic.h>
42
43#ifndef QBASICATOMIC_H
44#define QBASICATOMIC_H
45
46#if defined(QT_BOOTSTRAPPED)
47# include <QtCore/qatomic_bootstrap.h>
48#else
49# include <QtCore/qatomic_cxx11.h>
50#endif
51
52QT_WARNING_PUSH
53QT_WARNING_DISABLE_MSVC(4522)
54
55QT_BEGIN_NAMESPACE
56
57#if 0
58// silence syncqt warnings
59QT_END_NAMESPACE
60#pragma qt_no_master_include
61#pragma qt_sync_stop_processing
62#endif
63
64// New atomics
65
66#if defined(Q_COMPILER_CONSTEXPR) && defined(Q_COMPILER_DEFAULT_MEMBERS) && defined(Q_COMPILER_DELETE_MEMBERS)
67# if defined(Q_CC_CLANG) && Q_CC_CLANG < 303
68 /*
69 Do not define QT_BASIC_ATOMIC_HAS_CONSTRUCTORS for Clang before version 3.3.
70 For details about the bug: see http://llvm.org/bugs/show_bug.cgi?id=12670
71 */
72# else
73# define QT_BASIC_ATOMIC_HAS_CONSTRUCTORS
74# endif
75#endif
76
77template <typename T>
78class QBasicAtomicInteger
79{
80public:
81 typedef T Type;
82 typedef QAtomicOps<T> Ops;
83 // static check that this is a valid integer
84 Q_STATIC_ASSERT_X(QTypeInfo<T>::isIntegral, "template parameter is not an integral type");
85 Q_STATIC_ASSERT_X(QAtomicOpsSupport<sizeof(T)>::IsSupported, "template parameter is an integral of a size not supported on this platform");
86
87 typename Ops::Type _q_value;
88
89 // Everything below is either implemented in ../arch/qatomic_XXX.h or (as fallback) in qgenericatomic.h
90
91 T load() const Q_DECL_NOTHROW { return Ops::load(_q_value); }
92 void store(T newValue) Q_DECL_NOTHROW { Ops::store(_q_value, newValue); }
93
94 T loadAcquire() const Q_DECL_NOTHROW { return Ops::loadAcquire(_q_value); }
95 void storeRelease(T newValue) Q_DECL_NOTHROW { Ops::storeRelease(_q_value, newValue); }
96 operator T() const Q_DECL_NOTHROW { return loadAcquire(); }
97 T operator=(T newValue) Q_DECL_NOTHROW { storeRelease(newValue); return newValue; }
98
99 static Q_DECL_CONSTEXPR bool isReferenceCountingNative() Q_DECL_NOTHROW { return Ops::isReferenceCountingNative(); }
100 static Q_DECL_CONSTEXPR bool isReferenceCountingWaitFree() Q_DECL_NOTHROW { return Ops::isReferenceCountingWaitFree(); }
101
102 bool ref() Q_DECL_NOTHROW { return Ops::ref(_q_value); }
103 bool deref() Q_DECL_NOTHROW { return Ops::deref(_q_value); }
104
105 static Q_DECL_CONSTEXPR bool isTestAndSetNative() Q_DECL_NOTHROW { return Ops::isTestAndSetNative(); }
106 static Q_DECL_CONSTEXPR bool isTestAndSetWaitFree() Q_DECL_NOTHROW { return Ops::isTestAndSetWaitFree(); }
107
108 bool testAndSetRelaxed(T expectedValue, T newValue) Q_DECL_NOTHROW
109 { return Ops::testAndSetRelaxed(_q_value, expectedValue, newValue); }
110 bool testAndSetAcquire(T expectedValue, T newValue) Q_DECL_NOTHROW
111 { return Ops::testAndSetAcquire(_q_value, expectedValue, newValue); }
112 bool testAndSetRelease(T expectedValue, T newValue) Q_DECL_NOTHROW
113 { return Ops::testAndSetRelease(_q_value, expectedValue, newValue); }
114 bool testAndSetOrdered(T expectedValue, T newValue) Q_DECL_NOTHROW
115 { return Ops::testAndSetOrdered(_q_value, expectedValue, newValue); }
116
117 bool testAndSetRelaxed(T expectedValue, T newValue, T &currentValue) Q_DECL_NOTHROW
118 { return Ops::testAndSetRelaxed(_q_value, expectedValue, newValue, &currentValue); }
119 bool testAndSetAcquire(T expectedValue, T newValue, T &currentValue) Q_DECL_NOTHROW
120 { return Ops::testAndSetAcquire(_q_value, expectedValue, newValue, &currentValue); }
121 bool testAndSetRelease(T expectedValue, T newValue, T &currentValue) Q_DECL_NOTHROW
122 { return Ops::testAndSetRelease(_q_value, expectedValue, newValue, &currentValue); }
123 bool testAndSetOrdered(T expectedValue, T newValue, T &currentValue) Q_DECL_NOTHROW
124 { return Ops::testAndSetOrdered(_q_value, expectedValue, newValue, &currentValue); }
125
126 static Q_DECL_CONSTEXPR bool isFetchAndStoreNative() Q_DECL_NOTHROW { return Ops::isFetchAndStoreNative(); }
127 static Q_DECL_CONSTEXPR bool isFetchAndStoreWaitFree() Q_DECL_NOTHROW { return Ops::isFetchAndStoreWaitFree(); }
128
129 T fetchAndStoreRelaxed(T newValue) Q_DECL_NOTHROW
130 { return Ops::fetchAndStoreRelaxed(_q_value, newValue); }
131 T fetchAndStoreAcquire(T newValue) Q_DECL_NOTHROW
132 { return Ops::fetchAndStoreAcquire(_q_value, newValue); }
133 T fetchAndStoreRelease(T newValue) Q_DECL_NOTHROW
134 { return Ops::fetchAndStoreRelease(_q_value, newValue); }
135 T fetchAndStoreOrdered(T newValue) Q_DECL_NOTHROW
136 { return Ops::fetchAndStoreOrdered(_q_value, newValue); }
137
138 static Q_DECL_CONSTEXPR bool isFetchAndAddNative() Q_DECL_NOTHROW { return Ops::isFetchAndAddNative(); }
139 static Q_DECL_CONSTEXPR bool isFetchAndAddWaitFree() Q_DECL_NOTHROW { return Ops::isFetchAndAddWaitFree(); }
140
141 T fetchAndAddRelaxed(T valueToAdd) Q_DECL_NOTHROW
142 { return Ops::fetchAndAddRelaxed(_q_value, valueToAdd); }
143 T fetchAndAddAcquire(T valueToAdd) Q_DECL_NOTHROW
144 { return Ops::fetchAndAddAcquire(_q_value, valueToAdd); }
145 T fetchAndAddRelease(T valueToAdd) Q_DECL_NOTHROW
146 { return Ops::fetchAndAddRelease(_q_value, valueToAdd); }
147 T fetchAndAddOrdered(T valueToAdd) Q_DECL_NOTHROW
148 { return Ops::fetchAndAddOrdered(_q_value, valueToAdd); }
149
150 T fetchAndSubRelaxed(T valueToAdd) Q_DECL_NOTHROW
151 { return Ops::fetchAndSubRelaxed(_q_value, valueToAdd); }
152 T fetchAndSubAcquire(T valueToAdd) Q_DECL_NOTHROW
153 { return Ops::fetchAndSubAcquire(_q_value, valueToAdd); }
154 T fetchAndSubRelease(T valueToAdd) Q_DECL_NOTHROW
155 { return Ops::fetchAndSubRelease(_q_value, valueToAdd); }
156 T fetchAndSubOrdered(T valueToAdd) Q_DECL_NOTHROW
157 { return Ops::fetchAndSubOrdered(_q_value, valueToAdd); }
158
159 T fetchAndAndRelaxed(T valueToAdd) Q_DECL_NOTHROW
160 { return Ops::fetchAndAndRelaxed(_q_value, valueToAdd); }
161 T fetchAndAndAcquire(T valueToAdd) Q_DECL_NOTHROW
162 { return Ops::fetchAndAndAcquire(_q_value, valueToAdd); }
163 T fetchAndAndRelease(T valueToAdd) Q_DECL_NOTHROW
164 { return Ops::fetchAndAndRelease(_q_value, valueToAdd); }
165 T fetchAndAndOrdered(T valueToAdd) Q_DECL_NOTHROW
166 { return Ops::fetchAndAndOrdered(_q_value, valueToAdd); }
167
168 T fetchAndOrRelaxed(T valueToAdd) Q_DECL_NOTHROW
169 { return Ops::fetchAndOrRelaxed(_q_value, valueToAdd); }
170 T fetchAndOrAcquire(T valueToAdd) Q_DECL_NOTHROW
171 { return Ops::fetchAndOrAcquire(_q_value, valueToAdd); }
172 T fetchAndOrRelease(T valueToAdd) Q_DECL_NOTHROW
173 { return Ops::fetchAndOrRelease(_q_value, valueToAdd); }
174 T fetchAndOrOrdered(T valueToAdd) Q_DECL_NOTHROW
175 { return Ops::fetchAndOrOrdered(_q_value, valueToAdd); }
176
177 T fetchAndXorRelaxed(T valueToAdd) Q_DECL_NOTHROW
178 { return Ops::fetchAndXorRelaxed(_q_value, valueToAdd); }
179 T fetchAndXorAcquire(T valueToAdd) Q_DECL_NOTHROW
180 { return Ops::fetchAndXorAcquire(_q_value, valueToAdd); }
181 T fetchAndXorRelease(T valueToAdd) Q_DECL_NOTHROW
182 { return Ops::fetchAndXorRelease(_q_value, valueToAdd); }
183 T fetchAndXorOrdered(T valueToAdd) Q_DECL_NOTHROW
184 { return Ops::fetchAndXorOrdered(_q_value, valueToAdd); }
185
186 T operator++() Q_DECL_NOTHROW
187 { return fetchAndAddOrdered(1) + 1; }
188 T operator++(int) Q_DECL_NOTHROW
189 { return fetchAndAddOrdered(1); }
190 T operator--() Q_DECL_NOTHROW
191 { return fetchAndSubOrdered(1) - 1; }
192 T operator--(int) Q_DECL_NOTHROW
193 { return fetchAndSubOrdered(1); }
194
195 T operator+=(T v) Q_DECL_NOTHROW
196 { return fetchAndAddOrdered(v) + v; }
197 T operator-=(T v) Q_DECL_NOTHROW
198 { return fetchAndSubOrdered(v) - v; }
199 T operator&=(T v) Q_DECL_NOTHROW
200 { return fetchAndAndOrdered(v) & v; }
201 T operator|=(T v) Q_DECL_NOTHROW
202 { return fetchAndOrOrdered(v) | v; }
203 T operator^=(T v) Q_DECL_NOTHROW
204 { return fetchAndXorOrdered(v) ^ v; }
205
206
207#ifdef QT_BASIC_ATOMIC_HAS_CONSTRUCTORS
208 QBasicAtomicInteger() = default;
209 constexpr QBasicAtomicInteger(T value) Q_DECL_NOTHROW : _q_value(value) {}
210 QBasicAtomicInteger(const QBasicAtomicInteger &) = delete;
211 QBasicAtomicInteger &operator=(const QBasicAtomicInteger &) = delete;
212 QBasicAtomicInteger &operator=(const QBasicAtomicInteger &) volatile = delete;
213#endif
214};
215typedef QBasicAtomicInteger<int> QBasicAtomicInt;
216
217template <typename X>
218class QBasicAtomicPointer
219{
220public:
221 typedef X *Type;
222 typedef QAtomicOps<Type> Ops;
223 typedef typename Ops::Type AtomicType;
224
225 AtomicType _q_value;
226
227 Type load() const Q_DECL_NOTHROW { return Ops::load(_q_value); }
228 void store(Type newValue) Q_DECL_NOTHROW { Ops::store(_q_value, newValue); }
229 operator Type() const Q_DECL_NOTHROW { return loadAcquire(); }
230 Type operator=(Type newValue) Q_DECL_NOTHROW { storeRelease(newValue); return newValue; }
231
232 // Atomic API, implemented in qatomic_XXX.h
233 Type loadAcquire() const Q_DECL_NOTHROW { return Ops::loadAcquire(_q_value); }
234 void storeRelease(Type newValue) Q_DECL_NOTHROW { Ops::storeRelease(_q_value, newValue); }
235
236 static Q_DECL_CONSTEXPR bool isTestAndSetNative() Q_DECL_NOTHROW { return Ops::isTestAndSetNative(); }
237 static Q_DECL_CONSTEXPR bool isTestAndSetWaitFree() Q_DECL_NOTHROW { return Ops::isTestAndSetWaitFree(); }
238
239 bool testAndSetRelaxed(Type expectedValue, Type newValue) Q_DECL_NOTHROW
240 { return Ops::testAndSetRelaxed(_q_value, expectedValue, newValue); }
241 bool testAndSetAcquire(Type expectedValue, Type newValue) Q_DECL_NOTHROW
242 { return Ops::testAndSetAcquire(_q_value, expectedValue, newValue); }
243 bool testAndSetRelease(Type expectedValue, Type newValue) Q_DECL_NOTHROW
244 { return Ops::testAndSetRelease(_q_value, expectedValue, newValue); }
245 bool testAndSetOrdered(Type expectedValue, Type newValue) Q_DECL_NOTHROW
246 { return Ops::testAndSetOrdered(_q_value, expectedValue, newValue); }
247
248 bool testAndSetRelaxed(Type expectedValue, Type newValue, Type &currentValue) Q_DECL_NOTHROW
249 { return Ops::testAndSetRelaxed(_q_value, expectedValue, newValue, &currentValue); }
250 bool testAndSetAcquire(Type expectedValue, Type newValue, Type &currentValue) Q_DECL_NOTHROW
251 { return Ops::testAndSetAcquire(_q_value, expectedValue, newValue, &currentValue); }
252 bool testAndSetRelease(Type expectedValue, Type newValue, Type &currentValue) Q_DECL_NOTHROW
253 { return Ops::testAndSetRelease(_q_value, expectedValue, newValue, &currentValue); }
254 bool testAndSetOrdered(Type expectedValue, Type newValue, Type &currentValue) Q_DECL_NOTHROW
255 { return Ops::testAndSetOrdered(_q_value, expectedValue, newValue, &currentValue); }
256
257 static Q_DECL_CONSTEXPR bool isFetchAndStoreNative() Q_DECL_NOTHROW { return Ops::isFetchAndStoreNative(); }
258 static Q_DECL_CONSTEXPR bool isFetchAndStoreWaitFree() Q_DECL_NOTHROW { return Ops::isFetchAndStoreWaitFree(); }
259
260 Type fetchAndStoreRelaxed(Type newValue) Q_DECL_NOTHROW
261 { return Ops::fetchAndStoreRelaxed(_q_value, newValue); }
262 Type fetchAndStoreAcquire(Type newValue) Q_DECL_NOTHROW
263 { return Ops::fetchAndStoreAcquire(_q_value, newValue); }
264 Type fetchAndStoreRelease(Type newValue) Q_DECL_NOTHROW
265 { return Ops::fetchAndStoreRelease(_q_value, newValue); }
266 Type fetchAndStoreOrdered(Type newValue) Q_DECL_NOTHROW
267 { return Ops::fetchAndStoreOrdered(_q_value, newValue); }
268
269 static Q_DECL_CONSTEXPR bool isFetchAndAddNative() Q_DECL_NOTHROW { return Ops::isFetchAndAddNative(); }
270 static Q_DECL_CONSTEXPR bool isFetchAndAddWaitFree() Q_DECL_NOTHROW { return Ops::isFetchAndAddWaitFree(); }
271
272 Type fetchAndAddRelaxed(qptrdiff valueToAdd) Q_DECL_NOTHROW
273 { return Ops::fetchAndAddRelaxed(_q_value, valueToAdd); }
274 Type fetchAndAddAcquire(qptrdiff valueToAdd) Q_DECL_NOTHROW
275 { return Ops::fetchAndAddAcquire(_q_value, valueToAdd); }
276 Type fetchAndAddRelease(qptrdiff valueToAdd) Q_DECL_NOTHROW
277 { return Ops::fetchAndAddRelease(_q_value, valueToAdd); }
278 Type fetchAndAddOrdered(qptrdiff valueToAdd) Q_DECL_NOTHROW
279 { return Ops::fetchAndAddOrdered(_q_value, valueToAdd); }
280
281 Type fetchAndSubRelaxed(qptrdiff valueToAdd) Q_DECL_NOTHROW
282 { return Ops::fetchAndSubRelaxed(_q_value, valueToAdd); }
283 Type fetchAndSubAcquire(qptrdiff valueToAdd) Q_DECL_NOTHROW
284 { return Ops::fetchAndSubAcquire(_q_value, valueToAdd); }
285 Type fetchAndSubRelease(qptrdiff valueToAdd) Q_DECL_NOTHROW
286 { return Ops::fetchAndSubRelease(_q_value, valueToAdd); }
287 Type fetchAndSubOrdered(qptrdiff valueToAdd) Q_DECL_NOTHROW
288 { return Ops::fetchAndSubOrdered(_q_value, valueToAdd); }
289
290 Type operator++() Q_DECL_NOTHROW
291 { return fetchAndAddOrdered(1) + 1; }
292 Type operator++(int) Q_DECL_NOTHROW
293 { return fetchAndAddOrdered(1); }
294 Type operator--() Q_DECL_NOTHROW
295 { return fetchAndSubOrdered(1) - 1; }
296 Type operator--(int) Q_DECL_NOTHROW
297 { return fetchAndSubOrdered(1); }
298 Type operator+=(qptrdiff valueToAdd) Q_DECL_NOTHROW
299 { return fetchAndAddOrdered(valueToAdd) + valueToAdd; }
300 Type operator-=(qptrdiff valueToSub) Q_DECL_NOTHROW
301 { return fetchAndSubOrdered(valueToSub) - valueToSub; }
302
303#ifdef QT_BASIC_ATOMIC_HAS_CONSTRUCTORS
304 QBasicAtomicPointer() = default;
305 constexpr QBasicAtomicPointer(Type value) Q_DECL_NOTHROW : _q_value(value) {}
306 QBasicAtomicPointer(const QBasicAtomicPointer &) = delete;
307 QBasicAtomicPointer &operator=(const QBasicAtomicPointer &) = delete;
308 QBasicAtomicPointer &operator=(const QBasicAtomicPointer &) volatile = delete;
309#endif
310};
311
312#ifndef Q_BASIC_ATOMIC_INITIALIZER
313# define Q_BASIC_ATOMIC_INITIALIZER(a) { (a) }
314#endif
315
316QT_END_NAMESPACE
317
318QT_WARNING_POP
319
320#endif // QBASICATOMIC_H
321