Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 15 additions & 11 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -57,27 +57,31 @@ jobs:

build-macos:
runs-on: macos-15
timeout-minutes: 20
timeout-minutes: 25
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Install Xlings
env:
XLINGS_NON_INTERACTIVE: 1
run: |
curl -fsSL https://raw.githubusercontent.com/d2learn/xlings/refs/heads/main/tools/other/quick_install.sh | bash -s -- $XLINGS_VERSION
echo "PATH=$HOME/.xlings/subos/current/bin:$PATH" >> "$GITHUB_ENV"
- name: Setup xmake
uses: xmake-io/github-action-setup-xmake@v1
with:
xmake-version: latest
package-cache: true

- name: Install LLVM 20
run: brew install llvm@20

- name: Install Project Dependencies via Xlings
- name: Verify toolchain
run: |
xlings install
xmake --version
/opt/homebrew/opt/llvm@20/bin/clang++ --version
clang --version

- name: Build with xmake
run: |
xmake f -m release --toolchain=llvm -vv -y
xmake -j$(nproc)
export PATH=/opt/homebrew/opt/llvm@20/bin:$PATH
xmake f -p macosx -m release --toolchain=llvm --sdk=/opt/homebrew/opt/llvm@20 -y -vv
xmake -y -vv -j$(sysctl -n hw.ncpu)

build-windows:
runs-on: windows-latest
Expand Down
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
.xmake
build/
build-*/
out/

# xlings
.xlings
Expand Down Expand Up @@ -50,4 +51,4 @@ Makefile

# IDE
/.idea
/.cache
/.cache
28 changes: 28 additions & 0 deletions examples/ex07_custom_policy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,34 @@ struct mcpplibs::primitives::policy::concurrency::handler<
}
};

template <typename CommonRep, typename ErrorPayload>
struct mcpplibs::primitives::policy::concurrency::handler<
demo::custom_concurrency, void, CommonRep, ErrorPayload> {
static constexpr bool enabled = true;
using injection_type = mcpplibs::primitives::policy::concurrency::injection;
using result_type = std::expected<CommonRep, ErrorPayload>;

static constexpr auto load(CommonRep const &value) noexcept -> CommonRep {
return value;
}

static constexpr auto store(CommonRep &value, CommonRep desired) noexcept
-> void {
value = desired;
}

static constexpr auto compare_exchange(CommonRep &value, CommonRep &expected,
CommonRep desired) noexcept -> bool {
if (value != expected) {
expected = value;
return false;
}

value = desired;
return true;
}
};

// Point 7 / Step 3C: Implement custom value handler.
// Complex point: finalize() post-processes decision and adjusts output.
template <operations::operation OpTag, typename CommonRep,
Expand Down
4 changes: 2 additions & 2 deletions src/operations/dispatcher.cppm
Original file line number Diff line number Diff line change
Expand Up @@ -123,9 +123,9 @@ constexpr auto dispatch(Lhs const &lhs, Rhs const &rhs)

// Runtime stage 2: value path.
auto const lhs_rep_raw =
underlying::traits<typename meta::lhs_value_type>::to_rep(lhs.value());
underlying::traits<typename meta::lhs_value_type>::to_rep(lhs.load());
auto const rhs_rep_raw =
underlying::traits<typename meta::rhs_value_type>::to_rep(rhs.value());
underlying::traits<typename meta::rhs_value_type>::to_rep(rhs.load());

if (!underlying::traits<typename meta::lhs_value_type>::is_valid_rep(
lhs_rep_raw) ||
Expand Down
43 changes: 43 additions & 0 deletions src/policy/impl.cppm
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,20 @@ template <typename T> constexpr void assert_atomic_ref_compatible() {
"satisfy std::atomic_ref<CommonRep>::required_alignment");
}

template <typename T>
concept has_underlying_rep_not_equal =
underlying_type<T> &&
requires(T const &lhs, T const &rhs) {
{
underlying::traits<std::remove_cv_t<T>>::to_rep(lhs) !=
underlying::traits<std::remove_cv_t<T>>::to_rep(rhs)
} -> std::convertible_to<bool>;
};

template <typename T>
inline constexpr bool none_compare_exchange_available_v =
has_underlying_rep_not_equal<T>;

template <typename OpTag>
inline constexpr bool is_arithmetic_operation_v =
operations::op_has_capability_v<OpTag, operations::capability::arithmetic>;
Expand Down Expand Up @@ -239,6 +253,35 @@ struct concurrency::handler<concurrency::none, OpTag, CommonRep, ErrorPayload> {
}
};

