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