[llvm] 673d963 - [llvm][ADT] Make `Twine` aware of `StringLiteral`
Jan Svoboda via llvm-commits
llvm-commits at lists.llvm.org
Thu Aug 3 10:53:04 PDT 2023
Author: Jan Svoboda
Date: 2023-08-03T10:52:57-07:00
New Revision: 673d963436666000aba89e3b5c7a85056bdba8ce
URL: https://github.com/llvm/llvm-project/commit/673d963436666000aba89e3b5c7a85056bdba8ce
DIFF: https://github.com/llvm/llvm-project/commit/673d963436666000aba89e3b5c7a85056bdba8ce.diff
LOG: [llvm][ADT] Make `Twine` aware of `StringLiteral`
The `const char *` storage backing StringLiteral has static lifetime. Making `Twine` aware of that allows us to avoid allocating heap memory in some contexts (e.g. avoid passing it to `StringSaver::save()` in a follow-up Clang patch).
Reviewed By: benlangmuir
Differential Revision: https://reviews.llvm.org/D157010
Added:
Modified:
llvm/include/llvm/ADT/Twine.h
llvm/lib/Support/Twine.cpp
llvm/unittests/ADT/TwineTest.cpp
Removed:
################################################################################
diff --git a/llvm/include/llvm/ADT/Twine.h b/llvm/include/llvm/ADT/Twine.h
index ecd9d6df60ac61..8dfbe4f72e07de 100644
--- a/llvm/include/llvm/ADT/Twine.h
+++ b/llvm/include/llvm/ADT/Twine.h
@@ -102,6 +102,10 @@ namespace llvm {
/// because they are not trivally constructible.
PtrAndLengthKind,
+ /// A pointer and length representation that's also null-terminated.
+ /// Guaranteed to be constructed from a compile-time string literal.
+ StringLiteralKind,
+
/// A pointer to a formatv_object_base instance.
FormatvObjectKind,
@@ -303,6 +307,14 @@ namespace llvm {
assert(isValid() && "Invalid twine!");
}
+ /// Construct from a StringLiteral.
+ /*implicit*/ Twine(const StringLiteral &Str)
+ : LHSKind(StringLiteralKind) {
+ LHS.ptrAndLength.ptr = Str.data();
+ LHS.ptrAndLength.length = Str.size();
+ assert(isValid() && "Invalid twine!");
+ }
+
/// Construct from a SmallString.
/*implicit*/ Twine(const SmallVectorImpl<char> &Str)
: LHSKind(PtrAndLengthKind) {
@@ -418,6 +430,11 @@ namespace llvm {
return isNullary();
}
+ /// Check if this twine is guaranteed to refer to single string literal.
+ bool isSingleStringLiteral() const {
+ return isUnary() && getLHSKind() == StringLiteralKind;
+ }
+
/// Return true if this twine can be dynamically accessed as a single
/// StringRef value with getSingleStringRef().
bool isSingleStringRef() const {
@@ -428,6 +445,7 @@ namespace llvm {
case CStringKind:
case StdStringKind:
case PtrAndLengthKind:
+ case StringLiteralKind:
return true;
default:
return false;
@@ -463,6 +481,7 @@ namespace llvm {
case StdStringKind:
return StringRef(*LHS.stdString);
case PtrAndLengthKind:
+ case StringLiteralKind:
return StringRef(LHS.ptrAndLength.ptr, LHS.ptrAndLength.length);
}
}
diff --git a/llvm/lib/Support/Twine.cpp b/llvm/lib/Support/Twine.cpp
index 8bbfd0815a402f..495b9cf2dbd680 100644
--- a/llvm/lib/Support/Twine.cpp
+++ b/llvm/lib/Support/Twine.cpp
@@ -44,6 +44,8 @@ StringRef Twine::toNullTerminatedStringRef(SmallVectorImpl<char> &Out) const {
const std::string *str = LHS.stdString;
return StringRef(str->c_str(), str->size());
}
+ case StringLiteralKind:
+ return StringRef(LHS.ptrAndLength.ptr, LHS.ptrAndLength.length);
default:
break;
}
@@ -69,6 +71,7 @@ void Twine::printOneChild(raw_ostream &OS, Child Ptr,
OS << *Ptr.stdString;
break;
case Twine::PtrAndLengthKind:
+ case Twine::StringLiteralKind:
OS << StringRef(Ptr.ptrAndLength.ptr, Ptr.ptrAndLength.length);
break;
case Twine::FormatvObjectKind:
@@ -124,6 +127,10 @@ void Twine::printOneChildRepr(raw_ostream &OS, Child Ptr,
OS << "ptrAndLength:\""
<< StringRef(Ptr.ptrAndLength.ptr, Ptr.ptrAndLength.length) << "\"";
break;
+ case Twine::StringLiteralKind:
+ OS << "constexprPtrAndLength:\""
+ << StringRef(Ptr.ptrAndLength.ptr, Ptr.ptrAndLength.length) << "\"";
+ break;
case Twine::FormatvObjectKind:
OS << "formatv:\"" << *Ptr.formatvObject << "\"";
break;
diff --git a/llvm/unittests/ADT/TwineTest.cpp b/llvm/unittests/ADT/TwineTest.cpp
index bb7127659ee924..d45805f4db7a39 100644
--- a/llvm/unittests/ADT/TwineTest.cpp
+++ b/llvm/unittests/ADT/TwineTest.cpp
@@ -30,6 +30,7 @@ TEST(TwineTest, Construction) {
EXPECT_EQ("hi", Twine(StringRef("hi")).str());
EXPECT_EQ("hi", Twine(StringRef(std::string("hi"))).str());
EXPECT_EQ("hi", Twine(StringRef("hithere", 2)).str());
+ EXPECT_EQ("hi", Twine(StringLiteral("hi")).str());
EXPECT_EQ("hi", Twine(SmallString<4>("hi")).str());
EXPECT_EQ("hi", Twine(formatv("{0}", "hi")).str());
EXPECT_EQ("hi", Twine(std::string_view("hi")).str());
@@ -96,6 +97,9 @@ TEST(TwineTest, toNullTerminatedStringRef) {
EXPECT_EQ(0, *Twine("hello").toNullTerminatedStringRef(storage).end());
EXPECT_EQ(0,
*Twine(StringRef("hello")).toNullTerminatedStringRef(storage).end());
+ EXPECT_EQ(
+ 0,
+ *Twine(StringLiteral("hello")).toNullTerminatedStringRef(storage).end());
EXPECT_EQ(0, *Twine(SmallString<11>("hello"))
.toNullTerminatedStringRef(storage)
.end());
@@ -104,6 +108,12 @@ TEST(TwineTest, toNullTerminatedStringRef) {
.end());
}
+TEST(TwineTest, isSingleStringLiteral) {
+ EXPECT_TRUE(Twine(StringLiteral("hi")).isSingleStringLiteral());
+ EXPECT_FALSE(Twine("hi").isSingleStringLiteral());
+ EXPECT_FALSE(Twine(StringRef("hi")).isSingleStringLiteral());
+}
+
TEST(TwineTest, LazyEvaluation) {
struct formatter : FormatAdapter<int> {
explicit formatter(int &Count) : FormatAdapter(0), Count(Count) {}
More information about the llvm-commits
mailing list