xref: /aosp_15_r20/external/tensorflow/tensorflow/core/platform/strcat.cc (revision b6fb3261f9314811a0f4371741dbb8839866f948)
1 /* Copyright 2015 The TensorFlow Authors. All Rights Reserved.
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     http://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 
16 #include "tensorflow/core/platform/strcat.h"
17 
18 #include <stdarg.h>
19 #include <stdint.h>
20 #include <stdio.h>
21 #include <string.h>
22 
23 #include <algorithm>
24 
25 #include "absl/meta/type_traits.h"
26 #include "tensorflow/core/platform/logging.h"
27 
28 namespace tensorflow {
29 namespace strings {
30 
AlphaNum(Hex hex)31 AlphaNum::AlphaNum(Hex hex) {
32   char *const end = &digits_[kFastToBufferSize];
33   char *writer = end;
34   uint64 value = hex.value;
35   uint64 width = hex.spec;
36   // We accomplish minimum width by OR'ing in 0x10000 to the user's value,
37   // where 0x10000 is the smallest hex number that is as wide as the user
38   // asked for.
39   uint64 mask = (static_cast<uint64>(1) << (width - 1) * 4) | value;
40   static const char hexdigits[] = "0123456789abcdef";
41   do {
42     *--writer = hexdigits[value & 0xF];
43     value >>= 4;
44     mask >>= 4;
45   } while (mask != 0);
46   piece_ = StringPiece(writer, end - writer);
47 }
48 
49 // ----------------------------------------------------------------------
50 // StrCat()
51 //    This merges the given strings or integers, with no delimiter.  This
52 //    is designed to be the fastest possible way to construct a string out
53 //    of a mix of raw C strings, StringPieces, strings, and integer values.
54 // ----------------------------------------------------------------------
55 
56 // Append is merely a version of memcpy that returns the address of the byte
57 // after the area just overwritten.  It comes in multiple flavors to minimize
58 // call overhead.
Append1(char * out,const AlphaNum & x)59 static char *Append1(char *out, const AlphaNum &x) {
60   memcpy(out, x.data(), x.size());
61   return out + x.size();
62 }
63 
Append2(char * out,const AlphaNum & x1,const AlphaNum & x2)64 static char *Append2(char *out, const AlphaNum &x1, const AlphaNum &x2) {
65   memcpy(out, x1.data(), x1.size());
66   out += x1.size();
67 
68   memcpy(out, x2.data(), x2.size());
69   return out + x2.size();
70 }
71 
Append4(char * out,const AlphaNum & x1,const AlphaNum & x2,const AlphaNum & x3,const AlphaNum & x4)72 static char *Append4(char *out, const AlphaNum &x1, const AlphaNum &x2,
73                      const AlphaNum &x3, const AlphaNum &x4) {
74   memcpy(out, x1.data(), x1.size());
75   out += x1.size();
76 
77   memcpy(out, x2.data(), x2.size());
78   out += x2.size();
79 
80   memcpy(out, x3.data(), x3.size());
81   out += x3.size();
82 
83   memcpy(out, x4.data(), x4.size());
84   return out + x4.size();
85 }
86 
StrCat(const AlphaNum & a)87 string StrCat(const AlphaNum &a) { return string(a.data(), a.size()); }
88 
StrCat(const AlphaNum & a,const AlphaNum & b)89 string StrCat(const AlphaNum &a, const AlphaNum &b) {
90   string result(a.size() + b.size(), '\0');
91   char *const begin = &*result.begin();
92   char *out = Append2(begin, a, b);
93   DCHECK_EQ(out, begin + result.size());
94   return result;
95 }
96 
StrCat(const AlphaNum & a,const AlphaNum & b,const AlphaNum & c)97 string StrCat(const AlphaNum &a, const AlphaNum &b, const AlphaNum &c) {
98   string result(a.size() + b.size() + c.size(), '\0');
99   char *const begin = &*result.begin();
100   char *out = Append2(begin, a, b);
101   out = Append1(out, c);
102   DCHECK_EQ(out, begin + result.size());
103   return result;
104 }
105 
StrCat(const AlphaNum & a,const AlphaNum & b,const AlphaNum & c,const AlphaNum & d)106 string StrCat(const AlphaNum &a, const AlphaNum &b, const AlphaNum &c,
107               const AlphaNum &d) {
108   string result(a.size() + b.size() + c.size() + d.size(), '\0');
109   char *const begin = &*result.begin();
110   char *out = Append4(begin, a, b, c, d);
111   DCHECK_EQ(out, begin + result.size());
112   return result;
113 }
114 
115 namespace {
116 // HasMember is true_type or false_type, depending on whether or not
117 // T has a __resize_default_init member. Resize will call the
118 // __resize_default_init member if it exists, and will call the resize
119 // member otherwise.
120 template <typename string_type, typename = void>
121 struct ResizeUninitializedTraits {
122   using HasMember = std::false_type;
Resizetensorflow::strings::__anon9e53eb1c0111::ResizeUninitializedTraits123   static void Resize(string_type* s, size_t new_size) { s->resize(new_size); }
124 };
125 
126 // __resize_default_init is provided by libc++ >= 8.0.
127 template <typename string_type>
128 struct ResizeUninitializedTraits<
129     string_type, absl::void_t<decltype(std::declval<string_type&>()
130                                            .__resize_default_init(237))> > {
131   using HasMember = std::true_type;
Resizetensorflow::strings::__anon9e53eb1c0111::ResizeUninitializedTraits132   static void Resize(string_type* s, size_t new_size) {
133     s->__resize_default_init(new_size);
134   }
135 };
136 
STLStringResizeUninitialized(string * s,size_t new_size)137 static inline void STLStringResizeUninitialized(string* s, size_t new_size) {
138   ResizeUninitializedTraits<string>::Resize(s, new_size);
139 }
140 
141 // Used to ensure exponential growth so that the amortized complexity of
142 // increasing the string size by a small amount is O(1), in contrast to
143 // O(str->size()) in the case of precise growth.
144 // TODO(b/217943845): Would be better to use absl::strings so we don't need to
145 // keep cherry-picking performance fixes.
146 template <typename string_type>
STLStringReserveAmortized(string_type * s,size_t new_size)147 void STLStringReserveAmortized(string_type *s, size_t new_size) {
148   const size_t cap = s->capacity();
149   if (new_size > cap) {
150     // Make sure to always grow by at least a factor of 2x.
151     s->reserve((std::max)(new_size, 2 * cap));
152   }
153 }
154 
155 // Like STLStringResizeUninitialized(str, new_size), except guaranteed to use
156 // exponential growth so that the amortized complexity of increasing the string
157 // size by a small amount is O(1), in contrast to O(str->size()) in the case of
158 // precise growth.
159 template <typename string_type>
STLStringResizeUninitializedAmortized(string_type * s,size_t new_size)160 void STLStringResizeUninitializedAmortized(string_type *s, size_t new_size) {
161   STLStringReserveAmortized(s, new_size);
162   STLStringResizeUninitialized(s, new_size);
163 }
164 
165 }  // namespace
166 namespace internal {
167 
168 // Do not call directly - these are not part of the public API.
CatPieces(std::initializer_list<StringPiece> pieces)169 string CatPieces(std::initializer_list<StringPiece> pieces) {
170   size_t total_size = 0;
171   for (const StringPiece piece : pieces) total_size += piece.size();
172   string result(total_size, '\0');
173 
174   char *const begin = &*result.begin();
175   char *out = begin;
176   for (const StringPiece piece : pieces) {
177     const size_t this_size = piece.size();
178     memcpy(out, piece.data(), this_size);
179     out += this_size;
180   }
181   DCHECK_EQ(out, begin + result.size());
182   return result;
183 }
184 
185 // It's possible to call StrAppend with a StringPiece that is itself a fragment
186 // of the string we're appending to.  However the results of this are random.
187 // Therefore, check for this in debug mode.  Use unsigned math so we only have
188 // to do one comparison.
189 #define DCHECK_NO_OVERLAP(dest, src) \
190   DCHECK_GE(uintptr_t((src).data() - (dest).data()), uintptr_t((dest).size()))
191 
AppendPieces(string * result,std::initializer_list<StringPiece> pieces)192 void AppendPieces(string *result, std::initializer_list<StringPiece> pieces) {
193   size_t old_size = result->size();
194   size_t total_size = old_size;
195   for (const StringPiece piece : pieces) {
196     DCHECK_NO_OVERLAP(*result, piece);
197     total_size += piece.size();
198   }
199   STLStringResizeUninitializedAmortized(result, total_size);
200 
201   char *const begin = &*result->begin();
202   char *out = begin + old_size;
203   for (const StringPiece piece : pieces) {
204     const size_t this_size = piece.size();
205     memcpy(out, piece.data(), this_size);
206     out += this_size;
207   }
208   DCHECK_EQ(out, begin + result->size());
209 }
210 
211 }  // namespace internal
212 
StrAppend(string * result,const AlphaNum & a)213 void StrAppend(string *result, const AlphaNum &a) {
214   DCHECK_NO_OVERLAP(*result, a);
215   result->append(a.data(), a.size());
216 }
217 
StrAppend(string * result,const AlphaNum & a,const AlphaNum & b)218 void StrAppend(string *result, const AlphaNum &a, const AlphaNum &b) {
219   DCHECK_NO_OVERLAP(*result, a);
220   DCHECK_NO_OVERLAP(*result, b);
221   string::size_type old_size = result->size();
222   STLStringResizeUninitializedAmortized(result, old_size + a.size() + b.size());
223   char *const begin = &*result->begin();
224   char *out = Append2(begin + old_size, a, b);
225   DCHECK_EQ(out, begin + result->size());
226 }
227 
StrAppend(string * result,const AlphaNum & a,const AlphaNum & b,const AlphaNum & c)228 void StrAppend(string *result, const AlphaNum &a, const AlphaNum &b,
229                const AlphaNum &c) {
230   DCHECK_NO_OVERLAP(*result, a);
231   DCHECK_NO_OVERLAP(*result, b);
232   DCHECK_NO_OVERLAP(*result, c);
233   string::size_type old_size = result->size();
234   STLStringResizeUninitializedAmortized(
235       result, old_size + a.size() + b.size() + c.size());
236   char *const begin = &*result->begin();
237   char *out = Append2(begin + old_size, a, b);
238   out = Append1(out, c);
239   DCHECK_EQ(out, begin + result->size());
240 }
241 
StrAppend(string * result,const AlphaNum & a,const AlphaNum & b,const AlphaNum & c,const AlphaNum & d)242 void StrAppend(string *result, const AlphaNum &a, const AlphaNum &b,
243                const AlphaNum &c, const AlphaNum &d) {
244   DCHECK_NO_OVERLAP(*result, a);
245   DCHECK_NO_OVERLAP(*result, b);
246   DCHECK_NO_OVERLAP(*result, c);
247   DCHECK_NO_OVERLAP(*result, d);
248   string::size_type old_size = result->size();
249   STLStringResizeUninitializedAmortized(
250       result, old_size + a.size() + b.size() + c.size() + d.size());
251   char *const begin = &*result->begin();
252   char *out = Append4(begin + old_size, a, b, c, d);
253   DCHECK_EQ(out, begin + result->size());
254 }
255 
256 }  // namespace strings
257 }  // namespace tensorflow
258