1f25cf3d56f54a1f736db066924e6db886b3f5f3dDouglas Gregor//===--- StringSwitch.h - Switch-on-literal-string Construct --------------===/ 2f25cf3d56f54a1f736db066924e6db886b3f5f3dDouglas Gregor// 3f25cf3d56f54a1f736db066924e6db886b3f5f3dDouglas Gregor// The LLVM Compiler Infrastructure 4f25cf3d56f54a1f736db066924e6db886b3f5f3dDouglas Gregor// 5f25cf3d56f54a1f736db066924e6db886b3f5f3dDouglas Gregor// This file is distributed under the University of Illinois Open Source 6f25cf3d56f54a1f736db066924e6db886b3f5f3dDouglas Gregor// License. See LICENSE.TXT for details. 7f25cf3d56f54a1f736db066924e6db886b3f5f3dDouglas Gregor//===----------------------------------------------------------------------===/ 8f25cf3d56f54a1f736db066924e6db886b3f5f3dDouglas Gregor// 9f25cf3d56f54a1f736db066924e6db886b3f5f3dDouglas Gregor// This file implements the StringSwitch template, which mimics a switch() 10074fe8324dd9533f1cd210091b15719ff67f49c2Gabor Greif// statement whose cases are string literals. 11f25cf3d56f54a1f736db066924e6db886b3f5f3dDouglas Gregor// 12f25cf3d56f54a1f736db066924e6db886b3f5f3dDouglas Gregor//===----------------------------------------------------------------------===/ 13f25cf3d56f54a1f736db066924e6db886b3f5f3dDouglas Gregor#ifndef LLVM_ADT_STRINGSWITCH_H 14f25cf3d56f54a1f736db066924e6db886b3f5f3dDouglas Gregor#define LLVM_ADT_STRINGSWITCH_H 15f25cf3d56f54a1f736db066924e6db886b3f5f3dDouglas Gregor 16f25cf3d56f54a1f736db066924e6db886b3f5f3dDouglas Gregor#include "llvm/ADT/StringRef.h" 17f25cf3d56f54a1f736db066924e6db886b3f5f3dDouglas Gregor#include <cassert> 18f25cf3d56f54a1f736db066924e6db886b3f5f3dDouglas Gregor#include <cstring> 19f25cf3d56f54a1f736db066924e6db886b3f5f3dDouglas Gregor 20f25cf3d56f54a1f736db066924e6db886b3f5f3dDouglas Gregornamespace llvm { 216c2a7a04da2a6c8829b82cecb355b718f350c4f1Gabor Greif 22f25cf3d56f54a1f736db066924e6db886b3f5f3dDouglas Gregor/// \brief A switch()-like statement whose cases are string literals. 23f25cf3d56f54a1f736db066924e6db886b3f5f3dDouglas Gregor/// 24f25cf3d56f54a1f736db066924e6db886b3f5f3dDouglas Gregor/// The StringSwitch class is a simple form of a switch() statement that 25f25cf3d56f54a1f736db066924e6db886b3f5f3dDouglas Gregor/// determines whether the given string matches one of the given string 26f25cf3d56f54a1f736db066924e6db886b3f5f3dDouglas Gregor/// literals. The template type parameter \p T is the type of the value that 27f25cf3d56f54a1f736db066924e6db886b3f5f3dDouglas Gregor/// will be returned from the string-switch expression. For example, 28f25cf3d56f54a1f736db066924e6db886b3f5f3dDouglas Gregor/// the following code switches on the name of a color in \c argv[i]: 29f25cf3d56f54a1f736db066924e6db886b3f5f3dDouglas Gregor/// 30f25cf3d56f54a1f736db066924e6db886b3f5f3dDouglas Gregor/// \code 31f25cf3d56f54a1f736db066924e6db886b3f5f3dDouglas Gregor/// Color color = StringSwitch<Color>(argv[i]) 32f25cf3d56f54a1f736db066924e6db886b3f5f3dDouglas Gregor/// .Case("red", Red) 33f25cf3d56f54a1f736db066924e6db886b3f5f3dDouglas Gregor/// .Case("orange", Orange) 34f25cf3d56f54a1f736db066924e6db886b3f5f3dDouglas Gregor/// .Case("yellow", Yellow) 35f25cf3d56f54a1f736db066924e6db886b3f5f3dDouglas Gregor/// .Case("green", Green) 36f25cf3d56f54a1f736db066924e6db886b3f5f3dDouglas Gregor/// .Case("blue", Blue) 37f25cf3d56f54a1f736db066924e6db886b3f5f3dDouglas Gregor/// .Case("indigo", Indigo) 386c2a7a04da2a6c8829b82cecb355b718f350c4f1Gabor Greif/// .Cases("violet", "purple", Violet) 39f25cf3d56f54a1f736db066924e6db886b3f5f3dDouglas Gregor/// .Default(UnknownColor); 40f25cf3d56f54a1f736db066924e6db886b3f5f3dDouglas Gregor/// \endcode 41d01518630ad165e0bc7d7194abb183abfa93e0d5Gabor Greiftemplate<typename T, typename R = T> 42f25cf3d56f54a1f736db066924e6db886b3f5f3dDouglas Gregorclass StringSwitch { 43f25cf3d56f54a1f736db066924e6db886b3f5f3dDouglas Gregor /// \brief The string we are matching. 44f25cf3d56f54a1f736db066924e6db886b3f5f3dDouglas Gregor StringRef Str; 456c2a7a04da2a6c8829b82cecb355b718f350c4f1Gabor Greif 46d01518630ad165e0bc7d7194abb183abfa93e0d5Gabor Greif /// \brief The pointer to the result of this switch statement, once known, 47d01518630ad165e0bc7d7194abb183abfa93e0d5Gabor Greif /// null before that. 48d01518630ad165e0bc7d7194abb183abfa93e0d5Gabor Greif const T *Result; 496c2a7a04da2a6c8829b82cecb355b718f350c4f1Gabor Greif 50f25cf3d56f54a1f736db066924e6db886b3f5f3dDouglas Gregorpublic: 5112648bed2873fdf2120b54c5539026ff468283fbNick Kledzik explicit StringSwitch(StringRef S) 52dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines : Str(S), Result(nullptr) { } 536c2a7a04da2a6c8829b82cecb355b718f350c4f1Gabor Greif 54f25cf3d56f54a1f736db066924e6db886b3f5f3dDouglas Gregor template<unsigned N> 55f25cf3d56f54a1f736db066924e6db886b3f5f3dDouglas Gregor StringSwitch& Case(const char (&S)[N], const T& Value) { 56d01518630ad165e0bc7d7194abb183abfa93e0d5Gabor Greif if (!Result && N-1 == Str.size() && 57f25cf3d56f54a1f736db066924e6db886b3f5f3dDouglas Gregor (std::memcmp(S, Str.data(), N-1) == 0)) { 58d01518630ad165e0bc7d7194abb183abfa93e0d5Gabor Greif Result = &Value; 59f25cf3d56f54a1f736db066924e6db886b3f5f3dDouglas Gregor } 606c2a7a04da2a6c8829b82cecb355b718f350c4f1Gabor Greif 61f25cf3d56f54a1f736db066924e6db886b3f5f3dDouglas Gregor return *this; 62f25cf3d56f54a1f736db066924e6db886b3f5f3dDouglas Gregor } 636c2a7a04da2a6c8829b82cecb355b718f350c4f1Gabor Greif 64726a3d284ec1949c4ccf77e79ca0506e8a38b05cSean Hunt template<unsigned N> 65726a3d284ec1949c4ccf77e79ca0506e8a38b05cSean Hunt StringSwitch& EndsWith(const char (&S)[N], const T &Value) { 66726a3d284ec1949c4ccf77e79ca0506e8a38b05cSean Hunt if (!Result && Str.size() >= N-1 && 67726a3d284ec1949c4ccf77e79ca0506e8a38b05cSean Hunt std::memcmp(S, Str.data() + Str.size() + 1 - N, N-1) == 0) { 68726a3d284ec1949c4ccf77e79ca0506e8a38b05cSean Hunt Result = &Value; 69726a3d284ec1949c4ccf77e79ca0506e8a38b05cSean Hunt } 70726a3d284ec1949c4ccf77e79ca0506e8a38b05cSean Hunt 71726a3d284ec1949c4ccf77e79ca0506e8a38b05cSean Hunt return *this; 72726a3d284ec1949c4ccf77e79ca0506e8a38b05cSean Hunt } 73726a3d284ec1949c4ccf77e79ca0506e8a38b05cSean Hunt 74726a3d284ec1949c4ccf77e79ca0506e8a38b05cSean Hunt template<unsigned N> 75726a3d284ec1949c4ccf77e79ca0506e8a38b05cSean Hunt StringSwitch& StartsWith(const char (&S)[N], const T &Value) { 76726a3d284ec1949c4ccf77e79ca0506e8a38b05cSean Hunt if (!Result && Str.size() >= N-1 && 77726a3d284ec1949c4ccf77e79ca0506e8a38b05cSean Hunt std::memcmp(S, Str.data(), N-1) == 0) { 78726a3d284ec1949c4ccf77e79ca0506e8a38b05cSean Hunt Result = &Value; 79726a3d284ec1949c4ccf77e79ca0506e8a38b05cSean Hunt } 80726a3d284ec1949c4ccf77e79ca0506e8a38b05cSean Hunt 81726a3d284ec1949c4ccf77e79ca0506e8a38b05cSean Hunt return *this; 82726a3d284ec1949c4ccf77e79ca0506e8a38b05cSean Hunt } 83726a3d284ec1949c4ccf77e79ca0506e8a38b05cSean Hunt 8438424c9b5d464d262aa05adfc899285f86b43275Daniel Dunbar template<unsigned N0, unsigned N1> 8538424c9b5d464d262aa05adfc899285f86b43275Daniel Dunbar StringSwitch& Cases(const char (&S0)[N0], const char (&S1)[N1], 8638424c9b5d464d262aa05adfc899285f86b43275Daniel Dunbar const T& Value) { 8738424c9b5d464d262aa05adfc899285f86b43275Daniel Dunbar return Case(S0, Value).Case(S1, Value); 8838424c9b5d464d262aa05adfc899285f86b43275Daniel Dunbar } 896c2a7a04da2a6c8829b82cecb355b718f350c4f1Gabor Greif 9038424c9b5d464d262aa05adfc899285f86b43275Daniel Dunbar template<unsigned N0, unsigned N1, unsigned N2> 9138424c9b5d464d262aa05adfc899285f86b43275Daniel Dunbar StringSwitch& Cases(const char (&S0)[N0], const char (&S1)[N1], 9238424c9b5d464d262aa05adfc899285f86b43275Daniel Dunbar const char (&S2)[N2], const T& Value) { 9338424c9b5d464d262aa05adfc899285f86b43275Daniel Dunbar return Case(S0, Value).Case(S1, Value).Case(S2, Value); 9438424c9b5d464d262aa05adfc899285f86b43275Daniel Dunbar } 956c2a7a04da2a6c8829b82cecb355b718f350c4f1Gabor Greif 9638424c9b5d464d262aa05adfc899285f86b43275Daniel Dunbar template<unsigned N0, unsigned N1, unsigned N2, unsigned N3> 9738424c9b5d464d262aa05adfc899285f86b43275Daniel Dunbar StringSwitch& Cases(const char (&S0)[N0], const char (&S1)[N1], 9838424c9b5d464d262aa05adfc899285f86b43275Daniel Dunbar const char (&S2)[N2], const char (&S3)[N3], 9938424c9b5d464d262aa05adfc899285f86b43275Daniel Dunbar const T& Value) { 10038424c9b5d464d262aa05adfc899285f86b43275Daniel Dunbar return Case(S0, Value).Case(S1, Value).Case(S2, Value).Case(S3, Value); 10138424c9b5d464d262aa05adfc899285f86b43275Daniel Dunbar } 1022cd8abbf8631921c744d021214dd21998a25a946Nuno Lopes 1032cd8abbf8631921c744d021214dd21998a25a946Nuno Lopes template<unsigned N0, unsigned N1, unsigned N2, unsigned N3, unsigned N4> 1042cd8abbf8631921c744d021214dd21998a25a946Nuno Lopes StringSwitch& Cases(const char (&S0)[N0], const char (&S1)[N1], 1052cd8abbf8631921c744d021214dd21998a25a946Nuno Lopes const char (&S2)[N2], const char (&S3)[N3], 1066c2a7a04da2a6c8829b82cecb355b718f350c4f1Gabor Greif const char (&S4)[N4], const T& Value) { 1072cd8abbf8631921c744d021214dd21998a25a946Nuno Lopes return Case(S0, Value).Case(S1, Value).Case(S2, Value).Case(S3, Value) 1082cd8abbf8631921c744d021214dd21998a25a946Nuno Lopes .Case(S4, Value); 1092cd8abbf8631921c744d021214dd21998a25a946Nuno Lopes } 1106c2a7a04da2a6c8829b82cecb355b718f350c4f1Gabor Greif 111d01518630ad165e0bc7d7194abb183abfa93e0d5Gabor Greif R Default(const T& Value) const { 112d01518630ad165e0bc7d7194abb183abfa93e0d5Gabor Greif if (Result) 113d01518630ad165e0bc7d7194abb183abfa93e0d5Gabor Greif return *Result; 1146c2a7a04da2a6c8829b82cecb355b718f350c4f1Gabor Greif 115f25cf3d56f54a1f736db066924e6db886b3f5f3dDouglas Gregor return Value; 116f25cf3d56f54a1f736db066924e6db886b3f5f3dDouglas Gregor } 1176c2a7a04da2a6c8829b82cecb355b718f350c4f1Gabor Greif 118d01518630ad165e0bc7d7194abb183abfa93e0d5Gabor Greif operator R() const { 119d01518630ad165e0bc7d7194abb183abfa93e0d5Gabor Greif assert(Result && "Fell off the end of a string-switch"); 120d01518630ad165e0bc7d7194abb183abfa93e0d5Gabor Greif return *Result; 121f25cf3d56f54a1f736db066924e6db886b3f5f3dDouglas Gregor } 122f25cf3d56f54a1f736db066924e6db886b3f5f3dDouglas Gregor}; 123f25cf3d56f54a1f736db066924e6db886b3f5f3dDouglas Gregor 124f25cf3d56f54a1f736db066924e6db886b3f5f3dDouglas Gregor} // end namespace llvm 125f25cf3d56f54a1f736db066924e6db886b3f5f3dDouglas Gregor 1267a8b33a9a4da1724a652585ad805ea84a59b90e7Zhongxing Xu#endif // LLVM_ADT_STRINGSWITCH_H 127