1// Copyright 2017 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <fbl/atomic.h>
6
7#include <fbl/limits.h>
8#include <unittest/unittest.h>
9
10namespace {
11
12// A struct with an interesting size for pointer arithmetic tests.
13struct S {
14    char bytes[48];
15};
16
17using function_pointer = void(*)();
18
19bool atomic_explicit_declarations_test() {
20    BEGIN_TEST;
21
22    [[gnu::unused]] fbl::atomic<char> zero_char(0);
23    [[gnu::unused]] fbl::atomic<signed char> zero_schar(0);
24    [[gnu::unused]] fbl::atomic<unsigned char> zero_uchar(0);
25    [[gnu::unused]] fbl::atomic<short> zero_short(0);
26    [[gnu::unused]] fbl::atomic<unsigned short> zero_ushort(0);
27    [[gnu::unused]] fbl::atomic<int> zero_int(0);
28    [[gnu::unused]] fbl::atomic<unsigned int> zero_uint(0);
29    [[gnu::unused]] fbl::atomic<long> zero_long(0);
30    [[gnu::unused]] fbl::atomic<unsigned long> zero_ulong(0);
31    [[gnu::unused]] fbl::atomic<long long> zero_llong(0);
32    [[gnu::unused]] fbl::atomic<unsigned long long> zero_ullong(0);
33
34    [[gnu::unused]] fbl::atomic<intptr_t> zero_intptr_t(0);
35    [[gnu::unused]] fbl::atomic<uintptr_t> zero_uintptr_t(0);
36    [[gnu::unused]] fbl::atomic<size_t> zero_size_t(0);
37    [[gnu::unused]] fbl::atomic<ptrdiff_t> zero_ptrdiff_t(0);
38    [[gnu::unused]] fbl::atomic<intmax_t> zero_intmax_t(0);
39    [[gnu::unused]] fbl::atomic<uintmax_t> zero_uintmax_t(0);
40
41    [[gnu::unused]] fbl::atomic<int8_t> zero_int8_t(0);
42    [[gnu::unused]] fbl::atomic<uint8_t> zero_uint8_t(0);
43    [[gnu::unused]] fbl::atomic<int16_t> zero_int16_t(0);
44    [[gnu::unused]] fbl::atomic<uint16_t> zero_uint16_t(0);
45    [[gnu::unused]] fbl::atomic<int32_t> zero_int32_t(0);
46    [[gnu::unused]] fbl::atomic<uint32_t> zero_uint32_t(0);
47    [[gnu::unused]] fbl::atomic<int64_t> zero_int64_t(0);
48    [[gnu::unused]] fbl::atomic<uint64_t> zero_uint64_t(0);
49
50    [[gnu::unused]] fbl::atomic<int_least8_t> zero_int_least8_t(0);
51    [[gnu::unused]] fbl::atomic<uint_least8_t> zero_uint_least8_t(0);
52    [[gnu::unused]] fbl::atomic<int_least16_t> zero_int_least16_t(0);
53    [[gnu::unused]] fbl::atomic<uint_least16_t> zero_uint_least16_t(0);
54    [[gnu::unused]] fbl::atomic<int_least32_t> zero_int_least32_t(0);
55    [[gnu::unused]] fbl::atomic<uint_least32_t> zero_uint_least32_t(0);
56    [[gnu::unused]] fbl::atomic<int_least64_t> zero_int_least64_t(0);
57    [[gnu::unused]] fbl::atomic<uint_least64_t> zero_uint_least64_t(0);
58    [[gnu::unused]] fbl::atomic<int_fast8_t> zero_int_fast8_t(0);
59    [[gnu::unused]] fbl::atomic<uint_fast8_t> zero_uint_fast8_t(0);
60    [[gnu::unused]] fbl::atomic<int_fast16_t> zero_int_fast16_t(0);
61    [[gnu::unused]] fbl::atomic<uint_fast16_t> zero_uint_fast16_t(0);
62    [[gnu::unused]] fbl::atomic<int_fast32_t> zero_int_fast32_t(0);
63    [[gnu::unused]] fbl::atomic<uint_fast32_t> zero_uint_fast32_t(0);
64    [[gnu::unused]] fbl::atomic<int_fast64_t> zero_int_fast64_t(0);
65    [[gnu::unused]] fbl::atomic<uint_fast64_t> zero_uint_fast64_t(0);
66
67    [[gnu::unused]] fbl::atomic<bool> zero_bool(false);
68
69    [[gnu::unused]] fbl::atomic<void*> zero_void_pointer(nullptr);
70    [[gnu::unused]] fbl::atomic<const void*> zero_const_void_pointer(nullptr);
71    [[gnu::unused]] fbl::atomic<volatile void*> zero_volatile_void_pointer(nullptr);
72    [[gnu::unused]] fbl::atomic<const volatile void*> zero_const_volatile_void_pointer(nullptr);
73    [[gnu::unused]] fbl::atomic<int*> zero_int_pointer(nullptr);
74    [[gnu::unused]] fbl::atomic<const int*> zero_const_int_pointer(nullptr);
75    [[gnu::unused]] fbl::atomic<volatile int*> zero_volatile_int_pointer(nullptr);
76    [[gnu::unused]] fbl::atomic<const volatile int*> zero_const_volatile_int_pointer(nullptr);
77    [[gnu::unused]] fbl::atomic<S*> zero_S_pointer(nullptr);
78    [[gnu::unused]] fbl::atomic<const S*> zero_const_S_pointer(nullptr);
79    [[gnu::unused]] fbl::atomic<volatile S*> zero_volatile_S_pointer(nullptr);
80    [[gnu::unused]] fbl::atomic<const volatile S*> zero_const_volatile_S_pointer(nullptr);
81    [[gnu::unused]] fbl::atomic<function_pointer> zero_function_pointer(nullptr);
82
83    END_TEST;
84}
85
86bool atomic_using_declarations_test() {
87    BEGIN_TEST;
88
89    [[gnu::unused]] fbl::atomic_char zero_char(0);
90    [[gnu::unused]] fbl::atomic_schar zero_schar(0);
91    [[gnu::unused]] fbl::atomic_uchar zero_uchar(0);
92    [[gnu::unused]] fbl::atomic_short zero_short(0);
93    [[gnu::unused]] fbl::atomic_ushort zero_ushort(0);
94    [[gnu::unused]] fbl::atomic_int zero_int(0);
95    [[gnu::unused]] fbl::atomic_uint zero_uint(0);
96    [[gnu::unused]] fbl::atomic_long zero_long(0);
97    [[gnu::unused]] fbl::atomic_ulong zero_ulong(0);
98    [[gnu::unused]] fbl::atomic_llong zero_llong(0);
99    [[gnu::unused]] fbl::atomic_ullong zero_ullong(0);
100
101    [[gnu::unused]] fbl::atomic_intptr_t zero_intptr_t(0);
102    [[gnu::unused]] fbl::atomic_uintptr_t zero_uintptr_t(0);
103    [[gnu::unused]] fbl::atomic_size_t zero_size_t(0);
104    [[gnu::unused]] fbl::atomic_ptrdiff_t zero_ptrdiff_t(0);
105    [[gnu::unused]] fbl::atomic_intmax_t zero_intmax_t(0);
106    [[gnu::unused]] fbl::atomic_uintmax_t zero_uintmax_t(0);
107
108    [[gnu::unused]] fbl::atomic_int8_t zero_int8_t(0);
109    [[gnu::unused]] fbl::atomic_uint8_t zero_uint8_t(0);
110    [[gnu::unused]] fbl::atomic_int16_t zero_int16_t(0);
111    [[gnu::unused]] fbl::atomic_uint16_t zero_uint16_t(0);
112    [[gnu::unused]] fbl::atomic_int32_t zero_int32_t(0);
113    [[gnu::unused]] fbl::atomic_uint32_t zero_uint32_t(0);
114    [[gnu::unused]] fbl::atomic_int64_t zero_int64_t(0);
115    [[gnu::unused]] fbl::atomic_uint64_t zero_uint64_t(0);
116
117    [[gnu::unused]] fbl::atomic_int_least8_t zero_int_least8_t(0);
118    [[gnu::unused]] fbl::atomic_uint_least8_t zero_uint_least8_t(0);
119    [[gnu::unused]] fbl::atomic_int_least16_t zero_int_least16_t(0);
120    [[gnu::unused]] fbl::atomic_uint_least16_t zero_uint_least16_t(0);
121    [[gnu::unused]] fbl::atomic_int_least32_t zero_int_least32_t(0);
122    [[gnu::unused]] fbl::atomic_uint_least32_t zero_uint_least32_t(0);
123    [[gnu::unused]] fbl::atomic_int_least64_t zero_int_least64_t(0);
124    [[gnu::unused]] fbl::atomic_uint_least64_t zero_uint_least64_t(0);
125    [[gnu::unused]] fbl::atomic_int_fast8_t zero_int_fast8_t(0);
126    [[gnu::unused]] fbl::atomic_uint_fast8_t zero_uint_fast8_t(0);
127    [[gnu::unused]] fbl::atomic_int_fast16_t zero_int_fast16_t(0);
128    [[gnu::unused]] fbl::atomic_uint_fast16_t zero_uint_fast16_t(0);
129    [[gnu::unused]] fbl::atomic_int_fast32_t zero_int_fast32_t(0);
130    [[gnu::unused]] fbl::atomic_uint_fast32_t zero_uint_fast32_t(0);
131    [[gnu::unused]] fbl::atomic_int_fast64_t zero_int_fast64_t(0);
132    [[gnu::unused]] fbl::atomic_uint_fast64_t zero_uint_fast64_t(0);
133
134    [[gnu::unused]] fbl::atomic_bool zero_bool(false);
135
136    END_TEST;
137}
138
139// To increase test readability after this point, static_assert that
140// most of these are the same as fbl::atomic<some other type>. That
141// way no one has to read a million lines of test code about
142// fbl::atomic_uint_least32_t.
143
144template <typename T>
145constexpr bool IsSameAsSomeBuiltin() {
146    return fbl::is_same<T, fbl::atomic_char>::value ||
147           fbl::is_same<T, fbl::atomic_schar>::value ||
148           fbl::is_same<T, fbl::atomic_uchar>::value ||
149           fbl::is_same<T, fbl::atomic_short>::value ||
150           fbl::is_same<T, fbl::atomic_ushort>::value ||
151           fbl::is_same<T, fbl::atomic_int>::value ||
152           fbl::is_same<T, fbl::atomic_uint>::value ||
153           fbl::is_same<T, fbl::atomic_long>::value ||
154           fbl::is_same<T, fbl::atomic_ulong>::value ||
155           fbl::is_same<T, fbl::atomic_llong>::value ||
156           fbl::is_same<T, fbl::atomic_ullong>::value ||
157           fbl::is_same<T, fbl::atomic_bool>::value;
158}
159
160static_assert(IsSameAsSomeBuiltin<fbl::atomic_intptr_t>(), "");
161static_assert(IsSameAsSomeBuiltin<fbl::atomic_uintptr_t>(), "");
162static_assert(IsSameAsSomeBuiltin<fbl::atomic_size_t>(), "");
163static_assert(IsSameAsSomeBuiltin<fbl::atomic_ptrdiff_t>(), "");
164static_assert(IsSameAsSomeBuiltin<fbl::atomic_intmax_t>(), "");
165static_assert(IsSameAsSomeBuiltin<fbl::atomic_uintmax_t>(), "");
166
167static_assert(IsSameAsSomeBuiltin<fbl::atomic_int8_t>(), "");
168static_assert(IsSameAsSomeBuiltin<fbl::atomic_uint8_t>(), "");
169static_assert(IsSameAsSomeBuiltin<fbl::atomic_int16_t>(), "");
170static_assert(IsSameAsSomeBuiltin<fbl::atomic_uint16_t>(), "");
171static_assert(IsSameAsSomeBuiltin<fbl::atomic_int32_t>(), "");
172static_assert(IsSameAsSomeBuiltin<fbl::atomic_uint32_t>(), "");
173static_assert(IsSameAsSomeBuiltin<fbl::atomic_int64_t>(), "");
174static_assert(IsSameAsSomeBuiltin<fbl::atomic_uint64_t>(), "");
175
176static_assert(IsSameAsSomeBuiltin<fbl::atomic_int_least8_t>(), "");
177static_assert(IsSameAsSomeBuiltin<fbl::atomic_uint_least8_t>(), "");
178static_assert(IsSameAsSomeBuiltin<fbl::atomic_int_least16_t>(), "");
179static_assert(IsSameAsSomeBuiltin<fbl::atomic_uint_least16_t>(), "");
180static_assert(IsSameAsSomeBuiltin<fbl::atomic_int_least32_t>(), "");
181static_assert(IsSameAsSomeBuiltin<fbl::atomic_uint_least32_t>(), "");
182static_assert(IsSameAsSomeBuiltin<fbl::atomic_int_least64_t>(), "");
183static_assert(IsSameAsSomeBuiltin<fbl::atomic_uint_least64_t>(), "");
184static_assert(IsSameAsSomeBuiltin<fbl::atomic_int_fast8_t>(), "");
185static_assert(IsSameAsSomeBuiltin<fbl::atomic_uint_fast8_t>(), "");
186static_assert(IsSameAsSomeBuiltin<fbl::atomic_int_fast16_t>(), "");
187static_assert(IsSameAsSomeBuiltin<fbl::atomic_uint_fast16_t>(), "");
188static_assert(IsSameAsSomeBuiltin<fbl::atomic_int_fast32_t>(), "");
189static_assert(IsSameAsSomeBuiltin<fbl::atomic_uint_fast32_t>(), "");
190static_assert(IsSameAsSomeBuiltin<fbl::atomic_int_fast64_t>(), "");
191static_assert(IsSameAsSomeBuiltin<fbl::atomic_uint_fast64_t>(), "");
192
193// We should be able to instantiate fbl::atomics of enum type as well.
194
195enum unspecified_enum {
196    kUnspecifiedValue = 23,
197};
198__UNUSED fbl::atomic<unspecified_enum> atomic_unspecified_enum;
199
200enum specified_enum_char : char {
201    kSpecifiedValue_char = 23,
202};
203__UNUSED fbl::atomic<specified_enum_char> atomic_specified_enum_char;
204
205enum specified_enum_signed_char : signed char {
206    kSpecifiedValue_signed_char = 23,
207};
208__UNUSED fbl::atomic<specified_enum_signed_char> atomic_specified_enum_signed_char;
209
210enum specified_enum_unsigned_char : unsigned char {
211    kSpecifiedValue_unsigned_char = 23,
212};
213__UNUSED fbl::atomic<specified_enum_unsigned_char> atomic_specified_enum_unsigned_char;
214
215enum specified_enum_short : short {
216    kSpecifiedValue_short = 23,
217};
218__UNUSED fbl::atomic<specified_enum_short> atomic_specified_enum_short;
219
220enum specified_enum_unsigned_short : unsigned short {
221    kSpecifiedValue_unsigned_short = 23,
222};
223__UNUSED fbl::atomic<specified_enum_unsigned_short> atomic_specified_enum_unsigned_short;
224
225enum specified_enum_int : int {
226    kSpecifiedValue_int = 23,
227};
228__UNUSED fbl::atomic<specified_enum_int> atomic_specified_enum_int;
229
230enum specified_enum_unsigned_int : unsigned int {
231    kSpecifiedValue_unsigned_int = 23,
232};
233__UNUSED fbl::atomic<specified_enum_unsigned_int> atomic_specified_enum_unsigned_int;
234
235enum specified_enum_long : long {
236    kSpecifiedValue_long = 23,
237};
238__UNUSED fbl::atomic<specified_enum_long> atomic_specified_enum_long;
239
240enum specified_enum_unsigned_long : unsigned long{
241    kSpecifiedValue_unsigned_long = 23,
242};
243__UNUSED fbl::atomic<specified_enum_unsigned_long> atomic_specified_enum_unsigned_long;
244
245enum specified_enum_long_long : long long {
246    kSpecifiedValue_long_long = 23,
247};
248__UNUSED fbl::atomic<specified_enum_long_long> atomic_specified_enum_long_long;
249
250enum specified_enum_unsigned_long_long : unsigned long long {
251    kSpecifiedValue_unsigned_long_long = 23,
252};
253__UNUSED fbl::atomic<specified_enum_unsigned_long_long> atomic_specified_enum_unsigned_long_long;
254
255enum specified_enum_bool : bool {
256    kSpecifiedValue_bool = true,
257};
258__UNUSED fbl::atomic<specified_enum_bool> atomic_specified_enum_bool;
259
260enum struct unspecified_struct_enum {
261    kUnspecifiedValueStruct = 23,
262};
263__UNUSED fbl::atomic<unspecified_struct_enum> atomic_unspecified_struct_enum;
264
265enum struct specified_struct_enum_char : char {
266    kSpecifiedStructValue_char = 23,
267};
268__UNUSED fbl::atomic<specified_struct_enum_char> atomic_specified_struct_enum_char;
269
270enum struct specified_struct_enum_signed_char : signed char {
271    kSpecifiedStructValue_signed_char = 23,
272};
273__UNUSED fbl::atomic<specified_struct_enum_signed_char> atomic_specified_struct_enum_signed_char;
274
275enum struct specified_struct_enum_unsigned_char : unsigned char {
276    kSpecifiedStructValue_unsigned_char = 23,
277};
278__UNUSED fbl::atomic<specified_struct_enum_unsigned_char> atomic_specified_struct_enum_unsigned_char;
279
280enum struct specified_struct_enum_short : short {
281    kSpecifiedStructValue_short = 23,
282};
283__UNUSED fbl::atomic<specified_struct_enum_short> atomic_specified_struct_enum_short;
284
285enum struct specified_struct_enum_unsigned_short : unsigned short {
286    kSpecifiedStructValue_unsigned_short = 23,
287};
288__UNUSED fbl::atomic<specified_struct_enum_unsigned_short> atomic_specified_struct_enum_unsigned_short;
289
290enum struct specified_struct_enum_int : int {
291    kSpecifiedStructValue_int = 23,
292};
293__UNUSED fbl::atomic<specified_struct_enum_int> atomic_specified_struct_enum_int;
294
295enum struct specified_struct_enum_unsigned_int : unsigned int {
296    kSpecifiedStructValue_unsigned_int = 23,
297};
298__UNUSED fbl::atomic<specified_struct_enum_unsigned_int> atomic_specified_struct_enum_unsigned_int;
299
300enum struct specified_struct_enum_long : long {
301    kSpecifiedStructValue_long = 23,
302};
303__UNUSED fbl::atomic<specified_struct_enum_long> atomic_specified_struct_enum_long;
304
305enum struct specified_struct_enum_unsigned_long : unsigned long{
306    kSpecifiedStructValue_unsigned_long = 23,
307};
308__UNUSED fbl::atomic<specified_struct_enum_unsigned_long> atomic_specified_struct_enum_unsigned_long;
309
310enum struct specified_struct_enum_long_long : long long {
311    kSpecifiedStructValue_long_long = 23,
312};
313__UNUSED fbl::atomic<specified_struct_enum_long_long> atomic_specified_struct_enum_long_long;
314
315enum struct specified_struct_enum_unsigned_long_long : unsigned long long {
316    kSpecifiedStructValue_unsigned_long_long = 23,
317};
318__UNUSED fbl::atomic<specified_struct_enum_unsigned_long_long> atomic_specified_struct_enum_unsigned_long_long;
319
320enum struct specified_struct_enum_bool : bool {
321    kSpecifiedStructValue_bool = true,
322};
323__UNUSED fbl::atomic<specified_struct_enum_bool> atomic_specified_struct_enum_bool;
324
325bool atomic_wont_compile_test() {
326    BEGIN_TEST;
327
328    // fbl::atomic only supports integer, enum, and pointer types.
329
330#if TEST_WILL_NOT_COMPILE || 0
331    struct not_integral {};
332    fbl::atomic<not_integral> not_integral;
333#endif
334
335#if TEST_WILL_NOT_COMPILE || 0
336    fbl::atomic<float> not_integral;
337#endif
338
339#if TEST_WILL_NOT_COMPILE || 0
340    fbl::atomic<double> not_integral;
341#endif
342
343    END_TEST;
344}
345
346fbl::memory_order orders[] = {
347    fbl::memory_order_relaxed,
348    fbl::memory_order_acquire,
349    fbl::memory_order_release,
350    fbl::memory_order_acq_rel,
351    fbl::memory_order_seq_cst,
352};
353
354// Bunch of machinery for arithmetic tests.
355template <typename T>
356using ordinary_op = T (*)(T*, T);
357
358template <typename T>
359using atomic_op = T (*)(fbl::atomic<T>*, T, fbl::memory_order);
360
361template <typename T>
362using volatile_op = T (*)(volatile fbl::atomic<T>*, T, fbl::memory_order);
363
364template <typename T>
365struct TestCase {
366    ordinary_op<T> ordinary;
367    atomic_op<T> nonmember_atomic;
368    atomic_op<T> member_atomic;
369    volatile_op<T> nonmember_volatile;
370    volatile_op<T> member_volatile;
371};
372
373template <typename T>
374T test_values[] = {
375    0,
376    1,
377    23,
378    fbl::numeric_limits<T>::min() / 4,
379    fbl::numeric_limits<T>::max() / 4,
380};
381
382template <>
383bool test_values<bool>[] = {
384    false,
385    true,
386    true,
387    false,
388    true,
389};
390
391template <>
392void* test_values<void*>[] = {
393    &test_values<int>[0],
394    &test_values<int>[1],
395    &test_values<int>[2],
396    &test_values<int>[3],
397    &test_values<int>[4],
398};
399
400template <>
401const void* test_values<const void*>[] = {
402    &test_values<int>[0],
403    &test_values<int>[1],
404    &test_values<int>[2],
405    &test_values<int>[3],
406    &test_values<int>[4],
407};
408
409template <>
410volatile void* test_values<volatile void*>[] = {
411    &test_values<int>[0],
412    &test_values<int>[1],
413    &test_values<int>[2],
414    &test_values<int>[3],
415    &test_values<int>[4],
416};
417
418template <>
419const volatile void* test_values<const volatile void*>[] = {
420    &test_values<int>[0],
421    &test_values<int>[1],
422    &test_values<int>[2],
423    &test_values<int>[3],
424    &test_values<int>[4],
425};
426
427template <>
428int* test_values<int*>[] = {
429    &test_values<int>[0],
430    &test_values<int>[1],
431    &test_values<int>[2],
432    &test_values<int>[3],
433    &test_values<int>[4],
434};
435
436template <>
437const int* test_values<const int*>[] = {
438    &test_values<int>[0],
439    &test_values<int>[1],
440    &test_values<int>[2],
441    &test_values<int>[3],
442    &test_values<int>[4],
443};
444
445template <>
446volatile int* test_values<volatile int*>[] = {
447    &test_values<int>[0],
448    &test_values<int>[1],
449    &test_values<int>[2],
450    &test_values<int>[3],
451    &test_values<int>[4],
452};
453
454template <>
455const volatile int* test_values<const volatile int*>[] = {
456    &test_values<int>[0],
457    &test_values<int>[1],
458    &test_values<int>[2],
459    &test_values<int>[3],
460    &test_values<int>[4],
461};
462
463S test_values_of_S[] = { {}, {}, {}, {} };
464
465template <>
466S* test_values<S*>[] = {
467    &test_values_of_S[0],
468    &test_values_of_S[1],
469    &test_values_of_S[2],
470    &test_values_of_S[3],
471    nullptr,
472};
473
474template <>
475const S* test_values<const S*>[] = {
476    &test_values_of_S[0],
477    &test_values_of_S[1],
478    &test_values_of_S[2],
479    &test_values_of_S[3],
480    nullptr,
481};
482
483template <>
484volatile S* test_values<volatile S*>[] = {
485    &test_values_of_S[0],
486    &test_values_of_S[1],
487    &test_values_of_S[2],
488    &test_values_of_S[3],
489    nullptr,
490};
491
492template <>
493const volatile S* test_values<const volatile S*>[] = {
494    &test_values_of_S[0],
495    &test_values_of_S[1],
496    &test_values_of_S[2],
497    &test_values_of_S[3],
498    nullptr,
499};
500
501void nothing_0() {}
502void nothing_1() {}
503void nothing_2() {}
504void nothing_3() {}
505
506template <>
507function_pointer test_values<function_pointer>[] = {
508    &nothing_0,
509    &nothing_1,
510    &nothing_2,
511    &nothing_3,
512    nullptr,
513};
514
515template <typename T>
516TestCase<T> test_cases[] = {
517    {
518        [](T* ptr_to_a, T b) -> T {
519            T a = *ptr_to_a;
520            *ptr_to_a = static_cast<T>(a + b);
521            return a;
522        },
523        fbl::atomic_fetch_add<T>,
524        [](fbl::atomic<T>* ptr_to_atomic_a, T b, fbl::memory_order order) -> T {
525            return ptr_to_atomic_a->fetch_add(b, order);
526        },
527        fbl::atomic_fetch_add<T>,
528        [](volatile fbl::atomic<T>* ptr_to_atomic_a, T b, fbl::memory_order order) -> T {
529            return ptr_to_atomic_a->fetch_add(b, order);
530        },
531    },
532    {
533        [](T* ptr_to_a, T b) -> T {
534            T a = *ptr_to_a;
535            *ptr_to_a = static_cast<T>(a & b);
536            return a;
537        },
538        fbl::atomic_fetch_and<T>,
539        [](fbl::atomic<T>* ptr_to_atomic_a, T b, fbl::memory_order order) -> T {
540            return ptr_to_atomic_a->fetch_and(b, order);
541        },
542        fbl::atomic_fetch_and<T>,
543        [](volatile fbl::atomic<T>* ptr_to_atomic_a, T b, fbl::memory_order order) -> T {
544            return ptr_to_atomic_a->fetch_and(b, order);
545        },
546    },
547    {
548        [](T* ptr_to_a, T b) -> T {
549            T a = *ptr_to_a;
550            *ptr_to_a = static_cast<T>(a | b);
551            return a;
552        },
553        fbl::atomic_fetch_or<T>,
554        [](fbl::atomic<T>* ptr_to_atomic_a, T b, fbl::memory_order order) -> T {
555            return ptr_to_atomic_a->fetch_or(b, order);
556        },
557        fbl::atomic_fetch_or<T>,
558        [](volatile fbl::atomic<T>* ptr_to_atomic_a, T b, fbl::memory_order order) -> T {
559            return ptr_to_atomic_a->fetch_or(b, order);
560        },
561    },
562    {
563        [](T* ptr_to_a, T b) -> T {
564            T a = *ptr_to_a;
565            *ptr_to_a = static_cast<T>(a ^ b);
566            return a;
567        },
568        fbl::atomic_fetch_xor<T>,
569        [](fbl::atomic<T>* ptr_to_atomic_a, T b, fbl::memory_order order) -> T {
570            return ptr_to_atomic_a->fetch_xor(b, order);
571        },
572        fbl::atomic_fetch_xor<T>,
573        [](volatile fbl::atomic<T>* ptr_to_atomic_a, T b, fbl::memory_order order) -> T {
574            return ptr_to_atomic_a->fetch_xor(b, order);
575        },
576    },
577};
578
579template <typename T>
580TestCase<T> subtraction_test_case = {
581    [](T* ptr_to_a, T b) -> T {
582        T a = *ptr_to_a;
583        *ptr_to_a = static_cast<T>(a - b);
584        return a;
585    },
586    fbl::atomic_fetch_sub,
587    [](fbl::atomic<T>* ptr_to_atomic_a, T b, fbl::memory_order order) -> T {
588        return ptr_to_atomic_a->fetch_sub(b, order);
589    },
590    fbl::atomic_fetch_sub,
591    [](volatile fbl::atomic<T>* ptr_to_atomic_a, T b, fbl::memory_order order) -> T {
592        return ptr_to_atomic_a->fetch_sub(b, order);
593    },
594};
595
596template <typename T>
597bool math_test() {
598    for (const T original_left : test_values<T>) {
599        for (T right : test_values<T>) {
600            for (const auto& order : orders) {
601                for (auto test_case : test_cases<T>) {
602                    {
603                        fbl::atomic<T> atomic_left(original_left);
604                        T left = original_left;
605                        ASSERT_EQ(test_case.ordinary(&left, right),
606                                  test_case.member_atomic(&atomic_left, right, order),
607                                  "Atomic and ordinary math differ");
608                        ASSERT_EQ(left, atomic_load(&atomic_left), "Atomic and ordinary math differ");
609                    }
610                    {
611                        fbl::atomic<T> atomic_left(original_left);
612                        T left = original_left;
613                        ASSERT_EQ(test_case.ordinary(&left, right),
614                                  test_case.nonmember_atomic(&atomic_left, right, order),
615                                  "Atomic and ordinary math differ");
616                        ASSERT_EQ(left, atomic_load(&atomic_left), "Atomic and ordinary math differ");
617                    }
618                    {
619                        volatile fbl::atomic<T> atomic_left(original_left);
620                        T left = original_left;
621                        ASSERT_EQ(test_case.ordinary(&left, right),
622                                  test_case.member_volatile(&atomic_left, right, order),
623                                  "Atomic and ordinary math differ");
624                        ASSERT_EQ(left, atomic_load(&atomic_left), "Atomic and ordinary math differ");
625                    }
626                    {
627                        volatile fbl::atomic<T> atomic_left(original_left);
628                        T left = original_left;
629                        ASSERT_EQ(test_case.ordinary(&left, right),
630                                  test_case.nonmember_volatile(&atomic_left, right, order),
631                                  "Atomic and ordinary math differ");
632                        ASSERT_EQ(left, atomic_load(&atomic_left), "Atomic and ordinary math differ");
633                    }
634                }
635                // Let's not worry about signed subtraction UB.
636                if (fbl::is_unsigned<T>::value) {
637                    {
638                        fbl::atomic<T> atomic_left(original_left);
639                        T left = original_left;
640                        ASSERT_EQ(subtraction_test_case<T>.ordinary(&left, right),
641                                  subtraction_test_case<T>.member_atomic(&atomic_left, right, order),
642                                  "Atomic and ordinary math differ");
643                        ASSERT_EQ(left, atomic_load(&atomic_left), "Atomic and ordinary math differ");
644                    }
645                    {
646                        fbl::atomic<T> atomic_left(original_left);
647                        T left = original_left;
648                        ASSERT_EQ(subtraction_test_case<T>.ordinary(&left, right),
649                                  subtraction_test_case<T>.nonmember_atomic(&atomic_left, right, order),
650                                  "Atomic and ordinary math differ");
651                        ASSERT_EQ(left, atomic_load(&atomic_left), "Atomic and ordinary math differ");
652                    }
653                    {
654                        volatile fbl::atomic<T> atomic_left(original_left);
655                        T left = original_left;
656                        ASSERT_EQ(subtraction_test_case<T>.ordinary(&left, right),
657                                  subtraction_test_case<T>.member_volatile(&atomic_left, right, order),
658                                  "Atomic and ordinary math differ");
659                        ASSERT_EQ(left, atomic_load(&atomic_left), "Atomic and ordinary math differ");
660                    }
661                    {
662                        volatile fbl::atomic<T> atomic_left(original_left);
663                        T left = original_left;
664                        ASSERT_EQ(subtraction_test_case<T>.ordinary(&left, right),
665                                  subtraction_test_case<T>.nonmember_volatile(&atomic_left, right, order),
666                                  "Atomic and ordinary math differ");
667                        ASSERT_EQ(left, atomic_load(&atomic_left), "Atomic and ordinary math differ");
668                    }
669                }
670            }
671        }
672    }
673
674    return true;
675}
676
677template <typename T>
678using ordinary_pointer_op = T (*)(T*, ptrdiff_t);
679
680template <typename T>
681using atomic_pointer_op = T (*)(fbl::atomic<T>*, ptrdiff_t, fbl::memory_order);
682
683template <typename T>
684using volatile_pointer_op = T (*)(volatile fbl::atomic<T>*, ptrdiff_t, fbl::memory_order);
685
686template <typename T>
687struct PointerTestCase {
688    ordinary_pointer_op<T> ordinary;
689    atomic_pointer_op<T> nonmember_atomic;
690    atomic_pointer_op<T> member_atomic;
691    volatile_pointer_op<T> nonmember_volatile;
692    volatile_pointer_op<T> member_volatile;
693};
694
695template <typename T>
696PointerTestCase<T> pointer_add_test_case = {
697    [](T* ptr_to_a, ptrdiff_t d) -> T {
698        T a = *ptr_to_a;
699        *ptr_to_a = a + d;
700        return a;
701    },
702    [](fbl::atomic<T>* ptr_to_atomic_a, ptrdiff_t d, fbl::memory_order order) -> T {
703        return fbl::atomic_fetch_add(ptr_to_atomic_a, d, order);
704    },
705    [](fbl::atomic<T>* ptr_to_atomic_a, ptrdiff_t d, fbl::memory_order order) -> T {
706        return ptr_to_atomic_a->fetch_add(d, order);
707    },
708    [](volatile fbl::atomic<T>* ptr_to_atomic_a, ptrdiff_t d, fbl::memory_order order) -> T {
709        return fbl::atomic_fetch_add(ptr_to_atomic_a, d, order);
710    },
711    [](volatile fbl::atomic<T>* ptr_to_atomic_a, ptrdiff_t d, fbl::memory_order order) -> T {
712        return ptr_to_atomic_a->fetch_add(d, order);
713    },
714};
715
716template <typename T>
717PointerTestCase<T> pointer_sub_test_case = {
718    [](T* ptr_to_a, ptrdiff_t d) -> T {
719        T a = *ptr_to_a;
720        *ptr_to_a = a - d;
721        return a;
722    },
723    [](fbl::atomic<T>* ptr_to_atomic_a, ptrdiff_t d, fbl::memory_order order) -> T {
724        return fbl::atomic_fetch_sub(ptr_to_atomic_a, d, order);
725    },
726    [](fbl::atomic<T>* ptr_to_atomic_a, ptrdiff_t d, fbl::memory_order order) -> T {
727        return ptr_to_atomic_a->fetch_sub(d, order);
728    },
729    [](volatile fbl::atomic<T>* ptr_to_atomic_a, ptrdiff_t d, fbl::memory_order order) -> T {
730        return fbl::atomic_fetch_sub(ptr_to_atomic_a, d, order);
731    },
732    [](volatile fbl::atomic<T>* ptr_to_atomic_a, ptrdiff_t d, fbl::memory_order order) -> T {
733        return ptr_to_atomic_a->fetch_sub(d, order);
734    },
735};
736
737template <typename T>
738bool pointer_add_test() {
739    static_assert(fbl::is_pointer<T>::value, "");
740    ptrdiff_t right = 2;
741    const auto& test_case = pointer_add_test_case<T>;
742    for (const T original_left : test_values<T>) {
743        for (const auto& order : orders) {
744            {
745                fbl::atomic<T> atomic_left(original_left);
746                T left = original_left;
747                ASSERT_EQ(test_case.ordinary(&left, right),
748                          test_case.member_atomic(&atomic_left, right, order),
749                          "Atomic and ordinary math differ");
750                ASSERT_EQ(left, atomic_load(&atomic_left), "Atomic and ordinary math differ");
751            }
752            {
753                fbl::atomic<T> atomic_left(original_left);
754                T left = original_left;
755                ASSERT_EQ(test_case.ordinary(&left, right),
756                          test_case.nonmember_atomic(&atomic_left, right, order),
757                          "Atomic and ordinary math differ");
758                ASSERT_EQ(left, atomic_load(&atomic_left), "Atomic and ordinary math differ");
759            }
760            {
761                volatile fbl::atomic<T> atomic_left(original_left);
762                T left = original_left;
763                ASSERT_EQ(test_case.ordinary(&left, right),
764                          test_case.member_volatile(&atomic_left, right, order),
765                          "Atomic and ordinary math differ");
766                ASSERT_EQ(left, atomic_load(&atomic_left), "Atomic and ordinary math differ");
767            }
768            {
769                volatile fbl::atomic<T> atomic_left(original_left);
770                T left = original_left;
771                ASSERT_EQ(test_case.ordinary(&left, right),
772                          test_case.nonmember_volatile(&atomic_left, right, order),
773                          "Atomic and ordinary math differ");
774                ASSERT_EQ(left, atomic_load(&atomic_left), "Atomic and ordinary math differ");
775            }
776        }
777
778        right -= 1;
779    }
780
781    return true;
782}
783
784template <typename T>
785bool pointer_sub_test() {
786    static_assert(fbl::is_pointer<T>::value, "");
787    ptrdiff_t right = -2;
788    const auto& test_case = pointer_sub_test_case<T>;
789    for (const T original_left : test_values<T>) {
790        for (const auto& order : orders) {
791            {
792                fbl::atomic<T> atomic_left(original_left);
793                T left = original_left;
794                ASSERT_EQ(test_case.ordinary(&left, right),
795                          test_case.member_atomic(&atomic_left, right, order),
796                          "Atomic and ordinary math differ");
797                ASSERT_EQ(left, atomic_load(&atomic_left), "Atomic and ordinary math differ");
798            }
799            {
800                fbl::atomic<T> atomic_left(original_left);
801                T left = original_left;
802                ASSERT_EQ(test_case.ordinary(&left, right),
803                          test_case.nonmember_atomic(&atomic_left, right, order),
804                          "Atomic and ordinary math differ");
805                ASSERT_EQ(left, atomic_load(&atomic_left), "Atomic and ordinary math differ");
806            }
807            {
808                volatile fbl::atomic<T> atomic_left(original_left);
809                T left = original_left;
810                ASSERT_EQ(test_case.ordinary(&left, right),
811                          test_case.member_volatile(&atomic_left, right, order),
812                          "Atomic and ordinary math differ");
813                ASSERT_EQ(left, atomic_load(&atomic_left), "Atomic and ordinary math differ");
814            }
815            {
816                volatile fbl::atomic<T> atomic_left(original_left);
817                T left = original_left;
818                ASSERT_EQ(test_case.ordinary(&left, right),
819                          test_case.nonmember_volatile(&atomic_left, right, order),
820                          "Atomic and ordinary math differ");
821                ASSERT_EQ(left, atomic_load(&atomic_left), "Atomic and ordinary math differ");
822            }
823        }
824
825        right += 1;
826    }
827
828    return true;
829}
830
831template <typename T>
832bool load_store_test() {
833    fbl::atomic<T> atomic_value;
834
835    for (T value : test_values<T>) {
836        atomic_value.store(value);
837        ASSERT_EQ(atomic_value.load(), value, "Member load/store busted");
838    }
839
840    for (T value : test_values<T>) {
841        fbl::atomic_store(&atomic_value, value);
842        ASSERT_EQ(atomic_load(&atomic_value), value, "Nonmember load/store busted");
843    }
844
845    volatile fbl::atomic<T> volatile_value;
846
847    for (T value : test_values<T>) {
848        volatile_value.store(value);
849        ASSERT_EQ(volatile_value.load(), value, "Member load/store busted");
850    }
851
852    for (T value : test_values<T>) {
853        fbl::atomic_store(&volatile_value, value);
854        ASSERT_EQ(atomic_load(&volatile_value), value, "Nonmember load/store busted");
855    }
856
857    return true;
858}
859
860template <typename T>
861bool exchange_test() {
862    T last_value = test_values<T>[0];
863    fbl::atomic<T> atomic_value(last_value);
864
865    for (T value : test_values<T>) {
866        ASSERT_EQ(atomic_value.load(), last_value, "Member exchange busted");
867        ASSERT_EQ(atomic_value.exchange(value), last_value, "Member exchange busted");
868        last_value = value;
869    }
870
871    last_value = test_values<T>[0];
872    atomic_value.store(last_value);
873
874    for (T value : test_values<T>) {
875        ASSERT_EQ(fbl::atomic_load(&atomic_value), last_value, "Nonmember exchange busted");
876        ASSERT_EQ(fbl::atomic_exchange(&atomic_value, value), last_value, "Nonmember exchange busted");
877        last_value = value;
878    }
879
880    last_value = test_values<T>[0];
881    volatile fbl::atomic<T> volatile_value(last_value);
882
883    for (T value : test_values<T>) {
884        ASSERT_EQ(volatile_value.load(), last_value, "Member exchange busted");
885        ASSERT_EQ(volatile_value.exchange(value), last_value, "Member exchange busted");
886        last_value = value;
887    }
888
889    last_value = test_values<T>[0];
890    volatile_value.store(last_value);
891
892    for (T value : test_values<T>) {
893        ASSERT_EQ(fbl::atomic_load(&volatile_value), last_value, "Nonmember exchange busted");
894        ASSERT_EQ(fbl::atomic_exchange(&volatile_value, value), last_value, "Nonmember exchange busted");
895        last_value = value;
896    }
897
898    return true;
899}
900
901template <typename T>
902struct cas_function {
903    bool (*function)(fbl::atomic<T>* atomic_ptr, T* expected, T desired,
904                     fbl::memory_order success_order, fbl::memory_order failure_order);
905    bool can_spuriously_fail;
906};
907
908template <typename T>
909cas_function<T> cas_functions[] = {
910    {fbl::atomic_compare_exchange_weak, true},
911    {fbl::atomic_compare_exchange_strong, false},
912    {[](fbl::atomic<T>* atomic_ptr, T* expected, T desired,
913        fbl::memory_order success_order, fbl::memory_order failure_order) {
914         return atomic_ptr->compare_exchange_weak(expected, desired, success_order, failure_order);
915     },
916     true},
917    {[](fbl::atomic<T>* atomic_ptr, T* expected, T desired,
918        fbl::memory_order success_order, fbl::memory_order failure_order) {
919         return atomic_ptr->compare_exchange_strong(expected, desired, success_order, failure_order);
920     },
921     false},
922};
923
924template <typename T>
925struct volatile_cas_function {
926    bool (*function)(volatile fbl::atomic<T>* atomic_ptr, T* expected, T desired,
927                     fbl::memory_order success_order, fbl::memory_order failure_order);
928    bool can_spuriously_fail;
929};
930
931template <typename T>
932volatile_cas_function<T> volatile_cas_functions[] = {
933    {fbl::atomic_compare_exchange_weak, true},
934    {fbl::atomic_compare_exchange_strong, false},
935    {[](volatile fbl::atomic<T>* atomic_ptr, T* expected, T desired,
936        fbl::memory_order success_order, fbl::memory_order failure_order) {
937         return atomic_ptr->compare_exchange_weak(expected, desired, success_order, failure_order);
938     },
939     true},
940    {[](volatile fbl::atomic<T>* atomic_ptr, T* expected, T desired,
941        fbl::memory_order success_order, fbl::memory_order failure_order) {
942         return atomic_ptr->compare_exchange_strong(expected, desired, success_order, failure_order);
943     },
944     false}};
945
946enum cas_slots {
947    kExpected = 0,
948    kActual = 1,
949    kDesired = 2,
950};
951
952template <typename T>
953T cas_test_values[] = {
954    22,
955    23,
956    24,
957};
958
959template <>
960bool cas_test_values<bool>[] = {
961    false,
962    true,
963    false,
964};
965
966template <>
967void* cas_test_values<void*>[] = {
968    &cas_test_values<int>[0],
969    &cas_test_values<int>[1],
970    &cas_test_values<int>[2],
971};
972
973template <>
974const void* cas_test_values<const void*>[] = {
975    &cas_test_values<int>[0],
976    &cas_test_values<int>[1],
977    &cas_test_values<int>[2],
978};
979
980template <>
981volatile void* cas_test_values<volatile void*>[] = {
982    &cas_test_values<int>[0],
983    &cas_test_values<int>[1],
984    &cas_test_values<int>[2],
985};
986
987template <>
988const volatile void* cas_test_values<const volatile void*>[] = {
989    &cas_test_values<int>[0],
990    &cas_test_values<int>[1],
991    &cas_test_values<int>[2],
992};
993
994template <>
995int* cas_test_values<int*>[] = {
996    &cas_test_values<int>[0],
997    &cas_test_values<int>[1],
998    &cas_test_values<int>[2],
999};
1000
1001template <>
1002const int* cas_test_values<const int*>[] = {
1003    &cas_test_values<int>[0],
1004    &cas_test_values<int>[1],
1005    &cas_test_values<int>[2],
1006};
1007
1008template <>
1009volatile int* cas_test_values<volatile int*>[] = {
1010    &cas_test_values<int>[0],
1011    &cas_test_values<int>[1],
1012    &cas_test_values<int>[2],
1013};
1014
1015template <>
1016const volatile int* cas_test_values<const volatile int*>[] = {
1017    &cas_test_values<int>[0],
1018    &cas_test_values<int>[1],
1019    &cas_test_values<int>[2],
1020};
1021
1022S cas_test_values_of_S[] = { {}, {} };
1023
1024template <>
1025S* cas_test_values<S*>[] = {
1026    &cas_test_values_of_S[0],
1027    &cas_test_values_of_S[1],
1028    nullptr,
1029};
1030
1031template <>
1032const S* cas_test_values<const S*>[] = {
1033    &cas_test_values_of_S[0],
1034    &cas_test_values_of_S[1],
1035    nullptr,
1036};
1037
1038template <>
1039volatile S* cas_test_values<volatile S*>[] = {
1040    &cas_test_values_of_S[0],
1041    &cas_test_values_of_S[1],
1042    nullptr,
1043};
1044
1045template <>
1046const volatile S* cas_test_values<const volatile S*>[] = {
1047    &cas_test_values_of_S[0],
1048    &cas_test_values_of_S[1],
1049    nullptr,
1050};
1051
1052template <>
1053function_pointer cas_test_values<function_pointer>[] = {
1054    &nothing_0,
1055    &nothing_1,
1056    nullptr,
1057};
1058
1059template <typename T>
1060bool compare_exchange_test() {
1061    for (auto cas : cas_functions<T>) {
1062        for (const auto& success_order : orders) {
1063            for (const auto& failure_order : orders) {
1064                {
1065                    // Failure case
1066                    T actual = cas_test_values<T>[kActual];
1067                    fbl::atomic<T> atomic_value(actual);
1068                    T expected = cas_test_values<T>[kExpected];
1069                    T desired = cas_test_values<T>[kDesired];
1070                    EXPECT_FALSE(cas.function(&atomic_value, &expected, desired,
1071                                              success_order, failure_order),
1072                                 "compare-exchange shouldn't have succeeded!");
1073                    EXPECT_EQ(expected, actual, "compare-exchange didn't report actual value!");
1074                }
1075                {
1076                    // Success case
1077                    T actual = cas_test_values<T>[kActual];
1078                    fbl::atomic<T> atomic_value(actual);
1079                    T expected = actual;
1080                    T desired = cas_test_values<T>[kDesired];
1081                    // Some compare-and-swap functions can spuriously fail.
1082                    bool succeeded = cas.function(&atomic_value, &expected, desired,
1083                                                  success_order, failure_order);
1084                    if (!cas.can_spuriously_fail) {
1085                        EXPECT_TRUE(succeeded, "compare-exchange should've succeeded!");
1086                    }
1087                    EXPECT_EQ(expected, actual, "compare-exchange didn't report actual value!");
1088                }
1089            }
1090        }
1091    }
1092
1093    for (auto cas : volatile_cas_functions<T>) {
1094        for (const auto& success_order : orders) {
1095            for (const auto& failure_order : orders) {
1096                {
1097                    // Failure case
1098                    T actual = cas_test_values<T>[kActual];
1099                    fbl::atomic<T> atomic_value(actual);
1100                    T expected = cas_test_values<T>[kExpected];
1101                    T desired = cas_test_values<T>[kDesired];
1102                    EXPECT_FALSE(cas.function(&atomic_value, &expected, desired,
1103                                              success_order, failure_order),
1104                                 "compare-exchange shouldn't have succeeded!");
1105                    EXPECT_EQ(expected, actual, "compare-exchange didn't report actual value!");
1106                }
1107                {
1108                    // Success case
1109                    T actual = cas_test_values<T>[kActual];
1110                    fbl::atomic<T> atomic_value(actual);
1111                    T expected = actual;
1112                    T desired = cas_test_values<T>[kDesired];
1113                    // Compare-and-swap can spuriously fail.
1114                    // Some compare-and-swap functions can spuriously fail.
1115                    bool succeeded = cas.function(&atomic_value, &expected, desired,
1116                                                  success_order, failure_order);
1117                    if (!cas.can_spuriously_fail) {
1118                        EXPECT_TRUE(succeeded, "compare-exchange should've succeeded!");
1119                    }
1120                    EXPECT_EQ(expected, actual, "compare-exchange didn't report actual value!");
1121                }
1122            }
1123        }
1124    }
1125
1126    return true;
1127}
1128
1129// Actual test cases on operations for each builtin type.
1130bool atomic_math_test() {
1131    BEGIN_TEST;
1132
1133    ASSERT_TRUE(math_test<char>());
1134    ASSERT_TRUE(math_test<signed char>());
1135    ASSERT_TRUE(math_test<unsigned char>());
1136    ASSERT_TRUE(math_test<short>());
1137    ASSERT_TRUE(math_test<unsigned short>());
1138    ASSERT_TRUE(math_test<int>());
1139    ASSERT_TRUE(math_test<unsigned int>());
1140    ASSERT_TRUE(math_test<long>());
1141    ASSERT_TRUE(math_test<unsigned long>());
1142    ASSERT_TRUE(math_test<long long>());
1143    ASSERT_TRUE(math_test<unsigned long long>());
1144
1145    END_TEST;
1146}
1147
1148bool atomic_pointer_math_test() {
1149    BEGIN_TEST;
1150
1151    ASSERT_TRUE(pointer_add_test<int*>());
1152    ASSERT_TRUE(pointer_add_test<const int*>());
1153    ASSERT_TRUE(pointer_add_test<volatile int*>());
1154    ASSERT_TRUE(pointer_add_test<const volatile int*>());
1155    ASSERT_TRUE(pointer_add_test<S*>());
1156    ASSERT_TRUE(pointer_add_test<const S*>());
1157    ASSERT_TRUE(pointer_add_test<volatile S*>());
1158    ASSERT_TRUE(pointer_add_test<const volatile S*>());
1159
1160    ASSERT_TRUE(pointer_sub_test<int*>());
1161    ASSERT_TRUE(pointer_sub_test<const int*>());
1162    ASSERT_TRUE(pointer_sub_test<volatile int*>());
1163    ASSERT_TRUE(pointer_sub_test<const volatile int*>());
1164    ASSERT_TRUE(pointer_sub_test<S*>());
1165    ASSERT_TRUE(pointer_sub_test<const S*>());
1166    ASSERT_TRUE(pointer_sub_test<volatile S*>());
1167    ASSERT_TRUE(pointer_sub_test<const volatile S*>());
1168
1169    // Note that there is no void pointer or function pointer math,
1170    // and so no tests of them.
1171
1172    END_TEST;
1173}
1174
1175bool atomic_load_store_test() {
1176    BEGIN_TEST;
1177
1178    ASSERT_TRUE(load_store_test<char>());
1179    ASSERT_TRUE(load_store_test<signed char>());
1180    ASSERT_TRUE(load_store_test<unsigned char>());
1181    ASSERT_TRUE(load_store_test<short>());
1182    ASSERT_TRUE(load_store_test<unsigned short>());
1183    ASSERT_TRUE(load_store_test<int>());
1184    ASSERT_TRUE(load_store_test<unsigned int>());
1185    ASSERT_TRUE(load_store_test<long>());
1186    ASSERT_TRUE(load_store_test<unsigned long>());
1187    ASSERT_TRUE(load_store_test<long long>());
1188    ASSERT_TRUE(load_store_test<unsigned long long>());
1189    ASSERT_TRUE(load_store_test<bool>());
1190
1191    ASSERT_TRUE(load_store_test<void*>());
1192    ASSERT_TRUE(load_store_test<const void*>());
1193    ASSERT_TRUE(load_store_test<volatile void*>());
1194    ASSERT_TRUE(load_store_test<const volatile void*>());
1195    ASSERT_TRUE(load_store_test<int*>());
1196    ASSERT_TRUE(load_store_test<const int*>());
1197    ASSERT_TRUE(load_store_test<volatile int*>());
1198    ASSERT_TRUE(load_store_test<const volatile int*>());
1199    ASSERT_TRUE(load_store_test<function_pointer>());
1200
1201    END_TEST;
1202}
1203
1204bool atomic_exchange_test() {
1205    BEGIN_TEST;
1206
1207    ASSERT_TRUE(exchange_test<char>());
1208    ASSERT_TRUE(exchange_test<signed char>());
1209    ASSERT_TRUE(exchange_test<unsigned char>());
1210    ASSERT_TRUE(exchange_test<short>());
1211    ASSERT_TRUE(exchange_test<unsigned short>());
1212    ASSERT_TRUE(exchange_test<int>());
1213    ASSERT_TRUE(exchange_test<unsigned int>());
1214    ASSERT_TRUE(exchange_test<long>());
1215    ASSERT_TRUE(exchange_test<unsigned long>());
1216    ASSERT_TRUE(exchange_test<long long>());
1217    ASSERT_TRUE(exchange_test<unsigned long long>());
1218    ASSERT_TRUE(exchange_test<bool>());
1219
1220    ASSERT_TRUE(exchange_test<void*>());
1221    ASSERT_TRUE(exchange_test<const void*>());
1222    ASSERT_TRUE(exchange_test<volatile void*>());
1223    ASSERT_TRUE(exchange_test<const volatile void*>());
1224    ASSERT_TRUE(exchange_test<int*>());
1225    ASSERT_TRUE(exchange_test<const int*>());
1226    ASSERT_TRUE(exchange_test<volatile int*>());
1227    ASSERT_TRUE(exchange_test<const volatile int*>());
1228    ASSERT_TRUE(exchange_test<S*>());
1229    ASSERT_TRUE(exchange_test<const S*>());
1230    ASSERT_TRUE(exchange_test<volatile S*>());
1231    ASSERT_TRUE(exchange_test<const volatile S*>());
1232    ASSERT_TRUE(exchange_test<function_pointer>());
1233
1234    END_TEST;
1235}
1236
1237bool atomic_compare_exchange_test() {
1238    BEGIN_TEST;
1239
1240    ASSERT_TRUE(compare_exchange_test<char>());
1241    ASSERT_TRUE(compare_exchange_test<signed char>());
1242    ASSERT_TRUE(compare_exchange_test<unsigned char>());
1243    ASSERT_TRUE(compare_exchange_test<short>());
1244    ASSERT_TRUE(compare_exchange_test<unsigned short>());
1245    ASSERT_TRUE(compare_exchange_test<int>());
1246    ASSERT_TRUE(compare_exchange_test<unsigned int>());
1247    ASSERT_TRUE(compare_exchange_test<long>());
1248    ASSERT_TRUE(compare_exchange_test<unsigned long>());
1249    ASSERT_TRUE(compare_exchange_test<long long>());
1250    ASSERT_TRUE(compare_exchange_test<unsigned long long>());
1251    ASSERT_TRUE(compare_exchange_test<bool>());
1252
1253    ASSERT_TRUE(compare_exchange_test<void*>());
1254    ASSERT_TRUE(compare_exchange_test<const void*>());
1255    ASSERT_TRUE(compare_exchange_test<volatile void*>());
1256    ASSERT_TRUE(compare_exchange_test<const volatile void*>());
1257    ASSERT_TRUE(compare_exchange_test<int*>());
1258    ASSERT_TRUE(compare_exchange_test<const int*>());
1259    ASSERT_TRUE(compare_exchange_test<volatile int*>());
1260    ASSERT_TRUE(compare_exchange_test<const volatile int*>());
1261    ASSERT_TRUE(compare_exchange_test<S*>());
1262    ASSERT_TRUE(compare_exchange_test<const S*>());
1263    ASSERT_TRUE(compare_exchange_test<volatile S*>());
1264    ASSERT_TRUE(compare_exchange_test<const volatile S*>());
1265    ASSERT_TRUE(compare_exchange_test<function_pointer>());
1266
1267    END_TEST;
1268}
1269
1270// Code wants to rely on the ABI of fbl::atomic types. This means
1271// matching the underlying types' size and alignment, and the class
1272// being standard layout.
1273
1274static_assert(sizeof(fbl::atomic<char>) == sizeof(char), "");
1275static_assert(sizeof(fbl::atomic<signed char>) == sizeof(signed char), "");
1276static_assert(sizeof(fbl::atomic<unsigned char>) == sizeof(unsigned char), "");
1277static_assert(sizeof(fbl::atomic<short>) == sizeof(short), "");
1278static_assert(sizeof(fbl::atomic<unsigned short>) == sizeof(unsigned short), "");
1279static_assert(sizeof(fbl::atomic<int>) == sizeof(int), "");
1280static_assert(sizeof(fbl::atomic<unsigned int>) == sizeof(unsigned int), "");
1281static_assert(sizeof(fbl::atomic<long>) == sizeof(long), "");
1282static_assert(sizeof(fbl::atomic<unsigned long>) == sizeof(unsigned long), "");
1283static_assert(sizeof(fbl::atomic<long long>) == sizeof(long long), "");
1284static_assert(sizeof(fbl::atomic<unsigned long long>) == sizeof(unsigned long long), "");
1285static_assert(sizeof(fbl::atomic<bool>) == sizeof(bool), "");
1286static_assert(sizeof(fbl::atomic<void*>) == sizeof(void*), "");
1287static_assert(sizeof(fbl::atomic<const void*>) == sizeof(const void*), "");
1288static_assert(sizeof(fbl::atomic<volatile void*>) == sizeof(volatile void*), "");
1289static_assert(sizeof(fbl::atomic<const volatile void*>) == sizeof(const volatile void*), "");
1290static_assert(sizeof(fbl::atomic<int*>) == sizeof(int*), "");
1291static_assert(sizeof(fbl::atomic<const int*>) == sizeof(const int*), "");
1292static_assert(sizeof(fbl::atomic<volatile int*>) == sizeof(volatile int*), "");
1293static_assert(sizeof(fbl::atomic<const volatile int*>) == sizeof(const volatile int*), "");
1294static_assert(sizeof(fbl::atomic<S*>) == sizeof(S*), "");
1295static_assert(sizeof(fbl::atomic<const S*>) == sizeof(const S*), "");
1296static_assert(sizeof(fbl::atomic<volatile S*>) == sizeof(volatile S*), "");
1297static_assert(sizeof(fbl::atomic<const volatile S*>) == sizeof(const volatile S*), "");
1298static_assert(sizeof(fbl::atomic<function_pointer>) == sizeof(function_pointer), "");
1299
1300static_assert(alignof(fbl::atomic<char>) == alignof(char), "");
1301static_assert(alignof(fbl::atomic<signed char>) == alignof(signed char), "");
1302static_assert(alignof(fbl::atomic<unsigned char>) == alignof(unsigned char), "");
1303static_assert(alignof(fbl::atomic<short>) == alignof(short), "");
1304static_assert(alignof(fbl::atomic<unsigned short>) == alignof(unsigned short), "");
1305static_assert(alignof(fbl::atomic<int>) == alignof(int), "");
1306static_assert(alignof(fbl::atomic<unsigned int>) == alignof(unsigned int), "");
1307static_assert(alignof(fbl::atomic<long>) == alignof(long), "");
1308static_assert(alignof(fbl::atomic<unsigned long>) == alignof(unsigned long), "");
1309static_assert(alignof(fbl::atomic<long long>) == alignof(long long), "");
1310static_assert(alignof(fbl::atomic<unsigned long long>) == alignof(unsigned long long), "");
1311static_assert(alignof(fbl::atomic<bool>) == alignof(bool), "");
1312static_assert(alignof(fbl::atomic<void*>) == alignof(void*), "");
1313static_assert(alignof(fbl::atomic<const void*>) == alignof(const void*), "");
1314static_assert(alignof(fbl::atomic<volatile void*>) == alignof(volatile void*), "");
1315static_assert(alignof(fbl::atomic<const volatile void*>) == alignof(const volatile void*), "");
1316static_assert(alignof(fbl::atomic<int*>) == alignof(int*), "");
1317static_assert(alignof(fbl::atomic<const int*>) == alignof(const int*), "");
1318static_assert(alignof(fbl::atomic<volatile int*>) == alignof(volatile int*), "");
1319static_assert(alignof(fbl::atomic<const volatile int*>) == alignof(const volatile int*), "");
1320static_assert(alignof(fbl::atomic<S*>) == alignof(S*), "");
1321static_assert(alignof(fbl::atomic<const S*>) == alignof(const S*), "");
1322static_assert(alignof(fbl::atomic<volatile S*>) == alignof(volatile S*), "");
1323static_assert(alignof(fbl::atomic<const volatile S*>) == alignof(const volatile S*), "");
1324static_assert(alignof(fbl::atomic<function_pointer>) == alignof(function_pointer), "");
1325
1326static_assert(fbl::is_standard_layout<fbl::atomic<char>>::value, "");
1327static_assert(fbl::is_standard_layout<fbl::atomic<signed char>>::value, "");
1328static_assert(fbl::is_standard_layout<fbl::atomic<unsigned char>>::value, "");
1329static_assert(fbl::is_standard_layout<fbl::atomic<short>>::value, "");
1330static_assert(fbl::is_standard_layout<fbl::atomic<unsigned short>>::value, "");
1331static_assert(fbl::is_standard_layout<fbl::atomic<int>>::value, "");
1332static_assert(fbl::is_standard_layout<fbl::atomic<unsigned int>>::value, "");
1333static_assert(fbl::is_standard_layout<fbl::atomic<long>>::value, "");
1334static_assert(fbl::is_standard_layout<fbl::atomic<unsigned long>>::value, "");
1335static_assert(fbl::is_standard_layout<fbl::atomic<long long>>::value, "");
1336static_assert(fbl::is_standard_layout<fbl::atomic<unsigned long long>>::value, "");
1337static_assert(fbl::is_standard_layout<fbl::atomic<bool>>::value, "");
1338static_assert(fbl::is_standard_layout<fbl::atomic<void*>>::value, "");
1339static_assert(fbl::is_standard_layout<fbl::atomic<const void*>>::value, "");
1340static_assert(fbl::is_standard_layout<fbl::atomic<volatile void*>>::value, "");
1341static_assert(fbl::is_standard_layout<fbl::atomic<const volatile void*>>::value, "");
1342static_assert(fbl::is_standard_layout<fbl::atomic<void*>>::value, "");
1343static_assert(fbl::is_standard_layout<fbl::atomic<const int*>>::value, "");
1344static_assert(fbl::is_standard_layout<fbl::atomic<volatile int*>>::value, "");
1345static_assert(fbl::is_standard_layout<fbl::atomic<const volatile int*>>::value, "");
1346static_assert(fbl::is_standard_layout<fbl::atomic<S*>>::value, "");
1347static_assert(fbl::is_standard_layout<fbl::atomic<const S*>>::value, "");
1348static_assert(fbl::is_standard_layout<fbl::atomic<volatile S*>>::value, "");
1349static_assert(fbl::is_standard_layout<fbl::atomic<const volatile S*>>::value, "");
1350static_assert(fbl::is_standard_layout<fbl::atomic<function_pointer>>::value, "");
1351
1352bool atomic_fence_test() {
1353    BEGIN_TEST;
1354
1355    for (const auto& order : orders) {
1356        atomic_thread_fence(order);
1357        atomic_signal_fence(order);
1358    }
1359
1360    END_TEST;
1361}
1362
1363bool atomic_init_test() {
1364    BEGIN_TEST;
1365
1366    fbl::atomic_uint32_t atomic1;
1367    fbl::atomic_init(&atomic1, 1u);
1368    EXPECT_EQ(1u, atomic1.load());
1369
1370    fbl::atomic_uint32_t atomic2;
1371    volatile fbl::atomic_uint32_t* vatomic2 = &atomic2;
1372    fbl::atomic_init(vatomic2, 2u);
1373    EXPECT_EQ(2u, atomic2.load());
1374
1375    END_TEST;
1376}
1377
1378} // namespace
1379
1380BEGIN_TEST_CASE(atomic_tests)
1381RUN_NAMED_TEST("Atomic explicit declarations test", atomic_explicit_declarations_test)
1382RUN_NAMED_TEST("Atomic using declarations test", atomic_using_declarations_test)
1383RUN_NAMED_TEST("Atomic won't compile test", atomic_wont_compile_test)
1384RUN_NAMED_TEST("Atomic math test", atomic_math_test)
1385RUN_NAMED_TEST("Atomic pointer math test", atomic_pointer_math_test)
1386RUN_NAMED_TEST("Atomic load/store test", atomic_load_store_test)
1387RUN_NAMED_TEST("Atomic exchange test", atomic_exchange_test)
1388RUN_NAMED_TEST("Atomic compare-exchange test", atomic_compare_exchange_test)
1389RUN_NAMED_TEST("Atomic fence test", atomic_fence_test)
1390RUN_NAMED_TEST("Atomic init test", atomic_init_test)
1391END_TEST_CASE(atomic_tests);
1392