/* * Copyright (C) 2016 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef C2ENUM_H_ #define C2ENUM_H_ #include <C2Param.h> #include <_C2MacroUtils.h> #include <utility> #include <vector> /** \file * Tools for easier enum support. */ /// \cond INTERNAL /* ---------------------------- UTILITIES FOR ENUMERATION REFLECTION ---------------------------- */ /** * Utility class that allows ignoring enum value assignment (e.g. both '(_C2EnumConst)kValue = x' * and '(_C2EnumConst)kValue' will eval to kValue. */ template<typename T> class _C2EnumConst { public: // implicit conversion from T inline _C2EnumConst(T value) : _mValue(value) {} // implicit conversion to T inline operator T() { return _mValue; } // implicit conversion to C2Value::Primitive inline operator C2Value::Primitive() { return (T)_mValue; } // ignore assignment and return T here to avoid implicit conversion to T later inline T &operator =(T value __unused) { return _mValue; } private: T _mValue; }; /// mapper to get name of enum /// \note this will contain any initialization, which we will remove when converting to lower-case #define _C2_GET_ENUM_NAME(x, y) #x /// mapper to get value of enum #define _C2_GET_ENUM_VALUE(x, type) (_C2EnumConst<type>)x /// \endcond class _C2EnumUtils { static C2String camelCaseToDashed(C2String name); static std::vector<C2String> sanitizeEnumValueNames( const std::vector<C2StringLiteral> names, C2StringLiteral _prefix = NULL); friend class C2UtilTest_EnumUtilsTest_Test; public: // this may not be used... static C2_HIDE std::vector<C2String> parseEnumValuesFromString(C2StringLiteral value); template<typename T> static C2_HIDE C2FieldDescriptor::NamedValuesType sanitizeEnumValues( std::vector<T> values, std::vector<C2StringLiteral> names, C2StringLiteral prefix = NULL) { C2FieldDescriptor::NamedValuesType namedValues; std::vector<C2String> sanitizedNames = sanitizeEnumValueNames(names, prefix); for (size_t i = 0; i < values.size() && i < sanitizedNames.size(); ++i) { namedValues.emplace_back(sanitizedNames[i], values[i]); } return namedValues; } template<typename E> static C2_HIDE C2FieldDescriptor::NamedValuesType customEnumValues( std::vector<std::pair<C2StringLiteral, E>> items) { C2FieldDescriptor::NamedValuesType namedValues; for (auto &item : items) { namedValues.emplace_back(item.first, item.second); } return namedValues; } }; #define DEFINE_C2_ENUM_VALUE_AUTO_HELPER(name, type, prefix, ...) \ _DEFINE_C2_ENUM_VALUE_AUTO_HELPER(__C2_GENERATE_GLOBAL_VARS__, name, type, prefix, \ ##__VA_ARGS__) #define _DEFINE_C2_ENUM_VALUE_AUTO_HELPER(enabled, name, type, prefix, ...) \ __DEFINE_C2_ENUM_VALUE_AUTO_HELPER(enabled, name, type, prefix, ##__VA_ARGS__) #define __DEFINE_C2_ENUM_VALUE_AUTO_HELPER(enabled, name, type, prefix, ...) \ ___DEFINE_C2_ENUM_VALUE_AUTO_HELPER##enabled(name, type, prefix, ##__VA_ARGS__) #define ___DEFINE_C2_ENUM_VALUE_AUTO_HELPER(name, type, prefix, ...) \ template<> \ C2FieldDescriptor::NamedValuesType C2FieldDescriptor::namedValuesFor(const name &r __unused) { \ return _C2EnumUtils::sanitizeEnumValues( \ std::vector<C2Value::Primitive> { _C2_MAP(_C2_GET_ENUM_VALUE, type, __VA_ARGS__) }, \ { _C2_MAP(_C2_GET_ENUM_NAME, type, __VA_ARGS__) }, \ prefix); \ } #define ___DEFINE_C2_ENUM_VALUE_AUTO_HELPER__C2_GENERATE_GLOBAL_VARS__(name, type, prefix, ...) #define DEFINE_C2_ENUM_VALUE_CUSTOM_HELPER(name, names) \ _DEFINE_C2_ENUM_VALUE_CUSTOM_HELPER(__C2_GENERATE_GLOBAL_VARS__, name, names) #define _DEFINE_C2_ENUM_VALUE_CUSTOM_HELPER(enabled, name, names) \ __DEFINE_C2_ENUM_VALUE_CUSTOM_HELPER(enabled, name, names) #define __DEFINE_C2_ENUM_VALUE_CUSTOM_HELPER(enabled, name, names) \ ___DEFINE_C2_ENUM_VALUE_CUSTOM_HELPER##enabled(name, names) #define ___DEFINE_C2_ENUM_VALUE_CUSTOM_HELPER(name, names) \ template<> \ C2FieldDescriptor::NamedValuesType C2FieldDescriptor::namedValuesFor(const name &r __unused) { \ return _C2EnumUtils::customEnumValues( \ std::vector<std::pair<C2StringLiteral, name>> names); \ } #define ___DEFINE_C2_ENUM_VALUE_CUSTOM_HELPER__C2_GENERATE_GLOBAL_VARS__(name, names) /** * Defines an enum type with the default named value mapper. The default mapper * finds and removes the longest common prefix across all of the enum value names, and * replaces camel-case separators with dashes ('-'). * * This macro must be used in the global scope and namespace. * * ~~~~~~~~~~~~~ (.cpp) * C2ENUM(c2_enum_t, uint32_t, * C2_VALUE1, * C2_VALUE2 = 5, * C2_VALUE3 = C2_VALUE1 + 1) * // named values are: C2_VALUE1 => "1", C2_VALUE2 => "2", ... * // longest common prefix is "C2_VALUE" * ~~~~~~~~~~~~~ * * \param name name of the enum type (This can be an inner class enum.) * \param type underlying type */ #define C2ENUM(name, type, ...) \ enum name : type { __VA_ARGS__ }; \ DEFINE_C2_ENUM_VALUE_AUTO_HELPER(name, type, NULL, __VA_ARGS__) /** * Defines an enum type with the default named value mapper but custom prefix. The default * mapper removes the prefix from all of the enum value names (if present), and * inserts dashes at camel-case separators (lowHigh becomes low-high) and also replaces * non-leading underscores with dashes ('-'). * * This macro must be used in the global scope and namespace. * * ~~~~~~~~~~~~~ (.cpp) * C2ENUM_CUSTOM_PREFIX(c2_enum_t, uint32_t, "C2_", * C2_VALUE1, * C2_VALUE2 = 5, * C2_VALUE3 = C2_VALUE1 + 1) * // named values are: C2_VALUE1 => "VALUE1", C2_VALUE2 => "VALUE2", ... * ~~~~~~~~~~~~~ * * \param name name of the enum type (This can be an inner class enum.) * \param type underlying type * \param prefix prefix to remove */ #define C2ENUM_CUSTOM_PREFIX(name, type, prefix, ...) \ enum name : type { __VA_ARGS__ }; \ DEFINE_C2_ENUM_VALUE_AUTO_HELPER(name, type, prefix, __VA_ARGS__) /** * Defines an enum type with custom names. * * This macro must be used in the global scope and namespace. * * ~~~~~~~~~~~~~ (.cpp) * C2ENUM_CUSTOM_NAMES(SomeStruct::c2_enum_t, uint32_t, ({ * { "One", SomeStruct::C2_VALUE1 }, * { "Two", SomeStruct::C2_VALUE2 }, * { "Three", SomeStruct::C2_VALUE3 } }), * C2_VALUE1, * C2_VALUE2 = 5, * C2_VALUE3 = C2_VALUE1 + 1) * * // named values are: C2_VALUE1 => "One", C2_VALUE2 => "Two", ... * ~~~~~~~~~~~~~ */ #define C2ENUM_CUSTOM_NAMES(name, type, names, ...) \ enum name : type { __VA_ARGS__ }; \ DEFINE_C2_ENUM_VALUE_CUSTOM_HELPER(name, names) /** * Make enums usable as their integral types. * * Note: this makes them not usable in printf() */ template<class E> struct C2EasyEnum { using U = typename std::underlying_type<E>::type; E value; // define conversion functions inline constexpr operator E() const { return value; } inline constexpr C2EasyEnum(E value_) : value(value_) { } inline constexpr C2EasyEnum(U value_) : value(E(value_)) { } inline constexpr C2EasyEnum() = default; }; // make C2EasyEnum behave like a regular enum namespace std { template<typename E> struct underlying_type<C2EasyEnum<E>> { typedef typename underlying_type<E>::type type; }; template<typename E> struct is_enum<C2EasyEnum<E>> { constexpr static bool value = true; }; } #endif // C2ENUM_H_