di 0.1.0
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
47 requires(detail::VariantValidOverload<T, U>);
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&
67 requires(trivially_copy_assignable)
68 = default;
70 requires(trivially_move_assignable)
71 = default;
72
73 constexpr Variant()
75 {
76 do_emplace(c_<0ZU>);
77 }
78
79 constexpr Variant(Variant const& other)
80 requires(copyable && !trivially_copy_constructible)
81 {
83 other.index(),
84 []<size_t index>(Constexpr<index>, Variant& self, Variant const& other) {
85 self.do_emplace(c_<index>, util::get<index>(other));
86 },
87 *this, other);
88 }
89
90 constexpr Variant(Variant&& other)
91 requires(movable && !trivially_move_constructible)
92 {
94 other.index(),
95 []<size_t index>(Constexpr<index>, Variant& self, Variant&& other) {
96 self.do_emplace(c_<index>, util::get<index>(util::move(other)));
97 },
98 *this, util::move(other));
99 }
100
101 template<typename U>
105 constexpr Variant(U&& value)
106 : Variant(in_place_type<meta::InvokeResult<Selector<U>, U>>, util::forward<U>(value)) {}
107
108 template<size_t index, typename... Args, typename T = meta::At<List, index>>
109 requires(concepts::ConstructibleFrom<T, Args...>)
110 constexpr explicit Variant(Constexpr<index>, Args&&... args) {
111 do_emplace(c_<index>, util::forward<Args>(args)...);
112 }
113
114 template<size_t index, typename U, typename... Args, typename T = meta::At<List, index>>
116 constexpr explicit Variant(Constexpr<index>, std::initializer_list<U> list, Args&&... args) {
117 do_emplace(c_<index>, list, util::forward<Args>(args)...);
118 }
119
120 template<typename T, typename... Args, auto index = meta::Lookup<T, List>>
122 constexpr explicit Variant(InPlaceType<T>, Args&&... args) {
123 do_emplace(c_<index>, util::forward<Args>(args)...);
124 }
125
126 template<typename T, typename U, typename... Args, auto index = meta::Lookup<T, List>>
128 constexpr explicit Variant(InPlaceType<T>, std::initializer_list<U> list, Args&&... args) {
129 do_emplace(c_<index>, list, util::forward<Args>(args)...);
130 }
131
132 template<typename... Other>
133 requires(sizeof...(Types) == sizeof...(Other) &&
134 requires { requires(concepts::ConstructibleFrom<Types, Other const&> && ...); })
135 constexpr explicit((!concepts::ConvertibleTo<Other const&, Types> || ...)) Variant(Variant<Other...> const& other) {
136 function::index_dispatch<void, sizeof...(Types)>(other.index(), [&]<size_t index>(Constexpr<index>) {
137 do_emplace(c_<index>, util::get<index>(other));
138 });
139 }
140
141 template<typename... Other>
142 requires(sizeof...(Types) == sizeof...(Other) &&
143 requires { requires(concepts::ConstructibleFrom<Types, Other> && ...); })
144 constexpr explicit((!concepts::ConvertibleTo<Other, Types> || ...)) Variant(Variant<Other...>&& other) {
145 function::index_dispatch<void, sizeof...(Types)>(other.index(), [&]<size_t index>(Constexpr<index>) {
146 do_emplace(c_<index>, util::get<index>(util::move(other)));
147 });
148 }
149
150 constexpr ~Variant() { destroy(); }
151
152 constexpr auto operator=(Variant const& other) -> Variant&
153 requires(!trivially_copy_assignable && copyable)
154 {
155 destroy();
156 function::index_dispatch<void, sizeof...(Types)>(other.index(), [&]<size_t index>(Constexpr<index>) {
157 do_emplace(c_<index>, util::get<index>(other));
158 });
159 return *this;
160 }
161
162 constexpr auto operator=(Variant&& other) -> Variant&
163 requires(!trivially_move_assignable && movable)
164 {
165 destroy();
166 function::index_dispatch<void, sizeof...(Types)>(other.index(), [&]<size_t index>(Constexpr<index>) {
167 do_emplace(c_<index>, util::get<index>(util::move(other)));
168 });
169 return *this;
170 }
171
172 template<typename U>
176 constexpr auto operator=(U&& value) -> Variant& {
177 this->template emplace<meta::InvokeResult<Selector<U>, U>>(util::forward<U>(value));
178 return *this;
179 }
180
181 constexpr auto index() const -> size_t { return m_index; }
182
183 template<size_t index, typename... Args, typename T = meta::At<List, index>>
184 requires(concepts::ConstructibleFrom<T, Args...>)
185 constexpr auto emplace(Args&&... args) -> T& {
186 destroy();
187 return do_emplace(c_<index>, util::forward<Args>(args)...);
188 }
189
190 template<size_t index, typename U, typename... Args, typename T = meta::At<List, index>>
192 constexpr auto emplace(std::initializer_list<U> list, Args&&... args) -> T& {
193 destroy();
194 return do_emplace(c_<index>, list, util::forward<Args>(args)...);
195 }
196
197 template<typename T, typename... Args, auto index = meta::Lookup<T, List>>
199 constexpr auto emplace(Args&&... args) -> T& {
200 destroy();
201 return do_emplace(c_<index>, util::forward<Args>(args)...);
202 }
203
204 template<typename T, typename U, typename... Args, auto index = meta::Lookup<T, List>>
206 constexpr auto emplace(std::initializer_list<U> list, Args&&... args) -> T& {
207 destroy();
208 return do_emplace(c_<index>, list, util::forward<Args>(args)...);
209 }
210
211private:
212 template<typename... Other>
213 requires(sizeof...(Types) == sizeof...(Other) &&
214 requires { requires(concepts::EqualityComparableWith<Types, Other> && ...); })
215 constexpr friend auto operator==(Variant const& a, Variant<Other...> const& b) -> bool {
216 if (a.index() != b.index()) {
217 return false;
218 }
219 return function::index_dispatch<bool, sizeof...(Types)>(a.index(), [&]<size_t index>(Constexpr<index>) {
220 return util::get<index>(a) == util::get<index>(b);
221 });
222 }
223
224 template<typename... Other>
225 requires(sizeof...(Types) == sizeof...(Other) &&
226 requires { requires(concepts::ThreeWayComparableWith<Types, Other> && ...); })
227 constexpr friend auto operator<=>(Variant const& a, Variant<Other...> const& b) {
229 if (auto result = a.index() <=> b.index(); result != 0) {
230 return Result(result);
231 }
232 return function::index_dispatch<Result, sizeof...(Types)>(
233 a.index(), [&]<size_t index>(Constexpr<index>) -> Result {
234 return util::get<index>(a) <=> util::get<index>(b);
235 });
236 }
237
238 template<size_t index, concepts::DerivedFrom<Variant> Self = Variant>
243
244 template<size_t index, concepts::DerivedFrom<Variant> Self = Variant>
245 // NOLINTNEXTLINE(readability-const-return-type)
250
251 template<concepts::DerivedFrom<Variant> Self = Variant>
252 constexpr friend auto tag_invoke(types::Tag<variant_size>, InPlaceType<Self>) -> size_t {
253 return meta::Size<List>;
254 }
255
256 template<size_t index, typename Self = Variant>
258 constexpr friend auto tag_invoke(types::Tag<util::get_in_place>, Constexpr<index>, Self&& self)
260 DI_ASSERT(index == self.m_index);
261 return Impl::static_get(c_<index>, util::forward<Self>(self).m_impl);
262 }
263
264 template<typename T, typename Self = Variant>
266 constexpr friend auto tag_invoke(types::Tag<util::get_in_place>, InPlaceType<T>, Self&& self)
268 constexpr auto index = meta::Lookup<T, List>;
269 DI_ASSERT(index == self.m_index);
270 return Impl::static_get(c_<index>, util::forward<Self>(self).m_impl);
271 }
272
273 template<concepts::DerivedFrom<Variant> Self = Variant>
275 return List {};
276 }
277
278 constexpr void destroy()
279 requires(trivially_destructible)
280 {}
281
282 constexpr void destroy() {
284 this->index(),
285 []<size_t index>(Constexpr<index>, Impl& impl) {
286 impl.destroy_impl(c_<index>);
287 },
288 m_impl);
289 }
290
291 template<size_t index, typename... Args>
292 constexpr auto do_emplace(Constexpr<index>, Args&&... args) -> decltype(auto) {
293 m_index = index;
294 return m_impl.emplace_impl(c_<index>, util::forward<Args>(args)...);
295 }
296
297 template<size_t index, typename U, typename... Args>
298 constexpr auto do_emplace(Constexpr<index>, std::initializer_list<U> list, Args&&... args) -> decltype(auto) {
299 m_index = index;
300 return m_impl.emplace_impl(c_<index>, list, util::forward<Args>(args)...);
301 }
302
303 Impl m_impl;
305};
306}
#define DI_ASSERT(...)
Definition assert_bool.h:7
Variant(Variant const &)=default
Definition variant.h:30
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:258
constexpr Variant(U &&value)
Definition variant.h:105
constexpr Variant(Variant const &other)
Definition variant.h:79
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:239
constexpr Variant(Constexpr< index >, Args &&... args)
Definition variant.h:110
constexpr ~Variant()
Definition variant.h:150
constexpr friend auto tag_invoke(types::Tag< util::get_in_place >, InPlaceType< T >, Self &&self) -> meta::Like< Self, T > &&
Definition variant.h:266
constexpr auto operator=(Variant &&other) -> Variant &requires(!trivially_move_assignable &&movable)
Definition variant.h:162
constexpr Variant()
Definition variant.h:73
constexpr auto emplace(std::initializer_list< U > list, Args &&... args) -> T &
Definition variant.h:206
constexpr friend auto tag_invoke(types::Tag< variant_types >, InPlaceType< Self >) -> List
Definition variant.h:274
Variant(Variant &&)=default
constexpr Variant(Constexpr< index >, std::initializer_list< U > list, Args &&... args)
Definition variant.h:116
constexpr auto emplace(Args &&... args) -> T &
Definition variant.h:185
constexpr Variant(InPlaceType< T >, std::initializer_list< U > list, Args &&... args)
Definition variant.h:128
constexpr friend auto tag_invoke(types::Tag< variant_size >, InPlaceType< Self >) -> size_t
Definition variant.h:252
constexpr auto emplace(std::initializer_list< U > list, Args &&... args) -> T &
Definition variant.h:192
constexpr friend auto tag_invoke(types::Tag< variant_alternative >, InPlaceType< Self const >, Constexpr< index >) -> meta::At< List, index > const
Definition variant.h:246
constexpr Variant(InPlaceType< T >, Args &&... args)
Definition variant.h:122
Variant(Variant const &)=default
constexpr friend auto operator<=>(Variant const &a, Variant< Other... > const &b)
Definition variant.h:227
auto operator=(Variant const &) -> Variant &requires(trivially_copy_assignable)=default
constexpr Variant(Variant &&other)
Definition variant.h:90
constexpr auto emplace(Args &&... args) -> T &
Definition variant.h:199
constexpr auto operator=(Variant const &other) -> Variant &requires(!trivially_copy_assignable &&copyable)
Definition variant.h:152
constexpr auto index() const -> size_t
Definition variant.h:181
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:124
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:118
constexpr usize Size
Definition list.h:114
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 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
A wrapper for a constexpr value.
Definition constexpr.h:36
Definition core.h:5
Definition in_place_type.h:5