1/****************************************************************************
2**
3** Copyright (C) 2016 Intel Corporation.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the test suite of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:GPL-EXCEPT$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU
19** General Public License version 3 as published by the Free Software
20** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
21** included in the packaging of this file. Please review the following
22** information to ensure the GNU General Public License requirements will
23** be met: https://www.gnu.org/licenses/gpl-3.0.html.
24**
25** $QT_END_LICENSE$
26**
27****************************************************************************/
28
29#ifdef QT_ATOMIC_FORCE_CXX11
30// We need to check if this compiler has C++11 atomics and constexpr support.
31// We can't rely on qcompilerdetection.h because it forces all of qglobal.h to
32// be included, which causes qbasicatomic.h to be included too.
33// Incomplete, but ok
34# if defined(__INTEL_COMPILER) && __INTEL_COMPILER >= 1500 && (__cplusplus >= 201103L || defined(__INTEL_CXX11_MODE__))
35# elif defined(__clang__) && (__cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__))
36# if !__has_feature(cxx_constexpr) || !__has_feature(cxx_atomic) || !__has_include(<atomic>)
37# undef QT_ATOMIC_FORCE_CXX11
38# endif
39# elif defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__) >= 407 && (__cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__))
40# elif defined(_MSC_VER)
41 // We need MSVC 2015 because of: atomics (2012), constexpr (2015), and unrestricted unions (2015).
42 // Support for constexpr is not working completely on MSVC 2015 but it's enough for the test.
43# else
44# undef QT_ATOMIC_FORCE_CXX11
45# endif
46
47# ifndef QT_ATOMIC_FORCE_CXX11
48# undef QATOMIC_TEST_TYPE
49# define QATOMIC_TEST_TYPE unsupported
50# endif
51#endif
52
53#include <QtTest>
54#include <QAtomicInt>
55
56#include <limits>
57#include <limits.h>
58#include <wchar.h>
59
60#if !defined(Q_ATOMIC_INT32_IS_SUPPORTED)
61# error "QAtomicInteger for 32-bit types must be supported!"
62#endif
63#if QT_POINTER_SIZE == 8 && !defined(Q_ATOMIC_INT64_IS_SUPPORTED)
64# error "QAtomicInteger for 64-bit types must be supported on 64-bit builds!"
65#endif
66
67// always supported types:
68#define TYPE_SUPPORTED_int 1
69#define TYPE_SUPPORTED_uint 1
70#define TYPE_SUPPORTED_long 1
71#define TYPE_SUPPORTED_ulong 1
72#define TYPE_SUPPORTED_qptrdiff 1
73#define TYPE_SUPPORTED_quintptr 1
74#if (defined(__SIZEOF_WCHAR_T__) && (__SIZEOF_WCHAR_T__-0) > 2) \
75 || (defined(WCHAR_MAX) && (WCHAR_MAX-0 > 0x10000))
76# define TYPE_SUPPORTED_wchar_t 1
77#endif
78#ifdef Q_COMPILER_UNICODE_STRINGS
79# define TYPE_SUPPORTED_char32_t 1
80#endif
81
82#ifdef Q_ATOMIC_INT8_IS_SUPPORTED
83# define TYPE_SUPPORTED_char 1
84# define TYPE_SUPPORTED_uchar 1
85# define TYPE_SUPPORTED_schar 1
86#endif
87#ifdef Q_ATOMIC_INT16_IS_SUPPORTED
88# define TYPE_SUPPORTED_short 1
89# define TYPE_SUPPORTED_ushort 1
90# ifdef Q_COMPILER_UNICODE_STRINGS
91# define TYPE_SUPPORTED_char16_t 1
92# endif
93# ifndef TYPE_SUPPORTED_wchar_t
94# define TYPE_SUPPORTED_wchar_t 1
95# endif
96#endif
97#ifdef Q_ATOMIC_INT64_IS_SUPPORTED
98# define TYPE_SUPPORTED_qlonglong 1
99# define TYPE_SUPPORTED_qulonglong 1
100#endif
101
102#ifdef Q_MOC_RUN
103# define QATOMIC_TYPE_SUPPORTED(type) 1
104#else
105# define QATOMIC_TYPE_SUPPORTED2(type) TYPE_SUPPORTED_ ## type
106# define QATOMIC_TYPE_SUPPORTED(type) QATOMIC_TYPE_SUPPORTED2(type)
107#endif // Q_MOC_RUN
108
109#if QATOMIC_TYPE_SUPPORTED(QATOMIC_TEST_TYPE)
110# define TEST_TYPE QATOMIC_TEST_TYPE
111#else
112# define TEST_TYPE int
113# define QATOMIC_TEST_NOT_SUPPORTED
114#endif
115
116QT_WARNING_DISABLE_GCC("-Wtype-limits")
117QT_WARNING_DISABLE_GCC("-Wsign-compare")
118QT_WARNING_DISABLE_CLANG("-Wtautological-constant-out-of-range-compare")
119
120typedef signed char schar;
121
122typedef TEST_TYPE Type;
123typedef Type T; // shorthand
124enum {
125 TypeIsUnsigned = Type(-1) > Type(0),
126 TypeIsSigned = !TypeIsUnsigned
127};
128
129template <bool> struct LargeIntTemplate;
130template <> struct LargeIntTemplate<true> { typedef quint64 Type; };
131template <> struct LargeIntTemplate<false> { typedef qint64 Type; };
132typedef LargeIntTemplate<TypeIsUnsigned>::Type LargeInt;
133
134class tst_QAtomicIntegerXX : public QObject
135{
136 Q_OBJECT
137
138 void addData();
139
140private Q_SLOTS:
141 void initTestCase();
142 void static_checks();
143
144 void constructor_data() { addData(); }
145 void constructor();
146
147 void copy_data() { addData(); }
148 void copy();
149
150 void assign_data() { addData(); }
151 void assign();
152
153 void operatorInteger_data() { addData(); }
154 void operatorInteger();
155
156 void loadAcquireStoreRelease_data() { addData(); }
157 void loadAcquireStoreRelease();
158
159 void refDeref_data() { addData(); }
160 void refDeref();
161
162 void testAndSet_data() { addData(); }
163 void testAndSet();
164
165 void testAndSet3_data() { addData(); }
166 void testAndSet3();
167
168 void fetchAndStore_data() { addData(); }
169 void fetchAndStore();
170
171 void fetchAndAdd_data() { addData(); }
172 void fetchAndAdd();
173
174 void fetchAndSub_data() { addData(); }
175 void fetchAndSub();
176
177 void fetchAndOr_data() { addData(); }
178 void fetchAndOr();
179
180 void fetchAndAnd_data() { addData(); }
181 void fetchAndAnd();
182
183 void fetchAndXor_data() { addData(); }
184 void fetchAndXor();
185};
186
187template <bool> inline void booleanHelper() { }
188
189void tst_QAtomicIntegerXX::static_checks()
190{
191 Q_STATIC_ASSERT(sizeof(QAtomicInteger<T>) == sizeof(T));
192
193 // statements with no effect
194 (void) QAtomicInteger<T>::isReferenceCountingNative();
195 (void) QAtomicInteger<T>::isReferenceCountingWaitFree();
196 (void) QAtomicInteger<T>::isTestAndSetNative();
197 (void) QAtomicInteger<T>::isTestAndSetWaitFree();
198 (void) QAtomicInteger<T>::isFetchAndStoreNative();
199 (void) QAtomicInteger<T>::isFetchAndStoreWaitFree();
200 (void) QAtomicInteger<T>::isFetchAndAddNative();
201 (void) QAtomicInteger<T>::isFetchAndAddWaitFree();
202
203#ifdef Q_COMPILER_CONSTEXPR
204 // this is a compile-time test only
205 booleanHelper<QAtomicInteger<T>::isReferenceCountingNative()>();
206 booleanHelper<QAtomicInteger<T>::isReferenceCountingWaitFree()>();
207 booleanHelper<QAtomicInteger<T>::isTestAndSetNative()>();
208 booleanHelper<QAtomicInteger<T>::isTestAndSetWaitFree()>();
209 booleanHelper<QAtomicInteger<T>::isFetchAndStoreNative()>();
210 booleanHelper<QAtomicInteger<T>::isFetchAndStoreWaitFree()>();
211 booleanHelper<QAtomicInteger<T>::isFetchAndAddNative()>();
212 booleanHelper<QAtomicInteger<T>::isFetchAndAddWaitFree()>();
213#endif
214}
215
216void tst_QAtomicIntegerXX::addData()
217{
218 typedef std::numeric_limits<T> Limits;
219 QTest::addColumn<LargeInt>(name: "value");
220 QTest::newRow(dataTag: "0") << LargeInt(0);
221 QTest::newRow(dataTag: "+1") << LargeInt(1);
222 QTest::newRow(dataTag: "42") << LargeInt(42);
223 if (TypeIsSigned) {
224 QTest::newRow(dataTag: "-1") << qint64(-1);
225 QTest::newRow(dataTag: "-47") << qint64(-47);
226 }
227
228 // exercise bits
229 if (TypeIsSigned && Limits::min() < qint64(SCHAR_MIN))
230 QTest::newRow(dataTag: "int8_min") << qint64(SCHAR_MIN);
231 if (Limits::max() > LargeInt(SCHAR_MAX))
232 QTest::newRow(dataTag: "int8_max") << LargeInt(SCHAR_MAX);
233 if (Limits::max() > LargeInt(UCHAR_MAX))
234 QTest::newRow(dataTag: "uint8_max") << LargeInt(UCHAR_MAX);
235 if (TypeIsSigned && Limits::min() < -qint64(UCHAR_MAX))
236 QTest::newRow(dataTag: "-uint8_max") << -qint64(UCHAR_MAX);
237 if (Limits::max() > LargeInt(SHRT_MAX))
238 QTest::newRow(dataTag: "int16_max") << LargeInt(SHRT_MAX);
239 if (TypeIsSigned && Limits::min() < qint64(SHRT_MIN))
240 QTest::newRow(dataTag: "int16_min") << qint64(SHRT_MIN);
241 if (Limits::max() > LargeInt(USHRT_MAX))
242 QTest::newRow(dataTag: "uint16_max") << LargeInt(USHRT_MAX);
243 if (TypeIsSigned && Limits::min() < -qint64(USHRT_MAX))
244 QTest::newRow(dataTag: "-uint16_max") << -qint64(USHRT_MAX);
245 if (Limits::max() > LargeInt(INT_MAX))
246 QTest::newRow(dataTag: "int32_max") << LargeInt(INT_MAX);
247 if (TypeIsSigned && Limits::min() < qint64(INT_MIN))
248 QTest::newRow(dataTag: "int32_min") << qint64(INT_MIN);
249 if (Limits::max() > LargeInt(UINT_MAX))
250 QTest::newRow(dataTag: "uint32_max") << LargeInt(UINT_MAX);
251 if (Limits::max() > LargeInt(std::numeric_limits<qint64>::max()))
252 QTest::newRow(dataTag: "int64_max") << LargeInt(std::numeric_limits<qint64>::max());
253 if (TypeIsSigned && Limits::min() < -qint64(UINT_MAX))
254 QTest::newRow(dataTag: "-uint32_max") << -qint64(UINT_MAX);
255
256 if (TypeIsSigned)
257 QTest::newRow(QT_STRINGIFY(QATOMIC_TEST_TYPE) "_min") << qint64(Limits::min());
258 QTest::newRow(QT_STRINGIFY(QATOMIC_TEST_TYPE) "_max") << LargeInt(Limits::max());
259}
260
261void tst_QAtomicIntegerXX::initTestCase()
262{
263#ifdef QATOMIC_TEST_NOT_SUPPORTED
264 QSKIP("QAtomicInteger<" QT_STRINGIFY(QATOMIC_TEST_TYPE) "> is not supported on this platform");
265#endif
266}
267
268void tst_QAtomicIntegerXX::constructor()
269{
270 QFETCH(LargeInt, value);
271
272 QAtomicInteger<T> atomic(value);
273 QCOMPARE(atomic.loadRelaxed(), T(value));
274
275 QAtomicInteger<T> atomic2 = value;
276 QCOMPARE(atomic2.loadRelaxed(), T(value));
277
278 QVERIFY(atomic.loadRelaxed() >= std::numeric_limits<T>::min());
279 QVERIFY(atomic.loadRelaxed() <= std::numeric_limits<T>::max());
280}
281
282void tst_QAtomicIntegerXX::copy()
283{
284 QFETCH(LargeInt, value);
285
286 QAtomicInteger<T> atomic(value);
287 QAtomicInteger<T> copy(atomic);
288 QCOMPARE(copy.loadRelaxed(), atomic.loadRelaxed());
289
290 QAtomicInteger<T> copy2 = atomic;
291 QCOMPARE(copy2.loadRelaxed(), atomic.loadRelaxed());
292
293 // move
294 QAtomicInteger<T> copy3(std::move(copy));
295 QCOMPARE(copy3.loadRelaxed(), atomic.loadRelaxed());
296
297 QAtomicInteger<T> copy4 = std::move(copy2);
298 QCOMPARE(copy4.loadRelaxed(), atomic.loadRelaxed());
299}
300
301void tst_QAtomicIntegerXX::assign()
302{
303 QFETCH(LargeInt, value);
304
305 QAtomicInteger<T> atomic(value);
306 QAtomicInteger<T> copy;
307 copy = atomic;
308 QCOMPARE(copy.loadRelaxed(), atomic.loadRelaxed());
309
310 QAtomicInteger<T> copy2;
311 copy2 = atomic; // operator=(const QAtomicInteger &)
312 QCOMPARE(copy2.loadRelaxed(), atomic.loadRelaxed());
313
314 QAtomicInteger<T> copy2bis;
315 copy2bis = atomic.loadRelaxed(); // operator=(T)
316 QCOMPARE(copy2bis.loadRelaxed(), atomic.loadRelaxed());
317
318 // move
319 QAtomicInteger<T> copy3;
320 copy3 = std::move(copy);
321 QCOMPARE(copy3.loadRelaxed(), atomic.loadRelaxed());
322
323 QAtomicInteger<T> copy4;
324 copy4 = std::move(copy2);
325 QCOMPARE(copy4.loadRelaxed(), atomic.loadRelaxed());
326}
327
328void tst_QAtomicIntegerXX::operatorInteger()
329{
330 QFETCH(LargeInt, value);
331
332 QAtomicInteger<T> atomic(value);
333 T val2 = atomic;
334 QCOMPARE(val2, atomic.loadRelaxed());
335 QCOMPARE(val2, T(value));
336}
337
338void tst_QAtomicIntegerXX::loadAcquireStoreRelease()
339{
340 QFETCH(LargeInt, value);
341
342 QAtomicInteger<T> atomic(value);
343 QCOMPARE(atomic.loadAcquire(), T(value));
344
345 atomic.storeRelease(newValue: ~value);
346 QCOMPARE(atomic.loadAcquire(), T(~value));
347
348 atomic.storeRelease(newValue: value);
349 QCOMPARE(atomic.loadRelaxed(), T(value));
350}
351
352void tst_QAtomicIntegerXX::refDeref()
353{
354 QFETCH(LargeInt, value);
355 const bool needToPreventOverflow = TypeIsSigned && value == std::numeric_limits<T>::max();
356 const bool needToPreventUnderflow = TypeIsSigned && value == std::numeric_limits<T>::min();
357 T nextValue = T(value);
358 if (!needToPreventOverflow)
359 ++nextValue;
360 T prevValue = T(value);
361 if (!needToPreventUnderflow)
362 --prevValue;
363
364 QAtomicInteger<T> atomic(value);
365 if (!needToPreventOverflow) {
366 QCOMPARE(atomic.ref(), (nextValue != 0));
367 QCOMPARE(atomic.loadRelaxed(), nextValue);
368 QCOMPARE(atomic.deref(), (value != 0));
369 }
370 QCOMPARE(atomic.loadRelaxed(), T(value));
371 if (!needToPreventUnderflow) {
372 QCOMPARE(atomic.deref(), (prevValue != 0));
373 QCOMPARE(atomic.loadRelaxed(), prevValue);
374 QCOMPARE(atomic.ref(), (value != 0));
375 }
376 QCOMPARE(atomic.loadRelaxed(), T(value));
377
378 if (!needToPreventOverflow) {
379 QCOMPARE(++atomic, nextValue);
380 QCOMPARE(--atomic, T(value));
381 }
382 if (!needToPreventUnderflow) {
383 QCOMPARE(--atomic, prevValue);
384 QCOMPARE(++atomic, T(value));
385 }
386
387 if (!needToPreventOverflow) {
388 QCOMPARE(atomic++, T(value));
389 QCOMPARE(atomic--, nextValue);
390 }
391 if (!needToPreventUnderflow) {
392 QCOMPARE(atomic--, T(value));
393 QCOMPARE(atomic++, prevValue);
394 }
395 QCOMPARE(atomic.loadRelaxed(), T(value));
396}
397
398void tst_QAtomicIntegerXX::testAndSet()
399{
400 QFETCH(LargeInt, value);
401 T newValue = ~T(value);
402 QAtomicInteger<T> atomic(value);
403
404 QVERIFY(atomic.testAndSetRelaxed(value, newValue));
405 QCOMPARE(atomic.loadRelaxed(), newValue);
406 QVERIFY(!atomic.testAndSetRelaxed(value, newValue));
407 QVERIFY(atomic.testAndSetRelaxed(newValue, value));
408 QCOMPARE(atomic.loadRelaxed(), T(value));
409
410 QVERIFY(atomic.testAndSetAcquire(value, newValue));
411 QCOMPARE(atomic.loadRelaxed(), newValue);
412 QVERIFY(!atomic.testAndSetAcquire(value, newValue));
413 QVERIFY(atomic.testAndSetAcquire(newValue, value));
414 QCOMPARE(atomic.loadRelaxed(), T(value));
415
416 QVERIFY(atomic.testAndSetRelease(value, newValue));
417 QCOMPARE(atomic.loadAcquire(), newValue);
418 QVERIFY(!atomic.testAndSetRelease(value, newValue));
419 QVERIFY(atomic.testAndSetRelease(newValue, value));
420 QCOMPARE(atomic.loadAcquire(), T(value));
421
422 QVERIFY(atomic.testAndSetOrdered(value, newValue));
423 QCOMPARE(atomic.loadAcquire(), newValue);
424 QVERIFY(!atomic.testAndSetOrdered(value, newValue));
425 QVERIFY(atomic.testAndSetOrdered(newValue, value));
426 QCOMPARE(atomic.loadAcquire(), T(value));
427}
428
429void tst_QAtomicIntegerXX::testAndSet3()
430{
431 QFETCH(LargeInt, value);
432 T newValue = ~T(value);
433 T oldValue;
434 QAtomicInteger<T> atomic(value);
435
436 QVERIFY(atomic.testAndSetRelaxed(value, newValue, oldValue));
437 QCOMPARE(atomic.loadRelaxed(), newValue);
438 QVERIFY(!atomic.testAndSetRelaxed(value, newValue, oldValue));
439 QCOMPARE(oldValue, newValue);
440 QVERIFY(atomic.testAndSetRelaxed(newValue, value, oldValue));
441 QCOMPARE(atomic.loadRelaxed(), T(value));
442
443 QVERIFY(atomic.testAndSetAcquire(value, newValue, oldValue));
444 QCOMPARE(atomic.loadRelaxed(), newValue);
445 QVERIFY(!atomic.testAndSetAcquire(value, newValue, oldValue));
446 QCOMPARE(oldValue, newValue);
447 QVERIFY(atomic.testAndSetAcquire(newValue, value, oldValue));
448 QCOMPARE(atomic.loadRelaxed(), T(value));
449
450 QVERIFY(atomic.testAndSetRelease(value, newValue, oldValue));
451 QCOMPARE(atomic.loadAcquire(), newValue);
452 QVERIFY(!atomic.testAndSetRelease(value, newValue, oldValue));
453 QCOMPARE(oldValue, newValue);
454 QVERIFY(atomic.testAndSetRelease(newValue, value, oldValue));
455 QCOMPARE(atomic.loadAcquire(), T(value));
456
457 QVERIFY(atomic.testAndSetOrdered(value, newValue, oldValue));
458 QCOMPARE(atomic.loadAcquire(), newValue);
459 QVERIFY(!atomic.testAndSetOrdered(value, newValue, oldValue));
460 QCOMPARE(oldValue, newValue);
461 QVERIFY(atomic.testAndSetOrdered(newValue, value, oldValue));
462 QCOMPARE(atomic.loadAcquire(), T(value));
463}
464
465void tst_QAtomicIntegerXX::fetchAndStore()
466{
467 QFETCH(LargeInt, value);
468 T newValue = ~T(value);
469 QAtomicInteger<T> atomic(value);
470
471 QCOMPARE(atomic.fetchAndStoreRelaxed(newValue), T(value));
472 QCOMPARE(atomic.loadRelaxed(), newValue);
473 QCOMPARE(atomic.fetchAndStoreRelaxed(value), newValue);
474 QCOMPARE(atomic.loadRelaxed(), T(value));
475
476 QCOMPARE(atomic.fetchAndStoreAcquire(newValue), T(value));
477 QCOMPARE(atomic.loadRelaxed(), newValue);
478 QCOMPARE(atomic.fetchAndStoreAcquire(value), newValue);
479 QCOMPARE(atomic.loadRelaxed(), T(value));
480
481 QCOMPARE(atomic.fetchAndStoreRelease(newValue), T(value));
482 QCOMPARE(atomic.loadAcquire(), newValue);
483 QCOMPARE(atomic.fetchAndStoreRelease(value), newValue);
484 QCOMPARE(atomic.loadAcquire(), T(value));
485
486 QCOMPARE(atomic.fetchAndStoreOrdered(newValue), T(value));
487 QCOMPARE(atomic.loadAcquire(), newValue);
488 QCOMPARE(atomic.fetchAndStoreOrdered(value), newValue);
489 QCOMPARE(atomic.loadAcquire(), T(value));
490}
491
492void tst_QAtomicIntegerXX::fetchAndAdd()
493{
494 QFETCH(LargeInt, value);
495 QAtomicInteger<T> atomic(value);
496
497 T parcel1 = 42;
498 T parcel2 = T(0-parcel1);
499
500 const bool needToPreventOverflow = TypeIsSigned && value > std::numeric_limits<T>::max() + parcel2;
501 const bool needToPreventUnderflow = TypeIsSigned && value < std::numeric_limits<T>::min() + parcel1;
502
503 T newValue1 = T(value);
504 if (!needToPreventOverflow)
505 newValue1 += parcel1;
506 T newValue2 = T(value);
507 if (!needToPreventUnderflow)
508 newValue2 += parcel2;
509
510 if (!needToPreventOverflow) {
511 QCOMPARE(atomic.fetchAndAddRelaxed(parcel1), T(value));
512 QCOMPARE(atomic.loadRelaxed(), newValue1);
513 QCOMPARE(atomic.fetchAndAddRelaxed(parcel2), newValue1);
514 }
515 QCOMPARE(atomic.loadRelaxed(), T(value));
516 if (!needToPreventUnderflow) {
517 QCOMPARE(atomic.fetchAndAddRelaxed(parcel2), T(value));
518 QCOMPARE(atomic.loadRelaxed(), newValue2);
519 QCOMPARE(atomic.fetchAndAddRelaxed(parcel1), newValue2);
520 }
521 QCOMPARE(atomic.loadRelaxed(), T(value));
522
523 if (!needToPreventOverflow) {
524 QCOMPARE(atomic.fetchAndAddAcquire(parcel1), T(value));
525 QCOMPARE(atomic.loadRelaxed(), newValue1);
526 QCOMPARE(atomic.fetchAndAddAcquire(parcel2), newValue1);
527 }
528 QCOMPARE(atomic.loadRelaxed(), T(value));
529 if (!needToPreventUnderflow) {
530 QCOMPARE(atomic.fetchAndAddAcquire(parcel2), T(value));
531 QCOMPARE(atomic.loadRelaxed(), newValue2);
532 QCOMPARE(atomic.fetchAndAddAcquire(parcel1), newValue2);
533 }
534 QCOMPARE(atomic.loadRelaxed(), T(value));
535
536 if (!needToPreventOverflow) {
537 QCOMPARE(atomic.fetchAndAddRelease(parcel1), T(value));
538 QCOMPARE(atomic.loadAcquire(), newValue1);
539 QCOMPARE(atomic.fetchAndAddRelease(parcel2), newValue1);
540 }
541 QCOMPARE(atomic.loadAcquire(), T(value));
542 if (!needToPreventUnderflow) {
543 QCOMPARE(atomic.fetchAndAddRelease(parcel2), T(value));
544 QCOMPARE(atomic.loadAcquire(), newValue2);
545 QCOMPARE(atomic.fetchAndAddRelease(parcel1), newValue2);
546 }
547 QCOMPARE(atomic.loadAcquire(), T(value));
548
549 if (!needToPreventOverflow) {
550 QCOMPARE(atomic.fetchAndAddOrdered(parcel1), T(value));
551 QCOMPARE(atomic.loadAcquire(), newValue1);
552 QCOMPARE(atomic.fetchAndAddOrdered(parcel2), newValue1);
553 }
554 QCOMPARE(atomic.loadAcquire(), T(value));
555 if (!needToPreventUnderflow) {
556 QCOMPARE(atomic.fetchAndAddOrdered(parcel2), T(value));
557 QCOMPARE(atomic.loadAcquire(), newValue2);
558 QCOMPARE(atomic.fetchAndAddOrdered(parcel1), newValue2);
559 }
560 QCOMPARE(atomic.loadAcquire(), T(value));
561
562 // operator+=
563 if (!needToPreventOverflow) {
564 QCOMPARE(atomic += parcel1, newValue1);
565 QCOMPARE(atomic += parcel2, T(value));
566 }
567 if (!needToPreventUnderflow) {
568 QCOMPARE(atomic += parcel2, newValue2);
569 QCOMPARE(atomic += parcel1, T(value));
570 }
571}
572
573void tst_QAtomicIntegerXX::fetchAndSub()
574{
575 QFETCH(LargeInt, value);
576 QAtomicInteger<T> atomic(value);
577
578 T parcel1 = 42;
579 T parcel2 = T(0-parcel1);
580
581 const bool needToPreventOverflow = TypeIsSigned && value > std::numeric_limits<T>::max() - parcel1;
582 const bool needToPreventUnderflow = TypeIsSigned && value < std::numeric_limits<T>::min() - parcel2;
583
584 T newValue1 = T(value);
585 if (!needToPreventUnderflow)
586 newValue1 -= parcel1;
587 T newValue2 = T(value);
588 if (!needToPreventOverflow)
589 newValue2 -= parcel2;
590
591 if (!needToPreventUnderflow) {
592 QCOMPARE(atomic.fetchAndSubRelaxed(parcel1), T(value));
593 QCOMPARE(atomic.loadRelaxed(), newValue1);
594 QCOMPARE(atomic.fetchAndSubRelaxed(parcel2), newValue1);
595 }
596 QCOMPARE(atomic.loadRelaxed(), T(value));
597 if (!needToPreventOverflow) {
598 QCOMPARE(atomic.fetchAndSubRelaxed(parcel2), T(value));
599 QCOMPARE(atomic.loadRelaxed(), newValue2);
600 QCOMPARE(atomic.fetchAndSubRelaxed(parcel1), newValue2);
601 }
602 QCOMPARE(atomic.loadRelaxed(), T(value));
603
604 if (!needToPreventUnderflow) {
605 QCOMPARE(atomic.fetchAndSubAcquire(parcel1), T(value));
606 QCOMPARE(atomic.loadRelaxed(), newValue1);
607 QCOMPARE(atomic.fetchAndSubAcquire(parcel2), newValue1);
608 }
609 QCOMPARE(atomic.loadRelaxed(), T(value));
610 if (!needToPreventOverflow) {
611 QCOMPARE(atomic.fetchAndSubAcquire(parcel2), T(value));
612 QCOMPARE(atomic.loadRelaxed(), newValue2);
613 QCOMPARE(atomic.fetchAndSubAcquire(parcel1), newValue2);
614 }
615 QCOMPARE(atomic.loadRelaxed(), T(value));
616
617 if (!needToPreventUnderflow) {
618 QCOMPARE(atomic.fetchAndSubRelease(parcel1), T(value));
619 QCOMPARE(atomic.loadAcquire(), newValue1);
620 QCOMPARE(atomic.fetchAndSubRelease(parcel2), newValue1);
621 }
622 QCOMPARE(atomic.loadAcquire(), T(value));
623 if (!needToPreventOverflow) {
624 QCOMPARE(atomic.fetchAndSubRelease(parcel2), T(value));
625 QCOMPARE(atomic.loadAcquire(), newValue2);
626 QCOMPARE(atomic.fetchAndSubRelease(parcel1), newValue2);
627 }
628 QCOMPARE(atomic.loadAcquire(), T(value));
629
630 if (!needToPreventUnderflow) {
631 QCOMPARE(atomic.fetchAndSubOrdered(parcel1), T(value));
632 QCOMPARE(atomic.loadAcquire(), newValue1);
633 QCOMPARE(atomic.fetchAndSubOrdered(parcel2), newValue1);
634 }
635 QCOMPARE(atomic.loadAcquire(), T(value));
636 if (!needToPreventOverflow) {
637 QCOMPARE(atomic.fetchAndSubOrdered(parcel2), T(value));
638 QCOMPARE(atomic.loadAcquire(), newValue2);
639 QCOMPARE(atomic.fetchAndSubOrdered(parcel1), newValue2);
640 }
641 QCOMPARE(atomic.loadAcquire(), T(value));
642
643 // operator-=
644 if (!needToPreventUnderflow) {
645 QCOMPARE(atomic -= parcel1, newValue1);
646 QCOMPARE(atomic -= parcel2, T(value));
647 }
648 if (!needToPreventOverflow) {
649 QCOMPARE(atomic -= parcel2, newValue2);
650 QCOMPARE(atomic -= parcel1, T(value));
651 }
652}
653
654void tst_QAtomicIntegerXX::fetchAndOr()
655{
656 QFETCH(LargeInt, value);
657 QAtomicInteger<T> atomic(value);
658
659 T zero = 0;
660 T one = 1;
661 T minusOne = T(~0);
662
663 QCOMPARE(atomic.fetchAndOrRelaxed(zero), T(value));
664 QCOMPARE(atomic.fetchAndOrRelaxed(one), T(value));
665 QCOMPARE(atomic.loadRelaxed(), T(value | 1));
666 QCOMPARE(atomic.fetchAndOrRelaxed(minusOne), T(value | 1));
667 QCOMPARE(atomic.loadRelaxed(), minusOne);
668
669 atomic.storeRelaxed(newValue: value);
670 QCOMPARE(atomic.fetchAndOrAcquire(zero), T(value));
671 QCOMPARE(atomic.fetchAndOrAcquire(one), T(value));
672 QCOMPARE(atomic.loadRelaxed(), T(value | 1));
673 QCOMPARE(atomic.fetchAndOrAcquire(minusOne), T(value | 1));
674 QCOMPARE(atomic.loadRelaxed(), minusOne);
675
676 atomic.storeRelaxed(newValue: value);
677 QCOMPARE(atomic.fetchAndOrRelease(zero), T(value));
678 QCOMPARE(atomic.fetchAndOrRelease(one), T(value));
679 QCOMPARE(atomic.loadRelaxed(), T(value | 1));
680 QCOMPARE(atomic.fetchAndOrRelease(minusOne), T(value | 1));
681 QCOMPARE(atomic.loadRelaxed(), minusOne);
682
683 atomic.storeRelaxed(newValue: value);
684 QCOMPARE(atomic.fetchAndOrOrdered(zero), T(value));
685 QCOMPARE(atomic.fetchAndOrOrdered(one), T(value));
686 QCOMPARE(atomic.loadRelaxed(), T(value | 1));
687 QCOMPARE(atomic.fetchAndOrOrdered(minusOne), T(value | 1));
688 QCOMPARE(atomic.loadRelaxed(), minusOne);
689
690 atomic.storeRelaxed(newValue: value);
691 QCOMPARE(atomic |= zero, T(value));
692 QCOMPARE(atomic |= one, T(value | 1));
693 QCOMPARE(atomic |= minusOne, minusOne);
694}
695
696void tst_QAtomicIntegerXX::fetchAndAnd()
697{
698 QFETCH(LargeInt, value);
699 QAtomicInteger<T> atomic(value);
700
701 T zero = 0;
702 T f = 0xf;
703 T minusOne = T(~0);
704
705 QCOMPARE(atomic.fetchAndAndRelaxed(minusOne), T(value));
706 QCOMPARE(atomic.loadRelaxed(), T(value));
707 QCOMPARE(atomic.fetchAndAndRelaxed(f), T(value));
708 QCOMPARE(atomic.loadRelaxed(), T(value & 0xf));
709 QCOMPARE(atomic.fetchAndAndRelaxed(zero), T(value & 0xf));
710 QCOMPARE(atomic.loadRelaxed(), zero);
711
712 atomic.storeRelaxed(newValue: value);
713 QCOMPARE(atomic.fetchAndAndAcquire(minusOne), T(value));
714 QCOMPARE(atomic.loadRelaxed(), T(value));
715 QCOMPARE(atomic.fetchAndAndAcquire(f), T(value));
716 QCOMPARE(atomic.loadRelaxed(), T(value & 0xf));
717 QCOMPARE(atomic.fetchAndAndAcquire(zero), T(value & 0xf));
718 QCOMPARE(atomic.loadRelaxed(), zero);
719
720 atomic.storeRelaxed(newValue: value);
721 QCOMPARE(atomic.fetchAndAndRelease(minusOne), T(value));
722 QCOMPARE(atomic.loadRelaxed(), T(value));
723 QCOMPARE(atomic.fetchAndAndRelease(f), T(value));
724 QCOMPARE(atomic.loadRelaxed(), T(value & 0xf));
725 QCOMPARE(atomic.fetchAndAndRelease(zero), T(value & 0xf));
726 QCOMPARE(atomic.loadRelaxed(), zero);
727
728 atomic.storeRelaxed(newValue: value);
729 QCOMPARE(atomic.fetchAndAndOrdered(minusOne), T(value));
730 QCOMPARE(atomic.loadRelaxed(), T(value));
731 QCOMPARE(atomic.fetchAndAndOrdered(f), T(value));
732 QCOMPARE(atomic.loadRelaxed(), T(value & 0xf));
733 QCOMPARE(atomic.fetchAndAndOrdered(zero), T(value & 0xf));
734 QCOMPARE(atomic.loadRelaxed(), zero);
735
736 atomic.storeRelaxed(newValue: value);
737 QCOMPARE(atomic &= minusOne, T(value));
738 QCOMPARE(atomic &= f, T(value & 0xf));
739 QCOMPARE(atomic &= zero, zero);
740}
741
742void tst_QAtomicIntegerXX::fetchAndXor()
743{
744 QFETCH(LargeInt, value);
745 QAtomicInteger<T> atomic(value);
746
747 T zero = 0;
748 T pattern = T(Q_UINT64_C(0xcccccccccccccccc));
749 T minusOne = T(~0);
750
751 QCOMPARE(atomic.fetchAndXorRelaxed(zero), T(value));
752 QCOMPARE(atomic.loadRelaxed(), T(value));
753 QCOMPARE(atomic.fetchAndXorRelaxed(pattern), T(value));
754 QCOMPARE(atomic.loadRelaxed(), T(value ^ pattern));
755 QCOMPARE(atomic.fetchAndXorRelaxed(pattern), T(value ^ pattern));
756 QCOMPARE(atomic.loadRelaxed(), T(value));
757 QCOMPARE(atomic.fetchAndXorRelaxed(minusOne), T(value));
758 QCOMPARE(atomic.loadRelaxed(), T(~value));
759 QCOMPARE(atomic.fetchAndXorRelaxed(minusOne), T(~value));
760 QCOMPARE(atomic.loadRelaxed(), T(value));
761
762 QCOMPARE(atomic.fetchAndXorAcquire(zero), T(value));
763 QCOMPARE(atomic.loadRelaxed(), T(value));
764 QCOMPARE(atomic.fetchAndXorAcquire(pattern), T(value));
765 QCOMPARE(atomic.loadRelaxed(), T(value ^ pattern));
766 QCOMPARE(atomic.fetchAndXorAcquire(pattern), T(value ^ pattern));
767 QCOMPARE(atomic.loadRelaxed(), T(value));
768 QCOMPARE(atomic.fetchAndXorAcquire(minusOne), T(value));
769 QCOMPARE(atomic.loadRelaxed(), T(~value));
770 QCOMPARE(atomic.fetchAndXorAcquire(minusOne), T(~value));
771 QCOMPARE(atomic.loadRelaxed(), T(value));
772
773 QCOMPARE(atomic.fetchAndXorRelease(zero), T(value));
774 QCOMPARE(atomic.loadRelaxed(), T(value));
775 QCOMPARE(atomic.fetchAndXorRelease(pattern), T(value));
776 QCOMPARE(atomic.loadRelaxed(), T(value ^ pattern));
777 QCOMPARE(atomic.fetchAndXorRelease(pattern), T(value ^ pattern));
778 QCOMPARE(atomic.loadRelaxed(), T(value));
779 QCOMPARE(atomic.fetchAndXorRelease(minusOne), T(value));
780 QCOMPARE(atomic.loadRelaxed(), T(~value));
781 QCOMPARE(atomic.fetchAndXorRelease(minusOne), T(~value));
782 QCOMPARE(atomic.loadRelaxed(), T(value));
783
784 QCOMPARE(atomic.fetchAndXorOrdered(zero), T(value));
785 QCOMPARE(atomic.loadRelaxed(), T(value));
786 QCOMPARE(atomic.fetchAndXorOrdered(pattern), T(value));
787 QCOMPARE(atomic.loadRelaxed(), T(value ^ pattern));
788 QCOMPARE(atomic.fetchAndXorOrdered(pattern), T(value ^ pattern));
789 QCOMPARE(atomic.loadRelaxed(), T(value));
790 QCOMPARE(atomic.fetchAndXorOrdered(minusOne), T(value));
791 QCOMPARE(atomic.loadRelaxed(), T(~value));
792 QCOMPARE(atomic.fetchAndXorOrdered(minusOne), T(~value));
793 QCOMPARE(atomic.loadRelaxed(), T(value));
794
795 QCOMPARE(atomic ^= zero, T(value));
796 QCOMPARE(atomic ^= pattern, T(value ^ pattern));
797 QCOMPARE(atomic ^= pattern, T(value));
798 QCOMPARE(atomic ^= minusOne, T(~value));
799 QCOMPARE(atomic ^= minusOne, T(value));
800}
801
802#include "tst_qatomicinteger.moc"
803
804QTEST_APPLESS_MAIN(tst_QAtomicIntegerXX)
805
806

source code of qtbase/tests/auto/corelib/thread/qatomicinteger/tst_qatomicinteger.cpp