Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-10 08:43:10

0001 //===- TypeSwitch.h - Switch functionality for RTTI casting -*- C++ -*-----===//
0002 //
0003 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
0004 // See https://llvm.org/LICENSE.txt for license information.
0005 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
0006 //
0007 //===----------------------------------------------------------------------===//
0008 ///
0009 /// \file
0010 ///  This file implements the TypeSwitch template, which mimics a switch()
0011 ///  statement whose cases are type names.
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   /// TypeSwitchBase is not copyable.
0032   TypeSwitchBase(const TypeSwitchBase &) = delete;
0033   void operator=(const TypeSwitchBase &) = delete;
0034   void operator=(TypeSwitchBase &&other) = delete;
0035 
0036   /// Invoke a case on the derived class with multiple case types.
0037   template <typename CaseT, typename CaseT2, typename... CaseTs,
0038             typename CallableT>
0039   // This is marked always_inline and nodebug so it doesn't show up in stack
0040   // traces at -O0 (or other optimization levels).  Large TypeSwitch's are
0041   // common, are equivalent to a switch, and don't add any value to stack
0042   // traces.
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   /// Invoke a case on the derived class, inferring the type of the Case from
0051   /// the first input of the given callable.
0052   /// Note: This inference rules for this overload are very simple: strip
0053   ///       pointers and references.
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   /// Attempt to dyn_cast the given `value` to `CastT`.
0065   template <typename CastT, typename ValueT>
0066   static decltype(auto) castValue(ValueT &&value) {
0067     return dyn_cast<CastT>(value);
0068   }
0069 
0070   /// The root value we are switching on.
0071   const T value;
0072 };
0073 } // end namespace detail
0074 
0075 /// This class implements a switch-like dispatch statement for a value of 'T'
0076 /// using dyn_cast functionality. Each `Case<T>` takes a callable to be invoked
0077 /// if the root value isa<T>, the callable is invoked with the result of
0078 /// dyn_cast<T>() as a parameter.
0079 ///
0080 /// Example:
0081 ///  Operation *op = ...;
0082 ///  LogicalResult result = TypeSwitch<Operation *, LogicalResult>(op)
0083 ///    .Case<ConstantOp>([](ConstantOp op) { ... })
0084 ///    .Default([](Operation *op) { ... });
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   /// Add a case on the given type.
0095   template <typename CaseT, typename CallableT>
0096   TypeSwitch<T, ResultT> &Case(CallableT &&caseFn) {
0097     if (result)
0098       return *this;
0099 
0100     // Check to see if CaseT applies to 'value'.
0101     if (auto caseValue = BaseT::template castValue<CaseT>(this->value))
0102       result.emplace(caseFn(caseValue));
0103     return *this;
0104   }
0105 
0106   /// As a default, invoke the given callable within the root value.
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   /// As a default, return the given value.
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   /// The pointer to the result of this switch statement, once known,
0127   /// null before that.
0128   std::optional<ResultT> result;
0129 };
0130 
0131 /// Specialization of TypeSwitch for void returning callables.
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   /// Add a case on the given type.
0142   template <typename CaseT, typename CallableT>
0143   TypeSwitch<T, void> &Case(CallableT &&caseFn) {
0144     if (foundMatch)
0145       return *this;
0146 
0147     // Check to see if any of the types apply to 'value'.
0148     if (auto caseValue = BaseT::template castValue<CaseT>(this->value)) {
0149       caseFn(caseValue);
0150       foundMatch = true;
0151     }
0152     return *this;
0153   }
0154 
0155   /// As a default, invoke the given callable within the root value.
0156   template <typename CallableT> void Default(CallableT &&defaultFn) {
0157     if (!foundMatch)
0158       defaultFn(this->value);
0159   }
0160 
0161 private:
0162   /// A flag detailing if we have already found a match.
0163   bool foundMatch = false;
0164 };
0165 } // end namespace llvm
0166 
0167 #endif // LLVM_ADT_TYPESWITCH_H