/root/doris/be/src/gutil/strings/strcat.cc
Line | Count | Source (jump to first uncovered line) |
1 | | // Copyright 2008 and onwards Google Inc. All rights reserved. |
2 | | |
3 | | #include "gutil/strings/strcat.h" |
4 | | |
5 | | #include "common/logging.h" |
6 | | #include <stdarg.h> |
7 | | #include <stdint.h> |
8 | | #include <string.h> |
9 | | |
10 | | #include "gutil/stl_util.h" |
11 | | #include "gutil/strings/escaping.h" |
12 | | |
13 | | AlphaNum gEmptyAlphaNum(""); |
14 | | |
15 | | // ---------------------------------------------------------------------- |
16 | | // StrCat() |
17 | | // This merges the given strings or integers, with no delimiter. This |
18 | | // is designed to be the fastest possible way to construct a string out |
19 | | // of a mix of raw C strings, StringPieces, strings, and integer values. |
20 | | // ---------------------------------------------------------------------- |
21 | | |
22 | | // Append is merely a version of memcpy that returns the address of the byte |
23 | | // after the area just overwritten. It comes in multiple flavors to minimize |
24 | | // call overhead. |
25 | 0 | static char* Append1(char* out, const AlphaNum& x) { |
26 | 0 | memcpy(out, x.data(), x.size()); |
27 | 0 | return out + x.size(); |
28 | 0 | } |
29 | | |
30 | 91 | static char* Append2(char* out, const AlphaNum& x1, const AlphaNum& x2) { |
31 | 91 | memcpy(out, x1.data(), x1.size()); |
32 | 91 | out += x1.size(); |
33 | | |
34 | 91 | memcpy(out, x2.data(), x2.size()); |
35 | 91 | return out + x2.size(); |
36 | 91 | } |
37 | | |
38 | | static char* Append4(char* out, const AlphaNum& x1, const AlphaNum& x2, const AlphaNum& x3, |
39 | 0 | const AlphaNum& x4) { |
40 | 0 | memcpy(out, x1.data(), x1.size()); |
41 | 0 | out += x1.size(); |
42 | |
|
43 | 0 | memcpy(out, x2.data(), x2.size()); |
44 | 0 | out += x2.size(); |
45 | |
|
46 | 0 | memcpy(out, x3.data(), x3.size()); |
47 | 0 | out += x3.size(); |
48 | |
|
49 | 0 | memcpy(out, x4.data(), x4.size()); |
50 | 0 | return out + x4.size(); |
51 | 0 | } |
52 | | |
53 | 0 | string StrCat(const AlphaNum& a) { |
54 | 0 | return string(a.data(), a.size()); |
55 | 0 | } |
56 | | |
57 | 91 | string StrCat(const AlphaNum& a, const AlphaNum& b) { |
58 | 91 | string result; |
59 | 91 | STLStringResizeUninitialized(&result, a.size() + b.size()); |
60 | 91 | char* const begin = &*result.begin(); |
61 | 91 | char* out = Append2(begin, a, b); |
62 | 91 | DCHECK_EQ(out, begin + result.size()); |
63 | 91 | return result; |
64 | 91 | } |
65 | | |
66 | 0 | string StrCat(const AlphaNum& a, const AlphaNum& b, const AlphaNum& c) { |
67 | 0 | string result; |
68 | 0 | STLStringResizeUninitialized(&result, a.size() + b.size() + c.size()); |
69 | 0 | char* const begin = &*result.begin(); |
70 | 0 | char* out = Append2(begin, a, b); |
71 | 0 | out = Append1(out, c); |
72 | 0 | DCHECK_EQ(out, begin + result.size()); |
73 | 0 | return result; |
74 | 0 | } |
75 | | |
76 | 0 | string StrCat(const AlphaNum& a, const AlphaNum& b, const AlphaNum& c, const AlphaNum& d) { |
77 | 0 | string result; |
78 | 0 | STLStringResizeUninitialized(&result, a.size() + b.size() + c.size() + d.size()); |
79 | 0 | char* const begin = &*result.begin(); |
80 | 0 | char* out = Append4(begin, a, b, c, d); |
81 | 0 | DCHECK_EQ(out, begin + result.size()); |
82 | 0 | return result; |
83 | 0 | } |
84 | | |
85 | | string StrCat(const AlphaNum& a, const AlphaNum& b, const AlphaNum& c, const AlphaNum& d, |
86 | 0 | const AlphaNum& e) { |
87 | 0 | string result; |
88 | 0 | STLStringResizeUninitialized(&result, a.size() + b.size() + c.size() + d.size() + e.size()); |
89 | 0 | char* const begin = &*result.begin(); |
90 | 0 | char* out = Append4(begin, a, b, c, d); |
91 | 0 | out = Append1(out, e); |
92 | 0 | DCHECK_EQ(out, begin + result.size()); |
93 | 0 | return result; |
94 | 0 | } |
95 | | |
96 | | string StrCat(const AlphaNum& a, const AlphaNum& b, const AlphaNum& c, const AlphaNum& d, |
97 | 0 | const AlphaNum& e, const AlphaNum& f) { |
98 | 0 | string result; |
99 | 0 | STLStringResizeUninitialized(&result, |
100 | 0 | a.size() + b.size() + c.size() + d.size() + e.size() + f.size()); |
101 | 0 | char* const begin = &*result.begin(); |
102 | 0 | char* out = Append4(begin, a, b, c, d); |
103 | 0 | out = Append2(out, e, f); |
104 | 0 | DCHECK_EQ(out, begin + result.size()); |
105 | 0 | return result; |
106 | 0 | } |
107 | | |
108 | | string StrCat(const AlphaNum& a, const AlphaNum& b, const AlphaNum& c, const AlphaNum& d, |
109 | 0 | const AlphaNum& e, const AlphaNum& f, const AlphaNum& g) { |
110 | 0 | string result; |
111 | 0 | STLStringResizeUninitialized( |
112 | 0 | &result, a.size() + b.size() + c.size() + d.size() + e.size() + f.size() + g.size()); |
113 | 0 | char* const begin = &*result.begin(); |
114 | 0 | char* out = Append4(begin, a, b, c, d); |
115 | 0 | out = Append2(out, e, f); |
116 | 0 | out = Append1(out, g); |
117 | 0 | DCHECK_EQ(out, begin + result.size()); |
118 | 0 | return result; |
119 | 0 | } |
120 | | |
121 | | string StrCat(const AlphaNum& a, const AlphaNum& b, const AlphaNum& c, const AlphaNum& d, |
122 | 0 | const AlphaNum& e, const AlphaNum& f, const AlphaNum& g, const AlphaNum& h) { |
123 | 0 | string result; |
124 | 0 | STLStringResizeUninitialized(&result, a.size() + b.size() + c.size() + d.size() + e.size() + |
125 | 0 | f.size() + g.size() + h.size()); |
126 | 0 | char* const begin = &*result.begin(); |
127 | 0 | char* out = Append4(begin, a, b, c, d); |
128 | 0 | out = Append4(out, e, f, g, h); |
129 | 0 | DCHECK_EQ(out, begin + result.size()); |
130 | 0 | return result; |
131 | 0 | } |
132 | | |
133 | | namespace strings { |
134 | | namespace internal { |
135 | | |
136 | | // StrCat with this many params is exceedingly rare, but it has been |
137 | | // requested... therefore we'll rely on default arguments to make calling |
138 | | // slightly less efficient, to preserve code size. |
139 | 0 | string StrCatNineOrMore(const AlphaNum* a, ...) { |
140 | 0 | string result; |
141 | |
|
142 | 0 | va_list args; |
143 | 0 | va_start(args, a); |
144 | 0 | size_t size = a->size(); |
145 | 0 | while (const AlphaNum* arg = va_arg(args, const AlphaNum*)) { |
146 | 0 | size += arg->size(); |
147 | 0 | } |
148 | 0 | STLStringResizeUninitialized(&result, size); |
149 | 0 | va_end(args); |
150 | 0 | va_start(args, a); |
151 | 0 | char* const begin = &*result.begin(); |
152 | 0 | char* out = Append1(begin, *a); |
153 | 0 | while (const AlphaNum* arg = va_arg(args, const AlphaNum*)) { |
154 | 0 | out = Append1(out, *arg); |
155 | 0 | } |
156 | 0 | va_end(args); |
157 | 0 | DCHECK_EQ(out, begin + size); |
158 | 0 | return result; |
159 | 0 | } |
160 | | |
161 | | } // namespace internal |
162 | | } // namespace strings |
163 | | |
164 | | // It's possible to call StrAppend with a StringPiece that is itself a fragment |
165 | | // of the string we're appending to. However the results of this are random. |
166 | | // Therefore, check for this in debug mode. Use unsigned math so we only have |
167 | | // to do one comparison. |
168 | | #define DCHECK_NO_OVERLAP(dest, src) \ |
169 | 0 | DCHECK_GT(uintptr_t((src).data() - (dest).data()), uintptr_t((dest).size())) |
170 | | |
171 | 0 | void StrAppend(string* result, const AlphaNum& a) { |
172 | 0 | DCHECK_NO_OVERLAP(*result, a); |
173 | 0 | result->append(a.data(), a.size()); |
174 | 0 | } |
175 | | |
176 | 0 | void StrAppend(string* result, const AlphaNum& a, const AlphaNum& b) { |
177 | 0 | DCHECK_NO_OVERLAP(*result, a); |
178 | 0 | DCHECK_NO_OVERLAP(*result, b); |
179 | 0 | string::size_type old_size = result->size(); |
180 | 0 | STLStringResizeUninitialized(result, old_size + a.size() + b.size()); |
181 | 0 | char* const begin = &*result->begin(); |
182 | 0 | char* out = Append2(begin + old_size, a, b); |
183 | 0 | DCHECK_EQ(out, begin + result->size()); |
184 | 0 | } |
185 | | |
186 | 0 | void StrAppend(string* result, const AlphaNum& a, const AlphaNum& b, const AlphaNum& c) { |
187 | 0 | DCHECK_NO_OVERLAP(*result, a); |
188 | 0 | DCHECK_NO_OVERLAP(*result, b); |
189 | 0 | DCHECK_NO_OVERLAP(*result, c); |
190 | 0 | string::size_type old_size = result->size(); |
191 | 0 | STLStringResizeUninitialized(result, old_size + a.size() + b.size() + c.size()); |
192 | 0 | char* const begin = &*result->begin(); |
193 | 0 | char* out = Append2(begin + old_size, a, b); |
194 | 0 | out = Append1(out, c); |
195 | 0 | DCHECK_EQ(out, begin + result->size()); |
196 | 0 | } |
197 | | |
198 | | void StrAppend(string* result, const AlphaNum& a, const AlphaNum& b, const AlphaNum& c, |
199 | 0 | const AlphaNum& d) { |
200 | 0 | DCHECK_NO_OVERLAP(*result, a); |
201 | 0 | DCHECK_NO_OVERLAP(*result, b); |
202 | 0 | DCHECK_NO_OVERLAP(*result, c); |
203 | 0 | DCHECK_NO_OVERLAP(*result, d); |
204 | 0 | string::size_type old_size = result->size(); |
205 | 0 | STLStringResizeUninitialized(result, old_size + a.size() + b.size() + c.size() + d.size()); |
206 | 0 | char* const begin = &*result->begin(); |
207 | 0 | char* out = Append4(begin + old_size, a, b, c, d); |
208 | 0 | DCHECK_EQ(out, begin + result->size()); |
209 | 0 | } |
210 | | |
211 | | // StrAppend with this many params is even rarer than with StrCat. |
212 | | // Therefore we'll again rely on default arguments to make calling |
213 | | // slightly less efficient, to preserve code size. |
214 | | void StrAppend(string* result, const AlphaNum& a, const AlphaNum& b, const AlphaNum& c, |
215 | | const AlphaNum& d, const AlphaNum& e, const AlphaNum& f, const AlphaNum& g, |
216 | 0 | const AlphaNum& h, const AlphaNum& i) { |
217 | 0 | DCHECK_NO_OVERLAP(*result, a); |
218 | 0 | DCHECK_NO_OVERLAP(*result, b); |
219 | 0 | DCHECK_NO_OVERLAP(*result, c); |
220 | 0 | DCHECK_NO_OVERLAP(*result, d); |
221 | 0 | DCHECK_NO_OVERLAP(*result, e); |
222 | 0 | DCHECK_NO_OVERLAP(*result, f); |
223 | 0 | DCHECK_NO_OVERLAP(*result, g); |
224 | 0 | DCHECK_NO_OVERLAP(*result, h); |
225 | 0 | DCHECK_NO_OVERLAP(*result, i); |
226 | 0 | string::size_type old_size = result->size(); |
227 | 0 | STLStringResizeUninitialized(result, old_size + a.size() + b.size() + c.size() + d.size() + |
228 | 0 | e.size() + f.size() + g.size() + h.size() + |
229 | 0 | i.size()); |
230 | 0 | char* const begin = &*result->begin(); |
231 | 0 | char* out = Append4(begin + old_size, a, b, c, d); |
232 | 0 | out = Append4(out, e, f, g, h); |
233 | 0 | out = Append1(out, i); |
234 | 0 | DCHECK_EQ(out, begin + result->size()); |
235 | 0 | } |