str_cat.cc 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  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 <limits>
  21. #include <string>
  22. #include "absl/base/config.h"
  23. #include "absl/base/internal/raw_logging.h"
  24. #include "absl/base/nullability.h"
  25. #include "absl/strings/internal/resize_uninitialized.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. inline absl::Nonnull<char*> Append(absl::Nonnull<char*> out,
  39. const AlphaNum& x) {
  40. // memcpy is allowed to overwrite arbitrary memory, so doing this after the
  41. // call would force an extra fetch of x.size().
  42. char* after = out + x.size();
  43. if (x.size() != 0) {
  44. memcpy(out, x.data(), x.size());
  45. }
  46. return after;
  47. }
  48. inline void STLStringAppendUninitializedAmortized(std::string* dest,
  49. size_t to_append) {
  50. strings_internal::AppendUninitializedTraits<std::string>::Append(dest,
  51. to_append);
  52. }
  53. } // namespace
  54. std::string StrCat(const AlphaNum& a, const AlphaNum& b) {
  55. std::string result;
  56. // Use uint64_t to prevent size_t overflow. We assume it is not possible for
  57. // in memory strings to overflow a uint64_t.
  58. constexpr uint64_t kMaxSize = uint64_t{std::numeric_limits<size_t>::max()};
  59. const uint64_t result_size =
  60. static_cast<uint64_t>(a.size()) + static_cast<uint64_t>(b.size());
  61. ABSL_INTERNAL_CHECK(result_size <= kMaxSize, "size_t overflow");
  62. absl::strings_internal::STLStringResizeUninitialized(
  63. &result, static_cast<size_t>(result_size));
  64. char* const begin = &result[0];
  65. char* out = begin;
  66. out = Append(out, a);
  67. out = Append(out, b);
  68. assert(out == begin + result.size());
  69. return result;
  70. }
  71. std::string StrCat(const AlphaNum& a, const AlphaNum& b, const AlphaNum& c) {
  72. std::string result;
  73. // Use uint64_t to prevent size_t overflow. We assume it is not possible for
  74. // in memory strings to overflow a uint64_t.
  75. constexpr uint64_t kMaxSize = uint64_t{std::numeric_limits<size_t>::max()};
  76. const uint64_t result_size = static_cast<uint64_t>(a.size()) +
  77. static_cast<uint64_t>(b.size()) +
  78. static_cast<uint64_t>(c.size());
  79. ABSL_INTERNAL_CHECK(result_size <= kMaxSize, "size_t overflow");
  80. strings_internal::STLStringResizeUninitialized(
  81. &result, static_cast<size_t>(result_size));
  82. char* const begin = &result[0];
  83. char* out = begin;
  84. out = Append(out, a);
  85. out = Append(out, b);
  86. out = Append(out, c);
  87. assert(out == begin + result.size());
  88. return result;
  89. }
  90. std::string StrCat(const AlphaNum& a, const AlphaNum& b, const AlphaNum& c,
  91. const AlphaNum& d) {
  92. std::string result;
  93. // Use uint64_t to prevent size_t overflow. We assume it is not possible for
  94. // in memory strings to overflow a uint64_t.
  95. constexpr uint64_t kMaxSize = uint64_t{std::numeric_limits<size_t>::max()};
  96. const uint64_t result_size = static_cast<uint64_t>(a.size()) +
  97. static_cast<uint64_t>(b.size()) +
  98. static_cast<uint64_t>(c.size()) +
  99. static_cast<uint64_t>(d.size());
  100. ABSL_INTERNAL_CHECK(result_size <= kMaxSize, "size_t overflow");
  101. strings_internal::STLStringResizeUninitialized(
  102. &result, static_cast<size_t>(result_size));
  103. char* const begin = &result[0];
  104. char* out = begin;
  105. out = Append(out, a);
  106. out = Append(out, b);
  107. out = Append(out, c);
  108. out = Append(out, d);
  109. assert(out == begin + result.size());
  110. return result;
  111. }
  112. namespace strings_internal {
  113. // Do not call directly - these are not part of the public API.
  114. std::string CatPieces(std::initializer_list<absl::string_view> pieces) {
  115. std::string result;
  116. // Use uint64_t to prevent size_t overflow. We assume it is not possible for
  117. // in memory strings to overflow a uint64_t.
  118. constexpr uint64_t kMaxSize = uint64_t{std::numeric_limits<size_t>::max()};
  119. uint64_t total_size = 0;
  120. for (absl::string_view piece : pieces) {
  121. total_size += piece.size();
  122. }
  123. ABSL_INTERNAL_CHECK(total_size <= kMaxSize, "size_t overflow");
  124. strings_internal::STLStringResizeUninitialized(
  125. &result, static_cast<size_t>(total_size));
  126. char* const begin = &result[0];
  127. char* out = begin;
  128. for (absl::string_view piece : pieces) {
  129. const size_t this_size = piece.size();
  130. if (this_size != 0) {
  131. memcpy(out, piece.data(), this_size);
  132. out += this_size;
  133. }
  134. }
  135. assert(out == begin + result.size());
  136. return result;
  137. }
  138. // It's possible to call StrAppend with an absl::string_view that is itself a
  139. // fragment of the string we're appending to. However the results of this are
  140. // random. Therefore, check for this in debug mode. Use unsigned math so we
  141. // only have to do one comparison. Note, there's an exception case: appending an
  142. // empty string is always allowed.
  143. #define ASSERT_NO_OVERLAP(dest, src) \
  144. assert(((src).size() == 0) || \
  145. (uintptr_t((src).data() - (dest).data()) > uintptr_t((dest).size())))
  146. void AppendPieces(absl::Nonnull<std::string*> dest,
  147. std::initializer_list<absl::string_view> pieces) {
  148. size_t old_size = dest->size();
  149. size_t to_append = 0;
  150. for (absl::string_view piece : pieces) {
  151. ASSERT_NO_OVERLAP(*dest, piece);
  152. to_append += piece.size();
  153. }
  154. STLStringAppendUninitializedAmortized(dest, to_append);
  155. char* const begin = &(*dest)[0];
  156. char* out = begin + old_size;
  157. for (absl::string_view piece : pieces) {
  158. const size_t this_size = piece.size();
  159. if (this_size != 0) {
  160. memcpy(out, piece.data(), this_size);
  161. out += this_size;
  162. }
  163. }
  164. assert(out == begin + dest->size());
  165. }
  166. } // namespace strings_internal
  167. void StrAppend(absl::Nonnull<std::string*> dest, const AlphaNum& a) {
  168. ASSERT_NO_OVERLAP(*dest, a);
  169. std::string::size_type old_size = dest->size();
  170. STLStringAppendUninitializedAmortized(dest, a.size());
  171. char* const begin = &(*dest)[0];
  172. char* out = begin + old_size;
  173. out = Append(out, a);
  174. assert(out == begin + dest->size());
  175. }
  176. void StrAppend(absl::Nonnull<std::string*> dest, const AlphaNum& a,
  177. const AlphaNum& b) {
  178. ASSERT_NO_OVERLAP(*dest, a);
  179. ASSERT_NO_OVERLAP(*dest, b);
  180. std::string::size_type old_size = dest->size();
  181. STLStringAppendUninitializedAmortized(dest, a.size() + b.size());
  182. char* const begin = &(*dest)[0];
  183. char* out = begin + old_size;
  184. out = Append(out, a);
  185. out = Append(out, b);
  186. assert(out == begin + dest->size());
  187. }
  188. void StrAppend(absl::Nonnull<std::string*> dest, const AlphaNum& a,
  189. const AlphaNum& b, const AlphaNum& c) {
  190. ASSERT_NO_OVERLAP(*dest, a);
  191. ASSERT_NO_OVERLAP(*dest, b);
  192. ASSERT_NO_OVERLAP(*dest, c);
  193. std::string::size_type old_size = dest->size();
  194. STLStringAppendUninitializedAmortized(dest, a.size() + b.size() + c.size());
  195. char* const begin = &(*dest)[0];
  196. char* out = begin + old_size;
  197. out = Append(out, a);
  198. out = Append(out, b);
  199. out = Append(out, c);
  200. assert(out == begin + dest->size());
  201. }
  202. void StrAppend(absl::Nonnull<std::string*> dest, const AlphaNum& a,
  203. const AlphaNum& b, const AlphaNum& c, const AlphaNum& d) {
  204. ASSERT_NO_OVERLAP(*dest, a);
  205. ASSERT_NO_OVERLAP(*dest, b);
  206. ASSERT_NO_OVERLAP(*dest, c);
  207. ASSERT_NO_OVERLAP(*dest, d);
  208. std::string::size_type old_size = dest->size();
  209. STLStringAppendUninitializedAmortized(
  210. dest, a.size() + b.size() + c.size() + d.size());
  211. char* const begin = &(*dest)[0];
  212. char* out = begin + old_size;
  213. out = Append(out, a);
  214. out = Append(out, b);
  215. out = Append(out, c);
  216. out = Append(out, d);
  217. assert(out == begin + dest->size());
  218. }
  219. ABSL_NAMESPACE_END
  220. } // namespace absl