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