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