• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 // #status: RECOMMENDED
17 // #category: operations on strings
18 // #summary: Merges strings or numbers with no delimiter.
19 //
20 #ifndef TENSORFLOW_LIB_STRINGS_STRCAT_H_
21 #define TENSORFLOW_LIB_STRINGS_STRCAT_H_
22 
23 #include <string>
24 
25 #include "tensorflow/core/lib/core/stringpiece.h"
26 #include "tensorflow/core/lib/strings/numbers.h"
27 #include "tensorflow/core/platform/macros.h"
28 #include "tensorflow/core/platform/types.h"
29 
30 namespace Eigen {
31 struct half;
32 }
33 
34 // The AlphaNum type was designed to be used as the parameter type for StrCat().
35 // Any routine accepting either a string or a number may accept it.
36 // The basic idea is that by accepting a "const AlphaNum &" as an argument
37 // to your function, your callers will automatically convert bools, integers,
38 // and floating point values to strings for you.
39 //
40 // NOTE: Use of AlphaNum outside of the //strings package is unsupported except
41 // for the specific case of function parameters of type "AlphaNum" or "const
42 // AlphaNum &". In particular, instantiating AlphaNum directly as a stack
43 // variable is not supported.
44 //
45 // Conversion from 8-bit values is not accepted because if it were, then an
46 // attempt to pass ':' instead of ":" might result in a 58 ending up in your
47 // result.
48 //
49 // Bools convert to "0" or "1".
50 //
51 // Floating point values are converted to a string which, if passed to strtod(),
52 // would produce the exact same original double (except in case of NaN; all NaNs
53 // are considered the same value). We try to keep the string short but it's not
54 // guaranteed to be as short as possible.
55 //
56 // You can convert to Hexadecimal output rather than Decimal output using Hex.
57 // To do this, pass strings::Hex(my_int) as a parameter to StrCat. You may
58 // specify a minimum field width using a separate parameter, so the equivalent
59 // of Printf("%04x", my_int) is StrCat(Hex(my_int, strings::ZERO_PAD_4))
60 //
61 // This class has implicit constructors.
62 namespace tensorflow {
63 namespace strings {
64 
65 enum PadSpec {
66   NO_PAD = 1,
67   ZERO_PAD_2,
68   ZERO_PAD_3,
69   ZERO_PAD_4,
70   ZERO_PAD_5,
71   ZERO_PAD_6,
72   ZERO_PAD_7,
73   ZERO_PAD_8,
74   ZERO_PAD_9,
75   ZERO_PAD_10,
76   ZERO_PAD_11,
77   ZERO_PAD_12,
78   ZERO_PAD_13,
79   ZERO_PAD_14,
80   ZERO_PAD_15,
81   ZERO_PAD_16,
82 };
83 
84 struct Hex {
85   uint64 value;
86   enum PadSpec spec;
87   template <class Int>
specHex88   explicit Hex(Int v, PadSpec s = NO_PAD) : spec(s) {
89     // Prevent sign-extension by casting integers to
90     // their unsigned counterparts.
91     static_assert(
92         sizeof(v) == 1 || sizeof(v) == 2 || sizeof(v) == 4 || sizeof(v) == 8,
93         "Unknown integer type");
94     value = sizeof(v) == 1
95                 ? static_cast<uint8>(v)
96                 : sizeof(v) == 2 ? static_cast<uint16>(v)
97                                  : sizeof(v) == 4 ? static_cast<uint32>(v)
98                                                   : static_cast<uint64>(v);
99   }
100 };
101 
102 class AlphaNum {
103  public:
104   // No bool ctor -- bools convert to an integral type.
105   // A bool ctor would also convert incoming pointers (bletch).
106 
AlphaNum(int i32)107   AlphaNum(int i32)  // NOLINT(runtime/explicit)
108       : piece_(digits_, FastInt32ToBufferLeft(i32, digits_) - &digits_[0]) {}
AlphaNum(unsigned int u32)109   AlphaNum(unsigned int u32)  // NOLINT(runtime/explicit)
110       : piece_(digits_, FastUInt32ToBufferLeft(u32, digits_) - &digits_[0]) {}
AlphaNum(long x)111   AlphaNum(long x)  // NOLINT(runtime/explicit)
112       : piece_(digits_, FastInt64ToBufferLeft(x, digits_) - &digits_[0]) {}
AlphaNum(unsigned long x)113   AlphaNum(unsigned long x)  // NOLINT(runtime/explicit)
114       : piece_(digits_, FastUInt64ToBufferLeft(x, digits_) - &digits_[0]) {}
AlphaNum(long long int i64)115   AlphaNum(long long int i64)  // NOLINT(runtime/explicit)
116       : piece_(digits_, FastInt64ToBufferLeft(i64, digits_) - &digits_[0]) {}
AlphaNum(unsigned long long int u64)117   AlphaNum(unsigned long long int u64)  // NOLINT(runtime/explicit)
118       : piece_(digits_, FastUInt64ToBufferLeft(u64, digits_) - &digits_[0]) {}
119 
AlphaNum(float f)120   AlphaNum(float f)  // NOLINT(runtime/explicit)
121       : piece_(digits_, strlen(FloatToBuffer(f, digits_))) {}
AlphaNum(bfloat16 f)122   AlphaNum(bfloat16 f)  // NOLINT(runtime/explicit)
123       : piece_(digits_, strlen(FloatToBuffer(static_cast<float>(f), digits_))) {
124   }
AlphaNum(double f)125   AlphaNum(double f)  // NOLINT(runtime/explicit)
126       : piece_(digits_, strlen(DoubleToBuffer(f, digits_))) {}
127 
128   AlphaNum(const Eigen::half &f);  // NOLINT(runtime/explicit)
129   AlphaNum(Hex hex);               // NOLINT(runtime/explicit)
130 
AlphaNum(const char * c_str)131   AlphaNum(const char *c_str) : piece_(c_str) {}   // NOLINT(runtime/explicit)
AlphaNum(const StringPiece & pc)132   AlphaNum(const StringPiece &pc) : piece_(pc) {}  // NOLINT(runtime/explicit)
AlphaNum(const tensorflow::string & str)133   AlphaNum(const tensorflow::string &str)          // NOLINT(runtime/explicit)
134       : piece_(str) {}
135 
size()136   StringPiece::size_type size() const { return piece_.size(); }
data()137   const char *data() const { return piece_.data(); }
Piece()138   StringPiece Piece() const { return piece_; }
139 
140  private:
141   StringPiece piece_;
142   char digits_[kFastToBufferSize];
143 
144   // Use ":" not ':'
145   AlphaNum(char c);  // NOLINT(runtime/explicit)
146 
147   TF_DISALLOW_COPY_AND_ASSIGN(AlphaNum);
148 };
149 
150 // ----------------------------------------------------------------------
151 // StrCat()
152 //    This merges the given strings or numbers, with no delimiter.  This
153 //    is designed to be the fastest possible way to construct a string out
154 //    of a mix of raw C strings, StringPieces, strings, bool values,
155 //    and numeric values.
156 //
157 //    Don't use this for user-visible strings.  The localization process
158 //    works poorly on strings built up out of fragments.
159 //
160 //    For clarity and performance, don't use StrCat when appending to a
161 //    string.  In particular, avoid using any of these (anti-)patterns:
162 //      str.append(StrCat(...))
163 //      str += StrCat(...)
164 //      str = StrCat(str, ...)
165 //    where the last is the worse, with the potential to change a loop
166 //    from a linear time operation with O(1) dynamic allocations into a
167 //    quadratic time operation with O(n) dynamic allocations.  StrAppend
168 //    is a better choice than any of the above, subject to the restriction
169 //    of StrAppend(&str, a, b, c, ...) that none of the a, b, c, ... may
170 //    be a reference into str.
171 // ----------------------------------------------------------------------
172 
173 // For performance reasons, we have specializations for <= 4 args.
174 string StrCat(const AlphaNum &a) TF_MUST_USE_RESULT;
175 string StrCat(const AlphaNum &a, const AlphaNum &b) TF_MUST_USE_RESULT;
176 string StrCat(const AlphaNum &a, const AlphaNum &b,
177               const AlphaNum &c) TF_MUST_USE_RESULT;
178 string StrCat(const AlphaNum &a, const AlphaNum &b, const AlphaNum &c,
179               const AlphaNum &d) TF_MUST_USE_RESULT;
180 
181 namespace internal {
182 
183 // Do not call directly - this is not part of the public API.
184 string CatPieces(std::initializer_list<StringPiece> pieces);
185 void AppendPieces(string *dest, std::initializer_list<StringPiece> pieces);
186 
187 }  // namespace internal
188 
189 // Support 5 or more arguments
190 template <typename... AV>
191 string StrCat(const AlphaNum &a, const AlphaNum &b, const AlphaNum &c,
192               const AlphaNum &d, const AlphaNum &e,
193               const AV &... args) TF_MUST_USE_RESULT;
194 
195 template <typename... AV>
StrCat(const AlphaNum & a,const AlphaNum & b,const AlphaNum & c,const AlphaNum & d,const AlphaNum & e,const AV &...args)196 string StrCat(const AlphaNum &a, const AlphaNum &b, const AlphaNum &c,
197               const AlphaNum &d, const AlphaNum &e, const AV &... args) {
198   return internal::CatPieces({a.Piece(), b.Piece(), c.Piece(), d.Piece(),
199                               e.Piece(),
200                               static_cast<const AlphaNum &>(args).Piece()...});
201 }
202 
203 // ----------------------------------------------------------------------
204 // StrAppend()
205 //    Same as above, but adds the output to the given string.
206 //    WARNING: For speed, StrAppend does not try to check each of its input
207 //    arguments to be sure that they are not a subset of the string being
208 //    appended to.  That is, while this will work:
209 //
210 //    string s = "foo";
211 //    s += s;
212 //
213 //    This will not (necessarily) work:
214 //
215 //    string s = "foo";
216 //    StrAppend(&s, s);
217 //
218 //    Note: while StrCat supports appending up to 26 arguments, StrAppend
219 //    is currently limited to 9.  That's rarely an issue except when
220 //    automatically transforming StrCat to StrAppend, and can easily be
221 //    worked around as consecutive calls to StrAppend are quite efficient.
222 // ----------------------------------------------------------------------
223 
224 void StrAppend(string *dest, const AlphaNum &a);
225 void StrAppend(string *dest, const AlphaNum &a, const AlphaNum &b);
226 void StrAppend(string *dest, const AlphaNum &a, const AlphaNum &b,
227                const AlphaNum &c);
228 void StrAppend(string *dest, const AlphaNum &a, const AlphaNum &b,
229                const AlphaNum &c, const AlphaNum &d);
230 
231 // Support 5 or more arguments
232 template <typename... AV>
StrAppend(string * dest,const AlphaNum & a,const AlphaNum & b,const AlphaNum & c,const AlphaNum & d,const AlphaNum & e,const AV &...args)233 inline void StrAppend(string *dest, const AlphaNum &a, const AlphaNum &b,
234                       const AlphaNum &c, const AlphaNum &d, const AlphaNum &e,
235                       const AV &... args) {
236   internal::AppendPieces(dest,
237                          {a.Piece(), b.Piece(), c.Piece(), d.Piece(), e.Piece(),
238                           static_cast<const AlphaNum &>(args).Piece()...});
239 }
240 
241 }  // namespace strings
242 }  // namespace tensorflow
243 
244 #endif  // TENSORFLOW_LIB_STRINGS_STRCAT_H_
245