xref: /llvm-project/libcxx/test/std/atomics/atomics.ref/increment_decrement.pass.cpp (revision 19557a4c8fab0dbfe9d9c53b99b7960ef211684e)
142ba740aSDamien L-G //
242ba740aSDamien L-G // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
342ba740aSDamien L-G // See https://llvm.org/LICENSE.txt for license information.
442ba740aSDamien L-G // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
542ba740aSDamien L-G //
642ba740aSDamien L-G //===----------------------------------------------------------------------===//
742ba740aSDamien L-G 
842ba740aSDamien L-G // UNSUPPORTED: c++03, c++11, c++14, c++17
942ba740aSDamien L-G // XFAIL: !has-64-bit-atomics
1042ba740aSDamien L-G 
1142ba740aSDamien L-G // integral-type operator++(int) const noexcept;
1242ba740aSDamien L-G // integral-type operator--(int) const noexcept;
1342ba740aSDamien L-G // integral-type operator++() const noexcept;
1442ba740aSDamien L-G // integral-type operator--() const noexcept;
1542ba740aSDamien L-G 
1642ba740aSDamien L-G #include <atomic>
1742ba740aSDamien L-G #include <cassert>
1842ba740aSDamien L-G #include <concepts>
1942ba740aSDamien L-G #include <type_traits>
2009e3a360SLouis Dionne #include <utility>
2142ba740aSDamien L-G 
2242ba740aSDamien L-G #include "atomic_helpers.h"
2342ba740aSDamien L-G #include "test_macros.h"
2442ba740aSDamien L-G 
2542ba740aSDamien L-G template <typename T>
2642ba740aSDamien L-G concept has_pre_increment_operator = requires { ++std::declval<T const>(); };
2742ba740aSDamien L-G 
2842ba740aSDamien L-G template <typename T>
2942ba740aSDamien L-G concept has_post_increment_operator = requires { std::declval<T const>()++; };
3042ba740aSDamien L-G 
3142ba740aSDamien L-G template <typename T>
3242ba740aSDamien L-G concept has_pre_decrement_operator = requires { --std::declval<T const>(); };
3342ba740aSDamien L-G 
3442ba740aSDamien L-G template <typename T>
3542ba740aSDamien L-G concept has_post_decrement_operator = requires { std::declval<T const>()--; };
3642ba740aSDamien L-G 
3742ba740aSDamien L-G template <typename T>
3842ba740aSDamien L-G constexpr bool does_not_have_increment_nor_decrement_operators() {
3942ba740aSDamien L-G   return !has_pre_increment_operator<T> && !has_pre_decrement_operator<T> && !has_post_increment_operator<T> &&
4042ba740aSDamien L-G          !has_post_decrement_operator<T>;
4142ba740aSDamien L-G }
4242ba740aSDamien L-G 
4342ba740aSDamien L-G template <typename T>
4442ba740aSDamien L-G struct TestDoesNotHaveIncrementDecrement {
45*19557a4cSDamien L-G   void operator()() const { static_assert(does_not_have_increment_nor_decrement_operators<std::atomic_ref<T>>()); }
4642ba740aSDamien L-G };
4742ba740aSDamien L-G 
4842ba740aSDamien L-G template <typename T>
4942ba740aSDamien L-G struct TestIncrementDecrement {
5042ba740aSDamien L-G   void operator()() const {
51*19557a4cSDamien L-G     if constexpr (std::is_integral_v<T>) {
5242ba740aSDamien L-G       T x(T(1));
5342ba740aSDamien L-G       std::atomic_ref<T> const a(x);
5442ba740aSDamien L-G 
5542ba740aSDamien L-G       {
5642ba740aSDamien L-G         std::same_as<T> decltype(auto) y = ++a;
5742ba740aSDamien L-G         assert(y == T(2));
5842ba740aSDamien L-G         assert(x == T(2));
5942ba740aSDamien L-G         ASSERT_NOEXCEPT(++a);
6042ba740aSDamien L-G       }
6142ba740aSDamien L-G 
6242ba740aSDamien L-G       {
6342ba740aSDamien L-G         std::same_as<T> decltype(auto) y = --a;
6442ba740aSDamien L-G         assert(y == T(1));
6542ba740aSDamien L-G         assert(x == T(1));
6642ba740aSDamien L-G         ASSERT_NOEXCEPT(--a);
6742ba740aSDamien L-G       }
6842ba740aSDamien L-G 
6942ba740aSDamien L-G       {
7042ba740aSDamien L-G         std::same_as<T> decltype(auto) y = a++;
7142ba740aSDamien L-G         assert(y == T(1));
7242ba740aSDamien L-G         assert(x == T(2));
7342ba740aSDamien L-G         ASSERT_NOEXCEPT(a++);
7442ba740aSDamien L-G       }
7542ba740aSDamien L-G 
7642ba740aSDamien L-G       {
7742ba740aSDamien L-G         std::same_as<T> decltype(auto) y = a--;
7842ba740aSDamien L-G         assert(y == T(2));
7942ba740aSDamien L-G         assert(x == T(1));
8042ba740aSDamien L-G         ASSERT_NOEXCEPT(a--);
8142ba740aSDamien L-G       }
82*19557a4cSDamien L-G     } else if constexpr (std::is_pointer_v<T>) {
83*19557a4cSDamien L-G       using U = std::remove_pointer_t<T>;
84*19557a4cSDamien L-G       U t[9]  = {};
85*19557a4cSDamien L-G       T p{&t[1]};
86*19557a4cSDamien L-G       std::atomic_ref<T> const a(p);
87*19557a4cSDamien L-G 
88*19557a4cSDamien L-G       {
89*19557a4cSDamien L-G         std::same_as<T> decltype(auto) y = ++a;
90*19557a4cSDamien L-G         assert(y == &t[2]);
91*19557a4cSDamien L-G         assert(p == &t[2]);
92*19557a4cSDamien L-G         ASSERT_NOEXCEPT(++a);
93*19557a4cSDamien L-G       }
94*19557a4cSDamien L-G 
95*19557a4cSDamien L-G       {
96*19557a4cSDamien L-G         std::same_as<T> decltype(auto) y = --a;
97*19557a4cSDamien L-G         assert(y == &t[1]);
98*19557a4cSDamien L-G         assert(p == &t[1]);
99*19557a4cSDamien L-G         ASSERT_NOEXCEPT(--a);
100*19557a4cSDamien L-G       }
101*19557a4cSDamien L-G 
102*19557a4cSDamien L-G       {
103*19557a4cSDamien L-G         std::same_as<T> decltype(auto) y = a++;
104*19557a4cSDamien L-G         assert(y == &t[1]);
105*19557a4cSDamien L-G         assert(p == &t[2]);
106*19557a4cSDamien L-G         ASSERT_NOEXCEPT(a++);
107*19557a4cSDamien L-G       }
108*19557a4cSDamien L-G 
109*19557a4cSDamien L-G       {
110*19557a4cSDamien L-G         std::same_as<T> decltype(auto) y = a--;
111*19557a4cSDamien L-G         assert(y == &t[2]);
112*19557a4cSDamien L-G         assert(p == &t[1]);
113*19557a4cSDamien L-G         ASSERT_NOEXCEPT(a--);
114*19557a4cSDamien L-G       }
115*19557a4cSDamien L-G     } else {
116*19557a4cSDamien L-G       static_assert(std::is_void_v<T>);
117*19557a4cSDamien L-G     }
11842ba740aSDamien L-G   }
11942ba740aSDamien L-G };
12042ba740aSDamien L-G 
12142ba740aSDamien L-G int main(int, char**) {
12242ba740aSDamien L-G   TestEachIntegralType<TestIncrementDecrement>()();
12342ba740aSDamien L-G 
12442ba740aSDamien L-G   TestEachFloatingPointType<TestDoesNotHaveIncrementDecrement>()();
12542ba740aSDamien L-G 
126*19557a4cSDamien L-G   TestEachPointerType<TestIncrementDecrement>()();
12742ba740aSDamien L-G 
12842ba740aSDamien L-G   TestDoesNotHaveIncrementDecrement<bool>()();
12942ba740aSDamien L-G   TestDoesNotHaveIncrementDecrement<UserAtomicType>()();
13042ba740aSDamien L-G   TestDoesNotHaveIncrementDecrement<LargeUserAtomicType>()();
13142ba740aSDamien L-G 
13242ba740aSDamien L-G   return 0;
13342ba740aSDamien L-G }
134