X-Git-Url: http://demsky.eecs.uci.edu/git/?a=blobdiff_plain;f=include%2Fllvm%2FADT%2FTwine.h;h=db0bf4b68de833df3846d865ab49796fea196079;hb=697fe024f6dad16e21c9b8e41bb27463971939c0;hp=1a64d0a70110bee6581a7b99f184240bbf8cd707;hpb=2538f7ab2ef39ab1a5e48744548d66b560d1fee6;p=oota-llvm.git diff --git a/include/llvm/ADT/Twine.h b/include/llvm/ADT/Twine.h index 1a64d0a7011..db0bf4b68de 100644 --- a/include/llvm/ADT/Twine.h +++ b/include/llvm/ADT/Twine.h @@ -10,14 +10,14 @@ #ifndef LLVM_ADT_TWINE_H #define LLVM_ADT_TWINE_H +#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" +#include "llvm/Support/DataTypes.h" +#include "llvm/Support/ErrorHandling.h" #include #include namespace llvm { - template - class SmallVectorImpl; - class StringRef; class raw_ostream; /// Twine - A lightweight data structure for efficiently representing the @@ -41,8 +41,8 @@ namespace llvm { /// Twines support a special 'null' value, which always concatenates to form /// itself, and renders as an empty string. This can be returned from APIs to /// effectively nullify any concatenations performed on the result. - /// - /// \b Implementation \n + /// + /// \b Implementation /// /// Given the nature of a Twine, it is not possible for the Twine's /// concatenation method to construct interior nodes; the result must be @@ -65,7 +65,7 @@ namespace llvm { /// /// These invariants are check by \see isValid(). /// - /// \b Efficiency Considerations \n + /// \b Efficiency Considerations /// /// The Twine is designed to yield efficient and small code for common /// situations. For this reason, the concat() method is inlined so that @@ -78,7 +78,7 @@ namespace llvm { /// StringRef) codegen as desired. class Twine { /// NodeKind - Represent the type of an argument. - enum NodeKind { + enum NodeKind : unsigned char { /// An empty string; the result of concatenating anything with it is also /// empty. NullKind, @@ -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,21 +98,67 @@ namespace llvm { /// A pointer to a StringRef instance. StringRefKind, - /// A pointer to a Twine instance. - TwineKind + /// A pointer to a SmallString instance. + SmallStringKind, + + /// 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, + + /// An int value reinterpreted as a pointer, to render as a signed + /// decimal integer. + DecIKind, + + /// A pointer to an unsigned long value, to render as an unsigned decimal + /// integer. + DecULKind, + + /// A pointer to a long value, to render as a signed decimal integer. + DecLKind, + + /// A pointer to an unsigned long long value, to render as an unsigned + /// decimal integer. + DecULLKind, + + /// A pointer to a long long value, to render as a signed decimal integer. + DecLLKind, + + /// A pointer to a uint64_t value, to render as an unsigned hexadecimal + /// integer. + UHexKind + }; + + union Child + { + const Twine *twine; + const char *cString; + const std::string *stdString; + const StringRef *stringRef; + const SmallVectorImpl *smallString; + 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; /// LHSKind - The NodeKind of the left hand side, \see getLHSKind(). - NodeKind LHSKind : 8; - /// RHSKind - The NodeKind of the left hand side, \see getLHSKind(). - NodeKind RHSKind : 8; + NodeKind LHSKind; + /// RHSKind - The NodeKind of the right hand side, \see getRHSKind(). + NodeKind RHSKind; private: /// Construct a nullary twine; the kind must be NullKind or EmptyKind. @@ -119,44 +168,49 @@ namespace llvm { } /// Construct a binary twine. - explicit Twine(const Twine &_LHS, const Twine &_RHS) - : LHS(&_LHS), RHS(&_RHS), LHSKind(TwineKind), RHSKind(TwineKind) { + explicit Twine(const Twine &LHS, const Twine &RHS) + : LHSKind(TwineKind), RHSKind(TwineKind) { + this->LHS.twine = &LHS; + this->RHS.twine = &RHS; assert(isValid() && "Invalid twine!"); } /// Construct a twine from explicit values. - explicit Twine(const void *_LHS, unsigned _LHSKind, - const void *_RHS, unsigned _RHSKind) - : LHS(_LHS), RHS(_RHS), LHSKind(_LHSKind), RHSKind(_RHSKind) { + explicit Twine(Child LHS, NodeKind LHSKind, Child RHS, NodeKind RHSKind) + : LHS(LHS), RHS(RHS), LHSKind(LHSKind), RHSKind(RHSKind) { assert(isValid() && "Invalid twine!"); } - /// isNull - Check for the null twine. + /// Since the intended use of twines is as temporary objects, assignments + /// when concatenating might cause undefined behavior or stack corruptions + Twine &operator=(const Twine &Other) = delete; + + /// Check for the null twine. bool isNull() const { return getLHSKind() == NullKind; } - /// isEmpty - Check for the empty twine. + /// Check for the empty twine. bool isEmpty() const { return getLHSKind() == EmptyKind; } - /// isNullary - Check if this is a nullary twine (null or empty). + /// Check if this is a nullary twine (null or empty). bool isNullary() const { return isNull() || isEmpty(); } - /// isUnary - Check if this is a unary twine. + /// Check if this is a unary twine. bool isUnary() const { return getRHSKind() == EmptyKind && !isNullary(); } - /// isBinary - Check if this is a binary twine. + /// Check if this is a binary twine. bool isBinary() const { return getLHSKind() != NullKind && getRHSKind() != EmptyKind; } - /// isValid - Check if this is a valid twine (satisfying the invariants on + /// Check if this is a valid twine (satisfying the invariants on /// order and number of arguments). bool isValid() const { // Nullary twines always have Empty on the RHS. @@ -173,26 +227,26 @@ namespace llvm { // A twine child should always be binary. if (getLHSKind() == TwineKind && - !static_cast(LHS)->isBinary()) + !LHS.twine->isBinary()) return false; if (getRHSKind() == TwineKind && - !static_cast(RHS)->isBinary()) + !RHS.twine->isBinary()) return false; return true; } - /// getLHSKind - Get the NodeKind of the left-hand side. + /// Get the NodeKind of the left-hand side. NodeKind getLHSKind() const { return LHSKind; } - /// getRHSKind - Get the NodeKind of the left-hand side. + /// Get the NodeKind of the right-hand side. NodeKind getRHSKind() const { return RHSKind; } - /// printOneChild - Print one child from a twine. - void printOneChild(raw_ostream &OS, const void *Ptr, NodeKind Kind) const; + /// Print one child from a twine. + 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, + /// Print the representation of one child from a twine. + void printOneChildRepr(raw_ostream &OS, Child Ptr, NodeKind Kind) const; public: @@ -204,6 +258,8 @@ namespace llvm { assert(isValid() && "Invalid twine!"); } + Twine(const Twine &) = default; + /// Construct from a C string. /// /// We take care here to optimize "" into the empty twine -- this will be @@ -212,7 +268,7 @@ namespace llvm { /*implicit*/ Twine(const char *Str) : RHSKind(EmptyKind) { if (Str[0] != '\0') { - LHS = Str; + LHS.cString = Str; LHSKind = CStringKind; } else LHSKind = EmptyKind; @@ -222,20 +278,77 @@ 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!"); } - /// Create a 'null' string, which is an empty string that always - /// concatenates to form another empty string. - static Twine createNull() { - return Twine(NullKind); + /// Construct from a SmallString. + /*implicit*/ Twine(const SmallVectorImpl &Str) + : LHSKind(SmallStringKind), RHSKind(EmptyKind) { + LHS.smallString = &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(Val); + } + + /// Construct from an unsigned char. + explicit Twine(unsigned char Val) + : LHSKind(CharKind), RHSKind(EmptyKind) { + LHS.character = static_cast(Val); + } + + /// Construct a twine to print \p Val as an unsigned decimal integer. + explicit Twine(unsigned Val) + : LHSKind(DecUIKind), RHSKind(EmptyKind) { + LHS.decUI = Val; + } + + /// Construct a twine to print \p Val as a signed decimal integer. + explicit Twine(int Val) + : LHSKind(DecIKind), RHSKind(EmptyKind) { + LHS.decI = Val; + } + + /// Construct a twine to print \p Val as an unsigned decimal integer. + explicit Twine(const unsigned long &Val) + : LHSKind(DecULKind), RHSKind(EmptyKind) { + LHS.decUL = &Val; + } + + /// Construct a twine to print \p Val as a signed decimal integer. + explicit Twine(const long &Val) + : LHSKind(DecLKind), RHSKind(EmptyKind) { + LHS.decL = &Val; + } + + /// Construct a twine to print \p Val as an unsigned decimal integer. + explicit Twine(const unsigned long long &Val) + : LHSKind(DecULLKind), RHSKind(EmptyKind) { + LHS.decULL = &Val; + } + + /// Construct a twine to print \p Val as a signed decimal integer. + explicit Twine(const long long &Val) + : LHSKind(DecLLKind), RHSKind(EmptyKind) { + LHS.decLL = &Val; } // FIXME: Unfortunately, to make sure this is as efficient as possible we @@ -244,17 +357,66 @@ namespace llvm { // right thing. Yet. /// 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) { + /*implicit*/ Twine(const char *LHS, const StringRef &RHS) + : LHSKind(CStringKind), RHSKind(StringRefKind) { + this->LHS.cString = LHS; + this->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) { + /*implicit*/ Twine(const StringRef &LHS, const char *RHS) + : LHSKind(StringRefKind), RHSKind(CStringKind) { + this->LHS.stringRef = &LHS; + this->RHS.cString = RHS; 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 \p Val as an unsigned hexadecimal integer. + static Twine utohexstr(const uint64_t &Val) { + Child LHS, RHS; + LHS.uHex = &Val; + RHS.twine = nullptr; + return Twine(LHS, UHexKind, RHS, EmptyKind); + } + + /// @} + /// @name Predicate Operations + /// @{ + + /// Check if this twine is trivially empty; a false return value does not + /// necessarily mean the twine is empty. + bool isTriviallyEmpty() const { + return isNullary(); + } + + /// Return true if this twine can be dynamically accessed as a single + /// StringRef value with getSingleStringRef(). + bool isSingleStringRef() const { + if (getRHSKind() != EmptyKind) return false; + + switch (getLHSKind()) { + case EmptyKind: + case CStringKind: + case StdStringKind: + case StringRefKind: + case SmallStringKind: + return true; + default: + return false; + } + } + /// @} /// @name String Operations /// @{ @@ -265,24 +427,55 @@ namespace llvm { /// @name Output & Conversion. /// @{ - /// str - Return the twine contents as a std::string. + /// Return the twine contents as a std::string. std::string str() const; - /// toVector - Write the concatenated string into the given SmallString or - /// SmallVector. + /// Append the concatenated string into the given SmallString or SmallVector. void toVector(SmallVectorImpl &Out) const; - /// print - Write the concatenated string represented by this twine to the - /// stream \arg OS. + /// This returns the twine as a single StringRef. This method is only valid + /// if isSingleStringRef() is true. + StringRef getSingleStringRef() const { + assert(isSingleStringRef() &&"This cannot be had as a single stringref!"); + switch (getLHSKind()) { + default: llvm_unreachable("Out of sync with isSingleStringRef"); + case EmptyKind: return StringRef(); + case CStringKind: return StringRef(LHS.cString); + case StdStringKind: return StringRef(*LHS.stdString); + case StringRefKind: return *LHS.stringRef; + case SmallStringKind: + return StringRef(LHS.smallString->data(), LHS.smallString->size()); + } + } + + /// This returns the twine as a single StringRef if it can be + /// represented as such. Otherwise the twine is written into the given + /// SmallVector and a StringRef to the SmallVector's data is returned. + StringRef toStringRef(SmallVectorImpl &Out) const { + if (isSingleStringRef()) + return getSingleStringRef(); + toVector(Out); + return StringRef(Out.data(), Out.size()); + } + + /// This returns the twine as a single null terminated StringRef if it + /// can be represented as such. Otherwise the twine is written into the + /// given SmallVector and a StringRef to the SmallVector's data is returned. + /// + /// The returned StringRef's size does not include the null terminator. + StringRef toNullTerminatedStringRef(SmallVectorImpl &Out) const; + + /// Write the concatenated string represented by this twine to the + /// stream \p OS. void print(raw_ostream &OS) const; - /// dump - Dump the concatenated string represented by this twine to stderr. + /// Dump the concatenated string represented by this twine to stderr. void dump() const; - /// print - Write the representation of this twine to the stream \arg OS. + /// Write the representation of this twine to the stream \p OS. void printRepr(raw_ostream &OS) const; - /// dumpRepr - Dump the representation of this twine to stderr. + /// Dump the representation of this twine to stderr. void dumpRepr() const; /// @} @@ -304,7 +497,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;