template <typename CommonRep, typename ErrorPayload>
struct concurrency::handler<concurrency::none, void, CommonRep, ErrorPayload> {
static constexpr bool enabled = true;
using injection_type = concurrency::injection;
using result_type = std::expected<CommonRep, ErrorPayload>;

static constexpr auto load(CommonRep const &value) noexcept -> CommonRep {
return value;
}

static constexpr auto store(CommonRep &value, CommonRep desired) noexcept
-> void {
value = desired;
}

static constexpr auto compare_exchange(CommonRep &value, CommonRep &expected,
CommonRep desired) noexcept -> bool
requires(details::none_compare_exchange_available_v<CommonRep>) {
using traits_type = underlying::traits<std::remove_cv_t<CommonRep>>;
if (traits_type::to_rep(value) != traits_type::to_rep(expected)) {
expected = value;
return false;
}

value = desired;
return true;
}
};

template <operations::operation OpTag, typename CommonRep,
typename ErrorPayload>
struct concurrency::handler<concurrency::fenced, OpTag, CommonRep,
Expand Down
107 changes: 79 additions & 28 deletions src/primitive/impl.cppm
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,7 @@ struct resolve_concurrency_policy<First, Rest...> {
};

template <policy::policy_type... Policies>
using resolve_concurrency_policy_t =
typename resolve_concurrency_policy<Policies...>::type;
using resolve_concurrency_policy_t = resolve_concurrency_policy<Policies...>::type;

} // namespace details

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

constexpr explicit primitive(value_type v) noexcept : value_(v) {}

constexpr primitive(primitive const &other) noexcept {
if consteval {
value_ = other.value_;
} else {
value_ = other.load();
}
}

constexpr auto operator=(primitive const &other) noexcept -> primitive & {
if (this == &other) {
return *this;
}

if consteval {
value_ = other.value_;
} else {
store(other.load());
}
return *this;
}

constexpr primitive(primitive &&other) noexcept {
if consteval {
value_ = other.value_;
} else {
value_ = other.load();
}
}

constexpr auto operator=(primitive &&other) noexcept -> primitive & {
if (this == &other) {
return *this;
}

if consteval {
value_ = other.value_;
} else {
store(other.load());
}
return *this;
}

constexpr value_type &value() noexcept { return value_; }

[[nodiscard]] constexpr value_type const &value() const noexcept {
return value_;
}

constexpr explicit operator value_type() const noexcept { return value_; }

[[nodiscard]] auto load() const noexcept -> value_type {
using access_handler_t =
policy::concurrency::handler<concurrency_policy, void, value_type,
policy::error::kind>;
static_assert(
policy::concurrency::handler_access_available<concurrency_policy,
value_type>,
"Selected concurrency policy does not provide primitive "
"load/store/CAS support");
[[nodiscard]] constexpr auto load() const noexcept -> value_type {
if consteval {
return value_;
}
require_access_handler_();
return access_handler_t::load(value_);
}

auto store(value_type desired) noexcept -> void {
using access_handler_t =
policy::concurrency::handler<concurrency_policy, void, value_type,
policy::error::kind>;
static_assert(
policy::concurrency::handler_access_available<concurrency_policy,
value_type>,
"Selected concurrency policy does not provide primitive "
"load/store/CAS support");
access_handler_t::store(value_, desired);
constexpr auto store(value_type desired) noexcept -> void {
if consteval {
value_ = desired;
} else {
require_access_handler_();
access_handler_t::store(value_, desired);
}
}

auto compare_exchange(value_type &expected, value_type desired) noexcept
-> bool {
using access_handler_t =
policy::concurrency::handler<concurrency_policy, void, value_type,
policy::error::kind>;
constexpr auto compare_exchange(value_type &expected,
value_type desired) noexcept -> bool {
if consteval {
if (value_ != expected) {
expected = value_;
return false;
}

value_ = desired;
return true;
}
require_access_handler_();
return access_handler_t::compare_exchange(value_, expected, desired);
}

private:
using access_handler_t =
policy::concurrency::handler<concurrency_policy, void, value_type,
policy::error::kind>;

static constexpr auto require_access_handler_() noexcept -> void {
static_assert(
policy::concurrency::handler_access_available<concurrency_policy,
value_type>,
"Selected concurrency policy does not provide primitive "
"load/store/CAS support");
return access_handler_t::compare_exchange(value_, expected, desired);
}

private:
value_type value_;
};

Expand Down
Loading
Loading