From 85168a69379302f136eb8d50bc258062622a3a99 Mon Sep 17 00:00:00 2001 From: Ben Deane Date: Thu, 20 Mar 2025 16:22:05 -0600 Subject: [PATCH 1/2] :white_check_mark: Add test for atomic type partial specialization Problem: - There is no test for partial specialization of atomic config. Solution: - Add a test for atomic pointers. --- test/atomic_override.cpp | 6 ++++++ test/detail/atomic_cfg.hpp | 5 ++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/test/atomic_override.cpp b/test/atomic_override.cpp index 5774661..8bbe588 100644 --- a/test/atomic_override.cpp +++ b/test/atomic_override.cpp @@ -24,3 +24,9 @@ TEST_CASE("atomic works with overridden type", "[atomic_override]") { CHECK(!bs.exchange(true)); CHECK(bs); } + +TEST_CASE("atomic config works with partial specialization", + "[atomic_override]") { + using elem_t = ::atomic::atomic_type_t; + static_assert(std::is_same_v); +} diff --git a/test/detail/atomic_cfg.hpp b/test/detail/atomic_cfg.hpp index 3ac9212..1eca94b 100644 --- a/test/detail/atomic_cfg.hpp +++ b/test/detail/atomic_cfg.hpp @@ -1,7 +1,6 @@ #pragma once #include -#include template <> struct atomic::atomic_type { using type = std::uint32_t; @@ -10,3 +9,7 @@ template <> struct atomic::atomic_type { template <> struct atomic::atomic_type { using type = std::uint32_t; }; + +template struct atomic::atomic_type { + using type = std::uintptr_t; +}; From bed2843eea345ef2d1677a48ef4889d097e2d470 Mon Sep 17 00:00:00 2001 From: Ben Deane Date: Thu, 20 Mar 2025 16:37:06 -0600 Subject: [PATCH 2/2] :bug: Make `stdx::atomic` work with scoped enumerations Problem: - Configuring `stdx::atomic` for scoped enumerations doesn't work because a scoped enumeration is not convertible to its configured underlying type. Solution: - Instead of requiring convertibility, require the types to be trivially copyable, and that the size & alignment is compatible. --- include/stdx/atomic.hpp | 18 ++++++++++++++---- test/atomic_override.cpp | 12 ++++++++++++ test/detail/atomic_cfg.hpp | 8 ++++++++ 3 files changed, 34 insertions(+), 4 deletions(-) diff --git a/include/stdx/atomic.hpp b/include/stdx/atomic.hpp index efc3ebb..48fa7e7 100644 --- a/include/stdx/atomic.hpp +++ b/include/stdx/atomic.hpp @@ -27,12 +27,22 @@ template class atomic { using elem_t = ::atomic::atomic_type_t; constexpr static auto alignment = ::atomic::alignment_of; - static_assert(std::is_convertible_v, + static_assert(std::is_trivially_copyable_v, + "value_type of atomic must be trivially_copyable"); + static_assert(std::is_trivially_copyable_v, "::atomic::atomic_type_t specialization result must be " - "convertible to T"); - static_assert(std::is_convertible_v, + "trivially_copyable"); + + static_assert(sizeof(elem_t) >= sizeof(T), + "::atomic::atomic_type_t specialization result must be at " + "least as big as T"); + static_assert(alignof(elem_t) >= alignof(T), + "::atomic::atomic_type_t specialization result must be " + "alignment-compatible with T"); + + static_assert(alignof(elem_t) <= alignment, "::atomic::atomic_type_t specialization result must be " - "convertible from T"); + "alignment-compatible with alignment_of"); alignas(alignment) elem_t value; diff --git a/test/atomic_override.cpp b/test/atomic_override.cpp index 8bbe588..ff14348 100644 --- a/test/atomic_override.cpp +++ b/test/atomic_override.cpp @@ -30,3 +30,15 @@ TEST_CASE("atomic config works with partial specialization", using elem_t = ::atomic::atomic_type_t; static_assert(std::is_same_v); } + +#if __cplusplus >= 202002L +namespace { +enum E : std::uint8_t {}; +} + +TEST_CASE("atomic config works with enum", "[atomic_override]") { + auto bs = stdx::atomic{}; + static_assert(sizeof(decltype(bs)) == sizeof(std::uint32_t)); + static_assert(alignof(decltype(bs)) == alignof(std::uint32_t)); +} +#endif diff --git a/test/detail/atomic_cfg.hpp b/test/detail/atomic_cfg.hpp index 1eca94b..e58f1fd 100644 --- a/test/detail/atomic_cfg.hpp +++ b/test/detail/atomic_cfg.hpp @@ -1,6 +1,7 @@ #pragma once #include +#include template <> struct atomic::atomic_type { using type = std::uint32_t; @@ -13,3 +14,10 @@ template <> struct atomic::atomic_type { template struct atomic::atomic_type { using type = std::uintptr_t; }; + +#if __cplusplus >= 202002L +template + requires(std::is_enum_v) +struct atomic::atomic_type : atomic::atomic_type> { +}; +#endif