@@ -18,6 +18,18 @@ concept constructible_from_underlying =
1818 Primitive{u};
1919};
2020
21+ template <typename Primitive, typename U>
22+ concept storable_from_underlying =
23+ underlying_type<U> && requires (Primitive p, U u) {
24+ p.store (u);
25+ };
26+
27+ template <typename Primitive, typename U>
28+ concept cas_from_underlying =
29+ underlying_type<U> && requires (Primitive p, U expected, U desired) {
30+ { p.compare_exchange (expected, desired) } -> std::same_as<bool >;
31+ };
32+
2133TEST (OperationsTest, AddReturnsExpectedPrimitive) {
2234 using lhs_t = primitive<int , policy::value::checked>;
2335 using rhs_t = primitive<int , policy::value::checked>;
@@ -384,6 +396,55 @@ TEST(OperationsTest, TransparentTypePrimitiveConstructorAllowsCrossCategory) {
384396 EXPECT_EQ (value.load (), 42 );
385397}
386398
399+ TEST (OperationsTest, PrimitiveStoreAndCasRejectCrossUnderlyingWithStrictType) {
400+ using strict_t = primitive<int , policy::type::strict, policy::error::expected>;
401+
402+ static_assert (!storable_from_underlying<strict_t , short >);
403+ static_assert (!cas_from_underlying<strict_t , short >);
404+ }
405+
406+ TEST (OperationsTest, PrimitiveStoreAndCasAllowCompatibleSameCategory) {
407+ using compatible_t =
408+ primitive<int , policy::type::compatible, policy::error::expected>;
409+
410+ static_assert (storable_from_underlying<compatible_t , short >);
411+ static_assert (cas_from_underlying<compatible_t , short >);
412+ static_assert (!storable_from_underlying<compatible_t , double >);
413+ static_assert (!cas_from_underlying<compatible_t , double >);
414+
415+ auto value = compatible_t {10 };
416+ value.store (static_cast <short >(12 ));
417+ EXPECT_EQ (value.load (), 12 );
418+
419+ short expected = 12 ;
420+ EXPECT_TRUE (value.compare_exchange (expected, static_cast <short >(20 )));
421+ EXPECT_EQ (value.load (), 20 );
422+
423+ expected = 11 ;
424+ EXPECT_FALSE (value.compare_exchange (expected, static_cast <short >(30 )));
425+ EXPECT_EQ (expected, 20 );
426+ }
427+
428+ TEST (OperationsTest, PrimitiveStoreAndCasAllowTransparentCrossCategory) {
429+ using transparent_t =
430+ primitive<int , policy::type::transparent, policy::error::expected>;
431+
432+ static_assert (storable_from_underlying<transparent_t , double >);
433+ static_assert (cas_from_underlying<transparent_t , double >);
434+
435+ auto value = transparent_t {10 };
436+ value.store (42.75 );
437+ EXPECT_EQ (value.load (), 42 );
438+
439+ double expected = 42.0 ;
440+ EXPECT_TRUE (value.compare_exchange (expected, 99.5 ));
441+ EXPECT_EQ (value.load (), 99 );
442+
443+ expected = 3.0 ;
444+ EXPECT_FALSE (value.compare_exchange (expected, 1.0 ));
445+ EXPECT_EQ (expected, 99.0 );
446+ }
447+
387448TEST (OperationsTest, PrimitiveSpecialMembersSupportCrossUnderlyingWithCompatibleType) {
388449 using dst_t =
389450 primitive<int , policy::type::compatible, policy::error::expected>;
0 commit comments