File indexing completed on 2026-05-10 08:43:10
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015 #ifndef LLVM_ADT_TYPESWITCH_H
0016 #define LLVM_ADT_TYPESWITCH_H
0017
0018 #include "llvm/ADT/STLExtras.h"
0019 #include "llvm/Support/Casting.h"
0020 #include <optional>
0021
0022 namespace llvm {
0023 namespace detail {
0024
0025 template <typename DerivedT, typename T> class TypeSwitchBase {
0026 public:
0027 TypeSwitchBase(const T &value) : value(value) {}
0028 TypeSwitchBase(TypeSwitchBase &&other) : value(other.value) {}
0029 ~TypeSwitchBase() = default;
0030
0031
0032 TypeSwitchBase(const TypeSwitchBase &) = delete;
0033 void operator=(const TypeSwitchBase &) = delete;
0034 void operator=(TypeSwitchBase &&other) = delete;
0035
0036
0037 template <typename CaseT, typename CaseT2, typename... CaseTs,
0038 typename CallableT>
0039
0040
0041
0042
0043 LLVM_ATTRIBUTE_ALWAYS_INLINE LLVM_ATTRIBUTE_NODEBUG DerivedT &
0044 Case(CallableT &&caseFn) {
0045 DerivedT &derived = static_cast<DerivedT &>(*this);
0046 return derived.template Case<CaseT>(caseFn)
0047 .template Case<CaseT2, CaseTs...>(caseFn);
0048 }
0049
0050
0051
0052
0053
0054 template <typename CallableT> DerivedT &Case(CallableT &&caseFn) {
0055 using Traits = function_traits<std::decay_t<CallableT>>;
0056 using CaseT = std::remove_cv_t<std::remove_pointer_t<
0057 std::remove_reference_t<typename Traits::template arg_t<0>>>>;
0058
0059 DerivedT &derived = static_cast<DerivedT &>(*this);
0060 return derived.template Case<CaseT>(std::forward<CallableT>(caseFn));
0061 }
0062
0063 protected:
0064
0065 template <typename CastT, typename ValueT>
0066 static decltype(auto) castValue(ValueT &&value) {
0067 return dyn_cast<CastT>(value);
0068 }
0069
0070
0071 const T value;
0072 };
0073 }
0074
0075
0076
0077
0078
0079
0080
0081
0082
0083
0084
0085
0086 template <typename T, typename ResultT = void>
0087 class TypeSwitch : public detail::TypeSwitchBase<TypeSwitch<T, ResultT>, T> {
0088 public:
0089 using BaseT = detail::TypeSwitchBase<TypeSwitch<T, ResultT>, T>;
0090 using BaseT::BaseT;
0091 using BaseT::Case;
0092 TypeSwitch(TypeSwitch &&other) = default;
0093
0094
0095 template <typename CaseT, typename CallableT>
0096 TypeSwitch<T, ResultT> &Case(CallableT &&caseFn) {
0097 if (result)
0098 return *this;
0099
0100
0101 if (auto caseValue = BaseT::template castValue<CaseT>(this->value))
0102 result.emplace(caseFn(caseValue));
0103 return *this;
0104 }
0105
0106
0107 template <typename CallableT>
0108 [[nodiscard]] ResultT Default(CallableT &&defaultFn) {
0109 if (result)
0110 return std::move(*result);
0111 return defaultFn(this->value);
0112 }
0113
0114 [[nodiscard]] ResultT Default(ResultT defaultResult) {
0115 if (result)
0116 return std::move(*result);
0117 return defaultResult;
0118 }
0119
0120 [[nodiscard]] operator ResultT() {
0121 assert(result && "Fell off the end of a type-switch");
0122 return std::move(*result);
0123 }
0124
0125 private:
0126
0127
0128 std::optional<ResultT> result;
0129 };
0130
0131
0132 template <typename T>
0133 class TypeSwitch<T, void>
0134 : public detail::TypeSwitchBase<TypeSwitch<T, void>, T> {
0135 public:
0136 using BaseT = detail::TypeSwitchBase<TypeSwitch<T, void>, T>;
0137 using BaseT::BaseT;
0138 using BaseT::Case;
0139 TypeSwitch(TypeSwitch &&other) = default;
0140
0141
0142 template <typename CaseT, typename CallableT>
0143 TypeSwitch<T, void> &Case(CallableT &&caseFn) {
0144 if (foundMatch)
0145 return *this;
0146
0147
0148 if (auto caseValue = BaseT::template castValue<CaseT>(this->value)) {
0149 caseFn(caseValue);
0150 foundMatch = true;
0151 }
0152 return *this;
0153 }
0154
0155
0156 template <typename CallableT> void Default(CallableT &&defaultFn) {
0157 if (!foundMatch)
0158 defaultFn(this->value);
0159 }
0160
0161 private:
0162
0163 bool foundMatch = false;
0164 };
0165 }
0166
0167 #endif