Coverage Report

Created: 2023-06-07 07:09

/src/LPM/external.protobuf/include/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 <array>
91
#include <cstdint>
92
#include <string>
93
#include <type_traits>
94
#include <utility>
95
#include <vector>
96
97
#include "absl/base/port.h"
98
#include "absl/strings/internal/has_absl_stringify.h"
99
#include "absl/strings/internal/stringify_sink.h"
100
#include "absl/strings/numbers.h"
101
#include "absl/strings/string_view.h"
102
103
namespace absl {
104
ABSL_NAMESPACE_BEGIN
105
106
namespace strings_internal {
107
// AlphaNumBuffer allows a way to pass a string to StrCat without having to do
108
// memory allocation.  It is simply a pair of a fixed-size character array, and
109
// a size.  Please don't use outside of absl, yet.
110
template <size_t max_size>
111
struct AlphaNumBuffer {
112
  std::array<char, max_size> data;
113
  size_t size;
114
};
115
116
}  // namespace strings_internal
117
118
// Enum that specifies the number of significant digits to return in a `Hex` or
119
// `Dec` conversion and fill character to use. A `kZeroPad2` value, for example,
120
// would produce hexadecimal strings such as "0a","0f" and a 'kSpacePad5' value
121
// would produce hexadecimal strings such as "    a","    f".
122
enum PadSpec : uint8_t {
123
  kNoPad = 1,
124
  kZeroPad2,
125
  kZeroPad3,
126
  kZeroPad4,
127
  kZeroPad5,
128
  kZeroPad6,
129
  kZeroPad7,
130
  kZeroPad8,
131
  kZeroPad9,
132
  kZeroPad10,
133
  kZeroPad11,
134
  kZeroPad12,
135
  kZeroPad13,
136
  kZeroPad14,
137
  kZeroPad15,
138
  kZeroPad16,
139
  kZeroPad17,
140
  kZeroPad18,
141
  kZeroPad19,
142
  kZeroPad20,
143
144
  kSpacePad2 = kZeroPad2 + 64,
145
  kSpacePad3,
146
  kSpacePad4,
147
  kSpacePad5,
148
  kSpacePad6,
149
  kSpacePad7,
150
  kSpacePad8,
151
  kSpacePad9,
152
  kSpacePad10,
153
  kSpacePad11,
154
  kSpacePad12,
155
  kSpacePad13,
156
  kSpacePad14,
157
  kSpacePad15,
158
  kSpacePad16,
159
  kSpacePad17,
160
  kSpacePad18,
161
  kSpacePad19,
162
  kSpacePad20,
163
};
164
165
// -----------------------------------------------------------------------------
166
// Hex
167
// -----------------------------------------------------------------------------
168
//
169
// `Hex` stores a set of hexadecimal string conversion parameters for use
170
// within `AlphaNum` string conversions.
171
struct Hex {
172
  uint64_t value;
173
  uint8_t width;
174
  char fill;
175
176
  template <typename Int>
177
  explicit Hex(
178
      Int v, PadSpec spec = absl::kNoPad,
179
      typename std::enable_if<sizeof(Int) == 1 &&
180
                              !std::is_pointer<Int>::value>::type* = nullptr)
181
      : Hex(spec, static_cast<uint8_t>(v)) {}
182
  template <typename Int>
183
  explicit Hex(
184
      Int v, PadSpec spec = absl::kNoPad,
185
      typename std::enable_if<sizeof(Int) == 2 &&
186
                              !std::is_pointer<Int>::value>::type* = nullptr)
187
      : Hex(spec, static_cast<uint16_t>(v)) {}
188
  template <typename Int>
189
  explicit Hex(
190
      Int v, PadSpec spec = absl::kNoPad,
191
      typename std::enable_if<sizeof(Int) == 4 &&
192
                              !std::is_pointer<Int>::value>::type* = nullptr)
193
      : Hex(spec, static_cast<uint32_t>(v)) {}
194
  template <typename Int>
195
  explicit Hex(
196
      Int v, PadSpec spec = absl::kNoPad,
197
      typename std::enable_if<sizeof(Int) == 8 &&
198
                              !std::is_pointer<Int>::value>::type* = nullptr)
199
      : Hex(spec, static_cast<uint64_t>(v)) {}
200
  template <typename Pointee>
201
  explicit Hex(Pointee* v, PadSpec spec = absl::kNoPad)
202
      : Hex(spec, reinterpret_cast<uintptr_t>(v)) {}
203
204
 private:
205
  Hex(PadSpec spec, uint64_t v)
206
      : value(v),
207
        width(spec == absl::kNoPad
208
                  ? 1
209
                  : spec >= absl::kSpacePad2 ? spec - absl::kSpacePad2 + 2
210
                                             : spec - absl::kZeroPad2 + 2),
211
0
        fill(spec >= absl::kSpacePad2 ? ' ' : '0') {}
212
};
213
214
// -----------------------------------------------------------------------------
215
// Dec
216
// -----------------------------------------------------------------------------
217
//
218
// `Dec` stores a set of decimal string conversion parameters for use
219
// within `AlphaNum` string conversions.  Dec is slower than the default
220
// integer conversion, so use it only if you need padding.
221
struct Dec {
222
  uint64_t value;
223
  uint8_t width;
224
  char fill;
225
  bool neg;
226
227
  template <typename Int>
228
  explicit Dec(Int v, PadSpec spec = absl::kNoPad,
229
               typename std::enable_if<(sizeof(Int) <= 8)>::type* = nullptr)
230
      : value(v >= 0 ? static_cast<uint64_t>(v)
231
                     : uint64_t{0} - static_cast<uint64_t>(v)),
232
        width(spec == absl::kNoPad
233
                  ? 1
234
                  : spec >= absl::kSpacePad2 ? spec - absl::kSpacePad2 + 2
235
                                             : spec - absl::kZeroPad2 + 2),
236
        fill(spec >= absl::kSpacePad2 ? ' ' : '0'),
237
        neg(v < 0) {}
238
};
239
240
// -----------------------------------------------------------------------------
241
// AlphaNum
242
// -----------------------------------------------------------------------------
243
//
244
// The `AlphaNum` class acts as the main parameter type for `StrCat()` and
245
// `StrAppend()`, providing efficient conversion of numeric, boolean, decimal,
246
// and hexadecimal values (through the `Dec` and `Hex` types) into strings.
247
// `AlphaNum` should only be used as a function parameter. Do not instantiate
248
//  `AlphaNum` directly as a stack variable.
249
250
class AlphaNum {
251
 public:
252
  // No bool ctor -- bools convert to an integral type.
253
  // A bool ctor would also convert incoming pointers (bletch).
254
255
  AlphaNum(int x)  // NOLINT(runtime/explicit)
256
      : piece_(digits_, static_cast<size_t>(
257
                            numbers_internal::FastIntToBuffer(x, digits_) -
258
0
                            &digits_[0])) {}
259
  AlphaNum(unsigned int x)  // NOLINT(runtime/explicit)
260
      : piece_(digits_, static_cast<size_t>(
261
                            numbers_internal::FastIntToBuffer(x, digits_) -
262
0
                            &digits_[0])) {}
263
  AlphaNum(long x)  // NOLINT(*)
264
      : piece_(digits_, static_cast<size_t>(
265
                            numbers_internal::FastIntToBuffer(x, digits_) -
266
0
                            &digits_[0])) {}
267
  AlphaNum(unsigned long x)  // NOLINT(*)
268
      : piece_(digits_, static_cast<size_t>(
269
                            numbers_internal::FastIntToBuffer(x, digits_) -
270
0
                            &digits_[0])) {}
271
  AlphaNum(long long x)  // NOLINT(*)
272
      : piece_(digits_, static_cast<size_t>(
273
                            numbers_internal::FastIntToBuffer(x, digits_) -
274
0
                            &digits_[0])) {}
275
  AlphaNum(unsigned long long x)  // NOLINT(*)
276
      : piece_(digits_, static_cast<size_t>(
277
                            numbers_internal::FastIntToBuffer(x, digits_) -
278
0
                            &digits_[0])) {}
279
280
  AlphaNum(float f)  // NOLINT(runtime/explicit)
281
0
      : piece_(digits_, numbers_internal::SixDigitsToBuffer(f, digits_)) {}
282
  AlphaNum(double f)  // NOLINT(runtime/explicit)
283
0
      : piece_(digits_, numbers_internal::SixDigitsToBuffer(f, digits_)) {}
284
285
  AlphaNum(Hex hex);  // NOLINT(runtime/explicit)
286
  AlphaNum(Dec dec);  // NOLINT(runtime/explicit)
287
288
  template <size_t size>
289
  AlphaNum(  // NOLINT(runtime/explicit)
290
      const strings_internal::AlphaNumBuffer<size>& buf)
291
      : piece_(&buf.data[0], buf.size) {}
292
293
  AlphaNum(const char* c_str)                     // NOLINT(runtime/explicit)
294
0
      : piece_(NullSafeStringView(c_str)) {}      // NOLINT(runtime/explicit)
295
0
  AlphaNum(absl::string_view pc) : piece_(pc) {}  // NOLINT(runtime/explicit)
296
297
  template <typename T, typename = typename std::enable_if<
298
                            strings_internal::HasAbslStringify<T>::value>::type>
299
  AlphaNum(                                         // NOLINT(runtime/explicit)
300
      const T& v,                                   // NOLINT(runtime/explicit)
301
      strings_internal::StringifySink&& sink = {})  // NOLINT(runtime/explicit)
302
      : piece_(strings_internal::ExtractStringification(sink, v)) {}
303
304
  template <typename Allocator>
305
  AlphaNum(  // NOLINT(runtime/explicit)
306
      const std::basic_string<char, std::char_traits<char>, Allocator>& str)
307
      : piece_(str) {}
308
309
  // Use string literals ":" instead of character literals ':'.
310
  AlphaNum(char c) = delete;  // NOLINT(runtime/explicit)
311
312
  AlphaNum(const AlphaNum&) = delete;
313
  AlphaNum& operator=(const AlphaNum&) = delete;
314
315
0
  absl::string_view::size_type size() const { return piece_.size(); }
316
0
  const char* data() const { return piece_.data(); }
317
0
  absl::string_view Piece() const { return piece_; }
318
319
  // Normal enums are already handled by the integer formatters.
320
  // This overload matches only scoped enums.
321
  template <typename T,
322
            typename = typename std::enable_if<
323
                std::is_enum<T>{} && !std::is_convertible<T, int>{} &&
324
                !strings_internal::HasAbslStringify<T>::value>::type>
325
  AlphaNum(T e)  // NOLINT(runtime/explicit)
326
      : AlphaNum(static_cast<typename std::underlying_type<T>::type>(e)) {}
327
328
  // vector<bool>::reference and const_reference require special help to
329
  // convert to `AlphaNum` because it requires two user defined conversions.
330
  template <
331
      typename T,
332
      typename std::enable_if<
333
          std::is_class<T>::value &&
334
          (std::is_same<T, std::vector<bool>::reference>::value ||
335
           std::is_same<T, std::vector<bool>::const_reference>::value)>::type* =
336
          nullptr>
337
  AlphaNum(T e) : AlphaNum(static_cast<bool>(e)) {}  // NOLINT(runtime/explicit)
338
339
 private:
340
  absl::string_view piece_;
341
  char digits_[numbers_internal::kFastToBufferSize];
342
};
343
344
// -----------------------------------------------------------------------------
345
// StrCat()
346
// -----------------------------------------------------------------------------
347
//
348
// Merges given strings or numbers, using no delimiter(s), returning the merged
349
// result as a string.
350
//
351
// `StrCat()` is designed to be the fastest possible way to construct a string
352
// out of a mix of raw C strings, string_views, strings, bool values,
353
// and numeric values.
354
//
355
// Don't use `StrCat()` for user-visible strings. The localization process
356
// works poorly on strings built up out of fragments.
357
//
358
// For clarity and performance, don't use `StrCat()` when appending to a
359
// string. Use `StrAppend()` instead. In particular, avoid using any of these
360
// (anti-)patterns:
361
//
362
//   str.append(StrCat(...))
363
//   str += StrCat(...)
364
//   str = StrCat(str, ...)
365
//
366
// The last case is the worst, with a potential to change a loop
367
// from a linear time operation with O(1) dynamic allocations into a
368
// quadratic time operation with O(n) dynamic allocations.
369
//
370
// See `StrAppend()` below for more information.
371
372
namespace strings_internal {
373
374
// Do not call directly - this is not part of the public API.
375
std::string CatPieces(std::initializer_list<absl::string_view> pieces);
376
void AppendPieces(std::string* dest,
377
                  std::initializer_list<absl::string_view> pieces);
378
379
}  // namespace strings_internal
380
381
0
ABSL_MUST_USE_RESULT inline std::string StrCat() { return std::string(); }
382
383
0
ABSL_MUST_USE_RESULT inline std::string StrCat(const AlphaNum& a) {
384
0
  return std::string(a.data(), a.size());
385
0
}
386
387
ABSL_MUST_USE_RESULT std::string StrCat(const AlphaNum& a, const AlphaNum& b);
388
ABSL_MUST_USE_RESULT std::string StrCat(const AlphaNum& a, const AlphaNum& b,
389
                                        const AlphaNum& c);
390
ABSL_MUST_USE_RESULT std::string StrCat(const AlphaNum& a, const AlphaNum& b,
391
                                        const AlphaNum& c, const AlphaNum& d);
392
393
// Support 5 or more arguments
394
template <typename... AV>
395
ABSL_MUST_USE_RESULT inline std::string StrCat(
396
    const AlphaNum& a, const AlphaNum& b, const AlphaNum& c, const AlphaNum& d,
397
    const AlphaNum& e, const AV&... args) {
398
  return strings_internal::CatPieces(
399
      {a.Piece(), b.Piece(), c.Piece(), d.Piece(), e.Piece(),
400
       static_cast<const AlphaNum&>(args).Piece()...});
401
}
402
403
// -----------------------------------------------------------------------------
404
// StrAppend()
405
// -----------------------------------------------------------------------------
406
//
407
// Appends a string or set of strings to an existing string, in a similar
408
// fashion to `StrCat()`.
409
//
410
// WARNING: `StrAppend(&str, a, b, c, ...)` requires that none of the
411
// a, b, c, parameters be a reference into str. For speed, `StrAppend()` does
412
// not try to check each of its input arguments to be sure that they are not
413
// a subset of the string being appended to. That is, while this will work:
414
//
415
//   std::string s = "foo";
416
//   s += s;
417
//
418
// This output is undefined:
419
//
420
//   std::string s = "foo";
421
//   StrAppend(&s, s);
422
//
423
// This output is undefined as well, since `absl::string_view` does not own its
424
// data:
425
//
426
//   std::string s = "foobar";
427
//   absl::string_view p = s;
428
//   StrAppend(&s, p);
429
430
0
inline void StrAppend(std::string*) {}
431
void StrAppend(std::string* dest, const AlphaNum& a);
432
void StrAppend(std::string* dest, const AlphaNum& a, const AlphaNum& b);
433
void StrAppend(std::string* dest, const AlphaNum& a, const AlphaNum& b,
434
               const AlphaNum& c);
435
void StrAppend(std::string* dest, const AlphaNum& a, const AlphaNum& b,
436
               const AlphaNum& c, const AlphaNum& d);
437
438
// Support 5 or more arguments
439
template <typename... AV>
440
inline void StrAppend(std::string* dest, const AlphaNum& a, const AlphaNum& b,
441
                      const AlphaNum& c, const AlphaNum& d, const AlphaNum& e,
442
                      const AV&... args) {
443
  strings_internal::AppendPieces(
444
      dest, {a.Piece(), b.Piece(), c.Piece(), d.Piece(), e.Piece(),
445
             static_cast<const AlphaNum&>(args).Piece()...});
446
}
447
448
// Helper function for the future StrCat default floating-point format, %.6g
449
// This is fast.
450
inline strings_internal::AlphaNumBuffer<
451
    numbers_internal::kSixDigitsToBufferSize>
452
0
SixDigits(double d) {
453
0
  strings_internal::AlphaNumBuffer<numbers_internal::kSixDigitsToBufferSize>
454
0
      result;
455
0
  result.size = numbers_internal::SixDigitsToBuffer(d, &result.data[0]);
456
0
  return result;
457
0
}
458
459
ABSL_NAMESPACE_END
460
}  // namespace absl
461
462
#endif  // ABSL_STRINGS_STR_CAT_H_