LLVM: include/llvm/ADT/TypeSwitch.h Source File (original) (raw)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15#ifndef LLVM_ADT_TYPESWITCH_H
16#define LLVM_ADT_TYPESWITCH_H
17
21#include
22
23namespace llvm {
25
26template <typename DerivedT, typename T> class TypeSwitchBase {
27public:
31
32
36
37
38 template <typename CaseT, typename CaseT2, typename... CaseTs,
39 typename CallableT>
40
41
42
43
46 DerivedT &derived = static_cast<DerivedT &>(*this);
47 return derived.template Case(caseFn)
48 .template Case<CaseT2, CaseTs...>(caseFn);
49 }
50
51
52
53
54
55 template DerivedT &Case(CallableT &&caseFn) {
57 using CaseT = std::remove_cv_t<std::remove_pointer_t<
58 std::remove_reference_t<typename Traits::template arg_t<0>>>>;
59
60 DerivedT &derived = static_cast<DerivedT &>(*this);
61 return derived.template Case(std::forward(caseFn));
62 }
63
64protected:
65
66 template <typename CastT, typename ValueT>
70
71
73};
74}
75
76
77
78
79
80
81
82
83
84
85
86
87template <typename T, typename ResultT = void>
89public:
91 using BaseT::BaseT;
94
95
96 template <typename CaseT, typename CallableT>
98 if (result)
99 return *this;
100
101
103 result.emplace(caseFn(caseValue));
104 return *this;
105 }
106
107
108 template
109 [[nodiscard]] ResultT Default(CallableT &&defaultFn) {
110 if (result)
111 return std::move(*result);
112 return defaultFn(this->value);
113 }
114
115
116 [[nodiscard]] ResultT Default(ResultT defaultResult) {
117 if (result)
118 return std::move(*result);
119 return defaultResult;
120 }
121
122
123 template <typename ArgT = ResultT,
124 typename =
125 std::enable_if_t<std::is_constructible_v<ArgT, std::nullptr_t>>>
126 [[nodiscard]] ResultT Default(std::nullptr_t) {
127 return Default(ResultT(nullptr));
128 }
129
130
131 template <typename ArgT = ResultT,
132 typename =
133 std::enable_if_t<std::is_constructible_v<ArgT, std::nullopt_t>>>
134 [[nodiscard]] ResultT Default(std::nullopt_t) {
135 return Default(ResultT(std::nullopt));
136 }
137
138
140 const char *message = "Fell off the end of a type-switch") {
141 if (result)
142 return std::move(*result);
144 }
145
147
148private:
149
150
151 std::optional result;
152};
153
154
155template
158public:
160 using BaseT::BaseT;
163
164
165 template <typename CaseT, typename CallableT>
167 if (foundMatch)
168 return *this;
169
170
172 caseFn(caseValue);
173 foundMatch = true;
174 }
175 return *this;
176 }
177
178
179 template void Default(CallableT &&defaultFn) {
180 if (!foundMatch)
181 defaultFn(this->value);
182 }
183
184
186 const char *message = "Fell off the end of a type-switch") {
187 if (!foundMatch)
189 }
190
191private:
192
193 bool foundMatch = false;
194};
195}
196
197#endif
#define LLVM_ATTRIBUTE_ALWAYS_INLINE
LLVM_ATTRIBUTE_ALWAYS_INLINE - On compilers where we have a directive to do so, mark a method "always...
#define LLVM_ATTRIBUTE_NODEBUG
LLVM_ATTRIBUTE_NO_DEBUG - On compilers where we have a directive to do so, mark a method "no debug" b...
void Default(CallableT &&defaultFn)
As a default, invoke the given callable within the root value.
Definition TypeSwitch.h:179
TypeSwitch(TypeSwitch &&other)=default
TypeSwitch< T, void > & Case(CallableT &&caseFn)
Add a case on the given type.
Definition TypeSwitch.h:166
detail::TypeSwitchBase< TypeSwitch< T, void >, T > BaseT
Definition TypeSwitch.h:159
void DefaultUnreachable(const char *message="Fell off the end of a type-switch")
Declare default as unreachable, making sure that all cases were handled.
Definition TypeSwitch.h:185
detail::TypeSwitchBase< TypeSwitch< T, ResultT >, T > BaseT
Definition TypeSwitch.h:90
ResultT Default(CallableT &&defaultFn)
As a default, invoke the given callable within the root value.
Definition TypeSwitch.h:109
ResultT Default(ResultT defaultResult)
As a default, return the given value.
Definition TypeSwitch.h:116
TypeSwitch(TypeSwitch &&other)=default
TypeSwitch< T, ResultT > & Case(CallableT &&caseFn)
Add a case on the given type.
Definition TypeSwitch.h:97
ResultT Default(std::nullptr_t)
Default for pointer-like results types that accept nullptr.
Definition TypeSwitch.h:126
ResultT DefaultUnreachable(const char *message="Fell off the end of a type-switch")
Declare default as unreachable, making sure that all cases were handled.
Definition TypeSwitch.h:139
ResultT Default(std::nullopt_t)
Default for optional results types that accept std::nullopt.
Definition TypeSwitch.h:134
Definition TypeSwitch.h:26
DerivedT & Case(CallableT &&caseFn)
Invoke a case on the derived class, inferring the type of the Case from the first input of the given ...
Definition TypeSwitch.h:55
void operator=(TypeSwitchBase &&other)=delete
void operator=(const TypeSwitchBase &)=delete
~TypeSwitchBase()=default
TypeSwitchBase(TypeSwitchBase &&other)
Definition TypeSwitch.h:29
static decltype(auto) castValue(ValueT &&value)
Attempt to dyn_cast the given value to CastT.
Definition TypeSwitch.h:67
TypeSwitchBase(const TypeSwitchBase &)=delete
TypeSwitchBase is not copyable.
TypeSwitchBase(const T &value)
Definition TypeSwitch.h:28
const T value
Definition TypeSwitch.h:72
LLVM_ATTRIBUTE_ALWAYS_INLINE LLVM_ATTRIBUTE_NODEBUG DerivedT & Case(CallableT &&caseFn)
Invoke a case on the derived class with multiple case types.
Definition TypeSwitch.h:45
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
A self-contained host- and target-independent arbitrary-precision floating-point software implementat...
This is an optimization pass for GlobalISel generic memory operations.
decltype(auto) dyn_cast(const From &Val)
dyn_cast - Return the argument parameter cast to the specified type.
@ Default
The result values are uniform if and only if all operands are uniform.
This class provides various trait information about a callable object.