4#include "../Foundation/AlignedStorage.h"
5#include "../Foundation/InitializerList.h"
6#include "../Foundation/TypeList.h"
11template <
typename EnumType, EnumType enumValue,
typename MemberType>
22template <
typename EnumType, EnumType enumValue,
typename MemberType>
25 using type = MemberType;
26 using enumType = EnumType;
28 static constexpr EnumType value = enumValue;
36template <
typename Union>
44 static constexpr auto NumTypes = Union::FieldsTypes::size;
48 type = TypeAt<0>::value;
49 new (&fieldAt<0>(), PlacementNew())
typename TypeAt<0>::type();
60 visit(CopyConstruct(), other);
68 visit(MoveConstruct(), other);
75 if (type == other.type)
77 visit<CopyAssign>(other);
83 visit(CopyConstruct(), other);
92 if (type == other.type)
94 visit(MoveAssign(), other);
100 visit(MoveConstruct(), other);
105 using EnumType =
typename TypeAt<0>::enumType;
108 template <EnumType wantedEnum,
int StartIndex = NumTypes>
111 static constexpr int index = wantedEnum == TypeAt<StartIndex - 1>::value
113 :
EnumToType<wantedEnum, StartIndex - 1>::index;
114 static_assert(index >= 0,
"Type not found!");
116 typename TypeAt<StartIndex - 1>::type,
117 typename EnumToType<wantedEnum, StartIndex - 1>::type>;
120 template <EnumType wantedEnum>
123 using type =
typename TypeAt<0>::type;
124 static constexpr int index = 0;
141 bool operator==(
const TaggedUnion& other)
const {
return type == other.type and visit<Equals>(other); }
147 template <EnumType wantedType,
typename U>
150 auto&
field = fieldAt<EnumToType<wantedType>::index>();
151 if (type == wantedType)
153 field = forward<U>(other);
157 using T =
typename EnumToType<wantedType>::type;
160 new (&
field, PlacementNew()) T(forward<U>(other));
169 template <EnumType wantedType>
170 typename TypeAt<EnumToType<wantedType>::index>::type&
changeTo()
172 using T =
typename EnumToType<wantedType>::type;
173 auto&
field = fieldAt<EnumToType<wantedType>::index>();
174 if (type != wantedType)
178 new (&
field, PlacementNew()) T();
187 template <EnumType wantedType>
188 [[nodiscard]]
typename TypeAt<EnumToType<wantedType>::index>::type*
field()
190 if (wantedType == type)
192 return &fieldAt<EnumToType<wantedType>::index>();
201 template <EnumType wantedType>
202 [[nodiscard]]
const typename TypeAt<EnumToType<wantedType>::index>::type*
field()
const
204 if (wantedType == type)
206 return &fieldAt<EnumToType<wantedType>::index>();
217 using T =
typename TypeAt<Index>::type;
218 t1.fieldAt<Index>().~T();
225 void operator()(TaggedUnion& t1)
227 using T =
typename TypeAt<Index>::type;
228 new (&t1.fieldAt<Index>(), PlacementNew()) T();
235 void operator()(TaggedUnion& t1,
const TaggedUnion& t2)
237 using T =
typename TypeAt<Index>::type;
238 new (&t1.fieldAt<Index>(), PlacementNew()) T(t2.fieldAt<Index>());
245 void operator()(TaggedUnion& t1, TaggedUnion& t2)
247 using T =
typename TypeAt<Index>::type;
248 new (&t1.fieldAt<Index>(), PlacementNew()) T(
move(t2.fieldAt<Index>()));
255 void operator()(TaggedUnion& t1,
const TaggedUnion& t2)
257 t1.fieldAt<Index>() = t2.fieldAt<Index>();
264 void operator()(TaggedUnion& t1, TaggedUnion& t2)
266 t1.fieldAt<Index>() =
move(t2.fieldAt<Index>());
273 static auto visit(TaggedUnion& t1, TaggedUnion& t2)
275 return t1.fieldAt<Index>() ==
move(t2.fieldAt<Index>());
279 template <
typename Visitor,
typename... Arguments>
280 auto visit(Visitor&& visitor, Arguments&&... args)
282 return RuntimeEnumVisit<Visitor>::visit(forward<Visitor>(visitor), type, *
this, forward<Arguments>(args)...);
285 template <
typename Visitor,
size_t StartIndex = NumTypes>
286 struct RuntimeEnumVisit
288 static constexpr auto Index = StartIndex - 1;
290 template <
typename... Args>
291 static auto visit(Visitor&& visitor, EnumType enumType, Args&... args)
293 if (enumType == TypeAt<Index>::value)
295 return visitor.template operator()<Index>(args...);
299 return RuntimeEnumVisit<Visitor, Index>::visit(forward<Visitor>(visitor), enumType, args...);
304 template <
typename Visitor>
305 struct RuntimeEnumVisit<Visitor, 0>
307 template <
typename... Args>
308 static auto visit(Visitor&& visitor, EnumType, Args&... args)
310 return visitor.template operator()<0>(args...);
315 [[nodiscard]]
auto& fieldAt()
317 using T =
typename TypeAt<index>::type;
318 return storage.template reinterpret_as<T>();
322 [[nodiscard]]
const auto& fieldAt()
const
324 using T =
typename TypeAt<index>::type;
325 return storage.template reinterpret_as<const T>();
328 template <
class ForwardIt>
329 static constexpr ForwardIt MaxElement(ForwardIt first, ForwardIt last)
333 ForwardIt largest = first;
334 for (++first; first != last; ++first)
336 if (*largest < *first)
344 static constexpr T MaxElement(std::initializer_list<T> list)
346 return *MaxElement(list.begin(), list.end());
349 template <
class... Types>
350 struct ComputeMaxSizeAndAlignment;
352 template <
class... Types>
353 struct ComputeMaxSizeAndAlignment<TypeTraits::TypeList<Types...>>
355 static constexpr size_t maxAlignment = MaxElement({
alignof(
typename Types::type)...});
356 static constexpr size_t maxSize = MaxElement({
sizeof(
typename Types::type)...});
359 using Storage = ComputeMaxSizeAndAlignment<typename Union::FieldsTypes>;
361 AlignedStorage<Storage::maxSize, Storage::maxAlignment> storage;
typename Conditional< B, T, F >::type ConditionalT
ConditionalT is an alias template that resolves to type T if a boolean value is true,...
Definition: TypeTraits.h:70
typename TypeListGet< T, N >::type TypeListGetT
Alias template to simplify accessing the retrieved type using TypeListGet.
Definition: TypeList.h:69
constexpr T && move(T &value)
Converts an lvalue to an rvalue reference.
Definition: Compiler.h:269
Associate a Type to an Enum, as required by TaggedUnion.
Definition: TaggedUnion.h:24
Extracts type T corresponding to enumeration wantedEnum at compile time.
Definition: TaggedUnion.h:110
Type safe union with an enum type, where each type has an associated enum value.
Definition: TaggedUnion.h:38
TaggedUnion(const TaggedUnion &other)
Copy constructor.
Definition: TaggedUnion.h:57
void setType(EnumType newType)
Sets the currently active type at runtime, destructing and (default) constructing the new type.
Definition: TaggedUnion.h:131
TaggedUnion & operator=(TaggedUnion &&other)
Move assignment operator.
Definition: TaggedUnion.h:90
EnumType getType() const
Returns enumeration value of currently active union type.
Definition: TaggedUnion.h:128
const TypeAt< EnumToType< wantedType >::index >::type * field() const
Get a pointer to currently active field.
Definition: TaggedUnion.h:202
TaggedUnion & operator=(const TaggedUnion &other)
Copy assignment operator.
Definition: TaggedUnion.h:73
TypeAt< EnumToType< wantedType >::index >::type * field()
Get a pointer to currently active field.
Definition: TaggedUnion.h:188
void assign(U &&other)
Assigns a compile time known enum type with an object U.
Definition: TaggedUnion.h:148
~TaggedUnion()
Destroys the TaggedUnion object.
Definition: TaggedUnion.h:53
TypeAt< EnumToType< wantedType >::index >::type & changeTo()
Changes current active type in union to a different one.
Definition: TaggedUnion.h:170
TaggedUnion(TaggedUnion &&other)
Move constructor.
Definition: TaggedUnion.h:65