Skip to content
Newer
Older
100644 332 lines (283 sloc) 9.2 KB
27494a2 @jdelong Pull from FB rev 63ce89e2f2301e6bba44a111cc7d4218022156f6
jdelong authored Jun 2, 2012
1 /*
3215426 @markisaa folly copyright 2015 -> copyright 2016
markisaa authored Feb 12, 2016
2 * Copyright 2016 Facebook, Inc.
27494a2 @jdelong Pull from FB rev 63ce89e2f2301e6bba44a111cc7d4218022156f6
jdelong authored Jun 2, 2012
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
ce64f0f @tudor Codemod: use #include angle brackets in folly and thrift
tudor authored Jun 30, 2014
17 #include <folly/Format.h>
27494a2 @jdelong Pull from FB rev 63ce89e2f2301e6bba44a111cc7d4218022156f6
jdelong authored Jun 2, 2012
18
ad925ff @Orvid Don't use a VLA for the double->string buffer.
Orvid authored Feb 18, 2016
19 #include <folly/portability/Constexpr.h>
20
3b4d7b6 @mhorowitz folly refactorings to better support cross-platform
mhorowitz authored Apr 16, 2015
21 #include <double-conversion/double-conversion.h>
22
27494a2 @jdelong Pull from FB rev 63ce89e2f2301e6bba44a111cc7d4218022156f6
jdelong authored Jun 2, 2012
23 namespace folly {
24 namespace detail {
25
26 extern const FormatArg::Align formatAlignTable[];
27 extern const FormatArg::Sign formatSignTable[];
28
29 } // namespace detail
30
31 using namespace folly::detail;
32
3b4d7b6 @mhorowitz folly refactorings to better support cross-platform
mhorowitz authored Apr 17, 2015
33 void FormatValue<double>::formatHelper(
34 fbstring& piece, int& prefixLen, FormatArg& arg) const {
35 using ::double_conversion::DoubleToStringConverter;
36 using ::double_conversion::StringBuilder;
37
38 arg.validate(FormatArg::Type::FLOAT);
39
40 if (arg.presentation == FormatArg::kDefaultPresentation) {
41 arg.presentation = 'g';
42 }
43
44 const char* infinitySymbol = isupper(arg.presentation) ? "INF" : "inf";
45 const char* nanSymbol = isupper(arg.presentation) ? "NAN" : "nan";
46 char exponentSymbol = isupper(arg.presentation) ? 'E' : 'e';
47
48 if (arg.precision == FormatArg::kDefaultPrecision) {
49 arg.precision = 6;
50 }
51
52 // 2+: for null terminator and optional sign shenanigans.
ad925ff @Orvid Don't use a VLA for the double->string buffer.
Orvid authored Feb 18, 2016
53 constexpr size_t bufLen =
54 2 + constexpr_max(
55 2 + DoubleToStringConverter::kMaxFixedDigitsBeforePoint +
56 DoubleToStringConverter::kMaxFixedDigitsAfterPoint,
57 constexpr_max(8 + DoubleToStringConverter::kMaxExponentialDigits,
58 7 + DoubleToStringConverter::kMaxPrecisionDigits));
59 char buf[bufLen];
3b4d7b6 @mhorowitz folly refactorings to better support cross-platform
mhorowitz authored Apr 17, 2015
60 StringBuilder builder(buf + 1, static_cast<int> (sizeof(buf) - 1));
61
62 char plusSign;
63 switch (arg.sign) {
64 case FormatArg::Sign::PLUS_OR_MINUS:
65 plusSign = '+';
66 break;
67 case FormatArg::Sign::SPACE_OR_MINUS:
68 plusSign = ' ';
69 break;
70 default:
71 plusSign = '\0';
72 break;
73 };
74
75 auto flags =
76 DoubleToStringConverter::EMIT_POSITIVE_EXPONENT_SIGN |
77 (arg.trailingDot ? DoubleToStringConverter::EMIT_TRAILING_DECIMAL_POINT
78 : 0);
79
80 double val = val_;
81 switch (arg.presentation) {
82 case '%':
83 val *= 100;
84 case 'f':
85 case 'F':
86 {
87 if (arg.precision >
88 DoubleToStringConverter::kMaxFixedDigitsAfterPoint) {
89 arg.precision = DoubleToStringConverter::kMaxFixedDigitsAfterPoint;
90 }
91 DoubleToStringConverter conv(flags,
92 infinitySymbol,
93 nanSymbol,
94 exponentSymbol,
95 -4,
96 arg.precision,
97 0,
98 0);
99 arg.enforce(conv.ToFixed(val, arg.precision, &builder),
100 "fixed double conversion failed");
101 }
102 break;
103 case 'e':
104 case 'E':
105 {
106 if (arg.precision > DoubleToStringConverter::kMaxExponentialDigits) {
107 arg.precision = DoubleToStringConverter::kMaxExponentialDigits;
108 }
109
110 DoubleToStringConverter conv(flags,
111 infinitySymbol,
112 nanSymbol,
113 exponentSymbol,
114 -4,
115 arg.precision,
116 0,
117 0);
118 arg.enforce(conv.ToExponential(val, arg.precision, &builder));
119 }
120 break;
121 case 'n': // should be locale-aware, but isn't
122 case 'g':
123 case 'G':
124 {
125 if (arg.precision < DoubleToStringConverter::kMinPrecisionDigits) {
126 arg.precision = DoubleToStringConverter::kMinPrecisionDigits;
127 } else if (arg.precision >
128 DoubleToStringConverter::kMaxPrecisionDigits) {
129 arg.precision = DoubleToStringConverter::kMaxPrecisionDigits;
130 }
131 DoubleToStringConverter conv(flags,
132 infinitySymbol,
133 nanSymbol,
134 exponentSymbol,
135 -4,
136 arg.precision,
137 0,
138 0);
139 arg.enforce(conv.ToShortest(val, &builder));
140 }
141 break;
142 default:
143 arg.error("invalid specifier '", arg.presentation, "'");
144 }
145
146 int len = builder.position();
147 builder.Finalize();
148 DCHECK_GT(len, 0);
149
150 // Add '+' or ' ' sign if needed
151 char* p = buf + 1;
152 // anything that's neither negative nor nan
153 prefixLen = 0;
154 if (plusSign && (*p != '-' && *p != 'n' && *p != 'N')) {
155 *--p = plusSign;
156 ++len;
157 prefixLen = 1;
158 } else if (*p == '-') {
159 prefixLen = 1;
160 }
161
162 piece = fbstring(p, len);
163 }
164
165
27494a2 @jdelong Pull from FB rev 63ce89e2f2301e6bba44a111cc7d4218022156f6
jdelong authored Jun 2, 2012
166 void FormatArg::initSlow() {
167 auto b = fullArgString.begin();
168 auto end = fullArgString.end();
169
170 // Parse key
171 auto p = static_cast<const char*>(memchr(b, ':', end - b));
172 if (!p) {
173 key_ = StringPiece(b, end);
174 return;
175 }
176 key_ = StringPiece(b, p);
177
178 if (*p == ':') {
179 // parse format spec
180 if (++p == end) return;
181
182 // fill/align, or just align
183 Align a;
184 if (p + 1 != end &&
185 (a = formatAlignTable[static_cast<unsigned char>(p[1])]) !=
186 Align::INVALID) {
187 fill = *p;
188 align = a;
189 p += 2;
190 if (p == end) return;
191 } else if ((a = formatAlignTable[static_cast<unsigned char>(*p)]) !=
192 Align::INVALID) {
193 align = a;
194 if (++p == end) return;
195 }
196
197 Sign s;
198 unsigned char uSign = static_cast<unsigned char>(*p);
199 if ((s = formatSignTable[uSign]) != Sign::INVALID) {
200 sign = s;
201 if (++p == end) return;
202 }
203
204 if (*p == '#') {
205 basePrefix = true;
206 if (++p == end) return;
207 }
208
209 if (*p == '0') {
e1a2cde @simpkins revert format()'s behavior of crashing on error
simpkins authored Jan 26, 2014
210 enforce(align == Align::DEFAULT, "alignment specified twice");
27494a2 @jdelong Pull from FB rev 63ce89e2f2301e6bba44a111cc7d4218022156f6
jdelong authored Jun 2, 2012
211 fill = '0';
212 align = Align::PAD_AFTER_SIGN;
213 if (++p == end) return;
214 }
215
aa7aebf @swtaarrs Support dynamic field width in folly::format()
swtaarrs authored Aug 9, 2015
216 auto readInt = [&] {
448f127 @mzlee Start compiling a bit of `-Wshadow`
mzlee authored Apr 6, 2016
217 auto const c = p;
27494a2 @jdelong Pull from FB rev 63ce89e2f2301e6bba44a111cc7d4218022156f6
jdelong authored Jun 2, 2012
218 do {
219 ++p;
220 } while (p != end && *p >= '0' && *p <= '9');
448f127 @mzlee Start compiling a bit of `-Wshadow`
mzlee authored Apr 6, 2016
221 return to<int>(StringPiece(c, p));
aa7aebf @swtaarrs Support dynamic field width in folly::format()
swtaarrs authored Aug 9, 2015
222 };
223
224 if (*p == '*') {
225 width = kDynamicWidth;
226 ++p;
227
228 if (p == end) return;
229
230 if (*p >= '0' && *p <= '9') widthIndex = readInt();
231
232 if (p == end) return;
233 } else if (*p >= '0' && *p <= '9') {
234 width = readInt();
27494a2 @jdelong Pull from FB rev 63ce89e2f2301e6bba44a111cc7d4218022156f6
jdelong authored Jun 2, 2012
235
236 if (p == end) return;
237 }
238
239 if (*p == ',') {
240 thousandsSeparator = true;
241 if (++p == end) return;
242 }
243
244 if (*p == '.') {
448f127 @mzlee Start compiling a bit of `-Wshadow`
mzlee authored Apr 6, 2016
245 auto d = ++p;
27494a2 @jdelong Pull from FB rev 63ce89e2f2301e6bba44a111cc7d4218022156f6
jdelong authored Jun 2, 2012
246 while (p != end && *p >= '0' && *p <= '9') {
247 ++p;
248 }
448f127 @mzlee Start compiling a bit of `-Wshadow`
mzlee authored Apr 6, 2016
249 if (p != d) {
250 precision = to<int>(StringPiece(d, p));
33d3277 Support trailing decimals for floats
Tom Jackson authored Jul 23, 2014
251 if (p != end && *p == '.') {
252 trailingDot = true;
253 ++p;
254 }
255 } else {
256 trailingDot = true;
257 }
27494a2 @jdelong Pull from FB rev 63ce89e2f2301e6bba44a111cc7d4218022156f6
jdelong authored Jun 2, 2012
258
259 if (p == end) return;
260 }
261
262 presentation = *p;
263 if (++p == end) return;
264 }
265
e1a2cde @simpkins revert format()'s behavior of crashing on error
simpkins authored Jan 27, 2014
266 error("extra characters in format string");
27494a2 @jdelong Pull from FB rev 63ce89e2f2301e6bba44a111cc7d4218022156f6
jdelong authored Jun 2, 2012
267 }
268
269 void FormatArg::validate(Type type) const {
e1a2cde @simpkins revert format()'s behavior of crashing on error
simpkins authored Jan 27, 2014
270 enforce(keyEmpty(), "index not allowed");
27494a2 @jdelong Pull from FB rev 63ce89e2f2301e6bba44a111cc7d4218022156f6
jdelong authored Jun 2, 2012
271 switch (type) {
272 case Type::INTEGER:
e1a2cde @simpkins revert format()'s behavior of crashing on error
simpkins authored Jan 27, 2014
273 enforce(precision == kDefaultPrecision,
274 "precision not allowed on integers");
27494a2 @jdelong Pull from FB rev 63ce89e2f2301e6bba44a111cc7d4218022156f6
jdelong authored Jun 2, 2012
275 break;
276 case Type::FLOAT:
e1a2cde @simpkins revert format()'s behavior of crashing on error
simpkins authored Jan 27, 2014
277 enforce(!basePrefix,
278 "base prefix ('#') specifier only allowed on integers");
279 enforce(!thousandsSeparator,
280 "thousands separator (',') only allowed on integers");
27494a2 @jdelong Pull from FB rev 63ce89e2f2301e6bba44a111cc7d4218022156f6
jdelong authored Jun 2, 2012
281 break;
282 case Type::OTHER:
e1a2cde @simpkins revert format()'s behavior of crashing on error
simpkins authored Jan 27, 2014
283 enforce(align != Align::PAD_AFTER_SIGN,
284 "'='alignment only allowed on numbers");
285 enforce(sign == Sign::DEFAULT,
286 "sign specifier only allowed on numbers");
287 enforce(!basePrefix,
288 "base prefix ('#') specifier only allowed on integers");
289 enforce(!thousandsSeparator,
290 "thousands separator (',') only allowed on integers");
27494a2 @jdelong Pull from FB rev 63ce89e2f2301e6bba44a111cc7d4218022156f6
jdelong authored Jun 2, 2012
291 break;
292 }
293 }
294
74651ad Updating Folly Formatting's use of separators for Decimal Integers 'd…
John Ehrhardt authored Feb 25, 2015
295 namespace detail {
296 void insertThousandsGroupingUnsafe(char* start_buffer, char** end_buffer) {
297 uint32_t remaining_digits = *end_buffer - start_buffer;
298 uint32_t separator_size = (remaining_digits - 1) / 3;
299 uint32_t result_size = remaining_digits + separator_size;
300 *end_buffer = *end_buffer + separator_size;
301
302 // get the end of the new string with the separators
303 uint32_t buffer_write_index = result_size - 1;
304 uint32_t buffer_read_index = remaining_digits - 1;
305 start_buffer[buffer_write_index + 1] = 0;
306
307 bool done = false;
308 uint32_t next_group_size = 3;
309
310 while (!done) {
311 uint32_t current_group_size = std::max<uint32_t>(1,
312 std::min<uint32_t>(remaining_digits, next_group_size));
313
314 // write out the current group's digits to the buffer index
315 for (uint32_t i = 0; i < current_group_size; i++) {
316 start_buffer[buffer_write_index--] = start_buffer[buffer_read_index--];
317 }
318
319 // if not finished, write the separator before the next group
320 if (buffer_write_index < buffer_write_index + 1) {
321 start_buffer[buffer_write_index--] = ',';
322 } else {
323 done = true;
324 }
325
326 remaining_digits -= current_group_size;
327 }
328 }
329 } // detail
330
27494a2 @jdelong Pull from FB rev 63ce89e2f2301e6bba44a111cc7d4218022156f6
jdelong authored Jun 2, 2012
331 } // namespace folly
Something went wrong with that request. Please try again.