str_cat.h
Go to the documentation of this file.
00001 //
00002 // Copyright 2017 The Abseil Authors.
00003 //
00004 // Licensed under the Apache License, Version 2.0 (the "License");
00005 // you may not use this file except in compliance with the License.
00006 // You may obtain a copy of the License at
00007 //
00008 //      https://www.apache.org/licenses/LICENSE-2.0
00009 //
00010 // Unless required by applicable law or agreed to in writing, software
00011 // distributed under the License is distributed on an "AS IS" BASIS,
00012 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013 // See the License for the specific language governing permissions and
00014 // limitations under the License.
00015 //
00016 // -----------------------------------------------------------------------------
00017 // File: str_cat.h
00018 // -----------------------------------------------------------------------------
00019 //
00020 // This package contains functions for efficiently concatenating and appending
00021 // strings: `StrCat()` and `StrAppend()`. Most of the work within these routines
00022 // is actually handled through use of a special AlphaNum type, which was
00023 // designed to be used as a parameter type that efficiently manages conversion
00024 // to strings and avoids copies in the above operations.
00025 //
00026 // Any routine accepting either a string or a number may accept `AlphaNum`.
00027 // The basic idea is that by accepting a `const AlphaNum &` as an argument
00028 // to your function, your callers will automagically convert bools, integers,
00029 // and floating point values to strings for you.
00030 //
00031 // NOTE: Use of `AlphaNum` outside of the //absl/strings package is unsupported
00032 // except for the specific case of function parameters of type `AlphaNum` or
00033 // `const AlphaNum &`. In particular, instantiating `AlphaNum` directly as a
00034 // stack variable is not supported.
00035 //
00036 // Conversion from 8-bit values is not accepted because, if it were, then an
00037 // attempt to pass ':' instead of ":" might result in a 58 ending up in your
00038 // result.
00039 //
00040 // Bools convert to "0" or "1".
00041 //
00042 // Floating point numbers are formatted with six-digit precision, which is
00043 // the default for "std::cout <<" or printf "%g" (the same as "%.6g").
00044 //
00045 // You can convert to hexadecimal output rather than decimal output using the
00046 // `Hex` type contained here. To do so, pass `Hex(my_int)` as a parameter to
00047 // `StrCat()` or `StrAppend()`. You may specify a minimum hex field width using
00048 // a `PadSpec` enum.
00049 //
00050 // -----------------------------------------------------------------------------
00051 
00052 #ifndef ABSL_STRINGS_STR_CAT_H_
00053 #define ABSL_STRINGS_STR_CAT_H_
00054 
00055 #include <array>
00056 #include <cstdint>
00057 #include <string>
00058 #include <type_traits>
00059 #include <vector>
00060 
00061 #include "absl/base/port.h"
00062 #include "absl/strings/numbers.h"
00063 #include "absl/strings/string_view.h"
00064 
00065 namespace absl {
00066 
00067 namespace strings_internal {
00068 // AlphaNumBuffer allows a way to pass a string to StrCat without having to do
00069 // memory allocation.  It is simply a pair of a fixed-size character array, and
00070 // a size.  Please don't use outside of absl, yet.
00071 template <size_t max_size>
00072 struct AlphaNumBuffer {
00073   std::array<char, max_size> data;
00074   size_t size;
00075 };
00076 
00077 }  // namespace strings_internal
00078 
00079 // Enum that specifies the number of significant digits to return in a `Hex` or
00080 // `Dec` conversion and fill character to use. A `kZeroPad2` value, for example,
00081 // would produce hexadecimal strings such as "0a","0f" and a 'kSpacePad5' value
00082 // would produce hexadecimal strings such as "    a","    f".
00083 enum PadSpec : uint8_t {
00084   kNoPad = 1,
00085   kZeroPad2,
00086   kZeroPad3,
00087   kZeroPad4,
00088   kZeroPad5,
00089   kZeroPad6,
00090   kZeroPad7,
00091   kZeroPad8,
00092   kZeroPad9,
00093   kZeroPad10,
00094   kZeroPad11,
00095   kZeroPad12,
00096   kZeroPad13,
00097   kZeroPad14,
00098   kZeroPad15,
00099   kZeroPad16,
00100   kZeroPad17,
00101   kZeroPad18,
00102   kZeroPad19,
00103   kZeroPad20,
00104 
00105   kSpacePad2 = kZeroPad2 + 64,
00106   kSpacePad3,
00107   kSpacePad4,
00108   kSpacePad5,
00109   kSpacePad6,
00110   kSpacePad7,
00111   kSpacePad8,
00112   kSpacePad9,
00113   kSpacePad10,
00114   kSpacePad11,
00115   kSpacePad12,
00116   kSpacePad13,
00117   kSpacePad14,
00118   kSpacePad15,
00119   kSpacePad16,
00120   kSpacePad17,
00121   kSpacePad18,
00122   kSpacePad19,
00123   kSpacePad20,
00124 };
00125 
00126 // -----------------------------------------------------------------------------
00127 // Hex
00128 // -----------------------------------------------------------------------------
00129 //
00130 // `Hex` stores a set of hexadecimal string conversion parameters for use
00131 // within `AlphaNum` string conversions.
00132 struct Hex {
00133   uint64_t value;
00134   uint8_t width;
00135   char fill;
00136 
00137   template <typename Int>
00138   explicit Hex(
00139       Int v, PadSpec spec = absl::kNoPad,
00140       typename std::enable_if<sizeof(Int) == 1 &&
00141                               !std::is_pointer<Int>::value>::type* = nullptr)
00142       : Hex(spec, static_cast<uint8_t>(v)) {}
00143   template <typename Int>
00144   explicit Hex(
00145       Int v, PadSpec spec = absl::kNoPad,
00146       typename std::enable_if<sizeof(Int) == 2 &&
00147                               !std::is_pointer<Int>::value>::type* = nullptr)
00148       : Hex(spec, static_cast<uint16_t>(v)) {}
00149   template <typename Int>
00150   explicit Hex(
00151       Int v, PadSpec spec = absl::kNoPad,
00152       typename std::enable_if<sizeof(Int) == 4 &&
00153                               !std::is_pointer<Int>::value>::type* = nullptr)
00154       : Hex(spec, static_cast<uint32_t>(v)) {}
00155   template <typename Int>
00156   explicit Hex(
00157       Int v, PadSpec spec = absl::kNoPad,
00158       typename std::enable_if<sizeof(Int) == 8 &&
00159                               !std::is_pointer<Int>::value>::type* = nullptr)
00160       : Hex(spec, static_cast<uint64_t>(v)) {}
00161   template <typename Pointee>
00162   explicit Hex(Pointee* v, PadSpec spec = absl::kNoPad)
00163       : Hex(spec, reinterpret_cast<uintptr_t>(v)) {}
00164 
00165  private:
00166   Hex(PadSpec spec, uint64_t v)
00167       : value(v),
00168         width(spec == absl::kNoPad
00169                   ? 1
00170                   : spec >= absl::kSpacePad2 ? spec - absl::kSpacePad2 + 2
00171                                              : spec - absl::kZeroPad2 + 2),
00172         fill(spec >= absl::kSpacePad2 ? ' ' : '0') {}
00173 };
00174 
00175 // -----------------------------------------------------------------------------
00176 // Dec
00177 // -----------------------------------------------------------------------------
00178 //
00179 // `Dec` stores a set of decimal string conversion parameters for use
00180 // within `AlphaNum` string conversions.  Dec is slower than the default
00181 // integer conversion, so use it only if you need padding.
00182 struct Dec {
00183   uint64_t value;
00184   uint8_t width;
00185   char fill;
00186   bool neg;
00187 
00188   template <typename Int>
00189   explicit Dec(Int v, PadSpec spec = absl::kNoPad,
00190                typename std::enable_if<(sizeof(Int) <= 8)>::type* = nullptr)
00191       : value(v >= 0 ? static_cast<uint64_t>(v)
00192                      : uint64_t{0} - static_cast<uint64_t>(v)),
00193         width(spec == absl::kNoPad
00194                   ? 1
00195                   : spec >= absl::kSpacePad2 ? spec - absl::kSpacePad2 + 2
00196                                              : spec - absl::kZeroPad2 + 2),
00197         fill(spec >= absl::kSpacePad2 ? ' ' : '0'),
00198         neg(v < 0) {}
00199 };
00200 
00201 // -----------------------------------------------------------------------------
00202 // AlphaNum
00203 // -----------------------------------------------------------------------------
00204 //
00205 // The `AlphaNum` class acts as the main parameter type for `StrCat()` and
00206 // `StrAppend()`, providing efficient conversion of numeric, boolean, and
00207 // hexadecimal values (through the `Hex` type) into strings.
00208 
00209 class AlphaNum {
00210  public:
00211   // No bool ctor -- bools convert to an integral type.
00212   // A bool ctor would also convert incoming pointers (bletch).
00213 
00214   AlphaNum(int x)  // NOLINT(runtime/explicit)
00215       : piece_(digits_,
00216                numbers_internal::FastIntToBuffer(x, digits_) - &digits_[0]) {}
00217   AlphaNum(unsigned int x)  // NOLINT(runtime/explicit)
00218       : piece_(digits_,
00219                numbers_internal::FastIntToBuffer(x, digits_) - &digits_[0]) {}
00220   AlphaNum(long x)  // NOLINT(*)
00221       : piece_(digits_,
00222                numbers_internal::FastIntToBuffer(x, digits_) - &digits_[0]) {}
00223   AlphaNum(unsigned long x)  // NOLINT(*)
00224       : piece_(digits_,
00225                numbers_internal::FastIntToBuffer(x, digits_) - &digits_[0]) {}
00226   AlphaNum(long long x)  // NOLINT(*)
00227       : piece_(digits_,
00228                numbers_internal::FastIntToBuffer(x, digits_) - &digits_[0]) {}
00229   AlphaNum(unsigned long long x)  // NOLINT(*)
00230       : piece_(digits_,
00231                numbers_internal::FastIntToBuffer(x, digits_) - &digits_[0]) {}
00232 
00233   AlphaNum(float f)  // NOLINT(runtime/explicit)
00234       : piece_(digits_, numbers_internal::SixDigitsToBuffer(f, digits_)) {}
00235   AlphaNum(double f)  // NOLINT(runtime/explicit)
00236       : piece_(digits_, numbers_internal::SixDigitsToBuffer(f, digits_)) {}
00237 
00238   AlphaNum(Hex hex);  // NOLINT(runtime/explicit)
00239   AlphaNum(Dec dec);  // NOLINT(runtime/explicit)
00240 
00241   template <size_t size>
00242   AlphaNum(  // NOLINT(runtime/explicit)
00243       const strings_internal::AlphaNumBuffer<size>& buf)
00244       : piece_(&buf.data[0], buf.size) {}
00245 
00246   AlphaNum(const char* c_str) : piece_(c_str) {}  // NOLINT(runtime/explicit)
00247   AlphaNum(absl::string_view pc) : piece_(pc) {}  // NOLINT(runtime/explicit)
00248 
00249   template <typename Allocator>
00250   AlphaNum(  // NOLINT(runtime/explicit)
00251       const std::basic_string<char, std::char_traits<char>, Allocator>& str)
00252       : piece_(str) {}
00253 
00254   // Use std::string literals ":" instead of character literals ':'.
00255   AlphaNum(char c) = delete;  // NOLINT(runtime/explicit)
00256 
00257   AlphaNum(const AlphaNum&) = delete;
00258   AlphaNum& operator=(const AlphaNum&) = delete;
00259 
00260   absl::string_view::size_type size() const { return piece_.size(); }
00261   const char* data() const { return piece_.data(); }
00262   absl::string_view Piece() const { return piece_; }
00263 
00264   // Normal enums are already handled by the integer formatters.
00265   // This overload matches only scoped enums.
00266   template <typename T,
00267             typename = typename std::enable_if<
00268                 std::is_enum<T>{} && !std::is_convertible<T, int>{}>::type>
00269   AlphaNum(T e)  // NOLINT(runtime/explicit)
00270       : AlphaNum(static_cast<typename std::underlying_type<T>::type>(e)) {}
00271 
00272   // vector<bool>::reference and const_reference require special help to
00273   // convert to `AlphaNum` because it requires two user defined conversions.
00274   template <
00275       typename T,
00276       typename std::enable_if<
00277           std::is_class<T>::value &&
00278           (std::is_same<T, std::vector<bool>::reference>::value ||
00279            std::is_same<T, std::vector<bool>::const_reference>::value)>::type* =
00280           nullptr>
00281   AlphaNum(T e) : AlphaNum(static_cast<bool>(e)) {}  // NOLINT(runtime/explicit)
00282 
00283  private:
00284   absl::string_view piece_;
00285   char digits_[numbers_internal::kFastToBufferSize];
00286 };
00287 
00288 // -----------------------------------------------------------------------------
00289 // StrCat()
00290 // -----------------------------------------------------------------------------
00291 //
00292 // Merges given strings or numbers, using no delimiter(s).
00293 //
00294 // `StrCat()` is designed to be the fastest possible way to construct a string
00295 // out of a mix of raw C strings, string_views, strings, bool values,
00296 // and numeric values.
00297 //
00298 // Don't use `StrCat()` for user-visible strings. The localization process
00299 // works poorly on strings built up out of fragments.
00300 //
00301 // For clarity and performance, don't use `StrCat()` when appending to a
00302 // string. Use `StrAppend()` instead. In particular, avoid using any of these
00303 // (anti-)patterns:
00304 //
00305 //   str.append(StrCat(...))
00306 //   str += StrCat(...)
00307 //   str = StrCat(str, ...)
00308 //
00309 // The last case is the worst, with a potential to change a loop
00310 // from a linear time operation with O(1) dynamic allocations into a
00311 // quadratic time operation with O(n) dynamic allocations.
00312 //
00313 // See `StrAppend()` below for more information.
00314 
00315 namespace strings_internal {
00316 
00317 // Do not call directly - this is not part of the public API.
00318 std::string CatPieces(std::initializer_list<absl::string_view> pieces);
00319 void AppendPieces(std::string* dest,
00320                   std::initializer_list<absl::string_view> pieces);
00321 
00322 }  // namespace strings_internal
00323 
00324 ABSL_MUST_USE_RESULT inline std::string StrCat() { return std::string(); }
00325 
00326 ABSL_MUST_USE_RESULT inline std::string StrCat(const AlphaNum& a) {
00327   return std::string(a.data(), a.size());
00328 }
00329 
00330 ABSL_MUST_USE_RESULT std::string StrCat(const AlphaNum& a, const AlphaNum& b);
00331 ABSL_MUST_USE_RESULT std::string StrCat(const AlphaNum& a, const AlphaNum& b,
00332                                         const AlphaNum& c);
00333 ABSL_MUST_USE_RESULT std::string StrCat(const AlphaNum& a, const AlphaNum& b,
00334                                         const AlphaNum& c, const AlphaNum& d);
00335 
00336 // Support 5 or more arguments
00337 template <typename... AV>
00338 ABSL_MUST_USE_RESULT inline std::string StrCat(
00339     const AlphaNum& a, const AlphaNum& b, const AlphaNum& c, const AlphaNum& d,
00340     const AlphaNum& e, const AV&... args) {
00341   return strings_internal::CatPieces(
00342       {a.Piece(), b.Piece(), c.Piece(), d.Piece(), e.Piece(),
00343        static_cast<const AlphaNum&>(args).Piece()...});
00344 }
00345 
00346 // -----------------------------------------------------------------------------
00347 // StrAppend()
00348 // -----------------------------------------------------------------------------
00349 //
00350 // Appends a string or set of strings to an existing string, in a similar
00351 // fashion to `StrCat()`.
00352 //
00353 // WARNING: `StrAppend(&str, a, b, c, ...)` requires that none of the
00354 // a, b, c, parameters be a reference into str. For speed, `StrAppend()` does
00355 // not try to check each of its input arguments to be sure that they are not
00356 // a subset of the string being appended to. That is, while this will work:
00357 //
00358 //   std::string s = "foo";
00359 //   s += s;
00360 //
00361 // This output is undefined:
00362 //
00363 //   std::string s = "foo";
00364 //   StrAppend(&s, s);
00365 //
00366 // This output is undefined as well, since `absl::string_view` does not own its
00367 // data:
00368 //
00369 //   std::string s = "foobar";
00370 //   absl::string_view p = s;
00371 //   StrAppend(&s, p);
00372 
00373 inline void StrAppend(std::string*) {}
00374 void StrAppend(std::string* dest, const AlphaNum& a);
00375 void StrAppend(std::string* dest, const AlphaNum& a, const AlphaNum& b);
00376 void StrAppend(std::string* dest, const AlphaNum& a, const AlphaNum& b,
00377                const AlphaNum& c);
00378 void StrAppend(std::string* dest, const AlphaNum& a, const AlphaNum& b,
00379                const AlphaNum& c, const AlphaNum& d);
00380 
00381 // Support 5 or more arguments
00382 template <typename... AV>
00383 inline void StrAppend(std::string* dest, const AlphaNum& a, const AlphaNum& b,
00384                       const AlphaNum& c, const AlphaNum& d, const AlphaNum& e,
00385                       const AV&... args) {
00386   strings_internal::AppendPieces(
00387       dest, {a.Piece(), b.Piece(), c.Piece(), d.Piece(), e.Piece(),
00388              static_cast<const AlphaNum&>(args).Piece()...});
00389 }
00390 
00391 // Helper function for the future StrCat default floating-point format, %.6g
00392 // This is fast.
00393 inline strings_internal::AlphaNumBuffer<
00394     numbers_internal::kSixDigitsToBufferSize>
00395 SixDigits(double d) {
00396   strings_internal::AlphaNumBuffer<numbers_internal::kSixDigitsToBufferSize>
00397       result;
00398   result.size = numbers_internal::SixDigitsToBuffer(d, &result.data[0]);
00399   return result;
00400 }
00401 
00402 }  // namespace absl
00403 
00404 #endif  // ABSL_STRINGS_STR_CAT_H_


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