| //===--- 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 |