1//===--- StringSwitch.h - Switch-on-literal-string Construct --------------===/ 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7//===----------------------------------------------------------------------===/ 8// 9// This file implements the StringSwitch template, which mimics a switch() 10// statement whose cases are string literals. 11// 12//===----------------------------------------------------------------------===/ 13#ifndef LLVM_ADT_STRINGSWITCH_H 14#define LLVM_ADT_STRINGSWITCH_H 15 16#include "llvm/ADT/StringRef.h" 17#include "llvm/Support/Compiler.h" 18#include <cassert> 19#include <cstring> 20 21namespace llvm { 22 23/// \brief A switch()-like statement whose cases are string literals. 24/// 25/// The StringSwitch class is a simple form of a switch() statement that 26/// determines whether the given string matches one of the given string 27/// literals. The template type parameter \p T is the type of the value that 28/// will be returned from the string-switch expression. For example, 29/// the following code switches on the name of a color in \c argv[i]: 30/// 31/// \code 32/// Color color = StringSwitch<Color>(argv[i]) 33/// .Case("red", Red) 34/// .Case("orange", Orange) 35/// .Case("yellow", Yellow) 36/// .Case("green", Green) 37/// .Case("blue", Blue) 38/// .Case("indigo", Indigo) 39/// .Cases("violet", "purple", Violet) 40/// .Default(UnknownColor); 41/// \endcode 42template<typename T, typename R = T> 43class StringSwitch { 44 /// \brief The string we are matching. 45 StringRef Str; 46 47 /// \brief The pointer to the result of this switch statement, once known, 48 /// null before that. 49 const T *Result; 50 51public: 52 LLVM_ATTRIBUTE_ALWAYS_INLINE 53 explicit StringSwitch(StringRef S) 54 : Str(S), Result(nullptr) { } 55 56 template<unsigned N> 57 LLVM_ATTRIBUTE_ALWAYS_INLINE 58 StringSwitch& Case(const char (&S)[N], const T& Value) { 59 if (!Result && N-1 == Str.size() && 60 (std::memcmp(S, Str.data(), N-1) == 0)) { 61 Result = &Value; 62 } 63 64 return *this; 65 } 66 67 template<unsigned N> 68 LLVM_ATTRIBUTE_ALWAYS_INLINE 69 StringSwitch& EndsWith(const char (&S)[N], const T &Value) { 70 if (!Result && Str.size() >= N-1 && 71 std::memcmp(S, Str.data() + Str.size() + 1 - N, N-1) == 0) { 72 Result = &Value; 73 } 74 75 return *this; 76 } 77 78 template<unsigned N> 79 LLVM_ATTRIBUTE_ALWAYS_INLINE 80 StringSwitch& StartsWith(const char (&S)[N], const T &Value) { 81 if (!Result && Str.size() >= N-1 && 82 std::memcmp(S, Str.data(), N-1) == 0) { 83 Result = &Value; 84 } 85 86 return *this; 87 } 88 89 template<unsigned N0, unsigned N1> 90 LLVM_ATTRIBUTE_ALWAYS_INLINE 91 StringSwitch& Cases(const char (&S0)[N0], const char (&S1)[N1], 92 const T& Value) { 93 if (!Result && ( 94 (N0-1 == Str.size() && std::memcmp(S0, Str.data(), N0-1) == 0) || 95 (N1-1 == Str.size() && std::memcmp(S1, Str.data(), N1-1) == 0))) { 96 Result = &Value; 97 } 98 99 return *this; 100 } 101 102 template<unsigned N0, unsigned N1, unsigned N2> 103 LLVM_ATTRIBUTE_ALWAYS_INLINE 104 StringSwitch& Cases(const char (&S0)[N0], const char (&S1)[N1], 105 const char (&S2)[N2], const T& Value) { 106 if (!Result && ( 107 (N0-1 == Str.size() && std::memcmp(S0, Str.data(), N0-1) == 0) || 108 (N1-1 == Str.size() && std::memcmp(S1, Str.data(), N1-1) == 0) || 109 (N2-1 == Str.size() && std::memcmp(S2, Str.data(), N2-1) == 0))) { 110 Result = &Value; 111 } 112 113 return *this; 114 } 115 116 template<unsigned N0, unsigned N1, unsigned N2, unsigned N3> 117 LLVM_ATTRIBUTE_ALWAYS_INLINE 118 StringSwitch& Cases(const char (&S0)[N0], const char (&S1)[N1], 119 const char (&S2)[N2], const char (&S3)[N3], 120 const T& Value) { 121 if (!Result && ( 122 (N0-1 == Str.size() && std::memcmp(S0, Str.data(), N0-1) == 0) || 123 (N1-1 == Str.size() && std::memcmp(S1, Str.data(), N1-1) == 0) || 124 (N2-1 == Str.size() && std::memcmp(S2, Str.data(), N2-1) == 0) || 125 (N3-1 == Str.size() && std::memcmp(S3, Str.data(), N3-1) == 0))) { 126 Result = &Value; 127 } 128 129 return *this; 130 } 131 132 template<unsigned N0, unsigned N1, unsigned N2, unsigned N3, unsigned N4> 133 LLVM_ATTRIBUTE_ALWAYS_INLINE 134 StringSwitch& Cases(const char (&S0)[N0], const char (&S1)[N1], 135 const char (&S2)[N2], const char (&S3)[N3], 136 const char (&S4)[N4], const T& Value) { 137 if (!Result && ( 138 (N0-1 == Str.size() && std::memcmp(S0, Str.data(), N0-1) == 0) || 139 (N1-1 == Str.size() && std::memcmp(S1, Str.data(), N1-1) == 0) || 140 (N2-1 == Str.size() && std::memcmp(S2, Str.data(), N2-1) == 0) || 141 (N3-1 == Str.size() && std::memcmp(S3, Str.data(), N3-1) == 0) || 142 (N4-1 == Str.size() && std::memcmp(S4, Str.data(), N4-1) == 0))) { 143 Result = &Value; 144 } 145 146 return *this; 147 } 148 149 LLVM_ATTRIBUTE_ALWAYS_INLINE 150 R Default(const T& Value) const { 151 if (Result) 152 return *Result; 153 154 return Value; 155 } 156 157 LLVM_ATTRIBUTE_ALWAYS_INLINE 158 operator R() const { 159 assert(Result && "Fell off the end of a string-switch"); 160 return *Result; 161 } 162}; 163 164} // end namespace llvm 165 166#endif // LLVM_ADT_STRINGSWITCH_H 167