1 #ifndef MAGIC_ENUM_HPP
2 #define MAGIC_ENUM_HPP
3 
4 #include <array>
5 #include <exception>
6 #include <stdexcept>
7 #include <string_view>
8 #include <string>
9 
10 #    if defined(__clang__)
11 #        define PRETTY_FUNCTION_NAME __PRETTY_FUNCTION__
12 #        define ENUM_OFFSET               2
13 #    elif defined(__GNUC__)
14 #        define PRETTY_FUNCTION_NAME __PRETTY_FUNCTION__
15 #        define ENUM_OFFSET               51
16 #    elif defined(_MSC_VER)
17 #        define PRETTY_FUNCTION_NAME __FUNCSIG__
18 #        define ENUM_OFFSET               17
19 #    endif
20 namespace OHOS {
21 namespace Sharing {
22 namespace magic_enum {
23 
24 const int MAGIC_ENUM_RANGE_MAX = 1024;
25 template <typename E, E V>
get_enum_value_name()26 constexpr std::string_view get_enum_value_name()
27 {
28     std::string_view name{PRETTY_FUNCTION_NAME, sizeof(PRETTY_FUNCTION_NAME) - ENUM_OFFSET};
29     for (std::size_t i = name.size(); i > 0; --i) {
30         if (!((name[i - 1] >= '0' && name[i - 1] <= '9') || (name[i - 1] >= 'a' && name[i - 1] <= 'z') ||
31               (name[i - 1] >= 'A' && name[i - 1] <= 'Z') || (name[i - 1] == '_'))) {
32             name.remove_prefix(i);
33             break;
34         }
35     }
36     if (name.size() > 0 && ((name.front() >= 'a' && name.front() <= 'z') ||
37                             (name.front() >= 'A' && name.front() <= 'Z') || (name.front() == '_'))) {
38         return name;
39     }
40     return {}; // Invalid name.
41 }
42 
43 template <typename E, E V>
is_valid()44 constexpr bool is_valid()
45 {
46     return get_enum_value_name<E, V>().size() != 0;
47 }
48 
49 template <int... Is>
make_integer_list_wrapper(std::integer_sequence<int, Is...>)50 constexpr auto make_integer_list_wrapper(std::integer_sequence<int, Is...>)
51 {
52     constexpr int half_size = sizeof...(Is) / 2;
53     return std::integer_sequence<int, (Is - half_size)...>();
54 }
55 
56 constexpr auto test_integer_sequence_v =
57     make_integer_list_wrapper(std::make_integer_sequence<int, MAGIC_ENUM_RANGE_MAX>());
58 
59 template <typename E, int... Is>
get_enum_size(std::integer_sequence<int, Is...>)60 constexpr size_t get_enum_size(std::integer_sequence<int, Is...>)
61 {
62     constexpr std::array<bool, sizeof...(Is)> valid{is_valid<E, static_cast<E>(Is)>()...};
63     constexpr std::size_t count = [](decltype((valid)) valid_) constexpr noexcept->std::size_t
64     {
65         auto count_ = std::size_t{0};
66         for (std::size_t i_ = 0; i_ < valid_.size(); ++i_) {
67             if (valid_[i_]) {
68                 ++count_;
69             }
70         }
71         return count_;
72     }
73     (valid);
74     return count;
75 }
76 
77 template <typename E>
78 constexpr std::size_t enum_size_v = get_enum_size<E>(test_integer_sequence_v);
79 
80 template <typename E, int... Is>
get_all_valid_values(std::integer_sequence<int, Is...>)81 constexpr auto get_all_valid_values(std::integer_sequence<int, Is...>)
82 {
83     constexpr std::array<bool, sizeof...(Is)> valid{is_valid<E, static_cast<E>(Is)>()...};
84     constexpr std::array<int, sizeof...(Is)> integer_value{Is...};
85     std::array<int, enum_size_v<E>> values{};
86     for (std::size_t i = 0, v = 0; i < sizeof...(Is); ++i) {
87         if (valid[i]) {
88             values[v++] = integer_value[i];
89         }
90     }
91     return values;
92 }
93 
94 template <typename E, int... Is>
get_all_valid_names(std::integer_sequence<int, Is...>)95 constexpr auto get_all_valid_names(std::integer_sequence<int, Is...>)
96 {
97     constexpr std::array<std::string_view, sizeof...(Is)> names{get_enum_value_name<E, static_cast<E>(Is)>()...};
98     std::array<std::string_view, enum_size_v<E>> valid_names{};
99     for (std::size_t i = 0, v = 0; i < names.size(); ++i) {
100         if (names[i].size() != 0) {
101             valid_names[v++] = names[i];
102         }
103     }
104     return valid_names;
105 }
106 
107 template <typename E>
108 constexpr auto enum_names_v = get_all_valid_names<E>(test_integer_sequence_v);
109 
110 template <typename E>
111 constexpr auto enum_values_v = get_all_valid_values<E>(test_integer_sequence_v);
112 
113 template <typename E>
string2enum(const std::string_view str)114 constexpr E string2enum(const std::string_view str)
115 {
116     constexpr auto valid_names = enum_names_v<E>;
117     constexpr auto valid_values = enum_values_v<E>;
118     constexpr auto enum_size = enum_size_v<E>;
119     for (size_t i = 0; i < enum_size; ++i) {
120         if (str == valid_names[i]) {
121             return static_cast<E>(valid_values[i]);
122         }
123     }
124     return E{};
125 }
126 
127 template <typename E>
enum2string(E V)128 constexpr std::string_view enum2string(E V)
129 {
130     constexpr auto valid_names = enum_names_v<E>;
131     constexpr auto valid_values = enum_values_v<E>;
132     constexpr auto enum_size = enum_size_v<E>;
133     for (size_t i = 0; i < enum_size; ++i) {
134         if (static_cast<int>(V) == valid_values[i]) {
135             return valid_names[i];
136         }
137     }
138     return "";
139 }
140 
141 template <typename E>
enum_name(E value)142 constexpr auto enum_name(E value)
143 {
144     int num = static_cast<int>(value);
145     if (num > MAGIC_ENUM_RANGE_MAX / 2 || num < -(MAGIC_ENUM_RANGE_MAX / 2)) { // 2: maxnum
146         return std::to_string(static_cast<int>(value));
147     } else {
148         return std::string(enum2string<E>(value));
149     }
150 }
151 
152 } // namespace magic_enum
153 } // namespace Sharing
154 } // namespace OHOS
155 
156 #endif // MAGIC_ENUM_HPP