You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

str_cat.h 17 kB

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