str_cat.h 17 KB

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