diff --git a/README.md b/README.md
index 523b10c..add4370 100644
--- a/README.md
+++ b/README.md
@@ -9,10 +9,11 @@ Converting (scoped)enum values to/from string names written in C++>=11.
## Features
* Supports `enum` and `enum class`
* Supports enums in namespaces, classes or structs even templated or not
-* Supports compile-time as much as possible using with C++14 and later
+* Supports compile-time as much as possible using with C++17 and later
* Changing enum range with template parameter (default range: `[0, 256)`) on each call or with your special function for types or adding specialized `enum_range` struct
* Supports and automatically overloaded `operator<<` for Enum types to direct using with ostream objects
* Supports custom enum name output by explicit specialization of `constexpr inline auto mgutility::detail::enum_type::name() noexcept` function
+* Supports bitmasked enums and auto detect them
* Supports iterate over enum (names and values) with `mgutility::enum_for_each()` class and it is compatible with standard ranges and views
## Limitations
@@ -20,16 +21,32 @@ Converting (scoped)enum values to/from string names written in C++>=11.
* Wider range can increase compile time so user responsible to adjusting for enum's range
-## Usage ([try it!](https://godbolt.org/z/YM5EvY1Y5))
+## Usage ([try it!](https://godbolt.org/z/vYhYeq68c))
```C++
#include
#include "enum_name.hpp"
-num class rgb_color { red, green, blue, unknown = -1 };
+enum class rgb_color {
+ red = 1 << 0,
+ green = 1 << 1,
+ blue = 1 << 2,
+ unknown = -1
+};
+
+auto operator|(rgb_color lhs, rgb_color rhs) -> rgb_color {
+ return static_cast(mgutility::enum_to_underlying(lhs) |
+ mgutility::enum_to_underlying(rhs));
+}
+
+auto operator&(rgb_color lhs, rgb_color rhs) -> rgb_color {
+ return static_cast(mgutility::enum_to_underlying(lhs) &
+ mgutility::enum_to_underlying(rhs));
+}
// specialize rgb_color::unknown to make output "UNKNOWN" instead of "unknown"
template <>
-constexpr auto mgutility::detail::enum_type::name() noexcept
+constexpr inline auto
+mgutility::detail::enum_type::name() noexcept
-> string_view {
return "UNKNOWN";
}
@@ -38,38 +55,43 @@ constexpr auto mgutility::detail::enum_type::name
template <>
struct mgutility::enum_range {
static constexpr auto min = -1;
- static constexpr auto max = 3;
+ static constexpr auto max = 5;
};
// you can specialize enum ranges with overload per enum types (option 2)
-auto enum_name = [](rgb_color c) { return mgutility::enum_name<-1, 3>(c); };
+auto enum_name = [](rgb_color c) { return mgutility::enum_name<-1, 5>(c); };
#if defined(__cpp_lib_print)
#include
#include
#endif
-
int main() {
auto x = rgb_color::blue;
- auto y = mgutility::to_enum("greenn");
+ auto y = mgutility::to_enum("green|red");
#if defined(__cpp_lib_print)
-// enum_for_each can usable with views and range algorithms
-auto colors = mgutility::enum_for_each() |
- std::ranges::views::filter(
- [](auto &&pair) { return pair.second != "UNKNOWN"; });
+ // enum_for_each can usable with views and range algorithms
+ auto colors = mgutility::enum_for_each() |
+ std::ranges::views::filter([](auto &&pair) {
+ return !pair.second.empty() && pair.second != "UNKNOWN" &&
+ pair.second.find('|') == pair.second.npos;
+ });
std::ranges::for_each(colors, [](auto &&color) {
- std::println("{} \t: {}", color.second, mgutility::enum_to_underlying(color.first));
+ std::println("{} \t: {}", color.second,
+ mgutility::enum_to_underlying(color.first));
});
#else
for (auto&& e : mgutility::enum_for_each()) {
- if(e.second != "UNKNOWN"){
- std::cout << e.second << " \t: " << mgutility::enum_to_underlying(e.first) << '\n';
+ if (!e.second.empty() && e.second != "UNKNOWN" &&
+ e.second.find('|') == e.second.npos) {
+ std::cout << e.second
+ << " \t: " << mgutility::enum_to_underlying(e.first)
+ << '\n';
}
// std::pair {enum_type, name_of_enum}
}
@@ -78,8 +100,6 @@ auto colors = mgutility::enum_for_each() |
// default signature: enum_name(Enum&&) Changing max_value to not too much greater than enum's
// max value, it will compiles faster
- std::cout << mgutility::enum_name(x) << '\n'; // will print "blue" to output
- // or
std::cout << x << '\n'; // will print "blue" to output
// calling specialized enum ranges function for rgb_color type
diff --git a/include/enum_name.hpp b/include/enum_name.hpp
index c7ed6ab..d68ae97 100644
--- a/include/enum_name.hpp
+++ b/include/enum_name.hpp
@@ -33,7 +33,6 @@
#include
#include
#include
-#include
#if defined(_MSC_VER) && _MSC_VER < 1910
#error "Requires MSVC 2017 or newer!"
@@ -72,6 +71,13 @@ struct is_scoped_enum {
std::is_enum::value &&
!std::is_convertible::type>::value;
};
+
+template
+struct has_bit_or : std::false_type {};
+
+template
+struct has_bit_or : std::true_type {};
+
#if MG_ENUM_NAME_CPLUSPLUS > 201103L
template
static constexpr bool is_scoped_enum_v = is_scoped_enum::value;
@@ -131,8 +137,14 @@ class basic_string_view {
size_t len) const noexcept {
return basic_string_view(data_ + begin, len);
}
- constexpr inline size_t rfind(Char c, size_t pos = 0) const noexcept {
- return c == data_[pos] ? pos : rfind(c, --pos);
+ constexpr inline size_t rfind(Char c, size_t pos = npos) const noexcept {
+ return (pos == npos ? pos = size_ : pos = pos), c == data_[pos] ? pos
+ : pos == 0U
+ ? npos
+ : rfind(c, --pos);
+ }
+ constexpr inline size_t find(Char c, size_t pos = 0) const noexcept {
+ return c == data_[pos] ? pos : pos < size_ ? find(c, ++pos) : npos;
}
constexpr friend inline bool operator==(
@@ -168,6 +180,8 @@ class basic_string_view {
return os;
}
+ static constexpr auto npos = -1;
+
private:
size_t size_;
const Char* data_;
@@ -297,6 +311,11 @@ using enable_if_t = std::enable_if_t;
#endif
+template
+using string_or_view_t =
+ typename std::conditional::value, std::string,
+ detail::string_view>::type;
+
template
struct enum_sequence {};
@@ -362,20 +381,21 @@ struct enum_type {
};
template
-using enum_pair = std::pair;
+using enum_pair = std::pair>;
template
inline auto get_enum_array(detail::enum_sequence) noexcept
-> std::array {
- static std::array
- arr{"", enum_type::template name()...};
+ static std::array arr{
+ "", enum_type::template name()...};
return arr;
}
template
inline auto to_enum_impl(detail::string_view str) noexcept
-> detail::optional {
- auto arr = get_enum_array(detail::make_enum_sequence());
+ auto arr =
+ get_enum_array(detail::make_enum_sequence());
const auto index{std::find(arr.begin() + 1, arr.end(), str)};
return index == arr.end()
? detail::nullopt
@@ -384,11 +404,68 @@ inline auto to_enum_impl(detail::string_view str) noexcept
}
template
+inline auto to_enum_bitmask_impl(detail::string_view str) noexcept
+ -> detail::optional {
+ if (str.find('|') == detail::string_view::npos) {
+ return to_enum_impl(str);
+ } else {
+ auto index = std::size_t{};
+ auto result = detail::optional{detail::nullopt};
+ for (std::size_t i{}; i < str.size(); ++i) {
+ auto maybe_enum =
+ to_enum_impl(str.substr(index, i - index));
+ if (maybe_enum.has_value()) {
+ result.emplace(result ? static_cast(*result | *maybe_enum)
+ : *maybe_enum);
+ }
+
+ if (str[i] == '|') {
+ index = i + 1U;
+ }
+ }
+
+ auto maybe_enum =
+ to_enum_impl(str.substr(index, str.size() - index));
+ if (maybe_enum.has_value()) {
+ result.emplace(result ? static_cast(*result | *maybe_enum)
+ : *maybe_enum);
+ }
+ return result;
+ }
+}
+
+template ::value, bool> = true>
inline auto enum_name_impl(Enum e) noexcept -> detail::string_view {
- auto arr = get_enum_array(detail::make_enum_sequence());
+ auto arr =
+ get_enum_array(detail::make_enum_sequence());
const auto index{std::abs(Min) + static_cast(e) + (Min < 0 ? 1 : 1)};
return arr[(index < Min || index > arr.size() - 1) ? 0 : index];
}
+
+template ::value, bool> = true>
+inline auto enum_name_impl(Enum e) noexcept -> detail::string_or_view_t {
+ auto arr =
+ get_enum_array(detail::make_enum_sequence());
+ const auto index{std::abs(Min) + static_cast(e) + (Min < 0 ? 1 : 1)};
+ const auto name = arr[(index < Min || index > arr.size() - 1) ? 0 : index];
+
+ if (!name.empty() && !std::isdigit(name[0])) {
+ return std::string{name};
+ } else {
+ auto bitmasked_name = std::string{};
+
+ for (auto i{Min}; i < Max; ++i) {
+ const auto idx = std::abs(Min) + i + (Min < 0 ? 1 : 1);
+ if (!(idx < Min || idx > arr.size() - 1) && !arr[idx].empty() &&
+ !std::isdigit(arr[idx][0]) && (e & static_cast(i)) == static_cast(i)) {
+ bitmasked_name.append(arr[idx]).append("|");
+ }
+ }
+ return bitmasked_name.substr(0U, bitmasked_name.size() - 1);
+ }
+}
} // namespace detail
} // namespace mgutility
@@ -462,7 +539,7 @@ constexpr inline auto enum_to_underlying(Enum e) noexcept
template
MG_ENUM_NAME_CNSTXPR inline auto enum_name(Enum e) noexcept
- -> detail::string_view {
+ -> detail::string_or_view_t {
static_assert(Min < Max - 1, "Max must be greater than (Min + 1)!");
static_assert(std::is_enum::value, "Value is not an Enum type!");
return detail::enum_name_impl(e);
@@ -471,7 +548,7 @@ MG_ENUM_NAME_CNSTXPR inline auto enum_name(Enum e) noexcept
template ::min,
int Max = enum_range::max>
MG_ENUM_NAME_CNSTXPR inline auto enum_name(Enum e) noexcept
- -> detail::string_view {
+ -> detail::string_or_view_t {
static_assert(Min < Max - 1, "Max must be greater than (Min + 1)!");
static_assert(std::is_enum::value, "Value is not an Enum type!");
return detail::enum_name_impl(e);
@@ -484,13 +561,24 @@ auto enum_for_each::enum_iter::operator*() const -> value_type {
}
template ::min,
- int Max = enum_range::max>
+ int Max = enum_range::max,
+ detail::enable_if_t::value, bool> = true>
MG_ENUM_NAME_CNSTXPR inline auto to_enum(detail::string_view str) noexcept
-> detail::optional {
static_assert(Min < Max - 1, "Max must be greater than (Min + 1)!");
static_assert(std::is_enum::value, "Type is not an Enum type!");
return detail::to_enum_impl(str);
}
+
+template ::min,
+ int Max = enum_range::max,
+ detail::enable_if_t::value, bool> = true>
+MG_ENUM_NAME_CNSTXPR inline auto to_enum(detail::string_view str) noexcept
+ -> detail::optional {
+ static_assert(Min < Max - 1, "Max must be greater than (Min + 1)!");
+ static_assert(std::is_enum::value, "Type is not an Enum type!");
+ return detail::to_enum_bitmask_impl(str);
+}
} // namespace mgutility
template