Skip to content

Commit 7fd91b8

Browse files
feat: Add overload versions of store/compare_exchange of primitive
1 parent 51411a0 commit 7fd91b8

1 file changed

Lines changed: 59 additions & 26 deletions

File tree

src/primitive/impl.cppm

Lines changed: 59 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -22,38 +22,48 @@ private:
2222
policy::resolve_policy_t<policy::category::type, Policies...>;
2323
using value_rep_type = underlying::traits<value_type>::rep_type;
2424

25-
template <underlying_type U>
26-
static constexpr bool cross_underlying_constructible_v = [] {
27-
using source_value_type = std::remove_cv_t<U>;
25+
template <underlying_type Source, underlying_type Target>
26+
static constexpr bool policy_allows_underlying_bridge_v = [] {
2827
using source_rep_type =
29-
underlying::traits<source_value_type>::rep_type;
30-
28+
underlying::traits<std::remove_cv_t<Source>>::rep_type;
29+
using target_rep_type =
30+
underlying::traits<std::remove_cv_t<Target>>::rep_type;
3131
if constexpr (std::same_as<type_policy_t, policy::type::strict>) {
3232
return false;
3333
} else if constexpr (std::same_as<type_policy_t, policy::type::compatible>) {
34-
return underlying::traits<source_value_type>::kind ==
35-
underlying::traits<value_type>::kind &&
36-
has_common_rep<source_rep_type, value_rep_type> &&
37-
!std::same_as<common_rep_t<source_rep_type, value_rep_type>, void>;
34+
return underlying::traits<std::remove_cv_t<Source>>::kind ==
35+
underlying::traits<std::remove_cv_t<Target>>::kind &&
36+
has_common_rep<source_rep_type, target_rep_type> &&
37+
!std::same_as<common_rep_t<source_rep_type, target_rep_type>, void>;
3838
} else if constexpr (std::same_as<type_policy_t,
3939
policy::type::transparent>) {
40-
return has_common_rep<source_rep_type, value_rep_type> &&
41-
!std::same_as<common_rep_t<source_rep_type, value_rep_type>, void>;
40+
return has_common_rep<source_rep_type, target_rep_type> &&
41+
!std::same_as<common_rep_t<source_rep_type, target_rep_type>, void>;
4242
} else {
4343
return false;
4444
}
4545
}();
4646

4747
template <underlying_type U>
48-
static constexpr auto convert_cross_underlying_(U u) noexcept -> value_type {
49-
using source_value_type = std::remove_cv_t<U>;
50-
using source_rep_type =
51-
underlying::traits<source_value_type>::rep_type;
48+
static constexpr bool cross_underlying_constructible_v =
49+
policy_allows_underlying_bridge_v<U, value_type>;
5250

53-
auto const source_rep = underlying::traits<source_value_type>::to_rep(u);
54-
auto const target_rep = static_cast<value_rep_type>(
51+
template <underlying_type U>
52+
static constexpr bool cross_underlying_exchangeable_v =
53+
cross_underlying_constructible_v<U> &&
54+
policy_allows_underlying_bridge_v<value_type, U>;
55+
56+
template <underlying_type Target, underlying_type Source>
57+
static constexpr auto convert_underlying_(Source source) noexcept -> Target {
58+
using source_value_type = std::remove_cv_t<Source>;
59+
using source_rep_type = underlying::traits<source_value_type>::rep_type;
60+
using target_rep_type =
61+
underlying::traits<std::remove_cv_t<Target>>::rep_type;
62+
63+
auto const source_rep = underlying::traits<source_value_type>::to_rep(source);
64+
auto const target_rep = static_cast<target_rep_type>(
5565
static_cast<source_rep_type>(source_rep));
56-
return underlying::traits<value_type>::from_rep(target_rep);
66+
return underlying::traits<std::remove_cv_t<Target>>::from_rep(target_rep);
5767
}
5868

5969
public:
@@ -65,7 +75,7 @@ public:
6575
requires(!std::same_as<U, value_type> &&
6676
cross_underlying_constructible_v<U>)
6777
constexpr explicit primitive(U u) noexcept
68-
: value_(convert_cross_underlying_<U>(u)) {}
78+
: value_(convert_underlying_<value_type>(u)) {}
6979

7080
constexpr primitive(primitive const &other) noexcept {
7181
if consteval {
@@ -79,7 +89,7 @@ public:
7989
requires(!std::same_as<U, value_type>)
8090
explicit constexpr primitive(primitive<U, Policies...> const &other) noexcept
8191
requires(cross_underlying_constructible_v<U>)
82-
: value_(convert_cross_underlying_<U>(other.load())) {}
92+
: value_(convert_underlying_<value_type>(other.load())) {}
8393

8494
constexpr auto operator=(primitive const &other) noexcept -> primitive & {
8595
if (this == &other) {
@@ -99,7 +109,7 @@ public:
99109
constexpr auto
100110
operator=(primitive<U, Policies...> const &other) noexcept -> primitive &
101111
requires(cross_underlying_constructible_v<U>) {
102-
store(convert_cross_underlying_<U>(other.load()));
112+
store(convert_underlying_<value_type>(other.load()));
103113
return *this;
104114
}
105115

@@ -115,7 +125,7 @@ public:
115125
requires(!std::same_as<U, value_type>)
116126
explicit constexpr primitive(primitive<U, Policies...> &&other) noexcept
117127
requires(cross_underlying_constructible_v<U>)
118-
: value_(convert_cross_underlying_<U>(other.load())) {}
128+
: value_(convert_underlying_<value_type>(other.load())) {}
119129

120130
constexpr auto operator=(primitive &&other) noexcept -> primitive & {
121131
if (this == &other) {
@@ -135,7 +145,7 @@ public:
135145
constexpr auto operator=(primitive<U, Policies...> &&other) noexcept
136146
-> primitive &
137147
requires(cross_underlying_constructible_v<U>) {
138-
store(convert_cross_underlying_<U>(other.load()));
148+
store(convert_underlying_<value_type>(other.load()));
139149
return *this;
140150
}
141151

@@ -155,7 +165,9 @@ public:
155165
return access_handler_t::load(value_);
156166
}
157167

158-
constexpr auto store(value_type desired) noexcept -> void {
168+
template <underlying_type U>
169+
requires std::same_as<U, value_type>
170+
constexpr auto store(U desired) noexcept -> void {
159171
if consteval {
160172
value_ = desired;
161173
} else {
@@ -164,8 +176,16 @@ public:
164176
}
165177
}
166178

167-
constexpr auto compare_exchange(value_type &expected,
168-
value_type desired) noexcept -> bool {
179+
template <underlying_type U>
180+
requires(!std::same_as<U, value_type> &&
181+
cross_underlying_constructible_v<U>)
182+
constexpr auto store(U desired) noexcept -> void {
183+
store(convert_underlying_<value_type>(desired));
184+
}
185+
186+
template <underlying_type U>
187+
requires std::same_as<U, value_type>
188+
constexpr auto compare_exchange(U &expected, U desired) noexcept -> bool {
169189
if consteval {
170190
if (value_ != expected) {
171191
expected = value_;
@@ -179,6 +199,19 @@ public:
179199
return access_handler_t::compare_exchange(value_, expected, desired);
180200
}
181201

202+
template <underlying_type U>
203+
requires(!std::same_as<U, value_type> && cross_underlying_exchangeable_v<U>)
204+
constexpr auto compare_exchange(U &expected, U desired) noexcept -> bool {
205+
auto expected_native = convert_underlying_<value_type>(expected);
206+
auto const desired_native = convert_underlying_<value_type>(desired);
207+
208+
auto const exchanged = compare_exchange(expected_native, desired_native);
209+
if (!exchanged) {
210+
expected = convert_underlying_<U>(expected_native);
211+
}
212+
return exchanged;
213+
}
214+
182215
private:
183216
using concurrency_policy_t = policy::resolve_policy_t<
184217
policy::category::concurrency, Policies...>;

0 commit comments

Comments
 (0)