Adding support for printing arbitrary pointers
[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         valBufBegin = valBuf + 3;
433         valBufEnd = valBufBegin + uint64ToBufferUnsafe(uval, valBufBegin);
434       }
435       break;
436     case 'c':
437       arg.enforce(!arg.basePrefix,
438                   "base prefix not allowed with '", presentation,
439                   "' specifier");
440       arg.enforce(!arg.thousandsSeparator,
441                   "thousands separator (',') not allowed with '",
442                   presentation, "' specifier");
443       valBufBegin = valBuf + 3;
444       *valBufBegin = static_cast<char>(uval);
445       valBufEnd = valBufBegin + 1;
446       break;
447     case 'o':
448     case 'O':
449       arg.enforce(!arg.thousandsSeparator,
450                   "thousands separator (',') not allowed with '",
451                   presentation, "' specifier");
452       valBufEnd = valBuf + valBufSize - 1;
453       valBufBegin = valBuf + detail::uintToOctal(valBuf, valBufSize - 1, uval);
454       if (arg.basePrefix) {
455         *--valBufBegin = '0';
456         prefixLen = 1;
457       }
458       break;
459     case 'x':
460       arg.enforce(!arg.thousandsSeparator,
461                   "thousands separator (',') not allowed with '",
462                   presentation, "' specifier");
463       valBufEnd = valBuf + valBufSize - 1;
464       valBufBegin = valBuf + detail::uintToHexLower(valBuf, valBufSize - 1,
465                                                     uval);
466       if (arg.basePrefix) {
467         *--valBufBegin = 'x';
468         *--valBufBegin = '0';
469         prefixLen = 2;
470       }
471       break;
472     case 'X':
473       arg.enforce(!arg.thousandsSeparator,
474                   "thousands separator (',') not allowed with '",
475                   presentation, "' specifier");
476       valBufEnd = valBuf + valBufSize - 1;
477       valBufBegin = valBuf + detail::uintToHexUpper(valBuf, valBufSize - 1,
478                                                     uval);
479       if (arg.basePrefix) {
480         *--valBufBegin = 'X';
481         *--valBufBegin = '0';
482         prefixLen = 2;
483       }
484       break;
485     case 'b':
486     case 'B':
487       arg.enforce(!arg.thousandsSeparator,
488                   "thousands separator (',') not allowed with '",
489                   presentation, "' specifier");
490       valBufEnd = valBuf + valBufSize - 1;
491       valBufBegin = valBuf + detail::uintToBinary(valBuf, valBufSize - 1,
492                                                   uval);
493       if (arg.basePrefix) {
494         *--valBufBegin = presentation;  // 0b or 0B
495         *--valBufBegin = '0';
496         prefixLen = 2;
497       }
498       break;
499     default:
500       arg.error("invalid specifier '", presentation, "'");
501     }
502
503     if (sign) {
504       *--valBufBegin = sign;
505       ++prefixLen;
506     }
507
508     format_value::formatNumber(StringPiece(valBufBegin, valBufEnd), prefixLen,
509                                arg, cb);
510   }
511
512  private:
513   T val_;
514 };
515
516 // Bool
517 template <>
518 class FormatValue<bool> {
519  public:
520   explicit FormatValue(bool val) : val_(val) { }
521
522   template <class FormatCallback>
523   void format(FormatArg& arg, FormatCallback& cb) const {
524     if (arg.presentation == FormatArg::kDefaultPresentation) {
525       arg.validate(FormatArg::Type::OTHER);
526       format_value::formatString(val_ ? "true" : "false", arg, cb);
527     } else {  // number
528       FormatValue<int>(val_).format(arg, cb);
529     }
530   }
531
532  private:
533   bool val_;
534 };
535
536 // double
537 template <>
538 class FormatValue<double> {
539  public:
540   explicit FormatValue(double val) : val_(val) { }
541
542   template <class FormatCallback>
543   void format(FormatArg& arg, FormatCallback& cb) const {
544     using ::double_conversion::DoubleToStringConverter;
545     using ::double_conversion::StringBuilder;
546
547     arg.validate(FormatArg::Type::FLOAT);
548
549     if (arg.presentation == FormatArg::kDefaultPresentation) {
550       arg.presentation = 'g';
551     }
552
553     const char* infinitySymbol = isupper(arg.presentation) ? "INF" : "inf";
554     const char* nanSymbol = isupper(arg.presentation) ? "NAN" : "nan";
555     char exponentSymbol = isupper(arg.presentation) ? 'E' : 'e';
556
557     if (arg.precision == FormatArg::kDefaultPrecision) {
558       arg.precision = 6;
559     }
560
561     bool done = false;
562
563     // 2+: for null terminator and optional sign shenanigans.
564     char buf[2 + std::max({
565         (2 + DoubleToStringConverter::kMaxFixedDigitsBeforePoint +
566          DoubleToStringConverter::kMaxFixedDigitsAfterPoint),
567         (8 + DoubleToStringConverter::kMaxExponentialDigits),
568         (7 + DoubleToStringConverter::kMaxPrecisionDigits)})];
569     StringBuilder builder(buf + 1, sizeof(buf) - 1);
570
571     char plusSign;
572     switch (arg.sign) {
573     case FormatArg::Sign::PLUS_OR_MINUS:
574       plusSign = '+';
575       break;
576     case FormatArg::Sign::SPACE_OR_MINUS:
577       plusSign = ' ';
578       break;
579     default:
580       plusSign = '\0';
581       break;
582     };
583
584     double val = val_;
585     switch (arg.presentation) {
586     case '%':
587       val *= 100;
588     case 'f':
589     case 'F':
590       {
591         if (arg.precision >
592             DoubleToStringConverter::kMaxFixedDigitsAfterPoint) {
593           arg.precision = DoubleToStringConverter::kMaxFixedDigitsAfterPoint;
594         }
595         DoubleToStringConverter conv(
596             DoubleToStringConverter::EMIT_POSITIVE_EXPONENT_SIGN,
597             infinitySymbol,
598             nanSymbol,
599             exponentSymbol,
600             -4, arg.precision,
601             0, 0);
602         arg.enforce(conv.ToFixed(val, arg.precision, &builder),
603                     "fixed double conversion failed");
604       }
605       break;
606     case 'e':
607     case 'E':
608       {
609         if (arg.precision > DoubleToStringConverter::kMaxExponentialDigits) {
610           arg.precision = DoubleToStringConverter::kMaxExponentialDigits;
611         }
612
613         DoubleToStringConverter conv(
614             DoubleToStringConverter::EMIT_POSITIVE_EXPONENT_SIGN,
615             infinitySymbol,
616             nanSymbol,
617             exponentSymbol,
618             -4, arg.precision,
619             0, 0);
620         CHECK(conv.ToExponential(val, arg.precision, &builder));
621       }
622       break;
623     case 'n':  // should be locale-aware, but isn't
624     case 'g':
625     case 'G':
626       {
627         if (arg.precision < DoubleToStringConverter::kMinPrecisionDigits) {
628           arg.precision = DoubleToStringConverter::kMinPrecisionDigits;
629         } else if (arg.precision >
630                    DoubleToStringConverter::kMaxPrecisionDigits) {
631           arg.precision = DoubleToStringConverter::kMaxPrecisionDigits;
632         }
633         DoubleToStringConverter conv(
634             DoubleToStringConverter::EMIT_POSITIVE_EXPONENT_SIGN,
635             infinitySymbol,
636             nanSymbol,
637             exponentSymbol,
638             -4, arg.precision,
639             0, 0);
640         CHECK(conv.ToShortest(val, &builder));
641       }
642       break;
643     default:
644       arg.error("invalid specifier '", arg.presentation, "'");
645     }
646
647     int len = builder.position();
648     builder.Finalize();
649     DCHECK_GT(len, 0);
650
651     // Add '+' or ' ' sign if needed
652     char* p = buf + 1;
653     // anything that's neither negative nor nan
654     int prefixLen = 0;
655     if (plusSign && (*p != '-' && *p != 'n' && *p != 'N')) {
656       *--p = plusSign;
657       ++len;
658       prefixLen = 1;
659     } else if (*p == '-') {
660       prefixLen = 1;
661     }
662
663     format_value::formatNumber(StringPiece(p, len), prefixLen, arg, cb);
664   }
665
666  private:
667   double val_;
668 };
669
670 // float (defer to double)
671 template <>
672 class FormatValue<float> {
673  public:
674   explicit FormatValue(float val) : val_(val) { }
675
676   template <class FormatCallback>
677   void format(FormatArg& arg, FormatCallback& cb) const {
678     FormatValue<double>(val_).format(arg, cb);
679   }
680
681  private:
682   float val_;
683 };
684
685 // Sring-y types (implicitly convertible to StringPiece, except char*)
686 template <class T>
687 class FormatValue<
688   T, typename std::enable_if<
689       (!std::is_pointer<T>::value ||
690        !std::is_same<char, typename std::decay<
691           typename std::remove_pointer<T>::type>::type>::value) &&
692       std::is_convertible<T, StringPiece>::value>::type>
693   {
694  public:
695   explicit FormatValue(StringPiece val) : val_(val) { }
696
697   template <class FormatCallback>
698   void format(FormatArg& arg, FormatCallback& cb) const {
699     if (arg.keyEmpty()) {
700       arg.validate(FormatArg::Type::OTHER);
701       arg.enforce(arg.presentation == FormatArg::kDefaultPresentation ||
702                   arg.presentation == 's',
703                   "invalid specifier '", arg.presentation, "'");
704       format_value::formatString(val_, arg, cb);
705     } else {
706       FormatValue<char>(val_.at(arg.splitIntKey())).format(arg, cb);
707     }
708   }
709
710  private:
711   StringPiece val_;
712 };
713
714 // Null
715 template <>
716 class FormatValue<std::nullptr_t> {
717  public:
718   explicit FormatValue(std::nullptr_t) { }
719
720   template <class FormatCallback>
721   void format(FormatArg& arg, FormatCallback& cb) const {
722     arg.validate(FormatArg::Type::OTHER);
723     arg.enforce(arg.presentation == FormatArg::kDefaultPresentation,
724                 "invalid specifier '", arg.presentation, "'");
725     format_value::formatString("(null)", arg, cb);
726   }
727 };
728
729 // Partial specialization of FormatValue for char*
730 template <class T>
731 class FormatValue<
732   T*,
733   typename std::enable_if<
734       std::is_same<char, typename std::decay<T>::type>::value>::type>
735   {
736  public:
737   explicit FormatValue(T* val) : val_(val) { }
738
739   template <class FormatCallback>
740   void format(FormatArg& arg, FormatCallback& cb) const {
741     if (arg.keyEmpty()) {
742       if (!val_) {
743         FormatValue<std::nullptr_t>(nullptr).format(arg, cb);
744       } else {
745         FormatValue<StringPiece>(val_).format(arg, cb);
746       }
747     } else {
748       FormatValue<typename std::decay<T>::type>(
749           val_[arg.splitIntKey()]).format(arg, cb);
750     }
751   }
752
753  private:
754   T* val_;
755 };
756
757 // Partial specialization of FormatValue for void*
758 template <class T>
759 class FormatValue<
760   T*,
761   typename std::enable_if<
762       std::is_same<void, typename std::decay<T>::type>::value>::type>
763   {
764  public:
765   explicit FormatValue(T* val) : val_(val) { }
766
767   template <class FormatCallback>
768   void format(FormatArg& arg, FormatCallback& cb) const {
769     if (!val_) {
770       FormatValue<std::nullptr_t>(nullptr).format(arg, cb);
771     } else {
772       // Print as a pointer, in hex.
773       arg.validate(FormatArg::Type::OTHER);
774       arg.enforce(arg.presentation == FormatArg::kDefaultPresentation,
775                   "invalid specifier '", arg.presentation, "'");
776       arg.basePrefix = true;
777       arg.presentation = 'x';
778       if (arg.align == FormatArg::Align::DEFAULT) {
779         arg.align = FormatArg::Align::LEFT;
780       }
781       FormatValue<uintptr_t>(
782           reinterpret_cast<uintptr_t>(val_)).doFormat(arg, cb);
783     }
784   }
785
786  private:
787   T* val_;
788 };
789
790 template <class T, class = void>
791 class TryFormatValue {
792  public:
793   template <class FormatCallback>
794   static void formatOrFail(T& value, FormatArg& arg, FormatCallback& cb) {
795     arg.error("No formatter available for this type");
796   }
797 };
798
799 template <class T>
800 class TryFormatValue<
801   T,
802   typename std::enable_if<
803       0 < sizeof(FormatValue<typename std::decay<T>::type>)>::type>
804   {
805  public:
806   template <class FormatCallback>
807   static void formatOrFail(T& value, FormatArg& arg, FormatCallback& cb) {
808     FormatValue<typename std::decay<T>::type>(value).format(arg, cb);
809   }
810 };
811
812 // Partial specialization of FormatValue for other pointers
813 template <class T>
814 class FormatValue<
815   T*,
816   typename std::enable_if<
817       !std::is_same<char, typename std::decay<T>::type>::value &&
818       !std::is_same<void, typename std::decay<T>::type>::value>::type>
819   {
820  public:
821   explicit FormatValue(T* val) : val_(val) { }
822
823   template <class FormatCallback>
824   void format(FormatArg& arg, FormatCallback& cb) const {
825     if (arg.keyEmpty()) {
826       FormatValue<void*>((void*)val_).format(arg, cb);
827     } else {
828       TryFormatValue<T>::formatOrFail(val_[arg.splitIntKey()], arg, cb);
829     }
830   }
831  private:
832   T* val_;
833 };
834
835 namespace detail {
836
837 // Shortcut, so we don't have to use enable_if everywhere
838 struct FormatTraitsBase {
839   typedef void enabled;
840 };
841
842 // Traits that define enabled, value_type, and at() for anything
843 // indexable with integral keys: pointers, arrays, vectors, and maps
844 // with integral keys
845 template <class T, class Enable=void> struct IndexableTraits;
846
847 // Base class for sequences (vectors, deques)
848 template <class C>
849 struct IndexableTraitsSeq : public FormatTraitsBase {
850   typedef C container_type;
851   typedef typename C::value_type value_type;
852   static const value_type& at(const C& c, int idx) {
853     return c.at(idx);
854   }
855 };
856
857 // Base class for associative types (maps)
858 template <class C>
859 struct IndexableTraitsAssoc : public FormatTraitsBase {
860   typedef typename C::value_type::second_type value_type;
861   static const value_type& at(const C& c, int idx) {
862     return c.at(static_cast<typename C::key_type>(idx));
863   }
864 };
865
866 // std::array
867 template <class T, size_t N>
868 struct IndexableTraits<std::array<T, N>>
869   : public IndexableTraitsSeq<std::array<T, N>> {
870 };
871
872 // std::vector
873 template <class T, class A>
874 struct IndexableTraits<std::vector<T, A>>
875   : public IndexableTraitsSeq<std::vector<T, A>> {
876 };
877
878 // std::deque
879 template <class T, class A>
880 struct IndexableTraits<std::deque<T, A>>
881   : public IndexableTraitsSeq<std::deque<T, A>> {
882 };
883
884 // fbvector
885 template <class T, class A>
886 struct IndexableTraits<fbvector<T, A>>
887   : public IndexableTraitsSeq<fbvector<T, A>> {
888 };
889
890 // small_vector
891 template <class T, size_t M, class A, class B, class C>
892 struct IndexableTraits<small_vector<T, M, A, B, C>>
893   : public IndexableTraitsSeq<small_vector<T, M, A, B, C>> {
894 };
895
896 // std::map with integral keys
897 template <class K, class T, class C, class A>
898 struct IndexableTraits<
899   std::map<K, T, C, A>,
900   typename std::enable_if<std::is_integral<K>::value>::type>
901   : public IndexableTraitsAssoc<std::map<K, T, C, A>> {
902 };
903
904 // std::unordered_map with integral keys
905 template <class K, class T, class H, class E, class A>
906 struct IndexableTraits<
907   std::unordered_map<K, T, H, E, A>,
908   typename std::enable_if<std::is_integral<K>::value>::type>
909   : public IndexableTraitsAssoc<std::unordered_map<K, T, H, E, A>> {
910 };
911
912 }  // namespace detail
913
914 // Partial specialization of FormatValue for integer-indexable containers
915 template <class T>
916 class FormatValue<
917   T,
918   typename detail::IndexableTraits<T>::enabled> {
919  public:
920   explicit FormatValue(const T& val) : val_(val) { }
921
922   template <class FormatCallback>
923   void format(FormatArg& arg, FormatCallback& cb) const {
924     FormatValue<typename std::decay<
925       typename detail::IndexableTraits<T>::value_type>::type>(
926         detail::IndexableTraits<T>::at(
927             val_, arg.splitIntKey())).format(arg, cb);
928   }
929
930  private:
931   const T& val_;
932 };
933
934 namespace detail {
935
936 // Define enabled, key_type, convert from StringPiece to the key types
937 // that we support
938 template <class T> struct KeyFromStringPiece;
939
940 // std::string
941 template <>
942 struct KeyFromStringPiece<std::string> : public FormatTraitsBase {
943   typedef std::string key_type;
944   static std::string convert(StringPiece s) {
945     return s.toString();
946   }
947   typedef void enabled;
948 };
949
950 // fbstring
951 template <>
952 struct KeyFromStringPiece<fbstring> : public FormatTraitsBase {
953   typedef fbstring key_type;
954   static fbstring convert(StringPiece s) {
955     return s.toFbstring();
956   }
957 };
958
959 // StringPiece
960 template <>
961 struct KeyFromStringPiece<StringPiece> : public FormatTraitsBase {
962   typedef StringPiece key_type;
963   static StringPiece convert(StringPiece s) {
964     return s;
965   }
966 };
967
968 // Base class for associative types keyed by strings
969 template <class T> struct KeyableTraitsAssoc : public FormatTraitsBase {
970   typedef typename T::key_type key_type;
971   typedef typename T::value_type::second_type value_type;
972   static const value_type& at(const T& map, StringPiece key) {
973     return map.at(KeyFromStringPiece<key_type>::convert(key));
974   }
975 };
976
977 // Define enabled, key_type, value_type, at() for supported string-keyed
978 // types
979 template <class T, class Enabled=void> struct KeyableTraits;
980
981 // std::map with string key
982 template <class K, class T, class C, class A>
983 struct KeyableTraits<
984   std::map<K, T, C, A>,
985   typename KeyFromStringPiece<K>::enabled>
986   : public KeyableTraitsAssoc<std::map<K, T, C, A>> {
987 };
988
989 // std::unordered_map with string key
990 template <class K, class T, class H, class E, class A>
991 struct KeyableTraits<
992   std::unordered_map<K, T, H, E, A>,
993   typename KeyFromStringPiece<K>::enabled>
994   : public KeyableTraitsAssoc<std::unordered_map<K, T, H, E, A>> {
995 };
996
997 }  // namespace detail
998
999 // Partial specialization of FormatValue for string-keyed containers
1000 template <class T>
1001 class FormatValue<
1002   T,
1003   typename detail::KeyableTraits<T>::enabled> {
1004  public:
1005   explicit FormatValue(const T& val) : val_(val) { }
1006
1007   template <class FormatCallback>
1008   void format(FormatArg& arg, FormatCallback& cb) const {
1009     FormatValue<typename std::decay<
1010       typename detail::KeyableTraits<T>::value_type>::type>(
1011         detail::KeyableTraits<T>::at(
1012             val_, arg.splitKey())).format(arg, cb);
1013   }
1014
1015  private:
1016   const T& val_;
1017 };
1018
1019 // Partial specialization of FormatValue for pairs
1020 template <class A, class B>
1021 class FormatValue<std::pair<A, B>> {
1022  public:
1023   explicit FormatValue(const std::pair<A, B>& val) : val_(val) { }
1024
1025   template <class FormatCallback>
1026   void format(FormatArg& arg, FormatCallback& cb) const {
1027     int key = arg.splitIntKey();
1028     switch (key) {
1029     case 0:
1030       FormatValue<typename std::decay<A>::type>(val_.first).format(arg, cb);
1031       break;
1032     case 1:
1033       FormatValue<typename std::decay<B>::type>(val_.second).format(arg, cb);
1034       break;
1035     default:
1036       arg.error("invalid index for pair");
1037     }
1038   }
1039
1040  private:
1041   const std::pair<A, B>& val_;
1042 };
1043
1044 // Partial specialization of FormatValue for tuples
1045 template <class... Args>
1046 class FormatValue<std::tuple<Args...>> {
1047   typedef std::tuple<Args...> Tuple;
1048  public:
1049   explicit FormatValue(const Tuple& val) : val_(val) { }
1050
1051   template <class FormatCallback>
1052   void format(FormatArg& arg, FormatCallback& cb) const {
1053     int key = arg.splitIntKey();
1054     arg.enforce(key >= 0, "tuple index must be non-negative");
1055     doFormat(key, arg, cb);
1056   }
1057
1058  private:
1059   static constexpr size_t valueCount = std::tuple_size<Tuple>::value;
1060
1061   template <size_t K, class Callback>
1062   typename std::enable_if<K == valueCount>::type
1063   doFormatFrom(size_t i, FormatArg& arg, Callback& cb) const {
1064     arg.enforce("tuple index out of range, max=", i);
1065   }
1066
1067   template <size_t K, class Callback>
1068   typename std::enable_if<(K < valueCount)>::type
1069   doFormatFrom(size_t i, FormatArg& arg, Callback& cb) const {
1070     if (i == K) {
1071       FormatValue<typename std::decay<
1072         typename std::tuple_element<K, Tuple>::type>::type>(
1073           std::get<K>(val_)).format(arg, cb);
1074     } else {
1075       doFormatFrom<K+1>(i, arg, cb);
1076     }
1077   }
1078
1079   template <class Callback>
1080   void doFormat(size_t i, FormatArg& arg, Callback& cb) const {
1081     return doFormatFrom<0>(i, arg, cb);
1082   }
1083
1084   const Tuple& val_;
1085 };
1086
1087 // Partial specialization of FormatValue for nested Formatters
1088 template <bool containerMode, class... Args>
1089 class FormatValue<Formatter<containerMode, Args...>, void> {
1090   typedef Formatter<containerMode, Args...> FormatterValue;
1091  public:
1092   explicit FormatValue(const FormatterValue& f) : f_(f) { }
1093
1094   template <class FormatCallback>
1095   void format(FormatArg& arg, FormatCallback& cb) const {
1096     format_value::formatFormatter(f_, arg, cb);
1097   }
1098  private:
1099   const FormatterValue& f_;
1100 };
1101
1102 /**
1103  * Formatter objects can be appended to strings, and therefore they're
1104  * compatible with folly::toAppend and folly::to.
1105  */
1106 template <class Tgt, bool containerMode, class... Args>
1107 typename std::enable_if<
1108    detail::IsSomeString<Tgt>::value>::type
1109 toAppend(const Formatter<containerMode, Args...>& value, Tgt * result) {
1110   value.appendTo(*result);
1111 }
1112
1113 }  // namespace folly