diff --git a/include/llvm/ADT/Twine.h b/include/llvm/ADT/Twine.h index 93ff52c83f9..851839577f3 100644 --- a/include/llvm/ADT/Twine.h +++ b/include/llvm/ADT/Twine.h @@ -86,6 +86,9 @@ namespace llvm { /// The empty string. EmptyKind, + /// A pointer to a Twine instance. + TwineKind, + /// A pointer to a C string instance. CStringKind, @@ -95,8 +98,16 @@ namespace llvm { /// A pointer to a StringRef instance. StringRefKind, - /// A pointer to a Twine instance. - TwineKind + /// A pointer to a uint64_t value, to render as an unsigned decimal + /// integer. + UDecKind, + + /// A pointer to a uint64_t value, to render as an unsigned hexadecimal + /// integer. + UHexKind, + + /// A pointer to a uint64_t value, to render as a signed decimal integer. + SDecKind }; private: @@ -232,12 +243,6 @@ namespace llvm { assert(isValid() && "Invalid twine!"); } - /// Create a 'null' string, which is an empty string that always - /// concatenates to form another empty string. - static Twine createNull() { - return Twine(NullKind); - } - // FIXME: Unfortunately, to make sure this is as efficient as possible we // need extra binary constructors from particular types. We can't rely on // the compiler to be smart enough to fold operator+()/concat() down to the @@ -255,6 +260,38 @@ namespace llvm { assert(isValid() && "Invalid twine!"); } + /// Create a 'null' string, which is an empty string that always + /// concatenates to form another empty string. + static Twine createNull() { + return Twine(NullKind); + } + + /// @} + /// @name Numeric Conversions + /// @{ + + /// Construct a twine to print \arg Val as an unsigned decimal integer. + static Twine utostr(const uint64_t &Val) { + return Twine(&Val, UDecKind, 0, EmptyKind); + } + + /// Construct a twine to print \arg Val as a signed decimal integer. + static Twine itostr(const int64_t &Val) { + return Twine(&Val, SDecKind, 0, EmptyKind); + } + + // Construct a twine to print \arg Val as an unsigned hexadecimal integer. + static Twine utohexstr(const uint64_t &Val) { + return Twine(&Val, UHexKind, 0, EmptyKind); + } + + // Construct a twine to print \arg Val as an unsigned hexadecimal + // integer. This routine is provided as a convenience to sign extend values + // before printing. + static Twine itohexstr(const int64_t &Val) { + return Twine(&Val, UHexKind, 0, EmptyKind); + } + /// @} /// @name String Operations /// @{ diff --git a/lib/Support/Twine.cpp b/lib/Support/Twine.cpp index 4c34d279e8f..c9e5f2401ec 100644 --- a/lib/Support/Twine.cpp +++ b/lib/Support/Twine.cpp @@ -19,6 +19,13 @@ std::string Twine::str() const { } void Twine::toVector(SmallVectorImpl &Out) const { + // FIXME: This is very inefficient, since we are creating a large raw_ostream + // buffer -- hitting malloc, which we were supposed to avoid -- all when we + // have this pretty little small vector available. + // + // The best way to fix this is to make raw_svector_ostream do the right thing + // and be efficient, by augmenting the base raw_ostream with the ability to + // have the buffer managed by a concrete implementation. raw_svector_ostream OS(Out); print(OS); } @@ -28,6 +35,9 @@ void Twine::printOneChild(raw_ostream &OS, const void *Ptr, switch (Kind) { case Twine::NullKind: break; case Twine::EmptyKind: break; + case Twine::TwineKind: + static_cast(Ptr)->print(OS); + break; case Twine::CStringKind: OS << static_cast(Ptr); break; @@ -37,8 +47,15 @@ void Twine::printOneChild(raw_ostream &OS, const void *Ptr, case Twine::StringRefKind: OS << *static_cast(Ptr); break; - case Twine::TwineKind: - static_cast(Ptr)->print(OS); + case Twine::UDecKind: + OS << *static_cast(Ptr); + break; + case Twine::SDecKind: + OS << *static_cast(Ptr); + break; + case Twine::UHexKind: + // FIXME: Add raw_ostream functionality for this. + OS << ::utohexstr(*static_cast(Ptr)); break; } } @@ -50,22 +67,31 @@ void Twine::printOneChildRepr(raw_ostream &OS, const void *Ptr, OS << "null"; break; case Twine::EmptyKind: OS << "empty"; break; - case Twine::CStringKind: - OS << "cstring:\"" - << static_cast(Ptr) << "\""; - break; - case Twine::StdStringKind: - OS << "std::string:\"" - << *static_cast(Ptr) << "\""; - break; - case Twine::StringRefKind: - OS << "stringref:\"" - << *static_cast(Ptr) << "\""; - break; case Twine::TwineKind: OS << "rope:"; static_cast(Ptr)->printRepr(OS); break; + case Twine::CStringKind: + OS << "cstring:\"" + << static_cast(Ptr) << "\""; + break; + case Twine::StdStringKind: + OS << "std::string:\"" + << static_cast(Ptr) << "\""; + break; + case Twine::StringRefKind: + OS << "stringref:\"" + << static_cast(Ptr) << "\""; + break; + case Twine::UDecKind: + OS << "udec:" << static_cast(Ptr) << "\""; + break; + case Twine::SDecKind: + OS << "sdec:" << static_cast(Ptr) << "\""; + break; + case Twine::UHexKind: + OS << "uhex:" << static_cast(Ptr) << "\""; + break; } } diff --git a/unittests/ADT/TwineTest.cpp b/unittests/ADT/TwineTest.cpp index 50fdd2ed314..dae5fa02a1a 100644 --- a/unittests/ADT/TwineTest.cpp +++ b/unittests/ADT/TwineTest.cpp @@ -30,6 +30,18 @@ TEST(TwineTest, Construction) { EXPECT_EQ("hi", Twine(StringRef("hithere", 2)).str()); } +TEST(TwineTest, Numbers) { + EXPECT_EQ("123", Twine::utostr(123).str()); + EXPECT_EQ("-123", Twine::itostr(-123).str()); + EXPECT_EQ("123", Twine::utostr(123).str()); + EXPECT_EQ("-123", Twine::itostr(-123).str()); + EXPECT_EQ("123", Twine::utostr((char) 123).str()); + EXPECT_EQ("-123", Twine::itostr((char) -123).str()); + + EXPECT_EQ("7B", Twine::utohexstr(123).str()); + EXPECT_EQ("FFFFFFFFFFFFFF85", Twine::itohexstr(-123).str()); +} + TEST(TwineTest, Concat) { // Check verse repr, since we care about the actual representation not just // the result.