xref: /aosp_15_r20/external/abseil-cpp/absl/strings/str_cat.cc (revision 9356374a3709195abf420251b3e825997ff56c0f)
1*9356374aSAndroid Build Coastguard Worker // Copyright 2017 The Abseil Authors.
2*9356374aSAndroid Build Coastguard Worker //
3*9356374aSAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License");
4*9356374aSAndroid Build Coastguard Worker // you may not use this file except in compliance with the License.
5*9356374aSAndroid Build Coastguard Worker // You may obtain a copy of the License at
6*9356374aSAndroid Build Coastguard Worker //
7*9356374aSAndroid Build Coastguard Worker //      https://www.apache.org/licenses/LICENSE-2.0
8*9356374aSAndroid Build Coastguard Worker //
9*9356374aSAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*9356374aSAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
11*9356374aSAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*9356374aSAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
13*9356374aSAndroid Build Coastguard Worker // limitations under the License.
14*9356374aSAndroid Build Coastguard Worker 
15*9356374aSAndroid Build Coastguard Worker #include "absl/strings/str_cat.h"
16*9356374aSAndroid Build Coastguard Worker 
17*9356374aSAndroid Build Coastguard Worker #include <assert.h>
18*9356374aSAndroid Build Coastguard Worker 
19*9356374aSAndroid Build Coastguard Worker #include <cstddef>
20*9356374aSAndroid Build Coastguard Worker #include <cstdint>
21*9356374aSAndroid Build Coastguard Worker #include <cstring>
22*9356374aSAndroid Build Coastguard Worker #include <initializer_list>
23*9356374aSAndroid Build Coastguard Worker #include <limits>
24*9356374aSAndroid Build Coastguard Worker #include <string>
25*9356374aSAndroid Build Coastguard Worker 
26*9356374aSAndroid Build Coastguard Worker #include "absl/base/config.h"
27*9356374aSAndroid Build Coastguard Worker #include "absl/base/internal/raw_logging.h"
28*9356374aSAndroid Build Coastguard Worker #include "absl/base/nullability.h"
29*9356374aSAndroid Build Coastguard Worker #include "absl/strings/internal/resize_uninitialized.h"
30*9356374aSAndroid Build Coastguard Worker #include "absl/strings/string_view.h"
31*9356374aSAndroid Build Coastguard Worker 
32*9356374aSAndroid Build Coastguard Worker namespace absl {
33*9356374aSAndroid Build Coastguard Worker ABSL_NAMESPACE_BEGIN
34*9356374aSAndroid Build Coastguard Worker 
35*9356374aSAndroid Build Coastguard Worker // ----------------------------------------------------------------------
36*9356374aSAndroid Build Coastguard Worker // StrCat()
37*9356374aSAndroid Build Coastguard Worker //    This merges the given strings or integers, with no delimiter. This
38*9356374aSAndroid Build Coastguard Worker //    is designed to be the fastest possible way to construct a string out
39*9356374aSAndroid Build Coastguard Worker //    of a mix of raw C strings, string_views, strings, and integer values.
40*9356374aSAndroid Build Coastguard Worker // ----------------------------------------------------------------------
41*9356374aSAndroid Build Coastguard Worker 
42*9356374aSAndroid Build Coastguard Worker namespace {
43*9356374aSAndroid Build Coastguard Worker // Append is merely a version of memcpy that returns the address of the byte
44*9356374aSAndroid Build Coastguard Worker // after the area just overwritten.
Append(absl::Nonnull<char * > out,const AlphaNum & x)45*9356374aSAndroid Build Coastguard Worker inline absl::Nonnull<char*> Append(absl::Nonnull<char*> out,
46*9356374aSAndroid Build Coastguard Worker                                    const AlphaNum& x) {
47*9356374aSAndroid Build Coastguard Worker   // memcpy is allowed to overwrite arbitrary memory, so doing this after the
48*9356374aSAndroid Build Coastguard Worker   // call would force an extra fetch of x.size().
49*9356374aSAndroid Build Coastguard Worker   char* after = out + x.size();
50*9356374aSAndroid Build Coastguard Worker   if (x.size() != 0) {
51*9356374aSAndroid Build Coastguard Worker     memcpy(out, x.data(), x.size());
52*9356374aSAndroid Build Coastguard Worker   }
53*9356374aSAndroid Build Coastguard Worker   return after;
54*9356374aSAndroid Build Coastguard Worker }
55*9356374aSAndroid Build Coastguard Worker 
STLStringAppendUninitializedAmortized(std::string * dest,size_t to_append)56*9356374aSAndroid Build Coastguard Worker inline void STLStringAppendUninitializedAmortized(std::string* dest,
57*9356374aSAndroid Build Coastguard Worker                                                   size_t to_append) {
58*9356374aSAndroid Build Coastguard Worker   strings_internal::AppendUninitializedTraits<std::string>::Append(dest,
59*9356374aSAndroid Build Coastguard Worker                                                                    to_append);
60*9356374aSAndroid Build Coastguard Worker }
61*9356374aSAndroid Build Coastguard Worker }  // namespace
62*9356374aSAndroid Build Coastguard Worker 
StrCat(const AlphaNum & a,const AlphaNum & b)63*9356374aSAndroid Build Coastguard Worker std::string StrCat(const AlphaNum& a, const AlphaNum& b) {
64*9356374aSAndroid Build Coastguard Worker   std::string result;
65*9356374aSAndroid Build Coastguard Worker   // Use uint64_t to prevent size_t overflow. We assume it is not possible for
66*9356374aSAndroid Build Coastguard Worker   // in memory strings to overflow a uint64_t.
67*9356374aSAndroid Build Coastguard Worker   constexpr uint64_t kMaxSize = uint64_t{std::numeric_limits<size_t>::max()};
68*9356374aSAndroid Build Coastguard Worker   const uint64_t result_size =
69*9356374aSAndroid Build Coastguard Worker       static_cast<uint64_t>(a.size()) + static_cast<uint64_t>(b.size());
70*9356374aSAndroid Build Coastguard Worker   ABSL_INTERNAL_CHECK(result_size <= kMaxSize, "size_t overflow");
71*9356374aSAndroid Build Coastguard Worker   absl::strings_internal::STLStringResizeUninitialized(
72*9356374aSAndroid Build Coastguard Worker       &result, static_cast<size_t>(result_size));
73*9356374aSAndroid Build Coastguard Worker   char* const begin = &result[0];
74*9356374aSAndroid Build Coastguard Worker   char* out = begin;
75*9356374aSAndroid Build Coastguard Worker   out = Append(out, a);
76*9356374aSAndroid Build Coastguard Worker   out = Append(out, b);
77*9356374aSAndroid Build Coastguard Worker   assert(out == begin + result.size());
78*9356374aSAndroid Build Coastguard Worker   return result;
79*9356374aSAndroid Build Coastguard Worker }
80*9356374aSAndroid Build Coastguard Worker 
StrCat(const AlphaNum & a,const AlphaNum & b,const AlphaNum & c)81*9356374aSAndroid Build Coastguard Worker std::string StrCat(const AlphaNum& a, const AlphaNum& b, const AlphaNum& c) {
82*9356374aSAndroid Build Coastguard Worker   std::string result;
83*9356374aSAndroid Build Coastguard Worker   // Use uint64_t to prevent size_t overflow. We assume it is not possible for
84*9356374aSAndroid Build Coastguard Worker   // in memory strings to overflow a uint64_t.
85*9356374aSAndroid Build Coastguard Worker   constexpr uint64_t kMaxSize = uint64_t{std::numeric_limits<size_t>::max()};
86*9356374aSAndroid Build Coastguard Worker   const uint64_t result_size = static_cast<uint64_t>(a.size()) +
87*9356374aSAndroid Build Coastguard Worker                                static_cast<uint64_t>(b.size()) +
88*9356374aSAndroid Build Coastguard Worker                                static_cast<uint64_t>(c.size());
89*9356374aSAndroid Build Coastguard Worker   ABSL_INTERNAL_CHECK(result_size <= kMaxSize, "size_t overflow");
90*9356374aSAndroid Build Coastguard Worker   strings_internal::STLStringResizeUninitialized(
91*9356374aSAndroid Build Coastguard Worker       &result, static_cast<size_t>(result_size));
92*9356374aSAndroid Build Coastguard Worker   char* const begin = &result[0];
93*9356374aSAndroid Build Coastguard Worker   char* out = begin;
94*9356374aSAndroid Build Coastguard Worker   out = Append(out, a);
95*9356374aSAndroid Build Coastguard Worker   out = Append(out, b);
96*9356374aSAndroid Build Coastguard Worker   out = Append(out, c);
97*9356374aSAndroid Build Coastguard Worker   assert(out == begin + result.size());
98*9356374aSAndroid Build Coastguard Worker   return result;
99*9356374aSAndroid Build Coastguard Worker }
100*9356374aSAndroid Build Coastguard Worker 
StrCat(const AlphaNum & a,const AlphaNum & b,const AlphaNum & c,const AlphaNum & d)101*9356374aSAndroid Build Coastguard Worker std::string StrCat(const AlphaNum& a, const AlphaNum& b, const AlphaNum& c,
102*9356374aSAndroid Build Coastguard Worker                    const AlphaNum& d) {
103*9356374aSAndroid Build Coastguard Worker   std::string result;
104*9356374aSAndroid Build Coastguard Worker   // Use uint64_t to prevent size_t overflow. We assume it is not possible for
105*9356374aSAndroid Build Coastguard Worker   // in memory strings to overflow a uint64_t.
106*9356374aSAndroid Build Coastguard Worker   constexpr uint64_t kMaxSize = uint64_t{std::numeric_limits<size_t>::max()};
107*9356374aSAndroid Build Coastguard Worker   const uint64_t result_size = static_cast<uint64_t>(a.size()) +
108*9356374aSAndroid Build Coastguard Worker                                static_cast<uint64_t>(b.size()) +
109*9356374aSAndroid Build Coastguard Worker                                static_cast<uint64_t>(c.size()) +
110*9356374aSAndroid Build Coastguard Worker                                static_cast<uint64_t>(d.size());
111*9356374aSAndroid Build Coastguard Worker   ABSL_INTERNAL_CHECK(result_size <= kMaxSize, "size_t overflow");
112*9356374aSAndroid Build Coastguard Worker   strings_internal::STLStringResizeUninitialized(
113*9356374aSAndroid Build Coastguard Worker       &result, static_cast<size_t>(result_size));
114*9356374aSAndroid Build Coastguard Worker   char* const begin = &result[0];
115*9356374aSAndroid Build Coastguard Worker   char* out = begin;
116*9356374aSAndroid Build Coastguard Worker   out = Append(out, a);
117*9356374aSAndroid Build Coastguard Worker   out = Append(out, b);
118*9356374aSAndroid Build Coastguard Worker   out = Append(out, c);
119*9356374aSAndroid Build Coastguard Worker   out = Append(out, d);
120*9356374aSAndroid Build Coastguard Worker   assert(out == begin + result.size());
121*9356374aSAndroid Build Coastguard Worker   return result;
122*9356374aSAndroid Build Coastguard Worker }
123*9356374aSAndroid Build Coastguard Worker 
124*9356374aSAndroid Build Coastguard Worker namespace strings_internal {
125*9356374aSAndroid Build Coastguard Worker 
126*9356374aSAndroid Build Coastguard Worker // Do not call directly - these are not part of the public API.
CatPieces(std::initializer_list<absl::string_view> pieces)127*9356374aSAndroid Build Coastguard Worker std::string CatPieces(std::initializer_list<absl::string_view> pieces) {
128*9356374aSAndroid Build Coastguard Worker   std::string result;
129*9356374aSAndroid Build Coastguard Worker   // Use uint64_t to prevent size_t overflow. We assume it is not possible for
130*9356374aSAndroid Build Coastguard Worker   // in memory strings to overflow a uint64_t.
131*9356374aSAndroid Build Coastguard Worker   constexpr uint64_t kMaxSize = uint64_t{std::numeric_limits<size_t>::max()};
132*9356374aSAndroid Build Coastguard Worker   uint64_t total_size = 0;
133*9356374aSAndroid Build Coastguard Worker   for (absl::string_view piece : pieces) {
134*9356374aSAndroid Build Coastguard Worker     total_size += piece.size();
135*9356374aSAndroid Build Coastguard Worker   }
136*9356374aSAndroid Build Coastguard Worker   ABSL_INTERNAL_CHECK(total_size <= kMaxSize, "size_t overflow");
137*9356374aSAndroid Build Coastguard Worker   strings_internal::STLStringResizeUninitialized(
138*9356374aSAndroid Build Coastguard Worker       &result, static_cast<size_t>(total_size));
139*9356374aSAndroid Build Coastguard Worker 
140*9356374aSAndroid Build Coastguard Worker   char* const begin = &result[0];
141*9356374aSAndroid Build Coastguard Worker   char* out = begin;
142*9356374aSAndroid Build Coastguard Worker   for (absl::string_view piece : pieces) {
143*9356374aSAndroid Build Coastguard Worker     const size_t this_size = piece.size();
144*9356374aSAndroid Build Coastguard Worker     if (this_size != 0) {
145*9356374aSAndroid Build Coastguard Worker       memcpy(out, piece.data(), this_size);
146*9356374aSAndroid Build Coastguard Worker       out += this_size;
147*9356374aSAndroid Build Coastguard Worker     }
148*9356374aSAndroid Build Coastguard Worker   }
149*9356374aSAndroid Build Coastguard Worker   assert(out == begin + result.size());
150*9356374aSAndroid Build Coastguard Worker   return result;
151*9356374aSAndroid Build Coastguard Worker }
152*9356374aSAndroid Build Coastguard Worker 
153*9356374aSAndroid Build Coastguard Worker // It's possible to call StrAppend with an absl::string_view that is itself a
154*9356374aSAndroid Build Coastguard Worker // fragment of the string we're appending to.  However the results of this are
155*9356374aSAndroid Build Coastguard Worker // random. Therefore, check for this in debug mode.  Use unsigned math so we
156*9356374aSAndroid Build Coastguard Worker // only have to do one comparison. Note, there's an exception case: appending an
157*9356374aSAndroid Build Coastguard Worker // empty string is always allowed.
158*9356374aSAndroid Build Coastguard Worker #define ASSERT_NO_OVERLAP(dest, src) \
159*9356374aSAndroid Build Coastguard Worker   assert(((src).size() == 0) ||      \
160*9356374aSAndroid Build Coastguard Worker          (uintptr_t((src).data() - (dest).data()) > uintptr_t((dest).size())))
161*9356374aSAndroid Build Coastguard Worker 
AppendPieces(absl::Nonnull<std::string * > dest,std::initializer_list<absl::string_view> pieces)162*9356374aSAndroid Build Coastguard Worker void AppendPieces(absl::Nonnull<std::string*> dest,
163*9356374aSAndroid Build Coastguard Worker                   std::initializer_list<absl::string_view> pieces) {
164*9356374aSAndroid Build Coastguard Worker   size_t old_size = dest->size();
165*9356374aSAndroid Build Coastguard Worker   size_t to_append = 0;
166*9356374aSAndroid Build Coastguard Worker   for (absl::string_view piece : pieces) {
167*9356374aSAndroid Build Coastguard Worker     ASSERT_NO_OVERLAP(*dest, piece);
168*9356374aSAndroid Build Coastguard Worker     to_append += piece.size();
169*9356374aSAndroid Build Coastguard Worker   }
170*9356374aSAndroid Build Coastguard Worker   STLStringAppendUninitializedAmortized(dest, to_append);
171*9356374aSAndroid Build Coastguard Worker 
172*9356374aSAndroid Build Coastguard Worker   char* const begin = &(*dest)[0];
173*9356374aSAndroid Build Coastguard Worker   char* out = begin + old_size;
174*9356374aSAndroid Build Coastguard Worker   for (absl::string_view piece : pieces) {
175*9356374aSAndroid Build Coastguard Worker     const size_t this_size = piece.size();
176*9356374aSAndroid Build Coastguard Worker     if (this_size != 0) {
177*9356374aSAndroid Build Coastguard Worker       memcpy(out, piece.data(), this_size);
178*9356374aSAndroid Build Coastguard Worker       out += this_size;
179*9356374aSAndroid Build Coastguard Worker     }
180*9356374aSAndroid Build Coastguard Worker   }
181*9356374aSAndroid Build Coastguard Worker   assert(out == begin + dest->size());
182*9356374aSAndroid Build Coastguard Worker }
183*9356374aSAndroid Build Coastguard Worker 
184*9356374aSAndroid Build Coastguard Worker }  // namespace strings_internal
185*9356374aSAndroid Build Coastguard Worker 
StrAppend(absl::Nonnull<std::string * > dest,const AlphaNum & a)186*9356374aSAndroid Build Coastguard Worker void StrAppend(absl::Nonnull<std::string*> dest, const AlphaNum& a) {
187*9356374aSAndroid Build Coastguard Worker   ASSERT_NO_OVERLAP(*dest, a);
188*9356374aSAndroid Build Coastguard Worker   std::string::size_type old_size = dest->size();
189*9356374aSAndroid Build Coastguard Worker   STLStringAppendUninitializedAmortized(dest, a.size());
190*9356374aSAndroid Build Coastguard Worker   char* const begin = &(*dest)[0];
191*9356374aSAndroid Build Coastguard Worker   char* out = begin + old_size;
192*9356374aSAndroid Build Coastguard Worker   out = Append(out, a);
193*9356374aSAndroid Build Coastguard Worker   assert(out == begin + dest->size());
194*9356374aSAndroid Build Coastguard Worker }
195*9356374aSAndroid Build Coastguard Worker 
StrAppend(absl::Nonnull<std::string * > dest,const AlphaNum & a,const AlphaNum & b)196*9356374aSAndroid Build Coastguard Worker void StrAppend(absl::Nonnull<std::string*> dest, const AlphaNum& a,
197*9356374aSAndroid Build Coastguard Worker                const AlphaNum& b) {
198*9356374aSAndroid Build Coastguard Worker   ASSERT_NO_OVERLAP(*dest, a);
199*9356374aSAndroid Build Coastguard Worker   ASSERT_NO_OVERLAP(*dest, b);
200*9356374aSAndroid Build Coastguard Worker   std::string::size_type old_size = dest->size();
201*9356374aSAndroid Build Coastguard Worker   STLStringAppendUninitializedAmortized(dest, a.size() + b.size());
202*9356374aSAndroid Build Coastguard Worker   char* const begin = &(*dest)[0];
203*9356374aSAndroid Build Coastguard Worker   char* out = begin + old_size;
204*9356374aSAndroid Build Coastguard Worker   out = Append(out, a);
205*9356374aSAndroid Build Coastguard Worker   out = Append(out, b);
206*9356374aSAndroid Build Coastguard Worker   assert(out == begin + dest->size());
207*9356374aSAndroid Build Coastguard Worker }
208*9356374aSAndroid Build Coastguard Worker 
StrAppend(absl::Nonnull<std::string * > dest,const AlphaNum & a,const AlphaNum & b,const AlphaNum & c)209*9356374aSAndroid Build Coastguard Worker void StrAppend(absl::Nonnull<std::string*> dest, const AlphaNum& a,
210*9356374aSAndroid Build Coastguard Worker                const AlphaNum& b, const AlphaNum& c) {
211*9356374aSAndroid Build Coastguard Worker   ASSERT_NO_OVERLAP(*dest, a);
212*9356374aSAndroid Build Coastguard Worker   ASSERT_NO_OVERLAP(*dest, b);
213*9356374aSAndroid Build Coastguard Worker   ASSERT_NO_OVERLAP(*dest, c);
214*9356374aSAndroid Build Coastguard Worker   std::string::size_type old_size = dest->size();
215*9356374aSAndroid Build Coastguard Worker   STLStringAppendUninitializedAmortized(dest, a.size() + b.size() + c.size());
216*9356374aSAndroid Build Coastguard Worker   char* const begin = &(*dest)[0];
217*9356374aSAndroid Build Coastguard Worker   char* out = begin + old_size;
218*9356374aSAndroid Build Coastguard Worker   out = Append(out, a);
219*9356374aSAndroid Build Coastguard Worker   out = Append(out, b);
220*9356374aSAndroid Build Coastguard Worker   out = Append(out, c);
221*9356374aSAndroid Build Coastguard Worker   assert(out == begin + dest->size());
222*9356374aSAndroid Build Coastguard Worker }
223*9356374aSAndroid Build Coastguard Worker 
StrAppend(absl::Nonnull<std::string * > dest,const AlphaNum & a,const AlphaNum & b,const AlphaNum & c,const AlphaNum & d)224*9356374aSAndroid Build Coastguard Worker void StrAppend(absl::Nonnull<std::string*> dest, const AlphaNum& a,
225*9356374aSAndroid Build Coastguard Worker                const AlphaNum& b, const AlphaNum& c, const AlphaNum& d) {
226*9356374aSAndroid Build Coastguard Worker   ASSERT_NO_OVERLAP(*dest, a);
227*9356374aSAndroid Build Coastguard Worker   ASSERT_NO_OVERLAP(*dest, b);
228*9356374aSAndroid Build Coastguard Worker   ASSERT_NO_OVERLAP(*dest, c);
229*9356374aSAndroid Build Coastguard Worker   ASSERT_NO_OVERLAP(*dest, d);
230*9356374aSAndroid Build Coastguard Worker   std::string::size_type old_size = dest->size();
231*9356374aSAndroid Build Coastguard Worker   STLStringAppendUninitializedAmortized(
232*9356374aSAndroid Build Coastguard Worker       dest, a.size() + b.size() + c.size() + d.size());
233*9356374aSAndroid Build Coastguard Worker   char* const begin = &(*dest)[0];
234*9356374aSAndroid Build Coastguard Worker   char* out = begin + old_size;
235*9356374aSAndroid Build Coastguard Worker   out = Append(out, a);
236*9356374aSAndroid Build Coastguard Worker   out = Append(out, b);
237*9356374aSAndroid Build Coastguard Worker   out = Append(out, c);
238*9356374aSAndroid Build Coastguard Worker   out = Append(out, d);
239*9356374aSAndroid Build Coastguard Worker   assert(out == begin + dest->size());
240*9356374aSAndroid Build Coastguard Worker }
241*9356374aSAndroid Build Coastguard Worker 
242*9356374aSAndroid Build Coastguard Worker ABSL_NAMESPACE_END
243*9356374aSAndroid Build Coastguard Worker }  // namespace absl
244