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