blob: a5fd9437cdc4dba4dc68fec345d3e9d533ba4475 [file] [log] [blame]
Doug Horn1427b6a2018-12-11 13:19:16 -08001// Copyright 2018 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef LIB_FIT_VARIANT_H_
6#define LIB_FIT_VARIANT_H_
7
Adam Barth57eacf52020-11-04 00:38:09 +00008#include <exception>
Doug Horn1427b6a2018-12-11 13:19:16 -08009#include <new>
10#include <type_traits>
11#include <utility>
12
Adam Barth57eacf52020-11-04 00:38:09 +000013#include "constructors_internal.h"
14#include "in_place_internal.h"
15#include "storage_internal.h"
16#include "traits.h"
17#include "utility_internal.h"
18
Doug Horn1427b6a2018-12-11 13:19:16 -080019namespace fit {
Doug Horn1427b6a2018-12-11 13:19:16 -080020
Adam Barth57eacf52020-11-04 00:38:09 +000021// A default-constructible type that may be used as the first variant type to
22// make fit::variant default-constructible when other variants are not. This
23// type may also be used as an alternative representing an empty value.
Doug Horn1427b6a2018-12-11 13:19:16 -080024struct monostate final {
Adam Barth57eacf52020-11-04 00:38:09 +000025 constexpr bool operator==(const monostate& other) const { return true; }
26 constexpr bool operator!=(const monostate& other) const { return false; }
27 constexpr bool operator<(const monostate& other) const { return false; }
28 constexpr bool operator>(const monostate& other) const { return false; }
29 constexpr bool operator<=(const monostate& other) const { return true; }
30 constexpr bool operator>=(const monostate& other) const { return true; }
Doug Horn1427b6a2018-12-11 13:19:16 -080031};
32
Adam Barth57eacf52020-11-04 00:38:09 +000033namespace internal {
34
35// Helper type to avoid recursive instantiations of the full variant type.
36template <typename...>
37struct variant_list {};
38
39// Gets the number of alternatives in a variant_list as a compile-time constant.
40template <typename T>
41struct variant_list_size;
42
43template <typename... Ts>
44struct variant_list_size<variant_list<Ts...>> : std::integral_constant<size_t, sizeof...(Ts)> {};
45
46// Helper to get the type of a variant_list alternative with the given index.
47template <size_t Index, typename VariantList>
48struct variant_alternative;
49
50template <size_t Index, typename T0, typename... Ts>
51struct variant_alternative<Index, variant_list<T0, Ts...>>
52 : variant_alternative<Index - 1, variant_list<Ts...>> {};
53
54template <typename T0, typename... Ts>
55struct variant_alternative<0, variant_list<T0, Ts...>> {
56 using type = T0;
57};
58
59} // namespace internal
60
61// Forward declaration.
62template <typename... Ts>
63class variant;
64
65// Gets the type of a variant alternative with the given index.
66template <size_t Index, typename Variant>
67struct variant_alternative;
68
69template <size_t Index, typename... Ts>
70struct variant_alternative<Index, variant<Ts...>>
71 : ::fit::internal::variant_alternative<Index, ::fit::internal::variant_list<Ts...>> {};
72
73template <size_t index, typename Variant>
74using variant_alternative_t = typename variant_alternative<index, Variant>::type;
75
76// Gets the number of alternatives in a variant as a compile-time constant
77// expression.
78template <typename T>
79struct variant_size;
80
81template <typename... Ts>
82struct variant_size<variant<Ts...>> : std::integral_constant<size_t, sizeof...(Ts)> {};
83
84template <typename T>
85struct variant_size<const T> : variant_size<T> {};
86template <typename T>
87struct variant_size<volatile T> : variant_size<T> {};
88template <typename T>
89struct variant_size<const volatile T> : variant_size<T> {};
Doug Horn1427b6a2018-12-11 13:19:16 -080090
91#ifdef __cpp_inline_variables
92
Adam Barth57eacf52020-11-04 00:38:09 +000093template <typename T>
94inline constexpr size_t variant_size_v = variant_size<T>::value;
Doug Horn1427b6a2018-12-11 13:19:16 -080095
96#else
97
Adam Barth57eacf52020-11-04 00:38:09 +000098template <typename T>
99struct variant_size_holder {
100 static constexpr size_t value{variant_size<T>::value};
Doug Horn1427b6a2018-12-11 13:19:16 -0800101};
102
Adam Barth57eacf52020-11-04 00:38:09 +0000103template <typename T>
104constexpr size_t variant_size_holder<T>::value;
Doug Horn1427b6a2018-12-11 13:19:16 -0800105
Adam Barth57eacf52020-11-04 00:38:09 +0000106template <typename T>
107static constexpr const size_t& variant_size_v = variant_size_holder<T>::value;
Doug Horn1427b6a2018-12-11 13:19:16 -0800108
Adam Barth57eacf52020-11-04 00:38:09 +0000109#endif
Doug Horn1427b6a2018-12-11 13:19:16 -0800110
Adam Barth57eacf52020-11-04 00:38:09 +0000111// Exception type to report bad accesses to variant.
112class bad_variant_access : public std::exception {
113 public:
114 bad_variant_access() noexcept {}
Doug Horn1427b6a2018-12-11 13:19:16 -0800115
Adam Barth57eacf52020-11-04 00:38:09 +0000116 const char* what() const noexcept override { return reason_; }
117
118 private:
119 template <typename... Ts>
120 friend class variant;
121
122 bad_variant_access(const char* reason) noexcept : reason_{reason} {}
123
124 // String describing the reason for the bad access. Must point to a string
125 // with static storage duration.
126 const char* reason_;
Doug Horn1427b6a2018-12-11 13:19:16 -0800127};
128
Adam Barth57eacf52020-11-04 00:38:09 +0000129namespace internal {
Doug Horn1427b6a2018-12-11 13:19:16 -0800130
Adam Barth57eacf52020-11-04 00:38:09 +0000131// Helper type to check that conversions do not narrow.
132template <typename T>
133struct check_narrow {
134 T x[1];
Doug Horn1427b6a2018-12-11 13:19:16 -0800135};
136
Adam Barth57eacf52020-11-04 00:38:09 +0000137// Builds a check(Ti) function for each alternative Ti. This trait is evaluated
138// for each element of fit::variant<Ts...>. Essentially: for (Index, Ti) in Ts.
139//
140// Index is the zero-based index of the corresponding element Ti in the pack Ts.
141// T is the type deduced from the converting constructor or assignment operator
142// of fit::variant for which we want to find an appropriately convertible
143// element.
144//
145// The specializations below match the element Ti that passes the conversion
146// checks.
147template <size_t Index, typename T, typename Ti,
148 bool IsBool = std::is_same<bool, std::remove_cv_t<Ti>>::value, typename = void>
149struct check_valid_option {
150 // Non-static so that check_valid_option<...>::check is always a valid
151 // name, but doesn't participate in the overload resolution in the
152 // valid_option_index selection trait.
153 void check();
Doug Horn1427b6a2018-12-11 13:19:16 -0800154};
155
Adam Barth57eacf52020-11-04 00:38:09 +0000156// Checks that Ti x[] = {std::forward<T>()} is well formed.
157template <size_t Index, typename T, typename Ti>
158struct check_valid_option<Index, T, Ti, false,
159 void_t<decltype(check_narrow<Ti>{{std::declval<T>()}})>> {
160 static std::integral_constant<size_t, Index> check(Ti);
Doug Horn1427b6a2018-12-11 13:19:16 -0800161};
162
Adam Barth57eacf52020-11-04 00:38:09 +0000163// Checks that remove_cvref_t<T> is bool when Ti is cv bool.
164template <size_t Index, typename T, typename Ti>
165struct check_valid_option<Index, T, Ti, true,
166 std::enable_if_t<std::is_same<bool, remove_cvref_t<T>>::value>> {
167 static std::integral_constant<size_t, Index> check(Ti);
Doug Horn1427b6a2018-12-11 13:19:16 -0800168};
169
Adam Barth57eacf52020-11-04 00:38:09 +0000170// Mixes in instantiations of check_valid_option for each element in
171// fit::variant<Ts...>, creating a set of check(Ti) functions that might match
172// T following the conversion rules.
173template <typename T, typename VariantList,
174 typename = std::make_index_sequence<variant_list_size<VariantList>::value>>
175struct find_valid_option {
176 // Non-static so that find_valid_option<...>::check is always a valid name
177 // in the using clause of the recursive case, but doesn't participate in the
178 // overload resolution in the valid_option_index trait.
179 void check();
Doug Horn1427b6a2018-12-11 13:19:16 -0800180};
181
Adam Barth57eacf52020-11-04 00:38:09 +0000182// Recursive case. This would be simpler with C++17 pack expansion in using
183// directives, but this must function in C++14.
184template <typename T, typename Ti, size_t Index, typename... Ts, size_t... Is>
185struct find_valid_option<T, variant_list<Ti, Ts...>, std::index_sequence<Index, Is...>>
186 : check_valid_option<Index, T, Ti>,
187 find_valid_option<T, variant_list<Ts...>, std::index_sequence<Is...>> {
188 // Introduce the base class definitions of check() into this scope. The
189 // static check(Ti) methods participate in overload resolution in the
190 // valid_option_index trait, while the non-static check() methods are
191 // ignored.
192 using check_valid_option<Index, T, Ti>::check;
193 using find_valid_option<T, variant_list<Ts...>, std::index_sequence<Is...>>::check;
194};
195
196// Evaluates to the index of the valid target type Ti selected from
197// fit::variant<Ts...>. The type expression is well formed IFF a single valid
198// target type is available that converts from T.
199template <typename T, typename VariantList>
200using valid_option_index = decltype(find_valid_option<T, VariantList>::check(std::declval<T>()));
201
202// Evaluates to the index of the valid target Ti that converts from T or the
203// reserved empty index when no uniquely suitable option is available.
204template <typename T, typename Variant, typename = void>
205struct selected_index : std::integral_constant<size_t, ::fit::internal::empty_index> {};
206
207template <typename T, typename... Ts>
208struct selected_index<T, variant<Ts...>, void_t<valid_option_index<T, variant_list<Ts...>>>>
209 : valid_option_index<T, variant_list<Ts...>> {};
210
211} // namespace internal
212
213// A resonably complete implementation of std::variant compatible with C++14.
Doug Horn1427b6a2018-12-11 13:19:16 -0800214template <typename... Ts>
Adam Barth57eacf52020-11-04 00:38:09 +0000215class variant
216 : private ::fit::internal::modulate_default_constructor<::fit::internal::first_t<Ts...>>,
217 private ::fit::internal::modulate_copy_and_move<Ts...> {
218 private:
219 static_assert(sizeof...(Ts) > 0, "Variant must have at least one type!");
Doug Horn1427b6a2018-12-11 13:19:16 -0800220
Adam Barth57eacf52020-11-04 00:38:09 +0000221 static constexpr bool nothrow_default_constructible =
222 std::is_nothrow_default_constructible<::fit::internal::first_t<Ts...>>::value;
Doug Horn1427b6a2018-12-11 13:19:16 -0800223
Adam Barth57eacf52020-11-04 00:38:09 +0000224 static constexpr bool nothrow_move_constructible =
225 conjunction_v<std::is_nothrow_move_constructible<Ts>...>;
Doug Horn1427b6a2018-12-11 13:19:16 -0800226
Adam Barth57eacf52020-11-04 00:38:09 +0000227 static constexpr auto default_init_v = ::fit::internal::default_init_v;
228 static constexpr auto trivial_init_v = ::fit::internal::trivial_init_v;
Doug Horn1427b6a2018-12-11 13:19:16 -0800229
Adam Barth57eacf52020-11-04 00:38:09 +0000230 template <typename T>
231 using type_tag = ::fit::internal::type_tag<T>;
232 template <size_t Index>
233 using index_tag = ::fit::internal::index_tag<Index>;
Doug Horn1427b6a2018-12-11 13:19:16 -0800234
Adam Barth57eacf52020-11-04 00:38:09 +0000235 template <typename T>
236 using not_self_type = ::fit::internal::not_same_type<variant, T>;
Doug Horn1427b6a2018-12-11 13:19:16 -0800237
Adam Barth57eacf52020-11-04 00:38:09 +0000238 template <typename T>
239 using not_in_place = ::fit::internal::not_same_type<in_place_t, T>;
Doug Horn1427b6a2018-12-11 13:19:16 -0800240
Adam Barth57eacf52020-11-04 00:38:09 +0000241 template <typename T>
242 struct occurs_once
243 : std::integral_constant<bool, ::fit::internal::occurences_of_v<T, Ts...> == 1> {};
244
245 template <typename... Conditions>
246 using requires_conditions = ::fit::internal::requires_conditions<Conditions...>;
247
248 template <typename... Conditions>
249 using assignment_requires_conditions =
250 ::fit::internal::assignment_requires_conditions<variant&, Conditions...>;
251
252 template <typename T, typename... Args>
253 using emplace_constructible_by_type =
254 std::enable_if_t<(::fit::internal::occurences_of_v<T, Ts...> == 1 &&
255 std::is_constructible<T, Args...>::value),
256 std::add_lvalue_reference_t<T>>;
257
258 template <size_t Index, typename = std::enable_if_t<(Index < sizeof...(Ts))>>
259 using alternative_t = variant_alternative_t<Index, variant>;
260
261 template <size_t Index, typename... Args>
262 using emplace_constructible_by_index =
263 std::enable_if_t<std::is_constructible<alternative_t<Index>, Args...>::value,
264 std::add_lvalue_reference_t<alternative_t<Index>>>;
265
266 template <typename T>
267 static constexpr size_t selected_index = ::fit::internal::selected_index<T, variant>::value;
268
269 template <typename T, typename = std::enable_if<not_self_type<T>::value>>
270 using selected_t = alternative_t<selected_index<T>>;
271
272 [[noreturn]] static constexpr void throw_bad_variant_access(const char* reason) {
273#if __cpp_exceptions
274 throw bad_variant_access(reason);
275#else
276 (void)reason;
277 __builtin_abort();
278#endif
279 }
280
281 public:
282 // Default constructors.
283
284 constexpr variant() noexcept(nothrow_default_constructible) : storage_{default_init_v} {}
285
286 // Copy/move constructors and assignment operators.
287
288 constexpr variant(const variant&) = default;
289 constexpr variant& operator=(const variant&) = default;
290
291 constexpr variant(variant&&) noexcept(nothrow_move_constructible) = default;
292 constexpr variant& operator=(variant&&) = default;
293
294 // Converting constructors.
295
296 template <typename T,
297 requires_conditions<std::integral_constant<bool, (sizeof...(Ts) > 0)>,
298 not_in_place<T>> = true,
299 typename Ti = selected_t<T&&>,
300 requires_conditions<occurs_once<Ti>, std::is_constructible<Ti, T>> = true>
301 constexpr variant(T&& value) noexcept(std::is_nothrow_constructible<Ti, T>::value)
302 : storage_(type_tag<Ti>{}, std::forward<T>(value)) {}
303
304 template <typename T, typename... Args,
305 requires_conditions<occurs_once<T>, std::is_constructible<T, Args...>> = true>
306 explicit constexpr variant(in_place_type_t<T>, Args&&... args)
307 : storage_(type_tag<T>{}, std::forward<Args>(args)...) {}
308
309 template <typename T, typename U, typename... Args,
310 requires_conditions<occurs_once<T>, std::is_constructible<T, std::initializer_list<T>&,
311 Args...>> = true>
312 explicit constexpr variant(in_place_type_t<T>, std::initializer_list<U> init_list, Args&&... args)
313 : storage_(type_tag<T>{}, init_list, std::forward<Args>(args)...) {}
314
315 template <size_t Index, typename... Args,
316 requires_conditions<std::is_constructible<alternative_t<Index>, Args...>> = true>
317 explicit constexpr variant(in_place_index_t<Index>, Args&&... args)
318 : storage_(index_tag<Index>{}, std::forward<Args>(args)...) {}
319
320 template <size_t Index, typename U, typename... Args,
321 requires_conditions<std::is_constructible<alternative_t<Index>,
322 std::initializer_list<U>&, Args...>> = true>
323 explicit constexpr variant(in_place_index_t<Index>, std::initializer_list<U> init_list,
324 Args&&... args)
325 : storage_(index_tag<Index>{}, init_list, std::forward<Args>(args)...) {}
326
327 ~variant() = default;
328
329 // Converting assignment.
330
331 template <typename T>
332 constexpr assignment_requires_conditions<
333 occurs_once<selected_t<T>>, std::is_constructible<selected_t<T&&>, T>,
334 std::is_assignable<selected_t<T&&>&, T>,
335 disjunction<std::is_nothrow_constructible<selected_t<T&&>, T>,
336 negation<std::is_nothrow_move_constructible<selected_t<T&&>>>>>
337 operator=(T&& value) noexcept(std::is_nothrow_assignable<selected_t<T&&>&, T>::value&&
338 std::is_nothrow_constructible<selected_t<T&&>, T>::value) {
339 constexpr auto index = selected_index<T>;
340 if (storage_.index() == index) {
341 storage_.get(index_tag<index>{}) = std::forward<T>(value);
342 } else {
343 this->emplace<index>(std::forward<T>(value));
Doug Horn1427b6a2018-12-11 13:19:16 -0800344 }
Adam Barth57eacf52020-11-04 00:38:09 +0000345 return *this;
346 }
Doug Horn1427b6a2018-12-11 13:19:16 -0800347
Adam Barth57eacf52020-11-04 00:38:09 +0000348 template <typename T>
349 constexpr assignment_requires_conditions<
350 occurs_once<selected_t<T>>, std::is_constructible<selected_t<T&&>, T>,
351 std::is_assignable<selected_t<T&&>&, T>,
352 conjunction<negation<std::is_nothrow_constructible<selected_t<T&&>, T>>,
353 std::is_nothrow_move_constructible<selected_t<T&&>>>>
354 operator=(T&& value) noexcept(std::is_nothrow_assignable<selected_t<T&&>&, T>::value&&
355 std::is_nothrow_constructible<selected_t<T&&>, T>::value) {
356 constexpr auto index = selected_index<T>;
357 if (storage_.index() == index) {
358 storage_.get(index_tag<index>{}) = std::forward<T>(value);
359 } else {
360 this->operator=(variant(std::forward<T>(value)));
Doug Horn1427b6a2018-12-11 13:19:16 -0800361 }
Adam Barth57eacf52020-11-04 00:38:09 +0000362 return *this;
363 }
Doug Horn1427b6a2018-12-11 13:19:16 -0800364
Adam Barth57eacf52020-11-04 00:38:09 +0000365 constexpr size_t index() const noexcept { return storage_.index(); }
366
367 // TODO(eieio): Remove uses of these in favor of non-member get.
368 template <size_t Index>
369 constexpr auto& get() & {
370 if (storage_.has_value(index_tag<Index>{})) {
371 return storage_.get(index_tag<Index>{});
372 } else {
373 throw_bad_variant_access("Bad get<>() from variant!");
Doug Horn1427b6a2018-12-11 13:19:16 -0800374 }
Adam Barth57eacf52020-11-04 00:38:09 +0000375 }
376 template <size_t Index>
377 constexpr const auto& get() const& {
378 if (storage_.has_value(index_tag<Index>{})) {
379 return storage_.get(index_tag<Index>{});
380 } else {
381 throw_bad_variant_access("Bad get<>() from variant!");
Doug Horn1427b6a2018-12-11 13:19:16 -0800382 }
Adam Barth57eacf52020-11-04 00:38:09 +0000383 }
384 template <size_t Index>
385 constexpr auto&& get() && {
386 if (storage_.has_value(index_tag<Index>{})) {
387 return std::move(storage_.get(index_tag<Index>{}));
388 } else {
389 throw_bad_variant_access("Bad get<>() from variant!");
390 }
391 }
392 template <size_t Index>
393 constexpr const auto&& get() const&& {
394 if (storage_.has_value(index_tag<Index>{})) {
395 return std::move(storage_.get(index_tag<Index>{}));
396 } else {
397 throw_bad_variant_access("Bad get<>() from variant!");
398 }
399 }
Doug Horn1427b6a2018-12-11 13:19:16 -0800400
Adam Barth57eacf52020-11-04 00:38:09 +0000401 template <typename T>
402 constexpr auto& get() & {
403 if (storage_.has_value(type_tag<T>{})) {
404 return storage_.get(type_tag<T>{});
405 } else {
406 throw_bad_variant_access("Bad get<>() from variant!");
407 }
408 }
409 template <typename T>
410 constexpr const auto& get() const& {
411 if (storage_.has_value(type_tag<T>{})) {
412 return storage_.get(type_tag<T>{});
413 } else {
414 throw_bad_variant_access("Bad get<>() from variant!");
415 }
416 }
417 template <typename T>
418 constexpr auto&& get() && {
419 if (storage_.has_value(type_tag<T>{})) {
420 return std::move(storage_.get(type_tag<T>{}));
421 } else {
422 throw_bad_variant_access("Bad get<>() from variant!");
423 }
424 }
425 template <typename T>
426 constexpr const auto&& get() const&& {
427 if (storage_.has_value(type_tag<T>{})) {
428 return std::move(storage_.get(type_tag<T>{}));
429 } else {
430 throw_bad_variant_access("Bad get<>() from variant!");
431 }
432 }
433
434 // Emplacement.
435
436 template <typename T, typename... Args>
437 constexpr emplace_constructible_by_type<T, Args&&...> emplace(Args&&... args) {
438 storage_.reset();
439 storage_.construct(type_tag<T>{}, std::forward<Args>(args)...);
440 return storage_.get(type_tag<T>{});
441 }
442
443 template <typename T, typename U, typename... Args>
444 constexpr emplace_constructible_by_type<T, std::initializer_list<U>&, Args&&...> emplace(
445 std::initializer_list<U> init_list, Args&&... args) {
446 storage_.reset();
447 storage_.construct(type_tag<T>{}, init_list, std::forward<Args>(args)...);
448 return storage_.get(type_tag<T>{});
449 }
450
451 template <size_t Index, typename... Args>
452 constexpr emplace_constructible_by_index<Index, Args&&...> emplace(Args&&... args) {
453 storage_.reset();
454 storage_.construct(index_tag<Index>{}, std::forward<Args>(args)...);
455 return storage_.get(index_tag<Index>{});
456 }
457
458 template <size_t Index, typename U, typename... Args>
459 constexpr emplace_constructible_by_index<Index, std::initializer_list<U>&, Args&&...> emplace(
460 std::initializer_list<U> init_list, Args&&... args) {
461 storage_.reset();
462 storage_.construct(index_tag<Index>{}, init_list, std::forward<Args>(args)...);
463 return storage_.get(index_tag<Index>{});
464 }
465
466 // Swap.
467
468 void swap(variant& other) { storage_.swap(other.storage_); }
469
470 // Comparison.
471
472 friend constexpr bool operator==(const variant& lhs, const variant& rhs) {
473 bool result = false;
474 const bool has_value =
475 lhs.storage_.visit([&result, &lhs, &rhs](auto, auto active_index_tag, const auto*) {
476 if (lhs.index() != rhs.index()) {
477 result = false;
478 } else {
479 result = lhs.storage_.get(active_index_tag) == rhs.storage_.get(active_index_tag);
480 }
481 });
482 return !has_value || result;
483 }
484 friend constexpr bool operator!=(const variant& lhs, const variant& rhs) {
485 bool result = true;
486 const bool has_value =
487 lhs.storage_.visit([&result, &lhs, &rhs](auto, auto active_index_tag, const auto*) {
488 if (lhs.index() != rhs.index()) {
489 result = true;
490 } else {
491 result = lhs.storage_.get(active_index_tag) != rhs.storage_.get(active_index_tag);
492 }
493 });
494 return has_value && result;
495 }
496 friend constexpr bool operator<(const variant& lhs, const variant& rhs) {
497 bool result = true;
498 const bool has_value =
499 rhs.storage_.visit([&result, &lhs, &rhs](auto, auto active_index_tag, const auto*) {
500 if (lhs.storage_.is_empty()) {
501 result = true;
502 } else if (lhs.index() < rhs.index()) {
503 result = true;
504 } else if (lhs.index() > rhs.index()) {
505 result = false;
506 } else {
507 result = lhs.storage_.get(active_index_tag) < rhs.storage_.get(active_index_tag);
508 }
509 });
510 return has_value && result;
511 }
512 friend constexpr bool operator>(const variant& lhs, const variant& rhs) {
513 bool result = true;
514 const bool has_value =
515 lhs.storage_.visit([&result, &lhs, &rhs](auto, auto active_index_tag, const auto*) {
516 if (rhs.storage_.is_empty()) {
517 result = true;
518 } else if (lhs.index() > rhs.index()) {
519 result = true;
520 } else if (lhs.index() < rhs.index()) {
521 result = false;
522 } else {
523 result = lhs.storage_.get(active_index_tag) > rhs.storage_.get(active_index_tag);
524 }
525 });
526 return has_value && result;
527 }
528 friend constexpr bool operator<=(const variant& lhs, const variant& rhs) {
529 bool result = false;
530 const bool has_value =
531 lhs.storage_.visit([&result, &lhs, &rhs](auto, auto active_index_tag, const auto*) {
532 if (rhs.storage_.is_empty()) {
533 result = false;
534 } else if (lhs.index() < rhs.index()) {
535 result = true;
536 } else if (lhs.index() > rhs.index()) {
537 result = false;
538 } else {
539 result = lhs.storage_.get(active_index_tag) <= rhs.storage_.get(active_index_tag);
540 }
541 });
542 return !has_value || result;
543 }
544 friend constexpr bool operator>=(const variant& lhs, const variant& rhs) {
545 bool result = false;
546 const bool has_value =
547 rhs.storage_.visit([&result, &lhs, &rhs](auto, auto active_index_tag, const auto*) {
548 if (lhs.storage_.is_empty()) {
549 result = false;
550 } else if (lhs.index() > rhs.index()) {
551 result = true;
552 } else if (lhs.index() < rhs.index()) {
553 result = false;
554 } else {
555 result = lhs.storage_.get(active_index_tag) >= rhs.storage_.get(active_index_tag);
556 }
557 });
558 return !has_value || result;
559 }
560
561 private:
562 ::fit::internal::storage_type<Ts...> storage_;
Doug Horn1427b6a2018-12-11 13:19:16 -0800563};
564
565// Swaps variants.
566template <typename... Ts>
567void swap(variant<Ts...>& a, variant<Ts...>& b) {
Adam Barth57eacf52020-11-04 00:38:09 +0000568 a.swap(b);
Doug Horn1427b6a2018-12-11 13:19:16 -0800569}
570
Adam Barth57eacf52020-11-04 00:38:09 +0000571// Accesses the variant by zero-based index.
572//
573// Accesses should use ADL, similar to the pattern for std::swap:
574//
575// using std::get;
576// get<some_index>(some_fit_variant);
577//
578// This makes code adaptable to substituting std::variant for fit::variant on
579// newer compilers.
580template <size_t Index, typename... Ts>
581constexpr auto& get(variant<Ts...>& value) {
582 return value.template get<Index>();
583}
584template <size_t Index, typename... Ts>
585constexpr auto&& get(variant<Ts...>&& value) {
586 return std::move(value).template get<Index>();
587}
588template <size_t Index, typename... Ts>
589constexpr const auto& get(const variant<Ts...>& value) {
590 return value.template get<Index>();
591}
592template <size_t Index, typename... Ts>
593constexpr const auto&& get(const variant<Ts...>&& value) {
594 return std::move(value).template get<Index>();
595}
Doug Horn1427b6a2018-12-11 13:19:16 -0800596
Adam Barth57eacf52020-11-04 00:38:09 +0000597// Accesses the variant by unique type. See note above about ADL.
598template <typename T, typename... Ts>
599constexpr auto& get(variant<Ts...>& value) {
600 return value.template get<T>();
601}
602template <typename T, typename... Ts>
603constexpr auto&& get(variant<Ts...>&& value) {
604 return std::move(value).template get<T>();
605}
606template <typename T, typename... Ts>
607constexpr const auto& get(const variant<Ts...>& value) {
608 return value.template get<T>();
609}
610template <typename T, typename... Ts>
611constexpr const auto&& get(const variant<Ts...>&& value) {
612 return std::move(value).template get<T>();
613}
Doug Horn1427b6a2018-12-11 13:19:16 -0800614
Adam Barth57eacf52020-11-04 00:38:09 +0000615// Checks if the variant holds type T. See note above about ADL.
616template <typename T, typename... Ts>
617constexpr bool holds_alternative(const variant<Ts...>& value) {
618 constexpr auto index = ::fit::internal::selected_index<T, variant<Ts...>>::value;
619 return value.index() == index;
620}
Doug Horn1427b6a2018-12-11 13:19:16 -0800621
Adam Barth57eacf52020-11-04 00:38:09 +0000622// TODO(eieio): Remove once the old ::fit::internal spellings of these types is
623// removed from FIDL.
624namespace internal {
Doug Horn1427b6a2018-12-11 13:19:16 -0800625
Adam Barth57eacf52020-11-04 00:38:09 +0000626using ::fit::monostate;
627using ::fit::variant;
Doug Horn1427b6a2018-12-11 13:19:16 -0800628
Adam Barth57eacf52020-11-04 00:38:09 +0000629} // namespace internal
630
631} // namespace fit
632
633#endif // LIB_FIT_VARIANT_H_