1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef C2ENUM_H_
18 #define C2ENUM_H_
19 
20 #include <C2Param.h>
21 #include <_C2MacroUtils.h>
22 
23 #include <utility>
24 #include <vector>
25 
26 /** \file
27  * Tools for easier enum support.
28  */
29 
30 /// \cond INTERNAL
31 
32 /* ---------------------------- UTILITIES FOR ENUMERATION REFLECTION ---------------------------- */
33 
34 /**
35  * Utility class that allows ignoring enum value assignment (e.g. both '(_C2EnumConst)kValue = x'
36  * and '(_C2EnumConst)kValue' will eval to kValue.
37  */
38 template<typename T>
39 class _C2EnumConst {
40 public:
41     // implicit conversion from T
_C2EnumConst(T value)42     inline _C2EnumConst(T value) : _mValue(value) {}
43     // implicit conversion to T
T()44     inline operator T() { return _mValue; }
45     // implicit conversion to C2Value::Primitive
Primitive()46     inline operator C2Value::Primitive() { return (T)_mValue; }
47     // ignore assignment and return T here to avoid implicit conversion to T later
48     inline T &operator =(T value __unused) { return _mValue; }
49 private:
50     T _mValue;
51 };
52 
53 /// mapper to get name of enum
54 /// \note this will contain any initialization, which we will remove when converting to lower-case
55 #define _C2_GET_ENUM_NAME(x, y) #x
56 /// mapper to get value of enum
57 #define _C2_GET_ENUM_VALUE(x, type) (_C2EnumConst<type>)x
58 
59 /// \endcond
60 
61 class _C2EnumUtils {
62     static C2String camelCaseToDashed(C2String name);
63 
64     static std::vector<C2String> sanitizeEnumValueNames(
65             const std::vector<C2StringLiteral> names,
66             C2StringLiteral _prefix = nullptr);
67 
68     friend class C2UtilTest_EnumUtilsTest_Test;
69 
70 public:
71     // this may not be used...
72     static C2_HIDE std::vector<C2String> parseEnumValuesFromString(C2StringLiteral value);
73 
74     template<typename T>
75     static C2_HIDE C2FieldDescriptor::NamedValuesType sanitizeEnumValues(
76             std::vector<T> values,
77             std::vector<C2StringLiteral> names,
78             C2StringLiteral prefix = nullptr) {
79         C2FieldDescriptor::NamedValuesType namedValues;
80         std::vector<C2String> sanitizedNames = sanitizeEnumValueNames(names, prefix);
81         for (size_t i = 0; i < values.size() && i < sanitizedNames.size(); ++i) {
82             namedValues.emplace_back(sanitizedNames[i], values[i]);
83         }
84         return namedValues;
85     }
86 
87     template<typename E>
customEnumValues(std::vector<std::pair<C2StringLiteral,E>> items)88     static C2_HIDE C2FieldDescriptor::NamedValuesType customEnumValues(
89             std::vector<std::pair<C2StringLiteral, E>> items) {
90         C2FieldDescriptor::NamedValuesType namedValues;
91         for (auto &item : items) {
92             namedValues.emplace_back(item.first, item.second);
93         }
94         return namedValues;
95     }
96 };
97 
98 #define DEFINE_C2_ENUM_VALUE_AUTO_HELPER(name, type, prefix, ...) \
99     _DEFINE_C2_ENUM_VALUE_AUTO_HELPER(__C2_GENERATE_GLOBAL_VARS__, name, type, prefix, \
100             ##__VA_ARGS__)
101 #define _DEFINE_C2_ENUM_VALUE_AUTO_HELPER(enabled, name, type, prefix, ...) \
102     __DEFINE_C2_ENUM_VALUE_AUTO_HELPER(enabled, name, type, prefix, ##__VA_ARGS__)
103 #define __DEFINE_C2_ENUM_VALUE_AUTO_HELPER(enabled, name, type, prefix, ...) \
104     ___DEFINE_C2_ENUM_VALUE_AUTO_HELPER##enabled(name, type, prefix, ##__VA_ARGS__)
105 #define ___DEFINE_C2_ENUM_VALUE_AUTO_HELPER(name, type, prefix, ...) \
106 template<> \
107 C2FieldDescriptor::NamedValuesType C2FieldDescriptor::namedValuesFor(const name &r __unused) { \
108     return _C2EnumUtils::sanitizeEnumValues( \
109             std::vector<C2Value::Primitive> { _C2_MAP(_C2_GET_ENUM_VALUE, type, __VA_ARGS__) }, \
110             { _C2_MAP(_C2_GET_ENUM_NAME, type, __VA_ARGS__) }, \
111             prefix); \
112 }
113 #define ___DEFINE_C2_ENUM_VALUE_AUTO_HELPER__C2_GENERATE_GLOBAL_VARS__(name, type, prefix, ...)
114 
115 #define DEFINE_C2_ENUM_VALUE_CUSTOM_HELPER(name, names) \
116     _DEFINE_C2_ENUM_VALUE_CUSTOM_HELPER(__C2_GENERATE_GLOBAL_VARS__, name, names)
117 #define _DEFINE_C2_ENUM_VALUE_CUSTOM_HELPER(enabled, name, names) \
118     __DEFINE_C2_ENUM_VALUE_CUSTOM_HELPER(enabled, name, names)
119 #define __DEFINE_C2_ENUM_VALUE_CUSTOM_HELPER(enabled, name, names) \
120     ___DEFINE_C2_ENUM_VALUE_CUSTOM_HELPER##enabled(name, names)
121 #define ___DEFINE_C2_ENUM_VALUE_CUSTOM_HELPER(name, names) \
122 template<> \
123 C2FieldDescriptor::NamedValuesType C2FieldDescriptor::namedValuesFor(const name &r __unused) { \
124     return _C2EnumUtils::customEnumValues( \
125             std::vector<std::pair<C2StringLiteral, name>> names); \
126 }
127 #define ___DEFINE_C2_ENUM_VALUE_CUSTOM_HELPER__C2_GENERATE_GLOBAL_VARS__(name, names)
128 
129 /**
130  * Defines an enum type with the default named value mapper. The default mapper
131  * finds and removes the longest common prefix across all of the enum value names, and
132  * replaces camel-case separators with dashes ('-').
133  *
134  * This macro must be used in the global scope and namespace.
135  *
136  *  ~~~~~~~~~~~~~ (.cpp)
137  *  C2ENUM(c2_enum_t, uint32_t,
138  *    C2_VALUE1,
139  *    C2_VALUE2 = 5,
140  *    C2_VALUE3 = C2_VALUE1 + 1)
141  *  // named values are: C2_VALUE1 => "1", C2_VALUE2 => "2", ...
142  *  // longest common prefix is "C2_VALUE"
143  *  ~~~~~~~~~~~~~
144  *
145  * \param name name of the enum type (This can be an inner class enum.)
146  * \param type underlying type
147  */
148 #define C2ENUM(name, type, ...) \
149 enum name : type { __VA_ARGS__ }; \
150 DEFINE_C2_ENUM_VALUE_AUTO_HELPER(name, type, nullptr, __VA_ARGS__)
151 
152 /**
153  * Defines an enum type with the default named value mapper but custom prefix. The default
154  * mapper removes the prefix from all of the enum value names (if present), and
155  * inserts dashes at camel-case separators (lowHigh becomes low-high) and also replaces
156  * non-leading underscores with dashes ('-').
157  *
158  * This macro must be used in the global scope and namespace.
159  *
160  *  ~~~~~~~~~~~~~ (.cpp)
161  *  C2ENUM_CUSTOM_PREFIX(c2_enum_t, uint32_t, "C2_",
162  *    C2_VALUE1,
163  *    C2_VALUE2 = 5,
164  *    C2_VALUE3 = C2_VALUE1 + 1)
165  *  // named values are: C2_VALUE1 => "VALUE1", C2_VALUE2 => "VALUE2", ...
166  *  ~~~~~~~~~~~~~
167  *
168  * \param name name of the enum type (This can be an inner class enum.)
169  * \param type underlying type
170  * \param prefix prefix to remove
171  */
172 #define C2ENUM_CUSTOM_PREFIX(name, type, prefix, ...) \
173 enum name : type { __VA_ARGS__ }; \
174 DEFINE_C2_ENUM_VALUE_AUTO_HELPER(name, type, prefix, __VA_ARGS__)
175 
176 /**
177  * Defines an enum type with custom names.
178  *
179  * This macro must be used in the global scope and namespace.
180  *
181  *  ~~~~~~~~~~~~~ (.cpp)
182  *  C2ENUM_CUSTOM_NAMES(SomeStruct::c2_enum_t, uint32_t, ({
183  *      { "One", SomeStruct::C2_VALUE1 },
184  *      { "Two", SomeStruct::C2_VALUE2 },
185  *      { "Three", SomeStruct::C2_VALUE3 } }),
186  *    C2_VALUE1,
187  *    C2_VALUE2 = 5,
188  *    C2_VALUE3 = C2_VALUE1 + 1)
189  *
190  *  // named values are: C2_VALUE1 => "One", C2_VALUE2 => "Two", ...
191  *  ~~~~~~~~~~~~~
192  */
193 #define C2ENUM_CUSTOM_NAMES(name, type, names, ...) \
194 enum name : type { __VA_ARGS__ }; \
195 DEFINE_C2_ENUM_VALUE_CUSTOM_HELPER(name, names)
196 
197 /**
198  * Make enums usable as their integral types.
199  *
200  * Note: this makes them not usable in printf()
201  */
202 template<class E>
203 struct C2EasyEnum {
204     using U = typename std::underlying_type<E>::type;
205     E value;
206     // define conversion functions
EC2EasyEnum207     inline constexpr operator E() const { return value; }
C2EasyEnumC2EasyEnum208     inline constexpr C2EasyEnum(E value_) : value(value_) { }
C2EasyEnumC2EasyEnum209     inline constexpr C2EasyEnum(U value_) : value(E(value_)) { }
210     inline constexpr C2EasyEnum() = default;
211 };
212 
213 // make C2EasyEnum behave like a regular enum
214 
215 namespace std {
216     template<typename E>
217     struct underlying_type<C2EasyEnum<E>> {
218         typedef typename underlying_type<E>::type type;
219     };
220 
221     template<typename E>
222     struct is_enum<C2EasyEnum<E>> {
223         constexpr static bool value = true;
224     };
225 }
226 
227 #endif  // C2ENUM_H_
228 
229