AK: Add optional explicit cast to underlying type to DistinctNumeric

This commit is contained in:
Sam Atkins 2022-11-10 16:20:07 +00:00 committed by Ali Mohammad Pur
parent c33eae24f9
commit cf046dbfdb
Notes: sideshowbarker 2024-07-17 04:35:32 +09:00
2 changed files with 31 additions and 1 deletions

View file

@ -51,6 +51,7 @@ namespace AK {
namespace DistinctNumericFeature { namespace DistinctNumericFeature {
enum Arithmetic {}; enum Arithmetic {};
enum CastToBool {}; enum CastToBool {};
enum CastToUnderlying {};
enum Comparison {}; enum Comparison {};
enum Flags {}; enum Flags {};
enum Increment {}; enum Increment {};
@ -73,6 +74,7 @@ class DistinctNumeric {
constexpr void set(DistinctNumericFeature::Arithmetic const&) { arithmetic = true; } constexpr void set(DistinctNumericFeature::Arithmetic const&) { arithmetic = true; }
constexpr void set(DistinctNumericFeature::CastToBool const&) { cast_to_bool = true; } constexpr void set(DistinctNumericFeature::CastToBool const&) { cast_to_bool = true; }
constexpr void set(DistinctNumericFeature::CastToUnderlying const&) { cast_to_underlying = true; }
constexpr void set(DistinctNumericFeature::Comparison const&) { comparisons = true; } constexpr void set(DistinctNumericFeature::Comparison const&) { comparisons = true; }
constexpr void set(DistinctNumericFeature::Flags const&) { flags = true; } constexpr void set(DistinctNumericFeature::Flags const&) { flags = true; }
constexpr void set(DistinctNumericFeature::Increment const&) { increment = true; } constexpr void set(DistinctNumericFeature::Increment const&) { increment = true; }
@ -80,6 +82,7 @@ class DistinctNumeric {
bool arithmetic { false }; bool arithmetic { false };
bool cast_to_bool { false }; bool cast_to_bool { false };
bool cast_to_underlying { false };
bool comparisons { false }; bool comparisons { false };
bool flags { false }; bool flags { false };
bool increment { false }; bool increment { false };
@ -105,6 +108,13 @@ public:
return this->m_value == other.m_value; return this->m_value == other.m_value;
} }
// Only implemented when `CastToUnderlying` is true:
constexpr explicit operator T() const
{
static_assert(options.cast_to_underlying, "Cast to underlying type is only available for DistinctNumeric types with 'CastToUnderlying'.");
return value();
}
// Only implemented when `Increment` is true: // Only implemented when `Increment` is true:
constexpr Self& operator++() constexpr Self& operator++()
{ {
@ -316,6 +326,7 @@ struct Formatter<DistinctNumeric<T, X, Opts...>> : Formatter<T> {
struct NAME##_decl { \ struct NAME##_decl { \
using Arithmetic [[maybe_unused]] = AK::DistinctNumericFeature::Arithmetic; \ using Arithmetic [[maybe_unused]] = AK::DistinctNumericFeature::Arithmetic; \
using CastToBool [[maybe_unused]] = AK::DistinctNumericFeature::CastToBool; \ using CastToBool [[maybe_unused]] = AK::DistinctNumericFeature::CastToBool; \
using CastToUnderlying [[maybe_unused]] = AK::DistinctNumericFeature::CastToUnderlying; \
using Comparison [[maybe_unused]] = AK::DistinctNumericFeature::Comparison; \ using Comparison [[maybe_unused]] = AK::DistinctNumericFeature::Comparison; \
using Flags [[maybe_unused]] = AK::DistinctNumericFeature::Flags; \ using Flags [[maybe_unused]] = AK::DistinctNumericFeature::Flags; \
using Increment [[maybe_unused]] = AK::DistinctNumericFeature::Increment; \ using Increment [[maybe_unused]] = AK::DistinctNumericFeature::Increment; \

View file

@ -41,7 +41,8 @@ AK_TYPEDEF_DISTINCT_NUMERIC_GENERAL(int, BoolNumeric, CastToBool);
AK_TYPEDEF_DISTINCT_NUMERIC_GENERAL(int, FlagsNumeric, Flags); AK_TYPEDEF_DISTINCT_NUMERIC_GENERAL(int, FlagsNumeric, Flags);
AK_TYPEDEF_DISTINCT_NUMERIC_GENERAL(int, ShiftNumeric, Shift); AK_TYPEDEF_DISTINCT_NUMERIC_GENERAL(int, ShiftNumeric, Shift);
AK_TYPEDEF_DISTINCT_NUMERIC_GENERAL(int, ArithNumeric, Arithmetic); AK_TYPEDEF_DISTINCT_NUMERIC_GENERAL(int, ArithNumeric, Arithmetic);
AK_TYPEDEF_DISTINCT_NUMERIC_GENERAL(int, GeneralNumeric, Arithmetic, CastToBool, Comparison, Flags, Increment, Shift); AK_TYPEDEF_DISTINCT_NUMERIC_GENERAL(int, UnderlyingNumeric, CastToUnderlying);
AK_TYPEDEF_DISTINCT_NUMERIC_GENERAL(int, GeneralNumeric, Arithmetic, CastToBool, CastToUnderlying, Comparison, Flags, Increment, Shift);
TEST_CASE(address_identity) TEST_CASE(address_identity)
{ {
@ -105,6 +106,14 @@ TEST_CASE(operator_bool)
EXPECT_EQ(!c, false); EXPECT_EQ(!c, false);
} }
TEST_CASE(operator_underlying)
{
UnderlyingNumeric a = 0;
UnderlyingNumeric b = 42;
EXPECT_EQ(static_cast<int>(a), 0);
EXPECT_EQ(static_cast<int>(b), 42);
}
TEST_CASE(operator_flags) TEST_CASE(operator_flags)
{ {
FlagsNumeric a = 0; FlagsNumeric a = 0;
@ -216,6 +225,9 @@ TEST_CASE(composability)
EXPECT_EQ(-b, GeneralNumeric(-1)); EXPECT_EQ(-b, GeneralNumeric(-1));
EXPECT_EQ(a + b, b); EXPECT_EQ(a + b, b);
EXPECT_EQ(b * GeneralNumeric(42), GeneralNumeric(42)); EXPECT_EQ(b * GeneralNumeric(42), GeneralNumeric(42));
// Underlying
EXPECT_EQ(static_cast<int>(a), 0);
EXPECT_EQ(static_cast<int>(b), 1);
} }
/* /*
@ -268,6 +280,13 @@ TEST_CASE(negative_arith)
// error: static assertion failed: 'a+b' is only available for DistinctNumeric types with 'Arithmetic'. // error: static assertion failed: 'a+b' is only available for DistinctNumeric types with 'Arithmetic'.
} }
TEST_CASE(negative_underlying)
{
BareNumeric a = 12;
[[maybe_unused]] int res = static_cast<int>(a);
// error: static assertion failed: Cast to underlying type is only available for DistinctNumeric types with 'CastToUnderlying'.
}
TEST_CASE(negative_incompatible) TEST_CASE(negative_incompatible)
{ {
GeneralNumeric a = 12; GeneralNumeric a = 12;