WPILibC++  2018.4.1-20180821010228-1169-g4a3e43d
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Modules Pages
Twine.h
1 //===- Twine.h - Fast Temporary String Concatenation ------------*- C++ -*-===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #ifndef WPIUTIL_WPI_TWINE_H
11 #define WPIUTIL_WPI_TWINE_H
12 
13 #include "wpi/SmallVector.h"
14 #include "wpi/StringRef.h"
15 #include <cassert>
16 #include <cstdint>
17 #include <string>
18 
19 namespace wpi {
20 
21  class raw_ostream;
22 
79  class Twine {
81  enum NodeKind : unsigned char {
84  NullKind,
85 
87  EmptyKind,
88 
90  TwineKind,
91 
93  CStringKind,
94 
96  StdStringKind,
97 
99  StringRefKind,
100 
102  SmallStringKind,
103 
105  CharKind,
106 
108  DecUIKind,
109 
111  DecIKind,
112 
115  DecULKind,
116 
118  DecLKind,
119 
122  DecULLKind,
123 
125  DecLLKind,
126 
129  UHexKind
130  };
131 
132  union Child
133  {
134  const Twine *twine;
135  const char *cString;
136  const std::string *stdString;
137  const StringRef *stringRef;
138  const SmallVectorImpl<char> *smallString;
139  char character;
140  unsigned int decUI;
141  int decI;
142  const unsigned long *decUL;
143  const long *decL;
144  const unsigned long long *decULL;
145  const long long *decLL;
146  const uint64_t *uHex;
147  };
148 
151  Child LHS;
152 
155  Child RHS;
156 
158  NodeKind LHSKind = EmptyKind;
159 
161  NodeKind RHSKind = EmptyKind;
162 
164  explicit Twine(NodeKind Kind) : LHSKind(Kind) {
165  assert(isNullary() && "Invalid kind!");
166  }
167 
169  explicit Twine(const Twine &LHS, const Twine &RHS)
170  : LHSKind(TwineKind), RHSKind(TwineKind) {
171  this->LHS.twine = &LHS;
172  this->RHS.twine = &RHS;
173  assert(isValid() && "Invalid twine!");
174  }
175 
177  explicit Twine(Child LHS, NodeKind LHSKind, Child RHS, NodeKind RHSKind)
178  : LHS(LHS), RHS(RHS), LHSKind(LHSKind), RHSKind(RHSKind) {
179  assert(isValid() && "Invalid twine!");
180  }
181 
183  bool isEmpty() const {
184  return getLHSKind() == EmptyKind;
185  }
186 
188  bool isNullary() const {
189  return isNull() || isEmpty();
190  }
191 
193  bool isUnary() const {
194  return getRHSKind() == EmptyKind && !isNullary();
195  }
196 
198  bool isBinary() const {
199  return getLHSKind() != NullKind && getRHSKind() != EmptyKind;
200  }
201 
204  bool isValid() const {
205  // Nullary twines always have Empty on the RHS.
206  if (isNullary() && getRHSKind() != EmptyKind)
207  return false;
208 
209  // Null should never appear on the RHS.
210  if (getRHSKind() == NullKind)
211  return false;
212 
213  // The RHS cannot be non-empty if the LHS is empty.
214  if (getRHSKind() != EmptyKind && getLHSKind() == EmptyKind)
215  return false;
216 #if 0 // causes spurious warnings
217  // A twine child should always be binary.
218  if (getLHSKind() == TwineKind &&
219  !LHS.twine->isBinary())
220  return false;
221  if (getRHSKind() == TwineKind &&
222  !RHS.twine->isBinary())
223  return false;
224 #endif
225  return true;
226  }
227 
229  NodeKind getLHSKind() const { return LHSKind; }
230 
232  NodeKind getRHSKind() const { return RHSKind; }
233 
235  void printOneChild(raw_ostream &OS, Child Ptr, NodeKind Kind) const;
236 
238  void printOneChildRepr(raw_ostream &OS, Child Ptr,
239  NodeKind Kind) const;
240 
241  public:
244 
246  /*implicit*/ Twine() {
247  assert(isValid() && "Invalid twine!");
248  }
249 
250  Twine(const Twine &) = default;
251 
257  /*implicit*/ Twine(const char *Str) {
258  if (Str[0] != '\0') {
259  LHS.cString = Str;
260  LHSKind = CStringKind;
261  } else
262  LHSKind = EmptyKind;
263 
264  assert(isValid() && "Invalid twine!");
265  }
266 
268  /*implicit*/ Twine(const std::string &Str) : LHSKind(StdStringKind) {
269  LHS.stdString = &Str;
270  assert(isValid() && "Invalid twine!");
271  }
272 
274  /*implicit*/ Twine(const StringRef &Str) : LHSKind(StringRefKind) {
275  LHS.stringRef = &Str;
276  assert(isValid() && "Invalid twine!");
277  }
278 
280  /*implicit*/ Twine(const SmallVectorImpl<char> &Str)
281  : LHSKind(SmallStringKind) {
282  LHS.smallString = &Str;
283  assert(isValid() && "Invalid twine!");
284  }
285 
287  explicit Twine(char Val) : LHSKind(CharKind) {
288  LHS.character = Val;
289  }
290 
292  explicit Twine(signed char Val) : LHSKind(CharKind) {
293  LHS.character = static_cast<char>(Val);
294  }
295 
297  explicit Twine(unsigned char Val) : LHSKind(CharKind) {
298  LHS.character = static_cast<char>(Val);
299  }
300 
302  explicit Twine(unsigned Val) : LHSKind(DecUIKind) {
303  LHS.decUI = Val;
304  }
305 
307  explicit Twine(int Val) : LHSKind(DecIKind) {
308  LHS.decI = Val;
309  }
310 
312  explicit Twine(const unsigned long &Val) : LHSKind(DecULKind) {
313  LHS.decUL = &Val;
314  }
315 
317  explicit Twine(const long &Val) : LHSKind(DecLKind) {
318  LHS.decL = &Val;
319  }
320 
322  explicit Twine(const unsigned long long &Val) : LHSKind(DecULLKind) {
323  LHS.decULL = &Val;
324  }
325 
327  explicit Twine(const long long &Val) : LHSKind(DecLLKind) {
328  LHS.decLL = &Val;
329  }
330 
331  // FIXME: Unfortunately, to make sure this is as efficient as possible we
332  // need extra binary constructors from particular types. We can't rely on
333  // the compiler to be smart enough to fold operator+()/concat() down to the
334  // right thing. Yet.
335 
337  /*implicit*/ Twine(const char *LHS, const StringRef &RHS)
338  : LHSKind(CStringKind), RHSKind(StringRefKind) {
339  this->LHS.cString = LHS;
340  this->RHS.stringRef = &RHS;
341  assert(isValid() && "Invalid twine!");
342  }
343 
345  /*implicit*/ Twine(const StringRef &LHS, const char *RHS)
346  : LHSKind(StringRefKind), RHSKind(CStringKind) {
347  this->LHS.stringRef = &LHS;
348  this->RHS.cString = RHS;
349  assert(isValid() && "Invalid twine!");
350  }
351 
354  Twine &operator=(const Twine &) = delete;
355 
358  static Twine createNull() {
359  return Twine(NullKind);
360  }
361 
365 
366  // Construct a twine to print \p Val as an unsigned hexadecimal integer.
367  static Twine utohexstr(const uint64_t &Val) {
368  Child LHS, RHS;
369  LHS.uHex = &Val;
370  RHS.twine = nullptr;
371  return Twine(LHS, UHexKind, RHS, EmptyKind);
372  }
373 
377 
379  bool isNull() const {
380  return getLHSKind() == NullKind;
381  }
382 
385  bool isTriviallyEmpty() const {
386  return isNullary();
387  }
388 
391  bool isSingleStringRef() const {
392  if (getRHSKind() != EmptyKind) return false;
393 
394  switch (getLHSKind()) {
395  case EmptyKind:
396  case CStringKind:
397  case StdStringKind:
398  case StringRefKind:
399  case SmallStringKind:
400  case CharKind:
401  return true;
402  default:
403  return false;
404  }
405  }
406 
410 
411  Twine concat(const Twine &Suffix) const;
412 
416 
418  std::string str() const;
419 
421  void toVector(SmallVectorImpl<char> &Out) const;
422 
426  assert(isSingleStringRef() &&"This cannot be had as a single stringref!");
427  switch (getLHSKind()) {
428  default:
429  // unreachable("Out of sync with isSingleStringRef");
430  return StringRef();
431  case EmptyKind: return StringRef();
432  case CStringKind: return StringRef(LHS.cString);
433  case StdStringKind: return StringRef(*LHS.stdString);
434  case StringRefKind: return *LHS.stringRef;
435  case SmallStringKind:
436  return StringRef(LHS.smallString->data(), LHS.smallString->size());
437  case CharKind: return StringRef(&LHS.character, 1);
438  }
439  }
440 
445  if (isSingleStringRef())
446  return getSingleStringRef();
447  toVector(Out);
448  return StringRef(Out.data(), Out.size());
449  }
450 
457 
460  void print(raw_ostream &OS) const;
461 
463  void dump() const;
464 
466  void printRepr(raw_ostream &OS) const;
467 
469  void dumpRepr() const;
470 
472  };
473 
476 
477  inline Twine Twine::concat(const Twine &Suffix) const {
478  // Concatenation with null is null.
479  if (isNull() || Suffix.isNull())
480  return Twine(NullKind);
481 
482  // Concatenation with empty yields the other side.
483  if (isEmpty())
484  return Suffix;
485  if (Suffix.isEmpty())
486  return *this;
487 
488  // Otherwise we need to create a new node, taking care to fold in unary
489  // twines.
490  Child NewLHS, NewRHS;
491  NewLHS.twine = this;
492  NewRHS.twine = &Suffix;
493  NodeKind NewLHSKind = TwineKind, NewRHSKind = TwineKind;
494  if (isUnary()) {
495  NewLHS = LHS;
496  NewLHSKind = getLHSKind();
497  }
498  if (Suffix.isUnary()) {
499  NewRHS = Suffix.LHS;
500  NewRHSKind = Suffix.getLHSKind();
501  }
502 
503  return Twine(NewLHS, NewLHSKind, NewRHS, NewRHSKind);
504  }
505 
506  inline Twine operator+(const Twine &LHS, const Twine &RHS) {
507  return LHS.concat(RHS);
508  }
509 
512 
513  inline Twine operator+(const char *LHS, const StringRef &RHS) {
514  return Twine(LHS, RHS);
515  }
516 
519 
520  inline Twine operator+(const StringRef &LHS, const char *RHS) {
521  return Twine(LHS, RHS);
522  }
523 
524  inline raw_ostream &operator<<(raw_ostream &OS, const Twine &RHS) {
525  RHS.print(OS);
526  return OS;
527  }
528 
530 
531 } // end namespace wpi
532 
533 #endif // LLVM_ADT_TWINE_H
This class implements an extremely fast bulk output stream that can only output to a stream...
Definition: raw_ostream.h:45
StringRef toNullTerminatedStringRef(SmallVectorImpl< char > &Out) const
This returns the twine as a single null terminated StringRef if it can be represented as such...
bool isTriviallyEmpty() const
Check if this twine is trivially empty; a false return value does not necessarily mean the twine is e...
Definition: Twine.h:385
Twine(const unsigned long long &Val)
Construct a twine to print Val as an unsigned decimal integer.
Definition: Twine.h:322
Twine(const char *Str)
Construct from a C string.
Definition: Twine.h:257
Twine(unsigned char Val)
Construct from an unsigned char.
Definition: Twine.h:297
void dumpRepr() const
Dump the representation of this twine to stderr.
Twine()
Construct from an empty string.
Definition: Twine.h:246
static Twine createNull()
Create a 'null' string, which is an empty string that always concatenates to form another empty strin...
Definition: Twine.h:358
Twine(const unsigned long &Val)
Construct a twine to print Val as an unsigned decimal integer.
Definition: Twine.h:312
Twine(const long &Val)
Construct a twine to print Val as a signed decimal integer.
Definition: Twine.h:317
Twine(const StringRef &Str)
Construct from a StringRef.
Definition: Twine.h:274
WPILib C++ utilities (wpiutil) namespace.
Definition: SmallString.h:21
Twine(const char *LHS, const StringRef &RHS)
Construct as the concatenation of a C string and a StringRef.
Definition: Twine.h:337
bool isNull() const
Check for the null twine.
Definition: Twine.h:379
void print(raw_ostream &OS) const
Write the concatenated string represented by this twine to the stream OS.
Twine(char Val)
Construct from a char.
Definition: Twine.h:287
void printRepr(raw_ostream &OS) const
Write the representation of this twine to the stream OS.
std::string str() const
Return the twine contents as a std::string.
Twine(const SmallVectorImpl< char > &Str)
Construct from a SmallString.
Definition: Twine.h:280
Twine(const std::string &Str)
Construct from an std::string.
Definition: Twine.h:268
Twine(const StringRef &LHS, const char *RHS)
Construct as the concatenation of a StringRef and a C string.
Definition: Twine.h:345
void dump() const
Dump the concatenated string represented by this twine to stderr.
bool isSingleStringRef() const
Return true if this twine can be dynamically accessed as a single StringRef value with getSingleStrin...
Definition: Twine.h:391
void toVector(SmallVectorImpl< char > &Out) const
Append the concatenated string into the given SmallString or SmallVector.
Twine(int Val)
Construct a twine to print Val as a signed decimal integer.
Definition: Twine.h:307
Twine & operator=(const Twine &)=delete
Since the intended use of twines is as temporary objects, assignments when concatenating might cause ...
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:49
Twine(signed char Val)
Construct from a signed char.
Definition: Twine.h:292
Twine(unsigned Val)
Construct a twine to print Val as an unsigned decimal integer.
Definition: Twine.h:302
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition: Twine.h:79
pointer data()
Return a pointer to the vector's buffer, even if empty().
Definition: SmallVector.h:151
StringRef getSingleStringRef() const
This returns the twine as a single StringRef.
Definition: Twine.h:425
StringRef toStringRef(SmallVectorImpl< char > &Out) const
This returns the twine as a single StringRef if it can be represented as such.
Definition: Twine.h:444
Twine(const long long &Val)
Construct a twine to print Val as a signed decimal integer.
Definition: Twine.h:327