Audacity 3.2.0
Variant.h
Go to the documentation of this file.
1/*!********************************************************************
2
3 Audacity: A Digital Audio Editor
4
5 @file Variant.h
6
7 @brief emulates std::visit for one visitor
8
9 Paul Licameli split from MemoryX.h
10
11 **********************************************************************/
12#ifndef __AUDACITY_VARIANT__
13#define __AUDACITY_VARIANT__
14
15#include <algorithm>
16#include <array>
17#include <cassert>
18#include <functional>
19#include <type_traits>
20#include <utility>
21#include <variant>
22#include <stdexcept>
23
24namespace Variant {
25
26namespace detail {
27
29template <typename Visitor, typename Variant>
31 using Var = std::remove_reference_t<Variant>;
32 using Alt = std::variant_alternative_t<0, Var>;
33 using QAlt = std::conditional_t<
34 std::is_const_v<Var>, const Alt, Alt >;
35 using Arg = std::conditional_t<std::is_lvalue_reference_v<Variant>,
36 std::add_lvalue_reference_t<QAlt>, std::add_rvalue_reference_t<QAlt>
37 >;
38 using type =
39 decltype(std::invoke(std::declval<Visitor&&>(), std::declval<Arg>()));
40};
41
43template <typename Visitor, typename Variant>
44[[noreturn]] auto VisitHelperBad(Visitor &&, Variant &&)
46{
47 // Fall through here when the variant holds no value
48 // Should really throw std::bad_variant_access but that may not be available
49 throw std::invalid_argument{"Bad variant"};
50}
51
53template <size_t Index, typename Visitor, typename Variant>
54decltype(auto) VisitHelperFunction(Visitor &&vis, Variant &&var)
55{
56 // Invoke vis at most once
57 const auto pValue = std::get_if<Index>(&var);
58 // Trust VisitHelper to dispatch correctly
59 assert(pValue);
60 if constexpr (std::is_lvalue_reference_v<Variant>)
61 return std::invoke(std::forward<Visitor>(vis), (*pValue));
62 else
63 return std::invoke(std::forward<Visitor>(vis), std::move(*pValue));
64}
65
67template <size_t Index, typename Visitor, typename Variant>
68auto TypeCheckedVisitHelperFunction(Visitor &&vis, Variant &&var)
70{
71 static_assert(std::is_same_v<
73 std::invoke_result_t<
74 decltype(VisitHelperFunction<Index, Visitor&&, Variant&&>),
75 Visitor &&, Variant &&>
76 >,
77 "Visitor must return the same type for all alternatives of the Variant.");
78 return VisitHelperFunction<Index>(
79 std::forward<Visitor>(vis), std::forward<Variant>(var));
80}
81
83template <size_t... Indices, typename Visitor, typename Variant>
84decltype(auto)
85VisitHelper(std::index_sequence<Indices...>, Visitor &&vis, Variant &&var)
86{
87 constexpr auto size = sizeof...(Indices);
89 using Function = Return(*)(Visitor&&, Variant&&);
90 static constexpr std::array<Function, size + 1> jumpTable{
91 TypeCheckedVisitHelperFunction<Indices>...,
93 };
94 auto function = jumpTable[std::min(var.index(), size)];
95 return function(std::forward<Visitor>(vis), std::forward<Variant>(var));
96}
97
99template<typename T> struct type_identity{ using type = T; };
100
102auto deduce_variant(...) -> void;
103template<typename... Types>
104auto deduce_variant(std::variant<Types...>& v)
105 -> type_identity<std::remove_reference_t<decltype(v)>>;
106template<typename... Types>
107auto deduce_variant(std::variant<Types...>&& v)
108 -> type_identity<std::remove_reference_t<decltype(v)>>;
109template<typename... Types>
110auto deduce_variant(const std::variant<Types...>& v)
111 -> type_identity<std::remove_reference_t<decltype(v)>>;
112template<typename... Types>
113auto deduce_variant(const std::variant<Types...>&& v)
114 -> type_identity<std::remove_reference_t<decltype(v)>>;
115
116template<typename T> using deduced_variant =
117 typename decltype(deduce_variant(std::declval<T>()))::type;
118
119template<typename ForwardType, typename Variant>
120decltype(auto) forward_variant(Variant &var) {
121 return std::forward<ForwardType>(var);
122
123}
124template<typename ForwardType, typename Variant>
125decltype(auto) forward_variant(const Variant &var) {
126 return std::forward<ForwardType>(var);
127}
128}
129
131
136template <typename Visitor, typename Variant,
137 typename VariantBase = detail::deduced_variant<Variant &&>>
138decltype(auto) Visit(Visitor &&vis, Variant &&var)
139{
140 using ForwardType = std::conditional_t<std::is_lvalue_reference_v<Variant>,
141 std::add_lvalue_reference_t<VariantBase>, VariantBase>;
142 constexpr auto size = std::variant_size_v<VariantBase>;
143 return detail::VisitHelper(std::make_index_sequence<size>{},
144 std::forward<Visitor>(vis), detail::forward_variant<ForwardType>(var));
145}
146
147}
148
149#endif
int min(int a, int b)
decltype(auto) VisitHelper(std::index_sequence< Indices... >, Visitor &&vis, Variant &&var)
Help to define Visit() below.
Definition: Variant.h:85
auto VisitHelperBad(Visitor &&, Variant &&) -> typename VisitHelperReturn< Visitor &&, Variant && >::type
Help to define Visit() below.
Definition: Variant.h:44
decltype(auto) forward_variant(Variant &var)
Definition: Variant.h:120
decltype(auto) VisitHelperFunction(Visitor &&vis, Variant &&var)
Help to define Visit() below.
Definition: Variant.h:54
auto TypeCheckedVisitHelperFunction(Visitor &&vis, Variant &&var) -> typename VisitHelperReturn< Visitor &&, Variant && >::type
Help to define Visit() below.
Definition: Variant.h:68
auto deduce_variant(...) -> void
Unevaluated.
typename decltype(deduce_variant(std::declval< T >()))::type deduced_variant
Definition: Variant.h:117
decltype(auto) Visit(Visitor &&vis, Variant &&var)
Mimic some of std::visit, for the case of one visitor only.
Definition: Variant.h:138
Help to define Visit() below.
Definition: Variant.h:30
std::variant_alternative_t< 0, Var > Alt
Definition: Variant.h:32
std::conditional_t< std::is_const_v< Var >, const Alt, Alt > QAlt
Definition: Variant.h:34
std::conditional_t< std::is_lvalue_reference_v< Variant >, std::add_lvalue_reference_t< QAlt >, std::add_rvalue_reference_t< QAlt > > Arg
Definition: Variant.h:37
decltype(std::invoke(std::declval< Visitor && >(), std::declval< Arg >())) type
Definition: Variant.h:39
std::remove_reference_t< Variant > Var
Definition: Variant.h:31
Standard in C++20.
Definition: Variant.h:99