LkEngine 0.1.2
 
Loading...
Searching...
No Matches
Enum.h
1/******************************************************************
2 * Enum
3 *
4 *******************************************************************/
5#pragma once
6
17#ifndef FORCEINLINE
18# if defined(LK_ENGINE_MSVC)
19# define FORCEINLINE __forceinline
20# elif defined(LK_ENGINE_GCC)
21# define FORCEINLINE __attribute__((always_inline))
22# elif defined(LK_ENGINE_CLANG)
23# define FORCEINLINE __forceinline
24# endif
25#endif
26
27#include <typeinfo>
28#include <type_traits>
29
30#define LK_INTERNAL_ENUM_RANGE_TYPE_CONTIGIOUS 0
31#define LK_INTERNAL_ENUM_RANGE_TYPE_VALUEARRAY 1
32#define LK_INTERNAL_ENUM_RANGE_TYPE_FLAG 2
33
34namespace LkEngine {
35
41 #define LK_ENUM_CLASS(EnumClass) \
42 using LK_Enum_##EnumClass = std::underlying_type_t<EnumClass>; \
43 inline EnumClass& operator|=(EnumClass& Lhs, EnumClass Rhs) { return Lhs = (EnumClass)(static_cast<LK_Enum_##EnumClass>(Lhs) | static_cast<LK_Enum_##EnumClass>(Rhs)); } \
44 inline EnumClass& operator&=(EnumClass& Lhs, EnumClass Rhs) { return Lhs = (EnumClass)(static_cast<LK_Enum_##EnumClass>(Lhs) & static_cast<LK_Enum_##EnumClass>(Rhs)); } \
45 inline EnumClass& operator^=(EnumClass& Lhs, EnumClass Rhs) { return Lhs = (EnumClass)(static_cast<LK_Enum_##EnumClass>(Lhs) ^ static_cast<LK_Enum_##EnumClass>(Rhs)); } \
46 inline constexpr EnumClass operator| (EnumClass Lhs, EnumClass Rhs) { return (EnumClass)(static_cast<LK_Enum_##EnumClass>(Lhs) | static_cast<LK_Enum_##EnumClass>(Rhs)); } \
47 inline constexpr LK_Enum_##EnumClass operator& (EnumClass Lhs, EnumClass Rhs) { return (LK_Enum_##EnumClass)(static_cast<LK_Enum_##EnumClass>(Lhs) & static_cast<LK_Enum_##EnumClass>(Rhs)); } \
48 inline constexpr EnumClass operator^ (EnumClass Lhs, EnumClass Rhs) { return (EnumClass)(static_cast<LK_Enum_##EnumClass>(Lhs) ^ static_cast<LK_Enum_##EnumClass>(Rhs)); } \
49 inline constexpr bool operator! (EnumClass E) { return !static_cast<LK_Enum_##EnumClass>(E); } \
50 inline constexpr EnumClass operator~ (EnumClass E) { return (EnumClass)~static_cast<LK_Enum_##EnumClass>(E); } \
51 inline constexpr LK_Enum_##EnumClass operator&(LK_Enum_##EnumClass Lhs, EnumClass Rhs) { return static_cast<LK_Enum_##EnumClass>(Lhs & static_cast<LK_Enum_##EnumClass>(Rhs)); } \
52 inline constexpr LK_Enum_##EnumClass operator&(EnumClass Lhs, LK_Enum_##EnumClass Rhs) { return static_cast<LK_Enum_##EnumClass>(static_cast<LK_Enum_##EnumClass>(Lhs) & Rhs); } \
53 inline constexpr LK_Enum_##EnumClass operator|(LK_Enum_##EnumClass Lhs, EnumClass Rhs) { return static_cast<LK_Enum_##EnumClass>(Lhs | static_cast<LK_Enum_##EnumClass>(Rhs)); } \
54 inline constexpr LK_Enum_##EnumClass operator|(EnumClass Lhs, LK_Enum_##EnumClass Rhs) { return static_cast<LK_Enum_##EnumClass>(static_cast<LK_Enum_##EnumClass>(Lhs) | Rhs); } \
55 inline constexpr LK_Enum_##EnumClass operator^(LK_Enum_##EnumClass Lhs, EnumClass Rhs) { return static_cast<LK_Enum_##EnumClass>(Lhs ^ static_cast<LK_Enum_##EnumClass>(Rhs)); } \
56 inline constexpr LK_Enum_##EnumClass operator^(EnumClass Lhs, LK_Enum_##EnumClass Rhs) { return static_cast<LK_Enum_##EnumClass>(static_cast<LK_Enum_##EnumClass>(Lhs) ^ Rhs); } \
57 inline constexpr bool operator<(EnumClass Lhs, LK_Enum_##EnumClass Rhs) { return static_cast<LK_Enum_##EnumClass>(static_cast<LK_Enum_##EnumClass>(Lhs) < Rhs); } \
58 inline constexpr bool operator<(LK_Enum_##EnumClass Lhs, EnumClass Rhs) { return static_cast<LK_Enum_##EnumClass>(Lhs < static_cast<LK_Enum_##EnumClass>(Rhs)); } \
59 inline constexpr bool operator>(EnumClass Lhs, LK_Enum_##EnumClass Rhs) { return static_cast<LK_Enum_##EnumClass>(static_cast<LK_Enum_##EnumClass>(Lhs) > Rhs); } \
60 inline constexpr bool operator>(LK_Enum_##EnumClass Lhs, EnumClass Rhs) { return static_cast<LK_Enum_##EnumClass>(Lhs > static_cast<LK_Enum_##EnumClass>(Rhs)); } \
61 inline constexpr bool operator<=(EnumClass Lhs, LK_Enum_##EnumClass Rhs) { return static_cast<LK_Enum_##EnumClass>(static_cast<LK_Enum_##EnumClass>(Lhs) <= Rhs); } \
62 inline constexpr bool operator<=(LK_Enum_##EnumClass Lhs, EnumClass Rhs) { return static_cast<LK_Enum_##EnumClass>(Lhs <= static_cast<LK_Enum_##EnumClass>(Rhs)); } \
63 inline constexpr bool operator>=(EnumClass Lhs, LK_Enum_##EnumClass Rhs) { return static_cast<LK_Enum_##EnumClass>(static_cast<LK_Enum_##EnumClass>(Lhs) >= Rhs); } \
64 inline constexpr bool operator>=(LK_Enum_##EnumClass Lhs, EnumClass Rhs) { return static_cast<LK_Enum_##EnumClass>(Lhs >= static_cast<LK_Enum_##EnumClass>(Rhs)); } \
65 inline LK_Enum_##EnumClass& operator|=(LK_Enum_##EnumClass& Lhs, EnumClass Rhs) { return Lhs = (LK_Enum_##EnumClass)(Lhs | static_cast<LK_Enum_##EnumClass>(Rhs)); } \
66 inline LK_Enum_##EnumClass& operator&=(LK_Enum_##EnumClass& Lhs, EnumClass Rhs) { return Lhs = (LK_Enum_##EnumClass)(Lhs & static_cast<LK_Enum_##EnumClass>(Rhs)); } \
67 inline EnumClass& operator&=(EnumClass& Lhs, LK_Enum_##EnumClass Rhs) { return Lhs = (EnumClass)(static_cast<LK_Enum_##EnumClass>(Lhs) & Rhs); } \
68 inline EnumClass& operator|=(EnumClass& Lhs, LK_Enum_##EnumClass Rhs) { return Lhs = (EnumClass)(static_cast<LK_Enum_##EnumClass>(Lhs) | Rhs); }
69
70
71 namespace Enum::Internal::Range
72 {
79 template<typename EnumType>
80 struct Type
81 {
82 enum { RangeType = -1 };
83 };
84
85 template<typename EnumType>
87 {
88 using IntType = std::underlying_type_t<EnumType>;
89
90 FORCEINLINE explicit TContiguousIterator(IntType InValue) : Value(InValue) {}
91
92 FORCEINLINE TContiguousIterator& operator++()
93 {
94 ++Value;
95 return *this;
96 }
97
98 FORCEINLINE EnumType operator*() const { return (EnumType)Value; }
99
100 private:
101 FORCEINLINE friend bool operator!=(const TContiguousIterator& Lhs, const TContiguousIterator& Rhs)
102 {
103 return (Lhs.Value != Rhs.Value);
104 }
105
106 private:
107 IntType Value;
108 };
109
110 template<typename EnumType>
112 {
113 FORCEINLINE explicit TValueArrayIterator(const EnumType* InPtr) : Ptr(InPtr) {}
114
115 FORCEINLINE TValueArrayIterator& operator++()
116 {
117 ++Ptr;
118 return *this;
119 }
120
121 FORCEINLINE EnumType operator*() const { return *Ptr; }
122
123 private:
124 FORCEINLINE friend bool operator!=(const TValueArrayIterator& Lhs, const TValueArrayIterator& Rhs)
125 {
126 return (Lhs.Ptr != Rhs.Ptr);
127 }
128
129 private:
130 const EnumType* Ptr;
131 };
132
136 template<typename EnumType>
138 {
139 using IntType = std::underlying_type_t<EnumType>;
140
141 FORCEINLINE explicit TFlagIterator(IntType Flags) : RemainingFlags(Flags) {}
142
143 FORCEINLINE TFlagIterator& operator++()
144 {
145 /* Clear the lowest set bit. */
146 RemainingFlags &= (RemainingFlags - 1);
147 return *this;
148 }
149
150 FORCEINLINE EnumType operator*() const
151 {
152 /* Extract the lowest set bit. */
153 IntType Flag = RemainingFlags & -RemainingFlags;
154 return static_cast<EnumType>(Flag);
155 }
156
157 private:
158 friend bool operator!=(const TFlagIterator& Lhs, const TFlagIterator& Rhs)
159 {
160 return (Lhs.RemainingFlags != Rhs.RemainingFlags);
161 }
162
163 private:
164 IntType RemainingFlags;
165 };
166
167 template<typename EnumType>
169 {
170 using IntType = std::underlying_type_t<EnumType>;
171
172 FORCEINLINE explicit TIterator(EnumType InFlags)
173 : Flags(IntType(InFlags))
174 {
175 }
176
177 FORCEINLINE TIterator& operator++()
178 {
179 const IntType PoppedBit = Flags & (~Flags + 1);
180 Flags ^= PoppedBit;
181 return *this;
182 }
183
184 FORCEINLINE EnumType operator*() const
185 {
186 const IntType Result = Flags & (~Flags + 1);
187 return (EnumType)Result;
188 }
189
190 private:
191 FORCEINLINE friend bool operator!=(const TIterator& Lhs, const TIterator& Rhs)
192 {
193 return (Lhs.Flags != Rhs.Flags);
194 }
195
196 private:
197 IntType Flags;
198 };
199
200 template<typename EnumType, int32_t RangeType>
201 struct Impl
202 {
203 static_assert(sizeof(EnumType) == 0, "Unknown enum type");
204 };
205
209 template<typename EnumType>
210 struct Impl<EnumType, LK_INTERNAL_ENUM_RANGE_TYPE_CONTIGIOUS>
211 {
214 };
215
219 template<typename EnumType>
220 struct Impl<EnumType, LK_INTERNAL_ENUM_RANGE_TYPE_VALUEARRAY>
221 {
222 TValueArrayIterator<EnumType> begin() const { return TValueArrayIterator<EnumType>(Type<EnumType>::template GetPointer<void>(false)); }
223 TValueArrayIterator<EnumType> end() const { return TValueArrayIterator<EnumType>(Type<EnumType>::template GetPointer<void>(true)); }
224 };
225
229 template<typename EnumType>
230 struct Impl<EnumType, LK_INTERNAL_ENUM_RANGE_TYPE_FLAG>
231 {
233 TFlagIterator<EnumType> end() const { return TFlagIterator<EnumType>(0); }
234 };
235 }
236
244 template<typename EnumType>
245 struct TEnumRange : Enum::Internal::Range::Impl<EnumType, Enum::Internal::Range::Type<EnumType>::RangeType>
246 {
247 };
248
249}
250
251#if defined(LK_ENGINE_MSVC)
252
256#define LK_ENUM_RANGE_BY_FIRST_AND_LAST(EnumType, First, Last) \
257 template<> \
258 struct ::LkEngine::Enum::Internal::Range::Type<EnumType> \
259 { \
260 enum { RangeType = 0 }; \
261 static constexpr std::underlying_type_t<EnumType> Begin = (std::underlying_type_t<EnumType>)(First); \
262 static constexpr std::underlying_type_t<EnumType> End = (std::underlying_type_t<EnumType>)(Last) + 1; \
263 };
264
268#define LK_ENUM_RANGE_BY_VALUES(EnumType, ...) \
269 template<> \
270 struct ::LkEngine::Enum::Internal::Range::Type<EnumType> \
271 { \
272 enum { RangeType = 1 }; \
273 template<typename DummyType> \
274 static const EnumType* GetPointer(const bool IsLast) \
275 { \
276 static constexpr EnumType Values[] = { __VA_ARGS__ }; \
277 return IsLast ? Values + sizeof(Values) / sizeof(EnumType) : Values; \
278 } \
279 };
280
286#define LK_ENUM_RANGE_BY_COUNT(EnumType, Count) \
287 LK_ENUM_RANGE_BY_FIRST_AND_LAST(EnumType, 0, (std::underlying_type_t<EnumType>)Count - 1)
288
292#define LK_ENUM_RANGE_FLAGS_BY_COUNT(EnumType) \
293 template<> \
294 struct ::LkEngine::Enum::Internal::Range::Type<EnumType> \
295 { \
296 enum { RangeType = 2 }; \
297 static constexpr std::underlying_type_t<EnumType> ValidFlags() \
298 { \
299 using IntType = std::underlying_type_t<EnumType>; \
300 IntType Flags = 0; \
301 for (IntType Idx = 1; Idx < static_cast<IntType>(EnumType::COUNT); Idx <<= 1) \
302 { \
303 Flags |= Idx; \
304 } \
305 return Flags; \
306 } \
307 };
308
312#define LK_ENUM_RANGE_FLAGS_BY_FIRST_AND_LAST(EnumType, First, Last) \
313 template<> \
314 struct ::LkEngine::Enum::Internal::Range::Type<EnumType> \
315 { \
316 enum { RangeType = 2 }; \
317 static constexpr std::underlying_type_t<EnumType> ValidFlags() \
318 { \
319 using IntType = std::underlying_type_t<EnumType>; \
320 IntType Flags = static_cast<IntType>(First); \
321 for (IntType Idx = Flags; Idx <= static_cast<IntType>(Last); Idx <<= 1) \
322 { \
323 Flags |= Idx; \
324 } \
325 return Flags; \
326 } \
327 };
328
329#elif defined(LK_ENGINE_GCC)
330
334#define LK_ENUM_RANGE_BY_FIRST_AND_LAST(EnumType, First, Last) \
335 template<> \
336 struct LkEngine::Enum::Internal::Range::Type<EnumType> \
337 { \
338 enum { RangeType = 0 }; \
339 static constexpr std::underlying_type_t<EnumType> Begin = (std::underlying_type_t<EnumType>)(First); \
340 static constexpr std::underlying_type_t<EnumType> End = (std::underlying_type_t<EnumType>)(Last) + 1; \
341 };
342
346#define LK_ENUM_RANGE_BY_VALUES(EnumType, ...) \
347 template<> \
348 struct LkEngine::Enum::Internal::Range::Type<EnumType> \
349 { \
350 enum { RangeType = 1 }; \
351 template<typename DummyType> \
352 static const EnumType* GetPointer(const bool IsLast) \
353 { \
354 static constexpr EnumType Values[] = { __VA_ARGS__ }; \
355 return IsLast ? Values + sizeof(Values) / sizeof(EnumType) : Values; \
356 } \
357 };
358
364#define LK_ENUM_RANGE_BY_COUNT(EnumType, Count) \
365 LK_ENUM_RANGE_BY_FIRST_AND_LAST(EnumType, 0, (std::underlying_type_t<EnumType>)Count - 1)
366
370#define LK_ENUM_RANGE_FLAGS_BY_COUNT(EnumType) \
371 template<> \
372 struct LkEngine::Enum::Internal::Range::Type<EnumType> \
373 { \
374 enum { RangeType = 2 }; \
375 static constexpr std::underlying_type_t<EnumType> ValidFlags() \
376 { \
377 using IntType = std::underlying_type_t<EnumType>; \
378 IntType Flags = 0; \
379 for (IntType Idx = 1; Idx < static_cast<IntType>(EnumType::COUNT); Idx <<= 1) \
380 { \
381 Flags |= Idx; \
382 } \
383 return Flags; \
384 } \
385 };
386
390#define LK_ENUM_RANGE_FLAGS_BY_FIRST_AND_LAST(EnumType, First, Last) \
391 template<> \
392 struct LkEngine::Enum::Internal::Range::Type<EnumType> \
393 { \
394 enum { RangeType = 2 }; \
395 static constexpr std::underlying_type_t<EnumType> ValidFlags() \
396 { \
397 using IntType = std::underlying_type_t<EnumType>; \
398 IntType Flags = static_cast<IntType>(First); \
399 for (IntType Idx = Flags; Idx <= static_cast<IntType>(Last); Idx <<= 1) \
400 { \
401 Flags |= Idx; \
402 } \
403 return Flags; \
404 } \
405 };
406
407#endif
Definition Asset.h:11
Definition Enum.h:246