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