From 0e6336a6644aa54fb6ee511ccd4a889982874c1a Mon Sep 17 00:00:00 2001 From: Alexander Karatarakis Date: Sat, 14 Sep 2024 16:02:24 -0700 Subject: [PATCH] variant<> contains the individual variants --- test/enum_utils_test.cpp | 128 +++++++++++++++------------------------ 1 file changed, 48 insertions(+), 80 deletions(-) diff --git a/test/enum_utils_test.cpp b/test/enum_utils_test.cpp index e021b8d7..62baec80 100644 --- a/test/enum_utils_test.cpp +++ b/test/enum_utils_test.cpp @@ -160,10 +160,29 @@ enum class ColorVariantAll }; template -class ColorVariant +class ColorVariant; + +// This rich enum specialization is not strictly needed, but it gets us: +// - Optional semantics +// - Ability to reference to variants with the original color via ColorVariant +// This is show-cased with RED, whereas BLUE uses a normal enum. +template <> +class ColorVariant + : public SkeletalRichEnum, ColorVariantRed> +{ + friend SkeletalRichEnum::ValuesFriend; + using SkeletalRichEnum::SkeletalRichEnum; + +public: + FIXED_CONTAINERS_RICH_ENUM_CONSTANT_GEN_HELPER(ColorVariant, PINK) + FIXED_CONTAINERS_RICH_ENUM_CONSTANT_GEN_HELPER(ColorVariant, ORANGE) +}; + +template <> +class ColorVariant { public: - using ColorStdVariant = std::variant; + using ColorStdVariant = std::variant, ColorVariantBlue>; private: ColorStdVariant variant_{}; @@ -180,6 +199,16 @@ class ColorVariant [[nodiscard]] const ColorStdVariant& as_std_variant() const { return variant_; } ColorStdVariant& as_std_variant() { return variant_; } + + template + constexpr OptionalReference to() + { + if (const U* valid_variant = std::get_if(&as_std_variant()); valid_variant != nullptr) + { + return OptionalReference{*valid_variant}; + } + return std::nullopt; + } }; enum class ColorBackingEnum @@ -200,8 +229,10 @@ struct ColorValues { using BE = ColorBackingEnum; static constexpr auto VALUES = EnumMap::create_with_all_entries({ - Pair{BE::RED_PINK, {ColorBase::RED(), ColorVariantRed::PINK}}, - Pair{BE::RED_ORANGE, ColorData{ColorBase::RED(), ColorVariantRed::ORANGE}}, + Pair{BE::RED_PINK, + {ColorBase::RED(), ColorVariant::PINK()}}, + Pair{BE::RED_ORANGE, + ColorData{ColorBase::RED(), ColorVariant::ORANGE()}}, Pair{BE::BLUE_CYAN, ColorData{ColorBase::BLUE(), ColorVariantBlue::CYAN}}, Pair{BE::BLUE_AZURE, ColorData{ColorBase::BLUE(), ColorVariantBlue::AZURE}}, }); @@ -284,68 +315,6 @@ static_assert(ALL_RED_VARIANTS.size() == 2); static_assert(ALL_RED_VARIANTS.contains(Color::RED_ORANGE())); static_assert(ALL_RED_VARIANTS.contains(Color::RED_PINK())); -template <> -class ColorVariant - : public SkeletalRichEnum, ColorVariantRed> -{ - friend SkeletalRichEnum::ValuesFriend; - using SkeletalRichEnum::SkeletalRichEnum; - -public: - FIXED_CONTAINERS_RICH_ENUM_CONSTANT_GEN_HELPER(ColorVariant, PINK) - FIXED_CONTAINERS_RICH_ENUM_CONSTANT_GEN_HELPER(ColorVariant, ORANGE) - - static constexpr OptionalReference> from( - const ColorVariant<>& flat_variant) - { - if (const ColorVariantRed* valid_variant = - std::get_if(&flat_variant.as_std_variant()); - valid_variant != nullptr) - { - switch (std::get(flat_variant.as_std_variant())) - { - case ColorVariantRed::PINK: - return OptionalReference{PINK()}; - case ColorVariantRed::ORANGE: - return OptionalReference{ORANGE()}; - } - } - - return std::nullopt; - } -}; - -template <> -class ColorVariant - : public SkeletalRichEnum, ColorVariantBlue> -{ - friend SkeletalRichEnum::ValuesFriend; - using SkeletalRichEnum::SkeletalRichEnum; - -public: - FIXED_CONTAINERS_RICH_ENUM_CONSTANT_GEN_HELPER(ColorVariant, CYAN) - FIXED_CONTAINERS_RICH_ENUM_CONSTANT_GEN_HELPER(ColorVariant, AZURE) - - static constexpr OptionalReference> from( - const ColorVariant<>& flat_variant) - { - if (const ColorVariantBlue* valid_variant = - std::get_if(&flat_variant.as_std_variant()); - valid_variant != nullptr) - { - switch (std::get(flat_variant.as_std_variant())) - { - case ColorVariantBlue::CYAN: - return OptionalReference{CYAN()}; - case ColorVariantBlue::AZURE: - return OptionalReference{AZURE()}; - } - } - - return std::nullopt; - } -}; - namespace { void flat_switch(const Color& color) @@ -370,14 +339,14 @@ void flat_switch(const Color& color) void automatic_hierarchical_switch(const Color& color) { color.variant_switch( - [](const ColorVariantRed& variant) + [](const ColorVariant& variant) { switch (variant) { - case ColorVariantRed::PINK: + case ColorVariant::PINK(): std::cout << "RED:PINK2" << std::endl; break; - case ColorVariantRed::ORANGE: + case ColorVariant::ORANGE(): std::cout << "RED:ORANGE2" << std::endl; break; } @@ -389,7 +358,7 @@ void automatic_hierarchical_switch(const Color& color) case ColorVariantBlue::CYAN: std::cout << "BLUE:CYAN2" << std::endl; break; - case ColorVariant::AZURE(): + case ColorVariantBlue::AZURE: std::cout << "BLUE:AZURE2" << std::endl; break; } @@ -401,14 +370,14 @@ void std_visit_with_if_constexpr(const Color& color) std::visit( [](const T& variant) { - if constexpr (std::same_as) + if constexpr (std::same_as>) { switch (variant) { - case ColorVariantRed::PINK: + case ColorVariant::PINK(): std::cout << "RED:PINK3" << std::endl; break; - case ColorVariantRed::ORANGE: + case ColorVariant::ORANGE(): std::cout << "RED:ORANGE3" << std::endl; break; } @@ -420,7 +389,7 @@ void std_visit_with_if_constexpr(const Color& color) case ColorVariantBlue::CYAN: std::cout << "BLUE:CYAN3" << std::endl; break; - case ColorVariant::AZURE(): + case ColorVariantBlue::AZURE: std::cout << "BLUE:AZURE3" << std::endl; break; } @@ -445,7 +414,7 @@ void manual_hierarchical_switch(const Color& color) { // It is possible to have the wrong color here since the user is responsible for the nested // switch - switch (ColorVariant::from(color.color_variant()).value()) + switch (color.color_variant().to>().value()) { case ColorVariant::PINK(): std::cout << "RED:PINK1" << std::endl; @@ -458,12 +427,12 @@ void manual_hierarchical_switch(const Color& color) } case ColorBase::BLUE(): { - switch (ColorVariant::from(color.color_variant()).value()) + switch (color.color_variant().to().value()) { - case ColorVariant::CYAN(): + case ColorVariantBlue::CYAN: std::cout << "BLUE:CYAN1" << std::endl; break; - case ColorVariant::AZURE(): + case ColorVariantBlue::AZURE: std::cout << "BLUE:AZURE1" << std::endl; break; } @@ -475,8 +444,7 @@ void manual_hierarchical_switch(const Color& color) TEST(NestedEnums, Example) { - const Color color = - Color::from(ColorBase::BLUE(), ColorVariant::AZURE()).value(); + const Color color = Color::from(ColorBase::BLUE(), ColorVariantBlue::AZURE).value(); flat_switch(color); automatic_hierarchical_switch(color); std_visit_with_if_constexpr(color);