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/lib/strings/strcat.h" |
17 | |
18 | #include <stdarg.h> |
19 | #include <stdint.h> |
20 | #include <stdio.h> |
21 | #include <string.h> |
22 | |
23 | #include "tensorflow/core/lib/gtl/stl_util.h" |
24 | #include "tensorflow/core/platform/logging.h" |
25 | |
26 | namespace tensorflow { |
27 | namespace strings { |
28 | |
29 | AlphaNum::AlphaNum(Hex hex) { |
30 | char *const end = &digits_[kFastToBufferSize]; |
31 | char *writer = end; |
32 | uint64 value = hex.value; |
33 | uint64 width = hex.spec; |
34 | // We accomplish minimum width by OR'ing in 0x10000 to the user's value, |
35 | // where 0x10000 is the smallest hex number that is as wide as the user |
36 | // asked for. |
37 | uint64 mask = (static_cast<uint64>(1) << (width - 1) * 4) | value; |
38 | static const char hexdigits[] = "0123456789abcdef" ; |
39 | do { |
40 | *--writer = hexdigits[value & 0xF]; |
41 | value >>= 4; |
42 | mask >>= 4; |
43 | } while (mask != 0); |
44 | piece_ = StringPiece(writer, end - writer); |
45 | } |
46 | |
47 | // ---------------------------------------------------------------------- |
48 | // StrCat() |
49 | // This merges the given strings or integers, with no delimiter. This |
50 | // is designed to be the fastest possible way to construct a string out |
51 | // of a mix of raw C strings, StringPieces, strings, and integer values. |
52 | // ---------------------------------------------------------------------- |
53 | |
54 | // Append is merely a version of memcpy that returns the address of the byte |
55 | // after the area just overwritten. It comes in multiple flavors to minimize |
56 | // call overhead. |
57 | static char *Append1(char *out, const AlphaNum &x) { |
58 | memcpy(out, x.data(), x.size()); |
59 | return out + x.size(); |
60 | } |
61 | |
62 | static char *Append2(char *out, const AlphaNum &x1, const AlphaNum &x2) { |
63 | memcpy(out, x1.data(), x1.size()); |
64 | out += x1.size(); |
65 | |
66 | memcpy(out, x2.data(), x2.size()); |
67 | return out + x2.size(); |
68 | } |
69 | |
70 | static char *Append4(char *out, const AlphaNum &x1, const AlphaNum &x2, |
71 | const AlphaNum &x3, const AlphaNum &x4) { |
72 | memcpy(out, x1.data(), x1.size()); |
73 | out += x1.size(); |
74 | |
75 | memcpy(out, x2.data(), x2.size()); |
76 | out += x2.size(); |
77 | |
78 | memcpy(out, x3.data(), x3.size()); |
79 | out += x3.size(); |
80 | |
81 | memcpy(out, x4.data(), x4.size()); |
82 | return out + x4.size(); |
83 | } |
84 | |
85 | string StrCat(const AlphaNum &a) { return string(a.data(), a.size()); } |
86 | |
87 | string StrCat(const AlphaNum &a, const AlphaNum &b) { |
88 | string result; |
89 | gtl::STLStringResizeUninitialized(&result, a.size() + b.size()); |
90 | char *const begin = &*result.begin(); |
91 | char *out = Append2(begin, a, b); |
92 | DCHECK_EQ(out, begin + result.size()); |
93 | return result; |
94 | } |
95 | |
96 | string StrCat(const AlphaNum &a, const AlphaNum &b, const AlphaNum &c) { |
97 | string result; |
98 | gtl::STLStringResizeUninitialized(&result, a.size() + b.size() + c.size()); |
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 | |
106 | string StrCat(const AlphaNum &a, const AlphaNum &b, const AlphaNum &c, |
107 | const AlphaNum &d) { |
108 | string result; |
109 | gtl::STLStringResizeUninitialized(&result, |
110 | a.size() + b.size() + c.size() + d.size()); |
111 | char *const begin = &*result.begin(); |
112 | char *out = Append4(begin, a, b, c, d); |
113 | DCHECK_EQ(out, begin + result.size()); |
114 | return result; |
115 | } |
116 | |
117 | namespace internal { |
118 | |
119 | // Do not call directly - these are not part of the public API. |
120 | string CatPieces(std::initializer_list<StringPiece> pieces) { |
121 | string result; |
122 | size_t total_size = 0; |
123 | for (const StringPiece piece : pieces) total_size += piece.size(); |
124 | gtl::STLStringResizeUninitialized(&result, total_size); |
125 | |
126 | char *const begin = &*result.begin(); |
127 | char *out = begin; |
128 | for (const StringPiece piece : pieces) { |
129 | const size_t this_size = piece.size(); |
130 | memcpy(out, piece.data(), this_size); |
131 | out += this_size; |
132 | } |
133 | DCHECK_EQ(out, begin + result.size()); |
134 | return result; |
135 | } |
136 | |
137 | // It's possible to call StrAppend with a StringPiece that is itself a fragment |
138 | // of the string we're appending to. However the results of this are random. |
139 | // Therefore, check for this in debug mode. Use unsigned math so we only have |
140 | // to do one comparison. |
141 | #define DCHECK_NO_OVERLAP(dest, src) \ |
142 | DCHECK_GE(uintptr_t((src).data() - (dest).data()), uintptr_t((dest).size())) |
143 | |
144 | void AppendPieces(string *result, std::initializer_list<StringPiece> pieces) { |
145 | size_t old_size = result->size(); |
146 | size_t total_size = old_size; |
147 | for (const StringPiece piece : pieces) { |
148 | DCHECK_NO_OVERLAP(*result, piece); |
149 | total_size += piece.size(); |
150 | } |
151 | gtl::STLStringResizeUninitialized(result, total_size); |
152 | |
153 | char *const begin = &*result->begin(); |
154 | char *out = begin + old_size; |
155 | for (const StringPiece piece : pieces) { |
156 | const size_t this_size = piece.size(); |
157 | memcpy(out, piece.data(), this_size); |
158 | out += this_size; |
159 | } |
160 | DCHECK_EQ(out, begin + result->size()); |
161 | } |
162 | |
163 | } // namespace internal |
164 | |
165 | void StrAppend(string *result, const AlphaNum &a) { |
166 | DCHECK_NO_OVERLAP(*result, a); |
167 | result->append(a.data(), a.size()); |
168 | } |
169 | |
170 | void StrAppend(string *result, const AlphaNum &a, const AlphaNum &b) { |
171 | DCHECK_NO_OVERLAP(*result, a); |
172 | DCHECK_NO_OVERLAP(*result, b); |
173 | string::size_type old_size = result->size(); |
174 | gtl::STLStringResizeUninitialized(result, old_size + a.size() + b.size()); |
175 | char *const begin = &*result->begin(); |
176 | char *out = Append2(begin + old_size, a, b); |
177 | DCHECK_EQ(out, begin + result->size()); |
178 | } |
179 | |
180 | void StrAppend(string *result, const AlphaNum &a, const AlphaNum &b, |
181 | const AlphaNum &c) { |
182 | DCHECK_NO_OVERLAP(*result, a); |
183 | DCHECK_NO_OVERLAP(*result, b); |
184 | DCHECK_NO_OVERLAP(*result, c); |
185 | string::size_type old_size = result->size(); |
186 | gtl::STLStringResizeUninitialized(result, |
187 | old_size + a.size() + b.size() + c.size()); |
188 | char *const begin = &*result->begin(); |
189 | char *out = Append2(begin + old_size, a, b); |
190 | out = Append1(out, c); |
191 | DCHECK_EQ(out, begin + result->size()); |
192 | } |
193 | |
194 | void StrAppend(string *result, const AlphaNum &a, const AlphaNum &b, |
195 | const AlphaNum &c, const AlphaNum &d) { |
196 | DCHECK_NO_OVERLAP(*result, a); |
197 | DCHECK_NO_OVERLAP(*result, b); |
198 | DCHECK_NO_OVERLAP(*result, c); |
199 | DCHECK_NO_OVERLAP(*result, d); |
200 | string::size_type old_size = result->size(); |
201 | gtl::STLStringResizeUninitialized( |
202 | result, old_size + a.size() + b.size() + c.size() + d.size()); |
203 | char *const begin = &*result->begin(); |
204 | char *out = Append4(begin + old_size, a, b, c, d); |
205 | DCHECK_EQ(out, begin + result->size()); |
206 | } |
207 | |
208 | } // namespace strings |
209 | } // namespace tensorflow |
210 | |