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