Coverage Report

Created: 2023-09-25 06:27

/src/abseil-cpp/absl/strings/str_cat.h
Line
Count
Source (jump to first uncovered line)
1
//
2
// Copyright 2017 The Abseil Authors.
3
//
4
// Licensed under the Apache License, Version 2.0 (the "License");
5
// you may not use this file except in compliance with the License.
6
// You may obtain a copy of the License at
7
//
8
//      https://www.apache.org/licenses/LICENSE-2.0
9
//
10
// Unless required by applicable law or agreed to in writing, software
11
// distributed under the License is distributed on an "AS IS" BASIS,
12
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
// See the License for the specific language governing permissions and
14
// limitations under the License.
15
//
16
// -----------------------------------------------------------------------------
17
// File: str_cat.h
18
// -----------------------------------------------------------------------------
19
//
20
// This package contains functions for efficiently concatenating and appending
21
// strings: `StrCat()` and `StrAppend()`. Most of the work within these routines
22
// is actually handled through use of a special AlphaNum type, which was
23
// designed to be used as a parameter type that efficiently manages conversion
24
// to strings and avoids copies in the above operations.
25
//
26
// Any routine accepting either a string or a number may accept `AlphaNum`.
27
// The basic idea is that by accepting a `const AlphaNum &` as an argument
28
// to your function, your callers will automagically convert bools, integers,
29
// and floating point values to strings for you.
30
//
31
// NOTE: Use of `AlphaNum` outside of the //absl/strings package is unsupported
32
// except for the specific case of function parameters of type `AlphaNum` or
33
// `const AlphaNum &`. In particular, instantiating `AlphaNum` directly as a
34
// stack variable is not supported.
35
//
36
// Conversion from 8-bit values is not accepted because, if it were, then an
37
// attempt to pass ':' instead of ":" might result in a 58 ending up in your
38
// result.
39
//
40
// Bools convert to "0" or "1". Pointers to types other than `char *` are not
41
// valid inputs. No output is generated for null `char *` pointers.
42
//
43
// Floating point numbers are formatted with six-digit precision, which is
44
// the default for "std::cout <<" or printf "%g" (the same as "%.6g").
45
//
46
// You can convert to hexadecimal output rather than decimal output using the
47
// `Hex` type contained here. To do so, pass `Hex(my_int)` as a parameter to
48
// `StrCat()` or `StrAppend()`. You may specify a minimum hex field width using
49
// a `PadSpec` enum.
50
//
51
// User-defined types can be formatted with the `AbslStringify()` customization
52
// point. The API relies on detecting an overload in the user-defined type's
53
// namespace of a free (non-member) `AbslStringify()` function as a definition
54
// (typically declared as a friend and implemented in-line.
55
// with the following signature:
56
//
57
// class MyClass { ... };
58
//
59
// template <typename Sink>
60
// void AbslStringify(Sink& sink, const MyClass& value);
61
//
62
// An `AbslStringify()` overload for a type should only be declared in the same
63
// file and namespace as said type.
64
//
65
// Note that `AbslStringify()` also supports use with `absl::StrFormat()` and
66
// `absl::Substitute()`.
67
//
68
// Example:
69
//
70
// struct Point {
71
//   // To add formatting support to `Point`, we simply need to add a free
72
//   // (non-member) function `AbslStringify()`. This method specifies how
73
//   // Point should be printed when absl::StrCat() is called on it. You can add
74
//   // such a free function using a friend declaration within the body of the
75
//   // class. The sink parameter is a templated type to avoid requiring
76
//   // dependencies.
77
//   template <typename Sink> friend void AbslStringify(Sink&
78
//   sink, const Point& p) {
79
//     absl::Format(&sink, "(%v, %v)", p.x, p.y);
80
//   }
81
//
82
//   int x;
83
//   int y;
84
// };
85
// -----------------------------------------------------------------------------
86
87
#ifndef ABSL_STRINGS_STR_CAT_H_
88
#define ABSL_STRINGS_STR_CAT_H_
89
90
#include <algorithm>
91
#include <array>
92
#include <cassert>
93
#include <cstddef>
94
#include <cstdint>
95
#include <cstring>
96
#include <limits>
97
#include <string>
98
#include <type_traits>
99
#include <utility>
100
#include <vector>
101
102
#include "absl/base/attributes.h"
103
#include "absl/base/port.h"
104
#include "absl/meta/type_traits.h"
105
#include "absl/strings/has_absl_stringify.h"
106
#include "absl/strings/internal/resize_uninitialized.h"
107
#include "absl/strings/internal/stringify_sink.h"
108
#include "absl/strings/numbers.h"
109
#include "absl/strings/string_view.h"
110
111
namespace absl {
112
ABSL_NAMESPACE_BEGIN
113
114
namespace strings_internal {
115
// AlphaNumBuffer allows a way to pass a string to StrCat without having to do
116
// memory allocation.  It is simply a pair of a fixed-size character array, and
117
// a size.  Please don't use outside of absl, yet.
118
template <size_t max_size>
119
struct AlphaNumBuffer {
120
  std::array<char, max_size> data;
121
  size_t size;
122
};
123
124
}  // namespace strings_internal
125
126
// Enum that specifies the number of significant digits to return in a `Hex` or
127
// `Dec` conversion and fill character to use. A `kZeroPad2` value, for example,
128
// would produce hexadecimal strings such as "0a","0f" and a 'kSpacePad5' value
129
// would produce hexadecimal strings such as "    a","    f".
130
enum PadSpec : uint8_t {
131
  kNoPad = 1,
132
  kZeroPad2,
133
  kZeroPad3,
134
  kZeroPad4,
135
  kZeroPad5,
136
  kZeroPad6,
137
  kZeroPad7,
138
  kZeroPad8,
139
  kZeroPad9,
140
  kZeroPad10,
141
  kZeroPad11,
142
  kZeroPad12,
143
  kZeroPad13,
144
  kZeroPad14,
145
  kZeroPad15,
146
  kZeroPad16,
147
  kZeroPad17,
148
  kZeroPad18,
149
  kZeroPad19,
150
  kZeroPad20,
151
152
  kSpacePad2 = kZeroPad2 + 64,
153
  kSpacePad3,
154
  kSpacePad4,
155
  kSpacePad5,
156
  kSpacePad6,
157
  kSpacePad7,
158
  kSpacePad8,
159
  kSpacePad9,
160
  kSpacePad10,
161
  kSpacePad11,
162
  kSpacePad12,
163
  kSpacePad13,
164
  kSpacePad14,
165
  kSpacePad15,
166
  kSpacePad16,
167
  kSpacePad17,
168
  kSpacePad18,
169
  kSpacePad19,
170
  kSpacePad20,
171
};
172
173
// -----------------------------------------------------------------------------
174
// Hex
175
// -----------------------------------------------------------------------------
176
//
177
// `Hex` stores a set of hexadecimal string conversion parameters for use
178
// within `AlphaNum` string conversions.
179
struct Hex {
180
  uint64_t value;
181
  uint8_t width;
182
  char fill;
183
184
  template <typename Int>
185
  explicit Hex(
186
      Int v, PadSpec spec = absl::kNoPad,
187
      typename std::enable_if<sizeof(Int) == 1 &&
188
                              !std::is_pointer<Int>::value>::type* = nullptr)
189
      : Hex(spec, static_cast<uint8_t>(v)) {}
190
  template <typename Int>
191
  explicit Hex(
192
      Int v, PadSpec spec = absl::kNoPad,
193
      typename std::enable_if<sizeof(Int) == 2 &&
194
                              !std::is_pointer<Int>::value>::type* = nullptr)
195
      : Hex(spec, static_cast<uint16_t>(v)) {}
196
  template <typename Int>
197
  explicit Hex(
198
      Int v, PadSpec spec = absl::kNoPad,
199
      typename std::enable_if<sizeof(Int) == 4 &&
200
                              !std::is_pointer<Int>::value>::type* = nullptr)
201
      : Hex(spec, static_cast<uint32_t>(v)) {}
202
  template <typename Int>
203
  explicit Hex(
204
      Int v, PadSpec spec = absl::kNoPad,
205
      typename std::enable_if<sizeof(Int) == 8 &&
206
                              !std::is_pointer<Int>::value>::type* = nullptr)
207
      : Hex(spec, static_cast<uint64_t>(v)) {}
208
  template <typename Pointee>
209
  explicit Hex(Pointee* v, PadSpec spec = absl::kNoPad)
210
      : Hex(spec, reinterpret_cast<uintptr_t>(v)) {}
211
212
  template <typename S>
213
  friend void AbslStringify(S& sink, Hex hex) {
214
    static_assert(
215
        numbers_internal::kFastToBufferSize >= 32,
216
        "This function only works when output buffer >= 32 bytes long");
217
    char buffer[numbers_internal::kFastToBufferSize];
218
    char* const end = &buffer[numbers_internal::kFastToBufferSize];
219
    auto real_width =
220
        absl::numbers_internal::FastHexToBufferZeroPad16(hex.value, end - 16);
221
    if (real_width >= hex.width) {
222
      sink.Append(absl::string_view(end - real_width, real_width));
223
    } else {
224
      // Pad first 16 chars because FastHexToBufferZeroPad16 pads only to 16 and
225
      // max pad width can be up to 20.
226
      std::memset(end - 32, hex.fill, 16);
227
      // Patch up everything else up to the real_width.
228
      std::memset(end - real_width - 16, hex.fill, 16);
229
      sink.Append(absl::string_view(end - hex.width, hex.width));
230
    }
231
  }
232
233
 private:
234
  Hex(PadSpec spec, uint64_t v)
235
      : value(v),
236
        width(spec == absl::kNoPad
237
                  ? 1
238
                  : spec >= absl::kSpacePad2 ? spec - absl::kSpacePad2 + 2
239
                                             : spec - absl::kZeroPad2 + 2),
240
0
        fill(spec >= absl::kSpacePad2 ? ' ' : '0') {}
241
};
242
243
// -----------------------------------------------------------------------------
244
// Dec
245
// -----------------------------------------------------------------------------
246
//
247
// `Dec` stores a set of decimal string conversion parameters for use
248
// within `AlphaNum` string conversions.  Dec is slower than the default
249
// integer conversion, so use it only if you need padding.
250
struct Dec {
251
  uint64_t value;
252
  uint8_t width;
253
  char fill;
254
  bool neg;
255
256
  template <typename Int>
257
  explicit Dec(Int v, PadSpec spec = absl::kNoPad,
258
               typename std::enable_if<(sizeof(Int) <= 8)>::type* = nullptr)
259
      : value(v >= 0 ? static_cast<uint64_t>(v)
260
                     : uint64_t{0} - static_cast<uint64_t>(v)),
261
        width(spec == absl::kNoPad
262
                  ? 1
263
                  : spec >= absl::kSpacePad2 ? spec - absl::kSpacePad2 + 2
264
                                             : spec - absl::kZeroPad2 + 2),
265
        fill(spec >= absl::kSpacePad2 ? ' ' : '0'),
266
        neg(v < 0) {}
267
268
  template <typename S>
269
  friend void AbslStringify(S& sink, Dec dec) {
270
    assert(dec.width <= numbers_internal::kFastToBufferSize);
271
    char buffer[numbers_internal::kFastToBufferSize];
272
    char* const end = &buffer[numbers_internal::kFastToBufferSize];
273
    char* const minfill = end - dec.width;
274
    char* writer = end;
275
    uint64_t val = dec.value;
276
    while (val > 9) {
277
      *--writer = '0' + (val % 10);
278
      val /= 10;
279
    }
280
    *--writer = '0' + static_cast<char>(val);
281
    if (dec.neg) *--writer = '-';
282
283
    ptrdiff_t fillers = writer - minfill;
284
    if (fillers > 0) {
285
      // Tricky: if the fill character is ' ', then it's <fill><+/-><digits>
286
      // But...: if the fill character is '0', then it's <+/-><fill><digits>
287
      bool add_sign_again = false;
288
      if (dec.neg && dec.fill == '0') {  // If filling with '0',
289
        ++writer;                    // ignore the sign we just added
290
        add_sign_again = true;       // and re-add the sign later.
291
      }
292
      writer -= fillers;
293
      std::fill_n(writer, fillers, dec.fill);
294
      if (add_sign_again) *--writer = '-';
295
    }
296
297
    sink.Append(absl::string_view(writer, static_cast<size_t>(end - writer)));
298
  }
299
};
300
301
// -----------------------------------------------------------------------------
302
// AlphaNum
303
// -----------------------------------------------------------------------------
304
//
305
// The `AlphaNum` class acts as the main parameter type for `StrCat()` and
306
// `StrAppend()`, providing efficient conversion of numeric, boolean, decimal,
307
// and hexadecimal values (through the `Dec` and `Hex` types) into strings.
308
// `AlphaNum` should only be used as a function parameter. Do not instantiate
309
//  `AlphaNum` directly as a stack variable.
310
311
class AlphaNum {
312
 public:
313
  // No bool ctor -- bools convert to an integral type.
314
  // A bool ctor would also convert incoming pointers (bletch).
315
316
  AlphaNum(int x)  // NOLINT(runtime/explicit)
317
      : piece_(digits_, static_cast<size_t>(
318
                            numbers_internal::FastIntToBuffer(x, digits_) -
319
0
                            &digits_[0])) {}
320
  AlphaNum(unsigned int x)  // NOLINT(runtime/explicit)
321
      : piece_(digits_, static_cast<size_t>(
322
                            numbers_internal::FastIntToBuffer(x, digits_) -
323
0
                            &digits_[0])) {}
324
  AlphaNum(long x)  // NOLINT(*)
325
      : piece_(digits_, static_cast<size_t>(
326
                            numbers_internal::FastIntToBuffer(x, digits_) -
327
0
                            &digits_[0])) {}
328
  AlphaNum(unsigned long x)  // NOLINT(*)
329
      : piece_(digits_, static_cast<size_t>(
330
                            numbers_internal::FastIntToBuffer(x, digits_) -
331
0
                            &digits_[0])) {}
332
  AlphaNum(long long x)  // NOLINT(*)
333
      : piece_(digits_, static_cast<size_t>(
334
                            numbers_internal::FastIntToBuffer(x, digits_) -
335
0
                            &digits_[0])) {}
336
  AlphaNum(unsigned long long x)  // NOLINT(*)
337
      : piece_(digits_, static_cast<size_t>(
338
                            numbers_internal::FastIntToBuffer(x, digits_) -
339
0
                            &digits_[0])) {}
340
341
  AlphaNum(float f)  // NOLINT(runtime/explicit)
342
0
      : piece_(digits_, numbers_internal::SixDigitsToBuffer(f, digits_)) {}
343
  AlphaNum(double f)  // NOLINT(runtime/explicit)
344
0
      : piece_(digits_, numbers_internal::SixDigitsToBuffer(f, digits_)) {}
345
346
  template <size_t size>
347
  AlphaNum(  // NOLINT(runtime/explicit)
348
      const strings_internal::AlphaNumBuffer<size>& buf
349
          ABSL_ATTRIBUTE_LIFETIME_BOUND)
350
      : piece_(&buf.data[0], buf.size) {}
351
352
  AlphaNum(const char* c_str  // NOLINT(runtime/explicit)
353
               ABSL_ATTRIBUTE_LIFETIME_BOUND)
354
0
      : piece_(NullSafeStringView(c_str)) {}
355
  AlphaNum(absl::string_view pc  // NOLINT(runtime/explicit)
356
               ABSL_ATTRIBUTE_LIFETIME_BOUND)
357
0
      : piece_(pc) {}
358
359
  template <typename T, typename = typename std::enable_if<
360
                            HasAbslStringify<T>::value>::type>
361
  AlphaNum(  // NOLINT(runtime/explicit)
362
      const T& v ABSL_ATTRIBUTE_LIFETIME_BOUND,
363
      strings_internal::StringifySink&& sink ABSL_ATTRIBUTE_LIFETIME_BOUND = {})
364
      : piece_(strings_internal::ExtractStringification(sink, v)) {}
365
366
  template <typename Allocator>
367
  AlphaNum(  // NOLINT(runtime/explicit)
368
      const std::basic_string<char, std::char_traits<char>, Allocator>& str
369
          ABSL_ATTRIBUTE_LIFETIME_BOUND)
370
0
      : piece_(str) {}
371
372
  // Use string literals ":" instead of character literals ':'.
373
  AlphaNum(char c) = delete;  // NOLINT(runtime/explicit)
374
375
  AlphaNum(const AlphaNum&) = delete;
376
  AlphaNum& operator=(const AlphaNum&) = delete;
377
378
0
  absl::string_view::size_type size() const { return piece_.size(); }
379
0
  const char* data() const { return piece_.data(); }
380
0
  absl::string_view Piece() const { return piece_; }
381
382
  // Match unscoped enums.  Use integral promotion so that a `char`-backed
383
  // enum becomes a wider integral type AlphaNum will accept.
384
  template <typename T,
385
            typename = typename std::enable_if<
386
                std::is_enum<T>{} && std::is_convertible<T, int>{} &&
387
                !HasAbslStringify<T>::value>::type>
388
  AlphaNum(T e)  // NOLINT(runtime/explicit)
389
      : AlphaNum(+e) {}
390
391
  // This overload matches scoped enums.  We must explicitly cast to the
392
  // underlying type, but use integral promotion for the same reason as above.
393
  template <typename T,
394
            typename std::enable_if<std::is_enum<T>{} &&
395
                                        !std::is_convertible<T, int>{} &&
396
                                        !HasAbslStringify<T>::value,
397
                                    char*>::type = nullptr>
398
  AlphaNum(T e)  // NOLINT(runtime/explicit)
399
      : AlphaNum(+static_cast<typename std::underlying_type<T>::type>(e)) {}
400
401
  // vector<bool>::reference and const_reference require special help to
402
  // convert to `AlphaNum` because it requires two user defined conversions.
403
  template <
404
      typename T,
405
      typename std::enable_if<
406
          std::is_class<T>::value &&
407
          (std::is_same<T, std::vector<bool>::reference>::value ||
408
           std::is_same<T, std::vector<bool>::const_reference>::value)>::type* =
409
          nullptr>
410
  AlphaNum(T e) : AlphaNum(static_cast<bool>(e)) {}  // NOLINT(runtime/explicit)
411
412
 private:
413
  absl::string_view piece_;
414
  char digits_[numbers_internal::kFastToBufferSize];
415
};
416
417
// -----------------------------------------------------------------------------
418
// StrCat()
419
// -----------------------------------------------------------------------------
420
//
421
// Merges given strings or numbers, using no delimiter(s), returning the merged
422
// result as a string.
423
//
424
// `StrCat()` is designed to be the fastest possible way to construct a string
425
// out of a mix of raw C strings, string_views, strings, bool values,
426
// and numeric values.
427
//
428
// Don't use `StrCat()` for user-visible strings. The localization process
429
// works poorly on strings built up out of fragments.
430
//
431
// For clarity and performance, don't use `StrCat()` when appending to a
432
// string. Use `StrAppend()` instead. In particular, avoid using any of these
433
// (anti-)patterns:
434
//
435
//   str.append(StrCat(...))
436
//   str += StrCat(...)
437
//   str = StrCat(str, ...)
438
//
439
// The last case is the worst, with a potential to change a loop
440
// from a linear time operation with O(1) dynamic allocations into a
441
// quadratic time operation with O(n) dynamic allocations.
442
//
443
// See `StrAppend()` below for more information.
444
445
namespace strings_internal {
446
447
// Do not call directly - this is not part of the public API.
448
std::string CatPieces(std::initializer_list<absl::string_view> pieces);
449
void AppendPieces(std::string* dest,
450
                  std::initializer_list<absl::string_view> pieces);
451
452
template <typename Integer>
453
0
std::string IntegerToString(Integer i) {
454
  // Any integer (signed/unsigned) up to 64 bits can be formatted into a buffer
455
  // with 22 bytes (including NULL at the end).
456
0
  constexpr size_t kMaxDigits10 = 22;
457
0
  std::string result;
458
0
  strings_internal::STLStringResizeUninitialized(&result, kMaxDigits10);
459
0
  char* start = &result[0];
460
  // note: this can be optimized to not write last zero.
461
0
  char* end = numbers_internal::FastIntToBuffer(i, start);
462
0
  auto size = static_cast<size_t>(end - start);
463
0
  assert((size < result.size()) &&
464
0
         "StrCat(Integer) does not fit into kMaxDigits10");
465
0
  result.erase(size);
466
0
  return result;
467
0
}
Unexecuted instantiation: std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > absl::strings_internal::IntegerToString<int>(int)
Unexecuted instantiation: std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > absl::strings_internal::IntegerToString<unsigned int>(unsigned int)
Unexecuted instantiation: std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > absl::strings_internal::IntegerToString<long>(long)
Unexecuted instantiation: std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > absl::strings_internal::IntegerToString<unsigned long>(unsigned long)
Unexecuted instantiation: std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > absl::strings_internal::IntegerToString<long long>(long long)
Unexecuted instantiation: std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > absl::strings_internal::IntegerToString<unsigned long long>(unsigned long long)
468
template <typename Float>
469
0
std::string FloatToString(Float f) {
470
0
  std::string result;
471
0
  strings_internal::STLStringResizeUninitialized(
472
0
      &result, numbers_internal::kSixDigitsToBufferSize);
473
0
  char* start = &result[0];
474
0
  result.erase(numbers_internal::SixDigitsToBuffer(f, start));
475
0
  return result;
476
0
}
Unexecuted instantiation: std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > absl::strings_internal::FloatToString<float>(float)
Unexecuted instantiation: std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > absl::strings_internal::FloatToString<double>(double)
477
478
// `SingleArgStrCat` overloads take built-in `int`, `long` and `long long` types
479
// (signed / unsigned) to avoid ambiguity on the call side. If we used int32_t
480
// and int64_t, then at least one of the three (`int` / `long` / `long long`)
481
// would have been ambiguous when passed to `SingleArgStrCat`.
482
0
inline std::string SingleArgStrCat(int x) { return IntegerToString(x); }
483
0
inline std::string SingleArgStrCat(unsigned int x) {
484
0
  return IntegerToString(x);
485
0
}
486
// NOLINTNEXTLINE
487
0
inline std::string SingleArgStrCat(long x) { return IntegerToString(x); }
488
// NOLINTNEXTLINE
489
0
inline std::string SingleArgStrCat(unsigned long x) {
490
0
  return IntegerToString(x);
491
0
}
492
// NOLINTNEXTLINE
493
0
inline std::string SingleArgStrCat(long long x) { return IntegerToString(x); }
494
// NOLINTNEXTLINE
495
0
inline std::string SingleArgStrCat(unsigned long long x) {
496
0
  return IntegerToString(x);
497
0
}
498
0
inline std::string SingleArgStrCat(float x) { return FloatToString(x); }
499
0
inline std::string SingleArgStrCat(double x) { return FloatToString(x); }
500
501
// As of September 2023, the SingleArgStrCat() optimization is only enabled for
502
// libc++. The reasons for this are:
503
// 1) The SSO size for libc++ is 23, while libstdc++ and MSSTL have an SSO size
504
// of 15. Since IntegerToString unconditionally resizes the string to 22 bytes,
505
// this causes both libstdc++ and MSSTL to allocate.
506
// 2) strings_internal::STLStringResizeUninitialized() only has an
507
// implementation that avoids initialization when using libc++. This isn't as
508
// relevant as (1), and the cost should be benchmarked if (1) ever changes on
509
// libstc++ or MSSTL.
510
#ifdef _LIBCPP_VERSION
511
#define ABSL_INTERNAL_STRCAT_ENABLE_FAST_CASE true
512
#else
513
#define ABSL_INTERNAL_STRCAT_ENABLE_FAST_CASE false
514
#endif
515
516
template <typename T, typename = std::enable_if_t<
517
                          ABSL_INTERNAL_STRCAT_ENABLE_FAST_CASE &&
518
                          std::is_arithmetic<T>{} && !std::is_same<T, char>{}>>
519
using EnableIfFastCase = T;
520
521
#undef ABSL_INTERNAL_STRCAT_ENABLE_FAST_CASE
522
523
}  // namespace strings_internal
524
525
0
ABSL_MUST_USE_RESULT inline std::string StrCat() { return std::string(); }
526
527
template <typename T>
528
ABSL_MUST_USE_RESULT inline std::string StrCat(
529
0
    strings_internal::EnableIfFastCase<T> a) {
530
0
  return strings_internal::SingleArgStrCat(a);
531
0
}
Unexecuted instantiation: std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > absl::StrCat<short>(short)
Unexecuted instantiation: std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > absl::StrCat<unsigned short>(unsigned short)
Unexecuted instantiation: std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > absl::StrCat<int>(int)
Unexecuted instantiation: std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > absl::StrCat<unsigned int>(unsigned int)
Unexecuted instantiation: std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > absl::StrCat<long>(long)
Unexecuted instantiation: std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > absl::StrCat<unsigned long>(unsigned long)
Unexecuted instantiation: std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > absl::StrCat<long long>(long long)
Unexecuted instantiation: std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > absl::StrCat<unsigned long long>(unsigned long long)
532
0
ABSL_MUST_USE_RESULT inline std::string StrCat(const AlphaNum& a) {
533
0
  return std::string(a.data(), a.size());
534
0
}
535
536
ABSL_MUST_USE_RESULT std::string StrCat(const AlphaNum& a, const AlphaNum& b);
537
ABSL_MUST_USE_RESULT std::string StrCat(const AlphaNum& a, const AlphaNum& b,
538
                                        const AlphaNum& c);
539
ABSL_MUST_USE_RESULT std::string StrCat(const AlphaNum& a, const AlphaNum& b,
540
                                        const AlphaNum& c, const AlphaNum& d);
541
542
// Support 5 or more arguments
543
template <typename... AV>
544
ABSL_MUST_USE_RESULT inline std::string StrCat(
545
    const AlphaNum& a, const AlphaNum& b, const AlphaNum& c, const AlphaNum& d,
546
0
    const AlphaNum& e, const AV&... args) {
547
0
  return strings_internal::CatPieces(
548
0
      {a.Piece(), b.Piece(), c.Piece(), d.Piece(), e.Piece(),
549
0
       static_cast<const AlphaNum&>(args).Piece()...});
550
0
}
Unexecuted instantiation: std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > absl::StrCat<char [2]>(absl::AlphaNum const&, absl::AlphaNum const&, absl::AlphaNum const&, absl::AlphaNum const&, absl::AlphaNum const&, char const (&) [2])
Unexecuted instantiation: std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > absl::StrCat<absl::string_view, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >(absl::AlphaNum const&, absl::AlphaNum const&, absl::AlphaNum const&, absl::AlphaNum const&, absl::AlphaNum const&, absl::string_view const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)
Unexecuted instantiation: std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > absl::StrCat<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, char [30], std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >(absl::AlphaNum const&, absl::AlphaNum const&, absl::AlphaNum const&, absl::AlphaNum const&, absl::AlphaNum const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, char const (&) [30], std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)
Unexecuted instantiation: std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > absl::StrCat<char const*>(absl::AlphaNum const&, absl::AlphaNum const&, absl::AlphaNum const&, absl::AlphaNum const&, absl::AlphaNum const&, char const* const&)
Unexecuted instantiation: std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > absl::StrCat<>(absl::AlphaNum const&, absl::AlphaNum const&, absl::AlphaNum const&, absl::AlphaNum const&, absl::AlphaNum const&)
Unexecuted instantiation: std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > absl::StrCat<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, char [3]>(absl::AlphaNum const&, absl::AlphaNum const&, absl::AlphaNum const&, absl::AlphaNum const&, absl::AlphaNum const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, char const (&) [3])
Unexecuted instantiation: std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > absl::StrCat<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, char [4]>(absl::AlphaNum const&, absl::AlphaNum const&, absl::AlphaNum const&, absl::AlphaNum const&, absl::AlphaNum const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, char const (&) [4])
Unexecuted instantiation: std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > absl::StrCat<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, char [179]>(absl::AlphaNum const&, absl::AlphaNum const&, absl::AlphaNum const&, absl::AlphaNum const&, absl::AlphaNum const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, char const (&) [179])
551
552
// -----------------------------------------------------------------------------
553
// StrAppend()
554
// -----------------------------------------------------------------------------
555
//
556
// Appends a string or set of strings to an existing string, in a similar
557
// fashion to `StrCat()`.
558
//
559
// WARNING: `StrAppend(&str, a, b, c, ...)` requires that none of the
560
// a, b, c, parameters be a reference into str. For speed, `StrAppend()` does
561
// not try to check each of its input arguments to be sure that they are not
562
// a subset of the string being appended to. That is, while this will work:
563
//
564
//   std::string s = "foo";
565
//   s += s;
566
//
567
// This output is undefined:
568
//
569
//   std::string s = "foo";
570
//   StrAppend(&s, s);
571
//
572
// This output is undefined as well, since `absl::string_view` does not own its
573
// data:
574
//
575
//   std::string s = "foobar";
576
//   absl::string_view p = s;
577
//   StrAppend(&s, p);
578
579
0
inline void StrAppend(std::string*) {}
580
void StrAppend(std::string* dest, const AlphaNum& a);
581
void StrAppend(std::string* dest, const AlphaNum& a, const AlphaNum& b);
582
void StrAppend(std::string* dest, const AlphaNum& a, const AlphaNum& b,
583
               const AlphaNum& c);
584
void StrAppend(std::string* dest, const AlphaNum& a, const AlphaNum& b,
585
               const AlphaNum& c, const AlphaNum& d);
586
587
// Support 5 or more arguments
588
template <typename... AV>
589
inline void StrAppend(std::string* dest, const AlphaNum& a, const AlphaNum& b,
590
                      const AlphaNum& c, const AlphaNum& d, const AlphaNum& e,
591
                      const AV&... args) {
592
  strings_internal::AppendPieces(
593
      dest, {a.Piece(), b.Piece(), c.Piece(), d.Piece(), e.Piece(),
594
             static_cast<const AlphaNum&>(args).Piece()...});
595
}
596
597
// Helper function for the future StrCat default floating-point format, %.6g
598
// This is fast.
599
inline strings_internal::AlphaNumBuffer<
600
    numbers_internal::kSixDigitsToBufferSize>
601
0
SixDigits(double d) {
602
0
  strings_internal::AlphaNumBuffer<numbers_internal::kSixDigitsToBufferSize>
603
0
      result;
604
0
  result.size = numbers_internal::SixDigitsToBuffer(d, &result.data[0]);
605
0
  return result;
606
0
}
607
608
ABSL_NAMESPACE_END
609
}  // namespace absl
610
611
#endif  // ABSL_STRINGS_STR_CAT_H_