Coverage Report

Created: 2024-09-08 06:07

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