diff --git a/llvm/include/llvm/ADT/Twine.h b/llvm/include/llvm/ADT/Twine.h index 4501f928834e2..4ed4898df5459 100644 --- a/llvm/include/llvm/ADT/Twine.h +++ b/llvm/include/llvm/ADT/Twine.h @@ -20,566 +20,540 @@ namespace llvm { - class formatv_object_base; - class raw_ostream; +class formatv_object_base; +class raw_ostream; + +/// Twine - A lightweight data structure for efficiently representing the +/// concatenation of temporary values as strings. +/// +/// A Twine is a kind of rope, it represents a concatenated string using a +/// binary-tree, where the string is the preorder of the nodes. Since the +/// Twine can be efficiently rendered into a buffer when its result is used, +/// it avoids the cost of generating temporary values for intermediate string +/// results -- particularly in cases when the Twine result is never +/// required. By explicitly tracking the type of leaf nodes, we can also avoid +/// the creation of temporary strings for conversions operations (such as +/// appending an integer to a string). +/// +/// A Twine is not intended for use directly and should not be stored, its +/// implementation relies on the ability to store pointers to temporary stack +/// objects which may be deallocated at the end of a statement. Twines should +/// only be used as const references in arguments, when an API wishes +/// to accept possibly-concatenated strings. +/// +/// 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 +/// +/// Given the nature of a Twine, it is not possible for the Twine's +/// concatenation method to construct interior nodes; the result must be +/// represented inside the returned value. For this reason a Twine object +/// actually holds two values, the left- and right-hand sides of a +/// concatenation. We also have nullary Twine objects, which are effectively +/// sentinel values that represent empty strings. +/// +/// Thus, a Twine can effectively have zero, one, or two children. The \see +/// isNullary(), \see isUnary(), and \see isBinary() predicates exist for +/// testing the number of children. +/// +/// We maintain a number of invariants on Twine objects (FIXME: Why): +/// - Nullary twines are always represented with their Kind on the left-hand +/// side, and the Empty kind on the right-hand side. +/// - Unary twines are always represented with the value on the left-hand +/// side, and the Empty kind on the right-hand side. +/// - If a Twine has another Twine as a child, that child should always be +/// binary (otherwise it could have been folded into the parent). +/// +/// These invariants are check by \see isValid(). +/// +/// \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 +/// concatenations of leaf nodes can be optimized into stores directly into a +/// single stack allocated object. +/// +/// In practice, not all compilers can be trusted to optimize concat() fully, +/// so we provide two additional methods (and accompanying operator+ +/// overloads) to guarantee that particularly important cases (cstring plus +/// StringRef) codegen as desired. +class Twine { + /// NodeKind - Represent the type of an argument. + enum NodeKind : unsigned char { + /// An empty string; the result of concatenating anything with it is also + /// empty. + NullKind, + + /// The empty string. + EmptyKind, + + /// A pointer to a Twine instance. + TwineKind, + + /// A pointer to a C string instance. + CStringKind, + + /// A pointer to an std::string instance. + StdStringKind, + + /// A Pointer and Length representation. Used for std::string_view, + /// StringRef, and SmallString. Can't use a StringRef here + /// 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, + + /// A char value, to render as a character. + CharKind, + + /// An unsigned int value, to render as an unsigned decimal integer. + DecUIKind, + + /// An int value, 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 + }; - /// Twine - A lightweight data structure for efficiently representing the - /// concatenation of temporary values as strings. - /// - /// A Twine is a kind of rope, it represents a concatenated string using a - /// binary-tree, where the string is the preorder of the nodes. Since the - /// Twine can be efficiently rendered into a buffer when its result is used, - /// it avoids the cost of generating temporary values for intermediate string - /// results -- particularly in cases when the Twine result is never - /// required. By explicitly tracking the type of leaf nodes, we can also avoid - /// the creation of temporary strings for conversions operations (such as - /// appending an integer to a string). - /// - /// A Twine is not intended for use directly and should not be stored, its - /// implementation relies on the ability to store pointers to temporary stack - /// objects which may be deallocated at the end of a statement. Twines should - /// only be used as const references in arguments, when an API wishes - /// to accept possibly-concatenated strings. - /// - /// 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 - /// - /// Given the nature of a Twine, it is not possible for the Twine's - /// concatenation method to construct interior nodes; the result must be - /// represented inside the returned value. For this reason a Twine object - /// actually holds two values, the left- and right-hand sides of a - /// concatenation. We also have nullary Twine objects, which are effectively - /// sentinel values that represent empty strings. - /// - /// Thus, a Twine can effectively have zero, one, or two children. The \see - /// isNullary(), \see isUnary(), and \see isBinary() predicates exist for - /// testing the number of children. - /// - /// We maintain a number of invariants on Twine objects (FIXME: Why): - /// - Nullary twines are always represented with their Kind on the left-hand - /// side, and the Empty kind on the right-hand side. - /// - Unary twines are always represented with the value on the left-hand - /// side, and the Empty kind on the right-hand side. - /// - If a Twine has another Twine as a child, that child should always be - /// binary (otherwise it could have been folded into the parent). - /// - /// These invariants are check by \see isValid(). - /// - /// \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 - /// concatenations of leaf nodes can be optimized into stores directly into a - /// single stack allocated object. - /// - /// In practice, not all compilers can be trusted to optimize concat() fully, - /// so we provide two additional methods (and accompanying operator+ - /// overloads) to guarantee that particularly important cases (cstring plus - /// StringRef) codegen as desired. - class Twine { - /// NodeKind - Represent the type of an argument. - enum NodeKind : unsigned char { - /// An empty string; the result of concatenating anything with it is also - /// empty. - NullKind, - - /// The empty string. - EmptyKind, - - /// A pointer to a Twine instance. - TwineKind, - - /// A pointer to a C string instance. - CStringKind, - - /// A pointer to an std::string instance. - StdStringKind, - - /// A Pointer and Length representation. Used for std::string_view, - /// StringRef, and SmallString. Can't use a StringRef here - /// 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, - - /// A char value, to render as a character. - CharKind, - - /// An unsigned int value, to render as an unsigned decimal integer. - DecUIKind, - - /// An int value, 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; - struct { - const char *ptr; - size_t length; - } ptrAndLength; - const formatv_object_base *formatvObject; - 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; - }; - - /// LHS - The prefix in the concatenation, which may be uninitialized for - /// Null or Empty kinds. - Child LHS; - - /// RHS - The suffix in the concatenation, which may be uninitialized for - /// Null or Empty kinds. - Child RHS; - - /// LHSKind - The NodeKind of the left hand side, \see getLHSKind(). - NodeKind LHSKind = EmptyKind; - - /// RHSKind - The NodeKind of the right hand side, \see getRHSKind(). - NodeKind RHSKind = EmptyKind; - - /// Construct a nullary twine; the kind must be NullKind or EmptyKind. - explicit Twine(NodeKind Kind) : LHSKind(Kind) { - assert(isNullary() && "Invalid kind!"); - } + union Child { + const Twine *twine; + const char *cString; + const std::string *stdString; + struct { + const char *ptr; + size_t length; + } ptrAndLength; + const formatv_object_base *formatvObject; + 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; + }; - /// Construct a binary twine. - explicit Twine(const Twine &LHS, const Twine &RHS) - : LHSKind(TwineKind), RHSKind(TwineKind) { - this->LHS.twine = &LHS; - this->RHS.twine = &RHS; - assert(isValid() && "Invalid twine!"); - } + /// LHS - The prefix in the concatenation, which may be uninitialized for + /// Null or Empty kinds. + Child LHS; - /// Construct a twine from explicit values. - explicit Twine(Child LHS, NodeKind LHSKind, Child RHS, NodeKind RHSKind) - : LHS(LHS), RHS(RHS), LHSKind(LHSKind), RHSKind(RHSKind) { - assert(isValid() && "Invalid twine!"); - } + /// RHS - The suffix in the concatenation, which may be uninitialized for + /// Null or Empty kinds. + Child RHS; - /// Check for the null twine. - bool isNull() const { - return getLHSKind() == NullKind; - } + /// LHSKind - The NodeKind of the left hand side, \see getLHSKind(). + NodeKind LHSKind = EmptyKind; - /// Check for the empty twine. - bool isEmpty() const { - return getLHSKind() == EmptyKind; - } + /// RHSKind - The NodeKind of the right hand side, \see getRHSKind(). + NodeKind RHSKind = EmptyKind; - /// Check if this is a nullary twine (null or empty). - bool isNullary() const { - return isNull() || isEmpty(); - } + /// Construct a nullary twine; the kind must be NullKind or EmptyKind. + explicit Twine(NodeKind Kind) : LHSKind(Kind) { + assert(isNullary() && "Invalid kind!"); + } - /// Check if this is a unary twine. - bool isUnary() const { - return getRHSKind() == EmptyKind && !isNullary(); - } + /// Construct a binary twine. + explicit Twine(const Twine &LHS, const Twine &RHS) + : LHSKind(TwineKind), RHSKind(TwineKind) { + this->LHS.twine = &LHS; + this->RHS.twine = &RHS; + assert(isValid() && "Invalid twine!"); + } - /// Check if this is a binary twine. - bool isBinary() const { - return getLHSKind() != NullKind && getRHSKind() != EmptyKind; - } + /// Construct a twine from explicit values. + explicit Twine(Child LHS, NodeKind LHSKind, Child RHS, NodeKind RHSKind) + : LHS(LHS), RHS(RHS), LHSKind(LHSKind), RHSKind(RHSKind) { + assert(isValid() && "Invalid twine!"); + } - /// 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. - if (isNullary() && getRHSKind() != EmptyKind) - return false; - - // Null should never appear on the RHS. - if (getRHSKind() == NullKind) - return false; - - // The RHS cannot be non-empty if the LHS is empty. - if (getRHSKind() != EmptyKind && getLHSKind() == EmptyKind) - return false; - - // A twine child should always be binary. - if (getLHSKind() == TwineKind && - !LHS.twine->isBinary()) - return false; - if (getRHSKind() == TwineKind && - !RHS.twine->isBinary()) - return false; + /// Check for the null twine. + bool isNull() const { return getLHSKind() == NullKind; } - return true; - } + /// Check for the empty twine. + bool isEmpty() const { return getLHSKind() == EmptyKind; } - /// Get the NodeKind of the left-hand side. - NodeKind getLHSKind() const { return LHSKind; } + /// Check if this is a nullary twine (null or empty). + bool isNullary() const { return isNull() || isEmpty(); } - /// Get the NodeKind of the right-hand side. - NodeKind getRHSKind() const { return RHSKind; } + /// Check if this is a unary twine. + bool isUnary() const { return getRHSKind() == EmptyKind && !isNullary(); } - /// Print one child from a twine. - void printOneChild(raw_ostream &OS, Child Ptr, NodeKind Kind) const; + /// Check if this is a binary twine. + bool isBinary() const { + return getLHSKind() != NullKind && getRHSKind() != EmptyKind; + } - /// Print the representation of one child from a twine. - void printOneChildRepr(raw_ostream &OS, Child Ptr, - NodeKind Kind) const; + /// 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. + if (isNullary() && getRHSKind() != EmptyKind) + return false; - public: - /// @name Constructors - /// @{ + // Null should never appear on the RHS. + if (getRHSKind() == NullKind) + return false; - /// Construct from an empty string. - /*implicit*/ Twine() { - assert(isValid() && "Invalid twine!"); - } + // The RHS cannot be non-empty if the LHS is empty. + if (getRHSKind() != EmptyKind && getLHSKind() == EmptyKind) + return false; - Twine(const Twine &) = default; - - /// Construct from a C string. - /// - /// We take care here to optimize "" into the empty twine -- this will be - /// optimized out for string constants. This allows Twine arguments have - /// default "" values, without introducing unnecessary string constants. - /*implicit*/ Twine(const char *Str) { - if (Str[0] != '\0') { - LHS.cString = Str; - LHSKind = CStringKind; - } else { - LHSKind = EmptyKind; - } - - assert(isValid() && "Invalid twine!"); - } - /// Delete the implicit conversion from nullptr as Twine(const char *) - /// cannot take nullptr. - /*implicit*/ Twine(std::nullptr_t) = delete; - - /// Construct from an std::string. - /*implicit*/ Twine(const std::string &Str) : LHSKind(StdStringKind) { - LHS.stdString = &Str; - assert(isValid() && "Invalid twine!"); - } + // A twine child should always be binary. + if (getLHSKind() == TwineKind && !LHS.twine->isBinary()) + return false; + if (getRHSKind() == TwineKind && !RHS.twine->isBinary()) + return false; - /// Construct from an std::string_view by converting it to a pointer and - /// length. This handles string_views on a pure API basis, and avoids - /// storing one (or a pointer to one) inside a Twine, which avoids problems - /// when mixing code compiled under various C++ standards. - /*implicit*/ Twine(const std::string_view &Str) - : LHSKind(PtrAndLengthKind) { - LHS.ptrAndLength.ptr = Str.data(); - LHS.ptrAndLength.length = Str.length(); - assert(isValid() && "Invalid twine!"); - } + return true; + } - /// Construct from a StringRef. - /*implicit*/ Twine(const StringRef &Str) : LHSKind(PtrAndLengthKind) { - LHS.ptrAndLength.ptr = Str.data(); - LHS.ptrAndLength.length = Str.size(); - assert(isValid() && "Invalid twine!"); - } + /// Get the NodeKind of the left-hand side. + NodeKind getLHSKind() const { return LHSKind; } - /// 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!"); - } + /// Get the NodeKind of the right-hand side. + NodeKind getRHSKind() const { return RHSKind; } - /// Construct from a SmallString. - /*implicit*/ Twine(const SmallVectorImpl &Str) - : LHSKind(PtrAndLengthKind) { - LHS.ptrAndLength.ptr = Str.data(); - LHS.ptrAndLength.length = Str.size(); - assert(isValid() && "Invalid twine!"); - } + /// Print one child from a twine. + void printOneChild(raw_ostream &OS, Child Ptr, NodeKind Kind) const; - /// Construct from a formatv_object_base. - /*implicit*/ Twine(const formatv_object_base &Fmt) - : LHSKind(FormatvObjectKind) { - LHS.formatvObject = &Fmt; - assert(isValid() && "Invalid twine!"); - } + /// Print the representation of one child from a twine. + void printOneChildRepr(raw_ostream &OS, Child Ptr, NodeKind Kind) const; - /// Construct from a char. - explicit Twine(char Val) : LHSKind(CharKind) { - LHS.character = Val; - } +public: + /// @name Constructors + /// @{ - /// Construct from a signed char. - explicit Twine(signed char Val) : LHSKind(CharKind) { - LHS.character = static_cast(Val); - } + /// Construct from an empty string. + /*implicit*/ Twine() { assert(isValid() && "Invalid twine!"); } - /// Construct from an unsigned char. - explicit Twine(unsigned char Val) : LHSKind(CharKind) { - LHS.character = static_cast(Val); - } + Twine(const Twine &) = default; - /// Construct a twine to print \p Val as an unsigned decimal integer. - explicit Twine(unsigned Val) : LHSKind(DecUIKind) { - LHS.decUI = Val; - } + /// Construct from a C string. + /// + /// We take care here to optimize "" into the empty twine -- this will be + /// optimized out for string constants. This allows Twine arguments have + /// default "" values, without introducing unnecessary string constants. + /*implicit*/ Twine(const char *Str) { + if (Str[0] != '\0') { + LHS.cString = Str; + LHSKind = CStringKind; + } else { + LHSKind = EmptyKind; + } + + assert(isValid() && "Invalid twine!"); + } + /// Delete the implicit conversion from nullptr as Twine(const char *) + /// cannot take nullptr. + /*implicit*/ Twine(std::nullptr_t) = delete; + + /// Construct from an std::string. + /*implicit*/ Twine(const std::string &Str) : LHSKind(StdStringKind) { + LHS.stdString = &Str; + assert(isValid() && "Invalid twine!"); + } - /// Construct a twine to print \p Val as a signed decimal integer. - explicit Twine(int Val) : LHSKind(DecIKind) { - LHS.decI = Val; - } + /// Construct from an std::string_view by converting it to a pointer and + /// length. This handles string_views on a pure API basis, and avoids + /// storing one (or a pointer to one) inside a Twine, which avoids problems + /// when mixing code compiled under various C++ standards. + /*implicit*/ Twine(const std::string_view &Str) : LHSKind(PtrAndLengthKind) { + LHS.ptrAndLength.ptr = Str.data(); + LHS.ptrAndLength.length = Str.length(); + assert(isValid() && "Invalid twine!"); + } - /// Construct a twine to print \p Val as an unsigned decimal integer. - explicit Twine(const unsigned long &Val) : LHSKind(DecULKind) { - LHS.decUL = &Val; - } + /// Construct from a StringRef. + /*implicit*/ Twine(const StringRef &Str) : LHSKind(PtrAndLengthKind) { + LHS.ptrAndLength.ptr = Str.data(); + LHS.ptrAndLength.length = Str.size(); + assert(isValid() && "Invalid twine!"); + } - /// Construct a twine to print \p Val as a signed decimal integer. - explicit Twine(const long &Val) : LHSKind(DecLKind) { - LHS.decL = &Val; - } + /// 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 a twine to print \p Val as an unsigned decimal integer. - explicit Twine(const unsigned long long &Val) : LHSKind(DecULLKind) { - LHS.decULL = &Val; - } + /// Construct from a SmallString. + /*implicit*/ Twine(const SmallVectorImpl &Str) + : LHSKind(PtrAndLengthKind) { + LHS.ptrAndLength.ptr = Str.data(); + LHS.ptrAndLength.length = Str.size(); + assert(isValid() && "Invalid twine!"); + } - /// Construct a twine to print \p Val as a signed decimal integer. - explicit Twine(const long long &Val) : LHSKind(DecLLKind) { - LHS.decLL = &Val; - } + /// Construct from a formatv_object_base. + /*implicit*/ Twine(const formatv_object_base &Fmt) + : LHSKind(FormatvObjectKind) { + LHS.formatvObject = &Fmt; + assert(isValid() && "Invalid twine!"); + } - // 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 - // right thing. Yet. - - /// Construct as the concatenation of a C string and a StringRef. - /*implicit*/ Twine(const char *LHS, const StringRef &RHS) - : LHSKind(CStringKind), RHSKind(PtrAndLengthKind) { - this->LHS.cString = LHS; - this->RHS.ptrAndLength.ptr = RHS.data(); - this->RHS.ptrAndLength.length = RHS.size(); - assert(isValid() && "Invalid twine!"); - } + /// Construct from a char. + explicit Twine(char Val) : LHSKind(CharKind) { LHS.character = Val; } - /// Construct as the concatenation of a StringRef and a C string. - /*implicit*/ Twine(const StringRef &LHS, const char *RHS) - : LHSKind(PtrAndLengthKind), RHSKind(CStringKind) { - this->LHS.ptrAndLength.ptr = LHS.data(); - this->LHS.ptrAndLength.length = LHS.size(); - this->RHS.cString = RHS; - assert(isValid() && "Invalid twine!"); - } + /// Construct from a signed char. + explicit Twine(signed char Val) : LHSKind(CharKind) { + LHS.character = static_cast(Val); + } - /// Since the intended use of twines is as temporary objects, assignments - /// when concatenating might cause undefined behavior or stack corruptions - Twine &operator=(const Twine &) = delete; + /// Construct from an unsigned char. + explicit Twine(unsigned char Val) : LHSKind(CharKind) { + LHS.character = static_cast(Val); + } - /// Create a 'null' string, which is an empty string that always - /// concatenates to form another empty string. - static Twine createNull() { - return Twine(NullKind); - } + /// Construct a twine to print \p Val as an unsigned decimal integer. + explicit Twine(unsigned Val) : LHSKind(DecUIKind) { LHS.decUI = Val; } - /// @} - /// @name Numeric Conversions - /// @{ + /// Construct a twine to print \p Val as a signed decimal integer. + explicit Twine(int Val) : LHSKind(DecIKind) { LHS.decI = Val; } - // 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); - } + /// Construct a twine to print \p Val as an unsigned decimal integer. + explicit Twine(const unsigned long &Val) : LHSKind(DecULKind) { + LHS.decUL = &Val; + } - /// @} - /// @name Predicate Operations - /// @{ + /// Construct a twine to print \p Val as a signed decimal integer. + explicit Twine(const long &Val) : LHSKind(DecLKind) { LHS.decL = &Val; } - /// Check if this twine is trivially empty; a false return value does not - /// necessarily mean the twine is empty. - bool isTriviallyEmpty() const { - return isNullary(); - } + /// Construct a twine to print \p Val as an unsigned decimal integer. + explicit Twine(const unsigned long long &Val) : LHSKind(DecULLKind) { + LHS.decULL = &Val; + } - /// Check if this twine is guaranteed to refer to single string literal. - bool isSingleStringLiteral() const { - return isUnary() && getLHSKind() == StringLiteralKind; - } + /// Construct a twine to print \p Val as a signed decimal integer. + explicit Twine(const long long &Val) : LHSKind(DecLLKind) { + LHS.decLL = &Val; + } - /// 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 PtrAndLengthKind: - case StringLiteralKind: - return true; - default: - return false; - } - } + // 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 + // right thing. Yet. + + /// Construct as the concatenation of a C string and a StringRef. + /*implicit*/ Twine(const char *LHS, const StringRef &RHS) + : LHSKind(CStringKind), RHSKind(PtrAndLengthKind) { + this->LHS.cString = LHS; + this->RHS.ptrAndLength.ptr = RHS.data(); + this->RHS.ptrAndLength.length = RHS.size(); + assert(isValid() && "Invalid twine!"); + } - /// @} - /// @name String Operations - /// @{ - - Twine concat(const Twine &Suffix) const; - - /// @} - /// @name Output & Conversion. - /// @{ - - /// Return the twine contents as a std::string. - LLVM_ABI std::string str() const; - - /// Append the concatenated string into the given SmallString or SmallVector. - LLVM_ABI void toVector(SmallVectorImpl &Out) const; - - /// 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 PtrAndLengthKind: - case StringLiteralKind: - return StringRef(LHS.ptrAndLength.ptr, LHS.ptrAndLength.length); - } - } + /// Construct as the concatenation of a StringRef and a C string. + /*implicit*/ Twine(const StringRef &LHS, const char *RHS) + : LHSKind(PtrAndLengthKind), RHSKind(CStringKind) { + this->LHS.ptrAndLength.ptr = LHS.data(); + this->LHS.ptrAndLength.length = LHS.size(); + this->RHS.cString = RHS; + assert(isValid() && "Invalid twine!"); + } - /// 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()); - } + /// Since the intended use of twines is as temporary objects, assignments + /// when concatenating might cause undefined behavior or stack corruptions + Twine &operator=(const Twine &) = delete; - /// 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. - LLVM_ABI StringRef - toNullTerminatedStringRef(SmallVectorImpl &Out) const; + /// Create a 'null' string, which is an empty string that always + /// concatenates to form another empty string. + static Twine createNull() { return Twine(NullKind); } - /// Write the concatenated string represented by this twine to the - /// stream \p OS. - LLVM_ABI void print(raw_ostream &OS) const; + /// @} + /// @name Numeric Conversions + /// @{ - /// Write the representation of this twine to the stream \p OS. - LLVM_ABI void printRepr(raw_ostream &OS) const; + // 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); + } -#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) - /// Dump the concatenated string represented by this twine to stderr. - LLVM_DUMP_METHOD void dump() const; + /// @} + /// @name Predicate Operations + /// @{ - /// Dump the representation of this twine to stderr. - LLVM_DUMP_METHOD void dumpRepr() const; -#endif + /// Check if this twine is trivially empty; a false return value does not + /// necessarily mean the twine is empty. + bool isTriviallyEmpty() const { return isNullary(); } - /// @} - }; + /// Check if this twine is guaranteed to refer to single string literal. + bool isSingleStringLiteral() const { + return isUnary() && getLHSKind() == StringLiteralKind; + } - /// @name Twine Inline Implementations + /// 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 PtrAndLengthKind: + case StringLiteralKind: + return true; + default: + return false; + } + } + + /// @} + /// @name String Operations /// @{ - inline Twine Twine::concat(const Twine &Suffix) const { - // Concatenation with null is null. - if (isNull() || Suffix.isNull()) - return Twine(NullKind); - - // Concatenation with empty yields the other side. - if (isEmpty()) - return Suffix; - if (Suffix.isEmpty()) - return *this; - - // Otherwise we need to create a new node, taking care to fold in unary - // twines. - Child NewLHS, NewRHS; - NewLHS.twine = this; - NewRHS.twine = &Suffix; - NodeKind NewLHSKind = TwineKind, NewRHSKind = TwineKind; - if (isUnary()) { - NewLHS = LHS; - NewLHSKind = getLHSKind(); - } - if (Suffix.isUnary()) { - NewRHS = Suffix.LHS; - NewRHSKind = Suffix.getLHSKind(); - } + Twine concat(const Twine &Suffix) const; - return Twine(NewLHS, NewLHSKind, NewRHS, NewRHSKind); + /// @} + /// @name Output & Conversion. + /// @{ + + /// Return the twine contents as a std::string. + LLVM_ABI std::string str() const; + + /// Append the concatenated string into the given SmallString or SmallVector. + LLVM_ABI void toVector(SmallVectorImpl &Out) const; + + /// 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 PtrAndLengthKind: + case StringLiteralKind: + return StringRef(LHS.ptrAndLength.ptr, LHS.ptrAndLength.length); + } } - inline Twine operator+(const Twine &LHS, const Twine &RHS) { - return LHS.concat(RHS); + /// 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()); } - /// Additional overload to guarantee simplified codegen; this is equivalent to - /// concat(). + /// 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. + LLVM_ABI StringRef + toNullTerminatedStringRef(SmallVectorImpl &Out) const; - inline Twine operator+(const char *LHS, const StringRef &RHS) { - return Twine(LHS, RHS); - } + /// Write the concatenated string represented by this twine to the + /// stream \p OS. + LLVM_ABI void print(raw_ostream &OS) const; - /// Additional overload to guarantee simplified codegen; this is equivalent to - /// concat(). + /// Write the representation of this twine to the stream \p OS. + LLVM_ABI void printRepr(raw_ostream &OS) const; - inline Twine operator+(const StringRef &LHS, const char *RHS) { - return Twine(LHS, RHS); - } +#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) + /// Dump the concatenated string represented by this twine to stderr. + LLVM_DUMP_METHOD void dump() const; - inline raw_ostream &operator<<(raw_ostream &OS, const Twine &RHS) { - RHS.print(OS); - return OS; - } + /// Dump the representation of this twine to stderr. + LLVM_DUMP_METHOD void dumpRepr() const; +#endif /// @} +}; + +/// @name Twine Inline Implementations +/// @{ + +inline Twine Twine::concat(const Twine &Suffix) const { + // Concatenation with null is null. + if (isNull() || Suffix.isNull()) + return Twine(NullKind); + + // Concatenation with empty yields the other side. + if (isEmpty()) + return Suffix; + if (Suffix.isEmpty()) + return *this; + + // Otherwise we need to create a new node, taking care to fold in unary + // twines. + Child NewLHS, NewRHS; + NewLHS.twine = this; + NewRHS.twine = &Suffix; + NodeKind NewLHSKind = TwineKind, NewRHSKind = TwineKind; + if (isUnary()) { + NewLHS = LHS; + NewLHSKind = getLHSKind(); + } + if (Suffix.isUnary()) { + NewRHS = Suffix.LHS; + NewRHSKind = Suffix.getLHSKind(); + } + + return Twine(NewLHS, NewLHSKind, NewRHS, NewRHSKind); +} + +inline Twine operator+(const Twine &LHS, const Twine &RHS) { + return LHS.concat(RHS); +} + +/// Additional overload to guarantee simplified codegen; this is equivalent to +/// concat(). + +inline Twine operator+(const char *LHS, const StringRef &RHS) { + return Twine(LHS, RHS); +} + +/// Additional overload to guarantee simplified codegen; this is equivalent to +/// concat(). + +inline Twine operator+(const StringRef &LHS, const char *RHS) { + return Twine(LHS, RHS); +} + +inline raw_ostream &operator<<(raw_ostream &OS, const Twine &RHS) { + RHS.print(OS); + return OS; +} + +/// @} } // end namespace llvm diff --git a/llvm/lib/Support/Twine.cpp b/llvm/lib/Support/Twine.cpp index 495b9cf2dbd68..d6b48166fb0f6 100644 --- a/llvm/lib/Support/Twine.cpp +++ b/llvm/lib/Support/Twine.cpp @@ -56,11 +56,12 @@ StringRef Twine::toNullTerminatedStringRef(SmallVectorImpl &Out) const { return StringRef(Out.data(), Out.size()); } -void Twine::printOneChild(raw_ostream &OS, Child Ptr, - NodeKind Kind) const { +void Twine::printOneChild(raw_ostream &OS, Child Ptr, NodeKind Kind) const { switch (Kind) { - case Twine::NullKind: break; - case Twine::EmptyKind: break; + case Twine::NullKind: + break; + case Twine::EmptyKind: + break; case Twine::TwineKind: Ptr.twine->print(OS); break; @@ -104,24 +105,23 @@ void Twine::printOneChild(raw_ostream &OS, Child Ptr, } } -void Twine::printOneChildRepr(raw_ostream &OS, Child Ptr, - NodeKind Kind) const { +void Twine::printOneChildRepr(raw_ostream &OS, Child Ptr, NodeKind Kind) const { switch (Kind) { case Twine::NullKind: - OS << "null"; break; + OS << "null"; + break; case Twine::EmptyKind: - OS << "empty"; break; + OS << "empty"; + break; case Twine::TwineKind: OS << "rope:"; Ptr.twine->printRepr(OS); break; case Twine::CStringKind: - OS << "cstring:\"" - << Ptr.cString << "\""; + OS << "cstring:\"" << Ptr.cString << "\""; break; case Twine::StdStringKind: - OS << "std::string:\"" - << Ptr.stdString << "\""; + OS << "std::string:\"" << Ptr.stdString << "\""; break; case Twine::PtrAndLengthKind: OS << "ptrAndLength:\"" @@ -175,11 +175,7 @@ void Twine::printRepr(raw_ostream &OS) const { } #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) -LLVM_DUMP_METHOD void Twine::dump() const { - print(dbgs()); -} +LLVM_DUMP_METHOD void Twine::dump() const { print(dbgs()); } -LLVM_DUMP_METHOD void Twine::dumpRepr() const { - printRepr(dbgs()); -} +LLVM_DUMP_METHOD void Twine::dumpRepr() const { printRepr(dbgs()); } #endif