//===- Twine.h - Fast Temporary String Concatenation ------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #ifndef LLVM_ADT_TWINE_H #define LLVM_ADT_TWINE_H #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/ErrorHandling.h" #include <cassert> #include <cstdint> #include <string> #include <string_view> namespace llvm { 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 { … }; /// @name Twine Inline Implementations /// @{ inline Twine Twine::concat(const Twine &Suffix) const { … } inline Twine operator+(const Twine &LHS, const Twine &RHS) { … } /// Additional overload to guarantee simplified codegen; this is equivalent to /// concat(). inline Twine operator+(const char *LHS, const StringRef &RHS) { … } /// Additional overload to guarantee simplified codegen; this is equivalent to /// concat(). inline Twine operator+(const StringRef &LHS, const char *RHS) { … } inline raw_ostream &operator<<(raw_ostream &OS, const Twine &RHS) { … } /// @} } // end namespace llvm #endif // LLVM_ADT_TWINE_H