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 <class T> |
12 | // struct atomic<T*> |
13 | // { |
14 | // bool is_lock_free() const volatile; |
15 | // bool is_lock_free() const; |
16 | // void store(T* desr, memory_order m = memory_order_seq_cst) volatile; |
17 | // void store(T* desr, memory_order m = memory_order_seq_cst); |
18 | // T* load(memory_order m = memory_order_seq_cst) const volatile; |
19 | // T* load(memory_order m = memory_order_seq_cst) const; |
20 | // operator T*() const volatile; |
21 | // operator T*() const; |
22 | // T* exchange(T* desr, memory_order m = memory_order_seq_cst) volatile; |
23 | // T* exchange(T* desr, memory_order m = memory_order_seq_cst); |
24 | // bool compare_exchange_weak(T*& expc, T* desr, |
25 | // memory_order s, memory_order f) volatile; |
26 | // bool compare_exchange_weak(T*& expc, T* desr, |
27 | // memory_order s, memory_order f); |
28 | // bool compare_exchange_strong(T*& expc, T* desr, |
29 | // memory_order s, memory_order f) volatile; |
30 | // bool compare_exchange_strong(T*& expc, T* desr, |
31 | // memory_order s, memory_order f); |
32 | // bool compare_exchange_weak(T*& expc, T* desr, |
33 | // memory_order m = memory_order_seq_cst) volatile; |
34 | // bool compare_exchange_weak(T*& expc, T* desr, |
35 | // memory_order m = memory_order_seq_cst); |
36 | // bool compare_exchange_strong(T*& expc, T* desr, |
37 | // memory_order m = memory_order_seq_cst) volatile; |
38 | // bool compare_exchange_strong(T*& expc, T* desr, |
39 | // memory_order m = memory_order_seq_cst); |
40 | // T* fetch_add(ptrdiff_t op, memory_order m = memory_order_seq_cst) volatile; |
41 | // T* fetch_add(ptrdiff_t op, memory_order m = memory_order_seq_cst); |
42 | // T* fetch_sub(ptrdiff_t op, memory_order m = memory_order_seq_cst) volatile; |
43 | // T* fetch_sub(ptrdiff_t op, memory_order m = memory_order_seq_cst); |
44 | // |
45 | // atomic() = default; |
46 | // constexpr atomic(T* desr); |
47 | // atomic(const atomic&) = delete; |
48 | // atomic& operator=(const atomic&) = delete; |
49 | // atomic& operator=(const atomic&) volatile = delete; |
50 | // |
51 | // T* operator=(T*) volatile; |
52 | // T* operator=(T*); |
53 | // T* operator++(int) volatile; |
54 | // T* operator++(int); |
55 | // T* operator--(int) volatile; |
56 | // T* operator--(int); |
57 | // T* operator++() volatile; |
58 | // T* operator++(); |
59 | // T* operator--() volatile; |
60 | // T* operator--(); |
61 | // T* operator+=(ptrdiff_t op) volatile; |
62 | // T* operator+=(ptrdiff_t op); |
63 | // T* operator-=(ptrdiff_t op) volatile; |
64 | // T* operator-=(ptrdiff_t op); |
65 | // }; |
66 | |
67 | #include <atomic> |
68 | #include <cassert> |
69 | #include <cstddef> |
70 | #include <new> |
71 | #include <type_traits> |
72 | |
73 | #include <cmpxchg_loop.h> |
74 | |
75 | #include "test_macros.h" |
76 | |
77 | template <class A, class T> |
78 | void |
79 | do_test() |
80 | { |
81 | typedef typename std::remove_pointer<T>::type X; |
82 | A obj(T(0)); |
83 | assert(obj == T(0)); |
84 | { |
85 | bool lockfree = obj.is_lock_free(); |
86 | (void)lockfree; |
87 | #if TEST_STD_VER >= 17 |
88 | if (A::is_always_lock_free) |
89 | assert(lockfree); |
90 | #endif |
91 | } |
92 | obj.store(T(0)); |
93 | assert(obj == T(0)); |
94 | obj.store(T(1), std::memory_order_release); |
95 | assert(obj == T(1)); |
96 | assert(obj.load() == T(1)); |
97 | assert(obj.load(std::memory_order_acquire) == T(1)); |
98 | assert(obj.exchange(T(2)) == T(1)); |
99 | assert(obj == T(2)); |
100 | assert(obj.exchange(T(3), std::memory_order_relaxed) == T(2)); |
101 | assert(obj == T(3)); |
102 | T x = obj; |
103 | assert(cmpxchg_weak_loop(obj, x, T(2)) == true); |
104 | assert(obj == T(2)); |
105 | assert(x == T(3)); |
106 | assert(obj.compare_exchange_weak(x, T(1)) == false); |
107 | assert(obj == T(2)); |
108 | assert(x == T(2)); |
109 | x = T(2); |
110 | assert(obj.compare_exchange_strong(x, T(1)) == true); |
111 | assert(obj == T(1)); |
112 | assert(x == T(2)); |
113 | assert(obj.compare_exchange_strong(x, T(0)) == false); |
114 | assert(obj == T(1)); |
115 | assert(x == T(1)); |
116 | assert((obj = T(0)) == T(0)); |
117 | assert(obj == T(0)); |
118 | obj = T(2*sizeof(X)); |
119 | assert((obj += std::ptrdiff_t(3)) == T(5*sizeof(X))); |
120 | assert(obj == T(5*sizeof(X))); |
121 | assert((obj -= std::ptrdiff_t(3)) == T(2*sizeof(X))); |
122 | assert(obj == T(2*sizeof(X))); |
123 | |
124 | { |
125 | TEST_ALIGNAS_TYPE(A) char storage[sizeof(A)] = {23}; |
126 | A& zero = *new (storage) A(); |
127 | assert(zero == T(0)); |
128 | zero.~A(); |
129 | } |
130 | } |
131 | |
132 | template <class A, class T> |
133 | void test() |
134 | { |
135 | do_test<A, T>(); |
136 | do_test<volatile A, T>(); |
137 | } |
138 | |
139 | int main(int, char**) |
140 | { |
141 | test<std::atomic<int*>, int*>(); |
142 | |
143 | return 0; |
144 | } |
145 | |