str_cat.h
Go to the documentation of this file.
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".
41 //
42 // Floating point numbers are formatted with six-digit precision, which is
43 // the default for "std::cout <<" or printf "%g" (the same as "%.6g").
44 //
45 // You can convert to hexadecimal output rather than decimal output using the
46 // `Hex` type contained here. To do so, pass `Hex(my_int)` as a parameter to
47 // `StrCat()` or `StrAppend()`. You may specify a minimum hex field width using
48 // a `PadSpec` enum.
49 //
50 // -----------------------------------------------------------------------------
51 
52 #ifndef ABSL_STRINGS_STR_CAT_H_
53 #define ABSL_STRINGS_STR_CAT_H_
54 
55 #include <array>
56 #include <cstdint>
57 #include <string>
58 #include <type_traits>
59 #include <vector>
60 
61 #include "absl/base/port.h"
62 #include "absl/strings/numbers.h"
64 
65 namespace absl {
66 
67 namespace strings_internal {
68 // AlphaNumBuffer allows a way to pass a string to StrCat without having to do
69 // memory allocation. It is simply a pair of a fixed-size character array, and
70 // a size. Please don't use outside of absl, yet.
71 template <size_t max_size>
73  std::array<char, max_size> data;
74  size_t size;
75 };
76 
77 } // namespace strings_internal
78 
79 // Enum that specifies the number of significant digits to return in a `Hex` or
80 // `Dec` conversion and fill character to use. A `kZeroPad2` value, for example,
81 // would produce hexadecimal strings such as "0a","0f" and a 'kSpacePad5' value
82 // would produce hexadecimal strings such as " a"," f".
83 enum PadSpec : uint8_t {
84  kNoPad = 1,
104 
124 };
125 
126 // -----------------------------------------------------------------------------
127 // Hex
128 // -----------------------------------------------------------------------------
129 //
130 // `Hex` stores a set of hexadecimal string conversion parameters for use
131 // within `AlphaNum` string conversions.
132 struct Hex {
133  uint64_t value;
134  uint8_t width;
135  char fill;
136 
137  template <typename Int>
138  explicit Hex(
139  Int v, PadSpec spec = absl::kNoPad,
140  typename std::enable_if<sizeof(Int) == 1 &&
141  !std::is_pointer<Int>::value>::type* = nullptr)
142  : Hex(spec, static_cast<uint8_t>(v)) {}
143  template <typename Int>
144  explicit Hex(
145  Int v, PadSpec spec = absl::kNoPad,
146  typename std::enable_if<sizeof(Int) == 2 &&
147  !std::is_pointer<Int>::value>::type* = nullptr)
148  : Hex(spec, static_cast<uint16_t>(v)) {}
149  template <typename Int>
150  explicit Hex(
151  Int v, PadSpec spec = absl::kNoPad,
152  typename std::enable_if<sizeof(Int) == 4 &&
153  !std::is_pointer<Int>::value>::type* = nullptr)
154  : Hex(spec, static_cast<uint32_t>(v)) {}
155  template <typename Int>
156  explicit Hex(
157  Int v, PadSpec spec = absl::kNoPad,
158  typename std::enable_if<sizeof(Int) == 8 &&
159  !std::is_pointer<Int>::value>::type* = nullptr)
160  : Hex(spec, static_cast<uint64_t>(v)) {}
161  template <typename Pointee>
162  explicit Hex(Pointee* v, PadSpec spec = absl::kNoPad)
163  : Hex(spec, reinterpret_cast<uintptr_t>(v)) {}
164 
165  private:
166  Hex(PadSpec spec, uint64_t v)
167  : value(v),
168  width(spec == absl::kNoPad
169  ? 1
170  : spec >= absl::kSpacePad2 ? spec - absl::kSpacePad2 + 2
171  : spec - absl::kZeroPad2 + 2),
172  fill(spec >= absl::kSpacePad2 ? ' ' : '0') {}
173 };
174 
175 // -----------------------------------------------------------------------------
176 // Dec
177 // -----------------------------------------------------------------------------
178 //
179 // `Dec` stores a set of decimal string conversion parameters for use
180 // within `AlphaNum` string conversions. Dec is slower than the default
181 // integer conversion, so use it only if you need padding.
182 struct Dec {
183  uint64_t value;
184  uint8_t width;
185  char fill;
186  bool neg;
187 
188  template <typename Int>
189  explicit Dec(Int v, PadSpec spec = absl::kNoPad,
190  typename std::enable_if<(sizeof(Int) <= 8)>::type* = nullptr)
191  : value(v >= 0 ? static_cast<uint64_t>(v)
192  : uint64_t{0} - static_cast<uint64_t>(v)),
193  width(spec == absl::kNoPad
194  ? 1
195  : spec >= absl::kSpacePad2 ? spec - absl::kSpacePad2 + 2
196  : spec - absl::kZeroPad2 + 2),
197  fill(spec >= absl::kSpacePad2 ? ' ' : '0'),
198  neg(v < 0) {}
199 };
200 
201 // -----------------------------------------------------------------------------
202 // AlphaNum
203 // -----------------------------------------------------------------------------
204 //
205 // The `AlphaNum` class acts as the main parameter type for `StrCat()` and
206 // `StrAppend()`, providing efficient conversion of numeric, boolean, and
207 // hexadecimal values (through the `Hex` type) into strings.
208 
209 class AlphaNum {
210  public:
211  // No bool ctor -- bools convert to an integral type.
212  // A bool ctor would also convert incoming pointers (bletch).
213 
214  AlphaNum(int x) // NOLINT(runtime/explicit)
215  : piece_(digits_,
216  numbers_internal::FastIntToBuffer(x, digits_) - &digits_[0]) {}
217  AlphaNum(unsigned int x) // NOLINT(runtime/explicit)
218  : piece_(digits_,
219  numbers_internal::FastIntToBuffer(x, digits_) - &digits_[0]) {}
220  AlphaNum(long x) // NOLINT(*)
221  : piece_(digits_,
222  numbers_internal::FastIntToBuffer(x, digits_) - &digits_[0]) {}
223  AlphaNum(unsigned long x) // NOLINT(*)
224  : piece_(digits_,
225  numbers_internal::FastIntToBuffer(x, digits_) - &digits_[0]) {}
226  AlphaNum(long long x) // NOLINT(*)
227  : piece_(digits_,
228  numbers_internal::FastIntToBuffer(x, digits_) - &digits_[0]) {}
229  AlphaNum(unsigned long long x) // NOLINT(*)
230  : piece_(digits_,
231  numbers_internal::FastIntToBuffer(x, digits_) - &digits_[0]) {}
232 
233  AlphaNum(float f) // NOLINT(runtime/explicit)
234  : piece_(digits_, numbers_internal::SixDigitsToBuffer(f, digits_)) {}
235  AlphaNum(double f) // NOLINT(runtime/explicit)
236  : piece_(digits_, numbers_internal::SixDigitsToBuffer(f, digits_)) {}
237 
238  AlphaNum(Hex hex); // NOLINT(runtime/explicit)
239  AlphaNum(Dec dec); // NOLINT(runtime/explicit)
240 
241  template <size_t size>
242  AlphaNum( // NOLINT(runtime/explicit)
244  : piece_(&buf.data[0], buf.size) {}
245 
246  AlphaNum(const char* c_str) : piece_(c_str) {} // NOLINT(runtime/explicit)
247  AlphaNum(absl::string_view pc) : piece_(pc) {} // NOLINT(runtime/explicit)
248 
249  template <typename Allocator>
250  AlphaNum( // NOLINT(runtime/explicit)
251  const std::basic_string<char, std::char_traits<char>, Allocator>& str)
252  : piece_(str) {}
253 
254  // Use std::string literals ":" instead of character literals ':'.
255  AlphaNum(char c) = delete; // NOLINT(runtime/explicit)
256 
257  AlphaNum(const AlphaNum&) = delete;
258  AlphaNum& operator=(const AlphaNum&) = delete;
259 
260  absl::string_view::size_type size() const { return piece_.size(); }
261  const char* data() const { return piece_.data(); }
262  absl::string_view Piece() const { return piece_; }
263 
264  // Normal enums are already handled by the integer formatters.
265  // This overload matches only scoped enums.
266  template <typename T,
267  typename = typename std::enable_if<
268  std::is_enum<T>{} && !std::is_convertible<T, int>{}>::type>
269  AlphaNum(T e) // NOLINT(runtime/explicit)
270  : AlphaNum(static_cast<typename std::underlying_type<T>::type>(e)) {}
271 
272  // vector<bool>::reference and const_reference require special help to
273  // convert to `AlphaNum` because it requires two user defined conversions.
274  template <
275  typename T,
276  typename std::enable_if<
278  (std::is_same<T, std::vector<bool>::reference>::value ||
279  std::is_same<T, std::vector<bool>::const_reference>::value)>::type* =
280  nullptr>
281  AlphaNum(T e) : AlphaNum(static_cast<bool>(e)) {} // NOLINT(runtime/explicit)
282 
283  private:
286 };
287 
288 // -----------------------------------------------------------------------------
289 // StrCat()
290 // -----------------------------------------------------------------------------
291 //
292 // Merges given strings or numbers, using no delimiter(s).
293 //
294 // `StrCat()` is designed to be the fastest possible way to construct a string
295 // out of a mix of raw C strings, string_views, strings, bool values,
296 // and numeric values.
297 //
298 // Don't use `StrCat()` for user-visible strings. The localization process
299 // works poorly on strings built up out of fragments.
300 //
301 // For clarity and performance, don't use `StrCat()` when appending to a
302 // string. Use `StrAppend()` instead. In particular, avoid using any of these
303 // (anti-)patterns:
304 //
305 // str.append(StrCat(...))
306 // str += StrCat(...)
307 // str = StrCat(str, ...)
308 //
309 // The last case is the worst, with a potential to change a loop
310 // from a linear time operation with O(1) dynamic allocations into a
311 // quadratic time operation with O(n) dynamic allocations.
312 //
313 // See `StrAppend()` below for more information.
314 
315 namespace strings_internal {
316 
317 // Do not call directly - this is not part of the public API.
318 std::string CatPieces(std::initializer_list<absl::string_view> pieces);
319 void AppendPieces(std::string* dest,
320  std::initializer_list<absl::string_view> pieces);
321 
322 } // namespace strings_internal
323 
324 ABSL_MUST_USE_RESULT inline std::string StrCat() { return std::string(); }
325 
326 ABSL_MUST_USE_RESULT inline std::string StrCat(const AlphaNum& a) {
327  return std::string(a.data(), a.size());
328 }
329 
330 ABSL_MUST_USE_RESULT std::string StrCat(const AlphaNum& a, const AlphaNum& b);
331 ABSL_MUST_USE_RESULT std::string StrCat(const AlphaNum& a, const AlphaNum& b,
332  const AlphaNum& c);
333 ABSL_MUST_USE_RESULT std::string StrCat(const AlphaNum& a, const AlphaNum& b,
334  const AlphaNum& c, const AlphaNum& d);
335 
336 // Support 5 or more arguments
337 template <typename... AV>
338 ABSL_MUST_USE_RESULT inline std::string StrCat(
339  const AlphaNum& a, const AlphaNum& b, const AlphaNum& c, const AlphaNum& d,
340  const AlphaNum& e, const AV&... args) {
342  {a.Piece(), b.Piece(), c.Piece(), d.Piece(), e.Piece(),
343  static_cast<const AlphaNum&>(args).Piece()...});
344 }
345 
346 // -----------------------------------------------------------------------------
347 // StrAppend()
348 // -----------------------------------------------------------------------------
349 //
350 // Appends a string or set of strings to an existing string, in a similar
351 // fashion to `StrCat()`.
352 //
353 // WARNING: `StrAppend(&str, a, b, c, ...)` requires that none of the
354 // a, b, c, parameters be a reference into str. For speed, `StrAppend()` does
355 // not try to check each of its input arguments to be sure that they are not
356 // a subset of the string being appended to. That is, while this will work:
357 //
358 // std::string s = "foo";
359 // s += s;
360 //
361 // This output is undefined:
362 //
363 // std::string s = "foo";
364 // StrAppend(&s, s);
365 //
366 // This output is undefined as well, since `absl::string_view` does not own its
367 // data:
368 //
369 // std::string s = "foobar";
370 // absl::string_view p = s;
371 // StrAppend(&s, p);
372 
373 inline void StrAppend(std::string*) {}
374 void StrAppend(std::string* dest, const AlphaNum& a);
375 void StrAppend(std::string* dest, const AlphaNum& a, const AlphaNum& b);
376 void StrAppend(std::string* dest, const AlphaNum& a, const AlphaNum& b,
377  const AlphaNum& c);
378 void StrAppend(std::string* dest, const AlphaNum& a, const AlphaNum& b,
379  const AlphaNum& c, const AlphaNum& d);
380 
381 // Support 5 or more arguments
382 template <typename... AV>
383 inline void StrAppend(std::string* dest, const AlphaNum& a, const AlphaNum& b,
384  const AlphaNum& c, const AlphaNum& d, const AlphaNum& e,
385  const AV&... args) {
387  dest, {a.Piece(), b.Piece(), c.Piece(), d.Piece(), e.Piece(),
388  static_cast<const AlphaNum&>(args).Piece()...});
389 }
390 
391 // Helper function for the future StrCat default floating-point format, %.6g
392 // This is fast.
395 SixDigits(double d) {
397  result;
398  result.size = numbers_internal::SixDigitsToBuffer(d, &result.data[0]);
399  return result;
400 }
401 
402 } // namespace absl
403 
404 #endif // ABSL_STRINGS_STR_CAT_H_
int v
Definition: variant_test.cc:81
PadSpec
Definition: str_cat.h:83
bool neg
Definition: str_cat.h:186
uint8_t width
Definition: str_cat.h:134
AlphaNum(const char *c_str)
Definition: str_cat.h:246
char * FastIntToBuffer(int32_t, char *)
Definition: numbers.cc:241
void StrAppend(std::string *dest, const AlphaNum &a)
Definition: str_cat.cc:193
Hex(Int v, PadSpec spec=absl::kNoPad, typename std::enable_if< sizeof(Int)==1 &&!std::is_pointer< Int >::value >::type *=nullptr)
Definition: str_cat.h:138
char fill
Definition: str_cat.h:135
AlphaNum(long x)
Definition: str_cat.h:220
uint64_t value
Definition: str_cat.h:133
size_t SixDigitsToBuffer(double d, char *buffer)
Definition: numbers.cc:510
std::array< char, max_size > data
Definition: str_cat.h:73
AlphaNum(const strings_internal::AlphaNumBuffer< size > &buf)
Definition: str_cat.h:242
std::string StrCat(const AlphaNum &a, const AlphaNum &b)
Definition: str_cat.cc:98
uint8_t width
Definition: str_cat.h:184
AlphaNum(int x)
Definition: str_cat.h:214
int fill
std::string CatPieces(std::initializer_list< absl::string_view > pieces)
Definition: str_cat.cc:141
AlphaNum(unsigned long long x)
Definition: str_cat.h:229
char buf[N]
AlphaNum(absl::string_view pc)
Definition: str_cat.h:247
Definition: algorithm.h:29
uint64_t value
Definition: str_cat.h:183
strings_internal::AlphaNumBuffer< numbers_internal::kSixDigitsToBufferSize > SixDigits(double d)
Definition: str_cat.h:395
absl::string_view Piece() const
Definition: str_cat.h:262
Dec(Int v, PadSpec spec=absl::kNoPad, typename std::enable_if<(sizeof(Int)<=8)>::type *=nullptr)
Definition: str_cat.h:189
size_t value
Hex(PadSpec spec, uint64_t v)
Definition: str_cat.h:166
#define ABSL_MUST_USE_RESULT
Definition: attributes.h:449
const char * data() const
Definition: str_cat.h:261
Hex(Pointee *v, PadSpec spec=absl::kNoPad)
Definition: str_cat.h:162
AlphaNum(float f)
Definition: str_cat.h:233
absl::string_view piece_
Definition: str_cat.h:284
AlphaNum(double f)
Definition: str_cat.h:235
static const int kSixDigitsToBufferSize
Definition: numbers.h:94
Hex(Int v, PadSpec spec=absl::kNoPad, typename std::enable_if< sizeof(Int)==4 &&!std::is_pointer< Int >::value >::type *=nullptr)
Definition: str_cat.h:150
Hex(Int v, PadSpec spec=absl::kNoPad, typename std::enable_if< sizeof(Int)==2 &&!std::is_pointer< Int >::value >::type *=nullptr)
Definition: str_cat.h:144
AlphaNum(T e)
Definition: str_cat.h:269
AlphaNum(const std::basic_string< char, std::char_traits< char >, Allocator > &str)
Definition: str_cat.h:250
absl::string_view::size_type size() const
Definition: str_cat.h:260
AlphaNum(unsigned int x)
Definition: str_cat.h:217
static const int kFastToBufferSize
Definition: numbers.h:93
uint64_t b
Definition: layout_test.cc:50
char fill
Definition: str_cat.h:185
AlphaNum(long long x)
Definition: str_cat.h:226
void AppendPieces(std::string *dest, std::initializer_list< absl::string_view > pieces)
Definition: str_cat.cc:169
Hex(Int v, PadSpec spec=absl::kNoPad, typename std::enable_if< sizeof(Int)==8 &&!std::is_pointer< Int >::value >::type *=nullptr)
Definition: str_cat.h:156
AlphaNum(unsigned long x)
Definition: str_cat.h:223


abseil_cpp
Author(s):
autogenerated on Wed Jun 19 2019 19:19:58