impl/EnumDetails.h (178 lines of code) (raw):
// Copyright (c) Facebook, Inc. and its affiliates.
//
// This source code is licensed under the MIT license found in the
// LICENSE file in the root directory of this source tree.
#pragma once
#include <array>
#include <string>
#include <boost/preprocessor/comparison/equal.hpp>
#include <boost/preprocessor/control/if.hpp>
#include <boost/preprocessor/punctuation/remove_parens.hpp>
#include <boost/preprocessor/seq/for_each.hpp>
#include <boost/preprocessor/seq/for_each_i.hpp>
#include <boost/preprocessor/seq/pop_front.hpp>
#include <boost/preprocessor/stringize.hpp>
#include <boost/preprocessor/tuple/elem.hpp>
#include <boost/preprocessor/tuple/size.hpp>
#include <boost/preprocessor/tuple/to_seq.hpp>
#include "CompilerAttributes.h"
#include "Logging.h"
#include "StringView.h"
// Input: (A,2) A (A)
// Output: ((A,2)) ((A)) ((A))
#define MY_ENUM_DETAILS_OP_MAKE_TUPLE(dummy1, dummy2, ENUM) \
((BOOST_PP_REMOVE_PARENS(ENUM)))
// Input: (A, (B,2) , C)
// Output: ((A))((B,2))((C))
#define MY_ENUM_DETAILS_TO_SEQ_OF_TUPLES(...) \
BOOST_PP_SEQ_FOR_EACH(MY_ENUM_DETAILS_OP_MAKE_TUPLE, _, \
BOOST_PP_TUPLE_TO_SEQ(__VA_ARGS__))
// INPUT: size_t, (a,b, ...)
// Output: size_t
//
// INPUT: (a,b, ...)
// Output: int
#define MY_ENUM_DETAILS_GET_INT_TYPE(...) \
BOOST_PP_IF(BOOST_PP_EQUAL(BOOST_PP_TUPLE_SIZE((__VA_ARGS__)), 2), \
BOOST_PP_TUPLE_ELEM(0, (__VA_ARGS__)), int)
// INPUT: size_t, (a,b, ...)
// Output: (a,b, ...)
//
// INPUT: (a,b, ...)
// Output: (a,b, ...)
#define MY_ENUM_DETAILS_GET_VARS(...) \
BOOST_PP_REMOVE_PARENS( \
BOOST_PP_IF(BOOST_PP_EQUAL(BOOST_PP_TUPLE_SIZE((__VA_ARGS__)), 2), \
(BOOST_PP_TUPLE_ELEM(1, (__VA_ARGS__))), (__VA_ARGS__)))
// INPUT: (A,2) B (C,3)
// Output: , A=2 , B , C=3
#define MY_ENUM_DETAILS_OP_VALUE_WITH_INIT(PAIR) \
BOOST_PP_IF(BOOST_PP_EQUAL(BOOST_PP_TUPLE_SIZE(PAIR), 1), \
BOOST_PP_TUPLE_ELEM(0, PAIR), \
BOOST_PP_TUPLE_ELEM(0, PAIR) = BOOST_PP_TUPLE_ELEM(1, PAIR))
// INPUT: (A,2) B (C,3)
// Output: , A=2 , B , C=3
#define MY_ENUM_DETAILS_OP_COMMA_VALUE(dummy1, dummy2, PAIR) \
, MY_ENUM_DETAILS_OP_VALUE_WITH_INIT(PAIR)
// Input: ((A,2), B, C)
// Output: A=2, B, C
#define MY_ENUM_DETAILS_CSV(...) \
MY_ENUM_DETAILS_OP_VALUE_WITH_INIT( \
BOOST_PP_SEQ_ELEM(0, MY_ENUM_DETAILS_TO_SEQ_OF_TUPLES(__VA_ARGS__))) \
BOOST_PP_SEQ_FOR_EACH( \
MY_ENUM_DETAILS_OP_COMMA_VALUE, _, \
BOOST_PP_SEQ_POP_FRONT(MY_ENUM_DETAILS_TO_SEQ_OF_TUPLES(__VA_ARGS__)))
// Output:
// case ${TYPE}::${PAIR}[0]: {
// return "${PAIR}[0]";
// }
#define MY_ENUM_DETAILS_OP_TO_STRING_CASE(dummy1, TYPE, PAIR) \
case TYPE::BOOST_PP_TUPLE_ELEM(0, PAIR): { \
return BOOST_PP_STRINGIZE(BOOST_PP_TUPLE_ELEM(0, PAIR)); \
}
// Output:
// case ${TYPE}::${PAIR}[0]: {
// return "${PAIR}[0]" + std::string(" (=") +
// std::to_string(INT_TYPE(value)) + std::string(")");
// }
#define MY_ENUM_DETAILS_OP_TO_PRETTY_CASE(dummy, types, PAIR) \
case BOOST_PP_TUPLE_ELEM(0, types)::BOOST_PP_TUPLE_ELEM(0, PAIR): { \
return BOOST_PP_STRINGIZE(BOOST_PP_TUPLE_ELEM(0, PAIR)) + std::string(" (=") + \
std::to_string(BOOST_PP_TUPLE_ELEM(1, types)(value)) + \
std::string(")"); \
}
// Output:
// if (str == "${PAIR}[0]") {
// value = ${TYPE}::${PAIR}[0];
// return true;
// }
#define MY_ENUM_DETAILS_OP_SET_VALUE_CASES(dummy1, TYPE, PAIR) \
if (str == BOOST_PP_STRINGIZE(BOOST_PP_TUPLE_ELEM(0, PAIR))) { \
value = TYPE::BOOST_PP_TUPLE_ELEM(0, PAIR); \
return true; \
}
// Output: , "${PAIR}[0]"
#define MY_ENUM_DETAILS_OP_COMMA_STRING(dummy1, dummy2, PAIR) \
, BOOST_PP_STRINGIZE(BOOST_PP_TUPLE_ELEM(0, PAIR))
// Input: (A, (B,3), (C,5))
// Output: "A", "B", "C"
#define MY_ENUM_DETAILS_COMMA_SEP_STRINGS(...) \
BOOST_PP_STRINGIZE(BOOST_PP_TUPLE_ELEM( \
0, BOOST_PP_SEQ_ELEM(0, MY_ENUM_DETAILS_TO_SEQ_OF_TUPLES(__VA_ARGS__)))) \
BOOST_PP_SEQ_FOR_EACH( \
MY_ENUM_DETAILS_OP_COMMA_STRING, _, \
BOOST_PP_SEQ_POP_FRONT(MY_ENUM_DETAILS_TO_SEQ_OF_TUPLES(__VA_ARGS__)))
// Output: ", ${PAIR}[0]"
#define MY_ENUM_DETAILS_OP_COMMA_VALUE_STRING(dummy1, dummy2, PAIR) \
", " BOOST_PP_STRINGIZE(BOOST_PP_TUPLE_ELEM(0, PAIR))
// Output: case ${TYPE}::${PAIR}[0]: { return ${i}; }
#define MY_ENUM_DETAILS_OP_POSITION_ICASE(dummy, TYPE, I, PAIR) \
case TYPE::BOOST_PP_TUPLE_ELEM(0, PAIR): { \
return I; \
}
// Input: (A, (B, 5), C)
// Output: "A, B, C"
#define MY_ENUM_DETAILS_CSV_STRING(...) \
BOOST_PP_STRINGIZE(BOOST_PP_TUPLE_ELEM( \
0, BOOST_PP_SEQ_ELEM(0, MY_ENUM_DETAILS_TO_SEQ_OF_TUPLES(__VA_ARGS__)))) \
BOOST_PP_SEQ_FOR_EACH( \
MY_ENUM_DETAILS_OP_COMMA_VALUE_STRING, _, \
BOOST_PP_SEQ_POP_FRONT(MY_ENUM_DETAILS_TO_SEQ_OF_TUPLES(__VA_ARGS__)))
// Output: , ${TYPES}[1](${TYPES}[0]::${PAIR}[0])
#define MY_ENUM_DETAILS_OP_INTS(dummy, TYPES, PAIR) \
, BOOST_PP_TUPLE_ELEM( \
1, TYPES)(BOOST_PP_TUPLE_ELEM(0, TYPES)::BOOST_PP_TUPLE_ELEM(0, PAIR))
// Input: (A, (B,5), (C,11))
// Output: 0, 5, 11
//
// Note: Here, "0, 5, 11" are the values of "A, B, C".
#define MY_ENUM_DETAILS_COMMA_SEP_INTS(TYPE, INT_TYPE, ...) \
INT_TYPE(TYPE::BOOST_PP_TUPLE_ELEM( \
0, BOOST_PP_SEQ_ELEM(0, MY_ENUM_DETAILS_TO_SEQ_OF_TUPLES(__VA_ARGS__)))) \
BOOST_PP_SEQ_FOR_EACH( \
MY_ENUM_DETAILS_OP_INTS, (TYPE, INT_TYPE), \
BOOST_PP_SEQ_POP_FRONT(MY_ENUM_DETAILS_TO_SEQ_OF_TUPLES(__VA_ARGS__)))
#define MY_ENUM_DEF_IMPL(NAME, ...) \
namespace enum_wrapper_ { \
enum class NAME##Impl : MY_ENUM_DETAILS_GET_INT_TYPE(__VA_ARGS__){ \
MY_ENUM_DETAILS_CSV(MY_ENUM_DETAILS_GET_VARS(__VA_ARGS__))}; \
\
MY_ENUM_MAYBE_UNUSED inline std::string toString(NAME##Impl value) { \
switch (value) { \
BOOST_PP_SEQ_FOR_EACH(MY_ENUM_DETAILS_OP_TO_STRING_CASE, NAME##Impl, \
MY_ENUM_DETAILS_TO_SEQ_OF_TUPLES( \
MY_ENUM_DETAILS_GET_VARS(__VA_ARGS__))) \
} \
MY_ENUM_ABORT( \
BOOST_PP_STRINGIZE(NAME) " does contain invalid value: {}", \
MY_ENUM_DETAILS_GET_INT_TYPE(__VA_ARGS__)(value)); \
} \
\
MY_ENUM_MAYBE_UNUSED inline MY_ENUM_STRING_VIEW toStringView( \
NAME##Impl value) { \
switch (value) { \
BOOST_PP_SEQ_FOR_EACH(MY_ENUM_DETAILS_OP_TO_STRING_CASE, NAME##Impl, \
MY_ENUM_DETAILS_TO_SEQ_OF_TUPLES( \
MY_ENUM_DETAILS_GET_VARS(__VA_ARGS__))) \
} \
MY_ENUM_ABORT( \
BOOST_PP_STRINGIZE(NAME) " does contain invalid value: {}", \
MY_ENUM_DETAILS_GET_INT_TYPE(__VA_ARGS__)(value)); \
} \
\
MY_ENUM_MAYBE_UNUSED inline std::string toPretty(NAME##Impl value) { \
switch (value) { \
BOOST_PP_SEQ_FOR_EACH( \
MY_ENUM_DETAILS_OP_TO_PRETTY_CASE, \
(NAME##Impl, MY_ENUM_DETAILS_GET_INT_TYPE(__VA_ARGS__)), \
MY_ENUM_DETAILS_TO_SEQ_OF_TUPLES( \
MY_ENUM_DETAILS_GET_VARS(__VA_ARGS__))) \
} \
MY_ENUM_ABORT( \
BOOST_PP_STRINGIZE(NAME) " does contain invalid value: {}", \
MY_ENUM_DETAILS_GET_INT_TYPE(__VA_ARGS__)(value)); \
} \
\
MY_ENUM_MAYBE_UNUSED MY_ENUM_NODISCARD inline bool trySetFromString( \
NAME##Impl &value, const MY_ENUM_STRING_VIEW &str) { \
BOOST_PP_SEQ_FOR_EACH(MY_ENUM_DETAILS_OP_SET_VALUE_CASES, NAME##Impl, \
MY_ENUM_DETAILS_TO_SEQ_OF_TUPLES( \
MY_ENUM_DETAILS_GET_VARS(__VA_ARGS__))) \
return false; \
} \
\
MY_ENUM_MAYBE_UNUSED MY_ENUM_NODISCARD constexpr size_t getCount( \
NAME##Impl) { \
return BOOST_PP_TUPLE_SIZE(MY_ENUM_DETAILS_GET_VARS(__VA_ARGS__)); \
} \
\
MY_ENUM_MAYBE_UNUSED \
MY_ENUM_NODISCARD inline std::array< \
MY_ENUM_STRING_VIEW, \
BOOST_PP_TUPLE_SIZE(MY_ENUM_DETAILS_GET_VARS(__VA_ARGS__))> \
getStrings(NAME##Impl) { \
return {MY_ENUM_DETAILS_COMMA_SEP_STRINGS( \
MY_ENUM_DETAILS_GET_VARS(__VA_ARGS__))}; \
} \
\
MY_ENUM_MAYBE_UNUSED MY_ENUM_NODISCARD inline MY_ENUM_STRING_VIEW \
getStringOfNames(NAME##Impl) { \
return MY_ENUM_DETAILS_CSV_STRING(MY_ENUM_DETAILS_GET_VARS(__VA_ARGS__)); \
} \
\
MY_ENUM_MAYBE_UNUSED MY_ENUM_NODISCARD constexpr std::array< \
MY_ENUM_DETAILS_GET_INT_TYPE(__VA_ARGS__), \
BOOST_PP_TUPLE_SIZE(MY_ENUM_DETAILS_GET_VARS(__VA_ARGS__))> \
getValues(NAME##Impl) { \
return {MY_ENUM_DETAILS_COMMA_SEP_INTS( \
NAME##Impl, MY_ENUM_DETAILS_GET_INT_TYPE(__VA_ARGS__), \
MY_ENUM_DETAILS_GET_VARS(__VA_ARGS__))}; \
} \
\
MY_ENUM_MAYBE_UNUSED MY_ENUM_NODISCARD constexpr size_t getPosition( \
NAME##Impl value) { \
switch (value) { \
BOOST_PP_SEQ_FOR_EACH_I(MY_ENUM_DETAILS_OP_POSITION_ICASE, NAME##Impl, \
MY_ENUM_DETAILS_TO_SEQ_OF_TUPLES( \
MY_ENUM_DETAILS_GET_VARS(__VA_ARGS__))) \
} \
MY_ENUM_ABORT( \
BOOST_PP_STRINGIZE(NAME) " does contain invalid value: {}", \
MY_ENUM_DETAILS_GET_INT_TYPE(__VA_ARGS__)(value)); \
} \
\
MY_ENUM_MAYBE_UNUSED MY_ENUM_NODISCARD inline MY_ENUM_STRING_VIEW \
getTypeName(NAME##Impl) { \
return BOOST_PP_STRINGIZE(NAME); \
} \
} // namespace enum_wrapper_