2 * Copyright 2013 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/Traits.h"
27 extern const char formatHexUpper[256][2];
28 extern const char formatHexLower[256][2];
29 extern const char formatOctal[512][3];
30 extern const char formatBinary[256][8];
32 const size_t kMaxHexLength = 2 * sizeof(uintmax_t);
33 const size_t kMaxOctalLength = 3 * sizeof(uintmax_t);
34 const size_t kMaxBinaryLength = 8 * sizeof(uintmax_t);
37 * Convert an unsigned to hex, using repr (which maps from each possible
38 * 2-hex-bytes value to the 2-character representation).
40 * Just like folly::detail::uintToBuffer in Conv.h, writes at the *end* of
41 * the supplied buffer and returns the offset of the beginning of the string
42 * from the start of the buffer. The formatted string will be in range
43 * [buf+begin, buf+bufLen).
46 size_t uintToHex(char* buffer, size_t bufLen, Uint v,
47 const char (&repr)[256][2]) {
48 // 'v >>= 7, v >>= 1' is no more than a work around to get rid of shift size
49 // warning when Uint = uint8_t (it's false as v >= 256 implies sizeof(v) > 1).
50 for (; !less_than<unsigned, 256>(v); v >>= 7, v >>= 1) {
53 buffer[bufLen] = repr[b][0];
54 buffer[bufLen + 1] = repr[b][1];
56 buffer[--bufLen] = repr[v][1];
58 buffer[--bufLen] = repr[v][0];
64 * Convert an unsigned to hex, using lower-case letters for the digits
65 * above 9. See the comments for uintToHex.
68 inline size_t uintToHexLower(char* buffer, size_t bufLen, Uint v) {
69 return uintToHex(buffer, bufLen, v, formatHexLower);
73 * Convert an unsigned to hex, using upper-case letters for the digits
74 * above 9. See the comments for uintToHex.
77 inline size_t uintToHexUpper(char* buffer, size_t bufLen, Uint v) {
78 return uintToHex(buffer, bufLen, v, formatHexUpper);
82 * Convert an unsigned to octal.
84 * Just like folly::detail::uintToBuffer in Conv.h, writes at the *end* of
85 * the supplied buffer and returns the offset of the beginning of the string
86 * from the start of the buffer. The formatted string will be in range
87 * [buf+begin, buf+bufLen).
90 size_t uintToOctal(char* buffer, size_t bufLen, Uint v) {
91 auto& repr = formatOctal;
92 // 'v >>= 7, v >>= 2' is no more than a work around to get rid of shift size
93 // warning when Uint = uint8_t (it's false as v >= 512 implies sizeof(v) > 1).
94 for (; !less_than<unsigned, 512>(v); v >>= 7, v >>= 2) {
97 buffer[bufLen] = repr[b][0];
98 buffer[bufLen + 1] = repr[b][1];
99 buffer[bufLen + 2] = repr[b][2];
101 buffer[--bufLen] = repr[v][2];
103 buffer[--bufLen] = repr[v][1];
106 buffer[--bufLen] = repr[v][0];
112 * Convert an unsigned to binary.
114 * Just like folly::detail::uintToBuffer in Conv.h, writes at the *end* of
115 * the supplied buffer and returns the offset of the beginning of the string
116 * from the start of the buffer. The formatted string will be in range
117 * [buf+begin, buf+bufLen).
119 template <class Uint>
120 size_t uintToBinary(char* buffer, size_t bufLen, Uint v) {
121 auto& repr = formatBinary;
123 buffer[--bufLen] = '0';
126 for (; v; v >>= 7, v >>= 1) {
129 memcpy(buffer + bufLen, &(repr[b][0]), 8);
131 while (buffer[bufLen] == '0') {
137 } // namespace detail
140 template <bool containerMode, class... Args>
141 Formatter<containerMode, Args...>::Formatter(StringPiece str, Args&&... args)
143 values_(FormatValue<typename std::decay<Args>::type>(
144 std::forward<Args>(args))...) {
145 static_assert(!containerMode || sizeof...(Args) == 1,
146 "Exactly one argument required in container mode");
149 template <bool containerMode, class... Args>
150 template <class Output>
151 void Formatter<containerMode, Args...>::operator()(Output& out) const {
152 auto p = str_.begin();
153 auto end = str_.end();
155 // Copy raw string (without format specifiers) to output;
156 // not as simple as we'd like, as we still need to translate "}}" to "}"
157 // and throw if we see any lone "}"
158 auto outputString = [&out] (StringPiece s) {
162 auto q = static_cast<const char*>(memchr(p, '}', end - p));
164 out(StringPiece(p, end));
168 out(StringPiece(p, q));
171 CHECK(p != end && *p == '}') << "single '}' in format string";
177 bool hasDefaultArgIndex = false;
178 bool hasExplicitArgIndex = false;
180 auto q = static_cast<const char*>(memchr(p, '{', end - p));
182 outputString(StringPiece(p, end));
185 outputString(StringPiece(p, q));
188 CHECK(p != end) << "'{' at end of format string";
192 out(StringPiece(p, 1));
198 q = static_cast<const char*>(memchr(p, '}', end - p));
199 CHECK(q != end) << "missing ending '}'";
200 FormatArg arg(StringPiece(p, q));
204 auto piece = arg.splitKey<true>(); // empty key component is okay
205 if (containerMode) { // static
207 arg.setNextIntKey(nextArg++);
208 hasDefaultArgIndex = true;
210 arg.setNextKey(piece);
211 hasExplicitArgIndex = true;
215 argIndex = nextArg++;
216 hasDefaultArgIndex = true;
219 argIndex = to<int>(piece);
220 } catch (const std::out_of_range& e) {
221 LOG(FATAL) << "argument index must be integer";
224 << arg.errorStr("argument index must be non-negative");
225 hasExplicitArgIndex = true;
229 CHECK(!hasDefaultArgIndex || !hasExplicitArgIndex)
230 << "may not have both default and explicit arg indexes";
232 doFormat(argIndex, arg, out);
236 namespace format_value {
238 template <class FormatCallback>
239 void formatString(StringPiece val, FormatArg& arg, FormatCallback& cb) {
240 if (arg.precision != FormatArg::kDefaultPrecision &&
241 val.size() > arg.precision) {
242 val.reset(val.data(), arg.precision);
245 constexpr int padBufSize = 128;
246 char padBuf[padBufSize];
248 // Output padding, no more than padBufSize at once
249 auto pad = [&padBuf, &cb, padBufSize] (int chars) {
251 int n = std::min(chars, padBufSize);
252 cb(StringPiece(padBuf, n));
257 int padRemaining = 0;
258 if (arg.width != FormatArg::kDefaultWidth && val.size() < arg.width) {
259 char fill = arg.fill == FormatArg::kDefaultFill ? ' ' : arg.fill;
260 int padChars = arg.width - val.size();
261 memset(padBuf, fill, std::min(padBufSize, padChars));
264 case FormatArg::Align::DEFAULT:
265 case FormatArg::Align::LEFT:
266 padRemaining = padChars;
268 case FormatArg::Align::CENTER:
270 padRemaining = padChars - padChars / 2;
272 case FormatArg::Align::RIGHT:
273 case FormatArg::Align::PAD_AFTER_SIGN:
289 template <class FormatCallback>
290 void formatNumber(StringPiece val, int prefixLen, FormatArg& arg,
291 FormatCallback& cb) {
292 // precision means something different for numbers
293 arg.precision = FormatArg::kDefaultPrecision;
294 if (arg.align == FormatArg::Align::DEFAULT) {
295 arg.align = FormatArg::Align::RIGHT;
296 } else if (prefixLen && arg.align == FormatArg::Align::PAD_AFTER_SIGN) {
297 // Split off the prefix, then do any padding if necessary
298 cb(val.subpiece(0, prefixLen));
299 val.advance(prefixLen);
300 arg.width = std::max(arg.width - prefixLen, 0);
302 format_value::formatString(val, arg, cb);
305 template <class FormatCallback, bool containerMode, class... Args>
306 void formatFormatter(const Formatter<containerMode, Args...>& formatter,
308 FormatCallback& cb) {
309 if (arg.width == FormatArg::kDefaultWidth &&
310 arg.precision == FormatArg::kDefaultPrecision) {
313 } else if (arg.align != FormatArg::Align::LEFT &&
314 arg.align != FormatArg::Align::DEFAULT) {
315 // We can only avoid creating a temporary string if we align left,
316 // as we'd need to know the size beforehand otherwise
317 format_value::formatString(formatter.fbstr(), arg, cb);
319 auto fn = [&arg, &cb] (StringPiece sp) mutable {
320 int sz = static_cast<int>(sp.size());
321 if (arg.precision != FormatArg::kDefaultPrecision) {
322 sz = std::min(arg.precision, sz);
323 sp.reset(sp.data(), sz);
328 if (arg.width != FormatArg::kDefaultWidth) {
329 arg.width = std::max(arg.width - sz, 0);
334 if (arg.width != FormatArg::kDefaultWidth && arg.width != 0) {
335 // Rely on formatString to do appropriate padding
336 format_value::formatString(StringPiece(), arg, cb);
341 } // namespace format_value
343 // Definitions for default FormatValue classes
345 // Integral types (except bool)
348 T, typename std::enable_if<
349 std::is_integral<T>::value &&
350 !std::is_same<T, bool>::value>::type>
353 explicit FormatValue(T val) : val_(val) { }
354 template <class FormatCallback>
355 void format(FormatArg& arg, FormatCallback& cb) const {
356 arg.validate(FormatArg::Type::INTEGER);
360 template <class FormatCallback>
361 void doFormat(FormatArg& arg, FormatCallback& cb) const {
362 char presentation = arg.presentation;
363 if (presentation == FormatArg::kDefaultPresentation) {
364 presentation = std::is_same<T, char>::value ? 'c' : 'd';
367 // Do all work as unsigned, we'll add the prefix ('0' or '0x' if necessary)
368 // and sign ourselves.
369 typedef typename std::make_unsigned<T>::type UT;
372 if (std::is_signed<T>::value) {
373 if (folly::is_negative(val_)) {
374 uval = static_cast<UT>(-val_);
377 uval = static_cast<UT>(val_);
379 case FormatArg::Sign::PLUS_OR_MINUS:
382 case FormatArg::Sign::SPACE_OR_MINUS:
394 CHECK(arg.sign == FormatArg::Sign::DEFAULT)
395 << arg.errorStr("sign specifications not allowed for unsigned values");
399 // #x: 0x prefix + 16 bytes = 18 bytes
400 // #o: 0 prefix + 22 bytes = 23 bytes
401 // #b: 0b prefix + 64 bytes = 65 bytes
402 // ,d: 26 bytes (including thousands separators!)
404 // + 3 for sign and prefix shenanigans (see below)
405 constexpr size_t valBufSize = 69;
406 char valBuf[valBufSize];
407 char* valBufBegin = nullptr;
408 char* valBufEnd = nullptr;
411 auto useSprintf = [&] (const char* format) mutable {
412 valBufBegin = valBuf + 3; // room for sign and base prefix
413 valBufEnd = valBufBegin + sprintf(valBufBegin, format,
414 static_cast<uintmax_t>(uval));
419 switch (presentation) {
420 case 'n': // TODO(tudorb): locale awareness?
422 CHECK(!arg.basePrefix)
423 << arg.errorStr("base prefix not allowed with '", presentation,
425 if (arg.thousandsSeparator) {
428 // Use uintToBuffer, faster than sprintf
429 valBufBegin = valBuf + 3;
430 valBufEnd = valBufBegin + uint64ToBufferUnsafe(uval, valBufBegin);
434 CHECK(!arg.basePrefix)
435 << arg.errorStr("base prefix not allowed with '", presentation,
437 CHECK(!arg.thousandsSeparator)
438 << arg.errorStr("thousands separator (',') not allowed with '",
439 presentation, "' specifier");
440 valBufBegin = valBuf + 3;
441 *valBufBegin = static_cast<char>(uval);
442 valBufEnd = valBufBegin + 1;
446 CHECK(!arg.thousandsSeparator)
447 << arg.errorStr("thousands separator (',') not allowed with '",
448 presentation, "' specifier");
449 valBufEnd = valBuf + valBufSize - 1;
450 valBufBegin = valBuf + detail::uintToOctal(valBuf, valBufSize - 1, uval);
451 if (arg.basePrefix) {
452 *--valBufBegin = '0';
457 CHECK(!arg.thousandsSeparator)
458 << arg.errorStr("thousands separator (',') not allowed with '",
459 presentation, "' specifier");
460 valBufEnd = valBuf + valBufSize - 1;
461 valBufBegin = valBuf + detail::uintToHexLower(valBuf, valBufSize - 1,
463 if (arg.basePrefix) {
464 *--valBufBegin = 'x';
465 *--valBufBegin = '0';
470 CHECK(!arg.thousandsSeparator)
471 << arg.errorStr("thousands separator (',') not allowed with '",
472 presentation, "' specifier");
473 valBufEnd = valBuf + valBufSize - 1;
474 valBufBegin = valBuf + detail::uintToHexUpper(valBuf, valBufSize - 1,
476 if (arg.basePrefix) {
477 *--valBufBegin = 'X';
478 *--valBufBegin = '0';
484 CHECK(!arg.thousandsSeparator)
485 << arg.errorStr("thousands separator (',') not allowed with '",
486 presentation, "' specifier");
487 valBufEnd = valBuf + valBufSize - 1;
488 valBufBegin = valBuf + detail::uintToBinary(valBuf, valBufSize - 1,
490 if (arg.basePrefix) {
491 *--valBufBegin = presentation; // 0b or 0B
492 *--valBufBegin = '0';
497 LOG(FATAL) << arg.errorStr("invalid specifier '", presentation, "'");
501 *--valBufBegin = sign;
505 format_value::formatNumber(StringPiece(valBufBegin, valBufEnd), prefixLen,
515 class FormatValue<bool> {
517 explicit FormatValue(bool val) : val_(val) { }
519 template <class FormatCallback>
520 void format(FormatArg& arg, FormatCallback& cb) const {
521 if (arg.presentation == FormatArg::kDefaultPresentation) {
522 arg.validate(FormatArg::Type::OTHER);
523 format_value::formatString(val_ ? "true" : "false", arg, cb);
525 FormatValue<int>(val_).format(arg, cb);
535 class FormatValue<double> {
537 explicit FormatValue(double val) : val_(val) { }
539 template <class FormatCallback>
540 void format(FormatArg& arg, FormatCallback& cb) const {
541 using ::double_conversion::DoubleToStringConverter;
542 using ::double_conversion::StringBuilder;
544 arg.validate(FormatArg::Type::FLOAT);
546 if (arg.presentation == FormatArg::kDefaultPresentation) {
547 arg.presentation = 'g';
550 const char* infinitySymbol = isupper(arg.presentation) ? "INF" : "inf";
551 const char* nanSymbol = isupper(arg.presentation) ? "NAN" : "nan";
552 char exponentSymbol = isupper(arg.presentation) ? 'E' : 'e';
554 if (arg.precision == FormatArg::kDefaultPrecision) {
558 // 2+: for null terminator and optional sign shenanigans.
559 char buf[2 + std::max({
560 (2 + DoubleToStringConverter::kMaxFixedDigitsBeforePoint +
561 DoubleToStringConverter::kMaxFixedDigitsAfterPoint),
562 (8 + DoubleToStringConverter::kMaxExponentialDigits),
563 (7 + DoubleToStringConverter::kMaxPrecisionDigits)})];
564 StringBuilder builder(buf + 1, sizeof(buf) - 1);
568 case FormatArg::Sign::PLUS_OR_MINUS:
571 case FormatArg::Sign::SPACE_OR_MINUS:
580 switch (arg.presentation) {
587 DoubleToStringConverter::kMaxFixedDigitsAfterPoint) {
588 arg.precision = DoubleToStringConverter::kMaxFixedDigitsAfterPoint;
590 DoubleToStringConverter conv(
591 DoubleToStringConverter::EMIT_POSITIVE_EXPONENT_SIGN,
597 arg.enforce(conv.ToFixed(val, arg.precision, &builder),
598 "fixed double conversion failed");
604 if (arg.precision > DoubleToStringConverter::kMaxExponentialDigits) {
605 arg.precision = DoubleToStringConverter::kMaxExponentialDigits;
608 DoubleToStringConverter conv(
609 DoubleToStringConverter::EMIT_POSITIVE_EXPONENT_SIGN,
615 CHECK(conv.ToExponential(val, arg.precision, &builder));
618 case 'n': // should be locale-aware, but isn't
622 if (arg.precision < DoubleToStringConverter::kMinPrecisionDigits) {
623 arg.precision = DoubleToStringConverter::kMinPrecisionDigits;
624 } else if (arg.precision >
625 DoubleToStringConverter::kMaxPrecisionDigits) {
626 arg.precision = DoubleToStringConverter::kMaxPrecisionDigits;
628 DoubleToStringConverter conv(
629 DoubleToStringConverter::EMIT_POSITIVE_EXPONENT_SIGN,
635 CHECK(conv.ToShortest(val, &builder));
639 LOG(FATAL) << arg.errorStr("invalid specifier '", arg.presentation, "'");
642 int len = builder.position();
646 // Add '+' or ' ' sign if needed
648 // anything that's neither negative nor nan
650 if (plusSign && (*p != '-' && *p != 'n' && *p != 'N')) {
654 } else if (*p == '-') {
658 format_value::formatNumber(StringPiece(p, len), prefixLen, arg, cb);
665 // float (defer to double)
667 class FormatValue<float> {
669 explicit FormatValue(float val) : val_(val) { }
671 template <class FormatCallback>
672 void format(FormatArg& arg, FormatCallback& cb) const {
673 FormatValue<double>(val_).format(arg, cb);
680 // Sring-y types (implicitly convertible to StringPiece, except char*)
683 T, typename std::enable_if<
684 (!std::is_pointer<T>::value ||
685 !std::is_same<char, typename std::decay<
686 typename std::remove_pointer<T>::type>::type>::value) &&
687 std::is_convertible<T, StringPiece>::value>::type>
690 explicit FormatValue(StringPiece val) : val_(val) { }
692 template <class FormatCallback>
693 void format(FormatArg& arg, FormatCallback& cb) const {
694 if (arg.keyEmpty()) {
695 arg.validate(FormatArg::Type::OTHER);
696 CHECK(arg.presentation == FormatArg::kDefaultPresentation ||
697 arg.presentation == 's')
698 << arg.errorStr("invalid specifier '", arg.presentation, "'");
699 format_value::formatString(val_, arg, cb);
701 FormatValue<char>(val_.at(arg.splitIntKey())).format(arg, cb);
711 class FormatValue<std::nullptr_t> {
713 explicit FormatValue(std::nullptr_t) { }
715 template <class FormatCallback>
716 void format(FormatArg& arg, FormatCallback& cb) const {
717 arg.validate(FormatArg::Type::OTHER);
718 CHECK(arg.presentation == FormatArg::kDefaultPresentation)
719 << arg.errorStr("invalid specifier '", arg.presentation, "'");
720 format_value::formatString("(null)", arg, cb);
724 // Partial specialization of FormatValue for char*
728 typename std::enable_if<
729 std::is_same<char, typename std::decay<T>::type>::value>::type>
732 explicit FormatValue(T* val) : val_(val) { }
734 template <class FormatCallback>
735 void format(FormatArg& arg, FormatCallback& cb) const {
736 if (arg.keyEmpty()) {
738 FormatValue<std::nullptr_t>(nullptr).format(arg, cb);
740 FormatValue<StringPiece>(val_).format(arg, cb);
743 FormatValue<typename std::decay<T>::type>(
744 val_[arg.splitIntKey()]).format(arg, cb);
752 // Partial specialization of FormatValue for void*
756 typename std::enable_if<
757 std::is_same<void, typename std::decay<T>::type>::value>::type>
760 explicit FormatValue(T* val) : val_(val) { }
762 template <class FormatCallback>
763 void format(FormatArg& arg, FormatCallback& cb) const {
765 FormatValue<std::nullptr_t>(nullptr).format(arg, cb);
767 // Print as a pointer, in hex.
768 arg.validate(FormatArg::Type::OTHER);
769 CHECK(arg.presentation == FormatArg::kDefaultPresentation)
770 << arg.errorStr("invalid specifier '", arg.presentation, "'");
771 arg.basePrefix = true;
772 arg.presentation = 'x';
773 if (arg.align == FormatArg::Align::DEFAULT) {
774 arg.align = FormatArg::Align::LEFT;
776 FormatValue<uintptr_t>(
777 reinterpret_cast<uintptr_t>(val_)).doFormat(arg, cb);
785 template <class T, class = void>
786 class TryFormatValue {
788 template <class FormatCallback>
789 static void formatOrFail(T& value, FormatArg& arg, FormatCallback& cb) {
790 LOG(FATAL) << arg.errorStr("No formatter available for this type");
795 class TryFormatValue<
797 typename std::enable_if<
798 0 < sizeof(FormatValue<typename std::decay<T>::type>)>::type>
801 template <class FormatCallback>
802 static void formatOrFail(T& value, FormatArg& arg, FormatCallback& cb) {
803 FormatValue<typename std::decay<T>::type>(value).format(arg, cb);
807 // Partial specialization of FormatValue for other pointers
811 typename std::enable_if<
812 !std::is_same<char, typename std::decay<T>::type>::value &&
813 !std::is_same<void, typename std::decay<T>::type>::value>::type>
816 explicit FormatValue(T* val) : val_(val) { }
818 template <class FormatCallback>
819 void format(FormatArg& arg, FormatCallback& cb) const {
820 if (arg.keyEmpty()) {
821 FormatValue<void*>((void*)val_).format(arg, cb);
823 TryFormatValue<T>::formatOrFail(val_[arg.splitIntKey()], arg, cb);
832 // Shortcut, so we don't have to use enable_if everywhere
833 struct FormatTraitsBase {
834 typedef void enabled;
837 // Traits that define enabled, value_type, and at() for anything
838 // indexable with integral keys: pointers, arrays, vectors, and maps
839 // with integral keys
840 template <class T, class Enable=void> struct IndexableTraits;
842 // Base class for sequences (vectors, deques)
844 struct IndexableTraitsSeq : public FormatTraitsBase {
845 typedef C container_type;
846 typedef typename C::value_type value_type;
847 static const value_type& at(const C& c, int idx) {
852 // Base class for associative types (maps)
854 struct IndexableTraitsAssoc : public FormatTraitsBase {
855 typedef typename C::value_type::second_type value_type;
856 static const value_type& at(const C& c, int idx) {
857 return c.at(static_cast<typename C::key_type>(idx));
862 template <class T, size_t N>
863 struct IndexableTraits<std::array<T, N>>
864 : public IndexableTraitsSeq<std::array<T, N>> {
868 template <class T, class A>
869 struct IndexableTraits<std::vector<T, A>>
870 : public IndexableTraitsSeq<std::vector<T, A>> {
874 template <class T, class A>
875 struct IndexableTraits<std::deque<T, A>>
876 : public IndexableTraitsSeq<std::deque<T, A>> {
880 template <class T, class A>
881 struct IndexableTraits<fbvector<T, A>>
882 : public IndexableTraitsSeq<fbvector<T, A>> {
886 template <class T, size_t M, class A, class B, class C>
887 struct IndexableTraits<small_vector<T, M, A, B, C>>
888 : public IndexableTraitsSeq<small_vector<T, M, A, B, C>> {
891 // std::map with integral keys
892 template <class K, class T, class C, class A>
893 struct IndexableTraits<
894 std::map<K, T, C, A>,
895 typename std::enable_if<std::is_integral<K>::value>::type>
896 : public IndexableTraitsAssoc<std::map<K, T, C, A>> {
899 // std::unordered_map with integral keys
900 template <class K, class T, class H, class E, class A>
901 struct IndexableTraits<
902 std::unordered_map<K, T, H, E, A>,
903 typename std::enable_if<std::is_integral<K>::value>::type>
904 : public IndexableTraitsAssoc<std::unordered_map<K, T, H, E, A>> {
907 } // namespace detail
909 // Partial specialization of FormatValue for integer-indexable containers
913 typename detail::IndexableTraits<T>::enabled> {
915 explicit FormatValue(const T& val) : val_(val) { }
917 template <class FormatCallback>
918 void format(FormatArg& arg, FormatCallback& cb) const {
919 FormatValue<typename std::decay<
920 typename detail::IndexableTraits<T>::value_type>::type>(
921 detail::IndexableTraits<T>::at(
922 val_, arg.splitIntKey())).format(arg, cb);
931 // Define enabled, key_type, convert from StringPiece to the key types
933 template <class T> struct KeyFromStringPiece;
937 struct KeyFromStringPiece<std::string> : public FormatTraitsBase {
938 typedef std::string key_type;
939 static std::string convert(StringPiece s) {
942 typedef void enabled;
947 struct KeyFromStringPiece<fbstring> : public FormatTraitsBase {
948 typedef fbstring key_type;
949 static fbstring convert(StringPiece s) {
950 return s.toFbstring();
956 struct KeyFromStringPiece<StringPiece> : public FormatTraitsBase {
957 typedef StringPiece key_type;
958 static StringPiece convert(StringPiece s) {
963 // Base class for associative types keyed by strings
964 template <class T> struct KeyableTraitsAssoc : public FormatTraitsBase {
965 typedef typename T::key_type key_type;
966 typedef typename T::value_type::second_type value_type;
967 static const value_type& at(const T& map, StringPiece key) {
968 return map.at(KeyFromStringPiece<key_type>::convert(key));
972 // Define enabled, key_type, value_type, at() for supported string-keyed
974 template <class T, class Enabled=void> struct KeyableTraits;
976 // std::map with string key
977 template <class K, class T, class C, class A>
978 struct KeyableTraits<
979 std::map<K, T, C, A>,
980 typename KeyFromStringPiece<K>::enabled>
981 : public KeyableTraitsAssoc<std::map<K, T, C, A>> {
984 // std::unordered_map with string key
985 template <class K, class T, class H, class E, class A>
986 struct KeyableTraits<
987 std::unordered_map<K, T, H, E, A>,
988 typename KeyFromStringPiece<K>::enabled>
989 : public KeyableTraitsAssoc<std::unordered_map<K, T, H, E, A>> {
992 } // namespace detail
994 // Partial specialization of FormatValue for string-keyed containers
998 typename detail::KeyableTraits<T>::enabled> {
1000 explicit FormatValue(const T& val) : val_(val) { }
1002 template <class FormatCallback>
1003 void format(FormatArg& arg, FormatCallback& cb) const {
1004 FormatValue<typename std::decay<
1005 typename detail::KeyableTraits<T>::value_type>::type>(
1006 detail::KeyableTraits<T>::at(
1007 val_, arg.splitKey())).format(arg, cb);
1014 // Partial specialization of FormatValue for pairs
1015 template <class A, class B>
1016 class FormatValue<std::pair<A, B>> {
1018 explicit FormatValue(const std::pair<A, B>& val) : val_(val) { }
1020 template <class FormatCallback>
1021 void format(FormatArg& arg, FormatCallback& cb) const {
1022 int key = arg.splitIntKey();
1025 FormatValue<typename std::decay<A>::type>(val_.first).format(arg, cb);
1028 FormatValue<typename std::decay<B>::type>(val_.second).format(arg, cb);
1031 LOG(FATAL) << arg.errorStr("invalid index for pair");
1036 const std::pair<A, B>& val_;
1039 // Partial specialization of FormatValue for tuples
1040 template <class... Args>
1041 class FormatValue<std::tuple<Args...>> {
1042 typedef std::tuple<Args...> Tuple;
1044 explicit FormatValue(const Tuple& val) : val_(val) { }
1046 template <class FormatCallback>
1047 void format(FormatArg& arg, FormatCallback& cb) const {
1048 int key = arg.splitIntKey();
1049 CHECK(key >= 0) << arg.errorStr("tuple index must be non-negative");
1050 doFormat(key, arg, cb);
1054 static constexpr size_t valueCount = std::tuple_size<Tuple>::value;
1056 template <size_t K, class Callback>
1057 typename std::enable_if<K == valueCount>::type
1058 doFormatFrom(size_t i, FormatArg& arg, Callback& cb) const {
1059 LOG(FATAL) << arg.errorStr("tuple index out of range, max=", i);
1062 template <size_t K, class Callback>
1063 typename std::enable_if<(K < valueCount)>::type
1064 doFormatFrom(size_t i, FormatArg& arg, Callback& cb) const {
1066 FormatValue<typename std::decay<
1067 typename std::tuple_element<K, Tuple>::type>::type>(
1068 std::get<K>(val_)).format(arg, cb);
1070 doFormatFrom<K+1>(i, arg, cb);
1074 template <class Callback>
1075 void doFormat(size_t i, FormatArg& arg, Callback& cb) const {
1076 return doFormatFrom<0>(i, arg, cb);
1082 // Partial specialization of FormatValue for nested Formatters
1083 template <bool containerMode, class... Args>
1084 class FormatValue<Formatter<containerMode, Args...>, void> {
1085 typedef Formatter<containerMode, Args...> FormatterValue;
1087 explicit FormatValue(const FormatterValue& f) : f_(f) { }
1089 template <class FormatCallback>
1090 void format(FormatArg& arg, FormatCallback& cb) const {
1091 format_value::formatFormatter(f_, arg, cb);
1094 const FormatterValue& f_;
1098 * Formatter objects can be appended to strings, and therefore they're
1099 * compatible with folly::toAppend and folly::to.
1101 template <class Tgt, bool containerMode, class... Args>
1102 typename std::enable_if<
1103 detail::IsSomeString<Tgt>::value>::type
1104 toAppend(const Formatter<containerMode, Args...>& value, Tgt * result) {
1105 value.appendTo(*result);
1108 } // namespace folly