1 // Range v3 library
2 //
3 //  Copyright Eric Niebler 2014-present
4 //
5 //  Use, modification and distribution is subject to the
6 //  Boost Software License, Version 1.0. (See accompanying
7 //  file LICENSE_1_0.txt or copy at
8 //  http://www.boost.org/LICENSE_1_0.txt)
9 //
10 // Project home: https://github.com/ericniebler/range-v3
11 //
12 
13 #ifndef RANGES_V3_DETAIL_VARIANT_HPP
14 #define RANGES_V3_DETAIL_VARIANT_HPP
15 
16 #include <iterator>
17 #include <memory>
18 #include <new>
19 #include <stdexcept>
20 #include <tuple>
21 #include <type_traits>
22 #include <utility>
23 
24 #include <meta/meta.hpp>
25 
26 #include <concepts/concepts.hpp>
27 
28 #include <range/v3/range_fwd.hpp>
29 
30 #include <range/v3/functional/compose.hpp>
31 #include <range/v3/functional/identity.hpp>
32 #include <range/v3/functional/invoke.hpp>
33 #include <range/v3/iterator/concepts.hpp>
34 #include <range/v3/iterator/traits.hpp>
35 #include <range/v3/utility/get.hpp>
36 
37 #include <range/v3/detail/prologue.hpp>
38 
39 namespace ranges
40 {
41     template<std::size_t I>
42     struct emplaced_index_t;
43 
44     template<std::size_t I>
45     struct emplaced_index_t : meta::size_t<I>
46     {};
47 
48 #if RANGES_CXX_INLINE_VARIABLES < RANGES_CXX_INLINE_VARIABLES_17
49     namespace
50     {
51         template<std::size_t I>
52         constexpr auto & emplaced_index = static_const<emplaced_index_t<I>>::value;
53     }
54 #else  // RANGES_CXX_INLINE_VARIABLES >= RANGES_CXX_INLINE_VARIABLES_17
55     template<std::size_t I>
56     inline constexpr emplaced_index_t<I> emplaced_index{};
57 #endif // RANGES_CXX_INLINE_VARIABLES
58 
59     struct bad_variant_access : std::logic_error
60     {
bad_variant_accessranges::bad_variant_access61         explicit bad_variant_access(std::string const & what_arg)
62           : std::logic_error(what_arg)
63         {}
bad_variant_accessranges::bad_variant_access64         explicit bad_variant_access(char const * what_arg)
65           : std::logic_error(what_arg)
66         {}
67     };
68 
69     template<typename T, std::size_t Index>
70     struct indexed_element
71     {
72     private:
73         std::add_pointer_t<T> t_;
74 
75     public:
indexed_elementranges::indexed_element76         constexpr explicit indexed_element(T & t) noexcept
77           : t_(std::addressof(t))
78         {}
getranges::indexed_element79         constexpr T & get() const noexcept
80         {
81             return *t_;
82         }
83     };
84     template<typename T, std::size_t Index>
85     struct indexed_element<T &&, Index>
86     {
87     private:
88         T * t_;
89 
90     public:
indexed_elementranges::indexed_element91         constexpr explicit indexed_element(T && t) noexcept
92           : t_(std::addressof(t))
93         {}
getranges::indexed_element94         constexpr T && get() const noexcept
95         {
96             return static_cast<T &&>(*t_);
97         }
98     };
99     template<std::size_t Index>
100     struct indexed_element<void, Index>
101     {
getranges::indexed_element102         void get() const noexcept
103         {}
104     };
105 
106     /// \cond
107     namespace detail
108     {
109         struct indexed_element_fn;
110 
111         template(typename I, typename S, typename O)(
112             /// \pre
113             requires (!sized_sentinel_for<S, I>)) //
114         O uninitialized_copy(I first, S last, O out)
115         {
116             for(; first != last; ++first, ++out)
117                 ::new((void *)std::addressof(*out)) iter_value_t<O>(*first);
118             return out;
119         }
120 
121         template(typename I, typename S, typename O)(
122             /// \pre
123             requires sized_sentinel_for<S, I>)
124         O uninitialized_copy(I first, S last, O out)
125         {
126             return std::uninitialized_copy_n(first, (last - first), out);
127         }
128 
129         template<typename I, typename O>
130         O uninitialized_copy(I first, I last, O out)
131         {
132             return std::uninitialized_copy(first, last, out);
133         }
134 
135         template<typename T, typename Index>
136         struct indexed_datum
137         {
138         private:
139             template<typename, typename>
140             friend struct indexed_datum;
141             T datum_;
142 
143         public:
144             CPP_member
CPP_ctorranges::detail::indexed_datum145             constexpr CPP_ctor(indexed_datum)()(                          //
146                 noexcept(std::is_nothrow_default_constructible<T>::value) //
147                     requires default_constructible<T>)
148               : datum_{}
149             {}
150             template(typename... Ts)(
151                 /// \pre
152                 requires constructible_from<T, Ts...> AND (sizeof...(Ts) != 0)) //
153             constexpr indexed_datum(Ts &&... ts) noexcept(
154                     std::is_nothrow_constructible<T, Ts...>::value)
155               : datum_(static_cast<Ts &&>(ts)...)
156             {}
157             template(typename U)(
158                 /// \pre
159                 requires (!same_as<T, U>) AND convertible_to<U, T>)
160             constexpr indexed_datum(indexed_datum<U, Index> that) //
161                 noexcept(std::is_nothrow_constructible<T, U>::value) //
162               : datum_(std::move(that.datum_))
163             {}
164             constexpr auto ref() noexcept
165             {
166                 return indexed_element<T, Index::value>{datum_};
167             }
168             constexpr auto ref() const noexcept
169             {
170                 return indexed_element<T const, Index::value>{datum_};
171             }
172             constexpr T & get() noexcept
173             {
174                 return datum_;
175             }
176             constexpr T const & get() const noexcept
177             {
178                 return datum_;
179             }
180         };
181 
182         template<typename T, std::size_t N, typename Index>
183         struct indexed_datum<T[N], Index>;
184 
185         template<typename T, typename Index>
186         struct indexed_datum<T &, Index>
187         {
188         private:
189             template<typename, typename>
190             friend struct indexed_datum;
191             T * t_;
192 
193         public:
194             constexpr indexed_datum(T & t) noexcept
195               : t_(std::addressof(t))
196             {}
197             constexpr T & get() const noexcept
198             {
199                 return *t_;
200             }
201             constexpr auto ref() const noexcept
202             {
203                 return indexed_element<T &, Index::value>{*t_};
204             }
205         };
206         template<typename T, typename Index>
207         struct indexed_datum<T &&, Index>
208         {
209         private:
210             template<typename, typename>
211             friend struct indexed_datum;
212             T * t_;
213 
214         public:
215             constexpr indexed_datum(T && t) noexcept
216               : t_(std::addressof(t))
217             {}
218             constexpr T && get() const noexcept
219             {
220                 return static_cast<T &&>(*t_);
221             }
222             constexpr auto ref() const noexcept
223             {
224                 return indexed_element<T &&, Index::value>{static_cast<T &&>(*t_)};
225             }
226         };
227         template<typename Index>
228         struct indexed_datum<void, Index>
229         {
230             void get() const noexcept
231             {}
232             constexpr indexed_element<void, Index::value> ref() const noexcept
233             {
234                 return {};
235             }
236         };
237 
238         template<std::size_t Index, typename... Ts>
239         using variant_datum_t =
240             detail::indexed_datum<meta::at_c<meta::list<Ts...>, Index>,
241                                   meta::size_t<Index>>;
242 
243         using variant_nil = indexed_datum<void, meta::npos>;
244 
245         template<typename Ts,
246                  bool Trivial = meta::apply<
247                      meta::quote<meta::and_>,
248                      meta::transform<Ts, meta::quote<std::is_trivially_destructible>>>::
249                      type::value>
250         struct variant_data_
251         {
252             using type = indexed_datum<void, meta::npos>;
253         };
254 
255         template<typename T, typename... Ts>
256         struct variant_data_<meta::list<T, Ts...>, true>
257         {
258             struct type
259             {
260                 using head_t = T;
261                 using tail_t = meta::_t<variant_data_<meta::list<Ts...>>>;
262                 union
263                 {
264                     head_t head;
265                     tail_t tail;
266                 };
267 
268                 type() noexcept
269                 {}
270                 template<typename... Args>
271                 constexpr type(meta::size_t<0>, Args &&... args) noexcept(
272                     std::is_nothrow_constructible<head_t, Args...>::value)
273                   : head{((Args &&) args)...}
274                 {}
275                 template<std::size_t N, typename... Args>
276                 constexpr type(meta::size_t<N>, Args &&... args) noexcept(
277                     std::is_nothrow_constructible<tail_t, meta::size_t<N - 1>,
278                                                   Args...>::value)
279                   : tail{meta::size_t<N - 1>{}, ((Args &&) args)...}
280                 {}
281             };
282         };
283 
284         template<typename T, typename... Ts>
285         struct variant_data_<meta::list<T, Ts...>, false>
286         {
287             struct type
288             {
289                 using head_t = T;
290                 using tail_t = meta::_t<variant_data_<meta::list<Ts...>>>;
291                 union
292                 {
293                     head_t head;
294                     tail_t tail;
295                 };
296 
297                 type() noexcept
298                 {}
299                 ~type()
300                 {}
301                 template<typename... Args>
302                 constexpr type(meta::size_t<0>, Args &&... args) noexcept(
303                     std::is_nothrow_constructible<head_t, Args...>::value)
304                   : head{((Args &&) args)...}
305                 {}
306                 template<std::size_t N, typename... Args>
307                 constexpr type(meta::size_t<N>, Args &&... args) noexcept(
308                     std::is_nothrow_constructible<tail_t, meta::size_t<N - 1>,
309                                                   Args...>::value)
310                   : tail{meta::size_t<N - 1>{}, ((Args &&) args)...}
311                 {}
312             };
313         };
314 
315         template<typename... Ts>
316         using variant_data = meta::_t<variant_data_<meta::transform<
317             meta::list<Ts...>, meta::as_list<meta::make_index_sequence<sizeof...(Ts)>>,
318             meta::quote<indexed_datum>>>>;
319 
320         inline std::size_t variant_move_copy_(std::size_t, variant_nil, variant_nil)
321         {
322             return 0;
323         }
324         template<typename Data0, typename Data1>
325         std::size_t variant_move_copy_(std::size_t n, Data0 & self, Data1 && that)
326         {
327             using Head = typename Data0::head_t;
328             return 0 == n
329                        ? ((void)::new((void *)&self.head) Head(((Data1 &&) that).head), 0)
330                        : variant_move_copy_(n - 1, self.tail, ((Data1 &&) that).tail) + 1;
331         }
332         constexpr bool variant_equal_(std::size_t, variant_nil, variant_nil)
333         {
334             return true;
335         }
336         template<typename Data0, typename Data1>
337         constexpr bool variant_equal_(std::size_t n, Data0 const & self,
338                                       Data1 const & that)
339         {
340             return n == 0 ? self.head.get() == that.head.get()
341                           : variant_equal_(n - 1, self.tail, that.tail);
342         }
343         template<typename Fun, typename Proj = indexed_element_fn>
344         constexpr int variant_visit_(std::size_t, variant_nil, Fun, Proj = {})
345         {
346             return (RANGES_EXPECT(false), 0);
347         }
348         template<typename Data, typename Fun, typename Proj = indexed_element_fn>
349         constexpr int variant_visit_(std::size_t n, Data & self, Fun fun, Proj proj = {})
350         {
351             return 0 == n ? ((void)invoke(fun, invoke(proj, self.head)), 0)
352                           : detail::variant_visit_(
353                                 n - 1, self.tail, detail::move(fun), detail::move(proj));
354         }
355 
356         struct get_datum_fn
357         {
358             template<typename T>
359             decltype(auto) operator()(T && t) const noexcept
360             {
361                 return t.get();
362             }
363         };
364 
365         struct indexed_element_fn
366         {
367             template<typename T>
368             decltype(auto) operator()(T && t) const noexcept
369             {
370                 return t.ref();
371             }
372         };
373 
374         struct empty_variant_tag
375         {};
376 
377         struct variant_core_access
378         {
379             template<typename... Ts>
380             static constexpr variant_data<Ts...> & data(variant<Ts...> & var) noexcept
381             {
382                 return var.data_();
383             }
384             template<typename... Ts>
385             static constexpr variant_data<Ts...> const & data(
386                 variant<Ts...> const & var) noexcept
387             {
388                 return var.data_();
389             }
390             template<typename... Ts>
391             static constexpr variant_data<Ts...> && data(variant<Ts...> && var) noexcept
392             {
393                 return detail::move(var.data_());
394             }
395             template<typename... Ts>
396             static variant<Ts...> make_empty(meta::id<variant<Ts...>> = {}) noexcept
397             {
398                 return variant<Ts...>{empty_variant_tag{}};
399             }
400         };
401 
402         struct delete_fn
403         {
404             template<typename T>
405             void operator()(T const & t) const noexcept
406             {
407                 t.~T();
408             }
409         };
410 
411         template<std::size_t N, typename... Ts>
412         struct construct_fn
413         {
414             std::tuple<Ts...> args_;
415 
416             template<typename U, std::size_t... Is>
417             void construct_(U & u, meta::index_sequence<Is...>) noexcept(
418                 std::is_nothrow_constructible<U, Ts...>::value)
419             {
420                 ::new((void *)std::addressof(u))
421                     U(static_cast<Ts &&>(std::get<Is>(args_))...);
422             }
423 
424             construct_fn(Ts &&... ts) noexcept(
425                 std::is_nothrow_constructible<std::tuple<Ts...>, Ts...>::value)
426               : args_{static_cast<Ts &&>(ts)...}
427             {}
428             template<typename U, std::size_t M>
429             [[noreturn]] meta::if_c<N != M> operator()(
430                 indexed_datum<U, meta::size_t<M>> &) noexcept
431             {
432                 RANGES_EXPECT(false);
433             }
434             template<typename U>
435             meta::if_<std::is_object<U>> operator()(
436                 indexed_datum<U, meta::size_t<N>> &
437                     u) noexcept(std::is_nothrow_constructible<U, Ts...>::value)
438             {
439                 this->construct_(u.get(), meta::make_index_sequence<sizeof...(Ts)>{});
440             }
441             template<typename U>
442             meta::if_<meta::not_<std::is_object<U>>> operator()(
443                 indexed_datum<U, meta::size_t<N>> &
444                     u) noexcept(std::is_nothrow_constructible<detail::decay_t<U>,
445                                                               Ts...>::value)
446             {
447                 this->construct_(u, meta::make_index_sequence<sizeof...(Ts)>{});
448             }
449         };
450 
451         template<typename T, std::size_t N>
452         struct get_fn
453         {
454             T ** t_;
455 
456             template<typename U, std::size_t M>
457             [[noreturn]] meta::if_c<M != N> operator()(indexed_element<U, M>) const
458             {
459                 throw bad_variant_access("bad variant access");
460             }
461             template<typename U>
462             void operator()(indexed_element<U, N> t) const noexcept
463             {
464                 *t_ = std::addressof(t.get());
465             }
466             template<typename U>
467             void operator()(indexed_element<U &&, N> t) const noexcept
468             {
469                 U && u = t.get();
470                 *t_ = std::addressof(u);
471             }
472             void operator()(indexed_element<void, N>) const noexcept
473             {}
474         };
475 
476         template<typename Variant, std::size_t N>
477         struct emplace_fn
478         {
479             Variant * var_;
480             // clang-format off
481             template<typename...Ts>
482             auto CPP_auto_fun(operator())(Ts &&...ts) (const)
483             (
484                 return var_->template emplace<N>(static_cast<Ts &&>(ts)...)
485             )
486             // clang-format on
487         };
488 
489         template<typename Fun, typename Variant>
490         struct variant_visitor
491         {
492             Fun fun_;
493             Variant * var_;
494 
495             // clang-format off
496             template<typename U, std::size_t N>
497             auto CPP_auto_fun(operator())(indexed_element<U, N> u)
498             (
499                 return compose(emplace_fn<Variant, N>{var_}, fun_)(u)
500             )
501             // clang-format on
502         };
503 
504         template<typename Variant, typename Fun>
505         variant_visitor<Fun, Variant> make_variant_visitor(
506             Variant & var,
507             Fun fun) noexcept(std::is_nothrow_move_constructible<Fun>::value)
508         {
509             return {detail::move(fun), &var};
510         }
511 
512         template<typename To, typename From>
513         struct unique_visitor;
514 
515         template<typename... To, typename... From>
516         struct unique_visitor<variant<To...>, variant<From...>>
517         {
518             variant<To...> * var_;
519 
520             template<typename T, std::size_t N>
521             void operator()(indexed_element<T, N> t) const
522             {
523                 using E = meta::at_c<meta::list<From...>, N>;
524                 static_assert(RANGES_IS_SAME(T const, E const),
525                               "Is indexed_element broken?");
526                 using F = meta::find<meta::list<To...>, E>;
527                 static constexpr std::size_t M = sizeof...(To) - F::size();
528                 compose(emplace_fn<variant<To...>, M>{var_}, get_datum_fn{})(t);
529             }
530         };
531 
532         template<typename T>
533         constexpr T & variant_deref_(T * t) noexcept
534         {
535             return *t;
536         }
537         inline void variant_deref_(void const volatile *) noexcept
538         {}
539 
540         template<typename Variant>
541         struct variant_get
542         {
543             //////////////////////////////////////////////////////////////////////////////
544             // get
545             template<std::size_t N>
546             friend meta::_t<
547                 std::add_lvalue_reference<meta::at_c<meta::as_list<Variant>, N>>>
548             get(Variant & var)
549             {
550                 using elem_t = meta::_t<
551                     std::remove_reference<meta::at_c<meta::as_list<Variant>, N>>>;
552                 elem_t * elem = nullptr;
553                 auto & data_var = detail::variant_core_access::data(var);
554                 detail::variant_visit_(
555                     var.index(), data_var, detail::get_fn<elem_t, N>{&elem});
556                 return detail::variant_deref_(elem);
557             }
558             template<std::size_t N>
559             friend meta::_t<
560                 std::add_lvalue_reference<meta::at_c<meta::as_list<Variant>, N> const>>
561             get(Variant const & var)
562             {
563                 using elem_t = meta::_t<
564                     std::remove_reference<meta::at_c<meta::as_list<Variant>, N> const>>;
565                 elem_t * elem = nullptr;
566                 auto & data_var = detail::variant_core_access::data(var);
567                 detail::variant_visit_(
568                     var.index(), data_var, detail::get_fn<elem_t, N>{&elem});
569                 return detail::variant_deref_(elem);
570             }
571             template<std::size_t N>
572             friend meta::_t<
573                 std::add_rvalue_reference<meta::at_c<meta::as_list<Variant>, N>>>
574             get(Variant && var)
575             {
576                 using elem_t = meta::_t<
577                     std::remove_reference<meta::at_c<meta::as_list<Variant>, N>>>;
578                 elem_t * elem = nullptr;
579                 auto & data_var = detail::variant_core_access::data(var);
580                 detail::variant_visit_(
581                     var.index(), data_var, detail::get_fn<elem_t, N>{&elem});
582                 using res_t = meta::_t<
583                     std::add_rvalue_reference<meta::at_c<meta::as_list<Variant>, N>>>;
584                 return static_cast<res_t>(detail::variant_deref_(elem));
585             }
586         };
587 
588         template<typename Variant,
589                  bool Trivial = std::is_trivially_destructible<meta::apply<
590                      meta::quote<variant_data>, meta::as_list<Variant>>>::value>
591         struct variant_base : variant_get<Variant>
592         {
593             ~variant_base()
594             {
595                 static_cast<Variant *>(this)->clear_();
596             }
597         };
598         template<typename... Ts>
599         struct variant_base<variant<Ts...>, true> : variant_get<variant<Ts...>>
600         {};
601 
602         template<typename Fun, typename Types, typename Indices, typename = void>
603         struct variant_visit_results
604         {};
605         template<typename Fun, typename... Ts, std::size_t... Is>
606         struct variant_visit_results<
607             Fun, meta::list<Ts...>, meta::index_sequence<Is...>,
608             meta::void_<invoke_result_t<Fun &, indexed_element<Ts, Is>>...>>
609         {
610             using type = variant<invoke_result_t<Fun &, indexed_element<Ts, Is>>...>;
611         };
612         template<typename Fun, typename... Ts>
613         using variant_visit_results_t =
614             meta::_t<variant_visit_results<Fun, meta::list<Ts...>,
615                                            meta::make_index_sequence<sizeof...(Ts)>>>;
616     } // namespace detail
617     /// \endcond
618 
619     /// \addtogroup group-utility
620     /// @{
621     template<typename... Ts>
622     struct variant
623       : private detail::variant_data<Ts...>
624       , private detail::variant_base<variant<Ts...>>
625     {
626     private:
627         friend detail::variant_core_access;
628         template<typename...>
629         friend struct variant;
630         friend detail::variant_base<variant, false>;
631         template<std::size_t Index>
632         using datum_t = detail::variant_datum_t<Index, Ts...>;
633         template<typename T>
634         using add_const_t = meta::if_<std::is_void<T>, void, T const>;
635         using unbox_fn = detail::get_datum_fn;
636 
637         detail::variant_data<Ts...> & data_() & noexcept
638         {
639             return *this;
640         }
641         detail::variant_data<Ts...> const & data_() const & noexcept
642         {
643             return *this;
644         }
645         detail::variant_data<Ts...> && data_() && noexcept
646         {
647             return static_cast<detail::variant_data<Ts...> &&>(*this);
648         }
649 
650         std::size_t index_;
651 
652         void clear_() noexcept
653         {
654             if(valid())
655             {
656                 detail::variant_visit_(index_, data_(), detail::delete_fn{}, identity{});
657                 index_ = (std::size_t)-1;
658             }
659         }
660         template<typename That>
661         void assign_(That && that)
662         {
663             if(that.valid())
664                 index_ = detail::variant_move_copy_(
665                     that.index_, data_(), ((That &&) that).data_());
666         }
667         constexpr variant(detail::empty_variant_tag) noexcept
668           : detail::variant_data<Ts...>{}
669           , index_((std::size_t)-1)
670         {}
671         template(typename... Args)(
672             /// \pre
673             requires (sizeof...(Args) == sizeof...(Ts))) //
674         static constexpr bool all_convertible_to(int) noexcept
675         {
676             return and_v<convertible_to<Args, Ts>...>;
677         }
678         template<typename... Args>
679         static constexpr bool all_convertible_to(long) noexcept
680         {
681             return false;
682         }
683 
684     public:
685         CPP_member
686         constexpr CPP_ctor(variant)()(                                         //
687             noexcept(std::is_nothrow_default_constructible<datum_t<0>>::value) //
688                 requires default_constructible<datum_t<0>>)
689           : variant{emplaced_index<0>}
690         {}
691         template(std::size_t N, typename... Args)(
692             /// \pre
693             requires constructible_from<datum_t<N>, Args...>)
694             constexpr variant(emplaced_index_t<N>, Args &&... args) noexcept(
695                 std::is_nothrow_constructible<datum_t<N>, Args...>::value)
696           : detail::variant_data<Ts...>{meta::size_t<N>{}, static_cast<Args &&>(args)...}
697           , index_(N)
698         {}
699         template(std::size_t N, typename T, typename... Args)(
700             /// \pre
701             requires constructible_from<datum_t<N>, std::initializer_list<T> &,
702                                         Args...>)
703             constexpr variant(
704                 emplaced_index_t<N>, std::initializer_list<T> il,
705                 Args &&... args) noexcept(std::
706                                               is_nothrow_constructible<
707                                                   datum_t<N>, std::initializer_list<T> &,
708                                                   Args...>::value)
709           : detail::variant_data<Ts...>{meta::size_t<N>{},
710                                         il,
711                                         static_cast<Args &&>(args)...}
712           , index_(N)
713         {}
714         template(std::size_t N)(
715             /// \pre
716             requires constructible_from<datum_t<N>, meta::nil_>)
717         constexpr variant(emplaced_index_t<N>, meta::nil_)
718             noexcept(std::is_nothrow_constructible<datum_t<N>, meta::nil_>::value)
719           : detail::variant_data<Ts...>{meta::size_t<N>{}, meta::nil_{}}
720           , index_(N)
721         {}
722         variant(variant && that)
723           : detail::variant_data<Ts...>{}
724           , index_(detail::variant_move_copy_(that.index(), data_(),
725                                               std::move(that.data_())))
726         {}
727         variant(variant const & that)
728           : detail::variant_data<Ts...>{}
729           , index_(detail::variant_move_copy_(that.index(), data_(), that.data_()))
730         {}
731         template(typename... Args)(
732             /// \pre
733             requires (!same_as<variant<Args...>, variant>) AND
734             (all_convertible_to<Args...>(0))) //
735         variant(variant<Args...> that)
736           : detail::variant_data<Ts...>{}
737           , index_(detail::variant_move_copy_(that.index(), data_(),
738                                               std::move(that.data_())))
739         {}
740         variant & operator=(variant && that)
741         {
742             // TODO do a simple move assign when index()==that.index()
743             this->clear_();
744             this->assign_(detail::move(that));
745             return *this;
746         }
747         variant & operator=(variant const & that)
748         {
749             // TODO do a simple copy assign when index()==that.index()
750             this->clear_();
751             this->assign_(that);
752             return *this;
753         }
754         template(typename... Args)(
755             /// \pre
756             requires (!same_as<variant<Args...>, variant>) AND
757             (all_convertible_to<Args...>(0)))
758         variant & operator=(variant<Args...> that)
759         {
760             // TODO do a simple copy assign when index()==that.index() //
761             this->clear_();
762             this->assign_(that);
763             return *this;
764         }
765         static constexpr std::size_t size() noexcept
766         {
767             return sizeof...(Ts);
768         }
769         template(std::size_t N, typename... Args)(
770             /// \pre
771             requires constructible_from<datum_t<N>, Args...>)
772         void emplace(Args &&... args)
773         {
774             this->clear_();
775             detail::construct_fn<N, Args &&...> fn{static_cast<Args &&>(args)...};
776             detail::variant_visit_(N, data_(), std::ref(fn), identity{});
777             index_ = N;
778         }
779         constexpr bool valid() const noexcept
780         {
781             return index() != (std::size_t)-1;
782         }
783         constexpr std::size_t index() const noexcept
784         {
785             return index_;
786         }
787         template<typename Fun>
788         detail::variant_visit_results_t<composed<Fun, unbox_fn>, Ts...> visit(Fun fun)
789         {
790             detail::variant_visit_results_t<composed<Fun, unbox_fn>, Ts...> res{
791                 detail::empty_variant_tag{}};
792             detail::variant_visit_(index_,
793                                    data_(),
794                                    detail::make_variant_visitor(
795                                        res, compose(detail::move(fun), unbox_fn{})));
796             return res;
797         }
798         template<typename Fun>
799         detail::variant_visit_results_t<composed<Fun, unbox_fn>, add_const_t<Ts>...>
800         visit(Fun fun) const
801         {
802             detail::variant_visit_results_t<composed<Fun, unbox_fn>, add_const_t<Ts>...>
803                 res{detail::empty_variant_tag{}};
804             detail::variant_visit_(index_,
805                                    data_(),
806                                    detail::make_variant_visitor(
807                                        res, compose(detail::move(fun), unbox_fn{})));
808             return res;
809         }
810         template<typename Fun>
811         detail::variant_visit_results_t<Fun, Ts...> visit_i(Fun fun)
812         {
813             detail::variant_visit_results_t<Fun, Ts...> res{detail::empty_variant_tag{}};
814             detail::variant_visit_(
815                 index_, data_(), detail::make_variant_visitor(res, detail::move(fun)));
816             return res;
817         }
818         template<typename Fun>
819         detail::variant_visit_results_t<Fun, add_const_t<Ts>...> visit_i(Fun fun) const
820         {
821             detail::variant_visit_results_t<Fun, add_const_t<Ts>...> res{
822                 detail::empty_variant_tag{}};
823             detail::variant_visit_(
824                 index_, data_(), detail::make_variant_visitor(res, detail::move(fun)));
825             return res;
826         }
827     };
828 
829     template(typename... Ts, typename... Us)(
830         /// \pre
831         requires and_v<equality_comparable_with<Ts, Us>...>)
832     bool operator==(variant<Ts...> const & lhs, variant<Us...> const & rhs)
833     {
834         return (!lhs.valid() && !rhs.valid()) ||
835                (lhs.index() == rhs.index() &&
836                 detail::variant_equal_(lhs.index(),
837                                        detail::variant_core_access::data(lhs),
838                                        detail::variant_core_access::data(rhs)));
839     }
840 
841     template(typename... Ts, typename... Us)(
842         /// \pre
843         requires and_v<equality_comparable_with<Ts, Us>...>)
844     bool operator!=(variant<Ts...> const & lhs, variant<Us...> const & rhs)
845     {
846         return !(lhs == rhs);
847     }
848 
849     //////////////////////////////////////////////////////////////////////////////////////
850     // emplace
851     template(std::size_t N, typename... Ts, typename... Args)(
852         /// \pre
853         requires constructible_from<detail::variant_datum_t<N, Ts...>, Args...>)
854     void emplace(variant<Ts...> & var, Args &&... args)
855     {
856         var.template emplace<N>(static_cast<Args &&>(args)...);
857     }
858 
859     //////////////////////////////////////////////////////////////////////////////////////
860     // variant_unique
861     template<typename Var>
862     struct variant_unique
863     {};
864 
865     template<typename... Ts>
866     struct variant_unique<variant<Ts...>>
867     {
868         using type = meta::apply<meta::quote<variant>, meta::unique<meta::list<Ts...>>>;
869     };
870 
871     template<typename Var>
872     using variant_unique_t = meta::_t<variant_unique<Var>>;
873 
874     //////////////////////////////////////////////////////////////////////////////////////
875     // unique_variant
876     template<typename... Ts>
877     variant_unique_t<variant<Ts...>> unique_variant(variant<Ts...> const & var)
878     {
879         using From = variant<Ts...>;
880         using To = variant_unique_t<From>;
881         auto res = detail::variant_core_access::make_empty(meta::id<To>{});
882         var.visit_i(detail::unique_visitor<To, From>{&res});
883         RANGES_EXPECT(res.valid());
884         return res;
885     }
886     /// @}
887 } // namespace ranges
888 
889 RANGES_DIAGNOSTIC_PUSH
890 RANGES_DIAGNOSTIC_IGNORE_MISMATCHED_TAGS
891 
892 namespace std
893 {
894     template<typename... Ts>
895     struct tuple_size<::ranges::variant<Ts...>> : tuple_size<tuple<Ts...>>
896     {};
897 
898     template<size_t I, typename... Ts>
899     struct tuple_element<I, ::ranges::variant<Ts...>> : tuple_element<I, tuple<Ts...>>
900     {};
901 } // namespace std
902 
903 RANGES_DIAGNOSTIC_POP
904 
905 #include <range/v3/detail/epilogue.hpp>
906 
907 #endif
908