2 * Copyright 2015 Facebook, Inc.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #ifndef FOLLY_FORMAT_H_
18 #error This file may only be included from Format.h.
21 #include <folly/Exception.h>
22 #include <folly/Traits.h>
24 // Ignore -Wformat-nonliteral warnings within this file
25 #pragma GCC diagnostic push
26 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
32 // Updates the end of the buffer after the comma separators have been added.
33 void insertThousandsGroupingUnsafe(char* start_buffer, char** end_buffer);
35 extern const char formatHexUpper[256][2];
36 extern const char formatHexLower[256][2];
37 extern const char formatOctal[512][3];
38 extern const char formatBinary[256][8];
40 const size_t kMaxHexLength = 2 * sizeof(uintmax_t);
41 const size_t kMaxOctalLength = 3 * sizeof(uintmax_t);
42 const size_t kMaxBinaryLength = 8 * sizeof(uintmax_t);
45 * Convert an unsigned to hex, using repr (which maps from each possible
46 * 2-hex-bytes value to the 2-character representation).
48 * Just like folly::detail::uintToBuffer in Conv.h, writes at the *end* of
49 * the supplied buffer and returns the offset of the beginning of the string
50 * from the start of the buffer. The formatted string will be in range
51 * [buf+begin, buf+bufLen).
54 size_t uintToHex(char* buffer, size_t bufLen, Uint v,
55 const char (&repr)[256][2]) {
56 // 'v >>= 7, v >>= 1' is no more than a work around to get rid of shift size
57 // warning when Uint = uint8_t (it's false as v >= 256 implies sizeof(v) > 1).
58 for (; !less_than<unsigned, 256>(v); v >>= 7, v >>= 1) {
61 buffer[bufLen] = repr[b][0];
62 buffer[bufLen + 1] = repr[b][1];
64 buffer[--bufLen] = repr[v][1];
66 buffer[--bufLen] = repr[v][0];
72 * Convert an unsigned to hex, using lower-case letters for the digits
73 * above 9. See the comments for uintToHex.
76 inline size_t uintToHexLower(char* buffer, size_t bufLen, Uint v) {
77 return uintToHex(buffer, bufLen, v, formatHexLower);
81 * Convert an unsigned to hex, using upper-case letters for the digits
82 * above 9. See the comments for uintToHex.
85 inline size_t uintToHexUpper(char* buffer, size_t bufLen, Uint v) {
86 return uintToHex(buffer, bufLen, v, formatHexUpper);
90 * Convert an unsigned to octal.
92 * Just like folly::detail::uintToBuffer in Conv.h, writes at the *end* of
93 * the supplied buffer and returns the offset of the beginning of the string
94 * from the start of the buffer. The formatted string will be in range
95 * [buf+begin, buf+bufLen).
98 size_t uintToOctal(char* buffer, size_t bufLen, Uint v) {
99 auto& repr = formatOctal;
100 // 'v >>= 7, v >>= 2' is no more than a work around to get rid of shift size
101 // warning when Uint = uint8_t (it's false as v >= 512 implies sizeof(v) > 1).
102 for (; !less_than<unsigned, 512>(v); v >>= 7, v >>= 2) {
105 buffer[bufLen] = repr[b][0];
106 buffer[bufLen + 1] = repr[b][1];
107 buffer[bufLen + 2] = repr[b][2];
109 buffer[--bufLen] = repr[v][2];
111 buffer[--bufLen] = repr[v][1];
114 buffer[--bufLen] = repr[v][0];
120 * Convert an unsigned to binary.
122 * Just like folly::detail::uintToBuffer in Conv.h, writes at the *end* of
123 * the supplied buffer and returns the offset of the beginning of the string
124 * from the start of the buffer. The formatted string will be in range
125 * [buf+begin, buf+bufLen).
127 template <class Uint>
128 size_t uintToBinary(char* buffer, size_t bufLen, Uint v) {
129 auto& repr = formatBinary;
131 buffer[--bufLen] = '0';
134 for (; v; v >>= 7, v >>= 1) {
137 memcpy(buffer + bufLen, &(repr[b][0]), 8);
139 while (buffer[bufLen] == '0') {
145 } // namespace detail
147 template <class Derived, bool containerMode, class... Args>
148 BaseFormatter<Derived, containerMode, Args...>::BaseFormatter(StringPiece str,
151 values_(FormatValue<typename std::decay<Args>::type>(
152 std::forward<Args>(args))...) {
153 static_assert(!containerMode || sizeof...(Args) == 1,
154 "Exactly one argument required in container mode");
157 template <class Derived, bool containerMode, class... Args>
158 void BaseFormatter<Derived, containerMode, Args...>::handleFormatStrError()
161 LOG(FATAL) << "folly::format: bad format string \"" << str_ << "\": " <<
162 folly::exceptionStr(std::current_exception());
167 template <class Derived, bool containerMode, class... Args>
168 template <class Output>
169 void BaseFormatter<Derived, containerMode, Args...>::operator()(Output& out)
171 // Catch BadFormatArg and range_error exceptions, and call
172 // handleFormatStrError().
174 // These exception types indicate a problem with the format string. Most
175 // format strings are string literals specified by the programmer. If they
176 // have a problem, this is usually a programmer bug. We want to crash to
177 // ensure that these are found early on during development.
179 // BadFormatArg is thrown by the Format.h code, while range_error is thrown
180 // by Conv.h, which is used in several places in our format string
183 // (Note: This behavior is slightly dangerous. If the Output object throws a
184 // BadFormatArg or a range_error, we will also crash the program, even if it
185 // wasn't an issue with the format string. This seems highly unlikely
186 // though, and none of our current Output objects can throw these errors.)
188 // We also throw out_of_range errors if the format string references an
189 // argument that isn't present (or a key that isn't present in one of the
190 // argument containers). However, at the moment we don't crash on these
191 // errors, as it is likely that the container is dynamic at runtime.
194 } catch (const BadFormatArg& ex) {
195 handleFormatStrError();
196 } catch (const std::range_error& ex) {
197 handleFormatStrError();
201 template <class Derived, bool containerMode, class... Args>
202 template <class Output>
203 void BaseFormatter<Derived, containerMode, Args...>::appendOutput(Output& out)
206 // Copy raw string (without format specifiers) to output;
207 // not as simple as we'd like, as we still need to translate "}}" to "}"
208 // and throw if we see any lone "}"
209 auto outputString = [&out] (StringPiece s) {
213 auto q = static_cast<const char*>(memchr(p, '}', end - p));
215 out(StringPiece(p, end));
219 out(StringPiece(p, q));
222 if (p == end || *p != '}') {
223 throw BadFormatArg("folly::format: single '}' in format string");
229 auto p = str_.begin();
230 auto end = str_.end();
233 bool hasDefaultArgIndex = false;
234 bool hasExplicitArgIndex = false;
236 auto q = static_cast<const char*>(memchr(p, '{', end - p));
238 outputString(StringPiece(p, end));
241 outputString(StringPiece(p, q));
245 throw BadFormatArg("folly::format: '}' at end of format string");
250 out(StringPiece(p, 1));
256 q = static_cast<const char*>(memchr(p, '}', end - p));
258 throw BadFormatArg("folly::format: missing ending '}'");
260 FormatArg arg(StringPiece(p, q));
264 auto piece = arg.splitKey<true>(); // empty key component is okay
265 if (containerMode) { // static
267 arg.setNextIntKey(nextArg++);
268 hasDefaultArgIndex = true;
270 arg.setNextKey(piece);
271 hasExplicitArgIndex = true;
275 argIndex = nextArg++;
276 hasDefaultArgIndex = true;
279 argIndex = to<int>(piece);
280 } catch (const std::out_of_range& e) {
281 arg.error("argument index must be integer");
283 arg.enforce(argIndex >= 0, "argument index must be non-negative");
284 hasExplicitArgIndex = true;
288 if (hasDefaultArgIndex && hasExplicitArgIndex) {
290 "folly::format: may not have both default and explicit arg indexes");
293 doFormat(argIndex, arg, out);
297 template <class Derived, bool containerMode, class... Args>
298 void writeTo(FILE* fp,
299 const BaseFormatter<Derived, containerMode, Args...>& formatter) {
300 auto writer = [fp] (StringPiece sp) {
301 size_t n = fwrite(sp.data(), 1, sp.size(), fp);
303 throwSystemError("Formatter writeTo", "fwrite failed");
309 namespace format_value {
311 template <class FormatCallback>
312 void formatString(StringPiece val, FormatArg& arg, FormatCallback& cb) {
313 if (arg.width != FormatArg::kDefaultWidth && arg.width < 0) {
314 throw BadFormatArg("folly::format: invalid width");
316 if (arg.precision != FormatArg::kDefaultPrecision && arg.precision < 0) {
317 throw BadFormatArg("folly::format: invalid precision");
320 // XXX: clang should be smart enough to not need the two static_cast<size_t>
321 // uses below given the above checks. If clang ever becomes that smart, we
322 // should remove the otherwise unnecessary warts.
324 if (arg.precision != FormatArg::kDefaultPrecision &&
325 val.size() > static_cast<size_t>(arg.precision)) {
326 val.reset(val.data(), arg.precision);
329 constexpr int padBufSize = 128;
330 char padBuf[padBufSize];
332 // Output padding, no more than padBufSize at once
333 auto pad = [&padBuf, &cb, padBufSize] (int chars) {
335 int n = std::min(chars, padBufSize);
336 cb(StringPiece(padBuf, n));
341 int padRemaining = 0;
342 if (arg.width != FormatArg::kDefaultWidth &&
343 val.size() < static_cast<size_t>(arg.width)) {
344 char fill = arg.fill == FormatArg::kDefaultFill ? ' ' : arg.fill;
345 int padChars = static_cast<int> (arg.width - val.size());
346 memset(padBuf, fill, std::min(padBufSize, padChars));
349 case FormatArg::Align::DEFAULT:
350 case FormatArg::Align::LEFT:
351 padRemaining = padChars;
353 case FormatArg::Align::CENTER:
355 padRemaining = padChars - padChars / 2;
357 case FormatArg::Align::RIGHT:
358 case FormatArg::Align::PAD_AFTER_SIGN:
374 template <class FormatCallback>
375 void formatNumber(StringPiece val, int prefixLen, FormatArg& arg,
376 FormatCallback& cb) {
377 // precision means something different for numbers
378 arg.precision = FormatArg::kDefaultPrecision;
379 if (arg.align == FormatArg::Align::DEFAULT) {
380 arg.align = FormatArg::Align::RIGHT;
381 } else if (prefixLen && arg.align == FormatArg::Align::PAD_AFTER_SIGN) {
382 // Split off the prefix, then do any padding if necessary
383 cb(val.subpiece(0, prefixLen));
384 val.advance(prefixLen);
385 arg.width = std::max(arg.width - prefixLen, 0);
387 format_value::formatString(val, arg, cb);
390 template <class FormatCallback,
394 void formatFormatter(
395 const BaseFormatter<Derived, containerMode, Args...>& formatter,
397 FormatCallback& cb) {
398 if (arg.width == FormatArg::kDefaultWidth &&
399 arg.precision == FormatArg::kDefaultPrecision) {
402 } else if (arg.align != FormatArg::Align::LEFT &&
403 arg.align != FormatArg::Align::DEFAULT) {
404 // We can only avoid creating a temporary string if we align left,
405 // as we'd need to know the size beforehand otherwise
406 format_value::formatString(formatter.fbstr(), arg, cb);
408 auto fn = [&arg, &cb] (StringPiece sp) mutable {
409 int sz = static_cast<int>(sp.size());
410 if (arg.precision != FormatArg::kDefaultPrecision) {
411 sz = std::min(arg.precision, sz);
412 sp.reset(sp.data(), sz);
417 if (arg.width != FormatArg::kDefaultWidth) {
418 arg.width = std::max(arg.width - sz, 0);
423 if (arg.width != FormatArg::kDefaultWidth && arg.width != 0) {
424 // Rely on formatString to do appropriate padding
425 format_value::formatString(StringPiece(), arg, cb);
430 } // namespace format_value
432 // Definitions for default FormatValue classes
434 // Integral types (except bool)
437 T, typename std::enable_if<
438 std::is_integral<T>::value &&
439 !std::is_same<T, bool>::value>::type>
442 explicit FormatValue(T val) : val_(val) { }
443 template <class FormatCallback>
444 void format(FormatArg& arg, FormatCallback& cb) const {
445 arg.validate(FormatArg::Type::INTEGER);
449 template <class FormatCallback>
450 void doFormat(FormatArg& arg, FormatCallback& cb) const {
451 char presentation = arg.presentation;
452 if (presentation == FormatArg::kDefaultPresentation) {
453 presentation = std::is_same<T, char>::value ? 'c' : 'd';
456 // Do all work as unsigned, we'll add the prefix ('0' or '0x' if necessary)
457 // and sign ourselves.
458 typedef typename std::make_unsigned<T>::type UT;
461 if (std::is_signed<T>::value) {
462 if (folly::is_negative(val_)) {
463 uval = static_cast<UT>(-val_);
466 uval = static_cast<UT>(val_);
468 case FormatArg::Sign::PLUS_OR_MINUS:
471 case FormatArg::Sign::SPACE_OR_MINUS:
483 arg.enforce(arg.sign == FormatArg::Sign::DEFAULT,
484 "sign specifications not allowed for unsigned values");
488 // #x: 0x prefix + 16 bytes = 18 bytes
489 // #o: 0 prefix + 22 bytes = 23 bytes
490 // #b: 0b prefix + 64 bytes = 65 bytes
491 // ,d: 26 bytes (including thousands separators!)
493 // + 3 for sign and prefix shenanigans (see below)
494 constexpr size_t valBufSize = 69;
495 char valBuf[valBufSize];
496 char* valBufBegin = nullptr;
497 char* valBufEnd = nullptr;
500 switch (presentation) {
502 arg.enforce(!arg.basePrefix,
503 "base prefix not allowed with '", presentation,
506 arg.enforce(!arg.thousandsSeparator,
507 "cannot use ',' with the '", presentation,
510 valBufBegin = valBuf + 3; // room for sign and base prefix
511 valBufEnd = valBufBegin + sprintf(valBufBegin, "%'ju",
512 static_cast<uintmax_t>(uval));
515 arg.enforce(!arg.basePrefix,
516 "base prefix not allowed with '", presentation,
518 valBufBegin = valBuf + 3; // room for sign and base prefix
520 // Use uintToBuffer, faster than sprintf
521 valBufEnd = valBufBegin + uint64ToBufferUnsafe(uval, valBufBegin);
522 if (arg.thousandsSeparator) {
523 detail::insertThousandsGroupingUnsafe(valBufBegin, &valBufEnd);
527 arg.enforce(!arg.basePrefix,
528 "base prefix not allowed with '", presentation,
530 arg.enforce(!arg.thousandsSeparator,
531 "thousands separator (',') not allowed with '",
532 presentation, "' specifier");
533 valBufBegin = valBuf + 3;
534 *valBufBegin = static_cast<char>(uval);
535 valBufEnd = valBufBegin + 1;
539 arg.enforce(!arg.thousandsSeparator,
540 "thousands separator (',') not allowed with '",
541 presentation, "' specifier");
542 valBufEnd = valBuf + valBufSize - 1;
543 valBufBegin = valBuf + detail::uintToOctal(valBuf, valBufSize - 1, uval);
544 if (arg.basePrefix) {
545 *--valBufBegin = '0';
550 arg.enforce(!arg.thousandsSeparator,
551 "thousands separator (',') not allowed with '",
552 presentation, "' specifier");
553 valBufEnd = valBuf + valBufSize - 1;
554 valBufBegin = valBuf + detail::uintToHexLower(valBuf, valBufSize - 1,
556 if (arg.basePrefix) {
557 *--valBufBegin = 'x';
558 *--valBufBegin = '0';
563 arg.enforce(!arg.thousandsSeparator,
564 "thousands separator (',') not allowed with '",
565 presentation, "' specifier");
566 valBufEnd = valBuf + valBufSize - 1;
567 valBufBegin = valBuf + detail::uintToHexUpper(valBuf, valBufSize - 1,
569 if (arg.basePrefix) {
570 *--valBufBegin = 'X';
571 *--valBufBegin = '0';
577 arg.enforce(!arg.thousandsSeparator,
578 "thousands separator (',') not allowed with '",
579 presentation, "' specifier");
580 valBufEnd = valBuf + valBufSize - 1;
581 valBufBegin = valBuf + detail::uintToBinary(valBuf, valBufSize - 1,
583 if (arg.basePrefix) {
584 *--valBufBegin = presentation; // 0b or 0B
585 *--valBufBegin = '0';
590 arg.error("invalid specifier '", presentation, "'");
594 *--valBufBegin = sign;
598 format_value::formatNumber(StringPiece(valBufBegin, valBufEnd), prefixLen,
608 class FormatValue<bool> {
610 explicit FormatValue(bool val) : val_(val) { }
612 template <class FormatCallback>
613 void format(FormatArg& arg, FormatCallback& cb) const {
614 if (arg.presentation == FormatArg::kDefaultPresentation) {
615 arg.validate(FormatArg::Type::OTHER);
616 format_value::formatString(val_ ? "true" : "false", arg, cb);
618 FormatValue<int>(val_).format(arg, cb);
628 class FormatValue<double> {
630 explicit FormatValue(double val) : val_(val) { }
632 template <class FormatCallback>
633 void format(FormatArg& arg, FormatCallback& cb) const {
634 using ::double_conversion::DoubleToStringConverter;
635 using ::double_conversion::StringBuilder;
637 arg.validate(FormatArg::Type::FLOAT);
639 if (arg.presentation == FormatArg::kDefaultPresentation) {
640 arg.presentation = 'g';
643 const char* infinitySymbol = isupper(arg.presentation) ? "INF" : "inf";
644 const char* nanSymbol = isupper(arg.presentation) ? "NAN" : "nan";
645 char exponentSymbol = isupper(arg.presentation) ? 'E' : 'e';
647 if (arg.precision == FormatArg::kDefaultPrecision) {
651 // 2+: for null terminator and optional sign shenanigans.
652 char buf[2 + std::max({
653 (2 + DoubleToStringConverter::kMaxFixedDigitsBeforePoint +
654 DoubleToStringConverter::kMaxFixedDigitsAfterPoint),
655 (8 + DoubleToStringConverter::kMaxExponentialDigits),
656 (7 + DoubleToStringConverter::kMaxPrecisionDigits)})];
657 StringBuilder builder(buf + 1, static_cast<int> (sizeof(buf) - 1));
661 case FormatArg::Sign::PLUS_OR_MINUS:
664 case FormatArg::Sign::SPACE_OR_MINUS:
673 DoubleToStringConverter::EMIT_POSITIVE_EXPONENT_SIGN |
674 (arg.trailingDot ? DoubleToStringConverter::EMIT_TRAILING_DECIMAL_POINT
678 switch (arg.presentation) {
685 DoubleToStringConverter::kMaxFixedDigitsAfterPoint) {
686 arg.precision = DoubleToStringConverter::kMaxFixedDigitsAfterPoint;
688 DoubleToStringConverter conv(flags,
696 arg.enforce(conv.ToFixed(val, arg.precision, &builder),
697 "fixed double conversion failed");
703 if (arg.precision > DoubleToStringConverter::kMaxExponentialDigits) {
704 arg.precision = DoubleToStringConverter::kMaxExponentialDigits;
707 DoubleToStringConverter conv(flags,
715 arg.enforce(conv.ToExponential(val, arg.precision, &builder));
718 case 'n': // should be locale-aware, but isn't
722 if (arg.precision < DoubleToStringConverter::kMinPrecisionDigits) {
723 arg.precision = DoubleToStringConverter::kMinPrecisionDigits;
724 } else if (arg.precision >
725 DoubleToStringConverter::kMaxPrecisionDigits) {
726 arg.precision = DoubleToStringConverter::kMaxPrecisionDigits;
728 DoubleToStringConverter conv(flags,
736 arg.enforce(conv.ToShortest(val, &builder));
740 arg.error("invalid specifier '", arg.presentation, "'");
743 int len = builder.position();
747 // Add '+' or ' ' sign if needed
749 // anything that's neither negative nor nan
751 if (plusSign && (*p != '-' && *p != 'n' && *p != 'N')) {
755 } else if (*p == '-') {
759 format_value::formatNumber(StringPiece(p, len), prefixLen, arg, cb);
766 // float (defer to double)
768 class FormatValue<float> {
770 explicit FormatValue(float val) : val_(val) { }
772 template <class FormatCallback>
773 void format(FormatArg& arg, FormatCallback& cb) const {
774 FormatValue<double>(val_).format(arg, cb);
781 // Sring-y types (implicitly convertible to StringPiece, except char*)
784 T, typename std::enable_if<
785 (!std::is_pointer<T>::value ||
786 !std::is_same<char, typename std::decay<
787 typename std::remove_pointer<T>::type>::type>::value) &&
788 std::is_convertible<T, StringPiece>::value>::type>
791 explicit FormatValue(StringPiece val) : val_(val) { }
793 template <class FormatCallback>
794 void format(FormatArg& arg, FormatCallback& cb) const {
795 if (arg.keyEmpty()) {
796 arg.validate(FormatArg::Type::OTHER);
797 arg.enforce(arg.presentation == FormatArg::kDefaultPresentation ||
798 arg.presentation == 's',
799 "invalid specifier '", arg.presentation, "'");
800 format_value::formatString(val_, arg, cb);
802 FormatValue<char>(val_.at(arg.splitIntKey())).format(arg, cb);
812 class FormatValue<std::nullptr_t> {
814 explicit FormatValue(std::nullptr_t) { }
816 template <class FormatCallback>
817 void format(FormatArg& arg, FormatCallback& cb) const {
818 arg.validate(FormatArg::Type::OTHER);
819 arg.enforce(arg.presentation == FormatArg::kDefaultPresentation,
820 "invalid specifier '", arg.presentation, "'");
821 format_value::formatString("(null)", arg, cb);
825 // Partial specialization of FormatValue for char*
829 typename std::enable_if<
830 std::is_same<char, typename std::decay<T>::type>::value>::type>
833 explicit FormatValue(T* val) : val_(val) { }
835 template <class FormatCallback>
836 void format(FormatArg& arg, FormatCallback& cb) const {
837 if (arg.keyEmpty()) {
839 FormatValue<std::nullptr_t>(nullptr).format(arg, cb);
841 FormatValue<StringPiece>(val_).format(arg, cb);
844 FormatValue<typename std::decay<T>::type>(
845 val_[arg.splitIntKey()]).format(arg, cb);
853 // Partial specialization of FormatValue for void*
857 typename std::enable_if<
858 std::is_same<void, typename std::decay<T>::type>::value>::type>
861 explicit FormatValue(T* val) : val_(val) { }
863 template <class FormatCallback>
864 void format(FormatArg& arg, FormatCallback& cb) const {
866 FormatValue<std::nullptr_t>(nullptr).format(arg, cb);
868 // Print as a pointer, in hex.
869 arg.validate(FormatArg::Type::OTHER);
870 arg.enforce(arg.presentation == FormatArg::kDefaultPresentation,
871 "invalid specifier '", arg.presentation, "'");
872 arg.basePrefix = true;
873 arg.presentation = 'x';
874 if (arg.align == FormatArg::Align::DEFAULT) {
875 arg.align = FormatArg::Align::LEFT;
877 FormatValue<uintptr_t>(
878 reinterpret_cast<uintptr_t>(val_)).doFormat(arg, cb);
886 template <class T, class = void>
887 class TryFormatValue {
889 template <class FormatCallback>
890 static void formatOrFail(T& value, FormatArg& arg, FormatCallback& cb) {
891 arg.error("No formatter available for this type");
896 class TryFormatValue<
898 typename std::enable_if<
899 0 < sizeof(FormatValue<typename std::decay<T>::type>)>::type>
902 template <class FormatCallback>
903 static void formatOrFail(T& value, FormatArg& arg, FormatCallback& cb) {
904 FormatValue<typename std::decay<T>::type>(value).format(arg, cb);
908 // Partial specialization of FormatValue for other pointers
912 typename std::enable_if<
913 !std::is_same<char, typename std::decay<T>::type>::value &&
914 !std::is_same<void, typename std::decay<T>::type>::value>::type>
917 explicit FormatValue(T* val) : val_(val) { }
919 template <class FormatCallback>
920 void format(FormatArg& arg, FormatCallback& cb) const {
921 if (arg.keyEmpty()) {
922 FormatValue<void*>((void*)val_).format(arg, cb);
924 TryFormatValue<T>::formatOrFail(val_[arg.splitIntKey()], arg, cb);
933 // Shortcut, so we don't have to use enable_if everywhere
934 struct FormatTraitsBase {
935 typedef void enabled;
938 // Traits that define enabled, value_type, and at() for anything
939 // indexable with integral keys: pointers, arrays, vectors, and maps
940 // with integral keys
941 template <class T, class Enable=void> struct IndexableTraits;
943 // Base class for sequences (vectors, deques)
945 struct IndexableTraitsSeq : public FormatTraitsBase {
946 typedef C container_type;
947 typedef typename C::value_type value_type;
948 static const value_type& at(const C& c, int idx) {
952 static const value_type& at(const C& c, int idx,
953 const value_type& dflt) {
954 return (idx >= 0 && size_t(idx) < c.size()) ? c.at(idx) : dflt;
958 // Base class for associative types (maps)
960 struct IndexableTraitsAssoc : public FormatTraitsBase {
961 typedef typename C::value_type::second_type value_type;
962 static const value_type& at(const C& c, int idx) {
963 return c.at(static_cast<typename C::key_type>(idx));
965 static const value_type& at(const C& c, int idx,
966 const value_type& dflt) {
967 auto pos = c.find(static_cast<typename C::key_type>(idx));
968 return pos != c.end() ? pos->second : dflt;
973 template <class T, size_t N>
974 struct IndexableTraits<std::array<T, N>>
975 : public IndexableTraitsSeq<std::array<T, N>> {
979 template <class T, class A>
980 struct IndexableTraits<std::vector<T, A>>
981 : public IndexableTraitsSeq<std::vector<T, A>> {
985 template <class T, class A>
986 struct IndexableTraits<std::deque<T, A>>
987 : public IndexableTraitsSeq<std::deque<T, A>> {
991 template <class T, class A>
992 struct IndexableTraits<fbvector<T, A>>
993 : public IndexableTraitsSeq<fbvector<T, A>> {
997 template <class T, size_t M, class A, class B, class C>
998 struct IndexableTraits<small_vector<T, M, A, B, C>>
999 : public IndexableTraitsSeq<small_vector<T, M, A, B, C>> {
1002 // std::map with integral keys
1003 template <class K, class T, class C, class A>
1004 struct IndexableTraits<
1005 std::map<K, T, C, A>,
1006 typename std::enable_if<std::is_integral<K>::value>::type>
1007 : public IndexableTraitsAssoc<std::map<K, T, C, A>> {
1010 // std::unordered_map with integral keys
1011 template <class K, class T, class H, class E, class A>
1012 struct IndexableTraits<
1013 std::unordered_map<K, T, H, E, A>,
1014 typename std::enable_if<std::is_integral<K>::value>::type>
1015 : public IndexableTraitsAssoc<std::unordered_map<K, T, H, E, A>> {
1018 } // namespace detail
1020 // Partial specialization of FormatValue for integer-indexable containers
1024 typename detail::IndexableTraits<T>::enabled> {
1026 explicit FormatValue(const T& val) : val_(val) { }
1028 template <class FormatCallback>
1029 void format(FormatArg& arg, FormatCallback& cb) const {
1030 FormatValue<typename std::decay<
1031 typename detail::IndexableTraits<T>::value_type>::type>(
1032 detail::IndexableTraits<T>::at(
1033 val_, arg.splitIntKey())).format(arg, cb);
1040 template <class Container, class Value>
1042 detail::DefaultValueWrapper<Container, Value>,
1043 typename detail::IndexableTraits<Container>::enabled> {
1045 explicit FormatValue(const detail::DefaultValueWrapper<Container, Value>& val)
1048 template <class FormatCallback>
1049 void format(FormatArg& arg, FormatCallback& cb) const {
1050 FormatValue<typename std::decay<
1051 typename detail::IndexableTraits<Container>::value_type>::type>(
1052 detail::IndexableTraits<Container>::at(
1055 val_.defaultValue)).format(arg, cb);
1059 const detail::DefaultValueWrapper<Container, Value>& val_;
1064 // Define enabled, key_type, convert from StringPiece to the key types
1066 template <class T> struct KeyFromStringPiece;
1070 struct KeyFromStringPiece<std::string> : public FormatTraitsBase {
1071 typedef std::string key_type;
1072 static std::string convert(StringPiece s) {
1073 return s.toString();
1075 typedef void enabled;
1080 struct KeyFromStringPiece<fbstring> : public FormatTraitsBase {
1081 typedef fbstring key_type;
1082 static fbstring convert(StringPiece s) {
1083 return s.toFbstring();
1089 struct KeyFromStringPiece<StringPiece> : public FormatTraitsBase {
1090 typedef StringPiece key_type;
1091 static StringPiece convert(StringPiece s) {
1096 // Base class for associative types keyed by strings
1097 template <class T> struct KeyableTraitsAssoc : public FormatTraitsBase {
1098 typedef typename T::key_type key_type;
1099 typedef typename T::value_type::second_type value_type;
1100 static const value_type& at(const T& map, StringPiece key) {
1101 return map.at(KeyFromStringPiece<key_type>::convert(key));
1103 static const value_type& at(const T& map, StringPiece key,
1104 const value_type& dflt) {
1105 auto pos = map.find(KeyFromStringPiece<key_type>::convert(key));
1106 return pos != map.end() ? pos->second : dflt;
1110 // Define enabled, key_type, value_type, at() for supported string-keyed
1112 template <class T, class Enabled=void> struct KeyableTraits;
1114 // std::map with string key
1115 template <class K, class T, class C, class A>
1116 struct KeyableTraits<
1117 std::map<K, T, C, A>,
1118 typename KeyFromStringPiece<K>::enabled>
1119 : public KeyableTraitsAssoc<std::map<K, T, C, A>> {
1122 // std::unordered_map with string key
1123 template <class K, class T, class H, class E, class A>
1124 struct KeyableTraits<
1125 std::unordered_map<K, T, H, E, A>,
1126 typename KeyFromStringPiece<K>::enabled>
1127 : public KeyableTraitsAssoc<std::unordered_map<K, T, H, E, A>> {
1130 } // namespace detail
1132 // Partial specialization of FormatValue for string-keyed containers
1136 typename detail::KeyableTraits<T>::enabled> {
1138 explicit FormatValue(const T& val) : val_(val) { }
1140 template <class FormatCallback>
1141 void format(FormatArg& arg, FormatCallback& cb) const {
1142 FormatValue<typename std::decay<
1143 typename detail::KeyableTraits<T>::value_type>::type>(
1144 detail::KeyableTraits<T>::at(
1145 val_, arg.splitKey())).format(arg, cb);
1152 template <class Container, class Value>
1154 detail::DefaultValueWrapper<Container, Value>,
1155 typename detail::KeyableTraits<Container>::enabled> {
1157 explicit FormatValue(const detail::DefaultValueWrapper<Container, Value>& val)
1160 template <class FormatCallback>
1161 void format(FormatArg& arg, FormatCallback& cb) const {
1162 FormatValue<typename std::decay<
1163 typename detail::KeyableTraits<Container>::value_type>::type>(
1164 detail::KeyableTraits<Container>::at(
1167 val_.defaultValue)).format(arg, cb);
1171 const detail::DefaultValueWrapper<Container, Value>& val_;
1174 // Partial specialization of FormatValue for pairs
1175 template <class A, class B>
1176 class FormatValue<std::pair<A, B>> {
1178 explicit FormatValue(const std::pair<A, B>& val) : val_(val) { }
1180 template <class FormatCallback>
1181 void format(FormatArg& arg, FormatCallback& cb) const {
1182 int key = arg.splitIntKey();
1185 FormatValue<typename std::decay<A>::type>(val_.first).format(arg, cb);
1188 FormatValue<typename std::decay<B>::type>(val_.second).format(arg, cb);
1191 arg.error("invalid index for pair");
1196 const std::pair<A, B>& val_;
1199 // Partial specialization of FormatValue for tuples
1200 template <class... Args>
1201 class FormatValue<std::tuple<Args...>> {
1202 typedef std::tuple<Args...> Tuple;
1204 explicit FormatValue(const Tuple& val) : val_(val) { }
1206 template <class FormatCallback>
1207 void format(FormatArg& arg, FormatCallback& cb) const {
1208 int key = arg.splitIntKey();
1209 arg.enforce(key >= 0, "tuple index must be non-negative");
1210 doFormat(key, arg, cb);
1214 static constexpr size_t valueCount = std::tuple_size<Tuple>::value;
1216 template <size_t K, class Callback>
1217 typename std::enable_if<K == valueCount>::type
1218 doFormatFrom(size_t i, FormatArg& arg, Callback& cb) const {
1219 arg.enforce("tuple index out of range, max=", i);
1222 template <size_t K, class Callback>
1223 typename std::enable_if<(K < valueCount)>::type
1224 doFormatFrom(size_t i, FormatArg& arg, Callback& cb) const {
1226 FormatValue<typename std::decay<
1227 typename std::tuple_element<K, Tuple>::type>::type>(
1228 std::get<K>(val_)).format(arg, cb);
1230 doFormatFrom<K+1>(i, arg, cb);
1234 template <class Callback>
1235 void doFormat(size_t i, FormatArg& arg, Callback& cb) const {
1236 return doFormatFrom<0>(i, arg, cb);
1242 // Partial specialization of FormatValue for nested Formatters
1243 template <bool containerMode, class... Args,
1244 template <bool, class...> class F>
1245 class FormatValue<F<containerMode, Args...>,
1246 typename std::enable_if<detail::IsFormatter<
1247 F<containerMode, Args...>>::value>::type> {
1248 typedef typename F<containerMode, Args...>::BaseType FormatterValue;
1251 explicit FormatValue(const FormatterValue& f) : f_(f) { }
1253 template <class FormatCallback>
1254 void format(FormatArg& arg, FormatCallback& cb) const {
1255 format_value::formatFormatter(f_, arg, cb);
1258 const FormatterValue& f_;
1262 * Formatter objects can be appended to strings, and therefore they're
1263 * compatible with folly::toAppend and folly::to.
1265 template <class Tgt, class Derived, bool containerMode, class... Args>
1266 typename std::enable_if<IsSomeString<Tgt>::value>::type toAppend(
1267 const BaseFormatter<Derived, containerMode, Args...>& value, Tgt* result) {
1268 value.appendTo(*result);
1271 } // namespace folly
1273 #pragma GCC diagnostic pop