Home | History | Annotate | Download | only in include
      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