@@ -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
5969public:
@@ -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+
182215private:
183216 using concurrency_policy_t = policy::resolve_policy_t <
184217 policy::category::concurrency, Policies...>;
0 commit comments