str_cat.cc 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  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 <algorithm>
  17. #include <cstdint>
  18. #include <cstring>
  19. #include "absl/strings/ascii.h"
  20. #include "absl/strings/internal/resize_uninitialized.h"
  21. #include "absl/strings/numbers.h"
  22. namespace absl {
  23. ABSL_NAMESPACE_BEGIN
  24. AlphaNum::AlphaNum(Hex hex) {
  25. static_assert(numbers_internal::kFastToBufferSize >= 32,
  26. "This function only works when output buffer >= 32 bytes long");
  27. char* const end = &digits_[numbers_internal::kFastToBufferSize];
  28. auto real_width =
  29. absl::numbers_internal::FastHexToBufferZeroPad16(hex.value, end - 16);
  30. if (real_width >= hex.width) {
  31. piece_ = absl::string_view(end - real_width, real_width);
  32. } else {
  33. // Pad first 16 chars because FastHexToBufferZeroPad16 pads only to 16 and
  34. // max pad width can be up to 20.
  35. std::memset(end - 32, hex.fill, 16);
  36. // Patch up everything else up to the real_width.
  37. std::memset(end - real_width - 16, hex.fill, 16);
  38. piece_ = absl::string_view(end - hex.width, hex.width);
  39. }
  40. }
  41. AlphaNum::AlphaNum(Dec dec) {
  42. assert(dec.width <= numbers_internal::kFastToBufferSize);
  43. char* const end = &digits_[numbers_internal::kFastToBufferSize];
  44. char* const minfill = end - dec.width;
  45. char* writer = end;
  46. uint64_t value = dec.value;
  47. bool neg = dec.neg;
  48. while (value > 9) {
  49. *--writer = '0' + (value % 10);
  50. value /= 10;
  51. }
  52. *--writer = '0' + value;
  53. if (neg) *--writer = '-';
  54. ptrdiff_t fillers = writer - minfill;
  55. if (fillers > 0) {
  56. // Tricky: if the fill character is ' ', then it's <fill><+/-><digits>
  57. // But...: if the fill character is '0', then it's <+/-><fill><digits>
  58. bool add_sign_again = false;
  59. if (neg && dec.fill == '0') { // If filling with '0',
  60. ++writer; // ignore the sign we just added
  61. add_sign_again = true; // and re-add the sign later.
  62. }
  63. writer -= fillers;
  64. std::fill_n(writer, fillers, dec.fill);
  65. if (add_sign_again) *--writer = '-';
  66. }
  67. piece_ = absl::string_view(writer, end - writer);
  68. }
  69. // ----------------------------------------------------------------------
  70. // StrCat()
  71. // This merges the given strings or integers, with no delimiter. This
  72. // is designed to be the fastest possible way to construct a string out
  73. // of a mix of raw C strings, string_views, strings, and integer values.
  74. // ----------------------------------------------------------------------
  75. // Append is merely a version of memcpy that returns the address of the byte
  76. // after the area just overwritten.
  77. static char* Append(char* out, const AlphaNum& x) {
  78. // memcpy is allowed to overwrite arbitrary memory, so doing this after the
  79. // call would force an extra fetch of x.size().
  80. char* after = out + x.size();
  81. if (x.size() != 0) {
  82. memcpy(out, x.data(), x.size());
  83. }
  84. return after;
  85. }
  86. std::string StrCat(const AlphaNum& a, const AlphaNum& b) {
  87. std::string result;
  88. absl::strings_internal::STLStringResizeUninitialized(&result,
  89. a.size() + b.size());
  90. char* const begin = &result[0];
  91. char* out = begin;
  92. out = Append(out, a);
  93. out = Append(out, b);
  94. assert(out == begin + result.size());
  95. return result;
  96. }
  97. std::string StrCat(const AlphaNum& a, const AlphaNum& b, const AlphaNum& c) {
  98. std::string result;
  99. strings_internal::STLStringResizeUninitialized(
  100. &result, a.size() + b.size() + c.size());
  101. char* const begin = &result[0];
  102. char* out = begin;
  103. out = Append(out, a);
  104. out = Append(out, b);
  105. out = Append(out, c);
  106. assert(out == begin + result.size());
  107. return result;
  108. }
  109. std::string StrCat(const AlphaNum& a, const AlphaNum& b, const AlphaNum& c,
  110. const AlphaNum& d) {
  111. std::string result;
  112. strings_internal::STLStringResizeUninitialized(
  113. &result, a.size() + b.size() + c.size() + d.size());
  114. char* const begin = &result[0];
  115. char* out = begin;
  116. out = Append(out, a);
  117. out = Append(out, b);
  118. out = Append(out, c);
  119. out = Append(out, d);
  120. assert(out == begin + result.size());
  121. return result;
  122. }
  123. namespace strings_internal {
  124. // Do not call directly - these are not part of the public API.
  125. std::string CatPieces(std::initializer_list<absl::string_view> pieces) {
  126. std::string result;
  127. size_t total_size = 0;
  128. for (const absl::string_view& piece : pieces) total_size += piece.size();
  129. strings_internal::STLStringResizeUninitialized(&result, total_size);
  130. char* const begin = &result[0];
  131. char* out = begin;
  132. for (const absl::string_view& piece : pieces) {
  133. const size_t this_size = piece.size();
  134. if (this_size != 0) {
  135. memcpy(out, piece.data(), this_size);
  136. out += this_size;
  137. }
  138. }
  139. assert(out == begin + result.size());
  140. return result;
  141. }
  142. // It's possible to call StrAppend with an absl::string_view that is itself a
  143. // fragment of the string we're appending to. However the results of this are
  144. // random. Therefore, check for this in debug mode. Use unsigned math so we
  145. // only have to do one comparison. Note, there's an exception case: appending an
  146. // empty string is always allowed.
  147. #define ASSERT_NO_OVERLAP(dest, src) \
  148. assert(((src).size() == 0) || \
  149. (uintptr_t((src).data() - (dest).data()) > uintptr_t((dest).size())))
  150. void AppendPieces(std::string* dest,
  151. std::initializer_list<absl::string_view> pieces) {
  152. size_t old_size = dest->size();
  153. size_t total_size = old_size;
  154. for (const absl::string_view& piece : pieces) {
  155. ASSERT_NO_OVERLAP(*dest, piece);
  156. total_size += piece.size();
  157. }
  158. strings_internal::STLStringResizeUninitializedAmortized(dest, total_size);
  159. char* const begin = &(*dest)[0];
  160. char* out = begin + old_size;
  161. for (const absl::string_view& piece : pieces) {
  162. const size_t this_size = piece.size();
  163. if (this_size != 0) {
  164. memcpy(out, piece.data(), this_size);
  165. out += this_size;
  166. }
  167. }
  168. assert(out == begin + dest->size());
  169. }
  170. } // namespace strings_internal
  171. void StrAppend(std::string* dest, const AlphaNum& a) {
  172. ASSERT_NO_OVERLAP(*dest, a);
  173. dest->append(a.data(), a.size());
  174. }
  175. void StrAppend(std::string* dest, const AlphaNum& a, const AlphaNum& b) {
  176. ASSERT_NO_OVERLAP(*dest, a);
  177. ASSERT_NO_OVERLAP(*dest, b);
  178. std::string::size_type old_size = dest->size();
  179. strings_internal::STLStringResizeUninitializedAmortized(
  180. dest, old_size + a.size() + b.size());
  181. char* const begin = &(*dest)[0];
  182. char* out = begin + old_size;
  183. out = Append(out, a);
  184. out = Append(out, b);
  185. assert(out == begin + dest->size());
  186. }
  187. void StrAppend(std::string* dest, const AlphaNum& a, const AlphaNum& b,
  188. const AlphaNum& c) {
  189. ASSERT_NO_OVERLAP(*dest, a);
  190. ASSERT_NO_OVERLAP(*dest, b);
  191. ASSERT_NO_OVERLAP(*dest, c);
  192. std::string::size_type old_size = dest->size();
  193. strings_internal::STLStringResizeUninitializedAmortized(
  194. dest, old_size + 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(std::string* dest, const AlphaNum& a, const AlphaNum& b,
  203. 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. strings_internal::STLStringResizeUninitializedAmortized(
  210. dest, old_size + 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