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
2 changed files with 31 additions and 1 deletions

View file

@ -51,6 +51,7 @@ namespace AK {
namespace DistinctNumericFeature {
enum Arithmetic {};
enum CastToBool {};
enum CastToUnderlying {};
enum Comparison {};
enum Flags {};
enum Increment {};
@ -73,6 +74,7 @@ class DistinctNumeric {
constexpr void set(DistinctNumericFeature::Arithmetic const&) { arithmetic = 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::Flags const&) { flags = true; }
constexpr void set(DistinctNumericFeature::Increment const&) { increment = true; }
@ -80,6 +82,7 @@ class DistinctNumeric {
bool arithmetic { false };
bool cast_to_bool { false };
bool cast_to_underlying { false };
bool comparisons { false };
bool flags { false };
bool increment { false };
@ -105,6 +108,13 @@ public:
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:
constexpr Self& operator++()
{
@ -316,6 +326,7 @@ struct Formatter<DistinctNumeric<T, X, Opts...>> : Formatter<T> {
struct NAME##_decl { \
using Arithmetic [[maybe_unused]] = AK::DistinctNumericFeature::Arithmetic; \
using CastToBool [[maybe_unused]] = AK::DistinctNumericFeature::CastToBool; \
using CastToUnderlying [[maybe_unused]] = AK::DistinctNumericFeature::CastToUnderlying; \
using Comparison [[maybe_unused]] = AK::DistinctNumericFeature::Comparison; \
using Flags [[maybe_unused]] = AK::DistinctNumericFeature::Flags; \
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, ShiftNumeric, Shift);
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)
{
@ -105,6 +106,14 @@ TEST_CASE(operator_bool)
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)
{
FlagsNumeric a = 0;
@ -216,6 +225,9 @@ TEST_CASE(composability)
EXPECT_EQ(-b, GeneralNumeric(-1));
EXPECT_EQ(a + b, b);
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'.
}
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)
{
GeneralNumeric a = 12;