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_TSL_PLATFORM_STRCAT_H_ |
21 | #define TENSORFLOW_TSL_PLATFORM_STRCAT_H_ |
22 | |
23 | #include <string> |
24 | |
25 | #include "tensorflow/tsl/platform/macros.h" |
26 | #include "tensorflow/tsl/platform/numbers.h" |
27 | #include "tensorflow/tsl/platform/stringpiece.h" |
28 | #include "tensorflow/tsl/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 tsl { |
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> |
84 | 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 ? static_cast<uint8>(v) |
91 | : sizeof(v) == 2 ? static_cast<uint16>(v) |
92 | : sizeof(v) == 4 ? static_cast<uint32>(v) |
93 | : static_cast<uint64>(v); |
94 | } |
95 | }; |
96 | |
97 | class AlphaNum { |
98 | // NOLINTBEGIN(google-explicit-constructor) |
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) // NOLINT(runtime/explicit) |
103 | : piece_(digits_, FastInt32ToBufferLeft(i32, digits_)) {} |
104 | AlphaNum(unsigned int u32) // NOLINT(runtime/explicit) |
105 | : piece_(digits_, FastUInt32ToBufferLeft(u32, digits_)) {} |
106 | AlphaNum(long x) // NOLINT(runtime/explicit) |
107 | : piece_(digits_, FastInt64ToBufferLeft(x, digits_)) {} |
108 | AlphaNum(unsigned long x) // NOLINT(runtime/explicit) |
109 | : piece_(digits_, FastUInt64ToBufferLeft(x, digits_)) {} |
110 | AlphaNum(long long int i64) // NOLINT(runtime/explicit) |
111 | : piece_(digits_, FastInt64ToBufferLeft(i64, digits_)) {} |
112 | AlphaNum(unsigned long long int u64) // NOLINT(runtime/explicit) |
113 | : piece_(digits_, FastUInt64ToBufferLeft(u64, digits_)) {} |
114 | |
115 | AlphaNum(float f) // NOLINT(runtime/explicit) |
116 | : piece_(digits_, FloatToBuffer(f, digits_)) {} |
117 | AlphaNum(double f) // NOLINT(runtime/explicit) |
118 | : piece_(digits_, DoubleToBuffer(f, digits_)) {} |
119 | AlphaNum(bfloat16 bf) // NOLINT(runtime/explicit) |
120 | : piece_(digits_, FloatToBuffer(static_cast<float>(bf), digits_)) {} |
121 | |
122 | AlphaNum(Hex hex); // NOLINT(runtime/explicit) |
123 | |
124 | AlphaNum(const char *c_str) : piece_(c_str) {} // NOLINT(runtime/explicit) |
125 | AlphaNum(const StringPiece &pc) : piece_(pc) {} // NOLINT(runtime/explicit) |
126 | AlphaNum(const std::string &str) // NOLINT(runtime/explicit) |
127 | : piece_(str) {} |
128 | AlphaNum(const tstring &str) // NOLINT(runtime/explicit) |
129 | : piece_(str) {} |
130 | template <typename A> |
131 | AlphaNum(const std::basic_string<char, std::char_traits<char>, A> &str) |
132 | : piece_(str) {} // NOLINT(runtime/explicit) |
133 | |
134 | StringPiece::size_type size() const { return piece_.size(); } |
135 | const char *data() const { return piece_.data(); } |
136 | StringPiece Piece() const { return piece_; } |
137 | |
138 | private: |
139 | StringPiece piece_; |
140 | char digits_[kFastToBufferSize]; |
141 | |
142 | // Use ":" not ':' |
143 | AlphaNum(char c); // NOLINT(runtime/explicit) |
144 | |
145 | // NOLINTEND(google-explicit-constructor) |
146 | TF_DISALLOW_COPY_AND_ASSIGN(AlphaNum); |
147 | }; |
148 | |
149 | // ---------------------------------------------------------------------- |
150 | // StrCat() |
151 | // This merges the given strings or numbers, with no delimiter. This |
152 | // is designed to be the fastest possible way to construct a string out |
153 | // of a mix of raw C strings, StringPieces, strings, bool values, |
154 | // and numeric values. |
155 | // |
156 | // Don't use this for user-visible strings. The localization process |
157 | // works poorly on strings built up out of fragments. |
158 | // |
159 | // For clarity and performance, don't use StrCat when appending to a |
160 | // string. In particular, avoid using any of these (anti-)patterns: |
161 | // str.append(StrCat(...)) |
162 | // str += StrCat(...) |
163 | // str = StrCat(str, ...) |
164 | // where the last is the worse, with the potential to change a loop |
165 | // from a linear time operation with O(1) dynamic allocations into a |
166 | // quadratic time operation with O(n) dynamic allocations. StrAppend |
167 | // is a better choice than any of the above, subject to the restriction |
168 | // of StrAppend(&str, a, b, c, ...) that none of the a, b, c, ... may |
169 | // be a reference into str. |
170 | // ---------------------------------------------------------------------- |
171 | |
172 | // For performance reasons, we have specializations for <= 4 args. |
173 | std::string StrCat(const AlphaNum &a) TF_MUST_USE_RESULT; |
174 | std::string StrCat(const AlphaNum &a, const AlphaNum &b) TF_MUST_USE_RESULT; |
175 | std::string StrCat(const AlphaNum &a, const AlphaNum &b, |
176 | const AlphaNum &c) TF_MUST_USE_RESULT; |
177 | std::string StrCat(const AlphaNum &a, const AlphaNum &b, const AlphaNum &c, |
178 | const AlphaNum &d) TF_MUST_USE_RESULT; |
179 | |
180 | namespace internal { |
181 | |
182 | // Do not call directly - this is not part of the public API. |
183 | std::string CatPieces(std::initializer_list<StringPiece> pieces); |
184 | void AppendPieces(std::string *dest, std::initializer_list<StringPiece> pieces); |
185 | |
186 | } // namespace internal |
187 | |
188 | // Support 5 or more arguments |
189 | template <typename... AV> |
190 | std::string StrCat(const AlphaNum &a, const AlphaNum &b, const AlphaNum &c, |
191 | const AlphaNum &d, const AlphaNum &e, |
192 | const AV &...args) TF_MUST_USE_RESULT; |
193 | |
194 | template <typename... AV> |
195 | std::string StrCat(const AlphaNum &a, const AlphaNum &b, const AlphaNum &c, |
196 | const AlphaNum &d, const AlphaNum &e, const AV &...args) { |
197 | return internal::CatPieces({a.Piece(), b.Piece(), c.Piece(), d.Piece(), |
198 | e.Piece(), |
199 | static_cast<const AlphaNum &>(args).Piece()...}); |
200 | } |
201 | |
202 | // ---------------------------------------------------------------------- |
203 | // StrAppend() |
204 | // Same as above, but adds the output to the given string. |
205 | // WARNING: For speed, StrAppend does not try to check each of its input |
206 | // arguments to be sure that they are not a subset of the string being |
207 | // appended to. That is, while this will work: |
208 | // |
209 | // string s = "foo"; |
210 | // s += s; |
211 | // |
212 | // This will not (necessarily) work: |
213 | // |
214 | // string s = "foo"; |
215 | // StrAppend(&s, s); |
216 | // |
217 | // Note: while StrCat supports appending up to 26 arguments, StrAppend |
218 | // is currently limited to 9. That's rarely an issue except when |
219 | // automatically transforming StrCat to StrAppend, and can easily be |
220 | // worked around as consecutive calls to StrAppend are quite efficient. |
221 | // ---------------------------------------------------------------------- |
222 | |
223 | void StrAppend(std::string *dest, const AlphaNum &a); |
224 | void StrAppend(std::string *dest, const AlphaNum &a, const AlphaNum &b); |
225 | void StrAppend(std::string *dest, const AlphaNum &a, const AlphaNum &b, |
226 | const AlphaNum &c); |
227 | void StrAppend(std::string *dest, const AlphaNum &a, const AlphaNum &b, |
228 | const AlphaNum &c, const AlphaNum &d); |
229 | |
230 | // Support 5 or more arguments |
231 | template <typename... AV> |
232 | inline void StrAppend(std::string *dest, const AlphaNum &a, const AlphaNum &b, |
233 | const AlphaNum &c, const AlphaNum &d, const AlphaNum &e, |
234 | const AV &...args) { |
235 | internal::AppendPieces(dest, |
236 | {a.Piece(), b.Piece(), c.Piece(), d.Piece(), e.Piece(), |
237 | static_cast<const AlphaNum &>(args).Piece()...}); |
238 | } |
239 | |
240 | } // namespace strings |
241 | } // namespace tsl |
242 | |
243 | #endif // TENSORFLOW_TSL_PLATFORM_STRCAT_H_ |
244 | |