1 //===----------------------------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 // <atomic>
10 
11 // template <>
12 // struct atomic<integral>
13 // {
14 //     bool is_lock_free() const volatile;
15 //     bool is_lock_free() const;
16 //     void store(integral desr, memory_order m = memory_order_seq_cst) volatile;
17 //     void store(integral desr, memory_order m = memory_order_seq_cst);
18 //     integral load(memory_order m = memory_order_seq_cst) const volatile;
19 //     integral load(memory_order m = memory_order_seq_cst) const;
20 //     operator integral() const volatile;
21 //     operator integral() const;
22 //     integral exchange(integral desr,
23 //                       memory_order m = memory_order_seq_cst) volatile;
24 //     integral exchange(integral desr, memory_order m = memory_order_seq_cst);
25 //     bool compare_exchange_weak(integral& expc, integral desr,
26 //                                memory_order s, memory_order f) volatile;
27 //     bool compare_exchange_weak(integral& expc, integral desr,
28 //                                memory_order s, memory_order f);
29 //     bool compare_exchange_strong(integral& expc, integral desr,
30 //                                  memory_order s, memory_order f) volatile;
31 //     bool compare_exchange_strong(integral& expc, integral desr,
32 //                                  memory_order s, memory_order f);
33 //     bool compare_exchange_weak(integral& expc, integral desr,
34 //                                memory_order m = memory_order_seq_cst) volatile;
35 //     bool compare_exchange_weak(integral& expc, integral desr,
36 //                                memory_order m = memory_order_seq_cst);
37 //     bool compare_exchange_strong(integral& expc, integral desr,
38 //                                 memory_order m = memory_order_seq_cst) volatile;
39 //     bool compare_exchange_strong(integral& expc, integral desr,
40 //                                  memory_order m = memory_order_seq_cst);
41 //
42 //     integral
43 //         fetch_add(integral op, memory_order m = memory_order_seq_cst) volatile;
44 //     integral fetch_add(integral op, memory_order m = memory_order_seq_cst);
45 //     integral
46 //         fetch_sub(integral op, memory_order m = memory_order_seq_cst) volatile;
47 //     integral fetch_sub(integral op, memory_order m = memory_order_seq_cst);
48 //     integral
49 //         fetch_and(integral op, memory_order m = memory_order_seq_cst) volatile;
50 //     integral fetch_and(integral op, memory_order m = memory_order_seq_cst);
51 //     integral
52 //         fetch_or(integral op, memory_order m = memory_order_seq_cst) volatile;
53 //     integral fetch_or(integral op, memory_order m = memory_order_seq_cst);
54 //     integral
55 //         fetch_xor(integral op, memory_order m = memory_order_seq_cst) volatile;
56 //     integral fetch_xor(integral op, memory_order m = memory_order_seq_cst);
57 //
58 //     atomic() = default;
59 //     constexpr atomic(integral desr);
60 //     atomic(const atomic&) = delete;
61 //     atomic& operator=(const atomic&) = delete;
62 //     atomic& operator=(const atomic&) volatile = delete;
63 //     integral operator=(integral desr) volatile;
64 //     integral operator=(integral desr);
65 //
66 //     integral operator++(int) volatile;
67 //     integral operator++(int);
68 //     integral operator--(int) volatile;
69 //     integral operator--(int);
70 //     integral operator++() volatile;
71 //     integral operator++();
72 //     integral operator--() volatile;
73 //     integral operator--();
74 //     integral operator+=(integral op) volatile;
75 //     integral operator+=(integral op);
76 //     integral operator-=(integral op) volatile;
77 //     integral operator-=(integral op);
78 //     integral operator&=(integral op) volatile;
79 //     integral operator&=(integral op);
80 //     integral operator|=(integral op) volatile;
81 //     integral operator|=(integral op);
82 //     integral operator^=(integral op) volatile;
83 //     integral operator^=(integral op);
84 // };
85 
86 #include <atomic>
87 #include <new>
88 #include <cassert>
89 
90 #include <cmpxchg_loop.h>
91 
92 #include "test_macros.h"
93 
94 template <class A, class T>
95 void
do_test()96 do_test()
97 {
98     A obj(T(0));
99     assert(obj == T(0));
100     bool b0 = obj.is_lock_free();
101     ((void)b0); // mark as unused
102     obj.store(T(0));
103     assert(obj == T(0));
104     obj.store(T(1), std::memory_order_release);
105     assert(obj == T(1));
106     assert(obj.load() == T(1));
107     assert(obj.load(std::memory_order_acquire) == T(1));
108     assert(obj.exchange(T(2)) == T(1));
109     assert(obj == T(2));
110     assert(obj.exchange(T(3), std::memory_order_relaxed) == T(2));
111     assert(obj == T(3));
112     T x = obj;
113     assert(cmpxchg_weak_loop(obj, x, T(2)) == true);
114     assert(obj == T(2));
115     assert(x == T(3));
116     assert(obj.compare_exchange_weak(x, T(1)) == false);
117     assert(obj == T(2));
118     assert(x == T(2));
119     x = T(2);
120     assert(obj.compare_exchange_strong(x, T(1)) == true);
121     assert(obj == T(1));
122     assert(x == T(2));
123     assert(obj.compare_exchange_strong(x, T(0)) == false);
124     assert(obj == T(1));
125     assert(x == T(1));
126     assert((obj = T(0)) == T(0));
127     assert(obj == T(0));
128     assert(obj++ == T(0));
129     assert(obj == T(1));
130     assert(++obj == T(2));
131     assert(obj == T(2));
132     assert(--obj == T(1));
133     assert(obj == T(1));
134     assert(obj-- == T(1));
135     assert(obj == T(0));
136     obj = T(2);
137     assert((obj += T(3)) == T(5));
138     assert(obj == T(5));
139     assert((obj -= T(3)) == T(2));
140     assert(obj == T(2));
141     assert((obj |= T(5)) == T(7));
142     assert(obj == T(7));
143     assert((obj &= T(0xF)) == T(7));
144     assert(obj == T(7));
145     assert((obj ^= T(0xF)) == T(8));
146     assert(obj == T(8));
147 
148     {
149         TEST_ALIGNAS_TYPE(A) char storage[sizeof(A)] = {23};
150         A& zero = *new (storage) A();
151         assert(zero == 0);
152         zero.~A();
153     }
154 }
155 
156 template <class A, class T>
test()157 void test()
158 {
159     do_test<A, T>();
160     do_test<volatile A, T>();
161 }
162 
163 
main(int,char **)164 int main(int, char**)
165 {
166     test<std::atomic_char, char>();
167     test<std::atomic_schar, signed char>();
168     test<std::atomic_uchar, unsigned char>();
169     test<std::atomic_short, short>();
170     test<std::atomic_ushort, unsigned short>();
171     test<std::atomic_int, int>();
172     test<std::atomic_uint, unsigned int>();
173     test<std::atomic_long, long>();
174     test<std::atomic_ulong, unsigned long>();
175     test<std::atomic_llong, long long>();
176     test<std::atomic_ullong, unsigned long long>();
177 #if TEST_STD_VER > 17 && defined(__cpp_char8_t)
178     test<std::atomic_char8_t, char8_t>();
179 #endif
180     test<std::atomic_char16_t, char16_t>();
181     test<std::atomic_char32_t, char32_t>();
182 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
183     test<std::atomic_wchar_t, wchar_t>();
184 #endif
185 
186     test<std::atomic_int8_t,    int8_t>();
187     test<std::atomic_uint8_t,  uint8_t>();
188     test<std::atomic_int16_t,   int16_t>();
189     test<std::atomic_uint16_t, uint16_t>();
190     test<std::atomic_int32_t,   int32_t>();
191     test<std::atomic_uint32_t, uint32_t>();
192     test<std::atomic_int64_t,   int64_t>();
193     test<std::atomic_uint64_t, uint64_t>();
194 
195     test<volatile std::atomic_char, char>();
196     test<volatile std::atomic_schar, signed char>();
197     test<volatile std::atomic_uchar, unsigned char>();
198     test<volatile std::atomic_short, short>();
199     test<volatile std::atomic_ushort, unsigned short>();
200     test<volatile std::atomic_int, int>();
201     test<volatile std::atomic_uint, unsigned int>();
202     test<volatile std::atomic_long, long>();
203     test<volatile std::atomic_ulong, unsigned long>();
204     test<volatile std::atomic_llong, long long>();
205     test<volatile std::atomic_ullong, unsigned long long>();
206     test<volatile std::atomic_char16_t, char16_t>();
207     test<volatile std::atomic_char32_t, char32_t>();
208 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
209     test<volatile std::atomic_wchar_t, wchar_t>();
210 #endif
211 
212     test<volatile std::atomic_int8_t,    int8_t>();
213     test<volatile std::atomic_uint8_t,  uint8_t>();
214     test<volatile std::atomic_int16_t,   int16_t>();
215     test<volatile std::atomic_uint16_t, uint16_t>();
216     test<volatile std::atomic_int32_t,   int32_t>();
217     test<volatile std::atomic_uint32_t, uint32_t>();
218     test<volatile std::atomic_int64_t,   int64_t>();
219     test<volatile std::atomic_uint64_t, uint64_t>();
220 
221   return 0;
222 }
223