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 <cassert>
00018 #include <cstring>
00019 
00020 namespace llvm {
00021 
00022 /// \brief A switch()-like statement whose cases are string literals.
00023 ///
00024 /// The StringSwitch class is a simple form of a switch() statement that
00025 /// determines whether the given string matches one of the given string
00026 /// literals. The template type parameter \p T is the type of the value that
00027 /// will be returned from the string-switch expression. For example,
00028 /// the following code switches on the name of a color in \c argv[i]:
00029 ///
00030 /// \code
00031 /// Color color = StringSwitch<Color>(argv[i])
00032 ///   .Case("red", Red)
00033 ///   .Case("orange", Orange)
00034 ///   .Case("yellow", Yellow)
00035 ///   .Case("green", Green)
00036 ///   .Case("blue", Blue)
00037 ///   .Case("indigo", Indigo)
00038 ///   .Cases("violet", "purple", Violet)
00039 ///   .Default(UnknownColor);
00040 /// \endcode
00041 template<typename T, typename R = T>
00042 class StringSwitch {
00043   /// \brief The string we are matching.
00044   StringRef Str;
00045 
00046   /// \brief The pointer to the result of this switch statement, once known,
00047   /// null before that.
00048   const T *Result;
00049 
00050 public:
00051   explicit StringSwitch(StringRef S)
00052   : Str(S), Result(nullptr) { }
00053 
00054   template<unsigned N>
00055   StringSwitch& Case(const char (&S)[N], const T& Value) {
00056     if (!Result && N-1 == Str.size() &&
00057         (std::memcmp(S, Str.data(), N-1) == 0)) {
00058       Result = &Value;
00059     }
00060 
00061     return *this;
00062   }
00063 
00064   template<unsigned N>
00065   StringSwitch& EndsWith(const char (&S)[N], const T &Value) {
00066     if (!Result && Str.size() >= N-1 &&
00067         std::memcmp(S, Str.data() + Str.size() + 1 - N, N-1) == 0) {
00068       Result = &Value;
00069     }
00070 
00071     return *this;
00072   }
00073 
00074   template<unsigned N>
00075   StringSwitch& StartsWith(const char (&S)[N], const T &Value) {
00076     if (!Result && Str.size() >= N-1 &&
00077         std::memcmp(S, Str.data(), N-1) == 0) {
00078       Result = &Value;
00079     }
00080 
00081     return *this;
00082   }
00083 
00084   template<unsigned N0, unsigned N1>
00085   StringSwitch& Cases(const char (&S0)[N0], const char (&S1)[N1],
00086                       const T& Value) {
00087     return Case(S0, Value).Case(S1, Value);
00088   }
00089 
00090   template<unsigned N0, unsigned N1, unsigned N2>
00091   StringSwitch& Cases(const char (&S0)[N0], const char (&S1)[N1],
00092                       const char (&S2)[N2], const T& Value) {
00093     return Case(S0, Value).Case(S1, Value).Case(S2, Value);
00094   }
00095 
00096   template<unsigned N0, unsigned N1, unsigned N2, unsigned N3>
00097   StringSwitch& Cases(const char (&S0)[N0], const char (&S1)[N1],
00098                       const char (&S2)[N2], const char (&S3)[N3],
00099                       const T& Value) {
00100     return Case(S0, Value).Case(S1, Value).Case(S2, Value).Case(S3, Value);
00101   }
00102 
00103   template<unsigned N0, unsigned N1, unsigned N2, unsigned N3, unsigned N4>
00104   StringSwitch& Cases(const char (&S0)[N0], const char (&S1)[N1],
00105                       const char (&S2)[N2], const char (&S3)[N3],
00106                       const char (&S4)[N4], const T& Value) {
00107     return Case(S0, Value).Case(S1, Value).Case(S2, Value).Case(S3, Value)
00108       .Case(S4, Value);
00109   }
00110 
00111   R Default(const T& Value) const {
00112     if (Result)
00113       return *Result;
00114 
00115     return Value;
00116   }
00117 
00118   operator R() const {
00119     assert(Result && "Fell off the end of a string-switch");
00120     return *Result;
00121   }
00122 };
00123 
00124 } // end namespace llvm
00125 
00126 #endif // LLVM_ADT_STRINGSWITCH_H