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 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; } 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> 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 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 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