abseil-cpp/absl/strings/str_cat.cc
Go to the documentation of this file.
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 
15 #include "absl/strings/str_cat.h"
16 
17 #include <assert.h>
18 
19 #include <algorithm>
20 #include <cstdint>
21 #include <cstring>
22 
23 #include "absl/strings/ascii.h"
24 #include "absl/strings/internal/resize_uninitialized.h"
25 #include "absl/strings/numbers.h"
26 
27 namespace absl {
29 
31  static_assert(numbers_internal::kFastToBufferSize >= 32,
32  "This function only works when output buffer >= 32 bytes long");
34  auto real_width =
36  if (real_width >= hex.width) {
37  piece_ = absl::string_view(end - real_width, real_width);
38  } else {
39  // Pad first 16 chars because FastHexToBufferZeroPad16 pads only to 16 and
40  // max pad width can be up to 20.
41  std::memset(end - 32, hex.fill, 16);
42  // Patch up everything else up to the real_width.
43  std::memset(end - real_width - 16, hex.fill, 16);
44  piece_ = absl::string_view(end - hex.width, hex.width);
45  }
46 }
47 
51  char* const minfill = end - dec.width;
52  char* writer = end;
53  uint64_t value = dec.value;
54  bool neg = dec.neg;
55  while (value > 9) {
56  *--writer = '0' + (value % 10);
57  value /= 10;
58  }
59  *--writer = '0' + value;
60  if (neg) *--writer = '-';
61 
62  ptrdiff_t fillers = writer - minfill;
63  if (fillers > 0) {
64  // Tricky: if the fill character is ' ', then it's <fill><+/-><digits>
65  // But...: if the fill character is '0', then it's <+/-><fill><digits>
66  bool add_sign_again = false;
67  if (neg && dec.fill == '0') { // If filling with '0',
68  ++writer; // ignore the sign we just added
69  add_sign_again = true; // and re-add the sign later.
70  }
71  writer -= fillers;
72  std::fill_n(writer, fillers, dec.fill);
73  if (add_sign_again) *--writer = '-';
74  }
75 
77 }
78 
79 // ----------------------------------------------------------------------
80 // StrCat()
81 // This merges the given strings or integers, with no delimiter. This
82 // is designed to be the fastest possible way to construct a string out
83 // of a mix of raw C strings, string_views, strings, and integer values.
84 // ----------------------------------------------------------------------
85 
86 // Append is merely a version of memcpy that returns the address of the byte
87 // after the area just overwritten.
88 static char* Append(char* out, const AlphaNum& x) {
89  // memcpy is allowed to overwrite arbitrary memory, so doing this after the
90  // call would force an extra fetch of x.size().
91  char* after = out + x.size();
92  if (x.size() != 0) {
93  memcpy(out, x.data(), x.size());
94  }
95  return after;
96 }
97 
98 std::string StrCat(const AlphaNum& a, const AlphaNum& b) {
101  a.size() + b.size());
102  char* const begin = &result[0];
103  char* out = begin;
104  out = Append(out, a);
105  out = Append(out, b);
106  assert(out == begin + result.size());
107  return result;
108 }
109 
110 std::string StrCat(const AlphaNum& a, const AlphaNum& b, const AlphaNum& c) {
113  &result, a.size() + b.size() + c.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  assert(out == begin + result.size());
120  return result;
121 }
122 
123 std::string StrCat(const AlphaNum& a, const AlphaNum& b, const AlphaNum& c,
124  const AlphaNum& d) {
127  &result, a.size() + b.size() + c.size() + d.size());
128  char* const begin = &result[0];
129  char* out = begin;
130  out = Append(out, a);
131  out = Append(out, b);
132  out = Append(out, c);
133  out = Append(out, d);
134  assert(out == begin + result.size());
135  return result;
136 }
137 
138 namespace strings_internal {
139 
140 // Do not call directly - these are not part of the public API.
141 std::string CatPieces(std::initializer_list<absl::string_view> pieces) {
143  size_t total_size = 0;
144  for (const absl::string_view& piece : pieces) total_size += piece.size();
146 
147  char* const begin = &result[0];
148  char* out = begin;
149  for (const absl::string_view& piece : pieces) {
150  const size_t this_size = piece.size();
151  if (this_size != 0) {
152  memcpy(out, piece.data(), this_size);
153  out += this_size;
154  }
155  }
156  assert(out == begin + result.size());
157  return result;
158 }
159 
160 // It's possible to call StrAppend with an absl::string_view that is itself a
161 // fragment of the string we're appending to. However the results of this are
162 // random. Therefore, check for this in debug mode. Use unsigned math so we
163 // only have to do one comparison. Note, there's an exception case: appending an
164 // empty string is always allowed.
165 #define ASSERT_NO_OVERLAP(dest, src) \
166  assert(((src).size() == 0) || \
167  (uintptr_t((src).data() - (dest).data()) > uintptr_t((dest).size())))
168 
170  std::initializer_list<absl::string_view> pieces) {
171  size_t old_size = dest->size();
172  size_t total_size = old_size;
173  for (const absl::string_view& piece : pieces) {
174  ASSERT_NO_OVERLAP(*dest, piece);
175  total_size += piece.size();
176  }
178 
179  char* const begin = &(*dest)[0];
180  char* out = begin + old_size;
181  for (const absl::string_view& piece : pieces) {
182  const size_t this_size = piece.size();
183  if (this_size != 0) {
184  memcpy(out, piece.data(), this_size);
185  out += this_size;
186  }
187  }
188  assert(out == begin + dest->size());
189 }
190 
191 } // namespace strings_internal
192 
193 void StrAppend(std::string* dest, const AlphaNum& a) {
195  dest->append(a.data(), a.size());
196 }
197 
198 void StrAppend(std::string* dest, const AlphaNum& a, const AlphaNum& b) {
201  std::string::size_type old_size = dest->size();
203  dest, old_size + a.size() + b.size());
204  char* const begin = &(*dest)[0];
205  char* out = begin + old_size;
206  out = Append(out, a);
207  out = Append(out, b);
208  assert(out == begin + dest->size());
209 }
210 
211 void StrAppend(std::string* dest, const AlphaNum& a, const AlphaNum& b,
212  const AlphaNum& c) {
215  ASSERT_NO_OVERLAP(*dest, c);
216  std::string::size_type old_size = dest->size();
218  dest, old_size + a.size() + b.size() + c.size());
219  char* const begin = &(*dest)[0];
220  char* out = begin + old_size;
221  out = Append(out, a);
222  out = Append(out, b);
223  out = Append(out, c);
224  assert(out == begin + dest->size());
225 }
226 
227 void StrAppend(std::string* dest, const AlphaNum& a, const AlphaNum& b,
228  const AlphaNum& c, const AlphaNum& d) {
231  ASSERT_NO_OVERLAP(*dest, c);
232  ASSERT_NO_OVERLAP(*dest, d);
233  std::string::size_type old_size = dest->size();
235  dest, old_size + a.size() + b.size() + c.size() + d.size());
236  char* const begin = &(*dest)[0];
237  char* out = begin + old_size;
238  out = Append(out, a);
239  out = Append(out, b);
240  out = Append(out, c);
241  out = Append(out, d);
242  assert(out == begin + dest->size());
243 }
244 
246 } // namespace absl
absl::Append
static char * Append(char *out, const AlphaNum &x)
Definition: abseil-cpp/absl/strings/str_cat.cc:88
_gevent_test_main.result
result
Definition: _gevent_test_main.py:96
absl::StrAppend
void StrAppend(std::string *dest, const AlphaNum &a)
Definition: abseil-cpp/absl/strings/str_cat.cc:193
absl::strings_internal::AppendPieces
void AppendPieces(std::string *dest, std::initializer_list< absl::string_view > pieces)
Definition: abseil-cpp/absl/strings/str_cat.cc:169
absl::StrCat
std::string StrCat(const AlphaNum &a, const AlphaNum &b)
Definition: abseil-cpp/absl/strings/str_cat.cc:98
memset
return memset(p, 0, total)
absl::numbers_internal::FastHexToBufferZeroPad16
size_t FastHexToBufferZeroPad16(uint64_t val, char *out)
Definition: abseil-cpp/absl/strings/numbers.h:245
begin
char * begin
Definition: abseil-cpp/absl/strings/internal/str_format/float_conversion.cc:1007
absl::string_view
Definition: abseil-cpp/absl/strings/string_view.h:167
testing::internal::string
::std::string string
Definition: bloaty/third_party/protobuf/third_party/googletest/googletest/include/gtest/internal/gtest-port.h:881
absl::strings_internal::STLStringResizeUninitializedAmortized
void STLStringResizeUninitializedAmortized(string_type *s, size_t new_size)
Definition: abseil-cpp/absl/strings/internal/resize_uninitialized.h:106
absl::Dec::value
uint64_t value
Definition: abseil-cpp/absl/strings/str_cat.h:185
a
int a
Definition: abseil-cpp/absl/container/internal/hash_policy_traits_test.cc:88
absl::strings_internal::CatPieces
std::string CatPieces(std::initializer_list< absl::string_view > pieces)
Definition: abseil-cpp/absl/strings/str_cat.cc:141
ABSL_NAMESPACE_END
#define ABSL_NAMESPACE_END
Definition: third_party/abseil-cpp/absl/base/config.h:171
absl::Hex
Definition: abseil-cpp/absl/strings/str_cat.h:134
memcpy
memcpy(mem, inblock.get(), min(CONTAINING_RECORD(inblock.get(), MEMBLOCK, data) ->size, size))
ABSL_NAMESPACE_BEGIN
#define ABSL_NAMESPACE_BEGIN
Definition: third_party/abseil-cpp/absl/base/config.h:170
end
char * end
Definition: abseil-cpp/absl/strings/internal/str_format/float_conversion.cc:1008
absl::AlphaNum::AlphaNum
AlphaNum(int x)
Definition: abseil-cpp/absl/strings/str_cat.h:216
absl::AlphaNum
Definition: abseil-cpp/absl/strings/str_cat.h:211
absl::Dec::neg
bool neg
Definition: abseil-cpp/absl/strings/str_cat.h:188
uint64_t
unsigned __int64 uint64_t
Definition: stdint-msvc2008.h:90
absl::AlphaNum::digits_
char digits_[numbers_internal::kFastToBufferSize]
Definition: abseil-cpp/absl/strings/str_cat.h:294
absl::Dec::fill
char fill
Definition: abseil-cpp/absl/strings/str_cat.h:187
x
int x
Definition: bloaty/third_party/googletest/googlemock/test/gmock-matchers_test.cc:3610
b
uint64_t b
Definition: abseil-cpp/absl/container/internal/layout_test.cc:53
tests.qps.qps_worker.dest
dest
Definition: qps_worker.py:45
after
IntAfterTypedTestSuiteP after
Definition: googletest/googletest/test/gtest-typed-test_test.cc:375
writer
void writer(void *n)
Definition: libuv/docs/code/locks/main.c:22
absl::Dec::width
uint8_t width
Definition: abseil-cpp/absl/strings/str_cat.h:186
value
const char * value
Definition: hpack_parser_table.cc:165
absl::chars_format::hex
@ hex
ASSERT_NO_OVERLAP
#define ASSERT_NO_OVERLAP(dest, src)
Definition: abseil-cpp/absl/strings/str_cat.cc:165
absl::AlphaNum::piece_
absl::string_view piece_
Definition: abseil-cpp/absl/strings/str_cat.h:293
absl::strings_internal::STLStringResizeUninitialized
void STLStringResizeUninitialized(string_type *s, size_t new_size)
Definition: abseil-cpp/absl/strings/internal/resize_uninitialized.h:67
string_view
absl::string_view string_view
Definition: attr.cc:22
absl::numbers_internal::kFastToBufferSize
static const int kFastToBufferSize
Definition: abseil-cpp/absl/strings/numbers.h:153
absl
Definition: abseil-cpp/absl/algorithm/algorithm.h:31
absl::Dec
Definition: abseil-cpp/absl/strings/str_cat.h:184
absl::out
char * out
Definition: abseil-cpp/absl/synchronization/mutex.h:1048
binary_size.old_size
old_size
Definition: binary_size.py:125


grpc
Author(s):
autogenerated on Fri May 16 2025 03:00:19