Iros
 
Loading...
Searching...
No Matches
variant.h
Go to the documentation of this file.
1#pragma once
2
5#include "di/meta/algorithm.h"
6#include "di/meta/constexpr.h"
7#include "di/meta/core.h"
9#include "di/meta/trivial.h"
11#include "di/util/forward.h"
12#include "di/util/get.h"
14#include "di/util/move.h"
21
22namespace di::vocab {
23namespace detail {
24 template<typename T, typename U, typename A = T[1]>
25 concept VariantValidOverload = requires { A { util::declval<U>() }; };
26}
27
28template<typename... Types>
29requires(sizeof...(Types) > 0)
30class Variant : public util::AddMemberGet<Variant<Types...>> {
31private:
32 using Impl = detail::VariantImpl<Types...>;
33 using List = meta::List<Types...>;
34
35 constexpr static bool trivially_copy_constructible = (concepts::TriviallyCopyConstructible<Types> && ...);
36 constexpr static bool trivially_move_constructible = (concepts::TriviallyMoveConstructible<Types> && ...);
37 constexpr static bool trivially_copy_assignable = (concepts::TriviallyCopyAssignable<Types> && ...);
38 constexpr static bool trivially_move_assignable = (concepts::TriviallyMoveAssignable<Types> && ...);
39 constexpr static bool trivially_destructible = (concepts::TriviallyDestructible<Types> && ...);
40
41 constexpr static bool copyable = (concepts::CopyConstructible<Types> && ...);
42 constexpr static bool movable = (concepts::MoveConstructible<Types> && ...);
43
44 template<typename U, typename T>
45 struct SelectorImpl {
46 auto operator()(T) const -> T
48 };
49
50 template<typename U>
51 struct Selector : SelectorImpl<U, Types>... {
52 using SelectorImpl<U, Types>::operator()...;
53 };
54
55public:
56 // conditionally trivial special member functions.
58 requires(trivially_copy_constructible)
59 = default;
61 requires(trivially_move_constructible)
62 = default;
64 requires(trivially_destructible)
65 = default;
66 auto operator=(Variant const&) -> Variant& requires(trivially_copy_assignable) = default;
67 auto operator=(Variant&&) -> Variant& requires(trivially_move_assignable) = default;
68
69 constexpr Variant()
71 {
72 do_emplace(c_<0ZU>);
73 }
74
75 constexpr Variant(Variant const& other)
76 requires(copyable && !trivially_copy_constructible)
77 {
79 other.index(),
80 []<size_t index>(Constexpr<index>, Variant& self, Variant const& other) {
81 self.do_emplace(c_<index>, util::get<index>(other));
82 },
83 *this, other);
84 }
85
86 constexpr Variant(Variant&& other)
87 requires(movable && !trivially_move_constructible)
88 {
90 other.index(),
91 []<size_t index>(Constexpr<index>, Variant& self, Variant&& other) {
92 self.do_emplace(c_<index>, util::get<index>(util::move(other)));
93 },
94 *this, util::move(other));
95 }
96
97 template<typename U>
101 constexpr Variant(U&& value)
102 : Variant(in_place_type<meta::InvokeResult<Selector<U>, U>>, util::forward<U>(value)) {}
103
104 template<size_t index, typename... Args, typename T = meta::At<List, index>>
105 requires(concepts::ConstructibleFrom<T, Args...>)
106 constexpr explicit Variant(Constexpr<index>, Args&&... args) {
107 do_emplace(c_<index>, util::forward<Args>(args)...);
108 }
109
110 template<size_t index, typename U, typename... Args, typename T = meta::At<List, index>>
112 constexpr explicit Variant(Constexpr<index>, std::initializer_list<U> list, Args&&... args) {
113 do_emplace(c_<index>, list, util::forward<Args>(args)...);
114 }
115
116 template<typename T, typename... Args, auto index = meta::Lookup<T, List>>
118 constexpr explicit Variant(InPlaceType<T>, Args&&... args) {
119 do_emplace(c_<index>, util::forward<Args>(args)...);
120 }
121
122 template<typename T, typename U, typename... Args, auto index = meta::Lookup<T, List>>
124 constexpr explicit Variant(InPlaceType<T>, std::initializer_list<U> list, Args&&... args) {
125 do_emplace(c_<index>, list, util::forward<Args>(args)...);
126 }
127
128 template<typename... Other>
129 requires(sizeof...(Types) == sizeof...(Other) &&
130 requires { requires(concepts::ConstructibleFrom<Types, Other const&> && ...); })
131 constexpr explicit((!concepts::ConvertibleTo<Other const&, Types> || ...)) Variant(Variant<Other...> const& other) {
132 function::index_dispatch<void, sizeof...(Types)>(other.index(), [&]<size_t index>(Constexpr<index>) {
133 do_emplace(c_<index>, util::get<index>(other));
134 });
135 }
136
137 template<typename... Other>
138 requires(sizeof...(Types) == sizeof...(Other) &&
139 requires { requires(concepts::ConstructibleFrom<Types, Other> && ...); })
140 constexpr explicit((!concepts::ConvertibleTo<Other, Types> || ...)) Variant(Variant<Other...>&& other) {
141 function::index_dispatch<void, sizeof...(Types)>(other.index(), [&]<size_t index>(Constexpr<index>) {
142 do_emplace(c_<index>, util::get<index>(util::move(other)));
143 });
144 }
145
146 constexpr ~Variant() { destroy(); }
147
148 constexpr auto operator=(Variant const& other) -> Variant& requires(!trivially_copy_assignable && copyable) {
149 destroy();
150 function::index_dispatch<void, sizeof...(Types)>(other.index(), [&]<size_t index>(Constexpr<index>) {
151 do_emplace(c_<index>, util::get<index>(other));
152 });
153 return *this;
154 }
155
156 constexpr auto operator=(Variant&& other) -> Variant& requires(!trivially_move_assignable && movable) {
157 destroy();
158 function::index_dispatch<void, sizeof...(Types)>(other.index(), [&]<size_t index>(Constexpr<index>) {
159 do_emplace(c_<index>, util::get<index>(util::move(other)));
160 });
161 return *this;
162 }
163
164 template<typename U>
168 constexpr auto operator=(U&& value) -> Variant& {
169 this->template emplace<meta::InvokeResult<Selector<U>, U>>(util::forward<U>(value));
170 return *this;
171 }
172
173 constexpr auto index() const -> size_t { return m_index; }
174
175 template<size_t index, typename... Args, typename T = meta::At<List, index>>
176 requires(concepts::ConstructibleFrom<T, Args...>)
177 constexpr auto emplace(Args&&... args) -> T& {
178 destroy();
179 return do_emplace(c_<index>, util::forward<Args>(args)...);
180 }
181
182 template<size_t index, typename U, typename... Args, typename T = meta::At<List, index>>
184 constexpr auto emplace(std::initializer_list<U> list, Args&&... args) -> T& {
185 destroy();
186 return do_emplace(c_<index>, list, util::forward<Args>(args)...);
187 }
188
189 template<typename T, typename... Args, auto index = meta::Lookup<T, List>>
191 constexpr auto emplace(Args&&... args) -> T& {
192 destroy();
193 return do_emplace(c_<index>, util::forward<Args>(args)...);
194 }
195
196 template<typename T, typename U, typename... Args, auto index = meta::Lookup<T, List>>
198 constexpr auto emplace(std::initializer_list<U> list, Args&&... args) -> T& {
199 destroy();
200 return do_emplace(c_<index>, list, util::forward<Args>(args)...);
201 }
202
203private:
204 template<typename... Other>
205 requires(sizeof...(Types) == sizeof...(Other) &&
206 requires { requires(concepts::EqualityComparableWith<Types, Other> && ...); })
207 constexpr friend auto operator==(Variant const& a, Variant<Other...> const& b) -> bool {
208 if (a.index() != b.index()) {
209 return false;
210 }
211 return function::index_dispatch<bool, sizeof...(Types)>(a.index(), [&]<size_t index>(Constexpr<index>) {
212 return util::get<index>(a) == util::get<index>(b);
213 });
214 }
215
216 template<typename... Other>
217 requires(sizeof...(Types) == sizeof...(Other) &&
218 requires { requires(concepts::ThreeWayComparableWith<Types, Other> && ...); })
219 constexpr friend auto operator<=>(Variant const& a, Variant<Other...> const& b) {
221 if (auto result = a.index() <=> b.index(); result != 0) {
222 return Result(result);
223 }
224 return function::index_dispatch<Result, sizeof...(Types)>(
225 a.index(), [&]<size_t index>(Constexpr<index>) -> Result {
226 return util::get<index>(a) <=> util::get<index>(b);
227 });
228 }
229
230 template<size_t index, concepts::DerivedFrom<Variant> Self = Variant>
235
236 template<size_t index, concepts::DerivedFrom<Variant> Self = Variant>
237 // NOLINTNEXTLINE(readability-const-return-type)
242
243 template<concepts::DerivedFrom<Variant> Self = Variant>
244 constexpr friend auto tag_invoke(types::Tag<variant_size>, InPlaceType<Self>) -> size_t {
245 return meta::Size<List>;
246 }
247
248 template<size_t index, typename Self = Variant>
250 constexpr friend auto tag_invoke(types::Tag<util::get_in_place>, Constexpr<index>, Self&& self)
252 DI_ASSERT(index == self.m_index);
253 return Impl::static_get(c_<index>, util::forward<Self>(self).m_impl);
254 }
255
256 template<typename T, typename Self = Variant>
258 constexpr friend auto tag_invoke(types::Tag<util::get_in_place>, InPlaceType<T>, Self&& self)
260 constexpr auto index = meta::Lookup<T, List>;
261 DI_ASSERT(index == self.m_index);
262 return Impl::static_get(c_<index>, util::forward<Self>(self).m_impl);
263 }
264
265 template<concepts::DerivedFrom<Variant> Self = Variant>
267 return List {};
268 }
269
270 constexpr void destroy()
271 requires(trivially_destructible)
272 {}
273
274 constexpr void destroy() {
276 this->index(),
277 []<size_t index>(Constexpr<index>, Impl& impl) {
278 impl.destroy_impl(c_<index>);
279 },
280 m_impl);
281 }
282
283 template<size_t index, typename... Args>
284 constexpr auto do_emplace(Constexpr<index>, Args&&... args) -> decltype(auto) {
285 m_index = index;
286 return m_impl.emplace_impl(c_<index>, util::forward<Args>(args)...);
287 }
288
289 template<size_t index, typename U, typename... Args>
290 constexpr auto do_emplace(Constexpr<index>, std::initializer_list<U> list, Args&&... args) -> decltype(auto) {
291 m_index = index;
292 return m_impl.emplace_impl(c_<index>, list, util::forward<Args>(args)...);
293 }
294
295 Impl m_impl;
297};
298}
#define DI_ASSERT(...)
Definition assert_bool.h:7
Definition variant_forward_declaration.h:6
constexpr friend auto tag_invoke(types::Tag< util::get_in_place >, Constexpr< index >, Self &&self) -> meta::Like< Self, meta::At< List, index > > &&
Definition variant.h:250
constexpr Variant(U &&value)
Definition variant.h:101
constexpr Variant(Variant const &other)
Definition variant.h:75
auto operator=(Variant &&) -> Variant &requires(trivially_move_assignable)=default
constexpr friend auto tag_invoke(types::Tag< variant_alternative >, InPlaceType< Self >, Constexpr< index >) -> meta::At< List, index >
Definition variant.h:231
constexpr Variant(Constexpr< index >, Args &&... args)
Definition variant.h:106
constexpr ~Variant()
Definition variant.h:146
constexpr friend auto tag_invoke(types::Tag< util::get_in_place >, InPlaceType< T >, Self &&self) -> meta::Like< Self, T > &&
Definition variant.h:258
constexpr auto operator=(Variant &&other) -> Variant &requires(!trivially_move_assignable &&movable)
Definition variant.h:156
constexpr Variant()
Definition variant.h:69
constexpr auto emplace(std::initializer_list< U > list, Args &&... args) -> T &
Definition variant.h:198
constexpr friend auto tag_invoke(types::Tag< variant_types >, InPlaceType< Self >) -> List
Definition variant.h:266
Variant(Variant &&)=default
constexpr Variant(Constexpr< index >, std::initializer_list< U > list, Args &&... args)
Definition variant.h:112
constexpr auto emplace(Args &&... args) -> T &
Definition variant.h:177
constexpr Variant(InPlaceType< T >, std::initializer_list< U > list, Args &&... args)
Definition variant.h:124
constexpr friend auto tag_invoke(types::Tag< variant_size >, InPlaceType< Self >) -> size_t
Definition variant.h:244
constexpr auto emplace(std::initializer_list< U > list, Args &&... args) -> T &
Definition variant.h:184
constexpr friend auto tag_invoke(types::Tag< variant_alternative >, InPlaceType< Self const >, Constexpr< index >) -> meta::At< List, index > const
Definition variant.h:238
constexpr Variant(InPlaceType< T >, Args &&... args)
Definition variant.h:118
Variant(Variant const &)=default
constexpr friend auto operator<=>(Variant const &a, Variant< Other... > const &b)
Definition variant.h:219
auto operator=(Variant const &) -> Variant &requires(trivially_copy_assignable)=default
constexpr Variant(Variant &&other)
Definition variant.h:86
constexpr auto emplace(Args &&... args) -> T &
Definition variant.h:191
constexpr auto operator=(Variant const &other) -> Variant &requires(!trivially_copy_assignable &&copyable)
Definition variant.h:148
constexpr auto index() const -> size_t
Definition variant.h:173
Definition variant_impl.h:12
Checks if T is a Constexpr instance.
Definition constexpr.h:270
Definition operations.h:11
Definition operations.h:99
Definition operations.h:34
Definition operations.h:24
Definition operations.h:114
Definition core.h:139
Definition invoke.h:58
Definition operations.h:43
Definition list.h:116
constexpr auto index_dispatch
Definition index_dispatch.h:41
decltype(detail::smallest_unsigned_type_helper(c_< size >)) SmallestUnsignedType
Definition smallest_unsigned_type.h:27
typename T::template At< index > At
Definition list.h:110
constexpr usize Size
Definition list.h:106
Type< detail::LikeHelper< T, U > > Like
Definition language.h:468
decltype(function::detail::invoke_impl(util::declval< Ts >()...)) InvokeResult
Definition invoke.h:64
Type< detail::CommonComparisonCategoryHelper< Types... > > CommonComparisonCategory
Definition compare.h:31
di::meta::Decay< decltype(T)> Tag
Definition tag_invoke.h:28
Definition vocab.h:96
constexpr auto get(T &&value) -> decltype(auto)
Definition get.h:8
auto declval() -> meta::AddRValueReference< T >
Definition declval.h:8
Definition erasure_cast.h:7
Definition lazy.h:165
Expected< T, Error > Result
Definition result.h:8
constexpr auto destroy
Definition destroy.h:35
constexpr auto c_
A value of type Constexpr<val>.
Definition constexpr.h:252
constexpr auto in_place_type
Definition in_place_type.h:12
@ U
Definition key.h:30
A wrapper for a constexpr value.
Definition core.h:77
Definition core.h:5
Definition in_place_type.h:5