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 <new> |
69 | #include <type_traits> |
70 | #include <cassert> |
71 | |
72 | #include <cmpxchg_loop.h> |
73 | |
74 | #include "test_macros.h" |
75 | |
76 | template <class A, class T> |
77 | void |
78 | do_test() |
79 | { |
80 | typedef typename std::remove_pointer<T>::type X; |
81 | A obj(T(0)); |
82 | assert(obj == T(0)); |
83 | { |
84 | bool lockfree = obj.is_lock_free(); |
85 | (void)lockfree; |
86 | #if TEST_STD_VER >= 17 |
87 | if (A::is_always_lock_free) |
88 | assert(lockfree); |
89 | #endif |
90 | } |
91 | obj.store(T(0)); |
92 | assert(obj == T(0)); |
93 | obj.store(T(1), std::memory_order_release); |
94 | assert(obj == T(1)); |
95 | assert(obj.load() == T(1)); |
96 | assert(obj.load(std::memory_order_acquire) == T(1)); |
97 | assert(obj.exchange(T(2)) == T(1)); |
98 | assert(obj == T(2)); |
99 | assert(obj.exchange(T(3), std::memory_order_relaxed) == T(2)); |
100 | assert(obj == T(3)); |
101 | T x = obj; |
102 | assert(cmpxchg_weak_loop(obj, x, T(2)) == true); |
103 | assert(obj == T(2)); |
104 | assert(x == T(3)); |
105 | assert(obj.compare_exchange_weak(x, T(1)) == false); |
106 | assert(obj == T(2)); |
107 | assert(x == T(2)); |
108 | x = T(2); |
109 | assert(obj.compare_exchange_strong(x, T(1)) == true); |
110 | assert(obj == T(1)); |
111 | assert(x == T(2)); |
112 | assert(obj.compare_exchange_strong(x, T(0)) == false); |
113 | assert(obj == T(1)); |
114 | assert(x == T(1)); |
115 | assert((obj = T(0)) == T(0)); |
116 | assert(obj == T(0)); |
117 | obj = T(2*sizeof(X)); |
118 | assert((obj += std::ptrdiff_t(3)) == T(5*sizeof(X))); |
119 | assert(obj == T(5*sizeof(X))); |
120 | assert((obj -= std::ptrdiff_t(3)) == T(2*sizeof(X))); |
121 | assert(obj == T(2*sizeof(X))); |
122 | |
123 | { |
124 | TEST_ALIGNAS_TYPE(A) char storage[sizeof(A)] = {23}; |
125 | A& zero = *new (storage) A(); |
126 | assert(zero == T(0)); |
127 | zero.~A(); |
128 | } |
129 | } |
130 | |
131 | template <class A, class T> |
132 | void test() |
133 | { |
134 | do_test<A, T>(); |
135 | do_test<volatile A, T>(); |
136 | } |
137 | |
138 | int main(int, char**) |
139 | { |
140 | test<std::atomic<int*>, int*>(); |
141 | |
142 | return 0; |
143 | } |
144 | |