1198892Srdivacky//===--- StringSwitch.h - Switch-on-literal-string Construct --------------===/ 2198892Srdivacky// 3198892Srdivacky// The LLVM Compiler Infrastructure 4198892Srdivacky// 5198892Srdivacky// This file is distributed under the University of Illinois Open Source 6198892Srdivacky// License. See LICENSE.TXT for details. 7198892Srdivacky//===----------------------------------------------------------------------===/ 8198892Srdivacky// 9198892Srdivacky// This file implements the StringSwitch template, which mimics a switch() 10200581Srdivacky// statement whose cases are string literals. 11198892Srdivacky// 12198892Srdivacky//===----------------------------------------------------------------------===/ 13198892Srdivacky#ifndef LLVM_ADT_STRINGSWITCH_H 14198892Srdivacky#define LLVM_ADT_STRINGSWITCH_H 15198892Srdivacky 16198892Srdivacky#include "llvm/ADT/StringRef.h" 17198892Srdivacky#include <cassert> 18198892Srdivacky#include <cstring> 19198892Srdivacky 20198892Srdivackynamespace llvm { 21200581Srdivacky 22198892Srdivacky/// \brief A switch()-like statement whose cases are string literals. 23198892Srdivacky/// 24198892Srdivacky/// The StringSwitch class is a simple form of a switch() statement that 25198892Srdivacky/// determines whether the given string matches one of the given string 26198892Srdivacky/// literals. The template type parameter \p T is the type of the value that 27198892Srdivacky/// will be returned from the string-switch expression. For example, 28198892Srdivacky/// the following code switches on the name of a color in \c argv[i]: 29198892Srdivacky/// 30198892Srdivacky/// \code 31198892Srdivacky/// Color color = StringSwitch<Color>(argv[i]) 32198892Srdivacky/// .Case("red", Red) 33198892Srdivacky/// .Case("orange", Orange) 34198892Srdivacky/// .Case("yellow", Yellow) 35198892Srdivacky/// .Case("green", Green) 36198892Srdivacky/// .Case("blue", Blue) 37198892Srdivacky/// .Case("indigo", Indigo) 38200581Srdivacky/// .Cases("violet", "purple", Violet) 39198892Srdivacky/// .Default(UnknownColor); 40198892Srdivacky/// \endcode 41200581Srdivackytemplate<typename T, typename R = T> 42198892Srdivackyclass StringSwitch { 43198892Srdivacky /// \brief The string we are matching. 44198892Srdivacky StringRef Str; 45200581Srdivacky 46200581Srdivacky /// \brief The pointer to the result of this switch statement, once known, 47200581Srdivacky /// null before that. 48200581Srdivacky const T *Result; 49200581Srdivacky 50198892Srdivackypublic: 51245431Sdim explicit StringSwitch(StringRef S) 52245431Sdim : Str(S), Result(0) { } 53200581Srdivacky 54198892Srdivacky template<unsigned N> 55198892Srdivacky StringSwitch& Case(const char (&S)[N], const T& Value) { 56200581Srdivacky if (!Result && N-1 == Str.size() && 57198892Srdivacky (std::memcmp(S, Str.data(), N-1) == 0)) { 58200581Srdivacky Result = &Value; 59198892Srdivacky } 60200581Srdivacky 61198892Srdivacky return *this; 62198892Srdivacky } 63200581Srdivacky 64212904Sdim template<unsigned N> 65212904Sdim StringSwitch& EndsWith(const char (&S)[N], const T &Value) { 66212904Sdim if (!Result && Str.size() >= N-1 && 67212904Sdim std::memcmp(S, Str.data() + Str.size() + 1 - N, N-1) == 0) { 68212904Sdim Result = &Value; 69212904Sdim } 70212904Sdim 71212904Sdim return *this; 72212904Sdim } 73212904Sdim 74212904Sdim template<unsigned N> 75212904Sdim StringSwitch& StartsWith(const char (&S)[N], const T &Value) { 76212904Sdim if (!Result && Str.size() >= N-1 && 77212904Sdim std::memcmp(S, Str.data(), N-1) == 0) { 78212904Sdim Result = &Value; 79212904Sdim } 80212904Sdim 81212904Sdim return *this; 82212904Sdim } 83212904Sdim 84199481Srdivacky template<unsigned N0, unsigned N1> 85199481Srdivacky StringSwitch& Cases(const char (&S0)[N0], const char (&S1)[N1], 86199481Srdivacky const T& Value) { 87199481Srdivacky return Case(S0, Value).Case(S1, Value); 88199481Srdivacky } 89200581Srdivacky 90199481Srdivacky template<unsigned N0, unsigned N1, unsigned N2> 91199481Srdivacky StringSwitch& Cases(const char (&S0)[N0], const char (&S1)[N1], 92199481Srdivacky const char (&S2)[N2], const T& Value) { 93199481Srdivacky return Case(S0, Value).Case(S1, Value).Case(S2, Value); 94199481Srdivacky } 95200581Srdivacky 96199481Srdivacky template<unsigned N0, unsigned N1, unsigned N2, unsigned N3> 97199481Srdivacky StringSwitch& Cases(const char (&S0)[N0], const char (&S1)[N1], 98199481Srdivacky const char (&S2)[N2], const char (&S3)[N3], 99199481Srdivacky const T& Value) { 100199481Srdivacky return Case(S0, Value).Case(S1, Value).Case(S2, Value).Case(S3, Value); 101199481Srdivacky } 102199481Srdivacky 103199481Srdivacky template<unsigned N0, unsigned N1, unsigned N2, unsigned N3, unsigned N4> 104199481Srdivacky StringSwitch& Cases(const char (&S0)[N0], const char (&S1)[N1], 105199481Srdivacky const char (&S2)[N2], const char (&S3)[N3], 106200581Srdivacky const char (&S4)[N4], const T& Value) { 107199481Srdivacky return Case(S0, Value).Case(S1, Value).Case(S2, Value).Case(S3, Value) 108199481Srdivacky .Case(S4, Value); 109199481Srdivacky } 110200581Srdivacky 111200581Srdivacky R Default(const T& Value) const { 112200581Srdivacky if (Result) 113200581Srdivacky return *Result; 114200581Srdivacky 115198892Srdivacky return Value; 116198892Srdivacky } 117200581Srdivacky 118200581Srdivacky operator R() const { 119200581Srdivacky assert(Result && "Fell off the end of a string-switch"); 120200581Srdivacky return *Result; 121198892Srdivacky } 122198892Srdivacky}; 123198892Srdivacky 124198892Srdivacky} // end namespace llvm 125198892Srdivacky 126198892Srdivacky#endif // LLVM_ADT_STRINGSWITCH_H 127