forked from OSchip/llvm-project
[ADT] Simplify and optimize StringSwitch
This change improves incremental rebuild performance on dual Xeon 8168 machines by 54%. This change also improves run time code gen by not forcing the case values to be lvalues. llvm-svn: 326109
This commit is contained in:
parent
a456db3ea3
commit
d15f31936a
|
@ -855,6 +855,10 @@ namespace llvm {
|
|||
/// constexpr StringLiteral S("test");
|
||||
///
|
||||
class StringLiteral : public StringRef {
|
||||
private:
|
||||
constexpr StringLiteral(const char *Str, size_t N) : StringRef(Str, N) {
|
||||
}
|
||||
|
||||
public:
|
||||
template <size_t N>
|
||||
constexpr StringLiteral(const char (&Str)[N])
|
||||
|
@ -867,6 +871,12 @@ namespace llvm {
|
|||
#endif
|
||||
: StringRef(Str, N - 1) {
|
||||
}
|
||||
|
||||
// Explicit construction for strings like "foo\0bar".
|
||||
template <size_t N>
|
||||
static constexpr StringLiteral withInnerNUL(const char (&Str)[N]) {
|
||||
return StringLiteral(Str, N - 1);
|
||||
}
|
||||
};
|
||||
|
||||
/// @name StringRef Comparison Operators
|
||||
|
|
|
@ -42,16 +42,16 @@ namespace llvm {
|
|||
template<typename T, typename R = T>
|
||||
class StringSwitch {
|
||||
/// \brief The string we are matching.
|
||||
StringRef Str;
|
||||
const StringRef Str;
|
||||
|
||||
/// \brief The pointer to the result of this switch statement, once known,
|
||||
/// null before that.
|
||||
const T *Result;
|
||||
Optional<T> Result;
|
||||
|
||||
public:
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
explicit StringSwitch(StringRef S)
|
||||
: Str(S), Result(nullptr) { }
|
||||
: Str(S), Result() { }
|
||||
|
||||
// StringSwitch is not copyable.
|
||||
StringSwitch(const StringSwitch &) = delete;
|
||||
|
@ -61,196 +61,159 @@ public:
|
|||
*this = std::move(other);
|
||||
}
|
||||
StringSwitch &operator=(StringSwitch &&other) {
|
||||
Str = other.Str;
|
||||
Result = other.Result;
|
||||
Str = std::move(other.Str);
|
||||
Result = std::move(other.Result);
|
||||
return *this;
|
||||
}
|
||||
|
||||
~StringSwitch() = default;
|
||||
|
||||
// Case-sensitive case matchers
|
||||
template<unsigned N>
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
StringSwitch& Case(const char (&S)[N], const T& Value) {
|
||||
assert(N);
|
||||
if (!Result && N-1 == Str.size() &&
|
||||
(N == 1 || std::memcmp(S, Str.data(), N-1) == 0)) {
|
||||
Result = &Value;
|
||||
StringSwitch &Case(StringLiteral S, T Value) {
|
||||
if (!Result && Str == S) {
|
||||
Result = std::move(Value);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<unsigned N>
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
StringSwitch& EndsWith(const char (&S)[N], const T &Value) {
|
||||
assert(N);
|
||||
if (!Result && Str.size() >= N-1 &&
|
||||
(N == 1 || std::memcmp(S, Str.data() + Str.size() + 1 - N, N-1) == 0)) {
|
||||
Result = &Value;
|
||||
StringSwitch& EndsWith(StringLiteral S, T Value) {
|
||||
if (!Result && Str.endswith(S)) {
|
||||
Result = std::move(Value);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<unsigned N>
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
StringSwitch& StartsWith(const char (&S)[N], const T &Value) {
|
||||
assert(N);
|
||||
if (!Result && Str.size() >= N-1 &&
|
||||
(N == 1 || std::memcmp(S, Str.data(), N-1) == 0)) {
|
||||
Result = &Value;
|
||||
StringSwitch& StartsWith(StringLiteral S, T Value) {
|
||||
if (!Result && Str.startswith(S)) {
|
||||
Result = std::move(Value);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<unsigned N0, unsigned N1>
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
StringSwitch &Cases(const char (&S0)[N0], const char (&S1)[N1],
|
||||
const T& Value) {
|
||||
StringSwitch &Cases(StringLiteral S0, StringLiteral S1, T Value) {
|
||||
return Case(S0, Value).Case(S1, Value);
|
||||
}
|
||||
|
||||
template<unsigned N0, unsigned N1, unsigned N2>
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
StringSwitch &Cases(const char (&S0)[N0], const char (&S1)[N1],
|
||||
const char (&S2)[N2], const T& Value) {
|
||||
StringSwitch &Cases(StringLiteral S0, StringLiteral S1, StringLiteral S2,
|
||||
T Value) {
|
||||
return Case(S0, Value).Cases(S1, S2, Value);
|
||||
}
|
||||
|
||||
template<unsigned N0, unsigned N1, unsigned N2, unsigned N3>
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
StringSwitch &Cases(const char (&S0)[N0], const char (&S1)[N1],
|
||||
const char (&S2)[N2], const char (&S3)[N3],
|
||||
const T& Value) {
|
||||
StringSwitch &Cases(StringLiteral S0, StringLiteral S1, StringLiteral S2,
|
||||
StringLiteral S3, T Value) {
|
||||
return Case(S0, Value).Cases(S1, S2, S3, Value);
|
||||
}
|
||||
|
||||
template<unsigned N0, unsigned N1, unsigned N2, unsigned N3, unsigned N4>
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
StringSwitch &Cases(const char (&S0)[N0], const char (&S1)[N1],
|
||||
const char (&S2)[N2], const char (&S3)[N3],
|
||||
const char (&S4)[N4], const T& Value) {
|
||||
StringSwitch &Cases(StringLiteral S0, StringLiteral S1, StringLiteral S2,
|
||||
StringLiteral S3, StringLiteral S4, T Value) {
|
||||
return Case(S0, Value).Cases(S1, S2, S3, S4, Value);
|
||||
}
|
||||
|
||||
template <unsigned N0, unsigned N1, unsigned N2, unsigned N3, unsigned N4,
|
||||
unsigned N5>
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
StringSwitch &Cases(const char (&S0)[N0], const char (&S1)[N1],
|
||||
const char (&S2)[N2], const char (&S3)[N3],
|
||||
const char (&S4)[N4], const char (&S5)[N5],
|
||||
const T &Value) {
|
||||
StringSwitch &Cases(StringLiteral S0, StringLiteral S1, StringLiteral S2,
|
||||
StringLiteral S3, StringLiteral S4, StringLiteral S5,
|
||||
T Value) {
|
||||
return Case(S0, Value).Cases(S1, S2, S3, S4, S5, Value);
|
||||
}
|
||||
|
||||
template <unsigned N0, unsigned N1, unsigned N2, unsigned N3, unsigned N4,
|
||||
unsigned N5, unsigned N6>
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
StringSwitch &Cases(const char (&S0)[N0], const char (&S1)[N1],
|
||||
const char (&S2)[N2], const char (&S3)[N3],
|
||||
const char (&S4)[N4], const char (&S5)[N5],
|
||||
const char (&S6)[N6], const T &Value) {
|
||||
StringSwitch &Cases(StringLiteral S0, StringLiteral S1, StringLiteral S2,
|
||||
StringLiteral S3, StringLiteral S4, StringLiteral S5,
|
||||
StringLiteral S6, T Value) {
|
||||
return Case(S0, Value).Cases(S1, S2, S3, S4, S5, S6, Value);
|
||||
}
|
||||
|
||||
template <unsigned N0, unsigned N1, unsigned N2, unsigned N3, unsigned N4,
|
||||
unsigned N5, unsigned N6, unsigned N7>
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
StringSwitch &Cases(const char (&S0)[N0], const char (&S1)[N1],
|
||||
const char (&S2)[N2], const char (&S3)[N3],
|
||||
const char (&S4)[N4], const char (&S5)[N5],
|
||||
const char (&S6)[N6], const char (&S7)[N7],
|
||||
const T &Value) {
|
||||
StringSwitch &Cases(StringLiteral S0, StringLiteral S1, StringLiteral S2,
|
||||
StringLiteral S3, StringLiteral S4, StringLiteral S5,
|
||||
StringLiteral S6, StringLiteral S7, T Value) {
|
||||
return Case(S0, Value).Cases(S1, S2, S3, S4, S5, S6, S7, Value);
|
||||
}
|
||||
|
||||
template <unsigned N0, unsigned N1, unsigned N2, unsigned N3, unsigned N4,
|
||||
unsigned N5, unsigned N6, unsigned N7, unsigned N8>
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
StringSwitch &Cases(const char (&S0)[N0], const char (&S1)[N1],
|
||||
const char (&S2)[N2], const char (&S3)[N3],
|
||||
const char (&S4)[N4], const char (&S5)[N5],
|
||||
const char (&S6)[N6], const char (&S7)[N7],
|
||||
const char (&S8)[N8], const T &Value) {
|
||||
StringSwitch &Cases(StringLiteral S0, StringLiteral S1, StringLiteral S2,
|
||||
StringLiteral S3, StringLiteral S4, StringLiteral S5,
|
||||
StringLiteral S6, StringLiteral S7, StringLiteral S8,
|
||||
T Value) {
|
||||
return Case(S0, Value).Cases(S1, S2, S3, S4, S5, S6, S7, S8, Value);
|
||||
}
|
||||
|
||||
template <unsigned N0, unsigned N1, unsigned N2, unsigned N3, unsigned N4,
|
||||
unsigned N5, unsigned N6, unsigned N7, unsigned N8, unsigned N9>
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
StringSwitch &Cases(const char (&S0)[N0], const char (&S1)[N1],
|
||||
const char (&S2)[N2], const char (&S3)[N3],
|
||||
const char (&S4)[N4], const char (&S5)[N5],
|
||||
const char (&S6)[N6], const char (&S7)[N7],
|
||||
const char (&S8)[N8], const char (&S9)[N9],
|
||||
const T &Value) {
|
||||
StringSwitch &Cases(StringLiteral S0, StringLiteral S1, StringLiteral S2,
|
||||
StringLiteral S3, StringLiteral S4, StringLiteral S5,
|
||||
StringLiteral S6, StringLiteral S7, StringLiteral S8,
|
||||
StringLiteral S9, T Value) {
|
||||
return Case(S0, Value).Cases(S1, S2, S3, S4, S5, S6, S7, S8, S9, Value);
|
||||
}
|
||||
|
||||
// Case-insensitive case matchers.
|
||||
template <unsigned N>
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE StringSwitch &CaseLower(const char (&S)[N],
|
||||
const T &Value) {
|
||||
if (!Result && Str.equals_lower(StringRef(S, N - 1)))
|
||||
Result = &Value;
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
StringSwitch &CaseLower(StringLiteral S, T Value) {
|
||||
if (!Result && Str.equals_lower(S))
|
||||
Result = std::move(Value);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <unsigned N>
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE StringSwitch &EndsWithLower(const char (&S)[N],
|
||||
const T &Value) {
|
||||
if (!Result && Str.endswith_lower(StringRef(S, N - 1)))
|
||||
Result = &Value;
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
StringSwitch &EndsWithLower(StringLiteral S, T Value) {
|
||||
if (!Result && Str.endswith_lower(S))
|
||||
Result = Value;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <unsigned N>
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE StringSwitch &StartsWithLower(const char (&S)[N],
|
||||
const T &Value) {
|
||||
if (!Result && Str.startswith_lower(StringRef(S, N - 1)))
|
||||
Result = &Value;
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
StringSwitch &StartsWithLower(StringLiteral S, T Value) {
|
||||
if (!Result && Str.startswith_lower(S))
|
||||
Result = std::move(Value);
|
||||
|
||||
return *this;
|
||||
}
|
||||
template <unsigned N0, unsigned N1>
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE StringSwitch &
|
||||
CasesLower(const char (&S0)[N0], const char (&S1)[N1], const T &Value) {
|
||||
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
StringSwitch &CasesLower(StringLiteral S0, StringLiteral S1, T Value) {
|
||||
return CaseLower(S0, Value).CaseLower(S1, Value);
|
||||
}
|
||||
|
||||
template <unsigned N0, unsigned N1, unsigned N2>
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE StringSwitch &
|
||||
CasesLower(const char (&S0)[N0], const char (&S1)[N1], const char (&S2)[N2],
|
||||
const T &Value) {
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
StringSwitch &CasesLower(StringLiteral S0, StringLiteral S1, StringLiteral S2,
|
||||
T Value) {
|
||||
return CaseLower(S0, Value).CasesLower(S1, S2, Value);
|
||||
}
|
||||
|
||||
template <unsigned N0, unsigned N1, unsigned N2, unsigned N3>
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE StringSwitch &
|
||||
CasesLower(const char (&S0)[N0], const char (&S1)[N1], const char (&S2)[N2],
|
||||
const char (&S3)[N3], const T &Value) {
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
StringSwitch &CasesLower(StringLiteral S0, StringLiteral S1, StringLiteral S2,
|
||||
StringLiteral S3, T Value) {
|
||||
return CaseLower(S0, Value).CasesLower(S1, S2, S3, Value);
|
||||
}
|
||||
|
||||
template <unsigned N0, unsigned N1, unsigned N2, unsigned N3, unsigned N4>
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE StringSwitch &
|
||||
CasesLower(const char (&S0)[N0], const char (&S1)[N1], const char (&S2)[N2],
|
||||
const char (&S3)[N3], const char (&S4)[N4], const T &Value) {
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
StringSwitch &CasesLower(StringLiteral S0, StringLiteral S1, StringLiteral S2,
|
||||
StringLiteral S3, StringLiteral S4, T Value) {
|
||||
return CaseLower(S0, Value).CasesLower(S1, S2, S3, S4, Value);
|
||||
}
|
||||
|
||||
LLVM_NODISCARD
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
R Default(const T &Value) const {
|
||||
R Default(T Value) {
|
||||
if (Result)
|
||||
return *Result;
|
||||
return std::move(*Result);
|
||||
return Value;
|
||||
}
|
||||
|
||||
LLVM_NODISCARD
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
operator R() const {
|
||||
operator R() {
|
||||
assert(Result && "Fell off the end of a string-switch");
|
||||
return *Result;
|
||||
return std::move(*Result);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -158,7 +158,8 @@ TEST(StringSwitchTest, Cases) {
|
|||
|
||||
auto Translate = [](StringRef S) {
|
||||
return llvm::StringSwitch<OSType>(S)
|
||||
.Cases("wind\0ws", "win32", "winnt", OSType::Windows)
|
||||
.Cases(StringLiteral::withInnerNUL("wind\0ws"), "win32", "winnt",
|
||||
OSType::Windows)
|
||||
.Cases("linux", "unix", "*nix", "posix", OSType::Linux)
|
||||
.Default(OSType::Unknown);
|
||||
};
|
||||
|
@ -184,7 +185,8 @@ TEST(StringSwitchTest, CasesLower) {
|
|||
|
||||
auto Translate = [](StringRef S) {
|
||||
return llvm::StringSwitch<OSType>(S)
|
||||
.CasesLower("wind\0ws", "win32", "winnt", OSType::Windows)
|
||||
.CasesLower(StringLiteral::withInnerNUL("wind\0ws"), "win32", "winnt",
|
||||
OSType::Windows)
|
||||
.CasesLower("linux", "unix", "*nix", "posix", OSType::Linux)
|
||||
.Default(OSType::Unknown);
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue