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