blob: b0fad8f46cb7ee2853173fede1647c8e7ee8d2c9 [file] [log] [blame]
Pawin Vongmasa36653902018-11-15 00:10:25 -08001/*
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 */
38template<typename T>
39class _C2EnumConst {
40public:
41 // implicit conversion from T
42 inline _C2EnumConst(T value) : _mValue(value) {}
43 // implicit conversion to T
44 inline operator T() { return _mValue; }
45 // implicit conversion to C2Value::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; }
49private:
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
61class _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
70public:
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>
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, ...) \
106template<> \
107C2FieldDescriptor::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) \
122template<> \
123C2FieldDescriptor::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, ...) \
149enum name : type { __VA_ARGS__ }; \
150DEFINE_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, ...) \
173enum name : type { __VA_ARGS__ }; \
174DEFINE_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, ...) \
194enum name : type { __VA_ARGS__ }; \
195DEFINE_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 */
202template<class E>
203struct C2EasyEnum {
204 using U = typename std::underlying_type<E>::type;
205 E value;
206 // define conversion functions
207 inline constexpr operator E() const { return value; }
208 inline constexpr C2EasyEnum(E value_) : value(value_) { }
209 inline constexpr C2EasyEnum(U value_) : value(E(value_)) { }
210 inline constexpr C2EasyEnum() = default;
211};
212
213// make C2EasyEnum behave like a regular enum
214
215namespace 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