Skip to content

Commit e7948f3

Browse files
Merge pull request #10 from mcpplibs/refactor-concurrency-policy-enhanced
Enhance concurrency handling and improve documentation
2 parents 8a014af + b0fa0fd commit e7948f3

File tree

8 files changed

+292
-45
lines changed

8 files changed

+292
-45
lines changed

.github/workflows/ci.yml

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -57,27 +57,31 @@ jobs:
5757

5858
build-macos:
5959
runs-on: macos-15
60-
timeout-minutes: 20
60+
timeout-minutes: 25
6161
steps:
6262
- name: Checkout
6363
uses: actions/checkout@v4
6464

65-
- name: Install Xlings
66-
env:
67-
XLINGS_NON_INTERACTIVE: 1
68-
run: |
69-
curl -fsSL https://raw.githubusercontent.com/d2learn/xlings/refs/heads/main/tools/other/quick_install.sh | bash -s -- $XLINGS_VERSION
70-
echo "PATH=$HOME/.xlings/subos/current/bin:$PATH" >> "$GITHUB_ENV"
65+
- name: Setup xmake
66+
uses: xmake-io/github-action-setup-xmake@v1
67+
with:
68+
xmake-version: latest
69+
package-cache: true
70+
71+
- name: Install LLVM 20
72+
run: brew install llvm@20
7173

72-
- name: Install Project Dependencies via Xlings
74+
- name: Verify toolchain
7375
run: |
74-
xlings install
76+
xmake --version
77+
/opt/homebrew/opt/llvm@20/bin/clang++ --version
7578
clang --version
7679
7780
- name: Build with xmake
7881
run: |
79-
xmake f -m release --toolchain=llvm -vv -y
80-
xmake -j$(nproc)
82+
export PATH=/opt/homebrew/opt/llvm@20/bin:$PATH
83+
xmake f -p macosx -m release --toolchain=llvm --sdk=/opt/homebrew/opt/llvm@20 -y -vv
84+
xmake -y -vv -j$(sysctl -n hw.ncpu)
8185
8286
build-windows:
8387
runs-on: windows-latest

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
.xmake
33
build/
44
build-*/
5+
out/
56

67
# xlings
78
.xlings
@@ -50,4 +51,4 @@ Makefile
5051

5152
# IDE
5253
/.idea
53-
/.cache
54+
/.cache

examples/ex07_custom_policy.cpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,34 @@ struct mcpplibs::primitives::policy::concurrency::handler<
8787
}
8888
};
8989

90+
template <typename CommonRep, typename ErrorPayload>
91+
struct mcpplibs::primitives::policy::concurrency::handler<
92+
demo::custom_concurrency, void, CommonRep, ErrorPayload> {
93+
static constexpr bool enabled = true;
94+
using injection_type = mcpplibs::primitives::policy::concurrency::injection;
95+
using result_type = std::expected<CommonRep, ErrorPayload>;
96+
97+
static constexpr auto load(CommonRep const &value) noexcept -> CommonRep {
98+
return value;
99+
}
100+
101+
static constexpr auto store(CommonRep &value, CommonRep desired) noexcept
102+
-> void {
103+
value = desired;
104+
}
105+
106+
static constexpr auto compare_exchange(CommonRep &value, CommonRep &expected,
107+
CommonRep desired) noexcept -> bool {
108+
if (value != expected) {
109+
expected = value;
110+
return false;
111+
}
112+
113+
value = desired;
114+
return true;
115+
}
116+
};
117+
90118
// Point 7 / Step 3C: Implement custom value handler.
91119
// Complex point: finalize() post-processes decision and adjusts output.
92120
template <operations::operation OpTag, typename CommonRep,

src/operations/dispatcher.cppm

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,9 +123,9 @@ constexpr auto dispatch(Lhs const &lhs, Rhs const &rhs)
123123

124124
// Runtime stage 2: value path.
125125
auto const lhs_rep_raw =
126-
underlying::traits<typename meta::lhs_value_type>::to_rep(lhs.value());
126+
underlying::traits<typename meta::lhs_value_type>::to_rep(lhs.load());
127127
auto const rhs_rep_raw =
128-
underlying::traits<typename meta::rhs_value_type>::to_rep(rhs.value());
128+
underlying::traits<typename meta::rhs_value_type>::to_rep(rhs.load());
129129

130130
if (!underlying::traits<typename meta::lhs_value_type>::is_valid_rep(
131131
lhs_rep_raw) ||

src/policy/impl.cppm

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,20 @@ template <typename T> constexpr void assert_atomic_ref_compatible() {
158158
"satisfy std::atomic_ref<CommonRep>::required_alignment");
159159
}
160160

161+
template <typename T>
162+
concept has_underlying_rep_not_equal =
163+
underlying_type<T> &&
164+
requires(T const &lhs, T const &rhs) {
165+
{
166+
underlying::traits<std::remove_cv_t<T>>::to_rep(lhs) !=
167+
underlying::traits<std::remove_cv_t<T>>::to_rep(rhs)
168+
} -> std::convertible_to<bool>;
169+
};
170+
171+
template <typename T>
172+
inline constexpr bool none_compare_exchange_available_v =
173+
has_underlying_rep_not_equal<T>;
174+
161175
template <typename OpTag>
162176
inline constexpr bool is_arithmetic_operation_v =
163177
operations::op_has_capability_v<OpTag, operations::capability::arithmetic>;
@@ -239,6 +253,35 @@ struct concurrency::handler<concurrency::none, OpTag, CommonRep, ErrorPayload> {
239253
}
240254
};
241255

