1 | /* |
2 | * Copyright (c) Facebook, Inc. and its affiliates. |
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 | |
17 | #ifndef FOLLY_FORMAT_H_ |
18 | #error This file may only be included from Format.h. |
19 | #endif |
20 | |
21 | #include <array> |
22 | #include <cinttypes> |
23 | #include <deque> |
24 | #include <map> |
25 | #include <unordered_map> |
26 | #include <vector> |
27 | |
28 | #include <folly/Exception.h> |
29 | #include <folly/FormatTraits.h> |
30 | #include <folly/MapUtil.h> |
31 | #include <folly/Traits.h> |
32 | #include <folly/lang/Exception.h> |
33 | #include <folly/portability/Windows.h> |
34 | |
35 | // Ignore -Wformat-nonliteral and -Wconversion warnings within this file |
36 | FOLLY_PUSH_WARNING |
37 | FOLLY_GNU_DISABLE_WARNING("-Wformat-nonliteral" ) |
38 | FOLLY_GNU_DISABLE_WARNING("-Wconversion" ) |
39 | |
40 | namespace folly { |
41 | |
42 | namespace detail { |
43 | |
44 | // Updates the end of the buffer after the comma separators have been added. |
45 | void insertThousandsGroupingUnsafe(char* start_buffer, char** end_buffer); |
46 | |
47 | extern const std::array<std::array<char, 2>, 256> formatHexUpper; |
48 | extern const std::array<std::array<char, 2>, 256> formatHexLower; |
49 | extern const std::array<std::array<char, 3>, 512> formatOctal; |
50 | extern const std::array<std::array<char, 8>, 256> formatBinary; |
51 | |
52 | const size_t kMaxHexLength = 2 * sizeof(uintmax_t); |
53 | const size_t kMaxOctalLength = 3 * sizeof(uintmax_t); |
54 | const size_t kMaxBinaryLength = 8 * sizeof(uintmax_t); |
55 | |
56 | /** |
57 | * Convert an unsigned to hex, using repr (which maps from each possible |
58 | * 2-hex-bytes value to the 2-character representation). |
59 | * |
60 | * Just like folly::detail::uintToBuffer in Conv.h, writes at the *end* of |
61 | * the supplied buffer and returns the offset of the beginning of the string |
62 | * from the start of the buffer. The formatted string will be in range |
63 | * [buf+begin, buf+bufLen). |
64 | */ |
65 | template <class Uint> |
66 | size_t uintToHex( |
67 | char* buffer, |
68 | size_t bufLen, |
69 | Uint v, |
70 | std::array<std::array<char, 2>, 256> const& repr) { |
71 | // 'v >>= 7, v >>= 1' is no more than a work around to get rid of shift size |
72 | // warning when Uint = uint8_t (it's false as v >= 256 implies sizeof(v) > 1). |
73 | for (; !less_than<unsigned, 256>(v); v >>= 7, v >>= 1) { |
74 | auto b = v & 0xff; |
75 | bufLen -= 2; |
76 | buffer[bufLen] = repr[b][0]; |
77 | buffer[bufLen + 1] = repr[b][1]; |
78 | } |
79 | buffer[--bufLen] = repr[v][1]; |
80 | if (v >= 16) { |
81 | buffer[--bufLen] = repr[v][0]; |
82 | } |
83 | return bufLen; |
84 | } |
85 | |
86 | /** |
87 | * Convert an unsigned to hex, using lower-case letters for the digits |
88 | * above 9. See the comments for uintToHex. |
89 | */ |
90 | template <class Uint> |
91 | inline size_t uintToHexLower(char* buffer, size_t bufLen, Uint v) { |
92 | return uintToHex(buffer, bufLen, v, formatHexLower); |
93 | } |
94 | |
95 | /** |
96 | * Convert an unsigned to hex, using upper-case letters for the digits |
97 | * above 9. See the comments for uintToHex. |
98 | */ |
99 | template <class Uint> |
100 | inline size_t uintToHexUpper(char* buffer, size_t bufLen, Uint v) { |
101 | return uintToHex(buffer, bufLen, v, formatHexUpper); |
102 | } |
103 | |
104 | /** |
105 | * Convert an unsigned to octal. |
106 | * |
107 | * Just like folly::detail::uintToBuffer in Conv.h, writes at the *end* of |
108 | * the supplied buffer and returns the offset of the beginning of the string |
109 | * from the start of the buffer. The formatted string will be in range |
110 | * [buf+begin, buf+bufLen). |
111 | */ |
112 | template <class Uint> |
113 | size_t uintToOctal(char* buffer, size_t bufLen, Uint v) { |
114 | auto& repr = formatOctal; |
115 | // 'v >>= 7, v >>= 2' is no more than a work around to get rid of shift size |
116 | // warning when Uint = uint8_t (it's false as v >= 512 implies sizeof(v) > 1). |
117 | for (; !less_than<unsigned, 512>(v); v >>= 7, v >>= 2) { |
118 | auto b = v & 0x1ff; |
119 | bufLen -= 3; |
120 | buffer[bufLen] = repr[b][0]; |
121 | buffer[bufLen + 1] = repr[b][1]; |
122 | buffer[bufLen + 2] = repr[b][2]; |
123 | } |
124 | buffer[--bufLen] = repr[v][2]; |
125 | if (v >= 8) { |
126 | buffer[--bufLen] = repr[v][1]; |
127 | } |
128 | if (v >= 64) { |
129 | buffer[--bufLen] = repr[v][0]; |
130 | } |
131 | return bufLen; |
132 | } |
133 | |
134 | /** |
135 | * Convert an unsigned to binary. |
136 | * |
137 | * Just like folly::detail::uintToBuffer in Conv.h, writes at the *end* of |
138 | * the supplied buffer and returns the offset of the beginning of the string |
139 | * from the start of the buffer. The formatted string will be in range |
140 | * [buf+begin, buf+bufLen). |
141 | */ |
142 | template <class Uint> |
143 | size_t uintToBinary(char* buffer, size_t bufLen, Uint v) { |
144 | auto& repr = formatBinary; |
145 | if (v == 0) { |
146 | buffer[--bufLen] = '0'; |
147 | return bufLen; |
148 | } |
149 | for (; v; v >>= 7, v >>= 1) { |
150 | auto b = v & 0xff; |
151 | bufLen -= 8; |
152 | memcpy(buffer + bufLen, &(repr[b][0]), 8); |
153 | } |
154 | while (buffer[bufLen] == '0') { |
155 | ++bufLen; |
156 | } |
157 | return bufLen; |
158 | } |
159 | |
160 | } // namespace detail |
161 | |
162 | template <class Derived, bool containerMode, class... Args> |
163 | BaseFormatter<Derived, containerMode, Args...>::BaseFormatter( |
164 | StringPiece str, |
165 | Args&&... args) |
166 | : str_(str), values_(std::forward<Args>(args)...) {} |
167 | |
168 | template <class Derived, bool containerMode, class... Args> |
169 | template <class Output> |
170 | void BaseFormatter<Derived, containerMode, Args...>::operator()( |
171 | Output& out) const { |
172 | // Copy raw string (without format specifiers) to output; |
173 | // not as simple as we'd like, as we still need to translate "}}" to "}" |
174 | // and throw if we see any lone "}" |
175 | auto outputString = [&out](StringPiece s) { |
176 | auto p = s.begin(); |
177 | auto end = s.end(); |
178 | while (p != end) { |
179 | auto q = static_cast<const char*>(memchr(p, '}', size_t(end - p))); |
180 | if (!q) { |
181 | out(StringPiece(p, end)); |
182 | break; |
183 | } |
184 | ++q; |
185 | out(StringPiece(p, q)); |
186 | p = q; |
187 | |
188 | if (p == end || *p != '}') { |
189 | throw_exception<BadFormatArg>( |
190 | "folly::format: single '}' in format string" ); |
191 | } |
192 | ++p; |
193 | } |
194 | }; |
195 | |
196 | auto p = str_.begin(); |
197 | auto end = str_.end(); |
198 | |
199 | int nextArg = 0; |
200 | bool hasDefaultArgIndex = false; |
201 | bool hasExplicitArgIndex = false; |
202 | while (p != end) { |
203 | auto q = static_cast<const char*>(memchr(p, '{', size_t(end - p))); |
204 | if (!q) { |
205 | outputString(StringPiece(p, end)); |
206 | break; |
207 | } |
208 | outputString(StringPiece(p, q)); |
209 | p = q + 1; |
210 | |
211 | if (p == end) { |
212 | throw_exception<BadFormatArg>( |
213 | "folly::format: '}' at end of format string" ); |
214 | } |
215 | |
216 | // "{{" -> "{" |
217 | if (*p == '{') { |
218 | out(StringPiece(p, 1)); |
219 | ++p; |
220 | continue; |
221 | } |
222 | |
223 | // Format string |
224 | q = static_cast<const char*>(memchr(p, '}', size_t(end - p))); |
225 | if (q == nullptr) { |
226 | throw_exception<BadFormatArg>("folly::format: missing ending '}'" ); |
227 | } |
228 | FormatArg arg(StringPiece(p, q)); |
229 | p = q + 1; |
230 | |
231 | int argIndex = 0; |
232 | auto piece = arg.splitKey<true>(); // empty key component is okay |
233 | if (containerMode) { // static |
234 | arg.enforce( |
235 | arg.width != FormatArg::kDynamicWidth, |
236 | "dynamic field width not supported in vformat()" ); |
237 | if (piece.empty()) { |
238 | arg.setNextIntKey(nextArg++); |
239 | hasDefaultArgIndex = true; |
240 | } else { |
241 | arg.setNextKey(piece); |
242 | hasExplicitArgIndex = true; |
243 | } |
244 | } else { |
245 | if (piece.empty()) { |
246 | if (arg.width == FormatArg::kDynamicWidth) { |
247 | arg.enforce( |
248 | arg.widthIndex == FormatArg::kNoIndex, |
249 | "cannot provide width arg index without value arg index" ); |
250 | int sizeArg = nextArg++; |
251 | arg.width = asDerived().getSizeArg(size_t(sizeArg), arg); |
252 | } |
253 | |
254 | argIndex = nextArg++; |
255 | hasDefaultArgIndex = true; |
256 | } else { |
257 | if (arg.width == FormatArg::kDynamicWidth) { |
258 | arg.enforce( |
259 | arg.widthIndex != FormatArg::kNoIndex, |
260 | "cannot provide value arg index without width arg index" ); |
261 | arg.width = asDerived().getSizeArg(size_t(arg.widthIndex), arg); |
262 | } |
263 | |
264 | auto result = tryTo<int>(piece); |
265 | arg.enforce(result, "argument index must be integer" ); |
266 | argIndex = *result; |
267 | arg.enforce(argIndex >= 0, "argument index must be non-negative" ); |
268 | hasExplicitArgIndex = true; |
269 | } |
270 | } |
271 | |
272 | if (hasDefaultArgIndex && hasExplicitArgIndex) { |
273 | throw_exception<BadFormatArg>( |
274 | "folly::format: may not have both default and explicit arg indexes" ); |
275 | } |
276 | |
277 | asDerived().doFormat(size_t(argIndex), arg, out); |
278 | } |
279 | } |
280 | |
281 | template <class Derived, bool containerMode, class... Args> |
282 | void writeTo( |
283 | FILE* fp, |
284 | const BaseFormatter<Derived, containerMode, Args...>& formatter) { |
285 | auto writer = [fp](StringPiece sp) { |
286 | size_t n = fwrite(sp.data(), 1, sp.size(), fp); |
287 | if (n < sp.size()) { |
288 | throwSystemError("Formatter writeTo" , "fwrite failed" ); |
289 | } |
290 | }; |
291 | formatter(writer); |
292 | } |
293 | |
294 | namespace format_value { |
295 | |
296 | template <class FormatCallback> |
297 | void formatString(StringPiece val, FormatArg& arg, FormatCallback& cb) { |
298 | if (arg.width != FormatArg::kDefaultWidth && arg.width < 0) { |
299 | throw_exception<BadFormatArg>("folly::format: invalid width" ); |
300 | } |
301 | if (arg.precision != FormatArg::kDefaultPrecision && arg.precision < 0) { |
302 | throw_exception<BadFormatArg>("folly::format: invalid precision" ); |
303 | } |
304 | |
305 | if (arg.precision != FormatArg::kDefaultPrecision && |
306 | val.size() > static_cast<size_t>(arg.precision)) { |
307 | val.reset(val.data(), static_cast<size_t>(arg.precision)); |
308 | } |
309 | |
310 | constexpr int padBufSize = 128; |
311 | char padBuf[padBufSize]; |
312 | |
313 | // Output padding, no more than padBufSize at once |
314 | auto pad = [&padBuf, &cb, padBufSize](int chars) { |
315 | while (chars) { |
316 | int n = std::min(chars, padBufSize); |
317 | cb(StringPiece(padBuf, size_t(n))); |
318 | chars -= n; |
319 | } |
320 | }; |
321 | |
322 | int padRemaining = 0; |
323 | if (arg.width != FormatArg::kDefaultWidth && |
324 | val.size() < static_cast<size_t>(arg.width)) { |
325 | char fill = arg.fill == FormatArg::kDefaultFill ? ' ' : arg.fill; |
326 | int padChars = static_cast<int>(arg.width - val.size()); |
327 | memset(padBuf, fill, size_t(std::min(padBufSize, padChars))); |
328 | |
329 | switch (arg.align) { |
330 | case FormatArg::Align::DEFAULT: |
331 | case FormatArg::Align::LEFT: |
332 | padRemaining = padChars; |
333 | break; |
334 | case FormatArg::Align::CENTER: |
335 | pad(padChars / 2); |
336 | padRemaining = padChars - padChars / 2; |
337 | break; |
338 | case FormatArg::Align::RIGHT: |
339 | case FormatArg::Align::PAD_AFTER_SIGN: |
340 | pad(padChars); |
341 | break; |
342 | case FormatArg::Align::INVALID: |
343 | default: |
344 | abort(); |
345 | break; |
346 | } |
347 | } |
348 | |
349 | cb(val); |
350 | |
351 | if (padRemaining) { |
352 | pad(padRemaining); |
353 | } |
354 | } |
355 | |
356 | template <class FormatCallback> |
357 | void formatNumber( |
358 | StringPiece val, |
359 | int prefixLen, |
360 | FormatArg& arg, |
361 | FormatCallback& cb) { |
362 | // precision means something different for numbers |
363 | arg.precision = FormatArg::kDefaultPrecision; |
364 | if (arg.align == FormatArg::Align::DEFAULT) { |
365 | arg.align = FormatArg::Align::RIGHT; |
366 | } else if (prefixLen && arg.align == FormatArg::Align::PAD_AFTER_SIGN) { |
367 | // Split off the prefix, then do any padding if necessary |
368 | cb(val.subpiece(0, size_t(prefixLen))); |
369 | val.advance(size_t(prefixLen)); |
370 | arg.width = std::max(arg.width - prefixLen, 0); |
371 | } |
372 | format_value::formatString(val, arg, cb); |
373 | } |
374 | |
375 | template < |
376 | class FormatCallback, |
377 | class Derived, |
378 | bool containerMode, |
379 | class... Args> |
380 | void formatFormatter( |
381 | const BaseFormatter<Derived, containerMode, Args...>& formatter, |
382 | FormatArg& arg, |
383 | FormatCallback& cb) { |
384 | if (arg.width == FormatArg::kDefaultWidth && |
385 | arg.precision == FormatArg::kDefaultPrecision) { |
386 | // nothing to do |
387 | formatter(cb); |
388 | } else if ( |
389 | arg.align != FormatArg::Align::LEFT && |
390 | arg.align != FormatArg::Align::DEFAULT) { |
391 | // We can only avoid creating a temporary string if we align left, |
392 | // as we'd need to know the size beforehand otherwise |
393 | format_value::formatString(formatter.fbstr(), arg, cb); |
394 | } else { |
395 | auto fn = [&arg, &cb](StringPiece sp) mutable { |
396 | int sz = static_cast<int>(sp.size()); |
397 | if (arg.precision != FormatArg::kDefaultPrecision) { |
398 | sz = std::min(arg.precision, sz); |
399 | sp.reset(sp.data(), size_t(sz)); |
400 | arg.precision -= sz; |
401 | } |
402 | if (!sp.empty()) { |
403 | cb(sp); |
404 | if (arg.width != FormatArg::kDefaultWidth) { |
405 | arg.width = std::max(arg.width - sz, 0); |
406 | } |
407 | } |
408 | }; |
409 | formatter(fn); |
410 | if (arg.width != FormatArg::kDefaultWidth && arg.width != 0) { |
411 | // Rely on formatString to do appropriate padding |
412 | format_value::formatString(StringPiece(), arg, cb); |
413 | } |
414 | } |
415 | } |
416 | |
417 | } // namespace format_value |
418 | |
419 | // Definitions for default FormatValue classes |
420 | |
421 | // Integral types (except bool) |
422 | template <class T> |
423 | class FormatValue< |
424 | T, |
425 | typename std::enable_if< |
426 | std::is_integral<T>::value && !std::is_same<T, bool>::value>::type> { |
427 | public: |
428 | explicit FormatValue(T val) : val_(val) {} |
429 | |
430 | T getValue() const { |
431 | return val_; |
432 | } |
433 | |
434 | template <class FormatCallback> |
435 | void format(FormatArg& arg, FormatCallback& cb) const { |
436 | arg.validate(FormatArg::Type::INTEGER); |
437 | doFormat(arg, cb); |
438 | } |
439 | |
440 | template <class FormatCallback> |
441 | void doFormat(FormatArg& arg, FormatCallback& cb) const { |
442 | char presentation = arg.presentation; |
443 | if (presentation == FormatArg::kDefaultPresentation) { |
444 | presentation = std::is_same<T, char>::value ? 'c' : 'd'; |
445 | } |
446 | |
447 | // Do all work as unsigned, we'll add the prefix ('0' or '0x' if necessary) |
448 | // and sign ourselves. |
449 | typedef typename std::make_unsigned<T>::type UT; |
450 | UT uval; |
451 | char sign; |
452 | if (std::is_signed<T>::value) { |
453 | if (folly::is_negative(val_)) { |
454 | // avoid unary negation of unsigned types, which may be warned against |
455 | // avoid ub signed integer overflow, which ubsan checks against |
456 | uval = UT(0 - static_cast<UT>(val_)); |
457 | sign = '-'; |
458 | } else { |
459 | uval = static_cast<UT>(val_); |
460 | switch (arg.sign) { |
461 | case FormatArg::Sign::PLUS_OR_MINUS: |
462 | sign = '+'; |
463 | break; |
464 | case FormatArg::Sign::SPACE_OR_MINUS: |
465 | sign = ' '; |
466 | break; |
467 | case FormatArg::Sign::DEFAULT: |
468 | case FormatArg::Sign::MINUS: |
469 | case FormatArg::Sign::INVALID: |
470 | default: |
471 | sign = '\0'; |
472 | break; |
473 | } |
474 | } |
475 | } else { |
476 | uval = static_cast<UT>(val_); |
477 | sign = '\0'; |
478 | |
479 | arg.enforce( |
480 | arg.sign == FormatArg::Sign::DEFAULT, |
481 | "sign specifications not allowed for unsigned values" ); |
482 | } |
483 | |
484 | // max of: |
485 | // #x: 0x prefix + 16 bytes = 18 bytes |
486 | // #o: 0 prefix + 22 bytes = 23 bytes |
487 | // #b: 0b prefix + 64 bytes = 65 bytes |
488 | // ,d: 26 bytes (including thousands separators!) |
489 | // + nul terminator |
490 | // + 3 for sign and prefix shenanigans (see below) |
491 | constexpr size_t valBufSize = 69; |
492 | char valBuf[valBufSize]; |
493 | char* valBufBegin = nullptr; |
494 | char* valBufEnd = nullptr; |
495 | |
496 | int prefixLen = 0; |
497 | switch (presentation) { |
498 | case 'n': { |
499 | arg.enforce( |
500 | !arg.basePrefix, |
501 | "base prefix not allowed with '" , |
502 | presentation, |
503 | "' specifier" ); |
504 | |
505 | arg.enforce( |
506 | !arg.thousandsSeparator, |
507 | "cannot use ',' with the '" , |
508 | presentation, |
509 | "' specifier" ); |
510 | |
511 | valBufBegin = valBuf + 3; // room for sign and base prefix |
512 | #if defined(__ANDROID__) |
513 | int len = snprintf( |
514 | valBufBegin, |
515 | (valBuf + valBufSize) - valBufBegin, |
516 | "%" PRIuMAX, |
517 | static_cast<uintmax_t>(uval)); |
518 | #else |
519 | int len = snprintf( |
520 | valBufBegin, |
521 | size_t((valBuf + valBufSize) - valBufBegin), |
522 | "%ju" , |
523 | static_cast<uintmax_t>(uval)); |
524 | #endif |
525 | // valBufSize should always be big enough, so this should never |
526 | // happen. |
527 | assert(len < valBuf + valBufSize - valBufBegin); |
528 | valBufEnd = valBufBegin + len; |
529 | break; |
530 | } |
531 | case 'd': |
532 | arg.enforce( |
533 | !arg.basePrefix, |
534 | "base prefix not allowed with '" , |
535 | presentation, |
536 | "' specifier" ); |
537 | valBufBegin = valBuf + 3; // room for sign and base prefix |
538 | |
539 | // Use uintToBuffer, faster than sprintf |
540 | valBufEnd = valBufBegin + uint64ToBufferUnsafe(uval, valBufBegin); |
541 | if (arg.thousandsSeparator) { |
542 | detail::insertThousandsGroupingUnsafe(valBufBegin, &valBufEnd); |
543 | } |
544 | break; |
545 | case 'c': |
546 | arg.enforce( |
547 | !arg.basePrefix, |
548 | "base prefix not allowed with '" , |
549 | presentation, |
550 | "' specifier" ); |
551 | arg.enforce( |
552 | !arg.thousandsSeparator, |
553 | "thousands separator (',') not allowed with '" , |
554 | presentation, |
555 | "' specifier" ); |
556 | valBufBegin = valBuf + 3; |
557 | *valBufBegin = static_cast<char>(uval); |
558 | valBufEnd = valBufBegin + 1; |
559 | break; |
560 | case 'o': |
561 | case 'O': |
562 | arg.enforce( |
563 | !arg.thousandsSeparator, |
564 | "thousands separator (',') not allowed with '" , |
565 | presentation, |
566 | "' specifier" ); |
567 | valBufEnd = valBuf + valBufSize - 1; |
568 | valBufBegin = |
569 | valBuf + detail::uintToOctal(valBuf, valBufSize - 1, uval); |
570 | if (arg.basePrefix) { |
571 | *--valBufBegin = '0'; |
572 | prefixLen = 1; |
573 | } |
574 | break; |
575 | case 'x': |
576 | arg.enforce( |
577 | !arg.thousandsSeparator, |
578 | "thousands separator (',') not allowed with '" , |
579 | presentation, |
580 | "' specifier" ); |
581 | valBufEnd = valBuf + valBufSize - 1; |
582 | valBufBegin = |
583 | valBuf + detail::uintToHexLower(valBuf, valBufSize - 1, uval); |
584 | if (arg.basePrefix) { |
585 | *--valBufBegin = 'x'; |
586 | *--valBufBegin = '0'; |
587 | prefixLen = 2; |
588 | } |
589 | break; |
590 | case 'X': |
591 | arg.enforce( |
592 | !arg.thousandsSeparator, |
593 | "thousands separator (',') not allowed with '" , |
594 | presentation, |
595 | "' specifier" ); |
596 | valBufEnd = valBuf + valBufSize - 1; |
597 | valBufBegin = |
598 | valBuf + detail::uintToHexUpper(valBuf, valBufSize - 1, uval); |
599 | if (arg.basePrefix) { |
600 | *--valBufBegin = 'X'; |
601 | *--valBufBegin = '0'; |
602 | prefixLen = 2; |
603 | } |
604 | break; |
605 | case 'b': |
606 | case 'B': |
607 | arg.enforce( |
608 | !arg.thousandsSeparator, |
609 | "thousands separator (',') not allowed with '" , |
610 | presentation, |
611 | "' specifier" ); |
612 | valBufEnd = valBuf + valBufSize - 1; |
613 | valBufBegin = |
614 | valBuf + detail::uintToBinary(valBuf, valBufSize - 1, uval); |
615 | if (arg.basePrefix) { |
616 | *--valBufBegin = presentation; // 0b or 0B |
617 | *--valBufBegin = '0'; |
618 | prefixLen = 2; |
619 | } |
620 | break; |
621 | default: |
622 | arg.error("invalid specifier '" , presentation, "'" ); |
623 | } |
624 | |
625 | if (sign) { |
626 | *--valBufBegin = sign; |
627 | ++prefixLen; |
628 | } |
629 | |
630 | format_value::formatNumber( |
631 | StringPiece(valBufBegin, valBufEnd), prefixLen, arg, cb); |
632 | } |
633 | |
634 | private: |
635 | T val_; |
636 | }; |
637 | |
638 | // Bool |
639 | template <> |
640 | class FormatValue<bool> { |
641 | public: |
642 | explicit FormatValue(bool val) : val_(val) {} |
643 | |
644 | template <class FormatCallback> |
645 | void format(FormatArg& arg, FormatCallback& cb) const { |
646 | if (arg.presentation == FormatArg::kDefaultPresentation) { |
647 | arg.validate(FormatArg::Type::OTHER); |
648 | format_value::formatString(val_ ? "true" : "false" , arg, cb); |
649 | } else { // number |
650 | FormatValue<int>(val_).format(arg, cb); |
651 | } |
652 | } |
653 | |
654 | private: |
655 | bool val_; |
656 | }; |
657 | |
658 | // double |
659 | template <> |
660 | class FormatValue<double> { |
661 | public: |
662 | explicit FormatValue(double val) : val_(val) {} |
663 | |
664 | template <class FormatCallback> |
665 | void format(FormatArg& arg, FormatCallback& cb) const { |
666 | fbstring piece; |
667 | int prefixLen; |
668 | formatHelper(piece, prefixLen, arg); |
669 | format_value::formatNumber(piece, prefixLen, arg, cb); |
670 | } |
671 | |
672 | private: |
673 | void formatHelper(fbstring& piece, int& prefixLen, FormatArg& arg) const; |
674 | |
675 | double val_; |
676 | }; |
677 | |
678 | // float (defer to double) |
679 | template <> |
680 | class FormatValue<float> { |
681 | public: |
682 | explicit FormatValue(float val) : val_(val) {} |
683 | |
684 | template <class FormatCallback> |
685 | void format(FormatArg& arg, FormatCallback& cb) const { |
686 | FormatValue<double>(val_).format(arg, cb); |
687 | } |
688 | |
689 | private: |
690 | float val_; |
691 | }; |
692 | |
693 | // String-y types (implicitly convertible to StringPiece, except char*) |
694 | template <class T> |
695 | class FormatValue< |
696 | T, |
697 | typename std::enable_if< |
698 | (!std::is_pointer<T>::value || |
699 | !std::is_same< |
700 | char, |
701 | typename std::decay<typename std::remove_pointer<T>::type>::type>:: |
702 | value) && |
703 | std::is_convertible<T, StringPiece>::value>::type> { |
704 | public: |
705 | explicit FormatValue(StringPiece val) : val_(val) {} |
706 | |
707 | template <class FormatCallback> |
708 | void format(FormatArg& arg, FormatCallback& cb) const { |
709 | if (arg.keyEmpty()) { |
710 | arg.validate(FormatArg::Type::OTHER); |
711 | arg.enforce( |
712 | arg.presentation == FormatArg::kDefaultPresentation || |
713 | arg.presentation == 's', |
714 | "invalid specifier '" , |
715 | arg.presentation, |
716 | "'" ); |
717 | format_value::formatString(val_, arg, cb); |
718 | } else { |
719 | FormatValue<char>(val_.at(size_t(arg.splitIntKey()))).format(arg, cb); |
720 | } |
721 | } |
722 | |
723 | private: |
724 | StringPiece val_; |
725 | }; |
726 | |
727 | // Null |
728 | template <> |
729 | class FormatValue<std::nullptr_t> { |
730 | public: |
731 | explicit FormatValue(std::nullptr_t) {} |
732 | |
733 | template <class FormatCallback> |
734 | void format(FormatArg& arg, FormatCallback& cb) const { |
735 | arg.validate(FormatArg::Type::OTHER); |
736 | arg.enforce( |
737 | arg.presentation == FormatArg::kDefaultPresentation, |
738 | "invalid specifier '" , |
739 | arg.presentation, |
740 | "'" ); |
741 | format_value::formatString("(null)" , arg, cb); |
742 | } |
743 | }; |
744 | |
745 | // Partial specialization of FormatValue for char* |
746 | template <class T> |
747 | class FormatValue< |
748 | T*, |
749 | typename std::enable_if< |
750 | std::is_same<char, typename std::decay<T>::type>::value>::type> { |
751 | public: |
752 | explicit FormatValue(T* val) : val_(val) {} |
753 | |
754 | template <class FormatCallback> |
755 | void format(FormatArg& arg, FormatCallback& cb) const { |
756 | if (arg.keyEmpty()) { |
757 | if (!val_) { |
758 | FormatValue<std::nullptr_t>(nullptr).format(arg, cb); |
759 | } else { |
760 | FormatValue<StringPiece>(val_).format(arg, cb); |
761 | } |
762 | } else { |
763 | FormatValue<typename std::decay<T>::type>(val_[arg.splitIntKey()]) |
764 | .format(arg, cb); |
765 | } |
766 | } |
767 | |
768 | private: |
769 | T* val_; |
770 | }; |
771 | |
772 | // Partial specialization of FormatValue for void* |
773 | template <class T> |
774 | class FormatValue< |
775 | T*, |
776 | typename std::enable_if< |
777 | std::is_same<void, typename std::decay<T>::type>::value>::type> { |
778 | public: |
779 | explicit FormatValue(T* val) : val_(val) {} |
780 | |
781 | template <class FormatCallback> |
782 | void format(FormatArg& arg, FormatCallback& cb) const { |
783 | if (!val_) { |
784 | FormatValue<std::nullptr_t>(nullptr).format(arg, cb); |
785 | } else { |
786 | // Print as a pointer, in hex. |
787 | arg.validate(FormatArg::Type::OTHER); |
788 | arg.enforce( |
789 | arg.presentation == FormatArg::kDefaultPresentation, |
790 | "invalid specifier '" , |
791 | arg.presentation, |
792 | "'" ); |
793 | arg.basePrefix = true; |
794 | arg.presentation = 'x'; |
795 | if (arg.align == FormatArg::Align::DEFAULT) { |
796 | arg.align = FormatArg::Align::LEFT; |
797 | } |
798 | FormatValue<uintptr_t>(reinterpret_cast<uintptr_t>(val_)) |
799 | .doFormat(arg, cb); |
800 | } |
801 | } |
802 | |
803 | private: |
804 | T* val_; |
805 | }; |
806 | |
807 | template <class T, class = void> |
808 | class TryFormatValue { |
809 | public: |
810 | template <class FormatCallback> |
811 | static void |
812 | formatOrFail(T& /* value */, FormatArg& arg, FormatCallback& /* cb */) { |
813 | arg.error("No formatter available for this type" ); |
814 | } |
815 | }; |
816 | |
817 | template <class T> |
818 | class TryFormatValue< |
819 | T, |
820 | typename std::enable_if< |
821 | 0 < sizeof(FormatValue<typename std::decay<T>::type>)>::type> { |
822 | public: |
823 | template <class FormatCallback> |
824 | static void formatOrFail(T& value, FormatArg& arg, FormatCallback& cb) { |
825 | FormatValue<typename std::decay<T>::type>(value).format(arg, cb); |
826 | } |
827 | }; |
828 | |
829 | // Partial specialization of FormatValue for other pointers |
830 | template <class T> |
831 | class FormatValue< |
832 | T*, |
833 | typename std::enable_if< |
834 | !std::is_same<char, typename std::decay<T>::type>::value && |
835 | !std::is_same<void, typename std::decay<T>::type>::value>::type> { |
836 | public: |
837 | explicit FormatValue(T* val) : val_(val) {} |
838 | |
839 | template <class FormatCallback> |
840 | void format(FormatArg& arg, FormatCallback& cb) const { |
841 | if (arg.keyEmpty()) { |
842 | FormatValue<void*>((void*)val_).format(arg, cb); |
843 | } else { |
844 | TryFormatValue<T>::formatOrFail(val_[arg.splitIntKey()], arg, cb); |
845 | } |
846 | } |
847 | |
848 | private: |
849 | T* val_; |
850 | }; |
851 | |
852 | namespace detail { |
853 | |
854 | // std::array |
855 | template <class T, size_t N> |
856 | struct IndexableTraits<std::array<T, N>> |
857 | : public IndexableTraitsSeq<std::array<T, N>> {}; |
858 | |
859 | // std::vector |
860 | template <class T, class A> |
861 | struct IndexableTraits<std::vector<T, A>> |
862 | : public IndexableTraitsSeq<std::vector<T, A>> {}; |
863 | |
864 | // std::deque |
865 | template <class T, class A> |
866 | struct IndexableTraits<std::deque<T, A>> |
867 | : public IndexableTraitsSeq<std::deque<T, A>> {}; |
868 | |
869 | // std::map with integral keys |
870 | template <class K, class T, class C, class A> |
871 | struct IndexableTraits< |
872 | std::map<K, T, C, A>, |
873 | typename std::enable_if<std::is_integral<K>::value>::type> |
874 | : public IndexableTraitsAssoc<std::map<K, T, C, A>> {}; |
875 | |
876 | // std::unordered_map with integral keys |
877 | template <class K, class T, class H, class E, class A> |
878 | struct IndexableTraits< |
879 | std::unordered_map<K, T, H, E, A>, |
880 | typename std::enable_if<std::is_integral<K>::value>::type> |
881 | : public IndexableTraitsAssoc<std::unordered_map<K, T, H, E, A>> {}; |
882 | |
883 | } // namespace detail |
884 | |
885 | // Partial specialization of FormatValue for integer-indexable containers |
886 | template <class T> |
887 | class FormatValue<T, typename detail::IndexableTraits<T>::enabled> { |
888 | public: |
889 | explicit FormatValue(const T& val) : val_(val) {} |
890 | |
891 | template <class FormatCallback> |
892 | void format(FormatArg& arg, FormatCallback& cb) const { |
893 | FormatValue<typename std::decay< |
894 | typename detail::IndexableTraits<T>::value_type>::type>( |
895 | detail::IndexableTraits<T>::at(val_, arg.splitIntKey())) |
896 | .format(arg, cb); |
897 | } |
898 | |
899 | private: |
900 | const T& val_; |
901 | }; |
902 | |
903 | template <class Container, class Value> |
904 | class FormatValue< |
905 | detail::DefaultValueWrapper<Container, Value>, |
906 | typename detail::IndexableTraits<Container>::enabled> { |
907 | public: |
908 | explicit FormatValue(const detail::DefaultValueWrapper<Container, Value>& val) |
909 | : val_(val) {} |
910 | |
911 | template <class FormatCallback> |
912 | void format(FormatArg& arg, FormatCallback& cb) const { |
913 | FormatValue<typename std::decay< |
914 | typename detail::IndexableTraits<Container>::value_type>::type>( |
915 | detail::IndexableTraits<Container>::at( |
916 | val_.container, arg.splitIntKey(), val_.defaultValue)) |
917 | .format(arg, cb); |
918 | } |
919 | |
920 | private: |
921 | const detail::DefaultValueWrapper<Container, Value>& val_; |
922 | }; |
923 | |
924 | namespace detail { |
925 | |
926 | // Define enabled, key_type, convert from StringPiece to the key types |
927 | // that we support |
928 | template <class T> |
929 | struct KeyFromStringPiece; |
930 | |
931 | // std::string |
932 | template <> |
933 | struct KeyFromStringPiece<std::string> : public FormatTraitsBase { |
934 | typedef std::string key_type; |
935 | static std::string convert(StringPiece s) { |
936 | return s.toString(); |
937 | } |
938 | typedef void enabled; |
939 | }; |
940 | |
941 | // fbstring |
942 | template <> |
943 | struct KeyFromStringPiece<fbstring> : public FormatTraitsBase { |
944 | typedef fbstring key_type; |
945 | static fbstring convert(StringPiece s) { |
946 | return s.to<fbstring>(); |
947 | } |
948 | }; |
949 | |
950 | // StringPiece |
951 | template <> |
952 | struct KeyFromStringPiece<StringPiece> : public FormatTraitsBase { |
953 | typedef StringPiece key_type; |
954 | static StringPiece convert(StringPiece s) { |
955 | return s; |
956 | } |
957 | }; |
958 | |
959 | // Base class for associative types keyed by strings |
960 | template <class T> |
961 | struct KeyableTraitsAssoc : public FormatTraitsBase { |
962 | typedef typename T::key_type key_type; |
963 | typedef typename T::value_type::second_type value_type; |
964 | static const value_type& at(const T& map, StringPiece key) { |
965 | if (auto ptr = get_ptr(map, KeyFromStringPiece<key_type>::convert(key))) { |
966 | return *ptr; |
967 | } |
968 | throw_exception<FormatKeyNotFoundException>(key); |
969 | } |
970 | static const value_type& |
971 | at(const T& map, StringPiece key, const value_type& dflt) { |
972 | auto pos = map.find(KeyFromStringPiece<key_type>::convert(key)); |
973 | return pos != map.end() ? pos->second : dflt; |
974 | } |
975 | }; |
976 | |
977 | // Define enabled, key_type, value_type, at() for supported string-keyed |
978 | // types |
979 | template <class T, class Enabled = void> |
980 | struct KeyableTraits; |
981 | |
982 | // std::map with string key |
983 | template <class K, class T, class C, class A> |
984 | struct KeyableTraits< |
985 | std::map<K, T, C, A>, |
986 | typename KeyFromStringPiece<K>::enabled> |
987 | : public KeyableTraitsAssoc<std::map<K, T, C, A>> {}; |
988 | |
989 | // std::unordered_map with string key |
990 | template <class K, class T, class H, class E, class A> |
991 | struct KeyableTraits< |
992 | std::unordered_map<K, T, H, E, A>, |
993 | typename KeyFromStringPiece<K>::enabled> |
994 | : public KeyableTraitsAssoc<std::unordered_map<K, T, H, E, A>> {}; |
995 | |
996 | } // namespace detail |
997 | |
998 | // Partial specialization of FormatValue for string-keyed containers |
999 | template <class T> |
1000 | class FormatValue<T, typename detail::KeyableTraits<T>::enabled> { |
1001 | public: |
1002 | explicit FormatValue(const T& val) : val_(val) {} |
1003 | |
1004 | template <class FormatCallback> |
1005 | void format(FormatArg& arg, FormatCallback& cb) const { |
1006 | FormatValue<typename std::decay< |
1007 | typename detail::KeyableTraits<T>::value_type>::type>( |
1008 | detail::KeyableTraits<T>::at(val_, arg.splitKey())) |
1009 | .format(arg, cb); |
1010 | } |
1011 | |
1012 | private: |
1013 | const T& val_; |
1014 | }; |
1015 | |
1016 | template <class Container, class Value> |
1017 | class FormatValue< |
1018 | detail::DefaultValueWrapper<Container, Value>, |
1019 | typename detail::KeyableTraits<Container>::enabled> { |
1020 | public: |
1021 | explicit FormatValue(const detail::DefaultValueWrapper<Container, Value>& val) |
1022 | : val_(val) {} |
1023 | |
1024 | template <class FormatCallback> |
1025 | void format(FormatArg& arg, FormatCallback& cb) const { |
1026 | FormatValue<typename std::decay< |
1027 | typename detail::KeyableTraits<Container>::value_type>::type>( |
1028 | detail::KeyableTraits<Container>::at( |
1029 | val_.container, arg.splitKey(), val_.defaultValue)) |
1030 | .format(arg, cb); |
1031 | } |
1032 | |
1033 | private: |
1034 | const detail::DefaultValueWrapper<Container, Value>& val_; |
1035 | }; |
1036 | |
1037 | // Partial specialization of FormatValue for pairs |
1038 | template <class A, class B> |
1039 | class FormatValue<std::pair<A, B>> { |
1040 | public: |
1041 | explicit FormatValue(const std::pair<A, B>& val) : val_(val) {} |
1042 | |
1043 | template <class FormatCallback> |
1044 | void format(FormatArg& arg, FormatCallback& cb) const { |
1045 | int key = arg.splitIntKey(); |
1046 | switch (key) { |
1047 | case 0: |
1048 | FormatValue<typename std::decay<A>::type>(val_.first).format(arg, cb); |
1049 | break; |
1050 | case 1: |
1051 | FormatValue<typename std::decay<B>::type>(val_.second).format(arg, cb); |
1052 | break; |
1053 | default: |
1054 | arg.error("invalid index for pair" ); |
1055 | } |
1056 | } |
1057 | |
1058 | private: |
1059 | const std::pair<A, B>& val_; |
1060 | }; |
1061 | |
1062 | // Partial specialization of FormatValue for tuples |
1063 | template <class... Args> |
1064 | class FormatValue<std::tuple<Args...>> { |
1065 | typedef std::tuple<Args...> Tuple; |
1066 | |
1067 | public: |
1068 | explicit FormatValue(const Tuple& val) : val_(val) {} |
1069 | |
1070 | template <class FormatCallback> |
1071 | void format(FormatArg& arg, FormatCallback& cb) const { |
1072 | int key = arg.splitIntKey(); |
1073 | arg.enforce(key >= 0, "tuple index must be non-negative" ); |
1074 | doFormat(size_t(key), arg, cb); |
1075 | } |
1076 | |
1077 | private: |
1078 | static constexpr size_t valueCount = std::tuple_size<Tuple>::value; |
1079 | |
1080 | template <size_t K, class Callback> |
1081 | typename std::enable_if<K == valueCount>::type |
1082 | doFormatFrom(size_t i, FormatArg& arg, Callback& /* cb */) const { |
1083 | arg.error("tuple index out of range, max=" , i); |
1084 | } |
1085 | |
1086 | template <size_t K, class Callback> |
1087 | typename std::enable_if<(K < valueCount)>::type |
1088 | doFormatFrom(size_t i, FormatArg& arg, Callback& cb) const { |
1089 | if (i == K) { |
1090 | FormatValue<typename std::decay< |
1091 | typename std::tuple_element<K, Tuple>::type>::type>(std::get<K>(val_)) |
1092 | .format(arg, cb); |
1093 | } else { |
1094 | doFormatFrom<K + 1>(i, arg, cb); |
1095 | } |
1096 | } |
1097 | |
1098 | template <class Callback> |
1099 | void doFormat(size_t i, FormatArg& arg, Callback& cb) const { |
1100 | return doFormatFrom<0>(i, arg, cb); |
1101 | } |
1102 | |
1103 | const Tuple& val_; |
1104 | }; |
1105 | |
1106 | // Partial specialization of FormatValue for nested Formatters |
1107 | template <bool containerMode, class... Args, template <bool, class...> class F> |
1108 | class FormatValue< |
1109 | F<containerMode, Args...>, |
1110 | typename std::enable_if< |
1111 | detail::IsFormatter<F<containerMode, Args...>>::value>::type> { |
1112 | typedef typename F<containerMode, Args...>::BaseType FormatterValue; |
1113 | |
1114 | public: |
1115 | explicit FormatValue(const FormatterValue& f) : f_(f) {} |
1116 | |
1117 | template <class FormatCallback> |
1118 | void format(FormatArg& arg, FormatCallback& cb) const { |
1119 | format_value::formatFormatter(f_, arg, cb); |
1120 | } |
1121 | |
1122 | private: |
1123 | const FormatterValue& f_; |
1124 | }; |
1125 | |
1126 | /** |
1127 | * Formatter objects can be appended to strings, and therefore they're |
1128 | * compatible with folly::toAppend and folly::to. |
1129 | */ |
1130 | template <class Tgt, class Derived, bool containerMode, class... Args> |
1131 | typename std::enable_if<IsSomeString<Tgt>::value>::type toAppend( |
1132 | const BaseFormatter<Derived, containerMode, Args...>& value, |
1133 | Tgt* result) { |
1134 | value.appendTo(*result); |
1135 | } |
1136 | |
1137 | } // namespace folly |
1138 | |
1139 | FOLLY_POP_WARNING |
1140 | |