farm-ng-core
enum_details.h
Go to the documentation of this file.
1 // Copyright 2022, farm-ng inc.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 // Copyright (c) Facebook, Inc. and its affiliates.
16 //
17 // This source code is licensed under the MIT license found in the
18 // LICENSE file in the root directory of this source tree.
19 
20 #pragma once
21 
22 #include <farm_pp/preprocessor/comparison/equal.hpp>
23 #include <farm_pp/preprocessor/control/if.hpp>
24 #include <farm_pp/preprocessor/punctuation/remove_parens.hpp>
25 #include <farm_pp/preprocessor/seq/for_each.hpp>
26 #include <farm_pp/preprocessor/seq/for_each_i.hpp>
27 #include <farm_pp/preprocessor/seq/pop_front.hpp>
28 #include <farm_pp/preprocessor/stringize.hpp>
29 #include <farm_pp/preprocessor/tuple/elem.hpp>
30 #include <farm_pp/preprocessor/tuple/size.hpp>
31 #include <farm_pp/preprocessor/tuple/to_seq.hpp>
32 
33 #include <array>
34 #include <string>
35 #include <string_view>
36 
37 // Input: (A,2) A (A)
38 // Output: ((A,2)) ((A)) ((A))
39 #define FARM_ENUM_DETAILS_OP_MAKE_TUPLE(dummy1, dummy2, ENUM) \
40  ((FARM_PP_REMOVE_PARENS(ENUM)))
41 
42 // Input: (A, (B,2) , C)
43 // Output: ((A))((B,2))((C))
44 #define FARM_ENUM_DETAILS_TO_SEQ_OF_TUPLES(...) \
45  FARM_PP_SEQ_FOR_EACH( \
46  FARM_ENUM_DETAILS_OP_MAKE_TUPLE, _, FARM_PP_TUPLE_TO_SEQ(__VA_ARGS__))
47 
48 // INPUT: size_t, (a,b, ...)
49 // Output: size_t
50 //
51 // INPUT: (a,b, ...)
52 // Output: int
53 #define FARM_ENUM_DETAILS_GET_INT_TYPE(...) \
54  FARM_PP_IF( \
55  FARM_PP_EQUAL(FARM_PP_TUPLE_SIZE((__VA_ARGS__)), 2), \
56  FARM_PP_TUPLE_ELEM(0, (__VA_ARGS__)), \
57  int)
58 
59 // INPUT: size_t, (a,b, ...)
60 // Output: (a,b, ...)
61 //
62 // INPUT: (a,b, ...)
63 // Output: (a,b, ...)
64 #define FARM_ENUM_DETAILS_GET_VARS(...) \
65  FARM_PP_REMOVE_PARENS(FARM_PP_IF( \
66  FARM_PP_EQUAL(FARM_PP_TUPLE_SIZE((__VA_ARGS__)), 2), \
67  (FARM_PP_TUPLE_ELEM(1, (__VA_ARGS__))), \
68  (__VA_ARGS__)))
69 
70 // INPUT: (A,2) B (C,3)
71 // Output: A=2 B C=3
72 #define FARM_ENUM_DETAILS_OP_VALUE_WITH_INIT(PAIR) \
73  FARM_PP_IF( \
74  FARM_PP_EQUAL(FARM_PP_TUPLE_SIZE(PAIR), 1), \
75  FARM_PP_TUPLE_ELEM(0, PAIR), \
76  FARM_PP_TUPLE_ELEM(0, PAIR) = FARM_PP_TUPLE_ELEM(1, PAIR))
77 
78 // INPUT: (A,2) B (C,3)
79 // Output: NAMEImpl::A NAMEImpl::B NAMEImpl::C
80 #define FARM_ENUM_DETAILS_ENUM_NS_OP(NAME, PAIR) \
81  NAME##Impl::FARM_PP_TUPLE_ELEM(0, PAIR)
82 
83 // INPUT: (A,2) B (C,3)
84 // Output: , A=2 , B , C=3
85 #define FARM_ENUM_DETAILS_OP_COMMA_VALUE(dummy1, dummy2, PAIR) \
86  , FARM_ENUM_DETAILS_OP_VALUE_WITH_INIT(PAIR)
87 
88 // INPUT: (A,2) B (C,3)
89 // Output: , A , B , C
90 #define FARM_ENUM_DETAILS_NS_OP_COMMA(dummy1, NAME, PAIR) \
91  , FARM_ENUM_DETAILS_ENUM_NS_OP(NAME, PAIR)
92 
93 // Input: ((A,2), B, C)
94 // Output: A=2, B, C
95 #define FARM_ENUM_DETAILS_CSV(...) \
96  FARM_ENUM_DETAILS_OP_VALUE_WITH_INIT( \
97  FARM_PP_SEQ_ELEM(0, FARM_ENUM_DETAILS_TO_SEQ_OF_TUPLES(__VA_ARGS__))) \
98  FARM_PP_SEQ_FOR_EACH( \
99  FARM_ENUM_DETAILS_OP_COMMA_VALUE, \
100  _, \
101  FARM_PP_SEQ_POP_FRONT(FARM_ENUM_DETAILS_TO_SEQ_OF_TUPLES(__VA_ARGS__)))
102 
103 // Input: ((A,2), B, C)
104 // Output: A, B, C
105 #define FARM_ENUM_NS_ENUM_CSV(NAME, ...) \
106  FARM_ENUM_DETAILS_ENUM_NS_OP( \
107  NAME, \
108  FARM_PP_SEQ_ELEM(0, FARM_ENUM_DETAILS_TO_SEQ_OF_TUPLES(__VA_ARGS__))) \
109  FARM_PP_SEQ_FOR_EACH( \
110  FARM_ENUM_DETAILS_NS_OP_COMMA, \
111  NAME, \
112  FARM_PP_SEQ_POP_FRONT(FARM_ENUM_DETAILS_TO_SEQ_OF_TUPLES(__VA_ARGS__)))
113 
114 // Output:
115 // case ${TYPE}::${PAIR}[0]: {
116 // return "${PAIR}[0]";
117 // }
118 #define FARM_ENUM_DETAILS_OP_TO_STRING_CASE(dummy1, TYPE, PAIR) \
119  case TYPE::FARM_PP_TUPLE_ELEM(0, PAIR): { \
120  return FARM_PP_STRINGIZE(FARM_PP_TUPLE_ELEM(0, PAIR)); \
121  }
122 
123 // Output:
124 // case ${TYPE}::${PAIR}[0]: {
125 // return "${PAIR}[0]" + std::string(" (=") +
126 // std::to_string(INT_TYPE(value)) + std::string(")");
127 // }
128 #define FARM_ENUM_DETAILS_OP_TO_PRETTY_CASE(dummy, types, PAIR) \
129  case FARM_PP_TUPLE_ELEM(0, types)::FARM_PP_TUPLE_ELEM(0, PAIR): { \
130  return FARM_PP_STRINGIZE(FARM_PP_TUPLE_ELEM(0, PAIR)) + \
131  std::string(" (=") + \
132  std::to_string(FARM_PP_TUPLE_ELEM(1, types)(value)) + \
133  std::string(")"); \
134  }
135 
136 // Output:
137 // if (str == "${PAIR}[0]") {
138 // value = ${TYPE}::${PAIR}[0];
139 // return true;
140 // }
141 #define FARM_ENUM_DETAILS_OP_SET_VALUE_CASES(dummy1, TYPE, PAIR) \
142  if (str == FARM_PP_STRINGIZE(FARM_PP_TUPLE_ELEM(0, PAIR))) { \
143  value = TYPE::FARM_PP_TUPLE_ELEM(0, PAIR); \
144  return true; \
145  }
146 
147 // Output: , "${PAIR}[0]"
148 #define FARM_ENUM_DETAILS_OP_COMMA_STRING(dummy1, dummy2, PAIR) \
149  , FARM_PP_STRINGIZE(FARM_PP_TUPLE_ELEM(0, PAIR))
150 
151 // Input: (A, (B,3), (C,5))
152 // Output: "A", "B", "C"
153 #define FARM_ENUM_DETAILS_COMMA_SEP_STRINGS(...) \
154  FARM_PP_STRINGIZE(FARM_PP_TUPLE_ELEM( \
155  0, \
156  FARM_PP_SEQ_ELEM(0, FARM_ENUM_DETAILS_TO_SEQ_OF_TUPLES(__VA_ARGS__)))) \
157  FARM_PP_SEQ_FOR_EACH( \
158  FARM_ENUM_DETAILS_OP_COMMA_STRING, \
159  _, \
160  FARM_PP_SEQ_POP_FRONT(FARM_ENUM_DETAILS_TO_SEQ_OF_TUPLES(__VA_ARGS__)))
161 
162 // Output: ", ${PAIR}[0]"
163 #define FARM_ENUM_DETAILS_OP_COMMA_VALUE_STRING(dummy1, dummy2, PAIR) \
164  ", " FARM_PP_STRINGIZE(FARM_PP_TUPLE_ELEM(0, PAIR))
165 
166 // Output: case ${TYPE}::${PAIR}[0]: { return ${i}; }
167 #define FARM_ENUM_DETAILS_OP_POSITION_ICASE(dummy, TYPE, I, PAIR) \
168  case TYPE::FARM_PP_TUPLE_ELEM(0, PAIR): { \
169  return I; \
170  }
171 
172 // Input: (A, (B, 5), C)
173 // Output: "A, B, C"
174 #define FARM_ENUM_DETAILS_CSV_STRING(...) \
175  FARM_PP_STRINGIZE(FARM_PP_TUPLE_ELEM( \
176  0, \
177  FARM_PP_SEQ_ELEM(0, FARM_ENUM_DETAILS_TO_SEQ_OF_TUPLES(__VA_ARGS__)))) \
178  FARM_PP_SEQ_FOR_EACH( \
179  FARM_ENUM_DETAILS_OP_COMMA_VALUE_STRING, \
180  _, \
181  FARM_PP_SEQ_POP_FRONT(FARM_ENUM_DETAILS_TO_SEQ_OF_TUPLES(__VA_ARGS__)))
182 
183 // Output: , ${TYPES}[1](${TYPES}[0]::${PAIR}[0])
184 #define FARM_ENUM_DETAILS_OP_INTS(dummy, TYPES, PAIR) \
185  , FARM_PP_TUPLE_ELEM( \
186  1, TYPES)(FARM_PP_TUPLE_ELEM(0, TYPES)::FARM_PP_TUPLE_ELEM(0, PAIR))
187 
188 // Input: (A, (B,5), (C,11))
189 // Output: 0, 5, 11
190 //
191 // Note: Here, "0, 5, 11" are the values of "A, B, C".
192 #define FARM_ENUM_DETAILS_COMMA_SEP_INTS(TYPE, INT_TYPE, ...) \
193  INT_TYPE(TYPE::FARM_PP_TUPLE_ELEM( \
194  0, \
195  FARM_PP_SEQ_ELEM(0, FARM_ENUM_DETAILS_TO_SEQ_OF_TUPLES(__VA_ARGS__)))) \
196  FARM_PP_SEQ_FOR_EACH( \
197  FARM_ENUM_DETAILS_OP_INTS, \
198  (TYPE, INT_TYPE), \
199  FARM_PP_SEQ_POP_FRONT(FARM_ENUM_DETAILS_TO_SEQ_OF_TUPLES(__VA_ARGS__)))
200 
201 #define FARM_ENUM_DEF_IMPL(NAME, ...) \
202  namespace enum_wrapper_ { \
203  enum class NAME##Impl : FARM_ENUM_DETAILS_GET_INT_TYPE(__VA_ARGS__){ \
204  FARM_ENUM_DETAILS_CSV(FARM_ENUM_DETAILS_GET_VARS(__VA_ARGS__))}; \
205  \
206  [[maybe_unused]] inline auto toString(NAME##Impl value) -> std::string { \
207  switch (value) { \
208  FARM_PP_SEQ_FOR_EACH( \
209  FARM_ENUM_DETAILS_OP_TO_STRING_CASE, \
210  NAME##Impl, \
211  FARM_ENUM_DETAILS_TO_SEQ_OF_TUPLES( \
212  FARM_ENUM_DETAILS_GET_VARS(__VA_ARGS__))) \
213  } \
214  std::abort(); \
215  } \
216  \
217  [[maybe_unused]] inline auto constexpr toStringView(NAME##Impl value) \
218  -> std::string_view { \
219  switch (value) { \
220  FARM_PP_SEQ_FOR_EACH( \
221  FARM_ENUM_DETAILS_OP_TO_STRING_CASE, \
222  NAME##Impl, \
223  FARM_ENUM_DETAILS_TO_SEQ_OF_TUPLES( \
224  FARM_ENUM_DETAILS_GET_VARS(__VA_ARGS__))) \
225  } \
226  std::abort(); \
227  } \
228  \
229  [[maybe_unused]] inline auto toPretty(NAME##Impl value) -> std::string { \
230  switch (value) { \
231  FARM_PP_SEQ_FOR_EACH( \
232  FARM_ENUM_DETAILS_OP_TO_PRETTY_CASE, \
233  (NAME##Impl, FARM_ENUM_DETAILS_GET_INT_TYPE(__VA_ARGS__)), \
234  FARM_ENUM_DETAILS_TO_SEQ_OF_TUPLES( \
235  FARM_ENUM_DETAILS_GET_VARS(__VA_ARGS__))) \
236  } \
237  std::abort(); \
238  } \
239  \
240  [[maybe_unused]] [[nodiscard]] inline auto trySetFromString( \
241  NAME##Impl &value, std::string const &str) -> bool { \
242  FARM_PP_SEQ_FOR_EACH( \
243  FARM_ENUM_DETAILS_OP_SET_VALUE_CASES, \
244  NAME##Impl, \
245  FARM_ENUM_DETAILS_TO_SEQ_OF_TUPLES( \
246  FARM_ENUM_DETAILS_GET_VARS(__VA_ARGS__))) \
247  return false; \
248  } \
249  \
250  [[maybe_unused]] [[nodiscard]] auto constexpr getCount(NAME##Impl) \
251  -> size_t { \
252  return FARM_PP_TUPLE_SIZE(FARM_ENUM_DETAILS_GET_VARS(__VA_ARGS__)); \
253  } \
254  \
255  [[maybe_unused]] [[nodiscard]] inline auto getStrings(NAME##Impl) \
256  -> std::array< \
257  std::string_view, \
258  FARM_PP_TUPLE_SIZE(FARM_ENUM_DETAILS_GET_VARS(__VA_ARGS__))> { \
259  return {FARM_ENUM_DETAILS_COMMA_SEP_STRINGS( \
260  FARM_ENUM_DETAILS_GET_VARS(__VA_ARGS__))}; \
261  } \
262  \
263  [[maybe_unused]] [[nodiscard]] inline auto getStringOfNames(NAME##Impl) \
264  -> std::string_view { \
265  return FARM_ENUM_DETAILS_CSV_STRING( \
266  FARM_ENUM_DETAILS_GET_VARS(__VA_ARGS__)); \
267  } \
268  \
269  [[maybe_unused]] [[nodiscard]] auto constexpr getValues(NAME##Impl) \
270  -> std::array< \
271  FARM_ENUM_DETAILS_GET_INT_TYPE(__VA_ARGS__), \
272  FARM_PP_TUPLE_SIZE(FARM_ENUM_DETAILS_GET_VARS(__VA_ARGS__))> { \
273  return {FARM_ENUM_DETAILS_COMMA_SEP_INTS( \
274  NAME##Impl, \
275  FARM_ENUM_DETAILS_GET_INT_TYPE(__VA_ARGS__), \
276  FARM_ENUM_DETAILS_GET_VARS(__VA_ARGS__))}; \
277  } \
278  \
279  [[maybe_unused]] [[nodiscard]] auto constexpr getAll(NAME##Impl) \
280  -> std::array< \
281  NAME##Impl, \
282  FARM_PP_TUPLE_SIZE(FARM_ENUM_DETAILS_GET_VARS(__VA_ARGS__))> { \
283  /* return {NAME##Impl::apple, NAME##Impl::banana, NAME##Impl::pear}; */ \
284  return { \
285  FARM_ENUM_NS_ENUM_CSV(NAME, FARM_ENUM_DETAILS_GET_VARS(__VA_ARGS__))}; \
286  } \
287  \
288  [[maybe_unused]] [[nodiscard]] auto constexpr getPosition(NAME##Impl value) \
289  -> size_t { \
290  switch (value) { \
291  FARM_PP_SEQ_FOR_EACH_I( \
292  FARM_ENUM_DETAILS_OP_POSITION_ICASE, \
293  NAME##Impl, \
294  FARM_ENUM_DETAILS_TO_SEQ_OF_TUPLES( \
295  FARM_ENUM_DETAILS_GET_VARS(__VA_ARGS__))) \
296  } \
297  std::abort(); \
298  } \
299  \
300  [[maybe_unused]] [[nodiscard]] inline auto getTypeName(NAME##Impl) \
301  -> std::string_view { \
302  return FARM_PP_STRINGIZE(NAME); \
303  } \
304  } // namespace enum_wrapper_