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