1 /*
2  * Copyright (C) 2024-2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 #ifndef MAGIC_ENUM_H
16 #define MAGIC_ENUM_H
17 
18 #include <array>
19 #include <exception>
20 #include <stdexcept>
21 #include <string_view>
22 #include <string>
23 
24 #    if defined(__clang__)
25 #        define PRETTY_FUNCTION_NAME __PRETTY_FUNCTION__
26 #        define ENUM_OFFSET               2
27 #    elif defined(__GNUC__)
28 #        define PRETTY_FUNCTION_NAME __PRETTY_FUNCTION__
29 #        define ENUM_OFFSET               51
30 #    elif defined(_MSC_VER)
31 #        define PRETTY_FUNCTION_NAME __FUNCSIG__
32 #        define ENUM_OFFSET               17
33 #    endif
34 namespace OHOS {
35 namespace Wifi {
36 namespace magic_enum {
37 
38 const int MAGIC_ENUM_RANGE_MAX = 1024;
39 template <typename E, E V>
GetEnumValueName()40 constexpr std::string_view GetEnumValueName()
41 {
42     std::string_view name{PRETTY_FUNCTION_NAME, sizeof(PRETTY_FUNCTION_NAME) - ENUM_OFFSET};
43     for (std::size_t i = name.size(); i > 0; --i) {
44         if (!((name[i - 1] >= '0' && name[i - 1] <= '9') || (name[i - 1] >= 'a' && name[i - 1] <= 'z') ||
45               (name[i - 1] >= 'A' && name[i - 1] <= 'Z') || (name[i - 1] == '_'))) {
46             name.remove_prefix(i);
47             break;
48         }
49     }
50     if (name.size() > 0 && ((name.front() >= 'a' && name.front() <= 'z') ||
51                             (name.front() >= 'A' && name.front() <= 'Z') || (name.front() == '_'))) {
52         return name;
53     }
54     return {}; // Invalid name.
55 }
56 
57 template <typename E, E V>
IsValid()58 constexpr bool IsValid()
59 {
60     return GetEnumValueName<E, V>().size() != 0;
61 }
62 
63 template <int... Is>
MakeIntegerListWrapper(std::integer_sequence<int,Is...>)64 constexpr auto MakeIntegerListWrapper(std::integer_sequence<int, Is...>)
65 {
66     constexpr int halfSize = static_cast<int>(sizeof...(Is) / 2);
67     return std::integer_sequence<int, (Is - halfSize)...>();
68 }
69 
70 constexpr auto TEST_INTEGER_SEQUENCE_V =
71     MakeIntegerListWrapper(std::make_integer_sequence<int, MAGIC_ENUM_RANGE_MAX>());
72 
73 template <typename E, int... Is>
GetEnumSize(std::integer_sequence<int,Is...>)74 constexpr size_t GetEnumSize(std::integer_sequence<int, Is...>)
75 {
76     constexpr std::array<bool, sizeof...(Is)> valid{IsValid<E, static_cast<E>(Is)>()...};
77     constexpr std::size_t count = [](decltype((valid)) validValue) constexpr noexcept->std::size_t {
78         auto nSize = std::size_t{0};
79         for (std::size_t index = 0; index < validValue.size(); ++index) {
80             if (validValue[index]) {
81                 ++nSize;
82             }
83         }
84         return nSize;
85     }
86         (valid);
87     return count;
88 }
89 
90 template <typename E>
91 constexpr std::size_t ENUM_SIZE_V = GetEnumSize<E>(TEST_INTEGER_SEQUENCE_V);
92 
93 template <typename E, int... Is>
GetAllValidValues(std::integer_sequence<int,Is...>)94 constexpr auto GetAllValidValues(std::integer_sequence<int, Is...>)
95 {
96     constexpr std::array<bool, sizeof...(Is)> valid{IsValid<E, static_cast<E>(Is)>()...};
97     constexpr std::array<int, sizeof...(Is)> integerValue{Is...};
98     std::array<int, ENUM_SIZE_V<E>> values{};
99     for (std::size_t i = 0, v = 0; i < sizeof...(Is); ++i) {
100         if (valid[i]) {
101             values[v++] = integerValue[i];
102         }
103     }
104     return values;
105 }
106 
107 template <typename E, int... Is>
GetAllValidNames(std::integer_sequence<int,Is...>)108 constexpr auto GetAllValidNames(std::integer_sequence<int, Is...>)
109 {
110     constexpr std::array<std::string_view, sizeof...(Is)> names{GetEnumValueName<E, static_cast<E>(Is)>()...};
111     std::array<std::string_view, ENUM_SIZE_V<E>> valid_names{};
112     for (std::size_t i = 0, v = 0; i < names.size(); ++i) {
113         if (names[i].size() != 0) {
114             valid_names[v++] = names[i];
115         }
116     }
117     return valid_names;
118 }
119 
120 template <typename E>
121 constexpr auto ENUM_NAMES_V = GetAllValidNames<E>(TEST_INTEGER_SEQUENCE_V);
122 
123 template <typename E>
124 constexpr auto ENUM_VALUES_V = GetAllValidValues<E>(TEST_INTEGER_SEQUENCE_V);
125 
126 template <typename E>
Enum2string(E V)127 constexpr std::string_view Enum2string(E V)
128 {
129     constexpr auto validNames = ENUM_NAMES_V<E>;
130     constexpr auto validValues = ENUM_VALUES_V<E>;
131     constexpr auto enumSize = ENUM_SIZE_V<E>;
132     for (size_t i = 0; i < enumSize; ++i) {
133         if (static_cast<int>(V) == validValues[i]) {
134             return validNames[i];
135         }
136     }
137     return "";
138 }
139 
140 template <typename E>
Enum2Name(E value)141 constexpr auto Enum2Name(E value)
142 {
143     int num = static_cast<int>(value);
144     if (num > MAGIC_ENUM_RANGE_MAX / 2 || num < -(MAGIC_ENUM_RANGE_MAX / 2)) { // 2: maxnum
145         return std::to_string(static_cast<int>(value));
146     } else {
147         return std::string(Enum2string<E>(value));
148     }
149 }
150 
151 } // namespace magic_enum
152 } // namespace Wifi
153 } // namespace OHOS
154 
155 #endif