| //===--- StringSwitch.h - Switch-on-literal-string Construct --------------===/ |
| // |
| // The LLVM Compiler Infrastructure |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| //===----------------------------------------------------------------------===/ |
| // |
| // This file implements the StringSwitch template, which mimics a switch() |
| // statement whose cases are string literals. |
| // |
| //===----------------------------------------------------------------------===/ |
| #ifndef LLVM_ADT_STRINGSWITCH_H |
| #define LLVM_ADT_STRINGSWITCH_H |
| |
| #include "llvm/ADT/StringRef.h" |
| #include "llvm/Support/Compiler.h" |
| #include <cassert> |
| #include <cstring> |
| |
| namespace llvm { |
| |
| /// \brief A switch()-like statement whose cases are string literals. |
| /// |
| /// The StringSwitch class is a simple form of a switch() statement that |
| /// determines whether the given string matches one of the given string |
| /// literals. The template type parameter \p T is the type of the value that |
| /// will be returned from the string-switch expression. For example, |
| /// the following code switches on the name of a color in \c argv[i]: |
| /// |
| /// \code |
| /// Color color = StringSwitch<Color>(argv[i]) |
| /// .Case("red", Red) |
| /// .Case("orange", Orange) |
| /// .Case("yellow", Yellow) |
| /// .Case("green", Green) |
| /// .Case("blue", Blue) |
| /// .Case("indigo", Indigo) |
| /// .Cases("violet", "purple", Violet) |
| /// .Default(UnknownColor); |
| /// \endcode |
| template<typename T, typename R = T> |
| class StringSwitch { |
| /// \brief The string we are matching. |
| StringRef Str; |
| |
| /// \brief The pointer to the result of this switch statement, once known, |
| /// null before that. |
| const T *Result; |
| |
| public: |
| LLVM_ATTRIBUTE_ALWAYS_INLINE |
| explicit StringSwitch(StringRef S) |
| : Str(S), Result(nullptr) { } |
| |
| // StringSwitch is not copyable. |
| StringSwitch(const StringSwitch &) = delete; |
| void operator=(const StringSwitch &) = delete; |
| |
| StringSwitch(StringSwitch &&other) { |
| *this = std::move(other); |
| } |
| StringSwitch &operator=(StringSwitch &&other) { |
| Str = other.Str; |
| Result = other.Result; |
| return *this; |
| } |
| |
| ~StringSwitch() = default; |
| |
| // Case-sensitive case matchers |
| template<unsigned N> |
| LLVM_ATTRIBUTE_ALWAYS_INLINE |
| StringSwitch& Case(const char (&S)[N], const T& Value) { |
| assert(N); |
| if (!Result && N-1 == Str.size() && |
| (N == 1 || std::memcmp(S, Str.data(), N-1) == 0)) { |
| Result = &Value; |
| } |
| return *this; |
| } |
| |
| template<unsigned N> |
| LLVM_ATTRIBUTE_ALWAYS_INLINE |
| StringSwitch& EndsWith(const char (&S)[N], const T &Value) { |
| assert(N); |
| if (!Result && Str.size() >= N-1 && |
| (N == 1 || std::memcmp(S, Str.data() + Str.size() + 1 - N, N-1) == 0)) { |
| Result = &Value; |
| } |
| return *this; |
| } |
| |
| template<unsigned N> |
| LLVM_ATTRIBUTE_ALWAYS_INLINE |
| StringSwitch& StartsWith(const char (&S)[N], const T &Value) { |
| assert(N); |
| if (!Result && Str.size() >= N-1 && |
| (N == 1 || std::memcmp(S, Str.data(), N-1) == 0)) { |
| Result = &Value; |
| } |
| return *this; |
| } |
| |
| template<unsigned N0, unsigned N1> |
| LLVM_ATTRIBUTE_ALWAYS_INLINE |
| StringSwitch &Cases(const char (&S0)[N0], const char (&S1)[N1], |
| const T& Value) { |
| return Case(S0, Value).Case(S1, Value); |
| } |
| |
| template<unsigned N0, unsigned N1, unsigned N2> |
| LLVM_ATTRIBUTE_ALWAYS_INLINE |
| StringSwitch &Cases(const char (&S0)[N0], const char (&S1)[N1], |
| const char (&S2)[N2], const T& Value) { |
| return Case(S0, Value).Cases(S1, S2, Value); |
| } |
| |
| template<unsigned N0, unsigned N1, unsigned N2, unsigned N3> |
| LLVM_ATTRIBUTE_ALWAYS_INLINE |
| StringSwitch &Cases(const char (&S0)[N0], const char (&S1)[N1], |
| const char (&S2)[N2], const char (&S3)[N3], |
| const T& Value) { |
| return Case(S0, Value).Cases(S1, S2, S3, Value); |
| } |
| |
| template<unsigned N0, unsigned N1, unsigned N2, unsigned N3, unsigned N4> |
| LLVM_ATTRIBUTE_ALWAYS_INLINE |
| StringSwitch &Cases(const char (&S0)[N0], const char (&S1)[N1], |
| const char (&S2)[N2], const char (&S3)[N3], |
| const char (&S4)[N4], const T& Value) { |
| return Case(S0, Value).Cases(S1, S2, S3, S4, Value); |
| } |
| |
| template <unsigned N0, unsigned N1, unsigned N2, unsigned N3, unsigned N4, |
| unsigned N5> |
| LLVM_ATTRIBUTE_ALWAYS_INLINE |
| StringSwitch &Cases(const char (&S0)[N0], const char (&S1)[N1], |
| const char (&S2)[N2], const char (&S3)[N3], |
| const char (&S4)[N4], const char (&S5)[N5], |
| const T &Value) { |
| return Case(S0, Value).Cases(S1, S2, S3, S4, S5, Value); |
| } |
| |
| template <unsigned N0, unsigned N1, unsigned N2, unsigned N3, unsigned N4, |
| unsigned N5, unsigned N6> |
| LLVM_ATTRIBUTE_ALWAYS_INLINE |
| StringSwitch &Cases(const char (&S0)[N0], const char (&S1)[N1], |
| const char (&S2)[N2], const char (&S3)[N3], |
| const char (&S4)[N4], const char (&S5)[N5], |
| const char (&S6)[N6], const T &Value) { |
| return Case(S0, Value).Cases(S1, S2, S3, S4, S5, S6, Value); |
| } |
| |
| template <unsigned N0, unsigned N1, unsigned N2, unsigned N3, unsigned N4, |
| unsigned N5, unsigned N6, unsigned N7> |
| LLVM_ATTRIBUTE_ALWAYS_INLINE |
| StringSwitch &Cases(const char (&S0)[N0], const char (&S1)[N1], |
| const char (&S2)[N2], const char (&S3)[N3], |
| const char (&S4)[N4], const char (&S5)[N5], |
| const char (&S6)[N6], const char (&S7)[N7], |
| const T &Value) { |
| return Case(S0, Value).Cases(S1, S2, S3, S4, S5, S6, S7, Value); |
| } |
| |
| template <unsigned N0, unsigned N1, unsigned N2, unsigned N3, unsigned N4, |
| unsigned N5, unsigned N6, unsigned N7, unsigned N8> |
| LLVM_ATTRIBUTE_ALWAYS_INLINE |
| StringSwitch &Cases(const char (&S0)[N0], const char (&S1)[N1], |
| const char (&S2)[N2], const char (&S3)[N3], |
| const char (&S4)[N4], const char (&S5)[N5], |
| const char (&S6)[N6], const char (&S7)[N7], |
| const char (&S8)[N8], const T &Value) { |
| return Case(S0, Value).Cases(S1, S2, S3, S4, S5, S6, S7, S8, Value); |
| } |
| |
| template <unsigned N0, unsigned N1, unsigned N2, unsigned N3, unsigned N4, |
| unsigned N5, unsigned N6, unsigned N7, unsigned N8, unsigned N9> |
| LLVM_ATTRIBUTE_ALWAYS_INLINE |
| StringSwitch &Cases(const char (&S0)[N0], const char (&S1)[N1], |
| const char (&S2)[N2], const char (&S3)[N3], |
| const char (&S4)[N4], const char (&S5)[N5], |
| const char (&S6)[N6], const char (&S7)[N7], |
| const char (&S8)[N8], const char (&S9)[N9], |
| const T &Value) { |
| return Case(S0, Value).Cases(S1, S2, S3, S4, S5, S6, S7, S8, S9, Value); |
| } |
| |
| // Case-insensitive case matchers. |
| template <unsigned N> |
| LLVM_ATTRIBUTE_ALWAYS_INLINE StringSwitch &CaseLower(const char (&S)[N], |
| const T &Value) { |
| if (!Result && Str.equals_lower(StringRef(S, N - 1))) |
| Result = &Value; |
| |
| return *this; |
| } |
| |
| template <unsigned N> |
| LLVM_ATTRIBUTE_ALWAYS_INLINE StringSwitch &EndsWithLower(const char (&S)[N], |
| const T &Value) { |
| if (!Result && Str.endswith_lower(StringRef(S, N - 1))) |
| Result = &Value; |
| |
| return *this; |
| } |
| |
| template <unsigned N> |
| LLVM_ATTRIBUTE_ALWAYS_INLINE StringSwitch &StartsWithLower(const char (&S)[N], |
| const T &Value) { |
| if (!Result && Str.startswith_lower(StringRef(S, N - 1))) |
| Result = &Value; |
| |
| return *this; |
| } |
| template <unsigned N0, unsigned N1> |
| LLVM_ATTRIBUTE_ALWAYS_INLINE StringSwitch & |
| CasesLower(const char (&S0)[N0], const char (&S1)[N1], const T &Value) { |
| return CaseLower(S0, Value).CaseLower(S1, Value); |
| } |
| |
| template <unsigned N0, unsigned N1, unsigned N2> |
| LLVM_ATTRIBUTE_ALWAYS_INLINE StringSwitch & |
| CasesLower(const char (&S0)[N0], const char (&S1)[N1], const char (&S2)[N2], |
| const T &Value) { |
| return CaseLower(S0, Value).CasesLower(S1, S2, Value); |
| } |
| |
| template <unsigned N0, unsigned N1, unsigned N2, unsigned N3> |
| LLVM_ATTRIBUTE_ALWAYS_INLINE StringSwitch & |
| CasesLower(const char (&S0)[N0], const char (&S1)[N1], const char (&S2)[N2], |
| const char (&S3)[N3], const T &Value) { |
| return CaseLower(S0, Value).CasesLower(S1, S2, S3, Value); |
| } |
| |
| template <unsigned N0, unsigned N1, unsigned N2, unsigned N3, unsigned N4> |
| LLVM_ATTRIBUTE_ALWAYS_INLINE StringSwitch & |
| CasesLower(const char (&S0)[N0], const char (&S1)[N1], const char (&S2)[N2], |
| const char (&S3)[N3], const char (&S4)[N4], const T &Value) { |
| return CaseLower(S0, Value).CasesLower(S1, S2, S3, S4, Value); |
| } |
| |
| LLVM_ATTRIBUTE_ALWAYS_INLINE |
| R Default(const T &Value) const { |
| if (Result) |
| return *Result; |
| return Value; |
| } |
| |
| LLVM_ATTRIBUTE_ALWAYS_INLINE |
| operator R() const { |
| assert(Result && "Fell off the end of a string-switch"); |
| return *Result; |
| } |
| }; |
| |
| } // end namespace llvm |
| |
| #endif // LLVM_ADT_STRINGSWITCH_H |