Add Twine support for characters, and switch twine to use a union internally

to eliminate some casting.


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@135888 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Chris Lattner 2011-07-24 20:44:30 +00:00
parent 81d686edbe
commit 3f25ee080c
3 changed files with 122 additions and 54 deletions

View File

@ -99,6 +99,9 @@ namespace llvm {
/// A pointer to a StringRef instance.
StringRefKind,
/// A char value reinterpreted as a pointer, to render as a character.
CharKind,
/// An unsigned int value reinterpreted as a pointer, to render as an
/// unsigned decimal integer.
DecUIKind,
@ -126,13 +129,31 @@ namespace llvm {
UHexKind
};
union Child
{
const Twine *twine;
const char *cString;
const std::string *stdString;
const StringRef *stringRef;
char character;
unsigned int decUI;
int decI;
const unsigned long *decUL;
const long *decL;
const unsigned long long *decULL;
const long long *decLL;
const uint64_t *uHex;
};
private:
/// LHS - The prefix in the concatenation, which may be uninitialized for
/// Null or Empty kinds.
const void *LHS;
Child LHS;
/// RHS - The suffix in the concatenation, which may be uninitialized for
/// Null or Empty kinds.
const void *RHS;
Child RHS;
// enums stored as unsigned chars to save on space while some compilers
// don't support specifying the backing type for an enum
/// LHSKind - The NodeKind of the left hand side, \see getLHSKind().
unsigned char LHSKind;
/// RHSKind - The NodeKind of the left hand side, \see getLHSKind().
@ -147,13 +168,15 @@ namespace llvm {
/// Construct a binary twine.
explicit Twine(const Twine &_LHS, const Twine &_RHS)
: LHS(&_LHS), RHS(&_RHS), LHSKind(TwineKind), RHSKind(TwineKind) {
: LHSKind(TwineKind), RHSKind(TwineKind) {
LHS.twine = &_LHS;
RHS.twine = &_RHS;
assert(isValid() && "Invalid twine!");
}
/// Construct a twine from explicit values.
explicit Twine(const void *_LHS, NodeKind _LHSKind,
const void *_RHS, NodeKind _RHSKind)
explicit Twine(Child _LHS, NodeKind _LHSKind,
Child _RHS, NodeKind _RHSKind)
: LHS(_LHS), RHS(_RHS), LHSKind(_LHSKind), RHSKind(_RHSKind) {
assert(isValid() && "Invalid twine!");
}
@ -200,10 +223,10 @@ namespace llvm {
// A twine child should always be binary.
if (getLHSKind() == TwineKind &&
!static_cast<const Twine*>(LHS)->isBinary())
!LHS.twine->isBinary())
return false;
if (getRHSKind() == TwineKind &&
!static_cast<const Twine*>(RHS)->isBinary())
!RHS.twine->isBinary())
return false;
return true;
@ -216,10 +239,10 @@ namespace llvm {
NodeKind getRHSKind() const { return (NodeKind) RHSKind; }
/// printOneChild - Print one child from a twine.
void printOneChild(raw_ostream &OS, const void *Ptr, NodeKind Kind) const;
void printOneChild(raw_ostream &OS, Child Ptr, NodeKind Kind) const;
/// printOneChildRepr - Print the representation of one child from a twine.
void printOneChildRepr(raw_ostream &OS, const void *Ptr,
void printOneChildRepr(raw_ostream &OS, Child Ptr,
NodeKind Kind) const;
public:
@ -239,7 +262,7 @@ namespace llvm {
/*implicit*/ Twine(const char *Str)
: RHSKind(EmptyKind) {
if (Str[0] != '\0') {
LHS = Str;
LHS.cString = Str;
LHSKind = CStringKind;
} else
LHSKind = EmptyKind;
@ -249,44 +272,70 @@ namespace llvm {
/// Construct from an std::string.
/*implicit*/ Twine(const std::string &Str)
: LHS(&Str), LHSKind(StdStringKind), RHSKind(EmptyKind) {
: LHSKind(StdStringKind), RHSKind(EmptyKind) {
LHS.stdString = &Str;
assert(isValid() && "Invalid twine!");
}
/// Construct from a StringRef.
/*implicit*/ Twine(const StringRef &Str)
: LHS(&Str), LHSKind(StringRefKind), RHSKind(EmptyKind) {
: LHSKind(StringRefKind), RHSKind(EmptyKind) {
LHS.stringRef = &Str;
assert(isValid() && "Invalid twine!");
}
/// Construct from a char.
explicit Twine(char Val)
: LHSKind(CharKind), RHSKind(EmptyKind) {
LHS.character = Val;
}
/// Construct from a signed char.
explicit Twine(signed char Val)
: LHSKind(CharKind), RHSKind(EmptyKind) {
LHS.character = static_cast<char>(Val);
}
/// Construct from an unsigned char.
explicit Twine(unsigned char Val)
: LHSKind(CharKind), RHSKind(EmptyKind) {
LHS.character = static_cast<char>(Val);
}
/// Construct a twine to print \arg Val as an unsigned decimal integer.
explicit Twine(unsigned Val)
: LHS((void*)(intptr_t)Val), LHSKind(DecUIKind), RHSKind(EmptyKind) {
: LHSKind(DecUIKind), RHSKind(EmptyKind) {
LHS.decUI = Val;
}
/// Construct a twine to print \arg Val as a signed decimal integer.
explicit Twine(int Val)
: LHS((void*)(intptr_t)Val), LHSKind(DecIKind), RHSKind(EmptyKind) {
: LHSKind(DecIKind), RHSKind(EmptyKind) {
LHS.decI = Val;
}
/// Construct a twine to print \arg Val as an unsigned decimal integer.
explicit Twine(const unsigned long &Val)
: LHS(&Val), LHSKind(DecULKind), RHSKind(EmptyKind) {
: LHSKind(DecULKind), RHSKind(EmptyKind) {
LHS.decUL = &Val;
}
/// Construct a twine to print \arg Val as a signed decimal integer.
explicit Twine(const long &Val)
: LHS(&Val), LHSKind(DecLKind), RHSKind(EmptyKind) {
: LHSKind(DecLKind), RHSKind(EmptyKind) {
LHS.decL = &Val;
}
/// Construct a twine to print \arg Val as an unsigned decimal integer.
explicit Twine(const unsigned long long &Val)
: LHS(&Val), LHSKind(DecULLKind), RHSKind(EmptyKind) {
: LHSKind(DecULLKind), RHSKind(EmptyKind) {
LHS.decULL = &Val;
}
/// Construct a twine to print \arg Val as a signed decimal integer.
explicit Twine(const long long &Val)
: LHS(&Val), LHSKind(DecLLKind), RHSKind(EmptyKind) {
: LHSKind(DecLLKind), RHSKind(EmptyKind) {
LHS.decLL = &Val;
}
// FIXME: Unfortunately, to make sure this is as efficient as possible we
@ -296,13 +345,17 @@ namespace llvm {
/// Construct as the concatenation of a C string and a StringRef.
/*implicit*/ Twine(const char *_LHS, const StringRef &_RHS)
: LHS(_LHS), RHS(&_RHS), LHSKind(CStringKind), RHSKind(StringRefKind) {
: LHSKind(CStringKind), RHSKind(StringRefKind) {
LHS.cString = _LHS;
RHS.stringRef = &_RHS;
assert(isValid() && "Invalid twine!");
}
/// Construct as the concatenation of a StringRef and a C string.
/*implicit*/ Twine(const StringRef &_LHS, const char *_RHS)
: LHS(&_LHS), RHS(_RHS), LHSKind(StringRefKind), RHSKind(CStringKind) {
: LHSKind(StringRefKind), RHSKind(CStringKind) {
LHS.stringRef = &_LHS;
RHS.cString = _RHS;
assert(isValid() && "Invalid twine!");
}
@ -318,7 +371,10 @@ namespace llvm {
// 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);
Child LHS, RHS;
LHS.uHex = &Val;
RHS.twine = 0;
return Twine(LHS, UHexKind, RHS, EmptyKind);
}
/// @}
@ -371,9 +427,9 @@ namespace llvm {
switch (getLHSKind()) {
default: assert(0 && "Out of sync with isSingleStringRef");
case EmptyKind: return StringRef();
case CStringKind: return StringRef((const char*)LHS);
case StdStringKind: return StringRef(*(const std::string*)LHS);
case StringRefKind: return *(const StringRef*)LHS;
case CStringKind: return StringRef(LHS.cString);
case StdStringKind: return StringRef(*LHS.stdString);
case StringRefKind: return *LHS.stringRef;
}
}
@ -422,7 +478,9 @@ namespace llvm {
// Otherwise we need to create a new node, taking care to fold in unary
// twines.
const void *NewLHS = this, *NewRHS = &Suffix;
Child NewLHS, NewRHS;
NewLHS.twine = this;
NewRHS.twine = &Suffix;
NodeKind NewLHSKind = TwineKind, NewRHSKind = TwineKind;
if (isUnary()) {
NewLHS = LHS;

View File

@ -16,7 +16,7 @@ using namespace llvm;
std::string Twine::str() const {
// If we're storing only a std::string, just return it.
if (LHSKind == StdStringKind && RHSKind == EmptyKind)
return *static_cast<const std::string*>(LHS);
return *LHS.stdString;
// Otherwise, flatten and copy the contents first.
SmallString<256> Vec;
@ -40,9 +40,9 @@ StringRef Twine::toNullTerminatedStringRef(SmallVectorImpl<char> &Out) const {
switch (getLHSKind()) {
case CStringKind:
// Already null terminated, yay!
return StringRef(static_cast<const char*>(LHS));
return StringRef(LHS.cString);
case StdStringKind: {
const std::string *str = static_cast<const std::string*>(LHS);
const std::string *str = LHS.stdString;
return StringRef(str->c_str(), str->size());
}
default:
@ -55,48 +55,51 @@ StringRef Twine::toNullTerminatedStringRef(SmallVectorImpl<char> &Out) const {
return StringRef(Out.data(), Out.size());
}
void Twine::printOneChild(raw_ostream &OS, const void *Ptr,
void Twine::printOneChild(raw_ostream &OS, Child Ptr,
NodeKind Kind) const {
switch (Kind) {
case Twine::NullKind: break;
case Twine::EmptyKind: break;
case Twine::TwineKind:
static_cast<const Twine*>(Ptr)->print(OS);
Ptr.twine->print(OS);
break;
case Twine::CStringKind:
OS << static_cast<const char*>(Ptr);
OS << Ptr.cString;
break;
case Twine::StdStringKind:
OS << *static_cast<const std::string*>(Ptr);
OS << *Ptr.stdString;
break;
case Twine::StringRefKind:
OS << *static_cast<const StringRef*>(Ptr);
OS << *Ptr.stringRef;
break;
case Twine::CharKind:
OS << Ptr.character;
break;
case Twine::DecUIKind:
OS << (unsigned)(uintptr_t)Ptr;
OS << Ptr.decUI;
break;
case Twine::DecIKind:
OS << (int)(intptr_t)Ptr;
OS << Ptr.decI;
break;
case Twine::DecULKind:
OS << *static_cast<const unsigned long*>(Ptr);
OS << *Ptr.decUL;
break;
case Twine::DecLKind:
OS << *static_cast<const long*>(Ptr);
OS << *Ptr.decL;
break;
case Twine::DecULLKind:
OS << *static_cast<const unsigned long long*>(Ptr);
OS << *Ptr.decULL;
break;
case Twine::DecLLKind:
OS << *static_cast<const long long*>(Ptr);
OS << *Ptr.decLL;
break;
case Twine::UHexKind:
OS.write_hex(*static_cast<const uint64_t*>(Ptr));
OS.write_hex(*Ptr.uHex);
break;
}
}
void Twine::printOneChildRepr(raw_ostream &OS, const void *Ptr,
void Twine::printOneChildRepr(raw_ostream &OS, Child Ptr,
NodeKind Kind) const {
switch (Kind) {
case Twine::NullKind:
@ -105,40 +108,43 @@ void Twine::printOneChildRepr(raw_ostream &OS, const void *Ptr,
OS << "empty"; break;
case Twine::TwineKind:
OS << "rope:";
static_cast<const Twine*>(Ptr)->printRepr(OS);
Ptr.twine->printRepr(OS);
break;
case Twine::CStringKind:
OS << "cstring:\""
<< static_cast<const char*>(Ptr) << "\"";
<< Ptr.cString << "\"";
break;
case Twine::StdStringKind:
OS << "std::string:\""
<< static_cast<const std::string*>(Ptr) << "\"";
<< Ptr.stdString << "\"";
break;
case Twine::StringRefKind:
OS << "stringref:\""
<< static_cast<const StringRef*>(Ptr) << "\"";
<< Ptr.stringRef << "\"";
break;
case Twine::CharKind:
OS << "char:\"" << Ptr.character << "\"";
break;
case Twine::DecUIKind:
OS << "decUI:\"" << (unsigned)(uintptr_t)Ptr << "\"";
OS << "decUI:\"" << Ptr.decUI << "\"";
break;
case Twine::DecIKind:
OS << "decI:\"" << (int)(intptr_t)Ptr << "\"";
OS << "decI:\"" << Ptr.decI << "\"";
break;
case Twine::DecULKind:
OS << "decUL:\"" << *static_cast<const unsigned long*>(Ptr) << "\"";
OS << "decUL:\"" << *Ptr.decUL << "\"";
break;
case Twine::DecLKind:
OS << "decL:\"" << *static_cast<const long*>(Ptr) << "\"";
OS << "decL:\"" << *Ptr.decL << "\"";
break;
case Twine::DecULLKind:
OS << "decULL:\"" << *static_cast<const unsigned long long*>(Ptr) << "\"";
OS << "decULL:\"" << *Ptr.decULL << "\"";
break;
case Twine::DecLLKind:
OS << "decLL:\"" << *static_cast<const long long*>(Ptr) << "\"";
OS << "decLL:\"" << *Ptr.decLL << "\"";
break;
case Twine::UHexKind:
OS << "uhex:\"" << static_cast<const uint64_t*>(Ptr) << "\"";
OS << "uhex:\"" << Ptr.uHex << "\"";
break;
}
}

View File

@ -37,12 +37,16 @@ TEST(TwineTest, Numbers) {
EXPECT_EQ("-123", Twine(-123).str());
EXPECT_EQ("123", Twine(123).str());
EXPECT_EQ("-123", Twine(-123).str());
EXPECT_EQ("123", Twine((char) 123).str());
EXPECT_EQ("-123", Twine((signed char) -123).str());
EXPECT_EQ("7b", Twine::utohexstr(123).str());
}
TEST(TwineTest, Characters) {
EXPECT_EQ("x", Twine('x').str());
EXPECT_EQ("x", Twine(static_cast<unsigned char>('x')).str());
EXPECT_EQ("x", Twine(static_cast<signed char>('x')).str());
}
TEST(TwineTest, Concat) {
// Check verse repr, since we care about the actual representation not just
// the result.