1/* Copyright 2015 The TensorFlow Authors. All Rights Reserved.
2
3Licensed under the Apache License, Version 2.0 (the "License");
4you may not use this file except in compliance with the License.
5You may obtain a copy of the License at
6
7 http://www.apache.org/licenses/LICENSE-2.0
8
9Unless required by applicable law or agreed to in writing, software
10distributed under the License is distributed on an "AS IS" BASIS,
11WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12See the License for the specific language governing permissions and
13limitations 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
26namespace tensorflow {
27namespace strings {
28
29AlphaNum::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.
57static char *Append1(char *out, const AlphaNum &x) {
58 memcpy(out, x.data(), x.size());
59 return out + x.size();
60}
61
62static 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
70static 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
85string StrCat(const AlphaNum &a) { return string(a.data(), a.size()); }
86
87string 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
96string 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
106string 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
117namespace internal {
118
119// Do not call directly - these are not part of the public API.
120string 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
144void 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
165void StrAppend(string *result, const AlphaNum &a) {
166 DCHECK_NO_OVERLAP(*result, a);
167 result->append(a.data(), a.size());
168}
169
170void 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
180void 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
194void 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