LLVM  mainline
StringSwitch.h
Go to the documentation of this file.
00001 //===--- StringSwitch.h - Switch-on-literal-string Construct --------------===/
00002 //
00003 //                     The LLVM Compiler Infrastructure
00004 //
00005 // This file is distributed under the University of Illinois Open Source
00006 // License. See LICENSE.TXT for details.
00007 //===----------------------------------------------------------------------===/
00008 //
00009 //  This file implements the StringSwitch template, which mimics a switch()
00010 //  statement whose cases are string literals.
00011 //
00012 //===----------------------------------------------------------------------===/
00013 #ifndef LLVM_ADT_STRINGSWITCH_H
00014 #define LLVM_ADT_STRINGSWITCH_H
00015 
00016 #include "llvm/ADT/StringRef.h"
00017 #include "llvm/Support/Compiler.h"
00018 #include <cassert>
00019 #include <cstring>
00020 
00021 namespace llvm {
00022 
00023 /// \brief A switch()-like statement whose cases are string literals.
00024 ///
00025 /// The StringSwitch class is a simple form of a switch() statement that
00026 /// determines whether the given string matches one of the given string
00027 /// literals. The template type parameter \p T is the type of the value that
00028 /// will be returned from the string-switch expression. For example,
00029 /// the following code switches on the name of a color in \c argv[i]:
00030 ///
00031 /// \code
00032 /// Color color = StringSwitch<Color>(argv[i])
00033 ///   .Case("red", Red)
00034 ///   .Case("orange", Orange)
00035 ///   .Case("yellow", Yellow)
00036 ///   .Case("green", Green)
00037 ///   .Case("blue", Blue)
00038 ///   .Case("indigo", Indigo)
00039 ///   .Cases("violet", "purple", Violet)
00040 ///   .Default(UnknownColor);
00041 /// \endcode
00042 template<typename T, typename R = T>
00043 class StringSwitch {
00044   /// \brief The string we are matching.
00045   StringRef Str;
00046 
00047   /// \brief The pointer to the result of this switch statement, once known,
00048   /// null before that.
00049   const T *Result;
00050 
00051 public:
00052   LLVM_ATTRIBUTE_ALWAYS_INLINE
00053   explicit StringSwitch(StringRef S)
00054   : Str(S), Result(nullptr) { }
00055 
00056   template<unsigned N>
00057   LLVM_ATTRIBUTE_ALWAYS_INLINE
00058   StringSwitch& Case(const char (&S)[N], const T& Value) {
00059     if (!Result && N-1 == Str.size() &&
00060         (std::memcmp(S, Str.data(), N-1) == 0)) {
00061       Result = &Value;
00062     }
00063 
00064     return *this;
00065   }
00066 
00067   template<unsigned N>
00068   LLVM_ATTRIBUTE_ALWAYS_INLINE
00069   StringSwitch& EndsWith(const char (&S)[N], const T &Value) {
00070     if (!Result && Str.size() >= N-1 &&
00071         std::memcmp(S, Str.data() + Str.size() + 1 - N, N-1) == 0) {
00072       Result = &Value;
00073     }
00074 
00075     return *this;
00076   }
00077 
00078   template<unsigned N>
00079   LLVM_ATTRIBUTE_ALWAYS_INLINE
00080   StringSwitch& StartsWith(const char (&S)[N], const T &Value) {
00081     if (!Result && Str.size() >= N-1 &&
00082         std::memcmp(S, Str.data(), N-1) == 0) {
00083       Result = &Value;
00084     }
00085 
00086     return *this;
00087   }
00088 
00089   template<unsigned N0, unsigned N1>
00090   LLVM_ATTRIBUTE_ALWAYS_INLINE
00091   StringSwitch& Cases(const char (&S0)[N0], const char (&S1)[N1],
00092                       const T& Value) {
00093     if (!Result && (
00094         (N0-1 == Str.size() && std::memcmp(S0, Str.data(), N0-1) == 0) ||
00095         (N1-1 == Str.size() && std::memcmp(S1, Str.data(), N1-1) == 0))) {
00096       Result = &Value;
00097     }
00098 
00099     return *this;
00100   }
00101 
00102   template<unsigned N0, unsigned N1, unsigned N2>
00103   LLVM_ATTRIBUTE_ALWAYS_INLINE
00104   StringSwitch& Cases(const char (&S0)[N0], const char (&S1)[N1],
00105                       const char (&S2)[N2], const T& Value) {
00106     if (!Result && (
00107         (N0-1 == Str.size() && std::memcmp(S0, Str.data(), N0-1) == 0) ||
00108         (N1-1 == Str.size() && std::memcmp(S1, Str.data(), N1-1) == 0) ||
00109         (N2-1 == Str.size() && std::memcmp(S2, Str.data(), N2-1) == 0))) {
00110       Result = &Value;
00111     }
00112 
00113     return *this;
00114   }
00115 
00116   template<unsigned N0, unsigned N1, unsigned N2, unsigned N3>
00117   LLVM_ATTRIBUTE_ALWAYS_INLINE
00118   StringSwitch& Cases(const char (&S0)[N0], const char (&S1)[N1],
00119                       const char (&S2)[N2], const char (&S3)[N3],
00120                       const T& Value) {
00121     if (!Result && (
00122         (N0-1 == Str.size() && std::memcmp(S0, Str.data(), N0-1) == 0) ||
00123         (N1-1 == Str.size() && std::memcmp(S1, Str.data(), N1-1) == 0) ||
00124         (N2-1 == Str.size() && std::memcmp(S2, Str.data(), N2-1) == 0) ||
00125         (N3-1 == Str.size() && std::memcmp(S3, Str.data(), N3-1) == 0))) {
00126       Result = &Value;
00127     }
00128 
00129     return *this;
00130   }
00131 
00132   template<unsigned N0, unsigned N1, unsigned N2, unsigned N3, unsigned N4>
00133   LLVM_ATTRIBUTE_ALWAYS_INLINE
00134   StringSwitch& Cases(const char (&S0)[N0], const char (&S1)[N1],
00135                       const char (&S2)[N2], const char (&S3)[N3],
00136                       const char (&S4)[N4], const T& Value) {
00137     if (!Result && (
00138         (N0-1 == Str.size() && std::memcmp(S0, Str.data(), N0-1) == 0) ||
00139         (N1-1 == Str.size() && std::memcmp(S1, Str.data(), N1-1) == 0) ||
00140         (N2-1 == Str.size() && std::memcmp(S2, Str.data(), N2-1) == 0) ||
00141         (N3-1 == Str.size() && std::memcmp(S3, Str.data(), N3-1) == 0) ||
00142         (N4-1 == Str.size() && std::memcmp(S4, Str.data(), N4-1) == 0))) {
00143       Result = &Value;
00144     }
00145 
00146     return *this;
00147   }
00148 
00149   LLVM_ATTRIBUTE_ALWAYS_INLINE
00150   R Default(const T& Value) const {
00151     if (Result)
00152       return *Result;
00153 
00154     return Value;
00155   }
00156 
00157   LLVM_ATTRIBUTE_ALWAYS_INLINE
00158   operator R() const {
00159     assert(Result && "Fell off the end of a string-switch");
00160     return *Result;
00161   }
00162 };
00163 
00164 } // end namespace llvm
00165 
00166 #endif // LLVM_ADT_STRINGSWITCH_H