/Users/deen/code/yugabyte-db/src/yb/gutil/strings/strcat.cc
Line | Count | Source (jump to first uncovered line) |
1 | | // Copyright 2008 and onwards Google Inc. All rights reserved. |
2 | | // |
3 | | // The following only applies to changes made to this file as part of YugaByte development. |
4 | | // |
5 | | // Portions Copyright (c) YugaByte, Inc. |
6 | | // |
7 | | // Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except |
8 | | // in compliance with the License. You may obtain a copy of the License at |
9 | | // |
10 | | // http://www.apache.org/licenses/LICENSE-2.0 |
11 | | // |
12 | | // Unless required by applicable law or agreed to in writing, software distributed under the License |
13 | | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express |
14 | | // or implied. See the License for the specific language governing permissions and limitations |
15 | | // under the License. |
16 | | // |
17 | | |
18 | | #include "yb/gutil/strings/strcat.h" |
19 | | |
20 | | #include <stdarg.h> |
21 | | #include <stdint.h> |
22 | | #include <stdio.h> |
23 | | #include <string.h> |
24 | | |
25 | | #include <glog/logging.h> |
26 | | #include "yb/gutil/stl_util.h" |
27 | | |
28 | | AlphaNum gEmptyAlphaNum(""); |
29 | | |
30 | | // ---------------------------------------------------------------------- |
31 | | // StrCat() |
32 | | // This merges the given strings or integers, with no delimiter. This |
33 | | // is designed to be the fastest possible way to construct a string out |
34 | | // of a mix of raw C strings, GStringPieces, strings, and integer values. |
35 | | // ---------------------------------------------------------------------- |
36 | | |
37 | | // Append is merely a version of memcpy that returns the address of the byte |
38 | | // after the area just overwritten. It comes in multiple flavors to minimize |
39 | | // call overhead. |
40 | 44.9k | static char *Append1(char *out, const AlphaNum &x) { |
41 | 44.9k | memcpy(out, x.data(), x.size()); |
42 | 44.9k | return out + x.size(); |
43 | 44.9k | } |
44 | | |
45 | 148k | static char *Append2(char *out, const AlphaNum &x1, const AlphaNum &x2) { |
46 | 148k | memcpy(out, x1.data(), x1.size()); |
47 | 148k | out += x1.size(); |
48 | | |
49 | 148k | memcpy(out, x2.data(), x2.size()); |
50 | 148k | return out + x2.size(); |
51 | 148k | } |
52 | | |
53 | | static char *Append4(char *out, |
54 | | const AlphaNum &x1, const AlphaNum &x2, |
55 | 103k | const AlphaNum &x3, const AlphaNum &x4) { |
56 | 103k | memcpy(out, x1.data(), x1.size()); |
57 | 103k | out += x1.size(); |
58 | | |
59 | 103k | memcpy(out, x2.data(), x2.size()); |
60 | 103k | out += x2.size(); |
61 | | |
62 | 103k | memcpy(out, x3.data(), x3.size()); |
63 | 103k | out += x3.size(); |
64 | | |
65 | 103k | memcpy(out, x4.data(), x4.size()); |
66 | 103k | return out + x4.size(); |
67 | 103k | } |
68 | | |
69 | 0 | string StrCat(const AlphaNum &a) { |
70 | 0 | return string(a.data(), a.size()); |
71 | 0 | } |
72 | | |
73 | 0 | string StrCat(const AlphaNum &a, const AlphaNum &b) { |
74 | 0 | string result; |
75 | 0 | STLStringResizeUninitialized(&result, a.size() + b.size()); |
76 | 0 | char *const begin = &*result.begin(); |
77 | 0 | char *out = Append2(begin, a, b); |
78 | 0 | DCHECK_EQ(out, begin + result.size()); |
79 | 0 | return result; |
80 | 0 | } |
81 | | |
82 | 44.5k | string StrCat(const AlphaNum &a, const AlphaNum &b, const AlphaNum &c) { |
83 | 44.5k | string result; |
84 | 44.5k | STLStringResizeUninitialized(&result, a.size() + b.size() + c.size()); |
85 | 44.5k | char *const begin = &*result.begin(); |
86 | 44.5k | char *out = Append2(begin, a, b); |
87 | 44.5k | out = Append1(out, c); |
88 | 44.5k | DCHECK_EQ(out, begin + result.size()); |
89 | 44.5k | return result; |
90 | 44.5k | } |
91 | | |
92 | | string StrCat(const AlphaNum &a, const AlphaNum &b, const AlphaNum &c, |
93 | 1.02k | const AlphaNum &d) { |
94 | 1.02k | string result; |
95 | 1.02k | STLStringResizeUninitialized(&result, |
96 | 1.02k | a.size() + b.size() + c.size() + d.size()); |
97 | 1.02k | char *const begin = &*result.begin(); |
98 | 1.02k | char *out = Append4(begin, a, b, c, d); |
99 | 1.02k | DCHECK_EQ(out, begin + result.size()); |
100 | 1.02k | return result; |
101 | 1.02k | } |
102 | | |
103 | | string StrCat(const AlphaNum &a, const AlphaNum &b, const AlphaNum &c, |
104 | 0 | const AlphaNum &d, const AlphaNum &e) { |
105 | 0 | string result; |
106 | 0 | STLStringResizeUninitialized(&result, |
107 | 0 | a.size() + b.size() + c.size() + d.size() + e.size()); |
108 | 0 | char *const begin = &*result.begin(); |
109 | 0 | char *out = Append4(begin, a, b, c, d); |
110 | 0 | out = Append1(out, e); |
111 | 0 | DCHECK_EQ(out, begin + result.size()); |
112 | 0 | return result; |
113 | 0 | } |
114 | | |
115 | | string StrCat(const AlphaNum &a, const AlphaNum &b, const AlphaNum &c, |
116 | 103k | const AlphaNum &d, const AlphaNum &e, const AlphaNum &f) { |
117 | 103k | string result; |
118 | 103k | STLStringResizeUninitialized(&result, |
119 | 103k | a.size() + b.size() + c.size() + d.size() + e.size() + f.size()); |
120 | 103k | char *const begin = &*result.begin(); |
121 | 103k | char *out = Append4(begin, a, b, c, d); |
122 | 103k | out = Append2(out, e, f); |
123 | 103k | DCHECK_EQ(out, begin + result.size()); |
124 | 103k | return result; |
125 | 103k | } |
126 | | |
127 | | string StrCat(const AlphaNum &a, const AlphaNum &b, const AlphaNum &c, |
128 | | const AlphaNum &d, const AlphaNum &e, const AlphaNum &f, |
129 | 0 | const AlphaNum &g) { |
130 | 0 | string result; |
131 | 0 | STLStringResizeUninitialized(&result, |
132 | 0 | a.size() + b.size() + c.size() + d.size() + e.size() |
133 | 0 | + f.size() + g.size()); |
134 | 0 | char *const begin = &*result.begin(); |
135 | 0 | char *out = Append4(begin, a, b, c, d); |
136 | 0 | out = Append2(out, e, f); |
137 | 0 | out = Append1(out, g); |
138 | 0 | DCHECK_EQ(out, begin + result.size()); |
139 | 0 | return result; |
140 | 0 | } |
141 | | |
142 | | string StrCat(const AlphaNum &a, const AlphaNum &b, const AlphaNum &c, |
143 | | const AlphaNum &d, const AlphaNum &e, const AlphaNum &f, |
144 | 0 | const AlphaNum &g, const AlphaNum &h) { |
145 | 0 | string result; |
146 | 0 | STLStringResizeUninitialized(&result, |
147 | 0 | a.size() + b.size() + c.size() + d.size() + e.size() |
148 | 0 | + f.size() + g.size() + h.size()); |
149 | 0 | char *const begin = &*result.begin(); |
150 | 0 | char *out = Append4(begin, a, b, c, d); |
151 | 0 | out = Append4(out, e, f, g, h); |
152 | 0 | DCHECK_EQ(out, begin + result.size()); |
153 | 0 | return result; |
154 | 0 | } |
155 | | |
156 | | namespace strings { |
157 | | namespace internal { |
158 | | |
159 | | // StrCat with this many params is exceedingly rare, but it has been |
160 | | // requested... therefore we'll rely on default arguments to make calling |
161 | | // slightly less efficient, to preserve code size. |
162 | 0 | string StrCatNineOrMore(const AlphaNum *a, ...) { |
163 | 0 | string result; |
164 | |
|
165 | 0 | va_list args; |
166 | 0 | va_start(args, a); |
167 | 0 | size_t size = a->size(); |
168 | 0 | while (const AlphaNum *arg = va_arg(args, const AlphaNum *)) { |
169 | 0 | size += arg->size(); |
170 | 0 | } |
171 | 0 | STLStringResizeUninitialized(&result, size); |
172 | 0 | va_end(args); |
173 | 0 | va_start(args, a); |
174 | 0 | char *const begin = &*result.begin(); |
175 | 0 | char *out = Append1(begin, *a); |
176 | 0 | while (const AlphaNum *arg = va_arg(args, const AlphaNum *)) { |
177 | 0 | out = Append1(out, *arg); |
178 | 0 | } |
179 | 0 | va_end(args); |
180 | 0 | DCHECK_EQ(out, begin + size); |
181 | 0 | return result; |
182 | 0 | } |
183 | | |
184 | | } // namespace internal |
185 | | } // namespace strings |
186 | | |
187 | | // It's possible to call StrAppend with a GStringPiece that is itself a fragment |
188 | | // of the string we're appending to. However the results of this are random. |
189 | | // Therefore, check for this in debug mode. Use unsigned math so we only have |
190 | | // to do one comparison. |
191 | | #define DCHECK_NO_OVERLAP(dest, src) \ |
192 | 5.62k | DCHECK_GT(uintptr_t((src).data() - (dest).data()), uintptr_t((dest).size())) |
193 | | |
194 | 3.15k | void StrAppend(string *result, const AlphaNum &a) { |
195 | 3.15k | DCHECK_NO_OVERLAP(*result, a); |
196 | 3.15k | result->append(a.data(), a.size()); |
197 | 3.15k | } |
198 | | |
199 | 756 | void StrAppend(string *result, const AlphaNum &a, const AlphaNum &b) { |
200 | 756 | DCHECK_NO_OVERLAP(*result, a); |
201 | 756 | DCHECK_NO_OVERLAP(*result, b); |
202 | 756 | string::size_type old_size = result->size(); |
203 | 756 | STLStringResizeUninitialized(result, old_size + a.size() + b.size()); |
204 | 756 | char *const begin = &*result->begin(); |
205 | 756 | char *out = Append2(begin + old_size, a, b); |
206 | 756 | DCHECK_EQ(out, begin + result->size()); |
207 | 756 | } |
208 | | |
209 | | void StrAppend(string *result, |
210 | 318 | const AlphaNum &a, const AlphaNum &b, const AlphaNum &c) { |
211 | 318 | DCHECK_NO_OVERLAP(*result, a); |
212 | 318 | DCHECK_NO_OVERLAP(*result, b); |
213 | 318 | DCHECK_NO_OVERLAP(*result, c); |
214 | 318 | string::size_type old_size = result->size(); |
215 | 318 | STLStringResizeUninitialized(result, |
216 | 318 | old_size + a.size() + b.size() + c.size()); |
217 | 318 | char *const begin = &*result->begin(); |
218 | 318 | char *out = Append2(begin + old_size, a, b); |
219 | 318 | out = Append1(out, c); |
220 | 318 | DCHECK_EQ(out, begin + result->size()); |
221 | 318 | } |
222 | | |
223 | | void StrAppend(string *result, |
224 | | const AlphaNum &a, const AlphaNum &b, |
225 | 0 | const AlphaNum &c, const AlphaNum &d) { |
226 | 0 | DCHECK_NO_OVERLAP(*result, a); |
227 | 0 | DCHECK_NO_OVERLAP(*result, b); |
228 | 0 | DCHECK_NO_OVERLAP(*result, c); |
229 | 0 | DCHECK_NO_OVERLAP(*result, d); |
230 | 0 | string::size_type old_size = result->size(); |
231 | 0 | STLStringResizeUninitialized(result, |
232 | 0 | old_size + a.size() + b.size() + c.size() + d.size()); |
233 | 0 | char *const begin = &*result->begin(); |
234 | 0 | char *out = Append4(begin + old_size, a, b, c, d); |
235 | 0 | DCHECK_EQ(out, begin + result->size()); |
236 | 0 | } |
237 | | |
238 | | // StrAppend with this many params is even rarer than with StrCat. |
239 | | // Therefore we'll again rely on default arguments to make calling |
240 | | // slightly less efficient, to preserve code size. |
241 | | void StrAppend(string *result, |
242 | | const AlphaNum &a, const AlphaNum &b, const AlphaNum &c, |
243 | | const AlphaNum &d, const AlphaNum &e, const AlphaNum &f, |
244 | 0 | const AlphaNum &g, const AlphaNum &h, const AlphaNum &i) { |
245 | 0 | DCHECK_NO_OVERLAP(*result, a); |
246 | 0 | DCHECK_NO_OVERLAP(*result, b); |
247 | 0 | DCHECK_NO_OVERLAP(*result, c); |
248 | 0 | DCHECK_NO_OVERLAP(*result, d); |
249 | 0 | DCHECK_NO_OVERLAP(*result, e); |
250 | 0 | DCHECK_NO_OVERLAP(*result, f); |
251 | 0 | DCHECK_NO_OVERLAP(*result, g); |
252 | 0 | DCHECK_NO_OVERLAP(*result, h); |
253 | 0 | DCHECK_NO_OVERLAP(*result, i); |
254 | 0 | string::size_type old_size = result->size(); |
255 | 0 | STLStringResizeUninitialized(result, |
256 | 0 | old_size + a.size() + b.size() + c.size() + d.size() |
257 | 0 | + e.size() + f.size() + g.size() + h.size() + i.size()); |
258 | 0 | char *const begin = &*result->begin(); |
259 | 0 | char *out = Append4(begin + old_size, a, b, c, d); |
260 | 0 | out = Append4(out, e, f, g, h); |
261 | 0 | out = Append1(out, i); |
262 | 0 | DCHECK_EQ(out, begin + result->size()); |
263 | 0 | } |