1dff406469313119ba79883ea6c3b44e1c0bc5740Douglas Gregor//===--- StringSwitch.h - Switch-on-literal-string Construct --------------===/
2dff406469313119ba79883ea6c3b44e1c0bc5740Douglas Gregor//
3dff406469313119ba79883ea6c3b44e1c0bc5740Douglas Gregor//                     The LLVM Compiler Infrastructure
4dff406469313119ba79883ea6c3b44e1c0bc5740Douglas Gregor//
5dff406469313119ba79883ea6c3b44e1c0bc5740Douglas Gregor// This file is distributed under the University of Illinois Open Source
6dff406469313119ba79883ea6c3b44e1c0bc5740Douglas Gregor// License. See LICENSE.TXT for details.
7dff406469313119ba79883ea6c3b44e1c0bc5740Douglas Gregor//===----------------------------------------------------------------------===/
8dff406469313119ba79883ea6c3b44e1c0bc5740Douglas Gregor//
9dff406469313119ba79883ea6c3b44e1c0bc5740Douglas Gregor//  This file implements the StringSwitch template, which mimics a switch()
10cdb7736af562a153a1a3821737ec86876f0a817eGabor Greif//  statement whose cases are string literals.
11dff406469313119ba79883ea6c3b44e1c0bc5740Douglas Gregor//
12dff406469313119ba79883ea6c3b44e1c0bc5740Douglas Gregor//===----------------------------------------------------------------------===/
13dff406469313119ba79883ea6c3b44e1c0bc5740Douglas Gregor#ifndef LLVM_ADT_STRINGSWITCH_H
14dff406469313119ba79883ea6c3b44e1c0bc5740Douglas Gregor#define LLVM_ADT_STRINGSWITCH_H
15dff406469313119ba79883ea6c3b44e1c0bc5740Douglas Gregor
16dff406469313119ba79883ea6c3b44e1c0bc5740Douglas Gregor#include "llvm/ADT/StringRef.h"
17dff406469313119ba79883ea6c3b44e1c0bc5740Douglas Gregor#include <cassert>
18dff406469313119ba79883ea6c3b44e1c0bc5740Douglas Gregor#include <cstring>
19dff406469313119ba79883ea6c3b44e1c0bc5740Douglas Gregor
20dff406469313119ba79883ea6c3b44e1c0bc5740Douglas Gregornamespace llvm {
21f3798876dfe29818e97cff43cba6785648253867Gabor Greif
22dff406469313119ba79883ea6c3b44e1c0bc5740Douglas Gregor/// \brief A switch()-like statement whose cases are string literals.
23dff406469313119ba79883ea6c3b44e1c0bc5740Douglas Gregor///
24dff406469313119ba79883ea6c3b44e1c0bc5740Douglas Gregor/// The StringSwitch class is a simple form of a switch() statement that
25dff406469313119ba79883ea6c3b44e1c0bc5740Douglas Gregor/// determines whether the given string matches one of the given string
26dff406469313119ba79883ea6c3b44e1c0bc5740Douglas Gregor/// literals. The template type parameter \p T is the type of the value that
27dff406469313119ba79883ea6c3b44e1c0bc5740Douglas Gregor/// will be returned from the string-switch expression. For example,
28dff406469313119ba79883ea6c3b44e1c0bc5740Douglas Gregor/// the following code switches on the name of a color in \c argv[i]:
29dff406469313119ba79883ea6c3b44e1c0bc5740Douglas Gregor///
30dff406469313119ba79883ea6c3b44e1c0bc5740Douglas Gregor/// \code
31dff406469313119ba79883ea6c3b44e1c0bc5740Douglas Gregor/// Color color = StringSwitch<Color>(argv[i])
32dff406469313119ba79883ea6c3b44e1c0bc5740Douglas Gregor///   .Case("red", Red)
33dff406469313119ba79883ea6c3b44e1c0bc5740Douglas Gregor///   .Case("orange", Orange)
34dff406469313119ba79883ea6c3b44e1c0bc5740Douglas Gregor///   .Case("yellow", Yellow)
35dff406469313119ba79883ea6c3b44e1c0bc5740Douglas Gregor///   .Case("green", Green)
36dff406469313119ba79883ea6c3b44e1c0bc5740Douglas Gregor///   .Case("blue", Blue)
37dff406469313119ba79883ea6c3b44e1c0bc5740Douglas Gregor///   .Case("indigo", Indigo)
38f3798876dfe29818e97cff43cba6785648253867Gabor Greif///   .Cases("violet", "purple", Violet)
39dff406469313119ba79883ea6c3b44e1c0bc5740Douglas Gregor///   .Default(UnknownColor);
40dff406469313119ba79883ea6c3b44e1c0bc5740Douglas Gregor/// \endcode
41efa9046e1673863e2b091556e5c92b834cc4bdf5Gabor Greiftemplate<typename T, typename R = T>
42dff406469313119ba79883ea6c3b44e1c0bc5740Douglas Gregorclass StringSwitch {
43dff406469313119ba79883ea6c3b44e1c0bc5740Douglas Gregor  /// \brief The string we are matching.
44dff406469313119ba79883ea6c3b44e1c0bc5740Douglas Gregor  StringRef Str;
45f3798876dfe29818e97cff43cba6785648253867Gabor Greif
46efa9046e1673863e2b091556e5c92b834cc4bdf5Gabor Greif  /// \brief The pointer to the result of this switch statement, once known,
47efa9046e1673863e2b091556e5c92b834cc4bdf5Gabor Greif  /// null before that.
48efa9046e1673863e2b091556e5c92b834cc4bdf5Gabor Greif  const T *Result;
49f3798876dfe29818e97cff43cba6785648253867Gabor Greif
50dff406469313119ba79883ea6c3b44e1c0bc5740Douglas Gregorpublic:
51f3798876dfe29818e97cff43cba6785648253867Gabor Greif  explicit StringSwitch(StringRef Str)
52efa9046e1673863e2b091556e5c92b834cc4bdf5Gabor Greif  : Str(Str), Result(0) { }
53f3798876dfe29818e97cff43cba6785648253867Gabor Greif
54dff406469313119ba79883ea6c3b44e1c0bc5740Douglas Gregor  template<unsigned N>
55dff406469313119ba79883ea6c3b44e1c0bc5740Douglas Gregor  StringSwitch& Case(const char (&S)[N], const T& Value) {
56efa9046e1673863e2b091556e5c92b834cc4bdf5Gabor Greif    if (!Result && N-1 == Str.size() &&
57dff406469313119ba79883ea6c3b44e1c0bc5740Douglas Gregor        (std::memcmp(S, Str.data(), N-1) == 0)) {
58efa9046e1673863e2b091556e5c92b834cc4bdf5Gabor Greif      Result = &Value;
59dff406469313119ba79883ea6c3b44e1c0bc5740Douglas Gregor    }
60f3798876dfe29818e97cff43cba6785648253867Gabor Greif
61dff406469313119ba79883ea6c3b44e1c0bc5740Douglas Gregor    return *this;
62dff406469313119ba79883ea6c3b44e1c0bc5740Douglas Gregor  }
63f3798876dfe29818e97cff43cba6785648253867Gabor Greif
64586a84774307d18f60055fe3199c89559a539c54Sean Hunt  template<unsigned N>
65586a84774307d18f60055fe3199c89559a539c54Sean Hunt  StringSwitch& EndsWith(const char (&S)[N], const T &Value) {
66586a84774307d18f60055fe3199c89559a539c54Sean Hunt    if (!Result && Str.size() >= N-1 &&
67586a84774307d18f60055fe3199c89559a539c54Sean Hunt        std::memcmp(S, Str.data() + Str.size() + 1 - N, N-1) == 0) {
68586a84774307d18f60055fe3199c89559a539c54Sean Hunt      Result = &Value;
69586a84774307d18f60055fe3199c89559a539c54Sean Hunt    }
70586a84774307d18f60055fe3199c89559a539c54Sean Hunt
71586a84774307d18f60055fe3199c89559a539c54Sean Hunt    return *this;
72586a84774307d18f60055fe3199c89559a539c54Sean Hunt  }
73586a84774307d18f60055fe3199c89559a539c54Sean Hunt
74586a84774307d18f60055fe3199c89559a539c54Sean Hunt  template<unsigned N>
75586a84774307d18f60055fe3199c89559a539c54Sean Hunt  StringSwitch& StartsWith(const char (&S)[N], const T &Value) {
76586a84774307d18f60055fe3199c89559a539c54Sean Hunt    if (!Result && Str.size() >= N-1 &&
77586a84774307d18f60055fe3199c89559a539c54Sean Hunt        std::memcmp(S, Str.data(), N-1) == 0) {
78586a84774307d18f60055fe3199c89559a539c54Sean Hunt      Result = &Value;
79586a84774307d18f60055fe3199c89559a539c54Sean Hunt    }
80586a84774307d18f60055fe3199c89559a539c54Sean Hunt
81586a84774307d18f60055fe3199c89559a539c54Sean Hunt    return *this;
82586a84774307d18f60055fe3199c89559a539c54Sean Hunt  }
83586a84774307d18f60055fe3199c89559a539c54Sean Hunt
84b806339fc15e8fa03aedbbebefd7674bca853265Daniel Dunbar  template<unsigned N0, unsigned N1>
85b806339fc15e8fa03aedbbebefd7674bca853265Daniel Dunbar  StringSwitch& Cases(const char (&S0)[N0], const char (&S1)[N1],
86b806339fc15e8fa03aedbbebefd7674bca853265Daniel Dunbar                      const T& Value) {
87b806339fc15e8fa03aedbbebefd7674bca853265Daniel Dunbar    return Case(S0, Value).Case(S1, Value);
88b806339fc15e8fa03aedbbebefd7674bca853265Daniel Dunbar  }
89f3798876dfe29818e97cff43cba6785648253867Gabor Greif
90b806339fc15e8fa03aedbbebefd7674bca853265Daniel Dunbar  template<unsigned N0, unsigned N1, unsigned N2>
91b806339fc15e8fa03aedbbebefd7674bca853265Daniel Dunbar  StringSwitch& Cases(const char (&S0)[N0], const char (&S1)[N1],
92b806339fc15e8fa03aedbbebefd7674bca853265Daniel Dunbar                      const char (&S2)[N2], const T& Value) {
93b806339fc15e8fa03aedbbebefd7674bca853265Daniel Dunbar    return Case(S0, Value).Case(S1, Value).Case(S2, Value);
94b806339fc15e8fa03aedbbebefd7674bca853265Daniel Dunbar  }
95f3798876dfe29818e97cff43cba6785648253867Gabor Greif
96b806339fc15e8fa03aedbbebefd7674bca853265Daniel Dunbar  template<unsigned N0, unsigned N1, unsigned N2, unsigned N3>
97b806339fc15e8fa03aedbbebefd7674bca853265Daniel Dunbar  StringSwitch& Cases(const char (&S0)[N0], const char (&S1)[N1],
98b806339fc15e8fa03aedbbebefd7674bca853265Daniel Dunbar                      const char (&S2)[N2], const char (&S3)[N3],
99b806339fc15e8fa03aedbbebefd7674bca853265Daniel Dunbar                      const T& Value) {
100b806339fc15e8fa03aedbbebefd7674bca853265Daniel Dunbar    return Case(S0, Value).Case(S1, Value).Case(S2, Value).Case(S3, Value);
101b806339fc15e8fa03aedbbebefd7674bca853265Daniel Dunbar  }
10247d60dc7125c5c8d2fc0e752b2448792db668751Nuno Lopes
10347d60dc7125c5c8d2fc0e752b2448792db668751Nuno Lopes  template<unsigned N0, unsigned N1, unsigned N2, unsigned N3, unsigned N4>
10447d60dc7125c5c8d2fc0e752b2448792db668751Nuno Lopes  StringSwitch& Cases(const char (&S0)[N0], const char (&S1)[N1],
10547d60dc7125c5c8d2fc0e752b2448792db668751Nuno Lopes                      const char (&S2)[N2], const char (&S3)[N3],
106f3798876dfe29818e97cff43cba6785648253867Gabor Greif                      const char (&S4)[N4], const T& Value) {
10747d60dc7125c5c8d2fc0e752b2448792db668751Nuno Lopes    return Case(S0, Value).Case(S1, Value).Case(S2, Value).Case(S3, Value)
10847d60dc7125c5c8d2fc0e752b2448792db668751Nuno Lopes      .Case(S4, Value);
10947d60dc7125c5c8d2fc0e752b2448792db668751Nuno Lopes  }
110f3798876dfe29818e97cff43cba6785648253867Gabor Greif
111efa9046e1673863e2b091556e5c92b834cc4bdf5Gabor Greif  R Default(const T& Value) const {
112efa9046e1673863e2b091556e5c92b834cc4bdf5Gabor Greif    if (Result)
113efa9046e1673863e2b091556e5c92b834cc4bdf5Gabor Greif      return *Result;
114f3798876dfe29818e97cff43cba6785648253867Gabor Greif
115dff406469313119ba79883ea6c3b44e1c0bc5740Douglas Gregor    return Value;
116dff406469313119ba79883ea6c3b44e1c0bc5740Douglas Gregor  }
117f3798876dfe29818e97cff43cba6785648253867Gabor Greif
118efa9046e1673863e2b091556e5c92b834cc4bdf5Gabor Greif  operator R() const {
119efa9046e1673863e2b091556e5c92b834cc4bdf5Gabor Greif    assert(Result && "Fell off the end of a string-switch");
120efa9046e1673863e2b091556e5c92b834cc4bdf5Gabor Greif    return *Result;
121dff406469313119ba79883ea6c3b44e1c0bc5740Douglas Gregor  }
122dff406469313119ba79883ea6c3b44e1c0bc5740Douglas Gregor};
123dff406469313119ba79883ea6c3b44e1c0bc5740Douglas Gregor
124dff406469313119ba79883ea6c3b44e1c0bc5740Douglas Gregor} // end namespace llvm
125dff406469313119ba79883ea6c3b44e1c0bc5740Douglas Gregor
126936e59eb5b9d2d5648249ab6c7b14619ae0662e2Zhongxing Xu#endif // LLVM_ADT_STRINGSWITCH_H
127