Go to the documentation of this file.
22 #include <farm_pp/preprocessor/seq/for_each.hpp>
23 #include <farm_pp/preprocessor/seq/for_each_i.hpp>
24 #include <farm_pp/preprocessor/seq/pop_front.hpp>
25 #include <farm_pp/preprocessor/stringize.hpp>
26 #include <farm_pp/preprocessor/tuple/elem.hpp>
27 #include <farm_pp/preprocessor/tuple/size.hpp>
28 #include <farm_pp/preprocessor/tuple/to_seq.hpp>
32 #include <string_view>
33 #include <type_traits>
36 #define FARM_ENUMFLAGS_DETAILS_OP_INIT_FLAG(dummy1, dummy2, I, FLAG) \
37 , FLAG = (1 << (I + 1))
41 #define FARM_ENUMFLAGS_DETAILS_FLAG_DEFINITIONS(...) \
42 FARM_PP_TUPLE_ELEM(0, __VA_ARGS__) = 1 FARM_PP_SEQ_FOR_EACH_I( \
43 FARM_ENUMFLAGS_DETAILS_OP_INIT_FLAG, \
45 FARM_PP_SEQ_POP_FRONT(FARM_PP_TUPLE_TO_SEQ(__VA_ARGS__)))
52 #define FARM_ENUMFLAG_DETAILS_OP_SET_ENUM_FROM_STRING(dummy1, TYPE, FLAG) \
53 if (str == FARM_PP_STRINGIZE(FLAG)) { \
54 value = value | TYPE::FLAG; \
65 #if (defined __linux__ || defined __APPLE__)
66 #define FARM_ENUMFLAG_DETAILS_OP_SINGLE_FLAG_CHECK(dummy1, TYPE, FLAG) \
69 __builtin_popcount(uint64_t(TYPE::FLAG)) == 1, \
70 FARM_PP_STRINGIZE(FLAG) " must be a single bit flag"); \
74 #define FARM_ENUMFLAG_DETAILS_OP_SINGLE_FLAG_CHECK(dummy1, TYPE, FLAG) \
84 #define FARM_ENUMFLAG_DETAILS_OP_PUSHBACK_STRING(dummy1, TYPE, FLAG) \
85 if (hasMask(value, TYPE::FLAG)) { \
86 strings.push_back(FARM_PP_STRINGIZE(FLAG)); \
93 #define FARM_ENUMFLAG_DETAILS_OP_STRING_FOR_FLAG(dummy1, TYPE, FLAG) \
94 if (hasMask(value, TYPE::FLAG)) { \
96 FARM_PP_STRINGIZE(FLAG) " (=" + std::to_string(uint64_t(TYPE::FLAG)) + \
101 #define FARM_ENUMFLAGS_DETAILS_OP_COMMA_STRING(dummy1, dummy2, STRING) \
102 , FARM_PP_STRINGIZE(STRING)
106 #define FARM_ENUMFLAGS_DETAILS_COMMA_SEP_STRINGS(...) \
107 FARM_PP_STRINGIZE(FARM_PP_TUPLE_ELEM(0, __VA_ARGS__)) \
108 FARM_PP_SEQ_FOR_EACH( \
109 FARM_ENUMFLAGS_DETAILS_OP_COMMA_STRING, \
111 FARM_PP_SEQ_POP_FRONT(FARM_PP_TUPLE_TO_SEQ(__VA_ARGS__)))
114 #define FARM_ENUMFLAGS_DETAILS_OP_COMMA_VALUE_STRING(dummy1, dummy2, STRING) \
115 ", " FARM_PP_STRINGIZE(STRING)
119 #define FARM_ENUMFLAGS_DETAILS_CSV_STRING(...) \
120 FARM_PP_STRINGIZE(FARM_PP_TUPLE_ELEM(0, __VA_ARGS__)) \
121 FARM_PP_SEQ_FOR_EACH( \
122 FARM_ENUMFLAGS_DETAILS_OP_COMMA_VALUE_STRING, \
124 FARM_PP_SEQ_POP_FRONT(FARM_PP_TUPLE_TO_SEQ(__VA_ARGS__)))
127 #define FARM_ENUMFLAGS_DETAILS_OP_COMMA_INT(dummy1, TYPE, VAL) \
128 , uint64_t(TYPE::VAL)
134 #define FARM_ENUMFLAGS_DETAILS_COMMA_SEP_INTS(TYPE, ...) \
135 uint64_t(TYPE::FARM_PP_TUPLE_ELEM(0, __VA_ARGS__)) FARM_PP_SEQ_FOR_EACH( \
136 FARM_ENUMFLAGS_DETAILS_OP_COMMA_INT, \
138 FARM_PP_SEQ_POP_FRONT(FARM_PP_TUPLE_TO_SEQ(__VA_ARGS__)))
140 #define FARM_ENUMFLAGS_DEF_IMPL(NAME, UINT_TYPE, ...) \
141 namespace enum_wrapper_ { \
144 std::is_unsigned<UINT_TYPE>::value, \
145 FARM_PP_STRINGIZE(UINT_TYPE) " must be an unsigned integer type"); \
147 enum class NAME##Impl : UINT_TYPE{ \
148 none = 0u, FARM_ENUMFLAGS_DETAILS_FLAG_DEFINITIONS(__VA_ARGS__)}; \
150 inline auto constexpr operator|(NAME##Impl left, NAME##Impl right) -> NAME \
152 return NAME##Impl(UINT_TYPE(left) | UINT_TYPE(right)); \
155 inline auto constexpr operator&(NAME##Impl left, NAME##Impl right) -> NAME \
157 return NAME##Impl(UINT_TYPE(left) & UINT_TYPE(right)); \
160 [[maybe_unused]] inline auto trySetFlagFromString( \
161 NAME##Impl &value, std::string const &str) -> bool { \
162 FARM_PP_SEQ_FOR_EACH( \
163 FARM_ENUMFLAG_DETAILS_OP_SET_ENUM_FROM_STRING, \
165 FARM_PP_TUPLE_TO_SEQ(__VA_ARGS__)) \
169 [[maybe_unused]] inline auto constexpr hasMask( \
170 NAME##Impl value, NAME##Impl mask) -> bool { \
171 return (value & mask) == mask; \
174 [[maybe_unused]] inline auto setMask(NAME##Impl &value, NAME##Impl mask) \
176 value = value | mask; \
179 [[maybe_unused]] inline auto clearMask(NAME##Impl &value, NAME##Impl mask) \
181 value = value & NAME##Impl(~UINT_TYPE(mask)); \
184 [[maybe_unused]] inline auto toggleMask(NAME##Impl &value, NAME##Impl mask) \
186 value = NAME##Impl(UINT_TYPE(value) ^ UINT_TYPE(mask)); \
189 [[maybe_unused]] inline auto constexpr isSingleFlag(NAME##Impl value) \
192 FARM_PP_SEQ_FOR_EACH( \
193 FARM_ENUMFLAG_DETAILS_OP_SINGLE_FLAG_CHECK, \
195 FARM_PP_TUPLE_TO_SEQ(__VA_ARGS__)) \
196 case NAME##Impl::none: \
202 [[maybe_unused]] inline auto toStrings(NAME##Impl value) \
203 -> std::vector<std::string> { \
204 std::vector<std::string> strings; \
205 FARM_PP_SEQ_FOR_EACH( \
206 FARM_ENUMFLAG_DETAILS_OP_PUSHBACK_STRING, \
208 FARM_PP_TUPLE_TO_SEQ(__VA_ARGS__)) \
212 [[maybe_unused]] inline auto toPretty(NAME##Impl value) -> std::string { \
213 std::string prettySet("{"); \
214 FARM_PP_SEQ_FOR_EACH( \
215 FARM_ENUMFLAG_DETAILS_OP_STRING_FOR_FLAG, \
217 FARM_PP_TUPLE_TO_SEQ(__VA_ARGS__)) \
218 prettySet += "} (=" + std::to_string(UINT_TYPE(value)) + ")"; \
222 [[maybe_unused]] [[nodiscard]] auto constexpr getCount(NAME##Impl) \
224 return FARM_PP_TUPLE_SIZE(__VA_ARGS__); \
227 [[maybe_unused]] [[nodiscard]] inline auto getNames(NAME##Impl) \
228 -> std::array<std::string_view, FARM_PP_TUPLE_SIZE(__VA_ARGS__)> { \
229 return {FARM_ENUMFLAGS_DETAILS_COMMA_SEP_STRINGS(__VA_ARGS__)}; \
232 [[maybe_unused]] [[nodiscard]] inline auto getStringOfNames(NAME##Impl) \
233 -> std::string_view { \
234 return FARM_ENUMFLAGS_DETAILS_CSV_STRING(__VA_ARGS__); \
237 [[maybe_unused]] [[nodiscard]] auto constexpr getValues(NAME##Impl) \
238 -> std::array<UINT_TYPE, FARM_PP_TUPLE_SIZE(__VA_ARGS__)> { \
239 return {FARM_ENUMFLAGS_DETAILS_COMMA_SEP_INTS(NAME##Impl, __VA_ARGS__)}; \
242 [[maybe_unused]] [[nodiscard]] inline auto constexpr getTypeName(NAME##Impl) \
243 -> std::string_view { \
244 return FARM_PP_STRINGIZE(NAME); \
246 } // namespace enum_wrapper_