Skip to content

Commit 673d963

Browse files
committed
[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
1 parent e1ceae4 commit 673d963

File tree

3 files changed

+36
-0
lines changed

3 files changed

+36
-0
lines changed

llvm/include/llvm/ADT/Twine.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,10 @@ namespace llvm {
102102
/// because they are not trivally constructible.
103103
PtrAndLengthKind,
104104

105+
/// A pointer and length representation that's also null-terminated.
106+
/// Guaranteed to be constructed from a compile-time string literal.
107+
StringLiteralKind,
108+
105109
/// A pointer to a formatv_object_base instance.
106110
FormatvObjectKind,
107111

@@ -303,6 +307,14 @@ namespace llvm {
303307
assert(isValid() && "Invalid twine!");
304308
}
305309

310+
/// Construct from a StringLiteral.
311+
/*implicit*/ Twine(const StringLiteral &Str)
312+
: LHSKind(StringLiteralKind) {
313+
LHS.ptrAndLength.ptr = Str.data();
314+
LHS.ptrAndLength.length = Str.size();
315+
assert(isValid() && "Invalid twine!");
316+
}
317+
306318
/// Construct from a SmallString.
307319
/*implicit*/ Twine(const SmallVectorImpl<char> &Str)
308320
: LHSKind(PtrAndLengthKind) {
@@ -418,6 +430,11 @@ namespace llvm {
418430
return isNullary();
419431
}
420432

433+
/// Check if this twine is guaranteed to refer to single string literal.
434+
bool isSingleStringLiteral() const {
435+
return isUnary() && getLHSKind() == StringLiteralKind;
436+
}
437+
421438
/// Return true if this twine can be dynamically accessed as a single
422439
/// StringRef value with getSingleStringRef().
423440
bool isSingleStringRef() const {
@@ -428,6 +445,7 @@ namespace llvm {
428445
case CStringKind:
429446
case StdStringKind:
430447
case PtrAndLengthKind:
448+
case StringLiteralKind:
431449
return true;
432450
default:
433451
return false;
@@ -463,6 +481,7 @@ namespace llvm {
463481
case StdStringKind:
464482
return StringRef(*LHS.stdString);
465483
case PtrAndLengthKind:
484+
case StringLiteralKind:
466485
return StringRef(LHS.ptrAndLength.ptr, LHS.ptrAndLength.length);
467486
}
468487
}

llvm/lib/Support/Twine.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ StringRef Twine::toNullTerminatedStringRef(SmallVectorImpl<char> &Out) const {
4444
const std::string *str = LHS.stdString;
4545
return StringRef(str->c_str(), str->size());
4646
}
47+
case StringLiteralKind:
48+
return StringRef(LHS.ptrAndLength.ptr, LHS.ptrAndLength.length);
4749
default:
4850
break;
4951
}
@@ -69,6 +71,7 @@ void Twine::printOneChild(raw_ostream &OS, Child Ptr,
6971
OS << *Ptr.stdString;
7072
break;
7173
case Twine::PtrAndLengthKind:
74+
case Twine::StringLiteralKind:
7275
OS << StringRef(Ptr.ptrAndLength.ptr, Ptr.ptrAndLength.length);
7376
break;
7477
case Twine::FormatvObjectKind:
@@ -124,6 +127,10 @@ void Twine::printOneChildRepr(raw_ostream &OS, Child Ptr,
124127
OS << "ptrAndLength:\""
125128
<< StringRef(Ptr.ptrAndLength.ptr, Ptr.ptrAndLength.length) << "\"";
126129
break;
130+
case Twine::StringLiteralKind:
131+
OS << "constexprPtrAndLength:\""
132+
<< StringRef(Ptr.ptrAndLength.ptr, Ptr.ptrAndLength.length) << "\"";
133+
break;
127134
case Twine::FormatvObjectKind:
128135
OS << "formatv:\"" << *Ptr.formatvObject << "\"";
129136
break;

llvm/unittests/ADT/TwineTest.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ TEST(TwineTest, Construction) {
3030
EXPECT_EQ("hi", Twine(StringRef("hi")).str());
3131
EXPECT_EQ("hi", Twine(StringRef(std::string("hi"))).str());
3232
EXPECT_EQ("hi", Twine(StringRef("hithere", 2)).str());
33+
EXPECT_EQ("hi", Twine(StringLiteral("hi")).str());
3334
EXPECT_EQ("hi", Twine(SmallString<4>("hi")).str());
3435
EXPECT_EQ("hi", Twine(formatv("{0}", "hi")).str());
3536
EXPECT_EQ("hi", Twine(std::string_view("hi")).str());
@@ -96,6 +97,9 @@ TEST(TwineTest, toNullTerminatedStringRef) {
9697
EXPECT_EQ(0, *Twine("hello").toNullTerminatedStringRef(storage).end());
9798
EXPECT_EQ(0,
9899
*Twine(StringRef("hello")).toNullTerminatedStringRef(storage).end());
100+
EXPECT_EQ(
101+
0,
102+
*Twine(StringLiteral("hello")).toNullTerminatedStringRef(storage).end());
99103
EXPECT_EQ(0, *Twine(SmallString<11>("hello"))
100104
.toNullTerminatedStringRef(storage)
101105
.end());
@@ -104,6 +108,12 @@ TEST(TwineTest, toNullTerminatedStringRef) {
104108
.end());
105109
}
106110

111+
TEST(TwineTest, isSingleStringLiteral) {
112+
EXPECT_TRUE(Twine(StringLiteral("hi")).isSingleStringLiteral());
113+
EXPECT_FALSE(Twine("hi").isSingleStringLiteral());
114+
EXPECT_FALSE(Twine(StringRef("hi")).isSingleStringLiteral());
115+
}
116+
107117
TEST(TwineTest, LazyEvaluation) {
108118
struct formatter : FormatAdapter<int> {
109119
explicit formatter(int &Count) : FormatAdapter(0), Count(Count) {}

0 commit comments

Comments
 (0)