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