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