From cf046dbfdb766d0ceb6df530171af92cd407f1e7 Mon Sep 17 00:00:00 2001 From: Sam Atkins Date: Thu, 10 Nov 2022 16:20:07 +0000 Subject: [PATCH] AK: Add optional explicit cast to underlying type to DistinctNumeric --- AK/DistinctNumeric.h | 11 +++++++++++ Tests/AK/TestDistinctNumeric.cpp | 21 ++++++++++++++++++++- 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/AK/DistinctNumeric.h b/AK/DistinctNumeric.h index 13ae37d5b56..934d6ae4320 100644 --- a/AK/DistinctNumeric.h +++ b/AK/DistinctNumeric.h @@ -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> : Formatter { 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; \ diff --git a/Tests/AK/TestDistinctNumeric.cpp b/Tests/AK/TestDistinctNumeric.cpp index a00c286b700..e8b398b7402 100644 --- a/Tests/AK/TestDistinctNumeric.cpp +++ b/Tests/AK/TestDistinctNumeric.cpp @@ -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(a), 0); + EXPECT_EQ(static_cast(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(a), 0); + EXPECT_EQ(static_cast(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(a); + // error: static assertion failed: Cast to underlying type is only available for DistinctNumeric types with 'CastToUnderlying'. +} + TEST_CASE(negative_incompatible) { GeneralNumeric a = 12;