1198892Srdivacky//===--- StringSwitch.h - Switch-on-literal-string Construct --------------===/ 2198892Srdivacky// 3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4353358Sdim// See https://llvm.org/LICENSE.txt for license information. 5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6198892Srdivacky//===----------------------------------------------------------------------===/ 7198892Srdivacky// 8198892Srdivacky// This file implements the StringSwitch template, which mimics a switch() 9200581Srdivacky// statement whose cases are string literals. 10198892Srdivacky// 11198892Srdivacky//===----------------------------------------------------------------------===/ 12198892Srdivacky#ifndef LLVM_ADT_STRINGSWITCH_H 13198892Srdivacky#define LLVM_ADT_STRINGSWITCH_H 14198892Srdivacky 15198892Srdivacky#include "llvm/ADT/StringRef.h" 16296417Sdim#include "llvm/Support/Compiler.h" 17198892Srdivacky#include <cassert> 18198892Srdivacky#include <cstring> 19198892Srdivacky 20198892Srdivackynamespace llvm { 21200581Srdivacky 22341825Sdim/// 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 { 43341825Sdim /// The string we are matching. 44341825Sdim const StringRef Str; 45200581Srdivacky 46341825Sdim /// The pointer to the result of this switch statement, once known, 47200581Srdivacky /// null before that. 48341825Sdim Optional<T> Result; 49200581Srdivacky 50198892Srdivackypublic: 51239462Sdim explicit StringSwitch(StringRef S) 52341825Sdim : Str(S), Result() { } 53200581Srdivacky 54314564Sdim // StringSwitch is not copyable. 55314564Sdim StringSwitch(const StringSwitch &) = delete; 56341825Sdim 57341825Sdim // StringSwitch is not assignable due to 'Str' being 'const'. 58314564Sdim void operator=(const StringSwitch &) = delete; 59341825Sdim void operator=(StringSwitch &&other) = delete; 60314564Sdim 61341825Sdim StringSwitch(StringSwitch &&other) 62341825Sdim : Str(other.Str), Result(std::move(other.Result)) { } 63314564Sdim 64314564Sdim ~StringSwitch() = default; 65314564Sdim 66314564Sdim // Case-sensitive case matchers 67341825Sdim StringSwitch &Case(StringLiteral S, T Value) { 68341825Sdim if (!Result && Str == S) { 69341825Sdim Result = std::move(Value); 70198892Srdivacky } 71198892Srdivacky return *this; 72198892Srdivacky } 73200581Srdivacky 74341825Sdim StringSwitch& EndsWith(StringLiteral S, T Value) { 75341825Sdim if (!Result && Str.endswith(S)) { 76341825Sdim Result = std::move(Value); 77212904Sdim } 78212904Sdim return *this; 79212904Sdim } 80212904Sdim 81341825Sdim StringSwitch& StartsWith(StringLiteral S, T Value) { 82341825Sdim if (!Result && Str.startswith(S)) { 83341825Sdim Result = std::move(Value); 84212904Sdim } 85212904Sdim return *this; 86212904Sdim } 87212904Sdim 88341825Sdim StringSwitch &Cases(StringLiteral S0, StringLiteral S1, T Value) { 89314564Sdim return Case(S0, Value).Case(S1, Value); 90199481Srdivacky } 91200581Srdivacky 92341825Sdim StringSwitch &Cases(StringLiteral S0, StringLiteral S1, StringLiteral S2, 93341825Sdim T Value) { 94314564Sdim return Case(S0, Value).Cases(S1, S2, Value); 95199481Srdivacky } 96200581Srdivacky 97341825Sdim StringSwitch &Cases(StringLiteral S0, StringLiteral S1, StringLiteral S2, 98341825Sdim StringLiteral S3, T Value) { 99314564Sdim return Case(S0, Value).Cases(S1, S2, S3, Value); 100199481Srdivacky } 101199481Srdivacky 102341825Sdim StringSwitch &Cases(StringLiteral S0, StringLiteral S1, StringLiteral S2, 103341825Sdim StringLiteral S3, StringLiteral S4, T Value) { 104314564Sdim return Case(S0, Value).Cases(S1, S2, S3, S4, Value); 105314564Sdim } 106314564Sdim 107341825Sdim StringSwitch &Cases(StringLiteral S0, StringLiteral S1, StringLiteral S2, 108341825Sdim StringLiteral S3, StringLiteral S4, StringLiteral S5, 109341825Sdim T Value) { 110314564Sdim return Case(S0, Value).Cases(S1, S2, S3, S4, S5, Value); 111314564Sdim } 112314564Sdim 113341825Sdim StringSwitch &Cases(StringLiteral S0, StringLiteral S1, StringLiteral S2, 114341825Sdim StringLiteral S3, StringLiteral S4, StringLiteral S5, 115341825Sdim StringLiteral S6, T Value) { 116314564Sdim return Case(S0, Value).Cases(S1, S2, S3, S4, S5, S6, Value); 117314564Sdim } 118314564Sdim 119341825Sdim StringSwitch &Cases(StringLiteral S0, StringLiteral S1, StringLiteral S2, 120341825Sdim StringLiteral S3, StringLiteral S4, StringLiteral S5, 121341825Sdim StringLiteral S6, StringLiteral S7, T Value) { 122314564Sdim return Case(S0, Value).Cases(S1, S2, S3, S4, S5, S6, S7, Value); 123314564Sdim } 124314564Sdim 125341825Sdim StringSwitch &Cases(StringLiteral S0, StringLiteral S1, StringLiteral S2, 126341825Sdim StringLiteral S3, StringLiteral S4, StringLiteral S5, 127341825Sdim StringLiteral S6, StringLiteral S7, StringLiteral S8, 128341825Sdim T Value) { 129314564Sdim return Case(S0, Value).Cases(S1, S2, S3, S4, S5, S6, S7, S8, Value); 130314564Sdim } 131314564Sdim 132341825Sdim StringSwitch &Cases(StringLiteral S0, StringLiteral S1, StringLiteral S2, 133341825Sdim StringLiteral S3, StringLiteral S4, StringLiteral S5, 134341825Sdim StringLiteral S6, StringLiteral S7, StringLiteral S8, 135341825Sdim StringLiteral S9, T Value) { 136314564Sdim return Case(S0, Value).Cases(S1, S2, S3, S4, S5, S6, S7, S8, S9, Value); 137314564Sdim } 138314564Sdim 139314564Sdim // Case-insensitive case matchers. 140341825Sdim StringSwitch &CaseLower(StringLiteral S, T Value) { 141341825Sdim if (!Result && Str.equals_lower(S)) 142341825Sdim Result = std::move(Value); 143296417Sdim 144296417Sdim return *this; 145199481Srdivacky } 146200581Srdivacky 147341825Sdim StringSwitch &EndsWithLower(StringLiteral S, T Value) { 148341825Sdim if (!Result && Str.endswith_lower(S)) 149341825Sdim Result = Value; 150314564Sdim 151314564Sdim return *this; 152314564Sdim } 153314564Sdim 154341825Sdim StringSwitch &StartsWithLower(StringLiteral S, T Value) { 155341825Sdim if (!Result && Str.startswith_lower(S)) 156341825Sdim Result = std::move(Value); 157314564Sdim 158314564Sdim return *this; 159314564Sdim } 160341825Sdim 161341825Sdim StringSwitch &CasesLower(StringLiteral S0, StringLiteral S1, T Value) { 162314564Sdim return CaseLower(S0, Value).CaseLower(S1, Value); 163314564Sdim } 164314564Sdim 165341825Sdim StringSwitch &CasesLower(StringLiteral S0, StringLiteral S1, StringLiteral S2, 166341825Sdim T Value) { 167314564Sdim return CaseLower(S0, Value).CasesLower(S1, S2, Value); 168314564Sdim } 169314564Sdim 170341825Sdim StringSwitch &CasesLower(StringLiteral S0, StringLiteral S1, StringLiteral S2, 171341825Sdim StringLiteral S3, T Value) { 172314564Sdim return CaseLower(S0, Value).CasesLower(S1, S2, S3, Value); 173314564Sdim } 174314564Sdim 175341825Sdim StringSwitch &CasesLower(StringLiteral S0, StringLiteral S1, StringLiteral S2, 176341825Sdim StringLiteral S3, StringLiteral S4, T Value) { 177314564Sdim return CaseLower(S0, Value).CasesLower(S1, S2, S3, S4, Value); 178314564Sdim } 179314564Sdim 180341825Sdim LLVM_NODISCARD 181341825Sdim R Default(T Value) { 182200581Srdivacky if (Result) 183341825Sdim return std::move(*Result); 184198892Srdivacky return Value; 185198892Srdivacky } 186200581Srdivacky 187341825Sdim LLVM_NODISCARD 188341825Sdim operator R() { 189200581Srdivacky assert(Result && "Fell off the end of a string-switch"); 190341825Sdim return std::move(*Result); 191198892Srdivacky } 192198892Srdivacky}; 193198892Srdivacky 194198892Srdivacky} // end namespace llvm 195198892Srdivacky 196198892Srdivacky#endif // LLVM_ADT_STRINGSWITCH_H 197