Skip to content

Commit 3c24bb7

Browse files
yfeldblumfacebook-github-bot
authored andcommitted
atomic_ref of const
Summary: Allows taking an `atomic_ref` on a reference-to-`const`. The only possible operations on that `atomic_ref` are `load` operations. Reviewed By: ot Differential Revision: D76643441 fbshipit-source-id: ded8d89cb394556efaa82bc55562dd475f559431
1 parent 085c13a commit 3c24bb7

File tree

2 files changed

+60
-35
lines changed

2 files changed

+60
-35
lines changed

third-party/folly/src/folly/synchronization/AtomicRef.h

Lines changed: 52 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -30,65 +30,73 @@ namespace detail {
3030

3131
template <typename T>
3232
struct atomic_ref_base {
33-
static_assert(sizeof(T) == sizeof(std::atomic<T>), "size mismatch");
34-
static_assert(
35-
std::is_trivially_copyable_v<T>, "value not trivially-copyable");
33+
using value_type = remove_cvref_t<T>;
34+
35+
private:
36+
using atomic_reference = copy_cvref_t<T, std::atomic<value_type>>&;
3637

37-
using value_type = T;
38+
public:
39+
static_assert(
40+
sizeof(value_type) == sizeof(std::atomic<value_type>), "size mismatch");
41+
static_assert(
42+
std::is_trivially_copyable_v<value_type>, "value not trivially-copyable");
3843

3944
static inline constexpr std::size_t required_alignment =
40-
alignof(std::atomic<T>);
45+
alignof(std::atomic<value_type>);
4146

4247
explicit atomic_ref_base(T& ref) : ref_(ref) { check_alignment_(); }
4348
atomic_ref_base(atomic_ref_base const&) = default;
4449

45-
void store(T desired, std::memory_order order = std::memory_order_seq_cst)
46-
const noexcept {
50+
void store(
51+
value_type desired,
52+
std::memory_order order = std::memory_order_seq_cst) const noexcept {
4753
return atomic().store(desired, order);
4854
}
4955

50-
T load(std::memory_order order = std::memory_order_seq_cst) const noexcept {
56+
value_type load(
57+
std::memory_order order = std::memory_order_seq_cst) const noexcept {
5158
return atomic().load(order);
5259
}
5360

54-
T exchange(T desired, std::memory_order order = std::memory_order_seq_cst)
55-
const noexcept {
61+
value_type exchange(
62+
value_type desired,
63+
std::memory_order order = std::memory_order_seq_cst) const noexcept {
5664
return atomic().exchange(desired, order);
5765
}
5866

5967
bool compare_exchange_weak(
60-
T& expected,
61-
T desired,
68+
value_type& expected,
69+
value_type desired,
6270
std::memory_order success,
6371
std::memory_order failure) const noexcept {
6472
return atomic().compare_exchange_weak(expected, desired, success, failure);
6573
}
6674

6775
bool compare_exchange_weak(
68-
T& expected,
69-
T desired,
76+
value_type& expected,
77+
value_type desired,
7078
std::memory_order order = std::memory_order_seq_cst) const noexcept {
7179
return atomic().compare_exchange_weak(expected, desired, order);
7280
}
7381

7482
bool compare_exchange_strong(
75-
T& expected,
76-
T desired,
83+
value_type& expected,
84+
value_type desired,
7785
std::memory_order success,
7886
std::memory_order failure) const noexcept {
7987
return atomic().compare_exchange_strong(
8088
expected, desired, success, failure);
8189
}
8290

8391
bool compare_exchange_strong(
84-
T& expected,
85-
T desired,
92+
value_type& expected,
93+
value_type desired,
8694
std::memory_order order = std::memory_order_seq_cst) const noexcept {
8795
return atomic().compare_exchange_strong(expected, desired, order);
8896
}
8997

90-
std::atomic<T>& atomic() const noexcept {
91-
return reinterpret_cast<std::atomic<T>&>(ref_); // ub dragons be here
98+
atomic_reference atomic() const noexcept {
99+
return reinterpret_cast<atomic_reference>(ref_); // ub dragons be here
92100
}
93101

94102
private:
@@ -103,38 +111,45 @@ struct atomic_ref_base {
103111

104112
template <typename T>
105113
struct atomic_ref_integral_base : atomic_ref_base<T> {
114+
using typename atomic_ref_base<T>::value_type;
115+
106116
using atomic_ref_base<T>::atomic_ref_base;
107117
using atomic_ref_base<T>::atomic;
108118

109-
T fetch_add(T arg, std::memory_order order = std::memory_order_seq_cst)
110-
const noexcept {
119+
value_type fetch_add(
120+
value_type arg,
121+
std::memory_order order = std::memory_order_seq_cst) const noexcept {
111122
return atomic().fetch_add(arg, order);
112123
}
113124

114-
T fetch_sub(T arg, std::memory_order order = std::memory_order_seq_cst)
115-
const noexcept {
125+
value_type fetch_sub(
126+
value_type arg,
127+
std::memory_order order = std::memory_order_seq_cst) const noexcept {
116128
return atomic().fetch_sub(arg, order);
117129
}
118130

119-
T fetch_and(T arg, std::memory_order order = std::memory_order_seq_cst)
120-
const noexcept {
131+
value_type fetch_and(
132+
value_type arg,
133+
std::memory_order order = std::memory_order_seq_cst) const noexcept {
121134
return atomic().fetch_and(arg, order);
122135
}
123136

124-
T fetch_or(T arg, std::memory_order order = std::memory_order_seq_cst)
125-
const noexcept {
137+
value_type fetch_or(
138+
value_type arg,
139+
std::memory_order order = std::memory_order_seq_cst) const noexcept {
126140
return atomic().fetch_or(arg, order);
127141
}
128142

129-
T fetch_xor(T arg, std::memory_order order = std::memory_order_seq_cst)
130-
const noexcept {
143+
value_type fetch_xor(
144+
value_type arg,
145+
std::memory_order order = std::memory_order_seq_cst) const noexcept {
131146
return atomic().fetch_xor(arg, order);
132147
}
133148
};
134149

135-
template <typename T>
150+
template <typename T, typename TD = remove_cvref_t<T>>
136151
using atomic_ref_select = conditional_t<
137-
std::is_integral<T>::value && !std::is_same<T, bool>::value,
152+
std::is_integral<TD>::value && !std::is_same<TD, bool>::value,
138153
atomic_ref_integral_base<T>,
139154
atomic_ref_base<T>>;
140155

@@ -166,10 +181,12 @@ atomic_ref(T&) -> atomic_ref<T>;
166181
struct make_atomic_ref_t {
167182
template <
168183
typename T,
184+
typename...,
185+
typename TD = remove_cvref_t<T>,
186+
typename ATD = std::atomic<TD>,
169187
std::enable_if_t<
170-
std::is_trivially_copyable_v<T> &&
171-
sizeof(T) == sizeof(std::atomic<T>) &&
172-
alignof(T) == alignof(std::atomic<T>),
188+
std::is_trivially_copyable_v<TD> && //
189+
sizeof(TD) == sizeof(ATD) && alignof(TD) == alignof(ATD),
173190
int> = 0>
174191
atomic_ref<T> operator()(T& ref) const {
175192
return atomic_ref<T>{ref};

third-party/folly/src/folly/synchronization/test/AtomicRefTest.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,3 +170,11 @@ TEST_F(AtomicRefTest, integer_compare_exchange_strong) {
170170
EXPECT_EQ(19, expected);
171171
}
172172
}
173+
174+
TEST_F(AtomicRefTest, integer_const) {
175+
long const value = 17;
176+
static_assert(std::is_const_v<decltype(value)>);
177+
auto ref = folly::make_atomic_ref(value);
178+
static_assert(!std::is_const_v<decltype(ref)::value_type>);
179+
EXPECT_EQ(17, ref.load(std::memory_order_relaxed));
180+
}

0 commit comments

Comments
 (0)