256+
template <typename CommonRep, typename ErrorPayload>
257+
struct concurrency::handler<concurrency::none, void, CommonRep, ErrorPayload> {
258+
static constexpr bool enabled = true;
259+
using injection_type = concurrency::injection;
260+
using result_type = std::expected<CommonRep, ErrorPayload>;
261+
262+
static constexpr auto load(CommonRep const &value) noexcept -> CommonRep {
263+
return value;
264+
}
265+
266+
static constexpr auto store(CommonRep &value, CommonRep desired) noexcept
267+
-> void {
268+
value = desired;
269+
}
270+
271+
static constexpr auto compare_exchange(CommonRep &value, CommonRep &expected,
272+
CommonRep desired) noexcept -> bool
273+
requires(details::none_compare_exchange_available_v<CommonRep>) {
274+
using traits_type = underlying::traits<std::remove_cv_t<CommonRep>>;
275+
if (traits_type::to_rep(value) != traits_type::to_rep(expected)) {
276+
expected = value;
277+
return false;
278+
}
279+
280+
value = desired;
281+
return true;
282+
}
283+
};
284+
242285
template <operations::operation OpTag, typename CommonRep,
243286
typename ErrorPayload>
244287
struct concurrency::handler<concurrency::fenced, OpTag, CommonRep,

src/primitive/impl.cppm

Lines changed: 79 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,7 @@ struct resolve_concurrency_policy<First, Rest...> {
4343
};
4444

4545
template <policy::policy_type... Policies>
46-
using resolve_concurrency_policy_t =
47-
typename resolve_concurrency_policy<Policies...>::type;
46+
using resolve_concurrency_policy_t = resolve_concurrency_policy<Policies...>::type;
4847

4948
} // namespace details
5049

@@ -58,50 +57,102 @@ public:
5857
"Multiple concurrency policies are not allowed");
5958

6059
constexpr explicit primitive(value_type v) noexcept : value_(v) {}
60+
61+
constexpr primitive(primitive const &other) noexcept {
62+
if consteval {
63+
value_ = other.value_;
64+
} else {
65+
value_ = other.load();
66+
}
67+
}
68+
69+
constexpr auto operator=(primitive const &other) noexcept -> primitive & {
70+
if (this == &other) {
71+
return *this;
72+
}
73+
74+
if consteval {
75+
value_ = other.value_;
76+
} else {
77+
store(other.load());
78+
}
79+
return *this;
80+
}
81+
82+
constexpr primitive(primitive &&other) noexcept {
83+
if consteval {
84+
value_ = other.value_;
85+
} else {
86+
value_ = other.load();
87+
}
88+
}
89+
90+
constexpr auto operator=(primitive &&other) noexcept -> primitive & {
91+
if (this == &other) {
92+
return *this;
93+
}
94+
95+
if consteval {
96+
value_ = other.value_;
97+
} else {
98+
store(other.load());
99+
}
100+
return *this;
101+
}
102+
61103
constexpr value_type &value() noexcept { return value_; }
104+
62105
[[nodiscard]] constexpr value_type const &value() const noexcept {
63106
return value_;
64107
}
108+
65109
constexpr explicit operator value_type() const noexcept { return value_; }
66110

67-
[[nodiscard]] auto load() const noexcept -> value_type {
68-
using access_handler_t =
69-
policy::concurrency::handler<concurrency_policy, void, value_type,
70-
policy::error::kind>;
71-
static_assert(
72-
policy::concurrency::handler_access_available<concurrency_policy,
73-
value_type>,
74-
"Selected concurrency policy does not provide primitive "
75-
"load/store/CAS support");
111+
[[nodiscard]] constexpr auto load() const noexcept -> value_type {
112+
if consteval {
113+
return value_;
114+
}
115+
require_access_handler_();
76116
return access_handler_t::load(value_);
77117
}
78118

79-
auto store(value_type desired) noexcept -> void {
80-
using access_handler_t =
81-
policy::concurrency::handler<concurrency_policy, void, value_type,
82-
policy::error::kind>;
83-
static_assert(
84-
policy::concurrency::handler_access_available<concurrency_policy,
85-
value_type>,
86-
"Selected concurrency policy does not provide primitive "
87-
"load/store/CAS support");
88-
access_handler_t::store(value_, desired);
119+
constexpr auto store(value_type desired) noexcept -> void {
120+
if consteval {
121+
value_ = desired;
122+
} else {
123+
require_access_handler_();
124+
access_handler_t::store(value_, desired);
125+
}
89126
}
90127

91-
auto compare_exchange(value_type &expected, value_type desired) noexcept
92-
-> bool {
93-
using access_handler_t =
94-
policy::concurrency::handler<concurrency_policy, void, value_type,
95-
policy::error::kind>;
128+
constexpr auto compare_exchange(value_type &expected,
129+
value_type desired) noexcept -> bool {
130+
if consteval {
131+
if (value_ != expected) {
132+
expected = value_;
133+
return false;
134+
}
135+
136+
value_ = desired;
137+
return true;
138+
}
139+
require_access_handler_();
140+
return access_handler_t::compare_exchange(value_, expected, desired);
141+
}
142+
143+
private:
144+
using access_handler_t =
145+
policy::concurrency::handler<concurrency_policy, void, value_type,
146+
policy::error::kind>;
147+
148+
static constexpr auto require_access_handler_() noexcept -> void {
96149
static_assert(
97150
policy::concurrency::handler_access_available<concurrency_policy,
98151
value_type>,
99152
"Selected concurrency policy does not provide primitive "
100153
"load/store/CAS support");
101-
return access_handler_t::compare_exchange(value_, expected, desired);
102154
}
103155

104-
private:
105156
value_type value_;
106157
};
107158

0 commit comments

Comments
 (0)