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
AlphaNum(Hex hex)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.
Append1(char * out,const AlphaNum & x)57 static char *Append1(char *out, const AlphaNum &x) {
58 memcpy(out, x.data(), x.size());
59 return out + x.size();
60 }
61
Append2(char * out,const AlphaNum & x1,const AlphaNum & x2)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
Append4(char * out,const AlphaNum & x1,const AlphaNum & x2,const AlphaNum & x3,const AlphaNum & x4)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
StrCat(const AlphaNum & a)85 string StrCat(const AlphaNum &a) { return string(a.data(), a.size()); }
86
StrCat(const AlphaNum & a,const AlphaNum & b)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
StrCat(const AlphaNum & a,const AlphaNum & b,const AlphaNum & c)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
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;
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.
CatPieces(std::initializer_list<StringPiece> pieces)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
AppendPieces(string * result,std::initializer_list<StringPiece> pieces)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
StrAppend(string * result,const AlphaNum & a)165 void StrAppend(string *result, const AlphaNum &a) {
166 DCHECK_NO_OVERLAP(*result, a);
167 result->append(a.data(), a.size());
168 }
169
StrAppend(string * result,const AlphaNum & a,const AlphaNum & b)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
StrAppend(string * result,const AlphaNum & a,const AlphaNum & b,const AlphaNum & c)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
StrAppend(string * result,const AlphaNum & a,const AlphaNum & b,const AlphaNum & c,const AlphaNum & d)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