str_cat.cc 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336
  1. // Copyright 2017 The Abseil Authors.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // https://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. #include "absl/strings/str_cat.h"
  15. #include <assert.h>
  16. #include <cstddef>
  17. #include <cstdint>
  18. #include <cstring>
  19. #include <initializer_list>
  20. #include <string>
  21. #include <type_traits>
  22. #include "absl/base/config.h"
  23. #include "absl/base/nullability.h"
  24. #include "absl/strings/internal/resize_uninitialized.h"
  25. #include "absl/strings/numbers.h"
  26. #include "absl/strings/string_view.h"
  27. namespace absl {
  28. ABSL_NAMESPACE_BEGIN
  29. // ----------------------------------------------------------------------
  30. // StrCat()
  31. // This merges the given strings or integers, with no delimiter. This
  32. // is designed to be the fastest possible way to construct a string out
  33. // of a mix of raw C strings, string_views, strings, and integer values.
  34. // ----------------------------------------------------------------------
  35. namespace {
  36. // Append is merely a version of memcpy that returns the address of the byte
  37. // after the area just overwritten.
  38. absl::Nonnull<char*> Append(absl::Nonnull<char*> out, const AlphaNum& x) {
  39. // memcpy is allowed to overwrite arbitrary memory, so doing this after the
  40. // call would force an extra fetch of x.size().
  41. char* after = out + x.size();
  42. if (x.size() != 0) {
  43. memcpy(out, x.data(), x.size());
  44. }
  45. return after;
  46. }
  47. } // namespace
  48. std::string StrCat(const AlphaNum& a, const AlphaNum& b) {
  49. std::string result;
  50. absl::strings_internal::STLStringResizeUninitialized(&result,
  51. a.size() + b.size());
  52. char* const begin = &result[0];
  53. char* out = begin;
  54. out = Append(out, a);
  55. out = Append(out, b);
  56. assert(out == begin + result.size());
  57. return result;
  58. }
  59. std::string StrCat(const AlphaNum& a, const AlphaNum& b, const AlphaNum& c) {
  60. std::string result;
  61. strings_internal::STLStringResizeUninitialized(
  62. &result, a.size() + b.size() + c.size());
  63. char* const begin = &result[0];
  64. char* out = begin;
  65. out = Append(out, a);
  66. out = Append(out, b);
  67. out = Append(out, c);
  68. assert(out == begin + result.size());
  69. return result;
  70. }
  71. std::string StrCat(const AlphaNum& a, const AlphaNum& b, const AlphaNum& c,
  72. const AlphaNum& d) {
  73. std::string result;
  74. strings_internal::STLStringResizeUninitialized(
  75. &result, a.size() + b.size() + c.size() + d.size());
  76. char* const begin = &result[0];
  77. char* out = begin;
  78. out = Append(out, a);
  79. out = Append(out, b);
  80. out = Append(out, c);
  81. out = Append(out, d);
  82. assert(out == begin + result.size());
  83. return result;
  84. }
  85. namespace strings_internal {
  86. // Do not call directly - these are not part of the public API.
  87. void STLStringAppendUninitializedAmortized(std::string* dest,
  88. size_t to_append) {
  89. strings_internal::AppendUninitializedTraits<std::string>::Append(dest,
  90. to_append);
  91. }
  92. template <typename Integer>
  93. std::enable_if_t<std::is_integral<Integer>::value, std::string> IntegerToString(
  94. Integer i) {
  95. std::string str;
  96. const auto /* either bool or std::false_type */ is_negative =
  97. absl::numbers_internal::IsNegative(i);
  98. const uint32_t digits = absl::numbers_internal::Base10Digits(
  99. absl::numbers_internal::UnsignedAbsoluteValue(i));
  100. absl::strings_internal::STLStringResizeUninitialized(
  101. &str, digits + static_cast<uint32_t>(is_negative));
  102. absl::numbers_internal::FastIntToBufferBackward(i, &str[str.size()], digits);
  103. return str;
  104. }
  105. template <>
  106. std::string IntegerToString(long i) { // NOLINT
  107. if (sizeof(i) <= sizeof(int)) {
  108. return IntegerToString(static_cast<int>(i));
  109. } else {
  110. return IntegerToString(static_cast<long long>(i)); // NOLINT
  111. }
  112. }
  113. template <>
  114. std::string IntegerToString(unsigned long i) { // NOLINT
  115. if (sizeof(i) <= sizeof(unsigned int)) {
  116. return IntegerToString(static_cast<unsigned int>(i));
  117. } else {
  118. return IntegerToString(static_cast<unsigned long long>(i)); // NOLINT
  119. }
  120. }
  121. template <typename Float>
  122. std::enable_if_t<std::is_floating_point<Float>::value, std::string>
  123. FloatToString(Float f) {
  124. std::string result;
  125. strings_internal::STLStringResizeUninitialized(
  126. &result, numbers_internal::kSixDigitsToBufferSize);
  127. char* start = &result[0];
  128. result.erase(numbers_internal::SixDigitsToBuffer(f, start));
  129. return result;
  130. }
  131. std::string SingleArgStrCat(int x) { return IntegerToString(x); }
  132. std::string SingleArgStrCat(unsigned int x) { return IntegerToString(x); }
  133. // NOLINTNEXTLINE
  134. std::string SingleArgStrCat(long x) { return IntegerToString(x); }
  135. // NOLINTNEXTLINE
  136. std::string SingleArgStrCat(unsigned long x) { return IntegerToString(x); }
  137. // NOLINTNEXTLINE
  138. std::string SingleArgStrCat(long long x) { return IntegerToString(x); }
  139. // NOLINTNEXTLINE
  140. std::string SingleArgStrCat(unsigned long long x) { return IntegerToString(x); }
  141. std::string SingleArgStrCat(float x) { return FloatToString(x); }
  142. std::string SingleArgStrCat(double x) { return FloatToString(x); }
  143. template <class Integer>
  144. std::enable_if_t<std::is_integral<Integer>::value, void> AppendIntegerToString(
  145. std::string& str, Integer i) {
  146. const auto /* either bool or std::false_type */ is_negative =
  147. absl::numbers_internal::IsNegative(i);
  148. const uint32_t digits = absl::numbers_internal::Base10Digits(
  149. absl::numbers_internal::UnsignedAbsoluteValue(i));
  150. absl::strings_internal::STLStringAppendUninitializedAmortized(
  151. &str, digits + static_cast<uint32_t>(is_negative));
  152. absl::numbers_internal::FastIntToBufferBackward(i, &str[str.size()], digits);
  153. }
  154. template <>
  155. void AppendIntegerToString(std::string& str, long i) { // NOLINT
  156. if (sizeof(i) <= sizeof(int)) {
  157. return AppendIntegerToString(str, static_cast<int>(i));
  158. } else {
  159. return AppendIntegerToString(str, static_cast<long long>(i)); // NOLINT
  160. }
  161. }
  162. template <>
  163. void AppendIntegerToString(std::string& str,
  164. unsigned long i) { // NOLINT
  165. if (sizeof(i) <= sizeof(unsigned int)) {
  166. return AppendIntegerToString(str, static_cast<unsigned int>(i));
  167. } else {
  168. return AppendIntegerToString(str,
  169. static_cast<unsigned long long>(i)); // NOLINT
  170. }
  171. }
  172. // `SingleArgStrAppend` overloads are defined here for the same reasons as with
  173. // `SingleArgStrCat` above.
  174. void SingleArgStrAppend(std::string& str, int x) {
  175. return AppendIntegerToString(str, x);
  176. }
  177. void SingleArgStrAppend(std::string& str, unsigned int x) {
  178. return AppendIntegerToString(str, x);
  179. }
  180. // NOLINTNEXTLINE
  181. void SingleArgStrAppend(std::string& str, long x) {
  182. return AppendIntegerToString(str, x);
  183. }
  184. // NOLINTNEXTLINE
  185. void SingleArgStrAppend(std::string& str, unsigned long x) {
  186. return AppendIntegerToString(str, x);
  187. }
  188. // NOLINTNEXTLINE
  189. void SingleArgStrAppend(std::string& str, long long x) {
  190. return AppendIntegerToString(str, x);
  191. }
  192. // NOLINTNEXTLINE
  193. void SingleArgStrAppend(std::string& str, unsigned long long x) {
  194. return AppendIntegerToString(str, x);
  195. }
  196. std::string CatPieces(std::initializer_list<absl::string_view> pieces) {
  197. std::string result;
  198. size_t total_size = 0;
  199. for (absl::string_view piece : pieces) total_size += piece.size();
  200. strings_internal::STLStringResizeUninitialized(&result, total_size);
  201. char* const begin = &result[0];
  202. char* out = begin;
  203. for (absl::string_view piece : pieces) {
  204. const size_t this_size = piece.size();
  205. if (this_size != 0) {
  206. memcpy(out, piece.data(), this_size);
  207. out += this_size;
  208. }
  209. }
  210. assert(out == begin + result.size());
  211. return result;
  212. }
  213. // It's possible to call StrAppend with an absl::string_view that is itself a
  214. // fragment of the string we're appending to. However the results of this are
  215. // random. Therefore, check for this in debug mode. Use unsigned math so we
  216. // only have to do one comparison. Note, there's an exception case: appending an
  217. // empty string is always allowed.
  218. #define ASSERT_NO_OVERLAP(dest, src) \
  219. assert(((src).size() == 0) || \
  220. (uintptr_t((src).data() - (dest).data()) > uintptr_t((dest).size())))
  221. void AppendPieces(absl::Nonnull<std::string*> dest,
  222. std::initializer_list<absl::string_view> pieces) {
  223. size_t old_size = dest->size();
  224. size_t to_append = 0;
  225. for (absl::string_view piece : pieces) {
  226. ASSERT_NO_OVERLAP(*dest, piece);
  227. to_append += piece.size();
  228. }
  229. strings_internal::STLStringAppendUninitializedAmortized(dest, to_append);
  230. char* const begin = &(*dest)[0];
  231. char* out = begin + old_size;
  232. for (absl::string_view piece : pieces) {
  233. const size_t this_size = piece.size();
  234. if (this_size != 0) {
  235. memcpy(out, piece.data(), this_size);
  236. out += this_size;
  237. }
  238. }
  239. assert(out == begin + dest->size());
  240. }
  241. } // namespace strings_internal
  242. void StrAppend(absl::Nonnull<std::string*> dest, const AlphaNum& a) {
  243. ASSERT_NO_OVERLAP(*dest, a);
  244. std::string::size_type old_size = dest->size();
  245. strings_internal::STLStringAppendUninitializedAmortized(dest, a.size());
  246. char* const begin = &(*dest)[0];
  247. char* out = begin + old_size;
  248. out = Append(out, a);
  249. assert(out == begin + dest->size());
  250. }
  251. void StrAppend(absl::Nonnull<std::string*> dest, const AlphaNum& a,
  252. const AlphaNum& b) {
  253. ASSERT_NO_OVERLAP(*dest, a);
  254. ASSERT_NO_OVERLAP(*dest, b);
  255. std::string::size_type old_size = dest->size();
  256. strings_internal::STLStringAppendUninitializedAmortized(dest,
  257. a.size() + b.size());
  258. char* const begin = &(*dest)[0];
  259. char* out = begin + old_size;
  260. out = Append(out, a);
  261. out = Append(out, b);
  262. assert(out == begin + dest->size());
  263. }
  264. void StrAppend(absl::Nonnull<std::string*> dest, const AlphaNum& a,
  265. const AlphaNum& b, const AlphaNum& c) {
  266. ASSERT_NO_OVERLAP(*dest, a);
  267. ASSERT_NO_OVERLAP(*dest, b);
  268. ASSERT_NO_OVERLAP(*dest, c);
  269. std::string::size_type old_size = dest->size();
  270. strings_internal::STLStringAppendUninitializedAmortized(
  271. dest, a.size() + b.size() + c.size());
  272. char* const begin = &(*dest)[0];
  273. char* out = begin + old_size;
  274. out = Append(out, a);
  275. out = Append(out, b);
  276. out = Append(out, c);
  277. assert(out == begin + dest->size());
  278. }
  279. void StrAppend(absl::Nonnull<std::string*> dest, const AlphaNum& a,
  280. const AlphaNum& b, const AlphaNum& c, const AlphaNum& d) {
  281. ASSERT_NO_OVERLAP(*dest, a);
  282. ASSERT_NO_OVERLAP(*dest, b);
  283. ASSERT_NO_OVERLAP(*dest, c);
  284. ASSERT_NO_OVERLAP(*dest, d);
  285. std::string::size_type old_size = dest->size();
  286. strings_internal::STLStringAppendUninitializedAmortized(
  287. dest, a.size() + b.size() + c.size() + d.size());
  288. char* const begin = &(*dest)[0];
  289. char* out = begin + old_size;
  290. out = Append(out, a);
  291. out = Append(out, b);
  292. out = Append(out, c);
  293. out = Append(out, d);
  294. assert(out == begin + dest->size());
  295. }
  296. ABSL_NAMESPACE_END
  297. } // namespace absl