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
36FOLLY_PUSH_WARNING
37FOLLY_GNU_DISABLE_WARNING("-Wformat-nonliteral")
38
39namespace folly {
40
41namespace detail {
42
43// Updates the end of the buffer after the comma separators have been added.
44void insertThousandsGroupingUnsafe(char* start_buffer, char** end_buffer);
45
46extern const std::array<std::array<char, 2>, 256> formatHexUpper;
47extern const std::array<std::array<char, 2>, 256> formatHexLower;
48extern const std::array<std::array<char, 3>, 512> formatOctal;
49extern const std::array<std::array<char, 8>, 256> formatBinary;
50
51const size_t kMaxHexLength = 2 * sizeof(uintmax_t);
52const size_t kMaxOctalLength = 3 * sizeof(uintmax_t);
53const 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 */
64template <class Uint>
65size_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 */
89template <class Uint>
90inline 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 */
98template <class Uint>
99inline 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 */
111template <class Uint>
112size_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 */
141template <class Uint>
142size_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
161template <class Derived, bool containerMode, class... Args>
162BaseFormatter<Derived, containerMode, Args...>::BaseFormatter(
163 StringPiece str,
164 Args&&... args)
165 : str_(str), values_(std::forward<Args>(args)...) {}
166
167template <class Derived, bool containerMode, class... Args>
168template <class Output>
169void 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
280template <class Derived, bool containerMode, class... Args>
281void 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
293namespace format_value {
294
295template <class FormatCallback>
296void 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
354template <class FormatCallback>
355void 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
373template <
374 class FormatCallback,
375 class Derived,
376 bool containerMode,
377 class... Args>
378void 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)
420template <class T>
421class 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
632template <>
633class 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
652template <>
653class 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)
672template <>
673class 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*)
687template <class T>
688class 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
721template <>
722class 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*
739template <class T>
740class 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*
766template <class T>
767class 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
800template <class T, class = void>
801class 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
810template <class T>
811class 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
823template <class T>
824class 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
845namespace detail {
846
847// std::array
848template <class T, size_t N>
849struct IndexableTraits<std::array<T, N>>
850 : public IndexableTraitsSeq<std::array<T, N>> {};
851
852// std::vector
853template <class T, class A>
854struct IndexableTraits<std::vector<T, A>>
855 : public IndexableTraitsSeq<std::vector<T, A>> {};
856
857// std::deque
858template <class T, class A>
859struct IndexableTraits<std::deque<T, A>>
860 : public IndexableTraitsSeq<std::deque<T, A>> {};
861
862// std::map with integral keys
863template <class K, class T, class C, class A>
864struct 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
870template <class K, class T, class H, class E, class A>
871struct 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
879template <class T>
880class 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
896template <class Container, class Value>
897class 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
917namespace detail {
918
919// Define enabled, key_type, convert from StringPiece to the key types
920// that we support
921template <class T>
922struct KeyFromStringPiece;
923
924// std::string
925template <>
926struct 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
935template <>
936struct 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
944template <>
945struct 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
953template <class T>
954struct 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
972template <class T, class Enabled = void>
973struct KeyableTraits;
974
975// std::map with string key
976template <class K, class T, class C, class A>
977struct 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
983template <class K, class T, class H, class E, class A>
984struct 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
992template <class T>
993class 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
1009template <class Container, class Value>
1010class 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
1031template <class A, class B>
1032class 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
1056template <class... Args>
1057class 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
1100template <bool containerMode, class... Args, template <bool, class...> class F>
1101class 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 */
1123template <class Tgt, class Derived, bool containerMode, class... Args>
1124typename 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
1132FOLLY_POP_WARNING
1133