From aa2446161395f1da13dc3864c8a9d2f73fda5a4f Mon Sep 17 00:00:00 2001 From: oficsu <35731382+oficsu@users.noreply.github.com> Date: Fri, 13 Mar 2020 12:12:01 +0300 Subject: [PATCH] Introduce contains_value() * split enum_traits index * add more proper way to check if enum contains certain value * change description of contains_value() and add it in readme --- README.md | 1 + include/magic_enum.hpp | 18 ++++++++++++++---- test/test.cpp | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 47 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 369d074..1b2e309 100644 --- a/README.md +++ b/README.md @@ -32,6 +32,7 @@ Header-only C++17 library provides static reflection for enums, work with any en * `enum_names` obtains string enum name sequence. * `enum_entries` obtains pair (value enum, string enum name) sequence. * `enum_index` obtains index in enum value sequence from enum value. +* `contains_value` checks whether enum contains such value * `is_unscoped_enum` checks whether type is an [Unscoped enumeration](https://en.cppreference.com/w/cpp/language/enum#Unscoped_enumeration). * `is_scoped_enum` checks whether type is an [Scoped enumeration](https://en.cppreference.com/w/cpp/language/enum#Scoped_enumerations). * `underlying_type` improved UB-free "SFINAE-friendly" [std::underlying_type](https://en.cppreference.com/w/cpp/types/underlying_type). diff --git a/include/magic_enum.hpp b/include/magic_enum.hpp index d4fc1a5..c67d058 100644 --- a/include/magic_enum.hpp +++ b/include/magic_enum.hpp @@ -359,20 +359,24 @@ struct enum_traits { return static_cast(value) >= static_cast(reflected_min_v) && static_cast(value) <= static_cast(reflected_max_v); } - [[nodiscard]] static constexpr int index(E value) noexcept { - if (static_cast(value) >= static_cast(min_v) && static_cast(value) <= static_cast(max_v)) { + [[nodiscard]] static constexpr int index(underlying_type value) noexcept { + if (value >= min_v && value <= max_v) { if constexpr (is_sparse) { - if (const auto i = indexes[static_cast(value) - min_v]; i != invalid_index_v) { + if (const auto i = indexes[value - min_v]; i != invalid_index_v) { return i; } } else { - return static_cast(value) - min_v; + return value - min_v; } } return -1; // Value out of range. } + [[nodiscard]] static constexpr int index(E value) noexcept { + return index(static_cast(value)); + } + [[nodiscard]] static constexpr E value(std::size_t index) noexcept { if constexpr (is_sparse) { return assert(index < count), values[index]; @@ -486,6 +490,12 @@ template return std::nullopt; // Value out of range. } +// Checks whether enum contains enumerator with such value +template +[[nodiscard]] constexpr auto contains_value(underlying_type_t value) noexcept -> detail::enable_if_enum_t { + return enum_traits::index(value) != -1; +} + // Returns enum value at specified index. // No bounds checking is performed: the behavior is undefined if index >= number of enum values. template diff --git a/test/test.cpp b/test/test.cpp index c885c55..3aa963b 100644 --- a/test/test.cpp +++ b/test/test.cpp @@ -176,6 +176,38 @@ TEST_CASE("enum_index") { REQUIRE_FALSE(enum_index(static_cast(0)).has_value()); } +TEST_CASE("contains_value") { + REQUIRE(contains_value(-12)); + REQUIRE(contains_value(7)); + REQUIRE(contains_value(15)); + REQUIRE_FALSE(contains_value(42)); + REQUIRE_FALSE(contains_value(-120)); + REQUIRE_FALSE(contains_value(0)); + + constexpr auto no = enum_integer(Numbers::one); + REQUIRE(contains_value(no)); + REQUIRE(contains_value(enum_integer(Numbers::two))); + REQUIRE(contains_value(enum_integer(Numbers::three))); + REQUIRE_FALSE(contains_value(enum_integer(Numbers::many))); + + constexpr auto dr = enum_integer(Directions::Right); + REQUIRE(contains_value(dr)); + REQUIRE(contains_value(Directions::Down)); + REQUIRE(contains_value(Directions::Up)); + REQUIRE_FALSE(contains_value(static_cast(0))); + + constexpr auto nt = contains_value(number::three); + REQUIRE(contains_value(number::one)); + REQUIRE(contains_value(100)); + REQUIRE(contains_value(200)); + REQUIRE(contains_value(300)); + REQUIRE(contains_value(number::two)); + REQUIRE(nt); + REQUIRE_FALSE(contains_value(number::four)); + REQUIRE_FALSE(contains_value(111)); + REQUIRE_FALSE(contains_value(0)); +} + TEST_CASE("enum_value") { constexpr auto cr = enum_value(0); REQUIRE(cr == Color::RED);